summaryrefslogtreecommitdiff
path: root/chromium/components
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-24 12:15:48 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 13:30:04 +0000
commitb014812705fc80bff0a5c120dfcef88f349816dc (patch)
tree25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/components
parent9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff)
downloadqtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components')
-rw-r--r--chromium/components/BUILD.gn17
-rw-r--r--chromium/components/OWNERS3
-rw-r--r--chromium/components/account_id/BUILD.gn (renamed from chromium/components/signin/core/account_id/BUILD.gn)0
-rw-r--r--chromium/components/account_id/DEPS3
-rw-r--r--chromium/components/account_id/OWNERS3
-rw-r--r--chromium/components/account_id/account_id.cc (renamed from chromium/components/signin/core/account_id/account_id.cc)2
-rw-r--r--chromium/components/account_id/account_id.h (renamed from chromium/components/signin/core/account_id/account_id.h)6
-rw-r--r--chromium/components/account_id/interfaces/BUILD.gn (renamed from chromium/components/signin/public/interfaces/BUILD.gn)0
-rw-r--r--chromium/components/account_id/interfaces/OWNERS4
-rw-r--r--chromium/components/account_id/interfaces/account_id.mojom (renamed from chromium/components/signin/public/interfaces/account_id.mojom)0
-rw-r--r--chromium/components/account_id/interfaces/account_id.typemap (renamed from chromium/components/signin/public/interfaces/account_id.typemap)8
-rw-r--r--chromium/components/account_id/interfaces/account_id_traits.h (renamed from chromium/components/signin/public/interfaces/account_id_traits.h)21
-rw-r--r--chromium/components/app_modal_strings_grdp/OWNERS1
-rw-r--r--chromium/components/app_modal_strings_grdp/README.md5
-rw-r--r--chromium/components/arc/BUILD.gn66
-rw-r--r--chromium/components/arc/DEPS7
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.cc80
-rw-r--r--chromium/components/arc/arc_bridge_host_impl.h10
-rw-r--r--chromium/components/arc/arc_bridge_service.h18
-rw-r--r--chromium/components/arc/arc_data_remover_unittest.cc2
-rw-r--r--chromium/components/arc/arc_features.cc15
-rw-r--r--chromium/components/arc/arc_features.h3
-rw-r--r--chromium/components/arc/arc_prefs.cc12
-rw-r--r--chromium/components/arc/arc_prefs.h2
-rw-r--r--chromium/components/arc/arc_service_manager.h2
-rw-r--r--chromium/components/arc/arc_session_impl.cc12
-rw-r--r--chromium/components/arc/arc_session_impl_unittest.cc2
-rw-r--r--chromium/components/arc/arc_supervision_transition.cc27
-rw-r--r--chromium/components/arc/arc_supervision_transition.h31
-rw-r--r--chromium/components/arc/arc_util.cc8
-rw-r--r--chromium/components/arc/arc_util.h3
-rw-r--r--chromium/components/arc/arc_util_unittest.cc4
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_struct_traits.cc29
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc12
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters.cc38
-rw-r--r--chromium/components/arc/bluetooth/bluetooth_type_converters.h7
-rw-r--r--chromium/components/arc/common/BUILD.gn17
-rw-r--r--chromium/components/arc/common/app.mojom89
-rw-r--r--chromium/components/arc/common/arc_bridge.mojom9
-rw-r--r--chromium/components/arc/common/auth.mojom42
-rw-r--r--chromium/components/arc/common/bluetooth.mojom11
-rw-r--r--chromium/components/arc/common/ime.mojom10
-rw-r--r--chromium/components/arc/common/input_method_manager.mojom50
-rw-r--r--chromium/components/arc/common/notifications.mojom22
-rw-r--r--chromium/components/arc/common/policy.mojom20
-rw-r--r--chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc7
-rw-r--r--chromium/components/arc/ime/arc_ime_bridge.h1
-rw-r--r--chromium/components/arc/ime/arc_ime_bridge_impl.cc4
-rw-r--r--chromium/components/arc/ime/arc_ime_bridge_impl.h1
-rw-r--r--chromium/components/arc/ime/arc_ime_service.cc19
-rw-r--r--chromium/components/arc/ime/arc_ime_service.h3
-rw-r--r--chromium/components/arc/midis/arc_midis_bridge.cc2
-rw-r--r--chromium/components/arc/mojo_channel.h67
-rw-r--r--chromium/components/arc/power/DEPS2
-rw-r--r--chromium/components/arc/power/arc_power_bridge.h2
-rw-r--r--chromium/components/arc/usb/usb_host_bridge.cc6
-rw-r--r--chromium/components/assist_ranker/OWNERS2
-rw-r--r--chromium/components/assist_ranker/base_predictor.cc20
-rw-r--r--chromium/components/assist_ranker/base_predictor_unittest.cc15
-rw-r--r--chromium/components/assist_ranker/fake_ranker_model_loader.cc2
-rwxr-xr-xchromium/components/assist_ranker/print_example_preprocessor_config.py97
-rw-r--r--chromium/components/autofill/android/autofill_provider_android.cc17
-rw-r--r--chromium/components/autofill/android/autofill_provider_android.h2
-rw-r--r--chromium/components/autofill/android/form_field_data_android.cc2
-rw-r--r--chromium/components/autofill/content/DEPS1
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.cc4
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver.h2
-rw-r--r--chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc20
-rw-r--r--chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc3
-rw-r--r--chromium/components/autofill/content/common/BUILD.gn2
-rw-r--r--chromium/components/autofill/content/common/autofill_agent.mojom6
-rw-r--r--chromium/components/autofill/content/common/autofill_driver.mojom8
-rw-r--r--chromium/components/autofill/content/common/autofill_types.mojom12
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits.cc36
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits.h42
-rw-r--r--chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc19
-rw-r--r--chromium/components/autofill/content/renderer/BUILD.gn3
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.cc60
-rw-r--r--chromium/components/autofill/content/renderer/autofill_agent.h4
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util.cc126
-rw-r--r--chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc186
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.cc157
-rw-r--r--chromium/components/autofill/content/renderer/form_cache.h20
-rw-r--r--chromium/components/autofill/content/renderer/form_cache_unittest.cc82
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.cc85
-rw-r--r--chromium/components/autofill/content/renderer/html_based_username_detector.h19
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.cc254
-rw-r--r--chromium/components/autofill/content/renderer/password_autofill_agent.h32
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.cc809
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils.h23
-rw-r--r--chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc139
-rw-r--r--chromium/components/autofill/content/renderer/password_generation_agent.cc51
-rw-r--r--chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc3
-rw-r--r--chromium/components/autofill/core/browser/BUILD.gn11
-rw-r--r--chromium/components/autofill/core/browser/address.cc2
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager.cc6
-rw-r--r--chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc10
-rw-r--r--chromium/components/autofill/core/browser/autofill_client.h9
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.cc313
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager.h21
-rw-r--r--chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc226
-rw-r--r--chromium/components/autofill/core/browser/autofill_driver.h4
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.cc70
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments.h17
-rw-r--r--chromium/components/autofill/core/browser/autofill_experiments_unittest.cc64
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.cc38
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc73
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.cc66
-rw-r--r--chromium/components/autofill/core/browser/autofill_field.h64
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.cc7
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler.h6
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.cc5
-rw-r--r--chromium/components/autofill/core/browser/autofill_handler_proxy.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc6
-rw-r--r--chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.cc257
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager.h40
-rw-r--r--chromium/components/autofill/core/browser/autofill_manager_unittest.cc757
-rw-r--r--chromium/components/autofill/core/browser/autofill_merge_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.cc76
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics.h61
-rw-r--r--chromium/components/autofill/core/browser/autofill_metrics_unittest.cc587
-rw-r--r--chromium/components/autofill/core/browser/autofill_popup_delegate.h5
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.cc36
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_unittest.cc126
-rw-r--r--chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/autofill_provider.h2
-rw-r--r--chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc64
-rw-r--r--chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h7
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.cc44
-rw-r--r--chromium/components/autofill/core/browser/autofill_test_utils.h8
-rw-r--r--chromium/components/autofill/core/browser/autofill_type.cc5
-rw-r--r--chromium/components/autofill/core/browser/contact_info.cc6
-rw-r--r--chromium/components/autofill/core/browser/country_combobox_model.cc2
-rw-r--r--chromium/components/autofill/core/browser/credit_card.cc41
-rw-r--r--chromium/components/autofill/core/browser/credit_card.h21
-rw-r--r--chromium/components/autofill/core/browser/credit_card_save_manager.cc81
-rw-r--r--chromium/components/autofill/core/browser/credit_card_save_manager.h3
-rw-r--r--chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc218
-rw-r--r--chromium/components/autofill/core/browser/credit_card_unittest.cc309
-rw-r--r--chromium/components/autofill/core/browser/field_filler_unittest.cc52
-rw-r--r--chromium/components/autofill/core/browser/field_types.h4
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer.cc8
-rw-r--r--chromium/components/autofill/core/browser/form_data_importer_unittest.cc80
-rw-r--r--chromium/components/autofill/core/browser/form_field.cc7
-rw-r--r--chromium/components/autofill/core/browser/form_structure.cc108
-rw-r--r--chromium/components/autofill/core/browser/form_structure.h41
-rw-r--r--chromium/components/autofill/core/browser/form_structure_unittest.cc207
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.cc19
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client.h9
-rw-r--r--chromium/components/autofill/core/browser/payments/payments_client_unittest.cc158
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.cc255
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager.h40
-rw-r--r--chromium/components/autofill/core/browser/personal_data_manager_unittest.cc906
-rw-r--r--chromium/components/autofill/core/browser/phone_number_i18n.cc10
-rw-r--r--chromium/components/autofill/core/browser/popup_item_ids.h1
-rw-r--r--chromium/components/autofill/core/browser/popup_types.h24
-rw-r--r--chromium/components/autofill/core/browser/proto/server.proto47
-rw-r--r--chromium/components/autofill/core/browser/rationalization_util_unittest.cc52
-rw-r--r--chromium/components/autofill/core/browser/region_data_loader_impl.cc2
-rw-r--r--chromium/components/autofill/core/browser/subkey_requester_unittest.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.cc18
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_client.h5
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.cc3
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_driver.h2
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager.cc39
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_manager.h16
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.cc8
-rw-r--r--chromium/components/autofill/core/browser/test_autofill_provider.h4
-rw-r--r--chromium/components/autofill/core/browser/test_form_structure.cc2
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.cc22
-rw-r--r--chromium/components/autofill/core/browser/test_personal_data_manager.h3
-rw-r--r--chromium/components/autofill/core/browser/test_sync_service.cc11
-rw-r--r--chromium/components/autofill/core/browser/test_sync_service.h2
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc22
-rw-r--r--chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h43
-rw-r--r--chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h21
-rw-r--r--chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc2
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc112
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h72
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc220
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc20
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc223
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.cc31
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table.h6
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc314
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata.h4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc11
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h4
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc11
-rw-r--r--chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h2
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc14
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h14
-rw-r--r--chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc17
-rw-r--r--chromium/components/autofill/core/common/autofill_data_validation.cc8
-rw-r--r--chromium/components/autofill/core/common/autofill_features.cc43
-rw-r--r--chromium/components/autofill/core/common/autofill_features.h10
-rw-r--r--chromium/components/autofill/core/common/autofill_pref_names.cc37
-rw-r--r--chromium/components/autofill/core/common/autofill_pref_names.h2
-rw-r--r--chromium/components/autofill/core/common/autofill_switches.cc16
-rw-r--r--chromium/components/autofill/core/common/autofill_switches.h5
-rw-r--r--chromium/components/autofill/core/common/form_data.cc2
-rw-r--r--chromium/components/autofill/core/common/form_data.h8
-rw-r--r--chromium/components/autofill/core/common/form_field_data.cc24
-rw-r--r--chromium/components/autofill/core/common/form_field_data.h37
-rw-r--r--chromium/components/autofill/core/common/form_field_data_predictions.cc7
-rw-r--r--chromium/components/autofill/core/common/form_field_data_predictions.h1
-rw-r--r--chromium/components/autofill/core/common/form_field_data_unittest.cc21
-rw-r--r--chromium/components/autofill/core/common/password_form.cc21
-rw-r--r--chromium/components/autofill/core/common/password_form.h10
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.cc14
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data.h8
-rw-r--r--chromium/components/autofill/core/common/password_form_fill_data_unittest.cc5
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.cc14
-rw-r--r--chromium/components/autofill/core/common/save_password_progress_logger.h7
-rw-r--r--chromium/components/autofill/ios/browser/BUILD.gn1
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent.mm157
-rw-r--r--chromium/components/autofill/ios/browser/autofill_agent_unittests.mm35
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.h2
-rw-r--r--chromium/components/autofill/ios/browser/autofill_driver_ios.mm3
-rw-r--r--chromium/components/autofill/ios/browser/resources/autofill_controller.js146
-rw-r--r--chromium/components/autofill/ios/fill/fill_js_unittest.mm1
-rw-r--r--chromium/components/autofill/ios/fill/form_unittest.mm40
-rw-r--r--chromium/components/autofill/ios/fill/resources/fill.js177
-rw-r--r--chromium/components/autofill/ios/fill/resources/form.js56
-rw-r--r--chromium/components/autofill_strings.grdp41
-rw-r--r--chromium/components/autofill_strings_grdp/OWNERS1
-rw-r--r--chromium/components/autofill_strings_grdp/README.md5
-rw-r--r--chromium/components/bookmark_bar_strings_grdp/OWNERS1
-rw-r--r--chromium/components/bookmark_bar_strings_grdp/README.md5
-rw-r--r--chromium/components/bookmarks/browser/BUILD.gn40
-rw-r--r--chromium/components/bookmarks/browser/bookmark_codec_unittest.cc2
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.cc404
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model.h107
-rw-r--r--chromium/components/bookmarks/browser/bookmark_model_unittest.cc40
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node.cc36
-rw-r--r--chromium/components/bookmarks/browser/bookmark_node.h23
-rw-r--r--chromium/components/bookmarks/browser/bookmark_storage.cc143
-rw-r--r--chromium/components/bookmarks/browser/bookmark_storage.h81
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.cc6
-rw-r--r--chromium/components/bookmarks/browser/titled_url_index.h8
-rw-r--r--chromium/components/bookmarks/browser/url_and_title.h20
-rw-r--r--chromium/components/bookmarks/browser/url_index.cc135
-rw-r--r--chromium/components/bookmarks/browser/url_index.h92
-rw-r--r--chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc5
-rw-r--r--chromium/components/browser_sync/BUILD.gn3
-rw-r--r--chromium/components/browser_sync/abstract_profile_sync_service_test.cc12
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.cc48
-rw-r--r--chromium/components/browser_sync/profile_sync_components_factory_impl.h4
-rw-r--r--chromium/components/browser_sync/profile_sync_service.cc1088
-rw-r--r--chromium/components/browser_sync/profile_sync_service.h288
-rw-r--r--chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc21
-rw-r--r--chromium/components/browser_sync/profile_sync_service_mock.h2
-rw-r--r--chromium/components/browser_sync/profile_sync_service_startup_unittest.cc64
-rw-r--r--chromium/components/browser_sync/profile_sync_service_unittest.cc112
-rw-r--r--chromium/components/browser_sync/sync_auth_manager.cc359
-rw-r--r--chromium/components/browser_sync/sync_auth_manager.h149
-rw-r--r--chromium/components/browser_watcher/dump_stability_report_main_win.cc8
-rw-r--r--chromium/components/browser_watcher/endsession_watcher_window_win.cc9
-rw-r--r--chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc2
-rw-r--r--chromium/components/browser_watcher/stability_report.proto4
-rw-r--r--chromium/components/browser_watcher/stability_report_user_stream_data_source.cc19
-rw-r--r--chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc4
-rw-r--r--chromium/components/browser_watcher/window_hang_monitor_win.cc4
-rw-r--r--chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc9
-rw-r--r--chromium/components/browsing_data/content/BUILD.gn2
-rw-r--r--chromium/components/browsing_data/content/conditional_cache_counting_helper.cc8
-rw-r--r--chromium/components/browsing_data/content/conditional_cache_counting_helper.h2
-rw-r--r--chromium/components/browsing_data/content/counters/site_settings_counter.cc81
-rw-r--r--chromium/components/browsing_data/content/counters/site_settings_counter.h36
-rw-r--r--chromium/components/browsing_data/core/browsing_data_utils_unittest.cc55
-rw-r--r--chromium/components/browsing_data/core/counters/browsing_data_counter.h2
-rw-r--r--chromium/components/browsing_data/core/features.cc2
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils.cc14
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils.h10
-rw-r--r--chromium/components/browsing_data/core/history_notice_utils_unittest.cc38
-rw-r--r--chromium/components/browsing_data_strings.grdp6
-rw-r--r--chromium/components/browsing_data_strings_grdp/OWNERS1
-rw-r--r--chromium/components/browsing_data_strings_grdp/README.md5
-rw-r--r--chromium/components/captive_portal/captive_portal_detector.cc2
-rw-r--r--chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc2
-rw-r--r--chromium/components/cast_channel/BUILD.gn1
-rw-r--r--chromium/components/cast_channel/cast_auth_util_unittest.cc2
-rw-r--r--chromium/components/cast_channel/cast_message_handler.cc353
-rw-r--r--chromium/components/cast_channel/cast_message_handler.h149
-rw-r--r--chromium/components/cast_channel/cast_message_handler_unittest.cc128
-rw-r--r--chromium/components/cast_channel/cast_message_util.cc204
-rw-r--r--chromium/components/cast_channel/cast_message_util.h76
-rw-r--r--chromium/components/cast_channel/cast_message_util_unittest.cc82
-rw-r--r--chromium/components/cast_channel/cast_socket.cc6
-rw-r--r--chromium/components/cast_channel/cast_socket_unittest.cc20
-rw-r--r--chromium/components/cast_channel/cast_test_util.cc5
-rw-r--r--chromium/components/cast_channel/cast_test_util.h5
-rw-r--r--chromium/components/cast_channel/cast_transport.cc1
-rw-r--r--chromium/components/cast_channel/cast_transport_unittest.cc20
-rw-r--r--chromium/components/cbor/cbor_reader.cc20
-rw-r--r--chromium/components/cbor/cbor_reader.h46
-rw-r--r--chromium/components/cbor/cbor_reader_unittest.cc100
-rw-r--r--chromium/components/cdm/common/widevine_drm_delegate_android.cc5
-rw-r--r--chromium/components/cdm/renderer/android_key_systems.cc20
-rw-r--r--chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc26
-rw-r--r--chromium/components/cdm/renderer/external_clear_key_key_system_properties.h2
-rw-r--r--chromium/components/cdm/renderer/widevine_key_system_properties.cc14
-rw-r--r--chromium/components/cdm/renderer/widevine_key_system_properties.h10
-rw-r--r--chromium/components/certificate_transparency/BUILD.gn14
-rw-r--r--chromium/components/certificate_transparency/OWNERS8
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc307
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h33
-rw-r--r--chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc452
-rw-r--r--chromium/components/certificate_transparency/chrome_require_ct_delegate.cc (renamed from chromium/components/certificate_transparency/ct_policy_manager.cc)208
-rw-r--r--chromium/components/certificate_transparency/chrome_require_ct_delegate.h107
-rw-r--r--chromium/components/certificate_transparency/chrome_require_ct_delegate_unittest.cc (renamed from chromium/components/certificate_transparency/ct_policy_manager_unittest.cc)258
-rw-r--r--chromium/components/certificate_transparency/ct_known_logs.cc67
-rw-r--r--chromium/components/certificate_transparency/ct_known_logs.h55
-rw-r--r--chromium/components/certificate_transparency/ct_known_logs_unittest.cc38
-rw-r--r--chromium/components/certificate_transparency/ct_policy_manager.h54
-rw-r--r--chromium/components/certificate_transparency/data/BUILD.gn19
-rw-r--r--chromium/components/certificate_transparency/data/log_list.json377
-rw-r--r--chromium/components/certificate_transparency/log_dns_client.cc66
-rw-r--r--chromium/components/certificate_transparency/mock_log_dns_traffic.cc13
-rw-r--r--chromium/components/certificate_transparency/single_tree_tracker.cc18
-rw-r--r--chromium/components/certificate_transparency/single_tree_tracker.h11
-rw-r--r--chromium/components/certificate_transparency/tools/PRESUBMIT.py35
-rwxr-xr-xchromium/components/certificate_transparency/tools/make_ct_known_logs_list.py195
-rwxr-xr-xchromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py155
-rw-r--r--chromium/components/certificate_transparency/tree_state_tracker.cc3
-rw-r--r--chromium/components/chrome_apps/webstore_widget/cws_widget/BUILD.gn50
-rw-r--r--chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp47
-rw-r--r--chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp15
-rw-r--r--chromium/components/chrome_cleaner/OWNERS2
-rw-r--r--chromium/components/chrome_cleaner/public/constants/result_codes.h3
-rw-r--r--chromium/components/chrome_cleaner/public/interfaces/BUILD.gn3
-rw-r--r--chromium/components/client_update_protocol/ecdsa.cc8
-rw-r--r--chromium/components/client_update_protocol/ecdsa_unittest.cc2
-rw-r--r--chromium/components/component_updater/BUILD.gn2
-rw-r--r--chromium/components/component_updater/component_installer.cc14
-rw-r--r--chromium/components/component_updater/component_installer_unittest.cc12
-rw-r--r--chromium/components/component_updater/component_updater_command_line_config_policy.cc121
-rw-r--r--chromium/components/component_updater/component_updater_command_line_config_policy.h46
-rw-r--r--chromium/components/component_updater/component_updater_paths.cc11
-rw-r--r--chromium/components/component_updater/component_updater_service.cc47
-rw-r--r--chromium/components/component_updater/component_updater_service_internal.h4
-rw-r--r--chromium/components/component_updater/component_updater_service_unittest.cc4
-rw-r--r--chromium/components/component_updater/component_updater_url_constants.cc9
-rw-r--r--chromium/components/component_updater/component_updater_url_constants.h2
-rw-r--r--chromium/components/component_updater/configurator_impl.cc104
-rw-r--r--chromium/components/component_updater/configurator_impl.h13
-rw-r--r--chromium/components/component_updater/configurator_impl_unittest.cc50
-rw-r--r--chromium/components/component_updater/mock_component_updater_service.h3
-rw-r--r--chromium/components/component_updater/pref_names.cc6
-rw-r--r--chromium/components/component_updater/pref_names.h2
-rw-r--r--chromium/components/components_locale_settings.grd2
-rw-r--r--chromium/components/components_strings.grd16
-rw-r--r--chromium/components/consent_auditor/consent_auditor.cc11
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc4
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_policy_provider.cc45
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_pref.cc2
-rw-r--r--chromium/components/content_settings/core/browser/content_settings_utils.cc2
-rw-r--r--chromium/components/content_settings/core/browser/cookie_settings.cc2
-rw-r--r--chromium/components/content_settings/core/browser/host_content_settings_map.cc6
-rw-r--r--chromium/components/content_settings/core/common/content_settings.h1
-rw-r--r--chromium/components/content_settings/core/common/content_settings.mojom1
-rw-r--r--chromium/components/content_settings/core/common/content_settings_struct_traits.cc3
-rw-r--r--chromium/components/content_settings/core/common/content_settings_struct_traits.h5
-rw-r--r--chromium/components/content_settings/core/common/content_settings_types.h5
-rw-r--r--chromium/components/content_settings/core/common/pref_names.cc4
-rw-r--r--chromium/components/content_settings/core/common/pref_names.h2
-rw-r--r--chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc2
-rw-r--r--chromium/components/crash/OWNERS3
-rw-r--r--chromium/components/crash/android/OWNERS2
-rw-r--r--chromium/components/crash/content/app/BUILD.gn7
-rw-r--r--chromium/components/crash/content/app/breakpad_linux.cc5
-rw-r--r--chromium/components/crash/content/app/breakpad_win.cc50
-rw-r--r--chromium/components/crash/content/app/crash_keys_win.cc6
-rw-r--r--chromium/components/crash/content/app/crash_keys_win_unittest.cc4
-rw-r--r--chromium/components/crash/content/app/crash_reporter_client.cc6
-rw-r--r--chromium/components/crash/content/app/crash_reporter_client.h6
-rw-r--r--chromium/components/crash/content/app/crashpad.cc8
-rw-r--r--chromium/components/crash/content/app/crashpad.h11
-rw-r--r--chromium/components/crash/content/app/crashpad_linux.cc72
-rw-r--r--chromium/components/crash/content/app/crashpad_mac.mm110
-rw-r--r--chromium/components/crash/content/app/hard_error_handler_win.cc15
-rw-r--r--chromium/components/crash/content/browser/child_process_crash_observer_android.cc9
-rw-r--r--chromium/components/crash/content/browser/child_process_crash_observer_android.h6
-rw-r--r--chromium/components/crash/content/browser/crash_dump_manager_android.cc122
-rw-r--r--chromium/components/crash/content/browser/crash_dump_manager_android.h14
-rw-r--r--chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc49
-rw-r--r--chromium/components/crash/content/browser/crash_dump_observer_android.cc99
-rw-r--r--chromium/components/crash/content/browser/crash_dump_observer_android.h71
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.cc110
-rw-r--r--chromium/components/crash/content/browser/crash_handler_host_linux.h49
-rw-r--r--chromium/components/crash_strings_grdp/OWNERS1
-rw-r--r--chromium/components/crash_strings_grdp/README.md5
-rw-r--r--chromium/components/cronet/android/BUILD.gn367
-rw-r--r--chromium/components/cronet/ios/BUILD.gn3
-rw-r--r--chromium/components/cronet/ios/cronet_consumer/BUILD.gn2
-rw-r--r--chromium/components/cronet/ios/test/BUILD.gn1
-rw-r--r--chromium/components/crx_file/crx_creator_unittest.cc2
-rw-r--r--chromium/components/crx_file/crx_verifier.cc22
-rw-r--r--chromium/components/crx_file/crx_verifier_unittest.cc2
-rw-r--r--chromium/components/cryptauth/BUILD.gn21
-rw-r--r--chromium/components/cryptauth/background_eid_generator.cc5
-rw-r--r--chromium/components/cryptauth/background_eid_generator_unittest.cc2
-rw-r--r--chromium/components/cryptauth/ble/ble_advertisement_generator.cc11
-rw-r--r--chromium/components/cryptauth/ble/ble_advertisement_generator_unittest.cc7
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc8
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h6
-rw-r--r--chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc72
-rw-r--r--chromium/components/cryptauth/connection.cc27
-rw-r--r--chromium/components/cryptauth/connection.h18
-rw-r--r--chromium/components/cryptauth/connection_unittest.cc48
-rw-r--r--chromium/components/cryptauth/cryptauth_device_manager_impl.cc116
-rw-r--r--chromium/components/cryptauth/cryptauth_device_manager_impl.h20
-rw-r--r--chromium/components/cryptauth/cryptauth_device_manager_impl_unittest.cc148
-rw-r--r--chromium/components/cryptauth/cryptauth_enroller_impl.cc4
-rw-r--r--chromium/components/cryptauth/cryptauth_enroller_impl.h4
-rw-r--r--chromium/components/cryptauth/cryptauth_enroller_impl_unittest.cc6
-rw-r--r--chromium/components/cryptauth/cryptauth_test_util.cc19
-rw-r--r--chromium/components/cryptauth/cryptauth_test_util.h44
-rw-r--r--chromium/components/cryptauth/device_capability_manager.h46
-rw-r--r--chromium/components/cryptauth/device_capability_manager_impl.cc245
-rw-r--r--chromium/components/cryptauth/device_capability_manager_impl.h153
-rw-r--r--chromium/components/cryptauth/device_capability_manager_impl_unittest.cc424
-rw-r--r--chromium/components/cryptauth/device_to_device_authenticator.cc10
-rw-r--r--chromium/components/cryptauth/device_to_device_authenticator_unittest.cc15
-rw-r--r--chromium/components/cryptauth/fake_connection.cc22
-rw-r--r--chromium/components/cryptauth/fake_connection.h5
-rw-r--r--chromium/components/cryptauth/fake_cryptauth_device_manager.cc2
-rw-r--r--chromium/components/cryptauth/fake_cryptauth_device_manager.h22
-rw-r--r--chromium/components/cryptauth/fake_cryptauth_enrollment_manager.cc2
-rw-r--r--chromium/components/cryptauth/fake_cryptauth_enrollment_manager.h19
-rw-r--r--chromium/components/cryptauth/fake_device_capability_manager.cc51
-rw-r--r--chromium/components/cryptauth/fake_device_capability_manager.h76
-rw-r--r--chromium/components/cryptauth/fake_software_feature_manager.cc74
-rw-r--r--chromium/components/cryptauth/fake_software_feature_manager.h110
-rw-r--r--chromium/components/cryptauth/foreground_eid_generator.cc7
-rw-r--r--chromium/components/cryptauth/foreground_eid_generator_unittest.cc10
-rw-r--r--chromium/components/cryptauth/proto/cryptauth_api.proto6
-rw-r--r--chromium/components/cryptauth/remote_beacon_seed_fetcher.cc5
-rw-r--r--chromium/components/cryptauth/remote_beacon_seed_fetcher_unittest.cc10
-rw-r--r--chromium/components/cryptauth/remote_device.cc66
-rw-r--r--chromium/components/cryptauth/remote_device.h40
-rw-r--r--chromium/components/cryptauth/remote_device_cache.cc51
-rw-r--r--chromium/components/cryptauth/remote_device_cache.h43
-rw-r--r--chromium/components/cryptauth/remote_device_cache_unittest.cc85
-rw-r--r--chromium/components/cryptauth/remote_device_loader.cc40
-rw-r--r--chromium/components/cryptauth/remote_device_loader.h2
-rw-r--r--chromium/components/cryptauth/remote_device_loader_unittest.cc82
-rw-r--r--chromium/components/cryptauth/remote_device_provider_impl_unittest.cc14
-rw-r--r--chromium/components/cryptauth/remote_device_ref.cc67
-rw-r--r--chromium/components/cryptauth/remote_device_ref.h115
-rw-r--r--chromium/components/cryptauth/remote_device_ref_unittest.cc84
-rw-r--r--chromium/components/cryptauth/remote_device_test_util.cc86
-rw-r--r--chromium/components/cryptauth/remote_device_test_util.h31
-rw-r--r--chromium/components/cryptauth/secure_channel.cc2
-rw-r--r--chromium/components/cryptauth/secure_channel.h2
-rw-r--r--chromium/components/cryptauth/secure_channel_unittest.cc10
-rw-r--r--chromium/components/cryptauth/software_feature_manager.h43
-rw-r--r--chromium/components/cryptauth/software_feature_manager_impl.cc178
-rw-r--r--chromium/components/cryptauth/software_feature_manager_impl.h111
-rw-r--r--chromium/components/cryptauth/software_feature_manager_impl_unittest.cc382
-rw-r--r--chromium/components/cryptauth/software_feature_state.h18
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc30
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc2
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc24
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc13
-rw-r--r--chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc32
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/BUILD.gn10
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc138
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h17
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc205
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc115
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h24
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc329
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc29
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h22
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc116
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc111
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h34
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc122
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc45
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc29
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h20
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc259
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h15
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc7
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc22
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc65
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc28
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc18
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc52
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h27
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc99
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc17
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc70
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc12
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h5
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc8
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h4
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc22
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h8
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc10
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc59
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/network_properties_manager.cc5
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc59
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc3
-rw-r--r--chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc24
-rw-r--r--chromium/components/data_reduction_proxy/core/common/BUILD.gn1
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h21
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc4
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc6
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h9
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc99
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h32
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc76
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc2
-rw-r--r--chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h36
-rw-r--r--chromium/components/data_reduction_proxy/core/common/resource_type_provider.h3
-rw-r--r--chromium/components/data_reduction_proxy/proto/data_store.proto3
-rw-r--r--chromium/components/data_reduction_proxy/proto/pageload_metrics.proto31
-rw-r--r--chromium/components/data_usage/core/data_use_aggregator_unittest.cc6
-rw-r--r--chromium/components/data_use_measurement/content/content_url_request_classifier.cc25
-rw-r--r--chromium/components/data_use_measurement/content/content_url_request_classifier.h4
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.cc124
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement.h38
-rw-r--r--chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc45
-rw-r--r--chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc25
-rw-r--r--chromium/components/data_use_measurement/core/url_request_classifier.h3
-rw-r--r--chromium/components/device_event_log/device_event_log.h7
-rw-r--r--chromium/components/device_event_log/device_event_log_impl.cc3
-rw-r--r--chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc24
-rw-r--r--chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h8
-rw-r--r--chromium/components/discardable_memory/public/interfaces/BUILD.gn4
-rw-r--r--chromium/components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom4
-rw-r--r--chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc37
-rw-r--r--chromium/components/discardable_memory/service/discardable_shared_memory_manager.h13
-rw-r--r--chromium/components/discardable_memory/service/discardable_shared_memory_manager_unittest.cc58
-rw-r--r--chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc7
-rw-r--r--chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc6
-rw-r--r--chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source_unittest.cc5
-rw-r--r--chromium/components/dom_distiller/core/distiller.cc4
-rw-r--r--chromium/components/dom_distiller/core/distiller_unittest.cc5
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc4
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_service_unittest.cc4
-rw-r--r--chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/core/fake_distiller.h2
-rw-r--r--chromium/components/dom_distiller/core/page_features_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/core/task_tracker_unittest.cc2
-rw-r--r--chromium/components/dom_distiller/core/viewer_unittest.cc12
-rw-r--r--chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc5
-rw-r--r--chromium/components/dom_distiller_strings_grdp/OWNERS1
-rw-r--r--chromium/components/dom_distiller_strings_grdp/README.md5
-rw-r--r--chromium/components/domain_reliability/dispatcher.cc1
-rw-r--r--chromium/components/domain_reliability/header.cc4
-rw-r--r--chromium/components/domain_reliability/monitor.cc4
-rw-r--r--chromium/components/domain_reliability/quic_error_mapping.h2
-rw-r--r--chromium/components/domain_reliability/service.cc12
-rw-r--r--chromium/components/domain_reliability/service_unittest.cc2
-rw-r--r--chromium/components/domain_reliability/test_util.cc4
-rw-r--r--chromium/components/domain_reliability/test_util.h2
-rw-r--r--chromium/components/domain_reliability/util.cc4
-rw-r--r--chromium/components/domain_reliability/util.h4
-rw-r--r--chromium/components/download/content/factory/download_service_factory.h1
-rw-r--r--chromium/components/download/content/internal/download_driver_impl.cc6
-rw-r--r--chromium/components/download/content/public/all_download_item_notifier_unittest.cc8
-rw-r--r--chromium/components/download/downloader/in_progress/BUILD.gn9
-rw-r--r--chromium/components/download/downloader/in_progress/download_db_entry.cc19
-rw-r--r--chromium/components/download/downloader/in_progress/download_db_entry.h33
-rw-r--r--chromium/components/download/downloader/in_progress/download_entry.h1
-rw-r--r--chromium/components/download/downloader/in_progress/download_info.cc20
-rw-r--r--chromium/components/download/downloader/in_progress/download_info.h37
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_cache.h4
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_cache_impl.cc27
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_cache_impl.h9
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_cache_impl_unittest.cc1
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_conversions.cc149
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_conversions.h26
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_conversions_unittest.cc76
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_info.cc32
-rw-r--r--chromium/components/download/downloader/in_progress/in_progress_info.h105
-rw-r--r--chromium/components/download/downloader/in_progress/proto/download_entry.proto52
-rw-r--r--chromium/components/download/downloader/in_progress/ukm_info.cc23
-rw-r--r--chromium/components/download/downloader/in_progress/ukm_info.h34
-rw-r--r--chromium/components/download/internal/background_service/blob_task_proxy.cc2
-rw-r--r--chromium/components/download/internal/background_service/controller_impl.cc2
-rw-r--r--chromium/components/download/internal/background_service/controller_impl_unittest.cc4
-rw-r--r--chromium/components/download/internal/background_service/entry_utils.cc16
-rw-r--r--chromium/components/download/internal/background_service/entry_utils.h9
-rw-r--r--chromium/components/download/internal/background_service/entry_utils_unittest.cc56
-rw-r--r--chromium/components/download/internal/background_service/in_memory_download_driver.cc2
-rw-r--r--chromium/components/download/internal/background_service/in_memory_download_driver.h1
-rw-r--r--chromium/components/download/internal/background_service/in_memory_download_unittest.cc2
-rw-r--r--chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc5
-rw-r--r--chromium/components/download/internal/common/BUILD.gn7
-rw-r--r--chromium/components/download/internal/common/DEPS3
-rw-r--r--chromium/components/download/internal/common/base_file.cc32
-rw-r--r--chromium/components/download/internal/common/base_file_win.cc17
-rw-r--r--chromium/components/download/internal/common/download_file_impl.cc8
-rw-r--r--chromium/components/download/internal/common/download_file_unittest.cc10
-rw-r--r--chromium/components/download/internal/common/download_item_impl.cc40
-rw-r--r--chromium/components/download/internal/common/download_item_impl_unittest.cc49
-rw-r--r--chromium/components/download/internal/common/download_job_factory.cc13
-rw-r--r--chromium/components/download/internal/common/download_stats.cc3
-rw-r--r--chromium/components/download/internal/common/download_task_runner.cc1
-rw-r--r--chromium/components/download/internal/common/download_utils.cc21
-rw-r--r--chromium/components/download/internal/common/download_worker.cc20
-rw-r--r--chromium/components/download/internal/common/download_worker.h17
-rw-r--r--chromium/components/download/internal/common/in_progress_download_manager.cc402
-rw-r--r--chromium/components/download/internal/common/parallel_download_job.cc19
-rw-r--r--chromium/components/download/internal/common/parallel_download_job.h14
-rw-r--r--chromium/components/download/internal/common/parallel_download_job_unittest.cc14
-rw-r--r--chromium/components/download/internal/common/resource_downloader.cc34
-rw-r--r--chromium/components/download/internal/common/resource_downloader.h (renamed from chromium/components/download/public/common/resource_downloader.h)27
-rw-r--r--chromium/components/download/internal/common/url_download_handler_factory.cc13
-rw-r--r--chromium/components/download/public/background_service/download_metadata.cc5
-rw-r--r--chromium/components/download/public/background_service/download_metadata.h4
-rw-r--r--chromium/components/download/public/common/BUILD.gn6
-rw-r--r--chromium/components/download/public/common/download_danger_type.h19
-rw-r--r--chromium/components/download/public/common/download_item.h7
-rw-r--r--chromium/components/download/public/common/download_item_impl.h16
-rw-r--r--chromium/components/download/public/common/download_job_factory.h8
-rw-r--r--chromium/components/download/public/common/download_stats.h4
-rw-r--r--chromium/components/download/public/common/download_utils.h13
-rw-r--r--chromium/components/download/public/common/in_progress_download_manager.h171
-rw-r--r--chromium/components/download/public/common/mock_download_file.h2
-rw-r--r--chromium/components/download/public/common/mock_download_item.h1
-rw-r--r--chromium/components/download/public/common/mock_download_item_impl.h3
-rw-r--r--chromium/components/download/public/common/url_download_handler.h5
-rw-r--r--chromium/components/download/public/common/url_download_handler_factory.h11
-rw-r--r--chromium/components/download/quarantine/quarantine.h5
-rw-r--r--chromium/components/download/quarantine/quarantine_win.cc9
-rw-r--r--chromium/components/drive/BUILD.gn16
-rw-r--r--chromium/components/error_page/common/BUILD.gn2
-rw-r--r--chromium/components/error_page/common/error.cc3
-rw-r--r--chromium/components/error_page/common/error.h5
-rw-r--r--chromium/components/error_page/common/error_page_features.cc14
-rw-r--r--chromium/components/error_page/common/error_page_features.h21
-rw-r--r--chromium/components/error_page/common/error_page_switches.cc1
-rw-r--r--chromium/components/error_page/common/error_page_switches.h1
-rw-r--r--chromium/components/error_page/common/localized_error.cc15
-rw-r--r--chromium/components/error_page_strings.grdp13
-rw-r--r--chromium/components/error_page_strings_grdp/OWNERS1
-rw-r--r--chromium/components/error_page_strings_grdp/README.md5
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.cc128
-rw-r--r--chromium/components/exo/client_controlled_shell_surface.h18
-rw-r--r--chromium/components/exo/client_controlled_shell_surface_unittest.cc93
-rw-r--r--chromium/components/exo/display.cc31
-rw-r--r--chromium/components/exo/display.h1
-rw-r--r--chromium/components/exo/keyboard.cc84
-rw-r--r--chromium/components/exo/keyboard_unittest.cc20
-rw-r--r--chromium/components/exo/layer_tree_frame_sink_holder.cc6
-rw-r--r--chromium/components/exo/layer_tree_frame_sink_holder.h1
-rw-r--r--chromium/components/exo/notification_surface.cc6
-rw-r--r--chromium/components/exo/notification_surface.h2
-rw-r--r--chromium/components/exo/pointer.cc38
-rw-r--r--chromium/components/exo/pointer.h4
-rw-r--r--chromium/components/exo/pointer_unittest.cc226
-rw-r--r--chromium/components/exo/shell_surface_base.cc47
-rw-r--r--chromium/components/exo/shell_surface_base.h7
-rw-r--r--chromium/components/exo/shell_surface_unittest.cc32
-rw-r--r--chromium/components/exo/surface.cc8
-rw-r--r--chromium/components/exo/surface.h4
-rw-r--r--chromium/components/exo/surface_tree_host.cc18
-rw-r--r--chromium/components/exo/wayland/BUILD.gn1
-rw-r--r--chromium/components/exo/wayland/protocol/aura-shell.xml4
-rw-r--r--chromium/components/exo/wayland/public/aura-shell-protocol.c4
-rw-r--r--chromium/components/exo/wayland/server.cc169
-rw-r--r--chromium/components/favicon/content/DEPS1
-rw-r--r--chromium/components/favicon/content/content_favicon_driver.cc6
-rw-r--r--chromium/components/favicon/core/BUILD.gn2
-rw-r--r--chromium/components/favicon/core/favicon_handler.cc4
-rw-r--r--chromium/components/favicon/core/favicon_server_fetcher_params.cc57
-rw-r--r--chromium/components/favicon/core/favicon_server_fetcher_params.h53
-rw-r--r--chromium/components/favicon/core/large_icon_service.cc52
-rw-r--r--chromium/components/favicon/core/large_icon_service.h6
-rw-r--r--chromium/components/favicon/core/large_icon_service_unittest.cc136
-rw-r--r--chromium/components/feature_engagement/internal/configuration.cc3
-rw-r--r--chromium/components/feature_engagement/internal/event_model_impl.cc3
-rw-r--r--chromium/components/feature_engagement/internal/event_model_impl_unittest.cc2
-rw-r--r--chromium/components/feature_engagement/internal/in_memory_event_store.cc2
-rw-r--r--chromium/components/feature_engagement/internal/persistent_event_store.cc2
-rw-r--r--chromium/components/feature_engagement/internal/tracker_impl_unittest.cc2
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.cc10
-rw-r--r--chromium/components/feature_engagement/public/feature_constants.h5
-rw-r--r--chromium/components/feature_engagement/public/feature_list.cc5
-rw-r--r--chromium/components/feature_engagement/public/feature_list.h12
-rw-r--r--chromium/components/feed/DEPS7
-rw-r--r--chromium/components/feed/core/BUILD.gn7
-rw-r--r--chromium/components/feed/core/feed_host_service.cc27
-rw-r--r--chromium/components/feed/core/feed_host_service.h40
-rw-r--r--chromium/components/feed/core/feed_image_database.cc57
-rw-r--r--chromium/components/feed/core/feed_image_database.h21
-rw-r--r--chromium/components/feed/core/feed_image_database_unittest.cc37
-rw-r--r--chromium/components/feed/core/feed_image_manager.cc209
-rw-r--r--chromium/components/feed/core/feed_image_manager.h98
-rw-r--r--chromium/components/feed/core/feed_image_manager_unittest.cc269
-rw-r--r--chromium/components/feed/core/feed_networking_host.cc51
-rw-r--r--chromium/components/feed/core/feed_networking_host.h16
-rw-r--r--chromium/components/feed/core/feed_networking_host_unittest.cc77
-rw-r--r--chromium/components/feedback/anonymizer_tool.cc2
-rw-r--r--chromium/components/feedback/anonymizer_tool_unittest.cc10
-rw-r--r--chromium/components/feedback/feedback_report.cc4
-rw-r--r--chromium/components/feedback/feedback_uploader.cc4
-rw-r--r--chromium/components/feedback/feedback_uploader_unittest.cc53
-rw-r--r--chromium/components/flags_ui/BUILD.gn1
-rw-r--r--chromium/components/flags_ui/DEPS1
-rw-r--r--chromium/components/flags_ui/feature_entry.h4
-rw-r--r--chromium/components/flags_ui/feature_entry_macros.h3
-rw-r--r--chromium/components/flags_ui/flags_state.cc146
-rw-r--r--chromium/components/flags_ui/flags_state.h23
-rw-r--r--chromium/components/flags_ui/flags_state_unittest.cc11
-rw-r--r--chromium/components/flags_ui/flags_ui_constants.cc1
-rw-r--r--chromium/components/flags_ui/flags_ui_constants.h1
-rw-r--r--chromium/components/flags_ui/resources/flags.css11
-rw-r--r--chromium/components/flags_ui/resources/flags.html14
-rw-r--r--chromium/components/flags_ui/resources/flags.js16
-rw-r--r--chromium/components/gcm_driver/BUILD.gn14
-rw-r--r--chromium/components/gcm_driver/instance_id/BUILD.gn5
-rw-r--r--chromium/components/google/core/browser/BUILD.gn5
-rw-r--r--chromium/components/google/core/browser/DEPS2
-rw-r--r--chromium/components/google/core/browser/google_url_tracker.cc123
-rw-r--r--chromium/components/google/core/browser/google_url_tracker.h45
-rw-r--r--chromium/components/google/core/browser/google_url_tracker_client.h11
-rw-r--r--chromium/components/google/core/browser/google_url_tracker_unittest.cc117
-rw-r--r--chromium/components/google/core/browser/google_util.cc3
-rw-r--r--chromium/components/google/core/browser/google_util.h1
-rw-r--r--chromium/components/grpc_support/bidirectional_stream.cc6
-rw-r--r--chromium/components/grpc_support/bidirectional_stream.h12
-rw-r--r--chromium/components/grpc_support/bidirectional_stream_c.cc14
-rw-r--r--chromium/components/grpc_support/bidirectional_stream_unittest.cc5
-rw-r--r--chromium/components/guest_view/browser/guest_view_manager.cc12
-rw-r--r--chromium/components/guest_view/browser/guest_view_manager_unittest.cc3
-rw-r--r--chromium/components/guest_view/browser/test_guest_view_manager.cc6
-rw-r--r--chromium/components/guest_view/renderer/guest_view_container.cc6
-rw-r--r--chromium/components/heap_profiling/BUILD.gn49
-rw-r--r--chromium/components/heap_profiling/DEPS2
-rw-r--r--chromium/components/heap_profiling/client_connection_manager.cc16
-rw-r--r--chromium/components/heap_profiling/heap_profiling_test_shim.cc48
-rw-r--r--chromium/components/heap_profiling/heap_profiling_test_shim.h35
-rw-r--r--chromium/components/heap_profiling/supervisor.cc225
-rw-r--r--chromium/components/heap_profiling/supervisor.h147
-rw-r--r--chromium/components/heap_profiling/test_driver.cc1035
-rw-r--r--chromium/components/heap_profiling/test_driver.h170
-rw-r--r--chromium/components/history/content/browser/download_conversions.cc4
-rw-r--r--chromium/components/history/core/browser/BUILD.gn5
-rw-r--r--chromium/components/history/core/browser/DEPS1
-rw-r--r--chromium/components/history/core/browser/android/visit_sql_handler.cc2
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.cc8
-rw-r--r--chromium/components/history/core/browser/browsing_history_service.h5
-rw-r--r--chromium/components/history/core/browser/delete_directive_handler.cc2
-rw-r--r--chromium/components/history/core/browser/domain_mixing_metrics.cc150
-rw-r--r--chromium/components/history/core/browser/domain_mixing_metrics.h35
-rw-r--r--chromium/components/history/core/browser/domain_mixing_metrics_unittest.cc89
-rw-r--r--chromium/components/history/core/browser/download_constants.h1
-rw-r--r--chromium/components/history/core/browser/download_types.cc3
-rw-r--r--chromium/components/history/core/browser/expire_history_backend.cc80
-rw-r--r--chromium/components/history/core/browser/expire_history_backend.h17
-rw-r--r--chromium/components/history/core/browser/expire_history_backend_unittest.cc82
-rw-r--r--chromium/components/history/core/browser/history_backend.cc93
-rw-r--r--chromium/components/history/core/browser/history_backend.h17
-rw-r--r--chromium/components/history/core/browser/history_backend_db_unittest.cc115
-rw-r--r--chromium/components/history/core/browser/history_backend_notifier.h14
-rw-r--r--chromium/components/history/core/browser/history_backend_unittest.cc59
-rw-r--r--chromium/components/history/core/browser/history_constants.cc2
-rw-r--r--chromium/components/history/core/browser/history_constants.h5
-rw-r--r--chromium/components/history/core/browser/history_database.cc9
-rw-r--r--chromium/components/history/core/browser/history_database_params.cc5
-rw-r--r--chromium/components/history/core/browser/history_model_worker.cc4
-rw-r--r--chromium/components/history/core/browser/history_querying_unittest.cc2
-rw-r--r--chromium/components/history/core/browser/history_service.cc47
-rw-r--r--chromium/components/history/core/browser/history_service.h20
-rw-r--r--chromium/components/history/core/browser/history_service_observer.h31
-rw-r--r--chromium/components/history/core/browser/history_service_unittest.cc5
-rw-r--r--chromium/components/history/core/browser/history_types.cc46
-rw-r--r--chromium/components/history/core/browser/history_types.h98
-rw-r--r--chromium/components/history/core/browser/in_memory_database.cc3
-rw-r--r--chromium/components/history/core/browser/in_memory_history_backend.cc9
-rw-r--r--chromium/components/history/core/browser/in_memory_history_backend.h5
-rw-r--r--chromium/components/history/core/browser/thumbnail_database_unittest.cc12
-rw-r--r--chromium/components/history/core/browser/top_sites.cc3
-rw-r--r--chromium/components/history/core/browser/top_sites_impl.cc9
-rw-r--r--chromium/components/history/core/browser/top_sites_impl.h5
-rw-r--r--chromium/components/history/core/browser/typed_url_model_type_controller.cc21
-rw-r--r--chromium/components/history/core/browser/typed_url_model_type_controller.h2
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge.cc32
-rw-r--r--chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc136
-rw-r--r--chromium/components/history/core/browser/visit_database.cc106
-rw-r--r--chromium/components/history/core/browser/visit_database.h18
-rw-r--r--chromium/components/history/core/browser/visit_database_unittest.cc224
-rw-r--r--chromium/components/history/core/browser/web_history_service.cc2
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher.cc1
-rw-r--r--chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc36
-rw-r--r--chromium/components/image_fetcher/core/mock_image_decoder.h2
-rw-r--r--chromium/components/image_fetcher/core/request_metadata.cc3
-rw-r--r--chromium/components/image_fetcher/core/request_metadata.h1
-rw-r--r--chromium/components/image_fetcher/core/request_metadata_unittest.cc8
-rw-r--r--chromium/components/image_fetcher/ios/webp_decoder_unittest.mm2
-rw-r--r--chromium/components/infobars/core/confirm_infobar_delegate.cc8
-rw-r--r--chromium/components/infobars/core/confirm_infobar_delegate.h5
-rw-r--r--chromium/components/infobars/core/infobar_delegate.h1
-rw-r--r--chromium/components/infobars/core/simple_alert_infobar_delegate.cc3
-rw-r--r--chromium/components/invalidation/impl/BUILD.gn25
-rw-r--r--chromium/components/json_schema/json_schema_validator_unittest.cc2
-rw-r--r--chromium/components/json_schema/json_schema_validator_unittest_base.cc4
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_registry.cc11
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_registry.h3
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_types.cc2
-rw-r--r--chromium/components/keep_alive_registry/keep_alive_types.h1
-rw-r--r--chromium/components/language/content/browser/BUILD.gn6
-rw-r--r--chromium/components/language/content/browser/geo_language_model.cc32
-rw-r--r--chromium/components/language/content/browser/geo_language_model.h37
-rw-r--r--chromium/components/language/content/browser/geo_language_model_unittest.cc97
-rw-r--r--chromium/components/language/content/browser/geo_language_provider.cc6
-rw-r--r--chromium/components/language/content/browser/geo_language_provider.h1
-rw-r--r--chromium/components/language/content/browser/geo_language_provider_unittest.cc67
-rw-r--r--chromium/components/language/content/browser/test_utils.cc46
-rw-r--r--chromium/components/language/content/browser/test_utils.h62
-rw-r--r--chromium/components/language/core/browser/heuristic_language_model.cc3
-rw-r--r--chromium/components/language/core/browser/heuristic_language_model.h5
-rw-r--r--chromium/components/language/core/common/BUILD.gn2
-rw-r--r--chromium/components/language/core/common/language_experiments.cc71
-rw-r--r--chromium/components/language/core/common/language_experiments.h54
-rw-r--r--chromium/components/leveldb_proto/leveldb_database.cc12
-rw-r--r--chromium/components/leveldb_proto/leveldb_database.h4
-rw-r--r--chromium/components/leveldb_proto/proto_database.h7
-rw-r--r--chromium/components/leveldb_proto/proto_database_impl.h16
-rw-r--r--chromium/components/leveldb_proto/proto_database_impl_unittest.cc66
-rw-r--r--chromium/components/leveldb_proto/testing/fake_db.h16
-rw-r--r--chromium/components/login/BUILD.gn2
-rw-r--r--chromium/components/login/DEPS2
-rw-r--r--chromium/components/login/base_screen_handler_utils.cc2
-rw-r--r--chromium/components/login/base_screen_handler_utils.h2
-rw-r--r--chromium/components/login/screens/screen_context_unittest.cc2
-rw-r--r--chromium/components/metrics/BUILD.gn3
-rw-r--r--chromium/components/metrics/call_stack_profile_collector.cc3
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.cc223
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.h38
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc335
-rw-r--r--chromium/components/metrics/call_stack_profile_params.h6
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector.cc11
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector.h10
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector_unittest.cc3
-rw-r--r--chromium/components/metrics/drive_metrics_provider.cc2
-rw-r--r--chromium/components/metrics/drive_metrics_provider_win.cc2
-rw-r--r--chromium/components/metrics/expired_histogram_util.cc34
-rw-r--r--chromium/components/metrics/expired_histogram_util.h21
-rw-r--r--chromium/components/metrics/expired_histograms_checker.cc26
-rw-r--r--chromium/components/metrics/expired_histograms_checker.h20
-rw-r--r--chromium/components/metrics/expired_histograms_checker_unittest.cc40
-rw-r--r--chromium/components/metrics/machine_id_provider_win.cc35
-rw-r--r--chromium/components/metrics/metrics_log.cc3
-rw-r--r--chromium/components/metrics/metrics_log_manager.cc6
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc1
-rw-r--r--chromium/components/metrics/metrics_service.cc2
-rw-r--r--chromium/components/metrics/metrics_service_client.cc10
-rw-r--r--chromium/components/metrics/metrics_service_client.h14
-rw-r--r--chromium/components/metrics/metrics_service_unittest.cc1
-rw-r--r--chromium/components/metrics/metrics_switches.cc3
-rw-r--r--chromium/components/metrics/metrics_switches.h1
-rw-r--r--chromium/components/metrics/net/network_metrics_provider.cc9
-rw-r--r--chromium/components/metrics/public/interfaces/BUILD.gn2
-rw-r--r--chromium/components/metrics/reporting_service_unittest.cc1
-rw-r--r--chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc15
-rw-r--r--chromium/components/metrics/stability_metrics_helper.cc34
-rw-r--r--chromium/components/metrics/stability_metrics_helper.h5
-rw-r--r--chromium/components/metrics/stability_metrics_helper_unittest.cc30
-rw-r--r--chromium/components/metrics/system_session_analyzer_win.cc2
-rw-r--r--chromium/components/metrics/test_metrics_service_client.cc4
-rw-r--r--chromium/components/metrics/test_metrics_service_client.h1
-rw-r--r--chromium/components/metrics/ui/screen_info_metrics_provider.cc6
-rw-r--r--chromium/components/metrics_services_manager/BUILD.gn1
-rw-r--r--chromium/components/metrics_services_manager/DEPS1
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager.cc10
-rw-r--r--chromium/components/metrics_services_manager/metrics_services_manager_client.h10
-rw-r--r--chromium/components/mirroring/DEPS1
-rw-r--r--chromium/components/mirroring/browser/cast_remoting_sender.cc3
-rw-r--r--chromium/components/mirroring/browser/cast_remoting_sender_unittest.cc4
-rw-r--r--chromium/components/mirroring/browser/single_client_video_capture_host.cc21
-rw-r--r--chromium/components/mirroring/browser/single_client_video_capture_host.h11
-rw-r--r--chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc57
-rw-r--r--chromium/components/mirroring/service/BUILD.gn23
-rw-r--r--chromium/components/mirroring/service/DEPS7
-rw-r--r--chromium/components/mirroring/service/fake_network_service.cc10
-rw-r--r--chromium/components/mirroring/service/fake_network_service.h52
-rw-r--r--chromium/components/mirroring/service/fake_video_capture_host.cc8
-rw-r--r--chromium/components/mirroring/service/interface.cc15
-rw-r--r--chromium/components/mirroring/service/interface.h74
-rw-r--r--chromium/components/mirroring/service/message_dispatcher.cc157
-rw-r--r--chromium/components/mirroring/service/message_dispatcher.h73
-rw-r--r--chromium/components/mirroring/service/message_dispatcher_unittest.cc299
-rw-r--r--chromium/components/mirroring/service/mirror_settings.cc148
-rw-r--r--chromium/components/mirroring/service/mirror_settings.h57
-rw-r--r--chromium/components/mirroring/service/receiver_response.cc199
-rw-r--r--chromium/components/mirroring/service/receiver_response.h134
-rw-r--r--chromium/components/mirroring/service/receiver_response_unittest.cc263
-rw-r--r--chromium/components/mirroring/service/rtp_stream.cc99
-rw-r--r--chromium/components/mirroring/service/rtp_stream.h9
-rw-r--r--chromium/components/mirroring/service/rtp_stream_unittest.cc4
-rw-r--r--chromium/components/mirroring/service/session.cc551
-rw-r--r--chromium/components/mirroring/service/session.h75
-rw-r--r--chromium/components/mirroring/service/session_monitor.cc412
-rw-r--r--chromium/components/mirroring/service/session_monitor.h142
-rw-r--r--chromium/components/mirroring/service/session_monitor_unittest.cc397
-rw-r--r--chromium/components/mirroring/service/session_unittest.cc118
-rw-r--r--chromium/components/mirroring/service/udp_socket_client.cc8
-rw-r--r--chromium/components/mirroring/service/udp_socket_client.h4
-rw-r--r--chromium/components/mirroring/service/udp_socket_client_unittest.cc6
-rw-r--r--chromium/components/mirroring/service/value_util.cc95
-rw-r--r--chromium/components/mirroring/service/value_util.h39
-rw-r--r--chromium/components/mirroring/service/video_capture_client.cc31
-rw-r--r--chromium/components/mirroring/service/video_capture_client.h9
-rw-r--r--chromium/components/mirroring/service/video_capture_client_unittest.cc15
-rw-r--r--chromium/components/mirroring/service/wifi_status_monitor.cc80
-rw-r--r--chromium/components/mirroring/service/wifi_status_monitor.h61
-rw-r--r--chromium/components/mirroring/service/wifi_status_monitor_unittest.cc173
-rw-r--r--chromium/components/nacl/broker/BUILD.gn10
-rw-r--r--chromium/components/nacl/browser/BUILD.gn3
-rw-r--r--chromium/components/nacl/common/BUILD.gn1
-rw-r--r--chromium/components/nacl/loader/BUILD.gn6
-rw-r--r--chromium/components/navigation_interception/intercept_navigation_throttle.cc3
-rw-r--r--chromium/components/navigation_interception/navigation_params.cc23
-rw-r--r--chromium/components/navigation_interception/navigation_params.h8
-rw-r--r--chromium/components/navigation_interception/navigation_params_android.cc8
-rw-r--r--chromium/components/net_log/BUILD.gn4
-rw-r--r--chromium/components/net_log/DEPS1
-rw-r--r--chromium/components/net_log/chrome_net_log.cc16
-rw-r--r--chromium/components/net_log/chrome_net_log.h6
-rw-r--r--chromium/components/net_log/net_export_file_writer.cc171
-rw-r--r--chromium/components/net_log/net_export_file_writer.h96
-rw-r--r--chromium/components/net_log/net_export_file_writer_unittest.cc299
-rw-r--r--chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite-bday.pngbin0 -> 1102 bytes
-rw-r--r--chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.pngbin2628 -> 2433 bytes
-rw-r--r--chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite-bday.pngbin0 -> 1321 bytes
-rw-r--r--chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.pngbin3247 -> 3056 bytes
-rw-r--r--chromium/components/neterror/resources/neterror.html3
-rw-r--r--chromium/components/neterror/resources/offline.js165
-rw-r--r--chromium/components/network_hints/renderer/renderer_dns_prefetch.cc1
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator.cc39
-rw-r--r--chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc69
-rw-r--r--chromium/components/network_session_configurator/common/network_features.cc5
-rw-r--r--chromium/components/network_session_configurator/common/network_features.h3
-rw-r--r--chromium/components/ntp_snippets/BUILD.gn34
-rw-r--r--chromium/components/ntp_snippets/OWNERS2
-rw-r--r--chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc43
-rw-r--r--chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc6
-rw-r--r--chromium/components/ntp_snippets/category.h4
-rw-r--r--chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc34
-rw-r--r--chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc4
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.cc6
-rw-r--r--chromium/components/ntp_snippets/content_suggestion.h17
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_metrics.cc16
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.cc17
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service.h5
-rw-r--r--chromium/components/ntp_snippets/content_suggestions_service_unittest.cc45
-rw-r--r--chromium/components/ntp_snippets/contextual/cluster.h49
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc51
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h52
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.cc28
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.h29
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy_unittest.cc43
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc103
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestion.cc4
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestion.h4
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.cc52
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h52
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter_unittest.cc121
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.cc84
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h64
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_features.cc19
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_features.h18
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.cc66
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.h2
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch_unittest.cc86
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h6
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc9
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h8
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc135
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.cc22
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h115
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter_unittest.cc147
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.cc34
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.h146
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_result.cc (renamed from chromium/components/ntp_snippets/contextual/cluster.cc)36
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_result.h80
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.cc75
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.h55
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.cc45
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h12
-rw-r--r--chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry_unittest.cc37
-rw-r--r--chromium/components/ntp_snippets/features.cc17
-rw-r--r--chromium/components/ntp_snippets/features.h6
-rw-r--r--chromium/components/ntp_snippets/mock_content_suggestions_provider.h2
-rw-r--r--chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.cc12
-rw-r--r--chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.h6
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc329
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h119
-rw-r--r--chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc464
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/DEPS4
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc373
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h116
-rw-r--r--chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc466
-rw-r--r--chromium/components/ntp_snippets/pref_names.cc4
-rw-r--r--chromium/components/ntp_snippets/pref_names.h2
-rw-r--r--chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc4
-rw-r--r--chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc40
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc2
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc11
-rw-r--r--chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc1
-rw-r--r--chromium/components/ntp_snippets/user_classifier_unittest.cc2
-rw-r--r--chromium/components/ntp_snippets_strings_grdp/OWNERS1
-rw-r--r--chromium/components/ntp_snippets_strings_grdp/README.md5
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl.cc8
-rw-r--r--chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc6
-rw-r--r--chromium/components/ntp_tiles/popular_sites_impl.cc2
-rw-r--r--chromium/components/offline_items_collection/core/android/offline_item_bridge.cc4
-rw-r--r--chromium/components/offline_items_collection/core/offline_item.cc8
-rw-r--r--chromium/components/offline_items_collection/core/offline_item.h7
-rw-r--r--chromium/components/offline_items_collection/core/utilities/file_existence_checker_unittest.cc2
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents.cc6
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents.h2
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents_stub.cc8
-rw-r--r--chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc4
-rw-r--r--chromium/components/offline_pages/core/BUILD.gn8
-rw-r--r--chromium/components/offline_pages/core/archive_manager.cc2
-rw-r--r--chromium/components/offline_pages/core/archive_manager.h2
-rw-r--r--chromium/components/offline_pages/core/archive_validator_unittest.cc2
-rw-r--r--chromium/components/offline_pages/core/background/add_request_task.cc11
-rw-r--r--chromium/components/offline_pages/core/background/add_request_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/add_request_task_unittest.cc48
-rw-r--r--chromium/components/offline_pages/core/background/change_requests_state_task.cc18
-rw-r--r--chromium/components/offline_pages/core/background/change_requests_state_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc32
-rw-r--r--chromium/components/offline_pages/core/background/cleanup_task.cc6
-rw-r--r--chromium/components/offline_pages/core/background/cleanup_task_unittest.cc28
-rw-r--r--chromium/components/offline_pages/core/background/connection_notifier.cc6
-rw-r--r--chromium/components/offline_pages/core/background/connection_notifier.h6
-rw-r--r--chromium/components/offline_pages/core/background/get_requests_task.cc10
-rw-r--r--chromium/components/offline_pages/core/background/get_requests_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/get_requests_task_unittest.cc22
-rw-r--r--chromium/components/offline_pages/core/background/initialize_store_task.cc16
-rw-r--r--chromium/components/offline_pages/core/background/initialize_store_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc12
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_aborted_task.cc7
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_aborted_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc37
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_completed_task.cc8
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_completed_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc18
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_started_task.cc7
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_started_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc21
-rw-r--r--chromium/components/offline_pages/core/background/offliner.h11
-rw-r--r--chromium/components/offline_pages/core/background/offliner_stub.cc25
-rw-r--r--chromium/components/offline_pages/core/background/offliner_stub.h4
-rw-r--r--chromium/components/offline_pages/core/background/pending_state_updater.cc4
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task.cc24
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task.h6
-rw-r--r--chromium/components/offline_pages/core/background/pick_request_task_unittest.cc29
-rw-r--r--chromium/components/offline_pages/core/background/reconcile_task.cc16
-rw-r--r--chromium/components/offline_pages/core/background/reconcile_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/reconcile_task_unittest.cc26
-rw-r--r--chromium/components/offline_pages/core/background/remove_requests_task.cc10
-rw-r--r--chromium/components/offline_pages/core/background/remove_requests_task.h2
-rw-r--r--chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc32
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.cc159
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator.h56
-rw-r--r--chromium/components/offline_pages/core/background/request_coordinator_unittest.cc108
-rw-r--r--chromium/components/offline_pages/core/background/request_queue.cc58
-rw-r--r--chromium/components/offline_pages/core/background/request_queue.h28
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_in_memory_store.cc34
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_in_memory_store.h14
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store.h22
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store_sql.cc165
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store_sql.h18
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_store_unittest.cc104
-rw-r--r--chromium/components/offline_pages/core/background/request_queue_unittest.cc161
-rw-r--r--chromium/components/offline_pages/core/background/save_page_request.cc3
-rw-r--r--chromium/components/offline_pages/core/background/update_request_task.cc15
-rw-r--r--chromium/components/offline_pages/core/background/update_request_task.h2
-rw-r--r--chromium/components/offline_pages/core/client_policy_controller.cc1
-rw-r--r--chromium/components/offline_pages/core/downloads/download_notifying_observer.cc8
-rw-r--r--chromium/components/offline_pages/core/downloads/download_ui_adapter.cc48
-rw-r--r--chromium/components/offline_pages/core/downloads/download_ui_adapter.h9
-rw-r--r--chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc58
-rw-r--r--chromium/components/offline_pages/core/downloads/offline_item_conversions.cc17
-rw-r--r--chromium/components/offline_pages/core/model/add_page_to_download_manager_task_unittest.cc8
-rw-r--r--chromium/components/offline_pages/core/model/cleanup_thumbnails_task.cc4
-rw-r--r--chromium/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc8
-rw-r--r--chromium/components/offline_pages/core/model/delete_page_task.cc7
-rw-r--r--chromium/components/offline_pages/core/model/get_pages_task.cc83
-rw-r--r--chromium/components/offline_pages/core/model/get_pages_task.h24
-rw-r--r--chromium/components/offline_pages/core/model/get_pages_task_unittest.cc6
-rw-r--r--chromium/components/offline_pages/core/model/get_thumbnail_task.cc2
-rw-r--r--chromium/components/offline_pages/core/model/get_thumbnail_task_unittest.cc34
-rw-r--r--chromium/components/offline_pages/core/model/has_thumbnail_task.cc49
-rw-r--r--chromium/components/offline_pages/core/model/has_thumbnail_task.h41
-rw-r--r--chromium/components/offline_pages/core/model/has_thumbnail_task_unittest.cc61
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_taskified.cc68
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_taskified.h37
-rw-r--r--chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc40
-rw-r--r--chromium/components/offline_pages/core/model/persistent_page_consistency_check_task.cc8
-rw-r--r--chromium/components/offline_pages/core/model/startup_maintenance_task.cc50
-rw-r--r--chromium/components/offline_pages/core/model/store_thumbnail_task.cc2
-rw-r--r--chromium/components/offline_pages/core/model/store_thumbnail_task_unittest.cc12
-rw-r--r--chromium/components/offline_pages/core/offline_page_archiver_unittest.cc5
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature.cc2
-rw-r--r--chromium/components/offline_pages/core/offline_page_feature_unittest.cc8
-rw-r--r--chromium/components/offline_pages/core/offline_page_item.cc2
-rw-r--r--chromium/components/offline_pages/core/offline_page_model.cc6
-rw-r--r--chromium/components/offline_pages/core/offline_page_model.h39
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_event_logger.cc16
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_event_logger.h12
-rw-r--r--chromium/components/offline_pages/core/offline_page_model_event_logger_unittest.cc25
-rw-r--r--chromium/components/offline_pages/core/offline_page_types.h4
-rw-r--r--chromium/components/offline_pages/core/prefetch/BUILD.gn8
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc2
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc66
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h11
-rw-r--r--chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc36
-rw-r--r--chromium/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h8
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h6
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc91
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h25
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc280
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc3
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h6
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_item.cc59
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_item.h6
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc21
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h6
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_types.cc138
-rw-r--r--chromium/components/offline_pages/core/prefetch/prefetch_types.h9
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc1
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_schema.cc109
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc12
-rw-r--r--chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h3
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_download_service.cc112
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_download_service.h57
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc6
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h3
-rw-r--r--chromium/components/offline_pages/core/prefetch/test_util.cc66
-rw-r--r--chromium/components/offline_pages/core/prefetch/thumbnail_fetcher.h23
-rw-r--r--chromium/components/offline_pages/core/recent_tabs/BUILD.gn39
-rw-r--r--chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc101
-rw-r--r--chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h86
-rw-r--r--chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc123
-rw-r--r--chromium/components/offline_pages/core/stub_offline_page_model.cc27
-rw-r--r--chromium/components/offline_pages/core/stub_offline_page_model.h39
-rw-r--r--chromium/components/offline_pages/core/stub_system_download_manager.cc (renamed from chromium/components/offline_pages/core/system_download_manager_stub.cc)12
-rw-r--r--chromium/components/offline_pages/core/stub_system_download_manager.h (renamed from chromium/components/offline_pages/core/system_download_manager_stub.h)12
-rw-r--r--chromium/components/offline_pages/core/task_queue.cc2
-rw-r--r--chromium/components/offline_pages/resources/BUILD.gn14
-rw-r--r--chromium/components/offline_pages/resources/compiled_resources2.gyp11
-rw-r--r--chromium/components/offline_pages/resources/renovations.js20
-rw-r--r--chromium/components/omnibox/browser/BUILD.gn16
-rw-r--r--chromium/components/omnibox_strings.grdp7
-rw-r--r--chromium/components/omnibox_strings_grdp/OWNERS1
-rw-r--r--chromium/components/omnibox_strings_grdp/README.md5
-rw-r--r--chromium/components/onc/docs/onc_spec.md38
-rw-r--r--chromium/components/onc/onc_constants.cc19
-rw-r--r--chromium/components/onc/onc_constants.h9
-rw-r--r--chromium/components/os_crypt/BUILD.gn7
-rw-r--r--chromium/components/os_crypt/ie7_password_win.cc2
-rw-r--r--chromium/components/os_crypt/os_crypt_win.cc6
-rw-r--r--chromium/components/ownership/owner_settings_service.h4
-rw-r--r--chromium/components/page_info_strings.grdp7
-rw-r--r--chromium/components/page_info_strings_grdp/OWNERS1
-rw-r--r--chromium/components/page_info_strings_grdp/README.md5
-rw-r--r--chromium/components/password_manager/content/DEPS1
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.cc25
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver.h10
-rw-r--r--chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/BUILD.gn30
-rw-r--r--chromium/components/password_manager/core/browser/DEPS5
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc7
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc3
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc2
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc66
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h5
-rw-r--r--chromium/components/password_manager/core/browser/browser_save_password_progress_logger_unittest.cc71
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl.cc6
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc24
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc2
-rw-r--r--chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/credentials_filter.h5
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/BUILD.gn56
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn34
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto32
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc46
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.h23
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_fuzzer.cc42
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/ios_form_parser.cc22
-rw-r--r--chromium/components/password_manager/core/browser/form_parsing/ios_form_parser_unittest.cc22
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager.cc384
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager.h72
-rw-r--r--chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc191
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator.cc2
-rw-r--r--chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc27
-rw-r--r--chromium/components/password_manager/core/browser/login_database.cc6
-rw-r--r--chromium/components/password_manager/core/browser/login_database.h36
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios.cc13
-rw-r--r--chromium/components/password_manager/core/browser/login_database_ios_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/login_database_mac.cc6
-rw-r--r--chromium/components/password_manager/core/browser/login_database_posix.cc29
-rw-r--r--chromium/components/password_manager/core/browser/login_database_unittest.cc103
-rw-r--r--chromium/components/password_manager/core/browser/login_database_win.cc6
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.cc1
-rw-r--r--chromium/components/password_manager/core/browser/mock_password_store.h7
-rw-r--r--chromium/components/password_manager/core/browser/new_password_form_manager.cc214
-rw-r--r--chromium/components/password_manager/core/browser/new_password_form_manager.h111
-rw-r--r--chromium/components/password_manager/core/browser/new_password_form_manager_unittest.cc160
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.cc94
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager.h8
-rw-r--r--chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc375
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling.cc167
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling.h35
-rw-r--r--chromium/components/password_manager/core/browser/password_form_filling_unittest.cc177
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.cc604
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager.h169
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_for_ui.h106
-rw-r--r--chromium/components/password_manager/core/browser/password_form_manager_unittest.cc1678
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc27
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder.h18
-rw-r--r--chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc64
-rw-r--r--chromium/components/password_manager/core/browser/password_generation_manager.cc7
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.cc259
-rw-r--r--chromium/components/password_manager/core/browser/password_manager.h67
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_client.h18
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.cc13
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_metrics_util.h17
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.cc33
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_test_utils.h27
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_unittest.cc288
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.cc44
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util.h14
-rw-r--r--chromium/components/password_manager/core/browser/password_manager_util_unittest.cc118
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager.h9
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector.cc138
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector.h41
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h21
-rw-r--r--chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc342
-rw-r--r--chromium/components/password_manager/core/browser/password_store.cc55
-rw-r--r--chromium/components/password_manager/core/browser/password_store.h29
-rw-r--r--chromium/components/password_manager/core/browser/password_store_default_unittest.cc4
-rw-r--r--chromium/components/password_manager/core/browser/password_store_signin_notifier.cc9
-rw-r--r--chromium/components/password_manager/core/browser/password_store_signin_notifier.h4
-rw-r--r--chromium/components/password_manager/core/browser/password_store_unittest.cc36
-rw-r--r--chromium/components/password_manager/core/browser/stub_credentials_filter.cc5
-rw-r--r--chromium/components/password_manager/core/browser/stub_credentials_filter.h2
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.cc8
-rw-r--r--chromium/components/password_manager/core/browser/stub_password_manager_client.h6
-rw-r--r--chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc2
-rw-r--r--chromium/components/password_manager/core/browser/test_password_store.h1
-rw-r--r--chromium/components/password_manager/core/common/BUILD.gn15
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.cc8
-rw-r--r--chromium/components/password_manager/core/common/password_manager_features.h2
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.cc2
-rw-r--r--chromium/components/password_manager/core/common/password_manager_pref_names.h3
-rw-r--r--chromium/components/password_manager/core/common/passwords_directory_util_ios.cc43
-rw-r--r--chromium/components/password_manager/core/common/passwords_directory_util_ios.h24
-rw-r--r--chromium/components/password_manager/core/common/passwords_directory_util_ios_unittest.cc32
-rw-r--r--chromium/components/password_manager/public/interfaces/DEPS4
-rw-r--r--chromium/components/password_manager/public/interfaces/OWNERS11
-rw-r--r--chromium/components/password_manager/public/interfaces/sync_password_data.typemap16
-rw-r--r--chromium/components/password_manager/public/interfaces/sync_password_data_struct_traits.h45
-rw-r--r--chromium/components/password_manager/sync/browser/password_data_type_controller.cc4
-rw-r--r--chromium/components/password_manager/sync/browser/password_model_worker.cc2
-rw-r--r--chromium/components/password_manager/sync/browser/password_sync_util.cc69
-rw-r--r--chromium/components/password_manager/sync/browser/password_sync_util.h21
-rw-r--r--chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc30
-rw-r--r--chromium/components/password_manager/sync/browser/sync_credentials_filter.cc21
-rw-r--r--chromium/components/password_manager/sync/browser/sync_credentials_filter.h2
-rw-r--r--chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc11
-rw-r--r--chromium/components/payments/content/DEPS1
-rw-r--r--chromium/components/payments/content/android/currency_formatter_android.cc14
-rw-r--r--chromium/components/payments/content/android/currency_formatter_android.h1
-rw-r--r--chromium/components/payments/content/installable_payment_app_crawler.cc19
-rw-r--r--chromium/components/payments/content/payment_request.cc37
-rw-r--r--chromium/components/payments/content/payment_request_spec.cc15
-rw-r--r--chromium/components/payments/content/payment_request_spec.h5
-rw-r--r--chromium/components/payments/content/service_worker_payment_app_factory.cc5
-rw-r--r--chromium/components/payments/content/service_worker_payment_instrument.cc29
-rw-r--r--chromium/components/payments/content/service_worker_payment_instrument.h6
-rw-r--r--chromium/components/payments/content/service_worker_payment_instrument_unittest.cc7
-rw-r--r--chromium/components/payments/content/utility/payment_manifest_parser.cc2
-rw-r--r--chromium/components/payments/core/currency_formatter.cc12
-rw-r--r--chromium/components/payments/core/currency_formatter.h10
-rw-r--r--chromium/components/payments/core/currency_formatter_unittest.cc64
-rw-r--r--chromium/components/payments/core/features.cc2
-rw-r--r--chromium/components/payments/core/features.h3
-rw-r--r--chromium/components/payments/core/journey_logger.cc2
-rw-r--r--chromium/components/payments/core/payment_currency_amount.cc9
-rw-r--r--chromium/components/payments/core/payment_currency_amount_unittest.cc5
-rw-r--r--chromium/components/payments/core/payment_details_modifier_unittest.cc1
-rw-r--r--chromium/components/payments/core/payment_details_validation.cc7
-rw-r--r--chromium/components/payments/core/payment_item_unittest.cc2
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader.cc54
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader.h3
-rw-r--r--chromium/components/payments/core/payment_manifest_downloader_unittest.cc139
-rw-r--r--chromium/components/payments/core/payment_prefs.cc5
-rw-r--r--chromium/components/payments/core/payment_prefs.h4
-rw-r--r--chromium/components/payments/core/payments_validators.cc35
-rw-r--r--chromium/components/payments/core/payments_validators.h8
-rw-r--r--chromium/components/payments/core/payments_validators_unittest.cc45
-rw-r--r--chromium/components/payments/core/test_payment_request_delegate.h1
-rw-r--r--chromium/components/payments/mojom/payment_request_data.mojom8
-rw-r--r--chromium/components/payments_strings.grdp3
-rw-r--r--chromium/components/payments_strings_grdp/IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL.png.sha11
-rw-r--r--chromium/components/payments_strings_grdp/OWNERS1
-rw-r--r--chromium/components/payments_strings_grdp/README.md5
-rw-r--r--chromium/components/pdf/renderer/OWNERS2
-rw-r--r--chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc6
-rw-r--r--chromium/components/pdf_strings_grdp/OWNERS1
-rw-r--r--chromium/components/pdf_strings_grdp/README.md5
-rw-r--r--chromium/components/physical_web/OWNERS2
-rw-r--r--chromium/components/physical_web/data_source/BUILD.gn45
-rw-r--r--chromium/components/physical_web/data_source/fake_physical_web_data_source.cc111
-rw-r--r--chromium/components/physical_web/data_source/fake_physical_web_data_source.h63
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source.cc15
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source.h114
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl.cc49
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl.h44
-rw-r--r--chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc158
-rw-r--r--chromium/components/physical_web/data_source/physical_web_listener.h29
-rw-r--r--chromium/components/physical_web/resources/ic_link_grey600_36dp.pngbin337 -> 0 bytes
-rw-r--r--chromium/components/physical_web/webui/BUILD.gn17
-rw-r--r--chromium/components/physical_web/webui/physical_web_base_message_handler.cc124
-rw-r--r--chromium/components/physical_web/webui/physical_web_base_message_handler.h73
-rw-r--r--chromium/components/physical_web/webui/physical_web_ui_constants.cc29
-rw-r--r--chromium/components/physical_web/webui/physical_web_ui_constants.h35
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.css52
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.html45
-rw-r--r--chromium/components/physical_web/webui/resources/physical_web.js57
-rw-r--r--chromium/components/physical_web_ui_strings.grdp12
-rw-r--r--chromium/components/plugins/renderer/plugin_placeholder.cc4
-rw-r--r--chromium/components/plugins/renderer/webview_plugin.cc2
-rw-r--r--chromium/components/policy/core/common/BUILD.gn13
-rw-r--r--chromium/components/policy_strings.grdp10
-rw-r--r--chromium/components/policy_strings_grdp/IDS_EXPORT_POLICIES_MAC.png.sha11
-rw-r--r--chromium/components/policy_strings_grdp/OWNERS1
-rw-r--r--chromium/components/policy_strings_grdp/README.md5
-rw-r--r--chromium/components/pref_registry/pref_registry_syncable.h8
-rw-r--r--chromium/components/prefs/ios/BUILD.gn (renamed from chromium/components/password_manager/public/interfaces/BUILD.gn)11
-rw-r--r--chromium/components/prefs/ios/pref_observer_bridge.h32
-rw-r--r--chromium/components/prefs/ios/pref_observer_bridge.mm29
-rw-r--r--chromium/components/prefs/json_pref_store.cc2
-rw-r--r--chromium/components/prefs/pref_change_registrar_unittest.cc4
-rw-r--r--chromium/components/prefs/pref_notifier_impl_unittest.cc2
-rw-r--r--chromium/components/prefs/pref_service.cc11
-rw-r--r--chromium/components/prefs/pref_service.h1
-rw-r--r--chromium/components/prefs/pref_value_store.cc6
-rw-r--r--chromium/components/previews/content/previews_content_util_unittest.cc2
-rw-r--r--chromium/components/previews/core/previews_black_list_item.cc6
-rw-r--r--chromium/components/previews/core/previews_black_list_item.h4
-rw-r--r--chromium/components/previews/core/previews_opt_out_store_sql.cc6
-rw-r--r--chromium/components/previews/core/previews_user_data_unittest.cc2
-rw-r--r--chromium/components/printing/browser/BUILD.gn2
-rw-r--r--chromium/components/printing/browser/DEPS4
-rw-r--r--chromium/components/printing/browser/print_composite_client.cc8
-rw-r--r--chromium/components/printing/browser/print_composite_client.h8
-rw-r--r--chromium/components/printing/browser/print_manager_utils.cc1
-rw-r--r--chromium/components/printing/common/print_messages.cc18
-rw-r--r--chromium/components/printing/common/print_messages.h8
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.cc100
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper.h17
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper_linux.cc10
-rw-r--r--chromium/components/printing/renderer/print_render_frame_helper_mac.mm17
-rw-r--r--chromium/components/printing/resources/print_header_footer_template_page.html (renamed from chromium/components/printing/resources/print_preview_page.html)0
-rw-r--r--chromium/components/printing/service/public/cpp/pdf_service_mojo_types.h17
-rw-r--r--chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.h28
-rw-r--r--chromium/components/printing_component_strings.grdp (renamed from chromium/components/printing_strings.grdp)0
-rw-r--r--chromium/components/printing_component_strings_grdp/OWNERS1
-rw-r--r--chromium/components/printing_component_strings_grdp/README.md5
-rw-r--r--chromium/components/profile_metrics/counts.cc1
-rw-r--r--chromium/components/profile_metrics/counts.h2
-rw-r--r--chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc4
-rw-r--r--chromium/components/rappor/BUILD.gn3
-rw-r--r--chromium/components/rappor/DEPS1
-rw-r--r--chromium/components/rappor/log_uploader.cc73
-rw-r--r--chromium/components/rappor/log_uploader.h33
-rw-r--r--chromium/components/rappor/log_uploader_unittest.cc63
-rw-r--r--chromium/components/rappor/rappor_service_impl.cc5
-rw-r--r--chromium/components/rappor/rappor_service_impl.h8
-rw-r--r--chromium/components/reading_list/core/reading_list_store.cc4
-rw-r--r--chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc2
-rw-r--r--chromium/components/renderer_context_menu/views/toolkit_delegate_views.h5
-rw-r--r--chromium/components/reset_password_strings.grdp18
-rw-r--r--chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH.png.sha11
-rw-r--r--chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha11
-rw-r--r--chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_HEADING.png.sha11
-rw-r--r--chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH.png.sha11
-rw-r--r--chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha11
-rw-r--r--chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_HEADING.png.sha11
-rw-r--r--chromium/components/reset_password_strings_grdp/OWNERS1
-rw-r--r--chromium/components/reset_password_strings_grdp/README.md5
-rw-r--r--chromium/components/resources/OWNERS1
-rw-r--r--chromium/components/resources/autofill_scaled_resources.grdp2
-rw-r--r--chromium/components/resources/components_resources.grd1
-rw-r--r--chromium/components/resources/default_100_percent/autofill/cc-generic.pngbin240 -> 234 bytes
-rw-r--r--chromium/components/resources/default_100_percent/autofill/infobar_autofill_cc.pngbin396 -> 226 bytes
-rw-r--r--chromium/components/resources/default_100_percent/autofill/infobar_autofill_googlepay_with_divider.pngbin0 -> 1018 bytes
-rw-r--r--chromium/components/resources/default_100_percent/crash/favicon_sad_tab.pngbin299 -> 295 bytes
-rw-r--r--chromium/components/resources/default_200_percent/autofill/cc-generic.pngbin345 -> 348 bytes
-rw-r--r--chromium/components/resources/default_200_percent/autofill/infobar_autofill_cc.pngbin800 -> 311 bytes
-rw-r--r--chromium/components/resources/default_200_percent/autofill/infobar_autofill_googlepay_with_divider.pngbin0 -> 1872 bytes
-rw-r--r--chromium/components/resources/default_200_percent/crash/favicon_sad_tab.pngbin387 -> 388 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/cc-generic.pngbin451 -> 580 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/infobar_autofill_cc.pngbin0 -> 418 bytes
-rw-r--r--chromium/components/resources/default_300_percent/autofill/infobar_autofill_googlepay_with_divider.pngbin0 -> 2708 bytes
-rw-r--r--chromium/components/resources/default_300_percent/crash/favicon_sad_tab.pngbin851 -> 593 bytes
-rw-r--r--chromium/components/resources/physical_web_ui_resources.grdp9
-rw-r--r--chromium/components/resources/printing_resources.grdp4
-rw-r--r--chromium/components/safe_browsing/DEPS1
-rw-r--r--chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc79
-rw-r--r--chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h45
-rw-r--r--chromium/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc3
-rw-r--r--chromium/components/safe_browsing/browser/referrer_chain_provider.h39
-rw-r--r--chromium/components/safe_browsing/browser/safe_browsing_network_context.cc110
-rw-r--r--chromium/components/safe_browsing/browser/safe_browsing_network_context.h17
-rw-r--r--chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc7
-rw-r--r--chromium/components/safe_browsing/browser/threat_details.cc50
-rw-r--r--chromium/components/safe_browsing/browser/threat_details.h13
-rw-r--r--chromium/components/safe_browsing/browser/threat_details_cache.cc4
-rw-r--r--chromium/components/safe_browsing/browser/url_checker_delegate.h7
-rw-r--r--chromium/components/safe_browsing/common/BUILD.gn2
-rw-r--r--chromium/components/safe_browsing/common/DEPS1
-rw-r--r--chromium/components/safe_browsing/common/safe_browsing_prefs.cc25
-rw-r--r--chromium/components/safe_browsing/common/safe_browsing_prefs.h20
-rw-r--r--chromium/components/safe_browsing/common/safe_browsing_prefs_unittest.cc2
-rw-r--r--chromium/components/safe_browsing/common/utils.cc22
-rw-r--r--chromium/components/safe_browsing/common/utils.h11
-rw-r--r--chromium/components/safe_browsing/db/database_manager_unittest.cc4
-rw-r--r--chromium/components/safe_browsing/db/prefix_set.cc6
-rw-r--r--chromium/components/safe_browsing/db/prefix_set_unittest.cc26
-rw-r--r--chromium/components/safe_browsing/db/safebrowsing.proto3
-rw-r--r--chromium/components/safe_browsing/db/v4_embedded_test_server_util.cc15
-rw-r--r--chromium/components/safe_browsing/db/v4_embedded_test_server_util.h8
-rw-r--r--chromium/components/safe_browsing/db/v4_get_hash_protocol_manager.cc5
-rw-r--r--chromium/components/safe_browsing/db/v4_get_hash_protocol_manager_unittest.cc4
-rw-r--r--chromium/components/safe_browsing/db/v4_local_database_manager.cc26
-rw-r--r--chromium/components/safe_browsing/db/v4_local_database_manager.h1
-rw-r--r--chromium/components/safe_browsing/db/v4_local_database_manager_unittest.cc9
-rw-r--r--chromium/components/safe_browsing/db/v4_protocol_manager_util.cc11
-rw-r--r--chromium/components/safe_browsing/db/v4_protocol_manager_util.h1
-rw-r--r--chromium/components/safe_browsing/db/v4_store.cc15
-rw-r--r--chromium/components/safe_browsing/db/v4_update_protocol_manager.cc4
-rw-r--r--chromium/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc6
-rw-r--r--chromium/components/safe_browsing/db/whitelist_checker_client_unittest.cc13
-rw-r--r--chromium/components/safe_browsing/features.cc29
-rw-r--r--chromium/components/safe_browsing/features.h24
-rw-r--r--chromium/components/safe_browsing/password_protection/BUILD.gn22
-rw-r--r--chromium/components/safe_browsing/password_protection/mock_password_protection_service.cc27
-rw-r--r--chromium/components/safe_browsing/password_protection/mock_password_protection_service.h78
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_request.cc14
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service.cc98
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service.h47
-rw-r--r--chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc324
-rw-r--r--chromium/components/safe_browsing/proto/csd.proto36
-rw-r--r--chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc15
-rw-r--r--chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h7
-rw-r--r--chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc14
-rw-r--r--chromium/components/safe_browsing/triggers/BUILD.gn2
-rw-r--r--chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc1
-rw-r--r--chromium/components/safe_browsing/triggers/mock_trigger_manager.cc3
-rw-r--r--chromium/components/safe_browsing/triggers/mock_trigger_manager.h13
-rw-r--r--chromium/components/safe_browsing/triggers/suspicious_site_trigger.cc110
-rw-r--r--chromium/components/safe_browsing/triggers/suspicious_site_trigger.h99
-rw-r--r--chromium/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc279
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_manager.cc52
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_manager.h49
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc6
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_throttler.cc92
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_throttler.h35
-rw-r--r--chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc135
-rw-r--r--chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc2
-rw-r--r--chromium/components/search_engines/default_search_manager.cc1
-rw-r--r--chromium/components/search_engines/default_search_manager_unittest.cc6
-rw-r--r--chromium/components/search_engines/prepopulated_engines.json10
-rw-r--r--chromium/components/search_engines/search_host_to_urls_map.cc4
-rw-r--r--chromium/components/search_engines/search_host_to_urls_map.h6
-rw-r--r--chromium/components/search_engines/template_url.cc66
-rw-r--r--chromium/components/search_engines/template_url.h36
-rw-r--r--chromium/components/search_engines/template_url_fetcher.cc6
-rw-r--r--chromium/components/search_engines/template_url_service.cc157
-rw-r--r--chromium/components/search_engines/template_url_service.h83
-rw-r--r--chromium/components/search_engines/template_url_unittest.cc51
-rw-r--r--chromium/components/search_provider_logos/google_logo_api_unittest.cc2
-rw-r--r--chromium/components/search_provider_logos/logo_cache.cc2
-rw-r--r--chromium/components/search_provider_logos/logo_cache_unittest.cc2
-rw-r--r--chromium/components/search_provider_logos/logo_common.cc13
-rw-r--r--chromium/components/search_provider_logos/logo_common.h13
-rw-r--r--chromium/components/search_provider_logos/logo_service_impl_unittest.cc1
-rw-r--r--chromium/components/search_provider_logos/logo_tracker.cc27
-rw-r--r--chromium/components/security_interstitials/content/BUILD.gn22
-rw-r--r--chromium/components/security_interstitials/content/DEPS3
-rw-r--r--chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc160
-rw-r--r--chromium/components/security_interstitials/content/security_interstitial_tab_helper.h97
-rw-r--r--chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc210
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_large.html4
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_large.js11
-rw-r--r--chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css1
-rw-r--r--chromium/components/security_interstitials/core/common/resources/interstitial_common.css16
-rw-r--r--chromium/components/security_interstitials/core/common/resources/interstitial_core.css2
-rw-r--r--chromium/components/security_interstitials/core/common_string_util.cc4
-rw-r--r--chromium/components/security_interstitials/core/controller_client.cc4
-rw-r--r--chromium/components/security_interstitials/core/controller_client.h4
-rw-r--r--chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc4
-rw-r--r--chromium/components/security_interstitials/core/safe_browsing_quiet_error_ui.cc4
-rw-r--r--chromium/components/security_interstitials/core/ssl_error_ui.cc8
-rw-r--r--chromium/components/security_interstitials/core/superfish_error_ui.cc2
-rw-r--r--chromium/components/security_interstitials_strings.grdp3
-rw-r--r--chromium/components/security_state/core/features.cc2
-rw-r--r--chromium/components/security_state/core/security_state.cc32
-rw-r--r--chromium/components/security_state/core/security_state.h4
-rw-r--r--chromium/components/security_state/core/security_state_unittest.cc84
-rw-r--r--chromium/components/security_state_strings_grdp/OWNERS1
-rw-r--r--chromium/components/security_state_strings_grdp/README.md5
-rw-r--r--chromium/components/services/filesystem/BUILD.gn3
-rw-r--r--chromium/components/services/filesystem/DEPS1
-rw-r--r--chromium/components/services/filesystem/file_system_app.cc6
-rw-r--r--chromium/components/services/filesystem/manifest.json2
-rw-r--r--chromium/components/services/filesystem/public/interfaces/BUILD.gn1
-rw-r--r--chromium/components/services/filesystem/util.cc6
-rw-r--r--chromium/components/services/font/DEPS1
-rw-r--r--chromium/components/services/font/manifest.json2
-rw-r--r--chromium/components/services/font/public/cpp/BUILD.gn1
-rw-r--r--chromium/components/services/heap_profiling/BUILD.gn9
-rw-r--r--chromium/components/services/heap_profiling/connection_manager.cc11
-rw-r--r--chromium/components/services/heap_profiling/connection_manager.h4
-rw-r--r--chromium/components/services/heap_profiling/heap_profiling_manifest.json4
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/BUILD.gn5
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/OWNERS0
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/allocator_shim.cc210
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/allocator_shim.h8
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/client.cc17
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/sender_pipe.h10
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc4
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc4
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/sender_pipe_win.cc4
-rw-r--r--chromium/components/services/heap_profiling/public/cpp/settings.cc16
-rw-r--r--chromium/components/services/heap_profiling/public/mojom/BUILD.gn1
-rw-r--r--chromium/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom1
-rw-r--r--chromium/components/services/heap_profiling/receiver_pipe.cc3
-rw-r--r--chromium/components/services/heap_profiling/receiver_pipe.h4
-rw-r--r--chromium/components/services/heap_profiling/receiver_pipe_posix.cc17
-rw-r--r--chromium/components/services/heap_profiling/receiver_pipe_posix.h2
-rw-r--r--chromium/components/services/heap_profiling/receiver_pipe_win.cc17
-rw-r--r--chromium/components/services/heap_profiling/receiver_pipe_win.h2
-rw-r--r--chromium/components/services/leveldb/BUILD.gn3
-rw-r--r--chromium/components/services/leveldb/DEPS1
-rw-r--r--chromium/components/services/leveldb/leveldb_service_impl.cc5
-rw-r--r--chromium/components/services/leveldb/leveldb_service_impl.h1
-rw-r--r--chromium/components/services/leveldb/leveldb_service_unittest.cc2
-rw-r--r--chromium/components/services/leveldb/manifest.json2
-rw-r--r--chromium/components/services/leveldb/public/cpp/BUILD.gn1
-rw-r--r--chromium/components/services/leveldb/public/cpp/util.cc21
-rw-r--r--chromium/components/services/leveldb/public/cpp/util.h13
-rw-r--r--chromium/components/services/leveldb/public/interfaces/leveldb.mojom4
-rw-r--r--chromium/components/services/leveldb/remote_iterator_unittest.cc3
-rw-r--r--chromium/components/services/patch/manifest.json2
-rw-r--r--chromium/components/services/pdf_compositor/BUILD.gn (renamed from chromium/components/printing/service/BUILD.gn)14
-rw-r--r--chromium/components/services/pdf_compositor/DEPS (renamed from chromium/components/printing/service/DEPS)3
-rw-r--r--chromium/components/services/pdf_compositor/OWNERS (renamed from chromium/components/printing/service/OWNERS)2
-rw-r--r--chromium/components/services/pdf_compositor/README.md (renamed from chromium/components/printing/service/README.md)0
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_impl.cc (renamed from chromium/components/printing/service/pdf_compositor_impl.cc)31
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_impl.h (renamed from chromium/components/printing/service/pdf_compositor_impl.h)16
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc (renamed from chromium/components/printing/service/pdf_compositor_impl_unittest.cc)7
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_manifest.json (renamed from chromium/components/printing/service/pdf_compositor_manifest.json)5
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_service.cc (renamed from chromium/components/printing/service/pdf_compositor_service.cc)21
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_service.h (renamed from chromium/components/printing/service/pdf_compositor_service.h)8
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_service_unittest.cc (renamed from chromium/components/printing/service/pdf_compositor_service_unittest.cc)16
-rw-r--r--chromium/components/services/pdf_compositor/pdf_compositor_service_unittest_manifest.json (renamed from chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json)2
-rw-r--r--chromium/components/services/pdf_compositor/public/cpp/BUILD.gn (renamed from chromium/components/printing/service/public/cpp/BUILD.gn)4
-rw-r--r--chromium/components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.cc (renamed from chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc)4
-rw-r--r--chromium/components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.h (renamed from chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.h)6
-rw-r--r--chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h17
-rw-r--r--chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.cc (renamed from chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.cc)31
-rw-r--r--chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.h28
-rw-r--r--chromium/components/services/pdf_compositor/public/interfaces/BUILD.gn (renamed from chromium/components/printing/service/public/interfaces/BUILD.gn)1
-rw-r--r--chromium/components/services/pdf_compositor/public/interfaces/OWNERS (renamed from chromium/components/printing/service/public/interfaces/OWNERS)0
-rw-r--r--chromium/components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom (renamed from chromium/components/printing/service/public/interfaces/pdf_compositor.mojom)7
-rw-r--r--chromium/components/services/unzip/manifest.json2
-rw-r--r--chromium/components/session_manager/BUILD.gn2
-rw-r--r--chromium/components/session_manager/DEPS2
-rw-r--r--chromium/components/session_manager/core/BUILD.gn2
-rw-r--r--chromium/components/session_manager/session_manager_types.h2
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_builder.cc3
-rw-r--r--chromium/components/sessions/content/content_serialized_navigation_driver.cc2
-rw-r--r--chromium/components/sessions/core/base_session_service.cc2
-rw-r--r--chromium/components/sessions/core/base_session_service_commands.cc8
-rw-r--r--chromium/components/sessions/core/persistent_tab_restore_service.cc2
-rw-r--r--chromium/components/sessions/core/session_backend.cc8
-rw-r--r--chromium/components/sessions/core/session_service_commands.cc2
-rw-r--r--chromium/components/signin/core/account_id/DEPS2
-rw-r--r--chromium/components/signin/core/browser/BUILD.gn7
-rw-r--r--chromium/components/signin/core/browser/DEPS1
-rw-r--r--chromium/components/signin/core/browser/about_signin_internals.cc2
-rw-r--r--chromium/components/signin/core/browser/account_info.cc18
-rw-r--r--chromium/components/signin/core/browser/account_info.h5
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.cc128
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor.h21
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_delegate.cc9
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_delegate.h22
-rw-r--r--chromium/components/signin/core/browser/account_reconcilor_unittest.cc154
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service.h5
-rw-r--r--chromium/components/signin/core/browser/account_tracker_service_unittest.cc5
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc42
-rw-r--r--chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h4
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc99
-rw-r--r--chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h37
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service.cc16
-rw-r--r--chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc10
-rw-r--r--chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc7
-rw-r--r--chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h4
-rw-r--r--chromium/components/signin/core/browser/profile_identity_provider.cc15
-rw-r--r--chromium/components/signin/core/browser/profile_identity_provider.h8
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches.cc11
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches.h14
-rw-r--r--chromium/components/signin/core/browser/profile_management_switches_unittest.cc16
-rw-r--r--chromium/components/signin/core/browser/scoped_unified_consent.cc40
-rw-r--r--chromium/components/signin/core/browser/scoped_unified_consent.h31
-rw-r--r--chromium/components/signin/core/browser/signin_manager.cc4
-rw-r--r--chromium/components/signin/core/browser/signin_manager.h4
-rw-r--r--chromium/components/signin/core/browser/signin_metrics.cc21
-rw-r--r--chromium/components/signin/core/browser/signin_metrics_unittest.cc25
-rw-r--r--chromium/components/signin/core/browser/signin_pref_names.cc7
-rw-r--r--chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h1
-rw-r--r--chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm1
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm5
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h1
-rw-r--r--chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm1
-rw-r--r--chromium/components/signin/public/interfaces/OWNERS2
-rw-r--r--chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc6
-rw-r--r--chromium/components/spellcheck/browser/spelling_service_client.cc2
-rw-r--r--chromium/components/spellcheck/common/BUILD.gn1
-rw-r--r--chromium/components/spellcheck/common/spellcheck.mojom4
-rw-r--r--chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc8
-rw-r--r--chromium/components/spellcheck/renderer/hunspell_engine.cc6
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.cc53
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck.h23
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_language.cc13
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc2
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.cc45
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider.h8
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.cc5
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_test.h3
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc29
-rw-r--r--chromium/components/spellcheck/renderer/spellcheck_unittest.cc2
-rw-r--r--chromium/components/ssl_config/BUILD.gn38
-rw-r--r--chromium/components/ssl_config/DEPS9
-rw-r--r--chromium/components/ssl_config/OWNERS5
-rw-r--r--chromium/components/ssl_config/ssl_config_prefs.cc23
-rw-r--r--chromium/components/ssl_config/ssl_config_prefs.h23
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager.h45
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager_pref.cc351
-rw-r--r--chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc474
-rw-r--r--chromium/components/ssl_config/ssl_config_switches.cc30
-rw-r--r--chromium/components/ssl_config/ssl_config_switches.h22
-rw-r--r--chromium/components/ssl_errors_strings_grdp/OWNERS1
-rw-r--r--chromium/components/ssl_errors_strings_grdp/README.md5
-rw-r--r--chromium/components/startup_metric_utils/browser/startup_metric_utils.cc14
-rw-r--r--chromium/components/storage_monitor/BUILD.gn26
-rw-r--r--chromium/components/storage_monitor/DEPS4
-rw-r--r--chromium/components/storage_monitor/media_storage_util_unittest.cc1
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc151
-rw-r--r--chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h98
-rw-r--r--chromium/components/storage_monitor/mtp_manager_client_chromeos.cc133
-rw-r--r--chromium/components/storage_monitor/mtp_manager_client_chromeos.h78
-rw-r--r--chromium/components/storage_monitor/mtp_manager_client_chromeos_unittest.cc (renamed from chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc)80
-rw-r--r--chromium/components/storage_monitor/portable_device_watcher_win.cc37
-rw-r--r--chromium/components/storage_monitor/storage_info_utils.h2
-rw-r--r--chromium/components/storage_monitor/storage_monitor.cc10
-rw-r--r--chromium/components/storage_monitor/storage_monitor.h19
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.cc36
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos.h15
-rw-r--r--chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc10
-rw-r--r--chromium/components/storage_monitor/storage_monitor_linux_unittest.cc3
-rw-r--r--chromium/components/storage_monitor/storage_monitor_unittest.cc5
-rw-r--r--chromium/components/storage_monitor/storage_monitor_win.cc23
-rw-r--r--chromium/components/storage_monitor/storage_monitor_win_unittest.cc2
-rw-r--r--chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc96
-rw-r--r--chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h63
-rw-r--r--chromium/components/storage_monitor/test_storage_monitor.cc13
-rw-r--r--chromium/components/storage_monitor/test_storage_monitor.h7
-rw-r--r--chromium/components/storage_monitor/test_volume_mount_watcher_win.cc2
-rw-r--r--chromium/components/storage_monitor/volume_mount_watcher_win.cc28
-rw-r--r--chromium/components/strings/components_strings_am.xtb33
-rw-r--r--chromium/components/strings/components_strings_ar.xtb37
-rw-r--r--chromium/components/strings/components_strings_bg.xtb33
-rw-r--r--chromium/components/strings/components_strings_bn.xtb65
-rw-r--r--chromium/components/strings/components_strings_ca.xtb37
-rw-r--r--chromium/components/strings/components_strings_cs.xtb33
-rw-r--r--chromium/components/strings/components_strings_da.xtb33
-rw-r--r--chromium/components/strings/components_strings_de.xtb35
-rw-r--r--chromium/components/strings/components_strings_el.xtb35
-rw-r--r--chromium/components/strings/components_strings_en-GB.xtb33
-rw-r--r--chromium/components/strings/components_strings_es-419.xtb35
-rw-r--r--chromium/components/strings/components_strings_es.xtb41
-rw-r--r--chromium/components/strings/components_strings_et.xtb33
-rw-r--r--chromium/components/strings/components_strings_fa.xtb43
-rw-r--r--chromium/components/strings/components_strings_fi.xtb33
-rw-r--r--chromium/components/strings/components_strings_fil.xtb35
-rw-r--r--chromium/components/strings/components_strings_fr.xtb33
-rw-r--r--chromium/components/strings/components_strings_gu.xtb33
-rw-r--r--chromium/components/strings/components_strings_hi.xtb181
-rw-r--r--chromium/components/strings/components_strings_hr.xtb33
-rw-r--r--chromium/components/strings/components_strings_hu.xtb33
-rw-r--r--chromium/components/strings/components_strings_id.xtb35
-rw-r--r--chromium/components/strings/components_strings_it.xtb33
-rw-r--r--chromium/components/strings/components_strings_iw.xtb35
-rw-r--r--chromium/components/strings/components_strings_ja.xtb35
-rw-r--r--chromium/components/strings/components_strings_kn.xtb33
-rw-r--r--chromium/components/strings/components_strings_ko.xtb47
-rw-r--r--chromium/components/strings/components_strings_lt.xtb33
-rw-r--r--chromium/components/strings/components_strings_lv.xtb33
-rw-r--r--chromium/components/strings/components_strings_ml.xtb33
-rw-r--r--chromium/components/strings/components_strings_mr.xtb35
-rw-r--r--chromium/components/strings/components_strings_ms.xtb33
-rw-r--r--chromium/components/strings/components_strings_nl.xtb33
-rw-r--r--chromium/components/strings/components_strings_no.xtb33
-rw-r--r--chromium/components/strings/components_strings_pl.xtb33
-rw-r--r--chromium/components/strings/components_strings_pt-BR.xtb41
-rw-r--r--chromium/components/strings/components_strings_pt-PT.xtb33
-rw-r--r--chromium/components/strings/components_strings_ro.xtb33
-rw-r--r--chromium/components/strings/components_strings_ru.xtb35
-rw-r--r--chromium/components/strings/components_strings_sk.xtb39
-rw-r--r--chromium/components/strings/components_strings_sl.xtb33
-rw-r--r--chromium/components/strings/components_strings_sr.xtb33
-rw-r--r--chromium/components/strings/components_strings_sv.xtb33
-rw-r--r--chromium/components/strings/components_strings_sw.xtb53
-rw-r--r--chromium/components/strings/components_strings_ta.xtb33
-rw-r--r--chromium/components/strings/components_strings_te.xtb37
-rw-r--r--chromium/components/strings/components_strings_th.xtb57
-rw-r--r--chromium/components/strings/components_strings_tr.xtb35
-rw-r--r--chromium/components/strings/components_strings_uk.xtb33
-rw-r--r--chromium/components/strings/components_strings_vi.xtb33
-rw-r--r--chromium/components/strings/components_strings_zh-CN.xtb35
-rw-r--r--chromium/components/strings/components_strings_zh-TW.xtb33
-rw-r--r--chromium/components/subresource_filter/FILTER_LIST_GENERATION.md91
-rw-r--r--chromium/components/subresource_filter/OWNERS3
-rw-r--r--chromium/components/subresource_filter/content/browser/BUILD.gn7
-rw-r--r--chromium/components/subresource_filter/content/browser/DEPS2
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc5
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h7
-rw-r--r--chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc41
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc81
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h20
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc127
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h48
-rw-r--r--chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc133
-rw-r--r--chromium/components/subresource_filter/content/browser/navigation_console_logger.cc64
-rw-r--r--chromium/components/subresource_filter/content/browser/navigation_console_logger.h68
-rw-r--r--chromium/components/subresource_filter/content/browser/navigation_console_logger_unittest.cc138
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc27
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h23
-rw-r--r--chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc22
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_client.h8
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer.h7
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc6
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.h5
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc12
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h5
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc238
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h30
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc305
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc4
-rw-r--r--chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc9
-rw-r--r--chromium/components/subresource_filter/content/common/ad_delay_throttle.cc154
-rw-r--r--chromium/components/subresource_filter/content/common/ad_delay_throttle.h85
-rw-r--r--chromium/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc397
-rw-r--r--chromium/components/subresource_filter/content/common/subresource_filter_messages.h6
-rw-r--r--chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.cc36
-rw-r--r--chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.h12
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc44
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h17
-rw-r--r--chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc54
-rw-r--r--chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc4
-rw-r--r--chromium/components/subresource_filter/core/browser/BUILD.gn2
-rw-r--r--chromium/components/subresource_filter/core/browser/copying_file_stream.cc (renamed from chromium/components/url_pattern_index/copying_file_stream.cc)2
-rw-r--r--chromium/components/subresource_filter/core/browser/copying_file_stream.h (renamed from chromium/components/url_pattern_index/copying_file_stream.h)6
-rw-r--r--chromium/components/subresource_filter/core/browser/ruleset_service.cc4
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.cc41
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features.h16
-rw-r--r--chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc83
-rw-r--r--chromium/components/subresource_filter/core/common/BUILD.gn45
-rw-r--r--chromium/components/subresource_filter/core/common/PRESUBMIT.py35
-rw-r--r--chromium/components/subresource_filter/core/common/activation_decision.h16
-rw-r--r--chromium/components/subresource_filter/core/common/common_features.cc1
-rw-r--r--chromium/components/subresource_filter/core/common/common_features.h4
-rw-r--r--chromium/components/subresource_filter/core/common/indexed_ruleset.cc4
-rw-r--r--chromium/components/subresource_filter/core/common/perftests/data/http_archive_top_100_page_requests6621
-rw-r--r--chromium/components/subresource_filter/core/common/perftests/data/httparchive_request_corpus.csv6845
-rw-r--r--chromium/components/subresource_filter/core/common/perftests/indexed_ruleset_perftest.cc11
-rw-r--r--chromium/components/subresource_filter/core/common/test_ruleset_creator.cc2
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset.cc (renamed from chromium/components/url_pattern_index/unindexed_ruleset.cc)2
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset.h (renamed from chromium/components/url_pattern_index/unindexed_ruleset.h)6
-rw-r--r--chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc (renamed from chromium/components/url_pattern_index/unindexed_ruleset_unittest.cc)2
-rw-r--r--chromium/components/subresource_filter/tools/BUILD.gn121
-rw-r--r--chromium/components/subresource_filter/tools/filter_tool.cc (renamed from chromium/components/subresource_filter/core/common/tools/filter_tool.cc)36
-rw-r--r--chromium/components/subresource_filter/tools/filter_tool.h (renamed from chromium/components/subresource_filter/core/common/tools/filter_tool.h)6
-rw-r--r--chromium/components/subresource_filter/tools/filter_tool_main.cc (renamed from chromium/components/subresource_filter/core/common/tools/filter_tool_main.cc)16
-rw-r--r--chromium/components/subresource_filter/tools/filter_tool_unittest.cc (renamed from chromium/components/subresource_filter/core/common/tools/filter_tool_unittest.cc)69
-rw-r--r--chromium/components/subresource_filter/tools/indexing_tool.cc (renamed from chromium/components/subresource_filter/core/common/tools/indexing_tool.cc)6
-rw-r--r--chromium/components/subresource_filter/tools/indexing_tool.h (renamed from chromium/components/subresource_filter/core/common/tools/indexing_tool.h)6
-rw-r--r--chromium/components/subresource_filter/tools/indexing_tool_main.cc (renamed from chromium/components/subresource_filter/core/common/tools/indexing_tool_main.cc)2
-rw-r--r--chromium/components/subresource_filter/tools/indexing_tool_unittest.cc (renamed from chromium/components/subresource_filter/core/common/tools/indexing_tool_unittest.cc)2
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/BUILD.gn35
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule.cc351
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule.h136
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule_options.h93
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule_parser.cc478
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule_parser.h133
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule_parser_unittest.cc392
-rw-r--r--chromium/components/subresource_filter/tools/rule_parser/rule_unittest.cc187
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/BUILD.gn42
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/main.cc117
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.cc434
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.h98
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/rule_stream_unittest.cc415
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc176
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.h73
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc310
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.cc21
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.h32
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.cc143
-rw-r--r--chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h83
-rw-r--r--chromium/components/suggestions/image_manager.cc4
-rw-r--r--chromium/components/suggestions/suggestions_service_impl.cc8
-rw-r--r--chromium/components/suggestions/suggestions_service_impl_unittest.cc12
-rw-r--r--chromium/components/supervised_user_error_page_strings_grdp/OWNERS1
-rw-r--r--chromium/components/supervised_user_error_page_strings_grdp/README.md5
-rw-r--r--chromium/components/sync/BUILD.gn14
-rw-r--r--chromium/components/sync/protocol/protocol_sources.gni5
-rw-r--r--chromium/components/sync_bookmarks/BUILD.gn3
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_controller.cc14
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_controller.h6
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.cc342
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor.h74
-rw-r--r--chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc292
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker.cc55
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker.h85
-rw-r--r--chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc45
-rw-r--r--chromium/components/sync_preferences/BUILD.gn1
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.cc27
-rw-r--r--chromium/components/sync_preferences/pref_model_associator.h41
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable.cc9
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable.h7
-rw-r--r--chromium/components/sync_preferences/pref_service_syncable_unittest.cc340
-rw-r--r--chromium/components/sync_preferences/testing_pref_service_syncable.cc4
-rw-r--r--chromium/components/sync_preferences/testing_pref_service_syncable.h14
-rw-r--r--chromium/components/sync_sessions/BUILD.gn8
-rw-r--r--chromium/components/sync_sessions/abstract_sessions_sync_manager.cc13
-rw-r--r--chromium/components/sync_sessions/abstract_sessions_sync_manager.h43
-rw-r--r--chromium/components/sync_sessions/favicon_cache.cc11
-rw-r--r--chromium/components/sync_sessions/favicon_cache.h5
-rw-r--r--chromium/components/sync_sessions/favicon_cache_unittest.cc8
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl.cc183
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl.h14
-rw-r--r--chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc180
-rw-r--r--chromium/components/sync_sessions/session_store.cc617
-rw-r--r--chromium/components/sync_sessions/session_store.h173
-rw-r--r--chromium/components/sync_sessions/session_store_unittest.cc635
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge.cc517
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge.h137
-rw-r--r--chromium/components/sync_sessions/session_sync_bridge_unittest.cc1429
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.cc70
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager.h24
-rw-r--r--chromium/components/sync_sessions/sessions_sync_manager_unittest.cc23
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.cc198
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker.h72
-rw-r--r--chromium/components/sync_sessions/synced_session_tracker_unittest.cc274
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.cc63
-rw-r--r--chromium/components/sync_sessions/tab_node_pool.h24
-rw-r--r--chromium/components/sync_sessions/tab_node_pool_unittest.cc78
-rw-r--r--chromium/components/sync_sessions/test_synced_window_delegates_getter.cc10
-rw-r--r--chromium/components/sync_sessions/test_synced_window_delegates_getter.h3
-rw-r--r--chromium/components/sync_ui_strings_grdp/OWNERS1
-rw-r--r--chromium/components/sync_ui_strings_grdp/README.md5
-rw-r--r--chromium/components/task_scheduler_util/BUILD.gn (renamed from chromium/components/task_scheduler_util/common/BUILD.gn)4
-rw-r--r--chromium/components/task_scheduler_util/DEPS (renamed from chromium/components/task_scheduler_util/common/DEPS)0
-rw-r--r--chromium/components/task_scheduler_util/variations_util.cc (renamed from chromium/components/task_scheduler_util/common/variations_util.cc)2
-rw-r--r--chromium/components/task_scheduler_util/variations_util.h (renamed from chromium/components/task_scheduler_util/common/variations_util.h)6
-rw-r--r--chromium/components/task_scheduler_util/variations_util_unittest.cc (renamed from chromium/components/task_scheduler_util/common/variations_util_unittest.cc)2
-rw-r--r--chromium/components/test/BUILD.gn8
-rw-r--r--chromium/components/timers/alarm_timer_unittest.cc13
-rw-r--r--chromium/components/toolbar/BUILD.gn19
-rw-r--r--chromium/components/toolbar/toolbar_model_delegate.cc31
-rw-r--r--chromium/components/toolbar/toolbar_model_delegate.h12
-rw-r--r--chromium/components/toolbar/toolbar_model_impl.cc49
-rw-r--r--chromium/components/toolbar/toolbar_model_impl.h6
-rw-r--r--chromium/components/toolbar/toolbar_model_impl_unittest.cc49
-rw-r--r--chromium/components/toolbar/vector_icons/http.icon26
-rw-r--r--chromium/components/toolbar/vector_icons/http_20.icon32
-rw-r--r--chromium/components/toolbar/vector_icons/https_invalid_20.icon25
-rw-r--r--chromium/components/toolbar/vector_icons/https_valid_20.icon29
-rw-r--r--chromium/components/toolbar/vector_icons/product_20.icon36
-rw-r--r--chromium/components/tracing/BUILD.gn13
-rw-r--r--chromium/components/tracing/common/trace_startup.cc31
-rw-r--r--chromium/components/tracing/common/trace_startup_config.cc (renamed from chromium/components/tracing/common/trace_config_file.cc)68
-rw-r--r--chromium/components/tracing/common/trace_startup_config.h (renamed from chromium/components/tracing/common/trace_config_file.h)53
-rw-r--r--chromium/components/tracing/common/trace_startup_config_unittest.cc (renamed from chromium/components/tracing/common/trace_config_file_unittest.cc)88
-rw-r--r--chromium/components/tracing/docs/heap_profiler_internals.md2
-rw-r--r--chromium/components/translate/content/common/BUILD.gn1
-rw-r--r--chromium/components/translate/core/browser/BUILD.gn1
-rw-r--r--chromium/components/translate_strings_grdp/OWNERS1
-rw-r--r--chromium/components/translate_strings_grdp/README.md5
-rw-r--r--chromium/components/typemaps.gni5
-rw-r--r--chromium/components/ui_devtools/BUILD.gn8
-rw-r--r--chromium/components/ui_devtools/DEPS2
-rw-r--r--chromium/components/ui_devtools/devtools_server.cc108
-rw-r--r--chromium/components/ui_devtools/devtools_server.h38
-rw-r--r--chromium/components/ui_devtools/ui_element.cc2
-rw-r--r--chromium/components/ui_devtools/ui_element.h2
-rw-r--r--chromium/components/ui_devtools/viz_views/BUILD.gn21
-rw-r--r--chromium/components/ui_devtools/viz_views/DEPS4
-rw-r--r--chromium/components/ui_devtools/viz_views/dom_agent_viz.cc148
-rw-r--r--chromium/components/ui_devtools/viz_views/dom_agent_viz.h71
-rw-r--r--chromium/components/ui_devtools/viz_views/frame_sink_element.cc111
-rw-r--r--chromium/components/ui_devtools/viz_views/frame_sink_element.h61
-rw-r--r--chromium/components/ui_devtools/viz_views/overlay_agent_viz.cc30
-rw-r--r--chromium/components/ui_devtools/viz_views/overlay_agent_viz.h35
-rw-r--r--chromium/components/ukm/BUILD.gn4
-rw-r--r--chromium/components/ukm/content/BUILD.gn1
-rw-r--r--chromium/components/ukm/content/DEPS1
-rw-r--r--chromium/components/ukm/content/source_url_recorder.cc61
-rw-r--r--chromium/components/ukm/content/source_url_recorder_browsertest.cc33
-rw-r--r--chromium/components/ukm/debug/ukm_debug_data_extractor.cc23
-rw-r--r--chromium/components/ukm/observers/history_delete_observer.cc7
-rw-r--r--chromium/components/ukm/observers/history_delete_observer.h5
-rw-r--r--chromium/components/ukm/observers/sync_disable_observer.cc16
-rw-r--r--chromium/components/ukm/observers/sync_disable_observer.h20
-rw-r--r--chromium/components/ukm/observers/sync_disable_observer_unittest.cc40
-rw-r--r--chromium/components/ukm/test_ukm_recorder.cc10
-rw-r--r--chromium/components/ukm/ukm_recorder_impl.cc63
-rw-r--r--chromium/components/ukm/ukm_recorder_impl.h6
-rw-r--r--chromium/components/ukm/ukm_service.h8
-rw-r--r--chromium/components/ukm/ukm_service_unittest.cc189
-rw-r--r--chromium/components/undo_strings_grdp/OWNERS1
-rw-r--r--chromium/components/undo_strings_grdp/README.md5
-rw-r--r--chromium/components/update_client/BUILD.gn2
-rw-r--r--chromium/components/update_client/action_runner.cc2
-rw-r--r--chromium/components/update_client/background_downloader_win.cc16
-rw-r--r--chromium/components/update_client/command_line_config_policy.cc40
-rw-r--r--chromium/components/update_client/command_line_config_policy.h40
-rw-r--r--chromium/components/update_client/component.cc101
-rw-r--r--chromium/components/update_client/component.h29
-rw-r--r--chromium/components/update_client/component_patcher_unittest.cc2
-rw-r--r--chromium/components/update_client/component_unpacker_unittest.cc3
-rw-r--r--chromium/components/update_client/crx_downloader_unittest.cc3
-rw-r--r--chromium/components/update_client/crx_update_item.h5
-rw-r--r--chromium/components/update_client/ping_manager.cc4
-rw-r--r--chromium/components/update_client/ping_manager_unittest.cc17
-rw-r--r--chromium/components/update_client/protocol_builder.cc38
-rw-r--r--chromium/components/update_client/protocol_builder_unittest.cc3
-rw-r--r--chromium/components/update_client/request_sender_unittest.cc2
-rw-r--r--chromium/components/update_client/update_checker.cc3
-rw-r--r--chromium/components/update_client/update_checker_unittest.cc397
-rw-r--r--chromium/components/update_client/update_client.h9
-rw-r--r--chromium/components/update_client/update_client_errors.h18
-rw-r--r--chromium/components/update_client/update_client_unittest.cc653
-rw-r--r--chromium/components/update_client/update_engine.cc59
-rw-r--r--chromium/components/update_client/update_engine.h10
-rw-r--r--chromium/components/update_client/url_fetcher_downloader.cc1
-rw-r--r--chromium/components/update_client/url_request_post_interceptor.cc1
-rw-r--r--chromium/components/update_client/utils.cc1
-rw-r--r--chromium/components/update_client/utils.h12
-rw-r--r--chromium/components/update_client/utils_unittest.cc30
-rw-r--r--chromium/components/url_formatter/idn_spoof_checker.cc31
-rw-r--r--chromium/components/url_formatter/top_domains/test_domains.list4
-rw-r--r--chromium/components/url_formatter/top_domains/test_skeletons.gperf4
-rw-r--r--chromium/components/url_formatter/url_fixer.cc44
-rw-r--r--chromium/components/url_formatter/url_fixer_unittest.cc46
-rw-r--r--chromium/components/url_formatter/url_formatter.cc68
-rw-r--r--chromium/components/url_formatter/url_formatter.h4
-rw-r--r--chromium/components/url_formatter/url_formatter_android.cc26
-rw-r--r--chromium/components/url_formatter/url_formatter_unittest.cc162
-rw-r--r--chromium/components/url_pattern_index/BUILD.gn5
-rw-r--r--chromium/components/url_pattern_index/flat/url_pattern_index.fbs11
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index.cc11
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index.h8
-rw-r--r--chromium/components/url_pattern_index/url_pattern_index_unittest.cc3
-rw-r--r--chromium/components/url_pattern_index/url_rule_util.cc13
-rw-r--r--chromium/components/url_pattern_index/url_rule_util.h2
-rw-r--r--chromium/components/url_pattern_index/url_rule_util_unittest.cc70
-rw-r--r--chromium/components/user_manager/BUILD.gn6
-rw-r--r--chromium/components/user_manager/DEPS2
-rw-r--r--chromium/components/user_manager/fake_user_manager.h2
-rw-r--r--chromium/components/user_manager/known_user.cc59
-rw-r--r--chromium/components/user_manager/known_user.h12
-rw-r--r--chromium/components/user_manager/user.cc6
-rw-r--r--chromium/components/user_manager/user.h5
-rw-r--r--chromium/components/user_manager/user_info_impl.cc2
-rw-r--r--chromium/components/user_manager/user_info_impl.h2
-rw-r--r--chromium/components/user_manager/user_manager.cc4
-rw-r--r--chromium/components/user_manager/user_manager.h3
-rw-r--r--chromium/components/user_manager/user_manager_base.cc4
-rw-r--r--chromium/components/user_manager/user_manager_base.h2
-rw-r--r--chromium/components/user_manager/user_names.cc14
-rw-r--r--chromium/components/user_manager/user_names.h14
-rw-r--r--chromium/components/user_manager/user_unittest.cc2
-rw-r--r--chromium/components/variations/BUILD.gn2
-rw-r--r--chromium/components/variations/android/variations_seed_bridge.cc19
-rw-r--r--chromium/components/variations/android/variations_seed_bridge.h8
-rw-r--r--chromium/components/variations/field_trial_config/field_trial_util.cc28
-rw-r--r--chromium/components/variations/field_trial_config/field_trial_util.h3
-rw-r--r--chromium/components/variations/field_trial_config/field_trial_util_unittest.cc11
-rw-r--r--chromium/components/variations/seed_response.cc12
-rw-r--r--chromium/components/variations/seed_response.h27
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.cc12
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator.h7
-rw-r--r--chromium/components/variations/service/variations_field_trial_creator_unittest.cc26
-rw-r--r--chromium/components/variations/service/variations_service.cc25
-rw-r--r--chromium/components/variations/variations_seed_processor_unittest.cc1
-rw-r--r--chromium/components/variations/variations_seed_simulator.cc11
-rw-r--r--chromium/components/variations/variations_seed_simulator_unittest.cc33
-rw-r--r--chromium/components/variations/variations_seed_store.cc49
-rw-r--r--chromium/components/variations/variations_seed_store.h16
-rw-r--r--chromium/components/variations/variations_seed_store_unittest.cc31
-rw-r--r--chromium/components/vector_icons/BUILD.gn2
-rw-r--r--chromium/components/vector_icons/README.md39
-rw-r--r--chromium/components/vector_icons/aggregate_vector_icons.py87
-rw-r--r--chromium/components/vector_icons/cc_macros.h19
-rw-r--r--chromium/components/vector_icons/close_rounded.icon (renamed from chromium/components/vector_icons/close_16.icon)0
-rw-r--r--chromium/components/version_ui_strings_grdp/OWNERS1
-rw-r--r--chromium/components/version_ui_strings_grdp/README.md5
-rw-r--r--chromium/components/visitedlink/browser/visitedlink_master.cc3
-rw-r--r--chromium/components/viz/OWNERS5
-rw-r--r--chromium/components/viz/PRESUBMIT.py10
-rw-r--r--chromium/components/viz/client/BUILD.gn5
-rw-r--r--chromium/components/viz/client/DEPS1
-rw-r--r--chromium/components/viz/client/client_layer_tree_frame_sink.cc29
-rw-r--r--chromium/components/viz/client/client_layer_tree_frame_sink.h8
-rw-r--r--chromium/components/viz/client/client_shared_bitmap_manager.cc138
-rw-r--r--chromium/components/viz/client/client_shared_bitmap_manager.h66
-rw-r--r--chromium/components/viz/client/hit_test_data_provider.h16
-rw-r--r--chromium/components/viz/client/hit_test_data_provider_draw_quad.cc29
-rw-r--r--chromium/components/viz/client/hit_test_data_provider_draw_quad.h2
-rw-r--r--chromium/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc47
-rw-r--r--chromium/components/viz/client/hit_test_data_provider_surface_layer.cc116
-rw-r--r--chromium/components/viz/client/hit_test_data_provider_surface_layer.h39
-rw-r--r--chromium/components/viz/client/hit_test_data_provider_surface_layer_unittest.cc153
-rw-r--r--chromium/components/viz/client/local_surface_id_provider.cc4
-rw-r--r--chromium/components/viz/common/BUILD.gn31
-rw-r--r--chromium/components/viz/common/display/renderer_settings.h1
-rw-r--r--chromium/components/viz/common/display/use_layered_window.cc20
-rw-r--r--chromium/components/viz/common/display/use_layered_window.h20
-rw-r--r--chromium/components/viz/common/features.cc18
-rw-r--r--chromium/components/viz/common/features.h4
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_request.cc8
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_request.h13
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_result.cc10
-rw-r--r--chromium/components/viz/common/frame_sinks/copy_output_result.h5
-rw-r--r--chromium/components/viz/common/gl_helper.cc1
-rw-r--r--chromium/components/viz/common/gl_helper_benchmark.cc9
-rw-r--r--chromium/components/viz/common/gl_helper_scaling.cc1
-rw-r--r--chromium/components/viz/common/gl_helper_unittest.cc12
-rw-r--r--chromium/components/viz/common/gpu/DEPS4
-rw-r--r--chromium/components/viz/common/gpu/vulkan_context_provider.h2
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc51
-rw-r--r--chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h9
-rw-r--r--chromium/components/viz/common/hit_test/DEPS3
-rw-r--r--chromium/components/viz/common/hit_test/aggregated_hit_test_region.h25
-rw-r--r--chromium/components/viz/common/hit_test/hit_test_region_list.cc15
-rw-r--r--chromium/components/viz/common/hit_test/hit_test_region_list.h76
-rw-r--r--chromium/components/viz/common/quads/draw_quad_unittest.cc5
-rw-r--r--chromium/components/viz/common/quads/yuv_video_draw_quad.cc5
-rw-r--r--chromium/components/viz/common/quads/yuv_video_draw_quad.h4
-rw-r--r--chromium/components/viz/common/resources/platform_color.h29
-rw-r--r--chromium/components/viz/common/resources/resource.cc19
-rw-r--r--chromium/components/viz/common/resources/resource.h31
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.cc30
-rw-r--r--chromium/components/viz/common/resources/resource_format_utils.h4
-rw-r--r--chromium/components/viz/common/resources/resource_settings.h3
-rw-r--r--chromium/components/viz/common/resources/resource_sizes_unittest.cc170
-rw-r--r--chromium/components/viz/common/resources/resource_texture_hint.h37
-rw-r--r--chromium/components/viz/common/resources/resource_type.h1
-rw-r--r--chromium/components/viz/common/resources/return_callback.h18
-rw-r--r--chromium/components/viz/common/resources/shared_bitmap_manager.h13
-rw-r--r--chromium/components/viz/common/resources/shared_bitmap_reporter.cc (renamed from chromium/components/password_manager/public/interfaces/sync_password_data.mojom)16
-rw-r--r--chromium/components/viz/common/resources/shared_bitmap_reporter.h34
-rw-r--r--chromium/components/viz/common/resources/transferable_resource.h7
-rw-r--r--chromium/components/viz/common/skia_helper.cc3
-rw-r--r--chromium/components/viz/common/surfaces/child_local_surface_id_allocator.cc21
-rw-r--r--chromium/components/viz/common/surfaces/child_local_surface_id_allocator.h5
-rw-r--r--chromium/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc8
-rw-r--r--chromium/components/viz/common/surfaces/local_surface_id.h1
-rw-r--r--chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.cc19
-rw-r--r--chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.h6
-rw-r--r--chromium/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc60
-rw-r--r--chromium/components/viz/common/switches.cc4
-rw-r--r--chromium/components/viz/common/switches.h1
-rw-r--r--chromium/components/viz/common/yuv_readback_unittest.cc1
-rw-r--r--chromium/components/viz/host/BUILD.gn9
-rw-r--r--chromium/components/viz/host/DEPS4
-rw-r--r--chromium/components/viz/host/client_frame_sink_video_capturer.cc161
-rw-r--r--chromium/components/viz/host/client_frame_sink_video_capturer.h115
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.cc203
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query.h53
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query_fuzzer.cc31
-rw-r--r--chromium/components/viz/host/hit_test/hit_test_query_unittest.cc727
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.cc49
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager.h29
-rw-r--r--chromium/components/viz/host/host_frame_sink_manager_unittest.cc8
-rw-r--r--chromium/components/viz/host/layered_window_updater_impl.cc79
-rw-r--r--chromium/components/viz/host/layered_window_updater_impl.h48
-rw-r--r--chromium/components/viz/host/renderer_settings_creation.cc6
-rw-r--r--chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc7
-rw-r--r--chromium/components/viz/service/BUILD.gn25
-rw-r--r--chromium/components/viz/service/display/DEPS1
-rw-r--r--chromium/components/viz/service/display/bsp_tree_perftest.cc2
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.cc19
-rw-r--r--chromium/components/viz/service/display/ca_layer_overlay.h7
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.cc41
-rw-r--r--chromium/components/viz/service/display/dc_layer_overlay.h12
-rw-r--r--chromium/components/viz/service/display/direct_renderer.cc21
-rw-r--r--chromium/components/viz/service/display/direct_renderer.h13
-rw-r--r--chromium/components/viz/service/display/display.cc113
-rw-r--r--chromium/components/viz/service/display/display.h41
-rw-r--r--chromium/components/viz/service/display/display_client.h9
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.cc972
-rw-r--r--chromium/components/viz/service/display/display_resource_provider.h397
-rw-r--r--chromium/components/viz/service/display/display_resource_provider_unittest.cc1389
-rw-r--r--chromium/components/viz/service/display/display_unittest.cc125
-rw-r--r--chromium/components/viz/service/display/gl_renderer.cc155
-rw-r--r--chromium/components/viz/service/display/gl_renderer.h16
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.cc186
-rw-r--r--chromium/components/viz/service/display/gl_renderer_copier.h2
-rw-r--r--chromium/components/viz/service/display/gl_renderer_unittest.cc512
-rw-r--r--chromium/components/viz/service/display/output_surface.cc72
-rw-r--r--chromium/components/viz/service/display/output_surface.h76
-rw-r--r--chromium/components/viz/service/display/output_surface_client.h11
-rw-r--r--chromium/components/viz/service/display/output_surface_frame.h1
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.cc397
-rw-r--r--chromium/components/viz/service/display/overlay_candidate.h144
-rw-r--r--chromium/components/viz/service/display/overlay_candidate_validator.h4
-rw-r--r--chromium/components/viz/service/display/overlay_processor.cc43
-rw-r--r--chromium/components/viz/service/display/overlay_processor.h34
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.cc22
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_fullscreen.h6
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.cc26
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_single_on_top.h10
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.cc27
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay.h22
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc26
-rw-r--r--chromium/components/viz/service/display/overlay_strategy_underlay_cast.h6
-rw-r--r--chromium/components/viz/service/display/overlay_unittest.cc695
-rw-r--r--chromium/components/viz/service/display/renderer_pixeltest.cc609
-rw-r--r--chromium/components/viz/service/display/scoped_render_pass_texture.h1
-rw-r--r--chromium/components/viz/service/display/shader.cc85
-rw-r--r--chromium/components/viz/service/display/shader_unittest.cc27
-rw-r--r--chromium/components/viz/service/display/skia_output_surface.cc15
-rw-r--r--chromium/components/viz/service/display/skia_output_surface.h98
-rw-r--r--chromium/components/viz/service/display/skia_renderer.cc527
-rw-r--r--chromium/components/viz/service/display/skia_renderer.h57
-rw-r--r--chromium/components/viz/service/display/software_output_device.cc19
-rw-r--r--chromium/components/viz/service/display/software_output_device.h21
-rw-r--r--chromium/components/viz/service/display/software_output_device_client.h26
-rw-r--r--chromium/components/viz/service/display/software_renderer.cc36
-rw-r--r--chromium/components/viz/service/display/software_renderer.h12
-rw-r--r--chromium/components/viz/service/display/software_renderer_unittest.cc60
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.cc36
-rw-r--r--chromium/components/viz/service/display/surface_aggregator.h9
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_perftest.cc4
-rw-r--r--chromium/components/viz/service/display/surface_aggregator_unittest.cc59
-rw-r--r--chromium/components/viz/service/display/vulkan_renderer.cc2
-rw-r--r--chromium/components/viz/service/display/vulkan_renderer.h8
-rw-r--r--chromium/components/viz/service/display_embedder/DEPS12
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc14
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h2
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h2
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc6
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h2
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h2
-rw-r--r--chromium/components/viz/service/display_embedder/display_provider.h2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface.cc81
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface.h25
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc7
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h7
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_mac.h2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h13
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_win.cc2
-rw-r--r--chromium/components/viz/service/display_embedder/gl_output_surface_win.h2
-rw-r--r--chromium/components/viz/service/display_embedder/gpu_display_provider.cc70
-rw-r--r--chromium/components/viz/service/display_embedder/gpu_display_provider.h14
-rw-r--r--chromium/components/viz/service/display_embedder/output_device_backing.cc102
-rw-r--r--chromium/components/viz/service/display_embedder/output_device_backing.h65
-rw-r--r--chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc112
-rw-r--r--chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc50
-rw-r--r--chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h3
-rw-r--r--chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc56
-rw-r--r--chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc79
-rw-r--r--chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h63
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc516
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl.h141
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc398
-rw-r--r--chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h173
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_mac.cc42
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_mac.h19
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm5
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc3
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_win.cc457
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_device_win.h66
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.cc52
-rw-r--r--chromium/components/viz/service/display_embedder/software_output_surface.h15
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.cc (renamed from chromium/components/viz/common/gpu/in_process_context_provider.cc)78
-rw-r--r--chromium/components/viz/service/display_embedder/viz_process_context_provider.h (renamed from chromium/components/viz/common/gpu/in_process_context_provider.h)34
-rw-r--r--chromium/components/viz/service/frame_sinks/DEPS7
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc27
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h22
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc81
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h20
-rw-r--r--chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc54
-rw-r--r--chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc134
-rw-r--r--chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h13
-rw-r--r--chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc38
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc30
-rw-r--r--chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h12
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc19
-rw-r--r--chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h17
-rw-r--r--chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc35
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/OWNERS2
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h13
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc35
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h9
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc120
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc6
-rw-r--r--chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h4
-rw-r--r--chromium/components/viz/service/frame_sinks/video_detector.h1
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.cc37
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl.h15
-rw-r--r--chromium/components/viz/service/gl/gpu_service_impl_unittest.cc4
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator.cc125
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator.h60
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h15
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc714
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_manager.cc23
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_manager.h14
-rw-r--r--chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc68
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.cc13
-rw-r--r--chromium/components/viz/service/main/viz_main_impl.h1
-rw-r--r--chromium/components/viz/service/surfaces/surface.cc3
-rw-r--r--chromium/components/viz/service/surfaces/surface.h2
-rw-r--r--chromium/components/viz/service/surfaces/surface_client.h8
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_deadline.cc2
-rw-r--r--chromium/components/viz/service/surfaces/surface_dependency_deadline.h4
-rw-r--r--chromium/components/viz/service/surfaces/surface_hittest.cc12
-rw-r--r--chromium/components/viz/service/surfaces/surface_hittest_unittest.cc107
-rw-r--r--chromium/components/viz/test/BUILD.gn1
-rw-r--r--chromium/components/web_contents_delegate_android/java/DEPS1
-rw-r--r--chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc8
-rw-r--r--chromium/components/web_contents_delegate_android/web_contents_delegate_android.h6
-rw-r--r--chromium/components/web_modal/web_contents_modal_dialog_manager.h6
-rw-r--r--chromium/components/webcrypto/algorithms/test_helpers.cc2
-rw-r--r--chromium/components/webcrypto/webcrypto_impl.h1
-rw-r--r--chromium/components/webdata/common/web_database_migration_unittest.cc3
-rw-r--r--chromium/components/webdata_services/web_data_service_test_util.h1
-rw-r--r--chromium/components/webrtc_logging/browser/BUILD.gn4
-rw-r--r--chromium/components/webrtc_logging/common/BUILD.gn4
-rw-r--r--chromium/components/wifi/fake_wifi_service.cc1
-rw-r--r--chromium/components/wifi/network_properties.cc1
-rw-r--r--chromium/components/wifi/wifi_service_mac.mm1
-rw-r--r--chromium/components/wifi/wifi_service_win.cc3
-rw-r--r--chromium/components/wifi/wifi_test.cc3
-rw-r--r--chromium/components/zucchini/BUILD.gn70
-rw-r--r--chromium/components/zucchini/README.md2
-rw-r--r--chromium/components/zucchini/disassembler_ztf.cc647
-rw-r--r--chromium/components/zucchini/disassembler_ztf.h201
-rw-r--r--chromium/components/zucchini/disassembler_ztf_unittest.cc402
-rw-r--r--chromium/components/zucchini/element_detection.cc37
-rw-r--r--chromium/components/zucchini/element_detection_unittest.cc91
-rw-r--r--chromium/components/zucchini/equivalence_map_unittest.cc2
-rw-r--r--chromium/components/zucchini/fuzzers/BUILD.gn100
-rwxr-xr-xchromium/components/zucchini/fuzzers/create_seed_file_pair.py73
-rw-r--r--chromium/components/zucchini/fuzzers/disassembler_win32_fuzzer.cc (renamed from chromium/components/zucchini/disassembler_win32_fuzzer.cc)0
-rw-r--r--chromium/components/zucchini/fuzzers/file_pair.proto15
-rwxr-xr-xchromium/components/zucchini/fuzzers/generate_fuzzer_data.py83
-rw-r--r--chromium/components/zucchini/fuzzers/patch_fuzzer.cc (renamed from chromium/components/zucchini/patch_fuzzer.cc)0
-rw-r--r--chromium/components/zucchini/fuzzers/raw_apply_fuzzer.cc59
-rw-r--r--chromium/components/zucchini/fuzzers/raw_gen_fuzzer.cc58
-rw-r--r--chromium/components/zucchini/heuristic_ensemble_matcher.cc5
-rw-r--r--chromium/components/zucchini/image_utils.h68
-rw-r--r--chromium/components/zucchini/image_utils_unittest.cc17
-rw-r--r--chromium/components/zucchini/imposed_ensemble_matcher.cc143
-rw-r--r--chromium/components/zucchini/imposed_ensemble_matcher.h83
-rw-r--r--chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc214
-rw-r--r--chromium/components/zucchini/integration_test.cc2
-rw-r--r--chromium/components/zucchini/main_utils.cc9
-rw-r--r--chromium/components/zucchini/patch_read_write_unittest.cc317
-rw-r--r--chromium/components/zucchini/patch_reader.cc121
-rw-r--r--chromium/components/zucchini/patch_reader.h18
-rw-r--r--chromium/components/zucchini/patch_utils.h8
-rw-r--r--chromium/components/zucchini/patch_writer.cc4
-rw-r--r--chromium/components/zucchini/reference_bytes_mixer.cc48
-rw-r--r--chromium/components/zucchini/reference_bytes_mixer.h91
-rw-r--r--chromium/components/zucchini/target_pool.h3
-rw-r--r--chromium/components/zucchini/type_ztf.h52
-rw-r--r--chromium/components/zucchini/zucchini.h19
-rw-r--r--chromium/components/zucchini/zucchini_apply.cc10
-rw-r--r--chromium/components/zucchini/zucchini_commands.cc25
-rw-r--r--chromium/components/zucchini/zucchini_gen.cc86
-rw-r--r--chromium/components/zucchini/zucchini_gen.h2
-rw-r--r--chromium/components/zucchini/zucchini_tools.cc37
-rw-r--r--chromium/components/zucchini/zucchini_tools.h7
2330 files changed, 78359 insertions, 40116 deletions
diff --git a/chromium/components/BUILD.gn b/chromium/components/BUILD.gn
index bd18adc5959..867b35a7267 100644
--- a/chromium/components/BUILD.gn
+++ b/chromium/components/BUILD.gn
@@ -121,7 +121,6 @@ test("components_unittests") {
"//components/password_manager/core/common:unit_tests",
"//components/password_manager/sync/browser:unit_tests",
"//components/payments/core:unit_tests",
- "//components/physical_web/data_source:unit_tests",
"//components/prefs:unit_tests",
"//components/previews/core:unit_tests",
"//components/proxy_config:unit_tests",
@@ -136,18 +135,19 @@ test("components_unittests") {
"//components/services/unzip:unit_tests",
"//components/sessions:unit_tests",
"//components/signin/core/browser:unit_tests",
- "//components/ssl_config:unit_tests",
"//components/ssl_errors:unit_tests",
"//components/subresource_filter/core/browser:unit_tests",
"//components/subresource_filter/core/common:unit_tests",
+ "//components/subresource_filter/tools:unit_tests",
"//components/suggestions:unit_tests",
"//components/supervised_user_error_page:unit_tests",
"//components/sync:unit_tests",
"//components/sync_bookmarks:unit_tests",
"//components/sync_preferences:unit_tests",
"//components/sync_sessions:unit_tests",
- "//components/task_scheduler_util/common:unit_tests",
+ "//components/task_scheduler_util:unit_tests",
"//components/test:run_all_unittests",
+ "//components/toolbar:unit_tests",
"//components/translate/core/browser:unit_tests",
"//components/translate/core/common:unit_tests",
"//components/translate/core/language_detection:unit_tests",
@@ -223,6 +223,7 @@ test("components_unittests") {
"//components/safe_browsing/common:unit_tests",
"//components/safe_browsing/password_protection:password_protection_unittest",
"//components/safe_browsing/triggers:unit_tests",
+ "//components/security_interstitials/content:unit_tests",
"//components/security_state/content:unit_tests",
"//components/services/heap_profiling:unit_tests",
"//components/spellcheck/browser:unit_tests",
@@ -324,8 +325,8 @@ test("components_unittests") {
deps += [ "//components/browser_watcher:unit_tests" ]
}
- if (enable_basic_printing || enable_print_preview) {
- deps += [ "//components/printing/service:unit_tests" ]
+ if (enable_basic_printing) {
+ deps += [ "//components/services/pdf_compositor:unit_tests" ]
}
if (enable_print_preview) {
deps += [ "//components/pwg_encoder:unit_tests" ]
@@ -337,7 +338,7 @@ test("components_unittests") {
deps += [ "//components/safe_browsing/android:unit_tests_mobile" ]
}
- if (enable_webrtc && !is_ios) {
+ if (!is_ios) {
deps += [
"//components/webrtc_logging/browser:unit_tests",
"//components/webrtc_logging/common:unit_tests",
@@ -531,7 +532,7 @@ if (!is_ios) {
]
}
- if (enable_basic_printing || enable_print_preview) {
+ if (enable_basic_printing) {
sources += [ "printing/test/print_render_frame_helper_browsertest.cc" ]
deps += [ "//components/printing/test:test_support" ]
}
@@ -555,7 +556,7 @@ if (!is_ios) {
"//components/omnibox/browser",
"//components/omnibox/browser:test_support",
"//components/subresource_filter/core/common",
- "//components/subresource_filter/core/common:tools_lib",
+ "//components/subresource_filter/tools:tools_lib",
"//components/test:test_support",
"//components/visitedlink/browser",
"//testing/perf",
diff --git a/chromium/components/OWNERS b/chromium/components/OWNERS
index a071f6ced33..5bbb56254ee 100644
--- a/chromium/components/OWNERS
+++ b/chromium/components/OWNERS
@@ -19,9 +19,8 @@ per-file page_info_strings_grdp=file://chrome/browser/ui/page_info/OWNERS
per-file password_manager_strings.grdp=file://components/password_manager/OWNERS
per-file payments_strings.grdp=file://components/payments/OWNERS
per-file pdf_strings.grdp=raymes@chromium.org
-per-file physical_web_ui_strings.grdp=file://components/physical_web/OWNERS
per-file policy_strings.grdp=file://components/policy/OWNERS
-per-file printing_strings.grdp=file://components/printing/OWNERS
+per-file printing_component_strings.grdp=file://components/printing/OWNERS
per-file reset_password_strings.grdp=file://components/safe_browsing/OWNERS
per-file security_interstitials_strings.grdp=file://components/security_interstitials/OWNERS
per-file security_state_strings.grdp=file://components/security_state/OWNERS
diff --git a/chromium/components/signin/core/account_id/BUILD.gn b/chromium/components/account_id/BUILD.gn
index f769b9044b9..f769b9044b9 100644
--- a/chromium/components/signin/core/account_id/BUILD.gn
+++ b/chromium/components/account_id/BUILD.gn
diff --git a/chromium/components/account_id/DEPS b/chromium/components/account_id/DEPS
new file mode 100644
index 00000000000..7ef15ea0910
--- /dev/null
+++ b/chromium/components/account_id/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+google_apis/gaia",
+]
diff --git a/chromium/components/account_id/OWNERS b/chromium/components/account_id/OWNERS
new file mode 100644
index 00000000000..a0c217c9a7d
--- /dev/null
+++ b/chromium/components/account_id/OWNERS
@@ -0,0 +1,3 @@
+alemate@chromium.org
+rogerta@chromium.org
+xiyuan@chromium.org
diff --git a/chromium/components/signin/core/account_id/account_id.cc b/chromium/components/account_id/account_id.cc
index 735009eeac5..c422c39d4b4 100644
--- a/chromium/components/signin/core/account_id/account_id.cc
+++ b/chromium/components/account_id/account_id.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include <functional>
#include <memory>
diff --git a/chromium/components/signin/core/account_id/account_id.h b/chromium/components/account_id/account_id.h
index a263178d13d..2de8448eb28 100644
--- a/chromium/components/signin/core/account_id/account_id.h
+++ b/chromium/components/account_id/account_id.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 COMPONENTS_SIGNIN_CORE_ACCOUNT_ID_ACCOUNT_ID_H_
-#define COMPONENTS_SIGNIN_CORE_ACCOUNT_ID_ACCOUNT_ID_H_
+#ifndef COMPONENTS_ACCOUNT_ID_ACCOUNT_ID_H_
+#define COMPONENTS_ACCOUNT_ID_ACCOUNT_ID_H_
#include <stddef.h>
@@ -126,4 +126,4 @@ struct hash<AccountId> {
} // namespace BASE_HASH_NAMESPACE
-#endif // COMPONENTS_SIGNIN_CORE_ACCOUNT_ID_ACCOUNT_ID_H_
+#endif // COMPONENTS_ACCOUNT_ID_ACCOUNT_ID_H_
diff --git a/chromium/components/signin/public/interfaces/BUILD.gn b/chromium/components/account_id/interfaces/BUILD.gn
index 98d8a275153..98d8a275153 100644
--- a/chromium/components/signin/public/interfaces/BUILD.gn
+++ b/chromium/components/account_id/interfaces/BUILD.gn
diff --git a/chromium/components/account_id/interfaces/OWNERS b/chromium/components/account_id/interfaces/OWNERS
new file mode 100644
index 00000000000..229dacdd8a4
--- /dev/null
+++ b/chromium/components/account_id/interfaces/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/signin/public/interfaces/account_id.mojom b/chromium/components/account_id/interfaces/account_id.mojom
index f0f9abdc1a3..f0f9abdc1a3 100644
--- a/chromium/components/signin/public/interfaces/account_id.mojom
+++ b/chromium/components/account_id/interfaces/account_id.mojom
diff --git a/chromium/components/signin/public/interfaces/account_id.typemap b/chromium/components/account_id/interfaces/account_id.typemap
index 9d44e045e8e..7de97a2e700 100644
--- a/chromium/components/signin/public/interfaces/account_id.typemap
+++ b/chromium/components/account_id/interfaces/account_id.typemap
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//components/signin/public/interfaces/account_id.mojom"
-public_headers = [ "//components/signin/core/account_id/account_id.h" ]
-traits_headers = [ "//components/signin/public/interfaces/account_id_traits.h" ]
+mojom = "//components/account_id/interfaces/account_id.mojom"
+public_headers = [ "//components/account_id/account_id.h" ]
+traits_headers = [ "//components/account_id/interfaces/account_id_traits.h" ]
public_deps = [
- "//components/signin/core/account_id",
+ "//components/account_id",
]
type_mappings = [
"signin.mojom.AccountType=AccountType",
diff --git a/chromium/components/signin/public/interfaces/account_id_traits.h b/chromium/components/account_id/interfaces/account_id_traits.h
index a2107cbb30b..713c2ac448f 100644
--- a/chromium/components/signin/public/interfaces/account_id_traits.h
+++ b/chromium/components/account_id/interfaces/account_id_traits.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_SIGNIN_PUBLIC_INTERFACES_ACCOUNT_ID_TRAITS_H_
-#define COMPONENTS_SIGNIN_PUBLIC_INTERFACES_ACCOUNT_ID_TRAITS_H_
+#ifndef COMPONENTS_ACCOUNT_ID_INTERFACES_ACCOUNT_ID_TRAITS_H_
+#define COMPONENTS_ACCOUNT_ID_INTERFACES_ACCOUNT_ID_TRAITS_H_
#include <string>
-#include "components/signin/core/account_id/account_id.h"
-#include "components/signin/public/interfaces/account_id.mojom.h"
+#include "components/account_id/account_id.h"
+#include "components/account_id/interfaces/account_id.mojom.h"
namespace mojo {
@@ -27,8 +27,7 @@ struct EnumTraits<signin::mojom::AccountType, AccountType> {
return signin::mojom::AccountType::UNKNOWN;
}
- static bool FromMojom(signin::mojom::AccountType input,
- AccountType* out) {
+ static bool FromMojom(signin::mojom::AccountType input, AccountType* out) {
switch (input) {
case signin::mojom::AccountType::UNKNOWN:
*out = AccountType::UNKNOWN;
@@ -45,7 +44,6 @@ struct EnumTraits<signin::mojom::AccountType, AccountType> {
}
};
-
template <>
struct StructTraits<signin::mojom::AccountIdDataView, AccountId> {
static AccountType account_type(const AccountId& r) {
@@ -66,16 +64,13 @@ struct StructTraits<signin::mojom::AccountIdDataView, AccountId> {
NOTREACHED();
return std::string();
}
- static std::string user_email(const AccountId& r) {
- return r.GetUserEmail();
- }
+ static std::string user_email(const AccountId& r) { return r.GetUserEmail(); }
static bool Read(signin::mojom::AccountIdDataView data, AccountId* out) {
AccountType account_type;
std::string id;
std::string user_email;
- if (!data.ReadAccountType(&account_type) ||
- !data.ReadId(&id) ||
+ if (!data.ReadAccountType(&account_type) || !data.ReadId(&id) ||
!data.ReadUserEmail(&user_email)) {
return false;
}
@@ -108,4 +103,4 @@ struct StructTraits<signin::mojom::AccountIdDataView, AccountId> {
} // namespace mojo
-#endif // COMPONENTS_SIGNIN_PUBLIC_INTERFACES_ACCOUNT_ID_TRAITS_H_
+#endif // COMPONENTS_ACCOUNT_ID_INTERFACES_ACCOUNT_ID_TRAITS_H_
diff --git a/chromium/components/app_modal_strings_grdp/OWNERS b/chromium/components/app_modal_strings_grdp/OWNERS
new file mode 100644
index 00000000000..d092bde2ed3
--- /dev/null
+++ b/chromium/components/app_modal_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/app_modal/OWNERS
diff --git a/chromium/components/app_modal_strings_grdp/README.md b/chromium/components/app_modal_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/app_modal_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/arc/BUILD.gn b/chromium/components/arc/BUILD.gn
index a14b74ff51d..ee4af0d1166 100644
--- a/chromium/components/arc/BUILD.gn
+++ b/chromium/components/arc/BUILD.gn
@@ -77,12 +77,12 @@ static_library("arc") {
"//chromeos",
"//chromeos:login_manager_proto",
"//chromeos:power_manager_proto",
+ "//components/account_id",
"//components/exo",
"//components/google/core/browser",
"//components/onc",
"//components/prefs",
"//components/session_manager/core",
- "//components/signin/core/account_id",
"//components/timers",
"//components/url_formatter",
"//components/user_manager",
@@ -118,10 +118,26 @@ static_library("prefs") {
defines = [ "ARC_IMPLEMENTATION" ]
deps = [
+ ":arc_base_enums",
"//components/prefs",
]
}
+static_library("arc_base_enums") {
+ sources = [
+ "arc_instance_mode.cc",
+ "arc_instance_mode.h",
+ "arc_stop_reason.cc",
+ "arc_stop_reason.h",
+ "arc_supervision_transition.cc",
+ "arc_supervision_transition.h",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
+
static_library("arc_base") {
# TODO(hidehiko): Revisit here and move back some files to "arc"
# on completion to move ArcSession task to ArcSessionManager.
@@ -135,8 +151,6 @@ static_library("arc_base") {
"arc_data_remover.h",
"arc_features.cc",
"arc_features.h",
- "arc_instance_mode.cc",
- "arc_instance_mode.h",
"arc_service_manager.cc",
"arc_service_manager.h",
"arc_session.cc",
@@ -145,14 +159,8 @@ static_library("arc_base") {
"arc_session_impl.h",
"arc_session_runner.cc",
"arc_session_runner.h",
- "arc_stop_reason.cc",
- "arc_stop_reason.h",
"arc_util.cc",
"arc_util.h",
- "connection_holder.h",
- "connection_notifier.cc",
- "connection_notifier.h",
- "connection_observer.h",
]
deps = [
@@ -160,24 +168,55 @@ static_library("arc_base") {
"//base",
"//chromeos",
"//chromeos:login_manager_proto",
+ "//components/account_id",
"//components/keyed_service/content",
"//components/prefs",
- "//components/signin/core/account_id",
"//components/user_manager",
+ "//content/public/common",
"//mojo/edk",
"//ui/aura",
]
public_deps = [
+ ":arc_base_enums",
+ ":connection_holder",
":prefs",
"//components/arc/common",
]
}
-static_library("arc_test_support") {
+source_set("connection_holder") {
+ sources = [
+ "connection_holder.h",
+ "connection_notifier.cc",
+ "connection_notifier.h",
+ "connection_observer.h",
+ "mojo_channel.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ ]
+}
+
+static_library("notification_test_support") {
testonly = true
sources = [
"test/connection_holder_util.h",
+ "test/fake_notifications_instance.cc",
+ "test/fake_notifications_instance.h",
+ ]
+
+ public_deps = [
+ ":connection_holder",
+ "//components/arc/common:notifications",
+ ]
+}
+
+static_library("arc_test_support") {
+ testonly = true
+ sources = [
"test/fake_accessibility_helper_instance.cc",
"test/fake_accessibility_helper_instance.h",
"test/fake_app_instance.cc",
@@ -194,8 +233,6 @@ static_library("arc_test_support") {
"test/fake_file_system_instance.h",
"test/fake_intent_helper_instance.cc",
"test/fake_intent_helper_instance.h",
- "test/fake_notifications_instance.cc",
- "test/fake_notifications_instance.h",
"test/fake_policy_instance.cc",
"test/fake_policy_instance.h",
"test/fake_power_instance.cc",
@@ -214,6 +251,7 @@ static_library("arc_test_support") {
public_deps = [
":arc",
+ ":notification_test_support",
]
deps = [
@@ -257,9 +295,9 @@ source_set("unit_tests") {
"//chromeos",
"//chromeos:power_manager_proto",
"//chromeos:test_support_without_gmock",
+ "//components/account_id",
"//components/keyed_service/content",
"//components/prefs:test_support",
- "//components/signin/core/account_id",
"//components/user_manager",
"//components/user_manager:test_support",
"//content/public/common",
diff --git a/chromium/components/arc/DEPS b/chromium/components/arc/DEPS
index 320c49e4fe5..3839f7c4845 100644
--- a/chromium/components/arc/DEPS
+++ b/chromium/components/arc/DEPS
@@ -3,12 +3,12 @@ include_rules = [
"+chromeos/chromeos_switches.h",
"+chromeos/cryptohome",
"+chromeos/dbus",
+ "+components/account_id",
"+components/exo",
"+components/keyed_service",
"+components/pref_registry",
"+components/prefs",
"+components/session_manager/core",
- "+components/signin/core/account_id",
"+components/timers",
"+components/user_manager",
"+media/base/video_codecs.h",
@@ -22,6 +22,11 @@ include_rules = [
]
specific_include_rules = {
+ "arc_bridge_host_impl.cc": [
+ "+ash/public",
+ "+content/public/common/service_manager_connection.h",
+ "+services/service_manager/public",
+ ],
"arc_util.cc": [
"+ui/aura",
],
diff --git a/chromium/components/arc/arc_bridge_host_impl.cc b/chromium/components/arc/arc_bridge_host_impl.cc
index 5b42f0a1bc7..c59d2db6b9e 100644
--- a/chromium/components/arc/arc_bridge_host_impl.cc
+++ b/chromium/components/arc/arc_bridge_host_impl.cc
@@ -7,66 +7,17 @@
#include <algorithm>
#include <utility>
+#include "ash/public/interfaces/ash_message_center_controller.mojom.h"
+#include "ash/public/interfaces/constants.mojom.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "components/arc/arc_bridge_service.h"
+#include "components/arc/mojo_channel.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/service_manager/public/cpp/connector.h"
namespace arc {
-// Thin interface to wrap InterfacePtr<T> with type erasure.
-class ArcBridgeHostImpl::MojoChannel {
- public:
- virtual ~MojoChannel() = default;
-
- protected:
- MojoChannel() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MojoChannel);
-};
-
-namespace {
-
-// The thin wrapper for InterfacePtr<T>, where T is one of ARC mojo Instance
-// class.
-template <typename InstanceType, typename HostType>
-class MojoChannelImpl : public ArcBridgeHostImpl::MojoChannel {
- public:
- MojoChannelImpl(ConnectionHolder<InstanceType, HostType>* holder,
- mojo::InterfacePtr<InstanceType> ptr)
- : holder_(holder), ptr_(std::move(ptr)) {
- // Delay registration to the ConnectionHolder until the version is ready.
- }
-
- ~MojoChannelImpl() override { holder_->CloseInstance(ptr_.get()); }
-
- void set_connection_error_handler(base::OnceClosure error_handler) {
- ptr_.set_connection_error_handler(std::move(error_handler));
- }
-
- void QueryVersion() {
- // Note: the callback will not be called if |ptr_| is destroyed.
- ptr_.QueryVersion(
- base::Bind(&MojoChannelImpl::OnVersionReady, base::Unretained(this)));
- }
-
- private:
- void OnVersionReady(uint32_t unused_version) {
- holder_->SetInstance(ptr_.get(), ptr_.version());
- }
-
- // Owned by ArcBridgeService.
- ConnectionHolder<InstanceType, HostType>* const holder_;
-
- // Put as a last member to ensure that any callback tied to the |ptr_|
- // is not invoked.
- mojo::InterfacePtr<InstanceType> ptr_;
-
- DISALLOW_COPY_AND_ASSIGN(MojoChannelImpl);
-};
-
-} // namespace
-
ArcBridgeHostImpl::ArcBridgeHostImpl(ArcBridgeService* arc_bridge_service,
mojom::ArcBridgeInstancePtr instance)
: arc_bridge_service_(arc_bridge_service),
@@ -159,6 +110,12 @@ void ArcBridgeHostImpl::OnImeInstanceReady(mojom::ImeInstancePtr ime_ptr) {
OnInstanceReady(arc_bridge_service_->ime(), std::move(ime_ptr));
}
+void ArcBridgeHostImpl::OnInputMethodManagerInstanceReady(
+ mojom::InputMethodManagerInstancePtr input_method_manager_ptr) {
+ OnInstanceReady(arc_bridge_service_->input_method_manager(),
+ std::move(input_method_manager_ptr));
+}
+
void ArcBridgeHostImpl::OnIntentHelperInstanceReady(
mojom::IntentHelperInstancePtr intent_helper_ptr) {
OnInstanceReady(arc_bridge_service_->intent_helper(),
@@ -192,8 +149,13 @@ void ArcBridgeHostImpl::OnNetInstanceReady(mojom::NetInstancePtr net_ptr) {
void ArcBridgeHostImpl::OnNotificationsInstanceReady(
mojom::NotificationsInstancePtr notifications_ptr) {
- OnInstanceReady(arc_bridge_service_->notifications(),
- std::move(notifications_ptr));
+ // Forward notification instance to ash.
+ ash::mojom::AshMessageCenterControllerPtr ash_message_center_controller;
+ content::ServiceManagerConnection::GetForProcess()
+ ->GetConnector()
+ ->BindInterface(ash::mojom::kServiceName, &ash_message_center_controller);
+ ash_message_center_controller->SetArcNotificationsInstance(
+ std::move(notifications_ptr));
}
void ArcBridgeHostImpl::OnObbMounterInstanceReady(
@@ -320,7 +282,7 @@ void ArcBridgeHostImpl::OnInstanceReady(
// closed on ArcBridgeHost/Instance closing or the ArcBridgeHostImpl's
// destruction.
auto* channel =
- new MojoChannelImpl<InstanceType, HostType>(holder, std::move(ptr));
+ new MojoChannel<InstanceType, HostType>(holder, std::move(ptr));
mojo_channels_.emplace_back(channel);
// Since |channel| is managed by |mojo_channels_|, its lifetime is shorter
@@ -334,11 +296,11 @@ void ArcBridgeHostImpl::OnInstanceReady(
channel->QueryVersion();
}
-void ArcBridgeHostImpl::OnChannelClosed(MojoChannel* channel) {
+void ArcBridgeHostImpl::OnChannelClosed(MojoChannelBase* channel) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
mojo_channels_.erase(
std::find_if(mojo_channels_.begin(), mojo_channels_.end(),
- [channel](std::unique_ptr<MojoChannel>& ptr) {
+ [channel](std::unique_ptr<MojoChannelBase>& ptr) {
return ptr.get() == channel;
}));
}
diff --git a/chromium/components/arc/arc_bridge_host_impl.h b/chromium/components/arc/arc_bridge_host_impl.h
index 2738a94f7f3..07ca1b8d308 100644
--- a/chromium/components/arc/arc_bridge_host_impl.h
+++ b/chromium/components/arc/arc_bridge_host_impl.h
@@ -18,6 +18,7 @@
namespace arc {
class ArcBridgeService;
+class MojoChannelBase;
// Implementation of the ArcBridgeHost.
// The lifetime of ArcBridgeHost and ArcBridgeInstance mojo channels are tied
@@ -30,9 +31,6 @@ class ArcBridgeService;
// Note that ArcBridgeService must be alive while ArcBridgeHostImpl is alive.
class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
public:
- // Interface to keep the Mojo channel InterfacePtr.
- class MojoChannel;
-
ArcBridgeHostImpl(ArcBridgeService* arc_bridge_service,
mojom::ArcBridgeInstancePtr instance);
~ArcBridgeHostImpl() override;
@@ -62,6 +60,8 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
void OnFileSystemInstanceReady(
mojom::FileSystemInstancePtr file_system_ptr) override;
void OnImeInstanceReady(mojom::ImeInstancePtr ime_ptr) override;
+ void OnInputMethodManagerInstanceReady(
+ mojom::InputMethodManagerInstancePtr input_method_manager_ptr) override;
void OnIntentHelperInstanceReady(
mojom::IntentHelperInstancePtr intent_helper_ptr) override;
void OnKioskInstanceReady(mojom::KioskInstancePtr kiosk_ptr) override;
@@ -114,7 +114,7 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
mojo::InterfacePtr<InstanceType> ptr);
// Called if one of the established channels is closed.
- void OnChannelClosed(MojoChannel* channel);
+ void OnChannelClosed(MojoChannelBase* channel);
THREAD_CHECKER(thread_checker_);
@@ -126,7 +126,7 @@ class ArcBridgeHostImpl : public mojom::ArcBridgeHost {
// Put as a last member to ensure that any callback tied to the elements
// is not invoked.
- std::vector<std::unique_ptr<MojoChannel>> mojo_channels_;
+ std::vector<std::unique_ptr<MojoChannelBase>> mojo_channels_;
DISALLOW_COPY_AND_ASSIGN(ArcBridgeHostImpl);
};
diff --git a/chromium/components/arc/arc_bridge_service.h b/chromium/components/arc/arc_bridge_service.h
index d7cd39501db..43bd651aaa1 100644
--- a/chromium/components/arc/arc_bridge_service.h
+++ b/chromium/components/arc/arc_bridge_service.h
@@ -40,6 +40,8 @@ class FileSystemHost;
class FileSystemInstance;
class ImeHost;
class ImeInstance;
+class InputMethodManagerHost;
+class InputMethodManagerInstance;
class IntentHelperHost;
class IntentHelperInstance;
class KioskHost;
@@ -51,8 +53,6 @@ class MidisHost;
class MidisInstance;
class NetHost;
class NetInstance;
-class NotificationsHost;
-class NotificationsInstance;
class ObbMounterHost;
class ObbMounterInstance;
class OemCryptoHost;
@@ -146,6 +146,11 @@ class ArcBridgeService {
return &file_system_;
}
ConnectionHolder<mojom::ImeInstance, mojom::ImeHost>* ime() { return &ime_; }
+ ConnectionHolder<mojom::InputMethodManagerInstance,
+ mojom::InputMethodManagerHost>*
+ input_method_manager() {
+ return &input_method_manager_;
+ }
ConnectionHolder<mojom::IntentHelperInstance, mojom::IntentHelperHost>*
intent_helper() {
return &intent_helper_;
@@ -163,10 +168,6 @@ class ArcBridgeService {
return &midis_;
}
ConnectionHolder<mojom::NetInstance, mojom::NetHost>* net() { return &net_; }
- ConnectionHolder<mojom::NotificationsInstance, mojom::NotificationsHost>*
- notifications() {
- return &notifications_;
- }
ConnectionHolder<mojom::ObbMounterInstance, mojom::ObbMounterHost>*
obb_mounter() {
return &obb_mounter_;
@@ -250,6 +251,9 @@ class ArcBridgeService {
ConnectionHolder<mojom::FileSystemInstance, mojom::FileSystemHost>
file_system_;
ConnectionHolder<mojom::ImeInstance, mojom::ImeHost> ime_;
+ ConnectionHolder<mojom::InputMethodManagerInstance,
+ mojom::InputMethodManagerHost>
+ input_method_manager_;
ConnectionHolder<mojom::IntentHelperInstance, mojom::IntentHelperHost>
intent_helper_;
ConnectionHolder<mojom::KioskInstance, mojom::KioskHost> kiosk_;
@@ -257,8 +261,6 @@ class ArcBridgeService {
ConnectionHolder<mojom::MetricsInstance, mojom::MetricsHost> metrics_;
ConnectionHolder<mojom::MidisInstance, mojom::MidisHost> midis_;
ConnectionHolder<mojom::NetInstance, mojom::NetHost> net_;
- ConnectionHolder<mojom::NotificationsInstance, mojom::NotificationsHost>
- notifications_;
ConnectionHolder<mojom::ObbMounterInstance, mojom::ObbMounterHost>
obb_mounter_;
ConnectionHolder<mojom::OemCryptoInstance, mojom::OemCryptoHost> oemcrypto_;
diff --git a/chromium/components/arc/arc_data_remover_unittest.cc b/chromium/components/arc/arc_data_remover_unittest.cc
index d2ea11ea977..39693b8040b 100644
--- a/chromium/components/arc/arc_data_remover_unittest.cc
+++ b/chromium/components/arc/arc_data_remover_unittest.cc
@@ -12,9 +12,9 @@
#include "chromeos/cryptohome/cryptohome_parameters.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
+#include "components/account_id/account_id.h"
#include "components/arc/arc_prefs.h"
#include "components/prefs/testing_pref_service.h"
-#include "components/signin/core/account_id/account_id.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace arc {
diff --git a/chromium/components/arc/arc_features.cc b/chromium/components/arc/arc_features.cc
index 355a78b04ec..b87808fd3c1 100644
--- a/chromium/components/arc/arc_features.cc
+++ b/chromium/components/arc/arc_features.cc
@@ -8,7 +8,7 @@ namespace arc {
// Controls whether ARC is available for CHILD accounts.
const base::Feature kAvailableForChildAccountFeature{
- "ArcAvailableForChildAccount", base::FEATURE_DISABLED_BY_DEFAULT};
+ "ArcAvailableForChildAccount", base::FEATURE_ENABLED_BY_DEFAULT};
// Controls ACTION_BOOT_COMPLETED broadcast for third party applications on ARC.
// When disabled, third party apps will not receive this broadcast.
@@ -16,6 +16,19 @@ const base::Feature kBootCompletedBroadcastFeature {
"ArcBootCompletedBroadcast", base::FEATURE_ENABLED_BY_DEFAULT
};
+// Controls whether we should delete all ARC data before transitioning a user
+// from regular to child account.
+const base::Feature kCleanArcDataOnRegularToChildTransitionFeature{
+ "ArcCleanDataOnRegularToChildTransition", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Controls whether ARC handles child->regular account transition.
+const base::Feature kEnableChildToRegularTransitionFeature{
+ "ArcEnableChildToRegularTransition", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Controls whether ARC handles regular->child account transition.
+const base::Feature kEnableRegularToChildTransitionFeature{
+ "ArcEnableRegularToChildTransition", base::FEATURE_ENABLED_BY_DEFAULT};
+
// Controls experimental native bridge feature for ARC.
const base::Feature kNativeBridgeExperimentFeature {
"ArcNativeBridgeExperiment", base::FEATURE_ENABLED_BY_DEFAULT
diff --git a/chromium/components/arc/arc_features.h b/chromium/components/arc/arc_features.h
index 2489c6949ad..25fd5a603a7 100644
--- a/chromium/components/arc/arc_features.h
+++ b/chromium/components/arc/arc_features.h
@@ -14,6 +14,9 @@ namespace arc {
// Please keep alphabetized.
extern const base::Feature kAvailableForChildAccountFeature;
extern const base::Feature kBootCompletedBroadcastFeature;
+extern const base::Feature kCleanArcDataOnRegularToChildTransitionFeature;
+extern const base::Feature kEnableChildToRegularTransitionFeature;
+extern const base::Feature kEnableRegularToChildTransitionFeature;
extern const base::Feature kNativeBridgeExperimentFeature;
extern const base::Feature kUsbHostFeature;
extern const base::Feature kVpnFeature;
diff --git a/chromium/components/arc/arc_prefs.cc b/chromium/components/arc/arc_prefs.cc
index d60f5d50f3d..7527b09f3b2 100644
--- a/chromium/components/arc/arc_prefs.cc
+++ b/chromium/components/arc/arc_prefs.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "components/arc/arc_prefs.h"
+#include "components/arc/arc_supervision_transition.h"
#include <string>
@@ -40,6 +41,9 @@ const char kArcInitialSettingsPending[] = "arc.initial.settings.pending";
// A preference that indicated whether Android reported it's compliance status
// with provided policies. This is used only as a signal to start Android kiosk.
const char kArcPolicyComplianceReported[] = "arc.policy_compliance_reported";
+// A preference that indicates that a supervision transition is necessary, in
+// response to a CHILD_ACCOUNT transiting to a REGULAR_ACCOUNT or vice-versa.
+const char kArcSupervisionTransition[] = "arc.supervision_transition";
// A preference that indicates that user accepted PlayStore terms.
const char kArcTermsAccepted[] = "arc.terms.accepted";
// A preference that indicates that ToS was shown in OOBE flow.
@@ -61,6 +65,9 @@ const char kArcSetNotificationsEnabledDeferred[] =
"arc.set_notifications_enabled_deferred";
// A preference that indicates status of Android sign-in.
const char kArcSignedIn[] = "arc.signedin";
+// A preference that indicates that ARC skipped the setup UI flows that
+// contain a notice related to reporting of diagnostic information.
+const char kArcSkippedReportingNotice[] = "arc.skipped.reporting.notice";
// A preference that indicates an ARC comaptible filesystem was chosen for
// the user directory (i.e., the user finished required migration.)
const char kArcCompatibleFilesystemChosen[] =
@@ -99,6 +106,10 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
// This is used to decide whether migration from ecryptfs to ext4 is allowed.
registry->RegisterIntegerPref(prefs::kEcryptfsMigrationStrategy, 0);
+ registry->RegisterIntegerPref(
+ kArcSupervisionTransition,
+ static_cast<int>(ArcSupervisionTransition::NO_TRANSITION));
+
// Sorted in lexicographical order.
registry->RegisterBooleanPref(kArcDataRemoveRequested, false);
registry->RegisterBooleanPref(kArcEnabled, false);
@@ -106,6 +117,7 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(kArcPaiStarted, false);
registry->RegisterBooleanPref(kArcPolicyComplianceReported, false);
registry->RegisterBooleanPref(kArcSignedIn, false);
+ registry->RegisterBooleanPref(kArcSkippedReportingNotice, false);
registry->RegisterBooleanPref(kArcTermsAccepted, false);
registry->RegisterBooleanPref(kArcTermsShownInOobe, false);
registry->RegisterBooleanPref(kArcVoiceInteractionValuePropAccepted, false);
diff --git a/chromium/components/arc/arc_prefs.h b/chromium/components/arc/arc_prefs.h
index 99fd759c647..20adee6b35f 100644
--- a/chromium/components/arc/arc_prefs.h
+++ b/chromium/components/arc/arc_prefs.h
@@ -29,6 +29,8 @@ ARC_EXPORT extern const char kArcPushInstallAppsRequested[];
ARC_EXPORT extern const char kArcPushInstallAppsPending[];
ARC_EXPORT extern const char kArcSetNotificationsEnabledDeferred[];
ARC_EXPORT extern const char kArcSignedIn[];
+ARC_EXPORT extern const char kArcSkippedReportingNotice[];
+ARC_EXPORT extern const char kArcSupervisionTransition[];
ARC_EXPORT extern const char kArcCompatibleFilesystemChosen[];
ARC_EXPORT extern const char kArcVoiceInteractionValuePropAccepted[];
ARC_EXPORT extern const char kEcryptfsMigrationStrategy[];
diff --git a/chromium/components/arc/arc_service_manager.h b/chromium/components/arc/arc_service_manager.h
index 1e84e21d97b..dc79627c7fc 100644
--- a/chromium/components/arc/arc_service_manager.h
+++ b/chromium/components/arc/arc_service_manager.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/threading/thread_checker.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
namespace content {
class BrowserContext;
diff --git a/chromium/components/arc/arc_session_impl.cc b/chromium/components/arc/arc_session_impl.cc
index a3d733afaad..e9b77cfd837 100644
--- a/chromium/components/arc/arc_session_impl.cc
+++ b/chromium/components/arc/arc_session_impl.cc
@@ -114,7 +114,7 @@ class ArcSessionDelegateImpl : public ArcSessionImpl::Delegate {
// connected socket's file descriptor. This is designed to run on a
// blocking thread.
static mojo::ScopedMessagePipeHandle ConnectMojoInternal(
- mojo::edk::ScopedPlatformHandle socket_fd,
+ mojo::edk::ScopedInternalPlatformHandle socket_fd,
base::ScopedFD cancel_fd);
// Called when Mojo connection is established or canceled.
@@ -150,10 +150,10 @@ base::ScopedFD ArcSessionDelegateImpl::ConnectMojo(
// For production, |socket_fd| passed from session_manager is either a valid
// socket or a valid file descriptor (/dev/null). For testing, |socket_fd|
// might be invalid.
- mojo::edk::PlatformHandle raw_handle(socket_fd.release());
+ mojo::edk::InternalPlatformHandle raw_handle(socket_fd.release());
raw_handle.needs_connection = true;
- mojo::edk::ScopedPlatformHandle mojo_socket_fd(raw_handle);
+ mojo::edk::ScopedInternalPlatformHandle mojo_socket_fd(raw_handle);
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock()},
base::BindOnce(&ArcSessionDelegateImpl::ConnectMojoInternal,
@@ -165,14 +165,14 @@ base::ScopedFD ArcSessionDelegateImpl::ConnectMojo(
// static
mojo::ScopedMessagePipeHandle ArcSessionDelegateImpl::ConnectMojoInternal(
- mojo::edk::ScopedPlatformHandle socket_fd,
+ mojo::edk::ScopedInternalPlatformHandle socket_fd,
base::ScopedFD cancel_fd) {
if (!WaitForSocketReadable(socket_fd.get().handle, cancel_fd.get())) {
VLOG(1) << "Mojo connection was cancelled.";
return mojo::ScopedMessagePipeHandle();
}
- mojo::edk::ScopedPlatformHandle scoped_fd;
+ mojo::edk::ScopedInternalPlatformHandle scoped_fd;
if (!mojo::edk::ServerAcceptConnection(socket_fd, &scoped_fd,
/* check_peer_user = */ false) ||
!scoped_fd.is_valid()) {
@@ -192,7 +192,7 @@ mojo::ScopedMessagePipeHandle ArcSessionDelegateImpl::ConnectMojoInternal(
mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
channel_pair.PassServerHandle()));
- std::vector<mojo::edk::ScopedPlatformHandle> handles;
+ std::vector<mojo::edk::ScopedInternalPlatformHandle> handles;
handles.emplace_back(channel_pair.PassClientHandle());
// We need to send the length of the message as a single byte, so make sure it
diff --git a/chromium/components/arc/arc_session_impl_unittest.cc b/chromium/components/arc/arc_session_impl_unittest.cc
index 379eb47c007..15eb937bb34 100644
--- a/chromium/components/arc/arc_session_impl_unittest.cc
+++ b/chromium/components/arc/arc_session_impl_unittest.cc
@@ -18,9 +18,9 @@
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
+#include "components/account_id/account_id.h"
#include "components/arc/arc_session_impl.h"
#include "components/arc/test/fake_arc_bridge_host.h"
-#include "components/signin/core/account_id/account_id.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/arc/arc_supervision_transition.cc b/chromium/components/arc/arc_supervision_transition.cc
new file mode 100644
index 00000000000..d9b03ffdd8d
--- /dev/null
+++ b/chromium/components/arc/arc_supervision_transition.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/arc/arc_supervision_transition.h"
+#include "base/logging.h"
+
+namespace arc {
+
+std::ostream& operator<<(std::ostream& os,
+ ArcSupervisionTransition supervision_transition) {
+ switch (supervision_transition) {
+ case ArcSupervisionTransition::NO_TRANSITION:
+ return os << "NO_TRANSITION";
+ case ArcSupervisionTransition::CHILD_TO_REGULAR:
+ return os << "CHILD_TO_REGULAR";
+ case ArcSupervisionTransition::REGULAR_TO_CHILD:
+ return os << "REGULAR_TO_CHILD";
+ }
+ NOTREACHED() << "Unexpected value for ArcSupervisionTransition: "
+ << static_cast<int>(supervision_transition);
+
+ return os << "ArcSupervisionTransition("
+ << static_cast<int>(supervision_transition) << ")";
+}
+
+} // namespace arc
diff --git a/chromium/components/arc/arc_supervision_transition.h b/chromium/components/arc/arc_supervision_transition.h
new file mode 100644
index 00000000000..bc3fb9fcb0f
--- /dev/null
+++ b/chromium/components/arc/arc_supervision_transition.h
@@ -0,0 +1,31 @@
+// 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 COMPONENTS_ARC_ARC_SUPERVISION_TRANSITION_H_
+#define COMPONENTS_ARC_ARC_SUPERVISION_TRANSITION_H_
+
+#include <ostream>
+
+namespace arc {
+
+// These values must be kept in sync with
+// UpgradeArcInstanceRequest.SupervisionTransition in
+// third_party/cros_system_api/dbus/arc.proto.
+enum class ArcSupervisionTransition : int {
+ // No transition necessary.
+ NO_TRANSITION = 0,
+ // Child user is transitioning to a regular account, need to lift
+ // supervision.
+ CHILD_TO_REGULAR = 1,
+ // Regular user is transitioning to a child account, need to enable
+ // supervision.
+ REGULAR_TO_CHILD = 2,
+};
+
+std::ostream& operator<<(std::ostream& os,
+ ArcSupervisionTransition supervisionTransition);
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_ARC_SUPERVISION_TRANSITION_H_
diff --git a/chromium/components/arc/arc_util.cc b/chromium/components/arc/arc_util.cc
index b1925365724..880db840e9b 100644
--- a/chromium/components/arc/arc_util.cc
+++ b/chromium/components/arc/arc_util.cc
@@ -176,8 +176,7 @@ bool IsArcAllowedForUser(const user_manager::User* user) {
}
bool IsArcOptInVerificationDisabled() {
- const auto* command_line = base::CommandLine::ForCurrentProcess();
- return command_line->HasSwitch(
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
chromeos::switches::kDisableArcOptInVerification);
}
@@ -202,4 +201,9 @@ void SetArcCpuRestriction(bool do_restrict) {
state, base::BindOnce(SetArcCpuRestrictionCallback, state));
}
+bool IsArcDataCleanupOnStartRequested() {
+ return base::CommandLine::ForCurrentProcess()->HasSwitch(
+ chromeos::switches::kArcDataCleanupOnStart);
+}
+
} // namespace arc
diff --git a/chromium/components/arc/arc_util.h b/chromium/components/arc/arc_util.h
index 5af1de11355..c706565aa15 100644
--- a/chromium/components/arc/arc_util.h
+++ b/chromium/components/arc/arc_util.h
@@ -97,6 +97,9 @@ bool IsArcOptInVerificationDisabled();
// |window| is nullptr, returns false.
bool IsArcAppWindow(aura::Window* window);
+// Returns true if data clean up is requested for each ARC start.
+bool IsArcDataCleanupOnStartRequested();
+
// Adjusts the amount of CPU the ARC instance is allowed to use. When
// |do_restrict| is true, the limit is adjusted so ARC can only use tightly
// restricted CPU resources.
diff --git a/chromium/components/arc/arc_util_unittest.cc b/chromium/components/arc/arc_util_unittest.cc
index f83a51d9fb8..3fc9482a4a2 100644
--- a/chromium/components/arc/arc_util_unittest.cc
+++ b/chromium/components/arc/arc_util_unittest.cc
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/test/scoped_feature_list.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/fake_user_manager.h"
#include "components/user_manager/scoped_user_manager.h"
#include "components/user_manager/user.h"
@@ -198,7 +198,7 @@ TEST_F(ArcUtilTest, IsArcAllowedForUser) {
{user_manager::USER_TYPE_PUBLIC_ACCOUNT, true},
{user_manager::USER_TYPE_SUPERVISED, false},
{user_manager::USER_TYPE_KIOSK_APP, false},
- {user_manager::USER_TYPE_CHILD, false},
+ {user_manager::USER_TYPE_CHILD, true},
{user_manager::USER_TYPE_ARC_KIOSK_APP, true},
{user_manager::USER_TYPE_ACTIVE_DIRECTORY, true},
};
diff --git a/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc b/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
index f778315c2ff..dfb74234812 100644
--- a/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_struct_traits.cc
@@ -37,13 +37,31 @@ struct AdvertisementEntry {
virtual void AddTo(device::BluetoothAdvertisement::Data* data) {}
};
+struct ServiceUUID16Entry : public AdvertisementEntry {
+ std::vector<uint16_t> service_uuids_16;
+
+ ~ServiceUUID16Entry() override {}
+
+ void AddTo(device::BluetoothAdvertisement::Data* data) override {
+ auto string_uuids = data->service_uuids();
+ if (string_uuids == nullptr)
+ string_uuids = std::make_unique<std::vector<std::string>>();
+ for (const auto& uuid : service_uuids_16) {
+ string_uuids->emplace_back(base::StringPrintf("%04x", uuid));
+ }
+ data->set_service_uuids(std::move(string_uuids));
+ }
+};
+
struct ServiceUUIDEntry : public AdvertisementEntry {
std::vector<device::BluetoothUUID> service_uuids;
~ServiceUUIDEntry() override {}
void AddTo(device::BluetoothAdvertisement::Data* data) override {
- auto string_uuids = std::make_unique<std::vector<std::string>>();
+ auto string_uuids = data->service_uuids();
+ if (string_uuids == nullptr)
+ string_uuids = std::make_unique<std::vector<std::string>>();
for (const auto& uuid : service_uuids) {
string_uuids->emplace_back(uuid.value());
}
@@ -167,6 +185,15 @@ struct UnionTraits<arc::mojom::BluetoothAdvertisingDataDataView,
static bool Read(arc::mojom::BluetoothAdvertisingDataDataView data,
std::unique_ptr<AdvertisementEntry>* output) {
switch (data.tag()) {
+ case arc::mojom::BluetoothAdvertisingDataDataView::Tag::
+ SERVICE_UUIDS_16: {
+ std::unique_ptr<ServiceUUID16Entry> service_uuids_16 =
+ std::make_unique<ServiceUUID16Entry>();
+ if (!data.ReadServiceUuids16(&service_uuids_16->service_uuids_16))
+ return false;
+ *output = std::move(service_uuids_16);
+ break;
+ }
case arc::mojom::BluetoothAdvertisingDataDataView::Tag::SERVICE_UUIDS: {
std::unique_ptr<ServiceUUIDEntry> service_uuids =
std::make_unique<ServiceUUIDEntry>();
diff --git a/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc b/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
index 8532e5f4080..933461ca1ee 100644
--- a/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_struct_traits_unittest.cc
@@ -74,9 +74,14 @@ TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisement) {
arc::mojom::BluetoothAdvertisement::New();
std::vector<arc::mojom::BluetoothAdvertisingDataPtr> adv_data;
- // Create service UUIDs.
+ // Create 16bit service UUIDs.
arc::mojom::BluetoothAdvertisingDataPtr data =
arc::mojom::BluetoothAdvertisingData::New();
+ data->set_service_uuids_16({kUuid16});
+ adv_data.push_back(std::move(data));
+
+ // Create service UUIDs.
+ data = arc::mojom::BluetoothAdvertisingData::New();
std::vector<device::BluetoothUUID> service_uuids;
service_uuids.push_back((device::BluetoothUUID(kUuidStr)));
data->set_service_uuids(service_uuids);
@@ -110,8 +115,9 @@ TEST(BluetoothStructTraitsTest, DeserializeBluetoothAdvertisement) {
std::unique_ptr<device::BluetoothAdvertisement::UUIDList> converted_uuids =
advertisement->service_uuids();
- EXPECT_EQ(converted_uuids->size(), 1U);
- EXPECT_EQ(*converted_uuids->begin(), kUuidStr);
+ EXPECT_EQ(converted_uuids->size(), 2U);
+ EXPECT_EQ(converted_uuids->at(0), kUuid16Str);
+ EXPECT_EQ(converted_uuids->at(1), kUuidStr);
std::unique_ptr<device::BluetoothAdvertisement::ServiceData>
converted_service = advertisement->service_data();
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
index dd4c6137a22..9581d5138fc 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters.cc
@@ -77,44 +77,6 @@ std::string TypeConverter<std::string, arc::mojom::BluetoothAddress>::Convert(
}
// static
-arc::mojom::BluetoothGattStatus
-TypeConverter<arc::mojom::BluetoothGattStatus,
- device::BluetoothGattService::GattErrorCode>::
- Convert(const device::BluetoothGattService::GattErrorCode& error_code) {
- arc::mojom::BluetoothGattStatus ret;
-
- switch (error_code) {
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_INVALID_LENGTH:
- ret = arc::mojom::BluetoothGattStatus::GATT_INVALID_ATTRIBUTE_LENGTH;
- break;
-
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_NOT_PERMITTED:
- ret = arc::mojom::BluetoothGattStatus::GATT_READ_NOT_PERMITTED;
- break;
-
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_NOT_AUTHORIZED:
- ret = arc::mojom::BluetoothGattStatus::GATT_INSUFFICIENT_AUTHENTICATION;
- break;
-
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_NOT_SUPPORTED:
- ret = arc::mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED;
- break;
-
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_UNKNOWN:
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_FAILED:
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_IN_PROGRESS:
- case device::BluetoothGattService::GattErrorCode::GATT_ERROR_NOT_PAIRED:
- ret = arc::mojom::BluetoothGattStatus::GATT_FAILURE;
- break;
-
- default:
- ret = arc::mojom::BluetoothGattStatus::GATT_FAILURE;
- break;
- }
- return ret;
-}
-
-// static
arc::mojom::BluetoothSdpAttributePtr
TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
bluez::BluetoothServiceAttributeValueBlueZ>::
diff --git a/chromium/components/arc/bluetooth/bluetooth_type_converters.h b/chromium/components/arc/bluetooth/bluetooth_type_converters.h
index 295e3c8ea95..67a43e7436e 100644
--- a/chromium/components/arc/bluetooth/bluetooth_type_converters.h
+++ b/chromium/components/arc/bluetooth/bluetooth_type_converters.h
@@ -41,13 +41,6 @@ struct TypeConverter<std::string, arc::mojom::BluetoothAddress> {
};
template <>
-struct TypeConverter<arc::mojom::BluetoothGattStatus,
- device::BluetoothGattService::GattErrorCode> {
- static arc::mojom::BluetoothGattStatus Convert(
- const device::BluetoothGattService::GattErrorCode& error_code);
-};
-
-template <>
struct TypeConverter<arc::mojom::BluetoothSdpAttributePtr,
bluez::BluetoothServiceAttributeValueBlueZ> {
static arc::mojom::BluetoothSdpAttributePtr Convert(
diff --git a/chromium/components/arc/common/BUILD.gn b/chromium/components/arc/common/BUILD.gn
index ce86afffc18..b8da88bd7a0 100644
--- a/chromium/components/arc/common/BUILD.gn
+++ b/chromium/components/arc/common/BUILD.gn
@@ -17,7 +17,6 @@ if (is_chromeos) {
"audio.mojom",
"auth.mojom",
"backup_settings.mojom",
- "bitmap.mojom",
"bluetooth.mojom",
"boot_phase_monitor.mojom",
"cast_receiver.mojom",
@@ -27,13 +26,13 @@ if (is_chromeos) {
"enterprise_reporting.mojom",
"file_system.mojom",
"ime.mojom",
+ "input_method_manager.mojom",
"intent_helper.mojom",
"kiosk.mojom",
"lock_screen.mojom",
"metrics.mojom",
"midis.mojom",
"net.mojom",
- "notifications.mojom",
"obb_mounter.mojom",
"oemcrypto.mojom",
"oemcrypto_daemon.mojom",
@@ -58,12 +57,23 @@ if (is_chromeos) {
public_deps = [
":media",
+ ":notifications",
"//device/usb/public/mojom",
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo",
]
}
+
+ mojom("notifications") {
+ sources = [
+ "bitmap.mojom",
+ "notifications.mojom",
+ ]
+
+ deps = [
+ ":media", # for gfx.mojom
+ ]
+ }
}
# Media related mojo interfaces. There are used by
@@ -81,7 +91,6 @@ mojom("media") {
]
public_deps = [
- "//mojo/common:common_custom_types",
"//ui/gfx/geometry/mojo",
]
}
diff --git a/chromium/components/arc/common/app.mojom b/chromium/components/arc/common/app.mojom
index e4f00485f06..450e6879561 100644
--- a/chromium/components/arc/common/app.mojom
+++ b/chromium/components/arc/common/app.mojom
@@ -2,36 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 28
+// Next MinVersion: 32
module arc.mojom;
import "components/arc/common/gfx.mojom";
import "components/arc/common/scale_factor.mojom";
-// Describes OrientationLock request.
-// Note: ChromeOS currently assumes the internal panel is always landscape.
-// All rotation angles mentioned here are measured clockwise.
-// DEPRECATED: OrientationLock passed by Wayland instead.
-[Extensible]
-enum OrientationLockDeprecated {
- NONE = 0,
- // Rotated 90 or 270 deg.
- PORTRAIT = 1,
- // Rotated 0 or 180 deg.
- LANDSCAPE = 2,
- // Keep the current orientation.
- CURRENT = 3,
- // Rotated 90 deg.
- PORTRAIT_PRIMARY = 4,
- // Rotated 0 deg.
- LANDSCAPE_PRIMARY = 5,
- // Rotated 270 deg.
- PORTRAIT_SECONDARY = 6,
- // Rotated 180 deg.
- LANDSCAPE_SECONDARY = 7,
-};
-
// Describes installation result.
struct InstallationResult {
string package_name;
@@ -45,8 +22,6 @@ struct AppInfo {
string activity;
[MinVersion=2] bool sticky; // true if the app cannot be uninstalled
[MinVersion=7] bool notifications_enabled;
- // DEPRECATED: OrientationLock passed by Wayland instead.
- [MinVersion=12] OrientationLockDeprecated orientation_lock_deprecated;
};
// Describes ARC package.
@@ -135,14 +110,26 @@ enum AppDiscoveryRequestState {
PHONESKY_RESULT_INVALID_DATA = 16,
};
+// Describes the type/category of an app data search result.
+[Extensible]
+enum AppDataResultType {
+ PERSON = 0, // Person search result.
+ NOTE_DOCUMENT = 1, // Note document search result.
+};
+
// Describes an app data search result.
struct AppDataResult {
// Intent uri to launch the result.
- string launch_intent_uri;
+ string launch_intent_uri@0;
// Label for the result.
- string label;
- // Icon information in png format. It could be null if not provided.
- array<uint8>? icon_png_data;
+ string label@1;
+ // Text information for the result.
+ string text@3;
+ // Icon information in png format. It could be null if not provided. Decoded
+ // in the utility process.
+ array<uint8>? icon_png_data@2;
+ // Type of this app data search result.
+ [MinVersion=28] AppDataResultType type@4;
};
// Describes the status of an app data search request, including completed
@@ -169,6 +156,22 @@ enum AppDataRequestState {
FAILED_TO_CALL_GLOBALQUERY = 8,
};
+// Describes app shortcut that is published by Android's ShortcutManager.
+struct AppShortcutItem {
+ // The ID of this shortcut. Unique within each publisher app and stable across
+ // devices.
+ string shortcut_id;
+
+ // The short description of this shortcut.
+ string short_label;
+
+ // The icon for this shortcut, decoded in the utility process.
+ array<uint8> icon_png;
+
+ // The package name of the publisher app.
+ [MinVersion=31] string? package_name;
+};
+
// Next method ID: 18
interface AppHost {
// Sends newly added ARC app to Chrome. This message is sent when ARC receives
@@ -224,11 +227,6 @@ interface AppHost {
// Notifies that task has been destroyed.
[MinVersion=4] OnTaskDestroyed@5(int32 task_id);
- // Notifies that task requested orientation lock.
- // DEPRECATED: OrientationLock passed by Wayland instead.
- [MinVersion=12] OnTaskOrientationLockRequestedDeprecated@12(
- int32 task_id, OrientationLockDeprecated lock);
-
// Notifies that task has been activated.
[MinVersion=4] OnTaskSetActive@6(int32 task_id);
@@ -256,7 +254,7 @@ interface AppHost {
};
// TODO(lhchavez): Migrate all request/response messages to Mojo.
-// Next method ID: 23
+// Next method ID: 25
interface AppInstance {
// DEPRECATED: Please use Init@21 instead.
InitDeprecated@0(AppHost host_ptr);
@@ -286,6 +284,11 @@ interface AppInstance {
[MinVersion=23] LaunchApp@18(string package_name, string activity,
int64 display_id);
+ // Sends a request to ARC for the Android launcher to launch the specified app
+ // shortcut.
+ [MinVersion=30] LaunchAppShortcutItem@24(
+ string package_name, string shortcut_id, int64 display_id);
+
[MinVersion=9] LaunchIntentDeprecated@12(string intent_uri,
Rect? dimension_on_screen);
@@ -340,13 +343,19 @@ interface AppInstance {
// happens) is ignored, and uninstall option should appear in the UI.
[MinVersion=2] UninstallPackage@5(string package_name);
- // Starts a query for Play Store apps.
- [MinVersion=20] GetRecentAndSuggestedAppsFromPlayStore@16(
- string query, int32 max_results) =>
- (AppDiscoveryRequestState state@1, array<AppDiscoveryResult> results@0);
+ // Sends a request to ARC to get app shortcuts for app with |package_name|. If
+ // |package_name| is empty, it will query for all launchable activities.
+ [MinVersion=29] GetAppShortcutItems@23(string package_name) =>
+ (array<AppShortcutItem> shortcut_items);
// Starts a query for app data, which is querying icing indexable contents.
[MinVersion=27] GetIcingGlobalQueryResults@22(
string query, int32 max_results) =>
(AppDataRequestState state, array<AppDataResult> results);
+
+ // Starts a query for Play Store apps.
+ [MinVersion=20] GetRecentAndSuggestedAppsFromPlayStore@16(
+ string query, int32 max_results) =>
+ (AppDiscoveryRequestState state@1,
+ array<AppDiscoveryResult> results@0);
};
diff --git a/chromium/components/arc/common/arc_bridge.mojom b/chromium/components/arc/common/arc_bridge.mojom
index 778c73dc266..6966f3e53be 100644
--- a/chromium/components/arc/common/arc_bridge.mojom
+++ b/chromium/components/arc/common/arc_bridge.mojom
@@ -18,6 +18,7 @@ import "components/arc/common/crash_collector.mojom";
import "components/arc/common/enterprise_reporting.mojom";
import "components/arc/common/file_system.mojom";
import "components/arc/common/ime.mojom";
+import "components/arc/common/input_method_manager.mojom";
import "components/arc/common/intent_helper.mojom";
import "components/arc/common/kiosk.mojom";
import "components/arc/common/lock_screen.mojom";
@@ -45,9 +46,9 @@ import "components/arc/common/volume_mounter.mojom";
import "components/arc/common/wake_lock.mojom";
import "components/arc/common/wallpaper.mojom";
-// Next MinVersion: 38
+// Next MinVersion: 39
// Deprecated method IDs: 101, 105
-// Next method ID: 143
+// Next method ID: 144
interface ArcBridgeHost {
// Keep the entries alphabetical. In order to do so without breaking
// compatibility with the ARC instance, explicitly assign each interface a
@@ -102,6 +103,10 @@ interface ArcBridgeHost {
// Notifies Chrome that the ImeInstance interface is ready.
[MinVersion=3] OnImeInstanceReady@110(ImeInstance instance_ptr);
+ // Notifies Chrome that the InputMethodManagerInstance interface is ready.
+ [MinVersion=38] OnInputMethodManagerInstanceReady@143(
+ InputMethodManagerInstance instance_ptr);
+
// Notifies Chrome that the IntentHelperInstance interface is ready.
[MinVersion=4] OnIntentHelperInstanceReady@111(
IntentHelperInstance instance_ptr);
diff --git a/chromium/components/arc/common/auth.mojom b/chromium/components/arc/common/auth.mojom
index e1975919ac2..5cf12bdbfec 100644
--- a/chromium/components/arc/common/auth.mojom
+++ b/chromium/components/arc/common/auth.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 13
+// Next MinVersion: 14
module arc.mojom;
@@ -99,6 +99,32 @@ enum AccountCheckStatus {
// corresponding UMA callsite in Chrome arc::UpdateAuthAccountCheckStatus.
};
+// These values describe the result of ARC attempting to change supervision
+// state after an account type change.
+[Extensible]
+enum SupervisionChangeStatus {
+ // CloudDPC supervision was disabled successfully.
+ [MinVersion=13] CLOUD_DPC_DISABLED = 0,
+
+ // CloudDPC supervision was already disabled.
+ [MinVersion=13] CLOUD_DPC_ALREADY_DISABLED = 1,
+
+ // CloudDPC supervision was enabled successfully.
+ [MinVersion=13] CLOUD_DPC_ENABLED = 2,
+
+ // CloudDPC supervision was already enabled.
+ [MinVersion=13] CLOUD_DPC_ALREADY_ENABLED = 3,
+
+ // Invalid state returned from Chrome.
+ [MinVersion=13] INVALID_SUPERVISION_STATE = 4,
+
+ // Failed to disable CloudDPC due to an unspecified error.
+ [MinVersion=13] CLOUD_DPC_DISABLING_FAILED = 5,
+
+ // Failed to enable CloudDPC due to an unspecified error.
+ [MinVersion=13] CLOUD_DPC_ENABLING_FAILED = 6,
+};
+
// These values describe the type of the Chrome account to provision.
[Extensible]
enum ChromeAccountType {
@@ -144,8 +170,8 @@ struct AccountInfo {
[MinVersion=9] string? account_name@4;
// The authorization code that can be used in Android to sign in when
- // account_type is USER_ACCOUNT or ROBOT_ACCOUNT. If it is null in these
- // cases, sign-in will be skipped.
+ // account_type is USER_ACCOUNT, ROBOT_ACCOUNT or CHILD_ACCOUNT. If it is
+ // null in these cases, sign-in will be skipped.
string? auth_code@0;
// If account_type is ACTIVE_DIRECTORY_ACCOUNT, this contains an enrollment
@@ -160,7 +186,7 @@ struct AccountInfo {
bool is_managed@2;
};
-// Next Method ID: 11.
+// Next Method ID: 12.
interface AuthHost {
// Notifies Chrome that the authorization flow is completed and provides
// resulting |status|. If |initial_signin| is true then this indicates that
@@ -185,6 +211,13 @@ interface AuthHost {
// Reports result of account check.
[MinVersion=9] ReportAccountCheckStatus@9(AccountCheckStatus status);
+
+ // Reports to Chrome the result of changing the supervision state.
+ // Chrome informs ARC on every boot if a supervision transition is necessary
+ // or not (see https://crrev.com/c/1069031). ARC should report back only if
+ // a transition was necessary.
+ [MinVersion=13] ReportSupervisionChangeStatus@11(
+ SupervisionChangeStatus status);
};
// Next Method ID: 3
@@ -204,4 +237,5 @@ interface AuthInstance {
// of failure, other than SUCCESS.
[MinVersion=5] OnAccountInfoReady@1(
AccountInfo? account_info, [MinVersion=10] ArcSignInStatus status);
+
};
diff --git a/chromium/components/arc/common/bluetooth.mojom b/chromium/components/arc/common/bluetooth.mojom
index c3e0ebf5e4f..548f35b268d 100644
--- a/chromium/components/arc/common/bluetooth.mojom
+++ b/chromium/components/arc/common/bluetooth.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 10
+// Next MinVersion: 11
module arc.mojom;
@@ -278,8 +278,8 @@ struct BluetoothSdpAttribute {
// change. This field is introduced between version 7 and 8, though
// MinVersion is not annotated because of breaking change, too.
// See details in the bug linked below.
- // TODO(crbug.com/767313): Use mojo/common/values.mojom, when new libmojo
- // (440057 or later) is rolled to ARC repository.
+ // TODO(crbug.com/767313): Use mojo/public/mojom/base/values.mojom, when new
+ // libmojo (440057 or later) is rolled to ARC repository.
string? json_value@3;
};
@@ -405,7 +405,7 @@ interface BluetoothHost {
=> (BluetoothGattStatus status);
};
-// Next Method ID: 19
+// Next Method ID: 20
interface BluetoothInstance {
// DEPRECATED: Please use Init@18 instead.
InitDeprecated@0(BluetoothHost host_ptr);
@@ -465,10 +465,11 @@ interface BluetoothInstance {
array<uint8> value,
[MinVersion=9] BluetoothGattDBAttributeType attribute_type)
=> (BluetoothGattStatus status);
+ [MinVersion=10] OnMTUReceived@19(BluetoothAddress remote_addr, uint16 mtu);
// Bluetooth SDP function
[MinVersion=5] OnGetSdpRecords@17(BluetoothStatus status,
- BluetoothAddress remove_addr,
+ BluetoothAddress remote_addr,
BluetoothUUID target_uuid,
array<BluetoothSdpRecord> records);
};
diff --git a/chromium/components/arc/common/ime.mojom b/chromium/components/arc/common/ime.mojom
index 032f539bd6a..732a37bcbd4 100644
--- a/chromium/components/arc/common/ime.mojom
+++ b/chromium/components/arc/common/ime.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// Next MinVersion: 9
+// Next MinVersion: 10
module arc.mojom;
@@ -34,7 +34,7 @@ struct CompositionSegment {
bool emphasized;
};
-// Next method ID: 4
+// Next method ID: 6
interface ImeHost {
// Notifies Chrome that the text input focus is changed.
OnTextInputTypeChanged@0(TextInputType type);
@@ -75,6 +75,12 @@ interface ImeHost {
[MinVersion=8] bool is_screen_coordinates // Whether or not the |rect|
// are in screen coordinates.
);
+
+ // Requests Chrome to hide the virtual keyboard.
+ // Howver, hiding can be canceled if a text field gets focus.
+ // TODO(yhanada): We might be able to remove this method by adding an argument
+ // to OnTextInputTypeChanged().
+ [MinVersion=9] RequestHideIme@5();
};
// Next method ID: 7
diff --git a/chromium/components/arc/common/input_method_manager.mojom b/chromium/components/arc/common/input_method_manager.mojom
new file mode 100644
index 00000000000..e7ffdec2b25
--- /dev/null
+++ b/chromium/components/arc/common/input_method_manager.mojom
@@ -0,0 +1,50 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module arc.mojom;
+
+// Represents the information of an Android IME.
+struct ImeInfo {
+ // The unique ID for the Android IME. Corresponds to InputMethodInfo.getId().
+ string ime_id;
+ // The user-displayed label for the IME. Corresponds to
+ // InputMethodInfo.loadLabel().
+ string display_name;
+ // Whether the IME is enabled or not. It's equivalent to whether the IME is
+ // in ENABLED_INPUT_METHODS settings.
+ bool enabled;
+ // intent: URL to open the settings activity of the IME.
+ string settings_url;
+};
+
+// This interface is called by container when Android's InputMethodManager state
+// is changed.
+// In Android container, ArcInputMethodService IME is pre-installed to bridge
+// Chrome OS's IME to Android apps. The bridge is defined in ime.mojom.
+//
+// Next method ID: 2
+interface InputMethodManagerHost {
+ // Notifies Chrome that active IME in Android is changed.
+ OnActiveImeChanged@0(string ime_id);
+
+ // Notifies Chrome of information of installed IMEs in Android.
+ // The passed list doesn't contain information of our bridge IME,
+ // ArcInputMethodService.
+ OnImeInfoChanged@1(array<ImeInfo> ime_infos);
+};
+
+// This interface provides methods to control Android's InputMethodManager.
+//
+// Next method ID: 3
+interface InputMethodManagerInstance {
+ // Establishes full-duplex communication with the host.
+ Init@0(InputMethodManagerHost host_ptr) => ();
+
+ // Enables/Disables an IME in Android. Calling this method will add/remove
+ // the specified IME to/from ENABLED_INPUT_METHODS settings.
+ EnableIme@1(string ime_id, bool enable) => (bool success);
+
+ // Switches active IME in Android.
+ SwitchImeTo@2(string ime_id) => (bool success);
+};
diff --git a/chromium/components/arc/common/notifications.mojom b/chromium/components/arc/common/notifications.mojom
index 12848868c07..ffcbcc5b67b 100644
--- a/chromium/components/arc/common/notifications.mojom
+++ b/chromium/components/arc/common/notifications.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 16
+// Next MinVersion: 17
module arc.mojom;
@@ -34,14 +34,16 @@ enum ArcNotificationType {
BUNDLED = 4,
};
-// These values are corresponding to the priorities of Android notification.
+// These values are corresponding to the priorities or importance of Android
+// notification.
[Extensible]
enum ArcNotificationPriority {
- MIN = -2, // same value as Notification.PRIORITY_MIN
- LOW = -1, // same value as Notification.PRIORITY_LOW
- DEFAULT = 0, // same value as Notification.PRIORITY_DEFAULT
- HIGH = 1, // same value as Notification.PRIORITY_HIGH
- MAX = 2, // same value as Notification.PRIORITY_MAX
+ NONE = -3,
+ MIN = -2,
+ LOW = -1,
+ DEFAULT = 0,
+ HIGH = 1,
+ MAX = 2,
};
// DEPRECATED
@@ -139,7 +141,7 @@ struct ArcNotificationData {
string? package_name;
};
-// Next Method ID: 6
+// Next Method ID: 7
interface NotificationsHost {
// Tells the Chrome that a notification is posted (created or updated) on
// Android. If you know that the notification exists, please consider to use
@@ -154,6 +156,10 @@ interface NotificationsHost {
[MinVersion=13]
// Notifies that an existing notiication is updated on Android.
OnNotificationUpdated@5(ArcNotificationData notification_data);
+
+ [MinVersion=16]
+ // Opens the Chrome OS message center.
+ OpenMessageCenter@6();
};
// Next Method ID: 6
diff --git a/chromium/components/arc/common/policy.mojom b/chromium/components/arc/common/policy.mojom
index 2c0f02589fe..f2a8804d84a 100644
--- a/chromium/components/arc/common/policy.mojom
+++ b/chromium/components/arc/common/policy.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// Next MinVersion: 4
+// Next MinVersion: 5
module arc.mojom;
@@ -50,6 +50,15 @@ enum InstallErrorReason {
USER_INVALID = 10,
};
+// Should be kept in sync with device_management_backend.proto/
+// RemoteCommandResult/ResultType.
+[Extensible]
+enum CommandResultType {
+ IGNORED = 0, // The command was ignored as obsolete.
+ FAILURE = 1, // The command could not be executed.
+ SUCCESS = 2, // The command was successfully executed.
+};
+
// Next Method ID: 2
interface PolicyHost {
// Get policies from Chrome OS, as JSON-encoded dictionary with the policies'
@@ -76,7 +85,7 @@ interface PolicyHost {
InstallErrorReason reason);
};
-// Next Method ID: 3
+// Next Method ID: 4
interface PolicyInstance {
// DEPRECATED: Please use Init@2 instead.
InitDeprecated@0(PolicyHost host_ptr);
@@ -86,4 +95,11 @@ interface PolicyInstance {
// Indicates some policies have changed
OnPolicyUpdated@1();
+
+ // Forwards a command received from the management server. The payload is
+ // opaque to Chrome OS (it contains JSON from the RemoteCommand.payload field
+ // for the USER_ARC_COMMAND RemoteCommand - cf.
+ // device_management_backend.proto).
+ [MinVersion=4] OnCommandReceived@3(string command)
+ => (CommandResultType result);
};
diff --git a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
index e75aadaa3db..bb49c4d3c73 100644
--- a/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
+++ b/chromium/components/arc/crash_collector/arc_crash_collector_bridge.cc
@@ -27,7 +27,7 @@ void RunCrashReporter(const std::string& crash_type,
const std::string& device,
const std::string& board,
const std::string& cpu_abi,
- mojo::edk::ScopedPlatformHandle pipe) {
+ mojo::edk::ScopedInternalPlatformHandle pipe) {
base::LaunchOptions options;
options.fds_to_remap.push_back(
std::make_pair(pipe.get().handle, STDIN_FILENO));
@@ -91,8 +91,9 @@ ArcCrashCollectorBridge::~ArcCrashCollectorBridge() {
void ArcCrashCollectorBridge::DumpCrash(const std::string& type,
mojo::ScopedHandle pipe) {
- mojo::edk::ScopedPlatformHandle pipe_handle;
- mojo::edk::PassWrappedPlatformHandle(pipe.release().value(), &pipe_handle);
+ mojo::edk::ScopedInternalPlatformHandle pipe_handle;
+ mojo::edk::PassWrappedInternalPlatformHandle(pipe.release().value(),
+ &pipe_handle);
base::PostTaskWithTraits(
FROM_HERE, {base::WithBaseSyncPrimitives()},
diff --git a/chromium/components/arc/ime/arc_ime_bridge.h b/chromium/components/arc/ime/arc_ime_bridge.h
index 09cfce68d8c..b982b8b0c04 100644
--- a/chromium/components/arc/ime/arc_ime_bridge.h
+++ b/chromium/components/arc/ime/arc_ime_bridge.h
@@ -40,6 +40,7 @@ class ArcImeBridge {
const base::string16& text_in_range,
const gfx::Range& selection_range,
bool is_screen_coordinates) = 0;
+ virtual void RequestHideIme() = 0;
};
// Serializes and sends IME related requests through IPCs.
diff --git a/chromium/components/arc/ime/arc_ime_bridge_impl.cc b/chromium/components/arc/ime/arc_ime_bridge_impl.cc
index 348b2da2675..47b41789f54 100644
--- a/chromium/components/arc/ime/arc_ime_bridge_impl.cc
+++ b/chromium/components/arc/ime/arc_ime_bridge_impl.cc
@@ -162,4 +162,8 @@ void ArcImeBridgeImpl::OnCursorRectChangedWithSurroundingText(
is_screen_coordinates);
}
+void ArcImeBridgeImpl::RequestHideIme() {
+ delegate_->RequestHideIme();
+}
+
} // namespace arc
diff --git a/chromium/components/arc/ime/arc_ime_bridge_impl.h b/chromium/components/arc/ime/arc_ime_bridge_impl.h
index a71fdba2483..fdbffcab3d7 100644
--- a/chromium/components/arc/ime/arc_ime_bridge_impl.h
+++ b/chromium/components/arc/ime/arc_ime_bridge_impl.h
@@ -48,6 +48,7 @@ class ArcImeBridgeImpl : public ArcImeBridge, public mojom::ImeHost {
const std::string& text_in_range,
const gfx::Range& selection_range,
bool screen_coordinates) override;
+ void RequestHideIme() override;
private:
Delegate* const delegate_;
diff --git a/chromium/components/arc/ime/arc_ime_service.cc b/chromium/components/arc/ime/arc_ime_service.cc
index e541650473c..d6155b3297e 100644
--- a/chromium/components/arc/ime/arc_ime_service.cc
+++ b/chromium/components/arc/ime/arc_ime_service.cc
@@ -322,6 +322,12 @@ void ArcImeService::OnCursorRectChangedWithSurroundingText(
input_method->OnCaretBoundsChanged(this);
}
+void ArcImeService::RequestHideIme() {
+ auto* keyboard_controller = keyboard::KeyboardController::GetInstance();
+ if (keyboard_controller)
+ keyboard_controller->MaybeHideKeyboard();
+}
+
////////////////////////////////////////////////////////////////////////////////
// Overridden from keyboard::KeyboardControllerObserver
void ArcImeService::OnKeyboardAppearanceChanged(
@@ -478,6 +484,13 @@ bool ArcImeService::HasCompositionText() const {
return has_composition_text_;
}
+ui::TextInputClient::FocusReason ArcImeService::GetFocusReason() const {
+ // TODO(https://crbug.com/824604): Determine how the current input client got
+ // focused.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return ui::TextInputClient::FOCUS_REASON_OTHER;
+}
+
bool ArcImeService::GetCompositionTextRange(gfx::Range* range) const {
return false;
}
@@ -506,6 +519,12 @@ const std::string& ArcImeService::GetClientSourceInfo() const {
return base::EmptyString();
}
+bool ArcImeService::ShouldDoLearning() {
+ // TODO(https://crbug.com/311180): Implement this method.
+ NOTIMPLEMENTED_LOG_ONCE();
+ return true;
+}
+
// static
void ArcImeService::SetOverrideDefaultDeviceScaleFactorForTesting(
base::Optional<double> scale_factor) {
diff --git a/chromium/components/arc/ime/arc_ime_service.h b/chromium/components/arc/ime/arc_ime_service.h
index e74646a6b7f..a1beae6cdb7 100644
--- a/chromium/components/arc/ime/arc_ime_service.h
+++ b/chromium/components/arc/ime/arc_ime_service.h
@@ -96,6 +96,7 @@ class ArcImeService : public KeyedService,
const base::string16& text_in_range,
const gfx::Range& selection_range,
bool is_screen_coordinates) override;
+ void RequestHideIme() override;
// Overridden from keyboard::KeyboardControllerObserver.
void OnKeyboardAppearanceChanged(
@@ -124,6 +125,7 @@ class ArcImeService : public KeyedService,
bool GetCompositionCharacterBounds(uint32_t index,
gfx::Rect* rect) const override;
bool HasCompositionText() const override;
+ FocusReason GetFocusReason() const override;
bool GetCompositionTextRange(gfx::Range* range) const override;
bool SetSelectionRange(const gfx::Range& range) override;
bool DeleteRange(const gfx::Range& range) override;
@@ -136,6 +138,7 @@ class ArcImeService : public KeyedService,
void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override {
}
const std::string& GetClientSourceInfo() const override;
+ bool ShouldDoLearning() override;
// Normally, the default device scale factor is used to convert from DPI to
// physical pixels. This method provides a way to override it for testing.
diff --git a/chromium/components/arc/midis/arc_midis_bridge.cc b/chromium/components/arc/midis/arc_midis_bridge.cc
index 110586467df..5cc0ecfe9d6 100644
--- a/chromium/components/arc/midis/arc_midis_bridge.cc
+++ b/chromium/components/arc/midis/arc_midis_bridge.cc
@@ -86,7 +86,7 @@ void ArcMidisBridge::Connect(mojom::MidisServerRequest request,
base::kNullProcessHandle,
mojo::edk::ConnectionParams(mojo::edk::TransportProtocol::kLegacy,
channel_pair.PassServerHandle()));
- mojo::edk::ScopedPlatformHandle child_handle =
+ mojo::edk::ScopedInternalPlatformHandle child_handle =
channel_pair.PassClientHandle();
base::ScopedFD fd(child_handle.release().handle);
diff --git a/chromium/components/arc/mojo_channel.h b/chromium/components/arc/mojo_channel.h
new file mode 100644
index 00000000000..400607dfd19
--- /dev/null
+++ b/chromium/components/arc/mojo_channel.h
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_ARC_MOJO_CHANNEL_H_
+#define COMPONENTS_ARC_MOJO_CHANNEL_H_
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "components/arc/connection_holder.h"
+
+namespace arc {
+
+// Thin interface to wrap InterfacePtr<T> with type erasure.
+class MojoChannelBase {
+ public:
+ virtual ~MojoChannelBase() = default;
+
+ protected:
+ MojoChannelBase() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MojoChannelBase);
+};
+
+// Thin wrapper for InterfacePtr<T>, where T is one of ARC mojo Instance class.
+template <typename InstanceType, typename HostType>
+class MojoChannel : public MojoChannelBase {
+ public:
+ MojoChannel(ConnectionHolder<InstanceType, HostType>* holder,
+ mojo::InterfacePtr<InstanceType> ptr)
+ : holder_(holder), ptr_(std::move(ptr)) {
+ // Delay registration to the ConnectionHolder until the version is ready.
+ }
+
+ ~MojoChannel() override { holder_->CloseInstance(ptr_.get()); }
+
+ void set_connection_error_handler(base::OnceClosure error_handler) {
+ ptr_.set_connection_error_handler(std::move(error_handler));
+ }
+
+ void QueryVersion() {
+ // Note: the callback will not be called if |ptr_| is destroyed.
+ ptr_.QueryVersion(
+ base::Bind(&MojoChannel::OnVersionReady, base::Unretained(this)));
+ }
+
+ private:
+ void OnVersionReady(uint32_t unused_version) {
+ holder_->SetInstance(ptr_.get(), ptr_.version());
+ }
+
+ // Externally owned ConnectionHolder instance.
+ ConnectionHolder<InstanceType, HostType>* const holder_;
+
+ // Put as a last member to ensure that any callback tied to the |ptr_|
+ // is not invoked.
+ mojo::InterfacePtr<InstanceType> ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(MojoChannel);
+};
+
+} // namespace arc
+
+#endif // COMPONENTS_ARC_MOJO_CHANNEL_H_
diff --git a/chromium/components/arc/power/DEPS b/chromium/components/arc/power/DEPS
index 2a902196e7c..8d35727fbcb 100644
--- a/chromium/components/arc/power/DEPS
+++ b/chromium/components/arc/power/DEPS
@@ -1,7 +1,7 @@
include_rules = [
"+ash/shell.h",
"+content/public/common/service_manager_connection.h",
- "+ui/display/manager/chromeos",
+ "+ui/display/manager",
"+services/device/public",
"+services/service_manager/public",
]
diff --git a/chromium/components/arc/power/arc_power_bridge.h b/chromium/components/arc/power/arc_power_bridge.h
index bacd4acfbd0..5697d7c004b 100644
--- a/chromium/components/arc/power/arc_power_bridge.h
+++ b/chromium/components/arc/power/arc_power_bridge.h
@@ -15,7 +15,7 @@
#include "components/arc/connection_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
-#include "ui/display/manager/chromeos/display_configurator.h"
+#include "ui/display/manager/display_configurator.h"
namespace content {
class BrowserContext;
diff --git a/chromium/components/arc/usb/usb_host_bridge.cc b/chromium/components/arc/usb/usb_host_bridge.cc
index 111b9d8957c..b88ab1a9e30 100644
--- a/chromium/components/arc/usb/usb_host_bridge.cc
+++ b/chromium/components/arc/usb/usb_host_bridge.cc
@@ -51,10 +51,10 @@ void OnDeviceOpened(mojom::UsbHostHost::OpenDeviceCallback callback,
std::move(callback).Run(mojo::ScopedHandle());
return;
}
- mojo::edk::ScopedPlatformHandle platform_handle{
- mojo::edk::PlatformHandle(fd.release())};
+ mojo::edk::ScopedInternalPlatformHandle platform_handle{
+ mojo::edk::InternalPlatformHandle(fd.release())};
MojoHandle wrapped_handle;
- MojoResult wrap_result = mojo::edk::CreatePlatformHandleWrapper(
+ MojoResult wrap_result = mojo::edk::CreateInternalPlatformHandleWrapper(
std::move(platform_handle), &wrapped_handle);
if (wrap_result != MOJO_RESULT_OK) {
LOG(ERROR) << "Failed to wrap device FD. Closing: " << wrap_result;
diff --git a/chromium/components/assist_ranker/OWNERS b/chromium/components/assist_ranker/OWNERS
index 36ad72d71e6..8aee8cf06a5 100644
--- a/chromium/components/assist_ranker/OWNERS
+++ b/chromium/components/assist_ranker/OWNERS
@@ -1,3 +1,5 @@
+amoylan@chromium.org
charleszhao@chromium.org
hamelphi@chromium.org
+jiameng@chromium.org
rogerm@chromium.org
diff --git a/chromium/components/assist_ranker/base_predictor.cc b/chromium/components/assist_ranker/base_predictor.cc
index 28ccc264275..9060cd8de64 100644
--- a/chromium/components/assist_ranker/base_predictor.cc
+++ b/chromium/components/assist_ranker/base_predictor.cc
@@ -56,8 +56,7 @@ bool BasePredictor::IsReady() {
void BasePredictor::LogFeatureToUkm(const std::string& feature_name,
const Feature& feature,
ukm::UkmEntryBuilder* ukm_builder) {
- if (!ukm_builder)
- return;
+ DCHECK(ukm_builder);
if (!base::ContainsKey(*config_.feature_whitelist, feature_name)) {
DVLOG(1) << "Feature not whitelisted: " << feature_name;
@@ -72,7 +71,7 @@ void BasePredictor::LogFeatureToUkm(const std::string& feature_name,
int64_t feature_int64_value = -1;
FeatureToInt64(feature, &feature_int64_value);
DVLOG(3) << "Logging: " << feature_name << ": " << feature_int64_value;
- ukm_builder->AddMetric(feature_name.c_str(), feature_int64_value);
+ ukm_builder->SetMetric(feature_name, feature_int64_value);
break;
}
case Feature::kStringList: {
@@ -80,7 +79,7 @@ void BasePredictor::LogFeatureToUkm(const std::string& feature_name,
int64_t feature_int64_value = -1;
FeatureToInt64(feature, &feature_int64_value, i);
DVLOG(3) << "Logging: " << feature_name << ": " << feature_int64_value;
- ukm_builder->AddMetric(feature_name.c_str(), feature_int64_value);
+ ukm_builder->SetMetric(feature_name, feature_int64_value);
}
break;
}
@@ -105,16 +104,11 @@ void BasePredictor::LogExampleToUkm(const RankerExample& example,
return;
}
- // Releasing the builder will trigger logging.
- std::unique_ptr<ukm::UkmEntryBuilder> builder =
- ukm::UkmRecorder::Get()->GetEntryBuilder(source_id, config_.logging_name);
- if (builder) {
- for (const auto& feature_kv : example.features()) {
- LogFeatureToUkm(feature_kv.first, feature_kv.second, builder.get());
- }
- } else {
- DVLOG(0) << "Could not get UKM Entry Builder.";
+ ukm::UkmEntryBuilder builder(source_id, config_.logging_name);
+ for (const auto& feature_kv : example.features()) {
+ LogFeatureToUkm(feature_kv.first, feature_kv.second, &builder);
}
+ builder.Record(ukm::UkmRecorder::Get());
}
std::string BasePredictor::GetModelName() const {
diff --git a/chromium/components/assist_ranker/base_predictor_unittest.cc b/chromium/components/assist_ranker/base_predictor_unittest.cc
index 3ec770e99a4..aae82621b11 100644
--- a/chromium/components/assist_ranker/base_predictor_unittest.cc
+++ b/chromium/components/assist_ranker/base_predictor_unittest.cc
@@ -26,16 +26,19 @@ namespace {
// Predictor config for testing.
const char kTestModelName[] = "test_model";
-const char kTestLoggingName[] = "TestLoggingName";
+// This name needs to be an entry in ukm.xml
+const char kTestLoggingName[] = "ContextualSearch";
const char kTestUmaPrefixName[] = "Test.Ranker";
const char kTestUrlParamName[] = "ranker-model-url";
const char kTestDefaultModelUrl[] = "https://foo.bar/model.bin";
-const char kBoolFeature[] = "bool_feature";
-const char kIntFeature[] = "int_feature";
-const char kFloatFeature[] = "float_feature";
-const char kStringFeature[] = "string_feature";
-const char kStringListFeature[] = "string_list_feature";
+// The whitelisted features must be metrics of kTestLoggingName in ukm.xml,
+// though the types do not need to match.
+const char kBoolFeature[] = "DidOptIn";
+const char kIntFeature[] = "DurationAfterScrollMs";
+const char kFloatFeature[] = "FontSize";
+const char kStringFeature[] = "IsEntity";
+const char kStringListFeature[] = "IsEntityEligible";
const char kFeatureNotWhitelisted[] = "not_whitelisted";
const char kTestNavigationUrl[] = "https://foo.com";
diff --git a/chromium/components/assist_ranker/fake_ranker_model_loader.cc b/chromium/components/assist_ranker/fake_ranker_model_loader.cc
index b1804ce09c3..9097243c765 100644
--- a/chromium/components/assist_ranker/fake_ranker_model_loader.cc
+++ b/chromium/components/assist_ranker/fake_ranker_model_loader.cc
@@ -19,7 +19,7 @@ FakeRankerModelLoader::FakeRankerModelLoader(
FakeRankerModelLoader::~FakeRankerModelLoader() {}
void FakeRankerModelLoader::NotifyOfRankerActivity() {
- if (validate_model_cb_.Run(*ranker_model_.get()) == RankerModelStatus::OK) {
+ if (validate_model_cb_.Run(*ranker_model_) == RankerModelStatus::OK) {
on_model_available_cb_.Run(std::move(ranker_model_));
}
}
diff --git a/chromium/components/assist_ranker/print_example_preprocessor_config.py b/chromium/components/assist_ranker/print_example_preprocessor_config.py
new file mode 100755
index 00000000000..5e35a0f1a6e
--- /dev/null
+++ b/chromium/components/assist_ranker/print_example_preprocessor_config.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python2
+
+# 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.
+
+"""Dumps info from a ExamplePreprocessorConfig protobuf file.
+
+Prints feature names, types, and bucket values.
+"""
+
+import os
+import sys
+import textwrap
+from enum import Enum
+from google.protobuf import text_format
+
+class FeatureType(Enum):
+ CATEGORICAL = 'categorical'
+ BUCKETED = 'bucketed'
+ SCALAR = 'scalar'
+
+
+def ReadConfig(pb_file):
+ """Parses the protobuf containing the example preprocessor config."""
+ import example_preprocessor_pb2
+ config = example_preprocessor_pb2.ExamplePreprocessorConfig()
+ with open(pb_file) as pb:
+ config.ParseFromString(pb.read())
+ return config
+
+
+def PrintExamplePreprocessorConfig(pb_file):
+ """Prints the features listed the example preprocessor config."""
+ config = ReadConfig(pb_file)
+
+ features = set()
+ for feature_index in sorted(config.feature_indices):
+ # For string or string list feature types, remove the "_value" suffix to get
+ # the base name.
+ name_parts = feature_index.split('_')
+ base_name = name_parts[0]
+ # Skip additional values of the same base name.
+ if base_name in features:
+ continue
+
+ features.add(base_name)
+ if len(name_parts) == 1:
+ feature_type = FeatureType.SCALAR
+ elif base_name in config.bucketizers:
+ feature_type = FeatureType.BUCKETED
+ else:
+ feature_type = FeatureType.CATEGORICAL
+ description = '* %s (%s)' % (base_name, feature_type.value)
+
+ if feature_type == FeatureType.BUCKETED:
+ description += ':\n\t'
+ boundaries = config.bucketizers[base_name].boundaries
+ bucket_str = ', '.join(['%.1f' % bucket for bucket in boundaries])
+
+ # Indent description by a tab and wrap text.
+ max_len = 80 - 8 # Leave at least 8 columns for tab width.
+ description += ('\n\t').join(textwrap.wrap(bucket_str, max_len))
+ print description
+ return 0
+
+
+def Main(args):
+ if len(args) != 2:
+ print 'Usage: %s <out_dir> <path/to/example_preprocessor_config.pb>' % (
+ __file__)
+ return 1
+
+ out_dir = args[0]
+ if not os.path.isdir(out_dir):
+ print 'Could not find out directory: %s' % out_dir
+ return 1
+
+ pb_file = args[1]
+ if not os.path.isfile(pb_file):
+ print 'Protobuf file not found: %s' % pb_file
+ return 1
+
+ proto_dir = os.path.join(out_dir, 'pyproto/components/assist_ranker/proto')
+ if not os.path.isdir(proto_dir):
+ print 'Proto directory not found: %s' % proto_dir
+ print 'Build the "components/assist_ranker/proto" target'
+ print ' (usually built with chrome)'
+ return 1
+
+ # Allow importing the ExamplePreprocessorConfig proto definition.
+ sys.path.insert(0, proto_dir)
+ PrintExamplePreprocessorConfig(pb_file)
+
+
+if __name__ == '__main__':
+ sys.exit(Main(sys.argv[1:]))
diff --git a/chromium/components/autofill/android/autofill_provider_android.cc b/chromium/components/autofill/android/autofill_provider_android.cc
index fbc7832a9e4..bcc02fad5a1 100644
--- a/chromium/components/autofill/android/autofill_provider_android.cc
+++ b/chromium/components/autofill/android/autofill_provider_android.cc
@@ -86,8 +86,10 @@ void AutofillProviderAndroid::StartNewSession(AutofillHandlerProxy* handler,
form_ = std::make_unique<FormDataAndroid>(form);
size_t index;
- if (!form_->GetFieldIndex(field, &index))
+ if (!form_->GetFieldIndex(field, &index)) {
+ form_.reset();
return;
+ }
gfx::RectF transformed_bounding = ToClientAreaBound(bounding_box);
@@ -157,26 +159,27 @@ void AutofillProviderAndroid::FireSuccessfulSubmission(
ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
+
Java_AutofillProvider_onFormSubmitted(env, obj, (int)source);
Reset();
}
-bool AutofillProviderAndroid::OnFormSubmitted(AutofillHandlerProxy* handler,
+void AutofillProviderAndroid::OnFormSubmitted(AutofillHandlerProxy* handler,
const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!IsCurrentlyLinkedHandler(handler) || !IsCurrentlyLinkedForm(form))
- return false;
+ return;
if (known_success || source == SubmissionSource::FORM_SUBMISSION) {
FireSuccessfulSubmission(source);
- } else {
- check_submission_ = true;
- pending_submission_source_ = source;
+ return;
}
- return true;
+
+ check_submission_ = true;
+ pending_submission_source_ = source;
}
void AutofillProviderAndroid::OnFocusNoLongerOnForm(
diff --git a/chromium/components/autofill/android/autofill_provider_android.h b/chromium/components/autofill/android/autofill_provider_android.h
index 6c30caa99b1..9a707c541c4 100644
--- a/chromium/components/autofill/android/autofill_provider_android.h
+++ b/chromium/components/autofill/android/autofill_provider_android.h
@@ -44,7 +44,7 @@ class AutofillProviderAndroid : public AutofillProvider {
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
- bool OnFormSubmitted(AutofillHandlerProxy* handler,
+ void OnFormSubmitted(AutofillHandlerProxy* handler,
const FormData& form,
bool known_success,
SubmissionSource source,
diff --git a/chromium/components/autofill/android/form_field_data_android.cc b/chromium/components/autofill/android/form_field_data_android.cc
index a0f3bd1d25a..e44e88ece75 100644
--- a/chromium/components/autofill/android/form_field_data_android.cc
+++ b/chromium/components/autofill/android/form_field_data_android.cc
@@ -51,7 +51,7 @@ ScopedJavaLocalRef<jobject> FormFieldDataAndroid::GetJavaPeer() {
env, jname, jlabel, jvalue, jautocomplete_attr,
field_ptr_->should_autocomplete, jplaceholder, jtype, jid,
joption_values, joption_contents, IsCheckable(field_ptr_->check_status),
- IsChecked(field_ptr_->check_status));
+ IsChecked(field_ptr_->check_status), field_ptr_->max_length);
java_ref_ = JavaObjectWeakGlobalRef(env, obj);
}
return obj;
diff --git a/chromium/components/autofill/content/DEPS b/chromium/components/autofill/content/DEPS
index 0baa569b70e..d9c00e11673 100644
--- a/chromium/components/autofill/content/DEPS
+++ b/chromium/components/autofill/content/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+content/public/common",
- "+mojo/common",
"+mojo/public",
"+services/service_manager/public/cpp",
]
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.cc b/chromium/components/autofill/content/browser/content_autofill_driver.cc
index ef5b819c310..10784fd0147 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.cc
@@ -124,10 +124,10 @@ void ContentAutofillDriver::RendererShouldAcceptDataListSuggestion(
GetAutofillAgent()->AcceptDataListSuggestion(value);
}
-void ContentAutofillDriver::RendererShouldClearFilledForm() {
+void ContentAutofillDriver::RendererShouldClearFilledSection() {
if (!RendererIsAvailable())
return;
- GetAutofillAgent()->ClearForm();
+ GetAutofillAgent()->ClearSection();
}
void ContentAutofillDriver::RendererShouldClearPreviewedForm() {
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver.h b/chromium/components/autofill/content/browser/content_autofill_driver.h
index 9296121644f..96d93f94e24 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver.h
+++ b/chromium/components/autofill/content/browser/content_autofill_driver.h
@@ -61,7 +61,7 @@ class ContentAutofillDriver : public AutofillDriver,
const std::vector<FormStructure*>& forms) override;
void RendererShouldAcceptDataListSuggestion(
const base::string16& value) override;
- void RendererShouldClearFilledForm() override;
+ void RendererShouldClearFilledSection() override;
void RendererShouldClearPreviewedForm() override;
void RendererShouldFillFieldWithValue(const base::string16& value) override;
void RendererShouldPreviewFieldWithValue(
diff --git a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 36524343d44..bb199189394 100644
--- a/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/chromium/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -47,7 +47,7 @@ class FakeAutofillAgent : public mojom::AutofillAgent {
FakeAutofillAgent()
: fill_form_id_(-1),
preview_form_id_(-1),
- called_clear_form_(false),
+ called_clear_section_(false),
called_clear_previewed_form_(false) {}
~FakeAutofillAgent() override {}
@@ -101,7 +101,7 @@ class FakeAutofillAgent : public mojom::AutofillAgent {
// Returns whether mojo interface method mojom::AutofillAgent::ClearForm() got
// called.
- bool GetCalledClearForm() { return called_clear_form_; }
+ bool GetCalledClearSection() { return called_clear_section_; }
// Returns whether mojo interface method
// mojom::AutofillAgent::ClearPreviewedForm() got called.
@@ -167,8 +167,8 @@ class FakeAutofillAgent : public mojom::AutofillAgent {
CallDone();
}
- void ClearForm() override {
- called_clear_form_ = true;
+ void ClearSection() override {
+ called_clear_section_ = true;
CallDone();
}
@@ -222,8 +222,8 @@ class FakeAutofillAgent : public mojom::AutofillAgent {
base::Optional<FormData> preview_form_form_;
// Records data received from FieldTypePredictionsAvailable() call.
base::Optional<std::vector<FormDataPredictions>> predictions_;
- // Records whether ClearForm() got called.
- bool called_clear_form_;
+ // Records whether ClearSection() got called.
+ bool called_clear_section_;
// Records whether ClearPreviewedForm() got called.
bool called_clear_previewed_form_;
// Records string received from FillFieldWithValue() call.
@@ -240,7 +240,7 @@ class MockAutofillManager : public AutofillManager {
public:
MockAutofillManager(AutofillDriver* driver, AutofillClient* client)
: AutofillManager(driver, client, kAppLocale, kDownloadState) {}
- virtual ~MockAutofillManager() {}
+ ~MockAutofillManager() override {}
MOCK_METHOD0(Reset, void());
};
@@ -410,13 +410,13 @@ TEST_F(ContentAutofillDriverTest, AcceptDataListSuggestion) {
EXPECT_EQ(input_value, output_value);
}
-TEST_F(ContentAutofillDriverTest, ClearFilledFormSentToRenderer) {
+TEST_F(ContentAutofillDriverTest, ClearFilledSectionSentToRenderer) {
base::RunLoop run_loop;
fake_agent_.SetQuitLoopClosure(run_loop.QuitClosure());
- driver_->RendererShouldClearFilledForm();
+ driver_->RendererShouldClearFilledSection();
run_loop.RunUntilIdle();
- EXPECT_TRUE(fake_agent_.GetCalledClearForm());
+ EXPECT_TRUE(fake_agent_.GetCalledClearSection());
}
TEST_F(ContentAutofillDriverTest, ClearPreviewedFormSentToRenderer) {
diff --git a/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc b/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc
index 79bc0eea36d..601c895dc9c 100644
--- a/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc
+++ b/chromium/components/autofill/content/browser/key_press_handler_manager_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include "base/bind.h"
+#include "base/time/time.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -15,7 +16,7 @@ namespace autofill {
namespace {
const content::NativeWebKeyboardEvent
- kDummyEvent(blink::WebInputEvent::kUndefined, 0, 0);
+ kDummyEvent(blink::WebInputEvent::kUndefined, 0, base::TimeTicks());
// Dummy keyboard event handler: ignores the event, but appends the given |name|
// to a logging |target|.
diff --git a/chromium/components/autofill/content/common/BUILD.gn b/chromium/components/autofill/content/common/BUILD.gn
index 9067738bc81..1b2628c71b0 100644
--- a/chromium/components/autofill/content/common/BUILD.gn
+++ b/chromium/components/autofill/content/common/BUILD.gn
@@ -12,7 +12,6 @@ mojom("mojo_interfaces") {
public_deps = [
":mojo_types",
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
"//ui/gfx/geometry/mojo",
"//url/mojom:url_mojom_gurl",
@@ -25,7 +24,6 @@ mojom("mojo_types") {
]
public_deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
"//url/mojom:url_mojom_gurl",
"//url/mojom:url_mojom_origin",
diff --git a/chromium/components/autofill/content/common/autofill_agent.mojom b/chromium/components/autofill/content/common/autofill_agent.mojom
index bec0acd1f70..66a2f598b61 100644
--- a/chromium/components/autofill/content/common/autofill_agent.mojom
+++ b/chromium/components/autofill/content/common/autofill_agent.mojom
@@ -21,8 +21,10 @@ interface AutofillAgent {
// Sends the heuristic and server field type predictions to the renderer.
FieldTypePredictionsAvailable(array<FormDataPredictions> forms);
- // Clears the currently displayed Autofill results.
- ClearForm();
+ // Clears the currently displayed Autofill results of the current section.
+ // The current section is the section to which the element corresponding to
+ // the last request belongs.
+ ClearSection();
// Tells the renderer that the Autofill previewed form should be cleared.
ClearPreviewedForm();
diff --git a/chromium/components/autofill/content/common/autofill_driver.mojom b/chromium/components/autofill/content/common/autofill_driver.mojom
index 25e8102eb04..c15cb9fa67a 100644
--- a/chromium/components/autofill/content/common/autofill_driver.mojom
+++ b/chromium/components/autofill/content/common/autofill_driver.mojom
@@ -123,14 +123,6 @@ interface PasswordManagerDriver {
mojo_base.mojom.String16 typed_username,
int32 options, gfx.mojom.RectF bounds);
- // Instructs the browser to show a popup with a warning that the form
- // is not secure. The popup will use |text_direction| for displaying
- // text. This popup is shown when a password form on a non-secure page is
- // autofilled on page load.
- ShowNotSecureWarning(mojo_base.mojom.TextDirection text_direction,
- gfx.mojom.RectF bounds);
-
-
// Instructs the browser to show a suggestion, which will redirect the user to
// the list of all saved passwords. The popup will use |text_direction| for
// displaying text.
diff --git a/chromium/components/autofill/content/common/autofill_types.mojom b/chromium/components/autofill/content/common/autofill_types.mojom
index ba1b71997f0..bbda37d00a4 100644
--- a/chromium/components/autofill/content/common/autofill_types.mojom
+++ b/chromium/components/autofill/content/common/autofill_types.mojom
@@ -63,8 +63,6 @@ enum PasswordFormSubmissionIndicatorEvent {
MANUAL_SAVE,
DOM_MUTATION_AFTER_XHR,
PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD,
- FILLED_FORM_ON_START_PROVISIONAL_LOAD,
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD,
SUBMISSION_INDICATOR_EVENT_COUNT
};
@@ -111,15 +109,21 @@ struct FormFieldData {
string autocomplete_attribute;
mojo_base.mojom.String16 placeholder;
mojo_base.mojom.String16 css_classes;
+ uint32 unique_renderer_id;
uint32 properties_mask;
uint64 max_length;
bool is_autofilled;
+ string section;
CheckStatus check_status;
bool is_focusable;
bool should_autocomplete;
RoleAttribute role;
mojo_base.mojom.TextDirection text_direction;
+ bool is_enabled;
+ bool is_readonly;
+ bool is_default;
+ mojo_base.mojom.String16 typed_value;
array<mojo_base.mojom.String16> option_values;
array<mojo_base.mojom.String16> option_contents;
@@ -136,6 +140,7 @@ struct FormData {
url.mojom.Origin main_frame_origin;
bool is_form_tag;
bool is_formless_checkout;
+ uint32 unique_renderer_id;
array<FormFieldData> fields;
};
@@ -147,6 +152,7 @@ struct FormFieldDataPredictions {
string server_type;
string overall_type;
string parseable_name;
+ string section;
};
// autofill::FormDataPredictions
@@ -227,9 +233,9 @@ struct PasswordForm {
bool was_parsed_using_autofill_predictions;
bool is_public_suffix_match;
bool is_affiliation_based_match;
- bool does_look_like_signup_form;
PasswordFormSubmissionIndicatorEvent submission_event;
bool only_for_fallback_saving;
+ bool is_gaia_with_skip_save_password_form;
};
// TODO(leonhsl): Use map directly after http://crbug.com/628104 solved.
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
index 51e4eeb3a11..d4552fd7520 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.cc
@@ -285,13 +285,10 @@ EnumTraits<autofill::mojom::PasswordFormSubmissionIndicatorEvent,
return autofill::mojom::PasswordFormSubmissionIndicatorEvent::
PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD;
case autofill::PasswordForm::SubmissionIndicatorEvent::
- FILLED_FORM_ON_START_PROVISIONAL_LOAD:
- return autofill::mojom::PasswordFormSubmissionIndicatorEvent::
- FILLED_FORM_ON_START_PROVISIONAL_LOAD;
+ DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD:
case autofill::PasswordForm::SubmissionIndicatorEvent::
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD:
- return autofill::mojom::PasswordFormSubmissionIndicatorEvent::
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD;
+ DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD:
+ break;
case autofill::PasswordForm::SubmissionIndicatorEvent::
SUBMISSION_INDICATOR_EVENT_COUNT:
return autofill::mojom::PasswordFormSubmissionIndicatorEvent::
@@ -342,16 +339,6 @@ bool EnumTraits<autofill::mojom::PasswordFormSubmissionIndicatorEvent,
PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD;
return true;
case autofill::mojom::PasswordFormSubmissionIndicatorEvent::
- FILLED_FORM_ON_START_PROVISIONAL_LOAD:
- *output = autofill::PasswordForm::SubmissionIndicatorEvent::
- FILLED_FORM_ON_START_PROVISIONAL_LOAD;
- return true;
- case autofill::mojom::PasswordFormSubmissionIndicatorEvent::
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD:
- *output = autofill::PasswordForm::SubmissionIndicatorEvent::
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD;
- return true;
- case autofill::mojom::PasswordFormSubmissionIndicatorEvent::
SUBMISSION_INDICATOR_EVENT_COUNT:
*output = autofill::PasswordForm::SubmissionIndicatorEvent::
SUBMISSION_INDICATOR_EVENT_COUNT;
@@ -570,8 +557,11 @@ bool StructTraits<
if (!data.ReadCssClasses(&out->css_classes))
return false;
- out->properties_mask = data.properties_mask();
+ if (!data.ReadSection(&out->section))
+ return false;
+ out->properties_mask = data.properties_mask();
+ out->unique_renderer_id = data.unique_renderer_id();
out->max_length = data.max_length();
out->is_autofilled = data.is_autofilled();
@@ -587,6 +577,12 @@ bool StructTraits<
if (!data.ReadTextDirection(&out->text_direction))
return false;
+ out->is_enabled = data.is_enabled();
+ out->is_readonly = data.is_readonly();
+ out->is_default = data.is_default();
+ if (!data.ReadValue(&out->typed_value))
+ return false;
+
if (!data.ReadOptionValues(&out->option_values))
return false;
if (!data.ReadOptionContents(&out->option_contents))
@@ -613,6 +609,7 @@ bool StructTraits<autofill::mojom::FormDataDataView, autofill::FormData>::Read(
out->is_form_tag = data.is_form_tag();
out->is_formless_checkout = data.is_formless_checkout();
+ out->unique_renderer_id = data.unique_renderer_id();
if (!data.ReadFields(&out->fields))
return false;
@@ -637,6 +634,8 @@ bool StructTraits<autofill::mojom::FormFieldDataPredictionsDataView,
return false;
if (!data.ReadParseableName(&out->parseable_name))
return false;
+ if (!data.ReadSection(&out->section))
+ return false;
return true;
}
@@ -772,8 +771,9 @@ bool StructTraits<
data.was_parsed_using_autofill_predictions();
out->is_public_suffix_match = data.is_public_suffix_match();
out->is_affiliation_based_match = data.is_affiliation_based_match();
- out->does_look_like_signup_form = data.does_look_like_signup_form();
out->only_for_fallback_saving = data.only_for_fallback_saving();
+ out->is_gaia_with_skip_save_password_form =
+ data.is_gaia_with_skip_save_password_form();
return true;
}
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits.h b/chromium/components/autofill/content/common/autofill_types_struct_traits.h
index e69832b4af0..4c42d624ac8 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits.h
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits.h
@@ -155,6 +155,10 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView,
return r.css_classes;
}
+ static uint32_t unique_renderer_id(const autofill::FormFieldData& r) {
+ return r.unique_renderer_id;
+ }
+
static uint32_t properties_mask(const autofill::FormFieldData& r) {
return r.properties_mask;
}
@@ -167,6 +171,10 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView,
return r.is_autofilled;
}
+ static const std::string& section(const autofill::FormFieldData& r) {
+ return r.section;
+ }
+
static autofill::FormFieldData::CheckStatus check_status(
const autofill::FormFieldData& r) {
return r.check_status;
@@ -190,6 +198,22 @@ struct StructTraits<autofill::mojom::FormFieldDataDataView,
return r.text_direction;
}
+ static bool is_enabled(const autofill::FormFieldData& r) {
+ return r.is_enabled;
+ }
+
+ static bool is_readonly(const autofill::FormFieldData& r) {
+ return r.is_readonly;
+ }
+
+ static bool is_default(const autofill::FormFieldData& r) {
+ return r.is_default;
+ }
+
+ static const base::string16& typed_value(const autofill::FormFieldData& r) {
+ return r.typed_value;
+ }
+
static const std::vector<base::string16>& option_values(
const autofill::FormFieldData& r) {
return r.option_values;
@@ -229,6 +253,10 @@ struct StructTraits<autofill::mojom::FormDataDataView, autofill::FormData> {
return r.is_formless_checkout;
}
+ static uint32_t unique_renderer_id(const autofill::FormData& r) {
+ return r.unique_renderer_id;
+ }
+
static const std::vector<autofill::FormFieldData>& fields(
const autofill::FormData& r) {
return r.fields;
@@ -271,6 +299,11 @@ struct StructTraits<autofill::mojom::FormFieldDataPredictionsDataView,
return r.parseable_name;
}
+ static const std::string& section(
+ const autofill::FormFieldDataPredictions& r) {
+ return r.section;
+ }
+
static bool Read(autofill::mojom::FormFieldDataPredictionsDataView data,
autofill::FormFieldDataPredictions* out);
};
@@ -544,10 +577,6 @@ struct StructTraits<autofill::mojom::PasswordFormDataView,
return r.is_affiliation_based_match;
}
- static bool does_look_like_signup_form(const autofill::PasswordForm& r) {
- return r.does_look_like_signup_form;
- }
-
static autofill::PasswordForm::SubmissionIndicatorEvent submission_event(
const autofill::PasswordForm& r) {
return r.submission_event;
@@ -557,6 +586,11 @@ struct StructTraits<autofill::mojom::PasswordFormDataView,
return r.only_for_fallback_saving;
}
+ static bool is_gaia_with_skip_save_password_form(
+ const autofill::PasswordForm& r) {
+ return r.is_gaia_with_skip_save_password_form;
+ }
+
static bool Read(autofill::mojom::PasswordFormDataView data,
autofill::PasswordForm* out);
};
diff --git a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
index b4e94937994..6c0b146e472 100644
--- a/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
+++ b/chromium/components/autofill/content/common/autofill_types_struct_traits_unittest.cc
@@ -31,6 +31,7 @@ void CreateTestFieldDataPredictions(const std::string& signature,
field_predict->server_type = "TestServerType";
field_predict->overall_type = "TestOverallType";
field_predict->parseable_name = "TestParseableName";
+ field_predict->section = "TestSection";
}
void CreateTestPasswordFormFillData(PasswordFormFillData* fill_data) {
@@ -104,7 +105,6 @@ void CreateTestPasswordForm(PasswordForm* form) {
form->was_parsed_using_autofill_predictions = false;
form->is_public_suffix_match = true;
form->is_affiliation_based_match = true;
- form->does_look_like_signup_form = true;
form->submission_event =
PasswordForm::SubmissionIndicatorEvent::SAME_DOCUMENT_NAVIGATION;
}
@@ -168,23 +168,6 @@ void CheckEqualPasswordFormFillData(const PasswordFormFillData& expected,
ASSERT_EQ(iter2, end2);
}
- {
- EXPECT_EQ(expected.other_possible_usernames.size(),
- actual.other_possible_usernames.size());
- auto iter1 = expected.other_possible_usernames.begin();
- auto end1 = expected.other_possible_usernames.end();
- auto iter2 = actual.other_possible_usernames.begin();
- auto end2 = actual.other_possible_usernames.end();
- for (; iter1 != end1 && iter2 != end2; ++iter1, ++iter2) {
- EXPECT_EQ(iter1->first.username, iter2->first.username);
- EXPECT_EQ(iter1->first.password, iter2->first.password);
- EXPECT_EQ(iter1->first.realm, iter2->first.realm);
- EXPECT_EQ(iter1->second, iter2->second);
- }
- ASSERT_EQ(iter1, end1);
- ASSERT_EQ(iter2, end2);
- }
-
EXPECT_EQ(expected.wait_for_username, actual.wait_for_username);
EXPECT_EQ(expected.is_possible_change_password_form,
actual.is_possible_change_password_form);
diff --git a/chromium/components/autofill/content/renderer/BUILD.gn b/chromium/components/autofill/content/renderer/BUILD.gn
index f668ef832b7..94cc1648850 100644
--- a/chromium/components/autofill/content/renderer/BUILD.gn
+++ b/chromium/components/autofill/content/renderer/BUILD.gn
@@ -88,12 +88,15 @@ static_library("test_support") {
source_set("unit_tests") {
testonly = true
sources = [
+ "form_cache_unittest.cc",
"renderer_save_password_progress_logger_unittest.cc",
]
deps = [
":test_support",
+ "//base/test:test_support",
"//components/autofill/content/common:mojo_interfaces",
+ "//components/autofill/core/common",
"//testing/gtest",
]
}
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.cc b/chromium/components/autofill/content/renderer/autofill_agent.cc
index 8d356a4bf90..2af83153a60 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/autofill_agent.cc
@@ -88,24 +88,7 @@ size_t kWaitTimeForSelectOptionsChangesMs = 50;
// Whether the "single click" autofill feature is enabled, through command-line
// or field trial.
bool IsSingleClickEnabled() {
-// On Android, default to showing the dropdown on field focus.
-// On desktop, require an extra click after field focus by default, unless the
-// experiment is active.
-#if defined(OS_ANDROID)
- return !base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSingleClickAutofill);
-#endif
- const std::string group_name =
- base::FieldTrialList::FindFullName("AutofillSingleClick");
-
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableSingleClickAutofill))
- return true;
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableSingleClickAutofill))
- return false;
-
- return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
+ return base::FeatureList::IsEnabled(features::kSingleClickAutofill);
}
// Gets all the data list values (with corresponding label) for the given
@@ -213,8 +196,10 @@ void AutofillAgent::DidChangeScrollOffset() {
// Post a task here since scroll offset may change during layout.
// (https://crbug.com/804886)
weak_ptr_factory_.InvalidateWeakPtrs();
- base::SequencedTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&AutofillAgent::DidChangeScrollOffsetImpl,
+ render_frame()
+ ->GetTaskRunner(blink::TaskType::kInternalUserInteraction)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&AutofillAgent::DidChangeScrollOffsetImpl,
weak_ptr_factory_.GetWeakPtr(), element_));
} else if (!IsKeyboardAccessoryEnabled()) {
HidePopup();
@@ -466,11 +451,11 @@ void AutofillAgent::FieldTypePredictionsAvailable(
}
}
-void AutofillAgent::ClearForm() {
+void AutofillAgent::ClearSection() {
if (element_.IsNull())
return;
- form_cache_.ClearFormWithElement(element_);
+ form_cache_.ClearSectionWithElement(element_);
}
void AutofillAgent::ClearPreviewedForm() {
@@ -558,14 +543,6 @@ void AutofillAgent::ShowInitialPasswordAccountSuggestions(
ShowSuggestions(element, options);
}
-void AutofillAgent::ShowNotSecureWarning(
- const blink::WebInputElement& element) {
- if (is_generation_popup_possibly_visible_)
- return;
- password_autofill_agent_->ShowNotSecureWarning(element);
- is_popup_possibly_visible_ = true;
-}
-
bool AutofillAgent::CollectFormlessElements(FormData* output) {
if (render_frame() == nullptr || render_frame()->GetWebFrame() == nullptr)
return false;
@@ -842,13 +819,11 @@ void AutofillAgent::FormControlElementClicked(
ShowSuggestionsOptions options;
options.autofill_on_empty_values = true;
- options.show_full_suggestion_list = element.IsAutofilled();
+ // Show full suggestions when clicking on an already-focused form field.
+ options.show_full_suggestion_list = element.IsAutofilled() || was_focused;
if (!IsSingleClickEnabled()) {
- // Show full suggestions when clicking on an already-focused form field. On
- // the initial click (not focused yet), only show password suggestions.
- options.show_full_suggestion_list =
- options.show_full_suggestion_list || was_focused;
+ // On the initial click (not focused yet), only show password suggestions.
options.show_password_suggestions_only = !was_focused;
}
ShowSuggestions(element, options);
@@ -1052,13 +1027,18 @@ void AutofillAgent::ReplaceElementIfNowInvalid(const FormData& original_form) {
}
}
- // Could not find the new version of the form, bail out.
- if (form_element.IsNull())
- return;
+ WebVector<WebFormControlElement> elements;
+ if (form_element.IsNull()) {
+ // Could not find the new version of the form, get all the unowned elements.
+ std::vector<WebElement> fieldsets;
+ elements = form_util::GetUnownedAutofillableFormFieldElements(
+ element_.GetDocument().All(), &fieldsets);
+ } else {
+ // Get all the elements of the new version of the form.
+ form_element.GetFormControlElements(elements);
+ }
// Try to find the new version of the last interacted element.
- WebVector<WebFormControlElement> elements;
- form_element.GetFormControlElements(elements);
for (const WebFormControlElement& element : elements) {
if (element_.NameForAutofill() == element.NameForAutofill()) {
element_ = element;
diff --git a/chromium/components/autofill/content/renderer/autofill_agent.h b/chromium/components/autofill/content/renderer/autofill_agent.h
index 48e808a8cef..36bf731bb83 100644
--- a/chromium/components/autofill/content/renderer/autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/autofill_agent.h
@@ -71,7 +71,7 @@ class AutofillAgent : public content::RenderFrameObserver,
void PreviewForm(int32_t id, const FormData& form) override;
void FieldTypePredictionsAvailable(
const std::vector<FormDataPredictions>& forms) override;
- void ClearForm() override;
+ void ClearSection() override;
void ClearPreviewedForm() override;
void FillFieldWithValue(const base::string16& value) override;
void PreviewFieldWithValue(const base::string16& value) override;
@@ -88,8 +88,6 @@ class AutofillAgent : public content::RenderFrameObserver,
void SetFocusRequiresScroll(bool require) override;
void SetQueryPasswordSuggestion(bool required) override;
- void ShowNotSecureWarning(const blink::WebInputElement& element);
-
void FormControlElementClicked(const blink::WebFormControlElement& element,
bool was_focused);
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util.cc b/chromium/components/autofill/content/renderer/form_autofill_util.cc
index 262132f3f56..4c4ed513388 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util.cc
@@ -9,12 +9,13 @@
#include <map>
#include <memory>
#include <set>
+#include <utility>
#include <vector>
#include "base/command_line.h"
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
@@ -820,10 +821,21 @@ void ForEachMatchingFormFieldCommon(
bool force_override,
const Callback& callback) {
DCHECK(control_elements);
- if (control_elements->size() != data.fields.size()) {
- // This case should be reachable only for pathological websites and tests,
- // which add or remove form fields while the user is interacting with the
- // Autofill popup.
+
+ const bool num_elements_matches_num_fields =
+ control_elements->size() == data.fields.size();
+ UMA_HISTOGRAM_BOOLEAN("Autofill.NumElementsMatchesNumFields",
+ num_elements_matches_num_fields);
+ if (!num_elements_matches_num_fields) {
+ // http://crbug.com/841784
+ // This pathological case was only thought to be reachable iff the fields
+ // are added/removed from the form while the user is interacting with the
+ // autofill popup.
+ //
+ // Is is also reachable for formless non-checkout forms when checkout
+ // restrictions are applied.
+ //
+ // TODO(crbug/847221): Add a UKM to capture these events.
return;
}
@@ -910,8 +922,9 @@ void ForEachMatchingUnownedFormField(const WebElement& initiating_element,
filters, force_override, callback);
}
-// Sets the |field|'s value to the value in |data|.
-// Also sets the "autofilled" attribute, causing the background to be yellow.
+// Sets the |field|'s value to the value in |data|, and specifies the section
+// for filled fields. Also sets the "autofilled" attribute,
+// causing the background to be yellow.
void FillFormField(const FormFieldData& data,
bool is_initiating_node,
blink::WebFormControlElement* field) {
@@ -923,6 +936,7 @@ void FillFormField(const FormFieldData& data,
return;
WebInputElement* input_element = ToWebInputElement(field);
+
if (IsCheckableElement(input_element)) {
input_element->SetChecked(IsChecked(data.check_status), true);
} else {
@@ -940,6 +954,7 @@ void FillFormField(const FormFieldData& data,
return;
field->SetAutofilled(true);
+ field->SetAutofillSection(WebString::FromUTF8(data.section));
if (is_initiating_node &&
((IsTextInput(input_element) || IsMonthInput(input_element)) ||
@@ -1011,12 +1026,12 @@ bool ExtractFieldsFromControlElements(
continue;
// Create a new FormFieldData, fill it out and map it to the field's name.
- FormFieldData* form_field = new FormFieldData;
+ auto form_field = std::make_unique<FormFieldData>();
WebFormControlElementToFormField(control_element,
field_value_and_properties_map,
- extract_mask, form_field);
- form_fields->push_back(base::WrapUnique(form_field));
- (*element_map)[control_element] = form_field;
+ extract_mask, form_field.get());
+ (*element_map)[control_element] = form_field.get();
+ form_fields->push_back(std::move(form_field));
(*fields_extracted)[i] = true;
// To avoid overly expensive computation, we impose a maximum number of
@@ -1215,6 +1230,46 @@ bool UnownedFormElementsAndFieldSetsToFormData(
field_value_and_properties_map, extract_mask, form, field);
}
+// Check if a script modified username is suitable for Password Manager to
+// remember.
+bool ScriptModifiedUsernameAcceptable(
+ const base::string16& value,
+ const base::string16& typed_value,
+ const FieldValueAndPropertiesMaskMap& field_value_and_properties_map) {
+ // The minimal size of a field value that will be substring-matched.
+ constexpr size_t kMinMatchSize = 3u;
+ const auto lowercase = base::i18n::ToLower(value);
+ const auto typed_lowercase = base::i18n::ToLower(typed_value);
+ // If the page-generated value is just a completion of the typed value, that's
+ // likely acceptable.
+ if (base::StartsWith(lowercase, typed_lowercase,
+ base::CompareCase::SENSITIVE)) {
+ return true;
+ }
+ if (typed_lowercase.size() >= kMinMatchSize &&
+ lowercase.find(typed_lowercase) != base::string16::npos) {
+ return true;
+ }
+
+ // If the page-generated value comes from user typed or autofilled values in
+ // other fields, that's also likely OK.
+ for (const auto& map_key : field_value_and_properties_map) {
+ const base::string16* typed_from_key = map_key.second.first.get();
+ if (!typed_from_key)
+ continue;
+ const WebInputElement* input_element = ToWebInputElement(&map_key.first);
+ if (input_element && input_element->IsTextField() &&
+ !input_element->IsPasswordFieldForAutofill() &&
+ typed_from_key->size() >= kMinMatchSize &&
+ lowercase.find(base::i18n::ToLower(*typed_from_key)) !=
+ base::string16::npos) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
} // namespace
ScopedLayoutPreventer::ScopedLayoutPreventer() {
@@ -1381,12 +1436,12 @@ const base::string16 GetFormIdentifier(const WebFormElement& form) {
}
bool IsWebElementVisible(const blink::WebElement& element) {
- // hasNonEmptyLayoutSize might trigger layout, but it didn't cause problems so
- // far. If the layout is prohibited, hasNonEmptyLayoutSize is still used. See
- // details in crbug.com/595078.
- bool res = g_prevent_layout ? element.HasNonEmptyLayoutSize()
- : element.IsFocusable();
- return res;
+ // Testing anything related to visibility is likely to trigger layout. If that
+ // should not happen, all elements are suspected of being visible. This is
+ // consistent with the default value of FormFieldData::is_focusable.
+ if (g_prevent_layout)
+ return true;
+ return element.IsFocusable();
}
std::vector<blink::WebFormControlElement> ExtractAutofillableElementsFromSet(
@@ -1430,6 +1485,7 @@ void WebFormControlElementToFormField(
if (id != field->name)
field->id = id;
+ field->unique_renderer_id = element.UniqueRendererFormControlId();
field->form_control_type = element.FormControlTypeForAutofill().Utf8();
field->autocomplete_attribute = element.GetAttribute(kAutocomplete).Utf8();
if (field->autocomplete_attribute.size() > kMaxDataLength) {
@@ -1461,8 +1517,7 @@ void WebFormControlElementToFormField(
IsTextAreaElement(element) ||
IsSelectElement(element)) {
field->is_autofilled = element.IsAutofilled();
- if (!g_prevent_layout)
- field->is_focusable = element.IsFocusable();
+ field->is_focusable = IsWebElementVisible(element);
field->should_autocomplete = element.AutoComplete();
// Use 'text-align: left|right' if set or 'direction' otherwise.
@@ -1474,6 +1529,9 @@ void WebFormControlElementToFormField(
field->text_direction = base::i18n::LEFT_TO_RIGHT;
else if (element.AlignmentForFormData() == "right")
field->text_direction = base::i18n::RIGHT_TO_LEFT;
+ field->is_enabled = element.IsEnabled();
+ field->is_readonly = element.IsReadOnly();
+ field->is_default = element.GetAttribute("value") == element.Value();
}
if (IsAutofillableInputElement(input_element)) {
@@ -1519,6 +1577,24 @@ void WebFormControlElementToFormField(
TruncateString(&value, kMaxDataLength);
field->value = value;
+
+ // If the field was autofilled or the user typed into it, check the value
+ // stored in |field_value_and_properties_map| against the value property of
+ // the DOM element. If they differ, then the scripts on the website modified
+ // the value afterwards. Store the original value as the |typed_value|, unless
+ // this is one of recognised situations when the site-modified value is more
+ // useful for filling.
+ if (field_value_and_properties_map &&
+ field->properties_mask & (FieldPropertiesFlags::USER_TYPED |
+ FieldPropertiesFlags::AUTOFILLED)) {
+ const base::string16 typed_value =
+ *field_value_and_properties_map->at(element).first;
+
+ if (!ScriptModifiedUsernameAcceptable(value, typed_value,
+ *field_value_and_properties_map)) {
+ field->typed_value = typed_value;
+ }
+ }
}
bool WebFormElementToFormData(
@@ -1533,8 +1609,9 @@ bool WebFormElementToFormData(
return false;
form->name = GetFormIdentifier(form_element);
+ form->unique_renderer_id = form_element.UniqueRendererFormId();
form->origin = GetCanonicalOriginForDocument(frame->GetDocument());
- form->action = frame->GetDocument().CompleteURL(form_element.Action());
+ form->action = GetCanonicalActionForForm(form_element);
if (frame->Top()) {
form->main_frame_origin = frame->Top()->GetSecurityOrigin();
} else {
@@ -1664,6 +1741,15 @@ bool UnownedCheckoutFormElementsAndFieldSetsToFormData(
}
}
+ // http://crbug.com/841784
+ // Capture the number of times this formless checkout logic prevents a from
+ // being autofilled (fill logic expects to receive a autofill field entry,
+ // possibly not fillable, for each control element).
+ // Note: this will be fixed by http://crbug.com/806987
+ UMA_HISTOGRAM_BOOLEAN(
+ "Autofill.UnownedFieldsWereFiltered",
+ elements_with_autocomplete.size() != control_elements.size());
+
if (elements_with_autocomplete.empty())
return false;
diff --git a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
index 76afd7e40c2..f5dabe4f781 100644
--- a/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/form_autofill_util_browsertest.cc
@@ -6,6 +6,7 @@
#include "base/strings/utf_string_conversions.h"
#include "content/public/test/render_view_test.h"
+#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/web_document.h"
@@ -130,7 +131,7 @@ const char kDivTableExample6Expected[] = "";
class FormAutofillUtilsTest : public content::RenderViewTest {
public:
- FormAutofillUtilsTest() : content::RenderViewTest() {}
+ FormAutofillUtilsTest() {}
~FormAutofillUtilsTest() override {}
};
@@ -264,3 +265,186 @@ TEST_F(FormAutofillUtilsTest, InferLabelSourceTest) {
EXPECT_EQ(test_case.label_source, label_source);
}
}
+
+TEST_F(FormAutofillUtilsTest, IsEnabled) {
+ LoadHTML(
+ "<input type='text' id='name1'>"
+ "<input type='password' disabled id='name2'>"
+ "<input type='password' id='name3'>"
+ "<input type='text' id='name4' disabled>");
+
+ const std::vector<blink::WebElement> dummy_fieldsets;
+
+ WebLocalFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+ std::vector<blink::WebFormControlElement> control_elements;
+ blink::WebElementCollection inputs =
+ web_frame->GetDocument().GetElementsByHTMLTagName("input");
+ for (blink::WebElement element = inputs.FirstItem(); !element.IsNull();
+ element = inputs.NextItem()) {
+ control_elements.push_back(element.To<blink::WebFormControlElement>());
+ }
+
+ autofill::FormData target;
+ EXPECT_TRUE(
+ autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
+ dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
+ nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr));
+ const struct {
+ const char* const name;
+ bool enabled;
+ } kExpectedFields[] = {
+ {"name1", true}, {"name2", false}, {"name3", true}, {"name4", false},
+ };
+ const size_t number_of_cases = arraysize(kExpectedFields);
+ ASSERT_EQ(number_of_cases, target.fields.size());
+ for (size_t i = 0; i < number_of_cases; ++i) {
+ EXPECT_EQ(base::UTF8ToUTF16(kExpectedFields[i].name),
+ target.fields[i].name);
+ EXPECT_EQ(kExpectedFields[i].enabled, target.fields[i].is_enabled);
+ }
+}
+
+TEST_F(FormAutofillUtilsTest, IsReadonly) {
+ LoadHTML(
+ "<input type='text' id='name1'>"
+ "<input readonly type='password' id='name2'>"
+ "<input type='password' id='name3'>"
+ "<input type='text' id='name4' readonly>");
+
+ const std::vector<blink::WebElement> dummy_fieldsets;
+
+ WebLocalFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+ std::vector<blink::WebFormControlElement> control_elements;
+ blink::WebElementCollection inputs =
+ web_frame->GetDocument().GetElementsByHTMLTagName("input");
+ for (blink::WebElement element = inputs.FirstItem(); !element.IsNull();
+ element = inputs.NextItem()) {
+ control_elements.push_back(element.To<blink::WebFormControlElement>());
+ }
+
+ autofill::FormData target;
+ EXPECT_TRUE(
+ autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
+ dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
+ nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr));
+ const struct {
+ const char* const name;
+ bool readonly;
+ } kExpectedFields[] = {
+ {"name1", false}, {"name2", true}, {"name3", false}, {"name4", true},
+ };
+ const size_t number_of_cases = arraysize(kExpectedFields);
+ ASSERT_EQ(number_of_cases, target.fields.size());
+ for (size_t i = 0; i < number_of_cases; ++i) {
+ EXPECT_EQ(base::UTF8ToUTF16(kExpectedFields[i].name),
+ target.fields[i].name);
+ EXPECT_EQ(kExpectedFields[i].readonly, target.fields[i].is_readonly);
+ }
+}
+
+TEST_F(FormAutofillUtilsTest, IsDefault) {
+ LoadHTML(
+ "<input type='text' id='name1' value='123'>"
+ "<input type='password' id='name2'>"
+ "<input type='password' id='name3'>"
+ "<input type='text' id='name4' value='321'>");
+
+ const std::vector<blink::WebElement> dummy_fieldsets;
+
+ WebLocalFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ web_frame->GetDocument()
+ .GetElementById("name1")
+ .To<blink::WebInputElement>()
+ .SetAutofillValue("abc");
+ web_frame->GetDocument()
+ .GetElementById("name3")
+ .To<blink::WebInputElement>()
+ .SetAutofillValue("abc");
+
+ std::vector<blink::WebFormControlElement> control_elements;
+ blink::WebElementCollection inputs =
+ web_frame->GetDocument().GetElementsByHTMLTagName("input");
+ for (blink::WebElement element = inputs.FirstItem(); !element.IsNull();
+ element = inputs.NextItem()) {
+ control_elements.push_back(element.To<blink::WebFormControlElement>());
+ }
+
+ autofill::FormData target;
+ EXPECT_TRUE(
+ autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
+ dummy_fieldsets, control_elements, nullptr, web_frame->GetDocument(),
+ nullptr, autofill::form_util::EXTRACT_NONE, &target, nullptr));
+ const struct {
+ const char* const name;
+ bool is_default;
+ } kExpectedFields[] = {
+ {"name1", false}, {"name2", true}, {"name3", false}, {"name4", true},
+ };
+ const size_t number_of_cases = arraysize(kExpectedFields);
+ ASSERT_EQ(number_of_cases, target.fields.size());
+ for (size_t i = 0; i < number_of_cases; ++i) {
+ EXPECT_EQ(base::UTF8ToUTF16(kExpectedFields[i].name),
+ target.fields[i].name);
+ EXPECT_EQ(kExpectedFields[i].is_default, target.fields[i].is_default);
+ }
+}
+
+TEST_F(FormAutofillUtilsTest, IsFocusable) {
+ LoadHTML(
+ "<input type='text' id='name1' value='123'>"
+ "<input type='text' id='name2' style='display:none'>");
+
+ const std::vector<blink::WebElement> dummy_fieldsets;
+
+ WebLocalFrame* web_frame = GetMainFrame();
+ ASSERT_TRUE(web_frame);
+
+ std::vector<blink::WebFormControlElement> control_elements;
+ control_elements.push_back(web_frame->GetDocument()
+ .GetElementById("name1")
+ .To<blink::WebFormControlElement>());
+ control_elements.push_back(web_frame->GetDocument()
+ .GetElementById("name2")
+ .To<blink::WebFormControlElement>());
+
+ // Computing visibility only happens if causing a layout in Blink is
+ // acceptable. The first block below checks the "layout acceptable"
+ // situation, the one after it the "layout to be avoided" situation.
+ {
+ EXPECT_TRUE(autofill::form_util::IsWebElementVisible(control_elements[0]));
+ EXPECT_FALSE(autofill::form_util::IsWebElementVisible(control_elements[1]));
+
+ autofill::FormData target;
+ EXPECT_TRUE(
+ autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
+ dummy_fieldsets, control_elements, nullptr,
+ web_frame->GetDocument(), nullptr,
+ autofill::form_util::EXTRACT_NONE, &target, nullptr));
+ ASSERT_EQ(2u, target.fields.size());
+ EXPECT_EQ(base::UTF8ToUTF16("name1"), target.fields[0].name);
+ EXPECT_TRUE(target.fields[0].is_focusable);
+ EXPECT_EQ(base::UTF8ToUTF16("name2"), target.fields[1].name);
+ EXPECT_FALSE(target.fields[1].is_focusable);
+ }
+ {
+ autofill::form_util::ScopedLayoutPreventer preventer;
+ EXPECT_TRUE(autofill::form_util::IsWebElementVisible(control_elements[0]));
+ EXPECT_TRUE(autofill::form_util::IsWebElementVisible(control_elements[1]));
+
+ autofill::FormData target;
+ EXPECT_TRUE(
+ autofill::form_util::UnownedPasswordFormElementsAndFieldSetsToFormData(
+ dummy_fieldsets, control_elements, nullptr,
+ web_frame->GetDocument(), nullptr,
+ autofill::form_util::EXTRACT_NONE, &target, nullptr));
+ ASSERT_EQ(2u, target.fields.size());
+ EXPECT_EQ(base::UTF8ToUTF16("name1"), target.fields[0].name);
+ EXPECT_TRUE(target.fields[0].is_focusable);
+ EXPECT_EQ(base::UTF8ToUTF16("name2"), target.fields[1].name);
+ EXPECT_TRUE(target.fields[1].is_focusable);
+ }
+}
diff --git a/chromium/components/autofill/content/renderer/form_cache.cc b/chromium/components/autofill/content/renderer/form_cache.cc
index f30ebbf6fe9..665ebda4b05 100644
--- a/chromium/components/autofill/content/renderer/form_cache.cc
+++ b/chromium/components/autofill/content/renderer/form_cache.cc
@@ -8,6 +8,7 @@
#include <string>
#include <utility>
+#include "base/feature_list.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/stl_util.h"
@@ -18,6 +19,7 @@
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/content/renderer/page_form_analyser_logger.h"
#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/strings/grit/components_strings.h"
#include "third_party/blink/public/platform/web_string.h"
@@ -47,74 +49,106 @@ namespace autofill {
namespace {
+static const char* kSupportedAutocompleteTypes[] = {"given-name",
+ "additional-name",
+ "family-name",
+ "name",
+ "honorific-suffix",
+ "email",
+ "tel-local",
+ "tel-area-code",
+ "tel-country-code",
+ "tel-national",
+ "tel",
+ "tel-extension",
+ "street-address",
+ "address-line1",
+ "address-line2",
+ "address-line3",
+ "address-level1",
+ "address-level2",
+ "address-level3",
+ "postal-code",
+ "country-name",
+ "cc-name",
+ "cc-given-name",
+ "cc-family-name",
+ "cc-number",
+ "cc-exp-month",
+ "cc-exp-year",
+ "cc-exp",
+ "cc-type",
+ "cc-csc",
+ "organization"};
+
// For a given |type| (a string representation of enum values), return the
// appropriate autocomplete value that should be suggested to the website
// developer.
const char* MapTypePredictionToAutocomplete(base::StringPiece type) {
if (type == "NAME_FIRST")
- return "given-name";
+ return kSupportedAutocompleteTypes[0];
if (type == "NAME_MIDDLE")
- return "additional-name";
+ return kSupportedAutocompleteTypes[1];
if (type == "NAME_LAST")
- return "family-name";
+ return kSupportedAutocompleteTypes[2];
if (type == "NAME_FULL")
- return "name";
+ return kSupportedAutocompleteTypes[3];
if (type == "NAME_SUFFIX")
- return "honorific-suffix";
+ return kSupportedAutocompleteTypes[4];
if (type == "EMAIL_ADDRESS")
- return "email";
+ return kSupportedAutocompleteTypes[5];
if (type == "PHONE_HOME_NUMBER")
- return "tel-local";
+ return kSupportedAutocompleteTypes[6];
if (type == "PHONE_HOME_CITY_CODE")
- return "tel-area-code";
+ return kSupportedAutocompleteTypes[7];
if (type == "PHONE_HOME_COUNTRY_CODE")
- return "tel-country-code";
+ return kSupportedAutocompleteTypes[8];
if (type == "PHONE_HOME_CITY_AND_NUMBER")
- return "tel-national";
+ return kSupportedAutocompleteTypes[9];
if (type == "PHONE_HOME_WHOLE_NUMBER")
- return "tel";
+ return kSupportedAutocompleteTypes[10];
if (type == "PHONE_HOME_EXTENSION")
- return "tel-extension";
+ return kSupportedAutocompleteTypes[11];
if (type == "ADDRESS_HOME_STREET_ADDRESS")
- return "street-address";
- if (type == "ADDRESS_HOME_DEPENDENT_LOCALITY")
- return "address-level3";
+ return kSupportedAutocompleteTypes[12];
if (type == "ADDRESS_HOME_LINE1")
- return "address-line1";
+ return kSupportedAutocompleteTypes[13];
if (type == "ADDRESS_HOME_LINE2")
- return "address-line2";
+ return kSupportedAutocompleteTypes[14];
if (type == "ADDRESS_HOME_LINE3")
- return "address-line3";
+ return kSupportedAutocompleteTypes[15];
if (type == "ADDRESS_HOME_CITY")
- return "address-level2";
+ return kSupportedAutocompleteTypes[16];
if (type == "ADDRESS_HOME_STATE")
- return "address-level1";
+ return kSupportedAutocompleteTypes[17];
+ if (type == "ADDRESS_HOME_DEPENDENT_LOCALITY")
+ return kSupportedAutocompleteTypes[18];
if (type == "ADDRESS_HOME_ZIP")
- return "postal-code";
+ return kSupportedAutocompleteTypes[19];
if (type == "ADDRESS_HOME_COUNTRY")
- return "country-name";
+ return kSupportedAutocompleteTypes[20];
if (type == "CREDIT_CARD_NAME_FULL")
- return "cc-name";
+ return kSupportedAutocompleteTypes[21];
if (type == "CREDIT_CARD_NAME_FIRST")
- return "cc-given-name";
+ return kSupportedAutocompleteTypes[22];
if (type == "CREDIT_CARD_NAME_LAST")
- return "cc-family-name";
+ return kSupportedAutocompleteTypes[23];
if (type == "CREDIT_CARD_NUMBER")
- return "cc-number";
+ return kSupportedAutocompleteTypes[24];
if (type == "CREDIT_CARD_EXP_MONTH")
- return "cc-exp-month";
+ return kSupportedAutocompleteTypes[25];
if (type == "CREDIT_CARD_EXP_2_DIGIT_YEAR" ||
type == "CREDIT_CARD_EXP_4_DIGIT_YEAR")
- return "cc-exp-year";
+ return kSupportedAutocompleteTypes[26];
if (type == "CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR" ||
type == "CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR")
- return "cc-exp";
+ return kSupportedAutocompleteTypes[27];
if (type == "CREDIT_CARD_TYPE")
- return "cc-type";
+ return kSupportedAutocompleteTypes[28];
if (type == "CREDIT_CARD_VERIFICATION_CODE")
- return "cc-csc";
+ return kSupportedAutocompleteTypes[29];
if (type == "COMPANY_NAME")
- return "organization";
+ return kSupportedAutocompleteTypes[30];
return "";
}
@@ -265,7 +299,7 @@ void FormCache::Reset() {
initial_checked_state_.clear();
}
-bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
+bool FormCache::ClearSectionWithElement(const WebFormControlElement& element) {
WebFormElement form_element = element.Form();
std::vector<WebFormControlElement> control_elements;
if (form_element.IsNull()) {
@@ -285,6 +319,9 @@ bool FormCache::ClearFormWithElement(const WebFormControlElement& element) {
if (!control_element.IsAutofilled())
continue;
+ if (control_element.AutofillSection() != element.AutofillSection())
+ continue;
+
control_element.SetAutofilled(false);
WebInputElement* input_element = ToWebInputElement(&control_element);
@@ -394,15 +431,9 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
// autocomplete attributes.
const std::string predicted_autocomplete_attribute =
MapTypePredictionToAutocomplete(field.overall_type);
- std::string actual_autocomplete_attribute =
- element.GetAttribute("autocomplete").Utf8();
- if (!predicted_autocomplete_attribute.empty() &&
- (actual_autocomplete_attribute.empty() ||
- !base::ContainsValue(
- base::SplitStringPiece(actual_autocomplete_attribute, " ",
- base::WhitespaceHandling::TRIM_WHITESPACE,
- base::SplitResult::SPLIT_WANT_NONEMPTY),
- predicted_autocomplete_attribute))) {
+ if (ShouldShowAutocompleteConsoleWarnings(
+ predicted_autocomplete_attribute,
+ element.GetAttribute("autocomplete").Utf8())) {
logger.Send(
base::StringPrintf("Input elements should have autocomplete "
"attributes (suggested: autocomplete='%s', "
@@ -418,13 +449,13 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
0, std::min(field_data.label.length(), kMaxLabelSize));
// A rough estimate of the maximum title size is:
- // 7 field titles at <17 chars each
- // + 6 values at <40 chars each
+ // 8 field titles at <17 chars each
+ // + 7 values at <40 chars each
// + 1 truncated label at <kMaxLabelSize;
- // = 459 chars, rounded up to the next multiple of 64 = 512
+ // = 516 chars, rounded up to the next multiple of 64 = 576
// A particularly large parseable name could blow through this and cause
// another allocation, but that's OK.
- constexpr size_t kMaxTitleSize = 512;
+ constexpr size_t kMaxTitleSize = 576;
std::string title;
title.reserve(kMaxTitleSize);
title += "overall type: ";
@@ -437,6 +468,8 @@ bool FormCache::ShowPredictions(const FormDataPredictions& form,
title += base::UTF16ToUTF8(truncated_label);
title += "\nparseable name: ";
title += field.parseable_name;
+ title += "\nsection: ";
+ title += field.section;
title += "\nfield signature: ";
title += field.signature;
title += "\nform signature: ";
@@ -495,4 +528,36 @@ void FormCache::SaveInitialValues(
}
}
+bool FormCache::ShouldShowAutocompleteConsoleWarnings(
+ const std::string& predicted_autocomplete,
+ const std::string& actual_autocomplete) {
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillShowAutocompleteConsoleWarnings)) {
+ return false;
+ }
+
+ // If we have no better prediction, do not show.
+ if (predicted_autocomplete.empty())
+ return false;
+
+ // We should show a warning if the actual autocomplete attribute is empty,
+ // or we recognize the autocomplete attribute, but we think it's the wrong
+ // one.
+ if (actual_autocomplete.empty())
+ return true;
+
+ // An autocomplete attribute can be multiple strings (e.g. "shipping name").
+ // Look at all the tokens.
+ for (base::StringPiece actual : base::SplitStringPiece(
+ actual_autocomplete, " ", base::WhitespaceHandling::TRIM_WHITESPACE,
+ base::SplitResult::SPLIT_WANT_NONEMPTY)) {
+ // If we recognize the value but it's not correct, show a warning.
+ if (base::ContainsValue(kSupportedAutocompleteTypes, actual) &&
+ actual != predicted_autocomplete) {
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/form_cache.h b/chromium/components/autofill/content/renderer/form_cache.h
index c4f66297421..c4db022d8cb 100644
--- a/chromium/components/autofill/content/renderer/form_cache.h
+++ b/chromium/components/autofill/content/renderer/form_cache.h
@@ -11,6 +11,7 @@
#include <set>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/autofill/core/common/form_data.h"
@@ -39,9 +40,9 @@ class FormCache {
// Resets the forms.
void Reset();
- // Clears the values of all input elements in the form that contains
- // |element|. Returns false if the form is not found.
- bool ClearFormWithElement(const blink::WebFormControlElement& element);
+ // Clears the values of all input elements in the section of the form that
+ // contains |element|. Returns false if the form is not found.
+ bool ClearSectionWithElement(const blink::WebFormControlElement& element);
// For each field in the |form|, if |attach_predictions_to_dom| is true, sets
// the title to include the field's heuristic type, server type, and
@@ -52,6 +53,11 @@ class FormCache {
bool attach_predictions_to_dom);
private:
+ FRIEND_TEST_ALL_PREFIXES(FormCacheTest,
+ ShouldShowAutocompleteConsoleWarnings_Enabled);
+ FRIEND_TEST_ALL_PREFIXES(FormCacheTest,
+ ShouldShowAutocompleteConsoleWarnings_Disabled);
+
// Scans |control_elements| and returns the number of editable elements.
// Also remembers the initial <select> and <input> element states, and
// logs warning messages for deprecated attribute if
@@ -64,6 +70,14 @@ class FormCache {
void SaveInitialValues(
const std::vector<blink::WebFormControlElement>& control_elements);
+ // Returns whether we should show a console warning related to a wrong
+ // autocomplete attribute. We will show a warning if (1) there is no
+ // autocomplete attribute and we have a guess for one or (2) we recognize the
+ // autocomplete attribute but it appears to be the wrong one.
+ bool ShouldShowAutocompleteConsoleWarnings(
+ const std::string& predicted_autocomplete,
+ const std::string& actual_autocomplete);
+
// The frame this FormCache is associated with. Weak reference.
blink::WebLocalFrame* frame_;
diff --git a/chromium/components/autofill/content/renderer/form_cache_unittest.cc b/chromium/components/autofill/content/renderer/form_cache_unittest.cc
new file mode 100644
index 00000000000..1cf98ed29fd
--- /dev/null
+++ b/chromium/components/autofill/content/renderer/form_cache_unittest.cc
@@ -0,0 +1,82 @@
+// 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 "components/autofill/content/renderer/form_cache.h"
+
+#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+class FormCacheTest : public testing::Test {
+ public:
+ FormCacheTest() {}
+
+ protected:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(FormCacheTest);
+};
+
+TEST_F(FormCacheTest, ShouldShowAutocompleteConsoleWarnings_Enabled) {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillShowAutocompleteConsoleWarnings);
+ FormCache form_cache(nullptr);
+
+ // If we have a prediction and the actual attribute is empty.
+ EXPECT_TRUE(
+ form_cache.ShouldShowAutocompleteConsoleWarnings("given-name", ""));
+ // There is a predicted type, and there is an recognized type that is not the
+ // same.
+ EXPECT_TRUE(
+ form_cache.ShouldShowAutocompleteConsoleWarnings("given-name", "name"));
+ // Multi-values: there is a predicted type, and there is an recognized type
+ // that is not the same.
+ EXPECT_TRUE(form_cache.ShouldShowAutocompleteConsoleWarnings(
+ "given-name", "shipping name"));
+ // Multi-values: there is a predicted type, and there is an recognized type
+ // that is not the same along with an unrecognized type.
+ EXPECT_TRUE(form_cache.ShouldShowAutocompleteConsoleWarnings("given-name",
+ "fake name"));
+
+ // No predicted type, no actual attribute.
+ EXPECT_FALSE(form_cache.ShouldShowAutocompleteConsoleWarnings("", ""));
+ // No predicted type, and there is a recognized type.
+ EXPECT_FALSE(
+ form_cache.ShouldShowAutocompleteConsoleWarnings("", "given-name"));
+ // No predicted type, and there is an unrecognized type.
+ EXPECT_FALSE(form_cache.ShouldShowAutocompleteConsoleWarnings("", "fake"));
+ // There is a predicted type, and there is an unrecognized type.
+ EXPECT_FALSE(
+ form_cache.ShouldShowAutocompleteConsoleWarnings("given-name", "fake"));
+ // Multi-values: there is a predicted type, and there is an recognized type
+ // that is the same.
+ EXPECT_FALSE(form_cache.ShouldShowAutocompleteConsoleWarnings(
+ "given-name", "shipping given-name"));
+ // Multi-values: there is a predicted type, and there is an unrecognized type.
+ EXPECT_FALSE(form_cache.ShouldShowAutocompleteConsoleWarnings(
+ "given-name", "shipping fake"));
+}
+
+TEST_F(FormCacheTest, ShouldShowAutocompleteConsoleWarnings_Disabled) {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillShowAutocompleteConsoleWarnings);
+ FormCache form_cache(nullptr);
+
+ // If we have a prediction and the actual attribute is empty.
+ EXPECT_FALSE(
+ form_cache.ShouldShowAutocompleteConsoleWarnings("given-name", ""));
+ // There is a predicted type, and there is an recognized type that is not the
+ // same.
+ EXPECT_FALSE(
+ form_cache.ShouldShowAutocompleteConsoleWarnings("given-name", "name"));
+ // Multi-values: there is a predicted type, and there is an recognized type
+ // that is not the same.
+ EXPECT_FALSE(form_cache.ShouldShowAutocompleteConsoleWarnings(
+ "given-name", "shipping name"));
+}
+
+} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.cc b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
index 10e7b1ec23d..350bfc6e824 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.cc
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.cc
@@ -65,23 +65,13 @@ struct CategoryOfWords {
// Used only inside DCHECK.
bool AllElementsBelongsToSameForm(
- const std::vector<blink::WebFormControlElement>& all_control_elements,
- const std::vector<blink::WebInputElement>& possible_usernames) {
- if (std::adjacent_find(
- possible_usernames.begin(), possible_usernames.end(),
- [](const blink::WebInputElement& a, const blink::WebInputElement& b) {
- return a.Form() != b.Form();
- }) != possible_usernames.end())
- return false;
- if (std::adjacent_find(all_control_elements.begin(),
- all_control_elements.end(),
- [](const blink::WebFormControlElement& a,
- const blink::WebFormControlElement& b) {
- return a.Form() != b.Form();
- }) != all_control_elements.end())
- return false;
- DCHECK(!all_control_elements.empty());
- return all_control_elements[0].Form() == possible_usernames[0].Form();
+ const std::vector<WebFormControlElement>& all_control_elements) {
+ return std::adjacent_find(all_control_elements.begin(),
+ all_control_elements.end(),
+ [](const WebFormControlElement& a,
+ const WebFormControlElement& b) {
+ return a.Form() != b.Form();
+ }) == all_control_elements.end();
}
// 1. Removes delimiters from |raw_value| and appends the remainder to
@@ -295,69 +285,38 @@ void FindUsernameFieldInternal(
}
}
-// Find the first element in |username_predictions| (i.e. the most reliable
-// prediction) that occurs in |possible_usernames|. If the element found, the
-// method saves it to |username_element| and returns true.
-bool FindUsernameInPredictions(
- const std::vector<blink::WebInputElement>& username_predictions,
- const std::vector<blink::WebInputElement>& possible_usernames,
- WebInputElement* username_element) {
- // To keep linear time complexity, convert |possible_usernames| to a set.
- const base::flat_set<blink::WebInputElement> usernames(
- possible_usernames.begin(), possible_usernames.end());
-
- for (const blink::WebInputElement& prediction : username_predictions) {
- auto iter = usernames.find(prediction);
- if (iter != usernames.end()) {
- *username_element = *iter;
- return true;
- }
- }
- return false;
-}
-
} // namespace
-bool GetUsernameFieldBasedOnHtmlAttributes(
- const std::vector<blink::WebFormControlElement>& all_control_elements,
- const std::vector<blink::WebInputElement>& possible_usernames,
+const std::vector<WebInputElement>& GetPredictionsFieldBasedOnHtmlAttributes(
+ const std::vector<WebFormControlElement>& all_control_elements,
const FormData& form_data,
- WebInputElement* username_element,
UsernameDetectorCache* username_detector_cache) {
- DCHECK(username_element);
+ // The cache will store the object referenced in the return value, so it must
+ // exist. It can be empty.
+ DCHECK(username_detector_cache);
- if (possible_usernames.empty())
- return false;
+ DCHECK(!all_control_elements.empty());
- // All elements in |possible_usernames| and |all_control_elements| should have
- // the same |Form()|.
- DCHECK(
- AllElementsBelongsToSameForm(all_control_elements, possible_usernames));
+ // All elements in |all_control_elements| should have the same |Form()|.
+ DCHECK(AllElementsBelongsToSameForm(all_control_elements));
- const blink::WebFormElement form = possible_usernames[0].Form();
+ const WebFormElement form = all_control_elements[0].Form();
// True if the cache has no entry for |form|.
bool cache_miss = true;
// Iterator pointing to the entry for |form| if the entry for |form| is found.
UsernameDetectorCache::iterator form_position;
- if (username_detector_cache) {
- std::tie(form_position, cache_miss) = username_detector_cache->insert(
- std::make_pair(form, std::vector<blink::WebInputElement>()));
- }
+ std::tie(form_position, cache_miss) = username_detector_cache->insert(
+ std::make_pair(form, std::vector<WebInputElement>()));
- if (!username_detector_cache || cache_miss) {
- std::vector<blink::WebInputElement> username_predictions;
+ if (cache_miss) {
+ std::vector<WebInputElement> username_predictions;
FindUsernameFieldInternal(all_control_elements, form_data,
&username_predictions);
- bool result = FindUsernameInPredictions(
- username_predictions, possible_usernames, username_element);
- if (username_detector_cache && !username_predictions.empty())
+ if (!username_predictions.empty())
form_position->second = std::move(username_predictions);
- return result;
}
-
- return FindUsernameInPredictions(form_position->second, possible_usernames,
- username_element);
+ return form_position->second;
}
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/html_based_username_detector.h b/chromium/components/autofill/content/renderer/html_based_username_detector.h
index 9d4490a4629..ffebdd8b2b9 100644
--- a/chromium/components/autofill/content/renderer/html_based_username_detector.h
+++ b/chromium/components/autofill/content/renderer/html_based_username_detector.h
@@ -19,21 +19,20 @@ using UsernameDetectorCache =
std::map<blink::WebFormElement, std::vector<blink::WebInputElement>>;
// Classifier for getting username field by analyzing HTML attribute values.
-// The algorithm looks for words that are likely to point to username field
-// (ex. "username", "loginid" etc.), in the attribute values. When the first
-// match is found, the currently analyzed field is saved in |username_element|,
-// and the algorithm ends. By searching for words in order of their probability
-// to be username words, it is sure that the first match will also be the best
-// one. The function returns true if username element was found.
+// The algorithm looks for words that are likely to point to username field (ex.
+// "username", "loginid" etc.), in the attribute values. When the first match is
+// found, the currently analyzed field is saved in |username_element|, and the
+// algorithm ends. By searching for words in order of their probability to be
+// username words, it is sure that the first match will also be the best one.
// If detector's outcome for the given form is cached in
// |username_detector_cache|, then |username_element| is set based on the cached
// data. Otherwise, the detector will be run and the outcome will be saved to
-// the cache. |username_detector_cache| can be null.
-bool GetUsernameFieldBasedOnHtmlAttributes(
+// the cache. The function returns a reference to the vector of predictions,
+// which is stored in the cache.
+const std::vector<blink::WebInputElement>&
+GetPredictionsFieldBasedOnHtmlAttributes(
const std::vector<blink::WebFormControlElement>& all_control_elements,
- const std::vector<blink::WebInputElement>& possible_usernames,
const FormData& form_data,
- blink::WebInputElement* username_element,
UsernameDetectorCache* username_detector_cache);
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.cc b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
index ebffb6edd33..ea087e2d270 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.cc
@@ -13,10 +13,11 @@
#include <vector>
#include "base/bind.h"
+#include "base/containers/flat_set.h"
#include "base/i18n/case_conversion.h"
#include "base/memory/linked_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -79,6 +80,66 @@ bool FillDataContainsFillableUsername(const PasswordFormFillData& fill_data) {
!fill_data.username_field.value.empty());
}
+// Checks if the prefilled value of the username element is one of the known
+// values possibly used as placeholders. The list of possible placeholder
+// values comes from popular sites exhibiting this issue.
+// TODO(crbug.com/832622): Remove this once a stable solution is in place.
+bool PossiblePrefilledUsernameValue(const std::string& username_value) {
+ // Explicitly create a |StringFlatSet| when constructing
+ // kPrefilledUsernameValues to work around GCC bug 84849, which causes the
+ // initializer list not to be properly forwarded to base::flat_set's
+ // constructor.
+ using StringFlatSet = base::flat_set<std::string, std::less<>>;
+ static base::NoDestructor<StringFlatSet> kPrefilledUsernameValues(
+ StringFlatSet({"3~15个字符,中文字符7个以内",
+ "Benutzername",
+ "Digite seu CPF ou e-mail",
+ "DS Logon Username",
+ "Email Address",
+ "email address",
+ "Email masih kosong",
+ "Email/手機號碼",
+ "Enter User Name",
+ "Identifiant",
+ "Kullanıcı Adı",
+ "Kunden-ID",
+ "Nick",
+ "Nom Utilisateur",
+ "Rut",
+ "Siret",
+ "this is usually your email address",
+ "UID/用戶名/Email",
+ "User Id",
+ "User Name",
+ "Username",
+ "username",
+ "username or email",
+ "Username or email:",
+ "Username/Email",
+ "Usuario",
+ "Your email address",
+ "Имя",
+ "Логин",
+ "Логин...",
+ "כתובת דוא''ל",
+ "اسم العضو",
+ "اسم المستخدم",
+ "الاسم",
+ "نام کاربری",
+ "メールアドレス",
+ "用户名",
+ "用户名/Email",
+ "請輸入身份證字號",
+ "请用微博帐号登录",
+ "请输入手机号或邮箱",
+ "请输入邮箱或手机号",
+ "邮箱/手机/展位号"}));
+
+ return kPrefilledUsernameValues->find(
+ base::TrimWhitespaceASCII(username_value, base::TRIM_ALL)) !=
+ kPrefilledUsernameValues->end();
+}
+
// Returns true if password form has username and password fields with either
// same or no name and id attributes supplied.
bool DoesFormContainAmbiguousOrEmptyNames(
@@ -106,10 +167,12 @@ bool HasPasswordWithAutocompleteAttribute(
const blink::WebInputElement input_element =
control_element.ToConst<blink::WebInputElement>();
+ const AutocompleteFlag flag = AutocompleteFlagForElement(input_element);
if (input_element.IsPasswordFieldForAutofill() &&
- (HasAutocompleteAttributeValue(input_element, "current-password") ||
- HasAutocompleteAttributeValue(input_element, "new-password")))
+ (flag == AutocompleteFlag::CURRENT_PASSWORD ||
+ flag == AutocompleteFlag::NEW_PASSWORD)) {
return true;
+ }
}
return false;
@@ -171,7 +234,8 @@ bool FindFormInputElement(
// set. Also make sure we avoid keeping password fields having
// |autocomplete='new-password'| attribute set.
if (ambiguous_and_multiple_password_fields_with_autocomplete &&
- !HasAutocompleteAttributeValue(input_element, "current-password")) {
+ AutocompleteFlagForElement(input_element) !=
+ AutocompleteFlag::CURRENT_PASSWORD) {
continue;
}
@@ -296,15 +360,6 @@ bool IsUsernameAmendable(const blink::WebInputElement& username_element,
username_element.Value().IsEmpty());
}
-// Return true if either password_value or new_password_value is not empty and
-// not default.
-bool FormContainsNonDefaultPasswordValue(const PasswordForm& password_form) {
- return (!password_form.password_value.empty() &&
- !password_form.password_value_is_default) ||
- (!password_form.new_password_value.empty() &&
- !password_form.new_password_value_is_default);
-}
-
// Log a message including the name, method and action of |form|.
void LogHTMLForm(SavePasswordProgressLogger* logger,
SavePasswordProgressLogger::StringID message_id,
@@ -321,17 +376,6 @@ bool CanShowSuggestion(const PasswordFormFillData& fill_data,
const base::string16& current_username,
bool show_all) {
base::string16 current_username_lower = base::i18n::ToLower(current_username);
- for (const auto& usernames : fill_data.other_possible_usernames) {
- for (size_t i = 0; i < usernames.second.size(); ++i) {
- if (show_all ||
- base::StartsWith(
- base::i18n::ToLower(base::string16(usernames.second[i])),
- current_username_lower, base::CompareCase::SENSITIVE)) {
- return true;
- }
- }
- }
-
if (show_all ||
base::StartsWith(base::i18n::ToLower(fill_data.username_field.value),
current_username_lower, base::CompareCase::SENSITIVE)) {
@@ -415,22 +459,6 @@ void FindMatchesByUsername(const PasswordFormFillData& fill_data,
logger->LogBoolean(Logger::STRING_MATCH_IN_ADDITIONAL,
!(username->empty() && password->empty()));
}
-
- // Check possible usernames.
- if (username->empty() && password->empty()) {
- for (const auto& it : fill_data.other_possible_usernames) {
- for (size_t i = 0; i < it.second.size(); ++i) {
- if (DoUsernamesMatch(it.second[i], current_username,
- exact_username_match)) {
- *username = it.second[i];
- *password = it.first.password;
- break;
- }
- }
- if (!password->empty())
- break;
- }
- }
}
}
@@ -566,7 +594,7 @@ bool ShouldShowStandaloneManuallFallback(const blink::WebInputElement& element,
return (
element.IsPasswordFieldForAutofill() &&
!IsCreditCardVerificationPasswordField(element) &&
- !HasCreditCardAutocompleteAttributes(element) &&
+ AutocompleteFlagForElement(element) != AutocompleteFlag::CREDIT_CARD &&
!base::StartsWith(url.scheme(), "chrome", base::CompareCase::SENSITIVE) &&
!url.SchemeIs(url::kAboutScheme) &&
base::FeatureList::IsEnabled(
@@ -601,7 +629,6 @@ PasswordAutofillAgent::PasswordAutofillAgent(
content::RenderFrame* render_frame,
service_manager::BinderRegistry* registry)
: content::RenderFrameObserver(render_frame),
- web_input_to_password_info_(),
last_supplied_password_info_iter_(web_input_to_password_info_.end()),
logging_state_active_(false),
was_username_autofilled_(false),
@@ -671,8 +698,10 @@ void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() {
void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue(
blink::WebInputElement* element) {
- if (!element->IsNull() && !element->SuggestedValue().IsEmpty())
+ if (!element->IsNull() && !element->SuggestedValue().IsEmpty()) {
element->SetAutofillValue(element->SuggestedValue());
+ element->SetAutofilled(true);
+ }
}
bool PasswordAutofillAgent::TextDidChangeInTextField(
@@ -887,16 +916,6 @@ bool PasswordAutofillAgent::FindPasswordInfoForElement(
return true;
}
-bool PasswordAutofillAgent::ShouldShowNotSecureWarning(
- const blink::WebInputElement& element) {
- // Do not show a warning if the feature is disabled or the context is secure.
- return security_state::IsHttpWarningInFormEnabled() &&
- !content::IsOriginSecure(
- url::Origin(
- render_frame()->GetWebFrame()->Top()->GetSecurityOrigin())
- .GetURL());
-}
-
bool PasswordAutofillAgent::IsUsernameOrPasswordField(
const blink::WebInputElement& element) {
// Note: A site may use a Password field to collect a CVV or a Credit Card
@@ -906,7 +925,7 @@ bool PasswordAutofillAgent::IsUsernameOrPasswordField(
return true;
// If a field declares itself a username input, show the warning.
- if (HasAutocompleteAttributeValue(element, "username"))
+ if (AutocompleteFlagForElement(element) == AutocompleteFlag::USERNAME)
return true;
// Otherwise, analyze the form and return true if this input element seems
@@ -955,13 +974,6 @@ bool PasswordAutofillAgent::ShowSuggestions(
ShowManualFallbackSuggestion(element)) {
return true;
}
-
- if (ShouldShowNotSecureWarning(element)) {
- AutofillAgent* agent = autofill_agent_.get();
- if (agent)
- agent->ShowNotSecureWarning(element);
- return true;
- }
}
return false;
}
@@ -1006,16 +1018,6 @@ bool PasswordAutofillAgent::ShowSuggestions(
element.IsPasswordFieldForAutofill());
}
-void PasswordAutofillAgent::ShowNotSecureWarning(
- const blink::WebInputElement& element) {
- FormData form;
- FormFieldData field;
- form_util::FindFormAndFieldForFormControlElement(element, &form, &field);
- GetPasswordManagerDriver()->ShowNotSecureWarning(
- field.text_direction,
- render_frame()->GetRenderView()->ElementBoundsInWindow(element));
-}
-
bool PasswordAutofillAgent::FrameCanAccessPasswordManager() {
// about:blank or about:srcdoc frames should not be allowed to use password
// manager. See https://crbug.com/756587.
@@ -1104,16 +1106,6 @@ void PasswordAutofillAgent::SendPasswordForms(bool only_visible) {
std::vector<PasswordForm> password_forms;
for (const blink::WebFormElement& form : forms) {
- if (IsGaiaReauthenticationForm(form)) {
- // Bail if this is a GAIA passwords site reauthentication form, so that
- // page will be ignored.
- return;
- }
- if (IsGaiaWithSkipSavePasswordForm(form)) {
- // Bail if this is a GAIA enable Chrome sync flow, so that page will be
- // ignored.
- return;
- }
if (only_visible) {
bool is_form_visible = form_util::AreFormContentsVisible(form);
if (logger) {
@@ -1356,51 +1348,6 @@ void PasswordAutofillAgent::OnProbablyFormSubmitted() {
GetPasswordManagerDriver()->PasswordFormSubmitted(
provisionally_saved_form_.password_form());
provisionally_saved_form_.Reset();
- } else {
- std::vector<std::unique_ptr<PasswordForm>> possible_submitted_forms;
- // Loop through the forms on the page looking for one that has been
- // filled out. If one exists, try and save the credentials.
- blink::WebVector<blink::WebFormElement> forms;
- render_frame()->GetWebFrame()->GetDocument().Forms(forms);
-
- bool password_forms_found = false;
- for (const auto& form_element : forms) {
- if (logger) {
- LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE,
- form_element);
- }
- std::unique_ptr<PasswordForm> form =
- GetPasswordFormFromWebForm(form_element);
- if (form) {
- form->submission_event = PasswordForm::SubmissionIndicatorEvent::
- FILLED_FORM_ON_START_PROVISIONAL_LOAD;
- possible_submitted_forms.push_back(std::move(form));
- }
- }
-
- std::unique_ptr<PasswordForm> form =
- GetPasswordFormFromUnownedInputElements();
- if (form) {
- form->submission_event = PasswordForm::SubmissionIndicatorEvent::
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD;
- possible_submitted_forms.push_back(std::move(form));
- }
-
- for (const auto& password_form : possible_submitted_forms) {
- if (password_form && !password_form->username_value.empty() &&
- FormContainsNonDefaultPasswordValue(*password_form)) {
- password_forms_found = true;
- if (logger) {
- logger->LogPasswordForm(Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE,
- *password_form);
- }
- GetPasswordManagerDriver()->PasswordFormSubmitted(*password_form);
- break;
- }
- }
-
- if (!password_forms_found && logger)
- logger->LogMessage(Logger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE);
}
}
@@ -1754,18 +1701,29 @@ bool PasswordAutofillAgent::FillUserNameAndPassword(
// |current_username| is the username for credentials that are going to be
// autofilled. It is selected according to the algorithm:
- // 1. If the page already contain a non-empty value in |username_element|,
+ // 1. If the page already contains a non-empty value in |username_element|
+ // that is not found in the list of values known to be used as placeholders,
// this is adopted and not overridden.
// 2. Default username from |fill_data| if the username field is
// autocompletable.
// 3. Empty if username field doesn't exist or if username field is empty and
// not autocompletable (no username case).
base::string16 current_username;
+
+ // Whether the username element was prefilled with content that was not on a
+ // list of known placeholder texts (e.g. "username or email").
+ bool prefilled_not_placeholder_username = false;
+
if (!username_element->IsNull()) {
- if (!username_element->Value().IsEmpty())
+ if (!username_element->Value().IsEmpty() &&
+ !PossiblePrefilledUsernameValue(username_element->Value().Utf8())) {
+ // Username is filled with content that was not on a list of known
+ // placeholder texts (e.g. "username or email").
current_username = username_element->Value().Utf16();
- else if (IsElementAutocompletable(*username_element))
+ prefilled_not_placeholder_username = true;
+ } else if (IsElementAutocompletable(*username_element)) {
current_username = fill_data.username_field.value;
+ }
}
// username and password will contain the match found if any.
@@ -1775,8 +1733,13 @@ bool PasswordAutofillAgent::FillUserNameAndPassword(
FindMatchesByUsername(fill_data, current_username, exact_username_match,
logger, &username, &password);
- if (password.empty())
+ if (password.empty()) {
+ if (prefilled_not_placeholder_username) {
+ LogPrefilledUsernameFillOutcome(
+ PrefilledUsernameFillOutcome::kPrefilledUsernameNotOverridden);
+ }
return false;
+ }
// Call OnFieldAutofilled before WebInputElement::SetAutofilled which may
// cause frame closing.
@@ -1786,11 +1749,23 @@ bool PasswordAutofillAgent::FillUserNameAndPassword(
// Input matches the username, fill in required values.
if (!username_element->IsNull() &&
IsElementAutocompletable(*username_element)) {
- // Fill username only when it's not empty and not set by the page.
- if (!username.empty() && username_element->Value().IsEmpty()) {
- username_element->SetSuggestedValue(
- blink::WebString::FromUTF16(username));
- registration_callback.Run(username_element);
+ // Fill a non-empty username if it is safe to override the value of the
+ // username element. It is safe to override if the value is empty or a known
+ // placeholder value.
+ if (!username.empty()) {
+ if (username_element->Value().IsEmpty()) {
+ username_element->SetSuggestedValue(
+ blink::WebString::FromUTF16(username));
+ registration_callback.Run(username_element);
+ } else if (PossiblePrefilledUsernameValue(
+ username_element->Value().Utf8())) {
+ username_element->SetSuggestedValue(
+ blink::WebString::FromUTF16(username));
+ registration_callback.Run(username_element);
+ LogPrefilledUsernameFillOutcome(
+ PrefilledUsernameFillOutcome::
+ kPrefilledPlaceholderUsernameOverridden);
+ }
}
UpdateFieldValueAndPropertiesMaskMap(*username_element, &username,
FieldPropertiesFlags::AUTOFILLED,
@@ -1822,6 +1797,15 @@ bool PasswordAutofillAgent::FillUserNameAndPassword(
return true;
}
+void PasswordAutofillAgent::LogPrefilledUsernameFillOutcome(
+ PrefilledUsernameFillOutcome outcome) {
+ if (prefilled_username_metrics_logged_)
+ return;
+ prefilled_username_metrics_logged_ = true;
+ UMA_HISTOGRAM_ENUMERATION("PasswordManager.PrefilledUsernameFillOutcome",
+ outcome);
+}
+
bool PasswordAutofillAgent::FillFormOnPasswordReceived(
const PasswordFormFillData& fill_data,
blink::WebInputElement username_element,
diff --git a/chromium/components/autofill/content/renderer/password_autofill_agent.h b/chromium/components/autofill/content/renderer/password_autofill_agent.h
index c25839ad5e7..228907d12ce 100644
--- a/chromium/components/autofill/content/renderer/password_autofill_agent.h
+++ b/chromium/components/autofill/content/renderer/password_autofill_agent.h
@@ -38,6 +38,26 @@ class WebInputElement;
}
namespace autofill {
+// Used in UMA histograms, please do NOT reorder.
+// Metric: "PasswordManager.PrefilledUsernameFillOutcome".
+enum class PrefilledUsernameFillOutcome {
+ // This value is reported if all of the following three conditions are met:
+ // 1) the page has a username input element whose value was prefilled by the
+ // website itself.
+ // 2) the prefilled value was found in a list of known placeholder values
+ // (e.g. "username or email").
+ // 3) the user had a credential stored and the field content was overridden
+ // with the username of this credential due to 2).
+ kPrefilledPlaceholderUsernameOverridden = 0,
+ // This value is reported if all of the following conditions are met:
+ // 1) as above.
+ // 2) the prefilled value was NOT found in the list of known placeholder
+ // values.
+ // 3) the user had a credential stored for this site but the field content
+ // was NOT overridden due to 2).
+ kPrefilledUsernameNotOverridden = 1,
+ kMaxValue = kPrefilledUsernameNotOverridden,
+};
// Names of HTML attributes to show form and field signatures for debugging.
extern const char kDebugAttributeForFormSignature[];
@@ -110,11 +130,6 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
bool DidClearAutofillSelection(
const blink::WebFormControlElement& control_element);
- // Returns whether a "Login not secure" warning should be shown on the input
- // field. This is true if the feature is enabled and if the form is
- // non-secure.
- bool ShouldShowNotSecureWarning(const blink::WebInputElement& element);
-
// Returns whether the element is a username or password textfield.
bool IsUsernameOrPasswordField(const blink::WebInputElement& element);
@@ -299,6 +314,11 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
base::Callback<void(blink::WebInputElement*)> registration_callback,
RendererSavePasswordProgressLogger* logger);
+ // Logs whether a username value that was prefilled by the website was
+ // overridden when trying to fill with an existing credential. This logs
+ // only one value per |PasswordAutofillAgent| instance.
+ void LogPrefilledUsernameFillOutcome(PrefilledUsernameFillOutcome outcome);
+
// Attempts to fill |username_element| and |password_element| with the
// |fill_data|. Will use the data corresponding to the preferred username,
// unless the |username_element| already has a value set. In that case,
@@ -384,6 +404,8 @@ class PasswordAutofillAgent : public content::RenderFrameObserver,
bool blacklisted_form_found_ = false;
+ bool prefilled_username_metrics_logged_ = false;
+
DISALLOW_COPY_AND_ASSIGN(PasswordAutofillAgent);
};
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
index 7f034ac76b6..1cd2c4e812e 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -7,14 +7,18 @@
#include <stddef.h>
#include <algorithm>
+#include <set>
#include <string>
+#include "base/containers/flat_set.h"
#include "base/i18n/case_conversion.h"
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
+#include "base/no_destructor.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -35,8 +39,8 @@
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/re2/src/re2/re2.h"
+#include "url/gurl.h"
-using blink::WebDocument;
using blink::WebFormControlElement;
using blink::WebFormElement;
using blink::WebInputElement;
@@ -47,6 +51,82 @@ namespace autofill {
namespace {
+constexpr char kAutocompleteUsername[] = "username";
+constexpr char kAutocompleteCurrentPassword[] = "current-password";
+constexpr char kAutocompleteNewPassword[] = "new-password";
+constexpr char kAutocompleteCreditCardPrefix[] = "cc-";
+
+// Parses the string with the value of an autocomplete attribute. If any of the
+// tokens "username", "current-password" or "new-password" are present, returns
+// an appropriate enum value, picking an arbitrary one if more are applicable.
+// Otherwise, it returns CREDIT_CARD if a token with a "cc-" prefix is found.
+// Otherwise, returns NONE.
+AutocompleteFlag ExtractAutocompleteFlag(const std::string& attribute) {
+ std::vector<base::StringPiece> tokens =
+ base::SplitStringPiece(attribute, base::kWhitespaceASCII,
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ bool cc_seen = false;
+ for (base::StringPiece token : tokens) {
+ if (base::LowerCaseEqualsASCII(token, kAutocompleteUsername))
+ return AutocompleteFlag::USERNAME;
+ if (base::LowerCaseEqualsASCII(token, kAutocompleteCurrentPassword))
+ return AutocompleteFlag::CURRENT_PASSWORD;
+ if (base::LowerCaseEqualsASCII(token, kAutocompleteNewPassword))
+ return AutocompleteFlag::NEW_PASSWORD;
+
+ if (!cc_seen) {
+ cc_seen = base::StartsWith(token, kAutocompleteCreditCardPrefix,
+ base::CompareCase::SENSITIVE);
+ }
+ }
+ return cc_seen ? AutocompleteFlag::CREDIT_CARD : AutocompleteFlag::NONE;
+}
+
+// Helper to spare map::find boilerplate when caching element's autocomplete
+// attributes.
+class AutocompleteCache {
+ public:
+ AutocompleteCache();
+
+ ~AutocompleteCache();
+
+ // Computes and stores the AutocompleteFlag for |element| based on its
+ // autocomplete attribute. Note that this cannot be done on-demand during
+ // RetrieveFor, because the cache spares space and look-up time by not storing
+ // AutocompleteFlag::NONE values, hence for all elements without an
+ // autocomplete attribute, every retrieval would result in a new computation.
+ void Store(const WebInputElement& element);
+
+ // Retrieves the value previously stored for |element|.
+ AutocompleteFlag RetrieveFor(const WebInputElement& element) const;
+
+ private:
+ std::map<WebInputElement, AutocompleteFlag> cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutocompleteCache);
+};
+
+AutocompleteCache::AutocompleteCache() = default;
+
+AutocompleteCache::~AutocompleteCache() = default;
+
+void AutocompleteCache::Store(const WebInputElement& element) {
+ const AutocompleteFlag flag = AutocompleteFlagForElement(element);
+ // Only store non-trivial flags. Most of the elements will have the NONE
+ // value, so spare storage and lookup time by assuming anything not stored in
+ // |cache_| has the NONE flag.
+ if (flag != AutocompleteFlag::NONE)
+ cache_[element] = flag;
+}
+
+AutocompleteFlag AutocompleteCache::RetrieveFor(
+ const WebInputElement& element) const {
+ auto it = cache_.find(element);
+ if (it == cache_.end())
+ return AutocompleteFlag::NONE;
+ return it->second;
+}
+
// Describes fields filtering criteria. More priority criteria has higher value
// in the enum. The fields with the maximal criteria are considered in a form,
// others are ignored. Criteria for password and username fields are calculated
@@ -65,21 +145,22 @@ enum class FieldFilteringLevel {
// view of the underlying data, regardless of its origin.
struct SyntheticForm {
SyntheticForm();
+ SyntheticForm(SyntheticForm&& other);
~SyntheticForm();
- std::vector<blink::WebElement> fieldsets;
// Contains control elements of the represented form, including not fillable
// ones.
std::vector<blink::WebFormControlElement> control_elements;
- blink::WebDocument document;
- blink::WebString action;
+ // The origin of the containing document.
+ GURL origin;
private:
DISALLOW_COPY_AND_ASSIGN(SyntheticForm);
};
-SyntheticForm::SyntheticForm() {}
-SyntheticForm::~SyntheticForm() {}
+SyntheticForm::SyntheticForm() = default;
+SyntheticForm::SyntheticForm(SyntheticForm&& other) = default;
+SyntheticForm::~SyntheticForm() = default;
// Layout classification of password forms
// A layout sequence of a form is the sequence of it's non-password and password
@@ -109,11 +190,6 @@ const char kLoginAndSignupRegex[] =
"N+P" // Sign-up section.
".*"; // Anything beyond that.
-const char kAutocompleteUsername[] = "username";
-const char kAutocompleteCurrentPassword[] = "current-password";
-const char kAutocompleteNewPassword[] = "new-password";
-const char kAutocompleteCreditCardPrefix[] = "cc-";
-
struct LoginAndSignupLazyInstanceTraits
: public base::internal::DestructorAtExitLazyInstanceTraits<re2::RE2> {
static re2::RE2* New(void* instance) {
@@ -126,9 +202,9 @@ base::LazyInstance<re2::RE2, LoginAndSignupLazyInstanceTraits>
// Return a pointer to WebInputElement iff |control_element| is an enabled text
// input element. Otherwise, returns nullptr.
-WebInputElement* GetEnabledTextInputFieldOrNull(
- WebFormControlElement* control_element) {
- WebInputElement* input_element = ToWebInputElement(control_element);
+const WebInputElement* GetEnabledTextInputFieldOrNull(
+ const WebFormControlElement& control_element) {
+ const WebInputElement* input_element = ToWebInputElement(&control_element);
if (input_element && input_element->IsEnabled() &&
input_element->IsTextField()) {
return input_element;
@@ -160,8 +236,8 @@ void PopulateSyntheticFormFromWebForm(const WebFormElement& web_form,
web_form.GetFormControlElements(web_control_elements);
synthetic_form->control_elements.assign(web_control_elements.begin(),
web_control_elements.end());
- synthetic_form->action = web_form.Action();
- synthetic_form->document = web_form.GetDocument();
+ synthetic_form->origin =
+ form_util::GetCanonicalOriginForDocument(web_form.GetDocument());
}
// Helper to determine which password is the main (current) one, and which is
@@ -171,7 +247,8 @@ void PopulateSyntheticFormFromWebForm(const WebFormElement& web_form,
void LocateSpecificPasswords(std::vector<WebInputElement> passwords,
WebInputElement* current_password,
WebInputElement* new_password,
- WebInputElement* confirmation_password) {
+ WebInputElement* confirmation_password,
+ const AutocompleteCache& autocomplete_cache) {
DCHECK(!passwords.empty());
DCHECK(current_password && current_password->IsNull());
DCHECK(new_password && new_password->IsNull());
@@ -180,16 +257,17 @@ void LocateSpecificPasswords(std::vector<WebInputElement> passwords,
// First, look for elements marked with either autocomplete='current-password'
// or 'new-password' -- if we find any, take the hint, and treat the first of
// each kind as the element we are looking for.
- for (const WebInputElement& it : passwords) {
- if (HasAutocompleteAttributeValue(it, kAutocompleteCurrentPassword) &&
+ for (const WebInputElement& password : passwords) {
+ const AutocompleteFlag flag = autocomplete_cache.RetrieveFor(password);
+ if (flag == AutocompleteFlag::CURRENT_PASSWORD &&
current_password->IsNull()) {
- *current_password = it;
- } else if (HasAutocompleteAttributeValue(it, kAutocompleteNewPassword) &&
+ *current_password = password;
+ } else if (flag == AutocompleteFlag::NEW_PASSWORD &&
new_password->IsNull()) {
- *new_password = it;
+ *new_password = password;
} else if (!new_password->IsNull() &&
- (new_password->Value() == it.Value())) {
- *confirmation_password = it;
+ (new_password->Value() == password.Value())) {
+ *confirmation_password = password;
}
}
@@ -253,25 +331,8 @@ void LocateSpecificPasswords(std::vector<WebInputElement> passwords,
}
}
-// Checks the |form_predictions| map to see if there is a key associated with
-// the |prediction_type| value. Assigns the key to |prediction_field| and
-// returns true if it is found.
-bool MapContainsPrediction(
- const std::map<WebInputElement, PasswordFormFieldPredictionType>&
- form_predictions,
- PasswordFormFieldPredictionType prediction_type,
- WebInputElement* prediction_field) {
- for (auto it = form_predictions.begin(); it != form_predictions.end(); ++it) {
- if (it->second == prediction_type) {
- (*prediction_field) = it->first;
- return true;
- }
- }
- return false;
-}
-
void FindPredictedElements(
- const SyntheticForm& form,
+ const std::vector<blink::WebFormControlElement>& control_elements,
const FormData& form_data,
const FormsPredictionsMap& form_predictions,
std::map<WebInputElement, PasswordFormFieldPredictionType>*
@@ -279,22 +340,21 @@ void FindPredictedElements(
// Matching only requires that action and name of the form match to allow
// the username to be updated even if the form is changed after page load.
// See https://crbug.com/476092 for more details.
- auto predictions_it = form_predictions.begin();
- for (; predictions_it != form_predictions.end(); ++predictions_it) {
- if (predictions_it->first.action == form_data.action &&
- predictions_it->first.name == form_data.name) {
+ const PasswordFormFieldPredictionMap* field_predictions = nullptr;
+ for (const auto& form_predictions_pair : form_predictions) {
+ if (form_predictions_pair.first.action == form_data.action &&
+ form_predictions_pair.first.name == form_data.name) {
+ field_predictions = &form_predictions_pair.second;
break;
}
}
- if (predictions_it == form_predictions.end())
+ if (!field_predictions)
return;
std::vector<blink::WebFormControlElement> autofillable_elements =
- form_util::ExtractAutofillableElementsFromSet(form.control_elements);
- const PasswordFormFieldPredictionMap& field_predictions =
- predictions_it->second;
- for (const auto& prediction : field_predictions) {
+ form_util::ExtractAutofillableElementsFromSet(control_elements);
+ for (const auto& prediction : *field_predictions) {
const FormFieldData& target_field = prediction.first;
const PasswordFormFieldPredictionType& type = prediction.second;
for (const auto& control_element : autofillable_elements) {
@@ -407,8 +467,7 @@ void GetFieldFilteringLevels(
}
}
-autofill::ValueElementPair MakePossibleUsernamePair(
- const blink::WebInputElement& input) {
+ValueElementPair MakePossibleUsernamePair(const blink::WebInputElement& input) {
base::string16 trimmed_input_value, trimmed_input_autofill;
base::TrimString(input.Value().Utf16(), base::ASCIIToUTF16(" "),
&trimmed_input_value);
@@ -455,247 +514,290 @@ bool ScriptModifiedUsernameAcceptable(
return false;
}
+bool StringMatchesCVC(const base::string16& str) {
+ static const base::NoDestructor<base::string16> kCardCvcReCached(
+ base::UTF8ToUTF16(kCardCvcRe));
+
+ return MatchesPattern(str, *kCardCvcReCached);
+}
+
+bool IsEnabledPasswordFieldPresent(const std::vector<FormFieldData>& fields) {
+ return std::find_if(
+ fields.begin(), fields.end(), [](const FormFieldData& field) {
+ return field.is_enabled && field.form_control_type == "password";
+ }) != fields.end();
+}
+
+// Find the first element in |username_predictions| (i.e. the most reliable
+// prediction) that occurs in |possible_usernames|. If the element is found, the
+// method saves it to |username_element| and returns true.
+bool FindUsernameInPredictions(
+ const std::vector<blink::WebInputElement>& username_predictions,
+ const std::vector<blink::WebInputElement>& possible_usernames,
+ WebInputElement* username_element) {
+ // To speed-up the matching for-loop below, convert |possible_usernames| to a
+ // set. Creating is O(N log N) for N=possible_usernames.size(). Retrieval is
+ // O(log N), so the whole for-loop is O(M log N) for
+ // M=username_predictions.size(). Use flat_set, because of cache locality (the
+ // M and N are likely small, so this can make a difference) and less heap
+ // allocations.
+ const base::flat_set<blink::WebInputElement> usernames(
+ possible_usernames.begin(), possible_usernames.end());
+
+ for (const blink::WebInputElement& prediction : username_predictions) {
+ auto iter = usernames.find(prediction);
+ if (iter != usernames.end()) {
+ *username_element = *iter;
+ return true;
+ }
+ }
+ return false;
+}
+
// Get information about a login form encapsulated in a PasswordForm struct.
// If an element of |form| has an entry in |nonscript_modified_values|, the
// associated string is used instead of the element's value to create
// the PasswordForm.
bool GetPasswordForm(
- const SyntheticForm& form,
+ SyntheticForm form,
PasswordForm* password_form,
const FieldValueAndPropertiesMaskMap* field_value_and_properties_map,
const FormsPredictionsMap* form_predictions,
UsernameDetectorCache* username_detector_cache) {
- bool form_has_password_field =
- std::find_if(form.control_elements.begin(), form.control_elements.end(),
- [](WebFormControlElement e) {
- WebInputElement* input_element =
- GetEnabledTextInputFieldOrNull(&e);
- return input_element &&
- input_element->IsPasswordFieldForAutofill();
- }) != form.control_elements.end();
- if (!form_has_password_field)
- return false;
+ DCHECK(!form.control_elements.empty());
- WebInputElement username_element;
- UsernameDetectionMethod username_detection_method =
- UsernameDetectionMethod::NO_USERNAME_DETECTED;
- password_form->username_marked_by_site = false;
+ // Early exit if no passwords to be typed into.
+ if (!IsEnabledPasswordFieldPresent(password_form->form_data.fields))
+ return false;
- std::vector<WebInputElement> passwords;
- WebInputElement latest_input_element;
- std::map<blink::WebInputElement, blink::WebInputElement>
- last_text_input_before_password;
+ // Narrow the scope to enabled inputs.
+ std::vector<WebInputElement> enabled_inputs;
+ enabled_inputs.reserve(form.control_elements.size());
+ for (const WebFormControlElement& control_element : form.control_elements) {
+ const WebInputElement* input_element =
+ GetEnabledTextInputFieldOrNull(control_element);
+ if (input_element)
+ enabled_inputs.push_back(*input_element);
+ }
+ // Remember the list of password fields without any heuristics applied in case
+ // the heuristics fail and a fall-back is needed:
+ // All password fields.
std::vector<WebInputElement> passwords_without_heuristics;
- WebInputElement latest_input_element_without_heuristics;
- std::map<blink::WebInputElement, blink::WebInputElement>
- last_text_input_without_heuristics;
+ // Map from all password fields to the most recent non-password text input.
+ std::map<WebInputElement, WebInputElement>
+ preceding_text_input_for_password_without_heuristics;
+ WebInputElement most_recent_text_input; // Just a temporary.
+ for (const WebInputElement& input : enabled_inputs) {
+ if (input.IsPasswordFieldForAutofill()) {
+ passwords_without_heuristics.push_back(input);
+ preceding_text_input_for_password_without_heuristics[input] =
+ most_recent_text_input;
+ } else {
+ most_recent_text_input = input;
+ }
+ }
- std::vector<WebInputElement> possible_usernames;
+ // Fill the cache with autocomplete flags.
+ AutocompleteCache autocomplete_cache;
+ for (const WebInputElement& input : enabled_inputs) {
+ autocomplete_cache.Store(input);
+ }
- // Calculate filtering levels for password and username fields. For details
- // see to the comment to |FieldFilteringLevel|.
+ // Narrow the scope further: drop credit-card fields.
+ std::vector<WebInputElement> plausible_inputs;
+ plausible_inputs.reserve(enabled_inputs.size());
+ for (const WebInputElement& input : enabled_inputs) {
+ const AutocompleteFlag flag = autocomplete_cache.RetrieveFor(input);
+ if (flag == AutocompleteFlag::CURRENT_PASSWORD ||
+ flag == AutocompleteFlag::NEW_PASSWORD) {
+ // A field marked as a password is considered not a credit-card field, no
+ // matter what.
+ plausible_inputs.push_back(input);
+ } else if (flag != AutocompleteFlag::CREDIT_CARD &&
+ !IsCreditCardVerificationPasswordField(input)) {
+ // Otherwise ensure that nothing hints that |input| is a credit-card
+ // field.
+ plausible_inputs.push_back(input);
+ }
+ }
+
+ // Further narrow to interesting fields (e.g., with user input, visible), if
+ // present.
+ // Compute the best filtering levels for usernames and for passwords.
FieldFilteringLevel username_fields_level = FieldFilteringLevel::NO_FILTER;
FieldFilteringLevel password_fields_level = FieldFilteringLevel::NO_FILTER;
GetFieldFilteringLevels(form.control_elements, field_value_and_properties_map,
&username_fields_level, &password_fields_level);
+ // Remove all fields with filtering level below the best.
+ base::EraseIf(
+ plausible_inputs, [&field_value_and_properties_map, password_fields_level,
+ username_fields_level](const WebInputElement& input) {
+ FieldFilteringLevel current_field_level =
+ GetFiltertingLevelForField(input, field_value_and_properties_map,
+ false /* ignore_autofilled_values */);
+ if (input.IsPasswordFieldForAutofill())
+ return (current_field_level < password_fields_level);
+ else
+ return (current_field_level < username_fields_level);
+ });
+
+ // Further, remove all readonly passwords. If the password field is readonly,
+ // the page is likely using a virtual keyboard and bypassing the password
+ // field value (see http://crbug.com/475488). There is nothing Chrome can do
+ // to fill passwords for now. Notable exceptions: if the password field was
+ // made readonly by JavaScript before submission, it remains interesting. If
+ // the password was marked via the autocomplete attribute, it also remains
+ // interesting.
+ base::EraseIf(plausible_inputs, [&field_value_and_properties_map,
+ &autocomplete_cache](
+ const WebInputElement& input) {
+ if (!input.IsPasswordFieldForAutofill())
+ return false;
+ if (!input.IsReadOnly())
+ return false;
+ // Check if the field was only made readonly before submission.
+ if (FieldHasPropertiesMask(field_value_and_properties_map, input,
+ FieldPropertiesFlags::USER_TYPED |
+ FieldPropertiesFlags::AUTOFILLED)) {
+ return false;
+ }
+ // Check whether the field was explicitly marked as password.
+ const AutocompleteFlag flag = autocomplete_cache.RetrieveFor(input);
+ if (flag == AutocompleteFlag::CURRENT_PASSWORD ||
+ flag == AutocompleteFlag::NEW_PASSWORD) {
+ return false;
+ }
+ return true;
+ });
+ // Evaluate available server-side predictions.
std::map<WebInputElement, PasswordFormFieldPredictionType> predicted_elements;
+ WebInputElement predicted_username_element;
if (form_predictions) {
- FindPredictedElements(form, password_form->form_data, *form_predictions,
- &predicted_elements);
- WebInputElement predicted_username_element;
- bool map_has_username_prediction = MapContainsPrediction(
- predicted_elements, PREDICTION_USERNAME, &predicted_username_element);
-
- // Let server predictions override the selection of the username field. This
- // allows instant adjusting without changing Chromium code.
- // If a form already has user input, but the predicted username field has
- // empty value, then don't trust the prediction (e.g. a <form> actually
- // contains several forms).
- if (map_has_username_prediction &&
- (password_fields_level < FieldFilteringLevel::USER_INPUT ||
- !predicted_username_element.Value().IsEmpty())) {
- username_element = predicted_username_element;
- password_form->was_parsed_using_autofill_predictions = true;
- username_detection_method =
- UsernameDetectionMethod::SERVER_SIDE_PREDICTION;
+ FindPredictedElements(form.control_elements, password_form->form_data,
+ *form_predictions, &predicted_elements);
+
+ for (const auto& predicted_pair : predicted_elements) {
+ if (predicted_pair.second == PREDICTION_USERNAME) {
+ predicted_username_element = predicted_pair.first;
+ break;
+ }
}
}
- std::string layout_sequence;
- layout_sequence.reserve(form.control_elements.size());
- size_t number_of_non_empty_text_non_password_fields = 0;
- for (size_t i = 0; i < form.control_elements.size(); ++i) {
- WebFormControlElement control_element = form.control_elements[i];
-
- WebInputElement* input_element =
- GetEnabledTextInputFieldOrNull(&control_element);
- if (!input_element)
- continue;
-
- // Fill |...without_heuristics| variables before heuristics are applied.
- if (input_element->IsPasswordFieldForAutofill()) {
- passwords_without_heuristics.push_back(*input_element);
- last_text_input_without_heuristics[*input_element] =
- latest_input_element_without_heuristics;
- } else {
- latest_input_element_without_heuristics = *input_element;
+ // Finally, remove all password fields for which we have a negative
+ // prediction, unless they are explicitly marked by the autocomplete attribute
+ // as a password.
+ base::EraseIf(plausible_inputs, [&predicted_elements, &autocomplete_cache](
+ const WebInputElement& input) {
+ if (!input.IsPasswordFieldForAutofill())
+ return false;
+ const AutocompleteFlag flag = autocomplete_cache.RetrieveFor(input);
+ if (flag == AutocompleteFlag::CURRENT_PASSWORD ||
+ flag == AutocompleteFlag::NEW_PASSWORD) {
+ return false;
}
-
- bool password_marked_by_autocomplete_attribute =
- HasAutocompleteAttributeValue(*input_element,
- kAutocompleteCurrentPassword) ||
- HasAutocompleteAttributeValue(*input_element, kAutocompleteNewPassword);
- if (!password_marked_by_autocomplete_attribute &&
- (HasCreditCardAutocompleteAttributes(*input_element) ||
- IsCreditCardVerificationPasswordField(*input_element)))
- continue;
-
- FieldFilteringLevel current_field_level = GetFiltertingLevelForField(
- control_element, field_value_and_properties_map,
- false /* ignore_autofilled_values */);
-
- if (input_element->IsPasswordFieldForAutofill()) {
- if (current_field_level < password_fields_level)
- continue;
- layout_sequence.push_back('P');
+ auto possible_password_element_iterator = predicted_elements.find(input);
+ return possible_password_element_iterator != predicted_elements.end() &&
+ possible_password_element_iterator->second ==
+ PREDICTION_NOT_PASSWORD;
+ });
+
+ // Derive the list of all plausible passwords, usernames and the non-password
+ // inputs preceding the plausible passwords.
+ std::vector<WebInputElement> plausible_passwords;
+ std::vector<WebInputElement> plausible_usernames;
+ std::map<WebInputElement, WebInputElement>
+ preceding_text_input_for_plausible_password;
+ most_recent_text_input.Reset();
+ plausible_usernames.reserve(plausible_inputs.size());
+ for (const WebInputElement& input : plausible_inputs) {
+ if (input.IsPasswordFieldForAutofill()) {
+ plausible_passwords.push_back(input);
+ preceding_text_input_for_plausible_password[input] =
+ most_recent_text_input;
} else {
- if (current_field_level == FieldFilteringLevel::USER_INPUT)
- ++number_of_non_empty_text_non_password_fields;
- if (current_field_level < username_fields_level)
- continue;
- layout_sequence.push_back('N');
- }
-
- // If the password field is readonly, the page is likely using a virtual
- // keyboard and bypassing the password field value (see
- // http://crbug.com/475488). There is nothing Chrome can do to fill
- // passwords for now. Continue processing in case when the password field
- // was made readonly by JavaScript before submission. We can do this by
- // checking whether password element was updated not from JavaScript.
- if (input_element->IsPasswordFieldForAutofill() &&
- (!input_element->IsReadOnly() ||
- FieldHasPropertiesMask(field_value_and_properties_map, *input_element,
- FieldPropertiesFlags::USER_TYPED |
- FieldPropertiesFlags::AUTOFILLED) ||
- password_marked_by_autocomplete_attribute)) {
- // We add the field to the list of password fields if it was not flagged
- // as a special NOT_PASSWORD prediction by Autofill. The NOT_PASSWORD
- // mechanism exists because some webpages use the type "password" for
- // fields which Autofill knows shouldn't be treated as passwords by the
- // Password Manager. This is ultimately bypassed if the field has
- // autocomplete attributes.
- auto possible_password_element_iterator =
- predicted_elements.find(*input_element);
- if (password_marked_by_autocomplete_attribute ||
- possible_password_element_iterator == predicted_elements.end() ||
- possible_password_element_iterator->second !=
- PREDICTION_NOT_PASSWORD) {
- passwords.push_back(*input_element);
- last_text_input_before_password[*input_element] = latest_input_element;
- }
+ plausible_usernames.push_back(input);
+ most_recent_text_input = input;
}
+ }
- // Various input types such as text, url, email can be a username field.
- if (!input_element->IsPasswordFieldForAutofill()) {
- possible_usernames.push_back(*input_element);
- if (HasAutocompleteAttributeValue(*input_element,
- kAutocompleteUsername)) {
- if (password_form->username_marked_by_site) {
- // A second or subsequent element marked with autocomplete='username'.
- // This makes us less confident that we have understood the form. We
- // will stick to our choice that the first such element was the real
- // username.
- } else {
- // The first element marked with autocomplete='username'. Take the
- // hint and treat it as the username (overruling the tentative choice
- // we might have made before). Furthermore, drop all other possible
- // usernames we have accrued so far: they come from fields not marked
- // with the autocomplete attribute, making them unlikely alternatives.
-
- // Don't override the server-side prediction if any.
- if (username_element.IsNull()) {
- username_element = *input_element;
- password_form->username_marked_by_site = true;
- username_detection_method =
- UsernameDetectionMethod::AUTOCOMPLETE_ATTRIBUTE;
- }
- }
- } else {
- if (password_form->username_marked_by_site) {
- // Having seen elements with autocomplete='username', elements without
- // this attribute are no longer interesting. No-op.
- } else {
- // No elements marked with autocomplete='username' so far whatsoever.
- // If we have not yet selected a username element even provisionally,
- // then remember this element for the case when the next field turns
- // out to be a password. Save a non-empty username as a possible
- // alternative, at least for now.
- if (username_element.IsNull())
- latest_input_element = *input_element;
+ // Evaluate autocomplete attributes for username.
+ WebInputElement username_by_attribute;
+ for (const WebInputElement& input : plausible_inputs) {
+ if (!input.IsPasswordFieldForAutofill()) {
+ if (autocomplete_cache.RetrieveFor(input) == AutocompleteFlag::USERNAME) {
+ // Only consider the first occurrence of autocomplete='username'.
+ // Multiple occurences hint at the attribute being used incorrectly, in
+ // which case sticking to the first one is just a bet.
+ if (username_by_attribute.IsNull()) {
+ username_by_attribute = input;
}
}
}
}
- // If for some reason (e.g. only credit card fields, confusing autocomplete
- // attributes) the passwords list is empty, build list based on user input (if
- // there is any non-empty password field) and the type of a field. Also mark
- // that the form should be available only for fallback saving (automatic
- // bubble will not pop up).
- password_form->only_for_fallback_saving = passwords.empty();
- if (passwords.empty()) {
- passwords = passwords_without_heuristics;
- last_text_input_before_password = last_text_input_without_heuristics;
- }
- DCHECK_EQ(passwords.size(), last_text_input_before_password.size());
-
- // |passwords| must be non-empty. Just in case the heuristics above have a
- // bug, return now.
- if (passwords.empty()) {
- NOTREACHED();
- return false;
- }
-
- // Call HTML based username detector, only if corresponding flag is enabled.
+ // Evaluate the context of the fields.
+ WebInputElement username_element_by_context;
if (base::FeatureList::IsEnabled(
password_manager::features::kHtmlBasedUsernameDetector)) {
- if (username_element.IsNull()) {
- GetUsernameFieldBasedOnHtmlAttributes(
- form.control_elements, possible_usernames, password_form->form_data,
- &username_element, username_detector_cache);
- if (!username_element.IsNull()) {
- username_detection_method =
- UsernameDetectionMethod::HTML_BASED_CLASSIFIER;
+ // Call HTML based username detector only if neither server predictions nor
+ // autocomplete attributes were useful to detect the username.
+ if (predicted_username_element.IsNull() && username_by_attribute.IsNull()) {
+ // Dummy cache stores the predictions in case no real cache was passed to
+ // here.
+ UsernameDetectorCache dummy_cache;
+ if (!username_detector_cache)
+ username_detector_cache = &dummy_cache;
+
+ const std::vector<blink::WebInputElement>& username_predictions =
+ GetPredictionsFieldBasedOnHtmlAttributes(form.control_elements,
+ password_form->form_data,
+ username_detector_cache);
+
+ if (!FindUsernameInPredictions(username_predictions, plausible_usernames,
+ &username_element_by_context)) {
+ username_element_by_context.Reset();
}
}
}
- WebInputElement password;
- WebInputElement new_password;
- WebInputElement confirmation_password;
- LocateSpecificPasswords(passwords, &password, &new_password,
- &confirmation_password);
+ // Evaluate the structure of the form for determining the form type (e.g.,
+ // sign-up, sign-in, etc.).
+ std::string layout_sequence;
+ layout_sequence.reserve(plausible_inputs.size());
+ for (const WebInputElement& input : plausible_inputs) {
+ layout_sequence.push_back((input.IsPasswordFieldForAutofill()) ? 'P' : 'N');
+ }
- bool form_has_autofilled_value = false;
- // Add non-empty unique possible passwords to the vector.
- std::vector<autofill::ValueElementPair> all_possible_passwords;
+ // Populate all_possible_passwords and form_has_autofilled_value in
+ // |password_form|.
+ // Contains the first password element for each non-empty password value.
+ std::vector<ValueElementPair> all_possible_passwords;
+ // Reserve enough space to prevent re-allocation. A re-allocation would
+ // invalidate the contents of |seen_values|.
+ all_possible_passwords.reserve(passwords_without_heuristics.size());
+ std::set<base::StringPiece16> seen_values;
+ // Pretend that an empty value has been already seen, so that empty-valued
+ // password elements won't get added to |all_possible_passwords|.
+ seen_values.insert(base::StringPiece16());
for (const WebInputElement& password_element : passwords_without_heuristics) {
const base::string16 value = password_element.Value().Utf16();
- if (value.empty())
+ if (seen_values.count(value) > 0)
continue;
+ all_possible_passwords.push_back(
+ {std::move(value), password_element.NameForAutofill().Utf16()});
+ seen_values.insert(
+ base::StringPiece16(all_possible_passwords.back().first));
+ }
+
+ bool form_has_autofilled_value = false;
+ for (const WebInputElement& password_element : passwords_without_heuristics) {
bool element_has_autofilled_value =
FieldHasPropertiesMask(field_value_and_properties_map, password_element,
FieldPropertiesFlags::AUTOFILLED);
form_has_autofilled_value |= element_has_autofilled_value;
- if (find_if(all_possible_passwords.begin(), all_possible_passwords.end(),
- [&value](const auto& pair) -> bool {
- return pair.first == value;
- }) == all_possible_passwords.end()) {
- all_possible_passwords.push_back(
- {std::move(value), password_element.NameForAutofill().Utf16()});
- }
}
if (!all_possible_passwords.empty()) {
@@ -703,22 +805,79 @@ bool GetPasswordForm(
password_form->form_has_autofilled_value = form_has_autofilled_value;
}
- // Base heuristic for username detection.
- WebInputElement base_heuristic_prediction;
- if (!password.IsNull())
- base_heuristic_prediction = last_text_input_before_password[password];
- if (base_heuristic_prediction.IsNull() && !new_password.IsNull())
- base_heuristic_prediction = last_text_input_before_password[new_password];
+ // If for some reason (e.g. only credit card fields, confusing autocomplete
+ // attributes) the passwords list is empty, build list based on user input (if
+ // there is any non-empty password field) and the type of a field. Also mark
+ // that the form should be available only for fallback saving (automatic
+ // bubble will not pop up).
+ password_form->only_for_fallback_saving = plausible_passwords.empty();
+ if (plausible_passwords.empty()) {
+ plausible_passwords = std::move(passwords_without_heuristics);
+ preceding_text_input_for_plausible_password =
+ std::move(preceding_text_input_for_password_without_heuristics);
+ }
+
+ // Find the password fields.
+ WebInputElement password;
+ WebInputElement new_password;
+ WebInputElement confirmation_password;
+ LocateSpecificPasswords(std::move(plausible_passwords), &password,
+ &new_password, &confirmation_password,
+ autocomplete_cache);
+
+ // Choose the username element.
+ WebInputElement username_element;
+ UsernameDetectionMethod username_detection_method =
+ UsernameDetectionMethod::NO_USERNAME_DETECTED;
+ password_form->username_marked_by_site = false;
+
+ if (!predicted_username_element.IsNull()) {
+ // Server predictions are most trusted, so try them first. Only if the form
+ // already has user input and the predicted username field has an empty
+ // value, then don't trust the prediction (can be caused by, e.g., a <form>
+ // actually contains several forms).
+ if ((password_fields_level < FieldFilteringLevel::USER_INPUT ||
+ !predicted_username_element.Value().IsEmpty())) {
+ username_element = predicted_username_element;
+ password_form->was_parsed_using_autofill_predictions = true;
+ username_detection_method =
+ UsernameDetectionMethod::SERVER_SIDE_PREDICTION;
+ }
+ }
+ if (username_element.IsNull() && !username_by_attribute.IsNull()) {
+ // Next in the trusted queue: autocomplete attributes.
+ username_element = username_by_attribute;
+ username_detection_method = UsernameDetectionMethod::AUTOCOMPLETE_ATTRIBUTE;
+ }
+
+ if (username_element.IsNull() && !username_element_by_context.IsNull()) {
+ // Last step before base heuristics: HTML-based classifier.
+ username_element = username_element_by_context;
+ username_detection_method = UsernameDetectionMethod::HTML_BASED_CLASSIFIER;
+ }
+
+ // Compute base heuristic for username detection.
+ WebInputElement base_heuristic_username;
+ if (!password.IsNull()) {
+ base_heuristic_username =
+ preceding_text_input_for_plausible_password[password];
+ }
+ if (base_heuristic_username.IsNull() && !new_password.IsNull()) {
+ base_heuristic_username =
+ preceding_text_input_for_plausible_password[new_password];
+ }
+
+ // Apply base heuristic for username detection.
if (username_element.IsNull()) {
- username_element = base_heuristic_prediction;
- if (!base_heuristic_prediction.IsNull())
+ username_element = base_heuristic_username;
+ if (!username_element.IsNull())
username_detection_method = UsernameDetectionMethod::BASE_HEURISTIC;
- } else if (base_heuristic_prediction == username_element &&
+ } else if (base_heuristic_username == username_element &&
username_detection_method !=
UsernameDetectionMethod::AUTOCOMPLETE_ATTRIBUTE) {
// TODO(crbug.com/786404): when the bug is fixed, remove this block and
- // calculate |base_heuristic_prediction| only if |username_element.IsNull()|
+ // calculate |base_heuristic_username| only if |username_element.IsNull()|
// This block was added to measure the impact of server-side predictions and
// HTML based classifier compared to "old classifiers" (the based heuristic
// and 'autocomplete' attribute).
@@ -728,8 +887,7 @@ bool GetPasswordForm(
"PasswordManager.UsernameDetectionMethod", username_detection_method,
UsernameDetectionMethod::USERNAME_DETECTION_METHOD_COUNT);
- password_form->layout = SequenceToLayout(layout_sequence);
-
+ // Populate the username fields in |password_form|.
if (!username_element.IsNull()) {
password_form->username_element =
FieldName(username_element, "anonymous_username");
@@ -743,30 +901,16 @@ bool GetPasswordForm(
if (!ScriptModifiedUsernameAcceptable(username_value,
typed_username_value, password_form,
field_value_and_properties_map)) {
- // We check that |username_value| was not obtained by autofilling
- // |typed_username_value|. In case when it was, |typed_username_value|
- // is incomplete, so we should leave autofilled value.
+ // If |username_value| was obtained by autofilling
+ // |typed_username_value|, |typed_username_value| might be incomplete,
+ // so we should leave autofilled value.
username_value = typed_username_value;
}
}
password_form->username_value = username_value;
}
- password_form->origin =
- form_util::GetCanonicalOriginForDocument(form.document);
- password_form->signon_realm = GetSignOnRealm(password_form->origin);
-
- // Convert |possible_usernames| to ValueElementVector.
- autofill::ValueElementVector other_possible_usernames;
- for (const WebInputElement& possible_username : possible_usernames) {
- if (possible_username == username_element)
- continue;
- auto pair = MakePossibleUsernamePair(possible_username);
- if (!pair.first.empty())
- other_possible_usernames.push_back(std::move(pair));
- }
- password_form->other_possible_usernames.swap(other_possible_usernames);
-
+ // Populate the password fields in |password_form|.
if (!password.IsNull()) {
password_form->password_element = FieldName(password, "anonymous_password");
blink::WebString password_value = password.Value();
@@ -784,14 +928,28 @@ bool GetPasswordForm(
password_form->new_password_value = new_password.Value().Utf16();
password_form->new_password_value_is_default =
new_password.GetAttribute("value") == new_password.Value();
- if (HasAutocompleteAttributeValue(new_password, kAutocompleteNewPassword))
+ if (autocomplete_cache.RetrieveFor(new_password) ==
+ AutocompleteFlag::NEW_PASSWORD) {
password_form->new_password_marked_by_site = true;
+ }
if (!confirmation_password.IsNull()) {
password_form->confirmation_password_element =
FieldName(confirmation_password, "anonymous_confirmation_password");
}
}
+ // Populate |other_possible_usernames| in |password_form|.
+ ValueElementVector other_possible_usernames;
+ for (const WebInputElement& plausible_username : plausible_usernames) {
+ if (plausible_username == username_element)
+ continue;
+ auto pair = MakePossibleUsernamePair(plausible_username);
+ if (!pair.first.empty())
+ other_possible_usernames.push_back(std::move(pair));
+ }
+ password_form->other_possible_usernames = std::move(other_possible_usernames);
+
+ // Report metrics.
if (username_element.IsNull()) {
// To get a better idea on how password forms without a username field
// look like, report the total number of text and password fields.
@@ -804,24 +962,26 @@ bool GetPasswordForm(
std::count(layout_sequence.begin(), layout_sequence.end(), 'P'));
}
+ password_form->origin = std::move(form.origin);
+ password_form->signon_realm = GetSignOnRealm(password_form->origin);
password_form->scheme = PasswordForm::SCHEME_HTML;
password_form->preferred = false;
password_form->blacklisted_by_user = false;
password_form->type = PasswordForm::TYPE_MANUAL;
+ password_form->layout = SequenceToLayout(layout_sequence);
- // The password form is considered that it looks like SignUp form if it has
- // more than 1 text field with user input or it has a new password field and
- // no current password field.
- password_form->does_look_like_signup_form =
- number_of_non_empty_text_non_password_fields > 1 ||
- (number_of_non_empty_text_non_password_fields == 1 &&
- password_form->password_element.empty() &&
- !password_form->new_password_element.empty());
return true;
}
} // namespace
+AutocompleteFlag AutocompleteFlagForElement(const WebInputElement& element) {
+ static const base::NoDestructor<WebString> kAutocomplete(("autocomplete"));
+ return ExtractAutocompleteFlag(
+ element.GetAttribute(*kAutocomplete)
+ .Utf8(WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD));
+}
+
re2::RE2* CreateMatcher(void* instance, const char* pattern) {
re2::RE2::Options options;
options.set_case_sensitive(false);
@@ -886,27 +1046,30 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromWebForm(
const FormsPredictionsMap* form_predictions,
UsernameDetectorCache* username_detector_cache) {
if (web_form.IsNull())
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
- std::unique_ptr<PasswordForm> password_form(new PasswordForm());
+ auto password_form = std::make_unique<PasswordForm>();
password_form->action = form_util::GetCanonicalActionForForm(web_form);
if (!password_form->action.is_valid())
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
+ password_form->is_gaia_with_skip_save_password_form =
+ IsGaiaWithSkipSavePasswordForm(web_form) ||
+ IsGaiaReauthenticationForm(web_form);
SyntheticForm synthetic_form;
PopulateSyntheticFormFromWebForm(web_form, &synthetic_form);
if (!WebFormElementToFormData(
web_form, blink::WebFormControlElement(),
- field_value_and_properties_map, form_util::EXTRACT_NONE,
+ field_value_and_properties_map, form_util::EXTRACT_VALUE,
&password_form->form_data, nullptr /* FormFieldData */)) {
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
}
- if (!GetPasswordForm(synthetic_form, password_form.get(),
+ if (!GetPasswordForm(std::move(synthetic_form), password_form.get(),
field_value_and_properties_map, form_predictions,
username_detector_cache)) {
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
}
return password_form;
}
@@ -917,25 +1080,28 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
const FormsPredictionsMap* form_predictions,
UsernameDetectorCache* username_detector_cache) {
SyntheticForm synthetic_form;
+ std::vector<blink::WebElement> fieldsets;
synthetic_form.control_elements = form_util::GetUnownedFormFieldElements(
- frame.GetDocument().All(), &synthetic_form.fieldsets);
- synthetic_form.document = frame.GetDocument();
+ frame.GetDocument().All(), &fieldsets);
+ synthetic_form.origin =
+ form_util::GetCanonicalOriginForDocument(frame.GetDocument());
if (synthetic_form.control_elements.empty())
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
- std::unique_ptr<PasswordForm> password_form(new PasswordForm());
+ auto password_form = std::make_unique<PasswordForm>();
if (!UnownedPasswordFormElementsAndFieldSetsToFormData(
- synthetic_form.fieldsets, synthetic_form.control_elements, nullptr,
+ fieldsets, synthetic_form.control_elements, nullptr,
frame.GetDocument(), field_value_and_properties_map,
- form_util::EXTRACT_NONE, &password_form->form_data,
+ form_util::EXTRACT_VALUE, &password_form->form_data,
nullptr /* FormFieldData */)) {
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
}
- if (!GetPasswordForm(synthetic_form, password_form.get(),
+
+ if (!GetPasswordForm(std::move(synthetic_form), password_form.get(),
field_value_and_properties_map, form_predictions,
username_detector_cache)) {
- return std::unique_ptr<PasswordForm>();
+ return nullptr;
}
// No actual action on the form, so use the the origin as the action.
@@ -943,49 +1109,12 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
return password_form;
}
-bool HasAutocompleteAttributeValue(const blink::WebInputElement& element,
- base::StringPiece value_in_lowercase) {
- CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete"));
- const std::string autocomplete_value =
- element.GetAttribute(kAutocomplete)
- .Utf8(WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD);
-
- std::vector<base::StringPiece> tokens =
- base::SplitStringPiece(autocomplete_value, base::kWhitespaceASCII,
- base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- return std::find_if(tokens.begin(), tokens.end(),
- [value_in_lowercase](base::StringPiece token) {
- return base::LowerCaseEqualsASCII(token,
- value_in_lowercase);
- }) != tokens.end();
-}
-
-bool HasCreditCardAutocompleteAttributes(
- const blink::WebInputElement& element) {
- CR_DEFINE_STATIC_LOCAL(WebString, kAutocomplete, ("autocomplete"));
- const std::string autocomplete_value =
- element.GetAttribute(kAutocomplete)
- .Utf8(WebString::UTF8ConversionMode::kStrictReplacingErrorsWithFFFD);
-
- std::vector<base::StringPiece> tokens =
- base::SplitStringPiece(autocomplete_value, base::kWhitespaceASCII,
- base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- return std::find_if(
- tokens.begin(), tokens.end(), [](base::StringPiece token) {
- return base::StartsWith(token, kAutocompleteCreditCardPrefix,
- base::CompareCase::INSENSITIVE_ASCII);
- }) != tokens.end();
-}
-
bool IsCreditCardVerificationPasswordField(
const blink::WebInputElement& field) {
if (!field.IsPasswordFieldForAutofill())
return false;
-
- static const base::string16 kCardCvcReCached = base::UTF8ToUTF16(kCardCvcRe);
-
- return MatchesPattern(field.GetAttribute("id").Utf16(), kCardCvcReCached) ||
- MatchesPattern(field.GetAttribute("name").Utf16(), kCardCvcReCached);
+ return StringMatchesCVC(field.GetAttribute("id").Utf16()) ||
+ StringMatchesCVC(field.GetAttribute("name").Utf16());
}
std::string GetSignOnRealm(const GURL& origin) {
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
index f9135c1ad8d..a571ebd604d 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils.h
@@ -42,6 +42,20 @@ enum UsernameDetectionMethod {
USERNAME_DETECTION_METHOD_COUNT
};
+// The susbset of autocomplete flags related to passwords.
+enum class AutocompleteFlag {
+ NONE,
+ USERNAME,
+ CURRENT_PASSWORD,
+ NEW_PASSWORD,
+ // Represents the whole family of cc-* flags.
+ CREDIT_CARD
+};
+
+// Returns the AutocompleteFlag derived from |element|'s autocomplete attribute.
+AutocompleteFlag AutocompleteFlagForElement(
+ const blink::WebInputElement& element);
+
// The caller of this function is responsible for deleting the returned object.
re2::RE2* CreateMatcher(void* instance, const char* pattern);
@@ -81,15 +95,6 @@ std::unique_ptr<PasswordForm> CreatePasswordFormFromUnownedInputElements(
const FormsPredictionsMap* form_predictions,
UsernameDetectorCache* username_detector_cache);
-// Checks in a case-insensitive way if the autocomplete attribute for the given
-// |element| is present and has the specified |value_in_lowercase|.
-bool HasAutocompleteAttributeValue(const blink::WebInputElement& element,
- base::StringPiece value_in_lowercase);
-
-// Checks in a case-insensitive way if credit card autocomplete attributes for
-// the given |element| are present.
-bool HasCreditCardAutocompleteAttributes(const blink::WebInputElement& element);
-
// Returns whether the form |field| has a "password" type, but looks like a
// credit card verification field.
bool IsCreditCardVerificationPasswordField(const blink::WebInputElement& field);
diff --git a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
index 97b5a09eec6..30058360d75 100644
--- a/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
+++ b/chromium/components/autofill/content/renderer/password_form_conversion_utils_browsertest.cc
@@ -191,7 +191,7 @@ class PasswordFormBuilder {
class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest {
public:
- MAYBE_PasswordFormConversionUtilsTest() : content::RenderViewTest() {}
+ MAYBE_PasswordFormConversionUtilsTest() {}
~MAYBE_PasswordFormConversionUtilsTest() override {}
protected:
@@ -282,6 +282,11 @@ class MAYBE_PasswordFormConversionUtilsTest : public content::RenderViewTest {
return form_util::ExtractFormData(form, data);
}
+ void TearDown() override {
+ username_detector_cache_.clear();
+ content::RenderViewTest::TearDown();
+ }
+
UsernameDetectorCache username_detector_cache_;
private:
@@ -2328,79 +2333,6 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest,
}
}
-TEST_F(MAYBE_PasswordFormConversionUtilsTest,
- ProbablySignUpFormTwoTextOnePassword) {
- PasswordFormBuilder builder(kTestFormActionURL);
- builder.AddTextField("email", "johnsmith@gmail.com", nullptr);
- builder.AddTextField("username", "johnsmith", nullptr);
- builder.AddPasswordField("password", "secret", nullptr);
- std::string html = builder.ProduceHTML();
-
- // No user input, not considered as SignUp.
- std::unique_ptr<PasswordForm> password_form =
- LoadHTMLAndConvertForm(html, nullptr, false);
- ASSERT_TRUE(password_form);
- EXPECT_FALSE(password_form->only_for_fallback_saving);
- EXPECT_FALSE(password_form->does_look_like_signup_form);
-
- // With user input, considered as SignUp.
- password_form = LoadHTMLAndConvertForm(html, nullptr, true);
- ASSERT_TRUE(password_form);
- EXPECT_FALSE(password_form->only_for_fallback_saving);
- EXPECT_TRUE(password_form->does_look_like_signup_form);
-}
-
-TEST_F(MAYBE_PasswordFormConversionUtilsTest,
- ProbablySignUpFormOneTextNewAndConfirmPassword) {
- PasswordFormBuilder builder(kTestFormActionURL);
- builder.AddTextField("username", "johnsmith", nullptr);
- builder.AddPasswordField("new_password", "secret", nullptr);
- builder.AddPasswordField("confirm_password", "secret", nullptr);
- std::string html = builder.ProduceHTML();
-
- // No user input, not considered as SignUp.
- std::unique_ptr<PasswordForm> password_form =
- LoadHTMLAndConvertForm(html, nullptr, false);
- ASSERT_TRUE(password_form);
- EXPECT_FALSE(password_form->only_for_fallback_saving);
- EXPECT_FALSE(password_form->does_look_like_signup_form);
-
- // With user input, considered as SignUp.
- password_form = LoadHTMLAndConvertForm(html, nullptr, true);
- ASSERT_TRUE(password_form);
- EXPECT_FALSE(password_form->only_for_fallback_saving);
- EXPECT_TRUE(password_form->does_look_like_signup_form);
-}
-
-TEST_F(MAYBE_PasswordFormConversionUtilsTest,
- NotProbablySignUpFormOneTextCurrentAndNewPassword) {
- PasswordFormBuilder builder(kTestFormActionURL);
- builder.AddTextField("username", "johnsmith", nullptr);
- builder.AddPasswordField("password", "secret", nullptr);
- builder.AddPasswordField("new_password", "new_secret", nullptr);
- std::string html = builder.ProduceHTML();
-
- std::unique_ptr<PasswordForm> password_form =
- LoadHTMLAndConvertForm(html, nullptr, true);
- ASSERT_TRUE(password_form);
- EXPECT_FALSE(password_form->only_for_fallback_saving);
- EXPECT_FALSE(password_form->does_look_like_signup_form);
-}
-
-TEST_F(MAYBE_PasswordFormConversionUtilsTest,
- NotProbablySignUpFormForSignInForm) {
- PasswordFormBuilder builder(kTestFormActionURL);
- builder.AddTextField("username", "johnsmith", nullptr);
- builder.AddPasswordField("password", "secret", nullptr);
- std::string html = builder.ProduceHTML();
-
- std::unique_ptr<PasswordForm> password_form =
- LoadHTMLAndConvertForm(html, nullptr, true);
- ASSERT_TRUE(password_form);
- EXPECT_FALSE(password_form->only_for_fallback_saving);
- EXPECT_FALSE(password_form->does_look_like_signup_form);
-}
-
TEST_F(MAYBE_PasswordFormConversionUtilsTest, TooManyFieldsToParseForm) {
PasswordFormBuilder builder(kTestFormActionURL);
for (size_t i = 0; i < form_util::kMaxParseableFields + 1; ++i)
@@ -2511,4 +2443,63 @@ TEST_F(MAYBE_PasswordFormConversionUtilsTest, StickyPasswordType) {
EXPECT_EQ(old_form_data, new_form_data);
}
+// Check that Chrome remembers the value typed by the user in cases when it gets
+// overridden by the page.
+TEST_F(MAYBE_PasswordFormConversionUtilsTest, TypedValuePreserved) {
+ PasswordFormBuilder builder(kTestFormActionURL);
+ builder.AddTextField("fine", "", "username");
+ builder.AddPasswordField("mangled", "", "current-password");
+ builder.AddTextField("completed_for_user", "", nullptr);
+ std::string html = builder.ProduceHTML();
+
+ WebFormElement form;
+ LoadWebFormFromHTML(html, &form, nullptr);
+
+ FieldValueAndPropertiesMaskMap user_input;
+ WebVector<WebFormControlElement> control_elements;
+ form.GetFormControlElements(control_elements);
+
+ ASSERT_EQ(3u, control_elements.size());
+ ASSERT_EQ("fine", control_elements[0].NameForAutofill().Utf8());
+ control_elements[0].SetAutofillValue("same_value");
+ user_input[control_elements[0]] = std::make_pair(
+ std::make_unique<base::string16>(control_elements[0].Value().Utf16()),
+ FieldPropertiesFlags::USER_TYPED);
+
+ ASSERT_EQ("mangled", control_elements[1].NameForAutofill().Utf8());
+ control_elements[1].SetAutofillValue("mangled_value");
+ user_input[control_elements[1]] = std::make_pair(
+ std::make_unique<base::string16>(base::UTF8ToUTF16("original_value")),
+ FieldPropertiesFlags::USER_TYPED);
+
+ ASSERT_EQ("completed_for_user", control_elements[2].NameForAutofill().Utf8());
+ control_elements[2].SetAutofillValue("email@gmail.com");
+ user_input[control_elements[2]] = std::make_pair(
+ std::make_unique<base::string16>(base::UTF8ToUTF16("email")),
+ FieldPropertiesFlags::USER_TYPED);
+
+ std::unique_ptr<PasswordForm> password_form =
+ CreatePasswordFormFromWebForm(form, &user_input, nullptr, nullptr);
+
+ ASSERT_TRUE(password_form);
+
+ EXPECT_EQ(base::UTF8ToUTF16("same_value"), password_form->username_value);
+ EXPECT_EQ(base::UTF8ToUTF16("original_value"), password_form->password_value);
+
+ ASSERT_EQ(3u, password_form->form_data.fields.size());
+
+ EXPECT_EQ(base::UTF8ToUTF16("same_value"),
+ password_form->form_data.fields[0].value);
+ EXPECT_EQ(base::string16(), password_form->form_data.fields[0].typed_value);
+
+ EXPECT_EQ(base::UTF8ToUTF16("mangled_value"),
+ password_form->form_data.fields[1].value);
+ EXPECT_EQ(base::UTF8ToUTF16("original_value"),
+ password_form->form_data.fields[1].typed_value);
+
+ EXPECT_EQ(base::UTF8ToUTF16("email@gmail.com"),
+ password_form->form_data.fields[2].value);
+ EXPECT_EQ(base::string16(), password_form->form_data.fields[2].typed_value);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/content/renderer/password_generation_agent.cc b/chromium/components/autofill/content/renderer/password_generation_agent.cc
index 576d8139bb7..1173ba6a0ab 100644
--- a/chromium/components/autofill/content/renderer/password_generation_agent.cc
+++ b/chromium/components/autofill/content/renderer/password_generation_agent.cc
@@ -40,6 +40,26 @@ namespace {
using Logger = autofill::SavePasswordProgressLogger;
+// Returns pairs of |PasswordForm| and corresponding |WebFormElement| for all
+// <form>s in the frame and for unowned <input>s. The method doesn't filter out
+// invalid |PasswordForm|s.
+std::vector<std::pair<std::unique_ptr<PasswordForm>, blink::WebFormElement>>
+GetAllPasswordFormsInFrame(PasswordAutofillAgent* password_agent,
+ blink::WebLocalFrame* web_frame) {
+ blink::WebVector<blink::WebFormElement> web_forms;
+ web_frame->GetDocument().Forms(web_forms);
+ std::vector<std::pair<std::unique_ptr<PasswordForm>, blink::WebFormElement>>
+ all_forms;
+ for (const blink::WebFormElement& web_form : web_forms) {
+ all_forms.emplace_back(std::make_pair(
+ password_agent->GetPasswordFormFromWebForm(web_form), web_form));
+ }
+ all_forms.emplace_back(
+ std::make_pair(password_agent->GetPasswordFormFromUnownedInputElements(),
+ blink::WebFormElement()));
+ return all_forms;
+}
+
// Returns true if we think that this form is for account creation. Password
// field(s) of the form are pushed back to |passwords|.
bool GetAccountCreationPasswordFields(
@@ -79,7 +99,8 @@ std::vector<blink::WebInputElement> FindNewPasswordElementsMarkedBySite(
std::vector<blink::WebInputElement> passwords;
auto is_new_password_field = [](const blink::WebInputElement& element) {
- return HasAutocompleteAttributeValue(element, "new-password");
+ return AutocompleteFlagForElement(element) ==
+ AutocompleteFlag::NEW_PASSWORD;
};
auto field_iter =
@@ -288,17 +309,15 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
if (generation_form_data_)
return;
- blink::WebVector<blink::WebFormElement> forms;
- render_frame()->GetWebFrame()->GetDocument().Forms(forms);
- for (size_t i = 0; i < forms.size(); ++i) {
- if (forms[i].IsNull())
- continue;
-
+ blink::WebLocalFrame* web_frame = render_frame()->GetWebFrame();
+ std::vector<std::pair<std::unique_ptr<PasswordForm>, blink::WebFormElement>>
+ all_password_forms =
+ GetAllPasswordFormsInFrame(password_agent_, web_frame);
+ for (auto& form : all_password_forms) {
+ PasswordForm* password_form = form.first.get();
// If we can't get a valid PasswordForm, we skip this form because the
// the password won't get saved even if we generate it.
- std::unique_ptr<PasswordForm> password_form(
- password_agent_->GetPasswordFormFromWebForm(forms[i]));
- if (!password_form.get()) {
+ if (!password_form) {
LogMessage(Logger::STRING_GENERATION_RENDERER_INVALID_PASSWORD_FORM);
continue;
}
@@ -310,13 +329,17 @@ void PasswordGenerationAgent::FindPossibleGenerationForm() {
continue;
std::vector<blink::WebInputElement> passwords;
+ const blink::WebFormElement& web_form = form.second;
if (GetAccountCreationPasswordFields(
- form_util::ExtractAutofillableElementsInForm(forms[i]),
+ web_form.IsNull()
+ ? form_util::GetUnownedFormFieldElements(
+ web_frame->GetDocument().All(), nullptr)
+ : form_util::ExtractAutofillableElementsInForm(web_form),
&passwords)) {
- if (form_classifier_enabled_)
- RunFormClassifierAndSaveVote(forms[i], *password_form);
+ if (form_classifier_enabled_ && !web_form.IsNull())
+ RunFormClassifierAndSaveVote(web_form, *password_form);
possible_account_creation_forms_.emplace_back(
- make_linked_ptr(password_form.release()), std::move(passwords));
+ make_linked_ptr(form.first.release()), std::move(passwords));
}
}
diff --git a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
index c7b0b3a4324..9fd6c67503f 100644
--- a/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
+++ b/chromium/components/autofill/content/renderer/renderer_save_password_progress_logger_unittest.cc
@@ -70,9 +70,6 @@ class FakeContentPasswordManagerDriver : public mojom::PasswordManagerDriver {
int options,
const gfx::RectF& bounds) override {}
- void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
- const gfx::RectF& bounds) override {}
-
void ShowManualFallbackSuggestion(base::i18n::TextDirection text_direction,
const gfx::RectF& bounds) override {}
diff --git a/chromium/components/autofill/core/browser/BUILD.gn b/chromium/components/autofill/core/browser/BUILD.gn
index 835d48acf18..7a1cb4f07ff 100644
--- a/chromium/components/autofill/core/browser/BUILD.gn
+++ b/chromium/components/autofill/core/browser/BUILD.gn
@@ -130,6 +130,7 @@ static_library("browser") {
"phone_number_i18n.cc",
"phone_number_i18n.h",
"popup_item_ids.h",
+ "popup_types.h",
"rationalization_util.cc",
"rationalization_util.h",
"region_combobox_model.cc",
@@ -154,8 +155,6 @@ static_library("browser") {
"webdata/autocomplete_sync_bridge.h",
"webdata/autofill_change.cc",
"webdata/autofill_change.h",
- "webdata/autofill_data_type_controller.cc",
- "webdata/autofill_data_type_controller.h",
"webdata/autofill_entry.cc",
"webdata/autofill_entry.h",
"webdata/autofill_profile_data_type_controller.cc",
@@ -308,13 +307,6 @@ static_library("test_support") {
"test_sync_service.h",
]
- if (!is_android) {
- sources += [
- "ui/mock_save_card_bubble_controller.cc",
- "ui/mock_save_card_bubble_controller.h",
- ]
- }
-
public_deps = [
":browser",
]
@@ -420,7 +412,6 @@ source_set("unit_tests") {
"ui/card_unmask_prompt_controller_impl_unittest.cc",
"validation_unittest.cc",
"webdata/autocomplete_sync_bridge_unittest.cc",
- "webdata/autofill_data_type_controller_unittest.cc",
"webdata/autofill_profile_syncable_service_unittest.cc",
"webdata/autofill_table_unittest.cc",
"webdata/autofill_wallet_metadata_syncable_service_unittest.cc",
diff --git a/chromium/components/autofill/core/browser/address.cc b/chromium/components/autofill/core/browser/address.cc
index 04f2d8c4d76..f3ab3a3245f 100644
--- a/chromium/components/autofill/core/browser/address.cc
+++ b/chromium/components/autofill/core/browser/address.cc
@@ -27,7 +27,7 @@ namespace autofill {
Address::Address() {}
-Address::Address(const Address& address) : FormGroup() {
+Address::Address(const Address& address) {
*this = address;
}
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
index 1a4f54a622e..f9f06cf23b9 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager.cc
@@ -68,7 +68,7 @@ void AutocompleteHistoryManager::OnGetAutocompleteSuggestions(
return;
}
- if (database_.get()) {
+ if (database_) {
pending_query_handle_ = database_->GetFormValuesForElementName(
name, prefix, kMaxAutocompleteMenuItems, this);
}
@@ -108,7 +108,7 @@ void AutocompleteHistoryManager::OnWillSubmitForm(const FormData& form) {
void AutocompleteHistoryManager::OnRemoveAutocompleteEntry(
const base::string16& name, const base::string16& value) {
- if (database_.get())
+ if (database_)
database_->RemoveFormValueForElementName(name, value);
}
@@ -119,7 +119,7 @@ void AutocompleteHistoryManager::SetExternalDelegate(
void AutocompleteHistoryManager::CancelPendingQuery() {
if (pending_query_handle_) {
- if (database_.get())
+ if (database_)
database_->CancelRequest(pending_query_handle_);
pending_query_handle_ = 0;
}
diff --git a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
index 13096de0fe3..c22cf0c45c4 100644
--- a/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autocomplete_history_manager_unittest.cc
@@ -42,7 +42,7 @@ class MockWebDataService : public AutofillWebDataService {
MOCK_METHOD1(AddFormFields, void(const std::vector<FormFieldData>&));
protected:
- virtual ~MockWebDataService() {}
+ ~MockWebDataService() override {}
};
class MockAutofillClient : public TestAutofillClient {
@@ -101,7 +101,7 @@ TEST_F(AutocompleteHistoryManagerTest, CreditCardNumberValue) {
valid_cc.form_control_type = "text";
form.fields.push_back(valid_cc);
- EXPECT_CALL(*web_data_service_.get(), AddFormFields(_)).Times(0);
+ EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0);
autocomplete_manager_->OnWillSubmitForm(form);
}
@@ -140,7 +140,7 @@ TEST_F(AutocompleteHistoryManagerTest, SSNValue) {
ssn.form_control_type = "text";
form.fields.push_back(ssn);
- EXPECT_CALL(*web_data_service_.get(), AddFormFields(_)).Times(0);
+ EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0);
autocomplete_manager_->OnWillSubmitForm(form);
}
@@ -182,7 +182,7 @@ TEST_F(AutocompleteHistoryManagerTest, FieldWithAutocompleteOff) {
field.should_autocomplete = false;
form.fields.push_back(field);
- EXPECT_CALL(*web_data_service_.get(), AddFormFields(_)).Times(0);
+ EXPECT_CALL(*web_data_service_, AddFormFields(_)).Times(0);
autocomplete_manager_->OnWillSubmitForm(form);
}
@@ -193,7 +193,7 @@ class MockAutofillExternalDelegate : public AutofillExternalDelegate {
MockAutofillExternalDelegate(AutofillManager* autofill_manager,
AutofillDriver* autofill_driver)
: AutofillExternalDelegate(autofill_manager, autofill_driver) {}
- virtual ~MockAutofillExternalDelegate() {}
+ ~MockAutofillExternalDelegate() override {}
MOCK_METHOD3(OnSuggestionsReturned,
void(int query_id,
diff --git a/chromium/components/autofill/core/browser/autofill_client.h b/chromium/components/autofill/core/browser/autofill_client.h
index c93eeb2242e..77f5dd8390e 100644
--- a/chromium/components/autofill/core/browser/autofill_client.h
+++ b/chromium/components/autofill/core/browser/autofill_client.h
@@ -49,7 +49,6 @@ class CardUnmaskDelegate;
class CreditCard;
class FormStructure;
class PersonalDataManager;
-class SaveCardBubbleController;
struct Suggestion;
// A client interface that needs to be supplied to the Autofill component by the
@@ -114,10 +113,6 @@ class AutofillClient : public RiskDataLoader {
// Gets an AddressNormalizer instance (can be null).
virtual AddressNormalizer* GetAddressNormalizer() = 0;
- // Gets the SaveCardBubbleController instance associated with the client.
- // May return nullptr if the save card bubble has not been shown yet.
- virtual SaveCardBubbleController* GetSaveCardBubbleController() = 0;
-
// Causes the Autofill settings UI to be shown.
virtual void ShowAutofillSettings() = 0;
@@ -134,12 +129,10 @@ class AutofillClient : public RiskDataLoader {
const base::Closure& callback) = 0;
// Runs |callback| if the |card| should be uploaded to Payments. Displays the
- // contents of |legal_message| to the user. Display a CVC field in the bubble
- // if |should_cvc_be_requested| is true.
+ // contents of |legal_message| to the user.
virtual void ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
- bool should_cvc_be_requested,
const base::Closure& callback) = 0;
// Will show an infobar to get user consent for Credit Card assistive filling.
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.cc b/chromium/components/autofill/core/browser/autofill_download_manager.cc
index 7b1be675a5a..478ecb4cd5b 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.cc
@@ -4,32 +4,148 @@
#include "components/autofill/core/browser/autofill_download_manager.h"
+#include <tuple>
#include <utility>
+#include "base/base64url.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/rand_util.h"
+#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/autofill_driver.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/proto/server.pb.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_pref_names.h"
+#include "components/autofill/core/common/autofill_switches.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/variations/net/variations_http_headers.h"
#include "net/base/load_flags.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "url/gurl.h"
+
+namespace autofill {
namespace {
+const size_t kMaxQueryGetSize = 1400; // 1.25KB
+const size_t kMaxFormCacheSize = 16;
+const size_t kMaxFieldsPerQueryRequest = 100;
+
+const net::BackoffEntry::Policy kAutofillBackoffPolicy = {
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 0,
+
+ // Initial delay for exponential back-off in ms.
+ 1000, // 1 second.
+
+ // Factor by which the waiting time will be multiplied.
+ 2,
+
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0.33, // 33%.
+
+ // Maximum amount of time we are willing to delay our request in ms.
+ 30 * 1000, // 30 seconds.
+
+ // Time to keep an entry from being discarded even when it
+ // has no significant state, -1 to never discard.
+ -1,
+
+ // Don't use initial delay unless the last request was an error.
+ false,
+};
+
+#if defined(GOOGLE_CHROME_BUILD)
+const char kClientName[] = "Google+Chrome";
+#else
+const char kClientName[] = "Chromium";
+#endif // defined(GOOGLE_CHROME_BUILD)
+
+const char kDefaultAutofillServerURL[] =
+ "https://clients1.google.com/tbproxy/af/";
+
+// Returns the base URL for the autofill server.
+GURL GetAutofillServerURL() {
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kAutofillServerURL)) {
+ GURL url(command_line.GetSwitchValueASCII(switches::kAutofillServerURL));
+ if (url.is_valid())
+ return url;
+
+ LOG(ERROR) << "Invalid URL given for --" << switches::kAutofillServerURL
+ << ". Using default value.";
+ }
+
+ GURL default_url(kDefaultAutofillServerURL);
+ DCHECK(default_url.is_valid());
+ return default_url;
+}
+
+// Helper to log the HTTP |response_code| received for |request_type| to UMA.
+void LogHttpResponseCode(AutofillDownloadManager::RequestType request_type,
+ int response_code) {
+ const char* name = nullptr;
+ switch (request_type) {
+ case AutofillDownloadManager::REQUEST_QUERY:
+ name = "Autofill.Query.HttpResponseCode";
+ break;
+ case AutofillDownloadManager::REQUEST_UPLOAD:
+ name = "Autofill.Upload.HttpResponseCode";
+ break;
+ default:
+ NOTREACHED();
+ name = "Autofill.Unknown.HttpResponseCode";
+ }
+
+ if (response_code < 100 || response_code > 599)
+ response_code = 0;
+
+ // An expanded version of UMA_HISTOGRAM_ENUMERATION that supports using
+ // a different name with each invocation.
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ name, 1, 599, 600, base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(response_code);
+}
+
+// Helper to log, to UMA, the |num_bytes| sent for a failing instance of
+// |request_type|.
+void LogFailingPayloadSize(AutofillDownloadManager::RequestType request_type,
+ size_t num_bytes) {
+ const char* name = nullptr;
+ switch (request_type) {
+ case AutofillDownloadManager::REQUEST_QUERY:
+ name = "Autofill.Query.FailingPayloadSize";
+ break;
+ case AutofillDownloadManager::REQUEST_UPLOAD:
+ name = "Autofill.Upload.FailingPayloadSize";
+ break;
+ default:
+ NOTREACHED();
+ name = "Autofill.Unknown.FailingPayloadSize";
+ }
+
+ // An expanded version of UMA_HISTOGRAM_COUNTS_100000 that supports using
+ // a different name with each invocation.
+ base::HistogramBase* histogram = base::Histogram::FactoryGet(
+ name, 1, 100000, 50, base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(num_bytes);
+}
+
net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
const autofill::AutofillDownloadManager::RequestType& request_type) {
if (request_type == autofill::AutofillDownloadManager::REQUEST_QUERY) {
@@ -98,47 +214,6 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotation(
})");
}
-} // namespace
-
-namespace autofill {
-
-namespace {
-
-const size_t kMaxFormCacheSize = 16;
-const size_t kMaxFieldsPerQueryRequest = 100;
-
-const net::BackoffEntry::Policy kAutofillBackoffPolicy = {
- // Number of initial errors (in sequence) to ignore before applying
- // exponential back-off rules.
- 0,
-
- // Initial delay for exponential back-off in ms.
- 1000, // 1 second.
-
- // Factor by which the waiting time will be multiplied.
- 2,
-
- // Fuzzing percentage. ex: 10% will spread requests randomly
- // between 90%-100% of the calculated time.
- 0.33, // 33%.
-
- // Maximum amount of time we are willing to delay our request in ms.
- 30 * 1000, // 30 seconds.
-
- // Time to keep an entry from being discarded even when it
- // has no significant state, -1 to never discard.
- -1,
-
- // Don't use initial delay unless the last request was an error.
- false,
-};
-
-#if defined(GOOGLE_CHROME_BUILD)
-const char kClientName[] = "Google Chrome";
-#else
-const char kClientName[] = "Chromium";
-#endif // defined(GOOGLE_CHROME_BUILD)
-
size_t CountActiveFieldsInForms(const std::vector<FormStructure*>& forms) {
size_t active_field_count = 0;
for (const auto* form : forms)
@@ -146,7 +221,7 @@ size_t CountActiveFieldsInForms(const std::vector<FormStructure*>& forms) {
return active_field_count;
}
-std::string RequestTypeToString(AutofillDownloadManager::RequestType type) {
+const char* RequestTypeToString(AutofillDownloadManager::RequestType type) {
switch (type) {
case AutofillDownloadManager::REQUEST_QUERY:
return "query";
@@ -154,12 +229,7 @@ std::string RequestTypeToString(AutofillDownloadManager::RequestType type) {
return "upload";
}
NOTREACHED();
- return std::string();
-}
-
-GURL GetRequestUrl(AutofillDownloadManager::RequestType request_type) {
- return GURL("https://clients1.google.com/tbproxy/af/" +
- RequestTypeToString(request_type) + "?client=" + kClientName);
+ return "";
}
std::ostream& operator<<(std::ostream& out,
@@ -219,6 +289,7 @@ AutofillDownloadManager::AutofillDownloadManager(AutofillDriver* driver,
Observer* observer)
: driver_(driver),
observer_(observer),
+ autofill_server_url_(GetAutofillServerURL()),
max_form_cache_size_(kMaxFormCacheSize),
fetcher_backoff_(&kAutofillBackoffPolicy),
fetcher_id_for_unittest_(0),
@@ -247,12 +318,12 @@ bool AutofillDownloadManager::StartQueryRequest(
return false;
request_data.request_type = AutofillDownloadManager::REQUEST_QUERY;
- request_data.payload = payload;
+ request_data.payload = std::move(payload);
AutofillMetrics::LogServerQueryMetric(AutofillMetrics::QUERY_SENT);
std::string query_data;
if (CheckCacheForQueryRequest(request_data.form_signatures, &query_data)) {
- VLOG(1) << "AutofillDownloadManager: query request has been retrieved "
+ DVLOG(1) << "AutofillDownloadManager: query request has been retrieved "
<< "from the cache, form signatures: "
<< GetCombinedSignature(request_data.form_signatures);
observer_->OnLoadedServerPredictions(std::move(query_data),
@@ -260,9 +331,9 @@ bool AutofillDownloadManager::StartQueryRequest(
return true;
}
- VLOG(1) << "Sending Autofill Query Request:\n" << query;
+ DVLOG(1) << "Sending Autofill Query Request:\n" << query;
- return StartRequest(request_data);
+ return StartRequest(std::move(request_data));
}
bool AutofillDownloadManager::StartUploadRequest(
@@ -282,7 +353,7 @@ bool AutofillDownloadManager::StartUploadRequest(
return false;
if (form.upload_required() == UPLOAD_NOT_REQUIRED) {
- VLOG(1) << "AutofillDownloadManager: Upload request is ignored.";
+ DVLOG(1) << "AutofillDownloadManager: Upload request is ignored.";
// If we ever need notification that upload was skipped, add it here.
return false;
}
@@ -290,35 +361,69 @@ bool AutofillDownloadManager::StartUploadRequest(
FormRequestData request_data;
request_data.form_signatures.push_back(form.FormSignatureAsStr());
request_data.request_type = AutofillDownloadManager::REQUEST_UPLOAD;
- request_data.payload = payload;
+ request_data.payload = std::move(payload);
+
+ DVLOG(1) << "Sending Autofill Upload Request:\n" << upload;
+
+ return StartRequest(std::move(request_data));
+}
+
+std::tuple<GURL, net::URLFetcher::RequestType>
+AutofillDownloadManager::GetRequestURLAndMethod(
+ const FormRequestData& request_data) const {
+ net::URLFetcher::RequestType method = net::URLFetcher::POST;
+ std::string query_str(base::StrCat({"client=", kClientName}));
+
+ if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) {
+ if (request_data.payload.length() <= kMaxQueryGetSize &&
+ base::FeatureList::IsEnabled(features::kAutofillCacheQueryResponses)) {
+ method = net::URLFetcher::GET;
+ std::string base64_payload;
+ base::Base64UrlEncode(request_data.payload,
+ base::Base64UrlEncodePolicy::INCLUDE_PADDING,
+ &base64_payload);
+ base::StrAppend(&query_str, {"&q=", base64_payload});
+ }
+ UMA_HISTOGRAM_BOOLEAN("Autofill.Query.Method",
+ (method == net::URLFetcher::GET) ? 0 : 1);
+ }
- VLOG(1) << "Sending Autofill Upload Request:\n" << upload;
+ GURL::Replacements replacements;
+ replacements.SetQueryStr(std::move(query_str));
- return StartRequest(request_data);
+ GURL url = autofill_server_url_
+ .Resolve(RequestTypeToString(request_data.request_type))
+ .ReplaceComponents(replacements);
+
+ return std::make_tuple(std::move(url), method);
}
-bool AutofillDownloadManager::StartRequest(
- const FormRequestData& request_data) {
+bool AutofillDownloadManager::StartRequest(FormRequestData request_data) {
net::URLRequestContextGetter* request_context =
driver_->GetURLRequestContext();
DCHECK(request_context);
- GURL request_url = GetRequestUrl(request_data.request_type);
+
+ // Get the URL and method to use for this request.
+ net::URLFetcher::RequestType method;
+ GURL request_url;
+ std::tie(request_url, method) = GetRequestURLAndMethod(request_data);
// Id is ignored for regular chrome, in unit test id's for fake fetcher
// factory will be 0, 1, 2, ...
- std::unique_ptr<net::URLFetcher> owned_fetcher = net::URLFetcher::Create(
- fetcher_id_for_unittest_++, request_url, net::URLFetcher::POST, this,
+ std::unique_ptr<net::URLFetcher> fetcher = net::URLFetcher::Create(
+ fetcher_id_for_unittest_++, request_url, method, this,
GetNetworkTrafficAnnotation(request_data.request_type));
- net::URLFetcher* fetcher = owned_fetcher.get();
+
data_use_measurement::DataUseUserData::AttachToFetcher(
- fetcher, data_use_measurement::DataUseUserData::AUTOFILL);
- url_fetchers_[fetcher] =
- std::make_pair(std::move(owned_fetcher), request_data);
+ fetcher.get(), data_use_measurement::DataUseUserData::AUTOFILL);
fetcher->SetAutomaticallyRetryOn5xx(false);
fetcher->SetRequestContext(request_context);
- fetcher->SetUploadData("text/proto", request_data.payload);
fetcher->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DO_NOT_SEND_COOKIES);
+ if (method == net::URLFetcher::POST) {
+ fetcher->SetUploadData("text/proto", request_data.payload);
+ }
+
// Add Chrome experiment state to the request headers.
net::HttpRequestHeaders headers;
// Note: It's OK to pass SignedIn::kNo if it's unknown, as it does not affect
@@ -329,7 +434,14 @@ bool AutofillDownloadManager::StartRequest(
: variations::InIncognito::kNo,
variations::SignedIn::kNo, &headers);
fetcher->SetExtraRequestHeaders(headers.ToString());
- fetcher->Start();
+
+ // Transfer ownership of the fetcher into url_fetchers_. Temporarily hang
+ // onto the raw pointer to use it as a key and to kick off the request;
+ // transferring ownership (std::move) invalidates the |fetcher| variable.
+ auto* raw_fetcher = fetcher.get();
+ url_fetchers_[raw_fetcher] =
+ std::make_pair(std::move(fetcher), std::move(request_data));
+ raw_fetcher->Start();
return true;
}
@@ -394,41 +506,58 @@ void AutofillDownloadManager::OnURLFetchComplete(
// with unknown fetcher when network is refreshed.
return;
}
- std::string request_type(RequestTypeToString(it->second.second.request_type));
- CHECK(it->second.second.form_signatures.size());
- bool success = source->GetResponseCode() == net::HTTP_OK;
+ // Move the fetcher and request out of the active fetchers list.
+ std::unique_ptr<net::URLFetcher> fetcher = std::move(it->second.first);
+ FormRequestData request_data = std::move(it->second.second);
+ url_fetchers_.erase(it);
+
+ CHECK(request_data.form_signatures.size());
+ const int response_code = fetcher->GetResponseCode();
+ const bool success = (response_code == net::HTTP_OK);
fetcher_backoff_.InformOfRequest(success);
+ LogHttpResponseCode(request_data.request_type, response_code);
+
if (!success) {
+ DVLOG(1) << "AutofillDownloadManager: "
+ << RequestTypeToString(request_data.request_type)
+ << " request has failed with response " << response_code;
+
+ observer_->OnServerRequestError(request_data.form_signatures[0],
+ request_data.request_type, response_code);
+
+ LogFailingPayloadSize(request_data.request_type,
+ request_data.payload.length());
+
+ // If the failure was a client error don't retry.
+ if (response_code >= 400 && response_code <= 499)
+ return;
+
// Reschedule with the appropriate delay, ignoring return value because
// payload is already well formed.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
- base::Bind(base::IgnoreResult(&AutofillDownloadManager::StartRequest),
- weak_factory_.GetWeakPtr(), it->second.second),
+ base::BindOnce(
+ base::IgnoreResult(&AutofillDownloadManager::StartRequest),
+ weak_factory_.GetWeakPtr(), std::move(request_data)),
fetcher_backoff_.GetTimeUntilRelease());
+ return;
+ }
- VLOG(1) << "AutofillDownloadManager: " << request_type
- << " request has failed with response "
- << source->GetResponseCode();
- observer_->OnServerRequestError(it->second.second.form_signatures[0],
- it->second.second.request_type,
- source->GetResponseCode());
- } else {
+ if (request_data.request_type == AutofillDownloadManager::REQUEST_QUERY) {
std::string response_body;
- source->GetResponseAsString(&response_body);
- if (it->second.second.request_type ==
- AutofillDownloadManager::REQUEST_QUERY) {
- CacheQueryRequest(it->second.second.form_signatures, response_body);
- observer_->OnLoadedServerPredictions(std::move(response_body),
- it->second.second.form_signatures);
- } else {
- VLOG(1) << "AutofillDownloadManager: upload request has succeeded.";
- observer_->OnUploadedPossibleFieldTypes();
- }
+ fetcher->GetResponseAsString(&response_body);
+ CacheQueryRequest(request_data.form_signatures, response_body);
+ UMA_HISTOGRAM_BOOLEAN("Autofill.Query.WasInCache", fetcher->WasCached());
+ observer_->OnLoadedServerPredictions(std::move(response_body),
+ request_data.form_signatures);
+ return;
}
- url_fetchers_.erase(it);
+
+ DCHECK_EQ(request_data.request_type, AutofillDownloadManager::REQUEST_UPLOAD);
+ DVLOG(1) << "AutofillDownloadManager: upload request has succeeded.";
+ observer_->OnUploadedPossibleFieldTypes();
}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager.h b/chromium/components/autofill/core/browser/autofill_download_manager.h
index c1b39b1d58b..e0a564b14ad 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_download_manager.h
@@ -10,6 +10,7 @@
#include <map>
#include <memory>
#include <string>
+#include <tuple>
#include <utility>
#include <vector>
@@ -19,11 +20,9 @@
#include "base/time/time.h"
#include "components/autofill/core/browser/autofill_type.h"
#include "net/base/backoff_entry.h"
+#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_fetcher_delegate.h"
-
-namespace net {
-class URLFetcher;
-} // namespace net
+#include "url/gurl.h"
namespace autofill {
@@ -99,10 +98,18 @@ class AutofillDownloadManager : public net::URLFetcherDelegate {
struct FormRequestData;
typedef std::list<std::pair<std::string, std::string> > QueryRequestCache;
+ // Returns the URL and request method to use when issuing the request
+ // described by |request_data|. If the returned method is GET, the URL
+ // fully encompasses the request, do not include request_data.payload when
+ // transmitting the request.
+ std::tuple<GURL, net::URLFetcher::RequestType> GetRequestURLAndMethod(
+ const FormRequestData& request_data) const;
+
// Initiates request to Autofill servers to download/upload type predictions.
// |request_data| - form signature hash(es), request payload data and request
// type (query or upload).
- bool StartRequest(const FormRequestData& request_data);
+ // Note: |request_data| takes ownership of request_data, call with std::move.
+ bool StartRequest(FormRequestData request_data);
// Each request is page visited. We store last |max_form_cache_size|
// request, to avoid going over the wire. Set to 16 in constructor. Warning:
@@ -134,6 +141,10 @@ class AutofillDownloadManager : public net::URLFetcherDelegate {
// Must not be null.
AutofillDownloadManager::Observer* const observer_; // WEAK
+ // The autofill server URL root: scheme://host[:port]/path excluding the
+ // final path component for the request and the query params.
+ GURL autofill_server_url_;
+
// For each requested form for both query and upload we create a separate
// request and save its info. As url fetcher is identified by its address
// we use a map between fetchers and info. The value type is a pair of an
diff --git a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
index a35d456158b..cccf4753bfd 100644
--- a/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -16,7 +16,11 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/task_scheduler/post_task.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/autofill_field.h"
@@ -24,8 +28,13 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/test_autofill_driver.h"
+#include "components/autofill/core/common/autofill_features.h"
+#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
#include "net/http/http_status_code.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_test_util.h"
@@ -33,11 +42,18 @@
#include "testing/gtest/include/gtest/gtest.h"
using base::ASCIIToUTF16;
-
+using net::test_server::EmbeddedTestServer;
+using net::test_server::BasicHttpResponse;
+using net::test_server::HttpRequest;
+using net::test_server::HttpResponse;
namespace autofill {
namespace {
+const int METHOD_GET = 0;
+const int METHOD_POST = 1;
+const int CACHE_MISS = 0;
+const int CACHE_HIT = 1;
// Call |fetcher->OnURLFetchComplete()| as the URLFetcher would when
// a response is received. Params allow caller to set fake status.
void FakeOnURLFetchComplete(net::TestURLFetcher* fetcher,
@@ -135,6 +151,9 @@ class AutofillDownloadManagerTest : public AutofillDownloadManager::Observer,
};
TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
+ base::test::ScopedFeatureList fl;
+ fl.InitAndEnableFeature(features::kAutofillCacheQueryResponses);
+
// Create and register factory.
net::TestURLFetcherFactory factory;
@@ -228,6 +247,7 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
download_manager_.StartQueryRequest(ToRawPointerVector(form_structures)));
histogram.ExpectUniqueSample("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_SENT, 1);
+ histogram.ExpectUniqueSample("Autofill.Query.Method", METHOD_GET, 1);
// Request with id 1.
EXPECT_TRUE(download_manager_.StartUploadRequest(
@@ -260,17 +280,24 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
net::TestURLFetcher* fetcher = factory.GetFetcherByID(1);
ASSERT_TRUE(fetcher);
FakeOnURLFetchComplete(fetcher, net::HTTP_OK, std::string(responses[1]));
+ histogram.ExpectBucketCount("Autofill.Upload.HttpResponseCode", net::HTTP_OK,
+ 1);
// Request 2: Unsuccessful upload.
fetcher = factory.GetFetcherByID(2);
ASSERT_TRUE(fetcher);
FakeOnURLFetchComplete(fetcher, net::HTTP_NOT_FOUND,
std::string(responses[2]));
+ histogram.ExpectBucketCount("Autofill.Upload.HttpResponseCode",
+ net::HTTP_NOT_FOUND, 1);
// Request 0: Successful query.
fetcher = factory.GetFetcherByID(0);
ASSERT_TRUE(fetcher);
FakeOnURLFetchComplete(fetcher, net::HTTP_OK, std::string(responses[0]));
EXPECT_EQ(3U, responses_.size());
+ histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_MISS, 1);
+ histogram.ExpectBucketCount("Autofill.Query.HttpResponseCode", net::HTTP_OK,
+ 1);
// Check Request 1.
EXPECT_EQ(AutofillDownloadManagerTest::UPLOAD_SUCCESSFULL,
@@ -313,8 +340,11 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
ASSERT_TRUE(fetcher);
histogram.ExpectUniqueSample("Autofill.ServerQueryResponse",
AutofillMetrics::QUERY_SENT, 2);
+ histogram.ExpectUniqueSample("Autofill.Query.Method", METHOD_GET, 2);
FakeOnURLFetchComplete(fetcher, net::HTTP_INTERNAL_SERVER_ERROR,
std::string(responses[0]));
+ histogram.ExpectBucketCount("Autofill.Query.HttpResponseCode",
+ net::HTTP_INTERNAL_SERVER_ERROR, 1);
// Check Request 4.
EXPECT_EQ(AutofillDownloadManagerTest::REQUEST_QUERY_FAILED,
@@ -323,6 +353,45 @@ TEST_F(AutofillDownloadManagerTest, QueryAndUploadTest) {
// Expected response on non-query request is an empty string.
EXPECT_EQ(std::string(), responses_.front().response);
responses_.pop_front();
+
+ // Request with id 5. Let's pretend we hit the cache.
+ EXPECT_TRUE(
+ download_manager_.StartQueryRequest(ToRawPointerVector(form_structures)));
+ histogram.ExpectBucketCount("Autofill.ServerQueryResponse",
+ AutofillMetrics::QUERY_SENT, 3);
+ histogram.ExpectBucketCount("Autofill.Query.Method", METHOD_GET, 3);
+ fetcher = factory.GetFetcherByID(5);
+ ASSERT_TRUE(fetcher);
+ fetcher->set_was_cached(true);
+ FakeOnURLFetchComplete(fetcher, net::HTTP_OK, std::string(responses[0]));
+
+ // Check Request 5.
+ EXPECT_EQ(responses_.front().type_of_response,
+ AutofillDownloadManagerTest::QUERY_SUCCESSFULL);
+ responses_.pop_front();
+ histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_HIT, 1);
+
+ // Test query with caching disabled.
+ base::test::ScopedFeatureList fl2;
+ fl2.InitAndDisableFeature(features::kAutofillCacheQueryResponses);
+
+ // Don't hit the in-mem cache.
+ field.label = ASCIIToUTF16("Address line 3");
+ field.name = ASCIIToUTF16("address3");
+ field.form_control_type = "text";
+ form.fields.push_back(field);
+ form_structures.push_back(std::make_unique<FormStructure>(form));
+
+ // Request with id 6
+ EXPECT_TRUE(
+ download_manager_.StartQueryRequest(ToRawPointerVector(form_structures)));
+ histogram.ExpectBucketCount("Autofill.ServerQueryResponse",
+ AutofillMetrics::QUERY_SENT, 4);
+ histogram.ExpectBucketCount("Autofill.Query.Method", METHOD_POST, 1);
+ fetcher = factory.GetFetcherByID(6);
+ ASSERT_TRUE(fetcher);
+ FakeOnURLFetchComplete(fetcher, net::HTTP_OK, std::string(responses[0]));
+ histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_MISS, 2);
}
TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) {
@@ -365,12 +434,12 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) {
ASSERT_TRUE(fetcher);
// Request error incurs a retry after 1 second.
- FakeOnURLFetchComplete(fetcher, net::HTTP_NOT_FOUND, "<html></html>");
+ FakeOnURLFetchComplete(fetcher, net::HTTP_INTERNAL_SERVER_ERROR, "");
EXPECT_EQ(1U, responses_.size());
EXPECT_LT(download_manager_.fetcher_backoff_.GetTimeUntilRelease(),
base::TimeDelta::FromMilliseconds(1100));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
base::TimeDelta::FromMilliseconds(1100));
base::RunLoop().Run();
@@ -379,10 +448,20 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Query) {
ASSERT_TRUE(fetcher);
// Next error incurs a retry after 2 seconds.
- FakeOnURLFetchComplete(fetcher, net::HTTP_INTERNAL_SERVER_ERROR, "");
+ FakeOnURLFetchComplete(fetcher, net::HTTP_REQUEST_ENTITY_TOO_LARGE,
+ "<html></html>");
EXPECT_EQ(2U, responses_.size());
EXPECT_LT(download_manager_.fetcher_backoff_.GetTimeUntilRelease(),
base::TimeDelta::FromMilliseconds(2100));
+
+ // There should not be an additional retry.
+ fetcher = factory.GetFetcherByID(2);
+ ASSERT_FALSE(fetcher);
+ histogram.ExpectBucketCount("Autofill.Query.HttpResponseCode",
+ net::HTTP_REQUEST_ENTITY_TOO_LARGE, 1);
+ auto buckets = histogram.GetAllSamples("Autofill.Query.FailingPayloadSize");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_EQ(2, buckets[0].count);
}
TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) {
@@ -421,19 +500,19 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) {
ASSERT_TRUE(fetcher);
// Error incurs a retry after 1 second.
- FakeOnURLFetchComplete(fetcher, net::HTTP_NOT_FOUND, "<html></html>");
+ FakeOnURLFetchComplete(fetcher, net::HTTP_INTERNAL_SERVER_ERROR, "");
EXPECT_EQ(1U, responses_.size());
EXPECT_LT(download_manager_.fetcher_backoff_.GetTimeUntilRelease(),
base::TimeDelta::FromMilliseconds(1100));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
base::TimeDelta::FromMilliseconds(1100));
base::RunLoop().Run();
// Check that it was a failure.
EXPECT_EQ(AutofillDownloadManagerTest::REQUEST_UPLOAD_FAILED,
responses_.front().type_of_response);
- EXPECT_EQ(net::HTTP_NOT_FOUND, responses_.front().error);
+ EXPECT_EQ(net::HTTP_INTERNAL_SERVER_ERROR, responses_.front().error);
EXPECT_EQ(form_structure->FormSignatureAsStr(), responses_.front().signature);
// Expected response on non-query request is an empty string.
EXPECT_EQ(std::string(), responses_.front().response);
@@ -452,6 +531,21 @@ TEST_F(AutofillDownloadManagerTest, BackoffLogic_Upload) {
// Expected response on non-query request is an empty string.
EXPECT_EQ(std::string(), responses_.front().response);
responses_.pop_front();
+
+ // Validate no retry on sending a bad request.
+ base::HistogramTester histogram;
+ EXPECT_TRUE(download_manager_.StartUploadRequest(
+ *form_structure, true, ServerFieldTypeSet(), std::string(), true));
+ fetcher = factory.GetFetcherByID(2);
+ ASSERT_TRUE(fetcher);
+ FakeOnURLFetchComplete(fetcher, net::HTTP_REQUEST_ENTITY_TOO_LARGE, "");
+ fetcher = factory.GetFetcherByID(3);
+ ASSERT_FALSE(fetcher);
+ histogram.ExpectBucketCount("Autofill.Upload.HttpResponseCode",
+ net::HTTP_REQUEST_ENTITY_TOO_LARGE, 1);
+ auto buckets = histogram.GetAllSamples("Autofill.Upload.FailingPayloadSize");
+ ASSERT_EQ(1U, buckets.size());
+ EXPECT_EQ(1, buckets[0].count);
}
TEST_F(AutofillDownloadManagerTest, QueryTooManyFieldsTest) {
@@ -638,7 +732,7 @@ TEST_F(AutofillDownloadManagerTest, CacheQueryTest) {
EXPECT_EQ(responses[2], responses_.back().response);
responses_.clear();
- // The first structure should've expired.
+ // The first structure should have expired.
// Request with id 3.
EXPECT_TRUE(download_manager_.StartQueryRequest(
ToRawPointerVector(form_structures0)));
@@ -654,4 +748,120 @@ TEST_F(AutofillDownloadManagerTest, CacheQueryTest) {
EXPECT_EQ(responses[0], responses_.front().response);
}
+namespace {
+
+class AutofillQueryTest : public AutofillDownloadManager::Observer,
+ public testing::Test {
+ protected:
+ void SetUp() override {
+ scoped_feature_list_.InitAndEnableFeature(
+ features::kAutofillCacheQueryResponses);
+
+ // Setup the server.
+ server_.RegisterRequestHandler(base::BindRepeating(
+ &AutofillQueryTest::RequestHandler, base::Unretained(this)));
+ ASSERT_TRUE(server_.Start());
+
+ scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII(
+ switches::kAutofillServerURL,
+ server_.base_url().Resolve("/tbproxy/af/").spec().c_str());
+
+ // Intialize the autofill driver.
+ request_context_ = base::MakeRefCounted<net::TestURLRequestContextGetter>(
+ scoped_task_environment_.GetMainThreadTaskRunner());
+ driver_ = std::make_unique<TestAutofillDriver>();
+ driver_->SetURLRequestContext(request_context_.get());
+ }
+
+ void TearDown() override {
+ if (server_.Started())
+ ASSERT_TRUE(server_.ShutdownAndWaitUntilComplete());
+ }
+
+ // AutofillDownloadManager::Observer implementation.
+ void OnLoadedServerPredictions(
+ std::string /* response_xml */,
+ const std::vector<std::string>& /*form_signatures */) override {
+ ASSERT_TRUE(run_loop_);
+ run_loop_->QuitWhenIdle();
+ }
+
+ std::unique_ptr<HttpResponse> RequestHandler(const HttpRequest& request) {
+ GURL absolute_url = server_.GetURL(request.relative_url);
+ ++call_count_;
+
+ if (absolute_url.path() != "/tbproxy/af/query")
+ return nullptr;
+
+ AutofillQueryResponseContents proto;
+ proto.add_field()->set_overall_type_prediction(NAME_FIRST);
+
+ auto response = std::make_unique<BasicHttpResponse>();
+ response->set_code(net::HTTP_OK);
+ response->set_content(proto.SerializeAsString());
+ response->set_content_type("text/proto");
+ response->AddCustomHeader("Cache-Control", "max-age=86400");
+ return response;
+ }
+
+ void SendQueryRequest(
+ const std::vector<std::unique_ptr<FormStructure>>& form_structures) {
+ ASSERT_TRUE(run_loop_ == nullptr);
+ run_loop_ = std::make_unique<base::RunLoop>();
+
+ AutofillDownloadManager download_manager(driver_.get(), this);
+ ASSERT_TRUE(download_manager.StartQueryRequest(
+ ToRawPointerVector(form_structures)));
+ run_loop_->Run();
+ run_loop_.reset();
+ }
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_{
+ base::test::ScopedTaskEnvironment::MainThreadType::IO};
+ base::test::ScopedCommandLine scoped_command_line_;
+ base::test::ScopedFeatureList scoped_feature_list_;
+ EmbeddedTestServer server_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+ size_t call_count_ = 0;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+ std::unique_ptr<TestAutofillDriver> driver_;
+};
+
+} // namespace
+
+TEST_F(AutofillQueryTest, CacheableResponse) {
+ FormFieldData field;
+ field.label = ASCIIToUTF16("First Name:");
+ field.name = ASCIIToUTF16("firstname");
+ field.form_control_type = "text";
+
+ FormData form;
+ form.fields.push_back(field);
+
+ std::vector<std::unique_ptr<FormStructure>> form_structures;
+ form_structures.push_back(std::make_unique<FormStructure>(form));
+
+ // Query for the form. This should go to the embedded server.
+ {
+ SCOPED_TRACE("Firstl Query");
+ base::HistogramTester histogram;
+ ASSERT_NO_FATAL_FAILURE(SendQueryRequest(form_structures));
+ EXPECT_EQ(1u, call_count_);
+ histogram.ExpectBucketCount("Autofill.ServerQueryResponse",
+ AutofillMetrics::QUERY_SENT, 1);
+ histogram.ExpectBucketCount("Autofill.Query.Method", METHOD_GET, 1);
+ histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_MISS, 1);
+ }
+
+ // Query again for the form. This should go to the local cache.
+ {
+ SCOPED_TRACE("Second Query");
+ base::HistogramTester histogram;
+ ASSERT_NO_FATAL_FAILURE(SendQueryRequest(form_structures));
+ EXPECT_EQ(1u, call_count_);
+ histogram.ExpectBucketCount("Autofill.Query.Method", METHOD_GET, 1);
+ histogram.ExpectBucketCount("Autofill.Query.WasInCache", CACHE_HIT, 1);
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_driver.h b/chromium/components/autofill/core/browser/autofill_driver.h
index 5422060f529..2ed290d3321 100644
--- a/chromium/components/autofill/core/browser/autofill_driver.h
+++ b/chromium/components/autofill/core/browser/autofill_driver.h
@@ -68,8 +68,8 @@ class AutofillDriver {
virtual void RendererShouldAcceptDataListSuggestion(
const base::string16& value) = 0;
- // Tells the renderer to clear the currently filled Autofill results.
- virtual void RendererShouldClearFilledForm() = 0;
+ // Tells the renderer to clear the current section of the autofilled values.
+ virtual void RendererShouldClearFilledSection() = 0;
// Tells the renderer to clear the currently previewed Autofill results.
virtual void RendererShouldClearPreviewedForm() = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.cc b/chromium/components/autofill/core/browser/autofill_experiments.cc
index 2c56d295aca..04b3b3afa52 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments.cc
@@ -6,13 +6,13 @@
#include "base/command_line.h"
#include "base/feature_list.h"
-#include "base/metrics/field_trial.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/suggestion.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_service.h"
@@ -28,8 +28,6 @@ namespace autofill {
const base::Feature kAutofillAlwaysFillAddresses{
"AlwaysFillAddresses", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kAutofillAutoDismissableUpstreamBubble{
- "AutofillAutoDismissableUpstreamBubble", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillCreateDataForTest{
"AutofillCreateDataForTest", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillCreditCardAssist{
@@ -55,14 +53,16 @@ const base::Feature kAutofillPreferServerNamePredictions{
const base::Feature kAutofillRationalizeFieldTypePredictions{
"AutofillRationalizeFieldTypePredictions",
base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kAutofillSuggestInvalidProfileData{
+ "AutofillSuggestInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kAutofillSuppressDisusedAddresses{
"AutofillSuppressDisusedAddresses", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kAutofillSuppressDisusedCreditCards{
"AutofillSuppressDisusedCreditCards", base::FEATURE_ENABLED_BY_DEFAULT};
+const base::Feature kAutofillUpstream{"AutofillUpstream",
+ base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillUpstreamAllowAllEmailDomains{
"AutofillUpstreamAllowAllEmailDomains", base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kAutofillUpstreamRequestCvcIfMissing{
- "AutofillUpstreamRequestCvcIfMissing", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kAutofillUpstreamSendDetectedValues{
"AutofillUpstreamSendDetectedValues", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kAutofillUpstreamSendPanFirstSix{
@@ -70,6 +70,8 @@ const base::Feature kAutofillUpstreamSendPanFirstSix{
const base::Feature kAutofillUpstreamUpdatePromptExplanation{
"AutofillUpstreamUpdatePromptExplanation",
base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kAutofillVoteUsingInvalidProfileData{
+ "AutofillVoteUsingInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT};
const char kCreditCardSigninPromoImpressionLimitParamKey[] = "impression_limit";
const char kAutofillCreditCardPopupBackgroundColorKey[] = "background_color";
@@ -85,10 +87,8 @@ const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[] =
"show_expiration_date";
#if defined(OS_MACOSX)
-const base::Feature kCreditCardAutofillTouchBar{
- "CreditCardAutofillTouchBar", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kMacViewsAutofillPopup{"MacViewsAutofillPopup",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
#endif // defined(OS_MACOSX)
namespace {
@@ -129,10 +129,6 @@ bool IsAutofillCreditCardPopupLayoutExperimentEnabled() {
return base::FeatureList::IsEnabled(kAutofillCreditCardPopupLayout);
}
-bool IsAutofillAutoDismissableUpstreamBubbleExperimentEnabled() {
- return base::FeatureList::IsEnabled(kAutofillAutoDismissableUpstreamBubble);
-}
-
bool IsAutofillCreditCardLastUsedDateDisplayExperimentEnabled() {
return base::FeatureList::IsEnabled(kAutofillCreditCardLastUsedDateDisplay);
}
@@ -230,27 +226,28 @@ bool OfferStoreUnmaskedCards() {
bool IsCreditCardUploadEnabled(const PrefService* pref_service,
const syncer::SyncService* sync_service,
const std::string& user_email) {
- // Query the field trial first to ensure UMA always reports the correct group.
- std::string group_name =
- base::FieldTrialList::FindFullName("OfferUploadCreditCards");
-
// Check Autofill sync setting.
if (!(sync_service && sync_service->CanSyncStart() &&
sync_service->GetPreferredDataTypes().Has(syncer::AUTOFILL_PROFILE))) {
return false;
}
- // Check if the upload to Google state is active. This also returns false for
- // users that have a secondary passphrase. Users who have enabled a passphrase
- // have chosen to not make their sync information accessible to Google. Since
- // upload makes credit card data available to other Google systems, disable it
- // for passphrase users.
- if (syncer::GetUploadToGoogleState(sync_service,
+ // Check if the upload to Google state is active.
+ if (!base::FeatureList::IsEnabled(
+ features::kAutofillEnablePaymentsInteractionsOnAuthError) &&
+ syncer::GetUploadToGoogleState(sync_service,
syncer::ModelType::AUTOFILL_WALLET_DATA) !=
- syncer::UploadState::ACTIVE) {
+ syncer::UploadState::ACTIVE) {
return false;
}
+ // Also don't offer upload for users that have a secondary sync passphrase.
+ // Users who have enabled a passphrase have chosen to not make their sync
+ // information accessible to Google. Since upload makes credit card data
+ // available to other Google systems, disable it for passphrase users.
+ if (sync_service->IsUsingSecondaryPassphrase())
+ return false;
+
// Check Payments integration user setting.
if (!pref_service->GetBoolean(prefs::kAutofillWalletImportEnabled))
return false;
@@ -268,26 +265,7 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service,
return false;
}
- // With the user settings and logged in state verified, now we can consult the
- // command-line flags and experiment settings.
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableOfferUploadCreditCards)) {
- return true;
- }
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableOfferUploadCreditCards)) {
- return false;
- }
-
- return !group_name.empty() && group_name != "Disabled";
-}
-
-bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled() {
-#if defined(OS_ANDROID)
- return false;
-#else
- return base::FeatureList::IsEnabled(kAutofillUpstreamRequestCvcIfMissing);
-#endif
+ return base::FeatureList::IsEnabled(kAutofillUpstream);
}
bool IsAutofillUpstreamSendDetectedValuesExperimentEnabled() {
@@ -303,13 +281,9 @@ bool IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled() {
}
#if defined(OS_MACOSX)
-bool IsCreditCardAutofillTouchBarExperimentEnabled() {
- return base::FeatureList::IsEnabled(kCreditCardAutofillTouchBar);
-}
-
bool IsMacViewsAutofillPopupExperimentEnabled() {
#if BUILDFLAG(MAC_VIEWS_BROWSER)
- if (!features::IsViewsBrowserCocoa())
+ if (!::features::IsViewsBrowserCocoa())
return true;
#endif
diff --git a/chromium/components/autofill/core/browser/autofill_experiments.h b/chromium/components/autofill/core/browser/autofill_experiments.h
index 34ee51c1b7b..8a603e29765 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments.h
+++ b/chromium/components/autofill/core/browser/autofill_experiments.h
@@ -26,7 +26,6 @@ namespace autofill {
struct Suggestion;
extern const base::Feature kAutofillAlwaysFillAddresses;
-extern const base::Feature kAutofillAutoDismissableUpstreamBubble;
extern const base::Feature kAutofillCreateDataForTest;
extern const base::Feature kAutofillCreditCardAssist;
extern const base::Feature kAutofillScanCardholderName;
@@ -39,19 +38,20 @@ extern const base::Feature kAutofillDeleteDisusedCreditCards;
extern const base::Feature kAutofillExpandedPopupViews;
extern const base::Feature kAutofillPreferServerNamePredictions;
extern const base::Feature kAutofillRationalizeFieldTypePredictions;
+extern const base::Feature kAutofillSuggestInvalidProfileData;
extern const base::Feature kAutofillSuppressDisusedAddresses;
extern const base::Feature kAutofillSuppressDisusedCreditCards;
+extern const base::Feature kAutofillUpstream;
extern const base::Feature kAutofillUpstreamAllowAllEmailDomains;
-extern const base::Feature kAutofillUpstreamRequestCvcIfMissing;
extern const base::Feature kAutofillUpstreamSendDetectedValues;
extern const base::Feature kAutofillUpstreamSendPanFirstSix;
extern const base::Feature kAutofillUpstreamUpdatePromptExplanation;
+extern const base::Feature kAutofillVoteUsingInvalidProfileData;
extern const char kCreditCardSigninPromoImpressionLimitParamKey[];
extern const char kAutofillCreditCardLastUsedDateShowExpirationDateKey[];
extern const char kAutofillUpstreamMaxMinutesSinceAutofillProfileUseKey[];
#if defined(OS_MACOSX)
-extern const base::Feature kCreditCardAutofillTouchBar;
extern const base::Feature kMacViewsAutofillPopup;
#endif // defined(OS_MACOSX)
@@ -84,10 +84,6 @@ bool IsCreditCardUploadEnabled(const PrefService* pref_service,
// enabled.
bool IsAutofillCreditCardPopupLayoutExperimentEnabled();
-// Returns whether the experiment to make the credit card Upstream bubble non
-// sticky is enabled.
-bool IsAutofillAutoDismissableUpstreamBubbleExperimentEnabled();
-
// Returns whether Autofill credit card last used date display experiment is
// enabled.
bool IsAutofillCreditCardLastUsedDateDisplayExperimentEnabled();
@@ -130,10 +126,6 @@ void ModifyAutofillCreditCardSuggestion(struct Suggestion* suggestion);
// layout.
unsigned int GetPopupMargin();
-// Returns whether the experiment is enabled where Chrome Upstream requests CVC
-// in the offer to save bubble if it was not detected during the checkout flow.
-bool IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled();
-
// Returns whether the experiment is enabled where Chrome Upstream always checks
// to see if it can offer to save (even though some data like name, address, and
// CVC might be missing) by sending metadata on what form values were detected
@@ -151,9 +143,6 @@ bool IsAutofillUpstreamSendPanFirstSixExperimentEnabled();
bool IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled();
#if defined(OS_MACOSX)
-// Returns whether the Credit Card Autofill Touch Bar experiment is enabled.
-bool IsCreditCardAutofillTouchBarExperimentEnabled();
-
// Returns true if whether the views autofill popup feature is enabled or the
// we're using the views browser.
bool IsMacViewsAutofillPopupExperimentEnabled();
diff --git a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
index 97b7ab3e1e7..36bb8b727f6 100644
--- a/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_experiments_unittest.cc
@@ -4,11 +4,9 @@
#include "components/autofill/core/browser/autofill_experiments.h"
-#include "base/test/scoped_command_line.h"
#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/browser/test_sync_service.h"
#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,19 +24,10 @@ class AutofillExperimentsTest : public testing::Test {
}
bool IsCreditCardUploadEnabled() {
- return IsCreditCardUploadEnabled("john.smith@gmail.com", "Default");
+ return IsCreditCardUploadEnabled("john.smith@gmail.com");
}
bool IsCreditCardUploadEnabled(const std::string& user_email) {
- return IsCreditCardUploadEnabled(user_email, "Default");
- }
-
- bool IsCreditCardUploadEnabled(const std::string& user_email,
- const std::string& field_trial_value) {
- base::FieldTrialList field_trial_list(nullptr);
- base::FieldTrialList::CreateFieldTrial("OfferUploadCreditCards",
- field_trial_value);
-
return autofill::IsCreditCardUploadEnabled(&pref_service_, &sync_service_,
user_email);
}
@@ -48,49 +37,68 @@ class AutofillExperimentsTest : public testing::Test {
TestSyncService sync_service_;
};
+TEST_F(AutofillExperimentsTest, DenyUpload_FeatureEnabled) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
+ EXPECT_TRUE(IsCreditCardUploadEnabled());
+}
+
+TEST_F(AutofillExperimentsTest, DenyUpload_FeatureDisabled) {
+ scoped_feature_list_.InitAndDisableFeature(kAutofillUpstream);
+ EXPECT_FALSE(IsCreditCardUploadEnabled());
+}
+
TEST_F(AutofillExperimentsTest, DenyUpload_SyncServiceCannotStart) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
sync_service_.SetCanSyncStart(false);
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest, DenyUpload_AuthError) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
sync_service_.SetInAuthError(true);
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest,
DenyUpload_SyncServiceDoesNotHaveAutofillProfilePreferredDataType) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
sync_service_.SetPreferredDataTypes(syncer::ModelTypeSet());
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest, DenyUpload_SyncCycleNotComplete) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
sync_service_.SetSyncCycleComplete(false);
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest, DenyUpload_SyncConfigurationNotDone) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
sync_service_.SetConfigurationDone(false);
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest,
DenyUpload_SyncServiceUsingSecondaryPassphrase) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
sync_service_.SetIsUsingSecondaryPassphrase(true);
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest,
DenyUpload_AutofillWalletImportEnabledPrefIsDisabled) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
pref_service_.SetBoolean(prefs::kAutofillWalletImportEnabled, false);
EXPECT_FALSE(IsCreditCardUploadEnabled());
}
TEST_F(AutofillExperimentsTest, DenyUpload_EmptyUserEmail) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
EXPECT_FALSE(IsCreditCardUploadEnabled(""));
}
TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com"));
EXPECT_TRUE(IsCreditCardUploadEnabled("googler@google.com"));
EXPECT_TRUE(IsCreditCardUploadEnabled("old.school@googlemail.com"));
@@ -98,6 +106,7 @@ TEST_F(AutofillExperimentsTest, AllowUpload_UserEmailWithGoogleDomain) {
}
TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) {
+ scoped_feature_list_.InitAndEnableFeature(kAutofillUpstream);
EXPECT_FALSE(IsCreditCardUploadEnabled("cool.user@hotmail.com"));
EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@johnsmith.com"));
EXPECT_FALSE(IsCreditCardUploadEnabled("fake.googler@google.net"));
@@ -106,39 +115,12 @@ TEST_F(AutofillExperimentsTest, DenyUpload_UserEmailWithNonGoogleDomain) {
TEST_F(AutofillExperimentsTest,
AllowUpload_UserEmailWithNonGoogleDomainIfExperimentEnabled) {
- scoped_feature_list_.InitAndEnableFeature(
- kAutofillUpstreamAllowAllEmailDomains);
+ scoped_feature_list_.InitWithFeatures(
+ {kAutofillUpstream, kAutofillUpstreamAllowAllEmailDomains}, {});
EXPECT_TRUE(IsCreditCardUploadEnabled("cool.user@hotmail.com"));
EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@johnsmith.com"));
EXPECT_TRUE(IsCreditCardUploadEnabled("fake.googler@google.net"));
EXPECT_TRUE(IsCreditCardUploadEnabled("fake.committer@chromium.com"));
}
-TEST_F(AutofillExperimentsTest,
- AllowUpload_CommandLineSwitchOnEvenIfGroupDisabled) {
- base::test::ScopedCommandLine scoped_command_line;
- scoped_command_line.GetProcessCommandLine()->AppendSwitch(
- switches::kEnableOfferUploadCreditCards);
- EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Disabled"));
-}
-
-TEST_F(AutofillExperimentsTest, DenyUpload_CommandLineSwitchOff) {
- base::test::ScopedCommandLine scoped_command_line;
- scoped_command_line.GetProcessCommandLine()->AppendSwitch(
- switches::kDisableOfferUploadCreditCards);
- EXPECT_FALSE(IsCreditCardUploadEnabled());
-}
-
-TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameEmpty) {
- EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@gmail.com", ""));
-}
-
-TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameDisabled) {
- EXPECT_FALSE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Disabled"));
-}
-
-TEST_F(AutofillExperimentsTest, DenyUpload_GroupNameAnythingButDisabled) {
- EXPECT_TRUE(IsCreditCardUploadEnabled("john.smith@gmail.com", "Enabled"));
-}
-
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.cc b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
index 445ba1f9035..f49a26785b2 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.cc
@@ -10,8 +10,8 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
-#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -34,9 +34,7 @@ namespace {
// Returns true if the suggestion entry is an Autofill warning message.
// Warning messages should display on top of suggestion list.
bool IsAutofillWarningEntry(int frontend_id) {
- return frontend_id ==
- POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE ||
- frontend_id == POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE;
+ return frontend_id == POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE;
}
} // namespace
@@ -49,7 +47,7 @@ AutofillExternalDelegate::AutofillExternalDelegate(AutofillManager* manager,
has_autofill_suggestions_(false),
has_shown_popup_for_current_edit_(false),
should_show_scan_credit_card_(false),
- is_credit_card_popup_(false),
+ popup_type_(PopupType::kUnspecified),
should_show_cc_signin_promo_(false),
weak_ptr_factory_(this) {
DCHECK(manager);
@@ -70,8 +68,7 @@ void AutofillExternalDelegate::OnQuery(int query_id,
element_bounds_ = element_bounds;
should_show_scan_credit_card_ =
manager_->ShouldShowScanCreditCard(query_form_, query_field_);
- is_credit_card_popup_ =
- manager_->IsCreditCardPopup(query_form_, query_field_);
+ popup_type_ = manager_->GetPopupType(query_form_, query_field_);
should_show_cc_signin_promo_ =
manager_->ShouldShowCreditCardSigninPromo(query_form_, query_field_);
}
@@ -90,8 +87,11 @@ void AutofillExternalDelegate::OnSuggestionsReturned(
#if !defined(OS_ANDROID)
// If there are above the fold suggestions at this point, add a separator to
- // go between the values and menu items.
- if (!suggestions.empty()) {
+ // go between the values and menu items. Skip this when using the Native Views
+ // implementation, which has its own logic for distinguishing footer rows.
+ // TODO(crbug.com/831603): Remove this when the relevant feature is on 100%.
+ if (!suggestions.empty() &&
+ !base::FeatureList::IsEnabled(autofill::kAutofillExpandedPopupViews)) {
suggestions.push_back(Suggestion());
suggestions.back().frontend_id = POPUP_ITEM_ID_SEPARATOR;
}
@@ -214,7 +214,7 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
manager_->ShowAutofillSettings();
} else if (identifier == POPUP_ITEM_ID_CLEAR_FORM) {
// User selected 'Clear form'.
- driver_->RendererShouldClearFilledForm();
+ driver_->RendererShouldClearFilledSection();
} else if (identifier == POPUP_ITEM_ID_PASSWORD_ENTRY ||
identifier == POPUP_ITEM_ID_USERNAME_ENTRY) {
NOTREACHED(); // Should be handled elsewhere.
@@ -227,8 +227,7 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value,
} else if (identifier == POPUP_ITEM_ID_SCAN_CREDIT_CARD) {
manager_->client()->ScanCreditCard(base::Bind(
&AutofillExternalDelegate::OnCreditCardScanned, GetWeakPtr()));
- } else if (identifier == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO ||
- identifier == POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE) {
+ } else if (identifier == POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO) {
manager_->client()->ExecuteCommand(identifier);
} else {
if (identifier > 0) // Denotes an Autofill suggestion.
@@ -278,8 +277,8 @@ void AutofillExternalDelegate::ClearPreviewedForm() {
driver_->RendererShouldClearPreviewedForm();
}
-bool AutofillExternalDelegate::IsCreditCardPopup() {
- return is_credit_card_popup_;
+PopupType AutofillExternalDelegate::GetPopupType() const {
+ return popup_type_;
}
AutofillDriver* AutofillExternalDelegate::GetAutofillDriver() {
@@ -411,6 +410,17 @@ void AutofillExternalDelegate::InsertDataListValues(
base::string16 AutofillExternalDelegate::GetSettingsSuggestionValue()
const {
+ if (base::FeatureList::IsEnabled(autofill::kAutofillExpandedPopupViews)) {
+ if (GetPopupType() == PopupType::kAddresses)
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_ADDRESSES);
+
+ if (GetPopupType() == PopupType::kCreditCards)
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE_PAYMENT_METHODS);
+
+ DCHECK_EQ(GetPopupType(), PopupType::kPersonalInformation);
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE);
+ }
+
return l10n_util::GetStringUTF16(
IsKeyboardAccessoryEnabled() ? IDS_AUTOFILL_OPTIONS_CONTENT_DESCRIPTION
: IDS_AUTOFILL_SETTINGS_POPUP);
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate.h b/chromium/components/autofill/core/browser/autofill_external_delegate.h
index d2669f6c483..3a5bff6edcd 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate.h
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate.h
@@ -52,9 +52,9 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
base::string16* body) override;
bool RemoveSuggestion(const base::string16& value, int identifier) override;
void ClearPreviewedForm() override;
- // Returns false for all popups prior to |onQuery|, true for credit card
- // popups after call to |onQuery|.
- bool IsCreditCardPopup() override;
+ // Returns PopupType::kUnspecified for all popups prior to |onQuery|, or the
+ // popup type after call to |onQuery|.
+ PopupType GetPopupType() const override;
AutofillDriver* GetAutofillDriver() override;
void RegisterDeletionCallback(base::OnceClosure deletion_callback) override;
@@ -152,7 +152,7 @@ class AutofillExternalDelegate : public AutofillPopupDelegate {
bool has_shown_popup_for_current_edit_;
bool should_show_scan_credit_card_;
- bool is_credit_card_popup_;
+ PopupType popup_type_;
// Whether the credit card signin promo should be shown to the user.
bool should_show_cc_signin_promo_;
diff --git a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index cb2b8fb00a1..226b25921be 100644
--- a/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -12,8 +12,10 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/user_action_tester.h"
#include "build/build_config.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_external_delegate.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/autofill_metrics.h"
@@ -51,7 +53,7 @@ class MockAutofillDriver : public TestAutofillDriver {
// Mock methods to enable testability.
MOCK_METHOD1(RendererShouldAcceptDataListSuggestion,
void(const base::string16&));
- MOCK_METHOD0(RendererShouldClearFilledForm, void());
+ MOCK_METHOD0(RendererShouldClearFilledSection, void());
MOCK_METHOD0(RendererShouldClearPreviewedForm, void());
MOCK_METHOD1(RendererShouldFillFieldWithValue, void(const base::string16&));
MOCK_METHOD1(RendererShouldPreviewFieldWithValue,
@@ -92,7 +94,12 @@ class MockAutofillManager : public AutofillManager {
// Force to use the constructor designated for unit test, but we don't
// really need personal_data in this test so we pass a NULL pointer.
: AutofillManager(driver, client, nullptr) {}
- virtual ~MockAutofillManager() {}
+ ~MockAutofillManager() override {}
+
+ PopupType GetPopupType(const FormData& form,
+ const FormFieldData& field) override {
+ return PopupType::kPersonalInformation;
+ }
MOCK_METHOD2(ShouldShowScanCreditCard,
bool(const FormData& form, const FormFieldData& field));
@@ -495,13 +502,11 @@ TEST_F(AutofillExternalDelegateUnitTest,
// This should call ShowAutofillPopup.
std::vector<Suggestion> suggestions;
suggestions.push_back(Suggestion());
- suggestions[0].frontend_id = POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE;
- suggestions.push_back(Suggestion());
- suggestions[1].frontend_id =
+ suggestions[0].frontend_id =
POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE;
suggestions.push_back(Suggestion());
- suggestions[2].value = ASCIIToUTF16("Rick");
- suggestions[2].frontend_id = POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY;
+ suggestions[1].value = ASCIIToUTF16("Rick");
+ suggestions[1].frontend_id = POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY;
external_delegate_->OnSuggestionsReturned(kQueryId, suggestions);
}
@@ -586,7 +591,7 @@ TEST_F(AutofillExternalDelegateUnitTest,
// the user accepted the suggestion to clear the form.
TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearForm) {
EXPECT_CALL(autofill_client_, HideAutofillPopup());
- EXPECT_CALL(*autofill_driver_, RendererShouldClearFilledForm());
+ EXPECT_CALL(*autofill_driver_, RendererShouldClearFilledSection());
external_delegate_->DidAcceptSuggestion(base::string16(),
POPUP_ITEM_ID_CLEAR_FORM,
@@ -675,17 +680,6 @@ TEST_F(AutofillExternalDelegateUnitTest, SigninPromoMenuItem) {
base::string16(), POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO, 0);
}
-// Test that autofill client will open the security indicator help center url
-// after the user accepted the http warning message suggestion item.
-TEST_F(AutofillExternalDelegateUnitTest, HttpWarningMessageItem) {
- EXPECT_CALL(
- autofill_client_,
- ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
- EXPECT_CALL(autofill_client_, HideAutofillPopup());
- external_delegate_->DidAcceptSuggestion(
- base::string16(), POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE, 0);
-}
-
MATCHER_P(CreditCardMatches, card, "") {
return !arg.Compare(card);
}
@@ -794,4 +788,45 @@ TEST_F(AutofillExternalDelegateUnitTest, ShouldUseNewSettingName) {
external_delegate_->OnSuggestionsReturned(kQueryId, autofill_item);
}
+#if !defined(OS_ANDROID)
+// Test that the delegate includes a separator between the content rows and the
+// footer, if and only if the kAutofillExpandedPopupViews feature is disabled.
+TEST_F(AutofillExternalDelegateUnitTest, IncludeFooterSeparatorForOldUIOnly) {
+ // The guts of the test. This will be run once with the feature enabled,
+ // expecting not to find a separator, and a second time with the feature
+ // disabled, expecting to find a separator.
+ auto tester = [this](bool enabled, auto element_ids) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ if (enabled) {
+ scoped_feature_list.InitAndEnableFeature(
+ autofill::kAutofillExpandedPopupViews);
+ } else {
+ scoped_feature_list.InitAndDisableFeature(
+ autofill::kAutofillExpandedPopupViews);
+ }
+
+ IssueOnQuery(kQueryId);
+
+ EXPECT_CALL(
+ autofill_client_,
+ ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), _));
+
+ std::vector<Suggestion> autofill_item;
+ autofill_item.push_back(Suggestion());
+ autofill_item[0].frontend_id = kAutofillProfileId;
+ external_delegate_->OnSuggestionsReturned(kQueryId, autofill_item);
+ };
+
+ tester(false,
+ testing::ElementsAre(
+ kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
+ static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)));
+
+ tester(true, testing::ElementsAre(
+ kAutofillProfileId,
+ static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS)));
+}
+#endif // !defined(OS_ANDROID)
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_field.cc b/chromium/components/autofill/core/browser/autofill_field.cc
index 40b92446559..b1c931f73f9 100644
--- a/chromium/components/autofill/core/browser/autofill_field.cc
+++ b/chromium/components/autofill/core/browser/autofill_field.cc
@@ -9,15 +9,15 @@
#include "base/feature_list.h"
#include "base/strings/string_number_conversions.h"
#include "components/autofill/core/browser/autofill_experiments.h"
-#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/proto/server.pb.h"
namespace autofill {
AutofillField::AutofillField()
- : overall_server_type_(NO_SERVER_DATA),
+ : server_type_(NO_SERVER_DATA),
heuristic_type_(UNKNOWN_TYPE),
+ overall_type_(AutofillType(NO_SERVER_DATA)),
html_type_(HTML_TYPE_UNSPECIFIED),
html_mode_(HTML_MODE_NONE),
phone_part_(IGNORED),
@@ -27,14 +27,15 @@ AutofillField::AutofillField()
generation_type_(AutofillUploadContents::Field::NO_GENERATION),
generated_password_changed_(false),
form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME),
- username_vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {}
+ vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {}
AutofillField::AutofillField(const FormFieldData& field,
const base::string16& unique_name)
: FormFieldData(field),
unique_name_(unique_name),
- overall_server_type_(NO_SERVER_DATA),
+ server_type_(NO_SERVER_DATA),
heuristic_type_(UNKNOWN_TYPE),
+ overall_type_(AutofillType(NO_SERVER_DATA)),
html_type_(HTML_TYPE_UNSPECIFIED),
html_mode_(HTML_MODE_NONE),
phone_part_(IGNORED),
@@ -45,7 +46,7 @@ AutofillField::AutofillField(const FormFieldData& field,
generation_type_(AutofillUploadContents::Field::NO_GENERATION),
generated_password_changed_(false),
form_classifier_outcome_(AutofillUploadContents::Field::NO_OUTCOME),
- username_vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {}
+ vote_type_(AutofillUploadContents::Field::NO_INFORMATION) {}
AutofillField::~AutofillField() {}
@@ -59,19 +60,22 @@ void AutofillField::set_heuristic_type(ServerFieldType type) {
// implications on data uploaded to the server, better safe than sorry.
heuristic_type_ = UNKNOWN_TYPE;
}
+ overall_type_ = AutofillType(NO_SERVER_DATA);
}
-void AutofillField::set_overall_server_type(ServerFieldType type) {
+void AutofillField::set_server_type(ServerFieldType type) {
// Chrome no longer supports fax numbers, but the server still does.
if (type >= PHONE_FAX_NUMBER && type <= PHONE_FAX_WHOLE_NUMBER)
return;
- overall_server_type_ = type;
+ server_type_ = type;
+ overall_type_ = AutofillType(NO_SERVER_DATA);
}
void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) {
html_type_ = type;
html_mode_ = mode;
+ overall_type_ = AutofillType(NO_SERVER_DATA);
if (type == HTML_TYPE_TEL_LOCAL_PREFIX)
phone_part_ = PHONE_PREFIX;
@@ -81,25 +85,19 @@ void AutofillField::SetHtmlType(HtmlFieldType type, HtmlFieldMode mode) {
phone_part_ = IGNORED;
}
-void AutofillField::SetTypeTo(ServerFieldType type) {
- if (type == UNKNOWN_TYPE || type == NO_SERVER_DATA) {
- heuristic_type_ = UNKNOWN_TYPE;
- overall_server_type_ = NO_SERVER_DATA;
- } else if (overall_server_type_ == NO_SERVER_DATA) {
- heuristic_type_ = type;
- } else {
- overall_server_type_ = type;
- }
+void AutofillField::SetTypeTo(const AutofillType& type) {
+ DCHECK(type.GetStorableType() != NO_SERVER_DATA);
+ overall_type_ = type;
}
-AutofillType AutofillField::Type() const {
+AutofillType AutofillField::ComputedType() const {
// If autocomplete=tel/tel-* and server confirms it really is a phone field,
// we always user the server prediction as html types are not very reliable.
if ((GroupTypeOfHtmlFieldType(html_type_, html_mode_) == PHONE_BILLING ||
GroupTypeOfHtmlFieldType(html_type_, html_mode_) == PHONE_HOME) &&
- (GroupTypeOfServerFieldType(overall_server_type_) == PHONE_BILLING ||
- GroupTypeOfServerFieldType(overall_server_type_) == PHONE_HOME)) {
- return AutofillType(overall_server_type_);
+ (GroupTypeOfServerFieldType(server_type_) == PHONE_BILLING ||
+ GroupTypeOfServerFieldType(server_type_) == PHONE_HOME)) {
+ return AutofillType(server_type_);
}
// Use the html type specified by the website unless it is unrecognized and
@@ -109,7 +107,7 @@ AutofillType AutofillField::Type() const {
return AutofillType(html_type_, html_mode_);
}
- if (overall_server_type_ != NO_SERVER_DATA) {
+ if (server_type_ != NO_SERVER_DATA) {
// Sometimes the server and heuristics disagree on whether a name field
// should be associated with an address or a credit card. There was a
// decision to prefer the heuristics in these cases, but it looks like
@@ -119,29 +117,35 @@ AutofillType AutofillField::Type() const {
if (base::FeatureList::IsEnabled(kAutofillPreferServerNamePredictions)) {
believe_server = true;
} else {
- believe_server = !(overall_server_type_ == NAME_FULL &&
+ believe_server = !(server_type_ == NAME_FULL &&
heuristic_type_ == CREDIT_CARD_NAME_FULL) &&
- !(overall_server_type_ == CREDIT_CARD_NAME_FULL &&
+ !(server_type_ == CREDIT_CARD_NAME_FULL &&
heuristic_type_ == NAME_FULL) &&
- !(overall_server_type_ == NAME_FIRST &&
+ !(server_type_ == NAME_FIRST &&
heuristic_type_ == CREDIT_CARD_NAME_FIRST) &&
- !(overall_server_type_ == NAME_LAST &&
+ !(server_type_ == NAME_LAST &&
heuristic_type_ == CREDIT_CARD_NAME_LAST);
}
// Either way, retain a preference for the the CVC heuristic over the
// server's password predictions (http://crbug.com/469007)
- believe_server =
- believe_server &&
- !(AutofillType(overall_server_type_).group() == PASSWORD_FIELD &&
- heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
+ believe_server = believe_server &&
+ !(AutofillType(server_type_).group() == PASSWORD_FIELD &&
+ heuristic_type_ == CREDIT_CARD_VERIFICATION_CODE);
if (believe_server)
- return AutofillType(overall_server_type_);
+ return AutofillType(server_type_);
}
return AutofillType(heuristic_type_);
}
+AutofillType AutofillField::Type() const {
+ if (overall_type_.GetStorableType() != NO_SERVER_DATA) {
+ return overall_type_;
+ }
+ return ComputedType();
+}
+
bool AutofillField::IsEmpty() const {
return value.empty();
}
@@ -159,7 +163,7 @@ bool AutofillField::IsFieldFillable() const {
}
bool AutofillField::IsCreditCardPrediction() const {
- return AutofillType(overall_server_type_).group() == CREDIT_CARD ||
+ return AutofillType(server_type_).group() == CREDIT_CARD ||
AutofillType(heuristic_type_).group() == CREDIT_CARD;
}
diff --git a/chromium/components/autofill/core/browser/autofill_field.h b/chromium/components/autofill/core/browser/autofill_field.h
index e2bfce32763..5b40d57b1b3 100644
--- a/chromium/components/autofill/core/browser/autofill_field.h
+++ b/chromium/components/autofill/core/browser/autofill_field.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/proto/server.pb.h"
#include "components/autofill/core/common/form_field_data.h"
@@ -18,8 +19,6 @@
namespace autofill {
-class AutofillType;
-
class AutofillField : public FormFieldData {
public:
enum PhonePart {
@@ -34,9 +33,8 @@ class AutofillField : public FormFieldData {
const base::string16& unique_name() const { return unique_name_; }
- const std::string& section() const { return section_; }
ServerFieldType heuristic_type() const { return heuristic_type_; }
- ServerFieldType overall_server_type() const { return overall_server_type_; }
+ ServerFieldType server_type() const { return server_type_; }
const std::vector<AutofillQueryResponseContents::Field::FieldPrediction>&
server_predictions() const {
return server_predictions_;
@@ -49,10 +47,9 @@ class AutofillField : public FormFieldData {
const base::string16& parseable_name() const { return parseable_name_; }
bool only_fill_when_focused() const { return only_fill_when_focused_; }
- // Setters for the detected type and section for this field.
- void set_section(const std::string& section) { section_ = section; }
+ // Setters for the detected types.
void set_heuristic_type(ServerFieldType type);
- void set_overall_server_type(ServerFieldType type);
+ void set_server_type(ServerFieldType type);
void set_server_predictions(
const std::vector<AutofillQueryResponseContents::Field::FieldPrediction>
predictions) {
@@ -73,14 +70,27 @@ class AutofillField : public FormFieldData {
only_fill_when_focused_ = fill_when_focused;
}
- // Set the heuristic or server type, depending on whichever is currently
- // assigned, to |type|.
- void SetTypeTo(ServerFieldType type);
+ // Set the type of the field. This sets the value returned by |Type|.
+ // This function can be used to override the value that would be returned by
+ // |ComputedType|.
+ // As the |type| is expected to depend on |ComputedType|, the value will be
+ // reset to |ComputedType| if some internal value change (e.g. on call to
+ // (|set_heuristic_type| or |set_server_type|).
+ // |SetTypeTo| cannot be called with
+ // type.GetStoreableType() == NO_SERVER_DATA.
+ void SetTypeTo(const AutofillType& type);
- // This function automatically chooses between server and heuristic autofill
- // type, depending on the data available.
+ // This function returns |ComputedType| unless the value has been overriden
+ // by |SetTypeTo|.
+ // (i.e. overall_type_ != NO_SERVER_DATA ? overall_type_ : ComputedType())
AutofillType Type() const;
+ // This function automatically chooses between server and heuristic autofill
+ // type, depending on the data available for this field alone.
+ // This type does not take into account the rationalization involving the
+ // surrounding fields.
+ AutofillType ComputedType() const;
+
// Returns true if the value of this field is empty.
bool IsEmpty() const;
@@ -130,12 +140,11 @@ class AutofillField : public FormFieldData {
return form_classifier_outcome_;
}
- void set_username_vote_type(
- AutofillUploadContents::Field::UsernameVoteType type) {
- username_vote_type_ = type;
+ void set_vote_type(AutofillUploadContents::Field::VoteType type) {
+ vote_type_ = type;
}
- AutofillUploadContents::Field::UsernameVoteType username_vote_type() const {
- return username_vote_type_;
+ AutofillUploadContents::Field::VoteType vote_type() const {
+ return vote_type_;
}
private:
@@ -145,21 +154,23 @@ class AutofillField : public FormFieldData {
// The unique name of this field, generated by Autofill.
base::string16 unique_name_;
- // The unique identifier for the section (e.g. billing vs. shipping address)
- // that this field belongs to.
- std::string section_;
-
// The type of the field, as determined by the Autofill server.
- ServerFieldType overall_server_type_;
+ ServerFieldType server_type_;
// The possible types of the field, as determined by the Autofill server,
- // including |overall_server_type_| as the first item.
+ // including |server_type_| as the first item.
std::vector<AutofillQueryResponseContents::Field::FieldPrediction>
server_predictions_;
// The type of the field, as determined by the local heuristics.
ServerFieldType heuristic_type_;
+ // The type of the field. Overrides all other types (html_type_,
+ // heuristic_type_, server_type_).
+ // |AutofillType(NO_SERVER_DATA)| is used when this |overall_type_| has not
+ // been set.
+ AutofillType overall_type_;
+
// The type of the field, as specified by the site author in HTML.
HtmlFieldType html_type_;
@@ -200,9 +211,10 @@ class AutofillField : public FormFieldData {
// The outcome of HTML parsing based form classifier.
AutofillUploadContents::Field::FormClassifierOutcome form_classifier_outcome_;
- // The username vote type, if the autofill type is USERNAME. Otherwise, the
- // field is ignored.
- AutofillUploadContents::Field::UsernameVoteType username_vote_type_;
+ // The vote type, if the autofill type is USERNAME or any password vote.
+ // Otherwise, the field is ignored. |vote_type_| provides context as to what
+ // triggered the vote.
+ AutofillUploadContents::Field::VoteType vote_type_;
DISALLOW_COPY_AND_ASSIGN(AutofillField);
};
diff --git a/chromium/components/autofill/core/browser/autofill_handler.cc b/chromium/components/autofill/core/browser/autofill_handler.cc
index 4e3c8f701d1..89a5c7a5970 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler.cc
@@ -15,13 +15,12 @@ AutofillHandler::AutofillHandler(AutofillDriver* driver) : driver_(driver) {}
AutofillHandler::~AutofillHandler() {}
-bool AutofillHandler::OnFormSubmitted(const FormData& form,
+void AutofillHandler::OnFormSubmitted(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) {
- if (!IsValidFormData(form))
- return false;
- return OnFormSubmittedImpl(form, known_success, source, timestamp);
+ if (IsValidFormData(form))
+ OnFormSubmittedImpl(form, known_success, source, timestamp);
}
void AutofillHandler::OnTextFieldDidChange(const FormData& form,
diff --git a/chromium/components/autofill/core/browser/autofill_handler.h b/chromium/components/autofill/core/browser/autofill_handler.h
index a52849718db..b6592b1cfd7 100644
--- a/chromium/components/autofill/core/browser/autofill_handler.h
+++ b/chromium/components/autofill/core/browser/autofill_handler.h
@@ -65,8 +65,8 @@ class AutofillHandler {
// Invoked when |form| has been submitted.
// Processes the submitted |form|, saving any new Autofill data to the user's
- // personal profile. Returns false if this form is not relevant for Autofill.
- bool OnFormSubmitted(const FormData& form,
+ // personal profile.
+ void OnFormSubmitted(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp);
@@ -110,7 +110,7 @@ class AutofillHandler {
protected:
AutofillHandler(AutofillDriver* driver);
- virtual bool OnFormSubmittedImpl(const FormData& form,
+ virtual void OnFormSubmittedImpl(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
index 0b35d36292e..eee6adc468d 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.cc
@@ -16,12 +16,11 @@ AutofillHandlerProxy::AutofillHandlerProxy(AutofillDriver* driver,
AutofillHandlerProxy::~AutofillHandlerProxy() {}
-bool AutofillHandlerProxy::OnFormSubmittedImpl(const FormData& form,
+void AutofillHandlerProxy::OnFormSubmittedImpl(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) {
- return provider_->OnFormSubmitted(this, form, known_success, source,
- timestamp);
+ provider_->OnFormSubmitted(this, form, known_success, source, timestamp);
}
void AutofillHandlerProxy::OnTextFieldDidChangeImpl(
diff --git a/chromium/components/autofill/core/browser/autofill_handler_proxy.h b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
index 6f9c6742070..34af7760e1e 100644
--- a/chromium/components/autofill/core/browser/autofill_handler_proxy.h
+++ b/chromium/components/autofill/core/browser/autofill_handler_proxy.h
@@ -41,7 +41,7 @@ class AutofillHandlerProxy : public AutofillHandler {
}
protected:
- bool OnFormSubmittedImpl(const FormData& form,
+ void OnFormSubmittedImpl(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) override;
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
index 15ad63088d6..1edd5bd1b6a 100644
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
+++ b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win.cc
@@ -79,7 +79,7 @@ base::string16 ReadAndDecryptValue(const RegKey& key,
const wchar_t* value_name) {
DWORD data_type = REG_BINARY;
DWORD data_size = 0;
- LONG result = key.ReadValue(value_name, NULL, &data_size, &data_type);
+ LONG result = key.ReadValue(value_name, nullptr, &data_size, &data_type);
if ((result != ERROR_SUCCESS) || !data_size || data_type != REG_BINARY)
return base::string16();
std::string data;
@@ -284,8 +284,8 @@ bool ImportCurrentUserProfiles(const std::string& app_locale,
RegKey key(HKEY_CURRENT_USER, key_name.c_str(), KEY_READ);
CreditCard credit_card;
credit_card.set_origin(kIEToolbarImportOrigin);
- if (ImportSingleFormGroup(
- key, reg_to_field, app_locale, &credit_card, NULL)) {
+ if (ImportSingleFormGroup(key, reg_to_field, app_locale, &credit_card,
+ nullptr)) {
base::string16 cc_number = credit_card.GetRawInfo(CREDIT_CARD_NUMBER);
if (!cc_number.empty())
credit_cards->push_back(credit_card);
diff --git a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
index aba32f14446..abc0088a62f 100644
--- a/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_ie_toolbar_import_win_unittest.cc
@@ -141,7 +141,7 @@ void AutofillIeToolbarImportTest::SetUp() {
}
void AutofillIeToolbarImportTest::TearDown() {
- EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, NULL));
+ EXPECT_EQ(ERROR_SUCCESS, RegOverridePredefKey(HKEY_CURRENT_USER, nullptr));
temp_hkcu_hive_key_.Close();
RegKey key(HKEY_CURRENT_USER, kUnitTestRegistrySubKey, KEY_ALL_ACCESS);
key.DeleteKey(L"");
diff --git a/chromium/components/autofill/core/browser/autofill_manager.cc b/chromium/components/autofill/core/browser/autofill_manager.cc
index 5bec63cb638..2a6fc3470e2 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager.cc
@@ -23,7 +23,7 @@
#include "base/guid.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/strings/string16.h"
@@ -108,7 +108,7 @@ bool SectionHasAutofilledField(const FormStructure& form_structure,
const std::string& section) {
DCHECK_EQ(form_structure.field_count(), form.fields.size());
for (size_t i = 0; i < form_structure.field_count(); ++i) {
- if (form_structure.field(i)->section() == section &&
+ if (form_structure.field(i)->section == section &&
form.fields[i].is_autofilled) {
return true;
}
@@ -180,23 +180,6 @@ bool IsCreditCardExpirationType(ServerFieldType type) {
type == CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR;
}
-// Create http bad warning message at the top of autofill popup list showing
-// "Payment not secure" when users are on http sites or broken https sites.
-Suggestion CreateHttpWarningMessageSuggestionItem(const GURL& source_url) {
- Suggestion cc_field_http_warning_suggestion(
- l10n_util::GetStringUTF16(IDS_AUTOFILL_CREDIT_CARD_HTTP_WARNING_MESSAGE));
- cc_field_http_warning_suggestion.frontend_id =
- POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE;
- cc_field_http_warning_suggestion.label =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE);
- cc_field_http_warning_suggestion.icon =
- (source_url.is_valid() && source_url.SchemeIs("http"))
- ? base::ASCIIToUTF16("httpWarning")
- : base::ASCIIToUTF16("httpsInvalid");
-
- return cc_field_http_warning_suggestion;
-}
-
} // namespace
AutofillManager::FillingContext::FillingContext() = default;
@@ -229,9 +212,6 @@ void AutofillManager::RegisterProfilePrefs(
registry->RegisterBooleanPref(
prefs::kAutofillEnabled, true,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- registry->RegisterBooleanPref(
- prefs::kAutofillProfileUseDatesFixed, false,
- user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
registry->RegisterIntegerPref(
prefs::kAutofillLastVersionDeduped, 0,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
@@ -248,6 +228,7 @@ void AutofillManager::RegisterProfilePrefs(
registry->RegisterIntegerPref(
prefs::kAutofillLastVersionDisusedCreditCardsDeleted, 0);
registry->RegisterBooleanPref(prefs::kAutofillCreditCardEnabled, true);
+ registry->RegisterBooleanPref(prefs::kAutofillOrphanRowsRemoved, false);
}
void AutofillManager::SetExternalDelegate(AutofillExternalDelegate* delegate) {
@@ -290,10 +271,39 @@ bool AutofillManager::ShouldShowScanCreditCard(const FormData& form,
return field.value.size() <= kShowScanCreditCardMaxValueLength;
}
-bool AutofillManager::IsCreditCardPopup(const FormData& form,
+PopupType AutofillManager::GetPopupType(const FormData& form,
const FormFieldData& field) {
- AutofillField* autofill_field = GetAutofillField(form, field);
- return autofill_field && autofill_field->Type().group() == CREDIT_CARD;
+ const AutofillField* autofill_field = GetAutofillField(form, field);
+ if (!autofill_field)
+ return PopupType::kUnspecified;
+
+ switch (autofill_field->Type().group()) {
+ case NO_GROUP:
+ case PASSWORD_FIELD:
+ case TRANSACTION:
+ case USERNAME_FIELD:
+ case UNFILLABLE:
+ return PopupType::kUnspecified;
+
+ case CREDIT_CARD:
+ return PopupType::kCreditCards;
+
+ case ADDRESS_HOME:
+ case ADDRESS_BILLING:
+ return PopupType::kAddresses;
+
+ case NAME:
+ case NAME_BILLING:
+ case EMAIL:
+ case COMPANY:
+ case PHONE_HOME:
+ case PHONE_BILLING:
+ return FormHasAddressField(form) ? PopupType::kAddresses
+ : PopupType::kPersonalInformation;
+
+ default:
+ NOTREACHED();
+ }
}
bool AutofillManager::ShouldShowCreditCardSigninPromo(
@@ -347,19 +357,19 @@ void AutofillManager::OnFormsSeen(const std::vector<FormData>& forms,
ParseForms(forms);
}
-bool AutofillManager::OnFormSubmittedImpl(const FormData& form,
+void AutofillManager::OnFormSubmittedImpl(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) {
// TODO(crbug.com/801698): handle PROBABLY_FORM_SUBMITTED.
if (source == SubmissionSource::PROBABLY_FORM_SUBMITTED)
- return false;
+ return;
// We will always give Autocomplete a chance to save the data.
std::unique_ptr<FormStructure> submitted_form = ValidateSubmittedForm(form);
if (!submitted_form) {
autocomplete_history_manager_->OnWillSubmitForm(form);
- return false;
+ return;
}
// However, if Autofill has recognized a field as CVC, that shouldn't be
@@ -377,14 +387,15 @@ bool AutofillManager::OnFormSubmittedImpl(const FormData& form,
if (IsCreditCardAutofillEnabled())
credit_card_form_event_logger_->OnWillSubmitForm();
- bool ret = StartUploadProcess(std::move(submitted_form), timestamp, true);
+ MaybeStartVoteUploadProcess(std::move(submitted_form), timestamp,
+ /*observed_submission=*/true);
// TODO(crbug.com/803334): Add FormStructure::Clone() method.
// Create another FormStructure instance.
submitted_form = ValidateSubmittedForm(form);
DCHECK(submitted_form);
if (!submitted_form)
- return false;
+ return;
CreditCard credit_card =
form_data_importer_->ExtractCreditCardFromForm(*submitted_form);
@@ -397,17 +408,16 @@ bool AutofillManager::OnFormSubmittedImpl(const FormData& form,
credit_card_form_event_logger_->OnFormSubmitted(enable_ablation_logging_,
card_number_status);
+ if (!submitted_form->IsAutofillable())
+ return;
+
// Update Personal Data with the form's submitted data.
// Also triggers offering local/upload credit card save, if applicable.
- if (submitted_form->IsAutofillable()) {
- form_data_importer_->ImportFormData(*submitted_form,
- IsCreditCardAutofillEnabled());
- }
-
- return ret;
+ form_data_importer_->ImportFormData(*submitted_form,
+ IsCreditCardAutofillEnabled());
}
-bool AutofillManager::StartUploadProcess(
+bool AutofillManager::MaybeStartVoteUploadProcess(
std::unique_ptr<FormStructure> form_structure,
const TimeTicks& timestamp,
bool observed_submission) {
@@ -477,7 +487,8 @@ void AutofillManager::ProcessPendingFormForUpload() {
if (!upload_form)
return;
- StartUploadProcess(std::move(upload_form), TimeTicks::Now(), false);
+ MaybeStartVoteUploadProcess(std::move(upload_form), TimeTicks::Now(),
+ /*observed_submission=*/false);
}
void AutofillManager::OnTextFieldDidChangeImpl(const FormData& form,
@@ -554,9 +565,11 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
if (autofill_field->Type().group() == CREDIT_CARD) {
is_filling_credit_card = true;
driver()->DidInteractWithCreditCardForm();
- credit_card_form_event_logger_->OnDidInteractWithAutofillableForm();
+ credit_card_form_event_logger_->OnDidInteractWithAutofillableForm(
+ form_structure->form_signature());
} else {
- address_form_event_logger_->OnDidInteractWithAutofillableForm();
+ address_form_event_logger_->OnDidInteractWithAutofillableForm(
+ form_structure->form_signature());
}
}
@@ -565,8 +578,6 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
!IsFormNonSecure(form) ||
!base::FeatureList::IsEnabled(
features::kAutofillRequireSecureCreditCardContext);
- const bool is_http_warning_enabled =
- security_state::IsHttpWarningInFormEnabled();
// TODO(rogerm): Early exit here on !driver()->RendererIsAvailable()?
// We skip populating autofill data, but might generate warnings and or
@@ -613,15 +624,13 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
// Autofill is disabled for a website. The string is different if the
// credit card autofill HTTP warning experiment is enabled.
Suggestion warning_suggestion(l10n_util::GetStringUTF16(
- is_http_warning_enabled
- ? IDS_AUTOFILL_WARNING_PAYMENT_DISABLED
- : IDS_AUTOFILL_WARNING_INSECURE_CONNECTION));
+ IDS_AUTOFILL_WARNING_INSECURE_CONNECTION));
warning_suggestion.frontend_id =
POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE;
suggestions.assign(1, warning_suggestion);
} else {
bool section_has_autofilled_field = SectionHasAutofilledField(
- *form_structure, form, autofill_field->section());
+ *form_structure, form, autofill_field->section);
if (section_has_autofilled_field) {
// If the relevant section has auto-filled fields and the renderer is
// querying for suggestions, then for some fields, the user is editing
@@ -654,21 +663,6 @@ void AutofillManager::OnQueryFormFieldAutofillImpl(
}
}
- // Show a "Payment not secure" message.
- if (!is_context_secure && is_filling_credit_card && is_http_warning_enabled) {
-#if !defined(OS_ANDROID)
- if (!suggestions.empty()) {
- suggestions.insert(suggestions.begin(), Suggestion());
- suggestions.front().frontend_id = POPUP_ITEM_ID_SEPARATOR;
- }
-#endif
-
- suggestions.insert(
- suggestions.begin(),
- CreateHttpWarningMessageSuggestionItem(
- form_structure ? form_structure->source_url() : GURL::EmptyGURL()));
- }
-
// If there are no Autofill suggestions, consider showing Autocomplete
// suggestions. We will not show Autocomplete suggestions for a field that
// specifies autocomplete=off (or an unrecognized type), a field for which we
@@ -707,7 +701,7 @@ bool AutofillManager::WillFillCreditCardNumber(const FormData& form,
DCHECK_EQ(form_structure->field_count(), form.fields.size());
for (size_t i = 0; i < form_structure->field_count(); ++i) {
- if (form_structure->field(i)->section() == autofill_field->section() &&
+ if (form_structure->field(i)->section == autofill_field->section &&
form_structure->field(i)->Type().GetStorableType() ==
CREDIT_CARD_NUMBER &&
form.fields[i].value.empty() && !form.fields[i].is_autofilled) {
@@ -745,12 +739,12 @@ void AutofillManager::FillOrPreviewCreditCardForm(
return;
}
credit_card_form_event_logger_->OnDidFillSuggestion(
- credit_card, form_structure->form_parsed_timestamp());
+ credit_card, *form_structure, *autofill_field);
}
FillOrPreviewDataModelForm(
- action, query_id, form, field, credit_card, true /* is_credit_card */,
- base::string16() /* cvc */, form_structure, autofill_field);
+ action, query_id, form, field, credit_card, /*is_credit_card=*/true,
+ /*cvc=*/base::string16(), form_structure, autofill_field);
}
void AutofillManager::FillOrPreviewProfileForm(
@@ -764,13 +758,14 @@ void AutofillManager::FillOrPreviewProfileForm(
if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field))
return;
if (action == AutofillDriver::FORM_DATA_ACTION_FILL) {
- address_form_event_logger_->OnDidFillSuggestion(
- profile, form_structure->form_parsed_timestamp());
+ address_form_event_logger_->OnDidFillSuggestion(profile, *form_structure,
+ *autofill_field);
// Set up the information needed for an eventual refill of this form.
if (base::FeatureList::IsEnabled(features::kAutofillDynamicForms) &&
- !form_structure->form_name().empty()) {
- auto& entry = filling_contexts_map_[form_structure->form_name()];
+ !form_structure->GetIdentifierForRefill().empty()) {
+ auto& entry =
+ filling_contexts_map_[form_structure->GetIdentifierForRefill()];
auto filling_context = std::make_unique<FillingContext>();
filling_context->temp_data_model = profile;
filling_context->filled_field_name = autofill_field->unique_name();
@@ -780,8 +775,8 @@ void AutofillManager::FillOrPreviewProfileForm(
}
FillOrPreviewDataModelForm(
- action, query_id, form, field, profile, false /* is_credit_card */,
- base::string16() /* cvc */, form_structure, autofill_field);
+ action, query_id, form, field, profile, /*is_credit_card=*/false,
+ /*cvc=*/base::string16(), form_structure, autofill_field);
}
void AutofillManager::FillOrPreviewForm(
@@ -823,7 +818,7 @@ void AutofillManager::FillCreditCardForm(int query_id,
FillOrPreviewDataModelForm(
AutofillDriver::FORM_DATA_ACTION_FILL, query_id, form, field, credit_card,
- true /* is_credit_card */, cvc, form_structure, autofill_field);
+ /*is_credit_card=*/true, cvc, form_structure, autofill_field);
}
void AutofillManager::OnFocusNoLongerOnForm() {
@@ -894,10 +889,12 @@ void AutofillManager::DidShowSuggestions(bool is_new_popup,
if (autofill_field->Type().group() == CREDIT_CARD) {
credit_card_form_event_logger_->OnDidShowSuggestions(
- *autofill_field, form_structure->form_parsed_timestamp());
+ *form_structure, *autofill_field,
+ form_structure->form_parsed_timestamp());
} else {
address_form_event_logger_->OnDidShowSuggestions(
- *autofill_field, form_structure->form_parsed_timestamp());
+ *form_structure, *autofill_field,
+ form_structure->form_parsed_timestamp());
}
}
}
@@ -1033,7 +1030,13 @@ void AutofillManager::OnSetDataList(const std::vector<base::string16>& values,
void AutofillManager::SelectFieldOptionsDidChange(const FormData& form) {
FormStructure* form_structure = nullptr;
- if (!ParseForm(form, &form_structure))
+
+ // Look for a cached version of the form. It will be a null pointer if none is
+ // found, which is fine.
+ FormStructure* cached_form = nullptr;
+ ignore_result(FindCachedForm(form, &cached_form));
+
+ if (!ParseForm(form, cached_form, &form_structure))
return;
if (ShouldTriggerRefill(*form_structure))
@@ -1091,8 +1094,13 @@ void AutofillManager::OnFullCardRequestSucceeded(
const payments::FullCardRequest& full_card_request,
const CreditCard& card,
const base::string16& cvc) {
+ FormStructure* form_structure = nullptr;
+ AutofillField* autofill_field = nullptr;
+ if (!GetCachedFormAndField(unmasking_form_, unmasking_field_, &form_structure,
+ &autofill_field))
+ return;
credit_card_form_event_logger_->OnDidFillSuggestion(
- masked_card_, full_card_request.form_parsed_timestamp());
+ masked_card_, *form_structure, *autofill_field);
FillCreditCardForm(unmasking_query_id_, unmasking_form_, unmasking_field_,
card, cvc);
masked_card_ = CreditCard();
@@ -1176,7 +1184,7 @@ void AutofillManager::UploadFormData(const FormStructure& submitted_form,
download_manager_->StartUploadRequest(
submitted_form, was_autofilled, non_empty_types,
- std::string() /* login_form_signature */, observed_submission);
+ /*login_form_signature=*/std::string(), observed_submission);
}
void AutofillManager::Reset() {
@@ -1189,9 +1197,9 @@ void AutofillManager::Reset() {
new AutofillMetrics::FormInteractionsUkmLogger(
client_->GetUkmRecorder()));
address_form_event_logger_.reset(new AutofillMetrics::FormEventLogger(
- false /* is_for_credit_card */, form_interactions_ukm_logger_.get()));
+ /*is_for_credit_card=*/false, form_interactions_ukm_logger_.get()));
credit_card_form_event_logger_.reset(new AutofillMetrics::FormEventLogger(
- true /* is_for_credit_card */, form_interactions_ukm_logger_.get()));
+ /*is_for_credit_card=*/true, form_interactions_ukm_logger_.get()));
#if defined(OS_ANDROID) || defined(OS_IOS)
autofill_assistant_.Reset();
#endif
@@ -1227,7 +1235,8 @@ AutofillManager::AutofillManager(
/*unmask_delegate=*/this,
// save_delegate starts out as nullptr and is set up by the
// CreditCardSaveManager owned by form_data_importer_.
- /*save_delegate=*/nullptr)),
+ /*save_delegate=*/nullptr,
+ driver->IsIncognito())),
app_locale_(app_locale),
personal_data_(personal_data),
form_data_importer_(
@@ -1243,11 +1252,11 @@ AutofillManager::AutofillManager(
client->GetUkmRecorder())),
address_form_event_logger_(
std::make_unique<AutofillMetrics::FormEventLogger>(
- false /* is_for_credit_card */,
+ /*is_for_credit_card=*/false,
form_interactions_ukm_logger_.get())),
credit_card_form_event_logger_(
std::make_unique<AutofillMetrics::FormEventLogger>(
- true /* is_for_credit_card */,
+ /*is_for_credit_card=*/true,
form_interactions_ukm_logger_.get())),
#if defined(OS_ANDROID) || defined(OS_IOS)
autofill_assistant_(this),
@@ -1351,7 +1360,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
FormData result = form;
if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions)) {
- form_structure->RationalizePhoneNumbersInSection(autofill_field->section());
+ form_structure->RationalizePhoneNumbersInSection(autofill_field->section);
}
DCHECK_EQ(form_structure->field_count(), form.fields.size());
@@ -1364,7 +1373,8 @@ void AutofillManager::FillOrPreviewDataModelForm(
// This fill is not a refill attempt.
// This is not a credit card fill.
FillingContext* filling_context = nullptr;
- auto itr = filling_contexts_map_.find(form_structure->form_name());
+ auto itr =
+ filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
if (itr != filling_contexts_map_.end())
filling_context = itr->second.get();
bool could_attempt_refill =
@@ -1373,7 +1383,7 @@ void AutofillManager::FillOrPreviewDataModelForm(
!is_refill && !is_credit_card;
for (size_t i = 0; i < form_structure->field_count(); ++i) {
- if (form_structure->field(i)->section() != autofill_field->section())
+ if (form_structure->field(i)->section != autofill_field->section)
continue;
if (form_structure->field(i)->only_fill_when_focused() &&
@@ -1387,15 +1397,14 @@ void AutofillManager::FillOrPreviewDataModelForm(
AutofillField* cached_field = form_structure->field(i);
FieldTypeGroup field_group_type = cached_field->Type().group();
- // Don't fill non-focusable fields, with the exception of <select> fields.
- if (!cached_field->is_focusable &&
+ // Don't fill hidden fields, with the exception of <select> fields, for
+ // the sake of filling the synthetic fields.
+ if ((!cached_field->is_focusable ||
+ cached_field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION) &&
result.fields[i].form_control_type != "select-one") {
continue;
}
- if (cached_field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION)
- continue;
-
// Don't fill previously autofilled fields except the initiating field or
// when it's a refill.
if (result.fields[i].is_autofilled && !cached_field->SameFieldAs(field) &&
@@ -1437,6 +1446,15 @@ void AutofillManager::FillOrPreviewDataModelForm(
// will be sent to the renderer.
FillFieldWithValue(cached_field, data_model, &result.fields[i],
should_notify, cvc);
+
+ if (result.fields[i].is_autofilled)
+ result.fields[i].section = form_structure->field(i)->section;
+
+ if ((!cached_field->is_focusable ||
+ cached_field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION) &&
+ result.fields[i].is_autofilled) {
+ AutofillMetrics::LogHiddenOrPresentationalSelectFieldsFilled();
+ }
}
autofilled_form_signatures_.push_front(form_structure->FormSignatureAsStr());
@@ -1466,8 +1484,8 @@ std::unique_ptr<FormStructure> AutofillManager::ValidateSubmittedForm(
return std::unique_ptr<FormStructure>();
submitted_form->RetrieveFromCache(*cached_submitted_form,
- /* apply_is_autofilled */ false,
- /* only_server_and_autofill_state */ false);
+ /*apply_is_autofilled=*/false,
+ /*only_server_and_autofill_state=*/false);
return submitted_form;
}
@@ -1552,6 +1570,18 @@ AutofillField* AutofillManager::GetAutofillField(const FormData& form,
return autofill_field;
}
+bool AutofillManager::FormHasAddressField(const FormData& form) {
+ for (const FormFieldData& field : form.fields) {
+ const AutofillField* autofill_field = GetAutofillField(form, field);
+ if (autofill_field && (autofill_field->Type().group() == ADDRESS_HOME ||
+ autofill_field->Type().group() == ADDRESS_BILLING)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool AutofillManager::UpdateCachedForm(const FormData& live_form,
const FormStructure* cached_form,
FormStructure** updated_form) {
@@ -1566,14 +1596,9 @@ bool AutofillManager::UpdateCachedForm(const FormData& live_form,
// Note: We _must not_ remove the original version of the cached form from
// the list of |form_structures_|. Otherwise, we break parsing of the
// crowdsourcing server's response to our query.
- if (!ParseForm(live_form, updated_form))
+ if (!ParseForm(live_form, cached_form, updated_form))
return false;
- // We need to keep the server data.
- if (cached_form)
- (*updated_form)
- ->RetrieveFromCache(*cached_form, /* apply_is_autofilled */ true,
- /* only_server_and_autofill_state */ true);
// Annotate the updated form with its predicted types.
driver()->SendAutofillTypePredictionsToRenderer({*updated_form});
@@ -1661,7 +1686,7 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
const auto parse_form_start_time = TimeTicks::Now();
FormStructure* form_structure = nullptr;
- if (!ParseForm(form, &form_structure))
+ if (!ParseForm(form, /*cached_form=*/nullptr, &form_structure))
continue;
DCHECK(form_structure);
@@ -1681,7 +1706,8 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
// been a refill attempt on that form yet, start the process of triggering a
// refill.
if (ShouldTriggerRefill(*form_structure)) {
- auto itr = filling_contexts_map_.find(form_structure->form_name());
+ auto itr =
+ filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
DCHECK(itr != filling_contexts_map_.end());
FillingContext* filling_context = itr->second.get();
@@ -1740,6 +1766,7 @@ void AutofillManager::ParseForms(const std::vector<FormData>& forms) {
}
bool AutofillManager::ParseForm(const FormData& form,
+ const FormStructure* cached_form,
FormStructure** parsed_form_structure) {
DCHECK(parsed_form_structure);
if (form_structures_.size() >= kMaxFormCacheSize)
@@ -1747,8 +1774,17 @@ bool AutofillManager::ParseForm(const FormData& form,
auto form_structure = std::make_unique<FormStructure>(form);
form_structure->ParseFieldTypesFromAutocompleteAttributes();
- if (!form_structure->ShouldBeParsed())
+ if (!form_structure->ShouldBeParsed()) {
return false;
+ }
+
+ if (cached_form) {
+ // We need to keep the server data if available. We need to use them while
+ // determining the heuristics.
+ form_structure->RetrieveFromCache(*cached_form,
+ /*apply_is_autofilled=*/true,
+ /*only_server_and_autofill_state=*/true);
+ }
// Ownership is transferred to |form_structures_| which maintains it until
// the manager is Reset() or destroyed. It is safe to use references below
@@ -2027,22 +2063,35 @@ bool AutofillManager::ShouldTriggerRefill(const FormStructure& form_structure) {
if (!base::FeatureList::IsEnabled(features::kAutofillDynamicForms))
return false;
+ address_form_event_logger_->OnDidSeeDynamicForm();
+
// Should not refill if a form with the same name has not been filled before.
- auto itr = filling_contexts_map_.find(form_structure.form_name());
+ auto itr =
+ filling_contexts_map_.find(form_structure.GetIdentifierForRefill());
if (itr == filling_contexts_map_.end())
return false;
- FillingContext* filling_context = itr->second.get();
+ address_form_event_logger_->OnDidSeeFillableDynamicForm();
+ FillingContext* filling_context = itr->second.get();
base::TimeTicks now = base::TimeTicks::Now();
base::TimeDelta delta = now - filling_context->original_fill_time;
+
+ if (filling_context->attempted_refill &&
+ delta.InMilliseconds() < kLimitBeforeRefillMs) {
+ address_form_event_logger_->OnSubsequentRefillAttempt();
+ }
+
return !filling_context->attempted_refill &&
delta.InMilliseconds() < kLimitBeforeRefillMs;
}
void AutofillManager::TriggerRefill(const FormData& form,
FormStructure* form_structure) {
- auto itr = filling_contexts_map_.find(form_structure->form_name());
+ address_form_event_logger_->OnDidRefill();
+
+ auto itr =
+ filling_contexts_map_.find(form_structure->GetIdentifierForRefill());
DCHECK(itr != filling_contexts_map_.end());
FillingContext* filling_context = itr->second.get();
diff --git a/chromium/components/autofill/core/browser/autofill_manager.h b/chromium/components/autofill/core/browser/autofill_manager.h
index 2b3d077ddae..8b4130cc436 100644
--- a/chromium/components/autofill/core/browser/autofill_manager.h
+++ b/chromium/components/autofill/core/browser/autofill_manager.h
@@ -34,6 +34,7 @@
#include "components/autofill/core/browser/payments/full_card_request.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
+#include "components/autofill/core/browser/popup_types.h"
#include "components/autofill/core/common/form_data.h"
#if defined(OS_ANDROID) || defined(OS_IOS)
@@ -93,8 +94,8 @@ class AutofillManager : public AutofillHandler,
virtual bool ShouldShowScanCreditCard(const FormData& form,
const FormFieldData& field);
- // Whether the |field| belongs to CREDIT_CARD |FieldTypeGroup|.
- virtual bool IsCreditCardPopup(const FormData& form,
+ // Returns the type of the popup being shown.
+ virtual PopupType GetPopupType(const FormData& form,
const FormFieldData& field);
// Whether we should show the signin promo, based on the triggered |field|
@@ -161,11 +162,12 @@ class AutofillManager : public AutofillHandler,
// Will send an upload based on the |form_structure| data and the local
// Autofill profile data. |observed_submission| is specified if the upload
- // follows an observed submission event.
- // return false if the upload couldn't start.
- virtual bool StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
- const base::TimeTicks& timestamp,
- bool observed_submission);
+ // follows an observed submission event. Returns false if the upload couldn't
+ // start.
+ virtual bool MaybeStartVoteUploadProcess(
+ std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission);
// Update the pending form with |form|, possibly processing the current
// pending form for upload.
@@ -201,6 +203,9 @@ class AutofillManager : public AutofillHandler,
// to be uploadable. Exposed for testing.
bool ShouldUploadForm(const FormStructure& form);
+ // Returns the number of forms this Autofill Manager is aware of.
+ size_t NumFormsDetected() const { return form_structures_.size(); }
+
protected:
// Test code should prefer to use this constructor.
AutofillManager(AutofillDriver* driver,
@@ -240,7 +245,7 @@ class AutofillManager : public AutofillHandler,
std::string* profile_backend_id) const;
// AutofillHandler:
- bool OnFormSubmittedImpl(const FormData& form,
+ void OnFormSubmittedImpl(const FormData& form,
bool known_success,
SubmissionSource source,
base::TimeTicks timestamp) override;
@@ -402,6 +407,10 @@ class AutofillManager : public AutofillHandler,
const FormFieldData& field)
WARN_UNUSED_RESULT;
+ // Returns true if any form in the field corresponds to an address
+ // |FieldTypeGroup|.
+ bool FormHasAddressField(const FormData& form) WARN_UNUSED_RESULT;
+
// Re-parses |live_form| and adds the result to |form_structures_|.
// |cached_form| should be a pointer to the existing version of the form, or
// NULL if no cached version exists. The updated form is then written into
@@ -430,8 +439,13 @@ class AutofillManager : public AutofillHandler,
// Parses the forms using heuristic matching and querying the Autofill server.
void ParseForms(const std::vector<FormData>& forms);
- // Parses the form and adds it to |form_structures_|.
- bool ParseForm(const FormData& form, FormStructure** parsed_form_structure);
+ // Parses the |form| with the server data retrieved from the |cached_form|
+ // (if any), and writes it to the |parse_form_structure|. Adds the
+ // |parse_form_structure| to the |form_structures_|. Returns true if the form
+ // is parsed.
+ bool ParseForm(const FormData& form,
+ const FormStructure* cached_form,
+ FormStructure** parsed_form_structure);
// If |initial_interaction_timestamp_| is unset or is set to a later time than
// |interaction_timestamp|, updates the cached timestamp. The latter check is
@@ -598,7 +612,10 @@ class AutofillManager : public AutofillHandler,
friend class AutofillManagerTest;
friend class FormStructureBrowserTest;
+ friend class GetMatchingTypesTest;
friend class SaveCardBubbleViewsBrowserTestBase;
+ FRIEND_TEST_ALL_PREFIXES(ProfileMatchingTypesTest,
+ DeterminePossibleFieldTypesForUpload);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
DeterminePossibleFieldTypesForUpload);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
@@ -606,6 +623,8 @@ class AutofillManager : public AutofillHandler,
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, DisambiguateUploadTypes);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
DisabledAutofillDispatchesError);
+ FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
+ DetermineHeuristicsWithOverallPrediction);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressFilledFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressSubmittedFormEvents);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, AddressWillSubmitFormEvents);
@@ -651,6 +670,7 @@ class AutofillManager : public AutofillHandler,
QualityMetrics_LoggedCorrecltyForRationalizationBad);
FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, SaneMetricsWithCacheMismatch);
+ FRIEND_TEST_ALL_PREFIXES(AutofillMetricsTest, DynamicFormMetrics);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest, TestExternalDelegate);
FRIEND_TEST_ALL_PREFIXES(AutofillManagerTest,
TestTabContentsWithExternalDelegate);
diff --git a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
index 4bcb131a188..48067a8a6ac 100644
--- a/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -20,6 +20,7 @@
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
@@ -83,13 +84,6 @@ namespace {
const int kDefaultPageID = 137;
-const char kUTF8MidlineEllipsis[] =
- " "
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86";
-
class MockAutofillClient : public TestAutofillClient {
public:
MockAutofillClient() {}
@@ -405,12 +399,8 @@ class AutofillManagerTest : public testing::Test {
}
void FormSubmitted(const FormData& form) {
- autofill_manager_->ResetRunLoop();
- if (autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION,
- base::TimeTicks::Now())) {
- autofill_manager_->WaitForAsyncUploadProcess();
- }
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now());
}
void FillAutofillFormData(int query_id,
@@ -520,11 +510,6 @@ class AutofillManagerTest : public testing::Test {
autofill_manager_->full_card_request_.get());
}
- void SetHttpWarningEnabled() {
- scoped_feature_list_.InitAndEnableFeature(
- security_state::kHttpFormWarningFeature);
- }
-
void DisableCreditCardAutofill() {
scoped_feature_list_.InitAndEnableFeature(
kAutofillCreditCardAblationExperiment);
@@ -946,24 +931,6 @@ TEST_F(AutofillManagerTest, GetProfileSuggestions_EmptyValue) {
Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2));
}
-// Test that the HttpWarning does not appear on non-payment forms.
-TEST_F(AutofillManagerTest, GetProfileSuggestions_EmptyValueNotSecure) {
- SetHttpWarningEnabled();
- // Set up our form data.
- FormData form;
- test::CreateTestAddressFormData(&form);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- const FormFieldData& field = form.fields[0];
- GetAutofillSuggestions(form, field);
-
- // Test that we sent the right values to the external delegate.
- CheckSuggestions(kDefaultPageID,
- Suggestion("Charles", "123 Apple St.", "", 1),
- Suggestion("Elvis", "3734 Elvis Presley Blvd.", "", 2));
-}
-
// Test that we return only matching address profile suggestions when the
// selected form field has been partially filled out.
TEST_F(AutofillManagerTest, GetProfileSuggestions_MatchCharacter) {
@@ -1133,9 +1100,11 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_EmptyValue) {
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -1156,9 +1125,11 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_Whitespace) {
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -1179,9 +1150,11 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsOnly) {
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -1202,9 +1175,11 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_InvisibleUnicodeOnly) {
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -1232,11 +1207,11 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_StopCharsWithInput) {
GetAutofillSuggestions(form, field);
// Test that we sent the right value to the external delegate.
- CheckSuggestions(
- kDefaultPageID,
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "3123",
- "08/17", kMasterCard,
- autofill_manager_->GetPackedCreditCardID(7)));
+ CheckSuggestions(kDefaultPageID,
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("3123"),
+ "08/17", kMasterCard,
+ autofill_manager_->GetPackedCreditCardID(7)));
}
// Test that we return only matching credit card profile suggestions when the
@@ -1255,8 +1230,9 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_MatchCharacter) {
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)));
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)));
}
// Test that we return credit card profile suggestions when the selected form
@@ -1273,12 +1249,14 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonCCNumber) {
#if defined(OS_ANDROID)
static const std::string kVisaSuggestion =
- std::string("Visa") + kUTF8MidlineEllipsis + "3456";
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456");
static const std::string kMcSuggestion =
- std::string("Mastercard") + kUTF8MidlineEllipsis + "8765";
+ std::string("Mastercard ") + test::ObfuscatedCardDigitsAsUTF8("8765");
#else
- static const std::string kVisaSuggestion = "*3456";
- static const std::string kMcSuggestion = "*8765";
+ static const std::string kVisaSuggestion =
+ test::ObfuscatedCardDigitsAsUTF8("3456");
+ static const std::string kMcSuggestion =
+ test::ObfuscatedCardDigitsAsUTF8("8765");
#endif
// Test that we sent the right values to the external delegate.
@@ -1289,98 +1267,6 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonCCNumber) {
autofill_manager_->GetPackedCreditCardID(5)));
}
-// Test that we return a warning explaining that credit card profile suggestions
-// are unavailable when the page and the form target URL are not secure.
-TEST_F(AutofillManagerTest, GetCreditCardSuggestions_NonSecureContext) {
- // Set up our form data.
- FormData form;
- CreateTestCreditCardFormData(&form, /* is_https */ false, false);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- const FormFieldData& field = form.fields[0];
- GetAutofillSuggestions(form, field);
-
- // Test that we sent the right values to the external delegate.
- CheckSuggestions(kDefaultPageID,
- Suggestion(l10n_util::GetStringUTF8(
- IDS_AUTOFILL_WARNING_INSECURE_CONNECTION),
- "", "", -1));
-
- // Clear the test credit cards and try again -- we shouldn't return a warning.
- personal_data_.ClearCreditCards();
- GetAutofillSuggestions(form, field);
- // Autocomplete suggestions are queried, but not Autofill.
- EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
-}
-
-// Test that we return an extra "Payment not secure" warning when the page and
-// the form target URL are not secure.
-TEST_F(AutofillManagerTest,
- GetCreditCardSuggestions_NonSecureContextWithHttpBadSwitchOn) {
- SetHttpWarningEnabled();
-
- // Set up our form data.
- FormData form;
- CreateTestCreditCardFormData(&form, /* is_https */ false, false);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- const FormFieldData& field = form.fields[0];
- GetAutofillSuggestions(form, field);
-
- // Test that we sent the right values to the external delegate.
- CheckSuggestions(
- kDefaultPageID,
- Suggestion(l10n_util::GetStringUTF8(
- IDS_AUTOFILL_CREDIT_CARD_HTTP_WARNING_MESSAGE),
- l10n_util::GetStringUTF8(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE),
- "httpWarning", POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE),
-#if !defined(OS_ANDROID)
- Suggestion("", "", "", POPUP_ITEM_ID_SEPARATOR),
-#endif
- Suggestion(
- l10n_util::GetStringUTF8(IDS_AUTOFILL_WARNING_PAYMENT_DISABLED), "",
- "", POPUP_ITEM_ID_INSECURE_CONTEXT_PAYMENT_DISABLED_MESSAGE));
-
- // Clear the test credit cards and try again -- we should still show the
- // warning.
- personal_data_.ClearCreditCards();
- GetAutofillSuggestions(form, field);
- // Test that we sent the right values to the external delegate.
- CheckSuggestions(
- kDefaultPageID,
- Suggestion(l10n_util::GetStringUTF8(
- IDS_AUTOFILL_CREDIT_CARD_HTTP_WARNING_MESSAGE),
- l10n_util::GetStringUTF8(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE),
- "httpWarning", POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
-}
-
-// Test that we don't show the extra "Payment not secure" warning when the page
-// and the form target URL are secure, even when the switch is on.
-TEST_F(AutofillManagerTest,
- GetCreditCardSuggestions_SecureContextWithHttpBadSwitchOn) {
- SetHttpWarningEnabled();
-
- // Set up our form data.
- FormData form;
- CreateTestCreditCardFormData(&form, /* is_https */ true, false);
- std::vector<FormData> forms(1, form);
- FormsSeen(forms);
-
- FormFieldData field = form.fields[1];
- GetAutofillSuggestions(form, field);
-
- // Test that we sent the right values to the external delegate.
- CheckSuggestions(
- kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
- "10/98", kMasterCard,
- autofill_manager_->GetPackedCreditCardID(5)));
-}
-
// Test that we will eventually return the credit card signin promo when there
// are no credit card suggestions and the promo is active. See the tests in
// AutofillExternalDelegateTest that test whether the promo is added.
@@ -1459,9 +1345,11 @@ TEST_F(AutofillManagerTest,
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -1484,9 +1372,11 @@ TEST_F(AutofillManagerTest,
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -1517,12 +1407,15 @@ TEST_F(AutofillManagerTest, GetCreditCardSuggestions_RepeatedObfuscatedNumber) {
// Test that we sent the right values to the external delegate.
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "3456",
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("3456"),
"05/99", kMasterCard,
autofill_manager_->GetPackedCreditCardID(7)));
}
@@ -1551,9 +1444,11 @@ TEST_F(AutofillManagerTest, GetAddressAndCreditCardSuggestions) {
// Test that we sent the credit card suggestions to the external delegate.
CheckSuggestions(
kPageID2,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
- Suggestion(std::string("Mastercard") + kUTF8MidlineEllipsis + "8765",
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)),
+ Suggestion(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("8765"),
"10/98", kMasterCard,
autofill_manager_->GetPackedCreditCardID(5)));
}
@@ -3615,6 +3510,77 @@ TEST_F(AutofillManagerTest, FillFirstPhoneNumber_HiddenFieldShouldNotCount) {
}
}
+// The hidden and the presentational fields should be filled, only if their
+// control type is 'select-one'. This exception is made to support synthetic
+// fields.
+TEST_F(AutofillManagerTest, FormWithHiddenOrPresentationalSelects) {
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
+
+ FormFieldData field;
+
+ test::CreateTestFormField("First name", "firstname", "", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Last name", "lastname", "", "text", &field);
+ form.fields.push_back(field);
+
+ {
+ const std::vector<const char*> values{"CA", "US", "BR"};
+ const std::vector<const char*> contents{"Canada", "United States",
+ "Banana Republic"};
+ test::CreateTestSelectField("Country", "country", "", values, contents,
+ values.size(), &field);
+ field.is_focusable = false;
+ form.fields.push_back(field);
+ }
+ {
+ const std::vector<const char*> values{"NY", "CA", "TN"};
+ const std::vector<const char*> contents{"New York", "California",
+ "Tennessee"};
+ test::CreateTestSelectField("State", "state", "", values, contents,
+ values.size(), &field);
+ field.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
+ form.fields.push_back(field);
+ }
+
+ test::CreateTestFormField("City", "city", "", "text", &field);
+ field.is_focusable = false;
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Street Address", "address", "", "text", &field);
+ field.role = FormFieldData::ROLE_ATTRIBUTE_PRESENTATION;
+ form.fields.push_back(field);
+
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ const char guid[] = "00000000-0000-0000-0000-000000000001";
+ int response_page_id = 0;
+ FormData response_data;
+ base::HistogramTester histogram_tester;
+
+ FillAutofillFormDataAndSaveResults(kDefaultPageID, form, form.fields[0],
+ MakeFrontendID(std::string(), guid),
+ &response_page_id, &response_data);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.HiddenOrPresentationalSelectFieldsFilled", 2);
+
+ ExpectFilledField("First name", "firstname", "Elvis", "text",
+ response_data.fields[0]);
+ ExpectFilledField("Last name", "lastname", "Presley", "text",
+ response_data.fields[1]);
+ ExpectFilledField("Country", "country", "US", "select-one",
+ response_data.fields[2]);
+ ExpectFilledField("State", "state", "TN", "select-one",
+ response_data.fields[3]);
+ ExpectFilledField("City", "city", "", "text", response_data.fields[4]);
+ ExpectFilledField("Street Address", "address", "", "text",
+ response_data.fields[5]);
+}
+
TEST_F(AutofillManagerTest,
FillFirstPhoneNumber_MultipleSectionFilledCorrectly) {
AutofillProfile* work_profile =
@@ -3936,11 +3902,9 @@ TEST_F(AutofillManagerTest, FormSubmittedSaveData) {
ExpectFilledAddressFormElvis(response_page_id, response_data, kDefaultPageID,
false);
- autofill_manager_->ResetRunLoop();
autofill_manager_->OnFormSubmitted(response_data, false,
SubmissionSource::FORM_SUBMISSION,
base::TimeTicks::Now());
- autofill_manager_->WaitForAsyncUploadProcess();
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
}
@@ -4261,6 +4225,87 @@ TEST_F(AutofillManagerTest, OnLoadedServerPredictions_ResetManager) {
histogram_tester.ExpectTotalCount("Autofill.ServerQueryResponse", 0);
}
+// Test that when server predictions disagree with the heuristic ones, the
+// overall types and sections would be set based on the server one.
+TEST_F(AutofillManagerTest, DetermineHeuristicsWithOverallPrediction) {
+ // Set up our form data.
+ FormData form;
+ FormFieldData field;
+ test::CreateTestFormField("First Name", "firstname", "", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Expiration Year", "exp_year", "", "text", &field);
+ form.fields.push_back(field);
+
+ test::CreateTestFormField("Expiration Month", "exp_month", "", "text",
+ &field);
+ form.fields.push_back(field);
+
+ // Simulate having seen this form on page load.
+ // |form_structure| will be owned by |autofill_manager_|.
+ TestFormStructure* form_structure = new TestFormStructure(form);
+ form_structure->DetermineHeuristicTypes(nullptr /* ukm_recorder */);
+ autofill_manager_->AddSeenFormStructure(base::WrapUnique(form_structure));
+
+ AutofillQueryResponseContents response;
+ response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_FIRST);
+ response.add_field()->set_overall_type_prediction(CREDIT_CARD_NAME_LAST);
+ response.add_field()->set_overall_type_prediction(CREDIT_CARD_NUMBER);
+ response.add_field()->set_overall_type_prediction(CREDIT_CARD_EXP_MONTH);
+ response.add_field()->set_overall_type_prediction(
+ CREDIT_CARD_EXP_4_DIGIT_YEAR);
+
+ std::string response_string;
+ ASSERT_TRUE(response.SerializeToString(&response_string));
+
+ std::vector<std::string> signatures;
+ signatures.push_back(form_structure->FormSignatureAsStr());
+
+ base::HistogramTester histogram_tester;
+ autofill_manager_->OnLoadedServerPredictions(response_string, signatures);
+ // Verify that FormStructure::ParseQueryResponse was called (here and below).
+ histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
+ AutofillMetrics::QUERY_RESPONSE_RECEIVED,
+ 1);
+ histogram_tester.ExpectBucketCount("Autofill.ServerQueryResponse",
+ AutofillMetrics::QUERY_RESPONSE_PARSED, 1);
+
+ // Since the card holder name appears as the first name + last name (rather
+ // than the full name), and since they appears as the first fields of the
+ // section, the heuristics detect them as the address first/last name.
+ EXPECT_EQ(NAME_FIRST, form_structure->field(0)->heuristic_type());
+ EXPECT_EQ(NAME_LAST, form_structure->field(1)->heuristic_type());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(2)->heuristic_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ form_structure->field(4)->heuristic_type());
+
+ // We expect to see the server type as the overall type.
+ EXPECT_EQ(CREDIT_CARD_NAME_FIRST,
+ form_structure->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NAME_LAST,
+ form_structure->field(1)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, form_structure->field(2)->heuristic_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH, form_structure->field(3)->heuristic_type());
+ EXPECT_EQ(CREDIT_CARD_EXP_4_DIGIT_YEAR,
+ form_structure->field(4)->heuristic_type());
+
+ // Although the heuristic types of the first two fields belongs to the address
+ // section, the final fields' section should be based on the overall
+ // prediction, therefore they should be grouped in one section.
+ const auto section = form_structure->field(0)->section;
+ EXPECT_EQ(section, form_structure->field(1)->section);
+ EXPECT_EQ(section, form_structure->field(2)->section);
+ EXPECT_EQ(section, form_structure->field(3)->section);
+ EXPECT_EQ(section, form_structure->field(4)->section);
+}
+
// Test that we are able to save form data when forms are submitted and we only
// have server data for the field types.
TEST_F(AutofillManagerTest, FormSubmittedServerTypes) {
@@ -4412,28 +4457,163 @@ TEST_F(AutofillManagerTest, FormSubmittedWithDefaultValues) {
EXPECT_EQ(1, personal_data_.num_times_save_imported_profile_called());
}
+struct ProfileMatchingTypesTestCase {
+ const char* input_value; // The value to input in the field.
+ ServerFieldType field_type; // The expected field type to be determined.
+};
+
+class ProfileMatchingTypesTest
+ : public AutofillManagerTest,
+ public ::testing::WithParamInterface<
+ std::tuple<ProfileMatchingTypesTestCase,
+ int, // AutofillProfile::ValidityState
+ bool>> {}; // Enable AutofillVoteUsingInvalidProfileValues
+
+const ProfileMatchingTypesTestCase kProfileMatchingTypesTestCases[] = {
+ // Profile fields matches.
+ {"Elvis", NAME_FIRST},
+ {"Aaron", NAME_MIDDLE},
+ {"A", NAME_MIDDLE_INITIAL},
+ {"Presley", NAME_LAST},
+ {"Elvis Aaron Presley", NAME_FULL},
+ {"theking@gmail.com", EMAIL_ADDRESS},
+ {"RCA", COMPANY_NAME},
+ {"3734 Elvis Presley Blvd.", ADDRESS_HOME_LINE1},
+ {"Apt. 10", ADDRESS_HOME_LINE2},
+ {"Memphis", ADDRESS_HOME_CITY},
+ {"Tennessee", ADDRESS_HOME_STATE},
+ {"38116", ADDRESS_HOME_ZIP},
+ {"USA", ADDRESS_HOME_COUNTRY},
+ {"United States", ADDRESS_HOME_COUNTRY},
+ {"12345678901", PHONE_HOME_WHOLE_NUMBER},
+ {"+1 (234) 567-8901", PHONE_HOME_WHOLE_NUMBER},
+ {"(234)567-8901", PHONE_HOME_CITY_AND_NUMBER},
+ {"2345678901", PHONE_HOME_CITY_AND_NUMBER},
+ {"1", PHONE_HOME_COUNTRY_CODE},
+ {"234", PHONE_HOME_CITY_CODE},
+ {"5678901", PHONE_HOME_NUMBER},
+ {"567", PHONE_HOME_NUMBER},
+ {"8901", PHONE_HOME_NUMBER},
+
+ // Test a European profile.
+ {"Paris", ADDRESS_HOME_CITY},
+ {"Île de France", ADDRESS_HOME_STATE}, // Exact match
+ {"Ile de France", ADDRESS_HOME_STATE}, // Missing accent.
+ {"-Ile-de-France-", ADDRESS_HOME_STATE}, // Extra punctuation.
+ {"île dÉ FrÃÑÇË", ADDRESS_HOME_STATE}, // Other accents & case mismatch.
+ {"75008", ADDRESS_HOME_ZIP},
+ {"FR", ADDRESS_HOME_COUNTRY},
+ {"France", ADDRESS_HOME_COUNTRY},
+ {"33249197070", PHONE_HOME_WHOLE_NUMBER},
+ {"+33 2 49 19 70 70", PHONE_HOME_WHOLE_NUMBER},
+ {"2 49 19 70 70", PHONE_HOME_CITY_AND_NUMBER},
+ {"249197070", PHONE_HOME_CITY_AND_NUMBER},
+ {"33", PHONE_HOME_COUNTRY_CODE},
+ {"2", PHONE_HOME_CITY_CODE},
+
+ // Credit card fields matches.
+ {"John Doe", CREDIT_CARD_NAME_FULL},
+ {"John", CREDIT_CARD_NAME_FIRST},
+ {"Doe", CREDIT_CARD_NAME_LAST},
+ {"4234-5678-9012-3456", CREDIT_CARD_NUMBER},
+ {"04", CREDIT_CARD_EXP_MONTH},
+ {"April", CREDIT_CARD_EXP_MONTH},
+ {"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR},
+ {"99", CREDIT_CARD_EXP_2_DIGIT_YEAR},
+ {"04/2999", CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
+
+ // Make sure whitespace and invalid characters are handled properly.
+ {"", EMPTY_TYPE},
+ {" ", EMPTY_TYPE},
+ {"***", UNKNOWN_TYPE},
+ {" Elvis", NAME_FIRST},
+ {"Elvis ", NAME_FIRST},
+
+ // Make sure fields that differ by case match.
+ {"elvis ", NAME_FIRST},
+ {"UnItEd StAtEs", ADDRESS_HOME_COUNTRY},
+
+ // Make sure fields that differ by punctuation match.
+ {"3734 Elvis Presley Blvd", ADDRESS_HOME_LINE1},
+ {"3734, Elvis Presley Blvd.", ADDRESS_HOME_LINE1},
+
+ // Make sure that a state's full name and abbreviation match.
+ {"TN", ADDRESS_HOME_STATE}, // Saved as "Tennessee" in profile.
+ {"Texas", ADDRESS_HOME_STATE}, // Saved as "TX" in profile.
+
+ // Special phone number case. A profile with no country code should only
+ // match PHONE_HOME_CITY_AND_NUMBER.
+ {"5142821292", PHONE_HOME_CITY_AND_NUMBER},
+
+ // Make sure unsupported variants do not match.
+ {"Elvis Aaron", UNKNOWN_TYPE},
+ {"Mr. Presley", UNKNOWN_TYPE},
+ {"3734 Elvis Presley", UNKNOWN_TYPE},
+ {"38116-1023", UNKNOWN_TYPE},
+ {"5", UNKNOWN_TYPE},
+ {"56", UNKNOWN_TYPE},
+ {"901", UNKNOWN_TYPE},
+};
+
// Tests that DeterminePossibleFieldTypesForUpload makes accurate matches.
-TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload) {
+TEST_P(ProfileMatchingTypesTest, DeterminePossibleFieldTypesForUpload) {
+ // Unpack the test paramters
+ const auto& test_case = std::get<0>(GetParam());
+ const auto& validity_state =
+ static_cast<AutofillProfile::ValidityState>(std::get<1>(GetParam()));
+ const auto& vote_using_invalid_profile_data = std::get<2>(GetParam());
+
+ SCOPED_TRACE(base::StringPrintf(
+ "Test: input_value='%s', field_type=%s, validity_state=%d, "
+ "ignore_invalid_profile_data=%d",
+ test_case.input_value,
+ AutofillType(test_case.field_type).ToString().c_str(), validity_state,
+ vote_using_invalid_profile_data));
+
+ ASSERT_LE(AutofillProfile::UNVALIDATED, validity_state);
+ ASSERT_LE(validity_state, AutofillProfile::UNSUPPORTED);
+
+ // Enable/Disable ignoring invalid profile data for the scope of this test.
+ base::test::ScopedFeatureList sfl;
+ if (vote_using_invalid_profile_data) {
+ sfl.InitAndEnableFeature(kAutofillVoteUsingInvalidProfileData);
+ } else {
+ sfl.InitAndDisableFeature(kAutofillVoteUsingInvalidProfileData);
+ }
+
// Set up the test profiles.
std::vector<AutofillProfile> profiles;
- AutofillProfile profile;
- test::SetProfileInfo(&profile, "Elvis", "Aaron", "Presley",
+ profiles.resize(3);
+ test::SetProfileInfo(&profiles[0], "Elvis", "Aaron", "Presley",
"theking@gmail.com", "RCA", "3734 Elvis Presley Blvd.",
"Apt. 10", "Memphis", "Tennessee", "38116", "US",
"+1 (234) 567-8901");
- profile.set_guid("00000000-0000-0000-0000-000000000001");
- profiles.push_back(profile);
- test::SetProfileInfo(&profile, "Charles", "", "Holley", "buddy@gmail.com",
+ profiles[0].set_guid("00000000-0000-0000-0000-000000000001");
+
+ test::SetProfileInfo(&profiles[1], "Charles", "", "Holley", "buddy@gmail.com",
"Decca", "123 Apple St.", "unit 6", "Lubbock", "TX",
"79401", "US", "5142821292");
- profile.set_guid("00000000-0000-0000-0000-000000000002");
- profiles.push_back(profile);
- test::SetProfileInfo(&profile, "Charles", "", "Baudelaire",
+ profiles[1].set_guid("00000000-0000-0000-0000-000000000002");
+
+ test::SetProfileInfo(&profiles[2], "Charles", "", "Baudelaire",
"lesfleursdumal@gmail.com", "", "108 Rue Saint-Lazare",
"Apt. 10", "Paris", "Île de France", "75008", "FR",
"+33 2 49 19 70 70");
- profile.set_guid("00000000-0000-0000-0000-000000000001");
- profiles.push_back(profile);
+ profiles[2].set_guid("00000000-0000-0000-0000-000000000001");
+
+ // Set the validity state for the matching field type.
+ if (test_case.field_type != EMPTY_TYPE &&
+ test_case.field_type != UNKNOWN_TYPE) {
+ auto field_type = test_case.field_type;
+ auto field_type_group = AutofillType(field_type).group();
+ if (field_type_group != CREDIT_CARD) {
+ if (field_type_group == PHONE_HOME || field_type_group == PHONE_BILLING)
+ field_type = PHONE_HOME_WHOLE_NUMBER;
+ for (auto& profile : profiles) {
+ profile.SetValidityState(test_case.field_type, validity_state);
+ }
+ }
+ }
// Set up the test credit cards.
std::vector<CreditCard> credit_cards;
@@ -4443,122 +4623,56 @@ TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload) {
credit_card.set_guid("00000000-0000-0000-0000-000000000003");
credit_cards.push_back(credit_card);
- typedef struct {
- std::string input_value; // The value to input in the field.
- ServerFieldType field_type; // The expected field type to be determined.
- } TestCase;
-
- TestCase test_cases[] = {
- // Profile fields matches.
- {"Elvis", NAME_FIRST},
- {"Aaron", NAME_MIDDLE},
- {"A", NAME_MIDDLE_INITIAL},
- {"Presley", NAME_LAST},
- {"Elvis Aaron Presley", NAME_FULL},
- {"theking@gmail.com", EMAIL_ADDRESS},
- {"RCA", COMPANY_NAME},
- {"3734 Elvis Presley Blvd.", ADDRESS_HOME_LINE1},
- {"Apt. 10", ADDRESS_HOME_LINE2},
- {"Memphis", ADDRESS_HOME_CITY},
- {"Tennessee", ADDRESS_HOME_STATE},
- {"38116", ADDRESS_HOME_ZIP},
- {"USA", ADDRESS_HOME_COUNTRY},
- {"United States", ADDRESS_HOME_COUNTRY},
- {"12345678901", PHONE_HOME_WHOLE_NUMBER},
- {"+1 (234) 567-8901", PHONE_HOME_WHOLE_NUMBER},
- {"(234)567-8901", PHONE_HOME_CITY_AND_NUMBER},
- {"2345678901", PHONE_HOME_CITY_AND_NUMBER},
- {"1", PHONE_HOME_COUNTRY_CODE},
- {"234", PHONE_HOME_CITY_CODE},
- {"5678901", PHONE_HOME_NUMBER},
- {"567", PHONE_HOME_NUMBER},
- {"8901", PHONE_HOME_NUMBER},
-
- // Test a European profile.
- {"Paris", ADDRESS_HOME_CITY},
- {"Île de France", ADDRESS_HOME_STATE}, // Exact match
- {"Ile de France", ADDRESS_HOME_STATE}, // Missing accent.
- {"-Ile-de-France-", ADDRESS_HOME_STATE}, // Extra punctuation.
- {"île dÉ FrÃÑÇË", ADDRESS_HOME_STATE}, // Other accents & case mismatch.
- {"75008", ADDRESS_HOME_ZIP},
- {"FR", ADDRESS_HOME_COUNTRY},
- {"France", ADDRESS_HOME_COUNTRY},
- {"33249197070", PHONE_HOME_WHOLE_NUMBER},
- {"+33 2 49 19 70 70", PHONE_HOME_WHOLE_NUMBER},
- {"2 49 19 70 70", PHONE_HOME_CITY_AND_NUMBER},
- {"249197070", PHONE_HOME_CITY_AND_NUMBER},
- {"33", PHONE_HOME_COUNTRY_CODE},
- {"2", PHONE_HOME_CITY_CODE},
-
- // Credit card fields matches.
- {"John Doe", CREDIT_CARD_NAME_FULL},
- {"John", CREDIT_CARD_NAME_FIRST},
- {"Doe", CREDIT_CARD_NAME_LAST},
- {"4234-5678-9012-3456", CREDIT_CARD_NUMBER},
- {"04", CREDIT_CARD_EXP_MONTH},
- {"April", CREDIT_CARD_EXP_MONTH},
- {"2999", CREDIT_CARD_EXP_4_DIGIT_YEAR},
- {"99", CREDIT_CARD_EXP_2_DIGIT_YEAR},
- {"04/2999", CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR},
-
- // Make sure whitespace and invalid characters are handled properly.
- {"", EMPTY_TYPE},
- {" ", EMPTY_TYPE},
- {"***", UNKNOWN_TYPE},
- {" Elvis", NAME_FIRST},
- {"Elvis ", NAME_FIRST},
-
- // Make sure fields that differ by case match.
- {"elvis ", NAME_FIRST},
- {"UnItEd StAtEs", ADDRESS_HOME_COUNTRY},
-
- // Make sure fields that differ by punctuation match.
- {"3734 Elvis Presley Blvd", ADDRESS_HOME_LINE1},
- {"3734, Elvis Presley Blvd.", ADDRESS_HOME_LINE1},
-
- // Make sure that a state's full name and abbreviation match.
- {"TN", ADDRESS_HOME_STATE}, // Saved as "Tennessee" in profile.
- {"Texas", ADDRESS_HOME_STATE}, // Saved as "TX" in profile.
-
- // Special phone number case. A profile with no country code should only
- // match PHONE_HOME_CITY_AND_NUMBER.
- {"5142821292", PHONE_HOME_CITY_AND_NUMBER},
-
- // Make sure unsupported variants do not match.
- {"Elvis Aaron", UNKNOWN_TYPE},
- {"Mr. Presley", UNKNOWN_TYPE},
- {"3734 Elvis Presley", UNKNOWN_TYPE},
- {"38116-1023", UNKNOWN_TYPE},
- {"5", UNKNOWN_TYPE},
- {"56", UNKNOWN_TYPE},
- {"901", UNKNOWN_TYPE}};
-
- for (TestCase test_case : test_cases) {
- FormData form;
- form.name = ASCIIToUTF16("MyForm");
- form.origin = GURL("http://myform.com/form.html");
- form.action = GURL("http://myform.com/submit.html");
-
- FormFieldData field;
- test::CreateTestFormField("", "1", "", "text", &field);
- field.value = UTF8ToUTF16(test_case.input_value);
- form.fields.push_back(field);
-
- FormStructure form_structure(form);
+ FormData form;
+ form.name = ASCIIToUTF16("MyForm");
+ form.origin = GURL("http://myform.com/form.html");
+ form.action = GURL("http://myform.com/submit.html");
- AutofillManager::DeterminePossibleFieldTypesForUpload(
- profiles, credit_cards, "en-us", &form_structure);
+ FormFieldData field;
+ test::CreateTestFormField("", "1", "", "text", &field);
+ field.value = UTF8ToUTF16(test_case.input_value);
+ form.fields.push_back(field);
- ASSERT_EQ(1U, form_structure.field_count());
- ServerFieldTypeSet possible_types =
- form_structure.field(0)->possible_types();
- EXPECT_EQ(1U, possible_types.size());
+ FormStructure form_structure(form);
- EXPECT_NE(possible_types.end(), possible_types.find(test_case.field_type))
- << "Failed to determine type for: \"" << test_case.input_value << "\"";
+ base::HistogramTester histogram_tester;
+ AutofillManager::DeterminePossibleFieldTypesForUpload(
+ profiles, credit_cards, "en-us", &form_structure);
+
+ ASSERT_EQ(1U, form_structure.field_count());
+ ServerFieldTypeSet possible_types = form_structure.field(0)->possible_types();
+ EXPECT_EQ(1U, possible_types.size());
+
+ if (test_case.field_type != EMPTY_TYPE &&
+ AutofillProfile::IsValidationSupportedForType(test_case.field_type) &&
+ validity_state == AutofillProfile::INVALID) {
+ // There are two addresses in the US, every other type/value pair is unique.
+ int expected_count =
+ (test_case.field_type == ADDRESS_HOME_COUNTRY &&
+ base::StartsWith(test_case.input_value, "U",
+ base::CompareCase::INSENSITIVE_ASCII))
+ ? 2
+ : 1;
+ histogram_tester.ExpectBucketCount(
+ "Autofill.InvalidProfileData.UsedForMetrics",
+ vote_using_invalid_profile_data, expected_count);
+ EXPECT_EQ(*possible_types.begin(), vote_using_invalid_profile_data
+ ? test_case.field_type
+ : UNKNOWN_TYPE);
+ } else {
+ EXPECT_EQ(*possible_types.begin(), test_case.field_type);
}
}
+INSTANTIATE_TEST_CASE_P(
+ AutofillManagerTest,
+ ProfileMatchingTypesTest,
+ testing::Combine(
+ testing::ValuesIn(kProfileMatchingTypesTestCases),
+ testing::Range(static_cast<int>(AutofillProfile::UNVALIDATED),
+ static_cast<int>(AutofillProfile::UNSUPPORTED) + 1),
+ testing::Bool()));
+
// Tests that DeterminePossibleFieldTypesForUpload is called when a form is
// submitted.
TEST_F(AutofillManagerTest, DeterminePossibleFieldTypesForUpload_IsTriggered) {
@@ -4764,8 +4878,7 @@ TEST_F(AutofillManagerTest, DisambiguateUploadTypes) {
// Assign the specified predicted type for each field in the test case.
FormStructure form_structure(form);
for (size_t i = 0; i < test_fields.size(); ++i) {
- form_structure.field(i)->set_overall_server_type(
- test_fields[i].predicted_type);
+ form_structure.field(i)->set_server_type(test_fields[i].predicted_type);
}
AutofillManager::DeterminePossibleFieldTypesForUpload(
@@ -4873,11 +4986,8 @@ TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndUnfocus_Upload) {
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
gfx::RectF(), base::TimeTicks::Now());
- autofill_manager_->ResetRunLoop();
// Simulate lost of focus on the form.
autofill_manager_->OnFocusNoLongerOnForm();
- // Wait for upload to complete (will check expected types as well).
- autofill_manager_->WaitForAsyncUploadProcess();
}
// Test that navigating with a filled form sends an upload with types matching
@@ -4926,11 +5036,8 @@ TEST_F(AutofillManagerTest, OnTextFieldDidChangeAndNavigation_Upload) {
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
gfx::RectF(), base::TimeTicks::Now());
- autofill_manager_->ResetRunLoop();
// Simulate a navigation so that the pending form is uploaded.
autofill_manager_->Reset();
- // Wait for upload to complete (will check expected types as well).
- autofill_manager_->WaitForAsyncUploadProcess();
}
// Test that unfocusing a filled form sends an upload with types matching the
@@ -4977,11 +5084,8 @@ TEST_F(AutofillManagerTest, OnDidFillAutofillFormDataAndUnfocus_Upload) {
form.fields[2].value = ASCIIToUTF16("theking@gmail.com");
autofill_manager_->OnDidFillAutofillFormData(form, base::TimeTicks::Now());
- autofill_manager_->ResetRunLoop();
// Simulate lost of focus on the form.
autofill_manager_->OnFocusNoLongerOnForm();
- // Wait for upload to complete.
- autofill_manager_->WaitForAsyncUploadProcess();
}
// Test that suggestions are returned for credit card fields with an
@@ -5074,8 +5178,9 @@ TEST_F(AutofillManagerTest,
CheckSuggestions(
kDefaultPageID,
- Suggestion(std::string("Visa") + kUTF8MidlineEllipsis + "3456", "04/99",
- kVisaCard, autofill_manager_->GetPackedCreditCardID(4)));
+ Suggestion(
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456"),
+ "04/99", kVisaCard, autofill_manager_->GetPackedCreditCardID(4)));
}
// Test that inputs detected to be CVC inputs are forced to
@@ -5282,9 +5387,10 @@ TEST_F(AutofillManagerTest, DisplayCreditCardSuggestionsWithMatchingTokens) {
#if defined(OS_ANDROID)
static const std::string kVisaSuggestion =
- std::string("Visa") + kUTF8MidlineEllipsis + "3456";
+ std::string("Visa ") + test::ObfuscatedCardDigitsAsUTF8("3456");
#else
- static const std::string kVisaSuggestion = "*3456";
+ static const std::string kVisaSuggestion =
+ test::ObfuscatedCardDigitsAsUTF8("3456");
#endif
CheckSuggestions(kDefaultPageID,
@@ -5313,6 +5419,45 @@ TEST_F(AutofillManagerTest, NoCreditCardSuggestionsForNonPrefixTokenMatch) {
EXPECT_FALSE(external_delegate_->on_suggestions_returned_seen());
}
+TEST_F(AutofillManagerTest, GetPopupType_CreditCardForm) {
+ // Set up our form data.
+ FormData form;
+ CreateTestCreditCardFormData(&form, true, false);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ for (const FormFieldData& field : form.fields) {
+ EXPECT_EQ(PopupType::kCreditCards,
+ autofill_manager_->GetPopupType(form, field));
+ }
+}
+
+TEST_F(AutofillManagerTest, GetPopupType_AddressForm) {
+ // Set up our form data.
+ FormData form;
+ test::CreateTestAddressFormData(&form);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ for (const FormFieldData& field : form.fields) {
+ EXPECT_EQ(PopupType::kAddresses,
+ autofill_manager_->GetPopupType(form, field));
+ }
+}
+
+TEST_F(AutofillManagerTest, GetPopupType_PersonalInformationForm) {
+ // Set up our form data.
+ FormData form;
+ test::CreateTestPersonalInformationFormData(&form);
+ std::vector<FormData> forms(1, form);
+ FormsSeen(forms);
+
+ for (const FormFieldData& field : form.fields) {
+ EXPECT_EQ(PopupType::kPersonalInformation,
+ autofill_manager_->GetPopupType(form, field));
+ }
+}
+
// Test that ShouldShowCreditCardSigninPromo behaves as expected for a credit
// card form with an impression limit of three and no impressions yet.
TEST_F(AutofillManagerTest,
@@ -5883,7 +6028,6 @@ TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) {
autofill_manager_->SetExpectedSubmittedFieldTypes(expected_types);
autofill_manager_->SetExpectedObservedSubmission(true);
autofill_manager_->SetCallParentUploadFormData(true);
- autofill_manager_->ResetRunLoop();
std::unique_ptr<FormStructure> form_structure(new FormStructure(form));
form_structure->set_is_signin_upload(true);
@@ -5896,11 +6040,8 @@ TEST_F(AutofillManagerTest, SignInFormSubmission_Upload) {
EXPECT_CALL(*download_manager_,
StartUploadRequest(_, false, _, std::string(), true))
.WillOnce(DoAll(SaveArg<2>(&uploaded_available_types), Return(true)));
- autofill_manager_->StartUploadProcess(std::move(form_structure),
- base::TimeTicks::Now(), true);
-
- // Wait for upload to complete (will check expected types as well).
- autofill_manager_->WaitForAsyncUploadProcess();
+ autofill_manager_->MaybeStartVoteUploadProcess(std::move(form_structure),
+ base::TimeTicks::Now(), true);
EXPECT_EQ(signature, autofill_manager_->GetSubmittedFormSignature());
EXPECT_NE(uploaded_available_types.end(),
diff --git a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
index 87dc8149da5..2d29dc4284f 100644
--- a/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_merge_unittest.cc
@@ -57,7 +57,7 @@ const ServerFieldType kProfileFieldTypes[] = {NAME_FIRST,
const base::FilePath& GetTestDataDir() {
CR_DEFINE_STATIC_LOCAL(base::FilePath, dir, ());
if (dir.empty()) {
- PathService::Get(base::DIR_SOURCE_ROOT, &dir);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &dir);
dir = dir.AppendASCII("components");
dir = dir.AppendASCII("test");
dir = dir.AppendASCII("data");
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.cc b/chromium/components/autofill/core/browser/autofill_metrics.cc
index 8484eac58dd..9098b92214b 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics.cc
@@ -891,7 +891,7 @@ void AutofillMetrics::LogServerPredictionQualityMetrics(
QualityMetricType metric_type) {
LogPredictionQualityMetrics(
PREDICTION_SOURCE_SERVER,
- AutofillType(field.overall_server_type()).GetStorableType(),
+ AutofillType(field.server_type()).GetStorableType(),
form_interactions_ukm_logger, form, field, metric_type,
false /*log_rationalization_metrics*/);
}
@@ -1150,6 +1150,12 @@ void AutofillMetrics::LogNumberOfCreditCardsDeletedForDisuse(size_t num_cards) {
}
// static
+void AutofillMetrics::LogHiddenOrPresentationalSelectFieldsFilled() {
+ UMA_HISTOGRAM_BOOLEAN("Autofill.HiddenOrPresentationalSelectFieldsFilled",
+ true);
+}
+
+// static
void AutofillMetrics::LogNumberOfProfilesAtAutofillableFormSubmission(
size_t num_profiles) {
UMA_HISTOGRAM_COUNTS(
@@ -1230,6 +1236,7 @@ void AutofillMetrics::LogAutofillFormSubmittedState(
bool is_for_credit_card,
const std::set<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp,
+ FormSignature form_signature,
AutofillMetrics::FormInteractionsUkmLogger* form_interactions_ukm_logger) {
UMA_HISTOGRAM_ENUMERATION("Autofill.FormSubmittedState", state,
AUTOFILL_FORM_SUBMITTED_STATE_ENUM_SIZE);
@@ -1265,7 +1272,8 @@ void AutofillMetrics::LogAutofillFormSubmittedState(
break;
}
form_interactions_ukm_logger->LogFormSubmitted(is_for_credit_card, form_types,
- state, form_parsed_timestamp);
+ state, form_parsed_timestamp,
+ form_signature);
}
// static
@@ -1334,7 +1342,8 @@ void AutofillMetrics::LogDeveloperEngagementUkm(
const GURL& url,
bool is_for_credit_card,
std::set<FormType> form_types,
- int developer_engagement_metrics) {
+ int developer_engagement_metrics,
+ FormSignature form_signature) {
DCHECK(developer_engagement_metrics);
DCHECK_LT(developer_engagement_metrics,
1 << NUM_DEVELOPER_ENGAGEMENT_METRICS);
@@ -1345,6 +1354,7 @@ void AutofillMetrics::LogDeveloperEngagementUkm(
.SetDeveloperEngagement(developer_engagement_metrics)
.SetIsForCreditCard(is_for_credit_card)
.SetFormTypes(FormTypesToBitVector(form_types))
+ .SetFormSignature(HashFormSignature(form_signature))
.Record(ukm_recorder);
}
@@ -1366,12 +1376,13 @@ AutofillMetrics::FormEventLogger::FormEventLogger(
logged_suggestion_filled_was_masked_server_card_(false),
form_interactions_ukm_logger_(form_interactions_ukm_logger) {}
-void AutofillMetrics::FormEventLogger::OnDidInteractWithAutofillableForm() {
+void AutofillMetrics::FormEventLogger::OnDidInteractWithAutofillableForm(
+ FormSignature form_signature) {
if (!has_logged_interacted_) {
has_logged_interacted_ = true;
form_interactions_ukm_logger_->LogInteractedWithForm(
is_for_credit_card_, local_record_type_count_,
- server_record_type_count_);
+ server_record_type_count_, form_signature);
Log(AutofillMetrics::FORM_EVENT_INTERACTED_ONCE);
}
}
@@ -1396,10 +1407,11 @@ void AutofillMetrics::FormEventLogger::OnDidPollSuggestions(
}
void AutofillMetrics::FormEventLogger::OnDidShowSuggestions(
+ const FormStructure& form,
const AutofillField& field,
const base::TimeTicks& form_parsed_timestamp) {
- form_interactions_ukm_logger_->LogSuggestionsShown(field,
- form_parsed_timestamp);
+ form_interactions_ukm_logger_->LogSuggestionsShown(
+ form, field, form_parsed_timestamp);
Log(AutofillMetrics::FORM_EVENT_SUGGESTIONS_SHOWN);
if (!has_logged_suggestions_shown_) {
@@ -1436,10 +1448,11 @@ void AutofillMetrics::FormEventLogger::OnDidSelectMaskedServerCardSuggestion(
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
const CreditCard& credit_card,
- const base::TimeTicks& form_parsed_timestamp) {
+ const FormStructure& form,
+ const AutofillField& field) {
DCHECK(is_for_credit_card_);
form_interactions_ukm_logger_->LogDidFillSuggestion(
- static_cast<int>(credit_card.record_type()), form_parsed_timestamp);
+ static_cast<int>(credit_card.record_type()), form, field);
if (credit_card.record_type() == CreditCard::MASKED_SERVER_CARD)
Log(AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED);
@@ -1479,10 +1492,11 @@ void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
void AutofillMetrics::FormEventLogger::OnDidFillSuggestion(
const AutofillProfile& profile,
- const base::TimeTicks& form_parsed_timestamp) {
+ const FormStructure& form,
+ const AutofillField& field) {
DCHECK(!is_for_credit_card_);
form_interactions_ukm_logger_->LogDidFillSuggestion(
- static_cast<int>(profile.record_type()), form_parsed_timestamp);
+ static_cast<int>(profile.record_type()), form, field);
if (profile.record_type() == AutofillProfile::SERVER_PROFILE)
Log(AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_FILLED);
@@ -1565,6 +1579,22 @@ void AutofillMetrics::FormEventLogger::SetBankNameAvailable() {
has_logged_bank_name_available_ = true;
}
+void AutofillMetrics::FormEventLogger::OnDidSeeDynamicForm() {
+ Log(AutofillMetrics::FORM_EVENT_DID_SEE_DYNAMIC_FORM);
+}
+
+void AutofillMetrics::FormEventLogger::OnDidSeeFillableDynamicForm() {
+ Log(AutofillMetrics::FORM_EVENT_DID_SEE_FILLABLE_DYNAMIC_FORM);
+}
+
+void AutofillMetrics::FormEventLogger::OnDidRefill() {
+ Log(AutofillMetrics::FORM_EVENT_DID_DYNAMIC_REFILL);
+}
+
+void AutofillMetrics::FormEventLogger::OnSubsequentRefillAttempt() {
+ Log(AutofillMetrics::FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL);
+}
+
void AutofillMetrics::FormEventLogger::Log(FormEvent event) const {
DCHECK_LT(event, NUM_FORM_EVENTS);
std::string name("Autofill.FormEvents.");
@@ -1616,7 +1646,8 @@ void AutofillMetrics::FormInteractionsUkmLogger::OnFormsParsed(
void AutofillMetrics::FormInteractionsUkmLogger::LogInteractedWithForm(
bool is_for_credit_card,
size_t local_record_type_count,
- size_t server_record_type_count) {
+ size_t server_record_type_count,
+ FormSignature form_signature) {
if (!CanLog())
return;
@@ -1627,10 +1658,12 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogInteractedWithForm(
.SetIsForCreditCard(is_for_credit_card)
.SetLocalRecordTypeCount(local_record_type_count)
.SetServerRecordTypeCount(server_record_type_count)
+ .SetFormSignature(HashFormSignature(form_signature))
.Record(ukm_recorder_);
}
void AutofillMetrics::FormInteractionsUkmLogger::LogSuggestionsShown(
+ const FormStructure& form,
const AutofillField& field,
const base::TimeTicks& form_parsed_timestamp) {
if (!CanLog())
@@ -1642,7 +1675,9 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogSuggestionsShown(
ukm::builders::Autofill_SuggestionsShown(source_id_)
.SetHeuristicType(static_cast<int>(field.heuristic_type()))
.SetHtmlFieldType(static_cast<int>(field.html_type()))
- .SetServerType(static_cast<int>(field.overall_server_type()))
+ .SetServerType(static_cast<int>(field.server_type()))
+ .SetFormSignature(HashFormSignature(form.form_signature()))
+ .SetFieldSignature(HashFieldSignature(field.GetFieldSignature()))
.SetMillisecondsSinceFormParsed(
MillisecondsSinceFormParsed(form_parsed_timestamp))
.Record(ukm_recorder_);
@@ -1664,7 +1699,8 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogSelectedMaskedServerCard(
void AutofillMetrics::FormInteractionsUkmLogger::LogDidFillSuggestion(
int record_type,
- const base::TimeTicks& form_parsed_timestamp) {
+ const FormStructure& form,
+ const AutofillField& field) {
if (!CanLog())
return;
@@ -1674,7 +1710,9 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogDidFillSuggestion(
ukm::builders::Autofill_SuggestionFilled(source_id_)
.SetRecordType(record_type)
.SetMillisecondsSinceFormParsed(
- MillisecondsSinceFormParsed(form_parsed_timestamp))
+ MillisecondsSinceFormParsed(form.form_parsed_timestamp()))
+ .SetFormSignature(HashFormSignature(form.form_signature()))
+ .SetFieldSignature(HashFieldSignature(field.GetFieldSignature()))
.Record(ukm_recorder_);
}
@@ -1690,7 +1728,7 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogTextFieldDidChange(
ukm::builders::Autofill_TextFieldDidChange(source_id_)
.SetFieldTypeGroup(static_cast<int>(field.Type().group()))
.SetHeuristicType(static_cast<int>(field.heuristic_type()))
- .SetServerType(static_cast<int>(field.overall_server_type()))
+ .SetServerType(static_cast<int>(field.server_type()))
.SetHtmlFieldType(static_cast<int>(field.html_type()))
.SetHtmlFieldMode(static_cast<int>(field.html_mode()))
.SetIsAutofilled(field.is_autofilled)
@@ -1764,7 +1802,8 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
bool is_for_credit_card,
const std::set<FormType>& form_types,
AutofillFormSubmittedState state,
- const base::TimeTicks& form_parsed_timestamp) {
+ const base::TimeTicks& form_parsed_timestamp,
+ FormSignature form_signature) {
if (!CanLog())
return;
@@ -1774,7 +1813,8 @@ void AutofillMetrics::FormInteractionsUkmLogger::LogFormSubmitted(
ukm::builders::Autofill_FormSubmitted builder(source_id_);
builder.SetAutofillFormSubmittedState(static_cast<int>(state))
.SetIsForCreditCard(is_for_credit_card)
- .SetFormTypes(FormTypesToBitVector(form_types));
+ .SetFormTypes(FormTypesToBitVector(form_types))
+ .SetFormSignature(HashFormSignature(form_signature));
if (form_parsed_timestamp.is_null())
DCHECK(state == NON_FILLABLE_FORM_OR_NEW_DATA ||
state == FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS)
diff --git a/chromium/components/autofill/core/browser/autofill_metrics.h b/chromium/components/autofill/core/browser/autofill_metrics.h
index a4289248536..83c4bb39fc6 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics.h
+++ b/chromium/components/autofill/core/browser/autofill_metrics.h
@@ -203,14 +203,14 @@ class AutofillMetrics {
// The prompt was dismissed because the user clicked a legal message link.
SAVE_CARD_PROMPT_DISMISS_CLICK_LEGAL_MESSAGE,
- // The following _CVC_FIX_FLOW_ metrics are independent of the ones above.
- // For instance, accepting the CVC fix flow will trigger both
+ // The following _CVC_FIX_FLOW_ metrics are independent of the ones above,
+ // and were relevant when the CVC fix flow was active M62-M64. During that
+ // time, for instance, accepting the CVC fix flow would trigger both
// SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_ACCEPTED as well as
- // SAVE_CARD_PROMPT_END_ACCEPTED. They are split apart in order to track
+ // SAVE_CARD_PROMPT_END_ACCEPTED. They were split apart in order to track
// acceptance/abandonment rates of the multi-stage dialog user experience.
-
- // SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_DENIED is an impossible state because
- // the CVC fix flow uses a close button instead of a cancel button.
+ // (SAVE_CARD_PROMPT_CVC_FIX_FLOW_END_DENIED was an impossible state because
+ // the CVC fix flow uses a close button instead of a cancel button.)
// The prompt moved to a second stage that requested CVC from the user.
SAVE_CARD_PROMPT_CVC_FIX_FLOW_SHOWN,
@@ -496,6 +496,16 @@ class AutofillMetrics {
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_WRONG_SIZE_CARD,
FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_FAIL_LUHN_CHECK_CARD,
+ // The form was changed dynamically.
+ FORM_EVENT_DID_SEE_DYNAMIC_FORM,
+ // The form was changed dynamically and was fillable.
+ FORM_EVENT_DID_SEE_FILLABLE_DYNAMIC_FORM,
+ // There was a dynamic change of the form and it got re-filled
+ // automatically.
+ FORM_EVENT_DID_DYNAMIC_REFILL,
+ // The form dynamically changed another time after the refill.
+ FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL,
+
NUM_FORM_EVENTS,
};
@@ -665,13 +675,16 @@ class AutofillMetrics {
void OnFormsParsed(const GURL& url);
void LogInteractedWithForm(bool is_for_credit_card,
size_t local_record_type_count,
- size_t server_record_type_count);
- void LogSuggestionsShown(const AutofillField& field,
+ size_t server_record_type_count,
+ FormSignature form_signature);
+ void LogSuggestionsShown(const FormStructure& form,
+ const AutofillField& field,
const base::TimeTicks& form_parsed_timestamp);
void LogSelectedMaskedServerCard(
const base::TimeTicks& form_parsed_timestamp);
void LogDidFillSuggestion(int record_type,
- const base::TimeTicks& form_parsed_timestamp);
+ const FormStructure& form,
+ const AutofillField& field);
void LogTextFieldDidChange(const AutofillField& field,
const base::TimeTicks& form_parsed_timestamp);
void LogFieldFillStatus(const FormStructure& form,
@@ -687,7 +700,8 @@ class AutofillMetrics {
void LogFormSubmitted(bool is_for_credit_card,
const std::set<FormType>& form_types,
AutofillFormSubmittedState state,
- const base::TimeTicks& form_parsed_timestamp);
+ const base::TimeTicks& form_parsed_timestamp,
+ FormSignature form_signature);
// We initialize |url_| with the form's URL when we log the first form
// interaction. Later, we may update |url_| with the |source_url()| for the
@@ -926,6 +940,7 @@ class AutofillMetrics {
bool is_for_credit_card,
const std::set<FormType>& form_types,
const base::TimeTicks& form_parsed_timestamp,
+ FormSignature form_signature,
FormInteractionsUkmLogger* form_interactions_ukm_logger);
// This should be called when determining the heuristic types for a form's
@@ -969,7 +984,12 @@ class AutofillMetrics {
const GURL& url,
bool is_for_credit_card,
std::set<FormType> form_types,
- int developer_engagement_metrics);
+ int developer_engagement_metrics,
+ FormSignature form_signature);
+
+ // Log the number of hidden or presentational 'select' fields that were
+ // autofilled to support synthetic fields.
+ static void LogHiddenOrPresentationalSelectFieldsFilled();
// Logs the the |ukm_entry_name| with the specified |url| and the specified
// |metrics|. Returns whether the ukm was sucessfully logged.
@@ -1000,11 +1020,12 @@ class AutofillMetrics {
is_context_secure_ = is_context_secure;
}
- void OnDidInteractWithAutofillableForm();
+ void OnDidInteractWithAutofillableForm(FormSignature form_signature);
void OnDidPollSuggestions(const FormFieldData& field);
- void OnDidShowSuggestions(const AutofillField& field,
+ void OnDidShowSuggestions(const FormStructure& form,
+ const AutofillField& field,
const base::TimeTicks& form_parsed_timestamp);
void OnDidSelectMaskedServerCardSuggestion(
@@ -1013,10 +1034,12 @@ class AutofillMetrics {
// In case of masked cards, caller must make sure this gets called before
// the card is upgraded to a full card.
void OnDidFillSuggestion(const CreditCard& credit_card,
- const base::TimeTicks& form_parsed_timestamp);
+ const FormStructure& form,
+ const AutofillField& field);
void OnDidFillSuggestion(const AutofillProfile& profile,
- const base::TimeTicks& form_parsed_timestamp);
+ const FormStructure& form,
+ const AutofillField& field);
void OnWillSubmitForm();
@@ -1025,6 +1048,14 @@ class AutofillMetrics {
void SetBankNameAvailable();
+ void OnDidSeeDynamicForm();
+
+ void OnDidSeeFillableDynamicForm();
+
+ void OnDidRefill();
+
+ void OnSubsequentRefillAttempt();
+
private:
void Log(FormEvent event) const;
void Log(BankNameDisplayedFormEvent event) const;
diff --git a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
index fcf1e0ea451..9417d1f34b2 100644
--- a/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -94,7 +94,7 @@ void VerifyDeveloperEngagementUkm(
for (const auto* const entry : entries) {
ukm_recorder.ExpectEntrySourceHasUrl(entry,
GURL(form.main_frame_origin.GetURL()));
- EXPECT_EQ(3u, entry->metrics.size());
+ EXPECT_EQ(4u, entry->metrics.size());
ukm_recorder.ExpectEntryMetric(
entry, UkmDeveloperEngagementType::kDeveloperEngagementName,
expected_metric_value);
@@ -104,15 +104,18 @@ void VerifyDeveloperEngagementUkm(
ukm_recorder.ExpectEntryMetric(
entry, UkmDeveloperEngagementType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(form_types));
+ ukm_recorder.ExpectEntryMetric(
+ entry, UkmDeveloperEngagementType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form)));
}
}
MATCHER(CompareMetricsIgnoringMillisecondsSinceFormParsed, "") {
- const ukm::mojom::UkmMetric* lhs = ::testing::get<0>(arg).get();
+ const auto& lhs = ::testing::get<0>(arg);
const std::pair<const char*, int64_t>& rhs = ::testing::get<1>(arg);
- return lhs->metric_hash == base::HashMetricName(rhs.first) &&
- (lhs->value == rhs.second ||
- (lhs->value > 0 &&
+ return lhs.first == base::HashMetricName(rhs.first) &&
+ (lhs.second == rhs.second ||
+ (lhs.second > 0 &&
rhs.first ==
UkmSuggestionFilledType::kMillisecondsSinceFormParsedName));
}
@@ -145,7 +148,9 @@ void VerifySubmitFormUkm(const ukm::TestAutoSetUkmRecorder& ukm_recorder,
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmFormSubmittedType::kIsForCreditCardName, is_for_credit_card},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector(form_types)}}});
+ AutofillMetrics::FormTypesToBitVector(form_types)},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
}
void AppendFieldFillStatusUkm(const FormData& form,
@@ -439,7 +444,8 @@ TEST_F(AutofillMetricsTest, QualityMetrics) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// Heuristic predictions.
{
@@ -635,7 +641,8 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// Rationalization quality.
{
@@ -699,7 +706,8 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// Rationalization quality.
{
@@ -764,7 +772,8 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// Rationalization quality.
{
@@ -844,7 +853,8 @@ TEST_F(AutofillMetricsTest,
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// Rationalization quality.
{
@@ -1127,7 +1137,8 @@ TEST_P(QualityMetricsTest, Classification) {
// Run the form submission code while tracking the histograms.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
ExpectedUkmMetrics expected_ukm_metrics;
AppendFieldTypeUkm(form, heuristic_types, server_types, actual_types,
@@ -1356,9 +1367,7 @@ TEST_F(AutofillMetricsTest, QualityMetrics_NoSubmission) {
// Trigger a form upload and metrics by Resetting the manager.
base::HistogramTester histogram_tester;
- autofill_manager_->ResetRunLoop();
autofill_manager_->Reset();
- autofill_manager_->RunRunLoop();
// Heuristic predictions.
{
@@ -1633,7 +1642,8 @@ TEST_F(AutofillMetricsTest, UpiVirtualPaymentAddress) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.UserHappiness", AutofillMetrics::USER_DID_ENTER_UPI_VPA, 1);
@@ -1684,7 +1694,8 @@ TEST_F(AutofillMetricsTest, PredictedMetricsWithAutocomplete) {
// match what is in the test profile.
form.fields[1].value = base::ASCIIToUTF16("79401");
form.fields[2].value = base::ASCIIToUTF16("2345678901");
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
for (const std::string source : {"Heuristic", "Server", "Overall"}) {
std::string histogram_name =
@@ -1784,7 +1795,8 @@ TEST_F(AutofillMetricsTest, SaneMetricsWithCacheMismatch) {
// Simulate form submission.
base::HistogramTester histogram_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
for (const std::string source : {"Heuristic", "Server", "Overall"}) {
std::string aggregate_histogram =
@@ -1852,7 +1864,8 @@ TEST_F(AutofillMetricsTest, StoredProfileCountAutofillableFormSubmission) {
// Simulate form submission.
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// An autofillable form was submitted, and the number of stored profiles is
// logged.
@@ -1885,7 +1898,8 @@ TEST_F(AutofillMetricsTest, StoredProfileCountNonAutofillableFormSubmission) {
// Simulate form submission.
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// A non-autofillable form was submitted, and number of stored profiles is NOT
// logged.
@@ -1938,7 +1952,8 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields) {
TimeTicks());
// Simulate form submission.
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
// An autofillable form was submitted, and the number of edited autofilled
// fields is logged.
@@ -1989,9 +2004,7 @@ TEST_F(AutofillMetricsTest, NumberOfEditedAutofilledFields_NoSubmission) {
TimeTicks());
// We expect metrics to be logged when the manager is reset.
- autofill_manager_->ResetRunLoop();
autofill_manager_->Reset();
- autofill_manager_->RunRunLoop();
// An autofillable form was uploaded, and the number of edited autofilled
// fields is logged.
@@ -2145,7 +2158,7 @@ TEST_F(AutofillMetricsTest,
autofill_manager_->Reset();
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, form, /*is_for_credit_card=*/false,
+ test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
{FormType::ADDRESS_FORM},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITHOUT_TYPE_HINTS});
}
@@ -2196,7 +2209,7 @@ TEST_F(AutofillMetricsTest,
autofill_manager_->Reset();
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, form, /*is_for_credit_card=*/false,
+ test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
{FormType::ADDRESS_FORM},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS});
}
@@ -2239,7 +2252,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
autofill_manager_->Reset();
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, form, /*is_for_credit_card=*/false,
+ test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
/* UPI VPA has Unknown form type.*/
{FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE},
{AutofillMetrics::FORM_CONTAINS_UPI_VPA_HINT});
@@ -2257,7 +2270,7 @@ TEST_F(AutofillMetricsTest, UkmDeveloperEngagement_LogUpiVpaTypeHint) {
autofill_manager_->Reset();
VerifyDeveloperEngagementUkm(
- test_ukm_recorder_, form, /*is_for_credit_card=*/false,
+ test_ukm_recorder_, forms.back(), /*is_for_credit_card=*/false,
/* UPI VPA has Unknown form type.*/
{FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE},
{AutofillMetrics::FILLABLE_FORM_PARSED_WITH_TYPE_HINTS,
@@ -2621,6 +2634,7 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
{
base::UserActionTester user_action_tester;
std::string guid("10000000-0000-0000-0000-000000000001"); // local card
+ external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF());
external_delegate_->DidAcceptSuggestion(
ASCIIToUTF16("Test"),
autofill_manager_->MakeFrontendID(guid, std::string()), 0);
@@ -2643,7 +2657,8 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
{
base::UserActionTester user_action_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
EXPECT_EQ(1,
user_action_tester.GetActionCount("Autofill_OnWillSubmitForm"));
EXPECT_EQ(1, user_action_tester.GetActionCount(
@@ -2655,20 +2670,36 @@ TEST_F(AutofillMetricsTest, CreditCardCheckoutFlowUserActions) {
{{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NAME_FULL},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NAME_FULL}},
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NAME_FULL},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[0]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[1]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
// Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
// call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
// |autofill_manager_->FillOrPreviewForm|.
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
{{{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.front()))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.front()))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
// Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
// because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
VerifySubmitFormUkm(
@@ -2735,6 +2766,7 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
{
base::UserActionTester user_action_tester;
std::string guid("00000000-0000-0000-0000-000000000001"); // local profile.
+ external_delegate_->OnQuery(0, form, form.fields.front(), gfx::RectF());
external_delegate_->DidAcceptSuggestion(
ASCIIToUTF16("Test"),
autofill_manager_->MakeFrontendID(std::string(), guid), 0);
@@ -2757,7 +2789,8 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
{
base::UserActionTester user_action_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
EXPECT_EQ(1,
user_action_tester.GetActionCount("Autofill_OnWillSubmitForm"));
EXPECT_EQ(1, user_action_tester.GetActionCount(
@@ -2769,11 +2802,19 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
{{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName, ADDRESS_HOME_STATE},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, ADDRESS_HOME_STATE}},
+ {UkmTextFieldDidChangeType::kServerTypeName, ADDRESS_HOME_STATE},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[0]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName, ADDRESS_HOME_CITY},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, ADDRESS_HOME_CITY}}});
+ {UkmTextFieldDidChangeType::kServerTypeName, ADDRESS_HOME_CITY},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[1]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
// Expect 2 |FORM_EVENT_LOCAL_SUGGESTION_FILLED| events. First, from
// call to |external_delegate_->DidAcceptSuggestion|. Second, from call to
// |autofill_manager_->FillOrPreviewForm|.
@@ -2781,10 +2822,18 @@ TEST_F(AutofillMetricsTest, ProfileCheckoutFlowUserActions) {
test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
{{{UkmSuggestionFilledType::kRecordTypeName,
AutofillProfile::LOCAL_PROFILE},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.front()))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kRecordTypeName,
AutofillProfile::LOCAL_PROFILE},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.front()))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
// Expect |NON_FILLABLE_FORM_OR_NEW_DATA| in |AutofillFormSubmittedState|
// because |field.value| is empty in |DeterminePossibleFieldTypesForUpload|.
VerifySubmitFormUkm(test_ukm_recorder_, form,
@@ -3333,7 +3382,8 @@ TEST_F(AutofillMetricsTest, CreditCardFilledFormEvents) {
autofill_manager_->MakeFrontendID(guid, std::string()));
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"6011000990139424");
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -3600,7 +3650,8 @@ TEST_F(AutofillMetricsTest,
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD,
@@ -3640,7 +3691,8 @@ TEST_F(AutofillMetricsTest,
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::
@@ -3682,7 +3734,8 @@ TEST_F(AutofillMetricsTest,
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::
@@ -3726,7 +3779,8 @@ TEST_F(AutofillMetricsTest,
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::
@@ -3770,7 +3824,8 @@ TEST_F(AutofillMetricsTest,
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::
@@ -3819,7 +3874,8 @@ TEST_F(AutofillMetricsTest,
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.back(),
autofill_manager_->MakeFrontendID(guid, std::string()));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::
@@ -3867,7 +3923,8 @@ TEST_F(AutofillMetricsTest, ShouldNotLogFormEventNoCardForAddressForm) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUBMIT_WITHOUT_SELECTING_SUGGESTIONS_NO_CARD,
@@ -3908,7 +3965,8 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -3933,7 +3991,8 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 1);
@@ -3947,7 +4006,11 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
{UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
@@ -3967,12 +4030,10 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->ResetRunLoop();
autofill_manager_->OnFormSubmitted(
form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
- autofill_manager_->Reset();
// Trigger UploadFormDataAsyncCallback.
- autofill_manager_->RunRunLoop();
+ autofill_manager_->Reset();
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 1);
@@ -3986,7 +4047,11 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
{UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
@@ -4007,7 +4072,8 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(guid, std::string()));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4018,7 +4084,11 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
{{{UkmSuggestionFilledType::kRecordTypeName, CreditCard::LOCAL_CARD},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.front()))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
@@ -4040,7 +4110,8 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(guid, std::string()));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4052,7 +4123,11 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
{{{UkmSuggestionFilledType::kRecordTypeName,
CreditCard::FULL_SERVER_CARD},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.front()))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
@@ -4075,7 +4150,8 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
autofill_manager_->MakeFrontendID(guid, std::string()));
autofill_manager_->OnDidGetRealPan(AutofillClient::SUCCESS,
"6011000990139424");
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_MASKED_SERVER_CARD_SUGGESTION_FILLED, 1);
@@ -4088,7 +4164,11 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
{{{UkmSuggestionFilledType::kRecordTypeName,
CreditCard::MASKED_SERVER_CARD},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields.back()))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmSelectedMaskedServerCardType::kEntryName,
{{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
@@ -4116,14 +4196,16 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
{FormType::CREDIT_CARD_FORM});
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmFormSubmittedType::kEntryName,
@@ -4132,15 +4214,17 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmFormSubmittedType::kIsForCreditCardName, true},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector(
- {FormType::CREDIT_CARD_FORM})}},
+ AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmFormSubmittedType::kAutofillFormSubmittedStateName,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA},
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmFormSubmittedType::kIsForCreditCardName, true},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector(
- {FormType::CREDIT_CARD_FORM})}}});
+ AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
@@ -4189,7 +4273,8 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0);
@@ -4231,7 +4316,11 @@ TEST_F(AutofillMetricsTest, CreditCardSubmittedFormEvents) {
{UkmTextFieldDidChangeType::kHeuristicTypeName, CREDIT_CARD_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName,
HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER}}});
+ {UkmTextFieldDidChangeType::kServerTypeName, CREDIT_CARD_NUMBER},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifySubmitFormUkm(test_ukm_recorder_, form,
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA,
/*is_for_credit_card=*/true,
@@ -4274,7 +4363,8 @@ TEST_F(AutofillMetricsTest, CreditCardWillSubmitFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4292,7 +4382,8 @@ TEST_F(AutofillMetricsTest, CreditCardWillSubmitFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
@@ -4313,7 +4404,8 @@ TEST_F(AutofillMetricsTest, CreditCardWillSubmitFormEvents) {
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(guid, std::string()));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4335,7 +4427,8 @@ TEST_F(AutofillMetricsTest, CreditCardWillSubmitFormEvents) {
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(guid, std::string()));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SERVER_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4381,8 +4474,10 @@ TEST_F(AutofillMetricsTest, CreditCardWillSubmitFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4428,7 +4523,8 @@ TEST_F(AutofillMetricsTest, CreditCardWillSubmitFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_SUBMITTED_ONCE, 0);
@@ -4704,7 +4800,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4729,12 +4826,10 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// triggered.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->ResetRunLoop();
autofill_manager_->OnFormSubmitted(
form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
- autofill_manager_->Reset();
// Trigger UploadFormDataAsyncCallback.
- autofill_manager_->RunRunLoop();
+ autofill_manager_->Reset();
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4758,7 +4853,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
@@ -4779,7 +4875,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(std::string(), guid));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4796,8 +4893,10 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
@@ -4834,7 +4933,8 @@ TEST_F(AutofillMetricsTest, AddressSubmittedFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
@@ -4905,7 +5005,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
// Simulating submission with no filled data.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4923,7 +5024,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 1);
@@ -4944,7 +5046,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
autofill_manager_->FillOrPreviewForm(
AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
autofill_manager_->MakeFrontendID(std::string(), guid));
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_LOCAL_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -4961,8 +5064,10 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
// Simulating multiple submissions.
base::HistogramTester histogram_tester;
autofill_manager_->OnQueryFormFieldAutofill(0, form, field, gfx::RectF());
- autofill_manager_->SubmitForm(form);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0);
@@ -5008,7 +5113,8 @@ TEST_F(AutofillMetricsTest, AddressWillSubmitFormEvents) {
// interaction.
base::HistogramTester histogram_tester;
autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form, field);
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectBucketCount(
"Autofill.FormEvents.Address",
AutofillMetrics::FORM_EVENT_SUGGESTION_SHOWN_WILL_SUBMIT_ONCE, 0);
@@ -5276,7 +5382,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
@@ -5290,7 +5397,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -5309,7 +5418,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
@@ -5323,7 +5433,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -5344,7 +5456,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_NOT_SHOW_SUGGESTIONS,
@@ -5360,7 +5473,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
@@ -5377,7 +5492,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_NONE_DID_SHOW_SUGGESTIONS, 1);
@@ -5387,6 +5503,10 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
{{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))},
{UkmTextFieldDidChangeType::kHeuristicTypeName,
PHONE_HOME_WHOLE_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName,
@@ -5400,7 +5520,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -5419,7 +5541,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_SOME, 1);
@@ -5433,7 +5556,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -5453,7 +5578,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1);
@@ -5467,7 +5593,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -5490,7 +5618,8 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
kAutofillEnforceMinRequiredFieldsForHeuristics);
base::HistogramTester histogram_tester;
base::UserActionTester user_action_tester;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::NON_FILLABLE_FORM_OR_NEW_DATA, 1);
@@ -5504,7 +5633,9 @@ TEST_F(AutofillMetricsTest, AutofillFormSubmittedState) {
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector(
- {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})}});
+ {FormType::ADDRESS_FORM, FormType::UNKNOWN_FORM_TYPE})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -5560,7 +5691,8 @@ TEST_F(
form.fields[2].value = ASCIIToUTF16("12345678901");
form.fields[2].is_autofilled = true;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histogram_tester.ExpectUniqueSample(
"Autofill.FormSubmittedState",
AutofillMetrics::FILLABLE_FORM_AUTOFILLED_ALL, 1);
@@ -5576,7 +5708,9 @@ TEST_F(
{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmFormSubmittedType::kIsForCreditCardName, false},
{UkmFormSubmittedType::kFormTypesName,
- AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})}});
+ AutofillMetrics::FormTypesToBitVector({FormType::ADDRESS_FORM})},
+ {UkmFormSubmittedType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}});
VerifyFormInteractionUkm(test_ukm_recorder_, form,
UkmFormSubmittedType::kEntryName,
expected_form_submission_ukm_metrics);
@@ -6004,29 +6138,53 @@ TEST_F(AutofillMetricsTest, UserHappinessFormInteraction_AddressForm) {
{UkmTextFieldDidChangeType::kHeuristicTypeName,
PHONE_HOME_WHOLE_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName,
PHONE_HOME_WHOLE_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName,
PHONE_HOME_WHOLE_NUMBER},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}},
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
{UkmTextFieldDidChangeType::kHeuristicTypeName, EMAIL_ADDRESS},
{UkmTextFieldDidChangeType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
- {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA}}});
+ {UkmTextFieldDidChangeType::kServerTypeName, NO_SERVER_DATA},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[1]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmSuggestionFilledType::kEntryName,
{{{UkmSuggestionFilledType::kRecordTypeName,
AutofillProfile::LOCAL_PROFILE},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}},
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[0]))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}},
{{UkmSuggestionFilledType::kRecordTypeName,
AutofillProfile::LOCAL_PROFILE},
- {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0}}});
+ {UkmSuggestionFilledType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionFilledType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[2]))},
+ {UkmSuggestionFilledType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
VerifyFormInteractionUkm(
test_ukm_recorder_, form, UkmTextFieldDidChangeType::kEntryName,
{{{UkmTextFieldDidChangeType::kFieldTypeGroupName, NAME},
@@ -6097,7 +6255,9 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
{
base::HistogramTester histogram_tester;
autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
- autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromLoad.WithAutofill", 0);
@@ -6118,7 +6278,9 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
gfx::RectF(),
TimeTicks::FromInternalValue(3));
- autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromLoad.WithAutofill", 0);
@@ -6130,9 +6292,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
"Autofill.FillDuration.FromInteraction.WithoutAutofill", 14, 1);
// We expected an upload to be triggered when the manager is reset.
- autofill_manager_->ResetRunLoop();
autofill_manager_->Reset();
- autofill_manager_->RunRunLoop();
}
// Expect metric to be logged if the user autofilled the form.
@@ -6142,7 +6302,9 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
autofill_manager_->OnDidFillAutofillFormData(
form, TimeTicks::FromInternalValue(5));
- autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectUniqueSample(
"Autofill.FillDuration.FromLoad.WithAutofill", 16, 1);
@@ -6154,9 +6316,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
"Autofill.FillDuration.FromInteraction.WithoutAutofill", 0);
// We expected an upload to be triggered when the manager is reset.
- autofill_manager_->ResetRunLoop();
autofill_manager_->Reset();
- autofill_manager_->RunRunLoop();
}
// Expect metric to be logged if the user both manually filled some fields
@@ -6171,7 +6331,9 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
gfx::RectF(),
TimeTicks::FromInternalValue(3));
- autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectUniqueSample(
"Autofill.FillDuration.FromLoad.WithAutofill", 16, 1);
@@ -6183,9 +6345,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
"Autofill.FillDuration.FromInteraction.WithoutAutofill", 0);
// We expected an upload to be triggered when the manager is reset.
- autofill_manager_->ResetRunLoop();
autofill_manager_->Reset();
- autofill_manager_->RunRunLoop();
}
// Make sure that loading another form doesn't affect metrics from the first
@@ -6200,7 +6360,9 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
autofill_manager_->OnTextFieldDidChange(form, form.fields.front(),
gfx::RectF(),
TimeTicks::FromInternalValue(3));
- autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectUniqueSample(
"Autofill.FillDuration.FromLoad.WithAutofill", 16, 1);
@@ -6212,9 +6374,7 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
"Autofill.FillDuration.FromInteraction.WithoutAutofill", 0);
// We expected an upload to be triggered when the manager is reset.
- autofill_manager_->ResetRunLoop();
autofill_manager_->Reset();
- autofill_manager_->RunRunLoop();
}
// Make sure that submitting a form that was loaded later will report the
@@ -6224,8 +6384,9 @@ TEST_F(AutofillMetricsTest, FormFillDuration) {
autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
autofill_manager_->OnFormsSeen(second_forms,
TimeTicks::FromInternalValue(5));
- autofill_manager_->SubmitForm(second_form,
- TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(second_form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectTotalCount(
"Autofill.FillDuration.FromLoad.WithAutofill", 0);
@@ -6524,7 +6685,9 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
// submitted.
autofill_manager_->OnFormsSeen(forms, TimeTicks::FromInternalValue(1));
- autofill_manager_->SubmitForm(form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
AutofillMetrics::NEW_PROFILE_CREATED, 1);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -6536,7 +6699,9 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log EXISTING_PROFILE_USED for the metric since the same profile
// is submitted.
autofill_manager_->OnFormsSeen(second_forms, TimeTicks::FromInternalValue(1));
- autofill_manager_->SubmitForm(second_form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(second_form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
AutofillMetrics::NEW_PROFILE_CREATED, 1);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -6548,7 +6713,9 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log NEW_PROFILE_CREATED for the metric since a new profile is
// submitted.
autofill_manager_->OnFormsSeen(third_forms, TimeTicks::FromInternalValue(1));
- autofill_manager_->SubmitForm(third_form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(third_form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
AutofillMetrics::NEW_PROFILE_CREATED, 2);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -6560,7 +6727,9 @@ TEST_F(AutofillMetricsTest, ProfileActionOnFormSubmitted) {
// Expect to log EXISTING_PROFILE_UPDATED for the metric since the profile was
// updated.
autofill_manager_->OnFormsSeen(fourth_forms, TimeTicks::FromInternalValue(1));
- autofill_manager_->SubmitForm(fourth_form, TimeTicks::FromInternalValue(17));
+ autofill_manager_->OnFormSubmitted(fourth_form, false,
+ SubmissionSource::FORM_SUBMISSION,
+ TimeTicks::FromInternalValue(17));
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
AutofillMetrics::NEW_PROFILE_CREATED, 2);
histogram_tester.ExpectBucketCount("Autofill.ProfileActionOnFormSubmitted",
@@ -6689,14 +6858,6 @@ TEST_F(AutofillMetricsParseQueryResponseTest, PartialNoServerData) {
ElementsAre(Bucket(true, 2)));
}
-// Test that the Form-Not-Secure warning user action is recorded.
-TEST_F(AutofillMetricsTest, ShowHttpNotSecureExplanationUserAction) {
- EXPECT_CALL(autofill_client_,
- ExecuteCommand(POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
- external_delegate_->DidAcceptSuggestion(
- ASCIIToUTF16("Test"), POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE, 0);
-}
-
// Tests that credit card form submissions are logged specially when the form is
// on a non-secure page.
TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) {
@@ -6740,7 +6901,8 @@ TEST_F(AutofillMetricsTest, NonsecureCreditCardForm) {
// Simulate submitting the credit card form.
{
base::HistogramTester histograms;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histograms.ExpectBucketCount(
"Autofill.FormEvents.CreditCard.OnNonsecurePage",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_SUBMITTED_ONCE, 1);
@@ -6796,7 +6958,8 @@ TEST_F(AutofillMetricsTest,
// Simulate submitting the credit card form.
{
base::HistogramTester histograms;
- autofill_manager_->SubmitForm(form);
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, TimeTicks::Now());
histograms.ExpectBucketCount(
"Autofill.FormEvents.CreditCard",
AutofillMetrics::FORM_EVENT_NO_SUGGESTION_WILL_SUBMIT_ONCE, 1);
@@ -6833,16 +6996,17 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric) {
TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
GURL url("https://www.google.com");
int form_structure_metric = 1;
+ FormSignature form_signature = 100;
- AutofillMetrics::LogDeveloperEngagementUkm(&test_ukm_recorder_, url, true,
- {FormType::CREDIT_CARD_FORM},
- form_structure_metric);
+ AutofillMetrics::LogDeveloperEngagementUkm(
+ &test_ukm_recorder_, url, true, {FormType::CREDIT_CARD_FORM},
+ form_structure_metric, form_signature);
auto entries = test_ukm_recorder_.GetEntriesByName(
UkmDeveloperEngagementType::kEntryName);
EXPECT_EQ(1u, entries.size());
for (const auto* const entry : entries) {
test_ukm_recorder_.ExpectEntrySourceHasUrl(entry, url);
- EXPECT_EQ(3u, entry->metrics.size());
+ EXPECT_EQ(4u, entry->metrics.size());
test_ukm_recorder_.ExpectEntryMetric(
entry, UkmDeveloperEngagementType::kDeveloperEngagementName,
form_structure_metric);
@@ -6851,6 +7015,8 @@ TEST_F(AutofillMetricsTest, RecordDeveloperEngagementMetric) {
test_ukm_recorder_.ExpectEntryMetric(
entry, UkmDeveloperEngagementType::kFormTypesName,
AutofillMetrics::FormTypesToBitVector({FormType::CREDIT_CARD_FORM}));
+ test_ukm_recorder_.ExpectEntryMetric(
+ entry, UkmDeveloperEngagementType::kFormSignatureName, form_signature);
}
}
@@ -6870,4 +7036,141 @@ TEST_F(AutofillMetricsTest, RecordCardUploadDecisionMetric_NoUkmService) {
EXPECT_EQ(0ul, test_ukm_recorder_.entries_count());
}
+// Test the ukm recorded when Suggestion is shown.
+TEST_F(AutofillMetricsTest, AutofillSuggestionShownTest) {
+ RecreateCreditCards(true /* include_local_credit_card */,
+ false /* include_masked_server_credit_card */,
+ false /* include_full_server_credit_card */);
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example_cc.com/form.html");
+ form.action = GURL("http://example_cc.com/submit.html");
+ form.main_frame_origin =
+ url::Origin::Create(GURL("http://example_root_cc.com/form.html"));
+
+ FormFieldData field;
+ std::vector<ServerFieldType> field_types;
+ test::CreateTestFormField("Name on card", "cc-name", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_NAME_FULL);
+ test::CreateTestFormField("Credit card", "card", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_NUMBER);
+ test::CreateTestFormField("Month", "card_month", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(CREDIT_CARD_EXP_MONTH);
+ autofill_manager_->AddSeenForm(form, field_types, field_types);
+
+ // Simulate and Autofill query on credit card name field.
+ autofill_manager_->DidShowSuggestions(true /* is_new_popup */, form,
+ form.fields[0]);
+ VerifyFormInteractionUkm(
+ test_ukm_recorder_, form, UkmSuggestionsShownType::kEntryName,
+ {{{UkmSuggestionsShownType::kMillisecondsSinceFormParsedName, 0},
+ {UkmSuggestionsShownType::kHeuristicTypeName, CREDIT_CARD_NAME_FULL},
+ {UkmSuggestionsShownType::kHtmlFieldTypeName, HTML_TYPE_UNSPECIFIED},
+ {UkmSuggestionsShownType::kServerTypeName, CREDIT_CARD_NAME_FULL},
+ {UkmSuggestionsShownType::kFieldSignatureName,
+ Collapse(CalculateFieldSignatureForField(form.fields[0]))},
+ {UkmSuggestionsShownType::kFormSignatureName,
+ Collapse(CalculateFormSignature(form))}}});
+}
+
+TEST_F(AutofillMetricsTest, DynamicFormMetrics) {
+ scoped_feature_list_.InitWithFeatures(
+ {features::kAutofillDynamicForms},
+ {features::kAutofillRequireSecureCreditCardContext,
+ features::kAutofillRestrictUnownedFieldsToFormlessCheckout});
+
+ // Set up our form data.
+ FormData form;
+ form.name = ASCIIToUTF16("TestForm");
+ form.origin = GURL("http://example.com/form.html");
+ form.action = GURL("http://example.com/submit.html");
+ FormFieldData field;
+ std::vector<ServerFieldType> field_types;
+ test::CreateTestFormField("State", "state", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(ADDRESS_HOME_STATE);
+ test::CreateTestFormField("City", "city", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(ADDRESS_HOME_CITY);
+ test::CreateTestFormField("Street", "street", "", "text", &field);
+ form.fields.push_back(field);
+ field_types.push_back(ADDRESS_HOME_STREET_ADDRESS);
+
+ // Simulate seeing.
+ base::HistogramTester histogram_tester;
+ autofill_manager_->AddSeenForm(form, field_types, field_types);
+ std::string guid("00000000-0000-0000-0000-000000000001");
+
+ // Simulate checking whether to fill a dynamic form before the form was filled
+ // initially.
+ FormStructure form_structure(form);
+ autofill_manager_->ShouldTriggerRefill(form_structure);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_DYNAMIC_FORM, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_FILLABLE_DYNAMIC_FORM, 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_DYNAMIC_REFILL, 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, 0);
+
+ // Simulate filling the form.
+ autofill_manager_->FillOrPreviewForm(
+ AutofillDriver::FORM_DATA_ACTION_FILL, 0, form, form.fields.front(),
+ autofill_manager_->MakeFrontendID(std::string(), guid));
+
+ // Simulate checking whether to fill a dynamic form after the form was filled
+ // initially.
+ autofill_manager_->ShouldTriggerRefill(form_structure);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_DYNAMIC_FORM, 2);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_FILLABLE_DYNAMIC_FORM, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_DYNAMIC_REFILL, 0);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, 0);
+
+ // Trigger a refill, the refill metric should be updated.
+ autofill_manager_->TriggerRefill(form, &form_structure);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_DYNAMIC_FORM, 2);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_FILLABLE_DYNAMIC_FORM, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_DYNAMIC_REFILL, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, 0);
+
+ // Trigger a check to see whether a refill should happen. The
+ autofill_manager_->ShouldTriggerRefill(form_structure);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_DYNAMIC_FORM, 3);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_SEE_FILLABLE_DYNAMIC_FORM, 2);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DID_DYNAMIC_REFILL, 1);
+ histogram_tester.ExpectBucketCount(
+ "Autofill.FormEvents.Address",
+ AutofillMetrics::FORM_EVENT_DYNAMIC_CHANGE_AFTER_REFILL, 1);
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_popup_delegate.h b/chromium/components/autofill/core/browser/autofill_popup_delegate.h
index 4299f5c2d03..6e258d0dd1d 100644
--- a/chromium/components/autofill/core/browser/autofill_popup_delegate.h
+++ b/chromium/components/autofill/core/browser/autofill_popup_delegate.h
@@ -7,6 +7,7 @@
#include "base/callback_forward.h"
#include "base/strings/string16.h"
+#include "components/autofill/core/browser/popup_types.h"
namespace autofill {
@@ -47,8 +48,8 @@ class AutofillPopupDelegate {
// Informs the delegate that the Autofill previewed form should be cleared.
virtual void ClearPreviewedForm() = 0;
- // Returns true if popup is for credit card.
- virtual bool IsCreditCardPopup() = 0;
+ // Returns the type of the popup being shown.
+ virtual PopupType GetPopupType() const = 0;
// Returns the associated AutofillDriver.
virtual AutofillDriver* GetAutofillDriver() = 0;
diff --git a/chromium/components/autofill/core/browser/autofill_profile.cc b/chromium/components/autofill/core/browser/autofill_profile.cc
index cff037ad8c0..2154fa60b7c 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile.cc
@@ -25,6 +25,7 @@
#include "components/autofill/core/browser/address.h"
#include "components/autofill/core/browser/address_i18n.h"
#include "components/autofill/core/browser/autofill_country.h"
+#include "components/autofill/core/browser/autofill_experiments.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/autofill_profile_comparator.h"
@@ -35,6 +36,7 @@
#include "components/autofill/core/browser/state_names.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_l10n_util.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/strings/grit/components_strings.h"
@@ -192,10 +194,10 @@ void GetFieldsForDistinguishingProfiles(
}
// Constants for the validity bitfield.
-static const size_t kValidityBitsPerType = 2;
+const size_t kValidityBitsPerType = 2;
// The order is important to ensure a consistent bitfield value. New values
// should be added at the end NOT at the start or middle.
-static const ServerFieldType kSupportedTypesForValidation[] = {
+const ServerFieldType kSupportedTypesForValidation[] = {
ADDRESS_HOME_COUNTRY,
ADDRESS_HOME_STATE,
ADDRESS_HOME_ZIP,
@@ -204,13 +206,22 @@ static const ServerFieldType kSupportedTypesForValidation[] = {
EMAIL_ADDRESS,
PHONE_HOME_WHOLE_NUMBER};
-static const size_t kNumSupportedTypesForValidation =
+const size_t kNumSupportedTypesForValidation =
sizeof(kSupportedTypesForValidation) /
sizeof(kSupportedTypesForValidation[0]);
static_assert(kNumSupportedTypesForValidation * kValidityBitsPerType <= 64,
"Not enough bits to encode profile validity information!");
+// Some types are specializations of other types. Normalize these back to the
+// main stored type for used to mark field validity .
+ServerFieldType NormalizeTypeForValidityCheck(ServerFieldType type) {
+ auto field_type_group = AutofillType(type).group();
+ if (field_type_group == PHONE_HOME || field_type_group == PHONE_BILLING)
+ return PHONE_HOME_WHOLE_NUMBER;
+ return type;
+}
+
} // namespace
AutofillProfile::AutofillProfile(const std::string& guid,
@@ -278,9 +289,22 @@ void AutofillProfile::GetMatchingTypes(
const base::string16& text,
const std::string& app_locale,
ServerFieldTypeSet* matching_types) const {
+ ServerFieldTypeSet matching_types_in_this_profile;
FormGroupList info = FormGroups();
for (const auto* form_group : info) {
- form_group->GetMatchingTypes(text, app_locale, matching_types);
+ form_group->GetMatchingTypes(text, app_locale,
+ &matching_types_in_this_profile);
+ }
+ for (auto type : matching_types_in_this_profile) {
+ if (GetValidityState(type) == INVALID) {
+ bool vote_using_invalid_data =
+ base::FeatureList::IsEnabled(kAutofillVoteUsingInvalidProfileData);
+ UMA_HISTOGRAM_BOOLEAN("Autofill.InvalidProfileData.UsedForMetrics",
+ vote_using_invalid_data);
+ if (!vote_using_invalid_data)
+ continue;
+ }
+ matching_types->insert(type);
}
}
@@ -707,6 +731,7 @@ void AutofillProfile::RecordAndLogUse() {
AutofillProfile::ValidityState AutofillProfile::GetValidityState(
ServerFieldType type) const {
+ type = NormalizeTypeForValidityCheck(type);
// Return UNSUPPORTED for types that autofill does not validate.
if (!IsValidationSupportedForType(type))
return UNSUPPORTED;
@@ -724,7 +749,8 @@ void AutofillProfile::SetValidityState(ServerFieldType type,
validity_states_[type] = validity;
}
-bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) const {
+// static
+bool AutofillProfile::IsValidationSupportedForType(ServerFieldType type) {
for (auto supported_type : kSupportedTypesForValidation) {
if (type == supported_type)
return true;
diff --git a/chromium/components/autofill/core/browser/autofill_profile.h b/chromium/components/autofill/core/browser/autofill_profile.h
index f5a0644273f..c097d14cdcc 100644
--- a/chromium/components/autofill/core/browser/autofill_profile.h
+++ b/chromium/components/autofill/core/browser/autofill_profile.h
@@ -203,7 +203,7 @@ class AutofillProfile : public AutofillDataModel,
void SetValidityState(ServerFieldType type, ValidityState validity);
// Returns whether autofill does the validation of the specified |type|.
- bool IsValidationSupportedForType(ServerFieldType type) const;
+ static bool IsValidationSupportedForType(ServerFieldType type);
// Returns the bitfield value representing the validity state of this profile.
int GetValidityBitfieldValue() const;
diff --git a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
index 22934f970de..276979c8b10 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -60,14 +60,14 @@ std::vector<AutofillProfile*> ToRawPointerVector(
// Based on existence of first name, last name, and address line 1.
TEST(AutofillProfileTest, PreviewSummaryString) {
// Case 0/null: ""
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
// Empty profile - nothing to update.
base::string16 summary0 = GetLabel(&profile0);
EXPECT_EQ(base::string16(), summary0);
// Case 0a/empty name and address, so the first two fields of the rest of the
// data is used: "Hollywood, CA"
- AutofillProfile profile00(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile00(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile00, "", "", "",
"johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA", "91601", "US",
"16505678910");
@@ -75,7 +75,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("Hollywood, CA"), summary00);
// Case 1: "<address>" without line 2.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "", "", "",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "", "Hollywood", "CA",
"91601", "US", "16505678910");
@@ -83,7 +83,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("123 Zoo St., Hollywood"), summary1);
// Case 1a: "<address>" with line 2.
- AutofillProfile profile1a(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile1a(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1a, "", "", "",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
"91601", "US", "16505678910");
@@ -91,7 +91,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("123 Zoo St., unit 5"), summary1a);
// Case 2: "<lastname>"
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "", "Mitchell",
"Morrison", "johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA",
"91601", "US", "16505678910");
@@ -100,7 +100,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("Mitchell Morrison, Hollywood"), summary2);
// Case 3: "<lastname>, <address>"
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "", "Mitchell",
"Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "",
"Hollywood", "CA", "91601", "US", "16505678910");
@@ -108,7 +108,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("Mitchell Morrison, 123 Zoo St."), summary3);
// Case 4: "<firstname>"
- AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile4, "Marion", "Mitchell", "",
"johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA", "91601", "US",
"16505678910");
@@ -116,7 +116,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("Marion Mitchell, Hollywood"), summary4);
// Case 5: "<firstname>, <address>"
- AutofillProfile profile5(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile5(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile5, "Marion", "Mitchell", "",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
"91601", "US", "16505678910");
@@ -124,7 +124,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
EXPECT_EQ(ASCIIToUTF16("Marion Mitchell, 123 Zoo St."), summary5);
// Case 6: "<firstname> <lastname>"
- AutofillProfile profile6(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile6(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile6, "Marion", "Mitchell",
"Morrison", "johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA",
"91601", "US", "16505678910");
@@ -133,7 +133,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
summary6);
// Case 7: "<firstname> <lastname>, <address>"
- AutofillProfile profile7(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile7(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile7, "Marion", "Mitchell",
"Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "16505678910");
@@ -142,7 +142,7 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
// Case 7a: "<firstname> <lastname>, <address>" - same as #7, except for
// e-mail.
- AutofillProfile profile7a(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile7a(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile7a, "Marion", "Mitchell",
"Morrison", "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "16505678910");
@@ -162,8 +162,8 @@ TEST(AutofillProfileTest, PreviewSummaryString) {
TEST(AutofillProfileTest, AdjustInferredLabels) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[0].get(), "John", "", "Doe",
"johndoe@hades.com", "Underworld", "666 Erebus St.", "",
"Elysium", "CA", "91111", "US", "16502111111");
@@ -215,8 +215,8 @@ TEST(AutofillProfileTest, AdjustInferredLabels) {
EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."), labels[1]);
EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., CO"), labels[2]);
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[3].get(), "John", "", "Doe",
"johndoe@hades.com", "Underworld", "666 Erebus St.", "",
"Elysium", "CO", // State is different for some.
@@ -236,8 +236,8 @@ TEST(AutofillProfileTest, AdjustInferredLabels) {
EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., CO, 16504444444"),
labels[3]);
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[4].get(), "John", "", "Doe",
"johndoe@styx.com", // E-Mail is different for some.
"Underworld", "666 Erebus St.", "", "Elysium",
@@ -263,8 +263,8 @@ TEST(AutofillProfileTest, AdjustInferredLabels) {
TEST(AutofillProfileTest, CreateInferredLabelsI18n_CH) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles.back().get(), "H.", "R.", "Giger",
"hrgiger@beispiel.com", "Beispiel Inc",
"Brandschenkestrasse 110", "", "Zurich", "", "8002",
@@ -297,8 +297,8 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_CH) {
TEST(AutofillProfileTest, CreateInferredLabelsI18n_FR) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles.back().get(), "Antoine", "", "de Saint-Exupéry",
"antoine@exemple.com", "Exemple Inc", "8 Rue de Londres",
"", "Paris", "", "75009", "FR", "+33 (0) 1 42 68 53 00");
@@ -335,8 +335,8 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_FR) {
TEST(AutofillProfileTest, CreateInferredLabelsI18n_KR) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles.back().get(), "Park", "", "Jae-sang",
"park@yeleul.com", "Yeleul Inc",
"Gangnam Finance Center", "152 Teheran-ro", "Gangnam-Gu",
@@ -379,8 +379,8 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_KR) {
TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_Latn) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles.back().get(), "Miku", "", "Hatsune",
"miku@rei.com", "Rei Inc", "Roppongi Hills Mori Tower",
"6-10-1 Roppongi", "Minato-ku", "Tokyo", "106-6126",
@@ -417,8 +417,8 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_Latn) {
TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_ja) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles.back().get(), "ミク", "", "初音",
"miku@rei.com", "例", "六本木ヒルズ森タワー",
"六本木 6-10-1", "港区", "東京都", "106-6126", "JP",
@@ -451,13 +451,13 @@ TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_ja) {
TEST(AutofillProfileTest, CreateInferredLabels) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[0].get(), "John", "", "Doe",
"johndoe@hades.com", "Underworld", "666 Erebus St.", "",
"Elysium", "CA", "91111", "US", "16502111111");
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[1].get(), "Jane", "", "Doe",
"janedoe@tertium.com", "Pluto Inc.", "123 Letha Shore.",
"", "Dis", "CA", "91222", "US", "12345678910");
@@ -554,12 +554,12 @@ TEST(AutofillProfileTest, CreateInferredLabels) {
// distinguishing fields, but only if it makes sense given the suggested fields.
TEST(AutofillProfileTest, CreateInferredLabelsFallsBackToFullName) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
"", "88 Nowhere Ave.", "", "", "", "", "", "");
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[1].get(), "Johnny", "K", "Doe",
"doe@example.com", "", "88 Nowhere Ave.", "", "", "", "",
"", "");
@@ -591,12 +591,12 @@ TEST(AutofillProfileTest, CreateInferredLabelsFallsBackToFullName) {
// Test that we do not show duplicate fields in the labels.
TEST(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
"", "88 Nowhere Ave.", "", "", "", "", "", "");
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[1].get(), "John", "", "Doe", "dojo@example.com",
"", "88 Nowhere Ave.", "", "", "", "", "", "");
@@ -618,16 +618,16 @@ TEST(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) {
// Make sure that empty fields are not treated as distinguishing fields.
TEST(AutofillProfileTest, CreateInferredLabelsSkipsEmptyFields) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
"Gogole", "", "", "", "", "", "", "");
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[1].get(), "John", "", "Doe", "doe@example.com",
"Ggoole", "", "", "", "", "", "", "");
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[2].get(), "John", "", "Doe",
"john.doe@example.com", "Goolge", "", "", "", "", "", "",
"");
@@ -655,8 +655,8 @@ TEST(AutofillProfileTest, CreateInferredLabelsSkipsEmptyFields) {
// Test that labels that would otherwise have multiline values are flattened.
TEST(AutofillProfileTest, CreateInferredLabelsFlattensMultiLineValues) {
std::vector<std::unique_ptr<AutofillProfile>> profiles;
- profiles.push_back(std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com/"));
+ profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+ test::kEmptyOrigin));
test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
"", "88 Nowhere Ave.", "Apt. 42", "", "", "", "", "");
@@ -677,10 +677,8 @@ TEST(AutofillProfileTest, IsSubsetOf) {
std::unique_ptr<AutofillProfile> a, b;
// |a| is a subset of |b|.
- a.reset(
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
- b.reset(
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
+ a.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
+ b.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
test::SetProfileInfo(a.get(), "Thomas", nullptr, "Jefferson",
"declaration_guy@gmail.com", nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
@@ -697,10 +695,8 @@ TEST(AutofillProfileTest, IsSubsetOf) {
EXPECT_TRUE(a->IsSubsetOf(*a, "en-US"));
// One field in |b| is different.
- a.reset(
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
- b.reset(
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
+ a.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
+ b.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
test::SetProfileInfo(a.get(), "Thomas", nullptr, "Jefferson",
"declaration_guy@gmail.com", nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr, nullptr, nullptr);
@@ -797,14 +793,14 @@ TEST(AutofillProfileTest, OverwriteName_DifferentCase) {
}
TEST(AutofillProfileTest, AssignmentOperator) {
- AutofillProfile a(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile a(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
"marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US",
"12345678910");
// Result of assignment should be logically equal to the original profile.
- AutofillProfile b(base::GenerateGUID(), "http://www.example.com/");
+ AutofillProfile b(base::GenerateGUID(), test::kEmptyOrigin);
b = a;
EXPECT_TRUE(a == b);
@@ -814,7 +810,7 @@ TEST(AutofillProfileTest, AssignmentOperator) {
}
TEST(AutofillProfileTest, Copy) {
- AutofillProfile a(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile a(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
"marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US",
@@ -875,7 +871,7 @@ TEST(AutofillProfileTest, Compare) {
}
TEST(AutofillProfileTest, IsPresentButInvalid) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_STATE));
EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_ZIP));
EXPECT_FALSE(profile.IsPresentButInvalid(PHONE_HOME_WHOLE_NUMBER));
@@ -905,7 +901,7 @@ TEST(AutofillProfileTest, IsPresentButInvalid) {
}
TEST(AutofillProfileTest, SetRawInfoPreservesLineBreaks) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
ASCIIToUTF16("123 Super St.\n"
@@ -916,7 +912,7 @@ TEST(AutofillProfileTest, SetRawInfoPreservesLineBreaks) {
}
TEST(AutofillProfileTest, SetInfoPreservesLineBreaks) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
profile.SetInfo(ADDRESS_HOME_STREET_ADDRESS,
ASCIIToUTF16("123 Super St.\n"
@@ -928,7 +924,7 @@ TEST(AutofillProfileTest, SetInfoPreservesLineBreaks) {
}
TEST(AutofillProfileTest, SetRawInfoDoesntTrimWhitespace) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("\tuser@example.com "));
EXPECT_EQ(ASCIIToUTF16("\tuser@example.com "),
@@ -936,7 +932,7 @@ TEST(AutofillProfileTest, SetRawInfoDoesntTrimWhitespace) {
}
TEST(AutofillProfileTest, SetInfoTrimsWhitespace) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("\tuser@example.com "),
"en-US");
@@ -945,7 +941,7 @@ TEST(AutofillProfileTest, SetInfoTrimsWhitespace) {
}
TEST(AutofillProfileTest, FullAddress) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US",
@@ -1127,7 +1123,7 @@ TEST(AutofillProfileTest, ValidityStates_UnsupportedTypes) {
profile.GetValidityState(ADDRESS_HOME_LINE1));
EXPECT_EQ(AutofillProfile::UNSUPPORTED,
profile.GetValidityState(ADDRESS_HOME_LINE2));
- EXPECT_EQ(AutofillProfile::UNSUPPORTED,
+ EXPECT_EQ(AutofillProfile::UNVALIDATED,
profile.GetValidityState(PHONE_HOME_CITY_AND_NUMBER));
}
diff --git a/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc b/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
index f12dc1ddd5e..ce342da63c1 100644
--- a/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/autofill_profile_validation_util_unittest.cc
@@ -33,7 +33,7 @@ class AutofillProfileValidationUtilTest : public testing::Test,
protected:
AutofillProfileValidationUtilTest() {
base::FilePath file_path;
- CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
+ CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
file_path = file_path.Append(FILE_PATH_LITERAL("third_party"))
.Append(FILE_PATH_LITERAL("libaddressinput"))
.Append(FILE_PATH_LITERAL("src"))
diff --git a/chromium/components/autofill/core/browser/autofill_provider.h b/chromium/components/autofill/core/browser/autofill_provider.h
index cb986feb4bf..002b7051723 100644
--- a/chromium/components/autofill/core/browser/autofill_provider.h
+++ b/chromium/components/autofill/core/browser/autofill_provider.h
@@ -46,7 +46,7 @@ class AutofillProvider {
const FormFieldData& field,
const gfx::RectF& bounding_box) = 0;
- virtual bool OnFormSubmitted(AutofillHandlerProxy* handler,
+ virtual void OnFormSubmitted(AutofillHandlerProxy* handler,
const FormData& form,
bool known_success,
SubmissionSource source,
diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
index afa749b6d1b..9b91b1dc09d 100644
--- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
+++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/autofill/core/browser/autofill_experiments.h"
@@ -36,14 +37,8 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile(
save_card_callback_(save_card_callback),
pref_service_(pref_service),
had_user_interaction_(false),
-#if defined(OS_IOS)
- // TODO(jdonnelly): Use credit card issuer images on iOS.
- // http://crbug.com/535784
- issuer_icon_id_(kNoIconID),
-#else
issuer_icon_id_(CreditCard::IconResourceId(card.network())),
-#endif
- card_label_(base::string16(kMidlineEllipsis) + card.LastFourDigits()),
+ card_label_(card.NetworkAndLastFourDigits()),
card_sub_label_(card.AbbreviatedExpirationDateForDisplay()) {
if (legal_message) {
if (!LegalMessageLine::Parse(*legal_message, &legal_messages_,
@@ -55,10 +50,6 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile(
return;
}
}
- if (IsGooglePayBrandingEnabled()) {
- card_label_ = card.NetworkForDisplay() + base::string16(kMidlineEllipsis) +
- card.LastFourDigits();
- }
AutofillMetrics::LogCreditCardInfoBarMetric(
AutofillMetrics::INFOBAR_SHOWN, upload_,
@@ -86,16 +77,16 @@ bool AutofillSaveCardInfoBarDelegateMobile::LegalMessagesParsedSuccessfully() {
bool AutofillSaveCardInfoBarDelegateMobile::IsGooglePayBrandingEnabled() const {
return upload_ &&
base::FeatureList::IsEnabled(
- features::kAutofillUpstreamUseGooglePayOnAndroidBranding);
-}
-
-base::string16 AutofillSaveCardInfoBarDelegateMobile::GetTitleText() const {
- return l10n_util::GetStringUTF16(
- IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3);
+ features::kAutofillUpstreamUseGooglePayBrandingOnMobile);
}
base::string16 AutofillSaveCardInfoBarDelegateMobile::GetDescriptionText()
const {
+ // Without Google Pay branding, the title acts as the description (see
+ // |GetMessageText|).
+ if (!IsGooglePayBrandingEnabled())
+ return base::string16();
+
return IsAutofillUpstreamUpdatePromptExplanationExperimentEnabled()
? l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_CARD_PROMPT_UPLOAD_EXPLANATION_V3)
@@ -104,22 +95,15 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetDescriptionText()
}
int AutofillSaveCardInfoBarDelegateMobile::GetIconId() const {
- return IsGooglePayBrandingEnabled() ? 0 : IDR_INFOBAR_AUTOFILL_CC;
+ return IsGooglePayBrandingEnabled() ? IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER
+ : IDR_INFOBAR_AUTOFILL_CC;
}
base::string16 AutofillSaveCardInfoBarDelegateMobile::GetMessageText() const {
- if (IsGooglePayBrandingEnabled()) {
- return base::string16();
- }
return l10n_util::GetStringUTF16(
- upload_ ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD
- : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL);
-}
-
-base::string16 AutofillSaveCardInfoBarDelegateMobile::GetLinkText() const {
- return IsGooglePayBrandingEnabled()
- ? base::string16()
- : l10n_util::GetStringUTF16(IDS_LEARN_MORE);
+ IsGooglePayBrandingEnabled() || !upload_
+ ? IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD_V3
+ : IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD);
}
infobars::InfoBarDelegate::InfoBarIdentifier
@@ -139,11 +123,18 @@ void AutofillSaveCardInfoBarDelegateMobile::InfoBarDismissed() {
LogUserAction(AutofillMetrics::INFOBAR_DENIED);
}
+int AutofillSaveCardInfoBarDelegateMobile::GetButtons() const {
+ return BUTTON_OK;
+}
+
base::string16 AutofillSaveCardInfoBarDelegateMobile::GetButtonLabel(
InfoBarButton button) const {
- return l10n_util::GetStringUTF16(button == BUTTON_OK
- ? IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT
- : IDS_NO_THANKS);
+ if (button != BUTTON_OK) {
+ NOTREACHED() << "Unsupported button label requested.";
+ return base::string16();
+ }
+
+ return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT);
}
bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
@@ -153,15 +144,6 @@ bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
return true;
}
-bool AutofillSaveCardInfoBarDelegateMobile::Cancel() {
- LogUserAction(AutofillMetrics::INFOBAR_DENIED);
- return true;
-}
-
-GURL AutofillSaveCardInfoBarDelegateMobile::GetLinkURL() const {
- return IsGooglePayBrandingEnabled() ? GURL() : GURL(kHelpURL);
-}
-
void AutofillSaveCardInfoBarDelegateMobile::LogUserAction(
AutofillMetrics::InfoBarMetric user_action) {
DCHECK(!had_user_interaction_);
diff --git a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
index 0d4d63c0039..42b3b4e0a4c 100644
--- a/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
+++ b/chromium/components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h
@@ -53,21 +53,18 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
// to Google.
bool IsGooglePayBrandingEnabled() const;
- // All following changes are with respect to Google Pay branding.
- base::string16 GetTitleText() const;
+ // Description text to be shown above the card information in the infobar.
base::string16 GetDescriptionText() const;
// ConfirmInfoBarDelegate:
int GetIconId() const override;
base::string16 GetMessageText() const override;
- base::string16 GetLinkText() const override;
infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override;
bool ShouldExpire(const NavigationDetails& details) const override;
void InfoBarDismissed() override;
+ int GetButtons() const override;
base::string16 GetButtonLabel(InfoBarButton button) const override;
bool Accept() override;
- bool Cancel() override;
- GURL GetLinkURL() const override;
private:
void LogUserAction(AutofillMetrics::InfoBarMetric user_action);
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.cc b/chromium/components/autofill/core/browser/autofill_test_utils.cc
index 63682d7e717..f3bac64510f 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.cc
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.cc
@@ -174,6 +174,25 @@ void CreateTestAddressFormData(FormData* form,
types->push_back(type_set);
}
+void CreateTestPersonalInformationFormData(FormData* form) {
+ form->name = ASCIIToUTF16("MyForm");
+ form->origin = GURL("http://myform.com/form.html");
+ form->action = GURL("http://myform.com/submit.html");
+ form->main_frame_origin =
+ url::Origin::Create(GURL("https://myform_root.com/form.html"));
+
+ FormFieldData field;
+ ServerFieldTypeSet type_set;
+ test::CreateTestFormField("First Name", "firstname", "", "text", &field);
+ form->fields.push_back(field);
+ test::CreateTestFormField("Middle Name", "middlename", "", "text", &field);
+ form->fields.push_back(field);
+ test::CreateTestFormField("Last Name", "lastname", "", "text", &field);
+ form->fields.push_back(field);
+ test::CreateTestFormField("Email", "email", "", "email", &field);
+ form->fields.push_back(field);
+}
+
inline void check_and_set(
FormGroup* profile, ServerFieldType type, const char* value) {
if (value)
@@ -181,7 +200,7 @@ inline void check_and_set(
}
AutofillProfile GetFullValidProfileForCanada() {
- AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile, "Alice", "", "Wonderland", "alice@wonderland.ca",
"Fiction", "666 Notre-Dame Ouest", "Apt 8", "Montreal", "QC",
"H3B 2T9", "CA", "15141112233");
@@ -189,7 +208,7 @@ AutofillProfile GetFullValidProfileForCanada() {
}
AutofillProfile GetFullValidProfileForChina() {
- AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile, "John", "H.", "Doe", "johndoe@google.cn", "Google",
"100 Century Avenue", "", "赫章县", "毕节地区", "贵州省",
"200120", "CN", "+86-21-6133-7666");
@@ -197,7 +216,7 @@ AutofillProfile GetFullValidProfileForChina() {
}
AutofillProfile GetFullProfile() {
- AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile,
"John",
"H.",
@@ -214,7 +233,7 @@ AutofillProfile GetFullProfile() {
}
AutofillProfile GetFullProfile2() {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile,
"Jane",
"A.",
@@ -231,7 +250,7 @@ AutofillProfile GetFullProfile2() {
}
AutofillProfile GetFullCanadianProfile() {
- AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile, "Wayne", "", "Gretzky", "wayne@hockey.com", "NHL",
"123 Hockey rd.", "Apt 8", "Moncton", "New Brunswick",
"E1A 0A6", "CA", "15068531212");
@@ -239,7 +258,7 @@ AutofillProfile GetFullCanadianProfile() {
}
AutofillProfile GetIncompleteProfile1() {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile, "John", "H.", "Doe", "jsmith@example.com", "ACME",
"123 Main Street", "Unit 1", "Greensdale", "MI", "48838", "US",
"");
@@ -247,7 +266,7 @@ AutofillProfile GetIncompleteProfile1() {
}
AutofillProfile GetIncompleteProfile2() {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+ AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
SetProfileInfo(&profile, "", "", "", "jsmith@example.com", "", "", "", "", "",
"", "", "");
return profile;
@@ -266,14 +285,14 @@ AutofillProfile GetVerifiedProfile2() {
}
CreditCard GetCreditCard() {
- CreditCard credit_card(base::GenerateGUID(), "http://www.example.com");
+ CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
"11", "2022", "1");
return credit_card;
}
CreditCard GetCreditCard2() {
- CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
SetCreditCardInfo(&credit_card, "Someone Else", "378282246310005" /* AmEx */,
"07", "2022", "1");
return credit_card;
@@ -326,7 +345,7 @@ CreditCard GetRandomCreditCard(CreditCard::RecordType record_type) {
CreditCard credit_card =
(record_type == CreditCard::LOCAL_CARD)
- ? CreditCard(base::GenerateGUID(), "http://www.example.com")
+ ? CreditCard(base::GenerateGUID(), kEmptyOrigin)
: CreditCard(record_type, base::GenerateGUID().substr(24));
test::SetCreditCardInfo(
&credit_card, "Justin Thyme", GetRandomCardNumber().c_str(),
@@ -490,5 +509,10 @@ void GenerateTestAutofillPopup(
autofill_external_delegate->OnSuggestionsReturned(query_id, suggestions);
}
+std::string ObfuscatedCardDigitsAsUTF8(const std::string& str) {
+ return base::UTF16ToUTF8(
+ internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16(str)));
+}
+
} // namespace test
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_test_utils.h b/chromium/components/autofill/core/browser/autofill_test_utils.h
index f722ba5042d..80af947d034 100644
--- a/chromium/components/autofill/core/browser/autofill_test_utils.h
+++ b/chromium/components/autofill/core/browser/autofill_test_utils.h
@@ -30,6 +30,8 @@ struct FormFieldData;
// Common utilities shared amongst Autofill tests.
namespace test {
+const char kEmptyOrigin[] = "";
+
// The following methods return a PrefService that can be used for
// Autofill-related testing in contexts where the PrefService would otherwise
// have to be constructed manually (e.g., in unit tests within Autofill core
@@ -66,6 +68,10 @@ void CreateTestAddressFormData(FormData* form);
void CreateTestAddressFormData(FormData* form,
std::vector<ServerFieldTypeSet>* types);
+// Populates |form| with data corresponding to a simple personal information
+// form, including name and email, but no address-related fields.
+void CreateTestPersonalInformationFormData(FormData* form);
+
// Returns a full profile with valid info according to rules for Canada.
AutofillProfile GetFullValidProfileForCanada();
@@ -200,6 +206,8 @@ void FillQueryField(AutofillQueryContents::Form::Field* field,
void GenerateTestAutofillPopup(
AutofillExternalDelegate* autofill_external_delegate);
+std::string ObfuscatedCardDigitsAsUTF8(const std::string& str);
+
} // namespace test
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/autofill_type.cc b/chromium/components/autofill/core/browser/autofill_type.cc
index d0d814c21ee..24447b2d4b1 100644
--- a/chromium/components/autofill/core/browser/autofill_type.cc
+++ b/chromium/components/autofill/core/browser/autofill_type.cc
@@ -93,7 +93,6 @@ FieldTypeGroup GroupTypeOfServerFieldType(ServerFieldType field_type) {
case NEW_PASSWORD:
case PROBABLY_NEW_PASSWORD:
case NOT_NEW_PASSWORD:
- case PROBABLY_ACCOUNT_CREATION_PASSWORD:
case CONFIRMATION_PASSWORD:
return PASSWORD_FIELD;
@@ -202,7 +201,7 @@ AutofillType::AutofillType(ServerFieldType field_type)
if ((field_type < NO_SERVER_DATA || field_type >= MAX_VALID_FIELD_TYPE) ||
(field_type >= 15 && field_type <= 19) ||
(field_type >= 25 && field_type <= 29) ||
- (field_type >= 44 && field_type <= 50)) {
+ (field_type >= 44 && field_type <= 50) || field_type == 94) {
server_type_ = UNKNOWN_TYPE;
} else {
server_type_ = field_type;
@@ -768,8 +767,6 @@ std::string AutofillType::ServerFieldTypeToString(ServerFieldType type) {
return "PROBABLY_NEW_PASSWORD";
case NOT_NEW_PASSWORD:
return "NOT_NEW_PASSWORD";
- case PROBABLY_ACCOUNT_CREATION_PASSWORD:
- return "PROBABLY_ACCOUNT_CREATION_PASSWORD";
case CONFIRMATION_PASSWORD:
return "CONFIRMATION_PASSWORD";
case SEARCH_TERM:
diff --git a/chromium/components/autofill/core/browser/contact_info.cc b/chromium/components/autofill/core/browser/contact_info.cc
index 7d54216de31..105d135c28c 100644
--- a/chromium/components/autofill/core/browser/contact_info.cc
+++ b/chromium/components/autofill/core/browser/contact_info.cc
@@ -20,7 +20,7 @@ namespace autofill {
NameInfo::NameInfo() {}
-NameInfo::NameInfo(const NameInfo& info) : FormGroup() {
+NameInfo::NameInfo(const NameInfo& info) {
*this = info;
}
@@ -181,7 +181,7 @@ void NameInfo::SetFullName(const base::string16& full) {
EmailInfo::EmailInfo() {}
-EmailInfo::EmailInfo(const EmailInfo& info) : FormGroup() {
+EmailInfo::EmailInfo(const EmailInfo& info) {
*this = info;
}
@@ -217,7 +217,7 @@ void EmailInfo::SetRawInfo(ServerFieldType type, const base::string16& value) {
CompanyInfo::CompanyInfo() {}
-CompanyInfo::CompanyInfo(const CompanyInfo& info) : FormGroup() {
+CompanyInfo::CompanyInfo(const CompanyInfo& info) {
*this = info;
}
diff --git a/chromium/components/autofill/core/browser/country_combobox_model.cc b/chromium/components/autofill/core/browser/country_combobox_model.cc
index 5fe80954a7e..280c0234a4c 100644
--- a/chromium/components/autofill/core/browser/country_combobox_model.cc
+++ b/chromium/components/autofill/core/browser/country_combobox_model.cc
@@ -89,7 +89,7 @@ base::string16 CountryComboboxModel::GetItemAt(int index) {
}
bool CountryComboboxModel::IsItemSeparatorAt(int index) {
- return !countries_[index].get();
+ return !countries_[index];
}
std::string CountryComboboxModel::GetDefaultCountryCode() const {
diff --git a/chromium/components/autofill/core/browser/credit_card.cc b/chromium/components/autofill/core/browser/credit_card.cc
index 4788afc8cfc..1cfce7ab19e 100644
--- a/chromium/components/autofill/core/browser/credit_card.cc
+++ b/chromium/components/autofill/core/browser/credit_card.cc
@@ -12,6 +12,7 @@
#include <string>
#include "base/guid.h"
+#include "base/i18n/rtl.h"
#include "base/i18n/string_search.h"
#include "base/i18n/time_formatting.h"
#include "base/i18n/unicodestring.h"
@@ -32,6 +33,7 @@
#include "components/autofill/core/browser/autofill_type.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_regexes.h"
#include "components/autofill/core/common/form_field_data.h"
#include "components/grit/components_scaled_resources.h"
@@ -44,11 +46,8 @@ using base::ASCIIToUTF16;
namespace autofill {
-const base::char16 kMidlineEllipsis[] = { 0x0020, 0x0020,
- 0x2022, 0x2006,
- 0x2022, 0x2006,
- 0x2022, 0x2006,
- 0x2022, 0x2006, 0 };
+const base::char16 kMidlineEllipsis[] = {0x2022, 0x2006, 0x2022, 0x2006, 0x2022,
+ 0x2006, 0x2022, 0x2006, 0};
namespace {
@@ -112,6 +111,16 @@ base::string16 GetLastFourDigits(const base::string16& number) {
} // namespace
+namespace internal {
+
+base::string16 GetObfuscatedStringForCardDigits(const base::string16& digits) {
+ base::string16 obfuscated_string = base::string16(kMidlineEllipsis) + digits;
+ base::i18n::WrapStringWithLTRFormatting(&obfuscated_string);
+ return obfuscated_string;
+}
+
+} // namespace internal
+
CreditCard::CreditCard(const std::string& guid, const std::string& origin)
: AutofillDataModel(guid, origin),
record_type_(LOCAL_CARD),
@@ -735,24 +744,36 @@ base::string16 CreditCard::NetworkForDisplay() const {
return CreditCard::NetworkForDisplay(network_);
}
+base::string16 CreditCard::ObfuscatedLastFourDigits() const {
+ return internal::GetObfuscatedStringForCardDigits(LastFourDigits());
+}
+
base::string16 CreditCard::NetworkAndLastFourDigits() const {
- base::string16 network = NetworkForDisplay();
+ const base::string16 network = NetworkForDisplay();
// TODO(crbug.com/734197): truncate network.
- base::string16 digits = LastFourDigits();
+ const base::string16 digits = LastFourDigits();
if (digits.empty())
return network;
// TODO(estade): i18n?
- return network + base::string16(kMidlineEllipsis) + digits;
+ const base::string16 obfuscated_string =
+ internal::GetObfuscatedStringForCardDigits(digits);
+ return network.empty() ? obfuscated_string
+ : network + ASCIIToUTF16(" ") + obfuscated_string;
}
base::string16 CreditCard::BankNameAndLastFourDigits() const {
- base::string16 digits = LastFourDigits();
+ const base::string16 digits = LastFourDigits();
// TODO(crbug.com/734197): truncate bank name.
if (digits.empty())
return ASCIIToUTF16(bank_name_);
- return ASCIIToUTF16(bank_name_) + base::string16(kMidlineEllipsis) + digits;
+
+ const base::string16 obfuscated_string =
+ internal::GetObfuscatedStringForCardDigits(digits);
+ return bank_name_.empty() ? obfuscated_string
+ : ASCIIToUTF16(bank_name_) + ASCIIToUTF16(" ") +
+ obfuscated_string;
}
base::string16 CreditCard::NetworkOrBankNameAndLastFourDigits() const {
diff --git a/chromium/components/autofill/core/browser/credit_card.h b/chromium/components/autofill/core/browser/credit_card.h
index 1894581ebd2..74971b541b8 100644
--- a/chromium/components/autofill/core/browser/credit_card.h
+++ b/chromium/components/autofill/core/browser/credit_card.h
@@ -22,6 +22,17 @@ namespace autofill {
// A midline horizontal ellipsis (U+22EF).
extern const base::char16 kMidlineEllipsis[];
+namespace internal {
+
+// Returns an obfuscated representation of a credit card number given its last
+// digits. To ensure that the obfuscation is placed at the left of the last four
+// digits, even for RTL languages, inserts a Left-To-Right Embedding mark at the
+// beginning and a Pop Directional Formatting mark at the end.
+// Exposed for testing.
+base::string16 GetObfuscatedStringForCardDigits(const base::string16& digits);
+
+} // namespace internal
+
// A form group that stores card information.
class CreditCard : public AutofillDataModel {
public:
@@ -218,7 +229,7 @@ class CreditCard : public AutofillDataModel {
// Various display functions.
- // Card preview summary, for example: "Visa - 1234", ", 01/2020".
+ // Card preview summary, for example: "Visa - ****1234", ", 01/2020".
const std::pair<base::string16, base::string16> LabelPieces() const;
// Like LabelPieces, but appends the two pieces together.
const base::string16 Label() const;
@@ -227,11 +238,13 @@ class CreditCard : public AutofillDataModel {
base::string16 LastFourDigits() const;
// The user-visible issuer network of the card, e.g. 'Mastercard'.
base::string16 NetworkForDisplay() const;
- // A label for this card formatted as 'IssuerNetwork - 2345'.
+ // A label for this card formatted as '****2345'.
+ base::string16 ObfuscatedLastFourDigits() const;
+ // A label for this card formatted as 'IssuerNetwork - ****2345'.
base::string16 NetworkAndLastFourDigits() const;
- // A label for this card formatted as 'BankName' - 2345' if bank name
+ // A label for this card formatted as 'BankName' - ****2345' if bank name
// experiment turned on and bank name available; otherwise, formated as
- // 'IssuerNetwork - 2345'.
+ // 'IssuerNetwork - ****2345'.
base::string16 NetworkOrBankNameAndLastFourDigits() const;
// Localized expiration for this card formatted as 'Exp: 06/17'.
base::string16 AbbreviatedExpirationDateForDisplay() const;
diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.cc b/chromium/components/autofill/core/browser/credit_card_save_manager.cc
index 140ca98f97b..5eac76c7094 100644
--- a/chromium/components/autofill/core/browser/credit_card_save_manager.cc
+++ b/chromium/components/autofill/core/browser/credit_card_save_manager.cc
@@ -32,7 +32,6 @@
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_util.h"
@@ -103,24 +102,21 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
upload_request_.card = card;
uploading_local_card_ = uploading_local_card;
- // In order to prompt the user to upload their card, we must have both:
+ // Ideally, in order to upload a card, we must have both:
// 1) Card with CVC
// 2) 1+ recently-used or modified addresses that meet the client-side
// validation rules
- // Here we perform both checks before returning or logging anything, because
- // if only one of the two is missing, it may be fixable.
-
- // Additional note: If the "send detected values" experiment is enabled,
- // ignore the above and always ping Google Payments regardless. Include what
+ // We perform all checks before returning or logging in order to know where we
+ // stand with regards to card upload information. If the "send detected
+ // values" experiment is disabled and any problems were found, we do not offer
+ // to save the card. We could fall back to a local save, but we believe that
+ // sometimes offering upload and sometimes offering local save is a confusing
+ // user experience.
+
+ // Alternatively, if the "send detected values" experiment is enabled, always
+ // ping Google Payments regardless and ask if save is allowed. Include what
// data was found as part of the request, and let Payments decide whether
// upload save should be offered.
-
- // Check for a CVC to determine whether we can prompt the user to upload
- // their card. If no CVC is present and the experiment is off, do nothing.
- // We could fall back to a local save but we believe that sometimes offering
- // upload and sometimes offering local save is a confusing user experience.
- // If no CVC and the experiment is on, request CVC from the user in the
- // bubble and save using the provided value.
found_cvc_field_ = false;
found_value_in_cvc_field_ = false;
found_cvc_value_in_non_cvc_field_ = false;
@@ -149,29 +145,13 @@ void CreditCardSaveManager::AttemptToOfferCardUploadSave(
pending_upload_request_origin_ = submitted_form.main_frame_origin();
- should_cvc_be_requested_ = false;
if (upload_request_.cvc.empty()) {
- // CVC should be requested from the user if the CVC fix flow experiment is
- // enabled and no other problems were found (i.e., name and address are
- // available). At this point, |upload_decision_metrics_| is non-zero only if
- // there were problems gathering a unique name and address.
- should_cvc_be_requested_ =
- (!upload_decision_metrics_ &&
- IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled());
- if (should_cvc_be_requested_) {
- // If requesting CVC, don't apply the CVC decision to
- // |upload_decision_metrics_| yet as that will signify a problem. Instead,
- // it will be applied in OnDidGetUploadDetails(~).
- upload_request_.active_experiments.push_back(
- kAutofillUpstreamRequestCvcIfMissing.name);
- } else {
- // If not requesting CVC, apply the CVC decision to
- // |upload_decision_metrics_| to denote a problem was found.
- upload_decision_metrics_ |= GetCVCCardUploadDecisionMetric();
- }
+ // Apply the CVC decision to |upload_decision_metrics_| to denote a problem
+ // was found.
+ upload_decision_metrics_ |= GetCVCCardUploadDecisionMetric();
}
- // If any problems were found (including missing CVC and fix flow disabled),
+ // If any problems were found across CVC/name/address,
// |upload_decision_metrics_| will be non-zero. If the "send detected values"
// experiment is on, continue anyway and just let Payments know that not
// everything was found, as Payments may still allow the card to be saved.
@@ -248,7 +228,6 @@ void CreditCardSaveManager::OnDidGetUploadDetails(
user_did_accept_upload_prompt_ = false;
client_->ConfirmSaveCreditCardToCloud(
upload_request_.card, std::move(legal_message),
- should_cvc_be_requested_,
base::Bind(&CreditCardSaveManager::OnUserDidAcceptUpload,
weak_ptr_factory_.GetWeakPtr()));
client_->LoadRiskData(
@@ -303,18 +282,10 @@ void CreditCardSaveManager::OnDidGetUploadDetails(
AutofillMetrics::UPLOAD_NOT_OFFERED_GET_UPLOAD_DETAILS_FAILED;
}
- if (should_cvc_be_requested_) {
- // If we're requesting CVC from the user, it should be because the CVC field
- // was not found or it was found but empty or with an invalid value. In any
- // of those cases, CVC will not have been set on the card in the request.
- DCHECK(upload_request_.cvc.empty());
- upload_decision_metrics_ |= GetCVCCardUploadDecisionMetric();
- } else {
- // If we're not requesting CVC from the user, assert that we've either
- // detected the CVC or the send detected values experiment is enabled.
- DCHECK(IsAutofillUpstreamSendDetectedValuesExperimentEnabled() ||
- (found_cvc_field_ && found_value_in_cvc_field_));
- }
+ // Assert that we've either detected the CVC or the "send detected values"
+ // experiment is enabled.
+ DCHECK(IsAutofillUpstreamSendDetectedValuesExperimentEnabled() ||
+ (found_cvc_field_ && found_value_in_cvc_field_));
LogCardUploadDecisions(upload_decision_metrics_);
pending_upload_request_origin_ = url::Origin();
@@ -440,9 +411,8 @@ void CreditCardSaveManager::SetProfilesForCreditCardUpload(
int CreditCardSaveManager::GetDetectedValues() const {
int detected_values = 0;
- // Report detecting CVC if it was found or if we intend to request it from the
- // user.
- if (!upload_request_.cvc.empty() || should_cvc_be_requested_) {
+ // Report detecting CVC if it was found.
+ if (!upload_request_.cvc.empty()) {
detected_values |= DetectedValue::CVC;
}
@@ -520,17 +490,6 @@ void CreditCardSaveManager::SendUploadCardRequest() {
if (observer_for_testing_)
observer_for_testing_->OnSentUploadCardRequest();
upload_request_.app_locale = app_locale_;
- // If the upload request does not have card CVC and the CVC fix flow is
- // enabled, populate it with the value provided by the user. If the CVC fix
- // flow is not enabled, not sending CVC to Payments at all is expected
- // behavior.
- if (upload_request_.cvc.empty() &&
- IsAutofillUpstreamRequestCvcIfMissingExperimentEnabled()) {
- DCHECK(client_->GetSaveCardBubbleController());
- upload_request_.cvc =
- client_->GetSaveCardBubbleController()->GetCvcEnteredByUser();
- }
-
upload_request_.billing_customer_number =
static_cast<int64_t>(payments_client_->GetPrefService()->GetDouble(
prefs::kAutofillBillingCustomerNumber));
diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager.h b/chromium/components/autofill/core/browser/credit_card_save_manager.h
index c200797e2e0..2e076c3b48a 100644
--- a/chromium/components/autofill/core/browser/credit_card_save_manager.h
+++ b/chromium/components/autofill/core/browser/credit_card_save_manager.h
@@ -177,9 +177,6 @@ class CreditCardSaveManager : public payments::PaymentsClientSaveDelegate {
// |true| if the user has opted to upload save their credit card to Google.
bool user_did_accept_upload_prompt_ = false;
- // |should_cvc_be_requested_| is |true| if we should request CVC from the user
- // in the card upload dialog.
- bool should_cvc_be_requested_ = false;
// |found_cvc_field_| is |true| if there exists a field that is determined to
// be a CVC field via heuristics.
bool found_cvc_field_ = false;
diff --git a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc b/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc
index 18b627bba75..84c708b08f9 100644
--- a/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_save_manager_unittest.cc
@@ -130,11 +130,6 @@ class CreditCardSaveManagerTest : public testing::Test {
request_context_ = nullptr;
}
- void EnableAutofillUpstreamRequestCvcIfMissingExperiment() {
- scoped_feature_list_.InitAndEnableFeature(
- kAutofillUpstreamRequestCvcIfMissing);
- }
-
void DisableAutofillUpstreamSendDetectedValuesExperiment() {
scoped_feature_list_.InitAndDisableFeature(
kAutofillUpstreamSendDetectedValues);
@@ -145,13 +140,6 @@ class CreditCardSaveManagerTest : public testing::Test {
kAutofillUpstreamSendDetectedValues);
}
- void EnableAutofillUpstreamRequestCvcIfMissingAndSendDetectedValuesExps() {
- scoped_feature_list_.InitWithFeatures(
- {kAutofillUpstreamRequestCvcIfMissing,
- kAutofillUpstreamSendDetectedValues}, // Enabled
- {}); // Disabled
- }
-
void EnableAutofillUpstreamSendPanFirstSixExperiment() {
scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamSendPanFirstSix);
}
@@ -166,12 +154,8 @@ class CreditCardSaveManagerTest : public testing::Test {
}
void FormSubmitted(const FormData& form) {
- autofill_manager_->ResetRunLoop();
- if (autofill_manager_->OnFormSubmitted(form, false,
- SubmissionSource::FORM_SUBMISSION,
- base::TimeTicks::Now())) {
- autofill_manager_->WaitForAsyncUploadProcess();
- }
+ autofill_manager_->OnFormSubmitted(
+ form, false, SubmissionSource::FORM_SUBMISSION, base::TimeTicks::Now());
}
// Populates |form| with data corresponding to a simple credit card form.
@@ -486,43 +470,6 @@ TEST_F(CreditCardSaveManagerTest, UploadCreditCard) {
"Autofill.DaysSincePreviousUseAtSubmission.Profile", 0);
}
-TEST_F(CreditCardSaveManagerTest,
- UploadCreditCard_RequestCVCEnabled_DoesNotTrigger) {
- EnableAutofillUpstreamRequestCvcIfMissingExperiment();
-
- personal_data_.ClearCreditCards();
- personal_data_.ClearProfiles();
- credit_card_save_manager_->SetCreditCardUploadEnabled(true);
-
- // Create, fill and submit an address form in order to establish a recent
- // profile which can be selected for the upload request.
- FormData address_form;
- test::CreateTestAddressFormData(&address_form);
- FormsSeen({address_form});
-
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
- FormSubmitted(address_form);
-
- // Set up our credit card form data.
- FormData credit_card_form;
- CreateTestCreditCardFormData(&credit_card_form, true, false);
- FormsSeen({credit_card_form});
-
- // Edit the data, and submit.
- credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
- credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
- credit_card_form.fields[2].value = ASCIIToUTF16("11");
- credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
- credit_card_form.fields[4].value = ASCIIToUTF16("123");
-
- EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
- FormSubmitted(credit_card_form);
- EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
- // Submitted form included CVC, so user did not need to enter CVC.
- EXPECT_THAT(payments_client_->GetActiveExperimentsSetInRequest(),
- UnorderedElementsAre(kAutofillUpstreamSendDetectedValues.name));
-}
-
TEST_F(CreditCardSaveManagerTest, UploadCreditCardAndSaveCopy) {
personal_data_.ClearCreditCards();
personal_data_.ClearProfiles();
@@ -1334,80 +1281,6 @@ TEST_F(CreditCardSaveManagerTest,
ExpectCardUploadDecisionUkm(AutofillMetrics::CVC_FIELD_NOT_FOUND);
}
-// TODO(crbug.com/666704): Flaky on android_n5x_swarming_rel bot.
-#if defined(OS_ANDROID)
-#define MAYBE_UploadCreditCard_NoCvcFieldOnForm_UserEntersCvc \
- DISABLED_UploadCreditCard_NoCvcFieldOnForm_UserEntersCvc
-#else
-#define MAYBE_UploadCreditCard_NoCvcFieldOnForm_UserEntersCvc \
- UploadCreditCard_NoCvcFieldOnForm_UserEntersCvc
-#endif
-TEST_F(CreditCardSaveManagerTest,
- MAYBE_UploadCreditCard_NoCvcFieldOnForm_UserEntersCvc) {
- EnableAutofillUpstreamRequestCvcIfMissingExperiment();
- credit_card_save_manager_->SetCreditCardUploadEnabled(true);
-
- // Remove the profiles that were created in the TestPersonalDataManager
- // constructor because they would result in conflicting names that would
- // prevent the upload.
- personal_data_.ClearProfiles();
-
- // Create, fill and submit an address form in order to establish a recent
- // profile which can be selected for the upload request.
- FormData address_form;
- test::CreateTestAddressFormData(&address_form);
- FormsSeen(std::vector<FormData>(1, address_form));
- ManuallyFillAddressForm("Flo", "Master", "77401", "US", &address_form);
- FormSubmitted(address_form);
-
- // Set up our credit card form data. Note that CVC field is missing.
- FormData credit_card_form;
- credit_card_form.name = ASCIIToUTF16("MyForm");
- credit_card_form.origin = GURL("https://myform.com/form.html");
- credit_card_form.action = GURL("https://myform.com/submit.html");
- credit_card_form.main_frame_origin =
- url::Origin::Create(GURL("http://myform_root.com/form.html"));
-
- FormFieldData field;
- test::CreateTestFormField("Card Name", "cardname", "", "text", &field);
- credit_card_form.fields.push_back(field);
- test::CreateTestFormField("Card Number", "cardnumber", "", "text", &field);
- credit_card_form.fields.push_back(field);
- test::CreateTestFormField("Expiration Month", "ccmonth", "", "text", &field);
- credit_card_form.fields.push_back(field);
- test::CreateTestFormField("Expiration Year", "ccyear", "", "text", &field);
- credit_card_form.fields.push_back(field);
-
- FormsSeen(std::vector<FormData>(1, credit_card_form));
-
- // Edit the data, and submit.
- credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
- credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
- credit_card_form.fields[2].value = ASCIIToUTF16("11");
- credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
-
- base::HistogramTester histogram_tester;
-
- // Upload should still happen as long as the user provides CVC in the bubble.
- EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_, _)).Times(0);
- FormSubmitted(credit_card_form);
- EXPECT_TRUE(credit_card_save_manager_->CreditCardWasUploaded());
- EXPECT_THAT(payments_client_->GetActiveExperimentsSetInRequest(),
- UnorderedElementsAre(kAutofillUpstreamRequestCvcIfMissing.name,
- kAutofillUpstreamSendDetectedValues.name));
-
- // Verify that the correct histogram entries were logged.
- ExpectCardUploadDecision(histogram_tester, AutofillMetrics::UPLOAD_OFFERED);
- ExpectCardUploadDecision(histogram_tester,
- AutofillMetrics::CVC_FIELD_NOT_FOUND);
- // Verify that the correct UKM was logged.
- ExpectMetric(
- UkmCardUploadDecisionType::kUploadDecisionName,
- UkmCardUploadDecisionType::kEntryName,
- AutofillMetrics::UPLOAD_OFFERED | AutofillMetrics::CVC_FIELD_NOT_FOUND,
- 1 /* expected_num_matching_entries */);
-}
-
TEST_F(CreditCardSaveManagerTest, UploadCreditCard_NoProfileAvailable) {
personal_data_.ClearProfiles();
credit_card_save_manager_->SetCreditCardUploadEnabled(true);
@@ -2736,93 +2609,6 @@ TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCvc) {
CreditCardSaveManager::DetectedValue::CVC);
}
-// CVC fix flow is currently not available on Android.
-#if !defined(OS_ANDROID)
-TEST_F(CreditCardSaveManagerTest,
- GetDetectedValues_DetectCvcIfCvcFixFlowEnabledAndNameAndAddressFound) {
- EnableAutofillUpstreamRequestCvcIfMissingAndSendDetectedValuesExps();
- personal_data_.ClearProfiles();
- credit_card_save_manager_->SetCreditCardUploadEnabled(true);
-
- // Set up a new address profile.
- AutofillProfile profile;
- profile.set_guid("00000000-0000-0000-0000-000000000200");
- profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("94043"), "en-US");
- personal_data_.AddProfile(profile);
-
- // Set up our credit card form data.
- FormData credit_card_form;
- CreateTestCreditCardFormData(&credit_card_form, true, false);
- FormsSeen(std::vector<FormData>(1, credit_card_form));
-
- // Edit the data, and submit.
- credit_card_form.fields[0].value = ASCIIToUTF16("John Smith");
- credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
- credit_card_form.fields[2].value = ASCIIToUTF16("11");
- credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
- credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set
-
- // Submit the form and check what detected_values for an upload save would be.
- FormSubmitted(credit_card_form);
- EXPECT_TRUE(payments_client_->GetDetectedValuesSetInRequest() &
- CreditCardSaveManager::DetectedValue::CVC);
-}
-
-TEST_F(CreditCardSaveManagerTest,
- GetDetectedValues_DoNotDetectCvcIfCvcFixFlowEnabledAndNameMissing) {
- EnableAutofillUpstreamRequestCvcIfMissingAndSendDetectedValuesExps();
- personal_data_.ClearProfiles();
- credit_card_save_manager_->SetCreditCardUploadEnabled(true);
-
- // Set up a new address profile.
- AutofillProfile profile;
- profile.set_guid("00000000-0000-0000-0000-000000000200");
- profile.SetInfo(ADDRESS_HOME_ZIP, ASCIIToUTF16("94043"), "en-US");
- personal_data_.AddProfile(profile);
-
- // Set up our credit card form data.
- FormData credit_card_form;
- CreateTestCreditCardFormData(&credit_card_form, true, false);
- FormsSeen(std::vector<FormData>(1, credit_card_form));
-
- // Edit the data, and submit.
- credit_card_form.fields[0].value = ASCIIToUTF16(""); // No name set
- credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
- credit_card_form.fields[2].value = ASCIIToUTF16("11");
- credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
- credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set
-
- // Submit the form and check what detected_values for an upload save would be.
- FormSubmitted(credit_card_form);
- EXPECT_FALSE(payments_client_->GetDetectedValuesSetInRequest() &
- CreditCardSaveManager::DetectedValue::CVC);
-}
-
-TEST_F(CreditCardSaveManagerTest,
- GetDetectedValues_DoNotDetectCvcIfCvcFixFlowEnabledAndAddressMissing) {
- EnableAutofillUpstreamRequestCvcIfMissingAndSendDetectedValuesExps();
- personal_data_.ClearProfiles();
- credit_card_save_manager_->SetCreditCardUploadEnabled(true);
-
- // Set up our credit card form data.
- FormData credit_card_form;
- CreateTestCreditCardFormData(&credit_card_form, true, false);
- FormsSeen(std::vector<FormData>(1, credit_card_form));
-
- // Edit the data, and submit.
- credit_card_form.fields[0].value = ASCIIToUTF16("John Smith");
- credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
- credit_card_form.fields[2].value = ASCIIToUTF16("11");
- credit_card_form.fields[3].value = ASCIIToUTF16(NextYear());
- credit_card_form.fields[4].value = ASCIIToUTF16(""); // No CVC set
-
- // Submit the form and check what detected_values for an upload save would be.
- FormSubmitted(credit_card_form);
- EXPECT_FALSE(payments_client_->GetDetectedValuesSetInRequest() &
- CreditCardSaveManager::DetectedValue::CVC);
-}
-#endif
-
TEST_F(CreditCardSaveManagerTest, GetDetectedValues_DetectCardholderName) {
EnableAutofillUpstreamSendDetectedValuesExperiment();
personal_data_.ClearProfiles();
diff --git a/chromium/components/autofill/core/browser/credit_card_unittest.cc b/chromium/components/autofill/core/browser/credit_card_unittest.cc
index 19fd6a22eed..a2e5a935f26 100644
--- a/chromium/components/autofill/core/browser/credit_card_unittest.cc
+++ b/chromium/components/autofill/core/browser/credit_card_unittest.cc
@@ -65,15 +65,16 @@ const char* const kInvalidNumbers[] = {
"3056 9309 0259 04aa", /* non-digit characters */
};
-const char kUTF8MidlineEllipsis[] =
- " "
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86";
-
} // namespace
+TEST(CreditCardTest, GetObfuscatedStringForCardDigits) {
+ const base::string16 digits = base::ASCIIToUTF16("1235");
+ const base::string16 expected =
+ base::string16() + base::i18n::kLeftToRightEmbeddingMark +
+ kMidlineEllipsis + digits + base::i18n::kPopDirectionalFormatting;
+ EXPECT_EQ(expected, internal::GetObfuscatedStringForCardDigits(digits));
+}
+
// Tests credit card summary string generation. This test simulates a variety
// of different possible summary strings. Variations occur based on the
// existence of credit card number, month, and year fields.
@@ -107,39 +108,39 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
test::SetCreditCardInfo(&credit_card2, "John Dillinger",
"5105 1051 0510 5100", "", "2010", "1");
base::string16 summary2 = credit_card2.Label();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- summary2);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ summary2);
base::string16 obfuscated2 = credit_card2.NetworkAndLastFourDigits();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- obfuscated2);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ obfuscated2);
// Case 3: No year.
CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card3, "John Dillinger",
"5105 1051 0510 5100", "01", "", "1");
base::string16 summary3 = credit_card3.Label();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- summary3);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ summary3);
base::string16 obfuscated3 = credit_card3.NetworkAndLastFourDigits();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- obfuscated3);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ obfuscated3);
// Case 4: Have everything.
CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com/");
test::SetCreditCardInfo(&credit_card4, "John Dillinger",
"5105 1051 0510 5100", "01", "2010", "1");
base::string16 summary4 = credit_card4.Label();
- EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis +
- "5100, 01/2010"),
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
summary4);
base::string16 obfuscated4 = credit_card4.NetworkAndLastFourDigits();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- obfuscated4);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ obfuscated4);
// Case 5: Very long credit card
CreditCard credit_card5(base::GenerateGUID(), "https://www.example.com/");
@@ -148,11 +149,12 @@ TEST(CreditCardTest, PreviewSummaryAndNetworkAndLastFourDigitsStrings) {
"0123456789 0123456789 0123456789 5105 1051 0510 5100", "01", "2010",
"1");
base::string16 summary5 = credit_card5.Label();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Card") + kUTF8MidlineEllipsis + "5100, 01/2010"),
- summary5);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Card ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100") + ", 01/2010"),
+ summary5);
base::string16 obfuscated5 = credit_card5.NetworkAndLastFourDigits();
- EXPECT_EQ(UTF8ToUTF16(std::string("Card") + kUTF8MidlineEllipsis + "5100"),
+ EXPECT_EQ(UTF8ToUTF16(std::string("Card ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
obfuscated5);
}
@@ -165,7 +167,8 @@ TEST(CreditCardTest, BankNameAndLastFourDigitsStrings) {
credit_card1.set_bank_name("Chase");
base::string16 obfuscated1 = credit_card1.BankNameAndLastFourDigits();
EXPECT_FALSE(credit_card1.bank_name().empty());
- EXPECT_EQ(UTF8ToUTF16(std::string("Chase") + kUTF8MidlineEllipsis + "5100"),
+ EXPECT_EQ(UTF8ToUTF16(std::string("Chase ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
obfuscated1);
// Case 2: Have no bank name and not show bank name.
@@ -174,8 +177,9 @@ TEST(CreditCardTest, BankNameAndLastFourDigitsStrings) {
"5105 1051 0510 5100", "01", "2010", "1");
base::string16 obfuscated2 = credit_card2.BankNameAndLastFourDigits();
EXPECT_TRUE(credit_card2.bank_name().empty());
- EXPECT_EQ(UTF8ToUTF16(std::string(kUTF8MidlineEllipsis) + "5100"),
- obfuscated2);
+ EXPECT_EQ(
+ internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16("5100")),
+ obfuscated2);
// Case 3: Have bank name but no last four digits, only show bank name.
CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com/");
@@ -198,9 +202,9 @@ TEST(CreditCardTest, NetworkOrBankNameAndLastFourDigitsStrings) {
base::string16 obfuscated1 =
credit_card1.NetworkOrBankNameAndLastFourDigits();
EXPECT_FALSE(credit_card1.bank_name().empty());
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- obfuscated1);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ obfuscated1);
// Turn on feature flag.
base::test::ScopedFeatureList scoped_feature_list_;
@@ -214,9 +218,9 @@ TEST(CreditCardTest, NetworkOrBankNameAndLastFourDigitsStrings) {
EXPECT_TRUE(credit_card2.bank_name().empty());
base::string16 obfuscated2 =
credit_card2.NetworkOrBankNameAndLastFourDigits();
- EXPECT_EQ(
- UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis + "5100"),
- obfuscated2);
+ EXPECT_EQ(UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ obfuscated2);
// Case 3: Experiment on && bank name not empty -> show bank name.
CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com/");
@@ -227,23 +231,24 @@ TEST(CreditCardTest, NetworkOrBankNameAndLastFourDigitsStrings) {
base::string16 obfuscated3 =
credit_card3.NetworkOrBankNameAndLastFourDigits();
EXPECT_FALSE(credit_card3.bank_name().empty());
- EXPECT_EQ(UTF8ToUTF16(std::string("Chase") + kUTF8MidlineEllipsis + "5100"),
+ EXPECT_EQ(UTF8ToUTF16(std::string("Chase ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
obfuscated3);
}
TEST(CreditCardTest, AssignmentOperator) {
- CreditCard a(base::GenerateGUID(), "some origin");
+ CreditCard a(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&a, "John Dillinger", "123456789012", "01", "2010",
"1");
// Result of assignment should be logically equal to the original profile.
- CreditCard b(base::GenerateGUID(), "some other origin");
+ CreditCard b(base::GenerateGUID(), test::kEmptyOrigin);
b = a;
- EXPECT_TRUE(a == b);
+ EXPECT_EQ(a, b);
// Assignment to self should not change the profile value.
a = *&a; // The *& defeats Clang's -Wself-assign warning.
- EXPECT_TRUE(a == b);
+ EXPECT_EQ(a, b);
}
struct SetExpirationYearFromStringTestCase {
@@ -331,7 +336,7 @@ INSTANTIATE_TEST_CASE_P(
SetExpirationDateFromStringTestCase{"05_2045", 0, 0}));
TEST(CreditCardTest, Copy) {
- CreditCard a(base::GenerateGUID(), "https://www.example.com");
+ CreditCard a(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&a, "John Dillinger", "123456789012", "01", "2010",
base::GenerateGUID());
@@ -509,7 +514,7 @@ TEST(CreditCardTest, IconResourceId) {
}
TEST(CreditCardTest, UpdateFromImportedCard) {
- CreditCard original_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
"09", "2017", "1");
@@ -518,14 +523,14 @@ TEST(CreditCardTest, UpdateFromImportedCard) {
// The new card has a different name, expiration date, and origin.
CreditCard b = a;
b.set_guid(base::GenerateGUID());
- b.set_origin("https://www.example.org");
+ b.set_origin(test::kEmptyOrigin);
b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
// |a| should be updated with the information from |b|.
EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
- EXPECT_EQ("https://www.example.org", a.origin());
+ EXPECT_EQ(test::kEmptyOrigin, a.origin());
EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
@@ -537,7 +542,7 @@ TEST(CreditCardTest, UpdateFromImportedCard) {
b.SetRawInfo(CREDIT_CARD_NAME_FULL, base::string16());
EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
- EXPECT_EQ("https://www.example.org", a.origin());
+ EXPECT_EQ(test::kEmptyOrigin, a.origin());
EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
a.GetRawInfo(CREDIT_CARD_NAME_FULL));
EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
@@ -731,13 +736,13 @@ TEST(CreditCardTest, CreditCardVerificationCode) {
EXPECT_EQ(base::string16(), card.GetRawInfo(CREDIT_CARD_VERIFICATION_CODE));
}
-struct MatchingTypesCase {
- MatchingTypesCase(const char* value,
- const char* card_exp_month,
- const char* card_exp_year,
- CreditCard::RecordType record_type,
- ServerFieldTypeSet expected_matched_types,
- const char* locale = "US")
+struct CreditCardMatchingTypesCase {
+ CreditCardMatchingTypesCase(const char* value,
+ const char* card_exp_month,
+ const char* card_exp_year,
+ CreditCard::RecordType record_type,
+ ServerFieldTypeSet expected_matched_types,
+ const char* locale = "US")
: value(value),
card_exp_month(card_exp_month),
card_exp_year(card_exp_year),
@@ -746,7 +751,7 @@ struct MatchingTypesCase {
locale(locale) {}
// The value entered by the user.
- const std::string value;
+ const char* value;
// Some values for an already saved card. Card number will be fixed to
// 4012888888881881.
const char* card_exp_month;
@@ -755,13 +760,13 @@ struct MatchingTypesCase {
// The types that are expected to match.
const ServerFieldTypeSet expected_matched_types;
- const std::string locale;
+ const char* locale = "US";
};
-class GetMatchingTypesTest : public testing::TestWithParam<MatchingTypesCase> {
-};
+class CreditCardMatchingTypesTest
+ : public testing::TestWithParam<CreditCardMatchingTypesCase> {};
-TEST_P(GetMatchingTypesTest, Cases) {
+TEST_P(CreditCardMatchingTypesTest, Cases) {
auto test_case = GetParam();
CreditCard card(base::GenerateGUID(), "https://www.example.com/");
card.set_record_type(test_case.record_type);
@@ -777,129 +782,60 @@ TEST_P(GetMatchingTypesTest, Cases) {
EXPECT_EQ(test_case.expected_matched_types, matching_types);
}
-INSTANTIATE_TEST_CASE_P(
- CreditCardTest,
- GetMatchingTypesTest,
- testing::Values(
- // If comparing against a masked card, last four digits are checked.
- MatchingTypesCase{"1881",
- "01",
- "2020",
- MASKED_SERVER_CARD,
- {CREDIT_CARD_NUMBER}},
- MatchingTypesCase{"4012888888881881",
- "01",
- "2020",
- MASKED_SERVER_CARD,
- {CREDIT_CARD_NUMBER}},
- MatchingTypesCase{"4111111111111111", "01", "2020",
- CreditCard::MASKED_SERVER_CARD, ServerFieldTypeSet()},
- // Same value will not match a local card or full server card since we
- // have the full number for those. However the full number will.
- MatchingTypesCase{"1881", "01", "2020", LOCAL_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"1881", "01", "2020", FULL_SERVER_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"4012888888881881",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_NUMBER}},
- MatchingTypesCase{"4012888888881881",
- "01",
- "2020",
- FULL_SERVER_CARD,
- {CREDIT_CARD_NUMBER}},
-
- // Wrong last four digits.
- MatchingTypesCase{"1111", "01", "2020", MASKED_SERVER_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"1111", "01", "2020", LOCAL_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"1111", "01", "2020", FULL_SERVER_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"4111111111111111", "01", "2020", MASKED_SERVER_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"4111111111111111", "01", "2020", LOCAL_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"4111111111111111", "01", "2020", FULL_SERVER_CARD,
- ServerFieldTypeSet()},
-
- // Matching the expiration month.
- MatchingTypesCase{"01",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH}},
- MatchingTypesCase{"1",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH}},
- MatchingTypesCase{"jan",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH},
- "US"},
- // Locale-specific interpretations.
- MatchingTypesCase{"janv",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH},
- "FR"},
- MatchingTypesCase{"janv.",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH},
- "FR"},
- MatchingTypesCase{"janvier",
- "01",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH},
- "FR"},
- MatchingTypesCase{"février",
- "02",
- "2020",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_MONTH},
- "FR"},
- MatchingTypesCase{"mars", "01", "2020", LOCAL_CARD,
- ServerFieldTypeSet(), "FR"},
-
- // Matching the expiration year.
- MatchingTypesCase{"2019",
- "01",
- "2019",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_4_DIGIT_YEAR}},
- MatchingTypesCase{"19",
- "01",
- "2019",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_2_DIGIT_YEAR}},
- MatchingTypesCase{"01/2019",
- "01",
- "2019",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
- MatchingTypesCase{"01-2019",
- "01",
- "2019",
- LOCAL_CARD,
- {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
- MatchingTypesCase{"01/2020", "01", "2019", LOCAL_CARD,
- ServerFieldTypeSet()},
- MatchingTypesCase{"20", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
- MatchingTypesCase{"2021", "01", "2019", LOCAL_CARD,
- ServerFieldTypeSet()}));
+const CreditCardMatchingTypesCase kCreditCardMatchingTypesTestCases[] = {
+ // If comparing against a masked card, last four digits are checked.
+ {"1881", "01", "2020", MASKED_SERVER_CARD, {CREDIT_CARD_NUMBER}},
+ {"4012888888881881",
+ "01",
+ "2020",
+ MASKED_SERVER_CARD,
+ {CREDIT_CARD_NUMBER}},
+ {"4111111111111111", "01", "2020", CreditCard::MASKED_SERVER_CARD,
+ ServerFieldTypeSet()},
+ // Same value will not match a local card or full server card since we
+ // have the full number for those. However the full number will.
+ {"1881", "01", "2020", LOCAL_CARD, ServerFieldTypeSet()},
+ {"1881", "01", "2020", FULL_SERVER_CARD, ServerFieldTypeSet()},
+ {"4012888888881881", "01", "2020", LOCAL_CARD, {CREDIT_CARD_NUMBER}},
+ {"4012888888881881", "01", "2020", FULL_SERVER_CARD, {CREDIT_CARD_NUMBER}},
+
+ // Wrong last four digits.
+ {"1111", "01", "2020", MASKED_SERVER_CARD, ServerFieldTypeSet()},
+ {"1111", "01", "2020", LOCAL_CARD, ServerFieldTypeSet()},
+ {"1111", "01", "2020", FULL_SERVER_CARD, ServerFieldTypeSet()},
+ {"4111111111111111", "01", "2020", MASKED_SERVER_CARD,
+ ServerFieldTypeSet()},
+ {"4111111111111111", "01", "2020", LOCAL_CARD, ServerFieldTypeSet()},
+ {"4111111111111111", "01", "2020", FULL_SERVER_CARD, ServerFieldTypeSet()},
+
+ // Matching the expiration month.
+ {"01", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}},
+ {"1", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}},
+ {"jan", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "US"},
+ // Locale-specific interpretations.
+ {"janv", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+ {"janv.", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+ {"janvier", "01", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+ {"février", "02", "2020", LOCAL_CARD, {CREDIT_CARD_EXP_MONTH}, "FR"},
+ {"mars", "01", "2020", LOCAL_CARD, ServerFieldTypeSet(), "FR"},
+
+ // Matching the expiration year.
+ {"2019", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_4_DIGIT_YEAR}},
+ {"19", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_2_DIGIT_YEAR}},
+ {"01/2019", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+ {"01-2019", "01", "2019", LOCAL_CARD, {CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR}},
+ {"01/2020", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+ {"20", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+ {"2021", "01", "2019", LOCAL_CARD, ServerFieldTypeSet()},
+};
+
+INSTANTIATE_TEST_CASE_P(CreditCardTest,
+ CreditCardMatchingTypesTest,
+ testing::ValuesIn(kCreditCardMatchingTypesTestCases));
struct GetCardNetworkTestCase {
- std::string card_number;
- std::string issuer_network;
+ const char* card_number;
+ const char* issuer_network;
bool is_valid;
};
@@ -975,7 +911,7 @@ INSTANTIATE_TEST_CASE_P(
GetCardNetworkTestCase{"6362970000457013", kEloCard, true},
// Empty string
- GetCardNetworkTestCase{std::string(), kGenericCard, false},
+ GetCardNetworkTestCase{"", kGenericCard, false},
// Non-numeric
GetCardNetworkTestCase{"garbage", kGenericCard, false},
@@ -1119,16 +1055,27 @@ INSTANTIATE_TEST_CASE_P(
TEST(CreditCardTest, LastFourDigits) {
CreditCard card(base::GenerateGUID(), "https://www.example.com/");
ASSERT_EQ(base::string16(), card.LastFourDigits());
+ ASSERT_EQ(internal::GetObfuscatedStringForCardDigits(base::string16()),
+ card.ObfuscatedLastFourDigits());
test::SetCreditCardInfo(&card, "Baby Face Nelson", "5212341234123489", "01",
"2010", "1");
ASSERT_EQ(base::ASCIIToUTF16("3489"), card.LastFourDigits());
+ ASSERT_EQ(
+ internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16("3489")),
+ card.ObfuscatedLastFourDigits());
card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("3489"));
ASSERT_EQ(base::ASCIIToUTF16("3489"), card.LastFourDigits());
+ ASSERT_EQ(
+ internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16("3489")),
+ card.ObfuscatedLastFourDigits());
card.SetRawInfo(CREDIT_CARD_NUMBER, ASCIIToUTF16("489"));
ASSERT_EQ(base::ASCIIToUTF16("489"), card.LastFourDigits());
+ ASSERT_EQ(
+ internal::GetObfuscatedStringForCardDigits(base::ASCIIToUTF16("489")),
+ card.ObfuscatedLastFourDigits());
}
// Verifies that a credit card should be updated.
diff --git a/chromium/components/autofill/core/browser/field_filler_unittest.cc b/chromium/components/autofill/core/browser/field_filler_unittest.cc
index e834c8b6c4c..928e2b9f97e 100644
--- a/chromium/components/autofill/core/browser/field_filler_unittest.cc
+++ b/chromium/components/autofill/core/browser/field_filler_unittest.cc
@@ -144,7 +144,7 @@ class AutofillFieldFillerTest : public testing::Test {
TEST_F(AutofillFieldFillerTest, Type) {
AutofillField field;
- ASSERT_EQ(NO_SERVER_DATA, field.overall_server_type());
+ ASSERT_EQ(NO_SERVER_DATA, field.server_type());
ASSERT_EQ(UNKNOWN_TYPE, field.heuristic_type());
// |server_type_| is NO_SERVER_DATA, so |heuristic_type_| is returned.
@@ -156,12 +156,32 @@ TEST_F(AutofillFieldFillerTest, Type) {
EXPECT_EQ(NAME, field.Type().group());
// Set the server type and check it.
- field.set_overall_server_type(ADDRESS_BILLING_LINE1);
+ field.set_server_type(ADDRESS_BILLING_LINE1);
+ EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
+ EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+
+ // Checks that overall_type trumps everything.
+ field.SetTypeTo(AutofillType(ADDRESS_BILLING_ZIP));
+ EXPECT_EQ(ADDRESS_HOME_ZIP, field.Type().GetStorableType());
+ EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+
+ // Checks that setting server type resets overall type.
+ field.set_server_type(ADDRESS_BILLING_LINE1);
EXPECT_EQ(ADDRESS_HOME_LINE1, field.Type().GetStorableType());
EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
// Remove the server type to make sure the heuristic type is preserved.
- field.set_overall_server_type(NO_SERVER_DATA);
+ field.set_server_type(NO_SERVER_DATA);
+ EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
+ EXPECT_EQ(NAME, field.Type().group());
+
+ // Checks that overall_type trumps everything.
+ field.SetTypeTo(AutofillType(ADDRESS_BILLING_ZIP));
+ EXPECT_EQ(ADDRESS_HOME_ZIP, field.Type().GetStorableType());
+ EXPECT_EQ(ADDRESS_BILLING, field.Type().group());
+
+ // Set the heuristic type and check it and reset overall Type.
+ field.set_heuristic_type(NAME_FIRST);
EXPECT_EQ(NAME_FIRST, field.Type().GetStorableType());
EXPECT_EQ(NAME, field.Type().group());
}
@@ -197,18 +217,18 @@ TEST_F(AutofillFieldFillerTest, Type_CreditCardOverrideHtml_ServerPredicitons) {
field.SetHtmlType(HTML_TYPE_UNRECOGNIZED, HTML_MODE_NONE);
// A credit card server prediction overrides the unrecognized type.
- field.set_overall_server_type(CREDIT_CARD_NUMBER);
+ field.set_server_type(CREDIT_CARD_NUMBER);
EXPECT_EQ(CREDIT_CARD_NUMBER, field.Type().GetStorableType());
// A non credit card server prediction doesn't override the unrecognized
// type.
- field.set_overall_server_type(NAME_FIRST);
+ field.set_server_type(NAME_FIRST);
EXPECT_EQ(UNKNOWN_TYPE, field.Type().GetStorableType());
// A credit card server prediction doesn't override a known specified html
// type.
field.SetHtmlType(HTML_TYPE_NAME, HTML_MODE_NONE);
- field.set_overall_server_type(CREDIT_CARD_NUMBER);
+ field.set_server_type(CREDIT_CARD_NUMBER);
EXPECT_EQ(NAME_FULL, field.Type().GetStorableType());
}
@@ -221,27 +241,27 @@ TEST_F(AutofillFieldFillerTest,
field.SetHtmlType(HTML_TYPE_TEL, HTML_MODE_NONE);
- field.set_overall_server_type(PHONE_HOME_CITY_AND_NUMBER);
+ field.set_server_type(PHONE_HOME_CITY_AND_NUMBER);
EXPECT_EQ(PHONE_HOME_CITY_AND_NUMBER, field.Type().GetStorableType());
// Overrides to another number format.
- field.set_overall_server_type(PHONE_HOME_NUMBER);
+ field.set_server_type(PHONE_HOME_NUMBER);
EXPECT_EQ(PHONE_HOME_NUMBER, field.Type().GetStorableType());
// Overrides autocomplete=tel-national too.
field.SetHtmlType(HTML_TYPE_TEL_NATIONAL, HTML_MODE_NONE);
- field.set_overall_server_type(PHONE_HOME_WHOLE_NUMBER);
+ field.set_server_type(PHONE_HOME_WHOLE_NUMBER);
EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, field.Type().GetStorableType());
// If autocomplete=tel-national but server says it's not a phone field,
// do not override.
field.SetHtmlType(HTML_TYPE_TEL_NATIONAL, HTML_MODE_NONE);
- field.set_overall_server_type(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
+ field.set_server_type(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR);
EXPECT_EQ(PHONE_HOME_CITY_AND_NUMBER, field.Type().GetStorableType());
// If html type not specified, we still use server prediction.
field.SetHtmlType(HTML_TYPE_UNSPECIFIED, HTML_MODE_NONE);
- field.set_overall_server_type(PHONE_HOME_CITY_AND_NUMBER);
+ field.set_server_type(PHONE_HOME_CITY_AND_NUMBER);
EXPECT_EQ(PHONE_HOME_CITY_AND_NUMBER, field.Type().GetStorableType());
}
@@ -278,7 +298,7 @@ TEST_F(AutofillFieldFillerTest, FieldSignatureAsStr) {
EXPECT_EQ("502192749", field.FieldSignatureAsStr());
// Server type does not affect FieldSignature.
- field.set_overall_server_type(NAME_LAST);
+ field.set_server_type(NAME_LAST);
EXPECT_EQ("502192749", field.FieldSignatureAsStr());
}
@@ -295,12 +315,12 @@ TEST_F(AutofillFieldFillerTest, IsFieldFillable) {
// Only server type is set.
field.set_heuristic_type(UNKNOWN_TYPE);
- field.set_overall_server_type(NAME_LAST);
+ field.set_server_type(NAME_LAST);
EXPECT_TRUE(field.IsFieldFillable());
// Both types set.
field.set_heuristic_type(NAME_FIRST);
- field.set_overall_server_type(NAME_LAST);
+ field.set_server_type(NAME_LAST);
EXPECT_TRUE(field.IsFieldFillable());
// Field has autocomplete="off" set. Since autofill was able to make a
@@ -626,7 +646,7 @@ class AutofillSelectWithStatesTest
CountryNames::SetLocaleString("en-US");
base::FilePath file_path;
- CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
+ CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
file_path = file_path.Append(FILE_PATH_LITERAL("third_party"))
.Append(FILE_PATH_LITERAL("libaddressinput"))
.Append(FILE_PATH_LITERAL("src"))
@@ -1078,7 +1098,7 @@ TEST_F(AutofillFieldFillerTest, FillStreetAddressTextArea) {
TEST_F(AutofillFieldFillerTest, FillStreetAddressTextField) {
AutofillField field;
field.form_control_type = "text";
- field.set_overall_server_type(ADDRESS_HOME_STREET_ADDRESS);
+ field.set_server_type(ADDRESS_HOME_STREET_ADDRESS);
FieldFiller filler(/*app_locale=*/"en-US", /*address_normalizer=*/nullptr);
base::string16 value = ASCIIToUTF16(
diff --git a/chromium/components/autofill/core/browser/field_types.h b/chromium/components/autofill/core/browser/field_types.h
index 76095b76431..fe6d8ab5c1c 100644
--- a/chromium/components/autofill/core/browser/field_types.h
+++ b/chromium/components/autofill/core/browser/field_types.h
@@ -155,9 +155,7 @@ enum ServerFieldType {
PHONE_HOME_EXTENSION = 93,
- // The first password field in a form that looks like account creation form
- // for local heuristics.
- PROBABLY_ACCOUNT_CREATION_PASSWORD = 94,
+ // PROBABLY_ACCOUNT_CREATION_PASSWORD value 94 is deprecated.
// The confirmation password field in account creation or change password
// forms.
diff --git a/chromium/components/autofill/core/browser/form_data_importer.cc b/chromium/components/autofill/core/browser/form_data_importer.cc
index 4809b1003ac..da41dcdab12 100644
--- a/chromium/components/autofill/core/browser/form_data_importer.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer.cc
@@ -193,7 +193,7 @@ bool FormDataImporter::ImportAddressProfiles(const FormStructure& form) {
std::set<std::string> sections;
for (const auto& field : form) {
if (field->Type().group() != CREDIT_CARD)
- sections.insert(field->section());
+ sections.insert(field->section);
}
// We save a maximum of 2 profiles per submitted form (e.g. for shipping and
@@ -217,7 +217,6 @@ bool FormDataImporter::ImportAddressProfileForSection(
// The candidate for profile import. There are many ways for the candidate to
// be rejected (see everywhere this function returns false).
AutofillProfile candidate_profile;
- candidate_profile.set_origin(form.source_url().spec());
// We only set complete phone, so aggregate phone parts in these vars and set
// complete at the end.
@@ -230,7 +229,7 @@ bool FormDataImporter::ImportAddressProfileForSection(
// Go through each |form| field and attempt to constitute a valid profile.
for (const auto& field : form) {
// Reject fields that are not within the specified |section|.
- if (field->section() != section)
+ if (field->section != section)
continue;
base::string16 value;
@@ -300,7 +299,7 @@ bool FormDataImporter::ImportCreditCard(
const FormStructure& form,
bool should_return_local_card,
std::unique_ptr<CreditCard>* imported_credit_card) {
- DCHECK(!imported_credit_card->get());
+ DCHECK(!*imported_credit_card);
// The candidate for credit card import. There are many ways for the candidate
// to be rejected (see everywhere this function returns false, below).
@@ -390,7 +389,6 @@ CreditCard FormDataImporter::ExtractCreditCardFromForm(
*has_duplicate_field_type = false;
CreditCard candidate_credit_card;
- candidate_credit_card.set_origin(form.source_url().spec());
std::set<ServerFieldType> types_seen;
for (const auto& field : form) {
diff --git a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
index e6482824ca5..40237ad636e 100644
--- a/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -70,7 +70,7 @@ enum UserMode { USER_MODE_NORMAL, USER_MODE_INCOGNITO };
class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
public:
PersonalDataLoadedObserverMock() {}
- virtual ~PersonalDataLoadedObserverMock() {}
+ ~PersonalDataLoadedObserverMock() override {}
MOCK_METHOD0(OnPersonalDataChanged, void());
};
@@ -193,7 +193,7 @@ class FormDataImporterTestBase {
.WillOnce(QuitMessageLoop(&run_loop));
run_loop.Run();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, exp_name, exp_cc_num, exp_cc_month,
exp_cc_year, "");
const std::vector<CreditCard*>& results =
@@ -254,8 +254,6 @@ class FormDataImporterTest : public FormDataImporterTestBase,
// Reset the deduping pref to its default value.
personal_data_manager_->pref_service_->SetInteger(
prefs::kAutofillLastVersionDeduped, 0);
- personal_data_manager_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, false);
}
void TearDown() override {
@@ -295,7 +293,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles) {
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
@@ -527,7 +525,7 @@ TEST_F(FormDataImporterTest,
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
nullptr, "21 Laussat St", nullptr, "San Francisco",
"California", "94102", nullptr, "(650) 555-0000");
@@ -566,7 +564,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MultilineAddress) {
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St",
"Apt. #42", "San Francisco", "California", "94102",
@@ -606,7 +604,7 @@ TEST_F(FormDataImporterTest,
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
@@ -642,7 +640,7 @@ TEST_F(FormDataImporterTest,
WaitForOnPersonalDataChanged();
- AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
nullptr, "22 Laussat St", nullptr, "San Francisco",
"California", "94102", nullptr, nullptr);
@@ -699,12 +697,12 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_TwoValidProfilesSameForm) {
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
nullptr);
- AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
nullptr, "22 Laussat St", nullptr, "San Francisco",
"California", "94102", nullptr, nullptr);
@@ -773,7 +771,7 @@ TEST_F(FormDataImporterTest,
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
@@ -856,12 +854,12 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_ThreeValidProfilesSameForm) {
WaitForOnPersonalDataChanged();
// Only two are saved.
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
nullptr);
- AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
nullptr, "22 Laussat St", nullptr, "San Francisco",
"California", "94102", nullptr, nullptr);
@@ -909,7 +907,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_SameProfileWithConflict) {
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "1600 Pennsylvania Avenue",
"Suite A", "San Francisco", "California", "94102",
@@ -992,7 +990,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
nullptr, "190 High Street", nullptr, "Philadelphia",
"Pennsylvania", "19106", nullptr, nullptr);
@@ -1031,7 +1029,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInOld) {
const std::vector<AutofillProfile*>& results2 =
personal_data_manager_->GetProfiles();
- AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected2, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "190 High Street", nullptr,
"Philadelphia", "Pennsylvania", "19106", nullptr,
@@ -1072,7 +1070,7 @@ TEST_F(FormDataImporterTest, ImportAddressProfiles_MissingInfoInNew) {
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", "Government", "190 High Street",
nullptr, "Philadelphia", "Pennsylvania", "19106",
@@ -1297,7 +1295,7 @@ TEST_F(FormDataImporterTest,
WaitForOnPersonalDataChanged();
- AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", "MM", nullptr);
@@ -1372,7 +1370,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_Valid) {
WaitForOnPersonalDataChanged();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
"2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results =
@@ -1460,7 +1458,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MonthSelectInvalidText) {
WaitForOnPersonalDataChanged();
// See that the invalid option text was converted to the right value.
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "02",
"2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results =
@@ -1484,7 +1482,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) {
WaitForOnPersonalDataChanged();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
"2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results =
@@ -1505,7 +1503,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_TwoValidCards) {
WaitForOnPersonalDataChanged();
- CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected2, "", "5500000000000004", "02", "2999",
""); // Imported cards have no billing info.
std::vector<CreditCard*> cards;
@@ -1665,7 +1663,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) {
WaitForOnPersonalDataChanged();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
"2998", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results =
@@ -1689,7 +1687,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_SameCreditCardWithConflict) {
// Expect that the newer information is saved. In this case the year is
// updated to "2999".
- CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
"2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results2 =
@@ -1713,7 +1711,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) {
WaitForOnPersonalDataChanged();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
"2998", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results =
@@ -1740,7 +1738,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_ShouldReturnLocalCard) {
// Expect that the newer information is saved. In this case the year is
// updated to "2999".
- CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
"2999", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results2 =
@@ -1764,7 +1762,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) {
WaitForOnPersonalDataChanged();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
"2998", ""); // Imported cards have no billing info.
const std::vector<CreditCard*>& results =
@@ -1789,7 +1787,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_EmptyCardWithConflict) {
ResetPersonalDataManager(USER_MODE_NORMAL);
// No change is expected.
- CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
"2998", "");
const std::vector<CreditCard*>& results2 =
@@ -1813,7 +1811,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
WaitForOnPersonalDataChanged();
- CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
"2999", "");
const std::vector<CreditCard*>& results =
@@ -1838,7 +1836,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
ResetPersonalDataManager(USER_MODE_NORMAL);
// No change is expected.
- CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
"2999", "");
const std::vector<CreditCard*>& results2 =
@@ -1864,7 +1862,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
ResetPersonalDataManager(USER_MODE_NORMAL);
// No change is expected.
- CreditCard expected3(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected3, "Biggie Smalls", "4111111111111111", "01",
"2999", "");
const std::vector<CreditCard*>& results3 =
@@ -1876,7 +1874,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInNew) {
TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) {
// Start with a single valid credit card stored via the preferences.
// Note the empty name.
- CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&saved_credit_card, "", "4111111111111111" /* Visa */,
"01", "2998", "1");
personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -1904,7 +1902,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) {
// Expect that the newer information is saved. In this case the year is
// added to the existing credit card.
- CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
"2999", "1");
const std::vector<CreditCard*>& results2 =
@@ -1918,7 +1916,7 @@ TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) {
TEST_F(FormDataImporterTest, ImportCreditCard_SameCardWithSeparators) {
// Start with a single valid credit card stored via the preferences.
// Note the separators in the credit card number.
- CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&saved_credit_card, "Biggie Smalls",
"4111 1111 1111 1111" /* Visa */, "01", "2999", "");
personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -1995,7 +1993,7 @@ TEST_F(FormDataImporterTest,
// Ensures that |offering_upload_of_local_credit_card_| is set correctly.
TEST_F(FormDataImporterTest, ImportCreditCard_TrackOfferingUploadOfLocalCard) {
// Start with a single valid credit card stored via the preferences.
- CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&saved_credit_card, "Biggie Smalls",
"4111 1111 1111 1111" /* Visa */, "01", "2999", "");
personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -2083,8 +2081,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) {
WaitForOnPersonalDataChanged();
// Test that the address has been saved.
- AutofillProfile expected_address(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
@@ -2095,7 +2092,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressOneCreditCard) {
EXPECT_EQ(0, expected_address.Compare(*results_addr[0]));
// Test that the credit card has also been saved.
- CreditCard expected_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111",
"01", "2999", "");
const std::vector<CreditCard*>& results_cards =
@@ -2164,7 +2161,7 @@ TEST_F(FormDataImporterTest, ImportFormData_TwoAddressesOneCreditCard) {
EXPECT_EQ(2U, personal_data_manager_->GetProfiles().size());
// Test that the credit card has been saved.
- CreditCard expected_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111",
"01", "2999", "");
const std::vector<CreditCard*>& results =
@@ -2211,8 +2208,7 @@ TEST_F(FormDataImporterTest, ImportFormData_OneAddressCreditCardDisabled) {
WaitForOnPersonalDataChanged();
// Test that the address has been saved.
- AutofillProfile expected_address(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
"theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
"San Francisco", "California", "94102", nullptr,
diff --git a/chromium/components/autofill/core/browser/form_field.cc b/chromium/components/autofill/core/browser/form_field.cc
index b9329efdb99..1c8e97639a0 100644
--- a/chromium/components/autofill/core/browser/form_field.cc
+++ b/chromium/components/autofill/core/browser/form_field.cc
@@ -48,10 +48,11 @@ FieldCandidatesMap FormField::ParseFormFields(
// Ignore checkable fields as they interfere with parsers assuming context.
// Eg., while parsing address, "Is PO box" checkbox after ADDRESS_LINE1
// interferes with correctly understanding ADDRESS_LINE2.
- // Ignore fields marked as presentational. See
- // http://www.w3.org/TR/wai-aria/roles#presentation
+ // Ignore fields marked as presentational, unless for 'select' fields (for
+ // synthetic fields.)
if (IsCheckable(field->check_status) ||
- field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION) {
+ (field->role == FormFieldData::ROLE_ATTRIBUTE_PRESENTATION &&
+ field->form_control_type != "select-one")) {
continue;
}
processed_fields.push_back(field.get());
diff --git a/chromium/components/autofill/core/browser/form_structure.cc b/chromium/components/autofill/core/browser/form_structure.cc
index 29fddc448ef..66c5757c8f8 100644
--- a/chromium/components/autofill/core/browser/form_structure.cc
+++ b/chromium/components/autofill/core/browser/form_structure.cc
@@ -16,6 +16,7 @@
#include "base/i18n/case_conversion.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
#include "base/sha1.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -306,6 +307,28 @@ bool AllTypesCaptured(const FormStructure& form,
return true;
}
+// Encode password attributes |vote| into |upload|.
+void EncodePasswordAttributesVote(
+ const std::pair<PasswordAttribute, bool>& vote,
+ AutofillUploadContents* upload) {
+ switch (vote.first) {
+ case PasswordAttribute::kHasLowercaseLetter:
+ upload->set_password_has_lowercase_letter(vote.second);
+ break;
+ case PasswordAttribute::kHasUppercaseLetter:
+ upload->set_password_has_uppercase_letter(vote.second);
+ break;
+ case PasswordAttribute::kHasNumeric:
+ upload->set_password_has_numeric(vote.second);
+ break;
+ case PasswordAttribute::kHasSpecialSymbol:
+ upload->set_password_has_special_symbol(vote.second);
+ break;
+ case PasswordAttribute::kPasswordAttributesCount:
+ NOTREACHED();
+ }
+}
+
} // namespace
FormStructure::FormStructure(const FormData& form)
@@ -324,7 +347,8 @@ FormStructure::FormStructure(const FormData& form)
is_form_tag_(form.is_form_tag),
is_formless_checkout_(form.is_formless_checkout),
all_fields_are_passwords_(!form.fields.empty()),
- is_signin_upload_(false) {
+ is_signin_upload_(false),
+ passwords_were_revealed_(false) {
// Copy the form fields.
std::map<base::string16, size_t> unique_names;
for (const FormFieldData& field : form.fields) {
@@ -397,7 +421,7 @@ void FormStructure::DetermineHeuristicTypes(ukm::UkmRecorder* ukm_recorder) {
if (developer_engagement_metrics) {
AutofillMetrics::LogDeveloperEngagementUkm(
ukm_recorder, main_frame_origin().GetURL(), IsCompleteCreditCardForm(),
- GetFormTypes(), developer_engagement_metrics);
+ GetFormTypes(), developer_engagement_metrics, form_signature());
}
if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions))
@@ -421,6 +445,9 @@ bool FormStructure::EncodeUploadRequest(
upload->set_form_signature(form_signature());
upload->set_autofill_used(form_was_autofilled);
upload->set_data_present(EncodeFieldTypes(available_field_types));
+ upload->set_passwords_revealed(passwords_were_revealed_);
+ if (password_attributes_vote_)
+ EncodePasswordAttributesVote(*password_attributes_vote_, upload);
if (IsAutofillFieldMetadataEnabled()) {
upload->set_action_signature(StrToHash64Bit(target_url_.host()));
@@ -460,6 +487,7 @@ bool FormStructure::EncodeQueryRequest(
if (processed_forms.find(signature) != processed_forms.end())
continue;
processed_forms.insert(signature);
+ UMA_HISTOGRAM_COUNTS_1000("Autofill.FieldCount", form->field_count());
if (form->IsMalformed())
continue;
@@ -514,7 +542,7 @@ void FormStructure::ParseQueryResponse(
if (heuristic_type != UNKNOWN_TYPE)
heuristics_detected_fillable_field = true;
- field->set_overall_server_type(field_type);
+ field->set_server_type(field_type);
std::vector<AutofillQueryResponseContents::Field::FieldPrediction>
server_predictions;
if (current_field->predictions_size() == 0) {
@@ -537,10 +565,10 @@ void FormStructure::ParseQueryResponse(
!query_response_has_no_server_data);
form->UpdateAutofillCount();
- form->IdentifySections(false);
-
if (base::FeatureList::IsEnabled(kAutofillRationalizeFieldTypePredictions))
form->RationalizeFieldTypePredictions();
+
+ form->IdentifySections(false);
}
AutofillMetrics::ServerQueryMetric metric;
@@ -579,10 +607,11 @@ std::vector<FormDataPredictions> FormStructure::GetFieldTypePredictions(
annotated_field.heuristic_type =
AutofillType(field->heuristic_type()).ToString();
annotated_field.server_type =
- AutofillType(field->overall_server_type()).ToString();
+ AutofillType(field->server_type()).ToString();
annotated_field.overall_type = field->Type().ToString();
annotated_field.parseable_name =
base::UTF16ToUTF8(field->parseable_name());
+ annotated_field.section = field->section;
form.fields.push_back(annotated_field);
}
@@ -701,7 +730,7 @@ void FormStructure::RetrieveFromCache(
field->set_heuristic_type(cached_field->second->heuristic_type());
field->SetHtmlType(cached_field->second->html_type(),
cached_field->second->html_mode());
- field->set_section(cached_field->second->section());
+ field->section = cached_field->second->section;
field->set_only_fill_when_focused(
cached_field->second->only_fill_when_focused());
}
@@ -714,8 +743,7 @@ void FormStructure::RetrieveFromCache(
// default values are equivalent to empty fields.
field->value = base::string16();
}
- field->set_overall_server_type(
- cached_field->second->overall_server_type());
+ field->set_server_type(cached_field->second->server_type());
field->set_previously_autofilled(
cached_field->second->previously_autofilled());
}
@@ -845,7 +873,7 @@ void FormStructure::LogQualityMetrics(
main_frame_origin().GetURL());
AutofillMetrics::LogAutofillFormSubmittedState(
state, is_for_credit_card, GetFormTypes(), form_parsed_timestamp_,
- form_interactions_ukm_logger);
+ form_signature(), form_interactions_ukm_logger);
}
}
@@ -880,7 +908,7 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
// in the default section. These default section names will be overridden
// by subsequent heuristic parsing steps if there are no author-specified
// section names.
- field->set_section(kDefaultSection);
+ field->section = kDefaultSection;
std::vector<std::string> tokens =
LowercaseAndTokenizeAttributeString(field->autocomplete_attribute);
@@ -930,8 +958,8 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
tokens.pop_back();
}
- DCHECK_EQ(kDefaultSection, field->section());
- std::string section = field->section();
+ DCHECK_EQ(kDefaultSection, field->section);
+ std::string section = field->section;
HtmlFieldMode mode = HTML_MODE_NONE;
// (3) The preceding token, if any, may be a fixed string that is either
@@ -964,7 +992,7 @@ void FormStructure::ParseFieldTypesFromAutocompleteAttributes() {
if (section != kDefaultSection) {
has_author_specified_sections_ = true;
- field->set_section(section);
+ field->section = section;
}
// No errors encountered while parsing!
@@ -1086,7 +1114,8 @@ void FormStructure::RationalizeCreditCardFieldPredictions() {
size_t num_months_found = 0;
size_t num_other_fields_found = 0;
for (const auto& field : fields_) {
- ServerFieldType current_field_type = field->Type().GetStorableType();
+ ServerFieldType current_field_type =
+ field->ComputedType().GetStorableType();
switch (current_field_type) {
case CREDIT_CARD_NAME_FIRST:
cc_first_name_found = true;
@@ -1163,15 +1192,15 @@ void FormStructure::RationalizeCreditCardFieldPredictions() {
switch (current_field_type) {
case CREDIT_CARD_NAME_FIRST:
if (!keep_cc_fields)
- field->SetTypeTo(NAME_FIRST);
+ field->SetTypeTo(AutofillType(NAME_FIRST));
break;
case CREDIT_CARD_NAME_LAST:
if (!keep_cc_fields)
- field->SetTypeTo(NAME_LAST);
+ field->SetTypeTo(AutofillType(NAME_LAST));
break;
case CREDIT_CARD_NAME_FULL:
if (!keep_cc_fields)
- field->SetTypeTo(NAME_FULL);
+ field->SetTypeTo(AutofillType(NAME_FULL));
break;
case CREDIT_CARD_NUMBER:
case CREDIT_CARD_TYPE:
@@ -1179,7 +1208,7 @@ void FormStructure::RationalizeCreditCardFieldPredictions() {
case CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR:
case CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR:
if (!keep_cc_fields)
- field->SetTypeTo(UNKNOWN_TYPE);
+ field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
break;
case CREDIT_CARD_EXP_MONTH:
// Do not preserve an expiry month prediction if any of the following
@@ -1192,16 +1221,16 @@ void FormStructure::RationalizeCreditCardFieldPredictions() {
// that also has one or more quantity fields. Suppress the expiry
// month field(s) not immediately preceding an expiry year field.
if (!keep_cc_fields || !cc_date_found) {
- field->SetTypeTo(UNKNOWN_TYPE);
+ field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
} else if (num_months_found > 1) {
auto it2 = it + 1;
if (it2 == fields_.end()) {
- field->SetTypeTo(UNKNOWN_TYPE);
+ field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
} else {
ServerFieldType next_field_type = (*it2)->Type().GetStorableType();
if (next_field_type != CREDIT_CARD_EXP_2_DIGIT_YEAR &&
next_field_type != CREDIT_CARD_EXP_4_DIGIT_YEAR) {
- field->SetTypeTo(UNKNOWN_TYPE);
+ field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
}
}
}
@@ -1209,7 +1238,7 @@ void FormStructure::RationalizeCreditCardFieldPredictions() {
case CREDIT_CARD_EXP_2_DIGIT_YEAR:
case CREDIT_CARD_EXP_4_DIGIT_YEAR:
if (!keep_cc_fields || !cc_date_found)
- field->SetTypeTo(UNKNOWN_TYPE);
+ field->SetTypeTo(AutofillType(UNKNOWN_TYPE));
break;
default:
break;
@@ -1222,7 +1251,7 @@ void FormStructure::RationalizePhoneNumbersInSection(std::string section) {
return;
std::vector<AutofillField*> fields;
for (size_t i = 0; i < field_count(); ++i) {
- if (field(i)->section() != section)
+ if (field(i)->section != section)
continue;
fields.push_back(field(i));
}
@@ -1232,6 +1261,9 @@ void FormStructure::RationalizePhoneNumbersInSection(std::string section) {
void FormStructure::RationalizeFieldTypePredictions() {
RationalizeCreditCardFieldPredictions();
+ for (const auto& field : fields_) {
+ field->SetTypeTo(field->Type());
+ }
}
void FormStructure::EncodeFormForQuery(
@@ -1283,10 +1315,8 @@ void FormStructure::EncodeFormForUpload(AutofillUploadContents* upload) const {
field->form_classifier_outcome());
}
- if (field->username_vote_type()) {
- added_field->set_username_vote_type(field->username_vote_type());
- } else {
- DCHECK(field_type != autofill::USERNAME);
+ if (field->vote_type()) {
+ added_field->set_vote_type(field->vote_type());
}
added_field->set_signature(field->GetFieldSignature());
@@ -1318,10 +1348,10 @@ bool FormStructure::IsMalformed() const {
return true;
// Some badly formatted web sites repeat fields - limit number of fields to
- // 48, which is far larger than any valid form and proto still fits into 2K.
+ // 100, which is far larger than any valid form and proto still fits into 2K.
// Do not send requests for forms with more than this many fields, as they are
// near certainly not valid/auto-fillable.
- const size_t kMaxFieldsOnTheForm = 48;
+ const size_t kMaxFieldsOnTheForm = 100;
if (field_count() > kMaxFieldsOnTheForm)
return true;
return false;
@@ -1346,7 +1376,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
// All credit card fields belong to the same section that's different
// from address sections.
if (AutofillType(current_type).group() == CREDIT_CARD) {
- field->set_section("credit-card");
+ field->section = "credit-card";
continue;
}
@@ -1419,7 +1449,7 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
is_hidden_section = false;
}
- field->set_section(base::UTF16ToUTF8(current_section));
+ field->section = base::UTF16ToUTF8(current_section);
}
}
@@ -1428,9 +1458,9 @@ void FormStructure::IdentifySections(bool has_author_specified_sections) {
for (const auto& field : fields_) {
FieldTypeGroup field_type_group = field->Type().group();
if (field_type_group == CREDIT_CARD)
- field->set_section(field->section() + "-cc");
+ field->section = field->section + "-cc";
else
- field->set_section(field->section() + "-default");
+ field->section = field->section + "-default";
}
}
@@ -1505,4 +1535,14 @@ std::set<FormType> FormStructure::GetFormTypes() const {
return form_types;
}
+base::string16 FormStructure::GetIdentifierForRefill() const {
+ if (!form_name().empty())
+ return form_name();
+
+ if (field_count() && !field(0)->unique_name().empty())
+ return field(0)->unique_name();
+
+ return base::string16();
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/form_structure.h b/chromium/components/autofill/core/browser/form_structure.h
index b8783c4dcce..9e3406e33de 100644
--- a/chromium/components/autofill/core/browser/form_structure.h
+++ b/chromium/components/autofill/core/browser/form_structure.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <map>
#include <memory>
#include <set>
#include <string>
@@ -14,6 +15,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "components/autofill/core/browser/autofill_field.h"
@@ -37,6 +39,15 @@ class UkmRecorder;
namespace autofill {
+// Password attributes (whether a password has special symbols, numeric, etc.)
+enum class PasswordAttribute {
+ kHasLowercaseLetter,
+ kHasUppercaseLetter,
+ kHasNumeric,
+ kHasSpecialSymbol,
+ kPasswordAttributesCount
+};
+
struct FormData;
struct FormDataPredictions;
@@ -243,9 +254,31 @@ class FormStructure {
// Returns the possible form types.
std::set<FormType> GetFormTypes() const;
+ bool passwords_were_revealed() const { return passwords_were_revealed_; }
+ void set_passwords_were_revealed(bool passwords_were_revealed) {
+ passwords_were_revealed_ = passwords_were_revealed;
+ }
+
+ void set_password_attributes_vote(
+ const std::pair<PasswordAttribute, bool>& vote) {
+ password_attributes_vote_ = vote;
+ }
+#if defined(UNIT_TEST)
+ base::Optional<std::pair<PasswordAttribute, bool>>
+ get_password_attributes_vote_for_testing() const {
+ return password_attributes_vote_;
+ }
+#endif
+
bool operator==(const FormData& form) const;
bool operator!=(const FormData& form) const;
+ // Returns an identifier that is used by the refill logic. Takes the first non
+ // empty of these or returns an empty string:
+ // - Form name
+ // - Name for Autofill of first field
+ base::string16 GetIdentifierForRefill() const;
+
private:
friend class AutofillMergeTest;
friend class FormStructureTest;
@@ -367,6 +400,14 @@ class FormStructure {
// If phone number rationalization has been performed for a given section.
std::map<std::string, bool> phone_rationalized_;
+ // True iff the form is a password form and the user has seen the password
+ // value before accepting the prompt to save. Used for crowdsourcing.
+ bool passwords_were_revealed_;
+
+ // The vote about password attributes (e.g. whether the password has a numeric
+ // character).
+ base::Optional<std::pair<PasswordAttribute, bool>> password_attributes_vote_;
+
DISALLOW_COPY_AND_ASSIGN(FormStructure);
};
diff --git a/chromium/components/autofill/core/browser/form_structure_unittest.cc b/chromium/components/autofill/core/browser/form_structure_unittest.cc
index 1dc599e59eb..ff1b701dd36 100644
--- a/chromium/components/autofill/core/browser/form_structure_unittest.cc
+++ b/chromium/components/autofill/core/browser/form_structure_unittest.cc
@@ -1055,8 +1055,8 @@ TEST_F(FormStructureTest,
ASSERT_EQ(0U, form_structure.autofill_count());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_FALSE(form_structure.IsAutofillable());
}
@@ -1068,8 +1068,8 @@ TEST_F(FormStructureTest,
ASSERT_EQ(0U, form_structure.autofill_count());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_FALSE(form_structure.IsAutofillable());
}
@@ -1084,8 +1084,8 @@ TEST_F(FormStructureTest,
ASSERT_EQ(2U, form_structure.autofill_count());
EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type());
EXPECT_EQ(NAME_LAST, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_TRUE(form_structure.IsAutofillable());
}
}
@@ -1133,8 +1133,8 @@ TEST_F(FormStructureTest,
ASSERT_EQ(1U, form_structure.autofill_count());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_FALSE(form_structure.IsAutofillable());
}
@@ -1149,8 +1149,8 @@ TEST_F(FormStructureTest,
ASSERT_EQ(2U, form_structure.autofill_count());
EXPECT_EQ(NAME_FIRST, form_structure.field(0)->heuristic_type());
EXPECT_EQ(NAME_LAST, form_structure.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(1)->server_type());
EXPECT_EQ(NAME_FIRST, form_structure.field(0)->Type().GetStorableType());
EXPECT_EQ(NAME_LAST, form_structure.field(1)->Type().GetStorableType());
EXPECT_TRUE(form_structure.IsAutofillable());
@@ -1170,7 +1170,7 @@ TEST_F(FormStructureTest,
ASSERT_EQ(1U, form_structure.field_count());
ASSERT_EQ(1U, form_structure.autofill_count());
EXPECT_EQ(UNKNOWN_TYPE, form_structure.field(0)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form_structure.field(0)->server_type());
EXPECT_EQ(NAME_FIRST, form_structure.field(0)->Type().GetStorableType());
EXPECT_TRUE(form_structure.IsAutofillable());
}
@@ -1269,7 +1269,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSections) {
// sections.
std::set<std::string> section_names;
for (size_t i = 0; i < 9; ++i) {
- section_names.insert(form_structure.field(i)->section());
+ section_names.insert(form_structure.field(i)->section);
}
EXPECT_EQ(9U, section_names.size());
}
@@ -1313,7 +1313,7 @@ TEST_F(FormStructureTest,
// section.
std::set<std::string> section_names;
for (size_t i = 0; i < 6; ++i) {
- section_names.insert(form_structure.field(i)->section());
+ section_names.insert(form_structure.field(i)->section);
}
EXPECT_EQ(1U, section_names.size());
}
@@ -1342,7 +1342,7 @@ TEST_F(FormStructureTest, HeuristicsAutocompleteAttributeWithSectionsRepeated) {
// section.
std::set<std::string> section_names;
for (size_t i = 0; i < 2; ++i) {
- section_names.insert(form_structure.field(i)->section());
+ section_names.insert(form_structure.field(i)->section);
}
EXPECT_EQ(1U, section_names.size());
}
@@ -1380,8 +1380,7 @@ TEST_F(FormStructureTest, HeuristicsDontOverrideAutocompleteAttributeSections) {
// form, we do not apply these usual heuristics.
EXPECT_EQ(ASCIIToUTF16("one"), form_structure.field(0)->name);
EXPECT_EQ(ASCIIToUTF16("two"), form_structure.field(3)->name);
- EXPECT_EQ(form_structure.field(0)->section(),
- form_structure.field(3)->section());
+ EXPECT_EQ(form_structure.field(0)->section, form_structure.field(3)->section);
}
TEST_F(FormStructureTest, HeuristicsSample8) {
@@ -2302,9 +2301,9 @@ TEST_F(FormStructureTest, EncodeQueryRequest) {
EXPECT_EQ(expected_query_string, encoded_query_string);
FormData malformed_form(form);
- // Add 50 address fields - the form is not valid anymore, but previous ones
+ // Add 150 address fields - the form is not valid anymore, but previous ones
// are. The result should be the same as in previous test.
- for (size_t i = 0; i < 50; ++i) {
+ for (size_t i = 0; i < 150; ++i) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
malformed_form.fields.push_back(field);
@@ -2383,6 +2382,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
possible_field_types.back().insert(ADDRESS_HOME_COUNTRY);
form_structure.reset(new FormStructure(form));
+ form_structure->set_password_attributes_vote(
+ std::make_pair(PasswordAttribute::kHasNumeric, true));
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
for (size_t i = 0; i < form_structure->field_count(); ++i)
@@ -2406,6 +2407,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
upload.set_form_signature(8736493185895608956U);
upload.set_autofill_used(false);
upload.set_data_present("144200030e");
+ upload.set_passwords_revealed(false);
+ upload.set_password_has_numeric(true);
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text",
@@ -2455,6 +2458,8 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
}
form_structure.reset(new FormStructure(form));
+ form_structure->set_password_attributes_vote(
+ std::make_pair(PasswordAttribute::kHasNumeric, true));
ASSERT_EQ(form_structure->field_count(), possible_field_types.size());
for (size_t i = 0; i < form_structure->field_count(); ++i)
form_structure->field(i)->set_possible_types(possible_field_types[i]);
@@ -2483,8 +2488,9 @@ TEST_F(FormStructureTest, EncodeUploadRequest) {
encoded_upload3.SerializeToString(&encoded_upload_string);
EXPECT_EQ(expected_upload_string, encoded_upload_string);
- // Add 50 address fields - now the form is invalid, as it has too many fields.
- for (size_t i = 0; i < 50; ++i) {
+ // Add 150 address fields - now the form is invalid, as it has too many
+ // fields.
+ for (size_t i = 0; i < 150; ++i) {
field.label = ASCIIToUTF16("Address");
field.name = ASCIIToUTF16("address");
field.form_control_type = "text";
@@ -2567,7 +2573,7 @@ TEST_F(FormStructureTest,
AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
}
if (form_structure->field(i)->name == ASCIIToUTF16("username")) {
- form_structure->field(i)->set_username_vote_type(
+ form_structure->field(i)->set_vote_type(
AutofillUploadContents::Field::CREDENTIALS_REUSED);
}
}
@@ -2588,6 +2594,7 @@ TEST_F(FormStructureTest,
upload.set_data_present("1440000000000000000802");
upload.set_action_signature(15724779818122431245U);
upload.set_login_form_signature(42);
+ upload.set_passwords_revealed(false);
AutofillUploadContents::Field* upload_firstname_field = upload.add_field();
test::FillUploadField(upload_firstname_field, 4224610201U, "firstname", "",
@@ -2612,7 +2619,7 @@ TEST_F(FormStructureTest,
"email", 86U);
upload_username_field->set_form_classifier_outcome(
AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
- upload_username_field->set_username_vote_type(
+ upload_username_field->set_vote_type(
AutofillUploadContents::Field::CREDENTIALS_REUSED);
AutofillUploadContents::Field* upload_password_field = upload.add_field();
@@ -2688,6 +2695,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithAutocomplete) {
upload.set_autofill_used(true);
upload.set_data_present("1440");
upload.set_action_signature(15724779818122431245U);
+ upload.set_passwords_revealed(false);
test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text",
"given-name", 3U);
@@ -2771,6 +2779,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestWithPropertiesMask) {
upload.set_form_signature(14746822798145140279U);
upload.set_autofill_used(true);
upload.set_data_present("1440");
+ upload.set_passwords_revealed(false);
test::FillUploadField(upload.add_field(), 3763331450U, nullptr, nullptr,
nullptr, 3U);
@@ -2844,6 +2853,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_ObservedSubmissionFalse) {
upload.set_autofill_used(true);
upload.set_data_present("1440");
upload.set_action_signature(15724779818122431245U);
+ upload.set_passwords_revealed(false);
test::FillUploadField(upload.add_field(), 3763331450U, "firstname", "text",
nullptr, 3U);
@@ -2909,6 +2919,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithLabels) {
upload.set_autofill_used(true);
upload.set_data_present("1440");
upload.set_action_signature(15724779818122431245U);
+ upload.set_passwords_revealed(false);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
nullptr, 3U);
@@ -2971,6 +2982,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithCssClassesAndIds) {
upload.set_autofill_used(true);
upload.set_data_present("1440");
upload.set_action_signature(15724779818122431245U);
+ upload.set_passwords_revealed(false);
AutofillUploadContents::Field* firstname_field = upload.add_field();
test::FillUploadField(firstname_field, 1318412689U, nullptr, "text", nullptr,
@@ -3044,6 +3056,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_WithFormName) {
upload.set_data_present("1440");
upload.set_action_signature(15724779818122431245U);
upload.set_form_name("myform");
+ upload.set_passwords_revealed(false);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
nullptr, 3U);
@@ -3113,6 +3126,7 @@ TEST_F(FormStructureTest, EncodeUploadRequestPartialMetadata) {
upload.set_form_signature(13043654279838250996U);
upload.set_autofill_used(true);
upload.set_data_present("1440");
+ upload.set_passwords_revealed(false);
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 1318412689U, nullptr, "text",
@@ -3193,6 +3207,7 @@ TEST_F(FormStructureTest, EncodeUploadRequest_DisabledMetadataTrial) {
upload.set_form_signature(14746822798145140279U);
upload.set_autofill_used(true);
upload.set_data_present("1440");
+ upload.set_passwords_revealed(false);
test::FillUploadField(upload.add_field(), 3763331450U, nullptr, nullptr,
nullptr, 3U);
@@ -3252,6 +3267,7 @@ TEST_F(FormStructureTest, CheckDataPresence) {
upload.set_form_signature(6402244543831589061U);
upload.set_autofill_used(false);
upload.set_data_present("");
+ upload.set_passwords_revealed(false);
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 1089846351U, "first", "text",
@@ -3520,6 +3536,7 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
upload.set_form_signature(18062476096658145866U);
upload.set_autofill_used(false);
upload.set_data_present("1440000360000008");
+ upload.set_passwords_revealed(false);
upload.set_action_signature(15724779818122431245U);
test::FillUploadField(upload.add_field(), 420638584U, "email", "text",
@@ -3603,6 +3620,27 @@ TEST_F(FormStructureTest, CheckMultipleTypes) {
EXPECT_EQ(expected_upload_string, encoded_upload_string);
}
+TEST_F(FormStructureTest, EncodeUploadRequest_PasswordsRevealed) {
+ FormData form;
+ // Add 3 fields, to make the form uploadable.
+ FormFieldData field;
+ field.name = ASCIIToUTF16("email");
+ form.fields.push_back(field);
+ field.name = ASCIIToUTF16("first");
+ form.fields.push_back(field);
+ field.name = ASCIIToUTF16("last");
+ form.fields.push_back(field);
+
+ FormStructure form_structure(form);
+ form_structure.set_passwords_were_revealed(true);
+ AutofillUploadContents upload;
+ EXPECT_TRUE(form_structure.EncodeUploadRequest(
+ {{}} /* available_field_types */, false /* form_was_autofilled */,
+ std::string() /* login_form_signature */, true /* observed_submission */,
+ &upload));
+ EXPECT_EQ(true, upload.passwords_revealed());
+}
+
TEST_F(FormStructureTest, CheckFormSignature) {
// Check that form signature is created correctly.
std::unique_ptr<FormStructure> form_structure;
@@ -4035,19 +4073,19 @@ TEST_F(FormStructureTest, ParseQueryResponse_UnknownType) {
// Validate field 0.
EXPECT_EQ(NAME_FIRST, form.field(0)->heuristic_type());
- EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->overall_server_type());
+ EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->server_type());
EXPECT_EQ(HTML_TYPE_UNSPECIFIED, form.field(0)->html_type());
EXPECT_EQ(UNKNOWN_TYPE, form.field(0)->Type().GetStorableType());
// Validate field 1.
EXPECT_EQ(NAME_LAST, form.field(1)->heuristic_type());
- EXPECT_EQ(NO_SERVER_DATA, form.field(1)->overall_server_type());
+ EXPECT_EQ(NO_SERVER_DATA, form.field(1)->server_type());
EXPECT_EQ(HTML_TYPE_UNSPECIFIED, form.field(1)->html_type());
EXPECT_EQ(NAME_LAST, form.field(1)->Type().GetStorableType());
// Validate field 2. Note: HTML_TYPE_ADDRESS_LEVEL2 -> City
EXPECT_EQ(EMAIL_ADDRESS, form.field(2)->heuristic_type());
- EXPECT_EQ(ADDRESS_HOME_LINE1, form.field(2)->overall_server_type());
+ EXPECT_EQ(ADDRESS_HOME_LINE1, form.field(2)->server_type());
EXPECT_EQ(HTML_TYPE_ADDRESS_LEVEL2, form.field(2)->html_type());
EXPECT_EQ(ADDRESS_HOME_CITY, form.field(2)->Type().GetStorableType());
}
@@ -4110,17 +4148,17 @@ TEST_F(FormStructureTest, ParseQueryResponse) {
ASSERT_GE(forms[0]->field_count(), 2U);
ASSERT_GE(forms[1]->field_count(), 2U);
- EXPECT_EQ(7, forms[0]->field(0)->overall_server_type());
+ EXPECT_EQ(7, forms[0]->field(0)->server_type());
ASSERT_EQ(2U, forms[0]->field(0)->server_predictions().size());
EXPECT_EQ(7U, forms[0]->field(0)->server_predictions()[0].type());
EXPECT_EQ(22U, forms[0]->field(0)->server_predictions()[1].type());
- EXPECT_EQ(30, forms[0]->field(1)->overall_server_type());
+ EXPECT_EQ(30, forms[0]->field(1)->server_type());
ASSERT_EQ(1U, forms[0]->field(1)->server_predictions().size());
EXPECT_EQ(30U, forms[0]->field(1)->server_predictions()[0].type());
- EXPECT_EQ(9, forms[1]->field(0)->overall_server_type());
+ EXPECT_EQ(9, forms[1]->field(0)->server_type());
ASSERT_EQ(1U, forms[1]->field(0)->server_predictions().size());
EXPECT_EQ(9U, forms[1]->field(0)->server_predictions()[0].type());
- EXPECT_EQ(0, forms[1]->field(1)->overall_server_type());
+ EXPECT_EQ(0, forms[1]->field(1)->server_type());
ASSERT_EQ(1U, forms[1]->field(1)->server_predictions().size());
EXPECT_EQ(0U, forms[1]->field(1)->server_predictions()[0].type());
}
@@ -4157,10 +4195,9 @@ TEST_F(FormStructureTest, ParseQueryResponse_AuthorDefinedTypes) {
ASSERT_GE(forms[0]->field_count(), 2U);
// Server type is parsed from the response and is the end result type.
- EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(0)->overall_server_type());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(0)->server_type());
EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(0)->Type().GetStorableType());
- EXPECT_EQ(ACCOUNT_CREATION_PASSWORD,
- forms[0]->field(1)->overall_server_type());
+ EXPECT_EQ(ACCOUNT_CREATION_PASSWORD, forms[0]->field(1)->server_type());
// TODO(crbug.com/613666): Should be a properly defined type, and not
// UNKNOWN_TYPE.
EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(1)->Type().GetStorableType());
@@ -4211,10 +4248,10 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
- EXPECT_EQ(NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(2)->overall_server_type());
- EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->overall_server_type());
+ EXPECT_EQ(NAME_FULL, forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(2)->Type().GetStorableType());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->Type().GetStorableType());
}
// Sanity check that the enable/disabled works.
@@ -4226,10 +4263,11 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeLoneField) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
- EXPECT_EQ(NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->overall_server_type());
- EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->overall_server_type());
+ EXPECT_EQ(NAME_FULL, forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(ADDRESS_HOME_LINE1, forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+ forms[0]->field(2)->Type().GetStorableType());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(3)->Type().GetStorableType());
}
}
@@ -4272,9 +4310,9 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(3U, forms[0]->field_count());
- EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(NAME_LAST, forms[0]->field(1)->overall_server_type());
- EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->overall_server_type());
+ EXPECT_EQ(NAME_FIRST, forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(NAME_LAST, forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->Type().GetStorableType());
}
// Sanity check that the enable/disabled works.
@@ -4287,9 +4325,10 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeCCName) {
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(3U, forms[0]->field_count());
EXPECT_EQ(CREDIT_CARD_NAME_FIRST,
- forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_NAME_LAST, forms[0]->field(1)->overall_server_type());
- EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->overall_server_type());
+ forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NAME_LAST,
+ forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(EMAIL_ADDRESS, forms[0]->field(2)->Type().GetStorableType());
}
}
@@ -4344,12 +4383,14 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(5U, forms[0]->field_count());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->overall_server_type());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+ forms[0]->field(2)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
- forms[0]->field(3)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(4)->overall_server_type());
+ forms[0]->field(3)->Type().GetStorableType());
+ EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(4)->Type().GetStorableType());
}
// Sanity check that the enable/disabled works.
@@ -4361,12 +4402,15 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_1) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(5U, forms[0]->field_count());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(2)->overall_server_type());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+ forms[0]->field(2)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_EXP_2_DIGIT_YEAR,
- forms[0]->field(3)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(4)->overall_server_type());
+ forms[0]->field(3)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+ forms[0]->field(4)->Type().GetStorableType());
}
}
@@ -4415,11 +4459,12 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
- forms[0]->field(2)->overall_server_type());
- EXPECT_EQ(NO_SERVER_DATA, forms[0]->field(3)->overall_server_type());
+ forms[0]->field(2)->Type().GetStorableType());
+ EXPECT_EQ(UNKNOWN_TYPE, forms[0]->field(3)->Type().GetStorableType());
}
// Sanity check that the enable/disabled works.
@@ -4430,11 +4475,13 @@ TEST_F(FormStructureTest, ParseQueryResponse_RationalizeMultiMonth_2) {
FormStructure::ParseQueryResponse(response_string, forms);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
- EXPECT_EQ(CREDIT_CARD_NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->overall_server_type());
+ EXPECT_EQ(CREDIT_CARD_NAME_FULL,
+ forms[0]->field(0)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_NUMBER, forms[0]->field(1)->Type().GetStorableType());
EXPECT_EQ(CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR,
- forms[0]->field(2)->overall_server_type());
- EXPECT_EQ(CREDIT_CARD_EXP_MONTH, forms[0]->field(3)->overall_server_type());
+ forms[0]->field(2)->Type().GetStorableType());
+ EXPECT_EQ(CREDIT_CARD_EXP_MONTH,
+ forms[0]->field(3)->Type().GetStorableType());
}
}
@@ -4521,15 +4568,37 @@ TEST_F(FormStructureTest, RationalizePhoneNumber_RunsOncePerSection) {
EXPECT_TRUE(form_structure.phone_rationalized_["fullName_1-default"]);
ASSERT_EQ(1U, forms.size());
ASSERT_EQ(4U, forms[0]->field_count());
- EXPECT_EQ(NAME_FULL, forms[0]->field(0)->overall_server_type());
- EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS,
- forms[0]->field(1)->overall_server_type());
+ EXPECT_EQ(NAME_FULL, forms[0]->field(0)->server_type());
+ EXPECT_EQ(ADDRESS_HOME_STREET_ADDRESS, forms[0]->field(1)->server_type());
- EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, forms[0]->field(2)->overall_server_type());
+ EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, forms[0]->field(2)->server_type());
EXPECT_FALSE(forms[0]->field(2)->only_fill_when_focused());
- EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, forms[0]->field(3)->overall_server_type());
+ EXPECT_EQ(PHONE_HOME_WHOLE_NUMBER, forms[0]->field(3)->server_type());
EXPECT_TRUE(forms[0]->field(3)->only_fill_when_focused());
}
+TEST_F(FormStructureTest, AllowBigForms) {
+ FormData form;
+ form.origin = GURL("http://foo.com");
+ FormFieldData field;
+ // Check that the form with 100 fields are processed correctly.
+ for (size_t i = 0; i < 100; ++i) {
+ field.form_control_type = "text";
+ field.name = ASCIIToUTF16("text") + base::NumberToString16(i);
+ form.fields.push_back(field);
+ }
+
+ FormStructure form_structure(form);
+
+ std::vector<FormStructure*> forms;
+ forms.push_back(&form_structure);
+ std::vector<std::string> encoded_signatures;
+
+ AutofillQueryContents encoded_query;
+ ASSERT_TRUE(FormStructure::EncodeQueryRequest(forms, &encoded_signatures,
+ &encoded_query));
+ EXPECT_EQ(1u, encoded_signatures.size());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.cc b/chromium/components/autofill/core/browser/payments/payments_client.cc
index bc45fd24e9c..0c84d91a47d 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client.cc
@@ -23,7 +23,9 @@
#include "components/autofill/core/browser/credit_card.h"
#include "components/autofill/core/browser/payments/payments_request.h"
#include "components/autofill/core/browser/payments/payments_service_url.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/variations/net/variations_http_headers.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
@@ -456,12 +458,14 @@ PaymentsClient::PaymentsClient(net::URLRequestContextGetter* context_getter,
PrefService* pref_service,
identity::IdentityManager* identity_manager,
PaymentsClientUnmaskDelegate* unmask_delegate,
- PaymentsClientSaveDelegate* save_delegate)
+ PaymentsClientSaveDelegate* save_delegate,
+ bool is_off_the_record)
: context_getter_(context_getter),
pref_service_(pref_service),
identity_manager_(identity_manager),
unmask_delegate_(unmask_delegate),
save_delegate_(save_delegate),
+ is_off_the_record_(is_off_the_record),
has_retried_authorization_(false),
weak_ptr_factory_(this) {}
@@ -573,6 +577,19 @@ void PaymentsClient::InitializeUrlFetcher() {
url_fetcher_->SetUploadData(request_->GetRequestContentType(),
request_->GetRequestContent());
+
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillSendExperimentIdsInPaymentsRPCs)) {
+ // Add Chrome experiment state to the request headers.
+ net::HttpRequestHeaders headers;
+ // User is always signed-in to be able to upload card to Google Payments.
+ variations::AppendVariationHeaders(url_fetcher_->GetOriginalURL(),
+ is_off_the_record_
+ ? variations::InIncognito::kYes
+ : variations::InIncognito::kNo,
+ variations::SignedIn::kYes, &headers);
+ url_fetcher_->SetExtraRequestHeaders(headers.ToString());
+ }
}
void PaymentsClient::CancelRequest() {
diff --git a/chromium/components/autofill/core/browser/payments/payments_client.h b/chromium/components/autofill/core/browser/payments/payments_client.h
index f097be903ab..d68fdf59e31 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client.h
+++ b/chromium/components/autofill/core/browser/payments/payments_client.h
@@ -103,12 +103,14 @@ class PaymentsClient : public net::URLFetcherDelegate {
// |context_getter| is reference counted so it has no lifetime or ownership
// requirements. |pref_service| is used to get the registered preference
// value, |identity_manager|, |unmask_delegate| and |save_delegate| must all
- // outlive |this|. Either delegate might be nullptr.
+ // outlive |this|. Either delegate might be nullptr. |is_off_the_record|
+ // denotes incognito mode.
PaymentsClient(net::URLRequestContextGetter* context_getter,
PrefService* pref_service,
identity::IdentityManager* identity_manager,
PaymentsClientUnmaskDelegate* unmask_delegate,
- PaymentsClientSaveDelegate* save_delegate);
+ PaymentsClientSaveDelegate* save_delegate,
+ bool is_off_the_record = false);
~PaymentsClient() override;
@@ -205,6 +207,9 @@ class PaymentsClient : public net::URLFetcherDelegate {
// The OAuth2 token, or empty if not fetched.
std::string access_token_;
+ // Denotes incognito mode.
+ bool is_off_the_record_;
+
// True if |request_| has already retried due to a 401 response from the
// server.
bool has_retried_authorization_;
diff --git a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
index 2842b7b4437..8fffad918d6 100644
--- a/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/chromium/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -16,10 +16,13 @@
#include "components/autofill/core/browser/autofill_test_utils.h"
#include "components/autofill/core/browser/credit_card_save_manager.h"
#include "components/autofill/core/browser/payments/payments_client.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
+#include "components/variations/variations_associated_data.h"
+#include "components/variations/variations_http_header_provider.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "services/identity/public/cpp/identity_test_environment.h"
@@ -83,6 +86,22 @@ class PaymentsClientTest : public testing::Test,
scoped_feature_list_.InitAndEnableFeature(kAutofillUpstreamSendPanFirstSix);
}
+ void DisableAutofillSendExperimentIdsInPaymentsRPCs() {
+ scoped_feature_list_.InitAndDisableFeature(
+ features::kAutofillSendExperimentIdsInPaymentsRPCs);
+ }
+
+ // Registers a field trial with the specified name and group and an associated
+ // google web property variation id.
+ void CreateFieldTrialWithId(const std::string& trial_name,
+ const std::string& group_name,
+ int variation_id) {
+ variations::AssociateGoogleVariationID(
+ variations::GOOGLE_WEB_PROPERTIES, trial_name, group_name,
+ static_cast<variations::VariationID>(variation_id));
+ base::FieldTrialList::CreateFieldTrial(trial_name, group_name)->group();
+ }
+
// PaymentsClientUnmaskDelegate:
void OnDidGetRealPan(AutofillClient::PaymentsRpcResult result,
const std::string& real_pan) override {
@@ -149,7 +168,7 @@ class PaymentsClientTest : public testing::Test,
}
void IssueOAuthToken() {
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"totally_real_token",
base::Time::Now() + base::TimeDelta::FromDays(10));
@@ -220,7 +239,7 @@ class PaymentsClientTest : public testing::Test,
TEST_F(PaymentsClientTest, OAuthError) {
StartUnmasking();
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithError(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_UNAVAILABLE));
EXPECT_EQ(AutofillClient::PERMANENT_FAILURE, result_);
EXPECT_TRUE(real_pan_.empty());
@@ -302,6 +321,141 @@ TEST_F(PaymentsClientTest,
std::string::npos);
}
+TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTest) {
+ // Register a trial and variation id, so that there is data in variations
+ // headers. Also, the variations header provider may have been registered to
+ // observe some other field trial list, so reset it.
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+ base::FieldTrialList field_trial_list_(nullptr);
+ CreateFieldTrialWithId("AutofillTest", "Group", 369);
+ StartGettingUploadDetails();
+
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("X-Client-Data", &value));
+ // Note that experiment information is stored in X-Client-Data.
+ EXPECT_FALSE(value.empty());
+ // The fetcher's delegate is responsible for freeing the fetcher (and itself).
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+}
+
+TEST_F(PaymentsClientTest, GetUploadDetailsVariationsTestExperimentFlagOff) {
+ // Register a trial and variation id, so that there is data in variations
+ // headers. Also, the variations header provider may have been registered to
+ // observe some other field trial list, so reset it.
+ DisableAutofillSendExperimentIdsInPaymentsRPCs();
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+ base::FieldTrialList field_trial_list_(nullptr);
+ CreateFieldTrialWithId("AutofillTest", "Group", 369);
+ StartGettingUploadDetails();
+
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string value;
+ EXPECT_FALSE(headers.GetHeader("X-Client-Data", &value));
+ // Note that experiment information is stored in X-Client-Data.
+ EXPECT_TRUE(value.empty());
+ // The fetcher's delegate is responsible for freeing the fetcher (and itself).
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+}
+
+TEST_F(PaymentsClientTest, UploadCardVariationsTest) {
+ // Register a trial and variation id, so that there is data in variations
+ // headers. Also, the variations header provider may have been registered to
+ // observe some other field trial list, so reset it.
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+ base::FieldTrialList field_trial_list_(nullptr);
+ CreateFieldTrialWithId("AutofillTest", "Group", 369);
+ StartUploading(/*include_cvc=*/true);
+
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("X-Client-Data", &value));
+ // Note that experiment information is stored in X-Client-Data.
+ EXPECT_FALSE(value.empty());
+ // The fetcher's delegate is responsible for freeing the fetcher (and itself).
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+}
+
+TEST_F(PaymentsClientTest, UploadCardVariationsTestExperimentFlagOff) {
+ // Register a trial and variation id, so that there is data in variations
+ // headers. Also, the variations header provider may have been registered to
+ // observe some other field trial list, so reset it.
+ DisableAutofillSendExperimentIdsInPaymentsRPCs();
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+ base::FieldTrialList field_trial_list_(nullptr);
+ CreateFieldTrialWithId("AutofillTest", "Group", 369);
+ StartUploading(/*include_cvc=*/true);
+
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string value;
+ EXPECT_FALSE(headers.GetHeader("X-Client-Data", &value));
+ // Note that experiment information is stored in X-Client-Data.
+ EXPECT_TRUE(value.empty());
+ // The fetcher's delegate is responsible for freeing the fetcher (and itself).
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+}
+
+TEST_F(PaymentsClientTest, UnmaskCardVariationsTest) {
+ // Register a trial and variation id, so that there is data in variations
+ // headers. Also, the variations header provider may have been registered to
+ // observe some other field trial list, so reset it.
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+ base::FieldTrialList field_trial_list_(nullptr);
+ CreateFieldTrialWithId("AutofillTest", "Group", 369);
+ StartUnmasking();
+
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string value;
+ EXPECT_TRUE(headers.GetHeader("X-Client-Data", &value));
+ // Note that experiment information is stored in X-Client-Data.
+ EXPECT_FALSE(value.empty());
+ // The fetcher's delegate is responsible for freeing the fetcher (and itself).
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+}
+
+TEST_F(PaymentsClientTest, UnmaskCardVariationsTestExperimentOff) {
+ // Register a trial and variation id, so that there is data in variations
+ // headers. Also, the variations header provider may have been registered to
+ // observe some other field trial list, so reset it.
+ DisableAutofillSendExperimentIdsInPaymentsRPCs();
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+ base::FieldTrialList field_trial_list_(nullptr);
+ CreateFieldTrialWithId("AutofillTest", "Group", 369);
+ StartUnmasking();
+
+ net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0);
+ net::HttpRequestHeaders headers;
+ fetcher->GetExtraRequestHeaders(&headers);
+ std::string value;
+ EXPECT_FALSE(headers.GetHeader("X-Client-Data", &value));
+ // Note that experiment information is stored in X-Client-Data.
+ EXPECT_TRUE(value.empty());
+ // The fetcher's delegate is responsible for freeing the fetcher (and itself).
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ variations::VariationsHttpHeaderProvider::GetInstance()->ResetForTesting();
+}
+
TEST_F(PaymentsClientTest,
GetDetailsIncludesPanFirstSixInRequestIfExperimentOn) {
EnableAutofillUpstreamSendPanFirstSixExperiment();
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.cc b/chromium/components/autofill/core/browser/personal_data_manager.cc
index 9fbb1c5795f..1b683f584ec 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager.cc
@@ -16,6 +16,7 @@
#include "base/feature_list.h"
#include "base/i18n/case_conversion.h"
#include "base/i18n/timezone.h"
+#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -37,6 +38,8 @@
#include "components/autofill/core/browser/phone_number_i18n.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_util.h"
@@ -378,7 +381,7 @@ void PersonalDataManager::Init(scoped_refptr<AutofillWebDataService> database,
AutofillMetrics::LogIsAutofillEnabledAtStartup(IsAutofillEnabled());
// WebDataService may not be available in tests.
- if (!database_.get())
+ if (!database_)
return;
LoadProfiles();
@@ -402,7 +405,7 @@ PersonalDataManager::~PersonalDataManager() {
CancelPendingQuery(&pending_creditcards_query_);
CancelPendingQuery(&pending_server_creditcards_query_);
- if (database_.get())
+ if (database_)
database_->RemoveObserver(this);
}
@@ -418,20 +421,14 @@ void PersonalDataManager::OnSyncServiceInitialized(
// If the sync service is not enabled for autofill address profiles then run
// address cleanup/startup code here. Otherwise, defer until after sync has
// started.
- if (!IsSyncEnabledFor(sync_service, syncer::AUTOFILL_PROFILE)) {
- ApplyProfileUseDatesFix(); // One-time fix, otherwise NOP.
- ApplyDedupingRoutine(); // Once per major version, otherwise NOP.
- DeleteDisusedAddresses(); // Once per major version, otherwise NOP.
- CreateTestAddresses(); // Once per user profile startup.
- }
+ if (!IsSyncEnabledFor(sync_service, syncer::AUTOFILL_PROFILE))
+ ApplyAddressFixesAndCleanups();
// Similarly, if the sync service is not enabled for autofill credit cards
// then run credit card address cleanup/startup code here. Otherwise, defer
// until after sync has started.
- if (!IsSyncEnabledFor(sync_service, syncer::AUTOFILL_WALLET_DATA)) {
- DeleteDisusedCreditCards(); // Once per major version, otherwise NOP.
- CreateTestCreditCards(); // Once per user profile startup.
- }
+ if (!IsSyncEnabledFor(sync_service, syncer::AUTOFILL_WALLET_DATA))
+ ApplyCardFixesAndCleanups();
if (sync_service_ != sync_service) {
// Before the sync service pointer gets changed, remove the observer.
@@ -440,17 +437,31 @@ void PersonalDataManager::OnSyncServiceInitialized(
sync_service_ = sync_service;
+ UMA_HISTOGRAM_BOOLEAN(
+ "Autofill.ResetFullServerCards.SyncServiceNullOnInitialized",
+ !sync_service_);
if (!sync_service_) {
- ResetFullServerCards();
+ // TODO(crbug.com/851294): Reset server cards once the auth error
+ // investigation is done.
+ ResetFullServerCards(/*dry_run=*/!base::FeatureList::IsEnabled(
+ features::kAutofillResetFullServerCardsOnAuthError));
return;
}
sync_service_->AddObserver(this);
// Re-mask all server cards if the upload state is not active.
- if (syncer::GetUploadToGoogleState(
+ bool is_upload_not_active =
+ syncer::GetUploadToGoogleState(
sync_service_, syncer::ModelType::AUTOFILL_WALLET_DATA) ==
- syncer::UploadState::NOT_ACTIVE) {
- ResetFullServerCards();
+ syncer::UploadState::NOT_ACTIVE;
+ UMA_HISTOGRAM_BOOLEAN(
+ "Autofill.ResetFullServerCards.SyncServiceNotActiveOnInitialized",
+ is_upload_not_active);
+ if (is_upload_not_active) {
+ // TODO(crbug.com/851294): Reset server cards once the auth error
+ // investigation is done.
+ ResetFullServerCards(/*dry_run=*/!base::FeatureList::IsEnabled(
+ features::kAutofillResetFullServerCardsOnAuthError));
}
}
}
@@ -522,26 +533,30 @@ void PersonalDataManager::AutofillMultipleChanged() {
void PersonalDataManager::SyncStarted(syncer::ModelType model_type) {
// Run deferred autofill address profile startup code.
// See: OnSyncServiceInitialized
- if (model_type == syncer::AUTOFILL_PROFILE) {
- ApplyProfileUseDatesFix(); // One-time fix, otherwise NOP.
- ApplyDedupingRoutine(); // Once per major version, otherwise NOP.
- DeleteDisusedAddresses(); // Once per major version, otherwise NOP.
- CreateTestAddresses(); // Once per user profile startup.
- }
+ if (model_type == syncer::AUTOFILL_PROFILE)
+ ApplyAddressFixesAndCleanups();
// Run deferred credit card startup code.
// See: OnSyncServiceInitialized
- if (model_type == syncer::AUTOFILL_WALLET_DATA) {
- DeleteDisusedCreditCards(); // Once per major version, otherwise NOP.
- CreateTestCreditCards(); // Once per user profile startup.
- }
+ if (model_type == syncer::AUTOFILL_WALLET_DATA)
+ ApplyCardFixesAndCleanups();
}
void PersonalDataManager::OnStateChanged(syncer::SyncService* sync_service) {
- if (syncer::GetUploadToGoogleState(sync_service_,
- syncer::ModelType::AUTOFILL_WALLET_DATA) !=
- syncer::UploadState::ACTIVE) {
- ResetFullServerCards();
+ // TODO(mastiz,jkrcal): Once AUTOFILL_WALLET is migrated to USS, it shouldn't
+ // be necessary anymore to implement SyncServiceObserver; instead the
+ // notification should flow through the payments sync bridge.
+ DCHECK_EQ(sync_service_, sync_service);
+ syncer::UploadState upload_state = syncer::GetUploadToGoogleState(
+ sync_service_, syncer::ModelType::AUTOFILL_WALLET_DATA);
+ UMA_HISTOGRAM_ENUMERATION(
+ "Autofill.ResetFullServerCards.SyncServiceStatusOnStateChanged",
+ upload_state);
+ if (upload_state == syncer::UploadState::NOT_ACTIVE) {
+ // TODO(crbug.com/851294): Reset server cards once the auth error
+ // investigation is done.
+ ResetFullServerCards(/*dry_run=*/!base::FeatureList::IsEnabled(
+ features::kAutofillResetFullServerCardsOnAuthError));
}
}
@@ -560,7 +575,7 @@ void PersonalDataManager::MarkObserversInsufficientFormDataForImport() {
}
void PersonalDataManager::RecordUseOf(const AutofillDataModel& data_model) {
- if (is_off_the_record_ || !database_.get())
+ if (is_off_the_record_ || !database_)
return;
CreditCard* credit_card = GetCreditCardByGUID(data_model.guid());
@@ -600,7 +615,7 @@ void PersonalDataManager::AddProfile(const AutofillProfile& profile) {
if (FindByGUID<AutofillProfile>(web_profiles_, profile.guid()))
return;
- if (!database_.get())
+ if (!database_)
return;
// Don't add a duplicate.
@@ -631,7 +646,7 @@ void PersonalDataManager::UpdateProfile(const AutofillProfile& profile) {
return;
}
- if (!database_.get())
+ if (!database_)
return;
// Make the update.
@@ -665,7 +680,7 @@ void PersonalDataManager::AddCreditCard(const CreditCard& credit_card) {
if (FindByGUID<CreditCard>(local_credit_cards_, credit_card.guid()))
return;
- if (!database_.get())
+ if (!database_)
return;
// Don't add a duplicate.
@@ -700,7 +715,7 @@ void PersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) {
// Update the cached version.
*existing_credit_card = credit_card;
- if (!database_.get())
+ if (!database_)
return;
// Make the update.
@@ -716,7 +731,7 @@ void PersonalDataManager::AddFullServerCreditCard(
DCHECK(!credit_card.IsEmpty(app_locale_));
DCHECK(!credit_card.server_id().empty());
- if (is_off_the_record_ || !database_.get())
+ if (is_off_the_record_ || !database_)
return;
// Don't add a duplicate.
@@ -735,7 +750,7 @@ void PersonalDataManager::UpdateServerCreditCard(
const CreditCard& credit_card) {
DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type());
- if (is_off_the_record_ || !database_.get())
+ if (is_off_the_record_ || !database_)
return;
// Look up by server id, not GUID.
@@ -764,7 +779,7 @@ void PersonalDataManager::UpdateServerCardMetadata(
const CreditCard& credit_card) {
DCHECK_NE(CreditCard::LOCAL_CARD, credit_card.record_type());
- if (is_off_the_record_ || !database_.get())
+ if (is_off_the_record_ || !database_)
return;
database_->UpdateServerCardMetadata(credit_card);
@@ -785,15 +800,27 @@ void PersonalDataManager::ResetFullServerCard(const std::string& guid) {
}
}
-void PersonalDataManager::ResetFullServerCards() {
+void PersonalDataManager::ResetFullServerCards(bool is_dry_run) {
+ size_t nb_cards_reset = 0;
for (const auto& card : server_credit_cards_) {
if (card->record_type() == CreditCard::FULL_SERVER_CARD) {
- CreditCard card_copy = *card;
- card_copy.set_record_type(CreditCard::MASKED_SERVER_CARD);
- card_copy.SetNumber(card->LastFourDigits());
- UpdateServerCreditCard(card_copy);
+ ++nb_cards_reset;
+ if (!is_dry_run) {
+ CreditCard card_copy = *card;
+ card_copy.set_record_type(CreditCard::MASKED_SERVER_CARD);
+ card_copy.SetNumber(card->LastFourDigits());
+ UpdateServerCreditCard(card_copy);
+ }
}
}
+ if (is_dry_run) {
+ UMA_HISTOGRAM_COUNTS_100(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun",
+ nb_cards_reset);
+ } else {
+ UMA_HISTOGRAM_COUNTS_100("Autofill.ResetFullServerCards.NumberOfCardsReset",
+ nb_cards_reset);
+ }
}
void PersonalDataManager::ClearAllServerData() {
@@ -854,7 +881,7 @@ void PersonalDataManager::RemoveByGUID(const std::string& guid) {
if (!is_credit_card && !is_profile)
return;
- if (!database_.get())
+ if (!database_)
return;
if (is_credit_card) {
@@ -987,6 +1014,32 @@ void PersonalDataManager::RemoveProfilesNotUsedSinceTimestamp(
num_profiles_supressed);
}
+// static
+void PersonalDataManager::MaybeRemoveInvalidSuggestions(
+ const AutofillType& type,
+ std::vector<AutofillProfile*>* profiles) {
+ const bool suggest_invalid =
+ base::FeatureList::IsEnabled(kAutofillSuggestInvalidProfileData);
+
+ for (size_t i = 0; i < profiles->size(); ++i) {
+ bool is_invalid = (*profiles)[i]->GetValidityState(
+ type.GetStorableType()) == AutofillProfile::INVALID;
+ if (is_invalid) {
+ UMA_HISTOGRAM_BOOLEAN("Autofill.InvalidProfileData.UsedForSuggestion",
+ suggest_invalid);
+ if (!suggest_invalid)
+ (*profiles)[i] = nullptr;
+ }
+ }
+
+ if (!suggest_invalid) {
+ profiles->erase(
+ std::stable_partition(profiles->begin(), profiles->end(),
+ [](AutofillProfile* p) { return p != nullptr; }),
+ profiles->end());
+ }
+}
+
std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
const AutofillType& type,
const base::string16& field_contents,
@@ -1002,13 +1055,15 @@ std::vector<Suggestion> PersonalDataManager::GetProfileSuggestions(
// Get the profiles to suggest, which are already sorted.
std::vector<AutofillProfile*> profiles = GetProfilesToSuggest();
- // If enabled, suppress disused address profiles when triggered from an empty
- // field.
- if (field_contents_canon.empty() &&
- base::FeatureList::IsEnabled(kAutofillSuppressDisusedAddresses)) {
- const base::Time min_last_used =
- AutofillClock::Now() - kDisusedProfileTimeDelta;
- RemoveProfilesNotUsedSinceTimestamp(min_last_used, &profiles);
+ // When suggesting with no prefix to match, consider suppressing disused
+ // address suggestions as well as those based on invalid profile data.
+ if (field_contents_canon.empty()) {
+ if (base::FeatureList::IsEnabled(kAutofillSuppressDisusedAddresses)) {
+ const base::Time min_last_used =
+ AutofillClock::Now() - kDisusedProfileTimeDelta;
+ RemoveProfilesNotUsedSinceTimestamp(min_last_used, &profiles);
+ }
+ MaybeRemoveInvalidSuggestions(type, &profiles);
}
std::vector<Suggestion> suggestions;
@@ -1217,6 +1272,40 @@ void PersonalDataManager::SetPrefService(PrefService* pref_service) {
}
}
+void PersonalDataManager::ClearProfileNonSettingsOrigins() {
+ bool has_updated = false;
+
+ for (AutofillProfile* profile : GetProfiles()) {
+ if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) {
+ profile->set_origin(std::string());
+ database_->UpdateAutofillProfile(*profile);
+ has_updated = true;
+ }
+ }
+
+ // Refresh the local cache and send notifications to observers if a changed
+ // was made.
+ if (has_updated)
+ Refresh();
+}
+
+void PersonalDataManager::ClearCreditCardNonSettingsOrigins() {
+ bool has_updated = false;
+
+ for (CreditCard* card : GetLocalCreditCards()) {
+ if (card->origin() != kSettingsOrigin && !card->origin().empty()) {
+ card->set_origin(std::string());
+ database_->UpdateCreditCard(*card);
+ has_updated = true;
+ }
+ }
+
+ // Refresh the local cache and send notifications to observers if a changed
+ // was made.
+ if (has_updated)
+ Refresh();
+}
+
// TODO(crbug.com/618448): Refactor MergeProfile to not depend on class
// variables.
std::string PersonalDataManager::MergeProfile(
@@ -1360,7 +1449,7 @@ void PersonalDataManager::SetProfiles(std::vector<AutofillProfile>* profiles) {
IsEmptyFunctor<AutofillProfile>(app_locale_)),
profiles->end());
- if (!database_.get())
+ if (!database_)
return;
// Any profiles that are not in the new profile list should be removed from
@@ -1403,7 +1492,7 @@ void PersonalDataManager::SetCreditCards(
IsEmptyFunctor<CreditCard>(app_locale_)),
credit_cards->end());
- if (!database_.get())
+ if (!database_)
return;
// Any credit cards that are not in the new credit card list should be
@@ -1436,7 +1525,7 @@ void PersonalDataManager::SetCreditCards(
}
void PersonalDataManager::LoadProfiles() {
- if (!database_.get()) {
+ if (!database_) {
NOTREACHED();
return;
}
@@ -1449,7 +1538,7 @@ void PersonalDataManager::LoadProfiles() {
}
void PersonalDataManager::LoadCreditCards() {
- if (!database_.get()) {
+ if (!database_) {
NOTREACHED();
return;
}
@@ -1464,7 +1553,7 @@ void PersonalDataManager::LoadCreditCards() {
void PersonalDataManager::CancelPendingQuery(
WebDataServiceBase::Handle* handle) {
if (*handle) {
- if (!database_.get()) {
+ if (!database_) {
NOTREACHED();
return;
}
@@ -1681,12 +1770,11 @@ std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
} else {
#if defined(OS_ANDROID)
// Since Android places the label on its own row, there's more
- // horizontal
- // space to work with. Show "Amex - 1234" rather than desktop's "*1234".
+ // horizontal space to work with. Show "Amex - 1234" rather than
+ // desktop's "****1234".
suggestion->label = credit_card->NetworkOrBankNameAndLastFourDigits();
#else
- suggestion->label = base::ASCIIToUTF16("*");
- suggestion->label.append(credit_card->LastFourDigits());
+ suggestion->label = credit_card->ObfuscatedLastFourDigits();
#endif
}
}
@@ -1703,27 +1791,18 @@ std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
return suggestions;
}
-void PersonalDataManager::ApplyProfileUseDatesFix() {
+void PersonalDataManager::RemoveOrphanAutofillTableRows() {
// Don't run if the fix has already been applied.
- if (pref_service_->GetBoolean(prefs::kAutofillProfileUseDatesFixed))
+ if (pref_service_->GetBoolean(prefs::kAutofillOrphanRowsRemoved))
return;
- std::vector<AutofillProfile> profiles;
- bool has_changed_data = false;
- for (AutofillProfile* profile : GetProfiles()) {
- if (profile->use_date() == base::Time()) {
- profile->set_use_date(AutofillClock::Now() -
- base::TimeDelta::FromDays(14));
- has_changed_data = true;
- }
- profiles.push_back(*profile);
- }
+ if (!database_)
+ return;
- // Set the pref so that this fix is never run again.
- pref_service_->SetBoolean(prefs::kAutofillProfileUseDatesFixed, true);
+ database_->RemoveOrphanAutofillTableRows();
- if (has_changed_data)
- SetProfiles(&profiles);
+ // Set the pref so that this fix is never run again.
+ pref_service_->SetBoolean(prefs::kAutofillOrphanRowsRemoved, true);
}
bool PersonalDataManager::ApplyDedupingRoutine() {
@@ -2070,7 +2149,7 @@ std::string PersonalDataManager::MergeServerAddressesIntoProfiles(
return guid;
}
-void PersonalDataManager::CreateTestAddresses() {
+void PersonalDataManager::MaybeCreateTestAddresses() {
if (has_created_test_addresses_)
return;
@@ -2083,7 +2162,7 @@ void PersonalDataManager::CreateTestAddresses() {
AddProfile(CreateDisusedDeletableTestAddress(app_locale_));
}
-void PersonalDataManager::CreateTestCreditCards() {
+void PersonalDataManager::MaybeCreateTestCreditCards() {
if (has_created_test_credit_cards_)
return;
@@ -2228,10 +2307,30 @@ bool PersonalDataManager::ShouldSuggestServerCards() const {
if (is_syncing_for_test_)
return true;
+ // Check if the feature to offer server cards on auth error is enabled.
+ if (base::FeatureList::IsEnabled(
+ features::kAutofillEnablePaymentsInteractionsOnAuthError)) {
+ return true;
+ }
+
// Server cards should be suggested if the sync service active.
return syncer::GetUploadToGoogleState(
sync_service_, syncer::ModelType::AUTOFILL_WALLET_DATA) ==
syncer::UploadState::ACTIVE;
}
+void PersonalDataManager::ApplyAddressFixesAndCleanups() {
+ RemoveOrphanAutofillTableRows(); // One-time fix, otherwise NOP.
+ ApplyDedupingRoutine(); // Once per major version, otherwise NOP.
+ DeleteDisusedAddresses(); // Once per major version, otherwise NOP.
+ MaybeCreateTestAddresses(); // Once per user profile startup.
+ ClearProfileNonSettingsOrigins(); // Ran everytime it is called.
+}
+
+void PersonalDataManager::ApplyCardFixesAndCleanups() {
+ DeleteDisusedCreditCards(); // Once per major version, otherwise NOP.
+ MaybeCreateTestCreditCards(); // Once per user profile startup.
+ ClearCreditCardNonSettingsOrigins(); // Ran everytime it is called.
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/personal_data_manager.h b/chromium/components/autofill/core/browser/personal_data_manager.h
index 73dd7c529a3..9753af37f2d 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/personal_data_manager.h
@@ -163,8 +163,10 @@ class PersonalDataManager : public KeyedService,
// Resets the card for |guid| to the masked state.
void ResetFullServerCard(const std::string& guid);
- // Resets all unmasked cards to the masked state.
- void ResetFullServerCards();
+ // Resets all unmasked cards to the masked state if |is_dry_run| is false.
+ // Only records the number of cards that would have been remasked if
+ // |is_dry_run| is true.
+ void ResetFullServerCards(bool is_dry_run = false);
// Deletes all server profiles and cards (both masked and unmasked).
void ClearAllServerData();
@@ -215,6 +217,12 @@ class PersonalDataManager : public KeyedService,
base::Time min_last_used,
std::vector<AutofillProfile*>* profiles);
+ // Remove profiles that whose |type| field is flagged as invalid, if Chrome
+ // is configured to not make suggestions based on invalid data.
+ static void MaybeRemoveInvalidSuggestions(
+ const AutofillType& type,
+ std::vector<AutofillProfile*>* profiles);
+
// Loads profiles that can suggest data for |type|. |field_contents| is the
// part the user has already typed. |field_is_autofilled| is true if the field
// has already been autofilled. |other_field_types| represents the rest of
@@ -326,9 +334,6 @@ class PersonalDataManager : public KeyedService,
DedupeProfiles_GuidsMergeMap);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
UpdateCardsBillingAddressReference);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest, ApplyProfileUseDatesFix);
- FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
- ApplyProfileUseDatesFix_NotAppliedTwice);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
ApplyDedupingRoutine_CardsBillingAddressIdUpdated);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
@@ -375,6 +380,10 @@ class PersonalDataManager : public KeyedService,
GetCreditCardSuggestions_CreditCardAutofillDisabled);
FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
GetCreditCardSuggestions_NoCardsLoadedIfDisabled);
+ FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
+ ClearProfileNonSettingsOrigins);
+ FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
+ ClearCreditCardNonSettingsOrigins);
friend class autofill::AutofillInteractiveTest;
friend class autofill::PersonalDataManagerFactory;
@@ -448,6 +457,11 @@ class PersonalDataManager : public KeyedService,
// this class and must outlive |this|.
void SetPrefService(PrefService* pref_service);
+ // Clears the value of the origin field of the autofill profiles or cards that
+ // were not created from the settings page.
+ void ClearProfileNonSettingsOrigins();
+ void ClearCreditCardNonSettingsOrigins();
+
void set_database(scoped_refptr<AutofillWebDataService> database) {
database_ = database;
}
@@ -504,9 +518,9 @@ class PersonalDataManager : public KeyedService,
// upgrade. The card will need to be local and disused, to be deletable.
bool IsCreditCardDeletable(CreditCard* card);
- // Runs the Autofill use date fix routine if it's never been done. Returns
- // whether the routine was run.
- void ApplyProfileUseDatesFix();
+ // Runs the routine that removes the orphan rows in the autofill tables if
+ // it's never been done.
+ void RemoveOrphanAutofillTableRows();
// Applies the deduping routine once per major version if the feature is
// enabled. Calls DedupeProfiles with the content of |web_profiles_| as a
@@ -586,16 +600,22 @@ class PersonalDataManager : public KeyedService,
// If the AutofillCreateDataForTest feature is enabled, this helper creates
// autofill address data that would otherwise be difficult to create
// manually using the UI.
- void CreateTestAddresses();
+ void MaybeCreateTestAddresses();
// If the AutofillCreateDataForTest feature is enabled, this helper creates
// autofill credit card data that would otherwise be difficult to create
// manually using the UI.
- void CreateTestCreditCards();
+ void MaybeCreateTestCreditCards();
// Whether the server cards are enabled and should be suggested to the user.
bool ShouldSuggestServerCards() const;
+ // Applies various fixes and cleanups on autofill addresses.
+ void ApplyAddressFixesAndCleanups();
+
+ // Applies various fixes and cleanups on autofill credit cards.
+ void ApplyCardFixesAndCleanups();
+
const std::string app_locale_;
// The default country code for new addresses.
diff --git a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
index e1e668bfe17..e718d54a6bf 100644
--- a/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/chromium/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -19,7 +19,9 @@
#include "base/guid.h"
#include "base/i18n/time_formatting.h"
#include "base/message_loop/message_loop.h"
+#include "base/rand_util.h"
#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/histogram_tester.h"
@@ -41,11 +43,13 @@
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h"
+#include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_pref_names.h"
#include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/form_data.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/prefs/pref_service.h"
+#include "components/sync/driver/sync_service_utils.h"
#include "components/variations/variations_params_manager.h"
#include "components/webdata/common/web_data_service_base.h"
#include "components/webdata/common/web_database_service.h"
@@ -58,13 +62,6 @@ namespace {
enum UserMode { USER_MODE_NORMAL, USER_MODE_INCOGNITO };
-const char kUTF8MidlineEllipsis[] =
- " "
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86"
- "\xE2\x80\xA2\xE2\x80\x86";
-
const base::Time kArbitraryTime = base::Time::FromDoubleT(25);
const base::Time kSomeLaterTime = base::Time::FromDoubleT(1000);
const base::Time kMuchLaterTime = base::Time::FromDoubleT(5000);
@@ -76,7 +73,7 @@ ACTION(QuitMainMessageLoop) {
class PersonalDataLoadedObserverMock : public PersonalDataManagerObserver {
public:
PersonalDataLoadedObserverMock() {}
- virtual ~PersonalDataLoadedObserverMock() {}
+ ~PersonalDataLoadedObserverMock() override {}
MOCK_METHOD0(OnPersonalDataChanged, void());
};
@@ -151,7 +148,7 @@ class PersonalDataManagerTestBase {
void SetUpReferenceProfile() {
ASSERT_EQ(0U, personal_data_->GetProfiles().size());
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
@@ -172,7 +169,7 @@ class PersonalDataManagerTestBase {
ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -182,7 +179,7 @@ class PersonalDataManagerTestBase {
personal_data_->AddCreditCard(credit_card0);
CreditCard credit_card1("1141084B-72D7-4B73-90CF-3D6AC154673B",
- "https://www.example.com");
+ test::kEmptyOrigin);
credit_card1.set_use_count(300);
credit_card1.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(10));
@@ -191,7 +188,7 @@ class PersonalDataManagerTestBase {
personal_data_->AddCreditCard(credit_card1);
CreditCard credit_card2("002149C1-EE28-4213-A3B9-DA243FFF021B",
- "https://www.example.com");
+ test::kEmptyOrigin);
credit_card2.set_use_count(1);
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
@@ -207,8 +204,10 @@ class PersonalDataManagerTestBase {
ASSERT_EQ(3U, personal_data_->GetCreditCards().size());
}
- // Add 3 credit cards. One local, one masked, one full.
+ // Add 3 credit cards. One local, one masked, one full. Creates two masked
+ // cards on Linux, since full server cards are not supported.
void SetUpThreeCardTypes() {
+ EXPECT_EQ(0U, personal_data_->GetCreditCards().size());
CreditCard masked_server_card;
test::SetCreditCardInfo(&masked_server_card, "Elvis Presley",
"4234567890123456", // Visa
@@ -216,8 +215,19 @@ class PersonalDataManagerTestBase {
masked_server_card.set_guid("00000000-0000-0000-0000-000000000007");
masked_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
masked_server_card.set_server_id("masked_id");
+ masked_server_card.set_use_count(15);
personal_data_->AddFullServerCreditCard(masked_server_card);
- personal_data_->ResetFullServerCard(masked_server_card.guid());
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
+ .WillOnce(QuitMainMessageLoop());
+ base::RunLoop().Run();
+ ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
+
+// Cards are automatically remasked on Linux since full server cards are not
+// supported.
+#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+ personal_data_->ResetFullServerCard(
+ personal_data_->GetCreditCards()[0]->guid());
+#endif
CreditCard full_server_card;
test::SetCreditCardInfo(&full_server_card, "Buddy Holly",
@@ -226,6 +236,7 @@ class PersonalDataManagerTestBase {
full_server_card.set_guid("00000000-0000-0000-0000-000000000008");
full_server_card.set_record_type(CreditCard::FULL_SERVER_CARD);
full_server_card.set_server_id("full_id");
+ full_server_card.set_use_count(10);
personal_data_->AddFullServerCreditCard(full_server_card);
CreditCard local_card;
@@ -234,6 +245,7 @@ class PersonalDataManagerTestBase {
"08", "2999", "1");
local_card.set_guid("00000000-0000-0000-0000-000000000009");
local_card.set_record_type(CreditCard::LOCAL_CARD);
+ local_card.set_use_count(5);
personal_data_->AddCreditCard(local_card);
EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
@@ -247,7 +259,7 @@ class PersonalDataManagerTestBase {
// and has not been used in last 400 days. This card is supposed to be
// deleted during a major version upgrade.
void CreateDeletableExpiredAndDisusedCreditCard() {
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"1999", "1");
@@ -322,8 +334,6 @@ class PersonalDataManagerTest : public PersonalDataManagerTestBase,
// Reset the deduping pref to its default value.
personal_data_->pref_service_->SetInteger(
prefs::kAutofillLastVersionDeduped, 0);
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, false);
}
void TearDown() override {
@@ -569,17 +579,17 @@ TEST_F(PersonalDataManagerTest, SaveImportedProfileSetModificationDate) {
}
TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
"Orlando", "FL", "32801", "US", "19482937549");
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
@@ -619,16 +629,16 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
EnableWalletCardImport();
- CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
"5105105105105100" /* Mastercard */, "12", "2999",
"1");
- CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card2, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -669,7 +679,7 @@ TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
ExpectSameElements(cards, personal_data_->GetCreditCards());
// Add a full server card.
- CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card3, "Jane Doe",
"4111111111111111" /* Visa */, "04", "2999", "1");
credit_card3.set_record_type(CreditCard::FULL_SERVER_CARD);
@@ -711,7 +721,7 @@ TEST_F(PersonalDataManagerTest, AddCreditCard_BasicInformation) {
test_clock.SetNow(kArbitraryTime);
// Add a credit card to the database.
- CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
personal_data_->AddCreditCard(credit_card);
@@ -1030,21 +1040,21 @@ TEST_F(PersonalDataManagerTest, SavesServerCardType) {
}
TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
"Orlando", "FL", "32801", "US", "19482937549");
- CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
"5105105105105100" /* Mastercard */, "12", "2999",
"1");
@@ -1084,7 +1094,7 @@ TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
// Test for http://crbug.com/50047. Makes sure that guids are populated
// correctly on load.
TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "y", "", "", "", "", "", "", "", "", "", "",
"");
@@ -1099,7 +1109,7 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
EXPECT_EQ(0, profile0.Compare(*results2[0]));
// Add a new profile.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "z", "", "", "", "", "", "", "", "", "", "",
"");
personal_data_->AddProfile(profile1);
@@ -1115,17 +1125,17 @@ TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
}
TEST_F(PersonalDataManagerTest, SetUniqueCreditCardLabels) {
- CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
credit_card0.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("John"));
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
credit_card1.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Paul"));
- CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
credit_card2.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Ringo"));
- CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
credit_card3.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Other"));
- CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card4(base::GenerateGUID(), test::kEmptyOrigin);
credit_card4.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Ozzy"));
- CreditCard credit_card5(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card5(base::GenerateGUID(), test::kEmptyOrigin);
credit_card5.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Dio"));
// Add the test credit cards to the database.
@@ -1152,7 +1162,7 @@ TEST_F(PersonalDataManagerTest, SetUniqueCreditCardLabels) {
}
TEST_F(PersonalDataManagerTest, SetEmptyProfile) {
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "", "", "", "", "", "", "", "", "", "", "",
"");
@@ -1171,7 +1181,7 @@ TEST_F(PersonalDataManagerTest, SetEmptyProfile) {
}
TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) {
- CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "", "", "", "", "");
// Add the empty credit card to the database.
@@ -1189,12 +1199,12 @@ TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) {
}
TEST_F(PersonalDataManagerTest, Refresh) {
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
"Orlando", "FL", "32801", "US", "19482937549");
@@ -1210,7 +1220,7 @@ TEST_F(PersonalDataManagerTest, Refresh) {
profiles.push_back(&profile1);
ExpectSameElements(profiles, personal_data_->GetProfiles());
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
@@ -1252,7 +1262,7 @@ TEST_F(PersonalDataManagerTest, Refresh) {
// overwriting existing unverified profiles.
TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) {
// Start with an unverified profile.
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
@@ -1327,7 +1337,7 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_EQ(0U, non_empty_types.size());
// Test with one profile stored.
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Marion", nullptr, "Morrison",
"johnwayne@me.xyz", nullptr, "123 Zoo St.", nullptr,
"Hollywood", "CA", "91601", "US", "14155678910");
@@ -1357,12 +1367,12 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
// Test with multiple profiles stored.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
"Orlando", "FL", "32801", "US", "16502937549");
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "16502937549");
@@ -1396,7 +1406,7 @@ TEST_F(PersonalDataManagerTest, GetNonEmptyTypes) {
EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
// Test with credit card information also stored.
- CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "");
personal_data_->AddCreditCard(credit_card);
@@ -1441,13 +1451,13 @@ TEST_F(PersonalDataManagerTest, IncognitoReadOnly) {
ASSERT_TRUE(personal_data_->GetProfiles().empty());
ASSERT_TRUE(personal_data_->GetCreditCards().empty());
- AutofillProfile steve_jobs(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile steve_jobs(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&steve_jobs, "Steven", "Paul", "Jobs", "sjobs@apple.com",
"Apple Computer, Inc.", "1 Infinite Loop", "",
"Cupertino", "CA", "95014", "US", "(800) 275-2273");
personal_data_->AddProfile(steve_jobs);
- CreditCard bill_gates(base::GenerateGUID(), "https://www.example.com");
+ CreditCard bill_gates(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&bill_gates, "William H. Gates", "5555555555554444",
"1", "2020", "1");
personal_data_->AddCreditCard(bill_gates);
@@ -1464,7 +1474,7 @@ TEST_F(PersonalDataManagerTest, IncognitoReadOnly) {
// Add profiles or credit card shouldn't work.
personal_data_->AddProfile(test::GetFullProfile());
- CreditCard larry_page(base::GenerateGUID(), "https://www.example.com");
+ CreditCard larry_page(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&larry_page, "Lawrence Page", "4111111111111111",
"10", "2025", "1");
personal_data_->AddCreditCard(larry_page);
@@ -1602,7 +1612,7 @@ TEST_F(PersonalDataManagerTest, DefaultCountryCodeComesFromProfiles) {
}
TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
@@ -1625,7 +1635,7 @@ TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) {
}
TEST_F(PersonalDataManagerTest, GetProfileSuggestions) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1642,7 +1652,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions) {
}
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_PhoneSubstring) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1658,7 +1668,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_PhoneSubstring) {
}
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_HideSubsets) {
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1734,7 +1744,7 @@ TEST_F(PersonalDataManagerTest,
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) {
// Set up the profiles. They are named with number suffixes X so the X is the
// order in which they should be ordered by frecency.
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1743,7 +1753,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) {
profile3.set_use_count(5);
personal_data_->AddProfile(profile3);
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1752,7 +1762,7 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) {
profile1.set_use_count(10);
personal_data_->AddProfile(profile1);
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1775,21 +1785,21 @@ TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) {
// and only two if the appropriate field trial is set.
TEST_F(PersonalDataManagerTest, GetProfileSuggestions_NumberOfSuggestions) {
// Set up 3 different profiles.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
personal_data_->AddProfile(profile1);
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
personal_data_->AddProfile(profile2);
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1850,7 +1860,7 @@ TEST_F(PersonalDataManagerTest,
TEST_F(PersonalDataManagerTest,
GetProfileSuggestions_SuppressDisusedProfilesOnEmptyField) {
// Set up 2 different profiles.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1858,7 +1868,7 @@ TEST_F(PersonalDataManagerTest,
profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200));
personal_data_->AddProfile(profile1);
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox",
"456 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1926,6 +1936,54 @@ TEST_F(PersonalDataManagerTest,
}
}
+// Tests that suggestions based on invalid data are handled correctly.
+TEST_F(PersonalDataManagerTest, GetProfileSuggestions_InvalidData) {
+ // Set up 2 different profiles.
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "9876543210");
+ profile1.SetValidityState(PHONE_HOME_WHOLE_NUMBER, AutofillProfile::INVALID);
+ profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
+ personal_data_->AddProfile(profile1);
+
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "456 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "1234567890");
+ personal_data_->AddProfile(profile2);
+
+ ResetPersonalDataManager(USER_MODE_NORMAL);
+ {
+ base::HistogramTester histogram_tester;
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndDisableFeature(kAutofillSuggestInvalidProfileData);
+ std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
+ AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false,
+ std::vector<ServerFieldType>());
+ ASSERT_EQ(1U, suggestions.size());
+ EXPECT_EQ(base::ASCIIToUTF16("1234567890"), suggestions[0].value);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.InvalidProfileData.UsedForSuggestion", false, 1);
+ }
+
+ {
+ base::HistogramTester histogram_tester;
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndEnableFeature(kAutofillSuggestInvalidProfileData);
+ std::vector<Suggestion> suggestions = personal_data_->GetProfileSuggestions(
+ AutofillType(PHONE_HOME_WHOLE_NUMBER), base::string16(), false,
+ std::vector<ServerFieldType>());
+ ASSERT_EQ(2U, suggestions.size());
+ EXPECT_EQ(base::ASCIIToUTF16("1234567890"), suggestions[0].value);
+ EXPECT_EQ(base::ASCIIToUTF16("9876543210"), suggestions[1].value);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.InvalidProfileData.UsedForSuggestion", true, 1);
+ }
+}
+
TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesMaskedServerCard) {
// Add a masked server card.
std::vector<CreditCard> server_cards;
@@ -1969,7 +2027,7 @@ TEST_F(PersonalDataManagerTest, IsKnownCard_MatchesLocalCard) {
EnableWalletCardImport();
// Add a local card.
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
"4234 5678 9012 2110" /* Visa */, "04", "2999", "1");
personal_data_->AddCreditCard(credit_card0);
@@ -1988,7 +2046,7 @@ TEST_F(PersonalDataManagerTest, IsKnownCard_TypeDoesNotMatch) {
EnableWalletCardImport();
// Add a local card.
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
"4234 5678 9012 2110" /* Visa */, "04", "2999", "1");
personal_data_->AddCreditCard(credit_card0);
@@ -2008,7 +2066,7 @@ TEST_F(PersonalDataManagerTest, IsKnownCard_LastFourDoesNotMatch) {
EnableWalletCardImport();
// Add a local card.
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
"4234 5678 9012 2110" /* Visa */, "04", "2999", "1");
personal_data_->AddCreditCard(credit_card0);
@@ -2221,7 +2279,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) {
// Add a never used non expired credit card.
CreditCard credit_card0("002149C1-EE28-4213-A3B9-DA243FFF021B",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Bonnie Parker",
"5105105105105100" /* Mastercard */, "04", "2999",
"1");
@@ -2229,7 +2287,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) {
// Add an expired card with a higher frecency score.
CreditCard credit_card1("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"1999", "1");
@@ -2240,7 +2298,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ExpiredCards) {
// Add an expired card with a lower frecency score.
CreditCard credit_card2("1141084B-72D7-4B73-90CF-3D6AC154673B",
- "https://www.example.com");
+ test::kEmptyOrigin);
credit_card2.set_use_count(3);
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
@@ -2275,7 +2333,7 @@ TEST_F(PersonalDataManagerTest,
// Add a never used non expired local credit card.
CreditCard credit_card0("002149C1-EE28-4213-A3B9-DA243FFF021B",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Bonnie Parker",
"5105105105105100" /* Mastercard */, "04", "2999",
"1");
@@ -2305,7 +2363,7 @@ TEST_F(PersonalDataManagerTest,
// Add an expired local card last used 180 days ago.
CreditCard credit_card3("1141084B-72D7-4B73-90CF-3D6AC154673B",
- "https://www.example.com");
+ test::kEmptyOrigin);
credit_card3.set_use_date(now - base::TimeDelta::FromDays(182));
test::SetCreditCardInfo(&credit_card3, "John Dillinger",
"378282246310005" /* American Express */, "01",
@@ -2391,12 +2449,12 @@ TEST_F(PersonalDataManagerTest,
/*include_server_cards=*/true);
ASSERT_EQ(2U, suggestions.size());
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "3456"),
- suggestions[0].value);
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "6543"),
- suggestions[1].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Visa ") +
+ test::ObfuscatedCardDigitsAsUTF8("3456")),
+ suggestions[0].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Visa ") +
+ test::ObfuscatedCardDigitsAsUTF8("6543")),
+ suggestions[1].value);
}
}
@@ -2407,7 +2465,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -2417,7 +2475,7 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
personal_data_->AddCreditCard(credit_card0);
CreditCard credit_card1("1141084B-72D7-4B73-90CF-3D6AC154673B",
- "https://www.example.com");
+ test::kEmptyOrigin);
credit_card1.set_use_count(300);
credit_card1.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(10));
@@ -2437,9 +2495,9 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_NumberMissing) {
/* field_contents= */ base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(1U, suggestions.size());
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "0005"),
- suggestions[0].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Amex ") +
+ test::ObfuscatedCardDigitsAsUTF8("0005")),
+ suggestions[0].value);
EXPECT_EQ(base::ASCIIToUTF16("04/99"), suggestions[0].label);
}
@@ -2505,18 +2563,18 @@ TEST_F(PersonalDataManagerTest, GetCreditCardSuggestions_ServerDuplicates) {
AutofillType(CREDIT_CARD_NUMBER), /* field_contents= */ base::string16(),
/*include_server_cards=*/true);
ASSERT_EQ(4U, suggestions.size());
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "3456"),
- suggestions[0].value);
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "0005"),
- suggestions[1].value);
- EXPECT_EQ(base::UTF8ToUTF16(std::string("Mastercard") + kUTF8MidlineEllipsis +
- "5100"),
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Visa ") +
+ test::ObfuscatedCardDigitsAsUTF8("3456")),
+ suggestions[0].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Amex ") +
+ test::ObfuscatedCardDigitsAsUTF8("0005")),
+ suggestions[1].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Mastercard ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
suggestions[2].value);
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "5100"),
- suggestions[3].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Visa ") +
+ test::ObfuscatedCardDigitsAsUTF8("5100")),
+ suggestions[3].value);
}
// Tests that a full server card can be a dupe of more than one local card.
@@ -2551,7 +2609,7 @@ TEST_F(PersonalDataManagerTest,
// Add a second dupe local card to make sure a full server card can be a dupe
// of more than one local card.
CreditCard credit_card3("4141084B-72D7-4B73-90CF-3D6AC154673B",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card3, "Clyde Barrow", "", "04", "", "");
personal_data_->AddCreditCard(credit_card3);
@@ -2575,7 +2633,7 @@ TEST_F(PersonalDataManagerTest,
// Add a local card.
CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -2620,17 +2678,17 @@ TEST_F(PersonalDataManagerTest,
ASSERT_EQ(3U, suggestions.size());
// Local cards will show network.
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Amex") + kUTF8MidlineEllipsis + "0005"),
- suggestions[0].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Amex ") +
+ test::ObfuscatedCardDigitsAsUTF8("0005")),
+ suggestions[0].value);
// Server card without bank name will show network.
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Visa") + kUTF8MidlineEllipsis + "2110"),
- suggestions[1].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Visa ") +
+ test::ObfuscatedCardDigitsAsUTF8("2110")),
+ suggestions[1].value);
// Server card with bank name will show bank name.
- EXPECT_EQ(
- base::UTF8ToUTF16(std::string("Chase") + kUTF8MidlineEllipsis + "2111"),
- suggestions[2].value);
+ EXPECT_EQ(base::UTF8ToUTF16(std::string("Chase ") +
+ test::ObfuscatedCardDigitsAsUTF8("2111")),
+ suggestions[2].value);
}
// Tests that only the full server card is kept when deduping with a local
@@ -2641,7 +2699,7 @@ TEST_F(PersonalDataManagerTest,
// Create 3 different local credit cards.
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&local_card, "Homer Simpson",
"4234567890123456" /* Visa */, "01", "2999", "1");
local_card.set_use_count(3);
@@ -2670,7 +2728,7 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_LocalShadowsMasked) {
std::list<CreditCard*> credit_cards;
CreditCard local_card("1141084B-72D7-4B73-90CF-3D6AC154673B",
- "https://www.example.com");
+ test::kEmptyOrigin);
local_card.set_use_count(300);
local_card.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(10));
test::SetCreditCardInfo(&local_card, "Homer Simpson",
@@ -2727,7 +2785,7 @@ TEST_F(PersonalDataManagerTest, DedupeCreditCardToSuggest_DifferentCards) {
std::list<CreditCard*> credit_cards;
CreditCard credit_card2("002149C1-EE28-4213-A3B9-DA243FFF021B",
- "https://www.example.com");
+ test::kEmptyOrigin);
credit_card2.set_use_count(1);
credit_card2.set_use_date(AutofillClock::Now() -
base::TimeDelta::FromDays(1));
@@ -2771,7 +2829,7 @@ TEST_F(PersonalDataManagerTest, RecordUseOf) {
EXPECT_EQ(kArbitraryTime, profile.modification_date());
personal_data_->AddProfile(profile);
- CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
EXPECT_EQ(1U, credit_card.use_count());
@@ -3014,8 +3072,6 @@ class SaveImportedProfileTest
// Reset the deduping pref to its default value.
personal_data_->pref_service_->SetInteger(
prefs::kAutofillLastVersionDeduped, 0);
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, false);
}
void TearDown() override {
@@ -3044,7 +3100,7 @@ TEST_P(SaveImportedProfileTest, SaveImportedProfile) {
// Set the time to a bigger value.
test_clock.SetNow(kSomeLaterTime);
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Marion", "Mitchell", "Morrison",
"johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5",
"Hollywood", "CA", "91601", "US", "12345678910");
@@ -3359,12 +3415,12 @@ INSTANTIATE_TEST_CASE_P(
TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
// Create two very similar profiles except with different company names.
std::unique_ptr<AutofillProfile> profile1 = std::make_unique<AutofillProfile>(
- base::GenerateGUID(), "https://www.example.com");
+ base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile1.get(), "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3378,8 +3434,7 @@ TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
existing_profiles.push_back(base::WrapUnique(profile2));
// Create a new imported profile with no company name.
- AutofillProfile imported_profile(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile imported_profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "US", "12345678910");
@@ -3409,7 +3464,7 @@ TEST_F(PersonalDataManagerTest, MAYBE_MergeProfile_UsageStats) {
// Create an initial profile with a use count of 10, an old use date and an
// old modification date of 4 days ago.
AutofillProfile* profile =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3425,8 +3480,7 @@ TEST_F(PersonalDataManagerTest, MAYBE_MergeProfile_UsageStats) {
test_clock.SetNow(kSomeLaterTime);
// Create a new imported profile that will get merged with the existing one.
- AutofillProfile imported_profile(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile imported_profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "US", "12345678910");
@@ -3457,7 +3511,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
// Create the profile for which to find duplicates. It has the highest
// frecency.
AutofillProfile* profile1 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3465,7 +3519,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
// Create a different profile that should not be deduped (different address).
AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "Fox", "1234 Other Street", "",
"Springfield", "IL", "91601", "US", "12345678910");
@@ -3473,7 +3527,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
// Create a profile similar to profile1 which should be deduped.
AutofillProfile* profile3 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "US", "12345678910");
@@ -3482,7 +3536,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
// Create another different profile that should not be deduped (different
// name).
AutofillProfile* profile4 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3492,7 +3546,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_ProfilesToDelete) {
// frecency, the result of the merge should be in this profile at the end of
// the test.
AutofillProfile* profile5 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3542,7 +3596,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
// Create the profile for which to find duplicates. It has the highest
// frecency.
AutofillProfile* profile1 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3550,7 +3604,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
// Create a different profile that should not be deduped (different address).
AutofillProfile* profile2 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "Fox", "1234 Other Street", "",
"Springfield", "IL", "91601", "US", "12345678910");
@@ -3558,7 +3612,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
// Create a profile similar to profile1 which should be deduped.
AutofillProfile* profile3 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "US", "12345678910");
@@ -3567,7 +3621,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
// Create another different profile that should not be deduped (different
// name).
AutofillProfile* profile4 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3577,7 +3631,7 @@ TEST_F(PersonalDataManagerTest, DedupeProfiles_GuidsMergeMap) {
// frecency, the result of the merge should be in this profile at the end of
// the test.
AutofillProfile* profile5 =
- new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+ new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3631,16 +3685,16 @@ TEST_F(PersonalDataManagerTest, UpdateCardsBillingAddressReference) {
// Create cards that use A, D, E and F as their billing address id.
CreditCard* credit_card1 =
- new CreditCard(base::GenerateGUID(), "https://www.example.com");
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
credit_card1->set_billing_address_id("A");
CreditCard* credit_card2 =
- new CreditCard(base::GenerateGUID(), "https://www.example.com");
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
credit_card2->set_billing_address_id("D");
CreditCard* credit_card3 =
- new CreditCard(base::GenerateGUID(), "https://www.example.com");
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
credit_card3->set_billing_address_id("E");
CreditCard* credit_card4 =
- new CreditCard(base::GenerateGUID(), "https://www.example.com");
+ new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
credit_card4->set_billing_address_id("F");
// Add the credit cards to the database.
@@ -3677,7 +3731,7 @@ TEST_F(PersonalDataManagerTest,
// Create a set of 3 profiles to be merged together.
// Create a profile with a higher frecency score.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -3685,7 +3739,7 @@ TEST_F(PersonalDataManagerTest,
profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
// Create a profile with a medium frecency score.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "", "12345678910");
@@ -3693,7 +3747,7 @@ TEST_F(PersonalDataManagerTest,
profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
// Create a profile with a lower frecency score.
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -3702,7 +3756,7 @@ TEST_F(PersonalDataManagerTest,
// Create a set of two profiles to be merged together.
// Create a profile with a higher frecency score.
- AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile4, "Marge", "B", "Simpson",
"marge.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -3710,7 +3764,7 @@ TEST_F(PersonalDataManagerTest,
profile4.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
// Create a profile with a lower frecency score.
- AutofillProfile profile5(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile5(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile5, "Marge", "B", "Simpson",
"marge.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -3718,7 +3772,7 @@ TEST_F(PersonalDataManagerTest,
profile5.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
// Create a unique profile.
- AutofillProfile profile6(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile6(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile6, "Bart", "J", "Simpson",
"bart.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -3728,18 +3782,18 @@ TEST_F(PersonalDataManagerTest,
// Add three credit cards. Give them a frecency score so that they are
// suggested in order (1, 2, 3). This will ensure a deterministic order for
// verifying results.
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
credit_card1.set_use_count(10);
- CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card2, "John Dillinger",
"4234567890123456" /* Visa */, "01", "2999", "1");
credit_card2.set_use_count(5);
- CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card3, "Bonnie Parker",
"5105105105105100" /* Mastercard */, "12", "2999",
"1");
@@ -3808,7 +3862,7 @@ TEST_F(PersonalDataManagerTest,
// frecency score.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
// Create a profile with a higher frecency score.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -3816,7 +3870,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
// Create a profile with a medium frecency score.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "", "12345678910");
@@ -3824,7 +3878,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
// Create a profile with a lower frecency score.
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -3906,7 +3960,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
profile1.set_use_date(kMuchLaterTime);
// Create a similar non verified profile with a medium frecency score.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -3914,7 +3968,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
profile2.set_use_date(kSomeLaterTime);
// Create a similar non verified profile with a lower frecency score.
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -3964,7 +4018,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileFirst) {
// frecency score.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
// Create a profile to dedupe with a higher frecency score.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -3972,7 +4026,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
profile1.set_use_date(kMuchLaterTime);
// Create a similar non verified profile with a medium frecency score.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -4029,7 +4083,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
// a verified profile. Also tests that two verified profiles don't get merged.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
// Create a profile to dedupe with a higher frecency score.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -4098,106 +4152,6 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
EXPECT_EQ(profile3.use_date(), profiles[1]->use_date());
}
-// Tests that ApplyProfileUseDatesFix sets the use date of profiles from an
-// incorrect value of 0 to [two weeks from now]. Also tests that SetProfiles
-// does not modify any other profiles.
-TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix) {
- // Set the kAutofillProfileUseDatesFixed pref to true so that the fix is not
- // applied just yet.
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, true);
-
- // Create a profile. The use date will be set to now automatically.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(&profile1, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile1.set_use_date(kArbitraryTime);
-
- // Create another profile and set its use date to the default value.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(&profile2, "Marge", "", "Simpson",
- "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile2.set_use_date(base::Time());
-
- personal_data_->AddProfile(profile1);
- personal_data_->AddProfile(profile2);
-
- WaitForOnPersonalDataChanged();
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-
- // Get a sorted list of profiles. |profile1| will be first and |profile2| will
- // be second.
- std::vector<AutofillProfile*> saved_profiles =
- personal_data_->GetProfilesToSuggest();
-
- ASSERT_EQ(2U, saved_profiles.size());
-
- // The use dates should not have been modified.
- EXPECT_EQ(profile1.use_date(), saved_profiles[0]->use_date());
- EXPECT_EQ(profile2.use_date(), saved_profiles[1]->use_date());
-
- // Set the pref to false to indicate the fix has never been run.
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, false);
-
- // Create the test clock and set the time to a specific value.
- TestAutofillClock test_clock;
- test_clock.SetNow(kSomeLaterTime);
-
- personal_data_->ApplyProfileUseDatesFix();
- WaitForOnPersonalDataChanged();
-
- // Get a sorted list of profiles.
- saved_profiles = personal_data_->GetProfilesToSuggest();
-
- ASSERT_EQ(2U, saved_profiles.size());
-
- // |profile1|'s use date should not have been modified.
- EXPECT_LE(profile1.use_date(), saved_profiles[0]->use_date());
- // |profile2|'s use date should have been set to two weeks before now.
- EXPECT_EQ(kSomeLaterTime - base::TimeDelta::FromDays(14),
- saved_profiles[1]->use_date());
-}
-
-// Tests that ApplyProfileUseDatesFix does apply the fix if it's already been
-// applied.
-TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix_NotAppliedTwice) {
- // Set the kAutofillProfileUseDatesFixed pref which means the fix has already
- // been applied.
- personal_data_->pref_service_->SetBoolean(
- prefs::kAutofillProfileUseDatesFixed, true);
-
- // Create two profiles.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(&profile1, "Homer", "Jay", "Simpson",
- "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile1.set_use_date(kArbitraryTime);
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
- test::SetProfileInfo(&profile2, "Marge", "", "Simpson",
- "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
- "", "Springfield", "IL", "91601", "US", "12345678910");
- profile2.set_use_date(base::Time());
-
- personal_data_->AddProfile(profile1);
- personal_data_->AddProfile(profile2);
-
- WaitForOnPersonalDataChanged();
- EXPECT_EQ(2U, personal_data_->GetProfiles().size());
-
- // Get a sorted list of profiles. |profile1| will be first and |profile2| will
- // be second.
- std::vector<AutofillProfile*> saved_profiles =
- personal_data_->GetProfilesToSuggest();
-
- ASSERT_EQ(2U, saved_profiles.size());
- // The use dates should not have been modified.
- EXPECT_EQ(profile1.use_date(), saved_profiles[0]->use_date());
- EXPECT_EQ(base::Time(), saved_profiles[1]->use_date());
-}
-
// Tests that ApplyDedupingRoutine works as expected in a realistic scenario.
// Tests that it merges the diffent set of similar profiles independently and
// that the resulting profiles have the right values, has no effect on the other
@@ -4205,7 +4159,7 @@ TEST_F(PersonalDataManagerTest, ApplyProfileUseDatesFix_NotAppliedTwice) {
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// Create a Homer home profile with a higher frecency score than other Homer
// profiles.
- AutofillProfile Homer1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile Homer1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&Homer1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -4214,7 +4168,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// Create a Homer home profile with a medium frecency score compared to other
// Homer profiles.
- AutofillProfile Homer2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile Homer2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&Homer2, "Homer", "Jay", "Simpson",
"homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "", "12345678910");
@@ -4223,7 +4177,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// Create a Homer home profile with a lower frecency score than other Homer
// profiles.
- AutofillProfile Homer3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile Homer3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&Homer3, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -4231,7 +4185,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
Homer3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(5));
// Create a Homer work profile (different address).
- AutofillProfile Homer4(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile Homer4(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&Homer4, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "12 Nuclear Plant.", "",
"Springfield", "IL", "91601", "US", "9876543");
@@ -4249,7 +4203,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// Create a verified Marge home profile with a lower frecency score that the
// other Marge profile.
- AutofillProfile Marge2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile Marge2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&Marge2, "Marjorie", "Jacqueline", "Simpson",
"marge.simpson@abc.com", "", "742 Evergreen Terrace", "",
"Springfield", "IL", "91601", "", "12345678910");
@@ -4257,7 +4211,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
Marge2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
// Create a Barney profile (guest user).
- AutofillProfile Barney(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile Barney(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&Barney, "Barney", "", "Gumble", "barney.gumble@abc.com",
"ABC", "123 Other Street", "", "Springfield", "IL",
"91601", "", "");
@@ -4344,13 +4298,13 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
// Tests that ApplyDedupingRoutine is not run if the feature is disabled.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_FeatureDisabled) {
// Create a profile to dedupe.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
// Create a similar profile.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -4378,7 +4332,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfZeroProfiles) {
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
// Create a profile to dedupe.
- AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
@@ -4398,13 +4352,13 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
// version.
TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
// Create a profile to dedupe.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "", "742. Evergreen Terrace",
"", "Springfield", "IL", "91601", "US", "");
// Create a similar profile.
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -4429,7 +4383,7 @@ TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
EXPECT_EQ(1U, profiles.size());
// Add another duplicate profile.
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
"homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
"", "Springfield", "IL", "91601", "", "");
@@ -4502,7 +4456,7 @@ TEST_F(PersonalDataManagerTest,
// Create unverified/disused/not-used-by-valid-credit-card
// address(deletable).
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Alice", "", "Delete", "", "ACME",
"1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL",
"32801", "US", "15151231234");
@@ -4510,12 +4464,12 @@ TEST_F(PersonalDataManagerTest,
personal_data_->AddProfile(profile0);
// Create unverified/disused/used-by-expired-credit-card address(deletable).
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Bob", "", "Delete", "", "ACME",
"1234 Evergreen Terrace", "Bld. 7", "Springfield", "IL",
"32801", "US", "15151231234");
profile1.set_use_date(now - base::TimeDelta::FromDays(400));
- CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card0, "Bob",
"5105105105105100" /* Mastercard */, "04", "1999",
"1");
@@ -4526,7 +4480,7 @@ TEST_F(PersonalDataManagerTest,
// Create verified/disused/not-used-by-valid-credit-card address(not
// deletable).
- AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile2, "Charlie", "", "Keep", "", "ACME",
"1234 Evergreen Terrace", "Bld. 8", "Springfield", "IL",
"32801", "US", "15151231234");
@@ -4536,7 +4490,7 @@ TEST_F(PersonalDataManagerTest,
// Create unverified/recently-used/not-used-by-valid-credit-card address(not
// deletable).
- AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile3, "Dave", "", "Keep", "", "ACME",
"1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL",
"32801", "US", "15151231234");
@@ -4544,7 +4498,7 @@ TEST_F(PersonalDataManagerTest,
personal_data_->AddProfile(profile3);
// Create unverified/disused/used-by-valid-credit-card address(not deletable).
- AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile4, "Emma", "", "Keep", "", "ACME",
"1234 Evergreen Terrace", "Bld. 10", "Springfield", "IL",
"32801", "US", "15151231234");
@@ -4629,7 +4583,7 @@ TEST_F(PersonalDataManagerTest,
auto now = AutofillClock::Now();
// Create a recently used local card, it is expected to remain.
- CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card1, "Alice",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -4637,7 +4591,7 @@ TEST_F(PersonalDataManagerTest,
// Create a local card that was expired 400 days ago, but recently used.
// It is expected to remain.
- CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card2, "Bob",
"378282246310006" /* American Express */, "04",
"1999", "1");
@@ -4645,14 +4599,19 @@ TEST_F(PersonalDataManagerTest,
// Create a local card expired recently, and last used 400 days ago.
// It is expected to remain.
- CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
+ base::Time expiry_date = now - base::TimeDelta::FromDays(32);
+ base::Time::Exploded exploded;
+ expiry_date.UTCExplode(&exploded);
test::SetCreditCardInfo(&credit_card3, "Clyde", "4111111111111111" /* Visa */,
- "04", "2017", "1");
+ base::StringPrintf("%02d", exploded.month).c_str(),
+ base::StringPrintf("%04d", exploded.year).c_str(),
+ "1");
credit_card3.set_use_date(now - base::TimeDelta::FromDays(400));
// Create a local card expired 400 days ago, and last used 400 days ago.
// It is expected to be deleted.
- CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com");
+ CreditCard credit_card4(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&credit_card4, "David",
"5105105105105100" /* Mastercard */, "04", "1999",
"1");
@@ -4727,8 +4686,7 @@ TEST_F(PersonalDataManagerTest,
// Add two different profiles, a local and a server one. Set the use stats so
// the server profile has a higher frecency, to have a predictable ordering to
// validate results.
- AutofillProfile local_profile(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
"joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
"Orlando", "FL", "32801", "US", "19482937549");
@@ -4752,7 +4710,7 @@ TEST_F(PersonalDataManagerTest,
// Add a server and a local card that have the server address as billing
// address.
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&local_card, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -4833,8 +4791,7 @@ TEST_F(PersonalDataManagerTest,
// the server card has a higher frecency, to have a predicatble ordering to
// validate results.
// Add a local profile.
- AutofillProfile local_profile(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&local_profile, "John", "", "Doe", "john@doe.com", "",
"1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US",
"19482937549");
@@ -4857,7 +4814,7 @@ TEST_F(PersonalDataManagerTest,
// Add a server and a local card that have the server address as billing
// address.
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&local_card, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -4988,8 +4945,7 @@ TEST_F(
// Add a unique local profile and two similar server profiles. Set the use
// stats to have a predicatble ordering to validate results.
// Add a local profile.
- AutofillProfile local_profile(base::GenerateGUID(),
- "https://www.example.com");
+ AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&local_profile, "Bob", "", "Doe", "", "Fox",
"1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US",
"19482937549");
@@ -5025,7 +4981,7 @@ TEST_F(
// Add a server and a local card that have the first and second Wallet address
// as a billing address.
CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
- "https://www.example.com");
+ test::kEmptyOrigin);
test::SetCreditCardInfo(&local_card, "Clyde Barrow",
"378282246310005" /* American Express */, "04",
"2999", "1");
@@ -5211,16 +5167,16 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) {
std::vector<CreditCard> server_cards;
// Add two different profiles
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Bob", "", "Doe", "", "Fox", "1212 Center.",
"Bld. 5", "Orlando", "FL", "32801", "US", "19482937549");
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Seb", "", "Doe", "", "ACME",
"1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL",
"32801", "US", "15151231234");
// Add a local and a server card that have profile0 as their billing address.
- CreditCard local_card0(base::GenerateGUID(), "https://www.example.com");
+ CreditCard local_card0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&local_card0, "John Dillinger",
"4111111111111111" /* Visa */, "01", "2999",
profile0.guid());
@@ -5231,7 +5187,7 @@ TEST_F(PersonalDataManagerTest, RemoveByGUID_ResetsBillingAddress) {
server_cards.push_back(server_card0);
// Do the same but for profile1.
- CreditCard local_card1(base::GenerateGUID(), "https://www.example.com");
+ CreditCard local_card1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetCreditCardInfo(&local_card1, "Seb Dillinger",
"4111111111111111" /* Visa */, "01", "2999",
profile1.guid());
@@ -5300,14 +5256,14 @@ TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics_NoStoredProfiles) {
TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics) {
// Add a recently used (3 days ago) profile.
- AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile0, "Bob", "", "Doe", "", "Fox", "1212 Center.",
"Bld. 5", "Orlando", "FL", "32801", "US", "19482937549");
profile0.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
personal_data_->AddProfile(profile0);
// Add a profile used a long time (200 days) ago.
- AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
test::SetProfileInfo(&profile1, "Seb", "", "Doe", "", "ACME",
"1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL",
"32801", "US", "15151231234");
@@ -5406,7 +5362,7 @@ TEST_F(PersonalDataManagerTest, RemoveProfilesNotUsedSinceTimestamp) {
// Created a shuffled master copy of the profile pointers.
std::vector<AutofillProfile*> shuffled_profiles(all_profile_ptrs);
- std::random_shuffle(shuffled_profiles.begin(), shuffled_profiles.end());
+ base::RandomShuffle(shuffled_profiles.begin(), shuffled_profiles.end());
// Copy the shuffled profile pointer collections to use as the working set.
std::vector<AutofillProfile*> profiles(shuffled_profiles);
@@ -5635,7 +5591,7 @@ TEST_F(PersonalDataManagerTest, RemoveExpiredCreditCardsNotUsedSinceTimestamp) {
// Created a shuffled master copy of the card pointers.
std::vector<CreditCard*> shuffled_cards(all_card_ptrs);
- std::random_shuffle(shuffled_cards.begin(), shuffled_cards.end());
+ base::RandomShuffle(shuffled_cards.begin(), shuffled_cards.end());
// Copy the shuffled card pointer collections to use as the working
// set.
@@ -5711,7 +5667,7 @@ TEST_F(PersonalDataManagerTest, RemoveExpiredCreditCardsNotUsedSinceTimestamp) {
TEST_F(PersonalDataManagerTest, CreateDataForTest) {
// Disable sync so the data gets created.
- sync_service_.SetPreferredDataTypes(syncer::ModelType::UNSPECIFIED);
+ sync_service_.SetPreferredDataTypes(syncer::ModelTypeSet());
// By default, the creation of test data is disabled.
ResetPersonalDataManager(USER_MODE_NORMAL);
@@ -5820,12 +5776,57 @@ TEST_F(PersonalDataManagerTest, CannotAddFullServerCardOnLinux) {
for (CreditCard* card : server_cards)
EXPECT_TRUE(card->record_type() == CreditCard::MASKED_SERVER_CARD);
}
-#endif
+#endif // #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// These tests are not applicable on Linux since it does not support full server
+// cards.
#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
-// Make sure that an auth error masks all the server cards. Not applicable on
-// Linux since it does not support full server cards.
-TEST_F(PersonalDataManagerTest, SyncAuthErrorMasksServerCards) {
+// Make sure that an auth error does not mask all the server cards if the
+// feature is disabled.
+TEST_F(PersonalDataManagerTest, SyncAuthErrorMasksServerCards_FeatureDisabled) {
+ // Explicitely disable the feature that remasks server cards on auth error.
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndDisableFeature(
+ features::kAutofillResetFullServerCardsOnAuthError);
+
+ base::HistogramTester histogram_tester;
+ SetUpThreeCardTypes();
+
+ // Set an auth error and inform the personal data manager.
+ sync_service_.SetInAuthError(true);
+ personal_data_->OnStateChanged(&sync_service_);
+
+ // Remove the auth error to be able to get the server cards.
+ sync_service_.SetInAuthError(false);
+
+ // Check that the full server card was not remasked and that the others are
+ // still present.
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
+ std::vector<CreditCard*> server_cards =
+ personal_data_->GetServerCreditCards();
+ EXPECT_EQ(2U, server_cards.size());
+ EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, server_cards[0]->record_type());
+ EXPECT_EQ(CreditCard::FULL_SERVER_CARD, server_cards[1]->record_type());
+
+ // Check that the metrics are logged correctly.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.SyncServiceStatusOnStateChanged",
+ syncer::UploadState::NOT_ACTIVE, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset", 0);
+}
+
+// Make sure that an auth error masks all the server cards if the feature is
+// enabled.
+TEST_F(PersonalDataManagerTest, SyncAuthErrorMasksServerCards_FeatureEnabled) {
+ // Explicitely enable the feature that remasks server cards on auth error.
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndEnableFeature(
+ features::kAutofillResetFullServerCardsOnAuthError);
+
+ base::HistogramTester histogram_tester;
SetUpThreeCardTypes();
// Set an auth error and inform the personal data manager.
@@ -5843,8 +5844,161 @@ TEST_F(PersonalDataManagerTest, SyncAuthErrorMasksServerCards) {
EXPECT_EQ(2U, server_cards.size());
for (CreditCard* card : server_cards)
EXPECT_TRUE(card->record_type() == CreditCard::MASKED_SERVER_CARD);
+
+ // Check that the metrics are logged correctly.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.SyncServiceStatusOnStateChanged",
+ syncer::UploadState::NOT_ACTIVE, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun", 0);
+}
+
+// Test that calling OnSyncServiceInitialized with a null sync service does not
+// remask full server cards if the feature is disabled.
+TEST_F(PersonalDataManagerTest,
+ OnSyncServiceInitialized_NoSyncService_FeatureDisabled) {
+ // Explicitely disable the feature that remasks server cards on auth error.
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndDisableFeature(
+ features::kAutofillResetFullServerCardsOnAuthError);
+
+ base::HistogramTester histogram_tester;
+ SetUpThreeCardTypes();
+
+ // Call OnSyncServiceInitialized with no sync service.
+ personal_data_->OnSyncServiceInitialized(nullptr);
+
+ // Check that the full server card was not remasked and that the others are
+ // still present.
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
+ std::vector<CreditCard*> server_cards =
+ personal_data_->GetServerCreditCards();
+ EXPECT_EQ(2U, server_cards.size());
+ EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, server_cards[0]->record_type());
+ EXPECT_EQ(CreditCard::FULL_SERVER_CARD, server_cards[1]->record_type());
+
+ // Check that the metrics are logged correctly.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.SyncServiceNullOnInitialized", true, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset", 0);
+}
+
+// Test that calling OnSyncServiceInitialized with a null sync service remasks
+// full server cards if the feature is enabled.
+TEST_F(PersonalDataManagerTest,
+ OnSyncServiceInitialized_NoSyncService_FeatureEnabled) {
+ // Explicitely enable the feature that remasks server cards on auth error.
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndEnableFeature(
+ features::kAutofillResetFullServerCardsOnAuthError);
+
+ base::HistogramTester histogram_tester;
+ SetUpThreeCardTypes();
+
+ // Call OnSyncServiceInitialized with no sync service.
+ personal_data_->OnSyncServiceInitialized(nullptr);
+ WaitForOnPersonalDataChanged();
+
+ // Check that cards were masked and other were untouched.
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
+ std::vector<CreditCard*> server_cards =
+ personal_data_->GetServerCreditCards();
+ EXPECT_EQ(2U, server_cards.size());
+ for (CreditCard* card : server_cards)
+ EXPECT_TRUE(card->record_type() == CreditCard::MASKED_SERVER_CARD);
+
+ // Check that the metrics are logged correctly.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.SyncServiceNullOnInitialized", true, 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun", 0);
}
-#endif
+
+// Test that calling OnSyncServiceInitialized with a sync service in auth error
+// does not remask full server cards if the feature is disabled.
+TEST_F(PersonalDataManagerTest,
+ OnSyncServiceInitialized_NotActiveSyncService_FeatureDisabled) {
+ // Explicitely disable the feature that remasks server cards on auth error.
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndDisableFeature(
+ features::kAutofillResetFullServerCardsOnAuthError);
+
+ base::HistogramTester histogram_tester;
+ SetUpThreeCardTypes();
+
+ // Call OnSyncServiceInitialized with a sync service in auth error.
+ TestSyncService sync_service;
+ sync_service.SetInAuthError(true);
+ personal_data_->OnSyncServiceInitialized(&sync_service);
+
+ // Remove the auth error to be able to get the server cards.
+ sync_service.SetInAuthError(false);
+
+ // Check that the full server card was not remasked and that the others are
+ // still present.
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
+ std::vector<CreditCard*> server_cards =
+ personal_data_->GetServerCreditCards();
+ EXPECT_EQ(2U, server_cards.size());
+ EXPECT_EQ(CreditCard::MASKED_SERVER_CARD, server_cards[0]->record_type());
+ EXPECT_EQ(CreditCard::FULL_SERVER_CARD, server_cards[1]->record_type());
+
+ // Check that the metrics are logged correctly.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.SyncServiceNotActiveOnInitialized", true,
+ 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset", 0);
+}
+
+// Test that calling OnSyncServiceInitialized with a sync service in auth error
+// remasks full server cards if the feature is enabled.
+TEST_F(PersonalDataManagerTest,
+ OnSyncServiceInitialized_NotActiveSyncService_FeatureEnabled) {
+ // Explicitely enable the feature that remasks server cards on auth error.
+ base::test::ScopedFeatureList scoped_features;
+ scoped_features.InitAndEnableFeature(
+ features::kAutofillResetFullServerCardsOnAuthError);
+
+ base::HistogramTester histogram_tester;
+ SetUpThreeCardTypes();
+
+ // Call OnSyncServiceInitialized with a sync service in auth error.
+ TestSyncService sync_service;
+ sync_service.SetInAuthError(true);
+ personal_data_->OnSyncServiceInitialized(&sync_service);
+ WaitForOnPersonalDataChanged();
+
+ // Remove the auth error to be able to get the server cards.
+ sync_service.SetInAuthError(false);
+
+ // Check that cards were masked and other were untouched.
+ EXPECT_EQ(3U, personal_data_->GetCreditCards().size());
+ std::vector<CreditCard*> server_cards =
+ personal_data_->GetServerCreditCards();
+ EXPECT_EQ(2U, server_cards.size());
+ for (CreditCard* card : server_cards)
+ EXPECT_TRUE(card->record_type() == CreditCard::MASKED_SERVER_CARD);
+
+ // Check that the metrics are logged correctly.
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.SyncServiceNotActiveOnInitialized", true,
+ 1);
+ histogram_tester.ExpectUniqueSample(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset", 1, 1);
+ histogram_tester.ExpectTotalCount(
+ "Autofill.ResetFullServerCards.NumberOfCardsReset.DryRun", 0);
+}
+#endif // !defined(OS_LINUX) || defined(OS_CHROMEOS)
#if !defined(OS_ANDROID)
TEST_F(PersonalDataManagerTest, SyncAuthErrorHidesServerCards) {
@@ -5883,6 +6037,168 @@ TEST_F(PersonalDataManagerTest, ExcludeServerSideCards) {
EXPECT_EQ(1U, personal_data_->GetLocalCreditCards().size());
EXPECT_EQ(2U, personal_data_->GetServerCreditCards().size());
}
-#endif
+#endif // !defined(OS_ANDROID)
+
+// Tests that all the non settings origins of autofill profiles are cleared but
+// that the settings origins are untouched.
+TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) {
+ // Create three profile with a nonsettings, non-empty origin.
+ AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+ test::SetProfileInfo(&profile0, "Marion0", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile0.set_use_count(10000);
+ personal_data_->AddProfile(profile0);
+
+ AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile1.set_use_count(1000);
+ personal_data_->AddProfile(profile1);
+
+ AutofillProfile profile2(base::GenerateGUID(), "1234");
+ test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile2.set_use_count(100);
+ personal_data_->AddProfile(profile2);
+
+ // Create a profile with a settings origin.
+ AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
+ test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ profile3.set_use_count(10);
+ personal_data_->AddProfile(profile3);
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(4U, personal_data_->GetProfiles().size());
+
+ personal_data_->ClearProfileNonSettingsOrigins();
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(4U, personal_data_->GetProfiles().size());
+
+ // The first three profiles' origin should be cleared and the fourth one still
+ // be the settings origin.
+ EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[0]->origin().empty());
+ EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[1]->origin().empty());
+ EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[2]->origin().empty());
+ EXPECT_EQ(kSettingsOrigin,
+ personal_data_->GetProfilesToSuggest()[3]->origin());
+}
+
+// Tests that all the non settings origins of autofill credit cards are cleared
+// but that the settings origins are untouched.
+TEST_F(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins) {
+ // Create three cards with a non settings origin.
+ CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+ test::SetCreditCardInfo(&credit_card0, "Bob0",
+ "5105105105105100" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card0.set_use_count(10000);
+ personal_data_->AddCreditCard(credit_card0);
+
+ CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
+ test::SetCreditCardInfo(&credit_card1, "Bob1",
+ "5105105105105101" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card1.set_use_count(1000);
+ personal_data_->AddCreditCard(credit_card1);
+
+ CreditCard credit_card2(base::GenerateGUID(), "1234");
+ test::SetCreditCardInfo(&credit_card2, "Bob2",
+ "5105105105105102" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card2.set_use_count(100);
+ personal_data_->AddCreditCard(credit_card2);
+
+ // Create a card with a settings origin.
+ CreditCard credit_card3(base::GenerateGUID(), kSettingsOrigin);
+ test::SetCreditCardInfo(&credit_card3, "Bob3",
+ "5105105105105103" /* Mastercard */, "04", "1999",
+ "1");
+ credit_card3.set_use_count(10);
+ personal_data_->AddCreditCard(credit_card3);
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
+
+ personal_data_->ClearCreditCardNonSettingsOrigins();
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
+
+ // The first three profiles' origin should be cleared and the fourth one still
+ // be the settings origin.
+ EXPECT_TRUE(
+ personal_data_->GetCreditCardsToSuggest(false)[0]->origin().empty());
+ EXPECT_TRUE(
+ personal_data_->GetCreditCardsToSuggest(false)[1]->origin().empty());
+ EXPECT_TRUE(
+ personal_data_->GetCreditCardsToSuggest(false)[2]->origin().empty());
+ EXPECT_EQ(kSettingsOrigin,
+ personal_data_->GetCreditCardsToSuggest(false)[3]->origin());
+}
+
+// Tests that all the non settings origins of autofill profiles are cleared even
+// if Autofill is disabled.
+TEST_F(
+ PersonalDataManagerTest,
+ SyncServiceInitializedWithAutofillDisabled_ClearProfileNonSettingsOrigins) {
+ // Create a profile with a non-settings, non-empty origin.
+ AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+ test::SetProfileInfo(&profile, "Marion0", "Mitchell", "Morrison",
+ "johnwayne@me.xyz", "Fox",
+ "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+ "Hollywood", "CA", "91601", "US", "12345678910");
+ personal_data_->AddProfile(profile);
+ WaitForOnPersonalDataChanged();
+
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ prefs_->SetBoolean(prefs::kAutofillEnabled, false);
+
+ ASSERT_EQ(1U, personal_data_->GetProfiles().size());
+
+ personal_data_->OnSyncServiceInitialized(nullptr);
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(1U, personal_data_->GetProfiles().size());
+
+ // The profile's origin should be cleared
+ EXPECT_TRUE(personal_data_->GetProfiles()[0]->origin().empty());
+}
+
+// Tests that all the non settings origins of autofill credit cards are cleared
+// even if Autofill is disabled.
+TEST_F(
+ PersonalDataManagerTest,
+ SyncServiceInitializedWithAutofillDisabled_ClearCreditCardNonSettingsOrigins) {
+ // Create a card with a non-settings, non-empty origin.
+ CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+ test::SetCreditCardInfo(&credit_card, "Bob0",
+ "5105105105105100" /* Mastercard */, "04", "1999",
+ "1");
+ personal_data_->AddCreditCard(credit_card);
+ WaitForOnPersonalDataChanged();
+
+ EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+ prefs_->SetBoolean(prefs::kAutofillEnabled, false);
+
+ ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
+
+ personal_data_->OnSyncServiceInitialized(nullptr);
+
+ WaitForOnPersonalDataChanged();
+ ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
+
+ // The card's origin should be cleared
+ EXPECT_TRUE(personal_data_->GetCreditCards()[0]->origin().empty());
+}
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/phone_number_i18n.cc b/chromium/components/autofill/core/browser/phone_number_i18n.cc
index 6fdd9666e55..e849e44c903 100644
--- a/chromium/components/autofill/core/browser/phone_number_i18n.cc
+++ b/chromium/components/autofill/core/browser/phone_number_i18n.cc
@@ -241,14 +241,14 @@ bool PhoneNumbersMatch(const base::string16& number_a,
// Parse phone numbers based on the region
::i18n::phonenumbers::PhoneNumber i18n_number1;
- if (phone_util->Parse(base::UTF16ToUTF8(number_a), region.c_str(),
- &i18n_number1) != PhoneNumberUtil::NO_PARSING_ERROR) {
+ if (phone_util->Parse(base::UTF16ToUTF8(number_a), region, &i18n_number1) !=
+ PhoneNumberUtil::NO_PARSING_ERROR) {
return false;
}
::i18n::phonenumbers::PhoneNumber i18n_number2;
- if (phone_util->Parse(base::UTF16ToUTF8(number_b), region.c_str(),
- &i18n_number2) != PhoneNumberUtil::NO_PARSING_ERROR) {
+ if (phone_util->Parse(base::UTF16ToUTF8(number_b), region, &i18n_number2) !=
+ PhoneNumberUtil::NO_PARSING_ERROR) {
return false;
}
@@ -379,7 +379,7 @@ PhoneObject& PhoneObject::operator=(const PhoneObject& other) {
region_ = other.region_;
- if (other.i18n_number_.get())
+ if (other.i18n_number_)
i18n_number_.reset(
new ::i18n::phonenumbers::PhoneNumber(*other.i18n_number_));
else
diff --git a/chromium/components/autofill/core/browser/popup_item_ids.h b/chromium/components/autofill/core/browser/popup_item_ids.h
index 4b79d2cffab..dca2dd0b036 100644
--- a/chromium/components/autofill/core/browser/popup_item_ids.h
+++ b/chromium/components/autofill/core/browser/popup_item_ids.h
@@ -20,7 +20,6 @@ enum PopupItemId {
POPUP_ITEM_ID_SCAN_CREDIT_CARD = -7,
POPUP_ITEM_ID_TITLE = -8,
POPUP_ITEM_ID_CREDIT_CARD_SIGNIN_PROMO = -9,
- POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE = -10,
POPUP_ITEM_ID_USERNAME_ENTRY = -11,
POPUP_ITEM_ID_CREATE_HINT = -12,
POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY = -13,
diff --git a/chromium/components/autofill/core/browser/popup_types.h b/chromium/components/autofill/core/browser/popup_types.h
new file mode 100644
index 00000000000..f76e60fa1be
--- /dev/null
+++ b/chromium/components/autofill/core/browser/popup_types.h
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_POPUP_TYPES_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_POPUP_TYPES_H_
+
+namespace autofill {
+
+// The list of all Autofill popup types that can be presented to the user.
+enum class PopupType {
+ kUnspecified,
+ // Address form, but no address-related field is present. For example, it's
+ // a sign-up page in which the user only enters the name and the email.
+ kPersonalInformation,
+ // Address form with address-related fields.
+ kAddresses,
+ kCreditCards,
+ kPasswords,
+};
+
+} // namespace autofill
+
+#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_POPUP_TYPES_H_
diff --git a/chromium/components/autofill/core/browser/proto/server.proto b/chromium/components/autofill/core/browser/proto/server.proto
index 8156146c450..39fafca06b8 100644
--- a/chromium/components/autofill/core/browser/proto/server.proto
+++ b/chromium/components/autofill/core/browser/proto/server.proto
@@ -39,7 +39,7 @@ message AutofillQueryResponseContents {
// This message contains information about the field types in a single form.
// It is sent by the toolbar to contribute to the field type statistics.
-// Next available id: 24
+// Next available id: 29
message AutofillUploadContents {
required string client_version = 1;
required fixed64 form_signature = 2;
@@ -109,17 +109,34 @@ message AutofillUploadContents {
// the field is absent.
optional bool generated_password_changed = 22;
- enum UsernameVoteType {
+ enum VoteType {
NO_INFORMATION = 0;
+ // A credential saved on one form (typically a signup form) was used on a
+ // login form. The vote applies to the first (signup) form.
CREDENTIALS_REUSED = 1;
+ // When reusing a credential, the username value is not the saved
+ // username, but another value, which appeared on the form where we saved.
+ // The correct field is voted for.
USERNAME_OVERWRITTEN = 2;
+ // In the save prompt, the user corrected the username value to another
+ // value from the form. The new field is voted for.
USERNAME_EDITED = 3;
+ // The username field was detected by the base heuristic (take the last
+ // non-password field before the first password field). The value is not
+ // used at this point.
BASE_HEURISTIC = 4;
+ // The username field was detected by HTML-based detector. The value is
+ // not used at this point.
HTML_CLASSIFIER = 5;
+ // A saved credential was used for the first time on a submitted form. The
+ // vote applies to the form being submitted.
+ FIRST_USE = 6;
}
- // The type of username vote. If |autofill_type| != USERNAME, then the field
- // is missed.
- optional UsernameVoteType username_vote_type = 23;
+
+ // The type of password-related vote. If |autofill_type| is not a USERNAME
+ // or any PASSWORD vote, then the field is absent. This field describes the
+ // context of the vote.
+ optional VoteType vote_type = 23;
}
// Signature of the form action host (e.g. Hash64Bit("example.com")).
optional fixed64 action_signature = 13;
@@ -134,4 +151,24 @@ message AutofillUploadContents {
// The form name.
optional string form_name = 16;
+
+ // True iff the the non-obfuscated password values were shown to the user.
+ optional bool passwords_revealed = 24;
+
+ // The section of noisified data about password attributes.
+ // Upload only one attribute and only when a password is saved first time.
+ // Used to adjust the password generator's settings to site's requirements.
+
+ // Whether the password has any lowercase letter.
+ optional bool password_has_lowercase_letter = 25;
+
+ // Whether the password has any uppercase letter.
+ optional bool password_has_uppercase_letter = 26;
+
+ // Whether the password has any digit.
+ optional bool password_has_numeric = 27;
+
+ // Whether the password has any special symbol.
+ optional bool password_has_special_symbol = 28;
+ // The end of the section of password attributes.
}
diff --git a/chromium/components/autofill/core/browser/rationalization_util_unittest.cc b/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
index 304a1e6e692..67ebfbe0af9 100644
--- a/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
+++ b/chromium/components/autofill/core/browser/rationalization_util_unittest.cc
@@ -29,19 +29,19 @@ TEST_F(AutofillRationalizationUtilTest, PhoneNumber_FirstNumberIsWholeNumber) {
std::vector<AutofillField*> field_list;
AutofillField field0;
- field0.SetTypeTo(NAME_FULL);
+ field0.SetTypeTo(AutofillType(NAME_FULL));
field_list.push_back(&field0);
AutofillField field1;
- field1.SetTypeTo(ADDRESS_HOME_LINE1);
+ field1.SetTypeTo(AutofillType(ADDRESS_HOME_LINE1));
field_list.push_back(&field1);
AutofillField field2;
- field2.SetTypeTo(PHONE_HOME_WHOLE_NUMBER);
+ field2.SetTypeTo(AutofillType(PHONE_HOME_WHOLE_NUMBER));
field_list.push_back(&field2);
AutofillField field3;
- field3.SetTypeTo(PHONE_HOME_CITY_AND_NUMBER);
+ field3.SetTypeTo(AutofillType(PHONE_HOME_CITY_AND_NUMBER));
field_list.push_back(&field3);
rationalization_util::RationalizePhoneNumberFields(field_list);
@@ -57,41 +57,41 @@ TEST_F(AutofillRationalizationUtilTest,
std::vector<AutofillField*> field_list;
AutofillField field0;
- field0.SetTypeTo(NAME_FULL);
+ field0.SetTypeTo(AutofillType(NAME_FULL));
field_list.push_back(&field0);
AutofillField field1;
- field1.SetTypeTo(ADDRESS_HOME_LINE1);
+ field1.SetTypeTo(AutofillType(ADDRESS_HOME_LINE1));
field_list.push_back(&field1);
AutofillField field2;
field2.max_length = 2;
- field2.SetTypeTo(PHONE_HOME_COUNTRY_CODE);
+ field2.SetTypeTo(AutofillType(PHONE_HOME_COUNTRY_CODE));
field_list.push_back(&field2);
AutofillField field3;
field3.max_length = 3;
- field3.SetTypeTo(PHONE_HOME_CITY_CODE);
+ field3.SetTypeTo(AutofillType(PHONE_HOME_CITY_CODE));
field_list.push_back(&field3);
AutofillField field4;
field4.max_length = 7;
- field4.SetTypeTo(PHONE_HOME_NUMBER);
+ field4.SetTypeTo(AutofillType(PHONE_HOME_NUMBER));
field_list.push_back(&field4);
AutofillField field5;
field5.max_length = 2;
- field5.SetTypeTo(PHONE_HOME_COUNTRY_CODE);
+ field5.SetTypeTo(AutofillType(PHONE_HOME_COUNTRY_CODE));
field_list.push_back(&field5);
AutofillField field6;
field6.max_length = 3;
- field6.SetTypeTo(PHONE_HOME_CITY_CODE);
+ field6.SetTypeTo(AutofillType(PHONE_HOME_CITY_CODE));
field_list.push_back(&field6);
AutofillField field7;
field7.max_length = 7;
- field7.SetTypeTo(PHONE_HOME_NUMBER);
+ field7.SetTypeTo(AutofillType(PHONE_HOME_NUMBER));
field_list.push_back(&field7);
rationalization_util::RationalizePhoneNumberFields(field_list);
@@ -112,19 +112,19 @@ TEST_F(AutofillRationalizationUtilTest,
std::vector<AutofillField*> field_list;
AutofillField field0;
- field0.SetTypeTo(NAME_FULL);
+ field0.SetTypeTo(AutofillType(NAME_FULL));
field_list.push_back(&field0);
AutofillField field1;
- field1.SetTypeTo(ADDRESS_HOME_LINE1);
+ field1.SetTypeTo(AutofillType(ADDRESS_HOME_LINE1));
field_list.push_back(&field1);
AutofillField field2;
- field2.SetTypeTo(PHONE_HOME_COUNTRY_CODE);
+ field2.SetTypeTo(AutofillType(PHONE_HOME_COUNTRY_CODE));
field_list.push_back(&field2);
AutofillField field3;
- field3.SetTypeTo(PHONE_HOME_CITY_CODE);
+ field3.SetTypeTo(AutofillType(PHONE_HOME_CITY_CODE));
field_list.push_back(&field3);
rationalization_util::RationalizePhoneNumberFields(field_list);
@@ -139,29 +139,29 @@ TEST_F(AutofillRationalizationUtilTest, PhoneNumber_FillPhonePartsOnceOnly) {
std::vector<AutofillField*> field_list;
AutofillField field0;
- field0.SetTypeTo(NAME_FULL);
+ field0.SetTypeTo(AutofillType(NAME_FULL));
field_list.push_back(&field0);
AutofillField field1;
- field1.SetTypeTo(ADDRESS_HOME_LINE1);
+ field1.SetTypeTo(AutofillType(ADDRESS_HOME_LINE1));
field_list.push_back(&field1);
AutofillField field2;
- field2.SetTypeTo(PHONE_HOME_CITY_CODE);
+ field2.SetTypeTo(AutofillType(PHONE_HOME_CITY_CODE));
field_list.push_back(&field2);
AutofillField field3;
field3.max_length = 10;
- field3.SetTypeTo(PHONE_HOME_NUMBER);
+ field3.SetTypeTo(AutofillType(PHONE_HOME_NUMBER));
field_list.push_back(&field3);
AutofillField field4;
field4.max_length = 12;
- field4.SetTypeTo(PHONE_HOME_WHOLE_NUMBER);
+ field4.SetTypeTo(AutofillType(PHONE_HOME_WHOLE_NUMBER));
field_list.push_back(&field4);
AutofillField field5;
- field5.SetTypeTo(PHONE_HOME_CITY_CODE);
+ field5.SetTypeTo(AutofillType(PHONE_HOME_CITY_CODE));
field_list.push_back(&field5);
rationalization_util::RationalizePhoneNumberFields(field_list);
@@ -179,20 +179,20 @@ TEST_F(AutofillRationalizationUtilTest,
std::vector<AutofillField*> field_list;
AutofillField field0;
- field0.SetTypeTo(NAME_FULL);
+ field0.SetTypeTo(AutofillType(NAME_FULL));
field_list.push_back(&field0);
AutofillField field1;
- field1.SetTypeTo(ADDRESS_HOME_LINE1);
+ field1.SetTypeTo(AutofillType(ADDRESS_HOME_LINE1));
field_list.push_back(&field1);
AutofillField field2;
field2.is_focusable = false;
- field2.SetTypeTo(PHONE_HOME_CITY_AND_NUMBER);
+ field2.SetTypeTo(AutofillType(PHONE_HOME_CITY_AND_NUMBER));
field_list.push_back(&field2);
AutofillField field3;
- field3.SetTypeTo(PHONE_HOME_WHOLE_NUMBER);
+ field3.SetTypeTo(AutofillType(PHONE_HOME_WHOLE_NUMBER));
field_list.push_back(&field3);
rationalization_util::RationalizePhoneNumberFields(field_list);
diff --git a/chromium/components/autofill/core/browser/region_data_loader_impl.cc b/chromium/components/autofill/core/browser/region_data_loader_impl.cc
index 4dbe7a91ce9..9415cc247a0 100644
--- a/chromium/components/autofill/core/browser/region_data_loader_impl.cc
+++ b/chromium/components/autofill/core/browser/region_data_loader_impl.cc
@@ -31,7 +31,7 @@ void RegionDataLoaderImpl::LoadRegionData(
int64_t timeout_ms) {
callback_ = callback;
region_data_supplier_.LoadRules(country_code,
- *region_data_supplier_callback_.get());
+ *region_data_supplier_callback_);
timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(timeout_ms),
base::Bind(&RegionDataLoaderImpl::OnRegionDataLoaded,
diff --git a/chromium/components/autofill/core/browser/subkey_requester_unittest.cc b/chromium/components/autofill/core/browser/subkey_requester_unittest.cc
index 0f7c1971e73..5f0986c3071 100644
--- a/chromium/components/autofill/core/browser/subkey_requester_unittest.cc
+++ b/chromium/components/autofill/core/browser/subkey_requester_unittest.cc
@@ -87,7 +87,7 @@ class SubKeyRequesterTest : public testing::Test {
protected:
SubKeyRequesterTest() {
base::FilePath file_path;
- CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
+ CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
file_path = file_path.Append(FILE_PATH_LITERAL("third_party"))
.Append(FILE_PATH_LITERAL("libaddressinput"))
.Append(FILE_PATH_LITERAL("src"))
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.cc b/chromium/components/autofill/core/browser/test_autofill_client.cc
index 3038d7fdc5f..7bff6dfa86e 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_client.cc
@@ -3,20 +3,13 @@
// found in the LICENSE file.
#include "components/autofill/core/browser/test_autofill_client.h"
-#if !defined(OS_ANDROID)
-#include "components/autofill/core/browser/ui/mock_save_card_bubble_controller.h"
-#endif
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
namespace autofill {
TestAutofillClient::TestAutofillClient()
- :
-#if !defined(OS_ANDROID)
- save_card_bubble_controller_(new MockSaveCardBubbleController()),
-#endif
- form_origin_(GURL("https://example.test")) {}
+ : form_origin_(GURL("https://example.test")) {}
TestAutofillClient::~TestAutofillClient() {
}
@@ -50,14 +43,6 @@ AddressNormalizer* TestAutofillClient::GetAddressNormalizer() {
return nullptr;
}
-SaveCardBubbleController* TestAutofillClient::GetSaveCardBubbleController() {
-#if defined(OS_ANDROID)
- return nullptr;
-#else
- return save_card_bubble_controller_.get();
-#endif
-}
-
void TestAutofillClient::ShowAutofillSettings() {
}
@@ -78,7 +63,6 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally(
void TestAutofillClient::ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
- bool should_cvc_be_requested,
const base::Closure& callback) {
callback.Run();
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_client.h b/chromium/components/autofill/core/browser/test_autofill_client.h
index b5a2e74368f..6475c1c6d8a 100644
--- a/chromium/components/autofill/core/browser/test_autofill_client.h
+++ b/chromium/components/autofill/core/browser/test_autofill_client.h
@@ -34,7 +34,6 @@ class TestAutofillClient : public AutofillClient {
identity::IdentityManager* GetIdentityManager() override;
ukm::UkmRecorder* GetUkmRecorder() override;
AddressNormalizer* GetAddressNormalizer() override;
- SaveCardBubbleController* GetSaveCardBubbleController() override;
void ShowAutofillSettings() override;
void ShowUnmaskPrompt(const CreditCard& card,
UnmaskCardReason reason,
@@ -45,7 +44,6 @@ class TestAutofillClient : public AutofillClient {
void ConfirmSaveCreditCardToCloud(
const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message,
- bool should_cvc_be_requested,
const base::Closure& callback) override;
void ConfirmCreditCardFillAssist(const CreditCard& card,
const base::Closure& callback) override;
@@ -94,9 +92,6 @@ class TestAutofillClient : public AutofillClient {
// NULL by default.
std::unique_ptr<PrefService> prefs_;
-#if !defined(OS_ANDROID)
- std::unique_ptr<SaveCardBubbleController> save_card_bubble_controller_;
-#endif
GURL form_origin_;
DISALLOW_COPY_AND_ASSIGN(TestAutofillClient);
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.cc b/chromium/components/autofill/core/browser/test_autofill_driver.cc
index 53327e72108..94ef6316a2c 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.cc
@@ -41,8 +41,7 @@ void TestAutofillDriver::RendererShouldAcceptDataListSuggestion(
const base::string16& value) {
}
-void TestAutofillDriver::RendererShouldClearFilledForm() {
-}
+void TestAutofillDriver::RendererShouldClearFilledSection() {}
void TestAutofillDriver::RendererShouldClearPreviewedForm() {
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_driver.h b/chromium/components/autofill/core/browser/test_autofill_driver.h
index ef51d80363d..f5bbb55dced 100644
--- a/chromium/components/autofill/core/browser/test_autofill_driver.h
+++ b/chromium/components/autofill/core/browser/test_autofill_driver.h
@@ -32,7 +32,7 @@ class TestAutofillDriver : public AutofillDriver {
const std::vector<FormStructure*>& forms) override;
void RendererShouldAcceptDataListSuggestion(
const base::string16& value) override;
- void RendererShouldClearFilledForm() override;
+ void RendererShouldClearFilledSection() override;
void RendererShouldClearPreviewedForm() override;
void RendererShouldFillFieldWithValue(const base::string16& value) override;
void RendererShouldPreviewFieldWithValue(
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.cc b/chromium/components/autofill/core/browser/test_autofill_manager.cc
index 1ef5b047513..a56f1d59c2f 100644
--- a/chromium/components/autofill/core/browser/test_autofill_manager.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_manager.cc
@@ -64,6 +64,19 @@ void TestAutofillManager::UploadFormData(const FormStructure& submitted_form,
AutofillManager::UploadFormData(submitted_form, observed_submission);
}
+bool TestAutofillManager::MaybeStartVoteUploadProcess(
+ std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission) {
+ run_loop_ = std::make_unique<base::RunLoop>();
+ if (AutofillManager::MaybeStartVoteUploadProcess(
+ std::move(form_structure), timestamp, observed_submission)) {
+ run_loop_->Run();
+ return true;
+ }
+ return false;
+}
+
void TestAutofillManager::UploadFormDataAsyncCallback(
const FormStructure* submitted_form,
const base::TimeTicks& load_time,
@@ -101,18 +114,6 @@ void TestAutofillManager::UploadFormDataAsyncCallback(
observed_submission);
}
-void TestAutofillManager::ResetRunLoop() {
- run_loop_.reset(new base::RunLoop());
-}
-
-void TestAutofillManager::RunRunLoop() {
- run_loop_->Run();
-}
-
-void TestAutofillManager::WaitForAsyncUploadProcess() {
- run_loop_->Run();
-}
-
int TestAutofillManager::GetPackedCreditCardID(int credit_card_id) {
std::string credit_card_guid =
base::StringPrintf("00000000-0000-0000-0000-%012d", credit_card_id);
@@ -144,20 +145,6 @@ void TestAutofillManager::AddSeenFormStructure(
form_structures()->push_back(std::move(form_structure));
}
-void TestAutofillManager::SubmitForm(const FormData& form,
- const TimeTicks& timestamp) {
- ResetRunLoop();
- if (!OnFormSubmitted(form, false, SubmissionSource::FORM_SUBMISSION,
- timestamp))
- return;
-
- RunRunLoop();
-}
-
-void TestAutofillManager::SubmitForm(const FormData& form) {
- SubmitForm(form, TimeTicks::Now());
-}
-
void TestAutofillManager::ClearFormStructures() {
form_structures()->clear();
}
diff --git a/chromium/components/autofill/core/browser/test_autofill_manager.h b/chromium/components/autofill/core/browser/test_autofill_manager.h
index dc5acd3dc15..5864523eeba 100644
--- a/chromium/components/autofill/core/browser/test_autofill_manager.h
+++ b/chromium/components/autofill/core/browser/test_autofill_manager.h
@@ -52,6 +52,10 @@ class TestAutofillManager : public AutofillManager {
bool IsCreditCardAutofillEnabled() override;
void UploadFormData(const FormStructure& submitted_form,
bool observed_submission) override;
+ bool MaybeStartVoteUploadProcess(
+ std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission) override;
void UploadFormDataAsyncCallback(const FormStructure* submitted_form,
const base::TimeTicks& load_time,
const base::TimeTicks& interaction_time,
@@ -60,14 +64,6 @@ class TestAutofillManager : public AutofillManager {
// Unique to TestAutofillManager:
- // Resets the run loop so that it can wait for an asynchronous form
- // submission to complete.
- void ResetRunLoop();
- void RunRunLoop();
-
- // Wait for the asynchronous calls within StartUploadProcess() to complete.
- void WaitForAsyncUploadProcess();
-
int GetPackedCreditCardID(int credit_card_id);
void AddSeenForm(const FormData& form,
@@ -76,10 +72,6 @@ class TestAutofillManager : public AutofillManager {
void AddSeenFormStructure(std::unique_ptr<FormStructure> form_structure);
- // Calls AutofillManager::OnFormSubmitted and waits for it to complete.
- void SubmitForm(const FormData& form, const TimeTicks& timestamp);
- void SubmitForm(const FormData& form);
-
void ClearFormStructures();
const std::string GetSubmittedFormSignature();
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.cc b/chromium/components/autofill/core/browser/test_autofill_provider.cc
index 99889b26178..47e77d6226f 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.cc
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.cc
@@ -32,14 +32,6 @@ void TestAutofillProvider::OnSelectControlDidChange(
const FormFieldData& field,
const gfx::RectF& bounding_box) {}
-bool TestAutofillProvider::OnFormSubmitted(AutofillHandlerProxy* handler,
- const FormData& form,
- bool known_success,
- SubmissionSource source,
- base::TimeTicks timestamp) {
- return false;
-}
-
void TestAutofillProvider::OnFocusNoLongerOnForm(
AutofillHandlerProxy* handler) {}
diff --git a/chromium/components/autofill/core/browser/test_autofill_provider.h b/chromium/components/autofill/core/browser/test_autofill_provider.h
index b25e7c8c348..166556afa66 100644
--- a/chromium/components/autofill/core/browser/test_autofill_provider.h
+++ b/chromium/components/autofill/core/browser/test_autofill_provider.h
@@ -32,11 +32,11 @@ class TestAutofillProvider : public AutofillProvider {
const FormData& form,
const FormFieldData& field,
const gfx::RectF& bounding_box) override;
- bool OnFormSubmitted(AutofillHandlerProxy* handler,
+ void OnFormSubmitted(AutofillHandlerProxy* handler,
const FormData& form,
bool known_success,
SubmissionSource source,
- base::TimeTicks timestamp) override;
+ base::TimeTicks timestamp) override {}
void OnFocusNoLongerOnForm(AutofillHandlerProxy* handler) override;
void OnFocusOnFormField(AutofillHandlerProxy* handler,
const FormData& form,
diff --git a/chromium/components/autofill/core/browser/test_form_structure.cc b/chromium/components/autofill/core/browser/test_form_structure.cc
index b31106c765d..63e0933ad27 100644
--- a/chromium/components/autofill/core/browser/test_form_structure.cc
+++ b/chromium/components/autofill/core/browser/test_form_structure.cc
@@ -23,7 +23,7 @@ void TestFormStructure::SetFieldTypes(
AutofillField* form_field = field(i);
ASSERT_TRUE(form_field);
form_field->set_heuristic_type(heuristic_types[i]);
- form_field->set_overall_server_type(server_types[i]);
+ form_field->set_server_type(server_types[i]);
}
UpdateAutofillCount();
diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.cc b/chromium/components/autofill/core/browser/test_personal_data_manager.cc
index 1022d5d8d40..59f9398c3fb 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.cc
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.cc
@@ -42,6 +42,15 @@ void TestPersonalDataManager::AddProfile(const AutofillProfile& profile) {
NotifyPersonalDataChanged();
}
+void TestPersonalDataManager::UpdateProfile(const AutofillProfile& profile) {
+ AutofillProfile* existing_profile =
+ GetProfileWithGUID(profile.guid().c_str());
+ if (existing_profile) {
+ RemoveByGUID(existing_profile->guid());
+ AddProfile(profile);
+ }
+}
+
void TestPersonalDataManager::RemoveByGUID(const std::string& guid) {
CreditCard* credit_card = GetCreditCardWithGUID(guid.c_str());
if (credit_card) {
@@ -69,6 +78,15 @@ void TestPersonalDataManager::AddCreditCard(const CreditCard& credit_card) {
NotifyPersonalDataChanged();
}
+void TestPersonalDataManager::UpdateCreditCard(const CreditCard& credit_card) {
+ CreditCard* existing_credit_card =
+ GetCreditCardWithGUID(credit_card.guid().c_str());
+ if (existing_credit_card) {
+ RemoveByGUID(existing_credit_card->guid());
+ AddCreditCard(credit_card);
+ }
+}
+
void TestPersonalDataManager::AddFullServerCreditCard(
const CreditCard& credit_card) {
// Though the name is AddFullServerCreditCard, this test class treats masked
@@ -178,6 +196,10 @@ std::string TestPersonalDataManager::CountryCodeForCurrentTimezone()
return timezone_country_code_;
}
+bool TestPersonalDataManager::IsDataLoaded() const {
+ return true;
+}
+
void TestPersonalDataManager::ClearProfiles() {
web_profiles_.clear();
}
diff --git a/chromium/components/autofill/core/browser/test_personal_data_manager.h b/chromium/components/autofill/core/browser/test_personal_data_manager.h
index bfcb973cc6c..411c07ac8e1 100644
--- a/chromium/components/autofill/core/browser/test_personal_data_manager.h
+++ b/chromium/components/autofill/core/browser/test_personal_data_manager.h
@@ -33,8 +33,10 @@ class TestPersonalDataManager : public PersonalDataManager {
std::string SaveImportedCreditCard(
const CreditCard& imported_credit_card) override;
void AddProfile(const AutofillProfile& profile) override;
+ void UpdateProfile(const AutofillProfile& profile) override;
void RemoveByGUID(const std::string& guid) override;
void AddCreditCard(const CreditCard& credit_card) override;
+ void UpdateCreditCard(const CreditCard& credit_card) override;
void AddFullServerCreditCard(const CreditCard& credit_card) override;
std::vector<AutofillProfile*> GetProfiles() const override;
const std::string& GetDefaultCountryCodeForNewAddress() const override;
@@ -45,6 +47,7 @@ class TestPersonalDataManager : public PersonalDataManager {
bool IsAutofillCreditCardEnabled() const override;
bool IsAutofillWalletImportEnabled() const override;
std::string CountryCodeForCurrentTimezone() const override;
+ bool IsDataLoaded() const override;
// Unique to TestPersonalDataManager:
diff --git a/chromium/components/autofill/core/browser/test_sync_service.cc b/chromium/components/autofill/core/browser/test_sync_service.cc
index 5a0794b9a1b..0077449b04d 100644
--- a/chromium/components/autofill/core/browser/test_sync_service.cc
+++ b/chromium/components/autofill/core/browser/test_sync_service.cc
@@ -8,6 +8,7 @@
#include "components/sync/base/model_type.h"
#include "components/sync/base/progress_marker_map.h"
+#include "components/sync/driver/sync_token_status.h"
#include "components/sync/engine/cycle/model_neutral_state.h"
#include "components/sync/engine/cycle/sync_cycle_snapshot.h"
@@ -53,14 +54,16 @@ syncer::SyncCycleSnapshot TestSyncService::GetLastCycleSnapshot() const {
7, false, 0, base::Time::Now(), base::Time::Now(),
std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
- sync_pb::SyncEnums::UNKNOWN_ORIGIN);
+ sync_pb::SyncEnums::UNKNOWN_ORIGIN,
+ /*short_poll_interval=*/base::TimeDelta::FromMinutes(30),
+ /*long_poll_interval=*/base::TimeDelta::FromMinutes(180),
+ /*has_remaining_local_changes=*/false);
}
return syncer::SyncCycleSnapshot();
}
-syncer::SyncService::SyncTokenStatus TestSyncService::GetSyncTokenStatus()
- const {
- syncer::SyncService::SyncTokenStatus token;
+syncer::SyncTokenStatus TestSyncService::GetSyncTokenStatus() const {
+ syncer::SyncTokenStatus token;
if (is_in_auth_error_) {
token.connection_status = syncer::ConnectionStatus::CONNECTION_AUTH_ERROR;
diff --git a/chromium/components/autofill/core/browser/test_sync_service.h b/chromium/components/autofill/core/browser/test_sync_service.h
index 444501f47ab..0bf32d9405b 100644
--- a/chromium/components/autofill/core/browser/test_sync_service.h
+++ b/chromium/components/autofill/core/browser/test_sync_service.h
@@ -24,7 +24,7 @@ class TestSyncService : public syncer::FakeSyncService {
bool ConfigurationDone() const override;
syncer::SyncCycleSnapshot GetLastCycleSnapshot() const override;
const GoogleServiceAuthError& GetAuthError() const override;
- syncer::SyncService::SyncTokenStatus GetSyncTokenStatus() const override;
+ syncer::SyncTokenStatus GetSyncTokenStatus() const override;
void SetCanSyncStart(bool can_sync_start) {
can_sync_start_ = can_sync_start;
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc
deleted file mode 100644
index b0c8d787035..00000000000
--- a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/ui/mock_save_card_bubble_controller.h"
-
-namespace autofill {
-
-MockSaveCardBubbleController::MockSaveCardBubbleController() {}
-
-MockSaveCardBubbleController::~MockSaveCardBubbleController() {}
-
-base::string16 MockSaveCardBubbleController::GetCvcEnteredByUser() const {
- return cvc_entered_by_user_;
-}
-
-void MockSaveCardBubbleController::OnSaveButton(const base::string16& cvc) {
- if (!cvc.empty())
- cvc_entered_by_user_ = cvc;
-}
-
-} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
deleted file mode 100644
index 48e790d9b85..00000000000
--- a/chromium/components/autofill/core/browser/ui/mock_save_card_bubble_controller.h
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
-
-#include "components/autofill/core/browser/credit_card.h"
-#include "components/autofill/core/browser/ui/save_card_bubble_controller.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-namespace autofill {
-
-class MockSaveCardBubbleController : public SaveCardBubbleController {
- public:
- MockSaveCardBubbleController();
- ~MockSaveCardBubbleController() override;
-
- MOCK_CONST_METHOD0(GetWindowTitle, base::string16());
- MOCK_CONST_METHOD0(GetExplanatoryMessage, base::string16());
- MOCK_CONST_METHOD0(GetCard, const CreditCard());
- MOCK_CONST_METHOD0(GetCvcImageResourceId, int());
- MOCK_CONST_METHOD0(ShouldRequestCvcFromUser, bool());
- MOCK_METHOD0(OnCancelButton, void());
- MOCK_METHOD0(OnLearnMoreClicked, void());
- MOCK_METHOD1(OnLegalMessageLinkClicked, void(const GURL& url));
- MOCK_METHOD0(OnBubbleClosed, void());
- MOCK_CONST_METHOD0(GetLegalMessageLines, const LegalMessageLines&());
- MOCK_METHOD0(ContinueToRequestCvcStage, void());
- MOCK_CONST_METHOD1(InputCvcIsValid, bool(const base::string16& input_text));
-
- base::string16 GetCvcEnteredByUser() const override;
- void OnSaveButton(const base::string16& cvc = base::string16()) override;
-
- private:
- base::string16 cvc_entered_by_user_;
-
- DISALLOW_COPY_AND_ASSIGN(MockSaveCardBubbleController);
-};
-
-} // namespace autofill
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_MOCK_SAVE_CARD_BUBBLE_CONTROLLER_H_
diff --git a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
index 751a6048a6e..588810a9c5e 100644
--- a/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
+++ b/chromium/components/autofill/core/browser/ui/save_card_bubble_controller.h
@@ -34,20 +34,8 @@ class SaveCardBubbleController {
// Returns the card that will be uploaded if the user accepts.
virtual const CreditCard GetCard() const = 0;
- // Returns the CVC image icon resource ID.
- virtual int GetCvcImageResourceId() const = 0;
-
- // Returns whether the dialog should include a field requesting the card's CVC
- // from the user.
- virtual bool ShouldRequestCvcFromUser() const = 0;
-
- // Returns the CVC provided by the user in the save card bubble.
- virtual base::string16 GetCvcEnteredByUser() const = 0;
-
// Interaction.
- // OnSaveButton takes in a string value representing the CVC entered by the
- // user if it was requested, or an empty string otherwise.
- virtual void OnSaveButton(const base::string16& cvc) = 0;
+ virtual void OnSaveButton() = 0;
virtual void OnCancelButton() = 0;
virtual void OnLearnMoreClicked() = 0;
virtual void OnLegalMessageLinkClicked(const GURL& url) = 0;
@@ -58,13 +46,6 @@ class SaveCardBubbleController {
// Returns empty vector if no legal message should be shown.
virtual const LegalMessageLines& GetLegalMessageLines() const = 0;
- // Called when the upload save version of the UI needs to request CVC in order
- // to save, and has user has clicked [Next] in order to surface that UI.
- virtual void ContinueToRequestCvcStage() = 0;
-
- // Utilities.
- virtual bool InputCvcIsValid(const base::string16& input_text) const = 0;
-
private:
DISALLOW_COPY_AND_ASSIGN(SaveCardBubbleController);
};
diff --git a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
index 22c7866cd75..6a723bf077a 100644
--- a/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
+++ b/chromium/components/autofill/core/browser/webdata/autocomplete_sync_bridge.cc
@@ -459,7 +459,7 @@ void AutocompleteSyncBridge::LoadMetadata() {
{FROM_HERE, "Failed reading autofill metadata from WebDatabase."});
return;
}
- change_processor()->ModelReadyToSync(this, std::move(batch));
+ change_processor()->ModelReadyToSync(std::move(batch));
}
std::string AutocompleteSyncBridge::GetClientTag(
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
deleted file mode 100644
index 13080217e54..00000000000
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.cc
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/metrics/histogram.h"
-#include "components/autofill/core/browser/personal_data_manager.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/prefs/pref_service.h"
-#include "components/sync/base/experiments.h"
-#include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/model/sync_error.h"
-#include "components/sync/model/syncable_service.h"
-
-namespace browser_sync {
-
-AutofillDataTypeController::AutofillDataTypeController(
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
- const base::Closure& dump_stack,
- syncer::SyncClient* sync_client,
- const scoped_refptr<autofill::AutofillWebDataService>& web_data_service)
- : AsyncDirectoryTypeController(syncer::AUTOFILL,
- dump_stack,
- sync_client,
- syncer::GROUP_DB,
- std::move(db_thread)),
- web_data_service_(web_data_service),
- currently_enabled_(IsEnabled()) {
- pref_registrar_.Init(sync_client_->GetPrefService());
- pref_registrar_.Add(autofill::prefs::kAutofillEnabled,
- base::Bind(&AutofillDataTypeController::OnUserPrefChanged,
- base::AsWeakPtr(this)));
-}
-
-void AutofillDataTypeController::WebDatabaseLoaded() {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(MODEL_STARTING, state());
-
- OnModelLoaded();
-}
-
-AutofillDataTypeController::~AutofillDataTypeController() {
- DCHECK(CalledOnValidThread());
-}
-
-bool AutofillDataTypeController::StartModels() {
- DCHECK(CalledOnValidThread());
- DCHECK_EQ(MODEL_STARTING, state());
-
- if (!IsEnabled()) {
- DisableForPolicy();
- return false;
- }
-
- if (!web_data_service_)
- return false;
-
- if (web_data_service_->IsDatabaseLoaded()) {
- return true;
- } else {
- web_data_service_->RegisterDBLoadedCallback(base::Bind(
- &AutofillDataTypeController::WebDatabaseLoaded, base::AsWeakPtr(this)));
- return false;
- }
-}
-
-bool AutofillDataTypeController::ReadyForStart() const {
- DCHECK(CalledOnValidThread());
- return currently_enabled_;
-}
-
-void AutofillDataTypeController::OnUserPrefChanged() {
- DCHECK(CalledOnValidThread());
-
- bool new_enabled = IsEnabled();
- if (currently_enabled_ == new_enabled)
- return; // No change to sync state.
- currently_enabled_ = new_enabled;
-
- if (currently_enabled_) {
- // The preference was just enabled. Trigger a reconfiguration. This will do
- // nothing if the type isn't preferred.
- syncer::SyncService* sync_service = sync_client_->GetSyncService();
- sync_service->ReenableDatatype(type());
- } else {
- DisableForPolicy();
- }
-}
-
-bool AutofillDataTypeController::IsEnabled() {
- DCHECK(CalledOnValidThread());
-
- // Require the user-visible pref to be enabled to sync Autofill data.
- PrefService* ps = sync_client_->GetPrefService();
- return ps->GetBoolean(autofill::prefs::kAutofillEnabled);
-}
-
-void AutofillDataTypeController::DisableForPolicy() {
- if (state() != NOT_RUNNING && state() != STOPPING) {
- CreateErrorHandler()->OnUnrecoverableError(
- syncer::SyncError(FROM_HERE, syncer::SyncError::DATATYPE_POLICY_ERROR,
- "Autofill syncing is disabled by policy.", type()));
- }
-}
-
-} // namespace browser_sync
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h
deleted file mode 100644
index 81525f6606f..00000000000
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_DATA_TYPE_CONTROLLER_H__
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_DATA_TYPE_CONTROLLER_H__
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "base/gtest_prod_util.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/sync/driver/async_directory_type_controller.h"
-
-namespace autofill {
-class AutofillWebDataService;
-} // namespace autofill
-
-namespace browser_sync {
-
-// A class that manages the startup and shutdown of autofill sync.
-class AutofillDataTypeController : public syncer::AsyncDirectoryTypeController {
- public:
- // |dump_stack| is called when an unrecoverable error occurs.
- AutofillDataTypeController(
- scoped_refptr<base::SingleThreadTaskRunner> db_thread,
- const base::Closure& dump_stack,
- syncer::SyncClient* sync_client,
- const scoped_refptr<autofill::AutofillWebDataService>& web_data_service);
- ~AutofillDataTypeController() override;
-
- protected:
- // AsyncDirectoryTypeController implementation.
- bool StartModels() override;
- bool ReadyForStart() const override;
-
- private:
- friend class AutofillDataTypeControllerTest;
- FRIEND_TEST_ALL_PREFIXES(AutofillDataTypeControllerTest, StartWDSReady);
- FRIEND_TEST_ALL_PREFIXES(AutofillDataTypeControllerTest, StartWDSNotReady);
-
- // Callback once WebDatabase has loaded.
- void WebDatabaseLoaded();
-
- // Callback for changes to the autofill pref.
- void OnUserPrefChanged();
-
- // Returns true if the pref is set such that autofill sync should be enabled.
- bool IsEnabled();
-
- // Report an error (which will stop the datatype asynchronously).
- void DisableForPolicy();
-
- // A reference to the AutofillWebDataService for this controller.
- scoped_refptr<autofill::AutofillWebDataService> web_data_service_;
-
- // Registrar for listening to kAutofillWEnabled status.
- PrefChangeRegistrar pref_registrar_;
-
- // Stores whether we're currently syncing autofill data. This is the last
- // value computed by IsEnabled.
- bool currently_enabled_;
-
- DISALLOW_COPY_AND_ASSIGN(AutofillDataTypeController);
-};
-
-} // namespace browser_sync
-
-#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_WEBDATA_AUTOFILL_DATA_TYPE_CONTROLLER_H__
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
deleted file mode 100644
index 22530a1490a..00000000000
--- a/chromium/components/autofill/core/browser/webdata/autofill_data_type_controller_unittest.cc
+++ /dev/null
@@ -1,220 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
-#include "components/autofill/core/common/autofill_pref_names.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/sync/driver/data_type_controller_mock.h"
-#include "components/sync/driver/fake_generic_change_processor.h"
-#include "components/sync/driver/fake_sync_client.h"
-#include "components/sync/driver/sync_api_component_factory_mock.h"
-#include "components/sync/driver/sync_service.h"
-#include "components/sync/model/fake_syncable_service.h"
-#include "components/sync/model/sync_error.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using autofill::AutofillWebDataService;
-
-namespace browser_sync {
-
-namespace {
-
-// Fake WebDataService implementation that stubs out the database loading.
-class FakeWebDataService : public AutofillWebDataService {
- public:
- FakeWebDataService(
- const scoped_refptr<base::SingleThreadTaskRunner>& ui_task_runner,
- const scoped_refptr<base::SingleThreadTaskRunner>& db_task_runner)
- : AutofillWebDataService(ui_task_runner, db_task_runner),
- is_database_loaded_(false),
- db_loaded_callback_(base::Callback<void(void)>()) {}
-
- // Mark the database as loaded and send out the appropriate notification.
- void LoadDatabase() {
- is_database_loaded_ = true;
-
- if (!db_loaded_callback_.is_null()) {
- db_loaded_callback_.Run();
- // Clear the callback here or the WDS and DTC will have refs to each other
- // and create a memory leak.
- db_loaded_callback_ = base::Callback<void(void)>();
- }
- }
-
- bool IsDatabaseLoaded() override { return is_database_loaded_; }
-
- void RegisterDBLoadedCallback(
- const base::Callback<void(void)>& callback) override {
- db_loaded_callback_ = callback;
- }
-
- private:
- ~FakeWebDataService() override {}
-
- bool is_database_loaded_;
- base::Callback<void(void)> db_loaded_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(FakeWebDataService);
-};
-
-class AutofillDataTypeControllerTest : public testing::Test,
- public syncer::FakeSyncClient {
- public:
- AutofillDataTypeControllerTest()
- : syncer::FakeSyncClient(&profile_sync_factory_),
- last_type_(syncer::UNSPECIFIED),
- weak_ptr_factory_(this) {}
- ~AutofillDataTypeControllerTest() override {}
-
- void SetUp() override {
- prefs_.registry()->RegisterBooleanPref(autofill::prefs::kAutofillEnabled,
- true);
- web_data_service_ =
- new FakeWebDataService(base::ThreadTaskRunnerHandle::Get(),
- base::ThreadTaskRunnerHandle::Get());
- autofill_dtc_ = std::make_unique<AutofillDataTypeController>(
- base::ThreadTaskRunnerHandle::Get(), base::DoNothing(), this,
- web_data_service_);
-
- last_type_ = syncer::UNSPECIFIED;
- last_error_ = syncer::SyncError();
- }
-
- void TearDown() override {
- // Make sure WebDataService is shutdown properly on DB thread before we
- // destroy it.
- // Must be done before we pump the loop.
- syncable_service_.StopSyncing(syncer::AUTOFILL);
- }
-
- // FakeSyncClient overrides.
- PrefService* GetPrefService() override { return &prefs_; }
-
- base::WeakPtr<syncer::SyncableService> GetSyncableServiceForType(
- syncer::ModelType type) override {
- return syncable_service_.AsWeakPtr();
- }
-
- void OnLoadFinished(syncer::ModelType type, const syncer::SyncError& error) {
- last_type_ = type;
- last_error_ = error;
- }
-
- protected:
- void SetStartExpectations() {
- autofill_dtc_->SetGenericChangeProcessorFactoryForTest(
- base::WrapUnique<syncer::GenericChangeProcessorFactory>(
- new syncer::FakeGenericChangeProcessorFactory(
- std::make_unique<syncer::FakeGenericChangeProcessor>(
- syncer::AUTOFILL, this))));
- }
-
- void Start() {
- autofill_dtc_->LoadModels(
- base::Bind(&AutofillDataTypeControllerTest::OnLoadFinished,
- base::Unretained(this)));
- base::RunLoop().RunUntilIdle();
- if (autofill_dtc_->state() != syncer::DataTypeController::MODEL_LOADED)
- return;
- autofill_dtc_->StartAssociating(base::Bind(
- &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
- base::RunLoop().RunUntilIdle();
- }
-
- base::MessageLoop message_loop_;
- TestingPrefServiceSimple prefs_;
- syncer::StartCallbackMock start_callback_;
- syncer::SyncApiComponentFactoryMock profile_sync_factory_;
- syncer::FakeSyncableService syncable_service_;
- std::unique_ptr<AutofillDataTypeController> autofill_dtc_;
- scoped_refptr<FakeWebDataService> web_data_service_;
-
- syncer::ModelType last_type_;
- syncer::SyncError last_error_;
- base::WeakPtrFactory<AutofillDataTypeControllerTest> weak_ptr_factory_;
-};
-
-// Load the WDS's database, then start the Autofill DTC.
-TEST_F(AutofillDataTypeControllerTest, StartWDSReady) {
- SetStartExpectations();
- web_data_service_->LoadDatabase();
- EXPECT_CALL(start_callback_,
- Run(syncer::DataTypeController::OK, testing::_, testing::_));
-
- EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, autofill_dtc_->state());
- Start();
- EXPECT_FALSE(last_error_.IsSet());
- EXPECT_EQ(syncer::AUTOFILL, last_type_);
- EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_dtc_->state());
-}
-
-// Start the autofill DTC without the WDS's database loaded, then
-// start the DB. The Autofill DTC should be in the MODEL_STARTING
-// state until the database in loaded.
-TEST_F(AutofillDataTypeControllerTest, StartWDSNotReady) {
- SetStartExpectations();
- autofill_dtc_->LoadModels(
- base::Bind(&AutofillDataTypeControllerTest::OnLoadFinished,
- weak_ptr_factory_.GetWeakPtr()));
-
- EXPECT_EQ(syncer::DataTypeController::MODEL_STARTING, autofill_dtc_->state());
-
- web_data_service_->LoadDatabase();
- EXPECT_CALL(start_callback_,
- Run(syncer::DataTypeController::OK, testing::_, testing::_));
- autofill_dtc_->StartAssociating(base::Bind(
- &syncer::StartCallbackMock::Run, base::Unretained(&start_callback_)));
- base::RunLoop().RunUntilIdle();
-
- EXPECT_FALSE(last_error_.IsSet());
- EXPECT_EQ(syncer::AUTOFILL, last_type_);
- EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_dtc_->state());
-}
-
-TEST_F(AutofillDataTypeControllerTest, DatatypeDisabledWhileRunning) {
- SetStartExpectations();
- web_data_service_->LoadDatabase();
- EXPECT_CALL(start_callback_,
- Run(syncer::DataTypeController::OK, testing::_, testing::_));
-
- EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, autofill_dtc_->state());
- Start();
- EXPECT_EQ(syncer::DataTypeController::RUNNING, autofill_dtc_->state());
- GetPrefService()->SetBoolean(autofill::prefs::kAutofillEnabled, false);
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(last_error_.IsSet());
-}
-
-TEST_F(AutofillDataTypeControllerTest, DatatypeDisabledAtStartup) {
- SetStartExpectations();
- web_data_service_->LoadDatabase();
- GetPrefService()->SetBoolean(autofill::prefs::kAutofillEnabled, false);
- EXPECT_EQ(syncer::DataTypeController::NOT_RUNNING, autofill_dtc_->state());
- Start();
- base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(last_error_.IsSet());
-}
-
-} // namespace
-
-} // namespace browser_sync
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
index 08aad8eb959..c83262a2a2c 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
@@ -21,6 +21,7 @@
#include "components/autofill/core/browser/form_group.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_constants.h"
#include "components/sync/model/sync_error.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/protocol/sync.pb.h"
@@ -95,9 +96,9 @@ AutofillProfileSyncableService::MergeDataAndStartSyncing(
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(!sync_processor_.get());
- DCHECK(sync_processor.get());
- DCHECK(sync_error_factory.get());
+ DCHECK(!sync_processor_);
+ DCHECK(sync_processor);
+ DCHECK(sync_error_factory);
DVLOG(1) << "Associating Autofill: MergeDataAndStartSyncing";
syncer::SyncMergeResult merge_result(type);
@@ -216,7 +217,7 @@ void AutofillProfileSyncableService::StopSyncing(syncer::ModelType type) {
syncer::SyncDataList AutofillProfileSyncableService::GetAllSyncData(
syncer::ModelType type) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(sync_processor_.get());
+ DCHECK(sync_processor_);
DCHECK_EQ(type, syncer::AUTOFILL_PROFILE);
syncer::SyncDataList current_data;
@@ -229,7 +230,7 @@ syncer::SyncError AutofillProfileSyncableService::ProcessSyncChanges(
const base::Location& from_here,
const syncer::SyncChangeList& change_list) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (!sync_processor_.get()) {
+ if (!sync_processor_) {
syncer::SyncError error(FROM_HERE,
syncer::SyncError::DATATYPE_ERROR,
"Models not yet associated.",
@@ -279,7 +280,7 @@ void AutofillProfileSyncableService::AutofillProfileChanged(
// up we are going to process all when MergeData..() is called. If we receive
// notification after the sync exited, it will be sinced next time Chrome
// starts.
- if (sync_processor_.get()) {
+ if (sync_processor_) {
ActOnChange(change);
} else if (!flare_.is_null()) {
flare_.Run(syncer::AUTOFILL_PROFILE);
@@ -323,7 +324,10 @@ bool AutofillProfileSyncableService::OverwriteProfileWithServerData(
bool diff = false;
if (specifics.has_origin() && profile->origin() != specifics.origin()) {
bool was_verified = profile->IsVerified();
- profile->set_origin(specifics.origin());
+ // In this case, the local origin must be empty on the local |profile|, but
+ // the remote profile was verified.
+ if (specifics.origin() == kSettingsOrigin)
+ profile->set_origin(kSettingsOrigin);
diff = true;
// Verified profiles should never be overwritten by unverified ones.
@@ -579,7 +583,7 @@ void AutofillProfileSyncableService::ActOnChange(
(change.type() == AutofillProfileChange::REMOVE &&
!change.data_model()) ||
(change.type() != AutofillProfileChange::REMOVE && change.data_model()));
- DCHECK(sync_processor_.get());
+ DCHECK(sync_processor_);
if (change.data_model() &&
change.data_model()->record_type() != AutofillProfile::LOCAL_PROFILE) {
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
index 8566101b710..028b92f3766 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
@@ -128,6 +128,10 @@ class AutofillProfileSyncableService
MergeSimilarProfiles_DifferentNames);
FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
MergeSimilarProfiles_NonZeroUseCounts);
+ FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
+ OverwriteProfileWithServerData_NonSettingsOrigin);
+ FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
+ OverwriteProfileWithServerData_SettingsOrigin);
// The map of the guid to profiles owned by the |profiles_| vector.
typedef std::map<std::string, AutofillProfile*> GUIDToProfileMap;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index 031b7fed73d..cf031298a1d 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -39,15 +39,14 @@ const char kGuid1[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44B";
const char kGuid2[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C";
const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D";
const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E";
-const char kHttpOrigin[] = "http://www.example.com/";
-const char kHttpsOrigin[] = "https://www.example.com/";
+const char kEmptyOrigin[] = "";
const int kValidityStateBitfield = 1984;
class MockAutofillProfileSyncableService
: public AutofillProfileSyncableService {
public:
MockAutofillProfileSyncableService() {}
- virtual ~MockAutofillProfileSyncableService() {}
+ ~MockAutofillProfileSyncableService() override {}
using AutofillProfileSyncableService::DataBundle;
using AutofillProfileSyncableService::set_sync_processor;
@@ -142,7 +141,7 @@ class TestSyncChangeProcessor : public syncer::SyncChangeProcessor {
// returned from ConstructCompleteSyncData().
std::unique_ptr<AutofillProfile> ConstructCompleteProfile() {
std::unique_ptr<AutofillProfile> profile(
- new AutofillProfile(kGuid1, kHttpsOrigin));
+ new AutofillProfile(kGuid1, kSettingsOrigin));
profile->set_use_count(7);
profile->set_use_date(base::Time::FromTimeT(1423182152));
@@ -183,7 +182,7 @@ syncer::SyncData ConstructCompleteSyncData() {
entity_specifics.mutable_autofill_profile();
specifics->set_guid(kGuid1);
- specifics->set_origin(kHttpsOrigin);
+ specifics->set_origin(kSettingsOrigin);
specifics->set_use_count(7);
specifics->set_use_date(1423182152);
@@ -271,9 +270,9 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeDataAndStartSyncing) {
std::string guid_present2 = kGuid2;
std::string guid_synced1 = kGuid3;
std::string guid_synced2 = kGuid4;
- std::string origin_present1 = kHttpOrigin;
- std::string origin_present2 = std::string();
- std::string origin_synced1 = kHttpsOrigin;
+ std::string origin_present1 = kEmptyOrigin;
+ std::string origin_present2 = kEmptyOrigin;
+ std::string origin_synced1 = kEmptyOrigin;
std::string origin_synced2 = kSettingsOrigin;
profiles_from_web_db.push_back(
@@ -322,10 +321,10 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeIdenticalProfiles) {
std::string guid_present2 = kGuid2;
std::string guid_synced1 = kGuid3;
std::string guid_synced2 = kGuid4;
- std::string origin_present1 = kHttpOrigin;
+ std::string origin_present1 = kEmptyOrigin;
std::string origin_present2 = kSettingsOrigin;
- std::string origin_synced1 = kHttpsOrigin;
- std::string origin_synced2 = kHttpsOrigin;
+ std::string origin_synced1 = kEmptyOrigin;
+ std::string origin_synced2 = kEmptyOrigin;
profiles_from_web_db.push_back(
std::make_unique<AutofillProfile>(guid_present1, origin_present1));
@@ -376,10 +375,10 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeSimilarProfiles) {
std::string guid_present2 = kGuid2;
std::string guid_synced1 = kGuid3;
std::string guid_synced2 = kGuid4;
- std::string origin_present1 = kHttpOrigin;
+ std::string origin_present1 = kEmptyOrigin;
std::string origin_present2 = kSettingsOrigin;
- std::string origin_synced1 = kHttpsOrigin;
- std::string origin_synced2 = kHttpsOrigin;
+ std::string origin_synced1 = kEmptyOrigin;
+ std::string origin_synced2 = kEmptyOrigin;
profiles_from_web_db.push_back(
std::make_unique<AutofillProfile>(guid_present1, origin_present1));
@@ -486,10 +485,10 @@ TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) {
std::string guid_present2 = kGuid2;
profiles_from_web_db.push_back(
- std::make_unique<AutofillProfile>(guid_present1, kHttpOrigin));
+ std::make_unique<AutofillProfile>(guid_present1, kEmptyOrigin));
profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
profiles_from_web_db.push_back(
- std::make_unique<AutofillProfile>(guid_present2, kHttpsOrigin));
+ std::make_unique<AutofillProfile>(guid_present2, kEmptyOrigin));
profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
syncer::SyncChangeList expected_change_list;
@@ -515,8 +514,8 @@ TEST_F(AutofillProfileSyncableServiceTest, GetAllSyncData) {
ASSERT_EQ(2U, data.size());
EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid());
EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid());
- EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin());
- EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin());
+ EXPECT_EQ(kEmptyOrigin, data[0].GetSpecifics().autofill_profile().origin());
+ EXPECT_EQ(kEmptyOrigin, data[1].GetSpecifics().autofill_profile().origin());
autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
}
@@ -527,14 +526,14 @@ TEST_F(AutofillProfileSyncableServiceTest, ProcessSyncChanges) {
std::string guid_synced = kGuid2;
syncer::SyncChangeList change_list;
- AutofillProfile profile(guid_synced, kHttpOrigin);
+ AutofillProfile profile(guid_synced, kEmptyOrigin);
profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
change_list.push_back(
syncer::SyncChange(
FROM_HERE,
syncer::SyncChange::ACTION_ADD,
MockAutofillProfileSyncableService::CreateData(profile)));
- AutofillProfile empty_profile(guid_present, kHttpsOrigin);
+ AutofillProfile empty_profile(guid_present, kEmptyOrigin);
change_list.push_back(
syncer::SyncChange(
FROM_HERE,
@@ -563,7 +562,7 @@ TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) {
TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
autofill_syncable_service_.set_sync_processor(sync_change_processor);
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
autofill_syncable_service_.AutofillProfileChanged(change);
@@ -575,7 +574,7 @@ TEST_F(AutofillProfileSyncableServiceTest, AutofillProfileAdded) {
sync_pb::AutofillProfileSpecifics specifics =
result.sync_data().GetSpecifics().autofill_profile();
EXPECT_EQ(kGuid1, specifics.guid());
- EXPECT_EQ(kHttpsOrigin, specifics.origin());
+ EXPECT_EQ(kEmptyOrigin, specifics.origin());
EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane"));
}
@@ -616,10 +615,10 @@ TEST_F(AutofillProfileSyncableServiceTest, UpdateField) {
// |from_profile| into |into_profile| but not the other way around.
TEST_F(AutofillProfileSyncableServiceTest,
MergeSimilarProfiles_AdditionalInfoInBothProfiles) {
- AutofillProfile into_profile(kGuid1, kHttpOrigin);
+ AutofillProfile into_profile(kGuid1, kEmptyOrigin);
into_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
- AutofillProfile from_profile(kGuid2, kHttpsOrigin);
+ AutofillProfile from_profile(kGuid2, kEmptyOrigin);
from_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
from_profile.set_use_count(0);
@@ -644,7 +643,7 @@ TEST_F(AutofillProfileSyncableServiceTest,
from_profile, &into_profile, "en-US"));
EXPECT_EQ(ASCIIToUTF16("650234567"),
into_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
- EXPECT_EQ(kHttpsOrigin, into_profile.origin());
+ EXPECT_EQ(kEmptyOrigin, into_profile.origin());
// Make sure that the language code of |into_profile| was not added to
// |from_profile|.
@@ -656,8 +655,8 @@ TEST_F(AutofillProfileSyncableServiceTest,
TEST_F(AutofillProfileSyncableServiceTest,
MergeSimilarProfiles_DifferentUseDates) {
// Different guids, same origin.
- AutofillProfile into_profile(kGuid1, kHttpOrigin);
- AutofillProfile from_profile(kGuid2, kHttpOrigin);
+ AutofillProfile into_profile(kGuid1, kEmptyOrigin);
+ AutofillProfile from_profile(kGuid2, kEmptyOrigin);
from_profile.set_use_count(0);
into_profile.set_use_count(0);
@@ -687,8 +686,8 @@ TEST_F(AutofillProfileSyncableServiceTest,
TEST_F(AutofillProfileSyncableServiceTest,
MergeSimilarProfiles_NonZeroUseCounts) {
// Different guids, same origin, same use date.
- AutofillProfile into_profile(kGuid1, kHttpOrigin);
- AutofillProfile from_profile(kGuid2, kHttpOrigin);
+ AutofillProfile into_profile(kGuid1, kEmptyOrigin);
+ AutofillProfile from_profile(kGuid2, kEmptyOrigin);
from_profile.set_use_date(base::Time::FromTimeT(1234));
into_profile.set_use_date(base::Time::FromTimeT(1234));
@@ -759,7 +758,7 @@ TEST_F(AutofillProfileSyncableServiceTest,
sync_pb::AutofillProfileSpecifics* autofill_specifics =
specifics.mutable_autofill_profile();
autofill_specifics->set_guid(kGuid1);
- autofill_specifics->set_origin(kHttpsOrigin);
+ autofill_specifics->set_origin(kEmptyOrigin);
autofill_specifics->add_name_first(std::string());
autofill_specifics->add_name_middle(std::string());
autofill_specifics->add_name_last(std::string());
@@ -777,7 +776,7 @@ TEST_F(AutofillProfileSyncableServiceTest,
// Set up expectations: Full street address takes precedence over address
// lines.
syncer::SyncChangeList expected_change_list;
- AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+ AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
expected_profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
ASCIIToUTF16("456 El Camino Real\n"
"Suite #1337"));
@@ -804,7 +803,7 @@ TEST_F(AutofillProfileSyncableServiceTest, MergeDataEmptyStreetAddress) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Create a profile with the street address set.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
ASCIIToUTF16("123 Example St.\n"
"Apt. 42"));
@@ -851,7 +850,7 @@ TEST_F(AutofillProfileSyncableServiceTest, EmptySyncPreservesOrigin) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has an origin.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
// Remote data does not have an origin value.
@@ -886,12 +885,53 @@ TEST_F(AutofillProfileSyncableServiceTest, EmptySyncPreservesOrigin) {
autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
}
+// Sync data without origin should not overwrite existing origin in local
+// autofill profile.
+TEST_F(AutofillProfileSyncableServiceTest,
+ NonSettingsOriginFromSyncIsIgnored_Merge) {
+ std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
+
+ // Remote data has no origin value.
+ AutofillProfile profile(kGuid1, std::string());
+ profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
+
+ // Remote data has a non-settings origin value.
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::AutofillProfileSpecifics* autofill_specifics =
+ specifics.mutable_autofill_profile();
+ autofill_specifics->set_guid(profile.guid());
+ autofill_specifics->set_origin("www.example.com");
+ autofill_specifics->add_name_first("John");
+ autofill_specifics->add_name_middle(std::string());
+ autofill_specifics->add_name_last(std::string());
+ autofill_specifics->add_name_full(std::string());
+ autofill_specifics->add_email_address(std::string());
+ autofill_specifics->add_phone_home_whole_number(std::string());
+
+ syncer::SyncDataList data_list;
+ data_list.push_back(syncer::SyncData::CreateLocalData(
+ profile.guid(), profile.guid(), specifics));
+
+ // Expect the local autofill profile to still have an origin after sync.
+ MockAutofillProfileSyncableService::DataBundle expected_bundle;
+ AutofillProfile expected_profile(profile.guid(), profile.origin());
+ expected_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ expected_bundle.profiles_to_update.push_back(&expected_profile);
+
+ // Expect no sync events to add origin to the remote data.
+ syncer::SyncChangeList expected_empty_change_list;
+
+ MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list,
+ expected_bundle, expected_empty_change_list);
+ autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+}
+
// Missing language code field should not generate sync events.
TEST_F(AutofillProfileSyncableServiceTest, NoLanguageCodeNoSync) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has an empty language code.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
EXPECT_TRUE(profile.language_code().empty());
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -930,7 +970,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesEmptyLanguageCode) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has an empty language code.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
EXPECT_TRUE(profile.language_code().empty());
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -956,7 +996,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesEmptyLanguageCode) {
// Expect the local autofill profile to have "en" language code after sync.
MockAutofillProfileSyncableService::DataBundle expected_bundle;
- AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+ AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
expected_profile.set_language_code("en");
expected_bundle.profiles_to_update.push_back(&expected_profile);
@@ -973,7 +1013,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesIncorrectLanguageCode) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has "de" language code.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.set_language_code("de");
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -999,7 +1039,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesIncorrectLanguageCode) {
// Expect the local autofill profile to have "en" language code after sync.
MockAutofillProfileSyncableService::DataBundle expected_bundle;
- AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+ AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
expected_profile.set_language_code("en");
expected_bundle.profiles_to_update.push_back(&expected_profile);
@@ -1017,7 +1057,7 @@ TEST_F(AutofillProfileSyncableServiceTest, EmptySyncPreservesLanguageCode) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has "en" language code.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.set_language_code("en");
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1060,7 +1100,7 @@ TEST_F(AutofillProfileSyncableServiceTest, LanguageCodePropagates) {
TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
autofill_syncable_service_.set_sync_processor(sync_change_processor);
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.set_language_code("en");
AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
autofill_syncable_service_.AutofillProfileChanged(change);
@@ -1072,7 +1112,7 @@ TEST_F(AutofillProfileSyncableServiceTest, LanguageCodePropagates) {
sync_pb::AutofillProfileSpecifics specifics =
result.sync_data().GetSpecifics().autofill_profile();
EXPECT_EQ(kGuid1, specifics.guid());
- EXPECT_EQ(kHttpsOrigin, specifics.origin());
+ EXPECT_EQ(kEmptyOrigin, specifics.origin());
EXPECT_EQ("en", specifics.address_home_language_code());
}
@@ -1081,7 +1121,7 @@ TEST_F(AutofillProfileSyncableServiceTest, DefaultValidityStateNoSync) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has a default validity state bitfield.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
EXPECT_EQ(0, profile.GetValidityBitfieldValue());
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1119,7 +1159,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesDefaultValidityBitfield) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has a default validity state.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
EXPECT_EQ(0, profile.GetValidityBitfieldValue());
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1145,7 +1185,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesDefaultValidityBitfield) {
// Expect the local autofill profile to have the non default validity state
// bitfield after sync.
MockAutofillProfileSyncableService::DataBundle expected_bundle;
- AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+ AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
expected_bundle.profiles_to_update.push_back(&expected_profile);
@@ -1162,7 +1202,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesLocalValidityBitfield) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has a non default validity state bitfield value.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetValidityFromBitfieldValue(kValidityStateBitfield + 1);
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1188,7 +1228,7 @@ TEST_F(AutofillProfileSyncableServiceTest, SyncUpdatesLocalValidityBitfield) {
// Expect the local autofill profile to have the remote validity state
// bitfield value after sync.
MockAutofillProfileSyncableService::DataBundle expected_bundle;
- AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+ AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
expected_bundle.profiles_to_update.push_back(&expected_profile);
@@ -1207,7 +1247,7 @@ TEST_F(AutofillProfileSyncableServiceTest,
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has a non default validity state bitfield value.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1250,7 +1290,7 @@ TEST_F(AutofillProfileSyncableServiceTest, LocalValidityBitfieldPropagates) {
TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
autofill_syncable_service_.set_sync_processor(sync_change_processor);
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
autofill_syncable_service_.AutofillProfileChanged(change);
@@ -1262,7 +1302,7 @@ TEST_F(AutofillProfileSyncableServiceTest, LocalValidityBitfieldPropagates) {
sync_pb::AutofillProfileSpecifics specifics =
result.sync_data().GetSpecifics().autofill_profile();
EXPECT_EQ(kGuid1, specifics.guid());
- EXPECT_EQ(kHttpsOrigin, specifics.origin());
+ EXPECT_EQ(kEmptyOrigin, specifics.origin());
EXPECT_EQ(kValidityStateBitfield, specifics.validity_state_bitfield());
}
@@ -1271,7 +1311,7 @@ TEST_F(AutofillProfileSyncableServiceTest, NoFullNameNoSync) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has an empty full name.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1307,7 +1347,7 @@ TEST_F(AutofillProfileSyncableServiceTest, EmptySyncPreservesFullName) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has a full name.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Jacob Smith, Jr"));
profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
@@ -1347,7 +1387,7 @@ TEST_F(AutofillProfileSyncableServiceTest, NoUsageStatsNoSync) {
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
// Local autofill profile has 0 for use_count/use_date.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.set_language_code("en");
profile.set_use_count(0);
profile.set_use_date(base::Time());
@@ -1447,7 +1487,7 @@ TEST_P(SyncUpdatesUsageStatsTest, SyncUpdatesUsageStats) {
SetUp();
std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.set_language_code("en");
profile.set_use_count(test_case.local_use_count);
profile.set_use_date(test_case.local_use_date);
@@ -1515,7 +1555,7 @@ TEST_F(AutofillProfileSyncableServiceTest, ClientOverwritesUsageStats) {
sync_pb::AutofillProfileSpecifics* autofill_specifics =
specifics.mutable_autofill_profile();
autofill_specifics->set_guid(kGuid1);
- autofill_specifics->set_origin(kHttpsOrigin);
+ autofill_specifics->set_origin(kEmptyOrigin);
autofill_specifics->add_name_first(std::string());
autofill_specifics->add_name_middle(std::string());
autofill_specifics->add_name_last(std::string());
@@ -1528,8 +1568,7 @@ TEST_F(AutofillProfileSyncableServiceTest, ClientOverwritesUsageStats) {
syncer::SyncDataList data_list;
data_list.push_back(
- syncer::SyncData::CreateLocalData(
- kGuid1, kHttpsOrigin, specifics));
+ syncer::SyncData::CreateLocalData(kGuid1, kEmptyOrigin, specifics));
EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
.Times(1)
@@ -1545,7 +1584,7 @@ TEST_F(AutofillProfileSyncableServiceTest, ClientOverwritesUsageStats) {
new syncer::SyncErrorFactoryMock()));
// Update to the usage stats for that profile.
- AutofillProfile profile(kGuid1, kHttpsOrigin);
+ AutofillProfile profile(kGuid1, kEmptyOrigin);
profile.set_language_code("en");
profile.set_use_count(10U);
profile.set_use_date(base::Time::FromTimeT(30));
@@ -1586,4 +1625,74 @@ TEST_F(AutofillProfileSyncableServiceTest, IgnoreServerProfileUpdate) {
AutofillProfileChange::UPDATE, server_profile.guid(), &server_profile));
}
+// Tests that a non-settings origin from the server is never set to the local
+// profile.
+TEST_F(AutofillProfileSyncableServiceTest,
+ OverwriteProfileWithServerData_NonSettingsOrigin) {
+ // Create a profile with an empty origin.
+ AutofillProfile profile(kGuid1, std::string());
+ profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
+
+ // Create a Sync profile with a non-settings origin.
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::AutofillProfileSpecifics* autofill_specifics =
+ specifics.mutable_autofill_profile();
+ autofill_specifics->set_guid(profile.guid());
+ autofill_specifics->set_origin("https://www.example.com");
+ autofill_specifics->add_name_first("John");
+ autofill_specifics->add_name_middle(std::string());
+ autofill_specifics->add_name_last(std::string());
+ autofill_specifics->add_name_full(std::string());
+ autofill_specifics->add_email_address(std::string());
+ autofill_specifics->add_phone_home_whole_number(std::string());
+ autofill_specifics->set_address_home_line1("1 1st st");
+ autofill_specifics->set_use_count(profile.use_count());
+ autofill_specifics->set_use_date(profile.use_date().ToTimeT());
+
+ // Expect that the empty origin is not overwritten.
+ autofill_syncable_service_.OverwriteProfileWithServerData(*autofill_specifics,
+ &profile);
+ EXPECT_TRUE(profile.origin().empty());
+
+ // Set the local origin to settings.
+ profile.set_origin(kSettingsOrigin);
+
+ // Expect that the settings origin is not overwritten.
+ autofill_syncable_service_.OverwriteProfileWithServerData(*autofill_specifics,
+ &profile);
+ EXPECT_EQ(kSettingsOrigin, profile.origin());
+}
+
+// Tests that a non-settings origin from the server is not set to the local
+// profile.
+TEST_F(AutofillProfileSyncableServiceTest,
+ OverwriteProfileWithServerData_SettingsOrigin) {
+ // Create a profile with an empty origin.
+ AutofillProfile profile(kGuid1, std::string());
+ profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+ profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
+
+ // Create a Sync profile with a non-settings origin.
+ sync_pb::EntitySpecifics specifics;
+ sync_pb::AutofillProfileSpecifics* autofill_specifics =
+ specifics.mutable_autofill_profile();
+ autofill_specifics->set_guid(profile.guid());
+ autofill_specifics->set_origin(kSettingsOrigin);
+ autofill_specifics->add_name_first("John");
+ autofill_specifics->add_name_middle(std::string());
+ autofill_specifics->add_name_last(std::string());
+ autofill_specifics->add_name_full(std::string());
+ autofill_specifics->add_email_address(std::string());
+ autofill_specifics->add_phone_home_whole_number(std::string());
+ autofill_specifics->set_address_home_line1("1 1st st");
+ autofill_specifics->set_use_count(profile.use_count());
+ autofill_specifics->set_use_date(profile.use_date().ToTimeT());
+
+ // Expect that the settings origin replaced the empty origin.
+ autofill_syncable_service_.OverwriteProfileWithServerData(*autofill_specifics,
+ &profile);
+ EXPECT_EQ(kSettingsOrigin, profile.origin());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.cc b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
index bd5c3f9a4ce..31cbe830a10 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.cc
@@ -1578,6 +1578,12 @@ bool AutofillTable::RemoveAutofillDataModifiedBetween(
if (!s_profiles_get.Succeeded())
return false;
+ // Remove the profile pieces.
+ for (const std::string& guid : *profile_guids) {
+ if (!RemoveAutofillProfilePieces(guid, db_))
+ return false;
+ }
+
// Remove Autofill profiles in the time range.
sql::Statement s_profiles(db_->GetUniqueStatement(
"DELETE FROM autofill_profiles "
@@ -1848,6 +1854,31 @@ bool AutofillTable::ClearModelTypeState(syncer::ModelType model_type) {
return s.Run();
}
+bool AutofillTable::RemoveOrphanAutofillTableRows() {
+ // Get all the orphan guids.
+ std::set<std::string> orphan_guids;
+ sql::Statement s_orphan_profile_pieces_get(db_->GetUniqueStatement(
+ "SELECT guid FROM (SELECT guid FROM autofill_profile_names UNION SELECT "
+ "guid FROM autofill_profile_emails UNION SELECT guid FROM "
+ "autofill_profile_phones) WHERE guid NOT IN (SELECT guid FROM "
+ "autofill_profiles)"));
+
+ // Put the orphan guids in a set.
+ while (s_orphan_profile_pieces_get.Step())
+ orphan_guids.insert(s_orphan_profile_pieces_get.ColumnString(0));
+
+ if (!s_orphan_profile_pieces_get.Succeeded())
+ return false;
+
+ // Remove the profile pieces for the orphan guids.
+ for (const std::string& guid : orphan_guids) {
+ if (!RemoveAutofillProfilePieces(guid, db_))
+ return false;
+ }
+
+ return true;
+}
+
bool AutofillTable::InitMainTable() {
if (!db_->DoesTableExist("autofill")) {
if (!db_->Execute("CREATE TABLE autofill ("
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table.h b/chromium/components/autofill/core/browser/webdata/autofill_table.h
index 28c783dc40f..2d720be9ada 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table.h
@@ -451,6 +451,12 @@ class AutofillTable : public WebDatabaseTable,
const sync_pb::ModelTypeState& model_type_state) override;
bool ClearModelTypeState(syncer::ModelType model_type) override;
+ // Removes the orphan rows in the autofill_profile_names,
+ // autofill_profile_emails and autofill_profile_phones table that were not
+ // removed in the previous implementation of
+ // RemoveAutofillDataModifiedBetween(see crbug.com/836737).
+ bool RemoveOrphanAutofillTableRows();
+
// Table migration functions. NB: These do not and should not rely on other
// functions in this class. The implementation of a function such as
// GetCreditCard may change over time, but MigrateToVersionXX should never
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
index abcd0a4fe90..fed5711f60c 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_table_unittest.cc
@@ -1345,16 +1345,52 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
ASSERT_TRUE(db_->GetSQLConnection()->Execute(
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000000', 11);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000000', 'John Jones');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000000', 'john@jones.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000000', '111-111-1111');"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000001', 21);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000001', 'John Jones2');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000001', 'john@jones2.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000001', '222-222-2222');"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000002', 31);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000002', 'John Jones3');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000002', 'john@jones3.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000002', '333-333-3333');"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000003', 41);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000003', 'John Jones4');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000003', 'john@jones4.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000003', '444-444-4444');"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000004', 51);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000004', 'John Jones5');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000004', 'john@jones5.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000004', '555-555-5555');"
"INSERT INTO autofill_profiles (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000005', 61);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000005', 'John Jones6');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000005', 'john@jones6.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000005', '666-666-6666');"
"INSERT INTO credit_cards (guid, date_modified) "
"VALUES('00000000-0000-0000-0000-000000000006', 17);"
"INSERT INTO credit_cards (guid, date_modified) "
@@ -1374,9 +1410,13 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
table_->RemoveAutofillDataModifiedBetween(
Time::FromTimeT(17), Time::FromTimeT(41),
&profile_guids, &credit_card_guids);
+
+ // Two profiles should have been removed.
ASSERT_EQ(2UL, profile_guids.size());
EXPECT_EQ("00000000-0000-0000-0000-000000000001", profile_guids[0]);
EXPECT_EQ("00000000-0000-0000-0000-000000000002", profile_guids[1]);
+
+ // Make sure that only the expected profiles are still present.
sql::Statement s_autofill_profiles_bounded(
db_->GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
@@ -1390,10 +1430,63 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
ASSERT_TRUE(s_autofill_profiles_bounded.Step());
EXPECT_EQ(61, s_autofill_profiles_bounded.ColumnInt64(0));
EXPECT_FALSE(s_autofill_profiles_bounded.Step());
+
+ // Make sure that only the expected profile names are still present.
+ sql::Statement s_autofill_profile_names_bounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT full_name FROM autofill_profile_names"));
+ ASSERT_TRUE(s_autofill_profile_names_bounded.is_valid());
+ ASSERT_TRUE(s_autofill_profile_names_bounded.Step());
+ EXPECT_EQ("John Jones", s_autofill_profile_names_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_names_bounded.Step());
+ EXPECT_EQ("John Jones4", s_autofill_profile_names_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_names_bounded.Step());
+ EXPECT_EQ("John Jones5", s_autofill_profile_names_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_names_bounded.Step());
+ EXPECT_EQ("John Jones6", s_autofill_profile_names_bounded.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_names_bounded.Step());
+
+ // Make sure that only the expected profile emails are still present.
+ sql::Statement s_autofill_profile_emails_bounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT email FROM autofill_profile_emails"));
+ ASSERT_TRUE(s_autofill_profile_emails_bounded.is_valid());
+ ASSERT_TRUE(s_autofill_profile_emails_bounded.Step());
+ EXPECT_EQ("john@jones.com",
+ s_autofill_profile_emails_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_emails_bounded.Step());
+ EXPECT_EQ("john@jones4.com",
+ s_autofill_profile_emails_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_emails_bounded.Step());
+ EXPECT_EQ("john@jones5.com",
+ s_autofill_profile_emails_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_emails_bounded.Step());
+ EXPECT_EQ("john@jones6.com",
+ s_autofill_profile_emails_bounded.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_emails_bounded.Step());
+
+ // Make sure the expected profile phone numbers are still present.
+ sql::Statement s_autofill_profile_phones_bounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT number FROM autofill_profile_phones"));
+ ASSERT_TRUE(s_autofill_profile_phones_bounded.is_valid());
+ ASSERT_TRUE(s_autofill_profile_phones_bounded.Step());
+ EXPECT_EQ("111-111-1111", s_autofill_profile_phones_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_phones_bounded.Step());
+ EXPECT_EQ("444-444-4444", s_autofill_profile_phones_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_phones_bounded.Step());
+ EXPECT_EQ("555-555-5555", s_autofill_profile_phones_bounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_phones_bounded.Step());
+ EXPECT_EQ("666-666-6666", s_autofill_profile_phones_bounded.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_phones_bounded.Step());
+
+ // Three cards should have been removed.
ASSERT_EQ(3UL, credit_card_guids.size());
EXPECT_EQ("00000000-0000-0000-0000-000000000006", credit_card_guids[0]);
EXPECT_EQ("00000000-0000-0000-0000-000000000007", credit_card_guids[1]);
EXPECT_EQ("00000000-0000-0000-0000-000000000008", credit_card_guids[2]);
+
+ // Make sure the expected profiles are still present.
sql::Statement s_credit_cards_bounded(
db_->GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
@@ -1413,6 +1506,8 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
ASSERT_EQ(2UL, profile_guids.size());
EXPECT_EQ("00000000-0000-0000-0000-000000000004", profile_guids[0]);
EXPECT_EQ("00000000-0000-0000-0000-000000000005", profile_guids[1]);
+
+ // Make sure that only the expected profile names are still present.
sql::Statement s_autofill_profiles_unbounded(
db_->GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
@@ -1422,9 +1517,50 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
ASSERT_TRUE(s_autofill_profiles_unbounded.Step());
EXPECT_EQ(41, s_autofill_profiles_unbounded.ColumnInt64(0));
EXPECT_FALSE(s_autofill_profiles_unbounded.Step());
+
+ // Make sure that only the expected profile names are still present.
+ sql::Statement s_autofill_profile_names_unbounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT full_name FROM autofill_profile_names"));
+ ASSERT_TRUE(s_autofill_profile_names_unbounded.is_valid());
+ ASSERT_TRUE(s_autofill_profile_names_unbounded.Step());
+ EXPECT_EQ("John Jones", s_autofill_profile_names_unbounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_names_unbounded.Step());
+ EXPECT_EQ("John Jones4", s_autofill_profile_names_unbounded.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_names_unbounded.Step());
+
+ // Make sure that only the expected profile emails are still present.
+ sql::Statement s_autofill_profile_emails_unbounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT email FROM autofill_profile_emails"));
+ ASSERT_TRUE(s_autofill_profile_emails_unbounded.is_valid());
+ ASSERT_TRUE(s_autofill_profile_emails_unbounded.Step());
+ EXPECT_EQ("john@jones.com",
+ s_autofill_profile_emails_unbounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_emails_unbounded.Step());
+ EXPECT_EQ("john@jones4.com",
+ s_autofill_profile_emails_unbounded.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_emails_unbounded.Step());
+
+ // Make sure the expected profile phone numbers are still present.
+ sql::Statement s_autofill_profile_phones_unbounded(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT number FROM autofill_profile_phones"));
+ ASSERT_TRUE(s_autofill_profile_phones_unbounded.is_valid());
+ ASSERT_TRUE(s_autofill_profile_phones_unbounded.Step());
+ EXPECT_EQ("111-111-1111",
+ s_autofill_profile_phones_unbounded.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_phones_unbounded.Step());
+ EXPECT_EQ("444-444-4444",
+ s_autofill_profile_phones_unbounded.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_phones_unbounded.Step());
+
+ // Two cards should have been removed.
ASSERT_EQ(2UL, credit_card_guids.size());
EXPECT_EQ("00000000-0000-0000-0000-000000000010", credit_card_guids[0]);
EXPECT_EQ("00000000-0000-0000-0000-000000000011", credit_card_guids[1]);
+
+ // Make sure the remaining card is the expected one.
sql::Statement s_credit_cards_unbounded(
db_->GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
@@ -1437,16 +1573,45 @@ TEST_F(AutofillTableTest, RemoveAutofillDataModifiedBetween) {
table_->RemoveAutofillDataModifiedBetween(
Time(), Time(),
&profile_guids, &credit_card_guids);
+
+ // Two profiles should have been removed.
ASSERT_EQ(2UL, profile_guids.size());
EXPECT_EQ("00000000-0000-0000-0000-000000000000", profile_guids[0]);
EXPECT_EQ("00000000-0000-0000-0000-000000000003", profile_guids[1]);
+
+ // Make sure there are no profiles remaining.
sql::Statement s_autofill_profiles_empty(
db_->GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM autofill_profiles"));
ASSERT_TRUE(s_autofill_profiles_empty.is_valid());
EXPECT_FALSE(s_autofill_profiles_empty.Step());
+
+ // Make sure there are no profile names remaining.
+ sql::Statement s_autofill_profile_names_empty(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT full_name FROM autofill_profile_names"));
+ ASSERT_TRUE(s_autofill_profile_names_empty.is_valid());
+ EXPECT_FALSE(s_autofill_profile_names_empty.Step());
+
+ // Make sure there are no profile emails remaining.
+ sql::Statement s_autofill_profile_emails_empty(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT email FROM autofill_profile_emails"));
+ ASSERT_TRUE(s_autofill_profile_emails_empty.is_valid());
+ EXPECT_FALSE(s_autofill_profile_emails_empty.Step());
+
+ // Make sure there are no profile phones remaining.
+ sql::Statement s_autofill_profile_phones_empty(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT number FROM autofill_profile_phones"));
+ ASSERT_TRUE(s_autofill_profile_phones_empty.is_valid());
+ EXPECT_FALSE(s_autofill_profile_phones_empty.Step());
+
+ // One credit card should have been deleted.
ASSERT_EQ(1UL, credit_card_guids.size());
EXPECT_EQ("00000000-0000-0000-0000-000000000009", credit_card_guids[0]);
+
+ // There should be no cards left.
sql::Statement s_credit_cards_empty(
db_->GetSQLConnection()->GetUniqueStatement(
"SELECT date_modified FROM credit_cards"));
@@ -2272,4 +2437,153 @@ TEST_F(AutofillTableTest, AutofillCorruptModelTypeState) {
EXPECT_FALSE(table_->GetAllSyncMetadata(syncer::AUTOFILL, &metadata_batch));
}
+TEST_F(AutofillTableTest, RemoveOrphanAutofillTableRows) {
+ // Populate the different tables.
+ ASSERT_TRUE(db_->GetSQLConnection()->Execute(
+ // Add a profile in all the tables
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000000', 11);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000000', 'John Jones');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000000', 'john@jones.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000000', '111-111-1111');"
+
+ // Add a profile in profiles, names and emails tables.
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000001', 21);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000001', 'John Jones2');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000001', 'john@jones2.com');"
+
+ // Add a profile in profiles, names and phones tables.
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000002', 31);"
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000002', 'John Jones3');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000002', '333-333-3333');"
+
+ // Add a profile in profiles, emails and phones tables.
+ "INSERT INTO autofill_profiles (guid, date_modified) "
+ "VALUES('00000000-0000-0000-0000-000000000003', 41);"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000003', 'john@jones4.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000003', '444-444-4444');"
+
+ // Add a orphan profile in names, emails and phones tables.
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000004', 'John Jones5');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000004', 'john@jones5.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000004', '555-555-5555');"
+
+ // Add a orphan profile in names and emails tables.
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000005', 'John Jones6');"
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000005', 'john@jones6.com');"
+
+ // Add a orphan profile in names and phones tables.
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000006', 'John Jones7');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000006', '777-777-7777');"
+
+ // Add a orphan profile in emails and phones tables.
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000007', 'john@jones8.com');"
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000007', '999-999-9999');"
+
+ // Add a orphan profile in the names table.
+ "INSERT INTO autofill_profile_names (guid, full_name) "
+ "VALUES('00000000-0000-0000-0000-000000000008', 'John Jones9');"
+
+ // Add a orphan profile in the emails table.
+ "INSERT INTO autofill_profile_emails (guid, email) "
+ "VALUES('00000000-0000-0000-0000-000000000009', 'john@jones10.com');"
+
+ // Add a orphan profile in the phones table.
+ "INSERT INTO autofill_profile_phones (guid, number) "
+ "VALUES('00000000-0000-0000-0000-000000000010', '101-010-1010');"));
+
+ ASSERT_TRUE(table_->RemoveOrphanAutofillTableRows());
+
+ // Make sure that all the rows in the autofill_profiles table are still
+ // present.
+ sql::Statement s_autofill_profiles(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid FROM autofill_profiles"));
+ ASSERT_TRUE(s_autofill_profiles.is_valid());
+ ASSERT_TRUE(s_autofill_profiles.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000",
+ s_autofill_profiles.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profiles.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001",
+ s_autofill_profiles.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profiles.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000002",
+ s_autofill_profiles.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profiles.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000003",
+ s_autofill_profiles.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profiles.Step());
+
+ // Make sure that only the rows present in the autofill_profiles table are
+ // present in the autofill_profile_names table.
+ sql::Statement s_autofill_profile_names(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid FROM autofill_profile_names"));
+ ASSERT_TRUE(s_autofill_profile_names.is_valid());
+ ASSERT_TRUE(s_autofill_profile_names.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000",
+ s_autofill_profile_names.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_names.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001",
+ s_autofill_profile_names.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_names.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000002",
+ s_autofill_profile_names.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_names.Step());
+
+ // Make sure that only the rows present in the autofill_profiles table are
+ // present in the autofill_profile_emails table.
+ sql::Statement s_autofill_profile_emails(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid FROM autofill_profile_emails"));
+ ASSERT_TRUE(s_autofill_profile_emails.is_valid());
+ ASSERT_TRUE(s_autofill_profile_emails.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000",
+ s_autofill_profile_emails.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_emails.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000001",
+ s_autofill_profile_emails.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_emails.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000003",
+ s_autofill_profile_emails.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_emails.Step());
+
+ // Make sure that only the rows present in the autofill_profiles table are
+ // present in the autofill_profile_phones table.
+ sql::Statement s_autofill_profile_phones(
+ db_->GetSQLConnection()->GetUniqueStatement(
+ "SELECT guid FROM autofill_profile_phones"));
+ ASSERT_TRUE(s_autofill_profile_phones.is_valid());
+ ASSERT_TRUE(s_autofill_profile_phones.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000000",
+ s_autofill_profile_phones.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_phones.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000002",
+ s_autofill_profile_phones.ColumnString(0));
+ ASSERT_TRUE(s_autofill_profile_phones.Step());
+ EXPECT_EQ("00000000-0000-0000-0000-000000000003",
+ s_autofill_profile_phones.ColumnString(0));
+ EXPECT_FALSE(s_autofill_profile_phones.Step());
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata.h
index 07fe5002a2f..fc715a0aa31 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata.h
@@ -126,6 +126,10 @@ class AutofillWebData {
// the database.
virtual void RemoveOriginURLsModifiedBetween(
const base::Time& delete_begin, const base::Time& delete_end) = 0;
+
+ // Removes the orphan rows in the autofill_profile_names,
+ // autofill_profile_emails and autofill_profile_phones tables.
+ virtual void RemoveOrphanAutofillTableRows() = 0;
};
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
index 67de7896c07..d48dd083705 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.cc
@@ -49,7 +49,7 @@ void AutofillWebDataBackendImpl::RemoveObserver(
}
AutofillWebDataBackendImpl::~AutofillWebDataBackendImpl() {
- DCHECK(!user_data_.get()); // Forgot to call ResetUserData?
+ DCHECK(!user_data_); // Forgot to call ResetUserData?
}
WebDatabase* AutofillWebDataBackendImpl::GetDatabase() {
@@ -501,4 +501,13 @@ WebDatabase::State AutofillWebDataBackendImpl::RemoveExpiredFormElementsImpl(
return WebDatabase::COMMIT_NOT_NEEDED;
}
+WebDatabase::State AutofillWebDataBackendImpl::RemoveOrphanAutofillTableRows(
+ WebDatabase* db) {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ if (AutofillTable::FromWebDatabase(db)->RemoveOrphanAutofillTableRows()) {
+ return WebDatabase::COMMIT_NEEDED;
+ }
+ return WebDatabase::COMMIT_NOT_NEEDED;
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
index 9fcbc877a4b..59d7b12c3bc 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_backend_impl.h
@@ -179,6 +179,10 @@ class AutofillWebDataBackendImpl
const base::Time& delete_end,
WebDatabase* db);
+ // Removes the orphan rows in the autofill_profile_names,
+ // autofill_profile_emails and autofill_profile_phones tables.
+ WebDatabase::State RemoveOrphanAutofillTableRows(WebDatabase* db);
+
protected:
~AutofillWebDataBackendImpl() override;
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
index 2752366cbe6..c9d3d8a5dd0 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.cc
@@ -251,17 +251,24 @@ void AutofillWebDataService::RemoveOriginURLsModifiedBetween(
autofill_backend_, delete_begin, delete_end));
}
+void AutofillWebDataService::RemoveOrphanAutofillTableRows() {
+ wdbs_->ScheduleDBTask(
+ FROM_HERE,
+ Bind(&AutofillWebDataBackendImpl::RemoveOrphanAutofillTableRows,
+ autofill_backend_));
+}
+
void AutofillWebDataService::AddObserver(
AutofillWebDataServiceObserverOnDBSequence* observer) {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
- if (autofill_backend_.get())
+ if (autofill_backend_)
autofill_backend_->AddObserver(observer);
}
void AutofillWebDataService::RemoveObserver(
AutofillWebDataServiceObserverOnDBSequence* observer) {
DCHECK(db_task_runner_->RunsTasksInCurrentSequence());
- if (autofill_backend_.get())
+ if (autofill_backend_)
autofill_backend_->RemoveObserver(observer);
}
diff --git a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
index f6d265b36ec..fe42a7e9972 100644
--- a/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
+++ b/chromium/components/autofill/core/browser/webdata/autofill_webdata_service.h
@@ -108,6 +108,8 @@ class AutofillWebDataService : public AutofillWebData,
void RemoveOriginURLsModifiedBetween(const base::Time& delete_begin,
const base::Time& delete_end) override;
+ void RemoveOrphanAutofillTableRows() override;
+
void AddObserver(AutofillWebDataServiceObserverOnDBSequence* observer);
void RemoveObserver(AutofillWebDataServiceObserverOnDBSequence* observer);
diff --git a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc b/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc
index aa2eb36397d..d21981e122e 100644
--- a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc
+++ b/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.cc
@@ -18,18 +18,18 @@ WebDataModelTypeController::WebDataModelTypeController(
SyncClient* sync_client,
const scoped_refptr<base::SingleThreadTaskRunner>& model_thread,
const scoped_refptr<AutofillWebDataService>& web_data_service,
- const BridgeFromWebData& bridge_from_web_data)
+ const DelegateFromWebData& delegate_from_web_data)
: ModelTypeController(type, sync_client, model_thread),
web_data_service_(web_data_service),
- bridge_from_web_data_(bridge_from_web_data) {}
+ delegate_from_web_data_(delegate_from_web_data) {}
WebDataModelTypeController::~WebDataModelTypeController() {}
-ModelTypeController::BridgeProvider
-WebDataModelTypeController::GetBridgeProvider() {
- // As opposed to the default implementation, get the bridge on demand, the web
- // data service requires us to be on the model thread.
- return base::Bind(bridge_from_web_data_,
+ModelTypeController::DelegateProvider
+WebDataModelTypeController::GetDelegateProvider() {
+ // As opposed to the default implementation, get the delegate on demand, the
+ // web data service requires us to be on the model thread.
+ return base::Bind(delegate_from_web_data_,
base::RetainedRef(web_data_service_));
}
diff --git a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h b/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h
index b071d28c556..1a80c1e7be1 100644
--- a/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h
+++ b/chromium/components/autofill/core/browser/webdata/web_data_model_type_controller.h
@@ -11,15 +11,15 @@
#include "components/sync/driver/model_type_controller.h"
namespace syncer {
-class ModelTypeSyncBridge;
+class ModelTypeControllerDelegate;
} // namespace syncer
namespace autofill {
class WebDataModelTypeController : public syncer::ModelTypeController {
public:
- using BridgeFromWebData =
- base::Callback<base::WeakPtr<syncer::ModelTypeSyncBridge>(
+ using DelegateFromWebData =
+ base::Callback<base::WeakPtr<syncer::ModelTypeControllerDelegate>(
AutofillWebDataService*)>;
WebDataModelTypeController(
@@ -27,19 +27,19 @@ class WebDataModelTypeController : public syncer::ModelTypeController {
syncer::SyncClient* sync_client,
const scoped_refptr<base::SingleThreadTaskRunner>& model_thread,
const scoped_refptr<AutofillWebDataService>& web_data_service,
- const BridgeFromWebData& bridge_from_web_data);
+ const DelegateFromWebData& delegate_from_web_data);
~WebDataModelTypeController() override;
private:
// syncer::ModelTypeController implementation.
- syncer::ModelTypeController::BridgeProvider GetBridgeProvider() override;
+ syncer::ModelTypeController::DelegateProvider GetDelegateProvider() override;
// A reference to the AutofillWebDataService for this controller.
scoped_refptr<AutofillWebDataService> web_data_service_;
- // How to grab the correct bridge from a web data.
- BridgeFromWebData bridge_from_web_data_;
+ // How to grab the correct delegate from a web data.
+ DelegateFromWebData delegate_from_web_data_;
DISALLOW_COPY_AND_ASSIGN(WebDataModelTypeController);
};
diff --git a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
index a752d274e7b..9058c7eeccc 100644
--- a/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
+++ b/chromium/components/autofill/core/browser/webdata/web_data_service_unittest.cc
@@ -133,15 +133,14 @@ class WebDataServiceTest : public testing::Test {
class WebDataServiceAutofillTest : public WebDataServiceTest {
public:
WebDataServiceAutofillTest()
- : WebDataServiceTest(),
- unique_id1_(1),
+ : unique_id1_(1),
unique_id2_(2),
test_timeout_(TimeDelta::FromSeconds(kWebDataServiceTimeoutSeconds)),
done_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
protected:
- virtual void SetUp() {
+ void SetUp() override {
WebDataServiceTest::SetUp();
name1_ = ASCIIToUTF16("name1");
name2_ = ASCIIToUTF16("name2");
@@ -156,7 +155,7 @@ class WebDataServiceAutofillTest : public WebDataServiceTest {
base::TaskScheduler::GetInstance()->FlushForTesting();
}
- virtual void TearDown() {
+ void TearDown() override {
void (AutofillWebDataService::*remove_observer_func)(
AutofillWebDataServiceObserverOnDBSequence*) =
&AutofillWebDataService::RemoveObserver;
@@ -333,10 +332,10 @@ TEST_F(WebDataServiceAutofillTest, ProfileRemove) {
TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
// The GUIDs are alphabetical for easier testing.
AutofillProfile profile1("6141084B-72D7-4B73-90CF-3D6AC154673B",
- "http://example.com");
+ std::string());
profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Abe"));
AutofillProfile profile2("087151C8-6AB1-487C-9095-28E80BE5DA15",
- "http://example.com");
+ std::string());
profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Alice"));
EXPECT_CALL(observer_, AutofillProfileChanged(_))
@@ -423,11 +422,9 @@ TEST_F(WebDataServiceAutofillTest, CreditCardRemove) {
}
TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
- CreditCard card1("E4D2662E-5E16-44F3-AF5A-5A77FAE4A6F3",
- "https://ejemplo.mx");
+ CreditCard card1("E4D2662E-5E16-44F3-AF5A-5A77FAE4A6F3", std::string());
card1.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Abe"));
- CreditCard card2("B9C52112-BD5F-4080-84E1-C651D2CB90E2",
- "https://example.com");
+ CreditCard card2("B9C52112-BD5F-4080-84E1-C651D2CB90E2", std::string());
card2.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Alice"));
wds_->AddCreditCard(card1);
diff --git a/chromium/components/autofill/core/common/autofill_data_validation.cc b/chromium/components/autofill/core/common/autofill_data_validation.cc
index f1075dc384d..64eb6ebea9c 100644
--- a/chromium/components/autofill/core/common/autofill_data_validation.cc
+++ b/chromium/components/autofill/core/common/autofill_data_validation.cc
@@ -70,14 +70,6 @@ bool IsValidPasswordFormFillData(const PasswordFormFillData& form) {
return false;
}
- for (const auto& it : form.other_possible_usernames) {
- if (!IsValidString16(it.first.username) ||
- !IsValidString16(it.first.password) ||
- !IsValidString(it.first.realm) ||
- !IsValidString16Vector(it.second))
- return false;
- }
-
return true;
}
diff --git a/chromium/components/autofill/core/common/autofill_features.cc b/chromium/components/autofill/core/common/autofill_features.cc
index df694713df2..9846b16cc64 100644
--- a/chromium/components/autofill/core/common/autofill_features.cc
+++ b/chromium/components/autofill/core/common/autofill_features.cc
@@ -12,14 +12,21 @@ namespace features {
const base::Feature kAutofillAddressNormalizer{
"AutofillAddressNormalizer", base::FEATURE_ENABLED_BY_DEFAULT};
-// Controls whether credit card suggestions are made on insecure pages.
-const base::Feature kAutofillRequireSecureCreditCardContext{
- "AutofillRequireSecureCreditCardContext", base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls the use of GET (instead of POST) to fetch cacheable autofill query
+// responses.
+const base::Feature kAutofillCacheQueryResponses{
+ "AutofillCacheQueryResponses", base::FEATURE_ENABLED_BY_DEFAULT};
// Controls whether Autofill attemps to fill dynamically changing forms.
const base::Feature kAutofillDynamicForms{"AutofillDynamicForms",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls whether the server credit cards are offered to be filled and
+// uploaded to Google Pay if the sync service is in auth error.
+const base::Feature kAutofillEnablePaymentsInteractionsOnAuthError{
+ "AutofillDontOfferServerCardsOnAuthError",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether or not a minimum number of fields is required before
// heuristic field type prediction is run for a form.
const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics{
@@ -38,6 +45,16 @@ const base::Feature kAutofillEnforceMinRequiredFieldsForUpload{
"AutofillEnforceMinRequiredFieldsForUpload",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether credit card suggestions are made on insecure pages.
+const base::Feature kAutofillRequireSecureCreditCardContext{
+ "AutofillRequireSecureCreditCardContext", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Controls whether Full Server credit cards should be reset when the sync
+// service is in an auth error state.
+const base::Feature kAutofillResetFullServerCardsOnAuthError{
+ "AutofillResetFullServerCardsOnAuthError",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
// Controls whether or not a group of fields not enclosed in a form can be
// considered a form. If this is enabled, unowned fields will only constitute
// a form if there are signals to suggest that this might a checkout page.
@@ -45,6 +62,18 @@ const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout{
"AutofillRestrictUnownedFieldsToFormlessCheckout",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Controls whether experiment ids should be sent through
+// Google Payments RPCs or not.
+const base::Feature kAutofillSendExperimentIdsInPaymentsRPCs{
+ "AutofillSendExperimentIdsInPaymentsRPCs",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Controls whether we show warnings in the Dev console for misused autocomplete
+// types.
+const base::Feature kAutofillShowAutocompleteConsoleWarnings{
+ "AutofillShowAutocompleteConsoleWarnings",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
// Controls attaching the autofill type predictions to their respective
// element in the DOM.
const base::Feature kAutofillShowTypePredictions{
@@ -56,10 +85,14 @@ const base::Feature kAutofillSkipComparingInferredLabels{
"AutofillSkipComparingInferredLabels", base::FEATURE_DISABLED_BY_DEFAULT};
// Controls whether the credit card upload bubble shows the Google Pay logo and
-// a shorter "Save card?" header message on Android.
-const base::Feature kAutofillUpstreamUseGooglePayOnAndroidBranding{
+// a shorter "Save card?" header message on mobile.
+const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile{
"AutofillUpstreamUseGooglePayOnAndroidBranding",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Controls whether or not the autofill UI triggers on a single click.
+const base::Feature kSingleClickAutofill{"SingleClickAutofill",
+ base::FEATURE_ENABLED_BY_DEFAULT};
+
} // namespace features
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_features.h b/chromium/components/autofill/core/common/autofill_features.h
index 3d32bcfbb5b..b8e577e7f38 100644
--- a/chromium/components/autofill/core/common/autofill_features.h
+++ b/chromium/components/autofill/core/common/autofill_features.h
@@ -12,15 +12,21 @@ namespace features {
// All features in alphabetical order.
extern const base::Feature kAutofillAddressNormalizer;
-extern const base::Feature kAutofillRequireSecureCreditCardContext;
+extern const base::Feature kAutofillCacheQueryResponses;
extern const base::Feature kAutofillDynamicForms;
+extern const base::Feature kAutofillEnablePaymentsInteractionsOnAuthError;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForHeuristics;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForQuery;
extern const base::Feature kAutofillEnforceMinRequiredFieldsForUpload;
+extern const base::Feature kAutofillRequireSecureCreditCardContext;
+extern const base::Feature kAutofillResetFullServerCardsOnAuthError;
extern const base::Feature kAutofillRestrictUnownedFieldsToFormlessCheckout;
+extern const base::Feature kAutofillSendExperimentIdsInPaymentsRPCs;
+extern const base::Feature kAutofillShowAutocompleteConsoleWarnings;
extern const base::Feature kAutofillShowTypePredictions;
extern const base::Feature kAutofillSkipComparingInferredLabels;
-extern const base::Feature kAutofillUpstreamUseGooglePayOnAndroidBranding;
+extern const base::Feature kAutofillUpstreamUseGooglePayBrandingOnMobile;
+extern const base::Feature kSingleClickAutofill;
} // namespace features
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_pref_names.cc b/chromium/components/autofill/core/common/autofill_pref_names.cc
index ec4976a8f53..cb9bf1d1db4 100644
--- a/chromium/components/autofill/core/common/autofill_pref_names.cc
+++ b/chromium/components/autofill/core/common/autofill_pref_names.cc
@@ -7,10 +7,21 @@
namespace autofill {
namespace prefs {
+// Integer that is set to the last choice user made when prompted for saving a
+// credit card. The prompt is for user's consent in saving the card in the
+// server for signed in users and saving the card locally for non signed-in
+// users.
+const char kAutofillAcceptSaveCreditCardPromptState[] =
+ "autofill.accept_save_credit_card_prompt_state";
+
// Integer that is set to the billing customer number fetched from priority
// preference.
const char kAutofillBillingCustomerNumber[] = "billing_customer_number";
+// Boolean that is true if Autofill is enabled and allowed to save credit card
+// data.
+const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled";
+
// Number of times the credit card signin promo has been shown.
const char kAutofillCreditCardSigninPromoImpressionCount[] =
"autofill.credit_card_signin_promo_impression_count";
@@ -18,14 +29,6 @@ const char kAutofillCreditCardSigninPromoImpressionCount[] =
// Boolean that is true if Autofill is enabled and allowed to save profile data.
const char kAutofillEnabled[] = "autofill.enabled";
-// Boolean that is true if Autofill address profiles were fixed regarding their
-// bad use dates.
-const char kAutofillProfileUseDatesFixed[] = "autofill.profile_use_dates_fixed";
-
-// Boolean that's true when Wallet card and address import is enabled by the
-// user.
-const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled";
-
// Integer that is set to the last version where the profile deduping routine
// was run. This routine will be run once per version.
const char kAutofillLastVersionDeduped[] = "autofill.last_version_deduped";
@@ -40,21 +43,17 @@ const char kAutofillLastVersionDisusedAddressesDeleted[] =
const char kAutofillLastVersionDisusedCreditCardsDeleted[] =
"autofill.last_version_disused_credit_cards_deleted";
+// Boolean that is true if the orphan rows in the autofill table were removed.
+const char kAutofillOrphanRowsRemoved[] = "autofill.orphan_rows_removed";
+
+// Boolean that's true when Wallet card and address import is enabled by the
+// user.
+const char kAutofillWalletImportEnabled[] = "autofill.wallet_import_enabled";
+
// Boolean that is set to the last choice user made when prompted for saving an
// unmasked server card locally.
const char kAutofillWalletImportStorageCheckboxState[] =
"autofill.wallet_import_storage_checkbox_state";
-// Integer that is set to the last choice user made when prompted for saving a
-// credit card. The prompt is for user's consent in saving the card in the
-// server for signed in users and saving the card locally for non signed-in
-// users.
-const char kAutofillAcceptSaveCreditCardPromptState[] =
- "autofill.accept_save_credit_card_prompt_state";
-
-// Boolean that is true if Autofill is enabled and allowed to save credit card
-// data.
-const char kAutofillCreditCardEnabled[] = "autofill.credit_card_enabled";
-
} // namespace prefs
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/autofill_pref_names.h b/chromium/components/autofill/core/common/autofill_pref_names.h
index 43c0bdae174..43c2ba84974 100644
--- a/chromium/components/autofill/core/common/autofill_pref_names.h
+++ b/chromium/components/autofill/core/common/autofill_pref_names.h
@@ -19,7 +19,7 @@ extern const char kAutofillEnabled[];
extern const char kAutofillLastVersionDeduped[];
extern const char kAutofillLastVersionDisusedAddressesDeleted[];
extern const char kAutofillLastVersionDisusedCreditCardsDeleted[];
-extern const char kAutofillProfileUseDatesFixed[];
+extern const char kAutofillOrphanRowsRemoved[];
extern const char kAutofillWalletImportEnabled[];
extern const char kAutofillWalletImportStorageCheckboxState[];
diff --git a/chromium/components/autofill/core/common/autofill_switches.cc b/chromium/components/autofill/core/common/autofill_switches.cc
index eac7a997fbc..c48c96a70b5 100644
--- a/chromium/components/autofill/core/common/autofill_switches.cc
+++ b/chromium/components/autofill/core/common/autofill_switches.cc
@@ -8,38 +8,28 @@
namespace autofill {
namespace switches {
+// Override the default autofill server URL with "scheme://host[:port]/prefix/".
+const char kAutofillServerURL[] = "autofill-server-url";
+
// Force hiding the local save checkbox in the autofill dialog box for getting
// the full credit card number for a wallet card. The card will never be stored
// locally.
const char kDisableOfferStoreUnmaskedWalletCards[] =
"disable-offer-store-unmasked-wallet-cards";
-// Disables offering to upload credit cards.
-const char kDisableOfferUploadCreditCards[] =
- "disable-offer-upload-credit-cards";
-
// Disables password generation when we detect that the user is going through
// account creation.
const char kDisablePasswordGeneration[] = "disable-password-generation";
-// The "disable" flag for kEnableSingleClickAutofill.
-const char kDisableSingleClickAutofill[] = "disable-single-click-autofill";
-
// Force showing the local save checkbox in the autofill dialog box for getting
// the full credit card number for a wallet card.
const char kEnableOfferStoreUnmaskedWalletCards[] =
"enable-offer-store-unmasked-wallet-cards";
-// Enables offering to upload credit cards.
-const char kEnableOfferUploadCreditCards[] = "enable-offer-upload-credit-cards";
-
// Enables password generation when we detect that the user is going through
// account creation.
const char kEnablePasswordGeneration[] = "enable-password-generation";
-// Enables/disables suggestions without typing anything (on first click).
-const char kEnableSingleClickAutofill[] = "enable-single-click-autofill";
-
// Enables suggestions with substring matching instead of prefix matching.
const char kEnableSuggestionsWithSubstringMatch[] =
"enable-suggestions-with-substring-match";
diff --git a/chromium/components/autofill/core/common/autofill_switches.h b/chromium/components/autofill/core/common/autofill_switches.h
index d0ef9cc7687..240367104bb 100644
--- a/chromium/components/autofill/core/common/autofill_switches.h
+++ b/chromium/components/autofill/core/common/autofill_switches.h
@@ -12,14 +12,11 @@ namespace switches {
// All switches in alphabetical order. The switches should be documented
// alongside the definition of their values in the .cc file.
+extern const char kAutofillServerURL[];
extern const char kDisableOfferStoreUnmaskedWalletCards[];
-extern const char kDisableOfferUploadCreditCards[];
extern const char kDisablePasswordGeneration[];
-extern const char kDisableSingleClickAutofill[];
extern const char kEnableOfferStoreUnmaskedWalletCards[];
-extern const char kEnableOfferUploadCreditCards[];
extern const char kEnablePasswordGeneration[];
-extern const char kEnableSingleClickAutofill[];
extern const char kEnableSuggestionsWithSubstringMatch[];
extern const char kIgnoreAutocompleteOffForAutofill[];
extern const char kLocalHeuristicsOnlyForPasswordGeneration[];
diff --git a/chromium/components/autofill/core/common/form_data.cc b/chromium/components/autofill/core/common/form_data.cc
index 664354e0373..3fb7a74bb24 100644
--- a/chromium/components/autofill/core/common/form_data.cc
+++ b/chromium/components/autofill/core/common/form_data.cc
@@ -77,6 +77,7 @@ FormData::FormData(const FormData& data)
main_frame_origin(data.main_frame_origin),
is_form_tag(data.is_form_tag),
is_formless_checkout(data.is_formless_checkout),
+ unique_renderer_id(data.unique_renderer_id),
fields(data.fields) {}
FormData::~FormData() {
@@ -110,6 +111,7 @@ bool FormData::SimilarFormAs(const FormData& form) const {
bool FormData::operator==(const FormData& form) const {
return name == form.name && origin == form.origin && action == form.action &&
+ unique_renderer_id == form.unique_renderer_id &&
is_form_tag == form.is_form_tag &&
is_formless_checkout == form.is_formless_checkout &&
fields == form.fields;
diff --git a/chromium/components/autofill/core/common/form_data.h b/chromium/components/autofill/core/common/form_data.h
index 3076dedd9a7..d817c21318b 100644
--- a/chromium/components/autofill/core/common/form_data.h
+++ b/chromium/components/autofill/core/common/form_data.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_AUTOFILL_CORE_COMMON_FORM_DATA_H_
#define COMPONENTS_AUTOFILL_CORE_COMMON_FORM_DATA_H_
+#include <limits>
#include <vector>
#include "base/strings/string16.h"
@@ -16,6 +17,9 @@ namespace autofill {
// Holds information about a form to be filled and/or submitted.
struct FormData {
+ static constexpr uint32_t kNotSetFormRendererId =
+ std::numeric_limits<uint32_t>::max();
+
FormData();
FormData(const FormData& data);
~FormData();
@@ -51,6 +55,10 @@ struct FormData {
// and used if features::kAutofillRestrictUnownedFieldsToFormlessCheckout is
// enabled, to prevent heuristics from running on formless non-checkout.
bool is_formless_checkout;
+ // Unique renderer id which is returned by function
+ // WebFormElement::UniqueRendererFormId(). It is not persistant between page
+ // loads, so it is not saved and not used in comparison in SameFormAs().
+ uint32_t unique_renderer_id = kNotSetFormRendererId;
// A vector of all the input fields in the form.
std::vector<FormFieldData> fields;
};
diff --git a/chromium/components/autofill/core/common/form_field_data.cc b/chromium/components/autofill/core/common/form_field_data.cc
index 56dea7012e6..785c5ab152b 100644
--- a/chromium/components/autofill/core/common/form_field_data.cc
+++ b/chromium/components/autofill/core/common/form_field_data.cc
@@ -145,6 +145,9 @@ FormFieldData::FormFieldData()
role(ROLE_ATTRIBUTE_OTHER),
text_direction(base::i18n::UNKNOWN_DIRECTION),
properties_mask(0),
+ is_enabled(false),
+ is_readonly(false),
+ is_default(false),
label_source(LabelSource::UNKNOWN) {}
FormFieldData::FormFieldData(const FormFieldData& other) = default;
@@ -154,6 +157,11 @@ FormFieldData::~FormFieldData() {}
bool FormFieldData::SameFieldAs(const FormFieldData& field) const {
// A FormFieldData stores a value, but the value is not part of the identity
// of the field, so we don't want to compare the values.
+ // Similarly, flags like is_enabled, which are only used for parsing but are
+ // not stored persistently, are not used for comparison.
+ // is_autofilled and section are also secondary properties of a field. Two
+ // fields could be the same, and have different sections, because the section
+ // is updated for one, but not for the other.
return name == field.name && id == field.id &&
form_control_type == field.form_control_type &&
autocomplete_attribute == field.autocomplete_attribute &&
@@ -181,8 +189,15 @@ bool FormFieldData::SimilarFieldAs(const FormFieldData& field) const {
IsCheckable(check_status) == IsCheckable(field.check_status);
}
+bool FormFieldData::IsTextInputElement() const {
+ return form_control_type == "text" || form_control_type == "password" ||
+ form_control_type == "search" || form_control_type == "tel" ||
+ form_control_type == "url" || form_control_type == "email";
+}
+
bool FormFieldData::operator==(const FormFieldData& field) const {
- return SameFieldAs(field) && is_autofilled == field.is_autofilled &&
+ return SameFieldAs(field) && unique_renderer_id == field.unique_renderer_id &&
+ is_autofilled == field.is_autofilled &&
check_status == field.check_status &&
option_values == field.option_values &&
option_contents == field.option_contents &&
@@ -253,7 +268,8 @@ bool FormFieldData::operator<(const FormFieldData& field) const {
return true;
if (text_direction > field.text_direction)
return false;
- // See SameFieldAs above for why we don't check option_values/contents.
+ // See SameFieldAs above for why we don't check option_values/contents and
+ // flags like is_enabled.
return false;
}
@@ -431,6 +447,10 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field) {
<< "should_autocomplete=" << field.should_autocomplete << " "
<< "role=" << role_str << " "
<< "text_direction=" << field.text_direction << " "
+ << "is_enabled=" << field.is_enabled << " "
+ << "is_readonly=" << field.is_readonly << " "
+ << "is_default=" << field.is_default << " "
+ << "typed_value=" << field.typed_value << " "
<< "properties_mask=" << field.properties_mask << " "
<< "label_source=" << field.label_source;
}
diff --git a/chromium/components/autofill/core/common/form_field_data.h b/chromium/components/autofill/core/common/form_field_data.h
index 392d474170d..ce882a709f4 100644
--- a/chromium/components/autofill/core/common/form_field_data.h
+++ b/chromium/components/autofill/core/common/form_field_data.h
@@ -7,6 +7,7 @@
#include <stddef.h>
+#include <limits>
#include <vector>
#include "base/i18n/rtl.h"
@@ -23,10 +24,17 @@ namespace autofill {
enum FieldPropertiesFlags {
NO_FLAGS = 0u,
USER_TYPED = 1u << 0,
+ // AUTOFILLED means that at least one character of the field value comes from
+ // being autofilled. This is different from
+ // WebFormControlElement::IsAutofilled(). It is meant to be used for password
+ // fields, to determine whether viewing the value needs user reauthentication.
AUTOFILLED = 1u << 1,
HAD_FOCUS = 1u << 2,
// Use this flag, if some error occurred in flags processing.
- ERROR_OCCURRED = 1u << 3
+ ERROR_OCCURRED = 1u << 3,
+ // On submission, the value of the field was recognised as a value which is
+ // already stored.
+ KNOWN_VALUE = 1u << 4
};
// FieldPropertiesMask is used to contain combinations of FieldPropertiesFlags
@@ -64,6 +72,9 @@ struct FormFieldData {
VALUE, // label is the value of element.
};
+ static constexpr uint32_t kNotSetFormControlRendererId =
+ std::numeric_limits<uint32_t>::max();
+
FormFieldData();
FormFieldData(const FormFieldData& other);
~FormFieldData();
@@ -78,6 +89,12 @@ struct FormFieldData {
// other information isn't changed.
bool SimilarFieldAs(const FormFieldData& field) const;
+ // Returns true for all of textfield-looking types such as text, password,
+ // search, email, url, and number. It must work the same way as Blink function
+ // WebInputElement::IsTextField(), and it returns false if |*this| represents
+ // a textarea.
+ bool IsTextInputElement() const;
+
// Note: operator==() performs a full-field-comparison(byte by byte), this is
// different from SameFieldAs(), which ignores comparison for those "values"
// not regarded as part of identity of the field, such as is_autofilled and
@@ -97,6 +114,16 @@ struct FormFieldData {
std::string autocomplete_attribute;
base::string16 placeholder;
base::string16 css_classes;
+ // Unique renderer id which is returned by function
+ // WebFormControlElement::UniqueRendererFormControlId(). It is not persistant
+ // between page loads, so it is not saved and not used in comparison in
+ // SameFieldAs().
+ uint32_t unique_renderer_id = kNotSetFormControlRendererId;
+
+ // The unique identifier of the section (e.g. billing vs. shipping address)
+ // of this field.
+ std::string section;
+
// Note: we use uint64_t instead of size_t because this struct is sent over
// IPC which could span 32 & 64 bit processes. We chose uint64_t instead of
// uint32_t to maintain compatibility with old code which used size_t
@@ -110,6 +137,13 @@ struct FormFieldData {
base::i18n::TextDirection text_direction;
FieldPropertiesMask properties_mask;
+ // Data members from the next block are used for parsing only, they are not
+ // serialised for storage.
+ bool is_enabled;
+ bool is_readonly;
+ bool is_default;
+ base::string16 typed_value;
+
// For the HTML snippet |<option value="US">United States</option>|, the
// value is "US" and the contents are "United States".
std::vector<base::string16> option_values;
@@ -143,6 +177,7 @@ std::ostream& operator<<(std::ostream& os, const FormFieldData& field);
EXPECT_EQ(expected.max_length, actual.max_length); \
EXPECT_EQ(expected.css_classes, actual.css_classes); \
EXPECT_EQ(expected.is_autofilled, actual.is_autofilled); \
+ EXPECT_EQ(expected.section, actual.section); \
EXPECT_EQ(expected.check_status, actual.check_status); \
EXPECT_EQ(expected.properties_mask, actual.properties_mask); \
EXPECT_EQ(expected.id, actual.id); \
diff --git a/chromium/components/autofill/core/common/form_field_data_predictions.cc b/chromium/components/autofill/core/common/form_field_data_predictions.cc
index 25c883c02fd..9109fcfd537 100644
--- a/chromium/components/autofill/core/common/form_field_data_predictions.cc
+++ b/chromium/components/autofill/core/common/form_field_data_predictions.cc
@@ -16,8 +16,8 @@ FormFieldDataPredictions::FormFieldDataPredictions(
heuristic_type(other.heuristic_type),
server_type(other.server_type),
overall_type(other.overall_type),
- parseable_name(other.parseable_name) {
-}
+ parseable_name(other.parseable_name),
+ section(other.section) {}
FormFieldDataPredictions::~FormFieldDataPredictions() {
}
@@ -29,7 +29,8 @@ bool FormFieldDataPredictions::operator==(
heuristic_type == predictions.heuristic_type &&
server_type == predictions.server_type &&
overall_type == predictions.overall_type &&
- parseable_name == predictions.parseable_name);
+ parseable_name == predictions.parseable_name &&
+ section == predictions.section);
}
bool FormFieldDataPredictions::operator!=(
diff --git a/chromium/components/autofill/core/common/form_field_data_predictions.h b/chromium/components/autofill/core/common/form_field_data_predictions.h
index fa09807ec85..baeb68bfba8 100644
--- a/chromium/components/autofill/core/common/form_field_data_predictions.h
+++ b/chromium/components/autofill/core/common/form_field_data_predictions.h
@@ -24,6 +24,7 @@ struct FormFieldDataPredictions {
std::string server_type;
std::string overall_type;
std::string parseable_name;
+ std::string section;
// Added for the sake of testing.
bool operator==(const FormFieldDataPredictions& predictions) const;
diff --git a/chromium/components/autofill/core/common/form_field_data_unittest.cc b/chromium/components/autofill/core/common/form_field_data_unittest.cc
index 0c94126a202..648cf67b5a4 100644
--- a/chromium/components/autofill/core/common/form_field_data_unittest.cc
+++ b/chromium/components/autofill/core/common/form_field_data_unittest.cc
@@ -334,9 +334,28 @@ TEST(FormFieldDataTest, DeserializeBadData) {
base::PickleIterator iter(pickle);
FormFieldData actual;
EXPECT_FALSE(DeserializeFormFieldData(&iter, &actual));
-
FormFieldData empty;
EXPECT_TRUE(actual.SameFieldAs(empty));
}
+TEST(FormFieldDataTest, IsTextInputElement) {
+ struct TestData {
+ const char* form_control_type;
+ bool expected;
+ } test_data[] = {
+ {"text", true}, {"search", true},
+ {"tel", true}, {"url", true},
+ {"email", true}, {"password", true},
+ {"select", false}, {"", false},
+ {"checkbox", false}, {"random_string", false},
+ {"textarea", false},
+ };
+
+ for (const auto& test_case : test_data) {
+ FormFieldData data;
+ data.form_control_type = test_case.form_control_type;
+ EXPECT_EQ(test_case.expected, data.IsTextInputElement());
+ }
+}
+
} // namespace autofill
diff --git a/chromium/components/autofill/core/common/password_form.cc b/chromium/components/autofill/core/common/password_form.cc
index bb4b01c0265..a465d90cac8 100644
--- a/chromium/components/autofill/core/common/password_form.cc
+++ b/chromium/components/autofill/core/common/password_form.cc
@@ -67,12 +67,12 @@ void PasswordFormToJSON(const PasswordForm& form,
target->SetString("affiliated_web_realm", form.affiliated_web_realm);
target->SetString("app_display_name", form.app_display_name);
target->SetString("app_icon_url", form.app_icon_url.possibly_invalid_spec());
- target->SetBoolean("does_look_like_signup_form",
- form.does_look_like_signup_form);
std::ostringstream submission_event_string_stream;
submission_event_string_stream << form.submission_event;
target->SetString("submission_event", submission_event_string_stream.str());
target->SetBoolean("only_for_fallback_saving", form.only_for_fallback_saving);
+ target->SetBoolean("is_gaia_with_skip_save_password_form",
+ form.is_gaia_with_skip_save_password_form);
}
} // namespace
@@ -94,9 +94,9 @@ PasswordForm::PasswordForm()
was_parsed_using_autofill_predictions(false),
is_public_suffix_match(false),
is_affiliation_based_match(false),
- does_look_like_signup_form(false),
submission_event(SubmissionIndicatorEvent::NONE),
- only_for_fallback_saving(false) {}
+ only_for_fallback_saving(false),
+ is_gaia_with_skip_save_password_form(false) {}
PasswordForm::PasswordForm(const PasswordForm& other) = default;
@@ -150,9 +150,10 @@ bool PasswordForm::operator==(const PasswordForm& form) const {
affiliated_web_realm == form.affiliated_web_realm &&
app_display_name == form.app_display_name &&
app_icon_url == form.app_icon_url &&
- does_look_like_signup_form == form.does_look_like_signup_form &&
submission_event == form.submission_event &&
- only_for_fallback_saving == form.only_for_fallback_saving;
+ only_for_fallback_saving == form.only_for_fallback_saving &&
+ is_gaia_with_skip_save_password_form ==
+ form.is_gaia_with_skip_save_password_form;
}
bool PasswordForm::operator!=(const PasswordForm& form) const {
@@ -266,14 +267,6 @@ std::ostream& operator<<(
PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD:
os << "PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD";
break;
- case PasswordForm::SubmissionIndicatorEvent::
- FILLED_FORM_ON_START_PROVISIONAL_LOAD:
- os << "FILLED_FORM_ON_START_PROVISIONAL_LOAD";
- break;
- case PasswordForm::SubmissionIndicatorEvent::
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD:
- os << "FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD";
- break;
default:
os << "NO_SUBMISSION";
break;
diff --git a/chromium/components/autofill/core/common/password_form.h b/chromium/components/autofill/core/common/password_form.h
index f3f4ad357bf..76f0be0e876 100644
--- a/chromium/components/autofill/core/common/password_form.h
+++ b/chromium/components/autofill/core/common/password_form.h
@@ -98,8 +98,8 @@ struct PasswordForm {
MANUAL_SAVE,
DOM_MUTATION_AFTER_XHR,
PROVISIONALLY_SAVED_FORM_ON_START_PROVISIONAL_LOAD,
- FILLED_FORM_ON_START_PROVISIONAL_LOAD,
- FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD,
+ DEPRECATED_FILLED_FORM_ON_START_PROVISIONAL_LOAD, // unused
+ DEPRECATED_FILLED_INPUT_ELEMENTS_ON_START_PROVISIONAL_LOAD, // unused
SUBMISSION_INDICATOR_EVENT_COUNT
};
@@ -317,9 +317,6 @@ struct PasswordForm {
// found using affiliation-based match.
bool is_affiliation_based_match;
- // If true, this form looks like SignUp form according to local heuristics.
- bool does_look_like_signup_form;
-
// The type of the event that was taken as an indication that this form is
// being or has already been submitted. This field is not persisted and filled
// out only for submitted forms.
@@ -329,6 +326,9 @@ struct PasswordForm {
// fields were found). But this form can be saved only with the fallback.
bool only_for_fallback_saving;
+ // True iff this is Gaia form which should be skipped on saving.
+ bool is_gaia_with_skip_save_password_form;
+
// Return true if we consider this form to be a change password form.
// We use only client heuristics, so it could include signup forms.
bool IsPossibleChangePasswordForm() const;
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.cc b/chromium/components/autofill/core/common/password_form_fill_data.cc
index 5143e3f65f9..be1f4016818 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data.cc
@@ -35,7 +35,6 @@ void InitPasswordFormFillData(
const std::map<base::string16, const PasswordForm*>& matches,
const PasswordForm* const preferred_match,
bool wait_for_username_before_autofill,
- bool enable_other_possible_usernames,
PasswordFormFillData* result) {
// Note that many of the |FormFieldData| members are not initialized for
// |username_field| and |password_field| because they are currently not used
@@ -72,19 +71,6 @@ void InitPasswordFormFillData(
value.realm = it.second->signon_realm;
result->additional_logins[it.first] = value;
}
- if (enable_other_possible_usernames &&
- !it.second->other_possible_usernames.empty()) {
- // Note that there may be overlap between other_possible_usernames and
- // other saved usernames or with other other_possible_usernames. For now
- // we will ignore this overlap as it should be a rare occurence. We may
- // want to revisit this in the future.
- UsernamesCollectionKey key;
- key.username = it.first;
- key.password = it.second->password_value;
- if (it.second->is_public_suffix_match ||
- it.second->is_affiliation_based_match)
- key.realm = it.second->signon_realm;
- }
}
}
diff --git a/chromium/components/autofill/core/common/password_form_fill_data.h b/chromium/components/autofill/core/common/password_form_fill_data.h
index b7e8e27c0cd..e9c58d7b169 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data.h
+++ b/chromium/components/autofill/core/common/password_form_fill_data.h
@@ -59,13 +59,6 @@ struct PasswordFormFillData {
// A list of other matching username->PasswordAndRealm pairs for the form.
LoginCollection additional_logins;
- // A list of possible usernames in the case where we aren't completely sure
- // that the original saved username is correct. This data is keyed by the
- // saved username/password to ensure uniqueness, though the username is not
- // used.
- // TODO(crbug/188908). Remove |other_possible_usernames| or launch.
- UsernamesCollection other_possible_usernames;
-
// Tells us whether we need to wait for the user to enter a valid username
// before we autofill the password. By default, this is off unless the
// PasswordManager determined there is an additional risk associated with this
@@ -94,7 +87,6 @@ void InitPasswordFormFillData(
const std::map<base::string16, const PasswordForm*>& matches,
const PasswordForm* const preferred_match,
bool wait_for_username_before_autofill,
- bool enable_other_possible_usernames,
PasswordFormFillData* result);
// Renderer needs to have only a password that should be autofilled, all other
diff --git a/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc b/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc
index fd08e4f691e..883572c25cf 100644
--- a/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc
+++ b/chromium/components/autofill/core/common/password_form_fill_data_unittest.cc
@@ -54,7 +54,6 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
matches,
&preferred_match,
true,
- false,
&result);
// |wait_for_username| should reflect the |wait_for_username_before_autofill|
@@ -69,7 +68,6 @@ TEST(PasswordFormFillDataTest, TestSinglePreferredMatch) {
matches,
&preferred_match,
false,
- false,
&result2);
// |wait_for_username| should reflect the |wait_for_username_before_autofill|
@@ -149,7 +147,6 @@ TEST(PasswordFormFillDataTest, TestPublicSuffixDomainMatching) {
matches,
&preferred_match,
true,
- false,
&result);
EXPECT_TRUE(result.wait_for_username);
// The preferred realm should match the signon realm from the
@@ -227,7 +224,7 @@ TEST(PasswordFormFillDataTest, TestAffiliationMatch) {
PasswordFormFillData result;
InitPasswordFormFillData(form_on_page, matches, &preferred_match, false,
- false, &result);
+ &result);
EXPECT_FALSE(result.wait_for_username);
// The preferred realm should match the signon realm from the
// preferred match so the user can see where the result came from.
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.cc b/chromium/components/autofill/core/common/save_password_progress_logger.cc
index fd221d456e2..17f6da45b27 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.cc
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.cc
@@ -238,10 +238,6 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "|frame| is not the main frame";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME:
return "provisionally_saved_forms_[form_frame]";
- case SavePasswordProgressLogger::STRING_PASSWORD_FORM_FOUND_ON_PAGE:
- return "A password form found on the page";
- case SavePasswordProgressLogger::STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE:
- return "No password form found on the page";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD:
return "PasswordManager::ProvisionallySavePassword";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVE_PASSWORD_FORM:
@@ -268,8 +264,6 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Blocked password due to same origin but insecure scheme";
case SavePasswordProgressLogger::STRING_PROVISIONALLY_SAVED_FORM:
return "provisionally_saved_form";
- case SavePasswordProgressLogger::STRING_IGNORE_POSSIBLE_USERNAMES:
- return "Ignore other possible usernames";
case SavePasswordProgressLogger::STRING_ON_PASSWORD_FORMS_RENDERED_METHOD:
return "PasswordManager::OnPasswordFormsRendered";
case SavePasswordProgressLogger::STRING_ON_SAME_DOCUMENT_NAVIGATION:
@@ -422,6 +416,14 @@ std::string SavePasswordProgressLogger::GetStringFromID(
return "Generated password accepted";
case STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT:
return "Successful submission indicator event";
+ case STRING_MAIN_FRAME_ORIGIN:
+ return "Main frame origin";
+ case STRING_IS_FORM_TAG:
+ return "Form with form tag";
+ case STRING_FORM_PARSING_INPUT:
+ return "Form parsing input";
+ case STRING_FORM_PARSING_OUTPUT:
+ return "Form parsing output";
case SavePasswordProgressLogger::STRING_INVALID:
return "INVALID";
// Intentionally no default: clause here -- all IDs need to get covered.
diff --git a/chromium/components/autofill/core/common/save_password_progress_logger.h b/chromium/components/autofill/core/common/save_password_progress_logger.h
index 5e0679d8068..cb0523f4ac3 100644
--- a/chromium/components/autofill/core/common/save_password_progress_logger.h
+++ b/chromium/components/autofill/core/common/save_password_progress_logger.h
@@ -77,8 +77,6 @@ class SavePasswordProgressLogger {
STRING_DID_START_PROVISIONAL_LOAD_METHOD,
STRING_FRAME_NOT_MAIN_FRAME,
STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME,
- STRING_PASSWORD_FORM_FOUND_ON_PAGE,
- STRING_PASSWORD_FORM_NOT_FOUND_ON_PAGE,
STRING_PROVISIONALLY_SAVE_PASSWORD_METHOD,
STRING_PROVISIONALLY_SAVE_PASSWORD_FORM,
STRING_IS_SAVING_ENABLED,
@@ -92,7 +90,6 @@ class SavePasswordProgressLogger {
STRING_SYNC_CREDENTIAL,
STRING_BLOCK_PASSWORD_SAME_ORIGIN_INSECURE_SCHEME,
STRING_PROVISIONALLY_SAVED_FORM,
- STRING_IGNORE_POSSIBLE_USERNAMES,
STRING_ON_PASSWORD_FORMS_RENDERED_METHOD,
STRING_ON_SAME_DOCUMENT_NAVIGATION,
STRING_ON_ASK_USER_OR_SAVE_PASSWORD,
@@ -166,6 +163,10 @@ class SavePasswordProgressLogger {
STRING_GENERATION_RENDERER_SHOW_GENERATION_POPUP,
STRING_GENERATION_RENDERER_GENERATED_PASSWORD_ACCEPTED,
STRING_SUCCESSFUL_SUBMISSION_INDICATOR_EVENT,
+ STRING_MAIN_FRAME_ORIGIN,
+ STRING_IS_FORM_TAG,
+ STRING_FORM_PARSING_INPUT,
+ STRING_FORM_PARSING_OUTPUT,
STRING_INVALID, // Represents a string returned in a case of an error.
STRING_MAX = STRING_INVALID
};
diff --git a/chromium/components/autofill/ios/browser/BUILD.gn b/chromium/components/autofill/ios/browser/BUILD.gn
index 53cba6a9bb1..0371187bd64 100644
--- a/chromium/components/autofill/ios/browser/BUILD.gn
+++ b/chromium/components/autofill/ios/browser/BUILD.gn
@@ -36,6 +36,7 @@ source_set("browser") {
"//components/autofill/core/browser",
"//components/autofill/core/common",
"//components/prefs:prefs",
+ "//components/prefs/ios",
"//google_apis",
"//ios/web",
"//ui/gfx/geometry",
diff --git a/chromium/components/autofill/ios/browser/autofill_agent.mm b/chromium/components/autofill/ios/browser/autofill_agent.mm
index 2ecb512ff8f..43c90590c63 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent.mm
@@ -35,6 +35,8 @@
#include "components/autofill/ios/browser/autofill_util.h"
#import "components/autofill/ios/browser/form_suggestion.h"
#import "components/autofill/ios/browser/js_autofill_manager.h"
+#import "components/prefs/ios/pref_observer_bridge.h"
+#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "ios/web/public/url_scheme_util.h"
#include "ios/web/public/web_state/form_activity_params.h"
@@ -63,8 +65,7 @@ typedef void (^FetchFormsCompletionHandler)(BOOL, const FormDataVector&);
void GetFormAndField(autofill::FormData* form,
autofill::FormFieldData* field,
const FormDataVector& forms,
- const std::string& fieldIdentifier,
- const std::string& type) {
+ const std::string& fieldIdentifier) {
DCHECK_GE(forms.size(), 1U);
*form = forms[0];
const base::string16 fieldIdentifier16 = base::UTF8ToUTF16(fieldIdentifier);
@@ -88,7 +89,7 @@ void GetFormAndField(autofill::FormData* form,
} // namespace
-@interface AutofillAgent ()<CRWWebStateObserver>
+@interface AutofillAgent ()<CRWWebStateObserver, PrefObserverDelegate>
// Notifies the autofill manager when forms are detected on a page.
- (void)notifyAutofillManager:(autofill::AutofillManager*)autofillManager
@@ -116,14 +117,6 @@ void GetFormAndField(autofill::FormData* form,
pageURL:(const GURL&)pageURL
completionHandler:(FetchFormsCompletionHandler)completionHandler;
-// Processes the JSON form data extracted from the page when form activity is
-// detected and informs the AutofillManager.
-- (void)processFormActivityExtractedData:(const FormDataVector&)forms
- fieldName:(const std::string&)fieldName
- fieldIdentifier:(const std::string&)fieldIdentifier
- type:(const std::string&)type
- webState:(web::WebState*)webState;
-
// Returns whether Autofill is enabled by checking if Autofill is turned on and
// if the current URL has a web scheme and the page content is HTML.
- (BOOL)isAutofillEnabled;
@@ -193,6 +186,11 @@ void GetFormAndField(autofill::FormData* form,
// The autofill data that needs to be send when the |webState_| is shown.
// The string is in JSON format.
NSString* pendingFormJSON_;
+
+ // Bridge to listen to pref changes.
+ std::unique_ptr<PrefObserverBridge> prefObserverBridge_;
+ // Registrar for pref changes notifications.
+ PrefChangeRegistrar prefChangeRegistrar_;
}
- (instancetype)initWithPrefService:(PrefService*)prefService
@@ -206,6 +204,11 @@ void GetFormAndField(autofill::FormData* form,
webStateObserverBridge_ =
std::make_unique<web::WebStateObserverBridge>(self);
webState_->AddObserver(webStateObserverBridge_.get());
+ prefObserverBridge_ = std::make_unique<PrefObserverBridge>(self);
+ prefChangeRegistrar_.Init(prefService);
+ prefObserverBridge_->ObserveChangesForPreference(
+ autofill::prefs::kAutofillEnabled, &prefChangeRegistrar_);
+
jsAutofillManager_ = [[JsAutofillManager alloc]
initWithReceiver:webState_->GetJSInjectionReceiver()];
}
@@ -233,6 +236,9 @@ void GetFormAndField(autofill::FormData* form,
webStateObserverBridge_.reset();
webState_ = nullptr;
}
+
+ // Do not wait for deallocation. Remove all observers here.
+ prefChangeRegistrar_.RemoveAll();
}
#pragma mark -
@@ -370,8 +376,7 @@ void GetFormAndField(autofill::FormData* form,
autofill::FormFieldData field;
autofill::FormData form;
GetFormAndField(&form, &field, forms,
- base::SysNSStringToUTF8(fieldIdentifier),
- base::SysNSStringToUTF8(type));
+ base::SysNSStringToUTF8(fieldIdentifier));
// Save the completion and go look for suggestions.
suggestionsAvailableCompletion_ = [completion copy];
@@ -613,14 +618,13 @@ void GetFormAndField(autofill::FormData* form,
if (![self isAutofillEnabled])
return;
- // Returns early and reset the suggestion state if an error occurs.
- if (params.input_missing)
+ // Return early if the page is not processed yet.
+ if (!pageProcessed_)
return;
- // Processing the page can be needed here if Autofill is enabled in settings
- // when the page is already loaded, or if the user focuses a field before the
- // page is fully loaded.
- [self processPage:webState];
+ // Return early if |params| is not complete.
+ if (params.input_missing)
+ return;
web::URLVerificationTrustLevel trustLevel;
const GURL pageURL(webState->GetCurrentURL(&trustLevel));
@@ -628,35 +632,40 @@ void GetFormAndField(autofill::FormData* form,
// If the event is a form_changed, then the event concerns the whole page and
// not a particular form. The whole page need to be reparsed to find the new
// forms.
- if (params.type.compare("form_changed") == 0) {
+ if (params.type == "form_changed") {
[self scanFormsInPage:webState pageURL:pageURL];
return;
}
- // Blur not handled; we don't reset the suggestion state because if the
- // keyboard is about to be dismissed there's no point. If not it means the
- // next focus event will update the suggestion state within milliseconds, so
- // if we do it now a flicker will be seen.
- if (params.type.compare("blur") == 0)
+ // We are only interested in 'input' events in order to notify the autofill
+ // manager for metrics purposes.
+ if (params.type != "input" ||
+ (params.field_type != "text" && params.field_type != "password")) {
return;
+ }
- // Necessary so the strings can be used inside a block.
- std::string fieldNameCopy = params.field_name;
- std::string fieldIdentifierCopy = params.field_identifier;
- std::string typeCopy = params.type;
+ // Necessary so the string can be used inside the block.
+ std::string fieldIdentifier = params.field_identifier;
__weak AutofillAgent* weakSelf = self;
id completionHandler = ^(BOOL success, const FormDataVector& forms) {
- if (success && forms.size() == 1) {
- [weakSelf processFormActivityExtractedData:forms
- fieldName:fieldNameCopy
- fieldIdentifier:fieldIdentifierCopy
- type:typeCopy
- webState:webState];
- }
+ if (!success || forms.size() != 1)
+ return;
+
+ DCHECK_EQ(webState_, webState);
+ autofill::AutofillManager* autofillManager =
+ [weakSelf autofillManagerFromWebState:webState];
+ if (!autofillManager)
+ return;
+
+ autofill::FormFieldData field;
+ autofill::FormData form;
+ GetFormAndField(&form, &field, forms, fieldIdentifier);
+ autofillManager->OnTextFieldDidChange(form, field, gfx::RectF(),
+ base::TimeTicks::Now());
};
- // Re-extract the active form and field only. There is no minimum field
+ // Extract the active form and field only. There is no minimum field
// requirement because key/value suggestions are offered even on short forms.
[self fetchFormsFiltered:YES
withName:base::UTF8ToUTF16(params.form_name)
@@ -665,31 +674,20 @@ void GetFormAndField(autofill::FormData* form,
completionHandler:completionHandler];
}
-#pragma mark - Private methods.
+#pragma mark - PrefObserverDelegate
-- (void)processFormActivityExtractedData:(const FormDataVector&)forms
- fieldName:(const std::string&)fieldName
- fieldIdentifier:(const std::string&)fieldIdentifier
- type:(const std::string&)type
- webState:(web::WebState*)webState {
- DCHECK_EQ(webState_, webState);
- autofill::AutofillManager* autofillManager =
- [self autofillManagerFromWebState:webState];
- if (!autofillManager)
+- (void)onPreferenceChanged:(const std::string&)preferenceName {
+ if (preferenceName != autofill::prefs::kAutofillEnabled)
return;
- autofill::FormFieldData field;
- autofill::FormData form;
- GetFormAndField(&form, &field, forms, fieldIdentifier, type);
-
- // Tell the manager about the form activity (for metrics).
- if (type.compare("input") == 0 && (field.form_control_type == "text" ||
- field.form_control_type == "password")) {
- autofillManager->OnTextFieldDidChange(form, field, gfx::RectF(),
- base::TimeTicks::Now());
- }
+ // Processing the page can be needed here if Autofill is enabled in settings
+ // when the page is already loaded.
+ if ([self isAutofillEnabled])
+ [self processPage:webState_];
}
+#pragma mark - Private methods.
+
- (BOOL)isAutofillEnabled {
if (!prefService_->GetBoolean(autofill::prefs::kAutofillEnabled))
return NO;
@@ -728,32 +726,29 @@ void GetFormAndField(autofill::FormData* form,
}
- (void)onFormDataFilled:(const autofill::FormData&)form {
- std::unique_ptr<base::DictionaryValue> JSONForm(new base::DictionaryValue);
- JSONForm->SetString("formName", base::UTF16ToUTF8(form.name));
- // Note: Destruction of all child base::Value types is handled by the root
- // formData object on its own destruction.
- auto JSONFields = std::make_unique<base::DictionaryValue>();
-
- const std::vector<autofill::FormFieldData>& autofillFields = form.fields;
- for (const auto& autofillField : autofillFields) {
- if (JSONFields->HasKey(base::UTF16ToUTF8(autofillField.id)) &&
- autofillField.value.empty())
+ base::Value autofillData(base::Value::Type::DICTIONARY);
+ autofillData.SetKey("formName", base::Value(base::UTF16ToUTF8(form.name)));
+
+ base::Value fieldsData(base::Value::Type::DICTIONARY);
+ for (const auto& field : form.fields) {
+ // Skip empty fields and those that are not autofilled.
+ if (field.value.empty() || !field.is_autofilled)
continue;
- JSONFields->SetKey(base::UTF16ToUTF8(autofillField.id),
- base::Value(autofillField.value));
+
+ fieldsData.SetKey(base::UTF16ToUTF8(field.id), base::Value(field.value));
}
- JSONForm->Set("fields", std::move(JSONFields));
+ autofillData.SetKey("fields", std::move(fieldsData));
- // Stringify the JSON data and send it to the UIWebView-side fillForm method.
std::string JSONString;
- base::JSONWriter::Write(*JSONForm.get(), &JSONString);
- NSString* nsJSONString = base::SysUTF8ToNSString(JSONString);
+ base::JSONWriter::Write(autofillData, &JSONString);
+ // Store the form data when WebState is not visible, to send it as soon as it
+ // becomes visible again, e.g., when the CVC unmask prompt is showing.
if (!webState_->IsVisible()) {
- pendingFormJSON_ = nsJSONString;
+ pendingFormJSON_ = base::SysUTF8ToNSString(JSONString);
return;
}
- [self sendDataToWebState:nsJSONString];
+ [self sendDataToWebState:base::SysUTF8ToNSString(JSONString)];
}
- (void)sendDataToWebState:(NSString*)JSONData {
@@ -800,16 +795,16 @@ void GetFormAndField(autofill::FormData* form,
return;
}
- base::DictionaryValue predictionData;
+ base::Value predictionData(base::Value::Type::DICTIONARY);
for (const auto& form : forms) {
- auto formJSONData = std::make_unique<base::DictionaryValue>();
+ base::Value fieldData(base::Value::Type::DICTIONARY);
DCHECK(form.fields.size() == form.data.fields.size());
for (size_t i = 0; i < form.fields.size(); i++) {
- formJSONData->SetKey(base::UTF16ToUTF8(form.data.fields[i].id),
- base::Value(form.fields[i].overall_type));
+ fieldData.SetKey(base::UTF16ToUTF8(form.data.fields[i].id),
+ base::Value(form.fields[i].overall_type));
}
- predictionData.SetWithoutPathExpansion(base::UTF16ToUTF8(form.data.name),
- std::move(formJSONData));
+ predictionData.SetKey(base::UTF16ToUTF8(form.data.name),
+ std::move(fieldData));
}
std::string dataString;
base::JSONWriter::Write(predictionData, &dataString);
diff --git a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
index f4cda3f135c..05b985dc457 100644
--- a/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
+++ b/chromium/components/autofill/ios/browser/autofill_agent_unittests.mm
@@ -41,18 +41,28 @@ class AutofillAgentTests : public PlatformTest {
webState:&test_web_state_];
}
+ void TearDown() override {
+ [autofill_agent_ detachFromWebState];
+
+ PlatformTest::TearDown();
+ }
+
web::TestWebState test_web_state_;
- AutofillAgent* autofill_agent_;
std::unique_ptr<PrefService> prefs_;
+ AutofillAgent* autofill_agent_;
id mock_js_injection_receiver_;
DISALLOW_COPY_AND_ASSIGN(AutofillAgentTests);
};
+// Tests that form's name and fields' identifiers, values, and whether they are
+// autofilled are sent to the JS. Fields with empty values and those that are
+// not autofilled are skipped.
TEST_F(AutofillAgentTests, OnFormDataFilledTest) {
autofill::FormData form;
form.origin = GURL("https://myform.com");
form.action = GURL("https://myform.com/submit");
+ form.name = base::ASCIIToUTF16("CC form");
autofill::FormFieldData field;
field.form_control_type = "text";
@@ -60,23 +70,31 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTest) {
field.name = base::ASCIIToUTF16("number");
field.id = base::ASCIIToUTF16("number");
field.value = base::ASCIIToUTF16("number_value");
+ field.is_autofilled = true;
form.fields.push_back(field);
field.label = base::ASCIIToUTF16("Name on Card");
field.name = base::ASCIIToUTF16("name");
field.id = base::ASCIIToUTF16("name");
field.value = base::ASCIIToUTF16("name_value");
+ field.is_autofilled = true;
+ form.fields.push_back(field);
+ field.label = base::ASCIIToUTF16("Expiry Month");
+ field.name = base::ASCIIToUTF16("expiry_month");
+ field.id = base::ASCIIToUTF16("expiry_month");
+ field.value = base::ASCIIToUTF16("01");
+ field.is_autofilled = false;
form.fields.push_back(field);
field.label = base::ASCIIToUTF16("Unknown field");
field.name = base::ASCIIToUTF16("unknown");
field.id = base::ASCIIToUTF16("unknown");
field.value = base::ASCIIToUTF16("");
+ field.is_autofilled = true;
form.fields.push_back(field);
// Fields are in alphabetical order.
[[mock_js_injection_receiver_ expect]
executeJavaScript:
@"__gCrWeb.autofill.fillForm({\"fields\":{\"name\":\"name_value\","
- @"\"number\":\"number_value\",\"unknown\":\"\"},\"formName\":\"\"}, "
- @"\"\");"
+ @"\"number\":\"number_value\"},\"formName\":\"CC form\"}, \"\");"
completionHandler:[OCMArg any]];
[autofill_agent_ onFormDataFilled:form];
test_web_state_.WasShown();
@@ -84,33 +102,32 @@ TEST_F(AutofillAgentTests, OnFormDataFilledTest) {
EXPECT_OCMOCK_VERIFY(mock_js_injection_receiver_);
}
+// Tests that in the case of conflict in fields' identifiers, the last seen
+// value of a given field is used.
TEST_F(AutofillAgentTests, OnFormDataFilledWithNameCollisionTest) {
autofill::FormData form;
form.origin = GURL("https://myform.com");
form.action = GURL("https://myform.com/submit");
autofill::FormFieldData field;
- // Check that in case of conflict, the last value of a given field is used.
field.form_control_type = "text";
field.label = base::ASCIIToUTF16("State");
field.name = base::ASCIIToUTF16("region");
field.id = base::ASCIIToUTF16("region");
field.value = base::ASCIIToUTF16("California");
- form.fields.push_back(field);
- field.label = base::ASCIIToUTF16("Province");
- field.name = base::ASCIIToUTF16("region");
- field.id = base::ASCIIToUTF16("region");
- field.value = base::ASCIIToUTF16("");
+ field.is_autofilled = true;
form.fields.push_back(field);
field.label = base::ASCIIToUTF16("Other field");
field.name = base::ASCIIToUTF16("field1");
field.id = base::ASCIIToUTF16("field1");
field.value = base::ASCIIToUTF16("value 1");
+ field.is_autofilled = true;
form.fields.push_back(field);
field.label = base::ASCIIToUTF16("Other field");
field.name = base::ASCIIToUTF16("field1");
field.id = base::ASCIIToUTF16("field1");
field.value = base::ASCIIToUTF16("value 2");
+ field.is_autofilled = true;
form.fields.push_back(field);
// Fields are in alphabetical order.
[[mock_js_injection_receiver_ expect]
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.h b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
index febf00c0a70..a39cbc34c76 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.h
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.h
@@ -46,7 +46,7 @@ class AutofillDriverIOS : public AutofillDriver,
const std::vector<autofill::FormStructure*>& forms) override;
void SendAutofillTypePredictionsToRenderer(
const std::vector<FormStructure*>& forms) override;
- void RendererShouldClearFilledForm() override;
+ void RendererShouldClearFilledSection() override;
void RendererShouldClearPreviewedForm() override;
void RendererShouldAcceptDataListSuggestion(
const base::string16& value) override;
diff --git a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
index 6d1e612f5f1..d94e80e6bd8 100644
--- a/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
+++ b/chromium/components/autofill/ios/browser/autofill_driver_ios.mm
@@ -91,8 +91,7 @@ void AutofillDriverIOS::DidInteractWithCreditCardForm() {
}
}
-void AutofillDriverIOS::RendererShouldClearFilledForm() {
-}
+void AutofillDriverIOS::RendererShouldClearFilledSection() {}
void AutofillDriverIOS::RendererShouldClearPreviewedForm() {
}
diff --git a/chromium/components/autofill/ios/browser/resources/autofill_controller.js b/chromium/components/autofill/ios/browser/resources/autofill_controller.js
index 326d8c8c6e0..5bb6f60d0ea 100644
--- a/chromium/components/autofill/ios/browser/resources/autofill_controller.js
+++ b/chromium/components/autofill/ios/browser/resources/autofill_controller.js
@@ -17,6 +17,15 @@
*/
goog.provide('__crWeb.autofill');
+/**
+ * The autofill data for a form.
+ * @typedef {{
+ * formName: string,
+ * fields: !Object<string, string>,
+ * }}
+ */
+var FormData;
+
/* Beginning of anonymous object. */
(function() {
@@ -223,13 +232,22 @@ __gCrWeb.autofill['fillActiveFormField'] = function(data) {
__gCrWeb.autofill.fillFormField(data, activeElement);
};
+// Remove Autofill styling when control element is edited by the user.
+function controlElementInputListener_(evt) {
+ if (evt.isTrusted) {
+ evt.target.removeAttribute('chrome-autofilled');
+ evt.target.isAutofilled = false;
+ evt.target.removeEventListener('input', controlElementInputListener_);
+ }
+};
+
/**
* Fills a number of fields in the same named form for full-form Autofill.
* Applies Autofill CSS (i.e. yellow background) to filled elements.
* Only empty fields will be filled, except that field named
* |forceFillFieldName| will always be filled even if non-empty.
*
- * @param {Object} data Dictionary of data to fill in.
+ * @param {!FormData} data Autofill data to fill in.
* @param {string} forceFillFieldIdentifier Identified field will always be
* filled even if non-empty. May be null.
*/
@@ -246,67 +264,53 @@ __gCrWeb.autofill['fillForm'] = function(data, forceFillFieldIdentifier) {
__gCrWeb.autofill.styleInjected = true;
}
- // Remove Autofill styling when control element is edited by the user.
- var controlElementInputListener = function(evt) {
- if (evt.isTrusted) {
- evt.target.removeAttribute('chrome-autofilled');
- evt.target.isAutofilled = false;
- evt.target.removeEventListener('input', controlElementInputListener);
- }
- };
-
var form = __gCrWeb.form.getFormElementFromIdentifier(data.formName);
- var controlElements = [];
- if (form) {
- controlElements = __gCrWeb.form.getFormControlElements(form);
- } else {
- var fieldsets = [];
- controlElements =
- getUnownedAutofillableFormFieldElements_(document.all, fieldsets);
- }
- var delay = 0;
- for (var i = 0; i < controlElements.length; ++i) {
+ var controlElements = form ?
+ __gCrWeb.form.getFormControlElements(form) :
+ getUnownedAutofillableFormFieldElements_(document.all, /*fieldsets=*/[]);
+
+ for (var i = 0, delay = 0; i < controlElements.length;
+ ++i, delay += __gCrWeb.autofill.delayBetweenFieldFillingMs) {
var element = controlElements[i];
- if (!__gCrWeb.fill.isAutofillableElement(element)) {
+ if (!__gCrWeb.fill.isAutofillableElement(element))
continue;
- }
+
+ // TODO(crbug.com/836013): Investigate autofilling checkable elements.
+ if (__gCrWeb.fill.isCheckableElement(element))
+ continue;
+
+ // Skip fields if autofill data is missing.
var fieldIdentifier = __gCrWeb.form.getFieldIdentifier(element);
+ var value = data.fields[fieldIdentifier];
+ if (!value)
+ continue;
- // Skip non-empty fields unless this is the forceFillFieldName or it's a
- // 'select-one' element. 'select-one' elements are always autofilled even
- // if non-empty; see AutofillManager::FillOrPreviewDataModelForm().
+ // Skip non-empty fields unless:
+ // a) The element's identifier matches |forceFillFieldIdentifier|; or
+ // b) The element is a 'select-one' element. 'select-one' elements are
+ // always autofilled; see AutofillManager::FillOrPreviewDataModelForm().
+ // c) The "value" or "placeholder" attributes match the value, if any; or
if (element.value &&
!__gCrWeb.autofill.sanitizedFieldIsEmpty(element.value) &&
+ fieldIdentifier !== forceFillFieldIdentifier &&
!__gCrWeb.fill.isSelectElement(element) &&
- fieldIdentifier !== forceFillFieldIdentifier) {
+ !((element.hasAttribute('value') &&
+ element.getAttribute('value') == element.value) ||
+ (element.hasAttribute('placeholder') &&
+ element.getAttribute('placeholder').toLowerCase() ==
+ element.value.toLowerCase()))) {
continue;
}
- // Don't fill field if source value is empty or missing.
- var value = data.fields[fieldIdentifier];
- if (!value) continue;
-
- if (__gCrWeb.fill.isTextInput(element) ||
- __gCrWeb.fill.isTextAreaElement(element) ||
- __gCrWeb.fill.isSelectElement(element)) {
- (function(_element, _value, _delay) {
- window.setTimeout(function() {
- __gCrWeb.fill.setInputElementValue(
- _value, _element, function(changed) {
- if (!changed)
- return;
- _element.setAttribute('chrome-autofilled', '');
- _element.isAutofilled = true;
- _element.addEventListener('input', controlElementInputListener);
- });
- }, _delay);
- })(element, value, delay);
- delay = delay + __gCrWeb.autofill.delayBetweenFieldFillingMs;
- } else if (__gCrWeb.fill.isCheckableElement(element)) {
- // TODO(bondd): Handle __gCrWeb.fill.isCheckableElement(element) ==
- // true. |is_checked| is not currently passed in by the caller.
- }
-
+ (function(_element, _value, _delay) {
+ window.setTimeout(function() {
+ __gCrWeb.fill.setInputElementValue(_value, _element, function() {
+ _element.setAttribute('chrome-autofilled', '');
+ _element.isAutofilled = true;
+ _element.addEventListener('input', controlElementInputListener_);
+ });
+ }, _delay);
+ })(element, value, delay);
}
if (form) {
@@ -325,31 +329,29 @@ __gCrWeb.autofill['fillForm'] = function(data, forceFillFieldIdentifier) {
}
};
+// TODO(crbug.com/816941): Clear should only clear the current section and not
+// the whole form.
/**
- * Clear autofilled fields of the specified form. Fields that are not currently
- * autofilled are not modified.
+ * Clear autofilled fields of the specified form section. Fields that are not
+ * currently autofilled are not modified.
* Field contents are cleared, and Autofill flag and styling are removed.
* 'change' events are sent for fields whose contents changed.
- * Based on FormCache::ClearFormWithElement().
+ * Based on FormCache::ClearSectionWithElement().
*
* @param {string} formName Identifier for form element (from
* getFormIdentifier).
*/
__gCrWeb.autofill['clearAutofilledFields'] = function(formName) {
var form = __gCrWeb.form.getFormElementFromIdentifier(formName);
- var controlElements = [];
- if (form) {
- controlElements = __gCrWeb.form.getFormControlElements(form);
- } else {
- var fieldsets = [];
- controlElements =
- getUnownedAutofillableFormFieldElements_(document.all, fieldsets);
- }
- var delay = 0;
+ var controlElements = form ?
+ __gCrWeb.form.getFormControlElements(form) :
+ getUnownedAutofillableFormFieldElements_(document.all, /*fieldsets=*/[]);
- for (var i = 0; i < controlElements.length; ++i) {
+ for (var i = 0, delay = 0; i < controlElements.length;
+ ++i, delay += __gCrWeb.autofill.delayBetweenFieldFillingMs) {
var element = controlElements[i];
- if (!element.isAutofilled || element.disabled) continue;
+ if (!element.isAutofilled || element.disabled)
+ continue;
var value = null;
if (__gCrWeb.fill.isTextInput(element) ||
@@ -360,8 +362,7 @@ __gCrWeb.autofill['clearAutofilledFields'] = function(formName) {
// TODO(bondd): Store initial values and reset to the correct one here.
value = element.options[0].value;
} else if (__gCrWeb.fill.isCheckableElement(element)) {
- // TODO(bondd): Handle checkable elements. They aren't properly supported
- // by iOS Autofill yet.
+ // TODO(crbug.com/836013): Investigate autofilling checkable elements.
}
if (value !== null) {
(function(_element, _value, _delay) {
@@ -371,11 +372,10 @@ __gCrWeb.autofill['clearAutofilledFields'] = function(formName) {
_element.removeAttribute('chrome-autofilled');
_element.isAutofilled = false;
_element.removeEventListener(
- 'input', controlElementInputListener);
+ 'input', controlElementInputListener_);
});
}, _delay);
})(element, value, delay);
- delay = delay + __gCrWeb.autofill.delayBetweenFieldFillingMs;
}
}
};
@@ -415,8 +415,8 @@ __gCrWeb.autofill.extractNewForms = function(
/** @type {HTMLCollection} */
var webForms = document.forms;
- var extractMask = __gCrWeb.fill.EXTRACT_MASK_VALUE |
- __gCrWeb.fill.EXTRACT_MASK_OPTIONS;
+ var extractMask =
+ __gCrWeb.fill.EXTRACT_MASK_VALUE | __gCrWeb.fill.EXTRACT_MASK_OPTIONS;
var numFieldsSeen = 0;
for (var formIndex = 0; formIndex < webForms.length; ++formIndex) {
/** @type {HTMLFormElement} */
@@ -703,7 +703,7 @@ __gCrWeb.autofill['sanitizedFieldIsEmpty'] = function(value) {
// Some sites enter values such as ____-____-____-____ or (___)-___-____ in
// their fields. Check if the field value is empty after the removal of the
// formatting characters.
- return __gCrWeb.common.trim(value.replace(/[-_()/|]/g,'')) == '';
- };
+ return __gCrWeb.common.trim(value.replace(/[-_()/|]/g, '')) == '';
+};
}()); // End of anonymous object
diff --git a/chromium/components/autofill/ios/fill/fill_js_unittest.mm b/chromium/components/autofill/ios/fill/fill_js_unittest.mm
index 65b0b16331c..c3d22a6f313 100644
--- a/chromium/components/autofill/ios/fill/fill_js_unittest.mm
+++ b/chromium/components/autofill/ios/fill/fill_js_unittest.mm
@@ -58,7 +58,6 @@ TEST_F(FillJsTest, GetCanonicalActionForForm) {
LoadHtmlAndInject(html);
id result = ExecuteJavaScript(
@"__gCrWeb.fill.getCanonicalActionForForm(document.body.children[0])");
- // [NSThread sleepForTimeInterval:10000];
NSString* base_url = base::SysUTF8ToNSString(BaseUrl());
NSString* expected_action =
[data.expected_action stringByReplacingOccurrencesOfString:@"baseurl/"
diff --git a/chromium/components/autofill/ios/fill/form_unittest.mm b/chromium/components/autofill/ios/fill/form_unittest.mm
index a072e31249b..4bf728d5108 100644
--- a/chromium/components/autofill/ios/fill/form_unittest.mm
+++ b/chromium/components/autofill/ios/fill/form_unittest.mm
@@ -30,18 +30,42 @@ class FormJsTest : public web::WebJsTest<web::WebTestWithWebState> {
std::make_unique<FormTestClient>()) {}
};
-// Tests that keyup event correctly delivered to WebStateObserver.
-TEST_F(FormJsTest, KeyUpEvent) {
+// Tests that keyup event correctly delivered to WebStateObserver if the element
+// is focused.
+TEST_F(FormJsTest, KeyUpEventFocused) {
web::TestWebStateObserver observer(web_state());
- LoadHtml(@"<p></p>");
+ LoadHtml(@"<p><input id='test'/></p>");
ASSERT_FALSE(observer.form_activity_info());
- ExecuteJavaScript(@"document.dispatchEvent(new KeyboardEvent('keyup'));");
+ ExecuteJavaScript(
+ @"var e = document.getElementById('test');"
+ "e.focus();"
+ "var ev = new KeyboardEvent('keyup', {bubbles:true});"
+ "e.dispatchEvent(ev);");
+ web::TestWebStateObserver* block_observer = &observer;
+ WaitForCondition(^bool {
+ return block_observer->form_activity_info() != nullptr;
+ });
web::TestFormActivityInfo* info = observer.form_activity_info();
ASSERT_TRUE(info);
EXPECT_EQ("keyup", info->form_activity.type);
EXPECT_FALSE(info->form_activity.input_missing);
}
+// Tests that keyup event is not delivered to WebStateObserver if the element is
+// not focused.
+TEST_F(FormJsTest, KeyUpEventNotFocused) {
+ web::TestWebStateObserver observer(web_state());
+ LoadHtml(@"<p><input id='test'/></p>");
+ ASSERT_FALSE(observer.form_activity_info());
+ ExecuteJavaScript(
+ @"var e = document.getElementById('test');"
+ "var ev = new KeyboardEvent('keyup', {bubbles:true});"
+ "e.dispatchEvent(ev);");
+ WaitForBackgroundTasks();
+ web::TestFormActivityInfo* info = observer.form_activity_info();
+ ASSERT_FALSE(info);
+}
+
// Tests that focus event correctly delivered to WebStateObserver.
TEST_F(FormJsTest, FocusMainFrame) {
web::TestWebStateObserver observer(web_state());
@@ -52,6 +76,10 @@ TEST_F(FormJsTest, FocusMainFrame) {
"</form>");
ASSERT_FALSE(observer.form_activity_info());
ExecuteJavaScript(@"document.getElementById('id1').focus();");
+ web::TestWebStateObserver* block_observer = &observer;
+ WaitForCondition(^bool {
+ return block_observer->form_activity_info() != nullptr;
+ });
web::TestFormActivityInfo* info = observer.form_activity_info();
ASSERT_TRUE(info);
EXPECT_EQ("focus", info->form_activity.type);
@@ -88,6 +116,10 @@ TEST_F(FormJsTest, FocusSameOriginIFrame) {
ExecuteJavaScript(
@"document.getElementById('frame1').contentDocument.getElementById('id1')"
@".focus()");
+ web::TestWebStateObserver* block_observer = &observer;
+ WaitForCondition(^bool {
+ return block_observer->form_activity_info() != nullptr;
+ });
web::TestFormActivityInfo* info = observer.form_activity_info();
ASSERT_TRUE(info);
EXPECT_EQ("focus", info->form_activity.type);
diff --git a/chromium/components/autofill/ios/fill/resources/fill.js b/chromium/components/autofill/ios/fill/resources/fill.js
index 28ee9065532..0baae455648 100644
--- a/chromium/components/autofill/ios/fill/resources/fill.js
+++ b/chromium/components/autofill/ios/fill/resources/fill.js
@@ -191,8 +191,8 @@ function setInputElementAngularValue_(value, input) {
}
/**
- * Sets the value of an input and dispatches a change event if
- * |shouldSendChangeEvent|.
+ * Sets the value of an input, dispatches the events on the changed element and
+ * call |callback| if it is defined.
*
* It is based on the logic in
*
@@ -207,43 +207,119 @@ function setInputElementAngularValue_(value, input) {
*
* @param {string} value The value the input element will be set.
* @param {Element} input The input element of which the value is set.
- * @param {function(boolean)=} callback Callback function with a boolean
+ * @param {function()=} callback Callback function with a boolean
* argument that indicates if the input element's value was changed.
*/
__gCrWeb.fill.setInputElementValue = function(
value, input, callback = undefined) {
- if (!input) {
+ if (!input)
return;
+
+ var activeElement = document.activeElement;
+ if (input != activeElement) {
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ activeElement, value, 'blur', true, false);
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ input, value, 'focus', true, false);
}
- var changed = false;
- if (input.type === 'checkbox' || input.type === 'radio') {
- changed = input.checked !== value;
- input.checked = value;
- } else if (input.type === 'select-one') {
- changed = input.value !== value;
- input.value = value;
- } else {
+
+ setInputElementValue_(value, input);
+ if (callback)
+ callback();
+
+ if (input != activeElement) {
+ __gCrWeb.fill.createAndDispatchHTMLEvent(input, value, 'blur', true, false);
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ activeElement, value, 'focus', true, false);
+ }
+};
+
+/**
+ * Internal function to set the element value.
+ *
+ * @param {string} value The value the input element will be set.
+ * @param {Element} input The input element of which the value is set.
+ */
+function setInputElementValue_(value, input) {
+ var propertyName = (input.type === 'checkbox' || input.type === 'radio') ?
+ 'checked' :
+ 'value';
+ if (input.type !== 'select-one' && input.type !== 'checkbox' &&
+ input.type !== 'radio') {
// In HTMLInputElement.cpp there is a check on canSetValue(value), which
// returns false only for file input. As file input is not relevant for
// autofill and this method is only used for autofill for now, there is no
// such check in this implementation.
- var sanitizedValue =
- __gCrWeb.fill.sanitizeValueForInputElement(value, input);
- changed = sanitizedValue !== input.value;
- input.value = sanitizedValue;
+ value = __gCrWeb.fill.sanitizeValueForInputElement(value, input);
}
+
+ // Return early if the value hasn't changed.
+ if (input[propertyName] == value)
+ return;
+
+ // When the user inputs a value in an HTMLInput field, the property setter is
+ // not called. The different frameworks often call it explicitly when
+ // receiving the input event.
+ // This is probably due to the sync between the HTML object and the DOM
+ // object.
+ // The sequence of event is: User input -> input event -> setter.
+ // When the property is set programmatically (input.value = 'foo'), the setter
+ // is called immediately (then probably called again on the input event)
+ // JS input -> setter.
+ // The only way to emulate the user behavior is to override the property
+ // The getter will return the new value to emulate the fact the the HTML
+ // value was updated without calling the setter.
+ // The setter simply forwards the set to the older property descriptor.
+ // Once the setter has been called, just forward get and set calls.
+
+ var oldPropertyDescriptor = /** @type {!Object} */ (
+ Object.getOwnPropertyDescriptor(input, propertyName));
+ var overrideProperty =
+ oldPropertyDescriptor && oldPropertyDescriptor.configurable;
+ var setterCalled = false;
+
+ if (overrideProperty) {
+ var newProperty = {
+ get: function() {
+ if (setterCalled && oldPropertyDescriptor.get) {
+ return oldPropertyDescriptor.get.call(input);
+ }
+ // Simulate the fact that the HTML value has been set but not yet the
+ // property.
+ return value + '';
+ },
+ configurable: true
+ };
+ if (oldPropertyDescriptor.set) {
+ newProperty.set = function(e) {
+ setterCalled = true;
+ oldPropertyDescriptor.set.call(input, value);
+ }
+ }
+ Object.defineProperty(input, propertyName, newProperty);
+ } else {
+ setterCalled = true;
+ input[propertyName] = value;
+ }
+
if (window['angular']) {
// The page uses the AngularJS framework. Update the angular value before
// sending events.
setInputElementAngularValue_(value, input);
}
- if (changed) {
- __gCrWeb.fill.notifyElementValueChanged(input);
- }
- if (callback) {
- callback(changed);
+ __gCrWeb.fill.notifyElementValueChanged(input, value);
+
+ if (overrideProperty) {
+ Object.defineProperty(input, propertyName, oldPropertyDescriptor);
+ if (!setterCalled && input[propertyName] != value) {
+ // The setter was never called. This may be intentional (the framework
+ // ignored the input event) or not (the event did not conform to what
+ // framework expected). The whole function will likely fail, but try to
+ // set the value directly as a last try.
+ input[propertyName] = value;
+ }
}
-};
+}
/**
* Returns a sanitized value of proposedValue for a given input element type.
@@ -384,15 +460,23 @@ __gCrWeb.fill.sanitizeValueForNumberInputType = function(proposedValue) {
/**
* Creates and sends notification that element has changed.
*
- * Most handlers react to 'change' or 'input' event, so sent both.
+ * Send events that 'mimic' the user typing in a field.
+ * 'input' event is often use in case of a text field, and 'change'event is
+ * more often used in case of selects.
*
* @param {Element} element The element that changed.
*/
-__gCrWeb.fill.notifyElementValueChanged = function(element) {
- __gCrWeb.fill.createAndDispatchHTMLEvent(element, 'keydown', true, false);
- __gCrWeb.fill.createAndDispatchHTMLEvent(element, 'change', true, false);
- __gCrWeb.fill.createAndDispatchHTMLEvent(element, 'input', true, false);
- __gCrWeb.fill.createAndDispatchHTMLEvent(element, 'keyup', true, false);
+__gCrWeb.fill.notifyElementValueChanged = function(element, value) {
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ element, value, 'keydown', true, false);
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ element, value, 'keypress', true, false);
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ element, value, 'input', true, false);
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ element, value, 'keyup', true, false);
+ __gCrWeb.fill.createAndDispatchHTMLEvent(
+ element, value, 'change', true, false);
};
/**
@@ -406,30 +490,25 @@ __gCrWeb.fill.notifyElementValueChanged = function(element) {
* canceled.
*/
__gCrWeb.fill.createAndDispatchHTMLEvent = function(
- element, type, bubbles, cancelable) {
- var changeEvent =
- /** @type {!Event} */ (element.ownerDocument.createEvent('HTMLEvents'));
- changeEvent.initEvent(type, bubbles, cancelable);
- // Some frameworks will use the data field to update their cache value.
- changeEvent.data = element.value;
-
- // Adding a |simulated| flag on the event will force the React framework to
- // update the backend store.
- changeEvent.simulated = true;
-
- element.dispatchEvent(changeEvent);
+ element, value, type, bubbles, cancelable) {
+ var event =
+ new Event(type, {bubbles: bubbles, cancelable: cancelable, data: value});
+ if (type == 'input') {
+ event.inputType = 'insertText';
+ }
+ element.dispatchEvent(event);
};
- /**
- * Returns a canonical action for |formElement|. It works the same as upstream
- * function GetCanonicalActionForForm.
- * @param {HTMLFormElement} formElement
- * @return {string} Canonical action.
- */
+/**
+ * Returns a canonical action for |formElement|. It works the same as upstream
+ * function GetCanonicalActionForForm.
+ * @param {HTMLFormElement} formElement
+ * @return {string} Canonical action.
+ */
__gCrWeb.fill.getCanonicalActionForForm = function(formElement) {
- var rawAction = formElement.getAttribute('action') || "";
- var absoluteUrl = __gCrWeb.common.absoluteURL(
- formElement.ownerDocument, rawAction);
+ var rawAction = formElement.getAttribute('action') || '';
+ var absoluteUrl =
+ __gCrWeb.common.absoluteURL(formElement.ownerDocument, rawAction);
return __gCrWeb.common.removeQueryAndReferenceFromURL(absoluteUrl);
};
diff --git a/chromium/components/autofill/ios/fill/resources/form.js b/chromium/components/autofill/ios/fill/resources/form.js
index cb41ac7db49..e3e717a1a8e 100644
--- a/chromium/components/autofill/ios/fill/resources/form.js
+++ b/chromium/components/autofill/ios/fill/resources/form.js
@@ -59,6 +59,16 @@ __gCrWeb.form.formMutationObserver = null;
__gCrWeb.form.formMutationMessageToSend = null;
/**
+ * A message scheduled to be sent to host on the next runloop.
+ */
+__gCrWeb.form.messageToSend = null;
+
+/**
+ * The last HTML element that was focused by the user.
+ */
+__gCrWeb.form.lastFocusedElement = null;
+
+/**
* Based on Element::isFormControlElement() (WebKit)
* @param {Element} element A DOM element.
* @return {boolean} true if the |element| is a form control element.
@@ -287,31 +297,55 @@ __gCrWeb.form.getFormElementFromIdentifier = function(name) {
return null;
};
-
+/**
+ * Schedule |mesg| to be sent on next runloop.
+ * If called multiple times on the same runloop, only the last message is really
+ * sent.
+ */
+var sendMessageOnNextLoop_ = function(mesg) {
+ if (!__gCrWeb.form.messageToSend) {
+ setTimeout(function() {
+ __gCrWeb.message.invokeOnHost(__gCrWeb.form.messageToSend);
+ __gCrWeb.form.messageToSend = null;
+ }, 0);
+ }
+ __gCrWeb.form.messageToSend = mesg;
+}
/**
- * Focus and input events for form elements are messaged to the main
- * application for broadcast to WebStateObservers.
+ * Focus, input, change, keyup and blur events for form elements (form and input
+ * elements) are messaged to the main application for broadcast to
+ * WebStateObservers.
+ * Events will be included in a message to be sent in a future runloop (without
+ * delay). If an event is already scheduled to be sent, it is replaced by |evt|.
+ * Notably, 'blur' event will not be transmitted to the main application if they
+ * are triggered by the focus of another element as the 'focus' event will
+ * replace it.
+ * Only the events targetting the active element (or the previously active in
+ * case of 'blur') are sent to the main application.
* This is done with a single event handler for each type being added to the
* main document element which checks the source element of the event; this
* is much easier to manage than adding handlers to individual elements.
* @private
*/
var formActivity_ = function(evt) {
- var srcElement = evt.srcElement;
- var value = srcElement.value || '';
- var fieldType = srcElement.type || '';
-
+ var target = evt.target;
+ var value = target.value || '';
+ var fieldType = target.type || '';
+ if (evt.type != 'blur') {
+ __gCrWeb.form.lastFocusedElement = document.activeElement;
+ }
+ if (target != __gCrWeb.form.lastFocusedElement) return;
var msg = {
'command': 'form.activity',
- 'formName': __gCrWeb.form.getFormIdentifier(evt.srcElement.form),
- 'fieldName': __gCrWeb.form.getFieldName(srcElement),
- 'fieldIdentifier': __gCrWeb.form.getFieldIdentifier(srcElement),
+ 'formName': __gCrWeb.form.getFormIdentifier(evt.target.form),
+ 'fieldName': __gCrWeb.form.getFieldName(target),
+ 'fieldIdentifier': __gCrWeb.form.getFieldIdentifier(target),
'fieldType': fieldType,
'type': evt.type,
'value': value
};
- __gCrWeb.message.invokeOnHost(msg);
+ sendMessageOnNextLoop_(msg);
};
/**
diff --git a/chromium/components/autofill_strings.grdp b/chromium/components/autofill_strings.grdp
index 472e76d126e..2de9b8c9cce 100644
--- a/chromium/components/autofill_strings.grdp
+++ b/chromium/components/autofill_strings.grdp
@@ -20,12 +20,6 @@
<message name="IDS_AUTOFILL_WARNING_INSECURE_CONNECTION" desc="Warning text to show when credit card autofill is disabled because the website is not using a secure connection.">
Automatic credit card filling is disabled because this form does not use a secure connection.
</message>
- <message name="IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE" desc="The text displayed with http bad warning message in the Autofill popup to direct the user to the Chrome security connection help center page.">
- Learn more
- </message>
- <message name="IDS_AUTOFILL_CREDIT_CARD_HTTP_WARNING_MESSAGE" desc="Chrome can help the user fill credit card web forms by showing a pop-up with text suggestions next to a focused credit card text field. If the form is on an insecure site (e.g., http://), this text is shown on top of those suggestions.">
- Payment not secure
- </message>
<message name="IDS_AUTOFILL_CREDIT_CARD_SIGNIN_PROMO" desc="Promo text shown alongside credit card suggestions to get people to sign in.">
To use cards from your Google Account, sign in to Chrome
</message>
@@ -132,6 +126,22 @@
Autofill settings
</message>
+ <message name="IDS_AUTOFILL_MANAGE" desc="The text displayed at the bottom of the Autofill popup to allow the user to manage their Autofill preferences for addresses, credit cards, and passwords. Imperative. When the user clicks on it, opens the Autofill settings page." meaning="Manage addresses, credit cards and passwords in the user profile that can be used by Chrome Autofill.">
+ Manage...
+ </message>
+
+ <message name="IDS_AUTOFILL_MANAGE_ADDRESSES" desc="The text displayed at the bottom of the Autofill popup to allow the user to manage their Autofill preferences for addresses. Imperative. When the user clicks on it, opens the Autofill settings page." meaning="Manage addresses in the user profile that can be used by Chrome Autofill.">
+ Manage addresses...
+ </message>
+
+ <message name="IDS_AUTOFILL_MANAGE_PAYMENT_METHODS" desc="The text displayed at the bottom of the Autofill popup to allow the user to manage their Autofill preferences for payment methods like credit cards/debit cards. Imperative. When the user clicks on it, opens the Autofill settings page." meaning="Manage the payment methods in the user profile that can be used by Chrome Autofill.">
+ Manage payment methods...
+ </message>
+
+ <message name="IDS_AUTOFILL_MANAGE_PASSWORDS" desc="The text displayed at the bottom of the Autofill popup to allow the user to manage passwords that can be used by Chrome Autofill. Imperative. When the user clicks on it, opens the Passwords section of the Settings page." meaning="Manage passwords in the user profile that can be used by Chrome Autofill.">
+ Manage passwords...
+ </message>
+
<message name="IDS_AUTOFILL_OPTIONS_CONTENT_DESCRIPTION" desc="The text verbalised by a screen reader for the button that directs the user to the Autofill settings UI. This string is not displayed.">
settings
</message>
@@ -144,9 +154,6 @@
Use password for:
</message>
- <message name="IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE" desc="Chrome can help the user fill login web forms by showing a pop-up with text suggestions next to a focused text field. If the form is on an insecure site (e.g., http://), this text is shown on top of those suggestions.">
- Login not secure
- </message>
<if expr="not use_titlecase">
<message name="IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK" desc="The text shown as an option in the suggestion drop down when a password field is clicked">
Show all saved passwords
@@ -188,16 +195,6 @@
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CONFIRM" desc="Text to show for the Autofill upload save credit card prompt accept button when more information (e.g., CVC) was needed in order to save the card and was entered.">
Confirm
</message>
- <if expr="_google_chrome">
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
- Do you want Chrome to save this card?
- </message>
- </if>
- <if expr="not _google_chrome">
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
- Do you want Chromium to save this card?
- </message>
- </if>
<if expr="is_linux and not chromeos">
<then>
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
@@ -240,12 +237,6 @@
</message>
</else>
</if>
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_TITLE" desc="Title text to show for the Autofill upload save credit card prompt when more information (e.g., CVC) is needed in order to save the card.">
- Confirm security code
- </message>
- <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_ENTER_CVC_EXPLANATION" desc="Text displayed in the Autofill save credit card prompt requesting the additional CVC information needed in order to save the card to Google Payments. It will display the network and last four digits of the card to be saved.">
- Enter the security code for <ph name="CREDIT_CARD">$1<ex>Visa ****5678</ex></ph>. This code won't be saved.
- </message>
<!-- Autofill credit card suggestion popup -->
<message name="IDS_AUTOFILL_CREDIT_CARD_EXPIRATION_DATE_ABBR" desc="Abbreviated label for credit card expiration date. [CHAR-LIMIT=32]">
diff --git a/chromium/components/autofill_strings_grdp/OWNERS b/chromium/components/autofill_strings_grdp/OWNERS
new file mode 100644
index 00000000000..50a21bb6ec6
--- /dev/null
+++ b/chromium/components/autofill_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/autofill/OWNERS
diff --git a/chromium/components/autofill_strings_grdp/README.md b/chromium/components/autofill_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/autofill_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/bookmark_bar_strings_grdp/OWNERS b/chromium/components/bookmark_bar_strings_grdp/OWNERS
new file mode 100644
index 00000000000..166b0f10e25
--- /dev/null
+++ b/chromium/components/bookmark_bar_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/bookmarks/OWNERS
diff --git a/chromium/components/bookmark_bar_strings_grdp/README.md b/chromium/components/bookmark_bar_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/bookmark_bar_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/bookmarks/browser/BUILD.gn b/chromium/components/bookmarks/browser/BUILD.gn
index 8f3883400cb..fd9c3db8772 100644
--- a/chromium/components/bookmarks/browser/BUILD.gn
+++ b/chromium/components/bookmarks/browser/BUILD.gn
@@ -5,44 +5,50 @@
import("//build/config/ui.gni")
static_library("browser") {
- sources = [
- "base_bookmark_model_observer.cc",
+ public = [
"base_bookmark_model_observer.h",
- "bookmark_client.cc",
"bookmark_client.h",
- "bookmark_codec.cc",
"bookmark_codec.h",
- "bookmark_expanded_state_tracker.cc",
"bookmark_expanded_state_tracker.h",
- "bookmark_model.cc",
"bookmark_model.h",
"bookmark_model_observer.h",
- "bookmark_node.cc",
"bookmark_node.h",
- "bookmark_node_data.cc",
"bookmark_node_data.h",
- "bookmark_node_data_ios.cc",
- "bookmark_node_data_mac.cc",
"bookmark_pasteboard_helper_mac.h",
- "bookmark_pasteboard_helper_mac.mm",
- "bookmark_storage.cc",
"bookmark_storage.h",
"bookmark_undo_delegate.h",
"bookmark_undo_provider.h",
- "bookmark_utils.cc",
"bookmark_utils.h",
- "scoped_group_bookmark_actions.cc",
"scoped_group_bookmark_actions.h",
- "startup_task_runner_service.cc",
"startup_task_runner_service.h",
- "titled_url_index.cc",
"titled_url_index.h",
- "titled_url_match.cc",
"titled_url_match.h",
"titled_url_node.h",
"titled_url_node_sorter.h",
+ "typed_count_sorter.h",
+ "url_and_title.h",
+ ]
+ sources = [
+ "base_bookmark_model_observer.cc",
+ "bookmark_client.cc",
+ "bookmark_codec.cc",
+ "bookmark_expanded_state_tracker.cc",
+ "bookmark_model.cc",
+ "bookmark_node.cc",
+ "bookmark_node_data.cc",
+ "bookmark_node_data_ios.cc",
+ "bookmark_node_data_mac.cc",
+ "bookmark_pasteboard_helper_mac.mm",
+ "bookmark_storage.cc",
+ "bookmark_utils.cc",
+ "scoped_group_bookmark_actions.cc",
+ "startup_task_runner_service.cc",
+ "titled_url_index.cc",
+ "titled_url_match.cc",
"typed_count_sorter.cc",
"typed_count_sorter.h",
+ "url_index.cc",
+ "url_index.h",
]
public_deps = [
diff --git a/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc b/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc
index ff14a3f78c5..11d51d5adc6 100644
--- a/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_codec_unittest.cc
@@ -40,7 +40,7 @@ const char kFolder2Title[] = "folder2";
const base::FilePath& GetTestDataDir() {
CR_DEFINE_STATIC_LOCAL(base::FilePath, dir, ());
if (dir.empty()) {
- PathService::Get(base::DIR_SOURCE_ROOT, &dir);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &dir);
dir = dir.AppendASCII("components");
dir = dir.AppendASCII("test");
dir = dir.AppendASCII("data");
diff --git a/chromium/components/bookmarks/browser/bookmark_model.cc b/chromium/components/bookmarks/browser/bookmark_model.cc
index 9f15abf5655..9d316114bfb 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model.cc
@@ -26,6 +26,9 @@
#include "components/bookmarks/browser/titled_url_index.h"
#include "components/bookmarks/browser/titled_url_match.h"
#include "components/bookmarks/browser/typed_count_sorter.h"
+#include "components/bookmarks/browser/url_and_title.h"
+#include "components/bookmarks/browser/url_index.h"
+#include "components/bookmarks/common/bookmark_constants.h"
#include "components/favicon_base/favicon_types.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
@@ -54,10 +57,14 @@ class VisibilityComparator {
explicit VisibilityComparator(BookmarkClient* client) : client_(client) {}
// Returns true if |n1| precedes |n2|.
- bool operator()(const std::unique_ptr<BookmarkPermanentNode>& n1,
- const std::unique_ptr<BookmarkPermanentNode>& n2) {
- bool n1_visible = client_->IsPermanentNodeVisible(n1.get());
- bool n2_visible = client_->IsPermanentNodeVisible(n2.get());
+ bool operator()(const std::unique_ptr<BookmarkNode>& n1,
+ const std::unique_ptr<BookmarkNode>& n2) {
+ DCHECK(n1->is_permanent_node());
+ DCHECK(n2->is_permanent_node());
+ bool n1_visible = client_->IsPermanentNodeVisible(
+ static_cast<BookmarkPermanentNode*>(n1.get()));
+ bool n2_visible = client_->IsPermanentNodeVisible(
+ static_cast<BookmarkPermanentNode*>(n2.get()));
return n1_visible != n2_visible && n1_visible;
}
@@ -106,24 +113,33 @@ class EmptyUndoDelegate : public BookmarkUndoDelegate {
DISALLOW_COPY_AND_ASSIGN(EmptyUndoDelegate);
};
+void FinishedLoadOnMainThread(
+ base::OnceCallback<void(std::unique_ptr<BookmarkLoadDetails>)> callback,
+ std::unique_ptr<BookmarkLoadDetails> details) {
+ std::move(callback).Run(std::move(details));
+}
+
+void DoLoadOnBackgroundThread(
+ const base::FilePath& profile_path,
+ scoped_refptr<base::SequencedTaskRunner> result_task_runner,
+ base::OnceCallback<void(std::unique_ptr<BookmarkLoadDetails>)> callback,
+ std::unique_ptr<BookmarkLoadDetails> details) {
+ LoadBookmarks(profile_path, details.get());
+ result_task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&FinishedLoadOnMainThread, std::move(callback),
+ std::move(details)));
+}
+
} // namespace
// BookmarkModel --------------------------------------------------------------
BookmarkModel::BookmarkModel(std::unique_ptr<BookmarkClient> client)
: client_(std::move(client)),
- loaded_(false),
- root_(GURL()),
- bookmark_bar_node_(nullptr),
- other_node_(nullptr),
- mobile_node_(nullptr),
- next_node_id_(1),
+ owned_root_(std::make_unique<BookmarkNode>(GURL())),
+ root_(owned_root_.get()),
observers_(base::ObserverListPolicy::EXISTING_ONLY),
- loaded_signal_(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
- extensive_changes_(0),
- undo_delegate_(nullptr),
- empty_undo_delegate_(new EmptyUndoDelegate) {
+ empty_undo_delegate_(std::make_unique<EmptyUndoDelegate>()) {
DCHECK(client_);
client_->Init(this);
}
@@ -132,7 +148,7 @@ BookmarkModel::~BookmarkModel() {
for (BookmarkModelObserver& observer : observers_)
observer.BookmarkModelBeingDeleted(this);
- if (store_.get()) {
+ if (store_) {
// The store maintains a reference back to us. We need to tell it we're gone
// so that it doesn't try and invoke a method back on us again.
store_->BookmarkModelDeleted();
@@ -153,19 +169,23 @@ void BookmarkModel::Load(
const base::FilePath& profile_path,
const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
const scoped_refptr<base::SequencedTaskRunner>& ui_task_runner) {
- if (store_.get()) {
- // If the store is non-null, it means Load was already invoked. Load should
- // only be invoked once.
- NOTREACHED();
- return;
- }
+ // If the store is non-null, it means Load was already invoked. Load should
+ // only be invoked once.
+ DCHECK(!store_);
- expanded_state_tracker_.reset(
- new BookmarkExpandedStateTracker(this, pref_service));
+ expanded_state_tracker_ =
+ std::make_unique<BookmarkExpandedStateTracker>(this, pref_service);
- // Load the bookmarks. BookmarkStorage notifies us when done.
- store_.reset(new BookmarkStorage(this, profile_path, io_task_runner.get()));
- store_->LoadBookmarks(CreateLoadDetails(), ui_task_runner);
+ store_ = std::make_unique<BookmarkStorage>(this, profile_path,
+ io_task_runner.get());
+ auto done_loading_callback =
+ base::BindOnce(&BookmarkModel::DoneLoading, weak_factory_.GetWeakPtr());
+ io_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&DoLoadOnBackgroundThread,
+ profile_path.Append(kBookmarksFileName), ui_task_runner,
+ std::move(done_loading_callback),
+ std::make_unique<BookmarkLoadDetails>(client_.get())));
}
void BookmarkModel::AddObserver(BookmarkModelObserver* observer) {
@@ -206,7 +226,27 @@ void BookmarkModel::Remove(const BookmarkNode* node) {
DCHECK(loaded_);
DCHECK(node);
DCHECK(!is_root_node(node));
- RemoveAndDeleteNode(AsMutable(node));
+ const BookmarkNode* parent = node->parent();
+ DCHECK(parent);
+ int index = parent->GetIndexOf(node);
+ DCHECK_NE(-1, index);
+
+ for (BookmarkModelObserver& observer : observers_)
+ observer.OnWillRemoveBookmarks(this, parent, index, node);
+
+ std::set<GURL> removed_urls;
+ std::unique_ptr<BookmarkNode> owned_node =
+ url_index_->Remove(AsMutable(node), &removed_urls);
+ RemoveNode(owned_node.get());
+
+ if (store_)
+ store_->ScheduleSave();
+
+ for (BookmarkModelObserver& observer : observers_)
+ observer.BookmarkNodeRemoved(this, parent, index, node, removed_urls);
+
+ undo_delegate()->OnBookmarkNodeRemoved(this, parent, index,
+ std::move(owned_node));
}
void BookmarkModel::RemoveAllUserBookmarks() {
@@ -226,22 +266,22 @@ void BookmarkModel::RemoveAllUserBookmarks() {
// its immediate children. For removing all non permanent nodes just remove
// all children of non-root permanent nodes.
{
- base::AutoLock url_lock(url_lock_);
- for (int i = 0; i < root_.child_count(); ++i) {
- const BookmarkNode* permanent_node = root_.GetChild(i);
+ for (int i = 0; i < root_->child_count(); ++i) {
+ const BookmarkNode* permanent_node = root_->GetChild(i);
if (!client_->CanBeEditedByUser(permanent_node))
continue;
for (int j = permanent_node->child_count() - 1; j >= 0; --j) {
- std::unique_ptr<BookmarkNode> node = RemoveNodeAndGetRemovedUrls(
+ std::unique_ptr<BookmarkNode> node = url_index_->Remove(
AsMutable(permanent_node->GetChild(j)), &removed_urls);
+ RemoveNode(node.get());
removed_node_data_list.push_back({permanent_node, j, std::move(node)});
}
}
}
EndExtensiveChanges();
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
for (BookmarkModelObserver& observer : observers_)
@@ -291,7 +331,7 @@ void BookmarkModel::Move(const BookmarkNode* node,
BookmarkNode* mutable_new_parent = AsMutable(new_parent);
mutable_new_parent->Add(std::move(owned_node), index);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
for (BookmarkModelObserver& observer : observers_)
@@ -319,7 +359,7 @@ void BookmarkModel::Copy(const BookmarkNode* node,
// don't need to send notifications here.
CloneBookmarkNode(this, drag_data.elements, new_parent, index, true);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
}
@@ -363,7 +403,7 @@ void BookmarkModel::SetTitle(const BookmarkNode* node,
if (node->is_url())
index_->Add(node);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
for (BookmarkModelObserver& observer : observers_)
@@ -383,14 +423,11 @@ void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) {
for (BookmarkModelObserver& observer : observers_)
observer.OnWillChangeBookmarkNode(this, node);
- {
- base::AutoLock url_lock(url_lock_);
- RemoveNodeFromInternalMaps(mutable_node);
- mutable_node->set_url(url);
- AddNodeToInternalMaps(mutable_node);
- }
+ index_->Remove(mutable_node);
+ url_index_->SetUrl(mutable_node, url);
+ AddNodeToIndexRecursive(mutable_node);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
for (BookmarkModelObserver& observer : observers_)
@@ -426,7 +463,7 @@ void BookmarkModel::SetNodeMetaInfoMap(
observer.OnWillChangeBookmarkMetaInfo(this, node);
AsMutable(node)->SetMetaInfoMap(meta_info_map);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
for (BookmarkModelObserver& observer : observers_)
@@ -462,12 +499,15 @@ void BookmarkModel::SetNodeSyncTransactionVersion(
return;
AsMutable(node)->set_sync_transaction_version(sync_transaction_version);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
}
void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
const GURL& icon_url) {
+ if (!loaded_)
+ return;
+
std::set<const BookmarkNode*> to_update;
for (const GURL& page_url : page_urls) {
std::vector<const BookmarkNode*> nodes;
@@ -482,11 +522,7 @@ void BookmarkModel::OnFaviconsChanged(const std::set<GURL>& page_urls,
// many times a day for each user.
UMA_HISTOGRAM_BOOLEAN("Bookmarks.OnFaviconsChangedIconURL", true);
- base::AutoLock url_lock(url_lock_);
- for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
- if (node->icon_url() && icon_url == *node->icon_url())
- to_update.insert(node);
- }
+ url_index_->GetNodesWithIconUrl(icon_url, &to_update);
}
for (const BookmarkNode* node : to_update) {
@@ -511,20 +547,15 @@ void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) {
if (date_added > node->parent()->date_folder_modified()) {
// Will trigger store_->ScheduleSave().
SetDateFolderModified(node->parent(), date_added);
- } else if (store_.get()) {
+ } else if (store_) {
store_->ScheduleSave();
}
}
void BookmarkModel::GetNodesByURL(const GURL& url,
std::vector<const BookmarkNode*>* nodes) {
- base::AutoLock url_lock(url_lock_);
- BookmarkNode tmp_node(url);
- NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node);
- while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
- nodes->push_back(*i);
- ++i;
- }
+ if (url_index_)
+ url_index_->GetNodesByUrl(url, nodes);
}
const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
@@ -543,8 +574,7 @@ const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL(
}
bool BookmarkModel::HasBookmarks() {
- base::AutoLock url_lock(url_lock_);
- return !nodes_ordered_by_url_set_.empty();
+ return url_index_ && url_index_->HasBookmarks();
}
bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
@@ -553,26 +583,12 @@ bool BookmarkModel::HasNoUserCreatedBookmarksOrFolders() {
}
bool BookmarkModel::IsBookmarked(const GURL& url) {
- base::AutoLock url_lock(url_lock_);
- return IsBookmarkedNoLock(url);
+ return url_index_ && url_index_->IsBookmarked(url);
}
-void BookmarkModel::GetBookmarks(
- std::vector<BookmarkModel::URLAndTitle>* bookmarks) {
- base::AutoLock url_lock(url_lock_);
- const GURL* last_url = nullptr;
- for (NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.begin();
- i != nodes_ordered_by_url_set_.end(); ++i) {
- const GURL* url = &((*i)->url());
- // Only add unique URLs.
- if (!last_url || *url != *last_url) {
- BookmarkModel::URLAndTitle bookmark;
- bookmark.url = *url;
- bookmark.title = (*i)->GetTitle();
- bookmarks->push_back(bookmark);
- }
- last_url = url;
- }
+void BookmarkModel::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
+ if (url_index_)
+ url_index_->GetBookmarks(bookmarks);
}
void BookmarkModel::BlockTillLoaded() {
@@ -663,7 +679,7 @@ void BookmarkModel::SortChildren(const BookmarkNode* parent) {
mutable_parent->children().end(),
SortComparator(collator.get()));
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
for (BookmarkModelObserver& observer : observers_)
@@ -697,7 +713,7 @@ void BookmarkModel::ReorderChildren(
}
mutable_parent->children().swap(new_children);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
}
@@ -710,7 +726,7 @@ void BookmarkModel::SetDateFolderModified(const BookmarkNode* parent,
DCHECK(parent);
AsMutable(parent)->set_date_folder_modified(time);
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
}
@@ -781,39 +797,23 @@ void BookmarkModel::NotifyNodeAddedForAllDescendents(const BookmarkNode* node) {
}
}
-bool BookmarkModel::IsBookmarkedNoLock(const GURL& url) {
- BookmarkNode tmp_node(url);
- return (nodes_ordered_by_url_set_.find(&tmp_node) !=
- nodes_ordered_by_url_set_.end());
-}
-
-void BookmarkModel::RemoveNode(BookmarkNode* node,
- std::set<GURL>* removed_urls) {
- if (!loaded_ || !node || is_permanent_node(node)) {
- NOTREACHED();
- return;
- }
+void BookmarkModel::RemoveNode(BookmarkNode* node) {
+ DCHECK(loaded_);
+ DCHECK(!is_permanent_node(node));
- url_lock_.AssertAcquired();
- if (node->is_url()) {
- RemoveNodeFromInternalMaps(node);
- removed_urls->insert(node->url());
- }
+ if (node->is_url())
+ index_->Remove(node);
CancelPendingFaviconLoadRequests(node);
// Recurse through children.
for (int i = node->child_count() - 1; i >= 0; --i)
- RemoveNode(node->GetChild(i), removed_urls);
+ RemoveNode(node->GetChild(i));
}
void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
DCHECK(details);
- if (loaded_) {
- // We should only ever be loaded once.
- NOTREACHED();
- return;
- }
+ DCHECK(!loaded_);
next_node_id_ = details->max_id();
if (details->computed_checksum() != details->stored_checksum() ||
@@ -822,49 +822,28 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
// externally. In that case, the decoder may have reassigned IDs to make
// them unique. So when the file has changed externally, we should save the
// bookmarks file to persist new IDs.
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
}
- std::unique_ptr<BookmarkPermanentNode> owned_bb_node =
- details->owned_bb_node();
- std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node =
- details->owned_other_folder_node();
- std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node =
- details->owned_mobile_folder_node();
- index_ = details->owned_index();
- bookmark_bar_node_ = owned_bb_node.get();
- other_node_ = owned_other_folder_node.get();
- mobile_node_ = owned_mobile_folder_node.get();
-
- // Get any extra nodes and take ownership of them at the |root_|.
- std::vector<std::unique_ptr<BookmarkPermanentNode>> extra_nodes =
- details->owned_extra_nodes();
-
- // WARNING: order is important here, various places assume the order is
- // constant (but can vary between embedders with the initial visibility
- // of permanent nodes).
- std::vector<std::unique_ptr<BookmarkPermanentNode>> root_children;
- root_children.push_back(std::move(owned_bb_node));
- root_children.push_back(std::move(owned_other_folder_node));
- root_children.push_back(std::move(owned_mobile_folder_node));
- std::move(extra_nodes.begin(), extra_nodes.end(),
- std::back_inserter(root_children));
-
- std::stable_sort(root_children.begin(),
- root_children.end(),
+ index_ = details->owned_index();
+ url_index_ = details->owned_url_index();
+ root_ = details->root_node();
+ // See declaration for details on why |owned_root_| is reset.
+ owned_root_.reset();
+ bookmark_bar_node_ = details->bb_node();
+ other_node_ = details->other_folder_node();
+ mobile_node_ = details->mobile_folder_node();
+
+ index_->SetNodeSorter(std::make_unique<TypedCountSorter>(client_.get()));
+ // Sorting the permanent nodes has to happen on the main thread, so we do it
+ // here, after loading completes.
+ std::stable_sort(root_->children().begin(), root_->children().end(),
VisibilityComparator(client_.get()));
- for (size_t i = 0; i < root_children.size(); ++i)
- root_.Add(std::move(root_children[i]), static_cast<int>(i));
- root_.SetMetaInfoMap(details->model_meta_info_map());
- root_.set_sync_transaction_version(details->model_sync_transaction_version());
-
- {
- base::AutoLock url_lock(url_lock_);
- // Update nodes_ordered_by_url_set_ from the nodes.
- PopulateNodesByURL(&root_);
- }
+ root_->SetMetaInfoMap(details->model_meta_info_map());
+ root_->set_sync_transaction_version(
+ details->model_sync_transaction_version());
loaded_ = true;
@@ -875,88 +854,16 @@ void BookmarkModel::DoneLoading(std::unique_ptr<BookmarkLoadDetails> details) {
observer.BookmarkModelLoaded(this, details->ids_reassigned());
}
-void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* node_ptr) {
- std::unique_ptr<BookmarkNode> node;
-
- const BookmarkNode* parent = node_ptr->parent();
- DCHECK(parent);
- int index = parent->GetIndexOf(node_ptr);
- DCHECK_NE(-1, index);
-
- for (BookmarkModelObserver& observer : observers_)
- observer.OnWillRemoveBookmarks(this, parent, index, node_ptr);
-
- std::set<GURL> removed_urls;
- {
- base::AutoLock url_lock(url_lock_);
- node = RemoveNodeAndGetRemovedUrls(node_ptr, &removed_urls);
- }
-
- if (store_.get())
- store_->ScheduleSave();
-
- for (BookmarkModelObserver& observer : observers_)
- observer.BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls);
-
- undo_delegate()->OnBookmarkNodeRemoved(this, parent, index, std::move(node));
-}
-
-void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) {
- index_->Remove(node);
- // NOTE: this is called in such a way that url_lock_ is already held. As
- // such, this doesn't explicitly grab the lock.
- url_lock_.AssertAcquired();
- NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node);
- DCHECK(i != nodes_ordered_by_url_set_.end());
- // i points to the first node with the URL, advance until we find the
- // node we're removing.
- while (*i != node)
- ++i;
- nodes_ordered_by_url_set_.erase(i);
-}
-
-std::unique_ptr<BookmarkNode> BookmarkModel::RemoveNodeAndGetRemovedUrls(
- BookmarkNode* node_ptr,
- std::set<GURL>* removed_urls) {
- // NOTE: this method should be always called with |url_lock_| held.
- // This method does not explicitly acquires a lock.
- url_lock_.AssertAcquired();
- DCHECK(removed_urls);
- BookmarkNode* parent = node_ptr->parent();
- DCHECK(parent);
- std::unique_ptr<BookmarkNode> node = parent->Remove(node_ptr);
- RemoveNode(node_ptr, removed_urls);
- // RemoveNode adds an entry to removed_urls for each node of type URL. As we
- // allow duplicates we need to remove any entries that are still bookmarked.
- for (std::set<GURL>::iterator i = removed_urls->begin();
- i != removed_urls->end();) {
- if (IsBookmarkedNoLock(*i)) {
- // When we erase the iterator pointing at the erasee is
- // invalidated, so using i++ here within the "erase" call is
- // important as it advances the iterator before passing the
- // old value through to erase.
- removed_urls->erase(i++);
- } else {
- ++i;
- }
- }
-
- return node;
-}
-
BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
int index,
std::unique_ptr<BookmarkNode> node) {
BookmarkNode* node_ptr = node.get();
- parent->Add(std::move(node), index);
+ url_index_->Add(parent, index, std::move(node));
- if (store_.get())
+ if (store_)
store_->ScheduleSave();
- {
- base::AutoLock url_lock(url_lock_);
- AddNodeToInternalMaps(node_ptr);
- }
+ AddNodeToIndexRecursive(node_ptr);
for (BookmarkModelObserver& observer : observers_)
observer.BookmarkNodeAdded(this, parent, index);
@@ -964,14 +871,11 @@ BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent,
return node_ptr;
}
-void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) {
- url_lock_.AssertAcquired();
- if (node->is_url()) {
+void BookmarkModel::AddNodeToIndexRecursive(BookmarkNode* node) {
+ if (node->is_url())
index_->Add(node);
- nodes_ordered_by_url_set_.insert(node);
- }
for (int i = 0; i < node->child_count(); ++i)
- AddNodeToInternalMaps(node->GetChild(i));
+ AddNodeToIndexRecursive(node->GetChild(i));
}
bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
@@ -982,36 +886,6 @@ bool BookmarkModel::IsValidIndex(const BookmarkNode* parent,
(allow_end && index == parent->child_count()))));
}
-BookmarkPermanentNode* BookmarkModel::CreatePermanentNode(
- BookmarkNode::Type type) {
- DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
- type == BookmarkNode::OTHER_NODE ||
- type == BookmarkNode::MOBILE);
- BookmarkPermanentNode* node =
- new BookmarkPermanentNode(generate_next_node_id());
- node->set_type(type);
- node->set_visible(client_->IsPermanentNodeVisible(node));
-
- int title_id;
- switch (type) {
- case BookmarkNode::BOOKMARK_BAR:
- title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
- break;
- case BookmarkNode::OTHER_NODE:
- title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
- break;
- case BookmarkNode::MOBILE:
- title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
- break;
- default:
- NOTREACHED();
- title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
- break;
- }
- node->SetTitle(l10n_util::GetStringUTF16(title_id));
- return node;
-}
-
void BookmarkModel::OnFaviconDataAvailable(
BookmarkNode* node,
favicon_base::IconType icon_type,
@@ -1067,33 +941,11 @@ void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) {
}
}
-void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) {
- // NOTE: this is called with url_lock_ already held. As such, this doesn't
- // explicitly grab the lock.
- if (node->is_url())
- nodes_ordered_by_url_set_.insert(node);
- for (int i = 0; i < node->child_count(); ++i)
- PopulateNodesByURL(node->GetChild(i));
-}
-
int64_t BookmarkModel::generate_next_node_id() {
+ DCHECK(loaded_);
return next_node_id_++;
}
-std::unique_ptr<BookmarkLoadDetails> BookmarkModel::CreateLoadDetails() {
- BookmarkPermanentNode* bb_node =
- CreatePermanentNode(BookmarkNode::BOOKMARK_BAR);
- BookmarkPermanentNode* other_node =
- CreatePermanentNode(BookmarkNode::OTHER_NODE);
- BookmarkPermanentNode* mobile_node =
- CreatePermanentNode(BookmarkNode::MOBILE);
- std::unique_ptr<TitledUrlNodeSorter> node_sorter =
- std::make_unique<TypedCountSorter>(client_.get());
- return std::unique_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails(
- bb_node, other_node, mobile_node, client_->GetLoadExtraNodesCallback(),
- new TitledUrlIndex(std::move(node_sorter)), next_node_id_));
-}
-
void BookmarkModel::SetUndoDelegate(BookmarkUndoDelegate* undo_delegate) {
undo_delegate_ = undo_delegate;
if (undo_delegate_)
diff --git a/chromium/components/bookmarks/browser/bookmark_model.h b/chromium/components/bookmarks/browser/bookmark_model.h
index b555ba10fa2..868d8baf75e 100644
--- a/chromium/components/bookmarks/browser/bookmark_model.h
+++ b/chromium/components/bookmarks/browser/bookmark_model.h
@@ -16,9 +16,9 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/strings/string16.h"
-#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "components/bookmarks/browser/bookmark_client.h"
#include "components/bookmarks/browser/bookmark_node.h"
@@ -53,6 +53,9 @@ class BookmarkUndoDelegate;
class ScopedGroupBookmarkActions;
class TestBookmarkClient;
class TitledUrlIndex;
+class UrlIndex;
+
+struct UrlAndTitle;
struct TitledUrlMatch;
// BookmarkModel --------------------------------------------------------------
@@ -68,21 +71,15 @@ struct TitledUrlMatch;
class BookmarkModel : public BookmarkUndoProvider,
public KeyedService {
public:
- struct URLAndTitle {
- GURL url;
- base::string16 title;
- };
-
explicit BookmarkModel(std::unique_ptr<BookmarkClient> client);
~BookmarkModel() override;
// KeyedService:
void Shutdown() override;
- // Loads the bookmarks. This is called upon creation of the
- // BookmarkModel. You need not invoke this directly.
- // All load operations will be executed on |io_task_runner| and the completion
- // callback will be called from |ui_task_runner|.
+ // Loads the bookmarks. This is called upon creation of the BookmarkModel. You
+ // need not invoke this directly. All load operations will be executed on
+ // |io_task_runner|. |ui_task_runner| is the task runner the model runs on.
void Load(PrefService* pref_service,
const base::FilePath& profile_path,
const scoped_refptr<base::SequencedTaskRunner>& io_task_runner,
@@ -93,7 +90,7 @@ class BookmarkModel : public BookmarkUndoProvider,
// Returns the root node. The 'bookmark bar' node and 'other' node are
// children of the root node.
- const BookmarkNode* root_node() const { return &root_; }
+ const BookmarkNode* root_node() const { return root_; }
// Returns the 'bookmark bar' node. This is NULL until loaded.
const BookmarkNode* bookmark_bar_node() const { return bookmark_bar_node_; }
@@ -104,13 +101,13 @@ class BookmarkModel : public BookmarkUndoProvider,
// Returns the 'mobile' node. This is NULL until loaded.
const BookmarkNode* mobile_node() const { return mobile_node_; }
- bool is_root_node(const BookmarkNode* node) const { return node == &root_; }
+ bool is_root_node(const BookmarkNode* node) const { return node == root_; }
// Returns whether the given |node| is one of the permanent nodes - root node,
// 'bookmark bar' node, 'other' node or 'mobile' node, or one of the root
// nodes supplied by the |client_|.
bool is_permanent_node(const BookmarkNode* node) const {
- return node && (node == &root_ || node->parent() == &root_);
+ return node && (node == root_ || node->parent() == root_);
}
void AddObserver(BookmarkModelObserver* observer);
@@ -193,7 +190,7 @@ class BookmarkModel : public BookmarkUndoProvider,
// same or not.
//
// If not on the main thread you *must* invoke BlockTillLoaded first.
- void GetBookmarks(std::vector<BookmarkModel::URLAndTitle>* urls);
+ void GetBookmarks(std::vector<UrlAndTitle>* urls);
// Blocks until loaded. This is intended for usage on a thread other than
// the main thread.
@@ -323,14 +320,6 @@ class BookmarkModel : public BookmarkUndoProvider,
friend class ScopedGroupBookmarkActions;
friend class TestBookmarkClient;
- // Used to order BookmarkNodes by URL.
- class NodeURLComparator {
- public:
- bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
- return n1->url() < n2->url();
- }
- };
-
// BookmarkUndoProvider:
void RestoreRemovedNode(const BookmarkNode* parent,
int index,
@@ -339,54 +328,27 @@ class BookmarkModel : public BookmarkUndoProvider,
// Notifies the observers for adding every descedent of |node|.
void NotifyNodeAddedForAllDescendents(const BookmarkNode* node);
- // Implementation of IsBookmarked. Before calling this the caller must obtain
- // a lock on |url_lock_|.
- bool IsBookmarkedNoLock(const GURL& url);
-
// Removes the node from internal maps and recurses through all children. If
// the node is a url, its url is added to removed_urls.
//
// This does NOT delete the node.
- void RemoveNode(BookmarkNode* node, std::set<GURL>* removed_urls);
+ void RemoveNode(BookmarkNode* node);
- // Invoked when loading is finished. Sets |loaded_| and notifies observers.
- // BookmarkModel takes ownership of |details|.
+ // Called when done loading. Updates internal state and notifies observers.
void DoneLoading(std::unique_ptr<BookmarkLoadDetails> details);
- // Populates |nodes_ordered_by_url_set_| from root.
- void PopulateNodesByURL(BookmarkNode* node);
-
- // Removes the node from its parent and returns it. No notifications
- // are sent. |removed_urls| is populated with the urls which no longer have
- // any bookmarks associated with them.
- // This method should be called after acquiring |url_lock_|.
- std::unique_ptr<BookmarkNode> RemoveNodeAndGetRemovedUrls(
- BookmarkNode* node,
- std::set<GURL>* removed_urls);
-
- // Removes the node from its parent, sends notification, and deletes it.
- // type specifies how the node should be removed.
- void RemoveAndDeleteNode(BookmarkNode* delete_me);
-
- // Remove |node| from |nodes_ordered_by_url_set_| and |index_|.
- void RemoveNodeFromInternalMaps(BookmarkNode* node);
-
// Adds the |node| at |parent| in the specified |index| and notifies its
// observers.
BookmarkNode* AddNode(BookmarkNode* parent,
int index,
std::unique_ptr<BookmarkNode> node);
- // Adds the |node| to |nodes_ordered_by_url_set_| and |index_|.
- void AddNodeToInternalMaps(BookmarkNode* node);
+ // Adds |node| to |index_| and recursisvely invokes this for all children.
+ void AddNodeToIndexRecursive(BookmarkNode* node);
// Returns true if the parent and index are valid.
bool IsValidIndex(const BookmarkNode* parent, int index, bool allow_end);
- // Creates one of the possible permanent nodes (bookmark bar node, other node
- // and mobile node) from |type|.
- BookmarkPermanentNode* CreatePermanentNode(BookmarkNode::Type type);
-
// Notification that a favicon has finished loading. If we can decode the
// favicon, FaviconLoaded is invoked.
void OnFaviconDataAvailable(
@@ -417,39 +379,33 @@ class BookmarkModel : public BookmarkUndoProvider,
// decoding since during decoding codec assigns node IDs.
void set_next_node_id(int64_t id) { next_node_id_ = id; }
- // Creates and returns a new BookmarkLoadDetails. It's up to the caller to
- // delete the returned object.
- std::unique_ptr<BookmarkLoadDetails> CreateLoadDetails();
-
BookmarkUndoDelegate* undo_delegate() const;
std::unique_ptr<BookmarkClient> client_;
// Whether the initial set of data has been loaded.
- bool loaded_;
+ bool loaded_ = false;
+
+ // See |root_| for details.
+ std::unique_ptr<BookmarkNode> owned_root_;
// The root node. This contains the bookmark bar node, the 'other' node and
- // the mobile node as children.
- BookmarkNode root_;
+ // the mobile node as children. The value of |root_| is initially that of
+ // |owned_root_|. Once loading has completed, |owned_root_| is destroyed and
+ // this is set to url_index_->root(). |owned_root_| is done as lots of
+ // existing code assumes the root is non-null while loading.
+ BookmarkNode* root_ = nullptr;
- BookmarkPermanentNode* bookmark_bar_node_;
- BookmarkPermanentNode* other_node_;
- BookmarkPermanentNode* mobile_node_;
+ BookmarkPermanentNode* bookmark_bar_node_ = nullptr;
+ BookmarkPermanentNode* other_node_ = nullptr;
+ BookmarkPermanentNode* mobile_node_ = nullptr;
// The maximum ID assigned to the bookmark nodes in the model.
- int64_t next_node_id_;
+ int64_t next_node_id_ = 1;
// The observers.
base::ObserverList<BookmarkModelObserver> observers_;
- // Set of nodes ordered by URL. This is not a map to avoid copying the
- // urls.
- // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As
- // such, be sure and wrap all usage of it around |url_lock_|.
- typedef std::multiset<BookmarkNode*, NodeURLComparator> NodesOrderedByURLSet;
- NodesOrderedByURLSet nodes_ordered_by_url_set_;
- base::Lock url_lock_;
-
// Used for loading favicons.
base::CancelableTaskTracker cancelable_task_tracker_;
@@ -457,19 +413,22 @@ class BookmarkModel : public BookmarkUndoProvider,
std::unique_ptr<BookmarkStorage> store_;
std::unique_ptr<TitledUrlIndex> index_;
+ std::unique_ptr<UrlIndex> url_index_;
base::WaitableEvent loaded_signal_;
// See description of IsDoingExtensiveChanges above.
- int extensive_changes_;
+ int extensive_changes_ = 0;
std::unique_ptr<BookmarkExpandedStateTracker> expanded_state_tracker_;
std::set<std::string> non_cloned_keys_;
- BookmarkUndoDelegate* undo_delegate_;
+ BookmarkUndoDelegate* undo_delegate_ = nullptr;
std::unique_ptr<BookmarkUndoDelegate> empty_undo_delegate_;
+ base::WeakPtrFactory<BookmarkModel> weak_factory_{this};
+
DISALLOW_COPY_AND_ASSIGN(BookmarkModel);
};
diff --git a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
index 52253758ee0..12472c7795c 100644
--- a/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
+++ b/chromium/components/bookmarks/browser/bookmark_model_unittest.cc
@@ -16,17 +16,22 @@
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
+#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "components/bookmarks/browser/bookmark_model_observer.h"
#include "components/bookmarks/browser/bookmark_undo_delegate.h"
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/bookmarks/browser/titled_url_match.h"
+#include "components/bookmarks/browser/url_and_title.h"
#include "components/bookmarks/test/bookmark_test_helpers.h"
#include "components/bookmarks/test/test_bookmark_client.h"
#include "components/favicon_base/favicon_callback.h"
@@ -1006,7 +1011,7 @@ TEST_F(BookmarkModelTest, GetBookmarksWithDups) {
model_->AddURL(model_->bookmark_bar_node(), 0, title, url);
model_->AddURL(model_->bookmark_bar_node(), 1, title, url);
- std::vector<BookmarkModel::URLAndTitle> bookmarks;
+ std::vector<UrlAndTitle> bookmarks;
model_->GetBookmarks(&bookmarks);
ASSERT_EQ(1U, bookmarks.size());
EXPECT_EQ(url, bookmarks[0].url);
@@ -1220,6 +1225,39 @@ TEST_F(BookmarkModelTest, RenamedFolderNodeExcludedFromIndex) {
EXPECT_TRUE(matches.empty());
}
+// Verifies the TitledUrlIndex is probably loaded.
+TEST(BookmarkModelLoadTest, TitledUrlIndexPopulatedOnLoad) {
+ // Create a model with a single url.
+ base::ScopedTempDir tmp_dir;
+ ASSERT_TRUE(tmp_dir.CreateUniqueTempDir());
+ base::test::ScopedTaskEnvironment scoped_task_environment;
+ std::unique_ptr<BookmarkModel> model =
+ std::make_unique<BookmarkModel>(std::make_unique<TestBookmarkClient>());
+ model->Load(nullptr, tmp_dir.GetPath(), base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+ test::WaitForBookmarkModelToLoad(model.get());
+ const GURL node_url("http://google.com");
+ model->AddURL(model->bookmark_bar_node(), 0, base::ASCIIToUTF16("User"),
+ node_url);
+ // This is necessary to ensure the save completes.
+ base::RunLoop().RunUntilIdle();
+
+ // Recreate the model and ensure GetBookmarksMatching() returns the url that
+ // was added.
+ model =
+ std::make_unique<BookmarkModel>(std::make_unique<TestBookmarkClient>());
+ model->Load(nullptr, tmp_dir.GetPath(), base::ThreadTaskRunnerHandle::Get(),
+ base::ThreadTaskRunnerHandle::Get());
+ test::WaitForBookmarkModelToLoad(model.get());
+
+ std::vector<TitledUrlMatch> matches;
+ model->GetBookmarksMatching(base::ASCIIToUTF16("user"), 1,
+ query_parser::MatchingAlgorithm::DEFAULT,
+ &matches);
+ ASSERT_EQ(1u, matches.size());
+ EXPECT_EQ(node_url, matches[0].node->GetTitledUrlNodeUrl());
+}
+
TEST(BookmarkNodeTest, NodeMetaInfo) {
GURL url;
BookmarkNode node(url);
diff --git a/chromium/components/bookmarks/browser/bookmark_node.cc b/chromium/components/bookmarks/browser/bookmark_node.cc
index 5c2522a9826..8b68d4e5848 100644
--- a/chromium/components/bookmarks/browser/bookmark_node.cc
+++ b/chromium/components/bookmarks/browser/bookmark_node.cc
@@ -26,19 +26,15 @@ const base::char16 kInvalidChars[] = {
// BookmarkNode ---------------------------------------------------------------
+// static
const int64_t BookmarkNode::kInvalidSyncTransactionVersion = -1;
-BookmarkNode::BookmarkNode(const GURL& url)
- : url_(url) {
- Initialize(0);
-}
+BookmarkNode::BookmarkNode(const GURL& url) : BookmarkNode(0, url, false) {}
-BookmarkNode::BookmarkNode(int64_t id, const GURL& url) : url_(url) {
- Initialize(id);
-}
+BookmarkNode::BookmarkNode(int64_t id, const GURL& url)
+ : BookmarkNode(id, url, false) {}
-BookmarkNode::~BookmarkNode() {
-}
+BookmarkNode::~BookmarkNode() = default;
void BookmarkNode::SetTitle(const base::string16& title) {
// Replace newlines and other problematic whitespace characters in
@@ -111,16 +107,13 @@ const GURL& BookmarkNode::GetTitledUrlNodeUrl() const {
return url_;
}
-void BookmarkNode::Initialize(int64_t id) {
- id_ = id;
- type_ = url_.is_empty() ? FOLDER : URL;
- date_added_ = base::Time::Now();
- favicon_type_ = favicon_base::IconType::kInvalid;
- favicon_state_ = INVALID_FAVICON;
- favicon_load_task_id_ = base::CancelableTaskTracker::kBadTaskId;
- meta_info_map_.reset();
- sync_transaction_version_ = kInvalidSyncTransactionVersion;
-}
+BookmarkNode::BookmarkNode(int64_t id, const GURL& url, bool is_permanent_node)
+ : id_(id),
+ url_(url),
+ type_(url_.is_empty() ? FOLDER : URL),
+ date_added_(base::Time::Now()),
+ favicon_type_(favicon_base::IconType::kInvalid),
+ is_permanent_node_(is_permanent_node) {}
void BookmarkNode::InvalidateFavicon() {
icon_url_.reset();
@@ -132,10 +125,9 @@ void BookmarkNode::InvalidateFavicon() {
// BookmarkPermanentNode -------------------------------------------------------
BookmarkPermanentNode::BookmarkPermanentNode(int64_t id)
- : BookmarkNode(id, GURL()), visible_(true) {}
+ : BookmarkNode(id, GURL(), true) {}
-BookmarkPermanentNode::~BookmarkPermanentNode() {
-}
+BookmarkPermanentNode::~BookmarkPermanentNode() = default;
bool BookmarkPermanentNode::IsVisible() const {
return visible_ || !empty();
diff --git a/chromium/components/bookmarks/browser/bookmark_node.h b/chromium/components/bookmarks/browser/bookmark_node.h
index 7576f6c09ae..e6ce83cad26 100644
--- a/chromium/components/bookmarks/browser/bookmark_node.h
+++ b/chromium/components/bookmarks/browser/bookmark_node.h
@@ -53,6 +53,10 @@ class BookmarkNode : public ui::TreeNode<BookmarkNode>, public TitledUrlNode {
~BookmarkNode() override;
+ // Returns true if the node is a BookmarkPermanentNode (which does not include
+ // the root).
+ bool is_permanent_node() const { return is_permanent_node_; }
+
// Set the node's internal title. Note that this neither invokes observers
// nor updates any bookmark model this node may be in. For that functionality,
// BookmarkModel::SetTitle(..) should be used instead.
@@ -123,12 +127,12 @@ class BookmarkNode : public ui::TreeNode<BookmarkNode>, public TitledUrlNode {
// TODO(sky): Consider adding last visit time here, it'll greatly simplify
// HistoryContentsProvider.
+ protected:
+ BookmarkNode(int64_t id, const GURL& url, bool is_permanent_node);
+
private:
friend class BookmarkModel;
- // A helper function to initialize various fields during construction.
- void Initialize(int64_t id);
-
// Called when the favicon becomes invalid.
void InvalidateFavicon();
@@ -182,18 +186,21 @@ class BookmarkNode : public ui::TreeNode<BookmarkNode>, public TitledUrlNode {
std::unique_ptr<GURL> icon_url_;
// The loading state of the favicon.
- FaviconState favicon_state_;
+ FaviconState favicon_state_ = INVALID_FAVICON;
// If not base::CancelableTaskTracker::kBadTaskId, it indicates
// we're loading the
// favicon and the task is tracked by CancelabelTaskTracker.
- base::CancelableTaskTracker::TaskId favicon_load_task_id_;
+ base::CancelableTaskTracker::TaskId favicon_load_task_id_ =
+ base::CancelableTaskTracker::kBadTaskId;
// A map that stores arbitrary meta information about the node.
std::unique_ptr<MetaInfoMap> meta_info_map_;
- // The sync transaction version. Defaults to kInvalidSyncTransactionVersion.
- int64_t sync_transaction_version_;
+ // The sync transaction version.
+ int64_t sync_transaction_version_ = kInvalidSyncTransactionVersion;
+
+ const bool is_permanent_node_;
DISALLOW_COPY_AND_ASSIGN(BookmarkNode);
};
@@ -213,7 +220,7 @@ class BookmarkPermanentNode : public BookmarkNode {
bool IsVisible() const override;
private:
- bool visible_;
+ bool visible_ = false;
DISALLOW_COPY_AND_ASSIGN(BookmarkPermanentNode);
};
diff --git a/chromium/components/bookmarks/browser/bookmark_storage.cc b/chromium/components/bookmarks/browser/bookmark_storage.cc
index cf64723c3a6..1633ba1df2a 100644
--- a/chromium/components/bookmarks/browser/bookmark_storage.cc
+++ b/chromium/components/bookmarks/browser/bookmark_storage.cc
@@ -16,11 +16,16 @@
#include "base/json/json_string_value_serializer.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
+#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "components/bookmarks/browser/bookmark_codec.h"
#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/browser/bookmark_node.h"
#include "components/bookmarks/browser/titled_url_index.h"
+#include "components/bookmarks/browser/url_index.h"
#include "components/bookmarks/common/bookmark_constants.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
using base::TimeTicks;
@@ -51,10 +56,10 @@ void AddBookmarksToIndex(BookmarkLoadDetails* details,
}
}
-void LoadCallback(const base::FilePath& path,
- const base::WeakPtr<BookmarkStorage>& storage,
- std::unique_ptr<BookmarkLoadDetails> details,
- base::SequencedTaskRunner* task_runner) {
+} // namespace
+
+void LoadBookmarks(const base::FilePath& path, BookmarkLoadDetails* details) {
+ base::AssertBlockingAllowed();
bool load_index = false;
bool bookmark_file_exists = base::PathExists(path);
if (bookmark_file_exists) {
@@ -65,14 +70,14 @@ void LoadCallback(const base::FilePath& path,
std::unique_ptr<base::Value> root =
deserializer.Deserialize(nullptr, nullptr);
- if (root.get()) {
+ if (root) {
// Building the index can take a while, so we do it on the background
// thread.
int64_t max_node_id = 0;
BookmarkCodec codec;
TimeTicks start_time = TimeTicks::Now();
codec.Decode(details->bb_node(), details->other_folder_node(),
- details->mobile_folder_node(), &max_node_id, *root.get());
+ details->mobile_folder_node(), &max_node_id, *root);
details->set_max_id(std::max(max_node_id, details->max_id()));
details->set_computed_checksum(codec.computed_checksum());
details->set_stored_checksum(codec.stored_checksum());
@@ -96,62 +101,93 @@ void LoadCallback(const base::FilePath& path,
}
}
+ if (details->LoadExtraNodes())
+ load_index = true;
+
// Load any extra root nodes now, after the IDs have been potentially
// reassigned.
- details->LoadExtraNodes();
-
- // Load the index if there are any bookmarks in the extra nodes.
- const BookmarkPermanentNodeList& extra_nodes = details->extra_nodes();
- for (size_t i = 0; i < extra_nodes.size(); ++i) {
- if (!extra_nodes[i]->empty()) {
- load_index = true;
- break;
- }
- }
-
if (load_index) {
TimeTicks start_time = TimeTicks::Now();
- AddBookmarksToIndex(details.get(), details->bb_node());
- AddBookmarksToIndex(details.get(), details->other_folder_node());
- AddBookmarksToIndex(details.get(), details->mobile_folder_node());
- for (size_t i = 0; i < extra_nodes.size(); ++i)
- AddBookmarksToIndex(details.get(), extra_nodes[i].get());
+ AddBookmarksToIndex(details, details->root_node());
UMA_HISTOGRAM_TIMES("Bookmarks.CreateBookmarkIndexTime",
TimeTicks::Now() - start_time);
}
- task_runner->PostTask(
- FROM_HERE, base::BindOnce(&BookmarkStorage::OnLoadFinished, storage,
- std::move(details)));
+ details->CreateUrlIndex();
}
-} // namespace
-
// BookmarkLoadDetails ---------------------------------------------------------
-BookmarkLoadDetails::BookmarkLoadDetails(
- BookmarkPermanentNode* bb_node,
- BookmarkPermanentNode* other_folder_node,
- BookmarkPermanentNode* mobile_folder_node,
- const LoadExtraCallback& load_extra_callback,
- TitledUrlIndex* index,
- int64_t max_id)
- : bb_node_(bb_node),
- other_folder_node_(other_folder_node),
- mobile_folder_node_(mobile_folder_node),
- load_extra_callback_(load_extra_callback),
- index_(index),
+BookmarkLoadDetails::BookmarkLoadDetails(BookmarkClient* client)
+ : load_extra_callback_(client->GetLoadExtraNodesCallback()),
+ index_(std::make_unique<TitledUrlIndex>()),
model_sync_transaction_version_(
- BookmarkNode::kInvalidSyncTransactionVersion),
- max_id_(max_id),
- ids_reassigned_(false) {}
+ BookmarkNode::kInvalidSyncTransactionVersion) {
+ // WARNING: do NOT add |client| as a member. Much of this code runs on another
+ // thread, and |client_| is not thread safe, and/or may be destroyed before
+ // this.
+ root_node_ = std::make_unique<BookmarkNode>(GURL());
+ root_node_ptr_ = root_node_.get();
+ // WARNING: order is important here, various places assume the order is
+ // constant (but can vary between embedders with the initial visibility
+ // of permanent nodes).
+ bb_node_ = CreatePermanentNode(client, BookmarkNode::BOOKMARK_BAR);
+ other_folder_node_ = CreatePermanentNode(client, BookmarkNode::OTHER_NODE);
+ mobile_folder_node_ = CreatePermanentNode(client, BookmarkNode::MOBILE);
+}
BookmarkLoadDetails::~BookmarkLoadDetails() {
}
-void BookmarkLoadDetails::LoadExtraNodes() {
- if (!load_extra_callback_.is_null())
- extra_nodes_ = load_extra_callback_.Run(&max_id_);
+bool BookmarkLoadDetails::LoadExtraNodes() {
+ if (!load_extra_callback_)
+ return false;
+
+ BookmarkPermanentNodeList extra_nodes =
+ std::move(load_extra_callback_).Run(&max_id_);
+ bool has_non_empty_node = false;
+ for (auto& node : extra_nodes) {
+ if (node->child_count() != 0)
+ has_non_empty_node = true;
+ root_node_->Add(std::move(node), root_node_->child_count());
+ }
+ return has_non_empty_node;
+}
+
+void BookmarkLoadDetails::CreateUrlIndex() {
+ url_index_ = std::make_unique<UrlIndex>(std::move(root_node_));
+}
+
+BookmarkPermanentNode* BookmarkLoadDetails::CreatePermanentNode(
+ BookmarkClient* client,
+ BookmarkNode::Type type) {
+ DCHECK(type == BookmarkNode::BOOKMARK_BAR ||
+ type == BookmarkNode::OTHER_NODE || type == BookmarkNode::MOBILE);
+ std::unique_ptr<BookmarkPermanentNode> node =
+ std::make_unique<BookmarkPermanentNode>(max_id_++);
+ node->set_type(type);
+ node->set_visible(client->IsPermanentNodeVisible(node.get()));
+
+ int title_id;
+ switch (type) {
+ case BookmarkNode::BOOKMARK_BAR:
+ title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
+ break;
+ case BookmarkNode::OTHER_NODE:
+ title_id = IDS_BOOKMARK_BAR_OTHER_FOLDER_NAME;
+ break;
+ case BookmarkNode::MOBILE:
+ title_id = IDS_BOOKMARK_BAR_MOBILE_FOLDER_NAME;
+ break;
+ default:
+ NOTREACHED();
+ title_id = IDS_BOOKMARK_BAR_FOLDER_NAME;
+ break;
+ }
+ node->SetTitle(l10n_util::GetStringUTF16(title_id));
+ BookmarkPermanentNode* permanent_node = node.get();
+ root_node_->Add(std::move(node), root_node_->child_count());
+ return permanent_node;
}
// BookmarkStorage -------------------------------------------------------------
@@ -173,15 +209,6 @@ BookmarkStorage::~BookmarkStorage() {
writer_.DoScheduledWrite();
}
-void BookmarkStorage::LoadBookmarks(
- std::unique_ptr<BookmarkLoadDetails> details,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
- sequenced_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&LoadCallback, writer_.path(), weak_factory_.GetWeakPtr(),
- std::move(details), base::RetainedRef(task_runner)));
-}
-
void BookmarkStorage::ScheduleSave() {
switch (backup_state_) {
case BACKUP_NONE:
@@ -222,14 +249,6 @@ bool BookmarkStorage::SerializeData(std::string* output) {
return serializer.Serialize(*(value.get()));
}
-void BookmarkStorage::OnLoadFinished(
- std::unique_ptr<BookmarkLoadDetails> details) {
- if (!model_)
- return;
-
- model_->DoneLoading(std::move(details));
-}
-
bool BookmarkStorage::SaveNow() {
if (!model_ || !model_->loaded()) {
// We should only get here if we have a valid model and it's finished
diff --git a/chromium/components/bookmarks/browser/bookmark_storage.h b/chromium/components/bookmarks/browser/bookmark_storage.h
index 6f86188d3fc..08df5bb65d8 100644
--- a/chromium/components/bookmarks/browser/bookmark_storage.h
+++ b/chromium/components/bookmarks/browser/bookmark_storage.h
@@ -26,7 +26,10 @@ class SequencedTaskRunner;
namespace bookmarks {
+class BookmarkClient;
class BookmarkModel;
+class BookmarkNode;
+class UrlIndex;
// A list of BookmarkPermanentNodes that owns them.
using BookmarkPermanentNodeList =
@@ -35,7 +38,8 @@ using BookmarkPermanentNodeList =
// A callback that generates a BookmarkPermanentNodeList, given a max ID to
// use. The max ID argument will be updated after any new nodes have been
// created and assigned IDs.
-using LoadExtraCallback = base::Callback<BookmarkPermanentNodeList(int64_t*)>;
+using LoadExtraCallback =
+ base::OnceCallback<BookmarkPermanentNodeList(int64_t*)>;
// BookmarkLoadDetails is used by BookmarkStorage when loading bookmarks.
// BookmarkModel creates a BookmarkLoadDetails and passes it (including
@@ -47,38 +51,18 @@ using LoadExtraCallback = base::Callback<BookmarkPermanentNodeList(int64_t*)>;
// threading problems.
class BookmarkLoadDetails {
public:
- BookmarkLoadDetails(BookmarkPermanentNode* bb_node,
- BookmarkPermanentNode* other_folder_node,
- BookmarkPermanentNode* mobile_folder_node,
- const LoadExtraCallback& load_extra_callback,
- TitledUrlIndex* index,
- int64_t max_id);
+ explicit BookmarkLoadDetails(BookmarkClient* client);
~BookmarkLoadDetails();
- void LoadExtraNodes();
+ // Loads the extra nodes and adds them to |root_|. Returns true if at least
+ // one node was added that has children.
+ bool LoadExtraNodes();
+
+ BookmarkNode* root_node() { return root_node_ptr_; }
+ BookmarkPermanentNode* bb_node() { return bb_node_; }
+ BookmarkPermanentNode* mobile_folder_node() { return mobile_folder_node_; }
+ BookmarkPermanentNode* other_folder_node() { return other_folder_node_; }
- BookmarkPermanentNode* bb_node() { return bb_node_.get(); }
- std::unique_ptr<BookmarkPermanentNode> owned_bb_node() {
- return std::move(bb_node_);
- }
- BookmarkPermanentNode* mobile_folder_node() {
- return mobile_folder_node_.get();
- }
- std::unique_ptr<BookmarkPermanentNode> owned_mobile_folder_node() {
- return std::move(mobile_folder_node_);
- }
- BookmarkPermanentNode* other_folder_node() {
- return other_folder_node_.get();
- }
- std::unique_ptr<BookmarkPermanentNode> owned_other_folder_node() {
- return std::move(other_folder_node_);
- }
- const BookmarkPermanentNodeList& extra_nodes() {
- return extra_nodes_;
- }
- BookmarkPermanentNodeList owned_extra_nodes() {
- return std::move(extra_nodes_);
- }
TitledUrlIndex* index() { return index_.get(); }
std::unique_ptr<TitledUrlIndex> owned_index() { return std::move(index_); }
@@ -119,23 +103,38 @@ class BookmarkLoadDetails {
void set_ids_reassigned(bool value) { ids_reassigned_ = value; }
bool ids_reassigned() const { return ids_reassigned_; }
+ void CreateUrlIndex();
+ std::unique_ptr<UrlIndex> owned_url_index() { return std::move(url_index_); }
+
private:
- std::unique_ptr<BookmarkPermanentNode> bb_node_;
- std::unique_ptr<BookmarkPermanentNode> other_folder_node_;
- std::unique_ptr<BookmarkPermanentNode> mobile_folder_node_;
+ // Creates one of the possible permanent nodes (bookmark bar node, other node
+ // and mobile node) from |type|. The node is added to (and owned by) |root_|.
+ BookmarkPermanentNode* CreatePermanentNode(BookmarkClient* client,
+ BookmarkNode::Type type);
+
+ std::unique_ptr<BookmarkNode> root_node_;
+ BookmarkNode* root_node_ptr_;
+ BookmarkPermanentNode* bb_node_ = nullptr;
+ BookmarkPermanentNode* other_folder_node_ = nullptr;
+ BookmarkPermanentNode* mobile_folder_node_ = nullptr;
LoadExtraCallback load_extra_callback_;
- BookmarkPermanentNodeList extra_nodes_;
std::unique_ptr<TitledUrlIndex> index_;
BookmarkNode::MetaInfoMap model_meta_info_map_;
int64_t model_sync_transaction_version_;
- int64_t max_id_;
+ int64_t max_id_ = 1;
std::string computed_checksum_;
std::string stored_checksum_;
- bool ids_reassigned_;
+ bool ids_reassigned_ = false;
+ std::unique_ptr<UrlIndex> url_index_;
DISALLOW_COPY_AND_ASSIGN(BookmarkLoadDetails);
};
+// Loads the bookmarks. This is intended to be called on the background thread.
+// Updates state in |details| based on the load.
+void LoadBookmarks(const base::FilePath& profile_path,
+ BookmarkLoadDetails* details);
+
// BookmarkStorage handles reading/write the bookmark bar model. The
// BookmarkModel uses the BookmarkStorage to load bookmarks from disk, as well
// as notifying the BookmarkStorage every time the model changes.
@@ -151,13 +150,6 @@ class BookmarkStorage : public base::ImportantFileWriter::DataSerializer {
base::SequencedTaskRunner* sequenced_task_runner);
~BookmarkStorage() override;
- // Loads the bookmarks into the model, notifying the model when done. This
- // takes ownership of |details| and send the |OnLoadFinished| callback from
- // a task in |task_runner|. See BookmarkLoadDetails for details.
- void LoadBookmarks(
- std::unique_ptr<BookmarkLoadDetails> details,
- const scoped_refptr<base::SequencedTaskRunner>& task_runner);
-
// Schedules saving the bookmark bar model to disk.
void ScheduleSave();
@@ -165,9 +157,6 @@ class BookmarkStorage : public base::ImportantFileWriter::DataSerializer {
// a pending save, it is saved immediately.
void BookmarkModelDeleted();
- // Callback from backend after loading the bookmark file.
- void OnLoadFinished(std::unique_ptr<BookmarkLoadDetails> details);
-
// ImportantFileWriter::DataSerializer implementation.
bool SerializeData(std::string* output) override;
diff --git a/chromium/components/bookmarks/browser/titled_url_index.cc b/chromium/components/bookmarks/browser/titled_url_index.cc
index 5cde7f530de..bacf382b7f1 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.cc
+++ b/chromium/components/bookmarks/browser/titled_url_index.cc
@@ -15,7 +15,6 @@
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/bookmarks/browser/titled_url_match.h"
#include "components/bookmarks/browser/titled_url_node.h"
-#include "components/bookmarks/browser/titled_url_node_sorter.h"
#include "components/query_parser/snippet.h"
#include "third_party/icu/source/common/unicode/normalizer2.h"
#include "third_party/icu/source/common/unicode/utypes.h"
@@ -55,6 +54,11 @@ TitledUrlIndex::TitledUrlIndex(std::unique_ptr<TitledUrlNodeSorter> sorter)
TitledUrlIndex::~TitledUrlIndex() {
}
+void TitledUrlIndex::SetNodeSorter(
+ std::unique_ptr<TitledUrlNodeSorter> sorter) {
+ sorter_ = std::move(sorter);
+}
+
void TitledUrlIndex::Add(const TitledUrlNode* node) {
std::vector<base::string16> terms =
ExtractQueryWords(Normalize(node->GetTitledUrlNodeTitle()));
diff --git a/chromium/components/bookmarks/browser/titled_url_index.h b/chromium/components/bookmarks/browser/titled_url_index.h
index f6df5980d2e..37602fb4909 100644
--- a/chromium/components/bookmarks/browser/titled_url_index.h
+++ b/chromium/components/bookmarks/browser/titled_url_index.h
@@ -14,12 +14,13 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/strings/string16.h"
+#include "components/bookmarks/browser/titled_url_node_sorter.h"
#include "components/query_parser/query_parser.h"
namespace bookmarks {
class TitledUrlNode;
-class TitledUrlNodeSorter;
+
struct TitledUrlMatch;
// TitledUrlIndex maintains an index of paired titles and URLs for quick lookup.
@@ -32,9 +33,12 @@ class TitledUrlIndex {
// Constructs a TitledUrlIndex. |sorter| is used to construct a sorted list
// of matches when matches are returned from the index. If null, matches are
// returned unsorted.
- TitledUrlIndex(std::unique_ptr<TitledUrlNodeSorter> sorter);
+ explicit TitledUrlIndex(
+ std::unique_ptr<TitledUrlNodeSorter> sorter = nullptr);
~TitledUrlIndex();
+ void SetNodeSorter(std::unique_ptr<TitledUrlNodeSorter> sorter);
+
// Invoked when a title/URL pair has been added to the model.
void Add(const TitledUrlNode* node);
diff --git a/chromium/components/bookmarks/browser/url_and_title.h b/chromium/components/bookmarks/browser/url_and_title.h
new file mode 100644
index 00000000000..c35a4549b63
--- /dev/null
+++ b/chromium/components/bookmarks/browser/url_and_title.h
@@ -0,0 +1,20 @@
+// 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 COMPONENTS_BOOKMARKS_BROWSER_URL_AND_TITLE_H_
+#define COMPONENTS_BOOKMARKS_BROWSER_URL_AND_TITLE_H_
+
+#include "base/strings/string16.h"
+#include "url/gurl.h"
+
+namespace bookmarks {
+
+struct UrlAndTitle {
+ GURL url;
+ base::string16 title;
+};
+
+} // namespace bookmarks
+
+#endif // COMPONENTS_BOOKMARKS_BROWSER_URL_AND_TITLE_H_
diff --git a/chromium/components/bookmarks/browser/url_index.cc b/chromium/components/bookmarks/browser/url_index.cc
new file mode 100644
index 00000000000..b8cbf91d174
--- /dev/null
+++ b/chromium/components/bookmarks/browser/url_index.cc
@@ -0,0 +1,135 @@
+// 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 "components/bookmarks/browser/url_index.h"
+
+#include "components/bookmarks/browser/url_and_title.h"
+
+namespace bookmarks {
+
+UrlIndex::UrlIndex(std::unique_ptr<BookmarkNode> root)
+ : root_(std::move(root)) {
+ base::AutoLock url_lock(url_lock_);
+ AddImpl(root_.get());
+}
+
+UrlIndex::~UrlIndex() = default;
+
+void UrlIndex::Add(BookmarkNode* parent,
+ int index,
+ std::unique_ptr<BookmarkNode> node) {
+ base::AutoLock url_lock(url_lock_);
+ AddImpl(parent->Add(std::move(node), index));
+}
+
+std::unique_ptr<BookmarkNode> UrlIndex::Remove(BookmarkNode* node,
+ std::set<GURL>* removed_urls) {
+ base::AutoLock url_lock(url_lock_);
+ RemoveImpl(node, removed_urls);
+ if (removed_urls) {
+ // RemoveImpl() adds an entry to removed_urls for each node of type URL. As
+ // duplicates are allowed we need to remove any entries that are still
+ // bookmarked.
+ for (auto i = removed_urls->begin(); i != removed_urls->end();) {
+ if (IsBookmarkedNoLock(*i)) {
+ // When we erase the iterator pointing at the erasee is
+ // invalidated, so using i++ here within the "erase" call is
+ // important as it advances the iterator before passing the
+ // old value through to erase.
+ removed_urls->erase(i++);
+ } else {
+ ++i;
+ }
+ }
+ }
+ return node->parent()->Remove(node);
+}
+
+void UrlIndex::SetUrl(BookmarkNode* node, const GURL& url) {
+ base::AutoLock url_lock(url_lock_);
+ RemoveImpl(node, nullptr);
+ node->set_url(url);
+ AddImpl(node);
+}
+
+void UrlIndex::GetNodesWithIconUrl(const GURL& icon_url,
+ std::set<const BookmarkNode*>* nodes) {
+ base::AutoLock url_lock(url_lock_);
+ for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
+ if (node->icon_url() && icon_url == *node->icon_url())
+ nodes->insert(node);
+ }
+}
+
+void UrlIndex::GetNodesByUrl(const GURL& url,
+ std::vector<const BookmarkNode*>* nodes) {
+ base::AutoLock url_lock(url_lock_);
+ BookmarkNode tmp_node(url);
+ auto i = nodes_ordered_by_url_set_.find(&tmp_node);
+ while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
+ nodes->push_back(*i);
+ ++i;
+ }
+}
+
+bool UrlIndex::HasBookmarks() {
+ base::AutoLock url_lock(url_lock_);
+ return !nodes_ordered_by_url_set_.empty();
+}
+
+bool UrlIndex::IsBookmarked(const GURL& url) {
+ base::AutoLock url_lock(url_lock_);
+ return IsBookmarkedNoLock(url);
+}
+
+void UrlIndex::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
+ base::AutoLock url_lock(url_lock_);
+ const GURL* last_url = nullptr;
+ for (auto i = nodes_ordered_by_url_set_.begin();
+ i != nodes_ordered_by_url_set_.end(); ++i) {
+ const GURL* url = &((*i)->url());
+ // Only add unique URLs.
+ if (!last_url || *url != *last_url) {
+ UrlAndTitle bookmark;
+ bookmark.url = *url;
+ bookmark.title = (*i)->GetTitle();
+ bookmarks->push_back(bookmark);
+ }
+ last_url = url;
+ }
+}
+
+bool UrlIndex::IsBookmarkedNoLock(const GURL& url) {
+ url_lock_.AssertAcquired();
+ BookmarkNode tmp_node(url);
+ return (nodes_ordered_by_url_set_.find(&tmp_node) !=
+ nodes_ordered_by_url_set_.end());
+}
+
+void UrlIndex::AddImpl(BookmarkNode* node) {
+ url_lock_.AssertAcquired();
+ if (node->is_url())
+ nodes_ordered_by_url_set_.insert(node);
+ for (int i = 0; i < node->child_count(); ++i)
+ AddImpl(node->GetChild(i));
+}
+
+void UrlIndex::RemoveImpl(BookmarkNode* node, std::set<GURL>* removed_urls) {
+ url_lock_.AssertAcquired();
+ if (node->is_url()) {
+ auto i = nodes_ordered_by_url_set_.find(node);
+ DCHECK(i != nodes_ordered_by_url_set_.end());
+ // i points to the first node with the URL, advance until we find the
+ // node we're removing.
+ while (*i != node)
+ ++i;
+ nodes_ordered_by_url_set_.erase(i);
+ if (removed_urls)
+ removed_urls->insert(node->url());
+ }
+ for (int i = node->child_count() - 1; i >= 0; --i)
+ RemoveImpl(node->GetChild(i), removed_urls);
+}
+
+} // namespace bookmarks
diff --git a/chromium/components/bookmarks/browser/url_index.h b/chromium/components/bookmarks/browser/url_index.h
new file mode 100644
index 00000000000..0386be37905
--- /dev/null
+++ b/chromium/components/bookmarks/browser/url_index.h
@@ -0,0 +1,92 @@
+// 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 COMPONENTS_BOOKMARKS_BROWSER_URL_INDEX_H_
+#define COMPONENTS_BOOKMARKS_BROWSER_URL_INDEX_H_
+
+#include <memory>
+#include <set>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "url/gurl.h"
+
+namespace bookmarks {
+
+class BookmarkNode;
+
+struct UrlAndTitle;
+
+// UrlIndex maintains the bookmark nodes of type url. The nodes are ordered by
+// url for lookup using the url. The mapping is done based on the nodes in the
+// model.
+//
+// This class is accessed on multiple threads, so all mutation to the underlying
+// set must be done while holding a lock. While this class is accessed on
+// multiple threads, all mutation happens on main thread.
+//
+// This class is an implementation detail of BookmarkModel and is not intended
+// to be public.
+class UrlIndex {
+ public:
+ explicit UrlIndex(std::unique_ptr<BookmarkNode> root);
+ ~UrlIndex();
+
+ BookmarkNode* root() { return root_.get(); }
+
+ // Adds |node| to |parent| at |index|.
+ void Add(BookmarkNode* parent, int index, std::unique_ptr<BookmarkNode> node);
+
+ // Removes |node| and all its descendants from the map, returns the set of
+ // urls that are no longer contained in the index.
+ std::unique_ptr<BookmarkNode> Remove(BookmarkNode* node,
+ std::set<GURL>* removed_urls);
+
+ void SetUrl(BookmarkNode* node, const GURL& url);
+
+ // Returns the nodes whose icon_url is |icon_url|.
+ void GetNodesWithIconUrl(const GURL& icon_url,
+ std::set<const BookmarkNode*>* nodes);
+
+ void GetNodesByUrl(const GURL& url, std::vector<const BookmarkNode*>* nodes);
+
+ // Returns true if there is at least one bookmark.
+ bool HasBookmarks();
+
+ bool IsBookmarked(const GURL& url);
+
+ void GetBookmarks(std::vector<UrlAndTitle>* bookmarks);
+
+ private:
+ // Used to order BookmarkNodes by URL.
+ class NodeUrlComparator {
+ public:
+ bool operator()(const BookmarkNode* n1, const BookmarkNode* n2) const {
+ return n1->url() < n2->url();
+ }
+ };
+
+ bool IsBookmarkedNoLock(const GURL& url);
+
+ void AddImpl(BookmarkNode* node);
+ void RemoveImpl(BookmarkNode* node, std::set<GURL>* removed_urls);
+
+ std::unique_ptr<BookmarkNode> root_;
+
+ // Set of nodes ordered by URL. This is not a map to avoid copying the
+ // urls.
+ // WARNING: |nodes_ordered_by_url_set_| is accessed on multiple threads. As
+ // such, be sure and wrap all usage of it around |url_lock_|.
+ using NodesOrderedByUrlSet = std::multiset<BookmarkNode*, NodeUrlComparator>;
+ NodesOrderedByUrlSet nodes_ordered_by_url_set_;
+ base::Lock url_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(UrlIndex);
+};
+
+} // namespace bookmarks
+
+#endif // COMPONENTS_BOOKMARKS_BROWSER_URL_INDEX_H_
diff --git a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
index c5aa3cb00de..0cd426ebe15 100644
--- a/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
+++ b/chromium/components/bookmarks/managed/managed_bookmarks_tracker_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -42,6 +43,7 @@ class ManagedBookmarksTrackerTest : public testing::Test {
void SetUp() override {
RegisterManagedBookmarksPrefs(prefs_.registry());
+ ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
}
void TearDown() override {
@@ -68,7 +70,7 @@ class ManagedBookmarksTrackerTest : public testing::Test {
model_->AddObserver(&observer_);
EXPECT_CALL(observer_, BookmarkModelLoaded(model_.get(), _));
- model_->Load(&prefs_, base::FilePath(),
+ model_->Load(&prefs_, scoped_temp_dir_.GetPath(),
base::ThreadTaskRunnerHandle::Get(),
base::ThreadTaskRunnerHandle::Get());
test::WaitForBookmarkModelToLoad(model_.get());
@@ -168,6 +170,7 @@ class ManagedBookmarksTrackerTest : public testing::Test {
return true;
}
+ base::ScopedTempDir scoped_temp_dir_;
base::MessageLoop loop_;
TestingPrefServiceSimple prefs_;
std::unique_ptr<BookmarkModel> model_;
diff --git a/chromium/components/browser_sync/BUILD.gn b/chromium/components/browser_sync/BUILD.gn
index 716f6762beb..a7643e27149 100644
--- a/chromium/components/browser_sync/BUILD.gn
+++ b/chromium/components/browser_sync/BUILD.gn
@@ -14,6 +14,8 @@ static_library("browser_sync") {
"profile_sync_service.h",
"signin_confirmation_helper.cc",
"signin_confirmation_helper.h",
+ "sync_auth_manager.cc",
+ "sync_auth_manager.h",
]
public_deps = [
@@ -88,6 +90,7 @@ source_set("unit_tests") {
"//components/webdata_services:test_support",
"//google_apis",
"//net",
+ "//services/identity/public/cpp:test_support",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/components/browser_sync/abstract_profile_sync_service_test.cc b/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
index a331fb14181..8c0b263579c 100644
--- a/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
+++ b/chromium/components/browser_sync/abstract_profile_sync_service_test.cc
@@ -25,6 +25,7 @@
using syncer::SyncBackendHostImpl;
using syncer::ModelType;
using testing::_;
+using testing::ByMove;
using testing::Return;
namespace browser_sync {
@@ -171,12 +172,13 @@ void AbstractProfileSyncServiceTest::CreateSyncService(
syncer::SyncApiComponentFactoryMock* components =
profile_sync_service_bundle_.component_factory();
+ auto engine = std::make_unique<SyncEngineForProfileSyncTest>(
+ temp_dir_.GetPath(), sync_service_->GetSyncClient(),
+ profile_sync_service_bundle_.fake_invalidation_service(),
+ sync_service_->sync_prefs()->AsWeakPtr(),
+ std::move(initialization_success_callback));
EXPECT_CALL(*components, CreateSyncEngine(_, _, _, _))
- .WillOnce(Return(new SyncEngineForProfileSyncTest(
- temp_dir_.GetPath(), sync_service_->GetSyncClient(),
- profile_sync_service_bundle_.fake_invalidation_service(),
- sync_service_->sync_prefs()->AsWeakPtr(),
- std::move(initialization_success_callback))));
+ .WillOnce(Return(ByMove(std::move(engine))));
sync_service_->SetFirstSetupComplete();
}
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
index 8eb5fb2810f..156c5829386 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.cc
@@ -12,7 +12,6 @@
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_wallet_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autocomplete_sync_bridge.h"
-#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/autofill/core/browser/webdata/web_data_model_type_controller.h"
@@ -69,6 +68,18 @@ syncer::ModelTypeSet GetDisabledTypesFromCommandLine(
return disabled_types;
}
+// This helper function only wraps
+// autofill::AutocompleteSyncBridge::FromWebDataService(). This way, it
+// simplifies life for the compiler which cannot directly cast
+// "WeakPtr<ModelTypeSyncBridge> (AutofillWebDataService*)" to
+// "WeakPtr<ModelTypeControllerDelegate> (AutofillWebDataService*)".
+base::WeakPtr<syncer::ModelTypeControllerDelegate> DelegateFromDataService(
+ autofill::AutofillWebDataService* service) {
+ return autofill::AutocompleteSyncBridge::FromWebDataService(service)
+ ->change_processor()
+ ->GetControllerDelegateOnUIThread();
+}
+
} // namespace
ProfileSyncComponentsFactoryImpl::ProfileSyncComponentsFactoryImpl(
@@ -128,8 +139,7 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
sync_service->RegisterDataTypeController(
std::make_unique<autofill::WebDataModelTypeController>(
syncer::AUTOFILL, sync_client_, db_thread_, web_data_service_,
- base::Bind(
- &autofill::AutocompleteSyncBridge::FromWebDataService)));
+ base::Bind(&DelegateFromDataService)));
}
// Autofill sync is enabled by default. Register unless explicitly
@@ -198,11 +208,17 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
if (!disabled_types.Has(syncer::PROXY_TABS)) {
sync_service->RegisterDataTypeController(
std::make_unique<ProxyDataTypeController>(syncer::PROXY_TABS));
- sync_service->RegisterDataTypeController(
- std::make_unique<SessionDataTypeController>(
- error_callback, sync_client_,
- sync_service->GetLocalDeviceInfoProvider(),
- history_disabled_pref_));
+ if (FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
+ sync_service->RegisterDataTypeController(
+ std::make_unique<ModelTypeController>(syncer::SESSIONS,
+ sync_client_, ui_thread_));
+ } else {
+ sync_service->RegisterDataTypeController(
+ std::make_unique<SessionDataTypeController>(
+ error_callback, sync_client_,
+ sync_service->GetLocalDeviceInfoProvider(),
+ history_disabled_pref_));
+ }
}
// Favicon sync is enabled by default. Register unless explicitly disabled.
@@ -282,7 +298,8 @@ void ProfileSyncComponentsFactoryImpl::RegisterCommonDataTypes(
}
}
-DataTypeManager* ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
+std::unique_ptr<DataTypeManager>
+ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
syncer::ModelTypeSet initial_types,
const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
debug_info_listener,
@@ -290,18 +307,19 @@ DataTypeManager* ProfileSyncComponentsFactoryImpl::CreateDataTypeManager(
const syncer::DataTypeEncryptionHandler* encryption_handler,
syncer::ModelTypeConfigurer* configurer,
DataTypeManagerObserver* observer) {
- return new DataTypeManagerImpl(sync_client_, initial_types,
- debug_info_listener, controllers,
- encryption_handler, configurer, observer);
+ return std::make_unique<DataTypeManagerImpl>(
+ sync_client_, initial_types, debug_info_listener, controllers,
+ encryption_handler, configurer, observer);
}
-syncer::SyncEngine* ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
+std::unique_ptr<syncer::SyncEngine>
+ProfileSyncComponentsFactoryImpl::CreateSyncEngine(
const std::string& name,
invalidation::InvalidationService* invalidator,
const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
const base::FilePath& sync_data_folder) {
- return new syncer::SyncBackendHostImpl(name, sync_client_, invalidator,
- sync_prefs, sync_data_folder);
+ return std::make_unique<syncer::SyncBackendHostImpl>(
+ name, sync_client_, invalidator, sync_prefs, sync_data_folder);
}
std::unique_ptr<syncer::LocalDeviceInfoProvider>
diff --git a/chromium/components/browser_sync/profile_sync_components_factory_impl.h b/chromium/components/browser_sync/profile_sync_components_factory_impl.h
index d72ed962a82..3d27b5ecbf5 100644
--- a/chromium/components/browser_sync/profile_sync_components_factory_impl.h
+++ b/chromium/components/browser_sync/profile_sync_components_factory_impl.h
@@ -46,7 +46,7 @@ class ProfileSyncComponentsFactoryImpl
void RegisterDataTypes(
syncer::SyncService* sync_service,
const RegisterDataTypesMethod& register_platform_types_method) override;
- syncer::DataTypeManager* CreateDataTypeManager(
+ std::unique_ptr<syncer::DataTypeManager> CreateDataTypeManager(
syncer::ModelTypeSet initial_types,
const syncer::WeakHandle<syncer::DataTypeDebugInfoListener>&
debug_info_listener,
@@ -54,7 +54,7 @@ class ProfileSyncComponentsFactoryImpl
const syncer::DataTypeEncryptionHandler* encryption_handler,
syncer::ModelTypeConfigurer* configurer,
syncer::DataTypeManagerObserver* observer) override;
- syncer::SyncEngine* CreateSyncEngine(
+ std::unique_ptr<syncer::SyncEngine> CreateSyncEngine(
const std::string& name,
invalidation::InvalidationService* invalidator,
const base::WeakPtr<syncer::SyncPrefs>& sync_prefs,
diff --git a/chromium/components/browser_sync/profile_sync_service.cc b/chromium/components/browser_sync/profile_sync_service.cc
index edb33dafe55..348bcf10291 100644
--- a/chromium/components/browser_sync/profile_sync_service.cc
+++ b/chromium/components/browser_sync/profile_sync_service.cc
@@ -16,14 +16,14 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram_macros.h"
-#include "base/threading/thread_restrictions.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/browser_sync/browser_sync_switches.h"
+#include "components/browser_sync/sync_auth_manager.h"
#include "components/invalidation/impl/invalidation_prefs.h"
#include "components/invalidation/public/invalidation_service.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/reading_list/features/reading_list_buildflags.h"
-#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "components/signin/core/browser/account_info.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_metrics.h"
#include "components/sync/base/bind_to_task_runner.h"
@@ -37,7 +37,6 @@
#include "components/sync/device_info/device_info_tracker.h"
#include "components/sync/driver/backend_migrator.h"
#include "components/sync/driver/directory_data_type_controller.h"
-#include "components/sync/driver/glue/sync_backend_host_impl.h"
#include "components/sync/driver/signin_manager_wrapper.h"
#include "components/sync/driver/sync_api_component_factory.h"
#include "components/sync/driver/sync_driver_switches.h"
@@ -46,10 +45,11 @@
#include "components/sync/driver/sync_util.h"
#include "components/sync/driver/user_selectable_sync_type.h"
#include "components/sync/engine/configure_reason.h"
-#include "components/sync/engine/cycle/model_neutral_state.h"
#include "components/sync/engine/cycle/type_debug_info_observer.h"
+#include "components/sync/engine/engine_components_factory_impl.h"
#include "components/sync/engine/net/http_bridge_network_resources.h"
#include "components/sync/engine/net/network_resources.h"
+#include "components/sync/engine/polling_constants.h"
#include "components/sync/engine/sync_encryption_handler.h"
#include "components/sync/engine/sync_string_conversions.h"
#include "components/sync/js/js_event_details.h"
@@ -57,43 +57,38 @@
#include "components/sync/model/model_type_change_processor.h"
#include "components/sync/model/sync_error.h"
#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
-#include "components/sync/protocol/sync.pb.h"
#include "components/sync/syncable/directory.h"
-#include "components/sync/syncable/sync_db_util.h"
#include "components/sync/syncable/syncable_read_transaction.h"
#include "components/sync_preferences/pref_service_syncable.h"
#include "components/sync_sessions/favicon_cache.h"
#include "components/sync_sessions/session_data_type_controller.h"
+#include "components/sync_sessions/session_sync_bridge.h"
#include "components/sync_sessions/sessions_sync_manager.h"
#include "components/sync_sessions/sync_sessions_client.h"
#include "components/version_info/version_info_values.h"
-#include "net/cookies/cookie_monster.h"
#include "net/url_request/url_request_context_getter.h"
-#if defined(OS_ANDROID)
-#include "components/sync/syncable/read_transaction.h"
-#endif
-
-using sync_sessions::SessionsSyncManager;
using syncer::BackendMigrator;
-using syncer::ChangeProcessor;
using syncer::ClientTagBasedModelTypeProcessor;
using syncer::DataTypeController;
using syncer::DataTypeManager;
using syncer::DataTypeStatusTable;
using syncer::DeviceInfoSyncBridge;
+using syncer::EngineComponentsFactory;
+using syncer::EngineComponentsFactoryImpl;
using syncer::JsBackend;
using syncer::JsController;
-using syncer::JsEventDetails;
using syncer::JsEventHandler;
using syncer::ModelSafeRoutingInfo;
using syncer::ModelType;
-using syncer::ModelTypeChangeProcessor;
using syncer::ModelTypeSet;
using syncer::ModelTypeStore;
using syncer::ProtocolEventObserver;
-using syncer::SyncEngine;
+using syncer::SyncBackendRegistrar;
+using syncer::SyncClient;
using syncer::SyncCredentials;
+using syncer::SyncEngine;
+using syncer::SyncManagerFactory;
using syncer::SyncProtocolError;
using syncer::WeakHandle;
@@ -101,35 +96,44 @@ namespace browser_sync {
namespace {
-const char kSyncUnrecoverableErrorHistogram[] = "Sync.UnrecoverableErrors";
-
-const net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
- // Number of initial errors (in sequence) to ignore before applying
- // exponential back-off rules.
- 0,
+constexpr char kSyncUnrecoverableErrorHistogram[] = "Sync.UnrecoverableErrors";
- // Initial delay for exponential back-off in ms.
- 2000,
+constexpr base::FilePath::CharType kSyncDataFolderName[] =
+ FILE_PATH_LITERAL("Sync Data");
- // Factor by which the waiting time will be multiplied.
- 2,
+constexpr base::FilePath::CharType kLevelDBFolderName[] =
+ FILE_PATH_LITERAL("LevelDB");
- // Fuzzing percentage. ex: 10% will spread requests randomly
- // between 90%-100% of the calculated time.
- 0.2, // 20%
+base::FilePath FormatSyncDataPath(const base::FilePath& base_directory) {
+ return base_directory.Append(base::FilePath(kSyncDataFolderName));
+}
- // Maximum amount of time we are willing to delay our request in ms.
- // TODO(pavely): crbug.com/246686 ProfileSyncService should retry
- // RequestAccessToken on connection state change after backoff
- 1000 * 3600 * 4, // 4 hours.
+base::FilePath FormatSharedModelTypeStorePath(
+ const base::FilePath& base_directory) {
+ return FormatSyncDataPath(base_directory)
+ .Append(base::FilePath(kLevelDBFolderName));
+}
- // Time to keep an entry from being discarded even when it
- // has no significant state, -1 to never discard.
- -1,
+EngineComponentsFactory::Switches EngineSwitchesFromCommandLine() {
+ EngineComponentsFactory::Switches factory_switches = {
+ EngineComponentsFactory::ENCRYPTION_KEYSTORE,
+ EngineComponentsFactory::BACKOFF_NORMAL};
- // Don't use initial delay unless the last request was an error.
- false,
-};
+ base::CommandLine* cl = base::CommandLine::ForCurrentProcess();
+ if (cl->HasSwitch(switches::kSyncShortInitialRetryOverride)) {
+ factory_switches.backoff_override =
+ EngineComponentsFactory::BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE;
+ }
+ if (cl->HasSwitch(switches::kSyncEnableGetUpdateAvoidance)) {
+ factory_switches.pre_commit_updates_policy =
+ EngineComponentsFactory::FORCE_ENABLE_PRE_COMMIT_UPDATE_AVOIDANCE;
+ }
+ if (cl->HasSwitch(switches::kSyncShortNudgeDelayForTest)) {
+ factory_switches.nudge_delay =
+ EngineComponentsFactory::NudgeDelay::SHORT_NUDGE_DELAY;
+ }
+ return factory_switches;
+}
} // namespace
@@ -138,41 +142,43 @@ ProfileSyncService::InitParams::InitParams(InitParams&& other) = default;
ProfileSyncService::InitParams::~InitParams() = default;
ProfileSyncService::ProfileSyncService(InitParams init_params)
- : SyncServiceBase(std::move(init_params.sync_client),
- std::move(init_params.signin_wrapper),
- init_params.channel,
- init_params.base_directory,
- init_params.debug_identifier),
- OAuth2TokenService::Consumer("sync"),
- signin_scoped_device_id_callback_(
- init_params.signin_scoped_device_id_callback),
- last_auth_error_(GoogleServiceAuthError::AuthErrorNone()),
+ : sync_client_(std::move(init_params.sync_client)),
+ sync_prefs_(sync_client_->GetPrefService()),
+ signin_(std::move(init_params.signin_wrapper)),
+ auth_manager_(std::make_unique<SyncAuthManager>(
+ this,
+ &sync_prefs_,
+ signin_ ? signin_->GetIdentityManager() : nullptr,
+ init_params.oauth2_token_service)),
+ channel_(init_params.channel),
+ base_directory_(init_params.base_directory),
+ debug_identifier_(init_params.debug_identifier),
sync_service_url_(
syncer::GetSyncServiceURL(*base::CommandLine::ForCurrentProcess(),
init_params.channel)),
+ signin_scoped_device_id_callback_(
+ init_params.signin_scoped_device_id_callback),
network_time_update_callback_(
std::move(init_params.network_time_update_callback)),
url_request_context_(init_params.url_request_context),
is_first_time_sync_configure_(false),
engine_initialized_(false),
sync_disabled_by_admin_(false),
- is_auth_in_progress_(false),
unrecoverable_error_reason_(ERROR_REASON_UNSET),
expect_sync_configuration_aborted_(false),
- configure_status_(DataTypeManager::UNKNOWN),
- oauth2_token_service_(init_params.oauth2_token_service),
- request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
- connection_status_(syncer::CONNECTION_NOT_ATTEMPTED),
- last_get_token_error_(GoogleServiceAuthError::AuthErrorNone()),
gaia_cookie_manager_service_(init_params.gaia_cookie_manager_service),
- network_resources_(new syncer::HttpBridgeNetworkResources),
+ network_resources_(
+ std::make_unique<syncer::HttpBridgeNetworkResources>()),
start_behavior_(init_params.start_behavior),
passphrase_prompt_triggered_by_version_(false),
sync_enabled_weak_factory_(this),
weak_factory_(this) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(signin_scoped_device_id_callback_);
DCHECK(sync_client_);
+
+ ResetCryptoState();
+
std::string last_version = sync_prefs_.GetLastRunVersion();
std::string current_version = PRODUCT_VERSION;
sync_prefs_.SetLastRunVersion(current_version);
@@ -192,7 +198,7 @@ ProfileSyncService::ProfileSyncService(InitParams init_params)
}
ProfileSyncService::~ProfileSyncService() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (gaia_cookie_manager_service_)
gaia_cookie_manager_service_->RemoveObserver(this);
sync_prefs_.RemoveSyncPrefObserver(this);
@@ -201,31 +207,47 @@ ProfileSyncService::~ProfileSyncService() {
}
bool ProfileSyncService::CanSyncStart() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return (IsSyncAllowed() && IsSyncRequested() &&
(IsLocalSyncEnabled() || IsSignedIn()));
}
void ProfileSyncService::Initialize() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sync_client_->Initialize();
// We don't pass StartupController an Unretained reference to future-proof
// against the controller impl changing to post tasks.
startup_controller_ = std::make_unique<syncer::StartupController>(
&sync_prefs_,
- base::Bind(&ProfileSyncService::CanEngineStart, base::Unretained(this)),
- base::Bind(&ProfileSyncService::StartUpSlowEngineComponents,
- weak_factory_.GetWeakPtr()));
+ base::BindRepeating(&ProfileSyncService::CanEngineStart,
+ base::Unretained(this)),
+ base::BindRepeating(&ProfileSyncService::StartUpSlowEngineComponents,
+ weak_factory_.GetWeakPtr()));
local_device_ = sync_client_->GetSyncApiComponentFactory()
->CreateLocalDeviceInfoProvider();
sync_stopped_reporter_ = std::make_unique<syncer::SyncStoppedReporter>(
sync_service_url_, local_device_->GetSyncUserAgent(),
url_request_context_, syncer::SyncStoppedReporter::ResultCallback());
- sessions_sync_manager_ = std::make_unique<SessionsSyncManager>(
- sync_client_->GetSyncSessionsClient(), &sync_prefs_, local_device_.get(),
- base::Bind(&ProfileSyncService::NotifyForeignSessionUpdated,
- sync_enabled_weak_factory_.GetWeakPtr()));
+
+ if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
+ sessions_sync_manager_ = std::make_unique<sync_sessions::SessionSyncBridge>(
+ sync_client_->GetSyncSessionsClient(), &sync_prefs_,
+ local_device_.get(), model_type_store_factory_,
+ base::BindRepeating(&ProfileSyncService::NotifyForeignSessionUpdated,
+ sync_enabled_weak_factory_.GetWeakPtr()),
+ std::make_unique<ClientTagBasedModelTypeProcessor>(
+ syncer::SESSIONS,
+ base::BindRepeating(&syncer::ReportUnrecoverableError, channel_)));
+ } else {
+ sessions_sync_manager_ =
+ std::make_unique<sync_sessions::SessionsSyncManager>(
+ sync_client_->GetSyncSessionsClient(), &sync_prefs_,
+ local_device_.get(),
+ base::BindRepeating(
+ &ProfileSyncService::NotifyForeignSessionUpdated,
+ sync_enabled_weak_factory_.GetWeakPtr()));
+ }
device_info_sync_bridge_ = std::make_unique<DeviceInfoSyncBridge>(
local_device_.get(), model_type_store_factory_,
@@ -279,7 +301,7 @@ void ProfileSyncService::Initialize() {
}
if (!IsLocalSyncEnabled()) {
- RegisterAuthNotifications();
+ auth_manager_->RegisterForAuthNotifications();
if (!IsSignedIn()) {
// Clean up in case of previous crash during signout.
@@ -303,8 +325,8 @@ void ProfileSyncService::Initialize() {
#endif
memory_pressure_listener_ = std::make_unique<base::MemoryPressureListener>(
- base::Bind(&ProfileSyncService::OnMemoryPressure,
- sync_enabled_weak_factory_.GetWeakPtr()));
+ base::BindRepeating(&ProfileSyncService::OnMemoryPressure,
+ sync_enabled_weak_factory_.GetWeakPtr()));
startup_controller_->Reset(GetRegisteredDataTypes());
// Auto-start means the first time the profile starts up, sync should start up
@@ -334,24 +356,9 @@ void ProfileSyncService::StartSyncingWithServer() {
engine_->StartSyncingWithServer();
}
-void ProfileSyncService::RegisterAuthNotifications() {
- DCHECK(thread_checker_.CalledOnValidThread());
- oauth2_token_service_->AddObserver(this);
- if (signin_)
- signin_->GetSigninManager()->AddObserver(this);
-}
-
-void ProfileSyncService::UnregisterAuthNotifications() {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (signin_)
- signin_->GetSigninManager()->RemoveObserver(this);
- if (oauth2_token_service_)
- oauth2_token_service_->RemoveObserver(this);
-}
-
void ProfileSyncService::RegisterDataTypeController(
- std::unique_ptr<syncer::DataTypeController> data_type_controller) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ std::unique_ptr<DataTypeController> data_type_controller) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_EQ(data_type_controllers_.count(data_type_controller->type()), 0U);
data_type_controllers_[data_type_controller->type()] =
std::move(data_type_controller);
@@ -359,7 +366,7 @@ void ProfileSyncService::RegisterDataTypeController(
bool ProfileSyncService::IsDataTypeControllerRunning(
syncer::ModelType type) const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DataTypeController::TypeMap::const_iterator iter =
data_type_controllers_.find(type);
if (iter == data_type_controllers_.end()) {
@@ -369,7 +376,7 @@ bool ProfileSyncService::IsDataTypeControllerRunning(
}
sync_sessions::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Although the backing data actually is of type |SESSIONS|, the desire to use
// open tabs functionality is tracked by the state of the |PROXY_TABS| type.
if (!IsDataTypeControllerRunning(syncer::PROXY_TABS)) {
@@ -381,32 +388,23 @@ sync_sessions::OpenTabsUIDelegate* ProfileSyncService::GetOpenTabsUIDelegate() {
}
sync_sessions::FaviconCache* ProfileSyncService::GetFaviconCache() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sessions_sync_manager_->GetFaviconCache();
}
syncer::DeviceInfoTracker* ProfileSyncService::GetDeviceInfoTracker() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return device_info_sync_bridge_.get();
}
syncer::LocalDeviceInfoProvider*
ProfileSyncService::GetLocalDeviceInfoProvider() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return local_device_.get();
}
-void ProfileSyncService::GetDataTypeControllerStates(
- DataTypeController::StateMap* state_map) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- for (DataTypeController::TypeMap::const_iterator iter =
- data_type_controllers_.begin();
- iter != data_type_controllers_.end(); ++iter)
- (*state_map)[iter->first] = iter->second.get()->state();
-}
-
void ProfileSyncService::OnSessionRestoreComplete() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DataTypeController::TypeMap::const_iterator iter =
data_type_controllers_.find(syncer::SESSIONS);
if (iter == data_type_controllers_.end()) {
@@ -414,28 +412,12 @@ void ProfileSyncService::OnSessionRestoreComplete() {
}
DCHECK(iter->second);
- static_cast<sync_sessions::SessionDataTypeController*>(iter->second.get())
- ->OnSessionRestoreComplete();
-}
-
-SyncCredentials ProfileSyncService::GetCredentials() {
- SyncCredentials credentials;
-
- // No credentials exist or are needed for the local sync backend.
- if (IsLocalSyncEnabled())
- return credentials;
-
- credentials.account_id = signin_->GetAccountIdToUse();
- DCHECK(!credentials.account_id.empty());
- credentials.email = signin_->GetEffectiveUsername();
- credentials.sync_token = access_token_;
-
- if (credentials.sync_token.empty())
- credentials.sync_token = "credentials_lost";
-
- credentials.scope_set.insert(signin_->GetSyncScopeToUse());
-
- return credentials;
+ if (base::FeatureList::IsEnabled(switches::kSyncUSSSessions)) {
+ sessions_sync_manager_->OnSessionRestoreComplete();
+ } else {
+ static_cast<sync_sessions::SessionDataTypeController*>(iter->second.get())
+ ->OnSessionRestoreComplete();
+ }
}
syncer::WeakHandle<syncer::JsEventHandler>
@@ -445,9 +427,10 @@ ProfileSyncService::GetJsEventHandler() {
syncer::SyncEngine::HttpPostProviderFactoryGetter
ProfileSyncService::MakeHttpPostProviderFactoryGetter() {
- return base::Bind(&syncer::NetworkResources::GetHttpPostProviderFactory,
- base::Unretained(network_resources_.get()),
- url_request_context_, network_time_update_callback_);
+ return base::BindRepeating(
+ &syncer::NetworkResources::GetHttpPostProviderFactory,
+ base::Unretained(network_resources_.get()), url_request_context_,
+ network_time_update_callback_);
}
syncer::WeakHandle<syncer::UnrecoverableErrorHandler>
@@ -455,6 +438,15 @@ ProfileSyncService::GetUnrecoverableErrorHandler() {
return syncer::MakeWeakHandle(sync_enabled_weak_factory_.GetWeakPtr());
}
+void ProfileSyncService::ResetCryptoState() {
+ crypto_ = std::make_unique<syncer::SyncServiceCrypto>(
+ base::BindRepeating(&ProfileSyncService::NotifyObservers,
+ base::Unretained(this)),
+ base::BindRepeating(&ProfileSyncService::GetPreferredDataTypes,
+ base::Unretained(this)),
+ &sync_prefs_);
+}
+
bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
if (encryption_pending())
return true;
@@ -465,7 +457,7 @@ bool ProfileSyncService::IsEncryptedDatatypeEnabled() const {
}
void ProfileSyncService::OnProtocolEvent(const syncer::ProtocolEvent& event) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : protocol_event_observers_)
observer.OnProtocolEvent(event);
}
@@ -473,7 +465,7 @@ void ProfileSyncService::OnProtocolEvent(const syncer::ProtocolEvent& event) {
void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
syncer::ModelType type,
const syncer::CommitCounters& counters) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : type_debug_info_observers_)
observer.OnCommitCountersUpdated(type, counters);
}
@@ -481,7 +473,7 @@ void ProfileSyncService::OnDirectoryTypeCommitCounterUpdated(
void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
syncer::ModelType type,
const syncer::UpdateCounters& counters) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : type_debug_info_observers_)
observer.OnUpdateCountersUpdated(type, counters);
}
@@ -489,13 +481,13 @@ void ProfileSyncService::OnDirectoryTypeUpdateCounterUpdated(
void ProfileSyncService::OnDatatypeStatusCounterUpdated(
syncer::ModelType type,
const syncer::StatusCounters& counters) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
for (auto& observer : type_debug_info_observers_)
observer.OnStatusCountersUpdated(type, counters);
}
void ProfileSyncService::OnDataTypeRequestsSyncStartup(syncer::ModelType type) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(syncer::UserTypes().Has(type));
if (!GetPreferredDataTypes().Has(type)) {
@@ -529,9 +521,9 @@ void ProfileSyncService::StartUpSlowEngineComponents() {
invalidation::InvalidationService* invalidator =
sync_client_->GetInvalidationService();
- engine_.reset(sync_client_->GetSyncApiComponentFactory()->CreateSyncEngine(
+ engine_ = sync_client_->GetSyncApiComponentFactory()->CreateSyncEngine(
debug_identifier_, invalidator, sync_prefs_.AsWeakPtr(),
- FormatSyncDataPath(base_directory_)));
+ FormatSyncDataPath(base_directory_));
// Clear any old errors the first time sync starts.
if (!IsFirstSetupComplete())
@@ -544,138 +536,121 @@ void ProfileSyncService::StartUpSlowEngineComponents() {
ReportPreviousSessionMemoryWarningCount();
}
-void ProfileSyncService::OnGetTokenSuccess(
- const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(access_token_request_.get(), request);
- access_token_request_.reset();
- access_token_ = access_token;
- token_receive_time_ = base::Time::Now();
- last_get_token_error_ = GoogleServiceAuthError::AuthErrorNone();
+void ProfileSyncService::InitializeEngine() {
+ DCHECK(engine_);
+
+ if (!sync_thread_) {
+ sync_thread_ = std::make_unique<base::Thread>("Chrome_SyncThread");
+ base::Thread::Options options;
+ options.timer_slack = base::TIMER_SLACK_MAXIMUM;
+ bool success = sync_thread_->StartWithOptions(options);
+ DCHECK(success);
+ }
+
+ SyncEngine::InitParams params;
+ params.sync_task_runner = sync_thread_->task_runner();
+ params.host = this;
+ params.registrar = std::make_unique<SyncBackendRegistrar>(
+ debug_identifier_,
+ base::BindRepeating(&SyncClient::CreateModelWorkerForGroup,
+ base::Unretained(sync_client_.get())));
+ params.encryption_observer_proxy = crypto_->GetEncryptionObserverProxy();
+ params.extensions_activity = sync_client_->GetExtensionsActivity();
+ params.event_handler = GetJsEventHandler();
+ params.service_url = sync_service_url();
+ params.sync_user_agent = GetLocalDeviceInfoProvider()->GetSyncUserAgent();
+ params.http_factory_getter = MakeHttpPostProviderFactoryGetter();
+ params.credentials = auth_manager_->GetCredentials();
+ DCHECK(!params.credentials.account_id.empty() || IsLocalSyncEnabled());
+ invalidation::InvalidationService* invalidator =
+ sync_client_->GetInvalidationService();
+ params.invalidator_client_id =
+ invalidator ? invalidator->GetInvalidatorClientId() : "",
+ params.sync_manager_factory = std::make_unique<SyncManagerFactory>();
+ // The first time we start up the engine we want to ensure we have a clean
+ // directory, so delete any old one that might be there.
+ params.delete_sync_data_folder = !IsFirstSetupComplete();
+ params.enable_local_sync_backend = sync_prefs_.IsLocalSyncEnabled();
+ params.local_sync_backend_folder = sync_client_->GetLocalSyncBackendFolder();
+ params.restored_key_for_bootstrapping =
+ sync_prefs_.GetEncryptionBootstrapToken();
+ params.restored_keystore_key_for_bootstrapping =
+ sync_prefs_.GetKeystoreEncryptionBootstrapToken();
+ params.engine_components_factory =
+ std::make_unique<EngineComponentsFactoryImpl>(
+ EngineSwitchesFromCommandLine());
+ params.unrecoverable_error_handler = GetUnrecoverableErrorHandler();
+ params.report_unrecoverable_error_function =
+ base::BindRepeating(syncer::ReportUnrecoverableError, channel_);
+ params.saved_nigori_state = crypto_->TakeSavedNigoriState();
+ sync_prefs_.GetInvalidationVersions(&params.invalidation_versions);
+ params.short_poll_interval = sync_prefs_.GetShortPollInterval();
+ if (params.short_poll_interval.is_zero()) {
+ params.short_poll_interval =
+ base::TimeDelta::FromSeconds(syncer::kDefaultShortPollIntervalSeconds);
+ }
+ params.long_poll_interval = sync_prefs_.GetLongPollInterval();
+ if (params.long_poll_interval.is_zero()) {
+ params.long_poll_interval =
+ base::TimeDelta::FromSeconds(syncer::kDefaultLongPollIntervalSeconds);
+ }
+
+ engine_->Initialize(std::move(params));
+}
+
+void ProfileSyncService::AccessTokenFetched(
+ const GoogleServiceAuthError& error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (sync_prefs_.SyncHasAuthError()) {
- sync_prefs_.SetSyncAuthError(false);
+ if (error.state() == GoogleServiceAuthError::NONE) {
+ if (HasSyncingEngine()) {
+ engine_->UpdateCredentials(auth_manager_->GetCredentials());
+ } else {
+ startup_controller_->TryStart();
+ }
}
+ // Else: Some error happened. SyncAuthManager takes care of that (retry if
+ // appropriate etc), so there's nothing for us to do here.
- if (HasSyncingEngine())
- engine_->UpdateCredentials(GetCredentials());
- else
- startup_controller_->TryStart();
-
- UpdateAuthErrorState(GoogleServiceAuthError(GoogleServiceAuthError::NONE));
+ NotifyObservers();
}
-void ProfileSyncService::OnGetTokenFailure(
- const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(access_token_request_.get(), request);
- DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
- access_token_request_.reset();
- last_get_token_error_ = error;
- switch (error.state()) {
- case GoogleServiceAuthError::CONNECTION_FAILED:
- case GoogleServiceAuthError::REQUEST_CANCELED:
- case GoogleServiceAuthError::SERVICE_ERROR:
- case GoogleServiceAuthError::SERVICE_UNAVAILABLE: {
- // Transient error. Retry after some time.
- request_access_token_backoff_.InformOfRequest(false);
- next_token_request_time_ =
- base::Time::Now() +
- request_access_token_backoff_.GetTimeUntilRelease();
- request_access_token_retry_timer_.Start(
- FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
- base::Bind(&ProfileSyncService::RequestAccessToken,
- sync_enabled_weak_factory_.GetWeakPtr()));
- NotifyObservers();
- break;
- }
- case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: {
- if (!sync_prefs_.SyncHasAuthError()) {
- sync_prefs_.SetSyncAuthError(true);
- UMA_HISTOGRAM_ENUMERATION("Sync.SyncAuthError", AUTH_ERROR_ENCOUNTERED,
- AUTH_ERROR_LIMIT);
- }
- FALLTHROUGH;
- }
- default: {
- if (error.state() != GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS) {
- LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
- }
- // Show error to user.
- UpdateAuthErrorState(error);
- }
- }
-}
+void ProfileSyncService::OnRefreshTokenAvailable() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-void ProfileSyncService::OnRefreshTokenAvailable(
- const std::string& account_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (account_id == signin_->GetAccountIdToUse())
- OnRefreshTokensLoaded();
-}
-
-void ProfileSyncService::OnRefreshTokenRevoked(const std::string& account_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (account_id == signin_->GetAccountIdToUse()) {
- access_token_.clear();
- UpdateAuthErrorState(
- GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
- }
-}
-
-void ProfileSyncService::OnRefreshTokensLoaded() {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- GoogleServiceAuthError token_error =
- oauth2_token_service_->GetAuthError(signin_->GetAccountIdToUse());
- if (token_error == GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
- GoogleServiceAuthError::InvalidGaiaCredentialsReason::
- CREDENTIALS_REJECTED_BY_CLIENT)) {
- // When the refresh token is replaced by a new token with a
- // CREDENTIALS_REJECTED_BY_CLIENT error, Sync must be stopped immediately,
- // even if the current access token is still valid. This happens e.g. when
- // the user signs out of the web with Dice enabled.
- // It is not necessary to do this when the refresh token is
- // CREDENTIALS_REJECTED_BY_SERVER, because in that case the access token
- // will be rejected by the server too.
- // We only do this in OnRefreshTokensLoaded(), as opposed to
- // OAuth2TokenService::Observer::OnAuthErrorChanged(), because
- // CREDENTIALS_REJECTED_BY_CLIENT is only set by the signin component when
- // the refresh token is created.
- access_token_.clear();
- request_access_token_retry_timer_.Stop();
- access_token_request_.reset();
- is_auth_in_progress_ = false;
- if (HasSyncingEngine())
- engine_->InvalidateCredentials();
- }
-
- // This notification gets fired when OAuth2TokenService loads the tokens from
- // storage. Initialize the engine if sync is enabled. If the sync token was
- // not loaded, GetCredentials() will generate invalid credentials to cause the
- // engine to generate an auth error (crbug.com/121755).
if (HasSyncingEngine()) {
- RequestAccessToken();
+ auth_manager_->RequestAccessToken();
} else {
startup_controller_->TryStart();
}
}
+void ProfileSyncService::OnRefreshTokenRevoked() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (HasSyncingEngine())
+ engine_->InvalidateCredentials();
+
+ NotifyObservers();
+}
+
void ProfileSyncService::Shutdown() {
- DCHECK(thread_checker_.CalledOnValidThread());
- UnregisterAuthNotifications();
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
ShutdownImpl(syncer::BROWSER_SHUTDOWN);
NotifyShutdown();
+ // TODO(treib): DCHECK that all observers are gone now. All KeyedServices
+ // should have unregistered their observers already before, in their own
+ // Shutdown(), and all others should have done it now when they got the
+ // shutdown notification.
if (sync_error_controller_) {
// Destroy the SyncErrorController when the service shuts down for good.
RemoveObserver(sync_error_controller_.get());
sync_error_controller_.reset();
}
+ auth_manager_.reset();
+
signin_scoped_device_id_callback_.Reset();
if (sync_thread_)
@@ -689,8 +664,8 @@ void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
// the data directory needs to be cleaned up here.
sync_thread_->task_runner()->PostTask(
FROM_HERE,
- base::Bind(&syncer::syncable::Directory::DeleteDirectoryFiles,
- FormatSyncDataPath(base_directory_)));
+ base::BindOnce(&syncer::syncable::Directory::DeleteDirectoryFiles,
+ FormatSyncDataPath(base_directory_)));
}
return;
}
@@ -744,14 +719,9 @@ void ProfileSyncService::ShutdownImpl(syncer::ShutdownReason reason) {
// Clear various state.
ResetCryptoState();
expect_sync_configuration_aborted_ = false;
- is_auth_in_progress_ = false;
engine_initialized_ = false;
- access_token_.clear();
- request_access_token_retry_timer_.Stop();
last_snapshot_ = syncer::SyncCycleSnapshot();
- // Revert to "no auth error".
- if (last_auth_error_.state() != GoogleServiceAuthError::NONE)
- UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
+ auth_manager_->Clear();
NotifyObservers();
@@ -775,12 +745,12 @@ void ProfileSyncService::StopImpl(SyncStopDataFate data_fate) {
}
bool ProfileSyncService::IsFirstSetupComplete() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_prefs_.IsFirstSetupComplete();
}
void ProfileSyncService::SetFirstSetupComplete() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sync_prefs_.SetFirstSetupComplete();
if (IsEngineInitialized()) {
ReconfigureDatatypeManager();
@@ -788,7 +758,7 @@ void ProfileSyncService::SetFirstSetupComplete() {
}
bool ProfileSyncService::IsSyncConfirmationNeeded() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return (!IsLocalSyncEnabled() && IsSignedIn()) && !IsFirstSetupInProgress() &&
!IsFirstSetupComplete() && IsSyncRequested();
}
@@ -797,6 +767,12 @@ void ProfileSyncService::UpdateLastSyncedTime() {
sync_prefs_.SetLastSyncedTime(base::Time::Now());
}
+void ProfileSyncService::NotifyObservers() {
+ for (auto& observer : observers_) {
+ observer.OnStateChanged(this);
+ }
+}
+
void ProfileSyncService::NotifySyncCycleCompleted() {
for (auto& observer : observers_)
observer.OnSyncCycleCompleted(this);
@@ -816,7 +792,7 @@ void ProfileSyncService::ClearStaleErrors() {
ClearUnrecoverableError();
last_actionable_error_ = SyncProtocolError();
// Clear the data type errors as well.
- if (data_type_manager_.get())
+ if (data_type_manager_)
data_type_manager_->ResetDataTypeErrors();
}
@@ -830,7 +806,7 @@ void ProfileSyncService::ClearUnrecoverableError() {
// to do as little work as possible, to avoid further corruption or crashes.
void ProfileSyncService::OnUnrecoverableError(const base::Location& from_here,
const std::string& message) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Unrecoverable errors that arrive via the syncer::UnrecoverableErrorHandler
// interface are assumed to originate within the syncer.
unrecoverable_error_reason_ = ERROR_REASON_SYNCER;
@@ -851,15 +827,15 @@ void ProfileSyncService::OnUnrecoverableErrorImpl(
<< " -- ProfileSyncService unusable: " << message;
// Shut all data types down.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&ProfileSyncService::ShutdownImpl,
- sync_enabled_weak_factory_.GetWeakPtr(),
- delete_sync_database ? syncer::DISABLE_SYNC
- : syncer::STOP_SYNC));
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ProfileSyncService::ShutdownImpl,
+ sync_enabled_weak_factory_.GetWeakPtr(),
+ delete_sync_database ? syncer::DISABLE_SYNC
+ : syncer::STOP_SYNC));
}
void ProfileSyncService::ReenableDatatype(syncer::ModelType type) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!engine_initialized_ || !data_type_manager_)
return;
data_type_manager_->ReenableType(type);
@@ -891,7 +867,7 @@ void ProfileSyncService::OnEngineInitialized(
debug_info_listener,
const std::string& cache_guid,
bool success) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
UpdateEngineInitUMA(success);
if (!success) {
@@ -915,7 +891,6 @@ void ProfileSyncService::OnEngineInitialized(
engine_initialized_ = true;
sync_js_controller_.AttachJsBackend(js_backend);
- debug_info_listener_ = debug_info_listener;
// Initialize local device info.
local_device_->Initialize(cache_guid,
@@ -936,10 +911,10 @@ void ProfileSyncService::OnEngineInitialized(
UpdateLastSyncedTime();
}
- data_type_manager_.reset(
+ data_type_manager_ =
sync_client_->GetSyncApiComponentFactory()->CreateDataTypeManager(
- initial_types, debug_info_listener_, &data_type_controllers_, this,
- engine_.get(), this));
+ initial_types, debug_info_listener, &data_type_controllers_, this,
+ engine_.get(), this);
crypto_->SetSyncEngine(engine_.get());
crypto_->SetDataTypeManager(data_type_manager_.get());
@@ -971,13 +946,18 @@ void ProfileSyncService::OnEngineInitialized(
void ProfileSyncService::OnSyncCycleCompleted(
const syncer::SyncCycleSnapshot& snapshot) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
last_snapshot_ = snapshot;
UpdateLastSyncedTime();
if (!snapshot.poll_finish_time().is_null())
sync_prefs_.SetLastPollTime(snapshot.poll_finish_time());
+ DCHECK(!snapshot.short_poll_interval().is_zero());
+ sync_prefs_.SetShortPollInterval(snapshot.short_poll_interval());
+
+ DCHECK(!snapshot.long_poll_interval().is_zero());
+ sync_prefs_.SetLongPollInterval(snapshot.long_poll_interval());
if (IsDataTypeControllerRunning(syncer::SESSIONS) &&
snapshot.model_neutral_state().get_updates_request_types.Has(
@@ -985,9 +965,7 @@ void ProfileSyncService::OnSyncCycleCompleted(
!syncer::HasSyncerError(snapshot.model_neutral_state())) {
// Trigger garbage collection of old sessions now that we've downloaded
// any new session data.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(&SessionsSyncManager::DoGarbageCollection,
- base::AsWeakPtr(sessions_sync_manager_.get())));
+ sessions_sync_manager_->ScheduleGarbageCollection();
}
DVLOG(2) << "Notifying observers sync cycle completed";
NotifySyncCycleCompleted();
@@ -995,7 +973,7 @@ void ProfileSyncService::OnSyncCycleCompleted(
void ProfileSyncService::OnExperimentsChanged(
const syncer::Experiments& experiments) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (current_experiments_.Matches(experiments))
return;
@@ -1006,102 +984,15 @@ void ProfileSyncService::OnExperimentsChanged(
experiments.gcm_invalidations_enabled);
}
-void ProfileSyncService::UpdateAuthErrorState(
- const GoogleServiceAuthError& error) {
- is_auth_in_progress_ = false;
- last_auth_error_ = error;
-
- NotifyObservers();
-}
-
-namespace {
-
-GoogleServiceAuthError ConnectionStatusToAuthError(
- syncer::ConnectionStatus status) {
- switch (status) {
- case syncer::CONNECTION_OK:
- return GoogleServiceAuthError::AuthErrorNone();
- break;
- case syncer::CONNECTION_AUTH_ERROR:
- return GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
- GoogleServiceAuthError::InvalidGaiaCredentialsReason::
- CREDENTIALS_REJECTED_BY_SERVER);
- break;
- case syncer::CONNECTION_SERVER_ERROR:
- return GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED);
- break;
- default:
- NOTREACHED();
- return GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED);
- }
-}
-
-} // namespace
-
void ProfileSyncService::OnConnectionStatusChange(
syncer::ConnectionStatus status) {
- DCHECK(thread_checker_.CalledOnValidThread());
- connection_status_update_time_ = base::Time::Now();
- connection_status_ = status;
- if (status == syncer::CONNECTION_AUTH_ERROR) {
- // Sync server returned error indicating that access token is invalid. It
- // could be either expired or access is revoked. Let's request another
- // access token and if access is revoked then request for token will fail
- // with corresponding error. If access token is repeatedly reported
- // invalid, there may be some issues with server, e.g. authentication
- // state is inconsistent on sync and token server. In that case, we
- // backoff token requests exponentially to avoid hammering token server
- // too much and to avoid getting same token due to token server's caching
- // policy. |request_access_token_retry_timer_| is used to backoff request
- // triggered by both auth error and failure talking to GAIA server.
- // Therefore, we're likely to reach the backoff ceiling more quickly than
- // you would expect from looking at the BackoffPolicy if both types of
- // errors happen. We shouldn't receive two errors back-to-back without
- // attempting a token/sync request in between, thus crank up request delay
- // unnecessary. This is because we won't make a sync request if we hit an
- // error until GAIA succeeds at sending a new token, and we won't request
- // a new token unless sync reports a token failure. But to be safe, don't
- // schedule request if this happens.
- if (request_access_token_retry_timer_.IsRunning()) {
- // The timer to perform a request later is already running; nothing
- // further needs to be done at this point.
- } else if (request_access_token_backoff_.failure_count() == 0) {
- // First time request without delay. Currently invalid token is used
- // to initialize sync engine and we'll always end up here. We don't
- // want to delay initialization.
- request_access_token_backoff_.InformOfRequest(false);
- RequestAccessToken();
- } else {
- request_access_token_backoff_.InformOfRequest(false);
- request_access_token_retry_timer_.Start(
- FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
- base::Bind(&ProfileSyncService::RequestAccessToken,
- sync_enabled_weak_factory_.GetWeakPtr()));
- }
- // Make observers aware of the change. This call is unnecessary in the
- // block below because UpdateAuthErrorState() will notify observers.
- NotifyObservers();
- } else {
- // Reset backoff time after successful connection.
- if (status == syncer::CONNECTION_OK) {
- // Request shouldn't be scheduled at this time. But if it is, it's
- // possible that sync flips between OK and auth error states rapidly,
- // thus hammers token server. To be safe, only reset backoff delay when
- // no scheduled request.
- if (!request_access_token_retry_timer_.IsRunning()) {
- request_access_token_backoff_.Reset();
- }
- }
-
- const GoogleServiceAuthError auth_error =
- ConnectionStatusToAuthError(status);
- DVLOG(1) << "Connection status change: " << auth_error.ToString();
- UpdateAuthErrorState(auth_error);
- }
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ auth_manager_->ConnectionStatusChanged(status);
+ NotifyObservers();
}
void ProfileSyncService::OnMigrationNeededForTypes(syncer::ModelTypeSet types) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(engine_initialized_);
DCHECK(data_type_manager_);
@@ -1111,7 +1002,7 @@ void ProfileSyncService::OnMigrationNeededForTypes(syncer::ModelTypeSet types) {
}
void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
last_actionable_error_ = error;
DCHECK_NE(last_actionable_error_.action, syncer::UNKNOWN_ACTION);
switch (error.action) {
@@ -1168,10 +1059,10 @@ void ProfileSyncService::OnActionableError(const SyncProtocolError& error) {
}
void ProfileSyncService::ClearAndRestartSyncForPassphraseEncryption() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
engine_->ClearServerData(
- base::Bind(&ProfileSyncService::OnClearServerDataDone,
- sync_enabled_weak_factory_.GetWeakPtr()));
+ base::BindRepeating(&ProfileSyncService::OnClearServerDataDone,
+ sync_enabled_weak_factory_.GetWeakPtr()));
}
void ProfileSyncService::OnClearServerDataDone() {
@@ -1192,7 +1083,7 @@ void ProfileSyncService::OnClearServerDataDone() {
}
void ProfileSyncService::ClearServerDataForTest(const base::Closure& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Sync has a restriction that the engine must be in configuration mode
// in order to run clear server data.
engine_->StartConfiguration();
@@ -1201,12 +1092,11 @@ void ProfileSyncService::ClearServerDataForTest(const base::Closure& callback) {
void ProfileSyncService::OnConfigureDone(
const DataTypeManager::ConfigureResult& result) {
- DCHECK(thread_checker_.CalledOnValidThread());
- configure_status_ = result.status;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
data_type_status_table_ = result.data_type_status_table;
if (!sync_configure_start_time_.is_null()) {
- if (configure_status_ == DataTypeManager::OK) {
+ if (result.status == DataTypeManager::OK) {
base::Time sync_configure_stop_time = base::Time::Now();
base::TimeDelta delta =
sync_configure_stop_time - sync_configure_start_time_;
@@ -1223,7 +1113,7 @@ void ProfileSyncService::OnConfigureDone(
for (auto& observer : observers_)
observer.OnSyncConfigurationCompleted(this);
- DVLOG(1) << "PSS OnConfigureDone called with status: " << configure_status_;
+ DVLOG(1) << "PSS OnConfigureDone called with status: " << result.status;
// The possible status values:
// ABORT - Configuration was aborted. This is not an error, if
// initiated by user.
@@ -1231,7 +1121,7 @@ void ProfileSyncService::OnConfigureDone(
// Everything else is an UnrecoverableError. So treat it as such.
// First handle the abort case.
- if (configure_status_ == DataTypeManager::ABORTED &&
+ if (result.status == DataTypeManager::ABORTED &&
expect_sync_configuration_aborted_) {
DVLOG(0) << "ProfileSyncService::Observe Sync Configure aborted";
expect_sync_configuration_aborted_ = false;
@@ -1239,7 +1129,7 @@ void ProfileSyncService::OnConfigureDone(
}
// Handle unrecoverable error.
- if (configure_status_ != DataTypeManager::OK) {
+ if (result.status != DataTypeManager::OK) {
if (result.was_catch_up_configure) {
// Record catchup configuration failure.
UMA_HISTOGRAM_ENUMERATION("Sync.ClearServerDataEvents",
@@ -1252,7 +1142,7 @@ void ProfileSyncService::OnConfigureDone(
DCHECK(error.IsSet());
std::string message =
"Sync configuration failed with status " +
- DataTypeManager::ConfigureStatusToString(configure_status_) +
+ DataTypeManager::ConfigureStatusToString(result.status) +
" caused by " +
syncer::ModelTypeSetToString(
data_type_status_table_.GetUnrecoverableErrorTypes()) +
@@ -1263,7 +1153,7 @@ void ProfileSyncService::OnConfigureDone(
return;
}
- DCHECK_EQ(DataTypeManager::OK, configure_status_);
+ DCHECK_EQ(DataTypeManager::OK, result.status);
// We should never get in a state where we have no encrypted datatypes
// enabled, and yet we still think we require a passphrase for decryption.
@@ -1295,67 +1185,43 @@ void ProfileSyncService::OnConfigureDone(
}
void ProfileSyncService::OnConfigureStart() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sync_configure_start_time_ = base::Time::Now();
engine_->StartConfiguration();
NotifyObservers();
}
-ProfileSyncService::SyncStatusSummary
-ProfileSyncService::QuerySyncStatusSummary() {
- DCHECK(thread_checker_.CalledOnValidThread());
+std::string ProfileSyncService::QuerySyncStatusSummaryString() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
if (HasUnrecoverableError())
- return UNRECOVERABLE_ERROR;
+ return "Unrecoverable error detected";
if (!engine_)
- return NOT_ENABLED;
- if (engine_ && !IsFirstSetupComplete())
- return SETUP_INCOMPLETE;
- if (engine_ && IsFirstSetupComplete() && data_type_manager_ &&
+ return "Syncing not enabled";
+ if (!IsFirstSetupComplete())
+ return "First time sync setup incomplete";
+ if (data_type_manager_ &&
data_type_manager_->state() == DataTypeManager::STOPPED) {
- return DATATYPES_NOT_INITIALIZED;
+ return "Datatypes not fully initialized";
}
if (IsSyncActive())
- return INITIALIZED;
- return UNKNOWN_ERROR;
-}
+ return "Sync service initialized";
-std::string ProfileSyncService::QuerySyncStatusSummaryString() {
- DCHECK(thread_checker_.CalledOnValidThread());
- SyncStatusSummary status = QuerySyncStatusSummary();
-
- std::string config_status_str =
- configure_status_ != DataTypeManager::UNKNOWN
- ? DataTypeManager::ConfigureStatusToString(configure_status_)
- : "";
-
- switch (status) {
- case UNRECOVERABLE_ERROR:
- return "Unrecoverable error detected";
- case NOT_ENABLED:
- return "Syncing not enabled";
- case SETUP_INCOMPLETE:
- return "First time sync setup incomplete";
- case DATATYPES_NOT_INITIALIZED:
- return "Datatypes not fully initialized";
- case INITIALIZED:
- return "Sync service initialized";
- default:
- return "Status unknown: Internal error?";
- }
+ return "Status unknown: Internal error?";
}
std::string ProfileSyncService::GetEngineInitializationStateString() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return startup_controller_->GetEngineInitializationStateString();
}
bool ProfileSyncService::IsSetupInProgress() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return startup_controller_->IsSetupInProgress();
}
bool ProfileSyncService::QueryDetailedSyncStatus(SyncEngine::Status* result) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (engine_ && engine_initialized_) {
*result = engine_->GetDetailedStatus();
return true;
@@ -1367,8 +1233,8 @@ bool ProfileSyncService::QueryDetailedSyncStatus(SyncEngine::Status* result) {
}
const GoogleServiceAuthError& ProfileSyncService::GetAuthError() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return last_auth_error_;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return auth_manager_->GetLastAuthError();
}
bool ProfileSyncService::CanConfigureDataTypes() const {
@@ -1376,13 +1242,13 @@ bool ProfileSyncService::CanConfigureDataTypes() const {
}
bool ProfileSyncService::IsFirstSetupInProgress() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return !IsFirstSetupComplete() && startup_controller_->IsSetupInProgress();
}
std::unique_ptr<syncer::SyncSetupInProgressHandle>
ProfileSyncService::GetSetupInProgressHandle() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (++outstanding_setup_in_progress_handles_ == 1) {
DCHECK(!startup_controller_->IsSetupInProgress());
@@ -1391,81 +1257,73 @@ ProfileSyncService::GetSetupInProgressHandle() {
NotifyObservers();
}
- return std::unique_ptr<syncer::SyncSetupInProgressHandle>(
- new syncer::SyncSetupInProgressHandle(
- base::Bind(&ProfileSyncService::OnSetupInProgressHandleDestroyed,
- weak_factory_.GetWeakPtr())));
+ return std::make_unique<syncer::SyncSetupInProgressHandle>(
+ base::BindRepeating(&ProfileSyncService::OnSetupInProgressHandleDestroyed,
+ weak_factory_.GetWeakPtr()));
}
bool ProfileSyncService::IsSyncAllowed() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return IsSyncAllowedByFlag() && !IsManaged() && IsSyncAllowedByPlatform();
}
bool ProfileSyncService::IsSyncActive() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return engine_initialized_ && data_type_manager_ &&
data_type_manager_->state() != DataTypeManager::STOPPED;
}
bool ProfileSyncService::IsLocalSyncEnabled() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_prefs_.IsLocalSyncEnabled();
}
void ProfileSyncService::TriggerRefresh(const syncer::ModelTypeSet& types) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (engine_initialized_)
engine_->TriggerRefresh(types);
}
bool ProfileSyncService::IsSignedIn() const {
- // Sync is logged in if there is a non-empty effective account id.
- return !signin_->GetAccountIdToUse().empty();
+ // Sync is logged in if there is a non-empty account id.
+ return !GetAuthenticatedAccountInfo().account_id.empty();
}
bool ProfileSyncService::CanEngineStart() const {
if (IsLocalSyncEnabled())
return true;
- return CanSyncStart() && oauth2_token_service_ &&
- oauth2_token_service_->RefreshTokenIsAvailable(
- signin_->GetAccountIdToUse());
+ return CanSyncStart() && auth_manager_->RefreshTokenIsAvailable();
}
bool ProfileSyncService::IsEngineInitialized() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return engine_initialized_;
}
bool ProfileSyncService::ConfigurationDone() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return data_type_manager_ &&
data_type_manager_->state() == DataTypeManager::CONFIGURED;
}
bool ProfileSyncService::waiting_for_auth() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return is_auth_in_progress_;
-}
-
-const syncer::Experiments& ProfileSyncService::current_experiments() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return current_experiments_;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return auth_manager_->IsAuthInProgress();
}
bool ProfileSyncService::HasUnrecoverableError() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return unrecoverable_error_reason_ != ERROR_REASON_UNSET;
}
bool ProfileSyncService::IsPassphraseRequired() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->passphrase_required_reason() !=
syncer::REASON_PASSPHRASE_NOT_REQUIRED;
}
bool ProfileSyncService::IsPassphraseRequiredForDecryption() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// If there is an encrypted datatype enabled and we don't have the proper
// passphrase, we must prompt the user for a passphrase. The only way for the
// user to avoid entering their passphrase is to disable the encrypted types.
@@ -1503,7 +1361,7 @@ void ProfileSyncService::UpdateSelectedTypesHistogram(
syncer::user_selectable_type::PROXY_TABS,
};
- static_assert(40 == syncer::MODEL_TYPE_COUNT,
+ static_assert(41 == syncer::MODEL_TYPE_COUNT,
"If adding a user selectable type, update "
"UserSelectableSyncType in user_selectable_sync_type.h and "
"histograms.xml.");
@@ -1533,7 +1391,7 @@ void ProfileSyncService::UpdateSelectedTypesHistogram(
void ProfileSyncService::OnUserChoseDatatypes(
bool sync_everything,
syncer::ModelTypeSet chosen_types) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(syncer::UserSelectableTypes().HasAll(chosen_types));
if (!engine_ && !HasUnrecoverableError()) {
@@ -1549,23 +1407,9 @@ void ProfileSyncService::OnUserChoseDatatypes(
ChangePreferredDataTypes(chosen_types);
}
-void ProfileSyncService::OnUserChangedSyncEverythingOnly(bool sync_everything) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!engine_ && !HasUnrecoverableError()) {
- NOTREACHED();
- return;
- }
-
- sync_prefs_.SetKeepEverythingSynced(sync_everything);
- UpdateSelectedTypesHistogram(sync_everything, GetPreferredDataTypes());
- if (data_type_manager_)
- data_type_manager_->ResetDataTypeErrors();
- ReconfigureDatatypeManager();
-}
-
void ProfileSyncService::ChangePreferredDataTypes(
syncer::ModelTypeSet preferred_types) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(1) << "ChangePreferredDataTypes invoked";
const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
// Will only enable those types that are registered and preferred.
@@ -1576,19 +1420,35 @@ void ProfileSyncService::ChangePreferredDataTypes(
}
syncer::ModelTypeSet ProfileSyncService::GetActiveDataTypes() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!data_type_manager_)
return syncer::ModelTypeSet();
return data_type_manager_->GetActiveDataTypes();
}
syncer::SyncClient* ProfileSyncService::GetSyncClient() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_client_.get();
}
+void ProfileSyncService::AddObserver(syncer::SyncServiceObserver* observer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ observers_.AddObserver(observer);
+}
+
+void ProfileSyncService::RemoveObserver(syncer::SyncServiceObserver* observer) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ observers_.RemoveObserver(observer);
+}
+
+bool ProfileSyncService::HasObserver(
+ const syncer::SyncServiceObserver* observer) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return observers_.HasObserver(observer);
+}
+
syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
const syncer::ModelTypeSet registered_types = GetRegisteredDataTypes();
const syncer::ModelTypeSet preferred_types =
Union(sync_prefs_.GetPreferredDataTypes(registered_types),
@@ -1599,7 +1459,7 @@ syncer::ModelTypeSet ProfileSyncService::GetPreferredDataTypes() const {
}
syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(treib,zea): When SyncPrefs also implements SyncTypePreferenceProvider,
// we'll need another way to distinguish user-choosable types from
// programmatically-enabled types.
@@ -1607,25 +1467,25 @@ syncer::ModelTypeSet ProfileSyncService::GetForcedDataTypes() const {
}
syncer::ModelTypeSet ProfileSyncService::GetRegisteredDataTypes() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
syncer::ModelTypeSet registered_types;
// The data_type_controllers_ are determined by command-line flags;
// that's effectively what controls the values returned here.
- for (DataTypeController::TypeMap::const_iterator it =
- data_type_controllers_.begin();
- it != data_type_controllers_.end(); ++it) {
- registered_types.Put(it->first);
+ for (const std::pair<const syncer::ModelType,
+ std::unique_ptr<DataTypeController>>&
+ type_and_controller : data_type_controllers_) {
+ registered_types.Put(type_and_controller.first);
}
return registered_types;
}
bool ProfileSyncService::IsUsingSecondaryPassphrase() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->IsUsingSecondaryPassphrase();
}
std::string ProfileSyncService::GetCustomPassphraseKey() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
syncer::SystemEncryptor encryptor;
syncer::Cryptographer cryptographer(&encryptor);
cryptographer.Bootstrap(sync_prefs_.GetEncryptionBootstrapToken());
@@ -1633,24 +1493,24 @@ std::string ProfileSyncService::GetCustomPassphraseKey() const {
}
syncer::PassphraseType ProfileSyncService::GetPassphraseType() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->GetPassphraseType();
}
base::Time ProfileSyncService::GetExplicitPassphraseTime() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->GetExplicitPassphraseTime();
}
bool ProfileSyncService::IsCryptographerReady(
const syncer::BaseTransaction* trans) const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return engine_ && engine_->IsCryptographerReady(trans);
}
void ProfileSyncService::SetPlatformSyncAllowedProvider(
const PlatformSyncAllowedProvider& platform_sync_allowed_provider) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
platform_sync_allowed_provider_ = platform_sync_allowed_provider;
}
@@ -1684,8 +1544,8 @@ void ProfileSyncService::ConfigureDataTypeManager() {
// We create the migrator at the same time.
migrator_ = std::make_unique<BackendMigrator>(
debug_identifier_, GetUserShare(), this, data_type_manager_.get(),
- base::Bind(&ProfileSyncService::StartSyncingWithServer,
- base::Unretained(this)));
+ base::BindRepeating(&ProfileSyncService::StartSyncingWithServer,
+ base::Unretained(this)));
}
syncer::ModelTypeSet types;
@@ -1707,7 +1567,7 @@ void ProfileSyncService::ConfigureDataTypeManager() {
}
syncer::UserShare* ProfileSyncService::GetUserShare() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (engine_ && engine_initialized_) {
return engine_->GetUserShare();
}
@@ -1716,36 +1576,25 @@ syncer::UserShare* ProfileSyncService::GetUserShare() const {
}
syncer::SyncCycleSnapshot ProfileSyncService::GetLastCycleSnapshot() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return last_snapshot_;
}
-bool ProfileSyncService::HasUnsyncedItems() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (HasSyncingEngine() && engine_initialized_) {
- return engine_->HasUnsyncedItems();
- }
- NOTREACHED();
- return false;
+void ProfileSyncService::HasUnsyncedItemsForTest(
+ base::OnceCallback<void(bool)> cb) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(HasSyncingEngine());
+ DCHECK(engine_initialized_);
+ engine_->HasUnsyncedItemsForTest(std::move(cb));
}
BackendMigrator* ProfileSyncService::GetBackendMigratorForTest() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return migrator_.get();
}
-void ProfileSyncService::GetModelSafeRoutingInfo(
- syncer::ModelSafeRoutingInfo* out) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (engine_ && engine_initialized_) {
- engine_->GetModelSafeRoutingInfo(out);
- } else {
- NOTREACHED();
- }
-}
-
std::unique_ptr<base::Value> ProfileSyncService::GetTypeStatusMap() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto result = std::make_unique<base::ListValue>();
if (!engine_ || !engine_initialized_) {
@@ -1814,9 +1663,10 @@ std::unique_ptr<base::Value> ProfileSyncService::GetTypeStatusMap() {
// OnDatatypeStatusCounterUpdated that posts back to the UI thread so that
// real results can't get overwritten by the empty counters set at the end
// of this method.
- dtc_iter->second->GetStatusCounters(BindToCurrentThread(
- base::Bind(&ProfileSyncService::OnDatatypeStatusCounterUpdated,
- base::Unretained(this))));
+ dtc_iter->second->GetStatusCounters(
+ BindToCurrentSequence(base::BindRepeating(
+ &ProfileSyncService::OnDatatypeStatusCounterUpdated,
+ base::Unretained(this))));
type_status->SetString("state", DataTypeController::StateToString(
dtc_iter->second->state()));
}
@@ -1826,40 +1676,15 @@ std::unique_ptr<base::Value> ProfileSyncService::GetTypeStatusMap() {
return std::move(result);
}
-void ProfileSyncService::RequestAccessToken() {
- // Only one active request at a time.
- if (access_token_request_ != nullptr)
- return;
- request_access_token_retry_timer_.Stop();
- OAuth2TokenService::ScopeSet oauth2_scopes;
- oauth2_scopes.insert(signin_->GetSyncScopeToUse());
-
- // Invalidate previous token, otherwise token service will return the same
- // token again.
- const std::string& account_id = signin_->GetAccountIdToUse();
- if (!access_token_.empty()) {
- oauth2_token_service_->InvalidateAccessToken(account_id, oauth2_scopes,
- access_token_);
- }
-
- access_token_.clear();
-
- token_request_time_ = base::Time::Now();
- token_receive_time_ = base::Time();
- next_token_request_time_ = base::Time();
- access_token_request_ =
- oauth2_token_service_->StartRequest(account_id, oauth2_scopes, this);
-}
-
void ProfileSyncService::SetEncryptionPassphrase(const std::string& passphrase,
PassphraseType type) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
crypto_->SetEncryptionPassphrase(passphrase, type == EXPLICIT);
}
bool ProfileSyncService::SetDecryptionPassphrase(
const std::string& passphrase) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsPassphraseRequired()) {
DVLOG(1) << "Setting passphrase for decryption.";
bool result = crypto_->SetDecryptionPassphrase(passphrase);
@@ -1872,22 +1697,22 @@ bool ProfileSyncService::SetDecryptionPassphrase(
}
bool ProfileSyncService::IsEncryptEverythingAllowed() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->IsEncryptEverythingAllowed();
}
void ProfileSyncService::SetEncryptEverythingAllowed(bool allowed) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
crypto_->SetEncryptEverythingAllowed(allowed);
}
void ProfileSyncService::EnableEncryptEverything() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
crypto_->EnableEncryptEverything();
}
bool ProfileSyncService::encryption_pending() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// We may be called during the setup process before we're
// initialized (via IsEncryptedDatatypeEnabled and
// IsPassphraseRequiredForDecryption).
@@ -1895,17 +1720,17 @@ bool ProfileSyncService::encryption_pending() const {
}
bool ProfileSyncService::IsEncryptEverythingEnabled() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->IsEncryptEverythingEnabled();
}
syncer::ModelTypeSet ProfileSyncService::GetEncryptedDataTypes() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return crypto_->GetEncryptedDataTypes();
}
void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (is_sync_managed) {
StopImpl(CLEAR_DATA);
} else {
@@ -1914,26 +1739,16 @@ void ProfileSyncService::OnSyncManagedPrefChange(bool is_sync_managed) {
}
}
-void ProfileSyncService::GoogleSigninSucceeded(const std::string& account_id,
- const std::string& username) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (!IsEngineInitialized() ||
- GetAuthError().state() != GoogleServiceAuthError::NONE) {
- // Track the fact that we're still waiting for auth to complete.
- is_auth_in_progress_ = true;
- }
-
- if (oauth2_token_service_->RefreshTokenIsAvailable(account_id))
- OnRefreshTokenAvailable(account_id);
+void ProfileSyncService::OnPrimaryAccountSet() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!engine_);
}
-void ProfileSyncService::GoogleSignedOut(const std::string& account_id,
- const std::string& username) {
- DCHECK(thread_checker_.CalledOnValidThread());
+void ProfileSyncService::OnPrimaryAccountCleared() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sync_disabled_by_admin_ = false;
- UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
- syncer::STOP_SOURCE_LIMIT);
RequestStop(CLEAR_DATA);
+ DCHECK(!engine_);
}
void ProfileSyncService::OnGaiaAccountsInCookieUpdated(
@@ -1946,7 +1761,7 @@ void ProfileSyncService::OnGaiaAccountsInCookieUpdated(
void ProfileSyncService::OnGaiaAccountsInCookieUpdatedWithCallback(
const std::vector<gaia::ListedAccount>& accounts,
const base::Closure& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!IsEngineInitialized())
return;
@@ -1960,7 +1775,7 @@ void ProfileSyncService::OnGaiaAccountsInCookieUpdatedWithCallback(
bool ProfileSyncService::HasCookieJarMismatch(
const std::vector<gaia::ListedAccount>& cookie_jar_accounts) {
- std::string account_id = signin_->GetAccountIdToUse();
+ std::string account_id = GetAuthenticatedAccountInfo().account_id;
// Iterate through list of accounts, looking for current sync account.
for (const auto& account : cookie_jar_accounts) {
if (account.id == account_id)
@@ -1971,7 +1786,7 @@ bool ProfileSyncService::HasCookieJarMismatch(
void ProfileSyncService::AddProtocolEventObserver(
ProtocolEventObserver* observer) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
protocol_event_observers_.AddObserver(observer);
if (HasSyncingEngine()) {
engine_->RequestBufferedProtocolEventsAndEnableForwarding();
@@ -1980,7 +1795,7 @@ void ProfileSyncService::AddProtocolEventObserver(
void ProfileSyncService::RemoveProtocolEventObserver(
ProtocolEventObserver* observer) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
protocol_event_observers_.RemoveObserver(observer);
if (HasSyncingEngine() && !protocol_event_observers_.might_have_observers()) {
engine_->DisableProtocolEventForwarding();
@@ -1989,7 +1804,7 @@ void ProfileSyncService::RemoveProtocolEventObserver(
void ProfileSyncService::AddTypeDebugInfoObserver(
syncer::TypeDebugInfoObserver* type_debug_info_observer) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
type_debug_info_observers_.AddObserver(type_debug_info_observer);
if (type_debug_info_observers_.might_have_observers() &&
engine_initialized_) {
@@ -1999,7 +1814,7 @@ void ProfileSyncService::AddTypeDebugInfoObserver(
void ProfileSyncService::RemoveTypeDebugInfoObserver(
syncer::TypeDebugInfoObserver* type_debug_info_observer) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
type_debug_info_observers_.RemoveObserver(type_debug_info_observer);
if (!type_debug_info_observers_.might_have_observers() &&
engine_initialized_) {
@@ -2009,7 +1824,7 @@ void ProfileSyncService::RemoveTypeDebugInfoObserver(
void ProfileSyncService::AddPreferenceProvider(
syncer::SyncTypePreferenceProvider* provider) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!HasPreferenceProvider(provider))
<< "Providers may only be added once!";
preference_providers_.insert(provider);
@@ -2017,7 +1832,7 @@ void ProfileSyncService::AddPreferenceProvider(
void ProfileSyncService::RemovePreferenceProvider(
syncer::SyncTypePreferenceProvider* provider) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(HasPreferenceProvider(provider))
<< "Only providers that have been added before can be removed!";
preference_providers_.erase(provider);
@@ -2025,7 +1840,7 @@ void ProfileSyncService::RemovePreferenceProvider(
bool ProfileSyncService::HasPreferenceProvider(
syncer::SyncTypePreferenceProvider* provider) const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return preference_providers_.count(provider) > 0;
}
@@ -2036,7 +1851,7 @@ class GetAllNodesRequestHelper
public:
GetAllNodesRequestHelper(
syncer::ModelTypeSet requested_types,
- const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback);
+ base::OnceCallback<void(std::unique_ptr<base::ListValue>)> callback);
void OnReceivedNodesForType(const syncer::ModelType type,
std::unique_ptr<base::ListValue> node_list);
@@ -2047,18 +1862,18 @@ class GetAllNodesRequestHelper
std::unique_ptr<base::ListValue> result_accumulator_;
syncer::ModelTypeSet awaiting_types_;
- base::Callback<void(std::unique_ptr<base::ListValue>)> callback_;
- base::ThreadChecker thread_checker_;
+ base::OnceCallback<void(std::unique_ptr<base::ListValue>)> callback_;
+ SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(GetAllNodesRequestHelper);
};
GetAllNodesRequestHelper::GetAllNodesRequestHelper(
syncer::ModelTypeSet requested_types,
- const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback)
- : result_accumulator_(new base::ListValue()),
+ base::OnceCallback<void(std::unique_ptr<base::ListValue>)> callback)
+ : result_accumulator_(std::make_unique<base::ListValue>()),
awaiting_types_(requested_types),
- callback_(callback) {}
+ callback_(std::move(callback)) {}
GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
if (!awaiting_types_.Empty()) {
@@ -2073,20 +1888,20 @@ GetAllNodesRequestHelper::~GetAllNodesRequestHelper() {
void GetAllNodesRequestHelper::OnReceivedNodesForType(
const syncer::ModelType type,
std::unique_ptr<base::ListValue> node_list) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Add these results to our list.
- std::unique_ptr<base::DictionaryValue> type_dict(new base::DictionaryValue());
- type_dict->SetString("type", ModelTypeToString(type));
- type_dict->Set("nodes", std::move(node_list));
- result_accumulator_->Append(std::move(type_dict));
+ base::DictionaryValue type_dict;
+ type_dict.SetKey("type", base::Value(ModelTypeToString(type)));
+ type_dict.SetKey("nodes",
+ base::Value::FromUniquePtrValue(std::move(node_list)));
+ result_accumulator_->GetList().push_back(std::move(type_dict));
// Remember that this part of the request is satisfied.
awaiting_types_.Remove(type);
if (awaiting_types_.Empty()) {
- callback_.Run(std::move(result_accumulator_));
- callback_.Reset();
+ std::move(callback_).Run(std::move(result_accumulator_));
}
}
@@ -2094,42 +1909,46 @@ void GetAllNodesRequestHelper::OnReceivedNodesForType(
void ProfileSyncService::GetAllNodes(
const base::Callback<void(std::unique_ptr<base::ListValue>)>& callback) {
- DCHECK(thread_checker_.CalledOnValidThread());
- ModelTypeSet all_types = GetActiveDataTypes();
- all_types.PutAll(syncer::ControlTypes());
- scoped_refptr<GetAllNodesRequestHelper> helper =
- new GetAllNodesRequestHelper(all_types, callback);
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // If the engine isn't initialized yet, then there are no nodes to return.
if (!engine_initialized_) {
- // If there's no engine available to fulfill the request, handle it here.
- for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
- helper->OnReceivedNodesForType(it.Get(),
- std::make_unique<base::ListValue>());
- }
+ callback.Run(std::make_unique<base::ListValue>());
return;
}
+ ModelTypeSet all_types = GetActiveDataTypes();
+ all_types.PutAll(syncer::ControlTypes());
+ scoped_refptr<GetAllNodesRequestHelper> helper =
+ new GetAllNodesRequestHelper(all_types, callback);
+
for (ModelTypeSet::Iterator it = all_types.First(); it.Good(); it.Inc()) {
- const auto& dtc_iter = data_type_controllers_.find(it.Get());
+ ModelType type = it.Get();
+ const auto dtc_iter = data_type_controllers_.find(type);
if (dtc_iter != data_type_controllers_.end()) {
- dtc_iter->second->GetAllNodes(base::Bind(
+ dtc_iter->second->GetAllNodes(base::BindRepeating(
&GetAllNodesRequestHelper::OnReceivedNodesForType, helper));
} else {
- // Control Types
+ // Control Types.
helper->OnReceivedNodesForType(
- it.Get(),
+ type,
syncer::DirectoryDataTypeController::GetAllNodesForTypeFromDirectory(
- it.Get(), GetUserShare()->directory.get()));
+ type, GetUserShare()->directory.get()));
}
}
}
+AccountInfo ProfileSyncService::GetAuthenticatedAccountInfo() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return auth_manager_->GetAuthenticatedAccountInfo();
+}
+
syncer::GlobalIdMapper* ProfileSyncService::GetGlobalIdMapper() const {
return sessions_sync_manager_->GetGlobalIdMapper();
}
base::WeakPtr<syncer::JsController> ProfileSyncService::GetJsController() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_js_controller_.AsWeakPtr();
}
@@ -2145,31 +1964,31 @@ bool ProfileSyncService::IsSyncAllowedByFlag() {
}
bool ProfileSyncService::IsSyncAllowedByPlatform() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return platform_sync_allowed_provider_.is_null() ||
platform_sync_allowed_provider_.Run();
}
bool ProfileSyncService::IsManaged() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_prefs_.IsManaged() || sync_disabled_by_admin_;
}
void ProfileSyncService::RequestStop(SyncStopDataFate data_fate) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
sync_prefs_.SetSyncRequested(false);
StopImpl(data_fate);
}
bool ProfileSyncService::IsSyncRequested() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// When local sync is on sync should be considered requsted or otherwise it
// will not resume after the policy or the flag has been removed.
return sync_prefs_.IsSyncRequested() || sync_prefs_.IsLocalSyncEnabled();
}
void ProfileSyncService::RequestStart() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!IsSyncAllowed()) {
// Sync cannot be requested if it's not allowed.
return;
@@ -2183,7 +2002,7 @@ void ProfileSyncService::RequestStart() {
}
void ProfileSyncService::ReconfigureDatatypeManager() {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// If we haven't initialized yet, don't configure the DTM as it could cause
// association to start before a Directory has even been created.
if (engine_initialized_) {
@@ -2204,16 +2023,15 @@ void ProfileSyncService::ReconfigureDatatypeManager() {
syncer::ModelTypeSet ProfileSyncService::GetDataTypesFromPreferenceProviders()
const {
syncer::ModelTypeSet types;
- for (std::set<syncer::SyncTypePreferenceProvider*>::const_iterator it =
- preference_providers_.begin();
- it != preference_providers_.end(); ++it) {
- types.PutAll((*it)->GetPreferredDataTypes());
+ for (const syncer::SyncTypePreferenceProvider* provider :
+ preference_providers_) {
+ types.PutAll(provider->GetPreferredDataTypes());
}
return types;
}
const DataTypeStatusTable& ProfileSyncService::data_type_status_table() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return data_type_status_table_;
}
@@ -2228,42 +2046,47 @@ void ProfileSyncService::OnInternalUnrecoverableError(
}
bool ProfileSyncService::IsRetryingAccessTokenFetchForTest() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return request_access_token_retry_timer_.IsRunning();
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return auth_manager_->IsRetryingAccessTokenFetchForTest();
}
std::string ProfileSyncService::GetAccessTokenForTest() const {
- DCHECK(thread_checker_.CalledOnValidThread());
- return access_token_;
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return auth_manager_->access_token();
}
syncer::SyncableService* ProfileSyncService::GetSessionsSyncableService() {
- DCHECK(thread_checker_.CalledOnValidThread());
- return sessions_sync_manager_.get();
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!sessions_sync_manager_)
+ return nullptr;
+ return sessions_sync_manager_->GetSyncableService();
}
-syncer::ModelTypeSyncBridge* ProfileSyncService::GetDeviceInfoSyncBridge() {
- DCHECK(thread_checker_.CalledOnValidThread());
- return device_info_sync_bridge_.get();
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ProfileSyncService::GetSessionSyncControllerDelegateOnUIThread() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!sessions_sync_manager_)
+ return nullptr;
+ return sessions_sync_manager_->GetModelTypeSyncBridge()
+ ->change_processor()
+ ->GetControllerDelegateOnUIThread();
}
-syncer::SyncService::SyncTokenStatus ProfileSyncService::GetSyncTokenStatus()
- const {
- DCHECK(thread_checker_.CalledOnValidThread());
- SyncTokenStatus status;
- status.connection_status_update_time = connection_status_update_time_;
- status.connection_status = connection_status_;
- status.token_request_time = token_request_time_;
- status.token_receive_time = token_receive_time_;
- status.last_get_token_error = last_get_token_error_;
- if (request_access_token_retry_timer_.IsRunning())
- status.next_token_request_time = next_token_request_time_;
- return status;
+base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ProfileSyncService::GetDeviceInfoSyncControllerDelegateOnUIThread() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return device_info_sync_bridge_->change_processor()
+ ->GetControllerDelegateOnUIThread();
+}
+
+syncer::SyncTokenStatus ProfileSyncService::GetSyncTokenStatus() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return auth_manager_->GetSyncTokenStatus();
}
void ProfileSyncService::OverrideNetworkResourcesForTest(
std::unique_ptr<syncer::NetworkResources> network_resources) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
network_resources_ = std::move(network_resources);
}
@@ -2281,7 +2104,7 @@ void ProfileSyncService::UpdateFirstSyncTimePref() {
}
void ProfileSyncService::FlushDirectory() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// engine_initialized_ implies engine_ isn't null and the manager exists.
// If sync is not initialized yet, we fail silently.
if (engine_initialized_)
@@ -2289,12 +2112,12 @@ void ProfileSyncService::FlushDirectory() const {
}
base::FilePath ProfileSyncService::GetDirectoryPathForTest() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return FormatSyncDataPath(base_directory_);
}
base::MessageLoop* ProfileSyncService::GetSyncLoopForTest() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_thread_ ? sync_thread_->message_loop() : nullptr;
}
@@ -2312,8 +2135,9 @@ void ProfileSyncService::RemoveClientFromServer() const {
if (user_share && user_share->directory.get()) {
birthday = user_share->directory->store_birthday();
}
- if (!access_token_.empty() && !cache_guid.empty() && !birthday.empty()) {
- sync_stopped_reporter_->ReportSyncStopped(access_token_, cache_guid,
+ const std::string& access_token = auth_manager_->access_token();
+ if (!access_token.empty() && !cache_guid.empty() && !birthday.empty()) {
+ sync_stopped_reporter_->ReportSyncStopped(access_token, cache_guid,
birthday);
}
}
@@ -2357,17 +2181,17 @@ void ProfileSyncService::RecordMemoryUsageHistograms() {
}
const GURL& ProfileSyncService::sync_service_url() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return sync_service_url_;
}
std::string ProfileSyncService::unrecoverable_error_message() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return unrecoverable_error_message_;
}
base::Location ProfileSyncService::unrecoverable_error_location() const {
- DCHECK(thread_checker_.CalledOnValidThread());
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return unrecoverable_error_location_;
}
diff --git a/chromium/components/browser_sync/profile_sync_service.h b/chromium/components/browser_sync/profile_sync_service.h
index 7cc42542647..63f93473298 100644
--- a/chromium/components/browser_sync/profile_sync_service.h
+++ b/chromium/components/browser_sync/profile_sync_service.h
@@ -10,33 +10,29 @@
#include <string>
#include <vector>
-#include "base/compiler_specific.h"
#include "base/files/file_path.h"
-#include "base/gtest_prod_util.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
+#include "base/sequence_checker.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
-#include "base/timer/timer.h"
#include "build/build_config.h"
#include "components/signin/core/browser/gaia_cookie_manager_service.h"
-#include "components/signin/core/browser/signin_manager_base.h"
#include "components/sync/base/experiments.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/sync_prefs.h"
#include "components/sync/base/unrecoverable_error_handler.h"
-#include "components/sync/device_info/local_device_info_provider.h"
#include "components/sync/driver/data_type_controller.h"
#include "components/sync/driver/data_type_manager.h"
#include "components/sync/driver/data_type_manager_observer.h"
#include "components/sync/driver/data_type_status_table.h"
#include "components/sync/driver/startup_controller.h"
#include "components/sync/driver/sync_client.h"
-#include "components/sync/driver/sync_service_base.h"
+#include "components/sync/driver/sync_service.h"
+#include "components/sync/driver/sync_service_crypto.h"
#include "components/sync/driver/sync_stopped_reporter.h"
#include "components/sync/engine/events/protocol_event_observer.h"
#include "components/sync/engine/model_safe_worker.h"
@@ -44,46 +40,47 @@
#include "components/sync/engine/shutdown_reason.h"
#include "components/sync/engine/sync_engine.h"
#include "components/sync/engine/sync_engine_host.h"
-#include "components/sync/engine/sync_manager_factory.h"
#include "components/sync/js/sync_js_controller.h"
#include "components/sync/model/model_type_store.h"
-#include "components/sync/syncable/user_share.h"
#include "components/version_info/version_info.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "google_apis/gaia/oauth2_token_service.h"
-#include "net/base/backoff_entry.h"
#include "url/gurl.h"
class ProfileOAuth2TokenService;
class SigninManagerWrapper;
+namespace base {
+class MessageLoop;
+}
+
namespace sync_sessions {
+class AbstractSessionsSyncManager;
class FaviconCache;
class OpenTabsUIDelegate;
-class SessionsSyncManager;
} // namespace sync_sessions
namespace syncer {
class BackendMigrator;
class BaseTransaction;
-class DataTypeManager;
class DeviceInfoSyncBridge;
class DeviceInfoTracker;
class LocalDeviceInfoProvider;
+class ModelTypeControllerDelegate;
class NetworkResources;
-class SyncClient;
+class SyncableService;
class SyncErrorController;
class SyncTypePreferenceProvider;
class TypeDebugInfoObserver;
struct CommitCounters;
struct StatusCounters;
-struct SyncCredentials;
struct UpdateCounters;
struct UserShare;
} // namespace syncer
namespace browser_sync {
+class SyncAuthManager;
+
// ProfileSyncService is the layer between browser subsystems like bookmarks,
// and the sync engine. Each subsystem is logically thought of as being a sync
// datatype. Individual datatypes can, at any point, be in a variety of stages
@@ -129,8 +126,6 @@ namespace browser_sync {
//
// Sync configuration is accomplished via the following APIs:
// * OnUserChoseDatatypes(): Set the data types the user wants to sync.
-// * OnUserChangedSyncEverythingOnly(): Set only the keepEverythingSynced
-// value.
// * SetDecryptionPassphrase(): Attempt to decrypt the user's encrypted data
// using the passed passphrase.
// * SetEncryptionPassphrase(): Re-encrypt the user's data using the passed
@@ -164,52 +159,37 @@ namespace browser_sync {
// Once first setup has completed and there are no outstanding
// setup-in-progress handles, CanConfigureDataTypes() will return true and
// datatype configuration can begin.
-class ProfileSyncService : public syncer::SyncServiceBase,
+class ProfileSyncService : public syncer::SyncService,
+ public syncer::SyncEngineHost,
public syncer::SyncPrefObserver,
public syncer::DataTypeManagerObserver,
public syncer::UnrecoverableErrorHandler,
- public OAuth2TokenService::Consumer,
- public OAuth2TokenService::Observer,
- public SigninManagerBase::Observer,
public GaiaCookieManagerService::Observer {
public:
- using Status = syncer::SyncEngine::Status;
using PlatformSyncAllowedProvider = base::RepeatingCallback<bool()>;
using SigninScopedDeviceIdCallback = base::RepeatingCallback<std::string()>;
+ // NOTE: Used in a UMA histogram, do not reorder etc.
enum SyncEventCodes {
- MIN_SYNC_EVENT_CODE = 0,
-
// Events starting the sync service.
- START_FROM_NTP = 1, // Sync was started from the ad in NTP
- START_FROM_WRENCH = 2, // Sync was started from the Wrench menu.
- START_FROM_OPTIONS = 3, // Sync was started from Wrench->Options.
- START_FROM_BOOKMARK_MANAGER = 4, // Sync was started from Bookmark manager.
- START_FROM_PROFILE_MENU = 5, // Sync was started from multiprofile menu.
- START_FROM_URL = 6, // Sync was started from a typed URL.
+ // START_FROM_NTP = 1,
+ // START_FROM_WRENCH = 2,
+ // START_FROM_OPTIONS = 3,
+ // START_FROM_BOOKMARK_MANAGER = 4,
+ // START_FROM_PROFILE_MENU = 5,
+ // START_FROM_URL = 6,
// Events regarding cancellation of the signon process of sync.
- CANCEL_FROM_SIGNON_WITHOUT_AUTH = 10, // Cancelled before submitting
- // username and password.
- CANCEL_DURING_SIGNON = 11, // Cancelled after auth.
- CANCEL_DURING_CONFIGURE = 12, // Cancelled before choosing data
- // types and clicking OK.
- // Events resulting in the stoppage of sync service.
- STOP_FROM_OPTIONS = 20, // Sync was stopped from Wrench->Options.
- STOP_FROM_ADVANCED_DIALOG = 21, // Sync was stopped via advanced settings.
+ // CANCEL_FROM_SIGNON_WITHOUT_AUTH = 10,
+ // CANCEL_DURING_SIGNON = 11,
+ CANCEL_DURING_CONFIGURE = 12, // Cancelled before choosing data types and
+ // clicking OK.
- // Miscellaneous events caused by sync service.
-
- MAX_SYNC_EVENT_CODE
- };
+ // Events resulting in the stoppage of sync service.
+ STOP_FROM_OPTIONS = 20, // Sync was stopped from Wrench->Options.
+ // STOP_FROM_ADVANCED_DIALOG = 21,
- enum SyncStatusSummary {
- UNRECOVERABLE_ERROR,
- NOT_ENABLED,
- SETUP_INCOMPLETE,
- DATATYPES_NOT_INITIALIZED,
- INITIALIZED,
- UNKNOWN_ERROR,
+ MAX_SYNC_EVENT_CODE = 22
};
// If AUTO_START, sync will set IsFirstSetupComplete() automatically and sync
@@ -265,6 +245,9 @@ class ProfileSyncService : public syncer::SyncServiceBase,
void RequestStart() override;
syncer::ModelTypeSet GetActiveDataTypes() const override;
syncer::SyncClient* GetSyncClient() const override;
+ void AddObserver(syncer::SyncServiceObserver* observer) override;
+ void RemoveObserver(syncer::SyncServiceObserver* observer) override;
+ bool HasObserver(const syncer::SyncServiceObserver* observer) const override;
syncer::ModelTypeSet GetPreferredDataTypes() const override;
void OnUserChoseDatatypes(bool sync_everything,
syncer::ModelTypeSet chosen_types) override;
@@ -294,7 +277,7 @@ class ProfileSyncService : public syncer::SyncServiceBase,
void RegisterDataTypeController(std::unique_ptr<syncer::DataTypeController>
data_type_controller) override;
void ReenableDatatype(syncer::ModelType type) override;
- SyncTokenStatus GetSyncTokenStatus() const override;
+ syncer::SyncTokenStatus GetSyncTokenStatus() const override;
std::string QuerySyncStatusSummaryString() override;
bool QueryDetailedSyncStatus(syncer::SyncStatus* result) override;
base::Time GetLastSyncedTime() const override;
@@ -315,13 +298,9 @@ class ProfileSyncService : public syncer::SyncServiceBase,
base::WeakPtr<syncer::JsController> GetJsController() override;
void GetAllNodes(const base::Callback<void(std::unique_ptr<base::ListValue>)>&
callback) override;
+ AccountInfo GetAuthenticatedAccountInfo() const override;
syncer::GlobalIdMapper* GetGlobalIdMapper() const override;
- // Changes only the KeepEverythingSynced value.
- // TODO(crbug/820625): Refactor sync code for more robust way to get/set
- // preferred datatypes.
- void OnUserChangedSyncEverythingOnly(bool sync_everything);
-
// Add a sync type preference provider. Each provider may only be added once.
void AddPreferenceProvider(syncer::SyncTypePreferenceProvider* provider);
// Remove a sync type preference provider. May only be called for providers
@@ -332,23 +311,18 @@ class ProfileSyncService : public syncer::SyncServiceBase,
bool HasPreferenceProvider(
syncer::SyncTypePreferenceProvider* provider) const;
- void RegisterAuthNotifications();
- void UnregisterAuthNotifications();
-
- // Returns the SyncableService for syncer::SESSIONS.
+ // Returns the SyncableService or USS bridge for syncer::SESSIONS.
virtual syncer::SyncableService* GetSessionsSyncableService();
+ virtual base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ GetSessionSyncControllerDelegateOnUIThread();
- // Returns the ModelTypeSyncBridge for syncer::DEVICE_INFO.
- virtual syncer::ModelTypeSyncBridge* GetDeviceInfoSyncBridge();
+ // Returns the ModelTypeControllerDelegate for syncer::DEVICE_INFO.
+ virtual base::WeakPtr<syncer::ModelTypeControllerDelegate>
+ GetDeviceInfoSyncControllerDelegateOnUIThread();
// Returns synced devices tracker.
virtual syncer::DeviceInfoTracker* GetDeviceInfoTracker() const;
- // Fills state_map with a map of current data types that are possible to
- // sync, as well as their states.
- void GetDataTypeControllerStates(
- syncer::DataTypeController::StateMap* state_map) const;
-
// Called when asynchronous session restore has completed.
void OnSessionRestoreComplete();
@@ -385,11 +359,11 @@ class ProfileSyncService : public syncer::SyncServiceBase,
bool IsPassphraseRequired() const override;
syncer::ModelTypeSet GetEncryptedDataTypes() const override;
- // SigninManagerBase::Observer implementation.
- void GoogleSigninSucceeded(const std::string& account_id,
- const std::string& username) override;
- void GoogleSignedOut(const std::string& account_id,
- const std::string& username) override;
+ // Called by the SyncAuthManager when the primary account changes.
+ // TODO(crbug.com/842697): Make these private and pass a callback to the
+ // SyncAuthManager.
+ void OnPrimaryAccountSet();
+ void OnPrimaryAccountCleared();
// GaiaCookieManagerService::Observer implementation.
void OnGaiaAccountsInCookieUpdated(
@@ -407,9 +381,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
bool HasCookieJarMismatch(
const std::vector<gaia::ListedAccount>& cookie_jar_accounts);
- // Get the sync status code.
- SyncStatusSummary QuerySyncStatusSummary();
-
// Reconfigures the data type manager with the latest enabled types.
// Note: Does not initialize the engine if it is not already initialized.
// This function needs to be called only after sync has been initialized
@@ -457,16 +428,12 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// The functions below (until ActivateDataType()) should only be
// called if IsEngineInitialized() is true.
- // TODO(akalin): These two functions are used only by
- // ProfileSyncServiceHarness. Figure out a different way to expose
- // this info to that class, and remove these functions.
-
// Returns whether or not the underlying sync engine has made any
// local changes to items that have not yet been synced with the
// server.
- bool HasUnsyncedItems() const;
+ void HasUnsyncedItemsForTest(base::OnceCallback<void(bool)> cb) const;
- // Used by ProfileSyncServiceHarness. May return null.
+ // Used by MigrationWatcher. May return null.
syncer::BackendMigrator* GetBackendMigratorForTest();
// Used by tests to inspect interaction with OAuth2TokenService.
@@ -475,9 +442,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// Used by tests to inspect the OAuth2 access tokens used by PSS.
std::string GetAccessTokenForTest() const;
- // TODO(sync): This is only used in tests. Can we remove it?
- void GetModelSafeRoutingInfo(syncer::ModelSafeRoutingInfo* out) const;
-
// SyncPrefObserver implementation.
void OnSyncManagedPrefChange(bool is_sync_managed) override;
@@ -512,10 +476,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// TODO(sync): This is only used in tests. Can we remove it?
const syncer::DataTypeStatusTable& data_type_status_table() const;
- syncer::DataTypeManager::ConfigureStatus configure_status() {
- return configure_status_;
- }
-
// If true, the ProfileSyncService has detected that a new GAIA signin has
// succeeded, and is waiting for initialization to complete. This is used by
// the UI to differentiate between a new auth error (encountered as part of
@@ -523,20 +483,15 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// been cleared yet. Virtual for testing purposes.
virtual bool waiting_for_auth() const;
- // The set of currently enabled sync experiments.
- const syncer::Experiments& current_experiments() const;
+ // Called by the SyncAuthManager when the refresh token state changes.
+ // TODO(crbug.com/842697): Make these private and pass a callback to the
+ // SyncAuthManager.
+ void OnRefreshTokenAvailable();
+ void OnRefreshTokenRevoked();
- // OAuth2TokenService::Consumer implementation.
- void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
- const std::string& access_token,
- const base::Time& expiration_time) override;
- void OnGetTokenFailure(const OAuth2TokenService::Request* request,
- const GoogleServiceAuthError& error) override;
-
- // OAuth2TokenService::Observer implementation.
- void OnRefreshTokenAvailable(const std::string& account_id) override;
- void OnRefreshTokenRevoked(const std::string& account_id) override;
- void OnRefreshTokensLoaded() override;
+ // Called by SyncAuthManager when an access token fetch attempt finishes
+ // (successfully or not).
+ void AccessTokenFetched(const GoogleServiceAuthError& error);
// KeyedService implementation. This must be called exactly
// once (before this object is destroyed).
@@ -545,7 +500,9 @@ class ProfileSyncService : public syncer::SyncServiceBase,
sync_sessions::FaviconCache* GetFaviconCache();
// Overrides the NetworkResources used for Sync connections.
- // This function takes ownership of |network_resources|.
+ // TODO(treib): Inject this in the ctor instead. As it is, it's possible that
+ // the real NetworkResources were already used before the test had a chance
+ // to call this.
void OverrideNetworkResourcesForTest(
std::unique_ptr<syncer::NetworkResources> network_resources);
@@ -582,16 +539,16 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// to start accounts with a clean slate when performing end to end testing.
void ClearServerDataForTest(const base::Closure& callback);
- protected:
- // SyncServiceBase implementation.
- syncer::SyncCredentials GetCredentials() override;
- syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler() override;
+ private:
+ virtual syncer::WeakHandle<syncer::JsEventHandler> GetJsEventHandler();
syncer::SyncEngine::HttpPostProviderFactoryGetter
- MakeHttpPostProviderFactoryGetter() override;
+ MakeHttpPostProviderFactoryGetter();
syncer::WeakHandle<syncer::UnrecoverableErrorHandler>
- GetUnrecoverableErrorHandler() override;
+ GetUnrecoverableErrorHandler();
+
+ // Destroys the |crypto_| object and creates a new one with fresh state.
+ void ResetCryptoState();
- private:
enum UnrecoverableErrorReason {
ERROR_REASON_UNSET,
ERROR_REASON_SYNCER,
@@ -602,12 +559,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
ERROR_REASON_LIMIT
};
- enum AuthErrorMetric {
- AUTH_ERROR_ENCOUNTERED,
- AUTH_ERROR_FIXED,
- AUTH_ERROR_LIMIT
- };
-
// The initial state of sync, for the Sync.InitialState histogram. Even if
// this value is CAN_START, sync startup might fail for reasons that we may
// want to consider logging in the future, such as a passphrase needed for
@@ -650,22 +601,16 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// deleted or kept when the engine shuts down.
void StopImpl(SyncStopDataFate data_fate);
- // Update the last auth error and notify observers of error state.
- void UpdateAuthErrorState(const GoogleServiceAuthError& error);
-
// Puts the engine's sync scheduler into NORMAL mode.
// Called when configuration is complete.
void StartSyncingWithServer();
- // RequestAccessToken initiates RPC to request downscoped access token from
- // refresh token. This happens when a new OAuth2 login token is loaded and
- // when sync server returns AUTH_ERROR which indicates it is time to refresh
- // token.
- void RequestAccessToken();
-
// Sets the last synced time to the current time.
void UpdateLastSyncedTime();
+ // Notify all observers that a change has occurred.
+ void NotifyObservers();
+
void NotifySyncCycleCompleted();
void NotifyForeignSessionUpdated();
void NotifyShutdown();
@@ -677,6 +622,9 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// Starts up the engine sync components.
virtual void StartUpSlowEngineComponents();
+ // Kicks off asynchronous initialization of the SyncEngine.
+ void InitializeEngine();
+
// Collects preferred sync data types from |preference_providers_|.
syncer::ModelTypeSet GetDataTypesFromPreferenceProviders() const;
@@ -747,20 +695,54 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// Called when a SetupInProgressHandle issued by this instance is destroyed.
virtual void OnSetupInProgressHandleDestroyed();
- SigninScopedDeviceIdCallback signin_scoped_device_id_callback_;
+ // This profile's SyncClient, which abstracts away non-Sync dependencies and
+ // the Sync API component factory.
+ const std::unique_ptr<syncer::SyncClient> sync_client_;
- // This is a cache of the last authentication response we received from the
- // sync server. The UI queries this to display appropriate messaging to the
- // user.
- GoogleServiceAuthError last_auth_error_;
+ // The class that handles getting, setting, and persisting sync preferences.
+ syncer::SyncPrefs sync_prefs_;
- // Cache of the last SyncCycleSnapshot received from the sync engine.
- syncer::SyncCycleSnapshot last_snapshot_;
+ // Encapsulates user signin - used to set/get the user's authenticated
+ // email address.
+ const std::unique_ptr<SigninManagerWrapper> signin_;
+
+ std::unique_ptr<SyncAuthManager> auth_manager_;
+
+ // The product channel of the embedder.
+ const version_info::Channel channel_;
+
+ // The path to the base directory under which sync should store its
+ // information.
+ const base::FilePath base_directory_;
+
+ // An identifier representing this instance for debugging purposes.
+ const std::string debug_identifier_;
- // TODO(ncarter): Put this in a profile, once there is UI for it.
// This specifies where to find the sync server.
const GURL sync_service_url_;
+ // A utility object containing logic and state relating to encryption. It is
+ // never null.
+ std::unique_ptr<syncer::SyncServiceCrypto> crypto_;
+
+ // The thread where all the sync operations happen. This thread is kept alive
+ // until browser shutdown and reused if sync is turned off and on again. It is
+ // joined during the shutdown process, but there is an abort mechanism in
+ // place to prevent slow HTTP requests from blocking browser shutdown.
+ std::unique_ptr<base::Thread> sync_thread_;
+
+ // Our asynchronous engine to communicate with sync components living on
+ // other threads.
+ std::unique_ptr<syncer::SyncEngine> engine_;
+
+ // Used to ensure that certain operations are performed on the sequence that
+ // this object was created on.
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ SigninScopedDeviceIdCallback signin_scoped_device_id_callback_;
+ // Cache of the last SyncCycleSnapshot received from the sync engine.
+ syncer::SyncCycleSnapshot last_snapshot_;
+
// The time that OnConfigureStart is called. This member is zero if
// OnConfigureStart has not yet been called, and is reset to zero once
// OnConfigureDone is called.
@@ -791,10 +773,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// signed out.
bool sync_disabled_by_admin_;
- // Set to true if a signin has completed but we're still waiting for the
- // engine to refresh its credentials.
- bool is_auth_in_progress_;
-
// Information describing an unrecoverable error.
UnrecoverableErrorReason unrecoverable_error_reason_;
std::string unrecoverable_error_message_;
@@ -803,6 +781,7 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// Manages the start and stop of the data types.
std::unique_ptr<syncer::DataTypeManager> data_type_manager_;
+ base::ObserverList<syncer::SyncServiceObserver> observers_;
base::ObserverList<syncer::ProtocolEventObserver> protocol_event_observers_;
base::ObserverList<syncer::TypeDebugInfoObserver> type_debug_info_observers_;
@@ -828,52 +807,23 @@ class ProfileSyncService : public syncer::SyncServiceBase,
// or must delay loading for some reason).
syncer::DataTypeStatusTable data_type_status_table_;
- syncer::DataTypeManager::ConfigureStatus configure_status_;
-
// The set of currently enabled sync experiments.
syncer::Experiments current_experiments_;
- // Sync's internal debug info listener. Used to record datatype configuration
- // and association information.
- syncer::WeakHandle<syncer::DataTypeDebugInfoListener> debug_info_listener_;
-
- // ProfileSyncService uses this service to get access tokens.
- ProfileOAuth2TokenService* const oauth2_token_service_;
-
- // ProfileSyncService needs to remember access token in order to invalidate it
- // with OAuth2TokenService.
- std::string access_token_;
-
- // ProfileSyncService needs to hold reference to access_token_request_ for
- // the duration of request in order to receive callbacks.
- std::unique_ptr<OAuth2TokenService::Request> access_token_request_;
-
- // If RequestAccessToken fails with transient error then retry requesting
- // access token with exponential backoff.
- base::OneShotTimer request_access_token_retry_timer_;
- net::BackoffEntry request_access_token_backoff_;
-
- // States related to sync token and connection.
- base::Time connection_status_update_time_;
- syncer::ConnectionStatus connection_status_;
- base::Time token_request_time_;
- base::Time token_receive_time_;
- GoogleServiceAuthError last_get_token_error_;
- base::Time next_token_request_time_;
-
// The gaia cookie manager. Used for monitoring cookie jar changes to detect
// when the user signs out of the content area.
GaiaCookieManagerService* const gaia_cookie_manager_service_;
std::unique_ptr<syncer::LocalDeviceInfoProvider> local_device_;
- // Locally owned SyncableService and ModelTypeSyncBridge implementations.
- std::unique_ptr<sync_sessions::SessionsSyncManager> sessions_sync_manager_;
+ // Locally owned SyncableService or ModelTypeSyncBridge implementations.
+ std::unique_ptr<sync_sessions::AbstractSessionsSyncManager>
+ sessions_sync_manager_;
std::unique_ptr<syncer::DeviceInfoSyncBridge> device_info_sync_bridge_;
std::unique_ptr<syncer::NetworkResources> network_resources_;
- StartBehavior start_behavior_;
+ const StartBehavior start_behavior_;
std::unique_ptr<syncer::StartupController> startup_controller_;
std::unique_ptr<syncer::SyncStoppedReporter> sync_stopped_reporter_;
@@ -905,8 +855,6 @@ class ProfileSyncService : public syncer::SyncServiceBase,
DISALLOW_COPY_AND_ASSIGN(ProfileSyncService);
};
-bool ShouldShowActionOnUI(const syncer::SyncProtocolError& error);
-
} // namespace browser_sync
#endif // COMPONENTS_BROWSER_SYNC_PROFILE_SYNC_SERVICE_H_
diff --git a/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc b/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
index e5a17014324..c33feb4f3ef 100644
--- a/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_autofill_unittest.cc
@@ -30,7 +30,6 @@
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/webdata/autofill_change.h"
-#include "components/autofill/core/browser/webdata/autofill_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autofill_profile_data_type_controller.h"
#include "components/autofill/core/browser/webdata/autofill_profile_syncable_service.h"
#include "components/autofill/core/browser/webdata/autofill_table.h"
@@ -55,6 +54,7 @@
#include "components/version_info/version_info.h"
#include "components/webdata/common/web_database.h"
#include "components/webdata_services/web_data_service_test_util.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -98,12 +98,12 @@ void RegisterAutofillPrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(autofill::prefs::kAutofillEnabled, true);
registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled,
true);
- registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileUseDatesFixed,
- true);
registry->RegisterIntegerPref(autofill::prefs::kAutofillLastVersionDeduped,
atoi(version_info::GetVersionNumber().c_str()));
registry->RegisterDoublePref(autofill::prefs::kAutofillBillingCustomerNumber,
0.0);
+ registry->RegisterBooleanPref(autofill::prefs::kAutofillOrphanRowsRemoved,
+ true);
}
void RunAndSignal(base::OnceClosure cb, WaitableEvent* event) {
@@ -315,8 +315,8 @@ class WebDataServiceFake : public AutofillWebDataService {
ACTION_P2(ReturnNewDataTypeManagerWithDebugListener,
sync_client,
debug_listener) {
- return new syncer::DataTypeManagerImpl(sync_client, arg0, debug_listener,
- arg2, arg3, arg4, arg5);
+ return std::make_unique<syncer::DataTypeManagerImpl>(
+ sync_client, arg0, debug_listener, arg2, arg3, arg4, arg5);
}
class MockPersonalDataManager : public PersonalDataManager {
@@ -407,8 +407,11 @@ class ProfileSyncServiceAutofillTest
}
void StartAutofillProfileSyncService(base::OnceClosure callback) {
- SigninManagerBase* signin = profile_sync_service_bundle()->signin_manager();
- signin->SetAuthenticatedAccountInfo("12345", "test_user@gmail.com");
+ identity::MakePrimaryAccountAvailable(
+ profile_sync_service_bundle()->signin_manager(),
+ profile_sync_service_bundle()->auth_service(),
+ profile_sync_service_bundle()->identity_manager(),
+ "test_user@gmail.com");
CreateSyncService(std::move(sync_client_owned_), std::move(callback));
EXPECT_CALL(*profile_sync_service_bundle()->component_factory(),
@@ -420,10 +423,6 @@ class ProfileSyncServiceAutofillTest
EXPECT_CALL(personal_data_manager(), IsDataLoaded())
.WillRepeatedly(Return(true));
- // We need tokens to get the tests going
- profile_sync_service_bundle()->auth_service()->UpdateCredentials(
- signin->GetAuthenticatedAccountId(), "oauth2_login_token");
-
sync_service()->RegisterDataTypeController(
std::make_unique<AutofillProfileDataTypeController>(
data_type_thread()->task_runner(), base::DoNothing(), sync_client_,
diff --git a/chromium/components/browser_sync/profile_sync_service_mock.h b/chromium/components/browser_sync/profile_sync_service_mock.h
index cb5003ff577..627e4c6cbd9 100644
--- a/chromium/components/browser_sync/profile_sync_service_mock.h
+++ b/chromium/components/browser_sync/profile_sync_service_mock.h
@@ -32,7 +32,7 @@ class ProfileSyncServiceMock : public ProfileSyncService {
// code.
explicit ProfileSyncServiceMock(InitParams* init_params);
- virtual ~ProfileSyncServiceMock();
+ ~ProfileSyncServiceMock() override;
MOCK_METHOD5(
OnEngineInitialized,
diff --git a/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc b/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
index 722e16bc617..519b4f9cc26 100644
--- a/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_startup_unittest.cc
@@ -25,6 +25,7 @@
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_constants.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -33,6 +34,7 @@ using syncer::DataTypeManagerMock;
using syncer::FakeSyncEngine;
using testing::_;
using testing::AnyNumber;
+using testing::ByMove;
using testing::DoAll;
using testing::Mock;
using testing::Return;
@@ -47,7 +49,7 @@ const char kEmail[] = "test_user@gmail.com";
class SyncServiceObserverMock : public syncer::SyncServiceObserver {
public:
SyncServiceObserverMock();
- virtual ~SyncServiceObserverMock();
+ ~SyncServiceObserverMock() override;
MOCK_METHOD1(OnStateChanged, void(syncer::SyncService*));
};
@@ -106,34 +108,27 @@ class ProfileSyncServiceStartupTest : public testing::Test {
}
protected:
- void SimulateTestUserSignin() {
- std::string account_id =
- profile_sync_service_bundle_.account_tracker()->SeedAccountInfo(kGaiaId,
- kEmail);
- pref_service()->SetString(prefs::kGoogleServicesAccountId, account_id);
-#if !defined(OS_CHROMEOS)
- const char kDummyPassword[] = "foobar";
- profile_sync_service_bundle_.signin_manager()->SignIn(kGaiaId, kEmail,
- kDummyPassword);
-#else
- profile_sync_service_bundle_.signin_manager()->SignIn(account_id);
-#endif
- profile_sync_service_bundle_.auth_service()->UpdateCredentials(
- account_id, "oauth2_login_token");
+ virtual void SimulateTestUserSignin() {
+ identity::MakePrimaryAccountAvailable(
+ profile_sync_service_bundle_.signin_manager(),
+ profile_sync_service_bundle_.auth_service(),
+ profile_sync_service_bundle_.identity_manager(), kEmail);
}
DataTypeManagerMock* SetUpDataTypeManager() {
- DataTypeManagerMock* data_type_manager = new DataTypeManagerMock();
+ auto data_type_manager = std::make_unique<DataTypeManagerMock>();
+ DataTypeManagerMock* data_type_manager_raw = data_type_manager.get();
EXPECT_CALL(*component_factory_, CreateDataTypeManager(_, _, _, _, _, _))
- .WillOnce(Return(data_type_manager));
- return data_type_manager;
+ .WillOnce(Return(ByMove(std::move(data_type_manager))));
+ return data_type_manager_raw;
}
FakeSyncEngine* SetUpSyncEngine() {
- FakeSyncEngine* sync_backend_host = new FakeSyncEngine();
+ auto sync_engine = std::make_unique<FakeSyncEngine>();
+ FakeSyncEngine* sync_engine_raw = sync_engine.get();
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
- .WillOnce(Return(sync_backend_host));
- return sync_backend_host;
+ .WillOnce(Return(ByMove(std::move(sync_engine))));
+ return sync_engine_raw;
}
PrefService* pref_service() {
@@ -153,19 +148,26 @@ class ProfileSyncServiceStartupCrosTest : public ProfileSyncServiceStartupTest {
ProfileSyncServiceStartupCrosTest() {
CreateSyncService(ProfileSyncService::AUTO_START);
// Set the primary account *without* providing an OAuth token.
- std::string account_id =
- profile_sync_service_bundle_.account_tracker()->SeedAccountInfo(kGaiaId,
- kEmail);
-#if !defined(OS_CHROMEOS)
- const char kDummyPassword[] = "foobar";
- profile_sync_service_bundle_.signin_manager()->SignIn(kGaiaId, kEmail,
- kDummyPassword);
-#else
- profile_sync_service_bundle_.signin_manager()->SignIn(account_id);
-#endif
+ // TODO(https://crbug.com/814787): Change this flow to go through a
+ // mainstream Identity Service API once that API exists. Note that this
+ // might require supplying a valid refresh token here as opposed to an
+ // empty string.
+ profile_sync_service_bundle_.identity_manager()
+ ->SetPrimaryAccountSynchronously(kGaiaId, kEmail,
+ /*refresh_token=*/std::string());
EXPECT_TRUE(
profile_sync_service_bundle_.signin_manager()->IsAuthenticated());
}
+
+ void SimulateTestUserSignin() override {
+ // We already populated the primary account above, all that's left to do
+ // is provide a refresh token.
+ profile_sync_service_bundle_.auth_service()->UpdateCredentials(
+ profile_sync_service_bundle_.identity_manager()
+ ->GetPrimaryAccountInfo()
+ .account_id,
+ "oauth2_login_token");
+ }
};
TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
diff --git a/chromium/components/browser_sync/profile_sync_service_unittest.cc b/chromium/components/browser_sync/profile_sync_service_unittest.cc
index 36e6591ae3a..0b9ca2fbcbf 100644
--- a/chromium/components/browser_sync/profile_sync_service_unittest.cc
+++ b/chromium/components/browser_sync/profile_sync_service_unittest.cc
@@ -8,32 +8,30 @@
#include "base/callback.h"
#include "base/command_line.h"
-#include "base/feature_list.h"
#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "components/browser_sync/browser_sync_switches.h"
#include "components/browser_sync/profile_sync_test_util.h"
-#include "components/invalidation/impl/profile_invalidation_provider.h"
-#include "components/invalidation/public/invalidation_service.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
#include "components/sync/base/pref_names.h"
+#include "components/sync/device_info/local_device_info_provider.h"
#include "components/sync/driver/fake_data_type_controller.h"
+#include "components/sync/driver/signin_manager_wrapper.h"
#include "components/sync/driver/sync_api_component_factory_mock.h"
#include "components/sync/driver/sync_driver_switches.h"
#include "components/sync/driver/sync_service_observer.h"
+#include "components/sync/driver/sync_token_status.h"
#include "components/sync/driver/sync_util.h"
#include "components/sync/engine/fake_sync_engine.h"
#include "components/sync/model/model_type_store_test_util.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "components/version_info/version_info_values.h"
-#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/oauth2_token_service_delegate.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -41,15 +39,13 @@ using syncer::DataTypeController;
using syncer::FakeSyncEngine;
using syncer::ModelTypeSet;
using syncer::SyncMergeResult;
+using testing::ByMove;
using testing::Return;
namespace browser_sync {
namespace {
-const char kGaiaId[] = "12345";
-const char kEmail[] = "test_user@gmail.com";
-
class FakeDataTypeManager : public syncer::DataTypeManager {
public:
using ConfigureCalled = base::Callback<void(syncer::ConfigureReason)>;
@@ -79,7 +75,7 @@ class FakeDataTypeManager : public syncer::DataTypeManager {
};
ACTION_P(ReturnNewDataTypeManager, configure_called) {
- return new FakeDataTypeManager(configure_called);
+ return std::make_unique<FakeDataTypeManager>(configure_called);
}
using testing::Return;
@@ -90,6 +86,7 @@ class TestSyncServiceObserver : public syncer::SyncServiceObserver {
public:
TestSyncServiceObserver()
: setup_in_progress_(false), auth_error_(GoogleServiceAuthError()) {}
+
void OnStateChanged(syncer::SyncService* sync) override {
setup_in_progress_ = sync->IsSetupInProgress();
auth_error_ = sync->GetAuthError();
@@ -159,15 +156,7 @@ class SyncEngineCaptureInvalidateCredentials : public FakeSyncEngine {
};
ACTION(ReturnNewFakeSyncEngine) {
- return new FakeSyncEngine();
-}
-
-ACTION(ReturnNewSyncEngineNoReturn) {
- return new SyncEngineNoReturn();
-}
-
-ACTION_P(ReturnNewMockHostCollectDeleteDirParam, delete_dir_param) {
- return new FakeSyncEngineCollectDeleteDirParam(delete_dir_param);
+ return std::make_unique<FakeSyncEngine>();
}
void OnClearServerDataCalled(base::Closure* captured_callback,
@@ -175,15 +164,6 @@ void OnClearServerDataCalled(base::Closure* captured_callback,
*captured_callback = callback;
}
-ACTION_P(ReturnNewMockHostCaptureClearServerData, captured_callback) {
- return new SyncEngineCaptureClearServerData(base::Bind(
- &OnClearServerDataCalled, base::Unretained(captured_callback)));
-}
-
-ACTION_P(ReturnNewMockHostCaptureInvalidateCredentials, callback) {
- return new SyncEngineCaptureInvalidateCredentials(callback);
-}
-
// A test harness that uses a real ProfileSyncService and in most cases a
// MockSyncEngine.
//
@@ -208,14 +188,9 @@ class ProfileSyncServiceTest : public ::testing::Test {
}
void IssueTestTokens() {
- std::string account_id =
- account_tracker()->SeedAccountInfo(kGaiaId, kEmail);
- auth_service()->UpdateCredentials(account_id, "oauth2_login_token");
-#if defined(OS_CHROMEOS)
- signin_manager()->SignIn(account_id);
-#else
- signin_manager()->SignIn(kGaiaId, kEmail, "password");
-#endif
+ identity::MakePrimaryAccountAvailable(signin_manager(), auth_service(),
+ identity_manager(),
+ "test_user@gmail.com");
}
void CreateService(ProfileSyncService::StartBehavior behavior) {
@@ -316,32 +291,26 @@ class ProfileSyncServiceTest : public ::testing::Test {
.WillRepeatedly(ReturnNewFakeSyncEngine());
}
- void ExpectSyncEngineCreationCollectDeleteDir(
- int times,
- std::vector<bool>* delete_dir_param) {
- EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
- .Times(times)
- .WillRepeatedly(
- ReturnNewMockHostCollectDeleteDirParam(delete_dir_param));
- }
-
void ExpectSyncEngineCreationCaptureClearServerData(
base::Closure* captured_callback) {
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
- .Times(1)
- .WillOnce(ReturnNewMockHostCaptureClearServerData(captured_callback));
+ .WillOnce(
+ Return(ByMove(std::make_unique<SyncEngineCaptureClearServerData>(
+ base::BindRepeating(&OnClearServerDataCalled,
+ base::Unretained(captured_callback))))));
}
void ExpectSyncEngineCreationCaptureInvalidateCredentials(
const base::RepeatingClosure& callback) {
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
- .Times(1)
- .WillOnce(ReturnNewMockHostCaptureInvalidateCredentials(callback));
+ .WillOnce(Return(
+ ByMove(std::make_unique<SyncEngineCaptureInvalidateCredentials>(
+ callback))));
}
void PrepareDelayedInitSyncEngine() {
EXPECT_CALL(*component_factory_, CreateSyncEngine(_, _, _, _))
- .WillOnce(ReturnNewSyncEngineNoReturn());
+ .WillOnce(Return(ByMove(std::make_unique<SyncEngineNoReturn>())));
}
AccountTrackerService* account_tracker() {
@@ -362,6 +331,10 @@ class ProfileSyncServiceTest : public ::testing::Test {
return profile_sync_service_bundle_.auth_service();
}
+ identity::IdentityManager* identity_manager() {
+ return profile_sync_service_bundle_.identity_manager();
+ }
+
ProfileSyncService* service() { return service_.get(); }
sync_preferences::TestingPrefServiceSyncable* prefs() {
@@ -568,6 +541,8 @@ TEST_F(ProfileSyncServiceTest, EnableSyncAndSignOut) {
signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST,
signin_metrics::SignoutDelete::IGNORE_METRIC);
+ // Wait for PSS to be notified that the primary account has gone away.
+ base::RunLoop().RunUntilIdle();
EXPECT_FALSE(service()->IsSyncActive());
}
#endif // !defined(OS_CHROMEOS)
@@ -580,8 +555,7 @@ TEST_F(ProfileSyncServiceTest, GetSyncTokenStatus) {
InitializeForNthSync();
// Initial status.
- ProfileSyncService::SyncTokenStatus token_status =
- service()->GetSyncTokenStatus();
+ syncer::SyncTokenStatus token_status = service()->GetSyncTokenStatus();
ASSERT_EQ(syncer::CONNECTION_NOT_ATTEMPTED, token_status.connection_status);
ASSERT_TRUE(token_status.connection_status_update_time.is_null());
ASSERT_TRUE(token_status.token_request_time.is_null());
@@ -657,17 +631,14 @@ TEST_F(ProfileSyncServiceTest, CredentialsRejectedByClient) {
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(service()->GetAccessTokenForTest().empty());
+ // Simulate the credentials getting locally rejected by the client by setting
+ // the refresh token to a special invalid value.
+ auth_service()->UpdateCredentials(
+ primary_account_id, OAuth2TokenServiceDelegate::kInvalidRefreshToken);
GoogleServiceAuthError rejected_by_client =
GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
GoogleServiceAuthError::InvalidGaiaCredentialsReason::
CREDENTIALS_REJECTED_BY_CLIENT);
- auth_service()->UpdateAuthErrorForTesting(primary_account_id,
- rejected_by_client);
- // The access token is not yet invalidated, it will be invalidated when
- // OnRefreshTokenAvailable() is called.
- EXPECT_FALSE(service()->GetAccessTokenForTest().empty());
- EXPECT_FALSE(invalidate_credentials_called);
- auth_service()->LoadCredentials(primary_account_id);
ASSERT_EQ(rejected_by_client,
auth_service()->GetAuthError(primary_account_id));
EXPECT_TRUE(service()->GetAccessTokenForTest().empty());
@@ -735,6 +706,8 @@ TEST_F(ProfileSyncServiceTest, CredentialErrorReturned) {
std::string primary_account_id =
signin_manager()->GetAuthenticatedAccountId();
auth_service()->LoadCredentials(primary_account_id);
+ // Wait for ProfileSyncService to be notified of the loaded credentials and
+ // send an access token request.
base::RunLoop().RunUntilIdle();
auth_service()->IssueAllTokensForAccount(primary_account_id, "access token",
base::Time::Max());
@@ -744,6 +717,8 @@ TEST_F(ProfileSyncServiceTest, CredentialErrorReturned) {
// Emulate Chrome receiving a new, invalid LST. This happens when the user
// signs out of the content area.
auth_service()->UpdateCredentials(primary_account_id, "not a valid token");
+ // Again, wait for ProfileSyncService to be notified.
+ base::RunLoop().RunUntilIdle();
auth_service()->IssueErrorForAllPendingRequests(
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
@@ -776,6 +751,8 @@ TEST_F(ProfileSyncServiceTest, CredentialErrorClearsOnNewToken) {
std::string primary_account_id =
signin_manager()->GetAuthenticatedAccountId();
auth_service()->LoadCredentials(primary_account_id);
+ // Wait for ProfileSyncService to be notified of the loaded credentials and
+ // send an access token request.
base::RunLoop().RunUntilIdle();
auth_service()->IssueAllTokensForAccount(primary_account_id, "access token",
base::Time::Max());
@@ -785,6 +762,9 @@ TEST_F(ProfileSyncServiceTest, CredentialErrorClearsOnNewToken) {
// Emulate Chrome receiving a new, invalid LST. This happens when the user
// signs out of the content area.
auth_service()->UpdateCredentials(primary_account_id, "not a valid token");
+ // Wait for ProfileSyncService to be notified of the changed credentials and
+ // send a new access token request.
+ base::RunLoop().RunUntilIdle();
auth_service()->IssueErrorForAllPendingRequests(
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
@@ -794,6 +774,8 @@ TEST_F(ProfileSyncServiceTest, CredentialErrorClearsOnNewToken) {
// Now emulate Chrome receiving a new, valid LST.
auth_service()->UpdateCredentials(primary_account_id, "totally valid token");
+ // Again, wait for ProfileSyncService to be notified.
+ base::RunLoop().RunUntilIdle();
auth_service()->IssueTokenForAllPendingRequests(
"this one works", base::Time::Now() + base::TimeDelta::FromDays(10));
@@ -1136,7 +1118,15 @@ TEST_F(ProfileSyncServiceTest, LocalBackendDisabledByPolicy) {
TEST_F(ProfileSyncServiceTest, ValidPointersInDTCMap) {
CreateService(ProfileSyncService::AUTO_START);
service()->OnSessionRestoreComplete();
- service()->OnSyncCycleCompleted(syncer::SyncCycleSnapshot());
+ service()->OnSyncCycleCompleted(syncer::SyncCycleSnapshot(
+ syncer::ModelNeutralState(), syncer::ProgressMarkerMap(), false, 0, 0, 0,
+ false, 0, base::Time::Now(), base::Time::Now(),
+ std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
+ std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
+ sync_pb::SyncEnums::UNKNOWN_ORIGIN,
+ /*short_poll_interval=*/base::TimeDelta::FromMinutes(30),
+ /*long_poll_interval=*/base::TimeDelta::FromMinutes(180),
+ /*has_remaining_local_changes=*/false));
}
// The OpenTabsUIDelegate should only be accessable when PROXY_TABS is enabled.
diff --git a/chromium/components/browser_sync/sync_auth_manager.cc b/chromium/components/browser_sync/sync_auth_manager.cc
new file mode 100644
index 00000000000..8ff2fe90700
--- /dev/null
+++ b/chromium/components/browser_sync/sync_auth_manager.cc
@@ -0,0 +1,359 @@
+// 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 "components/browser_sync/sync_auth_manager.h"
+
+#include <utility>
+
+#include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "components/browser_sync/profile_sync_service.h"
+#include "components/sync/base/stop_source.h"
+#include "components/sync/base/sync_prefs.h"
+#include "components/sync/engine/sync_credentials.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
+
+namespace browser_sync {
+
+namespace {
+
+constexpr char kSyncOAuthConsumerName[] = "sync";
+
+constexpr net::BackoffEntry::Policy kRequestAccessTokenBackoffPolicy = {
+ // Number of initial errors (in sequence) to ignore before applying
+ // exponential back-off rules.
+ 0,
+
+ // Initial delay for exponential back-off in ms.
+ 2000,
+
+ // Factor by which the waiting time will be multiplied.
+ 2,
+
+ // Fuzzing percentage. ex: 10% will spread requests randomly
+ // between 90%-100% of the calculated time.
+ 0.2, // 20%
+
+ // Maximum amount of time we are willing to delay our request in ms.
+ // TODO(crbug.com/246686): We should retry RequestAccessToken on connection
+ // state change after backoff.
+ 1000 * 3600 * 4, // 4 hours.
+
+ // Time to keep an entry from being discarded even when it
+ // has no significant state, -1 to never discard.
+ -1,
+
+ // Don't use initial delay unless the last request was an error.
+ false,
+};
+
+} // namespace
+
+SyncAuthManager::SyncAuthManager(ProfileSyncService* sync_service,
+ syncer::SyncPrefs* sync_prefs,
+ identity::IdentityManager* identity_manager,
+ OAuth2TokenService* token_service)
+ : sync_service_(sync_service),
+ sync_prefs_(sync_prefs),
+ identity_manager_(identity_manager),
+ token_service_(token_service),
+ registered_for_auth_notifications_(false),
+ is_auth_in_progress_(false),
+ request_access_token_backoff_(&kRequestAccessTokenBackoffPolicy),
+ weak_ptr_factory_(this) {
+ DCHECK(sync_service_);
+ DCHECK(sync_prefs_);
+ // |identity_manager_| and |token_service_| can be null if local Sync is
+ // enabled.
+}
+
+SyncAuthManager::~SyncAuthManager() {
+ if (registered_for_auth_notifications_) {
+ token_service_->RemoveObserver(this);
+ identity_manager_->RemoveObserver(this);
+ }
+}
+
+void SyncAuthManager::RegisterForAuthNotifications() {
+ DCHECK(!registered_for_auth_notifications_);
+ identity_manager_->AddObserver(this);
+ token_service_->AddObserver(this);
+ registered_for_auth_notifications_ = true;
+}
+
+AccountInfo SyncAuthManager::GetAuthenticatedAccountInfo() const {
+ return identity_manager_ ? identity_manager_->GetPrimaryAccountInfo()
+ : AccountInfo();
+}
+
+bool SyncAuthManager::RefreshTokenIsAvailable() const {
+ std::string account_id = GetAuthenticatedAccountInfo().account_id;
+ return !account_id.empty() &&
+ token_service_->RefreshTokenIsAvailable(account_id);
+}
+
+const syncer::SyncTokenStatus& SyncAuthManager::GetSyncTokenStatus() const {
+ return token_status_;
+}
+
+syncer::SyncCredentials SyncAuthManager::GetCredentials() const {
+ syncer::SyncCredentials credentials;
+
+ const AccountInfo account_info = GetAuthenticatedAccountInfo();
+ credentials.account_id = account_info.account_id;
+ credentials.email = account_info.email;
+ credentials.sync_token = access_token_;
+
+ credentials.scope_set.insert(GaiaConstants::kChromeSyncOAuth2Scope);
+
+ return credentials;
+}
+
+void SyncAuthManager::ConnectionStatusChanged(syncer::ConnectionStatus status) {
+ token_status_.connection_status_update_time = base::Time::Now();
+ token_status_.connection_status = status;
+
+ switch (status) {
+ case syncer::CONNECTION_AUTH_ERROR:
+ // Sync server returned error indicating that access token is invalid. It
+ // could be either expired or access is revoked. Let's request another
+ // access token and if access is revoked then request for token will fail
+ // with corresponding error. If access token is repeatedly reported
+ // invalid, there may be some issues with server, e.g. authentication
+ // state is inconsistent on sync and token server. In that case, we
+ // backoff token requests exponentially to avoid hammering token server
+ // too much and to avoid getting same token due to token server's caching
+ // policy. |request_access_token_retry_timer_| is used to backoff request
+ // triggered by both auth error and failure talking to GAIA server.
+ // Therefore, we're likely to reach the backoff ceiling more quickly than
+ // you would expect from looking at the BackoffPolicy if both types of
+ // errors happen. We shouldn't receive two errors back-to-back without
+ // attempting a token/sync request in between, thus crank up request delay
+ // unnecessary. This is because we won't make a sync request if we hit an
+ // error until GAIA succeeds at sending a new token, and we won't request
+ // a new token unless sync reports a token failure. But to be safe, don't
+ // schedule request if this happens.
+ if (request_access_token_retry_timer_.IsRunning()) {
+ // The timer to perform a request later is already running; nothing
+ // further needs to be done at this point.
+ } else if (request_access_token_backoff_.failure_count() == 0) {
+ // First time request without delay. Currently invalid token is used
+ // to initialize sync engine and we'll always end up here. We don't
+ // want to delay initialization.
+ request_access_token_backoff_.InformOfRequest(false);
+ RequestAccessToken();
+ } else {
+ request_access_token_backoff_.InformOfRequest(false);
+ base::TimeDelta delay =
+ request_access_token_backoff_.GetTimeUntilRelease();
+ token_status_.next_token_request_time = base::Time::Now() + delay;
+ request_access_token_retry_timer_.Start(
+ FROM_HERE, delay,
+ base::BindRepeating(&SyncAuthManager::RequestAccessToken,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+ break;
+ case syncer::CONNECTION_OK:
+ // Reset backoff time after successful connection.
+ // Request shouldn't be scheduled at this time. But if it is, it's
+ // possible that sync flips between OK and auth error states rapidly,
+ // thus hammers token server. To be safe, only reset backoff delay when
+ // no scheduled request.
+ if (!request_access_token_retry_timer_.IsRunning()) {
+ request_access_token_backoff_.Reset();
+ }
+ ClearAuthError();
+ break;
+ case syncer::CONNECTION_SERVER_ERROR:
+ UpdateAuthErrorState(
+ GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
+ break;
+ case syncer::CONNECTION_NOT_ATTEMPTED:
+ // The connection status should never change to "not attempted".
+ NOTREACHED();
+ break;
+ }
+}
+
+void SyncAuthManager::UpdateAuthErrorState(
+ const GoogleServiceAuthError& error) {
+ is_auth_in_progress_ = false;
+ last_auth_error_ = error;
+}
+
+void SyncAuthManager::ClearAuthError() {
+ UpdateAuthErrorState(GoogleServiceAuthError::AuthErrorNone());
+}
+
+void SyncAuthManager::ClearAccessTokenAndRequest() {
+ access_token_.clear();
+ request_access_token_retry_timer_.Stop();
+ token_status_.next_token_request_time = base::Time();
+ ongoing_access_token_fetch_.reset();
+ weak_ptr_factory_.InvalidateWeakPtrs();
+}
+
+void SyncAuthManager::Clear() {
+ ClearAuthError();
+ ClearAccessTokenAndRequest();
+}
+
+void SyncAuthManager::OnPrimaryAccountSet(
+ const AccountInfo& primary_account_info) {
+ // Track the fact that we're still waiting for auth to complete.
+ DCHECK(!is_auth_in_progress_);
+ is_auth_in_progress_ = true;
+
+ sync_service_->OnPrimaryAccountSet();
+
+ if (token_service_->RefreshTokenIsAvailable(
+ primary_account_info.account_id)) {
+ OnRefreshTokenAvailable(primary_account_info.account_id);
+ }
+}
+
+void SyncAuthManager::OnPrimaryAccountCleared(
+ const AccountInfo& previous_primary_account_info) {
+ UMA_HISTOGRAM_ENUMERATION("Sync.StopSource", syncer::SIGN_OUT,
+ syncer::STOP_SOURCE_LIMIT);
+ is_auth_in_progress_ = false;
+ sync_service_->OnPrimaryAccountCleared();
+}
+
+void SyncAuthManager::OnRefreshTokenAvailable(const std::string& account_id) {
+ if (account_id != GetAuthenticatedAccountInfo().account_id) {
+ return;
+ }
+
+ GoogleServiceAuthError token_error =
+ token_service_->GetAuthError(GetAuthenticatedAccountInfo().account_id);
+ if (token_error == GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
+ GoogleServiceAuthError::InvalidGaiaCredentialsReason::
+ CREDENTIALS_REJECTED_BY_CLIENT)) {
+ is_auth_in_progress_ = false;
+ // When the refresh token is replaced by a new token with a
+ // CREDENTIALS_REJECTED_BY_CLIENT error, Sync must be stopped immediately,
+ // even if the current access token is still valid. This happens e.g. when
+ // the user signs out of the web with Dice enabled.
+ // It is not necessary to do this when the refresh token is
+ // CREDENTIALS_REJECTED_BY_SERVER, because in that case the access token
+ // will be rejected by the server too.
+ // We only do this in OnRefreshTokensLoaded(), as opposed to
+ // OAuth2TokenService::Observer::OnAuthErrorChanged(), because
+ // CREDENTIALS_REJECTED_BY_CLIENT is only set by the signin component when
+ // the refresh token is created.
+ ClearAccessTokenAndRequest();
+ // TODO(treib): Should we also set our auth error state?
+
+ sync_service_->OnRefreshTokenRevoked();
+ // TODO(treib): We can probably early-out here - no point in also calling
+ // OnRefreshTokenAvailable on the ProfileSyncService.
+ }
+
+ sync_service_->OnRefreshTokenAvailable();
+}
+
+void SyncAuthManager::OnRefreshTokenRevoked(const std::string& account_id) {
+ if (account_id != GetAuthenticatedAccountInfo().account_id) {
+ return;
+ }
+
+ UpdateAuthErrorState(
+ GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
+
+ ClearAccessTokenAndRequest();
+
+ sync_service_->OnRefreshTokenRevoked();
+}
+
+void SyncAuthManager::OnRefreshTokensLoaded() {
+ // This notification gets fired when OAuth2TokenService loads the tokens from
+ // storage. Initialize the engine if sync is enabled. If the sync token was
+ // not loaded, GetCredentials() will generate invalid credentials to cause the
+ // engine to generate an auth error (https://crbug.com/121755).
+ // TODO(treib): Is this necessary? Either we actually have a refresh token, in
+ // which case this was already called from OnRefreshTokenAvailable above, or
+ // there is no refresh token, in which case Sync can't start anyway.
+ sync_service_->OnRefreshTokenAvailable();
+}
+
+bool SyncAuthManager::IsRetryingAccessTokenFetchForTest() const {
+ return request_access_token_retry_timer_.IsRunning();
+}
+
+void SyncAuthManager::RequestAccessToken() {
+ // Only one active request at a time.
+ if (ongoing_access_token_fetch_) {
+ return;
+ }
+ request_access_token_retry_timer_.Stop();
+ token_status_.next_token_request_time = base::Time();
+
+ OAuth2TokenService::ScopeSet oauth2_scopes;
+ oauth2_scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
+
+ // Invalidate previous token, otherwise token service will return the same
+ // token again.
+ if (!access_token_.empty()) {
+ identity_manager_->RemoveAccessTokenFromCache(GetAuthenticatedAccountInfo(),
+ oauth2_scopes, access_token_);
+ }
+
+ access_token_.clear();
+
+ token_status_.token_request_time = base::Time::Now();
+ token_status_.token_receive_time = base::Time();
+ token_status_.next_token_request_time = base::Time();
+ ongoing_access_token_fetch_ =
+ identity_manager_->CreateAccessTokenFetcherForPrimaryAccount(
+ kSyncOAuthConsumerName, oauth2_scopes,
+ base::BindOnce(&SyncAuthManager::AccessTokenFetched,
+ base::Unretained(this)),
+ identity::PrimaryAccountAccessTokenFetcher::Mode::kImmediate);
+}
+
+void SyncAuthManager::AccessTokenFetched(const GoogleServiceAuthError& error,
+ const std::string& access_token) {
+ DCHECK(ongoing_access_token_fetch_);
+
+ std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> fetcher_deleter(
+ std::move(ongoing_access_token_fetch_));
+
+ access_token_ = access_token;
+ token_status_.last_get_token_error = error;
+
+ switch (error.state()) {
+ case GoogleServiceAuthError::NONE:
+ token_status_.token_receive_time = base::Time::Now();
+ sync_prefs_->SetSyncAuthError(false);
+ ClearAuthError();
+ break;
+ case GoogleServiceAuthError::CONNECTION_FAILED:
+ case GoogleServiceAuthError::REQUEST_CANCELED:
+ case GoogleServiceAuthError::SERVICE_ERROR:
+ case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
+ // Transient error. Retry after some time.
+ request_access_token_backoff_.InformOfRequest(false);
+ token_status_.next_token_request_time =
+ base::Time::Now() +
+ request_access_token_backoff_.GetTimeUntilRelease();
+ request_access_token_retry_timer_.Start(
+ FROM_HERE, request_access_token_backoff_.GetTimeUntilRelease(),
+ base::BindRepeating(&SyncAuthManager::RequestAccessToken,
+ weak_ptr_factory_.GetWeakPtr()));
+ break;
+ case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
+ sync_prefs_->SetSyncAuthError(true);
+ UpdateAuthErrorState(error);
+ break;
+ default:
+ LOG(ERROR) << "Unexpected persistent error: " << error.ToString();
+ UpdateAuthErrorState(error);
+ }
+
+ sync_service_->AccessTokenFetched(error);
+}
+
+} // namespace browser_sync
diff --git a/chromium/components/browser_sync/sync_auth_manager.h b/chromium/components/browser_sync/sync_auth_manager.h
new file mode 100644
index 00000000000..219c7d052e6
--- /dev/null
+++ b/chromium/components/browser_sync/sync_auth_manager.h
@@ -0,0 +1,149 @@
+// 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 COMPONENTS_BROWSER_SYNC_SYNC_AUTH_MANAGER_H_
+#define COMPONENTS_BROWSER_SYNC_SYNC_AUTH_MANAGER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/sync/driver/sync_token_status.h"
+#include "google_apis/gaia/google_service_auth_error.h"
+#include "google_apis/gaia/oauth2_token_service.h"
+#include "net/base/backoff_entry.h"
+#include "services/identity/public/cpp/identity_manager.h"
+
+namespace identity {
+class PrimaryAccountAccessTokenFetcher;
+}
+
+namespace syncer {
+struct SyncCredentials;
+class SyncPrefs;
+} // namespace syncer
+
+namespace browser_sync {
+
+class ProfileSyncService;
+
+// SyncAuthManager tracks the primary (i.e. blessed-for-sync) account and its
+// authentication state.
+class SyncAuthManager : public identity::IdentityManager::Observer,
+ public OAuth2TokenService::Observer {
+ public:
+ // |sync_service| and |sync_prefs| must not be null and must outlive this.
+ // |identity_manager| and |token_service| may be null (this is the case if
+ // local Sync is enabled), but if non-null, must outlive this object.
+ // TODO(crbug.com/842697): Don't pass the ProfileSyncService in here. Instead,
+ // pass a callback ("AccountStateChanged(new_state)").
+ SyncAuthManager(ProfileSyncService* sync_service,
+ syncer::SyncPrefs* sync_prefs,
+ identity::IdentityManager* identity_manager,
+ OAuth2TokenService* token_service);
+ ~SyncAuthManager() override;
+
+ // Tells the tracker to start listening for changes to the account/sign-in
+ // status. This gets called during SyncService initialization, except in the
+ // case of local Sync.
+ void RegisterForAuthNotifications();
+
+ // Returns the AccountInfo for the primary (i.e. blessed-for-sync) account, or
+ // an empty AccountInfo if there isn't one.
+ AccountInfo GetAuthenticatedAccountInfo() const;
+
+ // Returns whether a refresh token is available for the primary account.
+ // TODO(crbug.com/842697, crbug.com/825190): ProfileSyncService shouldn't have
+ // to care about the refresh token state.
+ bool RefreshTokenIsAvailable() const;
+
+ const GoogleServiceAuthError& GetLastAuthError() const {
+ return last_auth_error_;
+ }
+ bool IsAuthInProgress() const { return is_auth_in_progress_; }
+
+ // Returns the credentials to be passed to the SyncEngine.
+ syncer::SyncCredentials GetCredentials() const;
+
+ const std::string& access_token() const { return access_token_; }
+
+ // Returns the state of the access token and token request, for display in
+ // internals UI.
+ const syncer::SyncTokenStatus& GetSyncTokenStatus() const;
+
+ // Called by ProfileSyncService when the status of the connection to the Sync
+ // server changed. Updates auth error state accordingly.
+ void ConnectionStatusChanged(syncer::ConnectionStatus status);
+
+ // TODO(crbug.com/842697, crbug.com/825190): Make this private once
+ // ProfileSyncService doesn't care about the refresh token state anymore.
+ void RequestAccessToken();
+
+ // Clears all auth-related state (error, cached access token etc). Called
+ // when Sync is turned off.
+ void Clear();
+
+ // identity::IdentityManager::Observer implementation.
+ void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override;
+ void OnPrimaryAccountCleared(
+ const AccountInfo& previous_primary_account_info) override;
+
+ // OAuth2TokenService::Observer implementation.
+ void OnRefreshTokenAvailable(const std::string& account_id) override;
+ void OnRefreshTokenRevoked(const std::string& account_id) override;
+ void OnRefreshTokensLoaded() override;
+
+ // Test-only method for inspecting internal state.
+ bool IsRetryingAccessTokenFetchForTest() const;
+
+ private:
+ void UpdateAuthErrorState(const GoogleServiceAuthError& error);
+ void ClearAuthError();
+
+ void ClearAccessTokenAndRequest();
+
+ void AccessTokenFetched(const GoogleServiceAuthError& error,
+ const std::string& access_token);
+
+ ProfileSyncService* const sync_service_;
+ syncer::SyncPrefs* const sync_prefs_;
+ identity::IdentityManager* const identity_manager_;
+ OAuth2TokenService* const token_service_;
+
+ bool registered_for_auth_notifications_;
+
+ // This is a cache of the last authentication response we received either
+ // from the sync server or from Chrome's identity/token management system.
+ GoogleServiceAuthError last_auth_error_;
+
+ // Set to true if a signin has completed but we're still waiting for the
+ // engine to refresh its credentials.
+ bool is_auth_in_progress_;
+
+ std::string access_token_;
+
+ // Pending request for an access token. Non-null iff there is a request
+ // ongoing.
+ std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher>
+ ongoing_access_token_fetch_;
+
+ // If RequestAccessToken fails with transient error then retry requesting
+ // access token with exponential backoff.
+ base::OneShotTimer request_access_token_retry_timer_;
+ net::BackoffEntry request_access_token_backoff_;
+
+ // Info about the state of our access token, for display in the internals UI.
+ syncer::SyncTokenStatus token_status_;
+
+ base::WeakPtrFactory<SyncAuthManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncAuthManager);
+};
+
+} // namespace browser_sync
+
+#endif // COMPONENTS_BROWSER_SYNC_SYNC_AUTH_MANAGER_H_
diff --git a/chromium/components/browser_watcher/dump_stability_report_main_win.cc b/chromium/components/browser_watcher/dump_stability_report_main_win.cc
index bc3940ad8a0..b4a9cecfbe3 100644
--- a/chromium/components/browser_watcher/dump_stability_report_main_win.cc
+++ b/chromium/components/browser_watcher/dump_stability_report_main_win.cc
@@ -179,6 +179,10 @@ void PrintProcessState(FILE* out,
fprintf(out, "process_allocation_attempt: %u bytes\n",
windows_memory.process_allocation_attempt());
}
+ if (windows_memory.has_process_handle_count()) {
+ fprintf(out, "process_handle_count: %u handles\n",
+ windows_memory.process_handle_count());
+ }
}
for (const browser_watcher::ThreadState& thread : process.threads()) {
@@ -205,6 +209,10 @@ void PrintReport(FILE* out, const browser_watcher::StabilityReport& report) {
fprintf(out, "system_commit_remaining: %u pages\n",
windows_memory.system_commit_remaining());
}
+ if (windows_memory.has_system_handle_count()) {
+ fprintf(out, "system_handle_count: %u handles\n",
+ windows_memory.system_handle_count());
+ }
}
PrintUserData(out, 0, report.global_data());
for (int i = 0; i < report.process_states_size(); ++i) {
diff --git a/chromium/components/browser_watcher/endsession_watcher_window_win.cc b/chromium/components/browser_watcher/endsession_watcher_window_win.cc
index cf4bb82343b..8f6d3132918 100644
--- a/chromium/components/browser_watcher/endsession_watcher_window_win.cc
+++ b/chromium/components/browser_watcher/endsession_watcher_window_win.cc
@@ -21,16 +21,15 @@ EndSessionWatcherWindow::EndSessionWatcherWindow(
WNDCLASSEX window_class = {0};
base::win::InitializeWindowClass(
kWindowClassName,
- &base::win::WrappedWindowProc<EndSessionWatcherWindow::WndProcThunk>,
- 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
- &window_class);
+ &base::win::WrappedWindowProc<EndSessionWatcherWindow::WndProcThunk>, 0,
+ 0, 0, nullptr, nullptr, nullptr, nullptr, nullptr, &window_class);
instance_ = window_class.hInstance;
ATOM clazz = ::RegisterClassEx(&window_class);
DCHECK(clazz);
// TODO(siggi): will a message window do here?
- window_ = ::CreateWindow(kWindowClassName,
- 0, 0, 0, 0, 0, 0, 0, 0, instance_, 0);
+ window_ = ::CreateWindow(kWindowClassName, nullptr, 0, 0, 0, 0, 0, nullptr,
+ nullptr, instance_, nullptr);
::SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
DCHECK_EQ(::GetWindowLongPtr(window_, GWLP_USERDATA),
reinterpret_cast<LONG_PTR>(this));
diff --git a/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc b/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
index 9c1a0741b94..e5edaa282ee 100644
--- a/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
+++ b/chromium/components/browser_watcher/exit_code_watcher_win_unittest.cc
@@ -123,7 +123,7 @@ TEST_F(ExitCodeWatcherTest, ExitCodeWatcherInvalidHandleFailsInit) {
ExitCodeWatcher watcher(kRegistryPath);
// A waitable event has a non process-handle.
- base::Process event(::CreateEvent(NULL, false, false, NULL));
+ base::Process event(::CreateEvent(nullptr, false, false, nullptr));
// A non-process handle should fail.
EXPECT_FALSE(watcher.Initialize(std::move(event)));
diff --git a/chromium/components/browser_watcher/stability_report.proto b/chromium/components/browser_watcher/stability_report.proto
index 5cb28b90b50..72656983433 100644
--- a/chromium/components/browser_watcher/stability_report.proto
+++ b/chromium/components/browser_watcher/stability_report.proto
@@ -189,6 +189,8 @@ message ProcessState {
optional uint32 process_peak_pagefile_usage = 3;
// The allocation request that caused OOM, bytes.
optional uint32 process_allocation_attempt = 4;
+ // The number of opened handles in the process.
+ optional uint32 process_handle_count = 5;
}
optional WindowsMemory windows_memory = 1;
@@ -231,6 +233,8 @@ message SystemMemoryState {
optional uint32 system_commit_limit = 1;
// The amount of system commit remaining. Unit is number of 4K pages.
optional uint32 system_commit_remaining = 2;
+ // The current number of open handles.
+ optional uint32 system_handle_count = 3;
}
optional WindowsMemory windows_memory = 1;
diff --git a/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc b/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc
index ea6b61a4797..bec019b55e5 100644
--- a/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc
+++ b/chromium/components/browser_watcher/stability_report_user_stream_data_source.cc
@@ -97,7 +97,7 @@ bool CollectStabilityReport(const base::FilePath& path,
return true;
}
-void CollectSystemMemoryMetrics(StabilityReport* report) {
+void CollectSystemPerformanceMetrics(StabilityReport* report) {
// Grab system commit memory. Also best effort.
PERFORMANCE_INFORMATION perf_info = {sizeof(perf_info)};
if (GetPerformanceInfo(&perf_info, sizeof(perf_info))) {
@@ -107,11 +107,13 @@ void CollectSystemMemoryMetrics(StabilityReport* report) {
memory_state->set_system_commit_limit(perf_info.CommitLimit);
memory_state->set_system_commit_remaining(perf_info.CommitLimit -
perf_info.CommitTotal);
+ memory_state->set_system_handle_count(perf_info.HandleCount);
}
}
-void CollectProcessMemoryMetrics(crashpad::ProcessSnapshot* process_snapshot,
- StabilityReport* report) {
+void CollectProcessPerformanceMetrics(
+ crashpad::ProcessSnapshot* process_snapshot,
+ StabilityReport* report) {
const crashpad::ExceptionSnapshot* exception = process_snapshot->Exception();
if (!exception)
@@ -151,7 +153,7 @@ void CollectProcessMemoryMetrics(crashpad::ProcessSnapshot* process_snapshot,
if (process.IsValid()) {
PROCESS_MEMORY_COUNTERS_EX process_memory = {sizeof(process_memory)};
- if (GetProcessMemoryInfo(
+ if (::GetProcessMemoryInfo(
process.Handle(),
reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&process_memory),
sizeof(process_memory))) {
@@ -165,6 +167,11 @@ void CollectProcessMemoryMetrics(crashpad::ProcessSnapshot* process_snapshot,
memory_state->set_process_peak_pagefile_usage(
process_memory.PeakPagefileUsage / kPageSize);
}
+
+ DWORD process_handle_count = 0;
+ if (::GetProcessHandleCount(process.Handle(), &process_handle_count)) {
+ memory_state->set_process_handle_count(process_handle_count);
+ }
}
}
@@ -194,8 +201,8 @@ StabilityReportUserStreamDataSource::ProduceStreamData(
}
}
- CollectSystemMemoryMetrics(&report);
- CollectProcessMemoryMetrics(process_snapshot, &report);
+ CollectSystemPerformanceMetrics(&report);
+ CollectProcessPerformanceMetrics(process_snapshot, &report);
std::unique_ptr<BufferExtensionStreamDataSource> source(
new BufferExtensionStreamDataSource(kStabilityReportStreamType));
diff --git a/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc b/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
index af78d5d816b..65ba549ab04 100644
--- a/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
+++ b/chromium/components/browser_watcher/watcher_metrics_provider_win_unittest.cc
@@ -84,7 +84,7 @@ TEST_F(WatcherMetricsProviderWinTest, RecordsStabilityHistogram) {
base::FilePath(),
GetExecutableDetailsCallback());
- provider.ProvideStabilityMetrics(NULL);
+ provider.ProvideStabilityMetrics(nullptr);
histogram_tester_.ExpectBucketCount(
WatcherMetricsProviderWin::kBrowserExitCodeHistogramName, 0, 11);
histogram_tester_.ExpectBucketCount(
@@ -108,7 +108,7 @@ TEST_F(WatcherMetricsProviderWinTest, DoesNotReportOwnProcessId) {
base::FilePath(),
GetExecutableDetailsCallback());
- provider.ProvideStabilityMetrics(NULL);
+ provider.ProvideStabilityMetrics(nullptr);
histogram_tester_.ExpectUniqueSample(
WatcherMetricsProviderWin::kBrowserExitCodeHistogramName, 0, 11);
diff --git a/chromium/components/browser_watcher/window_hang_monitor_win.cc b/chromium/components/browser_watcher/window_hang_monitor_win.cc
index 96cadb62ca3..ca89e6ab1fe 100644
--- a/chromium/components/browser_watcher/window_hang_monitor_win.cc
+++ b/chromium/components/browser_watcher/window_hang_monitor_win.cc
@@ -151,8 +151,8 @@ void WindowHangMonitor::OnHangTimeout(HWND hwnd) {
// The ping is still outstanding, the window is hung or has vanished.
// Orphan the outstanding ping. If the callback arrives late, it will
// delete it, or if the callback never arrives it'll leak.
- outstanding_ping_->monitor = NULL;
- outstanding_ping_ = NULL;
+ outstanding_ping_->monitor = nullptr;
+ outstanding_ping_ = nullptr;
if (hwnd != FindChromeMessageWindow(window_process_.Pid())) {
// The window vanished.
diff --git a/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc b/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc
index 9bdedec3462..0ccf8a7cb3f 100644
--- a/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc
+++ b/chromium/components/browser_watcher/window_hang_monitor_win_unittest.cc
@@ -11,6 +11,7 @@
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/path_service.h"
#include "base/process/launch.h"
#include "base/process/process.h"
@@ -174,7 +175,7 @@ class MonitoredProcessClient {
LPARAM lparam,
LRESULT* result) {
EXPECT_EQ(message_window_thread_.message_loop(),
- base::MessageLoop::current());
+ base::MessageLoopCurrent::Get());
return false; // Pass through to DefWindowProc.
}
@@ -186,13 +187,13 @@ class MonitoredProcessClient {
// user data directory, the hang watcher verifies that the window name is an
// existing directory. DIR_CURRENT is used to meet this constraint.
base::FilePath existing_dir;
- CHECK(PathService::Get(base::DIR_CURRENT, &existing_dir));
+ CHECK(base::PathService::Get(base::DIR_CURRENT, &existing_dir));
message_window_.reset(new base::win::MessageWindow);
*success = message_window_->CreateNamed(
base::Bind(&MonitoredProcessClient::EmptyMessageCallback,
base::Unretained(this)),
- existing_dir.value().c_str());
+ existing_dir.value());
created->Signal();
}
@@ -250,7 +251,7 @@ class HangMonitorThread {
thread_("Hang monitor thread") {}
~HangMonitorThread() {
- if (hang_monitor_.get())
+ if (hang_monitor_)
DestroyWatcher();
}
diff --git a/chromium/components/browsing_data/content/BUILD.gn b/chromium/components/browsing_data/content/BUILD.gn
index 63c1b92fc9b..179a40a63dc 100644
--- a/chromium/components/browsing_data/content/BUILD.gn
+++ b/chromium/components/browsing_data/content/BUILD.gn
@@ -6,8 +6,6 @@ static_library("content") {
sources = [
"conditional_cache_counting_helper.cc",
"conditional_cache_counting_helper.h",
- "counters/site_settings_counter.cc",
- "counters/site_settings_counter.h",
]
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
diff --git a/chromium/components/browsing_data/content/conditional_cache_counting_helper.cc b/chromium/components/browsing_data/content/conditional_cache_counting_helper.cc
index 3e00187184f..7d7d518d454 100644
--- a/chromium/components/browsing_data/content/conditional_cache_counting_helper.cc
+++ b/chromium/components/browsing_data/content/conditional_cache_counting_helper.cc
@@ -66,10 +66,6 @@ ConditionalCacheCountingHelper::CountAndDestroySelfWhenFinished(
return weak_ptr_factory_.GetWeakPtr();
}
-bool ConditionalCacheCountingHelper::IsFinished() {
- return is_finished_;
-}
-
void ConditionalCacheCountingHelper::Finished() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(!is_finished_);
@@ -82,8 +78,8 @@ void ConditionalCacheCountingHelper::CountHttpCacheOnIOThread() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
next_cache_state_ = CacheState::NONE;
DCHECK_EQ(CacheState::NONE, next_cache_state_);
- DCHECK(main_context_getter_.get());
- DCHECK(media_context_getter_.get());
+ DCHECK(main_context_getter_);
+ DCHECK(media_context_getter_);
next_cache_state_ = CacheState::CREATE_MAIN;
DoCountCache(net::OK);
diff --git a/chromium/components/browsing_data/content/conditional_cache_counting_helper.h b/chromium/components/browsing_data/content/conditional_cache_counting_helper.h
index 0bca3f36478..6c3742f1da8 100644
--- a/chromium/components/browsing_data/content/conditional_cache_counting_helper.h
+++ b/chromium/components/browsing_data/content/conditional_cache_counting_helper.h
@@ -42,8 +42,6 @@ class ConditionalCacheCountingHelper {
base::WeakPtr<ConditionalCacheCountingHelper> CountAndDestroySelfWhenFinished(
const CacheCountCallback& result_callback);
- bool IsFinished();
-
private:
enum class CacheState {
NONE,
diff --git a/chromium/components/browsing_data/content/counters/site_settings_counter.cc b/chromium/components/browsing_data/content/counters/site_settings_counter.cc
deleted file mode 100644
index 9d29c724ac9..00000000000
--- a/chromium/components/browsing_data/content/counters/site_settings_counter.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/browsing_data/content/counters/site_settings_counter.h"
-
-#include <set>
-#include "build/build_config.h"
-#include "components/browsing_data/core/pref_names.h"
-#include "components/content_settings/core/browser/content_settings_registry.h"
-#include "components/content_settings/core/common/content_settings_pattern.h"
-
-#if !defined(OS_ANDROID)
-#include "content/public/browser/host_zoom_map.h"
-#endif
-
-namespace browsing_data {
-
-SiteSettingsCounter::SiteSettingsCounter(HostContentSettingsMap* map,
- content::HostZoomMap* zoom_map)
- : map_(map), zoom_map_(zoom_map) {
- DCHECK(map_);
-#if !defined(OS_ANDROID)
- DCHECK(zoom_map_);
-#else
- DCHECK(!zoom_map_);
-#endif
-}
-
-SiteSettingsCounter::~SiteSettingsCounter() {}
-
-void SiteSettingsCounter::OnInitialized() {}
-
-const char* SiteSettingsCounter::GetPrefName() const {
- return browsing_data::prefs::kDeleteSiteSettings;
-}
-
-void SiteSettingsCounter::Count() {
- std::set<std::string> hosts;
- int empty_host_pattern = 0;
- base::Time period_start = GetPeriodStart();
- base::Time period_end = GetPeriodEnd();
- auto* registry = content_settings::ContentSettingsRegistry::GetInstance();
- for (const content_settings::ContentSettingsInfo* info : *registry) {
- ContentSettingsType type = info->website_settings_info()->type();
- ContentSettingsForOneType content_settings_list;
- map_->GetSettingsForOneType(type, content_settings::ResourceIdentifier(),
- &content_settings_list);
- for (const auto& content_setting : content_settings_list) {
- // TODO(crbug.com/762560): Check the conceptual SettingSource instead of
- // ContentSettingPatternSource.source
- if (content_setting.source == "preference" ||
- content_setting.source == "notification_android") {
- base::Time last_modified = map_->GetSettingLastModifiedDate(
- content_setting.primary_pattern, content_setting.secondary_pattern,
- type);
- if (last_modified >= period_start && last_modified < period_end) {
- if (content_setting.primary_pattern.GetHost().empty())
- empty_host_pattern++;
- else
- hosts.insert(content_setting.primary_pattern.GetHost());
- }
- }
- }
- }
-
-#if !defined(OS_ANDROID)
- for (const auto& zoom_level : zoom_map_->GetAllZoomLevels()) {
- // zoom_level with non-empty scheme are only used for some internal
- // features and not stored in preferences. They are not counted.
- if (zoom_level.last_modified >= period_start &&
- zoom_level.last_modified < period_end && zoom_level.scheme.empty()) {
- hosts.insert(zoom_level.host);
- }
- }
-#endif
-
- ReportResult(hosts.size() + empty_host_pattern);
-}
-
-} // namespace browsing_data
diff --git a/chromium/components/browsing_data/content/counters/site_settings_counter.h b/chromium/components/browsing_data/content/counters/site_settings_counter.h
deleted file mode 100644
index 602e8075cf5..00000000000
--- a/chromium/components/browsing_data/content/counters/site_settings_counter.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_BROWSING_DATA_CONTENT_COUNTERS_SITE_SETTINGS_COUNTER_H_
-#define COMPONENTS_BROWSING_DATA_CONTENT_COUNTERS_SITE_SETTINGS_COUNTER_H_
-
-#include "components/browsing_data/core/counters/browsing_data_counter.h"
-#include "components/content_settings/core/browser/host_content_settings_map.h"
-
-namespace content {
-class HostZoomMap;
-}
-
-namespace browsing_data {
-
-class SiteSettingsCounter : public browsing_data::BrowsingDataCounter {
- public:
- explicit SiteSettingsCounter(HostContentSettingsMap* map,
- content::HostZoomMap* zoom_map);
- ~SiteSettingsCounter() override;
-
- const char* GetPrefName() const override;
-
- private:
- void OnInitialized() override;
-
- void Count() override;
-
- scoped_refptr<HostContentSettingsMap> map_;
- content::HostZoomMap* zoom_map_;
-};
-
-} // namespace browsing_data
-
-#endif // COMPONENTS_BROWSING_DATA_CONTENT_COUNTERS_SITE_SETTINGS_COUNTER_H_
diff --git a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
index 30e049baf4f..099a97d2ee4 100644
--- a/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
+++ b/chromium/components/browsing_data/core/browsing_data_utils_unittest.cc
@@ -12,6 +12,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
#include "components/browsing_data/core/counters/autofill_counter.h"
+#include "components/browsing_data/core/counters/history_counter.h"
#include "components/browsing_data/core/counters/passwords_counter.h"
#include "components/browsing_data/core/pref_names.h"
#include "components/password_manager/core/browser/test_password_store.h"
@@ -19,6 +20,8 @@
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace browsing_data {
+
namespace {
class FakeWebDataService : public autofill::AutofillWebDataService {
@@ -51,7 +54,7 @@ class BrowsingDataUtilsTest : public testing::Test {
// Tests the complex output of the Autofill counter.
TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
- browsing_data::AutofillCounter counter(
+ AutofillCounter counter(
scoped_refptr<FakeWebDataService>(new FakeWebDataService()), nullptr);
// Test all configurations of zero and nonzero partial results for datatypes.
@@ -80,7 +83,7 @@ TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
};
for (const TestCase& test_case : kTestCases) {
- browsing_data::AutofillCounter::AutofillResult result(
+ AutofillCounter::AutofillResult result(
&counter, test_case.num_suggestions, test_case.num_credit_cards,
test_case.num_addresses, test_case.sync_enabled);
@@ -99,7 +102,7 @@ TEST_F(BrowsingDataUtilsTest, AutofillCounterResult) {
TEST_F(BrowsingDataUtilsTest, PasswordsCounterResult) {
scoped_refptr<password_manager::TestPasswordStore> store(
new password_manager::TestPasswordStore());
- browsing_data::PasswordsCounter counter(
+ PasswordsCounter counter(
scoped_refptr<password_manager::PasswordStore>(store), nullptr);
const struct TestCase {
@@ -113,8 +116,8 @@ TEST_F(BrowsingDataUtilsTest, PasswordsCounterResult) {
};
for (const TestCase& test_case : kTestCases) {
- browsing_data::BrowsingDataCounter::SyncResult result(
- &counter, test_case.num_passwords, test_case.is_synced);
+ BrowsingDataCounter::SyncResult result(&counter, test_case.num_passwords,
+ test_case.is_synced);
SCOPED_TRACE(base::StringPrintf("Test params: %d password(s), %d is_synced",
test_case.num_passwords,
test_case.is_synced));
@@ -123,3 +126,45 @@ TEST_F(BrowsingDataUtilsTest, PasswordsCounterResult) {
}
store->ShutdownOnUIThread();
}
+
+// Tests the output of the History counter.
+TEST_F(BrowsingDataUtilsTest, HistoryCounterResult) {
+ history::HistoryService history_service;
+ HistoryCounter counter(&history_service,
+ HistoryCounter::GetUpdatedWebHistoryServiceCallback(),
+ nullptr);
+ counter.Init(prefs(), ClearBrowsingDataTab::ADVANCED, base::DoNothing());
+
+ const struct TestCase {
+ int num_history;
+ int is_sync_enabled;
+ int has_sync_visits;
+ std::string expected_output;
+ } kTestCases[] = {
+ // No sync, no synced visits:
+ {0, false, false, "None"},
+ {1, false, false, "1 item"},
+ {5, false, false, "5 items"},
+ // Sync but not synced visits:
+ {0, true, false, "None"},
+ {1, true, false, "1 item"},
+ {5, true, false, "5 items"},
+ // Sync and synced visits:
+ {0, true, true, "At least 1 item on synced devices"},
+ {1, true, true, "1 item (and more on synced devices)"},
+ {5, true, true, "5 items (and more on synced devices)"},
+ };
+
+ for (const TestCase& test_case : kTestCases) {
+ HistoryCounter::HistoryResult result(&counter, test_case.num_history,
+ test_case.is_sync_enabled,
+ test_case.has_sync_visits);
+ SCOPED_TRACE(
+ base::StringPrintf("Test params: %d history, %d has_synced_visits",
+ test_case.num_history, test_case.has_sync_visits));
+ base::string16 output = browsing_data::GetCounterTextFromResult(&result);
+ EXPECT_EQ(output, base::ASCIIToUTF16(test_case.expected_output));
+ }
+}
+
+} // namespace browsing_data \ No newline at end of file
diff --git a/chromium/components/browsing_data/core/counters/browsing_data_counter.h b/chromium/components/browsing_data/core/counters/browsing_data_counter.h
index bc52224a951..3c606bb7a36 100644
--- a/chromium/components/browsing_data/core/counters/browsing_data_counter.h
+++ b/chromium/components/browsing_data/core/counters/browsing_data_counter.h
@@ -77,7 +77,7 @@ class BrowsingDataCounter {
DISALLOW_COPY_AND_ASSIGN(SyncResult);
};
- typedef base::Callback<void(std::unique_ptr<Result>)> Callback;
+ typedef base::RepeatingCallback<void(std::unique_ptr<Result>)> Callback;
// Every calculation progresses through a state machine. At initialization,
// the counter is IDLE. If a result is calculated within a given time
diff --git a/chromium/components/browsing_data/core/features.cc b/chromium/components/browsing_data/core/features.cc
index 01224261391..054b27e751a 100644
--- a/chromium/components/browsing_data/core/features.cc
+++ b/chromium/components/browsing_data/core/features.cc
@@ -8,7 +8,7 @@ namespace browsing_data {
namespace features {
const base::Feature kRemoveNavigationHistory{"RemoveNavigationHistory",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
} // namespace features
} // namespace browsing_data
diff --git a/chromium/components/browsing_data/core/history_notice_utils.cc b/chromium/components/browsing_data/core/history_notice_utils.cc
index feec09b98d3..9e7de1c7dab 100644
--- a/chromium/components/browsing_data/core/history_notice_utils.cc
+++ b/chromium/components/browsing_data/core/history_notice_utils.cc
@@ -53,12 +53,6 @@ class MergeBooleanCallbacks {
namespace browsing_data {
-namespace testing {
-
-bool g_override_other_forms_of_browsing_history_query = false;
-
-} // namespace testing
-
void ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
const syncer::SyncService* sync_service,
history::WebHistoryService* history_service,
@@ -106,14 +100,6 @@ void ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
history::WebHistoryService* history_service,
version_info::Channel channel,
base::Callback<void(bool)> callback) {
- // If the query for other forms of browsing history is overriden for testing,
- // the conditions are identical with
- // ShouldShowNoticeAboutOtherFormsOfBrowsingHistory.
- if (testing::g_override_other_forms_of_browsing_history_query) {
- ShouldShowNoticeAboutOtherFormsOfBrowsingHistory(
- sync_service, history_service, callback);
- return;
- }
if (!sync_service ||
!sync_service->IsSyncActive() ||
diff --git a/chromium/components/browsing_data/core/history_notice_utils.h b/chromium/components/browsing_data/core/history_notice_utils.h
index 5f454c95939..15a57699c35 100644
--- a/chromium/components/browsing_data/core/history_notice_utils.h
+++ b/chromium/components/browsing_data/core/history_notice_utils.h
@@ -23,16 +23,6 @@ enum class Channel;
namespace browsing_data {
-namespace testing {
-
-// TODO(crbug.com/595332): A boolean flag indicating that
-// ShouldShowNoticeAboutOtherFormsOfBrowsingHistory() should skip the query
-// for other forms of browsing history and just assume some such forms were
-// found. Used only for testing. The default is false.
-extern bool g_override_other_forms_of_browsing_history_query;
-
-} // testing
-
// Whether the Clear Browsing Data UI should show a notice about the existence
// of other forms of browsing history stored in user's account. The response
// is returned in a |callback|.
diff --git a/chromium/components/browsing_data/core/history_notice_utils_unittest.cc b/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
index 0126a676b6e..8da708cb4bb 100644
--- a/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
+++ b/chromium/components/browsing_data/core/history_notice_utils_unittest.cc
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
#include "components/history/core/test/fake_web_history_service.h"
#include "components/sync/base/model_type.h"
#include "components/sync/driver/fake_sync_service.h"
@@ -26,8 +27,6 @@ class TestSyncService : public syncer::FakeSyncService {
// Getters (FakeSyncService implementation). ---------------------------------
bool IsSyncActive() const override { return sync_active_; }
- bool IsLocalSyncEnabled() const override { return false; }
-
syncer::ModelTypeSet GetActiveDataTypes() const override {
return active_data_types_;
}
@@ -79,45 +78,28 @@ class HistoryNoticeUtilsTest : public ::testing::Test {
void ExpectShouldPopupDialogAboutOtherFormsOfBrowsingHistoryWithResult(
bool expected_test_case_result) {
- bool got_result = false;
-
+ bool result;
+ base::RunLoop run_loop;
ShouldPopupDialogAboutOtherFormsOfBrowsingHistory(
- sync_service_.get(),
- history_service_.get(),
- version_info::Channel::STABLE,
- base::Bind(
- &HistoryNoticeUtilsTest::Callback,
- base::Unretained(this),
- base::Unretained(&got_result)));
-
- if (!got_result) {
- run_loop_.reset(new base::RunLoop());
- run_loop_->Run();
- }
+ sync_service_.get(), history_service_.get(),
+ version_info::Channel::STABLE, base::BindLambdaForTesting([&](bool r) {
+ result = r;
+ run_loop.Quit();
+ }));
+ run_loop.Run();
// Process the DeleteSoon() called on MergeBooleanCallbacks, otherwise
// this it will be considered to be leaked.
base::RunLoop().RunUntilIdle();
- EXPECT_EQ(expected_test_case_result, result_);
+ EXPECT_EQ(expected_test_case_result, result);
}
private:
- void Callback(bool* got_result, bool result) {
- *got_result = true;
- result_ = result;
-
- if (run_loop_)
- run_loop_->Quit();
- }
-
scoped_refptr<net::URLRequestContextGetter> url_request_context_;
std::unique_ptr<TestSyncService> sync_service_;
std::unique_ptr<history::FakeWebHistoryService> history_service_;
- std::unique_ptr<base::RunLoop> run_loop_;
- bool result_;
-
base::MessageLoop message_loop_;
};
diff --git a/chromium/components/browsing_data_strings.grdp b/chromium/components/browsing_data_strings.grdp
index ec6eeeb6775..50b08d15115 100644
--- a/chromium/components/browsing_data_strings.grdp
+++ b/chromium/components/browsing_data_strings.grdp
@@ -101,6 +101,12 @@
=1 {From 1 site }
other {From # sites }}
</message>
+ <message name="IDS_DEL_COOKIES_COUNTER_ADVANCED_WITH_EXCEPTION" desc="A counter showing the number of sites that use cookies, followed by an exception message.">
+ {COUNT, plural,
+ =0 {None}
+ =1 {From 1 site (you won't be signed out of your Google Account)}
+ other {From # sites (you won't be signed out of your Google Account)}}
+ </message>
<message name="IDS_DEL_DOWNLOADS_COUNTER" desc="A counter showing how many items of downloads history the user has.">
{COUNT, plural,
=0 {None}
diff --git a/chromium/components/browsing_data_strings_grdp/OWNERS b/chromium/components/browsing_data_strings_grdp/OWNERS
new file mode 100644
index 00000000000..93c725018e9
--- /dev/null
+++ b/chromium/components/browsing_data_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/browsing_data/OWNERS
diff --git a/chromium/components/browsing_data_strings_grdp/README.md b/chromium/components/browsing_data_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/browsing_data_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/captive_portal/captive_portal_detector.cc b/chromium/components/captive_portal/captive_portal_detector.cc
index b9397c09453..90a39046e20 100644
--- a/chromium/components/captive_portal/captive_portal_detector.cc
+++ b/chromium/components/captive_portal/captive_portal_detector.cc
@@ -159,7 +159,7 @@ base::Time CaptivePortalDetector::GetCurrentTime() const {
}
bool CaptivePortalDetector::FetchingURL() const {
- return simple_loader_.get() != nullptr;
+ return simple_loader_ != nullptr;
}
} // namespace captive_portal
diff --git a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
index 4a41ed2b0d3..8fbc748d652 100644
--- a/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
+++ b/chromium/components/cast_certificate/cast_cert_validator_test_helpers.cc
@@ -17,7 +17,7 @@ namespace testing {
std::string ReadTestFileToString(const base::StringPiece& file_name) {
base::FilePath filepath;
- PathService::Get(base::DIR_SOURCE_ROOT, &filepath);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &filepath);
filepath = filepath.Append(FILE_PATH_LITERAL("components"));
filepath = filepath.Append(FILE_PATH_LITERAL("test"));
filepath = filepath.Append(FILE_PATH_LITERAL("data"));
diff --git a/chromium/components/cast_channel/BUILD.gn b/chromium/components/cast_channel/BUILD.gn
index a73ef8f0047..02a353d391d 100644
--- a/chromium/components/cast_channel/BUILD.gn
+++ b/chromium/components/cast_channel/BUILD.gn
@@ -65,6 +65,7 @@ source_set("unit_tests") {
"cast_auth_util_unittest.cc",
"cast_framer_unittest.cc",
"cast_message_handler_unittest.cc",
+ "cast_message_util_unittest.cc",
"cast_socket_service_unittest.cc",
"cast_socket_unittest.cc",
"cast_transport_unittest.cc",
diff --git a/chromium/components/cast_channel/cast_auth_util_unittest.cc b/chromium/components/cast_channel/cast_auth_util_unittest.cc
index d1493f25ccf..5a9df906f5c 100644
--- a/chromium/components/cast_channel/cast_auth_util_unittest.cc
+++ b/chromium/components/cast_channel/cast_auth_util_unittest.cc
@@ -174,7 +174,7 @@ TEST_F(CastAuthUtilTest, VerifySenderNonceMissing) {
scoped_feature_list.InitAndEnableFeature(
base::Feature{"CastNonceEnforced", base::FEATURE_DISABLED_BY_DEFAULT});
AuthContext context = AuthContext::Create();
- std::string received_nonce = "";
+ std::string received_nonce;
EXPECT_FALSE(context.nonce().empty());
AuthResult result = context.VerifySenderNonce(received_nonce);
EXPECT_FALSE(result.success());
diff --git a/chromium/components/cast_channel/cast_message_handler.cc b/chromium/components/cast_channel/cast_message_handler.cc
index b12c1b49ae9..11e6042d427 100644
--- a/chromium/components/cast_channel/cast_message_handler.cc
+++ b/chromium/components/cast_channel/cast_message_handler.cc
@@ -16,6 +16,8 @@ namespace cast_channel {
namespace {
+constexpr base::TimeDelta kRequestTimeout = base::TimeDelta::FromSeconds(5);
+
constexpr net::NetworkTrafficAnnotationTag kMessageTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("cast_message_handler", R"(
semantics {
@@ -51,14 +53,11 @@ constexpr net::NetworkTrafficAnnotationTag kMessageTrafficAnnotation =
} // namespace
GetAppAvailabilityRequest::GetAppAvailabilityRequest(
- int channel_id,
- const std::string& app_id,
+ int request_id,
GetAppAvailabilityCallback callback,
- const base::TickClock* clock)
- : channel_id(channel_id),
- app_id(app_id),
- callback(std::move(callback)),
- timeout_timer(clock) {}
+ const base::TickClock* clock,
+ const std::string& app_id)
+ : PendingRequest(request_id, std::move(callback), clock), app_id(app_id) {}
GetAppAvailabilityRequest::~GetAppAvailabilityRequest() = default;
@@ -75,12 +74,18 @@ bool VirtualConnection::operator<(const VirtualConnection& other) const {
std::tie(other.channel_id, other.source_id, other.destination_id);
}
+InternalMessage::InternalMessage(CastMessageType type, base::Value message)
+ : type(type), message(std::move(message)) {}
+InternalMessage::~InternalMessage() = default;
+
CastMessageHandler::CastMessageHandler(CastSocketService* socket_service,
const std::string& user_agent,
- const std::string& browser_version)
+ const std::string& browser_version,
+ const std::string& locale)
: sender_id_(base::StringPrintf("sender-%d", base::RandInt(0, 1000000))),
user_agent_(user_agent),
browser_version_(browser_version),
+ locale_(locale),
socket_service_(socket_service),
clock_(base::DefaultTickClock::GetInstance()),
weak_ptr_factory_(this) {
@@ -96,6 +101,33 @@ CastMessageHandler::~CastMessageHandler() {
socket_service_->RemoveObserver(this);
}
+void CastMessageHandler::EnsureConnection(int channel_id,
+ const std::string& source_id,
+ const std::string& destination_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ CastSocket* socket = socket_service_->GetSocket(channel_id);
+ if (!socket) {
+ DVLOG(2) << __func__ << ": socket not found: " << channel_id;
+ return;
+ }
+
+ DoEnsureConnection(socket, source_id, destination_id);
+}
+
+CastMessageHandler::PendingRequests*
+CastMessageHandler::GetOrCreatePendingRequests(int channel_id) {
+ CastMessageHandler::PendingRequests* requests = nullptr;
+ auto pending_it = pending_requests_.find(channel_id);
+ if (pending_it != pending_requests_.end()) {
+ return pending_it->second.get();
+ }
+
+ auto new_requests = std::make_unique<CastMessageHandler::PendingRequests>();
+ requests = new_requests.get();
+ pending_requests_.emplace(channel_id, std::move(new_requests));
+ return requests;
+}
+
void CastMessageHandler::RequestAppAvailability(
CastSocket* socket,
const std::string& app_id,
@@ -103,122 +135,152 @@ void CastMessageHandler::RequestAppAvailability(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
int channel_id = socket->id();
- auto pending_it = std::find_if(
- pending_app_availability_requests_.begin(),
- pending_app_availability_requests_.end(),
- [&channel_id, &app_id](
- const std::pair<int, std::unique_ptr<GetAppAvailabilityRequest>>&
- entry) {
- const auto& request = entry.second;
- return request->channel_id == channel_id && app_id == request->app_id;
- });
- if (pending_it != pending_app_availability_requests_.end())
+ auto* requests = GetOrCreatePendingRequests(channel_id);
+ int request_id = NextRequestId();
+
+ DVLOG(2) << __func__ << ", channel_id: " << channel_id
+ << ", app_id: " << app_id << ", request_id: " << request_id;
+ if (requests->AddAppAvailabilityRequest(
+ std::make_unique<GetAppAvailabilityRequest>(
+ request_id, std::move(callback), clock_, app_id))) {
+ SendCastMessage(socket, CreateGetAppAvailabilityRequest(
+ sender_id_, request_id, app_id));
+ }
+}
+
+void CastMessageHandler::SendBroadcastMessage(
+ int channel_id,
+ const std::vector<std::string>& app_ids,
+ const BroadcastRequest& request) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ CastSocket* socket = socket_service_->GetSocket(channel_id);
+ if (!socket) {
+ DVLOG(2) << __func__ << ": socket not found: " << channel_id;
return;
+ }
int request_id = NextRequestId();
+ DVLOG(2) << __func__ << ", channel_id: " << channel_id
+ << ", request_id: " << request_id;
- DVLOG(2) << __func__ << ", socket_id: " << socket->id()
- << ", app_id: " << app_id << ", request_id: " << request_id;
+ // Note: Even though the message is formatted like a request, we don't care
+ // about the response, as broadcasts are fire-and-forget.
CastMessage message =
- CreateGetAppAvailabilityRequest(sender_id_, request_id, app_id);
+ CreateBroadcastRequest(sender_id_, request_id, app_ids, request);
+ SendCastMessage(socket, message);
+}
- auto request = std::make_unique<GetAppAvailabilityRequest>(
- channel_id, app_id, std::move(callback), clock_);
- request->timeout_timer.Start(
- FROM_HERE, base::TimeDelta::FromSeconds(5),
- base::Bind(&CastMessageHandler::AppAvailabilityTimedOut,
- base::Unretained(this), request_id));
- pending_app_availability_requests_.emplace(request_id, std::move(request));
+void CastMessageHandler::LaunchSession(int channel_id,
+ const std::string& app_id,
+ base::TimeDelta launch_timeout,
+ LaunchSessionCallback callback) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ CastSocket* socket = socket_service_->GetSocket(channel_id);
+ if (!socket) {
+ DVLOG(2) << __func__ << ": socket not found: " << channel_id;
+ std::move(callback).Run(LaunchSessionResponse());
+ return;
+ }
- SendCastMessage(socket, message);
+ auto* requests = GetOrCreatePendingRequests(channel_id);
+ int request_id = NextRequestId();
+ DVLOG(2) << __func__ << ", channel_id: " << channel_id
+ << ", request_id: " << request_id;
+
+ if (requests->AddLaunchRequest(std::make_unique<LaunchSessionRequest>(
+ request_id, std::move(callback), clock_),
+ launch_timeout)) {
+ SendCastMessage(
+ socket, CreateLaunchRequest(sender_id_, request_id, app_id, locale_));
+ }
}
-void CastMessageHandler::AppAvailabilityTimedOut(int request_id) {
+void CastMessageHandler::SendAppMessage(int channel_id,
+ const CastMessage& message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DVLOG(1) << __func__ << ", request_id: " << request_id;
- auto it = pending_app_availability_requests_.find(request_id);
- if (it == pending_app_availability_requests_.end())
+ DCHECK(!IsCastInternalNamespace(message.namespace_()))
+ << ": unexpected app message namespace: " << message.namespace_();
+
+ CastSocket* socket = socket_service_->GetSocket(channel_id);
+ if (!socket) {
+ DVLOG(2) << __func__ << ": socket not found: " << channel_id;
return;
+ }
- std::move(it->second->callback)
- .Run(it->second->app_id, GetAppAvailabilityResult::kUnknown);
- pending_app_availability_requests_.erase(it);
+ SendCastMessage(socket, message);
+}
+
+void CastMessageHandler::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void CastMessageHandler::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
}
void CastMessageHandler::OnError(const CastSocket& socket,
ChannelError error_state) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ int channel_id = socket.id();
base::EraseIf(virtual_connections_,
- [&socket](const VirtualConnection& connection) {
- return connection.channel_id == socket.id();
+ [&channel_id](const VirtualConnection& connection) {
+ return connection.channel_id == channel_id;
});
- auto it = pending_app_availability_requests_.begin();
- while (it != pending_app_availability_requests_.end()) {
- if (it->second->channel_id == socket.id()) {
- std::move(it->second->callback)
- .Run(it->second->app_id, GetAppAvailabilityResult::kUnknown);
- it = pending_app_availability_requests_.erase(it);
- } else {
- ++it;
- }
- }
+ pending_requests_.erase(channel_id);
}
void CastMessageHandler::OnMessage(const CastSocket& socket,
const CastMessage& message) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // TODO(crbug.com/698940): Handle other messages.
- DVLOG(2) << __func__ << ", socket_id: " << socket.id()
+ DVLOG(2) << __func__ << ", channel_id: " << socket.id()
<< ", message: " << CastMessageToString(message);
- if (!IsReceiverMessage(message) || message.destination_id() != sender_id_)
- return;
+ // TODO(crbug.com/698940): Support Observers for both kinds of messages.
+ if (IsCastInternalNamespace(message.namespace_())) {
+ HandleCastInternalMessage(socket, message);
+ } else {
+ DVLOG(2) << "Got app message from cast channel with namespace: "
+ << message.namespace_();
+
+ for (auto& observer : observers_)
+ observer.OnAppMessage(socket.id(), message);
+ }
+}
+
+void CastMessageHandler::HandleCastInternalMessage(const CastSocket& socket,
+ const CastMessage& message) {
+ // TODO(crbug.com/698940): Handle other messages (VIRTUAL_CONNECT_CLOSE).
std::unique_ptr<base::DictionaryValue> payload =
GetDictionaryFromCastMessage(message);
if (!payload)
return;
int request_id = 0;
- if (!GetRequestIdFromResponse(*payload, &request_id))
- return;
+ if (GetRequestIdFromResponse(*payload, &request_id) && request_id > 0) {
+ auto requests_it = pending_requests_.find(socket.id());
+ if (requests_it != pending_requests_.end())
+ requests_it->second->HandlePendingRequest(request_id, *payload);
+ }
- auto it = pending_app_availability_requests_.find(request_id);
- if (it != pending_app_availability_requests_.end()) {
- GetAppAvailabilityResult result =
- GetAppAvailabilityResultFromResponse(*payload, it->second->app_id);
- std::move(it->second->callback).Run(it->second->app_id, result);
- pending_app_availability_requests_.erase(it);
+ CastMessageType type = ParseMessageTypeFromPayload(*payload);
+ if (type == CastMessageType::kOther) {
+ DVLOG(2) << "Unknown message type: " << CastMessageToString(message);
+ return;
}
+
+ InternalMessage internal_message(type, std::move(*payload));
+ for (auto& observer : observers_)
+ observer.OnInternalMessage(socket.id(), internal_message);
}
void CastMessageHandler::SendCastMessage(CastSocket* socket,
const CastMessage& message) {
// A virtual connection must be opened to the receiver before other messages
// can be sent.
- VirtualConnection connection(socket->id(), message.source_id(),
- message.destination_id());
- if (virtual_connections_.find(connection) == virtual_connections_.end()) {
- DVLOG(1) << "Creating VC for channel: " << connection.channel_id
- << ", source: " << connection.source_id
- << ", dest: " << connection.destination_id;
- CastMessage virtual_connection_request = CreateVirtualConnectionRequest(
- connection.source_id, connection.destination_id,
- connection.destination_id == kPlatformReceiverId
- ? VirtualConnectionType::kStrong
- : VirtualConnectionType::kInvisible,
- user_agent_, browser_version_);
- socket->transport()->SendMessage(
- virtual_connection_request,
- base::Bind(&CastMessageHandler::OnMessageSent,
- weak_ptr_factory_.GetWeakPtr()),
- kMessageTrafficAnnotation);
-
- // We assume the virtual connection request will succeed; otherwise this
- // will eventually self-correct.
- virtual_connections_.insert(connection);
- }
+ DoEnsureConnection(socket, message.source_id(), message.destination_id());
socket->transport()->SendMessage(
message,
base::Bind(&CastMessageHandler::OnMessageSent,
@@ -226,9 +288,136 @@ void CastMessageHandler::SendCastMessage(CastSocket* socket,
kMessageTrafficAnnotation);
}
+void CastMessageHandler::DoEnsureConnection(CastSocket* socket,
+ const std::string& source_id,
+ const std::string& destination_id) {
+ VirtualConnection connection(socket->id(), source_id, destination_id);
+ if (virtual_connections_.find(connection) != virtual_connections_.end())
+ return;
+
+ DVLOG(1) << "Creating VC for channel: " << connection.channel_id
+ << ", source: " << connection.source_id
+ << ", dest: " << connection.destination_id;
+ CastMessage virtual_connection_request = CreateVirtualConnectionRequest(
+ connection.source_id, connection.destination_id,
+ connection.destination_id == kPlatformReceiverId
+ ? VirtualConnectionType::kStrong
+ : VirtualConnectionType::kInvisible,
+ user_agent_, browser_version_);
+ socket->transport()->SendMessage(
+ virtual_connection_request,
+ base::Bind(&CastMessageHandler::OnMessageSent,
+ weak_ptr_factory_.GetWeakPtr()),
+ kMessageTrafficAnnotation);
+
+ // We assume the virtual connection request will succeed; otherwise this
+ // will eventually self-correct.
+ virtual_connections_.insert(connection);
+}
+
void CastMessageHandler::OnMessageSent(int result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG_IF(2, result < 0) << "SendMessage failed with code: " << result;
}
+CastMessageHandler::PendingRequests::PendingRequests() {}
+CastMessageHandler::PendingRequests::~PendingRequests() {
+ for (auto& request : pending_app_availability_requests) {
+ std::move(request.second->callback)
+ .Run(request.second->app_id, GetAppAvailabilityResult::kUnknown);
+ }
+
+ if (pending_launch_session_request) {
+ LaunchSessionResponse response;
+ response.result = LaunchSessionResponse::kError;
+ std::move(pending_launch_session_request->callback)
+ .Run(std::move(response));
+ }
+}
+
+bool CastMessageHandler::PendingRequests::AddAppAvailabilityRequest(
+ std::unique_ptr<GetAppAvailabilityRequest> request) {
+ std::string app_id = request->app_id;
+ if (base::ContainsKey(pending_app_availability_requests, request->app_id))
+ return false;
+
+ int request_id = request->request_id;
+ request->timeout_timer.Start(
+ FROM_HERE, kRequestTimeout,
+ base::Bind(&CastMessageHandler::PendingRequests::AppAvailabilityTimedOut,
+ base::Unretained(this), request_id));
+ pending_app_availability_requests.emplace(app_id, std::move(request));
+ return true;
+}
+
+bool CastMessageHandler::PendingRequests::AddLaunchRequest(
+ std::unique_ptr<LaunchSessionRequest> request,
+ base::TimeDelta timeout) {
+ if (pending_launch_session_request)
+ return false;
+
+ int request_id = request->request_id;
+ request->timeout_timer.Start(
+ FROM_HERE, timeout,
+ base::Bind(&CastMessageHandler::PendingRequests::LaunchSessionTimedOut,
+ base::Unretained(this), request_id));
+ pending_launch_session_request = std::move(request);
+ return true;
+}
+
+void CastMessageHandler::PendingRequests::HandlePendingRequest(
+ int request_id,
+ const base::DictionaryValue& response) {
+ auto app_availability_it =
+ std::find_if(pending_app_availability_requests.begin(),
+ pending_app_availability_requests.end(),
+ [&request_id](const auto& entry) {
+ return entry.second->request_id == request_id;
+ });
+ if (app_availability_it != pending_app_availability_requests.end()) {
+ GetAppAvailabilityResult result = GetAppAvailabilityResultFromResponse(
+ response, app_availability_it->second->app_id);
+ std::move(app_availability_it->second->callback)
+ .Run(app_availability_it->second->app_id, result);
+ pending_app_availability_requests.erase(app_availability_it);
+ return;
+ }
+
+ if (pending_launch_session_request &&
+ pending_launch_session_request->request_id == request_id) {
+ std::move(pending_launch_session_request->callback)
+ .Run(GetLaunchSessionResponse(response));
+ pending_launch_session_request.reset();
+ return;
+ }
+}
+
+void CastMessageHandler::PendingRequests::AppAvailabilityTimedOut(
+ int request_id) {
+ DVLOG(1) << __func__ << ", request_id: " << request_id;
+
+ auto it = std::find_if(pending_app_availability_requests.begin(),
+ pending_app_availability_requests.end(),
+ [&request_id](const auto& entry) {
+ return entry.second->request_id == request_id;
+ });
+
+ CHECK(it != pending_app_availability_requests.end());
+ std::move(it->second->callback)
+ .Run(it->second->app_id, GetAppAvailabilityResult::kUnknown);
+ pending_app_availability_requests.erase(it);
+}
+
+void CastMessageHandler::PendingRequests::LaunchSessionTimedOut(
+ int request_id) {
+ DVLOG(1) << __func__ << ", request_id: " << request_id;
+ CHECK(pending_launch_session_request);
+ CHECK(pending_launch_session_request->request_id == request_id);
+
+ LaunchSessionResponse response;
+ response.result = LaunchSessionResponse::kTimedOut;
+ std::move(pending_launch_session_request->callback).Run(std::move(response));
+ pending_launch_session_request.reset();
+}
+
} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_message_handler.h b/chromium/components/cast_channel/cast_message_handler.h
index ad775ed7bfc..4a1d53747db 100644
--- a/chromium/components/cast_channel/cast_message_handler.h
+++ b/chromium/components/cast_channel/cast_message_handler.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_CAST_CHANNEL_CAST_MESSAGE_HANDLER_H_
#define COMPONENTS_CAST_CHANNEL_CAST_MESSAGE_HANDLER_H_
+#include "base/callback_list.h"
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
@@ -20,6 +21,23 @@ namespace cast_channel {
class CastSocketService;
+template <typename CallbackType>
+struct PendingRequest {
+ public:
+ PendingRequest(int request_id,
+ CallbackType callback,
+ const base::TickClock* clock)
+ : request_id(request_id),
+ callback(std::move(callback)),
+ timeout_timer(clock) {}
+
+ virtual ~PendingRequest() = default;
+
+ int request_id;
+ CallbackType callback;
+ base::OneShotTimer timeout_timer;
+};
+
// |app_id|: ID of app the result is for.
// |result|: Availability result from the receiver.
using GetAppAvailabilityCallback =
@@ -27,26 +45,24 @@ using GetAppAvailabilityCallback =
GetAppAvailabilityResult result)>;
// Represents an app availability request to a Cast sink.
-struct GetAppAvailabilityRequest {
- GetAppAvailabilityRequest(int channel_id,
- const std::string& app_id,
+struct GetAppAvailabilityRequest
+ : public PendingRequest<GetAppAvailabilityCallback> {
+ public:
+ GetAppAvailabilityRequest(int request_id,
GetAppAvailabilityCallback callback,
- const base::TickClock* clock);
- ~GetAppAvailabilityRequest();
-
- // ID of channel the request is sent over.
- int channel_id;
+ const base::TickClock* clock,
+ const std::string& app_id);
+ ~GetAppAvailabilityRequest() override;
// App ID of the request.
std::string app_id;
-
- // Callback to invoke when availability has been determined.
- GetAppAvailabilityCallback callback;
-
- // Timer to fail the request on timeout.
- base::OneShotTimer timeout_timer;
};
+// Represents an app launch request to a Cast sink.
+using LaunchSessionCallback =
+ base::OnceCallback<void(LaunchSessionResponse response)>;
+using LaunchSessionRequest = PendingRequest<LaunchSessionCallback>;
+
// Represents a virtual connection on a cast channel. A virtual connection is
// given by a source and destination ID pair, and must be created before
// messages can be sent. Virtual connections are managed by CastMessageHandler.
@@ -68,21 +84,45 @@ struct VirtualConnection {
std::string destination_id;
};
+struct InternalMessage {
+ InternalMessage(CastMessageType type, base::Value message);
+ ~InternalMessage();
+
+ CastMessageType type;
+ base::Value message;
+};
+
// Handles messages that are sent between this browser instance and the Cast
// devices connected to it. This class also manages virtual connections (VCs)
// with each connected Cast device and ensures a proper VC exists before the
// message is sent. This makes the concept of VC transparent to the client.
-// This class currently provides only supports requesting app availability from
-// a device, but will be expanded to support additional types of messages.
// This class may be created on any sequence, but other methods (including
// destructor) must be run on the same sequence that CastSocketService runs on.
class CastMessageHandler : public CastSocket::Observer {
public:
+ class Observer {
+ public:
+ virtual ~Observer() = default;
+ virtual void OnAppMessage(int channel_id, const CastMessage& message) = 0;
+ virtual void OnInternalMessage(int channel_id,
+ const InternalMessage& message) = 0;
+ };
+
explicit CastMessageHandler(CastSocketService* socket_service,
const std::string& user_agent,
- const std::string& browser_version);
+ const std::string& browser_version,
+ const std::string& locale);
~CastMessageHandler() override;
+ // Ensures a virtual connection exists for (|source_id|, |destination_id|) on
+ // the device given by |channel_id|, sending a virtual connection request to
+ // the device if necessary. Although a virtual connection is automatically
+ // created when sending a message, a caller may decide to create it beforehand
+ // in order to receive messages sooner.
+ void EnsureConnection(int channel_id,
+ const std::string& source_id,
+ const std::string& destination_id);
+
// Sends an app availability for |app_id| to the device given by |socket|.
// |callback| is always invoked asynchronously, and will be invoked when a
// response is received, or if the request timed out. No-ops if there is
@@ -91,17 +131,66 @@ class CastMessageHandler : public CastSocket::Observer {
const std::string& app_id,
GetAppAvailabilityCallback callback);
+ // Sends a broadcast message containing |app_ids| and |request| to the socket
+ // given by |channel_id|.
+ virtual void SendBroadcastMessage(int channel_id,
+ const std::vector<std::string>& app_ids,
+ const BroadcastRequest& request);
+
+ // Requests a session launch for |app_id| on the device given by |channel_id|.
+ // |callback| will be invoked with the response or with a timed out result if
+ // no response comes back before |launch_timeout|.
+ void LaunchSession(int channel_id,
+ const std::string& app_id,
+ base::TimeDelta launch_timeout,
+ LaunchSessionCallback callback);
+
+ // Sends |message| to the device given by |channel_id|. The caller may use
+ // this method to forward app messages from the SDK client to the device. It
+ // is invalid to call this method with a message in one of the Cast internal
+ // message namespaces.
+ void SendAppMessage(int channel_id, const CastMessage& message);
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
const std::string& sender_id() const { return sender_id_; }
private:
friend class CastMessageHandlerTest;
- FRIEND_TEST_ALL_PREFIXES(CastMessageHandlerTest, RequestAppAvailability);
- FRIEND_TEST_ALL_PREFIXES(CastMessageHandlerTest,
- RecreateVirtualConnectionAfterError);
+
+ // Set of PendingRequests for a CastSocket.
+ class PendingRequests {
+ public:
+ PendingRequests();
+ ~PendingRequests();
+
+ bool AddAppAvailabilityRequest(
+ std::unique_ptr<GetAppAvailabilityRequest> request);
+ bool AddLaunchRequest(std::unique_ptr<LaunchSessionRequest> request,
+ base::TimeDelta timeout);
+
+ void HandlePendingRequest(int request_id,
+ const base::DictionaryValue& response);
+
+ private:
+ // Invokes the pending callback associated with |request_id| with a timed
+ // out result.
+ void AppAvailabilityTimedOut(int request_id);
+ void LaunchSessionTimedOut(int request_id);
+
+ // App availability requests pending responses, keyed by app ID.
+ base::flat_map<std::string, std::unique_ptr<GetAppAvailabilityRequest>>
+ pending_app_availability_requests;
+
+ std::unique_ptr<LaunchSessionRequest> pending_launch_session_request;
+ };
// Used internally to generate the next ID to use in a request type message.
int NextRequestId() { return ++next_request_id_; }
+ PendingRequests* GetOrCreatePendingRequests(int channel_id);
+
// CastSocket::Observer implementation.
void OnError(const CastSocket& socket, ChannelError error_state) override;
void OnMessage(const CastSocket& socket, const CastMessage& message) override;
@@ -110,15 +199,20 @@ class CastMessageHandler : public CastSocket::Observer {
// connection exists before sending the message.
void SendCastMessage(CastSocket* socket, const CastMessage& message);
+ // Sends a virtual connection request to |socket| if the virtual connection
+ // for (|source_id|, |destination_id|) does not yet exist.
+ void DoEnsureConnection(CastSocket* socket,
+ const std::string& source_id,
+ const std::string& destination_id);
+
// Callback for CastTransport::SendMessage.
void OnMessageSent(int result);
- // Invokes the pending callback associated with |request_id| with kUnknown.
- void AppAvailabilityTimedOut(int request_id);
+ void HandleCastInternalMessage(const CastSocket& socket,
+ const CastMessage& message);
- // App availability requests pending responses, keyed by request ID.
- base::flat_map<int, std::unique_ptr<GetAppAvailabilityRequest>>
- pending_app_availability_requests_;
+ // Set of pending requests keyed by socket ID.
+ base::flat_map<int, std::unique_ptr<PendingRequests>> pending_requests_;
// Source ID used for platform messages. The suffix is randomized to
// distinguish it from other Cast senders on the same network.
@@ -129,8 +223,13 @@ class CastMessageHandler : public CastSocket::Observer {
const std::string user_agent_;
const std::string browser_version_;
+ // Locale string used for session launch requests.
+ const std::string locale_;
+
int next_request_id_ = 0;
+ base::ObserverList<Observer> observers_;
+
// Set of virtual connections opened to receivers.
base::flat_set<VirtualConnection> virtual_connections_;
diff --git a/chromium/components/cast_channel/cast_message_handler_unittest.cc b/chromium/components/cast_channel/cast_message_handler_unittest.cc
index c528bf83e1e..601f2841879 100644
--- a/chromium/components/cast_channel/cast_message_handler_unittest.cc
+++ b/chromium/components/cast_channel/cast_message_handler_unittest.cc
@@ -42,18 +42,40 @@ class CastMessageHandlerTest : public testing::Test {
: environment_(
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
cast_socket_service_(new base::TestSimpleTaskRunner()),
- handler_(&cast_socket_service_, kTestUserAgentString, "66.0.3331.0") {}
+ handler_(&cast_socket_service_,
+ kTestUserAgentString,
+ "66.0.3331.0",
+ "en-US") {
+ ON_CALL(cast_socket_service_, GetSocket(_))
+ .WillByDefault(testing::Return(&cast_socket_));
+ }
+
~CastMessageHandlerTest() override {}
+ void OnMessage(const CastMessage& message) {
+ handler_.OnMessage(cast_socket_, message);
+ }
+
+ void OnError(ChannelError error) { handler_.OnError(cast_socket_, error); }
+
MOCK_METHOD2(OnAppAvailability,
void(const std::string& app_id,
GetAppAvailabilityResult result));
+ void ExpectSessionLaunchResult(LaunchSessionResponse::Result expected_result,
+ LaunchSessionResponse response) {
+ ++session_launch_response_count_;
+ EXPECT_EQ(expected_result, response.result);
+ if (response.result == LaunchSessionResponse::Result::kOk)
+ EXPECT_TRUE(response.receiver_status);
+ }
+
protected:
base::test::ScopedTaskEnvironment environment_;
MockCastSocketService cast_socket_service_;
CastMessageHandler handler_;
MockCastSocket cast_socket_;
+ int session_launch_response_count_ = 0;
private:
DISALLOW_COPY_AND_ASSIGN(CastMessageHandlerTest);
@@ -98,7 +120,7 @@ TEST_F(CastMessageHandlerTest, RecreateVirtualConnectionAfterError) {
EXPECT_CALL(
*this, OnAppAvailability("AAAAAAAA", GetAppAvailabilityResult::kUnknown));
- handler_.OnError(cast_socket_, ChannelError::TRANSPORT_ERROR);
+ OnError(ChannelError::TRANSPORT_ERROR);
EXPECT_CALL(*cast_socket_.mock_transport(), SendMessage(_, _, _))
.WillOnce(SaveArg<0>(&virtual_connection_request))
@@ -108,8 +130,13 @@ TEST_F(CastMessageHandlerTest, RecreateVirtualConnectionAfterError) {
&cast_socket_, "BBBBBBBB",
base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
base::Unretained(this)));
+
EXPECT_EQ("CONNECT", GetMessageType(virtual_connection_request));
EXPECT_EQ("GET_APP_AVAILABILITY", GetMessageType(app_availability_request));
+ // The callback is invoked with kUnknown before the PendingRequests is
+ // destroyed.
+ EXPECT_CALL(
+ *this, OnAppAvailability("BBBBBBBB", GetAppAvailabilityResult::kUnknown));
}
TEST_F(CastMessageHandlerTest, RequestAppAvailability) {
@@ -149,7 +176,7 @@ TEST_F(CastMessageHandlerTest, RequestAppAvailability) {
EXPECT_CALL(*this, OnAppAvailability("ABCDEFAB",
GetAppAvailabilityResult::kAvailable));
- handler_.OnMessage(cast_socket_, response);
+ OnMessage(response);
}
TEST_F(CastMessageHandlerTest, RequestAppAvailabilityTimesOut) {
@@ -177,4 +204,99 @@ TEST_F(CastMessageHandlerTest, AppAvailabilitySentOnlyOnceWhilePending) {
base::Unretained(this)));
}
+TEST_F(CastMessageHandlerTest, EnsureConnection) {
+ CastMessage virtual_connection_request;
+ EXPECT_CALL(*cast_socket_.mock_transport(), SendMessage(_, _, _))
+ .WillOnce(SaveArg<0>(&virtual_connection_request));
+
+ handler_.EnsureConnection(cast_socket_.id(), "sourceId", "destinationId");
+ EXPECT_EQ(CastMessageType::kConnect,
+ ParseMessageType(virtual_connection_request));
+
+ // No-op because connection is already created the first time.
+ EXPECT_CALL(*cast_socket_.mock_transport(), SendMessage(_, _, _)).Times(0);
+ handler_.EnsureConnection(cast_socket_.id(), "sourceId", "destinationId");
+}
+
+TEST_F(CastMessageHandlerTest, LaunchSession) {
+ CastMessage virtual_connection_request;
+ CastMessage launch_session_request;
+ EXPECT_CALL(*cast_socket_.mock_transport(), SendMessage(_, _, _))
+ .WillOnce(SaveArg<0>(&virtual_connection_request))
+ .WillOnce(SaveArg<0>(&launch_session_request));
+
+ handler_.LaunchSession(
+ cast_socket_.id(), "AAAAAAAA", base::TimeDelta::FromSeconds(30),
+ base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
+ base::Unretained(this),
+ LaunchSessionResponse::Result::kOk));
+ EXPECT_EQ(CastMessageType::kConnect,
+ ParseMessageType(virtual_connection_request));
+ EXPECT_EQ(CastMessageType::kLaunch, ParseMessageType(launch_session_request));
+
+ std::unique_ptr<base::Value> dict =
+ GetDictionaryFromCastMessage(launch_session_request);
+ ASSERT_TRUE(dict);
+ const base::Value* request_id_value =
+ dict->FindKeyOfType("requestId", base::Value::Type::INTEGER);
+ ASSERT_TRUE(request_id_value);
+ int request_id = request_id_value->GetInt();
+ EXPECT_GT(request_id, 0);
+
+ CastMessage response;
+ response.set_namespace_("urn:x-cast:com.google.cast.receiver");
+ response.set_source_id("receiver-0");
+ response.set_destination_id(handler_.sender_id());
+ response.set_payload_type(
+ CastMessage::PayloadType::CastMessage_PayloadType_STRING);
+ response.set_payload_utf8(
+ base::StringPrintf("{"
+ "\"type\": \"RECEIVER_STATUS\","
+ "\"requestId\": %d,"
+ "\"status\": {}"
+ "}",
+ request_id));
+
+ OnMessage(response);
+ EXPECT_EQ(1, session_launch_response_count_);
+}
+
+TEST_F(CastMessageHandlerTest, LaunchSessionTimedOut) {
+ CastMessage virtual_connection_request;
+ CastMessage launch_session_request;
+ EXPECT_CALL(*cast_socket_.mock_transport(), SendMessage(_, _, _))
+ .WillOnce(SaveArg<0>(&virtual_connection_request))
+ .WillOnce(SaveArg<0>(&launch_session_request));
+
+ handler_.LaunchSession(
+ cast_socket_.id(), "AAAAAAAA", base::TimeDelta::FromSeconds(30),
+ base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
+ base::Unretained(this),
+ LaunchSessionResponse::Result::kTimedOut));
+ EXPECT_EQ(CastMessageType::kConnect,
+ ParseMessageType(virtual_connection_request));
+ EXPECT_EQ(CastMessageType::kLaunch, ParseMessageType(launch_session_request));
+
+ environment_.FastForwardBy(base::TimeDelta::FromSeconds(30));
+ EXPECT_EQ(1, session_launch_response_count_);
+}
+
+TEST_F(CastMessageHandlerTest, SendAppMessage) {
+ CastMessage virtual_connection_request;
+ CastMessage app_message;
+ EXPECT_CALL(*cast_socket_.mock_transport(), SendMessage(_, _, _))
+ .WillOnce(SaveArg<0>(&virtual_connection_request))
+ .WillOnce(SaveArg<0>(&app_message));
+
+ base::Value body(base::Value::Type::DICTIONARY);
+ body.SetKey("foo", base::Value("bar"));
+ CastMessage message =
+ CreateCastMessage("namespace", body, "sourceId", "destinationId");
+ handler_.SendAppMessage(cast_socket_.id(), message);
+
+ EXPECT_EQ(CastMessageType::kConnect,
+ ParseMessageType(virtual_connection_request));
+ EXPECT_EQ(message.payload_utf8(), app_message.payload_utf8());
+}
+
} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_message_util.cc b/chromium/components/cast_channel/cast_message_util.cc
index 415556f50b1..011ec8e247c 100644
--- a/chromium/components/cast_channel/cast_message_util.cc
+++ b/chromium/components/cast_channel/cast_message_util.cc
@@ -10,6 +10,7 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "components/cast_channel/cast_auth_util.h"
#include "components/cast_channel/proto/cast_channel.pb.h"
@@ -19,13 +20,15 @@ using base::Value;
namespace cast_channel {
namespace {
-// Message namespaces.
+// Reserved message namespaces for internal messages.
+constexpr char kCastInternalNamespacePrefix[] = "urn:x-cast:com.google.cast.";
constexpr char kAuthNamespace[] = "urn:x-cast:com.google.cast.tp.deviceauth";
constexpr char kHeartbeatNamespace[] =
"urn:x-cast:com.google.cast.tp.heartbeat";
constexpr char kConnectionNamespace[] =
"urn:x-cast:com.google.cast.tp.connection";
constexpr char kReceiverNamespace[] = "urn:x-cast:com.google.cast.receiver";
+constexpr char kBroadcastNamespace[] = "urn:x-cast:com.google.cast.broadcast";
// Text payload keys.
constexpr char kTypeNodeId[] = "type";
@@ -36,6 +39,10 @@ constexpr char kKeepAlivePingType[] = "PING";
constexpr char kKeepAlivePongType[] = "PONG";
constexpr char kGetAppAvailabilityRequestType[] = "GET_APP_AVAILABILITY";
constexpr char kConnectionRequestType[] = "CONNECT";
+constexpr char kBroadcastRequestType[] = "APPLICATION_BROADCAST";
+constexpr char kLaunchRequestType[] = "LAUNCH";
+constexpr char kReceiverStatusType[] = "RECEIVER_STATUS";
+constexpr char kLaunchErrorType[] = "LAUNCH_ERROR";
// The value used for "sdkType" in a virtual connect request. Historically, this
// value is used in the Media Router extension, but here it is reused in Chrome.
@@ -56,16 +63,10 @@ void FillCommonCastMessageFields(CastMessage* message,
}
CastMessage CreateKeepAliveMessage(const char* keep_alive_type) {
- CastMessage output;
- FillCommonCastMessageFields(&output, kPlatformSenderId, kPlatformReceiverId,
- kHeartbeatNamespace);
- output.set_payload_type(
- CastMessage::PayloadType::CastMessage_PayloadType_STRING);
-
base::DictionaryValue type_dict;
type_dict.SetString(kTypeNodeId, keep_alive_type);
- CHECK(base::JSONWriter::Write(type_dict, output.mutable_payload_utf8()));
- return output;
+ return CreateCastMessage(kHeartbeatNamespace, type_dict, kPlatformSenderId,
+ kPlatformReceiverId);
}
// Returns the value to be set as the "platform" value in a virtual connect
@@ -88,6 +89,9 @@ int GetVirtualConnectPlatformValue() {
} // namespace
bool IsCastMessageValid(const CastMessage& message_proto) {
+ if (!message_proto.IsInitialized())
+ return false;
+
if (message_proto.namespace_().empty() || message_proto.source_id().empty() ||
message_proto.destination_id().empty()) {
return false;
@@ -107,25 +111,25 @@ std::unique_ptr<base::DictionaryValue> GetDictionaryFromCastMessage(
base::JSONReader::Read(message.payload_utf8()));
}
+bool IsCastInternalNamespace(const std::string& message_namespace) {
+ // Note: any namespace with the prefix is assumed to be reserved for internal
+ // messages.
+ return base::StartsWith(message_namespace, kCastInternalNamespacePrefix,
+ base::CompareCase::SENSITIVE);
+}
+
CastMessageType ParseMessageType(const CastMessage& message) {
std::unique_ptr<base::DictionaryValue> dictionary =
GetDictionaryFromCastMessage(message);
- if (!dictionary)
- return CastMessageType::kOther;
+ return dictionary ? ParseMessageTypeFromPayload(*dictionary)
+ : CastMessageType::kOther;
+}
+CastMessageType ParseMessageTypeFromPayload(const base::Value& payload) {
const Value* type_string =
- dictionary->FindKeyOfType(kTypeNodeId, Value::Type::STRING);
- if (!type_string)
- return CastMessageType::kOther;
-
- const std::string& type = type_string->GetString();
- if (type == kKeepAlivePingType)
- return CastMessageType::kPing;
- if (type == kKeepAlivePongType)
- return CastMessageType::kPong;
-
- DVLOG(1) << "Unknown message type: " << type;
- return CastMessageType::kOther;
+ payload.FindKeyOfType(kTypeNodeId, Value::Type::STRING);
+ return type_string ? CastMessageTypeFromString(type_string->GetString())
+ : CastMessageType::kOther;
}
const char* CastMessageTypeToString(CastMessageType message_type) {
@@ -134,13 +138,47 @@ const char* CastMessageTypeToString(CastMessageType message_type) {
return kKeepAlivePingType;
case CastMessageType::kPong:
return kKeepAlivePongType;
+ case CastMessageType::kGetAppAvailability:
+ return kGetAppAvailabilityRequestType;
+ case CastMessageType::kConnect:
+ return kConnectionRequestType;
+ case CastMessageType::kBroadcast:
+ return kBroadcastRequestType;
+ case CastMessageType::kLaunch:
+ return kLaunchRequestType;
+ case CastMessageType::kReceiverStatus:
+ return kReceiverStatusType;
+ case CastMessageType::kLaunchError:
+ return kLaunchErrorType;
case CastMessageType::kOther:
- return "unknown";
+ return "";
}
NOTREACHED();
return "";
}
+CastMessageType CastMessageTypeFromString(const std::string& type) {
+ if (type == kKeepAlivePingType)
+ return CastMessageType::kPing;
+ if (type == kKeepAlivePongType)
+ return CastMessageType::kPong;
+ if (type == kGetAppAvailabilityRequestType)
+ return CastMessageType::kGetAppAvailability;
+ if (type == kConnectionRequestType)
+ return CastMessageType::kConnect;
+ if (type == kBroadcastRequestType)
+ return CastMessageType::kBroadcast;
+ if (type == kLaunchRequestType)
+ return CastMessageType::kLaunch;
+ if (type == kReceiverStatusType)
+ return CastMessageType::kReceiverStatus;
+ if (type == kLaunchErrorType)
+ return CastMessageType::kLaunchError;
+
+ DVLOG(1) << "Unknown message type: " << type;
+ return CastMessageType::kOther;
+}
+
std::string CastMessageToString(const CastMessage& message_proto) {
std::string out("{");
out += "namespace = " + message_proto.namespace_();
@@ -220,12 +258,6 @@ CastMessage CreateVirtualConnectionRequest(
const std::string& browser_version) {
DCHECK(destination_id != kPlatformReceiverId || connection_type == kStrong);
- CastMessage output;
- FillCommonCastMessageFields(&output, source_id, destination_id,
- kConnectionNamespace);
- output.set_payload_type(
- CastMessage::PayloadType::CastMessage_PayloadType_STRING);
-
// Parse system_version from user agent string. It contains platform, OS and
// CPU info and is contained in the first set of parentheses of the user
// agent string (e.g., X11; Linux x86_64).
@@ -243,6 +275,7 @@ CastMessage CreateVirtualConnectionRequest(
dict.SetKey(kTypeNodeId, Value(kConnectionRequestType));
dict.SetKey("userAgent", Value(user_agent));
dict.SetKey("connType", Value(connection_type));
+ dict.SetKey("origin", Value(Value::Type::DICTIONARY));
Value sender_info(Value::Type::DICTIONARY);
sender_info.SetKey("sdkType", Value(kVirtualConnectSdkType));
@@ -254,29 +287,90 @@ CastMessage CreateVirtualConnectionRequest(
sender_info.SetKey("systemVersion", Value(system_version));
dict.SetKey("senderInfo", std::move(sender_info));
- CHECK(base::JSONWriter::Write(dict, output.mutable_payload_utf8()));
- return output;
+
+ return CreateCastMessage(kConnectionNamespace, dict, source_id,
+ destination_id);
}
CastMessage CreateGetAppAvailabilityRequest(const std::string& source_id,
int request_id,
const std::string& app_id) {
- CastMessage output;
- FillCommonCastMessageFields(&output, source_id, kPlatformReceiverId,
- kReceiverNamespace);
- output.set_payload_type(
- CastMessage::PayloadType::CastMessage_PayloadType_STRING);
-
Value dict(Value::Type::DICTIONARY);
dict.SetKey(kTypeNodeId, Value(kGetAppAvailabilityRequestType));
Value app_id_value(Value::Type::LIST);
app_id_value.GetList().push_back(Value(app_id));
dict.SetKey("appId", std::move(app_id_value));
dict.SetKey(kRequestIdNodeId, Value(request_id));
- CHECK(base::JSONWriter::Write(dict, output.mutable_payload_utf8()));
+
+ return CreateCastMessage(kReceiverNamespace, dict, source_id,
+ kPlatformReceiverId);
+}
+
+BroadcastRequest::BroadcastRequest(const std::string& broadcast_namespace,
+ const std::string& message)
+ : broadcast_namespace(broadcast_namespace), message(message) {}
+BroadcastRequest::~BroadcastRequest() = default;
+
+bool BroadcastRequest::operator==(const BroadcastRequest& other) const {
+ return broadcast_namespace == other.broadcast_namespace &&
+ message == other.message;
+}
+
+CastMessage CreateBroadcastRequest(const std::string& source_id,
+ int request_id,
+ const std::vector<std::string>& app_ids,
+ const BroadcastRequest& request) {
+ Value dict(Value::Type::DICTIONARY);
+ dict.SetKey(kTypeNodeId, Value(kBroadcastRequestType));
+ std::vector<Value> app_ids_value;
+ for (const std::string& app_id : app_ids)
+ app_ids_value.push_back(Value(app_id));
+
+ dict.SetKey("appIds", Value(std::move(app_ids_value)));
+ dict.SetKey("namespace", Value(request.broadcast_namespace));
+ dict.SetKey("message", Value(request.message));
+ return CreateCastMessage(kBroadcastNamespace, dict, source_id,
+ kPlatformReceiverId);
+}
+
+CastMessage CreateLaunchRequest(const std::string& source_id,
+ int request_id,
+ const std::string& app_id,
+ const std::string& locale) {
+ Value dict(Value::Type::DICTIONARY);
+ dict.SetKey(kTypeNodeId, Value(kLaunchRequestType));
+ dict.SetKey(kRequestIdNodeId, Value(request_id));
+ dict.SetKey("appId", Value(app_id));
+ dict.SetKey("language", Value(locale));
+
+ return CreateCastMessage(kReceiverNamespace, dict, source_id,
+ kPlatformReceiverId);
+}
+
+CastMessage CreateCastMessage(const std::string& message_namespace,
+ const base::Value& message,
+ const std::string& source_id,
+ const std::string& destination_id) {
+ CastMessage output;
+ FillCommonCastMessageFields(&output, source_id, destination_id,
+ message_namespace);
+ output.set_payload_type(
+ CastMessage::PayloadType::CastMessage_PayloadType_STRING);
+ CHECK(base::JSONWriter::Write(message, output.mutable_payload_utf8()));
return output;
}
+const char* GetAppAvailabilityResultToString(GetAppAvailabilityResult result) {
+ switch (result) {
+ case GetAppAvailabilityResult::kAvailable:
+ return "available";
+ case GetAppAvailabilityResult::kUnavailable:
+ return "unavailable";
+ case GetAppAvailabilityResult::kUnknown:
+ return "unknown";
+ }
+}
+
bool GetRequestIdFromResponse(const Value& payload, int* request_id) {
DCHECK(request_id);
DCHECK(payload.is_dict());
@@ -307,4 +401,36 @@ GetAppAvailabilityResult GetAppAvailabilityResultFromResponse(
return GetAppAvailabilityResult::kUnknown;
}
+LaunchSessionResponse::LaunchSessionResponse() {}
+LaunchSessionResponse::LaunchSessionResponse(LaunchSessionResponse&& other) =
+ default;
+LaunchSessionResponse::~LaunchSessionResponse() = default;
+
+LaunchSessionResponse GetLaunchSessionResponse(
+ const base::DictionaryValue& payload) {
+ const Value* type_value =
+ payload.FindKeyOfType(kTypeNodeId, Value::Type::STRING);
+ if (!type_value)
+ return LaunchSessionResponse();
+
+ if (type_value->GetString() != kReceiverStatusType &&
+ type_value->GetString() != kLaunchErrorType)
+ return LaunchSessionResponse();
+
+ LaunchSessionResponse response;
+ if (type_value->GetString() == kLaunchErrorType) {
+ response.result = LaunchSessionResponse::Result::kError;
+ return response;
+ }
+
+ const Value* receiver_status =
+ payload.FindKeyOfType("status", Value::Type::DICTIONARY);
+ if (!receiver_status)
+ return LaunchSessionResponse();
+
+ response.result = LaunchSessionResponse::Result::kOk;
+ response.receiver_status = receiver_status->Clone();
+ return response;
+}
+
} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_message_util.h b/chromium/components/cast_channel/cast_message_util.h
index c0882cc52ed..aedf0bca1ad 100644
--- a/chromium/components/cast_channel/cast_message_util.h
+++ b/chromium/components/cast_channel/cast_message_util.h
@@ -20,7 +20,17 @@ constexpr char kPlatformSenderId[] = "sender-0";
constexpr char kPlatformReceiverId[] = "receiver-0";
// Cast application protocol message types.
-enum class CastMessageType { kOther, kPing, kPong };
+enum class CastMessageType {
+ kPing,
+ kPong,
+ kGetAppAvailability,
+ kConnect, // Virtual connection request
+ kBroadcast, // Application broadcast / precache
+ kLaunch, // Session launch request
+ kReceiverStatus,
+ kLaunchError,
+ kOther // Add new types above |kOther|.
+};
// Checks if the contents of |message_proto| are valid.
bool IsCastMessageValid(const CastMessage& message_proto);
@@ -30,14 +40,25 @@ bool IsCastMessageValid(const CastMessage& message_proto);
std::unique_ptr<base::DictionaryValue> GetDictionaryFromCastMessage(
const CastMessage& message);
+// Returns true if |message_namespace| is a namespace reserved for internal
+// messages.
+bool IsCastInternalNamespace(const std::string& message_namespace);
+
// Parses the JSON-encoded payload of |message| and returns the value in the
// "type" field or |kUnknown| if the parse fails or the field is not found.
// The result is only valid if |message| is a Cast application protocol message.
CastMessageType ParseMessageType(const CastMessage& message);
+// Similar to |ParseMessageType()|, but |payload| is already JSON-parsed.
+CastMessageType ParseMessageTypeFromPayload(const base::Value& payload);
+
// Returns a human readable string for |message_type|.
const char* CastMessageTypeToString(CastMessageType message_type);
+// Returns the CastMessageType for |type|, or |kOther| if it does not
+// correspond to a known type.
+CastMessageType CastMessageTypeFromString(const std::string& type);
+
// Returns a human readable string for |message_proto|.
std::string CastMessageToString(const CastMessage& message_proto);
@@ -87,6 +108,37 @@ CastMessage CreateGetAppAvailabilityRequest(const std::string& source_id,
int request_id,
const std::string& app_id);
+// Represents a broadcast request. Currently it is used for precaching data
+// on a receiver.
+struct BroadcastRequest {
+ BroadcastRequest(const std::string& broadcast_namespace,
+ const std::string& message);
+ ~BroadcastRequest();
+ bool operator==(const BroadcastRequest& other) const;
+
+ std::string broadcast_namespace;
+ std::string message;
+};
+
+// Creates a broadcast request with the given parameters.
+CastMessage CreateBroadcastRequest(const std::string& source_id,
+ int request_id,
+ const std::vector<std::string>& app_ids,
+ const BroadcastRequest& request);
+
+// Creates a session launch request with the given parameters.
+CastMessage CreateLaunchRequest(const std::string& source_id,
+ int request_id,
+ const std::string& app_id,
+ const std::string& locale);
+
+// Creates a generic CastMessage with |message| as the string payload. Used for
+// app messages.
+CastMessage CreateCastMessage(const std::string& message_namespace,
+ const base::Value& message,
+ const std::string& source_id,
+ const std::string& destination_id);
+
// Possible results of a GET_APP_AVAILABILITY request.
enum class GetAppAvailabilityResult {
kAvailable,
@@ -94,6 +146,8 @@ enum class GetAppAvailabilityResult {
kUnknown,
};
+const char* GetAppAvailabilityResultToString(GetAppAvailabilityResult result);
+
// Extracts request ID from |payload| corresponding to a Cast message response.
// If request ID is available, assigns it to |request_id|. Return |true| if
// request ID is found.
@@ -105,6 +159,26 @@ GetAppAvailabilityResult GetAppAvailabilityResultFromResponse(
const base::Value& payload,
const std::string& app_id);
+// Result of a session launch.
+struct LaunchSessionResponse {
+ enum Result { kOk, kError, kTimedOut, kUnknown };
+
+ LaunchSessionResponse();
+ LaunchSessionResponse(LaunchSessionResponse&& other);
+ ~LaunchSessionResponse();
+
+ Result result = Result::kUnknown;
+
+ // Populated if |result| is |kOk|.
+ base::Optional<base::Value> receiver_status;
+};
+
+// Parses |payload| into a LaunchSessionResponse. Returns an empty
+// LaunchSessionResponse if |payload| is not a properly formatted launch
+// response. |payload| must be from the string payload of a CastMessage.
+LaunchSessionResponse GetLaunchSessionResponse(
+ const base::DictionaryValue& payload);
+
} // namespace cast_channel
#endif // COMPONENTS_CAST_CHANNEL_CAST_MESSAGE_UTIL_H_
diff --git a/chromium/components/cast_channel/cast_message_util_unittest.cc b/chromium/components/cast_channel/cast_message_util_unittest.cc
new file mode 100644
index 00000000000..9fdbfa83c84
--- /dev/null
+++ b/chromium/components/cast_channel/cast_message_util_unittest.cc
@@ -0,0 +1,82 @@
+// 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 "components/cast_channel/cast_message_util.h"
+
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cast_channel {
+
+TEST(CastMessageUtilTest, IsCastInternalNamespace) {
+ EXPECT_TRUE(IsCastInternalNamespace("urn:x-cast:com.google.cast.receiver"));
+ EXPECT_FALSE(IsCastInternalNamespace("urn:x-cast:com.google.youtube"));
+ EXPECT_FALSE(IsCastInternalNamespace("urn:x-cast:com.foo"));
+ EXPECT_FALSE(IsCastInternalNamespace("foo"));
+ EXPECT_FALSE(IsCastInternalNamespace(""));
+}
+
+TEST(CastMessageUtilTest, CastMessageType) {
+ for (int i = 0; i < static_cast<int>(CastMessageType::kOther); ++i) {
+ CastMessageType type = static_cast<CastMessageType>(i);
+ EXPECT_EQ(type, CastMessageTypeFromString(CastMessageTypeToString(type)));
+ }
+}
+
+TEST(CastMessageUtilTest, GetLaunchSessionResponseOk) {
+ std::string payload = R"(
+ {
+ "type": "RECEIVER_STATUS",
+ "requestId": 123,
+ "status": {}
+ }
+ )";
+
+ std::unique_ptr<base::DictionaryValue> value =
+ base::DictionaryValue::From(base::JSONReader::Read(payload));
+ ASSERT_TRUE(value);
+
+ LaunchSessionResponse response = GetLaunchSessionResponse(*value);
+ EXPECT_EQ(LaunchSessionResponse::Result::kOk, response.result);
+ EXPECT_TRUE(response.receiver_status);
+}
+
+TEST(CastMessageUtilTest, GetLaunchSessionResponseError) {
+ std::string payload = R"(
+ {
+ "type": "LAUNCH_ERROR",
+ "requestId": 123
+ }
+ )";
+
+ std::unique_ptr<base::DictionaryValue> value =
+ base::DictionaryValue::From(base::JSONReader::Read(payload));
+ ASSERT_TRUE(value);
+
+ LaunchSessionResponse response = GetLaunchSessionResponse(*value);
+ EXPECT_EQ(LaunchSessionResponse::Result::kError, response.result);
+ EXPECT_FALSE(response.receiver_status);
+}
+
+TEST(CastMessageUtilTest, GetLaunchSessionResponseUnknown) {
+ // Unrelated type.
+ std::string payload = R"(
+ {
+ "type": "APPLICATION_BROADCAST",
+ "requestId": 123,
+ "status": {}
+ }
+ )";
+
+ std::unique_ptr<base::DictionaryValue> value =
+ base::DictionaryValue::From(base::JSONReader::Read(payload));
+ ASSERT_TRUE(value);
+
+ LaunchSessionResponse response = GetLaunchSessionResponse(*value);
+ EXPECT_EQ(LaunchSessionResponse::Result::kUnknown, response.result);
+ EXPECT_FALSE(response.receiver_status);
+}
+
+} // namespace cast_channel
diff --git a/chromium/components/cast_channel/cast_socket.cc b/chromium/components/cast_channel/cast_socket.cc
index 01ff7ed4a19..5ef5fb1b1ba 100644
--- a/chromium/components/cast_channel/cast_socket.cc
+++ b/chromium/components/cast_channel/cast_socket.cc
@@ -168,7 +168,7 @@ std::unique_ptr<net::SSLClientSocket> CastSocketImpl::CreateSslSocket(
cert_verifier_ = base::WrapUnique(new FakeCertVerifier);
transport_security_state_.reset(new net::TransportSecurityState);
cert_transparency_verifier_.reset(new net::MultiLogCTVerifier());
- ct_policy_enforcer_.reset(new net::CTPolicyEnforcer());
+ ct_policy_enforcer_.reset(new net::DefaultCTPolicyEnforcer());
// Note that |context| fields remain owned by CastSocketImpl.
net::SSLClientSocketContext context;
@@ -189,7 +189,7 @@ std::unique_ptr<net::SSLClientSocket> CastSocketImpl::CreateSslSocket(
scoped_refptr<net::X509Certificate> CastSocketImpl::ExtractPeerCert() {
net::SSLInfo ssl_info;
- if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert.get())
+ if (!socket_->GetSSLInfo(&ssl_info) || !ssl_info.cert)
return nullptr;
return ssl_info.cert;
@@ -430,7 +430,7 @@ int CastSocketImpl::DoSslConnectComplete(int result) {
}
// SSL connection succeeded.
- if (!transport_.get()) {
+ if (!transport_) {
// Create a channel transport if one wasn't already set (e.g. by test
// code).
transport_.reset(new CastTransportImpl(
diff --git a/chromium/components/cast_channel/cast_socket_unittest.cc b/chromium/components/cast_channel/cast_socket_unittest.cc
index e6ac4f7d060..75c46359e49 100644
--- a/chromium/components/cast_channel/cast_socket_unittest.cc
+++ b/chromium/components/cast_channel/cast_socket_unittest.cc
@@ -9,12 +9,12 @@
#include <utility>
#include <vector>
+#include "base/callback_helpers.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
@@ -97,7 +97,7 @@ CastMessage CreateTestMessage() {
base::FilePath GetTestCertsDirectory() {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.Append(FILE_PATH_LITERAL("components"));
path = path.Append(FILE_PATH_LITERAL("test"));
path = path.Append(FILE_PATH_LITERAL("data"));
@@ -112,13 +112,12 @@ class MockTCPSocket : public net::MockTCPClientSocket {
do_nothing_ = do_nothing;
}
- int Connect(const net::CompletionCallback& callback) override {
+ int Connect(net::CompletionOnceCallback callback) override {
if (do_nothing_) {
// Stall the I/O event loop.
return net::ERR_IO_PENDING;
}
-
- return net::MockTCPClientSocket::Connect(callback);
+ return net::MockTCPClientSocket::Connect(std::move(callback));
}
private:
@@ -257,13 +256,12 @@ class MockTestCastSocket : public TestCastSocketBase {
// may be live at a time.
std::unique_ptr<net::TransportClientSocket> CreateTcpSocket() override {
if (tcp_unresponsive_) {
- socket_data_provider_ = std::make_unique<net::StaticSocketDataProvider>(
- nullptr, 0, nullptr, 0);
+ socket_data_provider_ = std::make_unique<net::StaticSocketDataProvider>();
return std::unique_ptr<net::TransportClientSocket>(
new MockTCPSocket(true, socket_data_provider_.get()));
} else {
- socket_data_provider_ = std::make_unique<net::StaticSocketDataProvider>(
- reads_.data(), reads_.size(), writes_.data(), writes_.size());
+ socket_data_provider_ =
+ std::make_unique<net::StaticSocketDataProvider>(reads_, writes_);
socket_data_provider_->set_connect_data(*tcp_connect_data_);
return std::unique_ptr<net::TransportClientSocket>(
new MockTCPSocket(false, socket_data_provider_.get()));
@@ -359,7 +357,7 @@ class MockCastSocketTest : public CastSocketTestBase {
MockCastSocketTest() {}
void TearDown() override {
- if (socket_.get()) {
+ if (socket_) {
EXPECT_CALL(handler_, OnCloseComplete(net::OK));
socket_->Close(base::Bind(&CompleteHandler::OnCloseComplete,
base::Unretained(&handler_)));
@@ -398,7 +396,7 @@ class SslCastSocketTest : public CastSocketTestBase {
SslCastSocketTest() {}
void TearDown() override {
- if (socket_.get()) {
+ if (socket_) {
EXPECT_CALL(handler_, OnCloseComplete(net::OK));
socket_->Close(base::Bind(&CompleteHandler::OnCloseComplete,
base::Unretained(&handler_)));
diff --git a/chromium/components/cast_channel/cast_test_util.cc b/chromium/components/cast_channel/cast_test_util.cc
index f90d13d3ce7..3dbbbebf551 100644
--- a/chromium/components/cast_channel/cast_test_util.cc
+++ b/chromium/components/cast_channel/cast_test_util.cc
@@ -30,8 +30,7 @@ MockCastSocketObserver::MockCastSocketObserver() {}
MockCastSocketObserver::~MockCastSocketObserver() {}
MockCastSocketService::MockCastSocketService(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
- : CastSocketService() {
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
SetTaskRunnerForTest(task_runner);
}
MockCastSocketService::~MockCastSocketService() {}
@@ -50,7 +49,7 @@ net::IPEndPoint CreateIPEndPointForTest() {
MockCastMessageHandler::MockCastMessageHandler(
MockCastSocketService* socket_service)
- : CastMessageHandler(socket_service, "userAgent", "1.2.3.4") {}
+ : CastMessageHandler(socket_service, "userAgent", "1.2.3.4", "en-US") {}
MockCastMessageHandler::~MockCastMessageHandler() = default;
diff --git a/chromium/components/cast_channel/cast_test_util.h b/chromium/components/cast_channel/cast_test_util.h
index 87813250760..54484868213 100644
--- a/chromium/components/cast_channel/cast_test_util.h
+++ b/chromium/components/cast_channel/cast_test_util.h
@@ -160,6 +160,11 @@ class MockCastMessageHandler : public CastMessageHandler {
const std::string&,
GetAppAvailabilityCallback&));
+ MOCK_METHOD3(SendBroadcastMessage,
+ void(int,
+ const std::vector<std::string>&,
+ const BroadcastRequest&));
+
private:
DISALLOW_COPY_AND_ASSIGN(MockCastMessageHandler);
};
diff --git a/chromium/components/cast_channel/cast_transport.cc b/chromium/components/cast_channel/cast_transport.cc
index 8036767a9e6..4040f2f4fe3 100644
--- a/chromium/components/cast_channel/cast_transport.cc
+++ b/chromium/components/cast_channel/cast_transport.cc
@@ -88,6 +88,7 @@ void CastTransportImpl::SendMessage(
const net::CompletionCallback& callback,
const net::NetworkTrafficAnnotationTag& traffic_annotation) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(IsCastMessageValid(message));
std::string serialized_message;
if (!MessageFramer::Serialize(message, &serialized_message)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chromium/components/cast_channel/cast_transport_unittest.cc b/chromium/components/cast_channel/cast_transport_unittest.cc
index 98cb32509bb..e3abe1356af 100644
--- a/chromium/components/cast_channel/cast_transport_unittest.cc
+++ b/chromium/components/cast_channel/cast_transport_unittest.cc
@@ -7,6 +7,7 @@
#include <stddef.h>
#include <stdint.h>
+#include "base/callback_helpers.h"
#include "base/containers/queue.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
@@ -121,6 +122,21 @@ ACTION_TEMPLATE(EnqueueCallback,
class MockSocket : public net::Socket {
public:
+ int Read(net::IOBuffer* buffer,
+ int bytes,
+ net::CompletionOnceCallback callback) override {
+ return Read(buffer, bytes,
+ base::AdaptCallbackForRepeating(std::move(callback)));
+ }
+
+ int Write(net::IOBuffer* buffer,
+ int bytes,
+ net::CompletionOnceCallback callback,
+ const net::NetworkTrafficAnnotationTag& tag) override {
+ return Write(buffer, bytes,
+ base::AdaptCallbackForRepeating(std::move(callback)), tag);
+ }
+
MOCK_METHOD3(Read,
int(net::IOBuffer* buf,
int buf_len,
@@ -132,12 +148,12 @@ class MockSocket : public net::Socket {
const net::CompletionCallback& callback,
const net::NetworkTrafficAnnotationTag&));
- virtual int SetReceiveBufferSize(int32_t size) {
+ int SetReceiveBufferSize(int32_t size) override {
NOTREACHED();
return 0;
}
- virtual int SetSendBufferSize(int32_t size) {
+ int SetSendBufferSize(int32_t size) override {
NOTREACHED();
return 0;
}
diff --git a/chromium/components/cbor/cbor_reader.cc b/chromium/components/cbor/cbor_reader.cc
index c08bbd6a5b8..5abab730783 100644
--- a/chromium/components/cbor/cbor_reader.cc
+++ b/chromium/components/cbor/cbor_reader.cc
@@ -102,26 +102,6 @@ base::Optional<CBORValue> CBORReader::Read(base::span<uint8_t const> data,
return decoded_cbor;
}
-// static
-base::Optional<CBORReader::DataItemHeader> CBORReader::ReadDataItemHeader(
- base::span<const uint8_t> data,
- size_t* num_bytes_consumed,
- DecoderError* error_code_out) {
- CBORReader reader(data.cbegin(), data.cend());
- base::Optional<DataItemHeader> decoded_header = reader.DecodeDataItemHeader();
-
- if (error_code_out)
- *error_code_out = reader.GetErrorCode();
-
- if (reader.GetErrorCode() != DecoderError::CBOR_NO_ERROR) {
- *num_bytes_consumed = 0;
- return base::nullopt;
- }
-
- *num_bytes_consumed = reader.num_bytes_consumed();
- return decoded_header;
-}
-
base::Optional<CBORValue> CBORReader::DecodeCompleteDataItem(
int max_nesting_level) {
if (max_nesting_level < 0 || max_nesting_level > kCBORMaxDepth) {
diff --git a/chromium/components/cbor/cbor_reader.h b/chromium/components/cbor/cbor_reader.h
index 65b93d5bb68..9565e1e5f41 100644
--- a/chromium/components/cbor/cbor_reader.h
+++ b/chromium/components/cbor/cbor_reader.h
@@ -69,25 +69,6 @@ class CBOR_EXPORT CBORReader {
UNKNOWN_ERROR,
};
- // Encapsulates information extracted from the header of a CBOR data item,
- // which consists of the initial byte, and a variable-length-encoded integer
- // (if any).
- //
- // TODO(crbug.com/811717): This is an CBORReader internal detail which should
- // not be exposed outside. We should switch to an event-based interface
- // before adding another customer.
- struct CBOR_EXPORT DataItemHeader {
- // The major type decoded from the initial byte.
- CBORValue::Type type;
-
- // The raw 5-bit additional information from the initial byte.
- uint8_t additional_info;
-
- // The integer |value| decoded from the |additional_info| and the
- // variable-length-encoded integer, if any.
- uint64_t value;
- };
-
// CBOR nested depth sufficient for most use cases.
static const int kCBORMaxDepth = 16;
@@ -112,23 +93,28 @@ class CBOR_EXPORT CBORReader {
DecoderError* error_code_out = nullptr,
int max_nesting_level = kCBORMaxDepth);
- // Reads and parses the header of CBOR data item from |input_data|. Optional
- // |error_code_out| can be provided by the caller to obtain additional
- // information about decoding failures, which is always available if an empty
- // value is returned. Never fails with EXTRANEOUS_DATA, but informs the
- // caller of how many bytes were consumed through |num_bytes_consumed|, which
- // is set to zero on error.
- static base::Optional<DataItemHeader> ReadDataItemHeader(
- base::span<const uint8_t> input_data,
- size_t* num_bytes_consumed = nullptr,
- DecoderError* error_code_out = nullptr);
-
// Translates errors to human-readable error messages.
static const char* ErrorCodeToString(DecoderError error_code);
private:
CBORReader(base::span<const uint8_t>::const_iterator it,
const base::span<const uint8_t>::const_iterator end);
+
+ // Encapsulates information extracted from the header of a CBOR data item,
+ // which consists of the initial byte, and a variable-length-encoded integer
+ // (if any).
+ struct DataItemHeader {
+ // The major type decoded from the initial byte.
+ CBORValue::Type type;
+
+ // The raw 5-bit additional information from the initial byte.
+ uint8_t additional_info;
+
+ // The integer |value| decoded from the |additional_info| and the
+ // variable-length-encoded integer, if any.
+ uint64_t value;
+ };
+
base::Optional<DataItemHeader> DecodeDataItemHeader();
base::Optional<CBORValue> DecodeCompleteDataItem(int max_nesting_level);
base::Optional<CBORValue> DecodeValueToNegative(uint64_t value);
diff --git a/chromium/components/cbor/cbor_reader_unittest.cc b/chromium/components/cbor/cbor_reader_unittest.cc
index 419cd91b96e..902b9b94030 100644
--- a/chromium/components/cbor/cbor_reader_unittest.cc
+++ b/chromium/components/cbor/cbor_reader_unittest.cc
@@ -27,92 +27,6 @@ std::vector<uint8_t> WithExtraneousData(base::span<const uint8_t> original) {
} // namespace
-TEST(CBORReaderTest, TestDecodeDataItemHeader) {
- static const struct {
- CBORReader::DataItemHeader expected_header;
- const std::vector<uint8_t> cbor_data;
- } kTestCases[] = {
- {{CBORValue::Type::UNSIGNED, 0, 0}, {0x00}},
- {{CBORValue::Type::UNSIGNED, 24, 24}, {0x18, 0x18}},
- {{CBORValue::Type::UNSIGNED, 25, 12345}, {0x19, 0x30, 0x39}},
- {{CBORValue::Type::UNSIGNED, 27, 1234567890123456789ull},
- {0x1B, 0x11, 0x22, 0x10, 0xF4, 0x7D, 0xE9, 0x81, 0x15}},
- {{CBORValue::Type::NEGATIVE, 24, 255}, {0x38, 0xff}},
- {{CBORValue::Type::NEGATIVE, 26, 12345677},
- {0x3a, 0x00, 0xbc, 0x61, 0x4d}},
- {{CBORValue::Type::BYTE_STRING, 4, 4}, {0x44}},
- {{CBORValue::Type::STRING, 3, 3}, {0x63}},
- {{CBORValue::Type::ARRAY, 24, 25}, {0x98, 0x19}},
- {{CBORValue::Type::MAP, 4, 4}, {0xa4}},
- {{CBORValue::Type::SIMPLE_VALUE,
- static_cast<uint8_t>(CBORValue::SimpleValue::FALSE_VALUE), 20},
- {0xf4}},
- };
-
- int test_element_index = 0;
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "testing case " << test_element_index++);
- size_t consumed_bytes;
- CBORReader::DecoderError error_code;
- base::Optional<CBORReader::DataItemHeader> header =
- CBORReader::ReadDataItemHeader(test_case.cbor_data, &consumed_bytes,
- &error_code);
-
- ASSERT_TRUE(header.has_value());
- EXPECT_EQ(header->type, test_case.expected_header.type);
- EXPECT_EQ(header->additional_info,
- test_case.expected_header.additional_info);
- EXPECT_EQ(header->value, test_case.expected_header.value);
- EXPECT_EQ(consumed_bytes, test_case.cbor_data.size());
- EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
-
- auto cbor_data_with_extra_byte = WithExtraneousData(test_case.cbor_data);
- header = CBORReader::ReadDataItemHeader(cbor_data_with_extra_byte,
- &consumed_bytes, &error_code);
- ASSERT_TRUE(header.has_value());
- EXPECT_EQ(header->type, test_case.expected_header.type);
- EXPECT_EQ(header->additional_info,
- test_case.expected_header.additional_info);
- EXPECT_EQ(header->value, test_case.expected_header.value);
- EXPECT_EQ(consumed_bytes, test_case.cbor_data.size());
- EXPECT_EQ(error_code, CBORReader::DecoderError::CBOR_NO_ERROR);
- }
-}
-
-TEST(CBORReaderTest, TestDecodeIncompleteDataItemHeader) {
- static const std::vector<uint8_t> kTestCases[] = {
- // clang-format off
- {0x18}, // unsigned with pending 1 byte of numeric value.
- {0x99}, // array with pending 2 byte of numeric value (length).
- {0xba}, // map with pending 4 byte of numeric value (length).
- {0x5b}, // byte string with pending 4 byte of numeric value (length).
- {0x3b}, // negative integer with pending 8 byte of numeric value.
- {0x99, 0x01}, // array with pending 2 byte of numeric value (length),
- // with only 1 byte of additional data.
- {0xba, 0x01, 0x02, 0x03}, // map with pending 4 byte of numeric value
- // (length), with only 3 bytes of additional
- // data.
- {0x3b, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0x06, 0x07}, // negative integer with pending 8 byte of
- // numeric value, with only 7 bytes of
- // additional data.
- // clang-format on
- };
-
- int test_element_index = 0;
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "testing case " << test_element_index++);
- size_t consumed_bytes;
- CBORReader::DecoderError error_code;
- base::Optional<CBORReader::DataItemHeader> header =
- CBORReader::ReadDataItemHeader(test_case, &consumed_bytes, &error_code);
-
- ASSERT_FALSE(header.has_value());
- EXPECT_EQ(consumed_bytes, 0u);
- EXPECT_EQ(error_code, CBORReader::DecoderError::INCOMPLETE_CBOR_DATA);
- }
-}
-
TEST(CBORReaderTest, TestReadUint) {
struct UintTestCase {
const int64_t value;
@@ -997,6 +911,20 @@ TEST(CBORReaderTest, TestIncompleteCBORDataError) {
// CBOR map with single key value pair encoded with additional info of
// length 2.
{0xa2, 0x61, 0x61, 0x01},
+ {0x18}, // unsigned with pending 1 byte of numeric value.
+ {0x99}, // array with pending 2 byte of numeric value (length).
+ {0xba}, // map with pending 4 byte of numeric value (length).
+ {0x5b}, // byte string with pending 4 byte of numeric value (length).
+ {0x3b}, // negative integer with pending 8 byte of numeric value.
+ {0x99, 0x01}, // array with pending 2 byte of numeric value (length),
+ // with only 1 byte of additional data.
+ {0xba, 0x01, 0x02, 0x03}, // map with pending 4 byte of numeric value
+ // (length), with only 3 bytes of additional
+ // data.
+ {0x3b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07}, // negative integer with pending 8 byte of
+ // numeric value, with only 7 bytes of
+ // additional data.
};
int test_element_index = 0;
diff --git a/chromium/components/cdm/common/widevine_drm_delegate_android.cc b/chromium/components/cdm/common/widevine_drm_delegate_android.cc
index 7d5af4302c0..3bb54692b4a 100644
--- a/chromium/components/cdm/common/widevine_drm_delegate_android.cc
+++ b/chromium/components/cdm/common/widevine_drm_delegate_android.cc
@@ -6,7 +6,6 @@
#include "base/macros.h"
#include "media/cdm/cenc_utils.h"
-#include "media/media_buildflags.h"
namespace cdm {
@@ -35,13 +34,9 @@ bool WidevineDrmDelegateAndroid::OnCreateSession(
if (init_data_type != media::EmeInitDataType::CENC)
return true;
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
// Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as
// the init data when using MP4 container.
return media::GetPsshData(init_data, GetUUID(), init_data_out);
-#else
- return false;
-#endif
}
} // namespace cdm
diff --git a/chromium/components/cdm/renderer/android_key_systems.cc b/chromium/components/cdm/renderer/android_key_systems.cc
index ec177e94293..6eaa2ba963d 100644
--- a/chromium/components/cdm/renderer/android_key_systems.cc
+++ b/chromium/components/cdm/renderer/android_key_systems.cc
@@ -48,11 +48,7 @@ class AndroidPlatformKeySystemProperties : public KeySystemProperties {
case EmeInitDataType::WEBM:
return (supported_codecs_ & media::EME_CODEC_WEBM_ALL) != 0;
case EmeInitDataType::CENC:
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
return (supported_codecs_ & media::EME_CODEC_MP4_ALL) != 0;
-#else
- return false;
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
case EmeInitDataType::KEYIDS:
case EmeInitDataType::UNKNOWN:
return false;
@@ -61,6 +57,11 @@ class AndroidPlatformKeySystemProperties : public KeySystemProperties {
return false;
}
+ bool IsEncryptionSchemeSupported(
+ media::EncryptionMode encryption_scheme) const override {
+ return encryption_scheme == media::EncryptionMode::kCenc;
+ }
+
SupportedCodecs GetSupportedCodecs() const override {
return supported_codecs_;
}
@@ -112,8 +113,8 @@ SupportedKeySystemResponse QueryKeySystemSupport(
void AddAndroidWidevine(
std::vector<std::unique_ptr<KeySystemProperties>>* concrete_key_systems) {
- SupportedKeySystemResponse response = QueryKeySystemSupport(
- kWidevineKeySystem);
+ SupportedKeySystemResponse response =
+ QueryKeySystemSupport(kWidevineKeySystem);
// Since we do not control the implementation of the MediaDrm API on Android,
// we assume that it can and will make use of persistence no matter whether
@@ -126,7 +127,14 @@ void AddAndroidWidevine(
if (response.non_secure_codecs != media::EME_CODEC_NONE) {
DVLOG(3) << __func__ << " Widevine supported.";
+
+ // TODO(crbug.com/813845): Determine 'cbcs' support, which may vary by
+ // Android version.
+ base::flat_set<media::EncryptionMode> supported_encryption_schemes = {
+ media::EncryptionMode::kCenc};
+
concrete_key_systems->emplace_back(new WidevineKeySystemProperties(
+ supported_encryption_schemes, // Encryption schemes.
response.non_secure_codecs, // Regular codecs.
response.secure_codecs, // Hardware-secure codecs.
Robustness::HW_SECURE_CRYPTO, // Max audio robustness.
diff --git a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
index 9ff56dc6d68..828d628aceb 100644
--- a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
+++ b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.cc
@@ -6,7 +6,6 @@
#include "base/logging.h"
#include "media/base/eme_constants.h"
-#include "media/media_buildflags.h"
namespace cdm {
@@ -23,17 +22,11 @@ std::string ExternalClearKeyProperties::GetKeySystemName() const {
bool ExternalClearKeyProperties::IsSupportedInitDataType(
media::EmeInitDataType init_data_type) const {
switch (init_data_type) {
+ case media::EmeInitDataType::CENC:
case media::EmeInitDataType::WEBM:
case media::EmeInitDataType::KEYIDS:
return true;
- case media::EmeInitDataType::CENC:
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
- return true;
-#else
- return false;
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
-
case media::EmeInitDataType::UNKNOWN:
return false;
}
@@ -41,12 +34,21 @@ bool ExternalClearKeyProperties::IsSupportedInitDataType(
return false;
}
+bool ExternalClearKeyProperties::IsEncryptionSchemeSupported(
+ media::EncryptionMode encryption_scheme) const {
+ switch (encryption_scheme) {
+ case media::EncryptionMode::kCenc:
+ case media::EncryptionMode::kCbcs:
+ return true;
+ case media::EncryptionMode::kUnencrypted:
+ break;
+ }
+ NOTREACHED();
+ return false;
+}
+
media::SupportedCodecs ExternalClearKeyProperties::GetSupportedCodecs() const {
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
return media::EME_CODEC_MP4_ALL | media::EME_CODEC_WEBM_ALL;
-#else
- return media::EME_CODEC_WEBM_ALL;
-#endif
}
media::EmeConfigRule ExternalClearKeyProperties::GetRobustnessConfigRule(
diff --git a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
index f08967a61d7..224f22d4f6e 100644
--- a/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
+++ b/chromium/components/cdm/renderer/external_clear_key_key_system_properties.h
@@ -22,6 +22,8 @@ class ExternalClearKeyProperties : public media::KeySystemProperties {
std::string GetKeySystemName() const override;
bool IsSupportedInitDataType(
media::EmeInitDataType init_data_type) const override;
+ bool IsEncryptionSchemeSupported(
+ media::EncryptionMode encryption_scheme) const override;
media::SupportedCodecs GetSupportedCodecs() const override;
media::EmeConfigRule GetRobustnessConfigRule(
media::EmeMediaType media_type,
diff --git a/chromium/components/cdm/renderer/widevine_key_system_properties.cc b/chromium/components/cdm/renderer/widevine_key_system_properties.cc
index 3683fb8b573..60f4bb07d9c 100644
--- a/chromium/components/cdm/renderer/widevine_key_system_properties.cc
+++ b/chromium/components/cdm/renderer/widevine_key_system_properties.cc
@@ -4,7 +4,6 @@
#include "components/cdm/renderer/widevine_key_system_properties.h"
-#include "media/media_buildflags.h"
#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
#if defined(WIDEVINE_CDM_AVAILABLE)
@@ -39,6 +38,7 @@ Robustness ConvertRobustness(const std::string& robustness) {
} // namespace
WidevineKeySystemProperties::WidevineKeySystemProperties(
+ base::flat_set<media::EncryptionMode> supported_encryption_schemes,
media::SupportedCodecs supported_codecs,
#if defined(OS_ANDROID)
media::SupportedCodecs supported_secure_codecs,
@@ -49,7 +49,8 @@ WidevineKeySystemProperties::WidevineKeySystemProperties(
media::EmeSessionTypeSupport persistent_release_message_support,
media::EmeFeatureSupport persistent_state_support,
media::EmeFeatureSupport distinctive_identifier_support)
- : supported_codecs_(supported_codecs),
+ : supported_encryption_schemes_(std::move(supported_encryption_schemes)),
+ supported_codecs_(supported_codecs),
#if defined(OS_ANDROID)
supported_secure_codecs_(supported_secure_codecs),
#endif // defined(OS_ANDROID)
@@ -61,6 +62,8 @@ WidevineKeySystemProperties::WidevineKeySystemProperties(
distinctive_identifier_support_(distinctive_identifier_support) {
}
+WidevineKeySystemProperties::~WidevineKeySystemProperties() = default;
+
std::string WidevineKeySystemProperties::GetKeySystemName() const {
return kWidevineKeySystem;
}
@@ -72,14 +75,17 @@ bool WidevineKeySystemProperties::IsSupportedInitDataType(
// |init_data_type| x |container| pairings.
if (init_data_type == EmeInitDataType::WEBM)
return (supported_codecs_ & media::EME_CODEC_WEBM_ALL) != 0;
-#if BUILDFLAG(USE_PROPRIETARY_CODECS)
if (init_data_type == EmeInitDataType::CENC)
return (supported_codecs_ & media::EME_CODEC_MP4_ALL) != 0;
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
return false;
}
+bool WidevineKeySystemProperties::IsEncryptionSchemeSupported(
+ media::EncryptionMode encryption_scheme) const {
+ return supported_encryption_schemes_.count(encryption_scheme) != 0;
+}
+
SupportedCodecs WidevineKeySystemProperties::GetSupportedCodecs() const {
return supported_codecs_;
}
diff --git a/chromium/components/cdm/renderer/widevine_key_system_properties.h b/chromium/components/cdm/renderer/widevine_key_system_properties.h
index c758b84c144..05b88a659d0 100644
--- a/chromium/components/cdm/renderer/widevine_key_system_properties.h
+++ b/chromium/components/cdm/renderer/widevine_key_system_properties.h
@@ -5,9 +5,12 @@
#ifndef COMPONENTS_CDM_RENDERER_WIDEVINE_KEY_SYSTEM_PROPERTIES_H_
#define COMPONENTS_CDM_RENDERER_WIDEVINE_KEY_SYSTEM_PROPERTIES_H_
+#include <string>
+#include <vector>
+
+#include "base/containers/flat_set.h"
#include "build/build_config.h"
#include "media/base/key_system_properties.h"
-#include "media/media_buildflags.h"
namespace cdm {
@@ -27,6 +30,7 @@ class WidevineKeySystemProperties : public media::KeySystemProperties {
};
WidevineKeySystemProperties(
+ base::flat_set<media::EncryptionMode> supported_encryption_schemes,
media::SupportedCodecs supported_codecs,
#if defined(OS_ANDROID)
media::SupportedCodecs supported_secure_codecs,
@@ -37,10 +41,13 @@ class WidevineKeySystemProperties : public media::KeySystemProperties {
media::EmeSessionTypeSupport persistent_release_message_support,
media::EmeFeatureSupport persistent_state_support,
media::EmeFeatureSupport distinctive_identifier_support);
+ ~WidevineKeySystemProperties() override;
std::string GetKeySystemName() const override;
bool IsSupportedInitDataType(
media::EmeInitDataType init_data_type) const override;
+ bool IsEncryptionSchemeSupported(
+ media::EncryptionMode encryption_scheme) const override;
media::SupportedCodecs GetSupportedCodecs() const override;
#if defined(OS_ANDROID)
@@ -58,6 +65,7 @@ class WidevineKeySystemProperties : public media::KeySystemProperties {
media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override;
private:
+ const base::flat_set<media::EncryptionMode> supported_encryption_schemes_;
const media::SupportedCodecs supported_codecs_;
#if defined(OS_ANDROID)
const media::SupportedCodecs supported_secure_codecs_;
diff --git a/chromium/components/certificate_transparency/BUILD.gn b/chromium/components/certificate_transparency/BUILD.gn
index a2dae9e98c7..604177a7a46 100644
--- a/chromium/components/certificate_transparency/BUILD.gn
+++ b/chromium/components/certificate_transparency/BUILD.gn
@@ -4,8 +4,12 @@
static_library("certificate_transparency") {
sources = [
- "ct_policy_manager.cc",
- "ct_policy_manager.h",
+ "chrome_ct_policy_enforcer.cc",
+ "chrome_ct_policy_enforcer.h",
+ "chrome_require_ct_delegate.cc",
+ "chrome_require_ct_delegate.h",
+ "ct_known_logs.cc",
+ "ct_known_logs.h",
"features.cc",
"features.h",
"log_dns_client.cc",
@@ -25,6 +29,7 @@ static_library("certificate_transparency") {
deps = [
"//base",
"//components/base32",
+ "//components/certificate_transparency/data:ct_log_list",
"//components/prefs",
"//components/url_formatter",
"//components/url_matcher",
@@ -36,7 +41,9 @@ static_library("certificate_transparency") {
source_set("unit_tests") {
testonly = true
sources = [
- "ct_policy_manager_unittest.cc",
+ "chrome_ct_policy_enforcer_unittest.cc",
+ "chrome_require_ct_delegate_unittest.cc",
+ "ct_known_logs_unittest.cc",
"log_dns_client_unittest.cc",
"mock_log_dns_traffic.cc",
"mock_log_dns_traffic.h",
@@ -48,6 +55,7 @@ source_set("unit_tests") {
":certificate_transparency",
"//base/test:test_support",
"//components/base32",
+ "//components/certificate_transparency/data:ct_log_list",
"//components/prefs:test_support",
"//net:test_support",
"//testing/gmock",
diff --git a/chromium/components/certificate_transparency/OWNERS b/chromium/components/certificate_transparency/OWNERS
index 009e29e53fb..768b046eb7a 100644
--- a/chromium/components/certificate_transparency/OWNERS
+++ b/chromium/components/certificate_transparency/OWNERS
@@ -1,5 +1,11 @@
-eranm@chromium.org
+# Primary
rsleevi@chromium.org
+# Secondary
+file://net/OWNERS
+
+# Emeritus
+eranm@chromium.org
+
# TEAM: net-dev@chromium.org
# COMPONENT: Internals>Network>CertTrans
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc
new file mode 100644
index 00000000000..a2e2b493def
--- /dev/null
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.cc
@@ -0,0 +1,307 @@
+// 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 "components/certificate_transparency/chrome_ct_policy_enforcer.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/build_time.h"
+#include "base/callback_helpers.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "base/version.h"
+#include "components/certificate_transparency/ct_known_logs.h"
+#include "net/cert/ct_policy_status.h"
+#include "net/cert/signed_certificate_timestamp.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_certificate_net_log_param.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_parameters_callback.h"
+#include "net/log/net_log_with_source.h"
+
+using net::ct::CTPolicyCompliance;
+
+namespace certificate_transparency {
+
+namespace {
+
+// Returns true if the current build is recent enough to ensure that
+// built-in security information (e.g. CT Logs) is fresh enough.
+// TODO(eranm): Move to base or net/base
+bool IsBuildTimely() {
+ const base::Time build_time = base::GetBuildTime();
+ // We consider built-in information to be timely for 10 weeks.
+ return (base::Time::Now() - build_time).InDays() < 70 /* 10 weeks */;
+}
+
+// Returns a rounded-down months difference of |start| and |end|,
+// together with an indication of whether the last month was
+// a full month, because the range starts specified in the policy
+// are not consistent in terms of including the range start value.
+void RoundedDownMonthDifference(const base::Time& start,
+ const base::Time& end,
+ size_t* rounded_months_difference,
+ bool* has_partial_month) {
+ DCHECK(rounded_months_difference);
+ DCHECK(has_partial_month);
+ base::Time::Exploded exploded_start;
+ base::Time::Exploded exploded_expiry;
+ start.UTCExplode(&exploded_start);
+ end.UTCExplode(&exploded_expiry);
+ if (end < start) {
+ *rounded_months_difference = 0;
+ *has_partial_month = false;
+ return;
+ }
+
+ *has_partial_month = true;
+ uint32_t month_diff = (exploded_expiry.year - exploded_start.year) * 12 +
+ (exploded_expiry.month - exploded_start.month);
+ if (exploded_expiry.day_of_month < exploded_start.day_of_month)
+ --month_diff;
+ else if (exploded_expiry.day_of_month == exploded_start.day_of_month)
+ *has_partial_month = false;
+
+ *rounded_months_difference = month_diff;
+}
+
+const char* CTPolicyComplianceToString(CTPolicyCompliance status) {
+ switch (status) {
+ case CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS:
+ return "COMPLIES_VIA_SCTS";
+ case CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS:
+ return "NOT_ENOUGH_SCTS";
+ case CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS:
+ return "NOT_DIVERSE_SCTS";
+ case CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY:
+ return "BUILD_NOT_TIMELY";
+ case CTPolicyCompliance::CT_POLICY_COMPLIANCE_DETAILS_NOT_AVAILABLE:
+ case CTPolicyCompliance::CT_POLICY_MAX:
+ NOTREACHED();
+ return "unknown";
+ }
+
+ NOTREACHED();
+ return "unknown";
+}
+
+std::unique_ptr<base::Value> NetLogCertComplianceCheckResultCallback(
+ net::X509Certificate* cert,
+ bool build_timely,
+ CTPolicyCompliance compliance,
+ net::NetLogCaptureMode capture_mode) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->Set("certificate",
+ net::NetLogX509CertificateCallback(cert, capture_mode));
+ dict->SetBoolean("build_timely", build_timely);
+ dict->SetString("ct_compliance_status",
+ CTPolicyComplianceToString(compliance));
+ return std::move(dict);
+}
+
+// Evaluates against the policy specified at
+// https://sites.google.com/a/chromium.org/dev/Home/chromium-security/root-ca-policy/EVCTPlanMay2015edition.pdf?attredirects=0
+CTPolicyCompliance CheckCTPolicyCompliance(
+ const net::X509Certificate& cert,
+ const net::ct::SCTList& verified_scts) {
+ // Cert is outside the bounds of parsable; reject it.
+ if (cert.valid_start().is_null() || cert.valid_expiry().is_null() ||
+ cert.valid_start().is_max() || cert.valid_expiry().is_max()) {
+ return CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+ }
+
+ // Scan for the earliest SCT. This is used to determine whether to enforce
+ // log diversity requirements, as well as whether to enforce whether or not
+ // a log was qualified or pending qualification at time of issuance (in the
+ // case of embedded SCTs). It's acceptable to ignore the origin of the SCT,
+ // because SCTs delivered via OCSP/TLS extension will cover the full
+ // certificate, which necessarily will exist only after the precertificate
+ // has been logged and the actual certificate issued.
+ // Note: Here, issuance date is defined as the earliest of all SCTs, rather
+ // than the latest of embedded SCTs, in order to give CAs the benefit of
+ // the doubt in the event a log is revoked in the midst of processing
+ // a precertificate and issuing the certificate.
+ base::Time issuance_date = base::Time::Max();
+ for (const auto& sct : verified_scts) {
+ base::Time unused;
+ if (IsLogDisqualified(sct->log_id, &unused))
+ continue;
+ issuance_date = std::min(sct->timestamp, issuance_date);
+ }
+
+ bool has_valid_google_sct = false;
+ bool has_valid_nongoogle_sct = false;
+ bool has_valid_embedded_sct = false;
+ bool has_valid_nonembedded_sct = false;
+ bool has_embedded_google_sct = false;
+ bool has_embedded_nongoogle_sct = false;
+ std::vector<base::StringPiece> embedded_log_ids;
+ for (const auto& sct : verified_scts) {
+ base::Time disqualification_date;
+ bool is_disqualified =
+ IsLogDisqualified(sct->log_id, &disqualification_date);
+ if (is_disqualified &&
+ sct->origin != net::ct::SignedCertificateTimestamp::SCT_EMBEDDED) {
+ // For OCSP and TLS delivered SCTs, only SCTs that are valid at the
+ // time of check are accepted.
+ continue;
+ }
+
+ if (IsLogOperatedByGoogle(sct->log_id)) {
+ has_valid_google_sct |= !is_disqualified;
+ if (sct->origin == net::ct::SignedCertificateTimestamp::SCT_EMBEDDED)
+ has_embedded_google_sct = true;
+ } else {
+ has_valid_nongoogle_sct |= !is_disqualified;
+ if (sct->origin == net::ct::SignedCertificateTimestamp::SCT_EMBEDDED)
+ has_embedded_nongoogle_sct = true;
+ }
+ if (sct->origin != net::ct::SignedCertificateTimestamp::SCT_EMBEDDED) {
+ has_valid_nonembedded_sct = true;
+ } else {
+ has_valid_embedded_sct |= !is_disqualified;
+ // If the log is disqualified, it only counts towards quorum if
+ // the certificate was issued before the log was disqualified, and the
+ // SCT was obtained before the log was disqualified.
+ if (!is_disqualified || (issuance_date < disqualification_date &&
+ sct->timestamp < disqualification_date)) {
+ embedded_log_ids.push_back(sct->log_id);
+ }
+ }
+ }
+
+ // Option 1:
+ // An SCT presented via the TLS extension OR embedded within a stapled OCSP
+ // response is from a log qualified at time of check;
+ // AND there is at least one SCT from a Google Log that is qualified at
+ // time of check, presented via any method;
+ // AND there is at least one SCT from a non-Google Log that is qualified
+ // at the time of check, presented via any method.
+ //
+ // Note: Because SCTs embedded via TLS or OCSP can be updated on the fly,
+ // the issuance date is irrelevant, as any policy changes can be
+ // accomodated.
+ if (has_valid_nonembedded_sct && has_valid_google_sct &&
+ has_valid_nongoogle_sct) {
+ return CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
+ }
+ // Note: If has_valid_nonembedded_sct was true, but Option 2 isn't met,
+ // then the result will be that there weren't diverse enough SCTs, as that
+ // the only other way for the conditional above to fail). Because Option 1
+ // has the diversity requirement, it's implicitly a minimum number of SCTs
+ // (specifically, 2), but that's not explicitly specified in the policy.
+
+ // Option 2:
+ // There is at least one embedded SCT from a log qualified at the time of
+ // check ...
+ if (!has_valid_embedded_sct) {
+ // Under Option 2, there weren't enough SCTs, and potentially under
+ // Option 1, there weren't diverse enough SCTs. Try to signal the error
+ // that is most easily fixed.
+ return has_valid_nonembedded_sct
+ ? CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS
+ : CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+ }
+
+ // ... AND there is at least one embedded SCT from a Google Log once or
+ // currently qualified;
+ // AND there is at least one embedded SCT from a non-Google Log once or
+ // currently qualified;
+ // ...
+ //
+ // Note: This policy language is only enforced after the below issuance
+ // date, as that's when the diversity policy first came into effect for
+ // SCTs embedded in certificates.
+ // The date when diverse SCTs requirement is effective from.
+ // 2015-07-01 00:00:00 UTC.
+ const base::Time kDiverseSCTRequirementStartDate =
+ base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1435708800);
+ if (issuance_date >= kDiverseSCTRequirementStartDate &&
+ !(has_embedded_google_sct && has_embedded_nongoogle_sct)) {
+ // Note: This also covers the case for non-embedded SCTs, as it's only
+ // possible to reach here if both sets are not diverse enough.
+ return CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS;
+ }
+
+ size_t lifetime_in_months = 0;
+ bool has_partial_month = false;
+ RoundedDownMonthDifference(cert.valid_start(), cert.valid_expiry(),
+ &lifetime_in_months, &has_partial_month);
+
+ // ... AND the certificate embeds SCTs from AT LEAST the number of logs
+ // once or currently qualified shown in Table 1 of the CT Policy.
+ size_t num_required_embedded_scts = 5;
+ if (lifetime_in_months > 39 ||
+ (lifetime_in_months == 39 && has_partial_month)) {
+ num_required_embedded_scts = 5;
+ } else if (lifetime_in_months > 27 ||
+ (lifetime_in_months == 27 && has_partial_month)) {
+ num_required_embedded_scts = 4;
+ } else if (lifetime_in_months >= 15) {
+ num_required_embedded_scts = 3;
+ } else {
+ num_required_embedded_scts = 2;
+ }
+
+ // Sort the embedded log IDs and remove duplicates, so that only a single
+ // SCT from each log is accepted. This is to handle the case where a given
+ // log returns different SCTs for the same precertificate (which is
+ // permitted, but advised against).
+ std::sort(embedded_log_ids.begin(), embedded_log_ids.end());
+ auto sorted_end =
+ std::unique(embedded_log_ids.begin(), embedded_log_ids.end());
+ size_t num_embedded_scts =
+ std::distance(embedded_log_ids.begin(), sorted_end);
+
+ if (num_embedded_scts >= num_required_embedded_scts)
+ return CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS;
+
+ // Under Option 2, there weren't enough SCTs, and potentially under Option
+ // 1, there weren't diverse enough SCTs. Try to signal the error that is
+ // most easily fixed.
+ return has_valid_nonembedded_sct
+ ? CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS
+ : CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
+}
+
+} // namespace
+
+CTPolicyCompliance ChromeCTPolicyEnforcer::CheckCompliance(
+ net::X509Certificate* cert,
+ const net::ct::SCTList& verified_scts,
+ const net::NetLogWithSource& net_log) {
+ // If the build is not timely, no certificate is considered compliant
+ // with CT policy. The reasoning is that, for example, a log might
+ // have been pulled and is no longer considered valid; thus, a client
+ // needs up-to-date information about logs to consider certificates to
+ // be compliant with policy.
+ bool build_timely = IsBuildTimely();
+ CTPolicyCompliance compliance;
+ if (!build_timely) {
+ compliance = CTPolicyCompliance::CT_POLICY_BUILD_NOT_TIMELY;
+ } else {
+ compliance = CheckCTPolicyCompliance(*cert, verified_scts);
+ }
+
+ net::NetLogParametersCallback net_log_callback =
+ base::BindRepeating(&NetLogCertComplianceCheckResultCallback,
+ base::Unretained(cert), build_timely, compliance);
+
+ net_log.AddEvent(net::NetLogEventType::CERT_CT_COMPLIANCE_CHECKED,
+ net_log_callback);
+
+ return compliance;
+}
+
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h
new file mode 100644
index 00000000000..f61ff0d0564
--- /dev/null
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_CT_POLICY_ENFORCER_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_CT_POLICY_ENFORCER_H_
+
+#include "net/cert/ct_policy_enforcer.h"
+
+namespace certificate_transparency {
+
+// A CTPolicyEnforcer that enforces the "Certificate Transparency in Chrome"
+// policies detailed at
+// https://github.com/chromium/ct-policy/blob/master/ct_policy.md
+//
+// This should only be used when there is a reliable, rapid update mechanism
+// for the set of known, qualified logs - either through a reliable binary
+// updating mechanism or through out-of-band delivery. See
+// //net/docs/certificate-transparency.md for more details.
+class ChromeCTPolicyEnforcer : public net::CTPolicyEnforcer {
+ public:
+ ChromeCTPolicyEnforcer() = default;
+ ~ChromeCTPolicyEnforcer() override = default;
+
+ net::ct::CTPolicyCompliance CheckCompliance(
+ net::X509Certificate* cert,
+ const net::ct::SCTList& verified_scts,
+ const net::NetLogWithSource& net_log) override;
+};
+
+} // namespace certificate_transparency
+
+#endif // COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_CT_POLICY_ENFORCER_H_
diff --git a/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
new file mode 100644
index 00000000000..8a5d48eaaf7
--- /dev/null
+++ b/chromium/components/certificate_transparency/chrome_ct_policy_enforcer_unittest.cc
@@ -0,0 +1,452 @@
+// 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 "components/certificate_transparency/chrome_ct_policy_enforcer.h"
+
+#include <memory>
+#include <string>
+
+#include "base/stl_util.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "crypto/rsa_private_key.h"
+#include "crypto/sha2.h"
+#include "net/cert/ct_policy_status.h"
+#include "net/cert/ct_verify_result.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "net/log/net_log_with_source.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/ct_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::ct::CTPolicyCompliance;
+using net::ct::SCTList;
+using net::ct::SignedCertificateTimestamp;
+using net::NetLogWithSource;
+using net::X509Certificate;
+
+namespace certificate_transparency {
+
+namespace {
+
+const char kGoogleAviatorLogID[] =
+ "\x68\xf6\x98\xf8\x1f\x64\x82\xbe\x3a\x8c\xee\xb9\x28\x1d\x4c\xfc\x71\x51"
+ "\x5d\x67\x93\xd4\x44\xd1\x0a\x67\xac\xbb\x4f\x4f\xfb\xc4";
+static_assert(base::size(kGoogleAviatorLogID) - 1 == crypto::kSHA256Length,
+ "Incorrect log ID length.");
+
+class ChromeCTPolicyEnforcerTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ policy_enforcer_.reset(new ChromeCTPolicyEnforcer);
+
+ std::string der_test_cert(net::ct::GetDerEncodedX509Cert());
+ chain_ = X509Certificate::CreateFromBytes(der_test_cert.data(),
+ der_test_cert.size());
+ ASSERT_TRUE(chain_.get());
+ google_log_id_ = std::string(kGoogleAviatorLogID, crypto::kSHA256Length);
+ non_google_log_id_.assign(crypto::kSHA256Length, 1);
+ }
+
+ void FillListWithSCTsOfOrigin(
+ SignedCertificateTimestamp::Origin desired_origin,
+ size_t num_scts,
+ const std::vector<std::string>& desired_log_keys,
+ bool timestamp_past_enforcement_date,
+ SCTList* verified_scts) {
+ for (size_t i = 0; i < num_scts; ++i) {
+ scoped_refptr<SignedCertificateTimestamp> sct(
+ new SignedCertificateTimestamp());
+ sct->origin = desired_origin;
+ if (i < desired_log_keys.size())
+ sct->log_id = desired_log_keys[i];
+ else
+ sct->log_id = std::string(crypto::kSHA256Length, static_cast<char>(i));
+
+ if (timestamp_past_enforcement_date) {
+ EXPECT_TRUE(base::Time::FromUTCExploded({2015, 8, 0, 15, 0, 0, 0, 0},
+ &sct->timestamp));
+ } else {
+ EXPECT_TRUE(base::Time::FromUTCExploded({2015, 6, 0, 15, 0, 0, 0, 0},
+ &sct->timestamp));
+ }
+
+ verified_scts->push_back(sct);
+ }
+ }
+
+ void AddDisqualifiedLogSCT(SignedCertificateTimestamp::Origin desired_origin,
+ bool timestamp_after_disqualification_date,
+ SCTList* verified_scts) {
+ static const char kCertlyLogID[] =
+ "\xcd\xb5\x17\x9b\x7f\xc1\xc0\x46\xfe\xea\x31\x13\x6a\x3f\x8f\x00\x2e"
+ "\x61\x82\xfa\xf8\x89\x6f\xec\xc8\xb2\xf5\xb5\xab\x60\x49\x00";
+ static_assert(base::size(kCertlyLogID) - 1 == crypto::kSHA256Length,
+ "Incorrect log ID length.");
+
+ scoped_refptr<SignedCertificateTimestamp> sct(
+ new SignedCertificateTimestamp());
+ sct->origin = desired_origin;
+ sct->log_id = std::string(kCertlyLogID, crypto::kSHA256Length);
+ if (timestamp_after_disqualification_date) {
+ EXPECT_TRUE(base::Time::FromUTCExploded({2016, 4, 0, 16, 0, 0, 0, 0},
+ &sct->timestamp));
+ } else {
+ EXPECT_TRUE(base::Time::FromUTCExploded({2016, 4, 0, 1, 0, 0, 0, 0},
+ &sct->timestamp));
+ }
+
+ verified_scts->push_back(sct);
+ }
+
+ void FillListWithSCTsOfOrigin(
+ SignedCertificateTimestamp::Origin desired_origin,
+ size_t num_scts,
+ SCTList* verified_scts) {
+ std::vector<std::string> desired_log_ids;
+ desired_log_ids.push_back(google_log_id_);
+ FillListWithSCTsOfOrigin(desired_origin, num_scts, desired_log_ids, true,
+ verified_scts);
+ }
+
+ base::Time CreateTime(const base::Time::Exploded& exploded) {
+ base::Time result;
+ if (!base::Time::FromUTCExploded(exploded, &result)) {
+ ADD_FAILURE() << "Failed FromUTCExploded";
+ }
+ return result;
+ }
+
+ protected:
+ std::unique_ptr<net::CTPolicyEnforcer> policy_enforcer_;
+ scoped_refptr<X509Certificate> chain_;
+ std::string google_log_id_;
+ std::string non_google_log_id_;
+};
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ DoesNotConformToCTPolicyNotEnoughDiverseSCTsAllGoogle) {
+ SCTList scts;
+ std::vector<std::string> desired_log_ids(2, google_log_id_);
+
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ desired_log_ids.size(), desired_log_ids, true,
+ &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ DoesNotConformToCTPolicyNotEnoughDiverseSCTsAllNonGoogle) {
+ SCTList scts;
+ std::vector<std::string> desired_log_ids(2, non_google_log_id_);
+
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ desired_log_ids.size(), desired_log_ids, true,
+ &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ ConformsToCTPolicyIfSCTBeforeEnforcementDate) {
+ SCTList scts;
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ // All 5 SCTs will be from non-Google logs.
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 5,
+ std::vector<std::string>(), false, &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest, ConformsToCTPolicyWithNonEmbeddedSCTs) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 2, &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest, ConformsToCTPolicyWithEmbeddedSCTs) {
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 5, &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ ConformsToCTPolicyWithPooledNonEmbeddedSCTs) {
+ SCTList scts;
+ std::vector<std::string> desired_logs;
+
+ // One Google log, delivered via OCSP.
+ desired_logs.clear();
+ desired_logs.push_back(google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ // One non-Google log, delivered via TLS.
+ desired_logs.clear();
+ desired_logs.push_back(non_google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest, ConformsToCTPolicyWithPooledEmbeddedSCTs) {
+ SCTList scts;
+ std::vector<std::string> desired_logs;
+
+ // One Google log, delivered embedded.
+ desired_logs.clear();
+ desired_logs.push_back(google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ // One non-Google log, delivered via OCSP.
+ desired_logs.clear();
+ desired_logs.push_back(non_google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_OCSP_RESPONSE,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughSCTs) {
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 2, &scts);
+
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest, DoesNotConformToCTPolicyNotEnoughFreshSCTs) {
+ SCTList scts;
+
+ // The results should be the same before and after disqualification,
+ // regardless of the delivery method.
+
+ // SCT from before disqualification.
+ scts.clear();
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 1, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ false, &scts);
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+
+ // SCT from after disqualification.
+ scts.clear();
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 1, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ true, &scts);
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+
+ // Embedded SCT from before disqualification.
+ scts.clear();
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 1, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, false, &scts);
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+
+ // Embedded SCT from after disqualification.
+ scts.clear();
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_FROM_TLS_EXTENSION,
+ 1, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_DIVERSE_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ ConformsWithDisqualifiedLogBeforeDisqualificationDate) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, false, &scts);
+
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ DoesNotConformWithDisqualifiedLogAfterDisqualificationDate) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
+
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ DoesNotConformWithIssuanceDateAfterDisqualificationDate) {
+ SCTList scts;
+ AddDisqualifiedLogSCT(SignedCertificateTimestamp::SCT_EMBEDDED, true, &scts);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, 4, &scts);
+ // Make sure all SCTs are after the disqualification date.
+ for (size_t i = 1; i < scts.size(); ++i)
+ scts[i]->timestamp = scts[0]->timestamp;
+
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ DoesNotConformToCTPolicyNotEnoughUniqueEmbeddedLogs) {
+ SCTList scts;
+ std::vector<std::string> desired_logs;
+
+ // One Google Log.
+ desired_logs.clear();
+ desired_logs.push_back(google_log_id_);
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ // Two distinct non-Google logs.
+ desired_logs.clear();
+ desired_logs.push_back(std::string(crypto::kSHA256Length, 'A'));
+ desired_logs.push_back(std::string(crypto::kSHA256Length, 'B'));
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ // Two unique SCTs from the same non-Google log.
+ desired_logs.clear();
+ desired_logs.push_back(std::string(crypto::kSHA256Length, 'C'));
+ desired_logs.push_back(std::string(crypto::kSHA256Length, 'C'));
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ desired_logs.size(), desired_logs, true, &scts);
+
+ // |chain_| is valid for 10 years - over 121 months - so requires 5 SCTs.
+ // However, there are only 4 SCTs are from distinct logs.
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(chain_.get(), scts,
+ NetLogWithSource()));
+}
+
+TEST_F(ChromeCTPolicyEnforcerTest,
+ ConformsToPolicyExactNumberOfSCTsForValidityPeriod) {
+ std::unique_ptr<crypto::RSAPrivateKey> private_key(
+ crypto::RSAPrivateKey::Create(1024));
+ ASSERT_TRUE(private_key);
+
+ // Test multiple validity periods
+ base::Time time_2015_3_0_25_11_25_0_0 =
+ CreateTime({2015, 3, 0, 25, 11, 25, 0, 0});
+
+ base::Time time_2016_6_0_6_11_25_0_0 =
+ CreateTime({2016, 6, 0, 6, 11, 25, 0, 0});
+
+ base::Time time_2016_6_0_25_11_25_0_0 =
+ CreateTime({2016, 6, 0, 25, 11, 25, 0, 0});
+
+ base::Time time_2016_6_0_27_11_25_0_0 =
+ CreateTime({2016, 6, 0, 27, 11, 25, 0, 0});
+
+ base::Time time_2017_6_0_25_11_25_0_0 =
+ CreateTime({2017, 6, 0, 25, 11, 25, 0, 0});
+
+ base::Time time_2017_6_0_28_11_25_0_0 =
+ CreateTime({2017, 6, 0, 28, 11, 25, 0, 0});
+
+ base::Time time_2018_6_0_25_11_25_0_0 =
+ CreateTime({2018, 6, 0, 25, 11, 25, 0, 0});
+
+ base::Time time_2018_6_0_27_11_25_0_0 =
+ CreateTime({2018, 6, 0, 27, 11, 25, 0, 0});
+
+ const struct TestData {
+ base::Time validity_start;
+ base::Time validity_end;
+ size_t scts_required;
+ } kTestData[] = {{// Cert valid for -14 months (nonsensical), needs 2 SCTs.
+ time_2016_6_0_6_11_25_0_0, time_2015_3_0_25_11_25_0_0, 2},
+ {// Cert valid for 14 months, needs 2 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2016_6_0_6_11_25_0_0, 2},
+ {// Cert valid for exactly 15 months, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2016_6_0_25_11_25_0_0, 3},
+ {// Cert valid for over 15 months, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2016_6_0_27_11_25_0_0, 3},
+ {// Cert valid for exactly 27 months, needs 3 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2017_6_0_25_11_25_0_0, 3},
+ {// Cert valid for over 27 months, needs 4 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2017_6_0_28_11_25_0_0, 4},
+ {// Cert valid for exactly 39 months, needs 4 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2018_6_0_25_11_25_0_0, 4},
+ {// Cert valid for over 39 months, needs 5 SCTs.
+ time_2015_3_0_25_11_25_0_0, time_2018_6_0_27_11_25_0_0, 5}};
+
+ for (size_t i = 0; i < base::size(kTestData); ++i) {
+ SCOPED_TRACE(i);
+ const base::Time& start = kTestData[i].validity_start;
+ const base::Time& end = kTestData[i].validity_end;
+ size_t required_scts = kTestData[i].scts_required;
+
+ // Create a self-signed certificate with exactly the validity period.
+ std::string cert_data;
+ ASSERT_TRUE(net::x509_util::CreateSelfSignedCert(
+ private_key->key(), net::x509_util::DIGEST_SHA256, "CN=test",
+ i * 10 + required_scts, start, end, &cert_data));
+ scoped_refptr<X509Certificate> cert(
+ X509Certificate::CreateFromBytes(cert_data.data(), cert_data.size()));
+ ASSERT_TRUE(cert);
+
+ for (size_t i = 0; i < required_scts - 1; ++i) {
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED, i,
+ std::vector<std::string>(), false, &scts);
+ EXPECT_EQ(CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS,
+ policy_enforcer_->CheckCompliance(cert.get(), scts,
+ NetLogWithSource()))
+ << " for: " << (end - start).InDays() << " and " << required_scts
+ << " scts=" << scts.size() << " i=" << i;
+ }
+ SCTList scts;
+ FillListWithSCTsOfOrigin(SignedCertificateTimestamp::SCT_EMBEDDED,
+ required_scts, std::vector<std::string>(), false,
+ &scts);
+ EXPECT_EQ(
+ CTPolicyCompliance::CT_POLICY_COMPLIES_VIA_SCTS,
+ policy_enforcer_->CheckCompliance(cert.get(), scts, NetLogWithSource()))
+ << " for: " << (end - start).InDays() << " and " << required_scts
+ << " scts=" << scts.size();
+ }
+}
+
+} // namespace
+
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/ct_policy_manager.cc b/chromium/components/certificate_transparency/chrome_require_ct_delegate.cc
index d896d336254..c75aec77af0 100644
--- a/chromium/components/certificate_transparency/ct_policy_manager.cc
+++ b/chromium/components/certificate_transparency/chrome_require_ct_delegate.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/certificate_transparency/ct_policy_manager.h"
+#include "components/certificate_transparency/chrome_require_ct_delegate.h"
#include <algorithm>
#include <iterator>
@@ -161,111 +161,67 @@ bool AreCertsSameOrganization(const net::RDNSequence& leaf_rdn_sequence,
} // namespace
-class CTPolicyManager::CTDelegate
- : public net::TransportSecurityState::RequireCTDelegate {
- public:
- explicit CTDelegate();
- ~CTDelegate() override = default;
-
- // Updates the CTDelegate to require CT
- // for |required_hosts|, and exclude |excluded_hosts| from CT policies.
- void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis);
-
- // RequireCTDelegate implementation
- // Called on the network task runner.
- CTRequirementLevel IsCTRequiredForHost(
- const std::string& hostname,
- const net::X509Certificate* chain,
- const net::HashValueVector& hashes) override;
-
- private:
- struct Filter {
- bool ct_required = false;
- bool match_subdomains = false;
- size_t host_length = 0;
- };
-
- // Returns true if a policy for |hostname| is found, setting
- // |*ct_required| to indicate whether or not Certificate Transparency is
- // required for the host.
- bool MatchHostname(const std::string& hostname, bool* ct_required) const;
-
- // Returns true if a policy for |chain|, which contains the SPKI hashes
- // |hashes|, is found, setting |*ct_required| to indicate whether or not
- // Certificate Transparency is required for the certificate.
- bool MatchSPKI(const net::X509Certificate* chain,
- const net::HashValueVector& hashes,
- bool* ct_required) const;
-
- // Updates the |url_matcher_| to
- // require CT for |required_hosts| and exclude |excluded_hosts|, both
- // of which are Lists of Strings which are URLBlacklist filters, and
- // updates |excluded_spkis| and |excluded_legacy_spkis| to exclude CT for
- // those SPKIs, which are encoded as strings using net::HashValue::ToString.
- void Update(const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis);
-
- // Parses the filters from |host_patterns|, adding them as filters to
- // |filters_| (with |ct_required| indicating whether or not CT is required
- // for that host), and updating |*conditions| with the corresponding
- // URLMatcher::Conditions to match the host.
- void AddFilters(bool ct_required,
- const std::vector<std::string>& host_patterns,
- url_matcher::URLMatcherConditionSet::Vector* conditions);
-
- // Parses the SPKIs from |list|, setting |*hashes| to the sorted set of all
- // valid SPKIs.
- void ParseSpkiHashes(const std::vector<std::string> list,
- net::HashValueVector* hashes) const;
-
- // Returns true if |lhs| has greater precedence than |rhs|.
- bool FilterTakesPrecedence(const Filter& lhs, const Filter& rhs) const;
-
- std::unique_ptr<url_matcher::URLMatcher> url_matcher_;
- url_matcher::URLMatcherConditionSet::ID next_id_;
- std::map<url_matcher::URLMatcherConditionSet::ID, Filter> filters_;
-
- // Both SPKI lists are sorted.
- net::HashValueVector spkis_;
- net::HashValueVector legacy_spkis_;
-
- DISALLOW_COPY_AND_ASSIGN(CTDelegate);
-};
+ChromeRequireCTDelegate::ChromeRequireCTDelegate()
+ : url_matcher_(std::make_unique<url_matcher::URLMatcher>()), next_id_(0) {}
-CTPolicyManager::CTDelegate::CTDelegate()
- : url_matcher_(new url_matcher::URLMatcher), next_id_(0) {}
-
-void CTPolicyManager::CTDelegate::UpdateCTPolicies(
- const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis) {
- Update(required_hosts, excluded_hosts, excluded_spkis, excluded_legacy_spkis);
-}
+ChromeRequireCTDelegate::~ChromeRequireCTDelegate() {}
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel
-CTPolicyManager::CTDelegate::IsCTRequiredForHost(
+ChromeRequireCTDelegate::IsCTRequiredForHost(
const std::string& hostname,
const net::X509Certificate* chain,
- const net::HashValueVector& hashes) {
-
+ const net::HashValueVector& spki_hashes) {
bool ct_required = false;
if (MatchHostname(hostname, &ct_required) ||
- MatchSPKI(chain, hashes, &ct_required)) {
+ MatchSPKI(chain, spki_hashes, &ct_required)) {
return ct_required ? CTRequirementLevel::REQUIRED
: CTRequirementLevel::NOT_REQUIRED;
}
+ // Compute >= 2018-05-01, rather than deal with possible fractional
+ // seconds.
+ const base::Time kMay_1_2018 =
+ base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1525132800);
+ if (chain->valid_start() >= kMay_1_2018)
+ return CTRequirementLevel::REQUIRED;
+
return CTRequirementLevel::DEFAULT;
}
-bool CTPolicyManager::CTDelegate::MatchHostname(const std::string& hostname,
- bool* ct_required) const {
+void ChromeRequireCTDelegate::UpdateCTPolicies(
+ const std::vector<std::string>& required_hosts,
+ const std::vector<std::string>& excluded_hosts,
+ const std::vector<std::string>& excluded_spkis,
+ const std::vector<std::string>& excluded_legacy_spkis) {
+ url_matcher_ = std::make_unique<url_matcher::URLMatcher>();
+ filters_.clear();
+ next_id_ = 0;
+
+ url_matcher::URLMatcherConditionSet::Vector all_conditions;
+ AddFilters(true, required_hosts, &all_conditions);
+ AddFilters(false, excluded_hosts, &all_conditions);
+
+ url_matcher_->AddConditionSets(all_conditions);
+
+ ParseSpkiHashes(excluded_spkis, &spkis_);
+ ParseSpkiHashes(excluded_legacy_spkis, &legacy_spkis_);
+
+ // Filter out SPKIs that aren't for legacy CAs.
+ legacy_spkis_.erase(
+ std::remove_if(legacy_spkis_.begin(), legacy_spkis_.end(),
+ [](const net::HashValue& hash) {
+ if (!net::IsLegacyPubliclyTrustedCA(hash)) {
+ LOG(ERROR) << "Non-legacy SPKI configured "
+ << hash.ToString();
+ return true;
+ }
+ return false;
+ }),
+ legacy_spkis_.end());
+}
+
+bool ChromeRequireCTDelegate::MatchHostname(const std::string& hostname,
+ bool* ct_required) const {
if (url_matcher_->IsEmpty())
return false;
@@ -301,9 +257,9 @@ bool CTPolicyManager::CTDelegate::MatchHostname(const std::string& hostname,
return true;
}
-bool CTPolicyManager::CTDelegate::MatchSPKI(const net::X509Certificate* chain,
- const net::HashValueVector& hashes,
- bool* ct_required) const {
+bool ChromeRequireCTDelegate::MatchSPKI(const net::X509Certificate* chain,
+ const net::HashValueVector& hashes,
+ bool* ct_required) const {
// Try to scan legacy SPKIs first, if any, since they will only require
// comparing hash values.
if (!legacy_spkis_.empty()) {
@@ -379,39 +335,7 @@ bool CTPolicyManager::CTDelegate::MatchSPKI(const net::X509Certificate* chain,
return false;
}
-void CTPolicyManager::CTDelegate::Update(
- const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis) {
- url_matcher_.reset(new url_matcher::URLMatcher);
- filters_.clear();
- next_id_ = 0;
-
- url_matcher::URLMatcherConditionSet::Vector all_conditions;
- AddFilters(true, required_hosts, &all_conditions);
- AddFilters(false, excluded_hosts, &all_conditions);
-
- url_matcher_->AddConditionSets(all_conditions);
-
- ParseSpkiHashes(excluded_spkis, &spkis_);
- ParseSpkiHashes(excluded_legacy_spkis, &legacy_spkis_);
-
- // Filter out SPKIs that aren't for legacy CAs.
- legacy_spkis_.erase(
- std::remove_if(legacy_spkis_.begin(), legacy_spkis_.end(),
- [](const net::HashValue& hash) {
- if (!net::IsLegacyPubliclyTrustedCA(hash)) {
- LOG(ERROR) << "Non-legacy SPKI configured "
- << hash.ToString();
- return true;
- }
- return false;
- }),
- legacy_spkis_.end());
-}
-
-void CTPolicyManager::CTDelegate::AddFilters(
+void ChromeRequireCTDelegate::AddFilters(
bool ct_required,
const std::vector<std::string>& hosts,
url_matcher::URLMatcherConditionSet::Vector* conditions) {
@@ -472,11 +396,11 @@ void CTPolicyManager::CTDelegate::AddFilters(
}
}
-void CTPolicyManager::CTDelegate::ParseSpkiHashes(
- const std::vector<std::string> list,
+void ChromeRequireCTDelegate::ParseSpkiHashes(
+ const std::vector<std::string> spki_list,
net::HashValueVector* hashes) const {
hashes->clear();
- for (const auto& value : list) {
+ for (const auto& value : spki_list) {
net::HashValue hash;
if (!hash.FromString(value)) {
continue;
@@ -486,9 +410,8 @@ void CTPolicyManager::CTDelegate::ParseSpkiHashes(
std::sort(hashes->begin(), hashes->end());
}
-bool CTPolicyManager::CTDelegate::FilterTakesPrecedence(
- const Filter& lhs,
- const Filter& rhs) const {
+bool ChromeRequireCTDelegate::FilterTakesPrecedence(const Filter& lhs,
+ const Filter& rhs) const {
if (lhs.match_subdomains != rhs.match_subdomains)
return !lhs.match_subdomains; // Prefer the more explicit policy.
@@ -501,21 +424,4 @@ bool CTPolicyManager::CTDelegate::FilterTakesPrecedence(
return false;
}
-CTPolicyManager::CTPolicyManager() : delegate_(new CTDelegate()) {}
-
-CTPolicyManager::~CTPolicyManager() {}
-
-void CTPolicyManager::UpdateCTPolicies(
- const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis) {
- delegate_->UpdateCTPolicies(required_hosts, excluded_hosts, excluded_spkis,
- excluded_legacy_spkis);
-}
-
-net::TransportSecurityState::RequireCTDelegate* CTPolicyManager::GetDelegate() {
- return delegate_.get();
-}
-
} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/chrome_require_ct_delegate.h b/chromium/components/certificate_transparency/chrome_require_ct_delegate.h
new file mode 100644
index 00000000000..3b947f5b455
--- /dev/null
+++ b/chromium/components/certificate_transparency/chrome_require_ct_delegate.h
@@ -0,0 +1,107 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_REQUIRE_CT_DELEGATE_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_REQUIRE_CT_DELEGATE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/url_matcher/url_matcher.h"
+#include "net/base/hash_value.h"
+#include "net/http/transport_security_state.h"
+
+namespace net {
+class X509Certificate;
+} // namespace net
+
+namespace certificate_transparency {
+
+// ChromeRequireCTDelegate implements the policies used by Chrome to determine
+// when to require Certificate Transparency for a host or certificate. Combined
+// with ChromeCTPolicyEnforcer, these two classes implement the
+// "Certificate Transparency in Chrome" policy from
+// https://goo.gl/chrome/ct-policy - PolicyEnforcer imposing the policies on
+// the SCTs to determine whether or not a certificate complies, and
+// RequireCTDelegate to determine whether or not compliance is required for the
+// connection to succeed.
+//
+// To support Enterprise configuration, additional requirements or exceptions
+// can be provided via |UpdateCTPolicies()|, which uses the configuration
+// syntax documented in pref_names.h for each of the options.
+class ChromeRequireCTDelegate
+ : public net::TransportSecurityState::RequireCTDelegate {
+ public:
+ explicit ChromeRequireCTDelegate();
+ ~ChromeRequireCTDelegate() override;
+
+ // RequireCTDelegate implementation
+ CTRequirementLevel IsCTRequiredForHost(
+ const std::string& hostname,
+ const net::X509Certificate* chain,
+ const net::HashValueVector& spki_hashes) override;
+
+ // Updates the CTDelegate to require CT for |required_hosts|, and exclude
+ // |excluded_hosts| from CT policies. In addtion, this method updates
+ // |excluded_spkis| and |excluded_legacy_spkis| intended for use within an
+ // Enterprise (see https://crbug.com/824184).
+ void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
+ const std::vector<std::string>& excluded_hosts,
+ const std::vector<std::string>& excluded_spkis,
+ const std::vector<std::string>& excluded_legacy_spkis);
+
+ private:
+ struct Filter {
+ bool ct_required = false;
+ bool match_subdomains = false;
+ size_t host_length = 0;
+ };
+
+ // Returns true if a policy for |hostname| is found, setting
+ // |*ct_required| to indicate whether or not Certificate Transparency is
+ // required for the host.
+ bool MatchHostname(const std::string& hostname, bool* ct_required) const;
+
+ // Returns true if a policy for |chain|, which contains the SPKI hashes
+ // |hashes|, is found, setting |*ct_required| to indicate whether or not
+ // Certificate Transparency is required for the certificate.
+ bool MatchSPKI(const net::X509Certificate* chain,
+ const net::HashValueVector& hashes,
+ bool* ct_required) const;
+
+ // Parses the filters from |host_patterns|, adding them as filters to
+ // |filters_| (with |ct_required| indicating whether or not CT is required
+ // for that host), and updating |*conditions| with the corresponding
+ // URLMatcher::Conditions to match the host.
+ void AddFilters(bool ct_required,
+ const std::vector<std::string>& host_patterns,
+ url_matcher::URLMatcherConditionSet::Vector* conditions);
+
+ // Parses the SPKIs from |spki_list|, setting |*hashes| to the sorted set of
+ // all valid SPKIs.
+ void ParseSpkiHashes(const std::vector<std::string> spki_list,
+ net::HashValueVector* hashes) const;
+
+ // Returns true if |lhs| has greater precedence than |rhs|. Filters of
+ // higher precedence are consulted first when determining if a given filter
+ // matches.
+ bool FilterTakesPrecedence(const Filter& lhs, const Filter& rhs) const;
+
+ std::unique_ptr<url_matcher::URLMatcher> url_matcher_;
+ url_matcher::URLMatcherConditionSet::ID next_id_;
+ std::map<url_matcher::URLMatcherConditionSet::ID, Filter> filters_;
+
+ // Both SPKI lists are sorted.
+ net::HashValueVector spkis_;
+ net::HashValueVector legacy_spkis_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChromeRequireCTDelegate);
+};
+
+} // namespace certificate_transparency
+
+#endif // COMPONENTS_CERTIFICATE_TRANSPARENCY_CHROME_REQUIRE_CT_DELEGATE_H_
diff --git a/chromium/components/certificate_transparency/ct_policy_manager_unittest.cc b/chromium/components/certificate_transparency/chrome_require_ct_delegate_unittest.cc
index 9d3b3b1c5af..a9e16288e7b 100644
--- a/chromium/components/certificate_transparency/ct_policy_manager_unittest.cc
+++ b/chromium/components/certificate_transparency/chrome_require_ct_delegate_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/certificate_transparency/ct_policy_manager.h"
+#include "components/certificate_transparency/chrome_require_ct_delegate.h"
#include <iterator>
@@ -27,9 +27,9 @@ namespace certificate_transparency {
namespace {
-class CTPolicyManagerTest : public ::testing::Test {
+class ChromeRequireCTDelegateTest : public ::testing::Test {
public:
- CTPolicyManagerTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
+ ChromeRequireCTDelegateTest() : message_loop_(base::MessageLoop::TYPE_IO) {}
void SetUp() override {
cert_ = net::CreateCertificateChainFromFile(
@@ -48,7 +48,7 @@ class CTPolicyManagerTest : public ::testing::Test {
// Treat the preferences as a black box as far as naming, but ensure that
// preferences get registered.
-TEST_F(CTPolicyManagerTest, RegistersPrefs) {
+TEST_F(ChromeRequireCTDelegateTest, RegistersPrefs) {
TestingPrefServiceSimple pref_service;
auto registered_prefs = std::distance(pref_service.registry()->begin(),
pref_service.registry()->end());
@@ -58,171 +58,144 @@ TEST_F(CTPolicyManagerTest, RegistersPrefs) {
EXPECT_NE(registered_prefs, newly_registered_prefs);
}
-TEST_F(CTPolicyManagerTest, DelegateChecksRequired) {
+TEST_F(ChromeRequireCTDelegateTest, DelegateChecksRequired) {
using CTRequirementLevel =
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
- CTPolicyManager manager;
-
- net::TransportSecurityState::RequireCTDelegate* delegate =
- manager.GetDelegate();
- ASSERT_TRUE(delegate);
+ ChromeRequireCTDelegate delegate;
// No required host set yet.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
// Add a required host
- manager.UpdateCTPolicies(
- std::vector<std::string>{"google.com"}, std::vector<std::string>(),
- std::vector<std::string>(), std::vector<std::string>());
+ delegate.UpdateCTPolicies({"google.com"}, {}, {}, {});
// The new setting should take effect.
EXPECT_EQ(CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
}
-TEST_F(CTPolicyManagerTest, DelegateChecksExcluded) {
+TEST_F(ChromeRequireCTDelegateTest, DelegateChecksExcluded) {
using CTRequirementLevel =
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
- CTPolicyManager manager;
-
- net::TransportSecurityState::RequireCTDelegate* delegate =
- manager.GetDelegate();
- ASSERT_TRUE(delegate);
+ ChromeRequireCTDelegate delegate;
// No setting should yield the default results.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
// Add a excluded host
- manager.UpdateCTPolicies(
- std::vector<std::string>(), std::vector<std::string>{"google.com"},
- std::vector<std::string>(), std::vector<std::string>());
+ delegate.UpdateCTPolicies({}, {"google.com"}, {}, {});
// The new setting should take effect.
EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
}
-TEST_F(CTPolicyManagerTest, IgnoresInvalidEntries) {
+TEST_F(ChromeRequireCTDelegateTest, IgnoresInvalidEntries) {
using CTRequirementLevel =
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
- CTPolicyManager manager;
-
- net::TransportSecurityState::RequireCTDelegate* delegate =
- manager.GetDelegate();
- ASSERT_TRUE(delegate);
+ ChromeRequireCTDelegate delegate;
// No setting should yield the default results.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
// Now setup invalid state (that is, that fail to be parsable as
// URLs).
- manager.UpdateCTPolicies(
- std::vector<std::string>{
- "file:///etc/fstab", "file://withahost/etc/fstab",
- "file:///c|/Windows", "*", "https://*", "example.com",
- "https://example.test:invalid_port"},
- std::vector<std::string>(), std::vector<std::string>(),
- std::vector<std::string>());
+ delegate.UpdateCTPolicies(
+ {"file:///etc/fstab", "file://withahost/etc/fstab", "file:///c|/Windows",
+ "*", "https://*", "example.com", "https://example.test:invalid_port"},
+ {}, {}, {});
// Wildcards are ignored (both * and https://*).
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
// File URL hosts are ignored.
- EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("withahost", cert_.get(), hashes_));
+ // TODO(rsleevi): https://crbug.com/841407 - Ensure that file URLs have their
+ // hosts ignored for policy.
+ // EXPECT_EQ(CTRequirementLevel::DEFAULT,
+ // delegate.IsCTRequiredForHost("withahost", cert_.get(), hashes_));
// While the partially parsed hosts should take effect.
- EXPECT_EQ(
- CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("example.test", cert_.get(), hashes_));
EXPECT_EQ(CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("example.test", cert_.get(), hashes_));
+ EXPECT_EQ(CTRequirementLevel::REQUIRED,
+ delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
}
// Make sure the various 'undocumented' priorities apply:
// - non-wildcards beat wildcards
// - more specific hosts beat less specific hosts
// - requiring beats excluding
-TEST_F(CTPolicyManagerTest, AppliesPriority) {
+TEST_F(ChromeRequireCTDelegateTest, AppliesPriority) {
using CTRequirementLevel =
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
- CTPolicyManager manager;
-
- net::TransportSecurityState::RequireCTDelegate* delegate =
- manager.GetDelegate();
- ASSERT_TRUE(delegate);
+ ChromeRequireCTDelegate delegate;
// No setting should yield the default results.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
EXPECT_EQ(
CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("accounts.example.com", cert_.get(),
- hashes_));
+ delegate.IsCTRequiredForHost("accounts.example.com", cert_.get(),
+ hashes_));
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("login.accounts.example.com",
- cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("login.accounts.example.com",
+ cert_.get(), hashes_));
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("sub.accounts.example.com",
- cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("sub.accounts.example.com",
+ cert_.get(), hashes_));
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("login.sub.accounts.example.com",
- cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("login.sub.accounts.example.com",
+ cert_.get(), hashes_));
EXPECT_EQ(
CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
// Set up policies that exclude it for a domain and all of its subdomains,
// but then require it for a specific host.
- manager.UpdateCTPolicies(
- std::vector<std::string>{"sub.example.com", "accounts.example.com",
- "test.example.com"},
- std::vector<std::string>{"example.com", ".sub.example.com",
- ".sub.accounts.example.com", "test.example.com"},
- std::vector<std::string>(), std::vector<std::string>());
+ delegate.UpdateCTPolicies(
+ {"sub.example.com", "accounts.example.com", "test.example.com"},
+ {"example.com", ".sub.example.com", ".sub.accounts.example.com",
+ "test.example.com"},
+ {}, {});
EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
- delegate->IsCTRequiredForHost("example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
// Non-wildcarding (.sub.example.com) beats wildcarding (sub.example.com).
EXPECT_EQ(
CTRequirementLevel::NOT_REQUIRED,
- delegate->IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("sub.example.com", cert_.get(), hashes_));
// More specific hosts (accounts.example.com) beat less specific hosts
// (example.com + wildcard).
EXPECT_EQ(CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("accounts.example.com", cert_.get(),
- hashes_));
+ delegate.IsCTRequiredForHost("accounts.example.com", cert_.get(),
+ hashes_));
// More specific hosts (accounts.example.com) beat less specific hosts
// (example.com).
EXPECT_EQ(CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("login.accounts.example.com",
- cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("login.accounts.example.com",
+ cert_.get(), hashes_));
EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
- delegate->IsCTRequiredForHost("sub.accounts.example.com",
- cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("sub.accounts.example.com",
+ cert_.get(), hashes_));
EXPECT_EQ(CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("login.sub.accounts.example.com",
- cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("login.sub.accounts.example.com",
+ cert_.get(), hashes_));
// Requiring beats excluding.
EXPECT_EQ(
CTRequirementLevel::REQUIRED,
- delegate->IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("test.example.com", cert_.get(), hashes_));
}
-TEST_F(CTPolicyManagerTest, SupportsOrgRestrictions) {
+TEST_F(ChromeRequireCTDelegateTest, SupportsOrgRestrictions) {
using CTRequirementLevel =
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
- CTPolicyManager manager;
-
- net::TransportSecurityState::RequireCTDelegate* delegate =
- manager.GetDelegate();
- ASSERT_TRUE(delegate);
+ ChromeRequireCTDelegate delegate;
base::FilePath test_directory = net::GetTestNetDataDirectory().Append(
FILE_PATH_LITERAL("ov_name_constraints"));
@@ -339,33 +312,24 @@ TEST_F(CTPolicyManagerTest, SupportsOrgRestrictions) {
net::x509_util::DupCryptoBuffer(leaf->cert_buffer()),
std::move(intermediates));
}
- manager.UpdateCTPolicies(
- std::vector<std::string>(), std::vector<std::string>(),
- std::vector<std::string>(), std::vector<std::string>());
+ delegate.UpdateCTPolicies({}, {}, {}, {});
// There should be no existing settings.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", leaf.get(), hashes));
+ delegate.IsCTRequiredForHost("google.com", leaf.get(), hashes));
- manager.UpdateCTPolicies(std::vector<std::string>(),
- std::vector<std::string>(),
- std::vector<std::string>{test.spki.ToString()},
- std::vector<std::string>());
+ delegate.UpdateCTPolicies({}, {}, {test.spki.ToString()}, {});
// The new setting should take effect.
EXPECT_EQ(test.expected,
- delegate->IsCTRequiredForHost("google.com", leaf.get(), hashes));
+ delegate.IsCTRequiredForHost("google.com", leaf.get(), hashes));
}
}
-TEST_F(CTPolicyManagerTest, SupportsLegacyCaRestrictions) {
+TEST_F(ChromeRequireCTDelegateTest, SupportsLegacyCaRestrictions) {
using CTRequirementLevel =
net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
- CTPolicyManager manager;
-
- net::TransportSecurityState::RequireCTDelegate* delegate =
- manager.GetDelegate();
- ASSERT_TRUE(delegate);
+ ChromeRequireCTDelegate delegate;
// The hash of a known legacy CA. See
// //net/cert/root_cert_list_generated.h
@@ -374,35 +338,99 @@ TEST_F(CTPolicyManagerTest, SupportsLegacyCaRestrictions) {
0x38, 0x3E, 0x37, 0x3F, 0x0F, 0x22, 0x9E, 0x7D, 0xFE, 0x34, 0x44,
0x81, 0x0A, 0x8D, 0x6E, 0x50, 0x90, 0x5D, 0x20, 0xD6, 0x61,
}};
-
hashes_.push_back(net::HashValue(legacy_spki));
// No setting should yield the default results.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
// Setting to a non-legacy CA should not work.
std::string leaf_hash_string = hashes_.front().ToString();
- manager.UpdateCTPolicies(
- std::vector<std::string>(), std::vector<std::string>(),
- std::vector<std::string>(), std::vector<std::string>{leaf_hash_string});
+ delegate.UpdateCTPolicies({}, {}, {}, {leaf_hash_string});
// This setting should have no effect, because the hash for |cert_|
// is not a legacy CA hash.
EXPECT_EQ(CTRequirementLevel::DEFAULT,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
// Now set to a truly legacy CA, and create a chain that
// contains that legacy CA hash.
- std::string legacy_ca_hash_string = hashes_.back().ToString();
+ delegate.UpdateCTPolicies({}, {}, {}, {hashes_.back().ToString()});
+ EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
+ delegate.IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+}
+
+TEST_F(ChromeRequireCTDelegateTest, RequiresCTAfterApril2018) {
+ using CTRequirementLevel =
+ net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
+ ChromeRequireCTDelegate delegate;
- manager.UpdateCTPolicies(std::vector<std::string>(),
- std::vector<std::string>(),
- std::vector<std::string>(),
- std::vector<std::string>{legacy_ca_hash_string});
+ EXPECT_EQ(CTRequirementLevel::DEFAULT,
+ delegate.IsCTRequiredForHost("example.com", cert_.get(), hashes_));
- EXPECT_EQ(CTRequirementLevel::NOT_REQUIRED,
- delegate->IsCTRequiredForHost("google.com", cert_.get(), hashes_));
+ scoped_refptr<net::X509Certificate> may_2018 =
+ net::CreateCertificateChainFromFile(
+ net::GetTestCertsDirectory(), "may_2018.pem",
+ net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ ASSERT_TRUE(may_2018);
+
+ net::HashValueVector new_hashes;
+ new_hashes.push_back(net::HashValue(
+ net::X509Certificate::CalculateFingerprint256(may_2018->cert_buffer())));
+
+ EXPECT_EQ(
+ CTRequirementLevel::REQUIRED,
+ delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+}
+
+TEST_F(ChromeRequireCTDelegateTest,
+ PoliciesCheckedBeforeRequiringCTAfterApril2018) {
+ using CTRequirementLevel =
+ net::TransportSecurityState::RequireCTDelegate::CTRequirementLevel;
+ ChromeRequireCTDelegate delegate;
+
+ scoped_refptr<net::X509Certificate> may_2018 =
+ net::CreateCertificateChainFromFile(
+ net::GetTestCertsDirectory(), "may_2018.pem",
+ net::X509Certificate::FORMAT_PEM_CERT_SEQUENCE);
+ ASSERT_TRUE(may_2018);
+
+ net::HashValueVector new_hashes;
+ net::HashValue leaf_hash;
+ ASSERT_TRUE(net::x509_util::CalculateSha256SpkiHash(may_2018->cert_buffer(),
+ &leaf_hash));
+ new_hashes.push_back(std::move(leaf_hash));
+
+ EXPECT_EQ(
+ CTRequirementLevel::REQUIRED,
+ delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+
+ // Check excluding by hostname.
+ delegate.UpdateCTPolicies({}, {"example.com"}, {}, {});
+ EXPECT_EQ(
+ CTRequirementLevel::NOT_REQUIRED,
+ delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+
+ // Check excluding by leaf hash.
+ delegate.UpdateCTPolicies({}, {}, {new_hashes.front().ToString()}, {});
+ EXPECT_EQ(
+ CTRequirementLevel::NOT_REQUIRED,
+ delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
+
+ // Check excluding by legacy CA hash.
+
+ // The hash of a known legacy CA. See
+ // //net/cert/root_cert_list_generated.h
+ net::SHA256HashValue legacy_spki = {{
+ 0x00, 0x6C, 0xB2, 0x26, 0xA7, 0x72, 0xC7, 0x18, 0x2D, 0x77, 0x72,
+ 0x38, 0x3E, 0x37, 0x3F, 0x0F, 0x22, 0x9E, 0x7D, 0xFE, 0x34, 0x44,
+ 0x81, 0x0A, 0x8D, 0x6E, 0x50, 0x90, 0x5D, 0x20, 0xD6, 0x61,
+ }};
+ new_hashes.push_back(net::HashValue(legacy_spki));
+ delegate.UpdateCTPolicies({}, {}, {}, {new_hashes.back().ToString()});
+ EXPECT_EQ(
+ CTRequirementLevel::NOT_REQUIRED,
+ delegate.IsCTRequiredForHost("example.com", may_2018.get(), new_hashes));
}
} // namespace
diff --git a/chromium/components/certificate_transparency/ct_known_logs.cc b/chromium/components/certificate_transparency/ct_known_logs.cc
new file mode 100644
index 00000000000..328ea4abfc5
--- /dev/null
+++ b/chromium/components/certificate_transparency/ct_known_logs.cc
@@ -0,0 +1,67 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/certificate_transparency/ct_known_logs.h"
+
+#include <stddef.h>
+#include <string.h>
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
+#include "base/time/time.h"
+#include "crypto/sha2.h"
+
+namespace certificate_transparency {
+
+namespace {
+#include "components/certificate_transparency/data/log_list-inc.cc"
+} // namespace
+
+std::vector<CTLogInfo> GetKnownLogs() {
+ // Add all qualified logs.
+ std::vector<CTLogInfo> logs(std::begin(kCTLogList), std::end(kCTLogList));
+
+ // Add all disqualified logs. Callers are expected to filter verified SCTs
+ // via IsLogDisqualified().
+ for (const auto& disqualified_log : kDisqualifiedCTLogList) {
+ logs.push_back(disqualified_log.log_info);
+ }
+
+ return logs;
+}
+
+bool IsLogOperatedByGoogle(base::StringPiece log_id) {
+ CHECK_EQ(log_id.size(), crypto::kSHA256Length);
+
+ return std::binary_search(std::begin(kGoogleLogIDs), std::end(kGoogleLogIDs),
+ log_id.data(), [](const char* a, const char* b) {
+ return memcmp(a, b, crypto::kSHA256Length) < 0;
+ });
+}
+
+bool IsLogDisqualified(base::StringPiece log_id,
+ base::Time* disqualification_date) {
+ CHECK_EQ(log_id.size(), base::size(kDisqualifiedCTLogList[0].log_id) - 1);
+
+ auto* p = std::lower_bound(
+ std::begin(kDisqualifiedCTLogList), std::end(kDisqualifiedCTLogList),
+ log_id.data(),
+ [](const DisqualifiedCTLogInfo& disqualified_log, const char* log_id) {
+ return memcmp(disqualified_log.log_id, log_id, crypto::kSHA256Length) <
+ 0;
+ });
+ if (p == std::end(kDisqualifiedCTLogList) ||
+ memcmp(p->log_id, log_id.data(), crypto::kSHA256Length) != 0) {
+ return false;
+ }
+
+ *disqualification_date = base::Time::UnixEpoch() + p->disqualification_date;
+ return true;
+}
+
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/ct_known_logs.h b/chromium/components/certificate_transparency/ct_known_logs.h
new file mode 100644
index 00000000000..59fbc6a9cad
--- /dev/null
+++ b/chromium/components/certificate_transparency/ct_known_logs.h
@@ -0,0 +1,55 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_KNOWN_LOGS_H_
+#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_KNOWN_LOGS_H_
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "build/build_config.h"
+
+namespace base {
+class Time;
+} // namespace base
+
+namespace certificate_transparency {
+
+struct CTLogInfo {
+ // The DER-encoded SubjectPublicKeyInfo for the log.
+ const char* log_key;
+ // The length, in bytes, of |log_key|.
+ size_t log_key_length;
+ // The user-friendly log name.
+ // Note: This will not be translated.
+ const char* log_name;
+ // The DNS API endpoint for the log.
+ // This is used as the parent domain for all queries about the log.
+ // https://github.com/google/certificate-transparency-rfcs/blob/master/dns/draft-ct-over-dns.md.
+ const char* log_dns_domain;
+};
+
+// Returns information about all known logs, which includes those that are
+// presently qualified for inclusion and logs which were previously qualified,
+// but have since been disqualified. To determine the status of a given log
+// (via its log ID), use |IsLogDisqualified()|.
+std::vector<CTLogInfo> GetKnownLogs();
+
+// Returns true if the log identified by |log_id| (the SHA-256 hash of the
+// log's DER-encoded SPKI) is operated by Google.
+bool IsLogOperatedByGoogle(base::StringPiece log_id);
+
+// Returns true if the log identified by |log_id| (the SHA-256 hash of the
+// log's DER-encoded SPKI) has been disqualified, and sets
+// |*disqualification_date| to the date of disqualification. Any SCTs that
+// are embedded in certificates issued after |*disqualification_date| should
+// not be trusted, nor contribute to any uniqueness or freshness
+// requirements.
+bool IsLogDisqualified(base::StringPiece log_id,
+ base::Time* disqualification_date);
+
+} // namespace certificate_transparency
+
+#endif // COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_KNOWN_LOGS_H_
diff --git a/chromium/components/certificate_transparency/ct_known_logs_unittest.cc b/chromium/components/certificate_transparency/ct_known_logs_unittest.cc
new file mode 100644
index 00000000000..938062c1210
--- /dev/null
+++ b/chromium/components/certificate_transparency/ct_known_logs_unittest.cc
@@ -0,0 +1,38 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/certificate_transparency/ct_known_logs.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "base/time/time.h"
+#include "crypto/sha2.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace certificate_transparency {
+
+namespace {
+#include "components/certificate_transparency/data/log_list-inc.cc"
+} // namespace
+
+TEST(CTKnownLogsTest, GoogleIDsAreSorted) {
+ ASSERT_TRUE(std::is_sorted(std::begin(kGoogleLogIDs), std::end(kGoogleLogIDs),
+ [](const char* a, const char* b) {
+ return memcmp(a, b, crypto::kSHA256Length) < 0;
+ }));
+}
+
+TEST(CTKnownLogsTest, DisallowedLogsAreSortedByLogID) {
+ ASSERT_TRUE(std::is_sorted(
+ std::begin(kDisqualifiedCTLogList), std::end(kDisqualifiedCTLogList),
+ [](const DisqualifiedCTLogInfo& a, const DisqualifiedCTLogInfo& b) {
+ return memcmp(a.log_id, b.log_id, crypto::kSHA256Length) < 0;
+ }));
+}
+
+} // namespace certificate_transparency
diff --git a/chromium/components/certificate_transparency/ct_policy_manager.h b/chromium/components/certificate_transparency/ct_policy_manager.h
deleted file mode 100644
index 88f3b977b3e..00000000000
--- a/chromium/components/certificate_transparency/ct_policy_manager.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_POLICY_MANAGER_H_
-#define COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_POLICY_MANAGER_H_
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "net/http/transport_security_state.h"
-
-namespace certificate_transparency {
-
-// CTPolicyManager serves as the bridge between the Certificate Transparency
-// preferences (see pref_names.h) and the actual implementation, by exposing
-// a TransportSecurityState::RequireCTDelegate that can be used to query for
-// CT-related policies.
-class CTPolicyManager {
- public:
- // Creates a CTPolicyManager that will provide a RequireCTDelegate delegate.
- CTPolicyManager();
- ~CTPolicyManager();
-
- // Returns a RequireCTDelegate that responds based on the policies set via
- // preferences.
- //
- // The order of priority of the preferences is that:
- // - Specific hosts are preferred over those that match subdomains.
- // - The most specific host is preferred.
- // - Requiring CT is preferred over excluding CT
- //
- net::TransportSecurityState::RequireCTDelegate* GetDelegate();
-
- // Updates the CTDelegate to require CT for |required_hosts|, and exclude
- // |excluded_hosts| from CT policies. In addtion, this method updates
- // |excluded_spkis| and |excluded_legacy_spkis| intended for use within an
- // Enterprise (see https://crbug.com/824184).
- void UpdateCTPolicies(const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis);
-
- private:
- class CTDelegate;
- std::unique_ptr<CTDelegate> delegate_;
-
- DISALLOW_COPY_AND_ASSIGN(CTPolicyManager);
-};
-
-} // namespace certificate_transparency
-
-#endif // COMPONENTS_CERTIFICATE_TRANSPARENCY_CT_POLICY_MANAGER_H_
diff --git a/chromium/components/certificate_transparency/data/BUILD.gn b/chromium/components/certificate_transparency/data/BUILD.gn
new file mode 100644
index 00000000000..b2e3476788c
--- /dev/null
+++ b/chromium/components/certificate_transparency/data/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright (c) 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+action_foreach("ct_log_list") {
+ script =
+ "//components/certificate_transparency/tools/make_ct_known_logs_list.py"
+ sources = [
+ "log_list.json",
+ ]
+ outputs = [
+ "${target_gen_dir}/{{source_name_part}}-inc.cc",
+ ]
+ args = [
+ "{{source}}",
+ rebase_path("${target_gen_dir}/{{source_name_part}}-inc.cc",
+ root_build_dir),
+ ]
+}
diff --git a/chromium/components/certificate_transparency/data/log_list.json b/chromium/components/certificate_transparency/data/log_list.json
new file mode 100644
index 00000000000..9cf4692e70c
--- /dev/null
+++ b/chromium/components/certificate_transparency/data/log_list.json
@@ -0,0 +1,377 @@
+{
+ "logs": [
+ {
+ "description": "Google 'Argon2018' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE0gBVBa3VR7QZu82V+ynXWD14JM3ORp37MtRxTmACJV5ZPtfUA7htQ2hofuigZQs+bnFZkje+qejxoyvk2Q1VaA==",
+ "url": "ct.googleapis.com/logs/argon2018/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "argon2018.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Argon2019' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEI3MQm+HzXvaYa2mVlhB4zknbtAT8cSxakmBoJcBKGqGwYS0bhxSpuvABM1kdBTDpQhXnVdcq+LSiukXJRpGHVg==",
+ "url": "ct.googleapis.com/logs/argon2019/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "argon2019.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Argon2020' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6Tx2p1yKY4015NyIYvdrk36es0uAc1zA4PQ+TGRY+3ZjUTIYY9Wyu+3q/147JG4vNVKLtDWarZwVqGkg6lAYzA==",
+ "url": "ct.googleapis.com/logs/argon2020/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "argon2020.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Argon2021' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETeBmZOrzZKo4xYktx9gI2chEce3cw/tbr5xkoQlmhB18aKfsxD+MnILgGNl0FOm0eYGilFVi85wLRIOhK8lxKw==",
+ "url": "ct.googleapis.com/logs/argon2021/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "argon2021.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Aviator' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1/TMabLkDpCjiupacAlP7xNi0I1JYP8bQFAHDG1xhtolSY1l4QgNRzRrvSe8liE+NPWHdjGxfx3JhTsN9x8/6Q==",
+ "url": "ct.googleapis.com/aviator/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "final_sth": {
+ "tree_size": 46466472,
+ "timestamp": 1480512258330,
+ "sha256_root_hash": "LcGcZRsm+LGYmrlyC5LXhV1T6OD8iH5dNlb0sEJl9bA=",
+ "tree_head_signature": "BAMASDBGAiEA/M0Nvt77aNe+9eYbKsv6rRpTzFTKa5CGqb56ea4hnt8CIQCJDE7pL6xgAewMd5i3G1lrBWgFooT2kd3+zliEz5Rw8w=="
+ },
+ "dns_api_endpoint": "aviator.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Icarus' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETtK8v7MICve56qTHHDhhBOuV4IlUaESxZryCfk9QbG9co/CqPvTsgPDbCpp6oFtyAHwlDhnvr7JijXRD9Cb2FA==",
+ "url": "ct.googleapis.com/icarus/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "icarus.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Pilot' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfahLEimAoz2t01p3uMziiLOl/fHTDM0YDOhBRuiBARsV4UvxG2LdNgoIGLrtCzWE0J5APC2em4JlvR8EEEFMoA==",
+ "url": "ct.googleapis.com/pilot/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "pilot.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Rocketeer' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEIFsYyDzBi7MxCAC/oJBXK7dHjG+1aLCOkHjpoHPqTyghLpzA9BYbqvnV16mAw04vUjyYASVGJCUoI3ctBcJAeg==",
+ "url": "ct.googleapis.com/rocketeer/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "rocketeer.ct.googleapis.com"
+ },
+ {
+ "description": "Google 'Skydiver' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEmyGDvYXsRJsNyXSrYc9DjHsIa2xzb4UR7ZxVoV6mrc9iZB7xjI6+NrOiwH+P/xxkRmOFG6Jel20q37hTh58rA==",
+ "url": "ct.googleapis.com/skydiver/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 0
+ ],
+ "dns_api_endpoint": "skydiver.ct.googleapis.com"
+ },
+ {
+ "description": "Cloudflare 'Nimbus2018' Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAsVpWvrH3Ke0VRaMg9ZQoQjb5g/xh1z3DDa6IuxY5DyPsk6brlvrUNXZzoIg0DcvFiAn2kd6xmu4Obk5XA/nRg==",
+ "url": "ct.cloudflare.com/logs/nimbus2018/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 1
+ ],
+ "dns_api_endpoint": "cloudflare-nimbus2018.ct.googleapis.com"
+ },
+ {
+ "description": "Cloudflare 'Nimbus2019' Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkZHz1v5r8a9LmXSMegYZAg4UW+Ug56GtNfJTDNFZuubEJYgWf4FcC5D+ZkYwttXTDSo4OkanG9b3AI4swIQ28g==",
+ "url": "ct.cloudflare.com/logs/nimbus2019/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 1
+ ],
+ "dns_api_endpoint": "cloudflare-nimbus2019.ct.googleapis.com"
+ },
+ {
+ "description": "Cloudflare 'Nimbus2020' Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE01EAhx4o0zPQrXTcYjgCt4MVFsT0Pwjzb1RwrM0lhWDlxAYPP6/gyMCXNkOn/7KFsjL7rwk78tHMpY8rXn8AYg==",
+ "url": "ct.cloudflare.com/logs/nimbus2020/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 1
+ ],
+ "dns_api_endpoint": "cloudflare-nimbus2020.ct.googleapis.com"
+ },
+ {
+ "description": "Cloudflare 'Nimbus2021' Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExpon7ipsqehIeU1bmpog9TFo4Pk8+9oN8OYHl1Q2JGVXnkVFnuuvPgSo2Ep+6vLffNLcmEbxOucz03sFiematg==",
+ "url": "ct.cloudflare.com/logs/nimbus2021/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 1
+ ],
+ "dns_api_endpoint": "cloudflare-nimbus2021.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Log Server",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAkbFvhu7gkAW6MHSrBlpE1n4+HCFRkC5OLAjgqhkTH+/uzSfSl8ois8ZxAD2NgaTZe1M9akhYlrYkes4JECs6A==",
+ "url": "ct1.digicert-ct.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Log Server 2",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzF05L2a4TH/BLgOhNKPoioYCrkoRxvcmajeb8Dj4XQmNY+gxa4Zmz3mzJTwe33i0qMVp+rfwgnliQ/bM/oFmhA==",
+ "url": "ct2.digicert-ct.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert2.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Yeti2018 Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESYlKFDLLFmA9JScaiaNnqlU8oWDytxIYMfswHy9Esg0aiX+WnP/yj4O0ViEHtLwbmOQeSWBGkIu9YK9CLeer+g==",
+ "url": "yeti2018.ct.digicert.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert-yeti2018.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Yeti2019 Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkZd/ow8X+FSVWAVSf8xzkFohcPph/x6pS1JHh7g1wnCZ5y/8Hk6jzJxs6t3YMAWz2CPd4VkCdxwKexGhcFxD9A==",
+ "url": "yeti2019.ct.digicert.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert-yeti2019.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Yeti2020 Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEURAG+Zo0ac3n37ifZKUhBFEV6jfcCzGIRz3tsq8Ca9BP/5XUHy6ZiqsPaAEbVM0uI3Tm9U24RVBHR9JxDElPmg==",
+ "url": "yeti2020.ct.digicert.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert-yeti2020.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Yeti2021 Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6J4EbcpIAl1+AkSRsbhoY5oRTj3VoFfaf1DlQkfi7Rbe/HcjfVtrwN8jaC+tQDGjF+dqvKhWJAQ6Q6ev6q9Mew==",
+ "url": "yeti2021.ct.digicert.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert-yeti2021.ct.googleapis.com"
+ },
+ {
+ "description": "DigiCert Yeti2022 Log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEn/jYHd77W1G1+131td5mEbCdX/1v/KiYW5hPLcOROvv+xA8Nw2BDjB7y+RGyutD2vKXStp/5XIeiffzUfdYTJg==",
+ "url": "yeti2022.ct.digicert.com/log/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "digicert-yeti2022.ct.googleapis.com"
+ },
+ {
+ "description": "Symantec log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==",
+ "url": "ct.ws.symantec.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "symantec.ct.googleapis.com"
+ },
+ {
+ "description": "Symantec 'Vega' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE6pWeAv/u8TNtS4e8zf0ZF2L/lNPQWQc/Ai0ckP7IRzA78d0NuBEMXR2G3avTK0Zm+25ltzv9WWis36b4ztIYTQ==",
+ "url": "vega.ws.symantec.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "symantec-vega.ct.googleapis.com"
+ },
+ {
+ "description": "Symantec 'Sirius' log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEowJkhCK7JewN47zCyYl93UXQ7uYVhY/Z5xcbE4Dq7bKFN61qxdglnfr0tPNuFiglN+qjN2Syxwv9UeXBBfQOtQ==",
+ "url": "sirius.ws.symantec.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 2
+ ],
+ "dns_api_endpoint": "symantec-sirius.ct.googleapis.com"
+ },
+ {
+ "description": "Certly.IO log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECyPLhWKYYUgEc+tUXfPQB4wtGS2MNvXrjwFCCnyYJifBtd2Sk7Cu+Js9DNhMTh35FftHaHu6ZrclnNBKwmbbSA==",
+ "url": "log.certly.io/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 3
+ ],
+ "disqualified_at": 1460678400,
+ "dns_api_endpoint": "certly.ct.googleapis.com"
+ },
+ {
+ "description": "Izenpe log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJ2Q5DC3cUBj4IQCiDu0s6j51up+TZAkAEcQRF6tczw90rLWXkJMAW7jr9yc92bIKgV8vDXU4lDeZHvYHduDuvg==",
+ "url": "ct.izenpe.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 4
+ ],
+ "disqualified_at": 1464566400,
+ "dns_api_endpoint": "izenpe1.ct.googleapis.com"
+ },
+ {
+ "description": "WoSign log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzBGIey1my66PTTBmJxklIpMhRrQvAdPG+SvVyLpzmwai8IoCnNBrRhgwhbrpJIsO0VtwKAx+8TpFf1rzgkJgMQ==",
+ "url": "ctlog.wosign.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 5
+ ],
+ "disqualified_at": 1518479999,
+ "dns_api_endpoint": "wosign1.ct.googleapis.com"
+ },
+ {
+ "description": "Venafi log",
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAolpIHxdSlTXLo1s6H1OCdpSj/4DyHDc8wLG9wVmLqy1lk9fz4ATVmm+/1iN2Nk8jmctUKK2MFUtlWXZBSpym97M7frGlSaQXUWyA3CqQUEuIJOmlEjKTBEiQAvpfDjCHjlV2Be4qTM6jamkJbiWtgnYPhJL6ONaGTiSPm7Byy57iaz/hbckldSOIoRhYBiMzeNoA0DiRZ9KmfSeXZ1rB8y8X5urSW+iBzf2SaOfzBvDpcoTuAaWx2DPazoOl28fP1hZ+kHUYvxbcMjttjauCFx+JII0dmuZNIwjfeG/GBb9frpSX219k1O4Wi6OEbHEr8at/XQ0y7gTikOxBn/s5wQIDAQAB",
+ "url": "ctlog.api.venafi.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 6
+ ],
+ "disqualified_at": 1488307346,
+ "dns_api_endpoint": "venafi.ct.googleapis.com"
+ },
+ {
+ "description": "Venafi Gen2 CT log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjicnerZVCXTrbEuUhGW85BXx6lrYfA43zro/bAna5ymW00VQb94etBzSg4j/KS/Oqf/fNN51D8DMGA2ULvw3AQ==",
+ "url": "ctlog-gen2.api.venafi.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 6
+ ],
+ "dns_api_endpoint": "venafi2.ct.googleapis.com"
+ },
+ {
+ "description": "CNNIC CT log",
+ "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7UIYZopMgTTJWPp2IXhhuAf1l6a9zM7gBvntj5fLaFm9pVKhKYhVnno94XuXeN8EsDgiSIJIj66FpUGvai5samyetZhLocRuXhAiXXbDNyQ4KR51tVebtEq2zT0mT9liTtGwiksFQccyUsaVPhsHq9gJ2IKZdWauVA2Fm5x9h8B9xKn/L/2IaMpkIYtd967TNTP/dLPgixN1PLCLaypvurDGSVDsuWabA3FHKWL9z8wr7kBkbdpEhLlg2H+NAC+9nGKx+tQkuhZ/hWR65aX+CNUPy2OB9/u2rNPyDydb988LENXoUcMkQT0dU3aiYGkFAY0uZjD2vH97TM20xYtNQIDAQAB",
+ "url": "ctserver.cnnic.cn/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 7
+ ],
+ "dns_api_endpoint": "cnnic.ct.googleapis.com"
+ },
+ {
+ "description": "StartCom log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESPNZ8/YFGNPbsu1Gfs/IEbVXsajWTOaft0oaFIZDqUiwy1o/PErK38SCFFWa+PeOQFXc9NKv6nV0+05/YIYuUQ==",
+ "url": "ct.startssl.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 8
+ ],
+ "disqualified_at": 1518479999,
+ "dns_api_endpoint": "startcom1.ct.googleapis.com"
+ },
+ {
+ "description": "Comodo 'Sabre' CT log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8m/SiQ8/xfiHHqtls9m7FyOMBg4JVZY9CgiixXGz0akvKD6DEL8S0ERmFe9U4ZiA0M4kbT5nmuk3I85Sk4bagA==",
+ "url": "sabre.ct.comodo.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 9
+ ],
+ "dns_api_endpoint": "comodo-sabre.ct.googleapis.com"
+ },
+ {
+ "description": "Comodo 'Mammoth' CT log",
+ "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7+R9dC4VFbbpuyOL+yy14ceAmEf7QGlo/EmtYU6DRzwat43f/3swtLr/L8ugFOOt1YU/RFmMjGCL17ixv66MZw==",
+ "url": "mammoth.ct.comodo.com/",
+ "maximum_merge_delay": 86400,
+ "operated_by": [
+ 9
+ ],
+ "dns_api_endpoint": "comodo-mammoth.ct.googleapis.com"
+ }
+ ],
+ "operators": [
+ {
+ "name": "Google",
+ "id": 0
+ },
+ {
+ "name": "Cloudflare",
+ "id": 1
+ },
+ {
+ "name": "DigiCert",
+ "id": 2
+ },
+ {
+ "name": "Certly",
+ "id": 3
+ },
+ {
+ "name": "Izenpe",
+ "id": 4
+ },
+ {
+ "name": "WoSign",
+ "id": 5
+ },
+ {
+ "name": "Venafi",
+ "id": 6
+ },
+ {
+ "name": "CNNIC",
+ "id": 7
+ },
+ {
+ "name": "StartCom",
+ "id": 8
+ },
+ {
+ "name": "Comodo CA Limited",
+ "id": 9
+ }
+ ]
+} \ No newline at end of file
diff --git a/chromium/components/certificate_transparency/log_dns_client.cc b/chromium/components/certificate_transparency/log_dns_client.cc
index 2ed85e0c22d..4e17c67d9c7 100644
--- a/chromium/components/certificate_transparency/log_dns_client.cc
+++ b/chromium/components/certificate_transparency/log_dns_client.cc
@@ -9,6 +9,7 @@
#include "base/format_macros.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -32,26 +33,14 @@ namespace certificate_transparency {
namespace {
-// Used by UMA_HISTOGRAM_ENUMERATION to record query success/failures.
-// These values are written to logs. New enum values can be added, but existing
-// enums must never be renumbered or deleted and reused.
-enum QueryStatus {
- QUERY_STATUS_SUCCESS = 0,
- QUERY_STATUS_FAILED_UNKNOWN = 1,
- QUERY_STATUS_FAILED_NAME_RESOLUTION = 2,
- QUERY_STATUS_FAILED_LEAF_INDEX_MALFORMED = 3,
- QUERY_STATUS_FAILED_INCLUSION_PROOF_MALFORMED = 4,
- QUERY_STATUS_MAX // Upper bound
-};
-
-void LogQueryStatus(QueryStatus result) {
- UMA_HISTOGRAM_ENUMERATION("Net.CertificateTransparency.DnsQueryStatus",
- result, QUERY_STATUS_MAX);
-}
-
-void LogQueryDuration(const base::TimeDelta& duration) {
+void LogQueryDuration(net::Error error, const base::TimeDelta& duration) {
UMA_HISTOGRAM_MEDIUM_TIMES("Net.CertificateTransparency.DnsQueryDuration",
duration);
+
+ if (error == net::OK) {
+ UMA_HISTOGRAM_MEDIUM_TIMES(
+ "Net.CertificateTransparency.DnsQueryDuration.Success", duration);
+ }
}
// Returns an EDNS option that disables the client subnet extension, as
@@ -308,6 +297,10 @@ net::Error AuditProofQueryImpl::DoLoop(net::Error result) {
break;
case State::REQUEST_LEAF_INDEX_COMPLETE:
result = RequestLeafIndexComplete(result);
+ if (result == net::OK) {
+ base::UmaHistogramSparse(
+ "Net.CertificateTransparency.DnsQueryLeafIndexError", net::OK);
+ }
break;
case State::REQUEST_AUDIT_PROOF_NODES:
result = RequestAuditProofNodes();
@@ -323,31 +316,22 @@ net::Error AuditProofQueryImpl::DoLoop(net::Error result) {
if (result != net::ERR_IO_PENDING) {
// If the query is complete, log some metrics.
- LogQueryDuration(base::TimeTicks::Now() - start_time_);
-
- switch (result) {
- case net::OK:
- LogQueryStatus(QUERY_STATUS_SUCCESS);
- break;
- case net::ERR_NAME_RESOLUTION_FAILED:
- LogQueryStatus(QUERY_STATUS_FAILED_NAME_RESOLUTION);
+ LogQueryDuration(result, base::TimeTicks::Now() - start_time_);
+ switch (state) {
+ case State::REQUEST_LEAF_INDEX:
+ case State::REQUEST_LEAF_INDEX_COMPLETE:
+ // An error must have occurred if the query completed in this state.
+ base::UmaHistogramSparse(
+ "Net.CertificateTransparency.DnsQueryLeafIndexError", -result);
break;
- case net::ERR_DNS_MALFORMED_RESPONSE:
- switch (state) {
- case State::REQUEST_LEAF_INDEX_COMPLETE:
- LogQueryStatus(QUERY_STATUS_FAILED_LEAF_INDEX_MALFORMED);
- break;
- case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE:
- LogQueryStatus(QUERY_STATUS_FAILED_INCLUSION_PROOF_MALFORMED);
- break;
- default:
- NOTREACHED();
- break;
- }
+ case State::REQUEST_AUDIT_PROOF_NODES:
+ case State::REQUEST_AUDIT_PROOF_NODES_COMPLETE:
+ // The query may have completed successfully.
+ base::UmaHistogramSparse(
+ "Net.CertificateTransparency.DnsQueryAuditProofError", -result);
break;
- default:
- // Some other error occurred.
- LogQueryStatus(QUERY_STATUS_FAILED_UNKNOWN);
+ case State::NONE:
+ NOTREACHED();
break;
}
}
diff --git a/chromium/components/certificate_transparency/mock_log_dns_traffic.cc b/chromium/components/certificate_transparency/mock_log_dns_traffic.cc
index 46db34378ca..69d9578fab3 100644
--- a/chromium/components/certificate_transparency/mock_log_dns_traffic.cc
+++ b/chromium/components/certificate_transparency/mock_log_dns_traffic.cc
@@ -9,6 +9,7 @@
#include <vector>
#include "base/big_endian.h"
+#include "base/containers/span.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_byteorder.h"
@@ -32,10 +33,6 @@ const net::MockRead kNoMoreData(net::SYNCHRONOUS, net::ERR_UNEXPECTED, 2);
// Necessary to expose SetDnsConfig for testing.
class DnsChangeNotifier : public net::NetworkChangeNotifier {
public:
- static void SetInitialDnsConfig(const net::DnsConfig& config) {
- net::NetworkChangeNotifier::SetInitialDnsConfig(config);
- }
-
static void SetDnsConfig(const net::DnsConfig& config) {
net::NetworkChangeNotifier::SetDnsConfig(config);
}
@@ -158,7 +155,7 @@ class MockLogDnsTraffic::MockSocketData {
expected_read_payload_.size(),
1),
kNoMoreData},
- socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+ socket_data_(expected_reads_, base::make_span(&expected_write_, 1)) {}
// A socket that expects one write and a read error.
MockSocketData(const std::vector<char>& write, net::Error error)
@@ -168,7 +165,7 @@ class MockLogDnsTraffic::MockSocketData {
expected_write_payload_.size(),
0),
expected_reads_{net::MockRead(net::ASYNC, error, 1), kNoMoreData},
- socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+ socket_data_(expected_reads_, base::make_span(&expected_write_, 1)) {}
// A socket that expects one write and no response.
explicit MockSocketData(const std::vector<char>& write)
@@ -179,7 +176,7 @@ class MockLogDnsTraffic::MockSocketData {
0),
expected_reads_{net::MockRead(net::SYNCHRONOUS, net::ERR_IO_PENDING, 1),
kNoMoreData},
- socket_data_(expected_reads_, 2, &expected_write_, 1) {}
+ socket_data_(expected_reads_, base::make_span(&expected_write_, 1)) {}
~MockSocketData() {}
@@ -311,7 +308,7 @@ void MockLogDnsTraffic::InitializeDnsConfig() {
// IDs.
dns_config.randomize_ports = false;
- DnsChangeNotifier::SetInitialDnsConfig(dns_config);
+ DnsChangeNotifier::SetDnsConfig(dns_config);
}
void MockLogDnsTraffic::SetDnsConfig(const net::DnsConfig& config) {
diff --git a/chromium/components/certificate_transparency/single_tree_tracker.cc b/chromium/components/certificate_transparency/single_tree_tracker.cc
index 68cc2ced96d..b20bc9e1eaf 100644
--- a/chromium/components/certificate_transparency/single_tree_tracker.cc
+++ b/chromium/components/certificate_transparency/single_tree_tracker.cc
@@ -261,12 +261,24 @@ void SingleTreeTracker::OnSCTVerified(base::StringPiece hostname,
}
EntryToAudit entry(sct->timestamp);
- if (!GetLogEntryLeafHash(cert, sct, &entry.leaf_hash))
+ if (!GetLogEntryLeafHash(cert, sct, &entry.leaf_hash)) {
+ LogCanBeCheckedForInclusionToUMA(NOT_AUDITED_INVALID_LEAF_HASH);
return;
+ }
// Avoid queueing multiple instances of the same entry.
- if (GetAuditedEntryInclusionStatus(entry) != SCT_NOT_OBSERVED)
- return;
+ switch (GetAuditedEntryInclusionStatus(entry)) {
+ case SCT_NOT_OBSERVED:
+ // No need to record UMA, will be done below.
+ break;
+ case SCT_INCLUDED_IN_LOG:
+ LogCanBeCheckedForInclusionToUMA(NOT_AUDITED_ALREADY_CHECKED);
+ return;
+ default:
+ // Already pending, either due to a newer STH or in the queue.
+ LogCanBeCheckedForInclusionToUMA(NOT_AUDITED_ALREADY_PENDING_CHECK);
+ return;
+ }
if (pending_entries_.size() >= kPendingEntriesQueueSize) {
// Queue is full - cannot audit SCT.
diff --git a/chromium/components/certificate_transparency/single_tree_tracker.h b/chromium/components/certificate_transparency/single_tree_tracker.h
index be36b276095..c71985dbc1f 100644
--- a/chromium/components/certificate_transparency/single_tree_tracker.h
+++ b/chromium/components/certificate_transparency/single_tree_tracker.h
@@ -68,6 +68,17 @@ enum SCTCanBeCheckedForInclusion {
// privacy to do an inclusion check over DNS in this scenario.
NOT_AUDITED_NO_DNS_LOOKUP = 4,
+ // This SCT was not audited, because it was recently checked and the cached
+ // inclusion result can be used.
+ NOT_AUDITED_ALREADY_CHECKED = 5,
+
+ // This SCT is already pending an audit check, and thus can be
+ // de-duplicated.
+ NOT_AUDITED_ALREADY_PENDING_CHECK = 6,
+
+ // This SCT was not audited, as an Entry Leaf Hash could not be calculated.
+ NOT_AUDITED_INVALID_LEAF_HASH = 7,
+
SCT_CAN_BE_CHECKED_MAX
};
diff --git a/chromium/components/certificate_transparency/tools/PRESUBMIT.py b/chromium/components/certificate_transparency/tools/PRESUBMIT.py
new file mode 100644
index 00000000000..b0eb4750de6
--- /dev/null
+++ b/chromium/components/certificate_transparency/tools/PRESUBMIT.py
@@ -0,0 +1,35 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+
+"""Chromium presubmit script for src/net/tools/ct_log_list."""
+
+
+def _RunMakeCTLogListTests(input_api, output_api):
+ """Runs make_ct_known_logs_list unittests if related files were modified."""
+ files = (input_api.os_path.normpath(x) for x in
+ ('components/certificate_transparency/tools/make_ct_known_logs_list.py',
+ 'components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py',
+ 'components/certificate_transparency/data/log_list.json'))
+ if not any(f in (af.LocalPath() for af in input_api.change.AffectedFiles())
+ for f in files):
+ return []
+ test_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
+ 'make_ct_known_logs_list_unittest.py')
+ cmd_name = 'make_ct_known_logs_list_unittest'
+ cmd = [input_api.python_executable, test_path]
+ test_cmd = input_api.Command(
+ name=cmd_name,
+ cmd=cmd,
+ kwargs={},
+ message=output_api.PresubmitPromptWarning)
+ return input_api.RunTests([test_cmd])
+
+
+def CheckChangeOnUpload(input_api, output_api):
+ return _RunMakeCTLogListTests(input_api, output_api)
+
+
+def CheckChangeOnCommit(input_api, output_api):
+ return _RunMakeCTLogListTests(input_api, output_api)
diff --git a/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py
new file mode 100755
index 00000000000..cbcd023c5bd
--- /dev/null
+++ b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list.py
@@ -0,0 +1,195 @@
+#!/usr/bin/env python
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Generate a C++ file containing information on all accepted CT logs."""
+
+import base64
+import hashlib
+import json
+import math
+import sys
+
+
+def _write_cpp_header(f):
+ f.write("// This file is auto-generated, DO NOT EDIT.\n\n")
+
+
+def _write_disqualified_log_info_struct_definition(f):
+ f.write(
+ "// Information related to previously-qualified, but now disqualified,"
+ "\n"
+ "// CT logs.\n"
+ "struct DisqualifiedCTLogInfo {\n"
+ " // The ID of the log (the SHA-256 hash of |log_info.log_key|.\n"
+ " const char log_id[33];\n"
+ " const CTLogInfo log_info;\n"
+ " // The offset from the Unix Epoch of when the log was disqualified."
+ "\n"
+ " // SCTs embedded in pre-certificates after this date should not"
+ " count\n"
+ " // towards any uniqueness/freshness requirements.\n"
+ " const base::TimeDelta disqualification_date;\n"
+ "};\n\n")
+
+
+def _split_and_hexify_binary_data(bin_data):
+ """Pretty-prints, in hex, the given bin_data."""
+ hex_data = "".join(["\\x%.2x" % ord(c) for c in bin_data])
+ # line_width % 4 must be 0 to avoid splitting the hex-encoded data
+ # across '\' which will escape the quotation marks.
+ line_width = 68
+ assert line_width % 4 == 0
+ num_splits = int(math.ceil(len(hex_data) / float(line_width)))
+ return ['"%s"' % hex_data[i * line_width:(i + 1) * line_width]
+ for i in range(num_splits)]
+
+
+def _get_log_ids_array(log_ids, array_name):
+ num_logs = len(log_ids)
+ log_ids.sort()
+ log_id_length = len(log_ids[0]) + 1
+ log_id_code = [
+ "// The list is sorted.\n",
+ "const char %s[][%d] = {\n" % (array_name, log_id_length)]
+ for i in range(num_logs):
+ split_hex_id = _split_and_hexify_binary_data(log_ids[i])
+ s = " %s" % ("\n ".join(split_hex_id))
+ if (i < num_logs - 1):
+ s += ',\n'
+ log_id_code.append(s)
+ log_id_code.append('};\n\n')
+ return log_id_code
+
+
+
+def _find_google_operator_id(json_log_list):
+ goog_operator = [op for op in json_log_list["operators"]
+ if op["name"] == "Google"]
+ if len(goog_operator) != 1:
+ raise RuntimeError("Google operator ID not found.")
+
+ return goog_operator[0]["id"]
+
+
+def _get_log_ids_for_operator(logs, operator_id):
+ """Returns a list of Log IDs of logs operated by operator_id."""
+ log_ids = []
+ for log in logs:
+ # operated_by is a list, in practice we have not witnessed
+ # a log co-operated by more than one operator. Ensure we take this
+ # case into consideration if it ever happens.
+ assert(len(log["operated_by"]) == 1)
+ if operator_id == log["operated_by"][0]:
+ log_key = base64.decodestring(log["key"])
+ log_ids.append(hashlib.sha256(log_key).digest())
+ return log_ids
+
+
+def _is_log_disqualified(log):
+ return log.get("disqualified_at") != None
+
+
+def _escape_c_string(s):
+ def _escape_char(c):
+ if 32 <= ord(c) <= 126 and c not in '\\"':
+ return c
+ else:
+ return '\\%03o' % ord(c)
+ return ''.join([_escape_char(c) for c in s])
+
+
+def _to_loginfo_struct(log):
+ """Converts the given log to a CTLogInfo initialization code."""
+ log_key = base64.decodestring(log["key"])
+ split_hex_key = _split_and_hexify_binary_data(log_key)
+ s = " {"
+ s += "\n ".join(split_hex_key)
+ s += ',\n %d' % (len(log_key))
+ s += ',\n "%s"' % (_escape_c_string(log["description"]))
+ s += ',\n "%s"' % (log["dns_api_endpoint"])
+ s += '}'
+ return s
+
+
+def _get_log_definitions(logs):
+ """Returns a list of strings, each is a CTLogInfo definition."""
+ list_code = []
+ for log in logs:
+ list_code.append(_to_loginfo_struct(log))
+ return list_code
+
+
+def _to_disqualified_loginfo_struct(log):
+ log_key = base64.decodestring(log["key"])
+ log_id = hashlib.sha256(log_key).digest()
+ s = " {"
+ s += "\n ".join(_split_and_hexify_binary_data(log_id))
+ s += ",\n"
+ s += _to_loginfo_struct(log)
+ s += ",\n"
+ s += ' base::TimeDelta::FromSeconds(%d)' % (log["disqualified_at"])
+ s += '}'
+ return s
+
+
+def _get_disqualified_log_definitions(logs):
+ """Returns a list of DisqualifiedCTLogInfo definitions."""
+ list_code = []
+ for log in logs:
+ list_code.append(_to_disqualified_loginfo_struct(log))
+ return list_code
+
+
+def _sorted_disqualified_logs(all_logs):
+ return sorted(
+ filter(_is_log_disqualified, all_logs),
+ key=lambda l: hashlib.sha256(
+ base64.decodestring(l["key"])).digest())
+
+
+def _write_qualifying_logs_loginfo(f, qualifying_logs):
+ f.write("// The set of all presently-qualifying CT logs.\n"
+ "// Google provides DNS frontends for all of the logs.\n")
+ f.write("const CTLogInfo kCTLogList[] = {\n")
+ f.write(",\n".join(_get_log_definitions(qualifying_logs)))
+ f.write("\n};\n\n")
+
+
+def generate_cpp_file(input_file, f):
+ """Generate a header file of known logs to be included by Chromium."""
+ json_log_list = json.load(input_file)
+ _write_cpp_header(f)
+
+ logs = json_log_list["logs"]
+
+ # Write the list of currently-qualifying logs.
+ qualifying_logs = [log for log in logs if not _is_log_disqualified(log)]
+ _write_qualifying_logs_loginfo(f, qualifying_logs)
+
+ # Write the IDs of all CT Logs operated by Google
+ google_log_ids = _get_log_ids_for_operator(
+ logs, _find_google_operator_id(json_log_list))
+ f.writelines(_get_log_ids_array(google_log_ids, 'kGoogleLogIDs'))
+
+ # Write the list of all disqualified logs.
+ _write_disqualified_log_info_struct_definition(f)
+ f.write("// The set of all disqualified logs, sorted by |log_id|.\n")
+ f.write("constexpr DisqualifiedCTLogInfo kDisqualifiedCTLogList[] = {\n")
+ f.write(",\n".join(
+ _get_disqualified_log_definitions(
+ _sorted_disqualified_logs(logs))))
+ f.write("\n};\n")
+
+
+def main():
+ if len(sys.argv) != 3:
+ print('usage: %s in_loglist_json out_header' % sys.argv[0])
+ return 1
+ with open(sys.argv[1], 'r') as infile, open(sys.argv[2], 'w') as outfile:
+ generate_cpp_file(infile, outfile)
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py
new file mode 100755
index 00000000000..b4862bffcdf
--- /dev/null
+++ b/chromium/components/certificate_transparency/tools/make_ct_known_logs_list_unittest.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import base64
+import hashlib
+import sys
+import unittest
+import make_ct_known_logs_list
+
+
+def b64e(x):
+ return base64.encodestring(x)
+
+
+class FormattingTest(unittest.TestCase):
+ def testSplitAndHexifyBinData(self):
+ bin_data = ''.join([chr(i) for i in range(32,60)])
+ expected_encoded_array = [
+ ('"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a'
+ '\\x2b\\x2c\\x2d\\x2e\\x2f\\x30"'),
+ '"\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b"']
+ self.assertEqual(
+ make_ct_known_logs_list._split_and_hexify_binary_data(
+ bin_data),
+ expected_encoded_array)
+
+ # This data should fit in exactly one line - 17 bytes.
+ short_bin_data = ''.join([chr(i) for i in range(32, 49)])
+ expected_short_array = [
+ ('"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a'
+ '\\x2b\\x2c\\x2d\\x2e\\x2f\\x30"')]
+ self.assertEqual(
+ make_ct_known_logs_list._split_and_hexify_binary_data(
+ short_bin_data),
+ expected_short_array)
+
+ # This data should fit exactly in two lines - 34 bytes.
+ two_line_data = ''.join([chr(i) for i in range(32, 66)])
+ expected_two_line_data_array = [
+ ('"\\x20\\x21\\x22\\x23\\x24\\x25\\x26\\x27\\x28\\x29\\x2a'
+ '\\x2b\\x2c\\x2d\\x2e\\x2f\\x30"'),
+ ('"\\x31\\x32\\x33\\x34\\x35\\x36\\x37\\x38\\x39\\x3a\\x3b'
+ '\\x3c\\x3d\\x3e\\x3f\\x40\\x41"')]
+ self.assertEqual(
+ make_ct_known_logs_list._split_and_hexify_binary_data(
+ short_bin_data),
+ expected_short_array)
+
+ def testGetLogIDsArray(self):
+ log_ids = ["def", "abc", "ghi"]
+ expected_log_ids_code = [
+ "// The list is sorted.\n",
+ "const char kTestIDs[][4] = {\n",
+ ' "\\x61\\x62\\x63",\n',
+ ' "\\x64\\x65\\x66",\n',
+ ' "\\x67\\x68\\x69"',
+ "};\n\n"]
+ self.assertEqual(
+ make_ct_known_logs_list._get_log_ids_array(
+ log_ids, "kTestIDs"),
+ expected_log_ids_code)
+
+ def testToLogInfoStruct(self):
+ log = {"key": "YWJj",
+ "description": "Test Description",
+ "url": "ct.example.com",
+ "dns_api_endpoint": "dns.ct.example.com"}
+ expected_loginfo = (
+ ' {"\\x61\\x62\\x63",\n 3,\n "Test Description",\n'
+ ' "dns.ct.example.com"}')
+ self.assertEqual(
+ make_ct_known_logs_list._to_loginfo_struct(log),
+ expected_loginfo)
+
+
+class OperatorIDHandlingTest(unittest.TestCase):
+ def testFindingGoogleOperatorID(self):
+ ops_list = {"operators": [
+ {"id": 0, "name": "First"},
+ {"id": 1, "name": "Second"}]}
+ self.assertRaises(
+ RuntimeError,
+ make_ct_known_logs_list._find_google_operator_id,
+ ops_list)
+ ops_list["operators"].append({"id": 2, "name": "Google"})
+ self.assertEqual(
+ make_ct_known_logs_list._find_google_operator_id(ops_list),
+ 2)
+ ops_list["operators"].append({"id": 3, "name": "Google"})
+ self.assertRaises(
+ RuntimeError,
+ make_ct_known_logs_list._find_google_operator_id,
+ ops_list)
+
+ def testCollectingLogIDsByOperator(self):
+ logs = [
+ {"operated_by": (1,), "key": b64e('a')},
+ {"operated_by": (2,), "key": b64e('b')},
+ {"operated_by": (3,), "key": b64e('c')},
+ {"operated_by": (1,), "key": b64e('d')}
+ ]
+ log_ids = make_ct_known_logs_list._get_log_ids_for_operator(logs, 1)
+ self.assertEqual(2, len(log_ids))
+ self.assertItemsEqual(
+ [hashlib.sha256(t).digest() for t in ('a', 'd')],
+ log_ids)
+
+
+class DisqualifiedLogsHandlingTest(unittest.TestCase):
+ def testCorrectlyIdentifiesDisqualifiedLog(self):
+ self.assertTrue(
+ make_ct_known_logs_list._is_log_disqualified(
+ {"disqualified_at" : 12345}))
+ self.assertFalse(
+ make_ct_known_logs_list._is_log_disqualified(
+ {"name" : "example"}))
+
+ def testTranslatingToDisqualifiedLogDefinition(self):
+ log = {"key": "YWJj",
+ "description": "Test Description",
+ "url": "ct.example.com",
+ "dns_api_endpoint": "dns.ct.example.com",
+ "disqualified_at": 1464566400}
+ expected_disqualified_log_info = (
+ ' {"\\xba\\x78\\x16\\xbf\\x8f\\x01\\xcf\\xea\\x41\\x41\\x40'
+ '\\xde\\x5d\\xae\\x22\\x23\\xb0"\n "\\x03\\x61\\xa3\\x96\\x17'
+ '\\x7a\\x9c\\xb4\\x10\\xff\\x61\\xf2\\x00\\x15\\xad",\n {"\\x61'
+ '\\x62\\x63",\n 3,\n "Test Description",\n '
+ '"dns.ct.example.com"},\n '
+ 'base::TimeDelta::FromSeconds(1464566400)}')
+
+ self.assertEqual(
+ make_ct_known_logs_list._to_disqualified_loginfo_struct(log),
+ expected_disqualified_log_info)
+
+ def testSortingAndFilteringDisqualifiedLogs(self):
+ logs = [
+ {"disqualified_at": 1, "key": b64e('a')},
+ {"key": b64e('b')},
+ {"disqualified_at": 3, "key": b64e('c')},
+ {"disqualified_at": 2, "key": b64e('d')},
+ {"key": b64e('e')}
+ ]
+ disqualified_logs = make_ct_known_logs_list._sorted_disqualified_logs(
+ logs)
+ self.assertEqual(3, len(disqualified_logs))
+ self.assertEqual(b64e('d'), disqualified_logs[0]["key"])
+ self.assertEqual(b64e('c'), disqualified_logs[1]["key"])
+ self.assertEqual(b64e('a'), disqualified_logs[2]["key"])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/chromium/components/certificate_transparency/tree_state_tracker.cc b/chromium/components/certificate_transparency/tree_state_tracker.cc
index 25dad103c01..7d29f495f26 100644
--- a/chromium/components/certificate_transparency/tree_state_tracker.cc
+++ b/chromium/components/certificate_transparency/tree_state_tracker.cc
@@ -54,9 +54,6 @@ TreeStateTracker::~TreeStateTracker() {}
void TreeStateTracker::OnSCTVerified(base::StringPiece hostname,
X509Certificate* cert,
const SignedCertificateTimestamp* sct) {
- if (!base::FeatureList::IsEnabled(kCTLogAuditing))
- return;
-
auto it = tree_trackers_.find(sct->log_id);
// Ignore if the SCT is from an unknown log.
if (it == tree_trackers_.end())
diff --git a/chromium/components/chrome_apps/webstore_widget/cws_widget/BUILD.gn b/chromium/components/chrome_apps/webstore_widget/cws_widget/BUILD.gn
new file mode 100644
index 00000000000..e8518784a1a
--- /dev/null
+++ b/chromium/components/chrome_apps/webstore_widget/cws_widget/BUILD.gn
@@ -0,0 +1,50 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":app_installer",
+ ":cws_webview_client",
+ ":cws_widget_container",
+ ":cws_widget_container_error_dialog",
+ ":cws_widget_container_platform_delegate",
+ ]
+}
+
+js_library("app_installer") {
+ deps = [
+ ":cws_widget_container_platform_delegate",
+ ]
+}
+
+js_library("cws_widget_container") {
+ deps = [
+ ":app_installer",
+ ":cws_webview_client",
+ ":cws_widget_container_error_dialog",
+ ]
+}
+
+js_library("cws_widget_container_error_dialog") {
+ deps = [
+ "//ui/webui/resources/js/cr/ui:dialogs",
+ ]
+}
+
+js_library("cws_widget_container_platform_delegate") {
+}
+
+js_library("cws_webview_client") {
+ deps = [
+ ":cws_widget_container_platform_delegate",
+ "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js/cr:event_target",
+ ]
+ externs_list = [
+ "$externs_path/chrome_extensions.js",
+ "../externs/webview_tag.js",
+ ]
+}
diff --git a/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp b/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp
deleted file mode 100644
index b379ef8bb82..00000000000
--- a/chromium/components/chrome_apps/webstore_widget/cws_widget/compiled_resources2.gyp
+++ /dev/null
@@ -1,47 +0,0 @@
-# copyright 2017 the chromium authors. all rights reserved.
-# use of this source code is governed by a bsd-style license that can be
-# found in the license file.
-
-{
- 'targets': [
- {
- 'target_name': 'app_installer',
- 'dependencies': [
- 'cws_widget_container_platform_delegate',
- ],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
- 'target_name': 'cws_widget_container',
- 'dependencies': [
- 'app_installer',
- 'cws_webview_client',
- 'cws_widget_container_error_dialog',
- ],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
- 'target_name': 'cws_widget_container_error_dialog',
- 'dependencies': [
- '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:dialogs',
- ],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
- 'target_name': 'cws_widget_container_platform_delegate',
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- {
- 'target_name': 'cws_webview_client',
- 'dependencies': [
- '../externs/compiled_resources2.gyp:webview_tag',
- '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
- '<(DEPTH)/ui/webui/resources/js/cr/compiled_resources2.gyp:event_target',
- '<(EXTERNS_GYP):chrome_extensions',
- 'cws_widget_container_platform_delegate',
- ],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- ],
-}
-
diff --git a/chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp b/chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp
deleted file mode 100644
index 2b2347cdc02..00000000000
--- a/chromium/components/chrome_apps/webstore_widget/externs/compiled_resources2.gyp
+++ /dev/null
@@ -1,15 +0,0 @@
-# copyright 2017 the chromium authors. all rights reserved.
-# use of this source code is governed by a bsd-style license that can be
-# found in the license file.
-
-{
- 'targets': [
- {
- 'target_name': 'webview_tag',
- 'dependencies': [
- '<(EXTERNS_GYP):chrome_extensions',
- ],
- 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
- }
- ]
-}
diff --git a/chromium/components/chrome_cleaner/OWNERS b/chromium/components/chrome_cleaner/OWNERS
index eec9dad1995..6c83cc7980c 100644
--- a/chromium/components/chrome_cleaner/OWNERS
+++ b/chromium/components/chrome_cleaner/OWNERS
@@ -1,4 +1,4 @@
-file://chrome_cleaner/OWNERS
+file://chrome/chrome_cleaner/OWNERS
# TEAM: security-dev@chromium.org
# COMPONENT: UI>Browser>Preferences>Protector
diff --git a/chromium/components/chrome_cleaner/public/constants/result_codes.h b/chromium/components/chrome_cleaner/public/constants/result_codes.h
index 0450ab3ddb7..09e1f863f68 100644
--- a/chromium/components/chrome_cleaner/public/constants/result_codes.h
+++ b/chromium/components/chrome_cleaner/public/constants/result_codes.h
@@ -211,6 +211,9 @@ enum ResultCodeValues : ResultCode {
// which has been deprecated.
RESULT_CODE_MANUAL_EXECUTION_BY_USER = 52,
+ // Some of the scanning configuration switches have invalid values.
+ RESULT_CODE_INVALID_SCANNING_SWITCHES = 53,
+
// WHEN YOU ADD NEW EXIT CODES, DON'T FORGET TO UPDATE THE MONITORING RULES.
// See http://go/chrome-cleaner-exit-codes. (Google internal only - external
// contributors please ask one of the OWNERS to do the update.)
diff --git a/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn b/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn
index 39cfecc0c61..082d9b33fdc 100644
--- a/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn
+++ b/chromium/components/chrome_cleaner/public/interfaces/BUILD.gn
@@ -8,9 +8,6 @@ mojom("interfaces") {
sources = [
"chrome_prompt.mojom",
]
- deps = [
- "//mojo/common:common_custom_types",
- ]
# NOTE: We avoid scrambling message IDs here because these messages cross an
# IPC boundary to an external program built from a different source tree.
diff --git a/chromium/components/client_update_protocol/ecdsa.cc b/chromium/components/client_update_protocol/ecdsa.cc
index 1af829b76bc..1325d6a76a6 100644
--- a/chromium/components/client_update_protocol/ecdsa.cc
+++ b/chromium/components/client_update_protocol/ecdsa.cc
@@ -170,9 +170,8 @@ bool Ecdsa::ValidateResponse(const base::StringPiece& response_body,
// Initialize the signature verifier.
crypto::SignatureVerifier verifier;
- if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
- &signature.front(), signature.size(),
- &public_key_.front(), public_key_.size())) {
+ if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256, signature,
+ public_key_)) {
DVLOG(1) << "Couldn't init SignatureVerifier.";
return false;
}
@@ -182,8 +181,7 @@ bool Ecdsa::ValidateResponse(const base::StringPiece& response_body,
// * The buffer that the server signed does not match the buffer that the
// client assembled -- implying that either request body or response body
// was modified, or a different nonce value was used.
- verifier.VerifyUpdate(&signed_message_hash.front(),
- signed_message_hash.size());
+ verifier.VerifyUpdate(signed_message_hash);
return verifier.VerifyFinal();
}
diff --git a/chromium/components/client_update_protocol/ecdsa_unittest.cc b/chromium/components/client_update_protocol/ecdsa_unittest.cc
index 8c1e933d903..71c7441c213 100644
--- a/chromium/components/client_update_protocol/ecdsa_unittest.cc
+++ b/chromium/components/client_update_protocol/ecdsa_unittest.cc
@@ -46,7 +46,7 @@ class CupEcdsaTest : public testing::Test {
ASSERT_TRUE(cup_.get());
}
- Ecdsa& CUP() { return *cup_.get(); }
+ Ecdsa& CUP() { return *cup_; }
private:
std::unique_ptr<Ecdsa> cup_;
diff --git a/chromium/components/component_updater/BUILD.gn b/chromium/components/component_updater/BUILD.gn
index be691cd2c9d..0f854c6225f 100644
--- a/chromium/components/component_updater/BUILD.gn
+++ b/chromium/components/component_updater/BUILD.gn
@@ -6,6 +6,8 @@ static_library("component_updater") {
sources = [
"component_installer.cc",
"component_installer.h",
+ "component_updater_command_line_config_policy.cc",
+ "component_updater_command_line_config_policy.h",
"component_updater_paths.cc",
"component_updater_paths.h",
"component_updater_service.cc",
diff --git a/chromium/components/component_updater/component_installer.cc b/chromium/components/component_updater/component_installer.cc
index 93dfe655597..285f27391f3 100644
--- a/chromium/components/component_updater/component_installer.cc
+++ b/chromium/components/component_updater/component_installer.cc
@@ -105,7 +105,7 @@ Result ComponentInstaller::InstallHelper(
if (current_version_.CompareTo(manifest_version) > 0)
return Result(InstallError::VERSION_NOT_UPGRADED);
base::FilePath local_install_path;
- if (!PathService::Get(DIR_COMPONENT_USER, &local_install_path))
+ if (!base::PathService::Get(DIR_COMPONENT_USER, &local_install_path))
return Result(InstallError::NO_DIR_COMPONENT_USER);
local_install_path =
local_install_path.Append(installer_policy_->GetRelativeInstallDir())
@@ -250,14 +250,14 @@ bool ComponentInstaller::FindPreinstallation(
void ComponentInstaller::StartRegistration(
scoped_refptr<RegistrationInfo> registration_info) {
VLOG(1) << __func__ << " for " << installer_policy_->GetName();
- DCHECK(task_runner_.get());
+ DCHECK(task_runner_);
DCHECK(task_runner_->RunsTasksInCurrentSequence());
base::Version latest_version(kNullVersion);
// First check for an installation set up alongside Chrome itself.
base::FilePath root;
- if (PathService::Get(DIR_COMPONENT_PREINSTALLED, &root) &&
+ if (base::PathService::Get(DIR_COMPONENT_PREINSTALLED, &root) &&
FindPreinstallation(root, registration_info)) {
latest_version = registration_info->version;
}
@@ -265,7 +265,7 @@ void ComponentInstaller::StartRegistration(
// If there is a distinct alternate root, check there as well, and override
// anything found in the basic root.
base::FilePath root_alternate;
- if (PathService::Get(DIR_COMPONENT_PREINSTALLED_ALT, &root_alternate) &&
+ if (base::PathService::Get(DIR_COMPONENT_PREINSTALLED_ALT, &root_alternate) &&
root != root_alternate &&
FindPreinstallation(root_alternate, registration_info)) {
latest_version = registration_info->version;
@@ -275,7 +275,7 @@ void ComponentInstaller::StartRegistration(
base::FilePath latest_path;
std::unique_ptr<base::DictionaryValue> latest_manifest;
base::FilePath base_component_dir;
- if (!PathService::Get(DIR_COMPONENT_USER, &base_component_dir))
+ if (!base::PathService::Get(DIR_COMPONENT_USER, &base_component_dir))
return;
base::FilePath base_dir =
base_component_dir.Append(installer_policy_->GetRelativeInstallDir());
@@ -353,12 +353,12 @@ void ComponentInstaller::StartRegistration(
}
void ComponentInstaller::UninstallOnTaskRunner() {
- DCHECK(task_runner_.get());
+ DCHECK(task_runner_);
DCHECK(task_runner_->RunsTasksInCurrentSequence());
// Only try to delete any files that are in our user-level install path.
base::FilePath userInstallPath;
- if (!PathService::Get(DIR_COMPONENT_USER, &userInstallPath))
+ if (!base::PathService::Get(DIR_COMPONENT_USER, &userInstallPath))
return;
if (!userInstallPath.IsParent(current_install_dir_))
return;
diff --git a/chromium/components/component_updater/component_installer_unittest.cc b/chromium/components/component_updater/component_installer_unittest.cc
index 959ec1faad2..daf2ff738bd 100644
--- a/chromium/components/component_updater/component_installer_unittest.cc
+++ b/chromium/components/component_updater/component_installer_unittest.cc
@@ -58,7 +58,7 @@ constexpr base::FilePath::CharType relative_install_dir[] =
base::FilePath test_file(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
@@ -72,7 +72,7 @@ class MockUpdateClient : public UpdateClient {
void Install(const std::string& id,
CrxDataCallback crx_data_callback,
- Callback callback) {
+ Callback callback) override {
DoInstall(id, std::move(crx_data_callback));
std::move(callback).Run(update_client::Error::NONE);
}
@@ -80,7 +80,7 @@ class MockUpdateClient : public UpdateClient {
void Update(const std::vector<std::string>& ids,
CrxDataCallback crx_data_callback,
bool is_foreground,
- Callback callback) {
+ Callback callback) override {
DoUpdate(ids, std::move(crx_data_callback));
std::move(callback).Run(update_client::Error::NONE);
}
@@ -88,7 +88,7 @@ class MockUpdateClient : public UpdateClient {
void SendUninstallPing(const std::string& id,
const base::Version& version,
int reason,
- Callback callback) {
+ Callback callback) override {
DoSendUninstallPing(id, version, reason);
std::move(callback).Run(update_client::Error::NONE);
}
@@ -311,7 +311,7 @@ TEST_F(ComponentInstallerTest, UnpackPathInstallSuccess) {
base::ScopedPathOverride scoped_path_override(DIR_COMPONENT_USER);
base::FilePath base_dir;
- EXPECT_TRUE(PathService::Get(DIR_COMPONENT_USER, &base_dir));
+ EXPECT_TRUE(base::PathService::Get(DIR_COMPONENT_USER, &base_dir));
base_dir = base_dir.Append(relative_install_dir);
EXPECT_TRUE(base::CreateDirectory(base_dir));
installer->Install(
@@ -339,7 +339,7 @@ TEST_F(ComponentInstallerTest, UnpackPathInstallError) {
// Test the precondition that DIR_COMPONENT_USER is not registered with
// the path service.
base::FilePath base_dir;
- EXPECT_FALSE(PathService::Get(DIR_COMPONENT_USER, &base_dir));
+ EXPECT_FALSE(base::PathService::Get(DIR_COMPONENT_USER, &base_dir));
// Calling |Install| fails since DIR_COMPONENT_USER does not exist.
installer->Install(
diff --git a/chromium/components/component_updater/component_updater_command_line_config_policy.cc b/chromium/components/component_updater/component_updater_command_line_config_policy.cc
new file mode 100644
index 00000000000..00ff80c4a23
--- /dev/null
+++ b/chromium/components/component_updater/component_updater_command_line_config_policy.cc
@@ -0,0 +1,121 @@
+// 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 "components/component_updater/component_updater_command_line_config_policy.h"
+
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
+#include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
+#include "components/component_updater/component_updater_switches.h"
+
+namespace component_updater {
+
+namespace {
+
+// Debug values you can pass to --component-updater=value1,value2. Do not
+// use these values in production code.
+
+// Speed up the initial component checking.
+const char kSwitchFastUpdate[] = "fast-update";
+
+// Add "testrequest=1" attribute to the update check request.
+const char kSwitchTestRequestParam[] = "test-request";
+
+// Disables pings. Pings are the requests sent to the update server that report
+// the success or the failure of component install or update attempts.
+const char kSwitchDisablePings[] = "disable-pings";
+
+// Sets the URL for updates.
+const char kSwitchUrlSource[] = "url-source";
+
+// Disables differential updates.
+const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
+
+#if defined(OS_WIN)
+// Disables background downloads.
+const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads";
+#endif // defined(OS_WIN)
+
+// If there is an element of |vec| of the form |test|=.*, returns the right-
+// hand side of that assignment. Otherwise, returns an empty string.
+// The right-hand side may contain additional '=' characters, allowing for
+// further nesting of switch arguments.
+std::string GetSwitchArgument(const std::vector<std::string>& vec,
+ const char* test) {
+ if (vec.empty())
+ return std::string();
+ for (std::vector<std::string>::const_iterator it = vec.begin();
+ it != vec.end(); ++it) {
+ const std::size_t found = it->find("=");
+ if (found != std::string::npos) {
+ if (it->substr(0, found) == test) {
+ return it->substr(found + 1);
+ }
+ }
+ }
+ return std::string();
+}
+
+} // namespace
+
+ComponentUpdaterCommandLineConfigPolicy::
+ ComponentUpdaterCommandLineConfigPolicy(const base::CommandLine* cmdline) {
+ DCHECK(cmdline);
+ // Parse comma-delimited debug flags.
+ std::vector<std::string> switch_values = base::SplitString(
+ cmdline->GetSwitchValueASCII(switches::kComponentUpdater), ",",
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+#if defined(OS_WIN)
+ background_downloads_enabled_ =
+ !base::ContainsValue(switch_values, kSwitchDisableBackgroundDownloads);
+#else
+ background_downloads_enabled_ = false;
+#endif
+
+ deltas_enabled_ =
+ !base::ContainsValue(switch_values, kSwitchDisableDeltaUpdates);
+ fast_update_ = base::ContainsValue(switch_values, kSwitchFastUpdate);
+ pings_enabled_ = !base::ContainsValue(switch_values, kSwitchDisablePings);
+ test_request_ = base::ContainsValue(switch_values, kSwitchTestRequestParam);
+
+ const std::string switch_url_source =
+ GetSwitchArgument(switch_values, kSwitchUrlSource);
+ if (!switch_url_source.empty()) {
+ url_source_override_ = GURL(switch_url_source);
+ DCHECK(url_source_override_.is_valid());
+ }
+}
+
+bool ComponentUpdaterCommandLineConfigPolicy::BackgroundDownloadsEnabled()
+ const {
+ return background_downloads_enabled_;
+}
+
+bool ComponentUpdaterCommandLineConfigPolicy::DeltaUpdatesEnabled() const {
+ return deltas_enabled_;
+}
+
+bool ComponentUpdaterCommandLineConfigPolicy::FastUpdate() const {
+ return fast_update_;
+}
+
+bool ComponentUpdaterCommandLineConfigPolicy::PingsEnabled() const {
+ return pings_enabled_;
+}
+
+bool ComponentUpdaterCommandLineConfigPolicy::TestRequest() const {
+ return test_request_;
+}
+
+GURL ComponentUpdaterCommandLineConfigPolicy::UrlSourceOverride() const {
+ return url_source_override_;
+}
+
+} // namespace component_updater
diff --git a/chromium/components/component_updater/component_updater_command_line_config_policy.h b/chromium/components/component_updater/component_updater_command_line_config_policy.h
new file mode 100644
index 00000000000..e3dbc6701af
--- /dev/null
+++ b/chromium/components/component_updater/component_updater_command_line_config_policy.h
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_COMMAND_LINE_CONFIG_POLICY_H_
+#define COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_COMMAND_LINE_CONFIG_POLICY_H_
+
+#include "base/macros.h"
+#include "components/update_client/command_line_config_policy.h"
+#include "url/gurl.h"
+
+namespace base {
+class CommandLine;
+}
+
+namespace component_updater {
+
+// Component updater config policy implementation.
+class ComponentUpdaterCommandLineConfigPolicy final
+ : public update_client::CommandLineConfigPolicy {
+ public:
+ explicit ComponentUpdaterCommandLineConfigPolicy(
+ const base::CommandLine* cmdline);
+
+ // update_client::CommandLineConfigPolicy overrides.
+ bool BackgroundDownloadsEnabled() const override;
+ bool DeltaUpdatesEnabled() const override;
+ bool FastUpdate() const override;
+ bool PingsEnabled() const override;
+ bool TestRequest() const override;
+ GURL UrlSourceOverride() const override;
+
+ private:
+ bool background_downloads_enabled_ = false;
+ bool deltas_enabled_ = true;
+ bool fast_update_ = false;
+ bool pings_enabled_ = true;
+ bool test_request_ = false;
+ GURL url_source_override_;
+
+ DISALLOW_COPY_AND_ASSIGN(ComponentUpdaterCommandLineConfigPolicy);
+};
+
+} // namespace component_updater
+
+#endif // COMPONENTS_COMPONENT_UPDATER_COMPONENT_UPDATER_COMMAND_LINE_CONFIG_POLICY_H_
diff --git a/chromium/components/component_updater/component_updater_paths.cc b/chromium/components/component_updater/component_updater_paths.cc
index 254c0097ec7..8f962095e25 100644
--- a/chromium/components/component_updater/component_updater_paths.cc
+++ b/chromium/components/component_updater/component_updater_paths.cc
@@ -32,15 +32,16 @@ bool PathProvider(int key, base::FilePath* result) {
switch (key) {
case DIR_COMPONENT_PREINSTALLED:
- return PathService::Get(g_components_preinstalled_root_key, result);
+ return base::PathService::Get(g_components_preinstalled_root_key, result);
case DIR_COMPONENT_PREINSTALLED_ALT:
- return PathService::Get(g_components_preinstalled_root_key_alt, result);
+ return base::PathService::Get(g_components_preinstalled_root_key_alt,
+ result);
case DIR_COMPONENT_USER:
- return PathService::Get(g_components_user_root_key, result);
+ return base::PathService::Get(g_components_user_root_key, result);
}
base::FilePath cur;
- if (!PathService::Get(g_components_user_root_key, &cur))
+ if (!base::PathService::Get(g_components_user_root_key, &cur))
return false;
switch (key) {
@@ -85,7 +86,7 @@ void RegisterPathProvider(int components_preinstalled_root_key,
g_components_preinstalled_root_key = components_preinstalled_root_key;
g_components_preinstalled_root_key_alt = components_preinstalled_root_key_alt;
g_components_user_root_key = components_user_root_key;
- PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
+ base::PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
}
} // namespace component_updater
diff --git a/chromium/components/component_updater/component_updater_service.cc b/chromium/components/component_updater/component_updater_service.cc
index c7ed4b0930a..b684882da8c 100644
--- a/chromium/components/component_updater/component_updater_service.cc
+++ b/chromium/components/component_updater/component_updater_service.cc
@@ -291,7 +291,9 @@ void CrxUpdateService::OnDemandUpdateInternal(const std::string& id,
UMA_HISTOGRAM_ENUMERATION("ComponentUpdater.Calls", UPDATE_TYPE_MANUAL,
UPDATE_TYPE_COUNT);
update_client_->Install(
- id, base::BindOnce(&CrxUpdateService::OnUpdate, base::Unretained(this)),
+ id,
+ base::BindOnce(&CrxUpdateService::GetCrxComponents,
+ base::Unretained(this)),
base::BindOnce(&CrxUpdateService::OnUpdateComplete,
base::Unretained(this), std::move(callback),
base::TimeTicks::Now()));
@@ -316,23 +318,23 @@ bool CrxUpdateService::CheckForUpdates() {
}
if (!unsecure_ids.empty()) {
- update_client_->Update(
- unsecure_ids,
- base::BindOnce(&CrxUpdateService::OnUpdate, base::Unretained(this)),
- false,
- base::BindOnce(&CrxUpdateService::OnUpdateComplete,
- base::Unretained(this), Callback(),
- base::TimeTicks::Now()));
+ update_client_->Update(unsecure_ids,
+ base::BindOnce(&CrxUpdateService::GetCrxComponents,
+ base::Unretained(this)),
+ false,
+ base::BindOnce(&CrxUpdateService::OnUpdateComplete,
+ base::Unretained(this), Callback(),
+ base::TimeTicks::Now()));
}
if (!secure_ids.empty()) {
- update_client_->Update(
- secure_ids,
- base::BindOnce(&CrxUpdateService::OnUpdate, base::Unretained(this)),
- false,
- base::BindOnce(&CrxUpdateService::OnUpdateComplete,
- base::Unretained(this), Callback(),
- base::TimeTicks::Now()));
+ update_client_->Update(secure_ids,
+ base::BindOnce(&CrxUpdateService::GetCrxComponents,
+ base::Unretained(this)),
+ false,
+ base::BindOnce(&CrxUpdateService::OnUpdateComplete,
+ base::Unretained(this), Callback(),
+ base::TimeTicks::Now()));
}
return true;
@@ -358,16 +360,17 @@ bool CrxUpdateService::GetComponentDetails(const std::string& id,
return false;
}
-void CrxUpdateService::OnUpdate(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
+std::vector<std::unique_ptr<CrxComponent>> CrxUpdateService::GetCrxComponents(
+ const std::vector<std::string>& ids) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(components->empty());
-
+ std::vector<std::unique_ptr<CrxComponent>> components;
for (const auto& id : ids) {
- const update_client::CrxComponent* registered_component(GetComponent(id));
- if (registered_component)
- components->push_back(*registered_component);
+ const auto* registered_component = GetComponent(id);
+ components.push_back(registered_component ? std::make_unique<CrxComponent>(
+ *registered_component)
+ : nullptr);
}
+ return components;
}
void CrxUpdateService::OnUpdateComplete(Callback callback,
diff --git a/chromium/components/component_updater/component_updater_service_internal.h b/chromium/components/component_updater/component_updater_service_internal.h
index 7ad6243dca9..1094ffa79bd 100644
--- a/chromium/components/component_updater/component_updater_service_internal.h
+++ b/chromium/components/component_updater/component_updater_service_internal.h
@@ -76,8 +76,8 @@ class CrxUpdateService : public ComponentUpdateService,
const CrxUpdateItem* GetComponentState(const std::string& id) const;
- void OnUpdate(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components);
+ std::vector<std::unique_ptr<CrxComponent>> GetCrxComponents(
+ const std::vector<std::string>& ids);
void OnUpdateComplete(Callback callback,
const base::TimeTicks& start_time,
update_client::Error error);
diff --git a/chromium/components/component_updater/component_updater_service_unittest.cc b/chromium/components/component_updater/component_updater_service_unittest.cc
index c691cc37eb4..864d27fc2f7 100644
--- a/chromium/components/component_updater/component_updater_service_unittest.cc
+++ b/chromium/components/component_updater/component_updater_service_unittest.cc
@@ -51,7 +51,7 @@ class MockInstaller : public CrxInstaller {
// move semantics. This function is a shim to work around it.
void Install(const base::FilePath& unpack_path,
const std::string& public_key,
- update_client::CrxInstaller::Callback callback) {
+ update_client::CrxInstaller::Callback callback) override {
DoInstall(unpack_path, callback);
}
@@ -94,7 +94,7 @@ class MockUpdateClient : public UpdateClient {
void SendUninstallPing(const std::string& id,
const base::Version& version,
int reason,
- Callback callback) {
+ Callback callback) override {
DoSendUninstallPing(id, version, reason);
std::move(callback).Run(update_client::Error::NONE);
}
diff --git a/chromium/components/component_updater/component_updater_url_constants.cc b/chromium/components/component_updater/component_updater_url_constants.cc
index 754f83394e1..f797f7259e3 100644
--- a/chromium/components/component_updater/component_updater_url_constants.cc
+++ b/chromium/components/component_updater/component_updater_url_constants.cc
@@ -14,13 +14,10 @@ namespace component_updater {
//
// The value of |kDefaultUrlSource| can be overridden with
// --component-updater=url-source=someurl.
-const char kUpdaterDefaultUrl[] = "https://clients2.google.com/service/update2";
-
-const char kUpdaterFallbackUrl[] = "http://clients2.google.com/service/update2";
-
-const char kUpdaterDefaultUrlAlt[] =
+const char kUpdaterDefaultUrl[] =
"https://update.googleapis.com/service/update2";
-const char kUpdaterFallbackUrlAlt[] =
+const char kUpdaterFallbackUrl[] =
"http://update.googleapis.com/service/update2";
+
} // namespace component_updater
diff --git a/chromium/components/component_updater/component_updater_url_constants.h b/chromium/components/component_updater/component_updater_url_constants.h
index 51875ad86b8..10f3287d35f 100644
--- a/chromium/components/component_updater/component_updater_url_constants.h
+++ b/chromium/components/component_updater/component_updater_url_constants.h
@@ -9,8 +9,6 @@ namespace component_updater {
extern const char kUpdaterDefaultUrl[];
extern const char kUpdaterFallbackUrl[];
-extern const char kUpdaterDefaultUrlAlt[];
-extern const char kUpdaterFallbackUrlAlt[];
} // namespace component_updater
diff --git a/chromium/components/component_updater/configurator_impl.cc b/chromium/components/component_updater/configurator_impl.cc
index 43e9696ce49..e2182691e55 100644
--- a/chromium/components/component_updater/configurator_impl.cc
+++ b/chromium/components/component_updater/configurator_impl.cc
@@ -8,8 +8,6 @@
#include <algorithm>
-#include "base/command_line.h"
-#include "base/feature_list.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -17,6 +15,7 @@
#include "build/build_config.h"
#include "components/component_updater/component_updater_switches.h"
#include "components/component_updater/component_updater_url_constants.h"
+#include "components/update_client/command_line_config_policy.h"
#include "components/update_client/utils.h"
#include "components/version_info/version_info.h"
@@ -32,86 +31,18 @@ namespace {
const int kDelayOneMinute = 60;
const int kDelayOneHour = kDelayOneMinute * 60;
-// Debug values you can pass to --component-updater=value1,value2. Do not
-// use these values in production code.
-
-// Speed up the initial component checking.
-const char kSwitchFastUpdate[] = "fast-update";
-
-// Add "testrequest=1" attribute to the update check request.
-const char kSwitchRequestParam[] = "test-request";
-
-// Disables pings. Pings are the requests sent to the update server that report
-// the success or the failure of component install or update attempts.
-const char kSwitchDisablePings[] = "disable-pings";
-
-// Sets the URL for updates.
-const char kSwitchUrlSource[] = "url-source";
-
-// Disables differential updates.
-const char kSwitchDisableDeltaUpdates[] = "disable-delta-updates";
-
-#if defined(OS_WIN)
-// Disables background downloads.
-const char kSwitchDisableBackgroundDownloads[] = "disable-background-downloads";
-#endif // defined(OS_WIN)
-
-const base::Feature kAlternateComponentUrls{"AlternateComponentUrls",
- base::FEATURE_ENABLED_BY_DEFAULT};
-
-// If there is an element of |vec| of the form |test|=.*, returns the right-
-// hand side of that assignment. Otherwise, returns an empty string.
-// The right-hand side may contain additional '=' characters, allowing for
-// further nesting of switch arguments.
-std::string GetSwitchArgument(const std::vector<std::string>& vec,
- const char* test) {
- if (vec.empty())
- return std::string();
- for (std::vector<std::string>::const_iterator it = vec.begin();
- it != vec.end(); ++it) {
- const std::size_t found = it->find("=");
- if (found != std::string::npos) {
- if (it->substr(0, found) == test) {
- return it->substr(found + 1);
- }
- }
- }
- return std::string();
-}
-
} // namespace
-ConfiguratorImpl::ConfiguratorImpl(const base::CommandLine* cmdline,
- bool require_encryption)
- : fast_update_(false),
- pings_enabled_(false),
- deltas_enabled_(false),
- background_downloads_enabled_(false),
- require_encryption_(require_encryption) {
- // Parse comma-delimited debug flags.
- std::vector<std::string> switch_values = base::SplitString(
- cmdline->GetSwitchValueASCII(switches::kComponentUpdater), ",",
- base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- fast_update_ = base::ContainsValue(switch_values, kSwitchFastUpdate);
- pings_enabled_ = !base::ContainsValue(switch_values, kSwitchDisablePings);
- deltas_enabled_ =
- !base::ContainsValue(switch_values, kSwitchDisableDeltaUpdates);
-
-#if defined(OS_WIN)
- background_downloads_enabled_ =
- !base::ContainsValue(switch_values, kSwitchDisableBackgroundDownloads);
-#else
- background_downloads_enabled_ = false;
-#endif
-
- const std::string switch_url_source =
- GetSwitchArgument(switch_values, kSwitchUrlSource);
- if (!switch_url_source.empty()) {
- url_source_override_ = GURL(switch_url_source);
- DCHECK(url_source_override_.is_valid());
- }
-
- if (base::ContainsValue(switch_values, kSwitchRequestParam))
+ConfiguratorImpl::ConfiguratorImpl(
+ const update_client::CommandLineConfigPolicy& config_policy,
+ bool require_encryption)
+ : background_downloads_enabled_(config_policy.BackgroundDownloadsEnabled()),
+ deltas_enabled_(config_policy.DeltaUpdatesEnabled()),
+ fast_update_(config_policy.FastUpdate()),
+ pings_enabled_(config_policy.PingsEnabled()),
+ require_encryption_(require_encryption),
+ url_source_override_(config_policy.UrlSourceOverride()) {
+ if (config_policy.TestRequest())
extra_info_ += "testrequest=\"1\"";
}
@@ -134,20 +65,11 @@ int ConfiguratorImpl::UpdateDelay() const {
}
std::vector<GURL> ConfiguratorImpl::UpdateUrl() const {
- std::vector<GURL> urls;
if (url_source_override_.is_valid()) {
- urls.push_back(GURL(url_source_override_));
- return urls;
- }
-
- if (base::FeatureList::IsEnabled(kAlternateComponentUrls)) {
- urls.push_back(GURL(kUpdaterDefaultUrlAlt));
- urls.push_back(GURL(kUpdaterFallbackUrlAlt));
- } else {
- urls.push_back(GURL(kUpdaterDefaultUrl));
- urls.push_back(GURL(kUpdaterFallbackUrl));
+ return {GURL(url_source_override_)};
}
+ std::vector<GURL> urls{GURL(kUpdaterDefaultUrl), GURL(kUpdaterFallbackUrl)};
if (require_encryption_)
update_client::RemoveUnsecureUrls(&urls);
diff --git a/chromium/components/component_updater/configurator_impl.h b/chromium/components/component_updater/configurator_impl.h
index 6a680905113..24a68e6e98e 100644
--- a/chromium/components/component_updater/configurator_impl.h
+++ b/chromium/components/component_updater/configurator_impl.h
@@ -14,17 +14,20 @@
#include "url/gurl.h"
namespace base {
-class CommandLine;
class Version;
}
+namespace update_client {
+class CommandLineConfigPolicy;
+}
+
namespace component_updater {
// Helper class for the implementations of update_client::Configurator.
// Can be used both on iOS and other platforms.
class ConfiguratorImpl {
public:
- ConfiguratorImpl(const base::CommandLine* cmdline,
+ ConfiguratorImpl(const update_client::CommandLineConfigPolicy& config_policy,
bool require_encryption);
~ConfiguratorImpl();
@@ -84,12 +87,12 @@ class ConfiguratorImpl {
private:
std::string extra_info_;
- GURL url_source_override_;
+ bool background_downloads_enabled_;
+ bool deltas_enabled_;
bool fast_update_;
bool pings_enabled_;
- bool deltas_enabled_;
- bool background_downloads_enabled_;
bool require_encryption_;
+ GURL url_source_override_;
DISALLOW_COPY_AND_ASSIGN(ConfiguratorImpl);
};
diff --git a/chromium/components/component_updater/configurator_impl_unittest.cc b/chromium/components/component_updater/configurator_impl_unittest.cc
index 35a41bea336..b0b10f5361b 100644
--- a/chromium/components/component_updater/configurator_impl_unittest.cc
+++ b/chromium/components/component_updater/configurator_impl_unittest.cc
@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "base/macros.h"
+#include "components/component_updater/component_updater_command_line_config_policy.h"
#include "components/component_updater/configurator_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,8 +19,6 @@ const int kDelayOneHour = kDelayOneMinute * 60;
} // namespace
-using base::CommandLine;
-
class ComponentUpdaterConfiguratorImplTest : public testing::Test {
public:
ComponentUpdaterConfiguratorImplTest() {}
@@ -32,8 +31,8 @@ class ComponentUpdaterConfiguratorImplTest : public testing::Test {
TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdate) {
// Test the default timing values when no command line argument is present.
base::CommandLine cmdline(base::CommandLine::NO_PROGRAM);
- std::unique_ptr<ConfiguratorImpl> config =
- std::make_unique<ConfiguratorImpl>(&cmdline, false);
+ std::unique_ptr<ConfiguratorImpl> config = std::make_unique<ConfiguratorImpl>(
+ ComponentUpdaterCommandLineConfigPolicy(&cmdline), false);
CHECK_EQ(6 * kDelayOneMinute, config->InitialDelay());
CHECK_EQ(5 * kDelayOneHour, config->NextCheckDelay());
CHECK_EQ(30 * kDelayOneMinute, config->OnDemandDelay());
@@ -41,7 +40,48 @@ TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdate) {
// Test the fast-update timings.
cmdline.AppendSwitchASCII("--component-updater", "fast-update");
- config = std::make_unique<ConfiguratorImpl>(&cmdline, false);
+ config = std::make_unique<ConfiguratorImpl>(
+ ComponentUpdaterCommandLineConfigPolicy(&cmdline), false);
+ CHECK_EQ(10, config->InitialDelay());
+ CHECK_EQ(5 * kDelayOneHour, config->NextCheckDelay());
+ CHECK_EQ(2, config->OnDemandDelay());
+ CHECK_EQ(10, config->UpdateDelay());
+}
+
+TEST_F(ComponentUpdaterConfiguratorImplTest, FastUpdateWithCustomPolicy) {
+ // Test the default timing values when no command line argument is present
+ // (default).
+ class DefaultCommandLineConfigPolicy
+ : public update_client::CommandLineConfigPolicy {
+ public:
+ DefaultCommandLineConfigPolicy() {}
+
+ // update_client::CommandLineConfigPolicy overrides.
+ bool BackgroundDownloadsEnabled() const override { return false; }
+ bool DeltaUpdatesEnabled() const override { return false; }
+ bool FastUpdate() const override { return false; }
+ bool PingsEnabled() const override { return false; }
+ bool TestRequest() const override { return false; }
+ GURL UrlSourceOverride() const override { return GURL(); }
+ };
+
+ std::unique_ptr<ConfiguratorImpl> config = std::make_unique<ConfiguratorImpl>(
+ DefaultCommandLineConfigPolicy(), false);
+ CHECK_EQ(6 * kDelayOneMinute, config->InitialDelay());
+ CHECK_EQ(5 * kDelayOneHour, config->NextCheckDelay());
+ CHECK_EQ(30 * kDelayOneMinute, config->OnDemandDelay());
+ CHECK_EQ(15 * kDelayOneMinute, config->UpdateDelay());
+
+ // Test the fast-update timings.
+ class FastUpdateCommandLineConfigurator
+ : public DefaultCommandLineConfigPolicy {
+ public:
+ FastUpdateCommandLineConfigurator() {}
+
+ bool FastUpdate() const override { return true; }
+ };
+ config = std::make_unique<ConfiguratorImpl>(
+ FastUpdateCommandLineConfigurator(), false);
CHECK_EQ(10, config->InitialDelay());
CHECK_EQ(5 * kDelayOneHour, config->NextCheckDelay());
CHECK_EQ(2, config->OnDemandDelay());
diff --git a/chromium/components/component_updater/mock_component_updater_service.h b/chromium/components/component_updater/mock_component_updater_service.h
index 9365852b8c6..508863cd1ed 100644
--- a/chromium/components/component_updater/mock_component_updater_service.h
+++ b/chromium/components/component_updater/mock_component_updater_service.h
@@ -28,7 +28,8 @@ class MockComponentUpdateService : public ComponentUpdateService {
MockComponentUpdateService();
~MockComponentUpdateService() override;
- void MaybeThrottle(const std::string& id, base::OnceClosure callback) {
+ void MaybeThrottle(const std::string& id,
+ base::OnceClosure callback) override {
DoMaybeThrottle(id, std::move(callback));
}
diff --git a/chromium/components/component_updater/pref_names.cc b/chromium/components/component_updater/pref_names.cc
index ba038fc00d3..def66fc7258 100644
--- a/chromium/components/component_updater/pref_names.cc
+++ b/chromium/components/component_updater/pref_names.cc
@@ -27,6 +27,12 @@ const char kSwReporterLastTimeTriggered[] =
const char kSwReporterLastTimeSentReport[] =
"software_reporter.last_time_sent_report";
+// Enable running the SwReporter.
+const char kSwReporterEnabled[] = "software_reporter.enabled";
+
+// Control whether SwReporter results are reported to Google.
+const char kSwReporterReportingEnabled[] = "software_reporter.reporting";
+
// The version string of the reporter that triggered an SRT prompt. An empty
// string when the prompt wasn't shown yet. Stored in the protected prefs of the
// profile that owns the browser where the prompt was shown.
diff --git a/chromium/components/component_updater/pref_names.h b/chromium/components/component_updater/pref_names.h
index 1d3a2c86f00..f9fc109ee5b 100644
--- a/chromium/components/component_updater/pref_names.h
+++ b/chromium/components/component_updater/pref_names.h
@@ -17,6 +17,8 @@ extern const char kRecoveryComponentUnpackPath[];
extern const char kSwReporterLastExitCode[];
extern const char kSwReporterLastTimeTriggered[];
extern const char kSwReporterLastTimeSentReport[];
+extern const char kSwReporterEnabled[];
+extern const char kSwReporterReportingEnabled[];
// Profile prefs.
extern const char kSwReporterPromptReason[];
diff --git a/chromium/components/components_locale_settings.grd b/chromium/components/components_locale_settings.grd
index 1db75317168..a9ffdfb30fb 100644
--- a/chromium/components/components_locale_settings.grd
+++ b/chromium/components/components_locale_settings.grd
@@ -250,7 +250,7 @@
<messages fallback_to_english="true">
<!-- The default value for HTTP Accept-Language header. -->
- <message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true" formatter_data="android_java">
+ <message name="IDS_ACCEPT_LANGUAGES" use_name_for_id="true">
en-US,en
</message>
diff --git a/chromium/components/components_strings.grd b/chromium/components/components_strings.grd
index 3b1c6bfa3fd..4ee9c7b4d40 100644
--- a/chromium/components/components_strings.grd
+++ b/chromium/components/components_strings.grd
@@ -203,9 +203,8 @@
<part file="password_manager_strings.grdp" />
<part file="payments_strings.grdp" />
<part file="pdf_strings.grdp" />
- <part file="physical_web_ui_strings.grdp" />
<part file="policy_strings.grdp" />
- <part file="printing_strings.grdp" />
+ <part file="printing_component_strings.grdp" />
<part file="reset_password_strings.grdp" />
<part file="safe_browsing_strings.grdp" />
<part file="security_interstitials_strings.grdp" />
@@ -239,9 +238,16 @@
<message name="IDS_SAVE" desc="Used on a button to save information you are editing.">
Save
</message>
- <message name="IDS_NO_THANKS" desc="Used to dismiss various prompts.">
- No thanks
- </message>
+ <if expr="not use_titlecase">
+ <message name="IDS_NO_THANKS" desc="Used to dismiss various prompts.">
+ No thanks
+ </message>
+ </if>
+ <if expr="use_titlecase">
+ <message name="IDS_NO_THANKS" desc="In Title Case: Used to dismiss various prompts.">
+ No Thanks
+ </message>
+ </if>
<if expr="not use_titlecase">
<message name="IDS_NOT_NOW" desc="Used on a button that avoids taking a suggested action. The action will likely be suggested again or automatically taken later.">
Not now
diff --git a/chromium/components/consent_auditor/consent_auditor.cc b/chromium/components/consent_auditor/consent_auditor.cc
index e2961da5492..24f7f1fc47f 100644
--- a/chromium/components/consent_auditor/consent_auditor.cc
+++ b/chromium/components/consent_auditor/consent_auditor.cc
@@ -16,7 +16,8 @@
#include "components/sync/model/model_type_sync_bridge.h"
#include "components/sync/user_events/user_event_service.h"
-using UserEventSpecifics = sync_pb::UserEventSpecifics;
+using sync_pb::UserConsentTypes;
+using sync_pb::UserEventSpecifics;
namespace consent_auditor {
@@ -43,16 +44,16 @@ UserEventSpecifics::UserConsent::Feature FeatureToProtoEnum(
return UserEventSpecifics::UserConsent::FEATURE_UNSPECIFIED;
}
-UserEventSpecifics::UserConsent::ConsentStatus StatusToProtoEnum(
+UserConsentTypes::ConsentStatus StatusToProtoEnum(
consent_auditor::ConsentStatus status) {
switch (status) {
case consent_auditor::ConsentStatus::NOT_GIVEN:
- return UserEventSpecifics::UserConsent::NOT_GIVEN;
+ return UserConsentTypes::NOT_GIVEN;
case consent_auditor::ConsentStatus::GIVEN:
- return UserEventSpecifics::UserConsent::GIVEN;
+ return UserConsentTypes::GIVEN;
}
NOTREACHED();
- return UserEventSpecifics::UserConsent::CONSENT_STATUS_UNSPECIFIED;
+ return UserConsentTypes::CONSENT_STATUS_UNSPECIFIED;
}
} // namespace
diff --git a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
index 8bb2f98613c..a8758321202 100644
--- a/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_origin_identifier_value_map.cc
@@ -41,7 +41,7 @@ class RuleIteratorImpl : public RuleIterator {
DCHECK(current_rule_->second.value.get());
Rule to_return(current_rule_->first.primary_pattern,
current_rule_->first.secondary_pattern,
- current_rule_->second.value.get()->DeepCopy());
+ current_rule_->second.value->DeepCopy());
++current_rule_;
return to_return;
}
@@ -83,7 +83,7 @@ bool OriginIdentifierValueMap::PatternPair::operator<(
std::tie(other.primary_pattern, other.secondary_pattern);
}
-OriginIdentifierValueMap::ValueEntry::ValueEntry() : last_modified(), value(){};
+OriginIdentifierValueMap::ValueEntry::ValueEntry(){};
OriginIdentifierValueMap::ValueEntry::~ValueEntry(){};
diff --git a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
index 823300130bf..34f4a872bfc 100644
--- a/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_policy_provider.cc
@@ -57,6 +57,10 @@ const PrefsForManagedContentSettingsMapEntry
{prefs::kManagedPopupsAllowedForUrls, CONTENT_SETTINGS_TYPE_POPUPS,
CONTENT_SETTING_ALLOW},
{prefs::kManagedPopupsBlockedForUrls, CONTENT_SETTINGS_TYPE_POPUPS,
+ CONTENT_SETTING_BLOCK},
+ {prefs::kManagedWebUsbAskForUrls, CONTENT_SETTINGS_TYPE_USB_GUARD,
+ CONTENT_SETTING_ASK},
+ {prefs::kManagedWebUsbBlockedForUrls, CONTENT_SETTINGS_TYPE_USB_GUARD,
CONTENT_SETTING_BLOCK}};
} // namespace
@@ -111,6 +115,8 @@ void PolicyProvider::RegisterProfilePrefs(
registry->RegisterListPref(prefs::kManagedPluginsBlockedForUrls);
registry->RegisterListPref(prefs::kManagedPopupsAllowedForUrls);
registry->RegisterListPref(prefs::kManagedPopupsBlockedForUrls);
+ registry->RegisterListPref(prefs::kManagedWebUsbAskForUrls);
+ registry->RegisterListPref(prefs::kManagedWebUsbBlockedForUrls);
// Preferences for default content setting policies. If a policy is not set of
// the corresponding preferences below is set to CONTENT_SETTING_DEFAULT.
registry->RegisterIntegerPref(prefs::kManagedDefaultAdsSetting,
@@ -162,6 +168,8 @@ PolicyProvider::PolicyProvider(PrefService* prefs) : prefs_(prefs) {
pref_change_registrar_.Add(prefs::kManagedPluginsBlockedForUrls, callback);
pref_change_registrar_.Add(prefs::kManagedPopupsAllowedForUrls, callback);
pref_change_registrar_.Add(prefs::kManagedPopupsBlockedForUrls, callback);
+ pref_change_registrar_.Add(prefs::kManagedWebUsbAskForUrls, callback);
+ pref_change_registrar_.Add(prefs::kManagedWebUsbBlockedForUrls, callback);
// The following preferences are only used to indicate if a default content
// setting is managed and to hold the managed default setting value. If the
// value for any of the following preferences is set then the corresponding
@@ -292,6 +300,7 @@ void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
// }
// }
// }
+ std::unordered_map<std::string, base::DictionaryValue> filters_map;
for (size_t j = 0; j < pattern_filter_str_list->GetSize(); ++j) {
std::string pattern_filter_json;
if (!pattern_filter_str_list->GetString(j, &pattern_filter_json)) {
@@ -307,35 +316,43 @@ void PolicyProvider::GetAutoSelectCertificateSettingsFromPreferences(
continue;
}
- std::unique_ptr<base::DictionaryValue> pattern_filter_pair(
- static_cast<base::DictionaryValue*>(value.release()));
- std::string pattern_str;
- bool pattern_read = pattern_filter_pair->GetStringWithoutPathExpansion(
- "pattern", &pattern_str);
- base::DictionaryValue* cert_filter = nullptr;
- pattern_filter_pair->GetDictionaryWithoutPathExpansion("filter",
- &cert_filter);
- if (!pattern_read || !cert_filter) {
+ std::unique_ptr<base::DictionaryValue> pattern_filter_pair =
+ base::DictionaryValue::From(std::move(value));
+ base::Value* pattern = pattern_filter_pair->FindKey("pattern");
+ base::Value* filter = pattern_filter_pair->FindKey("filter");
+ if (!pattern || !filter) {
VLOG(1) << "Ignoring invalid certificate auto select setting. Reason:"
" Missing pattern or filter.";
continue;
}
+ std::string pattern_str = pattern->GetString();
+
+ if (filters_map.find(pattern_str) == filters_map.end())
+ filters_map[pattern_str].SetKey("filters", base::ListValue());
+
+ // Don't pass removed values from |value|, because base::Values read with
+ // JSONReader use a shared string buffer. Instead, Clone() here.
+ filters_map[pattern_str].FindKey("filters")->GetList().push_back(
+ filter->Clone());
+ }
+
+ for (const auto& it : filters_map) {
+ const std::string& pattern_str = it.first;
+ const base::DictionaryValue& setting = it.second;
ContentSettingsPattern pattern =
ContentSettingsPattern::FromString(pattern_str);
// Ignore invalid patterns.
if (!pattern.IsValid()) {
VLOG(1) << "Ignoring invalid certificate auto select setting:"
- " Invalid content settings pattern: " << pattern.ToString();
+ " Invalid content settings pattern: "
+ << pattern.ToString();
continue;
}
- // Don't pass removed values from |value|, because base::Values read with
- // JSONReader use a shared string buffer. Instead, DeepCopy here.
- // Don't set a timestamp for policy settings.
value_map->SetValue(pattern, ContentSettingsPattern::Wildcard(),
CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
- std::string(), base::Time(), cert_filter->DeepCopy());
+ std::string(), base::Time(), setting.DeepCopy());
}
}
diff --git a/chromium/components/content_settings/core/browser/content_settings_pref.cc b/chromium/components/content_settings/core/browser/content_settings_pref.cc
index 7f91a3cf2bc..4565d0fb424 100644
--- a/chromium/components/content_settings/core/browser/content_settings_pref.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_pref.cc
@@ -130,7 +130,7 @@ bool ContentSettingsPref::SetWebsiteSetting(
{
base::AutoLock auto_lock(lock_);
- if (value.get()) {
+ if (value) {
map_to_modify->SetValue(primary_pattern, secondary_pattern, content_type_,
resource_identifier, modified_time,
value->DeepCopy());
diff --git a/chromium/components/content_settings/core/browser/content_settings_utils.cc b/chromium/components/content_settings/core/browser/content_settings_utils.cc
index 721ab4378d2..6f087c5cb38 100644
--- a/chromium/components/content_settings/core/browser/content_settings_utils.cc
+++ b/chromium/components/content_settings/core/browser/content_settings_utils.cc
@@ -144,6 +144,8 @@ void GetRendererContentSettingRules(const HostContentSettingsMap* map,
map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_CLIENT_HINTS,
ResourceIdentifier(),
&(rules->client_hints_rules));
+ map->GetSettingsForOneType(CONTENT_SETTINGS_TYPE_POPUPS, ResourceIdentifier(),
+ &(rules->popup_redirect_rules));
}
bool IsMorePermissive(ContentSetting a, ContentSetting b) {
diff --git a/chromium/components/content_settings/core/browser/cookie_settings.cc b/chromium/components/content_settings/core/browser/cookie_settings.cc
index 1c238600a83..a1252ad44ce 100644
--- a/chromium/components/content_settings/core/browser/cookie_settings.cc
+++ b/chromium/components/content_settings/core/browser/cookie_settings.cc
@@ -189,7 +189,7 @@ void CookieSettings::GetCookieSetting(const GURL& url,
net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES);
// We should always have a value, at least from the default provider.
- DCHECK(value.get());
+ DCHECK(value);
ContentSetting setting = ValueToContentSetting(value.get());
bool block =
block_third && policy.CanAccessCookies(url, first_party_url) != net::OK;
diff --git a/chromium/components/content_settings/core/browser/host_content_settings_map.cc b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
index 47a277e9bf0..d45b95a6d6d 100644
--- a/chromium/components/content_settings/core/browser/host_content_settings_map.cc
+++ b/chromium/components/content_settings/core/browser/host_content_settings_map.cc
@@ -696,9 +696,9 @@ void HostContentSettingsMap::AddSettingsForOneType(
while (rule_iterator->HasNext()) {
const content_settings::Rule& rule = rule_iterator->Next();
- settings->push_back(ContentSettingPatternSource(
+ settings->emplace_back(
rule.primary_pattern, rule.secondary_pattern, rule.value->Clone(),
- kProviderNamesSourceMap[provider_type].provider_name, incognito));
+ kProviderNamesSourceMap[provider_type].provider_name, incognito);
}
}
@@ -850,7 +850,7 @@ HostContentSettingsMap::GetContentSettingValueAndPatterns(
*primary_pattern = rule.primary_pattern;
if (secondary_pattern)
*secondary_pattern = rule.secondary_pattern;
- return base::WrapUnique(rule.value.get()->DeepCopy());
+ return base::WrapUnique(rule.value->DeepCopy());
}
}
}
diff --git a/chromium/components/content_settings/core/common/content_settings.h b/chromium/components/content_settings/core/common/content_settings.h
index b1bb1a5b137..d99ee45df13 100644
--- a/chromium/components/content_settings/core/common/content_settings.h
+++ b/chromium/components/content_settings/core/common/content_settings.h
@@ -71,6 +71,7 @@ struct RendererContentSettingRules {
ContentSettingsForOneType script_rules;
ContentSettingsForOneType autoplay_rules;
ContentSettingsForOneType client_hints_rules;
+ ContentSettingsForOneType popup_redirect_rules;
};
namespace content_settings {
diff --git a/chromium/components/content_settings/core/common/content_settings.mojom b/chromium/components/content_settings/core/common/content_settings.mojom
index f06434f6474..3635caff1e2 100644
--- a/chromium/components/content_settings/core/common/content_settings.mojom
+++ b/chromium/components/content_settings/core/common/content_settings.mojom
@@ -72,4 +72,5 @@ struct RendererContentSettingRules {
array<ContentSettingPatternSource> script_rules;
array<ContentSettingPatternSource> autoplay_rules;
array<ContentSettingPatternSource> client_hints_rules;
+ array<ContentSettingPatternSource> popup_redirect_rules;
};
diff --git a/chromium/components/content_settings/core/common/content_settings_struct_traits.cc b/chromium/components/content_settings/core/common/content_settings_struct_traits.cc
index f3426ddeea0..74291e690bc 100644
--- a/chromium/components/content_settings/core/common/content_settings_struct_traits.cc
+++ b/chromium/components/content_settings/core/common/content_settings_struct_traits.cc
@@ -100,7 +100,8 @@ bool StructTraits<content_settings::mojom::RendererContentSettingRulesDataView,
return data.ReadImageRules(&out->image_rules) &&
data.ReadScriptRules(&out->script_rules) &&
data.ReadAutoplayRules(&out->autoplay_rules) &&
- data.ReadClientHintsRules(&out->client_hints_rules);
+ data.ReadClientHintsRules(&out->client_hints_rules) &&
+ data.ReadPopupRedirectRules(&out->popup_redirect_rules);
}
} // namespace mojo
diff --git a/chromium/components/content_settings/core/common/content_settings_struct_traits.h b/chromium/components/content_settings/core/common/content_settings_struct_traits.h
index 0da14fdf14c..55d50d612b0 100644
--- a/chromium/components/content_settings/core/common/content_settings_struct_traits.h
+++ b/chromium/components/content_settings/core/common/content_settings_struct_traits.h
@@ -140,6 +140,11 @@ struct StructTraits<
return r.client_hints_rules;
}
+ static const std::vector<ContentSettingPatternSource>& popup_redirect_rules(
+ const RendererContentSettingRules& r) {
+ return r.popup_redirect_rules;
+ }
+
static bool Read(
content_settings::mojom::RendererContentSettingRulesDataView data,
RendererContentSettingRules* out);
diff --git a/chromium/components/content_settings/core/common/content_settings_types.h b/chromium/components/content_settings/core/common/content_settings_types.h
index 9641d0a4ee2..c482a4dd5b7 100644
--- a/chromium/components/content_settings/core/common/content_settings_types.h
+++ b/chromium/components/content_settings/core/common/content_settings_types.h
@@ -23,6 +23,11 @@ enum ContentSettingsType {
CONTENT_SETTINGS_TYPE_IMAGES,
CONTENT_SETTINGS_TYPE_JAVASCRIPT,
CONTENT_SETTINGS_TYPE_PLUGINS,
+
+ // This setting governs both popups and unwanted redirects like tab-unders and
+ // framebusting.
+ // TODO(csharrison): Consider renaming it to POPUPS_AND_REDIRECTS, but it
+ // might not be worth the trouble.
CONTENT_SETTINGS_TYPE_POPUPS,
CONTENT_SETTINGS_TYPE_GEOLOCATION,
CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
diff --git a/chromium/components/content_settings/core/common/pref_names.cc b/chromium/components/content_settings/core/common/pref_names.cc
index d33b6a706e9..ed5f931ae47 100644
--- a/chromium/components/content_settings/core/common/pref_names.cc
+++ b/chromium/components/content_settings/core/common/pref_names.cc
@@ -73,4 +73,8 @@ const char kManagedPopupsAllowedForUrls[] =
"profile.managed_popups_allowed_for_urls";
const char kManagedPopupsBlockedForUrls[] =
"profile.managed_popups_blocked_for_urls";
+const char kManagedWebUsbAskForUrls[] = "profile.managed_web_usb_ask_for_urls";
+const char kManagedWebUsbBlockedForUrls[] =
+ "profile.managed_web_usb_blocked_for_urls";
+
} // namespace prefs
diff --git a/chromium/components/content_settings/core/common/pref_names.h b/chromium/components/content_settings/core/common/pref_names.h
index fe338041af9..af5e4db9d87 100644
--- a/chromium/components/content_settings/core/common/pref_names.h
+++ b/chromium/components/content_settings/core/common/pref_names.h
@@ -43,6 +43,8 @@ extern const char kManagedPopupsBlockedForUrls[];
extern const char kManagedNotificationsAllowedForUrls[];
extern const char kManagedNotificationsBlockedForUrls[];
extern const char kManagedAutoSelectCertificateForUrls[];
+extern const char kManagedWebUsbAskForUrls[];
+extern const char kManagedWebUsbBlockedForUrls[];
} // namespace prefs
diff --git a/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc b/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc
index 9e3d7912643..1fc9e49e63d 100644
--- a/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc
+++ b/chromium/components/contextual_search/browser/ctr_aggregator_unittest.cc
@@ -48,7 +48,7 @@ class CtrAggregatorTest : public testing::Test {
void SetUp() override {
storage_.reset(new WeeklyActivityStorageStub());
- aggregator_.reset(new CtrAggregator(*storage_.get(), kTestWeek));
+ aggregator_.reset(new CtrAggregator(*storage_, kTestWeek));
}
void TearDown() override {}
diff --git a/chromium/components/crash/OWNERS b/chromium/components/crash/OWNERS
index 15476a224b4..dc5fda65ab3 100644
--- a/chromium/components/crash/OWNERS
+++ b/chromium/components/crash/OWNERS
@@ -5,4 +5,7 @@ rsesek@chromium.org
scottmg@chromium.org
thestig@chromium.org
+# For Android-specific changes:
+per-file *android*=file://components/crash/android/OWNERS
+
# COMPONENT: Internals>CrashReporting
diff --git a/chromium/components/crash/android/OWNERS b/chromium/components/crash/android/OWNERS
index 6b952ef4a27..9c568c2eec8 100644
--- a/chromium/components/crash/android/OWNERS
+++ b/chromium/components/crash/android/OWNERS
@@ -1,4 +1,4 @@
-# Java readability
+# Java readability and UMA
mariakhomenko@chromium.org
# Crash uploading mechanism
diff --git a/chromium/components/crash/content/app/BUILD.gn b/chromium/components/crash/content/app/BUILD.gn
index 79aa52b1083..4d9d30aa891 100644
--- a/chromium/components/crash/content/app/BUILD.gn
+++ b/chromium/components/crash/content/app/BUILD.gn
@@ -98,6 +98,13 @@ static_library("app") {
]
}
+ if (is_mac) {
+ deps += [
+ "//third_party/crashpad/crashpad/minidump",
+ "//third_party/crashpad/crashpad/snapshot",
+ ]
+ }
+
if (is_android) {
libs = [ "log" ]
}
diff --git a/chromium/components/crash/content/app/breakpad_linux.cc b/chromium/components/crash/content/app/breakpad_linux.cc
index 1dde47fb6bb..76f15cb5b51 100644
--- a/chromium/components/crash/content/app/breakpad_linux.cc
+++ b/chromium/components/crash/content/app/breakpad_linux.cc
@@ -776,7 +776,7 @@ void EnableCrashDumping(bool unattended) {
g_is_crash_reporter_enabled = true;
base::FilePath tmp_path("/tmp");
- PathService::Get(base::DIR_TEMP, &tmp_path);
+ base::PathService::Get(base::DIR_TEMP, &tmp_path);
base::FilePath dumps_path(tmp_path);
if (GetCrashReporterClient()->GetCrashDumpLocation(&dumps_path)) {
@@ -992,8 +992,7 @@ class NonBrowserCrashHandler : public google_breakpad::CrashGenerationClient {
public:
NonBrowserCrashHandler()
: server_fd_(base::GlobalDescriptors::GetInstance()->Get(
- kCrashDumpSignal)) {
- }
+ service_manager::kCrashDumpSignal)) {}
~NonBrowserCrashHandler() override {}
diff --git a/chromium/components/crash/content/app/breakpad_win.cc b/chromium/components/crash/content/app/breakpad_win.cc
index 06e38f9a49a..382b79e970a 100644
--- a/chromium/components/crash/content/app/breakpad_win.cc
+++ b/chromium/components/crash/content/app/breakpad_win.cc
@@ -91,8 +91,8 @@ const wchar_t kChromePipeName[] = L"\\\\.\\pipe\\ChromeCrashServices";
// This is the well known SID for the system principal.
const wchar_t kSystemPrincipalSid[] = L"S-1-5-18";
-google_breakpad::ExceptionHandler* g_breakpad = NULL;
-google_breakpad::ExceptionHandler* g_dumphandler_no_crash = NULL;
+google_breakpad::ExceptionHandler* g_breakpad = nullptr;
+google_breakpad::ExceptionHandler* g_dumphandler_no_crash = nullptr;
#if !defined(_WIN64)
EXCEPTION_POINTERS g_surrogate_exception_pointers = {0};
@@ -102,7 +102,7 @@ CONTEXT g_surrogate_context = {0};
typedef NTSTATUS (WINAPI* NtTerminateProcessPtr)(HANDLE ProcessHandle,
NTSTATUS ExitStatus);
-char* g_real_terminate_process_stub = NULL;
+char* g_real_terminate_process_stub = nullptr;
} // namespace
@@ -133,8 +133,8 @@ extern "C" HANDLE __declspec(dllexport) __cdecl InjectDumpForHungInput(
HANDLE process) {
// |serialized_crash_keys| is not propagated in breakpad but is in crashpad
// since breakpad is deprecated.
- return CreateRemoteThread(process, NULL, 0, DumpProcessWithoutCrashThread,
- 0, 0, NULL);
+ return CreateRemoteThread(process, nullptr, 0, DumpProcessWithoutCrashThread,
+ nullptr, 0, nullptr);
}
// Returns a string containing a list of all modifiers for the loaded profile.
@@ -198,8 +198,9 @@ bool DumpDoneCallback(const wchar_t*, const wchar_t*, void*,
// Now we just start chrome browser with the same command line.
STARTUPINFOW si = {sizeof(si)};
PROCESS_INFORMATION pi;
- if (::CreateProcessW(NULL, ::GetCommandLineW(), NULL, NULL, FALSE,
- CREATE_UNICODE_ENVIRONMENT, NULL, NULL, &si, &pi)) {
+ if (::CreateProcessW(nullptr, ::GetCommandLineW(), nullptr, nullptr, FALSE,
+ CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr, &si,
+ &pi)) {
::CloseHandle(pi.hProcess);
::CloseHandle(pi.hThread);
}
@@ -234,12 +235,12 @@ bool FilterCallback(void*, EXCEPTION_POINTERS*, MDRawAssertionInfo*) {
// Previous unhandled filter. Will be called if not null when we
// intercept a crash.
-LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = NULL;
+LPTOP_LEVEL_EXCEPTION_FILTER previous_filter = nullptr;
// Exception filter used when breakpad is not enabled. We just display
// the "Do you want to restart" message and then we call the previous filter.
long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
- DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
+ DumpDoneCallback(nullptr, nullptr, nullptr, info, nullptr, false);
if (previous_filter)
return previous_filter(info);
@@ -251,7 +252,7 @@ long WINAPI ChromeExceptionFilter(EXCEPTION_POINTERS* info) {
// not enabled. We just display the "Do you want to restart" message and then
// die (without calling the previous filter).
long WINAPI CloudPrintServiceExceptionFilter(EXCEPTION_POINTERS* info) {
- DumpDoneCallback(NULL, NULL, NULL, info, NULL, false);
+ DumpDoneCallback(nullptr, nullptr, nullptr, info, nullptr, false);
return EXCEPTION_EXECUTE_HANDLER;
}
@@ -289,7 +290,7 @@ static bool WrapMessageBoxWithSEH(const wchar_t* text, const wchar_t* caption,
// machines with CursorXP, PeaDict or with FontExplorer installed it crashes
// uncontrollably here. Being this a best effort deal we better go away.
__try {
- *exit_now = (IDOK != ::MessageBoxW(NULL, text, caption, flags));
+ *exit_now = (IDOK != ::MessageBoxW(nullptr, text, caption, flags));
} __except(EXCEPTION_EXECUTE_HANDLER) {
// Its not safe to continue executing, exit silently here.
::TerminateProcess(::GetCurrentProcess(),
@@ -324,7 +325,7 @@ extern "C" void __declspec(dllexport) TerminateProcessWithoutDump() {
// Patched stub exists based on conditions (See InitCrashReporter).
// As a side note this function also gets called from
// WindowProcExceptionFilter.
- if (g_real_terminate_process_stub == NULL) {
+ if (g_real_terminate_process_stub == nullptr) {
::TerminateProcess(::GetCurrentProcess(), content::RESULT_CODE_KILLED);
} else {
NtTerminateProcessPtr real_terminate_proc =
@@ -488,7 +489,7 @@ void InitCrashReporter(const std::string& process_type_switch) {
wchar_t exe_path[MAX_PATH];
exe_path[0] = 0;
- GetModuleFileNameW(NULL, exe_path, MAX_PATH);
+ GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
// This is intentionally leaked.
CrashKeysWin* keeper = new CrashKeysWin();
@@ -498,8 +499,8 @@ void InitCrashReporter(const std::string& process_type_switch) {
base::CommandLine::ForCurrentProcess(),
GetCrashReporterClient());
- google_breakpad::ExceptionHandler::MinidumpCallback callback = NULL;
- LPTOP_LEVEL_EXCEPTION_FILTER default_filter = NULL;
+ google_breakpad::ExceptionHandler::MinidumpCallback callback = nullptr;
+ LPTOP_LEVEL_EXCEPTION_FILTER default_filter = nullptr;
// We install the post-dump callback only for the browser and service
// processes. It spawns a new browser/service process.
if (process_type == L"browser") {
@@ -546,21 +547,20 @@ void InitCrashReporter(const std::string& process_type_switch) {
else if (GetCrashReporterClient()->GetShouldDumpLargerDumps())
dump_type = kLargerDumpType;
- g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback,
- callback, NULL,
- google_breakpad::ExceptionHandler::HANDLER_ALL,
- dump_type, pipe_name.c_str(), custom_info);
+ g_breakpad = new google_breakpad::ExceptionHandler(
+ temp_dir, &FilterCallback, callback, nullptr,
+ google_breakpad::ExceptionHandler::HANDLER_ALL, dump_type,
+ pipe_name.c_str(), custom_info);
// Now initialize the non crash dump handler.
- g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(temp_dir,
- &FilterCallbackWhenNoCrash,
- &DumpDoneCallbackWhenNoCrash,
- NULL,
+ g_dumphandler_no_crash = new google_breakpad::ExceptionHandler(
+ temp_dir, &FilterCallbackWhenNoCrash, &DumpDoneCallbackWhenNoCrash,
+ nullptr,
// Set the handler to none so this handler would not be added to
// |handler_stack_| in |ExceptionHandler| which is a list of exception
// handlers.
- google_breakpad::ExceptionHandler::HANDLER_NONE,
- dump_type, pipe_name.c_str(), custom_info);
+ google_breakpad::ExceptionHandler::HANDLER_NONE, dump_type,
+ pipe_name.c_str(), custom_info);
// Set the DumpWithoutCrashingFunction for this instance of base.lib. Other
// executable images linked with base should set this again for
diff --git a/chromium/components/crash/content/app/crash_keys_win.cc b/chromium/components/crash/content/app/crash_keys_win.cc
index 7df713578e7..bcf8f100505 100644
--- a/chromium/components/crash/content/app/crash_keys_win.cc
+++ b/chromium/components/crash/content/app/crash_keys_win.cc
@@ -36,7 +36,7 @@ CrashKeysWin::CrashKeysWin()
CrashKeysWin::~CrashKeysWin() {
DCHECK_EQ(this, keeper_);
- keeper_ = NULL;
+ keeper_ = nullptr;
}
// Appends the plugin path to |g_custom_entries|.
@@ -167,7 +167,7 @@ void CrashKeysWin::SetCrashKeyValue(
base::AutoLock lock(lock_);
DynamicEntriesMap::iterator it = dynamic_entries_.find(safe_key);
- google_breakpad::CustomInfoEntry* entry = NULL;
+ google_breakpad::CustomInfoEntry* entry = nullptr;
if (it == dynamic_entries_.end()) {
if (dynamic_entries_.size() >= kMaxDynamicEntries)
return;
@@ -188,7 +188,7 @@ void CrashKeysWin::ClearCrashKeyValue(const std::wstring& key) {
if (it == dynamic_entries_.end())
return;
- it->second->set_value(NULL);
+ it->second->set_value(nullptr);
}
} // namespace breakpad
diff --git a/chromium/components/crash/content/app/crash_keys_win_unittest.cc b/chromium/components/crash/content/app/crash_keys_win_unittest.cc
index f7c387f2d2a..c9ad5c96a70 100644
--- a/chromium/components/crash/content/app/crash_keys_win_unittest.cc
+++ b/chromium/components/crash/content/app/crash_keys_win_unittest.cc
@@ -123,8 +123,8 @@ TEST_F(CrashKeysWinTest, OfficialLikeKeys) {
&cmd_line,
&crash_client_);
- ASSERT_TRUE(info != NULL);
- ASSERT_TRUE(info->entries != NULL);
+ ASSERT_TRUE(info != nullptr);
+ ASSERT_TRUE(info->entries != nullptr);
// We expect 7 fixed keys and a "freeboard" of 256 keys for dynamic entries.
EXPECT_EQ(256U + 7U, info->count);
diff --git a/chromium/components/crash/content/app/crash_reporter_client.cc b/chromium/components/crash/content/app/crash_reporter_client.cc
index 4ec26a2a487..464fe2efc0d 100644
--- a/chromium/components/crash/content/app/crash_reporter_client.cc
+++ b/chromium/components/crash/content/app/crash_reporter_client.cc
@@ -93,9 +93,9 @@ void CrashReporterClient::GetProductNameAndVersion(const char** product_name,
const char** version) {
}
-void CrashReporterClient::GetProductNameAndVersion(const char** product_name,
- const char** version,
- const char** channel) {}
+void CrashReporterClient::GetProductNameAndVersion(std::string* product_name,
+ std::string* version,
+ std::string* channel) {}
base::FilePath CrashReporterClient::GetReporterLogFilename() {
return base::FilePath();
diff --git a/chromium/components/crash/content/app/crash_reporter_client.h b/chromium/components/crash/content/app/crash_reporter_client.h
index 94cdee55b87..e6a09126bdb 100644
--- a/chromium/components/crash/content/app/crash_reporter_client.h
+++ b/chromium/components/crash/content/app/crash_reporter_client.h
@@ -98,9 +98,9 @@ class CrashReporterClient {
// Linux-ish breakpad clients have transitioned to crashpad.
virtual void GetProductNameAndVersion(const char** product_name,
const char** version);
- virtual void GetProductNameAndVersion(const char** product_name,
- const char** version,
- const char** channel);
+ virtual void GetProductNameAndVersion(std::string* product_name,
+ std::string* version,
+ std::string* channel);
virtual base::FilePath GetReporterLogFilename();
diff --git a/chromium/components/crash/content/app/crashpad.cc b/chromium/components/crash/content/app/crashpad.cc
index a5f6b2e6f42..c6a98292bb5 100644
--- a/chromium/components/crash/content/app/crashpad.cc
+++ b/chromium/components/crash/content/app/crashpad.cc
@@ -379,4 +379,12 @@ base::FilePath::StringType::const_pointer GetCrashpadDatabasePathImpl() {
return g_database_path->value().c_str();
}
+namespace internal {
+
+crashpad::CrashReportDatabase* GetCrashReportDatabase() {
+ return g_database;
+}
+
+} // namespace internal
+
} // namespace crash_reporter
diff --git a/chromium/components/crash/content/app/crashpad.h b/chromium/components/crash/content/app/crashpad.h
index cae8cfd29b8..7717dccceb8 100644
--- a/chromium/components/crash/content/app/crashpad.h
+++ b/chromium/components/crash/content/app/crashpad.h
@@ -23,6 +23,7 @@
namespace crashpad {
class CrashpadClient;
+class CrashReportDatabase;
}
namespace crash_reporter {
@@ -127,6 +128,12 @@ void RequestSingleCrashUploadImpl(const std::string& local_id);
// The implementation function for GetCrashpadDatabasePath.
base::FilePath::StringType::const_pointer GetCrashpadDatabasePathImpl();
+#if defined(OS_MACOSX)
+// Captures a minidump for the process named by its |task_port| and stores it
+// in the current crash report database.
+void DumpProcessWithoutCrashing(task_t task_port);
+#endif
+
namespace internal {
#if defined(OS_WIN)
@@ -169,6 +176,10 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
const std::string& user_data_dir,
const base::FilePath& exe_path);
+// Returns the current crash report database object, or null if it has not
+// been initialized yet.
+crashpad::CrashReportDatabase* GetCrashReportDatabase();
+
} // namespace internal
} // namespace crash_reporter
diff --git a/chromium/components/crash/content/app/crashpad_linux.cc b/chromium/components/crash/content/app/crashpad_linux.cc
index 05767fe2a26..d494877ca88 100644
--- a/chromium/components/crash/content/app/crashpad_linux.cc
+++ b/chromium/components/crash/content/app/crashpad_linux.cc
@@ -11,6 +11,7 @@
#include <algorithm>
+#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
@@ -41,7 +42,8 @@ class SandboxedHandler {
}
bool Initialize() {
- server_fd_ = base::GlobalDescriptors::GetInstance()->Get(kCrashDumpSignal);
+ server_fd_ = base::GlobalDescriptors::GetInstance()->Get(
+ service_manager::kCrashDumpSignal);
return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr);
}
@@ -50,7 +52,7 @@ class SandboxedHandler {
SandboxedHandler() = default;
~SandboxedHandler() = delete;
- int ConnectToHandler(base::ScopedFD* connection) {
+ int ConnectToHandler(int signo, base::ScopedFD* connection) {
int fds[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
return errno;
@@ -58,11 +60,15 @@ class SandboxedHandler {
base::ScopedFD local_connection(fds[0]);
base::ScopedFD handlers_socket(fds[1]);
+ iovec iov;
+ iov.iov_base = &signo;
+ iov.iov_len = sizeof(signo);
+
msghdr msg;
msg.msg_name = nullptr;
msg.msg_namelen = 0;
- msg.msg_iov = nullptr;
- msg.msg_iovlen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
char cmsg_buf[CMSG_SPACE(sizeof(int))];
msg.msg_control = cmsg_buf;
@@ -86,7 +92,7 @@ class SandboxedHandler {
SandboxedHandler* state = Get();
base::ScopedFD connection;
- if (state->ConnectToHandler(&connection) == 0) {
+ if (state->ConnectToHandler(signo, &connection) == 0) {
ExceptionInformation exception_information;
exception_information.siginfo_address =
FromPointerCast<decltype(exception_information.siginfo_address)>(
@@ -120,6 +126,26 @@ class SandboxedHandler {
namespace crash_reporter {
namespace internal {
+bool SetLdLibraryPath(const base::FilePath& lib_path) {
+#if defined(OS_ANDROID) && defined(COMPONENT_BUILD)
+ std::string library_path(lib_path.value());
+
+ static constexpr char kLibraryPathVar[] = "LD_LIBRARY_PATH";
+ std::unique_ptr<base::Environment> env(base::Environment::Create());
+ std::string old_path;
+ if (env->GetVar(kLibraryPathVar, &old_path)) {
+ library_path.push_back(':');
+ library_path.append(old_path);
+ }
+
+ if (!env->SetVar(kLibraryPathVar, library_path)) {
+ return false;
+ }
+#endif
+
+ return true;
+}
+
bool BuildHandlerArgs(base::FilePath* handler_path,
base::FilePath* database_path,
base::FilePath* metrics_path,
@@ -128,32 +154,47 @@ bool BuildHandlerArgs(base::FilePath* handler_path,
std::vector<std::string>* arguments) {
base::FilePath exe_dir;
#if defined(OS_ANDROID)
- if (!PathService::Get(base::DIR_MODULE, &exe_dir)) {
+ if (!base::PathService::Get(base::DIR_MODULE, &exe_dir)) {
#else
- if (!PathService::Get(base::DIR_EXE, &exe_dir)) {
+ if (!base::PathService::Get(base::DIR_EXE, &exe_dir)) {
#endif // OS_ANDROID
DCHECK(false);
return false;
}
+#if defined(OS_ANDROID)
+ // There is not any normal way to package native executables in an Android
+ // APK. The Crashpad handler is packaged like a loadable module, which
+ // Android's APK installer expects to be named like a shared library, but it
+ // is in fact a standalone executable.
+ *handler_path = exe_dir.Append("libcrashpad_handler.so");
+#else
*handler_path = exe_dir.Append("crashpad_handler");
+#endif
+
+ static bool env_setup = SetLdLibraryPath(exe_dir);
+ if (!env_setup) {
+ return false;
+ }
CrashReporterClient* crash_reporter_client = GetCrashReporterClient();
crash_reporter_client->GetCrashDumpLocation(database_path);
crash_reporter_client->GetCrashMetricsLocation(metrics_path);
-#if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD)
+// TODO(jperaza): Set URL for Android when Crashpad takes over report upload.
+#if defined(GOOGLE_CHROME_BUILD) && defined(OFFICIAL_BUILD) && \
+ !defined(OS_ANDROID)
*url = "https://clients2.google.com/cr/report";
#else
*url = std::string();
#endif
- const char* product_name;
- const char* product_version;
- const char* channel;
+ std::string product_name;
+ std::string product_version;
+ std::string channel;
crash_reporter_client->GetProductNameAndVersion(&product_name,
&product_version, &channel);
- (*process_annotations)["prod"] = std::string(product_name);
- (*process_annotations)["ver"] = std::string(product_version);
+ (*process_annotations)["prod"] = product_name;
+ (*process_annotations)["ver"] = product_version;
#if defined(GOOGLE_CHROME_BUILD)
// Empty means stable.
@@ -161,9 +202,8 @@ bool BuildHandlerArgs(base::FilePath* handler_path,
#else
const bool allow_empty_channel = false;
#endif
- std::string channel_string(channel);
- if (allow_empty_channel || !channel_string.empty()) {
- (*process_annotations)["channel"] = channel_string;
+ if (allow_empty_channel || !channel.empty()) {
+ (*process_annotations)["channel"] = channel;
}
#if defined(OS_ANDROID)
diff --git a/chromium/components/crash/content/app/crashpad_mac.mm b/chromium/components/crash/content/app/crashpad_mac.mm
index eb82f44053c..f06d903c2f4 100644
--- a/chromium/components/crash/content/app/crashpad_mac.mm
+++ b/chromium/components/crash/content/app/crashpad_mac.mm
@@ -26,8 +26,85 @@
#include "third_party/crashpad/crashpad/client/crashpad_info.h"
#include "third_party/crashpad/crashpad/client/settings.h"
#include "third_party/crashpad/crashpad/client/simulate_crash.h"
+#include "third_party/crashpad/crashpad/minidump/minidump_file_writer.h"
+#include "third_party/crashpad/crashpad/snapshot/mac/process_snapshot_mac.h"
namespace crash_reporter {
+
+namespace {
+
+std::map<std::string, std::string> GetProcessSimpleAnnotations() {
+ static std::map<std::string, std::string> annotations = []() -> auto {
+ std::map<std::string, std::string> process_annotations;
+ @autoreleasepool {
+ NSBundle* outer_bundle = base::mac::OuterBundle();
+ NSString* product = base::mac::ObjCCast<NSString>([outer_bundle
+ objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
+ process_annotations["prod"] =
+ base::SysNSStringToUTF8(product).append("_Mac");
+
+#if defined(GOOGLE_CHROME_BUILD)
+ // Empty means stable.
+ const bool allow_empty_channel = true;
+#else
+ const bool allow_empty_channel = false;
+#endif
+ NSString* channel = base::mac::ObjCCast<NSString>(
+ [outer_bundle objectForInfoDictionaryKey:@"KSChannelID"]);
+ if (channel) {
+ process_annotations["channel"] = base::SysNSStringToUTF8(channel);
+ } else if (allow_empty_channel) {
+ process_annotations["channel"] = "";
+ }
+
+ NSString* version =
+ base::mac::ObjCCast<NSString>([base::mac::FrameworkBundle()
+ objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+ process_annotations["ver"] = base::SysNSStringToUTF8(version);
+
+ process_annotations["plat"] = std::string("OS X");
+ } // @autoreleasepool
+ return process_annotations;
+ }();
+ return annotations;
+}
+
+} // namespace
+
+void DumpProcessWithoutCrashing(task_t task_port) {
+ crashpad::CrashReportDatabase* database = internal::GetCrashReportDatabase();
+ if (!database)
+ return;
+
+ crashpad::ProcessSnapshotMac snapshot;
+ if (!snapshot.Initialize(task_port))
+ return;
+
+ auto process_annotations = GetProcessSimpleAnnotations();
+ process_annotations["is-dump-process-without-crashing"] = "true";
+ snapshot.SetAnnotationsSimpleMap(process_annotations);
+
+ std::unique_ptr<crashpad::CrashReportDatabase::NewReport> new_report;
+ if (database->PrepareNewCrashReport(&new_report) !=
+ crashpad::CrashReportDatabase::kNoError) {
+ return;
+ }
+
+ crashpad::UUID client_id;
+ database->GetSettings()->GetClientID(&client_id);
+
+ snapshot.SetReportID(new_report->ReportID());
+ snapshot.SetClientID(client_id);
+
+ crashpad::MinidumpFileWriter minidump;
+ minidump.InitializeFromSnapshot(&snapshot);
+ if (!minidump.WriteEverything(new_report->Writer()))
+ return;
+
+ crashpad::UUID report_id;
+ database->FinishedWritingCrashReport(std::move(new_report), &report_id);
+}
+
namespace internal {
base::FilePath PlatformCrashpadInitialization(bool initial_client,
@@ -59,35 +136,6 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
std::string url;
#endif
- std::map<std::string, std::string> process_annotations;
-
- NSBundle* outer_bundle = base::mac::OuterBundle();
- NSString* product = base::mac::ObjCCast<NSString>([outer_bundle
- objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
- process_annotations["prod"] =
- base::SysNSStringToUTF8(product).append("_Mac");
-
-#if defined(GOOGLE_CHROME_BUILD)
- // Empty means stable.
- const bool allow_empty_channel = true;
-#else
- const bool allow_empty_channel = false;
-#endif
- NSString* channel = base::mac::ObjCCast<NSString>(
- [outer_bundle objectForInfoDictionaryKey:@"KSChannelID"]);
- if (channel) {
- process_annotations["channel"] = base::SysNSStringToUTF8(channel);
- } else if (allow_empty_channel) {
- process_annotations["channel"] = "";
- }
-
- NSString* version =
- base::mac::ObjCCast<NSString>([base::mac::FrameworkBundle()
- objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
- process_annotations["ver"] = base::SysNSStringToUTF8(version);
-
- process_annotations["plat"] = std::string("OS X");
-
std::vector<std::string> arguments;
if (crash_reporter_client->ShouldMonitorCrashHandlerExpensively()) {
@@ -109,8 +157,8 @@ base::FilePath PlatformCrashpadInitialization(bool initial_client,
}
bool result = GetCrashpadClient().StartHandler(
- handler_path, database_path, metrics_path, url, process_annotations,
- arguments, true, false);
+ handler_path, database_path, metrics_path, url,
+ GetProcessSimpleAnnotations(), arguments, true, false);
// If this is an initial client that's not the browser process, it's
// important to sever the connection to any existing handler. If
diff --git a/chromium/components/crash/content/app/hard_error_handler_win.cc b/chromium/components/crash/content/app/hard_error_handler_win.cc
index 11eca1c2904..dec998f9580 100644
--- a/chromium/components/crash/content/app/hard_error_handler_win.cc
+++ b/chromium/components/crash/content/app/hard_error_handler_win.cc
@@ -41,16 +41,12 @@ void RaiseHardErrorMsg(DWORD nt_status,
return;
HMODULE ntdll = ::GetModuleHandleA("NTDLL.DLL");
- wchar_t* msg_template = NULL;
+ wchar_t* msg_template = nullptr;
size_t count = ::FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS |
- FORMAT_MESSAGE_FROM_HMODULE,
- ntdll,
- nt_status,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- reinterpret_cast<wchar_t*>(&msg_template),
- 0,
- NULL);
+ FORMAT_MESSAGE_FROM_HMODULE,
+ ntdll, nt_status, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ reinterpret_cast<wchar_t*>(&msg_template), 0, nullptr);
if (!count)
return;
@@ -61,8 +57,7 @@ void RaiseHardErrorMsg(DWORD nt_status,
// The MB_SERVICE_NOTIFICATION causes this message to be displayed by
// csrss. This means that we are not creating windows or pumping WM messages
// in this process.
- ::MessageBox(NULL, message.c_str(),
- L"chrome.exe",
+ ::MessageBox(nullptr, message.c_str(), L"chrome.exe",
MB_OK | MB_SERVICE_NOTIFICATION);
::LocalFree(msg_template);
}
diff --git a/chromium/components/crash/content/browser/child_process_crash_observer_android.cc b/chromium/components/crash/content/browser/child_process_crash_observer_android.cc
index ad99ae8bc35..83d10f0c0d2 100644
--- a/chromium/components/crash/content/browser/child_process_crash_observer_android.cc
+++ b/chromium/components/crash/content/browser/child_process_crash_observer_android.cc
@@ -35,11 +35,7 @@ void ChildProcessCrashObserver::OnChildStart(
}
void ChildProcessCrashObserver::OnChildExit(
- int process_host_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) {
+ const CrashDumpObserver::TerminationInfo& info) {
// This might be called twice for a given child process, with a
// NOTIFICATION_RENDERER_PROCESS_TERMINATED and then with
// NOTIFICATION_RENDERER_PROCESS_CLOSED.
@@ -48,8 +44,7 @@ void ChildProcessCrashObserver::OnChildExit(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
base::Bind(&CrashDumpManager::ProcessMinidumpFileFromChild,
base::Unretained(CrashDumpManager::GetInstance()),
- crash_dump_dir_, process_host_id, process_type,
- termination_status, app_state));
+ crash_dump_dir_, info));
}
} // namespace breakpad
diff --git a/chromium/components/crash/content/browser/child_process_crash_observer_android.h b/chromium/components/crash/content/browser/child_process_crash_observer_android.h
index 6f65397e5bc..07a119cee8e 100644
--- a/chromium/components/crash/content/browser/child_process_crash_observer_android.h
+++ b/chromium/components/crash/content/browser/child_process_crash_observer_android.h
@@ -19,11 +19,7 @@ class ChildProcessCrashObserver : public breakpad::CrashDumpObserver::Client {
// breakpad::CrashDumpObserver::Client implementation:
void OnChildStart(int process_host_id,
content::PosixFileDescriptorInfo* mappings) override;
- void OnChildExit(int process_host_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) override;
+ void OnChildExit(const CrashDumpObserver::TerminationInfo& info) override;
private:
base::FilePath crash_dump_dir_;
diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.cc b/chromium/components/crash/content/browser/crash_dump_manager_android.cc
index d2adb83c924..1cc00de0bb2 100644
--- a/chromium/components/crash/content/browser/crash_dump_manager_android.cc
+++ b/chromium/components/crash/content/browser/crash_dump_manager_android.cc
@@ -29,16 +29,85 @@ namespace breakpad {
namespace {
base::LazyInstance<CrashDumpManager>::Leaky g_instance =
LAZY_INSTANCE_INITIALIZER;
+
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+enum class ProcessedCrashCounts {
+ kGpuForegroundOom = 0,
+ kRendererForegroundVisibleOom = 1,
+ kRendererForegroundIntentionalKill = 2,
+ kRendererForegroundVisibleSubframeOom = 3,
+ kRendererForegroundVisibleSubframeIntentionalKill = 4,
+ kRendererForegroundVisibleCrash = 5,
+ kRendererForegroundVisibleSubframeCrash = 6,
+ kGpuCrashAll = 7,
+ kRendererCrashAll = 8,
+ kMaxValue = kRendererCrashAll
+};
+
+void LogCount(ProcessedCrashCounts type) {
+ UMA_HISTOGRAM_ENUMERATION("Stability.Android.ProcessedCrashCounts", type);
}
+void LogProcessedMetrics(const CrashDumpObserver::TerminationInfo& info,
+ bool has_crash_dump) {
+ const bool app_foreground =
+ info.app_state ==
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES ||
+ info.app_state == base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES;
+ const bool intentional_kill = info.was_killed_intentionally_by_browser;
+ const bool android_oom_kill = !info.was_killed_intentionally_by_browser &&
+ !has_crash_dump && !info.normal_termination;
+ const bool renderer_visible = info.renderer_has_visible_clients;
+ const bool renderer_sub_frame = info.renderer_was_subframe;
+
+ if (info.process_type == content::PROCESS_TYPE_GPU) {
+ if (app_foreground && android_oom_kill) {
+ LogCount(ProcessedCrashCounts::kGpuForegroundOom);
+ }
+ if (has_crash_dump) {
+ LogCount(ProcessedCrashCounts::kGpuCrashAll);
+ }
+ }
+
+ if (info.process_type == content::PROCESS_TYPE_RENDERER) {
+ if (app_foreground && renderer_visible) {
+ if (android_oom_kill) {
+ LogCount(
+ renderer_sub_frame
+ ? ProcessedCrashCounts::kRendererForegroundVisibleSubframeOom
+ : ProcessedCrashCounts::kRendererForegroundVisibleOom);
+ }
+ if (has_crash_dump) {
+ LogCount(
+ renderer_sub_frame
+ ? ProcessedCrashCounts::kRendererForegroundVisibleSubframeCrash
+ : ProcessedCrashCounts::kRendererForegroundVisibleCrash);
+ }
+ }
+ if (app_foreground && intentional_kill) {
+ LogCount(ProcessedCrashCounts::kRendererForegroundIntentionalKill);
+ if (renderer_visible && renderer_sub_frame) {
+ LogCount(ProcessedCrashCounts::
+ kRendererForegroundVisibleSubframeIntentionalKill);
+ }
+ }
+ if (has_crash_dump) {
+ LogCount(ProcessedCrashCounts::kRendererCrashAll);
+ }
+ }
+}
+
+} // namespace
+
CrashDumpManager::CrashDumpDetails::CrashDumpDetails(
int process_host_id,
content::ProcessType process_type,
- base::TerminationStatus termination_status,
+ bool was_oom_protected_status,
base::android::ApplicationState app_state)
: process_host_id(process_host_id),
process_type(process_type),
- termination_status(termination_status),
+ was_oom_protected_status(was_oom_protected_status),
app_state(app_state) {}
CrashDumpManager::CrashDumpDetails::CrashDumpDetails() {}
@@ -48,7 +117,7 @@ CrashDumpManager::CrashDumpDetails::CrashDumpDetails(
const CrashDumpManager::CrashDumpDetails& other)
: CrashDumpDetails(other.process_host_id,
other.process_type,
- other.termination_status,
+ other.was_oom_protected_status,
other.app_state) {
file_size = other.file_size;
status = other.status;
@@ -63,8 +132,7 @@ CrashDumpManager* CrashDumpManager::GetInstance() {
bool CrashDumpManager::IsForegroundOom(const CrashDumpDetails& details) {
// If the crash is size 0, it is an OOM.
return details.process_type == content::PROCESS_TYPE_RENDERER &&
- details.termination_status == base::TERMINATION_STATUS_OOM_PROTECTED &&
- details.file_size == 0 &&
+ details.was_oom_protected_status && details.file_size == 0 &&
details.app_state ==
base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
}
@@ -109,17 +177,14 @@ base::ScopedFD CrashDumpManager::CreateMinidumpFileForChild(
void CrashDumpManager::ProcessMinidumpFileFromChild(
base::FilePath crash_dump_dir,
- int process_host_id,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) {
+ const CrashDumpObserver::TerminationInfo& info) {
base::AssertBlockingAllowed();
- CrashDumpDetails details(process_host_id, process_type, termination_status,
- app_state);
+ CrashDumpDetails details(info.process_host_id, info.process_type,
+ info.was_oom_protected_status, info.app_state);
base::FilePath minidump_path;
// If the minidump for a given child process has already been
// processed, then there is no more work to do.
- if (!GetMinidumpPath(process_host_id, &minidump_path)) {
+ if (!GetMinidumpPath(info.process_host_id, &minidump_path)) {
NotifyObservers(details);
return;
}
@@ -132,20 +197,19 @@ void CrashDumpManager::ProcessMinidumpFileFromChild(
}
int r = base::GetFileSize(minidump_path, &file_size);
- DCHECK(r) << "Failed to retrieve size for minidump "
- << minidump_path.value();
+ DCHECK(r) << "Failed to retrieve size for minidump " << minidump_path.value();
// TODO(wnwen): If these numbers match up to TabWebContentsObserver's
// TabRendererCrashStatus histogram, then remove that one as this is more
// accurate with more detail.
- if ((process_type == content::PROCESS_TYPE_RENDERER ||
- process_type == content::PROCESS_TYPE_GPU) &&
- app_state != base::android::APPLICATION_STATE_UNKNOWN) {
+ if ((info.process_type == content::PROCESS_TYPE_RENDERER ||
+ info.process_type == content::PROCESS_TYPE_GPU) &&
+ info.app_state != base::android::APPLICATION_STATE_UNKNOWN) {
ExitStatus exit_status;
- bool is_running =
- (app_state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
- bool is_paused =
- (app_state == base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES);
+ bool is_running = (info.app_state ==
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES);
+ bool is_paused = (info.app_state ==
+ base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES);
if (file_size == 0) {
if (is_running) {
exit_status = EMPTY_MINIDUMP_WHILE_RUNNING;
@@ -163,22 +227,23 @@ void CrashDumpManager::ProcessMinidumpFileFromChild(
exit_status = VALID_MINIDUMP_WHILE_BACKGROUND;
}
}
- if (process_type == content::PROCESS_TYPE_RENDERER) {
- if (termination_status == base::TERMINATION_STATUS_OOM_PROTECTED) {
- UMA_HISTOGRAM_ENUMERATION("Tab.RendererDetailedExitStatus",
- exit_status,
+ if (info.process_type == content::PROCESS_TYPE_RENDERER) {
+ if (info.was_oom_protected_status) {
+ UMA_HISTOGRAM_ENUMERATION("Tab.RendererDetailedExitStatus", exit_status,
ExitStatus::MINIDUMP_STATUS_COUNT);
} else {
UMA_HISTOGRAM_ENUMERATION("Tab.RendererDetailedExitStatusUnbound",
exit_status,
ExitStatus::MINIDUMP_STATUS_COUNT);
}
- } else if (process_type == content::PROCESS_TYPE_GPU) {
+ } else if (info.process_type == content::PROCESS_TYPE_GPU) {
UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessDetailedExitStatus", exit_status,
ExitStatus::MINIDUMP_STATUS_COUNT);
}
}
+ LogProcessedMetrics(info, file_size != 0);
+
if (file_size == 0) {
// Empty minidump, this process did not crash. Just remove the file.
r = base::DeleteFile(minidump_path, false);
@@ -196,8 +261,9 @@ void CrashDumpManager::ProcessMinidumpFileFromChild(
return;
}
const uint64_t rand = base::RandUint64();
- const std::string filename = base::StringPrintf(
- "chromium-renderer-minidump-%016" PRIx64 ".dmp%d", rand, process_host_id);
+ const std::string filename =
+ base::StringPrintf("chromium-renderer-minidump-%016" PRIx64 ".dmp%d",
+ rand, info.process_host_id);
base::FilePath dest_path = crash_dump_dir.Append(filename);
r = base::Move(minidump_path, dest_path);
if (!r) {
diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.h b/chromium/components/crash/content/browser/crash_dump_manager_android.h
index 5966abac797..96f14e1b2c9 100644
--- a/chromium/components/crash/content/browser/crash_dump_manager_android.h
+++ b/chromium/components/crash/content/browser/crash_dump_manager_android.h
@@ -13,8 +13,8 @@
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
-#include "base/process/kill.h"
#include "base/synchronization/lock.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/process_type.h"
@@ -58,7 +58,7 @@ class CrashDumpManager {
struct CrashDumpDetails {
CrashDumpDetails(int process_host_id,
content::ProcessType process_type,
- base::TerminationStatus termination_status,
+ bool was_oom_protected_status,
base::android::ApplicationState app_state);
CrashDumpDetails();
~CrashDumpDetails();
@@ -67,7 +67,7 @@ class CrashDumpManager {
int process_host_id = content::ChildProcessHost::kInvalidUniqueID;
content::ProcessType process_type = content::PROCESS_TYPE_UNKNOWN;
- base::TerminationStatus termination_status;
+ bool was_oom_protected_status = false;
base::android::ApplicationState app_state;
int64_t file_size = 0;
CrashDumpStatus status = CrashDumpStatus::kNoDump;
@@ -91,11 +91,9 @@ class CrashDumpManager {
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- void ProcessMinidumpFileFromChild(base::FilePath crash_dump_dir,
- int process_host_id,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state);
+ void ProcessMinidumpFileFromChild(
+ base::FilePath crash_dump_dir,
+ const CrashDumpObserver::TerminationInfo& info);
base::ScopedFD CreateMinidumpFileForChild(int process_host_id);
diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc b/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc
index a468f14f8ef..a3ad2e198dc 100644
--- a/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc
+++ b/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc
@@ -39,18 +39,15 @@ class CrashDumpManagerTest : public testing::Test {
// TODO(csharrison): This test harness is not robust enough. Namely, it does
// not support actually processing a non-empty crash dump, due to JNI calls.
static void CreateAndProcessEmptyMinidump(
- int process_host_id,
- content::ProcessType process_type,
- base::TerminationStatus status,
- base::android::ApplicationState app_state) {
+ const CrashDumpObserver::TerminationInfo& info) {
base::ScopedFD fd =
CrashDumpManager::GetInstance()->CreateMinidumpFileForChild(
- process_host_id);
+ info.process_host_id);
EXPECT_TRUE(fd.is_valid());
base::ScopedTempDir dump_dir;
EXPECT_TRUE(dump_dir.CreateUniqueTempDir());
CrashDumpManager::GetInstance()->ProcessMinidumpFileFromChild(
- dump_dir.GetPath(), process_host_id, process_type, status, app_state);
+ dump_dir.GetPath(), info);
}
private:
@@ -95,20 +92,27 @@ TEST_F(CrashDumpManagerTest, SimpleOOM) {
CrashDumpManagerObserver crash_dump_observer;
manager->AddObserver(&crash_dump_observer);
- int process_host_id = 1;
+ CrashDumpObserver::TerminationInfo termination_info;
+ termination_info.process_host_id = 1;
+ termination_info.pid = base::kNullProcessHandle;
+ termination_info.process_type = content::PROCESS_TYPE_RENDERER;
+ termination_info.app_state =
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
+ termination_info.normal_termination = false;
+ termination_info.has_oom_protection_bindings = true;
+ termination_info.was_killed_intentionally_by_browser = false;
+ termination_info.was_oom_protected_status = true;
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
base::Bind(&CrashDumpManagerTest::CreateAndProcessEmptyMinidump,
- process_host_id, content::PROCESS_TYPE_RENDERER,
- base::TERMINATION_STATUS_OOM_PROTECTED,
- base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES));
+ termination_info));
crash_dump_observer.WaitForProcessed();
const CrashDumpManager::CrashDumpDetails& details =
crash_dump_observer.last_details();
- EXPECT_EQ(process_host_id, details.process_host_id);
+ EXPECT_EQ(termination_info.process_host_id, details.process_host_id);
EXPECT_EQ(content::PROCESS_TYPE_RENDERER, details.process_type);
- EXPECT_EQ(base::TERMINATION_STATUS_OOM_PROTECTED, details.termination_status);
+ EXPECT_TRUE(details.was_oom_protected_status);
EXPECT_EQ(base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES,
details.app_state);
EXPECT_EQ(0, details.file_size);
@@ -126,21 +130,28 @@ TEST_F(CrashDumpManagerTest, NoDumpCreated) {
CrashDumpManagerObserver crash_dump_observer;
manager->AddObserver(&crash_dump_observer);
- int process_host_id = 1;
+ CrashDumpObserver::TerminationInfo termination_info;
+ termination_info.process_host_id = 1;
+ termination_info.pid = base::kNullProcessHandle;
+ termination_info.process_type = content::PROCESS_TYPE_RENDERER;
+ termination_info.app_state =
+ base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES;
+ termination_info.normal_termination = false;
+ termination_info.has_oom_protection_bindings = true;
+ termination_info.was_killed_intentionally_by_browser = false;
+ termination_info.was_oom_protected_status = true;
base::PostTaskWithTraits(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
base::Bind(&CrashDumpManager::ProcessMinidumpFileFromChild,
- base::Unretained(manager), base::FilePath(), process_host_id,
- content::PROCESS_TYPE_RENDERER,
- base::TERMINATION_STATUS_OOM_PROTECTED,
- base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES));
+ base::Unretained(manager), base::FilePath(),
+ termination_info));
crash_dump_observer.WaitForProcessed();
const CrashDumpManager::CrashDumpDetails& details =
crash_dump_observer.last_details();
- EXPECT_EQ(process_host_id, details.process_host_id);
+ EXPECT_EQ(termination_info.process_host_id, details.process_host_id);
EXPECT_EQ(content::PROCESS_TYPE_RENDERER, details.process_type);
- EXPECT_EQ(base::TERMINATION_STATUS_OOM_PROTECTED, details.termination_status);
+ EXPECT_TRUE(details.was_oom_protected_status);
EXPECT_EQ(base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES,
details.app_state);
EXPECT_EQ(0, details.file_size);
diff --git a/chromium/components/crash/content/browser/crash_dump_observer_android.cc b/chromium/components/crash/content/browser/crash_dump_observer_android.cc
index 678b52b4cf6..7e2883d9c39 100644
--- a/chromium/components/crash/content/browser/crash_dump_observer_android.cc
+++ b/chromium/components/crash/content/browser/crash_dump_observer_android.cc
@@ -11,6 +11,7 @@
#include "base/stl_util.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
+#include "content/public/browser/child_process_termination_info.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
#include "content/public/browser/render_process_host.h"
@@ -20,10 +21,28 @@ using content::BrowserThread;
namespace breakpad {
namespace {
+
base::LazyInstance<CrashDumpObserver>::DestructorAtExit g_instance =
LAZY_INSTANCE_INITIALIZER;
+
+void PopulateTerminationInfo(
+ const content::ChildProcessTerminationInfo& content_info,
+ CrashDumpObserver::TerminationInfo* info) {
+ info->has_oom_protection_bindings = content_info.has_oom_protection_bindings;
+ info->was_killed_intentionally_by_browser =
+ content_info.was_killed_intentionally_by_browser;
+ info->was_oom_protected_status =
+ content_info.status == base::TERMINATION_STATUS_OOM_PROTECTED;
}
+} // namespace
+
+CrashDumpObserver::TerminationInfo::TerminationInfo() = default;
+CrashDumpObserver::TerminationInfo::TerminationInfo(
+ const TerminationInfo& other) = default;
+CrashDumpObserver::TerminationInfo& CrashDumpObserver::TerminationInfo::
+operator=(const TerminationInfo& other) = default;
+
// static
void CrashDumpObserver::Create() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -63,11 +82,7 @@ void CrashDumpObserver::RegisterClient(std::unique_ptr<Client> client) {
registered_clients_.push_back(std::move(client));
}
-void CrashDumpObserver::OnChildExit(int process_host_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) {
+void CrashDumpObserver::OnChildExit(const TerminationInfo& info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
std::vector<Client*> registered_clients_copy;
{
@@ -76,8 +91,7 @@ void CrashDumpObserver::OnChildExit(int process_host_id,
registered_clients_copy.push_back(client.get());
}
for (auto* client : registered_clients_copy) {
- client->OnChildExit(process_host_id, pid, process_type, termination_status,
- app_state);
+ client->OnChildExit(info);
}
}
@@ -98,20 +112,34 @@ void CrashDumpObserver::BrowserChildProcessStarted(
void CrashDumpObserver::BrowserChildProcessHostDisconnected(
const content::ChildProcessData& data) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- OnChildExit(data.id, data.handle,
- static_cast<content::ProcessType>(data.process_type),
- base::TERMINATION_STATUS_MAX_ENUM,
- base::android::ApplicationStatusListener::GetState());
+ TerminationInfo info;
+ auto it = browser_child_process_info_.find(data.id);
+ if (it != browser_child_process_info_.end()) {
+ info = it->second;
+ browser_child_process_info_.erase(it);
+ } else {
+ info.process_host_id = data.id;
+ info.pid = data.handle;
+ info.process_type = static_cast<content::ProcessType>(data.process_type);
+ info.app_state = base::android::ApplicationStatusListener::GetState();
+ info.normal_termination = true;
+ }
+ OnChildExit(info);
}
-void CrashDumpObserver::BrowserChildProcessCrashed(
+void CrashDumpObserver::BrowserChildProcessKilled(
const content::ChildProcessData& data,
- int exit_code) {
+ const content::ChildProcessTerminationInfo& content_info) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- OnChildExit(data.id, data.handle,
- static_cast<content::ProcessType>(data.process_type),
- base::TERMINATION_STATUS_ABNORMAL_TERMINATION,
- base::android::APPLICATION_STATE_UNKNOWN);
+ DCHECK(!base::ContainsKey(browser_child_process_info_, data.id));
+ TerminationInfo info;
+ info.process_host_id = data.id;
+ info.pid = data.handle;
+ info.process_type = static_cast<content::ProcessType>(data.process_type);
+ info.app_state = base::android::ApplicationStatusListener::GetState();
+ PopulateTerminationInfo(content_info, &info);
+ browser_child_process_info_.emplace(data.id, info);
+ // Subsequent BrowserChildProcessHostDisconnected will call OnChildExit.
}
void CrashDumpObserver::Observe(int type,
@@ -120,50 +148,49 @@ void CrashDumpObserver::Observe(int type,
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::RenderProcessHost* rph =
content::Source<content::RenderProcessHost>(source).ptr();
- base::TerminationStatus term_status = base::TERMINATION_STATUS_MAX_ENUM;
- base::android::ApplicationState app_state =
- base::android::APPLICATION_STATE_UNKNOWN;
+ TerminationInfo info;
+ info.process_host_id = rph->GetID();
+ info.pid = rph->GetProcess().Handle();
+ info.process_type = content::PROCESS_TYPE_RENDERER;
+ info.app_state = base::android::APPLICATION_STATE_UNKNOWN;
+ info.renderer_has_visible_clients = rph->VisibleClientCount() > 0;
+ info.renderer_was_subframe = rph->GetFrameDepth() > 0u;
switch (type) {
case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
// NOTIFICATION_RENDERER_PROCESS_TERMINATED is sent when the renderer
// process is cleanly shutdown.
- term_status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
+ info.normal_termination = true;
break;
}
case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
// We do not care about android fast shutdowns as it is a known case where
// the renderer is intentionally killed when we are done with it.
- if (rph->FastShutdownStarted()) {
- break;
- }
- content::RenderProcessHost::RendererClosedDetails* process_details =
- content::Details<content::RenderProcessHost::RendererClosedDetails>(
- details)
- .ptr();
- term_status = process_details->status;
- app_state = base::android::ApplicationStatusListener::GetState();
+ info.normal_termination = rph->FastShutdownStarted();
+ info.app_state = base::android::ApplicationStatusListener::GetState();
+ const auto& content_info =
+ *content::Details<content::ChildProcessTerminationInfo>(details)
+ .ptr();
+ PopulateTerminationInfo(content_info, &info);
break;
}
case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
// The child process pid isn't available when process is gone, keep a
// mapping between process_host_id and pid, so we can find it later.
- process_host_id_to_pid_[rph->GetID()] = rph->GetHandle();
+ process_host_id_to_pid_[rph->GetID()] = rph->GetProcess().Handle();
return;
}
default:
NOTREACHED();
return;
}
- base::ProcessHandle pid = rph->GetHandle();
const auto& iter = process_host_id_to_pid_.find(rph->GetID());
if (iter != process_host_id_to_pid_.end()) {
- if (pid == base::kNullProcessHandle) {
- pid = iter->second;
+ if (info.pid == base::kNullProcessHandle) {
+ info.pid = iter->second;
}
process_host_id_to_pid_.erase(iter);
}
- OnChildExit(rph->GetID(), pid, content::PROCESS_TYPE_RENDERER, term_status,
- app_state);
+ OnChildExit(info);
}
} // namespace breakpad
diff --git a/chromium/components/crash/content/browser/crash_dump_observer_android.h b/chromium/components/crash/content/browser/crash_dump_observer_android.h
index 99de1b9c541..2564e1ecbae 100644
--- a/chromium/components/crash/content/browser/crash_dump_observer_android.h
+++ b/chromium/components/crash/content/browser/crash_dump_observer_android.h
@@ -11,14 +11,18 @@
#include "base/android/application_status_listener.h"
#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
-#include "base/process/kill.h"
#include "base/process/process.h"
#include "content/public/browser/browser_child_process_observer.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/posix_file_descriptor_info.h"
+#include "content/public/common/child_process_host.h"
#include "content/public/common/process_type.h"
+namespace content {
+struct ChildProcessTerminationInfo;
+}
+
namespace breakpad {
// This class centralises the observation of child processes for the
@@ -27,6 +31,45 @@ namespace breakpad {
class CrashDumpObserver : public content::BrowserChildProcessObserver,
public content::NotificationObserver {
public:
+ struct TerminationInfo {
+ TerminationInfo();
+ TerminationInfo(const TerminationInfo& other);
+ TerminationInfo& operator=(const TerminationInfo& other);
+
+ int process_host_id = content::ChildProcessHost::kInvalidUniqueID;
+ base::ProcessHandle pid = base::kNullProcessHandle;
+ content::ProcessType process_type = content::PROCESS_TYPE_UNKNOWN;
+ base::android::ApplicationState app_state =
+ base::android::APPLICATION_STATE_UNKNOWN;
+
+ // True if this is intentional shutdown of the child process, e.g. when a
+ // tab is closed. Some fields below may not be populated if this is true.
+ bool normal_termination = false;
+
+ // Values from ChildProcessTerminationInfo.
+ // Note base::TerminationStatus and exit_code are missing intentionally
+ // because those fields hold no useful information on Android.
+ bool has_oom_protection_bindings = false;
+ bool was_killed_intentionally_by_browser = false;
+
+ // Note this is slightly different |has_oom_protection_bindings|.
+ // This is equivalent to status == TERMINATION_STATUS_NORMAL_TERMINATION,
+ // which historically also checked whether app is in foreground, using
+ // a slightly different implementation than
+ // ApplicationStatusListener::GetState.
+ bool was_oom_protected_status = false;
+
+ // Applies to renderer process only. Generally means renderer is hosting
+ // one or more visible tabs.
+ bool renderer_has_visible_clients = false;
+
+ // Applies to renderer process only. Generally true indicates that there
+ // is no main frame being hosted in this renderer process. Note there are
+ // edge cases, eg if an invisible main frame and a visible sub frame from
+ // different tabs are sharing the same renderer, then this is false.
+ bool renderer_was_subframe = false;
+ };
+
// CrashDumpObserver client interface.
// Client methods will be called synchronously in the order in which
// clients were registered. It is the implementer's responsibility
@@ -44,13 +87,8 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
virtual void OnChildStart(int process_host_id,
content::PosixFileDescriptorInfo* mappings) = 0;
// OnChildExit is called on the UI thread.
- // OnChildExit may be called twice (once for the child process
- // termination, and once for the IPC channel disconnection).
- virtual void OnChildExit(int process_host_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state) = 0;
+ // OnChildExit may be called twice for the same process.
+ virtual void OnChildExit(const TerminationInfo& info) = 0;
virtual ~Client() {}
};
@@ -84,11 +122,9 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
// content::BrowserChildProcessObserver implementation:
void BrowserChildProcessHostDisconnected(
const content::ChildProcessData& data) override;
- void BrowserChildProcessCrashed(const content::ChildProcessData& data,
- int exit_code) override;
- // On Android we will never observe BrowserChildProcessCrashed
- // because we do not receive exit codes from zygote spawned
- // processes.
+ void BrowserChildProcessKilled(
+ const content::ChildProcessData& data,
+ const content::ChildProcessTerminationInfo& info) override;
// NotificationObserver implementation:
void Observe(int type,
@@ -96,11 +132,7 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
const content::NotificationDetails& details) override;
// Called on child process exit (including crash).
- void OnChildExit(int process_host_id,
- base::ProcessHandle pid,
- content::ProcessType process_type,
- base::TerminationStatus termination_status,
- base::android::ApplicationState app_state);
+ void OnChildExit(const TerminationInfo& info);
content::NotificationRegistrar notification_registrar_;
@@ -110,6 +142,9 @@ class CrashDumpObserver : public content::BrowserChildProcessObserver,
// process_host_id to process id.
std::map<int, base::ProcessHandle> process_host_id_to_pid_;
+ // Key is process_host_id. Only used for BrowserChildProcessHost.
+ std::map<int, TerminationInfo> browser_child_process_info_;
+
DISALLOW_COPY_AND_ASSIGN(CrashDumpObserver);
};
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.cc b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
index c9aca3c97fe..57f710ab886 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.cc
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.cc
@@ -24,6 +24,7 @@
#include "base/linux_util.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
#include "base/rand_util.h"
@@ -34,7 +35,6 @@
#include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
-#include "components/crash/content/app/breakpad_linux_impl.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.h"
#include "third_party/breakpad/breakpad/src/client/linux/minidump_writer/linux_dumper.h"
@@ -108,7 +108,7 @@ CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type,
#if !defined(OS_ANDROID)
upload_(upload),
#endif
- file_descriptor_watcher_(FROM_HERE),
+ fd_watch_controller_(FROM_HERE),
shutting_down_(false),
blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})) {
@@ -145,10 +145,10 @@ void CrashHandlerHostLinux::StartUploaderThread() {
}
void CrashHandlerHostLinux::Init() {
- base::MessageLoopForIO* ml = base::MessageLoopForIO::current();
+ base::MessageLoopCurrentForIO ml = base::MessageLoopCurrentForIO::Get();
CHECK(ml->WatchFileDescriptor(browser_socket_, true /* persistent */,
base::MessagePumpForIO::WATCH_READ,
- &file_descriptor_watcher_, this));
+ &fd_watch_controller_, this));
ml->AddDestructionObserver(this);
}
@@ -225,7 +225,7 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
<< " is disabled."
<< " msg_size:" << msg_size
<< " errno:" << errno;
- file_descriptor_watcher_.StopWatchingFileDescriptor();
+ fd_watch_controller_.StopWatchingFileDescriptor();
return;
}
const bool bad_message = (msg_size != expected_msg_size ||
@@ -417,7 +417,7 @@ void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info,
info->distro = distro_str;
base::FilePath dumps_path("/tmp");
- PathService::Get(base::DIR_TEMP, &dumps_path);
+ base::PathService::Get(base::DIR_TEMP, &dumps_path);
if (!info->upload)
dumps_path = dumps_path_;
const std::string minidump_filename =
@@ -480,7 +480,7 @@ void CrashHandlerHostLinux::QueueCrashDumpTask(
}
void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() {
- file_descriptor_watcher_.StopWatchingFileDescriptor();
+ fd_watch_controller_.StopWatchingFileDescriptor();
// If we are quitting and there are crash dumps in the queue, turn them into
// no-ops.
@@ -498,8 +498,39 @@ bool CrashHandlerHostLinux::IsShuttingDown() const {
namespace crashpad {
+void CrashHandlerHost::AddObserver(Observer* observer) {
+ base::AutoLock lock(observers_lock_);
+ bool inserted = observers_.insert(observer).second;
+ DCHECK(inserted);
+}
+
+void CrashHandlerHost::RemoveObserver(Observer* observer) {
+ base::AutoLock lock(observers_lock_);
+ size_t removed = observers_.erase(observer);
+ DCHECK(removed);
+}
+
+// static
+CrashHandlerHost* CrashHandlerHost::Get() {
+ static CrashHandlerHost* instance = new CrashHandlerHost();
+ return instance;
+}
+
+int CrashHandlerHost::GetDeathSignalSocket() {
+ static bool initialized = BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::BindOnce(&CrashHandlerHost::Init, base::Unretained(this)));
+ DCHECK(initialized);
+
+ return process_socket_.get();
+}
+
+CrashHandlerHost::~CrashHandlerHost() = default;
+
CrashHandlerHost::CrashHandlerHost()
- : file_descriptor_watcher_(FROM_HERE),
+ : observers_lock_(),
+ observers_(),
+ fd_watch_controller_(FROM_HERE),
process_socket_(),
browser_socket_() {
int fds[2];
@@ -513,30 +544,33 @@ CrashHandlerHost::CrashHandlerHost()
process_socket_.reset(fds[0]);
browser_socket_.reset(fds[1]);
- BrowserThread::PostTask(
- BrowserThread::IO, FROM_HERE,
- base::BindOnce(&CrashHandlerHost::Init, base::Unretained(this)));
+ static const int on = 1;
+ CHECK_EQ(0, setsockopt(browser_socket_.get(), SOL_SOCKET, SO_PASSCRED, &on,
+ sizeof(on)));
}
-CrashHandlerHost::~CrashHandlerHost() = default;
-
void CrashHandlerHost::Init() {
- base::MessageLoopForIO* ml = base::MessageLoopForIO::current();
+ base::MessageLoopCurrentForIO ml = base::MessageLoopCurrentForIO::Get();
CHECK(ml->WatchFileDescriptor(browser_socket_.get(), /* persistent= */ true,
base::MessagePumpForIO::WATCH_READ,
- &file_descriptor_watcher_, this));
+ &fd_watch_controller_, this));
ml->AddDestructionObserver(this);
}
bool CrashHandlerHost::ReceiveClientMessage(int client_fd,
base::ScopedFD* handler_fd) {
+ int signo;
+ iovec iov;
+ iov.iov_base = &signo;
+ iov.iov_len = sizeof(signo);
+
msghdr msg;
msg.msg_name = nullptr;
msg.msg_namelen = 0;
- msg.msg_iov = nullptr;
- msg.msg_iovlen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
- char cmsg_buf[CMSG_SPACE(sizeof(int))];
+ char cmsg_buf[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(ucred))];
msg.msg_control = cmsg_buf;
msg.msg_controllen = sizeof(cmsg_buf);
msg.msg_flags = 0;
@@ -547,19 +581,45 @@ bool CrashHandlerHost::ReceiveClientMessage(int client_fd,
return false;
}
- cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
- if (!cmsg || cmsg->cmsg_level != SOL_SOCKET ||
- cmsg->cmsg_type != SCM_RIGHTS || cmsg->cmsg_len < CMSG_LEN(sizeof(int))) {
+ base::ScopedFD child_fd;
+ pid_t child_pid = -1;
+ for (cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET) {
+ continue;
+ }
+
+ if (cmsg->cmsg_type == SCM_RIGHTS) {
+ child_fd.reset(*reinterpret_cast<int*>(CMSG_DATA(cmsg)));
+ } else if (cmsg->cmsg_type == SCM_CREDENTIALS) {
+ child_pid = reinterpret_cast<ucred*>(CMSG_DATA(cmsg))->pid;
+ }
+ }
+
+ if (!child_fd.is_valid()) {
LOG(ERROR) << "Death signal missing descriptor";
return false;
}
- DCHECK(!CMSG_NXTHDR(&msg, cmsg));
- handler_fd->reset(*reinterpret_cast<int*>(CMSG_DATA(cmsg)));
- DCHECK(handler_fd->is_valid());
+ if (child_pid < 0) {
+ LOG(ERROR) << "Death signal missing pid";
+ return false;
+ }
+
+ NotifyCrashSignalObservers(child_pid, signo);
+
+ handler_fd->reset(child_fd.release());
return true;
}
+void CrashHandlerHost::NotifyCrashSignalObservers(base::ProcessId pid,
+ int signo) {
+ base::AutoLock lock(observers_lock_);
+ for (Observer* observer : observers_) {
+ observer->ChildReceivedCrashSignal(pid, signo);
+ }
+}
+
void CrashHandlerHost::OnFileCanWriteWithoutBlocking(int fd) {
NOTREACHED();
}
@@ -591,7 +651,7 @@ void CrashHandlerHost::OnFileCanReadWithoutBlocking(int fd) {
}
void CrashHandlerHost::WillDestroyCurrentMessageLoop() {
- file_descriptor_watcher_.StopWatchingFileDescriptor();
+ fd_watch_controller_.StopWatchingFileDescriptor();
}
} // namespace crashpad
diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.h b/chromium/components/crash/content/browser/crash_handler_host_linux.h
index 147b2d734c3..958f4fa827c 100644
--- a/chromium/components/crash/content/browser/crash_handler_host_linux.h
+++ b/chromium/components/crash/content/browser/crash_handler_host_linux.h
@@ -8,13 +8,16 @@
#include <sys/types.h>
#include <memory>
+#include <set>
#include <string>
#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/message_loop/message_pump_for_io.h"
+#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "components/crash/content/app/breakpad_linux_impl.h"
@@ -34,8 +37,9 @@ struct BreakpadInfo;
// Processes signal that they need to be dumped by sending a datagram over a
// UNIX domain socket. All processes of the same type share the client end of
// this socket which is installed in their descriptor table before exec.
-class CrashHandlerHostLinux : public base::MessagePumpForIO::FdWatcher,
- public base::MessageLoop::DestructionObserver {
+class CrashHandlerHostLinux
+ : public base::MessagePumpForIO::FdWatcher,
+ public base::MessageLoopCurrent::DestructionObserver {
public:
CrashHandlerHostLinux(const std::string& process_type,
const base::FilePath& dumps_path,
@@ -56,7 +60,7 @@ class CrashHandlerHostLinux : public base::MessagePumpForIO::FdWatcher,
void OnFileCanWriteWithoutBlocking(int fd) override;
void OnFileCanReadWithoutBlocking(int fd) override;
- // MessageLoop::DestructionObserver impl:
+ // MessageLoopCurrent::DestructionObserver impl:
void WillDestroyCurrentMessageLoop() override;
// Whether we are shutting down or not.
@@ -97,7 +101,7 @@ class CrashHandlerHostLinux : public base::MessagePumpForIO::FdWatcher,
int process_socket_;
int browser_socket_;
- base::MessagePumpForIO::FdWatchController file_descriptor_watcher_;
+ base::MessagePumpForIO::FdWatchController fd_watch_controller_;
std::unique_ptr<base::Thread> uploader_thread_;
bool shutting_down_;
@@ -113,27 +117,50 @@ class CrashHandlerHostLinux : public base::MessagePumpForIO::FdWatcher,
namespace crashpad {
class CrashHandlerHost : public base::MessagePumpForIO::FdWatcher,
- public base::MessageLoop::DestructionObserver {
+ public base::MessageLoopCurrent::DestructionObserver {
public:
- CrashHandlerHost();
- ~CrashHandlerHost() override;
+ // An interface for observers to be notified when a child process is crashing.
+ class Observer {
+ public:
+ // Called when a child process is crashing. pid is the child's process ID in
+ // the CrashHandlerHost's PID namespace. signo is the signal the child
+ // received. Observers are notified synchronously while the child process
+ // is blocked in its signal handler. Observers may not call AddObserver()
+ // or RemoveObserver() in this method.
+ virtual void ChildReceivedCrashSignal(base::ProcessId pid, int signo) = 0;
+ };
+
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ // Return a pointer to the global CrashHandlerHost instance, which is created
+ // by the first call to this method.
+ static CrashHandlerHost* Get();
// Get the file descriptor which processes should be given in order to signal
// crashes to the browser.
- int GetDeathSignalSocket() const { return process_socket_.get(); }
+ int GetDeathSignalSocket();
+
+ protected:
+ ~CrashHandlerHost() override;
private:
+ CrashHandlerHost();
+
void Init();
bool ReceiveClientMessage(int client_fd, base::ScopedFD* handler_fd);
+ void NotifyCrashSignalObservers(base::ProcessId pid, int signo);
// MessagePumbLibevent::Watcher impl:
void OnFileCanWriteWithoutBlocking(int fd) override;
void OnFileCanReadWithoutBlocking(int fd) override;
- // MessageLoop::DestructionObserver impl:
+ // MessageLoopCurrent::DestructionObserver impl:
void WillDestroyCurrentMessageLoop() override;
- base::MessagePumpForIO::FdWatchController file_descriptor_watcher_;
+ base::Lock observers_lock_;
+ std::set<Observer*> observers_;
+ base::MessagePumpForIO::FdWatchController fd_watch_controller_;
base::ScopedFD process_socket_;
base::ScopedFD browser_socket_;
diff --git a/chromium/components/crash_strings_grdp/OWNERS b/chromium/components/crash_strings_grdp/OWNERS
new file mode 100644
index 00000000000..21fa1065124
--- /dev/null
+++ b/chromium/components/crash_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/crash/OWNERS
diff --git a/chromium/components/crash_strings_grdp/README.md b/chromium/components/crash_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/crash_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/cronet/android/BUILD.gn b/chromium/components/cronet/android/BUILD.gn
index 7fe505ad927..fc1f39aaee3 100644
--- a/chromium/components/cronet/android/BUILD.gn
+++ b/chromium/components/cronet/android/BUILD.gn
@@ -283,9 +283,9 @@ cronet_impl_common_java_srcjar_deps = [
cronet_impl_common_java_deps_to_package =
[ "//net/android:net_thread_stats_uid_java" ]
-# cronet_impl_common_java_base.jar - common Cronet code that is shared
+# cronet_impl_common_base_java.jar - common Cronet code that is shared
# by all Cronet engine implementations.
-android_library("cronet_impl_common_java_base") {
+android_library("cronet_impl_common_base_java") {
java_files = [
"java/src/org/chromium/net/impl/CallbackExceptionImpl.java",
"java/src/org/chromium/net/impl/CronetExceptionImpl.java",
@@ -302,6 +302,8 @@ android_library("cronet_impl_common_java_base") {
"java/src/org/chromium/net/impl/VersionSafeCallbacks.java",
]
+ # Adding deps here won't include those deps in the cronet_impl_common_java.jar.
+ # Please add to cronet_impl_common_java_deps_to_package instead.
deps = [
":cronet_api_java",
"//third_party/android_tools:android_support_annotations_java",
@@ -311,8 +313,8 @@ android_library("cronet_impl_common_java_base") {
srcjar_deps = cronet_impl_common_java_srcjar_deps
}
-# cronet_impl_platform_java.jar - Java platform based implementation of the Cronet engine.
-android_library("cronet_impl_platform_java") {
+# cronet_impl_platform_base_java.jar - Java platform based implementation of the Cronet engine.
+android_library("cronet_impl_platform_base_java") {
java_files = [
"java/src/org/chromium/net/impl/InputStreamChannel.java",
"java/src/org/chromium/net/impl/JavaCronetEngine.java",
@@ -323,7 +325,7 @@ android_library("cronet_impl_platform_java") {
deps = [
":cronet_api_java",
- ":cronet_impl_common_java_base",
+ ":cronet_impl_common_base_java",
"//third_party/android_tools:android_support_annotations_java",
"//third_party/jsr-305:jsr_305_javalib",
]
@@ -339,10 +341,28 @@ cronet_impl_native_java_deps_to_package = [
"//base:base_java",
"//net/android:net_java",
"//url:url_java",
+ ":cronet_urlconnection_impl_java",
]
-# cronet_impl_native_java_base.jar - native implementation of the Cronet engine.
-android_library("cronet_impl_native_java_base") {
+android_library("cronet_urlconnection_impl_java") {
+ java_files = [
+ "java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java",
+ "java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java",
+ "java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java",
+ "java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java",
+ "java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java",
+ "java/src/org/chromium/net/urlconnection/CronetInputStream.java",
+ "java/src/org/chromium/net/urlconnection/CronetOutputStream.java",
+ "java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java",
+ "java/src/org/chromium/net/urlconnection/MessageLoop.java",
+ ]
+ deps = [
+ ":cronet_api_java",
+ ]
+}
+
+# cronet_impl_native_base_java.jar - native implementation of the Cronet engine.
+android_library("cronet_impl_native_base_java") {
java_files = [
"java/src/org/chromium/net/impl/BidirectionalStreamBuilderImpl.java",
"java/src/org/chromium/net/impl/BidirectionalStreamNetworkException.java",
@@ -355,20 +375,13 @@ android_library("cronet_impl_native_java_base") {
"java/src/org/chromium/net/impl/NativeCronetEngineBuilderImpl.java",
"java/src/org/chromium/net/impl/NativeCronetEngineBuilderWithLibraryLoaderImpl.java",
"java/src/org/chromium/net/impl/NativeCronetProvider.java",
- "java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java",
- "java/src/org/chromium/net/urlconnection/CronetChunkedOutputStream.java",
- "java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java",
- "java/src/org/chromium/net/urlconnection/CronetHttpURLConnection.java",
- "java/src/org/chromium/net/urlconnection/CronetHttpURLStreamHandler.java",
- "java/src/org/chromium/net/urlconnection/CronetInputStream.java",
- "java/src/org/chromium/net/urlconnection/CronetOutputStream.java",
- "java/src/org/chromium/net/urlconnection/CronetURLStreamHandlerFactory.java",
- "java/src/org/chromium/net/urlconnection/MessageLoop.java",
]
+ # Adding deps here won't include those deps in the cronet_impl_native_java.jar.
+ # Please add to cronet_impl_native_java_deps_to_package instead.
deps = [
":cronet_api_java",
- ":cronet_impl_common_java_base",
+ ":cronet_impl_common_base_java",
"//third_party/android_tools:android_support_annotations_java",
"//third_party/jsr-305:jsr_305_javalib",
]
@@ -380,9 +393,9 @@ android_library("cronet_impl_native_java_base") {
# Groups all Cronet implementations and the common code into a single Java dependency.
java_group("cronet_impl_all_java") {
deps = [
- ":cronet_impl_common_java_base",
- ":cronet_impl_native_java_base",
- ":cronet_impl_platform_java",
+ ":cronet_impl_common_base_java",
+ ":cronet_impl_native_base_java",
+ ":cronet_impl_platform_base_java",
]
}
@@ -471,6 +484,7 @@ generate_jni("cronet_tests_jni_headers") {
testonly = true
sources = [
"test/javatests/src/org/chromium/net/CronetUrlRequestContextTest.java",
+ "test/javatests/src/org/chromium/net/CronetUrlRequestTest.java",
"test/javatests/src/org/chromium/net/ExperimentalOptionsTest.java",
"test/src/org/chromium/net/CronetTestUtil.java",
"test/src/org/chromium/net/MockCertVerifier.java",
@@ -498,6 +512,7 @@ shared_library("cronet_tests") {
"test/cronet_test_util.h",
"test/cronet_url_request_context_config_test.cc",
"test/cronet_url_request_context_config_test.h",
+ "test/cronet_url_request_test.cc",
"test/experimental_options_test.cc",
"test/mock_cert_verifier.cc",
"test/mock_url_request_job_factory.cc",
@@ -621,6 +636,16 @@ android_apk("cronet_test_apk") {
]
}
+cronet_javatests_deps_to_package = [
+ ":cronet_test_apk_java",
+ "//base:base_java",
+ "//base:base_java_test_support",
+ "//net/android:embedded_test_server_aidl_java",
+ "//net/android:net_java",
+ "//net/android:net_java_test_support",
+ "//url:url_java",
+]
+
android_library("cronet_javatests") {
testonly = true
@@ -664,17 +689,15 @@ android_library("cronet_javatests") {
"test/javatests/src/org/chromium/net/UrlResponseInfoTest.java",
]
+ # Adding deps here won't include those deps in the cronet_tests_java.jar.
+ # Please add to cronet_javatests_deps_to_package instead.
deps = [
":cronet_api_java",
":cronet_impl_all_java",
- ":cronet_test_apk_java",
- "//base:base_java",
- "//base:base_java_test_support",
- "//net/android:net_java",
- "//net/android:net_java_test_support",
"//third_party/android_support_test_runner:runner_java",
"//third_party/junit",
]
+ deps += cronet_javatests_deps_to_package
data = [
"//components/cronet/test/data/",
]
@@ -696,7 +719,9 @@ instrumentation_test_apk("cronet_test_instrumentation_apk") {
"//net/android:net_java",
"//net/android:net_java_test_support",
"//third_party/android_support_test_runner:runner_java",
+ "//third_party/hamcrest:hamcrest_core_java",
]
+ deps += android_extra_test_deps
additional_apks = [ "//net/android:net_test_support_apk" ]
data_deps = [
@@ -740,8 +765,8 @@ android_apk("cronet_smoketests_platform_only_apk") {
deps = [
":cronet_api_java",
- ":cronet_impl_common_java_base",
- ":cronet_impl_platform_java",
+ ":cronet_impl_common_base_java",
+ ":cronet_impl_platform_base_java",
":cronet_smoketests_platform_only_apk_resources",
]
}
@@ -756,6 +781,7 @@ instrumentation_test_apk(
"//base:base_java_test_support",
"//third_party/android_support_test_runner:runner_java",
]
+ deps += android_extra_test_deps
proguard_enabled = true
@@ -783,8 +809,8 @@ android_apk("cronet_smoketests_missing_native_library_apk") {
deps = [
":cronet_api_java",
":cronet_combine_proguard_flags",
- ":cronet_impl_common_java_base",
- ":cronet_impl_platform_java",
+ ":cronet_impl_common_base_java",
+ ":cronet_impl_platform_base_java",
":cronet_test_apk_resources",
]
@@ -805,6 +831,7 @@ instrumentation_test_apk(
deps = [
":cronet_smoketests_missing_native_library_java",
]
+ deps += android_extra_test_deps
proguard_enabled = true
@@ -841,6 +868,7 @@ android_apk("cronet_perf_test_apk") {
":cronet_test_apk_java",
"//base:base_java",
]
+ deps += android_extra_test_deps
proguard_enabled = true
proguard_configs = [
@@ -858,7 +886,7 @@ test("cronet_unittests_android") {
deps = [
":cronet_android_cert_proto",
- ":cronet_impl_native_java_base",
+ ":cronet_impl_native_base_java",
":cronet_static",
"//base",
"//base/test:test_support",
@@ -899,11 +927,13 @@ action("extract_cronet_native_jars") {
]
deps = [
- ":cronet_impl_native_java_base",
+ ":cronet_impl_native_base_java",
]
deps += cronet_impl_native_java_deps_to_package
sources = []
+
+ # Extract pre-desugared jar for each dependency.
foreach(dep, deps) {
sources += [ get_label_info(dep, "target_gen_dir") + "/" +
get_label_info(dep, "name") + ".javac.jar" ]
@@ -937,7 +967,8 @@ action("repackage_extracted_native_jars") {
"*/multidex/*.class",
"*/process_launcher/*.class",
"*/SysUtils.class",
- "*/CachedMetrics.class",
+ "*/CachedMetrics*.class",
+ "org/chromium/base/memory/MemoryPressureMonitor*.class",
]
args = [
@@ -964,11 +995,13 @@ action("extract_cronet_common_jars") {
]
deps = [
- ":cronet_impl_common_java_base",
+ ":cronet_impl_common_base_java",
]
deps += cronet_impl_common_java_deps_to_package
sources = []
+
+ # Extract pre-desugared jar for each dependency.
foreach(dep, deps) {
sources += [ get_label_info(dep, "target_gen_dir") + "/" +
get_label_info(dep, "name") + ".javac.jar" ]
@@ -1007,6 +1040,9 @@ action("repackage_extracted_common_jars") {
]
}
+cronet_test_deps = [ ":cronet_javatests" ]
+cronet_test_deps += cronet_javatests_deps_to_package
+
action("extract_cronet_test_jars") {
# extract_from_jars.py deletes the target directory before extracting.
script = "//components/cronet/tools/extract_from_jars.py"
@@ -1014,17 +1050,15 @@ action("extract_cronet_test_jars") {
testonly = true
sources = [
- "$root_out_dir/lib.java/base/base_java.jar",
- "$root_out_dir/lib.java/base/base_java_test_support.jar",
- "$root_out_dir/lib.java/components/cronet/android/cronet_javatests.jar",
- "$root_out_dir/lib.java/components/cronet/android/cronet_test_apk_java.jar",
- "$root_out_dir/lib.java/net/android/embedded_test_server_aidl_java.jar",
- "$root_out_dir/lib.java/net/android/net_java.jar",
- "$root_out_dir/lib.java/net/android/net_java_test_support.jar",
- "$root_out_dir/lib.java/url/url_java.jar",
NETTY4_JAR_FILE,
]
+ # Extract pre-desugared jar for each cronet_test_deps.
+ foreach(dep, cronet_test_deps) {
+ sources += [ get_label_info(dep, "target_gen_dir") + "/" +
+ get_label_info(dep, "name") + ".javac.jar" ]
+ }
+
_stamp_file = "$target_gen_dir/$target_name.stamp"
outputs = [
_stamp_file,
@@ -1043,16 +1077,9 @@ action("extract_cronet_test_jars") {
]
deps = [
- ":cronet_javatests",
- ":cronet_test_apk_java",
- "//base:base_java",
- "//base:base_java_test_support",
- "//net/android:embedded_test_server_aidl_java",
- "//net/android:net_java",
- "//net/android:net_java_test_support",
"//third_party/netty4:netty_all_java",
- "//url:url_java",
]
+ deps += cronet_test_deps
}
action("repackage_extracted_test_jars") {
@@ -1152,14 +1179,14 @@ jar_src("jar_cronet_api_source") {
jar_src("jar_cronet_impl_common_java_source") {
src_search_dirs = [ "java/src" ]
- source_deps = [ ":cronet_impl_common_java_base" ]
+ source_deps = [ ":cronet_impl_common_base_java" ]
srcjar_deps = cronet_impl_common_java_srcjar_deps
jar_path = "$_package_dir/cronet_impl_common_java-src.jar"
}
jar_src("jar_cronet_impl_platform_java_source") {
src_search_dirs = [ "java/src" ]
- source_deps = [ ":cronet_impl_platform_java" ]
+ source_deps = [ ":cronet_impl_platform_base_java" ]
jar_path = "$_package_dir/cronet_impl_platform_java-src.jar"
}
@@ -1189,7 +1216,7 @@ jar_src("jar_cronet_impl_native_java_source") {
"//url/android/java/src",
]
source_deps = [
- ":cronet_impl_native_java_base",
+ ":cronet_impl_native_base_java",
"//base:base_java",
"//net/android:net_java",
"//url:url_java",
@@ -1222,9 +1249,9 @@ action("generate_licenses") {
action("generate_javadoc") {
script = "//components/cronet/tools/generate_javadoc.py"
depfile = "$target_gen_dir/$target_name.d"
- _stamp_file = "$target_gen_dir/$target_name.stamp"
+ _zip_file = "$target_gen_dir/$target_name.zip"
outputs = [
- _stamp_file,
+ _zip_file,
]
args = [
"--output-dir",
@@ -1237,8 +1264,8 @@ action("generate_javadoc") {
rebase_path("//components/cronet/README.md", root_build_dir),
"--depfile",
rebase_path(depfile, root_build_dir),
- "--stamp",
- rebase_path(_stamp_file, root_build_dir),
+ "--zip-file",
+ rebase_path(_zip_file, root_build_dir),
"--android-sdk-jar",
rebase_path(android_sdk_jar, root_build_dir),
@@ -1268,8 +1295,8 @@ copy("cronet_package_copy") {
deps = [
":cronet_api_java",
":cronet_combine_proguard_flags",
- ":cronet_impl_common_java_base",
- ":cronet_impl_platform_java",
+ ":cronet_impl_common_base_java",
+ ":cronet_impl_platform_base_java",
]
}
@@ -1281,11 +1308,13 @@ template("copy_java8_jars") {
get_label_info(_dep, "target_gen_dir") + "/" + _dep_name + ".javac.jar"
_output_jar = "$_package_dir/" + _dep_name + ".jar"
- # cronet_api.jar is a special case. Its file name is
- # different from the target name that builds it.
+ # Adjust file names that are different from the target name that builds it.
if (_output_jar == "$_package_dir/" + "cronet_api_java.jar") {
_output_jar = "$_package_dir/" + "cronet_api.jar"
}
+ if (_output_jar == "$_package_dir/" + "cronet_impl_platform_base_java.jar") {
+ _output_jar = "$_package_dir/" + "cronet_impl_platform_java.jar"
+ }
# _deps have targets which match the java target whitelist. Add a
# trailing X to avoid the copy() target matching the whitelist.
@@ -1314,7 +1343,7 @@ template("copy_java8_jars") {
copy_java8_jars("copy_cronet_java8_jars") {
deps = [
":cronet_api_java",
- ":cronet_impl_platform_java",
+ ":cronet_impl_platform_base_java",
]
}
@@ -1464,6 +1493,15 @@ android_java_prebuilt("package_impl_native_java") {
]
}
+android_java_prebuilt("package_impl_platform_java") {
+ jar_path = "$_package_dir/cronet_impl_platform_java.jar"
+ deps = [
+ ":copy_cronet_java8_jars_cronet_impl_platform_base_javaX",
+ ":package_api_java",
+ ":package_impl_common_java",
+ ]
+}
+
# Enforce that ARM Neon is not used when building for ARMv7
if (target_cpu == "arm" && arm_version == 7 && !arm_use_neon) {
action("enforce_no_neon") {
@@ -1501,24 +1539,24 @@ action("api_static_checks") {
root_build_dir),
"--impl_jar",
rebase_path(
- "$root_out_dir/lib.java/components/cronet/android/cronet_impl_common_java_base.jar",
+ "$root_out_dir/lib.java/components/cronet/android/cronet_impl_common_base_java.jar",
root_build_dir),
"--impl_jar",
rebase_path(
- "$root_out_dir/lib.java/components/cronet/android/cronet_impl_platform_java.jar",
+ "$root_out_dir/lib.java/components/cronet/android/cronet_impl_platform_base_java.jar",
root_build_dir),
"--impl_jar",
rebase_path(
- "$root_out_dir/lib.java/components/cronet/android/cronet_impl_native_java_base.jar",
+ "$root_out_dir/lib.java/components/cronet/android/cronet_impl_native_base_java.jar",
root_build_dir),
"--stamp",
rebase_path(outputs[0], root_build_dir),
]
deps = [
":cronet_api_java",
- ":cronet_impl_common_java_base",
- ":cronet_impl_native_java_base",
- ":cronet_impl_platform_java",
+ ":cronet_impl_common_base_java",
+ ":cronet_impl_native_base_java",
+ ":cronet_impl_platform_base_java",
]
inputs = [
"//components/cronet/tools/update_api.py",
@@ -1577,3 +1615,198 @@ group("cronet_test_package") {
]
}
}
+
+_maven_dir = "$_package_dir/maven-$current_cpu"
+_maven_modules_dir = "$_maven_dir/org/chromium/net"
+_maven_test_dir = "$_maven_dir/test"
+_maven_version =
+ "$chrome_version_major.$chrome_version_build.$chrome_version_patch"
+
+copy("cronet_maven_test_copy") {
+ sources = [
+ "maven/build.gradle",
+ "maven/local.properties",
+ "maven/settings.gradle",
+ ]
+ outputs = [
+ "$_maven_test_dir/{{source_file_part}}",
+ ]
+}
+
+process_version("cronet_maven_build_embedded_copy") {
+ template_file = "maven/test/build_embedded.gradle.template"
+ sources = [
+ "//build/util/LASTCHANGE",
+ "//chrome/VERSION",
+ ]
+ output = "$_maven_test_dir/test_embedded/build.gradle"
+}
+
+process_version("cronet_maven_build_fallback_copy") {
+ template_file = "maven/test/build_fallback.gradle.template"
+ sources = [
+ "//build/util/LASTCHANGE",
+ "//chrome/VERSION",
+ ]
+ output = "$_maven_test_dir/test_fallback/build.gradle"
+}
+
+if (use_platform_icu_alternatives) {
+ action("cronet_maven_test_build") {
+ script = "maven/test/build_with_gradle.py"
+ depfile = "$target_gen_dir/$target_name.d"
+ deps = [
+ ":cronet_maven_build_embedded_copy",
+ ":cronet_maven_build_fallback_copy",
+ ":cronet_maven_modules",
+ ":cronet_maven_test_copy",
+
+ # These deps ensure all source files of the sample app are deps.
+ ":cronet_sample_apk",
+ ":cronet_sample_test_apk",
+ ]
+ _stamp_file = "$target_gen_dir/$target_name.stamp"
+ outputs = [
+ _stamp_file,
+ "$_maven_test_dir/build/outputs/apk/debug/test-debug.apk",
+ "$_maven_test_dir/build/outputs/apk/androidTest/debug/test-debug-androidTest.apk",
+ ]
+ args = [
+ "--project-dir",
+ rebase_path("$_maven_test_dir"),
+ "--depfile",
+ rebase_path(depfile, root_build_dir),
+ "--stamp",
+ rebase_path(_stamp_file, root_build_dir),
+ ]
+ testonly = true
+ }
+}
+
+# Builds a maven module.
+template("cronet_maven_module") {
+ _module_name = invoker.module_name
+
+ # Build POM file.
+ _pom_target_name = "pom_$target_name"
+ _deps = [ ":$_pom_target_name" ]
+ process_version(_pom_target_name) {
+ template_file = "maven/$_module_name.pom.template"
+ sources = [
+ "//build/util/LASTCHANGE",
+ "//chrome/VERSION",
+ ]
+ output = "$_maven_modules_dir/$_module_name/$_maven_version/$_module_name-$_maven_version.pom"
+ }
+
+ if (defined(invoker.resource_dir)) {
+ android_resources(invoker.module_name + "_resources") {
+ resource_dirs = [ invoker.resource_dir ]
+ android_manifest = "../../../build/android/AndroidManifest.xml"
+ }
+ }
+
+ # Build AAR file.
+ _aar_target_name = "aar_$target_name"
+ dist_aar(_aar_target_name) {
+ deps = [
+ ":cronet_package_copy",
+ invoker.aar_jar_dep,
+ ]
+ direct_deps_only = true
+ if (defined(invoker.aar_proguard_config)) {
+ proguard_configs = [ invoker.aar_proguard_config ]
+ }
+ if (defined(invoker.aar_native_lib_dep)) {
+ native_libraries = get_target_outputs(invoker.aar_native_lib_dep)
+ deps += [ invoker.aar_native_lib_dep ]
+ }
+ if (defined(invoker.resource_dir)) {
+ deps += [ ":" + invoker.module_name + "_resources" ]
+ }
+ output = "$root_build_dir/$_aar_target_name.aar"
+ }
+
+ _aar_copy_target_name = "$target_name.aar"
+ _deps += [ ":$_aar_copy_target_name" ]
+ copy(_aar_copy_target_name) {
+ sources = get_target_outputs(":$_aar_target_name")
+ outputs = [
+ "$_maven_modules_dir/$_module_name/$_maven_version/$_module_name-$_maven_version.aar",
+ ]
+ deps = [
+ ":$_aar_target_name",
+ ]
+ }
+
+ if (defined(invoker.src_jar_dep)) {
+ _copy_target_name = "$target_name-sources.jar"
+ _deps += [ ":$_copy_target_name" ]
+ copy(_copy_target_name) {
+ sources = get_target_outputs(invoker.src_jar_dep)
+ outputs = [
+ "$_maven_modules_dir/$_module_name/$_maven_version/$_module_name-$_maven_version-sources.jar",
+ ]
+ deps = [
+ invoker.src_jar_dep,
+ ]
+ }
+ }
+
+ if (defined(invoker.javadoc_jar_dep)) {
+ _copy_target_name = "$target_name-javadoc.jar"
+ _deps += [ ":$_copy_target_name" ]
+ copy(_copy_target_name) {
+ sources = get_target_outputs(invoker.javadoc_jar_dep)
+ outputs = [
+ "$_maven_modules_dir/$_module_name/$_maven_version/$_module_name-$_maven_version-javadoc.jar",
+ ]
+ deps = [
+ invoker.javadoc_jar_dep,
+ ]
+ }
+ }
+
+ group(target_name) {
+ deps = _deps
+ }
+}
+
+cronet_maven_module("cronet_maven_api_module") {
+ module_name = "cronet-api"
+ aar_jar_dep = ":package_api_java"
+ src_jar_dep = ":jar_cronet_api_source"
+ javadoc_jar_dep = ":generate_javadoc"
+ resource_dir = "api/res"
+}
+
+cronet_maven_module("cronet_maven_impl_common_module") {
+ module_name = "cronet-common"
+ aar_jar_dep = ":package_impl_common_java"
+ aar_proguard_config = "$_package_dir/cronet_impl_common_proguard.cfg"
+ src_jar_dep = ":jar_cronet_impl_common_java_source"
+}
+
+cronet_maven_module("cronet_maven_impl_native_module") {
+ module_name = "cronet-embedded"
+ aar_jar_dep = ":package_impl_native_java"
+ aar_proguard_config = "$_package_dir/cronet_impl_native_proguard.cfg"
+ aar_native_lib_dep = ":cronet_package_copy_native_lib"
+ src_jar_dep = ":jar_cronet_impl_native_java_source"
+}
+
+cronet_maven_module("cronet_maven_impl_platform_module") {
+ module_name = "cronet-fallback"
+ aar_jar_dep = ":package_impl_platform_java"
+ aar_proguard_config = "$_package_dir/cronet_impl_platform_proguard.cfg"
+ src_jar_dep = ":jar_cronet_impl_platform_java_source"
+}
+
+group("cronet_maven_modules") {
+ deps = [
+ ":cronet_maven_api_module",
+ ":cronet_maven_impl_common_module",
+ ":cronet_maven_impl_native_module",
+ ":cronet_maven_impl_platform_module",
+ ]
+}
diff --git a/chromium/components/cronet/ios/BUILD.gn b/chromium/components/cronet/ios/BUILD.gn
index b8043a2804b..f7388c5f94b 100644
--- a/chromium/components/cronet/ios/BUILD.gn
+++ b/chromium/components/cronet/ios/BUILD.gn
@@ -161,8 +161,7 @@ action("generate_accept_languages") {
static_library("cronet_static") {
visibility = [ ":*" ]
deps = _cronet_deps
- deps += [ ":cronet_sources_with_global_state" ]
- sources = _cronet_sources
+ sources = _cronet_sources + [ "ios_global_state_configuration.cc" ]
public_configs = [ ":cronet_include_config" ]
public_deps = [
"//components/grpc_support",
diff --git a/chromium/components/cronet/ios/cronet_consumer/BUILD.gn b/chromium/components/cronet/ios/cronet_consumer/BUILD.gn
index ea1be9030a4..a0454400856 100644
--- a/chromium/components/cronet/ios/cronet_consumer/BUILD.gn
+++ b/chromium/components/cronet/ios/cronet_consumer/BUILD.gn
@@ -46,7 +46,7 @@ cronet_consumer_template("cronet_consumer") {
# TODO(mef): Building "cronet_consumer_static" app with additional_target_cpus
# causes "cronet_static_framework" to build lipo_binary("libcronet") for
# duplicate architecture (e.g. arm64+arm64) and breaks the build.
-if (!defined(additional_target_cpus)) {
+if (!defined(additional_target_cpus) || additional_target_cpus == []) {
cronet_consumer_template("cronet_consumer_static") {
deps = [
"//components/cronet/ios:cronet_static_framework",
diff --git a/chromium/components/cronet/ios/test/BUILD.gn b/chromium/components/cronet/ios/test/BUILD.gn
index a8da143dd9e..f8ee42ab856 100644
--- a/chromium/components/cronet/ios/test/BUILD.gn
+++ b/chromium/components/cronet/ios/test/BUILD.gn
@@ -16,6 +16,7 @@ test("cronet_test") {
"cronet_pkp_test.mm",
"cronet_prefs_test.mm",
"cronet_quic_test.mm",
+ "cronet_test_base.h",
"cronet_test_base.mm",
"cronet_test_runner.mm",
"get_stream_engine.mm",
diff --git a/chromium/components/crx_file/crx_creator_unittest.cc b/chromium/components/crx_file/crx_creator_unittest.cc
index 627b8c92952..086a5a50ae1 100644
--- a/chromium/components/crx_file/crx_creator_unittest.cc
+++ b/chromium/components/crx_file/crx_creator_unittest.cc
@@ -16,7 +16,7 @@ namespace {
base::FilePath TestFile(const std::string& file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/crx_file/crx_verifier.cc b/chromium/components/crx_file/crx_verifier.cc
index 36c1c91f71e..a342d743e14 100644
--- a/chromium/components/crx_file/crx_verifier.cc
+++ b/chromium/components/crx_file/crx_verifier.cc
@@ -76,7 +76,7 @@ bool ReadHashAndVerifyArchive(base::File* file,
size_t len = 0;
while ((len = ReadAndHashBuffer(buffer, arraysize(buffer), file, hash)) > 0) {
for (auto& verifier : verifiers)
- verifier->VerifyUpdate(buffer, len);
+ verifier->VerifyUpdate(base::make_span(buffer, len));
}
for (auto& verifier : verifiers) {
if (!verifier->VerifyFinal())
@@ -163,16 +163,13 @@ VerifierResult VerifyCrx3(
auto v = std::make_unique<crypto::SignatureVerifier>();
static_assert(sizeof(unsigned char) == sizeof(uint8_t),
"Unsupported char size.");
- if (!v->VerifyInit(
- proof_type.second, reinterpret_cast<const uint8_t*>(sig.data()),
- sig.size(), reinterpret_cast<const uint8_t*>(key.data()),
- key.size()))
+ if (!v->VerifyInit(proof_type.second,
+ base::as_bytes(base::make_span(sig)),
+ base::as_bytes(base::make_span(key))))
return VerifierResult::ERROR_SIGNATURE_INITIALIZATION_FAILED;
- v->VerifyUpdate(kSignatureContext, arraysize(kSignatureContext));
- v->VerifyUpdate(header_size_octets, arraysize(header_size_octets));
- v->VerifyUpdate(
- reinterpret_cast<const uint8_t*>(signed_header_data_str.data()),
- signed_header_data_str.size());
+ v->VerifyUpdate(kSignatureContext);
+ v->VerifyUpdate(header_size_octets);
+ v->VerifyUpdate(base::as_bytes(base::make_span(signed_header_data_str)));
verifiers.push_back(std::move(v));
}
}
@@ -221,9 +218,8 @@ VerifierResult VerifyCrx2(
return VerifierResult::ERROR_HEADER_INVALID;
std::vector<std::unique_ptr<crypto::SignatureVerifier>> verifiers;
verifiers.push_back(std::make_unique<crypto::SignatureVerifier>());
- if (!verifiers[0]->VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1,
- sig.data(), sig.size(), key.data(),
- key.size())) {
+ if (!verifiers[0]->VerifyInit(crypto::SignatureVerifier::RSA_PKCS1_SHA1, sig,
+ key)) {
return VerifierResult::ERROR_SIGNATURE_INITIALIZATION_FAILED;
}
diff --git a/chromium/components/crx_file/crx_verifier_unittest.cc b/chromium/components/crx_file/crx_verifier_unittest.cc
index d5bd5a88296..54dd44f0cea 100644
--- a/chromium/components/crx_file/crx_verifier_unittest.cc
+++ b/chromium/components/crx_file/crx_verifier_unittest.cc
@@ -13,7 +13,7 @@ namespace {
base::FilePath TestFile(const std::string& file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/cryptauth/BUILD.gn b/chromium/components/cryptauth/BUILD.gn
index 6151b252dfb..791f0b9ef20 100644
--- a/chromium/components/cryptauth/BUILD.gn
+++ b/chromium/components/cryptauth/BUILD.gn
@@ -45,9 +45,6 @@ static_library("cryptauth") {
"cryptauth_service.h",
"data_with_timestamp.cc",
"data_with_timestamp.h",
- "device_capability_manager.h",
- "device_capability_manager_impl.cc",
- "device_capability_manager_impl.h",
"device_classifier_util.cc",
"device_classifier_util.h",
"device_to_device_authenticator.cc",
@@ -70,12 +67,16 @@ static_library("cryptauth") {
"remote_beacon_seed_fetcher.h",
"remote_device.cc",
"remote_device.h",
+ "remote_device_cache.cc",
+ "remote_device_cache.h",
"remote_device_loader.cc",
"remote_device_loader.h",
"remote_device_provider.cc",
"remote_device_provider.h",
"remote_device_provider_impl.cc",
"remote_device_provider_impl.h",
+ "remote_device_ref.cc",
+ "remote_device_ref.h",
"secure_channel.cc",
"secure_channel.h",
"secure_context.h",
@@ -85,6 +86,10 @@ static_library("cryptauth") {
"secure_message_delegate_impl.h",
"session_keys.cc",
"session_keys.h",
+ "software_feature_manager.h",
+ "software_feature_manager_impl.cc",
+ "software_feature_manager_impl.h",
+ "software_feature_state.h",
"switches.cc",
"switches.h",
"sync_scheduler.cc",
@@ -121,8 +126,6 @@ static_library("test_support") {
testonly = true
sources = [
- "cryptauth_test_util.cc",
- "cryptauth_test_util.h",
"device_to_device_responder_operations.cc",
"device_to_device_responder_operations.h",
"fake_authenticator.cc",
@@ -141,8 +144,6 @@ static_library("test_support") {
"fake_cryptauth_gcm_manager.h",
"fake_cryptauth_service.cc",
"fake_cryptauth_service.h",
- "fake_device_capability_manager.cc",
- "fake_device_capability_manager.h",
"fake_gcm_device_info_provider.cc",
"fake_gcm_device_info_provider.h",
"fake_remote_device_provider.cc",
@@ -153,6 +154,8 @@ static_library("test_support") {
"fake_secure_context.h",
"fake_secure_message_delegate.cc",
"fake_secure_message_delegate.h",
+ "fake_software_feature_manager.cc",
+ "fake_software_feature_manager.h",
"mock_cryptauth_client.cc",
"mock_cryptauth_client.h",
"mock_foreground_eid_generator.cc",
@@ -191,7 +194,6 @@ source_set("unit_tests") {
"cryptauth_enroller_impl_unittest.cc",
"cryptauth_enrollment_manager_impl_unittest.cc",
"cryptauth_gcm_manager_impl_unittest.cc",
- "device_capability_manager_impl_unittest.cc",
"device_to_device_authenticator_unittest.cc",
"device_to_device_operations_unittest.cc",
"device_to_device_secure_context_unittest.cc",
@@ -200,10 +202,13 @@ source_set("unit_tests") {
"local_device_data_provider_unittest.cc",
"raw_eid_generator_impl_unittest.cc",
"remote_beacon_seed_fetcher_unittest.cc",
+ "remote_device_cache_unittest.cc",
"remote_device_loader_unittest.cc",
"remote_device_provider_impl_unittest.cc",
+ "remote_device_ref_unittest.cc",
"secure_channel_unittest.cc",
"session_keys_unittest.cc",
+ "software_feature_manager_impl_unittest.cc",
"sync_scheduler_impl_unittest.cc",
"wire_message_unittest.cc",
]
diff --git a/chromium/components/cryptauth/background_eid_generator.cc b/chromium/components/cryptauth/background_eid_generator.cc
index fd41236800c..88b145ec29f 100644
--- a/chromium/components/cryptauth/background_eid_generator.cc
+++ b/chromium/components/cryptauth/background_eid_generator.cc
@@ -15,7 +15,7 @@
#include "components/cryptauth/raw_eid_generator.h"
#include "components/cryptauth/raw_eid_generator_impl.h"
#include "components/cryptauth/remote_beacon_seed_fetcher.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
namespace cryptauth {
@@ -112,7 +112,8 @@ std::string BackgroundEidGenerator::IdentifyRemoteDeviceByAdvertisement(
if (!remote_beacon_seed_fetcher->FetchSeedsForDeviceId(device_id,
&beacon_seeds)) {
PA_LOG(WARNING) << "Error fetching beacon seeds for device with ID "
- << RemoteDevice::TruncateDeviceIdForLogs(device_id);
+ << RemoteDeviceRef::TruncateDeviceIdForLogs(
+ device_id);
return false;
}
diff --git a/chromium/components/cryptauth/background_eid_generator_unittest.cc b/chromium/components/cryptauth/background_eid_generator_unittest.cc
index 2b02a1aee71..70bfdeb060e 100644
--- a/chromium/components/cryptauth/background_eid_generator_unittest.cc
+++ b/chromium/components/cryptauth/background_eid_generator_unittest.cc
@@ -14,7 +14,7 @@
#include "components/cryptauth/mock_remote_beacon_seed_fetcher.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/raw_eid_generator_impl.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/components/cryptauth/ble/ble_advertisement_generator.cc b/chromium/components/cryptauth/ble/ble_advertisement_generator.cc
index 82e32b20f2a..b9eea585cc1 100644
--- a/chromium/components/cryptauth/ble/ble_advertisement_generator.cc
+++ b/chromium/components/cryptauth/ble/ble_advertisement_generator.cc
@@ -10,7 +10,7 @@
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "components/cryptauth/local_device_data_provider.h"
#include "components/cryptauth/remote_beacon_seed_fetcher.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
namespace cryptauth {
@@ -64,14 +64,16 @@ BleAdvertisementGenerator::GenerateBleAdvertisementInternal(
if (!remote_beacon_seed_fetcher->FetchSeedsForDeviceId(
device_id, &remote_beacon_seeds)) {
PA_LOG(WARNING) << "Error fetching beacon seeds for device with ID "
- << RemoteDevice::TruncateDeviceIdForLogs(device_id) << ". "
+ << RemoteDeviceRef::TruncateDeviceIdForLogs(device_id)
+ << ". "
<< "Cannot advertise without seeds.";
return nullptr;
}
if (remote_beacon_seeds.empty()) {
PA_LOG(WARNING) << "No synced seeds exist for device with ID "
- << RemoteDevice::TruncateDeviceIdForLogs(device_id) << ". "
+ << RemoteDeviceRef::TruncateDeviceIdForLogs(device_id)
+ << ". "
<< "Cannot advertise without seeds.";
return nullptr;
}
@@ -81,7 +83,8 @@ BleAdvertisementGenerator::GenerateBleAdvertisementInternal(
remote_beacon_seeds);
if (!service_data) {
PA_LOG(WARNING) << "Error generating advertisement for device with ID "
- << RemoteDevice::TruncateDeviceIdForLogs(device_id) << ". "
+ << RemoteDeviceRef::TruncateDeviceIdForLogs(device_id)
+ << ". "
<< "Cannot advertise.";
return nullptr;
}
diff --git a/chromium/components/cryptauth/ble/ble_advertisement_generator_unittest.cc b/chromium/components/cryptauth/ble/ble_advertisement_generator_unittest.cc
index b28a49770b6..9a2cb064605 100644
--- a/chromium/components/cryptauth/ble/ble_advertisement_generator_unittest.cc
+++ b/chromium/components/cryptauth/ble/ble_advertisement_generator_unittest.cc
@@ -14,6 +14,7 @@
#include "components/cryptauth/mock_local_device_data_provider.h"
#include "components/cryptauth/mock_remote_beacon_seed_fetcher.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,7 +28,7 @@ namespace {
const char kFakePublicKey[] = "fakePublicKey";
std::vector<BeaconSeed> CreateFakeBeaconSeedsForDevice(
- const RemoteDevice& remote_device) {
+ RemoteDeviceRef remote_device) {
BeaconSeed seed1;
seed1.set_data("seed1Data" + remote_device.GetTruncatedDeviceIdForLogs());
seed1.set_start_time_millis(1000L);
@@ -47,7 +48,7 @@ std::vector<BeaconSeed> CreateFakeBeaconSeedsForDevice(
class CryptAuthBleAdvertisementGeneratorTest : public testing::Test {
protected:
CryptAuthBleAdvertisementGeneratorTest()
- : fake_device_(GenerateTestRemoteDevices(1)[0]),
+ : fake_device_(CreateRemoteDeviceRefListForTest(1)[0]),
fake_advertisement_("advertisement1", 1000L, 2000L) {}
void SetUp() override {
@@ -76,7 +77,7 @@ class CryptAuthBleAdvertisementGeneratorTest : public testing::Test {
mock_seed_fetcher_.get());
}
- const RemoteDevice fake_device_;
+ const RemoteDeviceRef fake_device_;
const DataWithTimestamp fake_advertisement_;
std::unique_ptr<MockRemoteBeaconSeedFetcher> mock_seed_fetcher_;
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
index 88b97a7378f..ae753447aa4 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.cc
@@ -56,7 +56,7 @@ BluetoothLowEnergyWeaveClientConnection::Factory*
// static
std::unique_ptr<Connection>
BluetoothLowEnergyWeaveClientConnection::Factory::NewInstance(
- const RemoteDevice& remote_device,
+ RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::BluetoothDevice* bluetooth_device,
@@ -77,7 +77,7 @@ void BluetoothLowEnergyWeaveClientConnection::Factory::SetInstanceForTesting(
std::unique_ptr<Connection>
BluetoothLowEnergyWeaveClientConnection::Factory::BuildInstance(
- const RemoteDevice& remote_device,
+ RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::BluetoothDevice* bluetooth_device,
@@ -140,7 +140,7 @@ std::string BluetoothLowEnergyWeaveClientConnection::SubStatusToString(
BluetoothLowEnergyWeaveClientConnection::
BluetoothLowEnergyWeaveClientConnection(
- const RemoteDevice& device,
+ RemoteDeviceRef device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::BluetoothDevice* bluetooth_device,
@@ -207,8 +207,6 @@ void BluetoothLowEnergyWeaveClientConnection::SetConnectionLatency() {
return;
}
- PA_LOG(INFO) << "Setting connection latency for " << GetDeviceInfoLogString()
- << ".";
bluetooth_device->SetConnectionLatency(
device::BluetoothDevice::ConnectionLatency::CONNECTION_LATENCY_LOW,
base::Bind(&BluetoothLowEnergyWeaveClientConnection::CreateGattConnection,
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
index fe5e5c4a78a..54d3bf96fdd 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection.h
@@ -56,7 +56,7 @@ class BluetoothLowEnergyWeaveClientConnection
class Factory {
public:
static std::unique_ptr<Connection> NewInstance(
- const RemoteDevice& remote_device,
+ RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::BluetoothDevice* bluetooth_device,
@@ -65,7 +65,7 @@ class BluetoothLowEnergyWeaveClientConnection
protected:
virtual std::unique_ptr<Connection> BuildInstance(
- const RemoteDevice& remote_device,
+ RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::BluetoothDevice* bluetooth_device,
@@ -91,7 +91,7 @@ class BluetoothLowEnergyWeaveClientConnection
// Constructs the Connection object; a subsequent call to Connect() is
// necessary to initiate the BLE connection.
BluetoothLowEnergyWeaveClientConnection(
- const RemoteDevice& remote_device,
+ RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::BluetoothDevice* bluetooth_device,
diff --git a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
index 2572194cf6e..d95625a3caf 100644
--- a/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
+++ b/chromium/components/cryptauth/ble/bluetooth_low_energy_weave_client_connection_unittest.cc
@@ -20,8 +20,8 @@
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "components/cryptauth/connection_finder.h"
#include "components/cryptauth/connection_observer.h"
-#include "components/cryptauth/cryptauth_test_util.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
+#include "components/cryptauth/remote_device_test_util.h"
#include "components/cryptauth/wire_message.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
@@ -61,6 +61,8 @@ const char kServiceID[] = "service id";
const char kTXCharacteristicID[] = "TX characteristic id";
const char kRXCharacteristicID[] = "RX characteristic id";
+const char kTestRemoteDeviceBluetoothAddress[] = "AA:BB:CC:DD:EE:FF";
+
const device::BluetoothRemoteGattCharacteristic::Properties
kCharacteristicProperties =
device::BluetoothRemoteGattCharacteristic::PROPERTY_BROADCAST |
@@ -210,7 +212,7 @@ class TestBluetoothLowEnergyWeaveClientConnection
: public BluetoothLowEnergyWeaveClientConnection {
public:
TestBluetoothLowEnergyWeaveClientConnection(
- const RemoteDevice& remote_device,
+ RemoteDeviceRef remote_device,
scoped_refptr<device::BluetoothAdapter> adapter,
const device::BluetoothUUID remote_service_uuid,
device::MockBluetoothDevice* mock_bluetooth_device,
@@ -334,7 +336,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
: public testing::Test {
public:
CryptAuthBluetoothLowEnergyWeaveClientConnectionTest()
- : remote_device_(CreateLERemoteDeviceForTest()),
+ : remote_device_(CreateRemoteDeviceRefForTest()),
service_uuid_(device::BluetoothUUID(kServiceUUID)),
tx_characteristic_uuid_(device::BluetoothUUID(kTXCharacteristicUUID)),
rx_characteristic_uuid_(device::BluetoothUUID(kRXCharacteristicUUID)) {}
@@ -405,7 +407,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
mock_bluetooth_device_.get(), should_set_low_connection_latency));
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
// Add the mock observer to observe on OnDidMessageSend.
connection_observer_ =
@@ -445,14 +447,14 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
// Handle setting the connection latency.
EXPECT_EQ(connection->sub_status(),
SubStatus::WAITING_CONNECTION_LATENCY);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
ASSERT_FALSE(connection_latency_callback_.is_null());
ASSERT_FALSE(connection_latency_error_callback_.is_null());
connection_latency_callback_.Run();
}
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_GATT_CONNECTION);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Preparing |connection| to run |create_gatt_connection_success_callback_|.
EXPECT_FALSE(create_gatt_connection_error_callback_.is_null());
@@ -468,7 +470,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
adapter_, kTestRemoteDeviceBluetoothAddress));
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CHARACTERISTICS);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
}
// Transitions |connection| from WAITING_CHARACTERISTICS to
@@ -487,7 +489,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
{rx_characteristic_uuid_, kRXCharacteristicID});
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_NOTIFY_SESSION);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
}
// Transitions |connection| from WAITING_NOTIFY_SESSION to
@@ -516,7 +518,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
EXPECT_EQ(last_value_written_on_tx_characteristic_, kConnectionRequest);
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_RESPONSE);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
}
// Transitions |connection| from WAITING_CONNECTION_RESPONSE to CONNECTED.
@@ -547,7 +549,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
}
EXPECT_EQ(connection->sub_status(), SubStatus::CONNECTED_AND_IDLE);
- EXPECT_EQ(connection->status(), Connection::CONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::CONNECTED);
}
// Transitions |connection| to a DISCONNECTED state regardless of its initial
@@ -570,7 +572,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
}
void DeleteConnectionWithoutCallingDisconnect(
@@ -648,7 +650,7 @@ class CryptAuthBluetoothLowEnergyWeaveClientConnectionTest
}
protected:
- const RemoteDevice remote_device_;
+ const RemoteDeviceRef remote_device_;
const device::BluetoothUUID service_uuid_;
const device::BluetoothUUID tx_characteristic_uuid_;
const device::BluetoothUUID rx_characteristic_uuid_;
@@ -775,7 +777,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
RunWriteCharacteristicSuccessCallback();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
BLE_WEAVE_CONNECTION_RESULT_CLOSED_NORMALLY);
@@ -849,7 +851,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
{rx_characteristic_uuid_, kRXCharacteristicID});
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyGattServicesUnavailableEventSent();
VerifyBleWeaveConnectionResult(
@@ -876,7 +878,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
{rx_characteristic_uuid_, kRXCharacteristicID});
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyGattServicesUnavailableEventSent();
VerifyBleWeaveConnectionResult(
@@ -901,7 +903,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
VerifyGattNotifySessionResult(false);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -940,7 +942,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1112,7 +1114,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1130,7 +1132,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
EXPECT_EQ(receiver_->GetReasonForClose(), ReasonForClose::UNKNOWN_ERROR);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1160,7 +1162,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 2 /* num_writes */);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1204,7 +1206,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
RunWriteCharacteristicSuccessCallback();
VerifyGattWriteCharacteristicResult(true /* success */, 3 /* num_writes */);
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1320,7 +1322,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
}
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1344,7 +1346,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
// No GATT connection should be created before the delay.
connection->Connect();
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_LATENCY);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
EXPECT_TRUE(create_gatt_connection_error_callback_.is_null());
EXPECT_TRUE(create_gatt_connection_success_callback_.is_null());
@@ -1439,7 +1441,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
// Call Connect(), which should set the connection latency.
connection->Connect();
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_LATENCY);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
ASSERT_FALSE(connection_latency_callback_.is_null());
ASSERT_FALSE(connection_latency_error_callback_.is_null());
@@ -1447,7 +1449,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1474,19 +1476,19 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
// Handle setting the connection latency.
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CONNECTION_LATENCY);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
ASSERT_FALSE(connection_latency_callback_.is_null());
ASSERT_FALSE(connection_latency_error_callback_.is_null());
connection_latency_callback_.Run();
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_GATT_CONNECTION);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1499,13 +1501,13 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
CreateConnection(true /* should_set_low_connection_latency */));
ConnectGatt(connection.get());
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_CHARACTERISTICS);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyGattServicesUnavailableEventSent();
VerifyBleWeaveConnectionResult(
@@ -1520,13 +1522,13 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
ConnectGatt(connection.get());
CharacteristicsFound(connection.get());
EXPECT_EQ(connection->sub_status(), SubStatus::WAITING_NOTIFY_SESSION);
- EXPECT_EQ(connection->status(), Connection::IN_PROGRESS);
+ EXPECT_EQ(connection->status(), Connection::Status::IN_PROGRESS);
// Simulate a timeout.
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1545,7 +1547,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
@@ -1569,7 +1571,7 @@ TEST_F(CryptAuthBluetoothLowEnergyWeaveClientConnectionTest,
test_timer_->Fire();
EXPECT_EQ(connection->sub_status(), SubStatus::DISCONNECTED);
- EXPECT_EQ(connection->status(), Connection::DISCONNECTED);
+ EXPECT_EQ(connection->status(), Connection::Status::DISCONNECTED);
VerifyBleWeaveConnectionResult(
BluetoothLowEnergyWeaveClientConnection::BleWeaveConnectionResult::
diff --git a/chromium/components/cryptauth/connection.cc b/chromium/components/cryptauth/connection.cc
index 59bed49ebb6..84158ffe58f 100644
--- a/chromium/components/cryptauth/connection.cc
+++ b/chromium/components/cryptauth/connection.cc
@@ -14,15 +14,15 @@
namespace cryptauth {
-Connection::Connection(const RemoteDevice& remote_device)
+Connection::Connection(RemoteDeviceRef remote_device)
: remote_device_(remote_device),
- status_(DISCONNECTED),
+ status_(Status::DISCONNECTED),
is_sending_message_(false) {}
Connection::~Connection() {}
bool Connection::IsConnected() const {
- return status_ == CONNECTED;
+ return status_ == Status::CONNECTED;
}
void Connection::SendMessage(std::unique_ptr<WireMessage> message) {
@@ -50,10 +50,6 @@ void Connection::RemoveObserver(ConnectionObserver* observer) {
observers_.RemoveObserver(observer);
}
-std::string Connection::GetDeviceAddress() {
- return remote_device_.bluetooth_address;
-}
-
void Connection::SetStatus(Status status) {
if (status_ == status)
return;
@@ -120,4 +116,21 @@ std::string Connection::GetDeviceInfoLogString() {
return ss.str();
}
+std::ostream& operator<<(std::ostream& stream,
+ const Connection::Status& status) {
+ switch (status) {
+ case Connection::Status::DISCONNECTED:
+ stream << "[disconnected]";
+ break;
+ case Connection::Status::IN_PROGRESS:
+ stream << "[in progress]";
+ break;
+ case Connection::Status::CONNECTED:
+ stream << "[connected]";
+ break;
+ }
+
+ return stream;
+}
+
} // namespace cryptauth
diff --git a/chromium/components/cryptauth/connection.h b/chromium/components/cryptauth/connection.h
index 8181b4a493f..84298049061 100644
--- a/chromium/components/cryptauth/connection.h
+++ b/chromium/components/cryptauth/connection.h
@@ -6,11 +6,12 @@
#define COMPONENTS_CRYPTAUTH_CONNECTION_H_
#include <memory>
+#include <ostream>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
namespace cryptauth {
@@ -21,14 +22,14 @@ class WireMessage;
// persistent bidirectional channel for sending and receiving wire messages.
class Connection {
public:
- enum Status {
+ enum class Status {
DISCONNECTED,
IN_PROGRESS,
CONNECTED,
};
// Constructs a connection to the given |remote_device|.
- explicit Connection(const RemoteDevice& remote_device);
+ explicit Connection(RemoteDeviceRef remote_device);
virtual ~Connection();
// Returns true iff the connection's status is CONNECTED.
@@ -45,9 +46,7 @@ class Connection {
virtual void AddObserver(ConnectionObserver* observer);
virtual void RemoveObserver(ConnectionObserver* observer);
- const RemoteDevice& remote_device() const {
- return remote_device_;
- }
+ RemoteDeviceRef remote_device() const { return remote_device_; }
// Abstract methods that subclasses should implement:
@@ -58,7 +57,7 @@ class Connection {
virtual void Disconnect() = 0;
// The bluetooth address of the connected device.
- virtual std::string GetDeviceAddress();
+ virtual std::string GetDeviceAddress() = 0;
Status status() const { return status_; }
@@ -99,7 +98,7 @@ class Connection {
private:
// The remote device corresponding to this connection.
- const RemoteDevice remote_device_;
+ const RemoteDeviceRef remote_device_;
// The current status of the connection.
Status status_;
@@ -117,6 +116,9 @@ class Connection {
DISALLOW_COPY_AND_ASSIGN(Connection);
};
+std::ostream& operator<<(std::ostream& stream,
+ const Connection::Status& status);
+
} // namespace cryptauth
#endif // COMPONENTS_CRYPTAUTH_CONNECTION_H_
diff --git a/chromium/components/cryptauth/connection_unittest.cc b/chromium/components/cryptauth/connection_unittest.cc
index d33146a6ac2..92ba0feb998 100644
--- a/chromium/components/cryptauth/connection_unittest.cc
+++ b/chromium/components/cryptauth/connection_unittest.cc
@@ -7,7 +7,8 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "components/cryptauth/connection_observer.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
+#include "components/cryptauth/remote_device_test_util.h"
#include "components/cryptauth/wire_message.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,12 +25,13 @@ namespace {
class MockConnection : public Connection {
public:
- MockConnection() : Connection(RemoteDevice()) {}
+ MockConnection() : Connection(cryptauth::CreateRemoteDeviceRefForTest()) {}
~MockConnection() {}
MOCK_METHOD1(SetPaused, void(bool paused));
MOCK_METHOD0(Connect, void());
MOCK_METHOD0(Disconnect, void());
+ MOCK_METHOD0(GetDeviceAddress, std::string());
MOCK_METHOD0(CancelConnectionAttempt, void());
MOCK_METHOD1(SendMessageImplProxy, void(WireMessage* message));
MOCK_METHOD1(DeserializeWireMessageProxy,
@@ -100,20 +102,21 @@ TEST(CryptAuthConnectionTest, IsConnected) {
StrictMock<MockConnection> connection;
EXPECT_FALSE(connection.IsConnected());
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
EXPECT_TRUE(connection.IsConnected());
- connection.SetStatus(Connection::DISCONNECTED);
+ connection.SetStatus(Connection::Status::DISCONNECTED);
EXPECT_FALSE(connection.IsConnected());
- connection.SetStatus(Connection::IN_PROGRESS);
+ connection.SetStatus(Connection::Status::IN_PROGRESS);
EXPECT_FALSE(connection.IsConnected());
}
TEST(CryptAuthConnectionTest, SendMessage_FailsWhenNotConnected) {
StrictMock<MockConnection> connection;
- connection.SetStatus(Connection::IN_PROGRESS);
+ connection.SetStatus(Connection::Status::IN_PROGRESS);
+ EXPECT_CALL(connection, GetDeviceAddress()).Times(1);
EXPECT_CALL(connection, SendMessageImplProxy(_)).Times(0);
connection.SendMessage(std::unique_ptr<WireMessage>());
}
@@ -121,7 +124,7 @@ TEST(CryptAuthConnectionTest, SendMessage_FailsWhenNotConnected) {
TEST(CryptAuthConnectionTest,
SendMessage_FailsWhenAnotherMessageSendIsInProgress) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
connection.SendMessage(std::unique_ptr<WireMessage>());
EXPECT_CALL(connection, SendMessageImplProxy(_)).Times(0);
@@ -130,7 +133,7 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest, SendMessage_SucceedsWhenConnected) {
StrictMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
EXPECT_CALL(connection, SendMessageImplProxy(_));
connection.SendMessage(std::unique_ptr<WireMessage>());
@@ -139,7 +142,7 @@ TEST(CryptAuthConnectionTest, SendMessage_SucceedsWhenConnected) {
TEST(CryptAuthConnectionTest,
SendMessage_SucceedsAfterPreviousMessageSendCompletes) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
connection.SendMessage(std::unique_ptr<WireMessage>());
connection.OnDidSendMessage(TestWireMessage(), true /* success */);
@@ -149,33 +152,33 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest, SetStatus_NotifiesObserversOfStatusChange) {
StrictMock<MockConnection> connection;
- EXPECT_EQ(Connection::DISCONNECTED, connection.status());
+ EXPECT_EQ(Connection::Status::DISCONNECTED, connection.status());
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
- EXPECT_CALL(observer,
- OnConnectionStatusChanged(&connection, Connection::DISCONNECTED,
- Connection::CONNECTED));
- connection.SetStatus(Connection::CONNECTED);
+ EXPECT_CALL(observer, OnConnectionStatusChanged(
+ &connection, Connection::Status::DISCONNECTED,
+ Connection::Status::CONNECTED));
+ connection.SetStatus(Connection::Status::CONNECTED);
}
TEST(CryptAuthConnectionTest,
SetStatus_DoesntNotifyObserversIfStatusUnchanged) {
StrictMock<MockConnection> connection;
- EXPECT_EQ(Connection::DISCONNECTED, connection.status());
+ EXPECT_EQ(Connection::Status::DISCONNECTED, connection.status());
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
EXPECT_CALL(observer, OnConnectionStatusChanged(_, _, _)).Times(0);
- connection.SetStatus(Connection::DISCONNECTED);
+ connection.SetStatus(Connection::Status::DISCONNECTED);
}
TEST(CryptAuthConnectionTest,
OnDidSendMessage_NotifiesObserversIfMessageSendInProgress) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
connection.SendMessage(std::unique_ptr<WireMessage>());
StrictMock<MockConnectionObserver> observer;
@@ -188,7 +191,7 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest,
OnDidSendMessage_DoesntNotifyObserversIfNoMessageSendInProgress) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
@@ -200,7 +203,7 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest,
OnBytesReceived_NotifiesObserversOnValidMessage) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
@@ -215,11 +218,12 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest,
OnBytesReceived_DoesntNotifyObserversIfNotConnected) {
StrictMock<MockConnection> connection;
- connection.SetStatus(Connection::IN_PROGRESS);
+ connection.SetStatus(Connection::Status::IN_PROGRESS);
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
+ EXPECT_CALL(connection, GetDeviceAddress()).Times(1);
EXPECT_CALL(observer, OnMessageReceived(_, _)).Times(0);
connection.OnBytesReceived(std::string());
}
@@ -227,7 +231,7 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest,
OnBytesReceived_DoesntNotifyObserversIfMessageIsIncomplete) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
@@ -241,7 +245,7 @@ TEST(CryptAuthConnectionTest,
TEST(CryptAuthConnectionTest,
OnBytesReceived_DoesntNotifyObserversIfMessageIsInvalid) {
NiceMock<MockConnection> connection;
- connection.SetStatus(Connection::CONNECTED);
+ connection.SetStatus(Connection::Status::CONNECTED);
StrictMock<MockConnectionObserver> observer;
connection.AddObserver(&observer);
diff --git a/chromium/components/cryptauth/cryptauth_device_manager_impl.cc b/chromium/components/cryptauth/cryptauth_device_manager_impl.cc
index e8afb982522..cc07d6fd88a 100644
--- a/chromium/components/cryptauth/cryptauth_device_manager_impl.cc
+++ b/chromium/components/cryptauth/cryptauth_device_manager_impl.cc
@@ -12,10 +12,12 @@
#include "base/base64url.h"
#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
#include "components/cryptauth/cryptauth_client.h"
#include "components/cryptauth/pref_names.h"
+#include "components/cryptauth/software_feature_state.h"
#include "components/cryptauth/sync_scheduler_impl.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
@@ -50,10 +52,15 @@ const char kExternalDeviceKeyDeviceType[] = "device_type";
const char kExternalDeviceKeyBeaconSeeds[] = "beacon_seeds";
const char kExternalDeviceKeyArcPlusPlus[] = "arc_plus_plus";
const char kExternalDeviceKeyPixelPhone[] = "pixel_phone";
+
+// Keys for ExternalDeviceInfo's BeaconSeed.
const char kExternalDeviceKeyBeaconSeedData[] = "beacon_seed_data";
const char kExternalDeviceKeyBeaconSeedStartMs[] = "beacon_seed_start_ms";
const char kExternalDeviceKeyBeaconSeedEndMs[] = "beacon_seed_end_ms";
+// Keys specific to the dictionary which stores ExternalDeviceInfo info.
+const char kDictionaryKeySoftwareFeatures[] = "software_features";
+
// Converts BeaconSeed protos to a list value that can be stored in user prefs.
std::unique_ptr<base::ListValue> BeaconSeedsToListValue(
const google::protobuf::RepeatedPtrField<BeaconSeed>& seeds) {
@@ -94,6 +101,48 @@ std::unique_ptr<base::ListValue> BeaconSeedsToListValue(
return list;
}
+void RecordDeviceSyncSoftwareFeaturesResult(bool success) {
+ UMA_HISTOGRAM_BOOLEAN("CryptAuth.DeviceSyncSoftwareFeaturesResult", success);
+}
+
+// Converts supported and enabled SoftwareFeature protos to a single dictionary
+// value that can be stored in user prefs.
+std::unique_ptr<base::DictionaryValue>
+SupportedAndEnabledSoftwareFeaturesToDictionaryValue(
+ const google::protobuf::RepeatedField<int>& supported_software_features,
+ const google::protobuf::RepeatedField<int>& enabled_software_features) {
+ std::unique_ptr<base::DictionaryValue> dictionary =
+ std::make_unique<base::DictionaryValue>();
+
+ for (const auto& supported_software_feature : supported_software_features) {
+ dictionary->SetInteger(std::to_string(supported_software_feature),
+ static_cast<int>(SoftwareFeatureState::kSupported));
+ }
+
+ for (const auto& enabled_software_feature : enabled_software_features) {
+ std::string software_feature_key = std::to_string(enabled_software_feature);
+
+ int software_feature_state;
+ if (!dictionary->GetInteger(software_feature_key,
+ &software_feature_state) ||
+ static_cast<SoftwareFeatureState>(software_feature_state) !=
+ SoftwareFeatureState::kSupported) {
+ PA_LOG(ERROR) << "A feature is marked as enabled but not as supported: "
+ << software_feature_key;
+ RecordDeviceSyncSoftwareFeaturesResult(false /* success */);
+
+ continue;
+ } else {
+ RecordDeviceSyncSoftwareFeaturesResult(true /* success */);
+ }
+
+ dictionary->SetInteger(software_feature_key,
+ static_cast<int>(SoftwareFeatureState::kEnabled));
+ }
+
+ return dictionary;
+}
+
// Converts an unlock key proto to a dictionary that can be stored in user
// prefs.
std::unique_ptr<base::DictionaryValue> UnlockKeyToDictionary(
@@ -153,6 +202,9 @@ std::unique_ptr<base::DictionaryValue> UnlockKeyToDictionary(
dictionary->SetInteger(kExternalDeviceKeyDeviceType, device.device_type());
}
+ dictionary->Set(kExternalDeviceKeyBeaconSeeds,
+ BeaconSeedsToListValue(device.beacon_seeds()));
+
if (device.has_arc_plus_plus()) {
dictionary->SetBoolean(kExternalDeviceKeyArcPlusPlus,
device.arc_plus_plus());
@@ -162,15 +214,16 @@ std::unique_ptr<base::DictionaryValue> UnlockKeyToDictionary(
dictionary->SetBoolean(kExternalDeviceKeyPixelPhone, device.pixel_phone());
}
- std::unique_ptr<base::ListValue> beacon_seed_list =
- BeaconSeedsToListValue(device.beacon_seeds());
- dictionary->Set(kExternalDeviceKeyBeaconSeeds, std::move(beacon_seed_list));
+ dictionary->Set(kDictionaryKeySoftwareFeatures,
+ SupportedAndEnabledSoftwareFeaturesToDictionaryValue(
+ device.supported_software_features(),
+ device.enabled_software_features()));
return dictionary;
}
void AddBeaconSeedsToExternalDevice(const base::ListValue& beacon_seeds,
- ExternalDeviceInfo& external_device) {
+ ExternalDeviceInfo* external_device) {
for (size_t i = 0; i < beacon_seeds.GetSize(); i++) {
const base::DictionaryValue* seed_dictionary = nullptr;
if (!beacon_seeds.GetDictionary(i, &seed_dictionary)) {
@@ -208,13 +261,38 @@ void AddBeaconSeedsToExternalDevice(const base::ListValue& beacon_seeds,
continue;
}
- BeaconSeed* seed = external_device.add_beacon_seeds();
+ BeaconSeed* seed = external_device->add_beacon_seeds();
seed->set_data(seed_data);
seed->set_start_time_millis(start_time_millis);
seed->set_end_time_millis(end_time_millis);
}
}
+void AddSoftwareFeaturesToExternalDevice(
+ const base::DictionaryValue& software_features_dictionary,
+ ExternalDeviceInfo* external_device) {
+ for (const auto& it : software_features_dictionary.DictItems()) {
+ int software_feature_state;
+ if (!it.second.GetAsInteger(&software_feature_state)) {
+ PA_LOG(WARNING) << "Unable to retrieve SoftwareFeature; skipping.";
+ continue;
+ }
+
+ SoftwareFeature software_feature =
+ static_cast<SoftwareFeature>(std::stoi(it.first));
+ switch (static_cast<SoftwareFeatureState>(software_feature_state)) {
+ case SoftwareFeatureState::kEnabled:
+ external_device->add_enabled_software_features(software_feature);
+ FALLTHROUGH;
+ case SoftwareFeatureState::kSupported:
+ external_device->add_supported_software_features(software_feature);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
// Converts an unlock key dictionary stored in user prefs to an
// ExternalDeviceInfo proto. Returns true if the dictionary is valid, and the
// parsed proto is written to |external_device|.
@@ -291,10 +369,9 @@ bool DictionaryToUnlockKey(const base::DictionaryValue& dictionary,
external_device->set_device_type(static_cast<DeviceType>(device_type));
}
- const base::ListValue* beacon_seeds = nullptr;
- dictionary.GetList(kExternalDeviceKeyBeaconSeeds, &beacon_seeds);
- if (beacon_seeds)
- AddBeaconSeedsToExternalDevice(*beacon_seeds, *external_device);
+ const base::ListValue* beacon_seeds;
+ if (dictionary.GetList(kExternalDeviceKeyBeaconSeeds, &beacon_seeds))
+ AddBeaconSeedsToExternalDevice(*beacon_seeds, external_device);
bool arc_plus_plus;
if (dictionary.GetBoolean(kExternalDeviceKeyArcPlusPlus, &arc_plus_plus))
@@ -304,6 +381,13 @@ bool DictionaryToUnlockKey(const base::DictionaryValue& dictionary,
if (dictionary.GetBoolean(kExternalDeviceKeyPixelPhone, &pixel_phone))
external_device->set_pixel_phone(pixel_phone);
+ const base::DictionaryValue* software_features_dictionary;
+ if (dictionary.GetDictionary(kDictionaryKeySoftwareFeatures,
+ &software_features_dictionary)) {
+ AddSoftwareFeaturesToExternalDevice(*software_features_dictionary,
+ external_device);
+ }
+
return true;
}
@@ -325,13 +409,13 @@ CryptAuthDeviceManagerImpl::Factory*
std::unique_ptr<CryptAuthDeviceManager>
CryptAuthDeviceManagerImpl::Factory::NewInstance(
base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* cryptauth_client_factory,
CryptAuthGCMManager* gcm_manager,
PrefService* pref_service) {
if (!factory_instance_)
factory_instance_ = new Factory();
- return factory_instance_->BuildInstance(clock, std::move(client_factory),
+ return factory_instance_->BuildInstance(clock, cryptauth_client_factory,
gcm_manager, pref_service);
}
@@ -346,20 +430,20 @@ CryptAuthDeviceManagerImpl::Factory::~Factory() = default;
std::unique_ptr<CryptAuthDeviceManager>
CryptAuthDeviceManagerImpl::Factory::BuildInstance(
base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* cryptauth_client_factory,
CryptAuthGCMManager* gcm_manager,
PrefService* pref_service) {
return base::WrapUnique(new CryptAuthDeviceManagerImpl(
- clock, std::move(client_factory), gcm_manager, pref_service));
+ clock, cryptauth_client_factory, gcm_manager, pref_service));
}
CryptAuthDeviceManagerImpl::CryptAuthDeviceManagerImpl(
base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* cryptauth_client_factory,
CryptAuthGCMManager* gcm_manager,
PrefService* pref_service)
: clock_(clock),
- client_factory_(std::move(client_factory)),
+ cryptauth_client_factory_(cryptauth_client_factory),
gcm_manager_(gcm_manager),
pref_service_(pref_service),
scheduler_(CreateSyncScheduler(this)),
@@ -554,7 +638,7 @@ void CryptAuthDeviceManagerImpl::OnSyncRequested(
NotifySyncStarted();
sync_request_ = std::move(sync_request);
- cryptauth_client_ = client_factory_->CreateInstance();
+ cryptauth_client_ = cryptauth_client_factory_->CreateInstance();
InvocationReason invocation_reason = INVOCATION_REASON_UNKNOWN;
diff --git a/chromium/components/cryptauth/cryptauth_device_manager_impl.h b/chromium/components/cryptauth/cryptauth_device_manager_impl.h
index 4d28d087ba6..128a81616a2 100644
--- a/chromium/components/cryptauth/cryptauth_device_manager_impl.h
+++ b/chromium/components/cryptauth/cryptauth_device_manager_impl.h
@@ -31,7 +31,7 @@ class CryptAuthDeviceManagerImpl : public CryptAuthDeviceManager,
public:
static std::unique_ptr<CryptAuthDeviceManager> NewInstance(
base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* cryptauth_client_factory,
CryptAuthGCMManager* gcm_manager,
PrefService* pref_service);
@@ -41,7 +41,7 @@ class CryptAuthDeviceManagerImpl : public CryptAuthDeviceManager,
virtual ~Factory();
virtual std::unique_ptr<CryptAuthDeviceManager> BuildInstance(
base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* cryptauth_client_factory,
CryptAuthGCMManager* gcm_manager,
PrefService* pref_service);
@@ -67,17 +67,17 @@ class CryptAuthDeviceManagerImpl : public CryptAuthDeviceManager,
protected:
// Creates the manager:
// |clock|: Used to determine the time between sync attempts.
- // |client_factory|: Creates CryptAuthClient instances to perform each sync.
- // |gcm_manager|: Notifies when GCM push messages trigger device syncs.
+ // |cryptauth_client_factory|: Creates CryptAuthClient instances to perform
+ // each sync. |gcm_manager|: Notifies when GCM push messages trigger device
+ // syncs.
// Not owned and must outlive this instance.
// |pref_service|: Stores syncing metadata and unlock key information to
// persist across browser restarts. Must already be registered
// with RegisterPrefs().
- CryptAuthDeviceManagerImpl(
- base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
- CryptAuthGCMManager* gcm_manager,
- PrefService* pref_service);
+ CryptAuthDeviceManagerImpl(base::Clock* clock,
+ CryptAuthClientFactory* cryptauth_client_factory,
+ CryptAuthGCMManager* gcm_manager,
+ PrefService* pref_service);
void SetSyncSchedulerForTest(std::unique_ptr<SyncScheduler> sync_scheduler);
@@ -100,7 +100,7 @@ class CryptAuthDeviceManagerImpl : public CryptAuthDeviceManager,
base::Clock* clock_;
// Creates CryptAuthClient instances for each sync attempt.
- std::unique_ptr<CryptAuthClientFactory> client_factory_;
+ CryptAuthClientFactory* cryptauth_client_factory_;
// Notifies when GCM push messages trigger device sync. Not owned and must
// outlive this instance.
diff --git a/chromium/components/cryptauth/cryptauth_device_manager_impl_unittest.cc b/chromium/components/cryptauth/cryptauth_device_manager_impl_unittest.cc
index 4a1ef752d8a..432a24ea84b 100644
--- a/chromium/components/cryptauth/cryptauth_device_manager_impl_unittest.cc
+++ b/chromium/components/cryptauth/cryptauth_device_manager_impl_unittest.cc
@@ -20,6 +20,7 @@
#include "components/cryptauth/mock_cryptauth_client.h"
#include "components/cryptauth/mock_sync_scheduler.h"
#include "components/cryptauth/pref_names.h"
+#include "components/cryptauth/software_feature_state.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/prefs/testing_pref_service.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
@@ -141,6 +142,27 @@ void ExpectSyncedDevicesAreEqual(
EXPECT_TRUE(seed.has_end_time_millis());
EXPECT_EQ(expected_seed.end_time_millis(), seed.end_time_millis());
}
+
+ EXPECT_EQ(expected_device.has_arc_plus_plus(), device.has_arc_plus_plus());
+ EXPECT_EQ(expected_device.arc_plus_plus(), device.arc_plus_plus());
+
+ EXPECT_EQ(expected_device.has_pixel_phone(), device.has_pixel_phone());
+ EXPECT_EQ(expected_device.pixel_phone(), device.pixel_phone());
+
+ ASSERT_EQ(expected_device.supported_software_features_size(),
+ device.supported_software_features_size());
+ for (int i = 0; i < expected_device.supported_software_features_size();
+ i++) {
+ EXPECT_EQ(expected_device.supported_software_features(i),
+ device.supported_software_features(i));
+ }
+
+ ASSERT_EQ(expected_device.enabled_software_features_size(),
+ device.enabled_software_features_size());
+ for (int i = 0; i < expected_device.enabled_software_features_size(); i++) {
+ EXPECT_EQ(expected_device.enabled_software_features(i),
+ device.enabled_software_features(i));
+ }
}
}
@@ -243,7 +265,7 @@ void ExpectSyncedDevicesAndPrefAreEqual(
const base::ListValue* beacon_seeds_from_prefs;
if (device_dictionary->GetList("beacon_seeds", &beacon_seeds_from_prefs)) {
- ASSERT_EQ((size_t)expected_device.beacon_seeds_size(),
+ ASSERT_EQ(static_cast<size_t>(expected_device.beacon_seeds_size()),
beacon_seeds_from_prefs->GetSize());
for (size_t i = 0; i < beacon_seeds_from_prefs->GetSize(); i++) {
const base::DictionaryValue* seed;
@@ -271,19 +293,79 @@ void ExpectSyncedDevicesAndPrefAreEqual(
} else {
EXPECT_FALSE(expected_device.beacon_seeds_size());
}
+
+ bool arc_plus_plus;
+ if (device_dictionary->GetBoolean("arc_plus_plus", &arc_plus_plus)) {
+ EXPECT_TRUE(expected_device.has_arc_plus_plus());
+ EXPECT_EQ(expected_device.arc_plus_plus(), arc_plus_plus);
+ } else {
+ EXPECT_FALSE(expected_device.has_arc_plus_plus());
+ }
+
+ bool pixel_phone;
+ if (device_dictionary->GetBoolean("pixel_phone", &pixel_phone)) {
+ EXPECT_TRUE(expected_device.has_pixel_phone());
+ EXPECT_EQ(expected_device.pixel_phone(), pixel_phone);
+ } else {
+ EXPECT_FALSE(expected_device.has_pixel_phone());
+ }
+
+ const base::DictionaryValue* software_features_from_prefs;
+ if (device_dictionary->GetDictionary("software_features",
+ &software_features_from_prefs)) {
+ std::vector<SoftwareFeature> supported_software_features;
+ std::vector<SoftwareFeature> enabled_software_features;
+
+ for (const auto& it : software_features_from_prefs->DictItems()) {
+ int software_feature_state;
+ ASSERT_TRUE(it.second.GetAsInteger(&software_feature_state));
+
+ SoftwareFeature software_feature =
+ static_cast<SoftwareFeature>(std::stoi(it.first));
+ switch (static_cast<SoftwareFeatureState>(software_feature_state)) {
+ case SoftwareFeatureState::kEnabled:
+ enabled_software_features.push_back(software_feature);
+ FALLTHROUGH;
+ case SoftwareFeatureState::kSupported:
+ supported_software_features.push_back(software_feature);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ASSERT_EQ(static_cast<size_t>(
+ expected_device.supported_software_features_size()),
+ supported_software_features.size());
+ ASSERT_EQ(
+ static_cast<size_t>(expected_device.enabled_software_features_size()),
+ enabled_software_features.size());
+ for (auto supported_software_feature :
+ expected_device.supported_software_features()) {
+ EXPECT_TRUE(base::ContainsValue(supported_software_features,
+ supported_software_feature));
+ }
+ for (auto enabled_software_feature :
+ expected_device.enabled_software_features()) {
+ EXPECT_TRUE(base::ContainsValue(enabled_software_features,
+ enabled_software_feature));
+ }
+ } else {
+ EXPECT_FALSE(expected_device.supported_software_features_size());
+ EXPECT_FALSE(expected_device.enabled_software_features_size());
+ }
}
}
// Harness for testing CryptAuthDeviceManager.
class TestCryptAuthDeviceManager : public CryptAuthDeviceManagerImpl {
public:
- TestCryptAuthDeviceManager(
- base::Clock* clock,
- std::unique_ptr<CryptAuthClientFactory> client_factory,
- CryptAuthGCMManager* gcm_manager,
- PrefService* pref_service)
+ TestCryptAuthDeviceManager(base::Clock* clock,
+ CryptAuthClientFactory* client_factory,
+ CryptAuthGCMManager* gcm_manager,
+ PrefService* pref_service)
: CryptAuthDeviceManagerImpl(clock,
- std::move(client_factory),
+ client_factory,
gcm_manager,
pref_service),
scoped_sync_scheduler_(new NiceMock<MockSyncScheduler>()),
@@ -319,7 +401,7 @@ class CryptAuthDeviceManagerImplTest
public MockCryptAuthClientFactory::Observer {
protected:
CryptAuthDeviceManagerImplTest()
- : client_factory_(new MockCryptAuthClientFactory(
+ : client_factory_(std::make_unique<MockCryptAuthClientFactory>(
MockCryptAuthClientFactory::MockType::MAKE_STRICT_MOCKS)),
gcm_manager_("existing gcm registration id") {
client_factory_->AddObserver(this);
@@ -341,6 +423,12 @@ class CryptAuthDeviceManagerImplTest
seed2->set_end_time_millis(kBeaconSeed2EndTime);
unlock_key.set_arc_plus_plus(kArcPlusPlus1);
unlock_key.set_pixel_phone(kPixelPhone1);
+ unlock_key.add_supported_software_features(
+ SoftwareFeature::BETTER_TOGETHER_HOST);
+ unlock_key.add_supported_software_features(
+ SoftwareFeature::BETTER_TOGETHER_CLIENT);
+ unlock_key.add_enabled_software_features(
+ SoftwareFeature::BETTER_TOGETHER_HOST);
devices_in_response_.push_back(unlock_key);
ExternalDeviceInfo unlockable_device;
@@ -359,6 +447,12 @@ class CryptAuthDeviceManagerImplTest
seed4->set_end_time_millis(kBeaconSeed4EndTime);
unlockable_device.set_arc_plus_plus(kArcPlusPlus2);
unlockable_device.set_pixel_phone(kPixelPhone2);
+ unlock_key.add_supported_software_features(
+ SoftwareFeature::MAGIC_TETHER_HOST);
+ unlock_key.add_supported_software_features(
+ SoftwareFeature::MAGIC_TETHER_CLIENT);
+ unlock_key.add_enabled_software_features(
+ SoftwareFeature::MAGIC_TETHER_HOST);
devices_in_response_.push_back(unlockable_device);
}
@@ -398,9 +492,11 @@ class CryptAuthDeviceManagerImplTest
device_dictionary->SetString("bluetooth_address", bluetooth_address_b64);
device_dictionary->SetBoolean("unlock_key", kStoredUnlockKey);
device_dictionary->SetBoolean("unlockable", kStoredUnlockable);
- device_dictionary->Set("beacon_seeds", std::make_unique<base::ListValue>());
device_dictionary->SetBoolean("mobile_hotspot_supported",
kStoredMobileHotspotSupported);
+ device_dictionary->Set("beacon_seeds", std::make_unique<base::ListValue>());
+ device_dictionary->Set("software_features",
+ std::make_unique<base::DictionaryValue>());
{
ListPrefUpdate update(&pref_service_,
prefs::kCryptAuthDeviceSyncUnlockKeys);
@@ -408,8 +504,7 @@ class CryptAuthDeviceManagerImplTest
}
device_manager_.reset(new TestCryptAuthDeviceManager(
- &clock_, base::WrapUnique(client_factory_), &gcm_manager_,
- &pref_service_));
+ &clock_, client_factory_.get(), &gcm_manager_, &pref_service_));
device_manager_->AddObserver(this);
get_my_devices_response_.add_devices()->CopyFrom(devices_in_response_[0]);
@@ -470,8 +565,7 @@ class CryptAuthDeviceManagerImplTest
base::SimpleTestClock clock_;
- // Owned by |device_manager_|.
- MockCryptAuthClientFactory* client_factory_;
+ std::unique_ptr<MockCryptAuthClientFactory> client_factory_;
TestingPrefServiceSimple pref_service_;
@@ -537,11 +631,8 @@ TEST_F(CryptAuthDeviceManagerImplTest, InitWithDefaultPrefs) {
TestingPrefServiceSimple pref_service;
CryptAuthDeviceManager::RegisterPrefs(pref_service.registry());
- TestCryptAuthDeviceManager device_manager(
- &clock,
- std::make_unique<MockCryptAuthClientFactory>(
- MockCryptAuthClientFactory::MockType::MAKE_STRICT_MOCKS),
- &gcm_manager_, &pref_service);
+ TestCryptAuthDeviceManager device_manager(&clock, client_factory_.get(),
+ &gcm_manager_, &pref_service);
EXPECT_CALL(
*(device_manager.GetSyncScheduler()),
@@ -803,8 +894,6 @@ TEST_F(CryptAuthDeviceManagerImplTest, SyncDeviceWithNoContents) {
}
TEST_F(CryptAuthDeviceManagerImplTest, SyncFullyDetailedExternalDeviceInfos) {
- GetMyDevicesResponse response;
-
// First, use a device with only a public key (a public key is the only
// required field). This ensures devices work properly when they do not have
// all fields filled out.
@@ -815,7 +904,6 @@ TEST_F(CryptAuthDeviceManagerImplTest, SyncFullyDetailedExternalDeviceInfos) {
// TODO(khorimoto): Remove this when support for storing all types of devices
// is added.
device_with_only_public_key.set_unlock_key(true);
- response.add_devices()->CopyFrom(device_with_only_public_key);
// Second, use a device with all fields filled out. This ensures that all
// device details are properly saved.
@@ -828,17 +916,29 @@ TEST_F(CryptAuthDeviceManagerImplTest, SyncFullyDetailedExternalDeviceInfos) {
device_with_all_fields.set_last_update_time_millis(123456789L);
device_with_all_fields.set_mobile_hotspot_supported(true);
device_with_all_fields.set_device_type(DeviceType::ANDROIDOS);
+
BeaconSeed seed1;
seed1.set_data(kBeaconSeed1Data);
seed1.set_start_time_millis(kBeaconSeed1StartTime);
seed1.set_end_time_millis(kBeaconSeed1EndTime);
device_with_all_fields.add_beacon_seeds()->CopyFrom(seed1);
+
BeaconSeed seed2;
seed2.set_data(kBeaconSeed2Data);
seed2.set_start_time_millis(kBeaconSeed2StartTime);
seed2.set_end_time_millis(kBeaconSeed2EndTime);
device_with_all_fields.add_beacon_seeds()->CopyFrom(seed2);
- response.add_devices()->CopyFrom(device_with_all_fields);
+
+ device_with_all_fields.set_arc_plus_plus(true);
+ device_with_all_fields.set_pixel_phone(true);
+
+ device_with_all_fields.add_supported_software_features(
+ SoftwareFeature::EASY_UNLOCK_HOST);
+ device_with_all_fields.add_supported_software_features(
+ SoftwareFeature::MAGIC_TETHER_HOST);
+
+ device_with_all_fields.add_enabled_software_features(
+ SoftwareFeature::MAGIC_TETHER_HOST);
std::vector<ExternalDeviceInfo> expected_devices;
expected_devices.push_back(device_with_only_public_key);
@@ -850,6 +950,10 @@ TEST_F(CryptAuthDeviceManagerImplTest, SyncFullyDetailedExternalDeviceInfos) {
EXPECT_CALL(*this, OnSyncFinishedProxy(
CryptAuthDeviceManager::SyncResult::SUCCESS,
CryptAuthDeviceManager::DeviceChangeResult::CHANGED));
+
+ GetMyDevicesResponse response;
+ response.add_devices()->CopyFrom(device_with_only_public_key);
+ response.add_devices()->CopyFrom(device_with_all_fields);
success_callback_.Run(response);
ExpectSyncedDevicesAndPrefAreEqual(
diff --git a/chromium/components/cryptauth/cryptauth_enroller_impl.cc b/chromium/components/cryptauth/cryptauth_enroller_impl.cc
index 4935e15d81d..be227cf384f 100644
--- a/chromium/components/cryptauth/cryptauth_enroller_impl.cc
+++ b/chromium/components/cryptauth/cryptauth_enroller_impl.cc
@@ -55,9 +55,9 @@ std::string CreateEnrollmentPublicMetadata() {
} // namespace
CryptAuthEnrollerImpl::CryptAuthEnrollerImpl(
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* client_factory,
std::unique_ptr<SecureMessageDelegate> secure_message_delegate)
- : client_factory_(std::move(client_factory)),
+ : client_factory_(client_factory),
secure_message_delegate_(std::move(secure_message_delegate)),
weak_ptr_factory_(this) {}
diff --git a/chromium/components/cryptauth/cryptauth_enroller_impl.h b/chromium/components/cryptauth/cryptauth_enroller_impl.h
index c4cca8ea0a9..cf90b1b53b5 100644
--- a/chromium/components/cryptauth/cryptauth_enroller_impl.h
+++ b/chromium/components/cryptauth/cryptauth_enroller_impl.h
@@ -32,7 +32,7 @@ class CryptAuthEnrollerImpl : public CryptAuthEnroller {
// |client_factory| creates CryptAuthClient instances for making API calls.
// |crypto_delegate| is responsible for SecureMessage operations.
CryptAuthEnrollerImpl(
- std::unique_ptr<CryptAuthClientFactory> client_factory,
+ CryptAuthClientFactory* client_factory,
std::unique_ptr<SecureMessageDelegate> secure_message_delegate);
~CryptAuthEnrollerImpl() override;
@@ -62,7 +62,7 @@ class CryptAuthEnrollerImpl : public CryptAuthEnroller {
void OnOuterSecureMessageCreated(const std::string& outer_message);
// Creates the CryptAuthClient instances to make API requests.
- std::unique_ptr<CryptAuthClientFactory> client_factory_;
+ CryptAuthClientFactory* client_factory_;
// Handles SecureMessage operations.
std::unique_ptr<SecureMessageDelegate> secure_message_delegate_;
diff --git a/chromium/components/cryptauth/cryptauth_enroller_impl_unittest.cc b/chromium/components/cryptauth/cryptauth_enroller_impl_unittest.cc
index 503b49381bc..dc2332c0afe 100644
--- a/chromium/components/cryptauth/cryptauth_enroller_impl_unittest.cc
+++ b/chromium/components/cryptauth/cryptauth_enroller_impl_unittest.cc
@@ -103,10 +103,10 @@ class CryptAuthEnrollerTest
public MockCryptAuthClientFactory::Observer {
public:
CryptAuthEnrollerTest()
- : client_factory_(new MockCryptAuthClientFactory(
+ : client_factory_(std::make_unique<MockCryptAuthClientFactory>(
MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS)),
secure_message_delegate_(new FakeSecureMessageDelegate()),
- enroller_(base::WrapUnique(client_factory_),
+ enroller_(client_factory_.get(),
base::WrapUnique(secure_message_delegate_)) {
client_factory_->AddObserver(this);
@@ -243,7 +243,7 @@ class CryptAuthEnrollerTest
std::string user_private_key_;
// Owned by |enroller_|.
- MockCryptAuthClientFactory* client_factory_;
+ std::unique_ptr<MockCryptAuthClientFactory> client_factory_;
// Owned by |enroller_|.
FakeSecureMessageDelegate* secure_message_delegate_;
// The CryptAuthEnroller under test.
diff --git a/chromium/components/cryptauth/cryptauth_test_util.cc b/chromium/components/cryptauth/cryptauth_test_util.cc
deleted file mode 100644
index 4d0be8586e9..00000000000
--- a/chromium/components/cryptauth/cryptauth_test_util.cc
+++ /dev/null
@@ -1,19 +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 "components/cryptauth/cryptauth_test_util.h"
-
-namespace cryptauth {
-
-// Attributes of the default test remote device.
-const char kTestRemoteDeviceUserId[] = "example@gmail.com";
-const char kTestRemoteDeviceName[] = "remote device";
-const char kTestRemoteDevicePublicKey[] = "public key";
-const char kTestRemoteDeviceBluetoothAddress[] = "AA:BB:CC:DD:EE:FF";
-const char kTestRemoteDevicePSK[] = "remote device psk";
-const bool kTestRemoteDeviceUnlockKey = true;
-const bool kTestRemoteDeviceSupportsMobileHotspot = true;
-const int64_t kTestRemoteDeviceLastUpdateTimeMillis = 0L;
-
-} // namespace cryptauth
diff --git a/chromium/components/cryptauth/cryptauth_test_util.h b/chromium/components/cryptauth/cryptauth_test_util.h
deleted file mode 100644
index 3ef00122a7f..00000000000
--- a/chromium/components/cryptauth/cryptauth_test_util.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRYPTAUTH_CRYPTAUTH_TEST_UTIL_H_
-#define COMPONENTS_CRYPTAUTH_CRYPTAUTH_TEST_UTIL_H_
-
-#include "components/cryptauth/remote_device.h"
-
-namespace cryptauth {
-
-// Attributes of the default test remote device.
-extern const char kTestRemoteDeviceUserId[];
-extern const char kTestRemoteDeviceName[];
-extern const char kTestRemoteDevicePublicKey[];
-extern const char kTestRemoteDeviceBluetoothAddress[];
-extern const char kTestRemoteDevicePSK[];
-extern const bool kTestRemoteDeviceUnlockKey;
-extern const bool kTestRemoteDeviceSupportsMobileHotspot;
-extern const int64_t kTestRemoteDeviceLastUpdateTimeMillis;
-
-// Returns a BLE RemoteDevice used for tests.
-inline RemoteDevice CreateLERemoteDeviceForTest() {
- return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
- kTestRemoteDevicePublicKey,
- kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
- kTestRemoteDeviceUnlockKey,
- kTestRemoteDeviceSupportsMobileHotspot,
- kTestRemoteDeviceLastUpdateTimeMillis);
-}
-
-// Returns a classic Bluetooth RemoteDevice used for tests.
-inline RemoteDevice CreateClassicRemoteDeviceForTest() {
- return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
- kTestRemoteDevicePublicKey,
- kTestRemoteDeviceBluetoothAddress, kTestRemoteDevicePSK,
- kTestRemoteDeviceUnlockKey,
- kTestRemoteDeviceSupportsMobileHotspot,
- kTestRemoteDeviceLastUpdateTimeMillis);
-}
-
-} // namespace cryptauth
-
-#endif // COMPONENTS_CRYPTAUTH_CRYPTAUTH_TEST_UTIL_H_
diff --git a/chromium/components/cryptauth/device_capability_manager.h b/chromium/components/cryptauth/device_capability_manager.h
deleted file mode 100644
index 1a5ea979399..00000000000
--- a/chromium/components/cryptauth/device_capability_manager.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_H_
-#define COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_H_
-
-#include "base/callback.h"
-#include "components/cryptauth/proto/cryptauth_api.pb.h"
-
-namespace cryptauth {
-
-// DeviceCapabilityManager sends requests to the back-end which enable/disable
-// device capabilities and finds devices which contain those capabilities. Here,
-// the term "capability" refers to the ability of a device to use a given
-// feature (e.g. EasyUnlock or Instant Tethering).
-class DeviceCapabilityManager {
- public:
- // CAPABILITY_UNLOCK_KEY refers to EasyUnlock.
- enum class Capability { CAPABILITY_UNLOCK_KEY };
-
- virtual ~DeviceCapabilityManager(){};
-
- virtual void SetCapabilityEnabled(
- const std::string& public_key,
- Capability capability,
- bool enabled,
- const base::Closure& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) = 0;
-
- virtual void FindEligibleDevicesForCapability(
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- success_callback,
- const base::Callback<void(const std::string&)>& error_callback) = 0;
-
- virtual void IsCapabilityPromotable(
- const std::string& public_key,
- Capability capability,
- const base::Callback<void(bool)>& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) = 0;
-};
-} // namespace cryptauth
-
-#endif // COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_H_
diff --git a/chromium/components/cryptauth/device_capability_manager_impl.cc b/chromium/components/cryptauth/device_capability_manager_impl.cc
deleted file mode 100644
index 5d427265b1e..00000000000
--- a/chromium/components/cryptauth/device_capability_manager_impl.cc
+++ /dev/null
@@ -1,245 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cryptauth/device_capability_manager_impl.h"
-
-#include <memory>
-
-#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "components/cryptauth/proto/cryptauth_api.pb.h"
-
-namespace cryptauth {
-
-// static
-DeviceCapabilityManagerImpl::Factory*
- DeviceCapabilityManagerImpl::Factory::factory_instance_ = nullptr;
-
-// static
-std::unique_ptr<DeviceCapabilityManager>
-DeviceCapabilityManagerImpl::Factory::NewInstance(
- CryptAuthClientFactory* cryptauth_client_factory) {
- if (!factory_instance_) {
- factory_instance_ = new Factory();
- }
- return factory_instance_->BuildInstance(cryptauth_client_factory);
-}
-
-void DeviceCapabilityManagerImpl::Factory::SetInstanceForTesting(
- Factory* factory) {
- factory_instance_ = factory;
-}
-
-std::unique_ptr<DeviceCapabilityManager>
-DeviceCapabilityManagerImpl::Factory::BuildInstance(
- CryptAuthClientFactory* cryptauth_client_factory) {
- return base::WrapUnique(
- new DeviceCapabilityManagerImpl(cryptauth_client_factory));
-}
-
-DeviceCapabilityManagerImpl::DeviceCapabilityManagerImpl(
- CryptAuthClientFactory* cryptauth_client_factory)
- : crypt_auth_client_factory_(cryptauth_client_factory),
- weak_ptr_factory_(this) {}
-
-DeviceCapabilityManagerImpl::~DeviceCapabilityManagerImpl() {}
-
-void DeviceCapabilityManagerImpl::SetCapabilityEnabled(
- const std::string& public_key,
- Capability capability,
- bool enabled,
- const base::Closure& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) {
- pending_requests_.emplace(std::make_unique<Request>(
- RequestType::SET_CAPABILITY_ENABLED, Capability::CAPABILITY_UNLOCK_KEY,
- public_key, enabled, success_callback, error_callback));
- ProcessRequestQueue();
-}
-
-void DeviceCapabilityManagerImpl::FindEligibleDevicesForCapability(
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- success_callback,
- const base::Callback<void(const std::string&)>& error_callback) {
- pending_requests_.emplace(std::make_unique<Request>(
- RequestType::FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY,
- Capability::CAPABILITY_UNLOCK_KEY, success_callback, error_callback));
- ProcessRequestQueue();
-}
-
-void DeviceCapabilityManagerImpl::IsCapabilityPromotable(
- const std::string& public_key,
- Capability capability,
- const base::Callback<void(bool)>& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) {
- pending_requests_.emplace(std::make_unique<Request>(
- RequestType::IS_CAPABILITY_PROMOTABLE, capability, public_key,
- success_callback, error_callback));
- ProcessRequestQueue();
-}
-
-DeviceCapabilityManagerImpl::Request::Request(
- RequestType request_type,
- Capability capability,
- std::string public_key,
- bool enabled,
- const base::Closure& set_capability_callback,
- const base::Callback<void(const std::string&)>& error_callback)
- : request_type(request_type),
- error_callback(error_callback),
- capability(capability),
- public_key(public_key),
- set_capability_callback(set_capability_callback),
- enabled(enabled) {}
-
-DeviceCapabilityManagerImpl::Request::Request(
- RequestType request_type,
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- find_eligible_devices_callback,
- const base::Callback<void(const std::string&)>& error_callback)
- : request_type(request_type),
- error_callback(error_callback),
- capability(capability),
- find_eligible_devices_callback(find_eligible_devices_callback) {}
-
-DeviceCapabilityManagerImpl::Request::Request(
- RequestType request_type,
- Capability capability,
- std::string public_key,
- const base::Callback<void(bool)> is_device_promotable_callback,
- const base::Callback<void(const std::string&)>& error_callback)
- : request_type(request_type),
- error_callback(error_callback),
- capability(capability),
- public_key(public_key),
- is_device_promotable_callback(is_device_promotable_callback) {}
-
-DeviceCapabilityManagerImpl::Request::~Request() {}
-
-void DeviceCapabilityManagerImpl::CreateNewCryptAuthClient() {
- DCHECK(!current_cryptauth_client_);
- current_cryptauth_client_ = crypt_auth_client_factory_->CreateInstance();
-}
-
-void DeviceCapabilityManagerImpl::ProcessSetCapabilityEnabledRequest() {
- DCHECK(current_request_->capability == Capability::CAPABILITY_UNLOCK_KEY);
- SetUnlockKeyCapability();
-}
-
-void DeviceCapabilityManagerImpl::ProcessFindEligibleDevicesForCapability() {
- DCHECK(current_request_->capability == Capability::CAPABILITY_UNLOCK_KEY);
- FindEligibleUnlockDevices();
-}
-
-void DeviceCapabilityManagerImpl::ProcessIsCapabilityPromotableRequest() {
- DCHECK(current_request_->capability == Capability::CAPABILITY_UNLOCK_KEY);
- IsDeviceUnlockPromotable();
-}
-
-void DeviceCapabilityManagerImpl::SetUnlockKeyCapability() {
- CreateNewCryptAuthClient();
-
- ToggleEasyUnlockRequest request;
- request.set_enable(current_request_->enabled);
- request.set_apply_to_all(true);
- request.set_public_key(current_request_->public_key);
-
- current_cryptauth_client_->ToggleEasyUnlock(
- request,
- base::Bind(&DeviceCapabilityManagerImpl::OnToggleEasyUnlockResponse,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&DeviceCapabilityManagerImpl::OnErrorResponse,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DeviceCapabilityManagerImpl::FindEligibleUnlockDevices() {
- CreateNewCryptAuthClient();
-
- current_cryptauth_client_->FindEligibleUnlockDevices(
- FindEligibleUnlockDevicesRequest(),
- base::Bind(
- &DeviceCapabilityManagerImpl::OnFindEligibleUnlockDevicesResponse,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&DeviceCapabilityManagerImpl::OnErrorResponse,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DeviceCapabilityManagerImpl::IsDeviceUnlockPromotable() {
- CreateNewCryptAuthClient();
-
- FindEligibleForPromotionRequest request;
- request.set_promoter_public_key(current_request_->public_key);
-
- current_cryptauth_client_->FindEligibleForPromotion(
- request,
- base::Bind(
- &DeviceCapabilityManagerImpl::OnIsDeviceUnlockPromotableResponse,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&DeviceCapabilityManagerImpl::OnErrorResponse,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void DeviceCapabilityManagerImpl::OnToggleEasyUnlockResponse(
- const ToggleEasyUnlockResponse& response) {
- current_cryptauth_client_.reset();
- current_request_->set_capability_callback.Run();
- current_request_.reset();
- ProcessRequestQueue();
-}
-
-void DeviceCapabilityManagerImpl::OnFindEligibleUnlockDevicesResponse(
- const FindEligibleUnlockDevicesResponse& response) {
- current_cryptauth_client_.reset();
- current_request_->find_eligible_devices_callback.Run(
- std::vector<ExternalDeviceInfo>(response.eligible_devices().begin(),
- response.eligible_devices().end()),
- std::vector<IneligibleDevice>(response.ineligible_devices().begin(),
- response.ineligible_devices().end()));
- current_request_.reset();
- ProcessRequestQueue();
-}
-
-void DeviceCapabilityManagerImpl::OnIsDeviceUnlockPromotableResponse(
- const FindEligibleForPromotionResponse& response) {
- current_cryptauth_client_.reset();
- current_request_->is_device_promotable_callback.Run(
- response.may_show_promo());
- current_request_.reset();
- ProcessRequestQueue();
-}
-
-void DeviceCapabilityManagerImpl::OnErrorResponse(const std::string& response) {
- current_cryptauth_client_.reset();
- current_request_->error_callback.Run(response);
- current_request_.reset();
- ProcessRequestQueue();
-}
-
-void DeviceCapabilityManagerImpl::ProcessRequestQueue() {
- if (current_request_ || pending_requests_.empty())
- return;
-
- current_request_ = std::move(pending_requests_.front());
- pending_requests_.pop();
-
- switch (current_request_->request_type) {
- case RequestType::SET_CAPABILITY_ENABLED:
- ProcessSetCapabilityEnabledRequest();
- return;
- case RequestType::FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY:
- ProcessFindEligibleDevicesForCapability();
- return;
- case RequestType::IS_CAPABILITY_PROMOTABLE:
- ProcessIsCapabilityPromotableRequest();
- return;
- default:
- NOTREACHED();
- return;
- }
-}
-
-} // namespace cryptauth
diff --git a/chromium/components/cryptauth/device_capability_manager_impl.h b/chromium/components/cryptauth/device_capability_manager_impl.h
deleted file mode 100644
index 2535d256d5e..00000000000
--- a/chromium/components/cryptauth/device_capability_manager_impl.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_IMPL_H_
-#define COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_IMPL_H_
-
-#include "base/bind.h"
-#include "base/callback_forward.h"
-#include "base/containers/queue.h"
-#include "base/memory/weak_ptr.h"
-#include "components/cryptauth/cryptauth_client.h"
-#include "components/cryptauth/device_capability_manager.h"
-#include "components/cryptauth/proto/cryptauth_api.pb.h"
-
-namespace cryptauth {
-
-using Capability = DeviceCapabilityManager::Capability;
-
-// Concrete DeviceCapabilityManager implementation.
-class DeviceCapabilityManagerImpl : public DeviceCapabilityManager {
- public:
- class Factory {
- public:
- static std::unique_ptr<DeviceCapabilityManager> NewInstance(
- CryptAuthClientFactory* cryptauth_client_factory);
-
- static void SetInstanceForTesting(Factory* factory);
-
- protected:
- virtual std::unique_ptr<DeviceCapabilityManager> BuildInstance(
- CryptAuthClientFactory* cryptauth_client_factory);
-
- private:
- static Factory* factory_instance_;
- };
-
- DeviceCapabilityManagerImpl(CryptAuthClientFactory* cryptauth_client_factory);
-
- ~DeviceCapabilityManagerImpl() override;
-
- // Enables or disables |capability| for the device corresponding to
- // |public_key|. In error cases, |error_callback| is invoked with an error
- // string.
- void SetCapabilityEnabled(
- const std::string& public_key,
- Capability capability,
- bool enabled,
- const base::Closure& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) override;
-
- // Fetches metadata about the device which are eligible for |capability|. In
- // error cases, |error_callback| is invoked with an error string.
- void FindEligibleDevicesForCapability(
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- success_callback,
- const base::Callback<void(const std::string&)>& error_callback) override;
-
- // Determines whether a device with |public_key| is promotable for
- // |capability|. In error cases, |error_callback| is invoked with an error
- // string.
- void IsCapabilityPromotable(
- const std::string& public_key,
- Capability capability,
- const base::Callback<void(bool)>& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) override;
-
- private:
- enum class RequestType {
- SET_CAPABILITY_ENABLED,
- FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY,
- IS_CAPABILITY_PROMOTABLE
- };
-
- struct Request {
- // Used for SET_CAPABILITY_ENABLED Requests.
- Request(RequestType request_type,
- Capability capability,
- std::string public_key,
- bool enabled,
- const base::Closure& set_capability_callback,
- const base::Callback<void(const std::string&)>& error_callback);
-
- // Used for FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY Requests.
- Request(RequestType request_type,
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- find_eligible_devices_callback,
- const base::Callback<void(const std::string&)>& error_callback);
-
- // Used for IS_CAPABILITY_PROMOTABLE Requests.
- Request(RequestType request_type,
- Capability capability,
- std::string public_key,
- const base::Callback<void(bool)> is_device_promotable_callback,
- const base::Callback<void(const std::string&)>& error_callback);
-
- ~Request();
-
- // Defined for every request.
- RequestType request_type;
- base::Callback<void(const std::string&)> error_callback;
- Capability capability;
-
- // Defined for SET_CAPABILITY_ENABLED and IS_CAPABILITY_PROMOTABLE;
- // otherwise, unused.
- std::string public_key;
-
- // Defined if |request_type_| is SET_CAPABILITY_ENABLED; otherwise, unused.
- base::Closure set_capability_callback;
- bool enabled;
-
- // Defined if |request_type_| is FIND_ELIGIBLE_DEVICES_FOR_CAPABILITY;
- // otherwise, unused.
- base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>
- find_eligible_devices_callback;
-
- // Defined if |request_type_| is IS_CAPABILITY_PROMOTABLE; otherwise,
- // unused.
- base::Callback<void(bool)> is_device_promotable_callback;
- };
-
- void CreateNewCryptAuthClient();
-
- void ProcessSetCapabilityEnabledRequest();
- void ProcessFindEligibleDevicesForCapability();
- void ProcessIsCapabilityPromotableRequest();
-
- void SetUnlockKeyCapability();
- void FindEligibleUnlockDevices();
- void IsDeviceUnlockPromotable();
-
- void OnToggleEasyUnlockResponse(const ToggleEasyUnlockResponse& response);
- void OnFindEligibleUnlockDevicesResponse(
- const FindEligibleUnlockDevicesResponse& response);
- void OnIsDeviceUnlockPromotableResponse(
- const FindEligibleForPromotionResponse& response);
- void OnErrorResponse(const std::string& response);
- void ProcessRequestQueue();
-
- std::unique_ptr<CryptAuthClient> current_cryptauth_client_;
- std::unique_ptr<Request> current_request_;
- base::queue<std::unique_ptr<Request>> pending_requests_;
- CryptAuthClientFactory* crypt_auth_client_factory_;
- base::WeakPtrFactory<DeviceCapabilityManagerImpl> weak_ptr_factory_;
-};
-} // namespace cryptauth
-
-#endif // COMPONENTS_CRYPTAUTH_DEVICE_CAPABILITY_MANAGER_IMPL_H_
diff --git a/chromium/components/cryptauth/device_capability_manager_impl_unittest.cc b/chromium/components/cryptauth/device_capability_manager_impl_unittest.cc
deleted file mode 100644
index 5868c6de7b5..00000000000
--- a/chromium/components/cryptauth/device_capability_manager_impl_unittest.cc
+++ /dev/null
@@ -1,424 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cryptauth/device_capability_manager_impl.h"
-
-#include <stddef.h>
-
-#include <chrono>
-#include <memory>
-#include <thread>
-#include <unordered_set>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "base/macros.h"
-#include "components/cryptauth/mock_cryptauth_client.h"
-#include "components/cryptauth/remote_device.h"
-#include "components/cryptauth/remote_device_test_util.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using testing::_;
-using testing::Invoke;
-
-namespace cryptauth {
-
-namespace {
-
-const char kSuccessResult[] = "success";
-const char kErrorOnToggleEasyUnlockResult[] = "toggleEasyUnlockError";
-const char kErrorFindEligibleUnlockDevices[] = "findEligibleUnlockDeviceError";
-const char kErrorFindEligibleForPromotion[] = "findEligibleForPromotionError";
-const std::string kTestErrorCodeTogglingIneligibleDevice =
- "togglingIneligibleDevice.";
-
-std::vector<cryptauth::ExternalDeviceInfo>
-CreateExternalDeviceInfosForRemoteDevices(
- const std::vector<cryptauth::RemoteDevice> remote_devices) {
- std::vector<cryptauth::ExternalDeviceInfo> device_infos;
- for (const auto& remote_device : remote_devices) {
- // Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
- cryptauth::ExternalDeviceInfo info;
- info.set_public_key(remote_device.public_key);
- device_infos.push_back(info);
- }
- return device_infos;
-}
-
-} // namespace
-
-class DeviceCapabilityManagerImplTest
- : public testing::Test,
- public MockCryptAuthClientFactory::Observer {
- public:
- DeviceCapabilityManagerImplTest()
- : all_test_external_device_infos_(
- CreateExternalDeviceInfosForRemoteDevices(
- cryptauth::GenerateTestRemoteDevices(5))),
- test_eligible_external_devices_infos_(
- {all_test_external_device_infos_[0],
- all_test_external_device_infos_[1],
- all_test_external_device_infos_[2]}),
- test_ineligible_external_devices_infos_(
- {all_test_external_device_infos_[3],
- all_test_external_device_infos_[4]}) {}
-
- void SetUp() override {
- mock_cryptauth_client_factory_ =
- std::make_unique<MockCryptAuthClientFactory>(
- MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS);
- mock_cryptauth_client_factory_->AddObserver(this);
- device_capability_manager_ = std::make_unique<DeviceCapabilityManagerImpl>(
- mock_cryptauth_client_factory_.get());
- }
-
- void OnCryptAuthClientCreated(MockCryptAuthClient* client) override {
- ON_CALL(*client, ToggleEasyUnlock(_, _, _))
- .WillByDefault(Invoke(
- this, &DeviceCapabilityManagerImplTest::MockToggleEasyUnlock));
- ON_CALL(*client, FindEligibleUnlockDevices(_, _, _))
- .WillByDefault(Invoke(
- this,
- &DeviceCapabilityManagerImplTest::MockFindEligibleUnlockDevices));
- ON_CALL(*client, FindEligibleForPromotion(_, _, _))
- .WillByDefault(Invoke(
- this,
- &DeviceCapabilityManagerImplTest::MockFindEligibleForPromotion));
- }
-
- // Mock CryptAuthClient::ToggleEasyUnlock() implementation.
- void MockToggleEasyUnlock(
- const ToggleEasyUnlockRequest& request,
- const CryptAuthClient::ToggleEasyUnlockCallback& callback,
- const CryptAuthClient::ErrorCallback& error_callback) {
- toggle_easy_unlock_callback_ = callback;
- error_callback_ = error_callback;
- error_code_ = kErrorOnToggleEasyUnlockResult;
- }
-
- // Mock CryptAuthClient::FindEligibleUnlockDevices() implementation.
- void MockFindEligibleUnlockDevices(
- const FindEligibleUnlockDevicesRequest& request,
- const CryptAuthClient::FindEligibleUnlockDevicesCallback& callback,
- const CryptAuthClient::ErrorCallback& error_callback) {
- find_eligible_unlock_devices_callback_ = callback;
- error_callback_ = error_callback;
- error_code_ = kErrorFindEligibleUnlockDevices;
- }
-
- // Mock CryptAuthClient::FindEligibleForPromotion() implementation.
- void MockFindEligibleForPromotion(
- const FindEligibleForPromotionRequest& request,
- const CryptAuthClient::FindEligibleForPromotionCallback& callback,
- const CryptAuthClient::ErrorCallback& error_callback) {
- find_eligible_for_promotion_callback_ = callback;
- error_callback_ = error_callback;
- error_code_ = kErrorFindEligibleForPromotion;
- }
-
- FindEligibleUnlockDevicesResponse CreateFindEligibleUnlockDevicesResponse() {
- FindEligibleUnlockDevicesResponse find_eligible_unlock_devices_response;
- for (const auto& device_info : test_eligible_external_devices_infos_) {
- find_eligible_unlock_devices_response.add_eligible_devices()->CopyFrom(
- device_info);
- }
- for (const auto& device_info : test_ineligible_external_devices_infos_) {
- find_eligible_unlock_devices_response.add_ineligible_devices()
- ->mutable_device()
- ->CopyFrom(device_info);
- }
- return find_eligible_unlock_devices_response;
- }
-
- void VerifyDeviceEligibility() {
- // Ensure that resulting devices are not empty. Otherwise, following for
- // loop checks will succeed on empty resulting devices.
- EXPECT_TRUE(result_eligible_devices_.size() > 0);
- EXPECT_TRUE(result_ineligible_devices_.size() > 0);
- for (const auto& device_info : result_eligible_devices_) {
- EXPECT_TRUE(
- std::find_if(
- test_eligible_external_devices_infos_.begin(),
- test_eligible_external_devices_infos_.end(),
- [&device_info](const cryptauth::ExternalDeviceInfo& device) {
- return device.public_key() == device_info.public_key();
- }) != test_eligible_external_devices_infos_.end());
- }
- for (const auto& ineligible_device : result_ineligible_devices_) {
- EXPECT_TRUE(
- std::find_if(test_ineligible_external_devices_infos_.begin(),
- test_ineligible_external_devices_infos_.end(),
- [&ineligible_device](
- const cryptauth::ExternalDeviceInfo& device) {
- return device.public_key() ==
- ineligible_device.device().public_key();
- }) != test_ineligible_external_devices_infos_.end());
- }
- result_eligible_devices_.clear();
- result_ineligible_devices_.clear();
- }
-
- void SetCapabilityEnabled(DeviceCapabilityManagerImpl::Capability capability,
- const ExternalDeviceInfo& device_info,
- bool enable) {
- device_capability_manager_->SetCapabilityEnabled(
- device_info.public_key(), capability, enable,
- base::Bind(&DeviceCapabilityManagerImplTest::
- TestSuccessSetCapabilityKeyUnlockCallback,
- base::Unretained(this)),
- base::Bind(&DeviceCapabilityManagerImplTest::TestErrorCallback,
- base::Unretained(this)));
- }
-
- void FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability capability) {
- device_capability_manager_->FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- base::Bind(&DeviceCapabilityManagerImplTest::
- TestSuccessFindEligibleUnlockDevicesCallback,
- base::Unretained(this)),
- base::Bind(&DeviceCapabilityManagerImplTest::TestErrorCallback,
- base::Unretained(this)));
- }
-
- void IsPromotableDevice(DeviceCapabilityManagerImpl::Capability capability,
- const std::string& public_key) {
- device_capability_manager_->IsCapabilityPromotable(
- public_key, capability,
- base::Bind(&DeviceCapabilityManagerImplTest::
- TestSuccessFindEligibleForPromotionDeviceCallback,
- base::Unretained(this)),
- base::Bind(&DeviceCapabilityManagerImplTest::TestErrorCallback,
- base::Unretained(this)));
- }
-
- void TestSuccessSetCapabilityKeyUnlockCallback() { result_ = kSuccessResult; }
-
- void TestSuccessFindEligibleUnlockDevicesCallback(
- const std::vector<ExternalDeviceInfo>& eligible_devices,
- const std::vector<IneligibleDevice>& ineligible_devices) {
- result_ = kSuccessResult;
- result_eligible_devices_ = eligible_devices;
- result_ineligible_devices_ = ineligible_devices;
- }
-
- void TestSuccessFindEligibleForPromotionDeviceCallback(bool eligible) {
- result_ = kSuccessResult;
- result_eligible_for_promotion_ = eligible;
- }
-
- void TestErrorCallback(const std::string& error_message) {
- result_ = error_message;
- }
-
- void InvokeSetCapabilityKeyUnlockCallback() {
- CryptAuthClient::ToggleEasyUnlockCallback success_callback =
- toggle_easy_unlock_callback_;
- ASSERT_TRUE(!success_callback.is_null());
- toggle_easy_unlock_callback_.Reset();
- success_callback.Run(ToggleEasyUnlockResponse());
- }
-
- void InvokeFindEligibleUnlockDevicesCallback(
- const FindEligibleUnlockDevicesResponse& retrieved_devices_response) {
- CryptAuthClient::FindEligibleUnlockDevicesCallback success_callback =
- find_eligible_unlock_devices_callback_;
- ASSERT_TRUE(!success_callback.is_null());
- find_eligible_unlock_devices_callback_.Reset();
- success_callback.Run(retrieved_devices_response);
- }
-
- void InvokeFindEligibleForPromotionCallback(bool eligible_for_promotion) {
- FindEligibleForPromotionResponse response;
- response.set_may_show_promo(eligible_for_promotion);
- CryptAuthClient::FindEligibleForPromotionCallback success_callback =
- find_eligible_for_promotion_callback_;
- ASSERT_TRUE(!success_callback.is_null());
- find_eligible_for_promotion_callback_.Reset();
- success_callback.Run(response);
- }
-
- void InvokeErrorCallback() {
- CryptAuthClient::ErrorCallback error_callback = error_callback_;
- ASSERT_TRUE(!error_callback.is_null());
- error_callback_.Reset();
- error_callback.Run(error_code_);
- }
-
- std::string GetResultAndReset() {
- std::string result;
- result.swap(result_);
- return result;
- }
-
- bool GetEligibleForPromotionAndReset() {
- bool result_eligible_for_promotion = result_eligible_for_promotion_;
- result_eligible_for_promotion_ = false;
- return result_eligible_for_promotion;
- }
-
- const std::vector<cryptauth::ExternalDeviceInfo>
- all_test_external_device_infos_;
- const std::vector<ExternalDeviceInfo> test_eligible_external_devices_infos_;
- const std::vector<ExternalDeviceInfo> test_ineligible_external_devices_infos_;
-
- std::unique_ptr<MockCryptAuthClientFactory> mock_cryptauth_client_factory_;
- std::unique_ptr<cryptauth::DeviceCapabilityManagerImpl>
- device_capability_manager_;
- CryptAuthClient::ToggleEasyUnlockCallback toggle_easy_unlock_callback_;
- CryptAuthClient::FindEligibleUnlockDevicesCallback
- find_eligible_unlock_devices_callback_;
- CryptAuthClient::FindEligibleForPromotionCallback
- find_eligible_for_promotion_callback_;
- CryptAuthClient::ErrorCallback error_callback_;
-
- // Used by all tests that involve CryptauthClient network calls internally.
- // Network call statuses are mocked out in place by |result_| and
- // |error_code_| to keep track of the order in which DevicaCapabilityManager
- // functions are called.
- std::string result_;
- std::string error_code_;
- // For FindEligibleUnlockDevice tests.
- std::vector<ExternalDeviceInfo> result_eligible_devices_;
- std::vector<IneligibleDevice> result_ineligible_devices_;
- // For FindEligibleForPromotion tests.
- bool result_eligible_for_promotion_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DeviceCapabilityManagerImplTest);
-};
-
-TEST_F(DeviceCapabilityManagerImplTest, TestOrderUponMultipleRequests) {
- SetCapabilityEnabled(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[0], true /* enable */);
- FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY);
- IsPromotableDevice(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[0].public_key());
- SetCapabilityEnabled(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[1], true /* enable */);
- FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY);
- IsPromotableDevice(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[1].public_key());
-
- InvokeSetCapabilityKeyUnlockCallback();
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
-
- InvokeFindEligibleUnlockDevicesCallback(
- CreateFindEligibleUnlockDevicesResponse());
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- VerifyDeviceEligibility();
-
- InvokeFindEligibleForPromotionCallback(true /* eligible */);
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- EXPECT_TRUE(GetEligibleForPromotionAndReset());
-
- InvokeSetCapabilityKeyUnlockCallback();
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
-
- InvokeFindEligibleUnlockDevicesCallback(
- CreateFindEligibleUnlockDevicesResponse());
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- VerifyDeviceEligibility();
-
- InvokeFindEligibleForPromotionCallback(true /* eligible */);
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- EXPECT_TRUE(GetEligibleForPromotionAndReset());
-}
-
-TEST_F(DeviceCapabilityManagerImplTest, TestMultipleSetUnlocksRequests) {
- SetCapabilityEnabled(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[0], true /* enable */);
- SetCapabilityEnabled(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[1], true /* enable */);
- SetCapabilityEnabled(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[2], true /* enable */);
-
- InvokeErrorCallback();
- EXPECT_EQ(kErrorOnToggleEasyUnlockResult, GetResultAndReset());
-
- InvokeSetCapabilityKeyUnlockCallback();
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
-
- InvokeSetCapabilityKeyUnlockCallback();
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
-}
-
-TEST_F(DeviceCapabilityManagerImplTest,
- TestMultipleFindEligibleForUnlockDevicesRequests) {
- FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY);
- FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY);
- FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY);
-
- InvokeFindEligibleUnlockDevicesCallback(
- CreateFindEligibleUnlockDevicesResponse());
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- VerifyDeviceEligibility();
-
- InvokeErrorCallback();
- EXPECT_EQ(kErrorFindEligibleUnlockDevices, GetResultAndReset());
-
- InvokeFindEligibleUnlockDevicesCallback(
- CreateFindEligibleUnlockDevicesResponse());
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- VerifyDeviceEligibility();
-}
-
-TEST_F(DeviceCapabilityManagerImplTest, TestMultipleIsPromotableRequests) {
- IsPromotableDevice(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[0].public_key());
- IsPromotableDevice(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[1].public_key());
- IsPromotableDevice(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[2].public_key());
-
- InvokeFindEligibleForPromotionCallback(true /*eligible*/);
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- EXPECT_TRUE(GetEligibleForPromotionAndReset());
-
- InvokeFindEligibleForPromotionCallback(true /*eligible*/);
- EXPECT_EQ(kSuccessResult, GetResultAndReset());
- EXPECT_TRUE(GetEligibleForPromotionAndReset());
-
- InvokeErrorCallback();
- EXPECT_EQ(kErrorFindEligibleForPromotion, GetResultAndReset());
-}
-
-TEST_F(DeviceCapabilityManagerImplTest, TestOrderViaMultipleErrors) {
- SetCapabilityEnabled(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[0], true /* enable */);
- FindEligibleDevicesForCapability(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY);
- IsPromotableDevice(
- DeviceCapabilityManagerImpl::Capability::CAPABILITY_UNLOCK_KEY,
- test_eligible_external_devices_infos_[0].public_key());
-
- InvokeErrorCallback();
- EXPECT_EQ(kErrorOnToggleEasyUnlockResult, GetResultAndReset());
-
- InvokeErrorCallback();
- EXPECT_EQ(kErrorFindEligibleUnlockDevices, GetResultAndReset());
-
- InvokeErrorCallback();
- EXPECT_EQ(kErrorFindEligibleForPromotion, GetResultAndReset());
-}
-
-} // namespace cryptauth
diff --git a/chromium/components/cryptauth/device_to_device_authenticator.cc b/chromium/components/cryptauth/device_to_device_authenticator.cc
index dc0053a54c2..e723cf183cb 100644
--- a/chromium/components/cryptauth/device_to_device_authenticator.cc
+++ b/chromium/components/cryptauth/device_to_device_authenticator.cc
@@ -116,7 +116,7 @@ void DeviceToDeviceAuthenticator::OnKeyPairGenerated(
// Create the [Initiator Hello] message to send to the remote device.
state_ = State::SENDING_HELLO;
helper_->CreateHelloMessage(
- public_key, connection_->remote_device().persistent_symmetric_key,
+ public_key, connection_->remote_device().persistent_symmetric_key(),
secure_message_delegate_.get(),
base::Bind(&DeviceToDeviceAuthenticator::OnHelloMessageCreated,
weak_ptr_factory_.GetWeakPtr()));
@@ -170,7 +170,7 @@ void DeviceToDeviceAuthenticator::OnResponderAuthValidated(
// Create the [Initiator Auth] message to send to the remote device.
helper_->CreateInitiatorAuthMessage(
- session_keys_, connection_->remote_device().persistent_symmetric_key,
+ session_keys_, connection_->remote_device().persistent_symmetric_key(),
responder_auth_message_, secure_message_delegate_.get(),
base::Bind(&DeviceToDeviceAuthenticator::OnInitiatorAuthCreated,
weak_ptr_factory_.GetWeakPtr()));
@@ -224,7 +224,7 @@ void DeviceToDeviceAuthenticator::OnConnectionStatusChanged(
Connection::Status old_status,
Connection::Status new_status) {
// We do not expect the connection to drop during authentication.
- if (new_status == Connection::DISCONNECTED) {
+ if (new_status == Connection::Status::DISCONNECTED) {
Fail("Disconnected while authentication is in progress",
Result::DISCONNECTED);
}
@@ -243,10 +243,10 @@ void DeviceToDeviceAuthenticator::OnMessageReceived(
// Attempt to validate the [Responder Auth] message received from the remote
// device.
- std::string responder_public_key = connection.remote_device().public_key;
+ std::string responder_public_key = connection.remote_device().public_key();
helper_->ValidateResponderAuthMessage(
responder_auth_message_, responder_public_key,
- connection_->remote_device().persistent_symmetric_key,
+ connection_->remote_device().persistent_symmetric_key(),
local_session_private_key_, hello_message_,
secure_message_delegate_.get(),
base::Bind(&DeviceToDeviceAuthenticator::OnResponderAuthValidated,
diff --git a/chromium/components/cryptauth/device_to_device_authenticator_unittest.cc b/chromium/components/cryptauth/device_to_device_authenticator_unittest.cc
index eecec3a0226..2f1d06762e9 100644
--- a/chromium/components/cryptauth/device_to_device_authenticator_unittest.cc
+++ b/chromium/components/cryptauth/device_to_device_authenticator_unittest.cc
@@ -16,9 +16,9 @@
#include "base/timer/mock_timer.h"
#include "components/cryptauth/authenticator.h"
#include "components/cryptauth/connection.h"
-#include "components/cryptauth/cryptauth_test_util.h"
#include "components/cryptauth/device_to_device_responder_operations.h"
#include "components/cryptauth/fake_secure_message_delegate.h"
+#include "components/cryptauth/remote_device_test_util.h"
#include "components/cryptauth/secure_context.h"
#include "components/cryptauth/session_keys.h"
#include "components/cryptauth/wire_message.h"
@@ -66,7 +66,7 @@ void SaveValidateHelloMessageResult(bool* validated_out,
// Connection implementation for testing.
class FakeConnection : public Connection {
public:
- FakeConnection(const RemoteDevice& remote_device)
+ FakeConnection(RemoteDeviceRef remote_device)
: Connection(remote_device), connection_blocked_(false) {}
~FakeConnection() override {}
@@ -77,6 +77,7 @@ class FakeConnection : public Connection {
void Disconnect() override {
SetStatus(Connection::Status::DISCONNECTED);
}
+ std::string GetDeviceAddress() override { return std::string(); }
using Connection::OnBytesReceived;
@@ -147,7 +148,7 @@ class DeviceToDeviceAuthenticatorForTest : public DeviceToDeviceAuthenticator {
class CryptAuthDeviceToDeviceAuthenticatorTest : public testing::Test {
public:
CryptAuthDeviceToDeviceAuthenticatorTest()
- : remote_device_(CreateClassicRemoteDeviceForTest()),
+ : remote_device_(CreateRemoteDeviceRefForTest()),
connection_(remote_device_),
secure_message_delegate_(new FakeSecureMessageDelegate),
authenticator_(&connection_,
@@ -190,7 +191,7 @@ class CryptAuthDeviceToDeviceAuthenticatorTest : public testing::Test {
bool validated = false;
std::string local_session_public_key;
DeviceToDeviceResponderOperations::ValidateHelloMessage(
- hello_message, remote_device_.persistent_symmetric_key,
+ hello_message, remote_device_.persistent_symmetric_key(),
secure_message_delegate_,
base::Bind(&SaveValidateHelloMessageResult, &validated,
&local_session_public_key));
@@ -210,7 +211,7 @@ class CryptAuthDeviceToDeviceAuthenticatorTest : public testing::Test {
std::string responder_auth_message;
DeviceToDeviceResponderOperations::CreateResponderAuthMessage(
hello_message, remote_session_public_key_, remote_session_private_key_,
- remote_device_private_key, remote_device_.persistent_symmetric_key,
+ remote_device_private_key, remote_device_.persistent_symmetric_key(),
secure_message_delegate_,
base::Bind(&SaveStringResult, &responder_auth_message));
EXPECT_FALSE(responder_auth_message.empty());
@@ -231,7 +232,7 @@ class CryptAuthDeviceToDeviceAuthenticatorTest : public testing::Test {
MOCK_METHOD1(OnAuthenticationResultProxy, void(Authenticator::Result result));
// Contains information about the remote device.
- const RemoteDevice remote_device_;
+ const RemoteDeviceRef remote_device_;
// Simulates the connection to the remote device.
FakeConnection connection_;
@@ -272,7 +273,7 @@ TEST_F(CryptAuthDeviceToDeviceAuthenticatorTest, AuthenticateSucceeds) {
bool initiator_auth_validated = false;
DeviceToDeviceResponderOperations::ValidateInitiatorAuthMessage(
initiator_auth, SessionKeys(session_symmetric_key_),
- remote_device_.persistent_symmetric_key, responder_auth_message,
+ remote_device_.persistent_symmetric_key(), responder_auth_message,
secure_message_delegate_,
base::Bind(&SaveBooleanResult, &initiator_auth_validated));
ASSERT_TRUE(initiator_auth_validated);
diff --git a/chromium/components/cryptauth/fake_connection.cc b/chromium/components/cryptauth/fake_connection.cc
index e126787861f..d68d600c93b 100644
--- a/chromium/components/cryptauth/fake_connection.cc
+++ b/chromium/components/cryptauth/fake_connection.cc
@@ -11,11 +11,11 @@
namespace cryptauth {
-FakeConnection::FakeConnection(const RemoteDevice& remote_device)
+FakeConnection::FakeConnection(RemoteDeviceRef remote_device)
: FakeConnection(remote_device, /* should_auto_connect */ true) {}
-FakeConnection::FakeConnection(
- const RemoteDevice& remote_device, bool should_auto_connect)
+FakeConnection::FakeConnection(RemoteDeviceRef remote_device,
+ bool should_auto_connect)
: Connection(remote_device), should_auto_connect_(should_auto_connect) {
if (should_auto_connect_) {
Connect();
@@ -28,14 +28,18 @@ FakeConnection::~FakeConnection() {
void FakeConnection::Connect() {
if (should_auto_connect_) {
- SetStatus(CONNECTED);
+ SetStatus(Status::CONNECTED);
} else {
- SetStatus(IN_PROGRESS);
+ SetStatus(Status::IN_PROGRESS);
}
}
void FakeConnection::Disconnect() {
- SetStatus(DISCONNECTED);
+ SetStatus(Status::DISCONNECTED);
+}
+
+std::string FakeConnection::GetDeviceAddress() {
+ return std::string();
}
void FakeConnection::AddObserver(ConnectionObserver* observer) {
@@ -52,12 +56,12 @@ void FakeConnection::RemoveObserver(ConnectionObserver* observer) {
void FakeConnection::CompleteInProgressConnection(bool success) {
DCHECK(!should_auto_connect_);
- DCHECK(status() == IN_PROGRESS);
+ DCHECK(status() == Status::IN_PROGRESS);
if (success) {
- SetStatus(CONNECTED);
+ SetStatus(Status::CONNECTED);
} else {
- SetStatus(DISCONNECTED);
+ SetStatus(Status::DISCONNECTED);
}
}
diff --git a/chromium/components/cryptauth/fake_connection.h b/chromium/components/cryptauth/fake_connection.h
index 9f8f613f2a2..981599dff59 100644
--- a/chromium/components/cryptauth/fake_connection.h
+++ b/chromium/components/cryptauth/fake_connection.h
@@ -15,13 +15,14 @@ class ConnectionObserver;
// A fake implementation of Connection to use in tests.
class FakeConnection : public Connection {
public:
- FakeConnection(const RemoteDevice& remote_device);
- FakeConnection(const RemoteDevice& remote_device, bool should_auto_connect);
+ FakeConnection(RemoteDeviceRef remote_device);
+ FakeConnection(RemoteDeviceRef remote_device, bool should_auto_connect);
~FakeConnection() override;
// Connection:
void Connect() override;
void Disconnect() override;
+ std::string GetDeviceAddress() override;
void AddObserver(ConnectionObserver* observer) override;
void RemoveObserver(ConnectionObserver* observer) override;
diff --git a/chromium/components/cryptauth/fake_cryptauth_device_manager.cc b/chromium/components/cryptauth/fake_cryptauth_device_manager.cc
index 0e7b815eb2c..a622c506259 100644
--- a/chromium/components/cryptauth/fake_cryptauth_device_manager.cc
+++ b/chromium/components/cryptauth/fake_cryptauth_device_manager.cc
@@ -15,7 +15,7 @@ FakeCryptAuthDeviceManager::~FakeCryptAuthDeviceManager() = default;
void FakeCryptAuthDeviceManager::FinishActiveSync(
SyncResult sync_result,
DeviceChangeResult device_change_result,
- const base::Time& sync_finish_time) {
+ base::Time sync_finish_time) {
DCHECK(is_sync_in_progress_);
is_sync_in_progress_ = false;
diff --git a/chromium/components/cryptauth/fake_cryptauth_device_manager.h b/chromium/components/cryptauth/fake_cryptauth_device_manager.h
index 582883b931c..459990e5ba0 100644
--- a/chromium/components/cryptauth/fake_cryptauth_device_manager.h
+++ b/chromium/components/cryptauth/fake_cryptauth_device_manager.h
@@ -21,6 +21,10 @@ class FakeCryptAuthDeviceManager : public CryptAuthDeviceManager {
bool has_started() { return has_started_; }
+ void set_last_sync_time(base::Time last_sync_time) {
+ last_sync_time_ = last_sync_time;
+ }
+
void set_time_to_next_attempt(base::TimeDelta time_to_next_attempt) {
time_to_next_attempt_ = time_to_next_attempt;
}
@@ -33,7 +37,7 @@ class FakeCryptAuthDeviceManager : public CryptAuthDeviceManager {
std::vector<ExternalDeviceInfo>& unlock_keys() { return unlock_keys_; }
- void set_unlock_keys(std::vector<ExternalDeviceInfo> unlock_keys) {
+ void set_unlock_keys(const std::vector<ExternalDeviceInfo>& unlock_keys) {
unlock_keys_ = unlock_keys;
}
@@ -42,13 +46,13 @@ class FakeCryptAuthDeviceManager : public CryptAuthDeviceManager {
}
void set_pixel_unlock_keys(
- std::vector<ExternalDeviceInfo> pixel_unlock_keys) {
+ const std::vector<ExternalDeviceInfo>& pixel_unlock_keys) {
pixel_unlock_keys_ = pixel_unlock_keys;
}
std::vector<ExternalDeviceInfo>& tether_hosts() { return tether_hosts_; }
- void set_tether_hosts(std::vector<ExternalDeviceInfo> tether_hosts) {
+ void set_tether_hosts(const std::vector<ExternalDeviceInfo>& tether_hosts) {
tether_hosts_ = tether_hosts;
}
@@ -57,17 +61,25 @@ class FakeCryptAuthDeviceManager : public CryptAuthDeviceManager {
}
void set_pixel_tether_hosts(
- std::vector<ExternalDeviceInfo> pixel_tether_hosts) {
+ const std::vector<ExternalDeviceInfo>& pixel_tether_hosts) {
pixel_tether_hosts_ = pixel_tether_hosts;
}
+ void set_is_recovering_from_failure(bool is_recovering_from_failure) {
+ is_recovering_from_failure_ = is_recovering_from_failure;
+ }
+
+ void set_is_sync_in_progress(bool is_sync_in_progress) {
+ is_sync_in_progress_ = is_sync_in_progress;
+ }
+
// Finishes the active sync; should only be called if a sync is in progress
// due to a previous call to ForceSyncNow(). If |sync_result| is SUCCESS,
// |sync_finish_time| will be stored as the last sync time and will be
// returned by future calls to GetLastSyncTime().
void FinishActiveSync(SyncResult sync_result,
DeviceChangeResult device_change_result,
- const base::Time& sync_finish_time = base::Time());
+ base::Time sync_finish_time = base::Time());
// Make these functions public for testing.
using CryptAuthDeviceManager::NotifySyncStarted;
diff --git a/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.cc b/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.cc
index ebfde03f422..413e9fea4eb 100644
--- a/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.cc
+++ b/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.cc
@@ -16,7 +16,7 @@ void FakeCryptAuthEnrollmentManager::Start() {
void FakeCryptAuthEnrollmentManager::FinishActiveEnrollment(
bool success,
- const base::Time& enrollment_finish_time) {
+ base::Time enrollment_finish_time) {
DCHECK(is_enrollment_in_progress_);
is_enrollment_in_progress_ = false;
diff --git a/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.h b/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.h
index 1ffc0482b1f..fe3ac911d8e 100644
--- a/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.h
+++ b/chromium/components/cryptauth/fake_cryptauth_enrollment_manager.h
@@ -21,7 +21,11 @@ class FakeCryptAuthEnrollmentManager : public CryptAuthEnrollmentManager {
FakeCryptAuthEnrollmentManager();
~FakeCryptAuthEnrollmentManager() override;
- void set_time_to_next_attempt(const base::TimeDelta& time_to_next_attempt) {
+ void set_last_enrollment_time(base::Time last_enrollment_time) {
+ last_enrollment_time_ = last_enrollment_time;
+ }
+
+ void set_time_to_next_attempt(base::TimeDelta time_to_next_attempt) {
time_to_next_attempt_ = time_to_next_attempt;
}
@@ -39,6 +43,14 @@ class FakeCryptAuthEnrollmentManager : public CryptAuthEnrollmentManager {
bool has_started() { return has_started_; }
+ void set_is_recovering_from_failure(bool is_recovering_from_failure) {
+ is_recovering_from_failure_ = is_recovering_from_failure;
+ }
+
+ void set_is_enrollment_in_progress(bool is_enrollment_in_progress) {
+ is_enrollment_in_progress_ = is_enrollment_in_progress;
+ }
+
base::Optional<InvocationReason> last_invocation_reason() {
return last_invocation_reason_;
}
@@ -47,9 +59,8 @@ class FakeCryptAuthEnrollmentManager : public CryptAuthEnrollmentManager {
// progress due to a previous call to ForceEnrollmentNow(). If |success| is
// true, |enrollment_finish_time| will be stored as the last enrollment time
// and will be returned by future calls to GetLastEnrollmentTime().
- void FinishActiveEnrollment(
- bool success,
- const base::Time& enrollment_finish_time = base::Time());
+ void FinishActiveEnrollment(bool success,
+ base::Time enrollment_finish_time = base::Time());
// Make these functions public for testing.
using CryptAuthEnrollmentManager::NotifyEnrollmentStarted;
diff --git a/chromium/components/cryptauth/fake_device_capability_manager.cc b/chromium/components/cryptauth/fake_device_capability_manager.cc
deleted file mode 100644
index c8d7692faac..00000000000
--- a/chromium/components/cryptauth/fake_device_capability_manager.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/cryptauth/fake_device_capability_manager.h"
-
-namespace cryptauth {
-
-FakeDeviceCapabilityManager::FakeDeviceCapabilityManager() {}
-
-FakeDeviceCapabilityManager::~FakeDeviceCapabilityManager() {}
-
-void FakeDeviceCapabilityManager::SetCapabilityEnabled(
- const std::string& public_key,
- Capability capability,
- bool enabled,
- const base::Closure& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) {
- if (set_capability_enabled_error_code_.empty()) {
- success_callback.Run();
- return;
- }
- error_callback.Run(std::move(set_capability_enabled_error_code_));
-}
-
-void FakeDeviceCapabilityManager::FindEligibleDevicesForCapability(
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- success_callback,
- const base::Callback<void(const std::string&)>& error_callback) {
- if (find_eligible_devices_for_capability_error_code_.empty()) {
- success_callback.Run(external_device_infos_, ineligible_devices_);
- return;
- }
- error_callback.Run(find_eligible_devices_for_capability_error_code_);
-}
-
-void FakeDeviceCapabilityManager::IsCapabilityPromotable(
- const std::string& public_key,
- Capability capability,
- const base::Callback<void(bool)>& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) {
- if (is_capability_promotable_error_code_.empty()) {
- success_callback.Run(true /* capability is promotable */);
- return;
- }
- error_callback.Run(is_capability_promotable_error_code_);
-}
-
-} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/fake_device_capability_manager.h b/chromium/components/cryptauth/fake_device_capability_manager.h
deleted file mode 100644
index b0d35e42e09..00000000000
--- a/chromium/components/cryptauth/fake_device_capability_manager.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_CRYPTAUTH_FAKE_DEVICE_CAPABILITY_MANAGER_H_
-#define COMPONENTS_CRYPTAUTH_FAKE_DEVICE_CAPABILITY_MANAGER_H_
-
-#include "base/callback.h"
-#include "components/cryptauth/device_capability_manager.h"
-#include "components/cryptauth/proto/cryptauth_api.pb.h"
-
-namespace cryptauth {
-
-using Capability = DeviceCapabilityManager::Capability;
-
-// Test double for Device Capability Manager.
-class FakeDeviceCapabilityManager : public cryptauth::DeviceCapabilityManager {
- public:
- FakeDeviceCapabilityManager();
-
- ~FakeDeviceCapabilityManager() override;
-
- void set_find_eligible_devices_for_capability_error_code(
- std::string error_code) {
- find_eligible_devices_for_capability_error_code_ = error_code;
- }
-
- void set_capability_enabled_error_code(std::string error_code) {
- set_capability_enabled_error_code_ = error_code;
- LOG(ERROR) << set_capability_enabled_error_code_;
- }
-
- void set_is_capability_promotable_error_code(std::string error_code) {
- is_capability_promotable_error_code_ = error_code;
- }
-
- void set_external_device_info(
- std::vector<ExternalDeviceInfo> external_device_infos) {
- external_device_infos_ = external_device_infos;
- }
-
- void set_ineligible_devices(
- std::vector<IneligibleDevice> ineligible_devices) {
- ineligible_devices_ = ineligible_devices;
- }
-
- // cryptauth::DeviceCapabilityManager:
- void SetCapabilityEnabled(
- const std::string& public_key,
- Capability capability,
- bool enabled,
- const base::Closure& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) override;
-
- void FindEligibleDevicesForCapability(
- Capability capability,
- const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
- const std::vector<IneligibleDevice>&)>&
- success_callback,
- const base::Callback<void(const std::string&)>& error_callback) override;
-
- void IsCapabilityPromotable(
- const std::string& public_key,
- Capability capability,
- const base::Callback<void(bool)>& success_callback,
- const base::Callback<void(const std::string&)>& error_callback) override;
-
- std::string set_capability_enabled_error_code_;
- std::string find_eligible_devices_for_capability_error_code_;
- std::string is_capability_promotable_error_code_;
- std::vector<ExternalDeviceInfo> external_device_infos_;
- std::vector<IneligibleDevice> ineligible_devices_;
-};
-} // namespace cryptauth
-
-#endif // COMPONENTS_CRYPTAUTH_FAKE_DEVICE_CAPABILITY_MANAGER_H_
diff --git a/chromium/components/cryptauth/fake_software_feature_manager.cc b/chromium/components/cryptauth/fake_software_feature_manager.cc
new file mode 100644
index 00000000000..a7625dc179d
--- /dev/null
+++ b/chromium/components/cryptauth/fake_software_feature_manager.cc
@@ -0,0 +1,74 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cryptauth/fake_software_feature_manager.h"
+
+namespace cryptauth {
+
+FakeSoftwareFeatureManager::SetSoftwareFeatureStateArgs::
+ SetSoftwareFeatureStateArgs(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive)
+ : public_key(public_key),
+ software_feature(software_feature),
+ enabled(enabled),
+ success_callback(success_callback),
+ error_callback(error_callback),
+ is_exclusive(is_exclusive) {}
+
+FakeSoftwareFeatureManager::SetSoftwareFeatureStateArgs::
+ ~SetSoftwareFeatureStateArgs() = default;
+
+FakeSoftwareFeatureManager::FindEligibleDevicesArgs::FindEligibleDevicesArgs(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback)
+ : software_feature(software_feature),
+ success_callback(success_callback),
+ error_callback(error_callback) {}
+
+FakeSoftwareFeatureManager::FindEligibleDevicesArgs::
+ ~FindEligibleDevicesArgs() = default;
+
+FakeSoftwareFeatureManager::FakeSoftwareFeatureManager() = default;
+
+FakeSoftwareFeatureManager::~FakeSoftwareFeatureManager() = default;
+
+void FakeSoftwareFeatureManager::SetSoftwareFeatureState(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive) {
+ set_software_feature_state_calls_.emplace_back(
+ std::make_unique<SetSoftwareFeatureStateArgs>(
+ public_key, software_feature, enabled, success_callback,
+ error_callback, is_exclusive));
+
+ if (delegate_)
+ delegate_->OnSetSoftwareFeatureStateCalled();
+}
+
+void FakeSoftwareFeatureManager::FindEligibleDevices(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) {
+ find_eligible_multidevice_host_calls_.emplace_back(
+ std::make_unique<FindEligibleDevicesArgs>(
+ software_feature, success_callback, error_callback));
+
+ if (delegate_)
+ delegate_->OnFindEligibleDevicesCalled();
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/fake_software_feature_manager.h b/chromium/components/cryptauth/fake_software_feature_manager.h
new file mode 100644
index 00000000000..e5a670a6e70
--- /dev/null
+++ b/chromium/components/cryptauth/fake_software_feature_manager.h
@@ -0,0 +1,110 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRYPTAUTH_FAKE_SOFTWARE_FEATURE_MANAGER_H_
+#define COMPONENTS_CRYPTAUTH_FAKE_SOFTWARE_FEATURE_MANAGER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/software_feature_manager.h"
+
+namespace cryptauth {
+
+// Test implementation of SoftwareFeatureManager.
+class FakeSoftwareFeatureManager : public SoftwareFeatureManager {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() = default;
+ virtual void OnSetSoftwareFeatureStateCalled() {}
+ virtual void OnFindEligibleDevicesCalled() {}
+ };
+
+ struct SetSoftwareFeatureStateArgs {
+ SetSoftwareFeatureStateArgs(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive);
+ ~SetSoftwareFeatureStateArgs();
+
+ std::string public_key;
+ SoftwareFeature software_feature;
+ bool enabled;
+ base::Closure success_callback;
+ base::Callback<void(const std::string&)> error_callback;
+ bool is_exclusive;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SetSoftwareFeatureStateArgs);
+ };
+
+ struct FindEligibleDevicesArgs {
+ FindEligibleDevicesArgs(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback);
+ ~FindEligibleDevicesArgs();
+
+ SoftwareFeature software_feature;
+ base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>
+ success_callback;
+ base::Callback<void(const std::string&)> error_callback;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FindEligibleDevicesArgs);
+ };
+
+ FakeSoftwareFeatureManager();
+ ~FakeSoftwareFeatureManager() override;
+
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+ const std::vector<std::unique_ptr<SetSoftwareFeatureStateArgs>>&
+ set_software_feature_state_calls() {
+ return set_software_feature_state_calls_;
+ }
+
+ const std::vector<std::unique_ptr<FindEligibleDevicesArgs>>&
+ find_eligible_multidevice_host_calls() {
+ return find_eligible_multidevice_host_calls_;
+ }
+
+ // SoftwareFeatureManager:
+ void SetSoftwareFeatureState(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive = false) override;
+ void FindEligibleDevices(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) override;
+
+ private:
+ Delegate* delegate_ = nullptr;
+
+ std::vector<std::unique_ptr<SetSoftwareFeatureStateArgs>>
+ set_software_feature_state_calls_;
+ std::vector<std::unique_ptr<FindEligibleDevicesArgs>>
+ find_eligible_multidevice_host_calls_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeSoftwareFeatureManager);
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_FAKE_SOFTWARE_FEATURE_MANAGER_H_
diff --git a/chromium/components/cryptauth/foreground_eid_generator.cc b/chromium/components/cryptauth/foreground_eid_generator.cc
index 581121f4a97..04ae3e65321 100644
--- a/chromium/components/cryptauth/foreground_eid_generator.cc
+++ b/chromium/components/cryptauth/foreground_eid_generator.cc
@@ -15,7 +15,7 @@
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/raw_eid_generator.h"
#include "components/cryptauth/raw_eid_generator_impl.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
namespace cryptauth {
@@ -125,8 +125,9 @@ std::string ForegroundEidGenerator::IdentifyRemoteDeviceByAdvertisement(
for (const auto& device_id : device_ids) {
std::vector<std::string> possible_advertisements =
- GeneratePossibleAdvertisements(RemoteDevice::DerivePublicKey(device_id),
- scanning_device_beacon_seeds);
+ GeneratePossibleAdvertisements(
+ RemoteDeviceRef::DerivePublicKey(device_id),
+ scanning_device_beacon_seeds);
for (const auto& possible_advertisement : possible_advertisements) {
if (service_data_without_flags == possible_advertisement) {
return device_id;
diff --git a/chromium/components/cryptauth/foreground_eid_generator_unittest.cc b/chromium/components/cryptauth/foreground_eid_generator_unittest.cc
index 37f460e9fff..f70a8058d79 100644
--- a/chromium/components/cryptauth/foreground_eid_generator_unittest.cc
+++ b/chromium/components/cryptauth/foreground_eid_generator_unittest.cc
@@ -12,7 +12,7 @@
#include "base/time/time.h"
#include "components/cryptauth/proto/cryptauth_api.pb.h"
#include "components/cryptauth/raw_eid_generator_impl.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -542,7 +542,7 @@ TEST_F(CryptAuthForegroundEidGeneratorTest,
kDefaultAdvertisingDevicePublicKey);
std::string device_id =
- RemoteDevice::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
+ RemoteDeviceRef::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
std::vector<std::string> device_id_list = {device_id};
std::string identified_device_id =
eid_generator_->IdentifyRemoteDeviceByAdvertisement(
@@ -564,7 +564,7 @@ TEST_F(CryptAuthForegroundEidGeneratorTest,
1, static_cast<char>(ForegroundEidGenerator::kBluetooth4Flag));
std::string device_id =
- RemoteDevice::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
+ RemoteDeviceRef::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
std::vector<std::string> device_id_list = {device_id};
std::string identified_device_id =
eid_generator_->IdentifyRemoteDeviceByAdvertisement(
@@ -585,7 +585,7 @@ TEST_F(CryptAuthForegroundEidGeneratorTest,
service_data.append("extra_flag_bytes");
std::string device_id =
- RemoteDevice::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
+ RemoteDeviceRef::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
std::vector<std::string> device_id_list = {device_id};
std::string identified_device_id =
eid_generator_->IdentifyRemoteDeviceByAdvertisement(
@@ -617,7 +617,7 @@ TEST_F(CryptAuthForegroundEidGeneratorTest,
kDefaultAdvertisingDevicePublicKey);
std::string device_id =
- RemoteDevice::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
+ RemoteDeviceRef::GenerateDeviceId(kDefaultAdvertisingDevicePublicKey);
std::vector<std::string> device_id_list = {device_id, "wrongDeviceId"};
std::string identified_device_id =
eid_generator_->IdentifyRemoteDeviceByAdvertisement(
diff --git a/chromium/components/cryptauth/proto/cryptauth_api.proto b/chromium/components/cryptauth/proto/cryptauth_api.proto
index 5aebfb37557..12930196475 100644
--- a/chromium/components/cryptauth/proto/cryptauth_api.proto
+++ b/chromium/components/cryptauth/proto/cryptauth_api.proto
@@ -333,9 +333,9 @@ message GcmDeviceInfo {
// A list of multi-device software features supported by the device.
repeated SoftwareFeature supported_software_features = 411;
- // A list of multi-device software features currently enabled (active) on the
- // device.
- repeated SoftwareFeature enabled_software_features = 412;
+ // Previously, field 412 referred to "enabled_software_features". However,
+ // this is not an intrinsic property of a device type, so this field has been
+ // removed.
// The enrollment session id this is sent with
optional bytes enrollment_session_id = 1000;
diff --git a/chromium/components/cryptauth/remote_beacon_seed_fetcher.cc b/chromium/components/cryptauth/remote_beacon_seed_fetcher.cc
index 709a4959206..16c743ad00a 100644
--- a/chromium/components/cryptauth/remote_beacon_seed_fetcher.cc
+++ b/chromium/components/cryptauth/remote_beacon_seed_fetcher.cc
@@ -5,7 +5,7 @@
#include "components/cryptauth/remote_beacon_seed_fetcher.h"
#include "components/cryptauth/cryptauth_device_manager.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
namespace cryptauth {
@@ -19,7 +19,8 @@ bool RemoteBeaconSeedFetcher::FetchSeedsForDeviceId(
const std::string& device_id,
std::vector<BeaconSeed>* beacon_seeds_out) const {
for(const auto& device_info : device_manager_->GetSyncedDevices()) {
- if (RemoteDevice::GenerateDeviceId(device_info.public_key()) == device_id) {
+ if (RemoteDeviceRef::GenerateDeviceId(device_info.public_key()) ==
+ device_id) {
if (device_info.beacon_seeds_size() == 0) {
return false;
}
diff --git a/chromium/components/cryptauth/remote_beacon_seed_fetcher_unittest.cc b/chromium/components/cryptauth/remote_beacon_seed_fetcher_unittest.cc
index 7e4aab88023..92d81fea528 100644
--- a/chromium/components/cryptauth/remote_beacon_seed_fetcher_unittest.cc
+++ b/chromium/components/cryptauth/remote_beacon_seed_fetcher_unittest.cc
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "components/cryptauth/cryptauth_client.h"
#include "components/cryptauth/fake_cryptauth_device_manager.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -106,7 +106,7 @@ TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestRemoteDeviceWithNoPublicKey) {
TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestNoSyncedDevices) {
std::vector<BeaconSeed> seeds;
EXPECT_FALSE(fetcher_->FetchSeedsForDeviceId(
- RemoteDevice::GenerateDeviceId(public_key1), &seeds));
+ RemoteDeviceRef::GenerateDeviceId(public_key1), &seeds));
}
TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestDeviceHasDifferentPublicKey) {
@@ -115,7 +115,7 @@ TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestDeviceHasDifferentPublicKey) {
std::vector<BeaconSeed> seeds;
EXPECT_FALSE(fetcher_->FetchSeedsForDeviceId(
- RemoteDevice::GenerateDeviceId("differentPublicKey"), &seeds));
+ RemoteDeviceRef::GenerateDeviceId("differentPublicKey"), &seeds));
}
TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestSuccess) {
@@ -124,7 +124,7 @@ TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestSuccess) {
std::vector<BeaconSeed> seeds1;
ASSERT_TRUE(fetcher_->FetchSeedsForDeviceId(
- RemoteDevice::GenerateDeviceId(public_key1), &seeds1));
+ RemoteDeviceRef::GenerateDeviceId(public_key1), &seeds1));
ASSERT_EQ(2u, seeds1.size());
EXPECT_EQ(fake_beacon_seed1_data, seeds1[0].data());
EXPECT_EQ(fake_beacon_seed1_start_ms, seeds1[0].start_time_millis());
@@ -135,7 +135,7 @@ TEST_F(CryptAuthRemoteBeaconSeedFetcherTest, TestSuccess) {
std::vector<BeaconSeed> seeds2;
ASSERT_TRUE(fetcher_->FetchSeedsForDeviceId(
- RemoteDevice::GenerateDeviceId(public_key2), &seeds2));
+ RemoteDeviceRef::GenerateDeviceId(public_key2), &seeds2));
ASSERT_EQ(2u, seeds2.size());
EXPECT_EQ(fake_beacon_seed3_data, seeds2[0].data());
EXPECT_EQ(fake_beacon_seed3_start_ms, seeds2[0].start_time_millis());
diff --git a/chromium/components/cryptauth/remote_device.cc b/chromium/components/cryptauth/remote_device.cc
index b26b6d4828e..16b740e425d 100644
--- a/chromium/components/cryptauth/remote_device.cc
+++ b/chromium/components/cryptauth/remote_device.cc
@@ -5,17 +5,17 @@
#include "components/cryptauth/remote_device.h"
#include "base/base64.h"
+#include "base/stl_util.h"
namespace cryptauth {
namespace {
-// Returns true if both vectors are BeaconSeeds are equal.
+// Returns true if both vectors of BeaconSeeds are equal.
bool AreBeaconSeedsEqual(const std::vector<BeaconSeed> beacon_seeds1,
const std::vector<BeaconSeed> beacon_seeds2) {
- if (beacon_seeds1.size() != beacon_seeds2.size()) {
+ if (beacon_seeds1.size() != beacon_seeds2.size())
return false;
- }
for (size_t i = 0; i < beacon_seeds1.size(); ++i) {
const BeaconSeed& seed1 = beacon_seeds1[i];
@@ -32,27 +32,35 @@ bool AreBeaconSeedsEqual(const std::vector<BeaconSeed> beacon_seeds1,
} // namespace
+// static
+std::string RemoteDevice::GenerateDeviceId(const std::string& public_key) {
+ std::string device_id;
+ base::Base64Encode(public_key, &device_id);
+ return device_id;
+}
+
RemoteDevice::RemoteDevice()
: unlock_key(false),
supports_mobile_hotspot(false),
last_update_time_millis(0L) {}
-RemoteDevice::RemoteDevice(const std::string& user_id,
- const std::string& name,
- const std::string& public_key,
- const std::string& bluetooth_address,
- const std::string& persistent_symmetric_key,
- bool unlock_key,
- bool supports_mobile_hotspot,
- int64_t last_update_time_millis)
+RemoteDevice::RemoteDevice(
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& public_key,
+ const std::string& persistent_symmetric_key,
+ bool unlock_key,
+ bool supports_mobile_hotspot,
+ int64_t last_update_time_millis,
+ const std::map<SoftwareFeature, SoftwareFeatureState>& software_features)
: user_id(user_id),
name(name),
public_key(public_key),
- bluetooth_address(bluetooth_address),
persistent_symmetric_key(persistent_symmetric_key),
unlock_key(unlock_key),
supports_mobile_hotspot(supports_mobile_hotspot),
- last_update_time_millis(last_update_time_millis) {}
+ last_update_time_millis(last_update_time_millis),
+ software_features(software_features) {}
RemoteDevice::RemoteDevice(const RemoteDevice& other) = default;
@@ -68,10 +76,6 @@ std::string RemoteDevice::GetDeviceId() const {
return RemoteDevice::GenerateDeviceId(public_key);
}
-std::string RemoteDevice::GetTruncatedDeviceIdForLogs() const {
- return RemoteDevice::TruncateDeviceIdForLogs(GetDeviceId());
-}
-
bool RemoteDevice::operator==(const RemoteDevice& other) const {
// Only compare |beacon_seeds| if they are loaded.
bool are_beacon_seeds_equal = false;
@@ -89,7 +93,7 @@ bool RemoteDevice::operator==(const RemoteDevice& other) const {
unlock_key == other.unlock_key &&
supports_mobile_hotspot == other.supports_mobile_hotspot &&
last_update_time_millis == other.last_update_time_millis &&
- are_beacon_seeds_equal;
+ software_features == other.software_features && are_beacon_seeds_equal;
}
bool RemoteDevice::operator<(const RemoteDevice& other) const {
@@ -99,30 +103,4 @@ bool RemoteDevice::operator<(const RemoteDevice& other) const {
return GetDeviceId().compare(other.GetDeviceId()) < 0;
}
-// static
-std::string RemoteDevice::GenerateDeviceId(const std::string& public_key) {
- std::string device_id;
- base::Base64Encode(public_key, &device_id);
- return device_id;
-}
-
-// static
-std::string RemoteDevice::DerivePublicKey(const std::string& device_id) {
- std::string public_key;
- if (base::Base64Decode(device_id, &public_key))
- return public_key;
- return std::string();
-}
-
-// static
-std::string RemoteDevice::TruncateDeviceIdForLogs(const std::string& full_id) {
- if (full_id.length() <= 10) {
- return full_id;
- }
-
- return full_id.substr(0, 5)
- + "..."
- + full_id.substr(full_id.length() - 5, full_id.length());
-}
-
} // namespace cryptauth
diff --git a/chromium/components/cryptauth/remote_device.h b/chromium/components/cryptauth/remote_device.h
index 59ad7abaf9c..1745bc9c94a 100644
--- a/chromium/components/cryptauth/remote_device.h
+++ b/chromium/components/cryptauth/remote_device.h
@@ -5,23 +5,28 @@
#ifndef COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_H_
#define COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_H_
+#include <map>
#include <string>
#include <vector>
#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/software_feature_state.h"
namespace cryptauth {
struct RemoteDevice {
public:
+ // Generates the device ID for a device given its public key.
+ static std::string GenerateDeviceId(const std::string& public_key);
+
std::string user_id;
std::string name;
std::string public_key;
- std::string bluetooth_address;
std::string persistent_symmetric_key;
bool unlock_key;
bool supports_mobile_hotspot;
int64_t last_update_time_millis;
+ std::map<SoftwareFeature, SoftwareFeatureState> software_features;
// Note: To save space, the BeaconSeeds may not necessarily be included in
// this object.
@@ -29,43 +34,28 @@ struct RemoteDevice {
std::vector<BeaconSeed> beacon_seeds;
RemoteDevice();
- RemoteDevice(const std::string& user_id,
- const std::string& name,
- const std::string& public_key,
- const std::string& bluetooth_address,
- const std::string& persistent_symmetric_key,
- bool unlock_key,
- bool supports_mobile_hotspot,
- int64_t last_update_time_millis);
+ RemoteDevice(
+ const std::string& user_id,
+ const std::string& name,
+ const std::string& public_key,
+ const std::string& persistent_symmetric_key,
+ bool unlock_key,
+ bool supports_mobile_hotspot,
+ int64_t last_update_time_millis,
+ const std::map<SoftwareFeature, SoftwareFeatureState>& software_features);
RemoteDevice(const RemoteDevice& other);
~RemoteDevice();
// Loads a vector of BeaconSeeds for the RemoteDevice.
void LoadBeaconSeeds(const std::vector<BeaconSeed>& beacon_seeds);
- // Returns a unique ID for the device.
std::string GetDeviceId() const;
- // Returns a shortened device ID for the purpose of concise logging (device
- // IDs are often so long that logs are difficult to read). Note that this
- // ID is not guaranteed to be unique, so it should only be used for log.
- std::string GetTruncatedDeviceIdForLogs() const;
-
bool operator==(const RemoteDevice& other) const;
// Compares devices via their public keys. Note that this function is
// necessary in order to use |RemoteDevice| as a key of a std::map.
bool operator<(const RemoteDevice& other) const;
-
- // Generates the device ID for a device given its public key.
- static std::string GenerateDeviceId(const std::string& public_key);
-
- // Derives the public key that was used to generate the given device ID;
- // returns empty string if |device_id| is not a valid device ID.
- static std::string DerivePublicKey(const std::string& device_id);
-
- // Static method for truncated device ID for logs.
- static std::string TruncateDeviceIdForLogs(const std::string& full_id);
};
typedef std::vector<RemoteDevice> RemoteDeviceList;
diff --git a/chromium/components/cryptauth/remote_device_cache.cc b/chromium/components/cryptauth/remote_device_cache.cc
new file mode 100644
index 00000000000..735c8850c5e
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_cache.cc
@@ -0,0 +1,51 @@
+// 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 "components/cryptauth/remote_device_cache.h"
+
+#include "base/stl_util.h"
+
+namespace cryptauth {
+
+RemoteDeviceCache::RemoteDeviceCache() = default;
+
+RemoteDeviceCache::~RemoteDeviceCache() = default;
+
+void RemoteDeviceCache::SetRemoteDevices(
+ const RemoteDeviceList& remote_devices) {
+ for (const auto& remote_device : remote_devices) {
+ if (!base::ContainsKey(remote_device_map_, remote_device.GetDeviceId())) {
+ remote_device_map_[remote_device.GetDeviceId()] =
+ std::make_shared<RemoteDevice>(remote_device);
+ continue;
+ }
+
+ // Keep the same |shared_ptr| obect, and simply update the RemoteDevice it
+ // references. This transparently updates the RemoteDeviceRefs used by
+ // clients.
+ *remote_device_map_[remote_device.GetDeviceId()] = remote_device;
+ }
+
+ // Intentionally leave behind devices in the map which weren't in
+ // |remote_devices|, to prevent clients from segfaulting by accessing "stale"
+ // devices.
+}
+
+RemoteDeviceRefList RemoteDeviceCache::GetRemoteDevices() const {
+ RemoteDeviceRefList remote_devices;
+ for (const auto& it : remote_device_map_)
+ remote_devices.push_back(RemoteDeviceRef(it.second));
+
+ return remote_devices;
+}
+
+base::Optional<RemoteDeviceRef> RemoteDeviceCache::GetRemoteDevice(
+ const std::string& device_id) const {
+ if (!base::ContainsKey(remote_device_map_, device_id))
+ return base::nullopt;
+
+ return RemoteDeviceRef(remote_device_map_.at(device_id));
+}
+
+} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/remote_device_cache.h b/chromium/components/cryptauth/remote_device_cache.h
new file mode 100644
index 00000000000..2e9cfc3ddea
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_cache.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_CACHE_H_
+#define COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_CACHE_H_
+
+#include <memory>
+#include <unordered_map>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
+
+namespace cryptauth {
+
+// A simple cache of RemoteDeviceRefs. Note that if multiple calls to
+// SetRemoteDevices() are provided different sets of devices, the set of devices
+// returned by GetRemoteDevices() is the union of those different sets (i.e.,
+// devices are not deleted from the cache).
+class RemoteDeviceCache {
+ public:
+ RemoteDeviceCache();
+ virtual ~RemoteDeviceCache();
+
+ void SetRemoteDevices(const RemoteDeviceList& remote_devices);
+
+ RemoteDeviceRefList GetRemoteDevices() const;
+
+ base::Optional<RemoteDeviceRef> GetRemoteDevice(
+ const std::string& device_id) const;
+
+ private:
+ std::unordered_map<std::string, std::shared_ptr<RemoteDevice>>
+ remote_device_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteDeviceCache);
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_CACHE_H_
diff --git a/chromium/components/cryptauth/remote_device_cache_unittest.cc b/chromium/components/cryptauth/remote_device_cache_unittest.cc
new file mode 100644
index 00000000000..28e3b3d3d0e
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_cache_unittest.cc
@@ -0,0 +1,85 @@
+// 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 "components/cryptauth/remote_device_cache.h"
+
+#include <algorithm>
+
+#include "components/cryptauth/remote_device_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cryptauth {
+
+class RemoteDeviceCacheTest : public testing::Test {
+ protected:
+ RemoteDeviceCacheTest()
+ : test_remote_device_list_(CreateRemoteDeviceListForTest(5)),
+ test_remote_device_ref_list_(CreateRemoteDeviceRefListForTest(5)){};
+
+ // testing::Test:
+ void SetUp() override { cache_ = std::make_unique<RemoteDeviceCache>(); }
+
+ void VerifyCacheRemoteDevices(
+ RemoteDeviceRefList expected_remote_device_ref_list) {
+ RemoteDeviceRefList remote_device_ref_list = cache_->GetRemoteDevices();
+ std::sort(remote_device_ref_list.begin(), remote_device_ref_list.end(),
+ [](const auto& device_1, const auto& device_2) {
+ return device_1 < device_2;
+ });
+
+ EXPECT_EQ(expected_remote_device_ref_list, remote_device_ref_list);
+ }
+
+ const RemoteDeviceList test_remote_device_list_;
+ const RemoteDeviceRefList test_remote_device_ref_list_;
+ std::unique_ptr<RemoteDeviceCache> cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteDeviceCacheTest);
+};
+
+TEST_F(RemoteDeviceCacheTest, TestNoRemoteDevices) {
+ VerifyCacheRemoteDevices(RemoteDeviceRefList());
+ EXPECT_EQ(base::nullopt, cache_->GetRemoteDevice(
+ test_remote_device_ref_list_[0].GetDeviceId()));
+}
+
+TEST_F(RemoteDeviceCacheTest, TestSetAndGetRemoteDevices) {
+ cache_->SetRemoteDevices(test_remote_device_list_);
+
+ VerifyCacheRemoteDevices(test_remote_device_ref_list_);
+ EXPECT_EQ(
+ test_remote_device_ref_list_[0],
+ cache_->GetRemoteDevice(test_remote_device_ref_list_[0].GetDeviceId()));
+}
+
+TEST_F(RemoteDeviceCacheTest,
+ TestSetRemoteDevices_RemoteDeviceRefsRemainValidAfterCacheRemoval) {
+ cache_->SetRemoteDevices(test_remote_device_list_);
+
+ VerifyCacheRemoteDevices(test_remote_device_ref_list_);
+
+ cache_->SetRemoteDevices(RemoteDeviceList());
+
+ VerifyCacheRemoteDevices(test_remote_device_ref_list_);
+}
+
+TEST_F(RemoteDeviceCacheTest,
+ TestSetRemoteDevices_RemoteDeviceRefsRemainValidAfterCacheUpdate) {
+ cryptauth::RemoteDevice remote_device =
+ cryptauth::CreateRemoteDeviceForTest();
+ cache_->SetRemoteDevices({remote_device});
+
+ cryptauth::RemoteDeviceRef remote_device_ref =
+ *cache_->GetRemoteDevice(remote_device.GetDeviceId());
+ EXPECT_EQ(remote_device.name, remote_device_ref.name());
+
+ remote_device.name = "new name";
+ cache_->SetRemoteDevices({remote_device});
+
+ EXPECT_EQ(remote_device.name, remote_device_ref.name());
+}
+
+// GetRemoteDevice
+
+} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/remote_device_loader.cc b/chromium/components/cryptauth/remote_device_loader.cc
index ad4a97814af..566bcf4f111 100644
--- a/chromium/components/cryptauth/remote_device_loader.cc
+++ b/chromium/components/cryptauth/remote_device_loader.cc
@@ -11,8 +11,32 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "chromeos/components/proximity_auth/logging/logging.h"
+#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/secure_message_delegate.h"
+namespace {
+
+std::map<cryptauth::SoftwareFeature, cryptauth::SoftwareFeatureState>
+GetSoftwareFeatureToStateMap(const cryptauth::ExternalDeviceInfo& device) {
+ std::map<cryptauth::SoftwareFeature, cryptauth::SoftwareFeatureState>
+ software_feature_to_state_map;
+
+ for (int i = 0; i < device.supported_software_features_size(); ++i) {
+ software_feature_to_state_map[device.supported_software_features(i)] =
+ cryptauth::SoftwareFeatureState::kSupported;
+ }
+
+ for (int i = 0; i < device.enabled_software_features_size(); ++i) {
+ software_feature_to_state_map[device.enabled_software_features(i)] =
+ cryptauth::SoftwareFeatureState::kEnabled;
+ }
+
+ return software_feature_to_state_map;
+}
+
+} // namespace
+
namespace cryptauth {
// static
@@ -101,13 +125,11 @@ void RemoteDeviceLoader::OnPSKDerived(
DCHECK(iterator != remaining_devices_.end());
remaining_devices_.erase(iterator);
- PA_LOG(INFO) << "Derived PSK for " << device.friendly_device_name()
- << ", " << remaining_devices_.size() << " keys remaining.";
- cryptauth::RemoteDevice remote_device(
- user_id_, device.friendly_device_name(), device.public_key(),
- device.bluetooth_address(), psk, device.unlock_key(),
- device.mobile_hotspot_supported(), device.last_update_time_millis());
+ RemoteDevice remote_device(
+ user_id_, device.friendly_device_name(), device.public_key(), psk,
+ device.unlock_key(), device.mobile_hotspot_supported(),
+ device.last_update_time_millis(), GetSoftwareFeatureToStateMap(device));
if (should_load_beacon_seeds_) {
std::vector<BeaconSeed> beacon_seeds;
@@ -116,10 +138,14 @@ void RemoteDeviceLoader::OnPSKDerived(
}
remote_device.LoadBeaconSeeds(beacon_seeds);
}
+
remote_devices_.push_back(remote_device);
- if (remaining_devices_.empty())
+ if (remaining_devices_.empty()) {
+ PA_LOG(INFO) << "Derived keys for " << remote_devices_.size()
+ << " devices.";
callback_.Run(remote_devices_);
+ }
}
} // namespace cryptauth
diff --git a/chromium/components/cryptauth/remote_device_loader.h b/chromium/components/cryptauth/remote_device_loader.h
index 155645dd85b..8dbf46c2476 100644
--- a/chromium/components/cryptauth/remote_device_loader.h
+++ b/chromium/components/cryptauth/remote_device_loader.h
@@ -48,7 +48,7 @@ class RemoteDeviceLoader {
// Creates the instance:
// |device_info_list|: The ExternalDeviceInfo objects to convert to
- // RemoteDevices.
+ // RemoteDevice.
// |user_private_key|: The private key of the user's local device. Used to
// derive the PSK.
// |secure_message_delegate|: Used to derive each persistent symmetric key.
diff --git a/chromium/components/cryptauth/remote_device_loader_unittest.cc b/chromium/components/cryptauth/remote_device_loader_unittest.cc
index 03599cdd7f0..680ea880886 100644
--- a/chromium/components/cryptauth/remote_device_loader_unittest.cc
+++ b/chromium/components/cryptauth/remote_device_loader_unittest.cc
@@ -21,7 +21,6 @@ namespace {
// Prefixes for RemoteDevice fields.
const char kDeviceNamePrefix[] = "device";
const char kPublicKeyPrefix[] = "pk";
-const char kBluetoothAddressPrefix[] = "11:22:33:44:55:0";
// The id of the user who the remote devices belong to.
const char kUserId[] = "example@gmail.com";
@@ -40,8 +39,6 @@ cryptauth::ExternalDeviceInfo CreateDeviceInfo(const std::string& suffix) {
cryptauth::ExternalDeviceInfo device_info;
device_info.set_friendly_device_name(std::string(kDeviceNamePrefix) + suffix);
device_info.set_public_key(std::string(kPublicKeyPrefix) + suffix);
- device_info.set_bluetooth_address(std::string(kBluetoothAddressPrefix) +
- suffix);
device_info.add_beacon_seeds();
BeaconSeed* beacon_seed = device_info.mutable_beacon_seeds(0);
beacon_seed->set_start_time_millis(kBeaconSeedStartTimeMs);
@@ -62,7 +59,7 @@ class CryptAuthRemoteDeviceLoaderTest : public testing::Test {
~CryptAuthRemoteDeviceLoaderTest() {}
void OnRemoteDevicesLoaded(
- const std::vector<cryptauth::RemoteDevice>& remote_devices) {
+ const cryptauth::RemoteDeviceList& remote_devices) {
remote_devices_ = remote_devices;
LoadCompleted();
}
@@ -79,7 +76,7 @@ class CryptAuthRemoteDeviceLoaderTest : public testing::Test {
std::string user_private_key_;
// Stores the result of the RemoteDeviceLoader.
- std::vector<cryptauth::RemoteDevice> remote_devices_;
+ cryptauth::RemoteDeviceList remote_devices_;
DISALLOW_COPY_AND_ASSIGN(CryptAuthRemoteDeviceLoaderTest);
};
@@ -89,7 +86,6 @@ TEST_F(CryptAuthRemoteDeviceLoaderTest, LoadZeroDevices) {
RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
std::move(secure_message_delegate_));
- std::vector<cryptauth::RemoteDevice> result;
EXPECT_CALL(*this, LoadCompleted());
loader.Load(
false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
@@ -104,7 +100,6 @@ TEST_F(CryptAuthRemoteDeviceLoaderTest, LoadOneDeviceWithBeaconSeeds) {
RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
std::move(secure_message_delegate_));
- std::vector<cryptauth::RemoteDevice> result;
EXPECT_CALL(*this, LoadCompleted());
loader.Load(
true, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
@@ -166,7 +161,6 @@ TEST_F(CryptAuthRemoteDeviceLoaderTest, BooleanAttributes) {
RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
std::move(secure_message_delegate_));
- std::vector<cryptauth::RemoteDevice> result;
EXPECT_CALL(*this, LoadCompleted());
loader.Load(
false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
@@ -195,7 +189,6 @@ TEST_F(CryptAuthRemoteDeviceLoaderTest, LastUpdateTimeMillis) {
RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
std::move(secure_message_delegate_));
- std::vector<cryptauth::RemoteDevice> result;
EXPECT_CALL(*this, LoadCompleted());
loader.Load(
false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
@@ -208,73 +201,36 @@ TEST_F(CryptAuthRemoteDeviceLoaderTest, LastUpdateTimeMillis) {
EXPECT_EQ(2000, remote_devices_[1].last_update_time_millis);
}
-TEST_F(CryptAuthRemoteDeviceLoaderTest, LoadOneDeviceWithAddress) {
- std::vector<cryptauth::ExternalDeviceInfo> device_infos(1,
- CreateDeviceInfo("0"));
- RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
- std::move(secure_message_delegate_));
+TEST_F(CryptAuthRemoteDeviceLoaderTest, SoftwareFeatures) {
+ const std::vector<SoftwareFeature> kSupportedSoftwareFeatures{
+ BETTER_TOGETHER_HOST, BETTER_TOGETHER_CLIENT};
+ const std::vector<SoftwareFeature> kEnabledSoftwareFeatures{
+ BETTER_TOGETHER_HOST};
- std::vector<cryptauth::RemoteDevice> result;
- EXPECT_CALL(*this, LoadCompleted());
- loader.Load(
- false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
- base::Unretained(this)));
+ cryptauth::ExternalDeviceInfo first = CreateDeviceInfo("0");
+ for (const auto& software_feature : kSupportedSoftwareFeatures)
+ first.add_supported_software_features(software_feature);
+ for (const auto& software_feature : kEnabledSoftwareFeatures)
+ first.add_enabled_software_features(software_feature);
- EXPECT_EQ(1u, remote_devices_.size());
- EXPECT_FALSE(remote_devices_[0].persistent_symmetric_key.empty());
- EXPECT_EQ(device_infos[0].friendly_device_name(), remote_devices_[0].name);
- EXPECT_EQ(device_infos[0].public_key(), remote_devices_[0].public_key);
- EXPECT_EQ(device_infos[0].bluetooth_address(),
- remote_devices_[0].bluetooth_address);
- EXPECT_EQ(0u, remote_devices_[0].beacon_seeds.size());
-}
+ std::vector<cryptauth::ExternalDeviceInfo> device_infos{first};
-TEST_F(CryptAuthRemoteDeviceLoaderTest, LoadOneDeviceWithoutAddress) {
- std::vector<cryptauth::ExternalDeviceInfo> device_infos(1,
- CreateDeviceInfo("0"));
- device_infos[0].set_bluetooth_address(std::string());
RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
std::move(secure_message_delegate_));
- std::vector<cryptauth::RemoteDevice> result;
EXPECT_CALL(*this, LoadCompleted());
loader.Load(
false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
base::Unretained(this)));
EXPECT_EQ(1u, remote_devices_.size());
- EXPECT_FALSE(remote_devices_[0].persistent_symmetric_key.empty());
- EXPECT_EQ(device_infos[0].friendly_device_name(), remote_devices_[0].name);
- EXPECT_EQ(device_infos[0].public_key(), remote_devices_[0].public_key);
- EXPECT_EQ("", remote_devices_[0].bluetooth_address);
-}
-
-TEST_F(CryptAuthRemoteDeviceLoaderTest, LoadThreeRemoteDevices) {
- std::vector<cryptauth::ExternalDeviceInfo> device_infos;
- device_infos.push_back(CreateDeviceInfo("0"));
- device_infos.push_back(CreateDeviceInfo("1"));
- device_infos.push_back(CreateDeviceInfo("2"));
-
- // Devices 0 and 1 do not have a Bluetooth address, but device 2 does.
- device_infos[0].set_bluetooth_address(std::string());
- device_infos[1].set_bluetooth_address(std::string());
-
- RemoteDeviceLoader loader(device_infos, user_private_key_, kUserId,
- std::move(secure_message_delegate_));
- EXPECT_CALL(*this, LoadCompleted());
- loader.Load(
- false, base::Bind(&CryptAuthRemoteDeviceLoaderTest::OnRemoteDevicesLoaded,
- base::Unretained(this)));
-
- EXPECT_EQ(3u, remote_devices_.size());
- for (size_t i = 0; i < 3; ++i) {
- EXPECT_FALSE(remote_devices_[i].persistent_symmetric_key.empty());
- EXPECT_EQ(device_infos[i].friendly_device_name(), remote_devices_[i].name);
- EXPECT_EQ(device_infos[i].public_key(), remote_devices_[i].public_key);
- EXPECT_EQ(device_infos[i].bluetooth_address(),
- remote_devices_[i].bluetooth_address);
- }
+ EXPECT_EQ(SoftwareFeatureState::kSupported,
+ remote_devices_[0].software_features[BETTER_TOGETHER_CLIENT]);
+ EXPECT_EQ(SoftwareFeatureState::kEnabled,
+ remote_devices_[0].software_features[BETTER_TOGETHER_HOST]);
+ EXPECT_EQ(SoftwareFeatureState::kNotSupported,
+ remote_devices_[0].software_features[MAGIC_TETHER_HOST]);
}
} // namespace cryptauth
diff --git a/chromium/components/cryptauth/remote_device_provider_impl_unittest.cc b/chromium/components/cryptauth/remote_device_provider_impl_unittest.cc
index a3bbf97cffc..54174ebc76a 100644
--- a/chromium/components/cryptauth/remote_device_provider_impl_unittest.cc
+++ b/chromium/components/cryptauth/remote_device_provider_impl_unittest.cc
@@ -49,7 +49,7 @@ class FakeSecureMessageDelegateFactory
std::vector<cryptauth::ExternalDeviceInfo>
CreateExternalDeviceInfosForRemoteDevices(
- const std::vector<cryptauth::RemoteDevice> remote_devices) {
+ const cryptauth::RemoteDeviceList remote_devices) {
std::vector<cryptauth::ExternalDeviceInfo> device_infos;
for (const auto& remote_device : remote_devices) {
// Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
@@ -82,7 +82,7 @@ class FakeDeviceLoader final : public cryptauth::RemoteDeviceLoader {
: public RemoteDeviceLoader::Factory {
public:
explicit TestRemoteDeviceLoaderFactory()
- : test_devices_(cryptauth::GenerateTestRemoteDevices(5)),
+ : test_devices_(cryptauth::CreateRemoteDeviceListForTest(5)),
test_device_infos_(
CreateExternalDeviceInfosForRemoteDevices(test_devices_)) {}
@@ -107,8 +107,8 @@ class FakeDeviceLoader final : public cryptauth::RemoteDeviceLoader {
ASSERT_TRUE(!callback_.is_null());
// Fetch only the devices inserted by tests, since test_devices_ contains
// all available devices.
- std::vector<RemoteDevice> devices;
- for (const auto& remote_device : test_devices_) {
+ RemoteDeviceList devices;
+ for (const auto remote_device : test_devices_) {
for (const auto& external_device_info : device_info_list) {
if (remote_device.public_key == external_device_info.public_key())
devices.push_back(remote_device);
@@ -121,7 +121,7 @@ class FakeDeviceLoader final : public cryptauth::RemoteDeviceLoader {
// Fetch is only started if the change result passed to OnSyncFinished() is
// CHANGED and sync is SUCCESS.
bool HasQueuedCallback() { return !callback_.is_null(); }
- const std::vector<cryptauth::RemoteDevice> test_devices_;
+ const cryptauth::RemoteDeviceList test_devices_;
const std::vector<cryptauth::ExternalDeviceInfo> test_device_infos_;
void QueueCallback(const RemoteDeviceCallback& callback) {
@@ -183,7 +183,7 @@ class RemoteDeviceProviderImplTest : public testing::Test {
}
void VerifySyncedDevicesMatchExpectation(size_t expected_size) {
- std::vector<cryptauth::RemoteDevice> synced_devices =
+ cryptauth::RemoteDeviceList synced_devices =
remote_device_provider_->GetSyncedDevices();
EXPECT_EQ(expected_size, synced_devices.size());
EXPECT_EQ(expected_size, fake_device_manager_->GetSyncedDevices().size());
@@ -197,7 +197,7 @@ class RemoteDeviceProviderImplTest : public testing::Test {
}
}
- std::vector<cryptauth::RemoteDevice> test_devices() {
+ cryptauth::RemoteDeviceList test_devices() {
return test_device_loader_factory_->test_devices_;
}
diff --git a/chromium/components/cryptauth/remote_device_ref.cc b/chromium/components/cryptauth/remote_device_ref.cc
new file mode 100644
index 00000000000..28587515518
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_ref.cc
@@ -0,0 +1,67 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cryptauth/remote_device_ref.h"
+
+#include "base/base64.h"
+#include "base/stl_util.h"
+
+namespace cryptauth {
+
+// static
+std::string RemoteDeviceRef::GenerateDeviceId(const std::string& public_key) {
+ return RemoteDevice::GenerateDeviceId(public_key);
+}
+
+// static
+std::string RemoteDeviceRef::DerivePublicKey(const std::string& device_id) {
+ std::string public_key;
+ if (base::Base64Decode(device_id, &public_key))
+ return public_key;
+ return std::string();
+}
+
+// static
+std::string RemoteDeviceRef::TruncateDeviceIdForLogs(
+ const std::string& full_id) {
+ if (full_id.length() <= 10) {
+ return full_id;
+ }
+
+ return full_id.substr(0, 5) + "..." +
+ full_id.substr(full_id.length() - 5, full_id.length());
+}
+
+RemoteDeviceRef::RemoteDeviceRef(std::shared_ptr<RemoteDevice> remote_device)
+ : remote_device_(std::move(remote_device)) {}
+
+RemoteDeviceRef::RemoteDeviceRef(const RemoteDeviceRef& other) = default;
+
+RemoteDeviceRef::~RemoteDeviceRef() = default;
+
+SoftwareFeatureState RemoteDeviceRef::GetSoftwareFeatureState(
+ const SoftwareFeature& software_feature) const {
+ if (!base::ContainsKey(remote_device_->software_features, software_feature))
+ return SoftwareFeatureState::kNotSupported;
+
+ return remote_device_->software_features.at(software_feature);
+}
+
+std::string RemoteDeviceRef::GetDeviceId() const {
+ return remote_device_->GetDeviceId();
+}
+
+std::string RemoteDeviceRef::GetTruncatedDeviceIdForLogs() const {
+ return RemoteDeviceRef::TruncateDeviceIdForLogs(GetDeviceId());
+}
+
+bool RemoteDeviceRef::operator==(const RemoteDeviceRef& other) const {
+ return *remote_device_ == *other.remote_device_;
+}
+
+bool RemoteDeviceRef::operator<(const RemoteDeviceRef& other) const {
+ return *remote_device_ < *other.remote_device_;
+}
+
+} // namespace cryptauth \ No newline at end of file
diff --git a/chromium/components/cryptauth/remote_device_ref.h b/chromium/components/cryptauth/remote_device_ref.h
new file mode 100644
index 00000000000..f02ec6c334e
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_ref.h
@@ -0,0 +1,115 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_REF_H_
+#define COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_REF_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/software_feature_state.h"
+
+namespace chromeos {
+class EasyUnlockServiceRegular;
+namespace tether {
+class TetherHostFetcherImpl;
+class TetherHostFetcherImplTest;
+} // namespace tether
+} // namespace chromeos
+
+namespace proximity_auth {
+class BluetoothLowEnergySetupConnectionFinder;
+class ProximityAuthWebUIHandler;
+} // namespace proximity_auth
+
+namespace cryptauth {
+
+class RemoteDeviceCache;
+
+// Contains metadata specific to a device associated with a user's account.
+// Because this metadata contains large and expensive data types, and that data
+// can become stale if a Device Sync occurs during a client application's
+// lifecycle, RemoteDeviceRef is implemented using a pointer to a struct
+// containing this metadata; if multiple clients want to reference the same
+// device, multiple RemoteDeviceRefs can be created cheaply without duplicating
+// the underlying data. Should be passed by value.
+class RemoteDeviceRef {
+ public:
+ // Generates the device ID for a device given its public key.
+ static std::string GenerateDeviceId(const std::string& public_key);
+
+ // Derives the public key that was used to generate the given device ID;
+ // returns empty string if |device_id| is not a valid device ID.
+ static std::string DerivePublicKey(const std::string& device_id);
+
+ // Static method for truncated device ID for logs.
+ static std::string TruncateDeviceIdForLogs(const std::string& full_id);
+
+ RemoteDeviceRef(const RemoteDeviceRef& other);
+ ~RemoteDeviceRef();
+
+ const std::string& user_id() const { return remote_device_->user_id; }
+ const std::string& name() const { return remote_device_->name; }
+ const std::string& public_key() const { return remote_device_->public_key; }
+ const std::string& persistent_symmetric_key() const {
+ return remote_device_->persistent_symmetric_key;
+ }
+ bool unlock_key() const { return remote_device_->unlock_key; }
+ bool supports_mobile_hotspot() const {
+ return remote_device_->supports_mobile_hotspot;
+ }
+ int64_t last_update_time_millis() const {
+ return remote_device_->last_update_time_millis;
+ }
+ const std::vector<BeaconSeed>& beacon_seeds() const {
+ return remote_device_->beacon_seeds;
+ }
+ bool are_beacon_seeds_loaded() const {
+ return remote_device_->are_beacon_seeds_loaded;
+ }
+
+ std::string GetDeviceId() const;
+ SoftwareFeatureState GetSoftwareFeatureState(
+ const SoftwareFeature& software_feature) const;
+
+ // Returns a shortened device ID for the purpose of concise logging (device
+ // IDs are often so long that logs are difficult to read). Note that this
+ // ID is not guaranteed to be unique, so it should only be used for log.
+ std::string GetTruncatedDeviceIdForLogs() const;
+
+ bool operator==(const RemoteDeviceRef& other) const;
+
+ // This function is necessary in order to use |RemoteDeviceRef| as a key of a
+ // std::map.
+ bool operator<(const RemoteDeviceRef& other) const;
+
+ private:
+ friend class RemoteDeviceCache;
+ friend class RemoteDeviceRefBuilder;
+ friend class RemoteDeviceRefTest;
+ FRIEND_TEST_ALL_PREFIXES(RemoteDeviceRefTest, TestFields);
+ FRIEND_TEST_ALL_PREFIXES(RemoteDeviceRefTest, TestCopyAndAssign);
+
+ // TODO(crbug.com/752273): Remove these once clients have migrated to Device
+ // Sync service.
+ friend class chromeos::EasyUnlockServiceRegular;
+ friend class chromeos::tether::TetherHostFetcherImpl;
+ friend class chromeos::tether::TetherHostFetcherImplTest;
+ friend class proximity_auth::ProximityAuthWebUIHandler;
+ friend class proximity_auth::BluetoothLowEnergySetupConnectionFinder;
+
+ explicit RemoteDeviceRef(std::shared_ptr<RemoteDevice> remote_device);
+
+ std::shared_ptr<const RemoteDevice> remote_device_;
+};
+
+typedef std::vector<RemoteDeviceRef> RemoteDeviceRefList;
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_REMOTE_DEVICE_REF_H_ \ No newline at end of file
diff --git a/chromium/components/cryptauth/remote_device_ref_unittest.cc b/chromium/components/cryptauth/remote_device_ref_unittest.cc
new file mode 100644
index 00000000000..2b06c00a643
--- /dev/null
+++ b/chromium/components/cryptauth/remote_device_ref_unittest.cc
@@ -0,0 +1,84 @@
+// 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 "components/cryptauth/remote_device_ref.h"
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/cryptauth/remote_device.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cryptauth {
+
+class RemoteDeviceRefTest : public testing::Test {
+ protected:
+ RemoteDeviceRefTest() = default;
+
+ // testing::Test:
+ void SetUp() override {
+ std::map<cryptauth::SoftwareFeature, cryptauth::SoftwareFeatureState>
+ software_feature_to_state_map;
+ software_feature_to_state_map
+ [cryptauth::SoftwareFeature::BETTER_TOGETHER_CLIENT] =
+ cryptauth::SoftwareFeatureState::kSupported;
+ software_feature_to_state_map
+ [cryptauth::SoftwareFeature::BETTER_TOGETHER_HOST] =
+ cryptauth::SoftwareFeatureState::kEnabled;
+
+ remote_device_ = std::make_shared<RemoteDevice>(
+ "user_id", "name", "public_key", "persistent_symmetric_key",
+ true /* unlock_key */, true /* supports_mobile_hotspot */,
+ 42000 /* last_update_time_millis */,
+ software_feature_to_state_map /* software_features */);
+ remote_device_->LoadBeaconSeeds({BeaconSeed(), BeaconSeed()});
+ }
+
+ std::shared_ptr<RemoteDevice> remote_device_;
+
+ DISALLOW_COPY_AND_ASSIGN(RemoteDeviceRefTest);
+};
+
+TEST_F(RemoteDeviceRefTest, TestFields) {
+ RemoteDeviceRef remote_device_ref(remote_device_);
+
+ EXPECT_EQ(remote_device_->user_id, remote_device_ref.user_id());
+ EXPECT_EQ(remote_device_->name, remote_device_ref.name());
+ EXPECT_EQ(remote_device_->public_key, remote_device_ref.public_key());
+ EXPECT_EQ(remote_device_->persistent_symmetric_key,
+ remote_device_ref.persistent_symmetric_key());
+ EXPECT_EQ(remote_device_->unlock_key, remote_device_ref.unlock_key());
+ EXPECT_EQ(remote_device_->supports_mobile_hotspot,
+ remote_device_ref.supports_mobile_hotspot());
+ EXPECT_EQ(remote_device_->last_update_time_millis,
+ remote_device_ref.last_update_time_millis());
+ EXPECT_EQ(&remote_device_->beacon_seeds, &remote_device_ref.beacon_seeds());
+
+ EXPECT_EQ(cryptauth::SoftwareFeatureState::kNotSupported,
+ remote_device_ref.GetSoftwareFeatureState(
+ cryptauth::SoftwareFeature::MAGIC_TETHER_CLIENT));
+ EXPECT_EQ(cryptauth::SoftwareFeatureState::kSupported,
+ remote_device_ref.GetSoftwareFeatureState(
+ cryptauth::SoftwareFeature::BETTER_TOGETHER_CLIENT));
+ EXPECT_EQ(cryptauth::SoftwareFeatureState::kEnabled,
+ remote_device_ref.GetSoftwareFeatureState(
+ cryptauth::SoftwareFeature::BETTER_TOGETHER_HOST));
+
+ EXPECT_EQ(remote_device_->GetDeviceId(), remote_device_ref.GetDeviceId());
+ EXPECT_EQ(
+ RemoteDeviceRef::TruncateDeviceIdForLogs(remote_device_->GetDeviceId()),
+ remote_device_ref.GetTruncatedDeviceIdForLogs());
+}
+
+TEST_F(RemoteDeviceRefTest, TestCopyAndAssign) {
+ RemoteDeviceRef remote_device_ref_1(remote_device_);
+
+ RemoteDeviceRef remote_device_ref_2 = remote_device_ref_1;
+ EXPECT_EQ(remote_device_ref_2, remote_device_ref_1);
+
+ RemoteDeviceRef remote_device_ref_3(remote_device_ref_1);
+ EXPECT_EQ(remote_device_ref_3, remote_device_ref_1);
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/remote_device_test_util.cc b/chromium/components/cryptauth/remote_device_test_util.cc
index 73fe0928ec8..062dfedfbe4 100644
--- a/chromium/components/cryptauth/remote_device_test_util.cc
+++ b/chromium/components/cryptauth/remote_device_test_util.cc
@@ -8,13 +8,89 @@
namespace cryptauth {
-std::vector<RemoteDevice> GenerateTestRemoteDevices(size_t num_to_create) {
- std::vector<RemoteDevice> generated_devices;
+// Attributes of the default test remote device.
+const char kTestRemoteDeviceUserId[] = "example@gmail.com";
+const char kTestRemoteDeviceName[] = "remote device";
+const char kTestRemoteDevicePublicKey[] = "public key";
+const char kTestRemoteDevicePSK[] = "remote device psk";
+const bool kTestRemoteDeviceUnlockKey = true;
+const bool kTestRemoteDeviceSupportsMobileHotspot = true;
+const int64_t kTestRemoteDeviceLastUpdateTimeMillis = 0L;
+
+RemoteDeviceRefBuilder::RemoteDeviceRefBuilder() {
+ remote_device_ = std::make_shared<RemoteDevice>(CreateRemoteDeviceForTest());
+}
+
+RemoteDeviceRefBuilder::~RemoteDeviceRefBuilder() = default;
+
+RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetUserId(
+ const std::string& user_id) {
+ remote_device_->user_id = user_id;
+ return *this;
+}
+
+RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetName(
+ const std::string& name) {
+ remote_device_->name = name;
+ return *this;
+}
+
+RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetPublicKey(
+ const std::string& public_key) {
+ remote_device_->public_key = public_key;
+ return *this;
+}
+
+RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetSupportsMobileHotspot(
+ bool supports_mobile_hotspot) {
+ remote_device_->supports_mobile_hotspot = supports_mobile_hotspot;
+ return *this;
+}
+
+RemoteDeviceRefBuilder& RemoteDeviceRefBuilder::SetLastUpdateTimeMillis(
+ int64_t last_update_time_millis) {
+ remote_device_->last_update_time_millis = last_update_time_millis;
+ return *this;
+}
+
+RemoteDeviceRef RemoteDeviceRefBuilder::Build() {
+ return RemoteDeviceRef(remote_device_);
+}
+
+RemoteDevice CreateRemoteDeviceForTest() {
+ return RemoteDevice(kTestRemoteDeviceUserId, kTestRemoteDeviceName,
+ kTestRemoteDevicePublicKey, kTestRemoteDevicePSK,
+ kTestRemoteDeviceUnlockKey,
+ kTestRemoteDeviceSupportsMobileHotspot,
+ kTestRemoteDeviceLastUpdateTimeMillis,
+ std::map<SoftwareFeature, SoftwareFeatureState>());
+}
+
+RemoteDeviceRef CreateRemoteDeviceRefForTest() {
+ return RemoteDeviceRefBuilder().Build();
+}
+
+RemoteDeviceRefList CreateRemoteDeviceRefListForTest(size_t num_to_create) {
+ RemoteDeviceRefList generated_devices;
+
+ for (size_t i = 0; i < num_to_create; i++) {
+ RemoteDeviceRef remote_device =
+ RemoteDeviceRefBuilder()
+ .SetPublicKey("publicKey" + std::to_string(i))
+ .Build();
+ generated_devices.push_back(remote_device);
+ }
+
+ return generated_devices;
+}
+
+RemoteDeviceList CreateRemoteDeviceListForTest(size_t num_to_create) {
+ RemoteDeviceList generated_devices;
for (size_t i = 0; i < num_to_create; i++) {
- RemoteDevice device;
- device.public_key = "publicKey" + std::to_string(i);
- generated_devices.push_back(device);
+ RemoteDevice remote_device = CreateRemoteDeviceForTest();
+ remote_device.public_key = "publicKey" + std::to_string(i);
+ generated_devices.push_back(remote_device);
}
return generated_devices;
diff --git a/chromium/components/cryptauth/remote_device_test_util.h b/chromium/components/cryptauth/remote_device_test_util.h
index f3af23409e4..b372c3e9a5b 100644
--- a/chromium/components/cryptauth/remote_device_test_util.h
+++ b/chromium/components/cryptauth/remote_device_test_util.h
@@ -7,11 +7,38 @@
#include <vector>
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
namespace cryptauth {
-std::vector<RemoteDevice> GenerateTestRemoteDevices(size_t num_to_create);
+// Attributes of the default test remote device.
+extern const char kTestRemoteDeviceName[];
+extern const char kTestRemoteDevicePublicKey[];
+
+class RemoteDeviceRefBuilder {
+ public:
+ RemoteDeviceRefBuilder();
+ ~RemoteDeviceRefBuilder();
+ RemoteDeviceRefBuilder& SetUserId(const std::string& user_id);
+ RemoteDeviceRefBuilder& SetName(const std::string& name);
+ RemoteDeviceRefBuilder& SetPublicKey(const std::string& public_key);
+ RemoteDeviceRefBuilder& SetSupportsMobileHotspot(
+ bool supports_mobile_hotspot);
+ RemoteDeviceRefBuilder& SetLastUpdateTimeMillis(
+ int64_t last_update_time_millis);
+ RemoteDeviceRef Build();
+
+ private:
+ std::shared_ptr<RemoteDevice> remote_device_;
+};
+
+RemoteDevice CreateRemoteDeviceForTest();
+
+RemoteDeviceRef CreateRemoteDeviceRefForTest();
+
+RemoteDeviceList CreateRemoteDeviceListForTest(size_t num_to_create);
+
+RemoteDeviceRefList CreateRemoteDeviceRefListForTest(size_t num_to_create);
} // namespace cryptauth
diff --git a/chromium/components/cryptauth/secure_channel.cc b/chromium/components/cryptauth/secure_channel.cc
index aac65ad40e4..57b540ca024 100644
--- a/chromium/components/cryptauth/secure_channel.cc
+++ b/chromium/components/cryptauth/secure_channel.cc
@@ -246,7 +246,7 @@ void SecureChannel::Authenticate() {
DCHECK(!authenticator_);
authenticator_ = DeviceToDeviceAuthenticator::Factory::NewInstance(
- connection_.get(), connection_->remote_device().user_id,
+ connection_.get(), connection_->remote_device().user_id(),
cryptauth::SecureMessageDelegateImpl::Factory::NewInstance());
authenticator_->Authenticate(
base::Bind(&SecureChannel::OnAuthenticationResult,
diff --git a/chromium/components/cryptauth/secure_channel.h b/chromium/components/cryptauth/secure_channel.h
index 82e04095619..201aa22c4a1 100644
--- a/chromium/components/cryptauth/secure_channel.h
+++ b/chromium/components/cryptauth/secure_channel.h
@@ -12,7 +12,7 @@
#include "components/cryptauth/connection.h"
#include "components/cryptauth/connection_observer.h"
#include "components/cryptauth/device_to_device_authenticator.h"
-#include "components/cryptauth/remote_device.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/secure_context.h"
namespace cryptauth {
diff --git a/chromium/components/cryptauth/secure_channel_unittest.cc b/chromium/components/cryptauth/secure_channel_unittest.cc
index 6961a42ef35..8aeb0a58c33 100644
--- a/chromium/components/cryptauth/secure_channel_unittest.cc
+++ b/chromium/components/cryptauth/secure_channel_unittest.cc
@@ -15,6 +15,7 @@
#include "components/cryptauth/fake_cryptauth_service.h"
#include "components/cryptauth/fake_secure_context.h"
#include "components/cryptauth/fake_secure_message_delegate.h"
+#include "components/cryptauth/remote_device_ref.h"
#include "components/cryptauth/remote_device_test_util.h"
#include "components/cryptauth/secure_message_delegate_impl.h"
#include "components/cryptauth/wire_message.h"
@@ -24,8 +25,6 @@ namespace cryptauth {
namespace {
-const std::string test_user_id = "testUserId";
-
struct SecureChannelStatusChange {
SecureChannelStatusChange(
const SecureChannel::Status& old_status,
@@ -159,9 +158,8 @@ class TestAuthenticatorFactory final
Authenticator* last_instance_;
};
-RemoteDevice CreateTestRemoteDevice() {
- RemoteDevice remote_device = GenerateTestRemoteDevices(1)[0];
- remote_device.user_id = test_user_id;
+RemoteDeviceRef CreateTestRemoteDevice() {
+ RemoteDeviceRef remote_device = CreateRemoteDeviceRefListForTest(1)[0];
return remote_device;
}
@@ -392,7 +390,7 @@ class CryptAuthSecureChannelTest : public testing::Test {
std::unique_ptr<TestAuthenticatorFactory> test_authenticator_factory_;
- const RemoteDevice test_device_;
+ const RemoteDeviceRef test_device_;
base::WeakPtrFactory<CryptAuthSecureChannelTest> weak_ptr_factory_;
diff --git a/chromium/components/cryptauth/software_feature_manager.h b/chromium/components/cryptauth/software_feature_manager.h
new file mode 100644
index 00000000000..d676c8a5624
--- /dev/null
+++ b/chromium/components/cryptauth/software_feature_manager.h
@@ -0,0 +1,43 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_MANAGER_H_
+#define COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_MANAGER_H_
+
+#include "base/callback.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+
+namespace cryptauth {
+
+// Queries for eligible MultiDevice hosts and sets/changes/unsets the current
+// MultiDevice host for the logged-in account.
+class SoftwareFeatureManager {
+ public:
+ virtual ~SoftwareFeatureManager() {}
+
+ // Enables or disables |software_feature| for the device with public key
+ // |public_key|. If |enabled| and |is_exclusive| are both true, then all other
+ // devices associated with this account will have |sofware_feature| disabled.
+ // |is_exclusive| is ignored if |enabled| is false.
+ virtual void SetSoftwareFeatureState(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive = false) = 0;
+
+ // Finds eligible devices associated with the logged-in account which support
+ // |software_feature|.
+ virtual void FindEligibleDevices(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) = 0;
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_MANAGER_H_
diff --git a/chromium/components/cryptauth/software_feature_manager_impl.cc b/chromium/components/cryptauth/software_feature_manager_impl.cc
new file mode 100644
index 00000000000..6aa36e6a731
--- /dev/null
+++ b/chromium/components/cryptauth/software_feature_manager_impl.cc
@@ -0,0 +1,178 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cryptauth/software_feature_manager_impl.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+
+namespace cryptauth {
+
+// static
+SoftwareFeatureManagerImpl::Factory*
+ SoftwareFeatureManagerImpl::Factory::test_factory_instance_ = nullptr;
+
+// static
+std::unique_ptr<SoftwareFeatureManager>
+SoftwareFeatureManagerImpl::Factory::NewInstance(
+ CryptAuthClientFactory* cryptauth_client_factory) {
+ if (test_factory_instance_)
+ return test_factory_instance_->BuildInstance(cryptauth_client_factory);
+
+ static base::NoDestructor<Factory> factory;
+ return factory->BuildInstance(cryptauth_client_factory);
+}
+
+void SoftwareFeatureManagerImpl::Factory::SetInstanceForTesting(
+ Factory* test_factory) {
+ test_factory_instance_ = test_factory;
+}
+
+SoftwareFeatureManagerImpl::Factory::~Factory() = default;
+
+std::unique_ptr<SoftwareFeatureManager>
+SoftwareFeatureManagerImpl::Factory::BuildInstance(
+ CryptAuthClientFactory* cryptauth_client_factory) {
+ return base::WrapUnique(
+ new SoftwareFeatureManagerImpl(cryptauth_client_factory));
+}
+
+SoftwareFeatureManagerImpl::Request::Request(
+ std::unique_ptr<ToggleEasyUnlockRequest> toggle_request,
+ const base::Closure& set_software_success_callback,
+ const base::Callback<void(const std::string&)> error_callback)
+ : error_callback(error_callback),
+ toggle_request(std::move(toggle_request)),
+ set_software_success_callback(set_software_success_callback) {}
+
+SoftwareFeatureManagerImpl::Request::Request(
+ std::unique_ptr<FindEligibleUnlockDevicesRequest> find_request,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>
+ find_hosts_success_callback,
+ const base::Callback<void(const std::string&)> error_callback)
+ : error_callback(error_callback),
+ find_request(std::move(find_request)),
+ find_hosts_success_callback(find_hosts_success_callback) {}
+
+SoftwareFeatureManagerImpl::Request::~Request() = default;
+
+SoftwareFeatureManagerImpl::SoftwareFeatureManagerImpl(
+ CryptAuthClientFactory* cryptauth_client_factory)
+ : crypt_auth_client_factory_(cryptauth_client_factory),
+ weak_ptr_factory_(this) {}
+
+SoftwareFeatureManagerImpl::~SoftwareFeatureManagerImpl() = default;
+
+void SoftwareFeatureManagerImpl::SetSoftwareFeatureState(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive) {
+ // Note: For legacy reasons, this proto message mentions "ToggleEasyUnlock"
+ // instead of "SetSoftwareFeature" in its name.
+ auto request = std::make_unique<ToggleEasyUnlockRequest>();
+ request->set_public_key(public_key);
+ request->set_feature(software_feature);
+ request->set_enable(enabled);
+ request->set_is_exclusive(enabled && is_exclusive);
+
+ // Special case for EasyUnlock: if EasyUnlock is being disabled, set the
+ // apply_to_all property to true.
+ request->set_apply_to_all(!enabled && software_feature ==
+ SoftwareFeature::EASY_UNLOCK_HOST);
+
+ pending_requests_.emplace(std::make_unique<Request>(
+ std::move(request), success_callback, error_callback));
+ ProcessRequestQueue();
+}
+
+void SoftwareFeatureManagerImpl::FindEligibleDevices(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) {
+ // Note: For legacy reasons, this proto message mentions "UnlockDevices"
+ // instead of "MultiDeviceHosts" in its name.
+ auto request = std::make_unique<FindEligibleUnlockDevicesRequest>();
+ request->set_feature(software_feature);
+
+ pending_requests_.emplace(std::make_unique<Request>(
+ std::move(request), success_callback, error_callback));
+ ProcessRequestQueue();
+}
+
+void SoftwareFeatureManagerImpl::ProcessRequestQueue() {
+ if (current_request_ || pending_requests_.empty())
+ return;
+
+ current_request_ = std::move(pending_requests_.front());
+ pending_requests_.pop();
+
+ if (current_request_->toggle_request)
+ ProcessSetSoftwareFeatureStateRequest();
+ else
+ ProcessFindEligibleDevicesRequest();
+}
+
+void SoftwareFeatureManagerImpl::ProcessSetSoftwareFeatureStateRequest() {
+ DCHECK(!current_cryptauth_client_);
+ current_cryptauth_client_ = crypt_auth_client_factory_->CreateInstance();
+
+ current_cryptauth_client_->ToggleEasyUnlock(
+ *current_request_->toggle_request,
+ base::Bind(&SoftwareFeatureManagerImpl::OnToggleEasyUnlockResponse,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&SoftwareFeatureManagerImpl::OnErrorResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SoftwareFeatureManagerImpl::ProcessFindEligibleDevicesRequest() {
+ DCHECK(!current_cryptauth_client_);
+ current_cryptauth_client_ = crypt_auth_client_factory_->CreateInstance();
+
+ current_cryptauth_client_->FindEligibleUnlockDevices(
+ *current_request_->find_request,
+ base::Bind(
+ &SoftwareFeatureManagerImpl::OnFindEligibleUnlockDevicesResponse,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&SoftwareFeatureManagerImpl::OnErrorResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SoftwareFeatureManagerImpl::OnToggleEasyUnlockResponse(
+ const ToggleEasyUnlockResponse& response) {
+ current_cryptauth_client_.reset();
+ current_request_->set_software_success_callback.Run();
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+void SoftwareFeatureManagerImpl::OnFindEligibleUnlockDevicesResponse(
+ const FindEligibleUnlockDevicesResponse& response) {
+ current_cryptauth_client_.reset();
+ current_request_->find_hosts_success_callback.Run(
+ std::vector<ExternalDeviceInfo>(response.eligible_devices().begin(),
+ response.eligible_devices().end()),
+ std::vector<IneligibleDevice>(response.ineligible_devices().begin(),
+ response.ineligible_devices().end()));
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+void SoftwareFeatureManagerImpl::OnErrorResponse(const std::string& response) {
+ current_cryptauth_client_.reset();
+ current_request_->error_callback.Run(response);
+ current_request_.reset();
+ ProcessRequestQueue();
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/software_feature_manager_impl.h b/chromium/components/cryptauth/software_feature_manager_impl.h
new file mode 100644
index 00000000000..3f7ec6c1d69
--- /dev/null
+++ b/chromium/components/cryptauth/software_feature_manager_impl.h
@@ -0,0 +1,111 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_MANAGER_IMPL_H_
+#define COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_MANAGER_IMPL_H_
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/containers/queue.h"
+#include "base/memory/weak_ptr.h"
+#include "components/cryptauth/cryptauth_client.h"
+#include "components/cryptauth/proto/cryptauth_api.pb.h"
+#include "components/cryptauth/software_feature_manager.h"
+
+namespace cryptauth {
+
+// Concrete SoftwareFeatureManager implementation. To query and/or set
+// MultiDevice hosts, this class makes network requests to the CryptAuth
+// back-end.
+class SoftwareFeatureManagerImpl : public SoftwareFeatureManager {
+ public:
+ class Factory {
+ public:
+ static std::unique_ptr<SoftwareFeatureManager> NewInstance(
+ CryptAuthClientFactory* cryptauth_client_factory);
+
+ static void SetInstanceForTesting(Factory* test_factory);
+
+ protected:
+ virtual ~Factory();
+ virtual std::unique_ptr<SoftwareFeatureManager> BuildInstance(
+ CryptAuthClientFactory* cryptauth_client_factory);
+
+ private:
+ static Factory* test_factory_instance_;
+ };
+
+ ~SoftwareFeatureManagerImpl() override;
+
+ // SoftwareFeatureManager:
+ void SetSoftwareFeatureState(
+ const std::string& public_key,
+ SoftwareFeature software_feature,
+ bool enabled,
+ const base::Closure& success_callback,
+ const base::Callback<void(const std::string&)>& error_callback,
+ bool is_exclusive = false) override;
+ void FindEligibleDevices(
+ SoftwareFeature software_feature,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>&
+ success_callback,
+ const base::Callback<void(const std::string&)>& error_callback) override;
+
+ private:
+ enum class RequestType {
+ SET_SOFTWARE_FEATURE,
+ FIND_ELIGIBLE_MULTIDEVICE_HOSTS,
+ };
+
+ struct Request {
+ // Used for SET_SOFTWARE_FEATURE Requests.
+ Request(std::unique_ptr<ToggleEasyUnlockRequest> toggle_request,
+ const base::Closure& set_software_success_callback,
+ const base::Callback<void(const std::string&)> error_callback);
+
+ // Used for FIND_ELIGIBLE_MULTIDEVICE_HOSTS Requests.
+ Request(std::unique_ptr<FindEligibleUnlockDevicesRequest> find_request,
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>
+ find_hosts_success_callback,
+ const base::Callback<void(const std::string&)> error_callback);
+
+ ~Request();
+
+ const base::Callback<void(const std::string&)> error_callback;
+
+ // Set for SET_SOFTWARE_FEATURE; unset otherwise.
+ std::unique_ptr<ToggleEasyUnlockRequest> toggle_request;
+ const base::Closure set_software_success_callback;
+
+ // Set for FIND_ELIGIBLE_MULTIDEVICE_HOSTS; unset otherwise.
+ std::unique_ptr<FindEligibleUnlockDevicesRequest> find_request;
+ const base::Callback<void(const std::vector<ExternalDeviceInfo>&,
+ const std::vector<IneligibleDevice>&)>
+ find_hosts_success_callback;
+ };
+
+ SoftwareFeatureManagerImpl(CryptAuthClientFactory* cryptauth_client_factory);
+
+ void ProcessRequestQueue();
+ void ProcessSetSoftwareFeatureStateRequest();
+ void ProcessFindEligibleDevicesRequest();
+
+ void OnToggleEasyUnlockResponse(const ToggleEasyUnlockResponse& response);
+ void OnFindEligibleUnlockDevicesResponse(
+ const FindEligibleUnlockDevicesResponse& response);
+ void OnErrorResponse(const std::string& response);
+
+ CryptAuthClientFactory* crypt_auth_client_factory_;
+
+ std::unique_ptr<CryptAuthClient> current_cryptauth_client_;
+ std::unique_ptr<Request> current_request_;
+ base::queue<std::unique_ptr<Request>> pending_requests_;
+
+ base::WeakPtrFactory<SoftwareFeatureManagerImpl> weak_ptr_factory_;
+};
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_MANAGER_IMPL_H_
diff --git a/chromium/components/cryptauth/software_feature_manager_impl_unittest.cc b/chromium/components/cryptauth/software_feature_manager_impl_unittest.cc
new file mode 100644
index 00000000000..2d951fa505a
--- /dev/null
+++ b/chromium/components/cryptauth/software_feature_manager_impl_unittest.cc
@@ -0,0 +1,382 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/cryptauth/software_feature_manager_impl.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "components/cryptauth/mock_cryptauth_client.h"
+#include "components/cryptauth/remote_device_ref.h"
+#include "components/cryptauth/remote_device_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Invoke;
+
+namespace cryptauth {
+
+namespace {
+
+const char kSuccessResult[] = "success";
+const char kErrorSetSoftwareFeatureState[] = "setSoftwareFeatureStateError";
+const char kErrorFindEligibleDevices[] = "findEligibleDevicesError";
+
+std::vector<cryptauth::ExternalDeviceInfo>
+CreateExternalDeviceInfosForRemoteDevices(
+ const cryptauth::RemoteDeviceRefList remote_devices) {
+ std::vector<cryptauth::ExternalDeviceInfo> device_infos;
+ for (const auto& remote_device : remote_devices) {
+ // Add an ExternalDeviceInfo with the same public key as the RemoteDevice.
+ cryptauth::ExternalDeviceInfo info;
+ info.set_public_key(remote_device.public_key());
+ device_infos.push_back(info);
+ }
+ return device_infos;
+}
+
+} // namespace
+
+class CryptAuthSoftwareFeatureManagerImplTest
+ : public testing::Test,
+ public MockCryptAuthClientFactory::Observer {
+ public:
+ CryptAuthSoftwareFeatureManagerImplTest()
+ : all_test_external_device_infos_(
+ CreateExternalDeviceInfosForRemoteDevices(
+ cryptauth::CreateRemoteDeviceRefListForTest(5))),
+ test_eligible_external_devices_infos_(
+ {all_test_external_device_infos_[0],
+ all_test_external_device_infos_[1],
+ all_test_external_device_infos_[2]}),
+ test_ineligible_external_devices_infos_(
+ {all_test_external_device_infos_[3],
+ all_test_external_device_infos_[4]}) {}
+
+ void SetUp() override {
+ mock_cryptauth_client_factory_ =
+ std::make_unique<MockCryptAuthClientFactory>(
+ MockCryptAuthClientFactory::MockType::MAKE_NICE_MOCKS);
+ mock_cryptauth_client_factory_->AddObserver(this);
+ software_feature_manager_ =
+ SoftwareFeatureManagerImpl::Factory::NewInstance(
+ mock_cryptauth_client_factory_.get());
+ }
+
+ void TearDown() override {
+ mock_cryptauth_client_factory_->RemoveObserver(this);
+ }
+
+ void OnCryptAuthClientCreated(MockCryptAuthClient* client) override {
+ ON_CALL(*client, ToggleEasyUnlock(_, _, _))
+ .WillByDefault(Invoke(
+ this,
+ &CryptAuthSoftwareFeatureManagerImplTest::MockToggleEasyUnlock));
+ ON_CALL(*client, FindEligibleUnlockDevices(_, _, _))
+ .WillByDefault(Invoke(this, &CryptAuthSoftwareFeatureManagerImplTest::
+ MockFindEligibleUnlockDevices));
+ }
+
+ // Mock CryptAuthClient::ToggleEasyUnlock() implementation.
+ void MockToggleEasyUnlock(
+ const ToggleEasyUnlockRequest& request,
+ const CryptAuthClient::ToggleEasyUnlockCallback& callback,
+ const CryptAuthClient::ErrorCallback& error_callback) {
+ last_toggle_request_ = request;
+ toggle_easy_unlock_callback_ = callback;
+ error_callback_ = error_callback;
+ error_code_ = kErrorSetSoftwareFeatureState;
+ }
+
+ // Mock CryptAuthClient::FindEligibleUnlockDevices() implementation.
+ void MockFindEligibleUnlockDevices(
+ const FindEligibleUnlockDevicesRequest& request,
+ const CryptAuthClient::FindEligibleUnlockDevicesCallback& callback,
+ const CryptAuthClient::ErrorCallback& error_callback) {
+ last_find_request_ = request;
+ find_eligible_unlock_devices_callback_ = callback;
+ error_callback_ = error_callback;
+ error_code_ = kErrorFindEligibleDevices;
+ }
+
+ FindEligibleUnlockDevicesResponse CreateFindEligibleUnlockDevicesResponse() {
+ FindEligibleUnlockDevicesResponse find_eligible_unlock_devices_response;
+ for (const auto& device_info : test_eligible_external_devices_infos_) {
+ find_eligible_unlock_devices_response.add_eligible_devices()->CopyFrom(
+ device_info);
+ }
+ for (const auto& device_info : test_ineligible_external_devices_infos_) {
+ find_eligible_unlock_devices_response.add_ineligible_devices()
+ ->mutable_device()
+ ->CopyFrom(device_info);
+ }
+ return find_eligible_unlock_devices_response;
+ }
+
+ void VerifyDeviceEligibility() {
+ // Ensure that resulting devices are not empty. Otherwise, following for
+ // loop checks will succeed on empty resulting devices.
+ EXPECT_TRUE(result_eligible_devices_.size() > 0);
+ EXPECT_TRUE(result_ineligible_devices_.size() > 0);
+ for (const auto& device_info : result_eligible_devices_) {
+ EXPECT_TRUE(
+ std::find_if(
+ test_eligible_external_devices_infos_.begin(),
+ test_eligible_external_devices_infos_.end(),
+ [&device_info](const cryptauth::ExternalDeviceInfo& device) {
+ return device.public_key() == device_info.public_key();
+ }) != test_eligible_external_devices_infos_.end());
+ }
+ for (const auto& ineligible_device : result_ineligible_devices_) {
+ EXPECT_TRUE(
+ std::find_if(test_ineligible_external_devices_infos_.begin(),
+ test_ineligible_external_devices_infos_.end(),
+ [&ineligible_device](
+ const cryptauth::ExternalDeviceInfo& device) {
+ return device.public_key() ==
+ ineligible_device.device().public_key();
+ }) != test_ineligible_external_devices_infos_.end());
+ }
+ result_eligible_devices_.clear();
+ result_ineligible_devices_.clear();
+ }
+
+ void SetSoftwareFeatureState(SoftwareFeature feature,
+ const ExternalDeviceInfo& device_info,
+ bool enabled,
+ bool is_exclusive = false) {
+ software_feature_manager_->SetSoftwareFeatureState(
+ device_info.public_key(), feature, enabled,
+ base::Bind(
+ &CryptAuthSoftwareFeatureManagerImplTest::OnSoftwareFeatureStateSet,
+ base::Unretained(this)),
+ base::Bind(&CryptAuthSoftwareFeatureManagerImplTest::OnError,
+ base::Unretained(this)),
+ is_exclusive);
+ }
+
+ void FindEligibleDevices(SoftwareFeature feature) {
+ software_feature_manager_->FindEligibleDevices(
+ feature,
+ base::Bind(
+ &CryptAuthSoftwareFeatureManagerImplTest::OnEligibleDevicesFound,
+ base::Unretained(this)),
+ base::Bind(&CryptAuthSoftwareFeatureManagerImplTest::OnError,
+ base::Unretained(this)));
+ }
+
+ void OnSoftwareFeatureStateSet() { result_ = kSuccessResult; }
+
+ void OnEligibleDevicesFound(
+ const std::vector<ExternalDeviceInfo>& eligible_devices,
+ const std::vector<IneligibleDevice>& ineligible_devices) {
+ result_ = kSuccessResult;
+ result_eligible_devices_ = eligible_devices;
+ result_ineligible_devices_ = ineligible_devices;
+ }
+
+ void OnError(const std::string& error_message) { result_ = error_message; }
+
+ void InvokeSetSoftwareFeatureCallback() {
+ CryptAuthClient::ToggleEasyUnlockCallback success_callback =
+ toggle_easy_unlock_callback_;
+ ASSERT_TRUE(!success_callback.is_null());
+ toggle_easy_unlock_callback_.Reset();
+ success_callback.Run(ToggleEasyUnlockResponse());
+ }
+
+ void InvokeFindEligibleDevicesCallback(
+ const FindEligibleUnlockDevicesResponse& retrieved_devices_response) {
+ CryptAuthClient::FindEligibleUnlockDevicesCallback success_callback =
+ find_eligible_unlock_devices_callback_;
+ ASSERT_TRUE(!success_callback.is_null());
+ find_eligible_unlock_devices_callback_.Reset();
+ success_callback.Run(retrieved_devices_response);
+ }
+
+ void InvokeErrorCallback() {
+ CryptAuthClient::ErrorCallback error_callback = error_callback_;
+ ASSERT_TRUE(!error_callback.is_null());
+ error_callback_.Reset();
+ error_callback.Run(error_code_);
+ }
+
+ std::string GetResultAndReset() {
+ std::string result;
+ result.swap(result_);
+ return result;
+ }
+
+ const std::vector<cryptauth::ExternalDeviceInfo>
+ all_test_external_device_infos_;
+ const std::vector<ExternalDeviceInfo> test_eligible_external_devices_infos_;
+ const std::vector<ExternalDeviceInfo> test_ineligible_external_devices_infos_;
+
+ std::unique_ptr<MockCryptAuthClientFactory> mock_cryptauth_client_factory_;
+ std::unique_ptr<cryptauth::SoftwareFeatureManager> software_feature_manager_;
+
+ CryptAuthClient::ErrorCallback error_callback_;
+
+ // Set when a CryptAuthClient function returns. If empty, no callback has been
+ // invoked.
+ std::string result_;
+
+ // The code passed to the error callback; varies depending on what
+ // CryptAuthClient function is invoked.
+ std::string error_code_;
+
+ // For SetSoftwareFeatureState() tests.
+ ToggleEasyUnlockRequest last_toggle_request_;
+ CryptAuthClient::ToggleEasyUnlockCallback toggle_easy_unlock_callback_;
+
+ // For FindEligibleDevices() tests.
+ FindEligibleUnlockDevicesRequest last_find_request_;
+ CryptAuthClient::FindEligibleUnlockDevicesCallback
+ find_eligible_unlock_devices_callback_;
+ std::vector<ExternalDeviceInfo> result_eligible_devices_;
+ std::vector<IneligibleDevice> result_ineligible_devices_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CryptAuthSoftwareFeatureManagerImplTest);
+};
+
+TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestOrderUponMultipleRequests) {
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
+ test_eligible_external_devices_infos_[0],
+ true /* enable */);
+ FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_CLIENT,
+ test_eligible_external_devices_infos_[1],
+ false /* enable */);
+ FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_CLIENT);
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_toggle_request_.feature());
+ EXPECT_EQ(true, last_toggle_request_.enable());
+ EXPECT_EQ(false, last_toggle_request_.is_exclusive());
+ InvokeSetSoftwareFeatureCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_find_request_.feature());
+ InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
+ last_toggle_request_.feature());
+ EXPECT_EQ(false, last_toggle_request_.enable());
+ EXPECT_EQ(false, last_toggle_request_.is_exclusive());
+ InvokeSetSoftwareFeatureCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
+ last_find_request_.feature());
+ InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+}
+
+TEST_F(CryptAuthSoftwareFeatureManagerImplTest,
+ TestMultipleSetUnlocksRequests) {
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
+ test_eligible_external_devices_infos_[0],
+ true /* enable */);
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_CLIENT,
+ test_eligible_external_devices_infos_[1],
+ false /* enable */);
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
+ test_eligible_external_devices_infos_[2],
+ true /* enable */);
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_toggle_request_.feature());
+ EXPECT_EQ(true, last_toggle_request_.enable());
+ EXPECT_EQ(false, last_toggle_request_.is_exclusive());
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
+ last_toggle_request_.feature());
+ EXPECT_EQ(false, last_toggle_request_.enable());
+ EXPECT_EQ(false, last_toggle_request_.is_exclusive());
+ InvokeSetSoftwareFeatureCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_toggle_request_.feature());
+ EXPECT_EQ(true, last_toggle_request_.enable());
+ EXPECT_EQ(false, last_toggle_request_.is_exclusive());
+ InvokeSetSoftwareFeatureCallback();
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+}
+
+TEST_F(CryptAuthSoftwareFeatureManagerImplTest,
+ TestMultipleFindEligibleForUnlockDevicesRequests) {
+ FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
+ FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_CLIENT);
+ FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_find_request_.feature());
+ InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_CLIENT,
+ last_find_request_.feature());
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorFindEligibleDevices, GetResultAndReset());
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_find_request_.feature());
+ InvokeFindEligibleDevicesCallback(CreateFindEligibleUnlockDevicesResponse());
+ EXPECT_EQ(kSuccessResult, GetResultAndReset());
+ VerifyDeviceEligibility();
+}
+
+TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestOrderViaMultipleErrors) {
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
+ test_eligible_external_devices_infos_[0],
+ true /* enable */);
+ FindEligibleDevices(SoftwareFeature::BETTER_TOGETHER_HOST);
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_toggle_request_.feature());
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_find_request_.feature());
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorFindEligibleDevices, GetResultAndReset());
+}
+
+TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestIsExclusive) {
+ SetSoftwareFeatureState(SoftwareFeature::BETTER_TOGETHER_HOST,
+ test_eligible_external_devices_infos_[0],
+ true /* enable */, true /* is_exclusive */);
+
+ EXPECT_EQ(SoftwareFeature::BETTER_TOGETHER_HOST,
+ last_toggle_request_.feature());
+ EXPECT_EQ(true, last_toggle_request_.enable());
+ EXPECT_EQ(true, last_toggle_request_.is_exclusive());
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
+}
+
+TEST_F(CryptAuthSoftwareFeatureManagerImplTest, TestEasyUnlockSpecialCase) {
+ SetSoftwareFeatureState(SoftwareFeature::EASY_UNLOCK_HOST,
+ test_eligible_external_devices_infos_[0],
+ false /* enable */);
+
+ EXPECT_EQ(SoftwareFeature::EASY_UNLOCK_HOST, last_toggle_request_.feature());
+ EXPECT_EQ(false, last_toggle_request_.enable());
+ // apply_to_all() should be false when disabling EasyUnlock host capabilities.
+ EXPECT_EQ(true, last_toggle_request_.apply_to_all());
+ InvokeErrorCallback();
+ EXPECT_EQ(kErrorSetSoftwareFeatureState, GetResultAndReset());
+}
+
+} // namespace cryptauth
diff --git a/chromium/components/cryptauth/software_feature_state.h b/chromium/components/cryptauth/software_feature_state.h
new file mode 100644
index 00000000000..bd21b37b2df
--- /dev/null
+++ b/chromium/components/cryptauth/software_feature_state.h
@@ -0,0 +1,18 @@
+// 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 COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_STATE_H_
+#define COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_STATE_H_
+
+namespace cryptauth {
+
+enum class SoftwareFeatureState {
+ kNotSupported = 0,
+ kSupported = 1,
+ kEnabled = 2
+};
+
+} // namespace cryptauth
+
+#endif // COMPONENTS_CRYPTAUTH_SOFTWARE_FEATURE_STATE_H_ \ No newline at end of file
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
index ed6203ca38f..8c11b055168 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
@@ -230,15 +230,15 @@ TEST_F(ContentLoFiDeciderTest, MaybeSetAcceptTransformNoAcceptForPreviewsOff) {
std::unique_ptr<net::URLRequest> request =
CreateRequest(true /* is main */, content::PREVIEWS_OFF);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
request = CreateRequest(true /* is main */, content::PREVIEWS_NO_TRANSFORM);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
request = CreateRequest(true /* is main */, content::PREVIEWS_UNSPECIFIED);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
}
@@ -255,12 +255,12 @@ TEST_F(ContentLoFiDeciderTest, MaybeSetAcceptTransformNoAcceptForHttps) {
std::unique_ptr<net::URLRequest> request =
CreateRequestByType(content::RESOURCE_TYPE_MAIN_FRAME, true /* https */,
both_previews_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
request = CreateRequestByType(content::RESOURCE_TYPE_IMAGE, true /* https */,
both_previews_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
}
@@ -275,11 +275,11 @@ TEST_F(ContentLoFiDeciderTest, MaybeSetAcceptTransformHeaderAcceptLitePage) {
// Verify accepting lite-page per resource type.
std::unique_ptr<net::URLRequest> request =
CreateRequest(true /* is main */, lite_page_enabled);
- VerifyAcceptTransformHeader(*request.get(), true /* lite-page */,
+ VerifyAcceptTransformHeader(*request, true /* lite-page */,
false /* empty-image */);
request = CreateRequest(false /* is main */, lite_page_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
}
@@ -294,27 +294,27 @@ TEST_F(ContentLoFiDeciderTest, MaybeSetAcceptTransformHeaderAcceptEmptyImage) {
// Verify accepting empty-image per resource type.
std::unique_ptr<net::URLRequest> request = CreateRequestByType(
content::RESOURCE_TYPE_MAIN_FRAME, false /* https */, lofi_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
request = CreateRequestByType(content::RESOURCE_TYPE_IMAGE, false /* https */,
lofi_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
true /* empty-image */);
request = CreateRequestByType(content::RESOURCE_TYPE_FAVICON,
false /* https */, lofi_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
true /* empty-image */);
request = CreateRequestByType(content::RESOURCE_TYPE_SCRIPT,
false /* https */, lofi_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
request = CreateRequestByType(content::RESOURCE_TYPE_STYLESHEET,
false /* https */, lofi_enabled);
- VerifyAcceptTransformHeader(*request.get(), false /* lite-page */,
+ VerifyAcceptTransformHeader(*request, false /* lite-page */,
false /* empty-image */);
}
@@ -466,13 +466,13 @@ TEST_F(ContentLoFiDeciderTest, ShouldRecordLoFiUMA) {
new data_reduction_proxy::ContentLoFiDecider());
std::unique_ptr<net::URLRequest> request1 = CreateRequestByType(
content::RESOURCE_TYPE_IMAGE, false, content::SERVER_LOFI_ON);
- EXPECT_TRUE(lofi_decider->ShouldRecordLoFiUMA(*request1.get()));
+ EXPECT_TRUE(lofi_decider->ShouldRecordLoFiUMA(*request1));
std::unique_ptr<net::URLRequest> request2 = CreateRequestByType(
content::RESOURCE_TYPE_MAIN_FRAME, false, content::PREVIEWS_OFF);
- EXPECT_FALSE(lofi_decider->ShouldRecordLoFiUMA(*request2.get()));
+ EXPECT_FALSE(lofi_decider->ShouldRecordLoFiUMA(*request2));
std::unique_ptr<net::URLRequest> request3 = CreateRequestByType(
content::RESOURCE_TYPE_MAIN_FRAME, false, content::SERVER_LITE_PAGE_ON);
- EXPECT_TRUE(lofi_decider->ShouldRecordLoFiUMA(*request3.get()));
+ EXPECT_TRUE(lofi_decider->ShouldRecordLoFiUMA(*request3));
}
TEST_F(ContentLoFiDeciderTest, NoTransformDoesNotAddHeader) {
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc b/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc
index 0d2990d0690..17184edb683 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider.cc
@@ -29,6 +29,8 @@ ResourceTypeProvider::ContentType GetContentTypeInternal(
content::ResourceType resource_type = request_info->GetResourceType();
if (resource_type == content::RESOURCE_TYPE_MEDIA)
return ContentResourceTypeProvider::CONTENT_TYPE_MEDIA;
+ if (resource_type == content::RESOURCE_TYPE_MAIN_FRAME)
+ return ContentResourceTypeProvider::CONTENT_TYPE_MAIN_FRAME;
return ContentResourceTypeProvider::CONTENT_TYPE_UNKNOWN;
}
diff --git a/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
index 6d8e74bb6a7..36ab5b0c750 100644
--- a/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/content_resource_type_provider_unittest.cc
@@ -160,7 +160,7 @@ TEST_F(ContentResourceProviderTest, VerifyCorrectProxyUsed) {
} tests[] = {
{GURL("http://www.google.com/main-frame"),
content::RESOURCE_TYPE_MAIN_FRAME,
- ResourceTypeProvider::CONTENT_TYPE_UNKNOWN},
+ ResourceTypeProvider::CONTENT_TYPE_MAIN_FRAME},
{GURL("http://www.google.com/sub-frame"),
content::RESOURCE_TYPE_SUB_FRAME,
ResourceTypeProvider::CONTENT_TYPE_UNKNOWN},
@@ -193,7 +193,7 @@ TEST_F(ContentResourceProviderTest, VerifyCorrectProxyUsed) {
net::MockRead(kBody.c_str()), net::MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket_data_provider);
base::HistogramTester histogram_tester;
@@ -202,10 +202,6 @@ TEST_F(ContentResourceProviderTest, VerifyCorrectProxyUsed) {
request->Start();
base::RunLoop().RunUntilIdle();
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ResourceContentType", test.expected_content_type,
- 1);
-
EXPECT_EQ(test.expected_content_type,
content_resource_type_provider()->GetContentType(request->url()));
@@ -241,7 +237,7 @@ TEST_F(ContentResourceProviderTest, SetAndGetContentResourceTypeContent) {
} tests[] = {
{GURL("http://www.google.com/main-frame"),
content::RESOURCE_TYPE_MAIN_FRAME,
- ResourceTypeProvider::CONTENT_TYPE_UNKNOWN},
+ ResourceTypeProvider::CONTENT_TYPE_MAIN_FRAME},
{GURL("http://www.google.com/sub-frame"),
content::RESOURCE_TYPE_SUB_FRAME,
ResourceTypeProvider::CONTENT_TYPE_UNKNOWN},
@@ -274,7 +270,7 @@ TEST_F(ContentResourceProviderTest, SetAndGetContentResourceTypeContent) {
net::MockRead(kBody.c_str()), net::MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket_data_provider);
base::HistogramTester histogram_tester;
@@ -283,10 +279,6 @@ TEST_F(ContentResourceProviderTest, SetAndGetContentResourceTypeContent) {
request->Start();
base::RunLoop().RunUntilIdle();
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ResourceContentType", test.expected_content_type,
- 1);
-
EXPECT_EQ(test.expected_content_type,
content_resource_type_provider()->GetContentType(request->url()));
@@ -327,7 +319,7 @@ TEST_F(ContentResourceProviderTest, FetchDirect) {
} tests[] = {
{GURL("http://www.google.com/main-frame"),
content::RESOURCE_TYPE_MAIN_FRAME,
- ResourceTypeProvider::CONTENT_TYPE_UNKNOWN},
+ ResourceTypeProvider::CONTENT_TYPE_MAIN_FRAME},
{GURL("http://www.google.com/sub-frame"),
content::RESOURCE_TYPE_SUB_FRAME,
ResourceTypeProvider::CONTENT_TYPE_UNKNOWN},
@@ -360,7 +352,7 @@ TEST_F(ContentResourceProviderTest, FetchDirect) {
net::MockRead(kBody.c_str()), net::MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket_data_provider);
base::HistogramTester histogram_tester;
@@ -369,10 +361,6 @@ TEST_F(ContentResourceProviderTest, FetchDirect) {
request->Start();
base::RunLoop().RunUntilIdle();
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ResourceContentType", test.expected_content_type,
- 1);
-
EXPECT_EQ(test.expected_content_type,
content_resource_type_provider()->GetContentType(request->url()));
diff --git a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc
index 61044ce7a27..025379c983d 100644
--- a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl.cc
@@ -106,6 +106,12 @@ void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
timing.load_event_start.value())
.release());
}
+ if (timing.first_input_delay) {
+ request->set_allocated_first_input_delay(
+ protobuf_parser::CreateDurationFromTimeDelta(
+ timing.first_input_delay.value())
+ .release());
+ }
if (timing.parse_blocked_on_script_load_duration) {
request->set_allocated_parse_blocked_on_script_load_duration(
protobuf_parser::CreateDurationFromTimeDelta(
@@ -121,8 +127,13 @@ void AddDataToPageloadMetrics(const DataReductionProxyData& request_data,
request->set_effective_connection_type(
protobuf_parser::ProtoEffectiveConnectionTypeFromEffectiveConnectionType(
request_data.effective_connection_type()));
+ request->set_connection_type(
+ protobuf_parser::ProtoConnectionTypeFromConnectionType(
+ request_data.connection_type()));
request->set_compressed_page_size_bytes(timing.network_bytes);
request->set_original_page_size_bytes(timing.original_network_bytes);
+ request->set_total_page_size_bytes(timing.total_page_size_bytes);
+ request->set_cached_fraction(timing.cached_fraction);
request->set_renderer_memory_usage_kb(timing.renderer_memory_usage_kb);
request->set_renderer_crash_type(crash_type);
@@ -326,7 +337,7 @@ void DataReductionProxyPingbackClientImpl::CreateReport(
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PageloadMetrics* pageload_metrics = metrics_request_.add_pageloads();
AddDataToPageloadMetrics(request_data, timing, crash_type, pageload_metrics);
- if (current_fetcher_.get())
+ if (current_fetcher_)
return;
DCHECK_EQ(1, metrics_request_.pageloads_size());
CreateFetcherForDataAndStart();
diff --git a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc
index 0e2f6b8fb86..7761afa8e99 100644
--- a/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc
+++ b/chromium/components/data_reduction_proxy/content/browser/data_reduction_proxy_pingback_client_impl_unittest.cc
@@ -14,6 +14,7 @@
#include "base/metrics/field_trial.h"
#include "base/optional.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/sys_info.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_task_environment.h"
@@ -27,6 +28,7 @@
#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
#include "content/public/common/child_process_host.h"
#include "net/base/net_errors.h"
+#include "net/base/network_change_notifier.h"
#include "net/nqe/effective_connection_type.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_context_getter.h"
@@ -46,6 +48,8 @@ static const char kSessionKey[] = "fake-session";
static const char kFakeURL[] = "http://www.google.com/";
static const int64_t kBytes = 10000;
static const int64_t kBytesOriginal = 1000000;
+static const int64_t kTotalPageSizeBytes = 20000;
+static const float kCachedFraction = 0.5;
static const int kCrashProcessId = 1;
static const int64_t kRendererMemory = 1024;
@@ -132,12 +136,16 @@ class DataReductionProxyPingbackClientImplTest : public testing::Test {
1900)) /* first_contentful_paint */,
base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
2000)) /* experimental_first_meaningful_paint */,
+ base::Optional<base::TimeDelta>(
+ base::TimeDelta::FromMilliseconds(3000)) /* first_input_delay */,
base::Optional<base::TimeDelta>(base::TimeDelta::FromMilliseconds(
100)) /* parse_blocked_on_script_load_duration */,
base::Optional<base::TimeDelta>(
base::TimeDelta::FromMilliseconds(2000)) /* parse_stop */,
kBytes /* network_bytes */, kBytesOriginal /* original_network_bytes */,
- app_background_occurred, opt_out_occurred, kRendererMemory,
+ kTotalPageSizeBytes /* total_page_size_bytes */,
+ kCachedFraction /* cached_fraction */, app_background_occurred,
+ opt_out_occurred, kRendererMemory,
crash ? kCrashProcessId : content::ChildProcessHost::kInvalidUniqueID);
DataReductionProxyData request_data;
@@ -145,6 +153,8 @@ class DataReductionProxyPingbackClientImplTest : public testing::Test {
request_data.set_request_url(GURL(kFakeURL));
request_data.set_effective_connection_type(
net::EFFECTIVE_CONNECTION_TYPE_OFFLINE);
+ request_data.set_connection_type(
+ net::NetworkChangeNotifier::CONNECTION_UNKNOWN);
request_data.set_lofi_received(lofi_received);
request_data.set_client_lofi_requested(client_lofi_requested);
request_data.set_lite_page_received(lite_page_received);
@@ -155,13 +165,11 @@ class DataReductionProxyPingbackClientImplTest : public testing::Test {
page_id_++;
}
- // Send a fake crash report frome breakpad.
+ // Send a fake crash report from breakpad.
void ReportCrash(bool oom) {
#if defined(OS_ANDROID)
breakpad::CrashDumpManager::CrashDumpDetails details = {
- kCrashProcessId, content::PROCESS_TYPE_RENDERER,
- oom ? base::TERMINATION_STATUS_OOM_PROTECTED
- : base::TERMINATION_STATUS_ABNORMAL_TERMINATION,
+ kCrashProcessId, content::PROCESS_TYPE_RENDERER, oom,
base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES};
details.file_size = oom ? 0 : 1;
static_cast<breakpad::CrashDumpManager::Observer*>(pingback_client_.get())
@@ -231,6 +239,9 @@ TEST_F(DataReductionProxyPingbackClientImplTest, VerifyPingbackContent) {
timing().experimental_first_meaningful_paint.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.experimental_time_to_first_meaningful_paint()));
+ EXPECT_EQ(timing().first_input_delay.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.first_input_delay()));
EXPECT_EQ(timing().parse_blocked_on_script_load_duration.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.parse_blocked_on_script_load_duration()));
@@ -241,6 +252,8 @@ TEST_F(DataReductionProxyPingbackClientImplTest, VerifyPingbackContent) {
EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
EXPECT_EQ(kBytes, pageload_metrics.compressed_page_size_bytes());
EXPECT_EQ(kBytesOriginal, pageload_metrics.original_page_size_bytes());
+ EXPECT_EQ(kTotalPageSizeBytes, pageload_metrics.total_page_size_bytes());
+ EXPECT_EQ(kCachedFraction, pageload_metrics.cached_fraction());
EXPECT_EQ(data_page_id, pageload_metrics.page_id());
EXPECT_EQ(PageloadMetrics_PreviewsType_NONE,
@@ -251,6 +264,8 @@ TEST_F(DataReductionProxyPingbackClientImplTest, VerifyPingbackContent) {
EXPECT_EQ(
PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE,
pageload_metrics.effective_connection_type());
+ EXPECT_EQ(PageloadMetrics_ConnectionType_CONNECTION_UNKNOWN,
+ pageload_metrics.connection_type());
EXPECT_EQ(kRendererMemory, pageload_metrics.renderer_memory_usage_kb());
EXPECT_EQ(std::string(), pageload_metrics.holdback_group());
EXPECT_EQ(PageloadMetrics_RendererCrashType_NO_CRASH,
@@ -360,6 +375,9 @@ TEST_F(DataReductionProxyPingbackClientImplTest,
timing().experimental_first_meaningful_paint.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.experimental_time_to_first_meaningful_paint()));
+ EXPECT_EQ(timing().first_input_delay.value(),
+ protobuf_parser::DurationToTimeDelta(
+ pageload_metrics.first_input_delay()));
EXPECT_EQ(timing().parse_blocked_on_script_load_duration.value(),
protobuf_parser::DurationToTimeDelta(
pageload_metrics.parse_blocked_on_script_load_duration()));
@@ -370,11 +388,15 @@ TEST_F(DataReductionProxyPingbackClientImplTest,
EXPECT_EQ(kFakeURL, pageload_metrics.first_request_url());
EXPECT_EQ(kBytes, pageload_metrics.compressed_page_size_bytes());
EXPECT_EQ(kBytesOriginal, pageload_metrics.original_page_size_bytes());
+ EXPECT_EQ(kTotalPageSizeBytes, pageload_metrics.total_page_size_bytes());
+ EXPECT_EQ(kCachedFraction, pageload_metrics.cached_fraction());
EXPECT_EQ(page_ids.front(), pageload_metrics.page_id());
page_ids.pop_front();
EXPECT_EQ(
PageloadMetrics_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_OFFLINE,
pageload_metrics.effective_connection_type());
+ EXPECT_EQ(PageloadMetrics_ConnectionType_CONNECTION_UNKNOWN,
+ pageload_metrics.connection_type());
EXPECT_EQ(kRendererMemory, pageload_metrics.renderer_memory_usage_kb());
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
index 5dd1eca334e..898be5c870b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/browser/BUILD.gn
@@ -2,6 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
browser_sources = [
"data_reduction_proxy_bypass_protocol.cc",
"data_reduction_proxy_bypass_protocol.h",
@@ -78,6 +82,12 @@ if (is_android) {
"//url:url",
]
}
+
+ java_cpp_enum("data_reduction_proxy_savings_cleared_enum_java") {
+ sources = [
+ "data_reduction_proxy_compression_stats.h",
+ ]
+ }
}
static_library("browser") {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
index ac307e58e61..460aceb4fb7 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.cc
@@ -8,7 +8,6 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h"
@@ -16,6 +15,8 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "net/base/load_flags.h"
#include "net/base/proxy_server.h"
#include "net/http/http_response_headers.h"
@@ -34,45 +35,38 @@ namespace data_reduction_proxy {
namespace {
-// Adds non-empty entries in |data_reduction_proxies| to the retry map
-// maintained by the proxy service of the request. Adds
-// |data_reduction_proxies.second| to the retry list only if |bypass_all| is
-// true.
-void MarkProxiesAsBadUntil(
- net::URLRequest* request,
- const base::TimeDelta& bypass_duration,
- bool bypass_all,
- const std::vector<net::ProxyServer>& data_reduction_proxies) {
- DCHECK(!data_reduction_proxies.empty());
+// Adds the Data Reduction Proxy servers in |proxy_type_info| that should be
+// marked bad according to |data_reduction_proxy_info| to the retry map
+// maintained by the proxy resolution service of the |request|.
+void MarkProxiesAsBad(const net::URLRequest& request,
+ const DataReductionProxyInfo& data_reduction_proxy_info,
+ const DataReductionProxyTypeInfo& proxy_type_info) {
+ DCHECK_GT(proxy_type_info.proxy_servers.size(), proxy_type_info.proxy_index);
+
// Synthesize a suitable |ProxyInfo| to add the proxies to the
// |ProxyRetryInfoMap| of the proxy service.
net::ProxyList proxy_list;
- std::vector<net::ProxyServer> additional_bad_proxies;
- for (const net::ProxyServer& proxy_server : data_reduction_proxies) {
- DCHECK(proxy_server.is_valid());
- proxy_list.AddProxyServer(proxy_server);
- if (!bypass_all)
- break;
- additional_bad_proxies.push_back(proxy_server);
+
+ const size_t bad_proxy_end_index = data_reduction_proxy_info.bypass_all
+ ? proxy_type_info.proxy_servers.size()
+ : proxy_type_info.proxy_index + 1U;
+
+ for (size_t i = proxy_type_info.proxy_index; i < bad_proxy_end_index; ++i) {
+ const net::ProxyServer& bad_proxy =
+ proxy_type_info.proxy_servers[i].proxy_server();
+ DCHECK(bad_proxy.is_valid());
+ DCHECK(!bad_proxy.is_direct());
+ proxy_list.AddProxyServer(bad_proxy);
}
+ std::vector<net::ProxyServer> bad_proxies = proxy_list.GetAll();
proxy_list.AddProxyServer(net::ProxyServer::Direct());
net::ProxyInfo proxy_info;
proxy_info.UseProxyList(proxy_list);
- DCHECK(request->context());
- net::ProxyResolutionService* proxy_resolution_service =
- request->context()->proxy_resolution_service();
- DCHECK(proxy_resolution_service);
- proxy_resolution_service->MarkProxiesAsBadUntil(
- proxy_info, bypass_duration, additional_bad_proxies, request->net_log());
-}
-
-void ReportResponseProxyServerStatusHistogram(
- DataReductionProxyBypassProtocol::ResponseProxyServerStatus status) {
- UMA_HISTOGRAM_ENUMERATION(
- "DataReductionProxy.ResponseProxyServerStatus", status,
- DataReductionProxyBypassProtocol::RESPONSE_PROXY_SERVER_STATUS_MAX);
+ request.context()->proxy_resolution_service()->MarkProxiesAsBadUntil(
+ proxy_info, data_reduction_proxy_info.bypass_duration, bad_proxies,
+ request.net_log());
}
} // namespace
@@ -93,29 +87,26 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(request);
- DataReductionProxyTypeInfo data_reduction_proxy_type_info;
DataReductionProxyBypassType bypass_type;
const net::HttpResponseHeaders* response_headers =
request->response_info().headers.get();
bool retry;
if (!response_headers) {
- retry = HandleInValidResponseHeadersCase(
- *request, data_reduction_proxy_info, &data_reduction_proxy_type_info,
- &bypass_type);
-
+ retry = HandleInvalidResponseHeadersCase(
+ *request, data_reduction_proxy_info, &bypass_type);
} else {
retry = HandleValidResponseHeadersCase(
- *request, proxy_bypass_type, data_reduction_proxy_info,
- &data_reduction_proxy_type_info, &bypass_type);
+ *request, proxy_bypass_type, data_reduction_proxy_info, &bypass_type);
}
if (!retry)
return false;
if (data_reduction_proxy_info->mark_proxies_as_bad) {
- MarkProxiesAsBadUntil(request, data_reduction_proxy_info->bypass_duration,
- data_reduction_proxy_info->bypass_all,
- data_reduction_proxy_type_info.proxy_servers);
+ base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
+ config_->FindConfiguredDataReductionProxy(request->proxy_server());
+ DCHECK(proxy_type_info);
+ MarkProxiesAsBad(*request, *data_reduction_proxy_info, *proxy_type_info);
} else {
request->SetLoadFlags(request->load_flags() | net::LOAD_BYPASS_CACHE |
net::LOAD_BYPASS_PROXY);
@@ -125,10 +116,9 @@ bool DataReductionProxyBypassProtocol::MaybeBypassProxyAndPrepareToRetry(
net::HttpUtil::IsMethodIdempotent(request->method());
}
-bool DataReductionProxyBypassProtocol::HandleInValidResponseHeadersCase(
+bool DataReductionProxyBypassProtocol::HandleInvalidResponseHeadersCase(
const net::URLRequest& request,
DataReductionProxyInfo* data_reduction_proxy_info,
- DataReductionProxyTypeInfo* data_reduction_proxy_type_info,
DataReductionProxyBypassType* bypass_type) const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(nullptr, request.response_info().headers.get());
@@ -140,10 +130,8 @@ bool DataReductionProxyBypassProtocol::HandleInValidResponseHeadersCase(
return false;
}
- if (!config_->WasDataReductionProxyUsed(&request,
- data_reduction_proxy_type_info)) {
+ if (!config_->FindConfiguredDataReductionProxy(request.proxy_server()))
return false;
- }
DCHECK(request.url().SchemeIs(url::kHttpScheme));
@@ -187,7 +175,6 @@ bool DataReductionProxyBypassProtocol::HandleValidResponseHeadersCase(
const net::URLRequest& request,
DataReductionProxyBypassType* proxy_bypass_type,
DataReductionProxyInfo* data_reduction_proxy_info,
- DataReductionProxyTypeInfo* data_reduction_proxy_type_info,
DataReductionProxyBypassType* bypass_type) const {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -197,51 +184,19 @@ bool DataReductionProxyBypassProtocol::HandleValidResponseHeadersCase(
request.response_info().headers.get();
DCHECK(response_headers);
- if (!request.proxy_server().is_valid() ||
- request.proxy_server().is_direct() ||
- request.proxy_server().host_port_pair().IsEmpty()) {
- ReportResponseProxyServerStatusHistogram(
- RESPONSE_PROXY_SERVER_STATUS_EMPTY);
- return false;
- }
- if (!config_->WasDataReductionProxyUsed(&request,
- data_reduction_proxy_type_info)) {
- if (!HasDataReductionProxyViaHeader(*response_headers, nullptr)) {
- ReportResponseProxyServerStatusHistogram(
- RESPONSE_PROXY_SERVER_STATUS_NON_DRP_NO_VIA);
- return false;
- }
- ReportResponseProxyServerStatusHistogram(
- RESPONSE_PROXY_SERVER_STATUS_NON_DRP_WITH_VIA);
-
- // If the |proxy_server| doesn't match any of the currently configured
- // Data Reduction Proxies, but it still has the Data Reduction Proxy via
- // header, then apply the bypass logic regardless.
- // TODO(sclittle): Remove this workaround once http://crbug.com/476610 is
- // fixed.
- const net::HostPortPair host_port_pair =
- !request.proxy_server().is_valid() || request.proxy_server().is_direct()
- ? net::HostPortPair()
- : request.proxy_server().host_port_pair();
- data_reduction_proxy_type_info->proxy_servers.push_back(
- net::ProxyServer(net::ProxyServer::SCHEME_HTTPS, host_port_pair));
- data_reduction_proxy_type_info->proxy_servers.push_back(
- net::ProxyServer(net::ProxyServer::SCHEME_HTTP, host_port_pair));
- data_reduction_proxy_type_info->proxy_index = 0;
- } else {
- ReportResponseProxyServerStatusHistogram(RESPONSE_PROXY_SERVER_STATUS_DRP);
- }
- if (data_reduction_proxy_type_info->proxy_servers.empty())
+ base::Optional<DataReductionProxyTypeInfo> data_reduction_proxy_type_info =
+ config_->FindConfiguredDataReductionProxy(request.proxy_server());
+ if (!data_reduction_proxy_type_info)
return false;
// At this point, the response is expected to have the data reduction proxy
// via header, so detect and report cases where the via header is missing.
DataReductionProxyBypassStats::DetectAndRecordMissingViaHeaderResponseCode(
- data_reduction_proxy_type_info->proxy_index == 0, *response_headers);
+ data_reduction_proxy_type_info->proxy_index == 0U, *response_headers);
// GetDataReductionProxyBypassType will only log a net_log event if a bypass
- // command was sent via the data reduction proxy headers
+ // command was sent via the data reduction proxy headers.
*bypass_type = GetDataReductionProxyBypassType(
request.url_chain(), *response_headers, data_reduction_proxy_info);
@@ -252,15 +207,20 @@ bool DataReductionProxyBypassProtocol::HandleValidResponseHeadersCase(
DCHECK(request.context());
DCHECK(request.context()->proxy_resolution_service());
- net::ProxyServer proxy_server =
- data_reduction_proxy_type_info->proxy_servers.front();
+ DCHECK_GT(data_reduction_proxy_type_info->proxy_servers.size(),
+ data_reduction_proxy_type_info->proxy_index);
+
+ const net::ProxyServer& proxy_server =
+ data_reduction_proxy_type_info
+ ->proxy_servers[data_reduction_proxy_type_info->proxy_index]
+ .proxy_server();
// Only record UMA if the proxy isn't already on the retry list.
if (!config_->IsProxyBypassed(
- request.context()->proxy_resolution_service()->proxy_retry_info(), proxy_server,
- nullptr)) {
+ request.context()->proxy_resolution_service()->proxy_retry_info(),
+ proxy_server, nullptr)) {
DataReductionProxyBypassStats::RecordDataReductionProxyBypassInfo(
- data_reduction_proxy_type_info->proxy_index == 0,
+ data_reduction_proxy_type_info->proxy_index == 0U,
data_reduction_proxy_info->bypass_all, proxy_server, *bypass_type);
}
return true;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h
index 40aaf09e5a2..af3bd0b0bff 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol.h
@@ -16,25 +16,12 @@ class URLRequest;
namespace data_reduction_proxy {
class DataReductionProxyConfig;
-struct DataReductionProxyTypeInfo;
// Class responsible for determining when a response should or should not cause
// the data reduction proxy to be bypassed, and to what degree. Owned by the
// DataReductionProxyInterceptor.
class DataReductionProxyBypassProtocol {
public:
- // Enum values that can be reported for the
- // DataReductionProxy.ResponseProxyServerStatus histogram. These values must
- // be kept in sync with their counterparts in histograms.xml. Visible here for
- // testing purposes.
- enum ResponseProxyServerStatus {
- RESPONSE_PROXY_SERVER_STATUS_EMPTY = 0,
- RESPONSE_PROXY_SERVER_STATUS_DRP,
- RESPONSE_PROXY_SERVER_STATUS_NON_DRP_NO_VIA,
- RESPONSE_PROXY_SERVER_STATUS_NON_DRP_WITH_VIA,
- RESPONSE_PROXY_SERVER_STATUS_MAX
- };
-
// Constructs a DataReductionProxyBypassProtocol object. |config| must be
// non-NULL and outlive |this|.
DataReductionProxyBypassProtocol(DataReductionProxyConfig* config);
@@ -57,10 +44,9 @@ class DataReductionProxyBypassProtocol {
// put it on the proxy retry map. Returns true if the request should be
// retried. Should be called only when the response of the |request| had null
// response headers.
- bool HandleInValidResponseHeadersCase(
+ bool HandleInvalidResponseHeadersCase(
const net::URLRequest& request,
DataReductionProxyInfo* data_reduction_proxy_info,
- DataReductionProxyTypeInfo* data_reduction_proxy_type_info,
DataReductionProxyBypassType* bypass_type) const;
// Decides whether to mark the data reduction proxy as temporarily bad and
@@ -71,7 +57,6 @@ class DataReductionProxyBypassProtocol {
const net::URLRequest& request,
DataReductionProxyBypassType* proxy_bypass_type,
DataReductionProxyInfo* data_reduction_proxy_info,
- DataReductionProxyTypeInfo* data_reduction_proxy_type_info,
DataReductionProxyBypassType* bypass_type) const;
// Must outlive |this|.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
index 2df31e2bc24..04b5c042a48 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_protocol_unittest.cc
@@ -346,11 +346,8 @@ class DataReductionProxyProtocolTest : public testing::Test {
MockRead(net::SYNCHRONOUS, net_error_code),
};
- StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
- StaticSocketDataProvider data1_error(data_reads_error,
- arraysize(data_reads_error),
- data_writes, arraysize(data_writes));
+ StaticSocketDataProvider data1(data_reads, data_writes);
+ StaticSocketDataProvider data1_error(data_reads_error, data_writes);
if (!generate_response_error)
mock_socket_factory_.AddSocketDataProvider(&data1);
else
@@ -358,8 +355,8 @@ class DataReductionProxyProtocolTest : public testing::Test {
std::string response2;
std::string request2;
- std::string response2_via_header = "";
- std::string request2_connection_type = "";
+ std::string response2_via_header;
+ std::string request2_connection_type;
std::string request2_path = "/";
if (expected_bad_proxy_count == 1) {
@@ -403,8 +400,7 @@ class DataReductionProxyProtocolTest : public testing::Test {
MockRead(net::SYNCHRONOUS, net::OK),
};
- StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
- data_writes2, arraysize(data_writes2));
+ StaticSocketDataProvider data2(data_reads2, data_writes2);
if (expected_retry) {
mock_socket_factory_.AddSocketDataProvider(&data2);
}
@@ -1053,194 +1049,6 @@ TEST_F(DataReductionProxyProtocolTest, BypassLogic) {
}
}
-class DataReductionProxyBypassProtocolEndToEndTest : public testing::Test {
- public:
- DataReductionProxyBypassProtocolEndToEndTest() {}
-
- void ResetDependencies() {
- context_.reset(new net::TestURLRequestContext(true));
- storage_.reset(new net::URLRequestContextStorage(context_.get()));
- mock_socket_factory_.reset(new net::MockClientSocketFactory());
- context_->set_client_socket_factory(mock_socket_factory_.get());
- drp_test_context_ =
- DataReductionProxyTestContext::Builder()
- .WithMockClientSocketFactory(mock_socket_factory_.get())
- .WithURLRequestContext(context_.get())
- .Build();
- proxy_delegate_ = drp_test_context_->io_data()->CreateProxyDelegate();
- context_->set_proxy_delegate(proxy_delegate_.get());
- }
-
- void AttachToContextAndInit() {
- drp_test_context_->AttachToURLRequestContext(storage_.get());
- context_->Init();
- }
-
- net::TestURLRequestContext* context() { return context_.get(); }
- net::URLRequestContextStorage* storage() { return storage_.get(); }
- net::MockClientSocketFactory* mock_socket_factory() {
- return mock_socket_factory_.get();
- }
- DataReductionProxyTestContext* drp_test_context() {
- return drp_test_context_.get();
- }
-
- private:
- base::MessageLoopForIO loop_;
- std::unique_ptr<net::TestURLRequestContext> context_;
- std::unique_ptr<net::URLRequestContextStorage> storage_;
- std::unique_ptr<net::MockClientSocketFactory> mock_socket_factory_;
- std::unique_ptr<net::ProxyDelegate> proxy_delegate_;
- std::unique_ptr<DataReductionProxyTestContext> drp_test_context_;
-
- DISALLOW_COPY_AND_ASSIGN(DataReductionProxyBypassProtocolEndToEndTest);
-};
-
-TEST_F(DataReductionProxyBypassProtocolEndToEndTest,
- BypassLogicAlwaysAppliesWhenViaHeaderPresent) {
- const struct {
- const char* first_response;
- bool expected_retry;
- bool expected_bad_proxy;
- DataReductionProxyBypassType expected_bypass_type;
- } test_cases[] = {
- {"HTTP/1.1 200 OK\r\n"
- "Server: proxy\r\n"
- "Chrome-Proxy: block=0\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
- true,
- true,
- BYPASS_EVENT_TYPE_MEDIUM},
- {"HTTP/1.1 200 OK\r\n"
- "Server: proxy\r\n"
- "Chrome-Proxy: bypass=0\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
- true,
- true,
- BYPASS_EVENT_TYPE_MEDIUM},
- {"HTTP/1.1 502 Bad Gateway\r\n"
- "Server: proxy\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
- true,
- true,
- BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY},
- {"HTTP/1.1 200 OK\r\n"
- "Server: proxy\r\n"
- "Chrome-Proxy: block=0\r\n\r\n",
- false,
- false,
- BYPASS_EVENT_TYPE_MAX},
- {"HTTP/1.1 502 Bad Gateway\r\n"
- "Server: proxy\r\n\r\n",
- false,
- false,
- BYPASS_EVENT_TYPE_MAX},
- };
-
- for (const auto& test : test_cases) {
- const std::string kPrimary = "https://unrecognized-drp.net:443";
-
- ResetDependencies();
- storage()->set_proxy_resolution_service(ProxyResolutionService::CreateFixed(
- kPrimary + ",direct://", TRAFFIC_ANNOTATION_FOR_TESTS));
- AttachToContextAndInit();
-
- // The proxy is an HTTPS proxy, so set up the fake SSL socket data.
- net::SSLSocketDataProvider ssl_socket(net::ASYNC, net::OK);
- mock_socket_factory()->AddSSLSocketDataProvider(&ssl_socket);
-
- MockRead first_reads[] = {MockRead(test.first_response),
- MockRead(""),
- MockRead(net::SYNCHRONOUS, net::OK)};
- net::StaticSocketDataProvider first_socket(
- first_reads, arraysize(first_reads), nullptr, 0);
- mock_socket_factory()->AddSocketDataProvider(&first_socket);
-
- MockRead retry_reads[] = {MockRead("HTTP/1.1 200 OK\n\r\n\r"),
- MockRead(""),
- MockRead(net::SYNCHRONOUS, net::OK)};
- net::StaticSocketDataProvider retry_socket(
- retry_reads, arraysize(retry_reads), nullptr, 0);
- if (test.expected_retry)
- mock_socket_factory()->AddSocketDataProvider(&retry_socket);
-
- net::TestDelegate delegate;
- std::unique_ptr<net::URLRequest> url_request(
- context()->CreateRequest(GURL("http://www.google.com"), net::IDLE,
- &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
- url_request->Start();
- drp_test_context()->RunUntilIdle();
-
- EXPECT_EQ(test.expected_bypass_type,
- drp_test_context()->io_data()->bypass_stats()->GetBypassType());
- // Check the bad proxy list.
- EXPECT_EQ(test.expected_bad_proxy, base::ContainsKey(
- context()->proxy_resolution_service()->proxy_retry_info(),
- kPrimary));
- }
-}
-
-TEST_F(DataReductionProxyBypassProtocolEndToEndTest,
- ResponseProxyServerStateHistogram) {
- const struct {
- const char* proxy_rules;
- bool enable_data_reduction_proxy;
- const char* response_headers;
- // |RESPONSE_PROXY_SERVER_STATUS_MAX| indicates no expected value.
- DataReductionProxyBypassProtocol::ResponseProxyServerStatus expected_status;
- } test_cases[] = {
- {"direct://",
- false,
- "HTTP/1.1 200 OK\r\n\r\n",
- DataReductionProxyBypassProtocol::RESPONSE_PROXY_SERVER_STATUS_EMPTY},
- {"direct://",
- true,
- "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n",
- DataReductionProxyBypassProtocol::RESPONSE_PROXY_SERVER_STATUS_DRP},
- {"unrecognized-drp.net",
- false,
- "HTTP/1.1 200 OK\r\n\r\n",
- DataReductionProxyBypassProtocol::
- RESPONSE_PROXY_SERVER_STATUS_NON_DRP_NO_VIA},
- {"unrecognized-drp.net",
- false,
- "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n",
- DataReductionProxyBypassProtocol::
- RESPONSE_PROXY_SERVER_STATUS_NON_DRP_WITH_VIA},
- };
-
- for (const auto& test : test_cases) {
- ResetDependencies();
- storage()->set_proxy_resolution_service(
- net::ProxyResolutionService::CreateFixed(test.proxy_rules,
- TRAFFIC_ANNOTATION_FOR_TESTS));
- AttachToContextAndInit();
- if (test.enable_data_reduction_proxy) {
- drp_test_context()->DisableWarmupURLFetch();
- drp_test_context()->EnableDataReductionProxyWithSecureProxyCheckSuccess();
- }
- drp_test_context()->config()->test_params()->UseNonSecureProxiesForHttp();
-
- MockRead reads[] = {MockRead(test.response_headers),
- MockRead(""),
- MockRead(net::SYNCHRONOUS, net::OK)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
- mock_socket_factory()->AddSocketDataProvider(&socket);
-
- base::HistogramTester histogram_tester;
- net::TestDelegate delegate;
- std::unique_ptr<net::URLRequest> request(
- context()->CreateRequest(GURL("http://google.com"), net::IDLE,
- &delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
- request->Start();
- drp_test_context()->RunUntilIdle();
-
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ResponseProxyServerStatus", test.expected_status,
- 1);
- }
-}
-
TEST_F(DataReductionProxyProtocolTest,
ProxyBypassIgnoredOnDirectConnection) {
// Verify that a Chrome-Proxy header is ignored when returned from a directly
@@ -1263,8 +1071,7 @@ TEST_F(DataReductionProxyProtocolTest,
"User-Agent:\r\n"
"Accept-Encoding: gzip, deflate\r\n\r\n"),
};
- StaticSocketDataProvider data1(data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
+ StaticSocketDataProvider data1(data_reads, data_writes);
mock_socket_factory_.AddSocketDataProvider(&data1);
TestDelegate d;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
index 39c311ae9bd..1c47b73da76 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
@@ -11,6 +11,7 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/proxy_server.h"
@@ -119,14 +120,16 @@ void DataReductionProxyBypassStats::OnUrlRequestCompleted(
bool started,
int net_error) {
DCHECK(thread_checker_.CalledOnValidThread());
- DataReductionProxyTypeInfo proxy_info;
+
+ base::Optional<DataReductionProxyTypeInfo> proxy_info =
+ data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
+ request->proxy_server());
+
// Ignore requests that did not use the data reduction proxy. The check for
// LOAD_BYPASS_PROXY is necessary because the proxy_server() in the |request|
// might still be set to the data reduction proxy if |request| was retried
// over direct and a network error occurred while retrying it.
- if (!data_reduction_proxy_config_->WasDataReductionProxyUsed(request,
- &proxy_info) ||
- (request->load_flags() & net::LOAD_BYPASS_PROXY) != 0 ||
+ if (!proxy_info || (request->load_flags() & net::LOAD_BYPASS_PROXY) != 0 ||
net_error != net::OK) {
return;
}
@@ -136,15 +139,11 @@ void DataReductionProxyBypassStats::OnUrlRequestCompleted(
// Report the success counts.
UMA_HISTOGRAM_COUNTS_100(
"DataReductionProxy.SuccessfulRequestCompletionCounts",
- proxy_info.proxy_index);
-
- DCHECK(request->proxy_server().host_port_pair().Equals(
- proxy_info.proxy_servers.front().host_port_pair()));
+ proxy_info->proxy_index);
// It is possible that the scheme of request->proxy_server() is different
// from the scheme of proxy_info.proxy_servers.front(). The former may be set
// to QUIC by the network stack, while the latter may be set to HTTPS.
-
UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.ProxySchemeUsed",
util::ConvertNetProxySchemeToProxyScheme(
request->proxy_server().scheme()),
@@ -152,8 +151,8 @@ void DataReductionProxyBypassStats::OnUrlRequestCompleted(
if (request->load_flags() & net::LOAD_MAIN_FRAME_DEPRECATED) {
UMA_HISTOGRAM_COUNTS_100(
"DataReductionProxy.SuccessfulRequestCompletionCounts.MainFrame",
- proxy_info.proxy_index);
- }
+ proxy_info->proxy_index);
+ }
}
void DataReductionProxyBypassStats::SetBypassType(
@@ -169,49 +168,37 @@ DataReductionProxyBypassStats::GetBypassType() const {
return last_bypass_type_;
}
-void DataReductionProxyBypassStats::RecordBytesHistograms(
- const net::URLRequest& request,
- bool data_reduction_proxy_enabled,
- const net::ProxyConfig& data_reduction_proxy_config) {
- DCHECK(thread_checker_.CalledOnValidThread());
- RecordBypassedBytesHistograms(request, data_reduction_proxy_enabled,
- data_reduction_proxy_config);
- RecordMissingViaHeaderBytes(request);
-}
-
void DataReductionProxyBypassStats::OnProxyFallback(
const net::ProxyServer& bypassed_proxy,
int net_error) {
DCHECK(thread_checker_.CalledOnValidThread());
- DataReductionProxyTypeInfo data_reduction_proxy_info;
- if (bypassed_proxy.is_valid() && !bypassed_proxy.is_direct() &&
- data_reduction_proxy_config_->IsDataReductionProxy(
- bypassed_proxy, &data_reduction_proxy_info)) {
- proxy_net_errors_count_++;
-
- // To account for the case when the proxy is reachable for sometime, and
- // then gets blocked, we reset counts when number of errors exceed
- // the threshold.
- if (proxy_net_errors_count_ >= kMaxFailedRequestsBeforeReset &&
- successful_requests_through_proxy_count_ >
- kMaxSuccessfulRequestsWhenUnavailable) {
- ClearRequestCounts();
- } else {
- NotifyUnavailabilityIfChanged();
- }
+ if (!bypassed_proxy.is_valid() || bypassed_proxy.is_direct())
+ return;
- if (data_reduction_proxy_info.proxy_index == 0) {
- RecordDataReductionProxyBypassInfo(
- true, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
- RecordDataReductionProxyBypassOnNetworkError(
- true, bypassed_proxy, net_error);
- } else {
- RecordDataReductionProxyBypassInfo(
- false, false, bypassed_proxy, BYPASS_EVENT_TYPE_NETWORK_ERROR);
- RecordDataReductionProxyBypassOnNetworkError(
- false, bypassed_proxy, net_error);
- }
+ base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
+ data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
+ bypassed_proxy);
+ if (!proxy_type_info)
+ return;
+
+ proxy_net_errors_count_++;
+
+ // To account for the case when the proxy is reachable for sometime, and
+ // then gets blocked, we reset counts when number of errors exceed
+ // the threshold.
+ if (proxy_net_errors_count_ >= kMaxFailedRequestsBeforeReset &&
+ successful_requests_through_proxy_count_ >
+ kMaxSuccessfulRequestsWhenUnavailable) {
+ ClearRequestCounts();
+ } else {
+ NotifyUnavailabilityIfChanged();
}
+
+ const bool is_first_proxy = proxy_type_info->proxy_index == 0U;
+ RecordDataReductionProxyBypassInfo(is_first_proxy, false, bypassed_proxy,
+ BYPASS_EVENT_TYPE_NETWORK_ERROR);
+ RecordDataReductionProxyBypassOnNetworkError(is_first_proxy, bypassed_proxy,
+ net_error);
}
void DataReductionProxyBypassStats::ClearRequestCounts() {
@@ -247,9 +234,8 @@ void DataReductionProxyBypassStats::RecordBypassedBytesHistograms(
if (!request.url().SchemeIsHTTPOrHTTPS())
return;
- DataReductionProxyTypeInfo data_reduction_proxy_type_info;
- if (data_reduction_proxy_config_->WasDataReductionProxyUsed(
- &request, &data_reduction_proxy_type_info)) {
+ if (data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
+ request.proxy_server())) {
RecordBypassedBytes(last_bypass_type_,
DataReductionProxyBypassStats::NOT_BYPASSED,
content_length);
@@ -266,7 +252,6 @@ void DataReductionProxyBypassStats::RecordBypassedBytesHistograms(
// Now that the data reduction proxy is a best effort proxy, if the effective
// proxy configuration resolves to anything other than direct:// for a URL,
// the data reduction proxy will not be used.
- DCHECK(data_reduction_proxy_type_info.proxy_servers.empty());
if (!request.proxy_server().is_valid() ||
!request.proxy_server().is_direct()) {
RecordBypassedBytes(last_bypass_type_,
@@ -337,32 +322,6 @@ void DataReductionProxyBypassStats::RecordBypassedBytesHistograms(
}
}
-void DataReductionProxyBypassStats::RecordMissingViaHeaderBytes(
- const net::URLRequest& request) {
- DCHECK(thread_checker_.CalledOnValidThread());
- // Responses that were served from cache should have been filtered out
- // already.
- DCHECK(!request.was_cached());
-
- if (!data_reduction_proxy_config_->WasDataReductionProxyUsed(&request,
- nullptr) ||
- HasDataReductionProxyViaHeader(*request.response_headers(), nullptr)) {
- // Only track requests that used the data reduction proxy and had responses
- // that were missing the data reduction proxy via header.
- return;
- }
-
- if (request.GetResponseCode() >= net::HTTP_BAD_REQUEST &&
- request.GetResponseCode() < net::HTTP_INTERNAL_SERVER_ERROR) {
- // Track 4xx responses that are missing via headers separately.
- UMA_HISTOGRAM_COUNTS("DataReductionProxy.MissingViaHeader.Bytes.4xx",
- request.received_response_content_length());
- } else {
- UMA_HISTOGRAM_COUNTS("DataReductionProxy.MissingViaHeader.Bytes.Other",
- request.received_response_content_length());
- }
-}
-
void DataReductionProxyBypassStats::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
index 222e2246172..4d2d383ea72 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h
@@ -73,9 +73,11 @@ class DataReductionProxyBypassStats
// Visible for testing.
DataReductionProxyBypassType GetBypassType() const;
- // Records all the data reduction proxy bytes-related histograms for the
- // completed URLRequest |request|.
- void RecordBytesHistograms(
+ // Given |data_reduction_proxy_enabled|, a |request|, and the
+ // |data_reduction_proxy_config| records the number of bypassed bytes for that
+ // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
+ // tells us the state of the Data Reduction Proxy enabling preference.
+ void RecordBypassedBytesHistograms(
const net::URLRequest& request,
bool data_reduction_proxy_enabled,
const net::ProxyConfig& data_reduction_proxy_config);
@@ -95,8 +97,6 @@ class DataReductionProxyBypassStats
private:
friend class DataReductionProxyBypassStatsTest;
- FRIEND_TEST_ALL_PREFIXES(DataReductionProxyBypassStatsTest,
- RecordMissingViaHeaderBytes);
enum BypassedBytesType {
NOT_BYPASSED = 0, /* Not bypassed. */
@@ -110,20 +110,6 @@ class DataReductionProxyBypassStats
BYPASSED_BYTES_TYPE_MAX /* This must always be last.*/
};
- // Given |data_reduction_proxy_enabled|, a |request|, and the
- // |data_reduction_proxy_config| records the number of bypassed bytes for that
- // |request| into UMAs based on bypass type. |data_reduction_proxy_enabled|
- // tells us the state of the Data Reduction Proxy enabling preference.
- void RecordBypassedBytesHistograms(
- const net::URLRequest& request,
- bool data_reduction_proxy_enabled,
- const net::ProxyConfig& data_reduction_proxy_config);
-
- // Records UMA of the number of response bytes of responses that are expected
- // to have the data reduction proxy via header, but where the data reduction
- // proxy via header is not present.
- void RecordMissingViaHeaderBytes(const net::URLRequest& request);
-
// NetworkChangeNotifier::NetworkChangeObserver:
void OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) override;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
index 3987634b72c..338c3a873ba 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -40,6 +40,7 @@
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
+#include "net/log/test_net_log.h"
#include "net/socket/socket_test_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/url_request.h"
@@ -129,122 +130,6 @@ class DataReductionProxyBypassStatsTest : public testing::Test {
};
-TEST_F(DataReductionProxyBypassStatsTest, RecordMissingViaHeaderBytes) {
- const std::string k4xxHistogramName =
- "DataReductionProxy.MissingViaHeader.Bytes.4xx";
- const std::string kOtherHistogramName =
- "DataReductionProxy.MissingViaHeader.Bytes.Other";
- const int64_t kResponseContentLength = 100;
-
- struct TestCase {
- bool was_proxy_used;
- const char* headers;
- bool is_4xx_sample_expected;
- bool is_other_sample_expected;
- };
- const TestCase test_cases[] = {
- // Nothing should be recorded for requests that don't use the proxy.
- {
- false,
- "HTTP/1.1 404 Not Found\n",
- false,
- false
- },
- {
- false,
- "HTTP/1.1 200 OK\n",
- false,
- false
- },
- // Nothing should be recorded for responses that have the via header.
- {
- true,
- "HTTP/1.1 404 Not Found\n"
- "Via: 1.1 Chrome-Compression-Proxy\n",
- false,
- false
- },
- {
- true,
- "HTTP/1.1 200 OK\n"
- "Via: 1.1 Chrome-Compression-Proxy\n",
- false,
- false
- },
- // 4xx responses that used the proxy and don't have the via header should be
- // recorded.
- {
- true,
- "HTTP/1.1 404 Not Found\n",
- true,
- false
- },
- {
- true,
- "HTTP/1.1 400 Bad Request\n",
- true,
- false
- },
- {
- true,
- "HTTP/1.1 499 Big Client Error Response Code\n",
- true,
- false
- },
- // Non-4xx responses that used the proxy and don't have the via header
- // should be recorded.
- {
- true,
- "HTTP/1.1 200 OK\n",
- false,
- true
- },
- {
- true,
- "HTTP/1.1 399 Big Redirection Response Code\n",
- false,
- true
- },
- {
- true,
- "HTTP/1.1 500 Internal Server Error\n",
- false,
- true
- }
- };
-
- for (size_t i = 0; i < arraysize(test_cases); ++i) {
- base::HistogramTester histogram_tester;
- std::unique_ptr<DataReductionProxyBypassStats> bypass_stats =
- BuildBypassStats();
-
- std::unique_ptr<net::URLRequest> fake_request(
- CreateURLRequestWithResponseHeaders(GURL("http://www.google.com/"),
- test_cases[i].headers));
- fake_request->set_received_response_content_length(kResponseContentLength);
-
- EXPECT_CALL(*config(),
- WasDataReductionProxyUsed(fake_request.get(), testing::_))
- .WillRepeatedly(Return(test_cases[i].was_proxy_used));
-
- bypass_stats->RecordMissingViaHeaderBytes(*fake_request);
-
- if (test_cases[i].is_4xx_sample_expected) {
- histogram_tester.ExpectUniqueSample(k4xxHistogramName,
- kResponseContentLength, 1);
- } else {
- histogram_tester.ExpectTotalCount(k4xxHistogramName, 0);
- }
-
- if (test_cases[i].is_other_sample_expected) {
- histogram_tester.ExpectUniqueSample(kOtherHistogramName,
- kResponseContentLength, 1);
- } else {
- histogram_tester.ExpectTotalCount(kOtherHistogramName, 0);
- }
- }
-}
-
// End-to-end tests for the DataReductionProxy.BypassedBytes histograms.
class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
public:
@@ -309,7 +194,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
MockRead(net::SYNCHRONOUS, finish_code),
};
net::StaticSocketDataProvider initial_socket_data_provider(
- initial_data_reads, arraysize(initial_data_reads), nullptr, 0);
+ initial_data_reads, base::span<net::MockWrite>());
mock_socket_factory_.AddSocketDataProvider(&initial_socket_data_provider);
// Prepare for the response from retrying the request, if applicable.
@@ -323,7 +208,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
retry_data_reads.push_back(MockRead(net::SYNCHRONOUS, finish_code));
retry_socket_data_provider.reset(new net::StaticSocketDataProvider(
- &retry_data_reads.front(), retry_data_reads.size(), nullptr, 0));
+ retry_data_reads, base::span<net::MockWrite>()));
mock_socket_factory_.AddSocketDataProvider(
retry_socket_data_provider.get());
}
@@ -347,7 +232,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_1(
- redirect_mock_reads_1, arraysize(redirect_mock_reads_1), nullptr, 0);
+ redirect_mock_reads_1, base::span<net::MockWrite>());
mock_socket_factory_.AddSocketDataProvider(
&redirect_socket_data_provider_1);
@@ -359,7 +244,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_2(
- redirect_mock_reads_2, arraysize(redirect_mock_reads_2), nullptr, 0);
+ redirect_mock_reads_2, base::span<net::MockWrite>());
mock_socket_factory_.AddSocketDataProvider(
&redirect_socket_data_provider_2);
@@ -372,7 +257,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_3(
- redirect_mock_reads_3, arraysize(redirect_mock_reads_3), nullptr, 0);
+ redirect_mock_reads_3, base::span<net::MockWrite>());
mock_socket_factory_.AddSocketDataProvider(
&redirect_socket_data_provider_3);
@@ -383,7 +268,7 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider response_socket_data_provider(
- response_mock_reads, arraysize(response_mock_reads), nullptr, 0);
+ response_mock_reads, base::span<net::MockWrite>());
mock_socket_factory_.AddSocketDataProvider(&response_socket_data_provider);
std::unique_ptr<net::URLRequest> request(
@@ -491,38 +376,6 @@ class DataReductionProxyBypassStatsEndToEndTest : public testing::Test {
net::TestDelegate* delegate() { return &delegate_; }
- // Marks a data reduction proxy as bypassed if
- // |bypassed_proxy_server_is_data_reduction_proxy| is true. Then, runs a
- // request via data reduction proxy if |is_data_reduction_proxy| is true,
- // and verifies that proxy is unreachable only if |is_unreachable| is true.
- void VerifyProxyReachablity(
- bool bypassed_proxy_server_is_data_reduction_proxy,
- bool is_data_reduction_proxy,
- bool is_unreachable) {
- InitializeContext();
-
- std::string proxy = bypassed_proxy_server_is_data_reduction_proxy
- ? "origin.net:80"
- : "foo.net:80";
- net::ProxyServer fallback_proxy_server =
- net::ProxyServer::FromURI(proxy, net::ProxyServer::SCHEME_HTTP);
-
- bypass_stats()->OnProxyFallback(fallback_proxy_server,
- net::ERR_PROXY_CONNECTION_FAILED);
- drp_test_context()->RunUntilIdle();
-
- if (!is_data_reduction_proxy)
- config()->SetWasDataReductionProxyNotUsed();
-
- CreateAndExecuteRequest(GURL("http://bar.com"), net::LOAD_NORMAL, net::OK,
- "HTTP/1.1 200 OK\r\n"
- "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
- kNextBody.c_str(), nullptr, nullptr);
-
- drp_test_context()->RunUntilIdle();
- EXPECT_EQ(is_unreachable, IsUnreachable());
- }
-
private:
base::MessageLoopForIO message_loop_;
net::TestDelegate delegate_;
@@ -862,26 +715,6 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
}
TEST_F(DataReductionProxyBypassStatsEndToEndTest,
- IsDataReductionProxyUnreachable_Unreachable) {
- VerifyProxyReachablity(true, false, true);
-}
-
-TEST_F(DataReductionProxyBypassStatsEndToEndTest,
- IsDataReductionProxyUnreachable_Unreachable_Then_Reachable) {
- VerifyProxyReachablity(true, true, false);
-}
-
-TEST_F(DataReductionProxyBypassStatsEndToEndTest,
- IsDataReductionProxyUnreachable_Not_A_data_reduction_proxy_1) {
- VerifyProxyReachablity(false, true, false);
-}
-
-TEST_F(DataReductionProxyBypassStatsEndToEndTest,
- IsDataReductionProxyUnreachableNot_A_data_reduction_proxy_2) {
- VerifyProxyReachablity(false, false, false);
-}
-
-TEST_F(DataReductionProxyBypassStatsEndToEndTest,
ProxyUnreachableThenReachable) {
net::ProxyServer fallback_proxy_server =
net::ProxyServer::FromURI("origin.net:80", net::ProxyServer::SCHEME_HTTP);
@@ -983,72 +816,124 @@ TEST_F(DataReductionProxyBypassStatsEndToEndTest,
}
}
-TEST_F(DataReductionProxyBypassStatsEndToEndTest, SuccessfulRequestCompletion) {
- const std::string kPrimaryHistogramName =
+TEST_F(DataReductionProxyBypassStatsEndToEndTest,
+ SuccessfulPrimaryProxyRequestCompletion) {
+ const std::string kHistogramName =
"DataReductionProxy.SuccessfulRequestCompletionCounts";
- const std::string kPrimaryMainFrameHistogramName =
+ const std::string kMainFrameHistogramName =
"DataReductionProxy.SuccessfulRequestCompletionCounts.MainFrame";
InitializeContext();
+
const struct {
- bool was_proxy_used;
- bool is_load_bypass_proxy;
- size_t proxy_index;
- bool is_main_frame;
+ int load_flags;
net::Error net_error;
- } tests[] = {{false, true, 0, true, net::OK},
- {false, true, 0, false, net::ERR_TOO_MANY_REDIRECTS},
- {false, false, 0, true, net::OK},
- {false, false, 0, false, net::ERR_TOO_MANY_REDIRECTS},
- {true, false, 0, true, net::OK},
- {true, false, 0, true, net::ERR_TOO_MANY_REDIRECTS},
- {true, false, 0, false, net::OK},
- {true, false, 0, false, net::ERR_TOO_MANY_REDIRECTS},
- {true, false, 1, true, net::OK},
- {true, false, 1, true, net::ERR_TOO_MANY_REDIRECTS},
- {true, false, 1, false, net::OK},
- {true, false, 1, false, net::ERR_TOO_MANY_REDIRECTS}};
+ bool expect_histogram_sample;
+ bool expect_main_frame_histogram_sample;
+ } tests[] = {
+ {net::LOAD_BYPASS_PROXY | net::LOAD_MAIN_FRAME_DEPRECATED, net::OK, false,
+ false},
+ {net::LOAD_BYPASS_PROXY | net::LOAD_MAIN_FRAME_DEPRECATED,
+ net::ERR_TOO_MANY_REDIRECTS, false, false},
+ {net::LOAD_BYPASS_PROXY, net::OK, false, false},
+ {net::LOAD_BYPASS_PROXY, net::ERR_TOO_MANY_REDIRECTS, false, false},
+ {net::LOAD_MAIN_FRAME_DEPRECATED, net::OK, true, true},
+ {net::LOAD_MAIN_FRAME_DEPRECATED, net::ERR_TOO_MANY_REDIRECTS, false,
+ false},
+ {0, net::OK, true, false},
+ {0, net::ERR_TOO_MANY_REDIRECTS, false, false},
+ };
for (const auto& test : tests) {
- config()->ResetWasDataReductionProxyUsed();
base::HistogramTester histogram_tester;
+ CreateAndExecuteRequest(GURL("http://foo.com"), test.load_flags,
+ test.net_error,
+ "HTTP/1.1 200 OK\r\n"
+ "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
+ kNextBody.c_str(), nullptr, nullptr);
+ drp_test_context()->RunUntilIdle();
- // Proxy succeeds.
- int load_flags = net::LOAD_NORMAL;
- if (test.is_load_bypass_proxy) {
- load_flags |= net::LOAD_BYPASS_PROXY;
- }
- if (test.is_main_frame) {
- load_flags |= net::LOAD_MAIN_FRAME_DEPRECATED;
- }
+ if (test.expect_histogram_sample)
+ histogram_tester.ExpectUniqueSample(kHistogramName, 0, 1);
+ else
+ histogram_tester.ExpectTotalCount(kHistogramName, 0);
- if (!test.was_proxy_used)
- config()->SetWasDataReductionProxyNotUsed();
- else {
- config()->SetWasDataReductionProxyUsedProxyIndex(test.proxy_index);
- }
+ if (test.expect_main_frame_histogram_sample)
+ histogram_tester.ExpectUniqueSample(kMainFrameHistogramName, 0, 1);
+ else
+ histogram_tester.ExpectTotalCount(kMainFrameHistogramName, 0);
+ }
+}
- CreateAndExecuteRequest(GURL("http://bar.com"), load_flags, test.net_error,
+TEST_F(DataReductionProxyBypassStatsEndToEndTest,
+ SuccessfulFallbackProxyRequestCompletion) {
+ const std::string kHistogramName =
+ "DataReductionProxy.SuccessfulRequestCompletionCounts";
+ const std::string kMainFrameHistogramName =
+ "DataReductionProxy.SuccessfulRequestCompletionCounts.MainFrame";
+
+ // Explicitly set primary and fallback Data Reduction Proxies to use.
+ config()->test_params()->SetProxiesForHttp(
+ std::vector<DataReductionProxyServer>(
+ {DataReductionProxyServer(
+ net::ProxyServer::FromURI("http://origin.net",
+ net::ProxyServer::SCHEME_HTTP),
+ ProxyServer::CORE),
+ DataReductionProxyServer(
+ net::ProxyServer::FromURI("http://fallback.net",
+ net::ProxyServer::SCHEME_HTTP),
+ ProxyServer::CORE)}));
+
+ // Make the first Data Reduction Proxy host in the list of Data Reduction
+ // Proxies to use fail to resolve, so that the tests below will use the
+ // fallback proxy.
+ std::unique_ptr<net::MockHostResolver> host_resolver(
+ new net::MockHostResolver());
+ const DataReductionProxyServer& primary_proxy =
+ config()->test_params()->proxies_for_http().front();
+ host_resolver->rules()->AddSimulatedFailure(
+ primary_proxy.proxy_server().host_port_pair().host());
+
+ set_host_resolver(host_resolver.get());
+ InitializeContext();
+
+ const struct {
+ int load_flags;
+ net::Error net_error;
+ bool expect_histogram_sample;
+ bool expect_main_frame_histogram_sample;
+ } tests[] = {
+ {net::LOAD_BYPASS_PROXY | net::LOAD_MAIN_FRAME_DEPRECATED, net::OK, false,
+ false},
+ {net::LOAD_BYPASS_PROXY | net::LOAD_MAIN_FRAME_DEPRECATED,
+ net::ERR_TOO_MANY_REDIRECTS, false, false},
+ {net::LOAD_BYPASS_PROXY, net::OK, false, false},
+ {net::LOAD_BYPASS_PROXY, net::ERR_TOO_MANY_REDIRECTS, false, false},
+ {net::LOAD_MAIN_FRAME_DEPRECATED, net::OK, true, true},
+ {net::LOAD_MAIN_FRAME_DEPRECATED, net::ERR_TOO_MANY_REDIRECTS, false,
+ false},
+ {0, net::OK, true, false},
+ {0, net::ERR_TOO_MANY_REDIRECTS, false, false},
+ };
+
+ for (const auto& test : tests) {
+ base::HistogramTester histogram_tester;
+ CreateAndExecuteRequest(GURL("http://foo.com"), test.load_flags,
+ test.net_error,
"HTTP/1.1 200 OK\r\n"
"Via: 1.1 Chrome-Compression-Proxy\r\n\r\n",
kNextBody.c_str(), nullptr, nullptr);
drp_test_context()->RunUntilIdle();
- if (test.was_proxy_used && !test.is_load_bypass_proxy &&
- test.net_error == net::OK) {
- histogram_tester.ExpectUniqueSample(kPrimaryHistogramName,
- test.proxy_index, 1);
- } else {
- histogram_tester.ExpectTotalCount(kPrimaryHistogramName, 0);
- }
+ if (test.expect_histogram_sample)
+ histogram_tester.ExpectUniqueSample(kHistogramName, 1, 1);
+ else
+ histogram_tester.ExpectTotalCount(kHistogramName, 0);
- if (test.was_proxy_used && !test.is_load_bypass_proxy &&
- test.is_main_frame && test.net_error == net::OK) {
- histogram_tester.ExpectUniqueSample(kPrimaryMainFrameHistogramName,
- test.proxy_index, 1);
- } else {
- histogram_tester.ExpectTotalCount(kPrimaryMainFrameHistogramName, 0);
- }
+ if (test.expect_main_frame_histogram_sample)
+ histogram_tester.ExpectUniqueSample(kMainFrameHistogramName, 1, 1);
+ else
+ histogram_tester.ExpectTotalCount(kMainFrameHistogramName, 0);
}
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
index 504cf46c689..9ac471c6fa7 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.cc
@@ -202,11 +202,11 @@ void RecordDailyContentLengthHistograms(
percent_savings_via_data_reduction_proxy);
}
-void RecordSavingsClearedNegativeClockMetric(int days_since_last_update) {
- // Data savings are cleared if the system clock moved back by more than
- // one day.
- UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.SavingsCleared.NegativeSystemClock",
- days_since_last_update < -1);
+void RecordSavingsClearedMetric(DataReductionProxySavingsClearedReason reason) {
+ DCHECK_GT(DataReductionProxySavingsClearedReason::REASON_COUNT, reason);
+ UMA_HISTOGRAM_ENUMERATION(
+ "DataReductionProxy.SavingsCleared.Reason", reason,
+ DataReductionProxySavingsClearedReason::REASON_COUNT);
}
} // namespace
@@ -632,6 +632,9 @@ void DataReductionProxyCompressionStats::DeleteBrowsingHistory(
}
service_->DeleteBrowsingHistory(start, end);
+
+ RecordSavingsClearedMetric(DataReductionProxySavingsClearedReason::
+ USER_ACTION_DELETE_BROWSING_HISTORY);
}
void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
@@ -664,6 +667,12 @@ void DataReductionProxyCompressionStats::OnCurrentDataUsageLoaded(
data_usage_map_last_updated_ =
base::Time::FromInternalValue(data_usage->last_updated_timestamp());
+ // Record if there was a read error.
+ if (data_usage->had_read_error()) {
+ RecordSavingsClearedMetric(
+ DataReductionProxySavingsClearedReason::PREFS_PARSE_ERROR);
+ }
+
current_data_usage_load_status_ = LOADED;
}
@@ -676,7 +685,8 @@ void DataReductionProxyCompressionStats::SetDataUsageReportingEnabled(
}
}
-void DataReductionProxyCompressionStats::ClearDataSavingStatistics() {
+void DataReductionProxyCompressionStats::ClearDataSavingStatistics(
+ DataReductionProxySavingsClearedReason reason) {
DeleteHistoricalDataUsage();
pref_service_->ClearPref(prefs::kDailyHttpContentLengthLastUpdateDate);
@@ -739,6 +749,8 @@ void DataReductionProxyCompressionStats::ClearDataSavingStatistics() {
++iter) {
iter->second->Clear();
}
+
+ RecordSavingsClearedMetric(reason);
}
void DataReductionProxyCompressionStats::DelayedWritePrefs() {
@@ -963,7 +975,10 @@ void DataReductionProxyCompressionStats::RecordRequestSizePrefs(
"Net.DailyContentLength_ViaDataReductionProxy_UnknownMime");
}
- RecordSavingsClearedNegativeClockMetric(days_since_last_update);
+ if (days_since_last_update < -1) {
+ RecordSavingsClearedMetric(
+ DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK);
+ }
// The system may go backwards in time by up to a day for legitimate
// reasons, such as with changes to the time zone. In such cases, we
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
index fbf7642cd80..c7917917889 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h
@@ -36,6 +36,24 @@ class DataReductionProxyService;
class DataUsageBucket;
class PerSiteDataUsage;
+// These values are persisted to logs. Entries should not be renumbered and
+// numeric values should never be reused.
+//
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.chrome.browser.preferences.datareduction)
+enum class DataReductionProxySavingsClearedReason {
+ SYSTEM_CLOCK_MOVED_BACK,
+ PREFS_PARSE_ERROR,
+ USER_ACTION_EXTENSION,
+ USER_ACTION_SETTINGS_MENU,
+ USER_ACTION_DELETE_BROWSING_HISTORY,
+ // NOTE: always keep this entry at the end. Add new result types only
+ // immediately above this line. Make sure to update the corresponding
+ // histogram enum accordingly.
+ REASON_COUNT,
+};
+
// Data reduction proxy delayed pref service reduces the number calls to pref
// service by storing prefs in memory and writing to the given PrefService after
// |delay| amount of time. If |delay| is zero, the delayed pref service writes
@@ -94,8 +112,8 @@ class DataReductionProxyCompressionStats {
// Resets daily content length statistics.
void ResetStatistics();
- // Clears all data saving statistics.
- void ClearDataSavingStatistics();
+ // Clears all data saving statistics for the given |reason|.
+ void ClearDataSavingStatistics(DataReductionProxySavingsClearedReason reason);
// Returns the total size of all HTTP content received from the network.
int64_t GetHttpReceivedContentLength();
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
index a5c0658e88c..0ec7dbdb450 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats_unittest.cc
@@ -433,7 +433,9 @@ class DataReductionProxyCompressionStatsTest : public testing::Test {
}
void ClearDataSavingStatistics() {
- compression_stats_->ClearDataSavingStatistics();
+ compression_stats_->ClearDataSavingStatistics(
+ DataReductionProxySavingsClearedReason::
+ USER_ACTION_DELETE_BROWSING_HISTORY);
}
void DeleteBrowsingHistory(const base::Time& start, const base::Time& end) {
@@ -852,73 +854,6 @@ TEST_F(DataReductionProxyCompressionStatsTest, PartialDayTimeChange) {
received2, 2, kNumDaysInHistory);
}
-TEST_F(DataReductionProxyCompressionStatsTest, ForwardMultipleDays) {
- base::HistogramTester histogram_tester;
- const int64_t kOriginalLength = 200;
- const int64_t kReceivedLength = 100;
- RecordContentLengthPrefs(
- kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
- FakeNow());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 1);
-
- // Forward three days.
- SetFakeTimeDeltaInHours(3 * 24);
-
- RecordContentLengthPrefs(
- kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
- FakeNow());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 2);
-
- int64_t original[] = {kOriginalLength, 0, 0, kOriginalLength};
- int64_t received[] = {kReceivedLength, 0, 0, kReceivedLength};
- VerifyDailyDataSavingContentLengthPrefLists(
- original, 4, received, 4, original, 4, received, 4, original, 4, received,
- 4, kNumDaysInHistory);
-
- // Forward four more days.
- AddFakeTimeDeltaInHours(4 * 24);
- RecordContentLengthPrefs(
- kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
- FakeNow());
- int64_t original2[] = {
- kOriginalLength, 0, 0, kOriginalLength, 0, 0, 0, kOriginalLength,
- };
- int64_t received2[] = {
- kReceivedLength, 0, 0, kReceivedLength, 0, 0, 0, kReceivedLength,
- };
- VerifyDailyDataSavingContentLengthPrefLists(
- original2, 8, received2, 8, original2, 8, received2, 8, original2, 8,
- received2, 8, kNumDaysInHistory);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 3);
-
- // Forward |kNumDaysInHistory| more days.
- AddFakeTimeDeltaInHours(kNumDaysInHistory * 24);
- RecordContentLengthPrefs(
- kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
- FakeNow());
- int64_t original3[] = {kOriginalLength};
- int64_t received3[] = {kReceivedLength};
- VerifyDailyDataSavingContentLengthPrefLists(
- original3, 1, received3, 1, original3, 1, received3, 1, original3, 1,
- received3, 1, kNumDaysInHistory);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 4);
-
- // Forward |kNumDaysInHistory| + 1 more days.
- AddFakeTimeDeltaInHours((kNumDaysInHistory + 1)* 24);
- RecordContentLengthPrefs(
- kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
- FakeNow());
- VerifyDailyDataSavingContentLengthPrefLists(
- original3, 1, received3, 1, original3, 1, received3, 1, original3, 1,
- received3, 1, kNumDaysInHistory);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 5);
-}
-
TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
base::HistogramTester histogram_tester;
const int64_t kOriginalLength = 200;
@@ -929,10 +864,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
FakeNow());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 1);
- // Backward one day.
+ // Backward one day, expect no count.
SetFakeTimeDeltaInHours(-24);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
@@ -942,10 +875,10 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
VerifyDailyDataSavingContentLengthPrefLists(
original, 1, received, 1, original, 1, received, 1, original, 1, received,
1, kNumDaysInHistory);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 2);
+ histogram_tester.ExpectTotalCount("DataReductionProxy.SavingsCleared.Reason",
+ 0);
- // Then, Forward one day
+ // Then forward one day, expect no count.
AddFakeTimeDeltaInHours(24);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
@@ -955,8 +888,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardAndForwardOneDay) {
VerifyDailyDataSavingContentLengthPrefLists(
original2, 2, received2, 2, original2, 2, received2, 2, original2, 2,
received2, 2, kNumDaysInHistory);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 3);
+ histogram_tester.ExpectTotalCount("DataReductionProxy.SavingsCleared.Reason",
+ 0);
}
TEST_F(DataReductionProxyCompressionStatsTest, BackwardTwoDays) {
@@ -969,10 +902,8 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardTwoDays) {
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
FakeNow());
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 1);
- // Backward two days.
+ // Backward two days, expect SYSTEM_CLOCK_MOVED_BACK.
SetFakeTimeDeltaInHours(-2 * 24);
RecordContentLengthPrefs(
kReceivedLength, kOriginalLength, true, VIA_DATA_REDUCTION_PROXY,
@@ -980,30 +911,27 @@ TEST_F(DataReductionProxyCompressionStatsTest, BackwardTwoDays) {
VerifyDailyDataSavingContentLengthPrefLists(
original, 1, received, 1, original, 1, received, 1, original, 1, received,
1, kNumDaysInHistory);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", 2);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", true, 1);
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.SavingsCleared.Reason",
+ DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK, 1);
VerifyPrefInt64(prefs::kDataReductionProxySavingsClearedNegativeSystemClock,
FakeNow().ToInternalValue());
- // Backward two days.
+ // Backward another two days, expect SYSTEM_CLOCK_MOVED_BACK.
SetFakeTimeDeltaInHours(-4 * 24);
RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true,
VIA_DATA_REDUCTION_PROXY, FakeNow());
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", 3);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", true, 2);
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.SavingsCleared.Reason",
+ DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK, 2);
- // Forward 10 days.
- AddFakeTimeDeltaInHours(10 * 24);
+ // Forward 2 days, expect no change.
+ AddFakeTimeDeltaInHours(2 * 24);
RecordContentLengthPrefs(kReceivedLength, kOriginalLength, true,
VIA_DATA_REDUCTION_PROXY, FakeNow());
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", 4);
- histogram_tester.ExpectBucketCount(
- "DataReductionProxy.SavingsCleared.NegativeSystemClock", false, 2);
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.SavingsCleared.Reason",
+ DataReductionProxySavingsClearedReason::SYSTEM_CLOCK_MOVED_BACK, 2);
}
TEST_F(DataReductionProxyCompressionStatsTest, NormalizeHostname) {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
index 9b43046be09..04ff7e8fcd3 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.cc
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include <algorithm>
#include <utility>
#include "base/bind.h"
@@ -33,6 +32,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
#include "components/previews/core/previews_decider.h"
#include "components/variations/variations_associated_data.h"
@@ -247,73 +247,11 @@ void DataReductionProxyConfig::ReloadConfig() {
}
}
-bool DataReductionProxyConfig::WasDataReductionProxyUsed(
- const net::URLRequest* request,
- DataReductionProxyTypeInfo* proxy_info) const {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(request);
- return IsDataReductionProxy(request->proxy_server(), proxy_info);
-}
-
-bool DataReductionProxyConfig::IsDataReductionProxyServerCore(
+base::Optional<DataReductionProxyTypeInfo>
+DataReductionProxyConfig::FindConfiguredDataReductionProxy(
const net::ProxyServer& proxy_server) const {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(IsDataReductionProxy(proxy_server, nullptr /* proxy_info */));
-
- const net::HostPortPair& host_port_pair = proxy_server.host_port_pair();
-
- const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers =
- config_values_->proxies_for_http();
-
- const auto proxy_it = std::find_if(
- data_reduction_proxy_servers.begin(), data_reduction_proxy_servers.end(),
- [&host_port_pair](const DataReductionProxyServer& proxy) {
- return proxy.proxy_server().is_valid() &&
- proxy.proxy_server().host_port_pair().Equals(host_port_pair);
- });
-
- return proxy_it->IsCoreProxy();
-}
-
-bool DataReductionProxyConfig::IsDataReductionProxy(
- const net::ProxyServer& proxy_server,
- DataReductionProxyTypeInfo* proxy_info) const {
- DCHECK(thread_checker_.CalledOnValidThread());
-
- if (!proxy_server.is_valid() || proxy_server.is_direct())
- return false;
-
- // Only compare the host port pair of the |proxy_server| since the proxy
- // scheme of the stored data reduction proxy may be different than the proxy
- // scheme of |proxy_server|. This may happen even when the |proxy_server| is a
- // valid data reduction proxy. As an example, the stored data reduction proxy
- // may have a proxy scheme of HTTPS while |proxy_server| may have QUIC as the
- // proxy scheme.
- const net::HostPortPair& host_port_pair = proxy_server.host_port_pair();
-
- const std::vector<DataReductionProxyServer>& data_reduction_proxy_servers =
- config_values_->proxies_for_http();
-
- const auto proxy_it = std::find_if(
- data_reduction_proxy_servers.begin(), data_reduction_proxy_servers.end(),
- [&host_port_pair](const DataReductionProxyServer& proxy) {
- return proxy.proxy_server().is_valid() &&
- proxy.proxy_server().host_port_pair().Equals(host_port_pair);
- });
-
- if (proxy_it == data_reduction_proxy_servers.end())
- return false;
-
- if (!proxy_info)
- return true;
-
- proxy_info->proxy_servers =
- DataReductionProxyServer::ConvertToNetProxyServers(
- std::vector<DataReductionProxyServer>(
- proxy_it, data_reduction_proxy_servers.end()));
- proxy_info->proxy_index =
- static_cast<size_t>(proxy_it - data_reduction_proxy_servers.begin());
- return true;
+ return config_values_->FindConfiguredDataReductionProxy(proxy_server);
}
bool DataReductionProxyConfig::IsBypassedByDataReductionProxyLocalRules(
@@ -329,7 +267,7 @@ bool DataReductionProxyConfig::IsBypassedByDataReductionProxyLocalRules(
return true;
if (result.proxy_server().is_direct())
return true;
- return !IsDataReductionProxy(result.proxy_server(), nullptr);
+ return !FindConfiguredDataReductionProxy(result.proxy_server());
}
bool DataReductionProxyConfig::AreDataReductionProxiesBypassed(
@@ -374,7 +312,7 @@ bool DataReductionProxyConfig::AreProxiesBypassed(
continue;
base::TimeDelta delay;
- if (IsDataReductionProxy(proxy, nullptr)) {
+ if (FindConfiguredDataReductionProxy(proxy)) {
if (!IsProxyBypassed(retry_map, proxy, &delay))
return false;
if (delay < min_delay)
@@ -418,7 +356,7 @@ bool DataReductionProxyConfig::ContainsDataReductionProxy(
proxy_rules.MapUrlSchemeToProxyList("http");
if (http_proxy_list && !http_proxy_list->IsEmpty() &&
// Sufficient to check only the first proxy.
- IsDataReductionProxy(http_proxy_list->Get(), nullptr)) {
+ FindConfiguredDataReductionProxy(http_proxy_list->Get())) {
return true;
}
@@ -451,8 +389,6 @@ void DataReductionProxyConfig::HandleCaptivePortal() {
DCHECK(thread_checker_.CalledOnValidThread());
bool is_captive_portal = GetIsCaptivePortal();
- UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.CaptivePortalDetected.Platform",
- is_captive_portal);
if (is_captive_portal == network_properties_manager_->IsCaptivePortal())
return;
network_properties_manager_->SetIsCaptivePortal(is_captive_portal);
@@ -503,7 +439,7 @@ DataReductionProxyConfig::GetProxyConnectionToProbe() const {
const std::vector<DataReductionProxyServer>& proxies =
DataReductionProxyConfig::GetProxiesForHttp();
- for (const auto proxy_server : proxies) {
+ for (const DataReductionProxyServer& proxy_server : proxies) {
// First find a proxy server that has never been probed before. Proxies that
// have been probed before successfully do not need to be probed. On the
// other hand, proxies that have been probed before unsuccessfully are
@@ -518,7 +454,7 @@ DataReductionProxyConfig::GetProxyConnectionToProbe() const {
}
}
- for (const auto proxy_server : proxies) {
+ for (const DataReductionProxyServer& proxy_server : proxies) {
// Now find any proxy server that can be probed. This would return proxies
// that were probed before, the result was unsuccessful, but they have not
// yet hit the maximum probe retry limit.
@@ -540,34 +476,37 @@ void DataReductionProxyConfig::HandleWarmupFetcherResponse(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(IsFetchInFlight());
- // If the probe times out, then proxy server information may not have been
- // set by the URL fetcher.
- bool timed_out_with_no_proxy_data =
- (success_response == WarmupURLFetcher::FetchResult::kTimedOut &&
- !proxy_server.is_valid());
+ base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
+ FindConfiguredDataReductionProxy(proxy_server);
// Check the proxy server used.
- if (!timed_out_with_no_proxy_data &&
- !IsDataReductionProxy(proxy_server, nullptr)) {
- // No need to do anything here since the warmup fetch did not go through
- // the data saver proxy.
+ if (!proxy_type_info && proxy_server.is_valid() &&
+ !proxy_server.is_direct()) {
+ // No need to do anything here since the warmup fetch went through
+ // a non-datasaver proxy.
return;
}
bool is_secure_proxy = false;
bool is_core_proxy = false;
- if (!timed_out_with_no_proxy_data) {
+ if (proxy_type_info) {
+ DCHECK(proxy_server.is_valid());
+ DCHECK(!proxy_server.is_direct());
is_secure_proxy = proxy_server.is_https() || proxy_server.is_quic();
- is_core_proxy = IsDataReductionProxyServerCore(proxy_server);
+ is_core_proxy = proxy_type_info->proxy_servers[proxy_type_info->proxy_index]
+ .IsCoreProxy();
+
// The proxy server through which the warmup URL was fetched should match
// the proxy server for which the warmup URL is in-flight.
DCHECK(GetInFlightWarmupProxyDetails());
DCHECK_EQ(is_secure_proxy, GetInFlightWarmupProxyDetails()->first);
DCHECK_EQ(is_core_proxy, GetInFlightWarmupProxyDetails()->second);
} else {
- // When the probe times out, the proxy information may not be set. Fill-in
- // the missing data using the proxy that was being probed.
+ DCHECK(!proxy_server.is_valid() || proxy_server.is_direct());
+ // When the probe times out or if the warmup URL was fetched via DIRECT
+ // proxy, the data reduction proxy information may not be set. Fill-in the
+ // missing data using the proxy that was being probed.
is_secure_proxy = warmup_url_fetch_in_flight_secure_proxy_;
is_core_proxy = warmup_url_fetch_in_flight_core_proxy_;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
index 986045b564e..46ad67237cc 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h
@@ -16,11 +16,13 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/secure_proxy_checker.h"
#include "components/data_reduction_proxy/core/browser/warmup_url_fetcher.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/previews/core/previews_experiments.h"
#include "net/base/network_change_notifier.h"
@@ -119,27 +121,11 @@ class DataReductionProxyConfig
// InitDataReductionProxySettings.
void SetProxyConfig(bool enabled, bool at_startup);
- // Returns true if a Data Reduction Proxy was used for the given |request|.
- // If true, |proxy_info.proxy_servers.front()| will contain the name of the
- // proxy that was used. Subsequent entries in |proxy_info.proxy_servers| will
- // contain the names of the Data Reduction Proxy servers that would be used if
- // |proxy_info.proxy_servers.front()| is bypassed, if any exist. In addition,
- // |proxy_info| will note if the proxy used was a fallback. |proxy_info| can
- // be NULL if the caller isn't interested in its values. Virtualized for
- // testing.
- virtual bool WasDataReductionProxyUsed(
- const net::URLRequest* request,
- DataReductionProxyTypeInfo* proxy_info) const;
-
- // Returns true if the specified |proxy_server| matches a Data Reduction
- // Proxy. If true, |proxy_info.proxy_servers.front()| will contain the name of
- // the proxy that matches. Subsequent entries in |proxy_info.proxy_servers|
- // will contain the name of the Data Reduction Proxy servers that would be
- // used if |proxy_info.proxy_servers.front()| is bypassed, if any exist. In
- // addition, |proxy_info| will note if the proxy was a fallback. |proxy_info|
- // can be NULL if the caller isn't interested in its values.
- bool IsDataReductionProxy(const net::ProxyServer& proxy_server,
- DataReductionProxyTypeInfo* proxy_info) const;
+ // If the specified |proxy_server| matches a Data Reduction Proxy, returns the
+ // DataReductionProxyTypeInfo showing where that proxy is in the list of
+ // configured proxies, otherwise returns an empty optional value.
+ base::Optional<DataReductionProxyTypeInfo> FindConfiguredDataReductionProxy(
+ const net::ProxyServer& proxy_server) const;
// Returns true if this request would be bypassed by the Data Reduction Proxy
// based on applying the |data_reduction_proxy_config| param rules to the
@@ -327,12 +313,6 @@ class DataReductionProxyConfig
// Fetches the warmup URL.
void FetchWarmupProbeURL();
- // Returns true if |proxy_server| is a core data reduction proxy server.
- // Should be called only if |proxy_server| is a valid data reduction proxy
- // server.
- bool IsDataReductionProxyServerCore(
- const net::ProxyServer& proxy_server) const;
-
// URL fetcher used for performing the secure proxy check.
std::unique_ptr<SecureProxyChecker> secure_proxy_checker_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
index 2e430008cbb..004072cdb06 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client.cc
@@ -275,69 +275,66 @@ bool DataReductionProxyConfigServiceClient::ShouldRetryDueToAuthFailure(
const net::LoadTimingInfo& load_timing_info) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(response_headers);
- if (config_->IsDataReductionProxy(proxy_server, nullptr)) {
- if (response_headers->response_code() ==
- net::HTTP_PROXY_AUTHENTICATION_REQUIRED) {
- std::string session_key =
- request_options_->GetSessionKeyFromRequestHeaders(request_headers);
-
- std::string current_session_key = request_options_->GetSecureSession();
-
- // If the session key used in the request is different from the current
- // session key, then the current session key does not need to be
- // invalidated.
- if (session_key != current_session_key) {
- RecordAuthExpiredSessionKey(false);
- return true;
- }
- RecordAuthExpiredSessionKey(true);
-
- // The default backoff logic is to increment the failure count (and
- // increase the backoff time) with each response failure to the remote
- // config service, and to decrement the failure count (and decrease the
- // backoff time) with each response success. In the case where the
- // config service returns a success response (decrementing the failure
- // count) but the session key is continually invalid (as a response from
- // the Data Reduction Proxy and not the config service), the previous
- // response should be considered a failure in order to ensure the backoff
- // time continues to increase.
- if (previous_request_failed_authentication_)
- GetBackoffEntry()->InformOfRequest(false);
-
- // Record that a request resulted in an authentication failure.
- RecordAuthExpiredHistogram(true);
- previous_request_failed_authentication_ = true;
- InvalidateConfig();
- DCHECK(!config_->IsDataReductionProxy(proxy_server, nullptr));
-
- if (fetch_in_progress_) {
- // If a client config fetch is already in progress, then do not start
- // another fetch since starting a new fetch will cause extra data
- // usage, and also cancel the ongoing fetch.
- return true;
- }
-
- RetrieveConfig();
-
- if (!load_timing_info.send_start.is_null() &&
- !load_timing_info.request_start.is_null() &&
- net::NetworkChangeNotifier::GetConnectionType() !=
- net::NetworkChangeNotifier::CONNECTION_NONE &&
- last_ip_address_change_ < load_timing_info.request_start) {
- // Record only if there was no change in the IP address since the
- // request started.
- UMA_HISTOGRAM_TIMES(
- "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty",
- base::TimeTicks::Now() - load_timing_info.request_start);
- }
-
- return true;
- }
+ if (!config_->FindConfiguredDataReductionProxy(proxy_server))
+ return false;
+
+ if (response_headers->response_code() !=
+ net::HTTP_PROXY_AUTHENTICATION_REQUIRED) {
previous_request_failed_authentication_ = false;
+ return false;
+ }
+
+ // If the session key used in the request is different from the current
+ // session key, then the current session key does not need to be
+ // invalidated.
+ if (request_options_->GetSessionKeyFromRequestHeaders(request_headers) !=
+ request_options_->GetSecureSession()) {
+ RecordAuthExpiredSessionKey(false);
+ return true;
+ }
+ RecordAuthExpiredSessionKey(true);
+
+ // The default backoff logic is to increment the failure count (and
+ // increase the backoff time) with each response failure to the remote
+ // config service, and to decrement the failure count (and decrease the
+ // backoff time) with each response success. In the case where the
+ // config service returns a success response (decrementing the failure
+ // count) but the session key is continually invalid (as a response from
+ // the Data Reduction Proxy and not the config service), the previous
+ // response should be considered a failure in order to ensure the backoff
+ // time continues to increase.
+ if (previous_request_failed_authentication_)
+ GetBackoffEntry()->InformOfRequest(false);
+
+ // Record that a request resulted in an authentication failure.
+ RecordAuthExpiredHistogram(true);
+ previous_request_failed_authentication_ = true;
+ InvalidateConfig();
+ DCHECK(config_->GetProxiesForHttp().empty());
+
+ if (fetch_in_progress_) {
+ // If a client config fetch is already in progress, then do not start
+ // another fetch since starting a new fetch will cause extra data
+ // usage, and also cancel the ongoing fetch.
+ return true;
}
- return false;
+ RetrieveConfig();
+
+ if (!load_timing_info.send_start.is_null() &&
+ !load_timing_info.request_start.is_null() &&
+ net::NetworkChangeNotifier::GetConnectionType() !=
+ net::NetworkChangeNotifier::CONNECTION_NONE &&
+ last_ip_address_change_ < load_timing_info.request_start) {
+ // Record only if there was no change in the IP address since the
+ // request started.
+ UMA_HISTOGRAM_TIMES(
+ "DataReductionProxy.ConfigService.AuthFailure.LatencyPenalty",
+ base::TimeTicks::Now() - load_timing_info.request_start);
+ }
+
+ return true;
}
net::BackoffEntry* DataReductionProxyConfigServiceClient::GetBackoffEntry() {
@@ -410,7 +407,7 @@ void DataReductionProxyConfigServiceClient::RetrieveRemoteConfig() {
request.SerializeToString(&serialized_request);
std::unique_ptr<net::URLFetcher> fetcher =
GetURLFetcherForConfig(config_service_url_, serialized_request);
- if (!fetcher.get()) {
+ if (!fetcher) {
HandleResponse(std::string(),
net::URLRequestStatus::FromError(net::ERR_ABORTED),
net::URLFetcher::RESPONSE_CODE_INVALID);
@@ -558,12 +555,11 @@ bool DataReductionProxyConfigServiceClient::ParseAndApplyProxyConfig(
if (!config.has_proxy_config())
return false;
+ // An empty proxy config is OK, and allows the server to effectively turn off
+ // DataSaver if needed. See http://crbug.com/840978.
std::vector<DataReductionProxyServer> proxies =
GetProxiesForHTTP(config.proxy_config());
- if (proxies.empty())
- return false;
-
request_options_->SetSecureSession(config.session_key());
config_values_->UpdateValues(proxies);
config_->OnNewClientConfigFetched();
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
index a3101975743..becb0e43ff4 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_service_client_unittest.cc
@@ -229,6 +229,13 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
half_reporting_fraction_encoded_config_ =
EncodeConfig(half_reporting_fraction_config);
+ ClientConfig no_proxies_config;
+ no_proxies_config.set_session_key(kSuccessSessionKey);
+ no_proxies_config.mutable_refresh_duration()->set_seconds(
+ kConfigRefreshDurationSeconds);
+ no_proxies_config.mutable_refresh_duration()->set_nanos(0);
+ no_proxies_config_ = EncodeConfig(no_proxies_config);
+
success_reads_[0] = net::MockRead("HTTP/1.1 200 OK\r\n\r\n");
success_reads_[1] =
net::MockRead(net::ASYNC, config_.c_str(), config_.length());
@@ -394,25 +401,24 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
void AddMockSuccess() {
socket_data_providers_.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads_, arraysize(success_reads_), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads_, base::span<net::MockWrite>()));
mock_socket_factory_->AddSocketDataProvider(
socket_data_providers_.back().get());
}
void AddMockPreviousSuccess() {
socket_data_providers_.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- previous_success_reads_, arraysize(previous_success_reads_),
- nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ previous_success_reads_, base::span<net::MockWrite>()));
mock_socket_factory_->AddSocketDataProvider(
socket_data_providers_.back().get());
}
void AddMockFailure() {
socket_data_providers_.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- not_found_reads_, arraysize(not_found_reads_), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ not_found_reads_, base::span<net::MockWrite>()));
mock_socket_factory_->AddSocketDataProvider(
socket_data_providers_.back().get());
}
@@ -448,6 +454,7 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
const std::string& half_reporting_fraction_encoded_config() const {
return half_reporting_fraction_encoded_config_;
}
+ const std::string& no_proxies_config() const { return no_proxies_config_; }
const std::string& loaded_config() const { return loaded_config_; }
@@ -491,6 +498,9 @@ class DataReductionProxyConfigServiceClientTest : public testing::Test {
// A configuration where the pingback reporting fraction is set to 0.5f.
std::string half_reporting_fraction_encoded_config_;
+ // A configuration where no proxies are configured.
+ std::string no_proxies_config_;
+
// Mock socket data.
std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers_;
@@ -929,9 +939,6 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
if (test.expect_valid_config) {
EXPECT_EQ(kSuccessSessionKey, request_options()->GetSecureSession());
}
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.ConfigService.PersistedConfigIsExpired",
- !test.expect_valid_config, 1);
}
}
@@ -995,7 +1002,7 @@ TEST_F(DataReductionProxyConfigServiceClientTest, MultipleAuthFailures) {
std::string(kSuccessSessionKey) + ", key=value");
// Calling ShouldRetryDueToAuthFailure should trigger fetching of remote
// config.
- EXPECT_FALSE(config_client()->ShouldRetryDueToAuthFailure(
+ EXPECT_TRUE(config_client()->ShouldRetryDueToAuthFailure(
request_headers, parsed.get(), origin, load_timing_info));
EXPECT_EQ(1, config_client()->GetBackoffErrorCount());
histogram_tester.ExpectBucketCount(
@@ -1018,9 +1025,13 @@ TEST_F(DataReductionProxyConfigServiceClientTest, MultipleAuthFailures) {
EXPECT_GE(persisted_config_retrieval_time() + base::TimeDelta::FromMinutes(2),
base::Time::Now());
- histogram_tester.ExpectUniqueSample(
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.ConfigService.AuthExpiredSessionKey",
+ 0 /* AUTH_EXPIRED_SESSION_KEY_MISMATCH */, 1);
+ histogram_tester.ExpectBucketCount(
"DataReductionProxy.ConfigService.AuthExpiredSessionKey",
1 /* AUTH_EXPIRED_SESSION_KEY_MATCH */, 1);
+
histogram_tester.ExpectBucketCount(
"DataReductionProxy.ConfigService.AuthExpired", false, 2);
histogram_tester.ExpectBucketCount(
@@ -1359,6 +1370,16 @@ TEST_F(DataReductionProxyConfigServiceClientTest,
EXPECT_EQ(0.5f, pingback_reporting_fraction());
}
+TEST_F(DataReductionProxyConfigServiceClientTest, EmptyConfigDisablesDRP) {
+ Init(true);
+ SetDataReductionProxyEnabled(true, true);
+ EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
+
+ config_client()->ApplySerializedConfig(no_proxies_config());
+ EXPECT_EQ(std::vector<net::ProxyServer>(), GetConfiguredProxiesForHttp());
+ EXPECT_TRUE(configurator()->GetProxyConfig().proxy_rules().empty());
+}
+
#if defined(OS_ANDROID)
// Verifies the correctness of fetching config when Chromium is in background
// and foreground.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
index 50b69ecb35f..15832edb34f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.cc
@@ -12,6 +12,7 @@
#include "base/time/tick_clock.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -77,34 +78,6 @@ base::TimeTicks TestDataReductionProxyConfig::GetTicksNow() const {
return DataReductionProxyConfig::GetTicksNow();
}
-bool TestDataReductionProxyConfig::WasDataReductionProxyUsed(
- const net::URLRequest* request,
- DataReductionProxyTypeInfo* proxy_info) const {
- if (was_data_reduction_proxy_used_ &&
- !was_data_reduction_proxy_used_.value()) {
- return false;
- }
- bool was_data_reduction_proxy_used =
- DataReductionProxyConfig::WasDataReductionProxyUsed(request, proxy_info);
- if (proxy_info && was_data_reduction_proxy_used && proxy_index_)
- proxy_info->proxy_index = proxy_index_.value();
- return was_data_reduction_proxy_used;
-}
-
-void TestDataReductionProxyConfig::SetWasDataReductionProxyNotUsed() {
- was_data_reduction_proxy_used_ = false;
-}
-
-void TestDataReductionProxyConfig::SetWasDataReductionProxyUsedProxyIndex(
- int proxy_index) {
- proxy_index_ = proxy_index;
-}
-
-void TestDataReductionProxyConfig::ResetWasDataReductionProxyUsed() {
- was_data_reduction_proxy_used_.reset();
- proxy_index_.reset();
-}
-
void TestDataReductionProxyConfig::SetIsCaptivePortal(bool is_captive_portal) {
is_captive_portal_ = is_captive_portal;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
index 818a7e815c6..3612ad25261 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h
@@ -74,21 +74,6 @@ class TestDataReductionProxyConfig : public DataReductionProxyConfig {
base::TimeTicks GetTicksNow() const override;
- bool WasDataReductionProxyUsed(
- const net::URLRequest* request,
- DataReductionProxyTypeInfo* proxy_info) const override;
-
- // Sets the data reduction proxy as not used. Subsequent calls to
- // WasDataReductionProxyUsed() would return false.
- void SetWasDataReductionProxyNotUsed();
-
- // Sets the proxy index of the data reduction proxy. Subsequent calls to
- // WasDataReductionProxyUsed are affected.
- void SetWasDataReductionProxyUsedProxyIndex(int proxy_index);
-
- // Resets the behavior of WasDataReductionProxyUsed() calls.
- void ResetWasDataReductionProxyUsed();
-
// Sets if the captive portal probe has been blocked for the current network.
void SetIsCaptivePortal(bool is_captive_portal);
@@ -132,9 +117,6 @@ class TestDataReductionProxyConfig : public DataReductionProxyConfig {
base::Optional<size_t> previous_attempt_counts_;
- base::Optional<bool> was_data_reduction_proxy_used_;
- base::Optional<int> proxy_index_;
-
base::Optional<std::string> current_network_id_;
base::Optional<std::pair<bool /* is_secure_proxy */, bool /*is_core_proxy */>>
@@ -164,7 +146,7 @@ class MockDataReductionProxyConfig : public TestDataReductionProxyConfig {
net::NetLog* net_log,
DataReductionProxyConfigurator* configurator,
DataReductionProxyEventCreator* event_creator);
- ~MockDataReductionProxyConfig();
+ ~MockDataReductionProxyConfig() override;
MOCK_CONST_METHOD2(WasDataReductionProxyUsed,
bool(const net::URLRequest*,
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
index ff82e5a53e9..6687ddeb505 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_config_unittest.cc
@@ -41,6 +41,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/previews/core/previews_experiments.h"
#include "components/previews/core/test_previews_decider.h"
@@ -175,11 +176,6 @@ class DataReductionProxyConfigTest : public testing::Test {
}
histogram_tester.ExpectUniqueSample("DataReductionProxy.ProbeURL",
expected_fetch_result, 1);
-
- // Recorded on every IP change.
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.CaptivePortalDetected.Platform", is_captive_portal,
- 1);
}
void RunUntilIdle() {
@@ -776,57 +772,32 @@ TEST_F(DataReductionProxyConfigTest, AreProxiesBypassedRetryDelay) {
EXPECT_EQ(delay, min_retry_delay);
}
-TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithParams) {
- const struct {
- net::ProxyServer proxy_server;
- bool expected_result;
- net::ProxyServer expected_first;
- net::ProxyServer expected_second;
- bool expected_is_fallback;
- } tests[] = {
- {params()->proxies_for_http().front().proxy_server(), true,
- params()->proxies_for_http().front().proxy_server(),
- params()->proxies_for_http().at(1).proxy_server(), false},
- {params()->proxies_for_http().at(1).proxy_server(), true,
- params()->proxies_for_http().at(1).proxy_server(), net::ProxyServer(),
- true},
- };
- for (size_t i = 0; i < arraysize(tests); ++i) {
- std::unique_ptr<TestDataReductionProxyParams> params(
- new TestDataReductionProxyParams());
- DataReductionProxyTypeInfo proxy_type_info;
- std::unique_ptr<DataReductionProxyConfig> config(
- new DataReductionProxyConfig(task_runner(), net_log(),
- std::move(params), configurator(),
- event_creator()));
- EXPECT_EQ(
- tests[i].expected_result,
- config->IsDataReductionProxy(tests[i].proxy_server, &proxy_type_info))
- << i;
- EXPECT_EQ(tests[i].expected_first.is_valid(),
- proxy_type_info.proxy_servers.size() >= 1 &&
- proxy_type_info.proxy_servers[0].is_valid())
- << i;
- if (proxy_type_info.proxy_servers.size() >= 1 &&
- proxy_type_info.proxy_servers[0].is_valid()) {
- EXPECT_EQ(tests[i].expected_first, proxy_type_info.proxy_servers[0]) << i;
- }
- EXPECT_EQ(tests[i].expected_second.is_valid(),
- proxy_type_info.proxy_servers.size() >= 2 &&
- proxy_type_info.proxy_servers[1].is_valid())
- << i;
- if (proxy_type_info.proxy_servers.size() >= 2 &&
- proxy_type_info.proxy_servers[1].is_valid()) {
- EXPECT_EQ(tests[i].expected_second, proxy_type_info.proxy_servers[1])
- << i;
- }
+TEST_F(DataReductionProxyConfigTest,
+ FindConfiguredDataReductionProxyWithParams) {
+ std::unique_ptr<TestDataReductionProxyParams> params(
+ new TestDataReductionProxyParams());
+
+ const std::vector<DataReductionProxyServer> expected_proxies =
+ params->proxies_for_http();
+ ASSERT_LT(0U, expected_proxies.size());
- EXPECT_EQ(tests[i].expected_is_fallback, proxy_type_info.proxy_index != 0)
- << i;
+ DataReductionProxyConfig config(task_runner(), net_log(), std::move(params),
+ configurator(), event_creator());
+
+ for (size_t expected_proxy_index = 0U;
+ expected_proxy_index < expected_proxies.size(); ++expected_proxy_index) {
+ base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
+ config.FindConfiguredDataReductionProxy(
+ expected_proxies[expected_proxy_index].proxy_server());
+
+ ASSERT_TRUE(proxy_type_info.has_value());
+ EXPECT_EQ(expected_proxies, proxy_type_info->proxy_servers);
+ EXPECT_EQ(expected_proxy_index, proxy_type_info->proxy_index);
}
}
-TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
+TEST_F(DataReductionProxyConfigTest,
+ FindConfiguredDataReductionProxyWithMutableConfig) {
std::vector<DataReductionProxyServer> proxies_for_http;
proxies_for_http.push_back(DataReductionProxyServer(
net::ProxyServer::FromURI("https://origin.net:443",
@@ -845,65 +816,38 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
const struct {
DataReductionProxyServer proxy_server;
bool expected_result;
- std::vector<DataReductionProxyServer> expected_proxies;
size_t expected_proxy_index;
} tests[] = {
- {
- proxies_for_http[0], true,
- std::vector<DataReductionProxyServer>(proxies_for_http.begin(),
- proxies_for_http.end()),
- 0,
- },
- {
- proxies_for_http[1], true,
- std::vector<DataReductionProxyServer>(proxies_for_http.begin() + 1,
- proxies_for_http.end()),
- 1,
- },
- {
- proxies_for_http[2], true,
- std::vector<DataReductionProxyServer>(proxies_for_http.begin() + 2,
- proxies_for_http.end()),
- 2,
- },
- {
- DataReductionProxyServer(net::ProxyServer(),
- ProxyServer::UNSPECIFIED_TYPE),
- false, std::vector<DataReductionProxyServer>(), 0,
- },
- {
- DataReductionProxyServer(
- net::ProxyServer(
- net::ProxyServer::SCHEME_HTTPS,
- net::HostPortPair::FromString("otherorigin.net:443")),
- ProxyServer::UNSPECIFIED_TYPE),
- false, std::vector<DataReductionProxyServer>(), 0,
- },
- {
- // Verifies that when determining if a proxy is a valid data reduction
- // proxy, only the host port pairs are compared.
- DataReductionProxyServer(
- net::ProxyServer::FromURI("origin.net:443",
- net::ProxyServer::SCHEME_QUIC),
- ProxyServer::UNSPECIFIED_TYPE),
- true, std::vector<DataReductionProxyServer>(proxies_for_http.begin(),
- proxies_for_http.end()),
- 0,
- },
- {
- DataReductionProxyServer(
- net::ProxyServer::FromURI("origin2.net:443",
- net::ProxyServer::SCHEME_HTTPS),
- ProxyServer::UNSPECIFIED_TYPE),
- false, std::vector<DataReductionProxyServer>(), 0,
- },
- {
- DataReductionProxyServer(
- net::ProxyServer::FromURI("origin2.net:443",
- net::ProxyServer::SCHEME_QUIC),
- ProxyServer::UNSPECIFIED_TYPE),
- false, std::vector<DataReductionProxyServer>(), 0,
- },
+ {proxies_for_http[0], true, 0U},
+ {proxies_for_http[1], true, 1U},
+ {proxies_for_http[2], true, 2U},
+ {DataReductionProxyServer(net::ProxyServer(),
+ ProxyServer::UNSPECIFIED_TYPE),
+ false, 0U},
+ {DataReductionProxyServer(net::ProxyServer(net::ProxyServer::SCHEME_HTTPS,
+ net::HostPortPair::FromString(
+ "otherorigin.net:443")),
+ ProxyServer::UNSPECIFIED_TYPE),
+ false, 0U},
+
+ // Verifies that when determining if a proxy is a valid data reduction
+ // proxy, only the host port pairs are compared.
+ {DataReductionProxyServer(
+ net::ProxyServer::FromURI("origin.net:443",
+ net::ProxyServer::SCHEME_QUIC),
+ ProxyServer::UNSPECIFIED_TYPE),
+ true, 0U},
+
+ {DataReductionProxyServer(
+ net::ProxyServer::FromURI("origin2.net:443",
+ net::ProxyServer::SCHEME_HTTPS),
+ ProxyServer::UNSPECIFIED_TYPE),
+ false, 0U},
+ {DataReductionProxyServer(
+ net::ProxyServer::FromURI("origin2.net:443",
+ net::ProxyServer::SCHEME_QUIC),
+ ProxyServer::UNSPECIFIED_TYPE),
+ false, 0U},
};
std::unique_ptr<DataReductionProxyMutableConfigValues> config_values =
@@ -914,14 +858,15 @@ TEST_F(DataReductionProxyConfigTest, IsDataReductionProxyWithMutableConfig) {
task_runner(), net_log(), std::move(config_values), configurator(),
event_creator()));
for (const auto& test : tests) {
- DataReductionProxyTypeInfo proxy_type_info;
- EXPECT_EQ(test.expected_result,
- config->IsDataReductionProxy(test.proxy_server.proxy_server(),
- &proxy_type_info));
- EXPECT_EQ(proxy_type_info.proxy_servers,
- DataReductionProxyServer::ConvertToNetProxyServers(
- test.expected_proxies));
- EXPECT_EQ(test.expected_proxy_index, proxy_type_info.proxy_index);
+ base::Optional<DataReductionProxyTypeInfo> proxy_type_info =
+ config->FindConfiguredDataReductionProxy(
+ test.proxy_server.proxy_server());
+ EXPECT_EQ(test.expected_result, proxy_type_info.has_value());
+
+ if (proxy_type_info) {
+ EXPECT_EQ(proxies_for_http, proxy_type_info->proxy_servers);
+ EXPECT_EQ(test.expected_proxy_index, proxy_type_info->proxy_index);
+ }
}
}
@@ -940,8 +885,8 @@ TEST_F(DataReductionProxyConfigTest,
net::LOAD_MAIN_FRAME_DEPRECATED);
std::unique_ptr<previews::TestPreviewsDecider> previews_decider =
std::make_unique<previews::TestPreviewsDecider>(true);
- EXPECT_FALSE(test_config()->ShouldAcceptServerPreview(
- *request.get(), *previews_decider.get()));
+ EXPECT_FALSE(
+ test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
}
TEST_F(DataReductionProxyConfigTest,
@@ -959,8 +904,8 @@ TEST_F(DataReductionProxyConfigTest,
net::LOAD_MAIN_FRAME_DEPRECATED);
std::unique_ptr<previews::TestPreviewsDecider> previews_decider =
std::make_unique<previews::TestPreviewsDecider>(true);
- EXPECT_FALSE(test_config()->ShouldAcceptServerPreview(
- *request.get(), *previews_decider.get()));
+ EXPECT_FALSE(
+ test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
}
TEST_F(DataReductionProxyConfigTest, ShouldAcceptServerPreview) {
@@ -984,14 +929,14 @@ TEST_F(DataReductionProxyConfigTest, ShouldAcceptServerPreview) {
std::make_unique<previews::TestPreviewsDecider>(true);
// Verify true for no flags.
- EXPECT_TRUE(test_config()->ShouldAcceptServerPreview(
- *request.get(), *previews_decider.get()));
+ EXPECT_TRUE(
+ test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
// Verify PreviewsDecider check.
base::CommandLine::ForCurrentProcess()->InitFromArgv(0, nullptr);
previews_decider = std::make_unique<previews::TestPreviewsDecider>(false);
- EXPECT_FALSE(test_config()->ShouldAcceptServerPreview(
- *request.get(), *previews_decider.get()));
+ EXPECT_FALSE(
+ test_config()->ShouldAcceptServerPreview(*request, *previews_decider));
histogram_tester.ExpectBucketCount(
"DataReductionProxy.Protocol.NotAcceptingTransform",
1 /* NOT_ACCEPTING_TRANSFORM_BLACKLISTED */, 1);
@@ -1017,14 +962,6 @@ TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherResponse) {
EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
GetConfiguredProxiesForHttp());
- // Report failed warmup for a non-DataSaver proxy, and verify that it does not
- // change the list of data saver proxies.
- test_config()->HandleWarmupFetcherResponse(
- net::ProxyServer(),
- WarmupURLFetcher::FetchResult::kFailed /* success_response */);
- EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
- GetConfiguredProxiesForHttp());
-
// Set the details of the proxy to which the warmup URL probe is in-flight to
// avoid triggering the DCHECKs in HandleWarmupFetcherResponse method.
test_config()->SetInFlightWarmupProxyDetails(
@@ -1154,6 +1091,62 @@ TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherResponse) {
GetConfiguredProxiesForHttp());
}
+// Tests that the proxy server last used for fetching the warmup URL is marked
+// as failed when the warmup fetched callback returns an invalid proxy.
+TEST_F(DataReductionProxyConfigTest,
+ HandleWarmupFetcherResponse_InvalidProxyServer) {
+ const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
+ const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
+ "https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
+ const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
+ "fallback.net:80", net::ProxyServer::SCHEME_HTTP);
+
+ SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
+ ResetSettings();
+
+ // The proxy is enabled.
+ test_config()->UpdateConfigForTesting(true, true, true);
+ test_config()->OnNewClientConfigFetched();
+ EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
+ GetConfiguredProxiesForHttp());
+
+ // Report failed warmup for a non-DataSaver proxy, and verify that it
+ // changes the list of data saver proxies.
+ test_config()->HandleWarmupFetcherResponse(
+ net::ProxyServer(),
+ WarmupURLFetcher::FetchResult::kFailed /* success_response */);
+ EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
+ GetConfiguredProxiesForHttp());
+}
+
+// Tests that the proxy server last used for fetching the warmup URL is marked
+// as failed when the warmup fetched callback returns a direct proxy.
+TEST_F(DataReductionProxyConfigTest,
+ HandleWarmupFetcherResponse_DirectProxyServer) {
+ const net::URLRequestStatus kSuccess(net::URLRequestStatus::SUCCESS, net::OK);
+ const net::ProxyServer kHttpsProxy = net::ProxyServer::FromURI(
+ "https://origin.net:443", net::ProxyServer::SCHEME_HTTP);
+ const net::ProxyServer kHttpProxy = net::ProxyServer::FromURI(
+ "fallback.net:80", net::ProxyServer::SCHEME_HTTP);
+
+ SetProxiesForHttpOnCommandLine({kHttpsProxy, kHttpProxy});
+ ResetSettings();
+
+ // The proxy is enabled.
+ test_config()->UpdateConfigForTesting(true, true, true);
+ test_config()->OnNewClientConfigFetched();
+ EXPECT_EQ(std::vector<net::ProxyServer>({kHttpsProxy, kHttpProxy}),
+ GetConfiguredProxiesForHttp());
+
+ // Report failed warmup for a non-DataSaver proxy, and verify that it
+ // changes the list of data saver proxies.
+ test_config()->HandleWarmupFetcherResponse(
+ net::ProxyServer::Direct(),
+ WarmupURLFetcher::FetchResult::kFailed /* success_response */);
+ EXPECT_EQ(std::vector<net::ProxyServer>({kHttpProxy}),
+ GetConfiguredProxiesForHttp());
+}
+
TEST_F(DataReductionProxyConfigTest, HandleWarmupFetcherRetry) {
constexpr size_t kMaxWarmupURLFetchAttempts = 3;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
index cdaa80c48e4..f03df0d2b09 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator_unittest.cc
@@ -94,8 +94,7 @@ class DataReductionProxyConfiguratorTest : public testing::Test {
const std::string& expected_bypass_list) {
test_context_->RunUntilIdle();
net::ProxyConfig::ProxyRules rules =
- config_
- ->CreateProxyConfig(probe_url_config, *manager_.get(), http_proxies)
+ config_->CreateProxyConfig(probe_url_config, *manager_, http_proxies)
.proxy_rules();
ASSERT_EQ(expected_rules_type, rules.type);
if (net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME ==
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
index 7947c300a1c..1d489b60ade 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.cc
@@ -19,7 +19,8 @@ DataReductionProxyData::DataReductionProxyData()
lite_page_received_(false),
lofi_policy_received_(false),
lofi_received_(false),
- effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {}
+ effective_connection_type_(net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
+ connection_type_(net::NetworkChangeNotifier::CONNECTION_UNKNOWN) {}
DataReductionProxyData::~DataReductionProxyData() {}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
index 36697b7d31d..a87b465b740 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/optional.h"
#include "base/supports_user_data.h"
+#include "net/base/network_change_notifier.h"
#include "net/nqe/effective_connection_type.h"
#include "url/gurl.h"
@@ -95,6 +96,16 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
effective_connection_type_ = effective_connection_type;
}
+ // The connection type (Wifi, 2G, 3G, 4G, None, etc) as reported by the
+ // NetworkChangeNotifier. Only set for main frame requests.
+ net::NetworkChangeNotifier::ConnectionType connection_type() const {
+ return connection_type_;
+ }
+ void set_connection_type(
+ const net::NetworkChangeNotifier::ConnectionType connection_type) {
+ connection_type_ = connection_type;
+ }
+
// An identifier that is guaranteed to be unique to each page load during a
// data saver session. Only present on main frame requests.
const base::Optional<uint64_t>& page_id() const { return page_id_; }
@@ -153,6 +164,10 @@ class DataReductionProxyData : public base::SupportsUserData::Data {
// set for main frame requests only.
net::EffectiveConnectionType effective_connection_type_;
+ // The connection type (Wifi, 2G, 3G, 4G, None, etc) as reported by the
+ // NetworkChangeNotifier. Only set for main frame requests.
+ net::NetworkChangeNotifier::ConnectionType connection_type_;
+
// An identifier that is guaranteed to be unique to each page load during a
// data saver session. Only present on main frame requests.
base::Optional<uint64_t> page_id_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
index 826be5e713c..447b117f21b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_data_unittest.cc
@@ -83,13 +83,12 @@ TEST_F(DataReductionProxyDataTest, AddToURLRequest) {
std::unique_ptr<net::URLRequest> fake_request(context->CreateRequest(
GURL("http://www.google.com"), net::RequestPriority::IDLE, nullptr,
TRAFFIC_ANNOTATION_FOR_TESTS));
- DataReductionProxyData* data =
- DataReductionProxyData::GetData(*fake_request.get());
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*fake_request);
EXPECT_FALSE(data);
data =
DataReductionProxyData::GetDataAndCreateIfNecessary(fake_request.get());
EXPECT_TRUE(data);
- data = DataReductionProxyData::GetData(*fake_request.get());
+ data = DataReductionProxyData::GetData(*fake_request);
EXPECT_TRUE(data);
DataReductionProxyData* data2 =
DataReductionProxyData::GetDataAndCreateIfNecessary(fake_request.get());
@@ -150,7 +149,7 @@ TEST_F(DataReductionProxyDataTest, ClearData) {
DataReductionProxyData::GetDataAndCreateIfNecessary(fake_request.get());
EXPECT_TRUE(data);
DataReductionProxyData::ClearData(fake_request.get());
- data = DataReductionProxyData::GetData(*fake_request.get());
+ data = DataReductionProxyData::GetData(*fake_request);
EXPECT_FALSE(data);
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
index c1d8e963e3d..21a0b7bafbb 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.cc
@@ -45,7 +45,6 @@ DataReductionProxyDelegate::DataReductionProxyDelegate(
event_creator_(event_creator),
bypass_stats_(bypass_stats),
tick_clock_(base::DefaultTickClock::GetInstance()),
- first_data_saver_request_recorded_(false),
io_data_(nullptr),
net_log_(net_log) {
DCHECK(config_);
@@ -78,7 +77,7 @@ void DataReductionProxyDelegate::OnResolveProxy(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(result);
DCHECK(result->is_empty() || result->is_direct() ||
- !config_->IsDataReductionProxy(result->proxy_server(), nullptr));
+ !config_->FindConfiguredDataReductionProxy(result->proxy_server()));
if (!params::IsIncludedInQuicFieldTrial())
RecordQuicProxyStatus(QUIC_PROXY_DISABLED_VIA_FIELD_TRIAL);
@@ -143,25 +142,19 @@ void DataReductionProxyDelegate::OnResolveProxy(
result->OverrideProxyList(data_reduction_proxy_info.proxy_list());
GetAlternativeProxy(url, proxy_retry_info, result);
-
- if (!first_data_saver_request_recorded_) {
- UMA_HISTOGRAM_MEDIUM_TIMES(
- "DataReductionProxy.TimeToFirstDataSaverRequest",
- tick_clock_->NowTicks() - last_network_change_time_);
- first_data_saver_request_recorded_ = true;
- }
}
DCHECK_GT(ResourceTypeProvider::CONTENT_TYPE_MAX, content_type);
- UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.ResourceContentType",
- content_type,
- ResourceTypeProvider::CONTENT_TYPE_MAX);
if (config_->enabled_by_user_and_reachable() &&
url.SchemeIs(url::kHttpScheme) && !net::IsLocalhost(url) &&
!params::IsIncludedInHoldbackFieldTrial()) {
UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.ConfigService.HTTPRequests",
!config_->GetProxiesForHttp().empty());
+ if (content_type == ResourceTypeProvider::CONTENT_TYPE_MAIN_FRAME) {
+ UMA_HISTOGRAM_BOOLEAN("DataReductionProxy.ConfigService.MainFrames",
+ !config_->GetProxiesForHttp().empty());
+ }
}
}
@@ -169,7 +162,7 @@ void DataReductionProxyDelegate::OnFallback(const net::ProxyServer& bad_proxy,
int net_error) {
DCHECK(thread_checker_.CalledOnValidThread());
if (bad_proxy.is_valid() &&
- config_->IsDataReductionProxy(bad_proxy, nullptr)) {
+ config_->FindConfiguredDataReductionProxy(bad_proxy)) {
event_creator_->AddProxyFallbackEvent(net_log_, bad_proxy.ToURI(),
net_error);
}
@@ -194,7 +187,7 @@ void DataReductionProxyDelegate::GetAlternativeProxy(
net::ProxyServer resolved_proxy_server = result->proxy_server();
DCHECK(resolved_proxy_server.is_valid());
- DCHECK(config_->IsDataReductionProxy(resolved_proxy_server, nullptr));
+ DCHECK(config_->FindConfiguredDataReductionProxy(resolved_proxy_server));
if (!url.is_valid() || !url.SchemeIsHTTPOrHTTPS() ||
url.SchemeIsCryptographic()) {
@@ -247,7 +240,6 @@ void DataReductionProxyDelegate::RecordQuicProxyStatus(
void DataReductionProxyDelegate::OnIPAddressChanged() {
DCHECK(thread_checker_.CalledOnValidThread());
- first_data_saver_request_recorded_ = false;
last_network_change_time_ = tick_clock_->NowTicks();
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
index 15e73f95863..3f94d38502b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate.h
@@ -94,11 +94,6 @@ class DataReductionProxyDelegate
// Tick clock used for obtaining the current time.
const base::TickClock* tick_clock_;
- // True if the metrics related to the first request whose resolved proxy was a
- // data saver proxy has been recorded. |first_data_saver_request_recorded_| is
- // reset to false on IP address change events.
- bool first_data_saver_request_recorded_;
-
// Set to the time when last IP address change event was received, or the time
// of initialization of |this|, whichever is later.
base::TimeTicks last_network_change_time_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
index 2b6444db90e..795fde3cd19 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_delegate_unittest.cc
@@ -216,7 +216,7 @@ class DataReductionProxyDelegateTest : public testing::Test {
net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
net::MockRead(net::SYNCHRONOUS, net::OK)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory_.AddSocketDataProvider(&socket);
net::TestDelegate delegate;
@@ -707,7 +707,7 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor200) {
std::unique_ptr<net::URLRequest> request =
FetchURLRequest(GURL("http://example.com/path/"), nullptr,
- test.DrpResponseHeaders.c_str(), 1000);
+ test.DrpResponseHeaders, 1000);
EXPECT_EQ(request->GetTotalReceivedBytes(),
total_received_bytes() - baseline_received_bytes);
@@ -724,56 +724,6 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor200) {
}
}
-TEST_F(DataReductionProxyDelegateTest, TimeToFirstHttpDataSaverRequest) {
- base::SimpleTestTickClock tick_clock;
- proxy_delegate()->SetTickClockForTesting(&tick_clock);
-
- const char kResponseHeaders[] =
- "HTTP/1.1 200 OK\r\n"
- "Via: 1.1 Chrome-Compression-Proxy-Suffix\r\n"
- "Content-Length: 10\r\n\r\n";
-
- params()->UseNonSecureProxiesForHttp();
- {
- base::HistogramTester histogram_tester;
- base::TimeDelta advance_time(base::TimeDelta::FromSeconds(1));
- tick_clock.Advance(advance_time);
-
- FetchURLRequest(GURL("http://example.com/path/"), nullptr, kResponseHeaders,
- 10);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.TimeToFirstDataSaverRequest",
- advance_time.InMilliseconds(), 1);
-
- // Second request should not result in recording of UMA.
- FetchURLRequest(GURL("http://example.com/path/"), nullptr, kResponseHeaders,
- 10);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.TimeToFirstDataSaverRequest", 1);
- }
-
- {
- base::HistogramTester histogram_tester;
- // Third request should result in recording of UMA due to change in IP.
- base::TimeDelta advance_time(base::TimeDelta::FromSeconds(2));
- net::NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests();
- base::RunLoop().RunUntilIdle();
-
- tick_clock.Advance(advance_time);
- FetchURLRequest(GURL("http://example.com/path/"), nullptr, kResponseHeaders,
- 10);
- histogram_tester.ExpectUniqueSample(
- "DataReductionProxy.TimeToFirstDataSaverRequest",
- advance_time.InMilliseconds(), 1);
-
- // Fourth request should not result in recording of UMA.
- FetchURLRequest(GURL("http://example.com/path/"), nullptr, kResponseHeaders,
- 10);
- histogram_tester.ExpectTotalCount(
- "DataReductionProxy.TimeToFirstDataSaverRequest", 1);
- }
-}
-
TEST_F(DataReductionProxyDelegateTest, Holdback) {
const char kResponseHeaders[] =
"HTTP/1.1 200 OK\r\n"
@@ -827,9 +777,8 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeFor304) {
int64_t baseline_received_bytes = total_received_bytes();
int64_t baseline_original_received_bytes = total_original_received_bytes();
- std::unique_ptr<net::URLRequest> request =
- FetchURLRequest(GURL("http://example.com/path/"), nullptr,
- test.DrpResponseHeaders.c_str(), 0);
+ std::unique_ptr<net::URLRequest> request = FetchURLRequest(
+ GURL("http://example.com/path/"), nullptr, test.DrpResponseHeaders, 0);
EXPECT_EQ(request->GetTotalReceivedBytes(),
total_received_bytes() - baseline_received_bytes);
@@ -852,7 +801,7 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeForWriteError) {
net::MockWrite("GET http://example.com/path/ HTTP/1.1\r\n"
"Host: example.com\r\n"),
net::MockWrite(net::ASYNC, net::ERR_ABORTED)};
- net::StaticSocketDataProvider socket(nullptr, 0, writes, arraysize(writes));
+ net::StaticSocketDataProvider socket(base::span<net::MockRead>(), writes);
mock_socket_factory()->AddSocketDataProvider(&socket);
net::TestDelegate delegate;
@@ -875,7 +824,7 @@ TEST_F(DataReductionProxyDelegateTest, OnCompletedSizeForReadError) {
params()->UseNonSecureProxiesForHttp();
net::MockRead reads[] = {net::MockRead("HTTP/1.1 "),
net::MockRead(net::ASYNC, net::ERR_ABORTED)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket);
net::TestDelegate delegate;
@@ -981,7 +930,7 @@ TEST_F(DataReductionProxyDelegateTest, PartialRangeSavings) {
test.response_headers.size()),
net::MockRead(net::ASYNC, response_body.data(), response_body.size()),
net::MockRead(net::SYNCHRONOUS, net::ERR_ABORTED)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket);
net::TestDelegate test_delegate;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
index 115b30925ad..2ff1a8cac8f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_interceptor_unittest.cc
@@ -210,7 +210,7 @@ class DataReductionProxyInterceptorWithServerTest : public testing::Test {
void SetUp() override {
base::FilePath root_path, proxy_file_path, direct_file_path;
- PathService::Get(base::DIR_SOURCE_ROOT, &root_path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &root_path);
proxy_file_path = root_path.AppendASCII(
"components/test/data/data_reduction_proxy/proxy");
direct_file_path = root_path.AppendASCII(
@@ -373,7 +373,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithoutRetry) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket_data_provider);
std::unique_ptr<net::URLRequest> request =
@@ -395,7 +395,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithoutRetry) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider(
- redirect_mock_reads, arraysize(redirect_mock_reads), nullptr, 0);
+ redirect_mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&redirect_socket_data_provider);
// The response after the redirect comes through proxy and should not be
@@ -406,7 +406,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithoutRetry) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider response_socket_data_provider(
- response_mock_reads, arraysize(response_mock_reads), nullptr, 0);
+ response_mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&response_socket_data_provider);
std::unique_ptr<net::URLRequest> request =
@@ -430,7 +430,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, URLRedirectCycle) {
MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_1(
- redirect_mock_reads_1, arraysize(redirect_mock_reads_1), nullptr, 0);
+ redirect_mock_reads_1, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(
&redirect_socket_data_provider_1);
@@ -441,7 +441,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, URLRedirectCycle) {
MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_2(
- redirect_mock_reads_2, arraysize(redirect_mock_reads_2), nullptr, 0);
+ redirect_mock_reads_2, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(
&redirect_socket_data_provider_2);
@@ -453,7 +453,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, URLRedirectCycle) {
MockRead(""), MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_3(
- redirect_mock_reads_3, arraysize(redirect_mock_reads_3), nullptr, 0);
+ redirect_mock_reads_3, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(
&redirect_socket_data_provider_3);
@@ -463,7 +463,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, URLRedirectCycle) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider_4(
- redirect_mock_reads_4, arraysize(redirect_mock_reads_4), nullptr, 0);
+ redirect_mock_reads_4, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(
&redirect_socket_data_provider_4);
@@ -488,7 +488,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithBypassAndRetry) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider initial_socket_data_provider(
- initial_mock_reads, arraysize(initial_mock_reads), nullptr, 0);
+ initial_mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&initial_socket_data_provider);
// The retry after the bypass is successful.
@@ -498,7 +498,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, ResponseWithBypassAndRetry) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider retry_socket_data_provider(
- retry_mock_reads, arraysize(retry_mock_reads), nullptr, 0);
+ retry_mock_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&retry_socket_data_provider);
std::unique_ptr<net::URLRequest> request =
@@ -542,8 +542,8 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectWithBypassAndRetry) {
std::vector<std::unique_ptr<net::SocketDataProvider>> socket_data_providers;
for (MockRead* mock_reads : mock_reads_array) {
socket_data_providers.push_back(
- std::make_unique<net::StaticSocketDataProvider>(mock_reads, 3, nullptr,
- 0));
+ std::make_unique<net::StaticSocketDataProvider>(
+ base::make_span(mock_reads, 3), base::span<net::MockWrite>()));
mock_socket_factory()->AddSocketDataProvider(
socket_data_providers.back().get());
}
@@ -575,7 +575,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectChainToHttps) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider first_redirect_socket(
- first_redirect_reads, arraysize(first_redirect_reads), nullptr, 0);
+ first_redirect_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&first_redirect_socket);
// Receive the response for https://play.google.com.
@@ -585,7 +585,7 @@ TEST_F(DataReductionProxyInterceptorEndToEndTest, RedirectChainToHttps) {
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider https_response_socket(
- https_response_reads, arraysize(https_response_reads), nullptr, 0);
+ https_response_reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&https_response_socket);
net::SSLSocketDataProvider https_response_ssl_socket(net::SYNCHRONOUS,
net::OK);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
index 050f4c86a1d..ac85b385e5e 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.cc
@@ -216,7 +216,7 @@ void DataReductionProxyIOData::InitializeOnIOThread() {
network_properties_manager_.get());
bypass_stats_->InitializeOnIOThread();
proxy_delegate_->InitializeOnIOThread(this);
- if (config_client_.get())
+ if (config_client_)
config_client_->InitializeOnIOThread(url_request_context_getter_);
if (ui_task_runner_->BelongsToCurrentThread()) {
service_->SetIOData(weak_factory_.GetWeakPtr());
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
index 7342956be62..a8975739d80 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data_unittest.cc
@@ -114,7 +114,7 @@ TEST_F(DataReductionProxyIODataTest, TestConstruction) {
// Check that the SimpleURLRequestContextGetter uses vanilla HTTP.
net::URLRequestContext* request_context =
- io_data->basic_url_request_context_getter_.get()->GetURLRequestContext();
+ io_data->basic_url_request_context_getter_->GetURLRequestContext();
const net::HttpNetworkSession::Params* http_params =
request_context->GetNetworkSessionParams();
EXPECT_FALSE(http_params->enable_http2);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
index edf466aff81..ee1d2e9dac6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
@@ -20,8 +20,8 @@ namespace data_reduction_proxy {
DataReductionProxyRequestType GetDataReductionProxyRequestType(
const net::URLRequest& request,
- const net::ProxyConfig& data_reduction_proxy_config,
- const DataReductionProxyConfig& config) {
+ const net::ProxyConfig& proxy_config,
+ const DataReductionProxyConfig& data_reduction_proxy_config) {
if (request.url().SchemeIs(url::kHttpsScheme))
return HTTPS;
if (!request.url().SchemeIs(url::kHttpScheme)) {
@@ -41,9 +41,10 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
if ((request.load_flags() & net::LOAD_BYPASS_PROXY) ||
(request.proxy_server().is_valid() &&
!request.proxy_server().is_direct() &&
- !config.IsDataReductionProxy(request.proxy_server(), nullptr)) ||
- config.IsBypassedByDataReductionProxyLocalRules(
- request, data_reduction_proxy_config)) {
+ !data_reduction_proxy_config.FindConfiguredDataReductionProxy(
+ request.proxy_server())) ||
+ data_reduction_proxy_config.IsBypassedByDataReductionProxyLocalRules(
+ request, proxy_config)) {
return SHORT_BYPASS;
}
@@ -53,8 +54,8 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
}
base::TimeDelta bypass_delay;
- if (config.AreDataReductionProxiesBypassed(
- request, data_reduction_proxy_config, &bypass_delay)) {
+ if (data_reduction_proxy_config.AreDataReductionProxiesBypassed(
+ request, proxy_config, &bypass_delay)) {
if (bypass_delay > base::TimeDelta::FromSeconds(kLongBypassDelayInSeconds))
return LONG_BYPASS;
return SHORT_BYPASS;
@@ -68,7 +69,8 @@ DataReductionProxyRequestType GetDataReductionProxyRequestType(
// if they came through the Data Reduction Proxy.
if (request.response_headers() &&
request.response_headers()->response_code() == net::HTTP_NOT_MODIFIED &&
- config.WasDataReductionProxyUsed(&request, nullptr)) {
+ data_reduction_proxy_config.FindConfiguredDataReductionProxy(
+ request.proxy_server())) {
return VIA_DATA_REDUCTION_PROXY;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h
index 9c52af5940d..d06dd623100 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h
@@ -47,8 +47,8 @@ enum DataReductionProxyRequestType {
// Returns DataReductionProxyRequestType for |request|.
DataReductionProxyRequestType GetDataReductionProxyRequestType(
const net::URLRequest& request,
- const net::ProxyConfig& data_reduction_proxy_config,
- const DataReductionProxyConfig& config);
+ const net::ProxyConfig& proxy_config,
+ const DataReductionProxyConfig& data_reduction_proxy_config);
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
index 024b60f6b4a..b68347d63fb 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
@@ -190,7 +190,7 @@ TEST(ChromeNetworkDailyDataSavingMetricsTest,
MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory.AddSocketDataProvider(&socket_data_provider);
net::TestDelegate delegate;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
index ddd898a4a15..092520bc736 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.cc
@@ -4,8 +4,11 @@
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h"
+#include <algorithm>
+
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
+#include "net/base/proxy_server.h"
namespace data_reduction_proxy {
@@ -34,15 +37,58 @@ DataReductionProxyMutableConfigValues::proxies_for_http() const {
return proxies_for_http_;
}
+base::Optional<DataReductionProxyTypeInfo>
+DataReductionProxyMutableConfigValues::FindConfiguredDataReductionProxy(
+ const net::ProxyServer& proxy_server) const {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+ base::Optional<DataReductionProxyTypeInfo> info =
+ DataReductionProxyParams::FindConfiguredProxyInVector(proxies_for_http(),
+ proxy_server);
+ if (info)
+ return info;
+
+ for (const auto& recent_proxies : recently_configured_proxy_lists_) {
+ base::Optional<DataReductionProxyTypeInfo> recent_info =
+ DataReductionProxyParams::FindConfiguredProxyInVector(recent_proxies,
+ proxy_server);
+ if (recent_info)
+ return recent_info;
+ }
+ return base::nullopt;
+}
+
void DataReductionProxyMutableConfigValues::UpdateValues(
- const std::vector<DataReductionProxyServer>& proxies_for_http) {
+ const std::vector<DataReductionProxyServer>& new_proxies_for_http) {
DCHECK(thread_checker_.CalledOnValidThread());
- proxies_for_http_ = proxies_for_http;
+
+ std::vector<DataReductionProxyServer> previous_proxies = proxies_for_http();
+
+ proxies_for_http_.clear();
+ std::remove_copy_if(new_proxies_for_http.begin(), new_proxies_for_http.end(),
+ std::back_inserter(proxies_for_http_),
+ [](const DataReductionProxyServer& proxy) {
+ return !proxy.proxy_server().is_valid() ||
+ proxy.proxy_server().is_direct();
+ });
+
+ if (previous_proxies.empty() || proxies_for_http() == previous_proxies) {
+ // There's no point in keeping track of an empty recent list of proxies or a
+ // list of proxies that's identical to the currently configured list.
+ return;
+ }
+
+ // Push |previous_proxies| onto the front of the
+ // |recently_configured_proxy_lists_|.
+ std::move_backward(std::begin(recently_configured_proxy_lists_),
+ std::end(recently_configured_proxy_lists_) - 1,
+ std::end(recently_configured_proxy_lists_));
+ recently_configured_proxy_lists_[0] = std::move(previous_proxies);
}
void DataReductionProxyMutableConfigValues::Invalidate() {
DCHECK(thread_checker_.CalledOnValidThread());
- proxies_for_http_.clear();
+ UpdateValues(std::vector<DataReductionProxyServer>());
}
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
index 145db2b19e1..ec52878f42f 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values.h
@@ -8,10 +8,14 @@
#include <vector>
#include "base/macros.h"
+#include "base/optional.h"
#include "base/threading/thread_checker.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h"
-#include "net/base/proxy_server.h"
-#include "url/gurl.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
+
+namespace net {
+class ProxyServer;
+}
namespace data_reduction_proxy {
@@ -26,16 +30,17 @@ class DataReductionProxyMutableConfigValues
~DataReductionProxyMutableConfigValues() override;
// Updates |proxies_for_http_| with the provided values.
- // Virtual for testing.
- virtual void UpdateValues(
- const std::vector<DataReductionProxyServer>& proxies_for_http);
+ void UpdateValues(
+ const std::vector<DataReductionProxyServer>& new_proxies_for_http);
// Invalidates |this| by clearing the stored Data Reduction Proxy servers.
void Invalidate();
- // Overrides of |DataReductionProxyConfigValues|
+ // Overrides of |DataReductionProxyConfigValues|.
const std::vector<DataReductionProxyServer>& proxies_for_http()
const override;
+ base::Optional<DataReductionProxyTypeInfo> FindConfiguredDataReductionProxy(
+ const net::ProxyServer& proxy_server) const override;
private:
std::vector<DataReductionProxyServer> proxies_for_http_;
@@ -45,6 +50,16 @@ class DataReductionProxyMutableConfigValues
// ones specified from the Data Saver API.
const bool use_override_proxies_for_http_;
+ // Keep track of some of the most recently configured proxy lists. This means
+ // that any requests that were in-progress to a Data Reduction Proxy when the
+ // list of proxies to use is changed can still be recognized as using a Data
+ // Reduction Proxy for the purposes of applying bypass logic and recording
+ // metrics. The number 2 is used because that way the proxy server used by an
+ // in-progress request can still be recognized if both the list of proxy
+ // servers to use changes and the proxy config gets invalidated before that
+ // request's response is processed.
+ std::vector<DataReductionProxyServer> recently_configured_proxy_lists_[2];
+
// Enforce usage on the IO thread.
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc
index bfea492ed7d..61b6ef89a19 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_mutable_config_values_unittest.cc
@@ -8,9 +8,11 @@
#include <vector>
#include "base/command_line.h"
+#include "base/optional.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "net/base/proxy_server.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,6 +21,15 @@ namespace data_reduction_proxy {
namespace {
+void ExpectTypeInfo(
+ base::Optional<DataReductionProxyTypeInfo> type_info,
+ const std::vector<DataReductionProxyServer>& expected_proxy_servers,
+ size_t expected_proxy_index) {
+ ASSERT_TRUE(type_info);
+ EXPECT_EQ(expected_proxy_servers, type_info->proxy_servers);
+ EXPECT_EQ(expected_proxy_index, type_info->proxy_index);
+}
+
class DataReductionProxyMutableConfigValuesTest : public testing::Test {
public:
DataReductionProxyMutableConfigValuesTest() {}
@@ -54,12 +65,34 @@ TEST_F(DataReductionProxyMutableConfigValuesTest, UpdateValuesAndInvalidate) {
proxies_for_http.push_back(DataReductionProxyServer(
second_proxy_server, ProxyServer::UNSPECIFIED_TYPE));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_proxy_server));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_proxy_server));
+
mutable_config_values()->UpdateValues(proxies_for_http);
EXPECT_EQ(proxies_for_http, mutable_config_values()->proxies_for_http());
+ // The configured proxies should be recognized as Data Reduction Proxies.
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_proxy_server),
+ proxies_for_http, 0U);
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_proxy_server),
+ proxies_for_http, 1U);
+
// Invalidation must clear out the list of proxies and their properties.
mutable_config_values()->Invalidate();
EXPECT_TRUE(mutable_config_values()->proxies_for_http().empty());
+
+ // The previously configured proxies should still be recognized as Data
+ // Reduction Proxies, even though the config was invalidated.
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_proxy_server),
+ proxies_for_http, 0U);
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_proxy_server),
+ proxies_for_http, 1U);
}
// Tests if HTTP proxies are overridden when |kDataReductionProxyHttpProxies|
@@ -70,18 +103,32 @@ TEST_F(DataReductionProxyMutableConfigValuesTest, OverrideProxiesForHttp) {
"http://override-first.net;http://override-second.net");
Init();
+ net::ProxyServer first_override_proxy_server = net::ProxyServer::FromURI(
+ "http://override-first.net", net::ProxyServer::SCHEME_HTTP);
+ net::ProxyServer second_override_proxy_server = net::ProxyServer::FromURI(
+ "http://override-second.net", net::ProxyServer::SCHEME_HTTP);
+
+ net::ProxyServer first_proxy_server(net::ProxyServer::FromURI(
+ "http://first.net", net::ProxyServer::SCHEME_HTTP));
+ net::ProxyServer second_proxy_server = net::ProxyServer::FromURI(
+ "http://second.net", net::ProxyServer::SCHEME_HTTP);
+
EXPECT_EQ(std::vector<DataReductionProxyServer>(),
mutable_config_values()->proxies_for_http());
- std::vector<DataReductionProxyServer> proxies_for_http;
+ // No proxy servers should be recognized as Data Reduction Proxies.
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_override_proxy_server));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_override_proxy_server));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_proxy_server));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_proxy_server));
- net::ProxyServer first_proxy_server(net::ProxyServer::FromURI(
- "http://first.net", net::ProxyServer::SCHEME_HTTP));
+ std::vector<DataReductionProxyServer> proxies_for_http;
proxies_for_http.push_back(
DataReductionProxyServer(first_proxy_server, ProxyServer::CORE));
-
- net::ProxyServer second_proxy_server = net::ProxyServer::FromURI(
- "http://second.net", net::ProxyServer::SCHEME_HTTP);
proxies_for_http.push_back(DataReductionProxyServer(
second_proxy_server, ProxyServer::UNSPECIFIED_TYPE));
@@ -89,20 +136,48 @@ TEST_F(DataReductionProxyMutableConfigValuesTest, OverrideProxiesForHttp) {
std::vector<DataReductionProxyServer> expected_override_proxies_for_http;
expected_override_proxies_for_http.push_back(DataReductionProxyServer(
- net::ProxyServer::FromURI("http://override-first.net",
- net::ProxyServer::SCHEME_HTTP),
- ProxyServer::UNSPECIFIED_TYPE));
+ first_override_proxy_server, ProxyServer::UNSPECIFIED_TYPE));
expected_override_proxies_for_http.push_back(DataReductionProxyServer(
- net::ProxyServer::FromURI("http://override-second.net",
- net::ProxyServer::SCHEME_HTTP),
- ProxyServer::UNSPECIFIED_TYPE));
+ second_override_proxy_server, ProxyServer::UNSPECIFIED_TYPE));
EXPECT_EQ(expected_override_proxies_for_http,
mutable_config_values()->proxies_for_http());
+ // The overriding proxy servers should be recognized as Data Reduction
+ // Proxies.
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_override_proxy_server),
+ expected_override_proxies_for_http, 0U);
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_override_proxy_server),
+ expected_override_proxies_for_http, 1U);
+
+ // The proxy servers that were overriden should not be recognized as Data
+ // Reduction Proxies.
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_proxy_server));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_proxy_server));
+
// Invalidation must clear out the list of proxies and their properties.
mutable_config_values()->Invalidate();
EXPECT_TRUE(mutable_config_values()->proxies_for_http().empty());
+
+ // The overriding proxy servers should be recognized as Data Reduction
+ // Proxies.
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_override_proxy_server),
+ expected_override_proxies_for_http, 0U);
+ ExpectTypeInfo(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_override_proxy_server),
+ expected_override_proxies_for_http, 1U);
+
+ // The proxy servers that were overriden should not be recognized as Data
+ // Reduction Proxies.
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ first_proxy_server));
+ EXPECT_FALSE(mutable_config_values()->FindConfiguredDataReductionProxy(
+ second_proxy_server));
}
// Tests if HTTP proxies are overridden when |kDataReductionProxy| or
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
index e34988e8ec3..da6a0a7eb66 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -26,6 +26,7 @@
#include "components/data_reduction_proxy/core/common/lofi_decider.h"
#include "net/base/load_flags.h"
#include "net/base/mime_util.h"
+#include "net/base/network_change_notifier.h"
#include "net/base/proxy_server.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
@@ -358,8 +359,8 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
using_data_reduction_proxy = false;
} else if (proxy_info.proxy_server().host_port_pair().IsEmpty()) {
using_data_reduction_proxy = false;
- } else if (!data_reduction_proxy_config_->IsDataReductionProxy(
- proxy_info.proxy_server(), nullptr)) {
+ } else if (!data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
+ proxy_info.proxy_server())) {
using_data_reduction_proxy = false;
}
@@ -391,6 +392,8 @@ void DataReductionProxyNetworkDelegate::OnBeforeSendHeadersInternal(
->network_quality_estimator()
->GetEffectiveConnectionType());
}
+ data->set_connection_type(
+ net::NetworkChangeNotifier::GetConnectionType());
// Generate a page ID for main frame requests that don't already have one.
// TODO(ryansturm): remove LOAD_MAIN_FRAME_DEPRECATED from d_r_p.
// crbug.com/709621
@@ -614,7 +617,7 @@ void DataReductionProxyNetworkDelegate::RecordContentLength(
if (data_reduction_proxy_io_data_ && data_reduction_proxy_bypass_stats_) {
// Record BypassedBytes histograms for the request.
- data_reduction_proxy_bypass_stats_->RecordBytesHistograms(
+ data_reduction_proxy_bypass_stats_->RecordBypassedBytesHistograms(
request, data_reduction_proxy_io_data_->IsEnabled(),
configurator_->GetProxyConfig());
}
@@ -633,8 +636,8 @@ bool DataReductionProxyNetworkDelegate::WasEligibleWithoutHoldback(
const net::ProxyRetryInfoMap& proxy_retry_info) const {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(proxy_info.is_empty() || proxy_info.is_direct() ||
- !data_reduction_proxy_config_->IsDataReductionProxy(
- proxy_info.proxy_server(), nullptr));
+ !data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
+ proxy_info.proxy_server()));
if (!util::EligibleForDataReductionProxy(proxy_info, request.url(),
request.method())) {
return false;
@@ -655,8 +658,8 @@ void DataReductionProxyNetworkDelegate::MaybeAddBrotliToAcceptEncodingHeader(
// This method should be called only when the resolved proxy was a data
// saver proxy.
- DCHECK(data_reduction_proxy_config_->IsDataReductionProxy(
- proxy_info.proxy_server(), nullptr));
+ DCHECK(data_reduction_proxy_config_->FindConfiguredDataReductionProxy(
+ proxy_info.proxy_server()));
DCHECK(request.url().is_valid());
DCHECK(!request.url().SchemeIsCryptographic());
DCHECK(request.url().SchemeIsHTTPOrHTTPS());
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
index cbe18a6957c..e9a1f9deb5b 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -52,7 +52,7 @@ class DataReductionProxyNetworkDelegate : public net::LayeredNetworkDelegate {
public:
// Provides an additional proxy configuration that can be consulted after
// proxy resolution. Used to get the Data Reduction Proxy config and give it
- // to the OnResolveProxyHandler and RecordBytesHistograms.
+ // to the OnResolveProxyHandler and RecordBypassedBytesHistograms.
typedef base::Callback<const net::ProxyConfig&()> ProxyConfigGetter;
// Constructs a DataReductionProxyNetworkDelegate object with the given
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
index b0cafc450aa..1c30339f2f6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -430,9 +430,8 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
}
EXPECT_FALSE(socket_);
- socket_ = std::make_unique<net::StaticSocketDataProvider>(
- reads_list->data(), reads_list->size(), writes_list->data(),
- writes_list->size());
+ socket_ = std::make_unique<net::StaticSocketDataProvider>(*reads_list,
+ *writes_list);
mock_socket_factory_->AddSocketDataProvider(socket_.get());
}
@@ -481,7 +480,7 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
net::MockRead reads[] = {net::MockRead(response_headers.c_str()),
net::MockRead(response_body.c_str()),
net::MockRead(net::SYNCHRONOUS, net::OK)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory_->AddSocketDataProvider(&socket);
net::TestDelegate delegate;
@@ -501,7 +500,7 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
// Get the path of data directory.
const size_t kDefaultBufferSize = 4096;
base::FilePath data_dir;
- PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &data_dir);
data_dir = data_dir.AppendASCII("net");
data_dir = data_dir.AppendASCII("data");
data_dir = data_dir.AppendASCII("filter_unittests");
@@ -594,8 +593,7 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
}
net::MockWrite writes[] = {net::MockWrite(mock_write.c_str())};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), writes,
- arraysize(writes));
+ net::StaticSocketDataProvider socket(reads, writes);
mock_socket_factory_->AddSocketDataProvider(&socket);
net::TestDelegate delegate;
@@ -707,12 +705,10 @@ class DataReductionProxyNetworkDelegateTest : public testing::Test {
std::unique_ptr<net::StaticSocketDataProvider> socket;
if (!redirect_once) {
- socket = std::make_unique<net::StaticSocketDataProvider>(
- reads, arraysize(reads), writes, arraysize(writes));
+ socket = std::make_unique<net::StaticSocketDataProvider>(reads, writes);
} else {
- socket = std::make_unique<net::StaticSocketDataProvider>(
- redirect_reads, arraysize(redirect_reads), redirect_writes,
- arraysize(redirect_writes));
+ socket = std::make_unique<net::StaticSocketDataProvider>(redirect_reads,
+ redirect_writes);
}
mock_socket_factory_->AddSocketDataProvider(socket.get());
@@ -911,15 +907,15 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
GURL(kTestURL), net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(config()->ShouldAcceptServerPreview(
- *fake_request.get(), test_previews_decider));
+ *fake_request, test_previews_decider));
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
VerifyHeaders(is_data_reduction_proxy_enabled[i], true, headers);
- VerifyDataReductionProxyData(
- *fake_request, is_data_reduction_proxy_enabled[i],
- config()->ShouldAcceptServerPreview(*fake_request.get(),
- test_previews_decider));
+ VerifyDataReductionProxyData(*fake_request,
+ is_data_reduction_proxy_enabled[i],
+ config()->ShouldAcceptServerPreview(
+ *fake_request, test_previews_decider));
}
{
@@ -994,13 +990,13 @@ TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) {
GURL(kTestURL), net::IDLE, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME_DEPRECATED);
lofi_decider()->SetIsUsingLoFi(config()->ShouldAcceptServerPreview(
- *fake_request.get(), test_previews_decider));
+ *fake_request, test_previews_decider));
NotifyNetworkDelegate(fake_request.get(), data_reduction_proxy_info,
proxy_retry_info, &headers);
- VerifyDataReductionProxyData(
- *fake_request, is_data_reduction_proxy_enabled[i],
- config()->ShouldAcceptServerPreview(*fake_request.get(),
- test_previews_decider));
+ VerifyDataReductionProxyData(*fake_request,
+ is_data_reduction_proxy_enabled[i],
+ config()->ShouldAcceptServerPreview(
+ *fake_request, test_previews_decider));
}
}
}
@@ -1064,8 +1060,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RequestDataConfigurations) {
&headers);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
- DataReductionProxyData* data =
- DataReductionProxyData::GetData(*request.get());
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
if (!test.used_data_reduction_proxy) {
EXPECT_FALSE(data);
} else {
@@ -1124,8 +1119,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
net::ProxyRetryInfoMap proxy_retry_info;
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
- DataReductionProxyData* data =
- DataReductionProxyData::GetData(*request.get());
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
if (!test.data_reduction_proxy_enabled || !test.used_direct) {
EXPECT_FALSE(data);
} else {
@@ -1170,8 +1164,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info,
&headers_original);
- DataReductionProxyData* data =
- DataReductionProxyData::GetData(*request.get());
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
EXPECT_TRUE(data);
EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
@@ -1186,7 +1179,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
// Simulate a redirect even though the same URL is used. Should clear
// DataReductionProxyData.
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
- data = DataReductionProxyData::GetData(*request.get());
+ data = DataReductionProxyData::GetData(*request);
EXPECT_FALSE(data && data->used_data_reduction_proxy());
// Call NotifyBeforeSendHeaders again with different proxy info to check that
@@ -1203,7 +1196,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest, RedirectRequestDataCleared) {
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info,
&headers_redirect);
- data = DataReductionProxyData::GetData(*request.get());
+ data = DataReductionProxyData::GetData(*request);
EXPECT_FALSE(data);
}
@@ -1447,8 +1440,8 @@ TEST_F(DataReductionProxyNetworkDelegateTest, DetailedNetHistograms) {
ssl_socket_data_provider());
}
- std::string via_header = "";
- std::string ocl_header = "";
+ std::string via_header;
+ std::string ocl_header;
if (test.proxy_config == USE_INSECURE_PROXY) {
via_header = "Via: 1.1 Chrome-Compression-Proxy\r\n";
@@ -1815,8 +1808,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
&headers);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
- DataReductionProxyData* data =
- DataReductionProxyData::GetData(*request.get());
+ DataReductionProxyData* data = DataReductionProxyData::GetData(*request);
EXPECT_TRUE(data_reduction_proxy_info.is_http());
EXPECT_EQ(++page_id, data->page_id().value());
@@ -1832,14 +1824,14 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
&headers);
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
- data = DataReductionProxyData::GetData(*request.get());
+ data = DataReductionProxyData::GetData(*request);
EXPECT_EQ(++page_id, data->page_id().value());
// Verify that redirects are the same page ID.
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
- data = DataReductionProxyData::GetData(*request.get());
+ data = DataReductionProxyData::GetData(*request);
EXPECT_EQ(page_id, data->page_id().value());
network_delegate()->NotifyBeforeRedirect(request.get(), GURL(kTestURL));
@@ -1848,7 +1840,7 @@ TEST_F(DataReductionProxyNetworkDelegateTest,
page_id = io_data()->request_options()->GeneratePageId();
network_delegate()->NotifyBeforeSendHeaders(
request.get(), data_reduction_proxy_info, proxy_retry_info, &headers);
- data = DataReductionProxyData::GetData(*request.get());
+ data = DataReductionProxyData::GetData(*request);
EXPECT_EQ(++page_id, data->page_id().value());
}
@@ -2077,7 +2069,7 @@ TEST_F(DataReductionProxyNetworkDelegateClientLoFiTest, DataSavingsNonDRP) {
net::MockRead reads[] = {net::MockRead(test.headers),
net::MockRead(response_body.c_str()),
net::MockRead(net::ASYNC, net::OK)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket);
net::TestDelegate test_delegate;
@@ -2111,7 +2103,7 @@ TEST_F(DataReductionProxyNetworkDelegateClientLoFiTest, DataSavingsThroughDRP) {
net::MockRead reads[] = {net::MockRead(kHeaders),
net::MockRead(response_body.c_str()),
net::MockRead(net::ASYNC, net::OK)};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory()->AddSocketDataProvider(&socket);
net::TestDelegate test_delegate;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
index 2002ef1991f..3f140df6ba3 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_service.cc
@@ -97,10 +97,6 @@ void DataReductionProxyService::ReadPersistedClientConfig() {
!last_config_retrieval_time.is_null() &&
time_since_last_config_retrieval > base::TimeDelta::FromHours(24);
- UMA_HISTOGRAM_BOOLEAN(
- "DataReductionProxy.ConfigService.PersistedConfigIsExpired",
- persisted_config_is_expired);
-
if (persisted_config_is_expired)
return;
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
index 124bd09e0b4..96f4e58de57 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.cc
@@ -13,7 +13,6 @@
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "build/build_config.h"
-#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_io_data.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service.h"
@@ -52,7 +51,7 @@ namespace data_reduction_proxy {
DataReductionProxySettings::DataReductionProxySettings()
: unreachable_(false),
deferred_initialization_(false),
- data_reduction_proxy_enabled_pref_name_(),
+
prefs_(nullptr),
config_(nullptr),
clock_(base::DefaultClock::GetInstance()) {}
@@ -79,7 +78,7 @@ void DataReductionProxySettings::InitDataReductionProxySettings(
DCHECK(prefs);
DCHECK(io_data);
DCHECK(io_data->config());
- DCHECK(data_reduction_proxy_service.get());
+ DCHECK(data_reduction_proxy_service);
data_reduction_proxy_enabled_pref_name_ =
data_reduction_proxy_enabled_pref_name;
prefs_ = prefs;
@@ -151,11 +150,12 @@ int64_t DataReductionProxySettings::GetDataReductionLastUpdateTime() {
data_reduction_proxy_service_->compression_stats()->GetLastUpdateTime();
}
-void DataReductionProxySettings::ClearDataSavingStatistics() {
+void DataReductionProxySettings::ClearDataSavingStatistics(
+ DataReductionProxySavingsClearedReason reason) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(data_reduction_proxy_service_->compression_stats());
- data_reduction_proxy_service_->compression_stats()
- ->ClearDataSavingStatistics();
+ data_reduction_proxy_service_->compression_stats()->ClearDataSavingStatistics(
+ reason);
}
int64_t DataReductionProxySettings::GetTotalHttpContentLengthSaved() {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
index faac818678f..a7109ccbb95 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings.h
@@ -15,6 +15,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
+#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_compression_stats.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_service_observer.h"
#include "components/prefs/pref_member.h"
@@ -104,8 +105,8 @@ class DataReductionProxySettings : public DataReductionProxyServiceObserver {
// daily original and received content lengths.
int64_t GetDataReductionLastUpdateTime();
- // Clears all data saving statistics.
- void ClearDataSavingStatistics();
+ // Clears all data saving statistics for the given |reason|.
+ void ClearDataSavingStatistics(DataReductionProxySavingsClearedReason reason);
// Returns the difference between the total original size of all HTTP content
// received from the network and the actual size of the HTTP content received.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
index aced43684ff..0945cd25296 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_test_utils.cc
@@ -32,9 +32,7 @@ const char kProxy[] = "proxy";
namespace data_reduction_proxy {
-DataReductionProxySettingsTestBase::DataReductionProxySettingsTestBase()
- : testing::Test() {
-}
+DataReductionProxySettingsTestBase::DataReductionProxySettingsTestBase() {}
DataReductionProxySettingsTestBase::~DataReductionProxySettingsTestBase() {}
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index 2561b739fb5..6cb54bcc0c9 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -236,7 +236,7 @@ TEST(DataReductionProxySettingsStandaloneTest, TestEndToEndSecureProxyCheck) {
net::MockRead(net::SYNCHRONOUS, test_case.net_error_code),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory.AddSocketDataProvider(&socket_data_provider);
// Toggle the pref to trigger the secure proxy check.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
index 8cfdd5483af..4da41fd11d6 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.cc
@@ -198,8 +198,8 @@ TestDataReductionProxyConfigServiceClient::TestTickClock::NowTicks() const {
return base::TimeTicks::UnixEpoch() + (time_ - base::Time::UnixEpoch());
}
-base::Time
-TestDataReductionProxyConfigServiceClient::TestTickClock::Now() {
+base::Time TestDataReductionProxyConfigServiceClient::TestTickClock::Now()
+ const {
return time_;
}
@@ -611,7 +611,7 @@ void DataReductionProxyTestContext::InitSettings() {
void DataReductionProxyTestContext::DestroySettings() {
// Force destruction of |DBDataOwner|, which lives on DB task runner and is
// indirectly owned by |settings_|.
- if (settings_.get()) {
+ if (settings_) {
settings_.reset();
storage_delegate_->SetStorageDelegate(nullptr);
RunUntilIdle();
@@ -687,7 +687,7 @@ void DataReductionProxyTestContext::
net::MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider socket_data_provider(
- mock_reads, arraysize(mock_reads), nullptr, 0);
+ mock_reads, base::span<net::MockWrite>());
mock_socket_factory_->AddSocketDataProvider(&socket_data_provider);
// Set the pref to cause the secure proxy check to be issued.
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
index 984bb8111ed..4c02b03a040 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h
@@ -87,7 +87,7 @@ class MockDataReductionProxyRequestOptions
MockDataReductionProxyRequestOptions(Client client,
DataReductionProxyConfig* config);
- ~MockDataReductionProxyRequestOptions();
+ ~MockDataReductionProxyRequestOptions() override;
MOCK_CONST_METHOD1(PopulateConfigResponse, void(ClientConfig* config));
};
@@ -155,7 +155,7 @@ class TestDataReductionProxyConfigServiceClient
base::TimeTicks NowTicks() const override;
// base::Clock implementation.
- base::Time Now() override;
+ base::Time Now() const override;
// Sets the current time.
void SetTime(const base::Time& time);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
index d4010a64059..77dfa992c73 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.cc
@@ -310,6 +310,28 @@ ProtoEffectiveConnectionTypeFromEffectiveConnectionType(
}
}
+PageloadMetrics_ConnectionType ProtoConnectionTypeFromConnectionType(
+ net::NetworkChangeNotifier::ConnectionType connection_type) {
+ switch (connection_type) {
+ case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
+ return PageloadMetrics_ConnectionType_CONNECTION_UNKNOWN;
+ case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
+ return PageloadMetrics_ConnectionType_CONNECTION_ETHERNET;
+ case net::NetworkChangeNotifier::CONNECTION_WIFI:
+ return PageloadMetrics_ConnectionType_CONNECTION_WIFI;
+ case net::NetworkChangeNotifier::CONNECTION_2G:
+ return PageloadMetrics_ConnectionType_CONNECTION_2G;
+ case net::NetworkChangeNotifier::CONNECTION_3G:
+ return PageloadMetrics_ConnectionType_CONNECTION_3G;
+ case net::NetworkChangeNotifier::CONNECTION_4G:
+ return PageloadMetrics_ConnectionType_CONNECTION_4G;
+ case net::NetworkChangeNotifier::CONNECTION_NONE:
+ return PageloadMetrics_ConnectionType_CONNECTION_NONE;
+ case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
+ return PageloadMetrics_ConnectionType_CONNECTION_BLUETOOTH;
+ }
+}
+
net::ProxyServer::Scheme SchemeFromProxyScheme(
ProxyServer_ProxyScheme proxy_scheme) {
switch (proxy_scheme) {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
index 98f4f52f315..8245d91cebe 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
+++ b/chromium/components/data_reduction_proxy/core/browser/data_reduction_proxy_util.h
@@ -10,6 +10,7 @@
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/data_reduction_proxy/proto/pageload_metrics.pb.h"
+#include "net/base/network_change_notifier.h"
#include "net/base/proxy_server.h"
#include "net/nqe/effective_connection_type.h"
#include "net/proxy_resolution/proxy_retry_info.h"
@@ -128,12 +129,17 @@ static_assert(net::EFFECTIVE_CONNECTION_TYPE_LAST == 6,
"If net::EFFECTIVE_CONNECTION_TYPE changes, "
"PageloadMetrics_EffectiveConnectionType needs to be updated.");
-// Returns the PageloadMetrics_EffectiveConnection equivalent of
+// Returns the PageloadMetrics_EffectiveConnectionType equivalent of
// |effective_connection_type|.
PageloadMetrics_EffectiveConnectionType
ProtoEffectiveConnectionTypeFromEffectiveConnectionType(
net::EffectiveConnectionType effective_connection_type);
+// Returns the PageloadMetrics_ConnectionType equivalent of
+// |connection_type|.
+PageloadMetrics_ConnectionType ProtoConnectionTypeFromConnectionType(
+ net::NetworkChangeNotifier::ConnectionType connection_type);
+
// Returns the |net::ProxyServer::Scheme| for a ProxyServer_ProxyScheme.
net::ProxyServer::Scheme SchemeFromProxyScheme(
ProxyServer_ProxyScheme proxy_scheme);
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
index 2c4db6767cf..dc1d7fd120c 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_usage_store.cc
@@ -106,7 +106,9 @@ void DataUsageStore::LoadCurrentDataUsageBucket(DataUsageBucket* current) {
DCHECK_LT(current_bucket_index_, kNumDataUsageBuckets);
DataStore::Status status = LoadBucketAtIndex(current_bucket_index_, current);
- if (status == DataStore::Status::OK) {
+ bool bucket_read_ok = status == DataStore::Status::OK;
+ current->set_had_read_error(!bucket_read_ok);
+ if (bucket_read_ok) {
current_bucket_last_updated_ =
base::Time::FromInternalValue(current->last_updated_timestamp());
}
@@ -119,7 +121,8 @@ void DataUsageStore::StoreCurrentDataUsageBucket(
current_bucket_index_ < kNumDataUsageBuckets);
// If current bucket does not have any information, we skip writing to DB.
- if (!current.has_last_updated_timestamp())
+ if (!current.has_last_updated_timestamp() ||
+ (current.has_had_read_error() && current.had_read_error()))
return;
int prev_current_bucket_index = current_bucket_index_;
@@ -197,6 +200,9 @@ void DataUsageStore::DeleteBrowsingHistory(const base::Time& start,
int index_to_delete = (first_index_to_delete + i) % kNumDataUsageBuckets;
db_->Delete(DbKeyForBucketIndex(index_to_delete));
}
+ UMA_HISTOGRAM_COUNTS_10000(
+ "DataReductionProxy.DeleteBrowsingHistory.NumBuckets",
+ num_buckets_to_delete);
}
int DataUsageStore::ComputeBucketIndex(const base::Time& time) const {
diff --git a/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
index a69344d5321..ecc7e6afd41 100644
--- a/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/data_usage_store_unittest.cc
@@ -11,6 +11,7 @@
#include <string>
#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_test_utils.h"
#include "components/data_reduction_proxy/core/browser/data_store.h"
@@ -71,6 +72,7 @@ class DataUsageStoreTest : public testing::Test {
DataUsageBucket current_bucket;
current_bucket.set_last_updated_timestamp(current_time.ToInternalValue());
+ current_bucket.set_had_read_error(false);
std::string bucket_value;
ASSERT_TRUE(current_bucket.SerializeToString(&bucket_value));
@@ -81,6 +83,7 @@ class DataUsageStoreTest : public testing::Test {
base::Time time = current_time - base::TimeDelta::FromMinutes(i * 5);
DataUsageBucket bucket;
bucket.set_last_updated_timestamp(time.ToInternalValue());
+ bucket.set_had_read_error(false);
int index = kTestCurrentBucketIndex - i;
if (index < 0)
index += kNumExpectedBuckets;
@@ -121,6 +124,7 @@ TEST_F(DataUsageStoreTest, LoadAndStoreToSameBucket) {
base::Time now = base::Time::Now();
bucket.set_last_updated_timestamp(now.ToInternalValue());
+ bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(bucket);
ASSERT_EQ(2u, store()->map()->size());
@@ -128,6 +132,7 @@ TEST_F(DataUsageStoreTest, LoadAndStoreToSameBucket) {
DataUsageBucket stored_bucket;
data_usage_store()->LoadCurrentDataUsageBucket(&stored_bucket);
ASSERT_EQ(now.ToInternalValue(), stored_bucket.last_updated_timestamp());
+ ASSERT_FALSE(stored_bucket.had_read_error());
std::vector<DataUsageBucket> data_usage;
data_usage_store()->LoadDataUsage(&data_usage);
@@ -138,6 +143,7 @@ TEST_F(DataUsageStoreTest, LoadAndStoreToSameBucket) {
data_usage[kNumExpectedBuckets - 2].has_last_updated_timestamp());
ASSERT_EQ(now.ToInternalValue(),
data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
+ ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
}
TEST_F(DataUsageStoreTest, StoreSameBucket) {
@@ -159,6 +165,7 @@ TEST_F(DataUsageStoreTest, StoreSameBucket) {
data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
bucket.set_last_updated_timestamp(time1.ToInternalValue());
+ bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(bucket);
ASSERT_EQ(2u, store()->map()->size());
@@ -176,6 +183,7 @@ TEST_F(DataUsageStoreTest, StoreSameBucket) {
data_usage[kNumExpectedBuckets - 2].has_last_updated_timestamp());
ASSERT_EQ(time2.ToInternalValue(),
data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
+ ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
}
TEST_F(DataUsageStoreTest, StoreConsecutiveBuckets) {
@@ -197,6 +205,7 @@ TEST_F(DataUsageStoreTest, StoreConsecutiveBuckets) {
data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
bucket.set_last_updated_timestamp(time1.ToInternalValue());
+ bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(bucket);
ASSERT_EQ(2u, store()->map()->size());
@@ -214,8 +223,10 @@ TEST_F(DataUsageStoreTest, StoreConsecutiveBuckets) {
data_usage[kNumExpectedBuckets - 3].has_last_updated_timestamp());
ASSERT_EQ(time1.ToInternalValue(),
data_usage[kNumExpectedBuckets - 2].last_updated_timestamp());
+ ASSERT_FALSE(data_usage[kNumExpectedBuckets - 2].had_read_error());
ASSERT_EQ(time2.ToInternalValue(),
data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
+ ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
}
TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
@@ -242,6 +253,7 @@ TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
DataUsageBucket bucket_before_history;
bucket_before_history.set_last_updated_timestamp(
before_history_time.ToInternalValue());
+ bucket_before_history.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(bucket_before_history);
// Only one bucket has been stored, so store should have 2 entries, one for
// current index and one for the bucket itself.
@@ -258,6 +270,7 @@ TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
// This will be the very first bucket once |last_bucket| is stored.
DataUsageBucket first_bucket;
first_bucket.set_last_updated_timestamp(first_bucket_time.ToInternalValue());
+ first_bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(first_bucket);
// A new bucket has been stored, so entires in map should increase by one.
ASSERT_EQ(3u, store()->map()->size());
@@ -266,6 +279,7 @@ TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
// calling |StoreCurrentDataUsageBucket| on 10 buckets.
DataUsageBucket tenth_bucket;
tenth_bucket.set_last_updated_timestamp(tenth_bucket_time.ToInternalValue());
+ tenth_bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(tenth_bucket);
// 9 more (empty) buckets should have been added to the store.
ASSERT_EQ(12u, store()->map()->size());
@@ -274,6 +288,7 @@ TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
DataUsageBucket second_last_bucket;
second_last_bucket.set_last_updated_timestamp(
second_last_bucket_time.ToInternalValue());
+ second_last_bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(second_last_bucket);
// Max number of buckets we store to DB plus one for the current index.
ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
@@ -282,6 +297,7 @@ TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
// store should be unchanged.
DataUsageBucket last_bucket;
last_bucket.set_last_updated_timestamp(last_bucket_time.ToInternalValue());
+ last_bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(last_bucket);
ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
@@ -297,6 +313,11 @@ TEST_F(DataUsageStoreTest, StoreMultipleBuckets) {
data_usage[kNumExpectedBuckets - 2].last_updated_timestamp());
ASSERT_EQ(last_bucket_time.ToInternalValue(),
data_usage[kNumExpectedBuckets - 1].last_updated_timestamp());
+
+ ASSERT_FALSE(data_usage[0].had_read_error());
+ ASSERT_FALSE(data_usage[9].had_read_error());
+ ASSERT_FALSE(data_usage[kNumExpectedBuckets - 2].had_read_error());
+ ASSERT_FALSE(data_usage[kNumExpectedBuckets - 1].had_read_error());
}
TEST_F(DataUsageStoreTest, DeleteHistoricalDataUsage) {
@@ -304,6 +325,7 @@ TEST_F(DataUsageStoreTest, DeleteHistoricalDataUsage) {
data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
bucket.set_last_updated_timestamp(base::Time::Now().ToInternalValue());
+ bucket.set_had_read_error(false);
data_usage_store()->StoreCurrentDataUsageBucket(bucket);
ASSERT_EQ(2u, store()->map()->size());
@@ -409,6 +431,7 @@ TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
PopulateStore();
DataUsageBucket current_bucket;
data_usage_store()->LoadCurrentDataUsageBucket(&current_bucket);
+ base::HistogramTester histogram_tester;
ASSERT_EQ(kNumExpectedBuckets + 1, store()->map()->size());
@@ -417,6 +440,7 @@ TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
base::Time now;
EXPECT_TRUE(base::Time::FromUTCExploded(exploded, &now));
base::Time fifteen_mins_from_now = now + base::TimeDelta::FromMinutes(15);
+
// Deleting browsing from the future should be a no-op.
data_usage_store()->DeleteBrowsingHistory(fifteen_mins_from_now,
fifteen_mins_from_now);
@@ -425,20 +449,27 @@ TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
ASSERT_TRUE(store()->map()->find(base::StringPrintf(
"data_usage_bucket:%d", kTestCurrentBucketIndex)) !=
store()->map()->end());
+
// Delete the current bucket.
data_usage_store()->DeleteBrowsingHistory(now, now);
ASSERT_EQ(kNumExpectedBuckets, store()->map()->size());
ASSERT_TRUE(store()->map()->find(base::StringPrintf(
"data_usage_bucket:%d", kTestCurrentBucketIndex)) ==
store()->map()->end());
+ histogram_tester.ExpectUniqueSample(
+ "DataReductionProxy.DeleteBrowsingHistory.NumBuckets", 1, 1);
+ // Delete the current bucket + the last 5 minutes, so two buckets.
data_usage_store()->DeleteBrowsingHistory(
now - base::TimeDelta::FromMinutes(5), now);
ASSERT_EQ(kNumExpectedBuckets - 1, store()->map()->size());
ASSERT_TRUE(store()->map()->find(base::StringPrintf(
"data_usage_bucket:%d", kTestCurrentBucketIndex - 1)) ==
store()->map()->end());
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.DeleteBrowsingHistory.NumBuckets", 2, 1);
+ // Delete 30 days of browsing history.
data_usage_store()->DeleteBrowsingHistory(now - base::TimeDelta::FromDays(30),
now);
ASSERT_EQ(kNumExpectedBuckets - kBucketsInHour * 30 * 24,
@@ -448,6 +479,9 @@ TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
ASSERT_TRUE(store()->map()->find(base::StringPrintf(
"data_usage_bucket:%d", kNumExpectedBuckets - 1)) !=
store()->map()->end());
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.DeleteBrowsingHistory.NumBuckets",
+ kBucketsInHour * 30 * 24, 1);
// Delete wraps around and removes the last element which is at position
// (|kNumExpectedBuckets| - 1).
@@ -466,6 +500,31 @@ TEST_F(DataUsageStoreTest, DeleteBrowsingHistory) {
data_usage_store()->DeleteBrowsingHistory(now - base::TimeDelta::FromDays(60),
now);
ASSERT_EQ(1u, store()->map()->size());
+ histogram_tester.ExpectBucketCount(
+ "DataReductionProxy.DeleteBrowsingHistory.NumBuckets",
+ kBucketsInHour * 30 * 24 - 1, 2);
+}
+
+TEST_F(DataUsageStoreTest, DontStoreReadError) {
+ DataUsageBucket bucket;
+ data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
+
+ base::Time now = base::Time::Now();
+ bucket.set_last_updated_timestamp(now.ToInternalValue());
+ bucket.set_had_read_error(true);
+
+ data_usage_store()->StoreCurrentDataUsageBucket(bucket);
+ ASSERT_EQ(0u, store()->map()->size());
+}
+
+TEST_F(DataUsageStoreTest, DontStoreNoTimestamp) {
+ DataUsageBucket bucket;
+ data_usage_store()->LoadCurrentDataUsageBucket(&bucket);
+
+ bucket.set_had_read_error(false);
+
+ data_usage_store()->StoreCurrentDataUsageBucket(bucket);
+ ASSERT_EQ(0u, store()->map()->size());
}
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc b/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
index 1273720c38f..dbe78df0c8a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/db_data_owner.cc
@@ -47,7 +47,7 @@ void DBDataOwner::StoreCurrentDataUsageBucket(
std::unique_ptr<DataUsageBucket> current) {
DCHECK(sequence_checker_.CalledOnValidSequence());
- data_usage_->StoreCurrentDataUsageBucket(*current.get());
+ data_usage_->StoreCurrentDataUsageBucket(*current);
}
void DBDataOwner::DeleteHistoricalDataUsage() {
diff --git a/chromium/components/data_reduction_proxy/core/browser/network_properties_manager.cc b/chromium/components/data_reduction_proxy/core/browser/network_properties_manager.cc
index bf30d9a9665..5ba29bd0471 100644
--- a/chromium/components/data_reduction_proxy/core/browser/network_properties_manager.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/network_properties_manager.cc
@@ -14,6 +14,7 @@
#include "base/strings/string_split.h"
#include "base/time/clock.h"
#include "base/values.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -236,6 +237,8 @@ void NetworkPropertiesManager::OnChangeInNetworkID(
if (it != network_properties_container_.end()) {
network_properties_ = it->second;
cached_entry_found = true;
+ if (params::ShouldDiscardCanaryCheckResult())
+ network_properties_.set_secure_proxy_disallowed_by_carrier(false);
} else {
// Reset to default state.
@@ -286,6 +289,8 @@ NetworkPropertiesManager::ConvertDictionaryValueToParsedPrefs(
GetParsedNetworkProperty(it.second);
if (!network_properties)
continue;
+ if (params::ShouldDiscardCanaryCheckResult())
+ network_properties->set_secure_proxy_disallowed_by_carrier(false);
read_prefs.emplace(std::make_pair(it.first, network_properties.value()));
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc
index 8c369fd3c8e..8194b3e509a 100644
--- a/chromium/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/network_properties_manager_unittest.cc
@@ -4,13 +4,19 @@
#include "components/data_reduction_proxy/core/browser/network_properties_manager.h"
+#include <map>
+
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -34,6 +40,14 @@ class TestNetworkPropertiesManager : public NetworkPropertiesManager {
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
: NetworkPropertiesManager(clock, pref_service, ui_task_runner) {}
~TestNetworkPropertiesManager() override {}
+
+ static void InitDiscardCanaryCheckResultExperiment(
+ base::test::ScopedFeatureList* scoped_feature_list) {
+ std::map<std::string, std::string> params;
+ params[params::GetDiscardCanaryCheckResultParam()] = "true";
+ scoped_feature_list->InitAndEnableFeatureWithParameters(
+ features::kDataReductionProxyRobustConnection, params);
+ }
};
TEST(NetworkPropertyTest, TestSetterGetterCaptivePortal) {
@@ -490,6 +504,49 @@ TEST(NetworkPropertyTest, TestDeleteOldValues) {
}
}
+TEST(NetworkPropertyTest,
+ TestSetterGetterDisallowedByCarrierDiscardingEnabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ for (bool discard : {false, true}) {
+ if (discard) {
+ TestNetworkPropertiesManager::InitDiscardCanaryCheckResultExperiment(
+ &scoped_feature_list);
+ }
+
+ TestingPrefServiceSimple test_prefs;
+ test_prefs.registry()->RegisterDictionaryPref(prefs::kNetworkProperties);
+ base::MessageLoopForIO loop;
+ TestNetworkPropertiesManager network_properties_manager(
+ &test_prefs, base::ThreadTaskRunnerHandle::Get());
+
+ // First network ID has a captive portal and the canary check failed.
+ std::string first_network_id("test1");
+ network_properties_manager.OnChangeInNetworkID(first_network_id);
+ EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+ network_properties_manager.SetIsSecureProxyDisallowedByCarrier(true);
+ network_properties_manager.SetIsCaptivePortal(true);
+ EXPECT_TRUE(network_properties_manager.IsSecureProxyDisallowedByCarrier());
+ EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+ base::RunLoop().RunUntilIdle();
+
+ // Change to a different network. State should be reset when there is a
+ // change in the network ID.
+ std::string second_network_id("test2");
+ network_properties_manager.OnChangeInNetworkID(second_network_id);
+ EXPECT_FALSE(network_properties_manager.IsCaptivePortal());
+ EXPECT_FALSE(network_properties_manager.IsSecureProxyDisallowedByCarrier());
+ base::RunLoop().RunUntilIdle();
+
+ // Change back to |first_network_id|. Captive portal state should be
+ // persisted but the canary check state should not be.
+ network_properties_manager.OnChangeInNetworkID(first_network_id);
+ EXPECT_NE(discard,
+ network_properties_manager.IsSecureProxyDisallowedByCarrier());
+ EXPECT_TRUE(network_properties_manager.IsCaptivePortal());
+ }
+}
+
} // namespace
-} // namespace data_reduction_proxy \ No newline at end of file
+} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc b/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
index 5895c123ca6..02cd3d47d89 100644
--- a/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher.cc
@@ -179,8 +179,7 @@ void WarmupURLFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
if (!source->GetStatus().is_success() &&
source->GetStatus().error() == net::ERR_INTERNET_DISCONNECTED) {
// Fetching failed due to Internet unavailability, and not due to some
- // error. Set the proxy server to unknown.
- callback_.Run(net::ProxyServer(), FetchResult::kSuccessful);
+ // error. No need to run the callback.
CleanupAfterFetch();
return;
}
diff --git a/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc b/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
index 54426fc2fea..6a891bc1936 100644
--- a/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
@@ -172,8 +172,8 @@ TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLNoViaHeader) {
success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
socket_data_providers.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads, arraysize(success_reads), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads, base::span<net::MockWrite>()));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
@@ -236,8 +236,8 @@ TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithViaHeader) {
success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
socket_data_providers.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads, arraysize(success_reads), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads, base::span<net::MockWrite>()));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
@@ -300,8 +300,8 @@ TEST(WarmupURLFetcherTest,
success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
socket_data_providers.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads, arraysize(success_reads), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads, base::span<net::MockWrite>()));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
@@ -353,8 +353,8 @@ TEST(WarmupURLFetcherTest, TestConnectionResetFetchWarmupURL) {
success_reads[0] = net::MockRead(net::SYNCHRONOUS, net::ERR_CONNECTION_RESET);
socket_data_providers.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads, arraysize(success_reads), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads, base::span<net::MockWrite>()));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
@@ -413,8 +413,8 @@ TEST(WarmupURLFetcherTest, TestFetchTimesout) {
success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
socket_data_providers.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads, arraysize(success_reads), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads, base::span<net::MockWrite>()));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
@@ -473,8 +473,8 @@ TEST(WarmupURLFetcherTest, TestSuccessfulFetchWarmupURLWithDelay) {
success_reads[2] = net::MockRead(net::SYNCHRONOUS, net::OK);
socket_data_providers.push_back(
- (std::make_unique<net::StaticSocketDataProvider>(
- success_reads, arraysize(success_reads), nullptr, 0)));
+ std::make_unique<net::StaticSocketDataProvider>(
+ success_reads, base::span<net::MockWrite>()));
mock_socket_factory.AddSocketDataProvider(socket_data_providers.back().get());
std::unique_ptr<net::TestURLRequestContext> test_request_context(
diff --git a/chromium/components/data_reduction_proxy/core/common/BUILD.gn b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
index d7930835fe6..97bc64a9cbb 100644
--- a/chromium/components/data_reduction_proxy/core/common/BUILD.gn
+++ b/chromium/components/data_reduction_proxy/core/common/BUILD.gn
@@ -31,6 +31,7 @@ template("common_tmpl") {
"data_reduction_proxy_server.h",
"data_reduction_proxy_switches.cc",
"data_reduction_proxy_switches.h",
+ "data_reduction_proxy_type_info.h",
"lofi_decider.h",
"lofi_ui_service.h",
"resource_type_provider.h",
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
index 320b6fe5327..023d8c87355 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h
@@ -7,6 +7,13 @@
#include <vector>
+#include "base/optional.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
+
+namespace net {
+class ProxyServer;
+}
+
namespace data_reduction_proxy {
class DataReductionProxyServer;
@@ -20,6 +27,20 @@ class DataReductionProxyConfigValues {
// included.
virtual const std::vector<DataReductionProxyServer>& proxies_for_http()
const = 0;
+
+ // Determines if the given |proxy_server| matches a currently or recent
+ // previously configured Data Reduction Proxy server, returning information
+ // about where that proxy is in the ordered list of proxies to use. It's up to
+ // the implementation to determine what counts as a recent previously
+ // configured Data Reduction Proxy server, but the idea is to be able to
+ // recognize proxies from requests that use the currently configured
+ // |proxies_for_http()| as well as recognize proxies from requests that are
+ // in-progress when the list of proxy servers to use changes. If
+ // |proxy_server| matches multiple proxies, then the most recent and highest
+ // precedence result is returned.
+ virtual base::Optional<DataReductionProxyTypeInfo>
+ FindConfiguredDataReductionProxy(
+ const net::ProxyServer& proxy_server) const = 0;
};
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
index e257a700122..00ec92cd34d 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store.cc
@@ -269,7 +269,7 @@ std::string DataReductionProxyEventStore::SanitizedLastBypassEvent() const {
}
std::string json;
- base::JSONWriter::Write(*last_bypass.get(), &json);
+ base::JSONWriter::Write(*last_bypass, &json);
return json;
}
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
index aede1168105..8f822f378de 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_event_store_unittest.cc
@@ -284,7 +284,7 @@ TEST_F(DataReductionProxyEventStoreTest, TestFeedbackLastBypassEventFullURL) {
bypass_event->Set("params", std::move(bypass_params));
std::string sanitized_output;
- base::JSONWriter::Write(*sanitized_event.get(), &sanitized_output);
+ base::JSONWriter::Write(*sanitized_event, &sanitized_output);
event_store()->AddAndSetLastBypassEvent(std::move(bypass_event), 0);
EXPECT_EQ(sanitized_output, event_store()->SanitizedLastBypassEvent());
}
@@ -323,7 +323,7 @@ TEST_F(DataReductionProxyEventStoreTest, TestFeedbackLastBypassEventHostOnly) {
bypass_event->Set("params", std::move(bypass_params));
std::string sanitized_output;
- base::JSONWriter::Write(*sanitized_event.get(), &sanitized_output);
+ base::JSONWriter::Write(*sanitized_event, &sanitized_output);
event_store()->AddAndSetLastBypassEvent(std::move(bypass_event), 0);
EXPECT_EQ(sanitized_output, event_store()->SanitizedLastBypassEvent());
}
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
index 38b2efb0bec..880c2f31a9b 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.cc
@@ -13,11 +13,14 @@ DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
const base::Optional<base::TimeDelta>& first_image_paint,
const base::Optional<base::TimeDelta>& first_contentful_paint,
const base::Optional<base::TimeDelta>& experimental_first_meaningful_paint,
+ const base::Optional<base::TimeDelta>& first_input_delay,
const base::Optional<base::TimeDelta>&
parse_blocked_on_script_load_duration,
const base::Optional<base::TimeDelta>& parse_stop,
int64_t network_bytes,
int64_t original_network_bytes,
+ int64_t total_page_size_bytes,
+ float cached_fraction,
bool app_background_occurred,
bool opt_out_occurred,
int64_t renderer_memory_usage_kb,
@@ -28,11 +31,14 @@ DataReductionProxyPageLoadTiming::DataReductionProxyPageLoadTiming(
first_image_paint(first_image_paint),
first_contentful_paint(first_contentful_paint),
experimental_first_meaningful_paint(experimental_first_meaningful_paint),
+ first_input_delay(first_input_delay),
parse_blocked_on_script_load_duration(
parse_blocked_on_script_load_duration),
parse_stop(parse_stop),
network_bytes(network_bytes),
original_network_bytes(original_network_bytes),
+ total_page_size_bytes(total_page_size_bytes),
+ cached_fraction(cached_fraction),
app_background_occurred(app_background_occurred),
opt_out_occurred(opt_out_occurred),
renderer_memory_usage_kb(renderer_memory_usage_kb),
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
index 11ec6b00cfe..7ad962ceca0 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_page_load_timing.h
@@ -22,11 +22,14 @@ struct DataReductionProxyPageLoadTiming {
const base::Optional<base::TimeDelta>& first_contentful_paint,
const base::Optional<base::TimeDelta>&
experimental_first_meaningful_paint,
+ const base::Optional<base::TimeDelta>& first_input_delay,
const base::Optional<base::TimeDelta>&
parse_blocked_on_script_load_duration,
const base::Optional<base::TimeDelta>& parse_stop,
int64_t network_bytes,
int64_t original_network_bytes,
+ int64_t total_page_size_bytes,
+ float cached_fraction,
bool app_background_occurred,
bool opt_out_occurred,
int64_t renderer_memory_usage_kb,
@@ -52,6 +55,8 @@ struct DataReductionProxyPageLoadTiming {
const base::Optional<base::TimeDelta> first_contentful_paint;
// (Experimental) Time when the page's primary content is painted.
const base::Optional<base::TimeDelta> experimental_first_meaningful_paint;
+ // The queuing delay for the first user input on the page.
+ const base::Optional<base::TimeDelta> first_input_delay;
// Time that parsing was blocked by loading script.
const base::Optional<base::TimeDelta> parse_blocked_on_script_load_duration;
// Time when parsing completed.
@@ -61,6 +66,10 @@ struct DataReductionProxyPageLoadTiming {
// The number of bytes that would have been served over the network if the
// user were not using data reduction proxy, not including headers.
const int64_t original_network_bytes;
+ // The total number of bytes loaded for the page content, including cache.
+ const int64_t total_page_size_bytes;
+ // The fraction of bytes that were served from the cache for this page load.
+ const float cached_fraction;
// True when android app background occurred during the page load lifetime.
const bool app_background_occurred;
// True when the user clicks "Show Original" on the Previews infobar.
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
index 1e3fd9a7a0e..574c7117541 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -4,6 +4,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h"
+#include <algorithm>
#include <map>
#include <string>
#include <vector>
@@ -18,6 +19,7 @@
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/variations/variations_associated_data.h"
+#include "net/base/host_port_pair.h"
#include "net/base/proxy_server.h"
#include "net/http/http_status_code.h"
#include "url/url_constants.h"
@@ -56,6 +58,7 @@ const char kLitePageBlackListVersion[] = "lite-page-blacklist-version";
const char kWarmupFetchCallbackEnabledParam[] = "warmup_fetch_callback_enabled";
const char kMissingViaBypassDisabledParam[] = "bypass_missing_via_disabled";
+const char kDiscardCanaryCheckResultParam[] = "store_canary_check_result";
bool IsIncludedInFieldTrial(const std::string& name) {
return base::StartsWith(base::FieldTrialList::FindFullName(name), kEnabled,
@@ -127,6 +130,16 @@ const char* GetMissingViaBypassParamName() {
return kMissingViaBypassDisabledParam;
}
+const char* GetDiscardCanaryCheckResultParam() {
+ return kDiscardCanaryCheckResultParam;
+}
+
+bool ShouldDiscardCanaryCheckResult() {
+ return GetFieldTrialParamByFeatureAsBool(
+ features::kDataReductionProxyRobustConnection,
+ GetDiscardCanaryCheckResultParam(), false);
+}
+
bool IsIncludedInServerExperimentsFieldTrial() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
data_reduction_proxy::switches::
@@ -329,14 +342,18 @@ bool GetOverrideProxiesForHttpFromCommandLine(
std::string proxy_overrides =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kDataReductionProxyHttpProxies);
- std::vector<std::string> proxy_override_values = base::SplitString(
- proxy_overrides, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- for (const std::string& proxy_override : proxy_override_values) {
+
+ for (const auto& proxy_override :
+ base::SplitStringPiece(proxy_overrides, ";", base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ net::ProxyServer proxy_server = net::ProxyServer::FromURI(
+ proxy_override, net::ProxyServer::SCHEME_HTTP);
+ DCHECK(proxy_server.is_valid());
+ DCHECK(!proxy_server.is_direct());
+
// Overriding proxies have type UNSPECIFIED_TYPE.
override_proxies_for_http->push_back(DataReductionProxyServer(
- net::ProxyServer::FromURI(proxy_override,
- net::ProxyServer::SCHEME_HTTP),
- ProxyServer::UNSPECIFIED_TYPE));
+ std::move(proxy_server), ProxyServer::UNSPECIFIED_TYPE));
}
return true;
@@ -345,6 +362,7 @@ bool GetOverrideProxiesForHttpFromCommandLine(
std::string origin =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kDataReductionProxy);
+
std::string fallback_origin =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kDataReductionProxyFallback);
@@ -353,17 +371,23 @@ bool GetOverrideProxiesForHttpFromCommandLine(
return false;
override_proxies_for_http->clear();
+
// Overriding proxies have type UNSPECIFIED_TYPE.
if (!origin.empty()) {
+ net::ProxyServer primary_proxy =
+ net::ProxyServer::FromURI(origin, net::ProxyServer::SCHEME_HTTP);
+ DCHECK(primary_proxy.is_valid());
+ DCHECK(!primary_proxy.is_direct());
override_proxies_for_http->push_back(DataReductionProxyServer(
- net::ProxyServer::FromURI(origin, net::ProxyServer::SCHEME_HTTP),
- ProxyServer::UNSPECIFIED_TYPE));
+ std::move(primary_proxy), ProxyServer::UNSPECIFIED_TYPE));
}
if (!fallback_origin.empty()) {
+ net::ProxyServer fallback_proxy = net::ProxyServer::FromURI(
+ fallback_origin, net::ProxyServer::SCHEME_HTTP);
+ DCHECK(fallback_proxy.is_valid());
+ DCHECK(!fallback_proxy.is_direct());
override_proxies_for_http->push_back(DataReductionProxyServer(
- net::ProxyServer::FromURI(fallback_origin,
- net::ProxyServer::SCHEME_HTTP),
- ProxyServer::UNSPECIFIED_TYPE));
+ std::move(fallback_proxy), ProxyServer::UNSPECIFIED_TYPE));
}
return true;
@@ -385,13 +409,6 @@ GURL GetSecureProxyCheckURL() {
} // namespace params
-DataReductionProxyTypeInfo::DataReductionProxyTypeInfo() : proxy_index(0) {}
-
-DataReductionProxyTypeInfo::DataReductionProxyTypeInfo(
- const DataReductionProxyTypeInfo& other) = default;
-
-DataReductionProxyTypeInfo::~DataReductionProxyTypeInfo() {}
-
DataReductionProxyParams::DataReductionProxyParams() {
bool use_override_proxies_for_http =
params::GetOverrideProxiesForHttpFromCommandLine(&proxies_for_http_);
@@ -407,12 +424,24 @@ DataReductionProxyParams::DataReductionProxyParams() {
net::ProxyServer::SCHEME_HTTP),
ProxyServer::CORE));
}
+
+ DCHECK(std::all_of(proxies_for_http_.begin(), proxies_for_http_.end(),
+ [](const DataReductionProxyServer& proxy) {
+ return proxy.proxy_server().is_valid() &&
+ !proxy.proxy_server().is_direct();
+ }));
}
DataReductionProxyParams::~DataReductionProxyParams() {}
void DataReductionProxyParams::SetProxiesForHttpForTesting(
const std::vector<DataReductionProxyServer>& proxies_for_http) {
+ DCHECK(std::all_of(proxies_for_http.begin(), proxies_for_http.end(),
+ [](const DataReductionProxyServer& proxy) {
+ return proxy.proxy_server().is_valid() &&
+ !proxy.proxy_server().is_direct();
+ }));
+
proxies_for_http_ = proxies_for_http;
}
@@ -421,4 +450,38 @@ DataReductionProxyParams::proxies_for_http() const {
return proxies_for_http_;
}
+base::Optional<DataReductionProxyTypeInfo>
+DataReductionProxyParams::FindConfiguredDataReductionProxy(
+ const net::ProxyServer& proxy_server) const {
+ return FindConfiguredProxyInVector(proxies_for_http(), proxy_server);
+}
+
+// static
+base::Optional<DataReductionProxyTypeInfo>
+DataReductionProxyParams::FindConfiguredProxyInVector(
+ const std::vector<DataReductionProxyServer>& proxies,
+ const net::ProxyServer& proxy_server) {
+ if (!proxy_server.is_valid() || proxy_server.is_direct())
+ return base::nullopt;
+
+ // Only compare the host port pair of the |proxy_server| since the proxy
+ // scheme of the stored data reduction proxy may be different than the proxy
+ // scheme of |proxy_server|. This may happen even when the |proxy_server| is a
+ // valid data reduction proxy. As an example, the stored data reduction proxy
+ // may have a proxy scheme of HTTPS while |proxy_server| may have QUIC as the
+ // proxy scheme.
+ const net::HostPortPair& host_port_pair = proxy_server.host_port_pair();
+ auto it = std::find_if(
+ proxies.begin(), proxies.end(),
+ [&host_port_pair](const DataReductionProxyServer& proxy) {
+ return proxy.proxy_server().host_port_pair().Equals(host_port_pair);
+ });
+
+ if (it == proxies.end())
+ return base::nullopt;
+
+ return DataReductionProxyTypeInfo(proxies,
+ static_cast<size_t>(it - proxies.begin()));
+}
+
} // namespace data_reduction_proxy
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
index 8053a881351..a40d20b135e 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -10,8 +10,10 @@
#include <vector>
#include "base/macros.h"
+#include "base/optional.h"
#include "base/time/time.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_config_values.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "url/gurl.h"
namespace net {
@@ -145,18 +147,15 @@ const char* GetWarmupCallbackParamName();
// Returns the experiment parameter name to disable missing via header bypasses.
const char* GetMissingViaBypassParamName();
-} // namespace params
+// Returns the experiment parameter name to discard the cached result for canary
+// check probe.
+const char* GetDiscardCanaryCheckResultParam();
-// Contains information about a given proxy server. |proxies_for_http| contains
-// the configured data reduction proxy servers. |proxy_index| notes the index
-// of the data reduction proxy used in the list of all data reduction proxies.
-struct DataReductionProxyTypeInfo {
- DataReductionProxyTypeInfo();
- DataReductionProxyTypeInfo(const DataReductionProxyTypeInfo& other);
- ~DataReductionProxyTypeInfo();
- std::vector<net::ProxyServer> proxy_servers;
- size_t proxy_index;
-};
+// Returns true if canary check result should not be cached or reused across
+// network changes.
+bool ShouldDiscardCanaryCheckResult();
+
+} // namespace params
// Provides initialization parameters. Proxy origins, and the secure proxy
// check url are are taken from flags if available and from preprocessor
@@ -178,6 +177,17 @@ class DataReductionProxyParams : public DataReductionProxyConfigValues {
const std::vector<DataReductionProxyServer>& proxies_for_http()
const override;
+ // Finds the first proxy in |proxies_for_http()| that matches |proxy_server|
+ // if any exist.
+ base::Optional<DataReductionProxyTypeInfo> FindConfiguredDataReductionProxy(
+ const net::ProxyServer& proxy_server) const override;
+
+ // Helper function to locate |proxy_server| in |proxies| if it exists. This
+ // function is exposed publicly so that DataReductionProxyParams can use it.
+ static base::Optional<DataReductionProxyTypeInfo> FindConfiguredProxyInVector(
+ const std::vector<DataReductionProxyServer>& proxies,
+ const net::ProxyServer& proxy_server);
+
private:
std::vector<DataReductionProxyServer> proxies_for_http_;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc
index e79393a9f37..b99579f42eb 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.cc
@@ -9,7 +9,7 @@
namespace data_reduction_proxy {
TestDataReductionProxyParams::TestDataReductionProxyParams()
- : DataReductionProxyParams(), override_non_secure_proxies_(false) {
+ : override_non_secure_proxies_(false) {
proxies_for_http_.push_back(DataReductionProxyServer(
net::ProxyServer::FromURI("origin.net:80", net::ProxyServer::SCHEME_HTTP),
ProxyServer::CORE));
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
index a6e181b88e2..e49239c8ac0 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_params_unittest.cc
@@ -13,11 +13,13 @@
#include "base/command_line.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
+#include "base/optional.h"
#include "base/test/scoped_feature_list.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_features.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_server.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
+#include "components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h"
#include "components/data_reduction_proxy/proto/client_config.pb.h"
#include "components/variations/variations_associated_data.h"
#include "net/base/proxy_server.h"
@@ -30,27 +32,8 @@
#endif
namespace data_reduction_proxy {
-class DataReductionProxyParamsTest : public testing::Test {
- public:
- void CheckValues(const TestDataReductionProxyParams& params,
- const std::string& expected_origin,
- const std::string& expected_fallback_origin) {
- std::vector<net::ProxyServer> expected_proxies;
- if (!expected_origin.empty()) {
- expected_proxies.push_back(net::ProxyServer::FromURI(
- expected_origin, net::ProxyServer::SCHEME_HTTP));
- }
- if (!expected_fallback_origin.empty()) {
- expected_proxies.push_back(net::ProxyServer::FromURI(
- expected_fallback_origin, net::ProxyServer::SCHEME_HTTP));
- }
-
- EXPECT_EQ(expected_proxies,
- DataReductionProxyServer::ConvertToNetProxyServers(
- params.proxies_for_http()));
- }
-};
+class DataReductionProxyParamsTest : public testing::Test {};
TEST_F(DataReductionProxyParamsTest, EverythingDefined) {
TestDataReductionProxyParams params;
@@ -67,6 +50,24 @@ TEST_F(DataReductionProxyParamsTest, EverythingDefined) {
ProxyServer::CORE));
EXPECT_EQ(expected_proxies, params.proxies_for_http());
+
+ EXPECT_FALSE(
+ params.FindConfiguredDataReductionProxy(net::ProxyServer::FromURI(
+ "unrelated.proxy.net:80", net::ProxyServer::SCHEME_HTTP)));
+
+ base::Optional<DataReductionProxyTypeInfo> first_info =
+ params.FindConfiguredDataReductionProxy(
+ expected_proxies[0].proxy_server());
+ ASSERT_TRUE(first_info);
+ EXPECT_EQ(expected_proxies, first_info->proxy_servers);
+ EXPECT_EQ(0U, first_info->proxy_index);
+
+ base::Optional<DataReductionProxyTypeInfo> second_info =
+ params.FindConfiguredDataReductionProxy(
+ expected_proxies[1].proxy_server());
+ ASSERT_TRUE(second_info);
+ EXPECT_EQ(expected_proxies, second_info->proxy_servers);
+ EXPECT_EQ(1U, second_info->proxy_index);
}
TEST_F(DataReductionProxyParamsTest, Flags) {
@@ -75,7 +76,40 @@ TEST_F(DataReductionProxyParamsTest, Flags) {
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
switches::kDataReductionProxyFallback, "http://ovveride-2.com/");
TestDataReductionProxyParams params;
- CheckValues(params, "http://ovveride-1.com/", "http://ovveride-2.com/");
+
+ std::vector<DataReductionProxyServer> expected_proxies;
+ expected_proxies.push_back(DataReductionProxyServer(
+ net::ProxyServer::FromURI("http://ovveride-1.com/",
+ net::ProxyServer::SCHEME_HTTP),
+ ProxyServer::UNSPECIFIED_TYPE));
+ expected_proxies.push_back(DataReductionProxyServer(
+ net::ProxyServer::FromURI("http://ovveride-2.com/",
+ net::ProxyServer::SCHEME_HTTP),
+ ProxyServer::UNSPECIFIED_TYPE));
+
+ EXPECT_EQ(expected_proxies, params.proxies_for_http());
+
+ // The default proxies shouldn't be recognized as Data Reduction Proxies.
+ EXPECT_FALSE(
+ params.FindConfiguredDataReductionProxy(net::ProxyServer::FromURI(
+ "https://proxy.googlezip.net:443", net::ProxyServer::SCHEME_HTTP)));
+ EXPECT_FALSE(
+ params.FindConfiguredDataReductionProxy(net::ProxyServer::FromURI(
+ "compress.googlezip.net:80", net::ProxyServer::SCHEME_HTTP)));
+
+ base::Optional<DataReductionProxyTypeInfo> first_info =
+ params.FindConfiguredDataReductionProxy(
+ expected_proxies[0].proxy_server());
+ ASSERT_TRUE(first_info);
+ EXPECT_EQ(expected_proxies, first_info->proxy_servers);
+ EXPECT_EQ(0U, first_info->proxy_index);
+
+ base::Optional<DataReductionProxyTypeInfo> second_info =
+ params.FindConfiguredDataReductionProxy(
+ expected_proxies[1].proxy_server());
+ ASSERT_TRUE(second_info);
+ EXPECT_EQ(expected_proxies, second_info->proxy_servers);
+ EXPECT_EQ(1U, second_info->proxy_index);
}
TEST_F(DataReductionProxyParamsTest, IsClientConfigEnabled) {
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc
index 0aa528ae8c8..21600c29cf2 100644
--- a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_server.cc
@@ -30,6 +30,8 @@ bool DataReductionProxyServer::SupportsResourceType(
return true;
case ResourceTypeProvider::CONTENT_TYPE_MEDIA:
return false;
+ case ResourceTypeProvider::CONTENT_TYPE_MAIN_FRAME:
+ return true;
case ResourceTypeProvider::CONTENT_TYPE_MAX:
NOTREACHED();
return true;
diff --git a/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h
new file mode 100644
index 00000000000..1137ee01cca
--- /dev/null
+++ b/chromium/components/data_reduction_proxy/core/common/data_reduction_proxy_type_info.h
@@ -0,0 +1,36 @@
+// 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 COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_TYPE_INFO_H_
+#define COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_TYPE_INFO_H_
+
+#include <stddef.h>
+
+#include <vector>
+
+namespace data_reduction_proxy {
+
+class DataReductionProxyServer;
+
+// Contains information about a given proxy server.
+struct DataReductionProxyTypeInfo {
+ DataReductionProxyTypeInfo(
+ const std::vector<DataReductionProxyServer>& proxy_servers,
+ size_t proxy_index)
+ : proxy_servers(proxy_servers), proxy_index(proxy_index) {}
+
+ // The full configured list of proxy servers that includes the target proxy
+ // server. Since this is held onto as a const reference, the caller needs to
+ // ensure that it doesn't try to access |proxy_servers| if the list of
+ // configured proxies has changed since this DataReductionProxyTypeInfo was
+ // created.
+ const std::vector<DataReductionProxyServer>& proxy_servers;
+
+ // The index of this proxy in |proxy_servers|.
+ size_t proxy_index;
+};
+
+} // namespace data_reduction_proxy
+
+#endif // COMPONENTS_DATA_REDUCTION_PROXY_CORE_COMMON_DATA_REDUCTION_PROXY_TYPE_INFO_H_
diff --git a/chromium/components/data_reduction_proxy/core/common/resource_type_provider.h b/chromium/components/data_reduction_proxy/core/common/resource_type_provider.h
index ca80c4ec8b4..60ec2faa409 100644
--- a/chromium/components/data_reduction_proxy/core/common/resource_type_provider.h
+++ b/chromium/components/data_reduction_proxy/core/common/resource_type_provider.h
@@ -23,7 +23,8 @@ class ResourceTypeProvider {
enum ContentType {
CONTENT_TYPE_UNKNOWN = 0,
CONTENT_TYPE_MEDIA = 1,
- CONTENT_TYPE_MAX = 2,
+ CONTENT_TYPE_MAIN_FRAME = 2,
+ CONTENT_TYPE_MAX = 3,
};
virtual ~ResourceTypeProvider() {}
diff --git a/chromium/components/data_reduction_proxy/proto/data_store.proto b/chromium/components/data_reduction_proxy/proto/data_store.proto
index 2bb7c7272a8..0c67b97e480 100644
--- a/chromium/components/data_reduction_proxy/proto/data_store.proto
+++ b/chromium/components/data_reduction_proxy/proto/data_store.proto
@@ -16,6 +16,9 @@ message DataUsageBucket {
// Timestamp of the last update that was included in this bucket.
optional int64 last_updated_timestamp = 2;
+
+ // True if there was an error while parsing this from disk.
+ optional bool had_read_error = 3;
}
message PerConnectionDataUsage {
diff --git a/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto b/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
index 976093e0273..9fb91cd5026 100644
--- a/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
+++ b/chromium/components/data_reduction_proxy/proto/pageload_metrics.proto
@@ -44,6 +44,19 @@ message PageloadMetrics {
EFFECTIVE_CONNECTION_TYPE_4G = 5;
};
+ // The possible conntion type values. See //net/base/network_change_notifier.h
+ // for a detailed description of the enum values.
+ enum ConnectionType {
+ CONNECTION_UNKNOWN = 0;
+ CONNECTION_ETHERNET = 1;
+ CONNECTION_WIFI = 2;
+ CONNECTION_2G = 3;
+ CONNECTION_3G = 4;
+ CONNECTION_4G = 5;
+ CONNECTION_NONE = 6;
+ CONNECTION_BLUETOOTH = 7;
+ };
+
// The various opt out states seen by server previews.
enum PreviewsOptOut {
// Set for non-previews navigations and app background navigations.
@@ -101,9 +114,11 @@ message PageloadMetrics {
// The sum of original-content-length values, over resources that were not
// loaded from browser cache.
+ // Secure resources (i.e., HTTPS) that go into this sum are bucketed.
optional int64 original_page_size_bytes = 10;
// The sum of (compressed) content-length, over resources that were not loaded
// from browser cache.
+ // Secure resources (i.e., HTTPS) that go into this sum are bucketed.
optional int64 compressed_page_size_bytes = 11;
// The effective connection type at the start of the navigation.
@@ -140,4 +155,20 @@ message PageloadMetrics {
// The RendererCrashType for the page load.
optional RendererCrashType renderer_crash_type = 21;
+
+ // The percent of total_page_size_bytes that were loaded from the cache. This
+ // value is in the range [0.0, 1.0].
+ optional float cached_fraction = 22;
+
+ // The connection type (Wifi, 2G, 3G, 4G, None, etc) reported by the
+ // NetworkChangeNotifier.
+ optional ConnectionType connection_type = 23;
+
+ // The sum of all bytes loaded on a page. This is compressed_page_size_bytes
+ // plus the sum of content-length for all resources loaded from the browser
+ // cache. Secure resources (i.e., HTTPS) that go into this sum are bucketed.
+ optional int64 total_page_size_bytes = 24;
+
+ // The queuing delay for the first user input on the page.
+ optional Duration first_input_delay = 25;
}
diff --git a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
index 7a8bad92ac7..01dd0a8dd99 100644
--- a/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
+++ b/chromium/components/data_usage/core/data_use_aggregator_unittest.cc
@@ -14,6 +14,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/containers/span.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
@@ -60,8 +61,7 @@ class TestDataUseAggregator : public DataUseAggregator {
class TestNetworkChangeNotifier : public net::NetworkChangeNotifier {
public:
explicit TestNetworkChangeNotifier(TestDataUseAggregator* data_use_aggregator)
- : net::NetworkChangeNotifier(),
- data_use_aggregator_(data_use_aggregator),
+ : data_use_aggregator_(data_use_aggregator),
connection_type_to_return_(
net::NetworkChangeNotifier::CONNECTION_UNKNOWN) {}
@@ -275,7 +275,7 @@ class DataUseAggregatorTest : public testing::Test {
net::MockRead("HTTP/1.1 200 OK\r\n\r\n"), net::MockRead("hello world"),
net::MockRead(net::SYNCHRONOUS, net::OK),
};
- net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0);
+ net::StaticSocketDataProvider socket(reads, base::span<net::MockWrite>());
mock_socket_factory_->AddSocketDataProvider(&socket);
net::TestDelegate delegate;
diff --git a/chromium/components/data_use_measurement/content/content_url_request_classifier.cc b/chromium/components/data_use_measurement/content/content_url_request_classifier.cc
index dec90a8385a..3678ace5217 100644
--- a/chromium/components/data_use_measurement/content/content_url_request_classifier.cc
+++ b/chromium/components/data_use_measurement/content/content_url_request_classifier.cc
@@ -42,23 +42,6 @@ enum DataUsePageTransition {
namespace data_use_measurement {
-bool IsUserRequest(const net::URLRequest& request) {
- // The presence of ResourecRequestInfo in |request| implies that this request
- // was created for a content::WebContents. For now we could add a condition to
- // check ProcessType in info is content::PROCESS_TYPE_RENDERER, but it won't
- // be compatible with upcoming PlzNavigate architecture. So just existence of
- // ResourceRequestInfo is verified, and the current check should be compatible
- // with upcoming changes in PlzNavigate.
- // TODO(rajendrant): Verify this condition for different use cases. See
- // crbug.com/626063.
- return content::ResourceRequestInfo::ForRequest(&request) != nullptr;
-}
-
-bool ContentURLRequestClassifier::IsUserRequest(
- const net::URLRequest& request) const {
- return data_use_measurement::IsUserRequest(request);
-}
-
DataUseUserData::DataUseContentType ContentURLRequestClassifier::GetContentType(
const net::URLRequest& request,
const net::HttpResponseHeaders& response_headers) const {
@@ -141,12 +124,12 @@ void ContentURLRequestClassifier::RecordPageTransitionUMA(
DCHECK_NE(DataUsePageTransition::TRANSITION_MAX, data_use_page_transition);
// Use the more primitive STATIC_HISTOGRAM_POINTER_BLOCK macro because the
- // simple UMA_HISTOGRAM_ENUMERATION macros don't expose 'AddCount'.
+ // simple UMA_HISTOGRAM_ENUMERATION macros don't expose 'AddKiB'.
STATIC_HISTOGRAM_POINTER_BLOCK(
- "DataUse.PageTransition.UserTraffic",
- AddCount(data_use_page_transition, received_bytes),
+ "DataUse.PageTransition.UserTrafficKB",
+ AddKiB(data_use_page_transition, received_bytes),
base::LinearHistogram::FactoryGet(
- "DataUse.PageTransition.UserTraffic", 1,
+ "DataUse.PageTransition.UserTrafficKB", 1,
DataUsePageTransition::TRANSITION_MAX,
DataUsePageTransition::TRANSITION_MAX + 1,
base::HistogramBase::kUmaTargetedHistogramFlag));
diff --git a/chromium/components/data_use_measurement/content/content_url_request_classifier.h b/chromium/components/data_use_measurement/content/content_url_request_classifier.h
index 0726bb967c2..8ad2ec7bb6e 100644
--- a/chromium/components/data_use_measurement/content/content_url_request_classifier.h
+++ b/chromium/components/data_use_measurement/content/content_url_request_classifier.h
@@ -13,13 +13,9 @@ class URLRequest;
namespace data_use_measurement {
-// Returns true if the URLRequest |request| is initiated by user traffic.
-bool IsUserRequest(const net::URLRequest& request);
-
class ContentURLRequestClassifier : public URLRequestClassifier {
private:
// UrlRequestClassifier:
- bool IsUserRequest(const net::URLRequest& request) const override;
DataUseUserData::DataUseContentType GetContentType(
const net::URLRequest& request,
const net::HttpResponseHeaders& response_headers) const override;
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.cc b/chromium/components/data_use_measurement/core/data_use_measurement.cc
index da3b36e9299..7468983e747 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.cc
@@ -4,6 +4,9 @@
#include "components/data_use_measurement/core/data_use_measurement.h"
+#include <set>
+
+#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
@@ -19,6 +22,7 @@
#include "net/base/upload_data_stream.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
#include "net/url_request/url_request.h"
#if defined(OS_ANDROID)
@@ -42,17 +46,6 @@ void RecordUMAHistogramCount(const std::string& name, int64_t sample) {
histogram_pointer->Add(sample);
}
-// This function increases the value of |sample| bucket in |name| sparse
-// histogram by |value|. Conventional UMA histograms are not used because |name|
-// is not static.
-void IncreaseSparseHistogramByValue(const std::string& name,
- int64_t sample,
- int64_t value) {
- base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
- name + "KB", base::HistogramBase::kUmaTargetedHistogramFlag);
- histogram->AddKiB(sample, value);
-}
-
#if defined(OS_ANDROID)
void IncrementLatencyHistogramByCount(const std::string& name,
const base::TimeDelta& latency,
@@ -101,8 +94,6 @@ DataUseMeasurement::DataUseMeasurement(
{
DCHECK(ascriber_);
DCHECK(url_request_classifier_);
- memset(user_traffic_content_type_bytes_, 0,
- sizeof(user_traffic_content_type_bytes_));
#if defined(OS_ANDROID)
int64_t bytes = 0;
@@ -123,7 +114,7 @@ void DataUseMeasurement::OnBeforeURLRequest(net::URLRequest* request) {
if (!data_use_user_data) {
DataUseUserData::ServiceName service_name =
DataUseUserData::ServiceName::NOT_TAGGED;
- if (!url_request_classifier_->IsUserRequest(*request) &&
+ if (!IsUserRequest(*request) &&
domain_reliability::DomainReliabilityUploader::
OriginatedFromDomainReliability(*request)) {
// Detect if the request originated from DomainReliability.
@@ -198,7 +189,7 @@ void DataUseMeasurement::OnCompleted(const net::URLRequest& request,
void DataUseMeasurement::ReportDataUseUMA(const net::URLRequest& request,
TrafficDirection dir,
int64_t bytes) {
- bool is_user_traffic = url_request_classifier_->IsUserRequest(request);
+ bool is_user_traffic = IsUserRequest(request);
bool is_connection_cellular =
net::NetworkChangeNotifier::IsConnectionCellular(
net::NetworkChangeNotifier::GetConnectionType());
@@ -274,6 +265,9 @@ void DataUseMeasurement::UpdateDataUsePrefs(
: DataUseUserData::NOT_TAGGED;
// Update data use prefs for cellular connections.
+ // TODO(rajendrant): Change this to only report data use of user-initiated
+ // traffic and metrics services (UMA, UKM). This will help to remove the
+ // DataUseUserData::ServiceName enum.
if (!metrics_data_use_forwarder_.is_null()) {
metrics_data_use_forwarder_.Run(
DataUseUserData::GetServiceNameAsString(service_name),
@@ -298,6 +292,18 @@ DataUseUserData::AppState DataUseMeasurement::CurrentAppState() const {
return DataUseUserData::FOREGROUND;
}
+std::string DataUseMeasurement::GetHistogramNameWithConnectionType(
+ const char* prefix,
+ TrafficDirection dir,
+ DataUseUserData::AppState app_state) const {
+ return base::StringPrintf(
+ "%s.%s.%s", prefix, dir == UPSTREAM ? "Upstream" : "Downstream",
+ app_state == DataUseUserData::UNKNOWN
+ ? "Unknown"
+ : (app_state == DataUseUserData::FOREGROUND ? "Foreground"
+ : "Background"));
+}
+
std::string DataUseMeasurement::GetHistogramName(
const char* prefix,
TrafficDirection dir,
@@ -366,43 +372,28 @@ void DataUseMeasurement::MaybeRecordNetworkBytesOS() {
void DataUseMeasurement::ReportServicesMessageSizeUMA(
const net::URLRequest& request) {
- bool is_user_traffic = url_request_classifier_->IsUserRequest(request);
- bool is_connection_cellular =
- net::NetworkChangeNotifier::IsConnectionCellular(
- net::NetworkChangeNotifier::GetConnectionType());
-
- DataUseUserData* attached_service_data = static_cast<DataUseUserData*>(
- request.GetUserData(DataUseUserData::kUserDataKey));
- DataUseUserData::ServiceName service_name = DataUseUserData::NOT_TAGGED;
-
- if (attached_service_data)
- service_name = attached_service_data->service_name();
-
- if (!is_user_traffic) {
- ReportDataUsageServices(service_name, UPSTREAM, CurrentAppState(),
- is_connection_cellular,
+ if (!IsUserRequest(request)) {
+ ReportDataUsageServices(request.traffic_annotation().unique_id_hash_code,
+ UPSTREAM, CurrentAppState(),
request.GetTotalSentBytes());
- ReportDataUsageServices(service_name, DOWNSTREAM, CurrentAppState(),
- is_connection_cellular,
+ ReportDataUsageServices(request.traffic_annotation().unique_id_hash_code,
+ DOWNSTREAM, CurrentAppState(),
request.GetTotalReceivedBytes());
}
}
void DataUseMeasurement::ReportDataUsageServices(
- DataUseUserData::ServiceName service,
+ int32_t traffic_annotation_hash,
TrafficDirection dir,
DataUseUserData::AppState app_state,
- bool is_connection_cellular,
int64_t message_size) const {
if (message_size > 0) {
- IncreaseSparseHistogramByValue(
- GetHistogramName("DataUse.MessageSize.AllServices", dir, app_state,
- is_connection_cellular),
- service, message_size);
- if (app_state == DataUseUserData::BACKGROUND) {
- IncreaseSparseHistogramByValue("DataUse.AllServices.Background", service,
- message_size);
- }
+ // Conventional UMA histograms are not used because name is not static.
+ base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+ GetHistogramNameWithConnectionType("DataUse.AllServicesKB", dir,
+ app_state),
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->AddKiB(traffic_annotation_hash, message_size);
}
}
@@ -444,24 +435,19 @@ void DataUseMeasurement::RecordContentTypeHistogram(
: DataUseUserData::VIDEO);
}
// Use the more primitive STATIC_HISTOGRAM_POINTER_BLOCK macro because the
- // simple UMA_HISTOGRAM_ENUMERATION macros don't expose 'AddCount'.
+ // simple UMA_HISTOGRAM_ENUMERATION macros don't expose 'AddKiB'.
if (is_user_traffic) {
- bytes += user_traffic_content_type_bytes_[content_type];
- if (bytes >= 1024) {
- STATIC_HISTOGRAM_POINTER_BLOCK(
- "DataUse.ContentType.UserTrafficKB",
- AddCount(content_type, bytes / 1024),
- base::LinearHistogram::FactoryGet(
- "DataUse.ContentType.UserTrafficKB", 1, DataUseUserData::TYPE_MAX,
- DataUseUserData::TYPE_MAX + 1,
- base::HistogramBase::kUmaTargetedHistogramFlag));
- }
- user_traffic_content_type_bytes_[content_type] = bytes % 1024;
+ STATIC_HISTOGRAM_POINTER_BLOCK(
+ "DataUse.ContentType.UserTrafficKB", AddKiB(content_type, bytes),
+ base::LinearHistogram::FactoryGet(
+ "DataUse.ContentType.UserTrafficKB", 1, DataUseUserData::TYPE_MAX,
+ DataUseUserData::TYPE_MAX + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag));
} else {
STATIC_HISTOGRAM_POINTER_BLOCK(
- "DataUse.ContentType.Services", AddCount(content_type, bytes),
+ "DataUse.ContentType.ServicesKB", AddKiB(content_type, bytes),
base::LinearHistogram::FactoryGet(
- "DataUse.ContentType.Services", 1, DataUseUserData::TYPE_MAX,
+ "DataUse.ContentType.ServicesKB", 1, DataUseUserData::TYPE_MAX,
DataUseUserData::TYPE_MAX + 1,
base::HistogramBase::kUmaTargetedHistogramFlag));
}
@@ -469,7 +455,7 @@ void DataUseMeasurement::RecordContentTypeHistogram(
void DataUseMeasurement::RecordPageTransitionUMA(
const net::URLRequest& request) const {
- if (!url_request_classifier_->IsUserRequest(request))
+ if (!IsUserRequest(request))
return;
const DataUseRecorder* recorder = ascriber_->GetDataUseRecorder(request);
@@ -479,4 +465,28 @@ void DataUseMeasurement::RecordPageTransitionUMA(
}
}
+bool DataUseMeasurement::IsUserRequest(const net::URLRequest& request) const {
+ static const std::set<int32_t> kUserInitiatedTrafficAnnotations = {
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
+ "blink_extension_resource_loader"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("blink_resource_loader"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("parallel_download_job"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("renderer_initiated_download"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("drag_download_file"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
+ "download_web_contents_frame"), /*save page action*/
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
+ "render_view_context_menu"), /* save link as*/
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("webstore_installer"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("pdf_plugin_placeholder"),
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(
+ "downloads_api_run_async"), /* Can be user request or
+ autonomous request from extensions*/
+ COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("resource_dispatcher_host"),
+ };
+ return kUserInitiatedTrafficAnnotations.find(
+ request.traffic_annotation().unique_id_hash_code) !=
+ kUserInitiatedTrafficAnnotations.end();
+}
+
} // namespace data_use_measurement
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement.h b/chromium/components/data_use_measurement/core/data_use_measurement.h
index f4538382151..f72dc860416 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement.h
+++ b/chromium/components/data_use_measurement/core/data_use_measurement.h
@@ -88,6 +88,16 @@ class DataUseMeasurement {
// Makes the full name of the histogram. It is made from |prefix| and suffix
// which is made based on network and application status. suffix is a string
// representing whether the data use was on the send ("Upstream") or receive
+ // ("Downstream") path, and whether the app was in the "Foreground" or
+ // "Background".
+ std::string GetHistogramNameWithConnectionType(
+ const char* prefix,
+ TrafficDirection dir,
+ DataUseUserData::AppState app_state) const;
+
+ // Makes the full name of the histogram. It is made from |prefix| and suffix
+ // which is made based on network and application status. suffix is a string
+ // representing whether the data use was on the send ("Upstream") or receive
// ("Downstream") path, whether the app was in the "Foreground" or
// "Background", and whether a "Cellular" or "WiFi" network was use. For
// example, "Prefix.Upstream.Foreground.Cellular" is a possible output.
@@ -125,14 +135,11 @@ class DataUseMeasurement {
// Records data use histograms of services. It gets the size of exchanged
// message, its direction (which is upstream or downstream) and reports to the
// histogram DataUse.Services.{Dimensions} with, services as the buckets.
- // |app_state| indicates the app state which can be foreground, background, or
- // unknown.
- void ReportDataUsageServices(
- data_use_measurement::DataUseUserData::ServiceName service,
- TrafficDirection dir,
- DataUseUserData::AppState app_state,
- bool is_connection_cellular,
- int64_t message_size) const;
+ // |app_state| indicates the app state which can be foreground, or background.
+ void ReportDataUsageServices(int32_t traffic_annotation_hash,
+ TrafficDirection dir,
+ DataUseUserData::AppState app_state,
+ int64_t message_size) const;
// Records data use histograms split on TrafficDirection, AppState and
// TabState.
@@ -153,13 +160,16 @@ class DataUseMeasurement {
bool is_tab_visible,
int64_t bytes);
+ // Returns true if the |request| is initiated by user traffic.
+ bool IsUserRequest(const net::URLRequest& request) const;
+
// Classifier for identifying if an URL request is user initiated.
std::unique_ptr<URLRequestClassifier> url_request_classifier_;
- // Callback for updating data use prefs.
- // TODO(rajendrant): If a similar mechanism would need be used for components
- // other than metrics, then the better approach would be to refactor this
- // class to support registering arbitrary observers. crbug.com/601185
+ // Callback for updating metrics about data use of user traffic and services.
+ // TODO(rajendrant): Change this to not report data use service name. Instead
+ // pass a bool to distinguish if the data use is for metrics services
+ // (UMA, UKM).
metrics::UpdateUsagePrefCallbackType metrics_data_use_forwarder_;
// DataUseAscriber used to get the attributes of data use.
@@ -193,10 +203,6 @@ class DataUseMeasurement {
bool no_reads_since_background_;
#endif
- // User traffic data use by content type is logged in 1KB increments. The
- // remaining bytes are saved in this array until logged next time.
- int16_t user_traffic_content_type_bytes_[DataUseUserData::TYPE_MAX];
-
DISALLOW_COPY_AND_ASSIGN(DataUseMeasurement);
};
diff --git a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc b/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
index a91c363b7ff..599909eb2d3 100644
--- a/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
+++ b/chromium/components/data_use_measurement/core/data_use_measurement_unittest.cc
@@ -37,15 +37,6 @@ class TestURLRequestClassifier : public base::SupportsUserData::Data,
TestURLRequestClassifier() : content_type_(DataUseUserData::OTHER) {}
- bool IsUserRequest(const net::URLRequest& request) const override {
- return request.GetUserData(kUserDataKey) != nullptr;
- }
-
- static void MarkAsUserRequest(net::URLRequest* request) {
- request->SetUserData(kUserDataKey,
- std::make_unique<TestURLRequestClassifier>());
- }
-
DataUseUserData::DataUseContentType GetContentType(
const net::URLRequest& request,
const net::HttpResponseHeaders& response_headers) const override {
@@ -130,16 +121,22 @@ class DataUseMeasurementTest : public testing::Test {
net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 OK\r\n"
"Content-Length: 12\r\n\r\n"),
net::MockRead("Test Content")};
- net::StaticSocketDataProvider socket_data(reads, arraysize(reads), nullptr,
- 0);
+ net::StaticSocketDataProvider socket_data(reads,
+ base::span<net::MockWrite>());
socket_factory_->AddSocketDataProvider(&socket_data);
+ const auto traffic_annotation =
+ (is_user_request == kServiceRequest)
+ ? TRAFFIC_ANNOTATION_FOR_TESTS
+ : net::DefineNetworkTrafficAnnotation("blink_resource_loader",
+ "blink resource loaded will "
+ "be treated as "
+ "user-initiated request");
+
std::unique_ptr<net::URLRequest> request(
context_->CreateRequest(GURL("http://foo.com"), net::DEFAULT_PRIORITY,
- &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
- if (is_user_request == kUserRequest) {
- TestURLRequestClassifier::MarkAsUserRequest(request.get());
- } else {
+ &test_delegate, traffic_annotation));
+ if (is_user_request == kServiceRequest) {
request->SetUserData(
data_use_measurement::DataUseUserData::kUserDataKey,
std::make_unique<data_use_measurement::DataUseUserData>(
@@ -454,9 +451,9 @@ TEST_F(DataUseMeasurementTest, ContentType) {
std::unique_ptr<net::URLRequest> request =
CreateTestRequest(kServiceRequest);
data_use_measurement_.OnBeforeURLRequest(request.get());
- data_use_measurement_.OnNetworkBytesReceived(*request, 1000);
- histogram_tester.ExpectUniqueSample("DataUse.ContentType.Services",
- DataUseUserData::OTHER, 1000);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1024);
+ histogram_tester.ExpectUniqueSample("DataUse.ContentType.ServicesKB",
+ DataUseUserData::OTHER, 1);
}
// Video request in foreground.
@@ -516,16 +513,16 @@ TEST_F(DataUseMeasurementTest, ContentTypeInKB) {
ascriber_.SetTabVisibility(false);
data_use_measurement_.OnBeforeURLRequest(request.get());
data_use_measurement_.OnHeadersReceived(request.get(), nullptr);
- data_use_measurement_.OnNetworkBytesReceived(*request, 600);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 1024);
- // UserTrafficKB metric is not recorded for the first 600 bytes of data use.
- histogram_tester.ExpectTotalCount("DataUse.ContentType.UserTrafficKB", 0);
+ // UserTrafficKB metric is recorded for the first 1KB of data use.
+ histogram_tester.ExpectTotalCount("DataUse.ContentType.UserTrafficKB", 1);
- data_use_measurement_.OnNetworkBytesReceived(*request, 600);
+ data_use_measurement_.OnNetworkBytesReceived(*request, 3 * 1024);
- // UserTrafficKB recorded for 1KB.
+ // UserTrafficKB recorded for the total 4KB.
histogram_tester.ExpectUniqueSample("DataUse.ContentType.UserTrafficKB",
- DataUseUserData::VIDEO_APPBACKGROUND, 1);
+ DataUseUserData::VIDEO_APPBACKGROUND, 4);
}
#endif
diff --git a/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc b/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc
index 6423e459861..f7794235dfa 100644
--- a/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc
+++ b/chromium/components/data_use_measurement/core/data_use_network_delegate_unittest.cc
@@ -28,15 +28,6 @@ class TestURLRequestClassifier : public base::SupportsUserData::Data,
public:
static const void* const kUserDataKey;
- bool IsUserRequest(const net::URLRequest& request) const override {
- return request.GetUserData(kUserDataKey) != nullptr;
- }
-
- static void MarkAsUserRequest(net::URLRequest* request) {
- request->SetUserData(kUserDataKey,
- std::make_unique<TestURLRequestClassifier>());
- }
-
DataUseUserData::DataUseContentType GetContentType(
const net::URLRequest& request,
const net::HttpResponseHeaders& response_headers) const override {
@@ -91,7 +82,7 @@ std::unique_ptr<net::URLRequest> RequestURL(
net::MockRead(net::SYNCHRONOUS, net::OK),
};
net::StaticSocketDataProvider redirect_socket_data_provider(
- redirect_mock_reads, arraysize(redirect_mock_reads), nullptr, 0);
+ redirect_mock_reads, base::span<net::MockWrite>());
if (redirect)
socket_factory->AddSocketDataProvider(&redirect_socket_data_provider);
@@ -99,18 +90,22 @@ std::unique_ptr<net::URLRequest> RequestURL(
net::MockRead("HTTP/1.1 200 OK\r\n\r\n"), net::MockRead("response body"),
net::MockRead(net::SYNCHRONOUS, net::OK),
};
+ const auto traffic_annotation =
+ from_user ? net::DefineNetworkTrafficAnnotation("blink_resource_loader",
+ "blink resource loaded "
+ "will be treated as "
+ "user-initiated request")
+ : TRAFFIC_ANNOTATION_FOR_TESTS;
net::StaticSocketDataProvider response_socket_data_provider(
- response_mock_reads, arraysize(response_mock_reads), nullptr, 0);
+ response_mock_reads, base::span<net::MockWrite>());
socket_factory->AddSocketDataProvider(&response_socket_data_provider);
net::TestDelegate test_delegate;
test_delegate.set_quit_on_complete(true);
std::unique_ptr<net::URLRequest> request(
context->CreateRequest(GURL("http://example.com"), net::DEFAULT_PRIORITY,
- &test_delegate, TRAFFIC_ANNOTATION_FOR_TESTS));
+ &test_delegate, traffic_annotation));
- if (from_user) {
- TestURLRequestClassifier::MarkAsUserRequest(request.get());
- } else {
+ if (!from_user) {
request->SetUserData(
data_use_measurement::DataUseUserData::kUserDataKey,
std::make_unique<data_use_measurement::DataUseUserData>(
diff --git a/chromium/components/data_use_measurement/core/url_request_classifier.h b/chromium/components/data_use_measurement/core/url_request_classifier.h
index d8239b3f26b..65a10894541 100644
--- a/chromium/components/data_use_measurement/core/url_request_classifier.h
+++ b/chromium/components/data_use_measurement/core/url_request_classifier.h
@@ -21,9 +21,6 @@ class URLRequestClassifier {
public:
virtual ~URLRequestClassifier() {}
- // Returns true if the URLRequest |request| is initiated by user traffic.
- virtual bool IsUserRequest(const net::URLRequest& request) const = 0;
-
// Returns the content type of the URL request |request| with response headers
// |response_headers|. |is_app_foreground| and |is_tab_visible| indicate the
// current app and tab visibility state.
diff --git a/chromium/components/device_event_log/device_event_log.h b/chromium/components/device_event_log/device_event_log.h
index c3d52a72352..f5afc12f91b 100644
--- a/chromium/components/device_event_log/device_event_log.h
+++ b/chromium/components/device_event_log/device_event_log.h
@@ -60,6 +60,9 @@
#define MEMORY_LOG(level) \
DEVICE_LOG(::device_event_log::LOG_TYPE_MEMORY, \
::device_event_log::LOG_LEVEL_##level)
+#define PRINTER_LOG(level) \
+ DEVICE_LOG(::device_event_log::LOG_TYPE_PRINTER, \
+ ::device_event_log::LOG_LEVEL_##level)
// Generally prefer the above macros unless |type| or |level| is not constant.
@@ -101,8 +104,10 @@ enum LogType {
LOG_TYPE_HID = 5,
// Memory related events.
LOG_TYPE_MEMORY = 6,
+ // Printer related events.
+ LOG_TYPE_PRINTER = 7,
// Used internally, must be the last type (may be changed).
- LOG_TYPE_UNKNOWN = 7
+ LOG_TYPE_UNKNOWN = 8
};
// Used to specify the detail level for logging. In GetAsString, used to
diff --git a/chromium/components/device_event_log/device_event_log_impl.cc b/chromium/components/device_event_log/device_event_log_impl.cc
index 7d0cfe73e3a..a7f82c16737 100644
--- a/chromium/components/device_event_log/device_event_log_impl.cc
+++ b/chromium/components/device_event_log/device_event_log_impl.cc
@@ -33,6 +33,7 @@ const char* kLogTypeBluetoothDesc = "Bluetooth";
const char* kLogTypeUsbDesc = "USB";
const char* kLogTypeHidDesc = "HID";
const char* kLogTypeMemoryDesc = "Memory";
+const char* kLogTypePrinterDesc = "Printer";
std::string GetLogTypeString(LogType type) {
switch (type) {
@@ -50,6 +51,8 @@ std::string GetLogTypeString(LogType type) {
return kLogTypeHidDesc;
case LOG_TYPE_MEMORY:
return kLogTypeMemoryDesc;
+ case LOG_TYPE_PRINTER:
+ return kLogTypePrinterDesc;
case LOG_TYPE_UNKNOWN:
break;
}
diff --git a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
index 337e1eb9e13..2cd5e0e5b1f 100644
--- a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
+++ b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.cc
@@ -25,7 +25,6 @@
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "components/crash/core/common/crash_key.h"
-#include "mojo/public/cpp/system/platform_handle.h"
namespace discardable_memory {
namespace {
@@ -168,7 +167,7 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
// Search free lists for suitable span.
std::unique_ptr<DiscardableSharedMemoryHeap::Span> free_span =
heap_->SearchFreeLists(pages, slack);
- if (!free_span.get())
+ if (!free_span)
break;
// Attempt to lock |free_span|. Delete span and search free lists again
@@ -357,7 +356,7 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
"ClientDiscardableSharedMemoryManager::"
"AllocateLockedDiscardableSharedMemory",
"size", size, "id", id);
- base::SharedMemoryHandle handle;
+ base::UnsafeSharedMemoryRegion region;
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
base::ScopedClosureRunner event_signal_runner(
@@ -365,11 +364,12 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
io_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ClientDiscardableSharedMemoryManager::AllocateOnIO,
- base::Unretained(this), size, id, &handle,
+ base::Unretained(this), size, id, &region,
std::move(event_signal_runner)));
// Waiting until IPC has finished on the IO thread.
event.Wait();
- auto memory = std::make_unique<base::DiscardableSharedMemory>(handle);
+ auto memory =
+ std::make_unique<base::DiscardableSharedMemory>(std::move(region));
if (!memory->Map(size))
base::TerminateBecauseOutOfMemory(size);
return memory;
@@ -378,25 +378,21 @@ ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
void ClientDiscardableSharedMemoryManager::AllocateOnIO(
size_t size,
int32_t id,
- base::SharedMemoryHandle* handle,
+ base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner) {
(*manager_mojo_)
->AllocateLockedDiscardableSharedMemory(
static_cast<uint32_t>(size), id,
base::BindOnce(
&ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO,
- base::Unretained(this), handle, std::move(closure_runner)));
+ base::Unretained(this), region, std::move(closure_runner)));
}
void ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO(
- base::SharedMemoryHandle* handle,
+ base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner,
- mojo::ScopedSharedBufferHandle mojo_handle) {
- if (!mojo_handle.is_valid())
- return;
- auto result = mojo::UnwrapSharedMemoryHandle(std::move(mojo_handle), handle,
- nullptr, nullptr);
- DCHECK_EQ(result, MOJO_RESULT_OK);
+ base::UnsafeSharedMemoryRegion ret_region) {
+ *region = std::move(ret_region);
}
void ClientDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory(
diff --git a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h
index c6b375bdaa2..6e650e09cfe 100644
--- a/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h
+++ b/chromium/components/discardable_memory/client/client_discardable_shared_memory_manager.h
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/discardable_memory_allocator.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory_handle.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_provider.h"
#include "components/discardable_memory/common/discardable_memory_export.h"
@@ -67,11 +67,11 @@ class DISCARDABLE_MEMORY_EXPORT ClientDiscardableSharedMemoryManager
AllocateLockedDiscardableSharedMemory(size_t size, int32_t id);
void AllocateOnIO(size_t size,
int32_t id,
- base::SharedMemoryHandle* handle,
+ base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner);
- void AllocateCompletedOnIO(base::SharedMemoryHandle* handle,
+ void AllocateCompletedOnIO(base::UnsafeSharedMemoryRegion* region,
base::ScopedClosureRunner closure_runner,
- mojo::ScopedSharedBufferHandle mojo_handle);
+ base::UnsafeSharedMemoryRegion ret_region);
void DeletedDiscardableSharedMemory(int32_t id);
void MemoryUsageChanged(size_t new_bytes_allocated,
diff --git a/chromium/components/discardable_memory/public/interfaces/BUILD.gn b/chromium/components/discardable_memory/public/interfaces/BUILD.gn
index 0ce0a31e416..eba976f2b30 100644
--- a/chromium/components/discardable_memory/public/interfaces/BUILD.gn
+++ b/chromium/components/discardable_memory/public/interfaces/BUILD.gn
@@ -14,4 +14,8 @@ mojom("interfaces") {
get_path_info("../../../..", "abspath"),
"//mojo/services",
]
+
+ public_deps = [
+ "//mojo/public/mojom/base",
+ ]
}
diff --git a/chromium/components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom b/chromium/components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom
index 9d291d82d22..4fb837e8c8b 100644
--- a/chromium/components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom
+++ b/chromium/components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom
@@ -4,13 +4,15 @@
module discardable_memory.mojom;
+import "mojo/public/mojom/base/shared_memory.mojom";
+
// This interface is used for allocating discardable shared memory from browser
// process. For mus+ash, this service will live in mus process.
interface DiscardableSharedMemoryManager {
// Allocate a locked discardable shared memory segment.
AllocateLockedDiscardableSharedMemory(
uint32 size,
- int32 id) => (handle<shared_buffer>? memory);
+ int32 id) => (mojo_base.mojom.UnsafeSharedMemoryRegion region);
// Notify manager that a memory segment has been deleted.
DeletedDiscardableSharedMemory(int32 id);
};
diff --git a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
index 620c60e8967..17cdbbcfb43 100644
--- a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
+++ b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.cc
@@ -31,7 +31,6 @@
#include "components/crash/core/common/crash_key.h"
#include "components/discardable_memory/common/discardable_shared_memory_heap.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "mojo/public/cpp/system/platform_handle.h"
#if defined(OS_LINUX)
#include "base/files/file_path.h"
@@ -69,16 +68,12 @@ class MojoDiscardableSharedMemoryManagerImpl
uint32_t size,
int32_t id,
AllocateLockedDiscardableSharedMemoryCallback callback) override {
- base::SharedMemoryHandle handle;
- mojo::ScopedSharedBufferHandle memory;
+ base::UnsafeSharedMemoryRegion region;
if (manager_) {
manager_->AllocateLockedDiscardableSharedMemoryForClient(client_id_, size,
- id, &handle);
- memory = mojo::WrapSharedMemoryHandle(
- handle, size,
- mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
+ id, &region);
}
- std::move(callback).Run(std::move(memory));
+ std::move(callback).Run(std::move(region));
}
void DeletedDiscardableSharedMemory(int32_t id) override {
@@ -270,7 +265,7 @@ void DiscardableSharedMemoryManager::Bind(
DCHECK(!mojo_thread_message_loop_ ||
mojo_thread_message_loop_ == base::MessageLoop::current());
if (!mojo_thread_message_loop_) {
- mojo_thread_message_loop_ = base::MessageLoop::current();
+ mojo_thread_message_loop_ = base::MessageLoopCurrent::Get();
mojo_thread_message_loop_->AddDestructionObserver(this);
}
@@ -288,11 +283,11 @@ DiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(size_t size) {
// Note: Use DiscardableSharedMemoryHeap for in-process allocation
// of discardable memory if the cost of each allocation is too high.
- base::SharedMemoryHandle handle;
+ base::UnsafeSharedMemoryRegion region;
AllocateLockedDiscardableSharedMemory(kInvalidUniqueClientID, size, new_id,
- &handle);
+ &region);
std::unique_ptr<base::DiscardableSharedMemory> memory(
- new base::DiscardableSharedMemory(handle));
+ new base::DiscardableSharedMemory(std::move(region)));
if (!memory->Map(size))
base::TerminateBecauseOutOfMemory(size);
// Close file descriptor to avoid running out.
@@ -354,9 +349,9 @@ void DiscardableSharedMemoryManager::
int client_id,
size_t size,
int32_t id,
- base::SharedMemoryHandle* shared_memory_handle) {
+ base::UnsafeSharedMemoryRegion* shared_memory_region) {
AllocateLockedDiscardableSharedMemory(client_id, size, id,
- shared_memory_handle);
+ shared_memory_region);
}
void DiscardableSharedMemoryManager::ClientDeletedDiscardableSharedMemory(
@@ -432,7 +427,7 @@ void DiscardableSharedMemoryManager::OnPurgeMemory() {
void DiscardableSharedMemoryManager::WillDestroyCurrentMessageLoop() {
// The mojo thead is going to be destroyed. We should invalidate all related
// weak ptrs and remove the destrunction observer.
- DCHECK_EQ(mojo_thread_message_loop_, base::MessageLoop::current());
+ DCHECK_EQ(mojo_thread_message_loop_, base::MessageLoopCurrent::Get());
DLOG_IF(WARNING, mojo_thread_weak_ptr_factory_.HasWeakPtrs())
<< "Some MojoDiscardableSharedMemoryManagerImpls are still alive. They "
"will be leaked.";
@@ -443,14 +438,14 @@ void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
int client_id,
size_t size,
int32_t id,
- base::SharedMemoryHandle* shared_memory_handle) {
+ base::UnsafeSharedMemoryRegion* shared_memory_region) {
base::AutoLock lock(lock_);
// Make sure |id| is not already in use.
MemorySegmentMap& client_segments = clients_[client_id];
if (client_segments.find(id) != client_segments.end()) {
LOG(ERROR) << "Invalid discardable shared memory ID";
- *shared_memory_handle = base::SharedMemoryHandle();
+ *shared_memory_region = base::UnsafeSharedMemoryRegion();
return;
}
@@ -471,21 +466,21 @@ void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
std::unique_ptr<base::DiscardableSharedMemory> memory(
new base::DiscardableSharedMemory);
if (!memory->CreateAndMap(size)) {
- *shared_memory_handle = base::SharedMemoryHandle();
+ *shared_memory_region = base::UnsafeSharedMemoryRegion();
return;
}
base::CheckedNumeric<size_t> checked_bytes_allocated = bytes_allocated_;
checked_bytes_allocated += memory->mapped_size();
if (!checked_bytes_allocated.IsValid()) {
- *shared_memory_handle = base::SharedMemoryHandle();
+ *shared_memory_region = base::UnsafeSharedMemoryRegion();
return;
}
bytes_allocated_ = checked_bytes_allocated.ValueOrDie();
BytesAllocatedChanged(bytes_allocated_);
- *shared_memory_handle = base::SharedMemory::DuplicateHandle(memory->handle());
+ *shared_memory_region = memory->DuplicateRegion();
// Close file descriptor to avoid running out.
memory->Close();
@@ -642,7 +637,7 @@ void DiscardableSharedMemoryManager::ScheduleEnforceMemoryPolicy() {
void DiscardableSharedMemoryManager::InvalidateMojoThreadWeakPtrs(
base::WaitableEvent* event) {
- DCHECK_EQ(mojo_thread_message_loop_, base::MessageLoop::current());
+ DCHECK_EQ(mojo_thread_message_loop_, base::MessageLoopCurrent::Get());
mojo_thread_weak_ptr_factory_.InvalidateWeakPtrs();
mojo_thread_message_loop_->RemoveDestructionObserver(this);
mojo_thread_message_loop_ = nullptr;
diff --git a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.h b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.h
index 183e444083a..354cf393b44 100644
--- a/chromium/components/discardable_memory/service/discardable_shared_memory_manager.h
+++ b/chromium/components/discardable_memory/service/discardable_shared_memory_manager.h
@@ -20,9 +20,10 @@
#include "base/memory/memory_coordinator_client.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/process/process_handle.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -49,7 +50,7 @@ class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryManager
: public base::DiscardableMemoryAllocator,
public base::trace_event::MemoryDumpProvider,
public base::MemoryCoordinatorClient,
- public base::MessageLoop::DestructionObserver {
+ public base::MessageLoopCurrent::DestructionObserver {
public:
DiscardableSharedMemoryManager();
~DiscardableSharedMemoryManager() override;
@@ -67,12 +68,12 @@ class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryManager
base::trace_event::ProcessMemoryDump* pmd) override;
// This allocates a discardable memory segment for |process_handle|.
- // A valid shared memory handle is returned on success.
+ // A valid shared memory region is returned on success.
void AllocateLockedDiscardableSharedMemoryForClient(
int client_id,
size_t size,
int32_t id,
- base::SharedMemoryHandle* shared_memory_handle);
+ base::UnsafeSharedMemoryRegion* shared_memory_region);
// Call this to notify the manager that client process associated with
// |client_id| has deleted discardable memory segment with |id|.
@@ -120,14 +121,14 @@ class DISCARDABLE_MEMORY_EXPORT DiscardableSharedMemoryManager
void OnMemoryStateChange(base::MemoryState state) override;
void OnPurgeMemory() override;
- // base::MessageLoop::DestructionObserver implementation:
+ // base::MessageLoopCurrent::DestructionObserver implementation:
void WillDestroyCurrentMessageLoop() override;
void AllocateLockedDiscardableSharedMemory(
int client_id,
size_t size,
int32_t id,
- base::SharedMemoryHandle* shared_memory_handle);
+ base::UnsafeSharedMemoryRegion* shared_memory_region);
void DeletedDiscardableSharedMemory(int32_t id, int client_id);
void OnMemoryPressure(
base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
diff --git a/chromium/components/discardable_memory/service/discardable_shared_memory_manager_unittest.cc b/chromium/components/discardable_memory/service/discardable_shared_memory_manager_unittest.cc
index 3c2992401a6..bf6ef200036 100644
--- a/chromium/components/discardable_memory/service/discardable_shared_memory_manager_unittest.cc
+++ b/chromium/components/discardable_memory/service/discardable_shared_memory_manager_unittest.cc
@@ -20,8 +20,8 @@ class TestDiscardableSharedMemory : public base::DiscardableSharedMemory {
public:
TestDiscardableSharedMemory() {}
- explicit TestDiscardableSharedMemory(base::SharedMemoryHandle handle)
- : DiscardableSharedMemory(handle) {}
+ explicit TestDiscardableSharedMemory(base::UnsafeSharedMemoryRegion region)
+ : DiscardableSharedMemory(std::move(region)) {}
void SetNow(base::Time now) { now_ = now; }
@@ -75,12 +75,12 @@ TEST_F(DiscardableSharedMemoryManagerTest, AllocateForClient) {
uint8_t data[kDataSize];
memset(data, 0x80, kDataSize);
- base::SharedMemoryHandle shared_handle;
+ base::UnsafeSharedMemoryRegion shared_region;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 0, &shared_handle);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
+ kInvalidUniqueID, kDataSize, 0, &shared_region);
+ ASSERT_TRUE(shared_region.IsValid());
- TestDiscardableSharedMemory memory(shared_handle);
+ TestDiscardableSharedMemory memory(std::move(shared_region));
bool rv = memory.Map(kDataSize);
ASSERT_TRUE(rv);
@@ -96,21 +96,21 @@ TEST_F(DiscardableSharedMemoryManagerTest, AllocateForClient) {
TEST_F(DiscardableSharedMemoryManagerTest, Purge) {
const int kDataSize = 1024;
- base::SharedMemoryHandle shared_handle1;
+ base::UnsafeSharedMemoryRegion shared_region1;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 1, &shared_handle1);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1));
+ kInvalidUniqueID, kDataSize, 1, &shared_region1);
+ ASSERT_TRUE(shared_region1.IsValid());
- TestDiscardableSharedMemory memory1(shared_handle1);
+ TestDiscardableSharedMemory memory1(std::move(shared_region1));
bool rv = memory1.Map(kDataSize);
ASSERT_TRUE(rv);
- base::SharedMemoryHandle shared_handle2;
+ base::UnsafeSharedMemoryRegion shared_region2;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 2, &shared_handle2);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2));
+ kInvalidUniqueID, kDataSize, 2, &shared_region2);
+ ASSERT_TRUE(shared_region2.IsValid());
- TestDiscardableSharedMemory memory2(shared_handle2);
+ TestDiscardableSharedMemory memory2(std::move(shared_region2));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
@@ -160,12 +160,12 @@ TEST_F(DiscardableSharedMemoryManagerTest, Purge) {
TEST_F(DiscardableSharedMemoryManagerTest, EnforceMemoryPolicy) {
const int kDataSize = 1024;
- base::SharedMemoryHandle shared_handle;
+ base::UnsafeSharedMemoryRegion shared_region;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 0, &shared_handle);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
+ kInvalidUniqueID, kDataSize, 0, &shared_region);
+ ASSERT_TRUE(shared_region.IsValid());
- TestDiscardableSharedMemory memory(shared_handle);
+ TestDiscardableSharedMemory memory(std::move(shared_region));
bool rv = memory.Map(kDataSize);
ASSERT_TRUE(rv);
@@ -198,21 +198,21 @@ TEST_F(DiscardableSharedMemoryManagerTest,
ReduceMemoryAfterSegmentHasBeenDeleted) {
const int kDataSize = 1024;
- base::SharedMemoryHandle shared_handle1;
+ base::UnsafeSharedMemoryRegion shared_region1;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 1, &shared_handle1);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle1));
+ kInvalidUniqueID, kDataSize, 1, &shared_region1);
+ ASSERT_TRUE(shared_region1.IsValid());
- TestDiscardableSharedMemory memory1(shared_handle1);
+ TestDiscardableSharedMemory memory1(std::move(shared_region1));
bool rv = memory1.Map(kDataSize);
ASSERT_TRUE(rv);
- base::SharedMemoryHandle shared_handle2;
+ base::UnsafeSharedMemoryRegion shared_region2;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 2, &shared_handle2);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle2));
+ kInvalidUniqueID, kDataSize, 2, &shared_region2);
+ ASSERT_TRUE(shared_region2.IsValid());
- TestDiscardableSharedMemory memory2(shared_handle2);
+ TestDiscardableSharedMemory memory2(std::move(shared_region2));
rv = memory2.Map(kDataSize);
ASSERT_TRUE(rv);
@@ -261,10 +261,10 @@ TEST_F(DiscardableSharedMemoryManagerScheduleEnforceMemoryPolicyTest,
SetMemoryLimitOnSimpleThread) {
const int kDataSize = 1024;
- base::SharedMemoryHandle shared_handle;
+ base::UnsafeSharedMemoryRegion shared_region;
manager_->AllocateLockedDiscardableSharedMemoryForClient(
- kInvalidUniqueID, kDataSize, 0, &shared_handle);
- ASSERT_TRUE(base::SharedMemory::IsHandleValid(shared_handle));
+ kInvalidUniqueID, kDataSize, 0, &shared_region);
+ ASSERT_TRUE(shared_region.IsValid());
// Set the memory limit to a value that will require EnforceMemoryPolicy()
// to be schedule on a thread without a message loop.
diff --git a/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc b/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
index 43a6f040035..db2d88d6383 100644
--- a/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
+++ b/chromium/components/dom_distiller/content/browser/distillable_page_utils_browsertest.cc
@@ -59,10 +59,10 @@ class DomDistillerDistillablePageUtilsTest : public content::ContentBrowserTest,
base::FilePath pak_file;
base::FilePath pak_dir;
#if defined(OS_ANDROID)
- CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir));
+ CHECK(base::PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir));
pak_dir = pak_dir.Append(FILE_PATH_LITERAL("paks"));
#else
- PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::PathService::Get(base::DIR_MODULE, &pak_dir);
#endif // OS_ANDROID
pak_file =
pak_dir.Append(FILE_PATH_LITERAL("components_tests_resources.pak"));
@@ -72,7 +72,7 @@ class DomDistillerDistillablePageUtilsTest : public content::ContentBrowserTest,
void SetUpTestServer() {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.AppendASCII("components/test/data/dom_distiller");
embedded_test_server()->ServeFilesFromDirectory(path);
ASSERT_TRUE(embedded_test_server()->Start());
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
index 9c821be249e..9dd3a81fea2 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents.cc
@@ -121,19 +121,20 @@ void DistillerPageWebContents::CreateNewWebContents(const GURL& url) {
// Create new WebContents to use for distilling the content.
content::WebContents::CreateParams create_params(browser_context_);
create_params.initially_hidden = true;
- content::WebContents* web_contents =
+ std::unique_ptr<content::WebContents> web_contents =
content::WebContents::Create(create_params);
DCHECK(web_contents);
web_contents->SetDelegate(this);
// Start observing WebContents and load the requested URL.
- content::WebContentsObserver::Observe(web_contents);
+ content::WebContentsObserver::Observe(web_contents.get());
content::NavigationController::LoadURLParams params(url);
web_contents->GetController().LoadURLWithParams(params);
+ // SourcePageHandleWebContents takes ownership of |web_contents|.
source_page_handle_.reset(
- new SourcePageHandleWebContents(web_contents, true));
+ new SourcePageHandleWebContents(web_contents.release(), true));
}
gfx::Size DistillerPageWebContents::GetSizeForNewRenderView(
diff --git a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
index eaf9ed8717e..1fb0fad2e79 100644
--- a/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
+++ b/chromium/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
@@ -122,10 +122,10 @@ class DistillerPageWebContentsTest : public ContentBrowserTest {
base::FilePath pak_file;
base::FilePath pak_dir;
#if defined(OS_ANDROID)
- CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir));
+ CHECK(base::PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_dir));
pak_dir = pak_dir.Append(FILE_PATH_LITERAL("paks"));
#else
- PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::PathService::Get(base::DIR_MODULE, &pak_dir);
#endif // OS_ANDROID
pak_file =
pak_dir.Append(FILE_PATH_LITERAL("components_tests_resources.pak"));
@@ -135,7 +135,7 @@ class DistillerPageWebContentsTest : public ContentBrowserTest {
void SetUpTestServer() {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
embedded_test_server()->ServeFilesFromDirectory(
path.AppendASCII("components/test/data/dom_distiller"));
embedded_test_server()->ServeFilesFromDirectory(
diff --git a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source_unittest.cc b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source_unittest.cc
index df1fa73cc9f..5238069e723 100644
--- a/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source_unittest.cc
+++ b/chromium/components/dom_distiller/content/browser/dom_distiller_viewer_source_unittest.cc
@@ -22,9 +22,8 @@ class DomDistillerViewerSourceTest : public testing::Test {
};
TEST_F(DomDistillerViewerSourceTest, TestMimeType) {
- EXPECT_EQ("text/css", source_.get()->GetMimeType(kViewerCssPath));
- EXPECT_EQ("text/html", source_.get()->GetMimeType("anythingelse"));
-
+ EXPECT_EQ("text/css", source_->GetMimeType(kViewerCssPath));
+ EXPECT_EQ("text/html", source_->GetMimeType("anythingelse"));
}
} // namespace dom_distiller
diff --git a/chromium/components/dom_distiller/core/distiller.cc b/chromium/components/dom_distiller/core/distiller.cc
index f3ebbd8f66c..e7417310609 100644
--- a/chromium/components/dom_distiller/core/distiller.cc
+++ b/chromium/components/dom_distiller/core/distiller.cc
@@ -159,7 +159,7 @@ void DistillerImpl::OnPageDistillationFinished(
}
}
- DCHECK(distiller_result.get());
+ DCHECK(distiller_result);
DistilledPageData* page_data =
GetPageAtIndex(started_pages_index_[page_num]);
page_data->distilled_page_proto =
@@ -311,7 +311,7 @@ void DistillerImpl::OnFetchImageDone(int page_num,
const std::string& response) {
DCHECK(started_pages_index_.find(page_num) != started_pages_index_.end());
DistilledPageData* page_data = GetPageAtIndex(started_pages_index_[page_num]);
- DCHECK(page_data->distilled_page_proto.get());
+ DCHECK(page_data->distilled_page_proto);
DCHECK(url_fetcher);
auto fetcher_it = std::find_if(
page_data->image_fetchers_.begin(), page_data->image_fetchers_.end(),
diff --git a/chromium/components/dom_distiller/core/distiller_unittest.cc b/chromium/components/dom_distiller/core/distiller_unittest.cc
index d64a86234e3..3420e542d1b 100644
--- a/chromium/components/dom_distiller/core/distiller_unittest.cc
+++ b/chromium/components/dom_distiller/core/distiller_unittest.cc
@@ -18,6 +18,7 @@
#include "base/location.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
@@ -241,7 +242,7 @@ class TestDistillerURLFetcher : public DistillerURLFetcher {
}
void PostCallbackTask() {
- ASSERT_TRUE(base::MessageLoop::current());
+ ASSERT_TRUE(base::MessageLoopCurrent::Get());
ASSERT_FALSE(callback_.is_null());
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(callback_, responses_[url_]));
@@ -267,7 +268,7 @@ class TestDistillerURLFetcherFactory : public DistillerURLFetcherFactory {
class MockDistillerURLFetcherFactory : public DistillerURLFetcherFactory {
public:
MockDistillerURLFetcherFactory() : DistillerURLFetcherFactory(nullptr) {}
- virtual ~MockDistillerURLFetcherFactory() {}
+ ~MockDistillerURLFetcherFactory() override {}
MOCK_CONST_METHOD0(CreateDistillerURLFetcher, DistillerURLFetcher*());
};
diff --git a/chromium/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc b/chromium/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc
index 102c2d5e5e7..f7d8dd9a1e5 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc
@@ -194,7 +194,7 @@ TEST_F(DomDistillerRequestViewTest, TestContentNeverEmpty) {
std::unique_ptr<ArticleDistillationUpdate> article_update(
new ArticleDistillationUpdate(pages, false, false));
- handle.OnArticleUpdated(*article_update.get());
+ handle.OnArticleUpdated(*article_update);
EXPECT_THAT(handle.GetJavaScriptBuffer(), HasSubstr(no_content));
EXPECT_THAT(handle.GetJavaScriptBuffer(), Not(HasSubstr(valid_content)));
@@ -220,7 +220,7 @@ TEST_F(DomDistillerRequestViewTest, TestLoadingIndicator) {
std::unique_ptr<ArticleDistillationUpdate> article_update(
new ArticleDistillationUpdate(pages, true, false));
- handle.OnArticleUpdated(*article_update.get());
+ handle.OnArticleUpdated(*article_update);
EXPECT_THAT(handle.GetJavaScriptBuffer(), HasSubstr(show_loader));
}
diff --git a/chromium/components/dom_distiller/core/dom_distiller_service_unittest.cc b/chromium/components/dom_distiller/core/dom_distiller_service_unittest.cc
index 027339337a6..2e2271d46fc 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_service_unittest.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_service_unittest.cc
@@ -36,7 +36,7 @@ namespace {
class FakeViewRequestDelegate : public ViewRequestDelegate {
public:
- virtual ~FakeViewRequestDelegate() {}
+ ~FakeViewRequestDelegate() override {}
MOCK_METHOD1(OnArticleReady, void(const DistilledArticleProto* proto));
MOCK_METHOD1(OnArticleUpdated,
void(ArticleDistillationUpdate article_update));
@@ -45,7 +45,7 @@ class FakeViewRequestDelegate : public ViewRequestDelegate {
class MockDistillerObserver : public DomDistillerObserver {
public:
MOCK_METHOD1(ArticleEntriesUpdated, void(const std::vector<ArticleUpdate>&));
- virtual ~MockDistillerObserver() {}
+ ~MockDistillerObserver() override {}
};
class MockArticleAvailableCallback {
diff --git a/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc b/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc
index 09cb30ee9ca..ce2a0fc27e2 100644
--- a/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc
+++ b/chromium/components/dom_distiller/core/dom_distiller_store_unittest.cc
@@ -122,7 +122,7 @@ ArticleEntry GetSampleEntry(int id) {
class MockDistillerObserver : public DomDistillerObserver {
public:
MOCK_METHOD1(ArticleEntriesUpdated, void(const std::vector<ArticleUpdate>&));
- virtual ~MockDistillerObserver() {}
+ ~MockDistillerObserver() override {}
};
} // namespace
diff --git a/chromium/components/dom_distiller/core/fake_distiller.h b/chromium/components/dom_distiller/core/fake_distiller.h
index 94092d0105c..ff020145f49 100644
--- a/chromium/components/dom_distiller/core/fake_distiller.h
+++ b/chromium/components/dom_distiller/core/fake_distiller.h
@@ -20,7 +20,7 @@ namespace test {
class MockDistillerFactory : public DistillerFactory {
public:
MockDistillerFactory();
- virtual ~MockDistillerFactory();
+ ~MockDistillerFactory() override;
MOCK_METHOD0(CreateDistillerImpl, Distiller*());
std::unique_ptr<Distiller> CreateDistillerForUrl(
const GURL& unused) override {
diff --git a/chromium/components/dom_distiller/core/page_features_unittest.cc b/chromium/components/dom_distiller/core/page_features_unittest.cc
index 0bfeb142d69..93795c34f4c 100644
--- a/chromium/components/dom_distiller/core/page_features_unittest.cc
+++ b/chromium/components/dom_distiller/core/page_features_unittest.cc
@@ -24,7 +24,7 @@ namespace dom_distiller {
// done in Chromium matches that in the training pipeline.
TEST(DomDistillerPageFeaturesTest, TestCalculateDerivedFeatures) {
base::FilePath dir_source_root;
- EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &dir_source_root));
+ EXPECT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &dir_source_root));
std::string input_data;
ASSERT_TRUE(base::ReadFileToString(
dir_source_root.AppendASCII(
diff --git a/chromium/components/dom_distiller/core/task_tracker_unittest.cc b/chromium/components/dom_distiller/core/task_tracker_unittest.cc
index 8df60da74cc..5759cfa6bcb 100644
--- a/chromium/components/dom_distiller/core/task_tracker_unittest.cc
+++ b/chromium/components/dom_distiller/core/task_tracker_unittest.cc
@@ -22,7 +22,7 @@ namespace test {
class FakeViewRequestDelegate : public ViewRequestDelegate {
public:
- virtual ~FakeViewRequestDelegate() {}
+ ~FakeViewRequestDelegate() override {}
MOCK_METHOD1(OnArticleReady,
void(const DistilledArticleProto* article_proto));
MOCK_METHOD1(OnArticleUpdated,
diff --git a/chromium/components/dom_distiller/core/viewer_unittest.cc b/chromium/components/dom_distiller/core/viewer_unittest.cc
index d064704d033..e7bfd5afd83 100644
--- a/chromium/components/dom_distiller/core/viewer_unittest.cc
+++ b/chromium/components/dom_distiller/core/viewer_unittest.cc
@@ -92,9 +92,9 @@ TEST_F(DomDistillerViewerTest, TestCreatingViewUrlRequest) {
std::unique_ptr<FakeViewRequestDelegate> view_request_delegate(
new FakeViewRequestDelegate());
ViewerHandle* viewer_handle(new ViewerHandle(ViewerHandle::CancelCallback()));
- EXPECT_CALL(*service_.get(), ViewUrlImpl())
+ EXPECT_CALL(*service_, ViewUrlImpl())
.WillOnce(testing::Return(viewer_handle));
- EXPECT_CALL(*service_.get(), ViewEntryImpl()).Times(0);
+ EXPECT_CALL(*service_, ViewEntryImpl()).Times(0);
CreateViewRequest(
std::string("?") + kUrlKey + "=http%3A%2F%2Fwww.example.com%2F",
view_request_delegate.get());
@@ -104,9 +104,9 @@ TEST_F(DomDistillerViewerTest, TestCreatingViewEntryRequest) {
std::unique_ptr<FakeViewRequestDelegate> view_request_delegate(
new FakeViewRequestDelegate());
ViewerHandle* viewer_handle(new ViewerHandle(ViewerHandle::CancelCallback()));
- EXPECT_CALL(*service_.get(), ViewEntryImpl())
+ EXPECT_CALL(*service_, ViewEntryImpl())
.WillOnce(testing::Return(viewer_handle));
- EXPECT_CALL(*service_.get(), ViewUrlImpl()).Times(0);
+ EXPECT_CALL(*service_, ViewUrlImpl()).Times(0);
CreateViewRequest(std::string("?") + kEntryIdKey + "=abc-def",
view_request_delegate.get());
}
@@ -114,8 +114,8 @@ TEST_F(DomDistillerViewerTest, TestCreatingViewEntryRequest) {
TEST_F(DomDistillerViewerTest, TestCreatingInvalidViewRequest) {
std::unique_ptr<FakeViewRequestDelegate> view_request_delegate(
new FakeViewRequestDelegate());
- EXPECT_CALL(*service_.get(), ViewEntryImpl()).Times(0);
- EXPECT_CALL(*service_.get(), ViewUrlImpl()).Times(0);
+ EXPECT_CALL(*service_, ViewEntryImpl()).Times(0);
+ EXPECT_CALL(*service_, ViewUrlImpl()).Times(0);
// Specify none of the required query parameters.
CreateViewRequest("?foo=bar", view_request_delegate.get());
// Specify both of the required query parameters.
diff --git a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
index c9014ca1c73..5acc5f380e6 100644
--- a/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
+++ b/chromium/components/dom_distiller/standalone/content_extractor_browsertest.cc
@@ -11,7 +11,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
@@ -186,7 +185,7 @@ std::unique_ptr<DomDistillerService> CreateDomDistillerService(
void AddComponentsTestResources() {
base::FilePath pak_file;
base::FilePath pak_dir;
- PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::PathService::Get(base::DIR_MODULE, &pak_dir);
pak_file =
pak_dir.Append(FILE_PATH_LITERAL("components_tests_resources.pak"));
ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
@@ -422,7 +421,7 @@ class ContentExtractor : public ContentBrowserTest {
requests_.clear();
service_.reset();
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
size_t pending_tasks_;
diff --git a/chromium/components/dom_distiller_strings_grdp/OWNERS b/chromium/components/dom_distiller_strings_grdp/OWNERS
new file mode 100644
index 00000000000..9db389388fb
--- /dev/null
+++ b/chromium/components/dom_distiller_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/dom_distiller/OWNERS
diff --git a/chromium/components/dom_distiller_strings_grdp/README.md b/chromium/components/dom_distiller_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/dom_distiller_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/domain_reliability/dispatcher.cc b/chromium/components/domain_reliability/dispatcher.cc
index 00166e62201..0dd1c17674a 100644
--- a/chromium/components/domain_reliability/dispatcher.cc
+++ b/chromium/components/domain_reliability/dispatcher.cc
@@ -10,7 +10,6 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/message_loop/message_loop.h"
#include "base/timer/timer.h"
#include "components/domain_reliability/util.h"
diff --git a/chromium/components/domain_reliability/header.cc b/chromium/components/domain_reliability/header.cc
index 0d2136d8a12..cefcd602a52 100644
--- a/chromium/components/domain_reliability/header.cc
+++ b/chromium/components/domain_reliability/header.cc
@@ -278,7 +278,7 @@ DomainReliabilityHeader::ReleaseConfig() {
}
std::string DomainReliabilityHeader::ToString() const {
- std::string string = "";
+ std::string string;
int64_t max_age_s = max_age_.InSeconds();
if (config_->collectors.empty()) {
@@ -314,7 +314,7 @@ DomainReliabilityHeader::DomainReliabilityHeader(
base::TimeDelta max_age)
: status_(status), config_(std::move(config)), max_age_(max_age) {
DCHECK_EQ(PARSE_SET_CONFIG, status_);
- DCHECK(config_.get());
+ DCHECK(config_);
DCHECK_NE(0, max_age_.InMicroseconds());
}
diff --git a/chromium/components/domain_reliability/monitor.cc b/chromium/components/domain_reliability/monitor.cc
index a5cf89e8aca..64cf9b17883 100644
--- a/chromium/components/domain_reliability/monitor.cc
+++ b/chromium/components/domain_reliability/monitor.cc
@@ -336,7 +336,7 @@ void DomainReliabilityMonitor::OnRequestLegComplete(
return;
int response_code;
- if (request.response_info.headers.get())
+ if (request.response_info.headers)
response_code = request.response_info.headers->response_code();
else
response_code = -1;
@@ -394,7 +394,7 @@ void DomainReliabilityMonitor::OnRequestLegComplete(
void DomainReliabilityMonitor::MaybeHandleHeader(
const RequestInfo& request) {
- if (!request.response_info.headers.get())
+ if (!request.response_info.headers)
return;
size_t iter = 0;
diff --git a/chromium/components/domain_reliability/quic_error_mapping.h b/chromium/components/domain_reliability/quic_error_mapping.h
index f9d373b27d6..48e5b238dfb 100644
--- a/chromium/components/domain_reliability/quic_error_mapping.h
+++ b/chromium/components/domain_reliability/quic_error_mapping.h
@@ -7,7 +7,7 @@
#include <string>
-#include "net/quic/core/quic_packets.h"
+#include "net/third_party/quic/core/quic_packets.h"
// N.B. This file and the .cc are separate from util.h/.cc so that they can be
// independently updated by folks working on QUIC when new errors are added.
diff --git a/chromium/components/domain_reliability/service.cc b/chromium/components/domain_reliability/service.cc
index ed369b869d6..3efe542ef57 100644
--- a/chromium/components/domain_reliability/service.cc
+++ b/chromium/components/domain_reliability/service.cc
@@ -65,7 +65,7 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner)
override {
- DCHECK(!network_task_runner_.get());
+ DCHECK(!network_task_runner_);
std::unique_ptr<DomainReliabilityMonitor> monitor(
new DomainReliabilityMonitor(
@@ -86,7 +86,7 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
DomainReliabilityClearMode clear_mode,
const base::Callback<bool(const GURL&)>& origin_filter,
const base::Closure& callback) override {
- DCHECK(network_task_runner_.get());
+ DCHECK(network_task_runner_);
network_task_runner_->PostTaskAndReply(
FROM_HERE, base::Bind(&DomainReliabilityMonitor::ClearBrowsingData,
@@ -96,7 +96,7 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
void GetWebUIData(const base::Callback<void(std::unique_ptr<base::Value>)>&
callback) const override {
- DCHECK(network_task_runner_.get());
+ DCHECK(network_task_runner_);
PostTaskAndReplyWithResult(
network_task_runner_.get(),
@@ -106,7 +106,7 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
}
void SetDiscardUploadsForTesting(bool discard_uploads) override {
- DCHECK(network_task_runner_.get());
+ DCHECK(network_task_runner_);
network_task_runner_->PostTask(
FROM_HERE,
@@ -117,7 +117,7 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
void AddContextForTesting(
std::unique_ptr<const DomainReliabilityConfig> config) override {
- DCHECK(network_task_runner_.get());
+ DCHECK(network_task_runner_);
network_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&AddContextForTestingOnNetworkTaskRunner,
@@ -125,7 +125,7 @@ class DomainReliabilityServiceImpl : public DomainReliabilityService {
}
void ForceUploadsForTesting() override {
- DCHECK(network_task_runner_.get());
+ DCHECK(network_task_runner_);
network_task_runner_->PostTask(
FROM_HERE,
diff --git a/chromium/components/domain_reliability/service_unittest.cc b/chromium/components/domain_reliability/service_unittest.cc
index 301b8df1b0e..84a1b1b459b 100644
--- a/chromium/components/domain_reliability/service_unittest.cc
+++ b/chromium/components/domain_reliability/service_unittest.cc
@@ -5,8 +5,8 @@
#include "components/domain_reliability/service.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "base/time/time.h"
#include "components/domain_reliability/monitor.h"
diff --git a/chromium/components/domain_reliability/test_util.cc b/chromium/components/domain_reliability/test_util.cc
index e34d1bd59cb..c805207e282 100644
--- a/chromium/components/domain_reliability/test_util.cc
+++ b/chromium/components/domain_reliability/test_util.cc
@@ -121,7 +121,9 @@ MockTime::MockTime()
MockTime::~MockTime() {}
-base::Time MockTime::Now() { return now_; }
+base::Time MockTime::Now() const {
+ return now_;
+}
base::TimeTicks MockTime::NowTicks() const {
return now_ticks_;
}
diff --git a/chromium/components/domain_reliability/test_util.h b/chromium/components/domain_reliability/test_util.h
index 30d32d08d8d..725f3ae66a9 100644
--- a/chromium/components/domain_reliability/test_util.h
+++ b/chromium/components/domain_reliability/test_util.h
@@ -75,7 +75,7 @@ class MockTime : public MockableTime {
~MockTime() override;
// MockableTime implementation:
- base::Time Now() override;
+ base::Time Now() const override;
base::TimeTicks NowTicks() const override;
std::unique_ptr<MockableTime::Timer> CreateTimer() override;
diff --git a/chromium/components/domain_reliability/util.cc b/chromium/components/domain_reliability/util.cc
index 5895c7653b2..27ebf275d9c 100644
--- a/chromium/components/domain_reliability/util.cc
+++ b/chromium/components/domain_reliability/util.cc
@@ -241,7 +241,9 @@ MockableTime::MockableTime() {}
ActualTime::ActualTime() {}
ActualTime::~ActualTime() {}
-base::Time ActualTime::Now() { return base::Time::Now(); }
+base::Time ActualTime::Now() const {
+ return base::Time::Now();
+}
base::TimeTicks ActualTime::NowTicks() const {
return base::TimeTicks::Now();
}
diff --git a/chromium/components/domain_reliability/util.h b/chromium/components/domain_reliability/util.h
index 0b95d2329e6..b0fba9d5e55 100644
--- a/chromium/components/domain_reliability/util.h
+++ b/chromium/components/domain_reliability/util.h
@@ -82,7 +82,7 @@ class DOMAIN_RELIABILITY_EXPORT MockableTime : public base::Clock,
~MockableTime() override;
// Clock impl; returns base::Time::Now() or a mocked version thereof.
- base::Time Now() override = 0;
+ base::Time Now() const override = 0;
// TickClock impl; returns base::TimeTicks::Now() or a mocked version thereof.
base::TimeTicks NowTicks() const override = 0;
@@ -105,7 +105,7 @@ class DOMAIN_RELIABILITY_EXPORT ActualTime : public MockableTime {
~ActualTime() override;
// MockableTime implementation:
- base::Time Now() override;
+ base::Time Now() const override;
base::TimeTicks NowTicks() const override;
std::unique_ptr<MockableTime::Timer> CreateTimer() override;
};
diff --git a/chromium/components/download/content/factory/download_service_factory.h b/chromium/components/download/content/factory/download_service_factory.h
index a1142c179e5..0f7a1dc6182 100644
--- a/chromium/components/download/content/factory/download_service_factory.h
+++ b/chromium/components/download/content/factory/download_service_factory.h
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "components/download/internal/background_service/blob_task_proxy.h"
#include "components/download/public/background_service/clients.h"
diff --git a/chromium/components/download/content/internal/download_driver_impl.cc b/chromium/components/download/content/internal/download_driver_impl.cc
index 050d79d7922..f0d9a07cfa1 100644
--- a/chromium/components/download/content/internal/download_driver_impl.cc
+++ b/chromium/components/download/content/internal/download_driver_impl.cc
@@ -84,7 +84,7 @@ DriverEntry DownloadDriverImpl::CreateDriverEntry(
: item->GetFullPath();
entry.completion_time = item->GetEndTime();
entry.response_headers = item->GetResponseHeaders();
- if (entry.response_headers.get()) {
+ if (entry.response_headers) {
entry.can_resume =
entry.response_headers->HasHeaderValue("Accept-Ranges", "bytes") ||
(entry.response_headers->HasHeader("Content-Range") &&
@@ -171,7 +171,9 @@ void DownloadDriverImpl::Start(
download::DownloadSource::INTERNAL_API);
download_url_params->set_post_body(post_body);
- download_manager_->DownloadUrl(std::move(download_url_params), nullptr);
+ download_manager_->DownloadUrl(std::move(download_url_params),
+ nullptr /* blob_data_handle */,
+ nullptr /* blob_url_loader_factory */);
}
void DownloadDriverImpl::Remove(const std::string& guid) {
diff --git a/chromium/components/download/content/public/all_download_item_notifier_unittest.cc b/chromium/components/download/content/public/all_download_item_notifier_unittest.cc
index 98a9394b551..b893c8ab19a 100644
--- a/chromium/components/download/content/public/all_download_item_notifier_unittest.cc
+++ b/chromium/components/download/content/public/all_download_item_notifier_unittest.cc
@@ -20,7 +20,7 @@ namespace {
class MockNotifierObserver : public AllDownloadItemNotifier::Observer {
public:
MockNotifierObserver() {}
- virtual ~MockNotifierObserver() {}
+ ~MockNotifierObserver() override {}
MOCK_METHOD2(OnDownloadCreated,
void(content::DownloadManager* manager, DownloadItem* item));
@@ -40,9 +40,9 @@ class AllDownloadItemNotifierTest : public testing::Test {
AllDownloadItemNotifierTest()
: download_manager_(new content::MockDownloadManager) {}
- virtual ~AllDownloadItemNotifierTest() {}
+ ~AllDownloadItemNotifierTest() override {}
- content::MockDownloadManager& manager() { return *download_manager_.get(); }
+ content::MockDownloadManager& manager() { return *download_manager_; }
download::MockDownloadItem& item() { return item_; }
@@ -57,7 +57,7 @@ class AllDownloadItemNotifierTest : public testing::Test {
MockNotifierObserver& observer() { return observer_; }
void SetNotifier() {
- EXPECT_CALL(*download_manager_.get(), AddObserver(_));
+ EXPECT_CALL(*download_manager_, AddObserver(_));
notifier_.reset(
new AllDownloadItemNotifier(download_manager_.get(), &observer_));
}
diff --git a/chromium/components/download/downloader/in_progress/BUILD.gn b/chromium/components/download/downloader/in_progress/BUILD.gn
index bd728e0ec35..fea2be16b81 100644
--- a/chromium/components/download/downloader/in_progress/BUILD.gn
+++ b/chromium/components/download/downloader/in_progress/BUILD.gn
@@ -9,13 +9,21 @@ if (is_android) {
source_set("in_progress") {
sources = [
+ "download_db_entry.cc",
+ "download_db_entry.h",
"download_entry.cc",
"download_entry.h",
+ "download_info.cc",
+ "download_info.h",
"in_progress_cache.h",
"in_progress_cache_impl.cc",
"in_progress_cache_impl.h",
"in_progress_conversions.cc",
"in_progress_conversions.h",
+ "in_progress_info.cc",
+ "in_progress_info.h",
+ "ukm_info.cc",
+ "ukm_info.h",
]
deps = [
@@ -23,6 +31,7 @@ source_set("in_progress") {
"//components/download/downloader/in_progress/proto",
"//net",
"//services/metrics/public/cpp:metrics_cpp",
+ "//services/network/public/mojom",
]
}
diff --git a/chromium/components/download/downloader/in_progress/download_db_entry.cc b/chromium/components/download/downloader/in_progress/download_db_entry.cc
new file mode 100644
index 00000000000..b36192a39a6
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/download_db_entry.cc
@@ -0,0 +1,19 @@
+// 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 "components/download/downloader/in_progress/download_db_entry.h"
+
+namespace download {
+
+DownloadDBEntry::DownloadDBEntry() = default;
+
+DownloadDBEntry::DownloadDBEntry(const DownloadDBEntry& other) = default;
+
+DownloadDBEntry::~DownloadDBEntry() = default;
+
+bool DownloadDBEntry::operator==(const DownloadDBEntry& other) const {
+ return id == other.id && download_info == other.download_info;
+}
+
+} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/download_db_entry.h b/chromium/components/download/downloader/in_progress/download_db_entry.h
new file mode 100644
index 00000000000..0aee2cf6175
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/download_db_entry.h
@@ -0,0 +1,33 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_DOWNLOAD_DB_ENTRY_H_
+#define COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_DOWNLOAD_DB_ENTRY_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "components/download/downloader/in_progress/download_info.h"
+
+namespace download {
+
+// Representing one entry in the DownloadDB.
+struct DownloadDBEntry {
+ public:
+ DownloadDBEntry();
+ DownloadDBEntry(const DownloadDBEntry& other);
+ ~DownloadDBEntry();
+
+ bool operator==(const DownloadDBEntry& other) const;
+
+ // ID of the entry, this should be namespace + GUID of the download.
+ std::string id;
+
+ // Information about a regular download.
+ base::Optional<DownloadInfo> download_info;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_DOWNLOAD_DB_ENTRY_H_
diff --git a/chromium/components/download/downloader/in_progress/download_entry.h b/chromium/components/download/downloader/in_progress/download_entry.h
index 4881ae859a8..c06ac01e531 100644
--- a/chromium/components/download/downloader/in_progress/download_entry.h
+++ b/chromium/components/download/downloader/in_progress/download_entry.h
@@ -7,6 +7,7 @@
#include <string>
+#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_source.h"
#include "components/download/public/common/download_url_parameters.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
diff --git a/chromium/components/download/downloader/in_progress/download_info.cc b/chromium/components/download/downloader/in_progress/download_info.cc
new file mode 100644
index 00000000000..80b7f6257d6
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/download_info.cc
@@ -0,0 +1,20 @@
+// 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 "components/download/downloader/in_progress/download_info.h"
+
+namespace download {
+
+DownloadInfo::DownloadInfo() = default;
+
+DownloadInfo::DownloadInfo(const DownloadInfo& other) = default;
+
+DownloadInfo::~DownloadInfo() = default;
+
+bool DownloadInfo::operator==(const DownloadInfo& other) const {
+ return guid == other.guid && ukm_info == other.ukm_info &&
+ in_progress_info == other.in_progress_info;
+}
+
+} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/download_info.h b/chromium/components/download/downloader/in_progress/download_info.h
new file mode 100644
index 00000000000..80085ee1406
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/download_info.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_DOWNLOAD_INFO_H_
+#define COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_DOWNLOAD_INFO_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "components/download/downloader/in_progress/in_progress_info.h"
+#include "components/download/downloader/in_progress/ukm_info.h"
+
+namespace download {
+
+// Contains needed information to reconstruct a download item.
+struct DownloadInfo {
+ public:
+ DownloadInfo();
+ DownloadInfo(const DownloadInfo& other);
+ ~DownloadInfo();
+
+ bool operator==(const DownloadInfo& other) const;
+
+ // Download GUID.
+ std::string guid;
+
+ // UKM information for reporting.
+ base::Optional<UkmInfo> ukm_info;
+
+ // In progress information for active download.
+ base::Optional<InProgressInfo> in_progress_info;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_DOWNLOAD_INFO_H_
diff --git a/chromium/components/download/downloader/in_progress/in_progress_cache.h b/chromium/components/download/downloader/in_progress/in_progress_cache.h
index af2c859929d..02459c0e026 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_cache.h
+++ b/chromium/components/download/downloader/in_progress/in_progress_cache.h
@@ -12,6 +12,8 @@
namespace download {
+extern const base::FilePath::CharType kDownloadMetadataStoreFilename[];
+
// InProgressCache provides a write-through cache that persists
// information related to an in-progress download such as request origin, retry
// count, resumption parameters etc to the disk. The entries are written to disk
@@ -21,7 +23,7 @@ class InProgressCache {
virtual ~InProgressCache() = default;
// Initializes the cache.
- virtual void Initialize(const base::RepeatingClosure& callback) = 0;
+ virtual void Initialize(base::OnceClosure callback) = 0;
// Adds or updates an existing entry.
virtual void AddOrReplaceEntry(const DownloadEntry& entry) = 0;
diff --git a/chromium/components/download/downloader/in_progress/in_progress_cache_impl.cc b/chromium/components/download/downloader/in_progress/in_progress_cache_impl.cc
index 5640de21ab9..6088307f523 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_cache_impl.cc
+++ b/chromium/components/download/downloader/in_progress/in_progress_cache_impl.cc
@@ -14,6 +14,9 @@
namespace download {
+const base::FilePath::CharType kDownloadMetadataStoreFilename[] =
+ FILE_PATH_LITERAL("in_progress_download_metadata_store");
+
namespace {
// Helper functions for |entries_| related operations.
@@ -57,6 +60,9 @@ void RemoveEntryFromEntries(metadata_pb::DownloadEntries& entries,
// Helper functions for file read/write operations.
std::vector<char> ReadEntriesFromFile(base::FilePath file_path) {
+ if (file_path.empty())
+ return std::vector<char>();
+
// Check validity of file.
base::File entries_file(file_path,
base::File::FLAG_OPEN | base::File::FLAG_READ);
@@ -110,7 +116,8 @@ std::string EntriesToString(const metadata_pb::DownloadEntries& entries) {
}
void WriteEntriesToFile(const std::string& entries, base::FilePath file_path) {
- DCHECK(!file_path.empty());
+ if (file_path.empty())
+ return;
if (!base::ImportantFileWriter::WriteFileAtomically(file_path, entries)) {
LOG(ERROR) << "Could not write download entries to file: "
@@ -129,26 +136,26 @@ InProgressCacheImpl::InProgressCacheImpl(
InProgressCacheImpl::~InProgressCacheImpl() = default;
-void InProgressCacheImpl::Initialize(const base::RepeatingClosure& callback) {
+void InProgressCacheImpl::Initialize(base::OnceClosure callback) {
// If it's already initialized, just run the callback.
if (initialization_status_ == CACHE_INITIALIZED) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, callback);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(callback));
return;
}
- pending_actions_.push_back(callback);
-
// If uninitialized, initialize |entries_| by reading from file.
if (initialization_status_ == CACHE_UNINITIALIZED) {
base::PostTaskAndReplyWithResult(
task_runner_.get(), FROM_HERE,
base::BindOnce(&ReadEntriesFromFile, file_path_),
base::BindOnce(&InProgressCacheImpl::OnInitialized,
- weak_ptr_factory_.GetWeakPtr()));
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
}
-void InProgressCacheImpl::OnInitialized(const std::vector<char>& entries) {
+void InProgressCacheImpl::OnInitialized(base::OnceClosure callback,
+ const std::vector<char>& entries) {
if (!entries.empty()) {
if (!entries_.ParseFromArray(entries.data(), entries.size())) {
// TODO(crbug.com/778425): Get UMA for errors.
@@ -160,11 +167,7 @@ void InProgressCacheImpl::OnInitialized(const std::vector<char>& entries) {
initialization_status_ = CACHE_INITIALIZED;
- while (!pending_actions_.empty()) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- pending_actions_.front());
- pending_actions_.pop_front();
- }
+ std::move(callback).Run();
}
void InProgressCacheImpl::AddOrReplaceEntry(const DownloadEntry& entry) {
diff --git a/chromium/components/download/downloader/in_progress/in_progress_cache_impl.h b/chromium/components/download/downloader/in_progress/in_progress_cache_impl.h
index 6dd5fcea7f9..23687e0b7b8 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_cache_impl.h
+++ b/chromium/components/download/downloader/in_progress/in_progress_cache_impl.h
@@ -7,7 +7,6 @@
#include <string>
-#include "base/containers/circular_deque.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -24,13 +23,13 @@ namespace download {
// right away.
class InProgressCacheImpl : public InProgressCache {
public:
- explicit InProgressCacheImpl(
+ InProgressCacheImpl(
const base::FilePath& cache_file_path,
const scoped_refptr<base::SequencedTaskRunner>& task_runner);
~InProgressCacheImpl() override;
// InProgressCache implementation.
- void Initialize(const base::RepeatingClosure& callback) override;
+ void Initialize(base::OnceClosure callback) override;
void AddOrReplaceEntry(const DownloadEntry& entry) override;
base::Optional<DownloadEntry> RetrieveEntry(const std::string& guid) override;
void RemoveEntry(const std::string& guid) override;
@@ -44,12 +43,12 @@ class InProgressCacheImpl : public InProgressCache {
};
// Steps to execute after initialization is complete.
- void OnInitialized(const std::vector<char>& entries);
+ void OnInitialized(base::OnceClosure callback,
+ const std::vector<char>& entries);
metadata_pb::DownloadEntries entries_;
base::FilePath file_path_;
InitializationStatus initialization_status_;
- base::circular_deque<base::RepeatingClosure> pending_actions_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::WeakPtrFactory<InProgressCacheImpl> weak_ptr_factory_;
diff --git a/chromium/components/download/downloader/in_progress/in_progress_cache_impl_unittest.cc b/chromium/components/download/downloader/in_progress/in_progress_cache_impl_unittest.cc
index 12012af4938..8150815bf31 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_cache_impl_unittest.cc
+++ b/chromium/components/download/downloader/in_progress/in_progress_cache_impl_unittest.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
#include "base/task_runner.h"
#include "base/task_scheduler/post_task.h"
#include "base/test/scoped_task_environment.h"
diff --git a/chromium/components/download/downloader/in_progress/in_progress_conversions.cc b/chromium/components/download/downloader/in_progress/in_progress_conversions.cc
index a5e3c8d819f..5620961d2c6 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_conversions.cc
+++ b/chromium/components/download/downloader/in_progress/in_progress_conversions.cc
@@ -6,6 +6,7 @@
#include <utility>
#include "base/logging.h"
+#include "base/pickle.h"
namespace download {
@@ -37,7 +38,6 @@ metadata_pb::DownloadEntry InProgressConversions::DownloadEntryToProto(
auto* proto_header = proto.add_request_headers();
*proto_header = HttpRequestHeaderToProto(header);
}
-
return proto;
}
@@ -139,4 +139,151 @@ InProgressConversions::HttpRequestHeaderFromProto(
return std::make_pair(proto.key(), proto.value());
}
+// static
+metadata_pb::InProgressInfo InProgressConversions::InProgressInfoToProto(
+ const InProgressInfo& in_progress_info) {
+ metadata_pb::InProgressInfo proto;
+ for (size_t i = 0; i < in_progress_info.url_chain.size(); ++i)
+ proto.add_url_chain(in_progress_info.url_chain[i].spec());
+ proto.set_fetch_error_body(in_progress_info.fetch_error_body);
+ for (const auto& header : in_progress_info.request_headers) {
+ auto* proto_header = proto.add_request_headers();
+ *proto_header = HttpRequestHeaderToProto(header);
+ }
+ proto.set_etag(in_progress_info.etag);
+ proto.set_last_modified(in_progress_info.last_modified);
+ proto.set_total_bytes(in_progress_info.total_bytes);
+ base::Pickle current_path;
+ in_progress_info.current_path.WriteToPickle(&current_path);
+ proto.set_current_path(current_path.data(), current_path.size());
+ base::Pickle target_path;
+ in_progress_info.target_path.WriteToPickle(&target_path);
+ proto.set_target_path(target_path.data(), target_path.size());
+ proto.set_received_bytes(in_progress_info.received_bytes);
+ proto.set_end_time(
+ in_progress_info.end_time.ToDeltaSinceWindowsEpoch().InMilliseconds());
+ for (size_t i = 0; i < in_progress_info.received_slices.size(); ++i) {
+ metadata_pb::ReceivedSlice* slice = proto.add_received_slices();
+ slice->set_received_bytes(
+ in_progress_info.received_slices[i].received_bytes);
+ slice->set_offset(in_progress_info.received_slices[i].offset);
+ slice->set_finished(in_progress_info.received_slices[i].finished);
+ }
+ proto.set_hash(in_progress_info.hash);
+ proto.set_transient(in_progress_info.transient);
+ proto.set_state(in_progress_info.state);
+ proto.set_danger_type(in_progress_info.danger_type);
+ proto.set_interrupt_reason(in_progress_info.interrupt_reason);
+ proto.set_paused(in_progress_info.paused);
+ proto.set_metered(in_progress_info.metered);
+ proto.set_request_origin(in_progress_info.request_origin);
+ proto.set_bytes_wasted(in_progress_info.bytes_wasted);
+ return proto;
+}
+
+// static
+InProgressInfo InProgressConversions::InProgressInfoFromProto(
+ const metadata_pb::InProgressInfo& proto) {
+ InProgressInfo info;
+ for (const auto& url : proto.url_chain())
+ info.url_chain.emplace_back(url);
+ info.fetch_error_body = proto.fetch_error_body();
+ for (const auto& header : proto.request_headers())
+ info.request_headers.emplace_back(HttpRequestHeaderFromProto(header));
+ info.etag = proto.etag();
+ info.last_modified = proto.last_modified();
+ info.total_bytes = proto.total_bytes();
+ base::PickleIterator current_path(
+ base::Pickle(proto.current_path().data(), proto.current_path().size()));
+ info.current_path.ReadFromPickle(&current_path);
+ base::PickleIterator target_path(
+ base::Pickle(proto.target_path().data(), proto.target_path().size()));
+ info.target_path.ReadFromPickle(&target_path);
+ info.received_bytes = proto.received_bytes();
+ info.end_time = base::Time::FromDeltaSinceWindowsEpoch(
+ base::TimeDelta::FromMilliseconds(proto.end_time()));
+
+ for (int i = 0; i < proto.received_slices_size(); ++i) {
+ info.received_slices.emplace_back(proto.received_slices(i).offset(),
+ proto.received_slices(i).received_bytes(),
+ proto.received_slices(i).finished());
+ }
+ info.hash = proto.hash();
+ info.transient = proto.transient();
+ info.state = static_cast<DownloadItem::DownloadState>(proto.state());
+ info.danger_type = static_cast<DownloadDangerType>(proto.danger_type());
+ info.interrupt_reason =
+ static_cast<DownloadInterruptReason>(proto.interrupt_reason());
+ info.paused = proto.paused();
+ info.metered = proto.metered();
+ info.request_origin = proto.request_origin();
+ info.bytes_wasted = proto.bytes_wasted();
+ return info;
+}
+
+UkmInfo InProgressConversions::UkmInfoFromProto(
+ const metadata_pb::UkmInfo& proto) {
+ UkmInfo info;
+ info.download_source = DownloadSourceFromProto(proto.download_source());
+ info.ukm_download_id = proto.ukm_download_id();
+ return info;
+}
+
+metadata_pb::UkmInfo InProgressConversions::UkmInfoToProto(
+ const UkmInfo& info) {
+ metadata_pb::UkmInfo proto;
+ proto.set_download_source(DownloadSourceToProto(info.download_source));
+ proto.set_ukm_download_id(info.ukm_download_id);
+ return proto;
+}
+
+DownloadInfo InProgressConversions::DownloadInfoFromProto(
+ const metadata_pb::DownloadInfo& proto) {
+ DownloadInfo info;
+ info.guid = proto.guid();
+ if (proto.has_ukm_info())
+ info.ukm_info = UkmInfoFromProto(proto.ukm_info());
+ if (proto.has_in_progress_info())
+ info.in_progress_info = InProgressInfoFromProto(proto.in_progress_info());
+ return info;
+}
+
+metadata_pb::DownloadInfo InProgressConversions::DownloadInfoToProto(
+ const DownloadInfo& info) {
+ metadata_pb::DownloadInfo proto;
+ proto.set_guid(info.guid);
+ if (info.ukm_info.has_value()) {
+ auto ukm_info = std::make_unique<metadata_pb::UkmInfo>(
+ UkmInfoToProto(info.ukm_info.value()));
+ proto.set_allocated_ukm_info(ukm_info.release());
+ }
+ if (info.in_progress_info.has_value()) {
+ auto in_progress_info = std::make_unique<metadata_pb::InProgressInfo>(
+ InProgressInfoToProto(info.in_progress_info.value()));
+ proto.set_allocated_in_progress_info(in_progress_info.release());
+ }
+ return proto;
+}
+
+DownloadDBEntry InProgressConversions::DownloadDBEntryFromProto(
+ const metadata_pb::DownloadDBEntry& proto) {
+ DownloadDBEntry entry;
+ entry.id = proto.id();
+ if (proto.has_download_info())
+ entry.download_info = DownloadInfoFromProto(proto.download_info());
+ return entry;
+}
+
+metadata_pb::DownloadDBEntry InProgressConversions::DownloadDBEntryToProto(
+ const DownloadDBEntry& info) {
+ metadata_pb::DownloadDBEntry proto;
+ proto.set_id(info.id);
+ if (info.download_info.has_value()) {
+ auto download_info = std::make_unique<metadata_pb::DownloadInfo>(
+ DownloadInfoToProto(info.download_info.value()));
+ proto.set_allocated_download_info(download_info.release());
+ }
+ return proto;
+}
+
} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/in_progress_conversions.h b/chromium/components/download/downloader/in_progress/in_progress_conversions.h
index d5b97cc8497..e95f6084bba 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_conversions.h
+++ b/chromium/components/download/downloader/in_progress/in_progress_conversions.h
@@ -6,9 +6,13 @@
#define COMPONENTS_DOWNLOAD_IN_PROGRESS_IN_PROGRESS_CONVERSIONS_H_
#include "base/macros.h"
+#include "components/download/downloader/in_progress/download_db_entry.h"
#include "components/download/downloader/in_progress/download_entry.h"
+#include "components/download/downloader/in_progress/download_info.h"
+#include "components/download/downloader/in_progress/in_progress_info.h"
#include "components/download/downloader/in_progress/proto/download_entry.pb.h"
#include "components/download/downloader/in_progress/proto/download_source.pb.h"
+#include "components/download/downloader/in_progress/ukm_info.h"
namespace download {
@@ -37,6 +41,28 @@ class InProgressConversions {
static std::pair<std::string, std::string> HttpRequestHeaderFromProto(
const metadata_pb::HttpRequestHeader& proto);
+
+ static metadata_pb::InProgressInfo InProgressInfoToProto(
+ const InProgressInfo& in_progress_info);
+
+ static InProgressInfo InProgressInfoFromProto(
+ const metadata_pb::InProgressInfo& proto);
+
+ static metadata_pb::UkmInfo UkmInfoToProto(const UkmInfo& ukm_info);
+
+ static UkmInfo UkmInfoFromProto(const metadata_pb::UkmInfo& proto);
+
+ static metadata_pb::DownloadInfo DownloadInfoToProto(
+ const DownloadInfo& download_info);
+
+ static DownloadInfo DownloadInfoFromProto(
+ const metadata_pb::DownloadInfo& proto);
+
+ static metadata_pb::DownloadDBEntry DownloadDBEntryToProto(
+ const DownloadDBEntry& entry);
+
+ static DownloadDBEntry DownloadDBEntryFromProto(
+ const metadata_pb::DownloadDBEntry& proto);
};
} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/in_progress_conversions_unittest.cc b/chromium/components/download/downloader/in_progress/in_progress_conversions_unittest.cc
index 4fcda352b45..df5fb673b1c 100644
--- a/chromium/components/download/downloader/in_progress/in_progress_conversions_unittest.cc
+++ b/chromium/components/download/downloader/in_progress/in_progress_conversions_unittest.cc
@@ -9,6 +9,48 @@
namespace download {
+namespace {
+
+InProgressInfo CreateInProgressInfo() {
+ InProgressInfo info;
+ // InProgressInfo with valid fields.
+ info.current_path = base::FilePath(FILE_PATH_LITERAL("/tmp.crdownload"));
+ info.target_path = base::FilePath(FILE_PATH_LITERAL("/tmp"));
+ info.url_chain.emplace_back("http://foo");
+ info.url_chain.emplace_back("http://foo2");
+ info.end_time = base::Time::NowFromSystemTime().LocalMidnight();
+ info.etag = "A";
+ info.last_modified = "Wed, 1 Oct 2018 07:00:00 GMT";
+ info.received_bytes = 1000;
+ info.total_bytes = 10000;
+ info.state = DownloadItem::IN_PROGRESS;
+ info.danger_type = DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
+ info.interrupt_reason = DOWNLOAD_INTERRUPT_REASON_NONE;
+ info.transient = false;
+ info.paused = false;
+ info.hash = "abcdefg";
+ info.metered = true;
+ info.received_slices.emplace_back(0, 500, false);
+ info.received_slices.emplace_back(5000, 500, false);
+ info.request_origin = "request origin";
+ info.bytes_wasted = 1234;
+ info.fetch_error_body = true;
+ info.request_headers.emplace_back(
+ std::make_pair<std::string, std::string>("123", "456"));
+ info.request_headers.emplace_back(
+ std::make_pair<std::string, std::string>("ABC", "def"));
+ return info;
+}
+
+DownloadInfo CreateDownloadInfo() {
+ DownloadInfo info;
+ info.in_progress_info = CreateInProgressInfo();
+ info.ukm_info = UkmInfo(DownloadSource::FROM_RENDERER, 100);
+ return info;
+}
+
+} // namespace
+
class InProgressConversionsTest : public testing::Test,
public InProgressConversions {
public:
@@ -79,4 +121,38 @@ TEST_F(InProgressConversionsTest, HttpRequestHeaders) {
HttpRequestHeaderFromProto(HttpRequestHeaderToProto(header)));
}
+TEST_F(InProgressConversionsTest, InProgressInfo) {
+ // InProgressInfo with no fields.
+ InProgressInfo info;
+ EXPECT_EQ(false, info.fetch_error_body);
+ EXPECT_TRUE(info.request_headers.empty());
+ EXPECT_EQ(info, InProgressInfoFromProto(InProgressInfoToProto(info)));
+
+ // InProgressInfo with valid fields.
+ info = CreateInProgressInfo();
+ EXPECT_EQ(info, InProgressInfoFromProto(InProgressInfoToProto(info)));
+}
+
+TEST_F(InProgressConversionsTest, UkmInfo) {
+ UkmInfo info(DownloadSource::FROM_RENDERER, 100);
+ EXPECT_EQ(info, UkmInfoFromProto(UkmInfoToProto(info)));
+}
+
+TEST_F(InProgressConversionsTest, DownloadInfo) {
+ DownloadInfo info;
+ EXPECT_EQ(info, DownloadInfoFromProto(DownloadInfoToProto(info)));
+
+ info = CreateDownloadInfo();
+ EXPECT_EQ(info, DownloadInfoFromProto(DownloadInfoToProto(info)));
+}
+
+TEST_F(InProgressConversionsTest, DownloadDBEntry) {
+ DownloadDBEntry entry;
+ EXPECT_EQ(entry, DownloadDBEntryFromProto(DownloadDBEntryToProto(entry)));
+
+ entry.id = "abc";
+ entry.download_info = CreateDownloadInfo();
+ EXPECT_EQ(entry, DownloadDBEntryFromProto(DownloadDBEntryToProto(entry)));
+}
+
} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/in_progress_info.cc b/chromium/components/download/downloader/in_progress/in_progress_info.cc
new file mode 100644
index 00000000000..2a622e6da5f
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/in_progress_info.cc
@@ -0,0 +1,32 @@
+// 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 "components/download/downloader/in_progress/in_progress_info.h"
+
+namespace download {
+
+InProgressInfo::InProgressInfo() = default;
+
+InProgressInfo::InProgressInfo(const InProgressInfo& other) = default;
+
+InProgressInfo::~InProgressInfo() = default;
+
+bool InProgressInfo::operator==(const InProgressInfo& other) const {
+ return url_chain == other.url_chain &&
+ fetch_error_body == other.fetch_error_body &&
+ request_headers == other.request_headers && etag == other.etag &&
+ last_modified == other.last_modified &&
+ total_bytes == other.total_bytes &&
+ current_path == other.current_path &&
+ target_path == other.target_path &&
+ received_bytes == other.received_bytes && end_time == other.end_time &&
+ received_slices == other.received_slices && hash == other.hash &&
+ transient == other.transient && state == other.state &&
+ danger_type == other.danger_type &&
+ interrupt_reason == other.interrupt_reason && paused == other.paused &&
+ metered == other.metered && request_origin == other.request_origin &&
+ bytes_wasted == other.bytes_wasted;
+}
+
+} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/in_progress_info.h b/chromium/components/download/downloader/in_progress/in_progress_info.h
new file mode 100644
index 00000000000..b075e9bd336
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/in_progress_info.h
@@ -0,0 +1,105 @@
+// 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 COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_IN_PROGRESS_INFO_H_
+#define COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_IN_PROGRESS_INFO_H_
+
+#include <string>
+#include <vector>
+
+#include "components/download/public/common/download_danger_type.h"
+#include "components/download/public/common/download_item.h"
+#include "components/download/public/common/download_url_parameters.h"
+#include "url/gurl.h"
+
+namespace download {
+
+// Contains information to reconstruct an interrupted download item for
+// resumption.
+struct InProgressInfo {
+ public:
+ InProgressInfo();
+ InProgressInfo(const InProgressInfo& other);
+ ~InProgressInfo();
+
+ bool operator==(const InProgressInfo& other) const;
+
+ // request info ------------------------------------------------------------
+
+ // The url chain.
+ std::vector<GURL> url_chain;
+
+ // If the entity body of unsuccessful HTTP response, like HTTP 404, will be
+ // downloaded.
+ bool fetch_error_body = false;
+
+ // Request header key/value pairs that will be added to the download HTTP
+ // request.
+ DownloadUrlParameters::RequestHeadersType request_headers;
+
+ // response info -----------------------------------------------------------
+
+ // Contents of most recently seen ETag header.
+ std::string etag;
+
+ // Contents of most recently seen Last-Modified header.
+ std::string last_modified;
+
+ // The total number of bytes in the download.
+ int64_t total_bytes = 0;
+
+ // destination info --------------------------------------------------------
+
+ // The current path to the download (potentially different from final if
+ // download is in progress or interrupted).
+ base::FilePath current_path;
+
+ // The target path where the download will go when it's complete.
+ base::FilePath target_path;
+
+ // The number of bytes received (so far).
+ int64_t received_bytes = 0;
+
+ // The time when the download completed.
+ base::Time end_time;
+
+ // Data slices that have been downloaded so far. The slices must be ordered
+ // by their offset.
+ std::vector<DownloadItem::ReceivedSlice> received_slices;
+
+ // Hash of the downloaded content.
+ std::string hash;
+
+ // state info --------------------------------------------------------------
+
+ // Whether this download is transient. Transient items are cleaned up after
+ // completion and not shown in the UI.
+ bool transient = false;
+
+ // The current state of the download.
+ DownloadItem::DownloadState state = DownloadItem::DownloadState::IN_PROGRESS;
+
+ // Whether and how the download is dangerous.
+ DownloadDangerType danger_type =
+ DownloadDangerType::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS;
+
+ // The reason the download was interrupted, if state == kStateInterrupted.
+ DownloadInterruptReason interrupt_reason = DOWNLOAD_INTERRUPT_REASON_NONE;
+
+ // Whether this download is paused.
+ bool paused = false;
+
+ // Whether the download is initiated on a metered network
+ bool metered = false;
+
+ // Represents the origin information for this download. Used by offline pages.
+ std::string request_origin;
+
+ // Count for how many (extra) bytes were used (including resumption).
+ int64_t bytes_wasted = 0;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_IN_PROGRESS_INFO_H_
diff --git a/chromium/components/download/downloader/in_progress/proto/download_entry.proto b/chromium/components/download/downloader/in_progress/proto/download_entry.proto
index 776b00600a4..ddf18d4a196 100644
--- a/chromium/components/download/downloader/in_progress/proto/download_entry.proto
+++ b/chromium/components/download/downloader/in_progress/proto/download_entry.proto
@@ -15,6 +15,13 @@ message HttpRequestHeader {
optional string value = 2;
}
+// Slice information for parallel downloading.
+message ReceivedSlice {
+ optional int64 offset = 1;
+ optional int64 received_bytes = 2;
+ optional bool finished = 3;
+}
+
// Stores various in-progress metadata related to a download.
message DownloadEntry {
optional string guid = 1;
@@ -30,3 +37,48 @@ message DownloadEntry {
message DownloadEntries {
repeated DownloadEntry entries = 1;
}
+
+// Information for ukm reporting
+message UkmInfo {
+ optional DownloadSource download_source = 1;
+ optional int64 ukm_download_id = 2;
+}
+
+// Information about an in progress download.
+message InProgressInfo {
+ repeated string url_chain = 1;
+ optional bool fetch_error_body = 2;
+ repeated HttpRequestHeader request_headers = 3;
+ optional string etag = 4;
+ optional string last_modified = 5;
+ optional int64 total_bytes = 6;
+ optional bytes current_path = 7; // Serialized pickles to support string16
+ optional bytes target_path = 8; // Serialized pickles to support string16
+ optional int64 received_bytes = 9;
+ optional int64 end_time = 10;
+ repeated ReceivedSlice received_slices = 11;
+ optional string hash = 12;
+ optional bool transient = 13;
+ optional int32 state = 14;
+ optional int32 danger_type = 15;
+ optional int32 interrupt_reason = 16;
+ optional bool paused = 17;
+ optional bool metered = 18;
+ optional string request_origin = 19;
+ optional int64 bytes_wasted = 20;
+}
+
+// Stores various in-progress metadata related to a download.
+// WIP and will replace DownloadEntry.
+message DownloadInfo {
+ optional string guid = 1;
+ optional UkmInfo ukm_info = 2;
+ optional InProgressInfo in_progress_info = 3;
+}
+
+// database entry for download information.
+message DownloadDBEntry {
+ optional string id = 1;
+ // Add field for offline page download.
+ oneof entry { DownloadInfo download_info = 2; }
+} \ No newline at end of file
diff --git a/chromium/components/download/downloader/in_progress/ukm_info.cc b/chromium/components/download/downloader/in_progress/ukm_info.cc
new file mode 100644
index 00000000000..a02851403ac
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/ukm_info.cc
@@ -0,0 +1,23 @@
+// 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 "components/download/downloader/in_progress/ukm_info.h"
+
+namespace download {
+
+UkmInfo::UkmInfo() = default;
+
+UkmInfo::UkmInfo(const UkmInfo& other) = default;
+
+UkmInfo::UkmInfo(DownloadSource download_source, int64_t ukm_download_id)
+ : download_source(download_source), ukm_download_id(ukm_download_id) {}
+
+UkmInfo::~UkmInfo() = default;
+
+bool UkmInfo::operator==(const UkmInfo& other) const {
+ return download_source == other.download_source &&
+ ukm_download_id == other.ukm_download_id;
+}
+
+} // namespace download
diff --git a/chromium/components/download/downloader/in_progress/ukm_info.h b/chromium/components/download/downloader/in_progress/ukm_info.h
new file mode 100644
index 00000000000..ac3c73ff17d
--- /dev/null
+++ b/chromium/components/download/downloader/in_progress/ukm_info.h
@@ -0,0 +1,34 @@
+// 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 COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_UKM_INFO_H_
+#define COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_UKM_INFO_H_
+
+#include <stdint.h>
+
+#include "components/download/public/common/download_source.h"
+
+namespace download {
+
+// Contains information for UKM reporting.
+struct UkmInfo {
+ public:
+ UkmInfo();
+ UkmInfo(DownloadSource download_source, int64_t ukm_download_id);
+ UkmInfo(const UkmInfo& other);
+ ~UkmInfo();
+
+ bool operator==(const UkmInfo& other) const;
+
+ // The source that triggered the download.
+ DownloadSource download_source = DownloadSource::UNKNOWN;
+
+ // Unique ID that tracks the download UKM entry, where 0 means the
+ // download_id is not yet initialized.
+ uint64_t ukm_download_id = 0;
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_DOWNLOADER_IN_PROGRESS_UKM_INFO_H_
diff --git a/chromium/components/download/internal/background_service/blob_task_proxy.cc b/chromium/components/download/internal/background_service/blob_task_proxy.cc
index ab525937720..4c0813902d0 100644
--- a/chromium/components/download/internal/background_service/blob_task_proxy.cc
+++ b/chromium/components/download/internal/background_service/blob_task_proxy.cc
@@ -61,7 +61,7 @@ void BlobTaskProxy::SaveAsBlobOnIO(std::unique_ptr<std::string> data,
// Build blob data. This has to do a copy into blob's internal storage.
std::string blob_uuid = base::GenerateGUID();
auto builder = std::make_unique<storage::BlobDataBuilder>(blob_uuid);
- builder->AppendData(*data.get());
+ builder->AppendData(*data);
blob_data_handle_ =
blob_storage_context_->AddFinishedBlob(std::move(builder));
diff --git a/chromium/components/download/internal/background_service/controller_impl.cc b/chromium/components/download/internal/background_service/controller_impl.cc
index 5b602187936..2150eca0b17 100644
--- a/chromium/components/download/internal/background_service/controller_impl.cc
+++ b/chromium/components/download/internal/background_service/controller_impl.cc
@@ -1051,7 +1051,7 @@ void ControllerImpl::KillTimedOutUploads() {
void ControllerImpl::NotifyClientsOfStartup(bool state_lost) {
auto categorized = util::MapEntriesToMetadataForClients(
- clients_->GetRegisteredClients(), model_->PeekEntries());
+ clients_->GetRegisteredClients(), model_->PeekEntries(), driver_.get());
for (auto client_id : clients_->GetRegisteredClients()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
diff --git a/chromium/components/download/internal/background_service/controller_impl_unittest.cc b/chromium/components/download/internal/background_service/controller_impl_unittest.cc
index 66d8ff523da..1e4f96bab34 100644
--- a/chromium/components/download/internal/background_service/controller_impl_unittest.cc
+++ b/chromium/components/download/internal/background_service/controller_impl_unittest.cc
@@ -437,8 +437,8 @@ TEST_F(DownloadServiceControllerImplTest, SuccessfulInitWithExistingDownload) {
std::vector<Entry> entries = {entry1, entry2, entry3};
std::vector<DownloadMetaData> expected_downloads = {
- util::BuildDownloadMetaData(&entry1),
- util::BuildDownloadMetaData(&entry2)};
+ util::BuildDownloadMetaData(&entry1, driver_),
+ util::BuildDownloadMetaData(&entry2, driver_)};
EXPECT_CALL(*client_,
OnServiceInitialized(false, testing::UnorderedElementsAreArray(
diff --git a/chromium/components/download/internal/background_service/entry_utils.cc b/chromium/components/download/internal/background_service/entry_utils.cc
index 8738cb02350..4402d4c9647 100644
--- a/chromium/components/download/internal/background_service/entry_utils.cc
+++ b/chromium/components/download/internal/background_service/entry_utils.cc
@@ -6,6 +6,7 @@
#include <algorithm>
+#include "components/download/internal/background_service/download_driver.h"
#include "components/download/internal/background_service/entry.h"
#include "components/download/public/background_service/download_metadata.h"
@@ -24,7 +25,8 @@ uint32_t GetNumberOfLiveEntriesForClient(DownloadClient client,
std::map<DownloadClient, std::vector<DownloadMetaData>>
MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients,
- const std::vector<Entry*>& entries) {
+ const std::vector<Entry*>& entries,
+ DownloadDriver* driver) {
std::map<DownloadClient, std::vector<DownloadMetaData>> categorized;
for (auto* entry : entries) {
@@ -32,7 +34,7 @@ MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients,
if (clients.find(client) == clients.end())
client = DownloadClient::INVALID;
- categorized[client].push_back(BuildDownloadMetaData(entry));
+ categorized[client].push_back(BuildDownloadMetaData(entry, driver));
}
return categorized;
@@ -86,14 +88,22 @@ bool EntryBetterThan(const Entry& lhs, const Entry& rhs) {
return lhs.create_time < rhs.create_time;
}
-DownloadMetaData BuildDownloadMetaData(Entry* entry) {
+DownloadMetaData BuildDownloadMetaData(Entry* entry, DownloadDriver* driver) {
DCHECK(entry);
DownloadMetaData meta_data;
meta_data.guid = entry->guid;
if (entry->state == Entry::State::COMPLETE) {
meta_data.completion_info =
CompletionInfo(entry->target_file_path, entry->bytes_downloaded);
+ // If the download is completed, the |current_size| needs to pull from entry
+ // since the history db record has been deleted.
+ meta_data.current_size = entry->bytes_downloaded;
+ return meta_data;
}
+
+ auto driver_entry = driver->Find(entry->guid);
+ if (driver_entry)
+ meta_data.current_size = driver_entry->bytes_downloaded;
return meta_data;
}
diff --git a/chromium/components/download/internal/background_service/entry_utils.h b/chromium/components/download/internal/background_service/entry_utils.h
index 410383c50b6..a519d759e24 100644
--- a/chromium/components/download/internal/background_service/entry_utils.h
+++ b/chromium/components/download/internal/background_service/entry_utils.h
@@ -17,6 +17,7 @@
namespace download {
+class DownloadDriver;
struct DownloadMetaData;
struct Entry;
@@ -35,7 +36,8 @@ uint32_t GetNumberOfLiveEntriesForClient(DownloadClient client,
// not be included.
std::map<DownloadClient, std::vector<DownloadMetaData>>
MapEntriesToMetadataForClients(const std::set<DownloadClient>& clients,
- const std::vector<Entry*>& entries);
+ const std::vector<Entry*>& entries,
+ DownloadDriver* driver);
// Gets the least strict scheduling criteria from |entries|, the criteria is
// used to schedule platform background tasks.
@@ -46,8 +48,9 @@ Criteria GetSchedulingCriteria(const Model::EntryList& entries,
// |rhs| based on their priority and cancel time.
bool EntryBetterThan(const Entry& lhs, const Entry& rhs);
-// Builds a download meta data based on |entry|.
-DownloadMetaData BuildDownloadMetaData(Entry* entry);
+// Builds a download meta data based on |entry| and the states from |driver| in
+// the history db.
+DownloadMetaData BuildDownloadMetaData(Entry* entry, DownloadDriver* driver);
} // namespace util
} // namespace download
diff --git a/chromium/components/download/internal/background_service/entry_utils_unittest.cc b/chromium/components/download/internal/background_service/entry_utils_unittest.cc
index fda16a7f2a8..75f36afc8be 100644
--- a/chromium/components/download/internal/background_service/entry_utils_unittest.cc
+++ b/chromium/components/download/internal/background_service/entry_utils_unittest.cc
@@ -7,6 +7,7 @@
#include <algorithm>
#include "components/download/internal/background_service/test/entry_utils.h"
+#include "components/download/internal/background_service/test/test_download_driver.h"
#include "components/download/public/background_service/clients.h"
#include "components/download/public/background_service/download_metadata.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -35,21 +36,23 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) {
Entry entry5 = test::BuildBasicEntry(Entry::State::AVAILABLE);
std::vector<Entry*> entries = {&entry1, &entry2, &entry3, &entry4, &entry5};
+ test::TestDownloadDriver driver;
std::vector<DownloadMetaData> expected_list = {
- util::BuildDownloadMetaData(&entry1),
- util::BuildDownloadMetaData(&entry2),
- util::BuildDownloadMetaData(&entry3),
- util::BuildDownloadMetaData(&entry4),
- util::BuildDownloadMetaData(&entry5)};
+ util::BuildDownloadMetaData(&entry1, &driver),
+ util::BuildDownloadMetaData(&entry2, &driver),
+ util::BuildDownloadMetaData(&entry3, &driver),
+ util::BuildDownloadMetaData(&entry4, &driver),
+ util::BuildDownloadMetaData(&entry5, &driver)};
std::vector<DownloadMetaData> expected_pruned_list = {
- util::BuildDownloadMetaData(&entry1),
- util::BuildDownloadMetaData(&entry2),
- util::BuildDownloadMetaData(&entry3),
- util::BuildDownloadMetaData(&entry5)};
+ util::BuildDownloadMetaData(&entry1, &driver),
+ util::BuildDownloadMetaData(&entry2, &driver),
+ util::BuildDownloadMetaData(&entry3, &driver),
+ util::BuildDownloadMetaData(&entry5, &driver)};
+
// If DownloadClient::TEST isn't a valid Client, all of the associated entries
// should move to the DownloadClient::INVALID bucket.
- auto mapped1 =
- util::MapEntriesToMetadataForClients(std::set<DownloadClient>(), entries);
+ auto mapped1 = util::MapEntriesToMetadataForClients(
+ std::set<DownloadClient>(), entries, &driver);
EXPECT_EQ(1U, mapped1.size());
EXPECT_NE(mapped1.end(), mapped1.find(DownloadClient::INVALID));
EXPECT_EQ(mapped1.end(), mapped1.find(DownloadClient::TEST));
@@ -62,7 +65,8 @@ TEST(DownloadServiceEntryUtilsTest, MapEntriesToClients) {
// If DownloadClient::TEST is a valid Client, it should have the associated
// entries.
std::set<DownloadClient> clients = {DownloadClient::TEST};
- auto mapped2 = util::MapEntriesToMetadataForClients(clients, entries);
+ auto mapped2 =
+ util::MapEntriesToMetadataForClients(clients, entries, &driver);
EXPECT_EQ(1U, mapped2.size());
EXPECT_NE(mapped2.end(), mapped2.find(DownloadClient::TEST));
EXPECT_EQ(mapped2.end(), mapped2.find(DownloadClient::INVALID));
@@ -136,15 +140,22 @@ TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaData) {
Entry entry = test::BuildBasicEntry(Entry::State::PAUSED);
entry.target_file_path = base::FilePath::FromUTF8Unsafe("123");
entry.bytes_downloaded = 200u;
- auto meta_data = util::BuildDownloadMetaData(&entry);
+ test::TestDownloadDriver driver;
+
+ auto meta_data = util::BuildDownloadMetaData(&entry, &driver);
EXPECT_EQ(entry.guid, meta_data.guid);
+
// Incomplete downloads don't copy the following data.
EXPECT_FALSE(meta_data.completion_info.has_value());
+ // Current size is always pulled from driver, and we don't persist the current
+ // size in each OnDownloadUpdated call in DownloadDriver.
+ EXPECT_EQ(0u, meta_data.current_size);
+
entry = test::BuildBasicEntry(Entry::State::COMPLETE);
entry.target_file_path = base::FilePath::FromUTF8Unsafe("123");
entry.bytes_downloaded = 100u;
- meta_data = util::BuildDownloadMetaData(&entry);
+ meta_data = util::BuildDownloadMetaData(&entry, &driver);
EXPECT_EQ(entry.guid, meta_data.guid);
EXPECT_TRUE(meta_data.completion_info.has_value());
EXPECT_EQ(entry.target_file_path, meta_data.completion_info->path);
@@ -152,4 +163,21 @@ TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaData) {
meta_data.completion_info->bytes_downloaded);
}
+// Test to verify the current size is correctly built into the meta data.
+TEST(DownloadServiceEntryUtilsTest, BuildDownloadMetaDataCurrentSize) {
+ Entry entry = test::BuildBasicEntry(Entry::State::PAUSED);
+ entry.target_file_path = base::FilePath::FromUTF8Unsafe("123");
+ entry.bytes_downloaded = 0u;
+
+ test::TestDownloadDriver driver;
+ DriverEntry driver_entry;
+ driver_entry.guid = entry.guid;
+ driver_entry.bytes_downloaded = 100u;
+ driver.AddTestData({driver_entry});
+
+ auto meta_data = util::BuildDownloadMetaData(&entry, &driver);
+ meta_data = util::BuildDownloadMetaData(&entry, &driver);
+ EXPECT_EQ(driver_entry.bytes_downloaded, meta_data.current_size);
+}
+
} // namespace download
diff --git a/chromium/components/download/internal/background_service/in_memory_download_driver.cc b/chromium/components/download/internal/background_service/in_memory_download_driver.cc
index 99ba0970550..50eeda0460c 100644
--- a/chromium/components/download/internal/background_service/in_memory_download_driver.cc
+++ b/chromium/components/download/internal/background_service/in_memory_download_driver.cc
@@ -131,7 +131,7 @@ base::Optional<DriverEntry> InMemoryDownloadDriver::Find(
base::Optional<DriverEntry> entry;
auto it = downloads_.find(guid);
if (it != downloads_.end())
- entry = CreateDriverEntry(*it->second.get());
+ entry = CreateDriverEntry(*it->second);
return entry;
}
diff --git a/chromium/components/download/internal/background_service/in_memory_download_driver.h b/chromium/components/download/internal/background_service/in_memory_download_driver.h
index b1594999c72..c28df4c386e 100644
--- a/chromium/components/download/internal/background_service/in_memory_download_driver.h
+++ b/chromium/components/download/internal/background_service/in_memory_download_driver.h
@@ -11,6 +11,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
#include "components/download/internal/background_service/in_memory_download.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
diff --git a/chromium/components/download/internal/background_service/in_memory_download_unittest.cc b/chromium/components/download/internal/background_service/in_memory_download_unittest.cc
index c89ae3a0cdc..e04ec21317e 100644
--- a/chromium/components/download/internal/background_service/in_memory_download_unittest.cc
+++ b/chromium/components/download/internal/background_service/in_memory_download_unittest.cc
@@ -44,7 +44,7 @@ class MockDelegate : public InMemoryDownload::Delegate {
// InMemoryDownload::Delegate implementation.
MOCK_METHOD1(OnDownloadProgress, void(InMemoryDownload*));
- void OnDownloadComplete(InMemoryDownload* download) {
+ void OnDownloadComplete(InMemoryDownload* download) override {
if (run_loop_.running())
run_loop_.Quit();
}
diff --git a/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc b/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc
index 18ab129af56..74ceabe5538 100644
--- a/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc
+++ b/chromium/components/download/internal/background_service/scheduler/device_status_listener_unittest.cc
@@ -34,8 +34,7 @@ MATCHER_P(BatteryStatusEqual, value, "") {
class TestNetworkChangeNotifier : public net::NetworkChangeNotifier {
public:
TestNetworkChangeNotifier()
- : net::NetworkChangeNotifier(),
- conn_type_(ConnectionType::CONNECTION_UNKNOWN) {}
+ : conn_type_(ConnectionType::CONNECTION_UNKNOWN) {}
// net::NetworkChangeNotifier implementation.
ConnectionType GetCurrentConnectionType() const override {
@@ -129,7 +128,7 @@ class DeviceStatusListenerTest : public testing::Test {
// Simulates a network change call, the event will be sent to client
// immediately.
void ChangeNetworkTypeImmediately(ConnectionType type) {
- DCHECK(listener_.get());
+ DCHECK(listener_);
static_cast<NetworkStatusListener::Observer*>(listener_.get())
->OnNetworkChanged(type);
}
diff --git a/chromium/components/download/internal/common/BUILD.gn b/chromium/components/download/internal/common/BUILD.gn
index bb3a9299559..42ed3007fc8 100644
--- a/chromium/components/download/internal/common/BUILD.gn
+++ b/chromium/components/download/internal/common/BUILD.gn
@@ -14,7 +14,6 @@ source_set("internal") {
sources = [
"base_file.cc",
- "base_file_posix.cc",
"base_file_win.cc",
"download_create_info.cc",
"download_file_factory.cc",
@@ -35,12 +34,14 @@ source_set("internal") {
"download_utils.cc",
"download_worker.cc",
"download_worker.h",
+ "in_progress_download_manager.cc",
"parallel_download_job.cc",
"parallel_download_job.h",
"parallel_download_utils.cc",
"parallel_download_utils.h",
"rate_estimator.cc",
"resource_downloader.cc",
+ "resource_downloader.h",
"save_package_download_job.cc",
"save_package_download_job.h",
"stream_handle_input_stream.cc",
@@ -61,6 +62,10 @@ source_set("internal") {
"//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp",
]
+
+ if (is_posix || is_fuchsia) {
+ sources += [ "base_file_posix.cc" ]
+ }
}
# tests need to access both public and internal sources. So in the component
diff --git a/chromium/components/download/internal/common/DEPS b/chromium/components/download/internal/common/DEPS
index 65c70055f64..a5df1addd5a 100644
--- a/chromium/components/download/internal/common/DEPS
+++ b/chromium/components/download/internal/common/DEPS
@@ -6,10 +6,12 @@ include_rules = [
"+components/ukm/test_ukm_recorder.h",
"+crypto",
"+mojo/public/c/system",
+ "+mojo/public/cpp/bindings",
"+net/base/filename_util.h",
"+net/base/load_flags.h",
"+net/base/io_buffer.h",
"+net/base/net_errors.h",
+ "+net/cert/cert_status_flags.h",
"+net/http/http_content_disposition.h",
"+net/http/http_request_headers.h",
"+net/http/http_response_headers.h",
@@ -18,4 +20,5 @@ include_rules = [
"+net/traffic_annotation/network_traffic_annotation.h",
"+services/metrics/public/cpp",
"+services/network/public/cpp",
+ "+services/network/public/mojom",
]
diff --git a/chromium/components/download/internal/common/base_file.cc b/chromium/components/download/internal/common/base_file.cc
index fce4f343809..03416fb14a8 100644
--- a/chromium/components/download/internal/common/base_file.cc
+++ b/chromium/components/download/internal/common/base_file.cc
@@ -13,6 +13,7 @@
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/numerics/safe_conversions.h"
#include "base/pickle.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_restrictions.h"
@@ -137,14 +138,6 @@ DownloadInterruptReason BaseFile::WriteDataToFile(int64_t offset,
// belong to the same download will be grouped together.
CONDITIONAL_TRACE(
NESTABLE_ASYNC_BEGIN0("download", "DownloadFileWrite", download_id_));
- int write_result = file_.Write(offset, data, data_len);
- DCHECK_NE(0, write_result);
-
- // Report errors on file writes.
- if (write_result < 0)
- return LogSystemError("Write", logging::GetLastSystemErrorCode());
-
- DCHECK_EQ(static_cast<size_t>(write_result), data_len);
if (bytes_so_far_ != offset) {
// A hole is created in the file.
@@ -152,7 +145,28 @@ DownloadInterruptReason BaseFile::WriteDataToFile(int64_t offset,
secure_hash_.reset();
}
- bytes_so_far_ += data_len;
+ // Writes to the file.
+ int64_t len = base::saturated_cast<int64_t>(data_len);
+ const char* current_data = data;
+ int64_t current_offset = offset;
+ while (len > 0) {
+ // |write_result| may be less than |len|, and return an error on the next
+ // write call when the disk is unavaliable.
+ int write_result = file_.Write(current_offset, current_data, len);
+ DCHECK_NE(0, write_result);
+
+ // Report errors on file writes.
+ if (write_result < 0)
+ return LogSystemError("Write", logging::GetLastSystemErrorCode());
+
+ // Update status.
+ DCHECK_LE(write_result, len);
+ len -= write_result;
+ current_data += write_result;
+ current_offset += write_result;
+ bytes_so_far_ += write_result;
+ }
+
CONDITIONAL_TRACE(NESTABLE_ASYNC_END1("download", "DownloadFileWrite",
download_id_, "bytes", data_len));
diff --git a/chromium/components/download/internal/common/base_file_win.cc b/chromium/components/download/internal/common/base_file_win.cc
index df78b6956d5..11796902e9a 100644
--- a/chromium/components/download/internal/common/base_file_win.cc
+++ b/chromium/components/download/internal/common/base_file_win.cc
@@ -257,25 +257,22 @@ DownloadInterruptReason MapShFileOperationCodes(int code) {
if (result == DOWNLOAD_INTERRUPT_REASON_FILE_FAILED) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Download.MapWinShErrorFileFailed", code,
- base::CustomHistogram::ArrayToCustomRanges(
- kAllSpecialShFileOperationCodes,
- arraysize(kAllSpecialShFileOperationCodes)));
+ base::CustomHistogram::ArrayToCustomEnumRanges(
+ kAllSpecialShFileOperationCodes));
}
if (result == DOWNLOAD_INTERRUPT_REASON_FILE_ACCESS_DENIED) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Download.MapWinShErrorAccessDenied", code,
- base::CustomHistogram::ArrayToCustomRanges(
- kAllSpecialShFileOperationCodes,
- arraysize(kAllSpecialShFileOperationCodes)));
+ base::CustomHistogram::ArrayToCustomEnumRanges(
+ kAllSpecialShFileOperationCodes));
}
if (result == DOWNLOAD_INTERRUPT_REASON_FILE_TRANSIENT_ERROR) {
UMA_HISTOGRAM_CUSTOM_ENUMERATION(
"Download.MapWinShErrorTransientError", code,
- base::CustomHistogram::ArrayToCustomRanges(
- kAllSpecialShFileOperationCodes,
- arraysize(kAllSpecialShFileOperationCodes)));
+ base::CustomHistogram::ArrayToCustomEnumRanges(
+ kAllSpecialShFileOperationCodes));
}
if (result != DOWNLOAD_INTERRUPT_REASON_NONE)
@@ -302,7 +299,7 @@ DownloadInterruptReason BaseFile::MoveFileAndAdjustPermissions(
source.append(1, L'\0');
target.append(1, L'\0');
- SHFILEOPSTRUCT move_info = {0};
+ SHFILEOPSTRUCT move_info = {nullptr};
move_info.wFunc = FO_MOVE;
move_info.pFrom = source.c_str();
move_info.pTo = target.c_str();
diff --git a/chromium/components/download/internal/common/download_file_impl.cc b/chromium/components/download/internal/common/download_file_impl.cc
index 7acae0764dd..05d8f7c5c19 100644
--- a/chromium/components/download/internal/common/download_file_impl.cc
+++ b/chromium/components/download/internal/common/download_file_impl.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/files/file_util.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
@@ -147,7 +147,7 @@ DownloadFileImpl::DownloadFileImpl(
bytes_seen_without_parallel_streams_(0),
is_paused_(false),
download_id_(download_id),
- main_task_runner_(base::MessageLoop::current()->task_runner()),
+ main_task_runner_(base::MessageLoopCurrent::Get()->task_runner()),
observer_(observer),
weak_factory_(this) {
TRACE_EVENT_INSTANT0("download", "DownloadFileCreated",
@@ -229,7 +229,7 @@ void DownloadFileImpl::AddInputStream(std::unique_ptr<InputStream> stream,
CancelRequest(offset);
return;
}
-
+ DCHECK(source_streams_.find(offset) == source_streams_.end());
source_streams_[offset] =
std::make_unique<SourceStream>(offset, length, std::move(stream));
OnSourceStreamAdded(source_streams_[offset].get());
@@ -504,7 +504,7 @@ void DownloadFileImpl::StreamActive(SourceStream* source_stream,
DCHECK_GE(incoming_data_size, bytes_to_write);
reason = WriteDataToFile(
source_stream->offset() + source_stream->bytes_written(),
- incoming_data.get()->data(), bytes_to_write);
+ incoming_data->data(), bytes_to_write);
disk_writes_time_ += (base::TimeTicks::Now() - write_start);
bytes_seen_ += bytes_to_write;
total_incoming_data_size += bytes_to_write;
diff --git a/chromium/components/download/internal/common/download_file_unittest.cc b/chromium/components/download/internal/common/download_file_unittest.cc
index 91c9d212691..f0f2204d6a5 100644
--- a/chromium/components/download/internal/common/download_file_unittest.cc
+++ b/chromium/components/download/internal/common/download_file_unittest.cc
@@ -201,7 +201,7 @@ class DownloadFileTest : public testing::Test {
bool calculate_hash,
const DownloadItem::ReceivedSlices& received_slices) {
// There can be only one.
- DCHECK(!download_file_.get());
+ DCHECK(!download_file_);
input_stream_ = new StrictMock<MockInputStream>();
@@ -721,8 +721,8 @@ void TestRenameCompletionCallback(const base::Closure& closure,
// succeed.
//
// Note that there is only one queue of tasks to run, and that is in the tests'
-// base::MessageLoop::current(). Each RunLoop processes that queue until it sees
-// a QuitClosure() targeted at itself, at which point it stops processing.
+// base::MessageLoopCurrent::Get(). Each RunLoop processes that queue until it
+// sees a QuitClosure() targeted at itself, at which point it stops processing.
TEST_P(DownloadFileTestWithRename, RenameWithErrorRetry) {
ASSERT_TRUE(CreateDownloadFile(0, true));
base::FilePath initial_path(download_file_->FullPath());
@@ -1042,8 +1042,8 @@ TEST_F(DownloadFileTest, SecondStreamStartingOffsetAlreadyWritten) {
.RetiresOnSaturation();
download_file_->AddInputStream(
- std::unique_ptr<MockInputStream>(additional_streams_[0]), 0,
- DownloadSaveInfo::kLengthFullContent);
+ std::unique_ptr<MockInputStream>(additional_streams_[0]),
+ strlen(kTestData1), DownloadSaveInfo::kLengthFullContent);
// The stream should get terminated and reset the callback.
EXPECT_TRUE(sink_callback_.is_null());
diff --git a/chromium/components/download/internal/common/download_item_impl.cc b/chromium/components/download/internal/common/download_item_impl.cc
index 7181a2ca5c8..817deacd108 100644
--- a/chromium/components/download/internal/common/download_item_impl.cc
+++ b/chromium/components/download/internal/common/download_item_impl.cc
@@ -147,6 +147,8 @@ std::string GetDownloadDangerNames(DownloadDangerType type) {
return "DANGEROUS_HOST";
case DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
return "POTENTIALLY_UNWANTED";
+ case DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY:
+ return "WHITELISTED_BY_POLICY";
default:
NOTREACHED();
return "UNKNOWN_DANGER_TYPE";
@@ -418,7 +420,7 @@ DownloadItemImpl::~DownloadItemImpl() {
// Should always have been nuked before now, at worst in
// DownloadManager shutdown.
- DCHECK(!download_file_.get());
+ DCHECK(!download_file_);
CHECK(!is_updating_observers_);
for (auto& observer : observers_)
@@ -957,6 +959,11 @@ bool DownloadItemImpl::IsTransient() const {
return transient_;
}
+bool DownloadItemImpl::IsParallelDownload() const {
+ bool is_parallelizable = job_ ? job_->IsParallelizable() : false;
+ return is_parallelizable && download::IsParallelDownloadEnabled();
+}
+
void DownloadItemImpl::OnContentCheckCompleted(DownloadDangerType danger_type,
DownloadInterruptReason reason) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -1040,7 +1047,7 @@ std::string DownloadItemImpl::DebugString(bool verbose) const {
IsPaused() ? 'T' : 'F', DebugResumeModeString(GetResumeMode()),
auto_resume_count_, GetDangerType(), AllDataSaved() ? 'T' : 'F',
GetLastModifiedTime().c_str(), GetETag().c_str(),
- download_file_.get() ? "true" : "false", url_list.c_str(),
+ download_file_ ? "true" : "false", url_list.c_str(),
GetFullPath().value().c_str(), GetTargetFilePath().value().c_str(),
GetReferrerUrl().spec().c_str(), GetSiteUrl().spec().c_str());
} else {
@@ -1383,17 +1390,18 @@ void DownloadItemImpl::Start(
std::unique_ptr<DownloadFile> file,
std::unique_ptr<DownloadRequestHandleInterface> req_handle,
const DownloadCreateInfo& new_create_info,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
net::URLRequestContextGetter* url_request_context_getter) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(!download_file_.get());
+ DCHECK(!download_file_);
DVLOG(20) << __func__ << "() this=" << DebugString(true);
RecordDownloadCountWithSource(START_COUNT, download_source_);
download_file_ = std::move(file);
job_ = DownloadJobFactory::CreateJob(
this, std::move(req_handle), new_create_info, false,
- std::move(shared_url_loader_factory), url_request_context_getter);
+ std::move(url_loader_factory_getter), url_request_context_getter);
if (job_->IsParallelizable()) {
RecordParallelizableDownloadCount(START_COUNT, IsParallelDownloadEnabled());
}
@@ -1422,23 +1430,20 @@ void DownloadItemImpl::Start(
// If a resumption attempted failed, or if the download was DOA, then the
// download should go back to being interrupted.
if (new_create_info.result != DOWNLOAD_INTERRUPT_REASON_NONE) {
- DCHECK(!download_file_.get());
+ DCHECK(!download_file_);
// Download requests that are interrupted by Start() should result in a
// DownloadCreateInfo with an intact DownloadSaveInfo.
DCHECK(new_create_info.save_info);
- int64_t offset = new_create_info.save_info->offset;
std::unique_ptr<crypto::SecureHash> hash_state =
new_create_info.save_info->hash_state
? new_create_info.save_info->hash_state->Clone()
: nullptr;
- destination_info_.received_bytes = offset;
hash_state_ = std::move(hash_state);
destination_info_.hash.clear();
deferred_interrupt_reason_ = new_create_info.result;
- received_slices_.clear();
TransitionTo(INTERRUPTED_TARGET_PENDING_INTERNAL);
DetermineDownloadTarget();
return;
@@ -1473,9 +1478,8 @@ void DownloadItemImpl::Start(
if (state_ == RESUMING_INTERNAL)
UpdateValidatorsOnResumption(new_create_info);
- // If the download is not parallel download during resumption, clear the
- // |received_slices_|.
- if (!job_->IsParallelizable() && !received_slices_.empty()) {
+ // If the download is not parallel, clear the |received_slices_|.
+ if (!received_slices_.empty() && !job_->IsParallelizable()) {
destination_info_.received_bytes =
GetMaxContiguousDataBlockSizeFromBeginning(received_slices_);
received_slices_.clear();
@@ -1715,7 +1719,7 @@ void DownloadItemImpl::OnDownloadCompleting() {
DCHECK(!GetTargetFilePath().empty());
DCHECK(!IsDangerous());
- DCHECK(download_file_.get());
+ DCHECK(download_file_);
// Unilaterally rename; even if it already has the right name,
// we need theannotation.
DownloadFile::RenameCompletionCallback callback =
@@ -1727,7 +1731,9 @@ void DownloadItemImpl::OnDownloadCompleting() {
base::Unretained(download_file_.get()),
GetTargetFilePath(),
delegate_->GetApplicationClientIdForFileScanning(),
- GetURL(), GetReferrerUrl(), std::move(callback)));
+ delegate_->IsOffTheRecord() ? GURL() : GetURL(),
+ delegate_->IsOffTheRecord() ? GURL() : GetReferrerUrl(),
+ std::move(callback)));
}
void DownloadItemImpl::OnDownloadRenamedToFinalName(
@@ -2229,7 +2235,8 @@ void DownloadItemImpl::SetDangerType(DownloadDangerType danger_type) {
if ((danger_type_ == DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS ||
danger_type_ == DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE ||
danger_type_ == DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT ||
- danger_type_ == DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT) &&
+ danger_type_ == DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT ||
+ danger_type_ == DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY) &&
(danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST ||
danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_URL ||
danger_type == DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT ||
@@ -2341,6 +2348,9 @@ void DownloadItemImpl::ResumeInterruptedDownload(
for (const auto& header : request_headers_) {
download_params->add_request_header(header.first, header.second);
}
+ // The offset is calculated after decompression, so the range request cannot
+ // involve any compression,
+ download_params->add_request_header("Accept-Encoding", "identity");
auto entry = delegate_->GetInProgressEntry(this);
if (entry)
diff --git a/chromium/components/download/internal/common/download_item_impl_unittest.cc b/chromium/components/download/internal/common/download_item_impl_unittest.cc
index 8515eb822f6..1503ec33b07 100644
--- a/chromium/components/download/internal/common/download_item_impl_unittest.cc
+++ b/chromium/components/download/internal/common/download_item_impl_unittest.cc
@@ -66,7 +66,7 @@ base::HistogramBase::Sample ToHistogramSample(T t) {
class MockDelegate : public DownloadItemImplDelegate {
public:
- MockDelegate() : DownloadItemImplDelegate() { SetDefaultExpectations(); }
+ MockDelegate() { SetDefaultExpectations(); }
MOCK_METHOD2(DetermineDownloadTarget,
void(DownloadItemImpl*,
@@ -89,6 +89,7 @@ class MockDelegate : public DownloadItemImplDelegate {
MOCK_METHOD1(DownloadOpened, void(DownloadItemImpl*));
MOCK_METHOD1(DownloadRemoved, void(DownloadItemImpl*));
MOCK_CONST_METHOD1(AssertStateConsistent, void(DownloadItemImpl*));
+ MOCK_CONST_METHOD0(IsOffTheRecord, bool());
void VerifyAndClearExpectations() {
::testing::Mock::VerifyAndClearExpectations(this);
@@ -101,6 +102,7 @@ class MockDelegate : public DownloadItemImplDelegate {
EXPECT_CALL(*this, ShouldOpenFileBasedOnExtension(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(*this, ShouldOpenDownload(_, _)).WillRepeatedly(Return(true));
+ EXPECT_CALL(*this, IsOffTheRecord()).WillRepeatedly(Return(false));
}
};
@@ -2010,6 +2012,48 @@ TEST_F(DownloadItemTest, StealInterruptedNonContinuableDangerousDownload) {
EXPECT_TRUE(returned_path.empty());
}
+// Tests that for an incognito download, the target file is annotated with an
+// empty source URL.
+TEST_F(DownloadItemTest, AnnotationWithEmptyURLInIncognito) {
+ // Non-incognito case
+ DownloadItemImpl* item = CreateDownloadItem();
+ MockDownloadFile* download_file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
+ // Target file should be annotated with the source URL.
+ EXPECT_CALL(*download_file,
+ RenameAndAnnotate(_, _, create_info()->url(), _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath),
+ base::ThreadTaskRunnerHandle::Get()));
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*download_file, FullPath())
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
+ EXPECT_CALL(*download_file, Detach());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, std::unique_ptr<crypto::SecureHash>());
+ task_environment_.RunUntilIdle();
+
+ // Incognito case
+ item = CreateDownloadItem();
+ download_file =
+ DoIntermediateRename(item, DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS);
+ // Target file should be annotated with an empty URL.
+ EXPECT_CALL(*download_file, RenameAndAnnotate(_, _, GURL(), _, _))
+ .WillOnce(ScheduleRenameAndAnnotateCallback(
+ DOWNLOAD_INTERRUPT_REASON_NONE, base::FilePath(kDummyTargetPath),
+ base::ThreadTaskRunnerHandle::Get()));
+ EXPECT_CALL(*mock_delegate(), ShouldCompleteDownload(item, _))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*mock_delegate(), IsOffTheRecord()).WillRepeatedly(Return(true));
+ EXPECT_CALL(*download_file, FullPath())
+ .WillOnce(ReturnRefOfCopy(base::FilePath()));
+ EXPECT_CALL(*download_file, Detach());
+ item->DestinationObserverAsWeakPtr()->DestinationCompleted(
+ 0, std::unique_ptr<crypto::SecureHash>());
+ task_environment_.RunUntilIdle();
+}
+
namespace {
// The DownloadItemDestinationUpdateRaceTest fixture (defined below) is used to
@@ -2191,8 +2235,7 @@ class DownloadItemDestinationUpdateRaceTest
public ::testing::WithParamInterface<EventList> {
public:
DownloadItemDestinationUpdateRaceTest()
- : DownloadItemTest(),
- item_(CreateDownloadItem()),
+ : item_(CreateDownloadItem()),
file_(new ::testing::StrictMock<MockDownloadFile>()),
request_handle_(new ::testing::StrictMock<MockRequestHandle>()) {
DCHECK_EQ(GetParam().size(), static_cast<unsigned>(kEventCount));
diff --git a/chromium/components/download/internal/common/download_job_factory.cc b/chromium/components/download/internal/common/download_job_factory.cc
index b2fda04191a..c9cffbebc1b 100644
--- a/chromium/components/download/internal/common/download_job_factory.cc
+++ b/chromium/components/download/internal/common/download_job_factory.cc
@@ -12,7 +12,7 @@
#include "components/download/internal/common/save_package_download_job.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_stats.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
namespace download {
@@ -44,10 +44,12 @@ bool IsParallelizableDownload(const DownloadCreateInfo& create_info,
net::HttpResponseInfo::CONNECTION_INFO_HTTP1_1;
bool http_get_method =
create_info.method == "GET" && create_info.url().SchemeIsHTTPOrHTTPS();
-
+ bool partial_response_success =
+ download_item->GetReceivedSlices().empty() || create_info.offset != 0;
bool is_parallelizable = has_strong_validator && create_info.accept_range &&
has_content_length && satisfy_min_file_size &&
- satisfy_connection_type && http_get_method;
+ satisfy_connection_type && http_get_method &&
+ partial_response_success;
if (!IsParallelDownloadEnabled())
return is_parallelizable;
@@ -93,7 +95,8 @@ std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob(
std::unique_ptr<DownloadRequestHandleInterface> req_handle,
const DownloadCreateInfo& create_info,
bool is_save_package_download,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
net::URLRequestContextGetter* url_request_context_getter) {
if (is_save_package_download) {
return std::make_unique<SavePackageDownloadJob>(download_item,
@@ -105,7 +108,7 @@ std::unique_ptr<DownloadJob> DownloadJobFactory::CreateJob(
if (IsParallelDownloadEnabled() && is_parallelizable) {
return std::make_unique<ParallelDownloadJob>(
download_item, std::move(req_handle), create_info,
- std::move(shared_url_loader_factory), url_request_context_getter);
+ std::move(url_loader_factory_getter), url_request_context_getter);
}
// An ordinary download job.
diff --git a/chromium/components/download/internal/common/download_stats.cc b/chromium/components/download/internal/common/download_stats.cc
index 829b99ed9d6..fb06e932988 100644
--- a/chromium/components/download/internal/common/download_stats.cc
+++ b/chromium/components/download/internal/common/download_stats.cc
@@ -377,8 +377,7 @@ void RecordDownloadInterrupted(DownloadInterruptReason reason,
}
std::vector<base::HistogramBase::Sample> samples =
- base::CustomHistogram::ArrayToCustomRanges(
- kAllInterruptReasonCodes, arraysize(kAllInterruptReasonCodes));
+ base::CustomHistogram::ArrayToCustomEnumRanges(kAllInterruptReasonCodes);
UMA_HISTOGRAM_CUSTOM_ENUMERATION("Download.InterruptedReason", reason,
samples);
diff --git a/chromium/components/download/internal/common/download_task_runner.cc b/chromium/components/download/internal/common/download_task_runner.cc
index 0cc99355e32..55db38f64b6 100644
--- a/chromium/components/download/internal/common/download_task_runner.cc
+++ b/chromium/components/download/internal/common/download_task_runner.cc
@@ -6,6 +6,7 @@
#include "base/lazy_instance.h"
#include "base/no_destructor.h"
+#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/task_scheduler/lazy_task_runner.h"
#include "build/build_config.h"
diff --git a/chromium/components/download/internal/common/download_utils.cc b/chromium/components/download/internal/common/download_utils.cc
index 224894906f4..cc9f500041b 100644
--- a/chromium/components/download/internal/common/download_utils.cc
+++ b/chromium/components/download/internal/common/download_utils.cc
@@ -5,6 +5,7 @@
#include "components/download/public/common/download_utils.h"
#include "base/format_macros.h"
+#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "components/download/public/common/download_create_info.h"
#include "components/download/public/common/download_interrupt_reasons_utils.h"
@@ -347,4 +348,24 @@ std::unique_ptr<net::HttpRequestHeaders> GetAdditionalRequestHeaders(
return headers;
}
+DownloadEntry CreateDownloadEntryFromItem(
+ const DownloadItem& item,
+ const std::string& request_origin,
+ DownloadSource download_source,
+ bool fetch_error_body,
+ const DownloadUrlParameters::RequestHeadersType& request_headers) {
+ return DownloadEntry(item.GetGuid(), request_origin, download_source,
+ fetch_error_body, request_headers,
+ GetUniqueDownloadId());
+}
+
+uint64_t GetUniqueDownloadId() {
+ // Get a new UKM download_id that is not 0.
+ uint64_t download_id = 0;
+ do {
+ download_id = base::RandUint64();
+ } while (download_id == 0);
+ return download_id;
+}
+
} // namespace download
diff --git a/chromium/components/download/internal/common/download_worker.cc b/chromium/components/download/internal/common/download_worker.cc
index c05b1f8a0c2..b6f3aa58879 100644
--- a/chromium/components/download/internal/common/download_worker.cc
+++ b/chromium/components/download/internal/common/download_worker.cc
@@ -4,13 +4,13 @@
#include "components/download/internal/common/download_worker.h"
-#include "base/message_loop/message_loop.h"
+#include "components/download/internal/common/resource_downloader.h"
#include "components/download/public/common/download_create_info.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/download/public/common/download_task_runner.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
#include "components/download/public/common/download_utils.h"
#include "components/download/public/common/input_stream.h"
-#include "components/download/public/common/resource_downloader.h"
#include "components/download/public/common/url_download_handler_factory.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -43,10 +43,11 @@ class CompletedInputStream : public InputStream {
void CreateUrlDownloadHandler(
std::unique_ptr<DownloadUrlParameters> params,
base::WeakPtr<UrlDownloadHandler::Delegate> delegate,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
auto downloader = UrlDownloadHandlerFactory::Create(
- std::move(params), delegate, std::move(shared_url_loader_factory),
+ std::move(params), delegate, std::move(url_loader_factory_getter),
task_runner);
task_runner->PostTask(
FROM_HERE,
@@ -74,11 +75,12 @@ DownloadWorker::~DownloadWorker() = default;
void DownloadWorker::SendRequest(
std::unique_ptr<DownloadUrlParameters> params,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory) {
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter) {
GetIOTaskRunner()->PostTask(
FROM_HERE, base::BindOnce(&CreateUrlDownloadHandler, std::move(params),
weak_factory_.GetWeakPtr(),
- std::move(shared_url_loader_factory),
+ std::move(url_loader_factory_getter),
base::ThreadTaskRunnerHandle::Get()));
}
@@ -104,7 +106,8 @@ void DownloadWorker::Cancel(bool user_cancel) {
void DownloadWorker::OnUrlDownloadStarted(
std::unique_ptr<DownloadCreateInfo> create_info,
std::unique_ptr<InputStream> input_stream,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const DownloadUrlParameters::OnStartedCallback& callback) {
// |callback| is not used in subsequent requests.
DCHECK(callback.is_null());
@@ -134,7 +137,8 @@ void DownloadWorker::OnUrlDownloadStarted(
Pause();
}
- delegate_->OnInputStreamReady(this, std::move(input_stream));
+ delegate_->OnInputStreamReady(this, std::move(input_stream),
+ std::move(create_info));
}
void DownloadWorker::OnUrlDownloadStopped(UrlDownloadHandler* downloader) {
diff --git a/chromium/components/download/internal/common/download_worker.h b/chromium/components/download/internal/common/download_worker.h
index 8996f082d12..8c712607093 100644
--- a/chromium/components/download/internal/common/download_worker.h
+++ b/chromium/components/download/internal/common/download_worker.h
@@ -14,11 +14,8 @@
#include "components/download/public/common/download_url_parameters.h"
#include "components/download/public/common/url_download_handler.h"
-namespace network {
-class SharedURLLoaderFactory;
-}
-
namespace download {
+class DownloadURLLoaderFactoryGetter;
// Helper class used to send subsequent range requests to fetch slices of the
// file after handling response of the original non-range request.
@@ -34,7 +31,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadWorker
// destination file.
virtual void OnInputStreamReady(
DownloadWorker* worker,
- std::unique_ptr<InputStream> input_stream) = 0;
+ std::unique_ptr<InputStream> input_stream,
+ std::unique_ptr<DownloadCreateInfo> download_create_info) = 0;
};
DownloadWorker(DownloadWorker::Delegate* delegate,
@@ -46,9 +44,9 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadWorker
int64_t length() const { return length_; }
// Send network request to ask for a download.
- void SendRequest(
- std::unique_ptr<DownloadUrlParameters> params,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory);
+ void SendRequest(std::unique_ptr<DownloadUrlParameters> params,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter);
// Download operations.
void Pause();
@@ -60,7 +58,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadWorker
void OnUrlDownloadStarted(
std::unique_ptr<DownloadCreateInfo> create_info,
std::unique_ptr<InputStream> input_stream,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const DownloadUrlParameters::OnStartedCallback& callback) override;
void OnUrlDownloadStopped(UrlDownloadHandler* downloader) override;
void OnUrlDownloadHandlerCreated(
diff --git a/chromium/components/download/internal/common/in_progress_download_manager.cc b/chromium/components/download/internal/common/in_progress_download_manager.cc
new file mode 100644
index 00000000000..9ed647a5b05
--- /dev/null
+++ b/chromium/components/download/internal/common/in_progress_download_manager.cc
@@ -0,0 +1,402 @@
+// 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 "components/download/public/common/in_progress_download_manager.h"
+
+#include "base/optional.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/download/downloader/in_progress/in_progress_cache_impl.h"
+#include "components/download/internal/common/resource_downloader.h"
+#include "components/download/public/common/download_file.h"
+#include "components/download/public/common/download_item_impl.h"
+#include "components/download/public/common/download_stats.h"
+#include "components/download/public/common/download_task_runner.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
+#include "components/download/public/common/download_url_parameters.h"
+#include "components/download/public/common/download_utils.h"
+#include "components/download/public/common/input_stream.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+
+namespace download {
+
+namespace {
+
+void OnUrlDownloadHandlerCreated(
+ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader,
+ base::WeakPtr<InProgressDownloadManager> download_manager,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) {
+ main_task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(&UrlDownloadHandler::Delegate::OnUrlDownloadHandlerCreated,
+ download_manager, std::move(downloader)));
+}
+
+void BeginResourceDownload(
+ std::unique_ptr<DownloadUrlParameters> params,
+ std::unique_ptr<network::ResourceRequest> request,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ uint32_t download_id,
+ base::WeakPtr<InProgressDownloadManager> download_manager,
+ const GURL& site_url,
+ const GURL& tab_url,
+ const GURL& tab_referrer_url,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) {
+ DCHECK(GetIOTaskRunner()->BelongsToCurrentThread());
+ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader(
+ ResourceDownloader::BeginDownload(
+ download_manager, std::move(params), std::move(request),
+ std::move(url_loader_factory_getter), site_url, tab_url,
+ tab_referrer_url, download_id, false, main_task_runner)
+ .release(),
+ base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
+
+ OnUrlDownloadHandlerCreated(std::move(downloader), download_manager,
+ main_task_runner);
+}
+
+void CreateDownloadHandlerForNavigation(
+ base::WeakPtr<InProgressDownloadManager> download_manager,
+ std::unique_ptr<network::ResourceRequest> resource_request,
+ int render_process_id,
+ int render_frame_id,
+ const GURL& site_url,
+ const GURL& tab_url,
+ const GURL& tab_referrer_url,
+ std::vector<GURL> url_chain,
+ scoped_refptr<network::ResourceResponse> response,
+ net::CertStatus cert_status,
+ network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) {
+ DCHECK(GetIOTaskRunner()->BelongsToCurrentThread());
+ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader(
+ ResourceDownloader::InterceptNavigationResponse(
+ download_manager, std::move(resource_request), render_process_id,
+ render_frame_id, site_url, tab_url, tab_referrer_url,
+ std::move(url_chain), std::move(response), std::move(cert_status),
+ std::move(url_loader_client_endpoints),
+ std::move(url_loader_factory_getter), main_task_runner)
+ .release(),
+ base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
+
+ OnUrlDownloadHandlerCreated(std::move(downloader), download_manager,
+ main_task_runner);
+}
+
+// Responsible for persisting the in-progress metadata associated with a
+// download.
+class InProgressDownloadObserver : public DownloadItem::Observer {
+ public:
+ explicit InProgressDownloadObserver(InProgressCache* in_progress_cache);
+ ~InProgressDownloadObserver() override;
+
+ private:
+ // DownloadItem::Observer
+ void OnDownloadUpdated(DownloadItem* download) override;
+ void OnDownloadRemoved(DownloadItem* download) override;
+
+ // The persistent cache to store in-progress metadata.
+ InProgressCache* in_progress_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProgressDownloadObserver);
+};
+
+InProgressDownloadObserver::InProgressDownloadObserver(
+ InProgressCache* in_progress_cache)
+ : in_progress_cache_(in_progress_cache) {}
+
+InProgressDownloadObserver::~InProgressDownloadObserver() = default;
+
+void InProgressDownloadObserver::OnDownloadUpdated(DownloadItem* download) {
+ // TODO(crbug.com/778425): Properly handle fail/resume/retry for downloads
+ // that are in the INTERRUPTED state for a long time.
+ if (!in_progress_cache_)
+ return;
+
+ switch (download->GetState()) {
+ case DownloadItem::DownloadState::COMPLETE:
+ // Intentional fallthrough.
+ case DownloadItem::DownloadState::CANCELLED:
+ if (in_progress_cache_)
+ in_progress_cache_->RemoveEntry(download->GetGuid());
+ break;
+
+ case DownloadItem::DownloadState::INTERRUPTED:
+ // Intentional fallthrough.
+ case DownloadItem::DownloadState::IN_PROGRESS: {
+ // Make sure the entry exists in the cache.
+ base::Optional<DownloadEntry> entry_opt =
+ in_progress_cache_->RetrieveEntry(download->GetGuid());
+ DownloadEntry entry;
+ if (!entry_opt.has_value()) {
+ entry = CreateDownloadEntryFromItem(
+ *download, std::string(), /* request_origin */
+ DownloadSource::UNKNOWN, false, /* fetch_error_body */
+ DownloadUrlParameters::RequestHeadersType());
+ in_progress_cache_->AddOrReplaceEntry(entry);
+ break;
+ }
+ entry = entry_opt.value();
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void InProgressDownloadObserver::OnDownloadRemoved(DownloadItem* download) {
+ if (!in_progress_cache_)
+ return;
+
+ in_progress_cache_->RemoveEntry(download->GetGuid());
+}
+
+} // namespace
+
+InProgressDownloadManager::InProgressDownloadManager(
+ Delegate* delegate,
+ const IsOriginSecureCallback& is_origin_secure_cb)
+ : delegate_(delegate),
+ file_factory_(new DownloadFileFactory()),
+ is_origin_secure_cb_(is_origin_secure_cb),
+ weak_factory_(this) {}
+
+InProgressDownloadManager::~InProgressDownloadManager() = default;
+
+void InProgressDownloadManager::OnUrlDownloadStarted(
+ std::unique_ptr<DownloadCreateInfo> download_create_info,
+ std::unique_ptr<InputStream> input_stream,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ const DownloadUrlParameters::OnStartedCallback& callback) {
+ StartDownload(std::move(download_create_info), std::move(input_stream),
+ std::move(url_loader_factory_getter), callback);
+}
+
+void InProgressDownloadManager::OnUrlDownloadStopped(
+ UrlDownloadHandler* downloader) {
+ for (auto ptr = url_download_handlers_.begin();
+ ptr != url_download_handlers_.end(); ++ptr) {
+ if (ptr->get() == downloader) {
+ url_download_handlers_.erase(ptr);
+ return;
+ }
+ }
+}
+
+void InProgressDownloadManager::OnUrlDownloadHandlerCreated(
+ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader) {
+ if (downloader)
+ url_download_handlers_.push_back(std::move(downloader));
+}
+
+void InProgressDownloadManager::BeginDownload(
+ std::unique_ptr<DownloadUrlParameters> params,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ uint32_t download_id,
+ const GURL& site_url,
+ const GURL& tab_url,
+ const GURL& tab_referrer_url) {
+ std::unique_ptr<network::ResourceRequest> request =
+ CreateResourceRequest(params.get());
+ GetIOTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&BeginResourceDownload, std::move(params),
+ std::move(request), std::move(url_loader_factory_getter),
+ download_id, weak_factory_.GetWeakPtr(), site_url, tab_url,
+ tab_referrer_url, base::ThreadTaskRunnerHandle::Get()));
+}
+
+void InProgressDownloadManager::InterceptDownloadFromNavigation(
+ std::unique_ptr<network::ResourceRequest> resource_request,
+ int render_process_id,
+ int render_frame_id,
+ const GURL& site_url,
+ const GURL& tab_url,
+ const GURL& tab_referrer_url,
+ std::vector<GURL> url_chain,
+ scoped_refptr<network::ResourceResponse> response,
+ net::CertStatus cert_status,
+ network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter) {
+ GetIOTaskRunner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&CreateDownloadHandlerForNavigation,
+ weak_factory_.GetWeakPtr(), std::move(resource_request),
+ render_process_id, render_frame_id, site_url, tab_url,
+ tab_referrer_url, std::move(url_chain),
+ std::move(response), std::move(cert_status),
+ std::move(url_loader_client_endpoints),
+ std::move(url_loader_factory_getter),
+ base::ThreadTaskRunnerHandle::Get()));
+}
+
+void InProgressDownloadManager::Initialize(
+ const base::FilePath& metadata_cache_dir,
+ base::OnceClosure callback) {
+ download_metadata_cache_ = std::make_unique<InProgressCacheImpl>(
+ metadata_cache_dir.empty() ? base::FilePath() :
+ metadata_cache_dir.Append(kDownloadMetadataStoreFilename),
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}));
+
+ download_metadata_cache_->Initialize(std::move(callback));
+}
+
+void InProgressDownloadManager::ShutDown() {
+ url_download_handlers_.clear();
+}
+
+void InProgressDownloadManager::ResumeInterruptedDownload(
+ std::unique_ptr<DownloadUrlParameters> params,
+ uint32_t id,
+ const GURL& site_url) {}
+
+base::Optional<DownloadEntry> InProgressDownloadManager::GetInProgressEntry(
+ DownloadItemImpl* download) {
+ if (!download || !download_metadata_cache_)
+ return base::Optional<DownloadEntry>();
+
+ return download_metadata_cache_->RetrieveEntry(download->GetGuid());
+}
+
+void InProgressDownloadManager::ReportBytesWasted(DownloadItemImpl* download) {
+ if (!download_metadata_cache_)
+ return;
+ base::Optional<DownloadEntry> entry_opt =
+ download_metadata_cache_->RetrieveEntry(download->GetGuid());
+ if (entry_opt.has_value()) {
+ DownloadEntry entry = entry_opt.value();
+ entry.bytes_wasted = download->GetBytesWasted();
+ download_metadata_cache_->AddOrReplaceEntry(entry);
+ }
+}
+
+void InProgressDownloadManager::StartDownload(
+ std::unique_ptr<DownloadCreateInfo> info,
+ std::unique_ptr<InputStream> stream,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ const DownloadUrlParameters::OnStartedCallback& on_started) {
+ DCHECK(info);
+
+ uint32_t download_id = info->download_id;
+ bool new_download = (download_id == DownloadItem::kInvalidId);
+ if (new_download && info->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ if (delegate_ && delegate_->InterceptDownload(*info)) {
+ GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release());
+ return;
+ }
+ }
+
+ // |stream| is only non-null if the download request was successful.
+ DCHECK(
+ (info->result == DOWNLOAD_INTERRUPT_REASON_NONE && !stream->IsEmpty()) ||
+ (info->result != DOWNLOAD_INTERRUPT_REASON_NONE && stream->IsEmpty()));
+ DVLOG(20) << __func__
+ << "() result=" << DownloadInterruptReasonToString(info->result);
+
+ GURL url = info->url();
+ std::vector<GURL> url_chain = info->url_chain;
+ std::string mime_type = info->mime_type;
+
+ if (new_download) {
+ RecordDownloadConnectionSecurity(info->url(), info->url_chain);
+ RecordDownloadContentTypeSecurity(info->url(), info->url_chain,
+ info->mime_type, is_origin_secure_cb_);
+ }
+
+ base::RepeatingCallback<void(uint32_t)> got_id(base::BindRepeating(
+ &InProgressDownloadManager::StartDownloadWithId,
+ weak_factory_.GetWeakPtr(), base::Passed(&info), base::Passed(&stream),
+ std::move(url_loader_factory_getter), on_started, new_download));
+ if (new_download) {
+ // TODO(qinmin): use GUID as the key for downloads history table so we don't
+ // rely on the delegate to provide the next download ID.
+ if (delegate_)
+ delegate_->GetNextId(std::move(got_id));
+ } else {
+ std::move(got_id).Run(download_id);
+ }
+}
+
+void InProgressDownloadManager::StartDownloadWithId(
+ std::unique_ptr<DownloadCreateInfo> info,
+ std::unique_ptr<InputStream> stream,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ const DownloadUrlParameters::OnStartedCallback& on_started,
+ bool new_download,
+ uint32_t id) {
+ DCHECK_NE(DownloadItem::kInvalidId, id);
+ DownloadItemImpl* download =
+ delegate_ ? delegate_->GetDownloadItem(id, new_download, *info) : nullptr;
+
+ if (!download) {
+ // If the download is no longer known to the DownloadManager, then it was
+ // removed after it was resumed. Ignore. If the download is cancelled
+ // while resuming, then also ignore the request.
+ if (info->request_handle)
+ info->request_handle->CancelRequest(true);
+ if (!on_started.is_null())
+ on_started.Run(nullptr, DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
+ // The ByteStreamReader lives and dies on the download sequence.
+ if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE)
+ GetDownloadTaskRunner()->DeleteSoon(FROM_HERE, stream.release());
+ return;
+ }
+
+ base::FilePath default_download_directory;
+ if (delegate_)
+ default_download_directory = delegate_->GetDefaultDownloadDirectory();
+
+ if (download_metadata_cache_) {
+ base::Optional<DownloadEntry> entry_opt =
+ download_metadata_cache_->RetrieveEntry(download->GetGuid());
+ if (!entry_opt.has_value()) {
+ download_metadata_cache_->AddOrReplaceEntry(CreateDownloadEntryFromItem(
+ *download, info->request_origin, info->download_source,
+ info->fetch_error_body, info->request_headers));
+ }
+ }
+
+ if (!in_progress_download_observer_) {
+ in_progress_download_observer_ =
+ std::make_unique<InProgressDownloadObserver>(
+ download_metadata_cache_.get());
+ }
+ // May already observe this item, remove observer first.
+ download->RemoveObserver(in_progress_download_observer_.get());
+ download->AddObserver(in_progress_download_observer_.get());
+
+ std::unique_ptr<DownloadFile> download_file;
+ if (info->result == DOWNLOAD_INTERRUPT_REASON_NONE) {
+ DCHECK(stream);
+ download_file.reset(file_factory_->CreateFile(
+ std::move(info->save_info), default_download_directory,
+ std::move(stream), id, download->DestinationObserverAsWeakPtr()));
+ }
+ // It is important to leave info->save_info intact in the case of an interrupt
+ // so that the DownloadItem can salvage what it can out of a failed
+ // resumption attempt.
+
+ download->Start(
+ std::move(download_file), std::move(info->request_handle), *info,
+ std::move(url_loader_factory_getter),
+ delegate_ ? delegate_->GetURLRequestContextGetter(*info) : nullptr);
+
+ // For interrupted downloads, Start() will transition the state to
+ // IN_PROGRESS and consumers will be notified via OnDownloadUpdated().
+ // For new downloads, we notify here, rather than earlier, so that
+ // the download_file is bound to download and all the usual
+ // setters (e.g. Cancel) work.
+ if (new_download && delegate_)
+ delegate_->OnNewDownloadStarted(download);
+
+ if (!on_started.is_null())
+ on_started.Run(download, DOWNLOAD_INTERRUPT_REASON_NONE);
+}
+
+} // namespace download
diff --git a/chromium/components/download/internal/common/parallel_download_job.cc b/chromium/components/download/internal/common/parallel_download_job.cc
index e139a42c314..e72f9af89c0 100644
--- a/chromium/components/download/internal/common/parallel_download_job.cc
+++ b/chromium/components/download/internal/common/parallel_download_job.cc
@@ -12,6 +12,7 @@
#include "components/download/internal/common/parallel_download_utils.h"
#include "components/download/public/common/download_create_info.h"
#include "components/download/public/common/download_stats.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace download {
@@ -23,7 +24,8 @@ ParallelDownloadJob::ParallelDownloadJob(
DownloadItem* download_item,
std::unique_ptr<DownloadRequestHandleInterface> request_handle,
const DownloadCreateInfo& create_info,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
net::URLRequestContextGetter* url_request_context_getter)
: DownloadJobImpl(download_item, std::move(request_handle), true),
initial_request_offset_(create_info.offset),
@@ -31,7 +33,7 @@ ParallelDownloadJob::ParallelDownloadJob(
content_length_(create_info.total_bytes),
requests_sent_(false),
is_canceled_(false),
- shared_url_loader_factory_(std::move(shared_url_loader_factory)),
+ url_loader_factory_getter_(std::move(url_loader_factory_getter)),
url_request_context_getter_(url_request_context_getter) {}
ParallelDownloadJob::~ParallelDownloadJob() = default;
@@ -121,9 +123,14 @@ void ParallelDownloadJob::BuildParallelRequestAfterDelay() {
void ParallelDownloadJob::OnInputStreamReady(
DownloadWorker* worker,
- std::unique_ptr<InputStream> input_stream) {
- bool success = DownloadJob::AddInputStream(
- std::move(input_stream), worker->offset(), worker->length());
+ std::unique_ptr<InputStream> input_stream,
+ std::unique_ptr<DownloadCreateInfo> download_create_info) {
+ // If server returns a wrong range, abort the parallel request.
+ bool success = download_create_info->offset == worker->offset();
+ if (success) {
+ success = DownloadJob::AddInputStream(std::move(input_stream),
+ worker->offset(), worker->length());
+ }
RecordParallelDownloadAddStreamSuccess(success);
// Destroy the request if the sink is gone.
@@ -286,7 +293,7 @@ void ParallelDownloadJob::CreateRequest(int64_t offset, int64_t length) {
download_params->set_referrer_policy(net::URLRequest::NEVER_CLEAR_REFERRER);
// Send the request.
- worker->SendRequest(std::move(download_params), shared_url_loader_factory_);
+ worker->SendRequest(std::move(download_params), url_loader_factory_getter_);
DCHECK(workers_.find(offset) == workers_.end());
workers_[offset] = std::move(worker);
}
diff --git a/chromium/components/download/internal/common/parallel_download_job.h b/chromium/components/download/internal/common/parallel_download_job.h
index c37fb07eb96..a6803e22ee4 100644
--- a/chromium/components/download/internal/common/parallel_download_job.h
+++ b/chromium/components/download/internal/common/parallel_download_job.h
@@ -35,7 +35,8 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob
DownloadItem* download_item,
std::unique_ptr<DownloadRequestHandleInterface> request_handle,
const DownloadCreateInfo& create_info,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
net::URLRequestContextGetter* url_request_context_getter);
~ParallelDownloadJob() override;
@@ -67,8 +68,10 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob
friend class ParallelDownloadJobTest;
// DownloadWorker::Delegate implementation.
- void OnInputStreamReady(DownloadWorker* worker,
- std::unique_ptr<InputStream> input_stream) override;
+ void OnInputStreamReady(
+ DownloadWorker* worker,
+ std::unique_ptr<InputStream> input_stream,
+ std::unique_ptr<DownloadCreateInfo> download_create_info) override;
// Build parallel requests after a delay, to effectively measure the single
// stream bandwidth.
@@ -110,8 +113,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ParallelDownloadJob
// If the download progress is canceled.
bool is_canceled_;
- // SharedURLLoaderFactory to issue network requests with network service
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
+ // URLLoaderFactory getter to issue network requests with network service
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter_;
// URLRequestContextGetter for issueing network requests when network service
// is disabled.
diff --git a/chromium/components/download/internal/common/parallel_download_job_unittest.cc b/chromium/components/download/internal/common/parallel_download_job_unittest.cc
index eb09f931707..61761c49fb4 100644
--- a/chromium/components/download/internal/common/parallel_download_job_unittest.cc
+++ b/chromium/components/download/internal/common/parallel_download_job_unittest.cc
@@ -94,8 +94,10 @@ class ParallelDownloadJobForTest : public ParallelDownloadJob {
return min_remaining_time_;
}
- void OnInputStreamReady(DownloadWorker* worker,
- std::unique_ptr<InputStream> input_stream) override {
+ void OnInputStreamReady(
+ DownloadWorker* worker,
+ std::unique_ptr<InputStream> input_stream,
+ std::unique_ptr<DownloadCreateInfo> download_create_info) override {
CountOnInputStreamReady();
}
@@ -429,7 +431,7 @@ TEST_F(ParallelDownloadJobTest, EarlyCancelBeforeByteStreamReady) {
for (auto& worker : job_->workers()) {
std::unique_ptr<MockDownloadRequestHandle> mock_handle =
std::make_unique<MockDownloadRequestHandle>();
- EXPECT_CALL(*mock_handle.get(), CancelRequest(_));
+ EXPECT_CALL(*mock_handle, CancelRequest(_));
MakeWorkerReady(worker.second.get(), std::move(mock_handle));
}
@@ -451,10 +453,10 @@ TEST_F(ParallelDownloadJobTest, EarlyPauseBeforeByteStreamReady) {
EXPECT_TRUE(job_->is_paused());
for (auto& worker : job_->workers()) {
- EXPECT_CALL(*job_.get(), CountOnInputStreamReady());
+ EXPECT_CALL(*job_, CountOnInputStreamReady());
std::unique_ptr<MockDownloadRequestHandle> mock_handle =
std::make_unique<MockDownloadRequestHandle>();
- EXPECT_CALL(*mock_handle.get(), PauseRequest());
+ EXPECT_CALL(*mock_handle, PauseRequest());
MakeWorkerReady(worker.second.get(), std::move(mock_handle));
}
@@ -517,7 +519,7 @@ TEST_F(ParallelDownloadJobTest, InterruptOnStartup) {
job_->MakeFileInitialized(callback.Get(), DOWNLOAD_INTERRUPT_REASON_NONE);
// Simulate and inject an error from IO thread after file initialized.
- EXPECT_CALL(*download_item_.get(), GetState())
+ EXPECT_CALL(*download_item_, GetState())
.WillRepeatedly(Return(DownloadItem::DownloadState::INTERRUPTED));
// Because of the error, no parallel requests are built.
diff --git a/chromium/components/download/internal/common/resource_downloader.cc b/chromium/components/download/internal/common/resource_downloader.cc
index ab961f310e3..988cf5cef88 100644
--- a/chromium/components/download/internal/common/resource_downloader.cc
+++ b/chromium/components/download/internal/common/resource_downloader.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/download/public/common/resource_downloader.h"
+#include "components/download/internal/common/resource_downloader.h"
#include <memory>
-#include "base/strings/utf_string_conversions.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
#include "components/download/public/common/stream_handle_input_stream.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
@@ -60,7 +60,8 @@ std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload(
base::WeakPtr<UrlDownloadHandler::Delegate> delegate,
std::unique_ptr<DownloadUrlParameters> params,
std::unique_ptr<network::ResourceRequest> request,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const GURL& site_url,
const GURL& tab_url,
const GURL& tab_referrer_url,
@@ -71,7 +72,7 @@ std::unique_ptr<ResourceDownloader> ResourceDownloader::BeginDownload(
delegate, std::move(request), params->render_process_host_id(),
params->render_frame_host_routing_id(), site_url, tab_url,
tab_referrer_url, download_id, task_runner,
- std::move(shared_url_loader_factory));
+ std::move(url_loader_factory_getter));
downloader->Start(std::move(params), is_parallel_request);
return downloader;
@@ -88,18 +89,18 @@ ResourceDownloader::InterceptNavigationResponse(
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
- const base::Optional<std::string>& suggested_filename,
const scoped_refptr<network::ResourceResponse>& response,
net::CertStatus cert_status,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
auto downloader = std::make_unique<ResourceDownloader>(
delegate, std::move(resource_request), render_process_id, render_frame_id,
site_url, tab_url, tab_referrer_url, download::DownloadItem::kInvalidId,
- task_runner, std::move(shared_url_loader_factory));
+ task_runner, std::move(url_loader_factory_getter));
downloader->InterceptResponse(std::move(response), std::move(url_chain),
- suggested_filename, cert_status,
+ cert_status,
std::move(url_loader_client_endpoints));
return downloader;
}
@@ -114,7 +115,8 @@ ResourceDownloader::ResourceDownloader(
const GURL& tab_referrer_url,
uint32_t download_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory)
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter)
: delegate_(delegate),
resource_request_(std::move(resource_request)),
download_id_(download_id),
@@ -124,7 +126,7 @@ ResourceDownloader::ResourceDownloader(
tab_url_(tab_url),
tab_referrer_url_(tab_referrer_url),
delegate_task_runner_(task_runner),
- shared_url_loader_factory_(std::move(shared_url_loader_factory)),
+ url_loader_factory_getter_(std::move(url_loader_factory_getter)),
weak_ptr_factory_(this) {}
ResourceDownloader::~ResourceDownloader() = default;
@@ -154,7 +156,7 @@ void ResourceDownloader::Start(
// Set up the URLLoader
network::mojom::URLLoaderRequest url_loader_request =
mojo::MakeRequest(&url_loader_);
- shared_url_loader_factory_->CreateLoaderAndStart(
+ url_loader_factory_getter_->GetURLLoaderFactory()->CreateLoaderAndStart(
std::move(url_loader_request),
0, // routing_id
0, // request_id
@@ -169,18 +171,14 @@ void ResourceDownloader::Start(
void ResourceDownloader::InterceptResponse(
const scoped_refptr<network::ResourceResponse>& response,
std::vector<GURL> url_chain,
- const base::Optional<std::string>& suggested_filename,
net::CertStatus cert_status,
network::mojom::URLLoaderClientEndpointsPtr endpoints) {
// Set the URLLoader.
url_loader_.Bind(std::move(endpoints->url_loader));
// Create the new URLLoaderClient that will intercept the navigation.
- auto save_info = std::make_unique<DownloadSaveInfo>();
- if (suggested_filename.has_value())
- save_info->suggested_name = base::UTF8ToUTF16(suggested_filename.value());
url_loader_client_ = std::make_unique<DownloadResponseHandler>(
- resource_request_.get(), this, std::move(save_info),
+ resource_request_.get(), this, std::make_unique<DownloadSaveInfo>(),
false, /* is_parallel_request */
false, /* is_transient */
false, /* fetch_error_body */
@@ -216,11 +214,11 @@ void ResourceDownloader::OnResponseStarted(
&UrlDownloadHandler::Delegate::OnUrlDownloadStarted, delegate_,
std::move(download_create_info),
std::make_unique<StreamHandleInputStream>(std::move(stream_handle)),
- std::move(shared_url_loader_factory_), callback_));
+ std::move(url_loader_factory_getter_), callback_));
}
void ResourceDownloader::OnReceiveRedirect() {
- url_loader_->FollowRedirect();
+ url_loader_->FollowRedirect(base::nullopt);
}
} // namespace download
diff --git a/chromium/components/download/public/common/resource_downloader.h b/chromium/components/download/internal/common/resource_downloader.h
index 9106f98d3dd..ce6eef63834 100644
--- a/chromium/components/download/public/common/resource_downloader.h
+++ b/chromium/components/download/internal/common/resource_downloader.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 COMPONENTS_DOWNLOAD_PUBLIC_COMMON_RESOURCE_DOWNLOADER_H_
-#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_RESOURCE_DOWNLOADER_H_
+#ifndef COMPONENTS_DOWNLOAD_INTERNAL_COMMON_RESOURCE_DOWNLOADER_H_
+#define COMPONENTS_DOWNLOAD_INTERNAL_COMMON_RESOURCE_DOWNLOADER_H_
#include "components/download/public/common/download_export.h"
#include "components/download/public/common/download_response_handler.h"
@@ -13,11 +13,8 @@
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/mojom/url_loader.mojom.h"
-namespace network {
-class SharedURLLoaderFactory;
-}
-
namespace download {
+class DownloadURLLoaderFactoryGetter;
// Class for handing the download of a url.
class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
@@ -29,7 +26,8 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
std::unique_ptr<download::DownloadUrlParameters> download_url_parameters,
std::unique_ptr<network::ResourceRequest> request,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const GURL& site_url,
const GURL& tab_url,
const GURL& tab_referrer_url,
@@ -49,11 +47,11 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
const GURL& tab_url,
const GURL& tab_referrer_url,
std::vector<GURL> url_chain,
- const base::Optional<std::string>& suggested_filename,
const scoped_refptr<network::ResourceResponse>& response,
net::CertStatus cert_status,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
ResourceDownloader(
@@ -66,7 +64,8 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
const GURL& tab_referrer_url,
uint32_t download_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory);
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter);
~ResourceDownloader() override;
// download::DownloadResponseHandler::Delegate
@@ -85,7 +84,6 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
void InterceptResponse(
const scoped_refptr<network::ResourceResponse>& response,
std::vector<GURL> url_chain,
- const base::Optional<std::string>& suggested_filename,
net::CertStatus cert_status,
network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints);
@@ -133,8 +131,9 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
// TaskRunner to post callbacks to the |delegate_|
scoped_refptr<base::SingleThreadTaskRunner> delegate_task_runner_;
- // URLLoaderFactory for issueing network requests.
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
+ // URLLoaderFactory getter for issueing network requests.
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter_;
base::WeakPtrFactory<ResourceDownloader> weak_ptr_factory_;
@@ -143,4 +142,4 @@ class COMPONENTS_DOWNLOAD_EXPORT ResourceDownloader
} // namespace download
-#endif // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_RESOURCE_DOWNLOADER_H_
+#endif // COMPONENTS_DOWNLOAD_INTERNAL_COMMON_RESOURCE_DOWNLOADER_H_
diff --git a/chromium/components/download/internal/common/url_download_handler_factory.cc b/chromium/components/download/internal/common/url_download_handler_factory.cc
index fec5bf41cd0..625f6da4ffd 100644
--- a/chromium/components/download/internal/common/url_download_handler_factory.cc
+++ b/chromium/components/download/internal/common/url_download_handler_factory.cc
@@ -6,9 +6,10 @@
#include "base/no_destructor.h"
#include "base/synchronization/lock.h"
+#include "components/download/internal/common/resource_downloader.h"
#include "components/download/public/common/download_item.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
#include "components/download/public/common/download_utils.h"
-#include "components/download/public/common/resource_downloader.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace download {
@@ -25,14 +26,15 @@ class DefaultUrlDownloadHandlerFactory : public UrlDownloadHandlerFactory {
UrlDownloadHandler::UniqueUrlDownloadHandlerPtr CreateUrlDownloadHandler(
std::unique_ptr<download::DownloadUrlParameters> params,
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) override {
std::unique_ptr<network::ResourceRequest> request =
CreateResourceRequest(params.get());
return UrlDownloadHandler::UniqueUrlDownloadHandlerPtr(
download::ResourceDownloader::BeginDownload(
delegate, std::move(params), std::move(request),
- std::move(shared_url_loader_factory), GURL(), GURL(), GURL(),
+ std::move(url_loader_factory_getter), GURL(), GURL(), GURL(),
download::DownloadItem::kInvalidId, true, task_runner)
.release(),
base::OnTaskRunnerDeleter(base::ThreadTaskRunnerHandle::Get()));
@@ -57,13 +59,14 @@ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr
UrlDownloadHandlerFactory::Create(
std::unique_ptr<download::DownloadUrlParameters> params,
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
base::AutoLock auto_lock(GetURLDownloadHandlerFactoryLock());
if (!g_url_download_handler_factory)
g_url_download_handler_factory = new DefaultUrlDownloadHandlerFactory();
return g_url_download_handler_factory->CreateUrlDownloadHandler(
- std::move(params), delegate, std::move(shared_url_loader_factory),
+ std::move(params), delegate, std::move(url_loader_factory_getter),
task_runner);
}
diff --git a/chromium/components/download/public/background_service/download_metadata.cc b/chromium/components/download/public/background_service/download_metadata.cc
index 22eb64c2c37..9beca125590 100644
--- a/chromium/components/download/public/background_service/download_metadata.cc
+++ b/chromium/components/download/public/background_service/download_metadata.cc
@@ -19,12 +19,13 @@ bool CompletionInfo::operator==(const CompletionInfo& other) const {
return path == other.path && bytes_downloaded == other.bytes_downloaded;
}
-DownloadMetaData::DownloadMetaData() = default;
+DownloadMetaData::DownloadMetaData() : current_size(0u) {}
DownloadMetaData::DownloadMetaData(const DownloadMetaData& other) = default;
bool DownloadMetaData::operator==(const DownloadMetaData& other) const {
- return guid == other.guid && completion_info == other.completion_info;
+ return guid == other.guid && current_size == other.current_size &&
+ completion_info == other.completion_info;
}
DownloadMetaData::~DownloadMetaData() = default;
diff --git a/chromium/components/download/public/background_service/download_metadata.h b/chromium/components/download/public/background_service/download_metadata.h
index b786ba19962..68a507fc2db 100644
--- a/chromium/components/download/public/background_service/download_metadata.h
+++ b/chromium/components/download/public/background_service/download_metadata.h
@@ -35,6 +35,10 @@ struct DownloadMetaData {
// The GUID of the download.
std::string guid;
+ // Data that has been fetched. Can be used to get the current size of
+ // uncompleted download.
+ uint64_t current_size;
+
// Info about successfully completed download, or null for in-progress
// download. Failed download will not be persisted and exposed as meta data.
base::Optional<CompletionInfo> completion_info;
diff --git a/chromium/components/download/public/common/BUILD.gn b/chromium/components/download/public/common/BUILD.gn
index f11815d9c84..16f35f36623 100644
--- a/chromium/components/download/public/common/BUILD.gn
+++ b/chromium/components/download/public/common/BUILD.gn
@@ -48,11 +48,11 @@ component("public") {
"download_url_parameters.cc",
"download_url_parameters.h",
"download_utils.h",
+ "in_progress_download_manager.h",
"input_stream.cc",
"input_stream.h",
"parallel_download_configs.h",
"rate_estimator.h",
- "resource_downloader.h",
"resume_mode.h",
"stream_handle_input_stream.h",
"url_download_handler_factory.h",
@@ -104,10 +104,6 @@ mojom("interfaces") {
"download_stream.mojom",
]
- public_deps = [
- "//mojo/common:common_custom_types",
- ]
-
export_class_attribute = "COMPONENTS_DOWNLOAD_EXPORT"
export_define = "COMPONENTS_DOWNLOAD_IMPLEMENTATION=1"
export_header = "components/download/public/common/download_export.h"
diff --git a/chromium/components/download/public/common/download_danger_type.h b/chromium/components/download/public/common/download_danger_type.h
index c97bd08eebc..e9e8952413b 100644
--- a/chromium/components/download/public/common/download_danger_type.h
+++ b/chromium/components/download/public/common/download_danger_type.h
@@ -15,34 +15,37 @@ enum DownloadDangerType {
// A dangerous file to the system (e.g.: a pdf or extension from
// places other than gallery).
- DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE,
+ DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE = 1,
// Safebrowsing download service shows this URL leads to malicious file
// download.
- DOWNLOAD_DANGER_TYPE_DANGEROUS_URL,
+ DOWNLOAD_DANGER_TYPE_DANGEROUS_URL = 2,
// SafeBrowsing download service shows this file content as being malicious.
- DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT,
+ DOWNLOAD_DANGER_TYPE_DANGEROUS_CONTENT = 3,
// The content of this download may be malicious (e.g., extension is exe but
// SafeBrowsing has not finished checking the content).
- DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT,
+ DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT = 4,
// SafeBrowsing download service checked the contents of the download, but
// didn't have enough data to determine whether it was malicious.
- DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT,
+ DOWNLOAD_DANGER_TYPE_UNCOMMON_CONTENT = 5,
// The download was evaluated to be one of the other types of danger,
// but the user told us to go ahead anyway.
- DOWNLOAD_DANGER_TYPE_USER_VALIDATED,
+ DOWNLOAD_DANGER_TYPE_USER_VALIDATED = 6,
// SafeBrowsing download service checked the contents of the download and
// didn't have data on this specific file, but the file was served from a host
// known to serve mostly malicious content.
- DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST,
+ DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST = 7,
// Applications and extensions that modify browser and/or computer settings
- DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED,
+ DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED = 8,
+
+ // Download URL whitelisted by enterprise policy.
+ DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY = 9,
// Memory space for histograms is determined by the max.
// ALWAYS ADD NEW VALUES BEFORE THIS ONE.
diff --git a/chromium/components/download/public/common/download_item.h b/chromium/components/download/public/common/download_item.h
index 3520400f3a6..225d60ce645 100644
--- a/chromium/components/download/public/common/download_item.h
+++ b/chromium/components/download/public/common/download_item.h
@@ -112,7 +112,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItem : public base::SupportsUserData {
// parallel downloading is enabled. Slices should have different offsets
// so that they don't overlap. |finished| will be marked as true when the
// download stream is successfully completed.
- struct COMPONENTS_DOWNLOAD_EXPORT ReceivedSlice {
+ struct ReceivedSlice {
ReceivedSlice(int64_t offset, int64_t received_bytes)
: offset(offset), received_bytes(received_bytes), finished(false) {}
@@ -432,6 +432,11 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItem : public base::SupportsUserData {
// for target file path determination.
virtual bool IsTransient() const = 0;
+ // Returns whether the download item corresponds to a parallel download. This
+ // usually means parallel download has been enabled and the download job is
+ // parallelizable.
+ virtual bool IsParallelDownload() const = 0;
+
// External state transitions/setters ----------------------------------------
// TODO(rdsmith): These should all be removed; the download item should
diff --git a/chromium/components/download/public/common/download_item_impl.h b/chromium/components/download/public/common/download_item_impl.h
index a92093e5497..bb8ae8623e1 100644
--- a/chromium/components/download/public/common/download_item_impl.h
+++ b/chromium/components/download/public/common/download_item_impl.h
@@ -23,9 +23,9 @@
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/download/public/common/download_item.h"
#include "components/download/public/common/download_request_handle_interface.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
#include "components/download/public/common/download_url_parameters.h"
#include "components/download/public/common/resume_mode.h"
-#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
namespace net {
@@ -33,7 +33,6 @@ class URLRequestContextGetter;
}
namespace download {
-
class DownloadFile;
class DownloadItemImplDelegate;
class DownloadJob;
@@ -275,6 +274,7 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
bool GetOpened() const override;
base::Time GetLastAccessTime() const override;
bool IsTransient() const override;
+ bool IsParallelDownload() const override;
void OnContentCheckCompleted(DownloadDangerType danger_type,
DownloadInterruptReason reason) override;
void SetOpenWhenComplete(bool open) override;
@@ -298,12 +298,12 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadItemImpl
// download resumption request.
// TODO(qinmin): Remove |url_request_context_getter| once network service is
// enabled.
- virtual void Start(
- std::unique_ptr<DownloadFile> download_file,
- std::unique_ptr<DownloadRequestHandleInterface> req_handle,
- const DownloadCreateInfo& new_create_info,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
- net::URLRequestContextGetter* url_request_context_getter);
+ virtual void Start(std::unique_ptr<DownloadFile> download_file,
+ std::unique_ptr<DownloadRequestHandleInterface> req_handle,
+ const DownloadCreateInfo& new_create_info,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
+ net::URLRequestContextGetter* url_request_context_getter);
// Needed because of intertwining with DownloadManagerImpl -------------------
diff --git a/chromium/components/download/public/common/download_job_factory.h b/chromium/components/download/public/common/download_job_factory.h
index ba90f668d11..cd44f441cad 100644
--- a/chromium/components/download/public/common/download_job_factory.h
+++ b/chromium/components/download/public/common/download_job_factory.h
@@ -15,15 +15,12 @@ namespace net {
class URLRequestContextGetter;
}
-namespace network {
-class SharedURLLoaderFactory;
-} // namespace network
-
namespace download {
class DownloadItem;
class DownloadJob;
class DownloadRequestHandleInterface;
+class DownloadURLLoaderFactoryGetter;
// Factory class to create different kinds of DownloadJob.
class COMPONENTS_DOWNLOAD_EXPORT DownloadJobFactory {
@@ -33,7 +30,8 @@ class COMPONENTS_DOWNLOAD_EXPORT DownloadJobFactory {
std::unique_ptr<DownloadRequestHandleInterface> req_handle,
const DownloadCreateInfo& create_info,
bool is_save_package_download,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
net::URLRequestContextGetter* url_request_context_getter);
private:
diff --git a/chromium/components/download/public/common/download_stats.h b/chromium/components/download/public/common/download_stats.h
index 251dfa8e99a..15652249738 100644
--- a/chromium/components/download/public/common/download_stats.h
+++ b/chromium/components/download/public/common/download_stats.h
@@ -136,6 +136,10 @@ enum DownloadCountTypes {
// Count of attempts for auto download resumption.
AUTO_RESUMPTION_COUNT,
+ // Count of download attempts that are dropped due to content settings or
+ // request limiter before DownloadItem is created.
+ DOWNLOAD_DROPPED_COUNT,
+
DOWNLOAD_COUNT_TYPES_LAST_ENTRY
};
diff --git a/chromium/components/download/public/common/download_utils.h b/chromium/components/download/public/common/download_utils.h
index 9fc9c5a5e39..c3e4b9f246b 100644
--- a/chromium/components/download/public/common/download_utils.h
+++ b/chromium/components/download/public/common/download_utils.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_UTILS_H_
#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_UTILS_H_
+#include "components/download/downloader/in_progress/download_entry.h"
#include "components/download/public/common/download_export.h"
#include "components/download/public/common/download_interrupt_reasons.h"
+#include "components/download/public/common/download_item.h"
+#include "components/download/public/common/download_source.h"
#include "net/base/net_errors.h"
#include "net/cert/cert_status_flags.h"
#include "net/http/http_response_headers.h"
@@ -57,6 +60,16 @@ COMPONENTS_DOWNLOAD_EXPORT int GetLoadFlags(DownloadUrlParameters* params,
COMPONENTS_DOWNLOAD_EXPORT std::unique_ptr<net::HttpRequestHeaders>
GetAdditionalRequestHeaders(DownloadUrlParameters* params);
+// Helper functions for DownloadItem -> DownloadEntry for InProgressCache.
+COMPONENTS_DOWNLOAD_EXPORT DownloadEntry CreateDownloadEntryFromItem(
+ const DownloadItem& item,
+ const std::string& request_origin,
+ DownloadSource download_source,
+ bool fetch_error_body,
+ const DownloadUrlParameters::RequestHeadersType& request_headers);
+
+COMPONENTS_DOWNLOAD_EXPORT uint64_t GetUniqueDownloadId();
+
} // namespace download
#endif // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_UTILS_H_
diff --git a/chromium/components/download/public/common/in_progress_download_manager.h b/chromium/components/download/public/common/in_progress_download_manager.h
new file mode 100644
index 00000000000..9dba8c67b1d
--- /dev/null
+++ b/chromium/components/download/public/common/in_progress_download_manager.h
@@ -0,0 +1,171 @@
+// 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 COMPONENTS_DOWNLOAD_PUBLIC_COMMON_IN_PROGRESS_DOWNLOAD_MANAGER_H_
+#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_IN_PROGRESS_DOWNLOAD_MANAGER_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "components/download/public/common/download_export.h"
+#include "components/download/public/common/download_file_factory.h"
+#include "components/download/public/common/download_item_impl_delegate.h"
+#include "components/download/public/common/url_download_handler.h"
+#include "url/gurl.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace network {
+struct ResourceResponse;
+}
+
+namespace download {
+
+class DownloadURLLoaderFactoryGetter;
+class DownloadUrlParameters;
+class InProgressCache;
+
+// Manager for handling all active downloads.
+class COMPONENTS_DOWNLOAD_EXPORT InProgressDownloadManager
+ : public UrlDownloadHandler::Delegate,
+ public DownloadItemImplDelegate {
+ public:
+ using DownloadIdCallback = base::RepeatingCallback<void(uint32_t)>;
+
+ // Class to be notified when download starts/stops.
+ class COMPONENTS_DOWNLOAD_EXPORT Delegate {
+ public:
+ // Intercepts the download to another system if applicable. Returns true if
+ // the download was intercepted.
+ virtual bool InterceptDownload(
+ const DownloadCreateInfo& download_create_info) = 0;
+
+ // Called to get an ID for a new download. |callback| may be called
+ // synchronously.
+ virtual void GetNextId(const DownloadIdCallback& callback) = 0;
+
+ // Gets the default download directory.
+ virtual base::FilePath GetDefaultDownloadDirectory() = 0;
+
+ // Gets the download item for the given id.
+ // TODO(qinmin): remove this method and let InProgressDownloadManager
+ // create the DownloadItem from in-progress cache.
+ virtual DownloadItemImpl* GetDownloadItem(
+ uint32_t id,
+ bool new_download,
+ const DownloadCreateInfo& download_create_info) = 0;
+
+ // Gets the URLRequestContextGetter for sending requests.
+ // TODO(qinmin): remove this once network service is fully enabled.
+ virtual net::URLRequestContextGetter* GetURLRequestContextGetter(
+ const DownloadCreateInfo& download_create_info) = 0;
+
+ // Called when a new download is started.
+ virtual void OnNewDownloadStarted(DownloadItem* download) = 0;
+ };
+
+ using IsOriginSecureCallback = base::RepeatingCallback<bool(const GURL&)>;
+ InProgressDownloadManager(Delegate* delegate,
+ const IsOriginSecureCallback& is_origin_secure_cb);
+ ~InProgressDownloadManager() override;
+ // Called to start a download.
+ void BeginDownload(
+ std::unique_ptr<DownloadUrlParameters> params,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ uint32_t download_id,
+ const GURL& site_url,
+ const GURL& tab_url,
+ const GURL& tab_referrer_url);
+
+ // Intercepts a download from navigation.
+ void InterceptDownloadFromNavigation(
+ std::unique_ptr<network::ResourceRequest> resource_request,
+ int render_process_id,
+ int render_frame_id,
+ const GURL& site_url,
+ const GURL& tab_url,
+ const GURL& tab_referrer_url,
+ std::vector<GURL> url_chain,
+ scoped_refptr<network::ResourceResponse> response,
+ net::CertStatus cert_status,
+ network::mojom::URLLoaderClientEndpointsPtr url_loader_client_endpoints,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter);
+
+ void Initialize(const base::FilePath& metadata_cache_dir,
+ base::OnceClosure callback);
+
+ void StartDownload(
+ std::unique_ptr<DownloadCreateInfo> info,
+ std::unique_ptr<InputStream> stream,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ const DownloadUrlParameters::OnStartedCallback& on_started);
+
+ // Shutting down the manager and stop all downloads.
+ void ShutDown();
+
+ // DownloadItemImplDelegate implementations.
+ void ResumeInterruptedDownload(std::unique_ptr<DownloadUrlParameters> params,
+ uint32_t id,
+ const GURL& site_url) override;
+ base::Optional<DownloadEntry> GetInProgressEntry(
+ DownloadItemImpl* download) override;
+ void ReportBytesWasted(DownloadItemImpl* download) override;
+
+ void set_file_factory(std::unique_ptr<DownloadFileFactory> file_factory) {
+ file_factory_ = std::move(file_factory);
+ }
+ DownloadFileFactory* file_factory() { return file_factory_.get(); }
+
+ private:
+ // UrlDownloadHandler::Delegate implementations.
+ void OnUrlDownloadStarted(
+ std::unique_ptr<DownloadCreateInfo> download_create_info,
+ std::unique_ptr<InputStream> input_stream,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> shared_url_loader_factory,
+ const DownloadUrlParameters::OnStartedCallback& callback) override;
+ void OnUrlDownloadStopped(UrlDownloadHandler* downloader) override;
+ void OnUrlDownloadHandlerCreated(
+ UrlDownloadHandler::UniqueUrlDownloadHandlerPtr downloader) override;
+
+ // Start a download with given ID.
+ void StartDownloadWithId(
+ std::unique_ptr<DownloadCreateInfo> info,
+ std::unique_ptr<InputStream> stream,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
+ const DownloadUrlParameters::OnStartedCallback& on_started,
+ bool new_download,
+ uint32_t id);
+
+ // Active download handlers.
+ std::vector<UrlDownloadHandler::UniqueUrlDownloadHandlerPtr>
+ url_download_handlers_;
+
+ // Delegate to provide information to create a new download. Can be null.
+ Delegate* delegate_;
+
+ // Factory for the creation of download files.
+ std::unique_ptr<DownloadFileFactory> file_factory_;
+
+ // Cache for storing metadata about in progress downloads.
+ std::unique_ptr<InProgressCache> download_metadata_cache_;
+
+ // listens to information about in-progress download items.
+ std::unique_ptr<DownloadItem::Observer> in_progress_download_observer_;
+
+ // callback to check if an origin is secure.
+ IsOriginSecureCallback is_origin_secure_cb_;
+
+ base::WeakPtrFactory<InProgressDownloadManager> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProgressDownloadManager);
+};
+
+} // namespace download
+
+#endif // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_IN_PROGRESS_DOWNLOAD_MANAGER_H_
diff --git a/chromium/components/download/public/common/mock_download_file.h b/chromium/components/download/public/common/mock_download_file.h
index 8f5bec44208..7684ee89a6e 100644
--- a/chromium/components/download/public/common/mock_download_file.h
+++ b/chromium/components/download/public/common/mock_download_file.h
@@ -23,7 +23,7 @@ namespace download {
class MockDownloadFile : public DownloadFile {
public:
MockDownloadFile();
- virtual ~MockDownloadFile();
+ ~MockDownloadFile() override;
// DownloadFile functions.
// Using the legacy workaround for move-only types in mock methods.
diff --git a/chromium/components/download/public/common/mock_download_item.h b/chromium/components/download/public/common/mock_download_item.h
index ddb4684f746..d079bdc2b95 100644
--- a/chromium/components/download/public/common/mock_download_item.h
+++ b/chromium/components/download/public/common/mock_download_item.h
@@ -106,6 +106,7 @@ class MockDownloadItem : public DownloadItem {
MOCK_CONST_METHOD0(GetOpened, bool());
MOCK_CONST_METHOD0(GetLastAccessTime, base::Time());
MOCK_CONST_METHOD0(IsTransient, bool());
+ MOCK_CONST_METHOD0(IsParallelDownload, bool());
MOCK_METHOD2(OnContentCheckCompleted,
void(DownloadDangerType, DownloadInterruptReason));
MOCK_METHOD1(SetOpenWhenComplete, void(bool));
diff --git a/chromium/components/download/public/common/mock_download_item_impl.h b/chromium/components/download/public/common/mock_download_item_impl.h
index 752eda539db..7bbb9589d24 100644
--- a/chromium/components/download/public/common/mock_download_item_impl.h
+++ b/chromium/components/download/public/common/mock_download_item_impl.h
@@ -53,7 +53,8 @@ class MockDownloadItemImpl : public DownloadItemImpl {
std::unique_ptr<DownloadFile> download_file,
std::unique_ptr<DownloadRequestHandleInterface> req_handle,
const DownloadCreateInfo& create_info,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
net::URLRequestContextGetter* url_request_context_getter) override {
MockStart(download_file.get(), req_handle.get());
}
diff --git a/chromium/components/download/public/common/url_download_handler.h b/chromium/components/download/public/common/url_download_handler.h
index 5779dd135a6..ce059d92313 100644
--- a/chromium/components/download/public/common/url_download_handler.h
+++ b/chromium/components/download/public/common/url_download_handler.h
@@ -6,11 +6,13 @@
#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_URL_DOWNLOAD_HANDLER_H_
#include "components/download/public/common/download_export.h"
+#include "components/download/public/common/download_url_loader_factory_getter.h"
#include "components/download/public/common/download_url_parameters.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace download {
struct DownloadCreateInfo;
+class DownloadURLLoaderFactoryGetter;
class InputStream;
// Class for handling the download of a url. Implemented by child classes.
@@ -24,8 +26,7 @@ class COMPONENTS_DOWNLOAD_EXPORT UrlDownloadHandler {
virtual void OnUrlDownloadStarted(
std::unique_ptr<DownloadCreateInfo> download_create_info,
std::unique_ptr<InputStream> input_stream,
- scoped_refptr<network::SharedURLLoaderFactory>
- shared_url_loader_factory,
+ scoped_refptr<DownloadURLLoaderFactoryGetter> url_loader_factory_getter,
const DownloadUrlParameters::OnStartedCallback& callback) = 0;
// Called after the connection is cancelled or finished.
diff --git a/chromium/components/download/public/common/url_download_handler_factory.h b/chromium/components/download/public/common/url_download_handler_factory.h
index c43719488b1..c09c37af0cc 100644
--- a/chromium/components/download/public/common/url_download_handler_factory.h
+++ b/chromium/components/download/public/common/url_download_handler_factory.h
@@ -7,11 +7,8 @@
#include "components/download/public/common/url_download_handler.h"
-namespace network {
-class SharedURLLoaderFactory;
-}
-
namespace download {
+class DownloadURLLoaderFactoryGetter;
class DownloadUrlParameters;
// Class for handling the creation of a URLDownloadHandler. This is used to
@@ -28,7 +25,8 @@ class COMPONENTS_DOWNLOAD_EXPORT UrlDownloadHandlerFactory {
static UrlDownloadHandler::UniqueUrlDownloadHandlerPtr Create(
std::unique_ptr<download::DownloadUrlParameters> params,
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
virtual ~UrlDownloadHandlerFactory();
@@ -42,7 +40,8 @@ class COMPONENTS_DOWNLOAD_EXPORT UrlDownloadHandlerFactory {
CreateUrlDownloadHandler(
std::unique_ptr<download::DownloadUrlParameters> params,
base::WeakPtr<download::UrlDownloadHandler::Delegate> delegate,
- scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
+ scoped_refptr<download::DownloadURLLoaderFactoryGetter>
+ url_loader_factory_getter,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) = 0;
};
diff --git a/chromium/components/download/quarantine/quarantine.h b/chromium/components/download/quarantine/quarantine.h
index cdd296d8f5e..01efc346a18 100644
--- a/chromium/components/download/quarantine/quarantine.h
+++ b/chromium/components/download/quarantine/quarantine.h
@@ -66,8 +66,9 @@ enum class QuarantineFileResult {
//
// Parameters:
// |file| : Final name of the file.
-// |source_url|: URL from which the file content was downloaded.
-// |referrer_url|: Referring URL.
+// |source_url|: URL from which the file content was downloaded. This is empty
+// for off-the-record download.
+// |referrer_url|: Referring URL. This is empty for off-the-record download.
// |client_guid|: Only used on Windows. Identifies the client application
// that downloaded the file.
QuarantineFileResult QuarantineFile(const base::FilePath& file,
diff --git a/chromium/components/download/quarantine/quarantine_win.cc b/chromium/components/download/quarantine/quarantine_win.cc
index 948c59682a6..f240414d7a6 100644
--- a/chromium/components/download/quarantine/quarantine_win.cc
+++ b/chromium/components/download/quarantine/quarantine_win.cc
@@ -74,7 +74,8 @@ bool ZoneIdentifierPresentForFile(const base::FilePath& path) {
std::vector<char> zone_identifier_contents_buffer(32);
DWORD actual_length = 0;
if (!ReadFile(file.Get(), &zone_identifier_contents_buffer.front(),
- zone_identifier_contents_buffer.size(), &actual_length, NULL))
+ zone_identifier_contents_buffer.size(), &actual_length,
+ nullptr))
return false;
zone_identifier_contents_buffer.resize(actual_length);
@@ -227,9 +228,9 @@ bool InvokeAttachmentServices(const base::FilePath& full_path,
return false;
}
- // The source URL could be empty if it was not a valid URL or was not HTTP/S.
- // If so, user "about:internet" as a fallback URL. The latter is known to
- // reliably map to the Internet zone.
+ // The source URL could be empty if it was not a valid URL, or was not HTTP/S,
+ // or the download was off-the-record. If so, user "about:internet" as a
+ // fallback URL. The latter is known to reliably map to the Internet zone.
//
// In addition, URLs that are longer than INTERNET_MAX_URL_LENGTH are also
// known to cause problems for URLMon. Hence also use "about:internet" in
diff --git a/chromium/components/drive/BUILD.gn b/chromium/components/drive/BUILD.gn
index 1ef9c4321b2..62924eff032 100644
--- a/chromium/components/drive/BUILD.gn
+++ b/chromium/components/drive/BUILD.gn
@@ -98,13 +98,22 @@ static_library("test_support") {
if (is_chromeos) {
source_set("drive_chromeos") {
sources = [
+ "chromeos/about_resource_loader.cc",
+ "chromeos/about_resource_loader.h",
+ "chromeos/about_resource_root_folder_id_loader.cc",
+ "chromeos/about_resource_root_folder_id_loader.h",
"chromeos/change_list_loader.cc",
"chromeos/change_list_loader.h",
"chromeos/change_list_loader_observer.h",
"chromeos/change_list_processor.cc",
"chromeos/change_list_processor.h",
+ "chromeos/default_corpus_change_list_loader.cc",
+ "chromeos/default_corpus_change_list_loader.h",
"chromeos/directory_loader.cc",
"chromeos/directory_loader.h",
+ "chromeos/drive_change_list_loader.h",
+ "chromeos/drive_file_util.cc",
+ "chromeos/drive_file_util.h",
"chromeos/file_cache.cc",
"chromeos/file_cache.h",
"chromeos/file_system.cc",
@@ -138,12 +147,17 @@ if (is_chromeos) {
"chromeos/file_system_interface.cc",
"chromeos/file_system_interface.h",
"chromeos/file_system_observer.h",
+ "chromeos/loader_controller.cc",
+ "chromeos/loader_controller.h",
"chromeos/remove_stale_cache_files.cc",
"chromeos/remove_stale_cache_files.h",
"chromeos/resource_metadata.cc",
"chromeos/resource_metadata.h",
+ "chromeos/root_folder_id_loader.h",
"chromeos/search_metadata.cc",
"chromeos/search_metadata.h",
+ "chromeos/start_page_token_loader.cc",
+ "chromeos/start_page_token_loader.h",
"chromeos/sync/entry_revert_performer.cc",
"chromeos/sync/entry_revert_performer.h",
"chromeos/sync/entry_update_performer.cc",
@@ -152,6 +166,8 @@ if (is_chromeos) {
"chromeos/sync/remove_performer.h",
"chromeos/sync_client.cc",
"chromeos/sync_client.h",
+ "chromeos/team_drive_list_loader.cc",
+ "chromeos/team_drive_list_loader.h",
]
deps = [
":drive",
diff --git a/chromium/components/error_page/common/BUILD.gn b/chromium/components/error_page/common/BUILD.gn
index c91f2e64e28..168f4afca40 100644
--- a/chromium/components/error_page/common/BUILD.gn
+++ b/chromium/components/error_page/common/BUILD.gn
@@ -6,6 +6,8 @@ static_library("common") {
sources = [
"error.cc",
"error.h",
+ "error_page_features.cc",
+ "error_page_features.h",
"error_page_params.cc",
"error_page_params.h",
"error_page_switches.cc",
diff --git a/chromium/components/error_page/common/error.cc b/chromium/components/error_page/common/error.cc
index 6bfce30e31b..654380df939 100644
--- a/chromium/components/error_page/common/error.cc
+++ b/chromium/components/error_page/common/error.cc
@@ -8,11 +8,12 @@
namespace error_page {
+const char Error::kNetErrorDomain[] = "net";
const char Error::kHttpErrorDomain[] = "http";
const char Error::kDnsProbeErrorDomain[] = "dnsprobe";
Error Error::NetError(const GURL& url, int reason, bool stale_copy_in_cache) {
- return Error(url, net::kErrorDomain, reason, stale_copy_in_cache);
+ return Error(url, kNetErrorDomain, reason, stale_copy_in_cache);
}
Error Error::HttpError(const GURL& url, int http_status_code) {
diff --git a/chromium/components/error_page/common/error.h b/chromium/components/error_page/common/error.h
index 08c3de882bc..980a7b1e0d4 100644
--- a/chromium/components/error_page/common/error.h
+++ b/chromium/components/error_page/common/error.h
@@ -15,13 +15,14 @@ namespace error_page {
// This class is a copiable value class.
class Error {
public:
- // Use net::kErroDomain for network errors.
+ // For network errors
+ static const char kNetErrorDomain[];
// For http errors.
static const char kHttpErrorDomain[];
// For DNS probe errors.
static const char kDnsProbeErrorDomain[];
- // Returns a net::kErrorDomain error.
+ // Returns a kNetErrorDomain error.
static Error NetError(const GURL& url, int reason, bool stale_copy_in_cache);
// Returns a kHttpErrorDomain error.
static Error HttpError(const GURL& url, int status);
diff --git a/chromium/components/error_page/common/error_page_features.cc b/chromium/components/error_page/common/error_page_features.cc
new file mode 100644
index 00000000000..fef6fbc889c
--- /dev/null
+++ b/chromium/components/error_page/common/error_page_features.cc
@@ -0,0 +1,14 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/error_page/common/error_page_features.h"
+
+namespace error_page {
+namespace features {
+
+const base::Feature kDinoEasterEggBdayMode{"DinoEasterEggBdayMode",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace features
+} // namespace error_page \ No newline at end of file
diff --git a/chromium/components/error_page/common/error_page_features.h b/chromium/components/error_page/common/error_page_features.h
new file mode 100644
index 00000000000..f90b56219f9
--- /dev/null
+++ b/chromium/components/error_page/common/error_page_features.h
@@ -0,0 +1,21 @@
+// 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 COMPONENTS_ERROR_PAGE_COMMON_ERROR_PAGE_FEATURES_H_
+#define COMPONENTS_ERROR_PAGE_COMMON_ERROR_PAGE_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace error_page {
+namespace features {
+
+// Defines all the features used by //components/error_page.
+
+// Enables or disables the offline dino easter egg bday mode.
+extern const base::Feature kDinoEasterEggBdayMode;
+
+} // namespace features
+} // namespace error_page
+
+#endif // COMPONENTS_ERROR_PAGE_COMMON_ERROR_PAGE_FEATURES_H_
diff --git a/chromium/components/error_page/common/error_page_switches.cc b/chromium/components/error_page/common/error_page_switches.cc
index 7d8ef37b885..1cbe003ba29 100644
--- a/chromium/components/error_page/common/error_page_switches.cc
+++ b/chromium/components/error_page/common/error_page_switches.cc
@@ -9,6 +9,7 @@ namespace switches {
// Disables the dinosaur easter egg on the offline interstitial.
const char kDisableDinosaurEasterEgg[] = "disable-dinosaur-easter-egg";
+const char kEnableEasterEggBdayMode[] = "enable-dino-easter-egg-bday-mode";
// Values for the kShowSavedCopy flag.
const char kDisableShowSavedCopy[] = "disable";
diff --git a/chromium/components/error_page/common/error_page_switches.h b/chromium/components/error_page/common/error_page_switches.h
index d154656d2f8..75f5e206b66 100644
--- a/chromium/components/error_page/common/error_page_switches.h
+++ b/chromium/components/error_page/common/error_page_switches.h
@@ -12,6 +12,7 @@ namespace switches {
extern const char kDisableDinosaurEasterEgg[];
extern const char kDisableShowSavedCopy[];
+extern const char kEnableEasterEggBdayMode[];
extern const char kEnableShowSavedCopyPrimary[];
extern const char kEnableShowSavedCopySecondary[];
extern const char kShowSavedCopy[];
diff --git a/chromium/components/error_page/common/localized_error.cc b/chromium/components/error_page/common/localized_error.cc
index 8ba9680327d..be109af74d4 100644
--- a/chromium/components/error_page/common/localized_error.cc
+++ b/chromium/components/error_page/common/localized_error.cc
@@ -22,6 +22,7 @@
#include "base/values.h"
#include "build/build_config.h"
#include "components/error_page/common/error.h"
+#include "components/error_page/common/error_page_features.h"
#include "components/error_page/common/error_page_params.h"
#include "components/error_page/common/error_page_switches.h"
#include "components/error_page/common/net_error_info.h"
@@ -452,7 +453,7 @@ const LocalizedErrorMap* FindErrorMapInArray(const LocalizedErrorMap* maps,
const LocalizedErrorMap* LookupErrorMap(const std::string& error_domain,
int error_code, bool is_post) {
- if (error_domain == net::kErrorDomain) {
+ if (error_domain == Error::kNetErrorDomain) {
// Display a different page in the special case of navigating through the
// history to an uncached page created by a POST.
if (is_post && error_code == net::ERR_CACHE_MISS)
@@ -495,7 +496,7 @@ base::DictionaryValue* GetStandardMenuItemsText() {
const char* GetIconClassForError(const std::string& error_domain,
int error_code) {
if ((error_code == net::ERR_INTERNET_DISCONNECTED &&
- error_domain == net::kErrorDomain) ||
+ error_domain == Error::kNetErrorDomain) ||
(error_code == error_page::DNS_PROBE_FINISHED_NO_INTERNET &&
error_domain == Error::kDnsProbeErrorDomain))
return "icon-offline";
@@ -892,7 +893,7 @@ void LocalizedError::GetStrings(
// file instead of just using the "not available" default message. Just adding
// ERR_ACCESS_DENIED to the map isn't sufficient, since that message may be
// generated by some OSs when the operation doesn't involve a file URL.
- if (error_domain == net::kErrorDomain &&
+ if (error_domain == Error::kNetErrorDomain &&
error_code == net::ERR_ACCESS_DENIED && failed_url.scheme() == "file") {
options.heading_resource_id = IDS_ERRORPAGES_HEADING_FILE_ACCESS_DENIED;
options.summary_resource_id = IDS_ERRORPAGES_SUMMARY_FILE_ACCESS_DENIED;
@@ -938,6 +939,12 @@ void LocalizedError::GetStrings(
l10n_util::GetStringUTF16(IDS_ERRORPAGE_FUN_DISABLED));
}
+ if (command_line->HasSwitch(error_page::switches::kEnableEasterEggBdayMode) ||
+ base::FeatureList::IsEnabled(
+ error_page::features::kDinoEasterEggBdayMode)) {
+ error_strings->SetBoolean("bdayMode", true);
+ }
+
summary->SetString("failedUrl", failed_url_string);
summary->SetString("hostName", host_name);
@@ -949,7 +956,7 @@ void LocalizedError::GetStrings(
error_strings->Set("summary", std::move(summary));
base::string16 error_string;
- if (error_domain == net::kErrorDomain) {
+ if (error_domain == Error::kNetErrorDomain) {
// Non-internationalized error string, for debugging Chrome itself.
error_string = base::ASCIIToUTF16(net::ErrorToShortString(error_code));
} else if (error_domain == Error::kDnsProbeErrorDomain) {
diff --git a/chromium/components/error_page_strings.grdp b/chromium/components/error_page_strings.grdp
index 8d5feb1a0ba..9a984881fc9 100644
--- a/chromium/components/error_page_strings.grdp
+++ b/chromium/components/error_page_strings.grdp
@@ -104,16 +104,9 @@
<message name="IDS_ERRORPAGES_HEADING_NETWORK_ACCESS_DENIED" desc="Heading of the error page when we're not being allowed to access the network.">
Your Internet access is blocked
</message>
- <if expr="not is_android">
- <message name="IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED" desc="Heading of the error page when the network connection failed.">
- There is no Internet connection
- </message>
- </if>
- <if expr="is_android">
- <message name="IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED" desc="Mobile: Heading of the error page when the network connection failed.">
- You are offline.
- </message>
- </if>
+ <message name="IDS_ERRORPAGES_HEADING_INTERNET_DISCONNECTED" desc="Heading of the error page when the network connection failed.">
+ No internet
+ </message>
<message name="IDS_ERRORPAGES_HEADING_CACHE_READ_FAILURE" desc="Heading in the error page when we encountered an error reading from the cache. Generally this happens when the disk cache is corrupted from improper shutdown.">
This site can’t be loaded from the cache
</message>
diff --git a/chromium/components/error_page_strings_grdp/OWNERS b/chromium/components/error_page_strings_grdp/OWNERS
new file mode 100644
index 00000000000..1a8ff93c3c1
--- /dev/null
+++ b/chromium/components/error_page_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/error_page/OWNERS
diff --git a/chromium/components/error_page_strings_grdp/README.md b/chromium/components/error_page_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/error_page_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/exo/client_controlled_shell_surface.cc b/chromium/components/exo/client_controlled_shell_surface.cc
index f7651175407..08891072923 100644
--- a/chromium/components/exo/client_controlled_shell_surface.cc
+++ b/chromium/components/exo/client_controlled_shell_surface.cc
@@ -4,8 +4,11 @@
#include "components/exo/client_controlled_shell_surface.h"
+#include <utility>
+
#include "ash/frame/caption_buttons/caption_button_model.h"
#include "ash/frame/custom_frame_view_ash.h"
+#include "ash/frame/header_view.h"
#include "ash/frame/wide_frame_view.h"
#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
#include "ash/public/cpp/shell_window_ids.h"
@@ -24,6 +27,7 @@
#include "ash/wm/window_state_delegate.h"
#include "ash/wm/window_util.h"
#include "base/logging.h"
+#include "base/no_destructor.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_argument.h"
@@ -42,8 +46,14 @@
#include "ui/wm/core/window_util.h"
namespace exo {
+
namespace {
-ClientControlledShellSurface::DelegateFactoryCallback g_factory_callback;
+
+ClientControlledShellSurface::DelegateFactoryCallback& GetFactoryForTesting() {
+ using CallbackType = ClientControlledShellSurface::DelegateFactoryCallback;
+ static base::NoDestructor<CallbackType> factory;
+ return *factory;
+}
// Maximum amount of time to wait for contents that match the display's
// orientation in tablet mode.
@@ -226,7 +236,7 @@ class CaptionButtonModel : public ash::CaptionButtonModel {
class ClientControlledShellSurface::ScopedSetBoundsLocally {
public:
- ScopedSetBoundsLocally(ClientControlledShellSurface* shell_surface)
+ explicit ScopedSetBoundsLocally(ClientControlledShellSurface* shell_surface)
: state_(shell_surface->client_controlled_state_) {
state_->set_bounds_locally(true);
}
@@ -240,7 +250,7 @@ class ClientControlledShellSurface::ScopedSetBoundsLocally {
class ClientControlledShellSurface::ScopedLockedToRoot {
public:
- ScopedLockedToRoot(views::Widget* widget)
+ explicit ScopedLockedToRoot(views::Widget* widget)
: window_(widget->GetNativeWindow()) {
window_->SetProperty(ash::kLockedToRootKey, true);
}
@@ -305,6 +315,11 @@ void ClientControlledShellSurface::SetSnappedToRight() {
pending_window_state_ = ash::mojom::WindowStateType::RIGHT_SNAPPED;
}
+void ClientControlledShellSurface::SetPip() {
+ TRACE_EVENT0("exo", "ClientControlledShellSurface::SetPip");
+ pending_window_state_ = ash::mojom::WindowStateType::PIP;
+}
+
void ClientControlledShellSurface::SetPinned(ash::mojom::WindowPinType type) {
TRACE_EVENT1("exo", "ClientControlledShellSurface::SetPinned", "type",
static_cast<int>(type));
@@ -387,7 +402,7 @@ void ClientControlledShellSurface::SetResizeOutset(int outset) {
void ClientControlledShellSurface::OnWindowStateChangeEvent(
ash::mojom::WindowStateType current_state,
ash::mojom::WindowStateType next_state) {
- if (!state_changed_callback_.is_null())
+ if (state_changed_callback_)
state_changed_callback_.Run(current_state, next_state);
}
@@ -414,7 +429,6 @@ void ClientControlledShellSurface::AttemptToStartDrag(
// 2) mouse was pressed on the target or its subsurfaces.
if (toplevel_handler->gesture_target() ||
(mouse_pressed_handler && target->Contains(mouse_pressed_handler))) {
-
gfx::Point point_in_root(location);
wm::ConvertPointFromScreen(target->GetRootWindow(), &point_in_root);
toplevel_handler->AttemptToStartDrag(
@@ -459,11 +473,26 @@ void ClientControlledShellSurface::SetExtraTitle(
TRACE_EVENT1("exo", "ClientControlledShellSurface::SetExtraTitle",
"extra_title", base::UTF16ToUTF8(extra_title));
// The extra title is used in the window frame.
- frame_title_ = extra_title;
+ extra_title_ = extra_title;
if (widget_)
widget_->UpdateWindowTitle();
}
+void ClientControlledShellSurface::SetOrientationLock(
+ ash::OrientationLockType orientation_lock) {
+ TRACE_EVENT1("exo", "ClientControlledShellSurface::SetOrientationLock",
+ "orientation_lock", static_cast<int>(orientation_lock));
+
+ if (!widget_) {
+ initial_orientation_lock_ = orientation_lock;
+ return;
+ }
+
+ ash::Shell* shell = ash::Shell::Get();
+ shell->screen_orientation_controller()->LockOrientationForWindow(
+ widget_->GetNativeWindow(), orientation_lock);
+}
+
void ClientControlledShellSurface::OnBoundsChangeEvent(
ash::mojom::WindowStateType current_state,
ash::mojom::WindowStateType requested_state,
@@ -472,7 +501,7 @@ void ClientControlledShellSurface::OnBoundsChangeEvent(
int bounds_change) {
// Do no update the bounds unless we have geometry from client.
if (!geometry().IsEmpty() && !window_bounds.IsEmpty() &&
- !bounds_changed_callback_.is_null()) {
+ bounds_changed_callback_) {
// Sends the client bounds, which matches the geometry
// when frame is enabled.
ash::CustomFrameViewAsh* frame_view = GetFrameView();
@@ -492,13 +521,13 @@ void ClientControlledShellSurface::OnBoundsChangeEvent(
}
void ClientControlledShellSurface::OnDragStarted(int component) {
- if (!drag_started_callback_.is_null())
+ if (drag_started_callback_)
drag_started_callback_.Run(component);
}
void ClientControlledShellSurface::OnDragFinished(bool canceled,
const gfx::Point& location) {
- if (!drag_finished_callback_.is_null())
+ if (drag_finished_callback_)
drag_finished_callback_.Run(location.x(), location.y(), canceled);
}
////////////////////////////////////////////////////////////////////////////////
@@ -545,7 +574,7 @@ void ClientControlledShellSurface::OnSurfaceCommit() {
UpdateFrame();
UpdateBackdrop();
- if (!geometry_changed_callback_.is_null())
+ if (geometry_changed_callback_)
geometry_changed_callback_.Run(GetVisibleBounds());
// Apply new top inset height.
@@ -607,6 +636,7 @@ void ClientControlledShellSurface::OnWindowBoundsChanged(
void ClientControlledShellSurface::OnWindowAddedToRootWindow(
aura::Window* window) {
+ ScopedSetBoundsLocally scoped_set_bounds(this);
ScopedLockedToRoot scoped_locked_to_root(widget_);
UpdateWidgetBounds();
}
@@ -622,9 +652,9 @@ views::NonClientFrameView*
ClientControlledShellSurface::CreateNonClientFrameView(views::Widget* widget) {
ash::wm::WindowState* window_state = GetWindowState();
std::unique_ptr<ash::wm::ClientControlledState::Delegate> delegate =
- g_factory_callback.is_null()
- ? std::make_unique<ClientControlledStateDelegate>(this)
- : g_factory_callback.Run();
+ GetFactoryForTesting()
+ ? GetFactoryForTesting().Run()
+ : std::make_unique<ClientControlledStateDelegate>(this);
auto window_delegate = std::make_unique<ClientControlledWindowStateDelegate>(
this, delegate.get());
@@ -666,6 +696,12 @@ gfx::Size ClientControlledShellSurface::GetMaximumSize() const {
return gfx::Size();
}
+void ClientControlledShellSurface::OnDeviceScaleFactorChanged(float old_dsf,
+ float new_dsf) {
+ views::View::OnDeviceScaleFactorChanged(old_dsf, new_dsf);
+ UpdateFrameWidth();
+}
+
////////////////////////////////////////////////////////////////////////////////
// display::DisplayObserver overrides:
@@ -733,23 +769,39 @@ void ClientControlledShellSurface::CompositorLockTimedOut() {
// ShellSurface overrides:
void ClientControlledShellSurface::SetWidgetBounds(const gfx::Rect& bounds) {
- if ((!client_controlled_move_resize_ && !GetWindowState()->is_dragged()) ||
+
+ if (((!client_controlled_move_resize_ && !GetWindowState()->is_dragged()) ||
(client_controlled_move_resize_ &&
- (!resizer_ || resizer_->details().window_component != HTCAPTION))) {
+ (!resizer_ || resizer_->details().window_component != HTCAPTION))) &&
+ !client_controlled_state_->set_bounds_locally()) {
{
// Calculate a minimum window visibility required bounds.
aura::Window* window = widget_->GetNativeWindow();
- gfx::Rect rect(bounds);
- wm::ConvertRectFromScreen(window->GetRootWindow(), &rect);
+ gfx::Rect root_rect(bounds);
+ wm::ConvertRectFromScreen(window->GetRootWindow(), &root_rect);
ash::wm::ClientControlledState::AdjustBoundsForMinimumWindowVisibility(
- window, &rect);
- wm::ConvertRectToScreen(window->GetRootWindow(), &rect);
-
- if (bounds != rect) {
+ window, &root_rect);
+ gfx::Rect screen_rect(root_rect);
+ wm::ConvertRectToScreen(window->GetRootWindow(), &screen_rect);
+ if (bounds != screen_rect &&
+ !GetWindowState()->IsMaximizedOrFullscreenOrPinned()) {
+ {
+ ScopedSetBoundsLocally scoped_set_bounds(this);
+ window->SetBounds(root_rect);
+ }
// Request the client a new bounds to ensure that it has enough visible
// area.
- window->SetBounds(rect);
+ auto state_type = GetWindowState()->GetStateType();
+ int64_t display_id =
+ display::Screen::GetScreen()
+ ->GetDisplayNearestWindow(window->GetRootWindow())
+ .id();
+ OnBoundsChangeEvent(state_type, state_type, display_id, screen_rect, 0);
} else {
+ // TODO(oshima|domlaskowski): This prevent a client from moving a window
+ // between display. This is ok for now because a user needs to take an
+ // action to move right now. This will be fixed by new API.
+ ScopedLockedToRoot scoped_locked_to_root(widget_);
ScopedSetBoundsLocally scoped_set_bounds(this);
widget_->SetBounds(bounds);
}
@@ -819,6 +871,9 @@ void ClientControlledShellSurface::InitializeWindowState(
frame_view->SetCaptionButtonModel(std::make_unique<CaptionButtonModel>(
frame_visible_button_mask_, frame_enabled_button_mask_));
UpdateAutoHideFrame();
+ UpdateFrameWidth();
+ if (initial_orientation_lock_ != ash::OrientationLockType::kAny)
+ SetOrientationLock(initial_orientation_lock_);
}
float ClientControlledShellSurface::GetScale() const {
@@ -869,18 +924,17 @@ gfx::Rect ClientControlledShellSurface::GetWidgetBounds() const {
// bounds.
if (widget_->IsMaximized())
return GetVisibleBounds();
- else
- return frame_view->GetWindowBoundsForClientBounds(GetVisibleBounds());
- } else {
- gfx::Rect bounds(GetVisibleBounds());
- bounds.Offset(-origin_offset_.x(), -origin_offset_.y());
- return bounds;
+ return frame_view->GetWindowBoundsForClientBounds(GetVisibleBounds());
}
+
+ gfx::Rect bounds(GetVisibleBounds());
+ bounds.Offset(-origin_offset_.x(), -origin_offset_.y());
+ return bounds;
}
gfx::Point ClientControlledShellSurface::GetSurfaceOrigin() const {
DCHECK(resize_component_ == HTCAPTION);
- if (!geometry_changed_callback_.is_null())
+ if (geometry_changed_callback_)
return gfx::Point();
// TODO(oshima): geometry_changed_callback_ must be always set by now, so
// this is not necessary any more. Remove this.
@@ -920,6 +974,7 @@ void ClientControlledShellSurface::UpdateFrame() {
immersive_fullscreen_controller_.get());
UpdateCaptionButtonModel();
}
+ UpdateFrameWidth();
}
// The autohide should be applied when the window state is in
// maximzied, fullscreen or pinned. Update the auto hide state
@@ -951,6 +1006,18 @@ void ClientControlledShellSurface::UpdateBackdrop() {
window->SetProperty(ash::kBackdropWindowMode, target_backdrop_mode);
}
+void ClientControlledShellSurface::UpdateFrameWidth() {
+ int width = -1;
+ if (shadow_bounds_) {
+ float device_scale_factor =
+ GetWidget()->GetNativeWindow()->layer()->device_scale_factor();
+ float dsf_to_default_dsf = device_scale_factor / scale_;
+ width = gfx::ToRoundedInt(shadow_bounds_->width() * dsf_to_default_dsf);
+ }
+ static_cast<ash::HeaderView*>(GetFrameView()->GetHeaderView())
+ ->SetWidthInPixels(width);
+}
+
void ClientControlledShellSurface::
EnsureCompositorIsLockedForOrientationChange() {
if (!orientation_compositor_lock_) {
@@ -980,7 +1047,8 @@ const ash::CustomFrameViewAsh* ClientControlledShellSurface::GetFrameView()
void ClientControlledShellSurface::
SetClientControlledStateDelegateFactoryForTest(
const DelegateFactoryCallback& callback) {
- g_factory_callback = callback;
+ auto& factory = GetFactoryForTesting();
+ factory = callback;
}
} // namespace exo
diff --git a/chromium/components/exo/client_controlled_shell_surface.h b/chromium/components/exo/client_controlled_shell_surface.h
index df90c8e621e..fcc906bdb0b 100644
--- a/chromium/components/exo/client_controlled_shell_surface.h
+++ b/chromium/components/exo/client_controlled_shell_surface.h
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
+#include "ash/display/screen_orientation_controller.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/wm/client_controlled_state.h"
#include "base/callback.h"
@@ -76,6 +77,9 @@ class ClientControlledShellSurface
// Called when the client was snapped to right.
void SetSnappedToRight();
+ // Called when the client was set to PIP.
+ void SetPip();
+
// Set the callback to run when the surface state changed.
using StateChangedCallback =
base::RepeatingCallback<void(ash::mojom::WindowStateType old_state_type,
@@ -171,6 +175,12 @@ class ClientControlledShellSurface
// Set the extra title for the surface.
void SetExtraTitle(const base::string16& extra_title);
+ // Set specific orientation lock for this surface. When this surface is in
+ // foreground and the display can be rotated (e.g. tablet mode), apply the
+ // behavior defined by |orientation_lock|. See more details in
+ // //ash/display/screen_orientation_controller.h.
+ void SetOrientationLock(ash::OrientationLockType orientation_lock);
+
// Overridden from SurfaceDelegate:
void OnSurfaceCommit() override;
bool IsInputEnabled(Surface* surface) const override;
@@ -189,6 +199,7 @@ class ClientControlledShellSurface
// Overridden from views::View:
gfx::Size GetMaximumSize() const override;
+ void OnDeviceScaleFactorChanged(float old_dsf, float new_dsf) override;
// Overridden from aura::WindowObserver:
void OnWindowBoundsChanged(aura::Window* window,
@@ -243,6 +254,8 @@ class ClientControlledShellSurface
void UpdateBackdrop();
+ void UpdateFrameWidth();
+
void AttemptToStartDrag(int component, const gfx::Point& location);
// Lock the compositor if it's not already locked, or extends the
@@ -291,6 +304,11 @@ class ClientControlledShellSurface
std::unique_ptr<ui::CompositorLock> orientation_compositor_lock_;
+ // The orientation to be applied when widget is being created. Only set when
+ // widget is not created yet orientation lock is being set.
+ ash::OrientationLockType initial_orientation_lock_ =
+ ash::OrientationLockType::kAny;
+
DISALLOW_COPY_AND_ASSIGN(ClientControlledShellSurface);
};
diff --git a/chromium/components/exo/client_controlled_shell_surface_unittest.cc b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
index 19f4859cf80..f5075de535f 100644
--- a/chromium/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/chromium/components/exo/client_controlled_shell_surface_unittest.cc
@@ -4,6 +4,7 @@
#include "components/exo/client_controlled_shell_surface.h"
+#include "ash/display/screen_orientation_controller.h"
#include "ash/frame/caption_buttons/caption_button_model.h"
#include "ash/frame/caption_buttons/frame_caption_button_container_view.h"
#include "ash/frame/custom_frame_view_ash.h"
@@ -65,6 +66,11 @@ int GetShadowElevation(aura::Window* window) {
return window->GetProperty(wm::kShadowElevationKey);
}
+void EnableTabletMode(bool enable) {
+ ash::Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
+ enable);
+}
+
} // namespace
TEST_F(ClientControlledShellSurfaceTest, SetPinned) {
@@ -451,7 +457,7 @@ TEST_F(ClientControlledShellSurfaceTest, Frame) {
gfx::Rect client_bounds(20, 50, 300, 200);
gfx::Rect fullscreen_bounds(0, 0, 800, 500);
// The window bounds is the client bounds + frame size.
- gfx::Rect normal_window_bounds(20, 17, 300, 233);
+ gfx::Rect normal_window_bounds(20, 18, 300, 232);
auto shell_surface =
exo_test_helper()->CreateClientControlledShellSurface(surface.get());
@@ -478,7 +484,7 @@ TEST_F(ClientControlledShellSurfaceTest, Frame) {
EXPECT_TRUE(frame_view->visible());
EXPECT_EQ(fullscreen_bounds, widget->GetWindowBoundsInScreen());
EXPECT_EQ(
- gfx::Size(800, 467),
+ gfx::Size(800, 468),
frame_view->GetClientBoundsForWindowBounds(fullscreen_bounds).size());
// AutoHide
@@ -1056,27 +1062,24 @@ TEST_F(ClientControlledShellSurfaceTest, SetExtraTitle) {
surface->Attach(buffer.get());
surface->Commit();
- // NativeWindow's title is used within the overview mode. It should be the
- // specified title, as ShellSurface does. On the other hand, the frame's
- // GetWindowTitle() should return the extra -- showing the debugging info
- // in the title bar but otherwise it should have empty string.
- // See https://crbug.com/831383.
+ // The window title should include the debugging info, if any, and should only
+ // be shown (in the frame) when there is debugging info. See
+ // https://crbug.com/831383.
const aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
- const ash::CustomFrameViewAsh* frame =
- static_cast<const ash::CustomFrameViewAsh*>(
- shell_surface->GetWidget()->non_client_view()->frame_view());
+ const views::WidgetDelegate* widget_delegate =
+ shell_surface->GetWidget()->widget_delegate();
shell_surface->SetExtraTitle(base::ASCIIToUTF16("extra"));
- EXPECT_EQ(base::string16(), window->GetTitle());
- EXPECT_EQ(base::ASCIIToUTF16("extra"), frame->GetFrameTitle());
+ EXPECT_EQ(base::ASCIIToUTF16(" (extra)"), window->GetTitle());
+ EXPECT_TRUE(widget_delegate->ShouldShowWindowTitle());
shell_surface->SetTitle(base::ASCIIToUTF16("title"));
- EXPECT_EQ(base::ASCIIToUTF16("title"), window->GetTitle());
- EXPECT_EQ(base::ASCIIToUTF16("extra"), frame->GetFrameTitle());
+ EXPECT_EQ(base::ASCIIToUTF16("title (extra)"), window->GetTitle());
+ EXPECT_TRUE(widget_delegate->ShouldShowWindowTitle());
shell_surface->SetExtraTitle(base::string16());
EXPECT_EQ(base::ASCIIToUTF16("title"), window->GetTitle());
- EXPECT_EQ(base::string16(), frame->GetFrameTitle());
+ EXPECT_FALSE(widget_delegate->ShouldShowWindowTitle());
}
TEST_F(ClientControlledShellSurfaceTest, WideFrame) {
@@ -1162,4 +1165,64 @@ TEST_F(ClientControlledShellSurfaceTest, MultiDisplay) {
}
}
+// Set orientation lock to a window.
+TEST_F(ClientControlledShellSurfaceTest, SetOrientationLock) {
+ display::test::DisplayManagerTestApi(ash::Shell::Get()->display_manager())
+ .SetFirstDisplayAsInternalDisplay();
+
+ EnableTabletMode(true);
+ ash::ScreenOrientationController* controller =
+ ash::Shell::Get()->screen_orientation_controller();
+
+ gfx::Size buffer_size(256, 256);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ std::unique_ptr<Surface> surface(new Surface);
+
+ auto shell_surface =
+ exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+ surface->Attach(buffer.get());
+ shell_surface->SetMaximized();
+ surface->Commit();
+
+ shell_surface->SetOrientationLock(
+ ash::OrientationLockType::kLandscapePrimary);
+ EXPECT_TRUE(controller->rotation_locked());
+ display::Display display(display::Screen::GetScreen()->GetPrimaryDisplay());
+ gfx::Size displaySize = display.size();
+ EXPECT_GT(displaySize.width(), displaySize.height());
+
+ shell_surface->SetOrientationLock(ash::OrientationLockType::kAny);
+ EXPECT_FALSE(controller->rotation_locked());
+
+ EnableTabletMode(false);
+}
+
+// Tests adjust bounds locally should also request remote client bounds update.
+TEST_F(ClientControlledShellSurfaceTest, AdjustBoundsLocally) {
+ UpdateDisplay("800x600");
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
+ std::unique_ptr<Surface> surface(new Surface);
+ auto shell_surface =
+ exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+ gfx::Rect requested_bounds;
+ shell_surface->set_bounds_changed_callback(base::BindRepeating(
+ [](gfx::Rect* dst, ash::mojom::WindowStateType current_state,
+ ash::mojom::WindowStateType requested_state, int64_t display_id,
+ const gfx::Rect& bounds, bool is_resize,
+ int bounds_change) { *dst = bounds; },
+ base::Unretained(&requested_bounds)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ gfx::Rect client_bounds(900, 0, 200, 300);
+ shell_surface->SetGeometry(client_bounds);
+ surface->Commit();
+
+ views::Widget* widget = shell_surface->GetWidget();
+ EXPECT_EQ(gfx::Rect(774, 0, 200, 300), widget->GetWindowBoundsInScreen());
+ EXPECT_EQ(gfx::Rect(774, 0, 200, 300), requested_bounds);
+}
+
} // namespace exo
diff --git a/chromium/components/exo/display.cc b/chromium/components/exo/display.cc
index 75f46095ab0..ebc4804b37f 100644
--- a/chromium/components/exo/display.cc
+++ b/chromium/components/exo/display.cc
@@ -36,24 +36,6 @@
#endif
namespace exo {
-namespace {
-#if defined(USE_OZONE)
-// TODO(dcastagna): The following formats should be determined at runtime
-// querying kms (via ozone).
-const gfx::BufferFormat kOverlayFormats[] = {
-// TODO(dcastagna): Remove RGBX/RGBA once all the platforms using the fullscreen
-// optimization will have switched to atomic.
-#if defined(ARCH_CPU_ARM_FAMILY)
- gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888,
-#endif
- gfx::BufferFormat::BGRX_8888, gfx::BufferFormat::BGRA_8888};
-
-const gfx::BufferFormat kOverlayFormatsForDrmAtomic[] = {
- gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888,
- gfx::BufferFormat::BGR_565, gfx::BufferFormat::YUV_420_BIPLANAR};
-#endif
-
-} // namespace
////////////////////////////////////////////////////////////////////////////////
// Display, public:
@@ -66,19 +48,10 @@ Display::Display(NotificationSurfaceManager* notification_surface_manager,
file_helper_(std::move(file_helper))
#if defined(USE_OZONE)
,
- overlay_formats_(std::begin(kOverlayFormats), std::end(kOverlayFormats)),
client_native_pixmap_factory_(
gfx::CreateClientNativePixmapFactoryDmabuf())
#endif
{
-#if defined(USE_OZONE)
- if (base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kEnableDrmAtomic)) {
- overlay_formats_.insert(overlay_formats_.end(),
- std::begin(kOverlayFormatsForDrmAtomic),
- std::end(kOverlayFormatsForDrmAtomic));
- }
-#endif
}
Display::~Display() {}
@@ -130,9 +103,7 @@ std::unique_ptr<Buffer> Display::CreateLinuxDMABufBuffer(
// Using zero-copy for optimal performance.
bool use_zero_copy = true;
- bool is_overlay_candidate =
- std::find(overlay_formats_.begin(), overlay_formats_.end(), format) !=
- overlay_formats_.end();
+ bool is_overlay_candidate = true;
return std::make_unique<Buffer>(
std::move(gpu_memory_buffer), GL_TEXTURE_EXTERNAL_OES,
diff --git a/chromium/components/exo/display.h b/chromium/components/exo/display.h
index 0f5e792d771..25a3bfffc56 100644
--- a/chromium/components/exo/display.h
+++ b/chromium/components/exo/display.h
@@ -105,7 +105,6 @@ class Display {
Seat seat_;
#if defined(USE_OZONE)
- std::vector<gfx::BufferFormat> overlay_formats_;
std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_;
#endif
diff --git a/chromium/components/exo/keyboard.cc b/chromium/components/exo/keyboard.cc
index 0f9626f7579..2d3b14a5300 100644
--- a/chromium/components/exo/keyboard.cc
+++ b/chromium/components/exo/keyboard.cc
@@ -214,60 +214,62 @@ void Keyboard::AckKeyboardKey(uint32_t serial, bool handled) {
// ui::EventHandler overrides:
void Keyboard::OnKeyEvent(ui::KeyEvent* event) {
+ if (!focus_)
+ return;
+
// Process reserved accelerators before sending it to client.
- if (focus_ && ProcessAcceleratorIfReserved(focus_, event)) {
+ if (ProcessAcceleratorIfReserved(focus_, event)) {
// Discard a key press event if it's a reserved accelerator and it's
// enabled.
event->SetHandled();
- // Send leave/enter event instead of key event, so the client can know the
- // actual state of the keyboard.
- SetFocus(focus_);
- return;
}
// When IME ate a key event, we use the event only for tracking key states and
// ignore for further processing. Otherwise it is handled in two places (IME
// and client) and causes undesired behavior.
- bool consumed_by_ime = focus_ ? ConsumedByIme(focus_, event) : false;
+ bool consumed_by_ime = ConsumedByIme(focus_, event);
- if (focus_ && !consumed_by_ime && !event->handled()) {
- int modifier_flags = event->flags() & kModifierMask;
- if (modifier_flags != modifier_flags_) {
- modifier_flags_ = modifier_flags;
- delegate_->OnKeyboardModifiers(modifier_flags_);
- }
+ // Always update modifiers.
+ int modifier_flags = event->flags() & kModifierMask;
+ if (modifier_flags != modifier_flags_) {
+ modifier_flags_ = modifier_flags;
+ delegate_->OnKeyboardModifiers(modifier_flags_);
+ }
- switch (event->type()) {
- case ui::ET_KEY_PRESSED:
- if (pressed_keys_.insert(event->code()).second) {
- uint32_t serial = delegate_->OnKeyboardKey(event->time_stamp(),
- event->code(), true);
- if (are_keyboard_key_acks_needed_) {
- pending_key_acks_.insert(
- {serial,
- {*event, base::TimeTicks::Now() +
- expiration_delay_for_pending_key_acks_}});
- event->SetHandled();
- }
+ switch (event->type()) {
+ case ui::ET_KEY_PRESSED:
+ // Process key press event if not already handled and not
+ // already pressed.
+ if (!consumed_by_ime && !event->handled() &&
+ pressed_keys_.insert(event->code()).second) {
+ uint32_t serial =
+ delegate_->OnKeyboardKey(event->time_stamp(), event->code(), true);
+ if (are_keyboard_key_acks_needed_) {
+ pending_key_acks_.insert(
+ {serial,
+ {*event, base::TimeTicks::Now() +
+ expiration_delay_for_pending_key_acks_}});
+ event->SetHandled();
}
- break;
- case ui::ET_KEY_RELEASED:
- if (pressed_keys_.erase(event->code())) {
- uint32_t serial = delegate_->OnKeyboardKey(event->time_stamp(),
- event->code(), false);
- if (are_keyboard_key_acks_needed_) {
- pending_key_acks_.insert(
- {serial,
- {*event, base::TimeTicks::Now() +
- expiration_delay_for_pending_key_acks_}});
- event->SetHandled();
- }
+ }
+ break;
+ case ui::ET_KEY_RELEASED:
+ // Process key release event if currently pressed.
+ if (pressed_keys_.erase(event->code())) {
+ uint32_t serial =
+ delegate_->OnKeyboardKey(event->time_stamp(), event->code(), false);
+ if (are_keyboard_key_acks_needed_) {
+ pending_key_acks_.insert(
+ {serial,
+ {*event, base::TimeTicks::Now() +
+ expiration_delay_for_pending_key_acks_}});
+ event->SetHandled();
}
- break;
- default:
- NOTREACHED();
- break;
- }
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
}
if (pending_key_acks_.empty())
diff --git a/chromium/components/exo/keyboard_unittest.cc b/chromium/components/exo/keyboard_unittest.cc
index 9d52ba09d5c..da22538c409 100644
--- a/chromium/components/exo/keyboard_unittest.cc
+++ b/chromium/components/exo/keyboard_unittest.cc
@@ -189,10 +189,28 @@ TEST_F(KeyboardTest, OnKeyboardKey) {
// This should not generate another press event for KEY_A.
generator.PressKey(ui::VKEY_A, 0);
- // This should only generate a release event for KEY_A.
+ // This should only generate a single release event for KEY_A.
EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_A, false));
generator.ReleaseKey(ui::VKEY_A, 0);
+ // Press accelerator after surface lost focus.
+ EXPECT_CALL(delegate, OnKeyboardLeave(surface.get()));
+ focus_client->FocusWindow(nullptr);
+ generator.PressKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
+
+ // Key should be pressed when focus returns.
+ EXPECT_CALL(delegate, CanAcceptKeyboardEventsForSurface(surface.get()))
+ .WillOnce(testing::Return(true));
+ EXPECT_CALL(delegate, OnKeyboardModifiers(ui::EF_CONTROL_DOWN));
+ EXPECT_CALL(delegate, OnKeyboardEnter(
+ surface.get(),
+ base::flat_set<ui::DomCode>({ui::DomCode::US_W})));
+ focus_client->FocusWindow(surface->window());
+
+ // Releasing accelerator when surface has focus should generate event.
+ EXPECT_CALL(delegate, OnKeyboardKey(testing::_, ui::DomCode::US_W, false));
+ generator.ReleaseKey(ui::VKEY_W, ui::EF_CONTROL_DOWN);
+
keyboard.reset();
}
diff --git a/chromium/components/exo/layer_tree_frame_sink_holder.cc b/chromium/components/exo/layer_tree_frame_sink_holder.cc
index 7da7e8bb24a..b9b95363e1f 100644
--- a/chromium/components/exo/layer_tree_frame_sink_holder.cc
+++ b/chromium/components/exo/layer_tree_frame_sink_holder.cc
@@ -8,6 +8,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "components/exo/surface_tree_host.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/resources/returned_resource.h"
namespace exo {
@@ -119,6 +120,11 @@ void LayerTreeFrameSinkHolder::SetBeginFrameSource(
surface_tree_host_->SetBeginFrameSource(source);
}
+base::Optional<viz::HitTestRegionList>
+LayerTreeFrameSinkHolder::BuildHitTestData() {
+ return {};
+}
+
void LayerTreeFrameSinkHolder::ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) {
for (auto& resource : resources) {
diff --git a/chromium/components/exo/layer_tree_frame_sink_holder.h b/chromium/components/exo/layer_tree_frame_sink_holder.h
index a2109f7b34e..4ffc4d49de8 100644
--- a/chromium/components/exo/layer_tree_frame_sink_holder.h
+++ b/chromium/components/exo/layer_tree_frame_sink_holder.h
@@ -51,6 +51,7 @@ class LayerTreeFrameSinkHolder : public cc::LayerTreeFrameSinkClient,
// Overridden from cc::LayerTreeFrameSinkClient:
void SetBeginFrameSource(viz::BeginFrameSource* source) override;
+ base::Optional<viz::HitTestRegionList> BuildHitTestData() override;
void ReclaimResources(
const std::vector<viz::ReturnedResource>& resources) override;
void SetTreeActivationCallback(const base::Closure& callback) override {}
diff --git a/chromium/components/exo/notification_surface.cc b/chromium/components/exo/notification_surface.cc
index 17ae6b18039..6c3209a5e28 100644
--- a/chromium/components/exo/notification_surface.cc
+++ b/chromium/components/exo/notification_surface.cc
@@ -5,6 +5,7 @@
#include "components/exo/notification_surface.h"
#include "components/exo/notification_surface_manager.h"
+#include "components/exo/shell_surface.h"
#include "components/exo/surface.h"
#include "ui/aura/window.h"
#include "ui/gfx/geometry/rect.h"
@@ -33,6 +34,11 @@ const gfx::Size& NotificationSurface::GetContentSize() const {
return root_surface()->content_size();
}
+void NotificationSurface::SetApplicationId(const char* application_id) {
+ exo::ShellSurface::SetApplicationId(host_window(),
+ base::make_optional(application_id));
+}
+
void NotificationSurface::OnSurfaceCommit() {
SurfaceTreeHost::OnSurfaceCommit();
diff --git a/chromium/components/exo/notification_surface.h b/chromium/components/exo/notification_surface.h
index a202ba630bd..2544e40c4d0 100644
--- a/chromium/components/exo/notification_surface.h
+++ b/chromium/components/exo/notification_surface.h
@@ -28,6 +28,8 @@ class NotificationSurface : public SurfaceTreeHost, public SurfaceObserver {
// Get the content size of the |root_surface()|.
const gfx::Size& GetContentSize() const;
+ void SetApplicationId(const char* application_id);
+
const std::string& notification_key() const { return notification_key_; }
// Overridden from SurfaceDelegate:
diff --git a/chromium/components/exo/pointer.cc b/chromium/components/exo/pointer.cc
index 5df27aa527f..6b6fd69fac4 100644
--- a/chromium/components/exo/pointer.cc
+++ b/chromium/components/exo/pointer.cc
@@ -88,7 +88,11 @@ Pointer::Pointer(PointerDelegate* delegate)
auto* helper = WMHelper::GetInstance();
helper->AddPreTargetHandler(this);
helper->AddDisplayConfigurationObserver(this);
- helper->GetCursorClient()->AddObserver(this);
+ // TODO(sky): CursorClient does not exist in mash
+ // yet. https://crbug.com/631103.
+ aura::client::CursorClient* cursor_client = helper->GetCursorClient();
+ if (cursor_client)
+ cursor_client->AddObserver(this);
}
Pointer::~Pointer() {
@@ -101,7 +105,11 @@ Pointer::~Pointer() {
auto* helper = WMHelper::GetInstance();
helper->RemoveDisplayConfigurationObserver(this);
helper->RemovePreTargetHandler(this);
- helper->GetCursorClient()->RemoveObserver(this);
+ // TODO(sky): CursorClient does not exist in mash
+ // yet. https://crbug.com/631103.
+ aura::client::CursorClient* cursor_client = helper->GetCursorClient();
+ if (cursor_client)
+ cursor_client->RemoveObserver(this);
if (root_surface())
root_surface()->RemoveSurfaceObserver(this);
}
@@ -123,9 +131,11 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
}
UpdatePointerSurface(surface);
cursor_changed = true;
+ } else if (!surface && cursor_ != ui::CursorType::kNone) {
+ cursor_changed = true;
}
- if (hotspot != cursor_hotspot_) {
+ if (hotspot != hotspot_) {
hotspot_ = hotspot;
cursor_changed = true;
}
@@ -138,14 +148,26 @@ void Pointer::SetCursor(Surface* surface, const gfx::Point& hotspot) {
// snapshot of cursor, otherwise cancel pending capture and immediately set
// the cursor to "none".
if (root_surface()) {
+ cursor_ = ui::CursorType::kCustom;
CaptureCursor(hotspot);
} else {
+ cursor_ = ui::CursorType::kNone;
cursor_bitmap_.reset();
cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
UpdateCursor();
}
}
+void Pointer::SetCursorType(ui::CursorType cursor_type) {
+ if (cursor_ == cursor_type)
+ return;
+ cursor_ = cursor_type;
+ cursor_bitmap_.reset();
+ UpdatePointerSurface(nullptr);
+ cursor_capture_weak_ptr_factory_.InvalidateWeakPtrs();
+ UpdateCursor();
+}
+
void Pointer::SetGesturePinchDelegate(PointerGesturePinchDelegate* delegate) {
pinch_delegate_ = delegate;
}
@@ -438,9 +460,7 @@ void Pointer::UpdateCursor() {
auto* helper = WMHelper::GetInstance();
aura::client::CursorClient* cursor_client = helper->GetCursorClient();
- if (cursor_bitmap_.drawsNothing()) {
- cursor_ = ui::CursorType::kNone;
- } else {
+ if (cursor_ == ui::CursorType::kCustom) {
SkBitmap bitmap = cursor_bitmap_;
gfx::Point hotspot =
gfx::ScaleToFlooredPoint(cursor_hotspot_, capture_ratio_);
@@ -460,15 +480,17 @@ void Pointer::UpdateCursor() {
ui::PlatformCursor platform_cursor;
#if defined(USE_OZONE)
// TODO(reveman): Add interface for creating cursors from GpuMemoryBuffers
- // and use that here instead of the current bitmap API. crbug.com/686600
+ // and use that here instead of the current bitmap API.
+ // https://crbug.com/686600
platform_cursor = ui::CursorFactoryOzone::GetInstance()->CreateImageCursor(
bitmap, hotspot, 0);
#elif defined(USE_X11)
XcursorImage* image = ui::SkBitmapToXcursorImage(&bitmap, hotspot);
platform_cursor = ui::CreateReffedCustomXCursor(image);
#endif
- cursor_ = ui::CursorType::kCustom;
cursor_.SetPlatformCursor(platform_cursor);
+ cursor_.set_custom_bitmap(bitmap);
+ cursor_.set_custom_hotspot(hotspot);
#if defined(USE_OZONE)
ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
#elif defined(USE_X11)
diff --git a/chromium/components/exo/pointer.h b/chromium/components/exo/pointer.h
index e4766e4a635..a5dd5c88ac4 100644
--- a/chromium/components/exo/pointer.h
+++ b/chromium/components/exo/pointer.h
@@ -57,6 +57,10 @@ class Pointer : public SurfaceTreeHost,
// pointer location, in surface local coordinates.
void SetCursor(Surface* surface, const gfx::Point& hotspot);
+ // Set the pointer cursor type. This is similar to SetCursor, but this method
+ // accepts ui::CursorType instead of the surface for the pointer image.
+ void SetCursorType(ui::CursorType cursor_type);
+
// Set delegate for pinch events.
void SetGesturePinchDelegate(PointerGesturePinchDelegate* delegate);
diff --git a/chromium/components/exo/pointer_unittest.cc b/chromium/components/exo/pointer_unittest.cc
index 5b81adc18e3..00a3a0d9e50 100644
--- a/chromium/components/exo/pointer_unittest.cc
+++ b/chromium/components/exo/pointer_unittest.cc
@@ -18,9 +18,11 @@
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface.h"
#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/aura/client/cursor_client.h"
#include "ui/aura/env.h"
#include "ui/events/event_utils.h"
#include "ui/events/test/event_generator.h"
+#include "ui/views/widget/widget.h"
namespace exo {
namespace {
@@ -70,9 +72,10 @@ TEST_F(PointerTest, SetCursor) {
pointer_surface->Commit();
// Set pointer surface.
- pointer->SetCursor(pointer_surface.get(), gfx::Point());
+ pointer->SetCursor(pointer_surface.get(), gfx::Point(5, 5));
RunAllPendingInMessageLoop();
+ const viz::RenderPass* last_render_pass;
{
viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
@@ -84,10 +87,25 @@ TEST_F(PointerTest, SetCursor) {
surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
frame.render_pass_list.back()->output_rect);
+ last_render_pass = frame.render_pass_list.back().get();
}
// Adjust hotspot.
- pointer->SetCursor(pointer_surface.get(), gfx::Point(1, 1));
+ pointer->SetCursor(pointer_surface.get(), gfx::Point());
+ RunAllPendingInMessageLoop();
+
+ // Verify that adjustment to hotspot resulted in new frame.
+ {
+ viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
+ viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
+ ->context_factory_private()
+ ->GetFrameSinkManager()
+ ->surface_manager();
+ ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
+ const viz::CompositorFrame& frame =
+ surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
+ EXPECT_TRUE(frame.render_pass_list.back().get() != last_render_pass);
+ }
// Unset pointer surface.
pointer->SetCursor(nullptr, gfx::Point());
@@ -96,6 +114,210 @@ TEST_F(PointerTest, SetCursor) {
pointer.reset();
}
+TEST_F(PointerTest, SetCursorNull) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ MockPointerDelegate delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
+ EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
+ generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+
+ pointer->SetCursor(nullptr, gfx::Point());
+ RunAllPendingInMessageLoop();
+
+ EXPECT_EQ(nullptr, pointer->root_surface());
+ aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
+ shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
+ EXPECT_EQ(ui::CursorType::kNone, cursor_client->GetCursor().native_type());
+
+ EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+
+TEST_F(PointerTest, SetCursorType) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ MockPointerDelegate delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
+ EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
+ generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+
+ pointer->SetCursorType(ui::CursorType::kIBeam);
+ RunAllPendingInMessageLoop();
+
+ EXPECT_EQ(nullptr, pointer->root_surface());
+ aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
+ shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
+ EXPECT_EQ(ui::CursorType::kIBeam, cursor_client->GetCursor().native_type());
+
+ // Set the pointer with surface after setting pointer type.
+ std::unique_ptr<Surface> pointer_surface(new Surface);
+ std::unique_ptr<Buffer> pointer_buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ pointer_surface->Attach(pointer_buffer.get());
+ pointer_surface->Commit();
+
+ pointer->SetCursor(pointer_surface.get(), gfx::Point());
+ RunAllPendingInMessageLoop();
+
+ {
+ viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
+ viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
+ ->context_factory_private()
+ ->GetFrameSinkManager()
+ ->surface_manager();
+ ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
+ const viz::CompositorFrame& frame =
+ surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
+ frame.render_pass_list.back()->output_rect);
+ }
+
+ // Set the pointer type after the pointer surface is specified.
+ pointer->SetCursorType(ui::CursorType::kCross);
+ RunAllPendingInMessageLoop();
+
+ EXPECT_EQ(nullptr, pointer->root_surface());
+ EXPECT_EQ(ui::CursorType::kCross, cursor_client->GetCursor().native_type());
+
+ EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+
+TEST_F(PointerTest, SetCursorAndSetCursorType) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ MockPointerDelegate delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
+ EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
+ generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+
+ std::unique_ptr<Surface> pointer_surface(new Surface);
+ std::unique_ptr<Buffer> pointer_buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ pointer_surface->Attach(pointer_buffer.get());
+ pointer_surface->Commit();
+
+ // Set pointer surface.
+ pointer->SetCursor(pointer_surface.get(), gfx::Point());
+ RunAllPendingInMessageLoop();
+
+ {
+ viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
+ viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
+ ->context_factory_private()
+ ->GetFrameSinkManager()
+ ->surface_manager();
+ ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
+ const viz::CompositorFrame& frame =
+ surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
+ frame.render_pass_list.back()->output_rect);
+ }
+
+ // Set the cursor type to the kNone through SetCursorType.
+ pointer->SetCursorType(ui::CursorType::kNone);
+ RunAllPendingInMessageLoop();
+ EXPECT_EQ(nullptr, pointer->root_surface());
+
+ // Set the same pointer surface again.
+ pointer->SetCursor(pointer_surface.get(), gfx::Point());
+ RunAllPendingInMessageLoop();
+
+ {
+ viz::SurfaceId surface_id = pointer->host_window()->GetSurfaceId();
+ viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
+ ->context_factory_private()
+ ->GetFrameSinkManager()
+ ->surface_manager();
+ ASSERT_TRUE(surface_manager->GetSurfaceForId(surface_id)->HasActiveFrame());
+ const viz::CompositorFrame& frame =
+ surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
+ EXPECT_EQ(gfx::Rect(0, 0, 10, 10),
+ frame.render_pass_list.back()->output_rect);
+ }
+
+ EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+
+TEST_F(PointerTest, SetCursorNullAndSetCursorType) {
+ std::unique_ptr<Surface> surface(new Surface);
+ std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ gfx::Size buffer_size(10, 10);
+ std::unique_ptr<Buffer> buffer(
+ new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
+ surface->Attach(buffer.get());
+ surface->Commit();
+
+ MockPointerDelegate delegate;
+ std::unique_ptr<Pointer> pointer(new Pointer(&delegate));
+ ui::test::EventGenerator generator(ash::Shell::GetPrimaryRootWindow());
+
+ EXPECT_CALL(delegate, CanAcceptPointerEventsForSurface(surface.get()))
+ .WillRepeatedly(testing::Return(true));
+ EXPECT_CALL(delegate, OnPointerFrame()).Times(1);
+ EXPECT_CALL(delegate, OnPointerEnter(surface.get(), gfx::PointF(), 0));
+ generator.MoveMouseTo(surface->window()->GetBoundsInScreen().origin());
+
+ // Set nullptr surface.
+ pointer->SetCursor(nullptr, gfx::Point());
+ RunAllPendingInMessageLoop();
+
+ EXPECT_EQ(nullptr, pointer->root_surface());
+ aura::client::CursorClient* cursor_client = aura::client::GetCursorClient(
+ shell_surface->GetWidget()->GetNativeWindow()->GetRootWindow());
+ EXPECT_EQ(ui::CursorType::kNone, cursor_client->GetCursor().native_type());
+
+ // Set the cursor type.
+ pointer->SetCursorType(ui::CursorType::kIBeam);
+ RunAllPendingInMessageLoop();
+ EXPECT_EQ(nullptr, pointer->root_surface());
+ EXPECT_EQ(ui::CursorType::kIBeam, cursor_client->GetCursor().native_type());
+
+ // Set nullptr surface again.
+ pointer->SetCursor(nullptr, gfx::Point());
+ RunAllPendingInMessageLoop();
+ EXPECT_EQ(nullptr, pointer->root_surface());
+ EXPECT_EQ(ui::CursorType::kNone, cursor_client->GetCursor().native_type());
+
+ EXPECT_CALL(delegate, OnPointerDestroying(pointer.get()));
+ pointer.reset();
+}
+
TEST_F(PointerTest, OnPointerEnter) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
diff --git a/chromium/components/exo/shell_surface_base.cc b/chromium/components/exo/shell_surface_base.cc
index 7321eed5a74..e3d8a7ea15e 100644
--- a/chromium/components/exo/shell_surface_base.cc
+++ b/chromium/components/exo/shell_surface_base.cc
@@ -7,11 +7,13 @@
#include <algorithm>
#include "ash/frame/custom_frame_view_ash.h"
+#include "ash/public/cpp/config.h"
#include "ash/public/cpp/shelf_types.h"
#include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/cpp/window_properties.h"
#include "ash/public/cpp/window_state_type.h"
#include "ash/public/interfaces/window_pin_type.mojom.h"
+#include "ash/shell.h"
#include "ash/wm/drag_window_resizer.h"
#include "ash/wm/window_resizer.h"
#include "ash/wm/window_state.h"
@@ -82,9 +84,6 @@ class ShellSurfaceWidget : public views::Widget {
if (GetFocusManager()->ProcessAccelerator(ui::Accelerator(*event)))
event->SetHandled();
}
- gfx::Size GetMinimumSize() const override {
- return shell_surface_->GetMinimumSize();
- }
private:
ShellSurfaceBase* const shell_surface_;
@@ -97,9 +96,11 @@ class CustomFrameView : public ash::CustomFrameViewAsh {
using ShapeRects = std::vector<gfx::Rect>;
CustomFrameView(views::Widget* widget,
+ ShellSurfaceBase* shell_surface,
bool enabled,
bool client_controlled_move_resize)
: CustomFrameViewAsh(widget),
+ shell_surface_(shell_surface),
client_controlled_move_resize_(client_controlled_move_resize) {
SetEnabled(enabled);
SetVisible(enabled);
@@ -110,10 +111,6 @@ class CustomFrameView : public ash::CustomFrameViewAsh {
~CustomFrameView() override {}
// Overridden from ash::CustomFrameViewAsh:
- base::string16 GetFrameTitle() const override {
- return static_cast<ShellSurfaceBase*>(GetWidget()->widget_delegate())
- ->frame_title();
- }
void SetShouldPaintHeader(bool paint) override {
if (visible()) {
CustomFrameViewAsh::SetShouldPaintHeader(paint);
@@ -196,11 +193,17 @@ class CustomFrameView : public ash::CustomFrameViewAsh {
return ash::CustomFrameViewAsh::SizeConstraintsChanged();
}
gfx::Size GetMinimumSize() const override {
- return static_cast<const ShellSurfaceWidget*>(GetWidget())
- ->GetMinimumSize();
+ gfx::Size minimum_size = shell_surface_->GetMinimumSize();
+ if (visible()) {
+ return ash::CustomFrameViewAsh::GetWindowBoundsForClientBounds(
+ gfx::Rect(minimum_size))
+ .size();
+ }
+ return minimum_size;
}
private:
+ ShellSurfaceBase* const shell_surface_;
// TODO(oshima): Remove this once the transition to new drag/resize
// is complete. https://crbug.com/801666.
const bool client_controlled_move_resize_;
@@ -900,11 +903,22 @@ bool ShellSurfaceBase::CanMaximize() const {
}
bool ShellSurfaceBase::CanMinimize() const {
- return can_minimize_;
+ // Non-transient shell surfaces can be minimized.
+ return !parent_ && can_minimize_;
}
base::string16 ShellSurfaceBase::GetWindowTitle() const {
- return title_;
+ if (extra_title_.empty())
+ return title_;
+
+ // TODO(estade): revisit how the extra title is shown in the window frame and
+ // other surfaces like overview mode.
+ return title_ + base::ASCIIToUTF16(" (") + extra_title_ +
+ base::ASCIIToUTF16(")");
+}
+
+bool ShellSurfaceBase::ShouldShowWindowTitle() const {
+ return !extra_title_.empty();
}
gfx::ImageSkia ShellSurfaceBase::GetWindowIcon() {
@@ -940,7 +954,7 @@ views::NonClientFrameView* ShellSurfaceBase::CreateNonClientFrameView(
window_state->SetDelegate(std::make_unique<CustomWindowStateDelegate>());
}
CustomFrameView* frame_view = new CustomFrameView(
- widget, frame_enabled(), client_controlled_move_resize_);
+ widget, this, frame_enabled(), client_controlled_move_resize_);
if (has_frame_colors_)
frame_view->SetFrameColors(active_frame_color_, inactive_frame_color_);
return frame_view;
@@ -1197,10 +1211,13 @@ void ShellSurfaceBase::CreateShellSurfaceWidget(
window->SetProperty(aura::client::kAccessibilityFocusFallsbackToWidgetKey,
false);
window->AddChild(host_window());
- // The window of widget_ is a container window. It doesn't handle pointer
- // events.
+ // Use DESCENDANTS_ONLY event targeting policy for mus/mash.
+ // TODO(https://crbug.com/839521): Revisit after event dispatching code is
+ // changed for mus/mash.
window->SetEventTargetingPolicy(
- ui::mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
+ ash::Shell::GetAshConfig() == ash::Config::CLASSIC
+ ? ui::mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS
+ : ui::mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
window->SetEventTargeter(base::WrapUnique(
new CustomWindowTargeter(widget_, client_controlled_move_resize_)));
SetApplicationId(window, application_id_);
diff --git a/chromium/components/exo/shell_surface_base.h b/chromium/components/exo/shell_surface_base.h
index 498e47cff21..64b6489f0d3 100644
--- a/chromium/components/exo/shell_surface_base.h
+++ b/chromium/components/exo/shell_surface_base.h
@@ -103,8 +103,6 @@ class ShellSurfaceBase : public SurfaceTreeHost,
// Set title for the surface.
void SetTitle(const base::string16& title);
- const base::string16& frame_title() const { return frame_title_; }
-
// Set icon for the surface.
void SetIcon(const gfx::ImageSkia& icon);
@@ -188,6 +186,7 @@ class ShellSurfaceBase : public SurfaceTreeHost,
bool CanMaximize() const override;
bool CanMinimize() const override;
base::string16 GetWindowTitle() const override;
+ bool ShouldShowWindowTitle() const override;
gfx::ImageSkia GetWindowIcon() override;
void WindowClosing() override;
views::Widget* GetWidget() override;
@@ -311,8 +310,8 @@ class ShellSurfaceBase : public SurfaceTreeHost,
bool shadow_bounds_changed_ = false;
std::unique_ptr<ash::WindowResizer> resizer_;
base::string16 title_;
- // The title string shown in the window frame (title bar).
- base::string16 frame_title_;
+ // The debug title string shown in the window frame (title bar).
+ base::string16 extra_title_;
std::unique_ptr<ui::CompositorLock> configure_compositor_lock_;
ConfigureCallback configure_callback_;
// TODO(oshima): Remove this once the transition to new drag/resize
diff --git a/chromium/components/exo/shell_surface_unittest.cc b/chromium/components/exo/shell_surface_unittest.cc
index b9f1ca1f620..79cb6cbe8aa 100644
--- a/chromium/components/exo/shell_surface_unittest.cc
+++ b/chromium/components/exo/shell_surface_unittest.cc
@@ -14,7 +14,6 @@
#include "ash/wm/wm_event.h"
#include "ash/wm/workspace/workspace_window_resizer.h"
#include "ash/wm/workspace_controller_test_api.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "components/exo/buffer.h"
@@ -170,6 +169,8 @@ TEST_F(ShellSurfaceTest, Minimize) {
std::unique_ptr<Surface> surface(new Surface);
std::unique_ptr<ShellSurface> shell_surface(new ShellSurface(surface.get()));
+ EXPECT_TRUE(shell_surface->CanMinimize());
+
// Minimizing can be performed before the surface is committed.
shell_surface->Minimize();
EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized());
@@ -182,8 +183,15 @@ TEST_F(ShellSurfaceTest, Minimize) {
shell_surface->Restore();
EXPECT_FALSE(shell_surface->GetWidget()->IsMinimized());
- shell_surface->Minimize();
- EXPECT_TRUE(shell_surface->GetWidget()->IsMinimized());
+ std::unique_ptr<Surface> child_surface(new Surface);
+ std::unique_ptr<ShellSurface> child_shell_surface(
+ new ShellSurface(child_surface.get()));
+
+ // Transient shell surfaces cannot be minimized.
+ child_surface->SetParent(surface.get(), gfx::Point());
+ child_surface->Attach(buffer.get());
+ child_surface->Commit();
+ EXPECT_FALSE(child_shell_surface->CanMinimize());
}
TEST_F(ShellSurfaceTest, Restore) {
@@ -241,12 +249,9 @@ TEST_F(ShellSurfaceTest, SetTitle) {
// have the specified title.
EXPECT_EQ(base::ASCIIToUTF16("test"),
shell_surface->GetWidget()->GetNativeWindow()->GetTitle());
- const ash::CustomFrameViewAsh* frame =
- static_cast<const ash::CustomFrameViewAsh*>(
- shell_surface->GetWidget()->non_client_view()->frame_view());
- // Frame's title is the string to be shown in the title bar. This should be
- // empty.
- EXPECT_EQ(base::string16(), frame->GetFrameTitle());
+ // The titlebar shouldn't show the title.
+ EXPECT_FALSE(
+ shell_surface->GetWidget()->widget_delegate()->ShouldShowWindowTitle());
}
TEST_F(ShellSurfaceTest, SetApplicationId) {
@@ -355,6 +360,15 @@ TEST_F(ShellSurfaceTest, SetMinimumSize) {
->GetNativeWindow()
->delegate()
->GetMinimumSize());
+
+ gfx::Size size_with_frame(50, 82);
+ surface->SetFrame(SurfaceFrameType::NORMAL);
+ EXPECT_EQ(size, shell_surface->GetMinimumSize());
+ EXPECT_EQ(size_with_frame, shell_surface->GetWidget()->GetMinimumSize());
+ EXPECT_EQ(size_with_frame, shell_surface->GetWidget()
+ ->GetNativeWindow()
+ ->delegate()
+ ->GetMinimumSize());
}
TEST_F(ShellSurfaceTest, SetMaximumSize) {
diff --git a/chromium/components/exo/surface.cc b/chromium/components/exo/surface.cc
index 560c71666ed..65d24608e12 100644
--- a/chromium/components/exo/surface.cc
+++ b/chromium/components/exo/surface.cc
@@ -576,8 +576,9 @@ void Surface::CommitSurfaceHierarchy(bool synchronized) {
if (state_.input_region) {
hit_test_region_ = *state_.input_region;
hit_test_region_.Intersect(surface_hierarchy_content_bounds_);
- } else
+ } else {
hit_test_region_ = surface_hierarchy_content_bounds_;
+ }
int outset = state_.input_outset;
if (outset > 0) {
@@ -727,7 +728,7 @@ Surface::State::State() {}
Surface::State::~State() = default;
-bool Surface::State::operator==(const State& other) {
+bool Surface::State::operator==(const State& other) const {
return other.opaque_region == opaque_region &&
other.input_region == input_region &&
other.buffer_scale == buffer_scale &&
@@ -843,9 +844,6 @@ void Surface::AppendContentsToFrame(const gfx::Point& origin,
gfx::ConvertRectToPixel(device_scale_factor, damage_rect));
}
- render_pass->output_rect.Union(
- gfx::ConvertRectToPixel(device_scale_factor, output_rect));
-
// Compute the total transformation from post-transform buffer coordinates to
// target coordinates.
SkMatrix viewport_to_target_matrix;
diff --git a/chromium/components/exo/surface.h b/chromium/components/exo/surface.h
index d0874a9e828..4f070a90dab 100644
--- a/chromium/components/exo/surface.h
+++ b/chromium/components/exo/surface.h
@@ -248,8 +248,8 @@ class Surface final : public ui::PropertyHandler {
State();
~State();
- bool operator==(const State& other);
- bool operator!=(const State& other) { return !(*this == other); }
+ bool operator==(const State& other) const;
+ bool operator!=(const State& other) const { return !(*this == other); }
cc::Region opaque_region;
base::Optional<cc::Region> input_region;
diff --git a/chromium/components/exo/surface_tree_host.cc b/chromium/components/exo/surface_tree_host.cc
index 43ec0701af8..2bb0cf3d51c 100644
--- a/chromium/components/exo/surface_tree_host.cc
+++ b/chromium/components/exo/surface_tree_host.cc
@@ -286,10 +286,22 @@ void SurfaceTreeHost::SubmitCompositorFrame() {
frame.render_pass_list.push_back(viz::RenderPass::Create());
const std::unique_ptr<viz::RenderPass>& render_pass =
frame.render_pass_list.back();
+
const int kRenderPassId = 1;
- render_pass->SetNew(kRenderPassId, gfx::Rect(), gfx::Rect(),
- gfx::Transform());
- float device_scale_factor = host_window()->layer()->device_scale_factor();
+ // Compute a temporaly stable (across frames) size for the render pass output
+ // rectangle that is consistent with the window size. It is used to set the
+ // size of the output surface. Note that computing the actual coverage while
+ // building up the render pass can lead to the size being one pixel too large,
+ // especially if the device scale factor has a floating point representation
+ // that requires many bits of precision in the mantissa, due to the coverage
+ // computing an "enclosing" pixel rectangle. This isn't a problem for the
+ // dirty rectangle, so it is updated as part of filling in the render pass.
+ const float device_scale_factor =
+ host_window()->layer()->device_scale_factor();
+ const gfx::Size output_surface_size_in_pixels = gfx::ConvertSizeToPixel(
+ device_scale_factor, host_window_->bounds().size());
+ render_pass->SetNew(kRenderPassId, gfx::Rect(output_surface_size_in_pixels),
+ gfx::Rect(), gfx::Transform());
frame.metadata.device_scale_factor = device_scale_factor;
root_surface_->AppendSurfaceHierarchyContentsToFrame(
root_surface_origin_, device_scale_factor,
diff --git a/chromium/components/exo/wayland/BUILD.gn b/chromium/components/exo/wayland/BUILD.gn
index fdc5eebac3d..0129450b78f 100644
--- a/chromium/components/exo/wayland/BUILD.gn
+++ b/chromium/components/exo/wayland/BUILD.gn
@@ -50,6 +50,7 @@ source_set("wayland") {
"//skia",
"//third_party/wayland:wayland_server",
"//third_party/wayland-protocols:alpha_compositing_protocol",
+ "//third_party/wayland-protocols:cursor_shapes_protocol",
"//third_party/wayland-protocols:gaming_input_protocol",
"//third_party/wayland-protocols:input_timestamps_protocol",
"//third_party/wayland-protocols:keyboard_configuration_protocol",
diff --git a/chromium/components/exo/wayland/protocol/aura-shell.xml b/chromium/components/exo/wayland/protocol/aura-shell.xml
index 443cf28755b..319d1b218d7 100644
--- a/chromium/components/exo/wayland/protocol/aura-shell.xml
+++ b/chromium/components/exo/wayland/protocol/aura-shell.xml
@@ -24,7 +24,7 @@
DEALINGS IN THE SOFTWARE.
</copyright>
- <interface name="zaura_shell" version="5">
+ <interface name="zaura_shell" version="6">
<description summary="aura_shell">
The global interface exposing aura shell capabilities is used to
instantiate an interface extension for a wl_surface object.
@@ -131,7 +131,7 @@
</request>
</interface>
- <interface name="zaura_output" version="5">
+ <interface name="zaura_output" version="6">
<description summary="aura shell interface to a wl_output">
An additional interface to a wl_output object, which allows the
client to access aura shell specific functionality for output.
diff --git a/chromium/components/exo/wayland/public/aura-shell-protocol.c b/chromium/components/exo/wayland/public/aura-shell-protocol.c
index 214ac7b14d8..1adc9170543 100644
--- a/chromium/components/exo/wayland/public/aura-shell-protocol.c
+++ b/chromium/components/exo/wayland/public/aura-shell-protocol.c
@@ -50,7 +50,7 @@ static const struct wl_message zaura_shell_requests[] = {
};
WL_EXPORT const struct wl_interface zaura_shell_interface = {
- "zaura_shell", 5,
+ "zaura_shell", 6,
2, zaura_shell_requests,
0, NULL,
};
@@ -76,7 +76,7 @@ static const struct wl_message zaura_output_events[] = {
};
WL_EXPORT const struct wl_interface zaura_output_interface = {
- "zaura_output", 5,
+ "zaura_output", 6,
0, NULL,
3, zaura_output_events,
};
diff --git a/chromium/components/exo/wayland/server.cc b/chromium/components/exo/wayland/server.cc
index 27a2a1b231e..49bb13341a5 100644
--- a/chromium/components/exo/wayland/server.cc
+++ b/chromium/components/exo/wayland/server.cc
@@ -6,6 +6,7 @@
#include <alpha-compositing-unstable-v1-server-protocol.h>
#include <aura-shell-server-protocol.h>
+#include <cursor-shapes-unstable-v1-server-protocol.h>
#include <gaming-input-unstable-v1-server-protocol.h>
#include <gaming-input-unstable-v2-server-protocol.h>
#include <grp.h>
@@ -36,6 +37,7 @@
#include <utility>
#include <vector>
+#include "ash/display/screen_orientation_controller.h"
#include "ash/frame/caption_buttons/caption_button_types.h"
#include "ash/ime/ime_controller.h"
#include "ash/public/cpp/shell_window_ids.h"
@@ -52,7 +54,6 @@
#include "base/memory/free_deleter.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -95,7 +96,7 @@
#include "ui/base/ui_features.h"
#include "ui/compositor/compositor_vsync_manager.h"
#include "ui/display/display_switches.h"
-#include "ui/display/manager/chromeos/display_util.h"
+#include "ui/display/manager/display_util.h"
#include "ui/display/manager/managed_display_info.h"
#include "ui/display/screen.h"
#include "ui/events/keycodes/dom/keycode_converter.h"
@@ -1854,6 +1855,7 @@ void xdg_surface_v6_get_toplevel(wl_client* client,
return;
}
+ shell_surface->SetCanMinimize(true);
shell_surface->SetEnabled(true);
wl_resource* xdg_toplevel_resource =
@@ -2262,6 +2264,40 @@ void remote_surface_set_extra_title(wl_client* client,
base::string16(base::UTF8ToUTF16(extra_title)));
}
+ash::OrientationLockType OrientationLock(uint32_t orientation_lock) {
+ switch (orientation_lock) {
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_NONE:
+ return ash::OrientationLockType::kAny;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_CURRENT:
+ return ash::OrientationLockType::kCurrent;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT:
+ return ash::OrientationLockType::kPortrait;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE:
+ return ash::OrientationLockType::kLandscape;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT_PRIMARY:
+ return ash::OrientationLockType::kPortraitPrimary;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_PORTRAIT_SECONDARY:
+ return ash::OrientationLockType::kPortraitSecondary;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE_PRIMARY:
+ return ash::OrientationLockType::kLandscapePrimary;
+ case ZCR_REMOTE_SURFACE_V1_ORIENTATION_LOCK_LANDSCAPE_SECONDARY:
+ return ash::OrientationLockType::kLandscapeSecondary;
+ }
+ VLOG(2) << "Unexpected value of orientation_lock: " << orientation_lock;
+ return ash::OrientationLockType::kAny;
+}
+
+void remote_surface_set_orientation_lock(wl_client* client,
+ wl_resource* resource,
+ uint32_t orientation_lock) {
+ GetUserDataAs<ClientControlledShellSurface>(resource)->SetOrientationLock(
+ OrientationLock(orientation_lock));
+}
+
+void remote_surface_pip(wl_client* client, wl_resource* resource) {
+ GetUserDataAs<ClientControlledShellSurface>(resource)->SetPip();
+}
+
const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
remote_surface_destroy,
remote_surface_set_app_id,
@@ -2301,7 +2337,9 @@ const struct zcr_remote_surface_v1_interface remote_surface_implementation = {
remote_surface_start_resize,
remote_surface_set_frame,
remote_surface_set_frame_buttons,
- remote_surface_set_extra_title};
+ remote_surface_set_extra_title,
+ remote_surface_set_orientation_lock,
+ remote_surface_pip};
////////////////////////////////////////////////////////////////////////////////
// notification_surface_interface:
@@ -2310,8 +2348,15 @@ void notification_surface_destroy(wl_client* client, wl_resource* resource) {
wl_resource_destroy(resource);
}
+void notification_surface_set_app_id(wl_client* client,
+ wl_resource* resource,
+ const char* app_id) {
+ GetUserDataAs<NotificationSurface>(resource)->SetApplicationId(app_id);
+}
+
const struct zcr_notification_surface_v1_interface
- notification_surface_implementation = {notification_surface_destroy};
+ notification_surface_implementation = {notification_surface_destroy,
+ notification_surface_set_app_id};
////////////////////////////////////////////////////////////////////////////////
// remote_shell_interface:
@@ -2562,6 +2607,9 @@ void HandleRemoteSurfaceStateChangedCallback(
case ash::mojom::WindowStateType::RIGHT_SNAPPED:
state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_RIGHT_SNAPPED;
break;
+ case ash::mojom::WindowStateType::PIP:
+ state_type = ZCR_REMOTE_SHELL_V1_STATE_TYPE_PIP;
+ break;
default:
break;
}
@@ -2728,7 +2776,7 @@ const struct zcr_remote_shell_v1_interface remote_shell_implementation = {
remote_shell_destroy, remote_shell_get_remote_surface,
remote_shell_get_notification_surface};
-const uint32_t remote_shell_version = 13;
+const uint32_t remote_shell_version = 16;
void bind_remote_shell(wl_client* client,
void* data,
@@ -2875,12 +2923,18 @@ class AuraOutput : public WaylandDisplayObserver::ScaleObserver {
const int32_t current_output_scale =
std::round(display_info.zoom_factor() * 1000.f);
for (double zoom_factor : display::GetDisplayZoomFactors(active_mode)) {
- const int32_t output_scale = std::round(zoom_factor * 1000.0);
+ int32_t output_scale = std::round(zoom_factor * 1000.0);
uint32_t flags = 0;
if (output_scale == 1000)
flags |= ZAURA_OUTPUT_SCALE_PROPERTY_PREFERRED;
if (current_output_scale == output_scale)
flags |= ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT;
+
+ // TODO(malaykeshav): This can be removed in the future when client
+ // has been updated.
+ if (wl_resource_get_version(resource_) < 6)
+ output_scale = std::round(1000.0 / zoom_factor);
+
zaura_output_send_scale(resource_, flags, output_scale);
}
} else if (display_manager->GetDisplayIdForUIScaling() == display.id()) {
@@ -2895,7 +2949,13 @@ class AuraOutput : public WaylandDisplayObserver::ScaleObserver {
if (active_mode.IsEquivalent(mode))
flags |= ZAURA_OUTPUT_SCALE_PROPERTY_CURRENT;
- zaura_output_send_scale(resource_, flags, mode.ui_scale() * 1000);
+ int32_t output_scale = std::round(mode.ui_scale() * 1000.f);
+ // TODO(malaykeshav): This can be removed in the future when client
+ // has been updated.
+ if (wl_resource_get_version(resource_) >= 6)
+ output_scale = std::round(1000.f / mode.ui_scale());
+
+ zaura_output_send_scale(resource_, flags, output_scale);
}
} else {
zaura_output_send_scale(resource_,
@@ -2975,7 +3035,7 @@ void aura_shell_get_aura_output(wl_client* client,
const struct zaura_shell_interface aura_shell_implementation = {
aura_shell_get_aura_surface, aura_shell_get_aura_output};
-const uint32_t aura_shell_version = 5;
+const uint32_t aura_shell_version = 6;
void bind_aura_shell(wl_client* client,
void* data,
@@ -4896,6 +4956,97 @@ void bind_keyboard_extension(wl_client* client,
}
////////////////////////////////////////////////////////////////////////////////
+// cursor_shapes interface:
+
+static ui::CursorType GetCursorType(int32_t cursor_shape) {
+ switch (cursor_shape) {
+#define ADD_CASE(wayland, chrome) \
+ case ZCR_CURSOR_SHAPES_V1_CURSOR_SHAPE_TYPE_##wayland: \
+ return ui::CursorType::chrome
+
+ ADD_CASE(POINTER, kPointer);
+ ADD_CASE(CROSS, kCross);
+ ADD_CASE(HAND, kHand);
+ ADD_CASE(IBEAM, kIBeam);
+ ADD_CASE(WAIT, kWait);
+ ADD_CASE(HELP, kHelp);
+ ADD_CASE(EAST_RESIZE, kEastResize);
+ ADD_CASE(NORTH_RESIZE, kNorthResize);
+ ADD_CASE(NORTH_EAST_RESIZE, kNorthEastResize);
+ ADD_CASE(NORTH_WEST_RESIZE, kNorthWestResize);
+ ADD_CASE(SOUTH_RESIZE, kSouthResize);
+ ADD_CASE(SOUTH_EAST_RESIZE, kSouthEastResize);
+ ADD_CASE(SOUTH_WEST_RESIZE, kSouthWestResize);
+ ADD_CASE(WEST_RESIZE, kWestResize);
+ ADD_CASE(NORTH_SOUTH_RESIZE, kNorthSouthResize);
+ ADD_CASE(EAST_WEST_RESIZE, kEastWestResize);
+ ADD_CASE(NORTH_EAST_SOUTH_WEST_RESIZE, kNorthEastSouthWestResize);
+ ADD_CASE(NORTH_WEST_SOUTH_EAST_RESIZE, kNorthWestSouthEastResize);
+ ADD_CASE(COLUMN_RESIZE, kColumnResize);
+ ADD_CASE(ROW_RESIZE, kRowResize);
+ ADD_CASE(MIDDLE_PANNING, kMiddlePanning);
+ ADD_CASE(EAST_PANNING, kEastPanning);
+ ADD_CASE(NORTH_PANNING, kNorthPanning);
+ ADD_CASE(NORTH_EAST_PANNING, kNorthEastPanning);
+ ADD_CASE(NORTH_WEST_PANNING, kNorthWestPanning);
+ ADD_CASE(SOUTH_PANNING, kSouthPanning);
+ ADD_CASE(SOUTH_EAST_PANNING, kSouthEastPanning);
+ ADD_CASE(SOUTH_WEST_PANNING, kSouthWestPanning);
+ ADD_CASE(WEST_PANNING, kWestPanning);
+ ADD_CASE(MOVE, kMove);
+ ADD_CASE(VERTICAL_TEXT, kVerticalText);
+ ADD_CASE(CELL, kCell);
+ ADD_CASE(CONTEXT_MENU, kContextMenu);
+ ADD_CASE(ALIAS, kAlias);
+ ADD_CASE(PROGRESS, kProgress);
+ ADD_CASE(NO_DROP, kNoDrop);
+ ADD_CASE(COPY, kCopy);
+ ADD_CASE(NONE, kNone);
+ ADD_CASE(NOT_ALLOWED, kNotAllowed);
+ ADD_CASE(ZOOM_IN, kZoomIn);
+ ADD_CASE(ZOOM_OUT, kZoomOut);
+ ADD_CASE(GRAB, kGrab);
+ ADD_CASE(GRABBING, kGrabbing);
+ ADD_CASE(DND_NONE, kDndNone);
+ ADD_CASE(DND_MOVE, kDndMove);
+ ADD_CASE(DND_COPY, kDndCopy);
+ ADD_CASE(DND_LINK, kDndLink);
+#undef ADD_CASE
+ default:
+ return ui::CursorType::kNull;
+ }
+}
+
+void cursor_shapes_set_cursor_shape(wl_client* client,
+ wl_resource* resource,
+ wl_resource* pointer_resource,
+ int32_t shape) {
+ ui::CursorType cursor_type = GetCursorType(shape);
+ if (cursor_type == ui::CursorType::kNull) {
+ wl_resource_post_error(resource, ZCR_CURSOR_SHAPES_V1_ERROR_INVALID_SHAPE,
+ "Unrecognized shape %d", shape);
+ return;
+ }
+
+ Pointer* pointer = GetUserDataAs<Pointer>(pointer_resource);
+ pointer->SetCursorType(cursor_type);
+}
+
+const struct zcr_cursor_shapes_v1_interface cursor_shapes_implementation = {
+ cursor_shapes_set_cursor_shape};
+
+void bind_cursor_shapes(wl_client* client,
+ void* data,
+ uint32_t version,
+ uint32_t id) {
+ wl_resource* resource =
+ wl_resource_create(client, &zcr_cursor_shapes_v1_interface, version, id);
+
+ wl_resource_set_implementation(resource, &cursor_shapes_implementation, data,
+ nullptr);
+}
+
+////////////////////////////////////////////////////////////////////////////////
// input_timestamps_v1 interface:
class WaylandInputTimestamps : public WaylandInputDelegate::Observer {
@@ -5048,6 +5199,8 @@ Server::Server(Display* display)
display_, bind_stylus_tools);
wl_global_create(wl_display_.get(), &zcr_keyboard_extension_v1_interface, 1,
display_, bind_keyboard_extension);
+ wl_global_create(wl_display_.get(), &zcr_cursor_shapes_v1_interface, 1,
+ display_, bind_cursor_shapes);
wl_global_create(wl_display_.get(),
&zwp_input_timestamps_manager_v1_interface, 1, display_,
bind_input_timestamps_manager);
diff --git a/chromium/components/favicon/content/DEPS b/chromium/components/favicon/content/DEPS
index 5bb1fc1368f..ce45cc00b20 100644
--- a/chromium/components/favicon/content/DEPS
+++ b/chromium/components/favicon/content/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/history/core/browser",
"+content/public",
+ "+third_party/blink/public/common",
"+third_party/skia/include",
]
diff --git a/chromium/components/favicon/content/content_favicon_driver.cc b/chromium/components/favicon/content/content_favicon_driver.cc
index a4d2fbc7734..08260fda1b8 100644
--- a/chromium/components/favicon/content/content_favicon_driver.cc
+++ b/chromium/components/favicon/content/content_favicon_driver.cc
@@ -17,7 +17,7 @@
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/common/favicon_url.h"
-#include "content/public/common/manifest.h"
+#include "third_party/blink/public/common/manifest/manifest.h"
#include "ui/gfx/image/image.h"
DEFINE_WEB_CONTENTS_USER_DATA_KEY(favicon::ContentFaviconDriver);
@@ -28,9 +28,9 @@ namespace {
void ExtractManifestIcons(
ContentFaviconDriver::ManifestDownloadCallback callback,
const GURL& manifest_url,
- const content::Manifest& manifest) {
+ const blink::Manifest& manifest) {
std::vector<FaviconURL> candidates;
- for (const content::Manifest::Icon& icon : manifest.icons) {
+ for (const blink::Manifest::Icon& icon : manifest.icons) {
candidates.emplace_back(icon.src, favicon_base::IconType::kWebManifestIcon,
icon.sizes);
}
diff --git a/chromium/components/favicon/core/BUILD.gn b/chromium/components/favicon/core/BUILD.gn
index 59f1e72817a..798ad7bce73 100644
--- a/chromium/components/favicon/core/BUILD.gn
+++ b/chromium/components/favicon/core/BUILD.gn
@@ -14,6 +14,8 @@ static_library("core") {
"favicon_driver_observer.h",
"favicon_handler.cc",
"favicon_handler.h",
+ "favicon_server_fetcher_params.cc",
+ "favicon_server_fetcher_params.h",
"favicon_service.cc",
"favicon_service.h",
"favicon_service_impl.cc",
diff --git a/chromium/components/favicon/core/favicon_handler.cc b/chromium/components/favicon/core/favicon_handler.cc
index 4c59b816886..52a8c144377 100644
--- a/chromium/components/favicon/core/favicon_handler.cc
+++ b/chromium/components/favicon/core/favicon_handler.cc
@@ -458,10 +458,6 @@ void FaviconHandler::OnGotInitialHistoryDataAndIconURLCandidates() {
return;
}
- if (!current_candidate()) {
- return;
- }
-
if (!initial_history_result_expired_or_incomplete_ &&
current_candidate()->icon_url == notification_icon_url_ &&
current_candidate()->icon_type == notification_icon_type_) {
diff --git a/chromium/components/favicon/core/favicon_server_fetcher_params.cc b/chromium/components/favicon/core/favicon_server_fetcher_params.cc
new file mode 100644
index 00000000000..dd23dd985ae
--- /dev/null
+++ b/chromium/components/favicon/core/favicon_server_fetcher_params.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 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 "components/favicon/core/favicon_server_fetcher_params.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/favicon_base/favicon_util.h"
+#include "ui/gfx/favicon_size.h"
+
+namespace favicon {
+namespace {
+
+const char kClientParamDesktop[] = "client=chrome_desktop";
+const char kClientParamMobile[] = "client=chrome";
+
+float GetMaxDeviceScaleFactor() {
+ std::vector<float> favicon_scales = favicon_base::GetFaviconScales();
+ DCHECK(!favicon_scales.empty());
+ return favicon_scales.back();
+}
+
+} // namespace
+
+std::unique_ptr<FaviconServerFetcherParams>
+FaviconServerFetcherParams::CreateForDesktop(const GURL& page_url) {
+ return base::WrapUnique(new FaviconServerFetcherParams(
+ page_url, favicon_base::IconType::kFavicon,
+ std::ceil(gfx::kFaviconSize * GetMaxDeviceScaleFactor()), 0,
+ kClientParamDesktop));
+}
+
+std::unique_ptr<FaviconServerFetcherParams>
+FaviconServerFetcherParams::CreateForMobile(const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel) {
+ return base::WrapUnique(new FaviconServerFetcherParams(
+ page_url, favicon_base::IconType::kTouchIcon, min_source_size_in_pixel,
+ desired_size_in_pixel, kClientParamMobile));
+}
+
+FaviconServerFetcherParams::FaviconServerFetcherParams(
+ const GURL& page_url,
+ favicon_base::IconType icon_type,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const std::string& google_server_client_param)
+ : page_url_(page_url),
+ icon_type_(icon_type),
+ min_source_size_in_pixel_(min_source_size_in_pixel),
+ desired_size_in_pixel_(desired_size_in_pixel),
+ google_server_client_param_(google_server_client_param) {}
+
+FaviconServerFetcherParams::~FaviconServerFetcherParams() = default;
+
+} // namespace favicon
diff --git a/chromium/components/favicon/core/favicon_server_fetcher_params.h b/chromium/components/favicon/core/favicon_server_fetcher_params.h
new file mode 100644
index 00000000000..8484239c8ad
--- /dev/null
+++ b/chromium/components/favicon/core/favicon_server_fetcher_params.h
@@ -0,0 +1,53 @@
+// Copyright (c) 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 COMPONENTS_FAVICON_CORE_FAVICON_SERVER_FETCHER_PARAMS_H_
+#define COMPONENTS_FAVICON_CORE_FAVICON_SERVER_FETCHER_PARAMS_H_
+
+#include "components/favicon_base/favicon_util.h"
+
+class GURL;
+
+namespace favicon {
+
+class FaviconServerFetcherParams {
+ public:
+ // Platform specific constructors that set default fetch parameters. Any
+ // platform not Android nor iOS is considered desktop.
+ static std::unique_ptr<FaviconServerFetcherParams> CreateForDesktop(
+ const GURL& page_url);
+ static std::unique_ptr<FaviconServerFetcherParams> CreateForMobile(
+ const GURL& page_url,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel);
+
+ ~FaviconServerFetcherParams();
+
+ const GURL& page_url() const { return page_url_; };
+ favicon_base::IconType icon_type() const { return icon_type_; };
+ int min_source_size_in_pixel() const { return min_source_size_in_pixel_; };
+ int desired_size_in_pixel() const { return desired_size_in_pixel_; };
+ const std::string& google_server_client_param() const {
+ return google_server_client_param_;
+ };
+
+ private:
+ FaviconServerFetcherParams(const GURL& page_url,
+ favicon_base::IconType icon_type,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ const std::string& google_server_client_param);
+
+ const GURL& page_url_;
+ favicon_base::IconType icon_type_;
+ int min_source_size_in_pixel_;
+ int desired_size_in_pixel_;
+ std::string google_server_client_param_;
+
+ DISALLOW_COPY_AND_ASSIGN(FaviconServerFetcherParams);
+};
+
+} // namespace favicon
+
+#endif // COMPONENTS_FAVICON_CORE_FAVICON_SERVER_FETCHER_PARAMS_H_
diff --git a/chromium/components/favicon/core/large_icon_service.cc b/chromium/components/favicon/core/large_icon_service.cc
index eac4973e3b5..4edb822bc24 100644
--- a/chromium/components/favicon/core/large_icon_service.cc
+++ b/chromium/components/favicon/core/large_icon_service.cc
@@ -24,6 +24,7 @@
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/favicon/core/favicon_server_fetcher_params.h"
#include "components/favicon/core/favicon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
@@ -52,6 +53,8 @@ const char kGoogleServerV2RequestFormat[] =
"size=%d&min_size=%d&max_size=%d&fallback_opts=TYPE,SIZE,URL&url=%s";
const char kGoogleServerV2RequestFormatParam[] = "request_format";
+const char kClientParam[] = "client=chrome";
+
const char kCheckSeenParam[] = "check_seen=true&";
const int kGoogleServerV2EnforcedMinSizeInPixel = 16;
@@ -79,10 +82,12 @@ GURL TrimPageUrlForGoogleServer(const GURL& page_url) {
return page_url.ReplaceComponents(replacements);
}
-GURL GetRequestUrlForGoogleServerV2(const GURL& page_url,
- int min_source_size_in_pixel,
- int desired_size_in_pixel,
- bool may_page_url_be_private) {
+GURL GetRequestUrlForGoogleServerV2(
+ const GURL& page_url,
+ const std::string& google_server_client_param,
+ int min_source_size_in_pixel,
+ int desired_size_in_pixel,
+ bool may_page_url_be_private) {
std::string url_format = base::GetFieldTrialParamValueByFeature(
kLargeIconServiceFetchingFeature, kGoogleServerV2RequestFormatParam);
double desired_to_max_size_factor = base::GetFieldTrialParamByFeatureAsDouble(
@@ -105,10 +110,13 @@ GURL GetRequestUrlForGoogleServerV2(const GURL& page_url,
static_cast<int>(desired_size_in_pixel * desired_to_max_size_factor);
max_size_in_pixel = std::max(max_size_in_pixel, minimum_max_size_in_pixel);
- return GURL(base::StringPrintf(
+ std::string request_url = base::StringPrintf(
url_format.empty() ? kGoogleServerV2RequestFormat : url_format.c_str(),
may_page_url_be_private ? kCheckSeenParam : "", desired_size_in_pixel,
- min_source_size_in_pixel, max_size_in_pixel, page_url.spec().c_str()));
+ min_source_size_in_pixel, max_size_in_pixel, page_url.spec().c_str());
+ base::ReplaceFirstSubstringAfterOffset(
+ &request_url, 0, std::string(kClientParam), google_server_client_param);
+ return GURL(request_url);
}
bool IsDbResultAdequate(const favicon_base::FaviconRawBitmapResult& db_result,
@@ -193,8 +201,8 @@ void ProcessIconOnBackgroundThread(
void FinishServerRequestAsynchronously(
const favicon_base::GoogleFaviconServerCallback& callback,
favicon_base::GoogleFaviconServerRequestStatus status) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, status));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(callback, status));
}
// Singleton map keyed by organization-identifying domain (excludes registrar
@@ -407,6 +415,7 @@ void OnSetOnDemandFaviconComplete(
void OnFetchIconFromGoogleServerComplete(
FaviconService* favicon_service,
const GURL& page_url,
+ favicon_base::IconType icon_type,
const favicon_base::GoogleFaviconServerCallback& callback,
const std::string& server_request_url,
const gfx::Image& image,
@@ -437,8 +446,8 @@ void OnFetchIconFromGoogleServerComplete(
// expired (out-of-date), they will be refetched when we visit the original
// page any time in the future.
favicon_service->SetOnDemandFavicons(
- page_url, GURL(original_icon_url), favicon_base::IconType::kTouchIcon,
- image, base::Bind(&OnSetOnDemandFaviconComplete, callback));
+ page_url, GURL(original_icon_url), icon_type, image,
+ base::BindOnce(&OnSetOnDemandFaviconComplete, callback));
}
} // namespace
@@ -485,13 +494,11 @@ LargeIconService::GetLargeIconImageOrFallbackStyle(
void LargeIconService::
GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- const GURL& page_url,
- int min_source_size_in_pixel,
- int desired_size_in_pixel,
+ std::unique_ptr<FaviconServerFetcherParams> params,
bool may_page_url_be_private,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const favicon_base::GoogleFaviconServerCallback& callback) {
- DCHECK_LE(0, min_source_size_in_pixel);
+ DCHECK_LE(0, params->min_source_size_in_pixel());
if (net::NetworkChangeNotifier::IsOffline()) {
// By exiting early when offline, we avoid caching the failure and thus
@@ -501,13 +508,13 @@ void LargeIconService::
return;
}
- if (!page_url.is_valid()) {
+ if (!params->page_url().is_valid()) {
FinishServerRequestAsynchronously(
callback, GoogleFaviconServerRequestStatus::FAILURE_TARGET_URL_INVALID);
return;
}
- const GURL trimmed_page_url = TrimPageUrlForGoogleServer(page_url);
+ const GURL trimmed_page_url = TrimPageUrlForGoogleServer(params->page_url());
if (!trimmed_page_url.is_valid()) {
FinishServerRequestAsynchronously(
callback, GoogleFaviconServerRequestStatus::FAILURE_TARGET_URL_SKIPPED);
@@ -515,7 +522,8 @@ void LargeIconService::
}
const GURL server_request_url = GetRequestUrlForGoogleServerV2(
- trimmed_page_url, min_source_size_in_pixel, desired_size_in_pixel,
+ trimmed_page_url, params->google_server_client_param(),
+ params->min_source_size_in_pixel(), params->desired_size_in_pixel(),
may_page_url_be_private);
if (!server_request_url.is_valid()) {
FinishServerRequestAsynchronously(
@@ -532,10 +540,11 @@ void LargeIconService::
}
favicon_service_->CanSetOnDemandFavicons(
- page_url, favicon_base::IconType::kTouchIcon,
+ params->page_url(), params->icon_type(),
base::BindOnce(&LargeIconService::OnCanSetOnDemandFaviconComplete,
weak_ptr_factory_.GetWeakPtr(), server_request_url,
- page_url, traffic_annotation, callback));
+ params->page_url(), params->icon_type(),
+ traffic_annotation, callback));
}
void LargeIconService::TouchIconFromGoogleServer(const GURL& icon_url) {
@@ -591,6 +600,7 @@ LargeIconService::GetLargeIconOrFallbackStyleImpl(
void LargeIconService::OnCanSetOnDemandFaviconComplete(
const GURL& server_request_url,
const GURL& page_url,
+ favicon_base::IconType icon_type,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const favicon_base::GoogleFaviconServerCallback& callback,
bool can_set_on_demand_favicon) {
@@ -603,8 +613,8 @@ void LargeIconService::OnCanSetOnDemandFaviconComplete(
data_use_measurement::DataUseUserData::LARGE_ICON_SERVICE);
image_fetcher_->FetchImage(
server_request_url.spec(), server_request_url,
- base::BindRepeating(&OnFetchIconFromGoogleServerComplete,
- favicon_service_, page_url, callback),
+ base::BindOnce(&OnFetchIconFromGoogleServerComplete, favicon_service_,
+ page_url, icon_type, callback),
traffic_annotation);
}
diff --git a/chromium/components/favicon/core/large_icon_service.h b/chromium/components/favicon/core/large_icon_service.h
index 96bd8b1ce74..1d1a32cdb5c 100644
--- a/chromium/components/favicon/core/large_icon_service.h
+++ b/chromium/components/favicon/core/large_icon_service.h
@@ -26,6 +26,7 @@ class ImageFetcher;
namespace favicon {
class FaviconService;
+class FaviconServerFetcherParams;
// The large icon service provides methods to access large icons. It relies on
// the favicon service.
@@ -93,9 +94,7 @@ class LargeIconService : public KeyedService {
// TODO(jkrcal): It is not clear from the name of this function, that it
// actually adds the icon to the local cache. Maybe "StoreLargeIcon..."?
void GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- const GURL& page_url,
- int min_source_size_in_pixel,
- int desired_size_in_pixel,
+ std::unique_ptr<FaviconServerFetcherParams> params,
bool may_page_url_be_private,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const favicon_base::GoogleFaviconServerCallback& callback);
@@ -125,6 +124,7 @@ class LargeIconService : public KeyedService {
void OnCanSetOnDemandFaviconComplete(
const GURL& server_request_url,
const GURL& page_url,
+ favicon_base::IconType icon_type,
const net::NetworkTrafficAnnotationTag& traffic_annotation,
const favicon_base::GoogleFaviconServerCallback& callback,
bool can_set_on_demand_favicon);
diff --git a/chromium/components/favicon/core/large_icon_service_unittest.cc b/chromium/components/favicon/core/large_icon_service_unittest.cc
index 7007c78e76c..acf0f2d75e6 100644
--- a/chromium/components/favicon/core/large_icon_service_unittest.cc
+++ b/chromium/components/favicon/core/large_icon_service_unittest.cc
@@ -17,6 +17,7 @@
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/favicon/core/favicon_client.h"
+#include "components/favicon/core/favicon_server_fetcher_params.h"
#include "components/favicon/core/test/mock_favicon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
@@ -29,6 +30,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
+#include "ui/base/layout.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
@@ -125,7 +127,10 @@ class LargeIconServiceTest : public testing::Test {
LargeIconServiceTest()
: mock_image_fetcher_(new NiceMock<MockImageFetcher>()),
large_icon_service_(&mock_favicon_service_,
- base::WrapUnique(mock_image_fetcher_)) {}
+ base::WrapUnique(mock_image_fetcher_)) {
+ scoped_set_supported_scale_factors_.reset(
+ new ui::test::ScopedSetSupportedScaleFactors({ui::SCALE_FACTOR_200P}));
+ }
~LargeIconServiceTest() override {}
@@ -135,6 +140,8 @@ class LargeIconServiceTest : public testing::Test {
testing::NiceMock<MockFaviconService> mock_favicon_service_;
LargeIconService large_icon_service_;
base::HistogramTester histogram_tester_;
+ std::unique_ptr<ui::test::ScopedSetSupportedScaleFactors>
+ scoped_set_supported_scale_factors_;
private:
DISALLOW_COPY_AND_ASSIGN(LargeIconServiceTest);
@@ -164,9 +171,12 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServer) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
@@ -175,6 +185,42 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServer) {
"Favicons.LargeIconService.DownloadedSize", 64, /*expected_count=*/1);
}
+TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerForDesktop) {
+ const GURL kExpectedServerUrl(
+ "https://t0.gstatic.com/faviconV2?client=chrome_desktop"
+ "&drop_404_icon=true&check_seen=true&size=32&min_size=32&max_size=256"
+ "&fallback_opts=TYPE,SIZE,URL&url=http://www.example.com/");
+
+ EXPECT_CALL(mock_favicon_service_, UnableToDownloadFavicon(_)).Times(0);
+ EXPECT_CALL(mock_favicon_service_,
+ CanSetOnDemandFavicons(GURL(kDummyUrl),
+ favicon_base::IconType::kFavicon, _))
+ .WillOnce(PostBoolReplyToArg2(true));
+
+ base::MockCallback<favicon_base::GoogleFaviconServerCallback> callback;
+ EXPECT_CALL(*mock_image_fetcher_,
+ FetchImageAndData_(_, kExpectedServerUrl, _, _, _))
+ .WillOnce(PostFetchReply(gfx::Image::CreateFrom1xBitmap(
+ CreateTestSkBitmap(32, 32, kTestColor))));
+ EXPECT_CALL(mock_favicon_service_,
+ SetOnDemandFavicons(GURL(kDummyUrl), kExpectedServerUrl,
+ favicon_base::IconType::kFavicon, _, _))
+ .WillOnce(PostBoolReplyToArg4(true));
+
+ large_icon_service_
+ .GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
+ favicon::FaviconServerFetcherParams::CreateForDesktop(
+ GURL(kDummyUrl)),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
+
+ EXPECT_CALL(callback,
+ Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
+ scoped_task_environment_.RunUntilIdle();
+ histogram_tester_.ExpectUniqueSample(
+ "Favicons.LargeIconService.DownloadedSize", 32, /*expected_count=*/1);
+}
+
TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithCustomUrl) {
variations::testing::VariationParamsManager variation_params(
"LargeIconServiceFetching",
@@ -206,9 +252,12 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithCustomUrl) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
@@ -243,9 +292,12 @@ TEST_F(LargeIconServiceTest, ShouldGetFromGoogleServerWithOriginalUrl) {
base::MockCallback<favicon_base::GoogleFaviconServerCallback> callback;
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback,
Run(favicon_base::GoogleFaviconServerRequestStatus::SUCCESS));
@@ -274,9 +326,11 @@ TEST_F(LargeIconServiceTest, ShouldTrimQueryParametersForGoogleServer) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrlWithQuery), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS,
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrlWithQuery),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
favicon_base::GoogleFaviconServerCallback());
scoped_task_environment_.RunUntilIdle();
@@ -298,9 +352,12 @@ TEST_F(LargeIconServiceTest, ShouldNotCheckOnPublicUrls) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/false,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/false, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_CONNECTION_ERROR));
@@ -316,9 +373,12 @@ TEST_F(LargeIconServiceTest, ShouldNotQueryGoogleServerIfInvalidScheme) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyFtpUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyFtpUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_TARGET_URL_SKIPPED));
@@ -337,9 +397,12 @@ TEST_F(LargeIconServiceTest, ShouldNotQueryGoogleServerIfInvalidURL) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyInvalidUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyInvalidUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_TARGET_URL_INVALID));
@@ -371,9 +434,12 @@ TEST_F(LargeIconServiceTest, ShouldReportUnavailableIfFetchFromServerFails) {
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_CONNECTION_ERROR));
@@ -400,9 +466,12 @@ TEST_F(LargeIconServiceTest, ShouldNotGetFromGoogleServerIfUnavailable) {
base::MockCallback<favicon_base::GoogleFaviconServerCallback> callback;
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_HTTP_ERROR_CACHED));
@@ -426,9 +495,12 @@ TEST_F(LargeIconServiceTest, ShouldNotGetFromGoogleServerIfCannotSet) {
base::MockCallback<favicon_base::GoogleFaviconServerCallback> callback;
large_icon_service_
.GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- GURL(kDummyUrl), /*min_source_size_in_pixel=*/42,
- /*desired_size_in_pixel=*/61, /*may_page_url_be_private=*/true,
- TRAFFIC_ANNOTATION_FOR_TESTS, callback.Get());
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ GURL(kDummyUrl),
+ /*min_source_size_in_pixel=*/42,
+ /*desired_size_in_pixel=*/61),
+ /*may_page_url_be_private=*/true, TRAFFIC_ANNOTATION_FOR_TESTS,
+ callback.Get());
EXPECT_CALL(callback, Run(favicon_base::GoogleFaviconServerRequestStatus::
FAILURE_ICON_EXISTS_IN_DB));
@@ -441,7 +513,7 @@ TEST_F(LargeIconServiceTest, ShouldNotGetFromGoogleServerIfCannotSet) {
class LargeIconServiceGetterTest : public LargeIconServiceTest,
public ::testing::WithParamInterface<bool> {
public:
- LargeIconServiceGetterTest() : LargeIconServiceTest() {}
+ LargeIconServiceGetterTest() {}
~LargeIconServiceGetterTest() override {}
void GetLargeIconOrFallbackStyleAndWaitForCallback(
diff --git a/chromium/components/feature_engagement/internal/configuration.cc b/chromium/components/feature_engagement/internal/configuration.cc
index 67b2dd553e0..174b28a99ee 100644
--- a/chromium/components/feature_engagement/internal/configuration.cc
+++ b/chromium/components/feature_engagement/internal/configuration.cc
@@ -97,8 +97,7 @@ std::ostream& operator<<(std::ostream& os, const EventConfig& event_config) {
<< ", storage: " << event_config.storage << " }";
}
-SessionRateImpact::SessionRateImpact()
- : type(SessionRateImpact::Type::ALL), affected_features() {}
+SessionRateImpact::SessionRateImpact() : type(SessionRateImpact::Type::ALL) {}
SessionRateImpact::SessionRateImpact(const SessionRateImpact& other) = default;
diff --git a/chromium/components/feature_engagement/internal/event_model_impl.cc b/chromium/components/feature_engagement/internal/event_model_impl.cc
index 2fd365c9c5a..3ea302a1c8a 100644
--- a/chromium/components/feature_engagement/internal/event_model_impl.cc
+++ b/chromium/components/feature_engagement/internal/event_model_impl.cc
@@ -24,8 +24,7 @@ namespace feature_engagement {
EventModelImpl::EventModelImpl(
std::unique_ptr<EventStore> store,
std::unique_ptr<EventStorageValidator> storage_validator)
- : EventModel(),
- store_(std::move(store)),
+ : store_(std::move(store)),
storage_validator_(std::move(storage_validator)),
ready_(false),
weak_factory_(this) {}
diff --git a/chromium/components/feature_engagement/internal/event_model_impl_unittest.cc b/chromium/components/feature_engagement/internal/event_model_impl_unittest.cc
index 82226deace9..92e2fda1e39 100644
--- a/chromium/components/feature_engagement/internal/event_model_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/event_model_impl_unittest.cc
@@ -171,7 +171,7 @@ class EventModelImplTest : public ::testing::Test {
class LoadFailingEventModelImplTest : public EventModelImplTest {
public:
- LoadFailingEventModelImplTest() : EventModelImplTest() {}
+ LoadFailingEventModelImplTest() {}
std::unique_ptr<TestInMemoryEventStore> CreateStore() override {
return std::make_unique<TestInMemoryEventStore>(
diff --git a/chromium/components/feature_engagement/internal/in_memory_event_store.cc b/chromium/components/feature_engagement/internal/in_memory_event_store.cc
index 348727a939f..40d3461121c 100644
--- a/chromium/components/feature_engagement/internal/in_memory_event_store.cc
+++ b/chromium/components/feature_engagement/internal/in_memory_event_store.cc
@@ -19,7 +19,7 @@ namespace feature_engagement {
InMemoryEventStore::InMemoryEventStore(
std::unique_ptr<std::vector<Event>> events)
- : EventStore(), events_(std::move(events)), ready_(false) {}
+ : events_(std::move(events)), ready_(false) {}
InMemoryEventStore::InMemoryEventStore()
: InMemoryEventStore(std::make_unique<std::vector<Event>>()) {}
diff --git a/chromium/components/feature_engagement/internal/persistent_event_store.cc b/chromium/components/feature_engagement/internal/persistent_event_store.cc
index fea509b2cba..2d11b2cb332 100644
--- a/chromium/components/feature_engagement/internal/persistent_event_store.cc
+++ b/chromium/components/feature_engagement/internal/persistent_event_store.cc
@@ -83,7 +83,7 @@ void PersistentEventStore::OnLoadComplete(
const OnLoadedCallback& callback,
bool success,
std::unique_ptr<std::vector<Event>> entries) {
- stats::RecordEventDbLoadEvent(success, *entries.get());
+ stats::RecordEventDbLoadEvent(success, *entries);
ready_ = success;
callback.Run(success, std::move(entries));
}
diff --git a/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
index bbcf9235695..5fb4c8bab23 100644
--- a/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
+++ b/chromium/components/feature_engagement/internal/tracker_impl_unittest.cc
@@ -81,7 +81,7 @@ class StoringInitializedCallback {
class TestInMemoryEventStore : public InMemoryEventStore {
public:
explicit TestInMemoryEventStore(bool load_should_succeed)
- : InMemoryEventStore(), load_should_succeed_(load_should_succeed) {}
+ : load_should_succeed_(load_should_succeed) {}
void Load(const OnLoadedCallback& callback) override {
HandleLoadResult(callback, load_should_succeed_);
diff --git a/chromium/components/feature_engagement/public/feature_constants.cc b/chromium/components/feature_engagement/public/feature_constants.cc
index aba16effeca..1ecbaf9b26b 100644
--- a/chromium/components/feature_engagement/public/feature_constants.cc
+++ b/chromium/components/feature_engagement/public/feature_constants.cc
@@ -41,6 +41,16 @@ const base::Feature kIPHContextualSearchOptInFeature{
"IPH_ContextualSearchOptIn", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kIPHContextualSuggestionsFeature{
"IPH_ContextualSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHDownloadSettingsFeature{
+ "IPH_DownloadSettings", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHDownloadInfoBarDownloadContinuingFeature{
+ "IPH_DownloadInfoBarDownloadContinuing", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHDownloadInfoBarDownloadsAreFasterFeature{
+ "IPH_DownloadInfoBarDownloadsAreFaster", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHHomePageButtonFeature{
+ "IPH_HomePageButton", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kIPHNewTabPageButtonFeature{
+ "IPH_NewTabPageButton", base::FEATURE_DISABLED_BY_DEFAULT};
#endif // defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
diff --git a/chromium/components/feature_engagement/public/feature_constants.h b/chromium/components/feature_engagement/public/feature_constants.h
index fe4fa56390e..fb9333c383a 100644
--- a/chromium/components/feature_engagement/public/feature_constants.h
+++ b/chromium/components/feature_engagement/public/feature_constants.h
@@ -34,6 +34,11 @@ extern const base::Feature kIPHContextualSearchPromoteTapFeature;
extern const base::Feature kIPHContextualSearchPromotePanelOpenFeature;
extern const base::Feature kIPHContextualSearchOptInFeature;
extern const base::Feature kIPHContextualSuggestionsFeature;
+extern const base::Feature kIPHDownloadSettingsFeature;
+extern const base::Feature kIPHDownloadInfoBarDownloadContinuingFeature;
+extern const base::Feature kIPHDownloadInfoBarDownloadsAreFasterFeature;
+extern const base::Feature kIPHHomePageButtonFeature;
+extern const base::Feature kIPHNewTabPageButtonFeature;
#endif // defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
diff --git a/chromium/components/feature_engagement/public/feature_list.cc b/chromium/components/feature_engagement/public/feature_list.cc
index a1cb2e05ac9..3b602b105cf 100644
--- a/chromium/components/feature_engagement/public/feature_list.cc
+++ b/chromium/components/feature_engagement/public/feature_list.cc
@@ -29,6 +29,11 @@ const base::Feature* const kAllFeatures[] = {
&kIPHContextualSearchPromotePanelOpenFeature,
&kIPHContextualSearchOptInFeature,
&kIPHContextualSuggestionsFeature,
+ &kIPHDownloadSettingsFeature,
+ &kIPHDownloadInfoBarDownloadContinuingFeature,
+ &kIPHDownloadInfoBarDownloadsAreFasterFeature,
+ &kIPHHomePageButtonFeature,
+ &kIPHNewTabPageButtonFeature,
#endif // defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
&kIPHBookmarkFeature,
diff --git a/chromium/components/feature_engagement/public/feature_list.h b/chromium/components/feature_engagement/public/feature_list.h
index dd4d80e1ab5..65174b4b588 100644
--- a/chromium/components/feature_engagement/public/feature_list.h
+++ b/chromium/components/feature_engagement/public/feature_list.h
@@ -66,6 +66,13 @@ DEFINE_VARIATION_PARAM(kIPHContextualSearchOptInFeature,
"IPH_ContextualSearchOptIn");
DEFINE_VARIATION_PARAM(kIPHContextualSuggestionsFeature,
"IPH_ContextualSuggestions");
+DEFINE_VARIATION_PARAM(kIPHDownloadSettingsFeature, "IPH_DownloadSettings");
+DEFINE_VARIATION_PARAM(kIPHDownloadInfoBarDownloadContinuingFeature,
+ "IPH_DownloadInfoBarDownloadContinuing");
+DEFINE_VARIATION_PARAM(kIPHDownloadInfoBarDownloadsAreFasterFeature,
+ "IPH_DownloadInfoBarDownloadsAreFaster");
+DEFINE_VARIATION_PARAM(kIPHHomePageButtonFeature, "IPH_HomePageButton");
+DEFINE_VARIATION_PARAM(kIPHNewTabPageButtonFeature, "IPH_NewTabPageButton");
#endif // defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
DEFINE_VARIATION_PARAM(kIPHBookmarkFeature, "IPH_Bookmark");
@@ -99,6 +106,11 @@ constexpr flags_ui::FeatureEntry::FeatureVariation
VARIATION_ENTRY(kIPHContextualSearchPromotePanelOpenFeature),
VARIATION_ENTRY(kIPHContextualSearchOptInFeature),
VARIATION_ENTRY(kIPHContextualSuggestionsFeature),
+ VARIATION_ENTRY(kIPHDownloadSettingsFeature),
+ VARIATION_ENTRY(kIPHDownloadInfoBarDownloadContinuingFeature),
+ VARIATION_ENTRY(kIPHDownloadInfoBarDownloadsAreFasterFeature),
+ VARIATION_ENTRY(kIPHHomePageButtonFeature),
+ VARIATION_ENTRY(kIPHNewTabPageButtonFeature),
#elif BUILDFLAG(ENABLE_DESKTOP_IN_PRODUCT_HELP)
VARIATION_ENTRY(kIPHBookmarkFeature),
VARIATION_ENTRY(kIPHIncognitoWindowFeature),
diff --git a/chromium/components/feed/DEPS b/chromium/components/feed/DEPS
index ea824a76a14..6ef6ce4d5ab 100644
--- a/chromium/components/feed/DEPS
+++ b/chromium/components/feed/DEPS
@@ -1,15 +1,20 @@
include_rules = [
"+components/data_use_measurement/core",
+ "+components/image_fetcher",
+ "+components/keyed_service/core",
"+components/leveldb_proto",
"+components/variations",
"+components/version_info",
"+net/base",
"+net/http",
"+net/traffic_annotation",
+ "+net/url_request",
"+google_apis",
"+services/identity/public/cpp",
"+services/network/public/cpp",
"+services/network/public/mojom",
"+services/network/test",
"+third_party/zlib/google",
-]
+ "+ui/gfx/geometry",
+ "+ui/gfx/image",
+ ]
diff --git a/chromium/components/feed/core/BUILD.gn b/chromium/components/feed/core/BUILD.gn
index b3f2b9a2395..74be816a7db 100644
--- a/chromium/components/feed/core/BUILD.gn
+++ b/chromium/components/feed/core/BUILD.gn
@@ -4,8 +4,12 @@
source_set("feed_core") {
sources = [
+ "feed_host_service.cc",
+ "feed_host_service.h",
"feed_image_database.cc",
"feed_image_database.h",
+ "feed_image_manager.cc",
+ "feed_image_manager.h",
"feed_networking_host.cc",
"feed_networking_host.h",
"time_serialization.cc",
@@ -15,6 +19,7 @@ source_set("feed_core") {
public_deps = [
"//base",
"//components/feed/core/proto",
+ "//components/image_fetcher/core:core",
"//components/keyed_service/core",
"//components/leveldb_proto",
"//net",
@@ -37,6 +42,7 @@ source_set("core_unit_tests") {
testonly = true
sources = [
"feed_image_database_unittest.cc",
+ "feed_image_manager_unittest.cc",
"feed_networking_host_unittest.cc",
]
@@ -52,5 +58,6 @@ source_set("core_unit_tests") {
"//services/network/public/cpp",
"//services/network/public/mojom",
"//third_party/zlib/google:compression_utils",
+ "//ui/gfx:test_support",
]
}
diff --git a/chromium/components/feed/core/feed_host_service.cc b/chromium/components/feed/core/feed_host_service.cc
new file mode 100644
index 00000000000..72e985c4b47
--- /dev/null
+++ b/chromium/components/feed/core/feed_host_service.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/feed/core/feed_host_service.h"
+
+#include <utility>
+
+namespace feed {
+
+FeedHostService::FeedHostService(
+ std::unique_ptr<FeedImageManager> image_manager,
+ std::unique_ptr<FeedNetworkingHost> networking_host)
+ : image_manager_(std::move(image_manager)),
+ networking_host_(std::move(networking_host)) {}
+
+FeedHostService::~FeedHostService() = default;
+
+FeedImageManager* FeedHostService::GetImageManager() {
+ return image_manager_.get();
+}
+
+FeedNetworkingHost* FeedHostService::GetNetworkingHost() {
+ return networking_host_.get();
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/feed_host_service.h b/chromium/components/feed/core/feed_host_service.h
new file mode 100644
index 00000000000..4270b317f14
--- /dev/null
+++ b/chromium/components/feed/core/feed_host_service.h
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_FEED_CORE_FEED_HOST_SERVICE_H_
+#define COMPONENTS_FEED_CORE_FEED_HOST_SERVICE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/feed/core/feed_image_manager.h"
+#include "components/feed/core/feed_networking_host.h"
+#include "components/keyed_service/core/keyed_service.h"
+
+namespace feed {
+
+// KeyedService responsible for managing the lifetime of Feed Host API
+// implementations. It instantiates and owns these API implementations, and
+// provides access to non-owning pointers to them. While host implementations
+// may be created on demand, it is possible they will not be fully initialized
+// yet.
+class FeedHostService : public KeyedService {
+ public:
+ FeedHostService(std::unique_ptr<FeedImageManager> image_manager,
+ std::unique_ptr<FeedNetworkingHost> networking_host);
+ ~FeedHostService() override;
+
+ FeedImageManager* GetImageManager();
+ FeedNetworkingHost* GetNetworkingHost();
+
+ private:
+ std::unique_ptr<FeedImageManager> image_manager_;
+ std::unique_ptr<FeedNetworkingHost> networking_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeedHostService);
+};
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_FEED_HOST_SERVICE_H_
diff --git a/chromium/components/feed/core/feed_image_database.cc b/chromium/components/feed/core/feed_image_database.cc
index 4656729bff9..ab5934b331c 100644
--- a/chromium/components/feed/core/feed_image_database.cc
+++ b/chromium/components/feed/core/feed_image_database.cc
@@ -98,16 +98,26 @@ void FeedImageDatabase::LoadImage(const std::string& url,
}
}
-void FeedImageDatabase::GarbageCollectImages(base::Time expired_time) {
+void FeedImageDatabase::DeleteImage(const std::string& url) {
+ DeleteImageImpl(url, base::BindOnce(&FeedImageDatabase::OnImageUpdated,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void FeedImageDatabase::GarbageCollectImages(
+ base::Time expired_time,
+ FeedImageDatabaseOperationCallback callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // If database is not initiailzed yet, ignore the request.
- if (!IsInitialized())
+ // If database is not initialized yet, ignore the request.
+ if (!IsInitialized()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), false));
return;
+ }
- image_database_->LoadEntries(
- base::BindOnce(&FeedImageDatabase::GarbageCollectImagesImpl,
- weak_ptr_factory_.GetWeakPtr(), expired_time));
+ image_database_->LoadEntries(base::BindOnce(
+ &FeedImageDatabase::GarbageCollectImagesImpl,
+ weak_ptr_factory_.GetWeakPtr(), expired_time, std::move(callback)));
}
void FeedImageDatabase::OnDatabaseInitialized(bool success) {
@@ -180,28 +190,53 @@ void FeedImageDatabase::OnImageUpdated(bool success) {
DVLOG_IF(1, !success) << "FeedImageDatabase update failed.";
}
+void FeedImageDatabase::DeleteImageImpl(
+ const std::string& url,
+ FeedImageDatabaseOperationCallback callback) {
+ image_database_->UpdateEntries(
+ std::make_unique<ImageKeyEntryVector>(),
+ std::make_unique<std::vector<std::string>>(1, url), std::move(callback));
+}
+
void FeedImageDatabase::GarbageCollectImagesImpl(
base::Time expired_time,
+ FeedImageDatabaseOperationCallback callback,
bool load_entries_success,
std::unique_ptr<std::vector<CachedImageProto>> image_entries) {
if (!load_entries_success) {
- DVLOG(1) << "FeedImageDatabase garbage collection failed.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&FeedImageDatabase::OnGarbageCollectionDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(callback), false));
return;
}
int64_t expired_database_time = ToDatabaseTime(expired_time);
auto keys_to_remove = std::make_unique<std::vector<std::string>>();
for (const CachedImageProto& image : *image_entries) {
- if (image.last_used_time() < expired_database_time)
+ if (image.last_used_time() < expired_database_time) {
keys_to_remove->emplace_back(image.url());
+ }
}
- if (keys_to_remove->empty())
+
+ if (keys_to_remove->empty()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), true));
return;
+ }
image_database_->UpdateEntries(
std::make_unique<ImageKeyEntryVector>(), std::move(keys_to_remove),
- base::BindOnce(&FeedImageDatabase::OnImageUpdated,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&FeedImageDatabase::OnGarbageCollectionDone,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+}
+
+void FeedImageDatabase::OnGarbageCollectionDone(
+ FeedImageDatabaseOperationCallback callback,
+ bool success) {
+ DVLOG_IF(1, !success) << "FeedImageDatabase garbage collection failed.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), success));
}
} // namespace feed
diff --git a/chromium/components/feed/core/feed_image_database.h b/chromium/components/feed/core/feed_image_database.h
index 7fdaa9a0c1c..9aa594e7775 100644
--- a/chromium/components/feed/core/feed_image_database.h
+++ b/chromium/components/feed/core/feed_image_database.h
@@ -27,6 +27,8 @@ class FeedImageDatabase {
// Returns the resulting raw image data as std::string of a |LoadImage| call.
using FeedImageDatabaseCallback = base::OnceCallback<void(std::string)>;
+ using FeedImageDatabaseOperationCallback = base::OnceCallback<void(bool)>;
+
// Initializes the database with |database_dir|.
explicit FeedImageDatabase(const base::FilePath& database_dir);
// Initializes the database with |database_dir|. Creates storage using the
@@ -54,9 +56,15 @@ class FeedImageDatabase {
// request will be pending until the database has been initialized.
void LoadImage(const std::string& url, FeedImageDatabaseCallback callback);
- // Deletes all images which are older than |expired_time|.
- // If database is not initialized, the call will be ignored.
- void GarbageCollectImages(base::Time expired_time);
+ // Deletes the image data for the |url|.
+ void DeleteImage(const std::string& url);
+
+ // Delete all images whose |last_used_time| is older than |expired_time| and
+ // passes the result to |callback|. |callback| will be called in the same
+ // thread as this function called. If database is not initialized, or failed
+ // to delete expired entry, false will be passed to |callback|.
+ void GarbageCollectImages(base::Time expired_time,
+ FeedImageDatabaseOperationCallback callback);
private:
friend class FeedImageDatabaseTest;
@@ -80,11 +88,18 @@ class FeedImageDatabase {
bool success,
std::unique_ptr<CachedImageProto> entry);
+ // Deleting
+ void DeleteImageImpl(const std::string& url,
+ FeedImageDatabaseOperationCallback callback);
+
// Garbage collection
void GarbageCollectImagesImpl(
base::Time expired_time,
+ FeedImageDatabaseOperationCallback callback,
bool load_entries_success,
std::unique_ptr<std::vector<CachedImageProto>> image_entries);
+ void OnGarbageCollectionDone(FeedImageDatabaseOperationCallback callback,
+ bool success);
State database_status_;
diff --git a/chromium/components/feed/core/feed_image_database_unittest.cc b/chromium/components/feed/core/feed_image_database_unittest.cc
index 0b82c4cb098..5052f560656 100644
--- a/chromium/components/feed/core/feed_image_database_unittest.cc
+++ b/chromium/components/feed/core/feed_image_database_unittest.cc
@@ -64,6 +64,7 @@ class FeedImageDatabaseTest : public testing::Test {
void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
MOCK_METHOD1(OnImageLoaded, void(std::string));
+ MOCK_METHOD1(OnGarbageCollected, void(bool));
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
@@ -214,6 +215,36 @@ TEST_F(FeedImageDatabaseTest, LoadUpdatesTime) {
EXPECT_TRUE(old_time != GetImageLastUsedTime(kImageURL));
}
+TEST_F(FeedImageDatabaseTest, Delete) {
+ CreateDatabase();
+ image_db()->InitCallback(true);
+ ASSERT_TRUE(db()->IsInitialized());
+
+ // Store the image.
+ db()->SaveImage(kImageURL, kImageData);
+ image_db()->UpdateCallback(true);
+
+ // Make sure the image is there.
+ EXPECT_CALL(*this, OnImageLoaded(kImageData));
+ db()->LoadImage(kImageURL,
+ base::BindOnce(&FeedImageDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ image_db()->GetCallback(true);
+
+ Mock::VerifyAndClearExpectations(this);
+
+ // Delete the image.
+ db()->DeleteImage(kImageURL);
+ image_db()->UpdateCallback(true);
+
+ // Make sure the image is gone.
+ EXPECT_CALL(*this, OnImageLoaded(std::string()));
+ db()->LoadImage(kImageURL,
+ base::BindOnce(&FeedImageDatabaseTest::OnImageLoaded,
+ base::Unretained(this)));
+ image_db()->GetCallback(true);
+}
+
TEST_F(FeedImageDatabaseTest, GarbageCollectImagesTest) {
CreateDatabase();
image_db()->InitCallback(true);
@@ -229,10 +260,14 @@ TEST_F(FeedImageDatabaseTest, GarbageCollectImagesTest) {
InjectImageProto("url3", "data3", very_old_time);
// Garbage collect all except the second.
- db()->GarbageCollectImages(expired_time);
+ EXPECT_CALL(*this, OnGarbageCollected(true));
+ db()->GarbageCollectImages(
+ expired_time, base::BindOnce(&FeedImageDatabaseTest::OnGarbageCollected,
+ base::Unretained(this)));
// This will first load all images, then delete the expired ones.
image_db()->LoadCallback(true);
image_db()->UpdateCallback(true);
+ RunUntilIdle();
// Make sure the images are gone.
EXPECT_CALL(*this, OnImageLoaded(std::string()));
diff --git a/chromium/components/feed/core/feed_image_manager.cc b/chromium/components/feed/core/feed_image_manager.cc
new file mode 100644
index 00000000000..719b7774e4e
--- /dev/null
+++ b/chromium/components/feed/core/feed_image_manager.cc
@@ -0,0 +1,209 @@
+// 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 "components/feed/core/feed_image_manager.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "components/feed/core/time_serialization.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image.h"
+
+namespace feed {
+
+namespace {
+const int kDefaultGarbageCollectionExpiredDays = 30;
+const int kLongGarbageCollectionInterval = 12 * 60 * 60; // 12 hours
+const int kShortGarbageCollectionInterval = 5 * 60; // 5 minutes
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+ net::DefineNetworkTrafficAnnotation("feed_image_fetcher", R"(
+ semantics {
+ sender: "Feed Library Image Fetch"
+ description:
+ "Retrieves images for content suggestions, for display on the "
+ "New Tab page."
+ trigger:
+ "Triggered when the user looks at a content suggestion (and its "
+ "thumbnail isn't cached yet)."
+ data: "None."
+ destination: GOOGLE_OWNED_SERVICE
+ }
+ policy {
+ cookies_allowed: NO
+ setting:
+ "This can be disabled from the New Tab Page by collapsing the "
+ "articles section."
+ chrome_policy {
+ NTPContentSuggestionsEnabled {
+ NTPContentSuggestionsEnabled: false
+ }
+ }
+ })");
+
+} // namespace
+
+FeedImageManager::FeedImageManager(
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
+ std::unique_ptr<FeedImageDatabase> image_database)
+ : image_garbage_collected_day_(FromDatabaseTime(0)),
+ image_fetcher_(std::move(image_fetcher)),
+ image_database_(std::move(image_database)),
+ weak_ptr_factory_(this) {
+ DoGarbageCollectionIfNeeded();
+}
+
+FeedImageManager::~FeedImageManager() {
+ StopGarbageCollection();
+}
+
+void FeedImageManager::FetchImage(std::vector<std::string> urls,
+ ImageFetchedCallback callback) {
+ DCHECK(image_database_);
+
+ FetchImagesFromDatabase(0, std::move(urls), std::move(callback));
+}
+
+void FeedImageManager::FetchImagesFromDatabase(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback) {
+ if (url_index >= urls.size()) {
+ // Already reached the last entry. Return an empty image.
+ std::move(callback).Run(gfx::Image());
+ return;
+ }
+
+ std::string image_id = urls[url_index];
+ image_database_->LoadImage(
+ image_id, base::BindOnce(&FeedImageManager::OnImageFetchedFromDatabase,
+ weak_ptr_factory_.GetWeakPtr(), url_index,
+ std::move(urls), std::move(callback)));
+}
+
+void FeedImageManager::OnImageFetchedFromDatabase(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ std::string image_data) {
+ if (image_data.empty()) {
+ // Fetching from the DB failed; start a network fetch.
+ FetchImageFromNetwork(url_index, std::move(urls), std::move(callback));
+ return;
+ }
+
+ image_fetcher_->GetImageDecoder()->DecodeImage(
+ image_data, gfx::Size(),
+ base::BindRepeating(&FeedImageManager::OnImageDecodedFromDatabase,
+ weak_ptr_factory_.GetWeakPtr(), url_index,
+ std::move(urls), base::Passed(std::move(callback))));
+}
+
+void FeedImageManager::OnImageDecodedFromDatabase(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ const gfx::Image& image) {
+ if (image.IsEmpty()) {
+ // If decoding the image failed, delete the DB entry.
+ image_database_->DeleteImage(urls[url_index]);
+ FetchImageFromNetwork(url_index, std::move(urls), std::move(callback));
+ return;
+ }
+
+ std::move(callback).Run(image);
+}
+
+void FeedImageManager::FetchImageFromNetwork(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback) {
+ GURL url(urls[url_index]);
+ if (!url.is_valid()) {
+ // url is not valid, go to next URL.
+ FetchImagesFromDatabase(url_index + 1, std::move(urls),
+ std::move(callback));
+ return;
+ }
+
+ image_fetcher_->FetchImageData(
+ url.spec(), url,
+ base::BindOnce(&FeedImageManager::OnImageFetchedFromNetwork,
+ weak_ptr_factory_.GetWeakPtr(), url_index, std::move(urls),
+ std::move(callback)),
+ kTrafficAnnotation);
+}
+
+void FeedImageManager::OnImageFetchedFromNetwork(
+ size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ const std::string& image_data,
+ const image_fetcher::RequestMetadata& request_metadata) {
+ if (image_data.empty()) {
+ // Fetching image failed, let's move to the next url.
+ FetchImagesFromDatabase(url_index + 1, std::move(urls),
+ std::move(callback));
+ return;
+ }
+
+ image_fetcher_->GetImageDecoder()->DecodeImage(
+ image_data, gfx::Size(),
+ base::BindRepeating(&FeedImageManager::OnImageDecodedFromNetwork,
+ weak_ptr_factory_.GetWeakPtr(), url_index,
+ std::move(urls), base::Passed(std::move(callback)),
+ image_data));
+}
+
+void FeedImageManager::OnImageDecodedFromNetwork(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ const std::string& image_data,
+ const gfx::Image& image) {
+ // Decoding urls[url_index] failed, let's move to the next url.
+ if (image.IsEmpty()) {
+ FetchImagesFromDatabase(url_index + 1, std::move(urls),
+ std::move(callback));
+ return;
+ }
+
+ image_database_->SaveImage(urls[url_index], image_data);
+ std::move(callback).Run(image);
+}
+
+void FeedImageManager::DoGarbageCollectionIfNeeded() {
+ // For saving resource purpose(ex. cpu, battery), We round up garbage
+ // collection age to day, so we only run GC once a day.
+ base::Time to_be_expired =
+ base::Time::Now().LocalMidnight() -
+ base::TimeDelta::FromDays(kDefaultGarbageCollectionExpiredDays);
+ if (image_garbage_collected_day_ != to_be_expired) {
+ image_database_->GarbageCollectImages(
+ to_be_expired,
+ base::BindOnce(&FeedImageManager::OnGarbageCollectionDone,
+ weak_ptr_factory_.GetWeakPtr(), to_be_expired));
+ }
+}
+
+void FeedImageManager::OnGarbageCollectionDone(base::Time garbage_collected_day,
+ bool success) {
+ base::TimeDelta gc_delay =
+ base::TimeDelta::FromSeconds(kShortGarbageCollectionInterval);
+ if (success) {
+ if (image_garbage_collected_day_ < garbage_collected_day)
+ image_garbage_collected_day_ = garbage_collected_day;
+ gc_delay = base::TimeDelta::FromSeconds(kLongGarbageCollectionInterval);
+ }
+
+ garbage_collection_timer_.Start(
+ FROM_HERE, gc_delay, this,
+ &FeedImageManager::DoGarbageCollectionIfNeeded);
+}
+
+void FeedImageManager::StopGarbageCollection() {
+ garbage_collection_timer_.Stop();
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/feed_image_manager.h b/chromium/components/feed/core/feed_image_manager.h
new file mode 100644
index 00000000000..4618b3f9938
--- /dev/null
+++ b/chromium/components/feed/core/feed_image_manager.h
@@ -0,0 +1,98 @@
+// 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 COMPONENTS_FEED_CORE_FEED_IMAGE_MANAGER_H_
+#define COMPONENTS_FEED_CORE_FEED_IMAGE_MANAGER_H_
+
+#include "base/memory/weak_ptr.h"
+#include "base/timer/timer.h"
+#include "components/feed/core/feed_image_database.h"
+
+namespace gfx {
+class Image;
+} // namespace gfx
+
+namespace image_fetcher {
+class ImageFetcher;
+struct RequestMetadata;
+} // namespace image_fetcher
+
+namespace feed {
+
+using ImageFetchedCallback = base::OnceCallback<void(const gfx::Image&)>;
+
+// FeedImageManager takes care of fetching images from the network and caching
+// them in the database.
+class FeedImageManager {
+ public:
+ FeedImageManager(std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher,
+ std::unique_ptr<FeedImageDatabase> image_database);
+ ~FeedImageManager();
+
+ // Fetches an image from |urls|.
+ // FeedImageManager will go through URLs in |urls| one by one trying to fetch
+ // and decode them in order. Upon success, a decoded image will be passed to
+ // |callback| as well as cached locally. |urls| should be supplied in priority
+ // order, and the first success will prevent any further processing. Failure
+ // to fetch or decode an image will cause FeedImageManager to process the next
+ // URL in |urls|. If FeedImageManager failed to fetch and decode all the URLs
+ // in |urls|, it will pass an empty image to |callback|. |callback| will be
+ // called exactly once.
+ void FetchImage(std::vector<std::string> urls, ImageFetchedCallback callback);
+
+ private:
+ friend class FeedImageManagerTest;
+
+ // Database
+ void FetchImagesFromDatabase(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback);
+ void OnImageFetchedFromDatabase(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ std::string image_data);
+ void OnImageDecodedFromDatabase(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ const gfx::Image& image);
+
+ // Network
+ void FetchImageFromNetwork(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback);
+ void OnImageFetchedFromNetwork(
+ size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ const std::string& image_data,
+ const image_fetcher::RequestMetadata& request_metadata);
+ void OnImageDecodedFromNetwork(size_t url_index,
+ std::vector<std::string> urls,
+ ImageFetchedCallback callback,
+ const std::string& image_data,
+ const gfx::Image& image);
+
+ // Garbage collection will be run when FeedImageManager starts up, and then
+ // once a day. Garbage collection will remove images, that have not been
+ // touched for 30 days.
+ void DoGarbageCollectionIfNeeded();
+ void OnGarbageCollectionDone(base::Time garbage_collected_day, bool success);
+ void StopGarbageCollection();
+
+ // The day which image database already ran garbage collection against on.
+ base::Time image_garbage_collected_day_;
+
+ base::OneShotTimer garbage_collection_timer_;
+
+ std::unique_ptr<image_fetcher::ImageFetcher> image_fetcher_;
+ std::unique_ptr<FeedImageDatabase> image_database_;
+
+ base::WeakPtrFactory<FeedImageManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeedImageManager);
+};
+
+} // namespace feed
+
+#endif // COMPONENTS_FEED_CORE_FEED_IMAGE_MANAGER_H_
diff --git a/chromium/components/feed/core/feed_image_manager_unittest.cc b/chromium/components/feed/core/feed_image_manager_unittest.cc
new file mode 100644
index 00000000000..bc3fd3812f2
--- /dev/null
+++ b/chromium/components/feed/core/feed_image_manager_unittest.cc
@@ -0,0 +1,269 @@
+// 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 "components/feed/core/feed_image_manager.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "components/image_fetcher/core/image_decoder.h"
+#include "components/image_fetcher/core/image_fetcher_impl.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_unittest_util.h"
+
+using testing::_;
+
+namespace feed {
+
+namespace {
+const char kImageURL[] = "http://pie.com/";
+const char kImageURL2[] = "http://cake.com/";
+const char kImageData[] = "pie image";
+const char kImageData2[] = "cake image";
+
+class FakeImageDecoder : public image_fetcher::ImageDecoder {
+ public:
+ void DecodeImage(
+ const std::string& image_data,
+ const gfx::Size& desired_image_frame_size,
+ const image_fetcher::ImageDecodedCallback& callback) override {
+ gfx::Image image;
+ if (valid_ && !image_data.empty()) {
+ ASSERT_EQ(image_data_, image_data);
+ image = gfx::test::CreateImage();
+ }
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindRepeating(callback, image));
+ }
+ void SetDecodingValid(bool valid) { valid_ = valid; }
+ void SetExpectedData(std::string data) { image_data_ = data; }
+
+ private:
+ bool valid_ = true;
+ std::string image_data_;
+};
+
+} // namespace
+
+class FeedImageManagerTest : public testing::Test {
+ public:
+ FeedImageManagerTest() : fake_url_fetcher_factory_(nullptr) {}
+
+ ~FeedImageManagerTest() override {
+ feed_image_manager_.reset();
+ // We need to run until idle after deleting the database, because
+ // ProtoDatabaseImpl deletes the actual LevelDB asynchronously.
+ RunUntilIdle();
+ }
+
+ void SetUp() override {
+ ASSERT_TRUE(database_dir_.CreateUniqueTempDir());
+
+ std::unique_ptr<FeedImageDatabase> image_database =
+ std::make_unique<FeedImageDatabase>(database_dir_.GetPath());
+ image_database_ = image_database.get();
+
+ request_context_getter_ = scoped_refptr<net::TestURLRequestContextGetter>(
+ new net::TestURLRequestContextGetter(
+ scoped_task_environment_.GetMainThreadTaskRunner()));
+
+ auto decoder = std::make_unique<FakeImageDecoder>();
+ decoder->SetExpectedData(kImageData);
+ fake_image_decoder_ = decoder.get();
+
+ feed_image_manager_ = std::make_unique<FeedImageManager>(
+ std::make_unique<image_fetcher::ImageFetcherImpl>(
+ std::move(decoder), request_context_getter_.get()),
+ std::move(image_database));
+
+ RunUntilIdle();
+
+ ASSERT_TRUE(image_database_->IsInitialized());
+ }
+
+ void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
+
+ FeedImageDatabase* image_database() { return image_database_; }
+
+ FeedImageManager* feed_image_manager() { return feed_image_manager_.get(); }
+
+ base::OneShotTimer& garbage_collection_timer() {
+ return feed_image_manager_->garbage_collection_timer_;
+ }
+
+ void StartGarbageCollection() {
+ feed_image_manager_->DoGarbageCollectionIfNeeded();
+ }
+
+ void StopGarbageCollection() { feed_image_manager_->StopGarbageCollection(); }
+
+ FakeImageDecoder* fake_image_decoder() { return fake_image_decoder_; }
+
+ net::FakeURLFetcherFactory* fake_url_fetcher_factory() {
+ return &fake_url_fetcher_factory_;
+ }
+
+ MOCK_METHOD1(OnImageLoaded, void(std::string));
+
+ private:
+ std::unique_ptr<FeedImageManager> feed_image_manager_;
+ FeedImageDatabase* image_database_;
+ base::ScopedTempDir database_dir_;
+ FakeImageDecoder* fake_image_decoder_;
+ scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+ net::FakeURLFetcherFactory fake_url_fetcher_factory_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeedImageManagerTest);
+};
+
+TEST_F(FeedImageManagerTest, FetchEmptyUrlVector) {
+ base::MockCallback<ImageFetchedCallback> image_callback;
+
+ // Make sure an empty image passed to callback.
+ EXPECT_CALL(image_callback,
+ Run(testing::Property(&gfx::Image::IsEmpty, testing::Eq(true))));
+ feed_image_manager()->FetchImage(std::vector<std::string>(),
+ image_callback.Get());
+
+ RunUntilIdle();
+}
+
+TEST_F(FeedImageManagerTest, FetchImageFromCache) {
+ // Save the image in the database.
+ image_database()->SaveImage(kImageURL, kImageData);
+ RunUntilIdle();
+
+ base::MockCallback<ImageFetchedCallback> image_callback;
+ EXPECT_CALL(image_callback,
+ Run(testing::Property(&gfx::Image::IsEmpty, testing::Eq(false))));
+ feed_image_manager()->FetchImage(std::vector<std::string>({kImageURL}),
+ image_callback.Get());
+
+ RunUntilIdle();
+}
+
+TEST_F(FeedImageManagerTest, FetchImagePopulatesCache) {
+ // Expect the image to be fetched by URL.
+ {
+ fake_url_fetcher_factory()->SetFakeResponse(GURL(kImageURL), kImageData,
+ net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ base::MockCallback<ImageFetchedCallback> image_callback;
+ EXPECT_CALL(image_callback, Run(testing::Property(&gfx::Image::IsEmpty,
+ testing::Eq(false))));
+ feed_image_manager()->FetchImage(std::vector<std::string>({kImageURL}),
+ image_callback.Get());
+
+ RunUntilIdle();
+ }
+ // Make sure the image data is in the database.
+ {
+ EXPECT_CALL(*this, OnImageLoaded(kImageData));
+ image_database()->LoadImage(
+ kImageURL, base::BindOnce(&FeedImageManagerTest::OnImageLoaded,
+ base::Unretained(this)));
+ RunUntilIdle();
+ }
+ // Fetch again. The cache should be populated, no network request is needed.
+ {
+ fake_url_fetcher_factory()->ClearFakeResponses();
+ base::MockCallback<ImageFetchedCallback> image_callback;
+ EXPECT_CALL(image_callback, Run(testing::Property(&gfx::Image::IsEmpty,
+ testing::Eq(false))));
+ feed_image_manager()->FetchImage(std::vector<std::string>({kImageURL}),
+ image_callback.Get());
+
+ RunUntilIdle();
+ }
+}
+
+TEST_F(FeedImageManagerTest, FetchSecondImageIfFirstFailed) {
+ // Expect the image to be fetched by URL.
+ {
+ fake_url_fetcher_factory()->SetFakeResponse(GURL(kImageURL), kImageData,
+ net::HTTP_NOT_FOUND,
+ net::URLRequestStatus::FAILED);
+ fake_url_fetcher_factory()->SetFakeResponse(GURL(kImageURL2), kImageData2,
+ net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ base::MockCallback<ImageFetchedCallback> image_callback;
+ EXPECT_CALL(image_callback, Run(testing::Property(&gfx::Image::IsEmpty,
+ testing::Eq(false))));
+ fake_image_decoder()->SetExpectedData(kImageData2);
+ feed_image_manager()->FetchImage(
+ std::vector<std::string>({kImageURL, kImageURL2}),
+ image_callback.Get());
+
+ RunUntilIdle();
+ }
+ // Make sure the image data is in the database.
+ {
+ EXPECT_CALL(*this, OnImageLoaded(kImageData2));
+ image_database()->LoadImage(
+ kImageURL2, base::BindOnce(&FeedImageManagerTest::OnImageLoaded,
+ base::Unretained(this)));
+ RunUntilIdle();
+ }
+}
+
+TEST_F(FeedImageManagerTest, DecodingErrorWillDeleteCache) {
+ // Save the image in the database.
+ image_database()->SaveImage(kImageURL, kImageData);
+ RunUntilIdle();
+ {
+ fake_url_fetcher_factory()->SetFakeResponse(GURL(kImageURL), kImageData,
+ net::HTTP_OK,
+ net::URLRequestStatus::SUCCESS);
+ // Set decoding always error.
+ fake_image_decoder()->SetDecodingValid(false);
+ base::MockCallback<ImageFetchedCallback> image_callback;
+
+ EXPECT_CALL(image_callback, Run(testing::Property(&gfx::Image::IsEmpty,
+ testing::Eq(true))));
+ feed_image_manager()->FetchImage(std::vector<std::string>({kImageURL}),
+ image_callback.Get());
+
+ RunUntilIdle();
+ }
+ // Make sure the image data was deleted from database.
+ {
+ EXPECT_CALL(*this, OnImageLoaded(std::string()));
+ image_database()->LoadImage(
+ kImageURL, base::BindOnce(&FeedImageManagerTest::OnImageLoaded,
+ base::Unretained(this)));
+ RunUntilIdle();
+ }
+}
+
+TEST_F(FeedImageManagerTest, GarbageCollectionRunOnStart) {
+ // Garbage Collection is scheduled by default.
+ EXPECT_TRUE(garbage_collection_timer().IsRunning());
+
+ StopGarbageCollection();
+ EXPECT_FALSE(garbage_collection_timer().IsRunning());
+
+ // StartGarbageCollection will start the garbage collection, but won't
+ // schedule the next one.
+ StartGarbageCollection();
+ EXPECT_FALSE(garbage_collection_timer().IsRunning());
+
+ // After finishing the garbage collection cycle, the next garbage collection
+ // will be scheduled.
+ RunUntilIdle();
+ EXPECT_TRUE(garbage_collection_timer().IsRunning());
+}
+
+} // namespace feed
diff --git a/chromium/components/feed/core/feed_networking_host.cc b/chromium/components/feed/core/feed_networking_host.cc
index 0949a62a129..f665392ee4a 100644
--- a/chromium/components/feed/core/feed_networking_host.cc
+++ b/chromium/components/feed/core/feed_networking_host.cc
@@ -4,6 +4,8 @@
#include "components/feed/core/feed_networking_host.h"
+#include <utility>
+
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/values.h"
@@ -45,13 +47,12 @@ namespace feed {
// second to the specified url.
class NetworkFetch {
public:
- NetworkFetch(
- const GURL& url,
- const std::string& request_type,
- std::vector<uint8_t> request_body,
- IdentityManager* identity_manager,
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
- const std::string& api_key);
+ NetworkFetch(const GURL& url,
+ const std::string& request_type,
+ std::vector<uint8_t> request_body,
+ IdentityManager* identity_manager,
+ network::SharedURLLoaderFactory* loader_factory,
+ const std::string& api_key);
void Start(FeedNetworkingHost::ResponseCallback done);
@@ -71,27 +72,25 @@ class NetworkFetch {
const std::vector<uint8_t> request_body_;
IdentityManager* const identity_manager_;
std::unique_ptr<identity::PrimaryAccountAccessTokenFetcher> token_fetcher_;
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info_;
std::unique_ptr<network::SimpleURLLoader> simple_loader_;
FeedNetworkingHost::ResponseCallback done_callback_;
- scoped_refptr<network::SharedURLLoaderFactory> loader_factory_ = nullptr;
+ network::SharedURLLoaderFactory* loader_factory_;
const std::string api_key_;
DISALLOW_COPY_AND_ASSIGN(NetworkFetch);
};
-NetworkFetch::NetworkFetch(
- const GURL& url,
- const std::string& request_type,
- std::vector<uint8_t> request_body,
- IdentityManager* identity_manager,
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
- const std::string& api_key)
+NetworkFetch::NetworkFetch(const GURL& url,
+ const std::string& request_type,
+ std::vector<uint8_t> request_body,
+ IdentityManager* identity_manager,
+ network::SharedURLLoaderFactory* loader_factory,
+ const std::string& api_key)
: url_(url),
request_type_(request_type),
request_body_(std::move(request_body)),
identity_manager_(identity_manager),
- loader_factory_info_(std::move(loader_factory_info)),
+ loader_factory_(loader_factory),
api_key_(api_key) {}
void NetworkFetch::Start(FeedNetworkingHost::ResponseCallback done_callback) {
@@ -125,12 +124,9 @@ void NetworkFetch::AccessTokenFetchFinished(const GoogleServiceAuthError& error,
void NetworkFetch::StartLoader(const std::string& access_token) {
simple_loader_ = MakeLoader(access_token);
- loader_factory_ =
- network::SharedURLLoaderFactory::Create(std::move(loader_factory_info_));
simple_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
- loader_factory_.get(),
- base::BindOnce(&NetworkFetch::OnSimpleLoaderComplete,
- base::Unretained(this)));
+ loader_factory_, base::BindOnce(&NetworkFetch::OnSimpleLoaderComplete,
+ base::Unretained(this)));
}
std::unique_ptr<network::SimpleURLLoader> NetworkFetch::MakeLoader(
@@ -163,7 +159,6 @@ std::unique_ptr<network::SimpleURLLoader> NetworkFetch::MakeLoader(
}
}
})");
-
GURL url(url_);
if (access_token.empty() && !api_key_.empty())
url = net::AppendQueryParameter(url_, kApiKeyQueryParam, api_key_);
@@ -250,8 +245,11 @@ void NetworkFetch::OnSimpleLoaderComplete(
FeedNetworkingHost::FeedNetworkingHost(
identity::IdentityManager* identity_manager,
- const std::string& api_key)
- : identity_manager_(identity_manager), api_key_(api_key) {}
+ const std::string& api_key,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory)
+ : identity_manager_(identity_manager),
+ api_key_(api_key),
+ loader_factory_(loader_factory) {}
FeedNetworkingHost::~FeedNetworkingHost() = default;
@@ -260,14 +258,13 @@ void FeedNetworkingHost::CancelRequests() {
}
void FeedNetworkingHost::Send(
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
const GURL& url,
const std::string& request_type,
std::vector<uint8_t> request_body,
ResponseCallback callback) {
auto fetch = std::make_unique<NetworkFetch>(
url, request_type, std::move(request_body), identity_manager_,
- std::move(loader_factory_info), api_key_);
+ loader_factory_.get(), api_key_);
NetworkFetch* fetch_unowned = fetch.get();
pending_requests_.emplace(std::move(fetch));
diff --git a/chromium/components/feed/core/feed_networking_host.h b/chromium/components/feed/core/feed_networking_host.h
index ca88553e691..31770d0fcff 100644
--- a/chromium/components/feed/core/feed_networking_host.h
+++ b/chromium/components/feed/core/feed_networking_host.h
@@ -7,12 +7,15 @@
#include <stdint.h>
+#include <memory>
+#include <string>
#include <vector>
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "url/gurl.h"
namespace identity {
@@ -20,7 +23,7 @@ class IdentityManager;
}
namespace network {
-class SharedURLLoaderFactoryInfo;
+class SharedURLLoaderFactory;
}
namespace feed {
@@ -38,8 +41,10 @@ class FeedNetworkingHost {
base::OnceCallback<void(int32_t status_code,
std::vector<uint8_t> response_bytes)>;
- FeedNetworkingHost(identity::IdentityManager* identity_manager,
- const std::string& api_key);
+ FeedNetworkingHost(
+ identity::IdentityManager* identity_manager,
+ const std::string& api_key,
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory);
~FeedNetworkingHost();
@@ -50,10 +55,8 @@ class FeedNetworkingHost {
// Start a request to |url| of type |request_type| with body |request_body|.
// |callback| will be called when the response is received or if there is
// an error, including non-protocol errors. The contents of |request_body|
- // will be gzipped. Uses |loader_factory| to construct the url loader that
- // performs the request.
+ // will be gzipped.
void Send(
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> loader_factory_info,
const GURL& url,
const std::string& request_type,
std::vector<uint8_t> request_body,
@@ -69,6 +72,7 @@ class FeedNetworkingHost {
pending_requests_;
identity::IdentityManager* identity_manager_;
const std::string api_key_;
+ scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
DISALLOW_COPY_AND_ASSIGN(FeedNetworkingHost);
};
diff --git a/chromium/components/feed/core/feed_networking_host_unittest.cc b/chromium/components/feed/core/feed_networking_host_unittest.cc
index d89e5f687d0..228276029a3 100644
--- a/chromium/components/feed/core/feed_networking_host_unittest.cc
+++ b/chromium/components/feed/core/feed_networking_host_unittest.cc
@@ -4,6 +4,8 @@
#include "components/feed/core/feed_networking_host.h"
+#include <utility>
+
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/test/histogram_tester.h"
@@ -61,6 +63,10 @@ class TestSharedURLLoaderFactory : public SharedURLLoaderFactory {
std::move(client), traffic_annotation);
}
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+ NOTREACHED();
+ }
+
std::unique_ptr<SharedURLLoaderFactoryInfo> Clone() override {
NOTREACHED();
return nullptr;
@@ -75,30 +81,6 @@ class TestSharedURLLoaderFactory : public SharedURLLoaderFactory {
TestURLLoaderFactory test_factory_;
};
-// Class that produces a TestSharedURLLoaderFactory instance when asked to
-// create a SharedURLLoaderFactory.
-class TestURLLoaderFactoryInfo : public network::SharedURLLoaderFactoryInfo {
- public:
- TestURLLoaderFactoryInfo() {
- loader_factory_ = base::MakeRefCounted<TestSharedURLLoaderFactory>();
- }
- ~TestURLLoaderFactoryInfo() override = default;
-
- TestURLLoaderFactory* GetTestFactory() {
- return loader_factory_->test_factory();
- }
-
- protected:
- // SharedURLLoaderFactoryInfo implementation.
- scoped_refptr<SharedURLLoaderFactory> CreateFactory() override {
- return loader_factory_;
- }
-
- private:
- scoped_refptr<TestSharedURLLoaderFactory> loader_factory_;
- DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactoryInfo);
-};
-
} // namespace
class FeedNetworkingHostTest : public testing::Test {
@@ -114,11 +96,8 @@ class FeedNetworkingHostTest : public testing::Test {
void SetUp() override {
net_service_ = std::make_unique<FeedNetworkingHost>(
- identity_test_env_.identity_manager(), "dummy_api_key");
- }
-
- std::unique_ptr<TestURLLoaderFactoryInfo> MakeFactoryInfo() {
- return std::make_unique<TestURLLoaderFactoryInfo>();
+ identity_test_env_.identity_manager(), "dummy_api_key",
+ test_loader_factory_);
}
FeedNetworkingHost* service() { return net_service_.get(); }
@@ -129,8 +108,7 @@ class FeedNetworkingHostTest : public testing::Test {
void RunUntilEmpty() { mock_task_runner_->FastForwardUntilNoTasksRemain(); }
- void Respond(TestURLLoaderFactory* loader_factory,
- const GURL& url,
+ void Respond(const GURL& url,
const std::string& response_string,
net::HttpStatusCode code = net::HTTP_OK,
network::URLLoaderCompletionStatus status =
@@ -142,7 +120,8 @@ class FeedNetworkingHostTest : public testing::Test {
status.decoded_body_length = response_string.length();
}
- loader_factory->AddResponse(url, head, response_string, status);
+ test_loader_factory_->test_factory()->AddResponse(url, head,
+ response_string, status);
RunUntilEmpty();
}
@@ -157,15 +136,11 @@ class FeedNetworkingHostTest : public testing::Test {
GURL req_url(url_string);
std::vector<uint8_t> request_body(request_string.begin(),
request_string.end());
-
- std::unique_ptr<TestURLLoaderFactoryInfo> factory_info = MakeFactoryInfo();
- TestURLLoaderFactory* test_factory = factory_info->GetTestFactory();
- service()->Send(std::move(factory_info), req_url, request_type,
- request_body,
+ service()->Send(req_url, request_type, request_body,
base::BindOnce(&MockResponseDoneCallback::Done,
base::Unretained(done_callback)));
- Respond(test_factory, req_url, response_string, code, status);
+ Respond(req_url, response_string, code, status);
}
void SendRequestAndValidateResponse(
@@ -190,6 +165,8 @@ class FeedNetworkingHostTest : public testing::Test {
scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_;
identity::IdentityTestEnvironment identity_test_env_;
std::unique_ptr<FeedNetworkingHost> net_service_;
+ scoped_refptr<TestSharedURLLoaderFactory> test_loader_factory_ =
+ base::MakeRefCounted<TestSharedURLLoaderFactory>();
DISALLOW_COPY_AND_ASSIGN(FeedNetworkingHostTest);
};
@@ -306,14 +283,12 @@ TEST_F(FeedNetworkingHostTest, CancellationIsSafe) {
MockResponseDoneCallback done_callback2;
std::vector<uint8_t> request_body;
- service()->Send(MakeFactoryInfo(), GURL("http://foobar.com/feed"), "POST",
- request_body,
+ service()->Send(GURL("http://foobar.com/feed"), "POST", request_body,
base::BindOnce(&MockResponseDoneCallback::Done,
base::Unretained(&done_callback)));
identity_env()->SetAutomaticIssueOfAccessTokens(false);
- service()->Send(MakeFactoryInfo(), GURL("http://foobar.com/feed2"), "POST",
- request_body,
+ service()->Send(GURL("http://foobar.com/feed2"), "POST", request_body,
base::BindOnce(&MockResponseDoneCallback::Done,
base::Unretained(&done_callback2)));
RunUntilEmpty();
@@ -325,17 +300,15 @@ TEST_F(FeedNetworkingHostTest, ShouldIncludeAPIKeyForAuthError) {
MockResponseDoneCallback done_callback;
base::HistogramTester histogram_tester;
- auto factory_info = MakeFactoryInfo();
- TestURLLoaderFactory* test_factory = factory_info->GetTestFactory();
- service()->Send(std::move(factory_info), GURL("http://foobar.com/feed"),
- "POST", std::vector<uint8_t>(),
+ service()->Send(GURL("http://foobar.com/feed"), "POST",
+ std::vector<uint8_t>(),
base::BindOnce(&MockResponseDoneCallback::Done,
base::Unretained(&done_callback)));
- identity_env()->WaitForAccessTokenRequestAndRespondWithError(
+ identity_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(
GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
- Respond(test_factory, GURL("http://foobar.com/feed?key=dummy_api_key"), "");
+ Respond(GURL("http://foobar.com/feed?key=dummy_api_key"), "");
EXPECT_TRUE(done_callback.has_run);
EXPECT_THAT(
@@ -353,14 +326,12 @@ TEST_F(FeedNetworkingHostTest, ShouldIncludeAPIKeyForNoSignedInUser) {
identity_env()->ClearPrimaryAccount();
MockResponseDoneCallback done_callback;
- auto factory_info = MakeFactoryInfo();
- TestURLLoaderFactory* test_factory = factory_info->GetTestFactory();
- service()->Send(std::move(factory_info), GURL("http://foobar.com/feed"),
- "POST", std::vector<uint8_t>(),
+ service()->Send(GURL("http://foobar.com/feed"), "POST",
+ std::vector<uint8_t>(),
base::BindOnce(&MockResponseDoneCallback::Done,
base::Unretained(&done_callback)));
- Respond(test_factory, GURL("http://foobar.com/feed?key=dummy_api_key"), "");
+ Respond(GURL("http://foobar.com/feed?key=dummy_api_key"), "");
EXPECT_TRUE(done_callback.has_run);
}
#endif
diff --git a/chromium/components/feedback/anonymizer_tool.cc b/chromium/components/feedback/anonymizer_tool.cc
index 73f2f97d291..f9f1fd6a7d4 100644
--- a/chromium/components/feedback/anonymizer_tool.cc
+++ b/chromium/components/feedback/anonymizer_tool.cc
@@ -77,7 +77,7 @@ constexpr const char* kCustomPatternsWithContext[] = {
#define PCT_ENCODED "%" HEXDIG HEXDIG
-#define DEC_OCTET NCG("[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-9]")
+#define DEC_OCTET NCG("1[0-9][0-9]|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9]")
#define IPV4ADDRESS DEC_OCTET "\\." DEC_OCTET "\\." DEC_OCTET "\\." DEC_OCTET
diff --git a/chromium/components/feedback/anonymizer_tool_unittest.cc b/chromium/components/feedback/anonymizer_tool_unittest.cc
index fc51ba3be9e..ef800baf4f9 100644
--- a/chromium/components/feedback/anonymizer_tool_unittest.cc
+++ b/chromium/components/feedback/anonymizer_tool_unittest.cc
@@ -208,7 +208,10 @@ TEST_F(AnonymizerToolTest, AnonymizeChunk) {
"aaaaaaaahttp://tets.comaaaaaaa\n" // URL.
"aaaaaemail@example.comaaa\n" // Email address.
"example@@1234\n" // No PII, it is not valid email address.
+ "255.255.155.2\n" // IP address.
"255.255.155.255\n" // IP address.
+ "255.255.259.255\n" // Not an IP address.
+ "255.300.255.255\n" // Not an IP address.
"aaaa123.123.45.4aaa\n" // IP address.
"11:11;11::11\n" // IP address.
"11::11\n" // IP address.
@@ -219,8 +222,11 @@ TEST_F(AnonymizerToolTest, AnonymizeChunk) {
"aaaaaaaa<URL: 1>\n"
"<email: 1>\n"
"example@@1234\n"
- "<IPv4: 1>55\n"
- "aaaa<IPv4: 2>aaa\n"
+ "<IPv4: 1>\n"
+ "<IPv4: 2>\n"
+ "255.255.259.255\n"
+ "255.300.255.255\n"
+ "aaaa<IPv4: 3>aaa\n"
"11:11;<IPv6: 1>\n"
"<IPv6: 1>\n"
"11:11:abcdef:0:0:0:0:0\n"
diff --git a/chromium/components/feedback/feedback_report.cc b/chromium/components/feedback/feedback_report.cc
index 5acb44b2a1c..faa5c7781e0 100644
--- a/chromium/components/feedback/feedback_report.cc
+++ b/chromium/components/feedback/feedback_report.cc
@@ -82,8 +82,6 @@ void FeedbackReport::DeleteReportOnDisk() {
base::Bind(base::IgnoreResult(&base::DeleteFile), file_, false));
}
-FeedbackReport::~FeedbackReport() {
- DeleteReportOnDisk();
-}
+FeedbackReport::~FeedbackReport() {}
} // namespace feedback
diff --git a/chromium/components/feedback/feedback_uploader.cc b/chromium/components/feedback/feedback_uploader.cc
index 7bd55ba97fb..fe1670461ce 100644
--- a/chromium/components/feedback/feedback_uploader.cc
+++ b/chromium/components/feedback/feedback_uploader.cc
@@ -84,6 +84,7 @@ void FeedbackUploader::OnReportUploadSuccess() {
retry_delay_ = g_minimum_retry_delay;
is_dispatching_ = false;
// Explicitly release the successfully dispatched report.
+ report_being_dispatched_->DeleteReportOnDisk();
report_being_dispatched_ = nullptr;
UpdateUploadTimer();
}
@@ -94,6 +95,9 @@ void FeedbackUploader::OnReportUploadFailure(bool should_retry) {
retry_delay_ *= 2;
report_being_dispatched_->set_upload_at(retry_delay_ + base::Time::Now());
reports_queue_.emplace(report_being_dispatched_);
+ } else {
+ // The report won't be retried, hence explicitly delete its file on disk.
+ report_being_dispatched_->DeleteReportOnDisk();
}
// The report dispatching failed, and should either be retried or not. In all
diff --git a/chromium/components/feedback/feedback_uploader_unittest.cc b/chromium/components/feedback/feedback_uploader_unittest.cc
index 7abe3aea312..d9bf658d3c2 100644
--- a/chromium/components/feedback/feedback_uploader_unittest.cc
+++ b/chromium/components/feedback/feedback_uploader_unittest.cc
@@ -13,6 +13,7 @@
#include "base/stl_util.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "components/feedback/feedback_report.h"
#include "components/feedback/feedback_uploader_factory.h"
#include "content/public/test/test_browser_context.h"
@@ -46,6 +47,15 @@ class MockFeedbackUploader : public FeedbackUploader {
run_loop_->Run();
}
+ void SimulateLoadingOfflineReports() {
+ task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &FeedbackReport::LoadReportsAndQueue, feedback_reports_path(),
+ base::Bind(&MockFeedbackUploader::QueueSingleReport,
+ base::SequencedTaskRunnerHandle::Get(), this)));
+ }
+
const std::map<std::string, unsigned int>& dispatched_reports() const {
return dispatched_reports_;
}
@@ -53,6 +63,15 @@ class MockFeedbackUploader : public FeedbackUploader {
void set_simulate_failure(bool value) { simulate_failure_ = value; }
private:
+ static void QueueSingleReport(
+ scoped_refptr<base::SequencedTaskRunner> main_task_runner,
+ MockFeedbackUploader* uploader,
+ const std::string& data) {
+ main_task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&MockFeedbackUploader::QueueReport,
+ uploader->AsWeakPtr(), data));
+ }
+
// FeedbackUploaderChrome:
void StartDispatchingReport() override {
if (base::ContainsKey(dispatched_reports_,
@@ -93,11 +112,15 @@ class FeedbackUploaderTest : public testing::Test {
public:
FeedbackUploaderTest() {
FeedbackUploader::SetMinimumRetryDelayForTesting(kRetryDelayForTest);
- uploader_ = std::make_unique<MockFeedbackUploader>(&context_);
+ RecreateUploader();
}
~FeedbackUploaderTest() override = default;
+ void RecreateUploader() {
+ uploader_ = std::make_unique<MockFeedbackUploader>(&context_);
+ }
+
void QueueReport(const std::string& data) {
uploader_->QueueReport(data);
}
@@ -156,4 +179,32 @@ TEST_F(FeedbackUploaderTest, QueueMultipleWithFailures) {
EXPECT_EQ(uploader()->dispatched_reports().at(kReportFive), 1u);
}
+TEST_F(FeedbackUploaderTest, SimulateOfflineReports) {
+ // Simulate offline reports by failing to upload three reports.
+ uploader()->set_simulate_failure(true);
+ QueueReport(kReportOne);
+ QueueReport(kReportTwo);
+ QueueReport(kReportThree);
+
+ // All three reports will be attempted to be uploaded, but the uploader queue
+ // will remain having three reports since they all failed.
+ uploader()->set_expected_reports(3);
+ uploader()->RunMessageLoop();
+ EXPECT_EQ(uploader()->dispatched_reports().size(), 3u);
+ EXPECT_FALSE(uploader()->QueueEmpty());
+
+ // Simulate a sign out / resign in by recreating the uploader. This should not
+ // clear any pending feedback report files on disk, and hence they can be
+ // reloaded.
+ RecreateUploader();
+ uploader()->SimulateLoadingOfflineReports();
+ uploader()->set_expected_reports(3);
+ uploader()->RunMessageLoop();
+
+ // The three reports were loaded, successfully uploaded, and the uploader
+ // queue is now empty.
+ EXPECT_EQ(uploader()->dispatched_reports().size(), 3u);
+ EXPECT_TRUE(uploader()->QueueEmpty());
+}
+
} // namespace feedback
diff --git a/chromium/components/flags_ui/BUILD.gn b/chromium/components/flags_ui/BUILD.gn
index 9d085a16ad0..e554054df0a 100644
--- a/chromium/components/flags_ui/BUILD.gn
+++ b/chromium/components/flags_ui/BUILD.gn
@@ -26,6 +26,7 @@ static_library("flags_ui") {
"//components/strings",
"//components/variations",
"//ui/base",
+ "//url",
]
}
diff --git a/chromium/components/flags_ui/DEPS b/chromium/components/flags_ui/DEPS
index ad5532c4903..89103e5eb46 100644
--- a/chromium/components/flags_ui/DEPS
+++ b/chromium/components/flags_ui/DEPS
@@ -4,4 +4,5 @@ include_rules = [
"+components/strings/grit/components_strings.h",
"+components/variations",
"+ui/base",
+ "+url",
]
diff --git a/chromium/components/flags_ui/feature_entry.h b/chromium/components/flags_ui/feature_entry.h
index 073eceae435..15a2610091b 100644
--- a/chromium/components/flags_ui/feature_entry.h
+++ b/chromium/components/flags_ui/feature_entry.h
@@ -73,6 +73,10 @@ struct FeatureEntry {
// feature is overriden to be enabled and empty set of parameters is used
// boiling down to the default behavior in the code.
FEATURE_WITH_PARAMS_VALUE,
+
+ // Corresponds to a command line switch where the value is treatead as a
+ // list of url::Origins. Default state is disabled like SINGLE_VALUE.
+ ORIGIN_LIST_VALUE
};
// Describes state of a feature.
diff --git a/chromium/components/flags_ui/feature_entry_macros.h b/chromium/components/flags_ui/feature_entry_macros.h
index e474374de19..3d520711aa2 100644
--- a/chromium/components/flags_ui/feature_entry_macros.h
+++ b/chromium/components/flags_ui/feature_entry_macros.h
@@ -15,6 +15,9 @@
nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr
#define SINGLE_VALUE_TYPE(command_line_switch) \
SINGLE_VALUE_TYPE_AND_VALUE(command_line_switch, "")
+#define ORIGIN_LIST_VALUE_TYPE(command_line_switch, switch_value) \
+ flags_ui::FeatureEntry::ORIGIN_LIST_VALUE, command_line_switch, \
+ switch_value, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr
#define SINGLE_DISABLE_VALUE_TYPE_AND_VALUE(command_line_switch, switch_value) \
flags_ui::FeatureEntry::SINGLE_DISABLE_VALUE, command_line_switch, \
switch_value, nullptr, nullptr, nullptr, 0, nullptr, nullptr, nullptr
diff --git a/chromium/components/flags_ui/flags_state.cc b/chromium/components/flags_ui/flags_state.cc
index b28bd45acb0..7218bfd52c0 100644
--- a/chromium/components/flags_ui/flags_state.cc
+++ b/chromium/components/flags_ui/flags_state.cc
@@ -16,6 +16,7 @@
#include "base/metrics/field_trial.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
+#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
@@ -25,6 +26,8 @@
#include "components/flags_ui/flags_ui_switches.h"
#include "components/variations/variations_associated_data.h"
#include "ui/base/l10n/l10n_util.h"
+#include "url/gurl.h"
+#include "url/origin.h"
namespace flags_ui {
@@ -116,6 +119,7 @@ void AddInternalName(const FeatureEntry& e, std::set<std::string>* names) {
switch (e.type) {
case FeatureEntry::SINGLE_VALUE:
case FeatureEntry::SINGLE_DISABLE_VALUE:
+ case FeatureEntry::ORIGIN_LIST_VALUE:
names->insert(e.internal_name);
break;
case FeatureEntry::MULTI_VALUE:
@@ -134,6 +138,7 @@ bool ValidateFeatureEntry(const FeatureEntry& e) {
switch (e.type) {
case FeatureEntry::SINGLE_VALUE:
case FeatureEntry::SINGLE_DISABLE_VALUE:
+ case FeatureEntry::ORIGIN_LIST_VALUE:
DCHECK_EQ(0, e.num_options);
DCHECK(!e.choices);
return true;
@@ -174,6 +179,7 @@ bool IsDefaultValue(const FeatureEntry& entry,
switch (entry.type) {
case FeatureEntry::SINGLE_VALUE:
case FeatureEntry::SINGLE_DISABLE_VALUE:
+ case FeatureEntry::ORIGIN_LIST_VALUE:
return enabled_entries.count(entry.internal_name) == 0;
case FeatureEntry::MULTI_VALUE:
case FeatureEntry::ENABLE_DISABLE_VALUE:
@@ -235,6 +241,51 @@ base::FieldTrial* RegisterFeatureVariationParameters(
return trial;
}
+// Returns true if |value| is safe to include in a command line string in the
+// form of --flag=value.
+bool IsSafeValue(const std::string& value) {
+ // Punctuation characters at the end ("-", ".", ":", "/") are allowed because
+ // origins can contain those (e.g. http://example.test). Comma is allowed
+ // because it's used as the separator character.
+ static const char kAllowedChars[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "-.:/,";
+ return value.find_first_not_of(kAllowedChars) == std::string::npos;
+}
+
+// Sanitizes |value| which contains a list of origins separated by whitespace
+// and/or comma. The sanitized value is added as a command line argument, so
+// this is a security critical operation: The sanitized value must have no
+// whitespaces, each individual origin must be separated by a comma, and each
+// origin must represent a url::Origin().
+std::string SanitizeOriginListFlag(const std::string& value) {
+ const std::string input = base::CollapseWhitespaceASCII(value, false);
+ const std::string delimiters = " ,";
+ base::StringTokenizer tokenizer(input, delimiters);
+ std::vector<std::string> origin_strings;
+ while (tokenizer.GetNext()) {
+ const std::string token = tokenizer.token();
+ if (token.empty()) {
+ continue;
+ }
+ const GURL url(token);
+ if (!url.is_valid() ||
+ (!url.SchemeIsHTTPOrHTTPS() && !url.SchemeIsWSOrWSS())) {
+ continue;
+ }
+ const std::string origin = url::Origin::Create(url).Serialize();
+ if (!IsSafeValue(origin)) {
+ continue;
+ }
+ origin_strings.push_back(origin);
+ }
+ const std::string result = base::JoinString(origin_strings, ",");
+ CHECK(IsSafeValue(result));
+ return result;
+}
+
} // namespace
struct FlagsState::SwitchEntry {
@@ -347,20 +398,20 @@ void FlagsState::SetFeatureEntryEnabled(FlagsStorage* flags_storage,
std::set<std::string> enabled_entries;
GetSanitizedEnabledFlags(flags_storage, &enabled_entries);
- const FeatureEntry* e = nullptr;
- for (size_t i = 0; i < num_feature_entries_; ++i) {
- if (feature_entries_[i].internal_name == internal_name) {
- e = feature_entries_ + i;
- break;
- }
- }
+ const FeatureEntry* e = FindFeatureEntryByName(internal_name);
DCHECK(e);
- if (e->type == FeatureEntry::SINGLE_VALUE) {
+ if (e->type == FeatureEntry::SINGLE_VALUE ||
+ e->type == FeatureEntry::ORIGIN_LIST_VALUE) {
if (enable)
needs_restart_ |= enabled_entries.insert(internal_name).second;
else
needs_restart_ |= (enabled_entries.erase(internal_name) > 0);
+
+ // If an origin list was enabled or disabled, update the command line flag.
+ if (e->type == FeatureEntry::ORIGIN_LIST_VALUE)
+ DidModifyOriginListFlag(*e, enable);
+
} else if (e->type == FeatureEntry::SINGLE_DISABLE_VALUE) {
if (!enable)
needs_restart_ |= enabled_entries.insert(internal_name).second;
@@ -387,6 +438,21 @@ void FlagsState::SetFeatureEntryEnabled(FlagsStorage* flags_storage,
flags_storage->SetFlags(enabled_entries);
}
+void FlagsState::SetOriginListFlag(const std::string& internal_name,
+ const std::string& value,
+ FlagsStorage* flags_storage) {
+ const FeatureEntry* entry = FindFeatureEntryByName(internal_name);
+ DCHECK(entry);
+
+ std::set<std::string> enabled_entries;
+ GetSanitizedEnabledFlags(flags_storage, &enabled_entries);
+ // const bool enabled =
+ // enabled_entries.find(entry->internal_name) != enabled_entries.end();
+ const bool enabled = base::ContainsKey(enabled_entries, entry->internal_name);
+ switch_values_[entry->command_line_switch] = value;
+ DidModifyOriginListFlag(*entry, enabled);
+}
+
void FlagsState::RemoveFlagsSwitches(
base::CommandLine::SwitchMap* switch_list) {
for (const auto& entry : flags_switches_)
@@ -547,6 +613,14 @@ void FlagsState::GetFlagFeatureEntries(
(is_default_value &&
entry.type == FeatureEntry::SINGLE_DISABLE_VALUE));
break;
+ case FeatureEntry::ORIGIN_LIST_VALUE:
+ data->SetBoolean("enabled", !is_default_value);
+ switch_values_[entry.internal_name] =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ entry.command_line_switch);
+ data->SetString("origin_list_value",
+ switch_values_[entry.internal_name]);
+ break;
case FeatureEntry::MULTI_VALUE:
case FeatureEntry::ENABLE_DISABLE_VALUE:
case FeatureEntry::FEATURE_VALUE:
@@ -665,6 +739,14 @@ void FlagsState::AddSwitchesToCommandLine(
continue;
}
+ const FeatureEntry* feature_entry = FindFeatureEntryByName(entry_name);
+ if (feature_entry &&
+ feature_entry->type == FeatureEntry::ORIGIN_LIST_VALUE) {
+ // This is not a feature value that can be enabled/disabled, it's a
+ // command line argument that takes a list of origins. Skip it.
+ continue;
+ }
+
const SwitchEntry& entry = entry_it->second;
if (!entry.feature_name.empty()) {
feature_switches[entry.feature_name] = entry.feature_state;
@@ -780,6 +862,16 @@ void FlagsState::GenerateFlagsToSwitchesMapping(
AddSwitchMapping(e.internal_name, e.command_line_switch,
e.command_line_value, name_to_switch_map);
break;
+
+ case FeatureEntry::ORIGIN_LIST_VALUE: {
+ const std::string value =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ e.command_line_switch);
+ AddSwitchMapping(e.internal_name, e.command_line_switch, value,
+ name_to_switch_map);
+ break;
+ }
+
case FeatureEntry::MULTI_VALUE:
for (int j = 0; j < e.num_options; ++j) {
AddSwitchMapping(
@@ -787,6 +879,7 @@ void FlagsState::GenerateFlagsToSwitchesMapping(
e.ChoiceForOption(j).command_line_value, name_to_switch_map);
}
break;
+
case FeatureEntry::ENABLE_DISABLE_VALUE:
AddSwitchMapping(e.NameForOption(0), std::string(), std::string(),
name_to_switch_map);
@@ -795,6 +888,7 @@ void FlagsState::GenerateFlagsToSwitchesMapping(
AddSwitchMapping(e.NameForOption(2), e.disable_command_line_switch,
e.disable_command_line_value, name_to_switch_map);
break;
+
case FeatureEntry::FEATURE_VALUE:
case FeatureEntry::FEATURE_WITH_PARAMS_VALUE:
for (int j = 0; j < e.num_options; ++j) {
@@ -813,4 +907,40 @@ void FlagsState::GenerateFlagsToSwitchesMapping(
}
}
+void FlagsState::DidModifyOriginListFlag(const FeatureEntry& entry,
+ bool enabled) {
+ // Remove the switch if it exists.
+ base::CommandLine* current_cl = base::CommandLine::ForCurrentProcess();
+ base::CommandLine new_cl(current_cl->GetProgram());
+ const base::CommandLine::SwitchMap switches = current_cl->GetSwitches();
+ for (const auto& it : switches) {
+ const auto& switch_name = it.first;
+ const auto& switch_value = it.second;
+ if (switch_name != entry.command_line_switch) {
+ if (switch_value.empty()) {
+ new_cl.AppendSwitch(switch_name);
+ } else {
+ new_cl.AppendSwitchNative(switch_name, switch_value);
+ }
+ }
+ }
+ *current_cl = new_cl;
+
+ if (enabled) {
+ current_cl->AppendSwitchASCII(
+ entry.command_line_switch,
+ SanitizeOriginListFlag(switch_values_[entry.command_line_switch]));
+ }
+}
+
+const FeatureEntry* FlagsState::FindFeatureEntryByName(
+ const std::string& internal_name) const {
+ for (size_t i = 0; i < num_feature_entries_; ++i) {
+ if (feature_entries_[i].internal_name == internal_name) {
+ return feature_entries_ + i;
+ }
+ }
+ return nullptr;
+}
+
} // namespace flags_ui
diff --git a/chromium/components/flags_ui/flags_state.h b/chromium/components/flags_ui/flags_state.h
index 8540ce8ff26..0ec9b0690e5 100644
--- a/chromium/components/flags_ui/flags_state.h
+++ b/chromium/components/flags_ui/flags_state.h
@@ -84,6 +84,15 @@ class FlagsState {
void SetFeatureEntryEnabled(FlagsStorage* flags_storage,
const std::string& internal_name,
bool enable);
+
+ // Sets |value| as the command line switch for feature given by
+ // |internal_name|. |value| contains a list of origins (serialized form of
+ // url::Origin()) separated by whitespace and/or comma. Invalid values in this
+ // list are ignored.
+ void SetOriginListFlag(const std::string& internal_name,
+ const std::string& value,
+ FlagsStorage* flags_storage);
+
void RemoveFlagsSwitches(base::CommandLine::SwitchMap* switch_list);
void ResetAllFlags(FlagsStorage* flags_storage);
void Reset();
@@ -190,6 +199,16 @@ class FlagsState {
std::set<std::string>* enabled_entries,
std::map<std::string, SwitchEntry>* name_to_switch_map);
+ // Called when the value of an entry with ORIGIN_LIST_VALUE is modified.
+ // Modifies the corresponding command line by adding or removing the switch
+ // based on the value of |enabled|.
+ void DidModifyOriginListFlag(const FeatureEntry& entry, bool enabled);
+
+ // Returns the FeatureEntry named |internal_name|. Returns null if no entry is
+ // matched.
+ const FeatureEntry* FindFeatureEntryByName(
+ const std::string& internal_name) const;
+
const FeatureEntry* feature_entries_;
size_t num_feature_entries_;
@@ -200,6 +219,10 @@ class FlagsState {
// were appended to existing (list value) switches.
std::map<std::string, std::set<std::string>> appended_switches_;
+ // Map from switch name to switch value. Only filled for features with
+ // ORIGIN_LIST_VALUE type.
+ std::map<std::string, std::string> switch_values_;
+
DISALLOW_COPY_AND_ASSIGN(FlagsState);
};
diff --git a/chromium/components/flags_ui/flags_state_unittest.cc b/chromium/components/flags_ui/flags_state_unittest.cc
index 9524d907902..17a8a9ed7f4 100644
--- a/chromium/components/flags_ui/flags_state_unittest.cc
+++ b/chromium/components/flags_ui/flags_state_unittest.cc
@@ -46,6 +46,7 @@ const char kFlags7[] = "flag7";
const char kFlags8[] = "flag8";
const char kFlags9[] = "flag9";
const char kFlags10[] = "flag10";
+const char kFlags11[] = "flag11";
const char kSwitch1[] = "switch";
const char kSwitch2[] = "switch2";
@@ -53,6 +54,9 @@ const char kSwitch3[] = "switch3";
const char kSwitch6[] = "switch6";
const char kValueForSwitch2[] = "value_for_switch2";
+const char kStringSwitch[] = "string_switch";
+const char kValueForStringSwitch[] = "value_for_string_switch";
+
const char kMultiSwitch1[] = "multi_switch1";
const char kMultiSwitch2[] = "multi_switch2";
const char kValueForMultiSwitch2[] = "value_for_multi_switch2";
@@ -143,7 +147,10 @@ static FeatureEntry kEntries[] = {
0, // Ends up being mapped to the current platform.
FeatureEntry::FEATURE_WITH_PARAMS_VALUE, nullptr, nullptr, nullptr,
nullptr, &kTestFeature2, 4, nullptr, kTestVariations2, kTestTrial},
-};
+ {kFlags11, kDummyName, kDummyDescription,
+ 0, // Ends up being mapped to the current platform.
+ FeatureEntry::ORIGIN_LIST_VALUE, kStringSwitch, kValueForStringSwitch,
+ nullptr, nullptr, nullptr /* feature */, 0, nullptr, nullptr, nullptr}};
class FlagsStateTest : public ::testing::Test {
protected:
@@ -886,7 +893,7 @@ TEST_F(FlagsStateTest, GetFlagFeatureEntries) {
&supported_entries, &unsupported_entries,
base::Bind(&SkipFeatureEntry));
// All |kEntries| except for |kFlags3| should be supported.
- EXPECT_EQ(9u, supported_entries.GetSize());
+ EXPECT_EQ(10u, supported_entries.GetSize());
EXPECT_EQ(1u, unsupported_entries.GetSize());
EXPECT_EQ(arraysize(kEntries),
supported_entries.GetSize() + unsupported_entries.GetSize());
diff --git a/chromium/components/flags_ui/flags_ui_constants.cc b/chromium/components/flags_ui/flags_ui_constants.cc
index 2b902245bf7..a3e2b1c9313 100644
--- a/chromium/components/flags_ui/flags_ui_constants.cc
+++ b/chromium/components/flags_ui/flags_ui_constants.cc
@@ -12,6 +12,7 @@ const char kFlagsJS[] = "flags.js";
// Message handlers.
const char kEnableExperimentalFeature[] = "enableExperimentalFeature";
const char kRequestExperimentalFeatures[] = "requestExperimentalFeatures";
+const char kSetOriginListFlag[] = "setOriginListFlag";
const char kResetAllFlags[] = "resetAllFlags";
const char kRestartBrowser[] = "restartBrowser";
diff --git a/chromium/components/flags_ui/flags_ui_constants.h b/chromium/components/flags_ui/flags_ui_constants.h
index 67442bc9ff4..5a3300ae68b 100644
--- a/chromium/components/flags_ui/flags_ui_constants.h
+++ b/chromium/components/flags_ui/flags_ui_constants.h
@@ -15,6 +15,7 @@ extern const char kFlagsJS[];
// Must match the constants used in the resource files.
extern const char kEnableExperimentalFeature[];
extern const char kRequestExperimentalFeatures[];
+extern const char kSetOriginListFlag[];
extern const char kResetAllFlags[];
extern const char kRestartBrowser[];
diff --git a/chromium/components/flags_ui/resources/flags.css b/chromium/components/flags_ui/resources/flags.css
index faca70f8111..b068942318e 100644
--- a/chromium/components/flags_ui/resources/flags.css
+++ b/chromium/components/flags_ui/resources/flags.css
@@ -260,6 +260,17 @@ h2 {
width: 100%;
}
+.experiment-origin-list-value {
+ border: 1px solid var(--color-light-gray);
+ border-radius: 3px;
+ box-sizing: border-box;
+ font-size: 1em;
+ margin: 0;
+ min-height: 3em;
+ padding: 8px;
+ width: 100%;
+}
+
.experiment-switched .experiment-actions select {
background: var(--google-blue-700);
color: white;
diff --git a/chromium/components/flags_ui/resources/flags.html b/chromium/components/flags_ui/resources/flags.html
index b19625a6eb2..a91d6d623e4 100644
--- a/chromium/components/flags_ui/resources/flags.html
+++ b/chromium/components/flags_ui/resources/flags.html
@@ -87,6 +87,11 @@
<span jsvalues=".innerHTML:description"></span> –
<span class="platforms" jscontent="supported_platforms.join(', ')"></span>
</p>
+ <div jsdisplay="origin_list_value!==null">
+ <textarea class="experiment-origin-list-value"
+ jsvalues=".internal_name:internal_name; .value:origin_list_value"
+ tabindex="7"></textarea>
+ </div>
<a class="permalink" jsvalues="href: '#' + internal_name"
jscontent="'#' + internal_name" tabindex="6"></a>
</div>
@@ -126,6 +131,11 @@
<span jsvalues=".innerHTML:description"></span> –
<span class="platforms" jscontent="supported_platforms.join(', ')"></span>
</p>
+ <div jsdisplay="origin_list_value!==null">
+ <textarea class="experiment-origin-list-value"
+ jsvalues=".internal_name:internal_name; .value:origin_list_value"
+ tabindex="7"></textarea>
+ </div>
<a class="permalink" jsvalues="href: '#' + internal_name"
jscontent="'#' + internal_name" tabindex="6"></a>
</div>
@@ -177,7 +187,7 @@
</p>
<a class="permalink"
jsvalues="href: '#' + internal_name"
- jscontent="'#' + internal_name" tabindex="7"></a>
+ jscontent="'#' + internal_name" tabindex="8"></a>
</div>
<div class="flex experiment-actions">Not available on your platform.</div>
</div>
@@ -194,7 +204,7 @@
<div class="flex restart-notice" jstcache="0">$i18n{flagsRestartNotice}</div>
<div class="flex">
<if expr="not is_ios">
- <button class="experiment-restart-button" type="button" tabindex="8">
+ <button class="experiment-restart-button" type="button" tabindex="9">
<if expr="not is_chromeos">
Relaunch Now
</if>
diff --git a/chromium/components/flags_ui/resources/flags.js b/chromium/components/flags_ui/resources/flags.js
index 807533b75dd..4508cfaf414 100644
--- a/chromium/components/flags_ui/resources/flags.js
+++ b/chromium/components/flags_ui/resources/flags.js
@@ -36,6 +36,14 @@ function renderTemplate(experimentalFeaturesData) {
};
}
+ elements = document.getElementsByClassName('experiment-origin-list-value');
+ for (var i = 0; i < elements.length; ++i) {
+ elements[i].onchange = function() {
+ handleSetOriginListFlag(this, this.value);
+ return false;
+ };
+ }
+
elements = document.getElementsByClassName('experiment-restart-button');
for (var i = 0; i < elements.length; ++i) {
elements[i].onclick = restartBrowser;
@@ -206,6 +214,11 @@ function handleEnableExperimentalFeature(node, enable) {
experimentChangesUiUpdates(node, enable ? 1 : 0);
}
+function handleSetOriginListFlag(node, value) {
+ chrome.send('setOriginListFlag', [String(node.internal_name), String(value)]);
+ $('needs-restart').classList.add('show');
+}
+
/**
* Invoked when the selection of a multi-value choice is changed to the
* specified index.
@@ -286,6 +299,9 @@ FlagSearch.prototype = {
this.clearSearch.bind(this));
window.addEventListener('keyup', function(e) {
+ if (document.activeElement.nodeName == "TEXTAREA") {
+ return;
+ }
switch(e.key) {
case '/':
this.searchBox_.focus();
diff --git a/chromium/components/gcm_driver/BUILD.gn b/chromium/components/gcm_driver/BUILD.gn
index cc148aeaddc..ad729b9c8d4 100644
--- a/chromium/components/gcm_driver/BUILD.gn
+++ b/chromium/components/gcm_driver/BUILD.gn
@@ -14,8 +14,6 @@ static_library("gcm_driver") {
sources = [
"features.cc",
"features.h",
- "gcm_account_tracker.cc",
- "gcm_account_tracker.h",
"gcm_activity.cc",
"gcm_activity.h",
"gcm_app_handler.cc",
@@ -88,8 +86,12 @@ static_library("gcm_driver") {
]
} else {
sources += [
+ "account_tracker.cc",
+ "account_tracker.h",
"gcm_account_mapper.cc",
"gcm_account_mapper.h",
+ "gcm_account_tracker.cc",
+ "gcm_account_tracker.h",
"gcm_channel_status_request.cc",
"gcm_channel_status_request.h",
"gcm_channel_status_syncer.cc",
@@ -169,7 +171,6 @@ source_set("unit_tests") {
testonly = true
sources = [
- "gcm_account_tracker_unittest.cc",
"gcm_delayed_task_controller_unittest.cc",
"gcm_stats_recorder_android_unittest.cc",
]
@@ -192,11 +193,18 @@ source_set("unit_tests") {
if (!use_gcm_from_platform) {
sources += [
+ "account_tracker_unittest.cc",
"gcm_account_mapper_unittest.cc",
+ "gcm_account_tracker_unittest.cc",
"gcm_channel_status_request_unittest.cc",
"gcm_client_impl_unittest.cc",
"gcm_driver_desktop_unittest.cc",
"gcm_stats_recorder_impl_unittest.cc",
]
}
+ deps += [
+ "//components/signin/core/browser",
+ "//components/signin/core/browser:test_support",
+ "//components/sync_preferences:test_support",
+ ]
}
diff --git a/chromium/components/gcm_driver/instance_id/BUILD.gn b/chromium/components/gcm_driver/instance_id/BUILD.gn
index 94e750ee7dc..b0936a16171 100644
--- a/chromium/components/gcm_driver/instance_id/BUILD.gn
+++ b/chromium/components/gcm_driver/instance_id/BUILD.gn
@@ -12,10 +12,15 @@ static_library("instance_id") {
"instance_id_driver.h",
"instance_id_impl.cc",
"instance_id_impl.h",
+ "instance_id_profile_service.cc",
+ "instance_id_profile_service.h",
]
deps = [
"//base",
+ "//components/gcm_driver:gcm_buildflags",
+ "//components/keyed_service/core:core",
+ "//components/prefs:prefs",
"//crypto",
]
diff --git a/chromium/components/google/core/browser/BUILD.gn b/chromium/components/google/core/browser/BUILD.gn
index 96ada900a71..5585b30d696 100644
--- a/chromium/components/google/core/browser/BUILD.gn
+++ b/chromium/components/google/core/browser/BUILD.gn
@@ -30,6 +30,8 @@ static_library("browser") {
"//components/prefs",
"//components/strings",
"//components/url_formatter",
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
]
}
@@ -46,6 +48,9 @@ source_set("unit_tests") {
"//base",
"//components/prefs:test_support",
"//net:test_support",
+ "//services/network:test_support",
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
"//testing/gtest",
]
}
diff --git a/chromium/components/google/core/browser/DEPS b/chromium/components/google/core/browser/DEPS
index afcec3dc7e7..1b29f86f793 100644
--- a/chromium/components/google/core/browser/DEPS
+++ b/chromium/components/google/core/browser/DEPS
@@ -2,4 +2,6 @@ include_rules = [
"+components/data_use_measurement/core",
"+components/keyed_service/core",
"+components/pref_registry",
+ "+services/network/public",
+ "+services/network/test",
]
diff --git a/chromium/components/google/core/browser/google_url_tracker.cc b/chromium/components/google/core/browser/google_url_tracker.cc
index 73037f72791..133dbfea7a3 100644
--- a/chromium/components/google/core/browser/google_url_tracker.cc
+++ b/chromium/components/google/core/browser/google_url_tracker.cc
@@ -21,14 +21,15 @@
#include "components/prefs/pref_service.h"
#include "net/base/load_flags.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
-
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
const char GoogleURLTracker::kDefaultGoogleHomepage[] =
"https://www.google.com/";
const char GoogleURLTracker::kSearchDomainCheckURL[] =
"https://www.google.com/searchdomaincheck?format=domain&type=chrome";
+const base::Feature GoogleURLTracker::kNoSearchDomainCheck{
+ "NoSearchDomainCheck", base::FEATURE_DISABLED_BY_DEFAULT};
GoogleURLTracker::GoogleURLTracker(
std::unique_ptr<GoogleURLTrackerClient> client,
@@ -38,16 +39,15 @@ GoogleURLTracker::GoogleURLTracker(
mode == ALWAYS_DOT_COM_MODE
? kDefaultGoogleHomepage
: client_->GetPrefs()->GetString(prefs::kLastKnownGoogleURL)),
- fetcher_id_(0),
in_startup_sleep_(true),
- already_fetched_(false),
- need_to_fetch_(false),
+ already_loaded_(false),
+ need_to_load_(false),
weak_ptr_factory_(this) {
net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
client_->set_google_url_tracker(this);
// Because this function can be called during startup, when kicking off a URL
- // fetch can eat up 20 ms of time, we delay five seconds, which is hopefully
+ // load can eat up 20 ms of time, we delay five seconds, which is hopefully
// long enough to be after startup, but still get results back quickly.
// Ideally, instead of this timer, we'd do something like "check if the
// browser is starting up, and if so, come back later", but there is currently
@@ -57,11 +57,12 @@ GoogleURLTracker::GoogleURLTracker(
// /searchdomaincheck lookups might still be issued by calling FinishSleep
// manually).
if (mode == NORMAL_MODE) {
- static const int kStartFetchDelayMS = 5000;
+ static const int kStartLoadDelayMS = 5000;
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::Bind(&GoogleURLTracker::FinishSleep,
- weak_ptr_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(kStartFetchDelayMS));
+ FROM_HERE,
+ base::BindOnce(&GoogleURLTracker::FinishSleep,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kStartLoadDelayMS));
}
}
@@ -77,8 +78,8 @@ void GoogleURLTracker::RegisterProfilePrefs(
}
void GoogleURLTracker::RequestServerCheck() {
- if (!fetcher_)
- SetNeedToFetch();
+ if (!simple_loader_)
+ SetNeedToLoad();
}
std::unique_ptr<GoogleURLTracker::Subscription>
@@ -86,24 +87,24 @@ GoogleURLTracker::RegisterCallback(const OnGoogleURLUpdatedCallback& cb) {
return callback_list_.Add(cb);
}
-void GoogleURLTracker::OnURLFetchComplete(const net::URLFetcher* source) {
- // Delete the fetcher on this function's exit.
- std::unique_ptr<net::URLFetcher> clean_up_fetcher(std::move(fetcher_));
+void GoogleURLTracker::OnURLLoaderComplete(
+ std::unique_ptr<std::string> response_body) {
+ // Delete the loader.
+ simple_loader_.reset();
// Don't update the URL if the request didn't succeed.
- if (!source->GetStatus().is_success() || (source->GetResponseCode() != 200)) {
- already_fetched_ = false;
+ if (!response_body) {
+ already_loaded_ = false;
return;
}
- // See if the response data was valid. It should be ".google.<TLD>".
- std::string url_str;
- source->GetResponseAsString(&url_str);
- base::TrimWhitespaceASCII(url_str, base::TRIM_ALL, &url_str);
- if (!base::StartsWith(url_str, ".google.",
+ // See if the response data was valid. It should be ".google.<TLD>".
+ base::TrimWhitespaceASCII(*response_body, base::TRIM_ALL,
+ response_body.get());
+ if (!base::StartsWith(*response_body, ".google.",
base::CompareCase::INSENSITIVE_ASCII))
return;
- GURL url("https://www" + url_str);
+ GURL url("https://www" + *response_body);
if (!url.is_valid() || (url.path().length() > 1) || url.has_query() ||
url.has_ref() ||
!google_util::IsGoogleDomainUrl(url, google_util::DISALLOW_SUBDOMAIN,
@@ -123,39 +124,39 @@ void GoogleURLTracker::OnNetworkChanged(
// Ignore destructive signals.
if (type == net::NetworkChangeNotifier::CONNECTION_NONE)
return;
- already_fetched_ = false;
- StartFetchIfDesirable();
+ already_loaded_ = false;
+ StartLoadIfDesirable();
}
void GoogleURLTracker::Shutdown() {
client_.reset();
- fetcher_.reset();
+ simple_loader_.reset();
weak_ptr_factory_.InvalidateWeakPtrs();
net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
}
-void GoogleURLTracker::SetNeedToFetch() {
- need_to_fetch_ = true;
- StartFetchIfDesirable();
+void GoogleURLTracker::SetNeedToLoad() {
+ need_to_load_ = true;
+ StartLoadIfDesirable();
}
void GoogleURLTracker::FinishSleep() {
in_startup_sleep_ = false;
- StartFetchIfDesirable();
+ StartLoadIfDesirable();
}
-void GoogleURLTracker::StartFetchIfDesirable() {
- // Bail if a fetch isn't appropriate right now. This function will be called
- // again each time one of the preconditions changes, so we'll fetch
+void GoogleURLTracker::StartLoadIfDesirable() {
+ // Bail if a load isn't appropriate right now. This function will be called
+ // again each time one of the preconditions changes, so we'll load
// immediately once all of them are met.
//
// See comments in header on the class, on RequestServerCheck(), and on the
// various members here for more detail on exactly what the conditions are.
- if (in_startup_sleep_ || already_fetched_ || !need_to_fetch_)
+ if (in_startup_sleep_ || already_loaded_ || !need_to_load_)
return;
// Some switches should disable the Google URL tracker entirely. If we can't
- // do background networking, we can't do the necessary fetch, and if the user
+ // do background networking, we can't do the necessary load, and if the user
// specified a Google base URL manually, we shouldn't bother to look up any
// alternatives or offer to switch to them.
if (!client_->IsBackgroundNetworkingEnabled() ||
@@ -163,7 +164,7 @@ void GoogleURLTracker::StartFetchIfDesirable() {
switches::kGoogleBaseURL))
return;
- already_fetched_ = true;
+ already_loaded_ = true;
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("google_url_tracker", R"(
semantics {
@@ -198,30 +199,30 @@ void GoogleURLTracker::StartFetchIfDesirable() {
"not be Google. But there is no policy that controls navigation "
"error resolution."
})");
- fetcher_ =
- net::URLFetcher::Create(fetcher_id_, GURL(kSearchDomainCheckURL),
- net::URLFetcher::GET, this, traffic_annotation);
- data_use_measurement::DataUseUserData::AttachToFetcher(
- fetcher_.get(),
- data_use_measurement::DataUseUserData::GOOGLE_URL_TRACKER);
- ++fetcher_id_;
- // We don't want this fetch to set new entries in the cache or cookies, lest
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->url = GURL(kSearchDomainCheckURL);
+ // We don't want this load to set new entries in the cache or cookies, lest
// we alarm the user.
- fetcher_->SetLoadFlags(net::LOAD_DISABLE_CACHE |
- net::LOAD_DO_NOT_SAVE_COOKIES);
- fetcher_->SetRequestContext(client_->GetRequestContext());
-
- // Configure to retry at most kMaxRetries times for 5xx errors.
+ resource_request->load_flags =
+ (net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SAVE_COOKIES);
+ simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+ traffic_annotation);
+ // Configure to retry at most kMaxRetries times for 5xx errors and network
+ // changes.
+ // A network change can propagate through Chrome in various stages, so it's
+ // possible for this code to be reached via OnNetworkChanged(), and then have
+ // the load we kick off be canceled due to e.g. the DNS server changing at a
+ // later time. In general it's not possible to ensure that by the time we
+ // reach here any requests we start won't be canceled in this fashion, so
+ // retrying is the best we can do.
static const int kMaxRetries = 5;
- fetcher_->SetMaxRetriesOn5xx(kMaxRetries);
-
- // Also retry kMaxRetries times on network change errors. A network change can
- // propagate through Chrome in various stages, so it's possible for this code
- // to be reached via OnNetworkChanged(), and then have the fetch we kick off
- // be canceled due to e.g. the DNS server changing at a later time. In general
- // it's not possible to ensure that by the time we reach here any requests we
- // start won't be canceled in this fashion, so retrying is the best we can do.
- fetcher_->SetAutomaticallyRetryOnNetworkChanges(kMaxRetries);
-
- fetcher_->Start();
+ simple_loader_->SetRetryOptions(
+ kMaxRetries,
+ network::SimpleURLLoader::RetryMode::RETRY_ON_5XX |
+ network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
+ simple_loader_->DownloadToString(
+ client_->GetURLLoaderFactory(),
+ base::BindOnce(&GoogleURLTracker::OnURLLoaderComplete,
+ base::Unretained(this)),
+ 2 * 1024 /* max_body_size */);
}
diff --git a/chromium/components/google/core/browser/google_url_tracker.h b/chromium/components/google/core/browser/google_url_tracker.h
index 7588e1fe5f6..0f2526e0c6c 100644
--- a/chromium/components/google/core/browser/google_url_tracker.h
+++ b/chromium/components/google/core/browser/google_url_tracker.h
@@ -9,19 +9,22 @@
#include "base/callback_forward.h"
#include "base/callback_list.h"
+#include "base/feature_list.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/google/core/browser/google_url_tracker_client.h"
#include "components/keyed_service/core/keyed_service.h"
#include "net/base/network_change_notifier.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_fetcher_delegate.h"
#include "url/gurl.h"
namespace user_prefs {
class PrefRegistrySyncable;
}
+namespace network {
+class SimpleURLLoader;
+} // namespace network
+
// This object is responsible for checking the Google URL once per network
// change. The current value is saved to prefs.
//
@@ -32,8 +35,7 @@ class PrefRegistrySyncable;
// performed (ever) unless at least one consumer registers interest by calling
// RequestServerCheck().
class GoogleURLTracker
- : public net::URLFetcherDelegate,
- public net::NetworkChangeNotifier::NetworkChangeObserver,
+ : public net::NetworkChangeNotifier::NetworkChangeObserver,
public KeyedService {
public:
// Callback that is called when the Google URL is updated.
@@ -46,7 +48,7 @@ class GoogleURLTracker
enum Mode {
// Use current local Google TLD.
// Defer network requests to update TLD until 5 seconds after
- // creation, to avoid an expensive fetch during Chrome startup.
+ // creation, to avoid an expensive load during Chrome startup.
NORMAL_MODE,
// Always use www.google.com.
@@ -55,6 +57,12 @@ class GoogleURLTracker
static const char kDefaultGoogleHomepage[];
+ // Flag to disable /searchdomaincheck lookups in Chrome and instead always use
+ // google.com. The tracker should be used in ALWAYS_DOT_COM_MODE when this
+ // flag is enabled.
+ // For more details, see http://goto.google.com/chrome-no-searchdomaincheck.
+ static const base::Feature kNoSearchDomainCheck;
+
// Only the GoogleURLTrackerFactory and tests should call this.
// Note: you *must* manually call Shutdown() before this instance gets
// destroyed if you want to create another instance in the same binary
@@ -66,7 +74,6 @@ class GoogleURLTracker
// Register user preferences for GoogleURLTracker.
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
// Returns the current Google homepage URL.
const GURL& google_url() const { return google_url_; }
@@ -86,8 +93,7 @@ class GoogleURLTracker
static const char kSearchDomainCheckURL[];
- // net::URLFetcherDelegate:
- void OnURLFetchComplete(const net::URLFetcher* source) override;
+ void OnURLLoaderComplete(std::unique_ptr<std::string> response_body);
// NetworkChangeNotifier::NetworkChangeObserver:
void OnNetworkChanged(
@@ -96,31 +102,30 @@ class GoogleURLTracker
// KeyedService:
void Shutdown() override;
- // Sets |need_to_fetch_| and attempts to start a fetch.
- void SetNeedToFetch();
+ // Sets |need_to_load_| and attempts to start a load.
+ void SetNeedToLoad();
// Called when the five second startup sleep has finished. Runs any pending
- // fetch.
+ // load.
void FinishSleep();
- // Starts the fetch of the up-to-date Google URL if we actually want to fetch
+ // Starts the load of the up-to-date Google URL if we actually want to load
// it and can currently do so.
- void StartFetchIfDesirable();
+ void StartLoadIfDesirable();
CallbackList callback_list_;
std::unique_ptr<GoogleURLTrackerClient> client_;
GURL google_url_;
- std::unique_ptr<net::URLFetcher> fetcher_;
- int fetcher_id_;
- bool in_startup_sleep_; // True if we're in the five-second "no fetching"
+ std::unique_ptr<network::SimpleURLLoader> simple_loader_;
+ bool in_startup_sleep_; // True if we're in the five-second "no loading"
// period that begins at browser start.
- bool already_fetched_; // True if we've already fetched a URL once this run;
- // we won't fetch again until after a restart.
- bool need_to_fetch_; // True if a consumer actually wants us to fetch an
+ bool already_loaded_; // True if we've already loaded a URL once this run;
+ // we won't load again until after a restart.
+ bool need_to_load_; // True if a consumer actually wants us to load an
// updated URL. If this is never set, we won't
- // bother to fetch anything.
+ // bother to load anything.
// Consumers should register a callback via
// RegisterCallback().
base::WeakPtrFactory<GoogleURLTracker> weak_ptr_factory_;
diff --git a/chromium/components/google/core/browser/google_url_tracker_client.h b/chromium/components/google/core/browser/google_url_tracker_client.h
index 58f51a7d74b..0ab7028ac6d 100644
--- a/chromium/components/google/core/browser/google_url_tracker_client.h
+++ b/chromium/components/google/core/browser/google_url_tracker_client.h
@@ -11,8 +11,10 @@
class GoogleURLTracker;
class PrefService;
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+namespace mojom {
+class URLLoaderFactory;
+}
}
// Interface by which GoogleURLTracker communicates with its embedder.
@@ -32,9 +34,8 @@ class GoogleURLTrackerClient {
// Returns the PrefService that the GoogleURLTracker should use.
virtual PrefService* GetPrefs() = 0;
- // Returns the URL request context information that the GoogleURLTracker
- // should use.
- virtual net::URLRequestContextGetter* GetRequestContext() = 0;
+ // Returns the URL loader factory that the GoogleURLTracker should use.
+ virtual network::mojom::URLLoaderFactory* GetURLLoaderFactory() = 0;
protected:
GoogleURLTracker* google_url_tracker() { return google_url_tracker_; }
diff --git a/chromium/components/google/core/browser/google_url_tracker_unittest.cc b/chromium/components/google/core/browser/google_url_tracker_unittest.cc
index e09db9a0971..800d217037e 100644
--- a/chromium/components/google/core/browser/google_url_tracker_unittest.cc
+++ b/chromium/components/google/core/browser/google_url_tracker_unittest.cc
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/google/core/browser/google_pref_names.h"
@@ -17,9 +18,10 @@
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/testing_pref_service.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -71,25 +73,29 @@ void TestCallbackListener::RegisterCallback(
class TestGoogleURLTrackerClient : public GoogleURLTrackerClient {
public:
- explicit TestGoogleURLTrackerClient(PrefService* prefs_);
+ TestGoogleURLTrackerClient(
+ PrefService* prefs_,
+ network::TestURLLoaderFactory* test_url_loader_factory);
~TestGoogleURLTrackerClient() override;
bool IsBackgroundNetworkingEnabled() override;
PrefService* GetPrefs() override;
- net::URLRequestContextGetter* GetRequestContext() override;
+ network::mojom::URLLoaderFactory* GetURLLoaderFactory() override;
private:
PrefService* prefs_;
- scoped_refptr<net::TestURLRequestContextGetter> request_context_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
DISALLOW_COPY_AND_ASSIGN(TestGoogleURLTrackerClient);
};
-TestGoogleURLTrackerClient::TestGoogleURLTrackerClient(PrefService* prefs)
+TestGoogleURLTrackerClient::TestGoogleURLTrackerClient(
+ PrefService* prefs,
+ network::TestURLLoaderFactory* test_url_loader_factory)
: prefs_(prefs),
- request_context_(new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get())) {
-}
+ test_shared_loader_factory_(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ test_url_loader_factory)) {}
TestGoogleURLTrackerClient::~TestGoogleURLTrackerClient() {
}
@@ -102,11 +108,11 @@ PrefService* TestGoogleURLTrackerClient::GetPrefs() {
return prefs_;
}
-net::URLRequestContextGetter* TestGoogleURLTrackerClient::GetRequestContext() {
- return request_context_.get();
+network::mojom::URLLoaderFactory*
+TestGoogleURLTrackerClient::GetURLLoaderFactory() {
+ return test_shared_loader_factory_.get();
}
-
} // namespace
// GoogleURLTrackerTest -------------------------------------------------------
@@ -120,7 +126,6 @@ class GoogleURLTrackerTest : public testing::Test {
void SetUp() override;
void TearDown() override;
- net::TestURLFetcher* GetFetcher();
void MockSearchDomainCheckResponse(const std::string& domain);
void RequestServerCheck();
void FinishSleep();
@@ -131,18 +136,24 @@ class GoogleURLTrackerTest : public testing::Test {
GURL google_url() const { return google_url_tracker_->google_url(); }
bool listener_notified() const { return listener_.notified(); }
void clear_listener_notified() { listener_.clear_notified(); }
+ bool handled_request() const { return handled_request_; }
+
+ GoogleURLTrackerClient* client() const { return client_; }
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
TestingPrefServiceSimple prefs_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
// Creating this allows us to call
// net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests().
std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
- net::TestURLFetcherFactory fetcher_factory_;
GoogleURLTrackerClient* client_;
+
std::unique_ptr<GoogleURLTracker> google_url_tracker_;
TestCallbackListener listener_;
+
+ bool handled_request_ = false;
};
GoogleURLTrackerTest::GoogleURLTrackerTest() {
@@ -158,7 +169,7 @@ void GoogleURLTrackerTest::SetUp() {
network_change_notifier_.reset(net::NetworkChangeNotifier::CreateMock());
// Ownership is passed to google_url_tracker_, but a weak pointer is kept;
// this is safe since GoogleURLTracker keeps the client for its lifetime.
- client_ = new TestGoogleURLTrackerClient(&prefs_);
+ client_ = new TestGoogleURLTrackerClient(&prefs_, &test_url_loader_factory_);
std::unique_ptr<GoogleURLTrackerClient> client(client_);
google_url_tracker_.reset(new GoogleURLTracker(
std::move(client), GoogleURLTracker::ALWAYS_DOT_COM_MODE));
@@ -168,33 +179,27 @@ void GoogleURLTrackerTest::TearDown() {
google_url_tracker_->Shutdown();
}
-net::TestURLFetcher* GoogleURLTrackerTest::GetFetcher() {
- // This will return the last fetcher created. If no fetchers have been
- // created, we'll pass GetFetcherByID() "-1", and it will return NULL.
- return fetcher_factory_.GetFetcherByID(google_url_tracker_->fetcher_id_ - 1);
-}
-
void GoogleURLTrackerTest::MockSearchDomainCheckResponse(
const std::string& domain) {
- net::TestURLFetcher* fetcher = GetFetcher();
- if (!fetcher)
- return;
- fetcher_factory_.RemoveFetcherFromMap(fetcher->id());
- fetcher->set_url(GURL(GoogleURLTracker::kSearchDomainCheckURL));
- fetcher->set_response_code(200);
- fetcher->SetResponseString(domain);
- fetcher->delegate()->OnURLFetchComplete(fetcher);
- // At this point, |fetcher| is deleted.
+ handled_request_ = false;
+ test_url_loader_factory_.SetInterceptor(
+ base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
+ handled_request_ = true;
+ }));
+ test_url_loader_factory_.AddResponse(GoogleURLTracker::kSearchDomainCheckURL,
+ domain);
}
void GoogleURLTrackerTest::RequestServerCheck() {
if (!listener_.HasRegisteredCallback())
listener_.RegisterCallback(google_url_tracker_.get());
- google_url_tracker_->SetNeedToFetch();
+ google_url_tracker_->SetNeedToLoad();
+ base::RunLoop().RunUntilIdle();
}
void GoogleURLTrackerTest::FinishSleep() {
google_url_tracker_->FinishSleep();
+ base::RunLoop().RunUntilIdle();
}
void GoogleURLTrackerTest::NotifyNetworkChanged() {
@@ -211,35 +216,37 @@ TEST_F(GoogleURLTrackerTest, DontFetchWhenNoOneRequestsCheck) {
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
FinishSleep();
// No one called RequestServerCheck() so nothing should have happened.
- EXPECT_FALSE(GetFetcher());
+ EXPECT_FALSE(handled_request());
MockSearchDomainCheckResponse(".google.co.uk");
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
EXPECT_FALSE(listener_notified());
}
TEST_F(GoogleURLTrackerTest, Update) {
+ MockSearchDomainCheckResponse(".google.co.uk");
+
RequestServerCheck();
- EXPECT_FALSE(GetFetcher());
+ EXPECT_FALSE(handled_request());
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
EXPECT_FALSE(listener_notified());
FinishSleep();
- MockSearchDomainCheckResponse(".google.co.uk");
EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
EXPECT_TRUE(listener_notified());
}
TEST_F(GoogleURLTrackerTest, DontUpdateWhenUnchanged) {
+ MockSearchDomainCheckResponse(".google.co.uk");
+
GURL original_google_url("https://www.google.co.uk/");
set_google_url(original_google_url);
RequestServerCheck();
- EXPECT_FALSE(GetFetcher());
+ EXPECT_FALSE(handled_request());
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
FinishSleep();
- MockSearchDomainCheckResponse(".google.co.uk");
EXPECT_EQ(original_google_url, google_url());
// No one should be notified, because the new URL matches the old.
EXPECT_FALSE(listener_notified());
@@ -250,107 +257,107 @@ TEST_F(GoogleURLTrackerTest, DontUpdateOnBadReplies) {
set_google_url(original_google_url);
RequestServerCheck();
- EXPECT_FALSE(GetFetcher());
+ EXPECT_FALSE(handled_request());
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Old-style URL string.
- FinishSleep();
MockSearchDomainCheckResponse("https://www.google.com/");
+ FinishSleep();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Not a Google domain.
- FinishSleep();
MockSearchDomainCheckResponse(".google.evil.com");
+ FinishSleep();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Doesn't start with .google.
- NotifyNetworkChanged();
MockSearchDomainCheckResponse(".mail.google.com");
+ NotifyNetworkChanged();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Non-empty path.
- NotifyNetworkChanged();
MockSearchDomainCheckResponse(".google.com/search");
+ NotifyNetworkChanged();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Non-empty query.
- NotifyNetworkChanged();
MockSearchDomainCheckResponse(".google.com/?q=foo");
+ NotifyNetworkChanged();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Non-empty ref.
- NotifyNetworkChanged();
MockSearchDomainCheckResponse(".google.com/#anchor");
+ NotifyNetworkChanged();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
// Complete garbage.
- NotifyNetworkChanged();
MockSearchDomainCheckResponse("HJ)*qF)_*&@f1");
+ NotifyNetworkChanged();
EXPECT_EQ(original_google_url, google_url());
EXPECT_FALSE(listener_notified());
}
TEST_F(GoogleURLTrackerTest, RefetchOnNetworkChange) {
+ MockSearchDomainCheckResponse(".google.co.uk");
RequestServerCheck();
FinishSleep();
- MockSearchDomainCheckResponse(".google.co.uk");
EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
EXPECT_TRUE(listener_notified());
clear_listener_notified();
- NotifyNetworkChanged();
MockSearchDomainCheckResponse(".google.co.in");
+ NotifyNetworkChanged();
EXPECT_EQ(GURL("https://www.google.co.in/"), google_url());
EXPECT_TRUE(listener_notified());
}
TEST_F(GoogleURLTrackerTest, DontRefetchWhenNoOneRequestsCheck) {
+ MockSearchDomainCheckResponse(".google.co.uk");
FinishSleep();
NotifyNetworkChanged();
// No one called RequestServerCheck() so nothing should have happened.
- EXPECT_FALSE(GetFetcher());
- MockSearchDomainCheckResponse(".google.co.uk");
+ EXPECT_FALSE(handled_request());
EXPECT_EQ(GURL(GoogleURLTracker::kDefaultGoogleHomepage), google_url());
EXPECT_FALSE(listener_notified());
}
TEST_F(GoogleURLTrackerTest, FetchOnLateRequest) {
+ MockSearchDomainCheckResponse(".google.co.jp");
FinishSleep();
NotifyNetworkChanged();
- MockSearchDomainCheckResponse(".google.co.jp");
+ MockSearchDomainCheckResponse(".google.co.uk");
RequestServerCheck();
// The first request for a check should trigger a fetch if it hasn't happened
// already.
- MockSearchDomainCheckResponse(".google.co.uk");
EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
EXPECT_TRUE(listener_notified());
}
TEST_F(GoogleURLTrackerTest, DontFetchTwiceOnLateRequests) {
+ MockSearchDomainCheckResponse(".google.co.jp");
FinishSleep();
NotifyNetworkChanged();
- MockSearchDomainCheckResponse(".google.co.jp");
+ MockSearchDomainCheckResponse(".google.co.uk");
RequestServerCheck();
// The first request for a check should trigger a fetch if it hasn't happened
// already.
- MockSearchDomainCheckResponse(".google.co.uk");
EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
EXPECT_TRUE(listener_notified());
clear_listener_notified();
+ MockSearchDomainCheckResponse(".google.co.in");
RequestServerCheck();
// The second request should be ignored.
- EXPECT_FALSE(GetFetcher());
- MockSearchDomainCheckResponse(".google.co.in");
+ EXPECT_FALSE(handled_request());
EXPECT_EQ(GURL("https://www.google.co.uk/"), google_url());
EXPECT_FALSE(listener_notified());
}
diff --git a/chromium/components/google/core/browser/google_util.cc b/chromium/components/google/core/browser/google_util.cc
index 2820e033dbf..5d712f7b521 100644
--- a/chromium/components/google/core/browser/google_util.cc
+++ b/chromium/components/google/core/browser/google_util.cc
@@ -175,7 +175,8 @@ std::string GetGoogleCountryCode(const GURL& google_homepage_url) {
// TODO(igorcov): This needs a fix for case when the host has a trailing dot,
// like "google.com./". https://crbug.com/720295.
const size_t last_dot = google_hostname.find_last_of('.');
- DCHECK_NE(std::string::npos, last_dot);
+ if (last_dot == std::string::npos)
+ return std::string();
base::StringPiece country_code = google_hostname.substr(last_dot + 1);
// Assume the com TLD implies the US.
if (country_code == "com")
diff --git a/chromium/components/google/core/browser/google_util.h b/chromium/components/google/core/browser/google_util.h
index de1f15d6b6d..77ded284d74 100644
--- a/chromium/components/google/core/browser/google_util.h
+++ b/chromium/components/google/core/browser/google_util.h
@@ -36,6 +36,7 @@ GURL AppendGoogleLocaleParam(const GURL& url,
const std::string& application_locale);
// Returns the Google country code string for the given Google homepage URL.
+// Returns an empty string if |google_homepage_url| contains no country code.
std::string GetGoogleCountryCode(const GURL& google_homepage_url);
// Returns the Google search URL for the given Google homepage URL.
diff --git a/chromium/components/grpc_support/bidirectional_stream.cc b/chromium/components/grpc_support/bidirectional_stream.cc
index 814e9ece76b..2a7ba562729 100644
--- a/chromium/components/grpc_support/bidirectional_stream.cc
+++ b/chromium/components/grpc_support/bidirectional_stream.cc
@@ -24,7 +24,7 @@
#include "net/http/http_status_code.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_util.h"
-#include "net/spdy/core/spdy_header_block.h"
+#include "net/third_party/spdy/core/spdy_header_block.h"
#include "net/ssl/ssl_info.h"
#include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
@@ -174,7 +174,7 @@ void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
}
void BidirectionalStream::OnHeadersReceived(
- const net::SpdyHeaderBlock& response_headers) {
+ const spdy::SpdyHeaderBlock& response_headers) {
DCHECK(IsOnNetworkThread());
DCHECK_EQ(STARTED, read_state_);
if (!bidi_stream_)
@@ -237,7 +237,7 @@ void BidirectionalStream::OnDataSent() {
}
void BidirectionalStream::OnTrailersReceived(
- const net::SpdyHeaderBlock& response_trailers) {
+ const spdy::SpdyHeaderBlock& response_trailers) {
DCHECK(IsOnNetworkThread());
if (!bidi_stream_)
return;
diff --git a/chromium/components/grpc_support/bidirectional_stream.h b/chromium/components/grpc_support/bidirectional_stream.h
index b65be345db8..bdcf41b2675 100644
--- a/chromium/components/grpc_support/bidirectional_stream.h
+++ b/chromium/components/grpc_support/bidirectional_stream.h
@@ -40,14 +40,15 @@ class BidirectionalStream : public net::BidirectionalStream::Delegate {
public:
virtual void OnStreamReady() = 0;
- virtual void OnHeadersReceived(const net::SpdyHeaderBlock& response_headers,
- const char* negotiated_protocol) = 0;
+ virtual void OnHeadersReceived(
+ const spdy::SpdyHeaderBlock& response_headers,
+ const char* negotiated_protocol) = 0;
virtual void OnDataRead(char* data, int size) = 0;
virtual void OnDataSent(const char* data) = 0;
- virtual void OnTrailersReceived(const net::SpdyHeaderBlock& trailers) = 0;
+ virtual void OnTrailersReceived(const spdy::SpdyHeaderBlock& trailers) = 0;
virtual void OnSucceeded() = 0;
@@ -171,10 +172,11 @@ class BidirectionalStream : public net::BidirectionalStream::Delegate {
// net::BidirectionalStream::Delegate implementations:
void OnStreamReady(bool request_headers_sent) override;
- void OnHeadersReceived(const net::SpdyHeaderBlock& response_headers) override;
+ void OnHeadersReceived(
+ const spdy::SpdyHeaderBlock& response_headers) override;
void OnDataRead(int bytes_read) override;
void OnDataSent() override;
- void OnTrailersReceived(const net::SpdyHeaderBlock& trailers) override;
+ void OnTrailersReceived(const spdy::SpdyHeaderBlock& trailers) override;
void OnFailed(int error) override;
// Helper method to derive OnSucceeded.
void MaybeOnSucceded();
diff --git a/chromium/components/grpc_support/bidirectional_stream_c.cc b/chromium/components/grpc_support/bidirectional_stream_c.cc
index aa7902b7de0..daeca99c5f9 100644
--- a/chromium/components/grpc_support/bidirectional_stream_c.cc
+++ b/chromium/components/grpc_support/bidirectional_stream_c.cc
@@ -28,7 +28,7 @@
#include "net/http/http_status_code.h"
#include "net/http/http_transaction_factory.h"
#include "net/http/http_util.h"
-#include "net/spdy/core/spdy_header_block.h"
+#include "net/third_party/spdy/core/spdy_header_block.h"
#include "net/ssl/ssl_info.h"
#include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/url_request_context.h"
@@ -38,7 +38,7 @@ namespace {
class HeadersArray : public bidirectional_stream_header_array {
public:
- explicit HeadersArray(const net::SpdyHeaderBlock& header_block);
+ explicit HeadersArray(const spdy::SpdyHeaderBlock& header_block);
~HeadersArray();
private:
@@ -46,7 +46,7 @@ class HeadersArray : public bidirectional_stream_header_array {
DISALLOW_COPY_AND_ASSIGN(HeadersArray);
};
-HeadersArray::HeadersArray(const net::SpdyHeaderBlock& header_block)
+HeadersArray::HeadersArray(const spdy::SpdyHeaderBlock& header_block)
: headers_strings_(header_block.size()) {
// Count and headers are inherited from parent structure.
count = capacity = header_block.size();
@@ -78,14 +78,14 @@ class BidirectionalStreamAdapter
void OnStreamReady() override;
- void OnHeadersReceived(const net::SpdyHeaderBlock& headers_block,
+ void OnHeadersReceived(const spdy::SpdyHeaderBlock& headers_block,
const char* negotiated_protocol) override;
void OnDataRead(char* data, int size) override;
void OnDataSent(const char* data) override;
- void OnTrailersReceived(const net::SpdyHeaderBlock& trailers_block) override;
+ void OnTrailersReceived(const spdy::SpdyHeaderBlock& trailers_block) override;
void OnSucceeded() override;
@@ -134,7 +134,7 @@ void BidirectionalStreamAdapter::OnStreamReady() {
}
void BidirectionalStreamAdapter::OnHeadersReceived(
- const net::SpdyHeaderBlock& headers_block,
+ const spdy::SpdyHeaderBlock& headers_block,
const char* negotiated_protocol) {
DCHECK(c_callback_->on_response_headers_received);
HeadersArray response_headers(headers_block);
@@ -153,7 +153,7 @@ void BidirectionalStreamAdapter::OnDataSent(const char* data) {
}
void BidirectionalStreamAdapter::OnTrailersReceived(
- const net::SpdyHeaderBlock& trailers_block) {
+ const spdy::SpdyHeaderBlock& trailers_block) {
DCHECK(c_callback_->on_response_trailers_received);
HeadersArray response_trailers(trailers_block);
c_callback_->on_response_trailers_received(c_stream(), &response_trailers);
diff --git a/chromium/components/grpc_support/bidirectional_stream_unittest.cc b/chromium/components/grpc_support/bidirectional_stream_unittest.cc
index ed57fb64fdb..24f9f7a5082 100644
--- a/chromium/components/grpc_support/bidirectional_stream_unittest.cc
+++ b/chromium/components/grpc_support/bidirectional_stream_unittest.cc
@@ -116,10 +116,7 @@ class TestBidirectionalStreamCallback {
read_buffer(nullptr),
net_error(0) {}
- ~TestBidirectionalStreamCallback() {
- if (read_buffer)
- delete[] read_buffer;
- }
+ ~TestBidirectionalStreamCallback() { delete[] read_buffer; }
static TestBidirectionalStreamCallback* FromStream(
bidirectional_stream* stream) {
diff --git a/chromium/components/guest_view/browser/guest_view_manager.cc b/chromium/components/guest_view/browser/guest_view_manager.cc
index 0738b691705..a18eacb3b74 100644
--- a/chromium/components/guest_view/browser/guest_view_manager.cc
+++ b/chromium/components/guest_view/browser/guest_view_manager.cc
@@ -57,7 +57,7 @@ class GuestViewManager::EmbedderRenderProcessHostObserver
}
void RenderProcessHostDestroyed(RenderProcessHost* host) override {
- if (guest_view_manager_.get())
+ if (guest_view_manager_)
guest_view_manager_->EmbedderProcessDestroyed(id_);
delete this;
}
@@ -192,9 +192,13 @@ content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams(
return nullptr;
content::WebContents::CreateParams guest_create_params(create_params);
guest_create_params.guest_delegate = guest;
- auto* guest_web_contents = WebContents::Create(guest_create_params);
- guest->InitWithWebContents(base::DictionaryValue(), guest_web_contents);
- return guest_web_contents;
+
+ // TODO(erikchen): Fix ownership semantics for this class.
+ // https://crbug.com/832879.
+ std::unique_ptr<content::WebContents> guest_web_contents =
+ WebContents::Create(guest_create_params);
+ guest->InitWithWebContents(base::DictionaryValue(), guest_web_contents.get());
+ return guest_web_contents.release();
}
content::WebContents* GuestViewManager::GetGuestByInstanceID(
diff --git a/chromium/components/guest_view/browser/guest_view_manager_unittest.cc b/chromium/components/guest_view/browser/guest_view_manager_unittest.cc
index 654efcbc8b5..45ebeda08b2 100644
--- a/chromium/components/guest_view/browser/guest_view_manager_unittest.cc
+++ b/chromium/components/guest_view/browser/guest_view_manager_unittest.cc
@@ -27,8 +27,7 @@ class GuestViewManagerTest : public content::RenderViewHostTestHarness {
~GuestViewManagerTest() override {}
std::unique_ptr<WebContents> CreateWebContents() {
- return std::unique_ptr<WebContents>(
- WebContentsTester::CreateTestWebContents(browser_context(), nullptr));
+ return WebContentsTester::CreateTestWebContents(browser_context(), nullptr);
}
private:
diff --git a/chromium/components/guest_view/browser/test_guest_view_manager.cc b/chromium/components/guest_view/browser/test_guest_view_manager.cc
index 8dfc283bc7e..e4b269e57f9 100644
--- a/chromium/components/guest_view/browser/test_guest_view_manager.cc
+++ b/chromium/components/guest_view/browser/test_guest_view_manager.cc
@@ -115,7 +115,7 @@ void TestGuestViewManager::AddGuest(int guest_instance_id,
std::make_unique<content::WebContentsDestroyedWatcher>(
guest_web_contents));
- if (created_message_loop_runner_.get())
+ if (created_message_loop_runner_)
created_message_loop_runner_->Quit();
++num_guests_created_;
@@ -124,7 +124,7 @@ void TestGuestViewManager::AddGuest(int guest_instance_id,
return;
}
- if (num_created_message_loop_runner_.get())
+ if (num_created_message_loop_runner_)
num_created_message_loop_runner_->Quit();
}
@@ -163,7 +163,7 @@ void TestGuestViewManager::ViewGarbageCollected(int embedder_process_id,
int view_instance_id) {
GuestViewManager::ViewGarbageCollected(embedder_process_id, view_instance_id);
++num_views_garbage_collected_;
- if (gc_message_loop_runner_.get())
+ if (gc_message_loop_runner_)
gc_message_loop_runner_->Quit();
}
diff --git a/chromium/components/guest_view/renderer/guest_view_container.cc b/chromium/components/guest_view/renderer/guest_view_container.cc
index 4d1e7a65079..38a0724a5b4 100644
--- a/chromium/components/guest_view/renderer/guest_view_container.cc
+++ b/chromium/components/guest_view/renderer/guest_view_container.cc
@@ -103,7 +103,7 @@ void GuestViewContainer::Destroy(bool embedder_frame_destroyed) {
g_guest_view_container_map.Get().erase(element_instance_id());
if (!embedder_frame_destroyed) {
- if (pending_response_.get())
+ if (pending_response_)
pending_response_->ExecuteCallbackIfAvailable(0 /* argc */, nullptr);
while (pending_requests_.size() > 0) {
@@ -155,7 +155,7 @@ void GuestViewContainer::PerformPendingRequest() {
void GuestViewContainer::HandlePendingResponseCallback(
const IPC::Message& message) {
- CHECK(pending_response_.get());
+ CHECK(pending_response_);
std::unique_ptr<GuestViewRequest> pending_response =
std::move(pending_response_);
pending_response->HandleResponse(message);
@@ -213,7 +213,7 @@ bool GuestViewContainer::OnMessageReceived(const IPC::Message& message) {
void GuestViewContainer::Ready() {
ready_ = true;
- CHECK(!pending_response_.get());
+ CHECK(!pending_response_);
PerformPendingRequest();
// Give the derived type an opportunity to perform some actions when the
diff --git a/chromium/components/heap_profiling/BUILD.gn b/chromium/components/heap_profiling/BUILD.gn
index b6b0f785f8c..892f5a6d1a5 100644
--- a/chromium/components/heap_profiling/BUILD.gn
+++ b/chromium/components/heap_profiling/BUILD.gn
@@ -2,10 +2,16 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+if (is_android) {
+ import("//build/config/android/rules.gni")
+}
+
static_library("heap_profiling") {
sources = [
"client_connection_manager.cc",
"client_connection_manager.h",
+ "supervisor.cc",
+ "supervisor.h",
]
deps = [
@@ -15,3 +21,46 @@ static_library("heap_profiling") {
"//content/public/common",
]
}
+
+if (is_android) {
+ generate_jni("jni_headers") {
+ sources = [
+ "javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java",
+ ]
+ jni_package = "components_heap_profiling"
+ }
+
+ # This library must be included by the apk_under_test in order for the JNI
+ # shim to function correctly.
+ android_library("heap_profiling_java_test_support") {
+ testonly = true
+ java_files = [ "javatests/src/org/chromium/components/heap_profiling/HeapProfilingTestShim.java" ]
+ deps = [
+ "//base:base_java",
+ ]
+ }
+}
+
+source_set("test_support") {
+ testonly = true
+ sources = [
+ "test_driver.cc",
+ "test_driver.h",
+ ]
+
+ deps = [
+ ":heap_profiling",
+ "//base",
+ "//components/services/heap_profiling/public/cpp",
+ "//content/public/browser",
+ "//content/public/common",
+ ]
+
+ if (is_android) {
+ sources += [
+ "heap_profiling_test_shim.cc",
+ "heap_profiling_test_shim.h",
+ ]
+ deps += [ ":jni_headers" ]
+ }
+}
diff --git a/chromium/components/heap_profiling/DEPS b/chromium/components/heap_profiling/DEPS
index 5a890ffdc83..24fd5c37329 100644
--- a/chromium/components/heap_profiling/DEPS
+++ b/chromium/components/heap_profiling/DEPS
@@ -1,5 +1,7 @@
include_rules = [
"+components/services/heap_profiling/public",
"+content/public",
+ "+jni",
+ "+services/resource_coordinator/public/cpp",
"+services/service_manager/public/cpp",
]
diff --git a/chromium/components/heap_profiling/client_connection_manager.cc b/chromium/components/heap_profiling/client_connection_manager.cc
index 75404095cbf..cecb5c27fcd 100644
--- a/chromium/components/heap_profiling/client_connection_manager.cc
+++ b/chromium/components/heap_profiling/client_connection_manager.cc
@@ -53,8 +53,7 @@ class ProfilingClientBinder {
mojom::ProfilingClientPtr take() { return std::move(memlog_client_); }
private:
- ProfilingClientBinder()
- : memlog_client_(), request_(mojo::MakeRequest(&memlog_client_)) {}
+ ProfilingClientBinder() : request_(mojo::MakeRequest(&memlog_client_)) {}
mojom::ProfilingClientPtr memlog_client_;
mojom::ProfilingClientRequest request_;
@@ -232,7 +231,7 @@ void ClientConnectionManager::StartProfilingProcess(base::ProcessId pid) {
// The RenderProcessHost iterator must be used on the UI thread.
for (auto iter = content::RenderProcessHost::AllHostsIterator();
!iter.IsAtEnd(); iter.Advance()) {
- if (pid == base::GetProcId(iter.GetCurrentValue()->GetHandle())) {
+ if (pid == iter.GetCurrentValue()->GetProcess().Pid()) {
StartProfilingRenderer(iter.GetCurrentValue());
return;
}
@@ -270,7 +269,8 @@ void ClientConnectionManager::StartProfilingExistingProcessesIfNecessary() {
for (auto iter = content::RenderProcessHost::AllHostsIterator();
!iter.IsAtEnd(); iter.Advance()) {
if (ShouldProfileNewRenderer(iter.GetCurrentValue()) &&
- iter.GetCurrentValue()->GetHandle() != base::kNullProcessHandle) {
+ iter.GetCurrentValue()->GetProcess().Handle() !=
+ base::kNullProcessHandle) {
StartProfilingRenderer(iter.GetCurrentValue());
}
}
@@ -359,10 +359,10 @@ void ClientConnectionManager::StartProfilingRenderer(
ProfilingClientBinder client(host);
content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
- ->PostTask(FROM_HERE, base::BindOnce(&StartProfilingClientOnIOThread,
- controller_, std::move(client),
- base::GetProcId(host->GetHandle()),
- mojom::ProcessType::RENDERER));
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&StartProfilingClientOnIOThread, controller_,
+ std::move(client), host->GetProcess().Pid(),
+ mojom::ProcessType::RENDERER));
}
} // namespace heap_profiling
diff --git a/chromium/components/heap_profiling/heap_profiling_test_shim.cc b/chromium/components/heap_profiling/heap_profiling_test_shim.cc
new file mode 100644
index 00000000000..ca6efeb9edc
--- /dev/null
+++ b/chromium/components/heap_profiling/heap_profiling_test_shim.cc
@@ -0,0 +1,48 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/heap_profiling/heap_profiling_test_shim.h"
+
+#include "base/android/jni_string.h"
+#include "components/heap_profiling/test_driver.h"
+#include "components/services/heap_profiling/public/cpp/settings.h"
+#include "jni/HeapProfilingTestShim_jni.h"
+
+using base::android::JavaParamRef;
+using base::android::ScopedJavaLocalRef;
+
+static jlong JNI_HeapProfilingTestShim_Init(JNIEnv* env,
+ const JavaParamRef<jobject>& obj) {
+ HeapProfilingTestShim* profiler = new HeapProfilingTestShim(env, obj);
+ return reinterpret_cast<intptr_t>(profiler);
+}
+
+HeapProfilingTestShim::HeapProfilingTestShim(JNIEnv* env, jobject obj) {}
+
+HeapProfilingTestShim::~HeapProfilingTestShim() {}
+
+void HeapProfilingTestShim::Destroy(JNIEnv* env,
+ const JavaParamRef<jobject>& obj) {
+ delete this;
+}
+
+jboolean HeapProfilingTestShim::RunTestForMode(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ const base::android::JavaParamRef<jstring>& mode,
+ jboolean dynamically_start_profiling,
+ const base::android::JavaParamRef<jstring>& stack_mode,
+ jboolean should_sample,
+ jboolean sample_everything) {
+ heap_profiling::TestDriver driver;
+ heap_profiling::TestDriver::Options options;
+ options.mode = heap_profiling::ConvertStringToMode(
+ base::android::ConvertJavaStringToUTF8(mode));
+ options.stack_mode = heap_profiling::ConvertStringToStackMode(
+ base::android::ConvertJavaStringToUTF8(stack_mode));
+ options.profiling_already_started = !dynamically_start_profiling;
+ options.should_sample = should_sample;
+ options.sample_everything = sample_everything;
+ return driver.RunTest(options);
+}
diff --git a/chromium/components/heap_profiling/heap_profiling_test_shim.h b/chromium/components/heap_profiling/heap_profiling_test_shim.h
new file mode 100644
index 00000000000..134d548ed09
--- /dev/null
+++ b/chromium/components/heap_profiling/heap_profiling_test_shim.h
@@ -0,0 +1,35 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_HEAP_PROFILING_HEAP_PROFILING_TEST_SHIM_H_
+#define COMPONENTS_HEAP_PROFILING_HEAP_PROFILING_TEST_SHIM_H_
+
+#include "base/android/jni_android.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+
+// This class implements the native methods of HeapProfilingTestShim.java, and
+// acts as a bridge to TestDriver. Note that this class is only used for
+// testing.
+class HeapProfilingTestShim {
+ public:
+ HeapProfilingTestShim(JNIEnv* env, jobject obj);
+ void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+ jboolean RunTestForMode(
+ JNIEnv* env,
+ const base::android::JavaParamRef<jobject>& obj,
+ const base::android::JavaParamRef<jstring>& mode,
+ jboolean dynamically_start_profiling,
+ const base::android::JavaParamRef<jstring>& stack_mode,
+ jboolean should_sample,
+ jboolean sample_everything);
+
+ private:
+ ~HeapProfilingTestShim();
+
+ DISALLOW_COPY_AND_ASSIGN(HeapProfilingTestShim);
+};
+
+#endif // COMPONENTS_HEAP_PROFILING_HEAP_PROFILING_TEST_SHIM_H_
diff --git a/chromium/components/heap_profiling/supervisor.cc b/chromium/components/heap_profiling/supervisor.cc
new file mode 100644
index 00000000000..ed21ae9063f
--- /dev/null
+++ b/chromium/components/heap_profiling/supervisor.cc
@@ -0,0 +1,225 @@
+// 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 "components/heap_profiling/supervisor.h"
+
+#include "base/memory/ref_counted_memory.h"
+#include "base/no_destructor.h"
+#include "components/heap_profiling/client_connection_manager.h"
+#include "components/services/heap_profiling/public/cpp/controller.h"
+#include "components/services/heap_profiling/public/cpp/settings.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/tracing_controller.h"
+#include "content/public/common/service_manager_connection.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace heap_profiling {
+
+namespace {
+
+base::trace_event::TraceConfig GetBackgroundTracingConfig(bool anonymize) {
+ // Disable all categories other than memory-infra.
+ base::trace_event::TraceConfig trace_config(
+ "-*,disabled-by-default-memory-infra",
+ base::trace_event::RECORD_UNTIL_FULL);
+
+ // This flag is set by background tracing to filter out undesired events.
+ if (anonymize)
+ trace_config.EnableArgumentFilter();
+
+ return trace_config;
+}
+
+} // namespace
+
+// static
+Supervisor* Supervisor::GetInstance() {
+ static base::NoDestructor<Supervisor> supervisor;
+ return supervisor.get();
+}
+
+Supervisor::Supervisor() = default;
+Supervisor::~Supervisor() {
+ NOTREACHED();
+}
+
+bool Supervisor::HasStarted() {
+ return started_;
+}
+
+void Supervisor::SetClientConnectionManagerConstructor(
+ ClientConnectionManagerConstructor constructor) {
+ DCHECK(!HasStarted());
+ constructor_ = constructor;
+}
+
+void Supervisor::Start(content::ServiceManagerConnection* connection,
+ base::OnceClosure closure) {
+ Start(connection, GetModeForStartup(), GetStackModeForStartup(),
+ GetSamplingRateForStartup(), std::move(closure));
+}
+
+void Supervisor::Start(content::ServiceManagerConnection* connection,
+ Mode mode,
+ mojom::StackMode stack_mode,
+ uint32_t sampling_rate,
+ base::OnceClosure closure) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(!started_);
+
+ content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&Supervisor::StartServiceOnIOThread,
+ base::Unretained(this),
+ connection->GetConnector()->Clone(), mode,
+ stack_mode, sampling_rate, std::move(closure)));
+}
+
+Mode Supervisor::GetMode() {
+ DCHECK(HasStarted());
+ return client_connection_manager_->GetMode();
+}
+
+void Supervisor::StartManualProfiling(base::ProcessId pid) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(HasStarted());
+ client_connection_manager_->StartProfilingProcess(pid);
+}
+
+void Supervisor::SetKeepSmallAllocations(bool keep_small_allocations) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(HasStarted());
+
+ content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
+ ->PostTask(
+ FROM_HERE,
+ base::BindOnce(&Supervisor::SetKeepSmallAllocationsOnIOThread,
+ base::Unretained(this), keep_small_allocations));
+}
+
+void Supervisor::GetProfiledPids(GetProfiledPidsCallback callback) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(HasStarted());
+
+ content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::IO)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&Supervisor::GetProfiledPidsOnIOThread,
+ base::Unretained(this), std::move(callback)));
+}
+
+uint32_t Supervisor::GetSamplingRate() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(HasStarted());
+
+ return controller_->sampling_rate();
+}
+
+void Supervisor::RequestTraceWithHeapDump(TraceFinishedCallback callback,
+ bool anonymize) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(HasStarted());
+
+ if (content::TracingController::GetInstance()->IsTracing()) {
+ DLOG(ERROR) << "Requesting heap dump when tracing has already started.";
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), false, std::string()));
+ return;
+ }
+
+ auto finished_dump_callback = base::BindOnce(
+ [](TraceFinishedCallback callback, bool success, uint64_t dump_guid) {
+ // Once the trace has stopped, run |callback| on the UI thread.
+ auto finish_sink_callback = base::Bind(
+ [](TraceFinishedCallback callback,
+ std::unique_ptr<const base::DictionaryValue> metadata,
+ base::RefCountedString* in) {
+ std::string result;
+ result.swap(in->data());
+ content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::UI)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), true,
+ std::move(result)));
+ },
+ base::Passed(std::move(callback)));
+ scoped_refptr<content::TracingController::TraceDataEndpoint> sink =
+ content::TracingController::CreateStringEndpoint(
+ std::move(finish_sink_callback));
+ content::TracingController::GetInstance()->StopTracing(sink);
+ },
+ std::move(callback));
+
+ memory_instrumentation::MemoryInstrumentation::GetInstance()
+ ->RequestGlobalDumpAndAppendToTrace(
+ base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED,
+ base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND,
+ base::AdaptCallbackForRepeating(std::move(finished_dump_callback)));
+
+ // The only reason this should return false is if tracing is already enabled,
+ // which we've already checked.
+ bool result = content::TracingController::GetInstance()->StartTracing(
+ GetBackgroundTracingConfig(anonymize), base::Closure());
+ DCHECK(result);
+}
+
+void Supervisor::StartServiceOnIOThread(
+ std::unique_ptr<service_manager::Connector> connector,
+ Mode mode,
+ mojom::StackMode stack_mode,
+ uint32_t sampling_rate,
+ base::OnceClosure closure) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ controller_.reset(
+ new Controller(std::move(connector), stack_mode, sampling_rate));
+ base::WeakPtr<Controller> controller_weak_ptr = controller_->GetWeakPtr();
+
+ content::BrowserThread::GetTaskRunnerForThread(content::BrowserThread::UI)
+ ->PostTask(FROM_HERE,
+ base::BindOnce(&Supervisor::FinishInitializationOnUIhread,
+ base::Unretained(this), mode,
+ std::move(closure), controller_weak_ptr));
+}
+
+void Supervisor::FinishInitializationOnUIhread(
+ Mode mode,
+ base::OnceClosure closure,
+ base::WeakPtr<Controller> controller_weak_ptr) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(!started_);
+ started_ = true;
+
+ if (constructor_) {
+ client_connection_manager_ = (*constructor_)(controller_weak_ptr, mode);
+ } else {
+ client_connection_manager_ =
+ std::make_unique<ClientConnectionManager>(controller_weak_ptr, mode);
+ }
+
+ client_connection_manager_->Start();
+ if (closure)
+ std::move(closure).Run();
+}
+
+void Supervisor::GetProfiledPidsOnIOThread(GetProfiledPidsCallback callback) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+ auto post_result_to_ui_thread = base::BindOnce(
+ [](GetProfiledPidsCallback callback,
+ const std::vector<base::ProcessId>& result) {
+ content::BrowserThread::GetTaskRunnerForThread(
+ content::BrowserThread::UI)
+ ->PostTask(FROM_HERE, base::BindOnce(std::move(callback), result));
+ },
+ std::move(callback));
+ controller_->GetProfiledPids(std::move(post_result_to_ui_thread));
+}
+
+void Supervisor::SetKeepSmallAllocationsOnIOThread(
+ bool keep_small_allocations) {
+ controller_->SetKeepSmallAllocations(keep_small_allocations);
+}
+
+} // namespace heap_profiling
diff --git a/chromium/components/heap_profiling/supervisor.h b/chromium/components/heap_profiling/supervisor.h
new file mode 100644
index 00000000000..b4b85151f6e
--- /dev/null
+++ b/chromium/components/heap_profiling/supervisor.h
@@ -0,0 +1,147 @@
+// 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 COMPONENTS_HEAP_PROFILING_SUPERVISOR_H_
+#define COMPONENTS_HEAP_PROFILING_SUPERVISOR_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/process/process.h"
+#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
+
+namespace content {
+class ServiceManagerConnection;
+} // namespace content
+
+namespace service_manager {
+class Connector;
+} // namespace service_manager
+
+namespace heap_profiling {
+
+class ClientConnectionManager;
+class Controller;
+enum class Mode;
+
+// This class presents a single interface for both tests and embedders to use
+// the HeapProfilingService. This class is intended to be used from the
+// browser/privileged process of the embedder.
+//
+// This class must be accessed from the UI thread.
+//
+// Internally, this class:
+// * Starts the HeapProfilingService.
+// * Hooks up all the connections so that the appropriate processes get
+// profiled.
+class Supervisor {
+ public:
+ static Supervisor* GetInstance();
+
+ // When this returns |false|, no method other than Start() or
+ // SetClientConnectionManagerConstructor() can be called.
+ bool HasStarted();
+
+ // Embedders can use this method to force the Supervisor to instantiate a
+ // ClientConnectionManager subclass during Start(). The function will be
+ // called on the UI thread.
+ using ClientConnectionManagerConstructor =
+ std::unique_ptr<ClientConnectionManager> (*)(
+ base::WeakPtr<Controller> controller_weak_ptr,
+ Mode mode);
+ void SetClientConnectionManagerConstructor(
+ ClientConnectionManagerConstructor constructor);
+
+ // Must be called at most once.
+ // The first method is a convenience method that calls the second with
+ // default parameters.
+ // Start is an asynchronous operation that must hop to the IO thread and then
+ // back to the UI thread. |callback| will be invoked on the UI thread after
+ // this is finished.
+ //
+ // This is a brief period of time when this object is in a semi-initialized
+ // state - when Start has been called, but the thread hops haven't finished.
+ // We avoid this side case by:
+ // * Providing a |callback| for callers to use, if they need to do anything
+ // shortly after Start().
+ // * Relying on the assumption that in all other cases, the object is either
+ // fully initialized or not initialized. There are DCHECKs to enforce this
+ // assumption.
+ void Start(content::ServiceManagerConnection* connection,
+ base::OnceClosure callback);
+ void Start(content::ServiceManagerConnection* connection,
+ Mode mode,
+ mojom::StackMode stack_mode,
+ uint32_t sampling_rate,
+ base::OnceClosure callback);
+
+ Mode GetMode();
+
+ // Starts profiling the process with the given id.
+ void StartManualProfiling(base::ProcessId pid);
+
+ // Public for testing. Controls whether the profiling service keeps small
+ // allocations in heap dumps.
+ void SetKeepSmallAllocations(bool keep_small_allocations);
+
+ // Returns the pids of all profiled processes. The callback is posted on the
+ // UI thread.
+ using GetProfiledPidsCallback =
+ base::OnceCallback<void(std::vector<base::ProcessId> pids)>;
+ void GetProfiledPids(GetProfiledPidsCallback callback);
+
+ uint32_t GetSamplingRate();
+
+ using TraceFinishedCallback =
+ base::OnceCallback<void(bool success, std::string trace_json)>;
+
+ // This method must be called from the UI thread. |callback| will be called
+ // asynchronously on the UI thread.
+ //
+ // This function does the following:
+ // 1. Starts tracing with no categories enabled.
+ // 2. Requests and waits for memory_instrumentation service to dump to
+ // trace.
+ // 3. Stops tracing.
+ void RequestTraceWithHeapDump(TraceFinishedCallback callback, bool anonymize);
+
+ private:
+ friend class base::NoDestructor<Supervisor>;
+
+ Supervisor();
+ ~Supervisor();
+
+ // Initialization stage 1: Start the Service on the IO thread.
+ void StartServiceOnIOThread(
+ std::unique_ptr<service_manager::Connector> connector,
+ Mode mode,
+ mojom::StackMode stack_mode,
+ uint32_t sampling_rate,
+ base::OnceClosure callback);
+
+ // Initialization stage 2: Start the ClientConnectManager on the UI thread.
+ void FinishInitializationOnUIhread(
+ Mode mode,
+ base::OnceClosure closure,
+ base::WeakPtr<Controller> controller_weak_ptr);
+
+ void GetProfiledPidsOnIOThread(GetProfiledPidsCallback callback);
+
+ void SetKeepSmallAllocationsOnIOThread(bool keep_small_allocations);
+
+ // Bound to the IO thread.
+ std::unique_ptr<Controller> controller_;
+
+ // Bound to the UI thread.
+ std::unique_ptr<ClientConnectionManager> client_connection_manager_;
+
+ ClientConnectionManagerConstructor constructor_ = nullptr;
+
+ bool started_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(Supervisor);
+};
+
+} // namespace heap_profiling
+
+#endif // COMPONENTS_HEAP_PROFILING_SUPERVISOR_H_
diff --git a/chromium/components/heap_profiling/test_driver.cc b/chromium/components/heap_profiling/test_driver.cc
new file mode 100644
index 00000000000..7c841bc5fbf
--- /dev/null
+++ b/chromium/components/heap_profiling/test_driver.cc
@@ -0,0 +1,1035 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/heap_profiling/test_driver.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/json/json_reader.h"
+#include "base/process/process_handle.h"
+#include "base/run_loop.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/platform_thread.h"
+#include "base/trace_event/heap_profiler_event_filter.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "components/heap_profiling/supervisor.h"
+#include "components/services/heap_profiling/public/cpp/allocator_shim.h"
+#include "components/services/heap_profiling/public/cpp/controller.h"
+#include "components/services/heap_profiling/public/cpp/settings.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/tracing_controller.h"
+#include "content/public/common/service_manager_connection.h"
+
+namespace heap_profiling {
+
+namespace {
+
+const char kTestCategory[] = "kTestCategory";
+const char kMallocEvent[] = "kMallocEvent";
+const char kMallocTypeTag[] = "kMallocTypeTag";
+const char kPAEvent[] = "kPAEvent";
+const char kVariadicEvent[] = "kVariadicEvent";
+const char kThreadName[] = "kThreadName";
+
+// Note: When we test sampling with |sample_everything| = true, we set the
+// sampling interval to 2. It's important that all allocations made in this file
+// have size >> 2, so that the probability that they are sampled is
+// exponentially close to 1.
+//
+// Make some specific allocations in Browser to do a deeper test of the
+// allocation tracking.
+constexpr int kMallocAllocSize = 7907;
+constexpr int kMallocAllocCount = 157;
+
+constexpr int kVariadicAllocCount = 157;
+
+// The sample rate should not affect the sampled allocations. Intentionally
+// choose an odd number.
+constexpr int kSampleRate = 7777;
+constexpr int kSamplingAllocSize = 100;
+constexpr int kSamplingAllocCount = 10000;
+const char kSamplingAllocTypeName[] = "kSamplingAllocTypeName";
+
+// Test fixed-size partition alloc. The size must be aligned to system pointer
+// size.
+constexpr int kPartitionAllocSize = 8 * 23;
+constexpr int kPartitionAllocCount = 107;
+static const char* kPartitionAllocTypeName = "kPartitionAllocTypeName";
+
+// Ideally, we'd check to see that at least one renderer exists, and all
+// renderers are being profiled, but something odd seems to be happening with
+// warm-up/spare renderers.
+//
+// Whether at least 1 renderer exists, and at least 1 renderer is being
+// profiled.
+bool RenderersAreBeingProfiled(
+ const std::vector<base::ProcessId>& profiled_pids) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ for (auto iter = content::RenderProcessHost::AllHostsIterator();
+ !iter.IsAtEnd(); iter.Advance()) {
+ if (iter.GetCurrentValue()->GetProcess().Handle() ==
+ base::kNullProcessHandle)
+ continue;
+ base::ProcessId pid = iter.GetCurrentValue()->GetProcess().Pid();
+ if (std::find(profiled_pids.begin(), profiled_pids.end(), pid) !=
+ profiled_pids.end()) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// On success, populates |pid|.
+int NumProcessesWithName(base::Value* dump_json,
+ std::string name,
+ std::vector<int>* pids) {
+ int num_processes = 0;
+ base::Value* events = dump_json->FindKey("traceEvents");
+ for (const base::Value& event : events->GetList()) {
+ const base::Value* found_name =
+ event.FindKeyOfType("name", base::Value::Type::STRING);
+ if (!found_name)
+ continue;
+ if (found_name->GetString() != "process_name")
+ continue;
+ const base::Value* found_args =
+ event.FindKeyOfType("args", base::Value::Type::DICTIONARY);
+ if (!found_args)
+ continue;
+ const base::Value* found_process_name =
+ found_args->FindKeyOfType("name", base::Value::Type::STRING);
+ if (!found_process_name)
+ continue;
+ if (found_process_name->GetString() != name)
+ continue;
+
+ if (pids) {
+ const base::Value* found_pid =
+ event.FindKeyOfType("pid", base::Value::Type::INTEGER);
+ if (!found_pid) {
+ LOG(ERROR) << "Process missing pid.";
+ return 0;
+ }
+ pids->push_back(found_pid->GetInt());
+ }
+
+ ++num_processes;
+ }
+ return num_processes;
+}
+
+base::Value* FindArgDump(base::ProcessId pid,
+ base::Value* dump_json,
+ const char* arg) {
+ base::Value* events = dump_json->FindKey("traceEvents");
+ base::Value* dumps = nullptr;
+ base::Value* heaps_v2 = nullptr;
+ for (base::Value& event : events->GetList()) {
+ const base::Value* found_name =
+ event.FindKeyOfType("name", base::Value::Type::STRING);
+ if (!found_name)
+ continue;
+ if (found_name->GetString() != "periodic_interval")
+ continue;
+ const base::Value* found_pid =
+ event.FindKeyOfType("pid", base::Value::Type::INTEGER);
+ if (!found_pid)
+ continue;
+ if (static_cast<base::ProcessId>(found_pid->GetInt()) != pid)
+ continue;
+ dumps = &event;
+ heaps_v2 = dumps->FindPath({"args", "dumps", arg});
+ if (heaps_v2)
+ return heaps_v2;
+ }
+ return nullptr;
+}
+
+constexpr uint64_t kNullParent = std::numeric_limits<int>::max();
+struct Node {
+ int name_id;
+ std::string name;
+ int parent_id = kNullParent;
+};
+using NodeMap = std::unordered_map<uint64_t, Node>;
+
+// Parses maps.nodes and maps.strings. Returns |true| on success.
+bool ParseNodes(base::Value* heaps_v2, NodeMap* output) {
+ base::Value* nodes = heaps_v2->FindPath({"maps", "nodes"});
+ for (const base::Value& node_value : nodes->GetList()) {
+ const base::Value* id = node_value.FindKey("id");
+ const base::Value* name_sid = node_value.FindKey("name_sid");
+ if (!id || !name_sid) {
+ LOG(ERROR) << "Node missing id or name_sid field";
+ return false;
+ }
+
+ Node node;
+ node.name_id = name_sid->GetInt();
+
+ const base::Value* parent_id = node_value.FindKey("parent");
+ if (parent_id) {
+ node.parent_id = parent_id->GetInt();
+ }
+
+ (*output)[id->GetInt()] = node;
+ }
+
+ base::Value* strings = heaps_v2->FindPath({"maps", "strings"});
+ for (const base::Value& string_value : strings->GetList()) {
+ const base::Value* id = string_value.FindKey("id");
+ const base::Value* string = string_value.FindKey("string");
+ if (!id || !string) {
+ LOG(ERROR) << "String struct missing id or string field";
+ return false;
+ }
+ for (auto& pair : *output) {
+ if (pair.second.name_id == id->GetInt()) {
+ pair.second.name = string->GetString();
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Parses maps.types and maps.strings. Returns |true| on success.
+bool ParseTypes(base::Value* heaps_v2, NodeMap* output) {
+ base::Value* types = heaps_v2->FindPath({"maps", "types"});
+ for (const base::Value& type_value : types->GetList()) {
+ const base::Value* id = type_value.FindKey("id");
+ const base::Value* name_sid = type_value.FindKey("name_sid");
+ if (!id || !name_sid) {
+ LOG(ERROR) << "Node missing id or name_sid field";
+ return false;
+ }
+
+ Node node;
+ node.name_id = name_sid->GetInt();
+ (*output)[id->GetInt()] = node;
+ }
+
+ base::Value* strings = heaps_v2->FindPath({"maps", "strings"});
+ for (const base::Value& string_value : strings->GetList()) {
+ const base::Value* id = string_value.FindKey("id");
+ const base::Value* string = string_value.FindKey("string");
+ if (!id || !string) {
+ LOG(ERROR) << "String struct missing id or string field";
+ return false;
+ }
+ for (auto& pair : *output) {
+ if (pair.second.name_id == id->GetInt()) {
+ pair.second.name = string->GetString();
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+// Verify expectations are present in heap dump.
+bool ValidateDump(base::Value* heaps_v2,
+ int expected_alloc_size,
+ int expected_alloc_count,
+ const char* allocator_name,
+ const char* type_name,
+ const std::string& frame_name,
+ const std::string& thread_name) {
+ base::Value* sizes =
+ heaps_v2->FindPath({"allocators", allocator_name, "sizes"});
+ if (!sizes) {
+ LOG(ERROR) << "Failed to find path: 'allocators." << allocator_name
+ << ".sizes' in heaps v2";
+ return false;
+ }
+
+ const base::Value::ListStorage& sizes_list = sizes->GetList();
+ if (sizes_list.empty()) {
+ LOG(ERROR) << "'allocators." << allocator_name
+ << ".sizes' is an empty list";
+ return false;
+ }
+
+ base::Value* counts =
+ heaps_v2->FindPath({"allocators", allocator_name, "counts"});
+ if (!counts) {
+ LOG(ERROR) << "Failed to find path: 'allocators." << allocator_name
+ << ".counts' in heaps v2";
+ return false;
+ }
+
+ const base::Value::ListStorage& counts_list = counts->GetList();
+ if (sizes_list.size() != counts_list.size()) {
+ LOG(ERROR)
+ << "'allocators." << allocator_name
+ << ".sizes' does not have the same number of elements as *.counts";
+ return false;
+ }
+
+ base::Value* types =
+ heaps_v2->FindPath({"allocators", allocator_name, "types"});
+ if (!types) {
+ LOG(ERROR) << "Failed to find path: 'allocators." << allocator_name
+ << ".types' in heaps v2";
+ return false;
+ }
+
+ const base::Value::ListStorage& types_list = types->GetList();
+ if (types_list.empty()) {
+ LOG(ERROR) << "'allocators." << allocator_name
+ << ".types' is an empty list";
+ return false;
+ }
+
+ if (sizes_list.size() != types_list.size()) {
+ LOG(ERROR)
+ << "'allocators." << allocator_name
+ << ".types' does not have the same number of elements as *.sizes";
+ return false;
+ }
+
+ base::Value* nodes =
+ heaps_v2->FindPath({"allocators", allocator_name, "nodes"});
+ if (!nodes) {
+ LOG(ERROR) << "Failed to find path: 'allocators." << allocator_name
+ << ".nodes' in heaps v2";
+ return false;
+ }
+
+ const base::Value::ListStorage& nodes_list = nodes->GetList();
+ if (sizes_list.size() != nodes_list.size()) {
+ LOG(ERROR)
+ << "'allocators." << allocator_name
+ << ".sizes' does not have the same number of elements as *.nodes";
+ return false;
+ }
+
+ bool found_browser_alloc = false;
+ size_t browser_alloc_index = 0;
+ for (size_t i = 0; i < sizes_list.size(); i++) {
+ if (counts_list[i].GetInt() == expected_alloc_count &&
+ sizes_list[i].GetInt() != expected_alloc_size) {
+ LOG(WARNING) << "Allocation candidate (size:" << sizes_list[i].GetInt()
+ << " count:" << counts_list[i].GetInt() << ")";
+ }
+ if (sizes_list[i].GetInt() == expected_alloc_size &&
+ counts_list[i].GetInt() == expected_alloc_count) {
+ browser_alloc_index = i;
+ found_browser_alloc = true;
+ break;
+ }
+ }
+
+ if (!found_browser_alloc) {
+ LOG(ERROR) << "Failed to find an allocation of the "
+ "appropriate size. Did the send buffer "
+ "not flush? (size: "
+ << expected_alloc_size << " count:" << expected_alloc_count
+ << ")";
+ return false;
+ }
+
+ // Find the type, if an expectation was passed in.
+ if (type_name) {
+ NodeMap node_map;
+ if (!ParseTypes(heaps_v2, &node_map)) {
+ LOG(ERROR) << "Failed to parse type and string structs";
+ return false;
+ }
+
+ int type = types_list[browser_alloc_index].GetInt();
+ auto it = node_map.find(type);
+ if (it == node_map.end()) {
+ LOG(ERROR) << "Failed to look up type.";
+ return false;
+ }
+ if (it->second.name != type_name) {
+ LOG(ERROR) << "actual name: " << it->second.name
+ << " expected name: " << type_name;
+ return false;
+ }
+ }
+
+ // Check that the frame has the right name.
+ if (!frame_name.empty()) {
+ NodeMap node_map;
+ if (!ParseNodes(heaps_v2, &node_map)) {
+ LOG(ERROR) << "Failed to parse node and string structs";
+ return false;
+ }
+
+ int node_id = nodes_list[browser_alloc_index].GetInt();
+ auto it = node_map.find(node_id);
+
+ if (it == node_map.end()) {
+ LOG(ERROR) << "Failed to find frame for node with id: " << node_id;
+ return false;
+ }
+
+ if (it->second.name != frame_name) {
+ LOG(ERROR) << "Wrong name: " << it->second.name
+ << " for frame with expected name: " << frame_name;
+ return false;
+ }
+ }
+
+ // Check that the thread [top frame] has the right name.
+ if (!thread_name.empty()) {
+ NodeMap node_map;
+ if (!ParseNodes(heaps_v2, &node_map)) {
+ LOG(ERROR) << "Failed to parse node and string structs";
+ return false;
+ }
+
+ int node_id = nodes_list[browser_alloc_index].GetInt();
+ auto it = node_map.find(node_id);
+ while (true) {
+ if (it == node_map.end() || it->second.parent_id == kNullParent)
+ break;
+ it = node_map.find(it->second.parent_id);
+ }
+
+ if (it == node_map.end()) {
+ LOG(ERROR) << "Failed to find root for node with id: " << node_id;
+ return false;
+ }
+
+ if (it->second.name != thread_name) {
+ LOG(ERROR) << "Wrong name: " << it->second.name
+ << " for thread with expected name: " << thread_name;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// |expected_size| of 0 means no expectation.
+bool GetAllocatorSubarray(base::Value* heaps_v2,
+ const char* allocator_name,
+ const char* subarray_name,
+ size_t expected_size,
+ const base::Value::ListStorage** output) {
+ base::Value* subarray =
+ heaps_v2->FindPath({"allocators", allocator_name, subarray_name});
+ if (!subarray) {
+ LOG(ERROR) << "Failed to find path: 'allocators." << allocator_name << "."
+ << subarray_name << "' in heaps v2";
+ return false;
+ }
+
+ const base::Value::ListStorage& subarray_list = subarray->GetList();
+ if (expected_size && subarray_list.size() != expected_size) {
+ LOG(ERROR) << subarray_name << " has wrong size";
+ return false;
+ }
+
+ *output = &subarray_list;
+ return true;
+}
+
+bool ValidateSamplingAllocations(base::Value* heaps_v2,
+ const char* allocator_name,
+ int approximate_size,
+ int approximate_count,
+ const char* type_name) {
+ // Maps type ids to strings.
+ NodeMap type_map;
+ if (!ParseTypes(heaps_v2, &type_map))
+ return false;
+
+ bool found = false;
+ int id_of_type = 0;
+ for (auto& pair : type_map) {
+ if (pair.second.name == type_name) {
+ id_of_type = pair.first;
+ found = true;
+ }
+ }
+
+ if (!found) {
+ LOG(ERROR) << "Failed to find type with name: " << type_name;
+ return false;
+ }
+
+ // Find the type with the appropriate id.
+ const base::Value::ListStorage* types_list;
+ if (!GetAllocatorSubarray(heaps_v2, allocator_name, "types", 0,
+ &types_list)) {
+ return false;
+ }
+
+ found = false;
+ size_t index = 0;
+ for (size_t i = 0; i < types_list->size(); ++i) {
+ if ((*types_list)[i].GetInt() == id_of_type) {
+ index = i;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ LOG(ERROR) << "Failed to find type with correct sid";
+ return false;
+ }
+
+ // Look up the size.
+ const base::Value::ListStorage* sizes;
+ if (!GetAllocatorSubarray(heaps_v2, allocator_name, "sizes",
+ types_list->size(), &sizes)) {
+ return false;
+ }
+
+ if ((*sizes)[index].GetInt() < approximate_size / 2 ||
+ (*sizes)[index].GetInt() > approximate_size * 2) {
+ LOG(ERROR) << "sampling size " << (*sizes)[index].GetInt()
+ << " was not within a factor of 2 of expected size "
+ << approximate_size;
+ return false;
+ }
+
+ // Look up the count.
+ const base::Value::ListStorage* counts;
+ if (!GetAllocatorSubarray(heaps_v2, allocator_name, "counts",
+ types_list->size(), &counts)) {
+ return false;
+ }
+
+ if ((*counts)[index].GetInt() < approximate_count / 2 ||
+ (*counts)[index].GetInt() > approximate_count * 2) {
+ LOG(ERROR) << "sampling size " << (*counts)[index].GetInt()
+ << " was not within a factor of 2 of expected count "
+ << approximate_count;
+ return false;
+ }
+ return true;
+}
+
+bool ValidateProcessMmaps(base::Value* process_mmaps,
+ bool should_have_contents) {
+ base::Value* vm_regions = process_mmaps->FindKey("vm_regions");
+ size_t count = vm_regions->GetList().size();
+ if (should_have_contents) {
+ if (count == 0) {
+ LOG(ERROR) << "vm_regions should have contents, but doesn't";
+ return false;
+ }
+ } else {
+ if (count != 0) {
+ LOG(ERROR) << "vm_regions should be empty, but has contents";
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+TestDriver::TestDriver()
+ : wait_for_ui_thread_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {
+ partition_allocator_.init();
+}
+TestDriver::~TestDriver() {}
+
+bool TestDriver::RunTest(const Options& options) {
+ options_ = options;
+
+ running_on_ui_thread_ =
+ content::BrowserThread::CurrentlyOn(content::BrowserThread::UI);
+
+ // The only thing to test for Mode::kNone is that profiling hasn't started.
+ if (options_.mode == Mode::kNone) {
+ if (running_on_ui_thread_) {
+ has_started_ = Supervisor::GetInstance()->HasStarted();
+ } else {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TestDriver::GetHasStartedOnUIThread,
+ base::Unretained(this)));
+ wait_for_ui_thread_.Wait();
+ }
+ if (has_started_) {
+ LOG(ERROR) << "Profiling should not have started";
+ return false;
+ }
+ return true;
+ }
+
+ if (running_on_ui_thread_) {
+ if (!CheckOrStartProfilingOnUIThreadWithNestedRunLoops())
+ return false;
+ Supervisor::GetInstance()->SetKeepSmallAllocations(true);
+ if (ShouldProfileRenderer())
+ WaitForProfilingToStartForAllRenderersUIThread();
+ if (ShouldProfileBrowser())
+ MakeTestAllocations();
+ CollectResults(true);
+ } else {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TestDriver::CheckOrStartProfilingOnUIThreadAndSignal,
+ base::Unretained(this)));
+ wait_for_ui_thread_.Wait();
+ if (!initialization_success_)
+ return false;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TestDriver::SetKeepSmallAllocationsOnUIThreadAndSignal,
+ base::Unretained(this)));
+ wait_for_ui_thread_.Wait();
+ if (ShouldProfileRenderer()) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(
+ &TestDriver::
+ WaitForProfilingToStartForAllRenderersUIThreadAndSignal,
+ base::Unretained(this)));
+ wait_for_ui_thread_.Wait();
+ }
+ if (ShouldProfileBrowser()) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TestDriver::MakeTestAllocations, base::Unretained(this)));
+ }
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(&TestDriver::CollectResults, base::Unretained(this), false));
+ wait_for_ui_thread_.Wait();
+ }
+
+ std::unique_ptr<base::Value> dump_json =
+ base::JSONReader::Read(serialized_trace_);
+ if (!dump_json) {
+ LOG(ERROR) << "Failed to deserialize trace.";
+ return false;
+ }
+
+ if (!ValidateBrowserAllocations(dump_json.get())) {
+ LOG(ERROR) << "Failed to validate browser allocations";
+ return false;
+ }
+
+ if (!ValidateRendererAllocations(dump_json.get())) {
+ LOG(ERROR) << "Failed to validate renderer allocations";
+ return false;
+ }
+
+ return true;
+}
+
+void TestDriver::GetHasStartedOnUIThread() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ has_started_ = Supervisor::GetInstance()->HasStarted();
+ wait_for_ui_thread_.Signal();
+}
+
+void TestDriver::CheckOrStartProfilingOnUIThreadAndSignal() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ initialization_success_ =
+ CheckOrStartProfilingOnUIThreadWithAsyncSignalling();
+
+ // If the flag is true, then the WaitableEvent will be signaled after
+ // profiling has started.
+ if (!wait_for_profiling_to_start_)
+ wait_for_ui_thread_.Signal();
+}
+
+void TestDriver::SetKeepSmallAllocationsOnUIThreadAndSignal() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ Supervisor::GetInstance()->SetKeepSmallAllocations(true);
+ wait_for_ui_thread_.Signal();
+}
+
+bool TestDriver::CheckOrStartProfilingOnUIThreadWithAsyncSignalling() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ if (options_.profiling_already_started) {
+ if (!Supervisor::GetInstance()->HasStarted()) {
+ LOG(ERROR) << "Profiling should have been started, but wasn't";
+ return false;
+ }
+
+ // Even if profiling has started, it's possible that the allocator shim
+ // has not yet been initialized. Wait for it.
+ if (ShouldProfileBrowser()) {
+ bool already_initialized = SetOnInitAllocatorShimCallbackForTesting(
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_for_ui_thread_)),
+ base::ThreadTaskRunnerHandle::Get());
+ if (!already_initialized) {
+ wait_for_profiling_to_start_ = true;
+ }
+ }
+ return true;
+ }
+
+ content::ServiceManagerConnection* connection =
+ content::ServiceManagerConnection::GetForProcess();
+ if (!connection) {
+ LOG(ERROR) << "A ServiceManagerConnection was not available for the "
+ "current process.";
+ return false;
+ }
+
+ wait_for_profiling_to_start_ = true;
+ base::OnceClosure start_callback;
+
+ // If we're going to profile the browser, then wait for the allocator shim to
+ // start. Otherwise, wait for the Supervisor to start.
+ if (ShouldProfileBrowser()) {
+ SetOnInitAllocatorShimCallbackForTesting(
+ base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_for_ui_thread_)),
+ base::ThreadTaskRunnerHandle::Get());
+ } else {
+ start_callback = base::BindOnce(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_for_ui_thread_));
+ }
+
+ uint32_t sampling_rate = options_.should_sample
+ ? (options_.sample_everything ? 2 : kSampleRate)
+ : 1;
+ Supervisor::GetInstance()->Start(connection, options_.mode,
+ options_.stack_mode, sampling_rate,
+ std::move(start_callback));
+
+ return true;
+}
+
+bool TestDriver::CheckOrStartProfilingOnUIThreadWithNestedRunLoops() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ if (options_.profiling_already_started) {
+ if (!Supervisor::GetInstance()->HasStarted()) {
+ LOG(ERROR) << "Profiling should have been started, but wasn't";
+ return false;
+ }
+
+ // Even if profiling has started, it's possible that the allocator shim
+ // has not yet been initialized. Wait for it.
+ if (ShouldProfileBrowser()) {
+ std::unique_ptr<base::RunLoop> run_loop(new base::RunLoop);
+ bool already_initialized = SetOnInitAllocatorShimCallbackForTesting(
+ run_loop->QuitClosure(), base::ThreadTaskRunnerHandle::Get());
+ if (!already_initialized)
+ run_loop->Run();
+ }
+ return true;
+ }
+
+ content::ServiceManagerConnection* connection =
+ content::ServiceManagerConnection::GetForProcess();
+ if (!connection) {
+ LOG(ERROR) << "A ServiceManagerConnection was not available for the "
+ "current process.";
+ return false;
+ }
+
+ // When this is not-null, initialization should wait for the QuitClosure to be
+ // called.
+ std::unique_ptr<base::RunLoop> run_loop(new base::RunLoop);
+ base::OnceClosure start_callback;
+
+ // If we're going to profile the browser, then wait for the allocator shim to
+ // start. Otherwise, wait for the Supervisor to start.
+ if (ShouldProfileBrowser()) {
+ SetOnInitAllocatorShimCallbackForTesting(
+ run_loop->QuitClosure(), base::ThreadTaskRunnerHandle::Get());
+ } else {
+ start_callback = run_loop->QuitClosure();
+ }
+
+ uint32_t sampling_rate = options_.should_sample
+ ? (options_.sample_everything ? 2 : kSampleRate)
+ : 1;
+ Supervisor::GetInstance()->Start(connection, options_.mode,
+ options_.stack_mode, sampling_rate,
+ std::move(start_callback));
+
+ run_loop->Run();
+
+ return true;
+}
+
+void TestDriver::MakeTestAllocations() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ base::PlatformThread::SetName(kThreadName);
+
+ // In sampling mode, only sampling allocations are relevant.
+ if (!IsRecordingAllAllocations()) {
+ leaks_.reserve(kSamplingAllocCount);
+ for (int i = 0; i < kSamplingAllocCount; ++i) {
+ leaks_.push_back(static_cast<char*>(partition_allocator_.root()->Alloc(
+ kSamplingAllocSize, kSamplingAllocTypeName)));
+ }
+ return;
+ }
+
+ leaks_.reserve(2 * kMallocAllocCount + 1 + kPartitionAllocSize);
+
+ {
+ TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION event(kMallocTypeTag);
+ TRACE_EVENT0(kTestCategory, kMallocEvent);
+
+ for (int i = 0; i < kMallocAllocCount; ++i) {
+ leaks_.push_back(new char[kMallocAllocSize]);
+ }
+ }
+
+ {
+ TRACE_EVENT0(kTestCategory, kPAEvent);
+
+ for (int i = 0; i < kPartitionAllocCount; ++i) {
+ leaks_.push_back(static_cast<char*>(partition_allocator_.root()->Alloc(
+ kPartitionAllocSize, kPartitionAllocTypeName)));
+ }
+ }
+
+ {
+ TRACE_EVENT0(kTestCategory, kVariadicEvent);
+
+ for (int i = 0; i < kVariadicAllocCount; ++i) {
+ leaks_.push_back(new char[i + 8000]); // Variadic allocation.
+ total_variadic_allocations_ += i + 8000;
+ }
+ }
+
+ // // Navigate around to force allocations in the renderer.
+ // ASSERT_TRUE(embedded_test_server()->Start());
+ // ui_test_utils::NavigateToURL(
+ // browser(), embedded_test_server()->GetURL("/english_page.html"));
+ // // Vive la France!
+ // ui_test_utils::NavigateToURL(
+ // browser(), embedded_test_server()->GetURL("/french_page.html"));
+}
+
+void TestDriver::CollectResults(bool synchronous) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ base::Closure finish_tracing_closure;
+ std::unique_ptr<base::RunLoop> run_loop;
+
+ if (synchronous) {
+ run_loop.reset(new base::RunLoop);
+ finish_tracing_closure = run_loop->QuitClosure();
+ } else {
+ finish_tracing_closure = base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait_for_ui_thread_));
+ }
+
+ Supervisor::GetInstance()->RequestTraceWithHeapDump(
+ base::Bind(&TestDriver::TraceFinished, base::Unretained(this),
+ std::move(finish_tracing_closure)),
+ false /* strip_path_from_mapped_files */);
+
+ if (synchronous)
+ run_loop->Run();
+}
+
+void TestDriver::TraceFinished(base::Closure closure,
+ bool success,
+ std::string trace_json) {
+ serialized_trace_.swap(trace_json);
+ std::move(closure).Run();
+}
+
+bool TestDriver::ValidateBrowserAllocations(base::Value* dump_json) {
+ base::Value* heaps_v2 =
+ FindArgDump(base::Process::Current().Pid(), dump_json, "heaps_v2");
+
+ if (options_.mode != Mode::kAll && options_.mode != Mode::kBrowser &&
+ options_.mode != Mode::kMinimal) {
+ if (heaps_v2) {
+ LOG(ERROR) << "There should be no heap dump for the browser.";
+ return false;
+ }
+ return true;
+ }
+
+ if (!heaps_v2) {
+ LOG(ERROR) << "Browser heap dump missing.";
+ return false;
+ }
+
+ bool result = false;
+
+ bool should_validate_dumps = true;
+#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
+ // TODO(ajwong): This step fails on Nexus 5X devices running kit-kat. It works
+ // on Nexus 5X devices running oreo. The problem is that all allocations have
+ // the same [an effectively empty] backtrace and get glommed together. More
+ // investigation is necessary. For now, I'm turning this off for Android.
+ // https://crbug.com/786450.
+ if (!HasPseudoFrames())
+ should_validate_dumps = false;
+#endif
+
+ std::string thread_name = ShouldIncludeNativeThreadNames() ? kThreadName : "";
+
+ if (IsRecordingAllAllocations()) {
+ if (should_validate_dumps) {
+ result = ValidateDump(heaps_v2, kMallocAllocSize * kMallocAllocCount,
+ kMallocAllocCount, "malloc",
+ HasPseudoFrames() ? kMallocTypeTag : nullptr,
+ HasPseudoFrames() ? kMallocEvent : "", thread_name);
+ if (!result) {
+ LOG(ERROR) << "Failed to validate malloc fixed allocations";
+ return false;
+ }
+
+ result = ValidateDump(
+ heaps_v2, total_variadic_allocations_, kVariadicAllocCount, "malloc",
+ nullptr, HasPseudoFrames() ? kVariadicEvent : "", thread_name);
+ if (!result) {
+ LOG(ERROR) << "Failed to validate malloc variadic allocations";
+ return false;
+ }
+ }
+
+ // TODO(ajwong): Like malloc, all Partition-Alloc allocations get glommed
+ // together for some Android device/OS configurations. However, since there
+ // is only one place that uses partition alloc in the browser process [this
+ // test], the count is still valid. This should still be made more robust by
+ // fixing backtrace. https://crbug.com/786450.
+ result = ValidateDump(heaps_v2, kPartitionAllocSize * kPartitionAllocCount,
+ kPartitionAllocCount, "partition_alloc",
+ kPartitionAllocTypeName,
+ HasPseudoFrames() ? kPAEvent : "", thread_name);
+ if (!result) {
+ LOG(ERROR) << "Failed to validate PA allocations";
+ return false;
+ }
+ } else {
+ bool result = ValidateSamplingAllocations(
+ heaps_v2, "partition_alloc", kSamplingAllocSize * kSamplingAllocCount,
+ kSamplingAllocCount, kSamplingAllocTypeName);
+ if (!result) {
+ LOG(ERROR) << "Failed to validate sampling allocations";
+ return false;
+ }
+ }
+
+ int process_count = NumProcessesWithName(dump_json, "Browser", nullptr);
+ if (process_count != 1) {
+ LOG(ERROR) << "Found " << process_count
+ << " processes with name: Browser. Expected 1.";
+ return false;
+ }
+
+ base::Value* process_mmaps =
+ FindArgDump(base::Process::Current().Pid(), dump_json, "process_mmaps");
+ if (!ValidateProcessMmaps(process_mmaps, HasNativeFrames())) {
+ LOG(ERROR) << "Failed to validate browser process mmaps.";
+ return false;
+ }
+
+ return true;
+}
+
+bool TestDriver::ValidateRendererAllocations(base::Value* dump_json) {
+ // On Android Webview, there is may not be a separate Renderer process. If we
+ // are not asked to profile the Renderer, do not perform any Renderer checks.
+ if (!ShouldProfileRenderer())
+ return true;
+
+ std::vector<int> pids;
+ bool result = NumProcessesWithName(dump_json, "Renderer", &pids) >= 1;
+ if (!result) {
+ LOG(ERROR) << "Failed to find process with name Renderer";
+ return false;
+ }
+
+ for (int pid : pids) {
+ base::ProcessId renderer_pid = static_cast<base::ProcessId>(pid);
+ base::Value* heaps_v2 = FindArgDump(renderer_pid, dump_json, "heaps_v2");
+ if (!heaps_v2) {
+ LOG(ERROR) << "Failed to find heaps v2 for renderer";
+ return false;
+ }
+
+ base::Value* process_mmaps =
+ FindArgDump(renderer_pid, dump_json, "process_mmaps");
+ if (!ValidateProcessMmaps(process_mmaps, HasNativeFrames())) {
+ LOG(ERROR) << "Failed to validate renderer process mmaps.";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool TestDriver::ShouldProfileBrowser() {
+ return options_.mode == Mode::kAll || options_.mode == Mode::kBrowser ||
+ options_.mode == Mode::kMinimal;
+}
+
+bool TestDriver::ShouldProfileRenderer() {
+ return options_.mode == Mode::kAll || options_.mode == Mode::kAllRenderers;
+}
+
+bool TestDriver::ShouldIncludeNativeThreadNames() {
+ return options_.stack_mode == mojom::StackMode::NATIVE_WITH_THREAD_NAMES;
+}
+
+bool TestDriver::HasPseudoFrames() {
+ return options_.stack_mode == mojom::StackMode::PSEUDO ||
+ options_.stack_mode == mojom::StackMode::MIXED;
+}
+
+bool TestDriver::HasNativeFrames() {
+ return options_.stack_mode == mojom::StackMode::NATIVE_WITH_THREAD_NAMES ||
+ options_.stack_mode == mojom::StackMode::NATIVE_WITHOUT_THREAD_NAMES ||
+ options_.stack_mode == mojom::StackMode::MIXED;
+}
+
+bool TestDriver::IsRecordingAllAllocations() {
+ return !options_.should_sample || options_.sample_everything;
+}
+
+void TestDriver::WaitForProfilingToStartForAllRenderersUIThread() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ while (true) {
+ std::vector<base::ProcessId> profiled_pids;
+ base::RunLoop run_loop;
+ auto callback = base::BindOnce(
+ [](std::vector<base::ProcessId>* results, base::OnceClosure finished,
+ std::vector<base::ProcessId> pids) {
+ results->swap(pids);
+ std::move(finished).Run();
+ },
+ &profiled_pids, run_loop.QuitClosure());
+ Supervisor::GetInstance()->GetProfiledPids(std::move(callback));
+ run_loop.Run();
+
+ if (RenderersAreBeingProfiled(profiled_pids))
+ break;
+ }
+}
+
+void TestDriver::WaitForProfilingToStartForAllRenderersUIThreadAndSignal() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ Supervisor::GetInstance()->GetProfiledPids(base::BindOnce(
+ &TestDriver::WaitForProfilingToStartForAllRenderersUIThreadCallback,
+ base::Unretained(this)));
+}
+
+void TestDriver::WaitForProfilingToStartForAllRenderersUIThreadCallback(
+ std::vector<base::ProcessId> results) {
+ if (RenderersAreBeingProfiled(results)) {
+ wait_for_ui_thread_.Signal();
+ return;
+ }
+ WaitForProfilingToStartForAllRenderersUIThreadAndSignal();
+}
+
+} // namespace heap_profiling
diff --git a/chromium/components/heap_profiling/test_driver.h b/chromium/components/heap_profiling/test_driver.h
new file mode 100644
index 00000000000..f897c67204e
--- /dev/null
+++ b/chromium/components/heap_profiling/test_driver.h
@@ -0,0 +1,170 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
+#define COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
+
+#include <vector>
+
+#include "base/allocator/partition_allocator/partition_alloc.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/synchronization/waitable_event.h"
+#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+namespace heap_profiling {
+
+enum class Mode;
+
+// This class runs tests for the Heap Profiling Service, a cross-platform,
+// multi-process component.
+//
+// Chrome on Android does not support browser_tests. It does support
+// content_browsertests, but those are not multi-process tests. On Android,
+// processes have to be started via the Activity mechanism, and the test
+// infrastructure does not support this.
+//
+// To avoid test-code duplication, all tests are pulled into this class.
+// browser_tests will directly call this class. The android
+// chrome_public_test_apk will invoke this class via a JNI shim. Since the
+// latter is not running within the gtest framework, this class cannot use
+// EXPECT* and ASSERT* macros. Instead, this class will return a bool indicating
+// success of the entire test. On failure, errors will be output via LOG(ERROR).
+// These will show up in the browser_tests output stream, and will be captured
+// by logcat [the Android logging facility]. The latter is already the canonical
+// mechanism for investigating test failures.
+//
+// Note: Outputting to stderr will not have the desired effect, since that is
+// not captured by logcat.
+class TestDriver {
+ public:
+ struct Options {
+ // The profiling mode to test.
+ Mode mode;
+
+ // The stack profiling mode to test.
+ mojom::StackMode stack_mode;
+
+ // Whether the caller has already started profiling with the given mode.
+ // When false, the test driver is responsible for starting profiling.
+ bool profiling_already_started;
+
+ // Whether to test sampling.
+ bool should_sample;
+
+ // When set to true, the internal sampling_rate is set to 2. While this
+ // doesn't record all allocations, it should record all test allocations
+ // made in this file with exponentially high probability.
+ // When set to false, the internal sampling rate is set to 10000.
+ bool sample_everything;
+ };
+
+ TestDriver();
+ ~TestDriver();
+
+ // If this is called on the content::BrowserThread::UI thread, then the
+ // platform must support nested message loops. [This is currently not
+ // supported on Android].
+ //
+ // Returns whether the test run was successful. Expectation/Assertion failures
+ // will be printed via LOG(ERROR).
+ bool RunTest(const Options& options);
+
+ private:
+ // Populates |has_started_| and then signals |wait_for_ui_thread_|.
+ void GetHasStartedOnUIThread();
+
+ // Populates |initialization_success_| with the result of
+ // |RunInitializationOnUIThread|, and then signals |wait_for_ui_thread_|.
+ void CheckOrStartProfilingOnUIThreadAndSignal();
+
+ // Calls Supervisor::SetKeepSmallAllocations() and then signals
+ // |wait_for_ui_thread_|.
+ void SetKeepSmallAllocationsOnUIThreadAndSignal();
+
+ // If profiling is expected to already be started, confirm it.
+ // Otherwise, start profiling with the given mode.
+ // This method must only be called on platforms that supported nested run
+ // loops on the UI thread.
+ bool CheckOrStartProfilingOnUIThreadWithNestedRunLoops();
+
+ // If profiling is expected to already be started, confirm it.
+ // Otherwise, start profiling with the given mode.
+ // This method must only be called on platforms that are running the
+ // TestDriver from a non-UI thread, which allows for async signalling.
+ bool CheckOrStartProfilingOnUIThreadWithAsyncSignalling();
+
+ // Performs allocations. These are expected to be profiled.
+ void MakeTestAllocations();
+
+ // Collects a trace that contains a heap dump. The result is stored in
+ // |serialized_trace_|.
+ //
+ // When |synchronous| is true, this method spins a nested message loop. When
+ // |synchronous| is false, this method posts some tasks that will eventually
+ // signal |wait_for_ui_thread_|.
+ void CollectResults(bool synchronous);
+
+ void TraceFinished(base::Closure closure,
+ bool success,
+ std::string trace_json);
+
+ bool ValidateBrowserAllocations(base::Value* dump_json);
+ bool ValidateRendererAllocations(base::Value* dump_json);
+
+ bool ShouldProfileBrowser();
+ bool ShouldProfileRenderer();
+ bool ShouldIncludeNativeThreadNames();
+ bool HasPseudoFrames();
+ bool HasNativeFrames();
+ bool IsRecordingAllAllocations();
+
+ void WaitForProfilingToStartForAllRenderersUIThread();
+
+ // Android does not support nested RunLoops. Instead, it signals
+ // |wait_for_ui_thread_| when finished.
+ void WaitForProfilingToStartForAllRenderersUIThreadAndSignal();
+ void WaitForProfilingToStartForAllRenderersUIThreadCallback(
+ std::vector<base::ProcessId> results);
+
+ Options options_;
+
+ // Allocations made by this class. Intentionally leaked, since deallocating
+ // them would trigger a large number of IPCs, which is slow.
+ std::vector<char*> leaks_;
+
+ // Sum of size of all variadic allocations.
+ size_t total_variadic_allocations_ = 0;
+
+ // Use to make PA allocations, which should also be shimmed.
+ base::PartitionAllocatorGeneric partition_allocator_;
+
+ // Contains nothing until |CollectResults| has been called.
+ std::string serialized_trace_;
+
+ // Whether the test was invoked on the ui thread.
+ bool running_on_ui_thread_ = true;
+
+ // Whether the supervisor has started.
+ bool has_started_ = false;
+
+ // Whether an error has occurred.
+ bool initialization_success_ = false;
+
+ // When |true|, initialization will wait for the allocator shim to enable
+ // before continuing.
+ bool wait_for_profiling_to_start_ = false;
+
+ base::WaitableEvent wait_for_ui_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestDriver);
+};
+
+} // namespace heap_profiling
+
+#endif // COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
diff --git a/chromium/components/history/content/browser/download_conversions.cc b/chromium/components/history/content/browser/download_conversions.cc
index 3a6fd5c21a5..60dc386d973 100644
--- a/chromium/components/history/content/browser/download_conversions.cc
+++ b/chromium/components/history/content/browser/download_conversions.cc
@@ -69,6 +69,8 @@ download::DownloadDangerType ToContentDownloadDangerType(
return download::DOWNLOAD_DANGER_TYPE_DANGEROUS_HOST;
case DownloadDangerType::POTENTIALLY_UNWANTED:
return download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED;
+ case DownloadDangerType::WHITELISTED_BY_POLICY:
+ return download::DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY;
case DownloadDangerType::INVALID:
NOTREACHED();
return download::DOWNLOAD_DANGER_TYPE_MAX;
@@ -98,6 +100,8 @@ DownloadDangerType ToHistoryDownloadDangerType(
return DownloadDangerType::DANGEROUS_HOST;
case download::DOWNLOAD_DANGER_TYPE_POTENTIALLY_UNWANTED:
return DownloadDangerType::POTENTIALLY_UNWANTED;
+ case download::DOWNLOAD_DANGER_TYPE_WHITELISTED_BY_POLICY:
+ return DownloadDangerType::WHITELISTED_BY_POLICY;
default:
NOTREACHED();
return DownloadDangerType::INVALID;
diff --git a/chromium/components/history/core/browser/BUILD.gn b/chromium/components/history/core/browser/BUILD.gn
index d3a9b446dbd..10fd62ac60e 100644
--- a/chromium/components/history/core/browser/BUILD.gn
+++ b/chromium/components/history/core/browser/BUILD.gn
@@ -11,6 +11,8 @@ static_library("browser") {
"default_top_sites_provider.h",
"delete_directive_handler.cc",
"delete_directive_handler.h",
+ "domain_mixing_metrics.cc",
+ "domain_mixing_metrics.h",
"download_constants.h",
"download_database.cc",
"download_database.h",
@@ -103,6 +105,7 @@ static_library("browser") {
"//base:i18n",
"//components/data_use_measurement/core",
"//components/favicon_base",
+ "//components/google/core/browser",
"//components/history/core/common",
"//components/keyed_service/core",
"//components/prefs",
@@ -171,6 +174,7 @@ bundle_data("unit_tests_bundle_data") {
"//components/test/data/history/history.31.sql",
"//components/test/data/history/history.32.sql",
"//components/test/data/history/history.38.sql",
+ "//components/test/data/history/history.39.sql",
"//components/test/data/history/thumbnail_wild/Favicons.corrupt_meta.disable",
"//components/test/data/history/thumbnail_wild/Favicons.v2.init.sql",
"//components/test/data/history/thumbnail_wild/Favicons.v3.init.sql",
@@ -191,6 +195,7 @@ source_set("unit_tests") {
testonly = true
sources = [
"browsing_history_service_unittest.cc",
+ "domain_mixing_metrics_unittest.cc",
"download_slice_info_unittest.cc",
"expire_history_backend_unittest.cc",
"history_backend_db_unittest.cc",
diff --git a/chromium/components/history/core/browser/DEPS b/chromium/components/history/core/browser/DEPS
index d8117751610..26e3a1cc0b1 100644
--- a/chromium/components/history/core/browser/DEPS
+++ b/chromium/components/history/core/browser/DEPS
@@ -1,5 +1,6 @@
include_rules = [
"+components/data_use_measurement/core",
+ "+components/google/core/browser/google_util.h",
"+components/variations",
"+services/identity/public",
]
diff --git a/chromium/components/history/core/browser/android/visit_sql_handler.cc b/chromium/components/history/core/browser/android/visit_sql_handler.cc
index 97222dd4339..5af06e70487 100644
--- a/chromium/components/history/core/browser/android/visit_sql_handler.cc
+++ b/chromium/components/history/core/browser/android/visit_sql_handler.cc
@@ -121,7 +121,7 @@ bool VisitSQLHandler::AddVisit(URLID url_id, const Time& visit_time) {
// TODO : Is 'ui::PAGE_TRANSITION_AUTO_BOOKMARK' proper?
// if not, a new ui::PageTransition type will need.
VisitRow visit_row(url_id, visit_time, 0,
- ui::PAGE_TRANSITION_AUTO_BOOKMARK, 0);
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK, 0, false);
return visit_db_->AddVisit(&visit_row, SOURCE_BROWSED);
}
diff --git a/chromium/components/history/core/browser/browsing_history_service.cc b/chromium/components/history/core/browser/browsing_history_service.cc
index fbb4f4a9c7e..153dad43e1d 100644
--- a/chromium/components/history/core/browser/browsing_history_service.cc
+++ b/chromium/components/history/core/browser/browsing_history_service.cc
@@ -742,11 +742,9 @@ static bool DeletionsDiffer(const URLRows& deleted_rows,
}
void BrowsingHistoryService::OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
- if (all_history || DeletionsDiffer(deleted_rows, urls_to_be_deleted_))
+ const DeletionInfo& deletion_info) {
+ if (deletion_info.IsAllHistory() ||
+ DeletionsDiffer(deletion_info.deleted_rows(), urls_to_be_deleted_))
driver_->HistoryDeleted();
}
diff --git a/chromium/components/history/core/browser/browsing_history_service.h b/chromium/components/history/core/browser/browsing_history_service.h
index 41d15e9dae2..b768c8a4744 100644
--- a/chromium/components/history/core/browser/browsing_history_service.h
+++ b/chromium/components/history/core/browser/browsing_history_service.h
@@ -202,10 +202,7 @@ class BrowsingHistoryService : public HistoryServiceObserver,
// HistoryServiceObserver implementation.
void OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const DeletionInfo& deletion_info) override;
// WebHistoryServiceObserver implementation.
void OnWebHistoryDeleted() override;
diff --git a/chromium/components/history/core/browser/delete_directive_handler.cc b/chromium/components/history/core/browser/delete_directive_handler.cc
index de730f6de8b..a0b737bb02b 100644
--- a/chromium/components/history/core/browser/delete_directive_handler.cc
+++ b/chromium/components/history/core/browser/delete_directive_handler.cc
@@ -178,7 +178,7 @@ bool DeleteDirectiveHandler::DeleteDirectiveTask::RunOnDBThread(
}
void DeleteDirectiveHandler::DeleteDirectiveTask::DoneRunOnMainThread() {
- if (delete_directive_handler_.get()) {
+ if (delete_directive_handler_) {
delete_directive_handler_->FinishProcessing(post_processing_action_,
delete_directives_);
}
diff --git a/chromium/components/history/core/browser/domain_mixing_metrics.cc b/chromium/components/history/core/browser/domain_mixing_metrics.cc
new file mode 100644
index 00000000000..88742939722
--- /dev/null
+++ b/chromium/components/history/core/browser/domain_mixing_metrics.cc
@@ -0,0 +1,150 @@
+// 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 "components/history/core/browser/domain_mixing_metrics.h"
+
+#include "base/containers/flat_map.h"
+#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+
+namespace history {
+namespace {
+
+// For readability, represents days as times rounded down to a multiple in
+// days from begin_time.
+using Day = base::Time;
+using DomainVisits = base::flat_map<std::string, int>;
+using DomainVisitsPerDay = base::flat_map<Day, DomainVisits>;
+
+// The time intervals in days to compute domain mixing metrics for, sorted
+// in ascending order.
+std::vector<int> NumDaysForMetrics() {
+ return {1, 7, 14, 30};
+}
+
+// Maps a time to the start of a day using ref_start_of_day as the reference
+// time for the start of a day. Some examples:
+//
+// time = 2018-01-02 13:00:00 UTC
+// ref = 2018-01-04 04:00:00 UTC
+// result = 2018-01-02 04:00:00 UTC
+//
+// time = 2018-01-06 03:00:00 UTC
+// ref = 2018-01-04 04:00:00 UTC
+// result = 2018-01-05 04:00:00 UTC
+Day ToStartOfDay(base::Time time, Day ref_start_of_day) {
+ return ref_start_of_day +
+ base::TimeDelta::FromDays((time - ref_start_of_day).InDaysFloored());
+}
+
+// Counts the number of visits per day and per domain as a nested map
+// day -> domain -> num_visits.
+// start_of_day is used as the reference time for the start of a day.
+DomainVisitsPerDay CountDomainVisitsPerDay(
+ base::Time start_of_day,
+ const std::vector<DomainVisit>& domain_visits) {
+ DomainVisitsPerDay domain_visits_per_day;
+ for (const DomainVisit& visit : domain_visits) {
+ const Day day = ToStartOfDay(visit.visit_time(), start_of_day);
+ DomainVisits& domain_visits_for_day = domain_visits_per_day[day];
+ ++domain_visits_for_day[visit.domain()];
+ }
+ return domain_visits_per_day;
+}
+
+// Computes the domain mixing ratio given the number of visits for each domain.
+double ComputeDomainMixingRatio(const DomainVisits& domain_visits) {
+ // First, we extract the domain with the most visits.
+ const auto top_domain = std::max_element(
+ domain_visits.begin(), domain_visits.end(),
+ [](const DomainVisits::value_type& a, const DomainVisits::value_type& b) {
+ return a.second < b.second;
+ });
+
+ // Then we compute the number of visits that are not on the top domain
+ // (secondary domains).
+ int other_visits = 0;
+ for (const auto& domain_num_visits : domain_visits) {
+ if (domain_num_visits.first != top_domain->first)
+ other_visits += domain_num_visits.second;
+ }
+
+ // Finally, we compute the domain mixing ratio which is the ratio of the
+ // number of visits on secondary domains to the total number of visits.
+ // This ratio is equal to 0 if all visits are on the top domain (no domain
+ // mixing) and is close to 1 if most visits are on secondary domains.
+ DCHECK_GT(other_visits + top_domain->second, 0)
+ << "Tried to compute domain mixing for a time range with no domain "
+ "visits, this should never happen as we only compute domain mixing "
+ "for active days.";
+ return static_cast<double>(other_visits) /
+ (other_visits + top_domain->second);
+}
+
+void EmitDomainMixingMetric(const DomainVisits& domain_visits, int num_days) {
+ double domain_mixing_ratio = ComputeDomainMixingRatio(domain_visits);
+ int percentage = gfx::ToRoundedInt(100 * domain_mixing_ratio);
+ switch (num_days) {
+ case 1:
+ UMA_HISTOGRAM_PERCENTAGE("DomainMixing.OneDay", percentage);
+ break;
+ case 7:
+ UMA_HISTOGRAM_PERCENTAGE("DomainMixing.OneWeek", percentage);
+ break;
+ case 14:
+ UMA_HISTOGRAM_PERCENTAGE("DomainMixing.TwoWeeks", percentage);
+ break;
+ case 30:
+ UMA_HISTOGRAM_PERCENTAGE("DomainMixing.OneMonth", percentage);
+ break;
+ default:
+ // This should never happen.
+ NOTREACHED();
+ }
+}
+
+void EmitDomainMixingMetricsForDay(
+ const DomainVisitsPerDay::const_iterator& active_day,
+ const DomainVisitsPerDay& domain_visits_per_day) {
+ DomainVisits domain_visits = active_day->second;
+ // To efficiently compute domain mixing for each of the time periods, we
+ // aggregate domain visits preceding the active day in a single pass.
+ // The metrics to emit are sorted by increasing time period lengths.
+ // We take them in order, aggregate the number of activity days required
+ // for the current one, then move on to the next one.
+ // Reverse iterator, starting at the day before active_day.
+ auto it = std::make_reverse_iterator(active_day);
+ for (const int num_days : NumDaysForMetrics()) {
+ const Day first_day =
+ active_day->first - base::TimeDelta::FromDays(num_days - 1);
+ for (; it != domain_visits_per_day.rend() && it->first >= first_day; ++it) {
+ for (const auto& domain_num_visits : it->second) {
+ domain_visits[domain_num_visits.first] += domain_num_visits.second;
+ }
+ }
+ // We have aggregated all the days within the time window for the current
+ // metric.
+ EmitDomainMixingMetric(domain_visits, num_days);
+ }
+}
+
+} // namespace
+
+void EmitDomainMixingMetrics(const std::vector<DomainVisit>& domain_visits,
+ base::Time start_of_first_day_to_emit) {
+ // We count the visits per domain for each day of user activity.
+ DomainVisitsPerDay domain_visits_per_day =
+ CountDomainVisitsPerDay(start_of_first_day_to_emit, domain_visits);
+
+ // We then compute domain mixing metrics for each day of activity within
+ // [start_of_first_day_to_emit, last_day].
+ for (auto active_day_it =
+ domain_visits_per_day.lower_bound(start_of_first_day_to_emit);
+ active_day_it != domain_visits_per_day.end(); ++active_day_it) {
+ EmitDomainMixingMetricsForDay(active_day_it, domain_visits_per_day);
+ }
+}
+
+} // namespace history \ No newline at end of file
diff --git a/chromium/components/history/core/browser/domain_mixing_metrics.h b/chromium/components/history/core/browser/domain_mixing_metrics.h
new file mode 100644
index 00000000000..7ae2e514446
--- /dev/null
+++ b/chromium/components/history/core/browser/domain_mixing_metrics.h
@@ -0,0 +1,35 @@
+// 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 COMPONENTS_HISTORY_CORE_BROWSER_DOMAIN_MIXING_METRICS_H_
+#define COMPONENTS_HISTORY_CORE_BROWSER_DOMAIN_MIXING_METRICS_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/time/time.h"
+#include "components/history/core/browser/history_types.h"
+
+namespace history {
+
+// Emits domain mixing metrics given a list of domain visits and the start of
+// the first day to compute metrics for.
+//
+// See http://goto.google.com/chrome-no-searchdomaincheck for more details on
+// what domain mixing metrics are and how they are computed.
+//
+// The domain_visits vector is expected to contain exactly all the domain visits
+// made by the user from start_of_first_day_to_emit - 29 days (to compute the 30
+// day domain mixing metric for the first day) until the end of the last day to
+// compute metrics for.
+//
+// This method wraps the business logic required to compute domain mixing
+// metrics and is exposed for testing purposes to decouple testing the logic
+// that computes the metrics from the database logic.
+void EmitDomainMixingMetrics(const std::vector<DomainVisit>& domain_visits,
+ base::Time start_of_first_day_to_emit);
+
+} // namespace history
+
+#endif \ No newline at end of file
diff --git a/chromium/components/history/core/browser/domain_mixing_metrics_unittest.cc b/chromium/components/history/core/browser/domain_mixing_metrics_unittest.cc
new file mode 100644
index 00000000000..b03bdbf4aec
--- /dev/null
+++ b/chromium/components/history/core/browser/domain_mixing_metrics_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/history/core/browser/domain_mixing_metrics.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/test/histogram_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace history {
+
+class DomainMixingMetricsTest : public testing::Test {
+ protected:
+ base::HistogramTester tester_;
+};
+
+TEST_F(DomainMixingMetricsTest, NoVisits) {
+ base::Time now =
+ base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1523432317);
+ EmitDomainMixingMetrics({}, now);
+
+ // Check that no metrics were emitted.
+ tester_.ExpectTotalCount("DomainMixing.OneDay", 0);
+ tester_.ExpectTotalCount("DomainMixing.OneWeek", 0);
+ tester_.ExpectTotalCount("DomainMixing.TwoWeeks", 0);
+ tester_.ExpectTotalCount("DomainMixing.OneMonth", 0);
+}
+
+TEST_F(DomainMixingMetricsTest, WithVisits) {
+ // Given the following Google domain visits:
+ // - Day 1, 1am, www.google.com
+ // - Day 2, 11pm, www.google.ch
+ // - Day 8, 2am, www.google.ch
+ // - Day 8, 10pm, www.google.fr
+ // this test checks that the correct domain mixing metrics for Day 8 are
+ // emitted:
+ // DomainMixing.OneDay 50% (Day 8 has one query on .ch, one on .fr)
+ // DomainMixing.OneWeek 33% (2 on .ch, 1 on .fr, day 1 is out of range)
+ // DomainMixing.TwoWeeks 50% (2 on .ch, 2 on other domains - 1.fr and 1 .com)
+ // DomainMixing.OneMonth 50% (ditto)
+ base::Time day1 =
+ base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1523432317);
+ base::Time day2 = day1 + base::TimeDelta::FromDays(1);
+ base::Time day8 = day1 + base::TimeDelta::FromDays(7);
+ EmitDomainMixingMetrics(
+ {
+ DomainVisit("www.google.com", day1 + base::TimeDelta::FromHours(1)),
+ DomainVisit("www.google.ch", day2 + base::TimeDelta::FromHours(23)),
+ DomainVisit("www.google.ch", day8 + base::TimeDelta::FromHours(2)),
+ DomainVisit("www.google.fr", day8 + base::TimeDelta::FromHours(22)),
+ },
+ day8);
+
+ tester_.ExpectUniqueSample("DomainMixing.OneDay", 50, 1);
+ tester_.ExpectUniqueSample("DomainMixing.OneWeek", 33, 1);
+ tester_.ExpectUniqueSample("DomainMixing.TwoWeeks", 50, 1);
+ tester_.ExpectUniqueSample("DomainMixing.OneMonth", 50, 1);
+}
+
+TEST_F(DomainMixingMetricsTest, WithInactiveDays) {
+ base::Time day1 =
+ base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(1523432317);
+ base::Time day3 = day1 + base::TimeDelta::FromDays(2);
+ EmitDomainMixingMetrics(
+ {
+ DomainVisit("www.google.com", day1),
+ DomainVisit("www.google.ch", day3),
+ },
+ day1);
+
+ // Check that no metrics are emitted for day2 when the user was inactive.
+ tester_.ExpectTotalCount("DomainMixing.OneDay", 2);
+ tester_.ExpectBucketCount("DomainMixing.OneDay", 0, 2); // Day 1 and 3.
+ tester_.ExpectTotalCount("DomainMixing.OneWeek", 2);
+ tester_.ExpectBucketCount("DomainMixing.OneWeek", 0, 1); // Day 1.
+ tester_.ExpectBucketCount("DomainMixing.OneWeek", 50, 1); // Day 3.
+ tester_.ExpectTotalCount("DomainMixing.TwoWeeks", 2);
+ tester_.ExpectBucketCount("DomainMixing.TwoWeeks", 0, 1); // Day 1.
+ tester_.ExpectBucketCount("DomainMixing.TwoWeeks", 50, 1); // Day 3.
+ tester_.ExpectTotalCount("DomainMixing.OneMonth", 2);
+ tester_.ExpectBucketCount("DomainMixing.OneMonth", 0, 1); // Day 1.
+ tester_.ExpectBucketCount("DomainMixing.OneMonth", 50, 1); // Day 3.
+}
+
+} // namespace history \ No newline at end of file
diff --git a/chromium/components/history/core/browser/download_constants.h b/chromium/components/history/core/browser/download_constants.h
index ea21725fafa..78530f340ce 100644
--- a/chromium/components/history/core/browser/download_constants.h
+++ b/chromium/components/history/core/browser/download_constants.h
@@ -35,6 +35,7 @@ enum class DownloadDangerType {
USER_VALIDATED = 6,
DANGEROUS_HOST = 7,
POTENTIALLY_UNWANTED = 8,
+ WHITELISTED_BY_POLICY = 9,
};
// DownloadId represents the id of a DownloadRow into the DownloadDatabase.
diff --git a/chromium/components/history/core/browser/download_types.cc b/chromium/components/history/core/browser/download_types.cc
index e75081e5b1c..1c740856649 100644
--- a/chromium/components/history/core/browser/download_types.cc
+++ b/chromium/components/history/core/browser/download_types.cc
@@ -63,6 +63,7 @@ DownloadDangerType IntToDownloadDangerType(int danger_type) {
case DownloadDangerType::USER_VALIDATED:
case DownloadDangerType::DANGEROUS_HOST:
case DownloadDangerType::POTENTIALLY_UNWANTED:
+ case DownloadDangerType::WHITELISTED_BY_POLICY:
return static_cast<DownloadDangerType>(danger_type);
case DownloadDangerType::INVALID:
@@ -100,6 +101,8 @@ std::ostream& operator<<(std::ostream& stream, DownloadDangerType danger_type) {
return stream << "history::DownloadDangerType::DANGEROUS_HOST";
case DownloadDangerType::POTENTIALLY_UNWANTED:
return stream << "history::DownloadDangerType::POTENTIALLY_UNWANTED";
+ case DownloadDangerType::WHITELISTED_BY_POLICY:
+ return stream << "history::DownloadDangerType::WHITELISTED_BY_POLICY";
}
NOTREACHED();
return stream;
diff --git a/chromium/components/history/core/browser/expire_history_backend.cc b/chromium/components/history/core/browser/expire_history_backend.cc
index e55dc56bf4e..ef0b2e3dc22 100644
--- a/chromium/components/history/core/browser/expire_history_backend.cc
+++ b/chromium/components/history/core/browser/expire_history_backend.cc
@@ -13,13 +13,13 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/containers/flat_set.h"
-#include "base/feature_list.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
+#include "build/build_config.h"
#include "components/history/core/browser/history_backend_client.h"
#include "components/history/core/browser/history_backend_notifier.h"
#include "components/history/core/browser/history_database.h"
@@ -117,6 +117,11 @@ const int kExpirationDelaySec = 30;
// iteration, so we want to wait longer before checking to avoid wasting CPU.
const int kExpirationEmptyDelayMin = 5;
+// If the expiration timer is delayed by over an hour, then assume that the
+// machine went to sleep.
+constexpr base::TimeDelta kExpirationSleepWakeupThreshold =
+ base::TimeDelta::FromHours(1);
+
// The minimum number of hours between checking for old on-demand favicons that
// should be cleared.
const int kClearOnDemandFaviconsIntervalHours = 24;
@@ -134,8 +139,12 @@ bool IsAnyURLBookmarked(HistoryBackendClient* backend_client,
namespace internal {
-const base::Feature kClearOldOnDemandFavicons{
- "ClearOldOnDemandFavicons", base::FEATURE_DISABLED_BY_DEFAULT};
+// Clearing old on-demand favicons is only enabled on mobile.
+#if defined(OS_ANDROID) || defined(OS_IOS)
+constexpr bool kClearOldOnDemandFaviconsEnabled = true;
+#else
+constexpr bool kClearOldOnDemandFaviconsEnabled = false;
+#endif
const int kOnDemandFaviconIsOldAfterDays = 30;
@@ -213,7 +222,7 @@ void ExpireHistoryBackend::DeleteURLs(const std::vector<GURL>& urls) {
DeleteFaviconsIfPossible(&effects);
BroadcastNotifications(&effects, DELETION_USER_INITIATED,
- DeletionTimeRange::Invalid());
+ DeletionTimeRange::Invalid(), base::nullopt);
}
void ExpireHistoryBackend::ExpireHistoryBetween(
@@ -239,10 +248,8 @@ void ExpireHistoryBackend::ExpireHistoryBetween(
visits.push_back(*visit);
}
}
- DeletionTimeRange time_range = restrict_urls.empty()
- ? DeletionTimeRange(begin_time, end_time)
- : DeletionTimeRange::Invalid();
- ExpireVisitsInternal(visits, time_range);
+ DeletionTimeRange time_range(begin_time, end_time);
+ ExpireVisitsInternal(visits, time_range, restrict_urls);
}
void ExpireHistoryBackend::ExpireHistoryForTimes(
@@ -265,12 +272,13 @@ void ExpireHistoryBackend::ExpireHistoryForTimes(
}
void ExpireHistoryBackend::ExpireVisits(const VisitVector& visits) {
- ExpireVisitsInternal(visits, DeletionTimeRange::Invalid());
+ ExpireVisitsInternal(visits, DeletionTimeRange::Invalid(), {});
}
void ExpireHistoryBackend::ExpireVisitsInternal(
const VisitVector& visits,
- const DeletionTimeRange& time_range) {
+ const DeletionTimeRange& time_range,
+ const std::set<GURL>& restrict_urls) {
if (visits.empty())
return;
@@ -287,7 +295,9 @@ void ExpireHistoryBackend::ExpireVisitsInternal(
// and we don't want to leave any evidence.
ExpireURLsForVisits(visits_and_redirects, &effects);
DeleteFaviconsIfPossible(&effects);
- BroadcastNotifications(&effects, DELETION_USER_INITIATED, time_range);
+ BroadcastNotifications(
+ &effects, DELETION_USER_INITIATED, time_range,
+ restrict_urls.empty() ? base::Optional<std::set<GURL>>() : restrict_urls);
// Pick up any bits possibly left over.
ParanoidExpireHistory();
@@ -301,7 +311,7 @@ void ExpireHistoryBackend::ExpireVisitsInternal(
}
}
-void ExpireHistoryBackend::ExpireHistoryBefore(base::Time end_time) {
+void ExpireHistoryBackend::ExpireHistoryBeforeForTesting(base::Time end_time) {
if (!main_db_)
return;
@@ -372,14 +382,15 @@ void ExpireHistoryBackend::DeleteFaviconsIfPossible(DeleteEffects* effects) {
void ExpireHistoryBackend::BroadcastNotifications(
DeleteEffects* effects,
DeletionType type,
- const DeletionTimeRange& time_range) {
+ const DeletionTimeRange& time_range,
+ base::Optional<std::set<GURL>> restrict_urls) {
if (!effects->modified_urls.empty()) {
notifier_->NotifyURLsModified(effects->modified_urls);
}
if (!effects->deleted_urls.empty() || time_range.IsValid()) {
- notifier_->NotifyURLsDeleted(time_range, type == DELETION_EXPIRED,
- effects->deleted_urls,
- effects->deleted_favicons);
+ notifier_->NotifyURLsDeleted(DeletionInfo(
+ time_range, type == DELETION_EXPIRED, std::move(effects->deleted_urls),
+ std::move(effects->deleted_favicons), std::move(restrict_urls)));
}
}
@@ -465,12 +476,7 @@ void ExpireHistoryBackend::ExpireURLsForVisits(const VisitVector& visits,
ui::PAGE_TRANSITION_RELOAD)) {
cur.visit_count++;
}
- if (ui::PageTransitionIsNewNavigation(visits[i].transition) &&
- ((ui::PageTransitionCoreTypeIs(visits[i].transition,
- ui::PAGE_TRANSITION_TYPED) &&
- !ui::PageTransitionIsRedirect(visits[i].transition)) ||
- ui::PageTransitionCoreTypeIs(visits[i].transition,
- ui::PAGE_TRANSITION_KEYWORD_GENERATED)))
+ if (visits[i].incremented_omnibox_typed_score)
cur.typed_count++;
}
@@ -524,6 +530,7 @@ void ExpireHistoryBackend::ScheduleExpire() {
delay = base::TimeDelta::FromSeconds(kExpirationDelaySec);
}
+ expected_expiration_time_ = base::Time::Now() + delay;
task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&ExpireHistoryBackend::DoExpireIteration,
@@ -534,6 +541,21 @@ void ExpireHistoryBackend::ScheduleExpire() {
void ExpireHistoryBackend::DoExpireIteration() {
DCHECK(!work_queue_.empty()) << "queue has to be non-empty";
+ // If the timer is firing more than an hour later than expected, than the
+ // machine likely just woke from sleep/hibernation. There is potentially a lot
+ // of expiring that needs to happen. Wait for 5 minutes before starting to do
+ // any expiry, to avoid conflicting with other work that happens on waking
+ // from sleep.
+ if (base::Time::Now() - expected_expiration_time_ >
+ kExpirationSleepWakeupThreshold) {
+ task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ExpireHistoryBackend::ScheduleExpire,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMinutes(kExpirationEmptyDelayMin));
+ return;
+ }
+
const ExpiringVisitsReader* reader = work_queue_.front();
bool more_to_expire = ExpireSomeOldHistory(
GetCurrentExpirationTime(), reader, kNumExpirePerIteration);
@@ -543,7 +565,7 @@ void ExpireHistoryBackend::DoExpireIteration() {
// If there are more items to expire, add the reader back to the queue, thus
// creating a new task for future iterations.
work_queue_.push(reader);
- } else {
+ } else if (internal::kClearOldOnDemandFaviconsEnabled) {
// Otherwise do a final clean-up - remove old favicons not bound to visits.
ClearOldOnDemandFaviconsIfPossible(
base::Time::Now() -
@@ -558,9 +580,6 @@ void ExpireHistoryBackend::ClearOldOnDemandFaviconsIfPossible(
if (!thumb_db_)
return;
- if (!base::FeatureList::IsEnabled(internal::kClearOldOnDemandFavicons))
- return;
-
// Extra precaution to avoid repeated calls to GetOldOnDemandFavicons() close
// in time, since it can be fairly expensive.
if (expiration_threshold <
@@ -590,7 +609,7 @@ void ExpireHistoryBackend::ClearOldOnDemandFaviconsIfPossible(
}
BroadcastNotifications(&effects, DELETION_EXPIRED,
- DeletionTimeRange::Invalid());
+ DeletionTimeRange::Invalid(), base::nullopt);
}
bool ExpireHistoryBackend::ExpireSomeOldHistory(
@@ -613,10 +632,9 @@ bool ExpireHistoryBackend::ExpireSomeOldHistory(
DeleteVisitRelatedInfo(deleted_visits, &deleted_effects);
ExpireURLsForVisits(deleted_visits, &deleted_effects);
DeleteFaviconsIfPossible(&deleted_effects);
- DeletionTimeRange time_range =
- more_to_expire ? DeletionTimeRange::Invalid()
- : DeletionTimeRange(base::Time(), end_time);
- BroadcastNotifications(&deleted_effects, DELETION_EXPIRED, time_range);
+
+ BroadcastNotifications(&deleted_effects, DELETION_EXPIRED,
+ DeletionTimeRange::Invalid(), base::nullopt);
return more_to_expire;
}
diff --git a/chromium/components/history/core/browser/expire_history_backend.h b/chromium/components/history/core/browser/expire_history_backend.h
index 1c89f47e8fd..c936412effc 100644
--- a/chromium/components/history/core/browser/expire_history_backend.h
+++ b/chromium/components/history/core/browser/expire_history_backend.h
@@ -20,7 +20,6 @@ class GURL;
class TestingProfile;
namespace base {
-struct Feature;
class SequencedTaskRunner;
}
@@ -44,9 +43,6 @@ class ExpiringVisitsReader {
typedef std::vector<const ExpiringVisitsReader*> ExpiringVisitsReaders;
namespace internal {
-// Feature that enables clearing old on-demand favicons.
-extern const base::Feature kClearOldOnDemandFavicons;
-
// The minimum number of days since last use for an icon to be considered old.
extern const int kOnDemandFaviconIsOldAfterDays;
} // namespace internal
@@ -96,8 +92,8 @@ class ExpireHistoryBackend {
void ExpireVisits(const VisitVector& visits);
// Expires all visits before and including the given time, updating the URLs
- // accordingly. Currently only used for testing.
- void ExpireHistoryBefore(base::Time end_time);
+ // accordingly.
+ void ExpireHistoryBeforeForTesting(base::Time end_time);
// Returns the current cut-off time before which we will start expiring stuff.
// Note that this as an absolute time rather than a delta, so the caller
@@ -202,7 +198,8 @@ class ExpireHistoryBackend {
void ExpireURLsForVisits(const VisitVector& visits, DeleteEffects* effects);
void ExpireVisitsInternal(const VisitVector& visits,
- const DeletionTimeRange& time_range);
+ const DeletionTimeRange& time_range,
+ const std::set<GURL>& restrict_urls);
// Deletes the favicons listed in |effects->affected_favicons| if they are
// unsued. Fails silently (we don't care about favicons so much, so don't want
@@ -223,7 +220,8 @@ class ExpireHistoryBackend {
// Broadcasts URL modified and deleted notifications.
void BroadcastNotifications(DeleteEffects* effects,
DeletionType type,
- const DeletionTimeRange& time_range);
+ const DeletionTimeRange& time_range,
+ base::Optional<std::set<GURL>> restrict_urls);
// Schedules a call to DoExpireIteration.
void ScheduleExpire();
@@ -272,6 +270,9 @@ class ExpireHistoryBackend {
// The threshold for "old" history where we will automatically delete it.
base::TimeDelta expiration_threshold_;
+ // The time at which we expect the expiration code to run.
+ base::Time expected_expiration_time_;
+
// The lastly used threshold for "old" on-demand favicons.
base::Time last_on_demand_expiration_threshold_;
diff --git a/chromium/components/history/core/browser/expire_history_backend_unittest.cc b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
index 2e98f96b093..a0215c0a522 100644
--- a/chromium/components/history/core/browser/expire_history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/expire_history_backend_unittest.cc
@@ -16,7 +16,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
#include "base/strings/string16.h"
@@ -105,9 +105,10 @@ class ExpireHistoryTest : public testing::Test, public HistoryBackendNotifier {
// |expired|, or manually deleted.
void EnsureURLInfoGone(const URLRow& row, bool expired);
- DeletionTimeRange GetLastDeletionTimeRange() {
- EXPECT_FALSE(urls_deleted_notifications_.empty());
- return std::get<0>(urls_deleted_notifications_.back());
+ const DeletionInfo* GetLastDeletionInfo() {
+ if (urls_deleted_notifications_.empty())
+ return nullptr;
+ return &urls_deleted_notifications_.back();
}
// Returns whether HistoryBackendNotifier::NotifyURLsModified was
@@ -148,8 +149,7 @@ class ExpireHistoryTest : public testing::Test, public HistoryBackendNotifier {
typedef std::vector<URLRows> URLsModifiedNotificationList;
URLsModifiedNotificationList urls_modified_notifications_;
- typedef std::vector<std::tuple<DeletionTimeRange, bool, URLRows>>
- URLsDeletedNotificationList;
+ typedef std::vector<DeletionInfo> URLsDeletedNotificationList;
URLsDeletedNotificationList urls_deleted_notifications_;
private:
@@ -191,7 +191,7 @@ class ExpireHistoryTest : public testing::Test, public HistoryBackendNotifier {
top_sites_->ShutdownOnUIThread();
top_sites_ = nullptr;
- if (base::MessageLoop::current())
+ if (base::MessageLoopCurrent::Get())
base::RunLoop().RunUntilIdle();
pref_service_.reset();
@@ -207,11 +207,8 @@ class ExpireHistoryTest : public testing::Test, public HistoryBackendNotifier {
void NotifyURLsModified(const URLRows& rows) override {
urls_modified_notifications_.push_back(rows);
}
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& rows,
- const std::set<GURL>& favicon_urls) override {
- urls_deleted_notifications_.push_back(std::tie(time_range, expired, rows));
+ void NotifyURLsDeleted(DeletionInfo deletion_info) override {
+ urls_deleted_notifications_.push_back(std::move(deletion_info));
}
};
@@ -229,7 +226,7 @@ class ExpireHistoryTest : public testing::Test, public HistoryBackendNotifier {
// added to the given arrays.
void ExpireHistoryTest::AddExampleData(URLID url_ids[3],
base::Time visit_times[4]) {
- if (!main_db_.get())
+ if (!main_db_)
return;
// Four times for each visit.
@@ -289,6 +286,7 @@ void ExpireHistoryTest::AddExampleData(URLID url_ids[3],
visit_row3.url_id = url_ids[1];
visit_row3.visit_time = visit_times[2];
visit_row3.transition = ui::PAGE_TRANSITION_TYPED;
+ visit_row3.incremented_omnibox_typed_score = true;
main_db_->AddVisit(&visit_row3, SOURCE_BROWSED);
VisitRow visit_row4;
@@ -311,23 +309,24 @@ void ExpireHistoryTest::AddExampleSourceData(const GURL& url, URLID* id) {
// Four times for each visit.
VisitRow visit_row1(url_id, last_visit_time - base::TimeDelta::FromDays(4), 0,
- ui::PAGE_TRANSITION_TYPED, 0);
+ ui::PAGE_TRANSITION_TYPED, 0, true);
main_db_->AddVisit(&visit_row1, SOURCE_SYNCED);
VisitRow visit_row2(url_id, last_visit_time - base::TimeDelta::FromDays(3), 0,
- ui::PAGE_TRANSITION_TYPED, 0);
+ ui::PAGE_TRANSITION_TYPED, 0, true);
main_db_->AddVisit(&visit_row2, SOURCE_BROWSED);
VisitRow visit_row3(url_id, last_visit_time - base::TimeDelta::FromDays(2), 0,
- ui::PAGE_TRANSITION_TYPED, 0);
+ ui::PAGE_TRANSITION_TYPED, 0, true);
main_db_->AddVisit(&visit_row3, SOURCE_EXTENSION);
- VisitRow visit_row4(url_id, last_visit_time, 0, ui::PAGE_TRANSITION_TYPED, 0);
+ VisitRow visit_row4(url_id, last_visit_time, 0, ui::PAGE_TRANSITION_TYPED, 0,
+ true);
main_db_->AddVisit(&visit_row4, SOURCE_FIREFOX_IMPORTED);
}
bool ExpireHistoryTest::HasFavicon(favicon_base::FaviconID favicon_id) {
- if (!thumb_db_.get() || favicon_id == 0)
+ if (!thumb_db_ || favicon_id == 0)
return false;
return thumb_db_->GetFaviconHeader(favicon_id, nullptr, nullptr);
}
@@ -373,9 +372,9 @@ void ExpireHistoryTest::EnsureURLInfoGone(const URLRow& row, bool expired) {
// EXPECT_FALSE(HasThumbnail(row.id()));
bool found_delete_notification = false;
- for (const auto& tuple : urls_deleted_notifications_) {
- EXPECT_EQ(expired, std::get<1>(tuple));
- const history::URLRows& rows(std::get<2>(tuple));
+ for (const auto& info : urls_deleted_notifications_) {
+ EXPECT_EQ(expired, info.is_from_expiration());
+ const history::URLRows& rows(info.deleted_rows());
history::URLRows::const_iterator it_row = std::find_if(
rows.begin(), rows.end(), history::URLRow::URLRowHasURL(row.url()));
if (it_row != rows.end()) {
@@ -622,8 +621,8 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarred) {
// This should delete the last two visits.
std::set<GURL> restrict_urls;
expirer_.ExpireHistoryBetween(restrict_urls, visit_times[2], base::Time());
- EXPECT_EQ(GetLastDeletionTimeRange().begin(), visit_times[2]);
- EXPECT_EQ(GetLastDeletionTimeRange().end(), base::Time());
+ EXPECT_EQ(GetLastDeletionInfo()->time_range().begin(), visit_times[2]);
+ EXPECT_EQ(GetLastDeletionInfo()->time_range().end(), base::Time());
// Verify that the middle URL had its last visit deleted only.
visits.clear();
@@ -813,7 +812,7 @@ TEST_F(ExpireHistoryTest, FlushURLsForTimes) {
times.push_back(visit_times[3]);
times.push_back(visit_times[2]);
expirer_.ExpireHistoryForTimes(times);
- EXPECT_FALSE(GetLastDeletionTimeRange().IsValid());
+ EXPECT_FALSE(GetLastDeletionInfo()->time_range().IsValid());
// Verify that the middle URL had its last visit deleted only.
visits.clear();
@@ -862,9 +861,12 @@ TEST_F(ExpireHistoryTest, FlushRecentURLsUnstarredRestricted) {
ASSERT_EQ(1U, visits.size());
// This should delete the last two visits.
- std::set<GURL> restrict_urls;
- restrict_urls.insert(url_row1.url());
+ std::set<GURL> restrict_urls = {url_row1.url()};
expirer_.ExpireHistoryBetween(restrict_urls, visit_times[2], base::Time());
+ EXPECT_EQ(GetLastDeletionInfo()->time_range().begin(), visit_times[2]);
+ EXPECT_EQ(GetLastDeletionInfo()->time_range().end(), base::Time());
+ EXPECT_EQ(GetLastDeletionInfo()->deleted_rows().size(), 0U);
+ EXPECT_EQ(GetLastDeletionInfo()->restrict_urls()->size(), 1U);
// Verify that the middle URL had its last visit deleted only.
visits.clear();
@@ -957,7 +959,7 @@ TEST_F(ExpireHistoryTest, ExpireHistoryBeforeUnstarred) {
ASSERT_TRUE(main_db_->GetURLRow(url_ids[2], &url_row2));
// Expire the oldest two visits.
- expirer_.ExpireHistoryBefore(visit_times[1]);
+ expirer_.ExpireHistoryBeforeForTesting(visit_times[1]);
// The first URL should be deleted along with its sole visit. The second URL
// itself should not be affected, as there is still one more visit to it, but
@@ -975,7 +977,7 @@ TEST_F(ExpireHistoryTest, ExpireHistoryBeforeUnstarred) {
// Now expire one more visit so that the second URL should be removed. The
// third URL and its visit should be intact.
ClearLastNotifications();
- expirer_.ExpireHistoryBefore(visit_times[2]);
+ expirer_.ExpireHistoryBeforeForTesting(visit_times[2]);
EnsureURLInfoGone(url_row1, true);
EXPECT_TRUE(main_db_->GetURLRow(url_ids[2], &temp_row));
main_db_->GetVisitsForURL(temp_row.id(), &visits);
@@ -998,7 +1000,7 @@ TEST_F(ExpireHistoryTest, ExpireHistoryBeforeStarred) {
// Now expire the first three visits (first two URLs). The first three visits
// should be deleted, but the URL records themselves should not, as they are
// starred.
- expirer_.ExpireHistoryBefore(visit_times[2]);
+ expirer_.ExpireHistoryBeforeForTesting(visit_times[2]);
URLRow temp_row;
ASSERT_TRUE(main_db_->GetURLRow(url_ids[0], &temp_row));
@@ -1031,19 +1033,19 @@ TEST_F(ExpireHistoryTest, ExpireSomeOldHistory) {
// Deleting a time range with no URLs should return false (nothing found).
EXPECT_FALSE(expirer_.ExpireSomeOldHistory(
visit_times[0] - base::TimeDelta::FromDays(100), reader, 1));
- EXPECT_EQ(GetLastDeletionTimeRange().begin(), base::Time());
- EXPECT_EQ(GetLastDeletionTimeRange().end(),
- visit_times[0] - base::TimeDelta::FromDays(100));
+ EXPECT_EQ(nullptr, GetLastDeletionInfo());
// Deleting a time range with not up the the max results should also return
// false (there will only be one visit deleted in this range).
EXPECT_FALSE(expirer_.ExpireSomeOldHistory(visit_times[0], reader, 2));
- EXPECT_EQ(GetLastDeletionTimeRange().begin(), base::Time());
- EXPECT_EQ(GetLastDeletionTimeRange().end(), visit_times[0]);
+ EXPECT_EQ(1U, GetLastDeletionInfo()->deleted_rows().size());
+ EXPECT_FALSE(GetLastDeletionInfo()->time_range().IsValid());
+ ClearLastNotifications();
// Deleting a time range with the max number of results should return true
// (max deleted).
EXPECT_TRUE(expirer_.ExpireSomeOldHistory(visit_times[2], reader, 1));
+ EXPECT_EQ(nullptr, GetLastDeletionInfo());
}
TEST_F(ExpireHistoryTest, ExpiringVisitsReader) {
@@ -1079,9 +1081,6 @@ TEST_F(ExpireHistoryTest, ExpiringVisitsReader) {
// Test that ClearOldOnDemandFaviconsIfPossible() deletes favicons associated
// only to unstarred page URLs.
TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesDeleteUnstarred) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
-
// The blob does not encode any real bitmap, obviously.
const unsigned char kBlob[] = "0";
scoped_refptr<base::RefCountedBytes> favicon(
@@ -1108,9 +1107,6 @@ TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesDeleteUnstarred) {
// Test that ClearOldOnDemandFaviconsIfPossible() deletes favicons associated to
// at least one starred page URL.
TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesNotDeleteStarred) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
-
// The blob does not encode any real bitmap, obviously.
const unsigned char kBlob[] = "0";
scoped_refptr<base::RefCountedBytes> favicon(
@@ -1147,9 +1143,6 @@ TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesNotDeleteStarred) {
// Test that ClearOldOnDemandFaviconsIfPossible() has effect if the last
// clearing was long time age (such as 2 days ago).
TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesDeleteAfterLongDelay) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
-
// Previous clearing (2 days ago).
expirer_.ClearOldOnDemandFaviconsIfPossible(GetOldFaviconThreshold() -
base::TimeDelta::FromDays(2));
@@ -1181,9 +1174,6 @@ TEST_F(ExpireHistoryTest, ClearOldOnDemandFaviconsDoesDeleteAfterLongDelay) {
// at least one starred page URL.
TEST_F(ExpireHistoryTest,
ClearOldOnDemandFaviconsDoesNotDeleteAfterShortDelay) {
- base::test::ScopedFeatureList feature_list;
- feature_list.InitAndEnableFeature(internal::kClearOldOnDemandFavicons);
-
// Previous clearing (5 minutes ago).
expirer_.ClearOldOnDemandFaviconsIfPossible(GetOldFaviconThreshold() -
base::TimeDelta::FromMinutes(5));
diff --git a/chromium/components/history/core/browser/history_backend.cc b/chromium/components/history/core/browser/history_backend.cc
index 851bf1c6818..478d3985a87 100644
--- a/chromium/components/history/core/browser/history_backend.cc
+++ b/chromium/components/history/core/browser/history_backend.cc
@@ -171,6 +171,18 @@ HistoryBackendHelper::~HistoryBackendHelper() {
// HistoryBackend --------------------------------------------------------------
+// static
+bool HistoryBackend::IsTypedIncrement(ui::PageTransition transition) {
+ if (ui::PageTransitionIsNewNavigation(transition) &&
+ ((ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) &&
+ !ui::PageTransitionIsRedirect(transition)) ||
+ ui::PageTransitionCoreTypeIs(transition,
+ ui::PAGE_TRANSITION_KEYWORD_GENERATED))) {
+ return true;
+ }
+ return false;
+}
+
HistoryBackend::HistoryBackend(
Delegate* delegate,
std::unique_ptr<HistoryBackendClient> backend_client,
@@ -413,6 +425,8 @@ OriginCountAndLastVisitMap HistoryBackend::GetCountsAndLastVisitForOrigins(
const std::set<GURL>& origins) const {
if (!db_)
return OriginCountAndLastVisitMap();
+ if (origins.empty())
+ return OriginCountAndLastVisitMap();
URLDatabase::URLEnumerator it;
if (!db_->InitURLEnumeratorForEverything(&it))
@@ -775,15 +789,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
ui::PageTransition transition,
bool hidden,
VisitSource visit_source) {
- // NOTE: This code must stay in sync with
- // ExpireHistoryBackend::ExpireURLsForVisits().
- int typed_increment = 0;
- if (ui::PageTransitionIsNewNavigation(transition) &&
- ((ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED) &&
- !ui::PageTransitionIsRedirect(transition)) ||
- ui::PageTransitionCoreTypeIs(transition,
- ui::PAGE_TRANSITION_KEYWORD_GENERATED)))
- typed_increment = 1;
+ const bool typed_increment = IsTypedIncrement(transition);
if (!host_ranks_.empty() && visit_source == SOURCE_BROWSED &&
(transition & ui::PAGE_TRANSITION_CHAIN_END)) {
@@ -798,7 +804,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
if (!ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD))
url_info.set_visit_count(url_info.visit_count() + 1);
if (typed_increment)
- url_info.set_typed_count(url_info.typed_count() + typed_increment);
+ url_info.set_typed_count(url_info.typed_count() + 1);
if (url_info.last_visit() < time)
url_info.set_last_visit(time);
@@ -810,7 +816,7 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
} else {
// Addition of a new row.
url_info.set_visit_count(1);
- url_info.set_typed_count(typed_increment);
+ url_info.set_typed_count(typed_increment ? 1 : 0);
url_info.set_last_visit(time);
url_info.set_hidden(hidden);
@@ -823,7 +829,8 @@ std::pair<URLID, VisitID> HistoryBackend::AddPageVisit(
}
// Add the visit with the time to the database.
- VisitRow visit_info(url_id, time, referring_visit, transition, 0);
+ VisitRow visit_info(url_id, time, referring_visit, transition, 0,
+ typed_increment);
VisitID visit_id = db_->AddVisit(&visit_info, visit_source);
if (visit_info.visit_time < first_recorded_time_)
@@ -879,7 +886,7 @@ void HistoryBackend::AddPagesWithDetails(const URLRows& urls,
ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
ui::PAGE_TRANSITION_CHAIN_START |
ui::PAGE_TRANSITION_CHAIN_END),
- 0);
+ 0, false);
if (!db_->AddVisit(&visit_info, visit_source)) {
NOTREACHED() << "Adding visit failed.";
return;
@@ -1633,11 +1640,9 @@ void HistoryBackend::MergeFavicon(
favicon_base::FaviconID favicon_id =
thumbnail_db_->GetFaviconIDForFaviconURL(icon_url, icon_type);
- bool favicon_created = false;
if (!favicon_id) {
// There is no favicon at |icon_url|, create it.
favicon_id = thumbnail_db_->AddFavicon(icon_url, icon_type);
- favicon_created = true;
}
std::vector<FaviconBitmapIDSize> bitmap_id_sizes;
@@ -1776,9 +1781,7 @@ void HistoryBackend::MergeFavicon(
SendFaviconChangedNotificationForPageAndRedirects(page_url);
}
- if (!favicon_created && (!bitmap_identical || favicon_bitmaps_copied)) {
- // If there was a favicon at |icon_url| prior to MergeFavicon() being
- // called, there may be page URLs which also use the favicon at |icon_url|.
+ if (!bitmap_identical || favicon_bitmaps_copied) {
// Notify the UI that the favicon has changed for |icon_url|.
SendFaviconChangedNotificationForIconURL(icon_url);
}
@@ -1995,10 +1998,8 @@ bool HistoryBackend::SetFaviconsImpl(const base::flat_set<GURL>& page_urls,
}
}
- if (favicon_data_modified && !favicon_created) {
- // If there was a favicon at |icon_url| prior to SetFavicons() being called,
- // there may be page URLs which also use the favicon at |icon_url|. Notify
- // the UI that the favicon has changed for |icon_url|.
+ if (favicon_data_modified) {
+ // Notify the UI that the favicon has changed for |icon_url|.
SendFaviconChangedNotificationForIconURL(icon_url);
}
ScheduleCommit();
@@ -2526,6 +2527,13 @@ void HistoryBackend::ExpireHistory(
}
}
+void HistoryBackend::ExpireHistoryBeforeForTesting(base::Time end_time) {
+ if (!db_)
+ return;
+
+ expirer_.ExpireHistoryBeforeForTesting(end_time);
+}
+
void HistoryBackend::URLsNoLongerBookmarked(const std::set<GURL>& urls) {
if (!db_)
return;
@@ -2549,15 +2557,13 @@ void HistoryBackend::DatabaseErrorCallback(int error, sql::Statement* stmt) {
db_diagnostics_ = db_->GetDiagnosticInfo(error, stmt);
- // Notify SyncBridge about storage error. It will report failure to sync
- // engine and stop accepting remote updates.
- if (typed_url_sync_bridge_)
- typed_url_sync_bridge_->OnDatabaseError();
-
// Don't just do the close/delete here, as we are being called by |db| and
// that seems dangerous.
- // TODO(shess): Consider changing KillHistoryDatabase() to use
- // RazeAndClose(). Then it can be cleared immediately.
+ // TODO(https://crbug.com/854258): It is also dangerous to kill the database
+ // by a posted task: tasks that run before KillHistoryDatabase still can try
+ // to use the broken database. Consider protecting against other tasks using
+ // the DB or consider changing KillHistoryDatabase() to use RazeAndClose()
+ // (then it can be cleared immediately).
task_runner_->PostTask(
FROM_HERE, base::Bind(&HistoryBackend::KillHistoryDatabase, this));
}
@@ -2568,6 +2574,11 @@ void HistoryBackend::KillHistoryDatabase() {
if (!db_)
return;
+ // Notify SyncBridge about storage error. It will report failure to sync
+ // engine and stop accepting remote updates.
+ if (typed_url_sync_bridge_)
+ typed_url_sync_bridge_->OnDatabaseError();
+
// Rollback transaction because Raze() cannot be called from within a
// transaction.
db_->RollbackTransaction();
@@ -2635,19 +2646,22 @@ void HistoryBackend::NotifyURLsModified(const URLRows& rows) {
delegate_->NotifyURLsModified(rows);
}
-void HistoryBackend::NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& rows,
- const std::set<GURL>& favicon_urls) {
- URLRows copied_rows(rows);
+void HistoryBackend::NotifyURLsDeleted(DeletionInfo deletion_info) {
+ std::set<GURL> origins;
+ for (const history::URLRow& row : deletion_info.deleted_rows())
+ origins.insert(row.url().GetOrigin());
+
+ deletion_info.set_deleted_urls_origin_map(
+ GetCountsAndLastVisitForOrigins(origins));
+
for (HistoryBackendObserver& observer : observers_) {
- observer.OnURLsDeleted(this, time_range.IsAllTime(), expired, copied_rows,
- favicon_urls);
+ observer.OnURLsDeleted(
+ this, deletion_info.IsAllHistory(), deletion_info.is_from_expiration(),
+ deletion_info.deleted_rows(), deletion_info.favicon_urls());
}
if (delegate_)
- delegate_->NotifyURLsDeleted(time_range, expired, copied_rows,
- favicon_urls);
+ delegate_->NotifyURLsDeleted(std::move(deletion_info));
}
// Deleting --------------------------------------------------------------------
@@ -2704,8 +2718,7 @@ void HistoryBackend::DeleteAllHistory() {
// Send out the notification that history is cleared. The in-memory database
// will pick this up and clear itself.
- NotifyURLsDeleted(DeletionTimeRange::AllTime(), false, URLRows(),
- std::set<GURL>());
+ NotifyURLsDeleted(DeletionInfo::ForAllHistory());
}
bool HistoryBackend::ClearAllThumbnailHistory(
diff --git a/chromium/components/history/core/browser/history_backend.h b/chromium/components/history/core/browser/history_backend.h
index fa77efd2dfe..be693853337 100644
--- a/chromium/components/history/core/browser/history_backend.h
+++ b/chromium/components/history/core/browser/history_backend.h
@@ -143,10 +143,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// Notify HistoryService that some or all of the URLs have been deleted.
// The event will be forwarded to the HistoryServiceObservers in the correct
// thread.
- virtual void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) = 0;
+ virtual void NotifyURLsDeleted(DeletionInfo deletion_info) = 0;
// Notify HistoryService that some keyword has been searched using omnibox.
// The event will be forwarded to the HistoryServiceObservers in the correct
@@ -164,6 +161,9 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
virtual void DBLoaded() = 0;
};
+ // Check if the transition should increment the typed_count of a visit.
+ static bool IsTypedIncrement(ui::PageTransition transition);
+
// Init must be called to complete object creation. This object can be
// constructed on any thread, but all other functions including Init() must
// be called on the history thread.
@@ -439,6 +439,10 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
// of ExpireHistoryBetween().
void ExpireHistory(const std::vector<ExpireHistoryArgs>& expire_list);
+ // Expires all visits before and including the given time, updating the URLs
+ // accordingly.
+ void ExpireHistoryBeforeForTesting(base::Time end_time);
+
// Bookmarks -----------------------------------------------------------------
// Notification that a URL is no longer bookmarked. If there are no visits
@@ -818,10 +822,7 @@ class HistoryBackend : public base::RefCountedThreadSafe<HistoryBackend>,
const RedirectList& redirects,
base::Time visit_time) override;
void NotifyURLsModified(const URLRows& rows) override;
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& rows,
- const std::set<GURL>& favicon_urls) override;
+ void NotifyURLsDeleted(DeletionInfo deletion_info) override;
void RecordTopHostsMetrics(const GURL& url);
diff --git a/chromium/components/history/core/browser/history_backend_db_unittest.cc b/chromium/components/history/core/browser/history_backend_db_unittest.cc
index 077da13c3dd..9f3ac0fad31 100644
--- a/chromium/components/history/core/browser/history_backend_db_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_db_unittest.cc
@@ -1583,6 +1583,121 @@ TEST_F(HistoryBackendDBTest, MigrateDownloadSliceFinished) {
}
}
+// Test to verify the incremented_omnibox_typed_score column will be correctly
+// added to visits table during migration to version 40.
+TEST_F(HistoryBackendDBTest, MigrateVisitsWithoutIncrementedOmniboxTypedScore) {
+ ASSERT_NO_FATAL_FAILURE(CreateDBVersion(39));
+
+ const VisitID visit_id1 = 1;
+ const VisitID visit_id2 = 2;
+ const URLID url_id1 = 3;
+ const URLID url_id2 = 4;
+ const base::Time visit_time1(base::Time::Now());
+ const base::Time visit_time2(base::Time::Now());
+ const VisitID referring_visit1 = 0;
+ const VisitID referring_visit2 = 0;
+ const ui::PageTransition transition1 = ui::PAGE_TRANSITION_LINK;
+ const ui::PageTransition transition2 = ui::PAGE_TRANSITION_TYPED;
+ const SegmentID segment_id1 = 7;
+ const SegmentID segment_id2 = 8;
+ const base::TimeDelta visit_duration1(base::TimeDelta::FromSeconds(30));
+ const base::TimeDelta visit_duration2(base::TimeDelta::FromSeconds(45));
+
+ const char kInsertStatement[] =
+ "INSERT INTO visits "
+ "(id, url, visit_time, from_visit, transition, segment_id, "
+ "visit_duration) VALUES (?, ?, ?, ?, ?, ?, ?)";
+
+ {
+ // Open the db for manual manipulation.
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+
+ // Add entries to visits.
+ {
+ sql::Statement s(db.GetUniqueStatement(kInsertStatement));
+ s.BindInt64(0, visit_id1);
+ s.BindInt64(1, url_id1);
+ s.BindInt64(2, visit_time1.ToDeltaSinceWindowsEpoch().InMicroseconds());
+ s.BindInt64(3, referring_visit1);
+ s.BindInt64(4, transition1);
+ s.BindInt64(5, segment_id1);
+ s.BindInt64(6, visit_duration1.InMicroseconds());
+ ASSERT_TRUE(s.Run());
+ }
+ {
+ sql::Statement s(db.GetUniqueStatement(kInsertStatement));
+ s.BindInt64(0, visit_id2);
+ s.BindInt64(1, url_id2);
+ s.BindInt64(2, visit_time2.ToDeltaSinceWindowsEpoch().InMicroseconds());
+ s.BindInt64(3, referring_visit2);
+ s.BindInt64(4, transition2);
+ s.BindInt64(5, segment_id2);
+ s.BindInt64(6, visit_duration2.InMicroseconds());
+ ASSERT_TRUE(s.Run());
+ }
+ }
+
+ // Re-open the db, triggering migration.
+ CreateBackendAndDatabase();
+
+ VisitRow visit_row1;
+ db_->GetRowForVisit(visit_id1, &visit_row1);
+ EXPECT_FALSE(visit_row1.incremented_omnibox_typed_score);
+
+ VisitRow visit_row2;
+ db_->GetRowForVisit(visit_id2, &visit_row2);
+ EXPECT_TRUE(visit_row2.incremented_omnibox_typed_score);
+}
+
+// Tests that the migration code correctly handles rows in the visit database
+// that may be in an invalid state where visit_id == referring_visit. Regression
+// test for https://crbug.com/847246.
+TEST_F(HistoryBackendDBTest,
+ MigrateVisitsWithoutIncrementedOmniboxTypedScore_BadRow) {
+ ASSERT_NO_FATAL_FAILURE(CreateDBVersion(39));
+
+ const VisitID visit_id = 1;
+ const URLID url_id = 2;
+ const base::Time visit_time(base::Time::Now());
+ // visit_id == referring_visit will trigger DCHECK_NE in UpdateVisitRow.
+ const VisitID referring_visit = 1;
+ const ui::PageTransition transition = ui::PAGE_TRANSITION_TYPED;
+ const SegmentID segment_id = 8;
+ const base::TimeDelta visit_duration(base::TimeDelta::FromSeconds(45));
+
+ const char kInsertStatement[] =
+ "INSERT INTO visits "
+ "(id, url, visit_time, from_visit, transition, segment_id, "
+ "visit_duration) VALUES (?, ?, ?, ?, ?, ?, ?)";
+
+ {
+ // Open the db for manual manipulation.
+ sql::Connection db;
+ ASSERT_TRUE(db.Open(history_dir_.Append(kHistoryFilename)));
+
+ // Add entry to visits.
+ sql::Statement s(db.GetUniqueStatement(kInsertStatement));
+ s.BindInt64(0, visit_id);
+ s.BindInt64(1, url_id);
+ s.BindInt64(2, visit_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+ s.BindInt64(3, referring_visit);
+ s.BindInt64(4, transition);
+ s.BindInt64(5, segment_id);
+ s.BindInt64(6, visit_duration.InMicroseconds());
+ ASSERT_TRUE(s.Run());
+ }
+
+ // Re-open the db, triggering migration.
+ CreateBackendAndDatabase();
+
+ // Field should be false since the migration won't update it from the default
+ // due to the invalid state of the row.
+ VisitRow visit_row;
+ db_->GetRowForVisit(visit_id, &visit_row);
+ EXPECT_FALSE(visit_row.incremented_omnibox_typed_score);
+}
+
bool FilterURL(const GURL& url) {
return url.SchemeIsHTTPOrHTTPS();
}
diff --git a/chromium/components/history/core/browser/history_backend_notifier.h b/chromium/components/history/core/browser/history_backend_notifier.h
index 668185016ec..9ede9c0b49e 100644
--- a/chromium/components/history/core/browser/history_backend_notifier.h
+++ b/chromium/components/history/core/browser/history_backend_notifier.h
@@ -40,17 +40,9 @@ class HistoryBackendNotifier {
virtual void NotifyURLsModified(const URLRows& changed_urls) = 0;
// Sends notification that some or the totality of the URLs have been
- // deleted. If time_range.IsValid() is true, all URLs between
- // time_range.begin() and time_range.end() have been removed.
- // If time_range.IsAllTime() is true, then all the URLs in the
- // history have been deleted, otherwise |deleted_urls| list the deleted URLs.
- // If the URL deletion is due to expiration, then |expired| is true.
- // |favicon_urls| is the list of favicon URLs that correspond to the deleted
- // URLs (empty if |time_range.IsAllTime()| is true).
- virtual void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_urls,
- const std::set<GURL>& favicon_urls) = 0;
+ // deleted.
+ // |deletion_info| describes the urls that have been removed from history.
+ virtual void NotifyURLsDeleted(DeletionInfo deletion_info) = 0;
};
} // namespace history
diff --git a/chromium/components/history/core/browser/history_backend_unittest.cc b/chromium/components/history/core/browser/history_backend_unittest.cc
index e1eb945adff..93859a28f9b 100644
--- a/chromium/components/history/core/browser/history_backend_unittest.cc
+++ b/chromium/components/history/core/browser/history_backend_unittest.cc
@@ -137,10 +137,7 @@ class HistoryBackendTestDelegate : public HistoryBackend::Delegate {
const RedirectList& redirects,
base::Time visit_time) override;
void NotifyURLsModified(const URLRows& changed_urls) override;
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ void NotifyURLsDeleted(DeletionInfo deletion_info) override;
void NotifyKeywordSearchTermUpdated(const URLRow& row,
KeywordID keyword_id,
const base::string16& term) override;
@@ -228,14 +225,10 @@ class HistoryBackendTestBase : public testing::Test {
urls_modified_notifications_.push_back(changed_urls);
}
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
- mem_backend_->OnURLsDeleted(nullptr, time_range.IsAllTime(), expired,
- deleted_rows, favicon_urls);
- urls_deleted_notifications_.push_back(
- std::make_pair(time_range.IsAllTime(), expired));
+ void NotifyURLsDeleted(DeletionInfo deletion_info) {
+ mem_backend_->OnURLsDeleted(nullptr, deletion_info);
+ urls_deleted_notifications_.push_back(std::make_pair(
+ deletion_info.IsAllHistory(), deletion_info.is_from_expiration()));
}
void NotifyKeywordSearchTermUpdated(const URLRow& row,
@@ -268,7 +261,7 @@ class HistoryBackendTestBase : public testing::Test {
}
void TearDown() override {
- if (backend_.get())
+ if (backend_)
backend_->Closing();
backend_ = nullptr;
mem_backend_.reset();
@@ -317,12 +310,8 @@ void HistoryBackendTestDelegate::NotifyURLsModified(
test_->NotifyURLsModified(changed_urls);
}
-void HistoryBackendTestDelegate::NotifyURLsDeleted(
- const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
- test_->NotifyURLsDeleted(time_range, expired, deleted_rows, favicon_urls);
+void HistoryBackendTestDelegate::NotifyURLsDeleted(DeletionInfo deletion_info) {
+ test_->NotifyURLsDeleted(std::move(deletion_info));
}
void HistoryBackendTestDelegate::NotifyKeywordSearchTermUpdated(
@@ -502,8 +491,7 @@ class InMemoryHistoryBackendTest : public HistoryBackendTestBase {
if (row2) rows.push_back(*row2);
if (row3) rows.push_back(*row3);
- NotifyURLsDeleted(DeletionTimeRange::Invalid(), false, rows,
- std::set<GURL>());
+ NotifyURLsDeleted(DeletionInfo::ForUrls(rows, std::set<GURL>()));
}
size_t GetNumberOfMatchingSearchTerms(const int keyword_id,
@@ -2539,7 +2527,7 @@ TEST_F(HistoryBackendTest, FaviconChangedNotificationNewFavicon) {
backend_->SetFavicons({page_url1}, IconType::kFavicon, icon_url1, bitmaps);
ASSERT_EQ(1u, favicon_changed_notifications_page_urls().size());
EXPECT_EQ(page_url1, favicon_changed_notifications_page_urls()[0]);
- EXPECT_EQ(0u, favicon_changed_notifications_icon_urls().size());
+ EXPECT_EQ(1u, favicon_changed_notifications_icon_urls().size());
ClearBroadcastedNotifications();
}
@@ -2553,7 +2541,7 @@ TEST_F(HistoryBackendTest, FaviconChangedNotificationNewFavicon) {
bitmap_data, kSmallSize);
ASSERT_EQ(1u, favicon_changed_notifications_page_urls().size());
EXPECT_EQ(page_url2, favicon_changed_notifications_page_urls()[0]);
- EXPECT_EQ(0u, favicon_changed_notifications_icon_urls().size());
+ EXPECT_EQ(1u, favicon_changed_notifications_icon_urls().size());
}
}
@@ -3870,6 +3858,28 @@ TEST_F(HistoryBackendTest, DatabaseError) {
base::RunLoop().RunUntilIdle();
}
+// Tests that calling DatabaseErrorCallback results in killing the database and
+// notifying the TypedURLSyncBridge at the same time so that no further
+// notification from the backend can lead to the bridge. (Regression test for
+// https://crbug.com/853395)
+TEST_F(HistoryBackendTest, DatabaseErrorSynchronouslyKillAndNotifyBridge) {
+ // Notify the backend that a database error occurred.
+ backend_->DatabaseErrorCallback(SQLITE_CORRUPT, nullptr);
+ // In-between (before the posted task finishes), we can again delete all
+ // history.
+ backend_->ExpireHistoryBetween(/*restrict_urls=*/std::set<GURL>(),
+ /*begin_time=*/base::Time(),
+ /*end_time=*/base::Time::Max());
+
+ // Run loop to let the posted task to kill the DB run.
+ base::RunLoop().RunUntilIdle();
+ // After DB is destroyed, we can again try to delete all history (with no
+ // effect but it should not crash).
+ backend_->ExpireHistoryBetween(/*restrict_urls=*/std::set<GURL>(),
+ /*begin_time=*/base::Time(),
+ /*end_time=*/base::Time::Max());
+}
+
// Common implementation for the two tests below, given that the only difference
// between them is the type of the notification sent out.
void InMemoryHistoryBackendTest::TestAddingAndChangingURLRows(
@@ -3955,8 +3965,7 @@ TEST_F(InMemoryHistoryBackendTest, OnURLsDeletedEnMasse) {
SimulateNotificationURLsModified(mem_backend_.get(), &row1, &row2, &row3);
// Now notify the in-memory database that all history has been deleted.
- mem_backend_->OnURLsDeleted(nullptr, true, false, URLRows(),
- std::set<GURL>());
+ mem_backend_->OnURLsDeleted(nullptr, history::DeletionInfo::ForAllHistory());
// Expect that everything goes away.
EXPECT_EQ(0, mem_backend_->db()->GetRowForURL(row1.url(), nullptr));
diff --git a/chromium/components/history/core/browser/history_constants.cc b/chromium/components/history/core/browser/history_constants.cc
index 79cd33fa6e0..d657062d4d8 100644
--- a/chromium/components/history/core/browser/history_constants.cc
+++ b/chromium/components/history/core/browser/history_constants.cc
@@ -18,6 +18,8 @@ const base::FilePath::CharType kTopSitesFilename[] =
const int kMaxTopHosts = 50;
+const int kMaxTitleChanges = 10;
+
base::TimeDelta GetTitleSettingWindow() {
const auto value = base::TimeDelta::FromSeconds(5);
return value;
diff --git a/chromium/components/history/core/browser/history_constants.h b/chromium/components/history/core/browser/history_constants.h
index b89804c49c3..1f3d88896da 100644
--- a/chromium/components/history/core/browser/history_constants.h
+++ b/chromium/components/history/core/browser/history_constants.h
@@ -18,6 +18,11 @@ extern const base::FilePath::CharType kTopSitesFilename[];
// The maximum size of the list returned by history::HistoryService::TopHosts().
extern const int kMaxTopHosts;
+// The maximum number of times a page can change it's title during the relevant
+// timestamp (page is either loading is has recently loaded as per
+// GetTitleSettingWindow() below).
+extern const int kMaxTitleChanges;
+
// The span of time after load is complete during which a page may set its title
// and have the title change be saved in history.
base::TimeDelta GetTitleSettingWindow();
diff --git a/chromium/components/history/core/browser/history_database.cc b/chromium/components/history/core/browser/history_database.cc
index 2a983559f11..d80bc2395a4 100644
--- a/chromium/components/history/core/browser/history_database.cc
+++ b/chromium/components/history/core/browser/history_database.cc
@@ -38,7 +38,7 @@ namespace {
// Current version number. We write databases at the "current" version number,
// but any previous version that can read the "compatible" one can make do with
// our database without *too* many bad effects.
-const int kCurrentVersionNumber = 39;
+const int kCurrentVersionNumber = 40;
const int kCompatibleVersionNumber = 16;
const char kEarlyExpirationThresholdKey[] = "early_expiration_threshold";
const int kMaxHostsInMemory = 10000;
@@ -600,6 +600,13 @@ sql::InitStatus HistoryDatabase::EnsureCurrentVersion() {
meta_table_.SetVersionNumber(cur_version);
}
+ if (cur_version == 39) {
+ if (!MigrateVisitsWithoutIncrementedOmniboxTypedScore())
+ return LogMigrationFailure(39);
+ cur_version++;
+ meta_table_.SetVersionNumber(cur_version);
+ }
+
// ========================= ^^ new migration code goes here ^^
// ADDING NEW MIGRATION CODE
// =========================
diff --git a/chromium/components/history/core/browser/history_database_params.cc b/chromium/components/history/core/browser/history_database_params.cc
index 3f02563a42a..ccc6983de91 100644
--- a/chromium/components/history/core/browser/history_database_params.cc
+++ b/chromium/components/history/core/browser/history_database_params.cc
@@ -7,10 +7,7 @@
namespace history {
HistoryDatabaseParams::HistoryDatabaseParams()
- : history_dir(),
- download_interrupt_reason_none(0),
- download_interrupt_reason_crash(0) {
-}
+ : download_interrupt_reason_none(0), download_interrupt_reason_crash(0) {}
HistoryDatabaseParams::HistoryDatabaseParams(
const base::FilePath& history_dir,
diff --git a/chromium/components/history/core/browser/history_model_worker.cc b/chromium/components/history/core/browser/history_model_worker.cc
index ed8a970f4b5..c68b377ea50 100644
--- a/chromium/components/history/core/browser/history_model_worker.cc
+++ b/chromium/components/history/core/browser/history_model_worker.cc
@@ -42,7 +42,7 @@ void PostWorkerTask(
const base::WeakPtr<history::HistoryService>& history_service,
base::OnceClosure work,
base::CancelableTaskTracker* cancelable_tracker) {
- if (history_service.get()) {
+ if (history_service) {
history_service->ScheduleDBTask(
FROM_HERE, std::make_unique<WorkerTask>(std::move(work)),
cancelable_tracker);
@@ -62,7 +62,7 @@ HistoryModelWorker::HistoryModelWorker(
// constructed and deleted on the same sequence.
cancelable_tracker_(new base::CancelableTaskTracker,
base::OnTaskRunnerDeleter(ui_thread_)) {
- CHECK(history_service.get());
+ CHECK(history_service);
DCHECK(ui_thread_->BelongsToCurrentThread());
}
diff --git a/chromium/components/history/core/browser/history_querying_unittest.cc b/chromium/components/history/core/browser/history_querying_unittest.cc
index fede4e3f9e6..04f821b90e4 100644
--- a/chromium/components/history/core/browser/history_querying_unittest.cc
+++ b/chromium/components/history/core/browser/history_querying_unittest.cc
@@ -183,7 +183,7 @@ class HistoryQueryTest : public testing::Test {
void TearDown() override {
if (history_) {
history_->SetOnBackendDestroyTask(
- base::MessageLoop::QuitWhenIdleClosure());
+ base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
history_->Cleanup();
history_.reset();
base::RunLoop().Run(); // Wait for the other thread.
diff --git a/chromium/components/history/core/browser/history_service.cc b/chromium/components/history/core/browser/history_service.cc
index d10919a3946..2f4975b203b 100644
--- a/chromium/components/history/core/browser/history_service.cc
+++ b/chromium/components/history/core/browser/history_service.cc
@@ -152,14 +152,10 @@ class HistoryService::BackendDelegate : public HistoryBackend::Delegate {
history_service_, changed_urls));
}
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override {
+ void NotifyURLsDeleted(DeletionInfo deletion_info) override {
service_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&HistoryService::NotifyURLsDeleted, history_service_,
- time_range, expired, deleted_rows, favicon_urls));
+ FROM_HERE, base::BindOnce(&HistoryService::NotifyURLsDeleted,
+ history_service_, std::move(deletion_info)));
}
void NotifyKeywordSearchTermUpdated(const URLRow& row,
@@ -344,7 +340,7 @@ void HistoryService::TopHosts(size_t num_hosts,
callback);
}
-void HistoryService::GetCountsAndLastVisitForOrigins(
+void HistoryService::GetCountsAndLastVisitForOriginsForTesting(
const std::set<GURL>& origins,
const GetCountsAndLastVisitForOriginsCallback& callback) const {
DCHECK(backend_task_runner_) << "History service being called after cleanup";
@@ -903,7 +899,7 @@ void HistoryService::Cleanup() {
history_client_->Shutdown();
// Unload the backend.
- if (history_backend_.get()) {
+ if (history_backend_) {
// Get rid of the in-memory backend.
in_memory_backend_.reset();
@@ -1109,6 +1105,19 @@ void HistoryService::ExpireHistory(
callback);
}
+void HistoryService::ExpireHistoryBeforeForTesting(
+ base::Time end_time,
+ base::OnceClosure callback,
+ base::CancelableTaskTracker* tracker) {
+ DCHECK(backend_task_runner_) << "History service being called after cleanup";
+ DCHECK(thread_checker_.CalledOnValidThread());
+ tracker->PostTaskAndReply(
+ backend_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&HistoryBackend::ExpireHistoryBeforeForTesting,
+ history_backend_, end_time),
+ std::move(callback));
+}
+
void HistoryService::ExpireLocalAndRemoteHistoryBetween(
WebHistoryService* web_history,
const std::set<GURL>& restrict_urls,
@@ -1182,12 +1191,8 @@ void HistoryService::NotifyURLsModified(const URLRows& changed_urls) {
observer.OnURLsModified(this, changed_urls);
}
-void HistoryService::NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
+void HistoryService::NotifyURLsDeleted(const DeletionInfo& deletion_info) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(!time_range.IsAllTime() || deleted_rows.empty());
if (!backend_task_runner_)
return;
@@ -1200,23 +1205,19 @@ void HistoryService::NotifyURLsDeleted(const DeletionTimeRange& time_range,
// respectful of privacy and never tell the user something is gone when it
// isn't. Therefore, we update the delete URLs after the fact.
if (visit_delegate_) {
- if (time_range.IsAllTime()) {
+ if (deletion_info.IsAllHistory()) {
visit_delegate_->DeleteAllURLs();
} else {
std::vector<GURL> urls;
- urls.reserve(deleted_rows.size());
- for (const auto& row : deleted_rows)
+ urls.reserve(deletion_info.deleted_rows().size());
+ for (const auto& row : deletion_info.deleted_rows())
urls.push_back(row.url());
visit_delegate_->DeleteURLs(urls);
}
}
- for (HistoryServiceObserver& observer : observers_) {
- observer.OnURLsDeleted(this, time_range.IsAllTime(), expired, deleted_rows,
- favicon_urls);
- observer.OnURLsDeleted(this, time_range, expired, deleted_rows,
- favicon_urls);
- }
+ for (HistoryServiceObserver& observer : observers_)
+ observer.OnURLsDeleted(this, deletion_info);
}
void HistoryService::NotifyHistoryServiceLoaded() {
diff --git a/chromium/components/history/core/browser/history_service.h b/chromium/components/history/core/browser/history_service.h
index d0e1a2805fb..6c4aeb6904e 100644
--- a/chromium/components/history/core/browser/history_service.h
+++ b/chromium/components/history/core/browser/history_service.h
@@ -161,7 +161,7 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
// Gets the counts and most recent visit date of URLs that belong to |origins|
// in the history database.
- void GetCountsAndLastVisitForOrigins(
+ void GetCountsAndLastVisitForOriginsForTesting(
const std::set<GURL>& origins,
const GetCountsAndLastVisitForOriginsCallback& callback) const;
@@ -371,6 +371,12 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
const base::Closure& callback,
base::CancelableTaskTracker* tracker);
+ // Expires all visits before and including the given time, updating the URLs
+ // accordingly.
+ void ExpireHistoryBeforeForTesting(base::Time end_time,
+ base::OnceClosure callback,
+ base::CancelableTaskTracker* tracker);
+
// Removes all visits to the given URLs in the specified time range. Calls
// ExpireHistoryBetween() to delete local visits, and handles deletion of
// synced visits if appropriate.
@@ -605,16 +611,8 @@ class HistoryService : public syncer::SyncableService, public KeyedService {
void NotifyURLsModified(const URLRows& changed_urls);
// Notify all HistoryServiceObservers registered that URLs have been deleted.
- // |all_history| is set to true, if all the URLs are deleted.
- // When set to true, |deleted_rows| and |favicon_urls| are
- // undefined.
- // |expired| is set to true, if the URL deletion is due to expiration.
- // |deleted_rows| list of the deleted URLs.
- // |favicon_urls| list of favicon URLs that correspond to the deleted URLs.
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls);
+ // |deletion_info| describes the urls that have been removed from history.
+ void NotifyURLsDeleted(const DeletionInfo& deletion_info);
// Notify all HistoryServiceObservers registered that the
// HistoryService has finished loading.
diff --git a/chromium/components/history/core/browser/history_service_observer.h b/chromium/components/history/core/browser/history_service_observer.h
index 3220ce56e47..e0809335a49 100644
--- a/chromium/components/history/core/browser/history_service_observer.h
+++ b/chromium/components/history/core/browser/history_service_observer.h
@@ -39,36 +39,11 @@ class HistoryServiceObserver {
virtual void OnURLsModified(HistoryService* history_service,
const URLRows& changed_urls) {}
- // Called when one or more of URLs are deleted.
+ // Called when one or more URLs are deleted.
//
- // |all_history| is set to true, if all the URLs are deleted.
- // When set to true, |deleted_rows| and |favicon_urls| are
- // undefined.
- // |expired| is set to true, if the URL deletion is due to expiration.
- // |deleted_rows| list of the deleted URLs.
- // |favicon_urls| list of favicon URLs that correspond to the deleted URLs.
- // DEPRECATED, use OnURLsDeleted() with |time_range| parameter.
- // TODO(dullweber): Migrate observers to new OnURLsDeleted() method.
+ // |deletion_info| describes the urls that have been removed from history.
virtual void OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {}
-
- // Called when one or more of URLs are deleted.
- //
- // |time_range| If time_range.IsValid() is true, all URLs between
- // time_range.begin() and time_range.end() have been removed.
- // If time_range.IsAllTime() is true, all URLs are deleted and
- // |deleted_rows| and |favicon_urls| are undefined.
- // |expired| is set to true, if the URL deletion is due to expiration.
- // |deleted_rows| list of the deleted URLs.
- // |favicon_urls| list of favicon URLs that correspond to the deleted URLs.
- virtual void OnURLsDeleted(HistoryService* history_service,
- const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {}
+ const DeletionInfo& deletion_info) {}
// Is called to notify when |history_service| has finished loading.
virtual void OnHistoryServiceLoaded(HistoryService* history_service) {}
diff --git a/chromium/components/history/core/browser/history_service_unittest.cc b/chromium/components/history/core/browser/history_service_unittest.cc
index 4ed089e1f4a..eb65c9ab1c3 100644
--- a/chromium/components/history/core/browser/history_service_unittest.cc
+++ b/chromium/components/history/core/browser/history_service_unittest.cc
@@ -25,7 +25,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/utf_string_conversions.h"
@@ -85,7 +84,7 @@ class HistoryServiceTest : public testing::Test {
// Make sure we don't have any event pending that could disrupt the next
// test.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
base::RunLoop().Run();
}
@@ -94,7 +93,7 @@ class HistoryServiceTest : public testing::Test {
history_service_->ClearCachedDataForContextID(nullptr);
history_service_->SetOnBackendDestroyTask(
- base::MessageLoop::QuitWhenIdleClosure());
+ base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
history_service_->Cleanup();
history_service_.reset();
diff --git a/chromium/components/history/core/browser/history_types.cc b/chromium/components/history/core/browser/history_types.cc
index ffbbff03376..67263b5344c 100644
--- a/chromium/components/history/core/browser/history_types.cc
+++ b/chromium/components/history/core/browser/history_types.cc
@@ -20,12 +20,14 @@ VisitRow::VisitRow(URLID arg_url_id,
base::Time arg_visit_time,
VisitID arg_referring_visit,
ui::PageTransition arg_transition,
- SegmentID arg_segment_id)
+ SegmentID arg_segment_id,
+ bool arg_incremented_omnibox_typed_score)
: url_id(arg_url_id),
visit_time(arg_visit_time),
referring_visit(arg_referring_visit),
transition(arg_transition),
- segment_id(arg_segment_id) {}
+ segment_id(arg_segment_id),
+ incremented_omnibox_typed_score(arg_incremented_omnibox_typed_score) {}
VisitRow::~VisitRow() {
}
@@ -369,4 +371,44 @@ bool DeletionTimeRange::IsAllTime() const {
return begin_.is_null() && (end_.is_null() || end_.is_max());
}
+// DeletionInfo
+// ----------------------------------------------------------
+
+// static
+DeletionInfo DeletionInfo::ForAllHistory() {
+ return DeletionInfo(DeletionTimeRange::AllTime(), false, {}, {},
+ base::nullopt);
+}
+
+// static
+DeletionInfo DeletionInfo::ForUrls(URLRows deleted_rows,
+ std::set<GURL> favicon_urls) {
+ return DeletionInfo(DeletionTimeRange::Invalid(), false,
+ std::move(deleted_rows), std::move(favicon_urls),
+ base::nullopt);
+}
+
+DeletionInfo::DeletionInfo(const DeletionTimeRange& time_range,
+ bool is_from_expiration,
+ URLRows deleted_rows,
+ std::set<GURL> favicon_urls,
+ base::Optional<std::set<GURL>> restrict_urls)
+ : time_range_(time_range),
+ is_from_expiration_(is_from_expiration),
+ deleted_rows_(std::move(deleted_rows)),
+ favicon_urls_(std::move(favicon_urls)),
+ restrict_urls_(std::move(restrict_urls)) {
+ // If time_range is all time or invalid, restrict_urls should be empty.
+ DCHECK(!time_range_.IsAllTime() || !restrict_urls_.has_value());
+ DCHECK(time_range_.IsValid() || !restrict_urls_.has_value());
+ // If restrict_urls_ is defined, it should be non-empty.
+ DCHECK(!restrict_urls_.has_value() || !restrict_urls_->empty());
+};
+
+DeletionInfo::~DeletionInfo() = default;
+
+DeletionInfo::DeletionInfo(DeletionInfo&& other) noexcept = default;
+
+DeletionInfo& DeletionInfo::operator=(DeletionInfo&& rhs) noexcept = default;
+
} // namespace history
diff --git a/chromium/components/history/core/browser/history_types.h b/chromium/components/history/core/browser/history_types.h
index ff27b0d7406..5e72a015705 100644
--- a/chromium/components/history/core/browser/history_types.h
+++ b/chromium/components/history/core/browser/history_types.h
@@ -17,6 +17,7 @@
#include "base/containers/stack_container.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
#include "base/time/time.h"
#include "components/favicon_base/favicon_types.h"
@@ -72,7 +73,8 @@ class VisitRow {
base::Time arg_visit_time,
VisitID arg_referring_visit,
ui::PageTransition arg_transition,
- SegmentID arg_segment_id);
+ SegmentID arg_segment_id,
+ bool arg_incremented_omnibox_typed_score);
~VisitRow();
// ID of this row (visit ID, used a a referrer for other visits).
@@ -100,6 +102,9 @@ class VisitRow {
// the visit was present.
base::TimeDelta visit_duration;
+ // Records whether the visit incremented the omnibox typed score.
+ bool incremented_omnibox_typed_score = false;
+
// Compares two visits based on dates, for sorting.
bool operator<(const VisitRow& other) const {
return visit_time < other.visit_time;
@@ -622,6 +627,97 @@ class DeletionTimeRange {
base::Time end_;
};
+// Describes the urls that have been removed due to a history deletion.
+// If |IsAllHistory()| returns true, all urls haven been deleted.
+// In this case, |deleted_rows()| and |favicon_urls()| are undefined.
+// Otherwise |deleted_rows()| contains the urls where all visits have been
+// removed from history.
+// If |expired()| returns true, this deletion is due to a regularly performed
+// history expiration. Otherwise it is an explicit deletion due to a user
+// action.
+class DeletionInfo {
+ public:
+ // Returns a DeletionInfo that covers all history.
+ static DeletionInfo ForAllHistory();
+ // Returns a DeletionInfo with invalid time range for the given urls.
+ static DeletionInfo ForUrls(URLRows deleted_rows,
+ std::set<GURL> favicon_urls);
+
+ DeletionInfo(const DeletionTimeRange& time_range,
+ bool is_from_expiration,
+ URLRows deleted_rows,
+ std::set<GURL> favicon_urls,
+ base::Optional<std::set<GURL>> restrict_urls);
+
+ ~DeletionInfo();
+ // Move-only because of potentially large containers.
+ DeletionInfo(DeletionInfo&& other) noexcept;
+ DeletionInfo& operator=(DeletionInfo&& rhs) noexcept;
+
+ // If IsAllHistory() returns true, all URLs are deleted and |deleted_rows()|
+ // and |favicon_urls()| are undefined.
+ bool IsAllHistory() const { return time_range_.IsAllTime(); }
+
+ // If time_range.IsValid() is true, |restrict_urls| (or all URLs if empty)
+ // between time_range.begin() and time_range.end() have been removed.
+ const DeletionTimeRange& time_range() const { return time_range_; }
+
+ // Restricts deletions within |time_range()|.
+ const base::Optional<std::set<GURL>>& restrict_urls() const {
+ return restrict_urls_;
+ }
+
+ // Returns true, if the URL deletion is due to expiration.
+ bool is_from_expiration() const { return is_from_expiration_; }
+
+ // Returns the list of the deleted URLs.
+ // Undefined if |IsAllHistory()| returns true.
+ const URLRows& deleted_rows() const { return deleted_rows_; }
+
+ // Returns the list of favicon URLs that correspond to the deleted URLs.
+ // Undefined if |IsAllHistory()| returns true.
+ const std::set<GURL>& favicon_urls() const { return favicon_urls_; }
+
+ // Returns a map from origins with deleted urls to a count of remaining URLs
+ // and the last visited time.
+ const OriginCountAndLastVisitMap& deleted_urls_origin_map() const {
+ // The map should only be accessed after it has been populated.
+ DCHECK(deleted_rows_.empty() || !deleted_urls_origin_map_.empty());
+ return deleted_urls_origin_map_;
+ }
+
+ // Populates deleted_urls_origin_map.
+ void set_deleted_urls_origin_map(OriginCountAndLastVisitMap origin_map) {
+ DCHECK(deleted_urls_origin_map_.empty());
+ deleted_urls_origin_map_ = std::move(origin_map);
+ }
+
+ private:
+ DeletionTimeRange time_range_;
+ bool is_from_expiration_;
+ URLRows deleted_rows_;
+ std::set<GURL> favicon_urls_;
+ base::Optional<std::set<GURL>> restrict_urls_;
+ OriginCountAndLastVisitMap deleted_urls_origin_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeletionInfo);
+};
+
+// Represents a visit to a domain.
+class DomainVisit {
+ public:
+ DomainVisit(const std::string& domain, base::Time visit_time)
+ : domain_(domain), visit_time_(visit_time) {}
+
+ const std::string& domain() const { return domain_; }
+
+ const base::Time visit_time() const { return visit_time_; }
+
+ private:
+ std::string domain_;
+ base::Time visit_time_;
+};
+
} // namespace history
#endif // COMPONENTS_HISTORY_CORE_BROWSER_HISTORY_TYPES_H_
diff --git a/chromium/components/history/core/browser/in_memory_database.cc b/chromium/components/history/core/browser/in_memory_database.cc
index 3ae5f679041..dfac5c5e125 100644
--- a/chromium/components/history/core/browser/in_memory_database.cc
+++ b/chromium/components/history/core/browser/in_memory_database.cc
@@ -13,8 +13,7 @@
namespace history {
-InMemoryDatabase::InMemoryDatabase() : URLDatabase() {
-}
+InMemoryDatabase::InMemoryDatabase() {}
InMemoryDatabase::~InMemoryDatabase() {
}
diff --git a/chromium/components/history/core/browser/in_memory_history_backend.cc b/chromium/components/history/core/browser/in_memory_history_backend.cc
index 9e11553e1ea..8384e6b5671 100644
--- a/chromium/components/history/core/browser/in_memory_history_backend.cc
+++ b/chromium/components/history/core/browser/in_memory_history_backend.cc
@@ -58,13 +58,10 @@ void InMemoryHistoryBackend::OnURLsModified(HistoryService* history_service,
}
void InMemoryHistoryBackend::OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
+ const DeletionInfo& deletion_info) {
DCHECK(db_);
- if (all_history) {
+ if (deletion_info.IsAllHistory()) {
// When all history is deleted, the individual URLs won't be listed. Just
// create a new database to quickly clear everything out.
db_.reset(new InMemoryDatabase);
@@ -74,7 +71,7 @@ void InMemoryHistoryBackend::OnURLsDeleted(HistoryService* history_service,
}
// Delete all matching URLs in our database.
- for (const auto& row : deleted_rows) {
+ for (const auto& row : deletion_info.deleted_rows()) {
// This will also delete the corresponding keyword search term.
// Ignore errors, as we typically only cache a subset of URLRows.
db_->DeleteURLRow(row.id());
diff --git a/chromium/components/history/core/browser/in_memory_history_backend.h b/chromium/components/history/core/browser/in_memory_history_backend.h
index 2462543c512..557467dc99c 100644
--- a/chromium/components/history/core/browser/in_memory_history_backend.h
+++ b/chromium/components/history/core/browser/in_memory_history_backend.h
@@ -78,10 +78,7 @@ class InMemoryHistoryBackend : public HistoryServiceObserver {
void OnURLsModified(HistoryService* history_service,
const URLRows& changed_urls) override;
void OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const DeletionInfo& deletion_info) override;
void OnKeywordSearchTermUpdated(HistoryService* history_service,
const URLRow& row,
KeywordID keyword_id,
diff --git a/chromium/components/history/core/browser/thumbnail_database_unittest.cc b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
index 4a3f3d793bd..8555de8676f 100644
--- a/chromium/components/history/core/browser/thumbnail_database_unittest.cc
+++ b/chromium/components/history/core/browser/thumbnail_database_unittest.cc
@@ -928,7 +928,7 @@ TEST_F(ThumbnailDatabaseTest, HasMappingFor) {
// Test loading version 3 database.
TEST_F(ThumbnailDatabaseTest, Version3) {
std::unique_ptr<ThumbnailDatabase> db = LoadFromGolden("Favicons.v3.sql");
- ASSERT_TRUE(db.get() != nullptr);
+ ASSERT_TRUE(db);
VerifyTablesAndColumns(&db->db_);
// Version 3 is deprecated, the data should all be gone.
@@ -938,7 +938,7 @@ TEST_F(ThumbnailDatabaseTest, Version3) {
// Test loading version 4 database.
TEST_F(ThumbnailDatabaseTest, Version4) {
std::unique_ptr<ThumbnailDatabase> db = LoadFromGolden("Favicons.v4.sql");
- ASSERT_TRUE(db.get() != nullptr);
+ ASSERT_TRUE(db);
VerifyTablesAndColumns(&db->db_);
// Version 4 is deprecated, the data should all be gone.
@@ -948,7 +948,7 @@ TEST_F(ThumbnailDatabaseTest, Version4) {
// Test loading version 5 database.
TEST_F(ThumbnailDatabaseTest, Version5) {
std::unique_ptr<ThumbnailDatabase> db = LoadFromGolden("Favicons.v5.sql");
- ASSERT_TRUE(db.get() != nullptr);
+ ASSERT_TRUE(db);
VerifyTablesAndColumns(&db->db_);
// Version 5 is deprecated, the data should all be gone.
@@ -958,7 +958,7 @@ TEST_F(ThumbnailDatabaseTest, Version5) {
// Test loading version 6 database.
TEST_F(ThumbnailDatabaseTest, Version6) {
std::unique_ptr<ThumbnailDatabase> db = LoadFromGolden("Favicons.v6.sql");
- ASSERT_TRUE(db.get() != nullptr);
+ ASSERT_TRUE(db);
VerifyTablesAndColumns(&db->db_);
// Version 6 is deprecated, the data should all be gone.
@@ -968,7 +968,7 @@ TEST_F(ThumbnailDatabaseTest, Version6) {
// Test loading version 7 database.
TEST_F(ThumbnailDatabaseTest, Version7) {
std::unique_ptr<ThumbnailDatabase> db = LoadFromGolden("Favicons.v7.sql");
- ASSERT_TRUE(db.get() != nullptr);
+ ASSERT_TRUE(db);
VerifyTablesAndColumns(&db->db_);
EXPECT_TRUE(CheckPageHasIcon(db.get(), kPageUrl1,
@@ -988,7 +988,7 @@ TEST_F(ThumbnailDatabaseTest, Version7) {
// Test loading version 8 database.
TEST_F(ThumbnailDatabaseTest, Version8) {
std::unique_ptr<ThumbnailDatabase> db = LoadFromGolden("Favicons.v8.sql");
- ASSERT_TRUE(db.get() != nullptr);
+ ASSERT_TRUE(db);
VerifyTablesAndColumns(&db->db_);
EXPECT_TRUE(CheckPageHasIcon(db.get(), kPageUrl1,
diff --git a/chromium/components/history/core/browser/top_sites.cc b/chromium/components/history/core/browser/top_sites.cc
index 5acf6dbf218..c24bacbf1ee 100644
--- a/chromium/components/history/core/browser/top_sites.cc
+++ b/chromium/components/history/core/browser/top_sites.cc
@@ -9,8 +9,7 @@
namespace history {
PrepopulatedPage::PrepopulatedPage()
- : most_visited(), favicon_id(-1), thumbnail_id(-1), color() {
-}
+ : favicon_id(-1), thumbnail_id(-1), color() {}
PrepopulatedPage::PrepopulatedPage(const GURL& url,
const base::string16& title,
diff --git a/chromium/components/history/core/browser/top_sites_impl.cc b/chromium/components/history/core/browser/top_sites_impl.cc
index 0ed5797f860..eba874f4c99 100644
--- a/chromium/components/history/core/browser/top_sites_impl.cc
+++ b/chromium/components/history/core/browser/top_sites_impl.cc
@@ -890,19 +890,16 @@ void TopSitesImpl::OnTopSitesAvailableFromHistory(
}
void TopSitesImpl::OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
+ const DeletionInfo& deletion_info) {
if (!loaded_)
return;
- if (all_history) {
+ if (deletion_info.IsAllHistory()) {
SetTopSites(MostVisitedURLList(), CALL_LOCATION_FROM_OTHER_PLACES);
backend_->ResetDatabase();
} else {
std::set<size_t> indices_to_delete; // Indices into top_sites_.
- for (const auto& row : deleted_rows) {
+ for (const auto& row : deletion_info.deleted_rows()) {
if (cache_->IsKnownURL(row.url()))
indices_to_delete.insert(cache_->GetURLIndex(row.url()));
}
diff --git a/chromium/components/history/core/browser/top_sites_impl.h b/chromium/components/history/core/browser/top_sites_impl.h
index dc40668f6d1..ea6751b3fb3 100644
--- a/chromium/components/history/core/browser/top_sites_impl.h
+++ b/chromium/components/history/core/browser/top_sites_impl.h
@@ -268,10 +268,7 @@ class TopSitesImpl : public TopSites, public HistoryServiceObserver {
// history::HistoryServiceObserver:
void OnURLsDeleted(HistoryService* history_service,
- bool all_history,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const DeletionInfo& deletion_info) override;
// Ensures that non thread-safe methods are called on the correct thread.
base::ThreadChecker thread_checker_;
diff --git a/chromium/components/history/core/browser/typed_url_model_type_controller.cc b/chromium/components/history/core/browser/typed_url_model_type_controller.cc
index 33fc6d462b4..08fa338e7bc 100644
--- a/chromium/components/history/core/browser/typed_url_model_type_controller.cc
+++ b/chromium/components/history/core/browser/typed_url_model_type_controller.cc
@@ -9,11 +9,13 @@
#include "components/history/core/browser/history_db_task.h"
#include "components/history/core/browser/history_service.h"
#include "components/prefs/pref_service.h"
+#include "components/sync/driver/model_type_controller.h"
#include "components/sync/driver/sync_client.h"
+#include "components/sync/model/model_type_controller_delegate.h"
using syncer::ModelType;
using syncer::ModelTypeController;
-using syncer::ModelTypeSyncBridge;
+using syncer::ModelTypeControllerDelegate;
using syncer::SyncClient;
namespace history {
@@ -25,7 +27,7 @@ namespace {
// the tasks we want to run.
class RunTaskOnHistoryThread : public HistoryDBTask {
public:
- explicit RunTaskOnHistoryThread(ModelTypeController::BridgeTask task)
+ explicit RunTaskOnHistoryThread(ModelTypeController::ModelTask task)
: task_(std::move(task)) {}
bool RunOnDBThread(HistoryBackend* backend, HistoryDatabase* db) override {
@@ -33,17 +35,20 @@ class RunTaskOnHistoryThread : public HistoryDBTask {
// around all the way until DoneRunOnMainThread() is invoked back on the
// main thread - we want to release references as soon as possible to avoid
// keeping them around too long during shutdown.
- TypedURLSyncBridge* bridge = backend->GetTypedURLSyncBridge();
- DCHECK(bridge);
+ base::WeakPtr<ModelTypeControllerDelegate> delegate =
+ backend->GetTypedURLSyncBridge()
+ ->change_processor()
+ ->GetControllerDelegateOnUIThread();
+ DCHECK(delegate);
- std::move(task_).Run(bridge);
+ std::move(task_).Run(delegate);
return true;
}
void DoneRunOnMainThread() override {}
protected:
- ModelTypeController::BridgeTask task_;
+ ModelTypeController::ModelTask task_;
};
} // namespace
@@ -68,8 +73,8 @@ bool TypedURLModelTypeController::ReadyForStart() const {
history_disabled_pref_name_);
}
-void TypedURLModelTypeController::PostBridgeTask(const base::Location& location,
- BridgeTask task) {
+void TypedURLModelTypeController::PostModelTask(const base::Location& location,
+ ModelTask task) {
history::HistoryService* history = sync_client()->GetHistoryService();
if (!history) {
// History must be disabled - don't start.
diff --git a/chromium/components/history/core/browser/typed_url_model_type_controller.h b/chromium/components/history/core/browser/typed_url_model_type_controller.h
index d528d409fbd..df2a43dded9 100644
--- a/chromium/components/history/core/browser/typed_url_model_type_controller.h
+++ b/chromium/components/history/core/browser/typed_url_model_type_controller.h
@@ -23,7 +23,7 @@ class TypedURLModelTypeController : public syncer::ModelTypeController {
private:
// syncer::ModelTypeController implementation.
- void PostBridgeTask(const base::Location& location, BridgeTask task) override;
+ void PostModelTask(const base::Location& location, ModelTask task) override;
void OnSavingBrowserHistoryDisabledChanged();
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge.cc b/chromium/components/history/core/browser/typed_url_sync_bridge.cc
index 230ac721223..edbd2b4e795 100644
--- a/chromium/components/history/core/browser/typed_url_sync_bridge.cc
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge.cc
@@ -281,7 +281,7 @@ void TypedURLSyncBridge::GetData(StorageKeyList storage_keys,
continue;
std::unique_ptr<syncer::EntityData> entity_data =
CreateEntityData(url_row, visits_vector);
- if (!entity_data.get()) {
+ if (!entity_data) {
// Cannot create EntityData, ex. no TYPED visits.
continue;
}
@@ -311,7 +311,7 @@ void TypedURLSyncBridge::GetAllData(DataCallback callback) {
continue;
std::unique_ptr<syncer::EntityData> entity_data =
CreateEntityData(url, visits_vector);
- if (!entity_data.get()) {
+ if (!entity_data) {
// Cannot create EntityData, ex. no TYPED visits.
continue;
}
@@ -410,8 +410,20 @@ void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
// client with a bad clock setting won't go on an expiration rampage and
// delete all history from every client). The server will gracefully age out
// the sync DB entries when they've been idle for long enough.
- if (expired)
+ if (expired) {
+ // Delete metadata from the DB and ask the processor to untrack the entries.
+ for (const URLRow& row : deleted_rows) {
+ std::string storage_key = GetStorageKeyFromURLRow(row);
+ sync_metadata_database_->ClearSyncMetadata(syncer::TYPED_URLS,
+ storage_key);
+ // TODO(jkrcal): Untrack the entity from the processor, too (by
+ // introducing UntrackEntityForStorageKey() function into the change
+ // processor). Extend the integration tests to cover the crash in
+ // https://crbug.com/827111. Also add unit-test coverage for expired
+ // deletions (needs some refactoring in the tests).
+ }
return;
+ }
std::unique_ptr<MetadataChangeList> metadata_change_list =
CreateMetadataChangeList();
@@ -431,7 +443,7 @@ void TypedURLSyncBridge::OnURLsDeleted(HistoryBackend* history_backend,
}
} else {
// Delete rows.
- for (const auto& row : deleted_rows) {
+ for (const URLRow& row : deleted_rows) {
std::string storage_key = GetStorageKeyFromURLRow(row);
change_processor()->Delete(storage_key, metadata_change_list.get());
}
@@ -648,8 +660,10 @@ TypedURLSyncBridge::MergeResult TypedURLSyncBridge::MergeUrls(
new_visit->first > visit_ix->visit_time) {
++visit_ix;
}
- visit_ix = visits->insert(visit_ix, VisitRow(url.id(), new_visit->first,
- 0, new_visit->second, 0));
+ visit_ix = visits->insert(
+ visit_ix,
+ VisitRow(url.id(), new_visit->first, 0, new_visit->second, 0,
+ HistoryBackend::IsTypedIncrement(new_visit->second)));
++visit_ix;
}
}
@@ -740,7 +754,7 @@ void TypedURLSyncBridge::LoadMetadata() {
"TypedURLSyncMetadataDatabase."});
return;
}
- change_processor()->ModelReadyToSync(this, std::move(batch));
+ change_processor()->ModelReadyToSync(std::move(batch));
}
void TypedURLSyncBridge::ClearErrorStats() {
@@ -1096,7 +1110,7 @@ bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url,
}
VisitRow visit(url->id(), url->last_visit(), 0, ui::PAGE_TRANSITION_TYPED,
- 0);
+ 0, true);
visits->push_back(visit);
}
@@ -1200,7 +1214,7 @@ void TypedURLSyncBridge::SendTypedURLToProcessor(
std::unique_ptr<syncer::EntityData> entity_data =
CreateEntityData(row, visits);
- if (!entity_data.get()) {
+ if (!entity_data) {
// Cannot create EntityData, ex. no TYPED visits.
return;
}
diff --git a/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc b/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc
index d96c38b3188..6eb285e17c1 100644
--- a/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc
+++ b/chromium/components/history/core/browser/typed_url_sync_bridge_unittest.cc
@@ -70,7 +70,9 @@ void AddNewestVisit(ui::PageTransition transition,
URLRow* url,
VisitVector* visits) {
base::Time time = base::Time::FromInternalValue(visit_time);
- visits->insert(visits->begin(), VisitRow(url->id(), time, 0, transition, 0));
+ visits->insert(visits->begin(),
+ VisitRow(url->id(), time, 0, transition, 0,
+ HistoryBackend::IsTypedIncrement(transition)));
if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) {
url->set_typed_count(url->typed_count() + 1);
@@ -85,7 +87,8 @@ void AddOldestVisit(ui::PageTransition transition,
URLRow* url,
VisitVector* visits) {
base::Time time = base::Time::FromInternalValue(visit_time);
- visits->push_back(VisitRow(url->id(), time, 0, transition, 0));
+ visits->push_back(VisitRow(url->id(), time, 0, transition, 0,
+ HistoryBackend::IsTypedIncrement(transition)));
if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_TYPED)) {
url->set_typed_count(url->typed_count() + 1);
@@ -115,11 +118,11 @@ URLRow MakeTypedUrlRow(const std::string& url,
if (typed_count > 0) {
// Add a typed visit for time |last_visit|.
visits->push_back(VisitRow(history_url.id(), last_visit_time, 0,
- ui::PAGE_TRANSITION_TYPED, 0));
+ ui::PAGE_TRANSITION_TYPED, 0, true));
} else {
// Add a non-typed visit for time |last_visit|.
visits->push_back(VisitRow(history_url.id(), last_visit_time, 0,
- ui::PAGE_TRANSITION_RELOAD, 0));
+ ui::PAGE_TRANSITION_RELOAD, 0, false));
}
history_url.set_visit_count(visits->size());
@@ -178,10 +181,7 @@ class TestHistoryBackendDelegate : public HistoryBackend::Delegate {
const RedirectList& redirects,
base::Time visit_time) override {}
void NotifyURLsModified(const URLRows& changed_urls) override {}
- void NotifyURLsDeleted(const DeletionTimeRange& time_range,
- bool expired,
- const URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override {}
+ void NotifyURLsDeleted(DeletionInfo deletion_info) override {}
void NotifyKeywordSearchTermUpdated(const URLRow& row,
KeywordID keyword_id,
const base::string16& term) override {}
@@ -305,14 +305,15 @@ class TypedURLSyncBridgeTest : public testing::Test {
int typed_count,
int64_t last_visit,
bool hidden,
+ bool update_metadata,
EntityChange::ChangeType change_type) {
VisitVector visits;
URLRow row =
MakeTypedUrlRow(url, title, typed_count, last_visit, hidden, &visits);
sync_pb::TypedUrlSpecifics typed_url_specifics;
WriteToTypedUrlSpecifics(row, visits, &typed_url_specifics);
- std::unique_ptr<MetadataChangeList> metadata_changes =
- bridge()->CreateMetadataChangeList();
+ std::string storage_key = GetStorageKey(typed_url_specifics.url());
+
EntityChangeList entity_changes;
switch (change_type) {
case EntityChange::ACTION_ADD:
@@ -320,15 +321,24 @@ class TypedURLSyncBridgeTest : public testing::Test {
std::string(), SpecificsToEntity(typed_url_specifics)));
break;
case EntityChange::ACTION_UPDATE:
- entity_changes.push_back(
- EntityChange::CreateUpdate(GetStorageKey(typed_url_specifics.url()),
- SpecificsToEntity(typed_url_specifics)));
+ entity_changes.push_back(EntityChange::CreateUpdate(
+ storage_key, SpecificsToEntity(typed_url_specifics)));
break;
case EntityChange::ACTION_DELETE:
- entity_changes.push_back(EntityChange::CreateDelete(
- GetStorageKey(typed_url_specifics.url())));
+ entity_changes.push_back(EntityChange::CreateDelete(storage_key));
break;
}
+
+ std::unique_ptr<MetadataChangeList> metadata_changes =
+ bridge()->CreateMetadataChangeList();
+ // There needs to be data present in the history DB before inserting
+ // metadata.
+ if (update_metadata) {
+ sync_pb::EntityMetadata metadata;
+ metadata.set_sequence_number(1);
+ metadata_changes->UpdateMetadata(storage_key, metadata);
+ }
+
bridge()->ApplySyncChanges(std::move(metadata_changes), entity_changes);
return visits;
}
@@ -416,7 +426,8 @@ class TypedURLSyncBridgeTest : public testing::Test {
}
static VisitRow CreateVisit(ui::PageTransition type, int64_t timestamp) {
- return VisitRow(0, base::Time::FromInternalValue(timestamp), 0, type, 0);
+ return VisitRow(0, base::Time::FromInternalValue(timestamp), 0, type, 0,
+ HistoryBackend::IsTypedIncrement(type));
}
static TypedURLSyncBridge::MergeResult MergeUrls(
@@ -998,6 +1009,65 @@ TEST_F(TypedURLSyncBridgeTest, DeleteLocalTypedUrl) {
ASSERT_TRUE(deleted_storage_keys.empty());
}
+// Expire several (but not all) local typed urls. This has only impact on local
+// store (metadata in the db and in-memory maps), nothing gets synced up.
+TEST_F(TypedURLSyncBridgeTest, ExpireLocalTypedUrl) {
+ StartSyncing(std::vector<TypedUrlSpecifics>());
+
+ URLRows url_rows;
+ std::vector<VisitVector> visit_vectors;
+ std::vector<std::string> urls;
+ urls.push_back("http://pie.com/");
+ urls.push_back("http://cake.com/");
+ urls.push_back("http://google.com/");
+ urls.push_back("http://foo.com/");
+ urls.push_back("http://bar.com/");
+
+ // Add the URLs into the history db and notify the bridge.
+ ASSERT_TRUE(BuildAndPushLocalChanges(5, 0, urls, &url_rows, &visit_vectors));
+ ASSERT_EQ(5U, processor().put_multimap().size());
+ int previous_put_size = processor().put_multimap().size();
+ // Store the typed_urls incl. metadata into the bridge's database.
+ for (const std::string& url : urls) {
+ ApplyUrlAndVisitsChange(url, kTitle, /*typed_count=*/1, /*last_visit=*/3,
+ /*hidden=*/false, /*update_metadata=*/true,
+ EntityChange::ACTION_ADD);
+ }
+
+ // Check all the metadata is here.
+ MetadataBatch metadata_batch;
+ metadata_store()->GetAllSyncMetadata(&metadata_batch);
+ ASSERT_EQ(5u, metadata_batch.TakeAllMetadata().size());
+
+ // Simulate expiration - delete some urls from the backend and create deleted
+ // row vector.
+ URLRows rows;
+ std::set<std::string> deleted_storage_keys;
+ for (size_t i = 0; i < 3u; ++i) {
+ std::string storage_key = GetStorageKey(url_rows[i].url().spec());
+ deleted_storage_keys.insert(storage_key);
+ fake_history_backend_->DeleteURL(url_rows[i].url());
+ rows.push_back(url_rows[i]);
+ }
+
+ // Notify typed url sync service of these URLs getting expired.
+ bridge()->OnURLsDeleted(fake_history_backend_.get(), /*all_history=*/false,
+ /*expired=*/true, rows, std::set<GURL>());
+
+ // This does not propagate to the processor.
+ EXPECT_EQ(0U, processor().put_multimap().size() - previous_put_size);
+ EXPECT_EQ(0U, processor().delete_set().size());
+
+ // The urls are removed from the metadata store.
+ MetadataBatch smaller_metadata_batch;
+ metadata_store()->GetAllSyncMetadata(&smaller_metadata_batch);
+ EXPECT_EQ(2u, smaller_metadata_batch.GetAllMetadata().size());
+ for (const auto& kv : smaller_metadata_batch.GetAllMetadata()) {
+ EXPECT_TRUE(deleted_storage_keys.find(kv.first) ==
+ deleted_storage_keys.end());
+ }
+}
+
// Saturate the visits for a typed url with both TYPED and LINK navigations.
// Check that no more than kMaxTypedURLVisits are synced, and that LINK visits
// are dropped rather than TYPED ones.
@@ -1105,8 +1175,10 @@ TEST_F(TypedURLSyncBridgeTest, ThrottleVisitLocalTypedUrl) {
// has started. Check that local DB is received the new URL and visit.
TEST_F(TypedURLSyncBridgeTest, AddUrlAndVisits) {
StartSyncing(std::vector<TypedUrlSpecifics>());
- VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false,
- EntityChange::ACTION_ADD);
+ VisitVector visits = ApplyUrlAndVisitsChange(
+ kURL, kTitle, /*typed_count=*/1, /*last_visit=*/3,
+ /*hidden=*/false,
+ /*update_metadata=*/false, EntityChange::ACTION_ADD);
ASSERT_EQ(0U, processor().put_multimap().size());
ASSERT_EQ(1U, processor().update_multimap().size());
@@ -1138,8 +1210,9 @@ TEST_F(TypedURLSyncBridgeTest, AddUrlAndVisits) {
// visit.
TEST_F(TypedURLSyncBridgeTest, AddExpiredUrlAndVisits) {
StartSyncing(std::vector<TypedUrlSpecifics>());
- VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, kExpiredVisit,
- false, EntityChange::ACTION_ADD);
+ VisitVector visits = ApplyUrlAndVisitsChange(
+ kURL, kTitle, /*typed_count=*/1, /*last_visit=*/kExpiredVisit,
+ /*hidden=*/false, /*update_metadata=*/false, EntityChange::ACTION_ADD);
ASSERT_EQ(0U, processor().put_multimap().size());
ASSERT_EQ(0U, processor().update_multimap().size());
@@ -1155,8 +1228,10 @@ TEST_F(TypedURLSyncBridgeTest, AddExpiredUrlAndVisits) {
TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) {
StartSyncing(std::vector<TypedUrlSpecifics>());
- VisitVector visits = ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false,
- EntityChange::ACTION_ADD);
+ VisitVector visits = ApplyUrlAndVisitsChange(
+ kURL, kTitle, /*typed_count=*/1, /*last_visit=*/3,
+ /*hidden=*/false,
+ /*update_metadata=*/false, EntityChange::ACTION_ADD);
base::Time visit_time = base::Time::FromInternalValue(3);
VisitVector all_visits;
URLRow url_row;
@@ -1173,8 +1248,10 @@ TEST_F(TypedURLSyncBridgeTest, UpdateUrlAndVisits) {
EXPECT_TRUE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
EXPECT_EQ(kTitle, base::UTF16ToUTF8(url_row.title()));
- VisitVector new_visits = ApplyUrlAndVisitsChange(kURL, kTitle2, 2, 6, false,
- EntityChange::ACTION_UPDATE);
+ VisitVector new_visits = ApplyUrlAndVisitsChange(
+ kURL, kTitle2, /*typed_count=*/2, /*last_visit=*/6,
+ /*hidden=*/false,
+ /*update_metadata=*/false, EntityChange::ACTION_UPDATE);
base::Time new_visit_time = base::Time::FromInternalValue(6);
url_id = fake_history_backend_->GetIdByUrl(GURL(kURL));
@@ -1219,7 +1296,8 @@ TEST_F(TypedURLSyncBridgeTest, DeleteUrlAndVisits) {
// changes back from fake_history_backend_.
AddObserver();
- ApplyUrlAndVisitsChange(kURL, kTitle, 1, 3, false,
+ ApplyUrlAndVisitsChange(kURL, kTitle, /*typed_count=*/1, /*last_visit=*/3,
+ /*hidden=*/false, /*update_metadata=*/false,
EntityChange::ACTION_DELETE);
EXPECT_FALSE(fake_history_backend_->GetURL(GURL(kURL), &url_row));
@@ -1241,7 +1319,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsSame) {
for (int64_t visit : visits) {
old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
+ ui::PAGE_TRANSITION_TYPED, 0, true));
new_url.add_visits(visit);
new_url.add_visit_transitions(ui::PAGE_TRANSITION_TYPED);
}
@@ -1271,7 +1349,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsRemove) {
for (int64_t visit : visits_left) {
old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
+ ui::PAGE_TRANSITION_TYPED, 0, true));
}
for (int64_t visit : visits_right) {
@@ -1305,7 +1383,7 @@ TEST_F(TypedURLSyncBridgeTest, DiffVisitsAdd) {
for (int64_t visit : visits_left) {
old_visits.push_back(VisitRow(0, base::Time::FromInternalValue(visit), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
+ ui::PAGE_TRANSITION_TYPED, 0, true));
}
for (int64_t visit : visits_right) {
@@ -1495,7 +1573,7 @@ TEST_F(TypedURLSyncBridgeTest, MergeUrlsAfterExpiration) {
// First, create a history row that has two visits, with timestamps 2 and 3.
VisitVector(history_visits);
history_visits.push_back(VisitRow(0, base::Time::FromInternalValue(2), 0,
- ui::PAGE_TRANSITION_TYPED, 0));
+ ui::PAGE_TRANSITION_TYPED, 0, true));
URLRow history_url(
MakeTypedUrlRow(kURL, kTitle, 2, 3, false, &history_visits));
diff --git a/chromium/components/history/core/browser/visit_database.cc b/chromium/components/history/core/browser/visit_database.cc
index 0ef84afb008..8dca02c1f2b 100644
--- a/chromium/components/history/core/browser/visit_database.cc
+++ b/chromium/components/history/core/browser/visit_database.cc
@@ -17,8 +17,11 @@
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
+#include "components/google/core/browser/google_util.h"
+#include "components/history/core/browser/history_backend.h"
#include "components/history/core/browser/url_database.h"
#include "sql/statement.h"
+#include "sql/transaction.h"
#include "ui/base/page_transition_types.h"
#include "url/url_constants.h"
@@ -42,7 +45,8 @@ bool VisitDatabase::InitVisitTable() {
"segment_id INTEGER,"
// Some old DBs may have an "is_indexed" field here, but this is no
// longer used and should NOT be read or written from any longer.
- "visit_duration INTEGER DEFAULT 0 NOT NULL)"))
+ "visit_duration INTEGER DEFAULT 0 NOT NULL,"
+ "incremented_omnibox_typed_score BOOLEAN DEFAULT FALSE NOT NULL)"))
return false;
}
@@ -98,6 +102,7 @@ void VisitDatabase::FillVisitRow(const sql::Statement& statement,
visit->segment_id = statement.ColumnInt64(5);
visit->visit_duration =
base::TimeDelta::FromInternalValue(statement.ColumnInt64(6));
+ visit->incremented_omnibox_typed_score = statement.ColumnBool(7);
}
// static
@@ -149,16 +154,19 @@ bool VisitDatabase::FillVisitVectorWithOptions(sql::Statement& statement,
}
VisitID VisitDatabase::AddVisit(VisitRow* visit, VisitSource source) {
- sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ sql::Statement statement(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
"INSERT INTO visits "
"(url, visit_time, from_visit, transition, segment_id, "
- "visit_duration) VALUES (?,?,?,?,?,?)"));
+ "visit_duration, incremented_omnibox_typed_score) "
+ "VALUES (?,?,?,?,?,?,?)"));
statement.BindInt64(0, visit->url_id);
statement.BindInt64(1, visit->visit_time.ToInternalValue());
statement.BindInt64(2, visit->referring_visit);
statement.BindInt64(3, visit->transition);
statement.BindInt64(4, visit->segment_id);
statement.BindInt64(5, visit->visit_duration.ToInternalValue());
+ statement.BindBool(6, visit->incremented_omnibox_typed_score);
if (!statement.Run()) {
DVLOG(0) << "Failed to execute visit insert statement: "
@@ -235,17 +243,19 @@ bool VisitDatabase::UpdateVisitRow(const VisitRow& visit) {
if (visit.visit_id == visit.referring_visit)
return false;
- sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
+ sql::Statement statement(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
"UPDATE visits SET "
"url=?,visit_time=?,from_visit=?,transition=?,segment_id=?,"
- "visit_duration=? WHERE id=?"));
+ "visit_duration=?,incremented_omnibox_typed_score=? WHERE id=?"));
statement.BindInt64(0, visit.url_id);
statement.BindInt64(1, visit.visit_time.ToInternalValue());
statement.BindInt64(2, visit.referring_visit);
statement.BindInt64(3, visit.transition);
statement.BindInt64(4, visit.segment_id);
statement.BindInt64(5, visit.visit_duration.ToInternalValue());
- statement.BindInt64(6, visit.visit_id);
+ statement.BindBool(6, visit.incremented_omnibox_typed_score);
+ statement.BindInt64(7, visit.visit_id);
return statement.Run();
}
@@ -610,6 +620,46 @@ void VisitDatabase::GetVisitsSource(const VisitVector& visits,
}
}
+std::vector<DomainVisit>
+VisitDatabase::GetGoogleDomainVisitsFromSearchesInRange(base::Time begin_time,
+ base::Time end_time) {
+ sql::Statement statement(GetDB().GetCachedStatement(
+ SQL_FROM_HERE,
+ "SELECT "
+ " visit_time, "
+ " u.url "
+ "FROM "
+ " urls u JOIN visits v ON u.id = v.url "
+ "WHERE "
+ // Pre-filtering to limit the number of entries to process in
+ // C++. The url column is indexed so this makes the query more
+ // efficient. We then confirm in C++ that the domain of an entry
+ // is a valid Google domain before counting the visit.
+ " (u.url LIKE \"https://www.google.__/search%\" OR "
+ " u.url LIKE \"https://www.google.___/search%\" OR "
+ " u.url LIKE \"https://www.google.__.__/search%\" OR "
+ " u.url LIKE \"https://www.google.___.__/search%\") AND "
+ // Restrict to visits that are more recent than the specified start
+ // time.
+ " visit_time >= ? AND "
+ // Restrict to visits that are older than the specified end time.
+ " visit_time < ? "));
+ statement.BindInt64(0,
+ begin_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+ statement.BindInt64(1, end_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
+ std::vector<DomainVisit> domain_visits;
+ while (statement.Step()) {
+ const GURL url(statement.ColumnString(1));
+ if (google_util::IsGoogleSearchUrl(url)) {
+ domain_visits.emplace_back(
+ url.host(),
+ base::Time::FromDeltaSinceWindowsEpoch(
+ base::TimeDelta::FromMicroseconds(statement.ColumnInt64(0))));
+ }
+ }
+ return domain_visits;
+}
+
bool VisitDatabase::MigrateVisitsWithoutDuration() {
if (!GetDB().DoesTableExist("visits")) {
NOTREACHED() << " Visits table should exist before migration";
@@ -626,4 +676,48 @@ bool VisitDatabase::MigrateVisitsWithoutDuration() {
return true;
}
+bool VisitDatabase::MigrateVisitsWithoutIncrementedOmniboxTypedScore() {
+ if (!GetDB().DoesTableExist("visits")) {
+ NOTREACHED() << " Visits table should exist before migration";
+ return false;
+ }
+
+ if (!GetDB().DoesColumnExist("visits", "incremented_omnibox_typed_score")) {
+ // Wrap the creation and initialization of the new column in a transaction
+ // since the value must be computed outside of SQL and iteratively updated.
+ sql::Transaction committer(&GetDB());
+ if (!committer.Begin())
+ return false;
+
+ // Old versions don't have the incremented_omnibox_typed_score column, we
+ // modify the table to add that field. We iterate through the table and
+ // compute the result for each row.
+ if (!GetDB().Execute("ALTER TABLE visits "
+ "ADD COLUMN incremented_omnibox_typed_score BOOLEAN "
+ "DEFAULT FALSE NOT NULL"))
+ return false;
+
+ // Iterate through rows in the visits table and update each with the
+ // appropriate increment_omnibox_typed_score value. Because this column was
+ // newly added, the existing (default) value is not valid/correct.
+ sql::Statement read(GetDB().GetUniqueStatement(
+ "SELECT" HISTORY_VISIT_ROW_FIELDS "FROM visits"));
+ while (read.is_valid() && read.Step()) {
+ VisitRow row;
+ FillVisitRow(read, &row);
+ // Check if the visit row is in an invalid state and if it is then
+ // leave the new field as the default value.
+ if (row.visit_id == row.referring_visit)
+ continue;
+ row.incremented_omnibox_typed_score =
+ HistoryBackend::IsTypedIncrement(row.transition);
+ if (!UpdateVisitRow(row))
+ return false;
+ }
+ if (!read.Succeeded() || !committer.Commit())
+ return false;
+ }
+ return true;
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/visit_database.h b/chromium/components/history/core/browser/visit_database.h
index ee950544f97..c4ec7ace7b1 100644
--- a/chromium/components/history/core/browser/visit_database.h
+++ b/chromium/components/history/core/browser/visit_database.h
@@ -188,6 +188,13 @@ class VisitDatabase {
void GetVisitsSource(const VisitVector& visits,
VisitSourceMap* sources);
+ // Returns the list of Google domain visits of the user based on the Google
+ // searches issued in the specified time interval.
+ // begin_time is inclusive, end_time is exclusive.
+ std::vector<DomainVisit> GetGoogleDomainVisitsFromSearchesInRange(
+ base::Time begin_time,
+ base::Time end_time);
+
protected:
// Returns the database for the functions in this interface.
virtual sql::Connection& GetDB() = 0;
@@ -216,14 +223,19 @@ class VisitDatabase {
// don't have visit_duration column yet.
bool MigrateVisitsWithoutDuration();
+ // Called by the derived classes to migrate the older visits table which
+ // don't have incremented_omnibox_typed_score column yet.
+ bool MigrateVisitsWithoutIncrementedOmniboxTypedScore();
+
private:
DISALLOW_COPY_AND_ASSIGN(VisitDatabase);
};
-// Rows, in order, of the visit table.
-#define HISTORY_VISIT_ROW_FIELDS \
- " id,url,visit_time,from_visit,transition,segment_id,visit_duration "
+// Columns, in order, of the visit table.
+#define HISTORY_VISIT_ROW_FIELDS \
+ " id,url,visit_time,from_visit,transition,segment_id,visit_duration," \
+ "incremented_omnibox_typed_score "
} // namespace history
diff --git a/chromium/components/history/core/browser/visit_database_unittest.cc b/chromium/components/history/core/browser/visit_database_unittest.cc
index 77be2f6388d..ee7aad30b4e 100644
--- a/chromium/components/history/core/browser/visit_database_unittest.cc
+++ b/chromium/components/history/core/browser/visit_database_unittest.cc
@@ -14,11 +14,16 @@
#include "components/history/core/browser/url_database.h"
#include "components/history/core/browser/visit_database.h"
#include "sql/connection.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
using base::Time;
using base::TimeDelta;
+using testing::AllOf;
+using testing::ElementsAre;
+using testing::IsEmpty;
+using testing::Property;
namespace history {
@@ -71,19 +76,18 @@ class VisitDatabaseTest : public PlatformTest,
TEST_F(VisitDatabaseTest, Add) {
// Add one visit.
- VisitRow visit_info1(1, Time::Now(), 0, ui::PAGE_TRANSITION_LINK, 0);
+ VisitRow visit_info1(1, Time::Now(), 0, ui::PAGE_TRANSITION_LINK, 0, false);
EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
// Add second visit for the same page.
VisitRow visit_info2(visit_info1.url_id,
- visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
- ui::PAGE_TRANSITION_TYPED, 0);
+ visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
+ ui::PAGE_TRANSITION_TYPED, 0, true);
EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
// Add third visit for a different page.
- VisitRow visit_info3(2,
- visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
- ui::PAGE_TRANSITION_LINK, 0);
+ VisitRow visit_info3(2, visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
+ ui::PAGE_TRANSITION_LINK, 0, false);
EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// Query the first two.
@@ -102,17 +106,17 @@ TEST_F(VisitDatabaseTest, Delete) {
// should link them.
static const int kTime1 = 1000;
VisitRow visit_info1(1, Time::FromInternalValue(kTime1), 0,
- ui::PAGE_TRANSITION_LINK, 0);
+ ui::PAGE_TRANSITION_LINK, 0, false);
EXPECT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
static const int kTime2 = kTime1 + 1;
- VisitRow visit_info2(1, Time::FromInternalValue(kTime2),
- visit_info1.visit_id, ui::PAGE_TRANSITION_LINK, 0);
+ VisitRow visit_info2(1, Time::FromInternalValue(kTime2), visit_info1.visit_id,
+ ui::PAGE_TRANSITION_LINK, 0, false);
EXPECT_TRUE(AddVisit(&visit_info2, SOURCE_BROWSED));
static const int kTime3 = kTime2 + 1;
- VisitRow visit_info3(1, Time::FromInternalValue(kTime3),
- visit_info2.visit_id, ui::PAGE_TRANSITION_LINK, 0);
+ VisitRow visit_info3(1, Time::FromInternalValue(kTime3), visit_info2.visit_id,
+ ui::PAGE_TRANSITION_LINK, 0, false);
EXPECT_TRUE(AddVisit(&visit_info3, SOURCE_BROWSED));
// First make sure all the visits are there.
@@ -138,7 +142,8 @@ TEST_F(VisitDatabaseTest, Delete) {
TEST_F(VisitDatabaseTest, Update) {
// Make something in the database.
- VisitRow original(1, Time::Now(), 23, ui::PageTransitionFromInt(0), 19);
+ VisitRow original(1, Time::Now(), 23, ui::PageTransitionFromInt(0), 19,
+ false);
AddVisit(&original, SOURCE_BROWSED);
// Mutate that row.
@@ -165,61 +170,58 @@ std::vector<VisitRow> GetTestVisitRows() {
base::Time base_time = Time::UnixEpoch().LocalMidnight();
// Add one visit.
- VisitRow visit_info1(1, base_time + TimeDelta::FromMinutes(1), 0,
- ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_LINK |
- ui::PAGE_TRANSITION_CHAIN_START |
- ui::PAGE_TRANSITION_CHAIN_END),
- 0);
+ VisitRow visit_info1(
+ 1, base_time + TimeDelta::FromMinutes(1), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ 0, false);
visit_info1.visit_id = 1;
// Add second visit for the same page.
- VisitRow visit_info2(visit_info1.url_id,
- visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
- ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_TYPED |
- ui::PAGE_TRANSITION_CHAIN_START |
- ui::PAGE_TRANSITION_CHAIN_END),
- 0);
+ VisitRow visit_info2(
+ visit_info1.url_id, visit_info1.visit_time + TimeDelta::FromSeconds(1), 1,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ 0, true);
visit_info2.visit_id = 2;
// Add third visit for a different page.
- VisitRow visit_info3(2,
- visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
- ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_LINK |
- ui::PAGE_TRANSITION_CHAIN_START),
- 0);
+ VisitRow visit_info3(
+ 2, visit_info1.visit_time + TimeDelta::FromSeconds(2), 0,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_CHAIN_START),
+ 0, false);
visit_info3.visit_id = 3;
// Add a redirect visit from the last page.
- VisitRow visit_info4(3,
- visit_info1.visit_time + TimeDelta::FromSeconds(3), visit_info3.visit_id,
- ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_SERVER_REDIRECT |
- ui::PAGE_TRANSITION_CHAIN_END),
- 0);
+ VisitRow visit_info4(
+ 3, visit_info1.visit_time + TimeDelta::FromSeconds(3),
+ visit_info3.visit_id,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_SERVER_REDIRECT |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ 0, false);
visit_info4.visit_id = 4;
// Add a subframe visit.
- VisitRow visit_info5(4,
- visit_info1.visit_time + TimeDelta::FromSeconds(4), visit_info4.visit_id,
- ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_AUTO_SUBFRAME |
- ui::PAGE_TRANSITION_CHAIN_START |
- ui::PAGE_TRANSITION_CHAIN_END),
- 0);
+ VisitRow visit_info5(
+ 4, visit_info1.visit_time + TimeDelta::FromSeconds(4),
+ visit_info4.visit_id,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_SUBFRAME |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ 0, false);
visit_info5.visit_id = 5;
// Add third visit for the same URL as visit 1 and 2, but exactly a day
// later than visit 2.
- VisitRow visit_info6(visit_info1.url_id,
- visit_info2.visit_time + TimeDelta::FromDays(1), 1,
- ui::PageTransitionFromInt(
- ui::PAGE_TRANSITION_TYPED |
- ui::PAGE_TRANSITION_CHAIN_START |
- ui::PAGE_TRANSITION_CHAIN_END),
- 0);
+ VisitRow visit_info6(
+ visit_info1.url_id, visit_info2.visit_time + TimeDelta::FromDays(1), 1,
+ ui::PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED |
+ ui::PAGE_TRANSITION_CHAIN_START |
+ ui::PAGE_TRANSITION_CHAIN_END),
+ 0, true);
visit_info6.visit_id = 6;
std::vector<VisitRow> test_visit_rows;
@@ -367,13 +369,13 @@ TEST_F(VisitDatabaseTest, GetAllURLIDsForTransition) {
TEST_F(VisitDatabaseTest, VisitSource) {
// Add visits.
- VisitRow visit_info1(111, Time::Now(), 0, ui::PAGE_TRANSITION_LINK, 0);
+ VisitRow visit_info1(111, Time::Now(), 0, ui::PAGE_TRANSITION_LINK, 0, false);
ASSERT_TRUE(AddVisit(&visit_info1, SOURCE_BROWSED));
- VisitRow visit_info2(112, Time::Now(), 1, ui::PAGE_TRANSITION_TYPED, 0);
+ VisitRow visit_info2(112, Time::Now(), 1, ui::PAGE_TRANSITION_TYPED, 0, true);
ASSERT_TRUE(AddVisit(&visit_info2, SOURCE_SYNCED));
- VisitRow visit_info3(113, Time::Now(), 0, ui::PAGE_TRANSITION_TYPED, 0);
+ VisitRow visit_info3(113, Time::Now(), 0, ui::PAGE_TRANSITION_TYPED, 0, true);
ASSERT_TRUE(AddVisit(&visit_info3, SOURCE_EXTENSION));
// Query each visit.
@@ -447,27 +449,27 @@ TEST_F(VisitDatabaseTest, GetHistoryCount) {
// Add 5 visits (3 distinct URLs) for the day before yesterday.
// Whether the URL was browsed on this machine or synced has no effect.
- VisitRow first_day_1(1, now, 0, standard_transition, 0);
+ VisitRow first_day_1(1, now, 0, standard_transition, 0, true);
first_day_1.visit_id = 1;
AddVisit(&first_day_1, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
- VisitRow first_day_2(2, now, 0, standard_transition, 0);
+ VisitRow first_day_2(2, now, 0, standard_transition, 0, true);
first_day_2.visit_id = 2;
AddVisit(&first_day_2, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
- VisitRow first_day_3(1, now, 0, standard_transition, 0);
+ VisitRow first_day_3(1, now, 0, standard_transition, 0, true);
first_day_3.visit_id = 3;
AddVisit(&first_day_3, SOURCE_SYNCED);
now += TimeDelta::FromHours(1);
- VisitRow first_day_4(3, now, 0, standard_transition, 0);
+ VisitRow first_day_4(3, now, 0, standard_transition, 0, true);
first_day_4.visit_id = 4;
AddVisit(&first_day_4, SOURCE_SYNCED);
now += TimeDelta::FromHours(1);
- VisitRow first_day_5(2, now, 0, standard_transition, 0);
+ VisitRow first_day_5(2, now, 0, standard_transition, 0, true);
first_day_5.visit_id = 5;
AddVisit(&first_day_5, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
@@ -476,22 +478,22 @@ TEST_F(VisitDatabaseTest, GetHistoryCount) {
// a user-visible navigation. Of the remaining 3, only 2 are unique.
now = yesterday;
- VisitRow second_day_1(1, now, 0, standard_transition, 0);
+ VisitRow second_day_1(1, now, 0, standard_transition, 0, true);
second_day_1.visit_id = 6;
AddVisit(&second_day_1, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
- VisitRow second_day_2(1, now, 0, standard_transition, 0);
+ VisitRow second_day_2(1, now, 0, standard_transition, 0, true);
second_day_2.visit_id = 7;
AddVisit(&second_day_2, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
- VisitRow second_day_3(2, now, 0, ui::PAGE_TRANSITION_AUTO_SUBFRAME, 0);
+ VisitRow second_day_3(2, now, 0, ui::PAGE_TRANSITION_AUTO_SUBFRAME, 0, false);
second_day_3.visit_id = 8;
AddVisit(&second_day_3, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
- VisitRow second_day_4(3, now, 0, standard_transition, 0);
+ VisitRow second_day_4(3, now, 0, standard_transition, 0, true);
second_day_4.visit_id = 9;
AddVisit(&second_day_4, SOURCE_BROWSED);
now += TimeDelta::FromHours(1);
@@ -568,12 +570,12 @@ TEST_F(VisitDatabaseTest, GetHistoryCount) {
// 24 hours later. The count should be 1, not 2, because the day is longer
// than 24 hours, and the two visits will be regarded as duplicate.
if (!shift_backward.is_null()) {
- VisitRow backward_1(1, shift_backward, 0, standard_transition, 0);
+ VisitRow backward_1(1, shift_backward, 0, standard_transition, 0, true);
backward_1.visit_id = 10;
AddVisit(&backward_1, SOURCE_BROWSED);
- VisitRow backward_2(1, shift_backward + TimeDelta::FromHours(24),
- 0, standard_transition, 0);
+ VisitRow backward_2(1, shift_backward + TimeDelta::FromHours(24), 0,
+ standard_transition, 0, true);
backward_2.visit_id = 11;
AddVisit(&backward_2, SOURCE_BROWSED);
@@ -588,14 +590,15 @@ TEST_F(VisitDatabaseTest, GetHistoryCount) {
// regarded as duplicate in a normal 24 hour day, but in this case the second
// visit is already in the next day.
if (!shift_forward.is_null()) {
- VisitRow forward_1(1, shift_forward, 0, standard_transition, 0);
+ VisitRow forward_1(1, shift_forward, 0, standard_transition, 0, true);
forward_1.visit_id = 12;
AddVisit(&forward_1, SOURCE_BROWSED);
Time almost_24_hours_later = shift_forward +
TimeDelta::FromHours(24) -
TimeDelta::FromMicroseconds(1);
- VisitRow forward_2(1, almost_24_hours_later, 0, standard_transition, 0);
+ VisitRow forward_2(1, almost_24_hours_later, 0, standard_transition, 0,
+ true);
forward_2.visit_id = 13;
AddVisit(&forward_2, SOURCE_BROWSED);
@@ -606,4 +609,89 @@ TEST_F(VisitDatabaseTest, GetHistoryCount) {
}
}
+TEST_F(VisitDatabaseTest, GetGoogleDomainVisitsFromSearchesInRange_NoVisits) {
+ const auto begin_time = base::Time::Now();
+ EXPECT_THAT(GetGoogleDomainVisitsFromSearchesInRange(
+ begin_time, begin_time + base::TimeDelta::FromDays(1)),
+ IsEmpty());
+}
+
+TEST_F(VisitDatabaseTest,
+ GetGoogleDomainVisitsFromSearchesInRange_TwoVistsInRange) {
+ const auto begin_time = base::Time::Now();
+ // Out of range, one hour before begin time.
+ VisitRow row{AddURL(URLRow(GURL("https://www.google.fr/search?q=foo"))),
+ begin_time + base::TimeDelta::FromHours(-1),
+ 0,
+ ui::PageTransitionFromInt(0),
+ 0,
+ false};
+ AddVisit(&row, SOURCE_BROWSED);
+ // In range, exactly begin time.
+ row = {AddURL(URLRow(GURL("https://www.google.com/search?q=foo"))),
+ begin_time,
+ 0,
+ ui::PageTransitionFromInt(0),
+ 0,
+ false};
+ AddVisit(&row, SOURCE_BROWSED);
+ // In range, 23 hours after begin time.
+ row = {AddURL(URLRow(GURL("https://www.google.ch/search?q=foo"))),
+ begin_time + base::TimeDelta::FromHours(23),
+ 0,
+ ui::PageTransitionFromInt(0),
+ 0,
+ false};
+ AddVisit(&row, SOURCE_BROWSED);
+ // Out of range, exactly a day after begin time.
+ row = {AddURL(URLRow(GURL("https://www.google.de/search?q=foo"))),
+ begin_time + base::TimeDelta::FromHours(24),
+ 0,
+ ui::PageTransitionFromInt(0),
+ 0,
+ false};
+ AddVisit(&row, SOURCE_BROWSED);
+
+ EXPECT_THAT(
+ GetGoogleDomainVisitsFromSearchesInRange(
+ begin_time, begin_time + base::TimeDelta::FromDays(1)),
+ ElementsAre(
+ AllOf(Property(&DomainVisit::domain, "www.google.com"),
+ Property(&DomainVisit::visit_time, begin_time)),
+ AllOf(Property(&DomainVisit::domain, "www.google.ch"),
+ Property(&DomainVisit::visit_time,
+ begin_time + base::TimeDelta::FromHours(23)))));
+}
+
+TEST_F(VisitDatabaseTest, GetGoogleDomainVisitsFromSearchesInRange_NotSearch) {
+ const auto begin_time = base::Time::Now();
+ VisitRow row{AddURL(URLRow(GURL("https://www.google.fr/searchin"))),
+ begin_time,
+ 0,
+ ui::PageTransitionFromInt(0),
+ 0,
+ false};
+ AddVisit(&row, SOURCE_BROWSED);
+
+ EXPECT_THAT(GetGoogleDomainVisitsFromSearchesInRange(
+ begin_time, begin_time + base::TimeDelta::FromDays(1)),
+ IsEmpty());
+}
+
+TEST_F(VisitDatabaseTest,
+ GetGoogleDomainVisitsFromSearchesInRange_InvalidGoogleDomain) {
+ const auto begin_time = base::Time::Now();
+ VisitRow row{AddURL(URLRow(GURL("https://www.google.foo/search?q=foo"))),
+ begin_time,
+ 0,
+ ui::PageTransitionFromInt(0),
+ 0,
+ false};
+ AddVisit(&row, SOURCE_BROWSED);
+
+ EXPECT_THAT(GetGoogleDomainVisitsFromSearchesInRange(
+ begin_time, begin_time + base::TimeDelta::FromDays(1)),
+ IsEmpty());
+}
+
} // namespace history
diff --git a/chromium/components/history/core/browser/web_history_service.cc b/chromium/components/history/core/browser/web_history_service.cc
index 6a6ae16bbd1..325566e56eb 100644
--- a/chromium/components/history/core/browser/web_history_service.cc
+++ b/chromium/components/history/core/browser/web_history_service.cc
@@ -379,7 +379,7 @@ std::unique_ptr<base::DictionaryValue> WebHistoryService::ReadResponse(
if (request->GetResponseCode() == net::HTTP_OK) {
std::unique_ptr<base::Value> value =
base::JSONReader::Read(request->GetResponseBody());
- if (value.get() && value.get()->is_dict())
+ if (value && value->is_dict())
result.reset(static_cast<base::DictionaryValue*>(value.release()));
else
DLOG(WARNING) << "Non-JSON response received from history server.";
diff --git a/chromium/components/image_fetcher/core/image_data_fetcher.cc b/chromium/components/image_fetcher/core/image_data_fetcher.cc
index 1ccc3b5cc8a..069e369a778 100644
--- a/chromium/components/image_fetcher/core/image_data_fetcher.cc
+++ b/chromium/components/image_fetcher/core/image_data_fetcher.cc
@@ -109,7 +109,6 @@ void ImageDataFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
&metadata.content_location_header);
success &= (metadata.http_response_code == net::HTTP_OK);
}
- metadata.from_http_cache = source->WasCached();
std::string image_data;
if (success) {
diff --git a/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
index d0ffca406e1..738cc1efb3f 100644
--- a/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
+++ b/chromium/components/image_fetcher/core/image_data_fetcher_unittest.cc
@@ -97,42 +97,6 @@ TEST_F(ImageDataFetcherTest, FetchImageData) {
test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
}
-TEST_F(ImageDataFetcherTest, FetchImageData_FromCache) {
- image_data_fetcher_.FetchImageData(
- GURL(kImageURL),
- base::Bind(&ImageDataFetcherTest::OnImageDataFetched,
- base::Unretained(this)),
- TRAFFIC_ANNOTATION_FOR_TESTS);
-
- RequestMetadata expected_metadata;
- expected_metadata.mime_type = std::string("image/png");
- expected_metadata.http_response_code = net::HTTP_OK;
- expected_metadata.from_http_cache = true;
- EXPECT_CALL(*this, OnImageDataFetched(std::string(kURLResponseData),
- expected_metadata));
-
- // Get and configure the TestURLFetcher.
- net::TestURLFetcher* test_url_fetcher =
- fetcher_factory_.GetFetcherByID(ImageDataFetcher::kFirstUrlFetcherId);
- ASSERT_NE(nullptr, test_url_fetcher);
- test_url_fetcher->set_status(
- net::URLRequestStatus(net::URLRequestStatus::SUCCESS, net::OK));
- test_url_fetcher->SetResponseString(kURLResponseData);
- test_url_fetcher->set_response_code(net::HTTP_OK);
- test_url_fetcher->set_was_cached(true);
-
- std::string raw_header =
- "HTTP/1.1 200 OK\n"
- "Content-type: image/png\n\n";
- std::replace(raw_header.begin(), raw_header.end(), '\n', '\0');
- scoped_refptr<net::HttpResponseHeaders> headers(
- new net::HttpResponseHeaders(raw_header));
- test_url_fetcher->set_response_headers(headers);
-
- // Call the URLFetcher delegate to continue the test.
- test_url_fetcher->delegate()->OnURLFetchComplete(test_url_fetcher);
-}
-
TEST_F(ImageDataFetcherTest, FetchImageData_NotFound) {
image_data_fetcher_.FetchImageData(
GURL(kImageURL),
diff --git a/chromium/components/image_fetcher/core/mock_image_decoder.h b/chromium/components/image_fetcher/core/mock_image_decoder.h
index 739ef65956c..1faeebb76b9 100644
--- a/chromium/components/image_fetcher/core/mock_image_decoder.h
+++ b/chromium/components/image_fetcher/core/mock_image_decoder.h
@@ -13,7 +13,7 @@ namespace image_fetcher {
class MockImageDecoder : public image_fetcher::ImageDecoder {
public:
MockImageDecoder();
- ~MockImageDecoder();
+ ~MockImageDecoder() override;
MOCK_METHOD3(DecodeImage,
void(const std::string& image_data,
const gfx::Size& desired_image_frame_size,
diff --git a/chromium/components/image_fetcher/core/request_metadata.cc b/chromium/components/image_fetcher/core/request_metadata.cc
index 13ffadaa357..9a830226b1f 100644
--- a/chromium/components/image_fetcher/core/request_metadata.cc
+++ b/chromium/components/image_fetcher/core/request_metadata.cc
@@ -7,12 +7,11 @@
namespace image_fetcher {
RequestMetadata::RequestMetadata()
- : http_response_code(RESPONSE_CODE_INVALID), from_http_cache(false) {}
+ : http_response_code(RESPONSE_CODE_INVALID) {}
bool operator==(const RequestMetadata& lhs, const RequestMetadata& rhs) {
return lhs.mime_type == rhs.mime_type &&
lhs.http_response_code == rhs.http_response_code &&
- lhs.from_http_cache == rhs.from_http_cache &&
lhs.content_location_header == rhs.content_location_header;
}
diff --git a/chromium/components/image_fetcher/core/request_metadata.h b/chromium/components/image_fetcher/core/request_metadata.h
index 630ffc6956c..84881c81403 100644
--- a/chromium/components/image_fetcher/core/request_metadata.h
+++ b/chromium/components/image_fetcher/core/request_metadata.h
@@ -23,7 +23,6 @@ struct RequestMetadata {
std::string mime_type;
int http_response_code;
- bool from_http_cache;
std::string content_location_header;
};
diff --git a/chromium/components/image_fetcher/core/request_metadata_unittest.cc b/chromium/components/image_fetcher/core/request_metadata_unittest.cc
index ea0d00f4e5c..c9b93ddcd25 100644
--- a/chromium/components/image_fetcher/core/request_metadata_unittest.cc
+++ b/chromium/components/image_fetcher/core/request_metadata_unittest.cc
@@ -17,8 +17,6 @@ TEST(RequestMetadataTest, Equality) {
lhs.mime_type = "testMimeType";
rhs.http_response_code = 1;
lhs.http_response_code = 1;
- rhs.from_http_cache = true;
- lhs.from_http_cache = true;
lhs.content_location_header = "http://test-location.com/image.png";
rhs.content_location_header = "http://test-location.com/image.png";
@@ -32,8 +30,6 @@ TEST(RequestMetadataTest, NoEquality) {
lhs.mime_type = "testMimeType";
rhs.http_response_code = 1;
lhs.http_response_code = 1;
- rhs.from_http_cache = true;
- lhs.from_http_cache = true;
lhs.content_location_header = "http://test-location.com/image.png";
rhs.content_location_header = "http://test-location.com/image.png";
@@ -45,10 +41,6 @@ TEST(RequestMetadataTest, NoEquality) {
EXPECT_NE(rhs, lhs);
lhs.http_response_code = 1;
- lhs.from_http_cache = false;
- EXPECT_NE(rhs, lhs);
- lhs.from_http_cache = true;
-
lhs.content_location_header = "http://other.test-location.com/image.png";
EXPECT_NE(rhs, lhs);
lhs.content_location_header = "http://test-location.com/image.png";
diff --git a/chromium/components/image_fetcher/ios/webp_decoder_unittest.mm b/chromium/components/image_fetcher/ios/webp_decoder_unittest.mm
index b9c27f6e961..cca0f5d7551 100644
--- a/chromium/components/image_fetcher/ios/webp_decoder_unittest.mm
+++ b/chromium/components/image_fetcher/ios/webp_decoder_unittest.mm
@@ -58,7 +58,7 @@ class WebpDecoderTest : public testing::Test {
NSData* LoadImage(const base::FilePath& filename) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.AppendASCII("components/test/data/webp_transcode")
.Append(filename);
return
diff --git a/chromium/components/infobars/core/confirm_infobar_delegate.cc b/chromium/components/infobars/core/confirm_infobar_delegate.cc
index 16b93e6a30d..e9a01cc4d5a 100644
--- a/chromium/components/infobars/core/confirm_infobar_delegate.cc
+++ b/chromium/components/infobars/core/confirm_infobar_delegate.cc
@@ -19,6 +19,10 @@ InfoBarDelegate::InfoBarAutomationType
return CONFIRM_INFOBAR;
}
+gfx::ElideBehavior ConfirmInfoBarDelegate::GetMessageElideBehavior() const {
+ return gfx::ELIDE_TAIL;
+}
+
int ConfirmInfoBarDelegate::GetButtons() const {
return BUTTON_OK | BUTTON_CANCEL;
}
@@ -54,9 +58,7 @@ bool ConfirmInfoBarDelegate::LinkClicked(WindowOpenDisposition disposition) {
return false;
}
-ConfirmInfoBarDelegate::ConfirmInfoBarDelegate()
- : InfoBarDelegate() {
-}
+ConfirmInfoBarDelegate::ConfirmInfoBarDelegate() {}
bool ConfirmInfoBarDelegate::EqualsDelegate(InfoBarDelegate* delegate) const {
ConfirmInfoBarDelegate* confirm_delegate =
diff --git a/chromium/components/infobars/core/confirm_infobar_delegate.h b/chromium/components/infobars/core/confirm_infobar_delegate.h
index f76d7c19609..8d0a89a2968 100644
--- a/chromium/components/infobars/core/confirm_infobar_delegate.h
+++ b/chromium/components/infobars/core/confirm_infobar_delegate.h
@@ -9,6 +9,7 @@
#include "base/strings/string16.h"
#include "components/infobars/core/infobar_delegate.h"
#include "components/infobars/core/infobar_manager.h"
+#include "ui/gfx/text_constants.h"
#include "url/gurl.h"
namespace infobars {
@@ -33,6 +34,10 @@ class ConfirmInfoBarDelegate : public infobars::InfoBarDelegate {
// Returns the message string to be displayed for the InfoBar.
virtual base::string16 GetMessageText() const = 0;
+ // Returns the elide behavior for the message string.
+ // Not supported on Android.
+ virtual gfx::ElideBehavior GetMessageElideBehavior() const;
+
// Returns the buttons to be shown for this InfoBar.
virtual int GetButtons() const;
diff --git a/chromium/components/infobars/core/infobar_delegate.h b/chromium/components/infobars/core/infobar_delegate.h
index 6e72ea81ed7..7e7857c225c 100644
--- a/chromium/components/infobars/core/infobar_delegate.h
+++ b/chromium/components/infobars/core/infobar_delegate.h
@@ -150,6 +150,7 @@ class InfoBarDelegate {
NEAR_OOM_INFOBAR_ANDROID = 79,
INSTALLABLE_AMBIENT_BADGE_INFOBAR_DELEGATE = 80,
PAGE_LOAD_CAPPING_INFOBAR_DELEGATE = 81,
+ DOWNLOAD_PROGRESS_INFOBAR_ANDROID = 82,
};
// Describes navigation events, used to decide whether infobars should be
diff --git a/chromium/components/infobars/core/simple_alert_infobar_delegate.cc b/chromium/components/infobars/core/simple_alert_infobar_delegate.cc
index 02b942ab1b0..a74326d69de 100644
--- a/chromium/components/infobars/core/simple_alert_infobar_delegate.cc
+++ b/chromium/components/infobars/core/simple_alert_infobar_delegate.cc
@@ -27,8 +27,7 @@ SimpleAlertInfoBarDelegate::SimpleAlertInfoBarDelegate(
const gfx::VectorIcon* vector_icon,
const base::string16& message,
bool auto_expire)
- : ConfirmInfoBarDelegate(),
- infobar_identifier_(infobar_identifier),
+ : infobar_identifier_(infobar_identifier),
vector_icon_(vector_icon),
message_(message),
auto_expire_(auto_expire) {}
diff --git a/chromium/components/invalidation/impl/BUILD.gn b/chromium/components/invalidation/impl/BUILD.gn
index 0e26b79a3aa..274056bee63 100644
--- a/chromium/components/invalidation/impl/BUILD.gn
+++ b/chromium/components/invalidation/impl/BUILD.gn
@@ -27,8 +27,12 @@ static_library("impl") {
"invalidator_storage.h",
"mock_ack_handler.cc",
"mock_ack_handler.h",
+ "per_user_topic_registration_request.cc",
+ "per_user_topic_registration_request.h",
"profile_invalidation_provider.cc",
"profile_invalidation_provider.h",
+ "status.cc",
+ "status.h",
"unacked_invalidation_set.cc",
"unacked_invalidation_set.h",
]
@@ -48,6 +52,8 @@ static_library("impl") {
"//google_apis",
"//jingle:notifier",
"//net:net",
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
# TODO(sync): Remove this (http://crbug.com/133352);
"//third_party/protobuf:protobuf_lite",
@@ -96,16 +102,34 @@ static_library("impl") {
}
}
+source_set("json_unsafe_parser") {
+ testonly = !is_ios
+
+ sources = [
+ "json_unsafe_parser.cc",
+ "json_unsafe_parser.h",
+ ]
+
+ public_deps = [
+ "//base",
+ ]
+}
+
source_set("unit_tests") {
testonly = true
sources = [
"invalidation_logger_unittest.cc",
+ "per_user_topic_registration_request_unittest.cc",
]
deps = [
":impl",
+ ":json_unsafe_parser",
":test_support",
"//base",
+ "//base/test:test_support",
"//components/prefs",
+ "//net:test_support",
+ "//services/network:test_support",
"//testing/gmock",
"//testing/gtest",
]
@@ -237,6 +261,7 @@ if (is_android) {
"//third_party/cacheinvalidation:cacheinvalidation_proto_java",
"//third_party/junit",
]
+ deps += android_extra_test_deps
java_files = [
"android/javatests/src/org/chromium/components/invalidation/InvalidationClientServiceTest.java",
"android/javatests/src/org/chromium/components/invalidation/TestableInvalidationClientService.java",
diff --git a/chromium/components/json_schema/json_schema_validator_unittest.cc b/chromium/components/json_schema/json_schema_validator_unittest.cc
index b37009238f3..19fc6f9b209 100644
--- a/chromium/components/json_schema/json_schema_validator_unittest.cc
+++ b/chromium/components/json_schema/json_schema_validator_unittest.cc
@@ -11,7 +11,7 @@
class JSONSchemaValidatorCPPTest : public JSONSchemaValidatorTestBase {
public:
- JSONSchemaValidatorCPPTest() : JSONSchemaValidatorTestBase() {}
+ JSONSchemaValidatorCPPTest() {}
protected:
void ExpectValid(const std::string& test_source,
diff --git a/chromium/components/json_schema/json_schema_validator_unittest_base.cc b/chromium/components/json_schema/json_schema_validator_unittest_base.cc
index 2a19e710714..ce220dc479a 100644
--- a/chromium/components/json_schema/json_schema_validator_unittest_base.cc
+++ b/chromium/components/json_schema/json_schema_validator_unittest_base.cc
@@ -27,7 +27,7 @@ namespace {
base::Value* LoadValue(const std::string& filename) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
path = path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
@@ -46,7 +46,7 @@ base::Value* LoadValue(const std::string& filename) {
base::Value* LoadValue(const std::string& filename, base::Value::Type type) {
std::unique_ptr<base::Value> result(LoadValue(filename));
- if (!result.get())
+ if (!result)
return nullptr;
if (result->type() != type) {
ADD_FAILURE() << "Expected type " << type << ", got: " << result->type();
diff --git a/chromium/components/keep_alive_registry/keep_alive_registry.cc b/chromium/components/keep_alive_registry/keep_alive_registry.cc
index a01e1035e75..053699b74c3 100644
--- a/chromium/components/keep_alive_registry/keep_alive_registry.cc
+++ b/chromium/components/keep_alive_registry/keep_alive_registry.cc
@@ -81,9 +81,7 @@ bool KeepAliveRegistry::WouldRestartWithout(
}
void KeepAliveRegistry::SetIsShuttingDown(bool value) {
-#if DCHECK_IS_ON()
is_shutting_down_ = value;
-#endif
}
////////////////////////////////////////////////////////////////////////////////
@@ -93,15 +91,14 @@ KeepAliveRegistry::KeepAliveRegistry()
: registered_count_(0), restart_allowed_count_(0) {}
KeepAliveRegistry::~KeepAliveRegistry() {
- DLOG_IF(ERROR, registered_count_ > 0 || registered_keep_alives_.size() > 0)
- << "KeepAliveRegistry not empty at destruction time. State:" << *this;
+ DCHECK_LE(registered_count_, 0) << "KeepAliveRegistry state:" << *this;
+ DCHECK_EQ(registered_keep_alives_.size(), 0u)
+ << "KeepAliveRegistry state:" << *this;
}
void KeepAliveRegistry::Register(KeepAliveOrigin origin,
KeepAliveRestartOption restart) {
-#if DCHECK_IS_ON()
- DCHECK(!is_shutting_down_);
-#endif
+ CHECK(!is_shutting_down_);
bool old_keeping_alive = IsKeepingAlive();
bool old_restart_allowed = IsRestartAllowed();
diff --git a/chromium/components/keep_alive_registry/keep_alive_registry.h b/chromium/components/keep_alive_registry/keep_alive_registry.h
index bcddc1155a5..40d4ed0c059 100644
--- a/chromium/components/keep_alive_registry/keep_alive_registry.h
+++ b/chromium/components/keep_alive_registry/keep_alive_registry.h
@@ -8,7 +8,6 @@
#include <unordered_map>
#include <vector>
-#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
@@ -92,10 +91,8 @@ class KeepAliveRegistry {
// Number of registered keep alives that have KeepAliveRestartOption::ENABLED.
int restart_allowed_count_;
-#if DCHECK_IS_ON()
// Used to guard against registering during shutdown.
bool is_shutting_down_ = false;
-#endif
base::ObserverList<KeepAliveStateObserver> observers_;
diff --git a/chromium/components/keep_alive_registry/keep_alive_types.cc b/chromium/components/keep_alive_registry/keep_alive_types.cc
index 1062a3e0533..25e90258360 100644
--- a/chromium/components/keep_alive_registry/keep_alive_types.cc
+++ b/chromium/components/keep_alive_registry/keep_alive_types.cc
@@ -21,6 +21,8 @@ std::ostream& operator<<(std::ostream& out, const KeepAliveOrigin& origin) {
return out << "BACKGROUND_MODE_MANAGER_STARTUP";
case KeepAliveOrigin::LOGIN_DISPLAY_HOST_WEBUI:
return out << "LOGIN_DISPLAY_HOST_WEBUI";
+ case KeepAliveOrigin::PIN_MIGRATION:
+ return out << "PIN_MIGRATION";
case KeepAliveOrigin::NOTIFICATION:
return out << "NOTIFICATION";
case KeepAliveOrigin::PENDING_NOTIFICATION_CLICK_EVENT:
diff --git a/chromium/components/keep_alive_registry/keep_alive_types.h b/chromium/components/keep_alive_registry/keep_alive_types.h
index 4ebcebb6ab8..ff7f13b58c1 100644
--- a/chromium/components/keep_alive_registry/keep_alive_types.h
+++ b/chromium/components/keep_alive_registry/keep_alive_types.h
@@ -26,6 +26,7 @@ enum class KeepAliveOrigin {
// c/b/chromeos
LOGIN_DISPLAY_HOST_WEBUI,
+ PIN_MIGRATION,
// c/b/notifications
NOTIFICATION,
diff --git a/chromium/components/language/content/browser/BUILD.gn b/chromium/components/language/content/browser/BUILD.gn
index 2930633d3c1..10344f4fee0 100644
--- a/chromium/components/language/content/browser/BUILD.gn
+++ b/chromium/components/language/content/browser/BUILD.gn
@@ -37,6 +37,8 @@ source_set("language_code_locator") {
static_library("browser") {
sources = [
+ "geo_language_model.cc",
+ "geo_language_model.h",
"geo_language_provider.cc",
"geo_language_provider.h",
]
@@ -44,6 +46,7 @@ static_library("browser") {
deps = [
":language_code_locator",
"//base",
+ "//components/language/core/browser:browser",
"//net",
"//services/device/public/mojom",
"//services/service_manager/public/cpp",
@@ -53,8 +56,11 @@ static_library("browser") {
source_set("unit_tests") {
testonly = true
sources = [
+ "geo_language_model_unittest.cc",
"geo_language_provider_unittest.cc",
"language_code_locator_unittest.cc",
+ "test_utils.cc",
+ "test_utils.h",
]
deps = [
":browser",
diff --git a/chromium/components/language/content/browser/geo_language_model.cc b/chromium/components/language/content/browser/geo_language_model.cc
new file mode 100644
index 00000000000..4ed7b5c10c3
--- /dev/null
+++ b/chromium/components/language/content/browser/geo_language_model.cc
@@ -0,0 +1,32 @@
+// 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 "components/language/content/browser/geo_language_model.h"
+
+#include <functional>
+
+#include "components/language/content/browser/geo_language_provider.h"
+
+namespace language {
+
+GeoLanguageModel::GeoLanguageModel(
+ const GeoLanguageProvider* const geo_language_provider)
+ : geo_language_provider_(geo_language_provider) {}
+
+GeoLanguageModel::~GeoLanguageModel() {}
+
+std::vector<LanguageModel::LanguageDetails> GeoLanguageModel::GetLanguages() {
+ const std::vector<std::string>& geo_inferred_languages =
+ geo_language_provider_->CurrentGeoLanguages();
+ std::vector<LanguageDetails> languages(geo_inferred_languages.size());
+
+ std::transform(geo_inferred_languages.begin(), geo_inferred_languages.end(),
+ languages.begin(), [](const std::string& language) {
+ return LanguageModel::LanguageDetails(language, 0.f);
+ });
+
+ return languages;
+}
+
+} // namespace language
diff --git a/chromium/components/language/content/browser/geo_language_model.h b/chromium/components/language/content/browser/geo_language_model.h
new file mode 100644
index 00000000000..1269be7f2e0
--- /dev/null
+++ b/chromium/components/language/content/browser/geo_language_model.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_LANGUAGE_CONTENT_BROWSER_GEO_LANGUAGE_MODEL_H_
+#define COMPONENTS_LANGUAGE_CONTENT_BROWSER_GEO_LANGUAGE_MODEL_H_
+
+#include "base/macros.h"
+#include "components/language/core/browser/language_model.h"
+
+namespace language {
+
+class GeoLanguageProvider;
+
+// A language model that uses the GeoLanguageProvider to determine the
+// languages the user is likely to understand based on their geographic
+// location.
+class GeoLanguageModel : public LanguageModel {
+ public:
+ GeoLanguageModel(const GeoLanguageProvider* const geo_language_provider);
+ ~GeoLanguageModel() override;
+
+ std::vector<LanguageDetails> GetLanguages() override;
+
+ private:
+ // Weak reference to the GeoLanguageProvider supplied to the constructor.
+ // The GeoLanguageProvider is a Singleton so it outlives this object but it
+ // is injected from the creator of this model to make testing easier by
+ // passing in a mock.
+ const GeoLanguageProvider* const geo_language_provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeoLanguageModel);
+};
+
+} // namespace language
+
+#endif // COMPONENTS_LANGUAGE_CONTENT_BROWSER_GEO_LANGUAGE_MODEL_H_
diff --git a/chromium/components/language/content/browser/geo_language_model_unittest.cc b/chromium/components/language/content/browser/geo_language_model_unittest.cc
new file mode 100644
index 00000000000..7c589e5c958
--- /dev/null
+++ b/chromium/components/language/content/browser/geo_language_model_unittest.cc
@@ -0,0 +1,97 @@
+// 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 "components/language/content/browser/geo_language_model.h"
+
+#include "base/macros.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/timer/timer.h"
+#include "components/language/content/browser/geo_language_provider.h"
+#include "components/language/content/browser/test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace language {
+namespace {
+
+// Compares LanguageDetails.
+MATCHER_P(EqualsLd, lang_details, "") {
+ constexpr static float kFloatEps = 0.00001f;
+ return arg.lang_code == lang_details.lang_code &&
+ std::abs(arg.score - lang_details.score) < kFloatEps;
+}
+
+} // namespace
+
+class GeoLanguageModelTest : public testing::Test {
+ public:
+ GeoLanguageModelTest()
+ : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>(
+ base::TestMockTimeTaskRunner::Type::kBoundToThread)),
+ scoped_context_(task_runner_.get()),
+ geo_language_provider_(task_runner_),
+ geo_language_model_(&geo_language_provider_),
+ mock_ip_geo_location_provider_(&mock_geo_location_) {
+ service_manager::mojom::ConnectorRequest request;
+ connector_ = service_manager::Connector::Create(&request);
+ service_manager::Connector::TestApi test_api(connector_.get());
+ test_api.OverrideBinderForTesting(
+ service_manager::Identity(device::mojom::kServiceName),
+ device::mojom::PublicIpAddressGeolocationProvider::Name_,
+ base::BindRepeating(&MockIpGeoLocationProvider::Bind,
+ base::Unretained(&mock_ip_geo_location_provider_)));
+ }
+
+ protected:
+ void StartGeoLanguageProvider() {
+ geo_language_provider_.StartUp(std::move(connector_));
+ }
+
+ void MoveToLocation(float latitude, float longitude) {
+ mock_geo_location_.MoveToLocation(latitude, longitude);
+ }
+
+ const scoped_refptr<base::TestMockTimeTaskRunner>& GetTaskRunner() {
+ return task_runner_;
+ }
+
+ GeoLanguageModel* language_model() { return &geo_language_model_; }
+
+ private:
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ const base::TestMockTimeTaskRunner::ScopedContext scoped_context_;
+
+ GeoLanguageProvider geo_language_provider_;
+ // Object under test.
+ GeoLanguageModel geo_language_model_;
+ MockGeoLocation mock_geo_location_;
+ MockIpGeoLocationProvider mock_ip_geo_location_provider_;
+ std::unique_ptr<service_manager::Connector> connector_;
+};
+
+TEST_F(GeoLanguageModelTest, InsideIndia) {
+ // Setup a random place in Madhya Pradesh, India.
+ MoveToLocation(23.0, 80.0);
+ StartGeoLanguageProvider();
+ const auto task_runner = GetTaskRunner();
+ task_runner->RunUntilIdle();
+
+ EXPECT_THAT(language_model()->GetLanguages(),
+ testing::ElementsAre(
+ EqualsLd(LanguageModel::LanguageDetails("hi", 0.f)),
+ EqualsLd(LanguageModel::LanguageDetails("mr", 0.f)),
+ EqualsLd(LanguageModel::LanguageDetails("ur", 0.f))));
+}
+
+TEST_F(GeoLanguageModelTest, OutsideIndia) {
+ // Setup a random place outside of India.
+ MoveToLocation(0.0, 0.0);
+ StartGeoLanguageProvider();
+ const auto task_runner = GetTaskRunner();
+ task_runner->RunUntilIdle();
+
+ EXPECT_EQ(0UL, language_model()->GetLanguages().size());
+}
+
+} // namespace language
diff --git a/chromium/components/language/content/browser/geo_language_provider.cc b/chromium/components/language/content/browser/geo_language_provider.cc
index 0ee3bbc1c69..c9cf368ae70 100644
--- a/chromium/components/language/content/browser/geo_language_provider.cc
+++ b/chromium/components/language/content/browser/geo_language_provider.cc
@@ -22,8 +22,7 @@ constexpr base::TimeDelta kMinUpdatePeriod = base::TimeDelta::FromDays(1);
} // namespace
GeoLanguageProvider::GeoLanguageProvider()
- : languages_(),
- creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
+ : creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
background_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})) {
@@ -33,8 +32,7 @@ GeoLanguageProvider::GeoLanguageProvider()
GeoLanguageProvider::GeoLanguageProvider(
scoped_refptr<base::SequencedTaskRunner> background_task_runner)
- : languages_(),
- creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
+ : creation_task_runner_(base::SequencedTaskRunnerHandle::Get()),
background_task_runner_(background_task_runner) {
// Constructor is not required to run on |background_task_runner_|:
DETACH_FROM_SEQUENCE(background_sequence_checker_);
diff --git a/chromium/components/language/content/browser/geo_language_provider.h b/chromium/components/language/content/browser/geo_language_provider.h
index 20e04721a14..241fb0b86e8 100644
--- a/chromium/components/language/content/browser/geo_language_provider.h
+++ b/chromium/components/language/content/browser/geo_language_provider.h
@@ -54,6 +54,7 @@ class GeoLanguageProvider {
std::vector<std::string> CurrentGeoLanguages() const;
private:
+ friend class GeoLanguageModelTest;
friend class GeoLanguageProviderTest;
GeoLanguageProvider();
diff --git a/chromium/components/language/content/browser/geo_language_provider_unittest.cc b/chromium/components/language/content/browser/geo_language_provider_unittest.cc
index 3b4f71ffc80..8bdd456920b 100644
--- a/chromium/components/language/content/browser/geo_language_provider_unittest.cc
+++ b/chromium/components/language/content/browser/geo_language_provider_unittest.cc
@@ -11,74 +11,9 @@
#include "base/macros.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/timer/timer.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/device/public/mojom/constants.mojom.h"
-#include "services/device/public/mojom/geolocation.mojom.h"
-#include "services/device/public/mojom/public_ip_address_geolocation_provider.mojom.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "components/language/content/browser/test_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace {
-
-// Mock impl of mojom::Geolocation that allows tests to control the returned
-// location.
-class MockGeoLocation : public device::mojom::Geolocation {
- public:
- MockGeoLocation() : binding_(this) {}
- // device::mojom::Geolocation implementation:
- void SetHighAccuracy(bool high_accuracy) override {}
- void QueryNextPosition(QueryNextPositionCallback callback) override {
- ++query_next_position_called_times_;
- std::move(callback).Run(position_.Clone());
- }
-
- void BindGeoLocation(device::mojom::GeolocationRequest request) {
- binding_.Bind(std::move(request));
- }
-
- void MoveToLocation(float latitude, float longitude) {
- position_.latitude = latitude;
- position_.longitude = longitude;
- }
-
- int query_next_position_called_times() const {
- return query_next_position_called_times_;
- }
-
- private:
- int query_next_position_called_times_ = 0;
- device::mojom::Geoposition position_;
- mojo::Binding<device::mojom::Geolocation> binding_;
-};
-
-// Mock impl of mojom::PublicIpAddressGeolocationProvider that binds Geolocation
-// to testing impl.
-class MockIpGeoLocationProvider
- : public device::mojom::PublicIpAddressGeolocationProvider {
- public:
- explicit MockIpGeoLocationProvider(MockGeoLocation* mock_geo_location)
- : mock_geo_location_(mock_geo_location), binding_(this) {}
-
- void Bind(mojo::ScopedMessagePipeHandle handle) {
- binding_.Bind(device::mojom::PublicIpAddressGeolocationProviderRequest(
- std::move(handle)));
- }
-
- void CreateGeolocation(
- const net::MutablePartialNetworkTrafficAnnotationTag& /* unused */,
- device::mojom::GeolocationRequest request) override {
- mock_geo_location_->BindGeoLocation(std::move(request));
- }
-
- private:
- MockGeoLocation* mock_geo_location_;
-
- mojo::Binding<device::mojom::PublicIpAddressGeolocationProvider> binding_;
-};
-
-} // namespace
-
namespace language {
class GeoLanguageProviderTest : public testing::Test {
diff --git a/chromium/components/language/content/browser/test_utils.cc b/chromium/components/language/content/browser/test_utils.cc
new file mode 100644
index 00000000000..ca19235cb4d
--- /dev/null
+++ b/chromium/components/language/content/browser/test_utils.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/language/content/browser/test_utils.h"
+
+namespace language {
+
+MockGeoLocation::MockGeoLocation() : binding_(this) {}
+MockGeoLocation::~MockGeoLocation() {}
+
+void MockGeoLocation::SetHighAccuracy(bool high_accuracy) {}
+
+void MockGeoLocation::QueryNextPosition(QueryNextPositionCallback callback) {
+ ++query_next_position_called_times_;
+ std::move(callback).Run(position_.Clone());
+}
+
+void MockGeoLocation::BindGeoLocation(
+ device::mojom::GeolocationRequest request) {
+ binding_.Bind(std::move(request));
+}
+
+void MockGeoLocation::MoveToLocation(float latitude, float longitude) {
+ position_.latitude = latitude;
+ position_.longitude = longitude;
+}
+
+MockIpGeoLocationProvider::MockIpGeoLocationProvider(
+ MockGeoLocation* mock_geo_location)
+ : mock_geo_location_(mock_geo_location), binding_(this) {}
+
+MockIpGeoLocationProvider::~MockIpGeoLocationProvider() {}
+
+void MockIpGeoLocationProvider::Bind(mojo::ScopedMessagePipeHandle handle) {
+ binding_.Bind(device::mojom::PublicIpAddressGeolocationProviderRequest(
+ std::move(handle)));
+}
+
+void MockIpGeoLocationProvider::CreateGeolocation(
+ const net::MutablePartialNetworkTrafficAnnotationTag& /* unused */,
+ device::mojom::GeolocationRequest request) {
+ mock_geo_location_->BindGeoLocation(std::move(request));
+}
+
+} // namespace language
diff --git a/chromium/components/language/content/browser/test_utils.h b/chromium/components/language/content/browser/test_utils.h
new file mode 100644
index 00000000000..a0c9593e49e
--- /dev/null
+++ b/chromium/components/language/content/browser/test_utils.h
@@ -0,0 +1,62 @@
+// 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 COMPONENTS_LANGUAGE_CONTENT_BROWSER_TEST_UTILS_H_
+#define COMPONENTS_LANGUAGE_CONTENT_BROWSER_TEST_UTILS_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/public_ip_address_geolocation_provider.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+
+namespace language {
+
+// Mock impl of mojom::Geolocation that allows tests to control the returned
+// location.
+class MockGeoLocation : public device::mojom::Geolocation {
+ public:
+ MockGeoLocation();
+ ~MockGeoLocation() override;
+
+ // device::mojom::Geolocation implementation:
+ void SetHighAccuracy(bool high_accuracy) override;
+ void QueryNextPosition(QueryNextPositionCallback callback) override;
+
+ void BindGeoLocation(device::mojom::GeolocationRequest request);
+ void MoveToLocation(float latitude, float longitude);
+
+ int query_next_position_called_times() const {
+ return query_next_position_called_times_;
+ }
+
+ private:
+ int query_next_position_called_times_ = 0;
+ device::mojom::Geoposition position_;
+ mojo::Binding<device::mojom::Geolocation> binding_;
+};
+
+// Mock impl of mojom::PublicIpAddressGeolocationProvider that binds Geolocation
+// to testing impl.
+class MockIpGeoLocationProvider
+ : public device::mojom::PublicIpAddressGeolocationProvider {
+ public:
+ explicit MockIpGeoLocationProvider(MockGeoLocation* mock_geo_location);
+ ~MockIpGeoLocationProvider() override;
+
+ void Bind(mojo::ScopedMessagePipeHandle handle);
+
+ void CreateGeolocation(
+ const net::MutablePartialNetworkTrafficAnnotationTag& /* unused */,
+ device::mojom::GeolocationRequest request) override;
+
+ private:
+ MockGeoLocation* mock_geo_location_;
+ mojo::Binding<device::mojom::PublicIpAddressGeolocationProvider> binding_;
+};
+
+} // namespace language
+
+#endif // COMPONENTS_LANGUAGE_CONTENT_BROWSER_TEST_UTILS_H_
diff --git a/chromium/components/language/core/browser/heuristic_language_model.cc b/chromium/components/language/core/browser/heuristic_language_model.cc
index 306cb72a2e6..98b4fe95197 100644
--- a/chromium/components/language/core/browser/heuristic_language_model.cc
+++ b/chromium/components/language/core/browser/heuristic_language_model.cc
@@ -37,9 +37,6 @@ constexpr char kUlpReadingKey[] = "reading";
} // namespace
-const base::Feature kUseHeuristicLanguageModel{
- "UseHeuristicLanguageModel", base::FEATURE_DISABLED_BY_DEFAULT};
-
bool HasBaseAndRegion(const std::string& lang, std::string* const base) {
const std::vector<base::StringPiece> tokens = base::SplitStringPiece(
lang, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
diff --git a/chromium/components/language/core/browser/heuristic_language_model.h b/chromium/components/language/core/browser/heuristic_language_model.h
index 916c2524801..c86baec754f 100644
--- a/chromium/components/language/core/browser/heuristic_language_model.h
+++ b/chromium/components/language/core/browser/heuristic_language_model.h
@@ -13,7 +13,6 @@
#include "components/language/core/browser/url_language_histogram.h"
namespace base {
-struct Feature;
class DictionaryValue;
} // namespace base
@@ -21,10 +20,6 @@ class PrefService;
namespace language {
-// The feature that enables the heuristic model of user language. If disabled,
-// the baseline model is used instead.
-extern const base::Feature kUseHeuristicLanguageModel;
-
// A model that heuristically assigns scores to languages that appear in the
// user's various language lists.
//
diff --git a/chromium/components/language/core/common/BUILD.gn b/chromium/components/language/core/common/BUILD.gn
index 6d8f155e37b..7ee80f982d7 100644
--- a/chromium/components/language/core/common/BUILD.gn
+++ b/chromium/components/language/core/common/BUILD.gn
@@ -4,6 +4,8 @@
static_library("common") {
sources = [
+ "language_experiments.cc",
+ "language_experiments.h",
"locale_util.cc",
"locale_util.h",
]
diff --git a/chromium/components/language/core/common/language_experiments.cc b/chromium/components/language/core/common/language_experiments.cc
new file mode 100644
index 00000000000..779cfae8261
--- /dev/null
+++ b/chromium/components/language/core/common/language_experiments.cc
@@ -0,0 +1,71 @@
+// 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 "components/language/core/common/language_experiments.h"
+
+#include <map>
+#include <string>
+
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace language {
+// Features:
+const base::Feature kUseHeuristicLanguageModel{
+ "UseHeuristicLanguageModel", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kOverrideTranslateTriggerInIndia{
+ "OverrideTranslateTriggerInIndia", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Params:
+const char kBackoffThresholdKey[] = "backoff_threshold";
+const char kOverrideModelKey[] = "override_model";
+const char kEnforceRankerKey[] = "enforce_ranker";
+const char kOverrideModelHeuristicValue[] = "heuristic";
+const char kOverrideModelGeoValue[] = "geo";
+
+OverrideLanguageModel GetOverrideLanguageModel() {
+ std::map<std::string, std::string> params;
+ bool should_override_model = base::GetFieldTrialParamsByFeature(
+ kOverrideTranslateTriggerInIndia, &params);
+
+ if (base::FeatureList::IsEnabled(kUseHeuristicLanguageModel) ||
+ (should_override_model &&
+ params[kOverrideModelKey] == kOverrideModelHeuristicValue)) {
+ return OverrideLanguageModel::HEURISTIC;
+ }
+
+ if (should_override_model &&
+ params[kOverrideModelKey] == kOverrideModelGeoValue) {
+ return OverrideLanguageModel::GEO;
+ }
+
+ return OverrideLanguageModel::DEFAULT;
+}
+
+bool ShouldForceTriggerTranslateOnEnglishPages(int force_trigger_count) {
+ return base::FeatureList::IsEnabled(kOverrideTranslateTriggerInIndia) &&
+ !IsForceTriggerBackoffThresholdReached(force_trigger_count);
+}
+
+bool ShouldPreventRankerEnforcementInIndia(int force_trigger_count) {
+ std::map<std::string, std::string> params;
+ return ShouldForceTriggerTranslateOnEnglishPages(force_trigger_count) &&
+ base::GetFieldTrialParamsByFeature(kOverrideTranslateTriggerInIndia,
+ &params) &&
+ params[kEnforceRankerKey] == "false";
+}
+
+bool IsForceTriggerBackoffThresholdReached(int force_trigger_count) {
+ int threshold;
+ std::map<std::string, std::string> params;
+ if (!base::GetFieldTrialParamsByFeature(kOverrideTranslateTriggerInIndia,
+ &params) ||
+ !base::StringToInt(params[kBackoffThresholdKey], &threshold)) {
+ return false;
+ }
+
+ return force_trigger_count >= threshold;
+}
+
+} // namespace language
diff --git a/chromium/components/language/core/common/language_experiments.h b/chromium/components/language/core/common/language_experiments.h
new file mode 100644
index 00000000000..43b06650e90
--- /dev/null
+++ b/chromium/components/language/core/common/language_experiments.h
@@ -0,0 +1,54 @@
+// 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 COMPONENTS_LANGUAGE_CORE_COMMON_LANGUAGE_EXPERIMENTS_H_
+#define COMPONENTS_LANGUAGE_CORE_COMMON_LANGUAGE_EXPERIMENTS_H_
+
+#include "base/feature_list.h"
+
+namespace language {
+
+// The feature that enables the heuristic model of user language. If disabled,
+// the baseline model is used instead.
+extern const base::Feature kUseHeuristicLanguageModel;
+
+// This feature controls the activation of the experiment to trigger Translate
+// in India on English pages independent of the user's UI language. The params
+// associated with the experiment dictate which model is used to determine the
+// target language. This can in turn be overriden by the Heuristic Model
+// experiment.
+extern const base::Feature kOverrideTranslateTriggerInIndia;
+extern const char kOverrideModelKey[];
+extern const char kEnforceRankerKey[];
+extern const char kOverrideModelHeuristicValue[];
+extern const char kOverrideModelGeoValue[];
+
+enum class OverrideLanguageModel {
+ DEFAULT,
+ HEURISTIC,
+ GEO,
+};
+
+// Returns which language model to use depending on the state of all Language
+// experiments.
+OverrideLanguageModel GetOverrideLanguageModel();
+
+// Returns true if kOverrideTranslateTriggerInIndia is enabled, false otherwise.
+// It should be interpreted as a signal to trigger translate UI on English
+// pages, even when the UI language is English.
+bool ShouldForceTriggerTranslateOnEnglishPages(int force_trigger_count);
+
+// Returns true if kOverrideTranslateTriggerInIndia is enabled and the current
+// experiment group specifies the param to enforce Ranker decisions, false
+// otherwise.
+bool ShouldPreventRankerEnforcementInIndia(int force_trigger_count);
+
+// Returns true if the user ignored or dismissed a prompt that was displayed
+// because of kOverrideTranslateTriggerInIndia often enough that the experiment
+// should stop being taken into account.
+bool IsForceTriggerBackoffThresholdReached(int force_trigger_count);
+
+} // namespace language
+
+#endif // COMPONENTS_LANGUAGE_CORE_COMMON_LANGUAGE_EXPERIMENTS_H_
diff --git a/chromium/components/leveldb_proto/leveldb_database.cc b/chromium/components/leveldb_proto/leveldb_database.cc
index b87eb064f06..c4fa33ac754 100644
--- a/chromium/components/leveldb_proto/leveldb_database.cc
+++ b/chromium/components/leveldb_proto/leveldb_database.cc
@@ -49,7 +49,7 @@ bool LevelDB::Init(const base::FilePath& database_dir,
open_options_ = options;
if (database_dir.empty()) {
- env_.reset(leveldb_chrome::NewMemEnv(leveldb::Env::Default()));
+ env_ = leveldb_chrome::NewMemEnv("LevelDB");
open_options_.env = env_.get();
}
@@ -100,6 +100,11 @@ bool LevelDB::Save(const base::StringPairs& entries_to_save,
}
bool LevelDB::Load(std::vector<std::string>* entries) {
+ return LoadWithFilter(KeyFilter(), entries);
+}
+
+bool LevelDB::LoadWithFilter(const KeyFilter& filter,
+ std::vector<std::string>* entries) {
DFAKE_SCOPED_LOCK(thread_checker_);
if (!db_)
return false;
@@ -107,6 +112,11 @@ bool LevelDB::Load(std::vector<std::string>* entries) {
leveldb::ReadOptions options;
std::unique_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
for (db_iterator->SeekToFirst(); db_iterator->Valid(); db_iterator->Next()) {
+ if (!filter.is_null()) {
+ leveldb::Slice key_slice = db_iterator->key();
+ if (!filter.Run(std::string(key_slice.data(), key_slice.size())))
+ continue;
+ }
leveldb::Slice value_slice = db_iterator->value();
std::string entry(value_slice.data(), value_slice.size());
entries->push_back(entry);
diff --git a/chromium/components/leveldb_proto/leveldb_database.h b/chromium/components/leveldb_proto/leveldb_database.h
index d5344d81d85..020f21582ea 100644
--- a/chromium/components/leveldb_proto/leveldb_database.h
+++ b/chromium/components/leveldb_proto/leveldb_database.h
@@ -40,6 +40,8 @@ class LevelDB {
explicit LevelDB(const char* client_name);
virtual ~LevelDB();
+ using KeyFilter = base::RepeatingCallback<bool(const std::string& key)>;
+
// Initializes a leveldb with the given options. If |database_dir| is
// empty, this opens an in-memory db.
virtual bool Init(const base::FilePath& database_dir,
@@ -48,6 +50,8 @@ class LevelDB {
virtual bool Save(const base::StringPairs& pairs_to_save,
const std::vector<std::string>& keys_to_remove);
virtual bool Load(std::vector<std::string>* entries);
+ virtual bool LoadWithFilter(const KeyFilter& filter,
+ std::vector<std::string>* entries);
virtual bool LoadKeys(std::vector<std::string>* keys);
virtual bool Get(const std::string& key, bool* found, std::string* entry);
// Close (if currently open) and then destroy (i.e. delete) the database
diff --git a/chromium/components/leveldb_proto/proto_database.h b/chromium/components/leveldb_proto/proto_database.h
index 1d6305c03d4..8dbdedf686d 100644
--- a/chromium/components/leveldb_proto/proto_database.h
+++ b/chromium/components/leveldb_proto/proto_database.h
@@ -11,6 +11,7 @@
#include <vector>
#include "base/callback.h"
+#include "components/leveldb_proto/leveldb_database.h"
#include "third_party/leveldatabase/env_chromium.h"
namespace base {
@@ -59,6 +60,12 @@ class ProtoDatabase {
// when complete.
virtual void LoadEntries(LoadCallback callback) = 0;
+ // Asynchronously loads entries that satisfies the |filter| from the database
+ // and invokes |callback| when complete. The filter will be called on
+ // ProtoDatabase's taskrunner.
+ virtual void LoadEntriesWithFilter(const LevelDB::KeyFilter& filter,
+ LoadCallback callback) = 0;
+
// Asynchronously loads all keys from the database and invokes |callback| with
// those keys when complete.
virtual void LoadKeys(LoadKeysCallback callback) = 0;
diff --git a/chromium/components/leveldb_proto/proto_database_impl.h b/chromium/components/leveldb_proto/proto_database_impl.h
index b7ecf115ee0..a3d236ab787 100644
--- a/chromium/components/leveldb_proto/proto_database_impl.h
+++ b/chromium/components/leveldb_proto/proto_database_impl.h
@@ -14,7 +14,6 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -52,6 +51,9 @@ class ProtoDatabaseImpl : public ProtoDatabase<T> {
std::unique_ptr<KeyVector> keys_to_remove,
typename ProtoDatabase<T>::UpdateCallback callback) override;
void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override;
+ void LoadEntriesWithFilter(
+ const LevelDB::KeyFilter& key_filter,
+ typename ProtoDatabase<T>::LoadCallback callback) override;
void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
void GetEntry(const std::string& key,
typename ProtoDatabase<T>::GetCallback callback) override;
@@ -153,6 +155,7 @@ void UpdateEntriesFromTaskRunner(
template <typename T>
void LoadEntriesFromTaskRunner(LevelDB* database,
+ const LevelDB::KeyFilter& filter,
std::vector<T>* entries,
bool* success) {
DCHECK(success);
@@ -161,7 +164,7 @@ void LoadEntriesFromTaskRunner(LevelDB* database,
entries->clear();
std::vector<std::string> loaded_entries;
- *success = database->Load(&loaded_entries);
+ *success = database->LoadWithFilter(filter, &loaded_entries);
for (const auto& serialized_entry : loaded_entries) {
T entry;
@@ -287,6 +290,13 @@ void ProtoDatabaseImpl<T>::UpdateEntries(
template <typename T>
void ProtoDatabaseImpl<T>::LoadEntries(
typename ProtoDatabase<T>::LoadCallback callback) {
+ LoadEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback));
+}
+
+template <typename T>
+void ProtoDatabaseImpl<T>::LoadEntriesWithFilter(
+ const LevelDB::KeyFilter& key_filter,
+ typename ProtoDatabase<T>::LoadCallback callback) {
DCHECK(thread_checker_.CalledOnValidThread());
bool* success = new bool(false);
@@ -297,7 +307,7 @@ void ProtoDatabaseImpl<T>::LoadEntries(
task_runner_->PostTaskAndReply(
FROM_HERE,
base::BindOnce(LoadEntriesFromTaskRunner<T>, base::Unretained(db_.get()),
- entries_ptr, success),
+ key_filter, entries_ptr, success),
base::BindOnce(RunLoadCallback<T>, std::move(callback),
base::Owned(success), std::move(entries)));
}
diff --git a/chromium/components/leveldb_proto/proto_database_impl_unittest.cc b/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
index f09895e899f..f2f23286b21 100644
--- a/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
+++ b/chromium/components/leveldb_proto/proto_database_impl_unittest.cc
@@ -53,6 +53,8 @@ class MockDB : public LevelDB {
const leveldb_env::Options& options));
MOCK_METHOD2(Save, bool(const KeyValueVector&, const KeyVector&));
MOCK_METHOD1(Load, bool(std::vector<std::string>*));
+ MOCK_METHOD2(LoadWithFilter,
+ bool(const KeyFilter&, std::vector<std::string>*));
MOCK_METHOD3(Get, bool(const std::string&, bool*, std::string*));
MOCK_METHOD0(Destroy, bool());
@@ -116,6 +118,10 @@ Matcher<const Options&> OptionsEq(const Options& expected) {
return MakeMatcher(new OptionsEqMatcher(expected));
}
+bool ZeroFilter(const std::string& key) {
+ return key == "0";
+}
+
} // namespace
EntryMap GetSmallModel() {
@@ -245,7 +251,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBDestroyFailure) {
}
ACTION_P(AppendLoadEntries, model) {
- std::vector<std::string>* output = arg0;
+ std::vector<std::string>* output = arg1;
for (const auto& pair : model)
output->push_back(pair.second.SerializeAsString());
@@ -274,7 +280,8 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadSuccess) {
base::WrapUnique(mock_db), path, CreateSimpleOptions(),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
- EXPECT_CALL(*mock_db, Load(_)).WillOnce(AppendLoadEntries(model));
+ EXPECT_CALL(*mock_db, LoadWithFilter(_, _))
+ .WillOnce(AppendLoadEntries(model));
EXPECT_CALL(caller, LoadCallback1(true, _))
.WillOnce(VerifyLoadEntries(testing::ByRef(model)));
db_->LoadEntries(
@@ -295,7 +302,7 @@ TEST_F(ProtoDatabaseImplTest, TestDBLoadFailure) {
base::WrapUnique(mock_db), path, CreateSimpleOptions(),
base::Bind(&MockDatabaseCaller::InitCallback, base::Unretained(&caller)));
- EXPECT_CALL(*mock_db, Load(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mock_db, LoadWithFilter(_, _)).WillOnce(Return(false));
EXPECT_CALL(caller, LoadCallback1(false, _));
db_->LoadEntries(
base::Bind(&MockDatabaseCaller::LoadCallback, base::Unretained(&caller)));
@@ -346,9 +353,20 @@ TEST_F(ProtoDatabaseImplTest, TestDBGetSuccess) {
base::RunLoop().RunUntilIdle();
}
-TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoadKeys) {
- base::MessageLoop main_loop;
+class ProtoDatabaseImplLevelDBTest : public testing::Test {
+ public:
+ void SetUp() override { main_loop_.reset(new MessageLoop()); }
+
+ void TearDown() override {
+ base::RunLoop().RunUntilIdle();
+ main_loop_.reset();
+ }
+ private:
+ std::unique_ptr<MessageLoop> main_loop_;
+};
+
+TEST_F(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoadKeys) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::Thread db_thread("dbthread");
@@ -677,15 +695,43 @@ void TestLevelDBSaveAndLoad(bool close_after_save) {
ExpectEntryPointersEquals(model, loaded_protos);
}
-TEST(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) {
+TEST_F(ProtoDatabaseImplLevelDBTest, TestDBSaveAndLoad) {
TestLevelDBSaveAndLoad(false);
}
-TEST(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) {
+TEST_F(ProtoDatabaseImplLevelDBTest, TestDBCloseAndReopen) {
TestLevelDBSaveAndLoad(true);
}
-TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
+TEST_F(ProtoDatabaseImplLevelDBTest, TestDBLoadWithFilter) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+
+ EntryMap model = GetSmallModel();
+
+ KeyValueVector save_entries;
+ std::vector<std::string> load_entries;
+ KeyVector remove_keys;
+
+ for (const auto& pair : model) {
+ save_entries.push_back(
+ std::make_pair(pair.second.id(), pair.second.SerializeAsString()));
+ }
+
+ std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
+ EXPECT_TRUE(db->Init(temp_dir.GetPath(), CreateSimpleOptions()));
+ EXPECT_TRUE(db->Save(save_entries, remove_keys));
+
+ EXPECT_TRUE(
+ db->LoadWithFilter(base::BindRepeating(&ZeroFilter), &load_entries));
+
+ EXPECT_EQ(load_entries.size(), 1u);
+ TestProto entry;
+ ASSERT_TRUE(entry.ParseFromString(load_entries[0]));
+ EXPECT_EQ(entry.SerializeAsString(), model["0"].SerializeAsString());
+}
+
+TEST_F(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
@@ -702,7 +748,7 @@ TEST(ProtoDatabaseImplLevelDBTest, TestDBInitFail) {
EXPECT_FALSE(db->Save(save_entries, remove_keys));
}
-TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
+TEST_F(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
std::unique_ptr<LevelDB> db(new LevelDB(kTestLevelDBClientName));
std::vector<std::string> load_entries;
@@ -723,7 +769,7 @@ TEST(ProtoDatabaseImplLevelDBTest, TestMemoryDatabase) {
EXPECT_EQ(1u, second_load_entries.size());
}
-TEST(ProtoDatabaseImplLevelDBTest, TestCorruptDBReset) {
+TEST_F(ProtoDatabaseImplLevelDBTest, TestCorruptDBReset) {
ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
diff --git a/chromium/components/leveldb_proto/testing/fake_db.h b/chromium/components/leveldb_proto/testing/fake_db.h
index 8be2645af7e..d349b316cc6 100644
--- a/chromium/components/leveldb_proto/testing/fake_db.h
+++ b/chromium/components/leveldb_proto/testing/fake_db.h
@@ -40,6 +40,9 @@ class FakeDB : public ProtoDatabase<T> {
std::unique_ptr<std::vector<std::string>> keys_to_remove,
typename ProtoDatabase<T>::UpdateCallback callback) override;
void LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) override;
+ void LoadEntriesWithFilter(
+ const LevelDB::KeyFilter& key_filter,
+ typename ProtoDatabase<T>::LoadCallback callback) override;
void LoadKeys(typename ProtoDatabase<T>::LoadKeysCallback callback) override;
void GetEntry(const std::string& key,
typename ProtoDatabase<T>::GetCallback callback) override;
@@ -118,9 +121,18 @@ void FakeDB<T>::UpdateEntries(
template <typename T>
void FakeDB<T>::LoadEntries(typename ProtoDatabase<T>::LoadCallback callback) {
+ LoadEntriesWithFilter(LevelDB::KeyFilter(), std::move(callback));
+}
+
+template <typename T>
+void FakeDB<T>::LoadEntriesWithFilter(
+ const LevelDB::KeyFilter& key_filter,
+ typename ProtoDatabase<T>::LoadCallback callback) {
std::unique_ptr<std::vector<T>> entries(new std::vector<T>());
- for (const auto& pair : *db_)
- entries->push_back(pair.second);
+ for (const auto& pair : *db_) {
+ if (key_filter.is_null() || key_filter.Run(pair.first))
+ entries->push_back(pair.second);
+ }
load_callback_ =
base::BindOnce(RunLoadCallback, std::move(callback), std::move(entries));
diff --git a/chromium/components/login/BUILD.gn b/chromium/components/login/BUILD.gn
index 00c322080b1..04e3647e353 100644
--- a/chromium/components/login/BUILD.gn
+++ b/chromium/components/login/BUILD.gn
@@ -17,7 +17,7 @@ component("login") {
defines = [ "LOGIN_IMPLEMENTATION" ]
deps = [
- "//components/signin/core/account_id",
+ "//components/account_id",
"//ui/base",
]
diff --git a/chromium/components/login/DEPS b/chromium/components/login/DEPS
index da38c4d0867..f8b770eab05 100644
--- a/chromium/components/login/DEPS
+++ b/chromium/components/login/DEPS
@@ -1,4 +1,4 @@
include_rules = [
- "+components/signin/core/account_id/account_id.h",
+ "+components/account_id/account_id.h",
"+ui/base/l10n"
]
diff --git a/chromium/components/login/base_screen_handler_utils.cc b/chromium/components/login/base_screen_handler_utils.cc
index 03a40a03d64..eff60f90ae9 100644
--- a/chromium/components/login/base_screen_handler_utils.cc
+++ b/chromium/components/login/base_screen_handler_utils.cc
@@ -4,7 +4,7 @@
#include "components/login/base_screen_handler_utils.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
namespace login {
diff --git a/chromium/components/login/base_screen_handler_utils.h b/chromium/components/login/base_screen_handler_utils.h
index e6224fb31dd..dfca5db9ce8 100644
--- a/chromium/components/login/base_screen_handler_utils.h
+++ b/chromium/components/login/base_screen_handler_utils.h
@@ -15,8 +15,8 @@
#include "base/logging.h"
#include "base/strings/string16.h"
#include "base/values.h"
+#include "components/account_id/account_id.h"
#include "components/login/login_export.h"
-#include "components/signin/core/account_id/account_id.h"
namespace login {
diff --git a/chromium/components/login/screens/screen_context_unittest.cc b/chromium/components/login/screens/screen_context_unittest.cc
index 2e5a569e7dc..29f7a837529 100644
--- a/chromium/components/login/screens/screen_context_unittest.cc
+++ b/chromium/components/login/screens/screen_context_unittest.cc
@@ -22,7 +22,7 @@ class ScreenContextTest : public testing::Test {
void TearDown() override {}
protected:
- ScreenContext& context() { return *context_.get(); }
+ ScreenContext& context() { return *context_; }
private:
std::unique_ptr<ScreenContext> context_;
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 0dafa9d1c59..75d36a28d49 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -33,6 +33,8 @@ static_library("metrics") {
"environment_recorder.h",
"execution_phase.cc",
"execution_phase.h",
+ "expired_histogram_util.cc",
+ "expired_histogram_util.h",
"expired_histograms_checker.cc",
"expired_histograms_checker.h",
"field_trials_provider.cc",
@@ -332,6 +334,7 @@ source_set("unit_tests") {
"data_use_tracker_unittest.cc",
"drive_metrics_provider_unittest.cc",
"environment_recorder_unittest.cc",
+ "expired_histograms_checker_unittest.cc",
"field_trials_provider_unittest.cc",
"file_metrics_provider_unittest.cc",
"histogram_encoder_unittest.cc",
diff --git a/chromium/components/metrics/call_stack_profile_collector.cc b/chromium/components/metrics/call_stack_profile_collector.cc
index 3dfb1dedafe..aa127fbf737 100644
--- a/chromium/components/metrics/call_stack_profile_collector.cc
+++ b/chromium/components/metrics/call_stack_profile_collector.cc
@@ -38,9 +38,8 @@ void CallStackProfileCollector::Collect(
return;
CallStackProfileParams params_copy = params;
- params_copy.start_timestamp = start_timestamp;
CallStackProfileMetricsProvider::ReceiveCompletedProfiles(
- &params_copy, std::move(profiles));
+ params_copy, start_timestamp, std::move(profiles));
}
} // namespace metrics
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.cc b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
index f8b22df662f..bce2bbbb871 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
@@ -36,10 +36,6 @@ namespace metrics {
namespace {
-// Interval for periodic (post-startup) sampling, when enabled.
-constexpr base::TimeDelta kPeriodicSamplingInterval =
- base::TimeDelta::FromSeconds(1);
-
// Provide a mapping from the C++ "enum" definition of various process mile-
// stones to the equivalent protobuf "enum" definition. This table-lookup
// conversion allows for the implementation to evolve and still be compatible
@@ -56,30 +52,13 @@ const ProcessPhase
ProcessPhase::SHUTDOWN_START,
};
-// Parameters for UI thread of browser process sampling. Not const since these
-// may be changed when transitioning from start-up profiling to periodic
-// profiling.
-CallStackProfileParams g_ui_thread_sampling_params(
- CallStackProfileParams::BROWSER_PROCESS,
- CallStackProfileParams::MAIN_THREAD,
- CallStackProfileParams::PROCESS_STARTUP,
- CallStackProfileParams::MAY_SHUFFLE);
-
-// Parameters for IO thread of browser process sampling. Not const since these
-// may be changed when transitioning from start-up profiling to periodic
-// profiling.
-CallStackProfileParams g_io_thread_sampling_params(
- CallStackProfileParams::BROWSER_PROCESS,
- CallStackProfileParams::IO_THREAD,
- CallStackProfileParams::PROCESS_STARTUP,
- CallStackProfileParams::MAY_SHUFFLE);
-
// ProfilesState --------------------------------------------------------------
// A set of profiles and the CallStackProfileMetricsProvider state associated
// with them.
struct ProfilesState {
ProfilesState(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
StackSamplingProfiler::CallStackProfiles profiles);
ProfilesState(ProfilesState&&);
ProfilesState& operator=(ProfilesState&&);
@@ -88,6 +67,9 @@ struct ProfilesState {
// CallStackProfileMetricsProvider::GetProfilerCallback().
CallStackProfileParams params;
+ // The time at which the profile collection was started.
+ base::TimeTicks start_timestamp;
+
// The call stack profiles collected by the profiler.
StackSamplingProfiler::CallStackProfiles profiles;
@@ -96,8 +78,11 @@ struct ProfilesState {
};
ProfilesState::ProfilesState(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
StackSamplingProfiler::CallStackProfiles profiles)
- : params(params), profiles(std::move(profiles)) {}
+ : params(params),
+ start_timestamp(start_timestamp),
+ profiles(std::move(profiles)) {}
ProfilesState::ProfilesState(ProfilesState&&) = default;
@@ -141,11 +126,6 @@ class PendingProfiles {
PendingProfiles();
~PendingProfiles();
- // Attemps to merge |profile_state| with existing |to_profile_state|. Returns
- // true if merged.
- bool TryProfileMerge(const ProfilesState& profile_state,
- ProfilesState* to_profile_state);
-
mutable base::Lock lock_;
// If true, profiles provided to CollectProfilesIfCollectionEnabled should be
@@ -198,24 +178,10 @@ void PendingProfiles::CollectProfilesIfCollectionEnabled(
// since the start of collection for this profile.
if (!collection_enabled_ ||
(!last_collection_disable_time_.is_null() &&
- last_collection_disable_time_ >= profiles.params.start_timestamp)) {
+ last_collection_disable_time_ >= profiles.start_timestamp)) {
return;
}
- if (profiles.params.trigger == CallStackProfileParams::PERIODIC_COLLECTION) {
- DCHECK_EQ(1U, profiles.profiles.size());
- profiles.profiles[0].sampling_period = kPeriodicSamplingInterval;
- // Use the process uptime as the collection time to indicate when this
- // profile was collected. This is useful to account for uptime bias during
- // analysis.
- profiles.profiles[0].profile_duration = internal::GetUptime();
- }
-
- for (ProfilesState& profile_state : profiles_) {
- if (TryProfileMerge(profiles, &profile_state))
- return;
- }
-
profiles_.push_back(std::move(profiles));
}
@@ -236,102 +202,21 @@ PendingProfiles::PendingProfiles() : collection_enabled_(true) {}
PendingProfiles::~PendingProfiles() {}
-bool PendingProfiles::TryProfileMerge(const ProfilesState& profile_state,
- ProfilesState* to_profile_state) {
- if (profile_state.profiles.empty() || to_profile_state->profiles.empty())
- return false;
-
- const auto& params = profile_state.params;
- // Only periodic profile merging is supported.
- if (params.trigger != CallStackProfileParams::PERIODIC_COLLECTION)
- return false;
-
- const auto& to_params = to_profile_state->params;
- if (to_params.trigger != params.trigger ||
- to_params.process != params.process ||
- to_params.thread != params.thread) {
- return false;
- }
- DCHECK_EQ(1U, profile_state.profiles.size());
- DCHECK_EQ(1U, to_profile_state->profiles.size());
- const auto& from_profile = profile_state.profiles[0];
- auto* to_profile = &to_profile_state->profiles[0];
-
- // Create a mapping from module id to index.
- std::map<std::string, size_t> module_id_to_index;
- for (const auto& module : to_profile->modules) {
- module_id_to_index.insert(
- std::make_pair(module.id, module_id_to_index.size()));
- }
-
- for (const auto& base_sample : from_profile.samples) {
- // Make a copy of the sample so we can update its module indexes.
- StackSamplingProfiler::Sample sample = base_sample;
- for (StackSamplingProfiler::Frame& frame : sample.frames) {
- if (frame.module_index ==
- base::StackSamplingProfiler::Frame::kUnknownModuleIndex) {
- continue;
- }
- const auto& module = from_profile.modules[frame.module_index];
- auto it = module_id_to_index.find(module.id);
- if (it == module_id_to_index.end()) {
- module_id_to_index.insert(
- std::make_pair(module.id, module_id_to_index.size()));
- to_profile->modules.push_back(module);
- frame.module_index = module_id_to_index.size() - 1;
- } else {
- frame.module_index = it->second;
- }
- }
-
- to_profile->samples.push_back(sample);
- }
-
- // Update the profile duration, which stores uptime for periodic profiles.
- to_profile->profile_duration = from_profile.profile_duration;
-
- return true;
-}
-
// Functions to process completed profiles ------------------------------------
// Will be invoked on either the main thread or the profiler's thread. Provides
// the profiles to PendingProfiles to append, if the collecting state allows.
-base::Optional<StackSamplingProfiler::SamplingParams>
-ReceiveCompletedProfilesImpl(
- CallStackProfileParams* params,
+void ReceiveCompletedProfilesImpl(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
StackSamplingProfiler::CallStackProfiles profiles) {
PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled(
- ProfilesState(*params, std::move(profiles)));
-
- // Now, schedule periodic sampling every 1s, if enabled by trial.
- // TODO(asvitkine): Support periodic sampling for non-browser processes.
- // TODO(asvitkine): In the future, we may want to have finer grained control
- // over this, for example ending sampling after some amount of time.
- if (CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled() &&
- params->process == CallStackProfileParams::BROWSER_PROCESS &&
- (params->thread == CallStackProfileParams::MAIN_THREAD ||
- params->thread == CallStackProfileParams::IO_THREAD)) {
- params->trigger = CallStackProfileParams::PERIODIC_COLLECTION;
- params->start_timestamp = base::TimeTicks::Now();
-
- StackSamplingProfiler::SamplingParams sampling_params;
- sampling_params.initial_delay = kPeriodicSamplingInterval;
- sampling_params.bursts = 1;
- sampling_params.samples_per_burst = 1;
- // Below are unused:
- sampling_params.burst_interval = base::TimeDelta::FromMilliseconds(0);
- sampling_params.sampling_interval = base::TimeDelta::FromMilliseconds(0);
- return sampling_params;
- }
- return base::Optional<StackSamplingProfiler::SamplingParams>();
+ ProfilesState(params, start_timestamp, std::move(profiles)));
}
// Invoked on an arbitrary thread. Ignores the provided profiles.
-base::Optional<StackSamplingProfiler::SamplingParams> IgnoreCompletedProfiles(
- StackSamplingProfiler::CallStackProfiles profiles) {
- return base::Optional<StackSamplingProfiler::SamplingParams>();
-}
+void IgnoreCompletedProfiles(
+ StackSamplingProfiler::CallStackProfiles profiles) {}
// Functions to encode protobufs ----------------------------------------------
@@ -513,36 +398,6 @@ SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
} // namespace
-namespace internal {
-
-base::TimeDelta GetUptime() {
- static base::Time process_creation_time;
-// base::CurrentProcessInfo::CreationTime() is only defined on some platforms.
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) || \
- defined(OS_LINUX)
- if (process_creation_time.is_null())
- process_creation_time = base::CurrentProcessInfo::CreationTime();
-#else
- NOTREACHED();
-#endif
- DCHECK(!process_creation_time.is_null());
- return base::Time::Now() - process_creation_time;
-}
-
-StackSamplingProfiler::CompletedCallback GetProfilerCallback(
- CallStackProfileParams* params) {
- // Ignore the profiles if the collection is disabled. If the collection state
- // changes while collecting, this will be detected by the callback and
- // profiles will be ignored at that point.
- if (!PendingProfiles::GetInstance()->IsCollectionEnabled())
- return base::Bind(&IgnoreCompletedProfiles);
-
- params->start_timestamp = base::TimeTicks::Now();
- return base::Bind(&ReceiveCompletedProfilesImpl, params);
-}
-
-} // namespace internal
-
// CallStackProfileMetricsProvider --------------------------------------------
const base::Feature CallStackProfileMetricsProvider::kEnableReporting = {
@@ -556,49 +411,23 @@ CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {
StackSamplingProfiler::CompletedCallback
CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess(
- CallStackProfileParams* params) {
- return internal::GetProfilerCallback(params);
-}
-
-StackSamplingProfiler::CompletedCallback CallStackProfileMetricsProvider::
- GetProfilerCallbackForBrowserProcessUIThreadStartup() {
- return internal::GetProfilerCallback(&g_ui_thread_sampling_params);
-}
+ const CallStackProfileParams& params) {
+ // Ignore the profiles if the collection is disabled. If the collection state
+ // changes while collecting, this will be detected by the callback and
+ // profiles will be ignored at that point.
+ if (!PendingProfiles::GetInstance()->IsCollectionEnabled())
+ return base::Bind(&IgnoreCompletedProfiles);
-StackSamplingProfiler::CompletedCallback CallStackProfileMetricsProvider::
- GetProfilerCallbackForBrowserProcessIOThreadStartup() {
- return internal::GetProfilerCallback(&g_io_thread_sampling_params);
+ return base::Bind(&ReceiveCompletedProfilesImpl, params,
+ base::TimeTicks::Now());
}
// static
void CallStackProfileMetricsProvider::ReceiveCompletedProfiles(
- CallStackProfileParams* params,
+ const CallStackProfileParams& params,
+ base::TimeTicks profile_start_time,
base::StackSamplingProfiler::CallStackProfiles profiles) {
- ReceiveCompletedProfilesImpl(params, std::move(profiles));
-}
-
-// static
-bool CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled() {
- // Ensure FeatureList has been initialized before calling into an API that
- // calls base::FeatureList::IsEnabled() internally. While extremely unlikely,
- // it is possible that the profiler callback and therefore this function get
- // called before FeatureList initialization (e.g. if machine was suspended).
- //
- // The result is cached in a static to avoid a shutdown hang calling into the
- // API while FieldTrialList is being destroyed. See also the comment below in
- // Init().
- static const bool is_enabled = base::FeatureList::GetInstance() != nullptr &&
- base::GetFieldTrialParamByFeatureAsBool(
- kEnableReporting, "periodic", false);
- return is_enabled;
-}
-
-void CallStackProfileMetricsProvider::Init() {
- // IsPeriodicSamplingEnabled() caches the result in a local static, so that
- // future calls will return it directly. Calling it in Init() will cache the
- // result, which will ensure we won't call into FieldTrialList during
- // shutdown which can hang if it's in the middle of being destroyed.
- CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled();
+ ReceiveCompletedProfilesImpl(params, profile_start_time, std::move(profiles));
}
void CallStackProfileMetricsProvider::OnRecordingEnabled() {
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.h b/chromium/components/metrics/call_stack_profile_metrics_provider.h
index a6a1ca5a222..f995a9a411b 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.h
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.h
@@ -18,21 +18,6 @@ namespace metrics {
class ChromeUserMetricsExtension;
-// Internal to expose functions for testing.
-namespace internal {
-
-// Returns the process uptime as a TimeDelta.
-base::TimeDelta GetUptime();
-
-// Get a callback for use with StackSamplingProfiler that provides completed
-// profiles to this object. The callback should be immediately passed to the
-// StackSamplingProfiler, and should not be reused between
-// StackSamplingProfilers. This function may be called on any thread.
-base::StackSamplingProfiler::CompletedCallback GetProfilerCallback(
- CallStackProfileParams* params);
-
-} // namespace internal
-
// Performs metrics logging for the stack sampling profiler.
class CallStackProfileMetricsProvider : public MetricsProvider {
public:
@@ -57,35 +42,18 @@ class CallStackProfileMetricsProvider : public MetricsProvider {
// parameters for general browser process sampling. The callback should be
// immediately passed to the StackSamplingProfiler, and should not be reused.
static base::StackSamplingProfiler::CompletedCallback
- GetProfilerCallbackForBrowserProcess(CallStackProfileParams* params);
-
- // Returns a callback for use with StackSamplingProfiler that sets up
- // parameters for UI thread of browser process startup sampling. The callback
- // should be immediately passed to the StackSamplingProfiler, and should not
- // be reused.
- static base::StackSamplingProfiler::CompletedCallback
- GetProfilerCallbackForBrowserProcessUIThreadStartup();
-
- // Returns a callback for use with StackSamplingProfiler that sets up
- // parameters for IO thread of browser process startup sampling. The callback
- // should be immediately passed to the StackSamplingProfiler, and should not
- // be reused.
- static base::StackSamplingProfiler::CompletedCallback
- GetProfilerCallbackForBrowserProcessIOThreadStartup();
+ GetProfilerCallbackForBrowserProcess(const CallStackProfileParams& params);
// Provides completed stack profiles to the metrics provider. Intended for use
// when receiving profiles over IPC. In-process StackSamplingProfiler users
// should instead use a variant of GetProfilerCallback*(). |profiles| is not
// const& because it must be passed with std::move.
static void ReceiveCompletedProfiles(
- CallStackProfileParams* params,
+ const CallStackProfileParams& params,
+ base::TimeTicks profile_start_time,
base::StackSamplingProfiler::CallStackProfiles profiles);
- // Whether periodic sampling is enabled via a trial.
- static bool IsPeriodicSamplingEnabled();
-
// MetricsProvider:
- void Init() override;
void OnRecordingEnabled() override;
void OnRecordingDisabled() override;
void ProvideCurrentSessionData(
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
index 68b2dd62859..c4777110ef4 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
@@ -129,8 +129,10 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
~CallStackProfileMetricsProviderTest() override {}
// Utility function to append profiles to the metrics provider.
- void AppendProfiles(CallStackProfileParams* params, Profiles profiles) {
- internal::GetProfilerCallback(params).Run(std::move(profiles));
+ void AppendProfiles(const CallStackProfileParams& params, Profiles profiles) {
+ CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess(
+ params)
+ .Run(std::move(profiles));
}
void VerifyProfileProto(const ExpectedProtoProfile& expected,
@@ -342,7 +344,7 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
provider.ProvideCurrentSessionData(&uma_proto);
@@ -426,7 +428,7 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
provider.ProvideCurrentSessionData(&uma_proto);
@@ -512,7 +514,7 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::PRESERVE_ORDER);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
provider.ProvideCurrentSessionData(&uma_proto);
@@ -556,7 +558,7 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
provider.ProvideCurrentSessionData(&uma_proto);
@@ -589,7 +591,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
provider.ProvideCurrentSessionData(&uma_proto);
@@ -619,7 +621,7 @@ TEST_F(CallStackProfileMetricsProviderTest,
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
@@ -646,7 +648,7 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
CallStackProfileParams::MAIN_THREAD,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&params, std::move(profiles));
+ AppendProfiles(params, std::move(profiles));
ChromeUserMetricsExtension uma_proto;
provider.ProvideCurrentSessionData(&uma_proto);
@@ -664,7 +666,8 @@ TEST_F(CallStackProfileMetricsProviderTest,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
base::StackSamplingProfiler::CompletedCallback callback =
- internal::GetProfilerCallback(&params);
+ CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess(
+ params);
provider.OnRecordingDisabled();
Profiles profiles = ProfilesFactory()
@@ -690,7 +693,8 @@ TEST_F(CallStackProfileMetricsProviderTest,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
base::StackSamplingProfiler::CompletedCallback callback =
- internal::GetProfilerCallback(&params);
+ CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess(
+ params);
provider.OnRecordingDisabled();
provider.OnRecordingEnabled();
@@ -717,7 +721,8 @@ TEST_F(CallStackProfileMetricsProviderTest,
CallStackProfileParams::PROCESS_STARTUP,
CallStackProfileParams::MAY_SHUFFLE);
base::StackSamplingProfiler::CompletedCallback callback =
- internal::GetProfilerCallback(&params);
+ CallStackProfileMetricsProvider::GetProfilerCallbackForBrowserProcess(
+ params);
provider.OnRecordingEnabled();
Profiles profiles = ProfilesFactory()
@@ -732,310 +737,4 @@ TEST_F(CallStackProfileMetricsProviderTest,
EXPECT_EQ(0, uma_proto.sampled_profile_size());
}
-// Only certain platforms support GetUptime() which is used both by the test
-// and the code being tested.
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) || \
- defined(OS_LINUX)
-#define MAYBE_PeriodicProfiles PeriodicProfiles
-#else
-#define MAYBE_PeriodicProfiles DISABLED_PeriodicProfiles
-#endif
-TEST_F(CallStackProfileMetricsProviderTest, MAYBE_PeriodicProfiles) {
- const uintptr_t module_base_address = 0x1000;
- const char* module_name = "ABCD";
-
-#if defined(OS_WIN)
- uint64_t module_md5 = 0x46C3E4166659AC02ULL;
- base::FilePath module_path(L"c:\\some\\path\\to\\chrome.exe");
-#else
- uint64_t module_md5 = 0x554838A8451AC36CULL;
- base::FilePath module_path("/some/path/to/chrome");
-#endif
-
- Profiles profiles =
- ProfilesFactory()
- .NewProfile(100, 10)
- .DefineModule(module_name, module_path, module_base_address)
-
- .AddMilestone(0)
- .NewSample()
- .AddFrame(0, module_base_address + 0x10)
- .NewSample()
- .AddFrame(0, module_base_address + 0x20)
- .NewSample()
- .AddFrame(0, module_base_address + 0x10)
- .NewSample()
- .AddFrame(0, module_base_address + 0x10)
-
- .AddMilestone(1)
- .NewSample()
- .AddFrame(0, module_base_address + 0x10)
- .NewSample()
- .AddFrame(0, module_base_address + 0x20)
- .NewSample()
- .AddFrame(0, module_base_address + 0x10)
- .NewSample()
- .AddFrame(0, module_base_address + 0x10)
-
- .Build();
-
- const ExpectedProtoModule expected_proto_modules[] = {
- {module_name, module_md5, module_base_address},
- };
-
- const ExpectedProtoEntry expected_proto_entries[] = {
- {0, 0x10}, {0, 0x20},
- };
- const ExpectedProtoSample expected_proto_samples[] = {
- {1, &expected_proto_entries[0], 1, 3},
- {0, &expected_proto_entries[1], 1, 1},
- {2, &expected_proto_entries[0], 1, 3},
- {0, &expected_proto_entries[1], 1, 1},
- };
-
- ExpectedProtoProfile expected_proto_profiles[] = {
- {
- 0, // Will be updated below.
- 1000, // Based on kPeriodicSamplingInterval in the .cc.
- expected_proto_modules, arraysize(expected_proto_modules),
- expected_proto_samples, arraysize(expected_proto_samples),
- },
- };
-
- ASSERT_EQ(arraysize(expected_proto_profiles), profiles.size());
-
- CallStackProfileMetricsProvider provider;
- provider.OnRecordingEnabled();
- CallStackProfileParams params(CallStackProfileParams::BROWSER_PROCESS,
- CallStackProfileParams::MAIN_THREAD,
- CallStackProfileParams::PERIODIC_COLLECTION,
- CallStackProfileParams::MAY_SHUFFLE);
- const base::TimeDelta min_expected_uptime = internal::GetUptime();
- AppendProfiles(&params, std::move(profiles));
- const base::TimeDelta max_expected_uptime = internal::GetUptime();
-
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideCurrentSessionData(&uma_proto);
-
- ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
- uma_proto.sampled_profile().size());
-
- // We expect duration_ms to be the process uptime. Check that it's within the
- // min/max boundary values that were retrieved earlier. Then, set the value
- // in |expected_proto_profiles| to be the actual value so it matches below.
- const int32_t profile_duration_ms =
- uma_proto.sampled_profile(0).call_stack_profile().profile_duration_ms();
- EXPECT_GE(profile_duration_ms, min_expected_uptime.InMilliseconds());
- EXPECT_LE(profile_duration_ms, max_expected_uptime.InMilliseconds());
- expected_proto_profiles[0].duration_ms = profile_duration_ms;
-
- for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) {
- SCOPED_TRACE("profile " + base::NumberToString(p));
- VerifyProfileProto(expected_proto_profiles[p],
- uma_proto.sampled_profile().Get(p));
- EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
- uma_proto.sampled_profile(p).trigger_event());
- }
-}
-
-// Only certain platforms support GetUptime() which is used by the code
-// being tested.
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) || \
- defined(OS_LINUX)
-#define MAYBE_PeriodicProfileMerging PeriodicProfileMerging
-#else
-#define MAYBE_PeriodicProfileMerging DISABLED_PeriodicProfileMerging
-#endif
-TEST_F(CallStackProfileMetricsProviderTest, MAYBE_PeriodicProfileMerging) {
- const char* moduleA_name = "ABCD";
- const uintptr_t moduleA_base_address = 0x1000;
- const char* moduleB_name = "BEEF";
- const uintptr_t moduleB_base_address = 0x2000;
-
-#if defined(OS_WIN)
- uint64_t moduleA_md5 = 0x46C3E4166659AC02ULL;
- base::FilePath moduleA_path(L"c:\\some\\path\\to\\chrome.exe");
- uint64_t moduleB_md5 = 0x7E2B8BFDDEAE1ABAULL;
- base::FilePath moduleB_path(L"c:\\some\\path\\to\\third_party.dll");
-#else
- uint64_t moduleA_md5 = 0x554838A8451AC36CULL;
- base::FilePath moduleA_path("/some/path/to/chrome");
- uint64_t moduleB_md5 = 0x843661148659C9F8ULL;
- base::FilePath moduleB_path("/some/path/to/third_party.so");
-#endif
-
- Profiles startup_profiles =
- ProfilesFactory()
- .NewProfile(100, 10)
- .DefineModule(moduleA_name, moduleA_path, moduleA_base_address)
- .DefineModule(moduleB_name, moduleB_path, moduleB_base_address)
-
- .AddMilestone(0)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x10)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x20)
- .NewSample()
- .AddFrame(1, moduleB_base_address + 0x40)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x20)
-
- .Build();
-
- // Provide periodic profiles in two separate sets, as expected by provider.
- Profiles periodic1_profiles =
- ProfilesFactory()
- .NewProfile(100, 10)
- .DefineModule(moduleA_name, moduleA_path, moduleA_base_address)
-
- .AddMilestone(0)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x10)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x20)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x30)
-
- .Build();
-
- Profiles periodic1_profiles2 =
- ProfilesFactory()
- .NewProfile(100, 10)
- .DefineModule(moduleB_name, moduleB_path, moduleB_base_address)
- .DefineModule(moduleA_name, moduleA_path, moduleA_base_address)
-
- .AddMilestone(0)
- .NewSample()
- .AddFrame(1, moduleA_base_address + 0x10)
- .NewSample()
- .AddFrame(0, moduleB_base_address + 0x15)
- .NewSample()
- .AddFrame(1, moduleA_base_address + 0x20)
-
- .Build();
-
- // Periodic samples for a different thread that should not be merged.
- Profiles periodic2_profiles =
- ProfilesFactory()
- .NewProfile(100, 10)
- .DefineModule(moduleA_name, moduleA_path, moduleA_base_address)
- .DefineModule(moduleB_name, moduleB_path, moduleB_base_address)
-
- .AddMilestone(0)
- .NewSample()
- .AddFrame(0, moduleA_base_address + 0x10)
- .NewSample()
- .AddFrame(1, moduleB_base_address + 0x15)
-
- .Build();
-
- const ExpectedProtoModule expected_proto_modules[] = {
- {moduleA_name, moduleA_md5, moduleA_base_address},
- {moduleB_name, moduleB_md5, moduleB_base_address},
- };
-
- // Expected startup samples.
- const ExpectedProtoEntry expected_startup_proto_entries[] = {
- {0, 0x10}, {0, 0x20}, {1, 0x40},
- };
- const ExpectedProtoSample expected_startup_proto_samples[] = {
- {1, &expected_startup_proto_entries[0], 1, 1},
- {0, &expected_startup_proto_entries[1], 1, 2},
- {0, &expected_startup_proto_entries[2], 1, 1},
- };
-
- // Expected periodic UI thread samples.
- const ExpectedProtoEntry expected_periodic1_proto_entries[] = {
- {0, 0x10}, {0, 0x20}, {0, 0x30}, {1, 0x15},
- };
- const ExpectedProtoSample expected_periodic1_proto_samples[] = {
- {1, &expected_periodic1_proto_entries[0], 1, 2},
- {0, &expected_periodic1_proto_entries[1], 1, 2},
- {0, &expected_periodic1_proto_entries[2], 1, 1},
- {0, &expected_periodic1_proto_entries[3], 1, 1},
- };
-
- // Expected periodic IO thread samples.
- const ExpectedProtoEntry expected_periodic2_proto_entries[] = {
- {0, 0x10}, {1, 0x15},
- };
- const ExpectedProtoSample expected_periodic2_proto_samples[] = {
- {1, &expected_periodic2_proto_entries[0], 1, 1},
- {0, &expected_periodic2_proto_entries[1], 1, 1},
- };
-
- ExpectedProtoProfile expected_proto_profiles[] = {
- // Startup profile:
- {
- 100, 10, expected_proto_modules, arraysize(expected_proto_modules),
- expected_startup_proto_samples,
- arraysize(expected_startup_proto_samples),
- },
- // Periodic profile, process1:
- {
- 0, // Will be updated below.
- 1000, // Based on kPeriodicSamplingInterval in the .cc.
- expected_proto_modules, arraysize(expected_proto_modules),
- expected_periodic1_proto_samples,
- arraysize(expected_periodic1_proto_samples),
- },
- // Periodic profile, process2:
- {
- 0, // Will be updated below.
- 1000, // Based on kPeriodicSamplingInterval in the .cc.
- expected_proto_modules, arraysize(expected_proto_modules),
- expected_periodic2_proto_samples,
- arraysize(expected_periodic2_proto_samples),
- },
- };
-
- CallStackProfileMetricsProvider provider;
- provider.OnRecordingEnabled();
-
- CallStackProfileParams startup_params(CallStackProfileParams::BROWSER_PROCESS,
- CallStackProfileParams::MAIN_THREAD,
- CallStackProfileParams::PROCESS_STARTUP,
- CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&startup_params, std::move(startup_profiles));
-
- CallStackProfileParams periodic1_params(
- CallStackProfileParams::BROWSER_PROCESS,
- CallStackProfileParams::MAIN_THREAD,
- CallStackProfileParams::PERIODIC_COLLECTION,
- CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&periodic1_params, std::move(periodic1_profiles));
- AppendProfiles(&periodic1_params, std::move(periodic1_profiles2));
-
- CallStackProfileParams periodic2_params(
- CallStackProfileParams::BROWSER_PROCESS,
- CallStackProfileParams::IO_THREAD,
- CallStackProfileParams::PERIODIC_COLLECTION,
- CallStackProfileParams::MAY_SHUFFLE);
- AppendProfiles(&periodic2_params, std::move(periodic2_profiles));
-
- ChromeUserMetricsExtension uma_proto;
- provider.ProvideCurrentSessionData(&uma_proto);
-
- ASSERT_EQ(static_cast<int>(arraysize(expected_proto_profiles)),
- uma_proto.sampled_profile().size());
-
- expected_proto_profiles[1].duration_ms =
- uma_proto.sampled_profile(1).call_stack_profile().profile_duration_ms();
- expected_proto_profiles[2].duration_ms =
- uma_proto.sampled_profile(2).call_stack_profile().profile_duration_ms();
-
- for (size_t p = 0; p < arraysize(expected_proto_profiles); ++p) {
- SCOPED_TRACE("profile " + base::NumberToString(p));
- VerifyProfileProto(expected_proto_profiles[p],
- uma_proto.sampled_profile().Get(p));
- if (p == 0) {
- EXPECT_EQ(SampledProfile::PROCESS_STARTUP,
- uma_proto.sampled_profile(p).trigger_event());
- } else {
- EXPECT_EQ(SampledProfile::PERIODIC_COLLECTION,
- uma_proto.sampled_profile(p).trigger_event());
- }
- }
-}
-
} // namespace metrics
diff --git a/chromium/components/metrics/call_stack_profile_params.h b/chromium/components/metrics/call_stack_profile_params.h
index 5aecf65b07d..05e4203fed0 100644
--- a/chromium/components/metrics/call_stack_profile_params.h
+++ b/chromium/components/metrics/call_stack_profile_params.h
@@ -85,12 +85,6 @@ struct CallStackProfileParams {
// Whether to preserve sample ordering.
SampleOrderingSpec ordering_spec;
-
- // The time at which the CallStackProfileMetricsProvider became aware of the
- // request for profiling. In particular, this is when callback was requested
- // via CallStackProfileMetricsProvider::GetProfilerCallback(). Used to
- // determine if collection was disabled during the collection of the profile.
- base::TimeTicks start_timestamp;
};
} // namespace metrics
diff --git a/chromium/components/metrics/child_call_stack_profile_collector.cc b/chromium/components/metrics/child_call_stack_profile_collector.cc
index 71ed56cae72..978ecd7382c 100644
--- a/chromium/components/metrics/child_call_stack_profile_collector.cc
+++ b/chromium/components/metrics/child_call_stack_profile_collector.cc
@@ -40,11 +40,11 @@ ChildCallStackProfileCollector::~ChildCallStackProfileCollector() {}
base::StackSamplingProfiler::CompletedCallback
ChildCallStackProfileCollector::GetProfilerCallback(
- const CallStackProfileParams& params) {
+ const CallStackProfileParams& params,
+ base::TimeTicks profile_start_time) {
return base::Bind(&ChildCallStackProfileCollector::Collect,
// This class has lazy instance lifetime.
- base::Unretained(this), params,
- base::TimeTicks::Now());
+ base::Unretained(this), params, profile_start_time);
}
void ChildCallStackProfileCollector::SetParentProfileCollector(
@@ -67,16 +67,13 @@ void ChildCallStackProfileCollector::SetParentProfileCollector(
profiles_.clear();
}
-base::Optional<base::StackSamplingProfiler::SamplingParams>
-ChildCallStackProfileCollector::Collect(
+void ChildCallStackProfileCollector::Collect(
const CallStackProfileParams& params,
base::TimeTicks start_timestamp,
std::vector<CallStackProfile> profiles) {
// Impl function is used as it needs to PostTask() to itself on a different
// thread - which only works with a void return value.
CollectImpl(params, start_timestamp, std::move(profiles));
- // Empty return value indicates that collection should not be re-started.
- return base::Optional<base::StackSamplingProfiler::SamplingParams>();
}
void ChildCallStackProfileCollector::CollectImpl(
diff --git a/chromium/components/metrics/child_call_stack_profile_collector.h b/chromium/components/metrics/child_call_stack_profile_collector.h
index 5cf08794fb6..a829f51911a 100644
--- a/chromium/components/metrics/child_call_stack_profile_collector.h
+++ b/chromium/components/metrics/child_call_stack_profile_collector.h
@@ -55,7 +55,8 @@ class ChildCallStackProfileCollector {
// StackSamplingProfiler, and should not be reused between
// StackSamplingProfilers. This function may be called on any thread.
base::StackSamplingProfiler::CompletedCallback GetProfilerCallback(
- const CallStackProfileParams& params);
+ const CallStackProfileParams& params,
+ base::TimeTicks profile_start_time);
// Sets the CallStackProfileCollector interface from |parent_collector|. This
// function MUST be invoked exactly once, regardless of whether
@@ -92,10 +93,9 @@ class ChildCallStackProfileCollector {
using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
- base::Optional<base::StackSamplingProfiler::SamplingParams> Collect(
- const CallStackProfileParams& params,
- base::TimeTicks start_timestamp,
- std::vector<CallStackProfile> profiles);
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ std::vector<CallStackProfile> profiles);
void CollectImpl(const CallStackProfileParams& params,
base::TimeTicks start_timestamp,
diff --git a/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
index 5040843191a..8bf1c5b7ca8 100644
--- a/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
+++ b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
@@ -60,7 +60,8 @@ class ChildCallStackProfileCollectorTest : public testing::Test {
base::StackSamplingProfiler::CallStackProfiles profiles;
for (size_t i = 0; i < profile_count; ++i)
profiles.push_back(base::StackSamplingProfiler::CallStackProfile());
- child_collector_.GetProfilerCallback(params).Run(std::move(profiles));
+ child_collector_.GetProfilerCallback(params, base::TimeTicks::Now())
+ .Run(std::move(profiles));
}
const std::vector<ChildCallStackProfileCollector::ProfilesState>&
diff --git a/chromium/components/metrics/drive_metrics_provider.cc b/chromium/components/metrics/drive_metrics_provider.cc
index badab8443cc..7f50c2b7b0a 100644
--- a/chromium/components/metrics/drive_metrics_provider.cc
+++ b/chromium/components/metrics/drive_metrics_provider.cc
@@ -65,7 +65,7 @@ void DriveMetricsProvider::QuerySeekPenalty(
DCHECK(response);
base::FilePath path;
- if (!PathService::Get(path_service_key, &path))
+ if (!base::PathService::Get(path_service_key, &path))
return;
base::TimeTicks start = base::TimeTicks::Now();
diff --git a/chromium/components/metrics/drive_metrics_provider_win.cc b/chromium/components/metrics/drive_metrics_provider_win.cc
index 04647a9d41b..6c1334e217c 100644
--- a/chromium/components/metrics/drive_metrics_provider_win.cc
+++ b/chromium/components/metrics/drive_metrics_provider_win.cc
@@ -34,7 +34,7 @@ bool DriveMetricsProvider::HasSeekPenalty(const base::FilePath& path,
BOOL success = DeviceIoControl(
volume.GetPlatformFile(), IOCTL_STORAGE_QUERY_PROPERTY, &query,
- sizeof(query), &result, sizeof(result), &bytes_returned, NULL);
+ sizeof(query), &result, sizeof(result), &bytes_returned, nullptr);
if (success == FALSE || bytes_returned < sizeof(result))
return false;
diff --git a/chromium/components/metrics/expired_histogram_util.cc b/chromium/components/metrics/expired_histogram_util.cc
new file mode 100644
index 00000000000..17844e77213
--- /dev/null
+++ b/chromium/components/metrics/expired_histogram_util.cc
@@ -0,0 +1,34 @@
+// 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 "components/metrics/expired_histogram_util.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/statistics_recorder.h"
+#include "components/metrics/expired_histograms_checker.h"
+
+namespace metrics {
+namespace {
+
+const base::Feature kExpiredHistogramLogicFeature{
+ "ExpiredHistogramLogic", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::FeatureParam<std::string> kWhitelistParam{
+ &kExpiredHistogramLogicFeature, "whitelist", ""};
+
+} // namespace
+
+void EnableExpiryChecker(const uint64_t* expired_histograms_hashes,
+ size_t num_expired_histograms) {
+ DCHECK(base::FeatureList::GetInstance());
+ if (base::FeatureList::IsEnabled(kExpiredHistogramLogicFeature)) {
+ base::StatisticsRecorder::SetRecordChecker(
+ std::make_unique<ExpiredHistogramsChecker>(expired_histograms_hashes,
+ num_expired_histograms,
+ kWhitelistParam.Get()));
+ }
+}
+
+} // namespace metrics \ No newline at end of file
diff --git a/chromium/components/metrics/expired_histogram_util.h b/chromium/components/metrics/expired_histogram_util.h
new file mode 100644
index 00000000000..cf6c455ed93
--- /dev/null
+++ b/chromium/components/metrics/expired_histogram_util.h
@@ -0,0 +1,21 @@
+// 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 COMPONENTS_METRICS_EXPIRED_HISTOGRAM_UTIL_H_
+#define COMPONENTS_METRICS_EXPIRED_HISTOGRAM_UTIL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace metrics {
+
+// Enables histogram expiry checker if it is enabled by field trial. Histogram
+// expiry is disbaled by default so that unit tests don't fail unexpectedly when
+// a histogram expires.
+void EnableExpiryChecker(const uint64_t* expired_histograms_hashes,
+ size_t num_expired_histograms);
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_EXPIRED_HISTOGRAM_UTIL_H_ \ No newline at end of file
diff --git a/chromium/components/metrics/expired_histograms_checker.cc b/chromium/components/metrics/expired_histograms_checker.cc
index 2eb14e7c1b7..d1d3ecb67f5 100644
--- a/chromium/components/metrics/expired_histograms_checker.cc
+++ b/chromium/components/metrics/expired_histograms_checker.cc
@@ -5,17 +5,37 @@
#include "components/metrics/expired_histograms_checker.h"
#include <algorithm>
+#include <vector>
+
+#include "base/metrics/metrics_hashes.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/stl_util.h"
+#include "base/strings/string_split.h"
namespace metrics {
-ExpiredHistogramsChecker::ExpiredHistogramsChecker(const uint64_t* array,
- size_t size)
- : array_(array), size_(size) {}
+ExpiredHistogramsChecker::ExpiredHistogramsChecker(
+ const uint64_t* array,
+ size_t size,
+ const std::string& whitelist_str)
+ : array_(array), size_(size) {
+ InitWhitelist(whitelist_str);
+}
ExpiredHistogramsChecker::~ExpiredHistogramsChecker() {}
bool ExpiredHistogramsChecker::ShouldRecord(uint64_t histogram_hash) const {
+ // If histogram is whitelisted then it should always be recorded.
+ if (base::ContainsKey(whitelist_, histogram_hash))
+ return true;
return !std::binary_search(array_, array_ + size_, histogram_hash);
}
+void ExpiredHistogramsChecker::InitWhitelist(const std::string& whitelist_str) {
+ std::vector<base::StringPiece> whitelist_names = base::SplitStringPiece(
+ whitelist_str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ for (base::StringPiece name : whitelist_names)
+ whitelist_.insert(base::HashMetricName(name));
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/expired_histograms_checker.h b/chromium/components/metrics/expired_histograms_checker.h
index 66834c836e4..b3ca4a7612a 100644
--- a/chromium/components/metrics/expired_histograms_checker.h
+++ b/chromium/components/metrics/expired_histograms_checker.h
@@ -6,9 +6,11 @@
#define COMPONENTS_METRICS_EXPIRED_HISTOGRAMS_CHECKER_H_
#include <stdint.h>
+#include <set>
#include "base/macros.h"
#include "base/metrics/record_histogram_checker.h"
+#include "base/strings/string_piece.h"
namespace metrics {
@@ -16,17 +18,31 @@ namespace metrics {
// to avoid recording expired metrics.
class ExpiredHistogramsChecker final : public base::RecordHistogramChecker {
public:
- // Takes sorted in nondecreasing order array of histogram hashes and its size.
- ExpiredHistogramsChecker(const uint64_t* array, size_t size);
+ // Takes sorted in nondecreasing order array of histogram hashes, its size and
+ // list of whitelisted histogram names concatenated as a comma-separated
+ // string.
+ ExpiredHistogramsChecker(const uint64_t* array,
+ size_t size,
+ const std::string& whitelist_str);
~ExpiredHistogramsChecker() override;
// Checks if the given |histogram_hash| corresponds to an expired histogram.
bool ShouldRecord(uint64_t histogram_hash) const override;
private:
+ // Initializes the |whitelist_| array of histogram hashes that should be
+ // recorded regardless of their expiration.
+ void InitWhitelist(const std::string& whitelist_str);
+
+ // Array of expired histogram hashes.
const uint64_t* const array_;
+
+ // Size of the |array_|.
const size_t size_;
+ // List of expired histogram hashes that should be recorded.
+ std::set<uint64_t> whitelist_;
+
DISALLOW_COPY_AND_ASSIGN(ExpiredHistogramsChecker);
};
diff --git a/chromium/components/metrics/expired_histograms_checker_unittest.cc b/chromium/components/metrics/expired_histograms_checker_unittest.cc
new file mode 100644
index 00000000000..13aa77d87f2
--- /dev/null
+++ b/chromium/components/metrics/expired_histograms_checker_unittest.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/expired_histograms_checker.h"
+
+#include "base/metrics/metrics_hashes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+TEST(ExpiredHistogramsCheckerTests, BasicTest) {
+ uint64_t expired_hashes[] = {1, 2, 3};
+ size_t size = 3;
+ std::string whitelist_str = "";
+ ExpiredHistogramsChecker checker(expired_hashes, size, whitelist_str);
+
+ EXPECT_TRUE(checker.ShouldRecord(0));
+ EXPECT_FALSE(checker.ShouldRecord(3));
+}
+
+TEST(ExpiredHistogramsCheckerTests, WhitelistTest) {
+ std::string hist1 = "hist1";
+ std::string hist2 = "hist2";
+ std::string hist3 = "hist3";
+ std::string hist4 = "hist4";
+
+ uint64_t expired_hashes[] = {base::HashMetricName(hist1),
+ base::HashMetricName(hist2)};
+ size_t size = 2;
+ std::string whitelist_str = hist2 + "," + hist4;
+ ExpiredHistogramsChecker checker(expired_hashes, size, whitelist_str);
+
+ EXPECT_FALSE(checker.ShouldRecord(base::HashMetricName(hist1)));
+ EXPECT_TRUE(checker.ShouldRecord(base::HashMetricName(hist2)));
+ EXPECT_TRUE(checker.ShouldRecord(base::HashMetricName(hist3)));
+ EXPECT_TRUE(checker.ShouldRecord(base::HashMetricName(hist4)));
+}
+
+} // namespace metrics \ No newline at end of file
diff --git a/chromium/components/metrics/machine_id_provider_win.cc b/chromium/components/metrics/machine_id_provider_win.cc
index c5176ac1df3..3a2251c3b26 100644
--- a/chromium/components/metrics/machine_id_provider_win.cc
+++ b/chromium/components/metrics/machine_id_provider_win.cc
@@ -32,7 +32,7 @@ std::string MachineIdProvider::GetMachineId() {
// This is fine as we do not support migrating Chrome installs to new drives.
base::FilePath executable_path;
- if (!PathService::Get(base::FILE_EXE, &executable_path)) {
+ if (!base::PathService::Get(base::FILE_EXE, &executable_path)) {
NOTREACHED();
return std::string();
}
@@ -46,13 +46,8 @@ std::string MachineIdProvider::GetMachineId() {
base::FilePath::StringType drive_name = L"\\\\.\\" + path_components[0];
base::win::ScopedHandle drive_handle(
- CreateFile(drive_name.c_str(),
- 0,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- 0,
- NULL));
+ CreateFile(drive_name.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr, OPEN_EXISTING, 0, nullptr));
STORAGE_PROPERTY_QUERY query = {};
query.PropertyId = StorageDeviceProperty;
@@ -61,28 +56,20 @@ std::string MachineIdProvider::GetMachineId() {
// Perform an initial query to get the number of bytes being returned.
DWORD bytes_returned;
STORAGE_DESCRIPTOR_HEADER header = {};
- BOOL status = DeviceIoControl(drive_handle.Get(),
- IOCTL_STORAGE_QUERY_PROPERTY,
- &query,
- sizeof(STORAGE_PROPERTY_QUERY),
- &header,
- sizeof(STORAGE_DESCRIPTOR_HEADER),
- &bytes_returned,
- NULL);
+ BOOL status = DeviceIoControl(
+ drive_handle.Get(), IOCTL_STORAGE_QUERY_PROPERTY, &query,
+ sizeof(STORAGE_PROPERTY_QUERY), &header,
+ sizeof(STORAGE_DESCRIPTOR_HEADER), &bytes_returned, nullptr);
if (!status)
return std::string();
// Query for the actual serial number.
std::vector<int8_t> output_buf(header.Size);
- status = DeviceIoControl(drive_handle.Get(),
- IOCTL_STORAGE_QUERY_PROPERTY,
- &query,
- sizeof(STORAGE_PROPERTY_QUERY),
- &output_buf[0],
- output_buf.size(),
- &bytes_returned,
- NULL);
+ status =
+ DeviceIoControl(drive_handle.Get(), IOCTL_STORAGE_QUERY_PROPERTY, &query,
+ sizeof(STORAGE_PROPERTY_QUERY), &output_buf[0],
+ output_buf.size(), &bytes_returned, nullptr);
if (!status)
return std::string();
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index 09e52b8d9ce..a99d3c7489c 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -173,6 +173,9 @@ void MetricsLog::RecordCoreSystemProfile(MetricsServiceClient* client,
#if defined(OS_ANDROID)
os->set_build_fingerprint(
base::android::BuildInfo::GetInstance()->android_build_fp());
+ std::string package_name = client->GetAppPackageName();
+ if (!package_name.empty() && package_name != "com.android.chrome")
+ system_profile->set_app_package_name(package_name);
#endif
}
diff --git a/chromium/components/metrics/metrics_log_manager.cc b/chromium/components/metrics/metrics_log_manager.cc
index 398b34d597f..d90aa7b3dc4 100644
--- a/chromium/components/metrics/metrics_log_manager.cc
+++ b/chromium/components/metrics/metrics_log_manager.cc
@@ -24,7 +24,7 @@ void MetricsLogManager::BeginLoggingWithLog(std::unique_ptr<MetricsLog> log) {
}
void MetricsLogManager::FinishCurrentLog(MetricsLogStore* log_store) {
- DCHECK(current_log_.get());
+ DCHECK(current_log_);
current_log_->CloseLog();
std::string log_data;
current_log_->GetEncodedLog(&log_data);
@@ -39,12 +39,12 @@ void MetricsLogManager::DiscardCurrentLog() {
}
void MetricsLogManager::PauseCurrentLog() {
- DCHECK(!paused_log_.get());
+ DCHECK(!paused_log_);
paused_log_ = std::move(current_log_);
}
void MetricsLogManager::ResumePausedLog() {
- DCHECK(!current_log_.get());
+ DCHECK(!current_log_);
current_log_ = std::move(paused_log_);
}
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index 6ea1238548a..c4250180a6d 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -156,6 +156,7 @@ TEST_F(MetricsLogTest, BasicRecord) {
#if defined(OS_ANDROID)
system_profile->mutable_os()->set_build_fingerprint(
base::android::BuildInfo::GetInstance()->android_build_fp());
+ system_profile->set_app_package_name("test app");
#endif
// Hard to mock.
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index 492ce966d48..b800b64ccc1 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -563,7 +563,7 @@ void MetricsService::FinishedInitTask() {
state_ = INIT_TASK_DONE;
// Create the initial log.
- if (!initial_metrics_log_.get()) {
+ if (!initial_metrics_log_) {
initial_metrics_log_ = CreateLog(MetricsLog::ONGOING_LOG);
delegating_provider_.OnDidCreateMetricsLog();
}
diff --git a/chromium/components/metrics/metrics_service_client.cc b/chromium/components/metrics/metrics_service_client.cc
index 2ba1dfee2de..a80dc8ad848 100644
--- a/chromium/components/metrics/metrics_service_client.cc
+++ b/chromium/components/metrics/metrics_service_client.cc
@@ -8,7 +8,7 @@
namespace metrics {
-MetricsServiceClient::MetricsServiceClient() : update_running_services_() {}
+MetricsServiceClient::MetricsServiceClient() {}
MetricsServiceClient::~MetricsServiceClient() {}
@@ -36,11 +36,11 @@ std::string MetricsServiceClient::GetInsecureMetricsServerUrl() {
return kNewMetricsServerUrlInsecure;
}
-bool MetricsServiceClient::IsHistorySyncEnabledOnAllProfiles() {
+bool MetricsServiceClient::SyncStateAllowsUkm() {
return false;
}
-bool MetricsServiceClient::IsExtensionSyncEnabledOnAllProfiles() {
+bool MetricsServiceClient::SyncStateAllowsExtensionUkm() {
return false;
}
@@ -58,4 +58,8 @@ void MetricsServiceClient::UpdateRunningServices() {
update_running_services_.Run();
}
+std::string MetricsServiceClient::GetAppPackageName() {
+ return std::string();
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index 84658225d3b..c1bc8285531 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -119,15 +119,21 @@ class MetricsServiceClient {
// Returns whether cellular logic is enabled for metrics reporting.
virtual bool IsUMACellularUploadLogicEnabled();
- // Returns whether history sync is enabled on all active profiles.
- virtual bool IsHistorySyncEnabledOnAllProfiles();
+ // Returns true iff sync is in a state that allows UKM to be enabled.
+ // See //components/ukm/observers/sync_disable_observer.h for details.
+ virtual bool SyncStateAllowsUkm();
- // Returns if extensions sync is enabled on all active profiles.
- virtual bool IsExtensionSyncEnabledOnAllProfiles();
+ // Returns true iff sync is in a state that allows UKM to capture extensions.
+ // See //components/ukm/observers/sync_disable_observer.h for details.
+ virtual bool SyncStateAllowsExtensionUkm();
// Returns whether UKM notification listeners were attached to all profiles.
virtual bool AreNotificationListenersEnabledOnAllProfiles();
+ // Gets the Chrome package name for Android. Returns empty string for other
+ // platforms.
+ virtual std::string GetAppPackageName();
+
// Sets the callback to run MetricsServiceManager::UpdateRunningServices.
void SetUpdateRunningServicesCallback(const base::Closure& callback);
diff --git a/chromium/components/metrics/metrics_service_unittest.cc b/chromium/components/metrics/metrics_service_unittest.cc
index ff7fea35ddf..4350238dcb8 100644
--- a/chromium/components/metrics/metrics_service_unittest.cc
+++ b/chromium/components/metrics/metrics_service_unittest.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/metrics_hashes.h"
#include "base/metrics/statistics_recorder.h"
#include "base/metrics/user_metrics.h"
diff --git a/chromium/components/metrics/metrics_switches.cc b/chromium/components/metrics/metrics_switches.cc
index f380ff8e7ce..38f65aef15a 100644
--- a/chromium/components/metrics/metrics_switches.cc
+++ b/chromium/components/metrics/metrics_switches.cc
@@ -18,5 +18,8 @@ const char kMetricsRecordingOnly[] = "metrics-recording-only";
// known as the Chrome Variations state.
const char kResetVariationState[] = "reset-variation-state";
+// Forces metrics reporting to be enabled.
+const char kForceEnableMetricsReporting[] = "force-enable-metrics-reporting";
+
} // namespace switches
} // namespace metrics
diff --git a/chromium/components/metrics/metrics_switches.h b/chromium/components/metrics/metrics_switches.h
index bfdf4143afd..10e41e94c04 100644
--- a/chromium/components/metrics/metrics_switches.h
+++ b/chromium/components/metrics/metrics_switches.h
@@ -13,6 +13,7 @@ namespace switches {
extern const char kMetricsRecordingOnly[];
extern const char kResetVariationState[];
+extern const char kForceEnableMetricsReporting[];
} // namespace switches
} // namespace metrics
diff --git a/chromium/components/metrics/net/network_metrics_provider.cc b/chromium/components/metrics/net/network_metrics_provider.cc
index 573a69ccf59..412f0afbb40 100644
--- a/chromium/components/metrics/net/network_metrics_provider.cc
+++ b/chromium/components/metrics/net/network_metrics_provider.cc
@@ -214,7 +214,7 @@ void NetworkMetricsProvider::ProvideSystemProfileMetrics(
min_effective_connection_type_ = effective_connection_type_;
max_effective_connection_type_ = effective_connection_type_;
- if (!wifi_access_point_info_provider_.get()) {
+ if (!wifi_access_point_info_provider_) {
#if defined(OS_CHROMEOS)
wifi_access_point_info_provider_.reset(
new WifiAccessPointInfoProviderChromeos());
@@ -404,10 +404,11 @@ void NetworkMetricsProvider::WriteWifiAccessPointProto(
for (const base::StringPiece& oui_str : base::SplitStringPiece(
info.oui_list, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
uint32_t oui;
- if (base::HexStringToUInt(oui_str, &oui))
+ if (base::HexStringToUInt(oui_str, &oui)) {
vendor->add_element_identifier(oui);
- else
- NOTREACHED();
+ } else {
+ DLOG(WARNING) << "Error when parsing OUI list of the WiFi access point";
+ }
}
}
diff --git a/chromium/components/metrics/public/interfaces/BUILD.gn b/chromium/components/metrics/public/interfaces/BUILD.gn
index 8dcb74481ed..2a84979353f 100644
--- a/chromium/components/metrics/public/interfaces/BUILD.gn
+++ b/chromium/components/metrics/public/interfaces/BUILD.gn
@@ -10,7 +10,6 @@ mojom("call_stack_mojo_bindings") {
]
deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
]
}
@@ -22,7 +21,6 @@ mojom("call_stack_mojo_test_bindings") {
deps = [
":call_stack_mojo_bindings",
- "//mojo/common:common_custom_types",
]
}
diff --git a/chromium/components/metrics/reporting_service_unittest.cc b/chromium/components/metrics/reporting_service_unittest.cc
index 71ba69e7df1..fb838cb27df 100644
--- a/chromium/components/metrics/reporting_service_unittest.cc
+++ b/chromium/components/metrics/reporting_service_unittest.cc
@@ -12,7 +12,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/sha1.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
diff --git a/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc b/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc
index 165ad99ba9e..f9fbbba6c44 100644
--- a/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc
+++ b/chromium/components/metrics/single_sample_metrics_factory_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "components/metrics/single_sample_metrics_factory_impl.h"
#include "base/message_loop/message_loop.h"
+#include "base/metrics/dummy_histogram.h"
#include "base/run_loop.h"
#include "base/test/gtest_util.h"
#include "base/test/histogram_tester.h"
@@ -124,12 +125,14 @@ TEST_F(SingleSampleMetricsFactoryImplTest, DefaultSingleSampleMetricWithValue) {
// Verify construction implicitly by requesting a histogram with the same
// parameters; this test relies on the fact that histogram objects are unique
- // per name. Different parameters will result in a nullptr being returned.
- EXPECT_FALSE(base::Histogram::FactoryGet(kMetricName, 1, 3, 3,
- base::HistogramBase::kNoFlags));
- EXPECT_TRUE(base::Histogram::FactoryGet(
- kMetricName, kMin, kMax, kBucketCount,
- base::HistogramBase::kUmaTargetedHistogramFlag));
+ // per name. Different parameters will result in a Dummy histogram returned.
+ EXPECT_EQ(base::DummyHistogram::GetInstance(),
+ base::Histogram::FactoryGet(kMetricName, 1, 3, 3,
+ base::HistogramBase::kNoFlags));
+ EXPECT_NE(base::DummyHistogram::GetInstance(),
+ base::Histogram::FactoryGet(
+ kMetricName, kMin, kMax, kBucketCount,
+ base::HistogramBase::kUmaTargetedHistogramFlag));
}
TEST_F(SingleSampleMetricsFactoryImplTest, MultithreadedMetrics) {
diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc
index 4fbcf10b6ca..375f75c4368 100644
--- a/chromium/components/metrics/stability_metrics_helper.cc
+++ b/chromium/components/metrics/stability_metrics_helper.cc
@@ -60,6 +60,24 @@ void RecordChildKills(RendererType histogram_type) {
histogram_type, RENDERER_TYPE_COUNT);
}
+// Macro for logging the age of a crashed process.
+//
+// Notes:
+// - IMPORTANT: When changing the constants below, please change the names of
+// the histograms logged via UMA_HISTOGRAM_CRASHED_PROCESS_AGE.
+// - 99th percentile of Memory.Experimental.Renderer.Uptime hovers around 17h.
+// - |kCrashedProcessAgeMin| is as low as possible, so that we may with
+// high-confidence categorize crashes that occur during early startup (e.g.
+// crashes that end up with STATUS_DLL_INIT_FAILED or STATUS_DLL_NOT_FOUND).
+// - Note that even with just 50 buckets, we still get narrow and accurate
+// buckets at the lower end: 0ms, 1ms, 2ms, 3ms, 4-5ms, 6-8ms, 9-12ms, ...
+constexpr auto kCrashedProcessAgeMin = base::TimeDelta::FromMilliseconds(1);
+constexpr auto kCrashedProcessAgeMax = base::TimeDelta::FromHours(48);
+constexpr uint32_t kCrashedProcessAgeCount = 50;
+#define UMA_HISTOGRAM_CRASHED_PROCESS_AGE(histogram_name, uptime) \
+ UMA_HISTOGRAM_CUSTOM_TIMES(histogram_name, uptime, kCrashedProcessAgeMin, \
+ kCrashedProcessAgeMax, kCrashedProcessAgeCount)
+
} // namespace
StabilityMetricsHelper::StabilityMetricsHelper(PrefService* local_state)
@@ -184,9 +202,11 @@ void StabilityMetricsHelper::LogLoadStarted(bool is_incognito) {
// might be lost due to a crash :-(.
}
-void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
- base::TerminationStatus status,
- int exit_code) {
+void StabilityMetricsHelper::LogRendererCrash(
+ bool was_extension_process,
+ base::TerminationStatus status,
+ int exit_code,
+ base::Optional<base::TimeDelta> uptime) {
RendererType histogram_type =
was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
@@ -204,11 +224,19 @@ void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
base::UmaHistogramSparse("CrashExitCodes.Extension",
MapCrashExitCodeForHistogram(exit_code));
+ if (uptime.has_value()) {
+ UMA_HISTOGRAM_CRASHED_PROCESS_AGE(
+ "Stability.CrashedProcessAge.Extension", uptime.value());
+ }
} else {
IncrementPrefValue(prefs::kStabilityRendererCrashCount);
base::UmaHistogramSparse("CrashExitCodes.Renderer",
MapCrashExitCodeForHistogram(exit_code));
+ if (uptime.has_value()) {
+ UMA_HISTOGRAM_CRASHED_PROCESS_AGE(
+ "Stability.CrashedProcessAge.Renderer", uptime.value());
+ }
}
UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
diff --git a/chromium/components/metrics/stability_metrics_helper.h b/chromium/components/metrics/stability_metrics_helper.h
index b7105772d95..ddf4d50c597 100644
--- a/chromium/components/metrics/stability_metrics_helper.h
+++ b/chromium/components/metrics/stability_metrics_helper.h
@@ -6,7 +6,9 @@
#define COMPONENTS_METRICS_STABILITY_METRICS_HELPER_H_
#include "base/macros.h"
+#include "base/optional.h"
#include "base/process/kill.h"
+#include "base/time/time.h"
class PrefRegistrySimple;
class PrefService;
@@ -37,7 +39,8 @@ class StabilityMetricsHelper {
// Records a renderer process crash.
void LogRendererCrash(bool was_extension_process,
base::TerminationStatus status,
- int exit_code);
+ int exit_code,
+ base::Optional<base::TimeDelta> uptime);
// Records that a new renderer process was successfully launched.
void LogRendererLaunched(bool was_extension_process);
diff --git a/chromium/components/metrics/stability_metrics_helper_unittest.cc b/chromium/components/metrics/stability_metrics_helper_unittest.cc
index 010aa90499b..bcaa2c1e017 100644
--- a/chromium/components/metrics/stability_metrics_helper_unittest.cc
+++ b/chromium/components/metrics/stability_metrics_helper_unittest.cc
@@ -4,6 +4,8 @@
#include "components/metrics/stability_metrics_helper.h"
+#include <memory>
+
#include "base/macros.h"
#include "base/test/histogram_tester.h"
#include "build/build_config.h"
@@ -65,22 +67,25 @@ TEST_F(StabilityMetricsHelperTest, BrowserChildProcessCrashed) {
TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
StabilityMetricsHelper helper(prefs());
base::HistogramTester histogram_tester;
+ const base::TimeDelta kUptime = base::TimeDelta::FromSeconds(123);
// Crash and abnormal termination should increment renderer crash count.
- helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_CRASHED, 1);
+ helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_CRASHED, 1,
+ kUptime);
helper.LogRendererCrash(false, base::TERMINATION_STATUS_ABNORMAL_TERMINATION,
- 1);
+ 1, kUptime);
// OOM should increment renderer crash count.
- helper.LogRendererCrash(false, base::TERMINATION_STATUS_OOM, 1);
+ helper.LogRendererCrash(false, base::TERMINATION_STATUS_OOM, 1, kUptime);
// Kill does not increment renderer crash count.
- helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_WAS_KILLED,
- 1);
+ helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_WAS_KILLED, 1,
+ kUptime);
// Failed launch increments failed launch count.
- helper.LogRendererCrash(false, base::TERMINATION_STATUS_LAUNCH_FAILED, 1);
+ helper.LogRendererCrash(false, base::TERMINATION_STATUS_LAUNCH_FAILED, 1,
+ kUptime);
metrics::SystemProfileProto system_profile;
@@ -108,6 +113,8 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
RENDERER_TYPE_EXTENSION, 0);
histogram_tester.ExpectBucketCount(
"BrowserRenderProcessHost.ChildLaunchFailureCodes", 1, 1);
+ histogram_tester.ExpectUniqueSample("Stability.CrashedProcessAge.Renderer",
+ kUptime.InMilliseconds(), 3);
}
// Note: ENABLE_EXTENSIONS is set to false in Android
@@ -115,15 +122,18 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
TEST_F(StabilityMetricsHelperTest, LogRendererCrashEnableExtensions) {
StabilityMetricsHelper helper(prefs());
base::HistogramTester histogram_tester;
+ const base::TimeDelta kUptime = base::TimeDelta::FromSeconds(123);
// Crash and abnormal termination should increment extension crash count.
- helper.LogRendererCrash(true, base::TERMINATION_STATUS_PROCESS_CRASHED, 1);
+ helper.LogRendererCrash(true, base::TERMINATION_STATUS_PROCESS_CRASHED, 1,
+ kUptime);
// OOM should increment extension renderer crash count.
- helper.LogRendererCrash(true, base::TERMINATION_STATUS_OOM, 1);
+ helper.LogRendererCrash(true, base::TERMINATION_STATUS_OOM, 1, kUptime);
// Failed launch increments extension failed launch count.
- helper.LogRendererCrash(true, base::TERMINATION_STATUS_LAUNCH_FAILED, 1);
+ helper.LogRendererCrash(true, base::TERMINATION_STATUS_LAUNCH_FAILED, 1,
+ kUptime);
metrics::SystemProfileProto system_profile;
helper.ProvideStabilityMetrics(&system_profile);
@@ -141,6 +151,8 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrashEnableExtensions) {
histogram_tester.ExpectBucketCount(
"BrowserRenderProcessHost.ChildLaunchFailures", RENDERER_TYPE_EXTENSION,
1);
+ histogram_tester.ExpectUniqueSample("Stability.CrashedProcessAge.Extension",
+ kUptime.InMilliseconds(), 2);
}
#endif
diff --git a/chromium/components/metrics/system_session_analyzer_win.cc b/chromium/components/metrics/system_session_analyzer_win.cc
index 2f28d4acd1a..e64501f8b55 100644
--- a/chromium/components/metrics/system_session_analyzer_win.cc
+++ b/chromium/components/metrics/system_session_analyzer_win.cc
@@ -251,7 +251,7 @@ SystemSessionAnalyzer::EvtHandle SystemSessionAnalyzer::CreateRenderContext() {
LPCWSTR value_paths[] = {kEventIdPath, kEventTimePath};
const DWORD kValueCnt = arraysize(value_paths);
- EVT_HANDLE context = NULL;
+ EVT_HANDLE context = nullptr;
context =
::EvtCreateRenderContext(kValueCnt, value_paths, EvtRenderContextValues);
if (!context)
diff --git a/chromium/components/metrics/test_metrics_service_client.cc b/chromium/components/metrics/test_metrics_service_client.cc
index 348c32b381b..4859b4e71f2 100644
--- a/chromium/components/metrics/test_metrics_service_client.cc
+++ b/chromium/components/metrics/test_metrics_service_client.cc
@@ -82,4 +82,8 @@ TestMetricsServiceClient::GetMetricsReportingDefaultState() {
return enable_default_;
}
+std::string TestMetricsServiceClient::GetAppPackageName() {
+ return "test app";
+}
+
} // namespace metrics
diff --git a/chromium/components/metrics/test_metrics_service_client.h b/chromium/components/metrics/test_metrics_service_client.h
index 3d45b5a19e5..c495536c402 100644
--- a/chromium/components/metrics/test_metrics_service_client.h
+++ b/chromium/components/metrics/test_metrics_service_client.h
@@ -43,6 +43,7 @@ class TestMetricsServiceClient : public MetricsServiceClient {
base::TimeDelta GetStandardUploadInterval() override;
bool IsReportingPolicyManaged() override;
EnableMetricsDefault GetMetricsReportingDefaultState() override;
+ std::string GetAppPackageName() override;
const std::string& get_client_id() const { return client_id_; }
// Returns a weak ref to the last created uploader.
diff --git a/chromium/components/metrics/ui/screen_info_metrics_provider.cc b/chromium/components/metrics/ui/screen_info_metrics_provider.cc
index d5518630a4f..f35639affa3 100644
--- a/chromium/components/metrics/ui/screen_info_metrics_provider.cc
+++ b/chromium/components/metrics/ui/screen_info_metrics_provider.cc
@@ -42,11 +42,11 @@ BOOL CALLBACK GetMonitorDPICallback(HMONITOR, HDC hdc, LPRECT, LPARAM dwData) {
}
void WriteScreenDPIInformationProto(SystemProfileProto::Hardware* hardware) {
- HDC desktop_dc = GetDC(NULL);
+ HDC desktop_dc = GetDC(nullptr);
if (desktop_dc) {
ScreenDPIInformation si = {0, 0};
- if (EnumDisplayMonitors(desktop_dc, NULL, GetMonitorDPICallback,
- reinterpret_cast<LPARAM>(&si))) {
+ if (EnumDisplayMonitors(desktop_dc, nullptr, GetMonitorDPICallback,
+ reinterpret_cast<LPARAM>(&si))) {
hardware->set_max_dpi_x(si.max_dpi_x);
hardware->set_max_dpi_y(si.max_dpi_y);
}
diff --git a/chromium/components/metrics_services_manager/BUILD.gn b/chromium/components/metrics_services_manager/BUILD.gn
index a09ffde8fda..7be3654ffd0 100644
--- a/chromium/components/metrics_services_manager/BUILD.gn
+++ b/chromium/components/metrics_services_manager/BUILD.gn
@@ -17,5 +17,6 @@ static_library("metrics_services_manager") {
"//components/ukm",
"//components/variations",
"//components/variations/service",
+ "//services/network/public/cpp:cpp",
]
}
diff --git a/chromium/components/metrics_services_manager/DEPS b/chromium/components/metrics_services_manager/DEPS
index be13669c5a2..d90fc81dc77 100644
--- a/chromium/components/metrics_services_manager/DEPS
+++ b/chromium/components/metrics_services_manager/DEPS
@@ -5,4 +5,5 @@ include_rules = [
"+components/rappor",
"+components/ukm",
"+components/variations",
+ "+services/network",
]
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager.cc b/chromium/components/metrics_services_manager/metrics_services_manager.cc
index 44e8fc132d6..49526315ac1 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager.cc
+++ b/chromium/components/metrics_services_manager/metrics_services_manager.cc
@@ -16,6 +16,7 @@
#include "components/rappor/rappor_service_impl.h"
#include "components/ukm/ukm_service.h"
#include "components/variations/service/variations_service.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace metrics_services_manager {
@@ -44,7 +45,7 @@ rappor::RapporServiceImpl* MetricsServicesManager::GetRapporServiceImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
if (!rappor_service_) {
rappor_service_ = client_->CreateRapporServiceImpl();
- rappor_service_->Initialize(client_->GetURLRequestContext());
+ rappor_service_->Initialize(client_->GetURLLoaderFactory());
}
return rappor_service_.get();
}
@@ -141,15 +142,14 @@ void MetricsServicesManager::UpdateUkmService() {
bool listeners_active =
GetMetricsServiceClient()->AreNotificationListenersEnabledOnAllProfiles();
- bool sync_enabled =
- client_->IsMetricsReportingForceEnabled() ||
- metrics_service_client_->IsHistorySyncEnabledOnAllProfiles();
+ bool sync_enabled = client_->IsMetricsReportingForceEnabled() ||
+ metrics_service_client_->SyncStateAllowsUkm();
bool is_incognito = client_->IsIncognitoSessionActive();
if (consent_given_ && listeners_active && sync_enabled && !is_incognito) {
// TODO(skare): revise this - merged in a big change
ukm->EnableRecording(
- metrics_service_client_->IsExtensionSyncEnabledOnAllProfiles());
+ metrics_service_client_->SyncStateAllowsExtensionUkm());
if (may_upload_)
ukm->EnableReporting();
else
diff --git a/chromium/components/metrics_services_manager/metrics_services_manager_client.h b/chromium/components/metrics_services_manager/metrics_services_manager_client.h
index e806067ccf6..138f1e00dc7 100644
--- a/chromium/components/metrics_services_manager/metrics_services_manager_client.h
+++ b/chromium/components/metrics_services_manager/metrics_services_manager_client.h
@@ -14,8 +14,8 @@ namespace metrics {
class MetricsServiceClient;
}
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
}
namespace rappor {
@@ -44,9 +44,9 @@ class MetricsServicesManagerClient {
virtual std::unique_ptr<const base::FieldTrial::EntropyProvider>
CreateEntropyProvider() = 0;
- // Returns the URL request context in which the metrics services should
- // operate.
- virtual net::URLRequestContextGetter* GetURLRequestContext() = 0;
+ // Returns the URL loader factory which the metrics services should use.
+ virtual scoped_refptr<network::SharedURLLoaderFactory>
+ GetURLLoaderFactory() = 0;
// Returns whether metrics reporting is enabled.
virtual bool IsMetricsReportingEnabled() = 0;
diff --git a/chromium/components/mirroring/DEPS b/chromium/components/mirroring/DEPS
index a2f3fc1a852..f5b9c0c247d 100644
--- a/chromium/components/mirroring/DEPS
+++ b/chromium/components/mirroring/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+media",
- "+mojo/common",
"+mojo/public",
# For testing
diff --git a/chromium/components/mirroring/browser/cast_remoting_sender.cc b/chromium/components/mirroring/browser/cast_remoting_sender.cc
index 63f355704c9..dcb057a5393 100644
--- a/chromium/components/mirroring/browser/cast_remoting_sender.cc
+++ b/chromium/components/mirroring/browser/cast_remoting_sender.cc
@@ -382,8 +382,7 @@ void CastRemotingSender::ReadFrame(uint32_t size) {
} else {
next_frame_data_.resize(size);
data_pipe_reader_->Read(
- reinterpret_cast<uint8_t*>(base::string_as_array(&next_frame_data_)),
- size,
+ reinterpret_cast<uint8_t*>(base::data(next_frame_data_)), size,
base::BindOnce(&CastRemotingSender::OnFrameRead,
base::Unretained(this)));
}
diff --git a/chromium/components/mirroring/browser/cast_remoting_sender_unittest.cc b/chromium/components/mirroring/browser/cast_remoting_sender_unittest.cc
index 780c3a7b537..4a18c55032d 100644
--- a/chromium/components/mirroring/browser/cast_remoting_sender_unittest.cc
+++ b/chromium/components/mirroring/browser/cast_remoting_sender_unittest.cc
@@ -124,8 +124,8 @@ class CastRemotingSenderTest : public ::testing::Test {
remoting_sender_->OnReceivedRtt(base::TimeDelta::FromMilliseconds(1));
const MojoCreateDataPipeOptions data_pipe_options{
- sizeof(MojoCreateDataPipeOptions),
- MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, 1, kDataPipeCapacity};
+ sizeof(MojoCreateDataPipeOptions), MOJO_CREATE_DATA_PIPE_FLAG_NONE, 1,
+ kDataPipeCapacity};
mojo::ScopedDataPipeConsumerHandle consumer_end;
CHECK_EQ(MOJO_RESULT_OK,
mojo::CreateDataPipe(&data_pipe_options, &producer_end_,
diff --git a/chromium/components/mirroring/browser/single_client_video_capture_host.cc b/chromium/components/mirroring/browser/single_client_video_capture_host.cc
index d04f18ed04d..aa16cb85e15 100644
--- a/chromium/components/mirroring/browser/single_client_video_capture_host.cc
+++ b/chromium/components/mirroring/browser/single_client_video_capture_host.cc
@@ -51,11 +51,9 @@ class DeviceLauncherCallbacks final
SingleClientVideoCaptureHost::SingleClientVideoCaptureHost(
const std::string& device_id,
content::MediaStreamType type,
- const VideoCaptureParams& params,
DeviceLauncherCreateCallback callback)
: device_id_(device_id),
type_(type),
- params_(params),
device_launcher_callback_(std::move(callback)),
weak_factory_(this) {
DCHECK(!device_launcher_callback_.is_null());
@@ -86,7 +84,7 @@ void SingleClientVideoCaptureHost::Start(
device_launcher_callback_.Run();
content::VideoCaptureDeviceLauncher* launcher = device_launcher.get();
launcher->LaunchDeviceAsync(
- device_id_, type_, params_, weak_factory_.GetWeakPtr(),
+ device_id_, type_, params, weak_factory_.GetWeakPtr(),
base::BindOnce(&SingleClientVideoCaptureHost::OnError,
weak_factory_.GetWeakPtr()),
callbacks,
@@ -106,11 +104,16 @@ void SingleClientVideoCaptureHost::Stop(int32_t device_id) {
return;
// Returns all the buffers.
- for (const auto& entry : buffer_context_map_) {
+ std::vector<int> buffers_in_use;
+ buffers_in_use.reserve(buffer_context_map_.size());
+ for (const auto& entry : buffer_context_map_)
+ buffers_in_use.push_back(entry.first);
+ for (int buffer_id : buffers_in_use) {
OnFinishedConsumingBuffer(
- entry.first,
+ buffer_id,
media::VideoFrameConsumerFeedbackObserver::kNoUtilizationRecorded);
}
+ DCHECK(buffer_context_map_.empty());
observer_->OnStateChanged(media::mojom::VideoCaptureState::ENDED);
observer_ = nullptr;
weak_factory_.InvalidateWeakPtrs();
@@ -167,9 +170,9 @@ void SingleClientVideoCaptureHost::GetDeviceFormatsInUse(
std::move(callback).Run(media::VideoCaptureFormats());
}
-void SingleClientVideoCaptureHost::OnNewBufferHandle(
+void SingleClientVideoCaptureHost::OnNewBuffer(
int buffer_id,
- std::unique_ptr<Buffer::HandleProvider> handle_provider) {
+ media::mojom::VideoBufferHandlePtr buffer_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DVLOG(3) << __func__ << ": buffer_id=" << buffer_id;
DCHECK(observer_);
@@ -177,9 +180,7 @@ void SingleClientVideoCaptureHost::OnNewBufferHandle(
const auto insert_result =
id_map_.emplace(std::make_pair(buffer_id, next_buffer_context_id_));
DCHECK(insert_result.second);
- observer_->OnBufferCreated(
- next_buffer_context_id_++,
- handle_provider->GetHandleForInterProcessTransit(true /* read only */));
+ observer_->OnNewBuffer(next_buffer_context_id_++, std::move(buffer_handle));
}
void SingleClientVideoCaptureHost::OnFrameReadyInBuffer(
diff --git a/chromium/components/mirroring/browser/single_client_video_capture_host.h b/chromium/components/mirroring/browser/single_client_video_capture_host.h
index c9f58e29d10..20fd5f1d7f1 100644
--- a/chromium/components/mirroring/browser/single_client_video_capture_host.h
+++ b/chromium/components/mirroring/browser/single_client_video_capture_host.h
@@ -39,14 +39,12 @@ class SingleClientVideoCaptureHost final
std::unique_ptr<content::VideoCaptureDeviceLauncher>()>;
SingleClientVideoCaptureHost(const std::string& device_id,
content::MediaStreamType type,
- const VideoCaptureParams& params,
DeviceLauncherCreateCallback callback);
~SingleClientVideoCaptureHost() override;
// media::mojom::VideoCaptureHost implementations
// |device_id| and |session_id| are ignored since there will be only one
- // device and one client. |params| is also ignored since it is already set
- // through the constructor.
+ // device and one client.
void Start(int32_t device_id,
int32_t session_id,
const VideoCaptureParams& params,
@@ -70,10 +68,8 @@ class SingleClientVideoCaptureHost final
// media::VideoFrameReceiver implementations
using Buffer = VideoCaptureDevice::Client::Buffer;
- void OnNewBufferHandle(
- int buffer_id,
- std::unique_ptr<VideoCaptureDevice::Client::Buffer::HandleProvider>
- handle_provider) override;
+ void OnNewBuffer(int buffer_id,
+ media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnFrameReadyInBuffer(
int buffer_id,
int frame_feedback_id,
@@ -99,7 +95,6 @@ class SingleClientVideoCaptureHost final
const std::string device_id_;
const content::MediaStreamType type_;
- const VideoCaptureParams params_;
const DeviceLauncherCreateCallback device_launcher_callback_;
media::mojom::VideoCaptureObserverPtr observer_;
diff --git a/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc b/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc
index 68e50568bca..e5971f8dc75 100644
--- a/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc
+++ b/chromium/components/mirroring/browser/single_client_video_capture_host_unittest.cc
@@ -29,7 +29,7 @@ class MockVideoCaptureDevice final
void SetPhotoOptions(
media::mojom::PhotoSettingsPtr settings,
VideoCaptureDevice::SetPhotoOptionsCallback callback) override {}
- void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback) {}
+ void TakePhoto(VideoCaptureDevice::TakePhotoCallback callback) override {}
void SetDesktopCaptureWindowIdAsync(gfx::NativeViewId window_id,
base::OnceClosure done_cb) override {}
MOCK_METHOD0(MaybeSuspendDevice, void());
@@ -84,34 +84,6 @@ class FakeDeviceLauncher final : public content::VideoCaptureDeviceLauncher {
DISALLOW_COPY_AND_ASSIGN(FakeDeviceLauncher);
};
-class StubBufferHandleProvider final
- : public VideoCaptureDevice::Client::Buffer::HandleProvider {
- public:
- StubBufferHandleProvider() {}
-
- ~StubBufferHandleProvider() override {}
-
- mojo::ScopedSharedBufferHandle GetHandleForInterProcessTransit(
- bool read_only) override {
- return mojo::SharedBufferHandle::Create(10);
- }
-
- base::SharedMemoryHandle GetNonOwnedSharedMemoryHandleForLegacyIPC()
- override {
- NOTREACHED();
- return base::SharedMemoryHandle();
- }
-
- std::unique_ptr<media::VideoCaptureBufferHandle> GetHandleForInProcessAccess()
- override {
- NOTREACHED();
- return nullptr;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(StubBufferHandleProvider);
-};
-
class StubReadWritePermission final
: public VideoCaptureDevice::Client::Buffer::ScopedAccessPermission {
public:
@@ -128,14 +100,13 @@ class MockVideoCaptureObserver final
explicit MockVideoCaptureObserver(media::mojom::VideoCaptureHostPtr host)
: host_(std::move(host)), binding_(this) {}
MOCK_METHOD1(OnBufferCreatedCall, void(int buffer_id));
- void OnBufferCreated(int32_t buffer_id,
- mojo::ScopedSharedBufferHandle handle) override {
+ void OnNewBuffer(int32_t buffer_id,
+ media::mojom::VideoBufferHandlePtr buffer_handle) override {
EXPECT_EQ(buffers_.find(buffer_id), buffers_.end());
EXPECT_EQ(frame_infos_.find(buffer_id), frame_infos_.end());
- buffers_[buffer_id] = std::move(handle);
+ buffers_[buffer_id] = std::move(buffer_handle);
OnBufferCreatedCall(buffer_id);
}
-
MOCK_METHOD1(OnBufferReadyCall, void(int buffer_id));
void OnBufferReady(int32_t buffer_id,
media::mojom::VideoFrameInfoPtr info) override {
@@ -177,7 +148,7 @@ class MockVideoCaptureObserver final
private:
media::mojom::VideoCaptureHostPtr host_;
mojo::Binding<media::mojom::VideoCaptureObserver> binding_;
- base::flat_map<int, mojo::ScopedSharedBufferHandle> buffers_;
+ base::flat_map<int, media::mojom::VideoBufferHandlePtr> buffers_;
base::flat_map<int, media::mojom::VideoFrameInfoPtr> frame_infos_;
DISALLOW_COPY_AND_ASSIGN(MockVideoCaptureObserver);
@@ -186,8 +157,7 @@ class MockVideoCaptureObserver final
media::mojom::VideoFrameInfoPtr GetVideoFrameInfo() {
return media::mojom::VideoFrameInfo::New(
base::TimeDelta(), base::Value(base::Value::Type::DICTIONARY),
- media::PIXEL_FORMAT_I420, media::VideoPixelStorage::CPU,
- gfx::Size(320, 180), gfx::Rect(320, 180));
+ media::PIXEL_FORMAT_I420, gfx::Size(320, 180), gfx::Rect(320, 180));
}
} // namespace
@@ -197,7 +167,6 @@ class SingleClientVideoCaptureHostTest : public ::testing::Test {
SingleClientVideoCaptureHostTest() : weak_factory_(this) {
auto host_impl = std::make_unique<SingleClientVideoCaptureHost>(
std::string(), content::MediaStreamType::MEDIA_TAB_VIDEO_CAPTURE,
- VideoCaptureParams(),
base::BindRepeating(
&SingleClientVideoCaptureHostTest::CreateDeviceLauncher,
base::Unretained(this)));
@@ -229,8 +198,11 @@ class SingleClientVideoCaptureHostTest : public ::testing::Test {
base::RunLoop run_loop;
EXPECT_CALL(*consumer_, OnBufferCreatedCall(expected_buffer_context_id))
.WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
- frame_receiver_->OnNewBufferHandle(
- buffer_id, std::make_unique<StubBufferHandleProvider>());
+ media::mojom::VideoBufferHandlePtr stub_buffer_handle =
+ media::mojom::VideoBufferHandle::New();
+ stub_buffer_handle->set_shared_buffer_handle(
+ mojo::SharedBufferHandle::Create(10));
+ frame_receiver_->OnNewBuffer(buffer_id, std::move(stub_buffer_handle));
run_loop.Run();
}
@@ -323,4 +295,11 @@ TEST_F(SingleClientVideoCaptureHostTest, ReuseBufferId) {
RetireBuffer(0, 1);
}
+TEST_F(SingleClientVideoCaptureHostTest, StopCapturingWhileBuffersInUse) {
+ for (int i = 0; i < 10; ++i) {
+ CreateBuffer(i, i);
+ FrameReadyInBuffer(i, i, i);
+ }
+}
+
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/BUILD.gn b/chromium/components/mirroring/service/BUILD.gn
index a8f92d0058e..a5b3ef6d2f4 100644
--- a/chromium/components/mirroring/service/BUILD.gn
+++ b/chromium/components/mirroring/service/BUILD.gn
@@ -6,6 +6,7 @@ import("//testing/test.gni")
source_set("interface") {
sources = [
+ "interface.cc",
"interface.h",
]
@@ -24,14 +25,26 @@ source_set("interface") {
source_set("service") {
sources = [
+ "message_dispatcher.cc",
+ "message_dispatcher.h",
+ "mirror_settings.cc",
+ "mirror_settings.h",
+ "receiver_response.cc",
+ "receiver_response.h",
"rtp_stream.cc",
"rtp_stream.h",
"session.cc",
"session.h",
+ "session_monitor.cc",
+ "session_monitor.h",
"udp_socket_client.cc",
"udp_socket_client.h",
+ "value_util.cc",
+ "value_util.h",
"video_capture_client.cc",
"video_capture_client.h",
+ "wifi_status_monitor.cc",
+ "wifi_status_monitor.h",
]
public_deps = [
@@ -40,7 +53,10 @@ source_set("service") {
deps = [
":interface",
+ "//components/version_info",
+ "//crypto",
"//media",
+ "//media/capture:capture_base",
"//media/capture/mojom:video_capture",
"//media/cast:common",
"//media/cast:net",
@@ -49,6 +65,7 @@ source_set("service") {
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//net",
+ "//services/network/public/cpp",
"//services/network/public/mojom",
"//ui/gfx",
]
@@ -61,10 +78,14 @@ source_set("unittests") {
"fake_network_service.h",
"fake_video_capture_host.cc",
"fake_video_capture_host.h",
+ "message_dispatcher_unittest.cc",
+ "receiver_response_unittest.cc",
"rtp_stream_unittest.cc",
+ "session_monitor_unittest.cc",
"session_unittest.cc",
"udp_socket_client_unittest.cc",
"video_capture_client_unittest.cc",
+ "wifi_status_monitor_unittest.cc",
]
deps = [
@@ -81,6 +102,8 @@ source_set("unittests") {
"//media/cast:test_support",
"//mojo/public/cpp/bindings",
"//net",
+ "//services/network:test_support",
+ "//services/network/public/cpp",
"//services/network/public/mojom",
"//testing/gmock",
"//testing/gtest",
diff --git a/chromium/components/mirroring/service/DEPS b/chromium/components/mirroring/service/DEPS
index d924f835b89..ddfc4b1cd47 100644
--- a/chromium/components/mirroring/service/DEPS
+++ b/chromium/components/mirroring/service/DEPS
@@ -1,4 +1,9 @@
include_rules = [
+ "-components",
+ "+components/mirroring/service",
+ "+components/version_info",
+ "+crypto",
"+net",
- "+services/network/public/mojom",
+ "+services/network/public",
+ "+services/network/test",
]
diff --git a/chromium/components/mirroring/service/fake_network_service.cc b/chromium/components/mirroring/service/fake_network_service.cc
index ca32b975005..971a350aef8 100644
--- a/chromium/components/mirroring/service/fake_network_service.cc
+++ b/chromium/components/mirroring/service/fake_network_service.cc
@@ -5,6 +5,8 @@
#include "components/mirroring/service/fake_network_service.h"
#include "media/cast/test/utility/net_utility.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/network/test/test_url_loader_factory.h"
namespace mirroring {
@@ -63,4 +65,12 @@ void MockNetworkContext::CreateUDPSocket(
OnUDPSocketCreated();
}
+void MockNetworkContext::CreateURLLoaderFactory(
+ network::mojom::URLLoaderFactoryRequest request,
+ network::mojom::URLLoaderFactoryParamsPtr params) {
+ ASSERT_TRUE(params);
+ mojo::MakeStrongBinding(std::make_unique<network::TestURLLoaderFactory>(),
+ std::move(request));
+}
+
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/fake_network_service.h b/chromium/components/mirroring/service/fake_network_service.h
index 8237befae49..3612147a52b 100644
--- a/chromium/components/mirroring/service/fake_network_service.h
+++ b/chromium/components/mirroring/service/fake_network_service.h
@@ -8,8 +8,8 @@
#include "base/callback.h"
#include "media/cast/net/cast_transport_config.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/udp_socket.mojom.h"
+#include "services/network/test/test_network_context.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -61,7 +61,7 @@ class MockUdpSocket final : public network::mojom::UDPSocket {
DISALLOW_COPY_AND_ASSIGN(MockUdpSocket);
};
-class MockNetworkContext final : public network::mojom::NetworkContext {
+class MockNetworkContext final : public network::TestNetworkContext {
public:
explicit MockNetworkContext(network::mojom::NetworkContextRequest request);
~MockNetworkContext() override;
@@ -69,53 +69,11 @@ class MockNetworkContext final : public network::mojom::NetworkContext {
MOCK_METHOD0(OnUDPSocketCreated, void());
// network::mojom::NetworkContext implementation:
- void CreateURLLoaderFactory(network::mojom::URLLoaderFactoryRequest request,
- uint32_t process_id) override {}
- void GetCookieManager(network::mojom::CookieManagerRequest request) override {
- }
- void GetRestrictedCookieManager(
- network::mojom::RestrictedCookieManagerRequest request,
- int32_t render_process_id,
- int32_t render_frame_id) override {}
- void ClearNetworkingHistorySince(
- base::Time time,
- base::OnceClosure completion_callback) override {}
- void ClearHttpCache(base::Time start_time,
- base::Time end_time,
- network::mojom::ClearCacheUrlFilterPtr filter,
- ClearHttpCacheCallback callback) override {}
- void SetNetworkConditions(
- const std::string& profile_id,
- network::mojom::NetworkConditionsPtr conditions) override {}
- void SetAcceptLanguage(const std::string& new_accept_language) override {}
- void SetCTPolicy(
- const std::vector<std::string>& required_hosts,
- const std::vector<std::string>& excluded_hosts,
- const std::vector<std::string>& excluded_spkis,
- const std::vector<std::string>& excluded_legacy_spkis) override {}
- void AddHSTSForTesting(const std::string& host,
- base::Time expiry,
- bool include_subdomains,
- AddHSTSForTestingCallback callback) override {}
void CreateUDPSocket(network::mojom::UDPSocketRequest request,
network::mojom::UDPSocketReceiverPtr receiver) override;
- void CreateTCPServerSocket(
- const net::IPEndPoint& local_addr,
- uint32_t backlog,
- const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
- network::mojom::TCPServerSocketRequest request,
- CreateTCPServerSocketCallback callback) override {}
- void CreateTCPConnectedSocket(
- const base::Optional<net::IPEndPoint>& local_addr,
- const net::AddressList& remote_addr_list,
- const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
- network::mojom::TCPConnectedSocketRequest request,
- network::mojom::TCPConnectedSocketObserverPtr observer,
- CreateTCPConnectedSocketCallback callback) override {}
- void CreateWebSocket(network::mojom::WebSocketRequest request,
- int process_id,
- int render_frame_id,
- const url::Origin& origin) override {}
+ void CreateURLLoaderFactory(
+ network::mojom::URLLoaderFactoryRequest request,
+ network::mojom::URLLoaderFactoryParamsPtr params) override;
MockUdpSocket* udp_socket() const { return udp_socket_.get(); }
diff --git a/chromium/components/mirroring/service/fake_video_capture_host.cc b/chromium/components/mirroring/service/fake_video_capture_host.cc
index 7e61d2da7d6..56a1574a3ba 100644
--- a/chromium/components/mirroring/service/fake_video_capture_host.cc
+++ b/chromium/components/mirroring/service/fake_video_capture_host.cc
@@ -41,7 +41,10 @@ void FakeVideoCaptureHost::SendOneFrame(const gfx::Size& size,
mojo::ScopedSharedBufferHandle buffer =
mojo::SharedBufferHandle::Create(5000);
memset(buffer->Map(5000).get(), 125, 5000);
- observer_->OnBufferCreated(0, std::move(buffer));
+ media::mojom::VideoBufferHandlePtr buffer_handle =
+ media::mojom::VideoBufferHandle::New();
+ buffer_handle->set_shared_buffer_handle(std::move(buffer));
+ observer_->OnNewBuffer(0, std::move(buffer_handle));
media::VideoFrameMetadata metadata;
metadata.SetDouble(media::VideoFrameMetadata::FRAME_RATE, 30);
metadata.SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME,
@@ -49,8 +52,7 @@ void FakeVideoCaptureHost::SendOneFrame(const gfx::Size& size,
observer_->OnBufferReady(
0, media::mojom::VideoFrameInfo::New(
base::TimeDelta(), metadata.GetInternalValues().Clone(),
- media::PIXEL_FORMAT_I420, media::VideoPixelStorage::CPU, size,
- gfx::Rect(size)));
+ media::PIXEL_FORMAT_I420, size, gfx::Rect(size)));
}
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/interface.cc b/chromium/components/mirroring/service/interface.cc
new file mode 100644
index 00000000000..6781ef77eac
--- /dev/null
+++ b/chromium/components/mirroring/service/interface.cc
@@ -0,0 +1,15 @@
+// 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 "components/mirroring/service/interface.h"
+
+namespace mirroring {
+
+CastSinkInfo::CastSinkInfo() {}
+
+CastSinkInfo::~CastSinkInfo() {}
+
+CastSinkInfo::CastSinkInfo(const CastSinkInfo& sink_info) = default;
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/interface.h b/chromium/components/mirroring/service/interface.h
index 501280efa0f..3feac5c3edb 100644
--- a/chromium/components/mirroring/service/interface.h
+++ b/chromium/components/mirroring/service/interface.h
@@ -5,13 +5,10 @@
#ifndef COMPONENTS_MIRRORING_SERVICE_INTERFACE_H_
#define COMPONENTS_MIRRORING_SERVICE_INTERFACE_H_
-#include <vector>
+#include <string>
-#include "base/callback.h"
-#include "base/values.h"
#include "media/capture/mojom/video_capture.mojom.h"
-#include "media/cast/cast_config.h"
-#include "net/base/ip_endpoint.h"
+#include "net/base/ip_address.h"
#include "services/network/public/mojom/network_service.mojom.h"
namespace mirroring {
@@ -21,22 +18,55 @@ namespace mirroring {
// Errors occurred in a mirroring session.
enum SessionError {
- SESSION_START_ERROR, // Error occurred while starting.
- AUDIO_CAPTURE_ERROR, // Error occurred in audio capturing.
- VIDEO_CAPTURE_ERROR, // Error occurred in video capturing.
- CAST_STREAMING_ERROR, // Error occurred in cast streaming.
- CAST_TRANSPORT_ERROR, // Error occurred in cast transport.
+ ANSWER_TIME_OUT, // ANSWER timeout.
+ ANSWER_NOT_OK, // Not OK answer response.
+ ANSWER_MISMATCHED_CAST_MODE, // ANSWER cast mode mismatched.
+ ANSWER_MISMATCHED_SSRC_LENGTH, // ANSWER ssrc length mismatched with indexes.
+ ANSWER_SELECT_MULTIPLE_AUDIO, // Multiple audio streams selected by ANSWER.
+ ANSWER_SELECT_MULTIPLE_VIDEO, // Multiple video streams selected by ANSWER.
+ ANSWER_SELECT_INVALID_INDEX, // Invalid index was selected.
+ ANSWER_NO_AUDIO_OR_VIDEO, // ANSWER not select audio or video.
+ AUDIO_CAPTURE_ERROR, // Error occurred in audio capturing.
+ VIDEO_CAPTURE_ERROR, // Error occurred in video capturing.
+ RTP_STREAM_ERROR, // Error reported by RtpStream.
+ ENCODING_ERROR, // Error occurred in encoding.
+ CAST_TRANSPORT_ERROR, // Error occurred in cast transport.
};
-enum SessionType {
+enum DeviceCapability {
AUDIO_ONLY,
VIDEO_ONLY,
AUDIO_AND_VIDEO,
};
-class SessionClient {
+constexpr char kRemotingNamespace[] = "urn:x-cast:com.google.cast.remoting";
+constexpr char kWebRtcNamespace[] = "urn:x-cast:com.google.cast.webrtc";
+
+struct CastMessage {
+ std::string message_namespace;
+ std::string json_format_data; // The content of the message.
+};
+
+class CastMessageChannel {
public:
- virtual ~SessionClient() {}
+ virtual ~CastMessageChannel() {}
+ virtual void Send(const CastMessage& message) = 0;
+};
+
+struct CastSinkInfo {
+ CastSinkInfo();
+ ~CastSinkInfo();
+ CastSinkInfo(const CastSinkInfo& sink_info);
+
+ net::IPAddress ip_address;
+ std::string model_name;
+ std::string friendly_name;
+ DeviceCapability capability;
+};
+
+class SessionObserver {
+ public:
+ virtual ~SessionObserver() {}
// Called when error occurred. The session will be stopped.
virtual void OnError(SessionError error) = 0;
@@ -46,25 +76,19 @@ class SessionClient {
// Called when the session is stopped.
virtual void DidStop() = 0;
+};
+
+class ResourceProvider {
+ public:
+ virtual ~ResourceProvider() {}
virtual void GetVideoCaptureHost(
media::mojom::VideoCaptureHostRequest request) = 0;
- virtual void GetNewWorkContext(
+ virtual void GetNetworkContext(
network::mojom::NetworkContextRequest request) = 0;
// TODO(xjz): Add interface to get AudioCaptureHost.
// TODO(xjz): Add interface for HW encoder profiles query and VEA create
// support.
-
- // TODO(xjz): Change this with an interface to send/receive messages to/from
- // receiver through cast channel, and generate/parse the OFFER/ANSWER message
- // in Mirroing service.
- using GetAnswerCallback = base::OnceCallback<void(
- const media::cast::FrameSenderConfig& audio_config,
- const media::cast::FrameSenderConfig& video_config)>;
- virtual void DoOfferAnswerExchange(
- const std::vector<media::cast::FrameSenderConfig>& audio_configs,
- const std::vector<media::cast::FrameSenderConfig>& video_configs,
- GetAnswerCallback callback) = 0;
};
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/message_dispatcher.cc b/chromium/components/mirroring/service/message_dispatcher.cc
new file mode 100644
index 00000000000..aa5ad4a4069
--- /dev/null
+++ b/chromium/components/mirroring/service/message_dispatcher.cc
@@ -0,0 +1,157 @@
+// 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 "components/mirroring/service/message_dispatcher.h"
+
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/rand_util.h"
+
+namespace mirroring {
+
+// Holds a request until |timeout| elapses or an acceptable response is
+// received. When timeout, |response_callback| runs with an UNKNOWN type
+// response.
+class MessageDispatcher::RequestHolder {
+ public:
+ RequestHolder() {}
+
+ ~RequestHolder() {
+ if (!response_callback_.is_null())
+ std::move(response_callback_).Run(ReceiverResponse());
+ }
+
+ void Start(const base::TimeDelta& timeout,
+ int32_t sequence_number,
+ OnceResponseCallback response_callback) {
+ response_callback_ = std::move(response_callback);
+ sequence_number_ = sequence_number;
+ DCHECK(!response_callback_.is_null());
+ timer_.Start(
+ FROM_HERE, timeout,
+ base::BindRepeating(&RequestHolder::SendResponse,
+ base::Unretained(this), ReceiverResponse()));
+ }
+
+ // Send |response| if the sequence number matches, or if the request times
+ // out, in which case the |response| is UNKNOWN type.
+ void SendResponse(const ReceiverResponse& response) {
+ if (!timer_.IsRunning() || response.sequence_number == sequence_number_)
+ std::move(response_callback_).Run(response);
+ // Ignore the response with mismatched sequence number.
+ }
+
+ private:
+ OnceResponseCallback response_callback_;
+ base::OneShotTimer timer_;
+ int32_t sequence_number_ = -1;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestHolder);
+};
+
+MessageDispatcher::MessageDispatcher(CastMessageChannel* outbound_channel,
+ ErrorCallback error_callback)
+ : outbound_channel_(outbound_channel),
+ error_callback_(std::move(error_callback)),
+ last_sequence_number_(base::RandInt(0, 1e9)) {
+ DCHECK(outbound_channel_);
+ DCHECK(!error_callback_.is_null());
+}
+
+MessageDispatcher::~MessageDispatcher() {
+ // Prevent the re-entrant operations on |callback_map_|.
+ decltype(callback_map_) subscriptions;
+ subscriptions.swap(callback_map_);
+ subscriptions.clear();
+}
+
+void MessageDispatcher::Send(const CastMessage& message) {
+ if (message.message_namespace != kWebRtcNamespace &&
+ message.message_namespace != kRemotingNamespace) {
+ DVLOG(2) << "Ignore message with unknown namespace = "
+ << message.message_namespace;
+ return; // Ignore message with wrong namespace.
+ }
+ if (message.json_format_data.empty())
+ return; // Ignore null message.
+
+ ReceiverResponse response;
+ if (!response.Parse(message.json_format_data)) {
+ error_callback_.Run("Response parsing error. message=" +
+ message.json_format_data);
+ return;
+ }
+
+#if DCHECK_IS_ON()
+ if (response.type == ResponseType::RPC)
+ DCHECK_EQ(kRemotingNamespace, message.message_namespace);
+ else
+ DCHECK_EQ(kWebRtcNamespace, message.message_namespace);
+#endif // DCHECK_IS_ON()
+
+ const auto callback_iter = callback_map_.find(response.type);
+ if (callback_iter == callback_map_.end()) {
+ error_callback_.Run("No callback subscribed. message=" +
+ message.json_format_data);
+ return;
+ }
+ callback_iter->second.Run(response);
+}
+
+void MessageDispatcher::Subscribe(ResponseType type,
+ ResponseCallback callback) {
+ DCHECK(type != ResponseType::UNKNOWN);
+ DCHECK(!callback.is_null());
+
+ const auto insert_result =
+ callback_map_.emplace(std::make_pair(type, std::move(callback)));
+ DCHECK(insert_result.second);
+}
+
+void MessageDispatcher::Unsubscribe(ResponseType type) {
+ auto iter = callback_map_.find(type);
+ if (iter != callback_map_.end())
+ callback_map_.erase(iter);
+}
+
+int32_t MessageDispatcher::GetNextSeqNumber() {
+ // Skip 0, which is used by Cast receiver to indicate that the broadcast
+ // status message is not coming from a specific sender (it is an autonomous
+ // status change, not triggered by a command from any sender). Strange usage
+ // of 0 though; could be a null / optional field.
+ return ++last_sequence_number_;
+}
+
+void MessageDispatcher::SendOutboundMessage(const CastMessage& message) {
+ outbound_channel_->Send(message);
+}
+
+void MessageDispatcher::RequestReply(const CastMessage& message,
+ ResponseType response_type,
+ int32_t sequence_number,
+ const base::TimeDelta& timeout,
+ OnceResponseCallback callback) {
+ DCHECK(!callback.is_null());
+ DCHECK(timeout > base::TimeDelta());
+ RequestHolder* const request_holder = new RequestHolder();
+ request_holder->Start(
+ timeout, sequence_number,
+ base::BindOnce(
+ [](MessageDispatcher* dispatcher, ResponseType response_type,
+ OnceResponseCallback callback, const ReceiverResponse& response) {
+ dispatcher->Unsubscribe(response_type);
+ std::move(callback).Run(response);
+ },
+ this, response_type, std::move(callback)));
+ // |request_holder| keeps alive until the callback is unsubscribed.
+ Subscribe(response_type, base::BindRepeating(
+ [](RequestHolder* request_holder,
+ const ReceiverResponse& response) {
+ request_holder->SendResponse(response);
+ },
+ base::Owned(request_holder)));
+ SendOutboundMessage(message);
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/message_dispatcher.h b/chromium/components/mirroring/service/message_dispatcher.h
new file mode 100644
index 00000000000..7b2ee9bfb62
--- /dev/null
+++ b/chromium/components/mirroring/service/message_dispatcher.h
@@ -0,0 +1,73 @@
+// 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 COMPONENTS_MIRRORING_SERVICE_MESSAGE_DISPATCHER_H_
+#define COMPONENTS_MIRRORING_SERVICE_MESSAGE_DISPATCHER_H_
+
+#include "base/callback.h"
+#include "base/containers/flat_map.h"
+#include "base/macros.h"
+#include "components/mirroring/service/interface.h"
+#include "components/mirroring/service/receiver_response.h"
+
+namespace mirroring {
+
+// Dispatches inbound/outbound messages. The outbound messages are sent out
+// through |outbound_channel|, and the inbound messages are handled by this
+// class.
+class MessageDispatcher final : public CastMessageChannel {
+ public:
+ using ErrorCallback = base::RepeatingCallback<void(const std::string&)>;
+ // TODO(xjz): Also pass a CastMessageChannel interface request for inbound
+ // message channel.
+ MessageDispatcher(CastMessageChannel* outbound_channel,
+ ErrorCallback error_callback);
+ ~MessageDispatcher() override;
+
+ using ResponseCallback =
+ base::RepeatingCallback<void(const ReceiverResponse& response)>;
+ // Registers/Unregisters callback for a certain type of responses.
+ void Subscribe(ResponseType type, ResponseCallback callback);
+ void Unsubscribe(ResponseType type);
+
+ using OnceResponseCallback =
+ base::OnceCallback<void(const ReceiverResponse& response)>;
+ // Sends the given message and subscribes to replies until an acceptable one
+ // is received or a timeout elapses. Message of the given response type is
+ // delivered to the supplied callback if the sequence number of the response
+ // matches |sequence_number|. If the timeout period elapses, the callback will
+ // be run once with an unknown type of |response|.
+ void RequestReply(const CastMessage& message,
+ ResponseType response_type,
+ int32_t sequence_number,
+ const base::TimeDelta& timeout,
+ OnceResponseCallback callback);
+
+ // Get the sequence number for the next outbound message. Never returns 0.
+ int32_t GetNextSeqNumber();
+
+ // Requests to send outbound |message|.
+ void SendOutboundMessage(const CastMessage& message);
+
+ private:
+ class RequestHolder;
+
+ // CastMessageChannel implementation. Handles inbound messages.
+ void Send(const CastMessage& message) override;
+
+ // Takes care of sending outbound messages.
+ CastMessageChannel* const outbound_channel_;
+ const ErrorCallback error_callback_;
+
+ int32_t last_sequence_number_;
+
+ // Holds callbacks for different types of responses.
+ base::flat_map<ResponseType, ResponseCallback> callback_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageDispatcher);
+};
+
+} // namespace mirroring
+
+#endif // COMPONENTS_MIRRORING_SERVICE_MESSAGE_DISPATCHER_H_
diff --git a/chromium/components/mirroring/service/message_dispatcher_unittest.cc b/chromium/components/mirroring/service/message_dispatcher_unittest.cc
new file mode 100644
index 00000000000..32cb7328ecc
--- /dev/null
+++ b/chromium/components/mirroring/service/message_dispatcher_unittest.cc
@@ -0,0 +1,299 @@
+// 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 "components/mirroring/service/message_dispatcher.h"
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InvokeWithoutArgs;
+using ::testing::_;
+
+namespace mirroring {
+
+namespace {
+
+bool IsEqual(const CastMessage& message1, const CastMessage& message2) {
+ return message1.message_namespace == message2.message_namespace &&
+ message1.json_format_data == message2.json_format_data;
+}
+
+void CloneResponse(const ReceiverResponse& response,
+ ReceiverResponse* cloned_response) {
+ cloned_response->type = response.type;
+ cloned_response->session_id = response.session_id;
+ cloned_response->sequence_number = response.sequence_number;
+ cloned_response->result = response.result;
+ if (response.answer)
+ cloned_response->answer = std::make_unique<Answer>(*response.answer);
+ if (response.status)
+ cloned_response->status =
+ std::make_unique<ReceiverStatus>(*response.status);
+ if (response.capabilities) {
+ cloned_response->capabilities =
+ std::make_unique<ReceiverCapability>(*response.capabilities);
+ }
+ cloned_response->rpc = response.rpc;
+ if (response.error) {
+ cloned_response->error = std::make_unique<ReceiverError>();
+ cloned_response->error->code = response.error->code;
+ cloned_response->error->description = response.error->description;
+ cloned_response->error->details = response.error->details;
+ }
+}
+
+} // namespace
+
+class MessageDispatcherTest : public CastMessageChannel,
+ public ::testing::Test {
+ public:
+ MessageDispatcherTest() {
+ message_dispatcher_ = std::make_unique<MessageDispatcher>(
+ this, base::BindRepeating(&MessageDispatcherTest::OnParsingError,
+ base::Unretained(this)));
+ message_dispatcher_->Subscribe(
+ ResponseType::ANSWER,
+ base::BindRepeating(&MessageDispatcherTest::OnAnswerResponse,
+ base::Unretained(this)));
+ message_dispatcher_->Subscribe(
+ ResponseType::STATUS_RESPONSE,
+ base::BindRepeating(&MessageDispatcherTest::OnStatusResponse,
+ base::Unretained(this)));
+ }
+ ~MessageDispatcherTest() override { scoped_task_environment_.RunUntilIdle(); }
+
+ void OnParsingError(const std::string& error_message) {
+ last_error_message_ = error_message;
+ }
+
+ void OnAnswerResponse(const ReceiverResponse& response) {
+ if (!last_answer_response_)
+ last_answer_response_ = std::make_unique<ReceiverResponse>();
+ CloneResponse(response, last_answer_response_.get());
+ }
+
+ void OnStatusResponse(const ReceiverResponse& response) {
+ if (!last_status_response_)
+ last_status_response_ = std::make_unique<ReceiverResponse>();
+ CloneResponse(response, last_status_response_.get());
+ }
+
+ protected:
+ // CastMessageChannel implementation. Handles outbound message.
+ void Send(const CastMessage& message) override {
+ last_outbound_message_.message_namespace = message.message_namespace;
+ last_outbound_message_.json_format_data = message.json_format_data;
+ }
+
+ // Simulates receiving an inbound message from receiver.
+ void SendInboundMessage(const CastMessage& message) {
+ CastMessageChannel* inbound_message_channel = message_dispatcher_.get();
+ inbound_message_channel->Send(message);
+ }
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<MessageDispatcher> message_dispatcher_;
+ CastMessage last_outbound_message_;
+ std::string last_error_message_;
+ std::unique_ptr<ReceiverResponse> last_answer_response_;
+ std::unique_ptr<ReceiverResponse> last_status_response_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MessageDispatcherTest);
+};
+
+TEST_F(MessageDispatcherTest, SendsOutboundMessage) {
+ const std::string test1 = "{\"a\": 1, \"b\": 2}";
+ const CastMessage message1 = CastMessage{kWebRtcNamespace, test1};
+ message_dispatcher_->SendOutboundMessage(message1);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_TRUE(IsEqual(message1, last_outbound_message_));
+ EXPECT_TRUE(last_error_message_.empty());
+
+ const std::string test2 = "{\"m\": 99, \"i\": 98, \"u\": 97}";
+ const CastMessage message2 = CastMessage{kWebRtcNamespace, test2};
+ message_dispatcher_->SendOutboundMessage(message2);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_TRUE(IsEqual(message2, last_outbound_message_));
+ EXPECT_TRUE(last_error_message_.empty());
+}
+
+TEST_F(MessageDispatcherTest, DispatchMessageToSubscriber) {
+ // Simulate a receiver ANSWER response and expect that just the ANSWER
+ // subscriber processes the message.
+ const std::string answer_response =
+ "{\"type\":\"ANSWER\",\"seqNum\":12345,\"result\":\"ok\","
+ "\"answer\":{\"udpPort\":50691}}";
+ const CastMessage answer_message =
+ CastMessage{kWebRtcNamespace, answer_response};
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ ASSERT_TRUE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_EQ(12345, last_answer_response_->sequence_number);
+ EXPECT_EQ(ResponseType::ANSWER, last_answer_response_->type);
+ EXPECT_EQ("ok", last_answer_response_->result);
+ EXPECT_EQ(50691, last_answer_response_->answer->udp_port);
+ EXPECT_FALSE(last_answer_response_->status);
+ last_answer_response_.reset();
+ EXPECT_TRUE(last_error_message_.empty());
+
+ // Simulate a receiver STATUS_RESPONSE and expect that just the
+ // STATUS_RESPONSE subscriber processes the message.
+ const std::string status_response =
+ "{\"type\":\"STATUS_RESPONSE\",\"seqNum\":12345,\"result\":\"ok\","
+ "\"status\":{\"wifiSnr\":42}}";
+ const CastMessage status_message =
+ CastMessage{kWebRtcNamespace, status_response};
+ SendInboundMessage(status_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ ASSERT_TRUE(last_status_response_);
+ EXPECT_EQ(12345, last_status_response_->sequence_number);
+ EXPECT_EQ(ResponseType::STATUS_RESPONSE, last_status_response_->type);
+ EXPECT_EQ("ok", last_status_response_->result);
+ EXPECT_EQ(42, last_status_response_->status->wifi_snr);
+ last_status_response_.reset();
+ EXPECT_TRUE(last_error_message_.empty());
+
+ // Unsubscribe from ANSWER messages, and when feeding-in an ANSWER message,
+ // nothing should happen.
+ message_dispatcher_->Unsubscribe(ResponseType::ANSWER);
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_FALSE(last_error_message_.empty()); // Expect an error reported.
+ last_error_message_.clear();
+
+ // However, STATUS_RESPONSE messages should still be dispatcher to the
+ // remaining subscriber.
+ SendInboundMessage(status_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_TRUE(last_status_response_);
+ last_status_response_.reset();
+ EXPECT_TRUE(last_error_message_.empty());
+
+ // Finally, unsubscribe from STATUS_RESPONSE messages, and when feeding-in
+ // either an ANSWER or a STATUS_RESPONSE message, nothing should happen.
+ message_dispatcher_->Unsubscribe(ResponseType::STATUS_RESPONSE);
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_FALSE(last_error_message_.empty());
+ last_error_message_.clear();
+ SendInboundMessage(status_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_FALSE(last_error_message_.empty());
+}
+
+TEST_F(MessageDispatcherTest, IgnoreMalformedMessage) {
+ const CastMessage message =
+ CastMessage{kWebRtcNamespace, "MUAHAHAHAHAHAHAHA!"};
+ SendInboundMessage(message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_FALSE(last_error_message_.empty());
+}
+
+TEST_F(MessageDispatcherTest, IgnoreMessageWithWrongNamespace) {
+ const std::string answer_response =
+ "{\"type\":\"ANSWER\",\"seqNum\":12345,\"result\":\"ok\","
+ "\"answer\":{\"udpPort\":50691}}";
+ const CastMessage answer_message =
+ CastMessage{"Wrong_namespace", answer_response};
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ // Messages with different namespace are ignored with no error reported.
+ EXPECT_TRUE(last_error_message_.empty());
+}
+
+TEST_F(MessageDispatcherTest, RequestReply) {
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ message_dispatcher_->Unsubscribe(ResponseType::ANSWER);
+ scoped_task_environment_.RunUntilIdle();
+ const std::string fake_offer = "{\"type\":\"OFFER\",\"seqNum\":45623}";
+ const CastMessage offer_message = CastMessage{kWebRtcNamespace, fake_offer};
+ message_dispatcher_->RequestReply(
+ offer_message, ResponseType::ANSWER, 45623,
+ base::TimeDelta::FromMilliseconds(100),
+ base::BindRepeating(&MessageDispatcherTest::OnAnswerResponse,
+ base::Unretained(this)));
+ scoped_task_environment_.RunUntilIdle();
+ // Received the request to send the outbound message.
+ EXPECT_TRUE(IsEqual(offer_message, last_outbound_message_));
+
+ std::string answer_response =
+ "{\"type\":\"ANSWER\",\"seqNum\":12345,\"result\":\"ok\","
+ "\"answer\":{\"udpPort\":50691}}";
+ CastMessage answer_message = CastMessage{kWebRtcNamespace, answer_response};
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ // The answer message with mismatched sequence number is ignored.
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_TRUE(last_error_message_.empty());
+
+ answer_response =
+ "{\"type\":\"ANSWER\",\"seqNum\":45623,\"result\":\"ok\","
+ "\"answer\":{\"udpPort\":50691}}";
+ answer_message = CastMessage{kWebRtcNamespace, answer_response};
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ ASSERT_TRUE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_TRUE(last_error_message_.empty());
+ EXPECT_EQ(45623, last_answer_response_->sequence_number);
+ EXPECT_EQ(ResponseType::ANSWER, last_answer_response_->type);
+ EXPECT_EQ("ok", last_answer_response_->result);
+ EXPECT_EQ(50691, last_answer_response_->answer->udp_port);
+ last_answer_response_.reset();
+
+ // Expect that the callback for ANSWER message was already unsubscribed.
+ SendInboundMessage(answer_message);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_FALSE(last_error_message_.empty());
+ last_error_message_.clear();
+
+ const CastMessage fake_message =
+ CastMessage{kWebRtcNamespace, "{\"type\":\"OFFER\",\"seqNum\":12345}"};
+ message_dispatcher_->RequestReply(
+ fake_message, ResponseType::ANSWER, 12345,
+ base::TimeDelta::FromMilliseconds(100),
+ base::BindRepeating(&MessageDispatcherTest::OnAnswerResponse,
+ base::Unretained(this)));
+ scoped_task_environment_.RunUntilIdle();
+ // Received the request to send the outbound message.
+ EXPECT_TRUE(IsEqual(fake_message, last_outbound_message_));
+ EXPECT_FALSE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+
+ // Destroy the dispatcher. Expect to receive an unknown type response.
+ message_dispatcher_.reset();
+ scoped_task_environment_.RunUntilIdle();
+ ASSERT_TRUE(last_answer_response_);
+ EXPECT_FALSE(last_status_response_);
+ EXPECT_TRUE(last_error_message_.empty());
+ EXPECT_EQ(ResponseType::UNKNOWN, last_answer_response_->type);
+ EXPECT_EQ(-1, last_answer_response_->sequence_number);
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/mirror_settings.cc b/chromium/components/mirroring/service/mirror_settings.cc
new file mode 100644
index 00000000000..a14799757a4
--- /dev/null
+++ b/chromium/components/mirroring/service/mirror_settings.cc
@@ -0,0 +1,148 @@
+// 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 "components/mirroring/service/mirror_settings.h"
+
+#include <algorithm>
+
+using media::cast::FrameSenderConfig;
+using media::cast::Codec;
+using media::cast::RtpPayloadType;
+using media::ResolutionChangePolicy;
+
+namespace mirroring {
+
+namespace {
+
+// Starting end-to-end latency for animated content.
+constexpr base::TimeDelta kAnimatedPlayoutDelay =
+ base::TimeDelta::FromMilliseconds(400);
+
+// Minimum end-to-end latency. This allows cast streaming to adaptively lower
+// latency in interactive streaming scenarios.
+// TODO(miu): This was 120 before stable launch, but we got user feedback that
+// this was causing audio drop-outs. So, we need to fix the Cast Streaming
+// implementation before lowering this setting.
+constexpr base::TimeDelta kMinPlayoutDelay =
+ base::TimeDelta::FromMilliseconds(400);
+
+// Maximum end-to-end latency.
+constexpr base::TimeDelta kMaxPlayoutDelay =
+ base::TimeDelta::FromMilliseconds(800);
+
+constexpr int kAudioTimebase = 48000;
+constexpr int kVidoTimebase = 90000;
+constexpr int kAudioChannels = 2;
+constexpr int kAudioFramerate = 100; // 100 FPS for 10ms packets.
+constexpr int kMinVideoBitrate = 300000;
+constexpr int kMaxVideoBitrate = 5000000;
+constexpr int kAudioBitrate = 0; // 0 means automatic.
+constexpr int kMaxFrameRate = 30; // The maximum frame rate for captures.
+constexpr int kMaxWidth = 1920; // Maximum video width in pixels.
+constexpr int kMaxHeight = 1080; // Maximum video height in pixels.
+constexpr int kMinWidth = 180; // Minimum video frame width in pixels.
+constexpr int kMinHeight = 180; // Minimum video frame height in pixels.
+
+} // namespace
+
+MirrorSettings::MirrorSettings()
+ : min_width_(kMinWidth),
+ min_height_(kMinHeight),
+ max_width_(kMaxWidth),
+ max_height_(kMaxHeight) {}
+
+MirrorSettings::~MirrorSettings() {}
+
+// static
+FrameSenderConfig MirrorSettings::GetDefaultAudioConfig(
+ RtpPayloadType payload_type,
+ Codec codec) {
+ FrameSenderConfig config;
+ config.sender_ssrc = 1;
+ config.receiver_ssrc = 2;
+ config.min_playout_delay = kMinPlayoutDelay;
+ config.max_playout_delay = kMaxPlayoutDelay;
+ config.animated_playout_delay = kAnimatedPlayoutDelay;
+ config.rtp_payload_type = payload_type;
+ config.rtp_timebase = kAudioTimebase;
+ config.channels = kAudioChannels;
+ config.min_bitrate = config.max_bitrate = config.start_bitrate =
+ kAudioBitrate;
+ config.max_frame_rate = kAudioFramerate; // 10 ms audio frames
+ config.codec = codec;
+ return config;
+}
+
+// static
+FrameSenderConfig MirrorSettings::GetDefaultVideoConfig(
+ RtpPayloadType payload_type,
+ Codec codec) {
+ FrameSenderConfig config;
+ config.sender_ssrc = 11;
+ config.receiver_ssrc = 12;
+ config.min_playout_delay = kMinPlayoutDelay;
+ config.max_playout_delay = kMaxPlayoutDelay;
+ config.animated_playout_delay = kAnimatedPlayoutDelay;
+ config.rtp_payload_type = payload_type;
+ config.rtp_timebase = kVidoTimebase;
+ config.channels = 1;
+ config.min_bitrate = kMinVideoBitrate;
+ config.max_bitrate = kMaxVideoBitrate;
+ config.start_bitrate = kMinVideoBitrate;
+ config.max_frame_rate = kMaxFrameRate;
+ config.codec = codec;
+ return config;
+}
+
+void MirrorSettings::SetResolutionContraints(int max_width, int max_height) {
+ max_width_ = std::max(max_width, min_width_);
+ max_height_ = std::max(max_height, min_height_);
+}
+
+media::VideoCaptureParams MirrorSettings::GetVideoCaptureParams() {
+ media::VideoCaptureParams params;
+ params.requested_format =
+ media::VideoCaptureFormat(gfx::Size(max_width_, max_height_),
+ kMaxFrameRate, media::PIXEL_FORMAT_I420);
+ if (max_height_ == min_height_ && max_width_ == min_width_) {
+ params.resolution_change_policy = ResolutionChangePolicy::FIXED_RESOLUTION;
+ } else if ((100 * min_width_ / min_height_) ==
+ (100 * max_width_ / max_height_)) {
+ params.resolution_change_policy =
+ ResolutionChangePolicy::FIXED_ASPECT_RATIO;
+ } else {
+ params.resolution_change_policy = ResolutionChangePolicy::ANY_WITHIN_LIMIT;
+ }
+ DCHECK(params.IsValid());
+ return params;
+}
+
+base::Value MirrorSettings::ToDictionaryValue() {
+ base::Value settings(base::Value::Type::DICTIONARY);
+ settings.SetKey("maxWidth", base::Value(max_width_));
+ settings.SetKey("maxHeight", base::Value(max_height_));
+ settings.SetKey("minWidth", base::Value(min_width_));
+ settings.SetKey("minHeight", base::Value(min_height_));
+ settings.SetKey("senderSideLetterboxing", base::Value(true));
+ settings.SetKey("minFrameRate", base::Value(0));
+ settings.SetKey("maxFrameRate", base::Value(kMaxFrameRate));
+ settings.SetKey("minVideoBitrate", base::Value(kMinVideoBitrate));
+ settings.SetKey("maxVideoBitrate", base::Value(kMaxVideoBitrate));
+ settings.SetKey("audioBitrate", base::Value(kAudioBitrate));
+ settings.SetKey(
+ "maxLatencyMillis",
+ base::Value(static_cast<int32_t>(kMaxPlayoutDelay.InMilliseconds())));
+ settings.SetKey(
+ "minLatencyMillis",
+ base::Value(static_cast<int32_t>(kMinPlayoutDelay.InMilliseconds())));
+ settings.SetKey("animatedLatencyMillis",
+ base::Value(static_cast<int32_t>(
+ kAnimatedPlayoutDelay.InMilliseconds())));
+ settings.SetKey("dscpEnabled", base::Value(false));
+ settings.SetKey("enableLogging", base::Value(true));
+ settings.SetKey("useTdls", base::Value(false));
+ return settings;
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/mirror_settings.h b/chromium/components/mirroring/service/mirror_settings.h
new file mode 100644
index 00000000000..937602d3e36
--- /dev/null
+++ b/chromium/components/mirroring/service/mirror_settings.h
@@ -0,0 +1,57 @@
+// 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 COMPONENTS_MIRRORING_SERVICE_MIRROR_SETTINGS_H_
+#define COMPONENTS_MIRRORING_SERVICE_MIRROR_SETTINGS_H_
+
+#include "base/time/time.h"
+#include "base/values.h"
+#include "media/capture/video_capture_types.h"
+#include "media/cast/cast_config.h"
+
+namespace mirroring {
+
+// Holds the default settings for a mirroring session. This class provides the
+// audio/video configs that this sender supports. And also provides the
+// audio/video constraints used for capturing.
+// TODO(xjz): Add the function to generate the audio capture contraints.
+// TODO(xjz): Add setters to the settings that might be overriden by integration
+// tests.
+class MirrorSettings {
+ public:
+ MirrorSettings();
+ ~MirrorSettings();
+
+ // Get the audio/video config with given codec.
+ static media::cast::FrameSenderConfig GetDefaultAudioConfig(
+ media::cast::RtpPayloadType payload_type,
+ media::cast::Codec codec);
+ static media::cast::FrameSenderConfig GetDefaultVideoConfig(
+ media::cast::RtpPayloadType payload_type,
+ media::cast::Codec codec);
+
+ // Call to override the default resolution settings.
+ void SetResolutionContraints(int max_width, int max_height);
+
+ // Get video capture constraints with the current settings.
+ media::VideoCaptureParams GetVideoCaptureParams();
+
+ int max_width() const { return max_width_; }
+ int max_height() const { return max_height_; }
+
+ // Returns a dictionary value of the current settings.
+ base::Value ToDictionaryValue();
+
+ private:
+ const int min_width_;
+ const int min_height_;
+ int max_width_;
+ int max_height_;
+
+ DISALLOW_COPY_AND_ASSIGN(MirrorSettings);
+};
+
+} // namespace mirroring
+
+#endif // COMPONENTS_MIRRORING_SERVICE_MIRROR_SETTINGS_H_
diff --git a/chromium/components/mirroring/service/receiver_response.cc b/chromium/components/mirroring/service/receiver_response.cc
new file mode 100644
index 00000000000..6feff42172c
--- /dev/null
+++ b/chromium/components/mirroring/service/receiver_response.cc
@@ -0,0 +1,199 @@
+// 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 "components/mirroring/service/receiver_response.h"
+
+#include "base/base64.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "components/mirroring/service/value_util.h"
+
+namespace mirroring {
+
+namespace {
+
+// Get the response type from the type string value in the JSON message.
+ResponseType GetResponseType(const std::string& type) {
+ if (type == "ANSWER")
+ return ResponseType::ANSWER;
+ if (type == "STATUS_RESPONSE")
+ return ResponseType::STATUS_RESPONSE;
+ if (type == "CAPABILITIES_RESPONSE")
+ return ResponseType::CAPABILITIES_RESPONSE;
+ if (type == "RPC")
+ return ResponseType::RPC;
+ return ResponseType::UNKNOWN;
+}
+
+} // namespace
+
+Answer::Answer()
+ : udp_port(-1), supports_get_status(false), cast_mode("mirroring") {}
+
+Answer::~Answer() {}
+
+Answer::Answer(const Answer& answer) = default;
+
+bool Answer::Parse(const base::Value& raw_value) {
+ return (raw_value.is_dict() && GetInt(raw_value, "udpPort", &udp_port) &&
+ GetIntArray(raw_value, "ssrcs", &ssrcs) &&
+ GetIntArray(raw_value, "sendIndexes", &send_indexes) &&
+ GetString(raw_value, "IV", &iv) &&
+ GetBool(raw_value, "receiverGetStatus", &supports_get_status) &&
+ GetString(raw_value, "castMode", &cast_mode));
+}
+
+// ----------------------------------------------------------------------------
+
+ReceiverStatus::ReceiverStatus() : wifi_snr(0) {}
+
+ReceiverStatus::~ReceiverStatus() {}
+
+ReceiverStatus::ReceiverStatus(const ReceiverStatus& status) = default;
+
+bool ReceiverStatus::Parse(const base::Value& raw_value) {
+ return (raw_value.is_dict() && GetDouble(raw_value, "wifiSnr", &wifi_snr) &&
+ GetIntArray(raw_value, "wifiSpeed", &wifi_speed));
+}
+
+// ----------------------------------------------------------------------------
+
+ReceiverKeySystem::ReceiverKeySystem() {}
+
+ReceiverKeySystem::~ReceiverKeySystem() {}
+
+ReceiverKeySystem::ReceiverKeySystem(
+ const ReceiverKeySystem& receiver_key_system) = default;
+
+bool ReceiverKeySystem::Parse(const base::Value& raw_value) {
+ return (raw_value.is_dict() && GetString(raw_value, "keySystemName", &name) &&
+ GetStringArray(raw_value, "initDataTypes", &init_data_types) &&
+ GetStringArray(raw_value, "codecs", &codecs) &&
+ GetStringArray(raw_value, "secureCodecs", &secure_codecs) &&
+ GetStringArray(raw_value, "audioRobustness", &audio_robustness) &&
+ GetStringArray(raw_value, "videoRobustness", &video_robustness) &&
+ GetString(raw_value, "persistentLicenseSessionSupport",
+ &persistent_license_session_support) &&
+ GetString(raw_value, "persistentReleaseMessageSessionSupport",
+ &persistent_release_message_session_support) &&
+ GetString(raw_value, "persistentStateSupport",
+ &persistent_state_support) &&
+ GetString(raw_value, "distinctiveIdentifierSupport",
+ &distinctive_identifier_support));
+}
+
+// ----------------------------------------------------------------------------
+
+ReceiverCapability::ReceiverCapability() {}
+
+ReceiverCapability::~ReceiverCapability() {}
+
+ReceiverCapability::ReceiverCapability(const ReceiverCapability& capabilities) =
+ default;
+
+bool ReceiverCapability::Parse(const base::Value& raw_value) {
+ if (!raw_value.is_dict() ||
+ !GetStringArray(raw_value, "mediaCaps", &media_caps))
+ return false;
+ auto* found = raw_value.FindKey("keySystems");
+ if (!found)
+ return true;
+ for (const auto& key_system_value : found->GetList()) {
+ ReceiverKeySystem key_system;
+ if (!key_system.Parse(key_system_value))
+ return false;
+ key_systems.emplace_back(key_system);
+ }
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+
+ReceiverError::ReceiverError() : code(-1) {}
+
+ReceiverError::~ReceiverError() {}
+
+bool ReceiverError::Parse(const base::Value& raw_value) {
+ if (!raw_value.is_dict() || !GetInt(raw_value, "code", &code) ||
+ !GetString(raw_value, "description", &description))
+ return false;
+ auto* found = raw_value.FindKey("details");
+ return found && base::JSONWriter::Write(*found, &details);
+}
+
+// ----------------------------------------------------------------------------
+
+ReceiverResponse::ReceiverResponse()
+ : type(ResponseType::UNKNOWN), session_id(-1), sequence_number(-1) {}
+
+ReceiverResponse::~ReceiverResponse() {}
+
+ReceiverResponse::ReceiverResponse(ReceiverResponse&& receiver_response) =
+ default;
+
+ReceiverResponse& ReceiverResponse::operator=(
+ ReceiverResponse&& receiver_response) = default;
+
+bool ReceiverResponse::Parse(const std::string& message_data) {
+ std::unique_ptr<base::Value> raw_value = base::JSONReader::Read(message_data);
+ if (!raw_value || !raw_value->is_dict() ||
+ !GetInt(*raw_value, "sessionId", &session_id) ||
+ !GetInt(*raw_value, "seqNum", &sequence_number) ||
+ !GetString(*raw_value, "result", &result))
+ return false;
+
+ if (result == "error") {
+ auto* found = raw_value->FindKey("error");
+ if (found) {
+ error = std::make_unique<ReceiverError>();
+ if (!error->Parse(*found))
+ return false;
+ }
+ }
+
+ std::string message_type;
+ if (!GetString(*raw_value, "type", &message_type))
+ return false;
+ // Convert |message_type| to uppercase.
+ message_type = base::ToUpperASCII(message_type);
+ type = GetResponseType(message_type);
+ if (type == ResponseType::UNKNOWN) {
+ DVLOG(2) << "Unknown response message type= " << message_type;
+ return false;
+ }
+
+ auto* found = raw_value->FindKey("answer");
+ if (found && !found->is_none()) {
+ answer = std::make_unique<Answer>();
+ if (!answer->Parse(*found))
+ return false;
+ }
+
+ found = raw_value->FindKey("status");
+ if (found && !found->is_none()) {
+ status = std::make_unique<ReceiverStatus>();
+ if (!status->Parse(*found))
+ return false;
+ }
+
+ found = raw_value->FindKey("capabilities");
+ if (found && !found->is_none()) {
+ capabilities = std::make_unique<ReceiverCapability>();
+ if (!capabilities->Parse(*found))
+ return false;
+ }
+
+ found = raw_value->FindKey("rpc");
+ if (found && !found->is_none()) {
+ // Decode the base64-encoded string.
+ if (!found->is_string() || !base::Base64Decode(found->GetString(), &rpc))
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/receiver_response.h b/chromium/components/mirroring/service/receiver_response.h
new file mode 100644
index 00000000000..0429e2fc6e9
--- /dev/null
+++ b/chromium/components/mirroring/service/receiver_response.h
@@ -0,0 +1,134 @@
+// 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 COMPONENTS_MIRRORING_SERVICE_RECEIVER_RESPONSE_H_
+#define COMPONENTS_MIRRORING_SERVICE_RECEIVER_RESPONSE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/values.h"
+
+namespace mirroring {
+
+// Receiver response message type.
+enum ResponseType {
+ UNKNOWN,
+ ANSWER, // Response to OFFER message.
+ STATUS_RESPONSE, // Response to GET_STATUS message.
+ CAPABILITIES_RESPONSE, // Response to GET_CAPABILITIES message.
+ RPC, // Rpc binary messages. The payload is base64 encoded.
+};
+
+struct Answer {
+ Answer();
+ ~Answer();
+ Answer(const Answer& answer);
+ bool Parse(const base::Value& raw_value);
+
+ // The UDP port used for all streams in this session.
+ int32_t udp_port;
+ // The indexes chosen from the OFFER message.
+ std::vector<int32_t> send_indexes;
+ // The RTP SSRC used to send the RTCP feedback of the stream, indicated by
+ // the |send_indexes| above.
+ std::vector<int32_t> ssrcs;
+ // A 128bit hex number containing the initialization vector for the crypto.
+ std::string iv;
+ // Indicates whether receiver supports the GET_STATUS command.
+ bool supports_get_status;
+ // "mirroring" for screen mirroring, or "remoting" for media remoting.
+ std::string cast_mode;
+};
+
+struct ReceiverStatus {
+ ReceiverStatus();
+ ~ReceiverStatus();
+ ReceiverStatus(const ReceiverStatus& status);
+ bool Parse(const base::Value& raw_value);
+
+ // Current WiFi signal to noise ratio in decibels.
+ double wifi_snr;
+ // Min, max, average, and current bandwidth in bps in order of the WiFi link.
+ // Example: [1200, 1300, 1250, 1230].
+ std::vector<int32_t> wifi_speed;
+};
+
+struct ReceiverKeySystem {
+ ReceiverKeySystem();
+ ~ReceiverKeySystem();
+ ReceiverKeySystem(const ReceiverKeySystem& receiver_key_system);
+ bool Parse(const base::Value& raw_value);
+
+ // Reverse URI (e.g. com.widevine.alpha).
+ std::string name;
+ // EME init data types (e.g. cenc).
+ std::vector<std::string> init_data_types;
+ // Codecs supported by key system. This will include AVC and VP8 on all
+ // Chromecasts.
+ std::vector<std::string> codecs;
+ // Codecs that are also hardware-secure.
+ std::vector<std::string> secure_codecs;
+ // Support levels for audio encryption robustness.
+ std::vector<std::string> audio_robustness;
+ // Support levels for video encryption robustness.
+ std::vector<std::string> video_robustness;
+
+ std::string persistent_license_session_support;
+ std::string persistent_release_message_session_support;
+ std::string persistent_state_support;
+ std::string distinctive_identifier_support;
+};
+
+struct ReceiverCapability {
+ ReceiverCapability();
+ ~ReceiverCapability();
+ ReceiverCapability(const ReceiverCapability& capabilities);
+ bool Parse(const base::Value& raw_value);
+
+ // Set of capabilities (e.g., ac3, 4k, hevc, vp9, dolby_vision, etc.).
+ std::vector<std::string> media_caps;
+ std::vector<ReceiverKeySystem> key_systems;
+};
+
+struct ReceiverError {
+ ReceiverError();
+ ~ReceiverError();
+ bool Parse(const base::Value& raw_value);
+
+ int32_t code;
+ std::string description;
+ std::string details; // In JSON format.
+};
+
+struct ReceiverResponse {
+ ReceiverResponse();
+ ~ReceiverResponse();
+ ReceiverResponse(ReceiverResponse&& receiver_response);
+ ReceiverResponse& operator=(ReceiverResponse&& receiver_response);
+ bool Parse(const std::string& message_data);
+
+ ResponseType type;
+ // All messages have same |session_id| for each mirroring session. This value
+ // is provided by the media router provider.
+ int32_t session_id;
+ // This should be same as the value in the corresponding query/OFFER messages
+ // for non-rpc messages.
+ int32_t sequence_number;
+
+ std::string result; // "ok" or "error".
+
+ // Only one of the following has value, according to |type|.
+ std::unique_ptr<Answer> answer;
+ std::string rpc;
+ std::unique_ptr<ReceiverStatus> status;
+ std::unique_ptr<ReceiverCapability> capabilities;
+ // Can only be non-null when result is "error".
+ std::unique_ptr<ReceiverError> error;
+};
+
+} // namespace mirroring
+
+#endif // COMPONENTS_MIRRORING_SERVICE_RECEIVER_RESPONSE_H_
diff --git a/chromium/components/mirroring/service/receiver_response_unittest.cc b/chromium/components/mirroring/service/receiver_response_unittest.cc
new file mode 100644
index 00000000000..807a683f48d
--- /dev/null
+++ b/chromium/components/mirroring/service/receiver_response_unittest.cc
@@ -0,0 +1,263 @@
+// 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 "components/mirroring/service/receiver_response.h"
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/test/mock_callback.h"
+#include "components/mirroring/service/value_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::InvokeWithoutArgs;
+using ::testing::_;
+
+namespace mirroring {
+
+class ReceiverResponseTest : public ::testing::Test {
+ public:
+ ReceiverResponseTest() {}
+ ~ReceiverResponseTest() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ReceiverResponseTest);
+};
+
+TEST_F(ReceiverResponseTest, ParseValidJson) {
+ const std::string response_string = "{\"type\":\"ANSWER\",\"result\":\"ok\"}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(-1, response.session_id);
+ EXPECT_EQ(-1, response.sequence_number);
+ EXPECT_EQ(ResponseType::ANSWER, response.type);
+ EXPECT_EQ("ok", response.result);
+ EXPECT_FALSE(response.answer);
+ EXPECT_FALSE(response.status);
+ EXPECT_FALSE(response.capabilities);
+ EXPECT_FALSE(response.error);
+ EXPECT_TRUE(response.rpc.empty());
+}
+
+TEST_F(ReceiverResponseTest, ParseInvalidValueType) {
+ const std::string response_string =
+ "{\"sessionId\":123, \"seqNum\":\"one-two-three\"}";
+ ReceiverResponse response;
+ EXPECT_FALSE(response.Parse(response_string));
+}
+
+TEST_F(ReceiverResponseTest, ParseNonJsonString) {
+ const std::string response_string = "This is not JSON.";
+ ReceiverResponse response;
+ EXPECT_FALSE(response.Parse(response_string));
+}
+
+TEST_F(ReceiverResponseTest, ParseRealWorldAnswerMessage) {
+ const std::string response_string =
+ "{\"answer\":{\"receiverRtcpEventLog\":[0,1],\"rtpExtensions\":"
+ "[[\"adaptive_playout_delay\"],[\"adaptive_playout_delay\"]],"
+ "\"sendIndexes\":[0,1],\"ssrcs\":[40863,759293],\"udpPort\":50691,"
+ "\"castMode\":\"mirroring\"},\"result\":\"ok\",\"seqNum\":989031000,"
+ "\"type\":\"ANSWER\"}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(-1, response.session_id);
+ EXPECT_EQ(989031000, response.sequence_number);
+ EXPECT_EQ(ResponseType::ANSWER, response.type);
+ EXPECT_EQ("ok", response.result);
+ ASSERT_TRUE(response.answer);
+ EXPECT_EQ(50691, response.answer->udp_port);
+ EXPECT_EQ(std::vector<int32_t>({0, 1}), response.answer->send_indexes);
+ EXPECT_EQ(std::vector<int32_t>({40863, 759293}), response.answer->ssrcs);
+ EXPECT_TRUE(response.answer->iv.empty());
+ EXPECT_EQ(false, response.answer->supports_get_status);
+ EXPECT_EQ("mirroring", response.answer->cast_mode);
+ EXPECT_FALSE(response.status);
+ EXPECT_FALSE(response.capabilities);
+ EXPECT_FALSE(response.error);
+}
+
+TEST_F(ReceiverResponseTest, ParseErrorMessage) {
+ const std::string response_string =
+ "{\"sessionId\": 123,"
+ "\"seqNum\": 999,"
+ "\"type\": \"ANSWER\","
+ "\"result\": \"error\","
+ "\"error\": {"
+ "\"code\": 42,"
+ "\"description\": \"it is broke\","
+ "\"details\": {\"foo\": -1, \"bar\": 88}"
+ "}"
+ "}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(123, response.session_id);
+ EXPECT_EQ(999, response.sequence_number);
+ EXPECT_EQ(ResponseType::ANSWER, response.type);
+ EXPECT_EQ("error", response.result);
+ EXPECT_FALSE(response.answer);
+ EXPECT_FALSE(response.status);
+ EXPECT_FALSE(response.capabilities);
+ ASSERT_TRUE(response.error);
+ EXPECT_EQ(42, response.error->code);
+ EXPECT_EQ("it is broke", response.error->description);
+ std::unique_ptr<base::Value> parsed_details =
+ base::JSONReader::Read(response.error->details);
+ ASSERT_TRUE(parsed_details && parsed_details->is_dict());
+ EXPECT_EQ(2u, parsed_details->DictSize());
+ int fool_value = 0;
+ EXPECT_TRUE(GetInt(*parsed_details, "foo", &fool_value));
+ EXPECT_EQ(-1, fool_value);
+ int bar_value = 0;
+ EXPECT_TRUE(GetInt(*parsed_details, "bar", &bar_value));
+ EXPECT_EQ(88, bar_value);
+}
+
+TEST_F(ReceiverResponseTest, ParseStatusMessage) {
+ const std::string response_string =
+ "{\"seqNum\": 777,"
+ "\"type\": \"STATUS_RESPONSE\","
+ "\"result\": \"ok\","
+ "\"status\": {"
+ "\"wifiSnr\": 36.7,"
+ "\"wifiSpeed\": [1234, 5678, 3000, 3001],"
+ "\"wifiFcsError\": [12, 13, 12, 12]}" // This will be ignored.
+ "}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(777, response.sequence_number);
+ EXPECT_EQ(ResponseType::STATUS_RESPONSE, response.type);
+ EXPECT_EQ("ok", response.result);
+ EXPECT_FALSE(response.error);
+ EXPECT_FALSE(response.answer);
+ ASSERT_TRUE(response.status);
+ EXPECT_EQ(36.7, response.status->wifi_snr);
+ const std::vector<int32_t> expect_speed({1234, 5678, 3000, 3001});
+ EXPECT_EQ(expect_speed, response.status->wifi_speed);
+ EXPECT_FALSE(response.capabilities);
+}
+
+TEST_F(ReceiverResponseTest, ParseCapabilityMessage) {
+ const std::string response_string =
+ "{\"sessionId\": 999888777,"
+ "\"seqNum\": 5551212,"
+ "\"type\": \"CAPABILITIES_RESPONSE\","
+ "\"result\": \"ok\","
+ "\"capabilities\": {"
+ "\"mediaCaps\": [\"audio\", \"video\", \"vp9\"],"
+ "\"keySystems\": ["
+ "{"
+ "\"keySystemName\": \"com.w3c.clearkey\""
+ "},"
+ "{"
+ "\"keySystemName\": \"com.widevine.alpha\","
+ "\"initDataTypes\": [\"a\", \"b\", \"c\", \"1\", \"2\", \"3\"],"
+ "\"codecs\": [\"vp8\", \"h264\"],"
+ "\"secureCodecs\": [\"h264\", \"vp8\"],"
+ "\"audioRobustness\": [\"nope\"],"
+ "\"videoRobustness\": [\"yep\"],"
+ "\"persistentLicenseSessionSupport\": \"SUPPORTED\","
+ "\"persistentReleaseMessageSessionSupport\": \"SUPPORTED_WITH_ID\","
+ "\"persistentStateSupport\": \"REQUESTABLE\","
+ "\"distinctiveIdentifierSupport\": \"ALWAYS_ENABLED\""
+ "}"
+ "]}}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(999888777, response.session_id);
+ EXPECT_EQ(5551212, response.sequence_number);
+ EXPECT_EQ(ResponseType::CAPABILITIES_RESPONSE, response.type);
+ EXPECT_EQ("ok", response.result);
+ EXPECT_FALSE(response.error);
+ EXPECT_FALSE(response.answer);
+ EXPECT_FALSE(response.status);
+ ASSERT_TRUE(response.capabilities);
+ EXPECT_EQ(std::vector<std::string>({"audio", "video", "vp9"}),
+ response.capabilities->media_caps);
+ const ReceiverKeySystem& first_key_system =
+ response.capabilities->key_systems[0];
+ EXPECT_EQ("com.w3c.clearkey", first_key_system.name);
+ EXPECT_TRUE(first_key_system.init_data_types.empty());
+ EXPECT_TRUE(first_key_system.codecs.empty());
+ EXPECT_TRUE(first_key_system.secure_codecs.empty());
+ EXPECT_TRUE(first_key_system.audio_robustness.empty());
+ EXPECT_TRUE(first_key_system.video_robustness.empty());
+ EXPECT_TRUE(first_key_system.persistent_license_session_support.empty());
+ EXPECT_TRUE(
+ first_key_system.persistent_release_message_session_support.empty());
+ EXPECT_TRUE(first_key_system.persistent_state_support.empty());
+ EXPECT_TRUE(first_key_system.distinctive_identifier_support.empty());
+ const ReceiverKeySystem& second_key_system =
+ response.capabilities->key_systems[1];
+ EXPECT_EQ("com.widevine.alpha", second_key_system.name);
+ EXPECT_EQ(std::vector<std::string>({"a", "b", "c", "1", "2", "3"}),
+ second_key_system.init_data_types);
+ EXPECT_EQ(std::vector<std::string>({"vp8", "h264"}),
+ second_key_system.codecs);
+ EXPECT_EQ(std::vector<std::string>({"h264", "vp8"}),
+ second_key_system.secure_codecs);
+ EXPECT_EQ(std::vector<std::string>({"nope"}),
+ second_key_system.audio_robustness);
+ EXPECT_EQ(std::vector<std::string>({"yep"}),
+ second_key_system.video_robustness);
+ EXPECT_EQ("SUPPORTED", second_key_system.persistent_license_session_support);
+ EXPECT_EQ("SUPPORTED_WITH_ID",
+ second_key_system.persistent_release_message_session_support);
+ EXPECT_EQ("REQUESTABLE", second_key_system.persistent_state_support);
+ EXPECT_EQ("ALWAYS_ENABLED", second_key_system.distinctive_identifier_support);
+}
+
+TEST_F(ReceiverResponseTest, ParseRpcMessage) {
+ const std::string message = "Hello from the Cast Receiver!";
+ std::string rpc_base64;
+ base::Base64Encode(message, &rpc_base64);
+ std::string response_string =
+ "{\"sessionId\": 735189,"
+ "\"seqNum\": 6789,"
+ "\"type\": \"RPC\","
+ "\"result\": \"ok\","
+ "\"rpc\": \"" +
+ rpc_base64 + "\"}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(735189, response.session_id);
+ EXPECT_EQ(6789, response.sequence_number);
+ EXPECT_EQ("ok", response.result);
+ EXPECT_EQ(ResponseType::RPC, response.type);
+ EXPECT_EQ(message, response.rpc);
+ EXPECT_FALSE(response.error);
+ EXPECT_FALSE(response.answer);
+ EXPECT_FALSE(response.status);
+ EXPECT_FALSE(response.capabilities);
+}
+
+TEST_F(ReceiverResponseTest, ParseResponseWithNullField) {
+ const std::string response_string =
+ "{\"sessionId\":null,\"seqNum\":808907000,\"type\":\"ANSWER\","
+ "\"result\":\"ok\",\"rpc\":null,\"error\":null,"
+ "\"answer\":{\"udpPort\":51706,\"sendIndexes\":[0,1],"
+ "\"ssrcs\":[152818,556029],\"IV\":null,\"receiverGetStatus\":true,"
+ "\"castMode\":\"mirroring\"},\"status\":null,\"capabilities\":null}";
+ ReceiverResponse response;
+ ASSERT_TRUE(response.Parse(response_string));
+ EXPECT_EQ(808907000, response.sequence_number);
+ EXPECT_EQ("ok", response.result);
+ EXPECT_FALSE(response.error);
+ EXPECT_FALSE(response.status);
+ EXPECT_FALSE(response.capabilities);
+ EXPECT_TRUE(response.rpc.empty());
+ EXPECT_EQ(ResponseType::ANSWER, response.type);
+ ASSERT_TRUE(response.answer);
+ EXPECT_EQ(51706, response.answer->udp_port);
+ EXPECT_EQ(std::vector<int32_t>({0, 1}), response.answer->send_indexes);
+ EXPECT_EQ(std::vector<int32_t>({152818, 556029}), response.answer->ssrcs);
+ EXPECT_TRUE(response.answer->iv.empty());
+ EXPECT_EQ(true, response.answer->supports_get_status);
+ EXPECT_EQ("mirroring", response.answer->cast_mode);
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/rtp_stream.cc b/chromium/components/mirroring/service/rtp_stream.cc
index 1051557731c..d9a95d39b28 100644
--- a/chromium/components/mirroring/service/rtp_stream.cc
+++ b/chromium/components/mirroring/service/rtp_stream.cc
@@ -8,7 +8,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/values.h"
-#include "build/build_config.h"
#include "media/base/video_frame.h"
#include "media/cast/cast_config.h"
#include "media/cast/sender/audio_sender.h"
@@ -30,81 +29,6 @@ constexpr base::TimeDelta kRefreshInterval =
// limit (60 * 250ms = 15 seconds), refresh frame requests will stop being made.
constexpr int kMaxConsecutiveRefreshFrames = 60;
-FrameSenderConfig DefaultOpusConfig() {
- FrameSenderConfig config;
- config.rtp_payload_type = RtpPayloadType::AUDIO_OPUS;
- config.sender_ssrc = 1;
- config.receiver_ssrc = 2;
- config.rtp_timebase = media::cast::kDefaultAudioSamplingRate;
- config.channels = 2;
- config.min_bitrate = config.max_bitrate = config.start_bitrate =
- media::cast::kDefaultAudioEncoderBitrate;
- config.max_frame_rate = 100; // 10 ms audio frames
- config.codec = media::cast::CODEC_AUDIO_OPUS;
- return config;
-}
-
-FrameSenderConfig DefaultVp8Config() {
- FrameSenderConfig config;
- config.rtp_payload_type = RtpPayloadType::VIDEO_VP8;
- config.sender_ssrc = 11;
- config.receiver_ssrc = 12;
- config.rtp_timebase = media::cast::kVideoFrequency;
- config.channels = 1;
- config.max_bitrate = media::cast::kDefaultMaxVideoBitrate;
- config.min_bitrate = media::cast::kDefaultMinVideoBitrate;
- config.max_frame_rate = media::cast::kDefaultMaxFrameRate;
- config.codec = media::cast::CODEC_VIDEO_VP8;
- return config;
-}
-
-FrameSenderConfig DefaultH264Config() {
- FrameSenderConfig config;
- config.rtp_payload_type = RtpPayloadType::VIDEO_H264;
- config.sender_ssrc = 11;
- config.receiver_ssrc = 12;
- config.rtp_timebase = media::cast::kVideoFrequency;
- config.channels = 1;
- config.max_bitrate = media::cast::kDefaultMaxVideoBitrate;
- config.min_bitrate = media::cast::kDefaultMinVideoBitrate;
- config.max_frame_rate = media::cast::kDefaultMaxFrameRate;
- config.codec = media::cast::CODEC_VIDEO_H264;
- return config;
-}
-
-bool IsHardwareVP8EncodingSupported(RtpStreamClient* client) {
- // Query for hardware VP8 encoder support.
- const std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- vea_profiles = client->GetSupportedVideoEncodeAcceleratorProfiles();
- for (const auto& vea_profile : vea_profiles) {
- if (vea_profile.profile >= media::VP8PROFILE_MIN &&
- vea_profile.profile <= media::VP8PROFILE_MAX) {
- return true;
- }
- }
- return false;
-}
-
-bool IsHardwareH264EncodingSupported(RtpStreamClient* client) {
-// Query for hardware H.264 encoder support.
-//
-// TODO(miu): Look into why H.264 hardware encoder on MacOS is broken.
-// http://crbug.com/596674
-// TODO(emircan): Look into HW encoder initialization issues on Win.
-// https://crbug.com/636064
-#if !defined(OS_MACOSX) && !defined(OS_WIN)
- const std::vector<media::VideoEncodeAccelerator::SupportedProfile>
- vea_profiles = client->GetSupportedVideoEncodeAcceleratorProfiles();
- for (const auto& vea_profile : vea_profiles) {
- if (vea_profile.profile >= media::H264PROFILE_MIN &&
- vea_profile.profile <= media::H264PROFILE_MAX) {
- return true;
- }
- }
-#endif // !defined(OS_MACOSX) && !defined(OS_WIN)
- return false;
-}
-
} // namespace
VideoRtpStream::VideoRtpStream(
@@ -125,24 +49,6 @@ VideoRtpStream::VideoRtpStream(
VideoRtpStream::~VideoRtpStream() {}
-// static
-std::vector<FrameSenderConfig> VideoRtpStream::GetSupportedConfigs(
- RtpStreamClient* client) {
- std::vector<FrameSenderConfig> supported_configs;
- // Prefer VP8 over H.264 for hardware encoder.
- if (IsHardwareVP8EncodingSupported(client))
- supported_configs.push_back(DefaultVp8Config());
- if (IsHardwareH264EncodingSupported(client))
- supported_configs.push_back(DefaultH264Config());
-
- // Propose the default software VP8 encoder, if no hardware encoders are
- // available.
- if (supported_configs.empty())
- supported_configs.push_back(DefaultVp8Config());
-
- return supported_configs;
-}
-
void VideoRtpStream::InsertVideoFrame(
scoped_refptr<media::VideoFrame> video_frame) {
DCHECK(client_);
@@ -205,11 +111,6 @@ AudioRtpStream::AudioRtpStream(
AudioRtpStream::~AudioRtpStream() {}
-// static
-std::vector<FrameSenderConfig> AudioRtpStream::GetSupportedConfigs() {
- return {DefaultOpusConfig()};
-}
-
void AudioRtpStream::InsertAudio(std::unique_ptr<media::AudioBus> audio_bus,
base::TimeTicks capture_time) {
audio_sender_->InsertAudio(std::move(audio_bus), capture_time);
diff --git a/chromium/components/mirroring/service/rtp_stream.h b/chromium/components/mirroring/service/rtp_stream.h
index ef5788d953c..9bffae1f60d 100644
--- a/chromium/components/mirroring/service/rtp_stream.h
+++ b/chromium/components/mirroring/service/rtp_stream.h
@@ -44,10 +44,6 @@ class RtpStreamClient {
// The following are for hardware video encoding.
- // Query the supported hardware encoding profiles.
- virtual media::VideoEncodeAccelerator::SupportedProfiles
- GetSupportedVideoEncodeAcceleratorProfiles() = 0;
-
virtual void CreateVideoEncodeAccelerator(
const media::cast::ReceiveVideoEncodeAcceleratorCallback& callback) = 0;
@@ -71,9 +67,6 @@ class VideoRtpStream {
base::WeakPtr<RtpStreamClient> client);
~VideoRtpStream();
- static std::vector<media::cast::FrameSenderConfig> GetSupportedConfigs(
- RtpStreamClient* client);
-
// Called by VideoCaptureClient when a video frame is received.
// |video_frame| is required to provide REFERENCE_TIME in the metadata.
void InsertVideoFrame(scoped_refptr<media::VideoFrame> video_frame);
@@ -115,8 +108,6 @@ class AudioRtpStream {
base::WeakPtr<RtpStreamClient> client);
~AudioRtpStream();
- static std::vector<media::cast::FrameSenderConfig> GetSupportedConfigs();
-
// Called by AudioCaptureClient when new audio data is available.
void InsertAudio(std::unique_ptr<media::AudioBus> audio_bus,
base::TimeTicks estimated_capture_time);
diff --git a/chromium/components/mirroring/service/rtp_stream_unittest.cc b/chromium/components/mirroring/service/rtp_stream_unittest.cc
index 1a2d2283643..b0a0ae26b04 100644
--- a/chromium/components/mirroring/service/rtp_stream_unittest.cc
+++ b/chromium/components/mirroring/service/rtp_stream_unittest.cc
@@ -43,10 +43,6 @@ class DummyClient final : public RtpStreamClient {
void CreateVideoEncodeMemory(
size_t size,
const media::cast::ReceiveVideoEncodeMemoryCallback& callback) override {}
- media::VideoEncodeAccelerator::SupportedProfiles
- GetSupportedVideoEncodeAcceleratorProfiles() override {
- return media::VideoEncodeAccelerator::SupportedProfiles();
- }
base::WeakPtr<RtpStreamClient> GetWeakPtr() {
return weak_factory_.GetWeakPtr();
diff --git a/chromium/components/mirroring/service/session.cc b/chromium/components/mirroring/service/session.cc
index 1d97af99207..58047f8db81 100644
--- a/chromium/components/mirroring/service/session.cc
+++ b/chromium/components/mirroring/service/session.cc
@@ -4,23 +4,34 @@
#include "components/mirroring/service/session.h"
+#include "base/json/json_writer.h"
#include "base/logging.h"
+#include "base/rand_util.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
+#include "base/values.h"
+#include "build/build_config.h"
#include "components/mirroring/service/udp_socket_client.h"
#include "components/mirroring/service/video_capture_client.h"
+#include "crypto/random.h"
#include "media/cast/net/cast_transport.h"
#include "media/cast/sender/audio_sender.h"
#include "media/cast/sender/video_sender.h"
#include "media/video/video_encode_accelerator.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/system/platform_handle.h"
+#include "net/base/ip_endpoint.h"
using media::cast::FrameSenderConfig;
using media::cast::RtpPayloadType;
using media::cast::CastTransportStatus;
+using media::cast::Codec;
using media::cast::FrameEvent;
using media::cast::PacketEvent;
using media::cast::OperationalStatus;
@@ -39,6 +50,23 @@ constexpr base::TimeDelta kSendEventsInterval = base::TimeDelta::FromSeconds(1);
constexpr base::TimeDelta kOfferAnswerExchangeTimeout =
base::TimeDelta::FromSeconds(15);
+// Used for OFFER/ANSWER message exchange. Some receivers will error out on
+// payloadType values other than the ones hard-coded here.
+constexpr int kAudioPayloadType = 127;
+constexpr int kVideoPayloadType = 96;
+
+constexpr int kAudioSsrcMin = 1;
+constexpr int kAudioSsrcMax = 5e5;
+constexpr int kVideoSsrcMin = 5e5 + 1;
+constexpr int kVideoSsrcMax = 10e5;
+
+// Maximum number of bytes of file data allowed in a single Crash report. As of
+// this writing, the total report upload size is capped at 20 MB.
+//
+// 2 KB of "overhead bytes" are subtracted to account for all of the non-file
+// data in a report upload, including HTTP headers/requests and form data.
+constexpr int kMaxCrashReportBytes = (20 * 1024 - 2) * 1024;
+
class TransportClient final : public media::cast::CastTransport::Client {
public:
explicit TransportClient(Session* session) : session_(session) {}
@@ -67,142 +95,192 @@ class TransportClient final : public media::cast::CastTransport::Client {
DISALLOW_COPY_AND_ASSIGN(TransportClient);
};
-} // namespace
-
-Session::Session(SessionType session_type,
- const net::IPEndPoint& receiver_endpoint,
- SessionClient* client)
- : client_(client), weak_factory_(this) {
- DCHECK(client_);
-
- std::vector<FrameSenderConfig> audio_configs;
- std::vector<FrameSenderConfig> video_configs;
- if (session_type != SessionType::VIDEO_ONLY)
- audio_configs = AudioRtpStream::GetSupportedConfigs();
- if (session_type != SessionType::AUDIO_ONLY)
- video_configs = VideoRtpStream::GetSupportedConfigs(this);
- start_timeout_timer_.Start(
- FROM_HERE, kOfferAnswerExchangeTimeout,
- base::BindRepeating(&Session::OnOfferAnswerExchangeTimeout,
- weak_factory_.GetWeakPtr()));
- client_->DoOfferAnswerExchange(
- audio_configs, video_configs,
- base::BindOnce(&Session::StartInternal, weak_factory_.GetWeakPtr(),
- receiver_endpoint));
+// Generates a string with cryptographically secure random bytes.
+std::string MakeRandomString(size_t length) {
+ std::string result(length, ' ');
+ crypto::RandBytes(base::data(result), length);
+ return result;
}
-Session::~Session() {
- StopSession();
+int NumberOfEncodeThreads() {
+ // Do not saturate CPU utilization just for encoding. On a lower-end system
+ // with only 1 or 2 cores, use only one thread for encoding. On systems with
+ // more cores, allow half of the cores to be used for encoding.
+ return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2);
}
-void Session::StartInternal(const net::IPEndPoint& receiver_endpoint,
- const FrameSenderConfig& audio_config,
- const FrameSenderConfig& video_config) {
- DVLOG(1) << __func__;
- start_timeout_timer_.Stop();
-
- DCHECK(!video_capture_client_);
- DCHECK(!cast_transport_);
- DCHECK(!audio_stream_);
- DCHECK(!video_stream_);
- DCHECK(!cast_environment_);
- DCHECK(client_);
-
- if (audio_config.rtp_payload_type == RtpPayloadType::REMOTE_AUDIO ||
- video_config.rtp_payload_type == RtpPayloadType::REMOTE_VIDEO) {
- NOTIMPLEMENTED(); // TODO(xjz): Add support for media remoting.
- return;
+// Scan profiles for hardware VP8 encoder support.
+bool IsHardwareVP8EncodingSupported(
+ const std::vector<media::VideoEncodeAccelerator::SupportedProfile>&
+ profiles) {
+ for (const auto& vea_profile : profiles) {
+ if (vea_profile.profile >= media::VP8PROFILE_MIN &&
+ vea_profile.profile <= media::VP8PROFILE_MAX) {
+ return true;
+ }
}
+ return false;
+}
- const bool has_audio =
- (audio_config.rtp_payload_type < RtpPayloadType::AUDIO_LAST) &&
- (audio_config.rtp_payload_type >= RtpPayloadType::FIRST);
- const bool has_video =
- (video_config.rtp_payload_type > RtpPayloadType::AUDIO_LAST) &&
- (video_config.rtp_payload_type < RtpPayloadType::LAST);
- if (!has_audio && !has_video) {
- VLOG(1) << "Incorrect ANSWER message: No audio or Video.";
- client_->OnError(SESSION_START_ERROR);
- return;
+// Scan profiles for hardware H.264 encoder support.
+bool IsHardwareH264EncodingSupported(
+ const std::vector<media::VideoEncodeAccelerator::SupportedProfile>&
+ profiles) {
+// TODO(miu): Look into why H.264 hardware encoder on MacOS is broken.
+// http://crbug.com/596674
+// TODO(emircan): Look into HW encoder initialization issues on Win.
+// https://crbug.com/636064
+#if !defined(OS_MACOSX) && !defined(OS_WIN)
+ for (const auto& vea_profile : profiles) {
+ if (vea_profile.profile >= media::H264PROFILE_MIN &&
+ vea_profile.profile <= media::H264PROFILE_MAX) {
+ return true;
+ }
}
+#endif // !defined(OS_MACOSX) && !defined(OS_WIN)
+ return false;
+}
- audio_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits(
- {base::TaskPriority::USER_BLOCKING,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
- base::SingleThreadTaskRunnerThreadMode::DEDICATED);
- video_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits(
- {base::TaskPriority::USER_BLOCKING,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
- base::SingleThreadTaskRunnerThreadMode::DEDICATED);
- cast_environment_ = new media::cast::CastEnvironment(
- base::DefaultTickClock::GetInstance(),
- base::ThreadTaskRunnerHandle::Get(), audio_encode_thread_,
- video_encode_thread_);
- network::mojom::NetworkContextPtr network_context;
- client_->GetNewWorkContext(mojo::MakeRequest(&network_context));
- auto udp_client = std::make_unique<UdpSocketClient>(
- receiver_endpoint, std::move(network_context),
- base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(),
- SessionError::CAST_TRANSPORT_ERROR));
- cast_transport_ = media::cast::CastTransport::Create(
- cast_environment_->Clock(), kSendEventsInterval,
- std::make_unique<TransportClient>(this), std::move(udp_client),
- base::ThreadTaskRunnerHandle::Get());
+// Helper to add |config| to |config_list| with given |aes_key|.
+void AddSenderConfig(int32_t sender_ssrc,
+ FrameSenderConfig config,
+ const std::string& aes_key,
+ const std::string& aes_iv,
+ std::vector<FrameSenderConfig>* config_list) {
+ config.aes_key = aes_key;
+ config.aes_iv_mask = aes_iv;
+ config.sender_ssrc = sender_ssrc;
+ config_list->emplace_back(config);
+}
- if (has_audio) {
- auto audio_sender = std::make_unique<media::cast::AudioSender>(
- cast_environment_, audio_config,
- base::BindRepeating(&Session::OnEncoderStatusChange,
- weak_factory_.GetWeakPtr()),
- cast_transport_.get());
- audio_stream_ = std::make_unique<AudioRtpStream>(
- std::move(audio_sender), weak_factory_.GetWeakPtr());
- // TODO(xjz): Start audio capturing.
- NOTIMPLEMENTED();
+// Generate the stream object from |config| and add it to |stream_list|.
+void AddStreamObject(int stream_index,
+ const std::string& codec_name,
+ const FrameSenderConfig& config,
+ const MirrorSettings& mirror_settings,
+ base::Value::ListStorage* stream_list) {
+ base::Value stream(base::Value::Type::DICTIONARY);
+ stream.SetKey("index", base::Value(stream_index));
+ stream.SetKey("codecName", base::Value(base::ToLowerASCII(codec_name)));
+ stream.SetKey("rtpProfile", base::Value("cast"));
+ const bool is_audio =
+ (config.rtp_payload_type <= media::cast::RtpPayloadType::AUDIO_LAST);
+ stream.SetKey("rtpPayloadType",
+ base::Value(is_audio ? kAudioPayloadType : kVideoPayloadType));
+ stream.SetKey("ssrc", base::Value(int(config.sender_ssrc)));
+ stream.SetKey(
+ "targetDelay",
+ base::Value(int(config.animated_playout_delay.InMilliseconds())));
+ stream.SetKey("aesKey", base::Value(base::HexEncode(config.aes_key.data(),
+ config.aes_key.size())));
+ stream.SetKey("aesIvMask",
+ base::Value(base::HexEncode(config.aes_iv_mask.data(),
+ config.aes_iv_mask.size())));
+ stream.SetKey("timeBase",
+ base::Value("1/" + std::to_string(config.rtp_timebase)));
+ stream.SetKey("receiverRtcpEventLog", base::Value(true));
+ stream.SetKey("rtpExtensions", base::Value("adaptive_playout_delay"));
+ if (is_audio) {
+ // Note on "AUTO" bitrate calculation: This is based on libopus source
+ // at the time of this writing. Internally, it uses the following math:
+ //
+ // packet_overhead_bps = 60 bits * num_packets_in_one_second
+ // approx_encoded_signal_bps = frequency * channels
+ // estimated_bps = packet_overhead_bps + approx_encoded_signal_bps
+ //
+ // For 100 packets/sec at 48 kHz and 2 channels, this is 102kbps.
+ const int bitrate = config.max_bitrate > 0
+ ? config.max_bitrate
+ : (60 * config.max_frame_rate +
+ config.rtp_timebase * config.channels);
+ stream.SetKey("type", base::Value("audio_source"));
+ stream.SetKey("bitRate", base::Value(bitrate));
+ stream.SetKey("sampleRate", base::Value(config.rtp_timebase));
+ stream.SetKey("channels", base::Value(config.channels));
+ } else /* is video */ {
+ stream.SetKey("type", base::Value("video_source"));
+ stream.SetKey("renderMode", base::Value("video"));
+ stream.SetKey("maxFrameRate",
+ base::Value(std::to_string(static_cast<int>(
+ config.max_frame_rate * 1000)) +
+ "/1000"));
+ stream.SetKey("maxBitRate", base::Value(config.max_bitrate));
+ base::Value::ListStorage resolutions;
+ base::Value resolution(base::Value::Type::DICTIONARY);
+ resolution.SetKey("width", base::Value(mirror_settings.max_width()));
+ resolution.SetKey("height", base::Value(mirror_settings.max_height()));
+ resolutions.emplace_back(std::move(resolution));
+ stream.SetKey("resolutions", base::Value(resolutions));
}
+ stream_list->emplace_back(std::move(stream));
+}
- if (has_video) {
- auto video_sender = std::make_unique<media::cast::VideoSender>(
- cast_environment_, video_config,
- base::BindRepeating(&Session::OnEncoderStatusChange,
- weak_factory_.GetWeakPtr()),
- base::BindRepeating(&Session::CreateVideoEncodeAccelerator,
- weak_factory_.GetWeakPtr()),
- base::BindRepeating(&Session::CreateVideoEncodeMemory,
- weak_factory_.GetWeakPtr()),
- cast_transport_.get(),
- base::BindRepeating(&Session::SetTargetPlayoutDelay,
- weak_factory_.GetWeakPtr()));
- video_stream_ = std::make_unique<VideoRtpStream>(
- std::move(video_sender), weak_factory_.GetWeakPtr());
- media::mojom::VideoCaptureHostPtr video_host;
- client_->GetVideoCaptureHost(mojo::MakeRequest(&video_host));
- video_capture_client_ =
- std::make_unique<VideoCaptureClient>(std::move(video_host));
- video_capture_client_->Start(
- base::BindRepeating(&VideoRtpStream::InsertVideoFrame,
- video_stream_->AsWeakPtr()),
- base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(),
- SessionError::VIDEO_CAPTURE_ERROR));
- }
+} // namespace
+
+Session::Session(int32_t session_id,
+ const CastSinkInfo& sink_info,
+ const gfx::Size& max_resolution,
+ SessionObserver* observer,
+ ResourceProvider* resource_provider,
+ CastMessageChannel* outbound_channel)
+ : session_id_(session_id),
+ sink_info_(sink_info),
+ observer_(observer),
+ resource_provider_(resource_provider),
+ message_dispatcher_(outbound_channel,
+ base::BindRepeating(&Session::OnResponseParsingError,
+ base::Unretained(this))),
+ weak_factory_(this) {
+ DCHECK(resource_provider_);
+ mirror_settings_.SetResolutionContraints(max_resolution.width(),
+ max_resolution.height());
+ resource_provider_->GetNetworkContext(mojo::MakeRequest(&network_context_));
+
+ auto wifi_status_monitor =
+ std::make_unique<WifiStatusMonitor>(session_id_, &message_dispatcher_);
+ network::mojom::URLLoaderFactoryPtr url_loader_factory;
+ network_context_->CreateURLLoaderFactory(
+ mojo::MakeRequest(&url_loader_factory),
+ network::mojom::URLLoaderFactoryParams::New(
+ network::mojom::kBrowserProcessId, false, std::string()));
+
+ // Generate session level tags.
+ base::Value session_tags(base::Value::Type::DICTIONARY);
+ session_tags.SetKey("mirrorSettings", mirror_settings_.ToDictionaryValue());
+ session_tags.SetKey("shouldCaptureAudio",
+ base::Value(sink_info_.capability != VIDEO_ONLY));
+ session_tags.SetKey("shouldCaptureVideo",
+ base::Value(sink_info_.capability != AUDIO_ONLY));
+ session_tags.SetKey("receiverProductName",
+ base::Value(sink_info_.model_name));
+
+ session_monitor_.emplace(
+ kMaxCrashReportBytes, sink_info_.ip_address, std::move(session_tags),
+ std::move(url_loader_factory), std::move(wifi_status_monitor));
+
+ CreateAndSendOffer();
+}
- client_->DidStart();
+Session::~Session() {
+ StopSession();
}
void Session::ReportError(SessionError error) {
- DVLOG(1) << __func__ << ": error=" << error;
- if (client_)
- client_->OnError(error);
+ if (session_monitor_.has_value())
+ session_monitor_->OnStreamingError(error);
+ if (observer_)
+ observer_->OnError(error);
StopSession();
}
void Session::StopSession() {
DVLOG(1) << __func__;
- if (!client_)
+ if (!resource_provider_)
return;
+ session_monitor_->StopStreamingSession();
+ session_monitor_.reset();
weak_factory_.InvalidateWeakPtrs();
- start_timeout_timer_.Stop();
audio_encode_thread_ = nullptr;
video_encode_thread_ = nullptr;
video_capture_client_.reset();
@@ -210,13 +288,15 @@ void Session::StopSession() {
video_stream_.reset();
cast_transport_.reset();
cast_environment_ = nullptr;
- client_->DidStop();
- client_ = nullptr;
+ resource_provider_ = nullptr;
+ if (observer_) {
+ observer_->DidStop();
+ observer_ = nullptr;
+ }
}
void Session::OnError(const std::string& message) {
- VLOG(1) << message;
- ReportError(SessionError::CAST_STREAMING_ERROR);
+ ReportError(SessionError::RTP_STREAM_ERROR);
}
void Session::RequestRefreshFrame() {
@@ -238,14 +318,13 @@ void Session::OnEncoderStatusChange(OperationalStatus status) {
case OperationalStatus::STATUS_UNSUPPORTED_CODEC:
case OperationalStatus::STATUS_CODEC_INIT_FAILED:
case OperationalStatus::STATUS_CODEC_RUNTIME_ERROR:
- DVLOG(1) << "OperationalStatus error.";
- ReportError(SessionError::CAST_STREAMING_ERROR);
+ ReportError(SessionError::ENCODING_ERROR);
break;
}
}
media::VideoEncodeAccelerator::SupportedProfiles
-Session::GetSupportedVideoEncodeAcceleratorProfiles() {
+Session::GetSupportedVeaProfiles() {
// TODO(xjz): Establish GPU channel and query for the supported profiles.
return media::VideoEncodeAccelerator::SupportedProfiles();
}
@@ -290,13 +369,7 @@ void Session::OnTransportStatusChanged(CastTransportStatus status) {
case CastTransportStatus::TRANSPORT_STREAM_INITIALIZED:
return; // Not errors, do nothing.
case CastTransportStatus::TRANSPORT_INVALID_CRYPTO_CONFIG:
- DVLOG(1) << "Warning: unexpected status: "
- << "TRANSPORT_INVALID_CRYPTO_CONFIG";
- ReportError(SessionError::CAST_TRANSPORT_ERROR);
- break;
case CastTransportStatus::TRANSPORT_SOCKET_ERROR:
- DVLOG(1) << "Warning: unexpected status: "
- << "TRANSPORT_SOCKET_ERROR";
ReportError(SessionError::CAST_TRANSPORT_ERROR);
break;
}
@@ -310,6 +383,156 @@ void Session::OnLoggingEventsReceived(
std::move(packet_events));
}
+void Session::OnAnswer(const std::string& cast_mode,
+ const std::vector<FrameSenderConfig>& audio_configs,
+ const std::vector<FrameSenderConfig>& video_configs,
+ const ReceiverResponse& response) {
+ if (!response.answer || response.type == ResponseType::UNKNOWN) {
+ ReportError(ANSWER_TIME_OUT);
+ return;
+ }
+
+ DCHECK_EQ(ResponseType::ANSWER, response.type);
+
+ if (response.result != "ok") {
+ ReportError(ANSWER_NOT_OK);
+ return;
+ }
+
+ const Answer& answer = *response.answer;
+ if (answer.cast_mode != cast_mode) {
+ ReportError(ANSWER_MISMATCHED_CAST_MODE);
+ return;
+ }
+
+ if (answer.send_indexes.size() != answer.ssrcs.size()) {
+ ReportError(ANSWER_MISMATCHED_SSRC_LENGTH);
+ return;
+ }
+
+ // Select Audio/Video config from ANSWER.
+ bool has_audio = false;
+ bool has_video = false;
+ FrameSenderConfig audio_config;
+ FrameSenderConfig video_config;
+ const int video_start_idx = audio_configs.size();
+ const int video_idx_bound = video_configs.size() + video_start_idx;
+ for (size_t i = 0; i < answer.send_indexes.size(); ++i) {
+ if (answer.send_indexes[i] < 0 ||
+ answer.send_indexes[i] >= video_idx_bound) {
+ ReportError(ANSWER_SELECT_INVALID_INDEX);
+ return;
+ }
+ if (answer.send_indexes[i] < video_start_idx) {
+ // Audio
+ if (has_audio) {
+ ReportError(ANSWER_SELECT_MULTIPLE_AUDIO);
+ return;
+ }
+ audio_config = audio_configs[answer.send_indexes[i]];
+ audio_config.receiver_ssrc = answer.ssrcs[i];
+ has_audio = true;
+ } else {
+ // Video
+ if (has_video) {
+ ReportError(ANSWER_SELECT_MULTIPLE_VIDEO);
+ return;
+ }
+ video_config = video_configs[answer.send_indexes[i] - video_start_idx];
+ video_config.receiver_ssrc = answer.ssrcs[i];
+ video_config.video_codec_params.number_of_encode_threads =
+ NumberOfEncodeThreads();
+ has_video = true;
+ }
+ }
+ if (!has_audio && !has_video) {
+ ReportError(ANSWER_NO_AUDIO_OR_VIDEO);
+ return;
+ }
+
+ if ((has_audio &&
+ audio_config.rtp_payload_type == RtpPayloadType::REMOTE_AUDIO) ||
+ (has_video &&
+ video_config.rtp_payload_type == RtpPayloadType::REMOTE_VIDEO)) {
+ NOTIMPLEMENTED(); // TODO(xjz): Add support for media remoting.
+ return;
+ }
+
+ // Start streaming.
+ audio_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits(
+ {base::TaskPriority::USER_BLOCKING,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::SingleThreadTaskRunnerThreadMode::DEDICATED);
+ video_encode_thread_ = base::CreateSingleThreadTaskRunnerWithTraits(
+ {base::TaskPriority::USER_BLOCKING,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::SingleThreadTaskRunnerThreadMode::DEDICATED);
+ cast_environment_ = new media::cast::CastEnvironment(
+ base::DefaultTickClock::GetInstance(),
+ base::ThreadTaskRunnerHandle::Get(), audio_encode_thread_,
+ video_encode_thread_);
+ auto udp_client = std::make_unique<UdpSocketClient>(
+ net::IPEndPoint(sink_info_.ip_address, answer.udp_port),
+ network_context_.get(),
+ base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(),
+ SessionError::CAST_TRANSPORT_ERROR));
+ cast_transport_ = media::cast::CastTransport::Create(
+ cast_environment_->Clock(), kSendEventsInterval,
+ std::make_unique<TransportClient>(this), std::move(udp_client),
+ base::ThreadTaskRunnerHandle::Get());
+
+ if (has_audio) {
+ auto audio_sender = std::make_unique<media::cast::AudioSender>(
+ cast_environment_, audio_config,
+ base::BindRepeating(&Session::OnEncoderStatusChange,
+ weak_factory_.GetWeakPtr()),
+ cast_transport_.get());
+ audio_stream_ = std::make_unique<AudioRtpStream>(
+ std::move(audio_sender), weak_factory_.GetWeakPtr());
+ // TODO(xjz): Start audio capturing.
+ NOTIMPLEMENTED();
+ }
+
+ if (has_video) {
+ auto video_sender = std::make_unique<media::cast::VideoSender>(
+ cast_environment_, video_config,
+ base::BindRepeating(&Session::OnEncoderStatusChange,
+ weak_factory_.GetWeakPtr()),
+ base::BindRepeating(&Session::CreateVideoEncodeAccelerator,
+ weak_factory_.GetWeakPtr()),
+ base::BindRepeating(&Session::CreateVideoEncodeMemory,
+ weak_factory_.GetWeakPtr()),
+ cast_transport_.get(),
+ base::BindRepeating(&Session::SetTargetPlayoutDelay,
+ weak_factory_.GetWeakPtr()));
+ video_stream_ = std::make_unique<VideoRtpStream>(
+ std::move(video_sender), weak_factory_.GetWeakPtr());
+ media::mojom::VideoCaptureHostPtr video_host;
+ resource_provider_->GetVideoCaptureHost(mojo::MakeRequest(&video_host));
+ video_capture_client_ = std::make_unique<VideoCaptureClient>(
+ mirror_settings_.GetVideoCaptureParams(), std::move(video_host));
+ video_capture_client_->Start(
+ base::BindRepeating(&VideoRtpStream::InsertVideoFrame,
+ video_stream_->AsWeakPtr()),
+ base::BindOnce(&Session::ReportError, weak_factory_.GetWeakPtr(),
+ SessionError::VIDEO_CAPTURE_ERROR));
+ }
+
+ const SessionMonitor::SessionType session_type =
+ (has_audio && has_video)
+ ? SessionMonitor::AUDIO_AND_VIDEO
+ : has_audio ? SessionMonitor::AUDIO_ONLY : SessionMonitor::VIDEO_ONLY;
+ session_monitor_->StartStreamingSession(cast_environment_, session_type,
+ false /* is_remoting */);
+
+ if (observer_)
+ observer_->DidStart();
+}
+
+void Session::OnResponseParsingError(const std::string& error_message) {
+ // TODO(xjz): Log the |error_message| in the mirroring logs.
+}
+
void Session::SetTargetPlayoutDelay(base::TimeDelta playout_delay) {
if (audio_stream_)
audio_stream_->SetTargetPlayoutDelay(playout_delay);
@@ -317,10 +540,78 @@ void Session::SetTargetPlayoutDelay(base::TimeDelta playout_delay) {
video_stream_->SetTargetPlayoutDelay(playout_delay);
}
-void Session::OnOfferAnswerExchangeTimeout() {
- VLOG(1) << "OFFER/ANSWER exchange timed out.";
- DCHECK(client_);
- client_->OnError(SESSION_START_ERROR);
+void Session::CreateAndSendOffer() {
+ // The random AES key and initialization vector pair used by all streams in
+ // this session.
+ const std::string aes_key = MakeRandomString(16); // AES-128.
+ const std::string aes_iv = MakeRandomString(16); // AES has 128-bit blocks.
+ std::vector<FrameSenderConfig> audio_configs;
+ std::vector<FrameSenderConfig> video_configs;
+
+ // Generate stream list with supported audio / video configs.
+ base::Value::ListStorage stream_list;
+ int stream_index = 0;
+ if (sink_info_.capability != DeviceCapability::VIDEO_ONLY) {
+ FrameSenderConfig config = MirrorSettings::GetDefaultAudioConfig(
+ RtpPayloadType::AUDIO_OPUS, Codec::CODEC_AUDIO_OPUS);
+ AddSenderConfig(base::RandInt(kAudioSsrcMin, kAudioSsrcMax), config,
+ aes_key, aes_iv, &audio_configs);
+ AddStreamObject(stream_index++, "OPUS", audio_configs.back(),
+ mirror_settings_, &stream_list);
+ }
+ if (sink_info_.capability != DeviceCapability::AUDIO_ONLY) {
+ const int32_t video_ssrc = base::RandInt(kVideoSsrcMin, kVideoSsrcMax);
+ if (IsHardwareVP8EncodingSupported(GetSupportedVeaProfiles())) {
+ FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig(
+ RtpPayloadType::VIDEO_VP8, Codec::CODEC_VIDEO_VP8);
+ config.use_external_encoder = true;
+ AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs);
+ AddStreamObject(stream_index++, "VP8", video_configs.back(),
+ mirror_settings_, &stream_list);
+ }
+ if (IsHardwareH264EncodingSupported(GetSupportedVeaProfiles())) {
+ FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig(
+ RtpPayloadType::VIDEO_H264, Codec::CODEC_VIDEO_H264);
+ config.use_external_encoder = true;
+ AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs);
+ AddStreamObject(stream_index++, "H264", video_configs.back(),
+ mirror_settings_, &stream_list);
+ }
+ if (video_configs.empty()) {
+ FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig(
+ RtpPayloadType::VIDEO_VP8, Codec::CODEC_VIDEO_VP8);
+ AddSenderConfig(video_ssrc, config, aes_key, aes_iv, &video_configs);
+ AddStreamObject(stream_index++, "VP8", video_configs.back(),
+ mirror_settings_, &stream_list);
+ }
+ }
+ DCHECK(!audio_configs.empty() || !video_configs.empty());
+
+ // Assemble the OFFER message.
+ const std::string cast_mode = "mirroring";
+ base::Value offer(base::Value::Type::DICTIONARY);
+ offer.SetKey("castMode", base::Value(cast_mode));
+ offer.SetKey("receiverGetStatus", base::Value("true"));
+ offer.SetKey("supportedStreams", base::Value(stream_list));
+
+ const int32_t sequence_number = message_dispatcher_.GetNextSeqNumber();
+ base::Value offer_message(base::Value::Type::DICTIONARY);
+ offer_message.SetKey("type", base::Value("OFFER"));
+ offer_message.SetKey("sessionId", base::Value(session_id_));
+ offer_message.SetKey("seqNum", base::Value(sequence_number));
+ offer_message.SetKey("offer", std::move(offer));
+
+ CastMessage message_to_receiver;
+ message_to_receiver.message_namespace = kWebRtcNamespace;
+ const bool did_serialize_offer = base::JSONWriter::Write(
+ offer_message, &message_to_receiver.json_format_data);
+ DCHECK(did_serialize_offer);
+
+ message_dispatcher_.RequestReply(
+ message_to_receiver, ResponseType::ANSWER, sequence_number,
+ kOfferAnswerExchangeTimeout,
+ base::BindOnce(&Session::OnAnswer, base::Unretained(this), cast_mode,
+ audio_configs, video_configs));
}
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/session.h b/chromium/components/mirroring/service/session.h
index 00cf32b7a22..efc7d8b125b 100644
--- a/chromium/components/mirroring/service/session.h
+++ b/chromium/components/mirroring/service/session.h
@@ -6,9 +6,14 @@
#define COMPONENTS_MIRRORING_SERVICE_SESSION_H_
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/single_thread_task_runner.h"
#include "components/mirroring/service/interface.h"
+#include "components/mirroring/service/message_dispatcher.h"
+#include "components/mirroring/service/mirror_settings.h"
#include "components/mirroring/service/rtp_stream.h"
+#include "components/mirroring/service/session_monitor.h"
+#include "components/mirroring/service/wifi_status_monitor.h"
#include "media/cast/cast_environment.h"
#include "media/cast/net/cast_transport_defines.h"
@@ -22,20 +27,32 @@ class CastTransport;
namespace mirroring {
+struct ReceiverResponse;
class VideoCaptureClient;
-
+class SessionMonitor;
+
+// Controls a mirroring session, including audio/video capturing and Cast
+// Streaming. When constructed, it does OFFER/ANSWER exchange with the mirroring
+// receiver. Mirroring starts when the exchange succeeds and stops when this
+// class is destructed or error occurs. |observer| will get notified when status
+// changes. |outbound_channel| is responsible for sending messages to the
+// mirroring receiver through Cast Channel.
class Session final : public RtpStreamClient {
public:
- Session(SessionType session_type,
- const net::IPEndPoint& receiver_endpoint,
- SessionClient* client);
+ Session(int32_t session_id,
+ const CastSinkInfo& sink_info,
+ const gfx::Size& max_resolution,
+ SessionObserver* observer,
+ ResourceProvider* resource_provider,
+ CastMessageChannel* outbound_channel);
+ // TODO(xjz): Add mojom::CastMessageChannelRequest |inbound_channel| to
+ // receive inbound messages.
+
~Session() override;
// RtpStreamClient implemenation.
void OnError(const std::string& message) override;
void RequestRefreshFrame() override;
- media::VideoEncodeAccelerator::SupportedProfiles
- GetSupportedVideoEncodeAcceleratorProfiles() override;
void CreateVideoEncodeAccelerator(
const media::cast::ReceiveVideoEncodeAcceleratorCallback& callback)
override;
@@ -49,16 +66,23 @@ class Session final : public RtpStreamClient {
std::unique_ptr<std::vector<media::cast::FrameEvent>> frame_events,
std::unique_ptr<std::vector<media::cast::PacketEvent>> packet_events);
- private:
- // Callback when OFFER/ANSWER message exchange finishes. Starts a mirroing
- // session.
- void StartInternal(const net::IPEndPoint& receiver_endpoint,
- const media::cast::FrameSenderConfig& audio_config,
- const media::cast::FrameSenderConfig& video_config);
+ // Callback for ANSWER response. If the ANSWER is invalid, |observer_| will
+ // get notified with error, and session is stopped. Otherwise, capturing and
+ // streaming are started with the selected configs.
+ void OnAnswer(
+ const std::string& cast_mode,
+ const std::vector<media::cast::FrameSenderConfig>& audio_configs,
+ const std::vector<media::cast::FrameSenderConfig>& video_configs,
+ const ReceiverResponse& response);
+ // Called by |message_dispatcher_| when error occurs while parsing the
+ // responses.
+ void OnResponseParsingError(const std::string& error_message);
+
+ private:
void StopSession();
- // Notify |client_| that error occurred and close the session.
+ // Notify |observer_| that error occurred and close the session.
void ReportError(SessionError error);
// Callback by Audio/VideoSender to indicate encoder status change.
@@ -67,12 +91,26 @@ class Session final : public RtpStreamClient {
// Callback by media::cast::VideoSender to set a new target playout delay.
void SetTargetPlayoutDelay(base::TimeDelta playout_delay);
- // Callback by |start_timeout_timer_|.
- void OnOfferAnswerExchangeTimeout();
+ media::VideoEncodeAccelerator::SupportedProfiles GetSupportedVeaProfiles();
+
+ // Create and send OFFER message.
+ void CreateAndSendOffer();
- SessionClient* client_ = nullptr;
+ // Provided by Cast Media Route Provider (MRP).
+ const int32_t session_id_;
+ const CastSinkInfo sink_info_;
- // Create on StartInternal().
+ SessionObserver* observer_ = nullptr;
+ ResourceProvider* resource_provider_ = nullptr;
+ MirrorSettings mirror_settings_;
+
+ MessageDispatcher message_dispatcher_;
+
+ network::mojom::NetworkContextPtr network_context_;
+
+ base::Optional<SessionMonitor> session_monitor_;
+
+ // Created after OFFER/ANSWER exchange succeeds.
std::unique_ptr<AudioRtpStream> audio_stream_;
std::unique_ptr<VideoRtpStream> video_stream_;
std::unique_ptr<VideoCaptureClient> video_capture_client_;
@@ -81,9 +119,6 @@ class Session final : public RtpStreamClient {
scoped_refptr<base::SingleThreadTaskRunner> audio_encode_thread_ = nullptr;
scoped_refptr<base::SingleThreadTaskRunner> video_encode_thread_ = nullptr;
- // Fire if the OFFER/ANSWER exchange times out.
- base::OneShotTimer start_timeout_timer_;
-
base::WeakPtrFactory<Session> weak_factory_;
};
diff --git a/chromium/components/mirroring/service/session_monitor.cc b/chromium/components/mirroring/service/session_monitor.cc
new file mode 100644
index 00000000000..94e6d77438a
--- /dev/null
+++ b/chromium/components/mirroring/service/session_monitor.cc
@@ -0,0 +1,412 @@
+// 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 "components/mirroring/service/session_monitor.h"
+
+#include <string>
+#include <vector>
+
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/stl_util.h"
+#include "components/mirroring/service/value_util.h"
+#include "components/mirroring/service/wifi_status_monitor.h"
+#include "components/version_info/version_info.h"
+#include "media/cast/cast_environment.h"
+#include "media/cast/logging/log_serializer.h"
+#include "media/cast/logging/logging_defines.h"
+#include "media/cast/logging/proto/raw_events.pb.h"
+#include "media/cast/logging/raw_event_subscriber_bundle.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
+
+namespace mirroring {
+
+namespace {
+
+// Interval between snapshots of Cast Streaming events/stats.
+constexpr base::TimeDelta kSnapshotInterval =
+ base::TimeDelta::FromMinutes(15); // Typical: 15 min → ~3 MB
+
+// The maximum number of bytes for receiver's setup info. 256kb should be more
+// than sufficient.
+constexpr int kMaxSetupResponseSizeBytes = 262144;
+
+// Returns the number of milliseconds elapsed since epoch.
+int32_t ToEpochTime(const base::Time& time) {
+ return (time - base::Time::UnixEpoch()).InMilliseconds();
+}
+
+// Helper to parse the response for receiver setup info and update the tags.
+bool AddReceiverSetupInfoTags(const std::string& response, base::Value* tags) {
+ DCHECK(tags);
+ std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
+
+ std::string build_version;
+ bool is_connected = false;
+ bool is_on_ethernet = false;
+ bool has_update = false;
+ int32_t uptime_seconds = 0;
+
+ const bool result =
+ value && value->is_dict() &&
+ GetString(*value, "cast_build_revision", &build_version) &&
+ GetBool(*value, "connected", &is_connected) &&
+ GetBool(*value, "ethernet_connected", &is_on_ethernet) &&
+ GetBool(*value, "has_update", &has_update) &&
+ GetInt(*value, "uptime", &uptime_seconds);
+ if (result) {
+ tags->SetKey("receiverVersion", base::Value(build_version));
+ tags->SetKey("receiverConnected", base::Value(is_connected));
+ tags->SetKey("receiverOnEthernet", base::Value(is_on_ethernet));
+ tags->SetKey("receiverHasUpdatePending", base::Value(has_update));
+ tags->SetKey("receiverUptimeSeconds", base::Value(uptime_seconds));
+ }
+ return result;
+}
+
+const char* ToErrorMessage(SessionError error) {
+ switch (error) {
+ case ANSWER_TIME_OUT:
+ return "ANSWER response time out";
+ case ANSWER_NOT_OK:
+ return "Received an error ANSWER response";
+ case ANSWER_MISMATCHED_CAST_MODE:
+ return "Unexpected cast mode in ANSWER response.";
+ case ANSWER_MISMATCHED_SSRC_LENGTH:
+ return "sendIndexes.length != ssrcs.length in ANSWER";
+ case ANSWER_SELECT_MULTIPLE_AUDIO:
+ return "Receiver selected audio RTP stream twice in ANSWER";
+ case ANSWER_SELECT_MULTIPLE_VIDEO:
+ return "Receiver selected video RTP stream twice in ANSWER";
+ case ANSWER_SELECT_INVALID_INDEX:
+ return "Invalid indexes selected in ANSWER";
+ case ANSWER_NO_AUDIO_OR_VIDEO:
+ return "Incorrect ANSWER message: No audio or Video.";
+ case AUDIO_CAPTURE_ERROR:
+ return "Audio capture error";
+ case VIDEO_CAPTURE_ERROR:
+ return "Video capture error";
+ case RTP_STREAM_ERROR:
+ return "RTP stream error";
+ case ENCODING_ERROR:
+ return "Encoding status error";
+ case CAST_TRANSPORT_ERROR:
+ return "Transport error";
+ }
+ return "";
+}
+
+} // namespace
+
+SessionMonitor::SessionMonitor(
+ int max_retention_bytes,
+ const net::IPAddress& receiver_address,
+ base::Value session_tags,
+ network::mojom::URLLoaderFactoryPtr loader_factory,
+ std::unique_ptr<WifiStatusMonitor> wifi_status_monitor)
+ : max_retention_bytes_(max_retention_bytes),
+ receiver_address_(receiver_address),
+ session_tags_(std::move(session_tags)),
+ url_loader_factory_(std::move(loader_factory)),
+ wifi_status_monitor_(std::move(wifi_status_monitor)),
+ stored_snapshots_bytes_(0),
+ weak_factory_(this) {}
+
+SessionMonitor::~SessionMonitor() {}
+
+void SessionMonitor::StartStreamingSession(
+ scoped_refptr<media::cast::CastEnvironment> cast_environment,
+ SessionType session_type,
+ bool is_remoting) {
+ DCHECK(!event_subscribers_);
+ DCHECK(!snapshot_timer_.IsRunning());
+
+ std::string session_activity =
+ session_type == AUDIO_AND_VIDEO
+ ? "audio+video"
+ : session_type == AUDIO_ONLY ? "audio-only" : "video-only";
+ session_activity += is_remoting ? " remoting" : " streaming";
+ session_tags_.SetKey("activity", base::Value(session_activity));
+
+ // Query the receiver setup info at the beginning of each streaming session.
+ QueryReceiverSetupInfo();
+
+ // Start collecting Cast Streaming events/stats.
+ event_subscribers_ = std::make_unique<media::cast::RawEventSubscriberBundle>(
+ std::move(cast_environment));
+ if (session_type != VIDEO_ONLY)
+ event_subscribers_->AddEventSubscribers(true /* is_audio */);
+ if (session_type != AUDIO_ONLY)
+ event_subscribers_->AddEventSubscribers(false /* is_audio */);
+
+ // Start periodically snapshotting Cast Streaming events/stats.
+ snapshot_timer_.Start(FROM_HERE, kSnapshotInterval,
+ base::BindRepeating(&SessionMonitor::TakeSnapshot,
+ base::Unretained(this)));
+
+ start_time_ = base::Time::Now();
+}
+
+void SessionMonitor::StopStreamingSession() {
+ if (snapshot_timer_.IsRunning()) {
+ snapshot_timer_.Stop();
+ TakeSnapshot(); // Final snapshot of this streaming session.
+ }
+ event_subscribers_.reset();
+}
+
+void SessionMonitor::OnStreamingError(SessionError error) {
+ DVLOG(2) << error;
+
+ if (!snapshot_timer_.IsRunning())
+ return; // Ignore errors before streaming starts.
+ // If the error has already been recorded, do not overwrite it with another
+ // since the first will usually be the most indicative of the problem.
+ if (error_.has_value())
+ return;
+ error_time_ = base::Time::Now();
+ error_.emplace(error);
+}
+
+std::vector<SessionMonitor::EventsAndStats>
+SessionMonitor::AssembleBundlesAndClear(
+ const std::vector<int32_t>& bundle_sizes) {
+ std::vector<EventsAndStats> bundles;
+ // If a streaming session is currently active, take a snapshot now so that all
+ // data collected since the last automatic periodic snapshot is included in
+ // the bundle.
+ if (snapshot_timer_.IsRunning()) {
+ TakeSnapshot();
+ snapshot_timer_.Reset();
+ }
+
+ for (int32_t max_bytes : bundle_sizes)
+ bundles.emplace_back(MakeSliceOfSnapshots(max_bytes));
+ snapshots_.clear();
+ stored_snapshots_bytes_ = 0;
+ return bundles;
+}
+
+SessionMonitor::EventsAndStats SessionMonitor::MakeSliceOfSnapshots(
+ int32_t max_bytes) {
+ // Immediately subtract two bytes for array brackets ("[]") since
+ // AssembleSnapshotsAndClear() will produce a JSON array of each snapshot's
+ // stats JSON.
+ max_bytes -= 2;
+ base::circular_deque<EventsAndStats> slice;
+ for (int i = snapshots_.size() - 1; i >= 0; --i) {
+ max_bytes -= snapshots_[i].second.length() + 1 /* size of the comma */;
+ // If insufficient bytes remain to retain the current stats JSON, stop
+ // adding more Snapshots to the slice.
+ if (max_bytes < 0)
+ break;
+ slice.emplace_front(std::make_pair("", snapshots_[i].second));
+ // If sufficient bytes remain to include the current events Blob, add it to
+ // the slice.
+ if (!snapshots_[i].first.empty()) {
+ const int32_t events_size = snapshots_[i].first.length();
+ if (max_bytes >= events_size) {
+ slice[0].first = snapshots_[i].first;
+ max_bytes -= events_size;
+ }
+ }
+ }
+
+ EventsAndStats bundle;
+ if (slice.empty())
+ return bundle;
+
+ bundle.second = "[";
+ for (size_t i = 0; i < slice.size(); i++) {
+ // To produce a single events gzipped-data Blob, simply concatenate the
+ // individual gzipped-data Blobs. The spec for gzip explicitly allows for
+ // this. :-)
+ bundle.first += slice[i].first;
+ // To produce the JSON stats array, concatenate the mix of string and Blob
+ // objects to produce a single UTF-8 encoded string.
+ if (i > 0)
+ bundle.second += ",";
+ bundle.second += slice[i].second;
+ }
+ bundle.second += "]";
+
+ return bundle;
+}
+
+void SessionMonitor::TakeSnapshot() {
+ // Session-level tags.
+ base::Value tags = session_tags_.Clone();
+
+ // Add snapshot-level tags.
+ tags.SetKey("startTime", base::Value(ToEpochTime(start_time_)));
+ const base::Time end_time = base::Time::Now();
+ tags.SetKey("endTime", base::Value(ToEpochTime(end_time)));
+ start_time_ = end_time;
+
+ if (wifi_status_monitor_) {
+ const std::vector<WifiStatus> wifi_status =
+ wifi_status_monitor_->GetRecentValues();
+ base::Value::ListStorage wifi_status_list;
+ for (const auto& status : wifi_status) {
+ base::Value status_value(base::Value::Type::DICTIONARY);
+ status_value.SetKey("wifiSnr", base::Value(status.snr));
+ status_value.SetKey("wifiSpeed", base::Value(status.speed));
+ status_value.SetKey("timestamp",
+ base::Value(ToEpochTime(status.timestamp)));
+ wifi_status_list.emplace_back(std::move(status_value));
+ }
+ tags.SetKey("receiverWifiStatus", base::Value(wifi_status_list));
+ }
+
+ // Streaming error tags (if any).
+ if (error_.has_value()) {
+ tags.SetKey("streamingErrorTime", base::Value(ToEpochTime(error_time_)));
+ tags.SetKey("streamingErrorMessage",
+ base::Value(ToErrorMessage(error_.value())));
+ error_.reset();
+ }
+
+ std::string tags_string;
+ base::JSONWriter::Write(tags, &tags_string);
+
+ // Collect raw events.
+ std::string events = GetEventLogsAndReset(true, tags_string) +
+ GetEventLogsAndReset(false, tags_string);
+
+ // Collect stats.
+ std::unique_ptr<base::DictionaryValue> audio_stats =
+ base::DictionaryValue::From(GetStatsAndReset(true));
+ std::unique_ptr<base::DictionaryValue> video_stats =
+ base::DictionaryValue::From(GetStatsAndReset(false));
+ base::DictionaryValue stats;
+ if (audio_stats)
+ stats.MergeDictionary(audio_stats.get());
+ if (video_stats)
+ stats.MergeDictionary(video_stats.get());
+ stats.SetKey("tags", std::move(tags));
+ std::string stats_string;
+ base::JSONWriter::Write(stats, &stats_string);
+
+ int snapshots_bytes =
+ stored_snapshots_bytes_ + events.size() + stats_string.size();
+ // Prune |snapshots_| if necessary.
+ while (snapshots_bytes > max_retention_bytes_) {
+ snapshots_bytes -= snapshots_[0].first.size();
+ snapshots_[0].first = std::string();
+ if (snapshots_bytes <= max_retention_bytes_)
+ break;
+ snapshots_bytes -= snapshots_[0].second.size();
+ snapshots_.pop_front();
+ }
+ snapshots_.emplace_back(std::make_pair(events, stats_string));
+ stored_snapshots_bytes_ = snapshots_bytes;
+}
+
+std::string SessionMonitor::GetEventLogsAndReset(
+ bool is_audio,
+ const std::string& extra_data) {
+ std::string result;
+ if (!event_subscribers_.get())
+ return result;
+
+ media::cast::EncodingEventSubscriber* subscriber =
+ event_subscribers_->GetEncodingEventSubscriber(is_audio);
+ if (!subscriber)
+ return result;
+
+ media::cast::proto::LogMetadata metadata;
+ media::cast::FrameEventList frame_events;
+ media::cast::PacketEventList packet_events;
+
+ subscriber->GetEventsAndReset(&metadata, &frame_events, &packet_events);
+
+ if (!extra_data.empty())
+ metadata.set_extra_data(extra_data);
+ media::cast::proto::GeneralDescription* gen_desc =
+ metadata.mutable_general_description();
+ gen_desc->set_product(version_info::GetProductName());
+ gen_desc->set_product_version(version_info::GetVersionNumber());
+ gen_desc->set_os(version_info::GetOSType());
+
+ result.resize(media::cast::kMaxSerializedBytes);
+ int output_bytes;
+ // TODO(xjz): media::cast::SerializeEvents() shouldn't require the caller to
+ // pre-allocate the memory. It should return a string result.
+ if (media::cast::SerializeEvents(metadata, frame_events, packet_events,
+ true /* compress */,
+ media::cast::kMaxSerializedBytes,
+ base::data(result), &output_bytes)) {
+ result.resize(output_bytes);
+ } else {
+ result.clear();
+ }
+ return result;
+}
+
+std::unique_ptr<base::Value> SessionMonitor::GetStatsAndReset(bool is_audio) {
+ if (!event_subscribers_.get())
+ return nullptr;
+
+ media::cast::StatsEventSubscriber* subscriber =
+ event_subscribers_->GetStatsEventSubscriber(is_audio);
+ if (!subscriber)
+ return nullptr;
+
+ std::unique_ptr<base::Value> stats = subscriber->GetStats();
+ subscriber->Reset();
+ return stats;
+}
+
+void SessionMonitor::QueryReceiverSetupInfo() {
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->method = "GET";
+ resource_request->url = GURL("http://" + receiver_address_.ToString() +
+ ":8008/setup/eureka_info");
+ net::NetworkTrafficAnnotationTag traffic_annotation =
+ net::DefineNetworkTrafficAnnotation("mirroring_get_setup_info", R"(
+ semantics {
+ sender: "Mirroring Service"
+ description:
+ "Mirroring Service sends a request to the receiver to obtain its "
+ "setup info such as the build version, the model name, etc. The "
+ "data is included in mirroring feedback for analysis."
+ trigger:
+ "A tab/desktop mirroring session starts."
+ data: "An HTTP GET request."
+ destination: OTHER
+ destination_other:
+ "A mirroring receiver, such as a ChromeCast device."
+ }
+ policy {
+ cookies_allowed: NO
+ setting: "This feature cannot be disabled in settings."
+ chrome_policy {
+ EnableMediaRouter {
+ EnableMediaRouter: false
+ }
+ }
+ })");
+ std::unique_ptr<network::SimpleURLLoader> url_loader =
+ network::SimpleURLLoader::Create(std::move(resource_request),
+ traffic_annotation);
+ network::SimpleURLLoader* url_loader_ptr = url_loader.get();
+ url_loader_ptr->DownloadToString(
+ url_loader_factory_.get(),
+ base::BindOnce(
+ [](base::WeakPtr<SessionMonitor> monitor,
+ std::unique_ptr<network::SimpleURLLoader> url_loader,
+ std::unique_ptr<std::string> response) {
+ if (monitor) {
+ if (url_loader->NetError() != net::OK ||
+ !AddReceiverSetupInfoTags(*response, &monitor->session_tags_))
+ VLOG(2) << "Unable to fetch/parse receiver setup info.";
+ }
+ },
+ weak_factory_.GetWeakPtr(), std::move(url_loader)),
+ kMaxSetupResponseSizeBytes);
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/session_monitor.h b/chromium/components/mirroring/service/session_monitor.h
new file mode 100644
index 00000000000..ba4892345c2
--- /dev/null
+++ b/chromium/components/mirroring/service/session_monitor.h
@@ -0,0 +1,142 @@
+// 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 COMPONENTS_MIRRORING_SERVICE_SESSION_MONITOR_H_
+#define COMPONENTS_MIRRORING_SERVICE_SESSION_MONITOR_H_
+
+#include "components/mirroring/service/interface.h"
+
+#include <memory>
+#include <string>
+
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "base/timer/timer.h"
+#include "base/values.h"
+#include "components/mirroring/service/interface.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace media {
+namespace cast {
+class CastEnvironment;
+class RawEventSubscriberBundle;
+} // namespace cast
+} // namespace media
+
+namespace mirroring {
+
+class WifiStatusMonitor;
+
+// Monitors a single mirroring session's multiple Cast Streaming "subsessions",
+// collecting and managing the following information:
+//
+// 1. WiFi signal strength, SNR, etc. on the connection between sender and
+// receiver.
+// 2. Extra "tags": Information about both the sender and receiver, such as
+// software versions, mirroring settings, and network configuration.
+// 3. Snapshots of Cast Streaming event logs (frame- and packet-level events
+// that will allow an analysis of the data flows and a diagnosing of any
+// issues occurring in-the-wild). Start/StopStreamingSession() are called
+// to notify this monitor whenever each (of multiple) Cast Streaming
+// sessions starts and ends.
+//
+// Either during or at the end of a session, AssembleBundlesAndClear() is called
+// to re-package all of the information across multiple snapshots together into
+// one bundle, whose blobs can then be included in user feedback report uploads.
+//
+// To avoid unbounded memory use, older data is discarded automatically if too
+// much is accumulating.
+class SessionMonitor {
+ public:
+ using EventsAndStats =
+ std::pair<std::string /* events */, std::string /* stats */>;
+ SessionMonitor(int max_retention_bytes,
+ const net::IPAddress& receiver_address,
+ base::Value session_tags,
+ network::mojom::URLLoaderFactoryPtr loader_factory,
+ std::unique_ptr<WifiStatusMonitor> wifi_status_monitor);
+
+ ~SessionMonitor();
+
+ enum SessionType {
+ AUDIO_ONLY,
+ VIDEO_ONLY,
+ AUDIO_AND_VIDEO,
+ };
+
+ // Notifies this monitor that it may now start/stop monitoring Cast Streaming
+ // events/stats.
+ void StartStreamingSession(
+ scoped_refptr<media::cast::CastEnvironment> cast_environment,
+ SessionType session_type,
+ bool is_remoting);
+ void StopStreamingSession();
+
+ // Called when error occurs. Only records the first error since last snapshot.
+ void OnStreamingError(SessionError error);
+
+ // Assembles one or more bundles of data, for inclusion in user feedback
+ // reports. The snapshot history is cleared each time this method is called,
+ // and so no two calls to this method will return the same data. The caller
+ // may request that multiple bundles be produced. This is used, for example,
+ // to get one bundle that meets the upload size maximum in addition to
+ // another. The total data size in bytes is strictly less-than-or-equal to
+ // |bundle_sizes|.
+ std::vector<EventsAndStats> AssembleBundlesAndClear(
+ const std::vector<int32_t>& bundle_sizes);
+
+ // Takes a snapshot of recent Cast Streaming events and statistics.
+ void TakeSnapshot();
+
+ private:
+ // Query the receiver for its current setup and uptime.
+ void QueryReceiverSetupInfo();
+
+ // Get Cast Streaming events/stats.
+ std::string GetEventLogsAndReset(bool is_audio,
+ const std::string& extra_data);
+ std::unique_ptr<base::Value> GetStatsAndReset(bool is_audio);
+
+ // Assemble the most-recent events+stats snapshots to a bundle of a byte size
+ // less than or equal to |max_bytes|.
+ EventsAndStats MakeSliceOfSnapshots(int32_t max_bytes);
+
+ const int max_retention_bytes_; // Maximum number of bytes to keep.
+
+ const net::IPAddress receiver_address_;
+
+ base::Value session_tags_; // Streaming session-level tags.
+
+ network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+
+ // Monitors the WiFi status if not null.
+ const std::unique_ptr<WifiStatusMonitor> wifi_status_monitor_;
+
+ std::unique_ptr<media::cast::RawEventSubscriberBundle> event_subscribers_;
+
+ base::RepeatingTimer snapshot_timer_;
+
+ // The time that the current snapshot starts.
+ base::Time start_time_;
+
+ // The most recent snapshots, from oldest to newest. The total size of the
+ // data stored in this list is bounded by |max_retention_bytes_|.
+ base::circular_deque<EventsAndStats> snapshots_;
+
+ // The number of bytes currently stored in |snapshots_|.
+ int stored_snapshots_bytes_;
+
+ base::Time error_time_;
+ base::Optional<SessionError> error_;
+
+ base::WeakPtrFactory<SessionMonitor> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionMonitor);
+};
+
+} // namespace mirroring
+
+#endif // COMPONENTS_MIRRORING_SERVICE_SESSION_MONITOR_H_
diff --git a/chromium/components/mirroring/service/session_monitor_unittest.cc b/chromium/components/mirroring/service/session_monitor_unittest.cc
new file mode 100644
index 00000000000..c887eaa0a9f
--- /dev/null
+++ b/chromium/components/mirroring/service/session_monitor_unittest.cc
@@ -0,0 +1,397 @@
+// 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 "components/mirroring/service/session_monitor.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/macros.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/time/default_tick_clock.h"
+#include "components/mirroring/service/message_dispatcher.h"
+#include "components/mirroring/service/mirror_settings.h"
+#include "components/mirroring/service/value_util.h"
+#include "components/mirroring/service/wifi_status_monitor.h"
+#include "media/cast/cast_environment.h"
+#include "media/cast/test/utility/net_utility.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/base/ip_endpoint.h"
+#include "services/network/test/test_url_loader_factory.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace mirroring {
+
+namespace {
+
+constexpr int kRetentionBytes = 512 * 1024; // 512k.
+
+void VerifyStringValue(const base::Value& raw_value,
+ const std::string& key,
+ const std::string& expected_value) {
+ std::string data;
+ EXPECT_TRUE(GetString(raw_value, key, &data));
+ EXPECT_EQ(expected_value, data);
+}
+
+void VerifyBoolValue(const base::Value& raw_value,
+ const std::string& key,
+ bool expected_value) {
+ bool data;
+ EXPECT_TRUE(GetBool(raw_value, key, &data));
+ EXPECT_EQ(expected_value, data);
+}
+
+void VerifyIntValue(const base::Value& raw_value,
+ const std::string& key,
+ int32_t expected_value) {
+ int32_t data;
+ EXPECT_TRUE(GetInt(raw_value, key, &data));
+ EXPECT_EQ(expected_value, data);
+}
+
+void VerifyWifiStatus(const base::Value& raw_value,
+ double starting_snr,
+ int starting_speed,
+ int num_of_status) {
+ EXPECT_TRUE(raw_value.is_dict());
+ auto* found = raw_value.FindKey("tags");
+ EXPECT_TRUE(found && found->is_dict());
+ auto* wifi_status = found->FindKey("receiverWifiStatus");
+ EXPECT_TRUE(wifi_status && wifi_status->is_list());
+ const base::Value::ListStorage& status_list = wifi_status->GetList();
+ EXPECT_EQ(num_of_status, static_cast<int>(status_list.size()));
+ for (int i = 0; i < num_of_status; ++i) {
+ double snr = -1;
+ int32_t speed = -1;
+ int32_t timestamp = 0;
+ EXPECT_TRUE(GetDouble(status_list[i], "wifiSnr", &snr));
+ EXPECT_EQ(starting_snr + i, snr);
+ EXPECT_TRUE(GetInt(status_list[i], "wifiSpeed", &speed));
+ EXPECT_EQ(starting_speed + i, speed);
+ EXPECT_TRUE(GetInt(status_list[i], "timestamp", &timestamp));
+ }
+}
+
+} // namespace
+
+class SessionMonitorTest : public CastMessageChannel, public ::testing::Test {
+ public:
+ SessionMonitorTest()
+ : receiver_address_(media::cast::test::GetFreeLocalPort().address()),
+ message_dispatcher_(this, error_callback_.Get()) {}
+ ~SessionMonitorTest() override {}
+
+ protected:
+ // CastMessageChannel implementation.
+ MOCK_METHOD1(Send, void(const CastMessage&));
+
+ void CreateSessionMonitor(int max_bytes, std::string* expected_settings) {
+ EXPECT_CALL(*this, Send(::testing::_)).Times(::testing::AtLeast(1));
+ auto wifi_status_monitor =
+ std::make_unique<WifiStatusMonitor>(123, &message_dispatcher_);
+ network::mojom::URLLoaderFactoryPtr url_loader_factory;
+ auto test_url_loader_factory =
+ std::make_unique<network::TestURLLoaderFactory>();
+ url_loader_factory_ = test_url_loader_factory.get();
+ mojo::MakeStrongBinding(std::move(test_url_loader_factory),
+ mojo::MakeRequest(&url_loader_factory));
+ MirrorSettings mirror_settings;
+ base::Value session_tags(base::Value::Type::DICTIONARY);
+ base::Value settings = mirror_settings.ToDictionaryValue();
+ if (expected_settings)
+ EXPECT_TRUE(base::JSONWriter::Write(settings, expected_settings));
+ session_tags.SetKey("mirrorSettings", std::move(settings));
+ session_tags.SetKey("receiverProductName", base::Value("ChromeCast"));
+ session_tags.SetKey("shouldCaptureAudio", base::Value(true));
+ session_tags.SetKey("shouldCaptureVideo", base::Value(true));
+ session_monitor_ = std::make_unique<SessionMonitor>(
+ max_bytes, receiver_address_, std::move(session_tags),
+ std::move(url_loader_factory), std::move(wifi_status_monitor));
+ }
+
+ // Generates and sends |num_of_responses| WiFi status.
+ void SendWifiStatus(double starting_snr,
+ int starting_speed,
+ int num_of_responses) {
+ for (int i = 0; i < num_of_responses; ++i) {
+ CastMessage message;
+ message.message_namespace = kWebRtcNamespace;
+ message.json_format_data =
+ "{\"seqNum\":" +
+ std::to_string(message_dispatcher_.GetNextSeqNumber()) +
+ ","
+ "\"type\": \"STATUS_RESPONSE\","
+ "\"result\": \"ok\","
+ "\"status\": {"
+ "\"wifiSnr\":" +
+ std::to_string(starting_snr + i) +
+ ","
+ "\"wifiSpeed\": [1234, 5678, 3000, " +
+ std::to_string(starting_speed + i) +
+ "],"
+ "\"wifiFcsError\": [12, 13, 12, 12]}" // This will be ignored.
+ "}";
+ static_cast<CastMessageChannel*>(&message_dispatcher_)->Send(message);
+ scoped_task_environment_.RunUntilIdle();
+ }
+ }
+
+ void StartStreamingSession() {
+ cast_environment_ = new media::cast::CastEnvironment(
+ base::DefaultTickClock::GetInstance(),
+ scoped_task_environment_.GetMainThreadTaskRunner(),
+ scoped_task_environment_.GetMainThreadTaskRunner(),
+ scoped_task_environment_.GetMainThreadTaskRunner());
+ EXPECT_TRUE(session_monitor_);
+ session_monitor_->StartStreamingSession(cast_environment_,
+ SessionMonitor::AUDIO_AND_VIDEO,
+ false /* is_remoting */);
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ void StopStreamingSession() {
+ EXPECT_TRUE(session_monitor_);
+ session_monitor_->StopStreamingSession();
+ cast_environment_ = nullptr;
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ std::vector<SessionMonitor::EventsAndStats> AssembleBundleAndVerify(
+ const std::vector<int32_t>& bundle_sizes) {
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ session_monitor_->AssembleBundlesAndClear(bundle_sizes);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_EQ(bundle_sizes.size(), bundles.size());
+ for (size_t i = 0; i < bundles.size(); ++i) {
+ EXPECT_FALSE(bundles[i].first.empty());
+ EXPECT_FALSE(bundles[i].second.empty());
+ EXPECT_LE(
+ static_cast<int>(bundles[i].first.size() + bundles[i].second.size()),
+ bundle_sizes[i]);
+ }
+ return bundles;
+ }
+
+ base::Value ReadStats(const std::string& stats_string) {
+ std::unique_ptr<base::Value> stats_ptr =
+ base::JSONReader::Read(stats_string);
+ EXPECT_TRUE(stats_ptr);
+ base::Value stats = base::Value::FromUniquePtrValue(std::move(stats_ptr));
+ EXPECT_TRUE(stats.is_list());
+ return stats;
+ }
+
+ void SendReceiverSetupInfo(const std::string& setup_info) {
+ url_loader_factory_->AddResponse(
+ "http://" + receiver_address_.ToString() + ":8008/setup/eureka_info",
+ setup_info);
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ void TakeSnapshot() {
+ ASSERT_TRUE(session_monitor_);
+ session_monitor_->TakeSnapshot();
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ void ReportError(SessionError error) {
+ ASSERT_TRUE(session_monitor_);
+ session_monitor_->OnStreamingError(error);
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ const net::IPAddress receiver_address_;
+ base::MockCallback<MessageDispatcher::ErrorCallback> error_callback_;
+ MessageDispatcher message_dispatcher_;
+ network::TestURLLoaderFactory* url_loader_factory_ = nullptr;
+ std::unique_ptr<SessionMonitor> session_monitor_;
+ scoped_refptr<media::cast::CastEnvironment> cast_environment_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionMonitorTest);
+};
+
+TEST_F(SessionMonitorTest, ProvidesExpectedTags) {
+ std::string expected_settings;
+ CreateSessionMonitor(kRetentionBytes, &expected_settings);
+ SendWifiStatus(34, 2000, 5);
+ StartStreamingSession();
+ std::vector<int32_t> bundle_sizes({kRetentionBytes});
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ AssembleBundleAndVerify(bundle_sizes);
+
+ base::Value stats = ReadStats(bundles[0].second);
+ const base::Value::ListStorage& stats_list = stats.GetList();
+ ASSERT_EQ(1u, stats_list.size());
+ // Verify tags.
+ EXPECT_TRUE(stats_list[0].is_dict());
+ auto* found = stats_list[0].FindKey("video");
+ EXPECT_TRUE(found && found->is_dict());
+ found = stats_list[0].FindKey("audio");
+ EXPECT_TRUE(found && found->is_dict());
+ found = stats_list[0].FindKey("tags");
+ EXPECT_TRUE(found && found->is_dict());
+ // Verify session tags.
+ VerifyStringValue(*found, "activity", "audio+video streaming");
+ VerifyStringValue(*found, "receiverProductName", "ChromeCast");
+ VerifyBoolValue(*found, "shouldCaptureAudio", true);
+ VerifyBoolValue(*found, "shouldCaptureVideo", true);
+ auto* settings = found->FindKey("mirrorSettings");
+ EXPECT_TRUE(settings && settings->is_dict());
+ std::string settings_string;
+ EXPECT_TRUE(base::JSONWriter::Write(*settings, &settings_string));
+ EXPECT_EQ(expected_settings, settings_string);
+ VerifyWifiStatus(stats_list[0], 34, 2000, 5);
+}
+
+// Test for multiple streaming sessions.
+TEST_F(SessionMonitorTest, MultipleSessions) {
+ CreateSessionMonitor(kRetentionBytes, nullptr);
+ StartStreamingSession();
+ StopStreamingSession();
+ // Starts the second streaming session.
+ StartStreamingSession();
+ StopStreamingSession();
+ std::vector<int32_t> bundle_sizes({kRetentionBytes});
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ AssembleBundleAndVerify(bundle_sizes);
+ base::Value stats = ReadStats(bundles[0].second);
+ const base::Value::ListStorage& stats_list = stats.GetList();
+ // There should be two sessions in the recorded stats.
+ EXPECT_EQ(2u, stats_list.size());
+}
+
+TEST_F(SessionMonitorTest, ConfigureMaxRetentionBytes) {
+ // 2500 is an estimate number of bytes for a snapshot that includes tags and
+ // five WiFi status records.
+ CreateSessionMonitor(2500, nullptr);
+ SendWifiStatus(34, 2000, 5);
+ StartStreamingSession();
+ StopStreamingSession();
+ SendWifiStatus(54, 3000, 5);
+ StartStreamingSession();
+ StopStreamingSession();
+ std::vector<int32_t> bundle_sizes({kRetentionBytes});
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ AssembleBundleAndVerify(bundle_sizes);
+ base::Value stats = ReadStats(bundles[0].second);
+ const base::Value::ListStorage& stats_list = stats.GetList();
+ // Expect to only record the second session.
+ ASSERT_EQ(1u, stats_list.size());
+ VerifyWifiStatus(stats_list[0], 54, 3000, 5);
+}
+
+TEST_F(SessionMonitorTest, AssembleBundlesWithVaryingSizes) {
+ CreateSessionMonitor(kRetentionBytes, nullptr);
+ SendWifiStatus(34, 2000, 5);
+ StartStreamingSession();
+ StopStreamingSession();
+ SendWifiStatus(54, 3000, 5);
+ StartStreamingSession();
+ StopStreamingSession();
+ std::vector<int32_t> bundle_sizes({2500, kRetentionBytes});
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ AssembleBundleAndVerify(bundle_sizes);
+
+ // Expect the first bundle has only one session.
+ base::Value stats = ReadStats(bundles[0].second);
+ const base::Value::ListStorage& stats_list = stats.GetList();
+ // Expect to only record the second session.
+ ASSERT_EQ(1u, stats_list.size());
+ VerifyWifiStatus(stats_list[0], 54, 3000, 5);
+
+ // Expect the second bundle has both sessions.
+ stats = ReadStats(bundles[1].second);
+ const base::Value::ListStorage& stats_list2 = stats.GetList();
+ ASSERT_EQ(2u, stats_list2.size());
+ VerifyWifiStatus(stats_list2[0], 34, 2000, 5);
+ VerifyWifiStatus(stats_list2[1], 54, 3000, 5);
+}
+
+TEST_F(SessionMonitorTest, ErrorTags) {
+ CreateSessionMonitor(kRetentionBytes, nullptr);
+ StartStreamingSession();
+ TakeSnapshot(); // Take the first snapshot.
+ ReportError(VIDEO_CAPTURE_ERROR);
+ ReportError(RTP_STREAM_ERROR);
+ TakeSnapshot(); // Take the second snapshot.
+ StopStreamingSession(); // Take the third snapshot.
+
+ std::vector<int32_t> bundle_sizes({kRetentionBytes});
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ AssembleBundleAndVerify(bundle_sizes);
+ base::Value stats = ReadStats(bundles[0].second);
+ const base::Value::ListStorage& stats_list = stats.GetList();
+ // There should be three snapshots in the bundle.
+ ASSERT_EQ(3u, stats_list.size());
+
+ // The first and the third snapshots should have no error tags.
+ auto* tags = stats_list[0].FindKey("tags");
+ ASSERT_TRUE(tags);
+ EXPECT_FALSE(tags->FindKey("streamingErrorTime"));
+ EXPECT_FALSE(tags->FindKey("streamingErrorMessage"));
+ tags = stats_list[2].FindKey("tags");
+ ASSERT_TRUE(tags);
+ EXPECT_FALSE(tags->FindKey("streamingErrorTime"));
+ EXPECT_FALSE(tags->FindKey("streamingErrorMessage"));
+
+ // The second snapshot should have the error tags. Only the first error is
+ // recorded.
+ tags = stats_list[1].FindKey("tags");
+ ASSERT_TRUE(tags && tags->FindKey("streamingErrorTime"));
+ VerifyStringValue(*tags, "streamingErrorMessage", "Video capture error");
+}
+
+TEST_F(SessionMonitorTest, ReceiverSetupInfo) {
+ CreateSessionMonitor(kRetentionBytes, nullptr);
+ StartStreamingSession();
+ // This snapshot should have no receiver setup info tags.
+ TakeSnapshot();
+
+ const std::string receiver_setup_info =
+ "{"
+ "\"cast_build_revision\": \"1.26.0.1\","
+ "\"connected\": true,"
+ "\"ethernet_connected\": false,"
+ "\"has_update\": false,"
+ "\"uptime\": 132536 }";
+
+ SendReceiverSetupInfo(receiver_setup_info);
+
+ // A final snapshot is taken and should have receiver setup info tags.
+ StopStreamingSession();
+
+ std::vector<int32_t> bundle_sizes({kRetentionBytes});
+ std::vector<SessionMonitor::EventsAndStats> bundles =
+ AssembleBundleAndVerify(bundle_sizes);
+ base::Value stats = ReadStats(bundles[0].second);
+ const base::Value::ListStorage& stats_list = stats.GetList();
+ // There should be two snapshots in the bundle.
+ EXPECT_EQ(2u, stats_list.size());
+
+ // The first snapshot should have no receiver setup info tags.
+ auto* tags = stats_list[0].FindKey("tags");
+ ASSERT_TRUE(tags);
+ EXPECT_FALSE(tags->FindKey("receiverVersion"));
+ EXPECT_FALSE(tags->FindKey("receiverConnected"));
+ EXPECT_FALSE(tags->FindKey("receiverOnEthernet"));
+ EXPECT_FALSE(tags->FindKey("receiverHasUpdatePending"));
+ EXPECT_FALSE(tags->FindKey("receiverUptimeSeconds"));
+
+ // The second snapshot should have the receiver setup info tags.
+ tags = stats_list[1].FindKey("tags");
+ ASSERT_TRUE(tags);
+ VerifyStringValue(*tags, "receiverVersion", "1.26.0.1");
+ VerifyBoolValue(*tags, "receiverConnected", true);
+ VerifyBoolValue(*tags, "receiverOnEthernet", false);
+ VerifyBoolValue(*tags, "receiverHasUpdatePending", false);
+ VerifyIntValue(*tags, "receiverUptimeSeconds", 132536);
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/session_unittest.cc b/chromium/components/mirroring/service/session_unittest.cc
index 751fa584225..973c0daed8a 100644
--- a/chromium/components/mirroring/service/session_unittest.cc
+++ b/chromium/components/mirroring/service/session_unittest.cc
@@ -6,17 +6,22 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/json/json_reader.h"
#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/simple_test_tick_clock.h"
+#include "base/values.h"
#include "components/mirroring/service/fake_network_service.h"
#include "components/mirroring/service/fake_video_capture_host.h"
#include "components/mirroring/service/interface.h"
+#include "components/mirroring/service/mirror_settings.h"
+#include "components/mirroring/service/receiver_response.h"
+#include "components/mirroring/service/value_util.h"
#include "media/cast/test/utility/default_config.h"
#include "media/cast/test/utility/net_utility.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "net/base/ip_address.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,74 +32,125 @@ using media::cast::Packet;
namespace mirroring {
-class SessionTest : public SessionClient, public ::testing::Test {
+const int kSessionId = 5;
+
+class SessionTest : public ResourceProvider,
+ public SessionObserver,
+ public CastMessageChannel,
+ public ::testing::Test {
public:
- SessionTest() : weak_factory_(this) {
+ SessionTest() : receiver_endpoint_(media::cast::test::GetFreeLocalPort()) {
testing_clock_.Advance(base::TimeTicks::Now() - base::TimeTicks());
}
~SessionTest() override { scoped_task_environment_.RunUntilIdle(); }
- // SessionClient implemenation.
+ // SessionObserver implemenation.
MOCK_METHOD1(OnError, void(SessionError));
MOCK_METHOD0(DidStart, void());
MOCK_METHOD0(DidStop, void());
- MOCK_METHOD0(OnOfferAnswerExchange, void());
+
+ // ResourceProvider implemenation.
MOCK_METHOD0(OnGetVideoCaptureHost, void());
MOCK_METHOD0(OnGetNetworkContext, void());
+ // Called when sends OFFER message.
+ MOCK_METHOD0(OnOffer, void());
+
+ // CastMessageHandler implementation. For outbound messages.
+ void Send(const CastMessage& message) {
+ EXPECT_TRUE(message.message_namespace == kWebRtcNamespace ||
+ message.message_namespace == kRemotingNamespace);
+ std::unique_ptr<base::Value> value =
+ base::JSONReader::Read(message.json_format_data);
+ ASSERT_TRUE(value);
+ std::string message_type;
+ EXPECT_TRUE(GetString(*value, "type", &message_type));
+ if (message_type == "OFFER") {
+ EXPECT_TRUE(GetInt(*value, "seqNum", &offer_sequence_number_));
+ OnOffer();
+ }
+ }
+
void GetVideoCaptureHost(
media::mojom::VideoCaptureHostRequest request) override {
video_host_ = std::make_unique<FakeVideoCaptureHost>(std::move(request));
OnGetVideoCaptureHost();
}
- void GetNewWorkContext(
+ void GetNetworkContext(
network::mojom::NetworkContextRequest request) override {
network_context_ = std::make_unique<MockNetworkContext>(std::move(request));
OnGetNetworkContext();
}
- void DoOfferAnswerExchange(
- const std::vector<FrameSenderConfig>& audio_configs,
- const std::vector<FrameSenderConfig>& video_configs,
- GetAnswerCallback callback) override {
- OnOfferAnswerExchange();
- std::move(callback).Run(FrameSenderConfig(),
- media::cast::GetDefaultVideoSenderConfig());
+ void SendAnswer() {
+ FrameSenderConfig config = MirrorSettings::GetDefaultVideoConfig(
+ media::cast::RtpPayloadType::VIDEO_VP8,
+ media::cast::Codec::CODEC_VIDEO_VP8);
+ std::vector<FrameSenderConfig> video_configs;
+ video_configs.emplace_back(config);
+
+ auto answer = std::make_unique<Answer>();
+ answer->udp_port = receiver_endpoint_.port();
+ answer->send_indexes.push_back(0);
+ answer->ssrcs.push_back(32);
+ answer->cast_mode = "mirroring";
+
+ ReceiverResponse response;
+ response.result = "ok";
+ response.type = ResponseType::ANSWER;
+ response.sequence_number = offer_sequence_number_;
+ response.answer = std::move(answer);
+
+ session_->OnAnswer("mirroring", std::vector<FrameSenderConfig>(),
+ video_configs, response);
}
protected:
+ void CreateSession() {
+ CastSinkInfo sink_info;
+ sink_info.ip_address = receiver_endpoint_.address();
+ sink_info.capability = DeviceCapability::AUDIO_AND_VIDEO;
+ // Expect to receive OFFER message when session is created.
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, OnGetNetworkContext()).Times(1);
+ EXPECT_CALL(*this, OnError(_)).Times(0);
+ EXPECT_CALL(*this, OnOffer())
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ session_ = std::make_unique<Session>(
+ kSessionId, sink_info, gfx::Size(1920, 1080), this, this, this);
+ run_loop.Run();
+ }
+
base::test::ScopedTaskEnvironment scoped_task_environment_;
+ const net::IPEndPoint receiver_endpoint_;
base::SimpleTestTickClock testing_clock_;
std::unique_ptr<Session> session_;
std::unique_ptr<FakeVideoCaptureHost> video_host_;
std::unique_ptr<MockNetworkContext> network_context_;
- base::WeakPtrFactory<SessionTest> weak_factory_;
+ int32_t offer_sequence_number_ = -1;
private:
DISALLOW_COPY_AND_ASSIGN(SessionTest);
};
TEST_F(SessionTest, Mirroring) {
- // Start a mirroring session.
+ CreateSession();
+ scoped_task_environment_.RunUntilIdle();
{
+ // Except mirroing session starts after receiving ANSWER message.
base::RunLoop run_loop;
EXPECT_CALL(*this, OnGetVideoCaptureHost()).Times(1);
- EXPECT_CALL(*this, OnGetNetworkContext()).Times(1);
- EXPECT_CALL(*this, OnOfferAnswerExchange()).Times(1);
+ EXPECT_CALL(*this, OnError(_)).Times(0);
EXPECT_CALL(*this, DidStart())
.WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
- session_ =
- std::make_unique<Session>(SessionType::AUDIO_AND_VIDEO,
- media::cast::test::GetFreeLocalPort(), this);
+ SendAnswer();
run_loop.Run();
}
-
scoped_task_environment_.RunUntilIdle();
-
{
base::RunLoop run_loop;
// Expect to send out some UDP packets.
@@ -106,7 +162,6 @@ TEST_F(SessionTest, Mirroring) {
video_host_->SendOneFrame(gfx::Size(64, 32), testing_clock_.NowTicks());
run_loop.Run();
}
-
scoped_task_environment_.RunUntilIdle();
// Stop the session.
@@ -121,4 +176,21 @@ TEST_F(SessionTest, Mirroring) {
scoped_task_environment_.RunUntilIdle();
}
+TEST_F(SessionTest, AnswerTimeout) {
+ CreateSession();
+ scoped_task_environment_.RunUntilIdle();
+ {
+ // Expect error.
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, OnGetVideoCaptureHost()).Times(0);
+ EXPECT_CALL(*this, DidStop()).Times(1);
+ EXPECT_CALL(*this, OnError(ANSWER_TIME_OUT))
+ .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
+ session_->OnAnswer("mirroring", std::vector<FrameSenderConfig>(),
+ std::vector<FrameSenderConfig>(), ReceiverResponse());
+ run_loop.Run();
+ }
+ scoped_task_environment_.RunUntilIdle();
+}
+
} // namespace mirroring
diff --git a/chromium/components/mirroring/service/udp_socket_client.cc b/chromium/components/mirroring/service/udp_socket_client.cc
index f7677692753..96923f88ee8 100644
--- a/chromium/components/mirroring/service/udp_socket_client.cc
+++ b/chromium/components/mirroring/service/udp_socket_client.cc
@@ -47,16 +47,18 @@ net::NetworkTrafficAnnotationTag GetNetworkTrafficAnnotationTag() {
} // namespace
UdpSocketClient::UdpSocketClient(const net::IPEndPoint& remote_endpoint,
- network::mojom::NetworkContextPtr context,
+ network::mojom::NetworkContext* context,
base::OnceClosure error_callback)
: remote_endpoint_(remote_endpoint),
- network_context_(std::move(context)),
+ network_context_(context),
error_callback_(std::move(error_callback)),
binding_(this),
bytes_sent_(0),
allow_sending_(false),
num_packets_pending_receive_(0),
- weak_factory_(this) {}
+ weak_factory_(this) {
+ DCHECK(network_context_);
+}
UdpSocketClient::~UdpSocketClient() {}
diff --git a/chromium/components/mirroring/service/udp_socket_client.h b/chromium/components/mirroring/service/udp_socket_client.h
index 2eda92f8d4d..c58a7ee3987 100644
--- a/chromium/components/mirroring/service/udp_socket_client.h
+++ b/chromium/components/mirroring/service/udp_socket_client.h
@@ -24,7 +24,7 @@ class UdpSocketClient final : public media::cast::PacketTransport,
public network::mojom::UDPSocketReceiver {
public:
UdpSocketClient(const net::IPEndPoint& remote_endpoint,
- network::mojom::NetworkContextPtr context,
+ network::mojom::NetworkContext* context,
base::OnceClosure error_callback);
~UdpSocketClient() override;
@@ -54,7 +54,7 @@ class UdpSocketClient final : public media::cast::PacketTransport,
const base::Optional<net::IPEndPoint>& addr);
const net::IPEndPoint remote_endpoint_;
- const network::mojom::NetworkContextPtr network_context_;
+ network::mojom::NetworkContext* const network_context_;
base::OnceClosure error_callback_;
mojo::Binding<network::mojom::UDPSocketReceiver> binding_;
diff --git a/chromium/components/mirroring/service/udp_socket_client_unittest.cc b/chromium/components/mirroring/service/udp_socket_client_unittest.cc
index 9ec51e25aa2..b88f2c7adfd 100644
--- a/chromium/components/mirroring/service/udp_socket_client_unittest.cc
+++ b/chromium/components/mirroring/service/udp_socket_client_unittest.cc
@@ -30,11 +30,10 @@ namespace mirroring {
class UdpSocketClientTest : public ::testing::Test {
public:
UdpSocketClientTest() {
- network::mojom::NetworkContextPtr network_context_ptr;
network_context_ = std::make_unique<MockNetworkContext>(
- mojo::MakeRequest(&network_context_ptr));
+ mojo::MakeRequest(&network_context_ptr_));
udp_transport_client_ = std::make_unique<UdpSocketClient>(
- media::cast::test::GetFreeLocalPort(), std::move(network_context_ptr),
+ media::cast::test::GetFreeLocalPort(), network_context_ptr_.get(),
base::OnceClosure());
}
@@ -49,6 +48,7 @@ class UdpSocketClientTest : public ::testing::Test {
protected:
base::test::ScopedTaskEnvironment scoped_task_environment_;
+ network::mojom::NetworkContextPtr network_context_ptr_;
std::unique_ptr<MockNetworkContext> network_context_;
std::unique_ptr<UdpSocketClient> udp_transport_client_;
std::unique_ptr<Packet> received_packet_;
diff --git a/chromium/components/mirroring/service/value_util.cc b/chromium/components/mirroring/service/value_util.cc
new file mode 100644
index 00000000000..63eec3d9999
--- /dev/null
+++ b/chromium/components/mirroring/service/value_util.cc
@@ -0,0 +1,95 @@
+// 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 "components/mirroring/service/value_util.h"
+
+namespace mirroring {
+
+bool GetInt(const base::Value& value, const std::string& key, int32_t* result) {
+ auto* found = value.FindKey(key);
+ if (!found || found->is_none())
+ return true;
+ if (found->is_int()) {
+ *result = found->GetInt();
+ return true;
+ }
+ return false;
+}
+
+bool GetDouble(const base::Value& value,
+ const std::string& key,
+ double* result) {
+ auto* found = value.FindKey(key);
+ if (!found || found->is_none())
+ return true;
+ if (found->is_double()) {
+ *result = found->GetDouble();
+ return true;
+ }
+ if (found->is_int()) {
+ *result = found->GetInt();
+ return true;
+ }
+ return false;
+}
+
+bool GetString(const base::Value& value,
+ const std::string& key,
+ std::string* result) {
+ auto* found = value.FindKey(key);
+ if (!found || found->is_none())
+ return true;
+ if (found->is_string()) {
+ *result = found->GetString();
+ return true;
+ }
+ return false;
+}
+
+bool GetBool(const base::Value& value, const std::string& key, bool* result) {
+ auto* found = value.FindKey(key);
+ if (!found || found->is_none())
+ return true;
+ if (found->is_bool()) {
+ *result = found->GetBool();
+ return true;
+ }
+ return false;
+}
+
+bool GetIntArray(const base::Value& value,
+ const std::string& key,
+ std::vector<int32_t>* result) {
+ auto* found = value.FindKey(key);
+ if (!found || found->is_none())
+ return true;
+ if (!found->is_list())
+ return false;
+ for (const auto& number_value : found->GetList()) {
+ if (number_value.is_int())
+ result->emplace_back(number_value.GetInt());
+ else
+ return false;
+ }
+ return true;
+}
+
+bool GetStringArray(const base::Value& value,
+ const std::string& key,
+ std::vector<std::string>* result) {
+ auto* found = value.FindKey(key);
+ if (!found || found->is_none())
+ return true;
+ if (!found->is_list())
+ return false;
+ for (const auto& string_value : found->GetList()) {
+ if (string_value.is_string())
+ result->emplace_back(string_value.GetString());
+ else
+ return false;
+ }
+ return true;
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/value_util.h b/chromium/components/mirroring/service/value_util.h
new file mode 100644
index 00000000000..d3247747999
--- /dev/null
+++ b/chromium/components/mirroring/service/value_util.h
@@ -0,0 +1,39 @@
+// 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 COMPONENTS_MIRRORING_SERVICE_VALUE_UTIL_H_
+#define COMPONENTS_MIRRORING_SERVICE_VALUE_UTIL_H_
+
+#include <string>
+
+#include "base/values.h"
+
+namespace mirroring {
+
+// Read certain type of data from dictionary |value| if |key| exits. Return
+// false if |key| exists and the type of the data mismatches. Return true
+// otherwise.
+
+bool GetInt(const base::Value& value, const std::string& key, int32_t* result);
+
+bool GetDouble(const base::Value& value,
+ const std::string& key,
+ double* result);
+
+bool GetString(const base::Value& value,
+ const std::string& key,
+ std::string* result);
+
+bool GetBool(const base::Value& value, const std::string& key, bool* result);
+
+bool GetIntArray(const base::Value& value,
+ const std::string& key,
+ std::vector<int32_t>* result);
+
+bool GetStringArray(const base::Value& value,
+ const std::string& key,
+ std::vector<std::string>* result);
+} // namespace mirroring
+
+#endif // COMPONENTS_MIRRORING_SERVICE_VALUE_UTIL_H_
diff --git a/chromium/components/mirroring/service/video_capture_client.cc b/chromium/components/mirroring/service/video_capture_client.cc
index bbbd088f87f..24ef5467d77 100644
--- a/chromium/components/mirroring/service/video_capture_client.cc
+++ b/chromium/components/mirroring/service/video_capture_client.cc
@@ -14,8 +14,10 @@ namespace {
constexpr int kDeviceId = 0;
} // namespace
-VideoCaptureClient::VideoCaptureClient(media::mojom::VideoCaptureHostPtr host)
- : video_capture_host_(std::move(host)),
+VideoCaptureClient::VideoCaptureClient(const media::VideoCaptureParams& params,
+ media::mojom::VideoCaptureHostPtr host)
+ : params_(params),
+ video_capture_host_(std::move(host)),
binding_(this),
weak_factory_(this) {
DCHECK(video_capture_host_);
@@ -36,8 +38,7 @@ void VideoCaptureClient::Start(FrameDeliverCallback deliver_callback,
media::mojom::VideoCaptureObserverPtr observer;
binding_.Bind(mojo::MakeRequest(&observer));
- video_capture_host_->Start(kDeviceId, 0, media::VideoCaptureParams(),
- std::move(observer));
+ video_capture_host_->Start(kDeviceId, 0, params_, std::move(observer));
}
void VideoCaptureClient::Stop() {
@@ -63,7 +64,7 @@ void VideoCaptureClient::Resume(FrameDeliverCallback deliver_callback) {
return;
}
frame_deliver_callback_ = std::move(deliver_callback);
- video_capture_host_->Resume(kDeviceId, 0, media::VideoCaptureParams());
+ video_capture_host_->Resume(kDeviceId, 0, params_);
}
void VideoCaptureClient::RequestRefreshFrame() {
@@ -100,15 +101,15 @@ void VideoCaptureClient::OnStateChanged(media::mojom::VideoCaptureState state) {
}
}
-void VideoCaptureClient::OnBufferCreated(
+void VideoCaptureClient::OnNewBuffer(
int32_t buffer_id,
- mojo::ScopedSharedBufferHandle handle) {
+ media::mojom::VideoBufferHandlePtr buffer_handle) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- DCHECK(handle.is_valid());
DVLOG(3) << __func__ << ": buffer_id=" << buffer_id;
+ DCHECK(buffer_handle->is_shared_buffer_handle());
- const auto insert_result =
- client_buffers_.emplace(std::make_pair(buffer_id, std::move(handle)));
+ const auto insert_result = client_buffers_.emplace(std::make_pair(
+ buffer_id, std::move(buffer_handle->get_shared_buffer_handle())));
DCHECK(insert_result.second);
}
@@ -118,13 +119,11 @@ void VideoCaptureClient::OnBufferReady(int32_t buffer_id,
DVLOG(3) << __func__ << ": buffer_id=" << buffer_id;
bool consume_buffer = !frame_deliver_callback_.is_null();
- if ((info->pixel_format != media::PIXEL_FORMAT_I420 &&
- info->pixel_format != media::PIXEL_FORMAT_Y16) ||
- info->storage_type != media::VideoPixelStorage::CPU) {
+ if (info->pixel_format != media::PIXEL_FORMAT_I420 &&
+ info->pixel_format != media::PIXEL_FORMAT_Y16) {
consume_buffer = false;
- LOG(DFATAL) << "Wrong pixel format or storage, got pixel format:"
- << VideoPixelFormatToString(info->pixel_format)
- << ", storage:" << static_cast<int>(info->storage_type);
+ LOG(DFATAL) << "Wrong pixel format, got pixel format:"
+ << VideoPixelFormatToString(info->pixel_format);
}
if (!consume_buffer) {
video_capture_host_->ReleaseBuffer(kDeviceId, buffer_id, -1.0);
diff --git a/chromium/components/mirroring/service/video_capture_client.h b/chromium/components/mirroring/service/video_capture_client.h
index 3c43cd0bb4e..a417dcdef2f 100644
--- a/chromium/components/mirroring/service/video_capture_client.h
+++ b/chromium/components/mirroring/service/video_capture_client.h
@@ -16,6 +16,7 @@
namespace media {
class VideoFrame;
+class VideoFrameMetadata;
} // namespace media
namespace mirroring {
@@ -26,7 +27,8 @@ namespace mirroring {
// received through the media::mojom::VideoCaptureObserver interface.
class VideoCaptureClient : public media::mojom::VideoCaptureObserver {
public:
- explicit VideoCaptureClient(media::mojom::VideoCaptureHostPtr host);
+ VideoCaptureClient(const media::VideoCaptureParams& params,
+ media::mojom::VideoCaptureHostPtr host);
~VideoCaptureClient() override;
using FrameDeliverCallback = base::RepeatingCallback<void(
@@ -47,8 +49,8 @@ class VideoCaptureClient : public media::mojom::VideoCaptureObserver {
// media::mojom::VideoCaptureObserver implementations.
void OnStateChanged(media::mojom::VideoCaptureState state) override;
- void OnBufferCreated(int32_t buffer_id,
- mojo::ScopedSharedBufferHandle handle) override;
+ void OnNewBuffer(int32_t buffer_id,
+ media::mojom::VideoBufferHandlePtr buffer_handle) override;
void OnBufferReady(int32_t buffer_id,
media::mojom::VideoFrameInfoPtr info) override;
void OnBufferDestroyed(int32_t buffer_id) override;
@@ -64,6 +66,7 @@ class VideoCaptureClient : public media::mojom::VideoCaptureObserver {
void OnClientBufferFinished(int buffer_id,
double consumer_resource_utilization);
+ const media::VideoCaptureParams params_;
const media::mojom::VideoCaptureHostPtr video_capture_host_;
// Called when capturing failed to start.
diff --git a/chromium/components/mirroring/service/video_capture_client_unittest.cc b/chromium/components/mirroring/service/video_capture_client_unittest.cc
index a903d086508..0e8637d84b7 100644
--- a/chromium/components/mirroring/service/video_capture_client_unittest.cc
+++ b/chromium/components/mirroring/service/video_capture_client_unittest.cc
@@ -8,6 +8,8 @@
#include "base/test/mock_callback.h"
#include "base/test/scoped_task_environment.h"
#include "components/mirroring/service/fake_video_capture_host.h"
+#include "media/base/video_frame.h"
+#include "media/base/video_frame_metadata.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,8 +28,7 @@ media::mojom::VideoFrameInfoPtr GetVideoFrameInfo(const gfx::Size& size) {
base::TimeTicks());
return media::mojom::VideoFrameInfo::New(
base::TimeDelta(), metadata.GetInternalValues().Clone(),
- media::PIXEL_FORMAT_I420, media::VideoPixelStorage::CPU, size,
- gfx::Rect(size));
+ media::PIXEL_FORMAT_I420, size, gfx::Rect(size));
}
} // namespace
@@ -38,7 +39,8 @@ class VideoCaptureClientTest : public ::testing::Test {
media::mojom::VideoCaptureHostPtr host;
host_impl_ =
std::make_unique<FakeVideoCaptureHost>(mojo::MakeRequest(&host));
- client_ = std::make_unique<VideoCaptureClient>(std::move(host));
+ client_ = std::make_unique<VideoCaptureClient>(media::VideoCaptureParams(),
+ std::move(host));
}
~VideoCaptureClientTest() override {
@@ -79,7 +81,12 @@ TEST_F(VideoCaptureClientTest, Basic) {
run_loop.Run();
}
scoped_task_environment_.RunUntilIdle();
- client_->OnBufferCreated(0, mojo::SharedBufferHandle::Create(100000));
+
+ media::mojom::VideoBufferHandlePtr buffer_handle =
+ media::mojom::VideoBufferHandle::New();
+ buffer_handle->set_shared_buffer_handle(
+ mojo::SharedBufferHandle::Create(100000));
+ client_->OnNewBuffer(0, std::move(buffer_handle));
scoped_task_environment_.RunUntilIdle();
{
base::RunLoop run_loop;
diff --git a/chromium/components/mirroring/service/wifi_status_monitor.cc b/chromium/components/mirroring/service/wifi_status_monitor.cc
new file mode 100644
index 00000000000..fa676b4a87d
--- /dev/null
+++ b/chromium/components/mirroring/service/wifi_status_monitor.cc
@@ -0,0 +1,80 @@
+// 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 "components/mirroring/service/wifi_status_monitor.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "components/mirroring/service/message_dispatcher.h"
+
+namespace mirroring {
+
+namespace {
+
+// The interval to query the status.
+constexpr base::TimeDelta kQueryInterval = base::TimeDelta::FromMinutes(2);
+
+// The maximum number of recent status to be kept.
+constexpr int kMaxRecords = 30;
+
+} // namespace
+
+WifiStatusMonitor::WifiStatusMonitor(int32_t session_id,
+ MessageDispatcher* message_dispatcher)
+ : session_id_(session_id), message_dispatcher_(message_dispatcher) {
+ DCHECK(message_dispatcher_);
+ message_dispatcher_->Subscribe(
+ ResponseType::STATUS_RESPONSE,
+ base::BindRepeating(&WifiStatusMonitor::RecordStatus,
+ base::Unretained(this)));
+ query_timer_.Start(FROM_HERE, kQueryInterval,
+ base::BindRepeating(&WifiStatusMonitor::QueryStatus,
+ base::Unretained(this)));
+ QueryStatus();
+}
+
+WifiStatusMonitor::~WifiStatusMonitor() {
+ message_dispatcher_->Unsubscribe(ResponseType::STATUS_RESPONSE);
+}
+
+std::vector<WifiStatus> WifiStatusMonitor::GetRecentValues() {
+ std::vector<WifiStatus> recent_status(recent_status_.begin(),
+ recent_status_.end());
+ recent_status_.clear();
+ return recent_status;
+}
+
+void WifiStatusMonitor::QueryStatus() {
+ base::Value query(base::Value::Type::DICTIONARY);
+ query.SetKey("type", base::Value("GET_STATUS"));
+ query.SetKey("sessionId", base::Value(session_id_));
+ query.SetKey("seqNum", base::Value(message_dispatcher_->GetNextSeqNumber()));
+ base::Value::ListStorage status;
+ status.emplace_back(base::Value("wifiSnr"));
+ status.emplace_back(base::Value("wifiSpeed"));
+ query.SetKey("get_status", base::Value(status));
+ CastMessage get_status_message;
+ get_status_message.message_namespace = kWebRtcNamespace;
+ const bool did_serialize_query =
+ base::JSONWriter::Write(query, &get_status_message.json_format_data);
+ DCHECK(did_serialize_query);
+ message_dispatcher_->SendOutboundMessage(get_status_message);
+}
+
+void WifiStatusMonitor::RecordStatus(const ReceiverResponse& response) {
+ if (!response.status || response.status->wifi_speed.size() != 4)
+ return;
+ if (recent_status_.size() == kMaxRecords)
+ recent_status_.pop_front();
+ WifiStatus received_status;
+ received_status.snr = response.status->wifi_snr;
+ // Only records the current speed.
+ received_status.speed = response.status->wifi_speed[3];
+ received_status.timestamp = base::Time::Now();
+ recent_status_.emplace_back(received_status);
+}
+
+} // namespace mirroring
diff --git a/chromium/components/mirroring/service/wifi_status_monitor.h b/chromium/components/mirroring/service/wifi_status_monitor.h
new file mode 100644
index 00000000000..ac348ce6d3e
--- /dev/null
+++ b/chromium/components/mirroring/service/wifi_status_monitor.h
@@ -0,0 +1,61 @@
+// 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 COMPONENTS_MIRRORING_SERVICE_WIFI_STATUS_MONITOR_H_
+#define COMPONENTS_MIRRORING_SERVICE_WIFI_STATUS_MONITOR_H_
+
+#include <vector>
+
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+
+namespace mirroring {
+
+class MessageDispatcher;
+struct ReceiverResponse;
+
+struct WifiStatus {
+ double snr;
+ int32_t speed; // The current WiFi speed.
+ base::Time timestamp; // Recording time of this status.
+};
+
+// Periodically sends requests to the Cast device for WiFi network status
+// updates, processes responses, and maintains a recent history of data points.
+// This data can be included in feedback logs to help identify and diagnose
+// issues related to lousy network performance.
+class WifiStatusMonitor {
+ public:
+ // |message_dispatcher| must keep alive during the lifetime of this class.
+ WifiStatusMonitor(int32_t session_id, MessageDispatcher* message_dispatcher);
+ ~WifiStatusMonitor();
+
+ // Gets the recorded status and clear |recent_status_|.
+ std::vector<WifiStatus> GetRecentValues();
+
+ // Sends GET_STATUS message to receiver.
+ void QueryStatus();
+
+ // Callback for the STATUS_RESPONSE message. Records the WiFi status reported
+ // by receiver.
+ void RecordStatus(const ReceiverResponse& response);
+
+ private:
+ const int32_t session_id_;
+
+ MessageDispatcher* const message_dispatcher_; // Outlives this class.
+
+ base::RepeatingTimer query_timer_;
+
+ // Stores the recent status. Will be reset when GetRecentValues() is called.
+ base::circular_deque<WifiStatus> recent_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(WifiStatusMonitor);
+};
+
+} // namespace mirroring
+
+#endif // COMPONENTS_MIRRORING_SERVICE_WIFI_STATUS_MONITOR_H_
diff --git a/chromium/components/mirroring/service/wifi_status_monitor_unittest.cc b/chromium/components/mirroring/service/wifi_status_monitor_unittest.cc
new file mode 100644
index 00000000000..0f7aac1a072
--- /dev/null
+++ b/chromium/components/mirroring/service/wifi_status_monitor_unittest.cc
@@ -0,0 +1,173 @@
+// 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 "components/mirroring/service/wifi_status_monitor.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/values.h"
+#include "components/mirroring/service/message_dispatcher.h"
+#include "components/mirroring/service/value_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+
+namespace mirroring {
+
+namespace {
+
+bool IsNullMessage(const CastMessage& message) {
+ return message.message_namespace.empty() && message.json_format_data.empty();
+}
+
+std::string GetMessageType(const CastMessage& message) {
+ std::string type;
+ std::unique_ptr<base::Value> value =
+ base::JSONReader::Read(message.json_format_data);
+ EXPECT_TRUE(value);
+ EXPECT_TRUE(GetString(*value, "type", &type));
+ return type;
+}
+
+void VerifyRecordedStatus(const std::vector<WifiStatus> recorded_status,
+ double starting_snr,
+ int starting_speed,
+ int num_of_responses) {
+ EXPECT_EQ(num_of_responses, static_cast<int>(recorded_status.size()));
+ for (int i = 0; i < num_of_responses; ++i) {
+ EXPECT_EQ(starting_snr + i, recorded_status[i].snr);
+ EXPECT_EQ(starting_speed + i, recorded_status[i].speed);
+ }
+}
+
+} // namespace
+
+class WifiStatusMonitorTest : public CastMessageChannel,
+ public ::testing::Test {
+ public:
+ WifiStatusMonitorTest() : message_dispatcher_(this, error_callback_.Get()) {}
+
+ ~WifiStatusMonitorTest() override {}
+
+ // CastMessageChannel implementation. For outbound messages.
+ void Send(const CastMessage& message) override {
+ last_outbound_message_.message_namespace = message.message_namespace;
+ last_outbound_message_.json_format_data = message.json_format_data;
+ }
+
+ protected:
+ // Generates and sends |num_of_responses| responses.
+ void SendStatusResponses(double starting_snr,
+ int starting_speed,
+ int num_of_responses) {
+ for (int i = 0; i < num_of_responses; ++i) {
+ const std::string response =
+ "{\"seqNum\":" +
+ std::to_string(message_dispatcher_.GetNextSeqNumber()) +
+ ","
+ "\"type\": \"STATUS_RESPONSE\","
+ "\"result\": \"ok\","
+ "\"status\": {"
+ "\"wifiSnr\":" +
+ std::to_string(starting_snr + i) +
+ ","
+ "\"wifiSpeed\": [1234, 5678, 3000, " +
+ std::to_string(starting_speed + i) +
+ "],"
+ "\"wifiFcsError\": [12, 13, 12, 12]}" // This will be ignored.
+ "}";
+ SendInboundMessage(response);
+ }
+ }
+
+ // Sends an inbound message to |message_dispatcher|.
+ void SendInboundMessage(const std::string& response) {
+ CastMessage message;
+ message.message_namespace = kWebRtcNamespace;
+ message.json_format_data = response;
+ static_cast<CastMessageChannel*>(&message_dispatcher_)->Send(message);
+ scoped_task_environment_.RunUntilIdle();
+ }
+
+ // Creates a WifiStatusMonitor and start monitoring the status.
+ std::unique_ptr<WifiStatusMonitor> StartMonitoring() {
+ EXPECT_TRUE(IsNullMessage(last_outbound_message_));
+ EXPECT_CALL(error_callback_, Run(_)).Times(0);
+ auto status_monitor =
+ std::make_unique<WifiStatusMonitor>(123, &message_dispatcher_);
+ scoped_task_environment_.RunUntilIdle();
+ // Expect to receive request to send GET_STATUS message when create a
+ // WifiStatusMonitor.
+ EXPECT_EQ(kWebRtcNamespace, last_outbound_message_.message_namespace);
+ EXPECT_EQ("GET_STATUS", GetMessageType(last_outbound_message_));
+ // Clear the old outbound message.
+ last_outbound_message_.message_namespace.clear();
+ last_outbound_message_.json_format_data.clear();
+ EXPECT_TRUE(IsNullMessage(last_outbound_message_));
+ return status_monitor;
+ }
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ base::MockCallback<MessageDispatcher::ErrorCallback> error_callback_;
+ MessageDispatcher message_dispatcher_;
+ CastMessage last_outbound_message_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WifiStatusMonitorTest);
+};
+
+TEST_F(WifiStatusMonitorTest, QueryStatusAndRecordResponse) {
+ std::unique_ptr<WifiStatusMonitor> status_monitor = StartMonitoring();
+
+ // Send two responses and verify the data are stored.
+ SendStatusResponses(36.7, 3001, 2);
+ std::vector<WifiStatus> recent_status = status_monitor->GetRecentValues();
+ VerifyRecordedStatus(recent_status, 36.7, 3001, 2);
+
+ // There should be no further status stored.
+ recent_status = status_monitor->GetRecentValues();
+ EXPECT_TRUE(recent_status.empty());
+
+ // Sends more than the maximum number (30) of records that can be stored.
+ SendStatusResponses(36.7, 3001, 40);
+ // Expect that only the recent 30 records were stored.
+ recent_status = status_monitor->GetRecentValues();
+ VerifyRecordedStatus(recent_status, 46.7, 3011, 30);
+}
+
+TEST_F(WifiStatusMonitorTest, IgnoreMalformedStatusMessage) {
+ std::unique_ptr<WifiStatusMonitor> status_monitor = StartMonitoring();
+
+ // Sends a response with incomplete wifiSpeed data and expects it is ignored.
+ const std::string response1 =
+ "{\"seqNum\": 123,"
+ "\"type\": \"STATUS_RESPONSE\","
+ "\"result\": \"ok\","
+ "\"status\": {"
+ "\"wifiSnr\": 32,"
+ "\"wifiSpeed\": [1234, 5678, 3000],"
+ "\"wifiFcsError\": [12, 13, 12, 12]}"
+ "}";
+ SendInboundMessage(response1);
+ std::vector<WifiStatus> recent_status = status_monitor->GetRecentValues();
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_TRUE(recent_status.empty());
+
+ // Sends a response with null status field and expects it is ignored.
+ const std::string response2 =
+ "{\"seqNum\": 123,"
+ "\"type\": \"STATUS_RESPONSE\","
+ "\"status\": null}";
+ SendInboundMessage(response2);
+ recent_status = status_monitor->GetRecentValues();
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_TRUE(recent_status.empty());
+}
+
+} // namespace mirroring
diff --git a/chromium/components/nacl/broker/BUILD.gn b/chromium/components/nacl/broker/BUILD.gn
index fe238f39d88..14641bdd76b 100644
--- a/chromium/components/nacl/broker/BUILD.gn
+++ b/chromium/components/nacl/broker/BUILD.gn
@@ -31,6 +31,7 @@ source_set("broker") {
"//mojo/edk",
"//sandbox",
"//services/service_manager/public/cpp",
+ "//services/service_manager/zygote:zygote_buildflags",
]
if (current_cpu == target_cpu) {
@@ -49,13 +50,6 @@ source_set("content_dummy") {
"//content/public/common/sandbox_init.h",
"//content/public/common/sandboxed_process_launcher_delegate.h",
]
-
- deps = [
- # sandboxed_process_launcher_delegate.h includes headers generated from
- # //content/public/common:zygote_buildflags, so this target needs to have a
- # dep on it as well.
- "//content/public/common:zygote_buildflags",
- ]
}
if (current_cpu == "x86") {
@@ -151,9 +145,9 @@ if (current_cpu == "x86") {
deps = [
"//base",
"//content/public/common:static_switches",
- "//content/public/common:zygote_buildflags",
"//sandbox",
"//services/service_manager/sandbox",
+ "//services/service_manager/zygote:zygote_buildflags",
]
}
diff --git a/chromium/components/nacl/browser/BUILD.gn b/chromium/components/nacl/browser/BUILD.gn
index 43079fb0f11..0f5426351f6 100644
--- a/chromium/components/nacl/browser/BUILD.gn
+++ b/chromium/components/nacl/browser/BUILD.gn
@@ -39,13 +39,13 @@ static_library("browser") {
"//components/url_formatter",
"//content/public/browser",
"//content/public/common",
- "//content/public/common:zygote_buildflags",
"//mojo/edk",
"//native_client/src/trusted/service_runtime:sel_main_chrome",
"//net",
"//ppapi/host",
"//ppapi/proxy:ipc",
"//ppapi/shared_impl",
+ "//services/service_manager/zygote:zygote_buildflags",
]
public_deps = [
@@ -65,6 +65,7 @@ static_library("browser") {
"//components/nacl/loader:nacl_helper_integration",
"//sandbox/linux:sandbox_services",
"//sandbox/linux:suid_sandbox_client",
+ "//services/service_manager/zygote",
]
if (enable_nacl_nonsfi) {
diff --git a/chromium/components/nacl/common/BUILD.gn b/chromium/components/nacl/common/BUILD.gn
index df8a120c317..8f9ef992673 100644
--- a/chromium/components/nacl/common/BUILD.gn
+++ b/chromium/components/nacl/common/BUILD.gn
@@ -51,7 +51,6 @@ if (enable_nacl) {
sources = [
"//content/public/common/content_descriptors.h",
"//content/public/common/content_switches.h",
- "//content/public/common/mojo_channel_switches.h",
"//content/public/common/process_type.h",
]
diff --git a/chromium/components/nacl/loader/BUILD.gn b/chromium/components/nacl/loader/BUILD.gn
index b125e1a663c..c468773ce22 100644
--- a/chromium/components/nacl/loader/BUILD.gn
+++ b/chromium/components/nacl/loader/BUILD.gn
@@ -43,6 +43,10 @@ source_set("minimal") {
"//sandbox",
"//services/service_manager/public/cpp",
]
+
+ if (is_linux) {
+ deps += [ "//services/service_manager/zygote" ]
+ }
}
# This exists just to make 'gn check' happy with :minimal and
@@ -129,6 +133,7 @@ if (is_linux) {
"//mojo/edk",
"//sandbox/linux:sandbox_services",
"//services/service_manager/sandbox",
+ "//services/service_manager/zygote",
"//url/ipc:url_ipc",
]
@@ -249,6 +254,7 @@ if (is_nacl_nonsfi) {
"//sandbox/linux:sandbox",
"//services/service_manager/public/cpp",
"//services/service_manager/sandbox",
+ "//services/service_manager/zygote:zygote_util",
]
}
diff --git a/chromium/components/navigation_interception/intercept_navigation_throttle.cc b/chromium/components/navigation_interception/intercept_navigation_throttle.cc
index b126c386e46..81acec45bb1 100644
--- a/chromium/components/navigation_interception/intercept_navigation_throttle.cc
+++ b/chromium/components/navigation_interception/intercept_navigation_throttle.cc
@@ -52,8 +52,7 @@ InterceptNavigationThrottle::CheckIfShouldIgnoreNavigation(bool is_redirect) {
navigation_handle()->HasUserGesture(), navigation_handle()->IsPost(),
navigation_handle()->GetPageTransition(), is_redirect,
navigation_handle()->IsExternalProtocol(), true,
- navigation_handle()->GetBaseURLForDataURL(),
- navigation_handle()->GetSuggestedFilename());
+ navigation_handle()->GetBaseURLForDataURL());
bool should_ignore_navigation = should_ignore_callback_.Run(
navigation_handle()->GetWebContents(), navigation_params);
return should_ignore_navigation
diff --git a/chromium/components/navigation_interception/navigation_params.cc b/chromium/components/navigation_interception/navigation_params.cc
index 2a60e7c2d47..02d8755a0e2 100644
--- a/chromium/components/navigation_interception/navigation_params.cc
+++ b/chromium/components/navigation_interception/navigation_params.cc
@@ -6,17 +6,15 @@
namespace navigation_interception {
-NavigationParams::NavigationParams(
- const GURL& url,
- const content::Referrer& referrer,
- bool has_user_gesture,
- bool is_post,
- ui::PageTransition transition_type,
- bool is_redirect,
- bool is_external_protocol,
- bool is_main_frame,
- const GURL& base_url_for_data_url,
- const base::Optional<std::string>& suggested_filename)
+NavigationParams::NavigationParams(const GURL& url,
+ const content::Referrer& referrer,
+ bool has_user_gesture,
+ bool is_post,
+ ui::PageTransition transition_type,
+ bool is_redirect,
+ bool is_external_protocol,
+ bool is_main_frame,
+ const GURL& base_url_for_data_url)
: url_(url),
referrer_(referrer),
has_user_gesture_(has_user_gesture),
@@ -25,8 +23,7 @@ NavigationParams::NavigationParams(
is_redirect_(is_redirect),
is_external_protocol_(is_external_protocol),
is_main_frame_(is_main_frame),
- base_url_for_data_url_(base_url_for_data_url),
- suggested_filename_(suggested_filename) {}
+ base_url_for_data_url_(base_url_for_data_url) {}
NavigationParams::~NavigationParams() = default;
diff --git a/chromium/components/navigation_interception/navigation_params.h b/chromium/components/navigation_interception/navigation_params.h
index 1630235f9fc..d14e88f9952 100644
--- a/chromium/components/navigation_interception/navigation_params.h
+++ b/chromium/components/navigation_interception/navigation_params.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_NAVIGATION_INTERCEPTION_NAVIGATION_PARAMS_H_
#define COMPONENTS_NAVIGATION_INTERCEPTION_NAVIGATION_PARAMS_H_
-#include "base/optional.h"
#include "content/public/common/referrer.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
@@ -22,8 +21,7 @@ class NavigationParams {
bool is_redirect,
bool is_external_protocol,
bool is_main_frame,
- const GURL& base_url_for_data_url,
- const base::Optional<std::string>& suggested_filename);
+ const GURL& base_url_for_data_url);
~NavigationParams();
NavigationParams(const NavigationParams&);
NavigationParams& operator=(const NavigationParams&) = delete;
@@ -38,9 +36,6 @@ class NavigationParams {
bool is_external_protocol() const { return is_external_protocol_; }
bool is_main_frame() const { return is_main_frame_; }
const GURL& base_url_for_data_url() const { return base_url_for_data_url_; }
- const base::Optional<std::string>& suggested_filename() const {
- return suggested_filename_;
- }
private:
@@ -53,7 +48,6 @@ class NavigationParams {
bool is_external_protocol_;
bool is_main_frame_;
GURL base_url_for_data_url_;
- base::Optional<std::string> suggested_filename_;
};
} // namespace navigation_interception
diff --git a/chromium/components/navigation_interception/navigation_params_android.cc b/chromium/components/navigation_interception/navigation_params_android.cc
index cc449e499b6..a5d6dcf0d32 100644
--- a/chromium/components/navigation_interception/navigation_params_android.cc
+++ b/chromium/components/navigation_interception/navigation_params_android.cc
@@ -25,17 +25,11 @@ base::android::ScopedJavaLocalRef<jobject> CreateJavaNavigationParams(
ScopedJavaLocalRef<jstring> jstring_referrer =
ConvertUTF8ToJavaString(env, params.referrer().url.spec());
- ScopedJavaLocalRef<jstring> jstring_suggested_filename = nullptr;
- if (params.suggested_filename().has_value()) {
- jstring_suggested_filename =
- ConvertUTF8ToJavaString(env, params.suggested_filename().value());
- }
-
return Java_NavigationParams_create(
env, jstring_url, jstring_referrer, params.is_post(),
params.has_user_gesture(), params.transition_type(), params.is_redirect(),
params.is_external_protocol(), params.is_main_frame(),
- jstring_suggested_filename, has_user_gesture_carryover);
+ has_user_gesture_carryover);
}
} // namespace navigation_interception
diff --git a/chromium/components/net_log/BUILD.gn b/chromium/components/net_log/BUILD.gn
index 133894e8046..dc1750ed536 100644
--- a/chromium/components/net_log/BUILD.gn
+++ b/chromium/components/net_log/BUILD.gn
@@ -17,6 +17,7 @@ static_library("net_log") {
"//components/data_reduction_proxy/core/common",
"//components/version_info",
"//net",
+ "//services/network/public/mojom",
]
}
@@ -31,6 +32,9 @@ source_set("unit_tests") {
"//base/test:test_support",
"//net",
"//net:test_support",
+ "//services/network:network_service",
+ "//services/network/public/cpp",
+ "//services/network/public/cpp:cpp_base",
"//testing/gtest",
]
}
diff --git a/chromium/components/net_log/DEPS b/chromium/components/net_log/DEPS
index efca3dd5b18..4d7f1c77f16 100644
--- a/chromium/components/net_log/DEPS
+++ b/chromium/components/net_log/DEPS
@@ -2,4 +2,5 @@ include_rules = [
"+components/data_reduction_proxy/core/common",
"+components/version_info",
"+net",
+ "+services/network",
]
diff --git a/chromium/components/net_log/chrome_net_log.cc b/chromium/components/net_log/chrome_net_log.cc
index a799eeed9c3..878b9649b92 100644
--- a/chromium/components/net_log/chrome_net_log.cc
+++ b/chromium/components/net_log/chrome_net_log.cc
@@ -49,7 +49,7 @@ void ChromeNetLog::StartWritingToFile(
NetExportFileWriter* ChromeNetLog::net_export_file_writer() {
if (!net_export_file_writer_)
- net_export_file_writer_ = base::WrapUnique(new NetExportFileWriter(this));
+ net_export_file_writer_ = base::WrapUnique(new NetExportFileWriter());
return net_export_file_writer_.get();
}
@@ -61,6 +61,18 @@ std::unique_ptr<base::Value> ChromeNetLog::GetConstants(
net::GetNetConstants();
DCHECK(constants_dict);
+ auto platform_dict =
+ GetPlatformConstants(command_line_string, channel_string);
+ if (platform_dict)
+ constants_dict->MergeDictionary(platform_dict.get());
+ return constants_dict;
+}
+
+std::unique_ptr<base::DictionaryValue> ChromeNetLog::GetPlatformConstants(
+ const base::CommandLine::StringType& command_line_string,
+ const std::string& channel_string) {
+ auto constants_dict = std::make_unique<base::DictionaryValue>();
+
// Add a dictionary with the version of the client and its command line
// arguments.
auto dict = std::make_unique<base::DictionaryValue>();
@@ -84,7 +96,7 @@ std::unique_ptr<base::Value> ChromeNetLog::GetConstants(
data_reduction_proxy::DataReductionProxyEventStore::AddConstants(
constants_dict.get());
- return std::move(constants_dict);
+ return constants_dict;
}
void ChromeNetLog::ShutDownBeforeTaskScheduler() {
diff --git a/chromium/components/net_log/chrome_net_log.h b/chromium/components/net_log/chrome_net_log.h
index cfa0298bf97..ead1479f1f2 100644
--- a/chromium/components/net_log/chrome_net_log.h
+++ b/chromium/components/net_log/chrome_net_log.h
@@ -56,6 +56,12 @@ class ChromeNetLog : public net::NetLog {
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string);
+ // Returns only platform-specific constants. This doesn't include the net/
+ // baseline, only Chrome-specific platform information.
+ static std::unique_ptr<base::DictionaryValue> GetPlatformConstants(
+ const base::CommandLine::StringType& command_line_string,
+ const std::string& channel_string);
+
// Notify the ChromeNetLog that things are shutting-down.
//
// If ChromeNetLog does not outlive the TaskScheduler, there is no need to
diff --git a/chromium/components/net_log/net_export_file_writer.cc b/chromium/components/net_log/net_export_file_writer.cc
index c30d2d70476..6f3597f84e2 100644
--- a/chromium/components/net_log/net_export_file_writer.cc
+++ b/chromium/components/net_log/net_export_file_writer.cc
@@ -13,20 +13,13 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
-#include "base/single_thread_task_runner.h"
+#include "base/sequenced_task_runner.h"
#include "base/task_runner_util.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/net_log/chrome_net_log.h"
-#include "net/log/file_net_log_observer.h"
-#include "net/log/net_log_util.h"
-#include "net/url_request/url_request_context_getter.h"
-
-namespace net {
-class URLRequestContext;
-}
namespace net_log {
@@ -60,31 +53,6 @@ NetExportFileWriter::DefaultLogPathResults SetUpDefaultLogPath(
return results;
}
-// Generates net log entries for ongoing events from |context_getters| and
-// adds them to |observer|.
-void CreateNetLogEntriesForActiveObjects(
- const NetExportFileWriter::URLRequestContextGetterList& context_getters,
- net::NetLog::ThreadSafeObserver* observer) {
- std::set<net::URLRequestContext*> contexts;
- for (const auto& getter : context_getters) {
- DCHECK(getter->GetNetworkTaskRunner()->BelongsToCurrentThread());
- contexts.insert(getter->GetURLRequestContext());
- }
- net::CreateNetLogEntriesForActiveObjects(contexts, observer);
-}
-
-// Adds net info from net::GetNetInfo() to |polled_data|.
-std::unique_ptr<base::DictionaryValue> AddNetInfo(
- scoped_refptr<net::URLRequestContextGetter> context_getter,
- std::unique_ptr<base::DictionaryValue> polled_data) {
- DCHECK(context_getter);
- std::unique_ptr<base::DictionaryValue> net_info = net::GetNetInfo(
- context_getter->GetURLRequestContext(), net::NET_INFO_ALL_SOURCES);
- if (polled_data)
- net_info->MergeDictionary(polled_data.get());
- return net_info;
-}
-
// If running on a POSIX OS, this will attempt to set all the permission flags
// of the file at |path| to 1. Will return |path| on success and the empty path
// on failure.
@@ -113,18 +81,19 @@ scoped_refptr<base::SequencedTaskRunner> CreateFileTaskRunner() {
} // namespace
-NetExportFileWriter::NetExportFileWriter(ChromeNetLog* chrome_net_log)
+NetExportFileWriter::NetExportFileWriter()
: state_(STATE_UNINITIALIZED),
log_exists_(false),
log_capture_mode_known_(false),
log_capture_mode_(net::NetLogCaptureMode::Default()),
- chrome_net_log_(chrome_net_log),
default_log_base_dir_getter_(base::Bind(&base::GetTempDir)),
weak_ptr_factory_(this) {}
NetExportFileWriter::~NetExportFileWriter() {
- if (file_net_log_observer_)
- file_net_log_observer_->StopObserving(nullptr, base::Closure());
+ if (net_log_exporter_) {
+ net_log_exporter_->Stop(base::Value(base::Value::Type::DICTIONARY),
+ base::DoNothing());
+ }
}
void NetExportFileWriter::AddObserver(StateObserver* observer) {
@@ -137,15 +106,10 @@ void NetExportFileWriter::RemoveObserver(StateObserver* observer) {
state_observer_list_.RemoveObserver(observer);
}
-void NetExportFileWriter::Initialize(
- scoped_refptr<base::TaskRunner> net_task_runner) {
+void NetExportFileWriter::Initialize() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(net_task_runner);
file_task_runner_ = CreateFileTaskRunner();
- if (net_task_runner_)
- DCHECK_EQ(net_task_runner_, net_task_runner);
- net_task_runner_ = net_task_runner;
if (state_ != STATE_UNINITIALIZED)
return;
@@ -164,10 +128,10 @@ void NetExportFileWriter::Initialize(
void NetExportFileWriter::StartNetLog(
const base::FilePath& log_path,
net::NetLogCaptureMode capture_mode,
- size_t max_file_size,
+ uint64_t max_file_size,
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string,
- const URLRequestContextGetterList& context_getters) {
+ network::mojom::NetworkContext* network_context) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(file_task_runner_);
@@ -183,41 +147,70 @@ void NetExportFileWriter::StartNetLog(
NotifyStateObserversAsync();
- std::unique_ptr<base::Value> constants(
- ChromeNetLog::GetConstants(command_line_string, channel_string));
+ network_context->CreateNetLogExporter(mojo::MakeRequest(&net_log_exporter_));
+ base::Value custom_constants = base::Value::FromUniquePtrValue(
+ ChromeNetLog::GetPlatformConstants(command_line_string, channel_string));
- file_net_log_observer_ = net::FileNetLogObserver::CreateBounded(
- log_path_, max_file_size, std::move(constants));
-
- net_task_runner_->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&CreateNetLogEntriesForActiveObjects, context_getters,
- base::Unretained(file_net_log_observer_.get())),
- base::Bind(
- &NetExportFileWriter::StartNetLogAfterCreateEntriesForActiveObjects,
- weak_ptr_factory_.GetWeakPtr(), capture_mode));
+ base::PostTaskAndReplyWithResult(
+ file_task_runner_.get(), FROM_HERE,
+ base::BindOnce(&NetExportFileWriter::CreateOutputFile, log_path_),
+ base::BindOnce(&NetExportFileWriter::StartNetLogAfterCreateFile,
+ weak_ptr_factory_.GetWeakPtr(), capture_mode,
+ max_file_size, std::move(custom_constants)));
}
-void NetExportFileWriter::StartNetLogAfterCreateEntriesForActiveObjects(
- net::NetLogCaptureMode capture_mode) {
+void NetExportFileWriter::StartNetLogAfterCreateFile(
+ net::NetLogCaptureMode capture_mode,
+ uint64_t max_file_size,
+ base::Value custom_constants,
+ base::File output_file) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_EQ(STATE_STARTING_LOG, state_);
- state_ = STATE_LOGGING;
- log_exists_ = true;
- log_capture_mode_known_ = true;
- log_capture_mode_ = capture_mode;
+ // TODO(morlovich): Communicate file open trouble better
+ // (https://crbug.com/838977)
+ if (!output_file.IsValid()) {
+ ResetExporterThenSetStateNotLogging();
+ return;
+ }
- NotifyStateObservers();
+ network::mojom::NetLogExporter_CaptureMode rpc_capture_mode =
+ network::mojom::NetLogExporter::CaptureMode::DEFAULT;
+ if (capture_mode.include_socket_bytes()) {
+ rpc_capture_mode =
+ network::mojom::NetLogExporter::CaptureMode::INCLUDE_SOCKET_BYTES;
+ } else if (capture_mode.include_cookies_and_credentials()) {
+ rpc_capture_mode = network::mojom::NetLogExporter::CaptureMode::
+ INCLUDE_COOKIES_AND_CREDENTIALS;
+ }
- file_net_log_observer_->StartObserving(chrome_net_log_, capture_mode);
+ // base::Unretained(this) is safe here since |net_log_exporter_| is owned by
+ // |this| and is a mojo InterfacePtr, which guarantees callback cancellation
+ // upon its destruction.
+ net_log_exporter_->Start(
+ std::move(output_file), std::move(custom_constants), rpc_capture_mode,
+ max_file_size,
+ base::BindOnce(&NetExportFileWriter::OnStartResult,
+ base::Unretained(this), capture_mode));
+}
+
+void NetExportFileWriter::OnStartResult(net::NetLogCaptureMode capture_mode,
+ int result) {
+ if (result == net::OK) {
+ state_ = STATE_LOGGING;
+ log_exists_ = true;
+ log_capture_mode_known_ = true;
+ log_capture_mode_ = capture_mode;
+
+ NotifyStateObservers();
+ } else {
+ ResetExporterThenSetStateNotLogging();
+ }
}
void NetExportFileWriter::StopNetLog(
- std::unique_ptr<base::DictionaryValue> polled_data,
- scoped_refptr<net::URLRequestContextGetter> context_getter) {
+ std::unique_ptr<base::DictionaryValue> polled_data) {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK(net_task_runner_);
if (state_ != STATE_LOGGING)
return;
@@ -226,15 +219,19 @@ void NetExportFileWriter::StopNetLog(
NotifyStateObserversAsync();
- if (context_getter) {
- base::PostTaskAndReplyWithResult(
- net_task_runner_.get(), FROM_HERE,
- base::BindOnce(&AddNetInfo, context_getter, std::move(polled_data)),
- base::BindOnce(&NetExportFileWriter::StopNetLogAfterAddNetInfo,
- weak_ptr_factory_.GetWeakPtr()));
- } else {
- StopNetLogAfterAddNetInfo(std::move(polled_data));
- }
+ base::Value polled_data_value(base::Value::Type::DICTIONARY);
+ if (polled_data)
+ polled_data_value = base::Value::FromUniquePtrValue(std::move(polled_data));
+ // base::Unretained(this) is safe here since |net_log_exporter_| is owned by
+ // |this| and is a mojo InterfacePtr, which guarantees callback cancellation
+ // upon its destruction.
+ net_log_exporter_->Stop(std::move(polled_data_value),
+ base::BindOnce(&NetExportFileWriter::OnStopResult,
+ base::Unretained(this)));
+}
+
+void NetExportFileWriter::OnStopResult(int result) {
+ ResetExporterThenSetStateNotLogging();
}
std::unique_ptr<base::DictionaryValue> NetExportFileWriter::GetState() const {
@@ -351,23 +348,17 @@ void NetExportFileWriter::SetStateAfterSetUpDefaultLogPath(
NotifyStateObservers();
}
-void NetExportFileWriter::StopNetLogAfterAddNetInfo(
- std::unique_ptr<base::DictionaryValue> polled_data) {
+void NetExportFileWriter::ResetExporterThenSetStateNotLogging() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(STATE_STOPPING_LOG, state_);
-
- file_net_log_observer_->StopObserving(
- std::move(polled_data),
- base::Bind(&NetExportFileWriter::ResetObserverThenSetStateNotLogging,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void NetExportFileWriter::ResetObserverThenSetStateNotLogging() {
- DCHECK(thread_checker_.CalledOnValidThread());
- file_net_log_observer_.reset();
+ net_log_exporter_.reset();
state_ = STATE_NOT_LOGGING;
NotifyStateObservers();
}
+base::File NetExportFileWriter::CreateOutputFile(base::FilePath path) {
+ return base::File(path,
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+}
+
} // namespace net_log
diff --git a/chromium/components/net_log/net_export_file_writer.h b/chromium/components/net_log/net_export_file_writer.h
index a1b11a58af3..b734e5d7433 100644
--- a/chromium/components/net_log/net_export_file_writer.h
+++ b/chromium/components/net_log/net_export_file_writer.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/command_line.h"
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
@@ -17,17 +18,19 @@
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
-#include "net/log/file_net_log_observer.h"
+#include "base/values.h"
#include "net/log/net_log_capture_mode.h"
+#include "services/network/public/mojom/network_service.mojom.h"
namespace base {
-class DictionaryValue;
class TaskRunner;
} // namespace base
-namespace net {
-class URLRequestContextGetter;
-} // namespace net
+namespace network {
+namespace mojom {
+class NetworkContext;
+}
+} // namespace network
namespace net_log {
@@ -37,10 +40,10 @@ class ChromeNetLog;
// It's a singleton that acts as the interface to all NetExportMessageHandlers
// which can tell it to start or stop logging in response to user actions from
// net-export UIs. Because it's a singleton, the logging state can be shared
-// between multiple instances of the net-export UI. Internally, it manages an
-// instance of net::FileNetLogObserver and handles the attaching/detaching of it
-// to the ChromeNetLog. This class is used by the iOS and non-iOS
-// implementations of net-export.
+// between multiple instances of the net-export UI. Internally, it manages a
+// pipe to an instance of network::NetLogExporter and handles the
+// attaching/detaching of it to the NetLog. This class is used by the iOS and
+// non-iOS implementations of net-export.
//
// NetExportFileWriter maintains the current logging state using the members
// |state_|, |log_exists_|, |log_capture_mode_known_|, |log_capture_mode_|.
@@ -52,11 +55,12 @@ class ChromeNetLog;
//
// This class is created and destroyed on the UI thread, and all public entry
// points are to be called on the UI thread. Internally, the class may run some
-// code on the |file_task_runner_| and |net_task_runner_|.
+// code on the |file_task_runner_|.
class NetExportFileWriter {
public:
// Special value meaning "can use an unlimited number of bytes".
- static constexpr size_t kNoLimit = net::FileNetLogObserver::kNoLimit;
+ static constexpr uint64_t kNoLimit =
+ network::mojom::NetLogExporter::kUnlimitedFileSize;
// The observer interface to be implemented by code that wishes to be notified
// of NetExportFileWriter's state changes.
@@ -75,8 +79,6 @@ class NetExportFileWriter {
using FilePathCallback = base::Callback<void(const base::FilePath&)>;
using DirectoryGetter = base::Callback<bool(base::FilePath*)>;
- using URLRequestContextGetterList =
- std::vector<scoped_refptr<net::URLRequestContextGetter>>;
~NetExportFileWriter();
@@ -90,11 +92,9 @@ class NetExportFileWriter {
// Detaches a StateObserver.
void RemoveObserver(StateObserver* observer);
- // Initializes NetExportFileWriter if not initialized and sets the network
- // task runner (used by NetExportFileWriter when querying network state).
- // This task runner must not be changed once set. Calling this function again
- // with the same parameter is OK.
- void Initialize(scoped_refptr<base::TaskRunner> net_task_runner);
+ // Initializes NetExportFileWriter if not initialized. Calling this function
+ // again is OK.
+ void Initialize();
// Starts collecting NetLog data into the file at |log_path|. If |log_path| is
// empty, the default log path is used. If NetExportFileWriter is already
@@ -103,30 +103,21 @@ class NetExportFileWriter {
// |max_file_size| places a bound on how large the log file can grow. To make
// it grow unboundedly pass kNoLimit.
//
- // |context_getters| is an optional list of URLRequestContextGetters used only
- // to add log entries for ongoing events when logging starts. They are not
- // used for retrieving polled data. All the contexts must be bound to the same
- // thread.
+ // |network_context| will be used to append net info (from net::GetInfo())
+ // at end of logging once StopNetLog is called.
void StartNetLog(const base::FilePath& log_path,
net::NetLogCaptureMode capture_mode,
- size_t max_file_size,
+ uint64_t max_file_size,
const base::CommandLine::StringType& command_line_string,
const std::string& channel_string,
- const URLRequestContextGetterList& context_getters);
+ network::mojom::NetworkContext* network_context);
// Stops collecting NetLog data into the file. It is a no-op if
// NetExportFileWriter is currently not logging.
//
// |polled_data| is a JSON dictionary that will be appended to the end of the
// log; it's for adding additional info to the log that aren't events.
- // If |context_getter| is not null, then StopNetLog() will automatically
- // append net info (from net::GetNetInfo() retrieved using |context_getter|)
- // to |polled_data|.
- // Note that StopNetLog() accepts (optionally) only one context getter for
- // retrieving net polled data as opposed to StartNetLog() which accepts zero
- // or more context getters for retrieving ongoing net events.
- void StopNetLog(std::unique_ptr<base::DictionaryValue> polled_data,
- scoped_refptr<net::URLRequestContextGetter> context_getter);
+ void StopNetLog(std::unique_ptr<base::DictionaryValue> polled_data);
// Creates a DictionaryValue summary of the state of the NetExportFileWriter
std::unique_ptr<base::DictionaryValue> GetState() const;
@@ -156,7 +147,7 @@ class NetExportFileWriter {
protected:
// Constructs a NetExportFileWriter. Only one instance is created in browser
// process.
- explicit NetExportFileWriter(ChromeNetLog* chrome_net_log);
+ NetExportFileWriter();
private:
friend class ChromeNetLog;
@@ -189,30 +180,30 @@ class NetExportFileWriter {
const DefaultLogPathResults& set_up_default_log_path_results);
// Called internally by StartNetLog(). Contains tasks to be done to start
- // logging after net log entries for ongoing events are added to the log from
- // the |net_task_runner_|.
- void StartNetLogAfterCreateEntriesForActiveObjects(
- net::NetLogCaptureMode capture_mode);
-
- // Called internally by StopNetLog(). Contains tasks to be done to stop
- // logging after net-thread polled data is retrieved on the
- // |net_task_runner_|.
- void StopNetLogAfterAddNetInfo(
- std::unique_ptr<base::DictionaryValue> polled_data);
-
- // Contains tasks to be done after |file_net_log_observer_| has completely
+ // logging after the output file has been created.
+ void StartNetLogAfterCreateFile(net::NetLogCaptureMode capture_mode,
+ uint64_t max_file_size,
+ base::Value custom_constants,
+ base::File log_file);
+
+ void OnStartResult(net::NetLogCaptureMode capture_mode, int result);
+ void OnStopResult(int result);
+
+ // Contains tasks to be done after |net_log_exporter_| has completely
// stopped writing.
- void ResetObserverThenSetStateNotLogging();
+ void ResetExporterThenSetStateNotLogging();
+
+ // Creates a new file for writing at |path|, trying to overwrite any existing
+ // file. Called on |file_task_runner_|.
+ static base::File CreateOutputFile(base::FilePath path);
// All members are accessed solely from the main thread (the thread that
// |thread_checker_| is bound to).
-
base::ThreadChecker thread_checker_;
// Task runners for file-specific and net-specific tasks that must run on a
// file or net task runner.
scoped_refptr<base::TaskRunner> file_task_runner_;
- scoped_refptr<base::TaskRunner> net_task_runner_;
State state_; // Current logging state of NetExportFileWriter.
@@ -222,13 +213,8 @@ class NetExportFileWriter {
base::FilePath log_path_; // base::FilePath to the NetLog file.
- // |file_net_log_observer_| watches the NetLog event stream, and
- // sends all entries to the file created in StartNetLog().
- std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
-
- // The |chrome_net_log_| is owned by the browser process, cached here to avoid
- // using global (g_browser_process).
- ChromeNetLog* chrome_net_log_;
+ // Used to ask the network service to do the actual exporting.
+ network::mojom::NetLogExporterPtr net_log_exporter_;
// List of StateObservers to notify on state changes.
base::ObserverList<StateObserver, true> state_observer_list_;
diff --git a/chromium/components/net_log/net_export_file_writer_unittest.cc b/chromium/components/net_log/net_export_file_writer_unittest.cc
index ebc5cf54b27..dead8880616 100644
--- a/chromium/components/net_log/net_export_file_writer_unittest.cc
+++ b/chromium/components/net_log/net_export_file_writer_unittest.cc
@@ -16,19 +16,22 @@
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_reader.h"
#include "base/json/json_string_value_serializer.h"
+#include "base/synchronization/waitable_event.h"
#include "base/test/scoped_task_environment.h"
-#include "base/threading/thread.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "build/build_config.h"
-#include "components/net_log/chrome_net_log.h"
#include "net/base/test_completion_callback.h"
-#include "net/http/http_network_session.h"
#include "net/log/net_log_capture_mode.h"
#include "net/log/net_log_event_type.h"
+#include "net/test/embedded_test_server/default_handlers.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/simple_url_loader.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -162,44 +165,6 @@ WARN_UNUSED_RESULT ::testing::AssertionResult ReadCompleteLogFile(
return ::testing::AssertionSuccess();
}
-void SetUpTestContextGetterWithQuicTimeoutInfo(
- net::NetLog* net_log,
- int quic_idle_connection_timeout_seconds,
- scoped_refptr<net::TestURLRequestContextGetter>* context_getter) {
- std::unique_ptr<net::TestURLRequestContext> context =
- std::make_unique<net::TestURLRequestContext>(true);
- context->set_net_log(net_log);
-
- std::unique_ptr<net::HttpNetworkSession::Params> params(
- new net::HttpNetworkSession::Params);
- params->quic_idle_connection_timeout_seconds =
- quic_idle_connection_timeout_seconds;
-
- context->set_http_network_session_params(std::move(params));
- context->Init();
-
- *context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(), std::move(context));
-}
-
-void SetUpTestContextGetterWithRequest(
- net::NetLog* net_log,
- const GURL& url,
- net::URLRequest::Delegate* delegate,
- scoped_refptr<net::TestURLRequestContextGetter>* context_getter,
- std::unique_ptr<net::URLRequest>* request) {
- auto context = std::make_unique<net::TestURLRequestContext>(true);
- context->set_net_log(net_log);
- context->Init();
-
- *request = context->CreateRequest(url, net::IDLE, delegate,
- TRAFFIC_ANNOTATION_FOR_TESTS);
- (*request)->Start();
-
- *context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(), std::move(context));
-}
-
// An implementation of NetExportFileWriter::StateObserver that allows waiting
// until it's notified of a new state.
class TestStateObserver : public NetExportFileWriter::StateObserver {
@@ -251,15 +216,23 @@ class TestFilePathCallback {
class NetExportFileWriterTest : public ::testing::Test {
public:
- using URLRequestContextGetterList =
- std::vector<scoped_refptr<net::URLRequestContextGetter>>;
-
NetExportFileWriterTest()
- : file_writer_(&net_log_), net_thread_("NetLogFileWriter net thread") {}
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ network_service_(network::NetworkService::CreateForTesting()) {}
// ::testing::Test implementation
void SetUp() override {
ASSERT_TRUE(log_temp_dir_.CreateUniqueTempDir());
+ network::mojom::NetworkContextParamsPtr params =
+ network::mojom::NetworkContextParams::New();
+ // Use a fixed proxy config, to avoid dependencies on local network
+ // configuration.
+ params->initial_proxy_config =
+ net::ProxyConfigWithAnnotation::CreateDirect();
+ network_context_ = std::make_unique<network::NetworkContext>(
+ network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
+ std::move(params));
// Override |file_writer_|'s default-log-base-directory-getter to
// a getter that returns the temp dir created for the test.
@@ -268,8 +241,6 @@ class NetExportFileWriterTest : public ::testing::Test {
default_log_path_ = log_temp_dir_.GetPath().Append(kLogRelativePath);
- ASSERT_TRUE(net_thread_.Start());
-
file_writer_.AddObserver(&test_state_observer_);
ASSERT_TRUE(VerifyState(file_writer_.GetState(), kStateUninitializedString,
@@ -291,7 +262,7 @@ class NetExportFileWriterTest : public ::testing::Test {
WARN_UNUSED_RESULT ::testing::AssertionResult InitializeThenVerifyNewState(
bool expected_initialize_success,
bool expected_log_exists) {
- file_writer_.Initialize(net_thread_.task_runner());
+ file_writer_.Initialize();
std::unique_ptr<base::DictionaryValue> state =
test_state_observer_.WaitForNewState();
::testing::AssertionResult result =
@@ -325,10 +296,10 @@ class NetExportFileWriterTest : public ::testing::Test {
const base::FilePath& custom_log_path,
net::NetLogCaptureMode capture_mode,
const std::string& expected_capture_mode_string,
- const URLRequestContextGetterList& context_getters) {
+ network::mojom::NetworkContext* network_context) {
file_writer_.StartNetLog(custom_log_path, capture_mode, kMaxLogSizeBytes,
base::CommandLine::StringType(), kChannelString,
- context_getters);
+ network_context);
std::unique_ptr<base::DictionaryValue> state =
test_state_observer_.WaitForNewState();
::testing::AssertionResult result =
@@ -366,9 +337,8 @@ class NetExportFileWriterTest : public ::testing::Test {
WARN_UNUSED_RESULT ::testing::AssertionResult StopThenVerifyNewStateAndFile(
const base::FilePath& custom_log_path,
std::unique_ptr<base::DictionaryValue> polled_data,
- scoped_refptr<net::URLRequestContextGetter> context_getter,
const std::string& expected_capture_mode_string) {
- file_writer_.StopNetLog(std::move(polled_data), context_getter);
+ file_writer_.StopNetLog(std::move(polled_data));
std::unique_ptr<base::DictionaryValue> state =
test_state_observer_.WaitForNewState();
::testing::AssertionResult result =
@@ -415,7 +385,7 @@ class NetExportFileWriterTest : public ::testing::Test {
return ::testing::AssertionSuccess();
}
- ChromeNetLog* net_log() { return &net_log_; }
+ net::NetLog* net_log() { return network_service_->net_log(); }
NetExportFileWriter* file_writer() { return &file_writer_; }
@@ -425,17 +395,22 @@ class NetExportFileWriterTest : public ::testing::Test {
const base::FilePath& default_log_path() const { return default_log_path_; }
- base::Thread* net_thread() { return &net_thread_; }
-
TestStateObserver* test_state_observer() { return &test_state_observer_; }
+ network::mojom::NetworkContext* network_context() {
+ return network_context_ptr_.get();
+ }
+
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<network::NetworkService> network_service_;
- ChromeNetLog net_log_;
+ network::mojom::NetworkContextPtr network_context_ptr_;
+ std::unique_ptr<network::NetworkContext> network_context_;
- // |file_writer_| is initialized after |net_log_| so that it can stop
- // obvserving on destruction.
+ // |file_writer_| is initialized after |network_context_ptr_| since
+ // |file_writer_| destructor can talk to mojo objects owned by
+ // |network_context_|.
NetExportFileWriter file_writer_;
base::ScopedTempDir log_temp_dir_;
@@ -443,8 +418,6 @@ class NetExportFileWriterTest : public ::testing::Test {
// The default log path that |file_writer_| will use is cached here.
base::FilePath default_log_path_;
- base::Thread net_thread_;
-
TestStateObserver test_state_observer_;
};
@@ -501,41 +474,38 @@ TEST_F(NetExportFileWriterTest, StartAndStopWithAllCaptureModes) {
// StartNetLog(), should result in state change.
ASSERT_TRUE(StartThenVerifyNewState(base::FilePath(), capture_modes[i],
capture_mode_strings[i],
- URLRequestContextGetterList()));
+ network_context()));
// Calling StartNetLog() again should be a no-op. Try doing StartNetLog()
// with various capture modes; they should all be ignored and result in no
// state change.
- file_writer()->StartNetLog(base::FilePath(), capture_modes[i],
- kMaxLogSizeBytes,
- base::CommandLine::StringType(), kChannelString,
- URLRequestContextGetterList());
- file_writer()->StartNetLog(base::FilePath(), capture_modes[(i + 1) % 3],
- kMaxLogSizeBytes,
- base::CommandLine::StringType(), kChannelString,
- URLRequestContextGetterList());
- file_writer()->StartNetLog(base::FilePath(), capture_modes[(i + 2) % 3],
- kMaxLogSizeBytes,
- base::CommandLine::StringType(), kChannelString,
- URLRequestContextGetterList());
+ file_writer()->StartNetLog(
+ base::FilePath(), capture_modes[i], kMaxLogSizeBytes,
+ base::CommandLine::StringType(), kChannelString, network_context());
+ file_writer()->StartNetLog(
+ base::FilePath(), capture_modes[(i + 1) % 3], kMaxLogSizeBytes,
+ base::CommandLine::StringType(), kChannelString, network_context());
+ file_writer()->StartNetLog(
+ base::FilePath(), capture_modes[(i + 2) % 3], kMaxLogSizeBytes,
+ base::CommandLine::StringType(), kChannelString, network_context());
// StopNetLog(), should result in state change. The capture mode should
// match that of the first StartNetLog() call (called by
// StartThenVerifyNewState()).
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(
- base::FilePath(), nullptr, nullptr, capture_mode_strings[i]));
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
+ capture_mode_strings[i]));
// Stopping a second time should be a no-op.
- file_writer()->StopNetLog(nullptr, nullptr);
+ file_writer()->StopNetLog(nullptr);
}
// Start and stop one more time just to make sure the last StopNetLog() call
// was properly ignored and left |file_writer_| in a valid state.
ASSERT_TRUE(StartThenVerifyNewState(base::FilePath(), capture_modes[0],
capture_mode_strings[0],
- URLRequestContextGetterList()));
+ network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
capture_mode_strings[0]));
}
@@ -546,9 +516,9 @@ TEST_F(NetExportFileWriterTest, StartClearsFile) {
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
kCaptureModeDefaultString));
int64_t stop_file_size;
@@ -567,9 +537,9 @@ TEST_F(NetExportFileWriterTest, StartClearsFile) {
// before adding the junk data.
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
kCaptureModeDefaultString));
int64_t new_stop_file_size;
@@ -585,9 +555,9 @@ TEST_F(NetExportFileWriterTest, AddEvent) {
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
kCaptureModeDefaultString));
// Get file size without the event.
@@ -596,11 +566,11 @@ TEST_F(NetExportFileWriterTest, AddEvent) {
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
net_log()->AddGlobalEntry(net::NetLogEventType::CANCELLED);
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
kCaptureModeDefaultString));
// Get file size after adding the event and make sure it's larger than before.
@@ -623,9 +593,9 @@ TEST_F(NetExportFileWriterTest, AddEventCustomPath) {
ASSERT_TRUE(StartThenVerifyNewState(
custom_log_path, net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(custom_log_path, nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(custom_log_path, nullptr,
kCaptureModeDefaultString));
// Get file size without the event.
@@ -634,11 +604,11 @@ TEST_F(NetExportFileWriterTest, AddEventCustomPath) {
ASSERT_TRUE(StartThenVerifyNewState(
custom_log_path, net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
net_log()->AddGlobalEntry(net::NetLogEventType::CANCELLED);
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(custom_log_path, nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(custom_log_path, nullptr,
kCaptureModeDefaultString));
// Get file size after adding the event and make sure it's larger than before.
@@ -647,7 +617,7 @@ TEST_F(NetExportFileWriterTest, AddEventCustomPath) {
EXPECT_GE(new_stop_file_size, stop_file_size);
}
-TEST_F(NetExportFileWriterTest, StopWithPolledDataAndContextGetter) {
+TEST_F(NetExportFileWriterTest, StopWithPolledData) {
ASSERT_TRUE(InitializeThenVerifyNewState(true, false));
// Create dummy polled data
@@ -657,24 +627,13 @@ TEST_F(NetExportFileWriterTest, StopWithPolledDataAndContextGetter) {
std::make_unique<base::DictionaryValue>();
dummy_polled_data->SetString(kDummyPolledDataPath, kDummyPolledDataString);
- // Create test context getter on |net_thread_| and wait for it to finish.
- scoped_refptr<net::TestURLRequestContextGetter> context_getter;
- const int kDummyQuicParam = 75;
- net::TestClosure init_done;
- net_thread()->task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&SetUpTestContextGetterWithQuicTimeoutInfo, net_log(),
- kDummyQuicParam, &context_getter),
- init_done.closure());
- init_done.WaitForResult();
-
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, URLRequestContextGetterList()));
+ kCaptureModeDefaultString, network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(
- base::FilePath(), std::move(dummy_polled_data), context_getter,
- kCaptureModeDefaultString));
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(),
+ std::move(dummy_polled_data),
+ kCaptureModeDefaultString));
// Read polledData from log file.
std::unique_ptr<base::DictionaryValue> root;
@@ -687,44 +646,79 @@ TEST_F(NetExportFileWriterTest, StopWithPolledDataAndContextGetter) {
ASSERT_TRUE(polled_data->GetString(kDummyPolledDataPath, &dummy_string));
EXPECT_EQ(kDummyPolledDataString, dummy_string);
- // Check that it also contains the field from the URLRequestContext that was
- // passed in.
- base::DictionaryValue* quic_info;
- ASSERT_TRUE(polled_data->GetDictionary("quicInfo", &quic_info));
- base::Value* timeout_value = nullptr;
- int timeout;
- ASSERT_TRUE(
- quic_info->Get("idle_connection_timeout_seconds", &timeout_value));
- ASSERT_TRUE(timeout_value->GetAsInteger(&timeout));
- EXPECT_EQ(kDummyQuicParam, timeout);
+ // Check that it also contains something from net::GetNetInfo.
+ base::DictionaryValue* http_cache_info;
+ ASSERT_TRUE(polled_data->GetDictionary("httpCacheInfo", &http_cache_info));
}
-TEST_F(NetExportFileWriterTest, StartWithContextGetters) {
- ASSERT_TRUE(InitializeThenVerifyNewState(true, false));
+// Test with requests in flight. This is done by going through a sequence of a
+// redirect --- at which point the log is started --- and then a fetch of
+// destination that's blocked on an event in EmbeddedTestServer.
+TEST_F(NetExportFileWriterTest, StartWithNetworkContextActive) {
+ net::EmbeddedTestServer test_server;
+ net::test_server::RegisterDefaultHandlers(&test_server);
+
+ base::WaitableEvent block_fetch(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+ test_server.RegisterRequestHandler(base::BindRepeating(
+ [](base::WaitableEvent* block_fetch,
+ const net::test_server::HttpRequest& request)
+ -> std::unique_ptr<net::test_server::HttpResponse> {
+ if (request.relative_url == "/block")
+ block_fetch->Wait();
+ return nullptr;
+ },
+ &block_fetch));
+
+ ASSERT_TRUE(test_server.Start());
- // Create test context getter and request on |net_thread_| and wait for it to
- // finish.
- const std::string kDummyUrl = "blah:blah";
- scoped_refptr<net::TestURLRequestContextGetter> context_getter;
- std::unique_ptr<net::URLRequest> request;
- net::TestDelegate delegate;
- delegate.set_quit_on_complete(false);
-
- net::TestClosure init_done;
- net_thread()->task_runner()->PostTaskAndReply(
- FROM_HERE,
- base::Bind(&SetUpTestContextGetterWithRequest, net_log(), GURL(kDummyUrl),
- &delegate, &context_getter, &request),
- init_done.closure());
- init_done.WaitForResult();
+ ASSERT_TRUE(InitializeThenVerifyNewState(true, false));
+ network::mojom::URLLoaderFactoryPtr url_loader_factory;
+ auto url_loader_factory_params =
+ network::mojom::URLLoaderFactoryParams::New();
+ url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
+ url_loader_factory_params->is_corb_enabled = false;
+ network_context()->CreateURLLoaderFactory(
+ mojo::MakeRequest(&url_loader_factory),
+ std::move(url_loader_factory_params));
+
+ const char kRedirectURL[] = "/server-redirect?/block";
+ std::unique_ptr<network::ResourceRequest> request =
+ std::make_unique<network::ResourceRequest>();
+ request->url = test_server.GetURL(kRedirectURL);
+
+ std::unique_ptr<network::SimpleURLLoader> simple_loader =
+ network::SimpleURLLoader::Create(std::move(request),
+ TRAFFIC_ANNOTATION_FOR_TESTS);
+ base::RunLoop run_loop, run_loop2;
+ simple_loader->SetOnRedirectCallback(base::BindRepeating(
+ [](base::RepeatingClosure notify_log,
+ const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ notify_log.Run();
+ },
+ run_loop.QuitClosure()));
+ simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ url_loader_factory.get(),
+ base::BindOnce(
+ [](base::OnceClosure quit_closure,
+ std::unique_ptr<std::string> response_body) {
+ std::move(quit_closure).Run();
+ },
+ run_loop2.QuitClosure()));
+
+ // Wait for fetch to get some bytes accross. It will not be the entire
+ // thing since the post-redirect URL will get blocked by the custom handler.
+ run_loop.Run();
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::Default(),
- kCaptureModeDefaultString, {context_getter}));
+ kCaptureModeDefaultString, network_context()));
- ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr, nullptr,
+ ASSERT_TRUE(StopThenVerifyNewStateAndFile(base::FilePath(), nullptr,
kCaptureModeDefaultString));
-
// Read events from log file.
std::unique_ptr<base::DictionaryValue> root;
ASSERT_TRUE(ReadCompleteLogFile(default_log_path(), &root));
@@ -732,7 +726,7 @@ TEST_F(NetExportFileWriterTest, StartWithContextGetters) {
ASSERT_TRUE(root->GetList("events", &events));
// Check there is at least one event as a result of the ongoing request.
- EXPECT_GE(events->GetSize(), 1u);
+ ASSERT_GE(events->GetSize(), 1u);
// Check the URL in the params of the first event.
base::DictionaryValue* event;
@@ -741,24 +735,24 @@ TEST_F(NetExportFileWriterTest, StartWithContextGetters) {
EXPECT_TRUE(event->GetDictionary("params", &event_params));
std::string event_url;
EXPECT_TRUE(event_params->GetString("url", &event_url));
- EXPECT_EQ(kDummyUrl, event_url);
+ EXPECT_EQ(test_server.GetURL(kRedirectURL), event_url);
- net_thread()->task_runner()->DeleteSoon(FROM_HERE, request.release());
+ block_fetch.Signal();
+ run_loop2.Run();
}
TEST_F(NetExportFileWriterTest, ReceiveStartWhileInitializing) {
// Trigger initialization of |file_writer_|.
- file_writer()->Initialize(net_thread()->task_runner());
+ file_writer()->Initialize();
// Before running the main message loop, tell |file_writer_| to start
// logging. Not running the main message loop prevents the initialization
// process from completing, so this ensures that StartNetLog() is received
// before |file_writer_| finishes initialization, which means this
// should be a no-op.
- file_writer()->StartNetLog(base::FilePath(),
- net::NetLogCaptureMode::Default(),
- kMaxLogSizeBytes, base::CommandLine::StringType(),
- kChannelString, URLRequestContextGetterList());
+ file_writer()->StartNetLog(
+ base::FilePath(), net::NetLogCaptureMode::Default(), kMaxLogSizeBytes,
+ base::CommandLine::StringType(), kChannelString, network_context());
// Now run the main message loop. Make sure StartNetLog() was ignored by
// checking that the next two states are "initializing" followed by
@@ -777,20 +771,19 @@ TEST_F(NetExportFileWriterTest, ReceiveStartWhileStoppingLog) {
// Call StartNetLog() on |file_writer_| and wait for the state change.
ASSERT_TRUE(StartThenVerifyNewState(
base::FilePath(), net::NetLogCaptureMode::IncludeSocketBytes(),
- kCaptureModeIncludeSocketBytesString, URLRequestContextGetterList()));
+ kCaptureModeIncludeSocketBytesString, network_context()));
// Tell |file_writer_| to stop logging.
- file_writer()->StopNetLog(nullptr, nullptr);
+ file_writer()->StopNetLog(nullptr);
// Before running the main message loop, tell |file_writer_| to start
// logging. Not running the main message loop prevents the stopping process
// from completing, so this ensures StartNetLog() is received before
// |file_writer_| finishes stopping, which means this should be a
// no-op.
- file_writer()->StartNetLog(base::FilePath(),
- net::NetLogCaptureMode::Default(),
- kMaxLogSizeBytes, base::CommandLine::StringType(),
- kChannelString, URLRequestContextGetterList());
+ file_writer()->StartNetLog(
+ base::FilePath(), net::NetLogCaptureMode::Default(), kMaxLogSizeBytes,
+ base::CommandLine::StringType(), kChannelString, network_context());
// Now run the main message loop. Make sure the last StartNetLog() was
// ignored by checking that the next two states are "stopping-log" followed by
diff --git a/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite-bday.png b/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite-bday.png
new file mode 100644
index 00000000000..4654ee0b2d1
--- /dev/null
+++ b/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite-bday.png
Binary files differ
diff --git a/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png b/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png
index dcaf75941bf..24c3fcd1cca 100644
--- a/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png
+++ b/chromium/components/neterror/resources/default_100_percent/offline/100-offline-sprite.png
Binary files differ
diff --git a/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite-bday.png b/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite-bday.png
new file mode 100644
index 00000000000..38227e47c5b
--- /dev/null
+++ b/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite-bday.png
Binary files differ
diff --git a/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png b/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png
index 366e82a910b..1a5ff75b9d6 100644
--- a/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png
+++ b/chromium/components/neterror/resources/default_200_percent/offline/200-offline-sprite.png
Binary files differ
diff --git a/chromium/components/neterror/resources/neterror.html b/chromium/components/neterror/resources/neterror.html
index 615d17162ed..464a56af290 100644
--- a/chromium/components/neterror/resources/neterror.html
+++ b/chromium/components/neterror/resources/neterror.html
@@ -2,6 +2,7 @@
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+ <meta name="theme-color" content="#fff">
<meta name="viewport" content="width=device-width, initial-scale=1.0,
maximum-scale=1.0, user-scalable=no">
<title>$i18n{title}</title>
@@ -77,6 +78,8 @@
<div id="offline-resources">
<img id="offline-resources-1x" src="default_100_percent/offline/100-offline-sprite.png">
<img id="offline-resources-2x" src="default_200_percent/offline/200-offline-sprite.png">
+ <img id="offline-resources-bday-1x" src="default_100_percent/offline/100-offline-sprite-bday.png">
+ <img id="offline-resources-bday-2x" src="default_200_percent/offline/200-offline-sprite-bday.png">
<template id="audio-resources">
<audio id="offline-sound-press" src="sounds/button-press.mp3"></audio>
<audio id="offline-sound-hit" src="sounds/hit.mp3"></audio>
diff --git a/chromium/components/neterror/resources/offline.js b/chromium/components/neterror/resources/offline.js
index c4cf84dec29..53a21904563 100644
--- a/chromium/components/neterror/resources/offline.js
+++ b/chromium/components/neterror/resources/offline.js
@@ -49,6 +49,7 @@ function Runner(outerContainerId, opt_config) {
this.inverted = false;
this.invertTimer = 0;
this.resizeTimerId_ = null;
+ this.bdayFlashTimer = null;
this.playCount = 0;
@@ -104,6 +105,9 @@ Runner.config = {
ACCELERATION: 0.001,
BG_CLOUD_SPEED: 0.2,
BOTTOM_PAD: 10,
+ BOTTOM_PAD_BDAY: 26,
+ BDAY_FLASH_DURATION: 1000,
+ BDAY_Y_POS_ADJUST: 16,
CLEAR_TIME: 3000,
CLOUD_FREQUENCY: 0.5,
GAMEOVER_CLEAR_TIME: 750,
@@ -160,6 +164,7 @@ Runner.classes = {
*/
Runner.spriteDefinition = {
LDPI: {
+ BALLOON: {x: 417, y: 29},
CACTUS_LARGE: {x: 332, y: 2},
CACTUS_SMALL: {x: 228, y: 2},
CLOUD: {x: 86, y: 2},
@@ -169,9 +174,12 @@ Runner.spriteDefinition = {
RESTART: {x: 2, y: 2},
TEXT_SPRITE: {x: 655, y: 2},
TREX: {x: 848, y: 2},
+ TREX_BDAY: {x: 0, y: 0},
+ SNACK: {x: 384, y: 22},
STAR: {x: 645, y: 2}
},
HDPI: {
+ BALLOON: {x: 834, y: 58},
CACTUS_LARGE: {x: 652, y: 2},
CACTUS_SMALL: {x: 446, y: 2},
CLOUD: {x: 166, y: 2},
@@ -181,6 +189,8 @@ Runner.spriteDefinition = {
RESTART: {x: 2, y: 2},
TEXT_SPRITE: {x: 1294, y: 2},
TREX: {x: 1678, y: 2},
+ TREX_BDAY: {x: 0, y: 0},
+ SNACK: {x: 768, y: 44},
STAR: {x: 1276, y: 2}
}
};
@@ -287,9 +297,13 @@ Runner.prototype = {
loadImages: function() {
if (IS_HIDPI) {
Runner.imageSprite = document.getElementById('offline-resources-2x');
+ Runner.bdayImageSprite =
+ document.getElementById('offline-resources-bday-2x');
this.spriteDef = Runner.spriteDefinition.HDPI;
} else {
Runner.imageSprite = document.getElementById('offline-resources-1x');
+ Runner.bdayImageSprite =
+ document.getElementById('offline-resources-bday-1x');
this.spriteDef = Runner.spriteDefinition.LDPI;
}
@@ -525,6 +539,20 @@ Runner.prototype = {
var now = getTimeStamp();
var deltaTime = now - (this.time || now);
+
+ // Flashing.
+ if (this.bdayFlashTimer != null) {
+ if (this.bdayFlashTimer <= 0) {
+ this.bdayFlashTimer = null;
+ this.tRex.setFlashing(false);
+ this.tRex.enableBdayMode(this.spriteDef.TREX_BDAY);
+ } else {
+ this.bdayFlashTimer -= deltaTime;
+ this.tRex.update(deltaTime);
+ deltaTime = 0;
+ }
+ }
+
this.time = now;
if (this.playing) {
@@ -555,6 +583,15 @@ Runner.prototype = {
var collision = hasObstacles &&
checkForCollision(this.horizon.obstacles[0], this.tRex);
+ // Ate snack.
+ if (Runner.isBdayModeEnabled() && collision &&
+ this.horizon.obstacles[0].typeConfig.type == 'SNACK') {
+ this.horizon.enableBdayMode();
+ this.tRex.setFlashing(true);
+ collision = false;
+ this.bdayFlashTimer = this.config.BDAY_FLASH_DURATION;
+ }
+
if (!collision) {
this.distanceRan += this.currentSpeed * deltaTime / this.msPerFrame;
@@ -828,6 +865,7 @@ Runner.prototype = {
this.tRex.reset();
this.playSound(this.soundFx.BUTTON_PRESS);
this.invert(true);
+ this.bdayFlashTimer = null;
this.update();
}
},
@@ -957,6 +995,15 @@ Runner.updateCanvasScaling = function(canvas, opt_width, opt_height) {
/**
+ * Whether the bday mode is enabled.
+ * @return {boolean}
+ */
+Runner.isBdayModeEnabled = function() {
+ return loadTimeData && loadTimeData.valueExists('bdayMode');
+}
+
+
+/**
* Get random number.
* @param {number} min
* @param {number} max
@@ -1142,7 +1189,7 @@ function checkForCollision(obstacle, tRex, opt_canvasCtx) {
tRex.xPos + 1,
tRex.yPos + 1,
tRex.config.WIDTH - 2,
- tRex.config.HEIGHT - 2);
+ (tRex.bdayModeActive ? tRex.config.HEIGHT_BDAY : tRex.config.HEIGHT) - 2);
var obstacleBox = new CollisionBox(
obstacle.xPos + 1,
@@ -1171,6 +1218,10 @@ function checkForCollision(obstacle, tRex, opt_canvasCtx) {
createAdjustedCollisionBox(collisionBoxes[i], obstacleBox);
var crashed = boxCompare(adjTrexBox, adjObstacleBox);
+ if (tRex.bdayModeActive) {
+ adjTrexBox.y += Runner.config.BDAY_Y_POS_ADJUST;
+ }
+
// Draw boxes for debug.
if (opt_canvasCtx) {
drawCollisionBoxes(opt_canvasCtx, adjTrexBox, adjObstacleBox);
@@ -1287,6 +1338,8 @@ function Obstacle(canvasCtx, type, spriteImgPos, dimensions,
this.collisionBoxes = [];
this.gap = 0;
this.speedOffset = 0;
+ this.imageSprite = this.typeConfig.type == 'SNACK' ? Runner.bdayImageSprite :
+ Runner.imageSprite;
// For animated obstacles.
this.currentFrame = 0;
@@ -1378,7 +1431,7 @@ Obstacle.prototype = {
sourceX += sourceWidth * this.currentFrame;
}
- this.canvasCtx.drawImage(Runner.imageSprite,
+ this.canvasCtx.drawImage(this.imageSprite,
sourceX, this.spritePos.y,
sourceWidth * this.size, sourceHeight,
this.xPos, this.yPos,
@@ -1508,6 +1561,18 @@ Obstacle.types = [
numFrames: 2,
frameRate: 1000/6,
speedOffset: .8
+ },
+ {
+ type: 'SNACK',
+ width: 33,
+ height: 42,
+ yPos: 85,
+ multipleSpeed: 999,
+ minGap: 999,
+ minSpeed: 0,
+ collisionBoxes: [
+ new CollisionBox(0, 0, 40, 40)
+ ]
}
];
@@ -1522,6 +1587,7 @@ Obstacle.types = [
function Trex(canvas, spritePos) {
this.canvas = canvas;
this.canvasCtx = canvas.getContext('2d');
+ this.imageSprite = Runner.imageSprite;
this.spritePos = spritePos;
this.xPos = 0;
this.yPos = 0;
@@ -1545,6 +1611,8 @@ function Trex(canvas, spritePos) {
this.speedDrop = false;
this.jumpCount = 0;
this.jumpspotX = 0;
+ this.bdayModeActive = false;
+ this.flashing = false;
this.init();
};
@@ -1556,8 +1624,11 @@ function Trex(canvas, spritePos) {
*/
Trex.config = {
DROP_VELOCITY: -5,
+ FLASH_OFF: 175,
+ FLASH_ON: 100,
GRAVITY: 0.6,
HEIGHT: 47,
+ HEIGHT_BDAY: 63,
HEIGHT_DUCK: 25,
INIITAL_JUMP_VELOCITY: -10,
INTRO_DURATION: 1500,
@@ -1631,7 +1702,7 @@ Trex.animFrames = {
msPerFrame: 1000 / 60
},
DUCKING: {
- frames: [262, 321],
+ frames: [264, 323],
msPerFrame: 1000 / 8
}
};
@@ -1653,6 +1724,25 @@ Trex.prototype = {
},
/**
+ * @param {Object} spritePos New positioning within image sprite.
+ */
+ enableBdayMode: function(spritePos) {
+ this.bdayModeActive = true;
+ this.spritePos = spritePos;
+ this.imageSprite = Runner.bdayImageSprite;
+ this.groundYPos = Runner.defaultDimensions.HEIGHT - this.config.HEIGHT -
+ Runner.config.BOTTOM_PAD_BDAY;
+ this.yPos -= Runner.config.BDAY_Y_POS_ADJUST;
+ },
+
+ /**
+ * @param {boolean} status Whether dino is flashing.
+ */
+ setFlashing: function(status) {
+ this.flashing = status;
+ },
+
+ /**
* Setter for the jump velocity.
* The approriate drop velocity is also set.
*/
@@ -1695,7 +1785,7 @@ Trex.prototype = {
}
// Update the frame position.
- if (this.timer >= this.msPerFrame) {
+ if (!this.flashing && this.timer >= this.msPerFrame) {
this.currentFrame = this.currentFrame ==
this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1;
this.timer = 0;
@@ -1718,7 +1808,10 @@ Trex.prototype = {
var sourceY = y;
var sourceWidth = this.ducking && this.status != Trex.status.CRASHED ?
this.config.WIDTH_DUCK : this.config.WIDTH;
- var sourceHeight = this.config.HEIGHT;
+ var sourceHeight = this.bdayModeActive ? this.config.HEIGHT_BDAY :
+ this.config.HEIGHT;
+ var outputHeight = sourceHeight;
+
if (IS_HIDPI) {
sourceX *= 2;
@@ -1731,23 +1824,33 @@ Trex.prototype = {
sourceX += this.spritePos.x;
sourceY += this.spritePos.y;
+ // Flashing.
+ if (this.flashing) {
+ if (this.timer < this.config.FLASH_ON) {
+ this.canvasCtx.globalAlpha = 0.5;
+ } else if (this.timer > this.config.FLASH_OFF) {
+ this.timer = 0;
+ }
+ }
+
// Ducking.
if (this.ducking && this.status != Trex.status.CRASHED) {
- this.canvasCtx.drawImage(Runner.imageSprite, sourceX, sourceY,
+ this.canvasCtx.drawImage(this.imageSprite, sourceX, sourceY,
sourceWidth, sourceHeight,
this.xPos, this.yPos,
- this.config.WIDTH_DUCK, this.config.HEIGHT);
+ this.config.WIDTH_DUCK, outputHeight);
} else {
// Crashed whilst ducking. Trex is standing up so needs adjustment.
if (this.ducking && this.status == Trex.status.CRASHED) {
this.xPos++;
}
// Standing / running
- this.canvasCtx.drawImage(Runner.imageSprite, sourceX, sourceY,
+ this.canvasCtx.drawImage(this.imageSprite, sourceX, sourceY,
sourceWidth, sourceHeight,
this.xPos, this.yPos,
- this.config.WIDTH, this.config.HEIGHT);
+ this.config.WIDTH, outputHeight);
}
+ this.canvasCtx.globalAlpha = 1;
},
/**
@@ -1835,8 +1938,6 @@ Trex.prototype = {
this.reset();
this.jumpCount++;
}
-
- this.update(deltaTime);
},
/**
@@ -2144,9 +2245,10 @@ DistanceMeter.prototype = {
* Similar to an obstacle object but without collision boxes.
* @param {HTMLCanvasElement} canvas Canvas element.
* @param {Object} spritePos Position of image in sprite.
+ * @param {boolean} isBalloon Switch Cloud to balloon.
* @param {number} containerWidth
*/
-function Cloud(canvas, spritePos, containerWidth) {
+function Cloud(canvas, spritePos, containerWidth, isBalloon) {
this.canvas = canvas;
this.canvasCtx = this.canvas.getContext('2d');
this.spritePos = spritePos;
@@ -2156,6 +2258,8 @@ function Cloud(canvas, spritePos, containerWidth) {
this.remove = false;
this.cloudGap = getRandomNum(Cloud.config.MIN_CLOUD_GAP,
Cloud.config.MAX_CLOUD_GAP);
+ this.isBalloon = isBalloon;
+ this.imageSprite = isBalloon ? Runner.bdayImageSprite : Runner.imageSprite;
this.init();
};
@@ -2167,11 +2271,13 @@ function Cloud(canvas, spritePos, containerWidth) {
*/
Cloud.config = {
HEIGHT: 14,
+ HEIGHT_BALLOON: 34,
MAX_CLOUD_GAP: 400,
MAX_SKY_LEVEL: 30,
MIN_CLOUD_GAP: 100,
MIN_SKY_LEVEL: 71,
- WIDTH: 46
+ WIDTH: 46,
+ WIDTH_BALLOON: 16
};
@@ -2190,19 +2296,22 @@ Cloud.prototype = {
*/
draw: function() {
this.canvasCtx.save();
- var sourceWidth = Cloud.config.WIDTH;
- var sourceHeight = Cloud.config.HEIGHT;
-
+ var sourceWidth = this.isBalloon ? Cloud.config.WIDTH_BALLOON :
+ Cloud.config.WIDTH;
+ var sourceHeight = this.isBalloon ? Cloud.config.HEIGHT_BALLOON :
+ Cloud.config.HEIGHT;
+ var outputWidth = sourceWidth;
+ var outputHeight = sourceHeight;
if (IS_HIDPI) {
sourceWidth = sourceWidth * 2;
sourceHeight = sourceHeight * 2;
}
- this.canvasCtx.drawImage(Runner.imageSprite, this.spritePos.x,
+ this.canvasCtx.drawImage(this.imageSprite, this.spritePos.x,
this.spritePos.y,
sourceWidth, sourceHeight,
this.xPos, this.yPos,
- Cloud.config.WIDTH, Cloud.config.HEIGHT);
+ outputWidth, outputHeight);
this.canvasCtx.restore();
},
@@ -2540,6 +2649,7 @@ function Horizon(canvas, spritePos, dimensions, gapCoefficient) {
this.cloudFrequency = this.config.CLOUD_FREQUENCY;
this.spritePos = spritePos;
this.nightMode = null;
+ this.bdayModeActive = false;
// Cloud
this.clouds = [];
@@ -2576,6 +2686,14 @@ Horizon.prototype = {
},
/**
+ * Enable additional items.
+ */
+ enableBdayMode: function() {
+ this.bdayModeActive = true;
+ this.removeFirstObstacle();
+ },
+
+ /**
* @param {number} deltaTime
* @param {number} currentSpeed
* @param {boolean} updateObstacles Used as an override to prevent
@@ -2671,7 +2789,10 @@ Horizon.prototype = {
* @param {number} currentSpeed
*/
addNewObstacle: function(currentSpeed) {
- var obstacleTypeIndex = getRandomNum(0, Obstacle.types.length - 1);
+ var obstacleCount = Runner.isBdayModeEnabled() &&
+ !this.bdayModeActive ? Obstacle.types.length - 1 :
+ Obstacle.types.length - 2;
+ var obstacleTypeIndex = getRandomNum(0, obstacleCount);
var obstacleType = Obstacle.types[obstacleTypeIndex];
// Check for multiples of the same type of obstacle.
@@ -2733,8 +2854,10 @@ Horizon.prototype = {
* Add a new cloud to the horizon.
*/
addCloud: function() {
- this.clouds.push(new Cloud(this.canvas, this.spritePos.CLOUD,
- this.dimensions.WIDTH));
+ var cloudType = this.bdayModeActive && getRandomNum(0, 1) > 0 ?
+ this.spritePos.BALLOON : this.spritePos.CLOUD;
+ this.clouds.push(new Cloud(this.canvas, cloudType,
+ this.dimensions.WIDTH, cloudType == this.spritePos.BALLOON));
}
};
})();
diff --git a/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc b/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc
index ec2d6f38a28..bc49b08c908 100644
--- a/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc
+++ b/chromium/components/network_hints/renderer/renderer_dns_prefetch.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/network_hints/common/network_hints_common.h"
#include "components/network_hints/common/network_hints_messages.h"
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator.cc b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
index 6857609fd21..d9f2a3d0d7d 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator.cc
@@ -24,8 +24,8 @@
#include "net/base/host_mapping_rules.h"
#include "net/http/http_stream_factory.h"
#include "net/quic/chromium/quic_utils_chromium.h"
-#include "net/quic/core/quic_packets.h"
-#include "net/spdy/core/spdy_protocol.h"
+#include "net/third_party/quic/core/quic_packets.h"
+#include "net/third_party/spdy/core/spdy_protocol.h"
namespace {
@@ -80,9 +80,9 @@ void ConfigureTCPFastOpenParams(const base::CommandLine& command_line,
}
}
-net::SettingsMap GetHttp2Settings(
+spdy::SettingsMap GetHttp2Settings(
const VariationParameters& http2_trial_params) {
- net::SettingsMap http2_settings;
+ spdy::SettingsMap http2_settings;
const std::string settings_string =
GetVariationParam(http2_trial_params, "http2_settings");
@@ -100,7 +100,7 @@ net::SettingsMap GetHttp2Settings(
uint32_t value;
if (!base::StringToUint(key_value.second, &value))
continue;
- http2_settings[static_cast<net::SpdyKnownSettingsId>(key)] = value;
+ http2_settings[static_cast<spdy::SpdyKnownSettingsId>(key)] = value;
}
return http2_settings;
@@ -263,27 +263,6 @@ bool ShouldQuicHeadersIncludeH2StreamDependencies(
"true");
}
-bool ShouldQuicConnectUsingDefaultNetwork(
- const VariationParameters& quic_trial_params) {
- return base::LowerCaseEqualsASCII(
- GetVariationParam(quic_trial_params, "connect_using_default_network"),
- "true");
-}
-
-bool ShouldQuicMigrateSessionsOnNetworkChange(
- const VariationParameters& quic_trial_params) {
- return base::LowerCaseEqualsASCII(
- GetVariationParam(quic_trial_params,
- "migrate_sessions_on_network_change"),
- "true");
-}
-
-bool ShouldQuicMigrateSessionsEarly(
- const VariationParameters& quic_trial_params) {
- return base::LowerCaseEqualsASCII(
- GetVariationParam(quic_trial_params, "migrate_sessions_early"), "true");
-}
-
bool ShouldQuicMigrateSessionsOnNetworkChangeV2(
const VariationParameters& quic_trial_params) {
return base::LowerCaseEqualsASCII(
@@ -419,12 +398,6 @@ void ConfigureQuicParams(base::StringPiece quic_trial_group,
ShouldQuicEstimateInitialRtt(quic_trial_params);
params->quic_headers_include_h2_stream_dependency =
ShouldQuicHeadersIncludeH2StreamDependencies(quic_trial_params);
- params->quic_connect_using_default_network =
- ShouldQuicConnectUsingDefaultNetwork(quic_trial_params);
- params->quic_migrate_sessions_on_network_change =
- ShouldQuicMigrateSessionsOnNetworkChange(quic_trial_params);
- params->quic_migrate_sessions_early =
- ShouldQuicMigrateSessionsEarly(quic_trial_params);
params->quic_migrate_sessions_on_network_change_v2 =
ShouldQuicMigrateSessionsOnNetworkChangeV2(quic_trial_params);
params->quic_migrate_sessions_early_v2 =
@@ -584,6 +557,8 @@ void ParseCommandLineAndFieldTrials(const base::CommandLine& command_line,
params->enable_token_binding =
base::FeatureList::IsEnabled(features::kTokenBinding);
+ params->enable_channel_id =
+ base::FeatureList::IsEnabled(features::kChannelID);
}
net::URLRequestContextBuilder::HttpCacheParams::Type ChooseCacheType(
diff --git a/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index 9ba7e76cbb2..7e14acff63c 100644
--- a/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/chromium/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -19,9 +19,9 @@
#include "net/base/host_mapping_rules.h"
#include "net/base/host_port_pair.h"
#include "net/http/http_stream_factory.h"
-#include "net/quic/core/crypto/crypto_protocol.h"
-#include "net/quic/core/quic_packets.h"
-#include "net/spdy/core/spdy_protocol.h"
+#include "net/third_party/quic/core/crypto/crypto_protocol.h"
+#include "net/third_party/quic/core/quic_packets.h"
+#include "net/third_party/spdy/core/spdy_protocol.h"
#include "net/url_request/url_request_context_builder.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -102,7 +102,6 @@ TEST_F(NetworkSessionConfiguratorTest, EnableQuicFromFieldTrialGroup) {
params_.quic_max_idle_time_before_crypto_handshake_seconds);
EXPECT_FALSE(params_.quic_race_cert_verification);
EXPECT_FALSE(params_.quic_estimate_initial_rtt);
- EXPECT_FALSE(params_.quic_connect_using_default_network);
EXPECT_FALSE(params_.quic_migrate_sessions_on_network_change);
EXPECT_FALSE(params_.quic_migrate_sessions_early);
EXPECT_FALSE(params_.quic_migrate_sessions_on_network_change_v2);
@@ -300,30 +299,6 @@ TEST_F(NetworkSessionConfiguratorTest, QuicEstimateInitialRtt) {
}
TEST_F(NetworkSessionConfiguratorTest,
- QuicConnectUsingDefaultNetworkFromFieldTrialParams) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["connect_using_default_network"] = "true";
- variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.quic_connect_using_default_network);
-}
-
-TEST_F(NetworkSessionConfiguratorTest,
- QuicMigrateSessionsOnNetworkChangeFromFieldTrialParams) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["migrate_sessions_on_network_change"] = "true";
- variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.quic_migrate_sessions_on_network_change);
-}
-
-TEST_F(NetworkSessionConfiguratorTest,
QuicMigrateSessionsOnNetworkChangeV2FromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["migrate_sessions_on_network_change_v2"] = "true";
@@ -336,18 +311,6 @@ TEST_F(NetworkSessionConfiguratorTest,
}
TEST_F(NetworkSessionConfiguratorTest,
- QuicMigrateSessionsEarlyFromFieldTrialParams) {
- std::map<std::string, std::string> field_trial_params;
- field_trial_params["migrate_sessions_early"] = "true";
- variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
- base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
-
- ParseFieldTrials();
-
- EXPECT_TRUE(params_.quic_migrate_sessions_early);
-}
-
-TEST_F(NetworkSessionConfiguratorTest,
QuicMigrateSessionsEarlyV2FromFieldTrialParams) {
std::map<std::string, std::string> field_trial_params;
field_trial_params["migrate_sessions_early_v2"] = "true";
@@ -526,9 +489,9 @@ TEST_F(NetworkSessionConfiguratorTest, Http2SettingsFromFieldTrialParams) {
ParseFieldTrials();
- net::SettingsMap expected_settings;
- expected_settings[static_cast<net::SpdyKnownSettingsId>(7)] = 1234;
- expected_settings[static_cast<net::SpdyKnownSettingsId>(25)] = 5678;
+ spdy::SettingsMap expected_settings;
+ expected_settings[static_cast<spdy::SpdyKnownSettingsId>(7)] = 1234;
+ expected_settings[static_cast<spdy::SpdyKnownSettingsId>(25)] = 5678;
EXPECT_EQ(expected_settings, params_.http2_settings);
}
@@ -712,6 +675,26 @@ TEST_F(NetworkSessionConfiguratorTest, TokenBindingEnabled) {
EXPECT_TRUE(params_.enable_token_binding);
}
+TEST_F(NetworkSessionConfiguratorTest, ChannelIDEnabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kChannelID);
+
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ ParseCommandLineAndFieldTrials(command_line);
+
+ EXPECT_TRUE(params_.enable_channel_id);
+}
+
+TEST_F(NetworkSessionConfiguratorTest, ChannelIDDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(features::kChannelID);
+
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ ParseCommandLineAndFieldTrials(command_line);
+
+ EXPECT_FALSE(params_.enable_channel_id);
+}
+
TEST_F(NetworkSessionConfiguratorTest, DefaultCacheBackend) {
base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS)
diff --git a/chromium/components/network_session_configurator/common/network_features.cc b/chromium/components/network_session_configurator/common/network_features.cc
index 87dbb7d9456..3a8d564dfd1 100644
--- a/chromium/components/network_session_configurator/common/network_features.cc
+++ b/chromium/components/network_session_configurator/common/network_features.cc
@@ -4,11 +4,16 @@
#include "components/network_session_configurator/common/network_features.h"
+#include "build/build_config.h"
+
namespace features {
const base::Feature kTokenBinding{"token-binding",
base::FEATURE_DISABLED_BY_DEFAULT};
+// TODO(nharper): Disable kChannelID on all platforms in M69.
+const base::Feature kChannelID{"channel-id", base::FEATURE_ENABLED_BY_DEFAULT};
+
const base::Feature kDnsOverHttps{"dns-over-https",
base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/network_session_configurator/common/network_features.h b/chromium/components/network_session_configurator/common/network_features.h
index 6d92c7ac673..cf64c0b31e2 100644
--- a/chromium/components/network_session_configurator/common/network_features.h
+++ b/chromium/components/network_session_configurator/common/network_features.h
@@ -14,6 +14,9 @@ namespace features {
// (https://www.ietf.org/id/draft-ietf-tokbind-protocol-04.txt).
NETWORK_SESSION_CONFIGURATOR_EXPORT extern const base::Feature kTokenBinding;
+// Enables Channel ID.
+NETWORK_SESSION_CONFIGURATOR_EXPORT extern const base::Feature kChannelID;
+
// Enabled DNS over HTTPS
// (https://tools.ietf.org/id/draft-ietf-doh-dns-over-https-02.txt).
NETWORK_SESSION_CONFIGURATOR_EXPORT extern const base::Feature kDnsOverHttps;
diff --git a/chromium/components/ntp_snippets/BUILD.gn b/chromium/components/ntp_snippets/BUILD.gn
index 88f8092c998..407a0b0486e 100644
--- a/chromium/components/ntp_snippets/BUILD.gn
+++ b/chromium/components/ntp_snippets/BUILD.gn
@@ -46,14 +46,18 @@ static_library("ntp_snippets") {
"content_suggestions_provider.h",
"content_suggestions_service.cc",
"content_suggestions_service.h",
- "contextual/cluster.cc",
- "contextual/cluster.h",
"contextual/contextual_content_suggestions_service.cc",
"contextual/contextual_content_suggestions_service.h",
"contextual/contextual_content_suggestions_service_proxy.cc",
"contextual/contextual_content_suggestions_service_proxy.h",
"contextual/contextual_suggestion.cc",
"contextual/contextual_suggestion.h",
+ "contextual/contextual_suggestions_composite_reporter.cc",
+ "contextual/contextual_suggestions_composite_reporter.h",
+ "contextual/contextual_suggestions_debugging_reporter.cc",
+ "contextual/contextual_suggestions_debugging_reporter.h",
+ "contextual/contextual_suggestions_features.cc",
+ "contextual/contextual_suggestions_features.h",
"contextual/contextual_suggestions_fetch.cc",
"contextual/contextual_suggestions_fetch.h",
"contextual/contextual_suggestions_fetcher.h",
@@ -61,6 +65,10 @@ static_library("ntp_snippets") {
"contextual/contextual_suggestions_fetcher_impl.h",
"contextual/contextual_suggestions_metrics_reporter.cc",
"contextual/contextual_suggestions_metrics_reporter.h",
+ "contextual/contextual_suggestions_reporter.cc",
+ "contextual/contextual_suggestions_reporter.h",
+ "contextual/contextual_suggestions_result.cc",
+ "contextual/contextual_suggestions_result.h",
"contextual/contextual_suggestions_ukm_entry.cc",
"contextual/contextual_suggestions_ukm_entry.h",
"features.cc",
@@ -69,10 +77,6 @@ static_library("ntp_snippets") {
"logger.h",
"ntp_snippets_constants.cc",
"ntp_snippets_constants.h",
- "offline_pages/recent_tab_suggestions_provider.cc",
- "offline_pages/recent_tab_suggestions_provider.h",
- "physical_web_pages/physical_web_page_suggestions_provider.cc",
- "physical_web_pages/physical_web_page_suggestions_provider.h",
"pref_names.cc",
"pref_names.h",
"pref_util.cc",
@@ -158,15 +162,10 @@ static_library("ntp_snippets") {
"//components/metrics",
"//components/ntp_snippets/remote/proto",
"//components/offline_pages/core",
- "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
- "//components/offline_pages/core/recent_tabs",
- "//components/physical_web/data_source",
"//components/reading_list/core",
"//components/sessions",
"//components/strings",
"//components/sync_sessions",
-
- # "//components/ukm/content",
"//components/url_formatter",
"//components/variations",
"//components/variations/net",
@@ -174,6 +173,7 @@ static_library("ntp_snippets") {
"//components/web_resource",
"//services/identity/public/cpp",
"//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//services/network/public/cpp",
"//services/network/public/mojom",
"//third_party/icu/",
@@ -189,7 +189,7 @@ if (is_android) {
"category_info.h",
"category_status.h",
"content_suggestions_service.cc",
- "contextual/contextual_suggestions_metrics_reporter.h",
+ "contextual/contextual_suggestions_reporter.h",
]
}
}
@@ -216,12 +216,12 @@ source_set("unit_tests") {
"content_suggestions_service_unittest.cc",
"contextual/contextual_content_suggestions_service_proxy_unittest.cc",
"contextual/contextual_content_suggestions_service_unittest.cc",
+ "contextual/contextual_suggestions_composite_reporter_unittest.cc",
+ "contextual/contextual_suggestions_fetch_unittest.cc",
"contextual/contextual_suggestions_fetcher_impl_unittest.cc",
"contextual/contextual_suggestions_metrics_reporter_unittest.cc",
"contextual/contextual_suggestions_ukm_entry_unittest.cc",
"logger_unittest.cc",
- "offline_pages/recent_tab_suggestions_provider_unittest.cc",
- "physical_web_pages/physical_web_page_suggestions_provider_unittest.cc",
"reading_list/reading_list_suggestions_provider_unittest.cc",
"remote/cached_image_fetcher_unittest.cc",
"remote/json_request_unittest.cc",
@@ -262,9 +262,6 @@ source_set("unit_tests") {
"//components/offline_pages/core",
"//components/offline_pages/core:test_support",
"//components/offline_pages/core/background:test_support",
- "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
- "//components/offline_pages/core/recent_tabs",
- "//components/physical_web/data_source:test_support",
"//components/prefs:test_support",
"//components/reading_list/core",
"//components/sessions",
@@ -280,6 +277,7 @@ source_set("unit_tests") {
"//net:test_support",
"//services/identity/public/cpp",
"//services/identity/public/cpp:test_support",
+ "//services/metrics/public/cpp:ukm_builders",
"//services/network:test_support",
"//services/network/public/cpp",
"//services/network/public/mojom",
@@ -296,6 +294,8 @@ source_set("test_support") {
"category_rankers/fake_category_ranker.h",
"category_rankers/mock_category_ranker.cc",
"category_rankers/mock_category_ranker.h",
+ "contextual/contextual_suggestions_test_utils.cc",
+ "contextual/contextual_suggestions_test_utils.h",
"fake_content_suggestions_provider_observer.cc",
"fake_content_suggestions_provider_observer.h",
"mock_content_suggestions_provider.cc",
diff --git a/chromium/components/ntp_snippets/OWNERS b/chromium/components/ntp_snippets/OWNERS
index ed0519eb118..ce4cfc960fb 100644
--- a/chromium/components/ntp_snippets/OWNERS
+++ b/chromium/components/ntp_snippets/OWNERS
@@ -13,3 +13,5 @@ vitaliii@chromium.org
# For ios:
noyau@chromium.org
+
+# COMPONENT: UI>Browser>ContentSuggestions \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
index 6e7b8fc4a4f..1efb4131cde 100644
--- a/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
+++ b/chromium/components/ntp_snippets/bookmarks/bookmark_last_visit_utils.cc
@@ -16,11 +16,13 @@
#include "base/time/time.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_node.h"
+#include "components/bookmarks/browser/url_and_title.h"
#include "components/ntp_snippets/time_serialization.h"
#include "url/gurl.h"
using bookmarks::BookmarkModel;
using bookmarks::BookmarkNode;
+using bookmarks::UrlAndTitle;
namespace ntp_snippets {
@@ -163,11 +165,11 @@ bool IsDismissedFromNTPForBookmark(const BookmarkNode& node) {
void MarkAllBookmarksUndismissed(BookmarkModel* bookmark_model) {
// Get all the bookmark URLs.
- std::vector<BookmarkModel::URLAndTitle> bookmarks;
+ std::vector<UrlAndTitle> bookmarks;
bookmark_model->GetBookmarks(&bookmarks);
// Remove dismissed flag from all bookmarks
- for (const BookmarkModel::URLAndTitle& bookmark : bookmarks) {
+ for (const UrlAndTitle& bookmark : bookmarks) {
std::vector<const BookmarkNode*> nodes;
bookmark_model->GetNodesByURL(bookmark.url, &nodes);
for (const BookmarkNode* node : nodes) {
@@ -182,13 +184,13 @@ std::vector<const BookmarkNode*> GetRecentlyVisitedBookmarks(
const base::Time& min_visit_time,
bool consider_visits_from_desktop) {
// Get all the bookmark URLs.
- std::vector<BookmarkModel::URLAndTitle> bookmark_urls;
+ std::vector<UrlAndTitle> bookmark_urls;
bookmark_model->GetBookmarks(&bookmark_urls);
std::vector<RecentBookmark> bookmarks;
// Find for each bookmark the most recently visited BookmarkNode and find out
// whether it is visited since |min_visit_time|.
- for (const BookmarkModel::URLAndTitle& url_and_title : bookmark_urls) {
+ for (const UrlAndTitle& url_and_title : bookmark_urls) {
// Skip URLs that are blacklisted.
if (IsBlacklisted(url_and_title.url)) {
continue;
@@ -241,27 +243,26 @@ std::vector<const BookmarkNode*> GetRecentlyVisitedBookmarks(
std::vector<const BookmarkNode*> GetDismissedBookmarksForDebugging(
BookmarkModel* bookmark_model) {
// Get all the bookmark URLs.
- std::vector<BookmarkModel::URLAndTitle> bookmarks;
+ std::vector<UrlAndTitle> bookmarks;
bookmark_model->GetBookmarks(&bookmarks);
// Remove the bookmark URLs which have at least one non-dismissed bookmark.
- base::EraseIf(
- bookmarks, [&bookmark_model](const BookmarkModel::URLAndTitle& bookmark) {
- std::vector<const BookmarkNode*> bookmarks_for_url;
- bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url);
- DCHECK(!bookmarks_for_url.empty());
-
- for (const BookmarkNode* node : bookmarks_for_url) {
- if (!IsDismissedFromNTPForBookmark(*node)) {
- return true;
- }
- }
- return false;
- });
+ base::EraseIf(bookmarks, [&bookmark_model](const UrlAndTitle& bookmark) {
+ std::vector<const BookmarkNode*> bookmarks_for_url;
+ bookmark_model->GetNodesByURL(bookmark.url, &bookmarks_for_url);
+ DCHECK(!bookmarks_for_url.empty());
+
+ for (const BookmarkNode* node : bookmarks_for_url) {
+ if (!IsDismissedFromNTPForBookmark(*node)) {
+ return true;
+ }
+ }
+ return false;
+ });
// Insert into |result|.
std::vector<const BookmarkNode*> result;
- for (const BookmarkModel::URLAndTitle& bookmark : bookmarks) {
+ for (const UrlAndTitle& bookmark : bookmarks) {
result.push_back(
bookmark_model->GetMostRecentlyAddedUserNodeForURL(bookmark.url));
}
@@ -289,10 +290,10 @@ void RemoveLastVisitedDatesBetween(const base::Time& begin,
base::Callback<bool(const GURL& url)> filter,
bookmarks::BookmarkModel* bookmark_model) {
// Get all the bookmark URLs.
- std::vector<BookmarkModel::URLAndTitle> bookmark_urls;
+ std::vector<UrlAndTitle> bookmark_urls;
bookmark_model->GetBookmarks(&bookmark_urls);
- for (const BookmarkModel::URLAndTitle& url_and_title : bookmark_urls) {
+ for (const UrlAndTitle& url_and_title : bookmark_urls) {
if (!filter.Run(url_and_title.url)) {
continue;
}
diff --git a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
index f79296ea258..0851b482aa9 100644
--- a/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/breaking_news/subscription_manager_impl_unittest.cc
@@ -178,7 +178,7 @@ TEST_F(SubscriptionManagerImplTest,
manager->Subscribe(subscription_token);
// Wait for the access token request and issue the access token.
- GetIdentityTestEnv()->WaitForAccessTokenRequestAndRespondWithToken(
+ GetIdentityTestEnv()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
ASSERT_FALSE(manager->IsSubscribed());
@@ -247,7 +247,7 @@ TEST_F(SubscriptionManagerImplTest,
// Wait for the access token request that should occur and grant the access
// token.
- GetIdentityTestEnv()->WaitForAccessTokenRequestAndRespondWithToken(
+ GetIdentityTestEnv()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/true);
@@ -269,7 +269,7 @@ TEST_F(SubscriptionManagerImplTest,
std::unique_ptr<SubscriptionManagerImpl> manager = BuildSubscriptionManager();
manager->Subscribe(subscription_token);
- GetIdentityTestEnv()->WaitForAccessTokenRequestAndRespondWithToken(
+ GetIdentityTestEnv()->WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
RespondToSubscriptionRequestSuccessfully(/*is_signed_in=*/true);
diff --git a/chromium/components/ntp_snippets/category.h b/chromium/components/ntp_snippets/category.h
index c40ed5ded2a..d4210498841 100644
--- a/chromium/components/ntp_snippets/category.h
+++ b/chromium/components/ntp_snippets/category.h
@@ -20,7 +20,7 @@ namespace ntp_snippets {
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.ntp.snippets
enum class KnownCategories {
// Pages recently downloaded during normal navigation.
- RECENT_TABS,
+ RECENT_TABS_DEPRECATED,
// Pages downloaded by the user for offline consumption.
DOWNLOADS,
@@ -29,7 +29,7 @@ enum class KnownCategories {
BOOKMARKS,
// Physical Web page available in the vicinity.
- PHYSICAL_WEB_PAGES,
+ PHYSICAL_WEB_PAGES_DEPRECATED,
// Pages recently browsed to on other devices.
FOREIGN_TABS,
diff --git a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
index 8bd537e8404..bdc779d1e6d 100644
--- a/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
+++ b/chromium/components/ntp_snippets/category_rankers/click_based_category_ranker_unittest.cc
@@ -608,13 +608,7 @@ TEST_F(ClickBasedCategoryRankerTest,
ResetRanker(base::DefaultClock::GetInstance());
// Make sure we have the default order.
EXPECT_TRUE(CompareCategories(
- Category::FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES),
- Category::FromKnownCategory(KnownCategories::DOWNLOADS)));
- EXPECT_TRUE(CompareCategories(
Category::FromKnownCategory(KnownCategories::DOWNLOADS),
- Category::FromKnownCategory(KnownCategories::RECENT_TABS)));
- EXPECT_TRUE(CompareCategories(
- Category::FromKnownCategory(KnownCategories::RECENT_TABS),
Category::FromKnownCategory(KnownCategories::FOREIGN_TABS)));
EXPECT_TRUE(CompareCategories(
Category::FromKnownCategory(KnownCategories::FOREIGN_TABS),
@@ -625,42 +619,42 @@ TEST_F(ClickBasedCategoryRankerTest,
}
TEST_F(ClickBasedCategoryRankerTest, ShouldEndPromotionOnSectionDismissal) {
- const Category physical_web =
- Category::FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES);
+ const Category downloads =
+ Category::FromKnownCategory(KnownCategories::DOWNLOADS);
const Category articles =
Category::FromKnownCategory(KnownCategories::ARTICLES);
- ASSERT_TRUE(CompareCategories(physical_web, articles));
+ ASSERT_TRUE(CompareCategories(downloads, articles));
SetPromotedCategoryVariationParam(articles.id());
ResetRanker(base::DefaultClock::GetInstance());
- ASSERT_TRUE(CompareCategories(articles, physical_web));
+ ASSERT_TRUE(CompareCategories(articles, downloads));
ranker()->OnCategoryDismissed(articles);
- EXPECT_FALSE(CompareCategories(articles, physical_web));
- EXPECT_TRUE(CompareCategories(physical_web, articles));
+ EXPECT_FALSE(CompareCategories(articles, downloads));
+ EXPECT_TRUE(CompareCategories(downloads, articles));
}
TEST_F(ClickBasedCategoryRankerTest,
ShouldResumePromotionAfter2WeeksSinceDismissal) {
const Category downloads =
Category::FromKnownCategory(KnownCategories::DOWNLOADS);
- const Category recent_tabs =
- Category::FromKnownCategory(KnownCategories::RECENT_TABS);
- ASSERT_TRUE(CompareCategories(downloads, recent_tabs));
+ const Category foreign_tabs =
+ Category::FromKnownCategory(KnownCategories::FOREIGN_TABS);
+ ASSERT_TRUE(CompareCategories(downloads, foreign_tabs));
- SetPromotedCategoryVariationParam(recent_tabs.id());
+ SetPromotedCategoryVariationParam(foreign_tabs.id());
ResetRanker(base::DefaultClock::GetInstance());
- ASSERT_TRUE(CompareCategories(recent_tabs, downloads));
+ ASSERT_TRUE(CompareCategories(foreign_tabs, downloads));
- ranker()->OnCategoryDismissed(recent_tabs);
- ASSERT_FALSE(CompareCategories(recent_tabs, downloads));
+ ranker()->OnCategoryDismissed(foreign_tabs);
+ ASSERT_FALSE(CompareCategories(foreign_tabs, downloads));
// Simulate a little over 2 weeks of time passing.
base::SimpleTestClock test_clock;
test_clock.SetNow(base::Time::Now() + base::TimeDelta::FromDays(15));
ResetRanker(&test_clock);
- EXPECT_TRUE(CompareCategories(recent_tabs, downloads));
+ EXPECT_TRUE(CompareCategories(foreign_tabs, downloads));
}
TEST_F(ClickBasedCategoryRankerTest,
diff --git a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
index c7ab47db3bf..00a6ae3f213 100644
--- a/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
+++ b/chromium/components/ntp_snippets/category_rankers/constant_category_ranker.cc
@@ -122,10 +122,8 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
// KnownCategories::CONTEXTUAL because it is not handled by
// ContentSuggestionsService.
case CategoryOrderChoice::GENERAL:
- categories.push_back(KnownCategories::PHYSICAL_WEB_PAGES);
categories.push_back(KnownCategories::READING_LIST);
categories.push_back(KnownCategories::DOWNLOADS);
- categories.push_back(KnownCategories::RECENT_TABS);
categories.push_back(KnownCategories::FOREIGN_TABS);
categories.push_back(KnownCategories::BOOKMARKS);
categories.push_back(KnownCategories::ARTICLES);
@@ -136,8 +134,6 @@ ConstantCategoryRanker::GetKnownCategoriesDefaultOrder() {
categories.push_back(KnownCategories::DOWNLOADS);
categories.push_back(KnownCategories::BOOKMARKS);
- categories.push_back(KnownCategories::PHYSICAL_WEB_PAGES);
- categories.push_back(KnownCategories::RECENT_TABS);
categories.push_back(KnownCategories::FOREIGN_TABS);
break;
}
diff --git a/chromium/components/ntp_snippets/content_suggestion.cc b/chromium/components/ntp_snippets/content_suggestion.cc
index c3919f7c740..5dd75b9c7f4 100644
--- a/chromium/components/ntp_snippets/content_suggestion.cc
+++ b/chromium/components/ntp_snippets/content_suggestion.cc
@@ -57,12 +57,6 @@ void ContentSuggestion::set_download_suggestion_extra(
download_suggestion_extra_ = std::move(download_suggestion_extra);
}
-void ContentSuggestion::set_recent_tab_suggestion_extra(
- std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra) {
- DCHECK(id_.category().IsKnownCategory(KnownCategories::RECENT_TABS));
- recent_tab_suggestion_extra_ = std::move(recent_tab_suggestion_extra);
-}
-
void ContentSuggestion::set_reading_list_suggestion_extra(
std::unique_ptr<ReadingListSuggestionExtra> reading_list_suggestion_extra) {
DCHECK(id_.category().IsKnownCategory(KnownCategories::READING_LIST));
diff --git a/chromium/components/ntp_snippets/content_suggestion.h b/chromium/components/ntp_snippets/content_suggestion.h
index b6cf3f42957..0dca3716c54 100644
--- a/chromium/components/ntp_snippets/content_suggestion.h
+++ b/chromium/components/ntp_snippets/content_suggestion.h
@@ -40,14 +40,6 @@ struct DownloadSuggestionExtra {
bool is_download_asset = false;
};
-// Contains additional data which is only available for recent tab suggestions.
-struct RecentTabSuggestionExtra {
- // Corresponding tab identifier.
- int tab_id;
- // Underlying offline page identifier.
- int64_t offline_page_id = 0;
-};
-
// ReadingListSuggestionExtra contains additional data which is only available
// for Reading List suggestions.
struct ReadingListSuggestionExtra {
@@ -163,14 +155,6 @@ class ContentSuggestion {
void set_download_suggestion_extra(
std::unique_ptr<DownloadSuggestionExtra> download_suggestion_extra);
- // Extra information for recent tab suggestions. Only available for
- // KnownCategories::RECENT_TABS suggestions.
- RecentTabSuggestionExtra* recent_tab_suggestion_extra() const {
- return recent_tab_suggestion_extra_.get();
- }
- void set_recent_tab_suggestion_extra(
- std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra);
-
// Extra information for reading list suggestions. Only available for
// KnownCategories::READING_LIST suggestions.
ReadingListSuggestionExtra* reading_list_suggestion_extra() const {
@@ -213,7 +197,6 @@ class ContentSuggestion {
base::string16 publisher_name_;
float score_;
std::unique_ptr<DownloadSuggestionExtra> download_suggestion_extra_;
- std::unique_ptr<RecentTabSuggestionExtra> recent_tab_suggestion_extra_;
std::unique_ptr<ReadingListSuggestionExtra> reading_list_suggestion_extra_;
std::unique_ptr<NotificationExtra> notification_extra_;
diff --git a/chromium/components/ntp_snippets/content_suggestions_metrics.cc b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
index 5c6746ce293..2b7e3caa9ea 100644
--- a/chromium/components/ntp_snippets/content_suggestions_metrics.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_metrics.cc
@@ -81,10 +81,10 @@ const char kPerCategoryHistogramFormat[] = "%s.%s";
// sync with ContentSuggestionsCategory in histograms.xml.
enum class HistogramCategories {
EXPERIMENTAL,
- RECENT_TABS,
+ RECENT_TABS_DEPRECATED,
DOWNLOADS,
BOOKMARKS,
- PHYSICAL_WEB_PAGES,
+ PHYSICAL_WEB_PAGES_DEPRECATED,
FOREIGN_TABS,
ARTICLES,
READING_LIST,
@@ -104,14 +104,10 @@ HistogramCategories GetHistogramCategory(Category category) {
// listed here.
auto known_category = static_cast<KnownCategories>(category.id());
switch (known_category) {
- case KnownCategories::RECENT_TABS:
- return HistogramCategories::RECENT_TABS;
case KnownCategories::DOWNLOADS:
return HistogramCategories::DOWNLOADS;
case KnownCategories::BOOKMARKS:
return HistogramCategories::BOOKMARKS;
- case KnownCategories::PHYSICAL_WEB_PAGES:
- return HistogramCategories::PHYSICAL_WEB_PAGES;
case KnownCategories::FOREIGN_TABS:
return HistogramCategories::FOREIGN_TABS;
case KnownCategories::ARTICLES:
@@ -120,6 +116,8 @@ HistogramCategories GetHistogramCategory(Category category) {
return HistogramCategories::READING_LIST;
case KnownCategories::CONTEXTUAL:
return HistogramCategories::CONTEXTUAL;
+ case KnownCategories::RECENT_TABS_DEPRECATED:
+ case KnownCategories::PHYSICAL_WEB_PAGES_DEPRECATED:
case KnownCategories::LOCAL_CATEGORIES_COUNT:
case KnownCategories::REMOTE_CATEGORIES_OFFSET:
NOTREACHED();
@@ -134,14 +132,10 @@ HistogramCategories GetHistogramCategory(Category category) {
std::string GetCategorySuffix(Category category) {
HistogramCategories histogram_category = GetHistogramCategory(category);
switch (histogram_category) {
- case HistogramCategories::RECENT_TABS:
- return "RecentTabs";
case HistogramCategories::DOWNLOADS:
return "Downloads";
case HistogramCategories::BOOKMARKS:
return "Bookmarks";
- case HistogramCategories::PHYSICAL_WEB_PAGES:
- return "PhysicalWeb";
case HistogramCategories::FOREIGN_TABS:
return "ForeignTabs";
case HistogramCategories::ARTICLES:
@@ -152,6 +146,8 @@ std::string GetCategorySuffix(Category category) {
return "ReadingList";
case HistogramCategories::CONTEXTUAL:
return "Contextual";
+ case HistogramCategories::RECENT_TABS_DEPRECATED:
+ case HistogramCategories::PHYSICAL_WEB_PAGES_DEPRECATED:
case HistogramCategories::COUNT:
NOTREACHED();
break;
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.cc b/chromium/components/ntp_snippets/content_suggestions_service.cc
index 0fc12b6b729..0e320f778ad 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service.cc
@@ -18,6 +18,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
#include "base/values.h"
+#include "components/favicon/core/favicon_server_fetcher_params.h"
#include "components/favicon/core/large_icon_service.h"
#include "components/favicon_base/fallback_icon_style.h"
#include "components/favicon_base/favicon_types.h"
@@ -295,7 +296,8 @@ void ContentSuggestionsService::OnGetFaviconFromCacheFinished(
})");
large_icon_service_
->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- publisher_url, minimum_size_in_pixel, desired_size_in_pixel,
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ publisher_url, minimum_size_in_pixel, desired_size_in_pixel),
/*may_page_url_be_private=*/false, traffic_annotation,
base::Bind(
&ContentSuggestionsService::OnGetFaviconFromGoogleServerFinished,
@@ -532,16 +534,13 @@ void ContentSuggestionsService::OnPrimaryAccountCleared(
// history::HistoryServiceObserver implementation.
void ContentSuggestionsService::OnURLsDeleted(
history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
+ const history::DeletionInfo& deletion_info) {
// We don't care about expired entries.
- if (expired) {
+ if (deletion_info.is_from_expiration()) {
return;
}
- if (all_history) {
+ if (deletion_info.IsAllHistory()) {
base::Callback<bool(const GURL& url)> filter =
base::Bind([](const GURL& url) { return true; });
ClearHistory(base::Time(), base::Time::Max(), filter);
@@ -552,11 +551,11 @@ void ContentSuggestionsService::OnURLsDeleted(
// basis. However this depends on the provider's details and thus cannot be
// done here. Introduce a OnURLsDeleted() method on the providers to move
// this decision further down.
- if (deleted_rows.size() < 2) {
+ if (deletion_info.deleted_rows().size() < 2) {
return;
}
std::set<GURL> deleted_urls;
- for (const history::URLRow& row : deleted_rows) {
+ for (const history::URLRow& row : deletion_info.deleted_rows()) {
deleted_urls.insert(row.url());
}
base::Callback<bool(const GURL& url)> filter =
diff --git a/chromium/components/ntp_snippets/content_suggestions_service.h b/chromium/components/ntp_snippets/content_suggestions_service.h
index 6cc866c2933..00ec36b5a4b 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service.h
+++ b/chromium/components/ntp_snippets/content_suggestions_service.h
@@ -294,10 +294,7 @@ class ContentSuggestionsService : public KeyedService,
// history::HistoryServiceObserver implementation.
void OnURLsDeleted(history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const history::DeletionInfo& deletion_info) override;
void HistoryServiceBeingDeleted(
history::HistoryService* history_service) override;
diff --git a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
index 9c2246a4e4a..8df09e4fbdc 100644
--- a/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
+++ b/chromium/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -576,8 +576,7 @@ TEST_F(ContentSuggestionsServiceTest, ShouldForwardDeleteAllHistoryURLs) {
MakeRegisteredMockProvider(category);
EXPECT_CALL(*provider, ClearHistory(base::Time(), base::Time::Max(), _));
static_cast<history::HistoryServiceObserver*>(service())->OnURLsDeleted(
- /*history_service=*/nullptr, /*all_history=*/true, /*expired=*/false,
- history::URLRows(), /*favicon_urls=*/std::set<GURL>());
+ /*history_service=*/nullptr, history::DeletionInfo::ForAllHistory());
service()->RemoveObserver(&observer);
}
@@ -590,15 +589,19 @@ TEST_F(ContentSuggestionsServiceTest, ShouldIgnoreExpiredURLDeletions) {
service()->AddObserver(&observer);
static_cast<history::HistoryServiceObserver*>(service())->OnURLsDeleted(
- /*history_service=*/nullptr, /*all_history=*/true,
- /*expired=*/true, history::URLRows(),
- /*favicon_urls=*/std::set<GURL>());
+ /*history_service=*/nullptr,
+ history::DeletionInfo(history::DeletionTimeRange::AllTime(),
+ /*expired=*/true, history::URLRows(),
+ /*favicon_urls=*/std::set<GURL>(),
+ /*restrict_urls=*/base::nullopt));
static_cast<history::HistoryServiceObserver*>(service())->OnURLsDeleted(
- /*history_service=*/nullptr, /*all_history=*/false,
- /*expired=*/true,
- history::URLRows({history::URLRow(GURL("http://google.com")),
- history::URLRow(GURL("http://maps.google.com"))}),
- /*favicon_urls=*/std::set<GURL>());
+ /*history_service=*/nullptr,
+ history::DeletionInfo(history::DeletionTimeRange::Invalid(),
+ /*expired=*/true,
+ {history::URLRow(GURL("http://google.com")),
+ history::URLRow(GURL("http://maps.google.com"))},
+ /*favicon_urls=*/std::set<GURL>(),
+ /*restrict_urls=*/base::nullopt));
service()->RemoveObserver(&observer);
}
@@ -607,9 +610,7 @@ TEST_F(ContentSuggestionsServiceTest, ShouldIgnoreEmptyURLDeletions) {
Category category = Category::FromKnownCategory(KnownCategories::DOWNLOADS);
MakeRegisteredMockProvider(category);
static_cast<history::HistoryServiceObserver*>(service())->OnURLsDeleted(
- /*history_service=*/nullptr, /*all_history=*/false,
- /*expired=*/false, history::URLRows(),
- /*favicon_urls=*/std::set<GURL>());
+ /*history_service=*/nullptr, history::DeletionInfo::ForUrls({}, {}));
}
TEST_F(ContentSuggestionsServiceTest,
@@ -618,10 +619,10 @@ TEST_F(ContentSuggestionsServiceTest,
MakeRegisteredMockProvider(category);
// Single URLs should not trigger
static_cast<history::HistoryServiceObserver*>(service())->OnURLsDeleted(
- /*history_service=*/nullptr, /*all_history=*/false,
- /*expired=*/false,
- history::URLRows({history::URLRow(GURL("http://google.com"))}),
- /*favicon_urls=*/std::set<GURL>());
+ /*history_service=*/nullptr,
+ history::DeletionInfo::ForUrls(
+ {history::URLRow(GURL("http://google.com"))},
+ /*favicon_urls=*/std::set<GURL>()));
}
TEST_F(ContentSuggestionsServiceTest,
@@ -636,11 +637,11 @@ TEST_F(ContentSuggestionsServiceTest,
EXPECT_CALL(*provider, ClearHistory(base::Time(), base::Time::Max(), _));
static_cast<history::HistoryServiceObserver*>(service())->OnURLsDeleted(
- /*history_service=*/nullptr, /*all_history=*/false,
- /*expired=*/false,
- history::URLRows({history::URLRow(GURL("http://google.com")),
- history::URLRow(GURL("http://youtube.com"))}),
- /*favicon_urls=*/std::set<GURL>());
+ /*history_service=*/nullptr,
+ history::DeletionInfo::ForUrls(
+ {history::URLRow(GURL("http://google.com")),
+ history::URLRow(GURL("http://youtube.com"))},
+ /*favicon_urls=*/std::set<GURL>()));
service()->RemoveObserver(&observer);
}
diff --git a/chromium/components/ntp_snippets/contextual/cluster.h b/chromium/components/ntp_snippets/contextual/cluster.h
deleted file mode 100644
index 621253867c1..00000000000
--- a/chromium/components/ntp_snippets/contextual/cluster.h
+++ /dev/null
@@ -1,49 +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 COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CLUSTER_H_
-#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CLUSTER_H_
-
-#include "components/ntp_snippets/contextual/contextual_suggestion.h"
-
-using ntp_snippets::ContextualSuggestion;
-using ntp_snippets::SuggestionBuilder;
-
-namespace contextual_suggestions {
-
-// A structure representing a suggestion cluster.
-struct Cluster {
- Cluster();
- Cluster(Cluster&&) noexcept;
- ~Cluster();
-
- std::string title;
- std::vector<ContextualSuggestion> suggestions;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Cluster);
-};
-
-// Allows concise construction of a cluster and copying, which cluster
-// doesn't allow.
-class ClusterBuilder {
- public:
- ClusterBuilder(const std::string& title);
-
- // Allow copying for ease of validation when testing.
- ClusterBuilder(const ClusterBuilder& other);
- ClusterBuilder& AddSuggestion(ContextualSuggestion suggestion);
- Cluster Build();
-
- private:
- Cluster cluster_;
-};
-
-using FetchClustersCallback =
- base::OnceCallback<void(std::string peek_text,
- std::vector<Cluster> clusters)>;
-
-} // namespace contextual_suggestions
-
-#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CLUSTER_H_ \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
index d7bdc7ac3ba..c88ce6ad113 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.cc
@@ -11,24 +11,28 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
-#include "components/ntp_snippets/contextual/cluster.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
#include "components/ntp_snippets/remote/cached_image_fetcher.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
#include "contextual_content_suggestions_service_proxy.h"
#include "ui/gfx/image/image.h"
-namespace ntp_snippets {
+namespace contextual_suggestions {
-using contextual_suggestions::Cluster;
-using contextual_suggestions::ContextualSuggestionsMetricsReporterProvider;
-using contextual_suggestions::FetchClustersCallback;
+using ntp_snippets::ContentSuggestion;
+using ntp_snippets::ImageDataFetchedCallback;
+using ntp_snippets::ImageFetchedCallback;
+using ntp_snippets::CachedImageFetcher;
+using ntp_snippets::RemoteSuggestionsDatabase;
namespace {
bool IsEligibleURL(const GURL& url) {
return url.is_valid() && url.SchemeIsHTTPOrHTTPS() && !url.HostIsIPAddress();
}
+static constexpr float kMinimumConfidence = 0.75;
+
} // namespace
ContextualContentSuggestionsService::ContextualContentSuggestionsService(
@@ -36,14 +40,13 @@ ContextualContentSuggestionsService::ContextualContentSuggestionsService(
contextual_suggestions_fetcher,
std::unique_ptr<CachedImageFetcher> image_fetcher,
std::unique_ptr<RemoteSuggestionsDatabase> contextual_suggestions_database,
- std::unique_ptr<ContextualSuggestionsMetricsReporterProvider>
- metrics_reporter_provider)
+ std::unique_ptr<ContextualSuggestionsReporterProvider> reporter_provider)
: contextual_suggestions_database_(
std::move(contextual_suggestions_database)),
contextual_suggestions_fetcher_(
std::move(contextual_suggestions_fetcher)),
image_fetcher_(std::move(image_fetcher)),
- metrics_reporter_provider_(std::move(metrics_reporter_provider)) {}
+ reporter_provider_(std::move(reporter_provider)) {}
ContextualContentSuggestionsService::~ContextualContentSuggestionsService() =
default;
@@ -54,10 +57,14 @@ void ContextualContentSuggestionsService::FetchContextualSuggestionClusters(
ReportFetchMetricsCallback metrics_callback) {
// TODO(pnoland): Also check that the url is safe.
if (IsEligibleURL(url)) {
+ FetchClustersCallback internal_callback = base::BindOnce(
+ &ContextualContentSuggestionsService::FetchDone, base::Unretained(this),
+ std::move(callback), metrics_callback);
contextual_suggestions_fetcher_->FetchContextualSuggestionsClusters(
- url, std::move(callback), std::move(metrics_callback));
+ url, std::move(internal_callback), metrics_callback);
} else {
- std::move(callback).Run("", {});
+ std::move(callback).Run(
+ ContextualSuggestionsResult("", {}, PeekConditions()));
}
}
@@ -70,20 +77,18 @@ void ContextualContentSuggestionsService::FetchContextualSuggestionImage(
std::move(callback));
}
-void ContextualContentSuggestionsService::FetchContextualSuggestionImageLegacy(
- const ContentSuggestion::ID& suggestion_id,
- ImageFetchedCallback callback) {
- const std::string& id_within_category = suggestion_id.id_within_category();
- auto image_url_iterator = image_url_by_id_.find(id_within_category);
- if (image_url_iterator == image_url_by_id_.end()) {
- DVLOG(1) << "FetchContextualSuggestionImage unknown image"
- << " id_within_category: " << id_within_category;
- std::move(callback).Run(gfx::Image());
+void ContextualContentSuggestionsService::FetchDone(
+ FetchClustersCallback callback,
+ ReportFetchMetricsCallback metrics_callback,
+ ContextualSuggestionsResult result) {
+ if (result.peek_conditions.confidence < kMinimumConfidence) {
+ metrics_callback.Run(contextual_suggestions::FETCH_BELOW_THRESHOLD);
+ std::move(callback).Run(
+ ContextualSuggestionsResult("", {}, PeekConditions()));
return;
}
- GURL image_url = image_url_iterator->second;
- FetchContextualSuggestionImage(suggestion_id, image_url, std::move(callback));
+ std::move(callback).Run(result);
}
std::unique_ptr<
@@ -91,7 +96,7 @@ std::unique_ptr<
ContextualContentSuggestionsService::CreateProxy() {
return std::make_unique<
contextual_suggestions::ContextualContentSuggestionsServiceProxy>(
- this, metrics_reporter_provider_->CreateMetricsReporter());
+ this, reporter_provider_->CreateReporter());
}
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
index 7f40448378d..23214ede416 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service.h
@@ -17,21 +17,17 @@
#include "components/ntp_snippets/callbacks.h"
#include "components/ntp_snippets/content_suggestion.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
-#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
-namespace contextual_suggestions {
-class ContextualContentSuggestionsServiceProxy;
-}
-
namespace ntp_snippets {
-
-using contextual_suggestions::Cluster;
-using contextual_suggestions::FetchClustersCallback;
-using contextual_suggestions::ReportFetchMetricsCallback;
-
class CachedImageFetcher;
class RemoteSuggestionsDatabase;
+} // namespace ntp_snippets
+
+namespace contextual_suggestions {
+
+class ContextualContentSuggestionsServiceProxy;
// Retrieves contextual suggestions for a given URL and fetches images
// for contextual suggestion, using caching.
@@ -40,12 +36,12 @@ class ContextualContentSuggestionsService : public KeyedService {
ContextualContentSuggestionsService(
std::unique_ptr<ContextualSuggestionsFetcher>
contextual_suggestions_fetcher,
- std::unique_ptr<CachedImageFetcher> image_fetcher,
- std::unique_ptr<RemoteSuggestionsDatabase>
+ std::unique_ptr<ntp_snippets::CachedImageFetcher> image_fetcher,
+ std::unique_ptr<ntp_snippets::RemoteSuggestionsDatabase>
contextual_suggestions_database,
std::unique_ptr<
- contextual_suggestions::ContextualSuggestionsMetricsReporterProvider>
- metrics_reporter_provider);
+ contextual_suggestions::ContextualSuggestionsReporterProvider>
+ reporter_provider);
~ContextualContentSuggestionsService() override;
// Asynchronously fetches contextual suggestions for the given URL.
@@ -57,32 +53,28 @@ class ContextualContentSuggestionsService : public KeyedService {
// Fetches an image pointed to by |url| and internally caches it using
// |suggestion_id|. Asynchronous if cache or network is queried.
virtual void FetchContextualSuggestionImage(
- const ContentSuggestion::ID& suggestion_id,
+ const ntp_snippets::ContentSuggestion::ID& suggestion_id,
const GURL& url,
- ImageFetchedCallback callback);
+ ntp_snippets::ImageFetchedCallback callback);
- // Fetches an image for a given contextual suggestion ID.
- // Asynchronous if cache or network is queried.
- virtual void FetchContextualSuggestionImageLegacy(
- const ContentSuggestion::ID& suggestion_id,
- ImageFetchedCallback callback);
+ void FetchDone(FetchClustersCallback callback,
+ ReportFetchMetricsCallback metrics_callback,
+ ContextualSuggestionsResult result);
- std::unique_ptr<
- contextual_suggestions::ContextualContentSuggestionsServiceProxy>
- CreateProxy();
+ std::unique_ptr<ContextualContentSuggestionsServiceProxy> CreateProxy();
private:
// Cache for images of contextual suggestions, needed by CachedImageFetcher.
- std::unique_ptr<RemoteSuggestionsDatabase> contextual_suggestions_database_;
+ std::unique_ptr<ntp_snippets::RemoteSuggestionsDatabase>
+ contextual_suggestions_database_;
// Performs actual network request to fetch contextual suggestions.
std::unique_ptr<ContextualSuggestionsFetcher> contextual_suggestions_fetcher_;
- std::unique_ptr<CachedImageFetcher> image_fetcher_;
+ std::unique_ptr<ntp_snippets::CachedImageFetcher> image_fetcher_;
- std::unique_ptr<
- contextual_suggestions::ContextualSuggestionsMetricsReporterProvider>
- metrics_reporter_provider_;
+ std::unique_ptr<contextual_suggestions::ContextualSuggestionsReporterProvider>
+ reporter_provider_;
// Look up by ContentSuggestion::ID::id_within_category() aka std::string to
// get image URL.
@@ -91,6 +83,6 @@ class ContextualContentSuggestionsService : public KeyedService {
DISALLOW_COPY_AND_ASSIGN(ContextualContentSuggestionsService);
};
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_CONTENT_SUGGESTIONS_SERVICE_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.cc b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.cc
index d622fd3b833..2cd0e8dc5df 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.cc
@@ -26,10 +26,10 @@ GURL ImageUrlFromId(const std::string& image_id) {
ContextualContentSuggestionsServiceProxy::
ContextualContentSuggestionsServiceProxy(
- ntp_snippets::ContextualContentSuggestionsService* service,
- std::unique_ptr<ContextualSuggestionsMetricsReporter> metrics_reporter)
+ ContextualContentSuggestionsService* service,
+ std::unique_ptr<ContextualSuggestionsReporter> reporter)
: service_(service),
- metrics_reporter_(std::move(metrics_reporter)),
+ reporter_(std::move(reporter)),
last_ukm_source_id_(ukm::kInvalidSourceId),
weak_ptr_factory_(this) {}
@@ -38,7 +38,7 @@ ContextualContentSuggestionsServiceProxy::
void ContextualContentSuggestionsServiceProxy::FetchContextualSuggestions(
const GURL& url,
- ClustersCallback callback) {
+ FetchClustersCallback callback) {
service_->FetchContextualSuggestionClusters(
url,
base::BindOnce(
@@ -46,7 +46,7 @@ void ContextualContentSuggestionsServiceProxy::FetchContextualSuggestions(
weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
base::BindRepeating(
&ContextualContentSuggestionsServiceProxy::ReportEvent,
- weak_ptr_factory_.GetWeakPtr(), last_ukm_source_id_));
+ weak_ptr_factory_.GetWeakPtr(), last_ukm_source_id_, url.spec()));
}
void ContextualContentSuggestionsServiceProxy::FetchContextualSuggestionImage(
@@ -88,6 +88,7 @@ void ContextualContentSuggestionsServiceProxy::ClearState() {
void ContextualContentSuggestionsServiceProxy::ReportEvent(
ukm::SourceId ukm_source_id,
+ const std::string& url,
ContextualSuggestionsEvent event) {
// TODO(pnoland): investigate how we can get into this state(one known
// example is if we switch tabs and there's no committed navigation in the new
@@ -100,17 +101,17 @@ void ContextualContentSuggestionsServiceProxy::ReportEvent(
// Flush the previous page (if any) and setup the new page.
if (ukm_source_id != last_ukm_source_id_) {
if (last_ukm_source_id_ != ukm::kInvalidSourceId)
- metrics_reporter_->Flush();
+ reporter_->Flush();
last_ukm_source_id_ = ukm_source_id;
- metrics_reporter_->SetupForPage(ukm_source_id);
+ reporter_->SetupForPage(url, ukm_source_id);
}
- metrics_reporter_->RecordEvent(event);
+ reporter_->RecordEvent(event);
}
void ContextualContentSuggestionsServiceProxy::FlushMetrics() {
if (last_ukm_source_id_ != ukm::kInvalidSourceId)
- metrics_reporter_->Flush();
+ reporter_->Flush();
last_ukm_source_id_ = ukm::kInvalidSourceId;
}
@@ -128,16 +129,15 @@ void ContextualContentSuggestionsServiceProxy::FetchImageImpl(
}
void ContextualContentSuggestionsServiceProxy::CacheSuggestions(
- ClustersCallback callback,
- std::string peek_text,
- std::vector<Cluster> clusters) {
+ FetchClustersCallback callback,
+ ContextualSuggestionsResult result) {
suggestions_.clear();
- for (auto& cluster : clusters) {
+ for (auto& cluster : result.clusters) {
for (auto& suggestion : cluster.suggestions) {
suggestions_.emplace(std::make_pair(suggestion.id, suggestion));
}
}
- std::move(callback).Run(peek_text, std::move(clusters));
+ std::move(callback).Run(std::move(result));
}
} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.h b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.h
index d5dfc58e8c5..42ad2d71a3d 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy.h
@@ -12,8 +12,8 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "components/ntp_snippets/contextual/cluster.h"
#include "components/ntp_snippets/contextual/contextual_content_suggestions_service.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
class GURL;
@@ -25,16 +25,14 @@ namespace contextual_suggestions {
// torn down with a part of UI that owns it, which doesn't affect other proxies.
class ContextualContentSuggestionsServiceProxy {
public:
- using ClustersCallback = ntp_snippets::FetchClustersCallback;
- using Cluster = ntp_snippets::Cluster;
-
ContextualContentSuggestionsServiceProxy(
- ntp_snippets::ContextualContentSuggestionsService* service,
- std::unique_ptr<ContextualSuggestionsMetricsReporter> metrics_reporter);
+ ContextualContentSuggestionsService* service,
+ std::unique_ptr<ContextualSuggestionsReporter> reporter);
~ContextualContentSuggestionsServiceProxy();
// Fetches contextual suggestions for a given |url|.
- void FetchContextualSuggestions(const GURL& url, ClustersCallback callback);
+ void FetchContextualSuggestions(const GURL& url,
+ FetchClustersCallback callback);
// Fetches an image for a contextual suggestion with specified
// |suggestion_id|.
@@ -52,7 +50,9 @@ class ContextualContentSuggestionsServiceProxy {
void ClearState();
// Reports user interface event to the service.
- void ReportEvent(ukm::SourceId, ContextualSuggestionsEvent event);
+ void ReportEvent(ukm::SourceId,
+ const std::string& url,
+ ContextualSuggestionsEvent event);
// Ensures that all metrics are properly flushed.
void FlushMetrics();
@@ -62,17 +62,16 @@ class ContextualContentSuggestionsServiceProxy {
const std::string& image_id,
ntp_snippets::ImageFetchedCallback callback);
- void CacheSuggestions(ClustersCallback callback,
- std::string peek_text,
- std::vector<Cluster> clusters);
+ void CacheSuggestions(FetchClustersCallback callback,
+ ContextualSuggestionsResult result);
// Pointer to the service.
- ntp_snippets::ContextualContentSuggestionsService* service_;
+ ContextualContentSuggestionsService* service_;
// Cache of contextual suggestions.
- std::map<std::string, ntp_snippets::ContextualSuggestion> suggestions_;
+ std::map<std::string, ContextualSuggestion> suggestions_;
// Sink for reporting metrics for this proxy.
- std::unique_ptr<contextual_suggestions::ContextualSuggestionsMetricsReporter>
- metrics_reporter_;
+ std::unique_ptr<contextual_suggestions::ContextualSuggestionsReporter>
+ reporter_;
// The most recent SourceId in use by metrics_reporter_, or
// ukm::kInvalidSourceId.
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy_unittest.cc
index 24d1bafe033..e0de6e85134 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy_unittest.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_proxy_unittest.cc
@@ -10,6 +10,7 @@
#include "base/bind.h"
#include "components/ntp_snippets/contextual/contextual_content_suggestions_service.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_test_utils.h"
#include "components/ntp_snippets/remote/cached_image_fetcher.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -20,37 +21,34 @@ using testing::Pointee;
namespace contextual_suggestions {
-using Cluster = ntp_snippets::Cluster;
-using ClustersCallback = ntp_snippets::FetchClustersCallback;
-
namespace {
static const std::string kTestPeekText("Test peek test");
static const std::string kValidFromUrl = "http://some.url";
class FakeContextualContentSuggestionsService
- : public ntp_snippets::ContextualContentSuggestionsService {
+ : public ContextualContentSuggestionsService {
public:
FakeContextualContentSuggestionsService();
~FakeContextualContentSuggestionsService() override;
void FetchContextualSuggestionClusters(
const GURL& url,
- ClustersCallback callback,
+ FetchClustersCallback callback,
ReportFetchMetricsCallback metrics_callback) override {
clusters_callback_ = std::move(callback);
}
- void RunClustersCallback(std::string peek_text,
- std::vector<Cluster> clusters) {
- std::move(clusters_callback_)
- .Run(std::move(peek_text), std::move(clusters));
+ void RunClustersCallback(ContextualSuggestionsResult result) {
+ std::move(clusters_callback_).Run(std::move(result));
}
private:
- ClustersCallback clusters_callback_;
+ FetchClustersCallback clusters_callback_;
};
+} // namespace
+
FakeContextualContentSuggestionsService::
FakeContextualContentSuggestionsService()
: ContextualContentSuggestionsService(nullptr, nullptr, nullptr, nullptr) {}
@@ -58,27 +56,6 @@ FakeContextualContentSuggestionsService::
FakeContextualContentSuggestionsService::
~FakeContextualContentSuggestionsService() {}
-// GMock does not support movable-only types (Cluster).
-// Instead WrappedRun is used as callback and it redirects the call to a
-// method without movable-only types, which is then mocked.
-class MockClustersCallback {
- public:
- void WrappedRun(std::string peek_text, std::vector<Cluster> clusters) {
- Run(peek_text, &clusters);
- }
-
- ClustersCallback ToOnceCallback() {
- return base::BindOnce(&MockClustersCallback::WrappedRun,
- base::Unretained(this));
- }
-
- MOCK_METHOD2(Run,
- void(const std::string& peek_text,
- std::vector<Cluster>* clusters));
-};
-
-} // namespace
-
class ContextualContentSuggestionsServiceProxyTest : public testing::Test {
public:
void SetUp() override;
@@ -106,8 +83,8 @@ TEST_F(ContextualContentSuggestionsServiceProxyTest,
proxy()->FetchContextualSuggestions(GURL(kValidFromUrl),
mock_cluster_callback.ToOnceCallback());
- EXPECT_CALL(mock_cluster_callback, Run(kTestPeekText, Pointee(IsEmpty())));
- service()->RunClustersCallback(kTestPeekText, std::vector<Cluster>());
+ service()->RunClustersCallback(ContextualSuggestionsResult());
+ EXPECT_TRUE(mock_cluster_callback.has_run);
}
// TODO(fgorski): More tests will be added, once we have the suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
index 65553517b75..b44bebfa921 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_content_suggestions_service_unittest.cc
@@ -18,8 +18,10 @@
#include "components/ntp_snippets/category_info.h"
#include "components/ntp_snippets/content_suggestion.h"
#include "components/ntp_snippets/contextual/contextual_suggestion.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_fetcher.h"
-#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_test_utils.h"
#include "components/ntp_snippets/remote/cached_image_fetcher.h"
#include "components/ntp_snippets/remote/json_to_categories.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
@@ -30,8 +32,15 @@
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_unittest_util.h"
-using contextual_suggestions::ClusterBuilder;
-using contextual_suggestions::ReportFetchMetricsCallback;
+using ntp_snippets::CachedImageFetcher;
+using ntp_snippets::Category;
+using ntp_snippets::ContentSuggestion;
+using ntp_snippets::KnownCategories;
+using ntp_snippets::ImageFetchedCallback;
+using ntp_snippets::ImageDataFetchedCallback;
+using ntp_snippets::RemoteSuggestionsDatabase;
+using ntp_snippets::RequestThrottler;
+
using testing::_;
using testing::AllOf;
using testing::ElementsAre;
@@ -40,24 +49,10 @@ using testing::Mock;
using testing::Pointee;
using testing::Property;
-namespace ntp_snippets {
+namespace contextual_suggestions {
namespace {
-class MockClustersCallback {
- public:
- void Done(std::string peek_text, std::vector<Cluster> clusters) {
- EXPECT_FALSE(has_run);
- has_run = true;
- response_peek_text = peek_text;
- response_clusters = std::move(clusters);
- }
-
- bool has_run = false;
- std::string response_peek_text;
- std::vector<Cluster> response_clusters;
-};
-
// Always fetches the result that was set by SetFakeResponse.
class FakeContextualSuggestionsFetcher : public ContextualSuggestionsFetcher {
public:
@@ -65,16 +60,23 @@ class FakeContextualSuggestionsFetcher : public ContextualSuggestionsFetcher {
const GURL& url,
FetchClustersCallback callback,
ReportFetchMetricsCallback metrics_callback) override {
- std::move(callback).Run("peek text", std::move(fake_suggestions_));
+ ContextualSuggestionsResult result;
+ result.peek_text = "peek text";
+ result.clusters = std::move(fake_suggestions_);
+ result.peek_conditions = peek_conditions_;
+ std::move(callback).Run(std::move(result));
fake_suggestions_.clear();
}
- void SetFakeResponse(std::vector<Cluster> fake_suggestions) {
+ void SetFakeResponse(std::vector<Cluster> fake_suggestions,
+ PeekConditions peek_conditions = PeekConditions()) {
fake_suggestions_ = std::move(fake_suggestions);
+ peek_conditions_ = peek_conditions;
}
private:
std::vector<Cluster> fake_suggestions_;
+ PeekConditions peek_conditions_;
};
// Always fetches a fake image if the given URL is valid.
@@ -106,13 +108,16 @@ class ContextualContentSuggestionsServiceTest : public testing::Test {
std::unique_ptr<FakeContextualSuggestionsFetcher> fetcher =
std::make_unique<FakeContextualSuggestionsFetcher>();
fetcher_ = fetcher.get();
- auto metrics_reporter_provider = std::make_unique<
- contextual_suggestions::ContextualSuggestionsMetricsReporterProvider>();
+ auto debugging_reporter = std::make_unique<
+ contextual_suggestions::ContextualSuggestionsDebuggingReporter>();
+ auto reporter_provider = std::make_unique<
+ contextual_suggestions::ContextualSuggestionsReporterProvider>(
+ std::move(debugging_reporter));
source_ = std::make_unique<ContextualContentSuggestionsService>(
std::move(fetcher),
std::make_unique<FakeCachedImageFetcher>(&pref_service_),
std::unique_ptr<RemoteSuggestionsDatabase>(),
- std::move(metrics_reporter_provider));
+ std::move(reporter_provider));
}
FakeContextualSuggestionsFetcher* fetcher() { return fetcher_; }
@@ -127,22 +132,6 @@ class ContextualContentSuggestionsServiceTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(ContextualContentSuggestionsServiceTest);
};
-
-TEST_F(ContextualContentSuggestionsServiceTest,
- ShouldFetchEmptyImageIfNotFound) {
- base::MockCallback<ImageFetchedCallback> mock_image_fetched_callback;
- const std::string kEmpty;
- ContentSuggestion::ID id(
- Category::FromKnownCategory(KnownCategories::CONTEXTUAL), kEmpty);
- EXPECT_CALL(mock_image_fetched_callback,
- Run(Property(&gfx::Image::IsEmpty, true)));
- source()->FetchContextualSuggestionImageLegacy(
- id, mock_image_fetched_callback.Get());
- // TODO(gaschler): Verify with a mock that the image fetcher is not called if
- // the id is unknown.
- base::RunLoop().RunUntilIdle();
-}
-
TEST_F(ContextualContentSuggestionsServiceTest,
ShouldFetchContextualSuggestionsClusters) {
MockClustersCallback mock_callback;
@@ -160,10 +149,7 @@ TEST_F(ContextualContentSuggestionsServiceTest,
fetcher()->SetFakeResponse(std::move(clusters));
source()->FetchContextualSuggestionClusters(
- context_url,
- base::BindOnce(&MockClustersCallback::Done,
- base::Unretained(&mock_callback)),
- base::DoNothing());
+ context_url, mock_callback.ToOnceCallback(), base::DoNothing());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(mock_callback.has_run);
@@ -187,4 +173,33 @@ TEST_F(ContextualContentSuggestionsServiceTest, ShouldRejectInvalidUrls) {
}
}
-} // namespace ntp_snippets
+TEST_F(ContextualContentSuggestionsServiceTest,
+ ShouldNotReportLowConfidenceResults) {
+ MockClustersCallback mock_callback;
+ std::vector<Cluster> clusters;
+ GURL context_url("http://www.from.url");
+
+ clusters.emplace_back(ClusterBuilder("Title")
+ .AddSuggestion(SuggestionBuilder(context_url)
+ .Title("Title1")
+ .PublisherName("from.url")
+ .Snippet("Summary")
+ .ImageId("abc")
+ .Build())
+ .Build());
+
+ PeekConditions peek_conditions;
+ peek_conditions.confidence = 0.5;
+
+ fetcher()->SetFakeResponse(std::move(clusters), peek_conditions);
+
+ source()->FetchContextualSuggestionClusters(
+ context_url, mock_callback.ToOnceCallback(), base::DoNothing());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(mock_callback.has_run);
+ EXPECT_EQ(mock_callback.response_clusters.size(), 0u);
+ EXPECT_EQ(mock_callback.response_peek_text, std::string());
+}
+
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestion.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestion.cc
index ce8e1bd5158..1155b7fc6e1 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestion.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestion.cc
@@ -4,7 +4,7 @@
#include "components/ntp_snippets/contextual/contextual_suggestion.h"
-namespace ntp_snippets {
+namespace contextual_suggestions {
ContextualSuggestion::ContextualSuggestion() = default;
@@ -68,4 +68,4 @@ ContextualSuggestion SuggestionBuilder::Build() {
return std::move(suggestion_);
}
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestion.h b/chromium/components/ntp_snippets/contextual/contextual_suggestion.h
index 8e015ce879d..d14e64a00a9 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestion.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestion.h
@@ -7,7 +7,7 @@
#include "url/gurl.h"
-namespace ntp_snippets {
+namespace contextual_suggestions {
// Struct containing the data for a single contextual content suggestion.
struct ContextualSuggestion {
@@ -62,6 +62,6 @@ class SuggestionBuilder {
ContextualSuggestion suggestion_;
};
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTION_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.cc
new file mode 100644
index 00000000000..8ce07fe9e39
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.cc
@@ -0,0 +1,52 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h"
+
+#include "components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h"
+
+namespace contextual_suggestions {
+
+ContextualSuggestionsCompositeReporter::
+ ContextualSuggestionsCompositeReporter() = default;
+
+ContextualSuggestionsCompositeReporter::
+ ~ContextualSuggestionsCompositeReporter() = default;
+
+void ContextualSuggestionsCompositeReporter::SetupForPage(
+ const std::string& url,
+ ukm::SourceId source_id) {
+ for (ContextualSuggestionsReporter* reporter : raw_reporters_)
+ reporter->SetupForPage(url, source_id);
+}
+
+void ContextualSuggestionsCompositeReporter::RecordEvent(
+ ContextualSuggestionsEvent event) {
+ for (ContextualSuggestionsReporter* reporter : raw_reporters_)
+ reporter->RecordEvent(event);
+}
+
+void ContextualSuggestionsCompositeReporter::Flush() {
+ for (ContextualSuggestionsReporter* reporter : raw_reporters_)
+ reporter->Flush();
+}
+
+void ContextualSuggestionsCompositeReporter::AddOwnedReporter(
+ std::unique_ptr<ContextualSuggestionsReporter> reporter) {
+ // It's possible the raw pointer has already been added. This case will
+ // be taken care of by the set used to store the raw pointers.
+ // This allows for the composite reporter to retroactively take ownership
+ // after a raw pointer has already been added.
+ ContextualSuggestionsReporter* raw_reporter = reporter.get();
+ owned_reporters_.insert(std::move(reporter));
+ AddRawReporter(raw_reporter);
+}
+
+void ContextualSuggestionsCompositeReporter::AddRawReporter(
+ ContextualSuggestionsReporter* reporter) {
+ CHECK(reporter);
+ raw_reporters_.insert(reporter);
+}
+
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h
new file mode 100644
index 00000000000..a75c8fbda56
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h
@@ -0,0 +1,52 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_COMPOSITE_REPORTER_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_COMPOSITE_REPORTER_H_
+
+#include <memory>
+#include <set>
+
+#include "base/macros.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+
+namespace contextual_suggestions {
+
+// Reporter specialized for reporting to many different reporters.
+// This is an add-only collection of reporters because right now reporters live
+// as long as the service, or a proxy owning the composite. Therefore everything
+// is torn down together.
+class ContextualSuggestionsCompositeReporter
+ : public ContextualSuggestionsReporter {
+ public:
+ ContextualSuggestionsCompositeReporter();
+ ~ContextualSuggestionsCompositeReporter() override;
+
+ // ContextualSuggestionsReporter
+ void SetupForPage(const std::string& url, ukm::SourceId source_id) override;
+ void RecordEvent(ContextualSuggestionsEvent event) override;
+ void Flush() override;
+
+ // Composite pattern.
+ // Add a reporter which will be cleaned up with this. Use this if you want the
+ // reporter to be destroyed with the composite reporter.
+ void AddOwnedReporter(
+ std::unique_ptr<ContextualSuggestionsReporter> reporter);
+ // Add an unmanaged reporter. Use this if you want to manage the lifetime of
+ // this reporter yourself.
+ void AddRawReporter(ContextualSuggestionsReporter* reporter);
+
+ private:
+ // List of owned reporters.
+ std::set<std::unique_ptr<ContextualSuggestionsReporter>> owned_reporters_;
+
+ // List of all reporters that get the events.
+ std::set<ContextualSuggestionsReporter*> raw_reporters_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsCompositeReporter);
+};
+} // namespace contextual_suggestions
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_COMPOSITE_REPORTER_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter_unittest.cc
new file mode 100644
index 00000000000..3d2a99c74f3
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_composite_reporter_unittest.cc
@@ -0,0 +1,121 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h"
+
+#include "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace contextual_suggestions {
+
+static const std::string kTestUrl = "https://foo.com";
+static const ukm::SourceId kSourceId = 1;
+
+class TestReporter : public ContextualSuggestionsReporter {
+ public:
+ TestReporter() = default;
+ ~TestReporter() override { reporter_destroy_count_++; }
+
+ /* ContextualSuggestionsReporter */
+
+ void SetupForPage(const std::string& url, ukm::SourceId source_id) override {
+ this->url_ = url;
+ this->source_id_ = source_id;
+ called_setup_for_page_count_++;
+ }
+
+ void RecordEvent(ContextualSuggestionsEvent event) override {
+ called_record_event_count_++;
+ }
+
+ void Flush() override { called_flush_count_++; }
+
+ /* Accessors */
+ std::string GetUrl() { return url_; }
+ ukm::SourceId GetSourceId() { return source_id_; }
+ int GetNSetupForPage() { return called_setup_for_page_count_; }
+ int GetNRecordEvent() { return called_record_event_count_; }
+ int GetNFlush() { return called_flush_count_; };
+
+ /* Static variables*/
+ static int GetReporterDestroyCount() { return reporter_destroy_count_; }
+ static void ResetReporterDestroyCount() { reporter_destroy_count_ = 0; }
+
+ private:
+ static int reporter_destroy_count_;
+
+ std::string url_;
+ ukm::SourceId source_id_;
+ int called_setup_for_page_count_ = 0;
+ int called_record_event_count_ = 0;
+ int called_flush_count_ = 0;
+};
+
+int TestReporter::reporter_destroy_count_ = 0;
+
+TEST(ContextualSuggestionsCompositeReporterTest, AddAndReportUnique) {
+ std::unique_ptr<ContextualSuggestionsCompositeReporter> composite_reporter =
+ std::make_unique<ContextualSuggestionsCompositeReporter>();
+
+ std::vector<TestReporter*> reporters;
+ for (int i = 0; i < 10; i++) {
+ auto reporter = std::make_unique<TestReporter>();
+ reporters.push_back(reporter.get());
+ composite_reporter->AddOwnedReporter(std::move(reporter));
+ }
+
+ composite_reporter->SetupForPage(kTestUrl, kSourceId);
+ composite_reporter->RecordEvent(ContextualSuggestionsEvent::FETCH_REQUESTED);
+ composite_reporter->Flush();
+
+ for (TestReporter* reporter : reporters) {
+ EXPECT_EQ(1, reporter->GetNSetupForPage());
+ EXPECT_EQ(1, reporter->GetNRecordEvent());
+ EXPECT_EQ(1, reporter->GetNFlush());
+ }
+
+ EXPECT_EQ(kTestUrl, reporters.front()->GetUrl());
+ EXPECT_EQ(kSourceId, reporters.front()->GetSourceId());
+}
+
+TEST(ContextualSuggestionsCompositeReporterTest, AddAndReportRaw) {
+ std::unique_ptr<ContextualSuggestionsCompositeReporter> composite_reporter =
+ std::make_unique<ContextualSuggestionsCompositeReporter>();
+
+ std::vector<std::unique_ptr<TestReporter>> reporters;
+ for (int i = 0; i < 10; i++) {
+ auto reporter = std::make_unique<TestReporter>();
+ composite_reporter->AddRawReporter(reporter.get());
+ reporters.push_back(std::move(reporter));
+ }
+
+ composite_reporter->SetupForPage(kTestUrl, kSourceId);
+ composite_reporter->RecordEvent(ContextualSuggestionsEvent::FETCH_REQUESTED);
+ composite_reporter->Flush();
+
+ for (auto& reporter : reporters) {
+ EXPECT_EQ(1, reporter->GetNSetupForPage());
+ EXPECT_EQ(1, reporter->GetNRecordEvent());
+ EXPECT_EQ(1, reporter->GetNFlush());
+ }
+
+ EXPECT_EQ(kTestUrl, reporters.front()->GetUrl());
+ EXPECT_EQ(kSourceId, reporters.front()->GetSourceId());
+}
+
+TEST(ContextualSuggestionsCompositeReporterTest, CheckOwnedDeleted) {
+ TestReporter::ResetReporterDestroyCount();
+ std::unique_ptr<ContextualSuggestionsCompositeReporter> composite_reporter =
+ std::make_unique<ContextualSuggestionsCompositeReporter>();
+
+ auto reporter = std::make_unique<TestReporter>();
+ composite_reporter->AddOwnedReporter(std::make_unique<TestReporter>());
+ composite_reporter->AddOwnedReporter(std::make_unique<TestReporter>());
+ composite_reporter->AddRawReporter(reporter.get());
+ composite_reporter.reset(nullptr);
+
+ EXPECT_EQ(2, TestReporter::GetReporterDestroyCount());
+}
+
+} // namespace contextual_suggestions \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.cc
new file mode 100644
index 00000000000..c3f9a48f2d5
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.cc
@@ -0,0 +1,84 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h"
+
+#include <algorithm>
+
+namespace {
+static constexpr int CACHE_SIZE = 5;
+} // namespace
+
+namespace contextual_suggestions {
+
+ContextualSuggestionsDebuggingReporter::
+ ContextualSuggestionsDebuggingReporter() = default;
+
+ContextualSuggestionsDebuggingReporter::
+ ~ContextualSuggestionsDebuggingReporter() = default;
+
+const std::vector<ContextualSuggestionsDebuggingEvent>&
+ContextualSuggestionsDebuggingReporter::GetEvents() const {
+ return events_;
+}
+
+void ContextualSuggestionsDebuggingReporter::SetupForPage(
+ const std::string& url,
+ ukm::SourceId source_id) {
+ current_event_ = ContextualSuggestionsDebuggingEvent();
+ current_event_.url = url;
+}
+
+void ContextualSuggestionsDebuggingReporter::RecordEvent(
+ ContextualSuggestionsEvent event) {
+ switch (event) {
+ case FETCH_DELAYED:
+ case FETCH_REQUESTED:
+ case FETCH_ERROR:
+ case FETCH_SERVER_BUSY:
+ case FETCH_BELOW_THRESHOLD:
+ case FETCH_EMPTY:
+ case FETCH_COMPLETED:
+ return;
+ case UI_PEEK_REVERSE_SCROLL:
+ current_event_.sheet_peeked = true;
+ return;
+ case UI_OPENED:
+ current_event_.sheet_opened = true;
+ return;
+ case UI_DISMISSED_WITHOUT_OPEN:
+ case UI_DISMISSED_AFTER_OPEN:
+ current_event_.sheet_closed = true;
+ return;
+ case SUGGESTION_DOWNLOADED:
+ current_event_.any_suggestion_downloaded = true;
+ return;
+ case SUGGESTION_CLICKED:
+ current_event_.any_suggestion_taken = true;
+ return;
+ case UI_CLOSED_OBSOLETE:
+ NOTREACHED() << "Obsolete event, do not use!";
+ return;
+ default:
+ NOTREACHED() << "Unexpected event, not correctly handled!";
+ return;
+ }
+}
+
+void ContextualSuggestionsDebuggingReporter::Flush() {
+ // Check if we've already sent an event with this url to the cache. If so,
+ // remove it before adding another one.
+ const std::string current_url = current_event_.url;
+ std::remove_if(events_.begin(), events_.end(),
+ [current_url](ContextualSuggestionsDebuggingEvent event) {
+ return current_url == event.url;
+ });
+ events_.push_back(current_event_);
+
+ // If the cache is too large, then remove the least recently used.
+ if (events_.size() > CACHE_SIZE)
+ events_.erase(events_.begin());
+}
+
+} // namespace contextual_suggestions \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h
new file mode 100644
index 00000000000..2baf1d91e41
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h
@@ -0,0 +1,64 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_DEBUGGING_REPORTER_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_DEBUGGING_REPORTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+
+namespace contextual_suggestions {
+
+// Models the events being reported to the debugging reporter.
+// TODO(wylieb): Timestamp events as they happen.
+struct ContextualSuggestionsDebuggingEvent {
+ // Name of the url.
+ std::string url;
+
+ // Whether any suggestion was downloaded.
+ bool any_suggestion_downloaded = false;
+
+ // Whether any suggestion was taken.
+ bool any_suggestion_taken = false;
+
+ // Whether the sheet was closed.
+ bool sheet_closed = false;
+
+ // Whether the sheet was ever opened.
+ bool sheet_opened = false;
+
+ // Whether the sheet ever peeked.
+ bool sheet_peeked = false;
+};
+
+// Reporter specialized for caching information for debugging purposes.
+class ContextualSuggestionsDebuggingReporter
+ : public ContextualSuggestionsReporter {
+ public:
+ ContextualSuggestionsDebuggingReporter();
+ ~ContextualSuggestionsDebuggingReporter() override;
+
+ // Get all events currently in the buffer.
+ const std::vector<ContextualSuggestionsDebuggingEvent>& GetEvents() const;
+
+ // ContextualSuggestionsReporter
+ void SetupForPage(const std::string& url, ukm::SourceId source_id) override;
+ void RecordEvent(
+ contextual_suggestions::ContextualSuggestionsEvent event) override;
+ void Flush() override;
+
+ private:
+ std::vector<ContextualSuggestionsDebuggingEvent> events_;
+ ContextualSuggestionsDebuggingEvent current_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsDebuggingReporter);
+};
+} // namespace contextual_suggestions
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_DEBUGGING_REPORTER_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_features.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_features.cc
new file mode 100644
index 00000000000..376e0afae5b
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_features.cc
@@ -0,0 +1,19 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_features.h"
+
+namespace contextual_suggestions {
+
+const base::Feature kContextualSuggestionsBottomSheet{
+ "ContextualSuggestionsBottomSheet", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kContextualSuggestionsEnterprisePolicyBypass{
+ "ContextualSuggestionsEnterprisePolicyBypass",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kContextualSuggestionsSlimPeekUI{
+ "ContextualSuggestionsSlimPeekUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_features.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_features.h
new file mode 100644
index 00000000000..9ca7f7a0e9e
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_features.h
@@ -0,0 +1,18 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FEATURES_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace contextual_suggestions {
+
+extern const base::Feature kContextualSuggestionsBottomSheet;
+extern const base::Feature kContextualSuggestionsEnterprisePolicyBypass;
+extern const base::Feature kContextualSuggestionsSlimPeekUI;
+
+} // namespace contextual_suggestions
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FEATURES_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.cc
index 4985c3d23b2..e4139f3bbb3 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.cc
@@ -6,12 +6,16 @@
#include "base/base64.h"
#include "base/base64url.h"
+#include "base/command_line.h"
+#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/ntp_snippets/contextual/contextual_suggestion.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_features.h"
#include "components/ntp_snippets/contextual/proto/chrome_search_api_request_context.pb.h"
#include "components/ntp_snippets/contextual/proto/get_pivots_request.pb.h"
#include "components/ntp_snippets/contextual/proto/get_pivots_response.pb.h"
@@ -29,8 +33,11 @@ namespace contextual_suggestions {
namespace {
-static constexpr char kFetchEndpoint[] =
- "https://www.google.com/httpservice/web/ExploreService/GetPivots/";
+static constexpr char kFetchEndpointUrlKey[] =
+ "contextual-suggestions-fetch-endpoint";
+static constexpr char kDefaultFetchEndpointUrl[] = "https://www.google.com";
+static constexpr char kFetchEndpointServicePath[] =
+ "/httpservice/web/ExploreService/GetPivots/";
static constexpr int kNumberOfSuggestionsToFetch = 10;
static constexpr int kMinNumberOfClusters = 1;
@@ -72,6 +79,22 @@ Cluster PivotToCluster(const PivotCluster& pivot) {
return cluster_builder.Build();
}
+PeekConditions PeekConditionsFromResponse(
+ const GetPivotsResponse& response_proto) {
+ AutoPeekConditions proto_conditions =
+ response_proto.pivots().auto_peek_conditions();
+ PeekConditions peek_conditions;
+
+ peek_conditions.confidence = proto_conditions.confidence();
+ peek_conditions.page_scroll_percentage =
+ proto_conditions.page_scroll_percentage();
+ peek_conditions.minimum_seconds_on_page =
+ proto_conditions.minimum_seconds_on_page();
+ peek_conditions.maximum_number_of_peeks =
+ proto_conditions.maximum_number_of_peeks();
+ return peek_conditions;
+}
+
std::vector<Cluster> ClustersFromResponse(
const GetPivotsResponse& response_proto) {
std::vector<Cluster> clusters;
@@ -130,6 +153,14 @@ const std::string SerializedPivotsRequest(const std::string& url,
return pivot_request.SerializeAsString();
}
+ContextualSuggestionsResult ResultFromResponse(
+ const GetPivotsResponse& response_proto) {
+ return ContextualSuggestionsResult(
+ PeekTextFromResponse(response_proto),
+ ClustersFromResponse(response_proto),
+ PeekConditionsFromResponse(response_proto));
+}
+
} // namespace
ContextualSuggestionsFetch::ContextualSuggestionsFetch(
@@ -141,7 +172,24 @@ ContextualSuggestionsFetch::~ContextualSuggestionsFetch() = default;
// static
const std::string ContextualSuggestionsFetch::GetFetchEndpoint() {
- return kFetchEndpoint;
+ std::string fetch_endpoint;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(kFetchEndpointUrlKey)) {
+ fetch_endpoint =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ kFetchEndpointUrlKey);
+ } else {
+ fetch_endpoint = base::GetFieldTrialParamValueByFeature(
+ kContextualSuggestionsBottomSheet, kFetchEndpointUrlKey);
+ }
+
+ if (!base::StartsWith(fetch_endpoint, "https://",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ fetch_endpoint = kDefaultFetchEndpointUrl;
+ }
+
+ fetch_endpoint.append(kFetchEndpointServicePath);
+
+ return fetch_endpoint;
}
void ContextualSuggestionsFetch::Start(
@@ -224,8 +272,7 @@ net::HttpRequestHeaders ContextualSuggestionsFetch::MakeHeaders() const {
void ContextualSuggestionsFetch::OnURLLoaderComplete(
ReportFetchMetricsCallback metrics_callback,
std::unique_ptr<std::string> result) {
- std::vector<Cluster> clusters;
- std::string peek_text;
+ ContextualSuggestionsResult suggestions_result;
int32_t response_code = 0;
int32_t error_code = url_loader_->NetError();
@@ -243,8 +290,7 @@ void ContextualSuggestionsFetch::OnURLLoaderComplete(
if (coded_stream.ReadVarint32(&response_size) && response_size != 0) {
GetPivotsResponse response_proto;
if (response_proto.MergePartialFromCodedStream(&coded_stream)) {
- clusters = ClustersFromResponse(response_proto);
- peek_text = PeekTextFromResponse(response_proto);
+ suggestions_result = ResultFromResponse(response_proto);
}
}
}
@@ -253,10 +299,10 @@ void ContextualSuggestionsFetch::OnURLLoaderComplete(
static_cast<int>(result->length() / 1024));
}
- ReportFetchMetrics(error_code, response_code, clusters.size(),
+ ReportFetchMetrics(error_code, response_code,
+ suggestions_result.clusters.size(),
std::move(metrics_callback));
-
- std::move(request_completed_callback_).Run(peek_text, std::move(clusters));
+ std::move(request_completed_callback_).Run(std::move(suggestions_result));
}
void ContextualSuggestionsFetch::ReportFetchMetrics(
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.h
index 7ac12818187..4fb5acbff93 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch.h
@@ -10,8 +10,8 @@
#include <utility>
#include "base/callback.h"
-#include "components/ntp_snippets/contextual/cluster.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
#include "net/http/http_request_headers.h"
#include "url/gurl.h"
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch_unittest.cc
new file mode 100644
index 00000000000..627f30aa09b
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetch_unittest.cc
@@ -0,0 +1,86 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_fetch.h"
+
+#include <map>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_features.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace contextual_suggestions {
+
+namespace {
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_Default) {
+ EXPECT_EQ("https://www.google.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_CommandLine_MissingValue) {
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII("contextual-suggestions-fetch-endpoint", "");
+ EXPECT_EQ("https://www.google.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_CommandLine_NonHTTPS) {
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII("contextual-suggestions-fetch-endpoint",
+ "http://test.com");
+ EXPECT_EQ("https://www.google.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_CommandLine_ProperEndpoint) {
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+ command_line->AppendSwitchASCII("contextual-suggestions-fetch-endpoint",
+ "https://test.com");
+ EXPECT_EQ("https://test.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_Feature_NoParameter) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(kContextualSuggestionsBottomSheet);
+ EXPECT_EQ("https://www.google.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_Feature_EmptyParameter) {
+ base::test::ScopedFeatureList feature_list;
+ std::map<std::string, std::string> parameters;
+ parameters["contextual-suggestions-fetch-endpoint"] = "";
+ feature_list.InitAndEnableFeatureWithParameters(
+ kContextualSuggestionsBottomSheet, parameters);
+ EXPECT_EQ("https://www.google.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_Feature_NonHTTPS) {
+ base::test::ScopedFeatureList feature_list;
+ std::map<std::string, std::string> parameters;
+ parameters["contextual-suggestions-fetch-endpoint"] = "http://test.com";
+ feature_list.InitAndEnableFeatureWithParameters(
+ kContextualSuggestionsBottomSheet, parameters);
+ EXPECT_EQ("https://www.google.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+TEST(ContextualSuggestionsFetch, GetFetchEndpoint_Feature_WithParameter) {
+ base::test::ScopedFeatureList feature_list;
+ std::map<std::string, std::string> parameters;
+ parameters["contextual-suggestions-fetch-endpoint"] = "https://test.com";
+ feature_list.InitAndEnableFeatureWithParameters(
+ kContextualSuggestionsBottomSheet, parameters);
+ EXPECT_EQ("https://test.com/httpservice/web/ExploreService/GetPivots/",
+ ContextualSuggestionsFetch::GetFetchEndpoint());
+}
+
+} // namespace
+
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h
index 8fbdcf2f767..a9770f32852 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher.h
@@ -5,14 +5,14 @@
#ifndef COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_H_
#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_H_
-#include "components/ntp_snippets/contextual/cluster.h"
#include "components/ntp_snippets/contextual/contextual_suggestion.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
using contextual_suggestions::FetchClustersCallback;
using contextual_suggestions::ReportFetchMetricsCallback;
-namespace ntp_snippets {
+namespace contextual_suggestions {
// Fetches contextual suggestions from the server.
class ContextualSuggestionsFetcher {
@@ -28,6 +28,6 @@ class ContextualSuggestionsFetcher {
ReportFetchMetricsCallback metrics_callback) = 0;
};
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
index bdafe0b669f..a86ba26ac75 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.cc
@@ -6,7 +6,7 @@
#include "services/network/public/cpp/shared_url_loader_factory.h"
-namespace ntp_snippets {
+namespace contextual_suggestions {
ContextualSuggestionsFetcherImpl::ContextualSuggestionsFetcherImpl(
const scoped_refptr<network::SharedURLLoaderFactory>& loader_factory,
@@ -35,13 +35,12 @@ void ContextualSuggestionsFetcherImpl::FetchContextualSuggestionsClusters(
void ContextualSuggestionsFetcherImpl::FetchFinished(
ContextualSuggestionsFetch* fetch,
FetchClustersCallback callback,
- std::string peek_text,
- std::vector<Cluster> clusters) {
+ ContextualSuggestionsResult result) {
auto fetch_iterator = pending_requests_.find(fetch);
CHECK(fetch_iterator != pending_requests_.end());
pending_requests_.erase(fetch_iterator);
- std::move(callback).Run(peek_text, std::move(clusters));
+ std::move(callback).Run(std::move(result));
}
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
index bb1041b9464..3eccc9da95b 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl.h
@@ -22,8 +22,9 @@ class SharedURLLoaderFactory;
using contextual_suggestions::Cluster;
using contextual_suggestions::ContextualSuggestionsFetch;
+using contextual_suggestions::ContextualSuggestionsResult;
-namespace ntp_snippets {
+namespace contextual_suggestions {
class ContextualSuggestionsFetcherImpl : public ContextualSuggestionsFetcher {
public:
@@ -41,8 +42,7 @@ class ContextualSuggestionsFetcherImpl : public ContextualSuggestionsFetcher {
private:
void FetchFinished(ContextualSuggestionsFetch* fetch,
FetchClustersCallback callback,
- std::string peek_text,
- std::vector<Cluster> clusters);
+ ContextualSuggestionsResult result);
const scoped_refptr<network::SharedURLLoaderFactory> loader_factory_;
/// BCP47 formatted language code to use.
@@ -56,6 +56,6 @@ class ContextualSuggestionsFetcherImpl : public ContextualSuggestionsFetcher {
DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsFetcherImpl);
};
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_FETCHER_IMPL_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
index b9de9cde2d5..89f10c6156f 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_fetcher_impl_unittest.cc
@@ -14,6 +14,8 @@
#include "base/test/bind_test_util.h"
#include "base/test/histogram_tester.h"
#include "base/test/scoped_task_environment.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_test_utils.h"
#include "components/ntp_snippets/contextual/proto/chrome_search_api_request_context.pb.h"
#include "components/ntp_snippets/contextual/proto/get_pivots_request.pb.h"
#include "components/ntp_snippets/contextual/proto/get_pivots_response.pb.h"
@@ -24,8 +26,9 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace ntp_snippets {
+namespace contextual_suggestions {
+using contextual_suggestions::AutoPeekConditions;
using contextual_suggestions::ClusterBuilder;
using contextual_suggestions::ContextualSuggestionsEvent;
using contextual_suggestions::ExploreContext;
@@ -33,6 +36,9 @@ using contextual_suggestions::GetPivotsQuery;
using contextual_suggestions::GetPivotsRequest;
using contextual_suggestions::GetPivotsResponse;
using contextual_suggestions::ImageId;
+using contextual_suggestions::MockClustersCallback;
+using contextual_suggestions::MockMetricsCallback;
+using contextual_suggestions::PeekConditions;
using contextual_suggestions::PivotCluster;
using contextual_suggestions::PivotClusteringParams;
using contextual_suggestions::PivotDocument;
@@ -45,27 +51,6 @@ using testing::ElementsAre;
namespace {
-class MockClustersCallback {
- public:
- void Done(std::string peek_text, std::vector<Cluster> clusters) {
- EXPECT_FALSE(has_run);
- has_run = true;
- response_peek_text = peek_text;
- response_clusters = std::move(clusters);
- }
-
- bool has_run = false;
- std::string response_peek_text;
- std::vector<Cluster> response_clusters;
-};
-
-class MockMetricsCallback {
- public:
- void Report(ContextualSuggestionsEvent event) { events.push_back(event); }
-
- std::vector<ContextualSuggestionsEvent> events;
-};
-
// TODO(pnoland): de-dupe this and the identical class in
// feed_networking_host_unittest.cc
class TestSharedURLLoaderFactory : public SharedURLLoaderFactory {
@@ -83,6 +68,10 @@ class TestSharedURLLoaderFactory : public SharedURLLoaderFactory {
std::move(client), traffic_annotation);
}
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+ NOTREACHED();
+ }
+
std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override {
NOTREACHED();
return nullptr;
@@ -127,12 +116,27 @@ void PopulateDocument(PivotDocument* document,
image_id->set_encrypted_docid(suggestion.image_id);
}
+void PopulatePeekConditions(AutoPeekConditions* proto_conditions,
+ const PeekConditions& peek_conditions) {
+ proto_conditions->set_confidence(peek_conditions.confidence);
+ proto_conditions->set_page_scroll_percentage(
+ peek_conditions.page_scroll_percentage);
+ proto_conditions->set_minimum_seconds_on_page(
+ peek_conditions.minimum_seconds_on_page);
+ proto_conditions->set_maximum_number_of_peeks(
+ peek_conditions.maximum_number_of_peeks);
+}
+
// Populates a GetPivotsResponse proto using |peek_text| and |clusters| and
// returns that proto as a serialized string.
-std::string SerializedResponseProto(const std::string& peek_text,
- std::vector<Cluster> clusters) {
+std::string SerializedResponseProto(
+ const std::string& peek_text,
+ std::vector<Cluster> clusters,
+ PeekConditions peek_conditions = PeekConditions()) {
GetPivotsResponse response_proto;
Pivots* pivots = response_proto.mutable_pivots();
+ PopulatePeekConditions(pivots->mutable_auto_peek_conditions(),
+ peek_conditions);
pivots->mutable_peek_text()->set_text(peek_text);
for (const auto& cluster : clusters) {
@@ -169,36 +173,6 @@ std::string SerializedResponseProto(const std::string& peek_text,
return " " + response_proto.SerializeAsString();
}
-void ExpectSuggestionsMatch(ContextualSuggestion actual,
- ContextualSuggestion expected) {
- EXPECT_EQ(actual.id, expected.id);
- EXPECT_EQ(actual.title, expected.title);
- EXPECT_EQ(actual.url, expected.url);
- EXPECT_EQ(actual.snippet, expected.snippet);
- EXPECT_EQ(actual.publisher_name, expected.publisher_name);
- EXPECT_EQ(actual.image_id, expected.image_id);
- EXPECT_EQ(actual.favicon_image_id, expected.favicon_image_id);
-}
-
-void ExpectClustersMatch(Cluster actual, Cluster expected) {
- EXPECT_EQ(actual.title, expected.title);
- for (size_t i = 0; i < actual.suggestions.size(); i++) {
- ExpectSuggestionsMatch(std::move(actual.suggestions[i]),
- std::move(expected.suggestions[i]));
- }
-}
-
-void ExpectResponsesMatch(MockClustersCallback callback,
- std::string expected_peek_text,
- std::vector<Cluster> expected_clusters) {
- EXPECT_EQ(callback.response_peek_text, expected_peek_text);
- ASSERT_EQ(callback.response_clusters.size(), expected_clusters.size());
- for (size_t i = 0; i < callback.response_clusters.size(); i++) {
- ExpectClustersMatch(std::move(callback.response_clusters[i]),
- std::move(expected_clusters[i]));
- }
-}
-
} // namespace
class ContextualSuggestionsFetcherTest : public testing::Test {
@@ -237,9 +211,7 @@ class ContextualSuggestionsFetcherTest : public testing::Test {
base::Unretained(mock_metrics_callback))
: base::DoNothing();
fetcher().FetchContextualSuggestionsClusters(
- context_url,
- base::BindOnce(&MockClustersCallback::Done, base::Unretained(callback)),
- metrics_callback);
+ context_url, callback->ToOnceCallback(), metrics_callback);
base::RunLoop().RunUntilIdle();
}
@@ -266,7 +238,9 @@ TEST_F(ContextualSuggestionsFetcherTest, SingleSuggestionResponse) {
&metrics_callback);
EXPECT_TRUE(callback.has_run);
- ExpectResponsesMatch(std::move(callback), "Peek Text", DefaultClusters());
+ ExpectResponsesMatch(std::move(callback),
+ ContextualSuggestionsResult(
+ "Peek Text", DefaultClusters(), PeekConditions()));
EXPECT_EQ(metrics_callback.events,
std::vector<ContextualSuggestionsEvent>(
{contextual_suggestions::FETCH_COMPLETED}));
@@ -327,8 +301,10 @@ TEST_F(ContextualSuggestionsFetcherTest,
SendAndAwaitResponse(GURL("http://www.article.com/"), &callback);
EXPECT_TRUE(callback.has_run);
- ExpectResponsesMatch(std::move(callback), "Peek Text",
- std::move(clusters_copy));
+ ExpectResponsesMatch(
+ std::move(callback),
+ ContextualSuggestionsResult("Peek Text", std::move(clusters_copy),
+ PeekConditions()));
histogram_tester.ExpectTotalCount("ContextualSuggestions.FetchResponseSizeKB",
1);
@@ -344,8 +320,31 @@ TEST_F(ContextualSuggestionsFetcherTest, FlatResponse) {
// PivotCluster to copy it from. So we clear the expected title.
std::vector<Cluster> expected_clusters = DefaultClusters();
expected_clusters[0].title = "";
- ExpectResponsesMatch(std::move(callback), "Peek Text",
- std::move(expected_clusters));
+ ExpectResponsesMatch(
+ std::move(callback),
+ ContextualSuggestionsResult("Peek Text", std::move(expected_clusters),
+ PeekConditions()));
+}
+
+TEST_F(ContextualSuggestionsFetcherTest, PeekConditionsAreParsed) {
+ MockClustersCallback callback;
+ MockMetricsCallback metrics_callback;
+ PeekConditions peek_conditions;
+ peek_conditions.confidence = 0.7;
+ peek_conditions.page_scroll_percentage = 35.0;
+ peek_conditions.minimum_seconds_on_page = 4.5;
+ peek_conditions.maximum_number_of_peeks = 5.0;
+
+ SetFakeResponse(
+ SerializedResponseProto("Peek Text", DefaultClusters(), peek_conditions));
+
+ SendAndAwaitResponse(GURL("http://www.article.com"), &callback,
+ &metrics_callback);
+
+ EXPECT_TRUE(callback.has_run);
+ ExpectResponsesMatch(std::move(callback),
+ ContextualSuggestionsResult(
+ "Peek Text", DefaultClusters(), peek_conditions));
}
TEST_F(ContextualSuggestionsFetcherTest, HtmlEntitiesAreUnescaped) {
@@ -371,8 +370,10 @@ TEST_F(ContextualSuggestionsFetcherTest, HtmlEntitiesAreUnescaped) {
// entities we added.
expected_clusters[0].suggestions[0].title = "\"foobar\"";
expected_clusters[0].suggestions[0].snippet = "\'barbaz\'";
- ExpectResponsesMatch(std::move(callback), "Peek Text",
- std::move(expected_clusters));
+ ExpectResponsesMatch(
+ std::move(callback),
+ ContextualSuggestionsResult("Peek Text", std::move(expected_clusters),
+ PeekConditions()));
}
TEST_F(ContextualSuggestionsFetcherTest, RequestHeaderSetCorrectly) {
@@ -509,7 +510,9 @@ TEST_F(ContextualSuggestionsFetcherTest, ResponseWithUnsetFields) {
EXPECT_TRUE(callback.has_run);
EXPECT_EQ(callback.response_clusters.size(), 1u);
- ExpectResponsesMatch(std::move(callback), "", std::move(expected_clusters));
+ ExpectResponsesMatch(std::move(callback),
+ ContextualSuggestionsResult(
+ "", std::move(expected_clusters), PeekConditions()));
}
TEST_F(ContextualSuggestionsFetcherTest, CorruptResponse) {
@@ -521,4 +524,4 @@ TEST_F(ContextualSuggestionsFetcherTest, CorruptResponse) {
EXPECT_EQ(callback.response_clusters.size(), 0u);
}
-} // namespace ntp_snippets
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.cc
index f3f4b600a1d..e588db611a0 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.cc
@@ -4,23 +4,14 @@
#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include <string>
+
#include "base/metrics/histogram_macros.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
namespace contextual_suggestions {
-ContextualSuggestionsMetricsReporterProvider::
- ContextualSuggestionsMetricsReporterProvider() = default;
-
-ContextualSuggestionsMetricsReporterProvider::
- ~ContextualSuggestionsMetricsReporterProvider() = default;
-
-std::unique_ptr<ContextualSuggestionsMetricsReporter>
-ContextualSuggestionsMetricsReporterProvider::CreateMetricsReporter() {
- return std::make_unique<ContextualSuggestionsMetricsReporter>();
-}
-
ContextualSuggestionsMetricsReporter::ContextualSuggestionsMetricsReporter()
: sheet_peeked_(false),
sheet_opened_(false),
@@ -34,6 +25,7 @@ ContextualSuggestionsMetricsReporter::~ContextualSuggestionsMetricsReporter() {
}
void ContextualSuggestionsMetricsReporter::SetupForPage(
+ const std::string& url,
ukm::SourceId source_id) {
DCHECK(!ukm_entry_) << "Flush should be called before SetupForPage!";
DCHECK(source_id != ukm::kInvalidSourceId);
@@ -77,7 +69,8 @@ void ContextualSuggestionsMetricsReporter::RecordUmaMetrics(
return;
sheet_opened_ = true;
break;
- case UI_CLOSED:
+ case UI_DISMISSED_WITHOUT_OPEN:
+ case UI_DISMISSED_AFTER_OPEN:
if (sheet_closed_)
return;
sheet_closed_ = true;
@@ -92,9 +85,12 @@ void ContextualSuggestionsMetricsReporter::RecordUmaMetrics(
return;
any_suggestion_taken_ = true;
break;
+ case UI_CLOSED_OBSOLETE:
+ NOTREACHED() << "Obsolete event, do not use!";
+ return;
default:
NOTREACHED() << "Unexpected event, not correctly handled!";
- break;
+ return;
}
UMA_HISTOGRAM_ENUMERATION("ContextualSuggestions.Events", event);
}
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h
index 8772d05a8ef..0cd8bff2ed4 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h
@@ -10,6 +10,7 @@
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
namespace contextual_suggestions {
@@ -18,115 +19,17 @@ class ContextualSuggestionsUkmEntry;
FORWARD_DECLARE_TEST(ContextualSuggestionsMetricsReporterTest, BaseTest);
-// NOTE: because this is used for UMA reporting, these values should not be
-// changed or reused; new values should be appended immediately before the
-// EVENT_MAX value. Make sure to update the histogram enum
-// (ContextualSuggestions.Event in enums.xml) accordingly!
-// A Java counterpart will be generated for this enum.
-// GENERATED_JAVA_ENUM_PACKAGE: (
-// org.chromium.chrome.browser.contextual_suggestions)
-enum ContextualSuggestionsEvent {
- // Indicates that this state is not initialized.
- // Should never be intentionally recorded, just used as a default value.
- UNINITIALIZED = 0,
- // Records that fetching suggestions has been delayed on the client side.
- FETCH_DELAYED = 1,
- // The fetch request has been made but a response has not yet been received.
- FETCH_REQUESTED = 2,
- // The fetch response has been received, but there was some error.
- FETCH_ERROR = 3,
- // The fetch response indicates that the server was too busy to return any
- // suggestions.
- FETCH_SERVER_BUSY = 4,
- // The fetch response includes suggestions but they were all below the
- // confidence threshold needed to show them to the user.
- FETCH_BELOW_THRESHOLD = 5,
- // The fetch response has been received and parsed, but there were no
- // suggestions.
- FETCH_EMPTY = 6,
- // The fetch response has been received and there are suggestions to show.
- FETCH_COMPLETED = 7,
- // The UI was shown in the "peeking bar" state, triggered by a reverse-scroll.
- // If new gestures are added to trigger the peeking sheet then a new event
- // should be added to this list.
- UI_PEEK_REVERSE_SCROLL = 8,
- // The UI sheet was opened.
- UI_OPENED = 9,
- // The UI was closed (via the close box).
- UI_CLOSED = 10,
- // A suggestion was downloaded.
- SUGGESTION_DOWNLOADED = 11,
- // A suggestion was taken, either with a click, or opened in a separate tab.
- SUGGESTION_CLICKED = 12,
- // Special name that marks the maximum value in an Enum used for UMA.
- // https://cs.chromium.org/chromium/src/tools/metrics/histograms/README.md.
- kMaxValue = SUGGESTION_CLICKED,
-};
-
-class ContextualSuggestionsMetricsReporter;
-
-// Class producing |ContextualSuggestionsMetricsReporter| instances. It enables
-// classes like |ContextualContentSuggestionService| to produce metrics
-// reporters when needed, e.g. creation of service proxy, without knowing how to
-// initialize them.
-class ContextualSuggestionsMetricsReporterProvider {
- public:
- ContextualSuggestionsMetricsReporterProvider();
- virtual ~ContextualSuggestionsMetricsReporterProvider();
-
- virtual std::unique_ptr<ContextualSuggestionsMetricsReporter>
- CreateMetricsReporter();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsMetricsReporterProvider);
-};
-
-// Tracks various UKM and UMA metrics based on reports of events that take place
-// within the Contextual Suggestions component.
-//
-// For example:
-// Java UI -> ContextualSuggestionsBridge#reportEvent(
-// /* web_contents */, @ContextualSuggestionsEvent int eventId) -> native
-// -> ContextualContentSuggestionsService#reportEvent(
-// ukm::GetSourceIdForWebContentsDocument(web_contents), eventId)) ->
-// if(!reporter) {
-// ContextualSuggestionsMetricsReporter* reporter =
-// new ContextualSuggestionsMetricsReporter();
-// }
-// ukm::SourceId source_id_for_web_contents;
-// reporter->SetupForPage(source_id_for_web_contents);
-// reporter->RecordEvent(FETCH_REQUESTED);
-// ...
-//
-// if (!my_results)
-// reporter->RecordEvent(FETCH_ERROR);
-// else if (my_result.size() == 0)
-// reporter->RecordEvent(FETCH_EMPTY);
-// else
-// reporter->RecordEvent(FETCH_COMPLETED);
-// ...
-// When the UI shows:
-// reporter->RecordEvent(UI_PEEK_SHOWN);
-// Make sure data is flushed when leaving the page:
-// reporter->Flush();
-class ContextualSuggestionsMetricsReporter {
+// Reporter specialized for UKM/UMA metrics reporting.
+class ContextualSuggestionsMetricsReporter
+ : public ContextualSuggestionsReporter {
public:
ContextualSuggestionsMetricsReporter();
- ~ContextualSuggestionsMetricsReporter();
-
- // Sets up the page with the given |source_id| for event reporting.
- // All subsequent RecordEvent calls will apply to this page.
- void SetupForPage(ukm::SourceId source_id);
-
- // Reports that an event occurred for the current page.
- // Some data is not written immediately, but will be written when |Reset| is
- // called.
- void RecordEvent(ContextualSuggestionsEvent event);
+ ~ContextualSuggestionsMetricsReporter() override;
- // Flushes all data staged using |RecordEvent|.
- // This is required before a subsequent call to |SetupForPage|, and can be
- // called multiple times.
- void Flush();
+ // ContextualSuggestionsReporter
+ void SetupForPage(const std::string& url, ukm::SourceId source_id) override;
+ void RecordEvent(ContextualSuggestionsEvent event) override;
+ void Flush() override;
private:
FRIEND_TEST_ALL_PREFIXES(ContextualSuggestionsMetricsReporterTest, BaseTest);
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter_unittest.cc
index ce95774f2d2..ddf6e47fd9f 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter_unittest.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter_unittest.cc
@@ -8,15 +8,33 @@
#include "base/test/scoped_task_environment.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h"
#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using ukm::TestUkmRecorder;
+using ukm::builders::ContextualSuggestions;
namespace contextual_suggestions {
namespace {
+const char kEventsHistogramName[] = "ContextualSuggestions.Events";
const char kTestNavigationUrl[] = "https://foo.com";
+const int kUninitialized = 0;
+const int kFetchDelayed = 1;
+const int kFetchRequested = 2;
+const int kFetchError = 3;
+const int kFetchServerBusy = 4;
+const int kFetchBelowThreshold = 5;
+const int kFetchEmpty = 6;
+const int kFetchCompleted = 7;
+const int kUiPeekReverseScroll = 8;
+const int kUiOpened = 9;
+const int kUiClosedObsolete = 10;
+const int kSuggestionDownloaded = 11;
+const int kSuggestionClicked = 12;
+const int kUiDismissedWithoutOpen = 13;
+const int kUiDismissedAfterOpen = 14;
} // namespace
class ContextualSuggestionsMetricsReporterTest : public ::testing::Test {
@@ -29,6 +47,9 @@ class ContextualSuggestionsMetricsReporterTest : public ::testing::Test {
ContextualSuggestionsMetricsReporter& GetReporter() { return reporter_; }
+ protected:
+ void ExpectMultipleEventsCountOnce(ContextualSuggestionsEvent event);
+
private:
// The reporter under test.
ContextualSuggestionsMetricsReporter reporter_;
@@ -50,7 +71,7 @@ ukm::SourceId ContextualSuggestionsMetricsReporterTest::GetSourceId() {
TEST_F(ContextualSuggestionsMetricsReporterTest, BaseTest) {
base::HistogramTester histogram_tester;
- GetReporter().SetupForPage(GetSourceId());
+ GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId());
GetReporter().RecordEvent(FETCH_REQUESTED);
GetReporter().RecordEvent(FETCH_COMPLETED);
GetReporter().RecordEvent(UI_PEEK_REVERSE_SCROLL);
@@ -59,32 +80,120 @@ TEST_F(ContextualSuggestionsMetricsReporterTest, BaseTest) {
GetReporter().RecordEvent(SUGGESTION_CLICKED);
// Flush data to write to UKM.
GetReporter().Flush();
- // Check what we wrote.
+ // Check that we wrote something to UKM. Details of UKM reporting are tested
+ // in a different test suite.
TestUkmRecorder* test_ukm_recorder = GetTestUkmRecorder();
std::vector<const ukm::mojom::UkmEntry*> entry_vector =
- test_ukm_recorder->GetEntriesByName(kContextualSuggestionsUkmEntryName);
+ test_ukm_recorder->GetEntriesByName(ContextualSuggestions::kEntryName);
EXPECT_EQ(1U, entry_vector.size());
const ukm::mojom::UkmEntry* first_entry = entry_vector[0];
EXPECT_TRUE(test_ukm_recorder->EntryHasMetric(
- first_entry, kContextualSuggestionsFetchMetricName));
+ first_entry, ContextualSuggestions::kFetchStateName));
EXPECT_EQ(static_cast<int64_t>(FetchState::COMPLETED),
*(test_ukm_recorder->GetEntryMetric(
- first_entry, kContextualSuggestionsFetchMetricName)));
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 0, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 1, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 2, 1);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 3, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 4, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 5, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 6, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 7, 1);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 8, 1);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 9, 1);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 10, 0);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 11, 1);
- histogram_tester.ExpectBucketCount("ContextualSuggestions.Events", 12, 1);
+ first_entry, ContextualSuggestions::kFetchStateName)));
+ // Test that the expected histogram events were written.
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kUninitialized, 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchDelayed, 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchError, 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchServerBusy, 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchBelowThreshold,
+ 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchEmpty, 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiPeekReverseScroll,
+ 1);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiOpened, 1);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kUiClosedObsolete,
+ 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName,
+ kSuggestionDownloaded, 1);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName, kSuggestionClicked,
+ 1);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName,
+ kUiDismissedWithoutOpen, 0);
+ histogram_tester.ExpectBucketCount(kEventsHistogramName,
+ kUiDismissedAfterOpen, 0);
+}
+
+void ContextualSuggestionsMetricsReporterTest::ExpectMultipleEventsCountOnce(
+ ContextualSuggestionsEvent event) {
+ std::unique_ptr<base::HistogramTester> histogram_tester =
+ std::make_unique<base::HistogramTester>();
+ GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId());
+ // Always report a single FETCH_DELAYED event so we ensure there's a
+ // histogram (otherwise the ExpectBucketCount may crash).
+ GetReporter().RecordEvent(FETCH_DELAYED);
+ int event_index = static_cast<int>(event);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, event_index, 0);
+ // Peek the UI, which starts the timer, expected by all the other UI or
+ // suggestion events.
+ GetReporter().RecordEvent(UI_PEEK_REVERSE_SCROLL);
+ // Report the event that we want to test multiple times.
+ GetReporter().RecordEvent(event);
+ GetReporter().RecordEvent(event);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, event_index, 1);
+ GetReporter().Flush();
+}
+
+TEST_F(ContextualSuggestionsMetricsReporterTest, UiPeekReverseScrollTest) {
+ ExpectMultipleEventsCountOnce(UI_PEEK_REVERSE_SCROLL);
}
-// TODO(donnd): add more tests, and test UMA data!
+TEST_F(ContextualSuggestionsMetricsReporterTest, UiOpenedTest) {
+ ExpectMultipleEventsCountOnce(UI_OPENED);
+}
+
+TEST_F(ContextualSuggestionsMetricsReporterTest, UiDismissedWithoutOpenTest) {
+ ExpectMultipleEventsCountOnce(UI_DISMISSED_WITHOUT_OPEN);
+}
+
+TEST_F(ContextualSuggestionsMetricsReporterTest, UiDismissedAfterOpenTest) {
+ ExpectMultipleEventsCountOnce(UI_DISMISSED_AFTER_OPEN);
+}
+
+TEST_F(ContextualSuggestionsMetricsReporterTest, SuggestionDownloadedTest) {
+ ExpectMultipleEventsCountOnce(SUGGESTION_DOWNLOADED);
+}
+
+TEST_F(ContextualSuggestionsMetricsReporterTest, SuggestionClickedTest) {
+ ExpectMultipleEventsCountOnce(SUGGESTION_CLICKED);
+}
+
+TEST_F(ContextualSuggestionsMetricsReporterTest, MultipleEventsTest) {
+ std::unique_ptr<base::HistogramTester> histogram_tester =
+ std::make_unique<base::HistogramTester>();
+ GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId());
+ // Test multiple cycles of FETCH_REQUESTED, FETCH_COMPLETED.
+ GetReporter().RecordEvent(FETCH_REQUESTED);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 0);
+ GetReporter().RecordEvent(FETCH_COMPLETED);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 1);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1);
+ GetReporter().RecordEvent(FETCH_REQUESTED);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 2);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 1);
+ GetReporter().RecordEvent(FETCH_COMPLETED);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchRequested, 2);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kFetchCompleted, 2);
+ GetReporter().Flush();
+}
+
+// Test that might catch enum reordering that's not done right.
+TEST_F(ContextualSuggestionsMetricsReporterTest, EnumNotReorderedTest) {
+ std::unique_ptr<base::HistogramTester> histogram_tester =
+ std::make_unique<base::HistogramTester>();
+ GetReporter().SetupForPage(kTestNavigationUrl, GetSourceId());
+ // Peek the UI, which starts the timer, expected by all the other UI or
+ // suggestion events.
+ GetReporter().RecordEvent(UI_PEEK_REVERSE_SCROLL);
+ // The current last legal event.
+ GetReporter().RecordEvent(SUGGESTION_CLICKED);
+ histogram_tester->ExpectBucketCount(kEventsHistogramName, kSuggestionClicked,
+ 1);
+ GetReporter().Flush();
+}
} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.cc
new file mode 100644
index 00000000000..12ca2fbbf88
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.cc
@@ -0,0 +1,34 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_reporter.h"
+
+#include "base/debug/stack_trace.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_composite_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_debugging_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+
+namespace contextual_suggestions {
+
+ContextualSuggestionsReporterProvider::ContextualSuggestionsReporterProvider(
+ std::unique_ptr<ContextualSuggestionsDebuggingReporter> debugging_reporter)
+ : debugging_reporter_(std::move(debugging_reporter)) {}
+
+ContextualSuggestionsReporterProvider::
+ ~ContextualSuggestionsReporterProvider() = default;
+
+std::unique_ptr<ContextualSuggestionsReporter>
+ContextualSuggestionsReporterProvider::CreateReporter() {
+ std::unique_ptr<ContextualSuggestionsCompositeReporter> reporter =
+ std::make_unique<ContextualSuggestionsCompositeReporter>();
+ reporter->AddOwnedReporter(
+ std::make_unique<ContextualSuggestionsMetricsReporter>());
+ reporter->AddRawReporter(debugging_reporter_.get());
+ return reporter;
+}
+
+ContextualSuggestionsReporter::ContextualSuggestionsReporter() = default;
+ContextualSuggestionsReporter::~ContextualSuggestionsReporter() = default;
+
+} // namespace contextual_suggestions \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.h
new file mode 100644
index 00000000000..b57e6e04466
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_reporter.h
@@ -0,0 +1,146 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_REPORTER_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_REPORTER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+
+namespace contextual_suggestions {
+
+class ContextualSuggestionsDebuggingReporter;
+class ContextualSuggestionsReporter;
+
+// Class producing |ContextualSuggestionsReporter| instances. It enables
+// classes like |ContextualContentSuggestionService| to produce metrics
+// reporters when needed, e.g. creation of service proxy, without knowing how to
+// initialize them.
+class ContextualSuggestionsReporterProvider {
+ public:
+ explicit ContextualSuggestionsReporterProvider(
+ std::unique_ptr<ContextualSuggestionsDebuggingReporter>
+ debugging_reporter);
+ virtual ~ContextualSuggestionsReporterProvider();
+
+ virtual std::unique_ptr<ContextualSuggestionsReporter> CreateReporter();
+
+ private:
+ // The debugging reporter is shared between instances of top-level reporter.
+ // Since multiple objects need a reference to this, it's kept as a unique
+ // pointer, and the raw pointer is given out to sub reporters.
+ std::unique_ptr<ContextualSuggestionsDebuggingReporter> debugging_reporter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsReporterProvider);
+};
+
+// NOTE: because this is used for UMA reporting, these values should not be
+// changed or reused; new values should be appended immediately before the
+// EVENT_MAX value. Make sure to update the histogram enum
+// (ContextualSuggestions.Event in enums.xml) accordingly!
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: (
+// org.chromium.chrome.browser.contextual_suggestions)
+enum ContextualSuggestionsEvent {
+ // Indicates that this state is not initialized.
+ // Should never be intentionally recorded, just used as a default value.
+ UNINITIALIZED = 0,
+ // Records that fetching suggestions has been delayed on the client side.
+ FETCH_DELAYED = 1,
+ // The fetch request has been made but a response has not yet been received.
+ FETCH_REQUESTED = 2,
+ // The fetch response has been received, but there was some error.
+ FETCH_ERROR = 3,
+ // The fetch response indicates that the server was too busy to return any
+ // suggestions.
+ FETCH_SERVER_BUSY = 4,
+ // The fetch response includes suggestions but they were all below the
+ // confidence threshold needed to show them to the user.
+ FETCH_BELOW_THRESHOLD = 5,
+ // The fetch response has been received and parsed, but there were no
+ // suggestions.
+ FETCH_EMPTY = 6,
+ // The fetch response has been received and there are suggestions to show.
+ FETCH_COMPLETED = 7,
+ // The UI was shown in the "peeking bar" state, triggered by a reverse-scroll.
+ // If new gestures are added to trigger the peeking sheet then a new event
+ // should be added to this list.
+ UI_PEEK_REVERSE_SCROLL = 8,
+ // The UI sheet was opened.
+ UI_OPENED = 9,
+ // The UI was closed. General event for closed/dismissed, now obsolete.
+ UI_CLOSED_OBSOLETE = 10,
+ // A suggestion was downloaded.
+ SUGGESTION_DOWNLOADED = 11,
+ // A suggestion was taken, either with a click, or opened in a separate tab.
+ SUGGESTION_CLICKED = 12,
+ // The UI was dismissed without ever being opened. This means the sheet was
+ // closed while peeked before ever being expanded.
+ UI_DISMISSED_WITHOUT_OPEN = 13,
+ // The UI was dismissed after having been opened. This means the sheet was
+ // closed from any position after it was expanded at least once.
+ UI_DISMISSED_AFTER_OPEN = 14,
+ // Special name that marks the maximum value in an Enum used for UMA.
+ // https://cs.chromium.org/chromium/src/tools/metrics/histograms/README.md.
+ kMaxValue = UI_DISMISSED_AFTER_OPEN,
+};
+
+// Tracks various metrics based on reports of events that take place
+// within the Contextual Suggestions component.
+//
+// For example:
+// Java UI -> ContextualSuggestionsBridge#reportEvent(
+// /* web_contents */, @ContextualSuggestionsEvent int eventId) -> native
+// -> ContextualContentSuggestionsService#reportEvent(
+// ukm::GetSourceIdForWebContentsDocument(web_contents), eventId)) ->
+// if(!reporter) {
+// ContextualSuggestionsReporter* reporter =
+// new ContextualSuggestionsMetricsReporter();
+// }
+// std::string url;
+// ukm::SourceId source_id_for_web_contents;
+// reporter->SetupForPage(url, source_id_for_web_contents);
+// reporter->RecordEvent(FETCH_REQUESTED);
+// ...
+//
+// if (!my_results)
+// reporter->RecordEvent(FETCH_ERROR);
+// else if (my_result.size() == 0)
+// reporter->RecordEvent(FETCH_EMPTY);
+// else
+// reporter->RecordEvent(FETCH_COMPLETED);
+// ...
+// When the UI shows:
+// reporter->RecordEvent(UI_PEEK_SHOWN);
+// Make sure data is flushed when leaving the page:
+// reporter->Flush();
+class ContextualSuggestionsReporter {
+ public:
+ ContextualSuggestionsReporter();
+ virtual ~ContextualSuggestionsReporter();
+
+ // Sets up the page with the given |source_id| for event reporting.
+ // All subsequent RecordEvent calls will apply to this page
+ virtual void SetupForPage(const std::string& url,
+ ukm::SourceId source_id) = 0;
+
+ // Reports that an event occurred for the current page.
+ // Some data is not written immediately, but will be written when |Reset| is
+ // called.
+ virtual void RecordEvent(ContextualSuggestionsEvent event) = 0;
+
+ // Flushes all data staged using |RecordEvent|.
+ // This is required before a subsequent call to |SetupForPage|, and can be
+ // called multiple times.
+ virtual void Flush() = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextualSuggestionsReporter);
+};
+
+} // namespace contextual_suggestions
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_REPORTER_H_
diff --git a/chromium/components/ntp_snippets/contextual/cluster.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_result.cc
index ebd3c491d39..a562a865467 100644
--- a/chromium/components/ntp_snippets/contextual/cluster.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_result.cc
@@ -2,12 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/ntp_snippets/contextual/cluster.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
#include "components/ntp_snippets/contextual/contextual_suggestion.h"
namespace contextual_suggestions {
+PeekConditions::PeekConditions()
+ : confidence(1.0),
+ page_scroll_percentage(0.0),
+ minimum_seconds_on_page(0.0),
+ maximum_number_of_peeks(0.0) {}
+
Cluster::Cluster() = default;
// MSVC doesn't support defaulted move constructors, so we have to define it
@@ -16,6 +22,8 @@ Cluster::Cluster(Cluster&& other) noexcept
: title(std::move(other.title)),
suggestions(std::move(other.suggestions)) {}
+Cluster::Cluster(const Cluster&) = default;
+
Cluster::~Cluster() = default;
ClusterBuilder::ClusterBuilder(const std::string& title) {
@@ -45,4 +53,30 @@ Cluster ClusterBuilder::Build() {
return std::move(cluster_);
}
+ContextualSuggestionsResult::ContextualSuggestionsResult() = default;
+
+ContextualSuggestionsResult::ContextualSuggestionsResult(
+ std::string peek_text,
+ std::vector<Cluster> clusters,
+ PeekConditions peek_conditions)
+ : clusters(clusters),
+ peek_text(peek_text),
+ peek_conditions(peek_conditions) {}
+
+ContextualSuggestionsResult::ContextualSuggestionsResult(
+ const ContextualSuggestionsResult& other) = default;
+
+// MSVC doesn't support defaulted move constructors, so we have to define it
+// ourselves.
+ContextualSuggestionsResult::ContextualSuggestionsResult(
+ ContextualSuggestionsResult&& other) noexcept
+ : clusters(std::move(other.clusters)),
+ peek_text(std::move(other.peek_text)),
+ peek_conditions(std::move(other.peek_conditions)) {}
+
+ContextualSuggestionsResult::~ContextualSuggestionsResult() = default;
+
+ContextualSuggestionsResult& ContextualSuggestionsResult::operator=(
+ ContextualSuggestionsResult&& other) = default;
+
} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_result.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_result.h
new file mode 100644
index 00000000000..6dadf379a21
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_result.h
@@ -0,0 +1,80 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_RESULT_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_RESULT_H_
+
+#include "components/ntp_snippets/contextual/contextual_suggestion.h"
+
+namespace contextual_suggestions {
+
+// Encapsulates conditions under which to show or "peek" the contextual
+// suggestions UI.
+struct PeekConditions {
+ PeekConditions();
+ // A measure of confidence that auto-peek should be enabled for this response
+ // in the range [0, 1].
+ float confidence = 1.0;
+
+ // The percentage of the page that the user scrolls required for an auto
+ // peek to occur.
+ float page_scroll_percentage;
+
+ // The minimum time (seconds) the user spends on the page required for
+ // auto peek.
+ float minimum_seconds_on_page;
+
+ // The maximum number of auto peeks that we can show for this page.
+ uint64_t maximum_number_of_peeks;
+};
+
+// A structure representing a suggestion cluster.
+struct Cluster {
+ Cluster();
+ Cluster(const Cluster&);
+ Cluster(Cluster&&) noexcept;
+ ~Cluster();
+
+ std::string title;
+ std::vector<ContextualSuggestion> suggestions;
+};
+
+// Allows concise construction of a cluster.
+class ClusterBuilder {
+ public:
+ ClusterBuilder(const std::string& title);
+
+ // Allow copying for ease of validation when testing.
+ ClusterBuilder(const ClusterBuilder& other);
+ ClusterBuilder& AddSuggestion(ContextualSuggestion suggestion);
+ Cluster Build();
+
+ private:
+ Cluster cluster_;
+};
+
+// Struct that holds the data from a ContextualSuggestions response that we care
+// about for UI purposes.
+struct ContextualSuggestionsResult {
+ ContextualSuggestionsResult();
+ ContextualSuggestionsResult(std::string peek_text,
+ std::vector<Cluster> clusters,
+ PeekConditions peek_conditions);
+ ContextualSuggestionsResult(const ContextualSuggestionsResult&);
+ ContextualSuggestionsResult(ContextualSuggestionsResult&&) noexcept;
+ ~ContextualSuggestionsResult();
+
+ ContextualSuggestionsResult& operator=(ContextualSuggestionsResult&&);
+
+ std::vector<Cluster> clusters;
+ std::string peek_text;
+ PeekConditions peek_conditions;
+};
+
+using FetchClustersCallback =
+ base::OnceCallback<void(ContextualSuggestionsResult result)>;
+
+} // namespace contextual_suggestions
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_RESULT_H_ \ No newline at end of file
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.cc
new file mode 100644
index 00000000000..69002ca4e87
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.cc
@@ -0,0 +1,75 @@
+// 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 "components/ntp_snippets/contextual/contextual_suggestions_test_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace contextual_suggestions {
+
+MockClustersCallback::MockClustersCallback() = default;
+MockClustersCallback::MockClustersCallback(const MockClustersCallback& other) =
+ default;
+MockClustersCallback::~MockClustersCallback() = default;
+
+void MockClustersCallback::Done(ContextualSuggestionsResult result) {
+ EXPECT_FALSE(has_run);
+ has_run = true;
+ response_peek_text = result.peek_text;
+ response_clusters = std::move(result.clusters);
+ peek_conditions = result.peek_conditions;
+}
+
+FetchClustersCallback MockClustersCallback::ToOnceCallback() {
+ return base::BindOnce(&MockClustersCallback::Done, base::Unretained(this));
+}
+
+MockMetricsCallback::MockMetricsCallback() = default;
+MockMetricsCallback::~MockMetricsCallback() = default;
+
+void MockMetricsCallback::Report(ContextualSuggestionsEvent event) {
+ events.push_back(event);
+}
+
+void ExpectSuggestionsMatch(const ContextualSuggestion& actual,
+ const ContextualSuggestion& expected) {
+ EXPECT_EQ(actual.id, expected.id);
+ EXPECT_EQ(actual.title, expected.title);
+ EXPECT_EQ(actual.url, expected.url);
+ EXPECT_EQ(actual.snippet, expected.snippet);
+ EXPECT_EQ(actual.publisher_name, expected.publisher_name);
+ EXPECT_EQ(actual.image_id, expected.image_id);
+ EXPECT_EQ(actual.favicon_image_id, expected.favicon_image_id);
+}
+
+void ExpectClustersMatch(const Cluster& actual, const Cluster& expected) {
+ EXPECT_EQ(actual.title, expected.title);
+ ASSERT_EQ(actual.suggestions.size(), expected.suggestions.size());
+ for (size_t i = 0; i < actual.suggestions.size(); i++) {
+ ExpectSuggestionsMatch(std::move(actual.suggestions[i]),
+ std::move(expected.suggestions[i]));
+ }
+}
+
+void ExpectPeekConditionsMatch(const PeekConditions& actual,
+ const PeekConditions& expected) {
+ EXPECT_EQ(actual.confidence, expected.confidence);
+ EXPECT_EQ(actual.page_scroll_percentage, expected.page_scroll_percentage);
+ EXPECT_EQ(actual.minimum_seconds_on_page, expected.minimum_seconds_on_page);
+ EXPECT_EQ(actual.maximum_number_of_peeks, expected.maximum_number_of_peeks);
+}
+
+void ExpectResponsesMatch(const MockClustersCallback& callback,
+ const ContextualSuggestionsResult& expected_result) {
+ EXPECT_EQ(callback.response_peek_text, expected_result.peek_text);
+ ExpectPeekConditionsMatch(callback.peek_conditions,
+ expected_result.peek_conditions);
+ ASSERT_EQ(callback.response_clusters.size(), expected_result.clusters.size());
+ for (size_t i = 0; i < callback.response_clusters.size(); i++) {
+ ExpectClustersMatch(std::move(callback.response_clusters[i]),
+ std::move(expected_result.clusters[i]));
+ }
+}
+
+} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.h
new file mode 100644
index 00000000000..b0265d2310e
--- /dev/null
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_test_utils.h
@@ -0,0 +1,55 @@
+// 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 COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_TEST_UTILS_H_
+#define COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_TEST_UTILS_H_
+
+#include "base/bind.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
+#include "components/ntp_snippets/contextual/contextual_suggestions_result.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace contextual_suggestions {
+
+// ClustersCallback implementation for testing purposes that expects to be
+// called only once, and remembers the results of that call in public members.
+class MockClustersCallback {
+ public:
+ MockClustersCallback();
+ MockClustersCallback(const MockClustersCallback&);
+ ~MockClustersCallback();
+
+ void Done(ContextualSuggestionsResult result);
+ FetchClustersCallback ToOnceCallback();
+
+ bool has_run = false;
+ std::string response_peek_text;
+ std::vector<Cluster> response_clusters;
+ PeekConditions peek_conditions;
+};
+
+class MockMetricsCallback {
+ public:
+ MockMetricsCallback();
+ ~MockMetricsCallback();
+
+ void Report(ContextualSuggestionsEvent event);
+
+ std::vector<ContextualSuggestionsEvent> events;
+};
+
+void ExpectSuggestionsMatch(const ContextualSuggestion& actual,
+ const ContextualSuggestion& expected);
+void ExpectClustersMatch(const Cluster& actual, const Cluster& expected);
+void ExpectPeekConditionsMatch(const PeekConditions& actual,
+ const PeekConditions& expected);
+
+// Expect that the individual data members saved in |callback| match the
+// corresponding data in |expected_result|.
+void ExpectResponsesMatch(const MockClustersCallback& callback,
+ const ContextualSuggestionsResult& expected_result);
+
+} // namespace contextual_suggestions
+
+#endif // COMPONENTS_NTP_SNIPPETS_CONTEXTUAL_CONTEXTUAL_SUGGESTIONS_TEST_UTILS_H_
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.cc
index 968e333739d..d06920c6157 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.cc
@@ -9,10 +9,7 @@
#include "base/timer/elapsed_timer.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
#include "services/metrics/public/cpp/metrics_utils.h"
-#include "services/metrics/public/cpp/ukm_entry_builder.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
-
-using ukm::UkmEntryBuilder;
+#include "services/metrics/public/cpp/ukm_builders.h"
namespace contextual_suggestions {
@@ -73,10 +70,8 @@ void ContextualSuggestionsUkmEntry::RecordEventMetrics(
was_sheet_opened_ = true;
StartTimerIfNeeded();
break;
- case UI_CLOSED:
- if (!was_sheet_opened_)
- closed_from_peek_ = true;
- StopTimerIfNeeded();
+ case UI_CLOSED_OBSOLETE:
+ NOTREACHED();
break;
case SUGGESTION_DOWNLOADED:
any_suggestion_downloaded_ = true;
@@ -86,6 +81,13 @@ void ContextualSuggestionsUkmEntry::RecordEventMetrics(
any_suggestion_taken_ = true;
StopTimerIfNeeded();
break;
+ case UI_DISMISSED_WITHOUT_OPEN:
+ closed_from_peek_ = true;
+ StopTimerIfNeeded();
+ break;
+ case UI_DISMISSED_AFTER_OPEN:
+ StopTimerIfNeeded();
+ break;
}
}
@@ -96,23 +98,16 @@ void ContextualSuggestionsUkmEntry::Flush() {
if (show_duration_timer_)
StopTimerIfNeeded();
- // When this variable goes out of scope the builder's destructor will write.
- std::unique_ptr<UkmEntryBuilder> builder =
- ukm::UkmRecorder::Get()->GetEntryBuilder(
- source_id_, kContextualSuggestionsUkmEntryName);
- // Keep these writes alphabetical by metric name (matching ukm.xml ordering).
- builder->AddMetric(kContextualSuggestionsClosedMetricName, closed_from_peek_);
- builder->AddMetric(kContextualSuggestionsDownloadedMetricName,
- any_suggestion_downloaded_);
- builder->AddMetric(kContextualSuggestionsOpenedMetricName, was_sheet_opened_);
- builder->AddMetric(kContextualSuggestionsFetchMetricName,
- static_cast<int64_t>(fetch_state_));
- builder->AddMetric(kContextualSuggestionsDurationMetricName,
- show_duration_exponential_bucket_);
- builder->AddMetric(kContextualSuggestionsTriggerMetricName,
- static_cast<int64_t>(trigger_event_));
- builder->AddMetric(kContextualSuggestionsTakenMetricName,
- any_suggestion_taken_);
+ // Keep these writes alphabetical by setter name (matching ukm.xml ordering).
+ ukm::builders::ContextualSuggestions builder(source_id_);
+ builder.SetAnyDownloaded(any_suggestion_downloaded_)
+ .SetAnySuggestionTaken(any_suggestion_taken_)
+ .SetClosedFromPeek(closed_from_peek_)
+ .SetEverOpened(was_sheet_opened_)
+ .SetFetchState(static_cast<int64_t>(fetch_state_))
+ .SetShowDurationBucketMin(show_duration_exponential_bucket_)
+ .SetTriggerEvent(static_cast<int64_t>(trigger_event_))
+ .Record(ukm::UkmRecorder::Get());
source_id_ = ukm::kInvalidSourceId;
}
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h b/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h
index 6c596c89768..c340419a95b 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry.h
@@ -17,18 +17,6 @@ namespace contextual_suggestions {
FORWARD_DECLARE_TEST(ContextualSuggestionsUkmEntryTest, BinaryOrderTest);
-// The name of the UKM entry written by this class.
-const char kContextualSuggestionsUkmEntryName[] = "ContextualSuggestions";
-
-// The names of individual UKM metrics written to our UKM entry.
-const char kContextualSuggestionsDownloadedMetricName[] = "AnyDownloaded";
-const char kContextualSuggestionsTakenMetricName[] = "AnySuggestionTaken";
-const char kContextualSuggestionsClosedMetricName[] = "ClosedFromPeek";
-const char kContextualSuggestionsOpenedMetricName[] = "EverOpened";
-const char kContextualSuggestionsFetchMetricName[] = "FetchState";
-const char kContextualSuggestionsDurationMetricName[] = "ShowDurationBucketMin";
-const char kContextualSuggestionsTriggerMetricName[] = "TriggerEvent";
-
// The state of the Fetcher request.
// This value is written to the "FetchState" UKM metric.
enum class FetchState {
diff --git a/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry_unittest.cc b/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry_unittest.cc
index 93d78903cf6..8af8952196d 100644
--- a/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry_unittest.cc
+++ b/chromium/components/ntp_snippets/contextual/contextual_suggestions_ukm_entry_unittest.cc
@@ -7,9 +7,11 @@
#include "base/test/scoped_task_environment.h"
#include "components/ntp_snippets/contextual/contextual_suggestions_metrics_reporter.h"
#include "components/ukm/test_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gtest/include/gtest/gtest.h"
using ukm::TestUkmRecorder;
+using ukm::builders::ContextualSuggestions;
namespace contextual_suggestions {
@@ -48,7 +50,7 @@ void ContextualSuggestionsUkmEntryTest::SetUp() {
const ukm::mojom::UkmEntry* ContextualSuggestionsUkmEntryTest::FirstEntry() {
TestUkmRecorder* recorder = GetTestUkmRecorder();
std::vector<const ukm::mojom::UkmEntry*> entry_vector =
- recorder->GetEntriesByName(kContextualSuggestionsUkmEntryName);
+ recorder->GetEntriesByName(ContextualSuggestions::kEntryName);
EXPECT_EQ(1U, entry_vector.size());
return entry_vector[0];
}
@@ -71,13 +73,14 @@ int ContextualSuggestionsUkmEntryTest::GetEntryMetric(const char* metric_name) {
TEST_F(ContextualSuggestionsUkmEntryTest, BaseTest) {
ukm_entry_->Flush();
// Deleting the entry should write default values for everything.
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsDownloadedMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsTakenMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsClosedMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsOpenedMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsFetchMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsDurationMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsTriggerMetricName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kAnyDownloadedName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kAnySuggestionTakenName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kClosedFromPeekName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kEverOpenedName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kFetchStateName));
+ EXPECT_EQ(0,
+ GetEntryMetric(ContextualSuggestions::kShowDurationBucketMinName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kTriggerEventName));
}
TEST_F(ContextualSuggestionsUkmEntryTest, ExpectedOperationTest) {
@@ -90,15 +93,15 @@ TEST_F(ContextualSuggestionsUkmEntryTest, ExpectedOperationTest) {
ukm_entry_->RecordEventMetrics(SUGGESTION_DOWNLOADED);
ukm_entry_->RecordEventMetrics(SUGGESTION_CLICKED);
ukm_entry_->Flush();
- EXPECT_EQ(1, GetEntryMetric(kContextualSuggestionsDownloadedMetricName));
- EXPECT_EQ(1, GetEntryMetric(kContextualSuggestionsTakenMetricName));
- EXPECT_EQ(0, GetEntryMetric(kContextualSuggestionsClosedMetricName));
- EXPECT_EQ(1, GetEntryMetric(kContextualSuggestionsOpenedMetricName));
- EXPECT_EQ(7, GetEntryMetric(kContextualSuggestionsFetchMetricName));
- EXPECT_LT(0, GetEntryMetric(kContextualSuggestionsDurationMetricName));
- EXPECT_EQ(1, GetEntryMetric(kContextualSuggestionsTriggerMetricName));
+ EXPECT_EQ(1, GetEntryMetric(ContextualSuggestions::kAnyDownloadedName));
+ EXPECT_EQ(1, GetEntryMetric(ContextualSuggestions::kAnySuggestionTakenName));
+ EXPECT_EQ(0, GetEntryMetric(ContextualSuggestions::kClosedFromPeekName));
+ EXPECT_EQ(1, GetEntryMetric(ContextualSuggestions::kEverOpenedName));
+ EXPECT_EQ(static_cast<int64_t>(FetchState::COMPLETED),
+ GetEntryMetric(ContextualSuggestions::kFetchStateName));
+ EXPECT_LT(0,
+ GetEntryMetric(ContextualSuggestions::kShowDurationBucketMinName));
+ EXPECT_EQ(1, GetEntryMetric(ContextualSuggestions::kTriggerEventName));
}
-// TODO(donnd): add more tests!
-
} // namespace contextual_suggestions
diff --git a/chromium/components/ntp_snippets/features.cc b/chromium/components/ntp_snippets/features.cc
index af71fdc7e65..8c49f5dc82d 100644
--- a/chromium/components/ntp_snippets/features.cc
+++ b/chromium/components/ntp_snippets/features.cc
@@ -31,11 +31,8 @@ const base::Feature* const kAllFeatures[] = {
&kIncreasedVisibility,
&kKeepPrefetchedContentSuggestions,
&kNotificationsFeature,
- &kPhysicalWebPageSuggestionsFeature,
&kPublisherFaviconsFromNewServerFeature,
- &kRecentOfflineTabSuggestionsFeature,
- &kRemoteSuggestionsBackendFeature,
- nullptr};
+ &kRemoteSuggestionsBackendFeature};
const base::Feature kArticleSuggestionsExpandableHeader{
"NTPArticleSuggestionsExpandableHeader", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -46,15 +43,9 @@ const base::Feature kArticleSuggestionsFeature{
const base::Feature kBookmarkSuggestionsFeature{
"NTPBookmarkSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kRecentOfflineTabSuggestionsFeature{
- "NTPOfflinePageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kIncreasedVisibility{"NTPSnippetsIncreasedVisibility",
base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kPhysicalWebPageSuggestionsFeature{
- "NTPPhysicalWebPageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kForeignSessionsSuggestionsFeature{
"NTPForeignSessionsSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -169,4 +160,10 @@ const base::Feature kKeepPrefetchedContentSuggestions{
const base::Feature kContentSuggestionsDebugLog{
"ContentSuggestionsDebugLog", base::FEATURE_DISABLED_BY_DEFAULT};
+std::vector<const base::Feature*> GetAllFeatures() {
+ // Skip the last feature as it's a nullptr.
+ return std::vector<const base::Feature*>(
+ kAllFeatures, kAllFeatures + arraysize(kAllFeatures));
+}
+
} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/features.h b/chromium/components/ntp_snippets/features.h
index 5c689e299aa..69369e1d4c0 100644
--- a/chromium/components/ntp_snippets/features.h
+++ b/chromium/components/ntp_snippets/features.h
@@ -33,8 +33,6 @@ extern const base::Feature* const kAllFeatures[];
// helpers in chrome/browser/ntp_snippets/dependent_features.h instead.
extern const base::Feature kBookmarkSuggestionsFeature;
-extern const base::Feature kRecentOfflineTabSuggestionsFeature;
-extern const base::Feature kPhysicalWebPageSuggestionsFeature;
extern const base::Feature kForeignSessionsSuggestionsFeature;
////////////////////////////////////////////////////////////////////////////////
@@ -43,7 +41,6 @@ extern const base::Feature kForeignSessionsSuggestionsFeature;
// Feature to allow show/hide article suggestions by clicking the header.
extern const base::Feature kArticleSuggestionsExpandableHeader;
-// TODO(jkrcal): Rename to kRemoteSuggestionsFeature.
extern const base::Feature kArticleSuggestionsFeature;
// Feature to allow UI as specified here: https://crbug.com/660837.
@@ -140,6 +137,9 @@ extern const base::Feature kKeepPrefetchedContentSuggestions;
// Enables debug logging accessible through snippets-internals.
extern const base::Feature kContentSuggestionsDebugLog;
+// Return all the features as a vector.
+std::vector<const base::Feature*> GetAllFeatures();
+
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_FEATURES_H_
diff --git a/chromium/components/ntp_snippets/mock_content_suggestions_provider.h b/chromium/components/ntp_snippets/mock_content_suggestions_provider.h
index 7cabecf8b97..54988823ca2 100644
--- a/chromium/components/ntp_snippets/mock_content_suggestions_provider.h
+++ b/chromium/components/ntp_snippets/mock_content_suggestions_provider.h
@@ -25,7 +25,7 @@ class MockContentSuggestionsProvider : public ContentSuggestionsProvider {
MockContentSuggestionsProvider(
Observer* observer,
const std::vector<Category>& provided_categories);
- ~MockContentSuggestionsProvider();
+ ~MockContentSuggestionsProvider() override;
void SetProvidedCategories(const std::vector<Category>& provided_categories);
diff --git a/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.cc b/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.cc
index 53151cf4eb7..0ee83c6920a 100644
--- a/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.cc
+++ b/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.cc
@@ -27,18 +27,18 @@ FakeOfflinePageModel::~FakeOfflinePageModel() = default;
void FakeOfflinePageModel::GetPagesByNamespace(
const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback) {
+ MultipleOfflinePageItemCallback callback) {
MultipleOfflinePageItemResult filtered_result;
for (auto& item : items_) {
if (item.client_id.name_space == name_space) {
filtered_result.emplace_back(item);
}
}
- callback.Run(filtered_result);
+ std::move(callback).Run(filtered_result);
}
void FakeOfflinePageModel::GetPagesSupportedByDownloads(
- const MultipleOfflinePageItemCallback& callback) {
+ MultipleOfflinePageItemCallback callback) {
ClientPolicyController controller;
MultipleOfflinePageItemResult filtered_result;
for (auto& item : items_) {
@@ -46,12 +46,12 @@ void FakeOfflinePageModel::GetPagesSupportedByDownloads(
filtered_result.emplace_back(item);
}
}
- callback.Run(filtered_result);
+ std::move(callback).Run(filtered_result);
}
void FakeOfflinePageModel::GetAllPages(
- const MultipleOfflinePageItemCallback& callback) {
- callback.Run(items_);
+ MultipleOfflinePageItemCallback callback) {
+ std::move(callback).Run(items_);
}
const std::vector<OfflinePageItem>& FakeOfflinePageModel::items() {
diff --git a/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.h b/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.h
index 56657af0694..5360096e412 100644
--- a/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.h
+++ b/chromium/components/ntp_snippets/offline_pages/offline_pages_test_utils.h
@@ -19,13 +19,13 @@ class FakeOfflinePageModel : public offline_pages::StubOfflinePageModel {
void GetPagesByNamespace(
const std::string& name_space,
- const offline_pages::MultipleOfflinePageItemCallback& callback) override;
+ offline_pages::MultipleOfflinePageItemCallback callback) override;
void GetPagesSupportedByDownloads(
- const offline_pages::MultipleOfflinePageItemCallback& callback) override;
+ offline_pages::MultipleOfflinePageItemCallback callback) override;
void GetAllPages(
- const offline_pages::MultipleOfflinePageItemCallback& callback) override;
+ offline_pages::MultipleOfflinePageItemCallback callback) override;
const std::vector<offline_pages::OfflinePageItem>& items();
std::vector<offline_pages::OfflinePageItem>* mutable_items();
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
deleted file mode 100644
index 8c64425f1a3..00000000000
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.cc
+++ /dev/null
@@ -1,329 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
-
-#include <algorithm>
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/ntp_snippets/features.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/ntp_snippets/pref_util.h"
-#include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/strings/grit/components_strings.h"
-#include "components/variations/variations_associated_data.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/gfx/image/image.h"
-
-using offline_pages::ClientId;
-using offline_pages::DownloadUIAdapter;
-
-namespace ntp_snippets {
-
-namespace {
-
-const int kDefaultMaxSuggestionsCount = 5;
-
-const char* kMaxSuggestionsCountParamName = "recent_tabs_max_count";
-
-int GetMaxSuggestionsCount() {
- return variations::GetVariationParamByFeatureAsInt(
- kRecentOfflineTabSuggestionsFeature, kMaxSuggestionsCountParamName,
- kDefaultMaxSuggestionsCount);
-}
-
-struct OrderUIItemsByMostRecentlyCreatedFirst {
- bool operator()(const OfflineItem& left, const OfflineItem& right) const {
- return left.creation_time > right.creation_time;
- }
-};
-
-struct OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst {
- bool operator()(const OfflineItem& left, const OfflineItem& right) const {
- if (left.page_url != right.page_url) {
- return left.page_url < right.page_url;
- }
- return left.creation_time > right.creation_time;
- }
-};
-
-} // namespace
-
-RecentTabSuggestionsProvider::RecentTabSuggestionsProvider(
- ContentSuggestionsProvider::Observer* observer,
- offline_pages::DownloadUIAdapter* ui_adapter,
- PrefService* pref_service)
- : ContentSuggestionsProvider(observer),
- category_status_(CategoryStatus::AVAILABLE_LOADING),
- provided_category_(
- Category::FromKnownCategory(KnownCategories::RECENT_TABS)),
- recent_tabs_ui_adapter_(ui_adapter),
- pref_service_(pref_service),
- weak_ptr_factory_(this) {
- observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
- recent_tabs_ui_adapter_->AddObserver(this);
-}
-
-RecentTabSuggestionsProvider::~RecentTabSuggestionsProvider() {
- recent_tabs_ui_adapter_->RemoveObserver(this);
-}
-
-CategoryStatus RecentTabSuggestionsProvider::GetCategoryStatus(
- Category category) {
- if (category == provided_category_) {
- return category_status_;
- }
- NOTREACHED() << "Unknown category " << category.id();
- return CategoryStatus::NOT_PROVIDED;
-}
-
-CategoryInfo RecentTabSuggestionsProvider::GetCategoryInfo(Category category) {
- DCHECK_EQ(provided_category_, category);
- return CategoryInfo(
- l10n_util::GetStringUTF16(IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_HEADER),
- ContentSuggestionsCardLayout::MINIMAL_CARD,
- ContentSuggestionsAdditionalAction::NONE,
- /*show_if_empty=*/false,
- l10n_util::GetStringUTF16(IDS_NTP_RECENT_TAB_SUGGESTIONS_SECTION_EMPTY));
-}
-
-void RecentTabSuggestionsProvider::DismissSuggestion(
- const ContentSuggestion::ID& suggestion_id) {
- DCHECK_EQ(provided_category_, suggestion_id.category());
- std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
- dismissed_ids.insert(suggestion_id.id_within_category());
- StoreDismissedIDsToPrefs(dismissed_ids);
-}
-
-void RecentTabSuggestionsProvider::FetchSuggestionImage(
- const ContentSuggestion::ID& suggestion_id,
- ImageFetchedCallback callback) {
- // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it's
- // available there.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), gfx::Image()));
-}
-
-void RecentTabSuggestionsProvider::FetchSuggestionImageData(
- const ContentSuggestion::ID& suggestion_id,
- ImageDataFetchedCallback callback) {
- // TODO(vitaliii): Fetch proper thumbnail from OfflinePageModel once it's
- // available there.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), std::string()));
-}
-
-void RecentTabSuggestionsProvider::Fetch(
- const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- FetchDoneCallback callback) {
- LOG(DFATAL) << "RecentTabSuggestionsProvider has no |Fetch| functionality!";
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- std::move(callback),
- Status(StatusCode::PERMANENT_ERROR,
- "RecentTabSuggestionsProvider has no |Fetch| functionality!"),
- std::vector<ContentSuggestion>()));
-}
-
-void RecentTabSuggestionsProvider::ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) {
- ClearDismissedSuggestionsForDebugging(provided_category_);
- FetchRecentTabs();
-}
-
-void RecentTabSuggestionsProvider::ClearCachedSuggestions() {
- // Ignored.
-}
-
-void RecentTabSuggestionsProvider::GetDismissedSuggestionsForDebugging(
- Category category,
- DismissedSuggestionsCallback callback) {
- DCHECK_EQ(provided_category_, category);
- recent_tabs_ui_adapter_->GetAllItems(base::BindOnce(
- &RecentTabSuggestionsProvider::OnGetDismissedSuggestionsForDebuggingDone,
- weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-}
-
-void RecentTabSuggestionsProvider::OnGetDismissedSuggestionsForDebuggingDone(
- DismissedSuggestionsCallback callback,
- const std::vector<OfflineItem>& offline_items) {
- std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
- std::vector<ContentSuggestion> suggestions;
- for (const OfflineItem& item : offline_items) {
- int64_t offline_page_id =
- recent_tabs_ui_adapter_->GetOfflineIdByGuid(item.id.id);
- if (!dismissed_ids.count(base::IntToString(offline_page_id))) {
- continue;
- }
-
- suggestions.push_back(ConvertUIItem(item));
- }
-
- std::move(callback).Run(std::move(suggestions));
-}
-
-void RecentTabSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
- Category category) {
- DCHECK_EQ(provided_category_, category);
- StoreDismissedIDsToPrefs(std::set<std::string>());
- FetchRecentTabs();
-}
-
-// static
-void RecentTabSuggestionsProvider::RegisterProfilePrefs(
- PrefRegistrySimple* registry) {
- registry->RegisterListPref(prefs::kDismissedRecentOfflineTabSuggestions);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private methods
-
-void RecentTabSuggestionsProvider::OnItemsAdded(
- const std::vector<OfflineItem>& items) {
- FetchRecentTabs();
-}
-
-void RecentTabSuggestionsProvider::OnItemUpdated(const OfflineItem& item) {
- FetchRecentTabs();
-}
-
-void RecentTabSuggestionsProvider::OnItemRemoved(const ContentId& id) {
- // Because we never switch to NOT_PROVIDED dynamically, there can be no open
- // UI containing an invalidated suggestion unless the status is something
- // other than NOT_PROVIDED, so only notify invalidation in that case.
- if (category_status_ != CategoryStatus::NOT_PROVIDED) {
- InvalidateSuggestion(id.id);
- }
-}
-
-void RecentTabSuggestionsProvider::FetchRecentTabs() {
- recent_tabs_ui_adapter_->GetAllItems(
- base::BindOnce(&RecentTabSuggestionsProvider::OnFetchRecentTabsDone,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void RecentTabSuggestionsProvider::OnFetchRecentTabsDone(
- const std::vector<OfflineItem>& offline_items) {
- NotifyStatusChanged(CategoryStatus::AVAILABLE);
- std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs();
- std::set<std::string> new_dismissed_ids;
- std::vector<OfflineItem> non_dismissed_items;
-
- for (const OfflineItem& item : offline_items) {
- std::string offline_page_id = base::IntToString(
- recent_tabs_ui_adapter_->GetOfflineIdByGuid(item.id.id));
- if (old_dismissed_ids.count(offline_page_id)) {
- new_dismissed_ids.insert(offline_page_id);
- } else {
- non_dismissed_items.push_back(item);
- }
- }
-
- observer()->OnNewSuggestions(
- this, provided_category_,
- GetMostRecentlyCreatedWithoutDuplicates(non_dismissed_items));
- if (new_dismissed_ids.size() != old_dismissed_ids.size()) {
- StoreDismissedIDsToPrefs(new_dismissed_ids);
- }
-}
-
-void RecentTabSuggestionsProvider::NotifyStatusChanged(
- CategoryStatus new_status) {
- DCHECK_NE(CategoryStatus::NOT_PROVIDED, category_status_);
- if (category_status_ == new_status) {
- return;
- }
- category_status_ = new_status;
- observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
-}
-
-ContentSuggestion RecentTabSuggestionsProvider::ConvertUIItem(
- const OfflineItem& ui_item) const {
- // UI items have the Tab ID embedded in the GUID and the offline ID is
- // available by querying.
- int64_t offline_page_id =
- recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item.id.id);
- ContentSuggestion suggestion(
- provided_category_, base::IntToString(offline_page_id), ui_item.page_url);
- suggestion.set_title(base::UTF8ToUTF16(ui_item.title));
- suggestion.set_publish_date(ui_item.creation_time);
- suggestion.set_publisher_name(base::UTF8ToUTF16(ui_item.page_url.host()));
- auto extra = std::make_unique<RecentTabSuggestionExtra>();
- int tab_id;
- bool success = base::StringToInt(ui_item.id.id, &tab_id);
- DCHECK(success);
- extra->tab_id = tab_id;
- extra->offline_page_id = offline_page_id;
- suggestion.set_recent_tab_suggestion_extra(std::move(extra));
-
- return suggestion;
-}
-
-std::vector<ContentSuggestion>
-RecentTabSuggestionsProvider::GetMostRecentlyCreatedWithoutDuplicates(
- std::vector<OfflineItem>& ui_items) const {
- // |std::unique| only removes duplicates that immediately follow each other.
- // Thus, first, we have to sort by URL and creation time and only then remove
- // duplicates and sort the remaining items by creation time.
- std::sort(ui_items.begin(), ui_items.end(),
- OrderUIItemsByUrlAndThenMostRecentlyCreatedFirst());
- std::vector<OfflineItem>::iterator new_end =
- std::unique(ui_items.begin(), ui_items.end(),
- [](const OfflineItem& left, const OfflineItem& right) {
- return left.page_url == right.page_url;
- });
- ui_items.erase(new_end, ui_items.end());
- std::sort(ui_items.begin(), ui_items.end(),
- OrderUIItemsByMostRecentlyCreatedFirst());
- std::vector<ContentSuggestion> suggestions;
- for (const OfflineItem& ui_item : ui_items) {
- suggestions.push_back(ConvertUIItem(ui_item));
- if (static_cast<int>(suggestions.size()) == GetMaxSuggestionsCount()) {
- break;
- }
- }
- return suggestions;
-}
-
-void RecentTabSuggestionsProvider::InvalidateSuggestion(
- const std::string& ui_item_guid) {
- std::string offline_page_id = base::IntToString(
- recent_tabs_ui_adapter_->GetOfflineIdByGuid(ui_item_guid));
- observer()->OnSuggestionInvalidated(
- this, ContentSuggestion::ID(provided_category_, offline_page_id));
-
- std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
- auto it = dismissed_ids.find(offline_page_id);
- if (it != dismissed_ids.end()) {
- dismissed_ids.erase(it);
- StoreDismissedIDsToPrefs(dismissed_ids);
- }
-}
-
-std::set<std::string> RecentTabSuggestionsProvider::ReadDismissedIDsFromPrefs()
- const {
- return prefs::ReadDismissedIDsFromPrefs(
- *pref_service_, prefs::kDismissedRecentOfflineTabSuggestions);
-}
-
-void RecentTabSuggestionsProvider::StoreDismissedIDsToPrefs(
- const std::set<std::string>& dismissed_ids) {
- prefs::StoreDismissedIDsToPrefs(pref_service_,
- prefs::kDismissedRecentOfflineTabSuggestions,
- dismissed_ids);
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
deleted file mode 100644
index 2c8c11e3228..00000000000
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
-#define COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/category_status.h"
-#include "components/ntp_snippets/content_suggestion.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/offline_page_model.h"
-
-class PrefRegistrySimple;
-class PrefService;
-
-using ContentId = offline_items_collection::ContentId;
-using OfflineItem = offline_items_collection::OfflineItem;
-using OfflineContentProvider = offline_items_collection::OfflineContentProvider;
-
-namespace ntp_snippets {
-
-// Provides recent tabs content suggestions from the offline pages model.
-class RecentTabSuggestionsProvider : public ContentSuggestionsProvider,
- public OfflineContentProvider::Observer {
- public:
- RecentTabSuggestionsProvider(ContentSuggestionsProvider::Observer* observer,
- offline_pages::DownloadUIAdapter* ui_adapter,
- PrefService* pref_service);
- ~RecentTabSuggestionsProvider() override;
-
- // ContentSuggestionsProvider implementation.
- CategoryStatus GetCategoryStatus(Category category) override;
- CategoryInfo GetCategoryInfo(Category category) override;
- void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
- void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- ImageFetchedCallback callback) override;
- void FetchSuggestionImageData(const ContentSuggestion::ID& suggestion_id,
- ImageDataFetchedCallback callback) override;
- void Fetch(const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- FetchDoneCallback callback) override;
- void ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) override;
- void ClearCachedSuggestions() override;
- void GetDismissedSuggestionsForDebugging(
- Category category,
- DismissedSuggestionsCallback callback) override;
- void ClearDismissedSuggestionsForDebugging(Category category) override;
-
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- private:
- friend class RecentTabSuggestionsProviderTestNoLoad;
-
- // OfflineContentProvider::Observer implementation.
- void OnItemsAdded(const std::vector<OfflineItem>& items) override;
- void OnItemRemoved(const ContentId& id) override;
- void OnItemUpdated(const OfflineItem& item) override;
-
- // Updates the |category_status_| of the |provided_category_| and notifies the
- // |observer_|, if necessary.
- void NotifyStatusChanged(CategoryStatus new_status);
-
- // Manually requests all Recent Tabs UI items and updates the suggestions.
- void FetchRecentTabs();
- void OnFetchRecentTabsDone(const std::vector<OfflineItem>& offline_items);
-
- void OnGetDismissedSuggestionsForDebuggingDone(
- DismissedSuggestionsCallback callback,
- const std::vector<OfflineItem>& offline_items);
-
- // Converts an OfflineItem to a ContentSuggestion for the
- // |provided_category_|.
- ContentSuggestion ConvertUIItem(const OfflineItem& ui_item) const;
-
- // Removes duplicates for the same URL leaving only the most recently created
- // items, returns at most |GetMaxSuggestionsCount()| ContentSuggestions
- // corresponding to the remaining items, sorted by creation time (newer
- // first).
- std::vector<ContentSuggestion> GetMostRecentlyCreatedWithoutDuplicates(
- std::vector<OfflineItem>& ui_items) const;
-
- // Fires the |OnSuggestionInvalidated| event for the suggestion corresponding
- // to the given |offline_id| and deletes it from the dismissed IDs list, if
- // necessary.
- void InvalidateSuggestion(const std::string& ui_item_guid);
-
- // Reads dismissed IDs from Prefs.
- std::set<std::string> ReadDismissedIDsFromPrefs() const;
-
- // Writes |dismissed_ids| into Prefs.
- void StoreDismissedIDsToPrefs(const std::set<std::string>& dismissed_ids);
-
- CategoryStatus category_status_;
- const Category provided_category_;
- offline_pages::DownloadUIAdapter* recent_tabs_ui_adapter_;
-
- PrefService* pref_service_;
-
- base::WeakPtrFactory<RecentTabSuggestionsProvider> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProvider);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_OFFLINE_PAGES_RECENT_TAB_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
deleted file mode 100644
index 504a61fac38..00000000000
--- a/chromium/components/ntp_snippets/offline_pages/recent_tab_suggestions_provider_unittest.cc
+++ /dev/null
@@ -1,464 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/files/file_path.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
-#include "components/ntp_snippets/offline_pages/offline_pages_test_utils.h"
-#include "components/offline_pages/core/background/request_coordinator_stub_taco.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/offline_page_item.h"
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ntp_snippets::test::CaptureDismissedSuggestions;
-using ntp_snippets::test::FakeOfflinePageModel;
-using offline_pages::ClientId;
-using offline_pages::MultipleOfflinePageItemCallback;
-using offline_pages::OfflinePageItem;
-using testing::_;
-using testing::IsEmpty;
-using testing::Mock;
-using testing::Property;
-using testing::SizeIs;
-
-namespace ntp_snippets {
-
-namespace {
-
-const int64_t kSystemDownloadId = 0;
-
-OfflinePageItem CreateDummyRecentTab(int offline_id) {
- // This is used to assign unique tab IDs to pages. Since offline IDs are
- // typically small integers like 1, 2, 3 etc, we start at 1001 to ensure that
- // they are different, and can catch bugs where offline page ID is used in
- // place of tab ID and vice versa.
- std::string tab_id = base::IntToString(offline_id + 1000);
- ClientId client_id(offline_pages::kLastNNamespace, tab_id);
- return test::CreateDummyOfflinePageItem(offline_id, client_id);
-}
-
-std::vector<OfflinePageItem> CreateDummyRecentTabs(
- const std::vector<int>& ids) {
- std::vector<OfflinePageItem> result;
- for (int id : ids) {
- result.push_back(CreateDummyRecentTab(id));
- }
- return result;
-}
-
-OfflinePageItem CreateDummyRecentTab(int id, base::Time time) {
- OfflinePageItem item = CreateDummyRecentTab(id);
- item.creation_time = time;
- item.last_access_time = time;
- return item;
-}
-
-void GetAllItemsDummyCallback(const std::vector<OfflineItem>& items) {}
-
-} // namespace
-
-class RecentTabSuggestionsProviderTestNoLoad : public testing::Test {
- public:
- RecentTabSuggestionsProviderTestNoLoad()
- : task_runner_(new base::TestSimpleTaskRunner()),
- task_runner_handle_(task_runner_),
- pref_service_(new TestingPrefServiceSimple()) {
- RecentTabSuggestionsProvider::RegisterProfilePrefs(
- pref_service()->registry());
-
- taco_ = std::make_unique<offline_pages::RequestCoordinatorStubTaco>();
- taco_->CreateRequestCoordinator();
-
- ui_adapter_ = offline_pages::RecentTabsUIAdapterDelegate::
- GetOrCreateRecentTabsUIAdapter(&model_, taco_->request_coordinator());
- delegate_ =
- offline_pages::RecentTabsUIAdapterDelegate::FromDownloadUIAdapter(
- ui_adapter_);
- provider_ = std::make_unique<RecentTabSuggestionsProvider>(
- &observer_, ui_adapter_, pref_service());
- // Force adapter to load its cache.
- ui_adapter_->GetAllItems(base::BindOnce(&GetAllItemsDummyCallback));
- provider_->FetchRecentTabs();
- }
-
- Category recent_tabs_category() {
- return Category::FromKnownCategory(KnownCategories::RECENT_TABS);
- }
-
- ContentSuggestion::ID GetDummySuggestionId(int id) {
- return ContentSuggestion::ID(recent_tabs_category(), base::IntToString(id));
- }
-
- void AddTabAndOfflinePageToModel(const OfflinePageItem& item) {
- AddTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
- item.client_id));
- AddOfflinePageToModel(item);
- }
-
- void AddTab(int tab_id) { delegate_->RegisterTab(tab_id); }
-
- void RemoveTab(int tab_id) { delegate_->UnregisterTab(tab_id); }
-
- void AddOfflinePageToModel(const OfflinePageItem& item) {
- ui_adapter_->OfflinePageAdded(&model_, item);
- }
-
- void FireOfflinePageDeleted(const OfflinePageItem& item) {
- int tab_id = offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
- item.client_id);
- RemoveTab(tab_id);
- ui_adapter_->OfflinePageDeleted(
- offline_pages::OfflinePageModel::DeletedPageInfo(
- item.offline_id, kSystemDownloadId, item.client_id,
- "" /* request_origin */));
- }
-
- std::set<std::string> ReadDismissedIDsFromPrefs() {
- return provider_->ReadDismissedIDsFromPrefs();
- }
-
- RecentTabSuggestionsProvider* provider() { return provider_.get(); }
- MockContentSuggestionsProviderObserver* observer() { return &observer_; }
- TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
- base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
-
- private:
- FakeOfflinePageModel model_;
- offline_pages::DownloadUIAdapter* ui_adapter_;
- offline_pages::RecentTabsUIAdapterDelegate* delegate_;
- scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
- base::ThreadTaskRunnerHandle task_runner_handle_;
- std::unique_ptr<offline_pages::RequestCoordinatorStubTaco> taco_;
- MockContentSuggestionsProviderObserver observer_;
- std::unique_ptr<TestingPrefServiceSimple> pref_service_;
- // Last so that the dependencies are deleted after the provider.
- std::unique_ptr<RecentTabSuggestionsProvider> provider_;
-
- DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTestNoLoad);
-};
-
-// Test that always loads the model before the start of the test.
-class RecentTabSuggestionsProviderTest
- : public RecentTabSuggestionsProviderTestNoLoad {
- public:
- RecentTabSuggestionsProviderTest() = default;
-
- void SetUp() override {
- // The UI adapter always fires asynchronously upon loading, so we want to
- // run past that moment before each test. Expect a call to hide warnings.
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(1);
- task_runner()->RunUntilIdle();
- Mock::VerifyAndClearExpectations(observer());
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(RecentTabSuggestionsProviderTest);
-};
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldConvertToSuggestions) {
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(2);
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/2")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/3")))));
-
- auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3});
- for (OfflinePageItem& recent_tab : recent_tabs_list) {
- AddTabAndOfflinePageToModel(recent_tab);
- }
- task_runner()->RunUntilIdle();
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldSortByCreationTime) {
- base::Time now = base::Time::Now();
- base::Time yesterday = now - base::TimeDelta::FromDays(1);
- base::Time tomorrow = now + base::TimeDelta::FromDays(1);
-
- std::vector<OfflinePageItem> offline_pages = {
- CreateDummyRecentTab(1, now), CreateDummyRecentTab(2, yesterday),
- CreateDummyRecentTab(3, tomorrow)};
-
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(_, recent_tabs_category(),
- ElementsAre(Property(&ContentSuggestion::url,
- GURL("http://dummy.com/1")))));
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(1, now));
- task_runner()->RunUntilIdle();
-
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- ElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(2, yesterday));
- task_runner()->RunUntilIdle();
-
- offline_pages[1].last_access_time =
- offline_pages[0].last_access_time + base::TimeDelta::FromHours(1);
-
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- ElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/3")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(3, tomorrow));
- task_runner()->RunUntilIdle();
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldDeliverCorrectCategoryInfo) {
- EXPECT_EQ(
- ContentSuggestionsAdditionalAction::NONE,
- provider()->GetCategoryInfo(recent_tabs_category()).additional_action());
-}
-
-// TODO(vitaliii): Break this test into multiple tests. Currently if it fails,
-// it takes long time to find which part of it actually fails.
-TEST_F(RecentTabSuggestionsProviderTest, ShouldDismiss) {
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
- auto recent_tabs_list = CreateDummyRecentTabs({1, 2, 3});
- for (OfflinePageItem& recent_tab : recent_tabs_list) {
- AddTabAndOfflinePageToModel(recent_tab);
- }
- task_runner()->RunUntilIdle();
-
- // Dismiss 2 and 3.
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
- provider()->DismissSuggestion(GetDummySuggestionId(2));
- provider()->DismissSuggestion(GetDummySuggestionId(3));
- Mock::VerifyAndClearExpectations(observer());
-
- // They should disappear from the reported suggestions.
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/4")))));
-
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(4));
- task_runner()->RunUntilIdle();
- Mock::VerifyAndClearExpectations(observer());
-
- // And appear in the dismissed suggestions.
- std::vector<ContentSuggestion> dismissed_suggestions;
- provider()->GetDismissedSuggestionsForDebugging(
- recent_tabs_category(),
- base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
- task_runner()->RunUntilIdle();
- EXPECT_THAT(
- dismissed_suggestions,
- UnorderedElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/2")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/3"))));
-
- // Clear dismissed suggestions.
- provider()->ClearDismissedSuggestionsForDebugging(recent_tabs_category());
- task_runner()->RunUntilIdle();
-
- // They should be gone from the dismissed suggestions.
- dismissed_suggestions.clear();
- provider()->GetDismissedSuggestionsForDebugging(
- recent_tabs_category(),
- base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
- task_runner()->RunUntilIdle();
- EXPECT_THAT(dismissed_suggestions, IsEmpty());
-
- // And appear in the reported suggestions for the category again.
- EXPECT_CALL(*observer(),
- OnNewSuggestions(_, recent_tabs_category(), SizeIs(5)));
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(5));
- task_runner()->RunUntilIdle();
- Mock::VerifyAndClearExpectations(observer());
-}
-
-TEST_F(RecentTabSuggestionsProviderTest,
- ShouldInvalidateWhenOfflinePageDeleted) {
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
- std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
- for (OfflinePageItem& recent_tab : offline_pages)
- AddTabAndOfflinePageToModel(recent_tab);
- task_runner()->RunUntilIdle();
-
- // Invalidation of suggestion 2 should be forwarded.
- EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(2)));
- FireOfflinePageDeleted(offline_pages[1]);
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnInvalidate) {
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
- std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
- for (OfflinePageItem& recent_tab : offline_pages)
- AddTabAndOfflinePageToModel(recent_tab);
- task_runner()->RunUntilIdle();
- EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
-
- provider()->DismissSuggestion(GetDummySuggestionId(2));
- EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1));
-
- FireOfflinePageDeleted(offline_pages[1]);
- EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldClearDismissedOnFetch) {
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(3);
- std::vector<OfflinePageItem> offline_pages = CreateDummyRecentTabs({1, 2, 3});
- for (OfflinePageItem& recent_tab : offline_pages)
- AddTabAndOfflinePageToModel(recent_tab);
- task_runner()->RunUntilIdle();
-
- provider()->DismissSuggestion(GetDummySuggestionId(2));
- provider()->DismissSuggestion(GetDummySuggestionId(3));
- EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(2));
-
- FireOfflinePageDeleted(offline_pages[0]);
- FireOfflinePageDeleted(offline_pages[2]);
- EXPECT_THAT(ReadDismissedIDsFromPrefs(), SizeIs(1));
-
- FireOfflinePageDeleted(offline_pages[1]);
- EXPECT_THAT(ReadDismissedIDsFromPrefs(), IsEmpty());
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowSameUrlMutlipleTimes) {
- base::Time now = base::Time::Now();
- base::Time yesterday = now - base::TimeDelta::FromDays(1);
- base::Time tomorrow = now + base::TimeDelta::FromDays(1);
- std::vector<OfflinePageItem> offline_pages = {
- CreateDummyRecentTab(1, yesterday), CreateDummyRecentTab(2, now),
- CreateDummyRecentTab(3, tomorrow)};
-
- // We leave IDs different, but make the URLs the same.
- offline_pages[2].url = offline_pages[0].url;
-
- AddTabAndOfflinePageToModel(offline_pages[0]);
- AddTabAndOfflinePageToModel(offline_pages[1]);
- task_runner()->RunUntilIdle();
- Mock::VerifyAndClearExpectations(observer());
- EXPECT_CALL(*observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::publish_date, now),
- Property(&ContentSuggestion::publish_date, tomorrow))));
-
- AddTabAndOfflinePageToModel(offline_pages[2]);
- task_runner()->RunUntilIdle();
-}
-
-TEST_F(RecentTabSuggestionsProviderTest,
- ShouldNotFetchIfAddedOfflinePageIsNotRecentTab) {
- // It should not fetch when not a recent tab is added, thus, it should not
- // report the first recent tab (which it is not aware about).
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
- AddOfflinePageToModel(ntp_snippets::test::CreateDummyOfflinePageItem(
- 2, offline_pages::kDefaultNamespace));
-}
-
-TEST_F(RecentTabSuggestionsProviderTest,
- ShouldInvalidateSuggestionWhenTabGone) {
- OfflinePageItem first_tab = CreateDummyRecentTab(1);
- AddTabAndOfflinePageToModel(first_tab);
- task_runner()->RunUntilIdle();
- Mock::VerifyAndClearExpectations(observer());
-
- EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(1)))
- .Times(1);
- RemoveTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
- first_tab.client_id));
- // Removing an unknown tab should not cause extra invalidations.
- RemoveTab(42);
-}
-
-TEST_F(RecentTabSuggestionsProviderTest, ShouldNotShowPagesWithoutTab) {
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
- // The provider is not notified about the first recent tab yet (no tab).
- OfflinePageItem first_tab = CreateDummyRecentTab(1);
- AddOfflinePageToModel(first_tab);
-
- Mock::VerifyAndClearExpectations(observer());
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(1);
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
-
- AddTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
- first_tab.client_id));
- OfflinePageItem second_tab = CreateDummyRecentTab(2);
- AddTabAndOfflinePageToModel(second_tab);
- task_runner()->RunUntilIdle();
-
- Mock::VerifyAndClearExpectations(observer());
-
- EXPECT_CALL(*observer(), OnNewSuggestions(_, _, _)).Times(0);
- // |RemoveTab| by itself doesn't cause OnNewSuggestions to be called.
- RemoveTab(offline_pages::RecentTabsUIAdapterDelegate::TabIdFromClientId(
- second_tab.client_id));
- Mock::VerifyAndClearExpectations(observer());
-
- // But when we get another tab, OnNewSuggestions will be called.
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/3")))));
-
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(3));
- task_runner()->RunUntilIdle();
-}
-
-// The following test uses a different fixture that does not automatically pump
-// the event loop in SetUp, which means that until |RunUntilIdle| is called, the
-// UI adapter will not be loaded (and should not fire any events).
-
-TEST_F(RecentTabSuggestionsProviderTestNoLoad, ShouldFetchOnLoad) {
- // Tabs are added to the model before the UI adapter is loaded, so there
- // should only be a single |OnNewSuggestions| call, at load time.
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(
- _, recent_tabs_category(),
- UnorderedElementsAre(
- Property(&ContentSuggestion::url, GURL("http://dummy.com/1")),
- Property(&ContentSuggestion::url, GURL("http://dummy.com/2")))));
-
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(1));
- AddTabAndOfflinePageToModel(CreateDummyRecentTab(2));
- // The provider is not notified about the recent tabs yet.
- task_runner()->RunUntilIdle();
- // However, it must return both tabs when the model is loaded.
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/physical_web_pages/DEPS b/chromium/components/ntp_snippets/physical_web_pages/DEPS
deleted file mode 100644
index ea8c01fdba6..00000000000
--- a/chromium/components/ntp_snippets/physical_web_pages/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
- "+components/grit",
- "+components/physical_web/data_source",
-]
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
deleted file mode 100644
index 357a8c74c2e..00000000000
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
+++ /dev/null
@@ -1,373 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h"
-
-#include <algorithm>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/grit/components_scaled_resources.h"
-#include "components/ntp_snippets/pref_names.h"
-#include "components/ntp_snippets/pref_util.h"
-#include "components/physical_web/data_source/physical_web_data_source.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
-#include "url/gurl.h"
-
-namespace ntp_snippets {
-
-namespace {
-
-const size_t kMaxSuggestionsCount = 10;
-
-std::string GetPageId(const physical_web::Metadata& page_metadata) {
- return page_metadata.resolved_url.spec();
-}
-
-bool CompareByDistance(const physical_web::Metadata& left,
- const physical_web::Metadata& right) {
- // When there is no estimate, the value is <= 0, so we implicitly treat it as
- // infinity.
- bool is_left_estimated = left.distance_estimate > 0;
- bool is_right_estimated = right.distance_estimate > 0;
-
- if (is_left_estimated != is_right_estimated)
- return is_left_estimated;
- return left.distance_estimate < right.distance_estimate;
-}
-
-void FilterOutByGroupId(physical_web::MetadataList& page_metadata_list) {
- // |std::unique| only removes duplicates that immediately follow each other.
- // Thus, first, we have to sort by group_id and distance and only then remove
- // duplicates.
- std::sort(page_metadata_list.begin(), page_metadata_list.end(),
- [](const physical_web::Metadata& left,
- const physical_web::Metadata& right) {
- if (left.group_id != right.group_id) {
- return left.group_id < right.group_id;
- }
-
- // We want closest pages first, so in case of same group_id we
- // sort by distance.
- return CompareByDistance(left, right);
- });
-
- // Each empty group_id must be treated as unique, so we do not apply
- // std::unique to them at all.
- auto nonempty_group_id_begin =
- std::find_if(page_metadata_list.begin(), page_metadata_list.end(),
- [](const physical_web::Metadata& page) {
- return !page.group_id.empty();
- });
-
- auto new_end = std::unique(nonempty_group_id_begin, page_metadata_list.end(),
- [](const physical_web::Metadata& left,
- const physical_web::Metadata& right) {
- return left.group_id == right.group_id;
- });
-
- page_metadata_list.erase(new_end, page_metadata_list.end());
-}
-
-} // namespace
-
-PhysicalWebPageSuggestionsProvider::PhysicalWebPageSuggestionsProvider(
- ContentSuggestionsProvider::Observer* observer,
- physical_web::PhysicalWebDataSource* physical_web_data_source,
- PrefService* pref_service)
- : ContentSuggestionsProvider(observer),
- category_status_(CategoryStatus::AVAILABLE),
- provided_category_(
- Category::FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES)),
- physical_web_data_source_(physical_web_data_source),
- pref_service_(pref_service) {
- observer->OnCategoryStatusChanged(this, provided_category_, category_status_);
- physical_web_data_source_->RegisterListener(
- this, physical_web::BACKGROUND_INTERMITTENT);
- // TODO(vitaliii): Rewrite initial fetch once crbug.com/667754 is resolved.
- FetchPhysicalWebPages();
-}
-
-PhysicalWebPageSuggestionsProvider::~PhysicalWebPageSuggestionsProvider() {
- physical_web_data_source_->UnregisterListener(this);
-}
-
-CategoryStatus PhysicalWebPageSuggestionsProvider::GetCategoryStatus(
- Category category) {
- return category_status_;
-}
-
-CategoryInfo PhysicalWebPageSuggestionsProvider::GetCategoryInfo(
- Category category) {
- return CategoryInfo(l10n_util::GetStringUTF16(
- IDS_NTP_PHYSICAL_WEB_PAGE_SUGGESTIONS_SECTION_HEADER),
- ContentSuggestionsCardLayout::FULL_CARD,
- ContentSuggestionsAdditionalAction::NONE,
- /*show_if_empty=*/false,
- l10n_util::GetStringUTF16(
- IDS_NTP_PHYSICAL_WEB_PAGE_SUGGESTIONS_SECTION_EMPTY));
-}
-
-void PhysicalWebPageSuggestionsProvider::DismissSuggestion(
- const ContentSuggestion::ID& suggestion_id) {
- DCHECK_EQ(provided_category_, suggestion_id.category());
- std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
- dismissed_ids.insert(suggestion_id.id_within_category());
- StoreDismissedIDsToPrefs(dismissed_ids);
-}
-
-void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage(
- const ContentSuggestion::ID& suggestion_id,
- ImageFetchedCallback callback) {
- ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance();
- base::StringPiece raw_data = resource_bundle.GetRawDataResourceForScale(
- IDR_PHYSICAL_WEB_LOGO_WITH_PADDING, resource_bundle.GetMaxScaleFactor());
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(
- std::move(callback),
- gfx::Image::CreateFrom1xPNGBytes(
- reinterpret_cast<const unsigned char*>(raw_data.data()),
- raw_data.size())));
-}
-
-void PhysicalWebPageSuggestionsProvider::FetchSuggestionImageData(
- const ContentSuggestion::ID& suggestion_id,
- ImageDataFetchedCallback callback) {
- // Not implemented for this provider.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), std::string()));
-}
-void PhysicalWebPageSuggestionsProvider::Fetch(
- const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- FetchDoneCallback callback) {
- DCHECK_EQ(category, provided_category_);
- std::vector<ContentSuggestion> suggestions =
- GetMostRecentPhysicalWebPagesWithFilter(kMaxSuggestionsCount,
- known_suggestion_ids);
- AppendToShownScannedUrls(suggestions);
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback), Status::Success(),
- std::move(suggestions)));
-}
-
-void PhysicalWebPageSuggestionsProvider::ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) {
- ClearDismissedSuggestionsForDebugging(provided_category_);
-}
-
-void PhysicalWebPageSuggestionsProvider::ClearCachedSuggestions() {
- // Ignored
-}
-
-void PhysicalWebPageSuggestionsProvider::GetDismissedSuggestionsForDebugging(
- Category category,
- DismissedSuggestionsCallback callback) {
- DCHECK_EQ(provided_category_, category);
- std::unique_ptr<physical_web::MetadataList> page_metadata_list =
- physical_web_data_source_->GetMetadataList();
- const std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
- std::vector<ContentSuggestion> suggestions;
- for (const auto& page_metadata : *page_metadata_list) {
- if (dismissed_ids.count(GetPageId(page_metadata))) {
- suggestions.push_back(ConvertPhysicalWebPage(page_metadata));
- }
- }
-
- std::move(callback).Run(std::move(suggestions));
-}
-
-void PhysicalWebPageSuggestionsProvider::ClearDismissedSuggestionsForDebugging(
- Category category) {
- DCHECK_EQ(provided_category_, category);
- StoreDismissedIDsToPrefs(std::set<std::string>());
- FetchPhysicalWebPages();
-}
-
-// static
-void PhysicalWebPageSuggestionsProvider::RegisterProfilePrefs(
- PrefRegistrySimple* registry) {
- registry->RegisterListPref(prefs::kDismissedPhysicalWebPageSuggestions);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Private methods
-
-void PhysicalWebPageSuggestionsProvider::NotifyStatusChanged(
- CategoryStatus new_status) {
- if (category_status_ == new_status) {
- return;
- }
- category_status_ = new_status;
- observer()->OnCategoryStatusChanged(this, provided_category_, new_status);
-}
-
-void PhysicalWebPageSuggestionsProvider::FetchPhysicalWebPages() {
- DCHECK_EQ(CategoryStatus::AVAILABLE, category_status_);
- std::vector<ContentSuggestion> suggestions =
- GetMostRecentPhysicalWebPagesWithFilter(
- kMaxSuggestionsCount,
- /*excluded_ids=*/std::set<std::string>());
- shown_resolved_urls_by_scanned_url_.clear();
- AppendToShownScannedUrls(suggestions);
- observer()->OnNewSuggestions(this, provided_category_,
- std::move(suggestions));
-}
-
-std::vector<ContentSuggestion>
-PhysicalWebPageSuggestionsProvider::GetMostRecentPhysicalWebPagesWithFilter(
- int max_count,
- const std::set<std::string>& excluded_ids) {
- std::unique_ptr<physical_web::MetadataList> page_metadata_list =
- physical_web_data_source_->GetMetadataList();
-
- // These is to filter out dismissed suggestions and at the same time prune the
- // dismissed IDs list removing nonavailable pages (this is needed since some
- // OnLost() calls may have been missed).
- const std::set<std::string> old_dismissed_ids = ReadDismissedIDsFromPrefs();
- std::set<std::string> new_dismissed_ids;
- physical_web::MetadataList filtered_metadata_list;
- for (const auto& page_metadata : *page_metadata_list) {
- const std::string page_id = GetPageId(page_metadata);
- if (!excluded_ids.count(page_id) && !old_dismissed_ids.count(page_id)) {
- filtered_metadata_list.push_back(page_metadata);
- }
-
- if (old_dismissed_ids.count(page_id)) {
- new_dismissed_ids.insert(page_id);
- }
- }
-
- if (old_dismissed_ids.size() != new_dismissed_ids.size()) {
- StoreDismissedIDsToPrefs(new_dismissed_ids);
- }
-
- FilterOutByGroupId(filtered_metadata_list);
-
- std::sort(filtered_metadata_list.begin(), filtered_metadata_list.end(),
- CompareByDistance);
-
- std::vector<ContentSuggestion> suggestions;
- for (const auto& page_metadata : filtered_metadata_list) {
- if (static_cast<int>(suggestions.size()) == max_count) {
- break;
- }
- suggestions.push_back(ConvertPhysicalWebPage(page_metadata));
- }
-
- return suggestions;
-}
-
-ContentSuggestion PhysicalWebPageSuggestionsProvider::ConvertPhysicalWebPage(
- const physical_web::Metadata& page) const {
- ContentSuggestion suggestion(provided_category_, GetPageId(page),
- page.resolved_url);
- DCHECK(base::IsStringUTF8(page.title));
- suggestion.set_title(base::UTF8ToUTF16(page.title));
- suggestion.set_publisher_name(base::UTF8ToUTF16(page.resolved_url.host()));
- DCHECK(base::IsStringUTF8(page.description));
- suggestion.set_snippet_text(base::UTF8ToUTF16(page.description));
- return suggestion;
-}
-
-// PhysicalWebListener implementation.
-void PhysicalWebPageSuggestionsProvider::OnFound(const GURL& url) {
- FetchPhysicalWebPages();
-}
-
-void PhysicalWebPageSuggestionsProvider::OnLost(const GURL& url) {
- auto it = shown_resolved_urls_by_scanned_url_.find(url);
- if (it == shown_resolved_urls_by_scanned_url_.end()) {
- // The notification is propagated further in case the suggestion is shown on
- // old NTPs (created before last |shown_resolved_urls_by_scanned_url_|
- // update).
-
- // TODO(vitaliii): Use |resolved_url| here when it is available. Currently
- // there is no way to find out |resolved_url|, which corresponds to this
- // |scanned_url| (the metadata has been already removed from the Physical
- // Web list). We use |scanned_url| (it may be the same as |resolved_url|,
- // otherwise nothing happens), however, we should use the latter once it is
- // provided (e.g. as an argument).
- InvalidateSuggestion(url.spec());
- return;
- }
-
- // This is not a reference, because the multimap pair will be removed below.
- const GURL lost_resolved_url = it->second;
- shown_resolved_urls_by_scanned_url_.erase(it);
- if (std::find_if(shown_resolved_urls_by_scanned_url_.begin(),
- shown_resolved_urls_by_scanned_url_.end(),
- [lost_resolved_url](const std::pair<GURL, GURL>& pair) {
- return lost_resolved_url == pair.second;
- }) == shown_resolved_urls_by_scanned_url_.end()) {
- // There are no more beacons for this URL.
- InvalidateSuggestion(lost_resolved_url.spec());
- }
-}
-
-void PhysicalWebPageSuggestionsProvider::OnDistanceChanged(
- const GURL& url,
- double distance_estimate) {
- FetchPhysicalWebPages();
-}
-
-void PhysicalWebPageSuggestionsProvider::InvalidateSuggestion(
- const std::string& page_id) {
- observer()->OnSuggestionInvalidated(
- this, ContentSuggestion::ID(provided_category_, page_id));
-
- // Remove |page_id| from dismissed suggestions, if present.
- std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs();
- auto it = dismissed_ids.find(page_id);
- if (it != dismissed_ids.end()) {
- dismissed_ids.erase(it);
- StoreDismissedIDsToPrefs(dismissed_ids);
- }
-}
-
-void PhysicalWebPageSuggestionsProvider::AppendToShownScannedUrls(
- const std::vector<ContentSuggestion>& suggestions) {
- std::unique_ptr<physical_web::MetadataList> page_metadata_list =
- physical_web_data_source_->GetMetadataList();
- for (const auto& page_metadata : *page_metadata_list) {
- if (std::find_if(suggestions.begin(), suggestions.end(),
- [page_metadata](const ContentSuggestion& suggestion) {
- return suggestion.url() == page_metadata.resolved_url;
- }) != suggestions.end()) {
- shown_resolved_urls_by_scanned_url_.insert(std::make_pair(
- page_metadata.scanned_url, page_metadata.resolved_url));
- }
- }
-}
-
-std::set<std::string>
-PhysicalWebPageSuggestionsProvider::ReadDismissedIDsFromPrefs() const {
- return prefs::ReadDismissedIDsFromPrefs(
- *pref_service_, prefs::kDismissedPhysicalWebPageSuggestions);
-}
-
-void PhysicalWebPageSuggestionsProvider::StoreDismissedIDsToPrefs(
- const std::set<std::string>& dismissed_ids) {
- prefs::StoreDismissedIDsToPrefs(pref_service_,
- prefs::kDismissedPhysicalWebPageSuggestions,
- dismissed_ids);
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
deleted file mode 100644
index c4c1130ad65..00000000000
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_NTP_SNIPPETS_PHYSICAL_WEB_PAGES_PHYSICAL_WEB_PAGE_SUGGESTIONS_PROVIDER_H_
-#define COMPONENTS_NTP_SNIPPETS_PHYSICAL_WEB_PAGES_PHYSICAL_WEB_PAGE_SUGGESTIONS_PROVIDER_H_
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "base/callback_forward.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/category_status.h"
-#include "components/ntp_snippets/content_suggestion.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/physical_web/data_source/physical_web_listener.h"
-
-class GURL;
-class PrefRegistrySimple;
-class PrefService;
-
-namespace physical_web {
-class PhysicalWebDataSource;
-struct Metadata;
-} // namespace physical_web
-
-namespace ntp_snippets {
-
-// Provides content suggestions from the Physical Web Service.
-class PhysicalWebPageSuggestionsProvider
- : public ContentSuggestionsProvider,
- public physical_web::PhysicalWebListener {
- public:
- PhysicalWebPageSuggestionsProvider(
- ContentSuggestionsProvider::Observer* observer,
- physical_web::PhysicalWebDataSource* physical_web_data_source,
- PrefService* pref_service);
- ~PhysicalWebPageSuggestionsProvider() override;
-
- // ContentSuggestionsProvider implementation.
- CategoryStatus GetCategoryStatus(Category category) override;
- CategoryInfo GetCategoryInfo(Category category) override;
- void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
- void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
- ImageFetchedCallback callback) override;
- void FetchSuggestionImageData(const ContentSuggestion::ID& suggestion_id,
- ImageDataFetchedCallback callback) override;
- void Fetch(const Category& category,
- const std::set<std::string>& known_suggestion_ids,
- FetchDoneCallback callback) override;
- void ClearHistory(
- base::Time begin,
- base::Time end,
- const base::Callback<bool(const GURL& url)>& filter) override;
- void ClearCachedSuggestions() override;
- void GetDismissedSuggestionsForDebugging(
- Category category,
- DismissedSuggestionsCallback callback) override;
- void ClearDismissedSuggestionsForDebugging(Category category) override;
-
- static void RegisterProfilePrefs(PrefRegistrySimple* registry);
-
- private:
- friend class PhysicalWebPageSuggestionsProviderTest;
-
- // Updates the |category_status_| and notifies the |observer_|, if necessary.
- void NotifyStatusChanged(CategoryStatus new_status);
-
- // Manually requests all physical web pages and updates the suggestions.
- void FetchPhysicalWebPages();
-
- // Returns at most |max_count| ContentSuggestions with IDs not in
- // |excluded_ids| and sorted by distance (the closest first). Dismissed
- // suggestions are excluded automatically (no need to add them to
- // |excluded_ids|) and pruned. The raw pages are obtained from Physical Web
- // data source.
- std::vector<ContentSuggestion> GetMostRecentPhysicalWebPagesWithFilter(
- int max_count,
- const std::set<std::string>& excluded_ids);
-
- // Converts an Physical Web page to a ContentSuggestion.
- ContentSuggestion ConvertPhysicalWebPage(
- const physical_web::Metadata& page) const;
-
- // PhysicalWebListener implementation.
- void OnFound(const GURL& url) override;
- void OnLost(const GURL& url) override;
- void OnDistanceChanged(const GURL& url, double distance_estimate) override;
-
- // Fires the |OnSuggestionInvalidated| event for the suggestion corresponding
- // to the given |page_id| and deletes it from the dismissed IDs list, if
- // necessary.
- void InvalidateSuggestion(const std::string& page_id);
-
- void AppendToShownScannedUrls(
- const std::vector<ContentSuggestion>& suggestions);
-
- // Reads dismissed IDs from Prefs.
- std::set<std::string> ReadDismissedIDsFromPrefs() const;
-
- // Writes |dismissed_ids| into Prefs.
- void StoreDismissedIDsToPrefs(const std::set<std::string>& dismissed_ids);
-
- std::multimap<GURL, GURL> shown_resolved_urls_by_scanned_url_;
- CategoryStatus category_status_;
- const Category provided_category_;
- physical_web::PhysicalWebDataSource* physical_web_data_source_;
- PrefService* pref_service_;
-
- DISALLOW_COPY_AND_ASSIGN(PhysicalWebPageSuggestionsProvider);
-};
-
-} // namespace ntp_snippets
-
-#endif // COMPONENTS_NTP_SNIPPETS_PHYSICAL_WEB_PAGES_PHYSICAL_WEB_PAGE_SUGGESTIONS_PROVIDER_H_
diff --git a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc b/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
deleted file mode 100644
index 0a2f069f2c3..00000000000
--- a/chromium/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider_unittest.cc
+++ /dev/null
@@ -1,466 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h"
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "components/ntp_snippets/category.h"
-#include "components/ntp_snippets/content_suggestions_provider.h"
-#include "components/ntp_snippets/mock_content_suggestions_provider_observer.h"
-#include "components/ntp_snippets/offline_pages/offline_pages_test_utils.h"
-#include "components/ntp_snippets/status.h"
-#include "components/physical_web/data_source/fake_physical_web_data_source.h"
-#include "components/prefs/testing_pref_service.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-using ntp_snippets::test::CaptureDismissedSuggestions;
-using physical_web::CreateDummyPhysicalWebPages;
-using physical_web::FakePhysicalWebDataSource;
-using testing::_;
-using testing::AnyNumber;
-using testing::AtMost;
-using testing::ElementsAre;
-using testing::ElementsAreArray;
-using testing::Mock;
-using testing::StrictMock;
-using testing::UnorderedElementsAre;
-
-namespace ntp_snippets {
-
-namespace {
-
-MATCHER_P(HasUrl, url, "") {
- *result_listener << "expected URL: " << url
- << ", but has URL: " << arg.url().spec();
- return url == arg.url().spec();
-}
-
-void CompareFetchMoreResult(
- const base::Closure& done_closure,
- Status expected_status,
- const std::vector<std::string>& expected_suggestion_urls,
- Status actual_status,
- std::vector<ContentSuggestion> actual_suggestions) {
- EXPECT_EQ(expected_status.code, actual_status.code);
- std::vector<std::string> actual_suggestion_urls;
- for (const ContentSuggestion& suggestion : actual_suggestions) {
- actual_suggestion_urls.push_back(suggestion.url().spec());
- }
- EXPECT_THAT(actual_suggestion_urls,
- ElementsAreArray(expected_suggestion_urls));
- done_closure.Run();
-}
-
-} // namespace
-
-class PhysicalWebPageSuggestionsProviderTest : public testing::Test {
- public:
- PhysicalWebPageSuggestionsProviderTest()
- : pref_service_(std::make_unique<TestingPrefServiceSimple>()) {
- PhysicalWebPageSuggestionsProvider::RegisterProfilePrefs(
- pref_service_->registry());
- }
-
- void IgnoreOnCategoryStatusChangedToAvailable() {
- EXPECT_CALL(observer_, OnCategoryStatusChanged(_, provided_category(),
- CategoryStatus::AVAILABLE))
- .Times(AnyNumber());
- EXPECT_CALL(observer_,
- OnCategoryStatusChanged(_, provided_category(),
- CategoryStatus::AVAILABLE_LOADING))
- .Times(AnyNumber());
- }
-
- void IgnoreOnSuggestionInvalidated() {
- EXPECT_CALL(observer_, OnSuggestionInvalidated(_, _)).Times(AnyNumber());
- }
-
- void IgnoreOnNewSuggestions() {
- EXPECT_CALL(observer_, OnNewSuggestions(_, provided_category(), _))
- .Times(AnyNumber());
- }
-
- PhysicalWebPageSuggestionsProvider* CreateProvider() {
- DCHECK(!provider_);
- provider_ = std::make_unique<PhysicalWebPageSuggestionsProvider>(
- &observer_, &physical_web_data_source_, pref_service_.get());
- return provider_.get();
- }
-
- void DestroyProvider() { provider_.reset(); }
-
- Category provided_category() {
- return Category::FromKnownCategory(KnownCategories::PHYSICAL_WEB_PAGES);
- }
-
- ContentSuggestion::ID GetDummySuggestionId(int id) {
- return ContentSuggestion::ID(
- provided_category(),
- "https://resolved_url.com/" + base::IntToString(id));
- }
-
- void FireUrlFound(const std::string& url) {
- physical_web_data_source_.NotifyOnFound(GURL(url));
- }
-
- void FireUrlLost(const std::string& url) {
- physical_web_data_source_.NotifyOnLost(GURL(url));
- }
-
- void FireUrlDistanceChanged(const GURL& url, double new_distance) {
- physical_web_data_source_.NotifyOnDistanceChanged(url, new_distance);
- }
-
- ContentSuggestionsProvider* provider() {
- DCHECK(provider_);
- return provider_.get();
- }
-
- FakePhysicalWebDataSource* physical_web_data_source() {
- return &physical_web_data_source_;
- }
- MockContentSuggestionsProviderObserver* observer() { return &observer_; }
- TestingPrefServiceSimple* pref_service() { return pref_service_.get(); }
-
- private:
- FakePhysicalWebDataSource physical_web_data_source_;
- StrictMock<MockContentSuggestionsProviderObserver> observer_;
- std::unique_ptr<TestingPrefServiceSimple> pref_service_;
- // Added in order to test provider's |Fetch| method.
- base::MessageLoop message_loop_;
- // Last so that the dependencies are deleted after the provider.
- std::unique_ptr<PhysicalWebPageSuggestionsProvider> provider_;
-
- DISALLOW_COPY_AND_ASSIGN(PhysicalWebPageSuggestionsProviderTest);
-};
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldSubmitSuggestionsOnStartup) {
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2, 3}));
- EXPECT_CALL(*observer(), OnCategoryStatusChanged(_, provided_category(),
- CategoryStatus::AVAILABLE));
- EXPECT_CALL(*observer(),
- OnNewSuggestions(
- _, provided_category(),
- UnorderedElementsAre(HasUrl("https://resolved_url.com/1"),
- HasUrl("https://resolved_url.com/2"),
- HasUrl("https://resolved_url.com/3"))));
- CreateProvider();
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest, ShouldSortByDistance) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- // |CreateDummyPhysicalWebPages| builds pages with distances 1, 2 and 3
- // respectively.
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({3, 2, 1}));
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(_, provided_category(),
- ElementsAre(HasUrl("https://resolved_url.com/3"),
- HasUrl("https://resolved_url.com/2"),
- HasUrl("https://resolved_url.com/1"))));
- CreateProvider();
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldConsiderPagesWithoutDistanceEstimateFurthest) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- // |CreateDummyPhysicalWebPages| builds pages with distances 1, 2 and 3
- // respectively.
- std::unique_ptr<physical_web::MetadataList> pages =
- CreateDummyPhysicalWebPages({3, 2, 1});
- // Set the second page distance estimate to unknown.
- (*pages)[1].distance_estimate = -1.0;
- physical_web_data_source()->SetMetadataList(std::move(pages));
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(_, provided_category(),
- ElementsAre(HasUrl("https://resolved_url.com/3"),
- HasUrl("https://resolved_url.com/1"),
- HasUrl("https://resolved_url.com/2"))));
- CreateProvider();
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldNotShowSuggestionsWithSameGroupId) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- // |CreateDummyPhysicalWebPages| builds pages with distances 1, 2
- // respectively.
- std::unique_ptr<physical_web::MetadataList> pages =
- CreateDummyPhysicalWebPages({2, 1});
- for (auto& page : *pages) {
- page.group_id = "some_group_id";
- }
-
- physical_web_data_source()->SetMetadataList(std::move(pages));
- // The closest page should be reported.
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(_, provided_category(),
- ElementsAre(HasUrl("https://resolved_url.com/2"))));
- CreateProvider();
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldShowSuggestionsWithEmptyGroupId) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- std::unique_ptr<physical_web::MetadataList> pages =
- CreateDummyPhysicalWebPages({1, 2});
- for (auto& page : *pages) {
- page.group_id = "";
- }
-
- physical_web_data_source()->SetMetadataList(std::move(pages));
- EXPECT_CALL(*observer(),
- OnNewSuggestions(
- _, provided_category(),
- UnorderedElementsAre(HasUrl("https://resolved_url.com/1"),
- HasUrl("https://resolved_url.com/2"))));
- CreateProvider();
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- FetchMoreShouldFilterAndReturnSortedSuggestions) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- std::vector<int> ids;
- const int kNumSuggestionsInSection = 10;
- const int kNumSuggestionsInSource = 3 * kNumSuggestionsInSection;
- for (int i = 1; i <= kNumSuggestionsInSource; ++i) {
- ids.push_back(i);
- }
- // |CreateDummyPhysicalWebPages| builds pages with distances 1, 2, 3, ... ,
- // so we know the order of suggestions in the provider.
- physical_web_data_source()->SetMetadataList(CreateDummyPhysicalWebPages(ids));
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _));
- CreateProvider();
-
- const std::string dummy_resolved_url = "https://resolved_url.com/";
- std::set<std::string> known_ids;
- for (int i = 1; i <= kNumSuggestionsInSection; ++i) {
- known_ids.insert(dummy_resolved_url + base::IntToString(i));
- }
- known_ids.insert(dummy_resolved_url + base::IntToString(12));
- known_ids.insert(dummy_resolved_url + base::IntToString(17));
- std::vector<std::string> expected_suggestion_urls;
- for (int i = 1; i <= kNumSuggestionsInSource; ++i) {
- if (expected_suggestion_urls.size() == kNumSuggestionsInSection) {
- break;
- }
- std::string url = dummy_resolved_url + base::IntToString(i);
- if (!known_ids.count(url)) {
- expected_suggestion_urls.push_back(url);
- }
- }
-
- // Added to wait for |Fetch| callback to be called.
- base::RunLoop run_loop;
- provider()->Fetch(provided_category(), known_ids,
- base::Bind(CompareFetchMoreResult, run_loop.QuitClosure(),
- Status::Success(), expected_suggestion_urls));
- // Wait for the callback to be called.
- run_loop.Run();
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest, ShouldDismiss) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- physical_web_data_source()->SetMetadataList(CreateDummyPhysicalWebPages({1}));
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _))
- .Times(AtMost(1));
- CreateProvider();
-
- provider()->DismissSuggestion(GetDummySuggestionId(1));
-
- std::vector<ContentSuggestion> dismissed_suggestions;
- provider()->GetDismissedSuggestionsForDebugging(
- provided_category(),
- base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
- EXPECT_THAT(dismissed_suggestions,
- ElementsAre(HasUrl("https://resolved_url.com/1")));
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldNotShowDismissedSuggestions) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- physical_web_data_source()->SetMetadataList(CreateDummyPhysicalWebPages({1}));
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _))
- .Times(AtMost(1));
- CreateProvider();
- Mock::VerifyAndClearExpectations(observer());
-
- provider()->DismissSuggestion(GetDummySuggestionId(1));
-
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2}));
- EXPECT_CALL(
- *observer(),
- OnNewSuggestions(_, provided_category(),
- ElementsAre(HasUrl("https://resolved_url.com/2"))));
- FireUrlFound("https://resolved_url.com/2");
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldPruneDismissedSuggestionsWhenFetching) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- IgnoreOnNewSuggestions();
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2}));
- CreateProvider();
-
- provider()->DismissSuggestion(GetDummySuggestionId(1));
- provider()->DismissSuggestion(GetDummySuggestionId(2));
-
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({2, 3}));
- FireUrlFound("https://resolved_url.com/3");
-
- // The first page needs to be silently added back to the source, because
- // |GetDismissedSuggestionsForDebugging| uses the data source to return
- // suggestions and dismissed suggestions, which are not present there, cannot
- // be returned.
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2, 3}));
- std::vector<ContentSuggestion> dismissed_suggestions;
- provider()->GetDismissedSuggestionsForDebugging(
- provided_category(),
- base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
- EXPECT_THAT(dismissed_suggestions,
- ElementsAre(HasUrl("https://resolved_url.com/2")));
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldPruneDismissedSuggestionsWhenUrlLost) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- IgnoreOnNewSuggestions();
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2}));
- CreateProvider();
-
- provider()->DismissSuggestion(GetDummySuggestionId(1));
- provider()->DismissSuggestion(GetDummySuggestionId(2));
-
- physical_web_data_source()->SetMetadataList(CreateDummyPhysicalWebPages({2}));
- FireUrlLost("https://resolved_url.com/1");
-
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2}));
- std::vector<ContentSuggestion> dismissed_suggestions;
- provider()->GetDismissedSuggestionsForDebugging(
- provided_category(),
- base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
- EXPECT_THAT(dismissed_suggestions,
- ElementsAre(HasUrl("https://resolved_url.com/2")));
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldStoreDismissedSuggestions) {
- IgnoreOnCategoryStatusChangedToAvailable();
- IgnoreOnSuggestionInvalidated();
- IgnoreOnNewSuggestions();
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2}));
- CreateProvider();
- provider()->DismissSuggestion(GetDummySuggestionId(1));
- DestroyProvider();
-
- CreateProvider();
- std::vector<ContentSuggestion> dismissed_suggestions;
- provider()->GetDismissedSuggestionsForDebugging(
- provided_category(),
- base::Bind(&CaptureDismissedSuggestions, &dismissed_suggestions));
- EXPECT_THAT(dismissed_suggestions,
- ElementsAre(HasUrl("https://resolved_url.com/1")));
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldInvalidateSuggestionWhenItsOnlyBeaconIsLost) {
- IgnoreOnCategoryStatusChangedToAvailable();
- physical_web_data_source()->SetMetadataList(
- CreateDummyPhysicalWebPages({1, 2}));
-
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _));
- CreateProvider();
-
- EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(1)));
- FireUrlLost("https://scanned_url.com/1");
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldNotInvalidateSuggestionWhenBeaconWithDifferentScannedURLRemains) {
- IgnoreOnCategoryStatusChangedToAvailable();
- // Make 2 beacons point to the same URL, while having different |scanned_url|.
- std::unique_ptr<physical_web::MetadataList> pages =
- CreateDummyPhysicalWebPages({1, 2});
- (*pages)[1].resolved_url = (*pages)[0].resolved_url;
- physical_web_data_source()->SetMetadataList(std::move(pages));
-
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _));
- CreateProvider();
-
- // The first beacons is lost, but the second one still points to the same
- // |resolved_url|, so the suggestion must not be invalidated.
- EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, _)).Times(0);
- FireUrlLost("https://scanned_url.com/1");
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldNotInvalidateSuggestionWhenBeaconWithSameScannedURLRemains) {
- IgnoreOnCategoryStatusChangedToAvailable();
- // Make 2 beacons point to the same URL, while having the same |scanned_url|.
- std::unique_ptr<physical_web::MetadataList> pages =
- CreateDummyPhysicalWebPages({1, 2});
- (*pages)[1].scanned_url = (*pages)[0].scanned_url;
- (*pages)[1].resolved_url = (*pages)[0].resolved_url;
- physical_web_data_source()->SetMetadataList(std::move(pages));
-
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _));
- CreateProvider();
-
- // The first beacons is lost, but the second one still points to the same
- // |resolved_url|, so the suggestion must not be invalidated.
- EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, _)).Times(0);
- FireUrlLost("https://scanned_url.com/1");
-}
-
-TEST_F(PhysicalWebPageSuggestionsProviderTest,
- ShouldInvalidateSuggestionWhenAllBeaconsLost) {
- IgnoreOnCategoryStatusChangedToAvailable();
- // Make 3 beacons point to the same URL. Two of them have the same
- // |scanned_url|.
- std::unique_ptr<physical_web::MetadataList> pages =
- CreateDummyPhysicalWebPages({1, 2, 3});
- (*pages)[1].scanned_url = (*pages)[0].scanned_url;
- (*pages)[1].resolved_url = (*pages)[0].resolved_url;
- (*pages)[2].resolved_url = (*pages)[0].resolved_url;
- physical_web_data_source()->SetMetadataList(std::move(pages));
-
- EXPECT_CALL(*observer(), OnNewSuggestions(_, provided_category(), _));
- CreateProvider();
-
- FireUrlLost("https://scanned_url.com/1");
- FireUrlLost("https://scanned_url.com/1");
- EXPECT_CALL(*observer(), OnSuggestionInvalidated(_, GetDummySuggestionId(1)));
- FireUrlLost("https://scanned_url.com/3");
-}
-
-} // namespace ntp_snippets
diff --git a/chromium/components/ntp_snippets/pref_names.cc b/chromium/components/ntp_snippets/pref_names.cc
index 781e0f2c89d..f9dc7d3af00 100644
--- a/chromium/components/ntp_snippets/pref_names.cc
+++ b/chromium/components/ntp_snippets/pref_names.cc
@@ -57,10 +57,6 @@ const char kDismissedForeignSessionsSuggestions[] =
"ntp_suggestions.foreign_sessions.dismissed_ids";
const char kDismissedOfflinePageDownloadSuggestions[] =
"ntp_suggestions.downloads.offline_pages.dismissed_ids";
-const char kDismissedPhysicalWebPageSuggestions[] =
- "ntp_suggestions.physical_web.dismissed_ids";
-const char kDismissedRecentOfflineTabSuggestions[] =
- "ntp_suggestions.offline_pages.recent_tabs.dismissed_ids";
const char kDismissedCategories[] = "ntp_suggestions.dismissed_categories";
diff --git a/chromium/components/ntp_snippets/pref_names.h b/chromium/components/ntp_snippets/pref_names.h
index e00b7778d29..7e26cc893ef 100644
--- a/chromium/components/ntp_snippets/pref_names.h
+++ b/chromium/components/ntp_snippets/pref_names.h
@@ -69,8 +69,6 @@ extern const char kLastSuccessfulBackgroundFetchTime[];
extern const char kDismissedAssetDownloadSuggestions[];
extern const char kDismissedForeignSessionsSuggestions[];
extern const char kDismissedOfflinePageDownloadSuggestions[];
-extern const char kDismissedPhysicalWebPageSuggestions[];
-extern const char kDismissedRecentOfflineTabSuggestions[];
extern const char kDismissedCategories[];
diff --git a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
index 516e7b904d5..f9a50bea910 100644
--- a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
+++ b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl.cc
@@ -55,8 +55,8 @@ void PrefetchedPagesTrackerImpl::Initialize(
if (initialization_completed_callbacks_.size() == 1) {
offline_page_model_->GetPagesByNamespace(
offline_pages::kSuggestedArticlesNamespace,
- base::BindRepeating(&PrefetchedPagesTrackerImpl::OfflinePagesLoaded,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&PrefetchedPagesTrackerImpl::OfflinePagesLoaded,
+ weak_ptr_factory_.GetWeakPtr()));
}
}
}
diff --git a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
index 4af1ac1c18e..5563844a385 100644
--- a/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/prefetched_pages_tracker_impl_unittest.cc
@@ -34,7 +34,7 @@ class MockOfflinePageModel : public offline_pages::StubOfflinePageModel {
MOCK_METHOD2(GetPagesByNamespace,
void(const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback));
+ MultipleOfflinePageItemCallback callback));
};
OfflinePageItem CreateOfflinePageItem(const GURL& url,
@@ -140,7 +140,7 @@ TEST_F(PrefetchedPagesTrackerImplTest, ShouldDeletePrefetchedURLWhenNotified) {
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
item.offline_id, kSystemDownloadId, item.client_id,
- /*request_origin=*/""));
+ /*request_origin=*/"", item.original_url));
EXPECT_FALSE(
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
}
@@ -163,7 +163,7 @@ TEST_F(PrefetchedPagesTrackerImplTest,
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
manually_downloaded_item.offline_id, kSystemDownloadId,
manually_downloaded_item.client_id,
- /*request_origin=*/""));
+ /*request_origin=*/"", manually_downloaded_item.original_url));
EXPECT_TRUE(
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
}
@@ -184,12 +184,15 @@ TEST_F(PrefetchedPagesTrackerImplTest,
EXPECT_CALL(
*mock_offline_page_model(),
GetPagesByNamespace(offline_pages::kSuggestedArticlesNamespace, _))
- .WillOnce(SaveArg<1>(&offline_pages_callback));
+ .WillOnce([&](const std::string& name_space,
+ MultipleOfflinePageItemCallback callback) {
+ offline_pages_callback = std::move(callback);
+ });
PrefetchedPagesTrackerImpl tracker(mock_offline_page_model());
tracker.Initialize(base::BindOnce([] {}));
ASSERT_FALSE(tracker.IsInitialized());
- offline_pages_callback.Run(std::vector<OfflinePageItem>());
+ std::move(offline_pages_callback).Run(std::vector<OfflinePageItem>());
EXPECT_TRUE(tracker.IsInitialized());
}
@@ -198,14 +201,17 @@ TEST_F(PrefetchedPagesTrackerImplTest, ShouldCallCallbackAfterInitialization) {
EXPECT_CALL(
*mock_offline_page_model(),
GetPagesByNamespace(offline_pages::kSuggestedArticlesNamespace, _))
- .WillOnce(SaveArg<1>(&offline_pages_callback));
+ .WillOnce([&](const std::string& name_space,
+ MultipleOfflinePageItemCallback callback) {
+ offline_pages_callback = std::move(callback);
+ });
PrefetchedPagesTrackerImpl tracker(mock_offline_page_model());
base::MockCallback<base::OnceCallback<void()>>
mock_initialization_completed_callback;
tracker.Initialize(mock_initialization_completed_callback.Get());
EXPECT_CALL(mock_initialization_completed_callback, Run());
- offline_pages_callback.Run(std::vector<OfflinePageItem>());
+ std::move(offline_pages_callback).Run(std::vector<OfflinePageItem>());
}
TEST_F(PrefetchedPagesTrackerImplTest,
@@ -214,7 +220,10 @@ TEST_F(PrefetchedPagesTrackerImplTest,
EXPECT_CALL(
*mock_offline_page_model(),
GetPagesByNamespace(offline_pages::kSuggestedArticlesNamespace, _))
- .WillOnce(SaveArg<1>(&offline_pages_callback));
+ .WillOnce([&](const std::string& name_space,
+ MultipleOfflinePageItemCallback callback) {
+ offline_pages_callback = std::move(callback);
+ });
PrefetchedPagesTrackerImpl tracker(mock_offline_page_model());
base::MockCallback<base::OnceCallback<void()>>
@@ -224,7 +233,7 @@ TEST_F(PrefetchedPagesTrackerImplTest,
tracker.Initialize(second_mock_initialization_completed_callback.Get());
EXPECT_CALL(first_mock_initialization_completed_callback, Run());
EXPECT_CALL(second_mock_initialization_completed_callback, Run());
- offline_pages_callback.Run(std::vector<OfflinePageItem>());
+ std::move(offline_pages_callback).Run(std::vector<OfflinePageItem>());
}
TEST_F(PrefetchedPagesTrackerImplTest,
@@ -233,11 +242,14 @@ TEST_F(PrefetchedPagesTrackerImplTest,
EXPECT_CALL(
*mock_offline_page_model(),
GetPagesByNamespace(offline_pages::kSuggestedArticlesNamespace, _))
- .WillOnce(SaveArg<1>(&offline_pages_callback));
+ .WillOnce([&](const std::string& name_space,
+ MultipleOfflinePageItemCallback callback) {
+ offline_pages_callback = std::move(callback);
+ });
PrefetchedPagesTrackerImpl tracker(mock_offline_page_model());
tracker.Initialize(base::BindOnce([] {}));
- offline_pages_callback.Run(std::vector<OfflinePageItem>());
+ std::move(offline_pages_callback).Run(std::vector<OfflinePageItem>());
base::MockCallback<base::OnceCallback<void()>>
mock_initialization_completed_callback;
@@ -262,7 +274,7 @@ TEST_F(PrefetchedPagesTrackerImplTest,
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
first_item.offline_id, kSystemDownloadId, first_item.client_id,
- /*request_origin=*/""));
+ /*request_origin=*/"", first_item.original_url));
// Only one offline page (out of two) has been removed, the remaining one
// should be reported here.
@@ -287,14 +299,14 @@ TEST_F(PrefetchedPagesTrackerImplTest,
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
first_item.offline_id, kSystemDownloadId, first_item.client_id,
- /*request_origin=*/""));
+ /*request_origin=*/"", first_item.original_url));
ASSERT_TRUE(
tracker.PrefetchedOfflinePageExists(GURL("http://prefetched.com")));
tracker.OfflinePageDeleted(offline_pages::OfflinePageModel::DeletedPageInfo(
second_item.offline_id, kSystemDownloadId, second_item.client_id,
- /*request_origin=*/""));
+ /*request_origin=*/"", second_item.original_url));
// All offline pages have been removed, their absence should be reported here.
EXPECT_FALSE(
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
index 118d019e285..868bb0b100e 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestion_unittest.cc
@@ -281,7 +281,6 @@ TEST(RemoteSuggestionTest, ToContentSuggestion) {
EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News")));
EXPECT_THAT(sugg.score(), Eq(9001));
EXPECT_THAT(sugg.download_suggestion_extra(), IsNull());
- EXPECT_THAT(sugg.recent_tab_suggestion_extra(), IsNull());
EXPECT_THAT(sugg.notification_extra(), IsNull());
EXPECT_THAT(sugg.fetch_date(), Eq(fetch_date));
}
@@ -306,7 +305,6 @@ TEST(RemoteSuggestionTest, ToContentSuggestionWithNotificationInfo) {
EXPECT_THAT(sugg.publisher_name(), Eq(base::UTF8ToUTF16("Foo News")));
EXPECT_THAT(sugg.score(), Eq(9001));
EXPECT_THAT(sugg.download_suggestion_extra(), IsNull());
- EXPECT_THAT(sugg.recent_tab_suggestion_extra(), IsNull());
ASSERT_THAT(sugg.notification_extra(), NotNull());
EXPECT_THAT(sugg.notification_extra()->deadline.ToJavaTime(),
Eq(1467291697000));
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index fe213ab6560..16363012725 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -10,7 +10,6 @@
#include "base/containers/circular_deque.h"
#include "base/json/json_reader.h"
-#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
@@ -489,7 +488,7 @@ TEST_F(RemoteSuggestionsFetcherImplTest, ShouldFetchSuccessfullyWhenSignedIn) {
fetcher().FetchSnippets(test_params(),
ToSnippetsAvailableCallback(&mock_callback()));
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
// Wait for the fake response.
@@ -522,7 +521,7 @@ TEST_F(RemoteSuggestionsFetcherImplTest,
fetcher().FetchSnippets(params,
ToSnippetsAvailableCallback(&mock_callback()));
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
// Wait for the fake response.
@@ -550,7 +549,7 @@ TEST_F(RemoteSuggestionsFetcherImplTest,
fetcher().FetchSnippets(params,
ToSnippetsAvailableCallback(&mock_callback()));
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
// Wait for the fake response.
@@ -594,12 +593,12 @@ TEST_F(RemoteSuggestionsFetcherImplTest,
ToSnippetsAvailableCallback(&mock_callback()));
// Cancel the first access token request that's made.
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithError(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(GoogleServiceAuthError::State::REQUEST_CANCELED));
// RemoteSuggestionsFetcher should retry fetching an access token if the first
// attempt is cancelled. Respond with a valid access token on the retry.
- identity_test_env_.WaitForAccessTokenRequestAndRespondWithToken(
+ identity_test_env_.WaitForAccessTokenRequestIfNecessaryAndRespondWithToken(
"access_token", base::Time::Max());
// Wait for the fake response.
diff --git a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
index 1c079450e1b..581c2ac2ebb 100644
--- a/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
+++ b/chromium/components/ntp_snippets/remote/remote_suggestions_scheduler_impl_unittest.cc
@@ -12,7 +12,6 @@
#include "base/command_line.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
diff --git a/chromium/components/ntp_snippets/user_classifier_unittest.cc b/chromium/components/ntp_snippets/user_classifier_unittest.cc
index af5464265eb..2dd874924d9 100644
--- a/chromium/components/ntp_snippets/user_classifier_unittest.cc
+++ b/chromium/components/ntp_snippets/user_classifier_unittest.cc
@@ -143,7 +143,7 @@ class UserClassifierMetricTest
public ::testing::WithParamInterface<
std::pair<UserClassifier::Metric, std::string>> {
public:
- UserClassifierMetricTest() : UserClassifierTest() {}
+ UserClassifierMetricTest() {}
private:
DISALLOW_COPY_AND_ASSIGN(UserClassifierMetricTest);
diff --git a/chromium/components/ntp_snippets_strings_grdp/OWNERS b/chromium/components/ntp_snippets_strings_grdp/OWNERS
new file mode 100644
index 00000000000..c7f9cc3fac0
--- /dev/null
+++ b/chromium/components/ntp_snippets_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/ntp_snippets/OWNERS
diff --git a/chromium/components/ntp_snippets_strings_grdp/README.md b/chromium/components/ntp_snippets_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/ntp_snippets_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl.cc b/chromium/components/ntp_tiles/icon_cacher_impl.cc
index ad8cfdd9300..2b5853e9995 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl.cc
@@ -8,6 +8,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
+#include "components/favicon/core/favicon_server_fetcher_params.h"
#include "components/favicon/core/favicon_service.h"
#include "components/favicon/core/favicon_util.h"
#include "components/favicon/core/large_icon_service.h"
@@ -264,9 +265,10 @@ void IconCacherImpl::OnGetLargeIconOrFallbackStyleFinished(
})");
large_icon_service_
->GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
- page_url,
- GetMinimumFetchingSizeForChromeSuggestionsFaviconsFromServer(),
- GetDesiredFetchingSizeForChromeSuggestionsFaviconsFromServer(),
+ favicon::FaviconServerFetcherParams::CreateForMobile(
+ page_url,
+ GetMinimumFetchingSizeForChromeSuggestionsFaviconsFromServer(),
+ GetDesiredFetchingSizeForChromeSuggestionsFaviconsFromServer()),
/*may_page_url_be_private=*/true, traffic_annotation,
base::Bind(&IconCacherImpl::OnMostLikelyFaviconDownloaded,
weak_ptr_factory_.GetWeakPtr(), page_url));
diff --git a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
index 7e79179659e..3722b859a91 100644
--- a/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
+++ b/chromium/components/ntp_tiles/icon_cacher_impl_unittest.cc
@@ -197,13 +197,13 @@ class IconCacherTestPopularSites : public IconCacherTestBase {
}
base::FilePath pak_path;
#if defined(OS_ANDROID)
- PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &pak_path);
+ base::PathService::Get(ui::DIR_RESOURCE_PAKS_ANDROID, &pak_path);
#else
- PathService::Get(base::DIR_MODULE, &pak_path);
+ base::PathService::Get(base::DIR_MODULE, &pak_path);
#endif
base::FilePath ui_test_pak_path;
- ASSERT_TRUE(PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
+ ASSERT_TRUE(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
diff --git a/chromium/components/ntp_tiles/popular_sites_impl.cc b/chromium/components/ntp_tiles/popular_sites_impl.cc
index b0fb9273834..4282e128d9b 100644
--- a/chromium/components/ntp_tiles/popular_sites_impl.cc
+++ b/chromium/components/ntp_tiles/popular_sites_impl.cc
@@ -33,6 +33,8 @@
#include "net/base/load_flags.h"
#include "net/http/http_status_code.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_request_status.h"
#if defined(OS_ANDROID) || defined(OS_IOS)
#include "base/json/json_reader.h"
diff --git a/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc b/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
index 0bf4831ae36..19eb3721ae2 100644
--- a/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
+++ b/chromium/components/offline_items_collection/core/android/offline_item_bridge.cc
@@ -33,7 +33,7 @@ JNI_OfflineItemBridge_createOfflineItemAndMaybeAddToList(
ConvertUTF8ToJavaString(env, item.title),
ConvertUTF8ToJavaString(env, item.description),
static_cast<jint>(item.filter), item.is_transient, item.is_suggested,
- item.total_size_bytes, item.externally_removed,
+ item.is_accelerated, item.total_size_bytes, item.externally_removed,
item.creation_time.ToJavaTime(), item.last_accessed_time.ToJavaTime(),
item.is_openable, ConvertUTF8ToJavaString(env, item.file_path.value()),
ConvertUTF8ToJavaString(env, item.mime_type),
@@ -43,7 +43,7 @@ JNI_OfflineItemBridge_createOfflineItemAndMaybeAddToList(
static_cast<jint>(item.pending_state), item.is_resumable,
item.allow_metered, item.received_bytes, item.progress.value,
item.progress.max.value_or(-1), static_cast<jint>(item.progress.unit),
- item.time_remaining_ms);
+ item.time_remaining_ms, item.is_dangerous);
}
} // namespace
diff --git a/chromium/components/offline_items_collection/core/offline_item.cc b/chromium/components/offline_items_collection/core/offline_item.cc
index 0b98972ce91..2a31be2cf97 100644
--- a/chromium/components/offline_items_collection/core/offline_item.cc
+++ b/chromium/components/offline_items_collection/core/offline_item.cc
@@ -42,6 +42,7 @@ OfflineItem::OfflineItem()
: filter(OfflineItemFilter::FILTER_OTHER),
is_transient(false),
is_suggested(false),
+ is_accelerated(false),
total_size_bytes(0),
externally_removed(false),
is_openable(false),
@@ -52,7 +53,8 @@ OfflineItem::OfflineItem()
is_resumable(false),
allow_metered(false),
received_bytes(0),
- time_remaining_ms(0) {}
+ time_remaining_ms(0),
+ is_dangerous(false) {}
OfflineItem::OfflineItem(const OfflineItem& other) = default;
@@ -68,6 +70,7 @@ bool OfflineItem::operator==(const OfflineItem& offline_item) const {
filter == offline_item.filter &&
is_transient == offline_item.is_transient &&
is_suggested == offline_item.is_suggested &&
+ is_accelerated == offline_item.is_accelerated &&
total_size_bytes == offline_item.total_size_bytes &&
externally_removed == offline_item.externally_removed &&
creation_time == offline_item.creation_time &&
@@ -84,7 +87,8 @@ bool OfflineItem::operator==(const OfflineItem& offline_item) const {
allow_metered == offline_item.allow_metered &&
received_bytes == offline_item.received_bytes &&
progress == offline_item.progress &&
- time_remaining_ms == offline_item.time_remaining_ms;
+ time_remaining_ms == offline_item.time_remaining_ms &&
+ is_dangerous == offline_item.is_dangerous;
}
OfflineItemVisuals::OfflineItemVisuals() = default;
diff --git a/chromium/components/offline_items_collection/core/offline_item.h b/chromium/components/offline_items_collection/core/offline_item.h
index 9ccb3ef9f68..80aec976f26 100644
--- a/chromium/components/offline_items_collection/core/offline_item.h
+++ b/chromium/components/offline_items_collection/core/offline_item.h
@@ -110,6 +110,9 @@ struct OfflineItem {
// Whether this item should show up as a suggested item for the user.
bool is_suggested;
+ // Whether this item is going through accelerated download.
+ bool is_accelerated;
+
// TODO(dtrainor): Build out custom per-item icon support.
// Content Metadata.
@@ -177,6 +180,10 @@ struct OfflineItem {
// represents an unknown time remaining. This field is not used if |state| is
// COMPLETE.
int64_t time_remaining_ms;
+
+ // Whether the download might be dangerous and will require additional
+ // validation from user.
+ bool is_dangerous;
};
// This struct holds any potentially expensive visuals for an OfflineItem. If
diff --git a/chromium/components/offline_items_collection/core/utilities/file_existence_checker_unittest.cc b/chromium/components/offline_items_collection/core/utilities/file_existence_checker_unittest.cc
index 8d7532c2ca1..c04bdda3820 100644
--- a/chromium/components/offline_items_collection/core/utilities/file_existence_checker_unittest.cc
+++ b/chromium/components/offline_items_collection/core/utilities/file_existence_checker_unittest.cc
@@ -32,7 +32,7 @@ FileIdPairSet CheckForMissingFiles(
set_alias->insert(result.begin(), result.end());
},
&missing_files));
- task_runner.get()->RunUntilIdle();
+ task_runner->RunUntilIdle();
return missing_files;
}
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc b/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc
index 6f8f80cc52b..d59cec9c4f4 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents.cc
@@ -11,8 +11,8 @@ namespace background_loader {
BackgroundLoaderContents::BackgroundLoaderContents(
content::BrowserContext* browser_context)
: browser_context_(browser_context) {
- web_contents_.reset(content::WebContents::Create(
- content::WebContents::CreateParams(browser_context_)));
+ web_contents_ = content::WebContents::Create(
+ content::WebContents::CreateParams(browser_context_));
web_contents_->SetAudioMuted(true);
web_contents_->SetDelegate(this);
}
@@ -88,7 +88,7 @@ bool BackgroundLoaderContents::ShouldCreateWebContents(
void BackgroundLoaderContents::AddNewContents(
content::WebContents* source,
- content::WebContents* new_contents,
+ std::unique_ptr<content::WebContents> new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents.h b/chromium/components/offline_pages/content/background_loader/background_loader_contents.h
index 53863a7bc8f..0cfdf259e46 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents.h
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents.h
@@ -71,7 +71,7 @@ class BackgroundLoaderContents : public content::WebContentsDelegate {
content::SessionStorageNamespace* session_storage_namespace) override;
void AddNewContents(content::WebContents* source,
- content::WebContents* new_contents,
+ std::unique_ptr<content::WebContents> new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents_stub.cc b/chromium/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
index c5df23dfefb..8b828fe5690 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents_stub.cc
@@ -12,11 +12,11 @@ namespace background_loader {
BackgroundLoaderContentsStub::BackgroundLoaderContentsStub(
content::BrowserContext* browser_context)
- : BackgroundLoaderContents(), is_loading_(false) {
- BackgroundLoaderContents::web_contents_.reset(
+ : is_loading_(false) {
+ BackgroundLoaderContents::web_contents_ =
content::WebContentsTester::CreateTestWebContents(browser_context,
- nullptr));
- web_contents_.get()->SetDelegate(this);
+ nullptr);
+ web_contents_->SetDelegate(this);
}
BackgroundLoaderContentsStub::~BackgroundLoaderContentsStub() {}
diff --git a/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc b/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
index 645ecd199c5..6910403a96c 100644
--- a/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
+++ b/chromium/components/offline_pages/content/background_loader/background_loader_contents_unittest.cc
@@ -5,6 +5,7 @@
#include "components/offline_pages/content/background_loader/background_loader_contents.h"
#include "base/synchronization/waitable_event.h"
+#include "content/public/browser/web_contents.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -139,7 +140,8 @@ TEST_F(BackgroundLoaderContentsTest, ShouldNotCreateWebContents) {
TEST_F(BackgroundLoaderContentsTest, ShouldNotAddNewContents) {
bool blocked;
contents()->AddNewContents(
- nullptr /* source */, nullptr /* new_contents */,
+ nullptr /* source */,
+ std::unique_ptr<content::WebContents>() /* new_contents */,
WindowOpenDisposition::CURRENT_TAB /* disposition */,
gfx::Rect() /* initial_rect */, false /* user_gesture */,
&blocked /* was_blocked */);
diff --git a/chromium/components/offline_pages/core/BUILD.gn b/chromium/components/offline_pages/core/BUILD.gn
index bd8d10f9d19..8138618d19e 100644
--- a/chromium/components/offline_pages/core/BUILD.gn
+++ b/chromium/components/offline_pages/core/BUILD.gn
@@ -36,6 +36,8 @@ static_library("core") {
"model/get_pages_task.h",
"model/get_thumbnail_task.cc",
"model/get_thumbnail_task.h",
+ "model/has_thumbnail_task.cc",
+ "model/has_thumbnail_task.h",
"model/mark_page_accessed_task.cc",
"model/mark_page_accessed_task.h",
"model/offline_page_model_taskified.cc",
@@ -116,8 +118,8 @@ static_library("test_support") {
"offline_page_test_archiver.h",
"stub_offline_page_model.cc",
"stub_offline_page_model.h",
- "system_download_manager_stub.cc",
- "system_download_manager_stub.h",
+ "stub_system_download_manager.cc",
+ "stub_system_download_manager.h",
"task_test_base.cc",
"task_test_base.h",
"test_task.cc",
@@ -166,6 +168,7 @@ source_set("unit_tests") {
"model/delete_page_task_unittest.cc",
"model/get_pages_task_unittest.cc",
"model/get_thumbnail_task_unittest.cc",
+ "model/has_thumbnail_task_unittest.cc",
"model/mark_page_accessed_task_unittest.cc",
"model/offline_page_model_taskified_unittest.cc",
"model/offline_page_model_utils_unittest.cc",
@@ -191,7 +194,6 @@ source_set("unit_tests") {
":switches",
":test_support",
"prefetch:unit_tests",
- "recent_tabs:unit_tests",
"renovations:unit_tests",
"//base",
"//base/test:test_support",
diff --git a/chromium/components/offline_pages/core/archive_manager.cc b/chromium/components/offline_pages/core/archive_manager.cc
index 7633809a675..ced20b2279e 100644
--- a/chromium/components/offline_pages/core/archive_manager.cc
+++ b/chromium/components/offline_pages/core/archive_manager.cc
@@ -136,7 +136,7 @@ const base::FilePath& ArchiveManager::GetPrivateArchivesDir() const {
return private_archives_dir_;
}
-const base::FilePath& ArchiveManager::GetPublicArchivesDir() const {
+const base::FilePath& ArchiveManager::GetPublicArchivesDir() {
return public_archives_dir_;
}
diff --git a/chromium/components/offline_pages/core/archive_manager.h b/chromium/components/offline_pages/core/archive_manager.h
index dbb2990f66e..b0ec8fa572c 100644
--- a/chromium/components/offline_pages/core/archive_manager.h
+++ b/chromium/components/offline_pages/core/archive_manager.h
@@ -64,7 +64,7 @@ class ArchiveManager {
// Gets the archive directories.
const base::FilePath& GetTemporaryArchivesDir() const;
const base::FilePath& GetPrivateArchivesDir() const;
- const base::FilePath& GetPublicArchivesDir() const;
+ virtual const base::FilePath& GetPublicArchivesDir();
protected:
// Used for testing.
diff --git a/chromium/components/offline_pages/core/archive_validator_unittest.cc b/chromium/components/offline_pages/core/archive_validator_unittest.cc
index 3841ff9390b..b226a2c777b 100644
--- a/chromium/components/offline_pages/core/archive_validator_unittest.cc
+++ b/chromium/components/offline_pages/core/archive_validator_unittest.cc
@@ -65,7 +65,7 @@ std::string MakeContentOfSize(int size) {
#if defined(OS_ANDROID)
base::FilePath GetContentUriPathForTest() {
base::FilePath test_dir;
- PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &test_dir);
test_dir = test_dir.AppendASCII("net");
test_dir = test_dir.AppendASCII("data");
test_dir = test_dir.AppendASCII("file_stream_unittest");
diff --git a/chromium/components/offline_pages/core/background/add_request_task.cc b/chromium/components/offline_pages/core/background/add_request_task.cc
index 822afcb8b55..e59f363ca46 100644
--- a/chromium/components/offline_pages/core/background/add_request_task.cc
+++ b/chromium/components/offline_pages/core/background/add_request_task.cc
@@ -11,10 +11,10 @@ namespace offline_pages {
AddRequestTask::AddRequestTask(RequestQueueStore* store,
const SavePageRequest& request,
- const RequestQueueStore::AddCallback& callback)
+ RequestQueueStore::AddCallback callback)
: store_(store),
request_(request),
- callback_(callback),
+ callback_(std::move(callback)),
weak_ptr_factory_(this) {}
AddRequestTask::~AddRequestTask() {}
@@ -24,12 +24,13 @@ void AddRequestTask::Run() {
}
void AddRequestTask::AddRequest() {
- store_->AddRequest(request_, base::Bind(&AddRequestTask::CompleteWithResult,
- weak_ptr_factory_.GetWeakPtr()));
+ store_->AddRequest(request_,
+ base::BindOnce(&AddRequestTask::CompleteWithResult,
+ weak_ptr_factory_.GetWeakPtr()));
}
void AddRequestTask::CompleteWithResult(ItemActionStatus status) {
- callback_.Run(status);
+ std::move(callback_).Run(status);
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/background/add_request_task.h b/chromium/components/offline_pages/core/background/add_request_task.h
index 9544f74b8ca..35c80625005 100644
--- a/chromium/components/offline_pages/core/background/add_request_task.h
+++ b/chromium/components/offline_pages/core/background/add_request_task.h
@@ -18,7 +18,7 @@ class AddRequestTask : public Task {
public:
AddRequestTask(RequestQueueStore* store,
const SavePageRequest& request,
- const RequestQueueStore::AddCallback& callback);
+ RequestQueueStore::AddCallback callback);
~AddRequestTask() override;
// Task implementation:
diff --git a/chromium/components/offline_pages/core/background/add_request_task_unittest.cc b/chromium/components/offline_pages/core/background/add_request_task_unittest.cc
index 17b86e19e44..e5e40c5458b 100644
--- a/chromium/components/offline_pages/core/background/add_request_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/add_request_task_unittest.cc
@@ -75,8 +75,8 @@ void AddRequestTaskTest::ClearResults() {
}
void AddRequestTaskTest::InitializeStore(RequestQueueStore* store) {
- store->Initialize(base::Bind(&AddRequestTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store->Initialize(base::BindOnce(&AddRequestTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -101,16 +101,16 @@ TEST_F(AddRequestTaskTest, AddSingleRequest) {
base::Time creation_time = base::Time::Now();
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
- AddRequestTask task(
- &store, request_1,
- base::Bind(&AddRequestTaskTest::AddRequestDone, base::Unretained(this)));
+ AddRequestTask task(&store, request_1,
+ base::BindOnce(&AddRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
EXPECT_EQ(ItemActionStatus::SUCCESS, last_status());
- store.GetRequests(base::Bind(&AddRequestTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store.GetRequests(base::BindOnce(&AddRequestTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, last_requests().size());
EXPECT_EQ(kRequestId1, last_requests().at(0)->request_id());
@@ -126,9 +126,9 @@ TEST_F(AddRequestTaskTest, AddMultipleRequests) {
base::Time creation_time_1 = base::Time::Now();
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time_1,
true);
- AddRequestTask task(
- &store, request_1,
- base::Bind(&AddRequestTaskTest::AddRequestDone, base::Unretained(this)));
+ AddRequestTask task(&store, request_1,
+ base::BindOnce(&AddRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
@@ -138,16 +138,16 @@ TEST_F(AddRequestTaskTest, AddMultipleRequests) {
base::Time creation_time_2 = base::Time::Now();
SavePageRequest request_2(kRequestId2, kUrl2, kClientId2, creation_time_2,
true);
- AddRequestTask task_2(
- &store, request_2,
- base::Bind(&AddRequestTaskTest::AddRequestDone, base::Unretained(this)));
+ AddRequestTask task_2(&store, request_2,
+ base::BindOnce(&AddRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
task_2.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
EXPECT_EQ(ItemActionStatus::SUCCESS, last_status());
- store.GetRequests(base::Bind(&AddRequestTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store.GetRequests(base::BindOnce(&AddRequestTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(2ul, last_requests().size());
int request_2_index =
@@ -166,9 +166,9 @@ TEST_F(AddRequestTaskTest, AddDuplicateRequest) {
base::Time creation_time_1 = base::Time::Now();
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time_1,
true);
- AddRequestTask task(
- &store, request_1,
- base::Bind(&AddRequestTaskTest::AddRequestDone, base::Unretained(this)));
+ AddRequestTask task(&store, request_1,
+ base::BindOnce(&AddRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
@@ -179,16 +179,16 @@ TEST_F(AddRequestTaskTest, AddDuplicateRequest) {
// This was has the same request ID.
SavePageRequest request_2(kRequestId1, kUrl2, kClientId2, creation_time_2,
true);
- AddRequestTask task_2(
- &store, request_2,
- base::Bind(&AddRequestTaskTest::AddRequestDone, base::Unretained(this)));
- task.Run();
+ AddRequestTask task_2(&store, request_2,
+ base::BindOnce(&AddRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ task_2.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
EXPECT_EQ(ItemActionStatus::ALREADY_EXISTS, last_status());
- store.GetRequests(base::Bind(&AddRequestTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store.GetRequests(base::BindOnce(&AddRequestTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, last_requests().size());
}
diff --git a/chromium/components/offline_pages/core/background/change_requests_state_task.cc b/chromium/components/offline_pages/core/background/change_requests_state_task.cc
index 456cb50becc..b3043550d6b 100644
--- a/chromium/components/offline_pages/core/background/change_requests_state_task.cc
+++ b/chromium/components/offline_pages/core/background/change_requests_state_task.cc
@@ -12,11 +12,11 @@ ChangeRequestsStateTask::ChangeRequestsStateTask(
RequestQueueStore* store,
const std::vector<int64_t>& request_ids,
const SavePageRequest::RequestState new_state,
- const RequestQueueStore::UpdateCallback& callback)
+ RequestQueueStore::UpdateCallback callback)
: store_(store),
request_ids_(request_ids.begin(), request_ids.end()),
new_state_(new_state),
- callback_(callback),
+ callback_(std::move(callback)),
weak_ptr_factory_(this) {}
ChangeRequestsStateTask::~ChangeRequestsStateTask() {}
@@ -27,9 +27,9 @@ void ChangeRequestsStateTask::Run() {
void ChangeRequestsStateTask::ReadRequests() {
std::vector<int64_t> request_ids(request_ids_.begin(), request_ids_.end());
- store_->GetRequestsByIds(request_ids,
- base::Bind(&ChangeRequestsStateTask::UpdateRequests,
- weak_ptr_factory_.GetWeakPtr()));
+ store_->GetRequestsByIds(
+ request_ids, base::BindOnce(&ChangeRequestsStateTask::UpdateRequests,
+ weak_ptr_factory_.GetWeakPtr()));
}
void ChangeRequestsStateTask::UpdateRequests(
@@ -54,9 +54,9 @@ void ChangeRequestsStateTask::UpdateRequests(
items_to_update.push_back(request);
}
- store_->UpdateRequests(items_to_update,
- base::Bind(&ChangeRequestsStateTask::UpdateCompleted,
- weak_ptr_factory_.GetWeakPtr()));
+ store_->UpdateRequests(
+ items_to_update, base::BindOnce(&ChangeRequestsStateTask::UpdateCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
}
void ChangeRequestsStateTask::UpdateCompleted(
@@ -76,7 +76,7 @@ void ChangeRequestsStateTask::UpdateCompleted(
std::make_pair(request_id, ItemActionStatus::NOT_FOUND));
}
- callback_.Run(std::move(update_result));
+ std::move(callback_).Run(std::move(update_result));
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/background/change_requests_state_task.h b/chromium/components/offline_pages/core/background/change_requests_state_task.h
index 63544791d2c..2619b124047 100644
--- a/chromium/components/offline_pages/core/background/change_requests_state_task.h
+++ b/chromium/components/offline_pages/core/background/change_requests_state_task.h
@@ -23,7 +23,7 @@ class ChangeRequestsStateTask : public Task {
ChangeRequestsStateTask(RequestQueueStore* store,
const std::vector<int64_t>& request_ids,
const SavePageRequest::RequestState new_state,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~ChangeRequestsStateTask() override;
// TaskQueue::Task implementation.
diff --git a/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc b/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc
index 98826a2a78c..3354e7e52e4 100644
--- a/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/change_requests_state_task_unittest.cc
@@ -58,8 +58,8 @@ void ChangeRequestsStateTaskTest::PumpLoop() {
void ChangeRequestsStateTaskTest::InitializeStore(RequestQueueStore* store) {
store->Initialize(
- base::Bind(&ChangeRequestsStateTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -68,13 +68,13 @@ void ChangeRequestsStateTaskTest::AddItemsToStore(RequestQueueStore* store) {
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
store->AddRequest(request_1,
- base::Bind(&ChangeRequestsStateTaskTest::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::AddRequestDone,
+ base::Unretained(this)));
SavePageRequest request_2(kRequestId2, kUrl2, kClientId2, creation_time,
true);
store->AddRequest(request_2,
- base::Bind(&ChangeRequestsStateTaskTest::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -98,8 +98,8 @@ TEST_F(ChangeRequestsStateTaskTest, UpdateWhenStoreEmpty) {
std::vector<int64_t> request_ids{kRequestId1};
ChangeRequestsStateTask task(
&store, request_ids, SavePageRequest::RequestState::PAUSED,
- base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -118,8 +118,8 @@ TEST_F(ChangeRequestsStateTaskTest, UpdateSingleItem) {
std::vector<int64_t> request_ids{kRequestId1};
ChangeRequestsStateTask task(
&store, request_ids, SavePageRequest::RequestState::PAUSED,
- base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -140,8 +140,8 @@ TEST_F(ChangeRequestsStateTaskTest, UpdateMultipleItems) {
std::vector<int64_t> request_ids{kRequestId1, kRequestId2};
ChangeRequestsStateTask task(
&store, request_ids, SavePageRequest::RequestState::PAUSED,
- base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -179,8 +179,8 @@ TEST_F(ChangeRequestsStateTaskTest, EmptyRequestsList) {
std::vector<int64_t> request_ids;
ChangeRequestsStateTask task(
&store, request_ids, SavePageRequest::RequestState::PAUSED,
- base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -196,8 +196,8 @@ TEST_F(ChangeRequestsStateTaskTest, UpdateMissingItem) {
std::vector<int64_t> request_ids{kRequestId1, kRequestId3};
ChangeRequestsStateTask task(
&store, request_ids, SavePageRequest::RequestState::PAUSED,
- base::Bind(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&ChangeRequestsStateTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
diff --git a/chromium/components/offline_pages/core/background/cleanup_task.cc b/chromium/components/offline_pages/core/background/cleanup_task.cc
index 4bde94370c4..33fad8ba341 100644
--- a/chromium/components/offline_pages/core/background/cleanup_task.cc
+++ b/chromium/components/offline_pages/core/background/cleanup_task.cc
@@ -52,7 +52,7 @@ void CleanupTask::Run() {
void CleanupTask::GetRequests() {
// Get all the requests from the queue, we will classify them in the callback.
store_->GetRequests(
- base::Bind(&CleanupTask::Prune, weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&CleanupTask::Prune, weak_ptr_factory_.GetWeakPtr()));
}
void CleanupTask::Prune(
@@ -77,8 +77,8 @@ void CleanupTask::Prune(
expired_request_ids.push_back(id_reason_pair.first);
store_->RemoveRequests(expired_request_ids,
- base::Bind(&CleanupTask::OnRequestsExpired,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&CleanupTask::OnRequestsExpired,
+ weak_ptr_factory_.GetWeakPtr()));
}
void CleanupTask::OnRequestsExpired(
diff --git a/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc b/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc
index 84529066c87..f58f7607e8f 100644
--- a/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/cleanup_task_unittest.cc
@@ -139,8 +139,8 @@ void CleanupTaskTest::SetUp() {
notifier_.reset(new RequestNotifierStub());
MakeFactoryAndTask();
- store_->Initialize(base::Bind(&CleanupTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store_->Initialize(base::BindOnce(&CleanupTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -164,10 +164,10 @@ void CleanupTaskTest::QueueRequests(const SavePageRequest& request1,
DeviceConditions conditions;
std::set<int64_t> disabled_requests;
// Add test requests on the Queue.
- store_->AddRequest(request1, base::Bind(&CleanupTaskTest::AddRequestDone,
- base::Unretained(this)));
- store_->AddRequest(request2, base::Bind(&CleanupTaskTest::AddRequestDone,
- base::Unretained(this)));
+ store_->AddRequest(request1, base::BindOnce(&CleanupTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ store_->AddRequest(request2, base::BindOnce(&CleanupTaskTest::AddRequestDone,
+ base::Unretained(this)));
// Pump the loop to give the async queue the opportunity to do the adds.
PumpLoop();
@@ -201,8 +201,8 @@ TEST_F(CleanupTaskTest, CleanupExpiredRequest) {
PumpLoop();
// See what is left in the queue, should be just the other request.
- store()->GetRequests(base::Bind(&CleanupTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store()->GetRequests(base::BindOnce(&CleanupTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(1UL, found_requests().size());
EXPECT_EQ(kRequestId1, found_requests().at(0)->request_id());
@@ -223,8 +223,8 @@ TEST_F(CleanupTaskTest, CleanupStartCountExceededRequest) {
PumpLoop();
// See what is left in the queue, should be just the other request.
- store()->GetRequests(base::Bind(&CleanupTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store()->GetRequests(base::BindOnce(&CleanupTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(1UL, found_requests().size());
EXPECT_EQ(kRequestId1, found_requests().at(0)->request_id());
@@ -245,8 +245,8 @@ TEST_F(CleanupTaskTest, CleanupCompletionCountExceededRequest) {
PumpLoop();
// See what is left in the queue, should be just the other request.
- store()->GetRequests(base::Bind(&CleanupTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store()->GetRequests(base::BindOnce(&CleanupTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(1UL, found_requests().size());
EXPECT_EQ(kRequestId1, found_requests().at(0)->request_id());
@@ -272,8 +272,8 @@ TEST_F(CleanupTaskTest, IgnoreRequestInProgress) {
// See what is left in the queue, request1 should be left in the queue even
// though it is expired because it was listed as in-progress while cleaning.
// Request2 should have been cleaned out of the queue.
- store()->GetRequests(base::Bind(&CleanupTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store()->GetRequests(base::BindOnce(&CleanupTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(1UL, found_requests().size());
EXPECT_EQ(kRequestId1, found_requests().at(0)->request_id());
diff --git a/chromium/components/offline_pages/core/background/connection_notifier.cc b/chromium/components/offline_pages/core/background/connection_notifier.cc
index 305e965b142..f2d5fc1f616 100644
--- a/chromium/components/offline_pages/core/background/connection_notifier.cc
+++ b/chromium/components/offline_pages/core/background/connection_notifier.cc
@@ -7,8 +7,8 @@
namespace offline_pages {
ConnectionNotifier::ConnectionNotifier(
- const ConnectionNotifier::ConnectedCallback& callback)
- : callback_(callback) {
+ ConnectionNotifier::ConnectedCallback callback)
+ : callback_(std::move(callback)) {
net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
}
@@ -19,7 +19,7 @@ ConnectionNotifier::~ConnectionNotifier() {
void ConnectionNotifier::OnNetworkChanged(
net::NetworkChangeNotifier::ConnectionType type) {
if (type != net::NetworkChangeNotifier::ConnectionType::CONNECTION_NONE)
- callback_.Run();
+ std::move(callback_).Run();
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background/connection_notifier.h b/chromium/components/offline_pages/core/background/connection_notifier.h
index bcfced8dc55..4edde82e960 100644
--- a/chromium/components/offline_pages/core/background/connection_notifier.h
+++ b/chromium/components/offline_pages/core/background/connection_notifier.h
@@ -14,9 +14,9 @@ class ConnectionNotifier
: public net::NetworkChangeNotifier::NetworkChangeObserver {
public:
// Callback to call when we become connected.
- typedef base::Callback<void()> ConnectedCallback;
+ typedef base::OnceCallback<void()> ConnectedCallback;
- ConnectionNotifier(const ConnectionNotifier::ConnectedCallback& callback);
+ ConnectionNotifier(ConnectionNotifier::ConnectedCallback callback);
~ConnectionNotifier() override;
// net::NetworkChangeNotifier::NetworkChangeObserver implementation.
@@ -24,7 +24,7 @@ class ConnectionNotifier
net::NetworkChangeNotifier::ConnectionType type) override;
private:
- base::Callback<void()> callback_;
+ base::OnceCallback<void()> callback_;
DISALLOW_COPY_AND_ASSIGN(ConnectionNotifier);
};
diff --git a/chromium/components/offline_pages/core/background/get_requests_task.cc b/chromium/components/offline_pages/core/background/get_requests_task.cc
index 9444a3dad11..80a89129e35 100644
--- a/chromium/components/offline_pages/core/background/get_requests_task.cc
+++ b/chromium/components/offline_pages/core/background/get_requests_task.cc
@@ -12,8 +12,8 @@ namespace offline_pages {
GetRequestsTask::GetRequestsTask(
RequestQueueStore* store,
- const RequestQueueStore::GetRequestsCallback& callback)
- : store_(store), callback_(callback), weak_ptr_factory_(this) {}
+ RequestQueueStore::GetRequestsCallback callback)
+ : store_(store), callback_(std::move(callback)), weak_ptr_factory_(this) {}
GetRequestsTask::~GetRequestsTask() {}
@@ -22,14 +22,14 @@ void GetRequestsTask::Run() {
}
void GetRequestsTask::ReadRequest() {
- store_->GetRequests(base::Bind(&GetRequestsTask::CompleteWithResult,
- weak_ptr_factory_.GetWeakPtr()));
+ store_->GetRequests(base::BindOnce(&GetRequestsTask::CompleteWithResult,
+ weak_ptr_factory_.GetWeakPtr()));
}
void GetRequestsTask::CompleteWithResult(
bool success,
std::vector<std::unique_ptr<SavePageRequest>> requests) {
- callback_.Run(success, std::move(requests));
+ std::move(callback_).Run(success, std::move(requests));
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/background/get_requests_task.h b/chromium/components/offline_pages/core/background/get_requests_task.h
index 00333c0894c..ea1b8196d66 100644
--- a/chromium/components/offline_pages/core/background/get_requests_task.h
+++ b/chromium/components/offline_pages/core/background/get_requests_task.h
@@ -17,7 +17,7 @@ namespace offline_pages {
class GetRequestsTask : public Task {
public:
GetRequestsTask(RequestQueueStore* store,
- const RequestQueueStore::GetRequestsCallback& callback);
+ RequestQueueStore::GetRequestsCallback callback);
~GetRequestsTask() override;
// Task implementation:
diff --git a/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc b/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc
index 9ebfa7c9f9c..082cb903655 100644
--- a/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/get_requests_task_unittest.cc
@@ -67,8 +67,8 @@ void GetRequestsTaskTest::PumpLoop() {
}
void GetRequestsTaskTest::InitializeStore(RequestQueueStore* store) {
- store->Initialize(base::Bind(&GetRequestsTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store->Initialize(base::BindOnce(&GetRequestsTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -76,13 +76,15 @@ void GetRequestsTaskTest::AddItemsToStore(RequestQueueStore* store) {
base::Time creation_time = base::Time::Now();
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
- store->AddRequest(request_1, base::Bind(&GetRequestsTaskTest::AddRequestDone,
- base::Unretained(this)));
+ store->AddRequest(request_1,
+ base::BindOnce(&GetRequestsTaskTest::AddRequestDone,
+ base::Unretained(this)));
creation_time = base::Time::Now();
SavePageRequest request_2(kRequestId2, kUrl2, kClientId2, creation_time,
true);
- store->AddRequest(request_2, base::Bind(&GetRequestsTaskTest::AddRequestDone,
- base::Unretained(this)));
+ store->AddRequest(request_2,
+ base::BindOnce(&GetRequestsTaskTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -106,8 +108,8 @@ TEST_F(GetRequestsTaskTest, GetFromEmptyStore) {
RequestQueueInMemoryStore store;
InitializeStore(&store);
GetRequestsTask task(&store,
- base::Bind(&GetRequestsTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&GetRequestsTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
@@ -121,8 +123,8 @@ TEST_F(GetRequestsTaskTest, GetMultipleRequests) {
AddItemsToStore(&store);
GetRequestsTask task(&store,
- base::Bind(&GetRequestsTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&GetRequestsTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
diff --git a/chromium/components/offline_pages/core/background/initialize_store_task.cc b/chromium/components/offline_pages/core/background/initialize_store_task.cc
index 8c680755cf4..7f0d15e8b3a 100644
--- a/chromium/components/offline_pages/core/background/initialize_store_task.cc
+++ b/chromium/components/offline_pages/core/background/initialize_store_task.cc
@@ -12,10 +12,10 @@ const int kRestartAttemptsMaximum = 3;
InitializeStoreTask::InitializeStoreTask(
RequestQueueStore* store,
- const RequestQueueStore::InitializeCallback& callback)
+ RequestQueueStore::InitializeCallback callback)
: store_(store),
reset_attempts_left_(kRestartAttemptsMaximum),
- callback_(callback),
+ callback_(std::move(callback)),
weak_ptr_factory_(this) {}
InitializeStoreTask::~InitializeStoreTask() {}
@@ -25,13 +25,13 @@ void InitializeStoreTask::Run() {
}
void InitializeStoreTask::InitializeStore() {
- store_->Initialize(base::Bind(&InitializeStoreTask::CompleteIfSuccessful,
- weak_ptr_factory_.GetWeakPtr()));
+ store_->Initialize(base::BindOnce(&InitializeStoreTask::CompleteIfSuccessful,
+ weak_ptr_factory_.GetWeakPtr()));
}
void InitializeStoreTask::CompleteIfSuccessful(bool success) {
if (success) {
- callback_.Run(true);
+ std::move(callback_).Run(true);
TaskComplete();
return;
}
@@ -41,14 +41,14 @@ void InitializeStoreTask::CompleteIfSuccessful(bool success) {
void InitializeStoreTask::TryToResetStore() {
if (reset_attempts_left_ == 0) {
- callback_.Run(false);
+ std::move(callback_).Run(false);
TaskComplete();
return;
}
reset_attempts_left_--;
- store_->Reset(base::Bind(&InitializeStoreTask::OnStoreResetDone,
- weak_ptr_factory_.GetWeakPtr()));
+ store_->Reset(base::BindOnce(&InitializeStoreTask::OnStoreResetDone,
+ weak_ptr_factory_.GetWeakPtr()));
}
void InitializeStoreTask::OnStoreResetDone(bool success) {
diff --git a/chromium/components/offline_pages/core/background/initialize_store_task.h b/chromium/components/offline_pages/core/background/initialize_store_task.h
index 0cceee8ae8a..4e17370a5cd 100644
--- a/chromium/components/offline_pages/core/background/initialize_store_task.h
+++ b/chromium/components/offline_pages/core/background/initialize_store_task.h
@@ -25,7 +25,7 @@ namespace offline_pages {
class InitializeStoreTask : public Task {
public:
InitializeStoreTask(RequestQueueStore* store,
- const RequestQueueStore::InitializeCallback& callback);
+ RequestQueueStore::InitializeCallback callback);
~InitializeStoreTask() override;
// TaskQueue::Task implementation.
diff --git a/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc b/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc
index c016b73e7c3..8e14188b6f4 100644
--- a/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/initialize_store_task_unittest.cc
@@ -64,8 +64,8 @@ void InitializeStoreTaskTest::InitializeCallback(bool success) {
TEST_F(InitializeStoreTaskTest, SuccessfulInitialization) {
RequestQueueInMemoryStore store;
InitializeStoreTask task(
- &store, base::Bind(&InitializeStoreTaskTest::InitializeCallback,
- base::Unretained(this)));
+ &store, base::BindOnce(&InitializeStoreTaskTest::InitializeCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
@@ -76,8 +76,8 @@ TEST_F(InitializeStoreTaskTest, SuccessfulInitialization) {
TEST_F(InitializeStoreTaskTest, SuccessfulReset) {
RequestQueueInMemoryStore store(TestScenario::LOAD_FAILED_RESET_SUCCESS);
InitializeStoreTask task(
- &store, base::Bind(&InitializeStoreTaskTest::InitializeCallback,
- base::Unretained(this)));
+ &store, base::BindOnce(&InitializeStoreTaskTest::InitializeCallback,
+ base::Unretained(this)));
task.Run();
EXPECT_FALSE(callback_called());
EXPECT_EQ(StoreState::FAILED_LOADING, store.state());
@@ -95,8 +95,8 @@ TEST_F(InitializeStoreTaskTest, SuccessfulReset) {
TEST_F(InitializeStoreTaskTest, FailedReset) {
RequestQueueInMemoryStore store(TestScenario::LOAD_FAILED_RESET_FAILED);
InitializeStoreTask task(
- &store, base::Bind(&InitializeStoreTaskTest::InitializeCallback,
- base::Unretained(this)));
+ &store, base::BindOnce(&InitializeStoreTaskTest::InitializeCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
EXPECT_TRUE(callback_called());
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.cc b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.cc
index 007dfa2aa58..9fa6c68b53b 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.cc
@@ -11,8 +11,8 @@ namespace offline_pages {
MarkAttemptAbortedTask::MarkAttemptAbortedTask(
RequestQueueStore* store,
int64_t request_id,
- const RequestQueueStore::UpdateCallback& callback)
- : UpdateRequestTask(store, request_id, callback) {}
+ RequestQueueStore::UpdateCallback callback)
+ : UpdateRequestTask(store, request_id, std::move(callback)) {}
MarkAttemptAbortedTask::~MarkAttemptAbortedTask() {}
@@ -28,7 +28,8 @@ void MarkAttemptAbortedTask::UpdateRequestImpl(
read_result->updated_items[0].MarkAttemptAborted();
store()->UpdateRequests(
read_result->updated_items,
- base::Bind(&MarkAttemptAbortedTask::CompleteWithResult, GetWeakPtr()));
+ base::BindOnce(&MarkAttemptAbortedTask::CompleteWithResult,
+ GetWeakPtr()));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.h b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.h
index 4deb15ff921..10c1d2ab6e3 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.h
+++ b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task.h
@@ -18,7 +18,7 @@ class MarkAttemptAbortedTask : public UpdateRequestTask {
public:
MarkAttemptAbortedTask(RequestQueueStore* store,
int64_t request_id,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~MarkAttemptAbortedTask() override;
protected:
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc
index bc15169e305..58f017bd982 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_aborted_task_unittest.cc
@@ -58,8 +58,9 @@ void MarkAttemptAbortedTaskTest::PumpLoop() {
}
void MarkAttemptAbortedTaskTest::InitializeStore(RequestQueueStore* store) {
- store->Initialize(base::Bind(&MarkAttemptAbortedTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store->Initialize(
+ base::BindOnce(&MarkAttemptAbortedTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -68,8 +69,8 @@ void MarkAttemptAbortedTaskTest::AddItemToStore(RequestQueueStore* store) {
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
store->AddRequest(request_1,
- base::Bind(&MarkAttemptAbortedTaskTest::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -96,8 +97,8 @@ TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenStoreEmpty) {
MarkAttemptAbortedTask task(
&store, kRequestId1,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -116,16 +117,16 @@ TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenExists) {
// First mark attempt started.
MarkAttemptStartedTask start_request_task(
&store, kRequestId1,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
start_request_task.Run();
PumpLoop();
ClearResults();
MarkAttemptAbortedTask task(
&store, kRequestId1,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
@@ -146,8 +147,8 @@ TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenItemMissing) {
MarkAttemptAbortedTask task(
&store, kRequestId2,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -166,8 +167,8 @@ TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenPaused) {
// First mark attempt started.
MarkAttemptStartedTask start_request_task(
&store, kRequestId1,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
start_request_task.Run();
PumpLoop();
ClearResults();
@@ -177,16 +178,16 @@ TEST_F(MarkAttemptAbortedTaskTest, MarkAttemptAbortedWhenPaused) {
requests.push_back(kRequestId1);
ChangeRequestsStateTask pauseTask(
&store, requests, SavePageRequest::RequestState::PAUSED,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
pauseTask.Run();
PumpLoop();
// Abort the task, the state should not change from PAUSED.
MarkAttemptAbortedTask abortTask(
&store, kRequestId1,
- base::Bind(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptAbortedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
abortTask.Run();
PumpLoop();
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_completed_task.cc b/chromium/components/offline_pages/core/background/mark_attempt_completed_task.cc
index e9a4ae1fdf4..348970df433 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_completed_task.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_completed_task.cc
@@ -15,8 +15,9 @@ MarkAttemptCompletedTask::MarkAttemptCompletedTask(
RequestQueueStore* store,
int64_t request_id,
FailState fail_state,
- const RequestQueueStore::UpdateCallback& callback)
- : UpdateRequestTask(store, request_id, callback), fail_state_(fail_state) {}
+ RequestQueueStore::UpdateCallback callback)
+ : UpdateRequestTask(store, request_id, std::move(callback)),
+ fail_state_(fail_state) {}
MarkAttemptCompletedTask::~MarkAttemptCompletedTask() {}
@@ -32,7 +33,8 @@ void MarkAttemptCompletedTask::UpdateRequestImpl(
read_result->updated_items[0].MarkAttemptCompleted(fail_state_);
store()->UpdateRequests(
read_result->updated_items,
- base::Bind(&MarkAttemptCompletedTask::CompleteWithResult, GetWeakPtr()));
+ base::BindOnce(&MarkAttemptCompletedTask::CompleteWithResult,
+ GetWeakPtr()));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_completed_task.h b/chromium/components/offline_pages/core/background/mark_attempt_completed_task.h
index 712aa905ee5..50a4a4485aa 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_completed_task.h
+++ b/chromium/components/offline_pages/core/background/mark_attempt_completed_task.h
@@ -22,7 +22,7 @@ class MarkAttemptCompletedTask : public UpdateRequestTask {
MarkAttemptCompletedTask(RequestQueueStore* store,
int64_t request_id,
FailState fail_state,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~MarkAttemptCompletedTask() override;
protected:
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc b/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc
index 766ac641831..441a178b3fb 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_completed_task_unittest.cc
@@ -56,8 +56,8 @@ void MarkAttemptCompletedTaskTest::PumpLoop() {
void MarkAttemptCompletedTaskTest::InitializeStore(RequestQueueStore* store) {
store->Initialize(
- base::Bind(&MarkAttemptCompletedTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptCompletedTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -67,9 +67,9 @@ void MarkAttemptCompletedTaskTest::AddStartedItemToStore(
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
request_1.MarkAttemptStarted(base::Time::Now());
- store->AddRequest(request_1,
- base::Bind(&MarkAttemptCompletedTaskTest::AddRequestDone,
- base::Unretained(this)));
+ store->AddRequest(
+ request_1, base::BindOnce(&MarkAttemptCompletedTaskTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -93,8 +93,8 @@ TEST_F(MarkAttemptCompletedTaskTest, MarkAttemptCompletedWhenExists) {
MarkAttemptCompletedTask task(
&store, kRequestId1, FailState::CANNOT_DOWNLOAD,
- base::Bind(&MarkAttemptCompletedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptCompletedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
@@ -117,8 +117,8 @@ TEST_F(MarkAttemptCompletedTaskTest, MarkAttemptCompletedWhenItemMissing) {
// Try to mark request 2 (not in the store).
MarkAttemptCompletedTask task(
&store, kRequestId2, FailState::CANNOT_DOWNLOAD,
- base::Bind(&MarkAttemptCompletedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptCompletedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_started_task.cc b/chromium/components/offline_pages/core/background/mark_attempt_started_task.cc
index 429b67a6315..f6228ccff7c 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_started_task.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_started_task.cc
@@ -14,8 +14,8 @@ namespace offline_pages {
MarkAttemptStartedTask::MarkAttemptStartedTask(
RequestQueueStore* store,
int64_t request_id,
- const RequestQueueStore::UpdateCallback& callback)
- : UpdateRequestTask(store, request_id, callback) {}
+ RequestQueueStore::UpdateCallback callback)
+ : UpdateRequestTask(store, request_id, std::move(callback)) {}
MarkAttemptStartedTask::~MarkAttemptStartedTask() {}
@@ -31,7 +31,8 @@ void MarkAttemptStartedTask::UpdateRequestImpl(
read_result->updated_items[0].MarkAttemptStarted(base::Time::Now());
store()->UpdateRequests(
read_result->updated_items,
- base::Bind(&MarkAttemptStartedTask::CompleteWithResult, GetWeakPtr()));
+ base::BindOnce(&MarkAttemptStartedTask::CompleteWithResult,
+ GetWeakPtr()));
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_started_task.h b/chromium/components/offline_pages/core/background/mark_attempt_started_task.h
index 93673a949e5..52a44b05461 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_started_task.h
+++ b/chromium/components/offline_pages/core/background/mark_attempt_started_task.h
@@ -18,7 +18,7 @@ class MarkAttemptStartedTask : public UpdateRequestTask {
public:
MarkAttemptStartedTask(RequestQueueStore* store,
int64_t request_id,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~MarkAttemptStartedTask() override;
protected:
diff --git a/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc b/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc
index 17da2ca901f..902fe50ce6f 100644
--- a/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/mark_attempt_started_task_unittest.cc
@@ -54,8 +54,9 @@ void MarkAttemptStartedTaskTest::PumpLoop() {
}
void MarkAttemptStartedTaskTest::InitializeStore(RequestQueueStore* store) {
- store->Initialize(base::Bind(&MarkAttemptStartedTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store->Initialize(
+ base::BindOnce(&MarkAttemptStartedTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -64,8 +65,8 @@ void MarkAttemptStartedTaskTest::AddItemToStore(RequestQueueStore* store) {
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
store->AddRequest(request_1,
- base::Bind(&MarkAttemptStartedTaskTest::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptStartedTaskTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -88,8 +89,8 @@ TEST_F(MarkAttemptStartedTaskTest, MarkAttemptStartedWhenStoreEmpty) {
MarkAttemptStartedTask task(
&store, kRequestId1,
- base::Bind(&MarkAttemptStartedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptStartedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -107,8 +108,8 @@ TEST_F(MarkAttemptStartedTaskTest, MarkAttemptStartedWhenExists) {
MarkAttemptStartedTask task(
&store, kRequestId1,
- base::Bind(&MarkAttemptStartedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptStartedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
// Current time for verification.
base::Time before_time = base::Time::Now();
@@ -136,8 +137,8 @@ TEST_F(MarkAttemptStartedTaskTest, MarkAttemptStartedWhenItemMissing) {
MarkAttemptStartedTask task(
&store, kRequestId2,
- base::Bind(&MarkAttemptStartedTaskTest::ChangeRequestsStateCallback,
- base::Unretained(this)));
+ base::BindOnce(&MarkAttemptStartedTaskTest::ChangeRequestsStateCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
diff --git a/chromium/components/offline_pages/core/background/offliner.h b/chromium/components/offline_pages/core/background/offliner.h
index 76a40e23fa0..d7121633bb8 100644
--- a/chromium/components/offline_pages/core/background/offliner.h
+++ b/chromium/components/offline_pages/core/background/offliner.h
@@ -80,14 +80,15 @@ class Offliner {
};
// Reports the load progress of a request.
- typedef base::Callback<void(const SavePageRequest&, int64_t received_bytes)>
+ typedef base::RepeatingCallback<void(const SavePageRequest&,
+ int64_t received_bytes)>
ProgressCallback;
// Reports the completion status of a request.
- typedef base::Callback<void(const SavePageRequest&, RequestStatus)>
+ typedef base::OnceCallback<void(const SavePageRequest&, RequestStatus)>
CompletionCallback;
// Reports that the cancel operation has completed.
// TODO(chili): make save operation cancellable.
- typedef base::Callback<void(const SavePageRequest&)> CancelCallback;
+ typedef base::OnceCallback<void(const SavePageRequest&)> CancelCallback;
Offliner() {}
virtual ~Offliner() {}
@@ -98,13 +99,13 @@ class Offliner {
// called on it. |progress_callback| is invoked periodically to report the
// number of bytes received from the network (for UI purposes).
virtual bool LoadAndSave(const SavePageRequest& request,
- const CompletionCallback& completion_callback,
+ CompletionCallback completion_callback,
const ProgressCallback& progress_callback) = 0;
// Clears the currently processing request, if any, and skips running its
// CompletionCallback. Returns false if there is nothing to cancel, otherwise
// returns true and canceled request will be delivered using callback.
- virtual bool Cancel(const CancelCallback& callback) = 0;
+ virtual bool Cancel(CancelCallback callback) = 0;
// On some external condition changes (RAM pressure, browser backgrounded on
// low-level devices, etc) it is needed to terminate a load if there is one
diff --git a/chromium/components/offline_pages/core/background/offliner_stub.cc b/chromium/components/offline_pages/core/background/offliner_stub.cc
index 92518428923..4e0b9050d83 100644
--- a/chromium/components/offline_pages/core/background/offliner_stub.cc
+++ b/chromium/components/offline_pages/core/background/offliner_stub.cc
@@ -19,49 +19,52 @@ OfflinerStub::OfflinerStub()
OfflinerStub::~OfflinerStub() {}
bool OfflinerStub::LoadAndSave(const SavePageRequest& request,
- const CompletionCallback& completion_callback,
+ CompletionCallback completion_callback,
const ProgressCallback& progress_callback) {
if (disable_loading_)
return false;
pending_request_.reset(new SavePageRequest(request));
- completion_callback_ = completion_callback;
+ completion_callback_ = std::move(completion_callback);
// Post the callback on the run loop.
if (enable_callback_) {
const int64_t arbitrary_size = 153LL;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(progress_callback, request, arbitrary_size));
+ FROM_HERE, base::BindOnce(progress_callback, request, arbitrary_size));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(completion_callback, *pending_request_.get(),
- Offliner::RequestStatus::SAVED));
+ FROM_HERE,
+ base::BindOnce(std::move(completion_callback_), *pending_request_,
+ Offliner::RequestStatus::SAVED));
}
return true;
}
-bool OfflinerStub::Cancel(const CancelCallback& callback) {
+bool OfflinerStub::Cancel(CancelCallback callback) {
cancel_called_ = true;
if (!pending_request_)
return false;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, *pending_request_.get()));
+ FROM_HERE, base::BindOnce(std::move(callback), *pending_request_));
pending_request_.reset();
return true;
}
void OfflinerStub::TerminateLoadIfInProgress() {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(completion_callback_, *pending_request_.get(),
- Offliner::RequestStatus::FOREGROUND_CANCELED));
+ FROM_HERE,
+ base::BindOnce(std::move(completion_callback_), *pending_request_,
+ Offliner::RequestStatus::FOREGROUND_CANCELED));
pending_request_.reset();
}
bool OfflinerStub::HandleTimeout(int64_t request_id) {
if (snapshot_on_last_retry_) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(completion_callback_, *pending_request_.get(),
- Offliner::RequestStatus::SAVED));
+ FROM_HERE,
+ base::BindOnce(std::move(completion_callback_), *pending_request_,
+ Offliner::RequestStatus::SAVED));
pending_request_.reset();
return true;
}
diff --git a/chromium/components/offline_pages/core/background/offliner_stub.h b/chromium/components/offline_pages/core/background/offliner_stub.h
index a4485990b82..6472058acc5 100644
--- a/chromium/components/offline_pages/core/background/offliner_stub.h
+++ b/chromium/components/offline_pages/core/background/offliner_stub.h
@@ -20,10 +20,10 @@ class OfflinerStub : public Offliner {
~OfflinerStub() override;
bool LoadAndSave(const SavePageRequest& request,
- const CompletionCallback& completion_callback,
+ CompletionCallback completion_callback,
const ProgressCallback& progress_callback) override;
- bool Cancel(const CancelCallback& callback) override;
+ bool Cancel(CancelCallback callback) override;
void TerminateLoadIfInProgress() override;
diff --git a/chromium/components/offline_pages/core/background/pending_state_updater.cc b/chromium/components/offline_pages/core/background/pending_state_updater.cc
index b581a6dfa64..bf2e70acc09 100644
--- a/chromium/components/offline_pages/core/background/pending_state_updater.cc
+++ b/chromium/components/offline_pages/core/background/pending_state_updater.cc
@@ -20,8 +20,8 @@ PendingStateUpdater::~PendingStateUpdater() {}
void PendingStateUpdater::UpdateRequestsOnLossOfNetwork() {
requests_pending_another_download_ = false;
request_coordinator_->GetAllRequests(
- base::Bind(&PendingStateUpdater::NotifyChangedPendingStates,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&PendingStateUpdater::NotifyChangedPendingStates,
+ weak_ptr_factory_.GetWeakPtr()));
}
void PendingStateUpdater::UpdateRequestsOnRequestPicked(
diff --git a/chromium/components/offline_pages/core/background/pick_request_task.cc b/chromium/components/offline_pages/core/background/pick_request_task.cc
index 6dfe09770d2..bf126b6dbfd 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task.cc
+++ b/chromium/components/offline_pages/core/background/pick_request_task.cc
@@ -42,9 +42,9 @@ PickRequestTask::PickRequestTask(
base::circular_deque<int64_t>& prioritized_requests)
: store_(store),
policy_(policy),
- picked_callback_(picked_callback),
- not_picked_callback_(not_picked_callback),
- request_count_callback_(request_count_callback),
+ picked_callback_(std::move(picked_callback)),
+ not_picked_callback_(std::move(not_picked_callback)),
+ request_count_callback_(std::move(request_count_callback)),
disabled_requests_(disabled_requests),
prioritized_requests_(prioritized_requests),
weak_ptr_factory_(this) {
@@ -60,7 +60,7 @@ void PickRequestTask::Run() {
void PickRequestTask::GetRequests() {
// Get all the requests from the queue, we will classify them in the callback.
store_->GetRequests(
- base::Bind(&PickRequestTask::Choose, weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&PickRequestTask::Choose, weak_ptr_factory_.GetWeakPtr()));
}
void PickRequestTask::Choose(
@@ -68,8 +68,9 @@ void PickRequestTask::Choose(
std::vector<std::unique_ptr<SavePageRequest>> requests) {
// If there is nothing to do, return right away.
if (requests.empty()) {
- request_count_callback_.Run(requests.size(), 0);
- not_picked_callback_.Run(!kNonUserRequestsFound, !kCleanupNeeded);
+ std::move(request_count_callback_).Run(requests.size(), 0);
+ std::move(not_picked_callback_)
+ .Run(!kNonUserRequestsFound, !kCleanupNeeded);
TaskComplete();
return;
}
@@ -126,7 +127,8 @@ void PickRequestTask::Choose(
available_request_ids.insert(request->request_id());
}
// Report the request queue counts.
- request_count_callback_.Run(total_request_count, available_requests->size());
+ std::move(request_count_callback_)
+ .Run(total_request_count, available_requests->size());
// Search for and pick the prioritized request which is available for picking
// from |available_request_ids|, the closer to the end means higher priority.
@@ -163,11 +165,11 @@ void PickRequestTask::Choose(
// If we have a best request to try next, get the request coodinator to
// start it. Otherwise return that we have no candidates.
if (picked_request != nullptr) {
- picked_callback_.Run(*picked_request, std::move(available_requests),
- cleanup_needed);
+ std::move(picked_callback_)
+ .Run(*picked_request, std::move(available_requests), cleanup_needed);
} else {
- not_picked_callback_.Run(non_user_requested_tasks_remaining,
- cleanup_needed);
+ std::move(not_picked_callback_)
+ .Run(non_user_requested_tasks_remaining, cleanup_needed);
}
TaskComplete();
diff --git a/chromium/components/offline_pages/core/background/pick_request_task.h b/chromium/components/offline_pages/core/background/pick_request_task.h
index 14c22ceb07f..ed0470d8498 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task.h
+++ b/chromium/components/offline_pages/core/background/pick_request_task.h
@@ -27,18 +27,18 @@ typedef bool (PickRequestTask::*RequestCompareFunction)(
class PickRequestTask : public Task {
public:
// Callback to report when a request was available.
- typedef base::Callback<void(
+ typedef base::OnceCallback<void(
const SavePageRequest& request,
std::unique_ptr<std::vector<SavePageRequest>> available_requests,
bool cleanup_needed)>
RequestPickedCallback;
// Callback to report when no request was available.
- typedef base::Callback<void(bool non_user_requests, bool cleanup_needed)>
+ typedef base::OnceCallback<void(bool non_user_requests, bool cleanup_needed)>
RequestNotPickedCallback;
// Callback to report available total and available queued request counts.
- typedef base::Callback<void(size_t, size_t)> RequestCountCallback;
+ typedef base::OnceCallback<void(size_t, size_t)> RequestCountCallback;
PickRequestTask(RequestQueueStore* store,
OfflinerPolicy* policy,
diff --git a/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc b/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
index 4a67fd5c65a..a84c2758233 100644
--- a/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/pick_request_task_unittest.cc
@@ -163,8 +163,8 @@ void PickRequestTaskTest::SetUp() {
last_picked_.reset();
cleanup_needed_ = false;
- store_->Initialize(base::Bind(&PickRequestTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store_->Initialize(base::BindOnce(&PickRequestTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -204,10 +204,12 @@ void PickRequestTaskTest::QueueRequests(const SavePageRequest& request1,
DeviceConditions conditions;
std::set<int64_t> disabled_requests;
// Add test requests on the Queue.
- store_->AddRequest(request1, base::Bind(&PickRequestTaskTest::AddRequestDone,
- base::Unretained(this)));
- store_->AddRequest(request2, base::Bind(&PickRequestTaskTest::AddRequestDone,
- base::Unretained(this)));
+ store_->AddRequest(request1,
+ base::BindOnce(&PickRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ store_->AddRequest(request2,
+ base::BindOnce(&PickRequestTaskTest::AddRequestDone,
+ base::Unretained(this)));
// Pump the loop to give the async queue the opportunity to do the adds.
PumpLoop();
@@ -217,16 +219,17 @@ void PickRequestTaskTest::MakePickRequestTask() {
DeviceConditions conditions;
task_.reset(new PickRequestTask(
store_.get(), policy_.get(),
- base::Bind(&PickRequestTaskTest::RequestPicked, base::Unretained(this)),
- base::Bind(&PickRequestTaskTest::RequestNotPicked,
- base::Unretained(this)),
- base::Bind(&PickRequestTaskTest::RequestCountCallback,
- base::Unretained(this)),
+ base::BindOnce(&PickRequestTaskTest::RequestPicked,
+ base::Unretained(this)),
+ base::BindOnce(&PickRequestTaskTest::RequestNotPicked,
+ base::Unretained(this)),
+ base::BindOnce(&PickRequestTaskTest::RequestCountCallback,
+ base::Unretained(this)),
conditions, disabled_requests_, prioritized_requests_));
task_->SetTaskCompletionCallbackForTesting(
task_runner_.get(),
- base::Bind(&PickRequestTaskTest::TaskCompletionCallback,
- base::Unretained(this)));
+ base::BindRepeating(&PickRequestTaskTest::TaskCompletionCallback,
+ base::Unretained(this)));
}
void PickRequestTaskTest::InitializeStoreDone(bool success) {
diff --git a/chromium/components/offline_pages/core/background/reconcile_task.cc b/chromium/components/offline_pages/core/background/reconcile_task.cc
index 66833e859e4..f1774344c51 100644
--- a/chromium/components/offline_pages/core/background/reconcile_task.cc
+++ b/chromium/components/offline_pages/core/background/reconcile_task.cc
@@ -15,8 +15,8 @@
namespace offline_pages {
ReconcileTask::ReconcileTask(RequestQueueStore* store,
- const RequestQueueStore::UpdateCallback& callback)
- : store_(store), callback_(callback), weak_ptr_factory_(this) {}
+ RequestQueueStore::UpdateCallback callback)
+ : store_(store), callback_(std::move(callback)), weak_ptr_factory_(this) {}
ReconcileTask::~ReconcileTask() {}
@@ -27,8 +27,8 @@ void ReconcileTask::Run() {
void ReconcileTask::GetRequests() {
// Get all the requests from the queue, we will reconcile them in the
// callback.
- store_->GetRequests(
- base::Bind(&ReconcileTask::Reconcile, weak_ptr_factory_.GetWeakPtr()));
+ store_->GetRequests(base::BindOnce(&ReconcileTask::Reconcile,
+ weak_ptr_factory_.GetWeakPtr()));
}
void ReconcileTask::Reconcile(
@@ -47,7 +47,7 @@ void ReconcileTask::Reconcile(
for (auto& request : requests) {
if (request->request_state() == SavePageRequest::RequestState::OFFLINING) {
request->set_request_state(SavePageRequest::RequestState::AVAILABLE);
- items_to_update.push_back(*request.get());
+ items_to_update.push_back(*request);
}
}
@@ -59,14 +59,14 @@ void ReconcileTask::Reconcile(
}
store_->UpdateRequests(items_to_update,
- base::Bind(&ReconcileTask::UpdateCompleted,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&ReconcileTask::UpdateCompleted,
+ weak_ptr_factory_.GetWeakPtr()));
}
void ReconcileTask::UpdateCompleted(
std::unique_ptr<UpdateRequestsResult> update_result) {
// Send a notification to the UI that these items have updated.
- callback_.Run(std::move(update_result));
+ std::move(callback_).Run(std::move(update_result));
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/background/reconcile_task.h b/chromium/components/offline_pages/core/background/reconcile_task.h
index f03b31fa3be..e5b30791eb2 100644
--- a/chromium/components/offline_pages/core/background/reconcile_task.h
+++ b/chromium/components/offline_pages/core/background/reconcile_task.h
@@ -21,7 +21,7 @@ namespace offline_pages {
class ReconcileTask : public Task {
public:
ReconcileTask(RequestQueueStore* store,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~ReconcileTask() override;
// TaskQueue::Task implementation:
diff --git a/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc b/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc
index e587723a0e4..e1e918539a7 100644
--- a/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/reconcile_task_unittest.cc
@@ -92,8 +92,8 @@ void ReconcileTaskTest::SetUp() {
store_.reset(new RequestQueueInMemoryStore());
MakeTask();
- store_->Initialize(base::Bind(&ReconcileTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store_->Initialize(base::BindOnce(&ReconcileTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -125,10 +125,12 @@ void ReconcileTaskTest::QueueRequests(const SavePageRequest& request1,
DeviceConditions conditions;
std::set<int64_t> disabled_requests;
// Add test requests on the Queue.
- store_->AddRequest(request1, base::Bind(&ReconcileTaskTest::AddRequestDone,
- base::Unretained(this)));
- store_->AddRequest(request2, base::Bind(&ReconcileTaskTest::AddRequestDone,
- base::Unretained(this)));
+ store_->AddRequest(request1,
+ base::BindOnce(&ReconcileTaskTest::AddRequestDone,
+ base::Unretained(this)));
+ store_->AddRequest(request2,
+ base::BindOnce(&ReconcileTaskTest::AddRequestDone,
+ base::Unretained(this)));
// Pump the loop to give the async queue the opportunity to do the adds.
PumpLoop();
@@ -136,8 +138,8 @@ void ReconcileTaskTest::QueueRequests(const SavePageRequest& request1,
void ReconcileTaskTest::MakeTask() {
task_.reset(new ReconcileTask(
- store_.get(), base::Bind(&ReconcileTaskTest::ReconcileCallback,
- base::Unretained(this))));
+ store_.get(), base::BindOnce(&ReconcileTaskTest::ReconcileCallback,
+ base::Unretained(this))));
}
void ReconcileTaskTest::InitializeStoreDone(bool success) {
@@ -160,8 +162,8 @@ TEST_F(ReconcileTaskTest, Reconcile) {
PumpLoop();
// See what is left in the queue, should be just the other request.
- store()->GetRequests(base::Bind(&ReconcileTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store()->GetRequests(base::BindOnce(&ReconcileTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(2UL, found_requests().size());
@@ -195,8 +197,8 @@ TEST_F(ReconcileTaskTest, NothingToReconcile) {
PumpLoop();
// See what is left in the queue, should be just the other request.
- store()->GetRequests(base::Bind(&ReconcileTaskTest::GetRequestsCallback,
- base::Unretained(this)));
+ store()->GetRequests(base::BindOnce(&ReconcileTaskTest::GetRequestsCallback,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(2UL, found_requests().size());
diff --git a/chromium/components/offline_pages/core/background/remove_requests_task.cc b/chromium/components/offline_pages/core/background/remove_requests_task.cc
index a18d31aeed5..5ba9c72d209 100644
--- a/chromium/components/offline_pages/core/background/remove_requests_task.cc
+++ b/chromium/components/offline_pages/core/background/remove_requests_task.cc
@@ -11,10 +11,10 @@ namespace offline_pages {
RemoveRequestsTask::RemoveRequestsTask(
RequestQueueStore* store,
const std::vector<int64_t>& request_ids,
- const RequestQueueStore::UpdateCallback& callback)
+ RequestQueueStore::UpdateCallback callback)
: store_(store),
request_ids_(request_ids),
- callback_(callback),
+ callback_(std::move(callback)),
weak_ptr_factory_(this) {}
RemoveRequestsTask::~RemoveRequestsTask() {}
@@ -30,8 +30,8 @@ void RemoveRequestsTask::RemoveRequests() {
}
store_->RemoveRequests(request_ids_,
- base::Bind(&RemoveRequestsTask::CompleteWithResult,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&RemoveRequestsTask::CompleteWithResult,
+ weak_ptr_factory_.GetWeakPtr()));
}
void RemoveRequestsTask::CompleteEarly(ItemActionStatus status) {
@@ -44,7 +44,7 @@ void RemoveRequestsTask::CompleteEarly(ItemActionStatus status) {
void RemoveRequestsTask::CompleteWithResult(
std::unique_ptr<UpdateRequestsResult> result) {
- callback_.Run(std::move(result));
+ std::move(callback_).Run(std::move(result));
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/background/remove_requests_task.h b/chromium/components/offline_pages/core/background/remove_requests_task.h
index 19b55438660..655cd5cdc88 100644
--- a/chromium/components/offline_pages/core/background/remove_requests_task.h
+++ b/chromium/components/offline_pages/core/background/remove_requests_task.h
@@ -21,7 +21,7 @@ class RemoveRequestsTask : public Task {
public:
RemoveRequestsTask(RequestQueueStore* store,
const std::vector<int64_t>& request_ids,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~RemoveRequestsTask() override;
// TaskQueue::Task implementation.
diff --git a/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc b/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc
index 5846dc2e3ec..d66fac16867 100644
--- a/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc
+++ b/chromium/components/offline_pages/core/background/remove_requests_task_unittest.cc
@@ -56,8 +56,8 @@ void RemoveRequestsTaskTest::PumpLoop() {
}
void RemoveRequestsTaskTest::InitializeStore(RequestQueueStore* store) {
- store->Initialize(base::Bind(&RemoveRequestsTaskTest::InitializeStoreDone,
- base::Unretained(this)));
+ store->Initialize(base::BindOnce(&RemoveRequestsTaskTest::InitializeStoreDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -66,13 +66,13 @@ void RemoveRequestsTaskTest::AddRequestsToStore(RequestQueueStore* store) {
SavePageRequest request_1(kRequestId1, kUrl1, kClientId1, creation_time,
true);
store->AddRequest(request_1,
- base::Bind(&RemoveRequestsTaskTest::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::AddRequestDone,
+ base::Unretained(this)));
SavePageRequest request_2(kRequestId2, kUrl2, kClientId2, creation_time,
true);
store->AddRequest(request_2,
- base::Bind(&RemoveRequestsTaskTest::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
}
@@ -96,8 +96,8 @@ TEST_F(RemoveRequestsTaskTest, RemoveWhenStoreEmpty) {
std::vector<int64_t> request_ids{kRequestId1};
RemoveRequestsTask task(
&store, request_ids,
- base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -116,8 +116,8 @@ TEST_F(RemoveRequestsTaskTest, RemoveSingleItem) {
std::vector<int64_t> request_ids{kRequestId1};
RemoveRequestsTask task(
&store, request_ids,
- base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -137,8 +137,8 @@ TEST_F(RemoveRequestsTaskTest, RemoveMultipleItems) {
std::vector<int64_t> request_ids{kRequestId1, kRequestId2};
RemoveRequestsTask task(
&store, request_ids,
- base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -161,8 +161,8 @@ TEST_F(RemoveRequestsTaskTest, DeleteWithEmptyIdList) {
std::vector<int64_t> request_ids;
RemoveRequestsTask task(
&store, request_ids,
- base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
@@ -178,8 +178,8 @@ TEST_F(RemoveRequestsTaskTest, RemoveMissingItem) {
std::vector<int64_t> request_ids{kRequestId1, kRequestId3};
RemoveRequestsTask task(
&store, request_ids,
- base::Bind(&RemoveRequestsTaskTest::RemoveRequestsCallback,
- base::Unretained(this)));
+ base::BindOnce(&RemoveRequestsTaskTest::RemoveRequestsCallback,
+ base::Unretained(this)));
task.Run();
PumpLoop();
ASSERT_TRUE(last_result());
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.cc b/chromium/components/offline_pages/core/background/request_coordinator.cc
index d03f57c3333..c310b7baa80 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator.cc
@@ -257,8 +257,8 @@ RequestCoordinator::RequestCoordinator(
// the AVAILABLE state, and update the UI by sending notifications. Do this
// before we cleanup, so any requests that are now OFFLINING which have
// expired can be legitimate candidates for cleanup.
- queue_->ReconcileRequests(base::Bind(&RequestCoordinator::ReconcileCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ queue_->ReconcileRequests(base::BindOnce(
+ &RequestCoordinator::ReconcileCallback, weak_ptr_factory_.GetWeakPtr()));
// Do a cleanup of expired or over tried requests at startup time.
queue_->CleanupRequestQueue();
}
@@ -267,15 +267,15 @@ RequestCoordinator::~RequestCoordinator() {}
int64_t RequestCoordinator::SavePageLater(
const SavePageLaterParams& save_page_later_params,
- const SavePageLaterCallback& save_page_later_callback) {
+ SavePageLaterCallback save_page_later_callback) {
DVLOG(2) << "URL is " << save_page_later_params.url << " " << __func__;
if (!OfflinePageModel::CanSaveURL(save_page_later_params.url)) {
DVLOG(1) << "Not able to save page for requested url: "
<< save_page_later_params.url;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(save_page_later_callback, AddRequestResult::URL_ERROR));
+ FROM_HERE, base::BindOnce(std::move(save_page_later_callback),
+ AddRequestResult::URL_ERROR));
return 0L;
}
@@ -298,10 +298,10 @@ int64_t RequestCoordinator::SavePageLater(
// Put the request on the request queue.
queue_->AddRequest(
- request,
- base::Bind(&RequestCoordinator::AddRequestResultCallback,
- weak_ptr_factory_.GetWeakPtr(), save_page_later_callback,
- save_page_later_params.availability));
+ request, base::BindOnce(&RequestCoordinator::AddRequestResultCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ std::move(save_page_later_callback),
+ save_page_later_params.availability));
// Record the network quality when this request is made.
if (network_quality_estimator_) {
@@ -321,37 +321,39 @@ int64_t RequestCoordinator::SavePageLater(
return id;
}
-void RequestCoordinator::GetAllRequests(const GetRequestsCallback& callback) {
+void RequestCoordinator::GetAllRequests(GetRequestsCallback callback) {
// Get all matching requests from the request queue, send them to our
// callback. We bind the namespace and callback to the front of the callback
// param set.
- queue_->GetRequests(base::Bind(&RequestCoordinator::GetQueuedRequestsCallback,
- weak_ptr_factory_.GetWeakPtr(), callback));
+ queue_->GetRequests(
+ base::BindOnce(&RequestCoordinator::GetQueuedRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void RequestCoordinator::GetQueuedRequestsCallback(
- const GetRequestsCallback& callback,
+ GetRequestsCallback callback,
GetRequestsResult result,
std::vector<std::unique_ptr<SavePageRequest>> requests) {
for (auto& request : requests) {
- pending_state_updater_.SetPendingState(*request.get());
+ pending_state_updater_.SetPendingState(*request);
}
- callback.Run(std::move(requests));
+ std::move(callback).Run(std::move(requests));
}
-void RequestCoordinator::StopOfflining(const CancelCallback& final_callback,
+void RequestCoordinator::StopOfflining(CancelCallback final_callback,
Offliner::RequestStatus stop_status) {
if (offliner_ && state_ == RequestCoordinatorState::OFFLINING) {
DCHECK_NE(active_request_id_, 0);
- if (offliner_->Cancel(base::Bind(
+ if (offliner_->Cancel(base::BindOnce(
&RequestCoordinator::HandleCancelUpdateStatusCallback,
- weak_ptr_factory_.GetWeakPtr(), final_callback, stop_status))) {
+ weak_ptr_factory_.GetWeakPtr(), std::move(final_callback),
+ stop_status))) {
return;
}
}
UpdateStatusForCancel(stop_status);
- final_callback.Run(active_request_id_);
+ std::move(final_callback).Run(active_request_id_);
}
void RequestCoordinator::GetRequestsForSchedulingCallback(
@@ -381,9 +383,10 @@ bool RequestCoordinator::CancelActiveRequestIfItMatches(
if (active_request_id_ != 0) {
if (request_ids.end() !=
std::find(request_ids.begin(), request_ids.end(), active_request_id_)) {
- StopOfflining(base::Bind(&RequestCoordinator::ResetActiveRequestCallback,
- weak_ptr_factory_.GetWeakPtr()),
- Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED);
+ StopOfflining(
+ base::BindOnce(&RequestCoordinator::ResetActiveRequestCallback,
+ weak_ptr_factory_.GetWeakPtr()),
+ Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED);
return true;
}
}
@@ -409,9 +412,10 @@ void RequestCoordinator::RemoveAttemptedRequest(
RequestNotifier::BackgroundSavePageResult result) {
std::vector<int64_t> remove_requests;
remove_requests.push_back(request.request_id());
- queue_->RemoveRequests(remove_requests,
- base::Bind(&RequestCoordinator::HandleRemovedRequests,
- weak_ptr_factory_.GetWeakPtr(), result));
+ queue_->RemoveRequests(
+ remove_requests,
+ base::BindOnce(&RequestCoordinator::HandleRemovedRequests,
+ weak_ptr_factory_.GetWeakPtr(), result));
RecordAttemptCount(request, result);
}
@@ -419,8 +423,8 @@ void RequestCoordinator::MarkAttemptAborted(int64_t request_id,
const std::string& name_space) {
queue_->MarkAttemptAborted(
request_id,
- base::Bind(&RequestCoordinator::MarkAttemptDone,
- weak_ptr_factory_.GetWeakPtr(), request_id, name_space));
+ base::BindOnce(&RequestCoordinator::MarkAttemptDone,
+ weak_ptr_factory_.GetWeakPtr(), request_id, name_space));
}
void RequestCoordinator::MarkAttemptDone(
@@ -441,15 +445,14 @@ void RequestCoordinator::MarkAttemptDone(
}
}
-void RequestCoordinator::RemoveRequests(
- const std::vector<int64_t>& request_ids,
- const RemoveRequestsCallback& callback) {
+void RequestCoordinator::RemoveRequests(const std::vector<int64_t>& request_ids,
+ RemoveRequestsCallback callback) {
bool canceled = CancelActiveRequestIfItMatches(request_ids);
queue_->RemoveRequests(
request_ids,
- base::Bind(&RequestCoordinator::HandleRemovedRequestsAndCallback,
- weak_ptr_factory_.GetWeakPtr(), callback,
- RequestNotifier::BackgroundSavePageResult::USER_CANCELED));
+ base::BindOnce(&RequestCoordinator::HandleRemovedRequestsAndCallback,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback),
+ RequestNotifier::BackgroundSavePageResult::USER_CANCELED));
// Record the network quality when this request is removed.
if (network_quality_estimator_) {
@@ -477,8 +480,8 @@ void RequestCoordinator::PauseRequests(
queue_->ChangeRequestsState(
request_ids, SavePageRequest::RequestState::PAUSED,
- base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&RequestCoordinator::UpdateMultipleRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr()));
// Record the network quality when this request is paused.
if (network_quality_estimator_) {
@@ -498,8 +501,8 @@ void RequestCoordinator::ResumeRequests(
request_ids.end());
queue_->ChangeRequestsState(
request_ids, SavePageRequest::RequestState::AVAILABLE,
- base::Bind(&RequestCoordinator::UpdateMultipleRequestsCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&RequestCoordinator::UpdateMultipleRequestsCallback,
+ weak_ptr_factory_.GetWeakPtr()));
// Record the network quality when this request is resumed.
if (network_quality_estimator_) {
@@ -514,7 +517,7 @@ void RequestCoordinator::ResumeRequests(
}
void RequestCoordinator::AddRequestResultCallback(
- const SavePageLaterCallback& save_page_later_callback,
+ SavePageLaterCallback save_page_later_callback,
RequestAvailability availability,
AddRequestResult result,
const SavePageRequest& request) {
@@ -527,14 +530,14 @@ void RequestCoordinator::AddRequestResultCallback(
// because foreground offlining is happening).
queue_->MarkAttemptStarted(
request.request_id(),
- base::Bind(&RequestCoordinator::MarkAttemptDone,
- weak_ptr_factory_.GetWeakPtr(), request.request_id(),
- request.client_id().name_space));
+ base::BindOnce(&RequestCoordinator::MarkAttemptDone,
+ weak_ptr_factory_.GetWeakPtr(), request.request_id(),
+ request.client_id().name_space));
} else if (request.user_requested()) {
StartImmediatelyIfConnected();
}
- save_page_later_callback.Run(result);
+ std::move(save_page_later_callback).Run(result);
}
void RequestCoordinator::UpdateMultipleRequestsCallback(
@@ -566,14 +569,14 @@ void RequestCoordinator::ReconcileCallback(
}
void RequestCoordinator::HandleRemovedRequestsAndCallback(
- const RemoveRequestsCallback& callback,
+ RemoveRequestsCallback callback,
RequestNotifier::BackgroundSavePageResult status,
std::unique_ptr<UpdateRequestsResult> result) {
// TODO(dougarnett): Define status code for user/api cancel and use here
// to determine whether to record cancel time UMA.
for (const auto& request : result->updated_items)
RecordCancelTimeUMA(request);
- callback.Run(result->item_statuses);
+ std::move(callback).Run(result->item_statuses);
HandleRemovedRequests(status, std::move(result));
}
@@ -585,7 +588,7 @@ void RequestCoordinator::HandleRemovedRequests(
}
void RequestCoordinator::HandleCancelUpdateStatusCallback(
- const CancelCallback& final_callback,
+ CancelCallback final_callback,
Offliner::RequestStatus stop_status,
const SavePageRequest& canceled_request) {
if (stop_status == Offliner::RequestStatus::REQUEST_COORDINATOR_TIMED_OUT ||
@@ -599,7 +602,7 @@ void RequestCoordinator::HandleCancelUpdateStatusCallback(
RecordOfflinerResult(canceled_request, stop_status);
UpdateStatusForCancel(stop_status);
- final_callback.Run(canceled_request.request_id());
+ std::move(final_callback).Run(canceled_request.request_id());
}
void RequestCoordinator::UpdateStatusForCancel(
@@ -625,14 +628,14 @@ void RequestCoordinator::TryNextRequestCallback(int64_t offline_id) {
void RequestCoordinator::ScheduleAsNeeded() {
// Get all requests from queue (there is no filtering mechanism).
queue_->GetRequests(
- base::Bind(&RequestCoordinator::GetRequestsForSchedulingCallback,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&RequestCoordinator::GetRequestsForSchedulingCallback,
+ weak_ptr_factory_.GetWeakPtr()));
}
void RequestCoordinator::StopProcessing(Offliner::RequestStatus stop_status) {
processing_state_ = ProcessingWindowState::STOPPED;
- StopOfflining(base::Bind(&RequestCoordinator::StartSchedulerCallback,
- weak_ptr_factory_.GetWeakPtr()),
+ StopOfflining(base::BindOnce(&RequestCoordinator::StartSchedulerCallback,
+ weak_ptr_factory_.GetWeakPtr()),
stop_status);
}
@@ -641,8 +644,8 @@ void RequestCoordinator::HandleWatchdogTimeout() {
Offliner::REQUEST_COORDINATOR_TIMED_OUT;
if (offliner_->HandleTimeout(active_request_id_))
return;
- StopOfflining(base::Bind(&RequestCoordinator::TryNextRequestCallback,
- weak_ptr_factory_.GetWeakPtr()),
+ StopOfflining(base::BindOnce(&RequestCoordinator::TryNextRequestCallback,
+ weak_ptr_factory_.GetWeakPtr()),
watchdog_status);
}
@@ -650,7 +653,7 @@ void RequestCoordinator::HandleWatchdogTimeout() {
// instance, this would return false if a request is already in progress.
bool RequestCoordinator::StartScheduledProcessing(
const DeviceConditions& device_conditions,
- const base::Callback<void(bool)>& callback) {
+ const base::RepeatingCallback<void(bool)>& callback) {
DVLOG(2) << "Scheduled " << __func__;
current_conditions_.reset(new DeviceConditions(device_conditions));
return StartProcessingInternal(ProcessingWindowState::SCHEDULED_WINDOW,
@@ -659,7 +662,7 @@ bool RequestCoordinator::StartScheduledProcessing(
// Returns true if the caller should expect a callback, false otherwise.
bool RequestCoordinator::StartImmediateProcessing(
- const base::Callback<void(bool)>& callback) {
+ const base::RepeatingCallback<void(bool)>& callback) {
UpdateCurrentConditionsFromAndroid();
OfflinerImmediateStartStatus immediate_start_status =
TryImmediateStart(callback);
@@ -673,7 +676,7 @@ bool RequestCoordinator::StartImmediateProcessing(
// StartProcessingInternal on all calling code paths.
bool RequestCoordinator::StartProcessingInternal(
const ProcessingWindowState processing_state,
- const base::Callback<void(bool)>& callback) {
+ const base::RepeatingCallback<void(bool)>& callback) {
if (state_ != RequestCoordinatorState::IDLE)
return false;
processing_state_ = processing_state;
@@ -694,7 +697,7 @@ void RequestCoordinator::StartImmediatelyIfConnected() {
RequestCoordinator::OfflinerImmediateStartStatus
RequestCoordinator::TryImmediateStart(
- const base::Callback<void(bool)>& callback) {
+ const base::RepeatingCallback<void(bool)>& callback) {
DVLOG(2) << "Immediate " << __func__;
// Make sure not already busy processing.
if (state_ == RequestCoordinatorState::OFFLINING)
@@ -727,8 +730,8 @@ RequestCoordinator::TryImmediateStart(
void RequestCoordinator::RequestConnectedEventForStarting() {
connection_notifier_.reset(new ConnectionNotifier(
- base::Bind(&RequestCoordinator::HandleConnectedEventForStarting,
- weak_ptr_factory_.GetWeakPtr())));
+ base::BindOnce(&RequestCoordinator::HandleConnectedEventForStarting,
+ weak_ptr_factory_.GetWeakPtr())));
}
void RequestCoordinator::ClearConnectedEventRequest() {
@@ -814,13 +817,13 @@ void RequestCoordinator::TryNextRequest(bool is_start_of_processing) {
// the task queue.
queue_->PickNextRequest(
policy_.get(),
- base::Bind(&RequestCoordinator::RequestPicked,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&RequestCoordinator::RequestNotPicked,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&RequestCoordinator::RequestCounts,
- weak_ptr_factory_.GetWeakPtr(), is_start_of_processing),
- *current_conditions_.get(), disabled_requests_, prioritized_requests_);
+ base::BindOnce(&RequestCoordinator::RequestPicked,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(&RequestCoordinator::RequestNotPicked,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindOnce(&RequestCoordinator::RequestCounts,
+ weak_ptr_factory_.GetWeakPtr(), is_start_of_processing),
+ *current_conditions_, disabled_requests_, prioritized_requests_);
}
// Called by the request picker when a request has been picked.
@@ -930,9 +933,9 @@ void RequestCoordinator::SendRequestToOffliner(const SavePageRequest& request) {
// Mark attempt started in the database and start offliner when completed.
queue_->MarkAttemptStarted(
request.request_id(),
- base::Bind(&RequestCoordinator::StartOffliner,
- weak_ptr_factory_.GetWeakPtr(), request.request_id(),
- request.client_id().name_space));
+ base::BindOnce(&RequestCoordinator::StartOffliner,
+ weak_ptr_factory_.GetWeakPtr(), request.request_id(),
+ request.client_id().name_space));
}
void RequestCoordinator::StartOffliner(
@@ -961,10 +964,10 @@ void RequestCoordinator::StartOffliner(
// Start the load and save process in the offliner (Async).
if (offliner_->LoadAndSave(
update_result->updated_items.at(0),
- base::Bind(&RequestCoordinator::OfflinerDoneCallback,
- weak_ptr_factory_.GetWeakPtr()),
- base::Bind(&RequestCoordinator::OfflinerProgressCallback,
- weak_ptr_factory_.GetWeakPtr()))) {
+ base::BindOnce(&RequestCoordinator::OfflinerDoneCallback,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::BindRepeating(&RequestCoordinator::OfflinerProgressCallback,
+ weak_ptr_factory_.GetWeakPtr()))) {
base::TimeDelta timeout;
if (processing_state_ == ProcessingWindowState::SCHEDULED_WINDOW) {
timeout = base::TimeDelta::FromSeconds(
@@ -1065,9 +1068,9 @@ void RequestCoordinator::UpdateRequestForCompletedAttempt(
// queue.
queue_->MarkAttemptCompleted(
request.request_id(), RequestStatusToFailState(status),
- base::Bind(&RequestCoordinator::MarkAttemptDone,
- weak_ptr_factory_.GetWeakPtr(), request.request_id(),
- request.client_id().name_space));
+ base::BindOnce(&RequestCoordinator::MarkAttemptDone,
+ weak_ptr_factory_.GetWeakPtr(), request.request_id(),
+ request.client_id().name_space));
}
}
@@ -1133,9 +1136,9 @@ void RequestCoordinator::MarkRequestCompleted(int64_t request_id) {
std::vector<int64_t> request_ids { request_id };
queue_->RemoveRequests(
request_ids,
- base::Bind(&RequestCoordinator::HandleRemovedRequests,
- weak_ptr_factory_.GetWeakPtr(),
- RequestNotifier::BackgroundSavePageResult::SUCCESS));
+ base::BindOnce(&RequestCoordinator::HandleRemovedRequests,
+ weak_ptr_factory_.GetWeakPtr(),
+ RequestNotifier::BackgroundSavePageResult::SUCCESS));
}
const Scheduler::TriggerConditions RequestCoordinator::GetTriggerConditions(
diff --git a/chromium/components/offline_pages/core/background/request_coordinator.h b/chromium/components/offline_pages/core/background/request_coordinator.h
index 866ba2ad37e..938abf2bd49 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator.h
+++ b/chromium/components/offline_pages/core/background/request_coordinator.h
@@ -98,18 +98,19 @@ class RequestCoordinator : public KeyedService,
};
// Callback specifying which request IDs were actually removed.
- typedef base::Callback<void(const MultipleItemStatuses&)>
+ typedef base::OnceCallback<void(const MultipleItemStatuses&)>
RemoveRequestsCallback;
// Callback that receives the response for GetAllRequests.
- typedef base::Callback<void(std::vector<std::unique_ptr<SavePageRequest>>)>
+ typedef base::OnceCallback<void(
+ std::vector<std::unique_ptr<SavePageRequest>>)>
GetRequestsCallback;
// Callback for stopping the background offlining.
- typedef base::Callback<void(int64_t request_id)> CancelCallback;
+ typedef base::OnceCallback<void(int64_t request_id)> CancelCallback;
// Callback for SavePageLater calls.
- typedef base::Callback<void(AddRequestResult)> SavePageLaterCallback;
+ typedef base::OnceCallback<void(AddRequestResult)> SavePageLaterCallback;
RequestCoordinator(std::unique_ptr<OfflinerPolicy> policy,
std::unique_ptr<Offliner> offliner,
@@ -124,12 +125,12 @@ class RequestCoordinator : public KeyedService,
// Queues |request| to later load and save when system conditions allow.
// Returns an id if the page could be queued successfully, 0L otherwise.
int64_t SavePageLater(const SavePageLaterParams& save_page_later_params,
- const SavePageLaterCallback& save_page_later_callback);
+ SavePageLaterCallback save_page_later_callback);
// Remove a list of requests by |request_id|. This removes requests from the
// request queue, and cancels an in-progress offliner.
void RemoveRequests(const std::vector<int64_t>& request_ids,
- const RemoveRequestsCallback& callback);
+ RemoveRequestsCallback callback);
// Pause a list of requests by |request_id|. This will change the state
// in the request queue so the request cannot be started.
@@ -139,14 +140,15 @@ class RequestCoordinator : public KeyedService,
void ResumeRequests(const std::vector<int64_t>& request_ids);
// Get all save page request items in the callback.
- void GetAllRequests(const GetRequestsCallback& callback);
+ void GetAllRequests(GetRequestsCallback callback);
// Starts processing of one or more queued save page later requests
// in scheduled background mode.
// Returns whether processing was started and that caller should expect
// a callback. If processing was already active, returns false.
- bool StartScheduledProcessing(const DeviceConditions& device_conditions,
- const base::Callback<void(bool)>& callback);
+ bool StartScheduledProcessing(
+ const DeviceConditions& device_conditions,
+ const base::RepeatingCallback<void(bool)>& callback);
// Attempts to starts processing of one or more queued save page later
// requests (if device conditions are suitable) in immediate mode
@@ -158,7 +160,8 @@ class RequestCoordinator : public KeyedService,
// a callback. If processing was already active or some condition was
// not suitable for immediate processing (e.g., network or low-end device),
// returns false.
- bool StartImmediateProcessing(const base::Callback<void(bool)>& callback);
+ bool StartImmediateProcessing(
+ const base::RepeatingCallback<void(bool)>& callback);
// Stops the current request processing if active. This is a way for
// caller to abort processing; otherwise, processing will complete on
@@ -179,7 +182,8 @@ class RequestCoordinator : public KeyedService,
const bool user_requested);
// A way for tests to set the callback in use when an operation is over.
- void SetProcessingCallbackForTest(const base::Callback<void(bool)> callback) {
+ void SetProcessingCallbackForTest(
+ const base::RepeatingCallback<void(bool)>& callback) {
scheduler_callback_ = callback;
}
@@ -187,7 +191,7 @@ class RequestCoordinator : public KeyedService,
// triggered immediately internally by the coordinator. Used by testing
// harness to determine if a request has been processed.
void SetInternalStartProcessingCallbackForTest(
- const base::Callback<void(bool)> callback) {
+ const base::RepeatingCallback<void(bool)>& callback) {
internal_start_processing_callback_ = callback;
}
@@ -268,7 +272,7 @@ class RequestCoordinator : public KeyedService,
// Receives the results of a get from the request queue, and turns that into
// SavePageRequest objects for the caller of GetQueuedRequests.
void GetQueuedRequestsCallback(
- const GetRequestsCallback& callback,
+ GetRequestsCallback callback,
GetRequestsResult result,
std::vector<std::unique_ptr<SavePageRequest>> requests);
@@ -279,11 +283,10 @@ class RequestCoordinator : public KeyedService,
std::vector<std::unique_ptr<SavePageRequest>> requests);
// Receives the result of add requests to the request queue.
- void AddRequestResultCallback(
- const SavePageLaterCallback& save_page_later_callback,
- RequestAvailability availability,
- AddRequestResult result,
- const SavePageRequest& request);
+ void AddRequestResultCallback(SavePageLaterCallback save_page_later_callback,
+ RequestAvailability availability,
+ AddRequestResult result,
+ const SavePageRequest& request);
void UpdateMultipleRequestsCallback(
std::unique_ptr<UpdateRequestsResult> result);
@@ -291,7 +294,7 @@ class RequestCoordinator : public KeyedService,
void ReconcileCallback(std::unique_ptr<UpdateRequestsResult> result);
void HandleRemovedRequestsAndCallback(
- const RemoveRequestsCallback& callback,
+ RemoveRequestsCallback callback,
RequestNotifier::BackgroundSavePageResult status,
std::unique_ptr<UpdateRequestsResult> result);
@@ -301,7 +304,7 @@ class RequestCoordinator : public KeyedService,
// Handle updating of request status after cancel is called. Will call
// HandleCancelRecordResultCallback for UMA handling
void HandleCancelUpdateStatusCallback(
- const CancelCallback& next_callback,
+ CancelCallback next_callback,
Offliner::RequestStatus stop_status,
const SavePageRequest& canceled_request);
void UpdateStatusForCancel(Offliner::RequestStatus stop_status);
@@ -309,15 +312,16 @@ class RequestCoordinator : public KeyedService,
void StartSchedulerCallback(int64_t offline_id);
void TryNextRequestCallback(int64_t offline_id);
- bool StartProcessingInternal(const ProcessingWindowState processing_state,
- const base::Callback<void(bool)>& callback);
+ bool StartProcessingInternal(
+ const ProcessingWindowState processing_state,
+ const base::RepeatingCallback<void(bool)>& callback);
// Start processing now if connected (but with conservative assumption
// as to other device conditions).
void StartImmediatelyIfConnected();
OfflinerImmediateStartStatus TryImmediateStart(
- const base::Callback<void(bool)>& callback);
+ const base::RepeatingCallback<void(bool)>& callback);
// Requests a callback upon the next network connection to start processing.
void RequestConnectedEventForStarting();
@@ -356,7 +360,7 @@ class RequestCoordinator : public KeyedService,
void HandleWatchdogTimeout();
// Cancels an in progress offlining, and updates state appropriately.
- void StopOfflining(const CancelCallback& callback,
+ void StopOfflining(CancelCallback callback,
Offliner::RequestStatus stop_status);
// Marks attempt on the request and sends it to offliner in continuation.
@@ -476,10 +480,10 @@ class RequestCoordinator : public KeyedService,
// processing was triggered internally.
// For StartScheduledProcessing() processing, calling its callback returns
// to the scheduler across the JNI bridge.
- base::Callback<void(bool)> scheduler_callback_;
+ base::RepeatingCallback<void(bool)> scheduler_callback_;
// Callback invoked when internally triggered processing is done. It is
// kept as a class member so that it may be overridden for test visibility.
- base::Callback<void(bool)> internal_start_processing_callback_;
+ base::RepeatingCallback<void(bool)> internal_start_processing_callback_;
// Logger to record events.
RequestCoordinatorEventLogger event_logger_;
// Timer to watch for pre-render attempts running too long.
diff --git a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
index f0232fa19a3..a135f81ce26 100644
--- a/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_coordinator_unittest.cc
@@ -281,8 +281,8 @@ class RequestCoordinatorTest : public testing::Test {
params.user_requested = kUserRequested;
params.request_origin = kRequestOrigin;
return coordinator()->SavePageLater(
- params, base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
- base::Unretained(this)));
+ params, base::BindOnce(&RequestCoordinatorTest::SavePageRequestCallback,
+ base::Unretained(this)));
}
int64_t SavePageLaterWithAvailability(
@@ -294,8 +294,8 @@ class RequestCoordinatorTest : public testing::Test {
params.availability = availability;
params.request_origin = kRequestOrigin;
return coordinator()->SavePageLater(
- params, base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
- base::Unretained(this)));
+ params, base::BindOnce(&RequestCoordinatorTest::SavePageRequestCallback,
+ base::Unretained(this)));
}
Offliner::RequestStatus last_offlining_status() const {
@@ -310,11 +310,14 @@ class RequestCoordinatorTest : public testing::Test {
DeviceConditions device_conditions() { return device_conditions_; }
- base::Callback<void(bool)> processing_callback() {
+ base::RepeatingCallback<void(bool)> processing_callback() {
return processing_callback_;
}
- base::Callback<void(bool)> waiting_callback() { return waiting_callback_; }
+ base::RepeatingCallback<void(bool)> waiting_callback() {
+ return waiting_callback_;
+ }
+
bool processing_callback_called() const {
return processing_callback_called_;
}
@@ -351,8 +354,8 @@ class RequestCoordinatorTest : public testing::Test {
bool processing_callback_called_;
bool processing_callback_result_;
DeviceConditions device_conditions_;
- base::Callback<void(bool)> processing_callback_;
- base::Callback<void(bool)> waiting_callback_;
+ base::RepeatingCallback<void(bool)> processing_callback_;
+ base::RepeatingCallback<void(bool)> waiting_callback_;
base::HistogramTester histogram_tester_;
};
@@ -393,10 +396,10 @@ void RequestCoordinatorTest::SetUp() {
coordinator()->AddObserver(&observer_);
SetNetworkConnected(true);
processing_callback_ =
- base::Bind(&RequestCoordinatorTest::ProcessingCallbackFunction,
- base::Unretained(this));
+ base::BindRepeating(&RequestCoordinatorTest::ProcessingCallbackFunction,
+ base::Unretained(this));
// Override the normal immediate callback with a wait releasing callback.
- waiting_callback_ = base::Bind(
+ waiting_callback_ = base::BindRepeating(
&RequestCoordinatorTest::WaitingCallbackFunction, base::Unretained(this));
SetDeviceConditionsForTest(device_conditions_);
// Ensure not low-end device so immediate start can happen for most tests.
@@ -436,14 +439,14 @@ void RequestCoordinatorTest::SetupForOfflinerDoneCallbackTest(
// then wait for callback to finish.
request->MarkAttemptStarted(base::Time::Now());
coordinator()->queue()->AddRequest(
- *request, base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ *request, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Override the processing callback for test visiblity.
- base::Callback<void(bool)> callback =
- base::Bind(&RequestCoordinatorTest::ProcessingCallbackFunction,
- base::Unretained(this));
+ base::RepeatingCallback<void(bool)> callback =
+ base::BindRepeating(&RequestCoordinatorTest::ProcessingCallbackFunction,
+ base::Unretained(this));
coordinator()->SetProcessingCallbackForTest(callback);
// Mock that coordinator is in actively processing state starting now.
@@ -463,8 +466,8 @@ SavePageRequest RequestCoordinatorTest::AddRequest1() {
offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest(
- request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ request1, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
return request1;
}
@@ -472,8 +475,8 @@ SavePageRequest RequestCoordinatorTest::AddRequest2() {
offline_pages::SavePageRequest request2(kRequestId2, kUrl2, kClientId2,
base::Time::Now(), kUserRequested);
coordinator()->queue()->AddRequest(
- request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ request2, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
return request2;
}
@@ -591,12 +594,12 @@ TEST_F(RequestCoordinatorTest, SavePageLater) {
params.original_url = kUrl2;
params.request_origin = kRequestOrigin;
EXPECT_NE(0, coordinator()->SavePageLater(
- params,
- base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
- base::Unretained(this))));
+ params, base::BindOnce(
+ &RequestCoordinatorTest::SavePageRequestCallback,
+ base::Unretained(this))));
// Expect that a request got placed on the queue.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
// Expect that the request is not added to the disabled list by default.
@@ -644,7 +647,7 @@ TEST_F(RequestCoordinatorTest, SavePageLaterFailed) {
EXPECT_NE(0, SavePageLater());
// Expect that a request got placed on the queue.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
// Wait for callbacks to finish, both request queue and offliner.
@@ -691,7 +694,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestSucceeded) {
EXPECT_TRUE(processing_callback_called());
// Verify the request gets removed from the queue, and wait for callbacks.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -763,7 +766,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailed) {
// Busy processing 2nd request.
EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -805,7 +808,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailedNoRetryFailure) {
// Busy processing 2nd request.
EXPECT_TRUE(state() == RequestCoordinatorState::OFFLINING);
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -848,7 +851,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneRequestFailedNoNextFailure) {
// Not busy for NO_NEXT failure.
EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -870,7 +873,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneForegroundCancel) {
EXPECT_TRUE(processing_callback_called());
// Verify the request is not removed from the queue, and wait for callbacks.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -893,7 +896,7 @@ TEST_F(RequestCoordinatorTest, OfflinerDoneOffliningCancel) {
EXPECT_TRUE(processing_callback_called());
// Verify the request is not removed from the queue, and wait for callbacks.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -965,8 +968,8 @@ TEST_F(RequestCoordinatorTest, SchedulerGetsLeastRestrictiveConditions) {
offline_pages::SavePageRequest request2(kRequestId2, kUrl2, kClientId2,
base::Time::Now(), !kUserRequested);
coordinator()->queue()->AddRequest(
- request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ request2, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Trigger the scheduler to schedule for the least restrictive condition.
@@ -1110,8 +1113,8 @@ TEST_F(RequestCoordinatorTest, RemoveInflightRequest) {
// Remove the request while it is processing.
std::vector<int64_t> request_ids{kRequestId1};
coordinator()->RemoveRequests(
- request_ids, base::Bind(&RequestCoordinatorTest::RemoveRequestsDone,
- base::Unretained(this)));
+ request_ids, base::BindOnce(&RequestCoordinatorTest::RemoveRequestsDone,
+ base::Unretained(this)));
// Let the async callbacks in the cancel run.
PumpLoop();
@@ -1183,8 +1186,8 @@ TEST_F(RequestCoordinatorTest,
int max_tries = coordinator()->policy()->GetMaxCompletedTries();
request.set_completed_attempt_count(max_tries - 1);
coordinator()->queue()->AddRequest(
- request, base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ request, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Ensure that the new request does not finish - we simulate it being
@@ -1256,8 +1259,8 @@ TEST_F(RequestCoordinatorTest, TimeBudgetExceeded) {
base::Time::Now(), kUserRequested);
request2.set_completed_attempt_count(kAttemptCount);
coordinator()->queue()->AddRequest(
- request2, base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ request2, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Sending the request to the offliner.
@@ -1274,7 +1277,7 @@ TEST_F(RequestCoordinatorTest, TimeBudgetExceeded) {
// TryNextRequest should decide that there is no more work to be done,
// and call back to the scheduler, even though there is another request in the
// queue. Both requests should be left in the queue.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -1311,7 +1314,7 @@ TEST_F(RequestCoordinatorTest, TryNextRequestWithNoNetwork) {
EXPECT_FALSE(state() == RequestCoordinatorState::OFFLINING);
// Get queued requests.
- coordinator()->queue()->GetRequests(base::Bind(
+ coordinator()->queue()->GetRequests(base::BindOnce(
&RequestCoordinatorTest::GetRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -1326,7 +1329,7 @@ TEST_F(RequestCoordinatorTest, GetAllRequests) {
PumpLoop();
// Start the async status fetching.
- coordinator()->GetAllRequests(base::Bind(
+ coordinator()->GetAllRequests(base::BindOnce(
&RequestCoordinatorTest::GetQueuedRequestsDone, base::Unretained(this)));
PumpLoop();
@@ -1384,8 +1387,8 @@ TEST_F(RequestCoordinatorTest, RemoveRequest) {
std::vector<int64_t> request_ids;
request_ids.push_back(kRequestId1);
coordinator()->RemoveRequests(
- request_ids, base::Bind(&RequestCoordinatorTest::RemoveRequestsDone,
- base::Unretained(this)));
+ request_ids, base::BindOnce(&RequestCoordinatorTest::RemoveRequestsDone,
+ base::Unretained(this)));
PumpLoop();
WaitForCallback();
@@ -1438,9 +1441,9 @@ TEST_F(RequestCoordinatorTest,
params.client_id = kClientId2;
params.user_requested = kUserRequested;
EXPECT_NE(0, coordinator()->SavePageLater(
- params,
- base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
- base::Unretained(this))));
+ params, base::BindOnce(
+ &RequestCoordinatorTest::SavePageRequestCallback,
+ base::Unretained(this))));
PumpLoop();
// Verify immediate processing did start this time.
@@ -1531,9 +1534,8 @@ TEST_F(RequestCoordinatorTest, SnapshotOnLastTryForScheduledProcessing) {
int max_tries = coordinator()->policy()->GetMaxCompletedTries();
request.set_completed_attempt_count(max_tries - 1);
coordinator()->queue()->AddRequest(
- request,
- base::Bind(&RequestCoordinatorTest::AddRequestDone,
- base::Unretained(this)));
+ request, base::BindOnce(&RequestCoordinatorTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Ensure that the new request does not finish - we simulate it being
@@ -1697,9 +1699,9 @@ TEST_F(RequestCoordinatorTest,
params.client_id = kClientId2;
params.user_requested = kUserRequested;
EXPECT_NE(0, coordinator()->SavePageLater(
- params,
- base::Bind(&RequestCoordinatorTest::SavePageRequestCallback,
- base::Unretained(this))));
+ params, base::BindOnce(
+ &RequestCoordinatorTest::SavePageRequestCallback,
+ base::Unretained(this))));
PumpLoop();
// Verify second request is waiting for another download to complete.
diff --git a/chromium/components/offline_pages/core/background/request_queue.cc b/chromium/components/offline_pages/core/background/request_queue.cc
index 6df16f53440..a0f3ed03f50 100644
--- a/chromium/components/offline_pages/core/background/request_queue.cc
+++ b/chromium/components/offline_pages/core/background/request_queue.cc
@@ -26,16 +26,16 @@ namespace offline_pages {
namespace {
// Completes the get requests call.
-void GetRequestsDone(const RequestQueue::GetRequestsCallback& callback,
+void GetRequestsDone(RequestQueue::GetRequestsCallback callback,
bool success,
std::vector<std::unique_ptr<SavePageRequest>> requests) {
GetRequestsResult result =
success ? GetRequestsResult::SUCCESS : GetRequestsResult::STORE_FAILURE;
- callback.Run(result, std::move(requests));
+ std::move(callback).Run(result, std::move(requests));
}
// Completes the add request call.
-void AddRequestDone(const RequestQueue::AddRequestCallback& callback,
+void AddRequestDone(RequestQueue::AddRequestCallback callback,
const SavePageRequest& request,
ItemActionStatus status) {
AddRequestResult result;
@@ -54,7 +54,7 @@ void AddRequestDone(const RequestQueue::AddRequestCallback& callback,
NOTREACHED();
return;
}
- callback.Run(result, request);
+ std::move(callback).Run(result, request);
}
} // namespace
@@ -68,54 +68,55 @@ RequestQueue::~RequestQueue() {}
void RequestQueue::OnTaskQueueIsIdle() {}
-void RequestQueue::GetRequests(const GetRequestsCallback& callback) {
+void RequestQueue::GetRequests(GetRequestsCallback callback) {
std::unique_ptr<Task> task(new GetRequestsTask(
- store_.get(), base::Bind(&GetRequestsDone, callback)));
+ store_.get(), base::BindOnce(&GetRequestsDone, std::move(callback))));
task_queue_.AddTask(std::move(task));
}
void RequestQueue::AddRequest(const SavePageRequest& request,
- const AddRequestCallback& callback) {
+ AddRequestCallback callback) {
std::unique_ptr<AddRequestTask> task(new AddRequestTask(
- store_.get(), request, base::Bind(&AddRequestDone, callback, request)));
+ store_.get(), request,
+ base::BindOnce(&AddRequestDone, std::move(callback), request)));
task_queue_.AddTask(std::move(task));
}
void RequestQueue::RemoveRequests(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
std::unique_ptr<Task> task(
- new RemoveRequestsTask(store_.get(), request_ids, callback));
+ new RemoveRequestsTask(store_.get(), request_ids, std::move(callback)));
task_queue_.AddTask(std::move(task));
}
void RequestQueue::ChangeRequestsState(
const std::vector<int64_t>& request_ids,
const SavePageRequest::RequestState new_state,
- const RequestQueue::UpdateCallback& callback) {
+ UpdateCallback callback) {
std::unique_ptr<Task> task(new ChangeRequestsStateTask(
- store_.get(), request_ids, new_state, callback));
+ store_.get(), request_ids, new_state, std::move(callback)));
task_queue_.AddTask(std::move(task));
}
void RequestQueue::MarkAttemptStarted(int64_t request_id,
- const UpdateCallback& callback) {
- std::unique_ptr<Task> task(
- new MarkAttemptStartedTask(store_.get(), request_id, callback));
+ UpdateCallback callback) {
+ std::unique_ptr<Task> task(new MarkAttemptStartedTask(
+ store_.get(), request_id, std::move(callback)));
task_queue_.AddTask(std::move(task));
}
void RequestQueue::MarkAttemptAborted(int64_t request_id,
- const UpdateCallback& callback) {
- std::unique_ptr<Task> task(
- new MarkAttemptAbortedTask(store_.get(), request_id, callback));
+ UpdateCallback callback) {
+ std::unique_ptr<Task> task(new MarkAttemptAbortedTask(
+ store_.get(), request_id, std::move(callback)));
task_queue_.AddTask(std::move(task));
}
void RequestQueue::MarkAttemptCompleted(int64_t request_id,
FailState fail_state,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
std::unique_ptr<Task> task(new MarkAttemptCompletedTask(
- store_.get(), request_id, fail_state, callback));
+ store_.get(), request_id, fail_state, std::move(callback)));
task_queue_.AddTask(std::move(task));
}
@@ -128,18 +129,19 @@ void RequestQueue::PickNextRequest(
std::set<int64_t>& disabled_requests,
base::circular_deque<int64_t>& prioritized_requests) {
// Using the PickerContext, create a picker task.
- std::unique_ptr<Task> task(
- new PickRequestTask(store_.get(), policy, picked_callback,
- not_picked_callback, request_count_callback,
- conditions, disabled_requests, prioritized_requests));
+ std::unique_ptr<Task> task(new PickRequestTask(
+ store_.get(), policy, std::move(picked_callback),
+ std::move(not_picked_callback), std::move(request_count_callback),
+ conditions, disabled_requests, prioritized_requests));
// Queue up the picking task, it will call one of the callbacks when it
// completes.
task_queue_.AddTask(std::move(task));
}
-void RequestQueue::ReconcileRequests(const UpdateCallback& callback) {
- std::unique_ptr<Task> task(new ReconcileTask(store_.get(), callback));
+void RequestQueue::ReconcileRequests(UpdateCallback callback) {
+ std::unique_ptr<Task> task(
+ new ReconcileTask(store_.get(), std::move(callback)));
// Queue up the reconcile task.
task_queue_.AddTask(std::move(task));
@@ -155,8 +157,8 @@ void RequestQueue::CleanupRequestQueue() {
void RequestQueue::Initialize() {
std::unique_ptr<Task> task(new InitializeStoreTask(
- store_.get(), base::Bind(&RequestQueue::InitializeStoreDone,
- weak_ptr_factory_.GetWeakPtr())));
+ store_.get(), base::BindOnce(&RequestQueue::InitializeStoreDone,
+ weak_ptr_factory_.GetWeakPtr())));
task_queue_.AddTask(std::move(task));
}
diff --git a/chromium/components/offline_pages/core/background/request_queue.h b/chromium/components/offline_pages/core/background/request_queue.h
index 658500ab587..48cb67d0b4d 100644
--- a/chromium/components/offline_pages/core/background/request_queue.h
+++ b/chromium/components/offline_pages/core/background/request_queue.h
@@ -35,20 +35,21 @@ class RequestQueueStore;
class RequestQueue : public TaskQueue::Delegate {
public:
// Callback used for |GetRequests|.
- typedef base::Callback<void(GetRequestsResult,
- std::vector<std::unique_ptr<SavePageRequest>>)>
+ typedef base::OnceCallback<
+ void(GetRequestsResult, std::vector<std::unique_ptr<SavePageRequest>>)>
GetRequestsCallback;
// Callback used for |AddRequest|.
- typedef base::Callback<void(AddRequestResult, const SavePageRequest& request)>
+ typedef base::OnceCallback<void(AddRequestResult,
+ const SavePageRequest& request)>
AddRequestCallback;
// Callback used by |ChangeRequestsState|.
- typedef base::Callback<void(std::unique_ptr<UpdateRequestsResult>)>
+ typedef base::OnceCallback<void(std::unique_ptr<UpdateRequestsResult>)>
UpdateCallback;
// Callback used by |UdpateRequest|.
- typedef base::Callback<void(UpdateRequestResult)> UpdateRequestCallback;
+ typedef base::OnceCallback<void(UpdateRequestResult)> UpdateRequestCallback;
explicit RequestQueue(std::unique_ptr<RequestQueueStore> store);
~RequestQueue() override;
@@ -58,41 +59,40 @@ class RequestQueue : public TaskQueue::Delegate {
// Gets all of the active requests from the store. Calling this method may
// schedule purging of the request queue.
- void GetRequests(const GetRequestsCallback& callback);
+ void GetRequests(GetRequestsCallback callback);
// Adds |request| to the request queue. Result is returned through |callback|.
// In case adding the request violates policy, the result will fail with
// appropriate result. Callback will also return a copy of a request with all
// fields set.
- void AddRequest(const SavePageRequest& request,
- const AddRequestCallback& callback);
+ void AddRequest(const SavePageRequest& request, AddRequestCallback callback);
// Removes the requests matching the |request_ids|. Result is returned through
// |callback|. If a request id cannot be removed, this will still remove the
// others.
void RemoveRequests(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback);
+ UpdateCallback callback);
// Changes the state to |new_state| for requests matching the
// |request_ids|. Results are returned through |callback|.
void ChangeRequestsState(const std::vector<int64_t>& request_ids,
const SavePageRequest::RequestState new_state,
- const UpdateCallback& callback);
+ UpdateCallback callback);
// Marks attempt with |request_id| as started. Results are returned through
// |callback|.
- void MarkAttemptStarted(int64_t request_id, const UpdateCallback& callback);
+ void MarkAttemptStarted(int64_t request_id, UpdateCallback callback);
// Marks attempt with |request_id| as aborted. Results are returned through
// |callback|.
- void MarkAttemptAborted(int64_t request_id, const UpdateCallback& callback);
+ void MarkAttemptAborted(int64_t request_id, UpdateCallback callback);
// Marks attempt with |request_id| as completed. The attempt may have
// completed with either success or failure (stored in FailState). Results are
// returned through |callback|.
void MarkAttemptCompleted(int64_t request_id,
FailState fail_state,
- const UpdateCallback& callback);
+ UpdateCallback callback);
// Make a task to pick the next request, and report our choice to the
// callbacks.
@@ -106,7 +106,7 @@ class RequestQueue : public TaskQueue::Delegate {
base::circular_deque<int64_t>& prioritized_requests);
// Reconcile any requests that were active the last time chrome exited.
- void ReconcileRequests(const UpdateCallback& callback);
+ void ReconcileRequests(UpdateCallback callback);
// Cleanup requests that have expired, exceeded the start or completed retry
// limit.
diff --git a/chromium/components/offline_pages/core/background/request_queue_in_memory_store.cc b/chromium/components/offline_pages/core/background/request_queue_in_memory_store.cc
index ee7145181e0..b37209d3ee2 100644
--- a/chromium/components/offline_pages/core/background/request_queue_in_memory_store.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_in_memory_store.cc
@@ -22,17 +22,17 @@ RequestQueueInMemoryStore::RequestQueueInMemoryStore(TestScenario scenario)
RequestQueueInMemoryStore::~RequestQueueInMemoryStore() {}
-void RequestQueueInMemoryStore::Initialize(const InitializeCallback& callback) {
+void RequestQueueInMemoryStore::Initialize(InitializeCallback callback) {
if (scenario_ == TestScenario::SUCCESSFUL)
state_ = StoreState::LOADED;
else
state_ = StoreState::FAILED_LOADING;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, state_ == StoreState::LOADED));
+ FROM_HERE,
+ base::BindOnce(std::move(callback), state_ == StoreState::LOADED));
}
-void RequestQueueInMemoryStore::GetRequests(
- const GetRequestsCallback& callback) {
+void RequestQueueInMemoryStore::GetRequests(GetRequestsCallback callback) {
DCHECK_NE(state_, StoreState::NOT_LOADED);
std::vector<std::unique_ptr<SavePageRequest>> result_requests;
for (const auto& id_request_pair : requests_) {
@@ -41,12 +41,13 @@ void RequestQueueInMemoryStore::GetRequests(
result_requests.push_back(std::move(request));
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(callback, true, std::move(result_requests)));
+ FROM_HERE,
+ base::BindOnce(std::move(callback), true, std::move(result_requests)));
}
void RequestQueueInMemoryStore::GetRequestsByIds(
const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
DCHECK_NE(state_, StoreState::NOT_LOADED);
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(state()));
@@ -69,11 +70,11 @@ void RequestQueueInMemoryStore::GetRequestsByIds(
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(callback, std::move(result)));
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
}
void RequestQueueInMemoryStore::AddRequest(const SavePageRequest& request,
- const AddCallback& callback) {
+ AddCallback callback) {
DCHECK_NE(state_, StoreState::NOT_LOADED);
RequestsMap::iterator iter = requests_.find(request.request_id());
ItemActionStatus status;
@@ -84,13 +85,13 @@ void RequestQueueInMemoryStore::AddRequest(const SavePageRequest& request,
status = ItemActionStatus::ALREADY_EXISTS;
}
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, status));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), status));
}
void RequestQueueInMemoryStore::UpdateRequests(
const std::vector<SavePageRequest>& requests,
- const RequestQueue::UpdateCallback& callback) {
+ UpdateCallback callback) {
DCHECK_NE(state_, StoreState::NOT_LOADED);
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(state()));
@@ -110,12 +111,12 @@ void RequestQueueInMemoryStore::UpdateRequests(
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(callback, std::move(result)));
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
}
void RequestQueueInMemoryStore::RemoveRequests(
const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
DCHECK_NE(state_, StoreState::NOT_LOADED);
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
@@ -136,10 +137,10 @@ void RequestQueueInMemoryStore::RemoveRequests(
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(callback, std::move(result)));
+ FROM_HERE, base::BindOnce(std::move(callback), std::move(result)));
}
-void RequestQueueInMemoryStore::Reset(const ResetCallback& callback) {
+void RequestQueueInMemoryStore::Reset(ResetCallback callback) {
if (scenario_ != TestScenario::LOAD_FAILED_RESET_FAILED) {
requests_.clear();
state_ = StoreState::NOT_LOADED;
@@ -148,7 +149,8 @@ void RequestQueueInMemoryStore::Reset(const ResetCallback& callback) {
state_ = StoreState::FAILED_RESET;
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, state_ == StoreState::NOT_LOADED));
+ FROM_HERE,
+ base::BindOnce(std::move(callback), state_ == StoreState::NOT_LOADED));
}
StoreState RequestQueueInMemoryStore::state() const {
diff --git a/chromium/components/offline_pages/core/background/request_queue_in_memory_store.h b/chromium/components/offline_pages/core/background/request_queue_in_memory_store.h
index 907a6a9cf79..7162016fe67 100644
--- a/chromium/components/offline_pages/core/background/request_queue_in_memory_store.h
+++ b/chromium/components/offline_pages/core/background/request_queue_in_memory_store.h
@@ -29,17 +29,17 @@ class RequestQueueInMemoryStore : public RequestQueueStore {
~RequestQueueInMemoryStore() override;
// RequestQueueStore implementaiton.
- void Initialize(const InitializeCallback& callback) override;
- void GetRequests(const GetRequestsCallback& callback) override;
+ void Initialize(InitializeCallback callback) override;
+ void GetRequests(GetRequestsCallback callback) override;
void GetRequestsByIds(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) override;
+ UpdateCallback callback) override;
void AddRequest(const SavePageRequest& offline_page,
- const AddCallback& callback) override;
+ AddCallback callback) override;
void UpdateRequests(const std::vector<SavePageRequest>& requests,
- const UpdateCallback& callback) override;
+ UpdateCallback callback) override;
void RemoveRequests(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) override;
- void Reset(const ResetCallback& callback) override;
+ UpdateCallback callback) override;
+ void Reset(ResetCallback callback) override;
StoreState state() const override;
private:
diff --git a/chromium/components/offline_pages/core/background/request_queue_store.h b/chromium/components/offline_pages/core/background/request_queue_store.h
index 5bf2738508d..93b698ef4f0 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store.h
+++ b/chromium/components/offline_pages/core/background/request_queue_store.h
@@ -26,35 +26,35 @@ class RequestQueueStore {
using UpdateCallback = RequestQueue::UpdateCallback;
- typedef base::Callback<void(bool /* success */)> InitializeCallback;
- typedef base::Callback<void(bool /* success */)> ResetCallback;
- typedef base::Callback<void(
+ typedef base::OnceCallback<void(bool /* success */)> InitializeCallback;
+ typedef base::OnceCallback<void(bool /* success */)> ResetCallback;
+ typedef base::OnceCallback<void(
bool /* success */,
std::vector<std::unique_ptr<SavePageRequest>> /* requests */)>
GetRequestsCallback;
- typedef base::Callback<void(ItemActionStatus)> AddCallback;
+ typedef base::OnceCallback<void(ItemActionStatus)> AddCallback;
virtual ~RequestQueueStore(){};
// Initializes the store. Should be called before any other methods.
- virtual void Initialize(const InitializeCallback& callback) = 0;
+ virtual void Initialize(InitializeCallback callback) = 0;
// Gets all of the requests from the store.
- virtual void GetRequests(const GetRequestsCallback& callback) = 0;
+ virtual void GetRequests(GetRequestsCallback callback) = 0;
// Gets requests with specified IDs from the store. UpdateCallback is used
// instead of GetRequestsCallback to indicate which requests where not found.
virtual void GetRequestsByIds(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) = 0;
+ UpdateCallback callback) = 0;
// Asynchronously adds request in store. Fails if request with the same
// offline ID already exists.
virtual void AddRequest(const SavePageRequest& offline_page,
- const AddCallback& callback) = 0;
+ AddCallback callback) = 0;
// Asynchronously updates requests in store.
virtual void UpdateRequests(const std::vector<SavePageRequest>& requests,
- const UpdateCallback& callback) = 0;
+ UpdateCallback callback) = 0;
// Asynchronously removes requests from the store using their IDs.
// Result of the update, and a number of removed pages is passed in the
@@ -62,10 +62,10 @@ class RequestQueueStore {
// Result of remove should be false, when one of the provided items couldn't
// be deleted, e.g. because it was missing.
virtual void RemoveRequests(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) = 0;
+ UpdateCallback callback) = 0;
// Resets the store (removes any existing data).
- virtual void Reset(const ResetCallback& callback) = 0;
+ virtual void Reset(ResetCallback callback) = 0;
// Gets the store state.
virtual StoreState state() const = 0;
diff --git a/chromium/components/offline_pages/core/background/request_queue_store_sql.cc b/chromium/components/offline_pages/core/background/request_queue_store_sql.cc
index e77b3b5418d..b601100955b 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store_sql.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_store_sql.cc
@@ -27,7 +27,7 @@ template class StoreUpdateResult<SavePageRequest>;
namespace {
-using SuccessCallback = base::Callback<void(bool)>;
+using SuccessCallback = base::OnceCallback<void(bool)>;
// This is a macro instead of a const so that
// it can be used inline in other SQL statements below.
@@ -280,31 +280,33 @@ void PostStoreUpdateResultForIds(
StoreState store_state,
const std::vector<int64_t>& item_ids,
ItemActionStatus action_status,
- const RequestQueueStore::UpdateCallback& callback) {
+ RequestQueueStore::UpdateCallback callback) {
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(store_state));
for (const auto& item_id : item_ids)
result->item_statuses.push_back(std::make_pair(item_id, action_status));
- runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
+ runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(result)));
}
void PostStoreErrorForAllRequests(
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<SavePageRequest>& items,
- const RequestQueueStore::UpdateCallback& callback) {
+ RequestQueueStore::UpdateCallback callback) {
std::vector<int64_t> item_ids;
for (const auto& item : items)
item_ids.push_back(item.request_id());
PostStoreUpdateResultForIds(runner, StoreState::LOADED, item_ids,
- ItemActionStatus::STORE_ERROR, callback);
+ ItemActionStatus::STORE_ERROR,
+ std::move(callback));
}
-void PostStoreErrorForAllIds(
- scoped_refptr<base::SingleThreadTaskRunner> runner,
- const std::vector<int64_t>& item_ids,
- const RequestQueueStore::UpdateCallback& callback) {
+void PostStoreErrorForAllIds(scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const std::vector<int64_t>& item_ids,
+ RequestQueueStore::UpdateCallback callback) {
PostStoreUpdateResultForIds(runner, StoreState::LOADED, item_ids,
- ItemActionStatus::STORE_ERROR, callback);
+ ItemActionStatus::STORE_ERROR,
+ std::move(callback));
}
bool InitDatabase(sql::Connection* db, const base::FilePath& path) {
@@ -325,7 +327,7 @@ bool InitDatabase(sql::Connection* db, const base::FilePath& path) {
void GetRequestsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
- const RequestQueueStore::GetRequestsCallback& callback) {
+ RequestQueueStore::GetRequestsCallback callback) {
const char kSql[] =
"SELECT request_id, creation_time, activation_time,"
" last_attempt_time, started_attempt_count, completed_attempt_count,"
@@ -339,14 +341,15 @@ void GetRequestsSync(sql::Connection* db,
while (statement.Step())
requests.push_back(MakeSavePageRequest(statement));
- runner->PostTask(FROM_HERE, base::BindOnce(callback, statement.Succeeded(),
- std::move(requests)));
+ runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), statement.Succeeded(),
+ std::move(requests)));
}
void GetRequestsByIdsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<int64_t>& request_ids,
- const RequestQueueStore::UpdateCallback& callback) {
+ RequestQueueStore::UpdateCallback callback) {
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
@@ -354,7 +357,7 @@ void GetRequestsByIdsSync(sql::Connection* db,
// rolled back by its destructor when it falls out of scope.
sql::Transaction transaction(db);
if (!transaction.Begin()) {
- PostStoreErrorForAllIds(runner, request_ids, callback);
+ PostStoreErrorForAllIds(runner, request_ids, std::move(callback));
return;
}
@@ -365,39 +368,40 @@ void GetRequestsByIdsSync(sql::Connection* db,
if (!processed_ids.insert(request_id).second)
continue;
std::unique_ptr<SavePageRequest> request = GetOneRequest(db, request_id);
- if (request.get())
+ if (request)
result->updated_items.push_back(*request);
ItemActionStatus status =
- request.get() ? ItemActionStatus::SUCCESS : ItemActionStatus::NOT_FOUND;
+ request ? ItemActionStatus::SUCCESS : ItemActionStatus::NOT_FOUND;
result->item_statuses.push_back(std::make_pair(request_id, status));
}
if (!transaction.Commit()) {
- PostStoreErrorForAllIds(runner, request_ids, callback);
+ PostStoreErrorForAllIds(runner, request_ids, std::move(callback));
return;
}
- runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
+ runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(result)));
}
void AddRequestSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const SavePageRequest& request,
- const RequestQueueStore::AddCallback& callback) {
+ RequestQueueStore::AddCallback callback) {
ItemActionStatus status = Insert(db, request);
- runner->PostTask(FROM_HERE, base::Bind(callback, status));
+ runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), status));
}
void UpdateRequestsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<SavePageRequest>& requests,
- const RequestQueueStore::UpdateCallback& callback) {
+ RequestQueueStore::UpdateCallback callback) {
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
sql::Transaction transaction(db);
if (!transaction.Begin()) {
- PostStoreErrorForAllRequests(runner, requests, callback);
+ PostStoreErrorForAllRequests(runner, requests, std::move(callback));
return;
}
@@ -410,17 +414,18 @@ void UpdateRequestsSync(sql::Connection* db,
}
if (!transaction.Commit()) {
- PostStoreErrorForAllRequests(runner, requests, callback);
+ PostStoreErrorForAllRequests(runner, requests, std::move(callback));
return;
}
- runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
+ runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(result)));
}
void RemoveRequestsSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const std::vector<int64_t>& request_ids,
- const RequestQueueStore::UpdateCallback& callback) {
+ RequestQueueStore::UpdateCallback callback) {
std::unique_ptr<UpdateRequestsResult> result(
new UpdateRequestsResult(StoreState::LOADED));
@@ -428,7 +433,7 @@ void RemoveRequestsSync(sql::Connection* db,
// rolled back by its destructor when it falls out of scope.
sql::Transaction transaction(db);
if (!transaction.Begin()) {
- PostStoreErrorForAllIds(runner, request_ids, callback);
+ PostStoreErrorForAllIds(runner, request_ids, std::move(callback));
return;
}
@@ -443,25 +448,26 @@ void RemoveRequestsSync(sql::Connection* db,
}
if (!transaction.Commit()) {
- PostStoreErrorForAllIds(runner, request_ids, callback);
+ PostStoreErrorForAllIds(runner, request_ids, std::move(callback));
return;
}
- runner->PostTask(FROM_HERE, base::BindOnce(callback, std::move(result)));
+ runner->PostTask(FROM_HERE,
+ base::BindOnce(std::move(callback), std::move(result)));
}
void OpenConnectionSync(sql::Connection* db,
scoped_refptr<base::SingleThreadTaskRunner> runner,
const base::FilePath& path,
- const SuccessCallback& callback) {
+ SuccessCallback callback) {
bool success = InitDatabase(db, path);
- runner->PostTask(FROM_HERE, base::Bind(callback, success));
+ runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), success));
}
void ResetSync(sql::Connection* db,
const base::FilePath& db_file_path,
scoped_refptr<base::SingleThreadTaskRunner> runner,
- const SuccessCallback& callback) {
+ SuccessCallback callback) {
// This method deletes the content of the whole store and reinitializes it.
bool success = true;
if (db) {
@@ -469,7 +475,7 @@ void ResetSync(sql::Connection* db,
db->Close();
}
success = base::DeleteFile(db_file_path, true /* recursive */) && success;
- runner->PostTask(FROM_HERE, base::Bind(callback, success));
+ runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), success));
}
} // anonymous namespace
@@ -483,121 +489,124 @@ RequestQueueStoreSQL::RequestQueueStoreSQL(
weak_ptr_factory_(this) {}
RequestQueueStoreSQL::~RequestQueueStoreSQL() {
- if (db_.get())
+ if (db_)
background_task_runner_->DeleteSoon(FROM_HERE, db_.release());
}
-void RequestQueueStoreSQL::Initialize(const InitializeCallback& callback) {
+void RequestQueueStoreSQL::Initialize(InitializeCallback callback) {
DCHECK(!db_);
db_.reset(new sql::Connection());
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&OpenConnectionSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), db_file_path_,
- base::Bind(&RequestQueueStoreSQL::OnOpenConnectionDone,
- weak_ptr_factory_.GetWeakPtr(), callback)));
+ base::BindOnce(
+ &OpenConnectionSync, db_.get(), base::ThreadTaskRunnerHandle::Get(),
+ db_file_path_,
+ base::BindOnce(&RequestQueueStoreSQL::OnOpenConnectionDone,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
}
-void RequestQueueStoreSQL::GetRequests(const GetRequestsCallback& callback) {
- DCHECK(db_.get());
+void RequestQueueStoreSQL::GetRequests(GetRequestsCallback callback) {
+ DCHECK(db_);
if (!CheckDb()) {
std::vector<std::unique_ptr<SavePageRequest>> requests;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(callback, false, std::move(requests)));
+ FROM_HERE,
+ base::BindOnce(std::move(callback), false, std::move(requests)));
return;
}
background_task_runner_->PostTask(
- FROM_HERE, base::Bind(&GetRequestsSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), callback));
+ FROM_HERE,
+ base::BindOnce(&GetRequestsSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), std::move(callback)));
}
void RequestQueueStoreSQL::GetRequestsByIds(
const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
if (!CheckDb()) {
PostStoreErrorForAllIds(base::ThreadTaskRunnerHandle::Get(), request_ids,
- callback);
+ std::move(callback));
return;
}
background_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&GetRequestsByIdsSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), request_ids, callback));
+ FROM_HERE, base::BindOnce(&GetRequestsByIdsSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ request_ids, std::move(callback)));
}
void RequestQueueStoreSQL::AddRequest(const SavePageRequest& request,
- const AddCallback& callback) {
+ AddCallback callback) {
if (!CheckDb()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(callback, ItemActionStatus::STORE_ERROR));
+ FROM_HERE,
+ base::BindOnce(std::move(callback), ItemActionStatus::STORE_ERROR));
return;
}
background_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&AddRequestSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), request, callback));
+ FROM_HERE, base::BindOnce(&AddRequestSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), request,
+ std::move(callback)));
}
void RequestQueueStoreSQL::UpdateRequests(
const std::vector<SavePageRequest>& requests,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
if (!CheckDb()) {
PostStoreErrorForAllRequests(base::ThreadTaskRunnerHandle::Get(), requests,
- callback);
+ std::move(callback));
return;
}
background_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&UpdateRequestsSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), requests, callback));
+ FROM_HERE, base::BindOnce(&UpdateRequestsSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(), requests,
+ std::move(callback)));
}
void RequestQueueStoreSQL::RemoveRequests(
const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) {
+ UpdateCallback callback) {
if (!CheckDb()) {
PostStoreErrorForAllIds(base::ThreadTaskRunnerHandle::Get(), request_ids,
- callback);
+ std::move(callback));
return;
}
background_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&RemoveRequestsSync, db_.get(),
- base::ThreadTaskRunnerHandle::Get(), request_ids, callback));
+ FROM_HERE, base::BindOnce(&RemoveRequestsSync, db_.get(),
+ base::ThreadTaskRunnerHandle::Get(),
+ request_ids, std::move(callback)));
}
-void RequestQueueStoreSQL::Reset(const ResetCallback& callback) {
+void RequestQueueStoreSQL::Reset(ResetCallback callback) {
background_task_runner_->PostTask(
FROM_HERE,
- base::Bind(&ResetSync, db_.get(), db_file_path_,
- base::ThreadTaskRunnerHandle::Get(),
- base::Bind(&RequestQueueStoreSQL::OnResetDone,
- weak_ptr_factory_.GetWeakPtr(), callback)));
+ base::BindOnce(
+ &ResetSync, db_.get(), db_file_path_,
+ base::ThreadTaskRunnerHandle::Get(),
+ base::BindOnce(&RequestQueueStoreSQL::OnResetDone,
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback))));
}
StoreState RequestQueueStoreSQL::state() const {
return state_;
}
-void RequestQueueStoreSQL::OnOpenConnectionDone(
- const InitializeCallback& callback,
- bool success) {
- DCHECK(db_.get());
+void RequestQueueStoreSQL::OnOpenConnectionDone(InitializeCallback callback,
+ bool success) {
+ DCHECK(db_);
state_ = success ? StoreState::LOADED : StoreState::FAILED_LOADING;
- callback.Run(success);
+ std::move(callback).Run(success);
}
-void RequestQueueStoreSQL::OnResetDone(const ResetCallback& callback,
- bool success) {
+void RequestQueueStoreSQL::OnResetDone(ResetCallback callback, bool success) {
state_ = success ? StoreState::NOT_LOADED : StoreState::FAILED_RESET;
db_.reset();
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- base::Bind(callback, success));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(std::move(callback), success));
}
bool RequestQueueStoreSQL::CheckDb() const {
diff --git a/chromium/components/offline_pages/core/background/request_queue_store_sql.h b/chromium/components/offline_pages/core/background/request_queue_store_sql.h
index 07a7b2daf46..93e36b4c1cb 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store_sql.h
+++ b/chromium/components/offline_pages/core/background/request_queue_store_sql.h
@@ -45,28 +45,28 @@ class RequestQueueStoreSQL : public RequestQueueStore {
~RequestQueueStoreSQL() override;
// RequestQueueStore implementation.
- void Initialize(const InitializeCallback& callback) override;
- void GetRequests(const GetRequestsCallback& callback) override;
+ void Initialize(InitializeCallback callback) override;
+ void GetRequests(GetRequestsCallback callback) override;
// Note: current implementation of this method makes a SQL query per ID. This
// is OK as long as number of IDs stays low, which is a typical case.
// Implementation should be revisited in case that presumption changes.
void GetRequestsByIds(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) override;
+ UpdateCallback callback) override;
void AddRequest(const SavePageRequest& offline_page,
- const AddCallback& callback) override;
+ AddCallback callback) override;
void UpdateRequests(const std::vector<SavePageRequest>& requests,
- const UpdateCallback& callback) override;
+ UpdateCallback callback) override;
void RemoveRequests(const std::vector<int64_t>& request_ids,
- const UpdateCallback& callback) override;
- void Reset(const ResetCallback& callback) override;
+ UpdateCallback callback) override;
+ void Reset(ResetCallback callback) override;
StoreState state() const override;
private:
// Used to finalize DB connection initialization.
- void OnOpenConnectionDone(const InitializeCallback& callback, bool success);
+ void OnOpenConnectionDone(InitializeCallback callback, bool success);
// Used to finalize DB connection reset.
- void OnResetDone(const ResetCallback& callback, bool success);
+ void OnResetDone(ResetCallback callback, bool success);
// Helper function to return immediately if no database is found.
bool CheckDb() const;
diff --git a/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc b/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc
index c943d8f3513..2350d517586 100644
--- a/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_store_unittest.cc
@@ -262,8 +262,8 @@ void RequestQueueStoreTestBase::ClearResults() {
}
void RequestQueueStoreTestBase::InitializeStore(RequestQueueStore* store) {
- store->Initialize(base::Bind(&RequestQueueStoreTestBase::InitializeCallback,
- base::Unretained(this)));
+ store->Initialize(base::BindOnce(
+ &RequestQueueStoreTestBase::InitializeCallback, base::Unretained(this)));
PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
ClearResults();
@@ -387,8 +387,8 @@ TYPED_TEST(RequestQueueStoreTest, UpgradeFromVersion57Store) {
return;
this->InitializeStore(store.get());
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
ASSERT_EQ(1u, this->last_requests().size());
@@ -404,8 +404,8 @@ TYPED_TEST(RequestQueueStoreTest, UpgradeFromVersion58Store) {
return;
this->InitializeStore(store.get());
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
ASSERT_EQ(1u, this->last_requests().size());
@@ -422,8 +422,8 @@ TYPED_TEST(RequestQueueStoreTest, UpgradeFromVersion61Store) {
return;
this->InitializeStore(store.get());
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
ASSERT_EQ(1u, this->last_requests().size());
@@ -438,8 +438,8 @@ TYPED_TEST(RequestQueueStoreTest, GetRequestsEmpty) {
std::unique_ptr<RequestQueueStore> store(this->BuildStore());
this->InitializeStore(store.get());
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
ASSERT_EQ(LastResult::RESULT_NONE, this->last_result());
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
@@ -454,20 +454,20 @@ TYPED_TEST(RequestQueueStoreTest, GetRequestsByIds) {
SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
store->AddRequest(request1,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
kUserRequested);
store->AddRequest(request2,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
std::vector<int64_t> request_ids{kRequestId, kRequestId2};
store->GetRequestsByIds(
- request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
- base::Unretained(this)));
+ request_ids, base::BindOnce(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
@@ -490,8 +490,8 @@ TYPED_TEST(RequestQueueStoreTest, GetRequestsByIds) {
request_ids.push_back(kRequestId);
store->GetRequestsByIds(
- request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
- base::Unretained(this)));
+ request_ids, base::BindOnce(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
@@ -517,16 +517,16 @@ TYPED_TEST(RequestQueueStoreTest, AddRequest) {
request.set_original_url(kUrl2);
store->AddRequest(request,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
ASSERT_EQ(ItemActionStatus::NOT_FOUND, this->last_add_status());
this->PumpLoop();
ASSERT_EQ(ItemActionStatus::SUCCESS, this->last_add_status());
// Verifying get reqeust results after a request was added.
this->ClearResults();
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
ASSERT_EQ(LastResult::RESULT_NONE, this->last_result());
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
@@ -536,16 +536,16 @@ TYPED_TEST(RequestQueueStoreTest, AddRequest) {
// Verify it is not possible to add the same request twice.
this->ClearResults();
store->AddRequest(request,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
ASSERT_EQ(ItemActionStatus::NOT_FOUND, this->last_add_status());
this->PumpLoop();
ASSERT_EQ(ItemActionStatus::ALREADY_EXISTS, this->last_add_status());
// Check that there is still only one item in the store.
this->ClearResults();
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
ASSERT_EQ(LastResult::RESULT_NONE, this->last_result());
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
@@ -560,8 +560,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
store->AddRequest(original_request,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
@@ -579,8 +579,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
updated_request2};
store->UpdateRequests(
requests_to_update,
- base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
ASSERT_TRUE(this->last_update_result());
@@ -597,8 +597,8 @@ TYPED_TEST(RequestQueueStoreTest, UpdateRequest) {
// Verifying get reqeust results after a request was updated.
this->ClearResults();
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
ASSERT_EQ(LastResult::RESULT_NONE, this->last_result());
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
@@ -614,20 +614,20 @@ TYPED_TEST(RequestQueueStoreTest, RemoveRequests) {
SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
store->AddRequest(request1,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
kUserRequested);
store->AddRequest(request2,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
std::vector<int64_t> request_ids{kRequestId, kRequestId2};
store->RemoveRequests(
- request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
- base::Unretained(this)));
+ request_ids, base::BindOnce(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
@@ -644,8 +644,8 @@ TYPED_TEST(RequestQueueStoreTest, RemoveRequests) {
EXPECT_EQ(request2, this->last_update_result()->updated_items.at(1));
this->ClearResults();
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
ASSERT_TRUE(this->last_requests().empty());
@@ -653,8 +653,8 @@ TYPED_TEST(RequestQueueStoreTest, RemoveRequests) {
// Try to remove a request that is not in the queue.
store->RemoveRequests(
- request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
- base::Unretained(this)));
+ request_ids, base::BindOnce(&RequestQueueStoreTestBase::UpdateRequestDone,
+ base::Unretained(this)));
ASSERT_FALSE(this->last_update_result());
this->PumpLoop();
ASSERT_TRUE(this->last_update_result());
@@ -678,21 +678,21 @@ TYPED_TEST(RequestQueueStoreTest, ResetStore) {
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
store->AddRequest(original_request,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
- store->Reset(base::Bind(&RequestQueueStoreTestBase::ResetDone,
- base::Unretained(this)));
+ store->Reset(base::BindOnce(&RequestQueueStoreTestBase::ResetDone,
+ base::Unretained(this)));
ASSERT_EQ(LastResult::RESULT_NONE, this->last_result());
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
this->ClearResults();
this->InitializeStore(store.get());
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
ASSERT_TRUE(this->last_requests().empty());
@@ -711,8 +711,8 @@ TEST_F(RequestQueueStoreSQLTest, SaveCloseReopenRead) {
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
store->AddRequest(original_request,
- base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueStoreTestBase::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ClearResults();
@@ -722,8 +722,8 @@ TEST_F(RequestQueueStoreSQLTest, SaveCloseReopenRead) {
store = BuildStore();
this->InitializeStore(store.get());
- store->GetRequests(base::Bind(&RequestQueueStoreTestBase::GetRequestsDone,
- base::Unretained(this)));
+ store->GetRequests(base::BindOnce(&RequestQueueStoreTestBase::GetRequestsDone,
+ base::Unretained(this)));
ASSERT_EQ(LastResult::RESULT_NONE, this->last_result());
this->PumpLoop();
ASSERT_EQ(LastResult::RESULT_TRUE, this->last_result());
diff --git a/chromium/components/offline_pages/core/background/request_queue_unittest.cc b/chromium/components/offline_pages/core/background/request_queue_unittest.cc
index 7200f684c16..a19ed342069 100644
--- a/chromium/components/offline_pages/core/background/request_queue_unittest.cc
+++ b/chromium/components/offline_pages/core/background/request_queue_unittest.cc
@@ -194,8 +194,8 @@ void RequestQueueTest::ClearResults() {
}
TEST_F(RequestQueueTest, GetRequestsEmpty) {
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(0ul, last_requests().size());
@@ -205,15 +205,15 @@ TEST_F(RequestQueueTest, AddRequest) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(AddRequestResult::SUCCESS, last_add_result());
ASSERT_TRUE(last_added_request());
ASSERT_EQ(kRequestId, last_added_request()->request_id());
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(1ul, last_requests().size());
@@ -223,15 +223,15 @@ TEST_F(RequestQueueTest, RemoveRequest) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(kRequestId, last_added_request()->request_id());
std::vector<int64_t> remove_requests{kRequestId};
queue()->RemoveRequests(remove_requests,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(1ul, update_requests_result()->item_statuses.size());
EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -240,8 +240,8 @@ TEST_F(RequestQueueTest, RemoveRequest) {
EXPECT_EQ(1UL, update_requests_result()->updated_items.size());
EXPECT_EQ(request, update_requests_result()->updated_items.at(0));
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(0ul, last_requests().size());
@@ -251,15 +251,16 @@ TEST_F(RequestQueueTest, RemoveSeveralRequests) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(kRequestId, last_added_request()->request_id());
SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
kUserRequested);
- queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request2,
+ base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(kRequestId2, last_added_request()->request_id());
@@ -268,8 +269,8 @@ TEST_F(RequestQueueTest, RemoveSeveralRequests) {
remove_requests.push_back(kRequestId2);
remove_requests.push_back(kRequestId3);
queue()->RemoveRequests(remove_requests,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(3ul, update_requests_result()->item_statuses.size());
ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -285,8 +286,8 @@ TEST_F(RequestQueueTest, RemoveSeveralRequests) {
EXPECT_EQ(request, update_requests_result()->updated_items.at(0));
EXPECT_EQ(request2, update_requests_result()->updated_items.at(1));
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
// Verify both requests are no longer in the queue.
@@ -298,13 +299,13 @@ TEST_F(RequestQueueTest, PauseAndResume) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(kRequestId, last_added_request()->request_id());
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(1ul, last_requests().size());
@@ -313,10 +314,10 @@ TEST_F(RequestQueueTest, PauseAndResume) {
request_ids.push_back(kRequestId);
// Pause the request.
- queue()->ChangeRequestsState(request_ids,
- SavePageRequest::RequestState::PAUSED,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->ChangeRequestsState(
+ request_ids, SavePageRequest::RequestState::PAUSED,
+ base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -326,8 +327,8 @@ TEST_F(RequestQueueTest, PauseAndResume) {
ASSERT_EQ(SavePageRequest::RequestState::PAUSED,
update_requests_result()->updated_items.at(0).request_state());
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
// Verify the request is paused.
@@ -337,10 +338,10 @@ TEST_F(RequestQueueTest, PauseAndResume) {
last_requests().at(0)->request_state());
// Resume the request.
- queue()->ChangeRequestsState(request_ids,
- SavePageRequest::RequestState::AVAILABLE,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->ChangeRequestsState(
+ request_ids, SavePageRequest::RequestState::AVAILABLE,
+ base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -350,8 +351,8 @@ TEST_F(RequestQueueTest, PauseAndResume) {
ASSERT_EQ(SavePageRequest::RequestState::AVAILABLE,
update_requests_result()->updated_items.at(0).request_state());
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
// Verify the request is no longer paused.
@@ -367,19 +368,21 @@ TEST_F(RequestQueueTest, MultipleRequestsAddGetRemove) {
base::Time creation_time = base::Time::Now();
SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request1, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request1,
+ base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(request1.request_id(), last_added_request()->request_id());
SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
kUserRequested);
- queue()->AddRequest(request2, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request2,
+ base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(request2.request_id(), last_added_request()->request_id());
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(2ul, last_requests().size());
@@ -387,16 +390,16 @@ TEST_F(RequestQueueTest, MultipleRequestsAddGetRemove) {
std::vector<int64_t> remove_requests;
remove_requests.push_back(request1.request_id());
queue()->RemoveRequests(remove_requests,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
ASSERT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
ASSERT_EQ(ItemActionStatus::SUCCESS,
update_requests_result()->item_statuses.at(0).second);
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(1ul, last_requests().size());
@@ -408,15 +411,15 @@ TEST_F(RequestQueueTest, MarkAttemptStarted) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
base::Time before_time = base::Time::Now();
// Update the request, ensure it succeeded.
- queue()->MarkAttemptStarted(kRequestId,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->MarkAttemptStarted(
+ kRequestId, base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -432,8 +435,8 @@ TEST_F(RequestQueueTest, MarkAttemptStarted) {
EXPECT_EQ(SavePageRequest::RequestState::OFFLINING,
update_requests_result()->updated_items.at(0).request_state());
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
PumpLoop();
EXPECT_EQ(GetRequestsResult::SUCCESS, last_get_requests_result());
ASSERT_EQ(1ul, last_requests().size());
@@ -448,9 +451,9 @@ TEST_F(RequestQueueTest, MarkAttempStartedRequestNotPresent) {
SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->MarkAttemptStarted(kRequestId,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->MarkAttemptStarted(
+ kRequestId, base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -463,20 +466,20 @@ TEST_F(RequestQueueTest, MarkAttemptAborted) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Start request.
- queue()->MarkAttemptStarted(kRequestId,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->MarkAttemptStarted(
+ kRequestId, base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ClearResults();
- queue()->MarkAttemptAborted(kRequestId,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->MarkAttemptAborted(
+ kRequestId, base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_TRUE(update_requests_result());
@@ -496,9 +499,9 @@ TEST_F(RequestQueueTest, MarkAttemptAbortedRequestNotPresent) {
SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->MarkAttemptAborted(kRequestId,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->MarkAttemptAborted(
+ kRequestId, base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_EQ(1ul, update_requests_result()->item_statuses.size());
EXPECT_EQ(kRequestId, update_requests_result()->item_statuses.at(0).first);
@@ -511,21 +514,21 @@ TEST_F(RequestQueueTest, MarkAttemptCompleted) {
base::Time creation_time = base::Time::Now();
SavePageRequest request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(request, base::Bind(&RequestQueueTest::AddRequestDone,
- base::Unretained(this)));
+ queue()->AddRequest(request, base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
PumpLoop();
// Start request.
- queue()->MarkAttemptStarted(kRequestId,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ queue()->MarkAttemptStarted(
+ kRequestId, base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ClearResults();
queue()->MarkAttemptCompleted(
kRequestId, FailState::CANNOT_DOWNLOAD,
- base::Bind(&RequestQueueTest::UpdateRequestsDone,
- base::Unretained(this)));
+ base::BindOnce(&RequestQueueTest::UpdateRequestsDone,
+ base::Unretained(this)));
PumpLoop();
ASSERT_TRUE(update_requests_result());
@@ -545,9 +548,9 @@ TEST_F(RequestQueueTest, CleanStaleRequests) {
SavePageRequest original_request(kRequestId, kUrl, kClientId, creation_time,
kUserRequested);
- queue()->AddRequest(
- original_request,
- base::Bind(&RequestQueueTest::AddRequestDone, base::Unretained(this)));
+ queue()->AddRequest(original_request,
+ base::BindOnce(&RequestQueueTest::AddRequestDone,
+ base::Unretained(this)));
this->PumpLoop();
this->ClearResults();
@@ -573,8 +576,8 @@ TEST_F(RequestQueueTest, CleanStaleRequests) {
// Doing a get should show no entries left in the queue since the expired
// request has been removed.
- queue()->GetRequests(
- base::Bind(&RequestQueueTest::GetRequestsDone, base::Unretained(this)));
+ queue()->GetRequests(base::BindOnce(&RequestQueueTest::GetRequestsDone,
+ base::Unretained(this)));
this->PumpLoop();
ASSERT_EQ(GetRequestsResult::SUCCESS, this->last_get_requests_result());
ASSERT_TRUE(this->last_requests().empty());
diff --git a/chromium/components/offline_pages/core/background/save_page_request.cc b/chromium/components/offline_pages/core/background/save_page_request.cc
index 2ebebf2566b..fe1910480f5 100644
--- a/chromium/components/offline_pages/core/background/save_page_request.cc
+++ b/chromium/components/offline_pages/core/background/save_page_request.cc
@@ -19,7 +19,8 @@ SavePageRequest::SavePageRequest(int64_t request_id,
completed_attempt_count_(0),
user_requested_(user_requested),
state_(RequestState::AVAILABLE),
- fail_state_(FailState::NO_FAILURE) {}
+ fail_state_(FailState::NO_FAILURE),
+ pending_state_(PendingState::NOT_PENDING) {}
SavePageRequest::SavePageRequest(const SavePageRequest& other)
: request_id_(other.request_id_),
diff --git a/chromium/components/offline_pages/core/background/update_request_task.cc b/chromium/components/offline_pages/core/background/update_request_task.cc
index ac5592f58f6..211b1e0965d 100644
--- a/chromium/components/offline_pages/core/background/update_request_task.cc
+++ b/chromium/components/offline_pages/core/background/update_request_task.cc
@@ -11,13 +11,12 @@
namespace offline_pages {
-UpdateRequestTask::UpdateRequestTask(
- RequestQueueStore* store,
- int64_t request_id,
- const RequestQueueStore::UpdateCallback& callback)
+UpdateRequestTask::UpdateRequestTask(RequestQueueStore* store,
+ int64_t request_id,
+ RequestQueueStore::UpdateCallback callback)
: store_(store),
request_id_(request_id),
- callback_(callback),
+ callback_(std::move(callback)),
weak_ptr_factory_(this) {}
UpdateRequestTask::~UpdateRequestTask() {}
@@ -29,13 +28,13 @@ void UpdateRequestTask::Run() {
void UpdateRequestTask::ReadRequest() {
std::vector<int64_t> request_ids{request_id_};
store_->GetRequestsByIds(request_ids,
- base::Bind(&UpdateRequestTask::UpdateRequestImpl,
- weak_ptr_factory_.GetWeakPtr()));
+ base::BindOnce(&UpdateRequestTask::UpdateRequestImpl,
+ weak_ptr_factory_.GetWeakPtr()));
}
void UpdateRequestTask::CompleteWithResult(
std::unique_ptr<UpdateRequestsResult> result) {
- callback_.Run(std::move(result));
+ std::move(callback_).Run(std::move(result));
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/background/update_request_task.h b/chromium/components/offline_pages/core/background/update_request_task.h
index bef04f5b373..9c5e012c6e5 100644
--- a/chromium/components/offline_pages/core/background/update_request_task.h
+++ b/chromium/components/offline_pages/core/background/update_request_task.h
@@ -22,7 +22,7 @@ class UpdateRequestTask : public Task {
public:
UpdateRequestTask(RequestQueueStore* store,
int64_t request_id,
- const RequestQueueStore::UpdateCallback& callback);
+ RequestQueueStore::UpdateCallback callback);
~UpdateRequestTask() override;
// TaskQueue::Task implementation.
diff --git a/chromium/components/offline_pages/core/client_policy_controller.cc b/chromium/components/offline_pages/core/client_policy_controller.cc
index efa68c88795..e7f47691fa7 100644
--- a/chromium/components/offline_pages/core/client_policy_controller.cc
+++ b/chromium/components/offline_pages/core/client_policy_controller.cc
@@ -79,6 +79,7 @@ ClientPolicyController::ClientPolicyController() {
kUnlimitedPages)
.SetIsRemovedOnCacheReset(false)
.SetIsSupportedByDownload(true)
+ .SetIsUserRequestedDownload(true)
.SetShouldAllowDownload(true)
.Build()));
diff --git a/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc b/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc
index 4bca70fa934..63b6c7b252e 100644
--- a/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc
+++ b/chromium/components/offline_pages/core/downloads/download_notifying_observer.cc
@@ -37,7 +37,7 @@ void DownloadNotifyingObserver::CreateAndStartObserving(
RequestCoordinator* request_coordinator,
std::unique_ptr<OfflinePageDownloadNotifier> notifier) {
DCHECK(request_coordinator);
- DCHECK(notifier.get());
+ DCHECK(notifier);
std::unique_ptr<DownloadNotifyingObserver> observer =
base::WrapUnique(new DownloadNotifyingObserver(
std::move(notifier), request_coordinator->GetPolicyController()));
@@ -46,7 +46,7 @@ void DownloadNotifyingObserver::CreateAndStartObserving(
}
void DownloadNotifyingObserver::OnAdded(const SavePageRequest& request) {
- DCHECK(notifier_.get());
+ DCHECK(notifier_);
if (!IsVisibleInUI(request.client_id()))
return;
@@ -61,7 +61,7 @@ void DownloadNotifyingObserver::OnAdded(const SavePageRequest& request) {
}
void DownloadNotifyingObserver::OnChanged(const SavePageRequest& request) {
- DCHECK(notifier_.get());
+ DCHECK(notifier_);
if (!IsVisibleInUI(request.client_id()))
return;
NotifyRequestStateChange(request);
@@ -77,7 +77,7 @@ void DownloadNotifyingObserver::OnNetworkProgress(
void DownloadNotifyingObserver::OnCompleted(
const SavePageRequest& request,
RequestCoordinator::BackgroundSavePageResult status) {
- DCHECK(notifier_.get());
+ DCHECK(notifier_);
if (!IsVisibleInUI(request.client_id()))
return;
if (status == RequestCoordinator::BackgroundSavePageResult::SUCCESS) {
diff --git a/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc b/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc
index d245df2ce65..dca1fdf4069 100644
--- a/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc
+++ b/chromium/components/offline_pages/core/downloads/download_ui_adapter.cc
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/guid.h"
#include "base/logging.h"
+#include "base/metrics/histogram_macros.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h"
#include "components/offline_pages/core/background/request_coordinator.h"
@@ -234,7 +235,7 @@ void DownloadUIAdapter::TemporaryHiddenStatusChanged(
observer.OnItemRemoved(item.second->ui_item->id);
} else {
for (auto& observer : observers_) {
- observer.OnItemsAdded({*item.second->ui_item.get()});
+ observer.OnItemsAdded({*item.second->ui_item});
}
}
}
@@ -262,39 +263,53 @@ void DownloadUIAdapter::GetVisualsForItem(
return;
}
const ItemInfo* item = it->second.get();
+
+ VisualResultCallback callback = base::BindOnce(visuals_callback, id);
+ if (item->client_id.name_space == kSuggestedArticlesNamespace) {
+ // Report PrefetchedItemHasThumbnail along with result callback.
+ auto report_and_callback =
+ [](VisualResultCallback result_callback,
+ std::unique_ptr<offline_items_collection::OfflineItemVisuals>
+ visuals) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "OfflinePages.DownloadUI.PrefetchedItemHasThumbnail",
+ visuals != nullptr);
+ std::move(result_callback).Run(std::move(visuals));
+ };
+ callback = base::BindOnce(report_and_callback, std::move(callback));
+ }
+
model_->GetThumbnailByOfflineId(
item->offline_id,
base::BindOnce(&DownloadUIAdapter::OnThumbnailLoaded,
- weak_ptr_factory_.GetWeakPtr(), id, visuals_callback));
+ weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void DownloadUIAdapter::OnThumbnailLoaded(
- const ContentId& content_id,
- const VisualsCallback& visuals_callback,
+ VisualResultCallback callback,
std::unique_ptr<OfflinePageThumbnail> thumbnail) {
DCHECK(thumbnail_decoder_);
if (!thumbnail || thumbnail->thumbnail.empty()) {
// PostTask not required, GetThumbnailByOfflineId does it for us.
- visuals_callback.Run(content_id, nullptr);
+ std::move(callback).Run(nullptr);
return;
}
- auto forward_visuals_lambda = [](const ContentId& content_id,
- const VisualsCallback& visuals_callback,
+ auto forward_visuals_lambda = [](VisualResultCallback callback,
const gfx::Image& image) {
if (image.IsEmpty()) {
- visuals_callback.Run(content_id, nullptr);
+ std::move(callback).Run(nullptr);
return;
}
auto visuals =
std::make_unique<offline_items_collection::OfflineItemVisuals>();
visuals->icon = image;
- visuals_callback.Run(content_id, std::move(visuals));
+ std::move(callback).Run(std::move(visuals));
};
thumbnail_decoder_->DecodeAndCropThumbnail(
thumbnail->thumbnail,
- base::BindOnce(forward_visuals_lambda, content_id, visuals_callback));
+ base::BindOnce(forward_visuals_lambda, std::move(callback)));
}
void DownloadUIAdapter::ThumbnailAdded(OfflinePageModel* model,
@@ -324,7 +339,7 @@ void DownloadUIAdapter::GetItemById(
OfflineItems::const_iterator it = items_.find(id.id);
if (it != items_.end() && it->second->ui_item &&
!delegate_->IsTemporarilyHiddenInUI(it->second->client_id)) {
- offline_item = *it->second->ui_item.get();
+ offline_item = *it->second->ui_item;
}
}
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -372,8 +387,8 @@ void DownloadUIAdapter::CancelDownload(const ContentId& id) {
// TODO(fgorski): Clean this up in a way where 2 round trips + GetAllRequests
// is not necessary. E.g. CancelByGuid(guid) might do the trick.
request_coordinator_->GetAllRequests(
- base::Bind(&DownloadUIAdapter::CancelDownloadContinuation,
- weak_ptr_factory_.GetWeakPtr(), id.id));
+ base::BindOnce(&DownloadUIAdapter::CancelDownloadContinuation,
+ weak_ptr_factory_.GetWeakPtr(), id.id));
}
void DownloadUIAdapter::CancelDownloadContinuation(
@@ -425,9 +440,8 @@ void DownloadUIAdapter::LoadCache() {
if (state_ != State::NOT_LOADED)
return;
state_ = State::LOADING_PAGES;
- model_->GetAllPages(
- base::BindRepeating(&DownloadUIAdapter::OnOfflinePagesLoaded,
- weak_ptr_factory_.GetWeakPtr()));
+ model_->GetAllPages(base::BindOnce(&DownloadUIAdapter::OnOfflinePagesLoaded,
+ weak_ptr_factory_.GetWeakPtr()));
}
// TODO(dimich): Start clearing this cache on UI close. Also, after OpenItem can
@@ -487,7 +501,7 @@ void DownloadUIAdapter::OnRequestsLoaded(
bool temporarily_hidden =
delegate_->IsTemporarilyHiddenInUI(request->client_id());
std::unique_ptr<ItemInfo> item =
- std::make_unique<ItemInfo>(*request.get(), temporarily_hidden);
+ std::make_unique<ItemInfo>(*request, temporarily_hidden);
items_[guid] = std::move(item);
}
}
diff --git a/chromium/components/offline_pages/core/downloads/download_ui_adapter.h b/chromium/components/offline_pages/core/downloads/download_ui_adapter.h
index ae74447e4c1..2457a495cd8 100644
--- a/chromium/components/offline_pages/core/downloads/download_ui_adapter.h
+++ b/chromium/components/offline_pages/core/downloads/download_ui_adapter.h
@@ -82,7 +82,7 @@ class DownloadUIAdapter : public OfflineContentProvider,
int64_t GetOfflineIdByGuid(const std::string& guid) const;
- // OfflineContentProvider implmentation.
+ // OfflineContentProvider implementation.
void OpenItem(const ContentId& id) override;
void RemoveItem(const ContentId& id) override;
void CancelDownload(const ContentId& id) override;
@@ -159,6 +159,8 @@ class DownloadUIAdapter : public OfflineContentProvider,
};
typedef std::map<std::string, std::unique_ptr<ItemInfo>> OfflineItems;
+ using VisualResultCallback = base::OnceCallback<void(
+ std::unique_ptr<offline_items_collection::OfflineItemVisuals>)>;
void LoadCache();
void ClearCache();
@@ -174,9 +176,8 @@ class DownloadUIAdapter : public OfflineContentProvider,
const std::string& guid,
std::vector<std::unique_ptr<SavePageRequest>> requests);
void OnOfflinePagesLoaded(const MultipleOfflinePageItemResult& pages);
- void OnThumbnailLoaded(const ContentId& content_id,
- const VisualsCallback& visuals_callback,
- std::unique_ptr<OfflinePageThumbnail>);
+ void OnThumbnailLoaded(VisualResultCallback callback,
+ std::unique_ptr<OfflinePageThumbnail> thumbnail);
void OnRequestsLoaded(std::vector<std::unique_ptr<SavePageRequest>> requests);
void OnDeletePagesDone(DeletePageResult result);
diff --git a/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc b/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
index 717661ce855..43a3de166dc 100644
--- a/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
+++ b/chromium/components/offline_pages/core/downloads/download_ui_adapter_unittest.cc
@@ -19,6 +19,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind_test_util.h"
+#include "base/test/histogram_tester.h"
#include "base/test/mock_callback.h"
#include "base/test/test_mock_time_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -54,6 +55,8 @@ static const ClientId kTestClientIdOtherNamespace(kLastNNamespace, kTestGuid1);
static const ClientId kTestClientIdOtherGuid(kLastNNamespace, kTestBadGuid);
static const ClientId kTestClientId1(kAsyncNamespace, kTestGuid1);
static const ClientId kTestClientId2(kAsyncNamespace, kTestGuid2);
+static const ClientId kTestClientIdPrefetch(kSuggestedArticlesNamespace,
+ kTestGuid1);
static const ContentId kTestContentId1(kOfflinePageNamespace, kTestGuid1);
static const base::FilePath kTestFilePath =
base::FilePath(FILE_PATH_LITERAL("foo/bar.mhtml"));
@@ -115,8 +118,8 @@ class MockOfflinePageModel : public StubOfflinePageModel {
~MockOfflinePageModel() override {}
- void AddInitialPage() {
- OfflinePageItem page(GURL(kTestUrl), kTestOfflineId1, kTestClientId1,
+ void AddInitialPage(ClientId client_id) {
+ OfflinePageItem page(GURL(kTestUrl), kTestOfflineId1, client_id,
kTestFilePath, kFileSize, kTestCreationTime);
page.title = kTestTitle;
pages[kTestOfflineId1] = page;
@@ -135,24 +138,25 @@ class MockOfflinePageModel : public StubOfflinePageModel {
}
// PostTask instead of just running callback to simpulate the real class.
- void GetAllPages(const MultipleOfflinePageItemCallback& callback) override {
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&MockOfflinePageModel::GetAllPagesImpl,
- base::Unretained(this), callback));
+ void GetAllPages(MultipleOfflinePageItemCallback callback) override {
+ task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&MockOfflinePageModel::GetAllPagesImpl,
+ base::Unretained(this), std::move(callback)));
}
- void GetAllPagesImpl(const MultipleOfflinePageItemCallback& callback) {
+ void GetAllPagesImpl(MultipleOfflinePageItemCallback callback) {
std::vector<OfflinePageItem> result;
for (const auto& page : pages)
result.push_back(page.second);
- callback.Run(result);
+ std::move(callback).Run(result);
}
void DeletePageAndNotifyAdapter(const std::string& guid) {
for (const auto& page : pages) {
if (page.second.client_id.id == guid) {
DeletedPageInfo info(page.second.offline_id, kSystemDownloadId,
- page.second.client_id, page.second.request_origin);
+ page.second.client_id, page.second.request_origin,
+ page.second.original_url);
observer_->OfflinePageDeleted(info);
pages.erase(page.first);
return;
@@ -230,7 +234,7 @@ class DownloadUIAdapterTest : public testing::Test,
return request_coordinator_taco_->request_coordinator();
}
bool items_loaded() { return adapter->IsCacheLoadedForTest(); }
- void AddInitialPage();
+ void AddInitialPage(const ClientId client_id);
int64_t AddInitialRequest(const GURL& url, const ClientId& client_id);
std::vector<std::string> added_guids, updated_guids, deleted_guids;
@@ -307,8 +311,9 @@ int64_t DownloadUIAdapterTest::AddRequest(const GURL& url,
params, base::Bind(&SavePageLaterCallback));
}
-void DownloadUIAdapterTest::AddInitialPage() {
- model->AddInitialPage();
+void DownloadUIAdapterTest::AddInitialPage(
+ const ClientId client_id = kTestClientId1) {
+ model->AddInitialPage(client_id);
// Trigger cache load in the adapter.
adapter->GetAllItems(base::DoNothing());
PumpLoop();
@@ -626,7 +631,7 @@ TEST_F(DownloadUIAdapterTest, UpdateProgress) {
}
TEST_F(DownloadUIAdapterTest, GetVisualsForItem) {
- AddInitialPage();
+ AddInitialPage(kTestClientIdPrefetch);
model->thumbnail_by_offline_id_result =
std::make_unique<OfflinePageThumbnail>(kThumbnail);
const int kImageWidth = 24;
@@ -641,19 +646,25 @@ TEST_F(DownloadUIAdapterTest, GetVisualsForItem) {
[&](const offline_items_collection::ContentId& id,
std::unique_ptr<offline_items_collection::OfflineItemVisuals>
visuals) {
+ EXPECT_TRUE(visuals);
EXPECT_EQ(kImageWidth, visuals->icon.Width());
called = true;
});
adapter->GetAllItems(base::DoNothing());
+ base::HistogramTester histogram_tester;
+
adapter->GetVisualsForItem(kTestContentId1, callback);
PumpLoop();
+
+ histogram_tester.ExpectUniqueSample(
+ "OfflinePages.DownloadUI.PrefetchedItemHasThumbnail", true, 1);
EXPECT_TRUE(called);
}
TEST_F(DownloadUIAdapterTest, GetVisualsForItemInvalidItem) {
EXPECT_CALL(*thumbnail_decoder, DecodeAndCropThumbnail_(kThumbnailData, _))
.Times(0);
- AddInitialPage();
+ AddInitialPage(kTestClientIdPrefetch);
const ContentId kContentID("not", "valid");
bool called = false;
auto callback = base::BindLambdaForTesting(
@@ -665,13 +676,18 @@ TEST_F(DownloadUIAdapterTest, GetVisualsForItemInvalidItem) {
called = true;
});
adapter->GetAllItems(base::DoNothing());
+ base::HistogramTester histogram_tester;
+
adapter->GetVisualsForItem(kContentID, callback);
PumpLoop();
+
+ histogram_tester.ExpectTotalCount(
+ "OfflinePages.DownloadUI.PrefetchedItemHasThumbnail", 0);
EXPECT_TRUE(called);
}
TEST_F(DownloadUIAdapterTest, GetVisualsForItemNoThumbnail) {
- AddInitialPage();
+ AddInitialPage(kTestClientIdPrefetch);
model->thumbnail_by_offline_id_result = nullptr;
EXPECT_CALL(*thumbnail_decoder, DecodeAndCropThumbnail_(_, _)).Times(0);
bool called = false;
@@ -684,13 +700,18 @@ TEST_F(DownloadUIAdapterTest, GetVisualsForItemNoThumbnail) {
called = true;
});
adapter->GetAllItems(base::DoNothing());
+ base::HistogramTester histogram_tester;
+
adapter->GetVisualsForItem(kTestContentId1, callback);
PumpLoop();
+
+ histogram_tester.ExpectUniqueSample(
+ "OfflinePages.DownloadUI.PrefetchedItemHasThumbnail", false, 1);
EXPECT_TRUE(called);
}
TEST_F(DownloadUIAdapterTest, GetVisualsForItemBadDecode) {
- AddInitialPage();
+ AddInitialPage(kTestClientIdPrefetch);
model->thumbnail_by_offline_id_result =
std::make_unique<OfflinePageThumbnail>(kThumbnail);
EXPECT_CALL(*thumbnail_decoder, DecodeAndCropThumbnail_(kThumbnailData, _))
@@ -708,8 +729,13 @@ TEST_F(DownloadUIAdapterTest, GetVisualsForItemBadDecode) {
called = true;
});
adapter->GetAllItems(base::DoNothing());
+ base::HistogramTester histogram_tester;
+
adapter->GetVisualsForItem(kTestContentId1, callback);
PumpLoop();
+
+ histogram_tester.ExpectUniqueSample(
+ "OfflinePages.DownloadUI.PrefetchedItemHasThumbnail", false, 1);
EXPECT_TRUE(called);
}
diff --git a/chromium/components/offline_pages/core/downloads/offline_item_conversions.cc b/chromium/components/offline_pages/core/downloads/offline_item_conversions.cc
index d893d01184e..1e638213878 100644
--- a/chromium/components/offline_pages/core/downloads/offline_item_conversions.cc
+++ b/chromium/components/offline_pages/core/downloads/offline_item_conversions.cc
@@ -18,6 +18,20 @@ using PendingState = offline_items_collection::PendingState;
namespace {
+const std::string GetDisplayName(const offline_pages::OfflinePageItem& page) {
+ if (!page.title.empty())
+ return base::UTF16ToUTF8(page.title);
+
+ std::string host = page.url.host();
+ return host.empty() ? page.url.spec() : host;
+}
+
+const std::string GetDisplayName(
+ const offline_pages::SavePageRequest& request) {
+ std::string host = request.url().host();
+ return host.empty() ? request.url().spec() : host;
+}
+
const std::string GetMimeType() {
return offline_pages::IsOfflinePagesSharingEnabled() ? "multipart/related"
: "text/html";
@@ -32,7 +46,7 @@ OfflineItem OfflineItemConversions::CreateOfflineItem(
bool is_suggested) {
OfflineItem item;
item.id = ContentId(kOfflinePageNamespace, page.client_id.id);
- item.title = base::UTF16ToUTF8(page.title);
+ item.title = GetDisplayName(page);
item.filter = OfflineItemFilter::FILTER_PAGE;
item.state = OfflineItemState::COMPLETE;
item.total_size_bytes = page.file_size;
@@ -54,6 +68,7 @@ OfflineItem OfflineItemConversions::CreateOfflineItem(
const SavePageRequest& request) {
OfflineItem item;
item.id = ContentId(kOfflinePageNamespace, request.client_id().id);
+ item.title = GetDisplayName(request);
item.filter = OfflineItemFilter::FILTER_PAGE;
item.creation_time = request.creation_time();
item.total_size_bytes = -1L;
diff --git a/chromium/components/offline_pages/core/model/add_page_to_download_manager_task_unittest.cc b/chromium/components/offline_pages/core/model/add_page_to_download_manager_task_unittest.cc
index a8a583f380b..8f3de730f0f 100644
--- a/chromium/components/offline_pages/core/model/add_page_to_download_manager_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/add_page_to_download_manager_task_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "components/offline_pages/core/model/model_task_test_base.h"
-#include "components/offline_pages/core/system_download_manager_stub.h"
+#include "components/offline_pages/core/stub_system_download_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -29,16 +29,16 @@ class AddPageToDownloadManagerTaskTest : public ModelTaskTestBase {
AddPageToDownloadManagerTaskTest();
~AddPageToDownloadManagerTaskTest() override;
- SystemDownloadManagerStub* download_manager() {
+ StubSystemDownloadManager* download_manager() {
return download_manager_.get();
}
private:
- std::unique_ptr<SystemDownloadManagerStub> download_manager_;
+ std::unique_ptr<StubSystemDownloadManager> download_manager_;
};
AddPageToDownloadManagerTaskTest::AddPageToDownloadManagerTaskTest()
- : download_manager_(new SystemDownloadManagerStub(kTestDownloadId, true)) {}
+ : download_manager_(new StubSystemDownloadManager(kTestDownloadId, true)) {}
AddPageToDownloadManagerTaskTest::~AddPageToDownloadManagerTaskTest() {}
diff --git a/chromium/components/offline_pages/core/model/cleanup_thumbnails_task.cc b/chromium/components/offline_pages/core/model/cleanup_thumbnails_task.cc
index 3922ca96031..dcb00a9d63c 100644
--- a/chromium/components/offline_pages/core/model/cleanup_thumbnails_task.cc
+++ b/chromium/components/offline_pages/core/model/cleanup_thumbnails_task.cc
@@ -18,7 +18,9 @@ typedef base::OnceCallback<void(CleanupThumbnailsTask::Result)> ResultCallback;
CleanupThumbnailsTask::Result CleanupThumbnailsSync(base::Time now,
sql::Connection* db) {
- const char kSql[] =
+ if (!db)
+ return CleanupThumbnailsTask::Result();
+ static const char kSql[] =
"DELETE FROM page_thumbnails "
"WHERE offline_id IN ("
" SELECT pt.offline_id from page_thumbnails pt"
diff --git a/chromium/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc b/chromium/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc
index cbf0fcab3de..f7d09afc33a 100644
--- a/chromium/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/cleanup_thumbnails_task_unittest.cc
@@ -38,6 +38,14 @@ class CleanupThumbnailsTaskTest : public ModelTaskTestBase {
}
};
+TEST_F(CleanupThumbnailsTaskTest, DbConnectionIsNull) {
+ base::MockCallback<StoreThumbnailTask::CompleteCallback> callback;
+ EXPECT_CALL(callback, Run(false)).Times(1);
+ store()->SetStateForTesting(StoreState::FAILED_LOADING, true);
+ RunTask(std::make_unique<CleanupThumbnailsTask>(
+ store(), store_utils::FromDatabaseTime(1000), callback.Get()));
+}
+
TEST_F(CleanupThumbnailsTaskTest, CleanupNoThumbnails) {
base::MockCallback<StoreThumbnailTask::CompleteCallback> callback;
EXPECT_CALL(callback, Run(true)).Times(1);
diff --git a/chromium/components/offline_pages/core/model/delete_page_task.cc b/chromium/components/offline_pages/core/model/delete_page_task.cc
index 43bbfe8a543..5ae3385d641 100644
--- a/chromium/components/offline_pages/core/model/delete_page_task.cc
+++ b/chromium/components/offline_pages/core/model/delete_page_task.cc
@@ -42,7 +42,7 @@ namespace {
// please take a look at GetCachedDeletedPageInfoWrappersByUrlPredicateSync.
#define INFO_WRAPPER_FIELDS \
"offline_id, system_download_id, client_namespace, client_id, file_path, " \
- "request_origin, access_count, creation_time"
+ "request_origin, access_count, creation_time, online_url"
#define INFO_WRAPPER_FIELD_COUNT 8
struct DeletedPageInfoWrapper {
@@ -56,6 +56,7 @@ struct DeletedPageInfoWrapper {
// Used by metric collection only:
int access_count;
base::Time creation_time;
+ GURL url;
};
DeletedPageInfoWrapper CreateInfoWrapper(const sql::Statement& statement) {
@@ -70,6 +71,7 @@ DeletedPageInfoWrapper CreateInfoWrapper(const sql::Statement& statement) {
info_wrapper.access_count = statement.ColumnInt(6);
info_wrapper.creation_time =
store_utils::FromDatabaseTime(statement.ColumnInt64(7));
+ info_wrapper.url = GURL(statement.ColumnString(8));
return info_wrapper;
}
@@ -134,7 +136,8 @@ DeletePageTaskResult DeletePagesByDeletedPageInfoWrappersSync(
if (DeletePageEntryByOfflineIdSync(db, info_wrapper.offline_id)) {
deleted_page_infos.emplace_back(
info_wrapper.offline_id, info_wrapper.system_download_id,
- info_wrapper.client_id, info_wrapper.request_origin);
+ info_wrapper.client_id, info_wrapper.request_origin,
+ info_wrapper.url);
}
}
}
diff --git a/chromium/components/offline_pages/core/model/get_pages_task.cc b/chromium/components/offline_pages/core/model/get_pages_task.cc
index 09c36a22dd2..0b470fd3018 100644
--- a/chromium/components/offline_pages/core/model/get_pages_task.cc
+++ b/chromium/components/offline_pages/core/model/get_pages_task.cc
@@ -276,12 +276,12 @@ ReadResult ReadPagesBySizeAndDigest(int64_t file_size,
return result;
}
-void WrapInMultipleItemsCallback(const SingleOfflinePageItemCallback& callback,
+void WrapInMultipleItemsCallback(SingleOfflinePageItemCallback callback,
const std::vector<OfflinePageItem>& pages) {
if (pages.size() == 0)
- callback.Run(nullptr);
+ std::move(callback).Run(nullptr);
else
- callback.Run(&pages[0]);
+ std::move(callback).Run(&pages[0]);
}
ReadResult SelectItemsForUpgrade(sql::Connection* db) {
@@ -316,124 +316,125 @@ GetPagesTask::ReadResult::~ReadResult() {}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingAllPages(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback) {
- return std::unique_ptr<GetPagesTask>(
- new GetPagesTask(store, base::BindOnce(&ReadAllPagesSync), callback));
+ MultipleOfflinePageItemCallback callback) {
+ return base::WrapUnique(new GetPagesTask(
+ store, base::BindOnce(&ReadAllPagesSync), std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingClientIds(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const std::vector<ClientId>& client_ids) {
// Creates an instance of GetPagesTask, which wraps the client_ids argument in
// a OnceClosure. It will then be used to execute.
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
- store, base::BindOnce(&ReadPagesByClientIdsSync, client_ids), callback));
+ return base::WrapUnique(new GetPagesTask(
+ store, base::BindOnce(&ReadPagesByClientIdsSync, client_ids),
+ std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingNamespace(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const std::string& name_space) {
std::vector<std::string> namespaces = {name_space};
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
+ return base::WrapUnique(new GetPagesTask(
store, base::BindOnce(&ReadPagesByMultipleNamespacesSync, namespaces),
- callback));
+ std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask>
GetPagesTask::CreateTaskMatchingPagesRemovedOnCacheReset(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
ClientPolicyController* policy_controller) {
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
+ return base::WrapUnique(new GetPagesTask(
store,
base::BindOnce(&ReadPagesByMultipleNamespacesSync,
policy_controller->GetNamespacesRemovedOnCacheReset()),
- callback));
+ std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask>
GetPagesTask::CreateTaskMatchingPagesSupportedByDownloads(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
ClientPolicyController* policy_controller) {
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
+ return base::WrapUnique(new GetPagesTask(
store,
base::BindOnce(&ReadPagesByMultipleNamespacesSync,
policy_controller->GetNamespacesSupportedByDownload()),
- callback));
+ std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingRequestOrigin(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const std::string& request_origin) {
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
+ return base::WrapUnique(new GetPagesTask(
store, base::BindOnce(&ReadPagesByRequestOriginSync, request_origin),
- callback));
+ std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingUrl(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const GURL& url) {
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
- store, base::BindOnce(&ReadPagesByUrlSync, url), callback));
+ return base::WrapUnique(new GetPagesTask(
+ store, base::BindOnce(&ReadPagesByUrlSync, url), std::move(callback)));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingOfflineId(
OfflinePageMetadataStoreSQL* store,
- const SingleOfflinePageItemCallback& callback,
+ SingleOfflinePageItemCallback callback,
int64_t offline_id) {
- return std::unique_ptr<GetPagesTask>(
- new GetPagesTask(store, base::BindOnce(&ReadPagesByOfflineId, offline_id),
- base::Bind(&WrapInMultipleItemsCallback, callback)));
+ return base::WrapUnique(new GetPagesTask(
+ store, base::BindOnce(&ReadPagesByOfflineId, offline_id),
+ base::BindOnce(&WrapInMultipleItemsCallback, std::move(callback))));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingGuid(
OfflinePageMetadataStoreSQL* store,
- const SingleOfflinePageItemCallback& callback,
+ SingleOfflinePageItemCallback callback,
const std::string& guid) {
- return base::WrapUnique(
- new GetPagesTask(store, base::BindOnce(&ReadPagesByGuid, guid),
- base::Bind(&WrapInMultipleItemsCallback, callback)));
+ return base::WrapUnique(new GetPagesTask(
+ store, base::BindOnce(&ReadPagesByGuid, guid),
+ base::BindOnce(&WrapInMultipleItemsCallback, std::move(callback))));
}
// static
std::unique_ptr<GetPagesTask> GetPagesTask::CreateTaskMatchingSizeAndDigest(
OfflinePageMetadataStoreSQL* store,
- const SingleOfflinePageItemCallback& callback,
+ SingleOfflinePageItemCallback callback,
int64_t file_size,
const std::string& digest) {
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
+ return base::WrapUnique(new GetPagesTask(
store, base::BindOnce(&ReadPagesBySizeAndDigest, file_size, digest),
- base::Bind(&WrapInMultipleItemsCallback, callback)));
+ base::BindOnce(&WrapInMultipleItemsCallback, std::move(callback))));
}
// static
std::unique_ptr<GetPagesTask>
GetPagesTask::CreateTaskSelectingItemsMarkedForUpgrade(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback) {
- return std::unique_ptr<GetPagesTask>(new GetPagesTask(
- store, base::BindOnce(&SelectItemsForUpgrade), callback));
+ MultipleOfflinePageItemCallback callback) {
+ return base::WrapUnique(new GetPagesTask(
+ store, base::BindOnce(&SelectItemsForUpgrade), std::move(callback)));
}
GetPagesTask::GetPagesTask(OfflinePageMetadataStoreSQL* store,
DbWorkCallback db_work_callback,
- const MultipleOfflinePageItemCallback& callback)
+ MultipleOfflinePageItemCallback callback)
: store_(store),
db_work_callback_(std::move(db_work_callback)),
- callback_(callback),
+ callback_(std::move(callback)),
weak_ptr_factory_(this) {
DCHECK(store_);
DCHECK(!callback_.is_null());
@@ -452,7 +453,7 @@ void GetPagesTask::ReadRequests() {
}
void GetPagesTask::CompleteWithResult(ReadResult result) {
- callback_.Run(result.pages);
+ std::move(callback_).Run(result.pages);
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/model/get_pages_task.h b/chromium/components/offline_pages/core/model/get_pages_task.h
index af3ffd485a3..c8008b73022 100644
--- a/chromium/components/offline_pages/core/model/get_pages_task.h
+++ b/chromium/components/offline_pages/core/model/get_pages_task.h
@@ -38,27 +38,27 @@ class GetPagesTask : public Task {
// Creates |GetPagesTask| reading all pages from DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingAllPages(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback);
+ MultipleOfflinePageItemCallback callback);
// Creates |GetPagesTask| reading pages matching provided |client_ids| from
// DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingClientIds(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const std::vector<ClientId>& client_ids);
// Creates |GetPagesTask| reading pages belonging to provided |name_space|
// from DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingNamespace(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const std::string& name_space);
// Creates |GetPagesTask| reading pages removed on cache reset from DB.
static std::unique_ptr<GetPagesTask>
CreateTaskMatchingPagesRemovedOnCacheReset(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
ClientPolicyController* policy_controller);
// Creates |GetPagesTask| reading pages in namespaces supported by downloads
@@ -66,14 +66,14 @@ class GetPagesTask : public Task {
static std::unique_ptr<GetPagesTask>
CreateTaskMatchingPagesSupportedByDownloads(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
ClientPolicyController* policy_controller);
// Creates |GetPagesTask| reading pages matching provided |request_origin|
// from DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingRequestOrigin(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const std::string& request_origin);
// Creates |GetPagesTask| reading pages matching provided |url| from DB.
@@ -82,28 +82,28 @@ class GetPagesTask : public Task {
// is necessary.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingUrl(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback,
+ MultipleOfflinePageItemCallback callback,
const GURL& url);
// Creates |GetPagesTask| reading a single page matching provided |offline_id|
// from DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingOfflineId(
OfflinePageMetadataStoreSQL* store,
- const SingleOfflinePageItemCallback& callback,
+ SingleOfflinePageItemCallback callback,
int64_t offline_id);
// Creates |GetPagesTask| reading a single page matching provided |guid| from
// DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingGuid(
OfflinePageMetadataStoreSQL* store,
- const SingleOfflinePageItemCallback& callback,
+ SingleOfflinePageItemCallback callback,
const std::string& guid);
// Creates |GetPagesTask| reading a single page matching provided |file_size|
// and |digest| from DB.
static std::unique_ptr<GetPagesTask> CreateTaskMatchingSizeAndDigest(
OfflinePageMetadataStoreSQL* store,
- const SingleOfflinePageItemCallback& callback,
+ SingleOfflinePageItemCallback callback,
int64_t file_size,
const std::string& digest);
@@ -113,7 +113,7 @@ class GetPagesTask : public Task {
// and creation time (descending).
static std::unique_ptr<GetPagesTask> CreateTaskSelectingItemsMarkedForUpgrade(
OfflinePageMetadataStoreSQL* store,
- const MultipleOfflinePageItemCallback& callback);
+ MultipleOfflinePageItemCallback callback);
~GetPagesTask() override;
@@ -123,7 +123,7 @@ class GetPagesTask : public Task {
private:
GetPagesTask(OfflinePageMetadataStoreSQL* store,
DbWorkCallback db_work_callback,
- const MultipleOfflinePageItemCallback& callback);
+ MultipleOfflinePageItemCallback callback);
void ReadRequests();
void CompleteWithResult(ReadResult result);
diff --git a/chromium/components/offline_pages/core/model/get_pages_task_unittest.cc b/chromium/components/offline_pages/core/model/get_pages_task_unittest.cc
index a8d7d0a2ccf..831c77911a9 100644
--- a/chromium/components/offline_pages/core/model/get_pages_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/get_pages_task_unittest.cc
@@ -56,11 +56,13 @@ void GetPagesTaskTest::OnGetPageDone(const OfflinePageItem* page) {
}
MultipleOfflinePageItemCallback GetPagesTaskTest::get_pages_callback() {
- return base::Bind(&GetPagesTaskTest::OnGetPagesDone, base::Unretained(this));
+ return base::BindOnce(&GetPagesTaskTest::OnGetPagesDone,
+ base::Unretained(this));
}
SingleOfflinePageItemCallback GetPagesTaskTest::get_single_page_callback() {
- return base::Bind(&GetPagesTaskTest::OnGetPageDone, base::Unretained(this));
+ return base::BindOnce(&GetPagesTaskTest::OnGetPageDone,
+ base::Unretained(this));
}
TEST_F(GetPagesTaskTest, GetAllPages) {
diff --git a/chromium/components/offline_pages/core/model/get_thumbnail_task.cc b/chromium/components/offline_pages/core/model/get_thumbnail_task.cc
index ee65502f040..9a17d93fc6a 100644
--- a/chromium/components/offline_pages/core/model/get_thumbnail_task.cc
+++ b/chromium/components/offline_pages/core/model/get_thumbnail_task.cc
@@ -16,6 +16,8 @@ namespace {
std::unique_ptr<OfflinePageThumbnail> GetThumbnailSync(int64_t offline_id,
sql::Connection* db) {
+ if (!db)
+ return nullptr;
std::unique_ptr<OfflinePageThumbnail> result;
static const char kSql[] =
"SELECT offline_id, expiration, thumbnail FROM page_thumbnails"
diff --git a/chromium/components/offline_pages/core/model/get_thumbnail_task_unittest.cc b/chromium/components/offline_pages/core/model/get_thumbnail_task_unittest.cc
index ad96ea8f917..0549c6e55ed 100644
--- a/chromium/components/offline_pages/core/model/get_thumbnail_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/get_thumbnail_task_unittest.cc
@@ -23,6 +23,14 @@ using testing::_;
namespace offline_pages {
namespace {
+OfflinePageThumbnail TestThumbnail() {
+ OfflinePageThumbnail thumb;
+ thumb.offline_id = 1;
+ thumb.expiration = store_utils::FromDatabaseTime(1234);
+ thumb.thumbnail = "123abc";
+ return thumb;
+}
+
class GetThumbnailTaskTest : public ModelTaskTestBase {
public:
~GetThumbnailTaskTest() override = default;
@@ -45,11 +53,6 @@ class GetThumbnailTaskTest : public ModelTaskTestBase {
};
TEST_F(GetThumbnailTaskTest, NotFound) {
- OfflinePageThumbnail thumb;
- thumb.offline_id = 1;
- thumb.expiration = store_utils::FromDatabaseTime(1234);
- thumb.thumbnail = "123abc";
-
bool called = false;
auto callback = base::BindLambdaForTesting(
[&](std::unique_ptr<OfflinePageThumbnail> result) {
@@ -62,10 +65,7 @@ TEST_F(GetThumbnailTaskTest, NotFound) {
}
TEST_F(GetThumbnailTaskTest, Found) {
- OfflinePageThumbnail thumb;
- thumb.offline_id = 1;
- thumb.expiration = store_utils::FromDatabaseTime(1234);
- thumb.thumbnail = "123abc";
+ const OfflinePageThumbnail thumb = TestThumbnail();
RunTask(
std::make_unique<StoreThumbnailTask>(store(), thumb, base::DoNothing()));
@@ -82,5 +82,21 @@ TEST_F(GetThumbnailTaskTest, Found) {
EXPECT_TRUE(called);
}
+TEST_F(GetThumbnailTaskTest, DbConnectionIsNull) {
+ RunTask(std::make_unique<StoreThumbnailTask>(store(), TestThumbnail(),
+ base::DoNothing()));
+ bool called = false;
+ auto callback = base::BindLambdaForTesting(
+ [&](std::unique_ptr<OfflinePageThumbnail> result) {
+ called = true;
+ EXPECT_FALSE(result);
+ });
+ store()->SetStateForTesting(StoreState::FAILED_LOADING, true);
+
+ RunTask(std::make_unique<GetThumbnailTask>(store(), 1, std::move(callback)));
+
+ EXPECT_TRUE(called);
+}
+
} // namespace
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/model/has_thumbnail_task.cc b/chromium/components/offline_pages/core/model/has_thumbnail_task.cc
new file mode 100644
index 00000000000..757e1fa1afd
--- /dev/null
+++ b/chromium/components/offline_pages/core/model/has_thumbnail_task.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/model/has_thumbnail_task.h"
+
+#include "components/offline_pages/core/offline_page_metadata_store_sql.h"
+#include "sql/connection.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+namespace offline_pages {
+
+namespace {
+
+bool ThumbnailExistsSync(int64_t offline_id, sql::Connection* db) {
+ if (!db)
+ return false;
+ static const char kSql[] =
+ "SELECT 1 FROM page_thumbnails WHERE offline_id = ?";
+ sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
+ statement.BindInt64(0, offline_id);
+ return statement.Step();
+}
+
+} // namespace
+
+HasThumbnailTask::HasThumbnailTask(OfflinePageMetadataStoreSQL* store,
+ int64_t offline_id,
+ ThumbnailExistsCallback exists_callback)
+ : store_(store),
+ offline_id_(offline_id),
+ exists_callback_(std::move(exists_callback)),
+ weak_ptr_factory_(this) {}
+
+HasThumbnailTask::~HasThumbnailTask() = default;
+
+void HasThumbnailTask::Run() {
+ store_->Execute(base::BindOnce(ThumbnailExistsSync, std::move(offline_id_)),
+ base::BindOnce(&HasThumbnailTask::OnThumbnailExists,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void HasThumbnailTask::OnThumbnailExists(bool exists) {
+ TaskComplete();
+ std::move(exists_callback_).Run(exists);
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/model/has_thumbnail_task.h b/chromium/components/offline_pages/core/model/has_thumbnail_task.h
new file mode 100644
index 00000000000..80b53d8cc2c
--- /dev/null
+++ b/chromium/components/offline_pages/core/model/has_thumbnail_task.h
@@ -0,0 +1,41 @@
+// 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 COMPONENTS_OFFLINE_PAGES_CORE_MODEL_HAS_THUMBNAIL_TASK_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_MODEL_HAS_THUMBNAIL_TASK_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "components/offline_pages/core/task.h"
+
+namespace offline_pages {
+class OfflinePageMetadataStoreSQL;
+
+// Checks if a thumbnail exists for the specified offline id.
+class HasThumbnailTask : public Task {
+ public:
+ using ThumbnailExistsCallback = base::OnceCallback<void(bool)>;
+
+ HasThumbnailTask(OfflinePageMetadataStoreSQL* store,
+ int64_t offline_id,
+ ThumbnailExistsCallback exists_callback);
+ ~HasThumbnailTask() override;
+
+ // Task implementation:
+ void Run() override;
+
+ private:
+ void OnThumbnailExists(bool exists);
+
+ OfflinePageMetadataStoreSQL* store_;
+ int64_t offline_id_;
+ ThumbnailExistsCallback exists_callback_;
+ base::WeakPtrFactory<HasThumbnailTask> weak_ptr_factory_;
+ DISALLOW_COPY_AND_ASSIGN(HasThumbnailTask);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_MODEL_HAS_THUMBNAIL_TASK_H_
diff --git a/chromium/components/offline_pages/core/model/has_thumbnail_task_unittest.cc b/chromium/components/offline_pages/core/model/has_thumbnail_task_unittest.cc
new file mode 100644
index 00000000000..f7fe69abc21
--- /dev/null
+++ b/chromium/components/offline_pages/core/model/has_thumbnail_task_unittest.cc
@@ -0,0 +1,61 @@
+// 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 "components/offline_pages/core/model/has_thumbnail_task.h"
+
+#include <memory>
+
+#include "base/bind_helpers.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/mock_callback.h"
+#include "components/offline_pages/core/model/model_task_test_base.h"
+#include "components/offline_pages/core/model/store_thumbnail_task.h"
+#include "components/offline_pages/core/offline_store_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace offline_pages {
+namespace {
+
+using ThumbnailExistsCallback = HasThumbnailTask::ThumbnailExistsCallback;
+
+class HasThumbnailTaskTest : public ModelTaskTestBase {};
+
+TEST_F(HasThumbnailTaskTest, CorrectlyFindsById) {
+ const int64_t valid_offline_id = 1;
+ const int64_t invalid_offline_id = 2;
+ OfflinePageThumbnail thumb;
+ thumb.offline_id = valid_offline_id;
+ thumb.expiration = store_utils::FromDatabaseTime(1234);
+ thumb.thumbnail = "123abc";
+ RunTask(
+ std::make_unique<StoreThumbnailTask>(store(), thumb, base::DoNothing()));
+
+ base::MockCallback<ThumbnailExistsCallback> exists_callback;
+ EXPECT_CALL(exists_callback, Run(true));
+ RunTask(std::make_unique<HasThumbnailTask>(store(), valid_offline_id,
+ exists_callback.Get()));
+
+ base::MockCallback<ThumbnailExistsCallback> doesnt_exist_callback;
+ EXPECT_CALL(doesnt_exist_callback, Run(false));
+ RunTask(std::make_unique<HasThumbnailTask>(store(), invalid_offline_id,
+ doesnt_exist_callback.Get()));
+}
+
+TEST_F(HasThumbnailTaskTest, DbConnectionIsNull) {
+ OfflinePageThumbnail thumb;
+ thumb.offline_id = 1;
+ thumb.expiration = store_utils::FromDatabaseTime(1234);
+ thumb.thumbnail = "123abc";
+ RunTask(
+ std::make_unique<StoreThumbnailTask>(store(), thumb, base::DoNothing()));
+
+ store()->SetStateForTesting(StoreState::FAILED_LOADING, true);
+ base::MockCallback<ThumbnailExistsCallback> exists_callback;
+ EXPECT_CALL(exists_callback, Run(false));
+ RunTask(std::make_unique<HasThumbnailTask>(store(), thumb.offline_id,
+ exists_callback.Get()));
+}
+
+} // namespace
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc b/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc
index 0c7605a9151..4345e25a82b 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -26,6 +26,7 @@
#include "components/offline_pages/core/model/delete_page_task.h"
#include "components/offline_pages/core/model/get_pages_task.h"
#include "components/offline_pages/core/model/get_thumbnail_task.h"
+#include "components/offline_pages/core/model/has_thumbnail_task.h"
#include "components/offline_pages/core/model/mark_page_accessed_task.h"
#include "components/offline_pages/core/model/offline_page_model_utils.h"
#include "components/offline_pages/core/model/persistent_page_consistency_check_task.h"
@@ -112,11 +113,11 @@ void ReportPageHistogramAfterSuccessfulSaving(
offline_page.file_size / 1024, 1, 10000, 50);
}
-void ReportSavedPagesCount(const MultipleOfflinePageItemCallback& callback,
+void ReportSavedPagesCount(MultipleOfflinePageItemCallback callback,
const MultipleOfflinePageItemResult& all_items) {
UMA_HISTOGRAM_COUNTS_10000("OfflinePages.SavedPageCountUponQuery",
all_items.size());
- callback.Run(all_items);
+ std::move(callback).Run(all_items);
}
void ReportStorageUsage(const ArchiveManager::StorageStats& storage_stats) {
@@ -232,7 +233,7 @@ void OfflinePageModelTaskified::SavePage(
}
// The web contents is not available if archiver is not created and passed.
- if (!archiver.get()) {
+ if (!archiver) {
InformSavePageDone(callback, SavePageResult::CONTENT_UNAVAILABLE,
save_page_params.client_id, kInvalidOfflineId);
return;
@@ -319,83 +320,85 @@ void OfflinePageModelTaskified::DeleteCachedPagesByURLPredicate(
}
void OfflinePageModelTaskified::GetAllPages(
- const MultipleOfflinePageItemCallback& callback) {
+ MultipleOfflinePageItemCallback callback) {
auto task = GetPagesTask::CreateTaskMatchingAllPages(
- store_.get(), base::BindRepeating(&ReportSavedPagesCount, callback));
+ store_.get(),
+ base::BindOnce(&ReportSavedPagesCount, std::move(callback)));
task_queue_.AddTask(std::move(task));
ScheduleMaintenanceTasks();
}
void OfflinePageModelTaskified::GetPageByOfflineId(
int64_t offline_id,
- const SingleOfflinePageItemCallback& callback) {
- auto task = GetPagesTask::CreateTaskMatchingOfflineId(store_.get(), callback,
- offline_id);
+ SingleOfflinePageItemCallback callback) {
+ auto task = GetPagesTask::CreateTaskMatchingOfflineId(
+ store_.get(), std::move(callback), offline_id);
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPageByGuid(
const std::string& guid,
- const SingleOfflinePageItemCallback& callback) {
- auto task =
- GetPagesTask::CreateTaskMatchingGuid(store_.get(), callback, guid);
+ SingleOfflinePageItemCallback callback) {
+ auto task = GetPagesTask::CreateTaskMatchingGuid(store_.get(),
+ std::move(callback), guid);
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPagesByClientIds(
const std::vector<ClientId>& client_ids,
- const MultipleOfflinePageItemCallback& callback) {
- auto task = GetPagesTask::CreateTaskMatchingClientIds(store_.get(), callback,
- client_ids);
+ MultipleOfflinePageItemCallback callback) {
+ auto task = GetPagesTask::CreateTaskMatchingClientIds(
+ store_.get(), std::move(callback), client_ids);
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPagesByURL(
const GURL& url,
URLSearchMode url_search_mode,
- const MultipleOfflinePageItemCallback& callback) {
- auto task = GetPagesTask::CreateTaskMatchingUrl(store_.get(), callback, url);
+ MultipleOfflinePageItemCallback callback) {
+ auto task = GetPagesTask::CreateTaskMatchingUrl(store_.get(),
+ std::move(callback), url);
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPagesByNamespace(
const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback) {
- auto task = GetPagesTask::CreateTaskMatchingNamespace(store_.get(), callback,
- name_space);
+ MultipleOfflinePageItemCallback callback) {
+ auto task = GetPagesTask::CreateTaskMatchingNamespace(
+ store_.get(), std::move(callback), name_space);
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPagesRemovedOnCacheReset(
- const MultipleOfflinePageItemCallback& callback) {
+ MultipleOfflinePageItemCallback callback) {
auto task = GetPagesTask::CreateTaskMatchingPagesRemovedOnCacheReset(
- store_.get(), callback, policy_controller_.get());
+ store_.get(), std::move(callback), policy_controller_.get());
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPagesSupportedByDownloads(
- const MultipleOfflinePageItemCallback& callback) {
+ MultipleOfflinePageItemCallback callback) {
auto task = GetPagesTask::CreateTaskMatchingPagesSupportedByDownloads(
- store_.get(), callback, policy_controller_.get());
+ store_.get(), std::move(callback), policy_controller_.get());
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPagesByRequestOrigin(
const std::string& request_origin,
- const MultipleOfflinePageItemCallback& callback) {
+ MultipleOfflinePageItemCallback callback) {
auto task = GetPagesTask::CreateTaskMatchingRequestOrigin(
- store_.get(), callback, request_origin);
+ store_.get(), std::move(callback), request_origin);
task_queue_.AddTask(std::move(task));
}
void OfflinePageModelTaskified::GetPageBySizeAndDigest(
int64_t file_size,
const std::string& digest,
- const SingleOfflinePageItemCallback& callback) {
+ SingleOfflinePageItemCallback callback) {
DCHECK_GT(file_size, 0);
DCHECK(!digest.empty());
auto task = GetPagesTask::CreateTaskMatchingSizeAndDigest(
- store_.get(), callback, file_size, digest);
+ store_.get(), std::move(callback), file_size, digest);
task_queue_.AddTask(std::move(task));
}
@@ -426,6 +429,13 @@ void OfflinePageModelTaskified::GetThumbnailByOfflineId(
store_.get(), offline_id, std::move(callback)));
}
+void OfflinePageModelTaskified::HasThumbnailForOfflineId(
+ int64_t offline_id,
+ base::OnceCallback<void(bool)> callback) {
+ task_queue_.AddTask(std::make_unique<HasThumbnailTask>(
+ store_.get(), offline_id, std::move(callback)));
+}
+
const base::FilePath& OfflinePageModelTaskified::GetInternalArchiveDirectory(
const std::string& name_space) const {
if (policy_controller_->IsRemovedOnCacheReset(name_space))
@@ -619,6 +629,9 @@ void OfflinePageModelTaskified::OnAddPageForSavePageDone(
.pages_allowed_per_url != kUnlimitedPages) {
RemovePagesMatchingUrlAndNamespace(page_attempted);
}
+ offline_event_logger_.RecordPageSaved(page_attempted.client_id.name_space,
+ page_attempted.url.spec(),
+ page_attempted.offline_id);
}
ScheduleMaintenanceTasks();
}
@@ -647,6 +660,7 @@ void OfflinePageModelTaskified::OnDeleteDone(
"OfflinePages.DeletePageCount",
model_utils::ToNamespaceEnum(info.client_id.name_space),
OfflinePagesNamespaceEnumeration::RESULT_COUNT);
+ offline_event_logger_.RecordPageDeleted(info.offline_id);
for (Observer& observer : observers_)
observer.OfflinePageDeleted(info);
if (info.system_download_id != 0)
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_taskified.h b/chromium/components/offline_pages/core/model/offline_page_model_taskified.h
index 52215f2a1a4..4e65fcc90f0 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_taskified.h
+++ b/chromium/components/offline_pages/core/model/offline_page_model_taskified.h
@@ -99,34 +99,30 @@ class OfflinePageModelTaskified : public OfflinePageModel,
const UrlPredicate& predicate,
const DeletePageCallback& callback) override;
- void GetAllPages(const MultipleOfflinePageItemCallback& callback) override;
- void GetPageByOfflineId(
- int64_t offline_id,
- const SingleOfflinePageItemCallback& callback) override;
+ void GetAllPages(MultipleOfflinePageItemCallback callback) override;
+ void GetPageByOfflineId(int64_t offline_id,
+ SingleOfflinePageItemCallback callback) override;
void GetPageByGuid(const std::string& guid,
- const SingleOfflinePageItemCallback& callback) override;
- void GetPagesByClientIds(
- const std::vector<ClientId>& client_ids,
- const MultipleOfflinePageItemCallback& callback) override;
+ SingleOfflinePageItemCallback callback) override;
+ void GetPagesByClientIds(const std::vector<ClientId>& client_ids,
+ MultipleOfflinePageItemCallback callback) override;
void GetPagesByURL(const GURL& url,
URLSearchMode url_search_mode,
- const MultipleOfflinePageItemCallback& callback) override;
- void GetPagesByNamespace(
- const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
+ void GetPagesByNamespace(const std::string& name_space,
+ MultipleOfflinePageItemCallback callback) override;
// Get all pages in the namespaces that will be removed on cache reset.
void GetPagesRemovedOnCacheReset(
- const MultipleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
// Get all pages in the namespaces that are shown in download ui.
void GetPagesSupportedByDownloads(
- const MultipleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
void GetPagesByRequestOrigin(
const std::string& request_origin,
- const MultipleOfflinePageItemCallback& callback) override;
- void GetPageBySizeAndDigest(
- int64_t file_size,
- const std::string& digest,
- const SingleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
+ void GetPageBySizeAndDigest(int64_t file_size,
+ const std::string& digest,
+ SingleOfflinePageItemCallback callback) override;
void GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) override;
@@ -135,6 +131,9 @@ class OfflinePageModelTaskified : public OfflinePageModel,
int64_t offline_id,
base::OnceCallback<void(std::unique_ptr<OfflinePageThumbnail>)> callback)
override;
+ void HasThumbnailForOfflineId(
+ int64_t offline_id,
+ base::OnceCallback<void(bool)> callback) override;
const base::FilePath& GetInternalArchiveDirectory(
const std::string& name_space) const override;
diff --git a/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
index 714f403bd5d..977717956c9 100644
--- a/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
+++ b/chromium/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -32,7 +32,7 @@
#include "components/offline_pages/core/offline_page_test_archiver.h"
#include "components/offline_pages/core/offline_page_types.h"
#include "components/offline_pages/core/offline_store_utils.h"
-#include "components/offline_pages/core/system_download_manager_stub.h"
+#include "components/offline_pages/core/stub_system_download_manager.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -66,7 +66,7 @@ const ClientId kTestBrowserActionsClientId(kBrowserActionsNamespace, "999");
const int64_t kTestFileSize = 876543LL;
const base::string16 kTestTitle = base::UTF8ToUTF16("a title");
const std::string kTestRequestOrigin("abc.xyz");
-const std::string kEmptyRequestOrigin("");
+const std::string kEmptyRequestOrigin;
const std::string kTestDigest("test digest");
const int64_t kDownloadId = 42LL;
@@ -133,7 +133,7 @@ class OfflinePageModelTaskifiedTest : public testing::Test,
OfflinePageMetadataStoreTestUtil* store_test_util() {
return &store_test_util_;
}
- SystemDownloadManagerStub* download_manager_stub() {
+ StubSystemDownloadManager* download_manager_stub() {
return download_manager_stub_;
}
OfflinePageItemGenerator* page_generator() { return &generator_; }
@@ -162,26 +162,12 @@ class OfflinePageModelTaskifiedTest : public testing::Test,
return model_->last_maintenance_tasks_schedule_time_;
}
- std::unique_ptr<OfflinePageThumbnail> GetThumbnailSync(int64_t offline_id) {
- bool called = false;
- std::unique_ptr<OfflinePageThumbnail> result;
- auto callback = base::BindLambdaForTesting(
- [&](std::unique_ptr<OfflinePageThumbnail> thumbnail) {
- called = true;
- result = std::move(thumbnail);
- });
- model_->GetThumbnailByOfflineId(offline_id, callback);
- PumpLoop();
- EXPECT_TRUE(called);
- return result;
- }
-
private:
scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
base::ThreadTaskRunnerHandle task_runner_handle_;
std::unique_ptr<OfflinePageModelTaskified> model_;
OfflinePageMetadataStoreTestUtil store_test_util_;
- SystemDownloadManagerStub* download_manager_stub_;
+ StubSystemDownloadManager* download_manager_stub_;
OfflinePageItemGenerator generator_;
std::unique_ptr<base::HistogramTester> histogram_tester_;
base::ScopedTempDir temporary_dir_;
@@ -243,7 +229,7 @@ void OfflinePageModelTaskifiedTest::BuildStore() {
void OfflinePageModelTaskifiedTest::BuildModel() {
ASSERT_TRUE(store_test_util_.store());
// Keep a copy of the system download manager stub to test against.
- download_manager_stub_ = new SystemDownloadManagerStub(kDownloadId, true);
+ download_manager_stub_ = new StubSystemDownloadManager(kDownloadId, true);
auto archive_manager = std::make_unique<ArchiveManager>(
temporary_dir_path(), private_archive_dir_path(),
public_archive_dir_path(), base::ThreadTaskRunnerHandle::Get());
@@ -1666,7 +1652,8 @@ TEST_F(OfflinePageModelTaskifiedTest, MaintenanceTasksAreDisabled) {
0);
}
-TEST_F(OfflinePageModelTaskifiedTest, StoreAndGetThumbnail) {
+TEST_F(OfflinePageModelTaskifiedTest, StoreAndCheckThumbnail) {
+ // Store a thumbnail.
OfflinePageThumbnail thumb;
thumb.offline_id = 1;
thumb.expiration = base::Time::Now();
@@ -1675,12 +1662,21 @@ TEST_F(OfflinePageModelTaskifiedTest, StoreAndGetThumbnail) {
EXPECT_CALL(*this, ThumbnailAdded(_, thumb));
PumpLoop();
+ // Check it exists
+ bool thumbnail_exists = false;
+ auto exists_callback = base::BindLambdaForTesting(
+ [&](bool exists) { thumbnail_exists = exists; });
+ model()->HasThumbnailForOfflineId(thumb.offline_id, exists_callback);
+ PumpLoop();
+ EXPECT_TRUE(thumbnail_exists);
+
+ // Obtain its data.
std::unique_ptr<OfflinePageThumbnail> result_thumbnail;
- auto callback = base::BindLambdaForTesting(
+ auto data_callback = base::BindLambdaForTesting(
[&](std::unique_ptr<OfflinePageThumbnail> result) {
result_thumbnail = std::move(result);
});
- model()->GetThumbnailByOfflineId(thumb.offline_id, callback);
+ model()->GetThumbnailByOfflineId(thumb.offline_id, data_callback);
PumpLoop();
EXPECT_EQ(thumb, *result_thumbnail);
}
diff --git a/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task.cc b/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
index 6efa18e7de9..1133faaeb55 100644
--- a/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
+++ b/chromium/components/offline_pages/core/model/persistent_page_consistency_check_task.cc
@@ -220,12 +220,8 @@ PersistentPageConsistencyCheckTask::~PersistentPageConsistencyCheckTask() =
default;
void PersistentPageConsistencyCheckTask::Run() {
- std::vector<std::string> namespaces = policy_controller_->GetAllNamespaces();
- std::vector<std::string> persistent_namespaces;
- for (const auto& name_space : namespaces) {
- if (!policy_controller_->IsRemovedOnCacheReset(name_space))
- persistent_namespaces.push_back(name_space);
- }
+ std::vector<std::string> persistent_namespaces =
+ policy_controller_->GetNamespacesForUserRequestedDownload();
store_->Execute(base::BindOnce(&PersistentPageConsistencyCheckSync, store_,
archive_manager_->GetPrivateArchivesDir(),
diff --git a/chromium/components/offline_pages/core/model/startup_maintenance_task.cc b/chromium/components/offline_pages/core/model/startup_maintenance_task.cc
index 7e33a2ab035..20f3ffb614c 100644
--- a/chromium/components/offline_pages/core/model/startup_maintenance_task.cc
+++ b/chromium/components/offline_pages/core/model/startup_maintenance_task.cc
@@ -225,8 +225,7 @@ SyncOperationResult CheckTemporaryPageConsistencySync(
}
void ReportStorageUsageSync(sql::Connection* db,
- const std::vector<std::string>& namespaces,
- ArchiveManager* archive_manager) {
+ const std::vector<std::string>& namespaces) {
static const char kSql[] =
"SELECT sum(file_size) FROM " OFFLINE_PAGES_TABLE_NAME
" WHERE client_namespace = ?";
@@ -243,37 +242,31 @@ void ReportStorageUsageSync(sql::Connection* db,
}
}
-bool StartupMaintenanceSync(OfflinePageMetadataStoreSQL* store,
- ArchiveManager* archive_manager,
- ClientPolicyController* policy_controller,
- sql::Connection* db) {
+bool StartupMaintenanceSync(
+ const std::vector<std::string>& persistent_namespaces,
+ const std::vector<std::string>& temporary_namespaces,
+ const base::FilePath& temporary_archives_dir,
+ const base::FilePath& private_archives_dir,
+ sql::Connection* db) {
if (!db)
return false;
- std::vector<std::string> namespaces = policy_controller->GetAllNamespaces();
- std::vector<std::string> temporary_namespaces;
- std::vector<std::string> persistent_namespaces;
- for (const auto& name_space : namespaces) {
- if (!policy_controller->IsRemovedOnCacheReset(name_space))
- persistent_namespaces.push_back(name_space);
- else
- temporary_namespaces.push_back(name_space);
- }
-
// Clear temporary pages that are in legacy directory, which is also the
// directory that serves as the 'private' directory.
SyncOperationResult result = ClearLegacyPagesInPrivateDirSync(
- db, temporary_namespaces, persistent_namespaces,
- archive_manager->GetPrivateArchivesDir());
+ db, temporary_namespaces, persistent_namespaces, private_archives_dir);
// Clear temporary pages in cache directory.
- result = CheckTemporaryPageConsistencySync(
- db, temporary_namespaces, archive_manager->GetTemporaryArchivesDir());
+ result = CheckTemporaryPageConsistencySync(db, temporary_namespaces,
+ temporary_archives_dir);
UMA_HISTOGRAM_ENUMERATION("OfflinePages.ConsistencyCheck.Temporary.Result",
result, SyncOperationResult::RESULT_COUNT);
- // Report storage usage UMA.
- ReportStorageUsageSync(db, namespaces, archive_manager);
+ // Report storage usage UMA, |temporary_namespaces| + |persistent_namespaces|
+ // should be all namespaces. This is implicitly checked by the
+ // TestReportStorageUsage unit test.
+ ReportStorageUsageSync(db, temporary_namespaces);
+ ReportStorageUsageSync(db, persistent_namespaces);
return true;
}
@@ -298,9 +291,18 @@ StartupMaintenanceTask::~StartupMaintenanceTask() = default;
void StartupMaintenanceTask::Run() {
TRACE_EVENT_ASYNC_BEGIN0("offline_pages", "StartupMaintenanceTask running",
this);
+ std::vector<std::string> all_namespaces =
+ policy_controller_->GetAllNamespaces();
+ std::vector<std::string> temporary_namespaces =
+ policy_controller_->GetNamespacesRemovedOnCacheReset();
+ std::vector<std::string> persistent_namespaces =
+ policy_controller_->GetNamespacesForUserRequestedDownload();
+
store_->Execute(
- base::BindOnce(&StartupMaintenanceSync, store_, archive_manager_,
- policy_controller_),
+ base::BindOnce(&StartupMaintenanceSync, persistent_namespaces,
+ temporary_namespaces,
+ archive_manager_->GetTemporaryArchivesDir(),
+ archive_manager_->GetPrivateArchivesDir()),
base::BindOnce(&StartupMaintenanceTask::OnStartupMaintenanceDone,
weak_ptr_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/offline_pages/core/model/store_thumbnail_task.cc b/chromium/components/offline_pages/core/model/store_thumbnail_task.cc
index 113c220137c..8a153a5ed2a 100644
--- a/chromium/components/offline_pages/core/model/store_thumbnail_task.cc
+++ b/chromium/components/offline_pages/core/model/store_thumbnail_task.cc
@@ -16,6 +16,8 @@ namespace {
bool StoreThumbnailSync(const OfflinePageThumbnail& thumbnail,
sql::Connection* db) {
+ if (!db)
+ return false;
static const char kSql[] =
"INSERT OR REPLACE INTO page_thumbnails (offline_id, expiration, "
"thumbnail) VALUES (?, ?, ?)";
diff --git a/chromium/components/offline_pages/core/model/store_thumbnail_task_unittest.cc b/chromium/components/offline_pages/core/model/store_thumbnail_task_unittest.cc
index de271063a8e..f5b9b6981ae 100644
--- a/chromium/components/offline_pages/core/model/store_thumbnail_task_unittest.cc
+++ b/chromium/components/offline_pages/core/model/store_thumbnail_task_unittest.cc
@@ -10,6 +10,7 @@
#include "base/test/mock_callback.h"
#include "components/offline_pages/core/model/get_thumbnail_task.h"
#include "components/offline_pages/core/model/model_task_test_base.h"
+#include "components/offline_pages/core/offline_page_metadata_store_sql.h"
#include "components/offline_pages/core/offline_store_utils.h"
namespace offline_pages {
@@ -67,5 +68,16 @@ TEST_F(StoreThumbnailTaskTest, AlreadyExists) {
EXPECT_EQ(thumb, MustReadThumbnail(thumb.offline_id));
}
+TEST_F(StoreThumbnailTaskTest, DbConnectionIsNull) {
+ store()->SetStateForTesting(StoreState::FAILED_LOADING, true);
+ OfflinePageThumbnail thumb;
+ thumb.offline_id = 1;
+ thumb.expiration = store_utils::FromDatabaseTime(1234);
+ thumb.thumbnail = "123abc";
+ base::MockCallback<StoreThumbnailTask::CompleteCallback> callback;
+ EXPECT_CALL(callback, Run(false)).Times(1);
+ RunTask(std::make_unique<StoreThumbnailTask>(store(), thumb, callback.Get()));
+}
+
} // namespace
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_archiver_unittest.cc b/chromium/components/offline_pages/core/offline_page_archiver_unittest.cc
index b0ce07036a5..a56f60b925e 100644
--- a/chromium/components/offline_pages/core/offline_page_archiver_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_archiver_unittest.cc
@@ -8,10 +8,11 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/model/offline_page_item_generator.h"
-#include "components/offline_pages/core/system_download_manager_stub.h"
+#include "components/offline_pages/core/stub_system_download_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -105,7 +106,7 @@ TEST_F(OfflinePageArchiverTest, PublishArchive) {
base::FilePath new_file_path =
public_archive_dir_path().Append(offline_page.file_path.BaseName());
std::unique_ptr<SystemDownloadManager> download_manager(
- new SystemDownloadManagerStub(kDownloadId, true));
+ new StubSystemDownloadManager(kDownloadId, true));
archiver.PublishArchive(
offline_page, base::ThreadTaskRunnerHandle::Get(),
diff --git a/chromium/components/offline_pages/core/offline_page_feature.cc b/chromium/components/offline_pages/core/offline_page_feature.cc
index 5e237d6d938..f25efba9519 100644
--- a/chromium/components/offline_pages/core/offline_page_feature.cc
+++ b/chromium/components/offline_pages/core/offline_page_feature.cc
@@ -64,7 +64,7 @@ const base::Feature kOfflinePagesDescriptiveFailStatusFeature{
"OfflinePagesDescriptiveFailStatus", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kOfflinePagesDescriptivePendingStatusFeature{
- "OfflinePagesDescriptivePendingStatus", base::FEATURE_DISABLED_BY_DEFAULT};
+ "OfflinePagesDescriptivePendingStatus", base::FEATURE_ENABLED_BY_DEFAULT};
const base::Feature kOfflinePagesInDownloadHomeOpenInCctFeature{
"OfflinePagesInDownloadHomeOpenInCct", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chromium/components/offline_pages/core/offline_page_feature_unittest.cc b/chromium/components/offline_pages/core/offline_page_feature_unittest.cc
index 7828ab1f4f6..e68635d84c9 100644
--- a/chromium/components/offline_pages/core/offline_page_feature_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_feature_unittest.cc
@@ -136,14 +136,14 @@ TEST(OfflinePageFeatureTest, OfflinePagesDescriptiveFailStatus) {
}
TEST(OfflinePageFeatureTest, OfflinePagesDescriptivePendingStatus) {
- // Disabled by default.
- EXPECT_FALSE(offline_pages::IsOfflinePagesDescriptivePendingStatusEnabled());
+ // Enabled by default.
+ EXPECT_TRUE(offline_pages::IsOfflinePagesDescriptivePendingStatusEnabled());
// Check if helper method works correctly when the features is enabled.
base::test::ScopedFeatureList scoped_feature_list;
- scoped_feature_list.InitAndEnableFeature(
+ scoped_feature_list.InitAndDisableFeature(
kOfflinePagesDescriptivePendingStatusFeature);
- EXPECT_TRUE(offline_pages::IsOfflinePagesDescriptivePendingStatusEnabled());
+ EXPECT_FALSE(offline_pages::IsOfflinePagesDescriptivePendingStatusEnabled());
}
TEST(OfflinePageFeatureTest, AlternateDinoPage) {
diff --git a/chromium/components/offline_pages/core/offline_page_item.cc b/chromium/components/offline_pages/core/offline_page_item.cc
index 5790e3c3401..e32196f15b5 100644
--- a/chromium/components/offline_pages/core/offline_page_item.cc
+++ b/chromium/components/offline_pages/core/offline_page_item.cc
@@ -74,7 +74,7 @@ OfflinePageItem::~OfflinePageItem() {}
bool OfflinePageItem::operator==(const OfflinePageItem& other) const {
return url == other.url && offline_id == other.offline_id &&
client_id == other.client_id && file_path == other.file_path &&
- creation_time == other.creation_time &&
+ file_size == other.file_size && creation_time == other.creation_time &&
last_access_time == other.last_access_time &&
access_count == other.access_count && title == other.title &&
flags == other.flags && original_url == other.original_url &&
diff --git a/chromium/components/offline_pages/core/offline_page_model.cc b/chromium/components/offline_pages/core/offline_page_model.cc
index 08d81b29367..a9d7d9c297b 100644
--- a/chromium/components/offline_pages/core/offline_page_model.cc
+++ b/chromium/components/offline_pages/core/offline_page_model.cc
@@ -27,11 +27,13 @@ OfflinePageModel::DeletedPageInfo::DeletedPageInfo(
int64_t offline_id,
int64_t system_download_id,
const ClientId& client_id,
- const std::string& request_origin)
+ const std::string& request_origin,
+ const GURL& url)
: offline_id(offline_id),
system_download_id(system_download_id),
client_id(client_id),
- request_origin(request_origin) {}
+ request_origin(request_origin),
+ url(url) {}
// static
bool OfflinePageModel::CanSaveURL(const GURL& url) {
diff --git a/chromium/components/offline_pages/core/offline_page_model.h b/chromium/components/offline_pages/core/offline_page_model.h
index 141e59c74c1..d953922f628 100644
--- a/chromium/components/offline_pages/core/offline_page_model.h
+++ b/chromium/components/offline_pages/core/offline_page_model.h
@@ -82,7 +82,8 @@ class OfflinePageModel : public base::SupportsUserData, public KeyedService {
DeletedPageInfo(int64_t offline_id,
int64_t system_download_id,
const ClientId& client_id,
- const std::string& request_origin);
+ const std::string& request_origin,
+ const GURL& url);
// The ID of the deleted page.
int64_t offline_id;
// The system download manager id of the deleted page. This will be 0 if
@@ -92,6 +93,8 @@ class OfflinePageModel : public base::SupportsUserData, public KeyedService {
ClientId client_id;
// The origin that the page was saved on behalf of.
std::string request_origin;
+ // URL of the page that was deleted.
+ GURL url;
};
// Observer of the OfflinePageModel.
@@ -169,54 +172,52 @@ class OfflinePageModel : public base::SupportsUserData, public KeyedService {
const DeletePageCallback& callback) = 0;
// Gets all offline pages.
- virtual void GetAllPages(const MultipleOfflinePageItemCallback& callback) = 0;
+ virtual void GetAllPages(MultipleOfflinePageItemCallback callback) = 0;
// Returns zero or one offline pages associated with a specified |offline_id|.
- virtual void GetPageByOfflineId(
- int64_t offline_id,
- const SingleOfflinePageItemCallback& callback) = 0;
+ virtual void GetPageByOfflineId(int64_t offline_id,
+ SingleOfflinePageItemCallback callback) = 0;
// Returns zero or one offline page associated with a specified |guid|.
// Note: this should only be used for the case that |guid| can uniquely
// identify the page regardless its namespace.
virtual void GetPageByGuid(const std::string& guid,
- const SingleOfflinePageItemCallback& callback) = 0;
+ SingleOfflinePageItemCallback callback) = 0;
// Retrieves all pages associated with any of |client_ids|.
virtual void GetPagesByClientIds(
const std::vector<ClientId>& client_ids,
- const MultipleOfflinePageItemCallback& callback) = 0;
+ MultipleOfflinePageItemCallback callback) = 0;
// Returns the offline pages that are related to |url|. |url_search_mode|
// controls how the url match is done. See URLSearchMode for more details.
- virtual void GetPagesByURL(
- const GURL& url,
- URLSearchMode url_search_mode,
- const MultipleOfflinePageItemCallback& callback) = 0;
+ virtual void GetPagesByURL(const GURL& url,
+ URLSearchMode url_search_mode,
+ MultipleOfflinePageItemCallback callback) = 0;
// Returns the offline pages that belong in |name_space|.
virtual void GetPagesByNamespace(
const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback) = 0;
+ MultipleOfflinePageItemCallback callback) = 0;
// Returns the offline pages that are removed when cache is reset.
virtual void GetPagesRemovedOnCacheReset(
- const MultipleOfflinePageItemCallback& callback) = 0;
+ MultipleOfflinePageItemCallback callback) = 0;
// Returns the offline pages that are visible in download manager UI.
virtual void GetPagesSupportedByDownloads(
- const MultipleOfflinePageItemCallback& callback) = 0;
+ MultipleOfflinePageItemCallback callback) = 0;
// Retrieves all pages associated with the |request_origin|.
virtual void GetPagesByRequestOrigin(
const std::string& request_origin,
- const MultipleOfflinePageItemCallback& callback) = 0;
+ MultipleOfflinePageItemCallback callback) = 0;
// Returns zero or one offline pages associated with a specified |digest|.
virtual void GetPageBySizeAndDigest(
int64_t file_size,
const std::string& digest,
- const SingleOfflinePageItemCallback& callback) = 0;
+ SingleOfflinePageItemCallback callback) = 0;
// Gets all offline ids where the offline page has the matching client id.
virtual void GetOfflineIdsForClientId(
@@ -231,6 +232,12 @@ class OfflinePageModel : public base::SupportsUserData, public KeyedService {
virtual void GetThumbnailByOfflineId(int64_t offline_id,
GetThumbnailCallback callback) = 0;
+ // Checks if a thumbnail for a specific |offline_id| exists in the
+ // page_thumbnails table. Calls callback with the bool result.
+ virtual void HasThumbnailForOfflineId(
+ int64_t offline_id,
+ base::OnceCallback<void(bool)> callback) = 0;
+
// Publishes an offline page from the internal offline page directory. This
// includes putting it in a public directory, updating the system download
// manager, if any, and updating the offline page model database.
diff --git a/chromium/components/offline_pages/core/offline_page_model_event_logger.cc b/chromium/components/offline_pages/core/offline_page_model_event_logger.cc
index 695d355eb95..63ae0ba48f9 100644
--- a/chromium/components/offline_pages/core/offline_page_model_event_logger.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_event_logger.cc
@@ -18,20 +18,4 @@ void OfflinePageModelEventLogger::RecordPageDeleted(int64_t offline_id) {
RecordActivity("Page with ID " + id_str + " has been deleted");
}
-void OfflinePageModelEventLogger::RecordPageExpired(int64_t offline_id) {
- std::string id_str = std::to_string(offline_id);
- RecordActivity("Page with ID " + id_str + " has been expired");
-}
-
-void OfflinePageModelEventLogger::RecordStoreClearError() {
- RecordActivity("Offline store clear failed");
-}
-
-void OfflinePageModelEventLogger::RecordStoreCleared() {
- RecordActivity("Offline store cleared");
-}
-
-void OfflinePageModelEventLogger::RecordStoreReloadError() {
- RecordActivity("There was an error reloading the offline store");
-}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_model_event_logger.h b/chromium/components/offline_pages/core/offline_page_model_event_logger.h
index ae3a05a6691..f976dd2d76b 100644
--- a/chromium/components/offline_pages/core/offline_page_model_event_logger.h
+++ b/chromium/components/offline_pages/core/offline_page_model_event_logger.h
@@ -19,18 +19,6 @@ class OfflinePageModelEventLogger : public OfflineEventLogger {
// Records that a page with |offline_id| has been deleted.
void RecordPageDeleted(int64_t offline_id);
-
- // Records that a page with |offline_id| has been expired.
- void RecordPageExpired(int64_t offline_id);
-
- // Records that the offline store has been cleared.
- void RecordStoreCleared();
-
- // Records that there was an error when clearing the offline store.
- void RecordStoreClearError();
-
- // Records that there was an error when reloading the offline store.
- void RecordStoreReloadError();
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/offline_page_model_event_logger_unittest.cc b/chromium/components/offline_pages/core/offline_page_model_event_logger_unittest.cc
index 5f7b690ea6b..d416c93833c 100644
--- a/chromium/components/offline_pages/core/offline_page_model_event_logger_unittest.cc
+++ b/chromium/components/offline_pages/core/offline_page_model_event_logger_unittest.cc
@@ -17,11 +17,6 @@ const int kTimeLength = 21;
const char kPageSaved[] =
"http://www.wikipedia.org is saved at last_n with id 12345";
const char kPageDeleted[] = "Page with ID 12345 has been deleted";
-const char kPageExpired[] = "Page with ID 12345 has been expired";
-const char kRecordStoreClearError[] = "Offline store clear failed";
-const char kRecordStoreCleared[] = "Offline store cleared";
-const char kRecordStoreReloadError[] =
- "There was an error reloading the offline store";
} // namespace
@@ -30,21 +25,13 @@ TEST(OfflinePageModelEventLoggerTest, RecordsWhenLoggingIsOn) {
std::vector<std::string> log;
logger.SetIsLogging(true);
- logger.RecordStoreCleared();
logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
logger.RecordPageDeleted(kOfflineId);
- logger.RecordPageExpired(kOfflineId);
- logger.RecordStoreClearError();
- logger.RecordStoreReloadError();
logger.GetLogs(&log);
- EXPECT_EQ(6u, log.size());
- EXPECT_EQ(std::string(kRecordStoreCleared), log[5].substr(kTimeLength));
- EXPECT_EQ(std::string(kPageSaved), log[4].substr(kTimeLength));
- EXPECT_EQ(std::string(kPageDeleted), log[3].substr(kTimeLength));
- EXPECT_EQ(std::string(kPageExpired), log[2].substr(kTimeLength));
- EXPECT_EQ(std::string(kRecordStoreClearError), log[1].substr(kTimeLength));
- EXPECT_EQ(std::string(kRecordStoreReloadError), log[0].substr(kTimeLength));
+ EXPECT_EQ(2u, log.size());
+ EXPECT_EQ(std::string(kPageSaved), log[1].substr(kTimeLength));
+ EXPECT_EQ(std::string(kPageDeleted), log[0].substr(kTimeLength));
}
TEST(OfflinePageModelEventLoggerTest, DoesNotRecordWhenLoggingIsOff) {
@@ -52,12 +39,8 @@ TEST(OfflinePageModelEventLoggerTest, DoesNotRecordWhenLoggingIsOff) {
std::vector<std::string> log;
logger.SetIsLogging(false);
- logger.RecordStoreCleared();
logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
logger.RecordPageDeleted(kOfflineId);
- logger.RecordPageExpired(kOfflineId);
- logger.RecordStoreClearError();
- logger.RecordStoreReloadError();
logger.GetLogs(&log);
EXPECT_EQ(0u, log.size());
@@ -69,7 +52,7 @@ TEST(OfflinePageModelEventLoggerTest, DoesNotExceedMaxSize) {
logger.SetIsLogging(true);
for (size_t i = 0; i < kMaxLogCount + 1; ++i) {
- logger.RecordStoreCleared();
+ logger.RecordPageSaved(kNamespace, kUrl, kOfflineId);
}
logger.GetLogs(&log);
diff --git a/chromium/components/offline_pages/core/offline_page_types.h b/chromium/components/offline_pages/core/offline_page_types.h
index 1c60e6279a9..591052ca574 100644
--- a/chromium/components/offline_pages/core/offline_page_types.h
+++ b/chromium/components/offline_pages/core/offline_page_types.h
@@ -100,9 +100,9 @@ typedef base::Callback<void(DeletePageResult)> DeletePageCallback;
typedef base::Callback<void(bool)> HasPagesCallback;
typedef base::Callback<void(const MultipleOfflineIdResult&)>
MultipleOfflineIdCallback;
-typedef base::Callback<void(const OfflinePageItem*)>
+typedef base::OnceCallback<void(const OfflinePageItem*)>
SingleOfflinePageItemCallback;
-typedef base::Callback<void(const MultipleOfflinePageItemResult&)>
+typedef base::OnceCallback<void(const MultipleOfflinePageItemResult&)>
MultipleOfflinePageItemCallback;
typedef base::Callback<bool(const GURL&)> UrlPredicate;
typedef base::Callback<void(int64_t)> SizeInBytesCallback;
diff --git a/chromium/components/offline_pages/core/prefetch/BUILD.gn b/chromium/components/offline_pages/core/prefetch/BUILD.gn
index bfaedd4fbe5..22c3e9e4cad 100644
--- a/chromium/components/offline_pages/core/prefetch/BUILD.gn
+++ b/chromium/components/offline_pages/core/prefetch/BUILD.gn
@@ -130,6 +130,10 @@ static_library("test_support") {
"prefetch_task_test_base.h",
"store/prefetch_store_test_util.cc",
"store/prefetch_store_test_util.h",
+ "test_download_client.cc",
+ "test_download_client.h",
+ "test_download_service.cc",
+ "test_download_service.h",
"test_offline_metrics_collector.h",
"test_prefetch_dispatcher.cc",
"test_prefetch_dispatcher.h",
@@ -141,12 +145,14 @@ static_library("test_support") {
"test_prefetch_importer.h",
"test_prefetch_network_request_factory.cc",
"test_prefetch_network_request_factory.h",
+ "test_util.cc",
]
deps = [
":prefetch",
"//base",
"//components/download/public/background_service:public",
+ "//components/download/public/background_service/test:test_support",
"//components/gcm_driver/instance_id",
"//components/keyed_service/core",
"//components/offline_pages/core",
@@ -206,8 +212,6 @@ source_set("unit_tests") {
"store/prefetch_store_schema_unittest.cc",
"store/prefetch_store_unittest.cc",
"suggested_articles_observer_unittest.cc",
- "test_download_client.cc",
- "test_download_client.h",
]
deps = [
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
index 07d6ee626f4..75e7b0460bf 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_request.cc
@@ -68,4 +68,4 @@ void GeneratePageBundleRequest::OnCompleted(PrefetchRequestStatus status,
callback_.Run(PrefetchRequestStatus::SUCCESS, operation_name, pages);
}
-} // offline_pages
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc
index 345d38bf66a..adc45fb0079 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.cc
@@ -8,7 +8,9 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/time/default_clock.h"
+#include "components/offline_pages/core/client_id.h"
#include "components/offline_pages/core/offline_store_utils.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
@@ -18,19 +20,32 @@
#include "sql/transaction.h"
namespace offline_pages {
+
+// A wrapper for two vectors, one with string URLs and one with offline and
+// client ids pairs, each holding data for the same set of prefetch items.
+struct GeneratePageBundleTask::UrlAndIds {
+ std::vector<std::string> urls;
+ PrefetchDispatcher::IdsVector ids;
+};
+
namespace {
+using UrlAndIds = GeneratePageBundleTask::UrlAndIds;
+
// Temporary storage for Urls metadata fetched from the storage.
struct FetchedUrl {
FetchedUrl() = default;
FetchedUrl(int64_t offline_id,
+ ClientId client_id,
const std::string& requested_url,
int generate_bundle_attempts)
: offline_id(offline_id),
+ client_id(client_id),
requested_url(requested_url),
generate_bundle_attempts(generate_bundle_attempts) {}
int64_t offline_id;
+ ClientId client_id;
std::string requested_url;
int generate_bundle_attempts;
};
@@ -58,7 +73,8 @@ bool UpdateStateSync(sql::Connection* db,
std::unique_ptr<std::vector<FetchedUrl>> FetchUrlsSync(sql::Connection* db) {
static const char kSql[] =
- "SELECT offline_id, requested_url, generate_bundle_attempts"
+ "SELECT offline_id, client_namespace, client_id, requested_url,"
+ " generate_bundle_attempts"
" FROM prefetch_items"
" WHERE state = ?"
" ORDER BY creation_time DESC";
@@ -67,10 +83,15 @@ std::unique_ptr<std::vector<FetchedUrl>> FetchUrlsSync(sql::Connection* db) {
auto urls = std::make_unique<std::vector<FetchedUrl>>();
while (statement.Step()) {
- urls->push_back(
- FetchedUrl(statement.ColumnInt64(0), // offline_id
- statement.ColumnString(1), // requested_url
- statement.ColumnInt(2))); // generate_bundle_attempts
+ urls->push_back(FetchedUrl(
+ // offline_id
+ statement.ColumnInt64(0),
+ // client_id
+ {statement.ColumnString(1), statement.ColumnString(2)},
+ // requested_url
+ statement.ColumnString(3),
+ // generate_bundle_attempts
+ statement.ColumnInt(4)));
}
return urls;
@@ -88,9 +109,8 @@ bool MarkUrlFinishedWithError(sql::Connection* db, const FetchedUrl& url) {
return statement.Run();
}
-std::unique_ptr<std::vector<std::string>> SelectUrlsToPrefetchSync(
- base::Clock* clock,
- sql::Connection* db) {
+std::unique_ptr<UrlAndIds> SelectUrlsToPrefetchSync(base::Clock* clock,
+ sql::Connection* db) {
if (!db)
return nullptr;
@@ -112,26 +132,29 @@ std::unique_ptr<std::vector<std::string>> SelectUrlsToPrefetchSync(
urls->resize(kMaxUrlsToSend);
}
- auto url_specs = std::make_unique<std::vector<std::string>>();
+ auto url_and_ids = std::make_unique<UrlAndIds>();
for (const auto& url : *urls) {
if (!UpdateStateSync(db, url.offline_id, clock))
return nullptr;
- url_specs->push_back(std::move(url.requested_url));
+ url_and_ids->urls.push_back(std::move(url.requested_url));
+ url_and_ids->ids.push_back({url.offline_id, std::move(url.client_id)});
}
if (!transaction.Commit())
return nullptr;
- return url_specs;
+ return url_and_ids;
}
} // namespace
GeneratePageBundleTask::GeneratePageBundleTask(
+ PrefetchDispatcher* prefetch_dispatcher,
PrefetchStore* prefetch_store,
PrefetchGCMHandler* gcm_handler,
PrefetchNetworkRequestFactory* request_factory,
const PrefetchRequestFinishedCallback& callback)
: clock_(base::DefaultClock::GetInstance()),
+ prefetch_dispatcher_(prefetch_dispatcher),
prefetch_store_(prefetch_store),
gcm_handler_(gcm_handler),
request_factory_(request_factory),
@@ -152,23 +175,30 @@ void GeneratePageBundleTask::SetClockForTesting(base::Clock* clock) {
}
void GeneratePageBundleTask::StartGeneratePageBundle(
- std::unique_ptr<std::vector<std::string>> urls) {
- if (!urls || urls->empty()) {
+ std::unique_ptr<UrlAndIds> url_and_ids) {
+ if (!url_and_ids) {
TaskComplete();
return;
}
+ DCHECK(!url_and_ids->urls.empty());
+ DCHECK_EQ(url_and_ids->urls.size(), url_and_ids->ids.size());
- gcm_handler_->GetGCMToken(
- base::Bind(&GeneratePageBundleTask::GotRegistrationId,
- weak_factory_.GetWeakPtr(), base::Passed(std::move(urls))));
+ gcm_handler_->GetGCMToken(base::AdaptCallbackForRepeating(base::BindOnce(
+ &GeneratePageBundleTask::GotRegistrationId, weak_factory_.GetWeakPtr(),
+ base::Passed(std::move(url_and_ids)))));
}
void GeneratePageBundleTask::GotRegistrationId(
- std::unique_ptr<std::vector<std::string>> urls,
+ std::unique_ptr<UrlAndIds> url_and_ids,
const std::string& id,
instance_id::InstanceID::Result result) {
+ DCHECK(url_and_ids);
// TODO(dimich): Add UMA reporting on instance_id::InstanceID::Result.
- request_factory_->MakeGeneratePageBundleRequest(*urls, id, callback_);
+ request_factory_->MakeGeneratePageBundleRequest(url_and_ids->urls, id,
+ callback_);
+ prefetch_dispatcher_->GeneratePageBundleRequested(
+ std::make_unique<PrefetchDispatcher::IdsVector>(
+ std::move(url_and_ids->ids)));
TaskComplete();
}
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h
index 7228eec6d34..04301649fdc 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task.h
@@ -12,6 +12,7 @@
#include "base/memory/weak_ptr.h"
#include "base/time/clock.h"
#include "components/gcm_driver/instance_id/instance_id.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_types.h"
#include "components/offline_pages/core/task.h"
@@ -24,7 +25,10 @@ class PrefetchStore;
// determined are viable to prefetch.
class GeneratePageBundleTask : public Task {
public:
- GeneratePageBundleTask(PrefetchStore* prefetch_store,
+ struct UrlAndIds;
+
+ GeneratePageBundleTask(PrefetchDispatcher* prefetch_dispatcher,
+ PrefetchStore* prefetch_store,
PrefetchGCMHandler* gcm_handler,
PrefetchNetworkRequestFactory* request_factory,
const PrefetchRequestFinishedCallback& callback);
@@ -36,13 +40,14 @@ class GeneratePageBundleTask : public Task {
void SetClockForTesting(base::Clock* clock);
private:
- void StartGeneratePageBundle(std::unique_ptr<std::vector<std::string>> urls);
- void GotRegistrationId(std::unique_ptr<std::vector<std::string>> urls,
+ void StartGeneratePageBundle(std::unique_ptr<UrlAndIds> url_and_ids);
+ void GotRegistrationId(std::unique_ptr<UrlAndIds> url_and_ids,
const std::string& id,
instance_id::InstanceID::Result result);
base::Clock* clock_;
+ PrefetchDispatcher* prefetch_dispatcher_;
PrefetchStore* prefetch_store_;
PrefetchGCMHandler* gcm_handler_;
PrefetchNetworkRequestFactory* request_factory_;
diff --git a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
index e185d99a1a5..0394acbacbc 100644
--- a/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/generate_page_bundle_task_unittest.cc
@@ -4,6 +4,8 @@
#include "components/offline_pages/core/prefetch/generate_page_bundle_task.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/test/mock_callback.h"
#include "base/test/simple_test_clock.h"
@@ -14,6 +16,7 @@
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_utils.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
#include "components/offline_pages/core/task.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -35,8 +38,11 @@ class GeneratePageBundleTaskTest : public PrefetchTaskTestBase {
TestPrefetchGCMHandler* gcm_handler() { return &gcm_handler_; }
+ TestPrefetchDispatcher* dispatcher() { return &dispatcher_; }
+
private:
TestPrefetchGCMHandler gcm_handler_;
+ TestPrefetchDispatcher dispatcher_;
};
TEST_F(GeneratePageBundleTaskTest, StoreFailure) {
@@ -44,17 +50,21 @@ TEST_F(GeneratePageBundleTaskTest, StoreFailure) {
base::MockCallback<PrefetchRequestFinishedCallback> callback;
RunTask(std::make_unique<GeneratePageBundleTask>(
- store(), gcm_handler(), prefetch_request_factory(), callback.Get()));
+ dispatcher(), store(), gcm_handler(), prefetch_request_factory(),
+ callback.Get()));
+ EXPECT_EQ(0, dispatcher()->generate_page_bundle_requested);
}
TEST_F(GeneratePageBundleTaskTest, EmptyTask) {
base::MockCallback<PrefetchRequestFinishedCallback> callback;
RunTask(std::make_unique<GeneratePageBundleTask>(
- store(), gcm_handler(), prefetch_request_factory(), callback.Get()));
+ dispatcher(), store(), gcm_handler(), prefetch_request_factory(),
+ callback.Get()));
EXPECT_FALSE(prefetch_request_factory()->HasOutstandingRequests());
auto requested_urls = prefetch_request_factory()->GetAllUrlsRequested();
EXPECT_TRUE(requested_urls->empty());
+ EXPECT_EQ(0, dispatcher()->generate_page_bundle_requested);
}
TEST_F(GeneratePageBundleTaskTest, TaskMakesNetworkRequest) {
@@ -62,6 +72,7 @@ TEST_F(GeneratePageBundleTaskTest, TaskMakesNetworkRequest) {
base::SimpleTestClock clock;
+ // This item will be sent with the bundle request.
PrefetchItem item1 =
item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
item1.freshness_time = clock.Now();
@@ -70,6 +81,8 @@ TEST_F(GeneratePageBundleTaskTest, TaskMakesNetworkRequest) {
clock.Advance(base::TimeDelta::FromSeconds(1));
+ // This item will also be sent with the bundle request but being the freshest
+ // it will come first in the list.
PrefetchItem item2 =
item_generator()->CreateItem(PrefetchItemState::NEW_REQUEST);
item1.freshness_time = clock.Now();
@@ -82,18 +95,33 @@ TEST_F(GeneratePageBundleTaskTest, TaskMakesNetworkRequest) {
PrefetchItem item3 =
item_generator()->CreateItem(PrefetchItemState::FINISHED);
EXPECT_TRUE(store_util()->InsertPrefetchItem(item3));
+ EXPECT_NE(item3.offline_id, item1.offline_id);
+ EXPECT_NE(item3.offline_id, item2.offline_id);
EXPECT_EQ(3, store_util()->CountPrefetchItems());
clock.Advance(base::TimeDelta::FromHours(1));
- GeneratePageBundleTask task(store(), gcm_handler(),
+ GeneratePageBundleTask task(dispatcher(), store(), gcm_handler(),
prefetch_request_factory(),
request_callback.Get());
task.SetClockForTesting(&clock);
RunTask(&task);
- auto requested_urls = prefetch_request_factory()->GetAllUrlsRequested();
+ // Note: even though the requested URLs checked further below are in undefined
+ // order (due to use of std::set) their order of requesting is known: latest
+ // creation dates should come first. But as these ids are stored in a
+ // std::vector we can rely on the order being correct.
+ EXPECT_EQ(1, dispatcher()->generate_page_bundle_requested);
+ EXPECT_EQ(2u, dispatcher()->ids_from_generate_page_bundle_requested->size());
+ EXPECT_EQ(std::make_pair(item1.offline_id, item1.client_id),
+ dispatcher()->ids_from_generate_page_bundle_requested->at(1));
+ EXPECT_EQ(std::make_pair(item2.offline_id, item2.client_id),
+ dispatcher()->ids_from_generate_page_bundle_requested->at(0));
+
+ std::unique_ptr<std::set<std::string>> requested_urls =
+ prefetch_request_factory()->GetAllUrlsRequested();
+ EXPECT_EQ(2u, requested_urls->size());
EXPECT_THAT(*requested_urls, Contains(item1.url.spec()));
EXPECT_THAT(*requested_urls, Contains(item2.url.spec()));
EXPECT_THAT(*requested_urls, Not(Contains(item3.url.spec())));
diff --git a/chromium/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h b/chromium/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h
index 91ee36ed327..87cefbdfa67 100644
--- a/chromium/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h
+++ b/chromium/components/offline_pages/core/prefetch/mock_thumbnail_fetcher.h
@@ -14,12 +14,14 @@ class MockThumbnailFetcher : public ThumbnailFetcher {
public:
MockThumbnailFetcher();
~MockThumbnailFetcher() override;
- MOCK_METHOD2(FetchSuggestionImageData_,
+ MOCK_METHOD3(FetchSuggestionImageData_,
void(const ClientId& client_id,
+ bool is_first_attempt,
ImageDataFetchedCallback* callback));
void FetchSuggestionImageData(const ClientId& client_id,
- ImageDataFetchedCallback callback) {
- FetchSuggestionImageData_(client_id, &callback);
+ bool is_first_attempt,
+ ImageDataFetchedCallback callback) override {
+ FetchSuggestionImageData_(client_id, is_first_attempt, &callback);
}
};
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h
index 0cfc6cfb588..f1e551d03f7 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher.h
@@ -44,6 +44,9 @@ class PrefetchService;
// Reconcilers during BackgroundTask processing.
class PrefetchDispatcher {
public:
+ // Vector of pairs of offline and client IDs.
+ using IdsVector = std::vector<std::pair<int64_t, ClientId>>;
+
virtual ~PrefetchDispatcher() = default;
// Initializes the dispatcher with its respective service instance. This must
@@ -104,6 +107,9 @@ class PrefetchDispatcher {
const std::map<std::string, std::pair<base::FilePath, int64_t>>&
success_downloads) = 0;
+ // Called when a GeneratePageBundle request has been sent.
+ virtual void GeneratePageBundleRequested(std::unique_ptr<IdsVector> ids) = 0;
+
// Called when a download is completed successfully or fails.
virtual void DownloadCompleted(
const PrefetchDownloadResult& download_result) = 0;
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index c1b0441c676..591627820bd 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -4,6 +4,7 @@
#include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
+#include <algorithm>
#include <utility>
#include "base/bind.h"
@@ -49,26 +50,11 @@
namespace offline_pages {
namespace {
+
void DeleteBackgroundTaskHelper(std::unique_ptr<PrefetchBackgroundTask> task) {
task.reset();
}
-void FetchComplete(OfflinePageModel* offline_model,
- int64_t offline_id,
- const std::string& image_data) {
- if (image_data.empty())
- return;
- // Thumbnails are marked to expire after this delta. Expired thumbnails are
- // eventually deleted if their offline_id does not correspond to an offline
- // item. Two days gives us plenty of time so that the prefetched item can be
- // imported into the offline item database.
- const base::TimeDelta kThumbnailExpirationDelta =
- base::TimeDelta::FromDays(2);
-
- offline_model->StoreThumbnail(OfflinePageThumbnail(
- offline_id, base::Time::Now() + kThumbnailExpirationDelta, image_data));
-}
-
} // namespace
PrefetchDispatcherImpl::PrefetchDispatcherImpl()
@@ -230,7 +216,7 @@ void PrefetchDispatcherImpl::QueueActionTasks() {
std::unique_ptr<Task> generate_page_bundle_task =
std::make_unique<GeneratePageBundleTask>(
- service_->GetPrefetchStore(), service_->GetPrefetchGCMHandler(),
+ this, service_->GetPrefetchStore(), service_->GetPrefetchGCMHandler(),
service_->GetPrefetchNetworkRequestFactory(),
base::Bind(
&PrefetchDispatcherImpl::DidGenerateBundleOrGetOperationRequest,
@@ -332,6 +318,14 @@ void PrefetchDispatcherImpl::CleanupDownloads(
success_downloads));
}
+void PrefetchDispatcherImpl::GeneratePageBundleRequested(
+ std::unique_ptr<PrefetchDispatcher::IdsVector> ids) {
+ // Reverse the order so that the fresher items are last. This is done because
+ // the ids are popped from the end of the vector.
+ std::reverse(ids->begin(), ids->end());
+ FetchThumbnails(std::move(ids), /* is_first_attempt= */ true);
+}
+
void PrefetchDispatcherImpl::DownloadCompleted(
const PrefetchDownloadResult& download_result) {
if (!service_->GetPrefetchConfiguration()->IsPrefetchingEnabled())
@@ -353,12 +347,9 @@ void PrefetchDispatcherImpl::DownloadCompleted(
void PrefetchDispatcherImpl::ItemDownloaded(int64_t offline_id,
const ClientId& client_id) {
- DCHECK(client_id.name_space == kSuggestedArticlesNamespace);
- auto complete_callback = base::BindOnce(
- &FetchComplete, base::Unretained(service_->GetOfflinePageModel()),
- offline_id);
- service_->GetThumbnailFetcher()->FetchSuggestionImageData(
- client_id, std::move(complete_callback));
+ auto ids = std::make_unique<IdsVector>();
+ ids->emplace_back(offline_id, client_id);
+ FetchThumbnails(std::move(ids), /* is_first_attempt= */ false);
}
void PrefetchDispatcherImpl::ArchiveImported(int64_t offline_id, bool success) {
@@ -396,4 +387,58 @@ void PrefetchDispatcherImpl::LogRequestResult(
}
}
+void PrefetchDispatcherImpl::FetchThumbnails(
+ std::unique_ptr<PrefetchDispatcher::IdsVector> remaining_ids,
+ bool is_first_attempt) {
+ if (remaining_ids->empty())
+ return;
+
+ int64_t offline_id = remaining_ids->back().first;
+ ClientId client_id = std::move(remaining_ids->back().second);
+ DCHECK(client_id.name_space == kSuggestedArticlesNamespace);
+ remaining_ids->pop_back();
+
+ service_->GetOfflinePageModel()->HasThumbnailForOfflineId(
+ offline_id,
+ base::BindOnce(&PrefetchDispatcherImpl::ThumbnailExistenceChecked,
+ base::Unretained(this), offline_id, std::move(client_id),
+ std::move(remaining_ids), is_first_attempt));
+}
+
+void PrefetchDispatcherImpl::ThumbnailExistenceChecked(
+ const int64_t offline_id,
+ ClientId client_id,
+ std::unique_ptr<PrefetchDispatcher::IdsVector> remaining_ids,
+ bool is_first_attempt,
+ bool thumbnail_exists) {
+ if (thumbnail_exists) {
+ FetchThumbnails(std::move(remaining_ids), is_first_attempt);
+ } else {
+ auto complete_callback = base::BindOnce(
+ &PrefetchDispatcherImpl::ThumbnailFetchComplete, base::Unretained(this),
+ offline_id, std::move(remaining_ids), is_first_attempt);
+ service_->GetThumbnailFetcher()->FetchSuggestionImageData(
+ client_id, is_first_attempt, std::move(complete_callback));
+ }
+}
+
+void PrefetchDispatcherImpl::ThumbnailFetchComplete(
+ const int64_t offline_id,
+ std::unique_ptr<PrefetchDispatcher::IdsVector> remaining_ids,
+ bool is_first_attempt,
+ const std::string& image_data) {
+ // Thumbnails are marked to expire after this delta. Expired thumbnails are
+ // eventually deleted if their offline_id does not correspond to an offline
+ // item. Two days gives us plenty of time so that the prefetched item can be
+ // imported into the offline item database.
+ const base::TimeDelta kThumbnailExpirationDelta =
+ base::TimeDelta::FromDays(2);
+
+ if (!image_data.empty()) {
+ service_->GetOfflinePageModel()->StoreThumbnail(OfflinePageThumbnail(
+ offline_id, base::Time::Now() + kThumbnailExpirationDelta, image_data));
+ }
+ FetchThumbnails(std::move(remaining_ids), is_first_attempt);
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 52535b16899..3cb1afdad36 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -45,6 +45,7 @@ class PrefetchDispatcherImpl : public PrefetchDispatcher,
const std::set<std::string>& outstanding_download_ids,
const std::map<std::string, std::pair<base::FilePath, int64_t>>&
success_downloads) override;
+ void GeneratePageBundleRequested(std::unique_ptr<IdsVector> ids) override;
void DownloadCompleted(
const PrefetchDownloadResult& download_result) override;
void ItemDownloaded(int64_t offline_id, const ClientId& client_id) override;
@@ -82,6 +83,30 @@ class PrefetchDispatcherImpl : public PrefetchDispatcher,
// becomes idle and any task called SchedulePipelineProcessing() before.
void QueueActionTasks();
+ // The methods below control the downloading of thumbnails for the provided
+ // prefetch items IDs. They are called multiple times for the same article,
+ // when they reach different points in the pipeline to increase the likeliness
+ // of the thumbnail to be available. The existence of the thumbnail is
+ // verified to avoid re-downloads.
+ // Also, even though unlikely, concurrent calls to these methods are
+ // supported. They will generate simultaneous download attempts but there will
+ // be no impact in the consistency of stored data.
+ // TODO(carlosk): This logic has become complex and holds too much state
+ // throughout the calls. It should be moved into a separate class (possibly
+ // internal to the implementation) to make it easier to maintain and
+ // understand.
+ void FetchThumbnails(std::unique_ptr<IdsVector> remaining_ids,
+ bool is_first_attempt);
+ void ThumbnailExistenceChecked(const int64_t offline_id,
+ ClientId client_id,
+ std::unique_ptr<IdsVector> remaining_ids,
+ bool is_first_attempt,
+ bool thumbnail_exists);
+ void ThumbnailFetchComplete(const int64_t offline_id,
+ std::unique_ptr<IdsVector> remaining_ids,
+ bool is_first_attempt,
+ const std::string& image_data);
+
PrefetchService* service_;
TaskQueue task_queue_;
bool needs_pipeline_processing_ = false;
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
index 772938a532e..20ec61e57e3 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_dispatcher_impl_unittest.cc
@@ -4,8 +4,10 @@
#include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "components/offline_pages/core/offline_event_logger.h"
@@ -16,6 +18,8 @@
#include "components/offline_pages/core/prefetch/prefetch_background_task.h"
#include "components/offline_pages/core/prefetch/prefetch_configuration.h"
#include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
+#include "components/offline_pages/core/prefetch/prefetch_importer_impl.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
#include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
#include "components/offline_pages/core/prefetch/prefetch_request_test_base.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
@@ -23,6 +27,7 @@
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
+#include "components/offline_pages/core/prefetch/test_download_service.h"
#include "components/offline_pages/core/prefetch/test_prefetch_network_request_factory.h"
#include "components/offline_pages/core/stub_offline_page_model.h"
#include "components/version_info/channel.h"
@@ -35,22 +40,53 @@
#include "url/gurl.h"
using testing::Contains;
+using ::testing::InSequence;
namespace offline_pages {
namespace {
using testing::_;
-const char kTestNamespace[] = "TestPrefetchClientNamespace";
const char kTestID[] = "id";
const GURL kTestURL("https://www.chromium.org");
const GURL kTestURL2("https://www.chromium.org/2");
const int64_t kTestOfflineID = 1111;
-const char kClientID1[] = "client-id-1";
+const char kClientID[] = "client-id-1";
+const char kOperationName[] = "operation-1";
+const char kBodyName[] = "body-1";
+const int64_t kBodyLength = 10;
+const char kBodyContent[] = "abcde12345";
+const base::Time kRenderTime = base::Time::Now();
+
+RenderPageInfo RenderInfo(const std::string& url) {
+ RenderPageInfo info;
+ info.url = url;
+ info.redirect_url = "";
+ info.status = RenderStatus::RENDERED;
+ info.body_name = kBodyName;
+ info.body_length = kBodyLength;
+ info.render_time = kRenderTime;
+ return info;
+}
class MockOfflinePageModel : public StubOfflinePageModel {
public:
+ MockOfflinePageModel(const base::FilePath& archive_directory) {
+ SetArchiveDirectory(archive_directory);
+ }
+ ~MockOfflinePageModel() override = default;
MOCK_METHOD1(StoreThumbnail, void(const OfflinePageThumbnail& thumb));
+ MOCK_METHOD2(HasThumbnailForOfflineId_,
+ void(int64_t offline_id,
+ base::OnceCallback<void(bool)>* callback));
+ MOCK_METHOD2(AddPage,
+ void(const OfflinePageItem& page,
+ const AddPageCallback& callback));
+ void HasThumbnailForOfflineId(
+ int64_t offline_id,
+ base::OnceCallback<void(bool)> callback) override {
+ HasThumbnailForOfflineId_(offline_id, &callback);
+ }
};
class TestPrefetchBackgroundTask : public PrefetchBackgroundTask {
@@ -82,6 +118,33 @@ class TestPrefetchConfiguration : public PrefetchConfiguration {
bool enabled_ = true;
};
+class FakePrefetchNetworkRequestFactory
+ : public TestPrefetchNetworkRequestFactory {
+ public:
+ void MakeGeneratePageBundleRequest(
+ const std::vector<std::string>& prefetch_urls,
+ const std::string& gcm_registration_id,
+ const PrefetchRequestFinishedCallback& callback) override {
+ TestPrefetchNetworkRequestFactory::MakeGeneratePageBundleRequest(
+ prefetch_urls, gcm_registration_id, callback);
+ if (!respond_to_generate_page_bundle_)
+ return;
+ std::vector<RenderPageInfo> pages;
+ for (const std::string& url : prefetch_urls) {
+ pages.push_back(RenderInfo(url));
+ }
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindRepeating(callback, PrefetchRequestStatus::SUCCESS,
+ kOperationName, pages));
+ }
+
+ void set_respond_to_generate_page_bundle(bool value) {
+ respond_to_generate_page_bundle_ = value;
+ }
+
+ private:
+ bool respond_to_generate_page_bundle_ = false;
+};
} // namespace
class PrefetchDispatcherTest : public PrefetchRequestTestBase {
@@ -116,7 +179,7 @@ class PrefetchDispatcherTest : public PrefetchRequestTestBase {
bool dispatcher_suspended() const { return dispatcher_->suspended_; }
TaskQueue* dispatcher_task_queue() { return &dispatcher_->task_queue_; }
PrefetchDispatcher* prefetch_dispatcher() { return dispatcher_; }
- TestPrefetchNetworkRequestFactory* network_request_factory() {
+ FakePrefetchNetworkRequestFactory* network_request_factory() {
return network_request_factory_;
}
@@ -125,15 +188,18 @@ class PrefetchDispatcherTest : public PrefetchRequestTestBase {
return reschedule_type_;
}
- void ExpectFetchThumbnail(const std::string& thumbnail_data) {
- EXPECT_CALL(*thumbnail_fetcher_,
- FetchSuggestionImageData_(
- ClientId(kSuggestedArticlesNamespace, kClientID1), _))
+ void ExpectFetchThumbnail(const std::string& thumbnail_data,
+ const bool first_attempt,
+ const char* client_id) {
+ EXPECT_CALL(
+ *thumbnail_fetcher_,
+ FetchSuggestionImageData_(
+ ClientId(kSuggestedArticlesNamespace, client_id), first_attempt, _))
.WillOnce(
testing::Invoke(testing::CallbackToFunctor(base::BindRepeating(
[](const std::string& thumbnail_data,
scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
- const ClientId& id,
+ const ClientId& id, bool is_first_attemp,
ThumbnailFetcher::ImageDataFetchedCallback* callback) {
task_runner->PostTask(
FROM_HERE,
@@ -142,12 +208,37 @@ class PrefetchDispatcherTest : public PrefetchRequestTestBase {
thumbnail_data, task_runner()))));
}
+ void ExpectHasThumbnailForOfflineId(int64_t offline_id, bool to_return) {
+ EXPECT_CALL(*offline_model_, HasThumbnailForOfflineId_(offline_id, _))
+ .WillOnce(
+ testing::Invoke(testing::CallbackToFunctor(base::BindRepeating(
+ [](bool to_return,
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner,
+ int64_t offline_id_,
+ base::OnceCallback<void(bool)>* callback) {
+ task_runner->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(*callback), to_return));
+ },
+ to_return, task_runner()))));
+ }
+
+ PrefetchDispatcherImpl* dispatcher() { return dispatcher_; }
+ PrefetchService* prefetch_service() { return taco_->prefetch_service(); }
+ TestDownloadService* download_service() { return taco_->download_service(); }
+
protected:
// Owned by |taco_|.
MockOfflinePageModel* offline_model_;
std::vector<PrefetchURL> test_urls_;
+ // Owned by |taco_|.
+ MockThumbnailFetcher* thumbnail_fetcher_;
+
+ PrefetchStoreTestUtil store_util_{task_runner()};
+ base::ScopedTempDir archive_directory_;
+
private:
std::unique_ptr<PrefetchServiceTestTaco> taco_;
@@ -156,9 +247,7 @@ class PrefetchDispatcherTest : public PrefetchRequestTestBase {
// Owned by |taco_|.
PrefetchDispatcherImpl* dispatcher_;
// Owned by |taco_|.
- TestPrefetchNetworkRequestFactory* network_request_factory_;
- // Owned by |taco_|.
- MockThumbnailFetcher* thumbnail_fetcher_;
+ FakePrefetchNetworkRequestFactory* network_request_factory_;
bool reschedule_called_ = false;
PrefetchBackgroundTaskRescheduleType reschedule_type_ =
@@ -170,9 +259,13 @@ PrefetchDispatcherTest::PrefetchDispatcherTest() {
}
void PrefetchDispatcherTest::SetUp() {
+ ASSERT_TRUE(archive_directory_.CreateUniqueTempDir());
+
dispatcher_ = new PrefetchDispatcherImpl();
- network_request_factory_ = new TestPrefetchNetworkRequestFactory();
+ network_request_factory_ = new FakePrefetchNetworkRequestFactory();
taco_.reset(new PrefetchServiceTestTaco);
+ store_util_.BuildStore();
+ taco_->SetPrefetchStore(store_util_.ReleaseStore());
taco_->SetPrefetchDispatcher(base::WrapUnique(dispatcher_));
taco_->SetPrefetchNetworkRequestFactory(
base::WrapUnique(network_request_factory_));
@@ -181,9 +274,14 @@ void PrefetchDispatcherTest::SetUp() {
auto thumbnail_fetcher = std::make_unique<MockThumbnailFetcher>();
thumbnail_fetcher_ = thumbnail_fetcher.get();
taco_->SetThumbnailFetcher(std::move(thumbnail_fetcher));
- auto model = std::make_unique<MockOfflinePageModel>();
+ auto model =
+ std::make_unique<MockOfflinePageModel>(archive_directory_.GetPath());
+
offline_model_ = model.get();
taco_->SetOfflinePageModel(std::move(model));
+ taco_->SetPrefetchImporter(std::make_unique<PrefetchImporterImpl>(
+ dispatcher_, offline_model_, task_runner()));
+
taco_->CreatePrefetchService();
ASSERT_TRUE(test_urls_.empty());
@@ -218,7 +316,8 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNotCrash) {
// with the state of adding tasks, and that the end state is we have tests
// that verify the proper tasks were added in the proper order at each wakeup
// signal of the dispatcher.
- prefetch_dispatcher()->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace,
+ test_urls_);
prefetch_dispatcher()->RemoveAllUnprocessedPrefetchURLs(
kSuggestedArticlesNamespace);
prefetch_dispatcher()->RemovePrefetchURLsByClientId(
@@ -226,7 +325,8 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNotCrash) {
}
TEST_F(PrefetchDispatcherTest, AddCandidatePrefetchURLsTask) {
- prefetch_dispatcher()->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace,
+ test_urls_);
EXPECT_TRUE(dispatcher_task_queue()->HasPendingTasks());
RunUntilIdle();
EXPECT_FALSE(dispatcher_task_queue()->HasPendingTasks());
@@ -234,10 +334,11 @@ TEST_F(PrefetchDispatcherTest, AddCandidatePrefetchURLsTask) {
}
TEST_F(PrefetchDispatcherTest, RemovePrefetchURLsByClientId) {
- prefetch_dispatcher()->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace,
+ test_urls_);
RunUntilIdle();
prefetch_dispatcher()->RemovePrefetchURLsByClientId(
- ClientId(kTestNamespace, test_urls_.front().id));
+ ClientId(kSuggestedArticlesNamespace, test_urls_.front().id));
EXPECT_TRUE(dispatcher_task_queue()->HasPendingTasks());
RunUntilIdle();
EXPECT_FALSE(dispatcher_task_queue()->HasPendingTasks());
@@ -249,7 +350,8 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNothingIfFeatureNotEnabled) {
disabled_feature_list.InitAndDisableFeature(kPrefetchingOfflinePagesFeature);
// Don't add a task for new prefetch URLs.
- prefetch_dispatcher()->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace,
+ test_urls_);
EXPECT_FALSE(dispatcher_task_queue()->HasRunningTask());
// Do nothing with a new background task.
@@ -263,7 +365,8 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNothingIfSettingsDoNotAllowIt) {
DisablePrefetchingInSettings();
// Don't add a task for new prefetch URLs.
- prefetch_dispatcher()->AddCandidatePrefetchURLs(kTestNamespace, test_urls_);
+ prefetch_dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace,
+ test_urls_);
EXPECT_FALSE(dispatcher_task_queue()->HasRunningTask());
// Do nothing with a new background task.
@@ -276,7 +379,7 @@ TEST_F(PrefetchDispatcherTest, DispatcherDoesNothingIfSettingsDoNotAllowIt) {
TEST_F(PrefetchDispatcherTest, DispatcherReleasesBackgroundTask) {
PrefetchURL prefetch_url(kTestID, kTestURL, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url));
RunUntilIdle();
// We start the background task, causing reconcilers and action tasks to be
@@ -307,7 +410,7 @@ TEST_F(PrefetchDispatcherTest, DispatcherReleasesBackgroundTask) {
TEST_F(PrefetchDispatcherTest, RetryWithBackoffAfterFailedNetworkRequest) {
PrefetchURL prefetch_url(kTestID, kTestURL, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url));
RunUntilIdle();
BeginBackgroundTask();
@@ -316,7 +419,7 @@ TEST_F(PrefetchDispatcherTest, RetryWithBackoffAfterFailedNetworkRequest) {
// Trigger another request to make sure we have more work to do.
PrefetchURL prefetch_url2(kTestID, kTestURL2, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
RunUntilIdle();
// This should trigger retry with backoff.
@@ -339,7 +442,7 @@ TEST_F(PrefetchDispatcherTest, RetryWithBackoffAfterFailedNetworkRequest) {
TEST_F(PrefetchDispatcherTest, RetryWithoutBackoffAfterFailedNetworkRequest) {
PrefetchURL prefetch_url(kTestID, kTestURL, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url));
RunUntilIdle();
BeginBackgroundTask();
@@ -348,7 +451,7 @@ TEST_F(PrefetchDispatcherTest, RetryWithoutBackoffAfterFailedNetworkRequest) {
// Trigger another request to make sure we have more work to do.
PrefetchURL prefetch_url2(kTestID, kTestURL2, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
// This should trigger retry without backoff.
RespondWithNetError(net::ERR_CONNECTION_CLOSED);
@@ -370,7 +473,7 @@ TEST_F(PrefetchDispatcherTest, RetryWithoutBackoffAfterFailedNetworkRequest) {
TEST_F(PrefetchDispatcherTest, SuspendAfterFailedNetworkRequest) {
PrefetchURL prefetch_url(kTestID, kTestURL, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url));
RunUntilIdle();
BeginBackgroundTask();
@@ -379,7 +482,7 @@ TEST_F(PrefetchDispatcherTest, SuspendAfterFailedNetworkRequest) {
// Trigger another request to make sure we have more work to do.
PrefetchURL prefetch_url2(kTestID, kTestURL2, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
EXPECT_FALSE(dispatcher_suspended());
@@ -405,7 +508,7 @@ TEST_F(PrefetchDispatcherTest, SuspendAfterFailedNetworkRequest) {
TEST_F(PrefetchDispatcherTest, SuspendRemovedAfterNewBackgroundTask) {
PrefetchURL prefetch_url(kTestID, kTestURL, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url));
RunUntilIdle();
BeginBackgroundTask();
@@ -431,7 +534,7 @@ TEST_F(PrefetchDispatcherTest, SuspendRemovedAfterNewBackgroundTask) {
// Trigger another request to make sure we have more work to do.
PrefetchURL prefetch_url2(kTestID, kTestURL2, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url2));
BeginBackgroundTask();
@@ -445,26 +548,133 @@ TEST_F(PrefetchDispatcherTest, SuspendRemovedAfterNewBackgroundTask) {
TEST_F(PrefetchDispatcherTest, NoNetworkRequestsAfterNewURLs) {
PrefetchURL prefetch_url(kTestID, kTestURL, base::string16());
prefetch_dispatcher()->AddCandidatePrefetchURLs(
- kTestNamespace, std::vector<PrefetchURL>(1, prefetch_url));
+ kSuggestedArticlesNamespace, std::vector<PrefetchURL>(1, prefetch_url));
RunUntilIdle();
// We should not have started GPB
EXPECT_EQ(nullptr, GetRunningFetcher());
}
-TEST_F(PrefetchDispatcherTest, ThumbnailFetchFailure) {
- ExpectFetchThumbnail("");
+TEST_F(PrefetchDispatcherTest, ThumbnailFetchFailure_ItemDownloaded) {
+ ExpectFetchThumbnail("", false, kClientID);
+ ExpectHasThumbnailForOfflineId(kTestOfflineID, false);
EXPECT_CALL(*offline_model_, StoreThumbnail(_)).Times(0);
prefetch_dispatcher()->ItemDownloaded(
- kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID1));
+ kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID));
}
-TEST_F(PrefetchDispatcherTest, ThumbnailFetchSuccess) {
+TEST_F(PrefetchDispatcherTest, ThumbnailFetchSuccess_ItemDownloaded) {
std::string kThumbnailData = "abc";
+ ExpectHasThumbnailForOfflineId(kTestOfflineID, false);
EXPECT_CALL(*offline_model_, StoreThumbnail(ValidThumbnail()));
- ExpectFetchThumbnail(kThumbnailData);
+ ExpectFetchThumbnail(kThumbnailData, false, kClientID);
+ prefetch_dispatcher()->ItemDownloaded(
+ kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID));
+}
+
+TEST_F(PrefetchDispatcherTest, ThumbnailAlreadyExists_ItemDownloaded) {
+ ExpectHasThumbnailForOfflineId(kTestOfflineID, true);
+ EXPECT_CALL(*thumbnail_fetcher_, FetchSuggestionImageData_(_, _, _)).Times(0);
+ EXPECT_CALL(*offline_model_, StoreThumbnail(_)).Times(0);
prefetch_dispatcher()->ItemDownloaded(
- kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID1));
+ kTestOfflineID, ClientId(kSuggestedArticlesNamespace, kClientID));
+}
+
+TEST_F(PrefetchDispatcherTest,
+ ThumbnailVariousCases_GeneratePageBundleRequested) {
+ // Covers all possible thumbnail cases with a single
+ // GeneratePageBundleRequested call: fetch succeeds (#1), fetch fails (#2),
+ // item already exists (#3).
+ const int64_t kTestOfflineID1 = 100;
+ const int64_t kTestOfflineID2 = 101;
+ const int64_t kTestOfflineID3 = 102;
+ const char kClientID1[] = "a";
+ const char kClientID2[] = "b";
+ const char kClientID3[] = "c";
+
+ InSequence in_sequence;
+ // Case #1.
+ ExpectHasThumbnailForOfflineId(kTestOfflineID1, false);
+ ExpectFetchThumbnail("abc", true, kClientID1);
+ EXPECT_CALL(*offline_model_, StoreThumbnail(_)).Times(1);
+ // Case #2.
+ ExpectHasThumbnailForOfflineId(kTestOfflineID2, false);
+ ExpectFetchThumbnail("", true, kClientID2);
+ // Case #3.
+ ExpectHasThumbnailForOfflineId(kTestOfflineID3, true);
+
+ auto prefetch_item_ids = std::make_unique<PrefetchDispatcher::IdsVector>();
+ prefetch_item_ids->emplace_back(
+ kTestOfflineID1, ClientId(kSuggestedArticlesNamespace, kClientID1));
+ prefetch_item_ids->emplace_back(
+ kTestOfflineID2, ClientId(kSuggestedArticlesNamespace, kClientID2));
+ prefetch_item_ids->emplace_back(
+ kTestOfflineID3, ClientId(kSuggestedArticlesNamespace, kClientID3));
+ prefetch_dispatcher()->GeneratePageBundleRequested(
+ std::move(prefetch_item_ids));
+}
+
+// Runs through the entire lifecycle of a successful prefetch item,
+// from GeneratePageBundle, GetOperation, download, import, and completion.
+TEST_F(PrefetchDispatcherTest, PrefetchItemFlow) {
+ auto get_item = [&]() {
+ std::set<PrefetchItem> items;
+ EXPECT_EQ(1ul, store_util_.GetAllItems(&items));
+ return *items.begin();
+ };
+ // The page should be added to the offline model. Return success through the
+ // callback, and store the page to added_page.
+ OfflinePageItem added_page;
+ EXPECT_CALL(*offline_model_, AddPage(_, _))
+ .WillOnce(testing::Invoke([&](const OfflinePageItem& page,
+ const AddPageCallback& callback) {
+ added_page = page;
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(callback, AddPageResult::SUCCESS, page.offline_id));
+ }));
+
+ network_request_factory()->set_respond_to_generate_page_bundle(true);
+ download_service()->SetTestFileData(kBodyContent);
+ std::vector<PrefetchURL> prefetch_urls;
+ prefetch_urls.push_back(PrefetchURL("url-1", GURL("http://www.url1.com"),
+ base::ASCIIToUTF16("URL 1")));
+
+ // Kick off the request.
+ dispatcher()->AddCandidatePrefetchURLs(kSuggestedArticlesNamespace,
+ prefetch_urls);
+
+ // Run the pipeline to completion.
+ RunUntilIdle();
+ PrefetchItem state1 = get_item();
+ BeginBackgroundTask();
+ RunUntilIdle();
+ PrefetchItem state2 = get_item();
+ BeginBackgroundTask();
+ RunUntilIdle();
+ PrefetchItem state3 = get_item();
+
+ // Check progression of item state. Log the states to help explain any failed
+ // expectations.
+ SCOPED_TRACE(testing::Message() << "\nstate1: " << state1 << "\nstate2: "
+ << state2 << "\nstate3: " << state3);
+
+ // State 1.
+ EXPECT_EQ(PrefetchItemState::NEW_REQUEST, state1.state);
+
+ // State 2.
+ EXPECT_EQ(PrefetchItemState::FINISHED, state2.state);
+ EXPECT_FALSE(state2.file_path.empty());
+ EXPECT_FALSE(added_page.file_path.empty());
+ std::string imported_file_contents;
+ EXPECT_TRUE(
+ base::ReadFileToString(added_page.file_path, &imported_file_contents));
+ EXPECT_EQ(kBodyContent, imported_file_contents);
+ EXPECT_EQ(kBodyLength, state2.file_size);
+
+ // State 3.
+ EXPECT_EQ(PrefetchItemState::ZOMBIE, state3.state);
+ EXPECT_EQ(PrefetchItemErrorCode::SUCCESS, state3.error_code);
}
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
index 7abe9f71cf8..c857544970d 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
@@ -43,9 +43,6 @@ PrefetchDownloaderImpl::PrefetchDownloaderImpl(
DCHECK(download_service);
}
-PrefetchDownloaderImpl::PrefetchDownloaderImpl(version_info::Channel channel)
- : download_service_(nullptr), channel_(channel), weak_ptr_factory_(this) {}
-
PrefetchDownloaderImpl::~PrefetchDownloaderImpl() = default;
void PrefetchDownloaderImpl::SetPrefetchService(PrefetchService* service) {
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
index 891a1087570..a61d58a1548 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
@@ -26,7 +26,6 @@ class DownloadService;
namespace offline_pages {
class PrefetchService;
-class PrefetchServiceTestTaco;
// Asynchronously downloads the archive.
class PrefetchDownloaderImpl : public PrefetchDownloader {
@@ -54,8 +53,6 @@ class PrefetchDownloaderImpl : public PrefetchDownloader {
void SetClockForTesting(base::Clock* clock);
private:
- friend class PrefetchServiceTestTaco;
-
enum class DownloadServiceStatus {
// The download service is booting up.
INITIALIZING,
@@ -66,9 +63,6 @@ class PrefetchDownloaderImpl : public PrefetchDownloader {
UNAVAILABLE,
};
- // For test only.
- explicit PrefetchDownloaderImpl(version_info::Channel channel);
-
// Callback for StartDownload.
void OnStartDownload(const std::string& download_id,
download::DownloadParams::StartResult result);
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_item.cc b/chromium/components/offline_pages/core/prefetch/prefetch_item.cc
index 8e332e99576..977aa59c411 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_item.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_item.cc
@@ -14,67 +14,8 @@ namespace offline_pages {
PrefetchItem::PrefetchItem() = default;
-PrefetchItem::PrefetchItem(const PrefetchItem& other) = default;
-
PrefetchItem::PrefetchItem(PrefetchItem&& other) = default;
PrefetchItem::~PrefetchItem() = default;
-PrefetchItem& PrefetchItem::operator=(const PrefetchItem& other) = default;
-
-PrefetchItem& PrefetchItem::operator=(PrefetchItem&& other) = default;
-
-bool PrefetchItem::operator==(const PrefetchItem& other) const {
- return offline_id == other.offline_id && guid == other.guid &&
- client_id == other.client_id && state == other.state &&
- url == other.url && final_archived_url == other.final_archived_url &&
- generate_bundle_attempts == other.generate_bundle_attempts &&
- get_operation_attempts == other.get_operation_attempts &&
- download_initiation_attempts == other.download_initiation_attempts &&
- operation_name == other.operation_name &&
- archive_body_name == other.archive_body_name &&
- archive_body_length == other.archive_body_length &&
- creation_time == other.creation_time &&
- freshness_time == other.freshness_time &&
- error_code == other.error_code && title == other.title &&
- file_path == other.file_path && file_size == other.file_size;
-}
-
-bool PrefetchItem::operator!=(const PrefetchItem& other) const {
- return !(*this == other);
-}
-
-bool PrefetchItem::operator<(const PrefetchItem& other) const {
- return offline_id < other.offline_id;
-}
-
-std::string PrefetchItem::ToString() const {
- std::string s("PrefetchItem(");
- s.append(base::Int64ToString(offline_id)).append(", ");
- s.append(guid).append(", ");
- s.append(client_id.ToString()).append(", ");
- s.append(base::IntToString(static_cast<int>(state))).append(", ");
- s.append(url.possibly_invalid_spec()).append(", ");
- s.append(final_archived_url.possibly_invalid_spec()).append(", ");
- s.append(base::IntToString(generate_bundle_attempts)).append(", ");
- s.append(base::IntToString(get_operation_attempts)).append(", ");
- s.append(base::IntToString(download_initiation_attempts)).append(", ");
- s.append(operation_name).append(", ");
- s.append(archive_body_name).append(", ");
- s.append(base::IntToString(archive_body_length)).append(", ");
- s.append(base::Int64ToString(store_utils::ToDatabaseTime(creation_time)))
- .append(", ");
- s.append(base::Int64ToString(store_utils::ToDatabaseTime(freshness_time)))
- .append(", ");
- s.append(base::IntToString(static_cast<int>(error_code))).append(", ");
- s.append(base::UTF16ToUTF8(title)).append(", ");
- s.append(file_path.AsUTF8Unsafe()).append(", ");
- s.append(base::IntToString(static_cast<int>(file_size))).append(")");
- return s;
-}
-
-std::ostream& operator<<(std::ostream& out, const PrefetchItem& pi) {
- return out << pi.ToString();
-}
-
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_item.h b/chromium/components/offline_pages/core/prefetch/prefetch_item.h
index 0baaf7c6a8a..e45066eb8a8 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_item.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_item.h
@@ -24,18 +24,17 @@ namespace offline_pages {
// inserted into) the persistent prefetching data store.
struct PrefetchItem {
PrefetchItem();
- PrefetchItem(const PrefetchItem& other);
PrefetchItem(PrefetchItem&& other);
~PrefetchItem();
+ // These methods are implemented in test_util.cc, for testing only.
+ PrefetchItem(const PrefetchItem& other);
PrefetchItem& operator=(const PrefetchItem& other);
PrefetchItem& operator=(PrefetchItem&& other);
-
bool operator==(const PrefetchItem& other) const;
bool operator!=(const PrefetchItem& other) const;
bool operator<(const PrefetchItem& other) const;
-
std::string ToString() const;
// Primary key that stays consistent between prefetch item, request and
@@ -116,6 +115,7 @@ struct PrefetchItem {
int64_t file_size = -1;
};
+// Provided for test only. Implemented in test_util.cc.
std::ostream& operator<<(std::ostream& out, const PrefetchItem& pi);
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
index 1eb5be7f0e3..d6d8a2dc690 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
@@ -22,6 +22,8 @@
#include "components/offline_pages/core/prefetch/prefetch_service_impl.h"
#include "components/offline_pages/core/prefetch/store/prefetch_store.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
+#include "components/offline_pages/core/prefetch/test_download_client.h"
+#include "components/offline_pages/core/prefetch/test_download_service.h"
#include "components/offline_pages/core/prefetch/test_offline_metrics_collector.h"
#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/test_prefetch_gcm_handler.h"
@@ -74,8 +76,12 @@ PrefetchServiceTestTaco::PrefetchServiceTestTaco() {
prefetch_store_ =
std::make_unique<PrefetchStore>(base::ThreadTaskRunnerHandle::Get());
suggested_articles_observer_ = std::make_unique<SuggestedArticlesObserver>();
- prefetch_downloader_ =
- base::WrapUnique(new PrefetchDownloaderImpl(kTestChannel));
+ download_service_ = std::make_unique<TestDownloadService>();
+ prefetch_downloader_ = base::WrapUnique(
+ new PrefetchDownloaderImpl(download_service_.get(), kTestChannel));
+ download_client_ =
+ std::make_unique<TestDownloadClient>(prefetch_downloader_.get());
+ download_service_->SetClient(download_client_.get());
prefetch_importer_ = std::make_unique<TestPrefetchImporter>();
// This sets up the testing articles as an empty vector, we can ignore the
// result here. This allows us to not create a ContentSuggestionsService.
@@ -92,30 +98,35 @@ PrefetchServiceTestTaco::~PrefetchServiceTestTaco() = default;
void PrefetchServiceTestTaco::SetOfflineMetricsCollector(
std::unique_ptr<OfflineMetricsCollector> metrics_collector) {
CHECK(!prefetch_service_);
+ CHECK(metrics_collector);
metrics_collector_ = std::move(metrics_collector);
}
void PrefetchServiceTestTaco::SetPrefetchDispatcher(
std::unique_ptr<PrefetchDispatcher> dispatcher) {
CHECK(!prefetch_service_);
+ CHECK(dispatcher);
dispatcher_ = std::move(dispatcher);
}
void PrefetchServiceTestTaco::SetPrefetchGCMHandler(
std::unique_ptr<PrefetchGCMHandler> gcm_handler) {
CHECK(!prefetch_service_);
+ CHECK(gcm_handler);
gcm_handler_ = std::move(gcm_handler);
}
void PrefetchServiceTestTaco::SetPrefetchNetworkRequestFactory(
std::unique_ptr<PrefetchNetworkRequestFactory> network_request_factory) {
CHECK(!prefetch_service_);
+ CHECK(network_request_factory);
network_request_factory_ = std::move(network_request_factory);
}
void PrefetchServiceTestTaco::SetPrefetchStore(
std::unique_ptr<PrefetchStore> prefetch_store) {
CHECK(!prefetch_service_);
+ CHECK(prefetch_store);
prefetch_store_ = std::move(prefetch_store);
}
@@ -128,6 +139,7 @@ void PrefetchServiceTestTaco::SetSuggestedArticlesObserver(
void PrefetchServiceTestTaco::SetPrefetchDownloader(
std::unique_ptr<PrefetchDownloader> prefetch_downloader) {
CHECK(!prefetch_service_);
+ CHECK(prefetch_downloader);
prefetch_downloader_ = std::move(prefetch_downloader);
}
@@ -164,10 +176,7 @@ void PrefetchServiceTestTaco::SetOfflinePageModel(
}
void PrefetchServiceTestTaco::CreatePrefetchService() {
- CHECK(metrics_collector_ && dispatcher_ && gcm_handler_ &&
- network_request_factory_ && prefetch_store_ &&
- suggested_articles_observer_ && prefetch_downloader_);
-
+ CHECK(!prefetch_service_);
prefetch_service_ = std::make_unique<PrefetchServiceImpl>(
std::move(metrics_collector_), std::move(dispatcher_),
std::move(gcm_handler_), std::move(network_request_factory_),
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
index 5f33b42ebc8..77d079e6fb0 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
@@ -24,6 +24,8 @@ class PrefetchNetworkRequestFactory;
class PrefetchService;
class PrefetchStore;
class SuggestedArticlesObserver;
+class TestDownloadClient;
+class TestDownloadService;
class ThumbnailFetcher;
// The taco class acts as a wrapper around the prefetch service making
@@ -78,6 +80,8 @@ class PrefetchServiceTestTaco {
return prefetch_service_.get();
}
+ TestDownloadService* download_service() { return download_service_.get(); }
+
// Creates and returns the ownership of the created PrefetchService instance.
// Leaves the taco empty, not usable.
std::unique_ptr<PrefetchService> CreateAndReturnPrefetchService();
@@ -97,6 +101,8 @@ class PrefetchServiceTestTaco {
std::unique_ptr<PrefetchService> prefetch_service_;
std::unique_ptr<ThumbnailFetcher> thumbnail_fetcher_;
std::unique_ptr<OfflinePageModel> offline_page_model_;
+ std::unique_ptr<TestDownloadService> download_service_;
+ std::unique_ptr<TestDownloadClient> download_client_;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_types.cc b/chromium/components/offline_pages/core/prefetch/prefetch_types.cc
index 59e0c5b9fe8..91f7f25f44f 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_types.cc
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_types.cc
@@ -6,6 +6,127 @@
namespace offline_pages {
+namespace {
+std::string PrefetchEnumToString(PrefetchBackgroundTaskRescheduleType value) {
+ switch (value) {
+ case PrefetchBackgroundTaskRescheduleType::NO_RESCHEDULE:
+ return "NO_RESCHEDULE";
+ case PrefetchBackgroundTaskRescheduleType::RESCHEDULE_WITHOUT_BACKOFF:
+ return "RESCHEDULE_WITHOUT_BACKOFF";
+ case PrefetchBackgroundTaskRescheduleType::RESCHEDULE_WITH_BACKOFF:
+ return "RESCHEDULE_WITH_BACKOFF";
+ case PrefetchBackgroundTaskRescheduleType::RESCHEDULE_DUE_TO_SYSTEM:
+ return "RESCHEDULE_DUE_TO_SYSTEM";
+ case PrefetchBackgroundTaskRescheduleType::SUSPEND:
+ return "SUSPEND";
+ }
+ CHECK(false) << static_cast<int>(value) << " not valid enum value";
+}
+
+std::string PrefetchEnumToString(PrefetchRequestStatus value) {
+ switch (value) {
+ case PrefetchRequestStatus::SUCCESS:
+ return "SUCCESS";
+ case PrefetchRequestStatus::SHOULD_RETRY_WITHOUT_BACKOFF:
+ return "SHOULD_RETRY_WITHOUT_BACKOFF";
+ case PrefetchRequestStatus::SHOULD_RETRY_WITH_BACKOFF:
+ return "SHOULD_RETRY_WITH_BACKOFF";
+ case PrefetchRequestStatus::SHOULD_SUSPEND:
+ return "SHOULD_SUSPEND";
+ case PrefetchRequestStatus::COUNT:
+ return "COUNT";
+ }
+ CHECK(false) << static_cast<int>(value) << " not valid enum value";
+}
+
+std::string PrefetchEnumToString(RenderStatus value) {
+ switch (value) {
+ case RenderStatus::RENDERED:
+ return "RENDERED";
+ case RenderStatus::PENDING:
+ return "PENDING";
+ case RenderStatus::FAILED:
+ return "FAILED";
+ case RenderStatus::EXCEEDED_LIMIT:
+ return "EXCEEDED_LIMIT";
+ }
+ CHECK(false) << static_cast<int>(value) << " not valid enum value";
+}
+
+std::string PrefetchEnumToString(PrefetchItemState value) {
+ switch (value) {
+ case PrefetchItemState::NEW_REQUEST:
+ return "NEW_REQUEST";
+ case PrefetchItemState::SENT_GENERATE_PAGE_BUNDLE:
+ return "SENT_GENERATE_PAGE_BUNDLE";
+ case PrefetchItemState::AWAITING_GCM:
+ return "AWAITING_GCM";
+ case PrefetchItemState::RECEIVED_GCM:
+ return "RECEIVED_GCM";
+ case PrefetchItemState::SENT_GET_OPERATION:
+ return "SENT_GET_OPERATION";
+ case PrefetchItemState::RECEIVED_BUNDLE:
+ return "RECEIVED_BUNDLE";
+ case PrefetchItemState::DOWNLOADING:
+ return "DOWNLOADING";
+ case PrefetchItemState::DOWNLOADED:
+ return "DOWNLOADED";
+ case PrefetchItemState::IMPORTING:
+ return "IMPORTING";
+ case PrefetchItemState::FINISHED:
+ return "FINISHED";
+ case PrefetchItemState::ZOMBIE:
+ return "ZOMBIE";
+ }
+ CHECK(false) << static_cast<int>(value) << " not valid enum value";
+}
+
+std::string PrefetchEnumToString(PrefetchItemErrorCode value) {
+ switch (value) {
+ case PrefetchItemErrorCode::SUCCESS:
+ return "SUCCESS";
+ case PrefetchItemErrorCode::TOO_MANY_NEW_URLS:
+ return "TOO_MANY_NEW_URLS";
+ case PrefetchItemErrorCode::DOWNLOAD_ERROR:
+ return "DOWNLOAD_ERROR";
+ case PrefetchItemErrorCode::IMPORT_ERROR:
+ return "IMPORT_ERROR";
+ case PrefetchItemErrorCode::ARCHIVING_FAILED:
+ return "ARCHIVING_FAILED";
+ case PrefetchItemErrorCode::ARCHIVING_LIMIT_EXCEEDED:
+ return "ARCHIVING_LIMIT_EXCEEDED";
+ case PrefetchItemErrorCode::STALE_AT_NEW_REQUEST:
+ return "STALE_AT_NEW_REQUEST";
+ case PrefetchItemErrorCode::STALE_AT_AWAITING_GCM:
+ return "STALE_AT_AWAITING_GCM";
+ case PrefetchItemErrorCode::STALE_AT_RECEIVED_GCM:
+ return "STALE_AT_RECEIVED_GCM";
+ case PrefetchItemErrorCode::STALE_AT_RECEIVED_BUNDLE:
+ return "STALE_AT_RECEIVED_BUNDLE";
+ case PrefetchItemErrorCode::STALE_AT_DOWNLOADING:
+ return "STALE_AT_DOWNLOADING";
+ case PrefetchItemErrorCode::STALE_AT_IMPORTING:
+ return "STALE_AT_IMPORTING";
+ case PrefetchItemErrorCode::STALE_AT_UNKNOWN:
+ return "STALE_AT_UNKNOWN";
+ case PrefetchItemErrorCode::GET_OPERATION_MAX_ATTEMPTS_REACHED:
+ return "GET_OPERATION_MAX_ATTEMPTS_REACHED";
+ case PrefetchItemErrorCode::
+ GENERATE_PAGE_BUNDLE_REQUEST_MAX_ATTEMPTS_REACHED:
+ return "GENERATE_PAGE_BUNDLE_REQUEST_MAX_ATTEMPTS_REACHED";
+ case PrefetchItemErrorCode::DOWNLOAD_MAX_ATTEMPTS_REACHED:
+ return "DOWNLOAD_MAX_ATTEMPTS_REACHED";
+ case PrefetchItemErrorCode::MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED:
+ return "MAXIMUM_CLOCK_BACKWARD_SKEW_EXCEEDED";
+ case PrefetchItemErrorCode::IMPORT_LOST:
+ return "IMPORT_LOST";
+ case PrefetchItemErrorCode::SUGGESTION_INVALIDATED:
+ return "SUGGESTION_INVALIDATED";
+ }
+ CHECK(false) << static_cast<int>(value) << " not valid enum value";
+}
+} // namespace
+
RenderPageInfo::RenderPageInfo() = default;
RenderPageInfo::RenderPageInfo(const RenderPageInfo& other) = default;
@@ -40,4 +161,21 @@ bool PrefetchArchiveInfo::empty() const {
return offline_id == 0;
}
+std::ostream& operator<<(std::ostream& out,
+ PrefetchBackgroundTaskRescheduleType value) {
+ return out << PrefetchEnumToString(value);
+}
+std::ostream& operator<<(std::ostream& out, PrefetchRequestStatus value) {
+ return out << PrefetchEnumToString(value);
+}
+std::ostream& operator<<(std::ostream& out, RenderStatus value) {
+ return out << PrefetchEnumToString(value);
+}
+std::ostream& operator<<(std::ostream& out, const PrefetchItemState& value) {
+ return out << PrefetchEnumToString(value);
+}
+std::ostream& operator<<(std::ostream& out, PrefetchItemErrorCode value) {
+ return out << PrefetchEnumToString(value);
+}
+
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/prefetch_types.h b/chromium/components/offline_pages/core/prefetch/prefetch_types.h
index 65030dbc2d6..633191289aa 100644
--- a/chromium/components/offline_pages/core/prefetch/prefetch_types.h
+++ b/chromium/components/offline_pages/core/prefetch/prefetch_types.h
@@ -255,6 +255,15 @@ struct PrefetchArchiveInfo {
int64_t file_size = 0;
};
+// These operators are implemented for testing only, see test_util.cc.
+// They are provided here to avoid ODR problems.
+std::ostream& operator<<(std::ostream& out,
+ PrefetchBackgroundTaskRescheduleType value);
+std::ostream& operator<<(std::ostream& out, PrefetchRequestStatus value);
+std::ostream& operator<<(std::ostream& out, RenderStatus value);
+std::ostream& operator<<(std::ostream& out, const PrefetchItemState& value);
+std::ostream& operator<<(std::ostream& out, PrefetchItemErrorCode value);
+
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_TYPES_H_
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc
index c2e37b21a95..82507579d91 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store.cc
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/offline_store_types.h"
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_schema.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_schema.cc
index ecc3064822a..92ab61e768d 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_schema.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_schema.cc
@@ -116,6 +116,62 @@ bool CreateLatestSchema(sql::Connection* db) {
return transaction.Commit();
}
+int MigrateFromVersion1To2(sql::Connection* db, sql::MetaTable* meta_table) {
+ const int target_version = 2;
+ const int target_compatible_version = 1;
+ const char kVersion1ToVersion2MigrationSql[] =
+ // Rename the existing items table.
+ "ALTER TABLE prefetch_items RENAME TO prefetch_items_old; "
+ // Creates the new items table.
+ "CREATE TABLE prefetch_items "
+ "(offline_id INTEGER PRIMARY KEY NOT NULL,"
+ " state INTEGER NOT NULL DEFAULT 0,"
+ " generate_bundle_attempts INTEGER NOT NULL DEFAULT 0,"
+ " get_operation_attempts INTEGER NOT NULL DEFAULT 0,"
+ " download_initiation_attempts INTEGER NOT NULL DEFAULT 0,"
+ " archive_body_length INTEGER_NOT_NULL DEFAULT -1,"
+ " creation_time INTEGER NOT NULL,"
+ " freshness_time INTEGER NOT NULL,"
+ " error_code INTEGER NOT NULL DEFAULT 0,"
+ // Note: default value changed from 0 to -1.
+ " file_size INTEGER NOT NULL DEFAULT -1,"
+ " guid VARCHAR NOT NULL DEFAULT '',"
+ " client_namespace VARCHAR NOT NULL DEFAULT '',"
+ " client_id VARCHAR NOT NULL DEFAULT '',"
+ " requested_url VARCHAR NOT NULL DEFAULT '',"
+ " final_archived_url VARCHAR NOT NULL DEFAULT '',"
+ " operation_name VARCHAR NOT NULL DEFAULT '',"
+ " archive_body_name VARCHAR NOT NULL DEFAULT '',"
+ " title VARCHAR NOT NULL DEFAULT '',"
+ " file_path VARCHAR NOT NULL DEFAULT ''); "
+ // Copy existing rows to the new items table.
+ "INSERT INTO prefetch_items "
+ " (offline_id, state, generate_bundle_attempts, get_operation_attempts,"
+ " download_initiation_attempts, archive_body_length, creation_time,"
+ " freshness_time, error_code, file_size, guid, client_namespace,"
+ " client_id, requested_url, final_archived_url, operation_name,"
+ " archive_body_name, title, file_path)"
+ " SELECT "
+ " offline_id, state, generate_bundle_attempts, get_operation_attempts,"
+ " download_initiation_attempts, archive_body_length, creation_time,"
+ " freshness_time, error_code, file_size, guid, client_namespace,"
+ " client_id, requested_url, final_archived_url, operation_name,"
+ " archive_body_name, title, file_path"
+ " FROM prefetch_items_old; "
+ // Drops the old items table.
+ "DROP TABLE prefetch_items_old; ";
+
+ sql::Transaction transaction(db);
+ if (transaction.Begin() && db->Execute(kVersion1ToVersion2MigrationSql) &&
+ SetVersionNumber(meta_table, target_version) &&
+ SetCompatibleVersionNumber(meta_table, target_compatible_version) &&
+ transaction.Commit()) {
+ return target_version;
+ }
+
+ return kVersionError;
+}
+
} // namespace
// static
@@ -130,7 +186,7 @@ bool PrefetchStoreSchema::CreateOrUpgradeIfNeeded(sql::Connection* db) {
return false;
const int compatible_version = GetCompatibleVersionNumber(&meta_table);
- const int current_version = GetVersionNumber(&meta_table);
+ int current_version = GetVersionNumber(&meta_table);
if (current_version == kVersionError || compatible_version == kVersionError)
return false;
DCHECK_GE(current_version, compatible_version);
@@ -151,50 +207,19 @@ bool PrefetchStoreSchema::CreateOrUpgradeIfNeeded(sql::Connection* db) {
return false;
// Schema upgrade code starts here.
- // Note: A series of if-else blocks was chosen to allow for more flexibility
- // in the upgrade logic than a single switch-case block would.
-
+ //
+ // Note #1: A series of if-else blocks was chosen to allow for more
+ // flexibility in the upgrade logic than a single switch-case block would.
+ // Note #2: Be very mindful when referring any constants from inside upgrade
+ // code as they might change as the schema evolve whereas the upgrade code
+ // should not. For instance, one should never refer to kCurrentVersion or
+ // kCompatibleVersion when setting values for the current and compatible
+ // versions as these are definitely going to change with each schema change.
if (current_version == 1) {
- sql::Transaction transaction(db);
- if (!transaction.Begin())
- return false;
-
- if (!db->Execute("ALTER TABLE prefetch_items RENAME TO prefetch_items_old"))
- return false;
-
- if (!CreatePrefetchItemsTable(db))
- return false;
-
- const char kMigrateItemsSql[] =
- "INSERT INTO prefetch_items "
- " (offline_id, state, generate_bundle_attempts, get_operation_attempts,"
- " download_initiation_attempts, archive_body_length, creation_time,"
- " freshness_time, error_code, file_size, guid, client_namespace,"
- " client_id, requested_url, final_archived_url, operation_name,"
- " archive_body_name, title, file_path)"
- " SELECT "
- " offline_id, state, generate_bundle_attempts, get_operation_attempts,"
- " download_initiation_attempts, archive_body_length, creation_time,"
- " freshness_time, error_code, file_size, guid, client_namespace,"
- " client_id, requested_url, final_archived_url, operation_name,"
- " archive_body_name, title, file_path"
- " FROM prefetch_items_old";
- if (!db->Execute(kMigrateItemsSql))
- return false;
-
- if (!db->Execute("DROP TABLE prefetch_items_old"))
- return false;
-
- if (!SetVersionNumber(&meta_table, kCurrentVersion) ||
- !SetCompatibleVersionNumber(&meta_table, kCompatibleVersion)) {
- return false;
- }
-
- if (!transaction.Commit())
- return false;
+ current_version = MigrateFromVersion1To2(db, &meta_table);
}
- return true;
+ return current_version == kCurrentVersion;
}
// static
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
index 2246e610705..18d679c0eba 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
@@ -256,6 +256,18 @@ std::size_t PrefetchStoreTestUtil::GetAllItems(
return items_count;
}
+std::string PrefetchStoreTestUtil::ToString() {
+ std::string result = "PrefetchItems: [";
+ std::set<PrefetchItem> items;
+ GetAllItems(&items);
+ for (const auto& item : items) {
+ result += "\n";
+ result += item.ToString();
+ }
+ result += "\n]";
+ return result;
+}
+
int PrefetchStoreTestUtil::ZombifyPrefetchItems(const std::string& name_space,
const GURL& url) {
int count = -1;
diff --git a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
index d335a9676e1..1536662daf6 100644
--- a/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
+++ b/chromium/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
@@ -61,6 +61,9 @@ class PrefetchStoreTestUtil {
// Returns the number of items found.
std::size_t GetAllItems(std::set<PrefetchItem>* all_items);
+ // Prints a representation of the prefetch store contents.
+ std::string ToString();
+
// Sets to the ZOMBIE state entries identified by |name_space| and
// |url|, returning the number of entries found.
int ZombifyPrefetchItems(const std::string& name_space, const GURL& url);
diff --git a/chromium/components/offline_pages/core/prefetch/test_download_service.cc b/chromium/components/offline_pages/core/prefetch/test_download_service.cc
new file mode 100644
index 00000000000..9b6d5fc02de
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/test_download_service.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/prefetch/test_download_service.h"
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/bind_test_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/download/public/background_service/download_metadata.h"
+#include "components/download/public/background_service/service_config.h"
+#include "components/offline_pages/core/prefetch/test_download_client.h"
+
+namespace offline_pages {
+
+namespace {
+
+// Implementation of ServiceConfig used for testing. This is never actually
+// constructed.
+class TestServiceConfig : public download::ServiceConfig {
+ public:
+ TestServiceConfig() = default;
+ ~TestServiceConfig() override = default;
+
+ // ServiceConfig implementation.
+ uint32_t GetMaxScheduledDownloadsPerClient() const override { return 0; }
+ uint32_t GetMaxConcurrentDownloads() const override { return 0; }
+ const base::TimeDelta& GetFileKeepAliveTime() const override {
+ return time_delta_;
+ }
+
+ private:
+ base::TimeDelta time_delta_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestServiceConfig);
+};
+
+} // namespace
+
+TestDownloadService::TestDownloadService() = default;
+TestDownloadService::~TestDownloadService() = default;
+
+const download::ServiceConfig& TestDownloadService::GetConfig() {
+ NOTIMPLEMENTED();
+ static TestServiceConfig config;
+ return config;
+}
+
+void TestDownloadService::StartDownload(
+ const download::DownloadParams& download_params) {
+ if (!download_dir_.IsValid())
+ CHECK(download_dir_.CreateUniqueTempDir());
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindRepeating(download_params.callback, download_params.guid,
+ download::DownloadParams::ACCEPTED));
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&TestDownloadService::FinishDownload,
+ base::Unretained(this), download_params.guid));
+}
+
+void TestDownloadService::FinishDownload(const std::string& guid) {
+ base::FilePath path = download_dir_.GetPath().AppendASCII(
+ base::StrCat({"dl_", base::NumberToString(next_file_id_++)}));
+ const int file_size = static_cast<int>(test_file_data_.size());
+ CHECK_EQ(file_size, base::WriteFile(path, test_file_data_.data(), file_size));
+ client_->OnDownloadSucceeded(
+ guid, download::CompletionInfo(path, test_file_data_.size()));
+}
+
+void TestDownloadService::SetTestFileData(const std::string& data) {
+ test_file_data_ = data;
+}
+
+void TestDownloadService::OnStartScheduledTask(
+ download::DownloadTaskType task_type,
+ const download::TaskFinishedCallback& callback) {
+ NOTIMPLEMENTED();
+}
+bool TestDownloadService::OnStopScheduledTask(
+ download::DownloadTaskType task_type) {
+ NOTIMPLEMENTED();
+ return false;
+}
+download::DownloadService::ServiceStatus TestDownloadService::GetStatus() {
+ NOTIMPLEMENTED();
+ return DownloadService::ServiceStatus();
+}
+void TestDownloadService::PauseDownload(const std::string& guid) {
+ NOTIMPLEMENTED();
+}
+void TestDownloadService::ResumeDownload(const std::string& guid) {
+ NOTIMPLEMENTED();
+}
+void TestDownloadService::CancelDownload(const std::string& guid) {
+ NOTIMPLEMENTED();
+}
+void TestDownloadService::ChangeDownloadCriteria(
+ const std::string& guid,
+ const download::SchedulingParams& params) {
+ NOTIMPLEMENTED();
+}
+download::Logger* TestDownloadService::GetLogger() {
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/test_download_service.h b/chromium/components/offline_pages/core/prefetch/test_download_service.h
new file mode 100644
index 00000000000..445d269b658
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/test_download_service.h
@@ -0,0 +1,57 @@
+// 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 COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_SERVICE_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_SERVICE_H_
+
+#include <list>
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/optional.h"
+#include "components/download/public/background_service/client.h"
+#include "components/download/public/background_service/download_params.h"
+#include "components/download/public/background_service/download_service.h"
+#include "components/offline_pages/core/prefetch/test_download_client.h"
+
+namespace offline_pages {
+
+// Implementation of DownloadService used for testing.
+class TestDownloadService : public download::DownloadService {
+ public:
+ explicit TestDownloadService();
+ ~TestDownloadService() override;
+
+ // DownloadService implementation.
+ const download::ServiceConfig& GetConfig() override;
+ void OnStartScheduledTask(
+ download::DownloadTaskType task_type,
+ const download::TaskFinishedCallback& callback) override;
+ bool OnStopScheduledTask(download::DownloadTaskType task_type) override;
+ DownloadService::ServiceStatus GetStatus() override;
+ void StartDownload(const download::DownloadParams& download_params) override;
+ void PauseDownload(const std::string& guid) override;
+ void ResumeDownload(const std::string& guid) override;
+ void CancelDownload(const std::string& guid) override;
+ void ChangeDownloadCriteria(
+ const std::string& guid,
+ const download::SchedulingParams& params) override;
+ download::Logger* GetLogger() override;
+
+ void SetClient(TestDownloadClient* client) { client_ = client; }
+ // Sets the content saved for downloads requested through StartDownload.
+ void SetTestFileData(const std::string& data);
+
+ private:
+ void FinishDownload(const std::string& guid);
+
+ base::ScopedTempDir download_dir_;
+ TestDownloadClient* client_ = nullptr;
+ int next_file_id_ = 0;
+ std::string test_file_data_;
+ DISALLOW_COPY_AND_ASSIGN(TestDownloadService);
+};
+
+} // namespace offline_pages
+
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_SERVICE_H_
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
index a535ae56cf5..f968c35a278 100644
--- a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.cc
@@ -59,6 +59,12 @@ void TestPrefetchDispatcher::CleanupDownloads(
cleanup_downloads_count++;
}
+void TestPrefetchDispatcher::GeneratePageBundleRequested(
+ std::unique_ptr<IdsVector> ids) {
+ generate_page_bundle_requested++;
+ ids_from_generate_page_bundle_requested = std::move(ids);
+}
+
void TestPrefetchDispatcher::DownloadCompleted(
const PrefetchDownloadResult& download_result) {
download_results.push_back(download_result);
diff --git a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
index 4ca398b4833..e1aa62eaf69 100644
--- a/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
+++ b/chromium/components/offline_pages/core/prefetch/test_prefetch_dispatcher.h
@@ -39,6 +39,7 @@ class TestPrefetchDispatcher : public PrefetchDispatcher {
const std::set<std::string>& outstanding_download_ids,
const std::map<std::string, std::pair<base::FilePath, int64_t>>&
success_downloads) override;
+ void GeneratePageBundleRequested(std::unique_ptr<IdsVector> ids) override;
void DownloadCompleted(
const PrefetchDownloadResult& download_result) override;
void ItemDownloaded(int64_t offline_id, const ClientId& client_id) override;
@@ -51,6 +52,7 @@ class TestPrefetchDispatcher : public PrefetchDispatcher {
std::vector<PrefetchDownloadResult> download_results;
std::vector<std::pair<int64_t, ClientId>> item_downloaded_results;
std::vector<std::pair<int64_t, bool>> import_results;
+ std::unique_ptr<IdsVector> ids_from_generate_page_bundle_requested;
int cleanup_downloads_count = 0;
int new_suggestions_count = 0;
@@ -58,6 +60,7 @@ class TestPrefetchDispatcher : public PrefetchDispatcher {
int remove_all_suggestions_count = 0;
int remove_by_client_id_count = 0;
int task_schedule_count = 0;
+ int generate_page_bundle_requested = 0;
};
} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/test_util.cc b/chromium/components/offline_pages/core/prefetch/test_util.cc
new file mode 100644
index 00000000000..35b0055ebb7
--- /dev/null
+++ b/chromium/components/offline_pages/core/prefetch/test_util.cc
@@ -0,0 +1,66 @@
+// 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 <sstream>
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/offline_pages/core/offline_store_utils.h"
+#include "components/offline_pages/core/prefetch/prefetch_item.h"
+
+namespace offline_pages {
+
+std::string PrefetchItem::ToString() const {
+ std::stringstream s;
+ s << "PrefetchItem(id=" << offline_id << ", guid=" << guid << ", "
+ << client_id << ", state=" << state
+ << ", url=" << url.possibly_invalid_spec()
+ << ", final_url=" << final_archived_url.possibly_invalid_spec()
+ << ", gb_attempts=" << generate_bundle_attempts
+ << ", get_attempts=" << get_operation_attempts
+ << ", dl_attempts=" << download_initiation_attempts
+ << ", operation=" << operation_name << ", body_name=" << archive_body_name
+ << ", body_len=" << archive_body_length
+ << ", creation_time=" << store_utils::ToDatabaseTime(creation_time)
+ << ", freshness_time=" << store_utils::ToDatabaseTime(freshness_time)
+ << ", error=" << error_code << ", title=" << base::UTF16ToUTF8(title)
+ << ", file_path=" << file_path.AsUTF8Unsafe() << ", file_size=" << file_size
+ << ")";
+ return s.str();
+}
+
+std::ostream& operator<<(std::ostream& out, const PrefetchItem& pi) {
+ return out << pi.ToString();
+}
+
+PrefetchItem::PrefetchItem(const PrefetchItem& other) = default;
+
+PrefetchItem& PrefetchItem::operator=(const PrefetchItem& other) = default;
+
+PrefetchItem& PrefetchItem::operator=(PrefetchItem&& other) = default;
+
+bool PrefetchItem::operator==(const PrefetchItem& other) const {
+ return offline_id == other.offline_id && guid == other.guid &&
+ client_id == other.client_id && state == other.state &&
+ url == other.url && final_archived_url == other.final_archived_url &&
+ generate_bundle_attempts == other.generate_bundle_attempts &&
+ get_operation_attempts == other.get_operation_attempts &&
+ download_initiation_attempts == other.download_initiation_attempts &&
+ operation_name == other.operation_name &&
+ archive_body_name == other.archive_body_name &&
+ archive_body_length == other.archive_body_length &&
+ creation_time == other.creation_time &&
+ freshness_time == other.freshness_time &&
+ error_code == other.error_code && title == other.title &&
+ file_path == other.file_path && file_size == other.file_size;
+}
+
+bool PrefetchItem::operator!=(const PrefetchItem& other) const {
+ return !(*this == other);
+}
+
+bool PrefetchItem::operator<(const PrefetchItem& other) const {
+ return offline_id < other.offline_id;
+}
+
+} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/prefetch/thumbnail_fetcher.h b/chromium/components/offline_pages/core/prefetch/thumbnail_fetcher.h
index 3aaee518264..a4c8093cd66 100644
--- a/chromium/components/offline_pages/core/prefetch/thumbnail_fetcher.h
+++ b/chromium/components/offline_pages/core/prefetch/thumbnail_fetcher.h
@@ -22,13 +22,23 @@ class ThumbnailFetcher {
base::OnceCallback<void(const std::string& image_data)>;
// Status of thumbnail fetch for UMA, exposed for tests only.
+ // These values are persisted to logs. Entries should not be renumbered and
+ // numeric values should never be reused.
enum class FetchCompleteStatus {
- // These values are persisted to logs. Entries should not be renumbered and
- // numeric values should never be reused.
- kSuccess, // Fetch returned a good thumbnail.
- kEmptyImage, // Fetch returned no thumbnail.
- kTooLarge, // Fetch returned a very large thumbnail we will not use.
- kMaxValue = kTooLarge, // Must be updated when adding a new value.
+ // Fetch returned a good thumbnail on the 1st attempt.
+ kFirstAttemptSuccess,
+ // Fetch returned no thumbnail on the 1st attempt.
+ kFirstAttemptEmptyImage,
+ // Fetch returned a very large thumbnail we will not use on the 1st attempt.
+ kFirstAttemptTooLarge,
+ // Fetch returned a good thumbnail on the 2nd attempt.
+ kSecondAttemptSuccess,
+ // Fetch returned no thumbnail on the 2nd attempt.
+ kSecondAttemptEmptyImage,
+ // Fetch returned a very large thumbnail we will not use on the 2nd attempt.
+ kSecondAttemptTooLarge,
+ // Must be updated when adding a new value.
+ kMaxValue = kSecondAttemptTooLarge,
};
// Thumbnails larger than 200KB are not retained. Thumbnails are typically
// around 10KB.
@@ -43,6 +53,7 @@ class ThumbnailFetcher {
// completes. |image_data| is empty if the fetch failed, otherwise it will
// be raw image data that may be decoded with image_fetcher::ImageDecoder.
virtual void FetchSuggestionImageData(const ClientId& client_id,
+ bool is_first_attempt,
ImageDataFetchedCallback callback) = 0;
};
diff --git a/chromium/components/offline_pages/core/recent_tabs/BUILD.gn b/chromium/components/offline_pages/core/recent_tabs/BUILD.gn
deleted file mode 100644
index fa8f938a665..00000000000
--- a/chromium/components/offline_pages/core/recent_tabs/BUILD.gn
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-if (is_android) {
- import("//build/config/android/rules.gni")
-}
-
-source_set("recent_tabs") {
- sources = [
- "recent_tabs_ui_adapter_delegate.cc",
- "recent_tabs_ui_adapter_delegate.h",
- ]
-
- deps = [
- "//base",
- "//components/offline_pages/core",
- "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
- "//url",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "recent_tabs_ui_adapter_delegate_unittest.cc",
- ]
-
- deps = [
- ":recent_tabs",
- "//base",
- "//base/test:test_support",
- "//components/offline_pages/core",
- "//components/offline_pages/core:test_support",
- "//components/offline_pages/core/background:test_support",
- "//components/offline_pages/core/downloads:offline_pages_ui_adapter",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc b/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc
deleted file mode 100644
index 0db7cda8297..00000000000
--- a/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-
-#include "base/bind.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "components/offline_pages/core/thumbnail_decoder.h"
-
-namespace offline_pages {
-
-namespace {
-const char kRecentTabsUIAdapterKey[] = "recent-tabs-download-ui-adapter";
-} // namespace
-
-RecentTabsUIAdapterDelegate::RecentTabsUIAdapterDelegate(
- OfflinePageModel* model)
- : model_(model) {}
-
-RecentTabsUIAdapterDelegate::~RecentTabsUIAdapterDelegate() = default;
-
-offline_pages::DownloadUIAdapter*
-RecentTabsUIAdapterDelegate::GetOrCreateRecentTabsUIAdapter(
- offline_pages::OfflinePageModel* offline_page_model,
- offline_pages::RequestCoordinator* request_coordinator) {
- offline_pages::DownloadUIAdapter* recent_tabs_ui_adapter =
- static_cast<DownloadUIAdapter*>(
- offline_page_model->GetUserData(kRecentTabsUIAdapterKey));
-
- if (!recent_tabs_ui_adapter) {
- auto delegate =
- std::make_unique<RecentTabsUIAdapterDelegate>(offline_page_model);
- recent_tabs_ui_adapter =
- new DownloadUIAdapter(nullptr, offline_page_model, request_coordinator,
- nullptr, std::move(delegate));
- offline_page_model->SetUserData(kRecentTabsUIAdapterKey,
- base::WrapUnique(recent_tabs_ui_adapter));
- }
-
- return recent_tabs_ui_adapter;
-}
-
-// static
-RecentTabsUIAdapterDelegate* RecentTabsUIAdapterDelegate::FromDownloadUIAdapter(
- DownloadUIAdapter* ui_adapter) {
- return static_cast<RecentTabsUIAdapterDelegate*>(ui_adapter->delegate());
-}
-
-// static
-int RecentTabsUIAdapterDelegate::TabIdFromClientId(const ClientId& client_id) {
- int tab_id = 0;
- bool convert_result = base::StringToInt(client_id.id, &tab_id);
- DCHECK(convert_result);
- return tab_id;
-}
-
-bool RecentTabsUIAdapterDelegate::IsVisibleInUI(const ClientId& client_id) {
- return IsRecentTab(client_id);
-}
-
-bool RecentTabsUIAdapterDelegate::IsTemporarilyHiddenInUI(
- const ClientId& client_id) {
- return active_tabs_.count(TabIdFromClientId(client_id)) == 0;
-}
-
-void RecentTabsUIAdapterDelegate::SetUIAdapter(DownloadUIAdapter* adapter) {
- ui_adapter_ = adapter;
-}
-
-void RecentTabsUIAdapterDelegate::RegisterTab(int tab_id) {
- DCHECK(ui_adapter_);
- if (active_tabs_.count(tab_id) > 0)
- return;
- active_tabs_.insert(tab_id);
- ui_adapter_->TemporaryHiddenStatusChanged(ClientIdFromTabId(tab_id));
-}
-
-void RecentTabsUIAdapterDelegate::UnregisterTab(int tab_id) {
- DCHECK(ui_adapter_);
- if (active_tabs_.count(tab_id) == 0)
- return;
- active_tabs_.erase(tab_id);
- ui_adapter_->TemporaryHiddenStatusChanged(ClientIdFromTabId(tab_id));
-}
-
-// static
-ClientId RecentTabsUIAdapterDelegate::ClientIdFromTabId(int tab_id) {
- return ClientId(kLastNNamespace, base::IntToString(tab_id));
-}
-
-bool RecentTabsUIAdapterDelegate::IsRecentTab(const ClientId& page) {
- return model_->GetPolicyController()->IsShownAsRecentlyVisitedSite(
- page.name_space);
-}
-
-} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h b/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h
deleted file mode 100644
index 212e4236171..00000000000
--- a/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_OFFLINE_PAGES_CORE_RECENT_TABS_RECENT_TABS_UI_ADAPTER_DELEGATE_H_
-#define COMPONENTS_OFFLINE_PAGES_CORE_RECENT_TABS_RECENT_TABS_UI_ADAPTER_DELEGATE_H_
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/observer_list.h"
-#include "base/supports_user_data.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/offline_page_model.h"
-#include "components/offline_pages/core/offline_page_types.h"
-#include "url/gurl.h"
-
-namespace offline_pages {
-
-// Keeps track of all the tabs open for the profile, and restricts its view of
-// the offline pages to only those that have an open tab. This begins
-// observation early, as soon as the first Tab is created, and even before that
-// tab gets a web contents.
-//
-// In this UI adapter, |guid| represents the tab ID for a given page.
-class RecentTabsUIAdapterDelegate : public DownloadUIAdapter::Delegate {
- public:
- explicit RecentTabsUIAdapterDelegate(OfflinePageModel* model);
- ~RecentTabsUIAdapterDelegate() override;
-
- static DownloadUIAdapter* GetOrCreateRecentTabsUIAdapter(
- OfflinePageModel* offline_page_model,
- RequestCoordinator* request_coordinator);
- static RecentTabsUIAdapterDelegate* FromDownloadUIAdapter(
- DownloadUIAdapter* adapter);
- // This extracts the tab ID out of the |id| field of the client ID using a
- // string conversion. Crashes if conversion fails.
- static int TabIdFromClientId(const ClientId& client_id);
-
- // This override returns true if the client ID is shown on the NTP as a recent
- // tab. This is determined by policy.
- bool IsVisibleInUI(const ClientId& client_id) override;
- // This returns true if there does not exist a tab ID for the given client ID.
- bool IsTemporarilyHiddenInUI(const ClientId& client_id) override;
- // Sets our reference to the UI adapter so we can notify it of visibility
- // changes.
- void SetUIAdapter(DownloadUIAdapter* ui_adapter) override;
- void OpenItem(const OfflineItem& item, int64_t offline_id) override {}
-
- // Register/UnregisterTab add and remove tab IDs from the list. These
- // functions can be called before a page actually exists with the given tab
- // ID.
- // Note that these change temporary visibility and therefore |set_ui_adapter|
- // must be called before either of these functions.
- void RegisterTab(int tab_id);
- void UnregisterTab(int tab_id);
-
- private:
- // Constructs the client ID assuming that we use the Last N namespace.
- //
- // TODO(dewittj): Make this more resilient to adding more namespaces.
- static ClientId ClientIdFromTabId(int tab_id);
-
- // Checks a client ID for proper namespace and ID format to be shown in the
- // Downloads Home UI.
- bool IsRecentTab(const ClientId& page);
-
- // Always valid, this class is owned by DownloadUIAdapter, which is owned by
- // Offline Page Model.
- OfflinePageModel* model_;
-
- // This is set by the UI adapter itself.
- DownloadUIAdapter* ui_adapter_ = nullptr;
-
- // The tabs we've seen.
- std::unordered_set<int> active_tabs_;
-
- DISALLOW_COPY_AND_ASSIGN(RecentTabsUIAdapterDelegate);
-};
-
-} // namespace offline_pages
-
-#endif // COMPONENTS_OFFLINE_PAGES_CORE_RECENT_TABS_RECENT_TABS_UI_ADAPTER_DELEGATE_H_
diff --git a/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc b/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc
deleted file mode 100644
index 90e4f5bc276..00000000000
--- a/chromium/components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate_unittest.cc
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
-
-#include <stdint.h>
-
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/test/test_mock_time_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "components/offline_pages/core/background/request_coordinator_stub_taco.h"
-#include "components/offline_pages/core/client_namespace_constants.h"
-#include "components/offline_pages/core/client_policy_controller.h"
-#include "components/offline_pages/core/downloads/download_ui_adapter.h"
-#include "components/offline_pages/core/stub_offline_page_model.h"
-#include "components/offline_pages/core/thumbnail_decoder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace offline_pages {
-
-namespace {
-static const char kTestGuid1[] = "1";
-static const char kTestGuid2[] = "2";
-static const char kTestBadGuid[] = "ccccccc-cccc-0ccc-0ccc-ccccccccccc0";
-static const ClientId kTestClientIdOtherNamespace(kAsyncNamespace, kTestGuid1);
-static const ClientId kTestClientIdOtherGuid(kLastNNamespace, kTestBadGuid);
-static const ClientId kTestClientId1(kLastNNamespace, kTestGuid1);
-static const ClientId kTestClientId2(kLastNNamespace, kTestGuid2);
-
-// Creates mock versions for OfflinePageModel, RequestCoordinator and their
-// dependencies, then passes them to DownloadUIAdapter for testing.
-// Note that initially the OfflienPageModel is not "loaded". PumpLoop() will
-// load it, firing ItemsLoaded callback to the Adapter. Hence some tests
-// start from PumpLoop() right away if they don't need to test this.
-class RecentTabsUIAdapterDelegateTest : public testing::Test {
- public:
- RecentTabsUIAdapterDelegateTest();
- ~RecentTabsUIAdapterDelegateTest() override;
-
- // Runs until all of the tasks that are not delayed are gone from the task
- // queue.
- void PumpLoop();
-
- RequestCoordinator* request_coordinator() {
- return request_coordinator_taco_->request_coordinator();
- }
-
- StubOfflinePageModel model;
- RecentTabsUIAdapterDelegate* adapter_delegate;
- std::unique_ptr<DownloadUIAdapter> adapter;
-
- private:
- std::unique_ptr<RequestCoordinatorStubTaco> request_coordinator_taco_;
- scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
- base::ThreadTaskRunnerHandle task_runner_handle_;
-};
-
-RecentTabsUIAdapterDelegateTest::RecentTabsUIAdapterDelegateTest()
- : task_runner_(new base::TestMockTimeTaskRunner()),
- task_runner_handle_(task_runner_) {
- request_coordinator_taco_ = std::make_unique<RequestCoordinatorStubTaco>();
- request_coordinator_taco_->CreateRequestCoordinator();
-
- auto delegate = std::make_unique<RecentTabsUIAdapterDelegate>(&model);
- adapter_delegate = delegate.get();
-
- adapter = std::make_unique<DownloadUIAdapter>(
- nullptr, &model, request_coordinator_taco_->request_coordinator(),
- nullptr, std::move(delegate));
-}
-
-RecentTabsUIAdapterDelegateTest::~RecentTabsUIAdapterDelegateTest() = default;
-
-void RecentTabsUIAdapterDelegateTest::PumpLoop() {
- task_runner_->RunUntilIdle();
-}
-
-TEST_F(RecentTabsUIAdapterDelegateTest, TabIdFromClientId) {
- EXPECT_EQ(1, RecentTabsUIAdapterDelegate::TabIdFromClientId(kTestClientId1));
- EXPECT_EQ(2, RecentTabsUIAdapterDelegate::TabIdFromClientId(kTestClientId2));
-}
-
-TEST_F(RecentTabsUIAdapterDelegateTest, IsVisibleInUI) {
- EXPECT_FALSE(adapter_delegate->IsVisibleInUI(kTestClientIdOtherNamespace));
- EXPECT_TRUE(adapter_delegate->IsVisibleInUI(kTestClientId1));
- EXPECT_TRUE(adapter_delegate->IsVisibleInUI(kTestClientId2));
-}
-
-TEST_F(RecentTabsUIAdapterDelegateTest, IsTemporarilyHiddenInUI) {
- adapter_delegate->RegisterTab(3);
- adapter_delegate->RegisterTab(4);
-
- EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
- EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-
- adapter_delegate->RegisterTab(1);
- EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
- EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-
- adapter_delegate->RegisterTab(2);
- EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
- EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-
- adapter_delegate->UnregisterTab(2);
- EXPECT_FALSE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId1));
- EXPECT_TRUE(adapter_delegate->IsTemporarilyHiddenInUI(kTestClientId2));
-}
-
-} // namespace
-} // namespace offline_pages
diff --git a/chromium/components/offline_pages/core/stub_offline_page_model.cc b/chromium/components/offline_pages/core/stub_offline_page_model.cc
index 80ad56896d5..d217c07d376 100644
--- a/chromium/components/offline_pages/core/stub_offline_page_model.cc
+++ b/chromium/components/offline_pages/core/stub_offline_page_model.cc
@@ -12,6 +12,10 @@ StubOfflinePageModel::StubOfflinePageModel()
: archive_directory_(base::FilePath(FILE_PATH_LITERAL("/archive_dir/"))) {}
StubOfflinePageModel::~StubOfflinePageModel() {}
+void StubOfflinePageModel::SetArchiveDirectory(const base::FilePath& path) {
+ archive_directory_ = path;
+}
+
void StubOfflinePageModel::AddObserver(Observer* observer) {}
void StubOfflinePageModel::RemoveObserver(Observer* observer) {}
void StubOfflinePageModel::SavePage(
@@ -34,43 +38,46 @@ void StubOfflinePageModel::DeletePagesByClientIdsAndOrigin(
const DeletePageCallback& callback) {}
void StubOfflinePageModel::GetPagesByClientIds(
const std::vector<ClientId>& client_ids,
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) {}
void StubOfflinePageModel::GetAllPages(
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) {}
void StubOfflinePageModel::GetPageByOfflineId(
int64_t offline_id,
- const SingleOfflinePageItemCallback& callback) {}
+ SingleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPageByGuid(
const std::string& guid,
- const SingleOfflinePageItemCallback& callback) {}
+ SingleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPagesByURL(
const GURL& url,
URLSearchMode url_search_mode,
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPagesByRequestOrigin(
const std::string& origin,
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPageBySizeAndDigest(
int64_t file_size,
const std::string& digest,
- const SingleOfflinePageItemCallback& callback) {}
+ SingleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPagesRemovedOnCacheReset(
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPagesByNamespace(
const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::GetPagesSupportedByDownloads(
- const MultipleOfflinePageItemCallback& callback) {}
+ MultipleOfflinePageItemCallback callback) {}
void StubOfflinePageModel::StoreThumbnail(const OfflinePageThumbnail& thumb) {}
void StubOfflinePageModel::GetThumbnailByOfflineId(
int64_t offline_id,
GetThumbnailCallback callback) {}
+void StubOfflinePageModel::HasThumbnailForOfflineId(
+ int64_t offline_id,
+ base::OnceCallback<void(bool)> callback) {}
void StubOfflinePageModel::PublishInternalArchive(
const OfflinePageItem& offline_page,
std::unique_ptr<OfflinePageArchiver> archiver,
diff --git a/chromium/components/offline_pages/core/stub_offline_page_model.h b/chromium/components/offline_pages/core/stub_offline_page_model.h
index 2a64463a770..c99f6ae12ff 100644
--- a/chromium/components/offline_pages/core/stub_offline_page_model.h
+++ b/chromium/components/offline_pages/core/stub_offline_page_model.h
@@ -22,6 +22,8 @@ class StubOfflinePageModel : public OfflinePageModel {
StubOfflinePageModel();
~StubOfflinePageModel() override;
+ void SetArchiveDirectory(const base::FilePath& path);
+
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
void SavePage(const SavePageParams& save_page_params,
@@ -39,41 +41,40 @@ class StubOfflinePageModel : public OfflinePageModel {
const std::vector<ClientId>& client_ids,
const std::string& origin,
const DeletePageCallback& callback) override;
- void GetPagesByClientIds(
- const std::vector<ClientId>& client_ids,
- const MultipleOfflinePageItemCallback& callback) override;
+ void GetPagesByClientIds(const std::vector<ClientId>& client_ids,
+ MultipleOfflinePageItemCallback callback) override;
void DeleteCachedPagesByURLPredicate(
const UrlPredicate& predicate,
const DeletePageCallback& callback) override;
- void GetAllPages(const MultipleOfflinePageItemCallback& callback) override;
+ void GetAllPages(MultipleOfflinePageItemCallback callback) override;
void GetOfflineIdsForClientId(
const ClientId& client_id,
const MultipleOfflineIdCallback& callback) override;
- void GetPageByOfflineId(
- int64_t offline_id,
- const SingleOfflinePageItemCallback& callback) override;
+ void GetPageByOfflineId(int64_t offline_id,
+ SingleOfflinePageItemCallback callback) override;
void GetPageByGuid(const std::string& guid,
- const SingleOfflinePageItemCallback& callback) override;
+ SingleOfflinePageItemCallback callback) override;
void GetPagesByURL(const GURL& url,
URLSearchMode url_search_mode,
- const MultipleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
void GetPagesByRequestOrigin(
const std::string& origin,
- const MultipleOfflinePageItemCallback& callback) override;
- void GetPageBySizeAndDigest(
- int64_t file_size,
- const std::string& digest,
- const SingleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
+ void GetPageBySizeAndDigest(int64_t file_size,
+ const std::string& digest,
+ SingleOfflinePageItemCallback callback) override;
void GetPagesRemovedOnCacheReset(
- const MultipleOfflinePageItemCallback& callback) override;
- void GetPagesByNamespace(
- const std::string& name_space,
- const MultipleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
+ void GetPagesByNamespace(const std::string& name_space,
+ MultipleOfflinePageItemCallback callback) override;
void GetPagesSupportedByDownloads(
- const MultipleOfflinePageItemCallback& callback) override;
+ MultipleOfflinePageItemCallback callback) override;
void StoreThumbnail(const OfflinePageThumbnail& thumb) override;
void GetThumbnailByOfflineId(int64_t offline_id,
GetThumbnailCallback callback) override;
+ void HasThumbnailForOfflineId(
+ int64_t offline_id,
+ base::OnceCallback<void(bool)> callback) override;
void PublishInternalArchive(
const OfflinePageItem& offline_page,
std::unique_ptr<OfflinePageArchiver> archiver,
diff --git a/chromium/components/offline_pages/core/system_download_manager_stub.cc b/chromium/components/offline_pages/core/stub_system_download_manager.cc
index 95477855b43..2b8562fe550 100644
--- a/chromium/components/offline_pages/core/system_download_manager_stub.cc
+++ b/chromium/components/offline_pages/core/stub_system_download_manager.cc
@@ -2,21 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/offline_pages/core/system_download_manager_stub.h"
+#include "components/offline_pages/core/stub_system_download_manager.h"
namespace offline_pages {
-SystemDownloadManagerStub::SystemDownloadManagerStub(int64_t id_to_use,
+StubSystemDownloadManager::StubSystemDownloadManager(int64_t id_to_use,
bool installed)
: download_id_(id_to_use), last_removed_id_(0), installed_(installed) {}
-SystemDownloadManagerStub::~SystemDownloadManagerStub() {}
+StubSystemDownloadManager::~StubSystemDownloadManager() {}
-bool SystemDownloadManagerStub::IsDownloadManagerInstalled() {
+bool StubSystemDownloadManager::IsDownloadManagerInstalled() {
return installed_;
}
-int64_t SystemDownloadManagerStub::AddCompletedDownload(
+int64_t StubSystemDownloadManager::AddCompletedDownload(
const std::string& title,
const std::string& description,
const std::string& path,
@@ -33,7 +33,7 @@ int64_t SystemDownloadManagerStub::AddCompletedDownload(
return download_id_;
}
-int SystemDownloadManagerStub::Remove(
+int StubSystemDownloadManager::Remove(
const std::vector<int64_t>& android_download_manager_ids) {
int count = static_cast<int>(android_download_manager_ids.size());
if (count > 0)
diff --git a/chromium/components/offline_pages/core/system_download_manager_stub.h b/chromium/components/offline_pages/core/stub_system_download_manager.h
index 7f2b3d797c3..dab21948369 100644
--- a/chromium/components/offline_pages/core/system_download_manager_stub.h
+++ b/chromium/components/offline_pages/core/stub_system_download_manager.h
@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef COMPONENTS_OFFLINE_PAGES_CORE_SYSTEM_DOWNLOAD_MANAGER_STUB_H_
-#define COMPONENTS_OFFLINE_PAGES_CORE_SYSTEM_DOWNLOAD_MANAGER_STUB_H_
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_STUB_SYSTEM_DOWNLOAD_MANAGER_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_STUB_SYSTEM_DOWNLOAD_MANAGER_H_
#include "components/offline_pages/core/system_download_manager.h"
namespace offline_pages {
// Stub replacement for the DownloadManager to be used by unit tests.
-class SystemDownloadManagerStub : public SystemDownloadManager {
+class StubSystemDownloadManager : public SystemDownloadManager {
public:
- SystemDownloadManagerStub(int64_t download_id, bool installed);
- ~SystemDownloadManagerStub() override;
+ StubSystemDownloadManager(int64_t download_id, bool installed);
+ ~StubSystemDownloadManager() override;
bool IsDownloadManagerInstalled() override;
@@ -51,4 +51,4 @@ class SystemDownloadManagerStub : public SystemDownloadManager {
} // namespace offline_pages
-#endif // COMPONENTS_OFFLINE_PAGES_CORE_SYSTEM_DOWNLOAD_MANAGER_STUB_H_
+#endif // COMPONENTS_OFFLINE_PAGES_CORE_STUB_SYSTEM_DOWNLOAD_MANAGER_H_
diff --git a/chromium/components/offline_pages/core/task_queue.cc b/chromium/components/offline_pages/core/task_queue.cc
index cb8b6ecea66..e5b10a54b47 100644
--- a/chromium/components/offline_pages/core/task_queue.cc
+++ b/chromium/components/offline_pages/core/task_queue.cc
@@ -29,7 +29,7 @@ bool TaskQueue::HasPendingTasks() const {
}
bool TaskQueue::HasRunningTask() const {
- return current_task_.get() != nullptr;
+ return current_task_ != nullptr;
}
void TaskQueue::StartTaskIfAvailable() {
diff --git a/chromium/components/offline_pages/resources/BUILD.gn b/chromium/components/offline_pages/resources/BUILD.gn
new file mode 100644
index 00000000000..6f9c5ecb9d2
--- /dev/null
+++ b/chromium/components/offline_pages/resources/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//third_party/closure_compiler/compile_js.gni")
+
+js_type_check("closure_compile") {
+ deps = [
+ ":renovations",
+ ]
+}
+
+js_library("renovations") {
+}
diff --git a/chromium/components/offline_pages/resources/compiled_resources2.gyp b/chromium/components/offline_pages/resources/compiled_resources2.gyp
deleted file mode 100644
index 191a74acf85..00000000000
--- a/chromium/components/offline_pages/resources/compiled_resources2.gyp
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-{
- 'targets': [
- {
- 'target_name': 'renovations',
- 'includes': ['../../../third_party/closure_compiler/compile_js2.gypi'],
- },
- ],
-}
diff --git a/chromium/components/offline_pages/resources/renovations.js b/chromium/components/offline_pages/resources/renovations.js
index 80d3881d456..5bb14785e63 100644
--- a/chromium/components/offline_pages/resources/renovations.js
+++ b/chromium/components/offline_pages/resources/renovations.js
@@ -4,12 +4,12 @@
function renovation_wikipedia() {
// Get list of elements to expand.
- elems = document.querySelectorAll(
- "div.collapsible-block,h2.collapsible-heading");
+ let elems =
+ document.querySelectorAll('div.collapsible-block,h2.collapsible-heading');
// Apply 'open-block' class to elements. This makes the sections'
// content visible.
- for (i = 0; i < elems.length; ++i) {
+ for (let i = 0; i < elems.length; ++i) {
// If a block was already expanded, re-adding the 'open-block'
// class will do nothing; no need to check if it's there already.
elems.item(i).className += " open-block";
@@ -21,18 +21,18 @@ function renovation_wikipedia() {
// disabled). We get the list of these elements in order. For every
// lazy image placeholder, there is always a corresponding noscript
// element.
- placeholders = document.querySelectorAll(
- ".image > span.lazy-image-placeholder, \
- .mwe-math-element > span.lazy-image-placeholder");
- noscripts = document.querySelectorAll(
- ".image > noscript, .mwe-math-element > noscript");
+ let placeholders = document.querySelectorAll(
+ '.image > span.lazy-image-placeholder, ' +
+ '.mwe-math-element > span.lazy-image-placeholder');
+ let noscripts = document.querySelectorAll(
+ '.image > noscript, .mwe-math-element > noscript');
// Next we delete all the placeholders, then move the img elements
// out of the noscripts, deleting the noscript element in the
// process.
- for (i = 0; i < placeholders.length; ++i) {
+ for (let i = 0; i < placeholders.length; ++i) {
placeholders.item(i).remove();
- innerText = noscripts.item(i).innerText;
+ let innerText = noscripts.item(i).innerText;
noscripts.item(i).outerHTML = innerText;
}
}
diff --git a/chromium/components/omnibox/browser/BUILD.gn b/chromium/components/omnibox/browser/BUILD.gn
index 5c02b85ae4f..765dd1b5e2a 100644
--- a/chromium/components/omnibox/browser/BUILD.gn
+++ b/chromium/components/omnibox/browser/BUILD.gn
@@ -23,7 +23,6 @@ aggregate_vector_icons("omnibox_vector_icons") {
"blank.icon",
"calculator.icon",
"extension_app.icon",
- "extension_app_20.icon",
"http.icon",
"keyword_search.icon",
"star.icon",
@@ -66,6 +65,8 @@ static_library("browser") {
"clipboard_url_provider.h",
"contextual_suggestions_service.cc",
"contextual_suggestions_service.h",
+ "favicon_cache.cc",
+ "favicon_cache.h",
"history_match.cc",
"history_match.h",
"history_provider.cc",
@@ -109,10 +110,6 @@ static_library("browser") {
"omnibox_switches.h",
"omnibox_view.cc",
"omnibox_view.h",
- "physical_web_node.cc",
- "physical_web_node.h",
- "physical_web_provider.cc",
- "physical_web_provider.h",
"scored_history_match.cc",
"scored_history_match.h",
"search_provider.cc",
@@ -157,11 +154,12 @@ static_library("browser") {
"//base:i18n",
"//components/bookmarks/browser",
"//components/data_use_measurement/core",
+ "//components/favicon/core",
+ "//components/favicon_base",
"//components/keyed_service/core",
"//components/metrics",
"//components/navigation_metrics",
"//components/open_from_clipboard",
- "//components/physical_web/data_source",
"//components/pref_registry",
"//components/prefs",
"//components/query_parser",
@@ -290,17 +288,18 @@ source_set("unit_tests") {
"bookmark_provider_unittest.cc",
"builtin_provider_unittest.cc",
"clipboard_url_provider_unittest.cc",
+ "favicon_cache_unittest.cc",
"history_provider_unittest.cc",
"history_quick_provider_unittest.cc",
"history_url_provider_unittest.cc",
"in_memory_url_index_types_unittest.cc",
"in_memory_url_index_unittest.cc",
"keyword_provider_unittest.cc",
+ "omnibox_controller_unittest.cc",
"omnibox_edit_model_unittest.cc",
"omnibox_field_trial_unittest.cc",
"omnibox_popup_model_unittest.cc",
"omnibox_view_unittest.cc",
- "physical_web_provider_unittest.cc",
"scored_history_match_unittest.cc",
"search_suggestion_parser_unittest.cc",
"shortcuts_backend_unittest.cc",
@@ -320,10 +319,9 @@ source_set("unit_tests") {
"//base",
"//components/bookmarks/browser",
"//components/bookmarks/test",
+ "//components/favicon/core/test:test_support",
"//components/history/core/test",
"//components/open_from_clipboard:test_support",
- "//components/physical_web/data_source",
- "//components/physical_web/data_source:test_support",
"//components/prefs:test_support",
"//components/search",
"//components/search_engines",
diff --git a/chromium/components/omnibox_strings.grdp b/chromium/components/omnibox_strings.grdp
index 5ff8bbbdd92..905cf841831 100644
--- a/chromium/components/omnibox_strings.grdp
+++ b/chromium/components/omnibox_strings.grdp
@@ -40,8 +40,11 @@
Search or type URL
</message>
</if>
- <message name="IDS_OMNIBOX_TAB_SUGGEST_HINT" desc="The text prefixing a suggestion description to say that this suggestion will switch to another tab.">
- Switch to tab
+ <message name="IDS_OMNIBOX_TAB_SUGGEST_HINT" desc="The button text contents to say that this suggestion will switch to another tab.">
+ Switch to this tab
+ </message>
+ <message name="IDS_OMNIBOX_TAB_SUGGEST_SHORT_HINT" desc="A shortened, one word version of button text to say that this suggestion will switch to another tab.">
+ Switch
</message>
<message name="IDS_PHYSICAL_WEB_OVERFLOW_DESCRIPTION" desc="The description in the omnibox dropdown indicating that multiple nearby devices are broadcasting URLs.">
Physical Web suggestions
diff --git a/chromium/components/omnibox_strings_grdp/OWNERS b/chromium/components/omnibox_strings_grdp/OWNERS
new file mode 100644
index 00000000000..5535cd29ae9
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/omnibox/OWNERS
diff --git a/chromium/components/omnibox_strings_grdp/README.md b/chromium/components/omnibox_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/omnibox_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/onc/docs/onc_spec.md b/chromium/components/onc/docs/onc_spec.md
index 116b305709d..8fec180ce0b 100644
--- a/chromium/components/onc/docs/onc_spec.md
+++ b/chromium/components/onc/docs/onc_spec.md
@@ -1741,29 +1741,45 @@ expansions. These allow one ONC to have basic user-specific variations.
### The expansions are:
-* ${LOGIN_ID} - expands to the email address of the user, but before the '@'.
-
-* ${LOGIN_EMAIL} - expands to the email address of the user.
+* Placeholders that will only be replaced in user-specific ONC:
+ * ${LOGIN\_ID} - expands to the email address of the user, but before
+ the '@'.
+ * ${LOGIN\_EMAIL} - expands to the email address of the user.
+
+* Placeholders that will only be replaced in device-wide ONC:
+ * ${DEVICE\_SERIAL\_NUMBER} - expands to the serial number of the device.
+ * ${DEVICE\_ASSET\_ID} - expands to the administrator-set asset ID of the
+ device.
+
+* Placeholders that will only be replaced when a client certificate has been
+ matched by a [CertificatePattern](#CertificatePattern-type):
+ * ${CERT\_SAN\_EMAIL} - expands to the first RFC822 SubjectAlternativeName
+ extracted from the client certificate.
+ * ${CERT\_SAN\_UPN} - expands to the first OtherName SubjectAlternativeName
+ with OID 1.3.6.1.4.1.311.20.2.3 (UserPrincipalName) extracted from the
+ client certificate.
+ * ${CERT\_SUBJECT\_COMMON\_NAME} - expands to the ASCII value of the Subject
+ CommonName extracted from the client certificate.
### The following SED would properly handle resolution.
-* s/\$\{LOGIN_ID\}/bobquail$1/g
+* s/\$\{LOGIN\_ID\}/bobquail$1/g
-* s/\$\{LOGIN_EMAIL\}/bobquail@example.com$1/g
+* s/\$\{LOGIN\_EMAIL\}/bobquail@example.com$1/g
### Example expansions, assuming the user was bobquail@example.com:
-* "${LOGIN_ID}" -> "bobquail"
+* "${LOGIN\_ID}" -> "bobquail"
-* "${LOGIN_ID}@corp.example.com" -> "bobquail@corp.example.com"
+* "${LOGIN\_ID}@corp.example.com" -> "bobquail@corp.example.com"
-* "${LOGIN_EMAIL}" -> "bobquail@example.com"
+* "${LOGIN\_EMAIL}" -> "bobquail@example.com"
-* "${LOGIN_ID}X" -> "bobquailX"
+* "${LOGIN\_ID}X" -> "bobquailX"
-* "${LOGIN_IDX}" -> "${LOGIN_IDX}"
+* "${LOGIN\_IDX}" -> "${LOGIN\_IDX}"
-* "X${LOGIN_ID}" -> "Xbobquail"
+* "X${LOGIN\_ID}" -> "Xbobquail"
## String Substitutions
diff --git a/chromium/components/onc/onc_constants.cc b/chromium/components/onc/onc_constants.cc
index 22d2c85af6b..681a255a497 100644
--- a/chromium/components/onc/onc_constants.cc
+++ b/chromium/components/onc/onc_constants.cc
@@ -440,11 +440,20 @@ const char kWPAD[] = "WPAD";
} // namespace proxy
namespace substitutes {
-const char kLoginIDField[] = "${LOGIN_ID}";
-const char kPasswordField[] = "${PASSWORD}";
-const char kEmailField[] = "${LOGIN_EMAIL}";
-const char kCertSANEmail[] = "${CERT_SAN_EMAIL}";
-const char kCertSANUPN[] = "${CERT_SAN_UPN}";
+const char kLoginID[] = "LOGIN_ID";
+const char kLoginEmail[] = "LOGIN_EMAIL";
+const char kCertSANEmail[] = "CERT_SAN_EMAIL";
+const char kCertSANUPN[] = "CERT_SAN_UPN";
+const char kCertSubjectCommonName[] = "CERT_SUBJECT_COMMON_NAME";
+const char kDeviceSerialNumber[] = "DEVICE_SERIAL_NUMBER";
+const char kDeviceAssetId[] = "DEVICE_ASSET_ID";
+// The password placeholder is defined as ${PASSWORD} because it's compared
+// verbatim against the policy-specified password field, and if it matches,
+// another bool (|shill::kEapUseLoginPasswordProperty|) is set, which makes
+// shill replace the whole password field.
+// The other placeholders above on the other hand are replaced using
+// VariableExpander.
+const char kPasswordPlaceholderVerbatim[] = "${PASSWORD}";
} // namespace substitutes
namespace global_network_config {
diff --git a/chromium/components/onc/onc_constants.h b/chromium/components/onc/onc_constants.h
index 281345b3f02..a662bc4f6ac 100644
--- a/chromium/components/onc/onc_constants.h
+++ b/chromium/components/onc/onc_constants.h
@@ -438,11 +438,14 @@ ONC_EXPORT extern const char kSubject[];
} // namespace verify_x509
namespace substitutes {
-ONC_EXPORT extern const char kEmailField[];
-ONC_EXPORT extern const char kPasswordField[];
-ONC_EXPORT extern const char kLoginIDField[];
+ONC_EXPORT extern const char kLoginEmail[];
+ONC_EXPORT extern const char kLoginID[];
ONC_EXPORT extern const char kCertSANEmail[];
ONC_EXPORT extern const char kCertSANUPN[];
+ONC_EXPORT extern const char kCertSubjectCommonName[];
+ONC_EXPORT extern const char kDeviceSerialNumber[];
+ONC_EXPORT extern const char kDeviceAssetId[];
+ONC_EXPORT extern const char kPasswordPlaceholderVerbatim[];
} // namespace substitutes
namespace proxy {
diff --git a/chromium/components/os_crypt/BUILD.gn b/chromium/components/os_crypt/BUILD.gn
index 0f8bbbc8103..363f0207b5e 100644
--- a/chromium/components/os_crypt/BUILD.gn
+++ b/chromium/components/os_crypt/BUILD.gn
@@ -38,7 +38,6 @@ static_library("os_crypt") {
"keychain_password_mac.mm",
"os_crypt.h",
"os_crypt_mac.mm",
- "os_crypt_posix.cc",
"os_crypt_switches.cc",
"os_crypt_switches.h",
"os_crypt_win.cc",
@@ -52,8 +51,9 @@ static_library("os_crypt") {
"//crypto:platform",
]
- if (is_mac || is_ios) {
- sources -= [ "os_crypt_posix.cc" ]
+ if ((is_posix || is_fuchsia) && !is_mac && !is_ios &&
+ (!is_desktop_linux || is_chromecast)) {
+ sources += [ "os_crypt_posix.cc" ]
}
if (is_ios) {
@@ -71,7 +71,6 @@ static_library("os_crypt") {
}
if (is_desktop_linux && !is_chromecast) {
- sources -= [ "os_crypt_posix.cc" ]
sources += [
"key_storage_config_linux.cc",
"key_storage_config_linux.h",
diff --git a/chromium/components/os_crypt/ie7_password_win.cc b/chromium/components/os_crypt/ie7_password_win.cc
index f5e9ac1ce20..5a3abc03c26 100644
--- a/chromium/components/os_crypt/ie7_password_win.cc
+++ b/chromium/components/os_crypt/ie7_password_win.cc
@@ -138,7 +138,7 @@ bool DecryptPasswords(const std::wstring& url,
url_key.cbData = static_cast<DWORD>((lower_case_url.size() + 1) *
sizeof(std::wstring::value_type));
- if (CryptUnprotectData(&input, NULL, &url_key, NULL, NULL,
+ if (CryptUnprotectData(&input, nullptr, &url_key, nullptr, nullptr,
CRYPTPROTECT_UI_FORBIDDEN, &output)) {
// Now that we have the decrypted information, we need to understand it.
std::vector<unsigned char> decrypted_data;
diff --git a/chromium/components/os_crypt/os_crypt_win.cc b/chromium/components/os_crypt/os_crypt_win.cc
index 093878d6833..b62323be9ff 100644
--- a/chromium/components/os_crypt/os_crypt_win.cc
+++ b/chromium/components/os_crypt/os_crypt_win.cc
@@ -32,8 +32,8 @@ bool OSCrypt::EncryptString(const std::string& plaintext,
input.cbData = static_cast<DWORD>(plaintext.length());
DATA_BLOB output;
- BOOL result = CryptProtectData(&input, L"", NULL, NULL, NULL,
- 0, &output);
+ BOOL result =
+ CryptProtectData(&input, L"", nullptr, nullptr, nullptr, 0, &output);
if (!result)
return false;
@@ -53,7 +53,7 @@ bool OSCrypt::DecryptString(const std::string& ciphertext,
input.cbData = static_cast<DWORD>(ciphertext.length());
DATA_BLOB output;
- BOOL result = CryptUnprotectData(&input, NULL, NULL, NULL, NULL,
+ BOOL result = CryptUnprotectData(&input, nullptr, nullptr, nullptr, nullptr,
0, &output);
if (!result)
return false;
diff --git a/chromium/components/ownership/owner_settings_service.h b/chromium/components/ownership/owner_settings_service.h
index ea4d6f98c61..e0bfed9c252 100644
--- a/chromium/components/ownership/owner_settings_service.h
+++ b/chromium/components/ownership/owner_settings_service.h
@@ -73,11 +73,11 @@ class OWNERSHIP_EXPORT OwnerSettingsService : public KeyedService {
// Returns whether current user is owner or not. When this method
// is called too early, incorrect result can be returned because
// private key loading may be in progress.
- bool IsOwner();
+ virtual bool IsOwner();
// Determines whether current user is owner or not, responds via
// |callback|.
- void IsOwnerAsync(const IsOwnerCallback& callback);
+ virtual void IsOwnerAsync(const IsOwnerCallback& callback);
// Assembles and signs |policy| on the |task_runner|, responds on
// the original thread via |callback|.
diff --git a/chromium/components/page_info_strings.grdp b/chromium/components/page_info_strings.grdp
index 69d375b36f6..be10afa9c63 100644
--- a/chromium/components/page_info_strings.grdp
+++ b/chromium/components/page_info_strings.grdp
@@ -212,8 +212,8 @@
<message name="IDS_PAGE_INFO_TYPE_JAVASCRIPT" desc="The label used for JavaScript permission controls in the Page Info popup.">
JavaScript
</message>
- <message name="IDS_PAGE_INFO_TYPE_POPUPS" desc="The label used for popups permission controls in the Page Info popup.">
- Popups
+ <message name="IDS_PAGE_INFO_TYPE_POPUPS_REDIRECTS" desc="The label used for the popup/redirect permission controls in the Page Info popup.">
+ Pop-ups and redirects
</message>
<message name="IDS_PAGE_INFO_TYPE_FLASH" desc="The label used for Flash permissions in the Page Info popup.">
Flash
@@ -365,9 +365,6 @@
<!-- Password Protection -->
<if expr="not is_android">
<message name="IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if user has reuse their google password on current website.">
- This site may have just stolen your password
- </message>
- <message name="IDS_PAGE_INFO_CHANGE_PASSWORD_SUMMARY_SOFTER" desc="A one-line summary at the top of the Page Info bubble (which shows when you click the security indicator) if user has reuse their google password on current website.">
Your password may be compromised
</message>
<if expr="_google_chrome">
diff --git a/chromium/components/page_info_strings_grdp/OWNERS b/chromium/components/page_info_strings_grdp/OWNERS
new file mode 100644
index 00000000000..7c601fd8f10
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://chrome/browser/ui/page_info/OWNERS
diff --git a/chromium/components/page_info_strings_grdp/README.md b/chromium/components/page_info_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/page_info_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/password_manager/content/DEPS b/chromium/components/password_manager/content/DEPS
index e86b35042fb..f96967fa5ab 100644
--- a/chromium/components/password_manager/content/DEPS
+++ b/chromium/components/password_manager/content/DEPS
@@ -1,7 +1,6 @@
include_rules = [
"+components/autofill/core/common",
"+content/public/common",
- "+mojo/common",
"+mojo/public",
# Allow inclusion of WebKit API files.
"+third_party/blink/public/platform",
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
index 79425948d17..ed4741525d5 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -6,6 +6,7 @@
#include <utility>
+#include "base/syslog_logging.h"
#include "components/autofill/content/browser/content_autofill_driver.h"
#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form.h"
@@ -39,7 +40,6 @@ ContentPasswordManagerDriver::ContentPasswordManagerDriver(
client_(client),
password_generation_manager_(client, this),
password_autofill_manager_(this, autofill_client, client),
- next_free_key_(0),
is_main_frame_(render_frame_host->GetParent() == nullptr),
password_manager_binding_(this),
weak_factory_(this) {
@@ -77,7 +77,7 @@ void ContentPasswordManagerDriver::BindRequest(
void ContentPasswordManagerDriver::FillPasswordForm(
const autofill::PasswordFormFillData& form_data) {
- const int key = next_free_key_++;
+ const int key = GetNextKey();
password_autofill_manager_.OnAddPasswordFormMapping(key, form_data);
GetPasswordAutofillAgent()->FillPasswordForm(
key, autofill::ClearPasswordValues(form_data));
@@ -125,7 +125,7 @@ void ContentPasswordManagerDriver::PreviewSuggestion(
void ContentPasswordManagerDriver::ShowInitialPasswordAccountSuggestions(
const autofill::PasswordFormFillData& form_data) {
- const int key = next_free_key_++;
+ const int key = GetNextKey();
password_autofill_manager_.OnAddPasswordFormMapping(key, form_data);
GetAutofillAgent()->ShowInitialPasswordAccountSuggestions(key, form_data);
}
@@ -306,13 +306,6 @@ void ContentPasswordManagerDriver::ShowPasswordSuggestions(
TransformToRootCoordinates(bounds));
}
-void ContentPasswordManagerDriver::ShowNotSecureWarning(
- base::i18n::TextDirection text_direction,
- const gfx::RectF& bounds) {
- password_autofill_manager_.OnShowNotSecureWarning(
- text_direction, TransformToRootCoordinates(bounds));
-}
-
void ContentPasswordManagerDriver::ShowManualFallbackSuggestion(
base::i18n::TextDirection text_direction,
const gfx::RectF& bounds) {
@@ -336,6 +329,8 @@ bool ContentPasswordManagerDriver::CheckChildProcessSecurityPolicy(
// about:blank frames as well as data URLs. If that's not the case, kill the
// renderer, as it might be exploited.
if (url.SchemeIs(url::kAboutScheme) || url.SchemeIs(url::kDataScheme)) {
+ SYSLOG(WARNING) << "Killing renderer: illegal password access from about: "
+ << " or data: URL. Reason: " << static_cast<int>(reason);
bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(), reason);
return false;
}
@@ -344,6 +339,8 @@ bool ContentPasswordManagerDriver::CheckChildProcessSecurityPolicy(
content::ChildProcessSecurityPolicy::GetInstance();
if (!policy->CanAccessDataForOrigin(render_frame_host_->GetProcess()->GetID(),
url)) {
+ SYSLOG(WARNING) << "Killing renderer: illegal password access. Reason: "
+ << static_cast<int>(reason);
bad_message::ReceivedBadMessage(render_frame_host_->GetProcess(), reason);
return false;
}
@@ -394,4 +391,12 @@ gfx::RectF ContentPasswordManagerDriver::TransformToRootCoordinates(
bounds_in_frame_coordinates.size());
}
+int ContentPasswordManagerDriver::GetNextKey() {
+ // Limit the range of the key to avoid excessive allocations. See
+ // https://crbug.com/846404.
+ constexpr int kMaxKeyRange = 4 * 1024;
+ next_free_key_ = (next_free_key_ + 1) % kMaxKeyRange;
+ return next_free_key_;
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver.h b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
index 94e775911ce..7fe883b92c5 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver.h
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver.h
@@ -106,8 +106,6 @@ class ContentPasswordManagerDriver
const base::string16& typed_username,
int options,
const gfx::RectF& bounds) override;
- void ShowNotSecureWarning(base::i18n::TextDirection text_direction,
- const gfx::RectF& bounds) override;
void ShowManualFallbackSuggestion(base::i18n::TextDirection text_direction,
const gfx::RectF& bounds) override;
void RecordSavePasswordProgress(const std::string& log) override;
@@ -136,6 +134,10 @@ class ContentPasswordManagerDriver
gfx::RectF TransformToRootCoordinates(
const gfx::RectF& bounds_in_frame_coordinates);
+ // Returns the next key to be used for PasswordFormFillData sent to
+ // PasswordAutofillManager and PasswordAutofillAgent.
+ int GetNextKey();
+
content::RenderFrameHost* render_frame_host_;
PasswordManagerClient* client_;
PasswordGenerationManager password_generation_manager_;
@@ -145,7 +147,9 @@ class ContentPasswordManagerDriver
// PasswordAutofillManager and PasswordAutofillAgent is given an ID, so that
// the latter two classes can reference to the same instance without sending
// it to each other over IPC. The counter below is used to generate new IDs.
- int next_free_key_;
+ // The counter cycles over a limited range of values, see
+ // https://crbug.com/846404#c5.
+ int next_free_key_ = 0;
// It should be filled in the constructor, since later the frame might be
// detached and it would be impossible to check whether the frame is a main
diff --git a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 500bc3af514..7a8ba9fedff 100644
--- a/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/chromium/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -126,7 +126,7 @@ PasswordFormFillData GetTestPasswordFormFillData() {
matches[non_preferred_match.username_value] = &non_preferred_match;
PasswordFormFillData result;
- InitPasswordFormFillData(form_on_page, matches, &preferred_match, true, false,
+ InitPasswordFormFillData(form_on_page, matches, &preferred_match, true,
&result);
return result;
}
diff --git a/chromium/components/password_manager/core/browser/BUILD.gn b/chromium/components/password_manager/core/browser/BUILD.gn
index 3309194ea84..e26d296486d 100644
--- a/chromium/components/password_manager/core/browser/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/BUILD.gn
@@ -77,16 +77,20 @@ static_library("browser") {
"login_database.h",
"login_database_ios.cc",
"login_database_mac.cc",
- "login_database_posix.cc",
"login_database_win.cc",
"login_model.cc",
"login_model.h",
+ "new_password_form_manager.cc",
+ "new_password_form_manager.h",
"password_autofill_manager.cc",
"password_autofill_manager.h",
"password_bubble_experiment.cc",
"password_bubble_experiment.h",
+ "password_form_filling.cc",
+ "password_form_filling.h",
"password_form_manager.cc",
"password_form_manager.h",
+ "password_form_manager_for_ui.h",
"password_form_metrics_recorder.cc",
"password_form_metrics_recorder.h",
"password_form_user_action.h",
@@ -181,6 +185,7 @@ static_library("browser") {
"//components/autofill/core/common",
"//components/keyed_service/core",
"//components/os_crypt",
+ "//components/password_manager/core/browser/form_parsing",
"//components/password_manager/core/common",
"//components/pref_registry",
"//components/prefs",
@@ -202,6 +207,13 @@ static_library("browser") {
"//url",
]
+ if (password_reuse_detection_support) {
+ deps += [
+ "//components/safe_browsing:features",
+ "//components/safe_browsing/common:safe_browsing_prefs",
+ ]
+ }
+
if (!is_ios) {
sources += [
"hsts_query.cc",
@@ -209,8 +221,8 @@ static_library("browser") {
]
}
- if (is_mac || is_ios) {
- sources -= [ "login_database_posix.cc" ]
+ if (is_posix && !is_mac && !is_ios) {
+ sources += [ "login_database_posix.cc" ]
}
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
@@ -270,6 +282,7 @@ static_library("test_support") {
public_deps = [
":browser",
+ ":hash_password_manager",
"//components/ukm",
"//testing/gmock",
"//url:url",
@@ -346,8 +359,10 @@ source_set("unit_tests") {
"log_router_unittest.cc",
"login_database_unittest.cc",
"login_model_unittest.cc",
+ "new_password_form_manager_unittest.cc",
"password_autofill_manager_unittest.cc",
"password_bubble_experiment_unittest.cc",
+ "password_form_filling_unittest.cc",
"password_form_manager_unittest.cc",
"password_form_metrics_recorder_unittest.cc",
"password_generation_manager_unittest.cc",
@@ -394,8 +409,10 @@ source_set("unit_tests") {
"//components/autofill/core/browser:test_support",
"//components/autofill/core/browser/proto",
"//components/autofill/core/common",
+ "//components/os_crypt",
"//components/os_crypt:test_support",
"//components/password_manager/core/browser:proto",
+ "//components/password_manager/core/browser/form_parsing:unit_tests",
"//components/password_manager/core/browser/form_parsing/fuzzer:unit_tests",
"//components/password_manager/core/common",
"//components/prefs:test_support",
@@ -414,6 +431,13 @@ source_set("unit_tests") {
"//url",
]
+ if (password_reuse_detection_support) {
+ deps += [
+ "//components/safe_browsing:features",
+ "//components/safe_browsing/common:safe_browsing_prefs",
+ ]
+ }
+
if (is_ios) {
deps +=
[ "//components/password_manager/core/browser/form_parsing:unit_tests" ]
diff --git a/chromium/components/password_manager/core/browser/DEPS b/chromium/components/password_manager/core/browser/DEPS
index abf89f4cae0..b62763e00cd 100644
--- a/chromium/components/password_manager/core/browser/DEPS
+++ b/chromium/components/password_manager/core/browser/DEPS
@@ -3,6 +3,8 @@ include_rules = [
"+components/keyed_service/core",
"+components/pref_registry",
"+components/security_state",
+ "+components/safe_browsing/common/safe_browsing_prefs.h",
+ "+components/safe_browsing/features.h",
"+components/sync/base",
"+components/sync/driver",
"+components/url_formatter",
@@ -28,4 +30,7 @@ specific_include_rules = {
"password_manager_metrics_recorder_unittest\.cc": [
"+components/ukm",
],
+ "password_manager_unittest\.cc": [
+ "+components/ukm",
+ ],
}
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
index a2b73635aac..7b77ba19030 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliated_match_helper_unittest.cc
@@ -185,6 +185,11 @@ class AffiliatedMatchHelperTest : public testing::Test {
AffiliatedMatchHelper::kInitializationDelayOnStartup);
}
+ void ExpectNoDeferredTasks() {
+ mock_time_task_runner_->RunUntilIdle();
+ ASSERT_FALSE(mock_time_task_runner_->HasPendingTask());
+ }
+
void RunUntilIdle() {
// TODO(gab): Add support for base::RunLoop().RunUntilIdle() in scope of
// ScopedMockTimeMessageLoopTaskRunner and use it instead of this helper
@@ -666,7 +671,7 @@ TEST_F(AffiliatedMatchHelperTest, DestroyBeforeDeferredInitialization) {
match_helper()->Initialize();
RunUntilIdle();
DestroyMatchHelper();
- ASSERT_NO_FATAL_FAILURE(RunDeferredInitialization());
+ ASSERT_NO_FATAL_FAILURE(ExpectNoDeferredTasks());
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
index 4a638875eda..127845381ff 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_backend_unittest.cc
@@ -45,7 +45,7 @@ class MockAffiliationFetchThrottler : public AffiliationFetchThrottler {
EXPECT_CALL(*this, OnInformOfNetworkRequestComplete(testing::_)).Times(0);
}
- ~MockAffiliationFetchThrottler() {
+ ~MockAffiliationFetchThrottler() override {
EXPECT_FALSE(signaled_network_request_needed_);
}
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
index 9f6e67a7101..41a22de0a5e 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_database_unittest.cc
@@ -342,7 +342,7 @@ TEST_F(AffiliationDatabaseTest, MigrateFromVersion1) {
CloseDatabase();
AffiliationDatabase::Delete(db_path());
base::FilePath src_root_dir;
- ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_root_dir));
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root_dir));
base::FilePath sql_path_v1 = src_root_dir.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
@@ -383,7 +383,7 @@ TEST_F(AffiliationDatabaseTest, InitializeFromVersion2) {
CloseDatabase();
AffiliationDatabase::Delete(db_path());
base::FilePath src_root_dir;
- ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &src_root_dir));
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &src_root_dir));
base::FilePath sql_path_v2 = src_root_dir.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc
index 016b37842a8..8c044d6ef7e 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetch_throttler_unittest.cc
@@ -411,7 +411,8 @@ TEST_F(AffiliationFetchThrottlerTest, InstanceDestroyedWhileInBackoff) {
throttler->SignalNetworkRequestNeeded();
throttler.reset();
- EXPECT_EQ(1u, GetPendingTaskCount());
+ // We expect the task to be cancelled.
+ EXPECT_EQ(0u, GetPendingTaskCount());
AssertNoReleaseUntilNoTasksRemain();
}
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
index a72b8bd2279..79351debdc7 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
@@ -42,7 +42,7 @@ class MockAffiliationFetcherDelegate
result_ = std::move(result);
}
- const Result& result() const { return *result_.get(); }
+ const Result& result() const { return *result_; }
private:
std::unique_ptr<Result> result_;
diff --git a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
index f206c88b693..c5e91cb0220 100644
--- a/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
+++ b/chromium/components/password_manager/core/browser/android_affiliation/affiliation_utils.cc
@@ -156,7 +156,7 @@ bool CanonicalizeAndroidFacetURI(const std::string& input_uri,
// We cannot use url::CanonicalizeHost as that would convert the package name
// to lower case, but the package name is case sensitive.
success &= CanonicalizePackageNameComponent(
- ComponentString(input_uri.data(), input_parsed.host), &canonical_output);
+ ComponentString(input_uri, input_parsed.host), &canonical_output);
canonical_output.Complete();
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
index c4d79d28522..25afbbbc4cf 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.cc
@@ -130,12 +130,14 @@ std::string BrowserSavePasswordProgressLogger::FormStructureToFieldsLogString(
std::string result;
result += GetStringFromID(STRING_FIELDS) + ": " + "\n";
for (const auto& field : form_structure) {
- std::string field_info = ScrubElementID(field->name) + ": " +
- ScrubNonDigit(field->FieldSignatureAsStr()) +
- ", " + ScrubElementID(field->form_control_type);
+ std::string field_info =
+ ScrubElementID(field->name) + ": " +
+ ScrubNonDigit(field->FieldSignatureAsStr()) +
+ ", type=" + ScrubElementID(field->form_control_type);
if (!field->autocomplete_attribute.empty())
- field_info += ", " + ScrubElementID(field->autocomplete_attribute);
+ field_info +=
+ ", autocomplete=" + ScrubElementID(field->autocomplete_attribute);
if (!field->Type().IsUnknown())
field_info += ", SERVER_PREDICTION: " + field->Type().ToString();
@@ -144,6 +146,26 @@ std::string BrowserSavePasswordProgressLogger::FormStructureToFieldsLogString(
field_info +=
", VOTE: " + autofill::AutofillType::ServerFieldTypeToString(type);
+ if (field->properties_mask) {
+ field_info += ", properties = ";
+ field_info +=
+ (field->properties_mask & autofill::FieldPropertiesFlags::USER_TYPED)
+ ? "T"
+ : "_";
+ field_info +=
+ (field->properties_mask & autofill::FieldPropertiesFlags::AUTOFILLED)
+ ? "A"
+ : "_";
+ field_info +=
+ (field->properties_mask & autofill::FieldPropertiesFlags::HAD_FOCUS)
+ ? "F"
+ : "_";
+ field_info +=
+ (field->properties_mask & autofill::FieldPropertiesFlags::KNOWN_VALUE)
+ ? "K"
+ : "_";
+ }
+
std::string generation = GenerationTypeToString(field->generation_type());
if (!generation.empty())
field_info += ", GENERATION_EVENT: " + generation;
@@ -174,6 +196,42 @@ void BrowserSavePasswordProgressLogger::LogSuccessfulSubmissionIndicatorEvent(
SendLog(message);
}
+void BrowserSavePasswordProgressLogger::LogFormData(
+ StringID label,
+ const autofill::FormData& form) {
+ std::string message = GetStringFromID(label) + ": {\n";
+ message +=
+ GetStringFromID(STRING_ORIGIN) + ": " + ScrubURL(form.origin) + "\n";
+ message +=
+ GetStringFromID(STRING_ACTION) + ": " + ScrubURL(form.action) + "\n";
+ if (form.main_frame_origin.GetURL().is_valid())
+ message += GetStringFromID(STRING_MAIN_FRAME_ORIGIN) + ": " +
+ ScrubURL(form.main_frame_origin.GetURL()) + "\n";
+ message += GetStringFromID(STRING_FORM_NAME) + ": " +
+ ScrubElementID(form.name) + "\n";
+
+ message += GetStringFromID(STRING_IS_FORM_TAG) + ": " +
+ (form.is_form_tag ? "true" : "false") + "\n";
+
+ // Log fields.
+ message += GetStringFromID(STRING_FIELDS) + ": " + "\n";
+ for (const auto& field : form.fields) {
+ std::string is_visible = field.is_focusable ? "visible" : "invisible";
+ std::string is_empty = field.value.empty() ? "empty" : "non-empty";
+ std::string autocomplete =
+ field.autocomplete_attribute.empty()
+ ? std::string()
+ : (", autocomplete=" +
+ ScrubElementID(field.autocomplete_attribute));
+ std::string field_info = ScrubElementID(field.name) + ": type=" +
+ ScrubElementID(field.form_control_type) + ", " +
+ is_visible + ", " + is_empty + autocomplete + "\n";
+ message += field_info;
+ }
+ message += "}";
+ SendLog(message);
+}
+
void BrowserSavePasswordProgressLogger::SendLog(const std::string& log) {
log_manager_->LogSavePasswordProgress(log);
}
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h
index de2f893b0b5..e820d23358e 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger.h
@@ -13,6 +13,7 @@
#include "url/gurl.h"
namespace autofill {
+struct FormData;
class FormStructure;
}
@@ -50,6 +51,10 @@ class BrowserSavePasswordProgressLogger
void LogSuccessfulSubmissionIndicatorEvent(
autofill::PasswordForm::SubmissionIndicatorEvent event);
+ // Browser-specific addition to the base class' Log* methods. The input is
+ // sanitized and passed to SendLog for display.
+ void LogFormData(StringID label, const autofill::FormData& form);
+
protected:
// autofill::SavePasswordProgressLogger:
void SendLog(const std::string& log) override;
diff --git a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger_unittest.cc b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger_unittest.cc
index 82d725bf6d5..ee3695be0d3 100644
--- a/chromium/components/password_manager/core/browser/browser_save_password_progress_logger_unittest.cc
+++ b/chromium/components/password_manager/core/browser/browser_save_password_progress_logger_unittest.cc
@@ -42,27 +42,41 @@ class MockLogManager : public StubLogManager {
MOCK_CONST_METHOD1(LogSavePasswordProgress, void(const std::string& text));
};
+class BrowserSavePasswordProgressLoggerTest : public testing::Test {
+ public:
+ BrowserSavePasswordProgressLoggerTest() {
+ form_.origin = GURL("http://myform.com/form.html");
+ form_.action = GURL("http://m.myform.com/submit.html");
+ form_.name = base::UTF8ToUTF16("form_name");
+
+ // Add a password field.
+ autofill::FormFieldData field;
+ field.name = base::UTF8ToUTF16("password");
+ field.form_control_type = "password";
+ field.is_focusable = true;
+ field.autocomplete_attribute = "new-password";
+ form_.fields.push_back(field);
+
+ // Add a text field.
+ field.name = base::UTF8ToUTF16("email");
+ field.form_control_type = "text";
+ field.is_focusable = false;
+ field.value = base::UTF8ToUTF16("a@example.com");
+ field.autocomplete_attribute.clear();
+ form_.fields.push_back(field);
+ }
+
+ protected:
+ autofill::FormData form_;
+};
+
} // namespace
-TEST(BrowserSavePasswordProgressLoggerTest, LogFormSignatures) {
+TEST_F(BrowserSavePasswordProgressLoggerTest, LogFormSignatures) {
MockLogManager log_manager;
TestLogger logger(&log_manager);
- autofill::FormData form;
- form.origin = GURL("http://myform.com/form.html");
- form.action = GURL("http://m.myform.com/submit.html");
-
- // Add a password field.
- autofill::FormFieldData field;
- field.name = base::UTF8ToUTF16("password");
- field.form_control_type = "password";
- form.fields.push_back(field);
-
- // Add a text field.
- field.name = base::UTF8ToUTF16("email");
- field.form_control_type = "text";
- form.fields.push_back(field);
- autofill::FormStructure form_structure(form);
+ autofill::FormStructure form_structure(form_);
// Add a vote, a generation event and a client-side classifier outcome to the
// password field.
@@ -76,7 +90,7 @@ TEST(BrowserSavePasswordProgressLoggerTest, LogFormSignatures) {
autofill::AutofillUploadContents::Field::GENERATION_ELEMENT);
// Add a server prediction for the text field.
- form_structure.field(1)->set_overall_server_type(autofill::EMAIL_ADDRESS);
+ form_structure.field(1)->set_server_type(autofill::EMAIL_ADDRESS);
logger.LogFormStructure(
autofill::SavePasswordProgressLogger::STRING_FORM_VOTES, form_structure);
@@ -87,11 +101,30 @@ TEST(BrowserSavePasswordProgressLoggerTest, LogFormSignatures) {
EXPECT_TRUE(logger.LogsContainSubstring("Origin: http://myform.com"));
EXPECT_TRUE(logger.LogsContainSubstring("Form fields:"));
EXPECT_TRUE(logger.LogsContainSubstring(
- "password: 2051817934, password, VOTE: NEW_PASSWORD, GENERATION_EVENT: "
+ "password: 2051817934, type=password, autocomplete=new-password, VOTE: "
+ "NEW_PASSWORD, GENERATION_EVENT: "
"Manual generation on sign-up, CLIENT_SIDE_CLASSIFIER: Generation "
"element"));
EXPECT_TRUE(logger.LogsContainSubstring(
- "email: 420638584, text, SERVER_PREDICTION: EMAIL_ADDRESS"));
+ "email: 420638584, type=text, SERVER_PREDICTION: EMAIL_ADDRESS"));
+}
+
+TEST_F(BrowserSavePasswordProgressLoggerTest, LogFormData) {
+ MockLogManager log_manager;
+ TestLogger logger(&log_manager);
+ logger.LogFormData(
+ autofill::SavePasswordProgressLogger::STRING_FORM_PARSING_INPUT, form_);
+ SCOPED_TRACE(testing::Message()
+ << "Log string = [" << logger.accumulated_log() << "]");
+ EXPECT_TRUE(logger.LogsContainSubstring("Origin: http://myform.com"));
+ EXPECT_TRUE(logger.LogsContainSubstring("Action: http://m.myform.com"));
+ EXPECT_TRUE(logger.LogsContainSubstring("Form name: form_name"));
+ EXPECT_TRUE(logger.LogsContainSubstring("Form with form tag: true"));
+ EXPECT_TRUE(logger.LogsContainSubstring("Form fields:"));
+ EXPECT_TRUE(logger.LogsContainSubstring(
+ "password: type=password, visible, empty, autocomplete=new-password"));
+ EXPECT_TRUE(
+ logger.LogsContainSubstring("email: type=text, invisible, non-empty"));
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl.cc b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
index c8d85dd967d..16baac07a52 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl.cc
@@ -217,7 +217,7 @@ void CredentialManagerImpl::DoneRequiringUserMediation() {
void CredentialManagerImpl::OnProvisionalSaveComplete() {
DCHECK(form_manager_);
DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage());
- const autofill::PasswordForm& form = form_manager_->pending_credentials();
+ const autofill::PasswordForm& form = form_manager_->GetPendingCredentials();
if (form_manager_->IsPendingCredentialsPublicSuffixMatch()) {
// Having a credential with a PSL match implies there is no credential with
@@ -231,7 +231,7 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
// If this is a federated credential, check it against the federated matches
// produced by the PasswordFormManager. If a match is found, update it and
// return.
- for (auto* match : form_manager_->form_fetcher()->GetFederatedMatches()) {
+ for (auto* match : form_manager_->GetFormFetcher()->GetFederatedMatches()) {
if (match->username_value == form.username_value &&
match->federation_origin.IsSameOriginWith(form.federation_origin)) {
form_manager_->Update(*match);
@@ -244,7 +244,7 @@ void CredentialManagerImpl::OnProvisionalSaveComplete() {
// 'skip_zero_click' state, as we've gotten an explicit signal that the page
// understands the credential management API and so can be trusted to notify
// us when they sign the user out.
- form_manager_->Update(form_manager_->pending_credentials());
+ form_manager_->Update(form_manager_->GetPendingCredentials());
return;
}
diff --git a/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
index 939c5c140ce..c0daf539fea 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_impl_unittest.cc
@@ -53,7 +53,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
MOCK_METHOD1(NotifyUserCouldBeAutoSignedInPtr,
bool(autofill::PasswordForm* form));
MOCK_METHOD0(NotifyStorePasswordCalled, void());
- MOCK_METHOD1(PromptUserToSavePasswordPtr, void(PasswordFormManager*));
+ MOCK_METHOD1(PromptUserToSavePasswordPtr, void(PasswordFormManagerForUI*));
MOCK_METHOD3(PromptUserToChooseCredentialsPtr,
bool(const std::vector<autofill::PasswordForm*>& local_forms,
const GURL& origin,
@@ -70,7 +70,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
~MockPasswordManagerClient() override {}
bool PromptUserToSaveOrUpdatePassword(
- std::unique_ptr<PasswordFormManager> manager,
+ std::unique_ptr<PasswordFormManagerForUI> manager,
bool update_password) override {
manager_.swap(manager);
PromptUserToSavePasswordPtr(manager_.get());
@@ -119,7 +119,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
NotifyUserAutoSigninPtr();
}
- PasswordFormManager* pending_manager() const { return manager_.get(); }
+ PasswordFormManagerForUI* pending_manager() const { return manager_.get(); }
void set_zero_click_enabled(bool zero_click_enabled) {
prefs_->SetBoolean(prefs::kCredentialsEnableAutosignin, zero_click_enabled);
@@ -137,7 +137,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
private:
std::unique_ptr<TestingPrefServiceSimple> prefs_;
PasswordStore* store_;
- std::unique_ptr<PasswordFormManager> manager_;
+ std::unique_ptr<PasswordFormManagerForUI> manager_;
PasswordManager password_manager_;
GURL last_committed_url_{kTestWebOrigin};
@@ -373,10 +373,10 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStore) {
EXPECT_TRUE(called);
EXPECT_EQ(FormFetcher::State::NOT_WAITING,
- client_->pending_manager()->form_fetcher()->GetState());
+ client_->pending_manager()->GetFormFetcher()->GetState());
autofill::PasswordForm new_form =
- client_->pending_manager()->pending_credentials();
+ client_->pending_manager()->GetPendingCredentials();
EXPECT_EQ(form_.username_value, new_form.username_value);
EXPECT_EQ(form_.display_name, new_form.display_name);
EXPECT_EQ(form_.password_value, new_form.password_value);
@@ -406,10 +406,10 @@ TEST_F(CredentialManagerImplTest, CredentialManagerOnStoreFederated) {
EXPECT_TRUE(called);
EXPECT_EQ(FormFetcher::State::NOT_WAITING,
- client_->pending_manager()->form_fetcher()->GetState());
+ client_->pending_manager()->GetFormFetcher()->GetState());
autofill::PasswordForm new_form =
- client_->pending_manager()->pending_credentials();
+ client_->pending_manager()->GetPendingCredentials();
EXPECT_EQ(form_.username_value, new_form.username_value);
EXPECT_EQ(form_.display_name, new_form.display_name);
EXPECT_EQ(form_.password_value, new_form.password_value);
@@ -445,7 +445,7 @@ TEST_F(CredentialManagerImplTest, StoreFederatedAfterPassword) {
EXPECT_TRUE(called);
EXPECT_EQ(FormFetcher::State::NOT_WAITING,
- client_->pending_manager()->form_fetcher()->GetState());
+ client_->pending_manager()->GetFormFetcher()->GetState());
client_->pending_manager()->Save();
RunAllPendingTasks();
@@ -550,7 +550,8 @@ TEST_F(CredentialManagerImplTest,
EXPECT_EQ(1U, passwords.size());
EXPECT_EQ(1U, passwords[psl_form.signon_realm].size());
- const auto& pending_cred = client_->pending_manager()->pending_credentials();
+ const auto& pending_cred =
+ client_->pending_manager()->GetPendingCredentials();
EXPECT_EQ(info.id, pending_cred.username_value);
EXPECT_EQ(info.password, pending_cred.password_value);
}
@@ -581,7 +582,8 @@ TEST_F(CredentialManagerImplTest,
EXPECT_EQ(1U, passwords.size());
EXPECT_EQ(1U, passwords[psl_form.signon_realm].size());
- const auto& pending_cred = client_->pending_manager()->pending_credentials();
+ const auto& pending_cred =
+ client_->pending_manager()->GetPendingCredentials();
EXPECT_EQ(info.id, pending_cred.username_value);
EXPECT_EQ(info.password, pending_cred.password_value);
}
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
index 323dff0c2ec..db5408e5a26 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager.cc
@@ -55,7 +55,7 @@ void CredentialManagerPasswordFormManager::ProcessMatches(
// Mark the form as "preferred", as we've been told by the API that this is
// indeed the credential set that the user used to sign into the site.
saved_form_->preferred = true;
- ProvisionallySave(*saved_form_, IGNORE_OTHER_POSSIBLE_USERNAMES);
+ ProvisionallySave(*saved_form_);
// Notify the delegate. This might result in deleting |this|, while
// ProcessMatches is being called from FormFetcherImpl, owned by |this|. If
diff --git a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
index a691345bb59..b5d30ef1dca 100644
--- a/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/credential_manager_password_form_manager_unittest.cc
@@ -59,7 +59,7 @@ TEST_F(CredentialManagerPasswordFormManagerTest, AbortEarly) {
// |form_manager| should call the delegate's OnProvisionalSaveComplete, which
// in turn should delete |form_fetcher|.
EXPECT_CALL(delegate, OnProvisionalSaveComplete()).WillOnce(Invoke(deleter));
- static_cast<FakeFormFetcher*>(form_manager->form_fetcher())
+ static_cast<FakeFormFetcher*>(form_manager->GetFormFetcher())
->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
// Check that |form_manager| was not deleted yet; doing so would have caused
// use after free during SetNonFederated.
diff --git a/chromium/components/password_manager/core/browser/credentials_filter.h b/chromium/components/password_manager/core/browser/credentials_filter.h
index aec30291a22..cf5038cabe1 100644
--- a/chromium/components/password_manager/core/browser/credentials_filter.h
+++ b/chromium/components/password_manager/core/browser/credentials_filter.h
@@ -27,6 +27,11 @@ class CredentialsFilter {
// Should |form| be offered to be saved?
virtual bool ShouldSave(const autofill::PasswordForm& form) const = 0;
+ // Returns true if the hash of |form.password_value| should be saved for
+ // password reuse checking.
+ virtual bool ShouldSavePasswordHash(
+ const autofill::PasswordForm& form) const = 0;
+
// Call this if the form associated with |form_manager| was filled, and the
// subsequent sign-in looked like a success.
virtual void ReportFormLoginSuccess(
diff --git a/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn b/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn
index 1ab9c565fda..7c5e844c480 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/form_parsing/BUILD.gn
@@ -4,37 +4,31 @@
import("//build/config/sanitizers/sanitizers.gni")
-# Determine whetner fuzzer_test targets are built.
-does_fuzzer_test_compile =
- !disable_libfuzzer && (use_fuzzing_engine || use_drfuzz || is_linux)
+static_library("form_parsing") {
+ sources = [
+ # TODO(https://crbug.com/831123): Make compilation of ios_form_parser only for iOS, when it is not needed for experimentation anymore.
+ "ios_form_parser.cc",
+ "ios_form_parser.h",
+ ]
-if (does_fuzzer_test_compile || is_ios) {
- # Compile for production under iOS and for fuzzing whenever fuzzer_tests are built.
- static_library("form_parsing") {
- sources = [
- "ios_form_parser.cc",
- "ios_form_parser.h",
- ]
+ deps = [
+ "//base",
+ "//components/autofill/core/common",
+ ]
+}
- deps = [
- "//base",
- "//components/autofill/core/common",
- ]
- }
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "ios_form_parser_unittest.cc",
+ ]
- source_set("unit_tests") {
- testonly = true
- sources = [
- "ios_form_parser_unittest.cc",
- ]
-
- deps = [
- ":form_parsing",
- "//base",
- "//components/autofill/core/common",
- "//testing/gmock",
- "//testing/gtest",
- "//url",
- ]
- }
-} # if (does_fuzzer_test_compile || is_ios)
+ deps = [
+ ":form_parsing",
+ "//base",
+ "//components/autofill/core/common",
+ "//testing/gmock",
+ "//testing/gtest",
+ "//url",
+ ]
+}
diff --git a/chromium/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn
index c763341225c..cba3911fbee 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn
+++ b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/BUILD.gn
@@ -3,19 +3,16 @@
# found in the LICENSE file.
import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/protobuf/proto_library.gni")
static_library("fuzzer_support") {
sources = [
"data_accessor.cc",
"data_accessor.h",
- "form_data_producer.cc",
- "form_data_producer.h",
]
deps = [
"//base",
- "//components/autofill/core/common",
- "//url",
]
}
@@ -34,6 +31,8 @@ source_set("unit_tests") {
fuzzer_test("password_manager_form_parser_fuzzer") {
sources = [
+ "form_data_producer.cc",
+ "form_data_producer.h",
"form_parser_fuzzer.cc",
]
@@ -43,7 +42,34 @@ fuzzer_test("password_manager_form_parser_fuzzer") {
"//base:i18n",
"//components/autofill/core/common",
"//components/password_manager/core/browser/form_parsing",
+ "//url",
]
dict = "form_parser_fuzzer.dict"
}
+
+fuzzer_test("password_manager_form_parser_proto_fuzzer") {
+ sources = [
+ "form_data_proto_producer.cc",
+ "form_data_proto_producer.h",
+ "form_parser_proto_fuzzer.cc",
+ ]
+
+ deps = [
+ ":form_data_essentials_proto",
+ "//base",
+ "//base:i18n",
+ "//components/autofill/core/common",
+ "//components/password_manager/core/browser/form_parsing",
+ "//third_party/libprotobuf-mutator",
+ "//url",
+ ]
+
+ dict = "form_parser_fuzzer.dict"
+}
+
+proto_library("form_data_essentials_proto") {
+ sources = [
+ "form_data_essentials.proto",
+ ]
+}
diff --git a/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto
new file mode 100644
index 00000000000..73e87f45dda
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.proto
@@ -0,0 +1,32 @@
+// 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.
+
+syntax = "proto3";
+package form_data_fuzzer;
+
+// The FormField message describes those data members of
+// autofill::FormFieldData, which are interesting for the FormData parsing code
+// being fuzzed.
+message FormField {
+ bool is_focusable = 1;
+ string form_control_type = 2;
+ string autocomplete_attribute = 3;
+ string label = 4;
+ string name = 5;
+ string id = 6;
+ string value = 7;
+}
+
+// The Form message describes those data members of autofill::FormData, which
+// are interesting for the FormData parsing code being fuzzed.
+message Form {
+ bool is_mode_filling = 1;
+ bool is_form_tag = 2;
+ bool is_formless_checkout = 3;
+ string name = 4;
+ string action = 5;
+ string origin = 6;
+ string main_frame_origin = 7;
+ repeated FormField fields = 8;
+}
diff --git a/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc
new file mode 100644
index 00000000000..4b375a8f621
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/form_field_data.h"
+#include "components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.pb.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+using autofill::FormData;
+using autofill::FormFieldData;
+using base::UTF8ToUTF16;
+
+namespace password_manager {
+
+FormData GenerateWithProto(const ::form_data_fuzzer::Form& form_proto) {
+ FormData result;
+
+ result.is_form_tag = form_proto.is_form_tag();
+ result.is_formless_checkout = form_proto.is_formless_checkout();
+ result.name = UTF8ToUTF16(form_proto.name());
+ result.action = GURL(form_proto.action());
+ result.origin = GURL(form_proto.origin());
+ result.main_frame_origin =
+ url::Origin::Create(GURL(form_proto.main_frame_origin()));
+
+ result.fields.resize(form_proto.fields_size());
+ for (int i = 0; i < form_proto.fields_size(); ++i) {
+ const ::form_data_fuzzer::FormField& form_data_proto = form_proto.fields(i);
+ result.fields[i].is_focusable = form_data_proto.is_focusable();
+ result.fields[i].form_control_type = form_data_proto.form_control_type();
+ result.fields[i].autocomplete_attribute =
+ form_data_proto.autocomplete_attribute();
+ result.fields[i].label = UTF8ToUTF16(form_data_proto.label());
+ result.fields[i].name = UTF8ToUTF16(form_data_proto.name());
+ result.fields[i].id = UTF8ToUTF16(form_data_proto.id());
+ result.fields[i].value = UTF8ToUTF16(form_data_proto.value());
+ }
+
+ return result;
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.h b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.h
new file mode 100644
index 00000000000..2542323f889
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.h
@@ -0,0 +1,23 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_PARSING_FUZZER_FORM_DATA_PROTO_PRODUCER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_PARSING_FUZZER_FORM_DATA_PROTO_PRODUCER_H_
+
+#include "components/autofill/core/common/form_data.h"
+
+namespace form_data_fuzzer {
+class Form;
+}
+
+namespace password_manager {
+
+// Generates a |FormData| object based on values represented by a parsed
+// protobuf |form_proto|.
+autofill::FormData GenerateWithProto(
+ const ::form_data_fuzzer::Form& form_proto);
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_FORM_PARSING_FUZZER_FORM_DATA_PROTO_PRODUCER_H_
diff --git a/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_fuzzer.cc b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_fuzzer.cc
new file mode 100644
index 00000000000..d4728e3e8e4
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/form_parsing/fuzzer/form_parser_proto_fuzzer.cc
@@ -0,0 +1,42 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/at_exit.h"
+#include "base/i18n/icu_util.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/form_parsing/fuzzer/form_data_essentials.pb.h"
+#include "components/password_manager/core/browser/form_parsing/fuzzer/form_data_proto_producer.h"
+#include "components/password_manager/core/browser/form_parsing/ios_form_parser.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+namespace password_manager {
+
+// ICU is used inside GURL parser, which is used by GenerateWithDataAccessor.
+struct IcuEnvironment {
+ IcuEnvironment() { CHECK(base::i18n::InitializeICU()); }
+ // used by ICU integration.
+ base::AtExitManager at_exit_manager;
+};
+
+IcuEnvironment* env = new IcuEnvironment();
+
+DEFINE_BINARY_PROTO_FUZZER(const ::form_data_fuzzer::Form& form_proto) {
+ FormParsingMode mode = form_proto.is_mode_filling() ? FormParsingMode::FILLING
+ : FormParsingMode::SAVING;
+ autofill::FormData form_data = GenerateWithProto(form_proto);
+ std::unique_ptr<autofill::PasswordForm> result =
+ ParseFormData(form_data, mode);
+ if (result) {
+ // Create a copy of the result -- running the copy-constructor might
+ // discover some invalid data in |result|.
+ autofill::PasswordForm copy(*result);
+ }
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser.cc b/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser.cc
index ff2e1b4426c..501a3b193be 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser.cc
@@ -67,17 +67,28 @@ bool HasAutocompleteAttributeValue(const FormFieldData& field,
}) != tokens.end();
}
-// Returns fields that do not have credit card related autocomplete attributes.
-FieldPointersVector GetNonCreditCardFields(
- const std::vector<FormFieldData>& fields) {
+// Returns text fields from |fields|.
+FieldPointersVector GetTextFields(const std::vector<FormFieldData>& fields) {
FieldPointersVector result;
+ result.reserve(fields.size());
for (const auto& field : fields) {
- if (!HasCreditCardAutocompleteAttributes(field))
+ if (field.IsTextInputElement())
result.push_back(&field);
}
return result;
}
+// Returns fields that do not have credit card related autocomplete attributes.
+FieldPointersVector GetNonCreditCardFields(const FieldPointersVector& fields) {
+ FieldPointersVector result;
+ result.reserve(fields.size());
+ for (const auto* field : fields) {
+ if (!HasCreditCardAutocompleteAttributes(*field))
+ result.push_back(field);
+ }
+ return result;
+}
+
// Returns true iff there is a password field.
bool HasPasswordField(const FieldPointersVector& fields) {
for (const FormFieldData* field : fields)
@@ -309,7 +320,8 @@ void SetFields(const ParseResult& parse_result, PasswordForm* password_form) {
std::unique_ptr<PasswordForm> ParseFormData(const FormData& form_data,
FormParsingMode mode) {
- FieldPointersVector fields = GetNonCreditCardFields(form_data.fields);
+ FieldPointersVector fields = GetTextFields(form_data.fields);
+ fields = GetNonCreditCardFields(fields);
// Skip forms without password fields.
if (!HasPasswordField(fields))
diff --git a/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser_unittest.cc b/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser_unittest.cc
index 2391290911d..2f3c6d212d3 100644
--- a/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser_unittest.cc
+++ b/chromium/components/password_manager/core/browser/form_parsing/ios_form_parser_unittest.cc
@@ -49,6 +49,8 @@ struct TestFieldData {
// is assumed to be not important for a test and it will be set to some unique
// value.
const char* value = nullptr;
+
+ const char* form_control_type = nullptr;
};
struct FormParsingTestCase {
@@ -76,7 +78,10 @@ FormData GetFormData(const FormParsingTestCase& test_form) {
// An exact id is not important, set id such that different fields have
// different id.
field.id = ASCIIToUTF16("field_id") + UintToString16(i);
- field.form_control_type = field_data.is_password ? "password" : "text";
+ if (field_data.form_control_type)
+ field.form_control_type = field_data.form_control_type;
+ else
+ field.form_control_type = field_data.is_password ? "password" : "text";
field.is_focusable = field_data.is_focusable;
if (field_data.value) {
field.value = ASCIIToUTF16(field_data.value);
@@ -183,6 +188,21 @@ TEST_F(IOSFormParserTest, NotPasswordForm) {
CheckTestData(test_data);
}
+TEST_F(IOSFormParserTest, SkipNotTextFields) {
+ std::vector<FormParsingTestCase> test_data = {
+ {
+ "Select between username and password fields",
+ {{.is_password = false, .is_empty = false},
+ {.form_control_type = "select", .is_empty = false},
+ {.is_password = true, .is_empty = false}},
+ {0, 2, kFieldNotFound, kFieldNotFound},
+ {0, 2, kFieldNotFound, kFieldNotFound},
+ },
+ };
+
+ CheckTestData(test_data);
+}
+
TEST_F(IOSFormParserTest, OnlyPasswordFields) {
std::vector<FormParsingTestCase> test_data = {
{
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager.cc b/chromium/components/password_manager/core/browser/hash_password_manager.cc
index ebbcf2ee168..74f5e76922a 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager.cc
@@ -4,11 +4,14 @@
#include "components/password_manager/core/browser/hash_password_manager.h"
+#include <vector>
+
#include "base/base64.h"
#include "base/strings/string_number_conversions.h"
#include "components/os_crypt/os_crypt.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
#include "crypto/openssl_util.h"
#include "crypto/random.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
@@ -16,21 +19,165 @@
namespace {
constexpr size_t kSyncPasswordSaltLength = 16;
constexpr char kSeparator = '.';
+constexpr char kHashFieldKey[] = "hash";
+constexpr char kLastSignInTimeFieldKey[] = "last_signin";
+constexpr char kLengthAndSaltFieldKey[] = "salt_length";
+constexpr char kUsernameFieldKey[] = "username";
+constexpr char kIsGaiaFieldKey[] = "is_gaia";
+
+// The maximum number of password hash data we store in prefs.
+constexpr size_t kMaxPasswordHashDataDictSize = 5;
} // namespace
namespace password_manager {
+namespace {
+
+// Returns empty string if decryption fails.
+std::string DecryptBase64String(const std::string& encrypted_base64_string) {
+ if (encrypted_base64_string.empty())
+ return std::string();
+
+ std::string encrypted_string;
+ if (!base::Base64Decode(encrypted_base64_string, &encrypted_string))
+ return std::string();
+
+ std::string plain_text;
+ if (!OSCrypt::DecryptString(encrypted_string, &plain_text))
+ return std::string();
+
+ return plain_text;
+}
+
+// Returns empty string if encryption fails.
+std::string EncryptString(const std::string& plain_text) {
+ std::string encrypted_text;
+ if (!OSCrypt::EncryptString(plain_text, &encrypted_text)) {
+ return std::string();
+ }
+ std::string encrypted_base64_text;
+ base::Base64Encode(encrypted_text, &encrypted_base64_text);
+ return encrypted_base64_text;
+}
+
+void RemoveOldestSignInPasswordHashData(
+ std::vector<base::Value>* password_hash_data_list) {
+ auto oldest_it = password_hash_data_list->end();
+ double oldest_signin_time = base::Time::Now().ToDoubleT();
+ for (auto it = password_hash_data_list->begin();
+ it != password_hash_data_list->end(); it++) {
+ const base::Value* last_signin_value = it->FindKey(kLastSignInTimeFieldKey);
+ DCHECK(last_signin_value);
+
+ double signin_time = last_signin_value->GetDouble();
+ if (signin_time < oldest_signin_time) {
+ oldest_signin_time = signin_time;
+ oldest_it = it;
+ }
+ }
+
+ DCHECK(oldest_it != password_hash_data_list->end());
+ password_hash_data_list->erase(oldest_it);
+}
+
+std::string GetAndDecryptField(const base::Value& dict,
+ const std::string& field_key) {
+ const base::Value* encrypted_field_value = dict.FindKey(field_key);
+ return encrypted_field_value
+ ? DecryptBase64String(encrypted_field_value->GetString())
+ : std::string();
+}
+
+// Packs |salt| and |password_length| to a string.
+std::string LengthAndSaltToString(const std::string& salt,
+ size_t password_length) {
+ return base::NumberToString(password_length) + kSeparator + salt;
+}
+
+// Unpacks |salt| and |password_length| from a string |s|.
+// Returns true on success.
+bool StringToLengthAndSalt(const std::string& s,
+ size_t* password_length,
+ std::string* salt) {
+ if (s.empty() || !salt)
+ return false;
+
+ size_t separator_index = s.find(kSeparator);
+ if (separator_index == std::string::npos)
+ return false;
+
+ std::string prefix = s.substr(0, separator_index);
+ *salt = s.substr(separator_index + 1);
+ return !salt->empty() && base::StringToSizeT(prefix, password_length);
+}
+
+std::string BooleanToString(bool bool_value) {
+ return bool_value ? "true" : "false";
+}
+
+// Helper function to convert a dictionary value to PasswordWordHashData.
+base::Optional<PasswordHashData> ConvertToPasswordHashData(
+ const base::Value& dict) {
+ PasswordHashData result;
+ result.username = GetAndDecryptField(dict, kUsernameFieldKey);
+ if (result.username.empty())
+ return base::nullopt;
+
+ if (!base::StringToUint64(GetAndDecryptField(dict, kHashFieldKey),
+ &result.hash)) {
+ return base::nullopt;
+ }
+
+ if (!StringToLengthAndSalt(GetAndDecryptField(dict, kLengthAndSaltFieldKey),
+ &result.length, &result.salt)) {
+ return base::nullopt;
+ }
+
+ result.is_gaia_password = GetAndDecryptField(dict, kIsGaiaFieldKey) == "true";
+
+ return result;
+}
+
+} // namespace
+
SyncPasswordData::SyncPasswordData(const base::string16& password,
bool force_update)
: length(password.size()),
salt(HashPasswordManager::CreateRandomSalt()),
- hash(HashPasswordManager::CalculateSyncPasswordHash(password, salt)),
+ hash(HashPasswordManager::CalculatePasswordHash(password, salt)),
force_update(force_update) {}
bool SyncPasswordData::MatchesPassword(const base::string16& password) {
if (password.size() != this->length)
return false;
- return HashPasswordManager::CalculateSyncPasswordHash(password, this->salt) ==
+ return HashPasswordManager::CalculatePasswordHash(password, this->salt) ==
+ this->hash;
+}
+
+PasswordHashData::PasswordHashData(const std::string& username,
+ const base::string16& password,
+ bool force_update,
+ bool is_gaia_password)
+ : username(username),
+ length(password.size()),
+ salt(HashPasswordManager::CreateRandomSalt()),
+ hash(HashPasswordManager::CalculatePasswordHash(password, salt)),
+ force_update(force_update),
+ is_gaia_password(is_gaia_password) {}
+
+PasswordHashData::PasswordHashData() = default;
+
+PasswordHashData::PasswordHashData(const PasswordHashData& other) = default;
+
+bool PasswordHashData::MatchesPassword(const std::string& username,
+ const base::string16& password,
+ bool is_gaia_password) {
+ if (password.size() != this->length || username != this->username ||
+ is_gaia_password != this->is_gaia_password) {
+ return false;
+ }
+
+ return HashPasswordManager::CalculatePasswordHash(password, this->salt) ==
this->hash;
}
@@ -51,6 +198,33 @@ bool HashPasswordManager::SavePasswordHash(const base::string16& password) {
return SavePasswordHash(SyncPasswordData(password, true));
}
+bool HashPasswordManager::SavePasswordHash(const std::string username,
+ const base::string16& password,
+ bool is_gaia_password) {
+ if (!prefs_)
+ return false;
+
+ // If we've already saved password hash for |username|, and the |password| is
+ // unchanged, no need to save password hash again. Instead we update the last
+ // sign in timestamp.
+ ListPrefUpdate update(prefs_, prefs::kPasswordHashDataList);
+ for (base::Value& password_hash_data : update.Get()->GetList()) {
+ if (GetAndDecryptField(password_hash_data, kUsernameFieldKey) == username) {
+ base::Optional<PasswordHashData> existing_password_hash =
+ ConvertToPasswordHashData(password_hash_data);
+ if (existing_password_hash && existing_password_hash->MatchesPassword(
+ username, password, is_gaia_password)) {
+ password_hash_data.SetKey(kLastSignInTimeFieldKey,
+ base::Value(base::Time::Now().ToDoubleT()));
+ return true;
+ }
+ }
+ }
+
+ return SavePasswordHash(
+ PasswordHashData(username, password, true, is_gaia_password));
+}
+
bool HashPasswordManager::SavePasswordHash(
const SyncPasswordData& sync_password_data) {
bool should_save = sync_password_data.force_update ||
@@ -65,31 +239,138 @@ bool HashPasswordManager::SavePasswordHash(
: false;
}
+bool HashPasswordManager::SavePasswordHash(
+ const PasswordHashData& password_hash_data) {
+ bool should_save = password_hash_data.force_update ||
+ !HasPasswordHash(password_hash_data.username,
+ password_hash_data.is_gaia_password);
+ return should_save ? EncryptAndSave(password_hash_data) : false;
+}
+
void HashPasswordManager::ClearSavedPasswordHash() {
if (prefs_)
prefs_->ClearPref(prefs::kSyncPasswordHash);
}
+void HashPasswordManager::ClearSavedPasswordHash(const std::string& username,
+ bool is_gaia_password) {
+ if (prefs_) {
+ ListPrefUpdate update(prefs_, prefs::kPasswordHashDataList);
+ for (auto it = update->GetList().begin(); it != update->GetList().end();
+ it++) {
+ if (GetAndDecryptField(*it, kUsernameFieldKey) == username &&
+ GetAndDecryptField(*it, kIsGaiaFieldKey) ==
+ BooleanToString(is_gaia_password)) {
+ update->GetList().erase(it);
+ return;
+ }
+ }
+ }
+}
+
base::Optional<SyncPasswordData> HashPasswordManager::RetrievePasswordHash() {
if (!prefs_ || !prefs_->HasPrefPath(prefs::kSyncPasswordHash))
return base::nullopt;
SyncPasswordData result;
std::string hash_str =
- RetrivedDecryptedStringFromPrefs(prefs::kSyncPasswordHash);
+ RetrievedDecryptedStringFromPrefs(prefs::kSyncPasswordHash);
if (!base::StringToUint64(hash_str, &result.hash))
return base::nullopt;
StringToLengthAndSalt(
- RetrivedDecryptedStringFromPrefs(prefs::kSyncPasswordLengthAndHashSalt),
+ RetrievedDecryptedStringFromPrefs(prefs::kSyncPasswordLengthAndHashSalt),
&result.length, &result.salt);
return result;
}
+std::vector<PasswordHashData> HashPasswordManager::RetrieveAllPasswordHashes() {
+ std::vector<PasswordHashData> result;
+ if (!prefs_ || !prefs_->HasPrefPath(prefs::kPasswordHashDataList))
+ return result;
+
+ const base::ListValue* hash_list =
+ prefs_->GetList(prefs::kPasswordHashDataList);
+
+ for (const base::Value& entry : hash_list->GetList()) {
+ base::Optional<PasswordHashData> password_hash_data =
+ ConvertToPasswordHashData(entry);
+ if (password_hash_data)
+ result.push_back(std::move(*password_hash_data));
+ }
+ return result;
+}
+
+base::Optional<PasswordHashData> HashPasswordManager::RetrievePasswordHash(
+ const std::string& username,
+ bool is_gaia_password) {
+ if (!prefs_ || username.empty() ||
+ !prefs_->HasPrefPath(prefs::kPasswordHashDataList)) {
+ return base::nullopt;
+ }
+
+ for (const base::Value& entry :
+ prefs_->GetList(prefs::kPasswordHashDataList)->GetList()) {
+ if (GetAndDecryptField(entry, kUsernameFieldKey) == username &&
+ GetAndDecryptField(entry, kIsGaiaFieldKey) ==
+ BooleanToString(is_gaia_password)) {
+ return ConvertToPasswordHashData(entry);
+ }
+ }
+
+ return base::nullopt;
+}
+
bool HashPasswordManager::HasPasswordHash() {
return prefs_ ? prefs_->HasPrefPath(prefs::kSyncPasswordHash) : false;
}
+bool HashPasswordManager::HasPasswordHash(const std::string& username,
+ bool is_gaia_password) {
+ if (username.empty() || !prefs_ ||
+ !prefs_->HasPrefPath(prefs::kPasswordHashDataList)) {
+ return false;
+ }
+
+ for (const base::Value& entry :
+ prefs_->GetList(prefs::kPasswordHashDataList)->GetList()) {
+ if (username == GetAndDecryptField(entry, kUsernameFieldKey) &&
+ BooleanToString(is_gaia_password) ==
+ GetAndDecryptField(entry, kIsGaiaFieldKey)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void HashPasswordManager::MaybeMigrateExistingSyncPasswordHash(
+ const std::string& sync_username) {
+ if (!prefs_ || sync_username.empty() ||
+ !prefs_->HasPrefPath(prefs::kSyncPasswordHash) ||
+ !prefs_->HasPrefPath(prefs::kSyncPasswordLengthAndHashSalt)) {
+ return;
+ }
+
+ base::Optional<SyncPasswordData> captured_sync_password_hash =
+ RetrievePasswordHash();
+
+ if (!captured_sync_password_hash)
+ return;
+
+ PasswordHashData password_hash_data;
+ password_hash_data.username = sync_username;
+ password_hash_data.length = captured_sync_password_hash->length;
+ password_hash_data.salt = captured_sync_password_hash->salt;
+ password_hash_data.hash = captured_sync_password_hash->hash;
+ password_hash_data.force_update = true;
+ password_hash_data.is_gaia_password = true;
+
+ SavePasswordHash(password_hash_data);
+ prefs_->ClearPref(prefs::kSyncPasswordHash);
+ prefs_->ClearPref(prefs::kSyncPasswordLengthAndHashSalt);
+}
+
// static
std::string HashPasswordManager::CreateRandomSalt() {
char buffer[kSyncPasswordSaltLength];
@@ -101,7 +382,7 @@ std::string HashPasswordManager::CreateRandomSalt() {
}
// static
-uint64_t HashPasswordManager::CalculateSyncPasswordHash(
+uint64_t HashPasswordManager::CalculatePasswordHash(
const base::StringPiece16& text,
const std::string& salt) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
@@ -136,53 +417,76 @@ uint64_t HashPasswordManager::CalculateSyncPasswordHash(
return hash37;
}
-std::string HashPasswordManager::LengthAndSaltToString(const std::string& salt,
- size_t password_length) {
- return base::NumberToString(password_length) + kSeparator + salt;
+bool HashPasswordManager::EncryptAndSaveToPrefs(const std::string& pref_name,
+ const std::string& s) {
+ std::string encrypted_base64_text = EncryptString(s);
+ if (encrypted_base64_text.empty())
+ return false;
+
+ prefs_->SetString(pref_name, encrypted_base64_text);
+ return true;
}
-void HashPasswordManager::StringToLengthAndSalt(const std::string& s,
- size_t* password_length,
- std::string* salt) {
- DCHECK(s.find(kSeparator) != std::string::npos);
- DCHECK(salt);
- size_t separator_index = s.find(kSeparator);
- std::string prefix = s.substr(0, separator_index);
+bool HashPasswordManager::EncryptAndSave(
+ const PasswordHashData& password_hash_data) {
+ if (!prefs_ || password_hash_data.username.empty()) {
+ return false;
+ }
- bool is_converted = base::StringToSizeT(prefix, password_length);
- DCHECK(is_converted);
+ std::string encrypted_username = EncryptString(password_hash_data.username);
+ if (encrypted_username.empty())
+ return false;
- *salt = s.substr(separator_index + 1);
-}
+ std::string encrypted_hash =
+ EncryptString(base::NumberToString(password_hash_data.hash));
+ if (encrypted_hash.empty())
+ return false;
-bool HashPasswordManager::EncryptAndSaveToPrefs(const std::string& pref_name,
- const std::string& s) {
- DCHECK(prefs_);
- std::string encrypted_text;
- if (!OSCrypt::EncryptString(s, &encrypted_text))
+ std::string encrypted_length_and_salt = EncryptString(LengthAndSaltToString(
+ password_hash_data.salt, password_hash_data.length));
+ if (encrypted_length_and_salt.empty())
return false;
- std::string encrypted_base64_text;
- base::Base64Encode(encrypted_text, &encrypted_base64_text);
- prefs_->SetString(pref_name, encrypted_base64_text);
+
+ std::string encrypted_is_gaia_value =
+ EncryptString(BooleanToString(password_hash_data.is_gaia_password));
+ if (encrypted_is_gaia_value.empty())
+ return false;
+
+ base::DictionaryValue encrypted_password_hash_entry;
+ encrypted_password_hash_entry.SetKey(kUsernameFieldKey,
+ base::Value(encrypted_username));
+ encrypted_password_hash_entry.SetKey(kHashFieldKey,
+ base::Value(encrypted_hash));
+ encrypted_password_hash_entry.SetKey(kLengthAndSaltFieldKey,
+ base::Value(encrypted_length_and_salt));
+ encrypted_password_hash_entry.SetKey(kIsGaiaFieldKey,
+ base::Value(encrypted_is_gaia_value));
+ encrypted_password_hash_entry.SetKey(
+ kLastSignInTimeFieldKey, base::Value(base::Time::Now().ToDoubleT()));
+ ListPrefUpdate update(prefs_, prefs::kPasswordHashDataList);
+ for (auto it = update->GetList().begin(); it != update->GetList().end();
+ it++) {
+ if (GetAndDecryptField(*it, kUsernameFieldKey) ==
+ password_hash_data.username &&
+ GetAndDecryptField(*it, kIsGaiaFieldKey) ==
+ BooleanToString(password_hash_data.is_gaia_password)) {
+ update->GetList().erase(it);
+ update->GetList().push_back(std::move(encrypted_password_hash_entry));
+ return true;
+ }
+ }
+ if (update->GetList().size() >= kMaxPasswordHashDataDictSize)
+ RemoveOldestSignInPasswordHashData(&update->GetList());
+
+ update->GetList().push_back(std::move(encrypted_password_hash_entry));
return true;
}
-std::string HashPasswordManager::RetrivedDecryptedStringFromPrefs(
+std::string HashPasswordManager::RetrievedDecryptedStringFromPrefs(
const std::string& pref_name) {
DCHECK(prefs_);
std::string encrypted_base64_text = prefs_->GetString(pref_name);
- if (encrypted_base64_text.empty())
- return std::string();
-
- std::string encrypted_text;
- if (!base::Base64Decode(encrypted_base64_text, &encrypted_text))
- return std::string();
-
- std::string plain_text;
- if (!OSCrypt::DecryptString(encrypted_text, &plain_text))
- return std::string();
-
- return plain_text;
+ return DecryptBase64String(encrypted_base64_text);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager.h b/chromium/components/password_manager/core/browser/hash_password_manager.h
index 8fc62196a96..b2a32dc9190 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager.h
+++ b/chromium/components/password_manager/core/browser/hash_password_manager.h
@@ -13,6 +13,7 @@ class PrefService;
namespace password_manager {
+// SyncPasswordData is being deprecated. Please use PasswordHashData instead.
struct SyncPasswordData {
SyncPasswordData() = default;
SyncPasswordData(const SyncPasswordData& other) = default;
@@ -27,8 +28,27 @@ struct SyncPasswordData {
bool force_update;
};
-// Responsible for saving, clearing, retrieving and encryption of a sync
-// password hash in preferences.
+struct PasswordHashData {
+ PasswordHashData();
+ PasswordHashData(const PasswordHashData& other);
+ PasswordHashData(const std::string& username,
+ const base::string16& password,
+ bool force_update,
+ bool is_gaia_password = true);
+ bool MatchesPassword(const std::string& username,
+ const base::string16& password,
+ bool is_gaia_password);
+
+ std::string username;
+ size_t length;
+ std::string salt;
+ uint64_t hash;
+ bool force_update;
+ bool is_gaia_password = true;
+};
+
+// Responsible for saving, clearing, retrieving and encryption of a password
+// hash data in preferences.
// All methods should be called on UI thread.
class HashPasswordManager {
public:
@@ -37,42 +57,58 @@ class HashPasswordManager {
~HashPasswordManager() = default;
bool SavePasswordHash(const base::string16& password);
+ bool SavePasswordHash(const std::string username,
+ const base::string16& password,
+ bool is_gaia_password = true);
bool SavePasswordHash(const SyncPasswordData& sync_password_data);
+ bool SavePasswordHash(const PasswordHashData& password_hash_data);
void ClearSavedPasswordHash();
+ void ClearSavedPasswordHash(const std::string& username,
+ bool is_gaia_password);
// Returns empty if no hash is available.
base::Optional<SyncPasswordData> RetrievePasswordHash();
+ // Returns empty array if no hash is available.
+ std::vector<PasswordHashData> RetrieveAllPasswordHashes();
+
+ // Returns empty if no hash matching |username| and |is_gaia_password| is
+ // available.
+ base::Optional<PasswordHashData> RetrievePasswordHash(
+ const std::string& username,
+ bool is_gaia_password);
+
// Whether |prefs_| has |kSyncPasswordHash| pref path.
bool HasPasswordHash();
+ // Whether password hash of |username| and |is_gaia_password| is stored.
+ bool HasPasswordHash(const std::string& username, bool is_gaia_password);
+
void set_prefs(PrefService* prefs) { prefs_ = prefs; }
+ // During the deprecation of SyncPasswordData, migrates the sync password hash
+ // that has already been captured.
+ void MaybeMigrateExistingSyncPasswordHash(const std::string& sync_username);
+
static std::string CreateRandomSalt();
- // Calculates 37 bits hash for a sync password. The calculation is based on a
- // slow hash function. The running time is ~10^{-4} seconds on Desktop.
- static uint64_t CalculateSyncPasswordHash(const base::StringPiece16& text,
- const std::string& salt);
+ // Calculates 37 bits hash for a password. The calculation is based on a slow
+ // hash function. The running time is ~10^{-4} seconds on Desktop.
+ static uint64_t CalculatePasswordHash(const base::StringPiece16& text,
+ const std::string& salt);
private:
- // Packs |salt| and |password_length| to a string.
- std::string LengthAndSaltToString(const std::string& salt,
- size_t password_length);
-
- // Unpacks |salt| and |password_length| from a string |s|.
- void StringToLengthAndSalt(const std::string& s,
- size_t* password_length,
- std::string* salt);
-
- // Saves encrypted string |s| in a preference |pref_name|. Return true on
+ // Saves encrypted string |s| in a preference |pref_name|. Returns true on
// success.
bool EncryptAndSaveToPrefs(const std::string& pref_name,
const std::string& s);
- // Retrieves and decrypts string value from a preference |pref_name|. Return
+ // Encrypts and saves |password_hash_data| to prefs. Returns true on success.
+ bool EncryptAndSave(const PasswordHashData& password_hash_data);
+
+ // Retrieves and decrypts string value from a preference |pref_name|. Returns
// an empty string on failure.
- std::string RetrivedDecryptedStringFromPrefs(const std::string& pref_name);
+ std::string RetrievedDecryptedStringFromPrefs(const std::string& pref_name);
PrefService* prefs_ = nullptr;
diff --git a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
index 5ff06f30fb7..02ed3e064ff 100644
--- a/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/hash_password_manager_unittest.cc
@@ -23,6 +23,8 @@ class HashPasswordManagerTest : public testing::Test {
prefs_.registry()->RegisterStringPref(prefs::kSyncPasswordLengthAndHashSalt,
std::string(),
PrefRegistry::NO_REGISTRATION_FLAGS);
+ prefs_.registry()->RegisterListPref(prefs::kPasswordHashDataList,
+ PrefRegistry::NO_REGISTRATION_FLAGS);
// Mock OSCrypt. There is a call to OSCrypt on initializling
// PasswordReuseDetector, so it should be mocked.
OSCryptMocker::SetUp();
@@ -34,7 +36,7 @@ class HashPasswordManagerTest : public testing::Test {
TestingPrefServiceSimple prefs_;
};
-TEST_F(HashPasswordManagerTest, Saving) {
+TEST_F(HashPasswordManagerTest, SavingSyncPasswordData) {
ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
HashPasswordManager hash_password_manager;
hash_password_manager.set_prefs(&prefs_);
@@ -61,7 +63,116 @@ TEST_F(HashPasswordManagerTest, Saving) {
EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
}
-TEST_F(HashPasswordManagerTest, Clearing) {
+TEST_F(HashPasswordManagerTest, SavingPasswordHashData) {
+ ASSERT_FALSE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(&prefs_);
+ base::string16 password(base::UTF8ToUTF16("password"));
+ std::string username("user@example.com");
+
+ // Verify |SavePasswordHash(const std::string,const base::string16&)|
+ // behavior.
+ hash_password_manager.SavePasswordHash(username, password,
+ /*force_update=*/true);
+ EXPECT_TRUE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+
+ // Saves the same password again won't change password hash, length or salt.
+ base::Optional<PasswordHashData> current_password_hash_data =
+ hash_password_manager.RetrievePasswordHash(username,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash(username, password,
+ /*force_update=*/true);
+ base::Optional<PasswordHashData> existing_password_data =
+ hash_password_manager.RetrievePasswordHash(username,
+ /*is_gaia_password=*/true);
+ EXPECT_EQ(current_password_hash_data->hash, existing_password_data->hash);
+ EXPECT_EQ(current_password_hash_data->salt, existing_password_data->salt);
+ EXPECT_TRUE(current_password_hash_data->is_gaia_password);
+ EXPECT_TRUE(existing_password_data->is_gaia_password);
+
+ // Verify |SavePasswordHash(const PasswordHashData&)| behavior.
+ base::string16 new_password(base::UTF8ToUTF16("new_password"));
+ PasswordHashData new_password_data(username, new_password,
+ /*force_update=*/true);
+ EXPECT_TRUE(hash_password_manager.SavePasswordHash(new_password_data));
+ EXPECT_NE(current_password_hash_data->hash,
+ hash_password_manager
+ .RetrievePasswordHash(username, /*is_gaia_password=*/true)
+ ->hash);
+}
+
+TEST_F(HashPasswordManagerTest, SavingGaiaPasswordAndNonGaiaPassword) {
+ ASSERT_FALSE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(&prefs_);
+ base::string16 password(base::UTF8ToUTF16("password"));
+ std::string username("user@example.com");
+
+ // Saves a Gaia password.
+ hash_password_manager.SavePasswordHash(username, password,
+ /*is_gaia_password=*/true);
+ EXPECT_TRUE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+ EXPECT_EQ(1u, hash_password_manager.RetrieveAllPasswordHashes().size());
+
+ // Saves the same password again but this time it is not a Gaia password.
+ hash_password_manager.SavePasswordHash(username, password,
+ /*is_gaia_password=*/false);
+ // Verifies that there should be two separate entry in the saved hash list.
+ EXPECT_EQ(2u, hash_password_manager.RetrieveAllPasswordHashes().size());
+}
+
+TEST_F(HashPasswordManagerTest, SavingMultipleHashesAndRetrieveAll) {
+ ASSERT_FALSE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(&prefs_);
+ base::string16 password(base::UTF8ToUTF16("password"));
+
+ // Save password hash for 6 different users.
+ hash_password_manager.SavePasswordHash("username1", password,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash("username2", password,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash("username3", password,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash("username4", password,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash("username5", password,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash("username6", password,
+ /*is_gaia_password=*/true);
+ hash_password_manager.SavePasswordHash("username3", password,
+ /*is_gaia_password=*/false);
+
+ // Since kMaxPasswordHashDataDictSize is set to 5, we will only save 5
+ // password hashes that were most recently signed in.
+ EXPECT_EQ(5u, hash_password_manager.RetrieveAllPasswordHashes().size());
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username1", /*is_gaia_password=*/true));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username1", /*is_gaia_password=*/false));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username2", /*is_gaia_password=*/true));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username2", /*is_gaia_password=*/false));
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("username3",
+ /*is_gaia_password=*/true));
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash(
+ "username3", /*is_gaia_password=*/false));
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("username4",
+ /*is_gaia_password=*/true));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username4", /*is_gaia_password=*/false));
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("username5",
+ /*is_gaia_password=*/true));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username5", /*is_gaia_password=*/false));
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("username6",
+ /*is_gaia_password=*/true));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username6", /*is_gaia_password=*/false));
+}
+
+TEST_F(HashPasswordManagerTest, ClearingSyncPasswordData) {
ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
HashPasswordManager hash_password_manager;
hash_password_manager.set_prefs(&prefs_);
@@ -70,7 +181,31 @@ TEST_F(HashPasswordManagerTest, Clearing) {
EXPECT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
}
-TEST_F(HashPasswordManagerTest, Retrieving) {
+TEST_F(HashPasswordManagerTest, ClearingPasswordHashData) {
+ ASSERT_FALSE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(&prefs_);
+ hash_password_manager.SavePasswordHash("username",
+ base::UTF8ToUTF16("sync_password"),
+ /*is_gaia_password=*/true);
+
+ hash_password_manager.ClearSavedPasswordHash("other_username",
+ /*is_gaia_password=*/true);
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("username",
+ /*is_gaia_password=*/true));
+ hash_password_manager.ClearSavedPasswordHash("username",
+ /*is_gaia_password=*/false);
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("username",
+ /*is_gaia_password=*/true));
+
+ hash_password_manager.ClearSavedPasswordHash("username",
+ /*is_gaia_password=*/true);
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "username", /*is_gaia_password=*/true));
+ EXPECT_EQ(0u, hash_password_manager.RetrieveAllPasswordHashes().size());
+}
+
+TEST_F(HashPasswordManagerTest, RetrievingSyncPasswordData) {
ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
HashPasswordManager hash_password_manager;
hash_password_manager.set_prefs(&prefs_);
@@ -82,12 +217,39 @@ TEST_F(HashPasswordManagerTest, Retrieving) {
ASSERT_TRUE(sync_password_data);
EXPECT_EQ(13u, sync_password_data->length);
EXPECT_EQ(16u, sync_password_data->salt.size());
- uint64_t expected_hash = HashPasswordManager::CalculateSyncPasswordHash(
+ uint64_t expected_hash = HashPasswordManager::CalculatePasswordHash(
base::UTF8ToUTF16("sync_password"), sync_password_data->salt);
EXPECT_EQ(expected_hash, sync_password_data->hash);
}
-TEST_F(HashPasswordManagerTest, CalculateSyncPasswordHash) {
+TEST_F(HashPasswordManagerTest, RetrievingPasswordHashData) {
+ ASSERT_FALSE(prefs_.HasPrefPath(prefs::kPasswordHashDataList));
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(&prefs_);
+ hash_password_manager.SavePasswordHash("username",
+ base::UTF8ToUTF16("password"),
+ /*is_gaia_password=*/true);
+ EXPECT_EQ(1u, hash_password_manager.RetrieveAllPasswordHashes().size());
+
+ base::Optional<PasswordHashData> password_hash_data =
+ hash_password_manager.RetrievePasswordHash("username",
+ /*is_gaia_password=*/false);
+ ASSERT_FALSE(password_hash_data);
+ password_hash_data = hash_password_manager.RetrievePasswordHash(
+ "username", /*is_gaia_password=*/true);
+ ASSERT_TRUE(password_hash_data);
+ EXPECT_EQ(8u, password_hash_data->length);
+ EXPECT_EQ(16u, password_hash_data->salt.size());
+ uint64_t expected_hash = HashPasswordManager::CalculatePasswordHash(
+ base::UTF8ToUTF16("password"), password_hash_data->salt);
+ EXPECT_EQ(expected_hash, password_hash_data->hash);
+
+ base::Optional<PasswordHashData> non_existing_data =
+ hash_password_manager.RetrievePasswordHash("non_existing_user", true);
+ ASSERT_FALSE(non_existing_data);
+}
+
+TEST_F(HashPasswordManagerTest, CalculatePasswordHash) {
const char* kPlainText[] = {"", "password", "password", "secret"};
const char* kSalt[] = {"", "salt", "123", "456"};
@@ -105,9 +267,26 @@ TEST_F(HashPasswordManagerTest, CalculateSyncPasswordHash) {
SCOPED_TRACE(i);
base::string16 text = base::UTF8ToUTF16(kPlainText[i]);
EXPECT_EQ(kExpectedHash[i],
- HashPasswordManager::CalculateSyncPasswordHash(text, kSalt[i]));
+ HashPasswordManager::CalculatePasswordHash(text, kSalt[i]));
}
}
+TEST_F(HashPasswordManagerTest, MigrateCapturedPasswordHash) {
+ ASSERT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(&prefs_);
+ hash_password_manager.SavePasswordHash(base::UTF8ToUTF16("sync_password"));
+ EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
+ EXPECT_TRUE(prefs_.HasPrefPath(prefs::kSyncPasswordLengthAndHashSalt));
+
+ hash_password_manager.MaybeMigrateExistingSyncPasswordHash("sync_username");
+ EXPECT_TRUE(hash_password_manager.HasPasswordHash("sync_username",
+ /*is_gaia_password=*/true));
+ EXPECT_FALSE(hash_password_manager.HasPasswordHash(
+ "sync_username", /*is_gaia_password=*/false));
+ EXPECT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordHash));
+ EXPECT_FALSE(prefs_.HasPrefPath(prefs::kSyncPasswordLengthAndHashSalt));
+}
+
} // namespace
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
index 859b04afecc..deeba5cf189 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator.cc
@@ -88,7 +88,7 @@ void HttpPasswordStoreMigrator::ProcessPasswordStoreResults() {
GURL::Replacements rep;
rep.SetSchemeStr(url::kHttpsScheme);
new_form.origin = form->origin.ReplaceComponents(rep);
- new_form.signon_realm = new_form.origin.spec();
+ new_form.signon_realm = new_form.origin.GetOrigin().spec();
// If |action| is not HTTPS then it's most likely obsolete. Otherwise, it
// may still be valid.
if (!form->action.SchemeIs(url::kHttpsScheme))
diff --git a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
index 4ae33128301..855a73cea90 100644
--- a/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
+++ b/chromium/components/password_manager/core/browser/http_password_store_migrator_unittest.cc
@@ -23,15 +23,15 @@ using testing::SaveArg;
using testing::Unused;
using testing::_;
-constexpr char kTestHttpsURL[] = "https://example.org/";
-constexpr char kTestHttpURL[] = "http://example.org/";
-constexpr char kTestSubdomainHttpURL[] = "http://login.example.org/";
+constexpr char kTestHttpsURL[] = "https://example.org/path";
+constexpr char kTestHttpURL[] = "http://example.org/path";
+constexpr char kTestSubdomainHttpURL[] = "http://login.example.org/path2";
// Creates a dummy http form with some basic arbitrary values.
PasswordForm CreateTestForm() {
PasswordForm form;
form.origin = GURL(kTestHttpURL);
- form.signon_realm = form.origin.spec();
+ form.signon_realm = form.origin.GetOrigin().spec();
form.action = GURL("https://example.org/action.html");
form.username_value = base::ASCIIToUTF16("user");
form.password_value = base::ASCIIToUTF16("password");
@@ -42,7 +42,7 @@ PasswordForm CreateTestForm() {
PasswordForm CreateTestPSLForm() {
PasswordForm form;
form.origin = GURL(kTestSubdomainHttpURL);
- form.signon_realm = form.origin.spec();
+ form.signon_realm = form.origin.GetOrigin().spec();
form.action = GURL(kTestSubdomainHttpURL);
form.username_value = base::ASCIIToUTF16("user2");
form.password_value = base::ASCIIToUTF16("password2");
@@ -127,8 +127,7 @@ class HttpPasswordStoreMigratorTest : public testing::Test {
};
void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
- PasswordStore::FormDigest form(autofill::PasswordForm::SCHEME_HTML,
- kTestHttpURL, GURL(kTestHttpURL));
+ PasswordStore::FormDigest form(CreateTestForm());
EXPECT_CALL(store(), GetLogins(form, _));
PasswordManagerClient::HSTSCallback callback;
EXPECT_CALL(client(), PostHSTSQueryForHost(GURL(kTestHttpsURL), _))
@@ -139,7 +138,8 @@ void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
// We expect a potential call to |RemoveSiteStatsImpl| which is a async task
// posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
// necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
- EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
+ EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL).GetOrigin()))
+ .Times(is_hsts);
WaitForPasswordStore();
EXPECT_CALL(consumer(), ProcessForms(std::vector<autofill::PasswordForm*>()));
@@ -148,8 +148,7 @@ void HttpPasswordStoreMigratorTest::TestEmptyStore(bool is_hsts) {
}
void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
- PasswordStore::FormDigest form_digest(autofill::PasswordForm::SCHEME_HTML,
- kTestHttpURL, GURL(kTestHttpURL));
+ PasswordStore::FormDigest form_digest(CreateTestForm());
EXPECT_CALL(store(), GetLogins(form_digest, _));
PasswordManagerClient::HSTSCallback callback;
EXPECT_CALL(client(), PostHSTSQueryForHost(GURL(kTestHttpsURL), _))
@@ -160,7 +159,8 @@ void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
// We expect a potential call to |RemoveSiteStatsImpl| which is a async task
// posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
// necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
- EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
+ EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL).GetOrigin()))
+ .Times(is_hsts);
WaitForPasswordStore();
PasswordForm form = CreateTestForm();
@@ -168,7 +168,7 @@ void HttpPasswordStoreMigratorTest::TestFullStore(bool is_hsts) {
PasswordForm android_form = CreateAndroidCredential();
PasswordForm expected_form = form;
expected_form.origin = GURL(kTestHttpsURL);
- expected_form.signon_realm = expected_form.origin.spec();
+ expected_form.signon_realm = expected_form.origin.GetOrigin().spec();
EXPECT_CALL(store(), AddLogin(expected_form));
EXPECT_CALL(store(), RemoveLogin(form)).Times(is_hsts);
@@ -205,7 +205,8 @@ void HttpPasswordStoreMigratorTest::TestMigratorDeletionByConsumer(
// We expect a potential call to |RemoveSiteStatsImpl| which is a async task
// posted from |PasswordStore::RemoveSiteStats|. Hence the following lines are
// necessary to ensure |RemoveSiteStatsImpl| gets called when expected.
- EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL))).Times(is_hsts);
+ EXPECT_CALL(store(), RemoveSiteStatsImpl(GURL(kTestHttpURL).GetOrigin()))
+ .Times(is_hsts);
WaitForPasswordStore();
}
diff --git a/chromium/components/password_manager/core/browser/login_database.cc b/chromium/components/password_manager/core/browser/login_database.cc
index 8a8e1df2461..19b17d48c21 100644
--- a/chromium/components/password_manager/core/browser/login_database.cc
+++ b/chromium/components/password_manager/core/browser/login_database.cc
@@ -987,10 +987,9 @@ bool LoginDatabase::DisableAutoSignInForOrigin(const GURL& origin) {
return s.Run();
}
-// static
LoginDatabase::EncryptionResult LoginDatabase::InitPasswordFormFromStatement(
PasswordForm* form,
- const sql::Statement& s) {
+ const sql::Statement& s) const {
std::string encrypted_password;
s.ColumnBlobAsString(COLUMN_PASSWORD_VALUE, &encrypted_password);
base::string16 decrypted_password;
@@ -1268,11 +1267,10 @@ std::string LoginDatabase::GetEncryptedPassword(
return encrypted_password;
}
-// static
bool LoginDatabase::StatementToForms(
sql::Statement* statement,
const PasswordStore::FormDigest* matched_form,
- std::vector<std::unique_ptr<PasswordForm>>* forms) {
+ std::vector<std::unique_ptr<PasswordForm>>* forms) const {
PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE;
forms->clear();
diff --git a/chromium/components/password_manager/core/browser/login_database.h b/chromium/components/password_manager/core/browser/login_database.h
index d49b3a11145..ef151257f20 100644
--- a/chromium/components/password_manager/core/browser/login_database.h
+++ b/chromium/components/password_manager/core/browser/login_database.h
@@ -147,6 +147,11 @@ class LoginDatabase {
StatisticsTable& stats_table() { return stats_table_; }
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ // This instance should not encrypt/decrypt password values using OSCrypt.
+ void disable_encryption() { use_encryption_ = false; }
+#endif // defined(OS_POSIX)
+
private:
#if defined(OS_IOS)
friend class LoginDatabaseIOSTest;
@@ -175,23 +180,25 @@ class LoginDatabase {
// successful, or returning false and leaving cipher_text unchanged if
// encryption fails (e.g., if the underlying OS encryption system is
// temporarily unavailable).
- static EncryptionResult EncryptedString(const base::string16& plain_text,
- std::string* cipher_text);
+ EncryptionResult EncryptedString(const base::string16& plain_text,
+ std::string* cipher_text) const
+ WARN_UNUSED_RESULT;
// Decrypts cipher_text, setting the value of plain_text and returning true if
// successful, or returning false and leaving plain_text unchanged if
// decryption fails (e.g., if the underlying OS encryption system is
// temporarily unavailable).
- static EncryptionResult DecryptedString(const std::string& cipher_text,
- base::string16* plain_text);
+ EncryptionResult DecryptedString(const std::string& cipher_text,
+ base::string16* plain_text) const
+ WARN_UNUSED_RESULT;
// Fills |form| from the values in the given statement (which is assumed to
// be of the form used by the Get*Logins methods).
// Returns the EncryptionResult from decrypting the password in |s|; if not
// ENCRYPTION_RESULT_SUCCESS, |form| is not filled.
- static EncryptionResult InitPasswordFormFromStatement(
- autofill::PasswordForm* form,
- const sql::Statement& s);
+ EncryptionResult InitPasswordFormFromStatement(autofill::PasswordForm* form,
+ const sql::Statement& s) const
+ WARN_UNUSED_RESULT;
// Gets all blacklisted or all non-blacklisted (depending on |blacklisted|)
// credentials. On success returns true and overwrites |forms| with the
@@ -203,10 +210,10 @@ class LoginDatabase {
// Overwrites |forms| with credentials retrieved from |statement|. If
// |matched_form| is not null, filters out all results but those PSL-matching
// |*matched_form| or federated credentials for it. On success returns true.
- static bool StatementToForms(
- sql::Statement* statement,
- const PasswordStore::FormDigest* matched_form,
- std::vector<std::unique_ptr<autofill::PasswordForm>>* forms);
+ bool StatementToForms(sql::Statement* statement,
+ const PasswordStore::FormDigest* matched_form,
+ std::vector<std::unique_ptr<autofill::PasswordForm>>*
+ forms) const WARN_UNUSED_RESULT;
// Initializes all the *_statement_ data members with appropriate SQL
// fragments based on |builder|.
@@ -233,6 +240,13 @@ class LoginDatabase {
std::string blacklisted_statement_;
std::string encrypted_statement_;
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+ // Whether password values should be encrypted.
+ // TODO(crbug.com/571003) Only linux doesn't use encryption. Remove this once
+ // Linux is fully migrated into LoginDatabase.
+ bool use_encryption_ = true;
+#endif // defined(OS_POSIX)
+
DISALLOW_COPY_AND_ASSIGN(LoginDatabase);
};
diff --git a/chromium/components/password_manager/core/browser/login_database_ios.cc b/chromium/components/password_manager/core/browser/login_database_ios.cc
index 41bd8deaa49..647548c5362 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios.cc
@@ -15,6 +15,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/password_manager/core/common/passwords_directory_util_ios.h"
using base::ScopedCFTypeRef;
using autofill::PasswordForm;
@@ -31,7 +32,7 @@ namespace password_manager {
LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
const base::string16& plain_text,
- std::string* cipher_text) {
+ std::string* cipher_text) const {
if (plain_text.size() == 0) {
*cipher_text = std::string();
return ENCRYPTION_RESULT_SUCCESS;
@@ -73,7 +74,7 @@ LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
const std::string& cipher_text,
- base::string16* plain_text) {
+ base::string16* plain_text) const {
if (cipher_text.size() == 0) {
*plain_text = base::string16();
return ENCRYPTION_RESULT_SUCCESS;
@@ -130,6 +131,14 @@ void LoginDatabase::DeleteEncryptedPassword(const PasswordForm& form) {
if (status != errSecSuccess && status != errSecItemNotFound) {
NOTREACHED() << "Unable to remove password from keychain: " << status;
}
+
+ // Delete the temporary passwords directory, since there might be leftover
+ // temporary files used for password export that contain the password being
+ // deleted. It can be called for a removal triggered by sync, which might
+ // happen at the same time as an export operation. In the unlikely event
+ // that the file is still needed by the consumer app, the export operation
+ // will fail.
+ password_manager::DeletePasswordsDirectory();
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
index 7835c979c8e..96ce8347e35 100644
--- a/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_ios_unittest.cc
@@ -11,6 +11,7 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_environment.h"
#include "components/autofill/core/common/password_form.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -45,6 +46,7 @@ class LoginDatabaseIOSTest : public PlatformTest {
protected:
base::ScopedTempDir temp_dir_;
std::unique_ptr<LoginDatabase> login_db_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
};
void LoginDatabaseIOSTest::ClearKeychain() {
diff --git a/chromium/components/password_manager/core/browser/login_database_mac.cc b/chromium/components/password_manager/core/browser/login_database_mac.cc
index ffaa1c34441..7e15cf3a672 100644
--- a/chromium/components/password_manager/core/browser/login_database_mac.cc
+++ b/chromium/components/password_manager/core/browser/login_database_mac.cc
@@ -8,19 +8,17 @@
namespace password_manager {
-// static
LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
const base::string16& plain_text,
- std::string* cipher_text) {
+ std::string* cipher_text) const {
return OSCrypt::EncryptString16(plain_text, cipher_text)
? ENCRYPTION_RESULT_SUCCESS
: ENCRYPTION_RESULT_SERVICE_FAILURE;
}
-// static
LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
const std::string& cipher_text,
- base::string16* plain_text) {
+ base::string16* plain_text) const {
return OSCrypt::DecryptString16(cipher_text, plain_text)
? ENCRYPTION_RESULT_SUCCESS
: ENCRYPTION_RESULT_SERVICE_FAILURE;
diff --git a/chromium/components/password_manager/core/browser/login_database_posix.cc b/chromium/components/password_manager/core/browser/login_database_posix.cc
index a700d9c0dd7..7ac5ad954f0 100644
--- a/chromium/components/password_manager/core/browser/login_database_posix.cc
+++ b/chromium/components/password_manager/core/browser/login_database_posix.cc
@@ -5,25 +5,34 @@
#include "components/password_manager/core/browser/login_database.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/os_crypt/os_crypt.h"
namespace password_manager {
-// TODO: Actually encrypt passwords on Linux.
-
-// static
LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
const base::string16& plain_text,
- std::string* cipher_text) {
- *cipher_text = base::UTF16ToUTF8(plain_text);
- return ENCRYPTION_RESULT_SUCCESS;
+ std::string* cipher_text) const {
+ if (!use_encryption_) {
+ *cipher_text = base::UTF16ToUTF8(plain_text);
+ return ENCRYPTION_RESULT_SUCCESS;
+ }
+
+ return OSCrypt::EncryptString16(plain_text, cipher_text)
+ ? ENCRYPTION_RESULT_SUCCESS
+ : ENCRYPTION_RESULT_SERVICE_FAILURE;
}
-// static
LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
const std::string& cipher_text,
- base::string16* plain_text) {
- *plain_text = base::UTF8ToUTF16(cipher_text);
- return ENCRYPTION_RESULT_SUCCESS;
+ base::string16* plain_text) const {
+ if (!use_encryption_) {
+ *plain_text = base::UTF8ToUTF16(cipher_text);
+ return ENCRYPTION_RESULT_SUCCESS;
+ }
+
+ return OSCrypt::DecryptString16(cipher_text, plain_text)
+ ? ENCRYPTION_RESULT_SUCCESS
+ : ENCRYPTION_RESULT_SERVICE_FAILURE;
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/login_database_unittest.cc b/chromium/components/password_manager/core/browser/login_database_unittest.cc
index a35f786d02f..8c76d1a516d 100644
--- a/chromium/components/password_manager/core/browser/login_database_unittest.cc
+++ b/chromium/components/password_manager/core/browser/login_database_unittest.cc
@@ -17,9 +17,11 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
+#include "base/test/scoped_task_environment.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
+#include "components/os_crypt/os_crypt.h"
#include "components/os_crypt/os_crypt_mocker.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/psl_matching_helper.h"
@@ -92,6 +94,28 @@ template<> std::string GetFirstColumn(const sql::Statement& s) {
return s.ColumnString(0);
}
+// Returns an empty vector on failure. Otherwise returns values in the column
+// |column_name| of the logins table. The order of the
+// returned rows is well-defined.
+template <class T>
+std::vector<T> GetColumnValuesFromDatabase(const base::FilePath& database_path,
+ const std::string& column_name) {
+ sql::Connection db;
+ std::vector<T> results;
+ CHECK(db.Open(database_path));
+
+ std::string statement = base::StringPrintf(
+ "SELECT %s FROM logins ORDER BY username_value, %s DESC",
+ column_name.c_str(), column_name.c_str());
+ sql::Statement s(db.GetCachedStatement(SQL_FROM_HERE, statement.c_str()));
+ EXPECT_TRUE(s.is_valid());
+
+ while (s.Step())
+ results.push_back(GetFirstColumn<T>(s));
+
+ return results;
+}
+
bool AddZeroClickableLogin(LoginDatabase* db,
const std::string& unique_string,
const GURL& origin) {
@@ -231,6 +255,7 @@ class LoginDatabaseTest : public testing::Test {
base::ScopedTempDir temp_dir_;
base::FilePath file_;
std::unique_ptr<LoginDatabase> db_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
};
TEST_F(LoginDatabaseTest, Logins) {
@@ -1693,6 +1718,45 @@ TEST_F(LoginDatabaseTest, FilePermissions) {
}
#endif // defined(OS_POSIX)
+#if !defined(OS_IOS)
+// Test that LoginDatabase encrypts the password values that it stores.
+TEST_F(LoginDatabaseTest, EncryptionEnabled) {
+ PasswordForm password_form;
+ GenerateExamplePasswordForm(&password_form);
+ base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
+ {
+ LoginDatabase db(file);
+ ASSERT_TRUE(db.Init());
+ EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
+ }
+ base::string16 decrypted_pw;
+ ASSERT_TRUE(OSCrypt::DecryptString16(
+ GetColumnValuesFromDatabase<std::string>(file, "password_value").at(0),
+ &decrypted_pw));
+ EXPECT_EQ(decrypted_pw, password_form.password_value);
+}
+#endif // !defined(OS_IOS)
+
+#if defined(OS_LINUX)
+// Test that LoginDatabase does not encrypt values when encryption is disabled.
+// TODO(crbug.com/829857) This is supported only for Linux, while transitioning
+// into LoginDB with full encryption.
+TEST_F(LoginDatabaseTest, EncryptionDisabled) {
+ PasswordForm password_form;
+ GenerateExamplePasswordForm(&password_form);
+ base::FilePath file = temp_dir_.GetPath().AppendASCII("TestUnencryptedDB");
+ {
+ LoginDatabase db(file);
+ db.disable_encryption();
+ ASSERT_TRUE(db.Init());
+ EXPECT_EQ(AddChangeForForm(password_form), db.AddLogin(password_form));
+ }
+ EXPECT_EQ(
+ GetColumnValuesFromDatabase<std::string>(file, "password_value").at(0),
+ base::UTF16ToUTF8(password_form.password_value));
+}
+#endif // defined(OS_LINUX)
+
// If the database initialisation fails, the initialisation transaction should
// roll back without crashing.
TEST(LoginDatabaseFailureTest, Init_NoCrashOnFailedRollback) {
@@ -1735,7 +1799,7 @@ class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
// Creates the database from |sql_file|.
void CreateDatabase(base::StringPiece sql_file) {
base::FilePath database_dump;
- ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &database_dump));
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &database_dump));
database_dump =
database_dump.Append(database_dump_location_).AppendASCII(sql_file);
ASSERT_TRUE(
@@ -1747,33 +1811,6 @@ class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
sql::Connection::Delete(database_path_);
}
- // Returns an empty vector on failure. Otherwise returns values in the column
- // |column_name| of the logins table. The order of the
- // returned rows is well-defined.
- template <class T>
- std::vector<T> GetValues(const std::string& column_name) {
- sql::Connection db;
- std::vector<T> results;
- if (!db.Open(database_path_))
- return results;
-
- std::string statement = base::StringPrintf(
- "SELECT %s FROM logins ORDER BY username_value, %s DESC",
- column_name.c_str(), column_name.c_str());
- sql::Statement s(db.GetCachedStatement(SQL_FROM_HERE, statement.c_str()));
- if (!s.is_valid()) {
- db.Close();
- return results;
- }
-
- while (s.Step())
- results.push_back(GetFirstColumn<T>(s));
-
- s.Clear();
- db.Close();
- return results;
- }
-
// Returns the database version for the test.
int version() const { return GetParam(); }
@@ -1785,6 +1822,7 @@ class LoginDatabaseMigrationTest : public testing::TestWithParam<int> {
private:
base::FilePath database_dump_location_;
base::ScopedTempDir temp_dir_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
};
void LoginDatabaseMigrationTest::MigrationToVCurrent(
@@ -1792,7 +1830,8 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
SCOPED_TRACE(testing::Message("Version file = ") << sql_file);
CreateDatabase(sql_file);
// Original date, in seconds since UTC epoch.
- std::vector<int64_t> date_created(GetValues<int64_t>("date_created"));
+ std::vector<int64_t> date_created(
+ GetColumnValuesFromDatabase<int64_t>(database_path_, "date_created"));
if (version() == 10) // Version 10 has a duplicate entry.
ASSERT_EQ(4U, date_created.size());
else
@@ -1840,7 +1879,8 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
EXPECT_TRUE(db.RemoveLogin(form));
}
// New date, in microseconds since platform independent epoch.
- std::vector<int64_t> new_date_created(GetValues<int64_t>("date_created"));
+ std::vector<int64_t> new_date_created(
+ GetColumnValuesFromDatabase<int64_t>(database_path_, "date_created"));
ASSERT_EQ(3U, new_date_created.size());
if (version() <= 8) {
// Check that the two dates match up.
@@ -1858,7 +1898,8 @@ void LoginDatabaseMigrationTest::MigrationToVCurrent(
// The "avatar_url" column first appeared in version 7. In version 14,
// it was renamed to "icon_url". Migration from a version <= 13
// to >= 14 should not break theses URLs.
- std::vector<std::string> urls(GetValues<std::string>("icon_url"));
+ std::vector<std::string> urls(
+ GetColumnValuesFromDatabase<std::string>(database_path_, "icon_url"));
EXPECT_THAT(urls, UnorderedElementsAre("", "https://www.google.com/icon",
"https://www.google.com/icon"));
diff --git a/chromium/components/password_manager/core/browser/login_database_win.cc b/chromium/components/password_manager/core/browser/login_database_win.cc
index 6cf9c2188e7..bd1e3b0567c 100644
--- a/chromium/components/password_manager/core/browser/login_database_win.cc
+++ b/chromium/components/password_manager/core/browser/login_database_win.cc
@@ -9,19 +9,17 @@
namespace password_manager {
-// static
LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
const base::string16& plain_text,
- std::string* cipher_text) {
+ std::string* cipher_text) const {
if (OSCrypt::EncryptString16(plain_text, cipher_text))
return ENCRYPTION_RESULT_SUCCESS;
return ENCRYPTION_RESULT_ITEM_FAILURE;
}
-// static
LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
const std::string& cipher_text,
- base::string16* plain_text) {
+ base::string16* plain_text) const {
// Unittests need to read sample database entries. If these entries had real
// passwords, their encoding would need to be different for every platform.
// To avoid the need for that, the entries have empty passwords. OSCrypt on
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.cc b/chromium/components/password_manager/core/browser/mock_password_store.cc
index 8b48c35cfaf..827930769de 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.cc
+++ b/chromium/components/password_manager/core/browser/mock_password_store.cc
@@ -4,6 +4,7 @@
#include "components/password_manager/core/browser/mock_password_store.h"
+#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
namespace password_manager {
diff --git a/chromium/components/password_manager/core/browser/mock_password_store.h b/chromium/components/password_manager/core/browser/mock_password_store.h
index f8ed24e52c8..60e67beb3a9 100644
--- a/chromium/components/password_manager/core/browser/mock_password_store.h
+++ b/chromium/components/password_manager/core/browser/mock_password_store.h
@@ -76,10 +76,11 @@ class MockPasswordStore : public PasswordStore {
void(const base::string16&,
const std::string&,
PasswordReuseDetectorConsumer*));
- MOCK_METHOD2(SaveSyncPasswordHash,
- void(const base::string16&,
+ MOCK_METHOD3(SaveSyncPasswordHash,
+ void(const std::string&,
+ const base::string16&,
metrics_util::SyncPasswordHashChange));
- MOCK_METHOD0(ClearSyncPasswordHash, void());
+ MOCK_METHOD1(ClearPasswordHash, void(const std::string&));
#endif
PasswordStoreSync* GetSyncInterface() { return this; }
diff --git a/chromium/components/password_manager/core/browser/new_password_form_manager.cc b/chromium/components/password_manager/core/browser/new_password_form_manager.cc
new file mode 100644
index 00000000000..150b7ab410b
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/new_password_form_manager.cc
@@ -0,0 +1,214 @@
+// 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 "components/password_manager/core/browser/new_password_form_manager.h"
+
+#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include "components/password_manager/core/browser/form_fetcher_impl.h"
+#include "components/password_manager/core/browser/form_parsing/ios_form_parser.h"
+#include "components/password_manager/core/browser/password_form_filling.h"
+#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+
+using autofill::FormData;
+
+using Logger = autofill::SavePasswordProgressLogger;
+
+namespace password_manager {
+
+namespace {
+
+// On iOS, id are used for field identification, whereas on other platforms
+// name field is used. Set id equal to name.
+// TODO(https://crbug.com/831123): Remove this method when the browser side form
+// parsing is ready.
+FormData PreprocessFormData(const FormData& form) {
+ FormData result_form = form;
+ for (auto& field : result_form.fields)
+ field.id = field.name;
+ return result_form;
+}
+
+// Helper function for calling form parsing and logging results if logging is
+// active.
+std::unique_ptr<autofill::PasswordForm> ParseFormAndMakeLogging(
+ PasswordManagerClient* client,
+ const FormData& form) {
+ // iOS form parsing is a prototype for parsing on all platforms. Call it for
+ // developing and experimentation purposes.
+ // TODO(https://crbug.com/831123): Call general form parsing instead of iOS
+ // one when it is ready.
+ std::unique_ptr<autofill::PasswordForm> password_form =
+ ParseFormData(PreprocessFormData(form), FormParsingMode::FILLING);
+
+ if (password_manager_util::IsLoggingActive(client)) {
+ BrowserSavePasswordProgressLogger logger(client->GetLogManager());
+ logger.LogFormData(Logger::STRING_FORM_PARSING_INPUT, form);
+ if (password_form)
+ logger.LogPasswordForm(Logger::STRING_FORM_PARSING_OUTPUT,
+ *password_form);
+ }
+ return password_form;
+}
+
+} // namespace
+
+NewPasswordFormManager::NewPasswordFormManager(
+ PasswordManagerClient* client,
+ const base::WeakPtr<PasswordManagerDriver>& driver,
+ const FormData& observed_form,
+ FormFetcher* form_fetcher)
+ : client_(client),
+ driver_(driver),
+ observed_form_(observed_form),
+ owned_form_fetcher_(
+ form_fetcher ? nullptr
+ : std::make_unique<FormFetcherImpl>(
+ PasswordStore::FormDigest(observed_form),
+ client_,
+ true /* should_migrate_http_passwords */,
+ true /* should_query_suppressed_https_forms */)),
+ form_fetcher_(form_fetcher ? form_fetcher : owned_form_fetcher_.get()) {
+ metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
+ client_->IsMainFrameSecure(), client_->GetUkmSourceId());
+ metrics_recorder_->RecordFormSignature(CalculateFormSignature(observed_form));
+
+ if (owned_form_fetcher_)
+ owned_form_fetcher_->Fetch();
+ form_fetcher_->AddConsumer(this);
+
+ // The folloing code is for development and debugging purposes.
+ // TODO(https://crbug.com/831123): remove it when NewPasswordFormManager will
+ // be production ready.
+ if (password_manager_util::IsLoggingActive(client_))
+ ParseFormAndMakeLogging(client_, observed_form_);
+}
+NewPasswordFormManager::~NewPasswordFormManager() = default;
+
+bool NewPasswordFormManager::DoesManage(
+ const autofill::FormData& form,
+ const PasswordManagerDriver* driver) const {
+ if (driver != driver_.get())
+ return false;
+ if (observed_form_.is_form_tag != form.is_form_tag)
+ return false;
+ // All unowned input elements are considered as one synthetic form.
+ if (!observed_form_.is_form_tag && !form.is_form_tag)
+ return true;
+ return observed_form_.unique_renderer_id == form.unique_renderer_id;
+}
+
+FormFetcher* NewPasswordFormManager::GetFormFetcher() {
+ return form_fetcher_;
+}
+
+const GURL& NewPasswordFormManager::GetOrigin() const {
+ return observed_form_.origin;
+}
+
+const std::map<base::string16, const autofill::PasswordForm*>&
+NewPasswordFormManager::GetBestMatches() const {
+ // TODO(https://crbug.com/831123): Implement.
+ DCHECK(false);
+ static std::map<base::string16, const autofill::PasswordForm*> dummy_map;
+ return dummy_map;
+}
+const autofill::PasswordForm& NewPasswordFormManager::GetPendingCredentials()
+ const {
+ // TODO(https://crbug.com/831123): Implement.
+ DCHECK(false);
+ static autofill::PasswordForm dummy_form;
+ return dummy_form;
+}
+metrics_util::CredentialSourceType
+NewPasswordFormManager::GetCredentialSource() {
+ // TODO(https://crbug.com/831123): Implement.
+ return metrics_util::CredentialSourceType::kPasswordManager;
+}
+PasswordFormMetricsRecorder* NewPasswordFormManager::GetMetricsRecorder() {
+ return metrics_recorder_.get();
+}
+const std::vector<const autofill::PasswordForm*>&
+NewPasswordFormManager::GetBlacklistedMatches() const {
+ // TODO(https://crbug.com/831123): Implement.
+ DCHECK(false);
+ static std::vector<const autofill::PasswordForm*> dummy_vector;
+ return dummy_vector;
+}
+bool NewPasswordFormManager::IsBlacklisted() const {
+ // TODO(https://crbug.com/831123): Implement.
+ return false;
+}
+bool NewPasswordFormManager::IsPasswordOverridden() const {
+ // TODO(https://crbug.com/831123): Implement.
+ return false;
+}
+const autofill::PasswordForm* NewPasswordFormManager::GetPreferredMatch()
+ const {
+ // TODO(https://crbug.com/831123): Implement or remove from
+ // PasswordFormManagerForUI.
+ return nullptr;
+}
+
+// TODO(https://crbug.com/831123): Implement all methods from
+// PasswordFormManagerForUI.
+void NewPasswordFormManager::Save() {}
+void NewPasswordFormManager::Update(
+ const autofill::PasswordForm& credentials_to_update) {}
+void NewPasswordFormManager::UpdateUsername(
+ const base::string16& new_username) {}
+void NewPasswordFormManager::UpdatePasswordValue(
+ const base::string16& new_password) {}
+void NewPasswordFormManager::OnNopeUpdateClicked() {}
+void NewPasswordFormManager::OnNeverClicked() {}
+void NewPasswordFormManager::OnNoInteraction(bool is_update) {}
+void NewPasswordFormManager::PermanentlyBlacklist() {}
+void NewPasswordFormManager::OnPasswordsRevealed() {}
+
+void NewPasswordFormManager::ProcessMatches(
+ const std::vector<const autofill::PasswordForm*>& non_federated,
+ size_t filtered_count) {
+ if (!driver_)
+ return;
+
+ // There are additional signals (server-side data) and parse results in
+ // filling and saving mode might be different so it is better not to cache
+ // parse result, but to parse each time again.
+ std::unique_ptr<autofill::PasswordForm> observed_password_form =
+ ParseFormAndMakeLogging(client_, observed_form_);
+ if (!observed_password_form)
+ return;
+
+ // TODO(https://crbug.com/831123). Implement correct treating of blacklisted
+ // matches.
+ std::map<base::string16, const autofill::PasswordForm*> best_matches;
+ std::vector<const autofill::PasswordForm*> not_best_matches;
+ const autofill::PasswordForm* preferred_match = nullptr;
+ password_manager_util::FindBestMatches(non_federated, &best_matches,
+ &not_best_matches, &preferred_match);
+ if (best_matches.empty())
+ return;
+
+ // TODO(https://crbug.com/831123). Implement correct treating of federated
+ // matches.
+ std::vector<const autofill::PasswordForm*> federated_matches;
+ SendFillInformationToRenderer(
+ *client_, driver_.get(), false /* is_blaclisted */,
+ *observed_password_form.get(), best_matches, federated_matches,
+ preferred_match, metrics_recorder_.get());
+}
+
+bool NewPasswordFormManager::SetSubmittedFormIfIsManaged(
+ const autofill::FormData& submitted_form,
+ const PasswordManagerDriver* driver) {
+ if (!DoesManage(submitted_form, driver))
+ return false;
+ submitted_form_ = submitted_form;
+ is_submitted_ = true;
+ return true;
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/new_password_form_manager.h b/chromium/components/password_manager/core/browser/new_password_form_manager.h
new file mode 100644
index 00000000000..1b935cc28ad
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/new_password_form_manager.h
@@ -0,0 +1,111 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_NEW_PASSWORD_FORM_MANAGER_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_NEW_PASSWORD_FORM_MANAGER_H_
+
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/password_manager/core/browser/form_fetcher.h"
+#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
+
+namespace password_manager {
+
+class PasswordFormMetricsRecorder;
+class PasswordManagerClient;
+class PasswordManagerDriver;
+
+// This class helps with filling the observed form and with saving/updating the
+// stored information about it. It is aimed to replace PasswordFormManager and
+// to be renamed in new Password Manager design. Details
+// go/new-cpm-design-refactoring.
+class NewPasswordFormManager : public PasswordFormManagerForUI,
+ public FormFetcher::Consumer {
+ public:
+ // TODO(crbug.com/621355): So far, |form_fetcher| can be null. In that case
+ // |this| creates an instance of it itself (meant for production code). Once
+ // the fetcher is shared between PasswordFormManager instances, it will be
+ // required that |form_fetcher| is not null.
+ NewPasswordFormManager(PasswordManagerClient* client,
+ const base::WeakPtr<PasswordManagerDriver>& driver,
+ const autofill::FormData& observed_form,
+ FormFetcher* form_fetcher);
+
+ ~NewPasswordFormManager() override;
+
+ // Compares |observed_form_| with |form| and returns true if they are the
+ // same and if |driver| is the same as |driver_|.
+ bool DoesManage(const autofill::FormData& form,
+ const PasswordManagerDriver* driver) const;
+
+ // If |submitted_form| is managed by *this (i.e. DoesManage returns true for
+ // |submitted_form| and |driver|) then saves |submitted_form| to
+ // |submitted_form_| field, sets |is_submitted| = true and returns true.
+ // Otherwise returns false.
+ bool SetSubmittedFormIfIsManaged(const autofill::FormData& submitted_form,
+ const PasswordManagerDriver* driver);
+ bool is_submitted() { return is_submitted_; }
+ void set_not_submitted() { is_submitted_ = false; }
+
+ // PasswordFormManagerForUI:
+ FormFetcher* GetFormFetcher() override;
+ const GURL& GetOrigin() const override;
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ GetBestMatches() const override;
+ const autofill::PasswordForm& GetPendingCredentials() const override;
+ metrics_util::CredentialSourceType GetCredentialSource() override;
+ PasswordFormMetricsRecorder* GetMetricsRecorder() override;
+ const std::vector<const autofill::PasswordForm*>& GetBlacklistedMatches()
+ const override;
+ bool IsBlacklisted() const override;
+ bool IsPasswordOverridden() const override;
+ const autofill::PasswordForm* GetPreferredMatch() const override;
+
+ void Save() override;
+ void Update(const autofill::PasswordForm& credentials_to_update) override;
+ void UpdateUsername(const base::string16& new_username) override;
+ void UpdatePasswordValue(const base::string16& new_password) override;
+
+ void OnNopeUpdateClicked() override;
+ void OnNeverClicked() override;
+ void OnNoInteraction(bool is_update) override;
+ void PermanentlyBlacklist() override;
+ void OnPasswordsRevealed() override;
+
+ protected:
+ // FormFetcher::Consumer:
+ void ProcessMatches(
+ const std::vector<const autofill::PasswordForm*>& non_federated,
+ size_t filtered_count) override;
+
+ private:
+ // The client which implements embedder-specific PasswordManager operations.
+ PasswordManagerClient* client_;
+
+ base::WeakPtr<PasswordManagerDriver> driver_;
+
+ const autofill::FormData observed_form_;
+
+ // Takes care of recording metrics and events for |*this|.
+ scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
+
+ // When not null, then this is the object which |form_fetcher_| points to.
+ std::unique_ptr<FormFetcher> owned_form_fetcher_;
+
+ // FormFetcher instance which owns the login data from PasswordStore.
+ FormFetcher* form_fetcher_;
+
+ // |is_submitted_| = true means that a submission of the managed form was seen
+ // and then |submitted_form_| contains the submitted form.
+ bool is_submitted_ = false;
+ autofill::FormData submitted_form_;
+
+ DISALLOW_COPY_AND_ASSIGN(NewPasswordFormManager);
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_NEW_PASSWORD_FORM_MANAGER_H_
diff --git a/chromium/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/new_password_form_manager_unittest.cc
new file mode 100644
index 00000000000..c87d06be9cf
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -0,0 +1,160 @@
+// 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 "components/password_manager/core/browser/new_password_form_manager.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/form_data.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/password_manager/core/browser/fake_form_fetcher.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/browser/stub_password_manager_driver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using autofill::FormData;
+using autofill::FormFieldData;
+using autofill::PasswordForm;
+using autofill::PasswordFormFillData;
+using base::ASCIIToUTF16;
+using testing::_;
+using testing::SaveArg;
+
+namespace password_manager {
+
+namespace {
+class MockPasswordManagerDriver : public StubPasswordManagerDriver {
+ public:
+ MockPasswordManagerDriver() {}
+
+ ~MockPasswordManagerDriver() override {}
+
+ MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
+ MOCK_METHOD1(AllowPasswordGenerationForForm, void(const PasswordForm&));
+};
+
+} // namespace
+
+class NewPasswordFormManagerTest : public testing::Test {
+ public:
+ NewPasswordFormManagerTest() {
+ GURL origin = GURL("http://accounts.google.com/a/ServiceLoginAuth");
+ GURL action = GURL("http://accounts.google.com/a/ServiceLogin");
+
+ observed_form_.origin = origin;
+ observed_form_.action = action;
+ observed_form_.name = ASCIIToUTF16("sign-in");
+ observed_form_.unique_renderer_id = 1;
+ observed_form_.is_form_tag = true;
+
+ FormFieldData field;
+ field.name = ASCIIToUTF16("firstname");
+ field.form_control_type = "text";
+ observed_form_.fields.push_back(field);
+
+ field.name = ASCIIToUTF16("username");
+ field.form_control_type = "text";
+ observed_form_.fields.push_back(field);
+
+ field.name = ASCIIToUTF16("password");
+ field.form_control_type = "password";
+ observed_form_.fields.push_back(field);
+
+ saved_match_.origin = origin;
+ saved_match_.action = action;
+ saved_match_.preferred = true;
+ saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
+ saved_match_.password_value = ASCIIToUTF16("test1");
+ }
+
+ protected:
+ FormData observed_form_;
+ PasswordForm saved_match_;
+ StubPasswordManagerClient client_;
+ MockPasswordManagerDriver driver_;
+};
+
+TEST_F(NewPasswordFormManagerTest, DoesManage) {
+ FakeFormFetcher fetcher;
+ fetcher.Fetch();
+ NewPasswordFormManager form_manager(&client_, driver_.AsWeakPtr(),
+ observed_form_, &fetcher);
+ EXPECT_TRUE(form_manager.DoesManage(observed_form_, &driver_));
+ // Forms on other drivers are not considered managed.
+ EXPECT_FALSE(form_manager.DoesManage(observed_form_, nullptr));
+ FormData another_form = observed_form_;
+ another_form.is_form_tag = false;
+ EXPECT_FALSE(form_manager.DoesManage(another_form, &driver_));
+
+ another_form = observed_form_;
+ another_form.unique_renderer_id = observed_form_.unique_renderer_id + 1;
+ EXPECT_FALSE(form_manager.DoesManage(another_form, &driver_));
+}
+
+TEST_F(NewPasswordFormManagerTest, DoesManageNoFormTag) {
+ observed_form_.is_form_tag = false;
+ FakeFormFetcher fetcher;
+ fetcher.Fetch();
+ NewPasswordFormManager form_manager(&client_, driver_.AsWeakPtr(),
+ observed_form_, &fetcher);
+ FormData another_form = observed_form_;
+ // Simulate that new input was added by JavaScript.
+ another_form.fields.push_back(FormFieldData());
+ EXPECT_TRUE(form_manager.DoesManage(another_form, &driver_));
+ // Forms on other drivers are not considered managed.
+ EXPECT_FALSE(form_manager.DoesManage(another_form, nullptr));
+}
+
+TEST_F(NewPasswordFormManagerTest, Autofill) {
+ FakeFormFetcher fetcher;
+ fetcher.Fetch();
+ EXPECT_CALL(driver_, AllowPasswordGenerationForForm(_));
+ PasswordFormFillData fill_data;
+ EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
+ NewPasswordFormManager form_manager(&client_, driver_.AsWeakPtr(),
+ observed_form_, &fetcher);
+ fetcher.SetNonFederated({&saved_match_}, 0u);
+
+ EXPECT_EQ(observed_form_.origin, fill_data.origin);
+ EXPECT_FALSE(fill_data.wait_for_username);
+ EXPECT_EQ(observed_form_.fields[1].name, fill_data.username_field.name);
+ EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
+ EXPECT_EQ(observed_form_.fields[2].name, fill_data.password_field.name);
+ EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
+}
+
+TEST_F(NewPasswordFormManagerTest, SetSubmitted) {
+ FakeFormFetcher fetcher;
+ fetcher.Fetch();
+ NewPasswordFormManager form_manager(&client_, driver_.AsWeakPtr(),
+ observed_form_, &fetcher);
+ EXPECT_FALSE(form_manager.is_submitted());
+ EXPECT_TRUE(
+ form_manager.SetSubmittedFormIfIsManaged(observed_form_, &driver_));
+ EXPECT_TRUE(form_manager.is_submitted());
+
+ FormData another_form = observed_form_;
+ another_form.name += ASCIIToUTF16("1");
+ // |another_form| is managed because the same |unique_renderer_id| as
+ // |observed_form_|.
+ EXPECT_TRUE(form_manager.SetSubmittedFormIfIsManaged(another_form, &driver_));
+ EXPECT_TRUE(form_manager.is_submitted());
+
+ form_manager.set_not_submitted();
+ EXPECT_FALSE(form_manager.is_submitted());
+
+ another_form.unique_renderer_id = observed_form_.unique_renderer_id + 1;
+ EXPECT_FALSE(
+ form_manager.SetSubmittedFormIfIsManaged(another_form, &driver_));
+ EXPECT_FALSE(form_manager.is_submitted());
+
+ // An identical form but in a different frame (represented here by a null
+ // driver) is also not considered managed.
+ EXPECT_FALSE(
+ form_manager.SetSubmittedFormIfIsManaged(observed_form_, nullptr));
+ EXPECT_FALSE(form_manager.is_submitted());
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.cc b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
index 7e43d9e0d95..3911c7018ce 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.cc
@@ -121,14 +121,6 @@ void GetSuggestions(const autofill::PasswordFormFillData& fill_data,
suggestions);
}
- for (const auto& usernames : fill_data.other_possible_usernames) {
- for (size_t i = 0; i < usernames.second.size(); ++i) {
- AppendSuggestionIfMatching(usernames.second[i], current_username,
- usernames.first.realm, show_all,
- is_password_field, suggestions);
- }
- }
-
// Prefix matches should precede other token matches.
if (autofill::IsFeatureSubstringMatchEnabled()) {
std::sort(suggestions->begin(), suggestions->end(),
@@ -224,18 +216,6 @@ void PasswordAutofillManager::OnAddPasswordFormMapping(
login_to_password_info_[key] = fill_data;
}
-autofill::Suggestion PasswordAutofillManager::CreateFormNotSecureWarning() {
- autofill::Suggestion http_warning_suggestion(
- l10n_util::GetStringUTF8(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE),
- l10n_util::GetStringUTF8(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE),
- "httpWarning", autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE);
- if (!did_show_form_not_secure_warning_) {
- did_show_form_not_secure_warning_ = true;
- metrics_util::LogShowedFormNotSecureWarningOnCurrentNavigation();
- }
- return http_warning_suggestion;
-}
-
void PasswordAutofillManager::OnShowPasswordSuggestions(
int key,
base::i18n::TextDirection text_direction,
@@ -269,34 +249,6 @@ void PasswordAutofillManager::OnShowPasswordSuggestions(
}
GURL origin = (fill_data_it->second).origin;
- bool is_context_secure = autofill_client_->IsContextSecure() &&
- (!origin.is_valid() || !origin.SchemeIs("http"));
- if (!is_context_secure && security_state::IsHttpWarningInFormEnabled()) {
- std::string icon_str;
-
- // Show http info icon for http sites.
- if (origin.is_valid() && origin.SchemeIs("http")) {
- icon_str = "httpWarning";
- } else {
- // Show https_invalid icon for broken https sites.
- icon_str = "httpsInvalid";
- }
-
- autofill::Suggestion http_warning_suggestion(
- l10n_util::GetStringUTF8(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE),
- l10n_util::GetStringUTF8(IDS_AUTOFILL_HTTP_WARNING_LEARN_MORE),
- icon_str, autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE);
-#if !defined(OS_ANDROID)
- suggestions.insert(suggestions.begin(), autofill::Suggestion());
- suggestions.front().frontend_id = autofill::POPUP_ITEM_ID_SEPARATOR;
-#endif
- suggestions.insert(suggestions.begin(), http_warning_suggestion);
-
- if (!did_show_form_not_secure_warning_) {
- did_show_form_not_secure_warning_ = true;
- metrics_util::LogShowedFormNotSecureWarningOnCurrentNavigation();
- }
- }
if (ShouldShowManualFallbackForPreLollipop(
autofill_client_->GetSyncService())) {
@@ -329,28 +281,6 @@ void PasswordAutofillManager::OnShowPasswordSuggestions(
weak_ptr_factory_.GetWeakPtr());
}
-void PasswordAutofillManager::OnShowNotSecureWarning(
- base::i18n::TextDirection text_direction,
- const gfx::RectF& bounds) {
- DCHECK(security_state::IsHttpWarningInFormEnabled());
- // TODO(estark): Other code paths in this file don't do null checks before
- // using |autofill_client_|. It seems that these other code paths somehow
- // short-circuit before dereferencing |autofill_client_| in cases where it's
- // null; it would be good to understand why/how and make a firm decision about
- // whether |autofill_client_| is allowed to be null. Ideally we would be able
- // to get rid of such cases so that we can enable Form-Not-Secure warnings
- // here in all cases. https://crbug.com/699217
- if (!autofill_client_)
- return;
-
- std::vector<autofill::Suggestion> suggestions;
- autofill::Suggestion http_warning_suggestion = CreateFormNotSecureWarning();
- suggestions.insert(suggestions.begin(), http_warning_suggestion);
-
- autofill_client_->ShowAutofillPopup(bounds, text_direction, suggestions,
- weak_ptr_factory_.GetWeakPtr());
-}
-
void PasswordAutofillManager::OnShowManualFallbackSuggestion(
base::i18n::TextDirection text_direction,
const gfx::RectF& bounds) {
@@ -414,8 +344,7 @@ void PasswordAutofillManager::OnPopupHidden() {
void PasswordAutofillManager::DidSelectSuggestion(const base::string16& value,
int identifier) {
ClearPreviewedForm();
- if (identifier == autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE ||
- identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY ||
+ if (identifier == autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY ||
identifier == autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY)
return;
bool success =
@@ -429,9 +358,7 @@ void PasswordAutofillManager::DidAcceptSuggestion(const base::string16& value,
autofill_client_->ExecuteCommand(identifier);
if (identifier == autofill::POPUP_ITEM_ID_GENERATE_PASSWORD_ENTRY) {
password_manager_driver_->UserSelectedManualGenerationOption();
- } else if (identifier !=
- autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE &&
- identifier != autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) {
+ } else if (identifier != autofill::POPUP_ITEM_ID_ALL_SAVED_PASSWORDS_ENTRY) {
bool success =
FillSuggestion(form_data_key_, GetUsernameFromSuggestion(value));
DCHECK(success);
@@ -486,8 +413,8 @@ void PasswordAutofillManager::ClearPreviewedForm() {
password_manager_driver_->ClearPreviewedForm();
}
-bool PasswordAutofillManager::IsCreditCardPopup() {
- return false;
+autofill::PopupType PasswordAutofillManager::GetPopupType() const {
+ return autofill::PopupType::kPasswords;
}
autofill::AutofillDriver* PasswordAutofillManager::GetAutofillDriver() {
@@ -527,19 +454,6 @@ bool PasswordAutofillManager::GetPasswordAndRealmForUsername(
}
}
- for (autofill::PasswordFormFillData::UsernamesCollection::const_iterator
- usernames_iter = fill_data.other_possible_usernames.begin();
- usernames_iter != fill_data.other_possible_usernames.end();
- ++usernames_iter) {
- for (size_t i = 0; i < usernames_iter->second.size(); ++i) {
- if (usernames_iter->second[i] == current_username) {
- password_and_realm->password = usernames_iter->first.password;
- password_and_realm->realm = usernames_iter->first.realm;
- return true;
- }
- }
- }
-
return false;
}
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager.h b/chromium/components/password_manager/core/browser/password_autofill_manager.h
index e8ba4ff3c66..e830ca726c6 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager.h
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager.h
@@ -46,7 +46,7 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
base::string16* body) override;
bool RemoveSuggestion(const base::string16& value, int identifier) override;
void ClearPreviewedForm() override;
- bool IsCreditCardPopup() override;
+ autofill::PopupType GetPopupType() const override;
autofill::AutofillDriver* GetAutofillDriver() override;
void RegisterDeletionCallback(base::OnceClosure deletion_callback) override;
@@ -64,12 +64,6 @@ class PasswordAutofillManager : public autofill::AutofillPopupDelegate {
int options,
const gfx::RectF& bounds);
- // Handles a request from the renderer to show a popup with a warning
- // indicating that the form is not secure, used when a password field
- // is autofilled on a non-secure page load.
- void OnShowNotSecureWarning(base::i18n::TextDirection text_direction,
- const gfx::RectF& bounds);
-
// Handles a request from the renderer to show a popup with an option to check
// user's saved passwords, used when a password field is not autofilled.
void OnShowManualFallbackSuggestion(base::i18n::TextDirection text_direction,
diff --git a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
index 7a5f2364c07..90bdfefc7fc 100644
--- a/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_autofill_manager_unittest.cc
@@ -93,7 +93,7 @@ class TestPasswordManagerClient : public StubPasswordManagerClient {
class MockSyncService : public syncer::FakeSyncService {
public:
MockSyncService() {}
- virtual ~MockSyncService() {}
+ ~MockSyncService() override {}
MOCK_CONST_METHOD0(IsFirstSetupComplete, bool());
MOCK_CONST_METHOD0(IsSyncActive, bool());
MOCK_CONST_METHOD0(IsUsingSecondaryPassphrase, bool());
@@ -165,11 +165,6 @@ class PasswordAutofillManagerTest : public testing::Test {
int fill_data_id() { return fill_data_id_; }
autofill::PasswordFormFillData& fill_data() { return fill_data_; }
- void SetHttpWarningEnabled() {
- scoped_feature_list_.InitAndEnableFeature(
- security_state::kHttpFormWarningFeature);
- }
-
void SetManualFallbacksForFilling(bool enabled) {
if (enabled) {
scoped_feature_list_.InitAndEnableFeature(
@@ -406,13 +401,6 @@ TEST_F(PasswordAutofillManagerTest, ExtractSuggestions) {
base::string16 additional_username(base::ASCIIToUTF16("John Foo"));
data.additional_logins[additional_username] = additional;
- autofill::UsernamesCollectionKey usernames_key;
- usernames_key.realm = "http://yetanother.net";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("John Different"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
-
int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
@@ -424,35 +412,33 @@ TEST_F(PasswordAutofillManagerTest, ExtractSuggestions) {
element_bounds, _,
testing::AllOf(
SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- test_username_, additional_username, other_username)),
+ test_username_, additional_username)),
SuggestionVectorLabelsAre(testing::UnorderedElementsAre(
base::UTF8ToUTF16(data.preferred_realm),
- base::UTF8ToUTF16(additional.realm),
- base::UTF8ToUTF16(usernames_key.realm)))),
+ base::UTF8ToUTF16(additional.realm)))),
_));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), false,
element_bounds);
// Now simulate displaying suggestions matching "John".
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- additional_username,
- other_username)),
- _));
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(element_bounds, _,
+ SuggestionVectorValuesAre(
+ testing::UnorderedElementsAre(additional_username)),
+ _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("John"), false,
element_bounds);
// Finally, simulate displaying all suggestions, without any prefix matching.
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- test_username_, additional_username, other_username)),
- _));
+ EXPECT_CALL(
+ *autofill_client,
+ ShowAutofillPopup(element_bounds, _,
+ SuggestionVectorValuesAre(testing::UnorderedElementsAre(
+ test_username_, additional_username)),
+ _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("xyz"), true,
element_bounds);
@@ -476,24 +462,16 @@ TEST_F(PasswordAutofillManagerTest, PrettifiedAndroidRealmsAreShownAsLabels) {
base::string16 additional_username(base::ASCIIToUTF16("John Foo"));
data.additional_logins[additional_username] = additional;
- autofill::UsernamesCollectionKey usernames_key;
- usernames_key.realm = "android://hash@com.example3.android/";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("John Different"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
-
const int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
- EXPECT_CALL(
- *autofill_client,
- ShowAutofillPopup(
- _, _, SuggestionVectorLabelsAre(testing::UnorderedElementsAre(
- base::ASCIIToUTF16("android://com.example1.android/"),
- base::ASCIIToUTF16("android://com.example2.android/"),
- base::ASCIIToUTF16("android://com.example3.android/"))),
- _));
+ EXPECT_CALL(*autofill_client,
+ ShowAutofillPopup(
+ _, _,
+ SuggestionVectorLabelsAre(testing::UnorderedElementsAre(
+ base::ASCIIToUTF16("android://com.example1.android/"),
+ base::ASCIIToUTF16("android://com.example2.android/"))),
+ _));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, base::string16(), false,
gfx::RectF());
@@ -518,10 +496,6 @@ TEST_F(PasswordAutofillManagerTest, FillSuggestionPasswordField) {
autofill::UsernamesCollectionKey usernames_key;
usernames_key.realm = "http://yetanother.net";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("John Different"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
@@ -578,10 +552,6 @@ TEST_F(PasswordAutofillManagerTest, DisplaySuggestionsWithMatchingTokens) {
autofill::UsernamesCollectionKey usernames_key;
usernames_key.realm = "http://yetanother.net";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("example@foo.com"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
@@ -590,7 +560,7 @@ TEST_F(PasswordAutofillManagerTest, DisplaySuggestionsWithMatchingTokens) {
*autofill_client,
ShowAutofillPopup(element_bounds, _,
SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- username, additional_username, other_username)),
+ username, additional_username)),
_));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), false,
@@ -623,10 +593,6 @@ TEST_F(PasswordAutofillManagerTest, NoSuggestionForNonPrefixTokenMatch) {
autofill::UsernamesCollectionKey usernames_key;
usernames_key.realm = "http://yetanother.net";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("example@foo.com"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
@@ -666,10 +632,6 @@ TEST_F(PasswordAutofillManagerTest,
autofill::UsernamesCollectionKey usernames_key;
usernames_key.realm = "http://yetanother.net";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("example@foo.com"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
@@ -713,10 +675,6 @@ TEST_F(PasswordAutofillManagerTest,
autofill::UsernamesCollectionKey usernames_key;
usernames_key.realm = "http://yetanother.net";
- std::vector<base::string16> other_names;
- base::string16 other_username(base::ASCIIToUTF16("example@foo.com"));
- other_names.push_back(other_username);
- data.other_possible_usernames[usernames_key] = other_names;
int dummy_key = 0;
password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
@@ -725,7 +683,7 @@ TEST_F(PasswordAutofillManagerTest,
*autofill_client,
ShowAutofillPopup(element_bounds, _,
SuggestionVectorValuesAre(testing::UnorderedElementsAre(
- other_username, username, additional_username)),
+ username, additional_username)),
_));
password_autofill_manager_->OnShowPasswordSuggestions(
dummy_key, base::i18n::RIGHT_TO_LEFT, base::ASCIIToUTF16("foo"), false,
@@ -766,291 +724,6 @@ TEST_F(PasswordAutofillManagerTest, PreviewAndFillEmptyUsernameSuggestion) {
testing::Mock::VerifyAndClearExpectations(client->mock_driver());
}
-// Tests that a standalone Form Not Secure warning shows up in the
-// autofill popup when PasswordAutofillManager::OnShowNotSecureWarning()
-// is called.
-TEST_F(PasswordAutofillManagerTest, ShowStandaloneNotSecureWarning) {
- auto client = std::make_unique<TestPasswordManagerClient>();
- auto autofill_client = std::make_unique<MockAutofillClient>();
- InitializePasswordAutofillManager(client.get(), autofill_client.get());
-
- gfx::RectF element_bounds;
- autofill::PasswordFormFillData data;
- data.username_field.value = test_username_;
- data.password_field.value = test_password_;
- data.origin = GURL("http://foo.test");
-
- int dummy_key = 0;
- password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
-
- // String "Login not secure" shown as a warning messages if password form is
- // on http sites.
- const base::string16 warning_message =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE);
-
- SetHttpWarningEnabled();
-
- auto elements = testing::ElementsAre(warning_message);
-
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(elements), _));
- password_autofill_manager_->OnShowNotSecureWarning(base::i18n::RIGHT_TO_LEFT,
- element_bounds);
-
- // Accepting the warning message should trigger a call to open an explanation
- // of the message and hide the popup.
- EXPECT_CALL(
- *autofill_client,
- ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
- EXPECT_CALL(*autofill_client, HideAutofillPopup());
- password_autofill_manager_->DidAcceptSuggestion(
- base::string16(), autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
- 0);
-}
-
-TEST_F(PasswordAutofillManagerTest, NonSecurePasswordFieldHttpWarningMessage) {
- auto client = std::make_unique<TestPasswordManagerClient>();
- auto autofill_client = std::make_unique<MockAutofillClient>();
- InitializePasswordAutofillManager(client.get(), autofill_client.get());
-
- gfx::RectF element_bounds;
- autofill::PasswordFormFillData data;
- data.username_field.value = test_username_;
- data.password_field.value = test_password_;
- data.origin = GURL("http://foo.test");
-
- int dummy_key = 0;
- password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
-
- // String "Login not secure" shown as a warning messages if password form is
- // on http sites.
- base::string16 warning_message =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE);
-
- // String "Use password for:" shown when displaying suggestions matching a
- // username and specifying that the field is a password field.
- base::string16 title =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
-
- base::string16 show_all_saved_row_text =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK);
- std::vector<base::string16> elements = {title, test_username_};
- if (IsManualFallbackForFillingEnabled()) {
-#if !defined(OS_ANDROID)
- elements.push_back(base::string16());
-#endif
- elements.push_back(show_all_saved_row_text);
- }
-
- // Http warning message won't show with switch flag off.
- EXPECT_CALL(
- *autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
- autofill::IS_PASSWORD_FIELD, element_bounds);
-
- SetHttpWarningEnabled();
-
- // Http warning message shows for non-secure context and switch flag on, so
- // there are 3 suggestions (+ 1 separator on desktop) in total, and the
- // message comes first among suggestions.
- elements = {
- warning_message,
-#if !defined(OS_ANDROID)
- base::string16(),
-#endif
- title,
- test_username_
- };
- if (IsManualFallbackForFillingEnabled()) {
-#if !defined(OS_ANDROID)
- elements.push_back(base::string16());
-#endif
- elements.push_back(show_all_saved_row_text);
- }
-
- EXPECT_CALL(
- *autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
- autofill::IS_PASSWORD_FIELD, element_bounds);
-
- // Accepting the warning message should trigger a call to open an explanation
- // of the message and hide the popup.
- EXPECT_CALL(
- *autofill_client,
- ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
- EXPECT_CALL(*autofill_client, HideAutofillPopup());
- password_autofill_manager_->DidAcceptSuggestion(
- base::string16(), autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
- 0);
-}
-
-// Tests that the "Login not secure" warning shows up in non-password
-// fields of login forms.
-TEST_F(PasswordAutofillManagerTest, NonSecureUsernameFieldHttpWarningMessage) {
- auto client = std::make_unique<TestPasswordManagerClient>();
- auto autofill_client = std::make_unique<MockAutofillClient>();
- InitializePasswordAutofillManager(client.get(), autofill_client.get());
-
- gfx::RectF element_bounds;
- autofill::PasswordFormFillData data;
- data.username_field.value = test_username_;
- data.password_field.value = test_password_;
- data.origin = GURL("http://foo.test");
-
- int dummy_key = 0;
- password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
-
- // String "Login not secure" shown as a warning messages if password form is
- // on http sites.
- base::string16 warning_message =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_LOGIN_HTTP_WARNING_MESSAGE);
-
- // Http warning message won't show with switch flag off.
- EXPECT_CALL(
- *autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAre(test_username_)), _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_, 0, element_bounds);
-
- SetHttpWarningEnabled();
-
- // Http warning message shows for non-secure context and switch flag on, so
- // there are 2 suggestions (+ 1 separator on desktop) in total, and the
- // message comes first among suggestions.
- auto elements = testing::ElementsAre(warning_message,
-#if !defined(OS_ANDROID)
- base::string16(),
-#endif
- test_username_);
-
- EXPECT_CALL(*autofill_client,
- ShowAutofillPopup(element_bounds, _,
- SuggestionVectorValuesAre(elements), _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_, 0, element_bounds);
-
- // Accepting the warning message should trigger a call to open an explanation
- // of the message and hide the popup.
- EXPECT_CALL(
- *autofill_client,
- ExecuteCommand(autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE));
- EXPECT_CALL(*autofill_client, HideAutofillPopup());
- password_autofill_manager_->DidAcceptSuggestion(
- base::string16(), autofill::POPUP_ITEM_ID_HTTP_NOT_SECURE_WARNING_MESSAGE,
- 0);
-}
-
-TEST_F(PasswordAutofillManagerTest, SecurePasswordFieldHttpWarningMessage) {
- auto client = std::make_unique<TestPasswordManagerClient>();
- auto autofill_client = std::make_unique<MockAutofillClient>();
- InitializePasswordAutofillManager(client.get(), autofill_client.get());
-
- gfx::RectF element_bounds;
- autofill::PasswordFormFillData data;
- data.username_field.value = test_username_;
- data.password_field.value = test_password_;
- data.origin = GURL("https://foo.test");
-
- int dummy_key = 0;
- password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
-
- // String "Use password for:" shown when displaying suggestions matching a
- // username and specifying that the field is a password field.
- base::string16 title =
- l10n_util::GetStringUTF16(IDS_AUTOFILL_PASSWORD_FIELD_SUGGESTIONS_TITLE);
-
- std::vector<base::string16> elements = {title, test_username_};
- if (IsManualFallbackForFillingEnabled()) {
- elements = {
- title,
- test_username_,
-#if !defined(OS_ANDROID)
- base::string16(),
-#endif
- l10n_util::GetStringUTF16(IDS_AUTOFILL_SHOW_ALL_SAVED_FALLBACK)
- };
- }
- // Http warning message won't show with switch flag off.
- EXPECT_CALL(
- *autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
- autofill::IS_PASSWORD_FIELD, element_bounds);
-
- SetHttpWarningEnabled();
-
- // Http warning message won't show for secure context, even with switch flag
- // on.
- EXPECT_CALL(
- *autofill_client,
- ShowAutofillPopup(
- element_bounds, _,
- SuggestionVectorValuesAre(testing::ElementsAreArray(elements)), _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
- autofill::IS_PASSWORD_FIELD, element_bounds);
-}
-
-// Tests that the Form-Not-Secure warning is recorded in UMA, at most once per
-// navigation.
-TEST_F(PasswordAutofillManagerTest, ShowedFormNotSecureHistogram) {
- const char kHistogram[] =
- "PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation";
- base::HistogramTester histograms;
- SetHttpWarningEnabled();
-
- auto client = std::make_unique<TestPasswordManagerClient>();
- auto autofill_client = std::make_unique<MockAutofillClient>();
- InitializePasswordAutofillManager(client.get(), autofill_client.get());
-
- // Test that the standalone warning (with no autofill suggestions) records the
- // histogram.
- gfx::RectF element_bounds;
- EXPECT_CALL(*autofill_client, ShowAutofillPopup(element_bounds, _, _, _));
- password_autofill_manager_->OnShowNotSecureWarning(base::i18n::RIGHT_TO_LEFT,
- element_bounds);
- histograms.ExpectUniqueSample(kHistogram, true, 1);
-
- // Simulate a navigation, because the histogram is recorded at most once per
- // navigation.
- password_autofill_manager_->DidNavigateMainFrame();
-
- // Test that the warning, when included with the normal autofill dropdown,
- // records the histogram.
- int dummy_key = 0;
- autofill::PasswordFormFillData data;
- data.username_field.value = test_username_;
- data.password_field.value = test_password_;
- data.origin = GURL("http://foo.test");
-
- password_autofill_manager_->OnAddPasswordFormMapping(dummy_key, data);
- EXPECT_CALL(*autofill_client, ShowAutofillPopup(element_bounds, _, _, _));
- password_autofill_manager_->OnShowPasswordSuggestions(
- dummy_key, base::i18n::RIGHT_TO_LEFT, test_username_,
- autofill::IS_PASSWORD_FIELD, element_bounds);
- histograms.ExpectUniqueSample(kHistogram, true, 2);
-
- // The histogram should not be recorded again on the same navigation.
- EXPECT_CALL(*autofill_client, ShowAutofillPopup(element_bounds, _, _, _));
- password_autofill_manager_->OnShowNotSecureWarning(base::i18n::RIGHT_TO_LEFT,
- element_bounds);
- histograms.ExpectUniqueSample(kHistogram, true, 2);
-}
-
// Tests that the "Show all passwords" suggestion isn't shown along with
// "Use password for" in the popup when the feature which controls its
// appearance is disabled.
diff --git a/chromium/components/password_manager/core/browser/password_form_filling.cc b/chromium/components/password_manager/core/browser/password_form_filling.cc
new file mode 100644
index 00000000000..7abbd663d20
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_filling.cc
@@ -0,0 +1,167 @@
+// 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 "components/password_manager/core/browser/password_form_filling.h"
+
+#include "base/feature_list.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/metrics/user_metrics.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
+#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
+#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_manager_driver.h"
+#include "components/password_manager/core/browser/password_manager_util.h"
+#include "components/password_manager/core/common/password_manager_features.h"
+
+using autofill::PasswordForm;
+using autofill::PasswordFormFillData;
+using Logger = autofill::SavePasswordProgressLogger;
+
+namespace password_manager {
+
+namespace {
+bool PreferredRealmIsFromAndroid(const PasswordFormFillData& fill_data) {
+ return FacetURI::FromPotentiallyInvalidSpec(fill_data.preferred_realm)
+ .IsValidAndroidFacetURI();
+}
+
+bool ContainsAndroidCredentials(const PasswordFormFillData& fill_data) {
+ for (const auto& login : fill_data.additional_logins) {
+ if (FacetURI::FromPotentiallyInvalidSpec(login.second.realm)
+ .IsValidAndroidFacetURI()) {
+ return true;
+ }
+ }
+
+ return PreferredRealmIsFromAndroid(fill_data);
+}
+
+bool ShouldShowInitialPasswordAccountSuggestions() {
+ return base::FeatureList::IsEnabled(
+ password_manager::features::kFillOnAccountSelect);
+}
+
+void Autofill(const PasswordManagerClient& client,
+ PasswordManagerDriver* driver,
+ const PasswordForm& form_for_autofill,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const std::vector<const PasswordForm*>& federated_matches,
+ const PasswordForm& preferred_match,
+ bool wait_for_username) {
+ DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
+
+ std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
+ if (password_manager_util::IsLoggingActive(&client)) {
+ logger.reset(new BrowserSavePasswordProgressLogger(client.GetLogManager()));
+ logger->LogMessage(Logger::STRING_PASSWORDMANAGER_AUTOFILL);
+ }
+
+ autofill::PasswordFormFillData fill_data;
+ InitPasswordFormFillData(form_for_autofill, best_matches, &preferred_match,
+ wait_for_username, &fill_data);
+ if (logger)
+ logger->LogBoolean(Logger::STRING_WAIT_FOR_USERNAME, wait_for_username);
+ UMA_HISTOGRAM_BOOLEAN(
+ "PasswordManager.FillSuggestionsIncludeAndroidAppCredentials",
+ ContainsAndroidCredentials(fill_data));
+ metrics_util::LogFilledCredentialIsFromAndroidApp(
+ PreferredRealmIsFromAndroid(fill_data));
+ driver->FillPasswordForm(fill_data);
+
+ client.PasswordWasAutofilled(best_matches, form_for_autofill.origin,
+ &federated_matches);
+}
+
+void ShowInitialPasswordAccountSuggestions(
+ const PasswordManagerClient& client,
+ PasswordManagerDriver* driver,
+ const PasswordForm& form_for_autofill,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const PasswordForm& preferred_match,
+ bool wait_for_username) {
+ DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
+
+ std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
+ if (password_manager_util::IsLoggingActive(&client)) {
+ logger.reset(new BrowserSavePasswordProgressLogger(client.GetLogManager()));
+ logger->LogMessage(
+ Logger::
+ STRING_PASSWORDMANAGER_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS);
+ }
+
+ PasswordFormFillData fill_data;
+ InitPasswordFormFillData(form_for_autofill, best_matches, &preferred_match,
+ wait_for_username, &fill_data);
+ if (logger)
+ logger->LogBoolean(Logger::STRING_WAIT_FOR_USERNAME, wait_for_username);
+ driver->ShowInitialPasswordAccountSuggestions(fill_data);
+}
+
+} // namespace
+
+void SendFillInformationToRenderer(
+ const PasswordManagerClient& client,
+ PasswordManagerDriver* driver,
+ bool is_blacklisted,
+ const PasswordForm& observed_form,
+ const std::map<base::string16, const PasswordForm*>& best_matches,
+ const std::vector<const PasswordForm*>& federated_matches,
+ const PasswordForm* preferred_match,
+ PasswordFormMetricsRecorder* metrics_recorder) {
+ DCHECK(driver);
+ DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form.scheme);
+
+ if (is_blacklisted)
+ driver->MatchingBlacklistedFormFound();
+
+ driver->AllowPasswordGenerationForForm(observed_form);
+
+ if (best_matches.empty()) {
+ driver->InformNoSavedCredentials();
+ metrics_recorder->RecordFillEvent(
+ PasswordFormMetricsRecorder::kManagerFillEventNoCredential);
+ return;
+ }
+ DCHECK(preferred_match);
+
+ // Proceed to autofill.
+ // Note that we provide the choices but don't actually prefill a value if:
+ // (1) we are in Incognito mode, or
+ // (2) if it matched using public suffix domain matching, or
+ // (3) the form is change password form.
+ bool wait_for_username = client.IsIncognito() ||
+ preferred_match->is_public_suffix_match ||
+ observed_form.IsPossibleChangePasswordForm();
+ if (wait_for_username) {
+ metrics_recorder->SetManagerAction(
+ PasswordFormMetricsRecorder::kManagerActionNone);
+ metrics_recorder->RecordFillEvent(
+ PasswordFormMetricsRecorder::kManagerFillEventBlockedOnInteraction);
+ } else {
+ metrics_recorder->SetManagerAction(
+ PasswordFormMetricsRecorder::kManagerActionAutofilled);
+ metrics_recorder->RecordFillEvent(
+ PasswordFormMetricsRecorder::kManagerFillEventAutofilled);
+ base::RecordAction(base::UserMetricsAction("PasswordManager_Autofilled"));
+ }
+ if (ShouldShowInitialPasswordAccountSuggestions()) {
+ // This is for the fill-on-account-select experiment. Instead of autofilling
+ // found usernames and passwords on load, this instructs the renderer to
+ // return with any found password forms so a list of password account
+ // suggestions can be drawn.
+ ShowInitialPasswordAccountSuggestions(client, driver, observed_form,
+ best_matches, *preferred_match,
+ wait_for_username);
+ } else {
+ // If fill-on-account-select is not enabled, continue with autofilling any
+ // password forms as traditionally has been done.
+ Autofill(client, driver, observed_form, best_matches, federated_matches,
+ *preferred_match, wait_for_username);
+ }
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_filling.h b/chromium/components/password_manager/core/browser/password_form_filling.h
new file mode 100644
index 00000000000..d8ca0282de1
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_filling.h
@@ -0,0 +1,35 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FILLING_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FILLING_H_
+
+#include <map>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string16.h"
+
+namespace autofill {
+struct PasswordForm;
+} // namespace autofill
+
+namespace password_manager {
+class PasswordManagerClient;
+class PasswordManagerDriver;
+class PasswordFormMetricsRecorder;
+
+void SendFillInformationToRenderer(
+ const PasswordManagerClient& client,
+ PasswordManagerDriver* driver,
+ bool is_blacklisted,
+ const autofill::PasswordForm& observed_form,
+ const std::map<base::string16, const autofill::PasswordForm*>& best_matches,
+ const std::vector<const autofill::PasswordForm*>& federated_matches,
+ const autofill::PasswordForm* preferred_match,
+ PasswordFormMetricsRecorder* metrics_recorder);
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_FILLING_H_
diff --git a/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
new file mode 100644
index 00000000000..7017c4cb8d3
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -0,0 +1,177 @@
+// 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 "components/password_manager/core/browser/password_form_filling.h"
+
+#include <map>
+#include <vector>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/autofill/core/common/password_form_fill_data.h"
+#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
+#include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "components/password_manager/core/browser/stub_password_manager_driver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using autofill::PasswordForm;
+using autofill::PasswordFormFillData;
+using base::ASCIIToUTF16;
+using testing::_;
+using testing::SaveArg;
+
+namespace password_manager {
+namespace {
+class MockPasswordManagerDriver : public StubPasswordManagerDriver {
+ public:
+ MockPasswordManagerDriver() {}
+
+ ~MockPasswordManagerDriver() override {}
+
+ MOCK_METHOD1(FillPasswordForm, void(const PasswordFormFillData&));
+ MOCK_METHOD0(InformNoSavedCredentials, void());
+ MOCK_METHOD1(ShowInitialPasswordAccountSuggestions,
+ void(const PasswordFormFillData&));
+ MOCK_METHOD1(AllowPasswordGenerationForForm, void(const PasswordForm&));
+ MOCK_METHOD0(MatchingBlacklistedFormFound, void());
+};
+
+class MockPasswordManagerClient : public StubPasswordManagerClient {
+ public:
+ MockPasswordManagerClient() {}
+
+ MOCK_CONST_METHOD3(PasswordWasAutofilled,
+ void(const std::map<base::string16, const PasswordForm*>&,
+ const GURL&,
+ const std::vector<const PasswordForm*>*));
+};
+
+} // namespace
+
+class PasswordFormFillingTest : public testing::Test {
+ public:
+ PasswordFormFillingTest() {
+ observed_form_.origin = GURL("http://accounts.google.com/a/LoginAuth");
+ observed_form_.action = GURL("http://accounts.google.com/a/Login");
+ observed_form_.username_element = ASCIIToUTF16("Email");
+ observed_form_.password_element = ASCIIToUTF16("Passwd");
+ observed_form_.submit_element = ASCIIToUTF16("signIn");
+ observed_form_.signon_realm = "http://accounts.google.com";
+ observed_form_.form_data.name = ASCIIToUTF16("the-form-name");
+
+ saved_match_ = observed_form_;
+ saved_match_.origin = GURL("http://accounts.google.com/a/ServiceLoginAuth");
+ saved_match_.action = GURL("http://accounts.google.com/a/ServiceLogin");
+ saved_match_.preferred = true;
+ saved_match_.username_value = ASCIIToUTF16("test@gmail.com");
+ saved_match_.password_value = ASCIIToUTF16("test1");
+
+ psl_saved_match_ = saved_match_;
+ psl_saved_match_.is_public_suffix_match = true;
+ psl_saved_match_.origin =
+ GURL("http://m.accounts.google.com/a/ServiceLoginAuth");
+ psl_saved_match_.action = GURL("http://m.accounts.google.com/a/Login");
+ psl_saved_match_.signon_realm = "http://m.accounts.google.com";
+
+ metrics_recorder_ = base::MakeRefCounted<PasswordFormMetricsRecorder>(
+ true, client_.GetUkmSourceId());
+ }
+
+ protected:
+ MockPasswordManagerDriver driver_;
+ MockPasswordManagerClient client_;
+ PasswordForm observed_form_;
+ PasswordForm saved_match_;
+ PasswordForm psl_saved_match_;
+ scoped_refptr<PasswordFormMetricsRecorder> metrics_recorder_;
+ std::vector<const autofill::PasswordForm*> federated_matches_;
+};
+
+TEST_F(PasswordFormFillingTest, NoSavedCredentials) {
+ std::map<base::string16, const autofill::PasswordForm*> best_matches;
+
+ EXPECT_CALL(driver_, AllowPasswordGenerationForForm(observed_form_));
+ EXPECT_CALL(driver_, InformNoSavedCredentials());
+ EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0);
+ EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
+
+ SendFillInformationToRenderer(
+ client_, &driver_, false /* is_blacklisted */, observed_form_,
+ best_matches, federated_matches_, nullptr, metrics_recorder_.get());
+}
+
+TEST_F(PasswordFormFillingTest, Autofill) {
+ for (bool is_blacklisted : {false, true}) {
+ std::map<base::string16, const autofill::PasswordForm*> best_matches;
+ best_matches[saved_match_.username_value] = &saved_match_;
+ PasswordForm another_saved_match = saved_match_;
+ another_saved_match.username_value += ASCIIToUTF16("1");
+ another_saved_match.password_value += ASCIIToUTF16("1");
+ best_matches[another_saved_match.username_value] = &another_saved_match;
+
+ EXPECT_CALL(driver_, AllowPasswordGenerationForForm(observed_form_));
+ EXPECT_CALL(driver_, InformNoSavedCredentials()).Times(0);
+ PasswordFormFillData fill_data;
+ EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
+ EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
+ EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
+ EXPECT_CALL(driver_, MatchingBlacklistedFormFound)
+ .Times(is_blacklisted ? 1 : 0);
+
+ SendFillInformationToRenderer(
+ client_, &driver_, is_blacklisted, observed_form_, best_matches,
+ federated_matches_, &saved_match_, metrics_recorder_.get());
+
+ // Check that the message to the renderer (i.e. |fill_data|) is filled
+ // correctly.
+ EXPECT_EQ(observed_form_.origin, fill_data.origin);
+ EXPECT_FALSE(fill_data.wait_for_username);
+ EXPECT_EQ(observed_form_.username_element, fill_data.username_field.name);
+ EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
+ EXPECT_EQ(observed_form_.password_element, fill_data.password_field.name);
+ EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
+
+ // Check that information about non-preferred best matches is filled.
+ ASSERT_EQ(1u, fill_data.additional_logins.size());
+ EXPECT_EQ(another_saved_match.username_value,
+ fill_data.additional_logins.begin()->first);
+ EXPECT_EQ(another_saved_match.password_value,
+ fill_data.additional_logins.begin()->second.password);
+ // Realm is empty for non-psl match.
+ EXPECT_TRUE(fill_data.additional_logins.begin()->second.realm.empty());
+ }
+}
+
+TEST_F(PasswordFormFillingTest, AutofillPSLMatch) {
+ std::map<base::string16, const autofill::PasswordForm*> best_matches;
+ best_matches[saved_match_.username_value] = &psl_saved_match_;
+
+ EXPECT_CALL(driver_, AllowPasswordGenerationForForm(observed_form_));
+ EXPECT_CALL(driver_, InformNoSavedCredentials()).Times(0);
+ PasswordFormFillData fill_data;
+ EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data));
+ EXPECT_CALL(driver_, ShowInitialPasswordAccountSuggestions(_)).Times(0);
+ EXPECT_CALL(client_, PasswordWasAutofilled(_, _, _));
+
+ SendFillInformationToRenderer(client_, &driver_, false /* is_blacklisted */,
+ observed_form_, best_matches,
+ federated_matches_, &psl_saved_match_,
+ metrics_recorder_.get());
+
+ // Check that the message to the renderer (i.e. |fill_data|) is filled
+ // correctly.
+ EXPECT_EQ(observed_form_.origin, fill_data.origin);
+ EXPECT_TRUE(fill_data.wait_for_username);
+ EXPECT_EQ(psl_saved_match_.signon_realm, fill_data.preferred_realm);
+ EXPECT_EQ(observed_form_.username_element, fill_data.username_field.name);
+ EXPECT_EQ(saved_match_.username_value, fill_data.username_field.value);
+ EXPECT_EQ(observed_form_.password_element, fill_data.password_field.name);
+ EXPECT_EQ(saved_match_.password_value, fill_data.password_field.value);
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.cc b/chromium/components/password_manager/core/browser/password_form_manager.cc
index 25ee965c9c5..663cba455fc 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager.cc
@@ -4,17 +4,19 @@
#include "components/password_manager/core/browser/password_form_manager.h"
+#include <ctype.h>
#include <stddef.h>
#include <algorithm>
+#include <iterator>
#include <map>
#include <memory>
#include <utility>
-#include "base/feature_list.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
+#include "base/rand_util.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
@@ -29,6 +31,7 @@
#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/form_saver.h"
#include "components/password_manager/core/browser/log_manager.h"
+#include "components/password_manager/core/browser/password_form_filling.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
@@ -51,11 +54,6 @@ namespace password_manager {
namespace {
-std::vector<std::string> SplitPathToSegments(const std::string& path) {
- return base::SplitString(path, "/", base::TRIM_WHITESPACE,
- base::SPLIT_WANT_ALL);
-}
-
bool DoesStringContainOnlyDigits(const base::string16& s) {
for (auto c : s) {
if (!base::IsAsciiDigit(c))
@@ -69,11 +67,6 @@ bool IsProbablyNotUsername(const base::string16& s) {
return !s.empty() && DoesStringContainOnlyDigits(s) && s.size() < 3;
}
-bool ShouldShowInitialPasswordAccountSuggestions() {
- return base::FeatureList::IsEnabled(
- password_manager::features::kFillOnAccountSelect);
-}
-
// Update |credential| to reflect usage.
void UpdateMetadataForUsage(PasswordForm* credential) {
++credential->times_used;
@@ -155,7 +148,6 @@ void SetFieldLabelsOnSave(const autofill::ServerFieldType password_type,
const autofill::PasswordForm& form,
FieldTypeMap* field_types) {
DCHECK(password_type == autofill::PASSWORD ||
- password_type == autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD ||
password_type == autofill::ACCOUNT_CREATION_PASSWORD ||
password_type == autofill::NOT_ACCOUNT_CREATION_PASSWORD)
<< password_type;
@@ -169,14 +161,13 @@ void SetFieldLabelsOnSave(const autofill::ServerFieldType password_type,
}
// Label username and password fields with autofill types in |form_structure|
-// based on |field_types|. The function also adds the types to
-// |available_field_types|. For field of |USERNAME| type, the username vote
-// type will be set to |username_vote_type|.
+// based on |field_types|, and vote types based on |vote_types|. The function
+// also adds the types to |available_field_types|. For fields of |USERNAME|
+// type, a vote type must exist.
void LabelFields(const FieldTypeMap& field_types,
+ const VoteTypeMap& vote_types,
FormStructure* form_structure,
- autofill::ServerFieldTypeSet* available_field_types,
- autofill::AutofillUploadContents::Field::UsernameVoteType
- username_vote_type) {
+ autofill::ServerFieldTypeSet* available_field_types) {
for (size_t i = 0; i < form_structure->field_count(); ++i) {
autofill::AutofillField* field = form_structure->field(i);
@@ -186,12 +177,14 @@ void LabelFields(const FieldTypeMap& field_types,
if (iter != field_types.end()) {
type = iter->second;
available_field_types->insert(type);
- if (type == autofill::USERNAME) {
- field->set_username_vote_type(username_vote_type);
- DCHECK_NE(autofill::AutofillUploadContents::Field::NO_INFORMATION,
- username_vote_type);
- }
}
+
+ auto vote_type_iter = vote_types.find(field->name);
+ if (vote_type_iter != vote_types.end())
+ field->set_vote_type(vote_type_iter->second);
+ DCHECK(type != autofill::USERNAME ||
+ field->vote_type() !=
+ autofill::AutofillUploadContents::Field::NO_INFORMATION);
}
autofill::ServerFieldTypeSet types;
@@ -200,6 +193,17 @@ void LabelFields(const FieldTypeMap& field_types,
}
}
+// Returns true iff |credentials| has the same password as an entry in |matches|
+// which doesn't have a username.
+bool IsAddingUsernameToExistingMatch(
+ const PasswordForm& credentials,
+ const std::map<base::string16, const autofill::PasswordForm*>& matches) {
+ const auto match = matches.find(base::string16());
+ return !credentials.username_value.empty() && match != matches.end() &&
+ !match->second->is_public_suffix_match &&
+ match->second->password_value == credentials.password_value;
+}
+
} // namespace
PasswordFormManager::PasswordFormManager(
@@ -211,14 +215,7 @@ PasswordFormManager::PasswordFormManager(
FormFetcher* form_fetcher)
: observed_form_(observed_form),
observed_form_signature_(CalculateFormSignature(observed_form.form_data)),
- other_possible_username_action_(
- PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES),
- form_path_segments_(
- observed_form_.origin.is_valid()
- ? SplitPathToSegments(observed_form_.origin.path())
- : std::vector<std::string>()),
is_new_login_(true),
- has_autofilled_(false),
has_generated_password_(false),
generated_password_changed_(false),
is_manual_generation_(false),
@@ -277,10 +274,10 @@ PasswordFormManager::~PasswordFormManager() {
}
// static
-base::string16 PasswordFormManager::PasswordToSave(const PasswordForm& form) {
+ValueElementPair PasswordFormManager::PasswordToSave(const PasswordForm& form) {
if (form.new_password_element.empty() || form.new_password_value.empty())
- return form.password_value;
- return form.new_password_value;
+ return {form.password_value, form.password_element};
+ return {form.new_password_value, form.new_password_element};
}
// TODO(crbug.com/700420): Refactor this function, to make comparison more
@@ -351,11 +348,6 @@ PasswordFormManager::MatchResultMask PasswordFormManager::DoesManage(
return result;
}
-bool PasswordFormManager::IsBlacklisted() const {
- DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
- return !blacklisted_matches_.empty();
-}
-
void PasswordFormManager::PermanentlyBlacklist() {
DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
DCHECK(!client_->IsIncognito());
@@ -376,9 +368,7 @@ bool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() const {
return pending_credentials_.is_public_suffix_match;
}
-void PasswordFormManager::ProvisionallySave(
- const PasswordForm& credentials,
- OtherPossibleUsernamesAction action) {
+void PasswordFormManager::ProvisionallySave(const PasswordForm& credentials) {
std::unique_ptr<autofill::PasswordForm> mutable_submitted_form(
new PasswordForm(credentials));
if (credentials.IsPossibleChangePasswordForm() &&
@@ -389,7 +379,6 @@ void PasswordFormManager::ProvisionallySave(
is_possible_change_password_form_without_username_ = true;
}
submitted_form_ = std::move(mutable_submitted_form);
- other_possible_username_action_ = action;
if (form_fetcher_->GetState() == FormFetcher::State::NOT_WAITING)
CreatePendingCredentials();
@@ -401,6 +390,8 @@ void PasswordFormManager::Save() {
metrics_util::LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
submitted_form_->submission_event);
+ metrics_recorder_->SetSubmissionIndicatorEvent(
+ submitted_form_->submission_event);
if ((user_action_ == UserAction::kNone) &&
DidPreferenceChange(best_matches_, pending_credentials_.username_value)) {
@@ -436,6 +427,8 @@ void PasswordFormManager::Update(
const autofill::PasswordForm& credentials_to_update) {
metrics_util::LogPasswordAcceptedSaveUpdateSubmissionIndicatorEvent(
submitted_form_->submission_event);
+ metrics_recorder_->SetSubmissionIndicatorEvent(
+ submitted_form_->submission_event);
if (observed_form_.IsPossibleChangePasswordForm()) {
FormStructure form_structure(credentials_to_update.form_data);
UploadPasswordVote(observed_form_, autofill::NEW_PASSWORD,
@@ -489,16 +482,43 @@ void PasswordFormManager::UpdateUsername(const base::string16& new_username) {
// |username_value| and |username_element| of the submitted form. When the
// user has to override the username, Chrome will send a username vote.
if (!submitted_form_->username_value.empty()) {
- credential.other_possible_usernames.push_back(autofill::ValueElementPair(
+ credential.other_possible_usernames.push_back(ValueElementPair(
submitted_form_->username_value, submitted_form_->username_element));
}
- ProvisionallySave(credential, IGNORE_OTHER_POSSIBLE_USERNAMES);
+ ProvisionallySave(credential);
}
void PasswordFormManager::UpdatePasswordValue(
const base::string16& new_password) {
- pending_credentials_.password_value = new_password;
+ DCHECK(!new_password.empty());
+
+ PasswordForm credential(*submitted_form_);
+ // Select whether to update |password_value| or |new_password_value|.
+ base::string16* password_value_ptr;
+ base::string16* password_element_ptr;
+ if (credential.new_password_value.empty()) {
+ DCHECK(!credential.password_value.empty());
+ password_value_ptr = &credential.password_value;
+ password_element_ptr = &credential.password_element;
+ } else {
+ password_value_ptr = &credential.new_password_value;
+ password_element_ptr = &credential.new_password_element;
+ }
+
+ *password_value_ptr = new_password;
+ // If |new_password| is not found among the known password fields, store an
+ // empty field name.
+ password_element_ptr->clear();
+ for (const ValueElementPair& pair : credential.all_possible_passwords) {
+ DCHECK(!pair.second.empty());
+ if (pair.first == new_password) {
+ *password_element_ptr = pair.second;
+ break;
+ }
+ }
+
+ ProvisionallySave(credential);
}
void PasswordFormManager::PresaveGeneratedPassword(
@@ -547,60 +567,6 @@ void PasswordFormManager::SaveSubmittedFormTypeForMetrics(
metrics_recorder_->SetSubmittedFormType(type);
}
-void PasswordFormManager::ScoreMatches(
- const std::vector<const PasswordForm*>& matches) {
- DCHECK(std::all_of(
- matches.begin(), matches.end(),
- [](const PasswordForm* match) { return !match->blacklisted_by_user; }));
-
- preferred_match_ = nullptr;
- best_matches_.clear();
- not_best_matches_.clear();
-
- if (matches.empty())
- return;
-
- // Compute scores.
- std::vector<uint32_t> credential_scores(matches.size());
- for (size_t i = 0; i < matches.size(); ++i)
- credential_scores[i] = ScoreResult(*matches[i]);
-
- const uint32_t best_score =
- *std::max_element(credential_scores.begin(), credential_scores.end());
-
- // Compute best score for each username.
- std::map<base::string16, uint32_t> best_scores;
- for (size_t i = 0; i < matches.size(); ++i) {
- uint32_t& score = best_scores[matches[i]->username_value];
- score = std::max(score, credential_scores[i]);
- }
-
- // Find the best match for each username, move the rest to
- // |non_best_matches_|. Also assign the overall best match to
- // |preferred_match_|.
- not_best_matches_.reserve(matches.size() - best_scores.size());
- // Fill |best_matches_| with the best-scoring credentials for each username.
- for (size_t i = 0; i < matches.size(); ++i) {
- const PasswordForm* const match = matches[i];
- const base::string16& username = match->username_value;
-
- if (credential_scores[i] < best_scores[username]) {
- not_best_matches_.push_back(match);
- continue;
- }
-
- if (!preferred_match_ && credential_scores[i] == best_score)
- preferred_match_ = match;
-
- // If there is already another best-score match for the same username, leave
- // it and add the current form to |not_best_matches_|.
- if (best_matches_.find(username) != best_matches_.end())
- not_best_matches_.push_back(match);
- else
- best_matches_.insert(std::make_pair(username, match));
- }
-}
-
void PasswordFormManager::ProcessMatches(
const std::vector<const PasswordForm*>& non_federated,
size_t filtered_count) {
@@ -615,20 +581,21 @@ void PasswordFormManager::ProcessMatches(
}
// Copy out and score non-blacklisted matches.
- std::vector<const PasswordForm*> matches(std::count_if(
- non_federated.begin(), non_federated.end(),
- [this](const PasswordForm* form) { return IsMatch(*form); }));
- std::copy_if(non_federated.begin(), non_federated.end(), matches.begin(),
+ std::vector<const PasswordForm*> matches;
+ std::copy_if(non_federated.begin(), non_federated.end(),
+ std::back_inserter(matches),
[this](const PasswordForm* form) { return IsMatch(*form); });
- ScoreMatches(matches);
+
+ password_manager_util::FindBestMatches(std::move(matches), &best_matches_,
+ &not_best_matches_, &preferred_match_);
// Copy out blacklisted matches.
- blacklisted_matches_.resize(std::count_if(
- non_federated.begin(), non_federated.end(),
- [this](const PasswordForm* form) { return IsBlacklistMatch(*form); }));
+ blacklisted_matches_.clear();
std::copy_if(
- non_federated.begin(), non_federated.end(), blacklisted_matches_.begin(),
- [this](const PasswordForm* form) { return IsBlacklistMatch(*form); });
+ non_federated.begin(), non_federated.end(),
+ std::back_inserter(blacklisted_matches_), [](const PasswordForm* form) {
+ return form->blacklisted_by_user && !form->is_public_suffix_match;
+ });
UMA_HISTOGRAM_COUNTS(
"PasswordManager.NumPasswordsNotShown",
@@ -669,58 +636,15 @@ void PasswordFormManager::ProcessFrame(
void PasswordFormManager::ProcessFrameInternal(
const base::WeakPtr<PasswordManagerDriver>& driver) {
- DCHECK_EQ(PasswordForm::SCHEME_HTML, observed_form_.scheme);
- if (!driver)
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kNewPasswordFormParsing))
return;
-
- if (IsBlacklisted())
- driver->MatchingBlacklistedFormFound();
-
- driver->AllowPasswordGenerationForForm(observed_form_);
-
- if (best_matches_.empty()) {
- driver->InformNoSavedCredentials();
- metrics_recorder_->RecordFillEvent(
- PasswordFormMetricsRecorder::kManagerFillEventNoCredential);
+ if (!driver)
return;
- }
-
- // Proceed to autofill.
- // Note that we provide the choices but don't actually prefill a value if:
- // (1) we are in Incognito mode, or
- // (2) if it matched using public suffix domain matching, or
- // (3) the form is change password form.
- bool wait_for_username = client_->IsIncognito() ||
- preferred_match_->is_public_suffix_match ||
- observed_form_.IsPossibleChangePasswordForm();
- if (wait_for_username) {
- metrics_recorder_->SetManagerAction(
- PasswordFormMetricsRecorder::kManagerActionNone);
- metrics_recorder_->RecordFillEvent(
- PasswordFormMetricsRecorder::kManagerFillEventBlockedOnInteraction);
- } else {
- has_autofilled_ = true;
- metrics_recorder_->SetManagerAction(
- PasswordFormMetricsRecorder::kManagerActionAutofilled);
- metrics_recorder_->RecordFillEvent(
- PasswordFormMetricsRecorder::kManagerFillEventAutofilled);
- base::RecordAction(base::UserMetricsAction("PasswordManager_Autofilled"));
- }
- if (ShouldShowInitialPasswordAccountSuggestions()) {
- // This is for the fill-on-account-select experiment. Instead of autofilling
- // found usernames and passwords on load, this instructs the renderer to
- // return with any found password forms so a list of password account
- // suggestions can be drawn.
- password_manager_->ShowInitialPasswordAccountSuggestions(
- driver.get(), observed_form_, best_matches_, *preferred_match_,
- wait_for_username);
- } else {
- // If fill-on-account-select is not enabled, continue with autofilling any
- // password forms as traditionally has been done.
- password_manager_->Autofill(driver.get(), observed_form_, best_matches_,
+ SendFillInformationToRenderer(*client_, driver.get(), IsBlacklisted(),
+ observed_form_, best_matches_,
form_fetcher_->GetFederatedMatches(),
- *preferred_match_, wait_for_username);
- }
+ preferred_match_, GetMetricsRecorder());
}
void PasswordFormManager::ProcessLoginPrompt() {
@@ -732,7 +656,6 @@ void PasswordFormManager::ProcessLoginPrompt() {
return;
}
- has_autofilled_ = true;
metrics_recorder_->SetManagerAction(
PasswordFormMetricsRecorder::kManagerActionAutofilled);
metrics_recorder_->RecordFillEvent(
@@ -760,20 +683,11 @@ void PasswordFormManager::ProcessUpdate() {
// Update() method.
if (!observed_form_.IsPossibleChangePasswordForm())
SendVoteOnCredentialsReuse(observed_form_, &pending_credentials_);
-}
-bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
- const base::string16& username) {
- for (const auto& key_value : best_matches_) {
- const PasswordForm& match = *key_value.second;
- for (size_t i = 0; i < match.other_possible_usernames.size(); ++i) {
- if (match.other_possible_usernames[i].first == username) {
- pending_credentials_ = match;
- return true;
- }
- }
- }
- return false;
+ // TODO(crbug.com/840384): If there is no username, we should vote again when
+ // the credential is updated with a username.
+ if (pending_credentials_.times_used == 1)
+ UploadFirstLoginVotes(*submitted_form_);
}
bool PasswordFormManager::FindUsernameInOtherPossibleUsernames(
@@ -832,7 +746,7 @@ void PasswordFormManager::SendVoteOnCredentialsReuse(
// Also bypass uploading if the username was edited. Offering generation
// in cases where we currently save the wrong username isn't great.
// TODO(gcasto): Determine if generation should be offered in this case.
- if (pending->times_used == 1 && selected_username_.empty()) {
+ if (pending->times_used == 1) {
if (UploadPasswordVote(*pending, autofill::ACCOUNT_CREATION_PASSWORD,
observed_structure.FormSignatureAsStr())) {
pending->generation_upload_status =
@@ -883,7 +797,7 @@ bool PasswordFormManager::UploadPasswordVote(
autofill::ServerFieldTypeSet available_field_types;
// A map from field names to field types.
FieldTypeMap field_types;
- autofill::AutofillUploadContents::Field::UsernameVoteType username_vote_type =
+ auto username_vote_type =
autofill::AutofillUploadContents::Field::NO_INFORMATION;
if (autofill_type != autofill::USERNAME) {
if (has_autofill_vote) {
@@ -899,8 +813,13 @@ bool PasswordFormManager::UploadPasswordVote(
SetFieldLabelsOnSave(autofill_type, form_to_upload, &field_types);
}
if (autofill_type != autofill::ACCOUNT_CREATION_PASSWORD) {
+ // If |autofill_type| == autofill::ACCOUNT_CREATION_PASSWORD, Chrome
+ // will upload a vote for another form: the one that the credential was
+ // saved on.
field_types[submitted_form_->confirmation_password_element] =
autofill::CONFIRMATION_PASSWORD;
+ form_structure.set_passwords_were_revealed(
+ has_passwords_revealed_vote_);
}
}
if (autofill_type != autofill::ACCOUNT_CREATION_PASSWORD) {
@@ -924,7 +843,12 @@ bool PasswordFormManager::UploadPasswordVote(
autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED;
}
}
-
+ if (autofill_type == autofill::PASSWORD) {
+ // The password attributes should be uploaded only on the first save.
+ DCHECK(pending_credentials_.times_used == 0);
+ GeneratePasswordAttributesVote(pending_credentials_.password_value,
+ &form_structure);
+ }
} else { // User overwrites username.
field_types[form_to_upload.username_element] = autofill::USERNAME;
field_types[form_to_upload.password_element] =
@@ -932,8 +856,9 @@ bool PasswordFormManager::UploadPasswordVote(
username_vote_type =
autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN;
}
- LabelFields(field_types, &form_structure, &available_field_types,
- username_vote_type);
+ LabelFields(field_types,
+ {{form_to_upload.username_element, username_vote_type}},
+ &form_structure, &available_field_types);
// Force uploading as these events are relatively rare and we want to make
// sure to receive them.
@@ -984,7 +909,11 @@ void PasswordFormManager::AddGeneratedVote(
autofill::AutofillField* field = form_structure->field(i);
if (field->name == generation_element_) {
field->set_generation_type(type);
- field->set_generated_password_changed(generated_password_changed_);
+ if (has_generated_password_) {
+ field->set_generated_password_changed(generated_password_changed_);
+ UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.GeneratedPasswordWasEdited",
+ generated_password_changed_);
+ }
break;
}
}
@@ -1008,9 +937,73 @@ void PasswordFormManager::AddFormClassifierVote(
}
}
+// TODO(crbug.com/840384): Share common code with UploadPasswordVote.
+void PasswordFormManager::UploadFirstLoginVotes(
+ const PasswordForm& form_to_upload) {
+ autofill::AutofillManager* autofill_manager =
+ client_->GetAutofillManagerForMainFrame();
+ if (!autofill_manager || !autofill_manager->download_manager())
+ return;
+
+ FormStructure form_structure(form_to_upload.form_data);
+ if (!autofill_manager->ShouldUploadForm(form_structure))
+ return;
+
+ FieldTypeMap field_types = {
+ {form_to_upload.username_element, autofill::USERNAME}};
+ VoteTypeMap vote_types = {
+ {form_to_upload.username_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE}};
+ if (!password_overridden_) {
+ field_types[form_to_upload.password_element] = autofill::PASSWORD;
+ vote_types[form_to_upload.password_element] =
+ autofill::AutofillUploadContents::Field::FIRST_USE;
+ }
+
+ autofill::ServerFieldTypeSet available_field_types;
+ LabelFields(field_types, vote_types, &form_structure, &available_field_types);
+ SetKnownValueFlag(&form_structure);
+
+ // Force uploading as these events are relatively rare and we want to make
+ // sure to receive them.
+ form_structure.set_upload_required(UPLOAD_REQUIRED);
+
+ if (password_manager_util::IsLoggingActive(client_)) {
+ BrowserSavePasswordProgressLogger logger(client_->GetLogManager());
+ logger.LogFormStructure(Logger::STRING_FORM_VOTES, form_structure);
+ }
+
+ autofill_manager->download_manager()->StartUploadRequest(
+ form_structure, false /* was_autofilled */, available_field_types,
+ std::string(), true /* observed_submission */);
+}
+
+void PasswordFormManager::SetKnownValueFlag(autofill::FormStructure* form) {
+ DCHECK(!password_overridden_ ||
+ best_matches_.find(pending_credentials_.username_value) !=
+ best_matches_.end())
+ << "The credential is being overriden, but it does not exist in "
+ "the best matches.";
+
+ const base::string16& known_username = pending_credentials_.username_value;
+ // If we are updating a password, the known value is the old password, not
+ // the new one.
+ const base::string16& known_password =
+ password_overridden_ ? best_matches_[known_username]->password_value
+ : pending_credentials_.password_value;
+
+ for (auto& field : *form) {
+ if (field->value.empty())
+ continue;
+ if (known_username == field->value || known_password == field->value) {
+ field->properties_mask |= autofill::FieldPropertiesFlags::KNOWN_VALUE;
+ }
+ }
+}
+
void PasswordFormManager::CreatePendingCredentials() {
DCHECK(submitted_form_);
- base::string16 password_to_save(PasswordToSave(*submitted_form_));
+ ValueElementPair password_to_save(PasswordToSave(*submitted_form_));
// Look for the actually submitted credentials in the list of previously saved
// credentials that were available to autofilling.
@@ -1022,7 +1015,7 @@ void PasswordFormManager::CreatePendingCredentials() {
// The user signed in with a login we autofilled.
pending_credentials_ = *saved_form;
password_overridden_ =
- pending_credentials_.password_value != password_to_save;
+ pending_credentials_.password_value != password_to_save.first;
if (IsPendingCredentialsPublicSuffixMatch()) {
// If the autofilled credentials were a PSL match or credentials stored
// from Android apps, store a copy with the current origin and signon
@@ -1031,11 +1024,6 @@ void PasswordFormManager::CreatePendingCredentials() {
SetUserAction(password_overridden_ ? UserAction::kOverridePassword
: UserAction::kChoosePslMatch);
- // Since this credential will not overwrite a previously saved credential,
- // username_value can be updated now.
- if (!selected_username_.empty())
- pending_credentials_.username_value = selected_username_;
-
// Update credential to reflect that it has been used for submission.
// If this isn't updated, then password generation uploads are off for
// sites where PSL matching is required to fill the login form, as two
@@ -1084,16 +1072,6 @@ void PasswordFormManager::CreatePendingCredentials() {
SetUserAction(UserAction::kOverridePassword);
}
}
- } else if (other_possible_username_action_ ==
- ALLOW_OTHER_POSSIBLE_USERNAMES &&
- UpdatePendingCredentialsIfOtherPossibleUsername(
- submitted_form_->username_value)) {
- // |pending_credentials_| is now set. Note we don't update
- // |pending_credentials_.username_value| to |credentials.username_value|
- // yet because we need to keep the original username to modify the stored
- // credential.
- selected_username_ = submitted_form_->username_value;
- is_new_login_ = false;
} else if (!best_matches_.empty() &&
submitted_form_->type != autofill::PasswordForm::TYPE_API &&
submitted_form_->username_value.empty()) {
@@ -1121,7 +1099,7 @@ void PasswordFormManager::CreatePendingCredentials() {
// If a password was generated and we didn't find a match, we have to save
// it in a separate entry since we have to store it but we don't know
// where.
- CreatePendingCredentialsForNewCredentials();
+ CreatePendingCredentialsForNewCredentials(password_to_save.second);
is_new_login_ = true;
} else {
// We don't have a good candidate to choose as the default credential for
@@ -1134,7 +1112,7 @@ void PasswordFormManager::CreatePendingCredentials() {
is_new_login_ = true;
// No stored credentials can be matched to the submitted form. Offer to
// save new credentials.
- CreatePendingCredentialsForNewCredentials();
+ CreatePendingCredentialsForNewCredentials(password_to_save.second);
// Generate username correction votes.
bool username_correction_found = FindCorrectedUsernameElement(
submitted_form_->username_value, submitted_form_->password_value);
@@ -1156,7 +1134,7 @@ void PasswordFormManager::CreatePendingCredentials() {
pending_credentials_.action = observed_form_.action;
}
- pending_credentials_.password_value = password_to_save;
+ pending_credentials_.password_value = password_to_save.first;
pending_credentials_.preferred = submitted_form_->preferred;
pending_credentials_.form_has_autofilled_value =
submitted_form_->form_has_autofilled_value;
@@ -1188,85 +1166,10 @@ void PasswordFormManager::CreatePendingCredentials() {
pending_credentials_.type = PasswordForm::TYPE_GENERATED;
}
-uint32_t PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
- DCHECK(!candidate.blacklisted_by_user);
- // For scoring of candidate login data:
- // The most important element that should match is the signon_realm followed
- // by the origin, the action, the password name, the submit button name, and
- // finally the username input field name.
- // If public suffix origin match was not used, it gives an addition of
- // 128 (1 << 7).
- // Exact origin match gives an addition of 64 (1 << 6) + # of matching url
- // dirs.
- // Partial match gives an addition of 32 (1 << 5) + # matching url dirs
- // That way, a partial match cannot trump an exact match even if
- // the partial one matches all other attributes (action, elements) (and
- // regardless of the matching depth in the URL path).
-
- // When comparing path segments, only consider at most 63 of them, so that the
- // potential gain from shared path prefix is not more than from an exact
- // origin match.
- const size_t kSegmentCountCap = 63;
- const size_t capped_form_path_segment_count =
- std::min(form_path_segments_.size(), kSegmentCountCap);
-
- uint32_t score = 0u;
- if (!candidate.is_public_suffix_match) {
- score += 1u << 8;
- }
-
- if (candidate.preferred)
- score += 1u << 7;
-
- if (candidate.origin == observed_form_.origin) {
- // This check is here for the most common case which
- // is we have a single match in the db for the given host,
- // so we don't generally need to walk the entire URL path (the else
- // clause).
- score += (1u << 6) + static_cast<uint32_t>(capped_form_path_segment_count);
- } else {
- // Walk the origin URL paths one directory at a time to see how
- // deep the two match.
- std::vector<std::string> candidate_path_segments =
- SplitPathToSegments(candidate.origin.path());
- size_t depth = 0u;
- const size_t max_dirs = std::min(capped_form_path_segment_count,
- candidate_path_segments.size());
- while ((depth < max_dirs) &&
- (form_path_segments_[depth] == candidate_path_segments[depth])) {
- depth++;
- score++;
- }
- // do we have a partial match?
- score += (depth > 0u) ? 1u << 5 : 0u;
- }
- if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
- if (candidate.action == observed_form_.action)
- score += 1u << 3;
- if (candidate.password_element == observed_form_.password_element)
- score += 1u << 2;
- if (candidate.submit_element == observed_form_.submit_element)
- score += 1u << 1;
- if (candidate.username_element == observed_form_.username_element)
- score += 1u << 0;
- }
-
- return score;
-}
-
bool PasswordFormManager::IsMatch(const autofill::PasswordForm& form) const {
return !form.blacklisted_by_user && form.scheme == observed_form_.scheme;
}
-bool PasswordFormManager::IsBlacklistMatch(
- const autofill::PasswordForm& blacklisted_form) const {
- return blacklisted_form.blacklisted_by_user &&
- !blacklisted_form.is_public_suffix_match &&
- blacklisted_form.scheme == observed_form_.scheme &&
- blacklisted_form.origin.GetOrigin() ==
- observed_form_.origin.GetOrigin();
-}
-
const PasswordForm* PasswordFormManager::FindBestMatchForUpdatePassword(
const base::string16& password) const {
// This function is called for forms that do not contain a username field.
@@ -1322,7 +1225,8 @@ const PasswordForm* PasswordFormManager::FindBestSavedMatch(
return nullptr;
}
-void PasswordFormManager::CreatePendingCredentialsForNewCredentials() {
+void PasswordFormManager::CreatePendingCredentialsForNewCredentials(
+ const base::string16& password_element) {
// User typed in a new, unknown username.
SetUserAction(UserAction::kOverrideUsernameAndPassword);
pending_credentials_ = observed_form_;
@@ -1335,15 +1239,11 @@ void PasswordFormManager::CreatePendingCredentialsForNewCredentials() {
// The password value will be filled in later, remove any garbage for now.
pending_credentials_.password_value.clear();
+ // The password element should be determined earlier in |PasswordToSave|.
+ pending_credentials_.password_element = password_element;
+ // The new password's value and element name should be empty.
pending_credentials_.new_password_value.clear();
-
- // If this was a sign-up or change password form, the names of the elements
- // are likely different than those on a login form, so do not bother saving
- // them. We will fill them with meaningful values during update when the user
- // goes onto a real login form for the first time.
- if (!submitted_form_->new_password_element.empty()) {
- pending_credentials_.password_element.clear();
- }
+ pending_credentials_.new_password_element.clear();
}
void PasswordFormManager::OnNopeUpdateClicked() {
@@ -1366,6 +1266,10 @@ void PasswordFormManager::OnNoInteraction(bool is_update) {
}
}
+void PasswordFormManager::OnPasswordsRevealed() {
+ has_passwords_revealed_vote_ = true;
+}
+
void PasswordFormManager::SetHasGeneratedPassword(bool generated_password) {
has_generated_password_ = generated_password;
metrics_recorder_->SetHasGeneratedPassword(generated_password);
@@ -1383,6 +1287,50 @@ void PasswordFormManager::MarkGenerationAvailable() {
metrics_recorder_->MarkGenerationAvailable();
}
+FormFetcher* PasswordFormManager::GetFormFetcher() {
+ return form_fetcher_;
+}
+
+const std::map<base::string16, const autofill::PasswordForm*>&
+PasswordFormManager::GetBestMatches() const {
+ return best_matches_;
+}
+
+const GURL& PasswordFormManager::GetOrigin() const {
+ return observed_form_.origin;
+}
+
+const autofill::PasswordForm& PasswordFormManager::GetPendingCredentials()
+ const {
+ return pending_credentials_;
+}
+
+metrics_util::CredentialSourceType PasswordFormManager::GetCredentialSource() {
+ return metrics_util::CredentialSourceType::kPasswordManager;
+}
+
+PasswordFormMetricsRecorder* PasswordFormManager::GetMetricsRecorder() {
+ return metrics_recorder_.get();
+}
+
+const std::vector<const autofill::PasswordForm*>&
+PasswordFormManager::GetBlacklistedMatches() const {
+ return blacklisted_matches_;
+}
+
+bool PasswordFormManager::IsBlacklisted() const {
+ DCHECK_EQ(FormFetcher::State::NOT_WAITING, form_fetcher_->GetState());
+ return !blacklisted_matches_.empty();
+}
+
+bool PasswordFormManager::IsPasswordOverridden() const {
+ return password_overridden_;
+}
+
+const autofill::PasswordForm* PasswordFormManager::GetPreferredMatch() const {
+ return preferred_match_;
+}
+
void PasswordFormManager::WipeStoreCopyIfOutdated() {
UMA_HISTOGRAM_BOOLEAN(
"PasswordManager.StoreReadyWhenWiping",
@@ -1448,14 +1396,12 @@ std::unique_ptr<PasswordFormManager> PasswordFormManager::Clone() {
// by the cloned FormFetcher.
if (submitted_form_)
result->submitted_form_ = std::make_unique<PasswordForm>(*submitted_form_);
- result->other_possible_username_action_ = other_possible_username_action_;
if (username_correction_vote_) {
result->username_correction_vote_ =
std::make_unique<PasswordForm>(*username_correction_vote_);
}
result->pending_credentials_ = pending_credentials_;
result->is_new_login_ = is_new_login_;
- result->has_autofilled_ = has_autofilled_;
result->has_generated_password_ = has_generated_password_;
result->generated_password_changed_ = generated_password_changed_;
result->is_manual_generation_ = is_manual_generation_;
@@ -1467,7 +1413,6 @@ std::unique_ptr<PasswordFormManager> PasswordFormManager::Clone() {
result->password_overridden_ = password_overridden_;
result->retry_password_form_password_update_ =
retry_password_form_password_update_;
- result->selected_username_ = selected_username_;
result->is_possible_change_password_form_without_username_ =
is_possible_change_password_form_without_username_;
result->user_action_ = user_action_;
@@ -1475,10 +1420,6 @@ std::unique_ptr<PasswordFormManager> PasswordFormManager::Clone() {
return result;
}
-metrics_util::CredentialSourceType PasswordFormManager::GetCredentialSource() {
- return metrics_util::CredentialSourceType::kPasswordManager;
-}
-
void PasswordFormManager::SendVotesOnSave() {
if (observed_form_.IsPossibleChangePasswordFormWithoutUsername())
return;
@@ -1495,15 +1436,17 @@ void PasswordFormManager::SendVotesOnSave() {
SendSignInVote(form_data);
}
+ if (pending_credentials_.times_used == 1 ||
+ IsAddingUsernameToExistingMatch(pending_credentials_, best_matches_)) {
+ UploadFirstLoginVotes(*submitted_form_);
+ }
+
// Upload credentials the first time they are saved. This data is used
// by password generation to help determine account creation sites.
// Credentials that have been previously used (e.g., PSL matches) are checked
// to see if they are valid account creation forms.
if (pending_credentials_.times_used == 0) {
- autofill::ServerFieldType password_type = autofill::PASSWORD;
- if (submitted_form_->does_look_like_signup_form)
- password_type = autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD;
- UploadPasswordVote(pending_credentials_, password_type, std::string());
+ UploadPasswordVote(pending_credentials_, autofill::PASSWORD, std::string());
if (username_correction_vote_) {
UploadPasswordVote(
*username_correction_vote_, autofill::USERNAME,
@@ -1524,8 +1467,43 @@ void PasswordFormManager::SendSignInVote(const FormData& form_data) {
DCHECK(form_structure->ShouldBeUploaded());
DCHECK_EQ(2u, form_structure->field_count());
form_structure->field(1)->set_possible_types({autofill::PASSWORD});
- autofill_manager->StartUploadProcess(std::move(form_structure),
- base::TimeTicks::Now(), true);
+ autofill_manager->MaybeStartVoteUploadProcess(std::move(form_structure),
+ base::TimeTicks::Now(),
+ /*observed_submission=*/true);
+}
+
+void PasswordFormManager::GeneratePasswordAttributesVote(
+ const base::string16& password_value,
+ FormStructure* form_structure) {
+ // Select a password attribute to upload. Do upload symbols more often as
+ // 2/3rd of issues are because of missing special symbols.
+ int bucket = base::RandGenerator(9);
+ int (*predicate)(int c) = nullptr;
+ autofill::PasswordAttribute attribute =
+ autofill::PasswordAttribute::kHasSpecialSymbol;
+ if (bucket == 0) {
+ predicate = &islower;
+ attribute = autofill::PasswordAttribute::kHasLowercaseLetter;
+ } else if (bucket == 1) {
+ predicate = &isupper;
+ attribute = autofill::PasswordAttribute::kHasUppercaseLetter;
+ } else if (bucket == 2) {
+ predicate = &isdigit;
+ attribute = autofill::PasswordAttribute::kHasNumeric;
+ } else { // 3 <= bucket < 9
+ predicate = &ispunct;
+ attribute = autofill::PasswordAttribute::kHasSpecialSymbol;
+ }
+ bool actual_value =
+ std::any_of(password_value.begin(), password_value.end(), predicate);
+
+ // Apply the randomized response technique to noisify the actual value
+ // (https://en.wikipedia.org/wiki/Randomized_response).
+ bool randomized_value =
+ base::RandGenerator(2) ? actual_value : base::RandGenerator(2);
+
+ form_structure->set_password_attributes_vote(
+ std::make_pair(attribute, randomized_value));
}
void PasswordFormManager::SetUserAction(UserAction user_action) {
@@ -1538,28 +1516,22 @@ base::Optional<PasswordForm> PasswordFormManager::UpdatePendingAndGetOldKey(
base::Optional<PasswordForm> old_primary_key;
bool update_related_credentials = false;
- if (!selected_username_.empty()) {
- // Username has changed. We set this selected username as the real
- // username. Given that |username_value| is part of the Sync and
- // PasswordStore primary key, the old primary key must be supplied.
- old_primary_key = pending_credentials_;
- pending_credentials_.username_value = selected_username_;
- // TODO(crbug.com/188908) This branch currently never executes (bound to
- // the other usernames experiment). Updating related credentials would be
- // complicated, so we skip that, given it influences no users.
- update_related_credentials = false;
- } else if (observed_form_.new_password_element.empty() &&
- pending_credentials_.federation_origin.unique() &&
- !IsValidAndroidFacetURI(pending_credentials_.signon_realm) &&
- (pending_credentials_.password_element.empty() ||
- pending_credentials_.username_element.empty() ||
- pending_credentials_.submit_element.empty())) {
- // If |observed_form_| is a sign-in form and some of the element names are
- // empty, it is likely the first time a credential saved on a
- // sign-up/change password form is used. Given that |password_element| and
- // |username_element| are part of Sync and PasswordStore primary key, the
- // old primary key must be used if the new names shal be saved.
+ if (pending_credentials_.federation_origin.unique() &&
+ !IsValidAndroidFacetURI(pending_credentials_.signon_realm) &&
+ (pending_credentials_.password_element.empty() ||
+ pending_credentials_.username_element.empty() ||
+ pending_credentials_.submit_element.empty())) {
+ // Given that |password_element| and |username_element| are part of Sync and
+ // PasswordStore primary key, the old primary key must be used in order to
+ // match and update the existing entry.
old_primary_key = pending_credentials_;
+ // TODO(crbug.com/833171) It is possible for best_matches to not contain the
+ // username being updated. Add comments and a test, when we realise why.
+ auto best_match = best_matches_.find(pending_credentials_.username_value);
+ if (best_match != best_matches_.end()) {
+ old_primary_key->username_element = best_match->second->username_element;
+ old_primary_key->password_element = best_match->second->password_element;
+ }
pending_credentials_.password_element = observed_form_.password_element;
pending_credentials_.username_element = observed_form_.username_element;
pending_credentials_.submit_element = observed_form_.submit_element;
diff --git a/chromium/components/password_manager/core/browser/password_form_manager.h b/chromium/components/password_manager/core/browser/password_form_manager.h
index ea76f0b5c94..e5076b9c1a3 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager.h
+++ b/chromium/components/password_manager/core/browser/password_form_manager.h
@@ -22,6 +22,7 @@
#include "components/autofill/core/common/password_form.h"
#include "components/autofill/core/common/signatures_util.h"
#include "components/password_manager/core/browser/form_fetcher.h"
+#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
#include "components/password_manager/core/browser/password_form_metrics_recorder.h"
#include "components/password_manager/core/browser/password_form_user_action.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
@@ -39,10 +40,14 @@ class PasswordManagerClient;
// A map from field names to field types.
using FieldTypeMap = std::map<base::string16, autofill::ServerFieldType>;
+// A map from field names to field vote types.
+using VoteTypeMap =
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>;
// This class helps with filling the observed form (both HTML and from HTTP
// auth) and with saving/updating the stored information about it.
-class PasswordFormManager : public FormFetcher::Consumer {
+class PasswordFormManager : public PasswordFormManagerForUI,
+ public FormFetcher::Consumer {
public:
// |password_manager| owns |this|, |client| and |driver| serve to
// communicate with embedder, |observed_form| is the associated form |this|
@@ -91,18 +96,14 @@ class PasswordFormManager : public FormFetcher::Consumer {
// caused by the enum values implicitly converting to signed int.
typedef int MatchResultMask;
- enum OtherPossibleUsernamesAction {
- ALLOW_OTHER_POSSIBLE_USERNAMES,
- IGNORE_OTHER_POSSIBLE_USERNAMES
- };
-
// The upper limit on how many times Chrome will try to autofill the same
// form.
static constexpr int kMaxTimesAutofill = 5;
// Chooses between the current and new password value which one to save. This
// is whichever is non-empty, with the preference being given to the new one.
- static base::string16 PasswordToSave(const autofill::PasswordForm& form);
+ static autofill::ValueElementPair PasswordToSave(
+ const autofill::PasswordForm& form);
// Compares basic data of |observed_form_| with |form| and returns how much
// they match. The return value is a MatchResultMask bitmask.
@@ -115,9 +116,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Used to determine what type the submitted form is for UMA stats.
void SaveSubmittedFormTypeForMetrics(const autofill::PasswordForm& form);
- // Determines if the user opted to 'never remember' passwords for this form.
- bool IsBlacklisted() const;
-
// Used by PasswordManager to determine whether or not to display
// a SavePasswordBar when given the green light to save the PasswordForm
// managed by this.
@@ -134,42 +132,10 @@ class PasswordFormManager : public FormFetcher::Consumer {
// delayed until the data arrives.
void ProcessFrame(const base::WeakPtr<PasswordManagerDriver>& driver);
- // A user opted to 'never remember' passwords for this form.
- // Blacklist it so that from now on when it is seen we ignore it.
- // TODO(vasilii): remove the 'virtual' specifier.
- virtual void PermanentlyBlacklist();
-
// If the user has submitted observed_form_, provisionally hold on to
// the submitted credentials until we are told by PasswordManager whether
- // or not the login was successful. |action| describes how we deal with
- // possible usernames. If |action| is ALLOW_OTHER_POSSIBLE_USERNAMES we will
- // treat a possible usernames match as a sign that our original heuristics
- // were wrong and that the user selected the correct username from the
- // Autofill UI.
- void ProvisionallySave(const autofill::PasswordForm& credentials,
- OtherPossibleUsernamesAction action);
-
- // Handles save-as-new or update of the form managed by this manager.
- // Note the basic data of updated_credentials must match that of
- // observed_form_ (e.g DoesManage(pending_credentials_) == true).
- void Save();
-
- // Update the password store entry for |credentials_to_update|, using the
- // password from |pending_credentials_|. It modifies |pending_credentials_|.
- // |credentials_to_update| should be one of |best_matches_| or
- // |pending_credentials_|.
- void Update(const autofill::PasswordForm& credentials_to_update);
-
- // Updates the username value. Called when user edits the username and clicks
- // the save button. Updates the username and modifies internal state
- // accordingly. This function should be called after ProvisionallySave().
- void UpdateUsername(const base::string16& new_username);
-
- // Updates the password value. Called when user selects a password from the
- // password selection dropdown and clicks the save button. Updates the
- // password and modifies internal state accordingly. This function should be
- // called after ProvisionallySave().
- void UpdatePasswordValue(const base::string16& new_password);
+ // or not the login was successful.
+ void ProvisionallySave(const autofill::PasswordForm& credentials);
// Call these if/when we know the form submission worked or failed.
// These routines are used to update internal statistics ("ActionsTaken").
@@ -213,8 +179,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
generation_popup_was_shown_ = generation_popup_was_shown;
}
- bool password_overridden() const { return password_overridden_; }
-
bool retry_password_form_password_update() const {
return retry_password_form_password_update_;
}
@@ -222,39 +186,17 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Called if the user could generate a password for this form.
void MarkGenerationAvailable();
+ const autofill::PasswordForm& observed_form() const { return observed_form_; }
+
// Returns the provisionally saved form, if it exists, otherwise nullptr.
const autofill::PasswordForm* submitted_form() const {
return submitted_form_.get();
}
- // Returns the pending credentials.
- const autofill::PasswordForm& pending_credentials() const {
- return pending_credentials_;
- }
-
- // Returns the best matches.
- const std::map<base::string16, const autofill::PasswordForm*>& best_matches()
- const {
- return best_matches_;
- }
-
- const autofill::PasswordForm* preferred_match() const {
- return preferred_match_;
- }
-
- const std::vector<const autofill::PasswordForm*>& blacklisted_matches()
- const {
- return blacklisted_matches_;
- }
-
- const autofill::PasswordForm& observed_form() const { return observed_form_; }
-
bool is_possible_change_password_form_without_username() const {
return is_possible_change_password_form_without_username_;
}
- FormFetcher* form_fetcher() { return form_fetcher_; }
-
// Use this to wipe copies of |pending_credentials_| from the password store
// (and |best_matches_| as well. It will only wipe if:
// 1. The stored password differs from the one in |pending_credentials_|.
@@ -265,20 +207,15 @@ class PasswordFormManager : public FormFetcher::Consumer {
// 'test@gmail.com' and 'test@googlemail.com', those will be wiped).
void WipeStoreCopyIfOutdated();
- // Called when the user chose not to update password.
- void OnNopeUpdateClicked();
-
- // Called when the user clicked "Never" button in the "save password" prompt.
- void OnNeverClicked();
-
- // Called when the user didn't interact with UI. |is_update| is true iff
- // it was the update UI.
- void OnNoInteraction(bool is_update);
-
// Saves the outcome of HTML parsing based form classifier to upload proto.
void SaveGenerationFieldDetectedByClassifier(
const base::string16& generation_field);
+ // Generates a password attributes vote based on |password_value| and saves it
+ // to |form_structure|. Declared as public for testing.
+ void GeneratePasswordAttributesVote(const base::string16& password_value,
+ FormStructure* form_structure);
+
FormSaver* form_saver() { return form_saver_.get(); }
// Clears references to matches derived from the associated FormFetcher data.
@@ -292,10 +229,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
// adds itself as a consumer of the new one.
void GrabFetcher(std::unique_ptr<FormFetcher> fetcher);
- PasswordFormMetricsRecorder* metrics_recorder() {
- return metrics_recorder_.get();
- }
-
// Create a copy of |*this| which can be passed to the code handling
// save-password related UI. This omits some parts of the internal data, so
// the result is not identical to the original.
@@ -303,10 +236,30 @@ class PasswordFormManager : public FormFetcher::Consumer {
// another one.
std::unique_ptr<PasswordFormManager> Clone();
- // Returns who created this PasswordFormManager. The Credential Management API
- // uses a derived class of the PasswordFormManager that can indicate its
- // origin.
- virtual metrics_util::CredentialSourceType GetCredentialSource();
+ // PasswordFormManagerForUI:
+ FormFetcher* GetFormFetcher() override;
+ const GURL& GetOrigin() const override;
+ const std::map<base::string16, const autofill::PasswordForm*>&
+ GetBestMatches() const override;
+ const autofill::PasswordForm& GetPendingCredentials() const override;
+ metrics_util::CredentialSourceType GetCredentialSource() override;
+ PasswordFormMetricsRecorder* GetMetricsRecorder() override;
+ const std::vector<const autofill::PasswordForm*>& GetBlacklistedMatches()
+ const override;
+ bool IsBlacklisted() const override;
+ bool IsPasswordOverridden() const override;
+ const autofill::PasswordForm* GetPreferredMatch() const override;
+
+ void Save() override;
+ void Update(const autofill::PasswordForm& credentials_to_update) override;
+ void UpdateUsername(const base::string16& new_username) override;
+ void UpdatePasswordValue(const base::string16& new_password) override;
+
+ void OnNopeUpdateClicked() override;
+ void OnNeverClicked() override;
+ void OnNoInteraction(bool is_update) override;
+ void PermanentlyBlacklist() override;
+ void OnPasswordsRevealed() override;
protected:
// FormFetcher::Consumer:
@@ -329,26 +282,15 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Trigger filling of HTTP auth dialog and update |manager_action_|.
void ProcessLoginPrompt();
- // Given all non-blacklisted |matches|, computes their score and populates
- // |best_matches_|, |preferred_match_| and |non_best_matches_| accordingly.
- void ScoreMatches(const std::vector<const autofill::PasswordForm*>& matches);
-
// Helper for Save in the case that best_matches.size() == 0, meaning
// we have no prior record of this form/username/password and the user
// has opted to 'Save Password'. The previously preferred login from
// |best_matches_| will be reset.
void SaveAsNewLogin();
- // Helper for OnGetPasswordStoreResults to score an individual result
- // against the observed_form_.
- uint32_t ScoreResult(const autofill::PasswordForm& candidate) const;
-
// Returns true iff |form| is a non-blacklisted match for |observed_form_|.
bool IsMatch(const autofill::PasswordForm& form) const;
- // Returns true iff |form| blacklists |observed_form_|.
- bool IsBlacklistMatch(const autofill::PasswordForm& form) const;
-
// Helper for Save in the case there is at least one match for the pending
// credentials. This sends needed signals to the autofill server, and also
// triggers some UMA reporting.
@@ -405,13 +347,22 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Adds a vote from HTML parsing based form classifier to |form_structure|.
void AddFormClassifierVote(autofill::FormStructure* form_structure);
+ // Sets the known-value flag for each field, indicating that the field
+ // contained a previously stored credential on submission.
+ void SetKnownValueFlag(autofill::FormStructure* form_to_upload);
+
+ // Sends USERNAME and PASSWORD votes, when a credential is used to login for
+ // the first time. |form_to_upload| is the submitted login form.
+ void UploadFirstLoginVotes(const autofill::PasswordForm& form_to_upload);
+
// Create pending credentials from provisionally saved form and forms received
// from password store.
void CreatePendingCredentials();
// Create pending credentials from provisionally saved form when this form
// represents credentials that were not previosly saved.
- void CreatePendingCredentialsForNewCredentials();
+ void CreatePendingCredentialsForNewCredentials(
+ const base::string16& password_element);
// If |best_matches_| contains only one entry, then return this entry.
// Otherwise for empty |password| return nullptr and for non-empty |password|
@@ -485,10 +436,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
// Stores a submitted form.
std::unique_ptr<const autofill::PasswordForm> submitted_form_;
- // Stores if for creating |pending_credentials_| other possible usernames
- // option should apply.
- OtherPossibleUsernamesAction other_possible_username_action_;
-
// If the user typed username that doesn't match any saved credentials, but
// matches an entry from |other_possible_usernames| of a saved credential,
// then |username_correction_vote_| stores the credential with matched
@@ -497,10 +444,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
// field where matched username was found.
std::unique_ptr<autofill::PasswordForm> username_correction_vote_;
- // The origin url path of observed_form_ tokenized, for convenience when
- // scoring.
- const std::vector<std::string> form_path_segments_;
-
// Stores updated credentials when the form was submitted but success is still
// unknown. This variable contains credentials that are ready to be written
// (saved or updated) to a password store. It is calculated based on
@@ -511,9 +454,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
// to an existing one.
bool is_new_login_;
- // Whether the form was autofilled with credentials.
- bool has_autofilled_;
-
// Whether this form has an auto generated password.
bool has_generated_password_;
@@ -546,10 +486,6 @@ class PasswordFormManager : public FormFetcher::Consumer {
// and it was entered on a retry password form.
bool retry_password_form_password_update_;
- // Set if the user has selected one of the other possible usernames in
- // |pending_credentials_|.
- base::string16 selected_username_;
-
// PasswordManager owning this.
PasswordManager* const password_manager_;
@@ -607,6 +543,9 @@ class PasswordFormManager : public FormFetcher::Consumer {
// loop.
int autofills_left_ = kMaxTimesAutofill;
+ // Whether the password values have been shown to the user on the save prompt.
+ bool has_passwords_revealed_vote_ = false;
+
DISALLOW_COPY_AND_ASSIGN(PasswordFormManager);
};
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h b/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
new file mode 100644
index 00000000000..ac7a6eb8c32
--- /dev/null
+++ b/chromium/components/password_manager/core/browser/password_form_manager_for_ui.h
@@ -0,0 +1,106 @@
+// 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 COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_FOR_UI_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_FOR_UI_H_
+
+#include <map>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "components/password_manager/core/browser/password_manager_metrics_util.h"
+
+namespace autofill {
+struct PasswordForm;
+}
+
+namespace password_manager {
+
+class FormFetcher;
+class PasswordFormMetricsRecorder;
+
+// Interface that contains all methods from PasswordFormManager that are used in
+// UI.
+class PasswordFormManagerForUI {
+ public:
+ virtual ~PasswordFormManagerForUI() = default;
+
+ // Returns the form fetcher which is responsible for fetching saved matches
+ // from the store for the observed from.
+ virtual FormFetcher* GetFormFetcher() = 0;
+
+ // Returns origin of the initially observed form.
+ virtual const GURL& GetOrigin() const = 0;
+
+ // Returns the best saved matches for the observed form.
+ virtual const std::map<base::string16, const autofill::PasswordForm*>&
+ GetBestMatches() const = 0;
+
+ // Returns credentials that are ready to be written (saved or updated) to a
+ // password store.
+ virtual const autofill::PasswordForm& GetPendingCredentials() const = 0;
+
+ // Returns who created this PasswordFormManager. The Credential Management API
+ // uses a derived class of the PasswordFormManager that can indicate its
+ // origin.
+ virtual metrics_util::CredentialSourceType GetCredentialSource() = 0;
+
+ // Returns metric recorder which responsible for recording metrics for this
+ // form.
+ virtual PasswordFormMetricsRecorder* GetMetricsRecorder() = 0;
+
+ // Returns the blacklisted matches for the current page.
+ virtual const std::vector<const autofill::PasswordForm*>&
+ GetBlacklistedMatches() const = 0;
+
+ // Determines if the user opted to 'never remember' passwords for this form.
+ virtual bool IsBlacklisted() const = 0;
+
+ // Returns whether filled password was overriden by the user.
+ // TODO(https://crbug.com/845826): Remove once mobile username
+ // editing is implemented.
+ virtual bool IsPasswordOverridden() const = 0;
+
+ virtual const autofill::PasswordForm* GetPreferredMatch() const = 0;
+
+ // Handles save-as-new or update of the form managed by this manager.
+ virtual void Save() = 0;
+
+ // Updates the password store entry for |credentials_to_update|, using the
+ // password from the pending credentials. It modifies the pending credentials.
+ // |credentials_to_update| should be one of the best matches or the pending
+ // credentials.
+ virtual void Update(const autofill::PasswordForm& credentials_to_update) = 0;
+
+ // Updates the username value. Called when user edits the username and clicks
+ // the save button. Updates the username and modifies internal state
+ // accordingly.
+ virtual void UpdateUsername(const base::string16& new_username) = 0;
+
+ // Updates the password value. Called when user selects a password from the
+ // password selection dropdown and clicks the save button. Updates the
+ // password and modifies internal state accordingly.
+ virtual void UpdatePasswordValue(const base::string16& new_password) = 0;
+
+ // Called when the user chose not to update password.
+ virtual void OnNopeUpdateClicked() = 0;
+
+ // Called when the user clicked "Never" button in the "save password" prompt.
+ virtual void OnNeverClicked() = 0;
+
+ // Called when the user didn't interact with UI. |is_update| is true iff
+ // it was the update UI.
+ virtual void OnNoInteraction(bool is_update) = 0;
+
+ // A user opted to 'never remember' passwords for this form.
+ // Blacklist it so that from now on when it is seen we ignore it.
+ virtual void PermanentlyBlacklist() = 0;
+
+ // Called when the passwords were shown on on the bubble without obfuscation.
+ virtual void OnPasswordsRevealed() = 0;
+};
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_MANAGER_FOR_UI_H_
diff --git a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
index 93c1ed134c2..d618926770b 100644
--- a/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_manager_unittest.cc
@@ -13,6 +13,8 @@
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/metrics_hashes.h"
+#include "base/optional.h"
+#include "base/rand_util.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/histogram_tester.h"
@@ -57,6 +59,8 @@ using autofill::PasswordForm;
using autofill::ValueElementPair;
using base::ASCIIToUTF16;
using ::testing::_;
+using ::testing::AllOf;
+using ::testing::AtMost;
using ::testing::Contains;
using ::testing::ElementsAre;
using ::testing::InSequence;
@@ -76,9 +80,34 @@ namespace password_manager {
namespace {
+constexpr int kNumberOfPasswordAttributes =
+ static_cast<int>(autofill::PasswordAttribute::kPasswordAttributesCount);
+
// Enum that describes what button the user pressed on the save prompt.
enum SavePromptInteraction { SAVE, NEVER, NO_INTERACTION };
+// Creates a form with 2 text fields and 1 password field. The first and second
+// fields are username and password respectively. |observed_form| is used for
+// default values.
+// TODO(crbug.com/824834): The minimal case should be a smaller form.
+PasswordForm CreateMinimalCrowdsourcableForm(
+ const PasswordForm& observed_form) {
+ PasswordForm form = observed_form;
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("email");
+ field.form_control_type = "text";
+ form.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("password");
+ field.form_control_type = "password";
+ form.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("petname");
+ field.form_control_type = "text";
+ form.form_data.fields.push_back(field);
+ form.username_element = ASCIIToUTF16("email");
+ form.password_element = ASCIIToUTF16("password");
+ return form;
+}
+
class MockFormSaver : public StubFormSaver {
public:
MockFormSaver() = default;
@@ -125,38 +154,42 @@ class MockFormFetcher : public FakeFormFetcher {
MOCK_METHOD0(Clone, std::unique_ptr<FormFetcher>());
};
-MATCHER_P(CheckUsername, username_value, "Username incorrect") {
- return arg.username_value == username_value;
+MATCHER_P(UsernamePtrIs, username_value, "") {
+ if (!arg)
+ return false;
+ if (arg->username_value != username_value) {
+ *result_listener << "has username: " << arg->username_value;
+ return false;
+ }
+ return true;
}
-MATCHER_P(CheckUsernamePtr, username_value, "Username incorrect") {
- return arg && arg->username_value == username_value;
-}
+// Matches a FormStructure if its signature is the same as that of the
+// PasswordForm |form|.
+MATCHER_P(SignatureIsSameAs,
+ form,
+ std::string(negation ? "signature isn't " : "signature is ") +
+ autofill::FormStructure(form.form_data).FormSignatureAsStr()) {
+ if (autofill::FormStructure(form.form_data).FormSignatureAsStr() ==
+ arg.FormSignatureAsStr())
+ return true;
-MATCHER_P4(CheckUploadedAutofillTypesAndSignature,
- form_signature,
- expected_types,
- expect_generation_vote,
- expected_username_vote_type,
- "Unexpected autofill types or form signature") {
- if (form_signature != arg.FormSignatureAsStr()) {
- // Unexpected form's signature.
- ADD_FAILURE() << "Expected form signature is " << form_signature
- << ", but found " << arg.FormSignatureAsStr();
- return false;
- }
+ *result_listener << "signature is " << arg.FormSignatureAsStr() << " instead";
+ return false;
+}
- bool found_generation_vote = false;
+MATCHER_P(UploadedAutofillTypesAre, expected_types, "") {
+ size_t fields_matched_type_count = 0;
+ bool conflict_found = false;
for (const auto& field : arg) {
+ fields_matched_type_count +=
+ expected_types.find(field->name) == expected_types.end() ? 0 : 1;
if (field->possible_types().size() > 1) {
- ADD_FAILURE() << field->name << " field has several possible types";
- return false;
+ *result_listener << (conflict_found ? ", " : "") << "Field "
+ << field->name << ": has several possible types";
+ conflict_found = true;
}
- found_generation_vote |=
- field->generation_type() !=
- autofill::AutofillUploadContents::Field::NO_GENERATION;
-
autofill::ServerFieldType expected_vote =
expected_types.find(field->name) == expected_types.end()
? autofill::NO_SERVER_DATA
@@ -165,106 +198,164 @@ MATCHER_P4(CheckUploadedAutofillTypesAndSignature,
field->possible_types().empty() ? autofill::NO_SERVER_DATA
: *field->possible_types().begin();
if (expected_vote != actual_vote) {
- ADD_FAILURE() << field->name << " field: expected vote " << expected_vote
- << ", but found " << actual_vote;
- return false;
+ *result_listener << (conflict_found ? ", " : "") << "Field "
+ << field->name << ": expected vote " << expected_vote
+ << " but found " << actual_vote;
+ conflict_found = true;
}
- if (expected_vote == autofill::USERNAME) {
- if (field->username_vote_type() != expected_username_vote_type) {
- ADD_FAILURE() << field->name
- << " field has expected username vote type "
- << expected_username_vote_type << ", but found "
- << field->username_vote_type();
- }
- } else {
- if (field->username_vote_type() !=
+ }
+ if (expected_types.size() != fields_matched_type_count) {
+ *result_listener << (conflict_found ? ", " : "")
+ << "Some types were expected but not found in the vote";
+ return false;
+ }
+
+ return !conflict_found;
+}
+
+MATCHER_P(HasGenerationVote, expect_generation_vote, "") {
+ bool found_generation_vote = false;
+ for (const auto& field : arg) {
+ if (field->generation_type() !=
+ autofill::AutofillUploadContents::Field::NO_GENERATION) {
+ found_generation_vote = true;
+ break;
+ }
+ }
+ return found_generation_vote == expect_generation_vote;
+}
+
+// Matches if all fields with a vote type are described in |expected_vote_types|
+// and all votes from |expected_vote_types| are found in a field.
+MATCHER_P(VoteTypesAre, expected_vote_types, "") {
+ size_t matched_count = 0;
+ bool conflict_found = false;
+ for (const auto& field : arg) {
+ auto expectation = expected_vote_types.find(field->name);
+ if (expectation == expected_vote_types.end()) {
+ if (field->vote_type() !=
autofill::AutofillUploadContents::Field::NO_INFORMATION) {
- ADD_FAILURE() << field->name
- << " field should not have any username vote type";
+ *result_listener << (conflict_found ? ", " : "") << "field "
+ << field->name << ": unexpected vote type "
+ << field->vote_type();
+ conflict_found = true;
}
+ continue;
+ }
+
+ matched_count++;
+ if (expectation->second != field->vote_type()) {
+ *result_listener << (conflict_found ? ", " : "") << "field "
+ << field->name << ": expected vote type "
+ << expectation->second << " but has "
+ << field->vote_type();
+ conflict_found = true;
}
}
- EXPECT_EQ(expect_generation_vote, found_generation_vote);
- return true;
+ if (expected_vote_types.size() != matched_count) {
+ *result_listener
+ << (conflict_found ? ", " : "")
+ << "some vote types were expected but not found in the vote";
+ conflict_found = true;
+ }
+
+ return !conflict_found;
}
-MATCHER_P3(CheckUploadedGenerationTypesAndSignature,
- form_signature,
+MATCHER_P2(UploadedGenerationTypesAre,
expected_generation_types,
generated_password_changed,
- "Unexpected generation types or form signature") {
- if (form_signature != arg.FormSignatureAsStr()) {
- // Unexpected form's signature.
- ADD_FAILURE() << "Expected form signature is " << form_signature
- << ", but found " << arg.FormSignatureAsStr();
- return false;
- }
+ "") {
for (const auto& field : arg) {
if (expected_generation_types.find(field->name) ==
expected_generation_types.end()) {
if (field->generation_type() !=
autofill::AutofillUploadContents::Field::NO_GENERATION) {
// Unexpected generation type.
- ADD_FAILURE() << "Expected no generation type for the field "
- << field->name << ", but found "
- << field->generation_type();
+ *result_listener << "Expected no generation type for the field "
+ << field->name << ", but found "
+ << field->generation_type();
return false;
}
} else {
if (expected_generation_types.find(field->name)->second !=
field->generation_type()) {
// Wrong generation type.
- ADD_FAILURE() << "Expected generation type for the field "
- << field->name << " is "
- << expected_generation_types.find(field->name)->second
- << ", but found " << field->generation_type();
+ *result_listener << "Expected generation type for the field "
+ << field->name << " is "
+ << expected_generation_types.find(field->name)->second
+ << ", but found " << field->generation_type();
return false;
}
if (field->generation_type() !=
autofill::AutofillUploadContents::Field::IGNORED_GENERATION_POPUP) {
- EXPECT_EQ(generated_password_changed,
- field->generated_password_changed());
+ if (generated_password_changed != field->generated_password_changed())
+ return false;
}
}
}
return true;
}
-MATCHER_P2(CheckUploadedFormClassifierVote,
+MATCHER_P2(UploadedFormClassifierVoteIs,
found_generation_element,
generation_element,
- "Wrong form classifier votes") {
+ "") {
for (const auto& field : arg) {
if (found_generation_element && field->name == generation_element) {
- EXPECT_EQ(field->form_classifier_outcome(),
- autofill::AutofillUploadContents::Field::GENERATION_ELEMENT);
+ if (field->form_classifier_outcome() !=
+ autofill::AutofillUploadContents::Field::GENERATION_ELEMENT)
+ return false;
} else {
- EXPECT_EQ(
- field->form_classifier_outcome(),
- autofill::AutofillUploadContents::Field::NON_GENERATION_ELEMENT);
+ if (field->form_classifier_outcome() !=
+ autofill::AutofillUploadContents::Field::NON_GENERATION_ELEMENT)
+ return false;
}
}
return true;
}
-MATCHER_P(CheckFieldPropertiesMasksUpload,
- expected_field_properties,
- "Wrong field properties flags") {
+MATCHER_P(PasswordsWereRevealed, revealed, "") {
+ return arg.passwords_were_revealed() == revealed;
+}
+
+MATCHER_P(HasPasswordAttributesVote, is_vote_expected, "") {
+ base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote =
+ arg.get_password_attributes_vote_for_testing();
+ EXPECT_EQ(is_vote_expected, vote.has_value());
+ return true;
+}
+
+// Matches iff the masks in |expected_field_properties| match the mask in the
+// uploaded form exactly.
+MATCHER_P(UploadedFieldPropertiesMasksAre, expected_field_properties, "") {
+ size_t matched_count = 0;
+ bool conflict_found = false;
for (const auto& field : arg) {
- autofill::FieldPropertiesMask expected_mask =
- expected_field_properties.find(field->name) !=
- expected_field_properties.end()
- ? FieldPropertiesFlags::USER_TYPED
- : 0;
+ auto expectation = expected_field_properties.find(field->name);
+ if (expectation == expected_field_properties.end())
+ continue;
+
+ matched_count++;
+ autofill::FieldPropertiesMask expected_mask = expectation->second;
+
if (field->properties_mask != expected_mask) {
- ADD_FAILURE() << "Wrong field properties flags for field " << field->name
- << ": expected mask " << expected_mask << ", but found "
- << field->properties_mask;
- return false;
+ *result_listener << (conflict_found ? ", " : "") << field->name
+ << " field: expected mask " << expected_mask
+ << ", but found " << field->properties_mask;
+ conflict_found = true;
}
}
- return true;
+
+ if (matched_count != expected_field_properties.size()) {
+ *result_listener
+ << (conflict_found ? ", " : "")
+ << "some expectations did not correspond to an uploaded field";
+ conflict_found = true;
+ }
+
+ return !conflict_found;
}
class MockAutofillDownloadManager : public autofill::AutofillDownloadManager {
@@ -297,15 +388,16 @@ class MockAutofillManager : public autofill::AutofillManager {
}
// Workaround for std::unique_ptr<> lacking a copy constructor.
- bool StartUploadProcess(std::unique_ptr<FormStructure> form_structure,
- const base::TimeTicks& timestamp,
- bool observed_submission) {
- StartUploadProcessPtr(form_structure.release(), timestamp,
- observed_submission);
+ bool MaybeStartVoteUploadProcess(
+ std::unique_ptr<FormStructure> form_structure,
+ const base::TimeTicks& timestamp,
+ bool observed_submission) override {
+ MaybeStartVoteUploadProcessPtr(form_structure.release(), timestamp,
+ observed_submission);
return true;
}
- MOCK_METHOD3(StartUploadProcessPtr,
+ MOCK_METHOD3(MaybeStartVoteUploadProcessPtr,
void(FormStructure*, const base::TimeTicks&, bool));
private:
@@ -329,7 +421,7 @@ class MockPasswordManagerDriver : public StubPasswordManagerDriver {
mock_autofill_manager_.SetDownloadManager(mock_autofill_download_manager_);
}
- ~MockPasswordManagerDriver() {}
+ ~MockPasswordManagerDriver() override {}
MOCK_METHOD1(FillPasswordForm, void(const autofill::PasswordFormFillData&));
MOCK_METHOD0(InformNoSavedCredentials, void());
@@ -414,6 +506,9 @@ class PasswordFormManagerTest : public testing::Test {
saved_match_.password_value = ASCIIToUTF16("test1");
saved_match_.other_possible_usernames.push_back(ValueElementPair(
ASCIIToUTF16("test2@gmail.com"), ASCIIToUTF16("full_name")));
+ saved_match_.all_possible_passwords = {
+ {ASCIIToUTF16("password"), base::string16()},
+ {ASCIIToUTF16("password"), ASCIIToUTF16("Passwd")}};
autofill::FormFieldData field;
field.label = ASCIIToUTF16("Full name");
@@ -489,17 +584,15 @@ class PasswordFormManagerTest : public testing::Test {
// When we're voting for an account creation form, we should also vote
// for its username field.
+ bool expect_username_vote = false;
if (field_type && *field_type == autofill::ACCOUNT_CREATION_PASSWORD) {
expected_types[match.username_element] = autofill::USERNAME;
expected_available_field_types.insert(autofill::USERNAME);
+ expect_username_vote = true;
} else {
expected_types[match.username_element] = autofill::UNKNOWN_TYPE;
}
- autofill::AutofillUploadContents::Field::UsernameVoteType
- expected_username_vote_type =
- autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED;
-
bool expect_generation_vote = false;
if (field_type) {
// Show the password generation popup to check that the generation vote
@@ -514,20 +607,35 @@ class PasswordFormManagerTest : public testing::Test {
}
if (field_type) {
- EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignatureAsStr(),
- expected_types, expect_generation_vote,
- expected_username_vote_type),
- false, expected_available_field_types,
- expected_login_signature, true));
+ if (expect_username_vote) {
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(AllOf(SignatureIsSameAs(*saved_match()),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(expect_generation_vote),
+ VoteTypesAre(VoteTypeMap(
+ {{match.username_element,
+ autofill::AutofillUploadContents::
+ Field::CREDENTIALS_REUSED}})),
+ HasPasswordAttributesVote(false)),
+ false, expected_available_field_types,
+ expected_login_signature, true));
+ } else {
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(AllOf(SignatureIsSameAs(*saved_match()),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(expect_generation_vote),
+ HasPasswordAttributesVote(false)),
+ false, expected_available_field_types,
+ expected_login_signature, true));
+ }
} else {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, _, _, _, _))
.Times(0);
}
- form_manager.ProvisionallySave(
- form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(form_to_save);
form_manager.Save();
Mock::VerifyAndClearExpectations(
client()->mock_driver()->mock_autofill_download_manager());
@@ -576,8 +684,7 @@ class PasswordFormManagerTest : public testing::Test {
if (has_confirmation_field)
submitted_form.confirmation_password_element = ASCIIToUTF16("ConfPwd");
submitted_form.preferred = true;
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to update.
@@ -589,8 +696,9 @@ class PasswordFormManagerTest : public testing::Test {
// value already to be the current password, and should no longer maintain
// any info about the new password value.
EXPECT_EQ(submitted_form.new_password_value,
- form_manager.pending_credentials().password_value);
- EXPECT_TRUE(form_manager.pending_credentials().new_password_value.empty());
+ form_manager.GetPendingCredentials().password_value);
+ EXPECT_TRUE(
+ form_manager.GetPendingCredentials().new_password_value.empty());
std::map<base::string16, autofill::ServerFieldType> expected_types;
expected_types[ASCIIToUTF16("full_name")] = autofill::UNKNOWN_TYPE;
@@ -608,24 +716,24 @@ class PasswordFormManagerTest : public testing::Test {
expected_available_field_types.insert(autofill::CONFIRMATION_PASSWORD);
}
- std::string observed_form_signature =
- autofill::FormStructure(observed_form()->form_data)
- .FormSignatureAsStr();
-
std::string expected_login_signature;
if (field_type == autofill::NEW_PASSWORD) {
autofill::FormStructure pending_structure(saved_match()->form_data);
expected_login_signature = pending_structure.FormSignatureAsStr();
+
+ // An unrelated vote that the credentials were used for the first time.
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(submitted_form), _, _, _, _));
}
- EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- observed_form_signature, expected_types,
- false /* expect_generation_vote */,
- autofill::AutofillUploadContents::Field::NO_INFORMATION
- /* expected_username_vote_type */),
- false, expected_available_field_types,
- expected_login_signature, true));
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(*observed_form()),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(false), HasPasswordAttributesVote(false)),
+ false, expected_available_field_types, expected_login_signature,
+ true));
switch (field_type) {
case autofill::NEW_PASSWORD:
@@ -743,18 +851,16 @@ class PasswordFormManagerTest : public testing::Test {
expected_generation_types;
expected_generation_types[generation_element] = expected_generation_type;
- autofill::FormStructure form_structure(submitted_form.form_data);
-
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
- CheckUploadedGenerationTypesAndSignature(
- form_structure.FormSignatureAsStr(), expected_generation_types,
- generated_password_changed),
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedGenerationTypesAre(expected_generation_types,
+ generated_password_changed)),
false, expected_available_field_types, std::string(), true));
+ base::HistogramTester histogram_tester;
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
switch (interaction) {
case SAVE:
form_manager.Save();
@@ -766,6 +872,11 @@ class PasswordFormManagerTest : public testing::Test {
form_manager.OnNoInteraction(false /* not an update prompt*/);
break;
}
+ if (has_generated_password) {
+ histogram_tester.ExpectUniqueSample(
+ "PasswordGeneration.GeneratedPasswordWasEdited",
+ generated_password_changed /* sample */, 1);
+ }
Mock::VerifyAndClearExpectations(
client()->mock_driver()->mock_autofill_download_manager());
}
@@ -866,8 +977,7 @@ class PasswordFormManagerTest : public testing::Test {
submitted_password ? base::ASCIIToUTF16(submitted_password)
: base::ASCIIToUTF16(filled_password);
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
if (submit_result == SimulatedSubmitResult::PASSED) {
form_manager.LogSubmitPassed();
form_manager.Save();
@@ -911,8 +1021,7 @@ TEST_F(PasswordFormManagerTest, TestNewLogin) {
credentials.username_value = saved_match()->username_value;
credentials.password_value = saved_match()->password_value;
credentials.preferred = true;
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, which should know this is a new login.
@@ -920,19 +1029,20 @@ TEST_F(PasswordFormManagerTest, TestNewLogin) {
// Make sure the credentials that would be submitted on successful login
// are going to match the stored entry in the db.
EXPECT_EQ(observed_form()->origin.spec(),
- form_manager()->pending_credentials().origin.spec());
+ form_manager()->GetPendingCredentials().origin.spec());
EXPECT_EQ(observed_form()->signon_realm,
- form_manager()->pending_credentials().signon_realm);
+ form_manager()->GetPendingCredentials().signon_realm);
EXPECT_EQ(observed_form()->action,
- form_manager()->pending_credentials().action);
- EXPECT_TRUE(form_manager()->pending_credentials().preferred);
+ form_manager()->GetPendingCredentials().action);
+ EXPECT_TRUE(form_manager()->GetPendingCredentials().preferred);
EXPECT_EQ(saved_match()->password_value,
- form_manager()->pending_credentials().password_value);
+ form_manager()->GetPendingCredentials().password_value);
EXPECT_EQ(saved_match()->username_value,
- form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().username_value);
EXPECT_TRUE(
- form_manager()->pending_credentials().new_password_element.empty());
- EXPECT_TRUE(form_manager()->pending_credentials().new_password_value.empty());
+ form_manager()->GetPendingCredentials().new_password_element.empty());
+ EXPECT_TRUE(
+ form_manager()->GetPendingCredentials().new_password_value.empty());
}
// Test provisionally saving a new login in presence of other saved logins.
@@ -948,22 +1058,22 @@ TEST_F(PasswordFormManagerTest, TestAdditionalLogin) {
new_login.password_value = new_pass;
new_login.preferred = true;
- form_manager()->ProvisionallySave(
- new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(new_login);
// The username value differs from the saved match, so this is a new login.
EXPECT_TRUE(form_manager()->IsNewLogin());
EXPECT_EQ(observed_form()->origin.spec(),
- form_manager()->pending_credentials().origin.spec());
+ form_manager()->GetPendingCredentials().origin.spec());
EXPECT_EQ(observed_form()->signon_realm,
- form_manager()->pending_credentials().signon_realm);
- EXPECT_TRUE(form_manager()->pending_credentials().preferred);
- EXPECT_EQ(new_pass, form_manager()->pending_credentials().password_value);
- EXPECT_EQ(new_user, form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().signon_realm);
+ EXPECT_TRUE(form_manager()->GetPendingCredentials().preferred);
+ EXPECT_EQ(new_pass, form_manager()->GetPendingCredentials().password_value);
+ EXPECT_EQ(new_user, form_manager()->GetPendingCredentials().username_value);
+ EXPECT_TRUE(
+ form_manager()->GetPendingCredentials().new_password_element.empty());
EXPECT_TRUE(
- form_manager()->pending_credentials().new_password_element.empty());
- EXPECT_TRUE(form_manager()->pending_credentials().new_password_value.empty());
+ form_manager()->GetPendingCredentials().new_password_value.empty());
}
// Test blacklisting in the presence of saved results.
@@ -976,27 +1086,26 @@ TEST_F(PasswordFormManagerTest, TestBlacklist) {
new_login.username_value = ASCIIToUTF16("newuser");
new_login.password_value = ASCIIToUTF16("newpass");
// Pretend Chrome detected a form submission with |new_login|.
- form_manager()->ProvisionallySave(
- new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(new_login);
EXPECT_TRUE(form_manager()->IsNewLogin());
EXPECT_EQ(observed_form()->origin.spec(),
- form_manager()->pending_credentials().origin.spec());
+ form_manager()->GetPendingCredentials().origin.spec());
EXPECT_EQ(observed_form()->signon_realm,
- form_manager()->pending_credentials().signon_realm);
+ form_manager()->GetPendingCredentials().signon_realm);
- const PasswordForm pending_form = form_manager()->pending_credentials();
+ const PasswordForm pending_form = form_manager()->GetPendingCredentials();
PasswordForm actual_add_form;
// Now pretend the user wants to never save passwords on this origin. Chrome
// is supposed to only request blacklisting of a single form.
EXPECT_CALL(MockFormSaver::Get(form_manager()), PermanentlyBlacklist(_))
.WillOnce(SaveArgPointee<0>(&actual_add_form));
form_manager()->PermanentlyBlacklist();
- EXPECT_EQ(pending_form, form_manager()->pending_credentials());
+ EXPECT_EQ(pending_form, form_manager()->GetPendingCredentials());
// The PasswordFormManager should have updated its knowledge of blacklisting
// without waiting for PasswordStore updates.
EXPECT_TRUE(form_manager()->IsBlacklisted());
- EXPECT_THAT(form_manager()->blacklisted_matches(),
+ EXPECT_THAT(form_manager()->GetBlacklistedMatches(),
UnorderedElementsAre(Pointee(actual_add_form)));
}
@@ -1028,10 +1137,10 @@ TEST_F(PasswordFormManagerTest, TestBlacklistMatching) {
fake_form_fetcher()->SetNonFederated(matches, 0u);
EXPECT_TRUE(form_manager()->IsBlacklisted());
- EXPECT_THAT(form_manager()->blacklisted_matches(),
+ EXPECT_THAT(form_manager()->GetBlacklistedMatches(),
ElementsAre(Pointee(blacklisted_match)));
- EXPECT_EQ(1u, form_manager()->best_matches().size());
- EXPECT_EQ(*saved_match(), *form_manager()->preferred_match());
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
+ EXPECT_EQ(*saved_match(), *form_manager()->GetPreferredMatch());
}
// Test that even in the presence of blacklisted matches, the non-blacklisted
@@ -1050,9 +1159,9 @@ TEST_F(PasswordFormManagerTest, AutofillBlacklisted) {
.WillOnce(SaveArg<0>(&fill_data));
fake_form_fetcher()->SetNonFederated({&saved_form, &blacklisted}, 0u);
- EXPECT_EQ(1u, form_manager()->blacklisted_matches().size());
+ EXPECT_EQ(1u, form_manager()->GetBlacklistedMatches().size());
EXPECT_TRUE(form_manager()->IsBlacklisted());
- EXPECT_EQ(1u, form_manager()->best_matches().size());
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
EXPECT_TRUE(fill_data.additional_logins.empty());
}
@@ -1070,8 +1179,7 @@ TEST_F(PasswordFormManagerTest,
credentials.username_value = saved_match()->username_value;
credentials.password_value =
saved_match()->password_value + ASCIIToUTF16("modify");
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
EXPECT_TRUE(form_manager()->IsNewLogin());
EXPECT_FALSE(form_manager()->IsPendingCredentialsPublicSuffixMatch());
@@ -1088,8 +1196,7 @@ TEST_F(PasswordFormManagerTest, PSLMatchedCredentialsMetadataUpdated) {
submitted_form.preferred = true;
submitted_form.username_value = saved_match()->username_value;
submitted_form.password_value = saved_match()->password_value;
- form_manager()->ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(submitted_form);
PasswordForm expected_saved_form(submitted_form);
expected_saved_form.times_used = 1;
@@ -1134,28 +1241,28 @@ TEST_F(PasswordFormManagerTest, TestNewLoginFromNewPasswordElement) {
credentials.password_value = ASCIIToUTF16("oldpassword");
credentials.new_password_value = ASCIIToUTF16("newpassword");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, which should know this is a new login.
EXPECT_TRUE(form_manager.IsNewLogin());
- EXPECT_EQ(credentials.origin, form_manager.pending_credentials().origin);
+ EXPECT_EQ(credentials.origin, form_manager.GetPendingCredentials().origin);
EXPECT_EQ(credentials.signon_realm,
- form_manager.pending_credentials().signon_realm);
- EXPECT_EQ(credentials.action, form_manager.pending_credentials().action);
- EXPECT_TRUE(form_manager.pending_credentials().preferred);
+ form_manager.GetPendingCredentials().signon_realm);
+ EXPECT_EQ(credentials.action, form_manager.GetPendingCredentials().action);
+ EXPECT_TRUE(form_manager.GetPendingCredentials().preferred);
EXPECT_EQ(credentials.username_value,
- form_manager.pending_credentials().username_value);
+ form_manager.GetPendingCredentials().username_value);
// By this point, the PasswordFormManager should have promoted the new
- // password value to be the current password, and should have wiped the
- // password element name: it is likely going to be different on a login
- // form, so it is not worth remembering them.
+ // password value to be the current password.
EXPECT_EQ(credentials.new_password_value,
- form_manager.pending_credentials().password_value);
- EXPECT_TRUE(form_manager.pending_credentials().password_element.empty());
- EXPECT_TRUE(form_manager.pending_credentials().new_password_value.empty());
+ form_manager.GetPendingCredentials().password_value);
+ EXPECT_EQ(credentials.new_password_element,
+ form_manager.GetPendingCredentials().password_element);
+ EXPECT_TRUE(form_manager.GetPendingCredentials().new_password_value.empty());
+ EXPECT_TRUE(
+ form_manager.GetPendingCredentials().new_password_element.empty());
}
TEST_F(PasswordFormManagerTest, TestUpdatePassword) {
@@ -1171,8 +1278,7 @@ TEST_F(PasswordFormManagerTest, TestUpdatePassword) {
credentials.username_value = saved_match()->username_value;
credentials.password_value = new_pass;
credentials.preferred = true;
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -1182,12 +1288,12 @@ TEST_F(PasswordFormManagerTest, TestUpdatePassword) {
// Make sure the credentials that would be submitted on successful login
// are going to match the stored entry in the db. (This verifies correct
// behaviour for bug 1074420).
- EXPECT_EQ(form_manager()->pending_credentials().origin.spec(),
+ EXPECT_EQ(form_manager()->GetPendingCredentials().origin.spec(),
saved_match()->origin.spec());
- EXPECT_EQ(form_manager()->pending_credentials().signon_realm,
+ EXPECT_EQ(form_manager()->GetPendingCredentials().signon_realm,
saved_match()->signon_realm);
- EXPECT_TRUE(form_manager()->pending_credentials().preferred);
- EXPECT_EQ(new_pass, form_manager()->pending_credentials().password_value);
+ EXPECT_TRUE(form_manager()->GetPendingCredentials().preferred);
+ EXPECT_EQ(new_pass, form_manager()->GetPendingCredentials().password_value);
}
TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
@@ -1195,15 +1301,6 @@ TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
// save the password from this field, instead of the current password field.
observed_form()->new_password_element = ASCIIToUTF16("NewPasswd");
- // Given that |observed_form| was most likely a change password form, it
- // should not serve as a source for updating meta-information stored with the
- // old credentials, such as element names, as they are likely going to be
- // different between change password and login forms. To test this in depth,
- // forcibly wipe |submit_element|, which should normally trigger updating
- // this field from |observed_form| during updating as a special case. We will
- // verify in the end that this did not happen.
- saved_match()->submit_element.clear();
-
FakeFormFetcher fetcher;
fetcher.Fetch();
PasswordFormManager form_manager(password_manager(), client(),
@@ -1218,8 +1315,7 @@ TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
credentials.password_value = saved_match()->password_value;
credentials.new_password_value = ASCIIToUTF16("test2");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -1230,9 +1326,10 @@ TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
// already to be the current password, and should no longer maintain any info
// about the new password.
EXPECT_EQ(credentials.new_password_value,
- form_manager.pending_credentials().password_value);
- EXPECT_TRUE(form_manager.pending_credentials().new_password_element.empty());
- EXPECT_TRUE(form_manager.pending_credentials().new_password_value.empty());
+ form_manager.GetPendingCredentials().password_value);
+ EXPECT_TRUE(
+ form_manager.GetPendingCredentials().new_password_element.empty());
+ EXPECT_TRUE(form_manager.GetPendingCredentials().new_password_value.empty());
// Trigger saving to exercise some special case handling for updating.
PasswordForm new_credentials;
@@ -1241,7 +1338,7 @@ TEST_F(PasswordFormManagerTest, TestUpdatePasswordFromNewPasswordElement) {
form_manager.Save();
- // No meta-information should be updated, only the password.
+ // The password should be updated.
EXPECT_EQ(credentials.new_password_value, new_credentials.password_value);
EXPECT_EQ(saved_match()->username_element, new_credentials.username_element);
EXPECT_EQ(saved_match()->password_element, new_credentials.password_element);
@@ -1269,8 +1366,8 @@ TEST_F(PasswordFormManagerTest, TestIgnoreResult_Paths) {
fetcher.SetNonFederated({&saved_form}, 0u);
// Different paths for action / origin are okay.
- EXPECT_EQ(1u, form_manager.best_matches().size());
- EXPECT_EQ(*form_manager.best_matches().begin()->second, saved_form);
+ EXPECT_EQ(1u, form_manager.GetBestMatches().size());
+ EXPECT_EQ(*form_manager.GetBestMatches().begin()->second, saved_form);
}
// Test that saved empty action URL is updated with the submitted action URL.
@@ -1282,13 +1379,12 @@ TEST_F(PasswordFormManagerTest, TestEmptyAction) {
PasswordForm login = *observed_form();
login.username_value = saved_match()->username_value;
login.password_value = saved_match()->password_value;
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(login);
EXPECT_FALSE(form_manager()->IsNewLogin());
// Chrome updates the saved PasswordForm entry with the action URL of the
// observed form.
EXPECT_EQ(observed_form()->action,
- form_manager()->pending_credentials().action);
+ form_manager()->GetPendingCredentials().action);
}
TEST_F(PasswordFormManagerTest, TestUpdateAction) {
@@ -1301,14 +1397,13 @@ TEST_F(PasswordFormManagerTest, TestUpdateAction) {
login.username_value = saved_match()->username_value;
login.password_value = saved_match()->password_value;
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(login);
EXPECT_FALSE(form_manager()->IsNewLogin());
// The observed action URL is different from the previously saved one. Chrome
// should update the store by setting the pending credential's action URL to
// be that of the currently observed form.
EXPECT_EQ(observed_form()->action,
- form_manager()->pending_credentials().action);
+ form_manager()->GetPendingCredentials().action);
}
TEST_F(PasswordFormManagerTest, TestDynamicAction) {
@@ -1319,12 +1414,11 @@ TEST_F(PasswordFormManagerTest, TestDynamicAction) {
// The submitted action URL is different from the one observed on page load.
login.action = GURL("http://www.google.com/new_action");
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(login);
EXPECT_TRUE(form_manager()->IsNewLogin());
// Check that the provisionally saved action URL is the same as the submitted
// action URL, not the one observed on page load.
- EXPECT_EQ(login.action, form_manager()->pending_credentials().action);
+ EXPECT_EQ(login.action, form_manager()->GetPendingCredentials().action);
}
// Test that if the saved match has other possible usernames stored, and the
@@ -1346,8 +1440,7 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_NoChange) {
login.username_value = saved_match()->username_value;
login.password_value = saved_match()->password_value;
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(login);
EXPECT_FALSE(form_manager()->IsNewLogin());
@@ -1364,45 +1457,6 @@ TEST_F(PasswordFormManagerTest, TestAlternateUsername_NoChange) {
EXPECT_TRUE(saved_result.other_possible_usernames.empty());
}
-// Test that if the saved match has other possible usernames stored, and the
-// user chooses an alternative one, then the other possible usernames are
-// dropped on update, but the main username is changed to the one chosen by the
-// user.
-TEST_F(PasswordFormManagerTest, TestAlternateUsername_OtherUsername) {
- EXPECT_CALL(*client()->mock_driver(), AllowPasswordGenerationForForm(_));
-
- const ValueElementPair kOtherUsername(
- ASCIIToUTF16("other_possible@gmail.com"), ASCIIToUTF16("other_username"));
- PasswordForm saved_form = *saved_match();
- saved_form.other_possible_usernames.push_back(kOtherUsername);
-
- fake_form_fetcher()->SetNonFederated({&saved_form}, 0u);
-
- // The user chooses an alternative username.
- PasswordForm login(*observed_form());
- login.preferred = true;
- login.username_value = kOtherUsername.first;
- login.password_value = saved_match()->password_value;
-
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
-
- EXPECT_FALSE(form_manager()->IsNewLogin());
-
- PasswordForm saved_result;
- // Changing the username changes the primary key of the stored credential.
- EXPECT_CALL(MockFormSaver::Get(form_manager()),
- Update(_, _, _, CheckUsernamePtr(saved_form.username_value)))
- .WillOnce(SaveArg<0>(&saved_result));
-
- form_manager()->Save();
-
- // |other_possible_usernames| should also be empty, but username_value should
- // be changed to match |new_username|.
- EXPECT_EQ(kOtherUsername.first, saved_result.username_value);
- EXPECT_TRUE(saved_result.other_possible_usernames.empty());
-}
-
TEST_F(PasswordFormManagerTest, TestSendNotBlacklistedMessage_NoCredentials) {
// First time sign-up attempt. Password store does not contain matching
// credentials. AllowPasswordGenerationForForm should be called to send the
@@ -1487,7 +1541,7 @@ TEST_F(PasswordFormManagerTest, TestBestCredentialsForEachUsernameAreIncluded) {
0u);
const std::map<base::string16, const PasswordForm*>& best_matches =
- form_manager()->best_matches();
+ form_manager()->GetBestMatches();
EXPECT_EQ(3u, best_matches.size());
EXPECT_NE(best_matches.end(),
best_matches.find(saved_match()->username_value));
@@ -1496,7 +1550,7 @@ TEST_F(PasswordFormManagerTest, TestBestCredentialsForEachUsernameAreIncluded) {
EXPECT_NE(best_matches.end(), best_matches.find(kUsername1));
EXPECT_NE(best_matches.end(), best_matches.find(kUsername2));
- EXPECT_EQ(*saved_match(), *form_manager()->preferred_match());
+ EXPECT_EQ(*saved_match(), *form_manager()->GetPreferredMatch());
EXPECT_EQ(2u, fill_data.additional_logins.size());
}
@@ -1515,10 +1569,7 @@ TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernames) {
credentials.username_value = ASCIIToUTF16("test@gmail.com");
credentials.preferred = true;
- // Pass in ALLOW_OTHER_POSSIBLE_USERNAMES, although it will not make a
- // difference as no matches coming from the password store were autofilled.
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
PasswordForm saved_result;
EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _))
@@ -1551,10 +1602,7 @@ TEST_F(PasswordFormManagerTest, TestSanitizePossibleUsernamesDuplicates) {
credentials.username_value = kUsernameEmail.first;
credentials.preferred = true;
- // Pass in ALLOW_OTHER_POSSIBLE_USERNAMES, although it will not make a
- // difference as no matches coming from the password store were autofilled.
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
PasswordForm saved_result;
EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, _))
@@ -1579,10 +1627,9 @@ TEST_F(PasswordFormManagerTest, TestAllPossiblePasswords) {
credentials.all_possible_passwords.push_back(pair2);
credentials.all_possible_passwords.push_back(pair3);
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
- EXPECT_THAT(form_manager()->pending_credentials().all_possible_passwords,
+ EXPECT_THAT(form_manager()->GetPendingCredentials().all_possible_passwords,
UnorderedElementsAre(pair1, pair2, pair3));
}
@@ -1630,8 +1677,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateIncompleteCredentials) {
// Feed the incomplete credentials to the manager.
fetcher.SetNonFederated({&incomplete_form}, 0u);
- form_manager.ProvisionallySave(
- complete_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(complete_form);
// By now that form has been used once.
complete_form.times_used = 1;
obsolete_form.times_used = 1;
@@ -1665,9 +1711,9 @@ TEST_F(PasswordFormManagerTest, TestScoringPublicSuffixMatch) {
fake_form_fetcher()->SetNonFederated({&psl_match, &same_origin_match}, 0u);
EXPECT_TRUE(fill_data.additional_logins.empty());
- EXPECT_EQ(1u, form_manager()->best_matches().size());
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
EXPECT_FALSE(
- form_manager()->best_matches().begin()->second->is_public_suffix_match);
+ form_manager()->GetBestMatches().begin()->second->is_public_suffix_match);
}
TEST_F(PasswordFormManagerTest, AndroidCredentialsAreAutofilled) {
@@ -1692,7 +1738,7 @@ TEST_F(PasswordFormManagerTest, AndroidCredentialsAreAutofilled) {
fake_form_fetcher()->SetNonFederated({&android_login}, 0u);
EXPECT_TRUE(fill_data.additional_logins.empty());
EXPECT_FALSE(fill_data.wait_for_username);
- EXPECT_EQ(1u, form_manager()->best_matches().size());
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
// When the user submits the filled form, no copy of the credential should be
// created, instead the usage counter of the original credential should be
@@ -1701,8 +1747,7 @@ TEST_F(PasswordFormManagerTest, AndroidCredentialsAreAutofilled) {
credential.username_value = android_login.username_value;
credential.password_value = android_login.password_value;
credential.preferred = true;
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credential);
EXPECT_FALSE(form_manager()->IsNewLogin());
PasswordForm updated_credential;
@@ -1763,7 +1808,7 @@ TEST_F(PasswordFormManagerTest, AndroidCredentialsAreProtected) {
EXPECT_EQ(1u, fill_data.additional_logins.size());
std::vector<std::unique_ptr<PasswordForm>> actual_matches;
- for (const auto& username_match_pair : form_manager()->best_matches())
+ for (const auto& username_match_pair : form_manager()->GetBestMatches())
actual_matches.push_back(
std::make_unique<PasswordForm>(*username_match_pair.second));
EXPECT_THAT(actual_matches,
@@ -1945,14 +1990,13 @@ TEST_F(PasswordFormManagerTest, CorrectlyUpdatePasswordsWithSameUsername) {
// |first| scored slightly higher.
EXPECT_EQ(ASCIIToUTF16("first"),
- form_manager()->preferred_match()->password_value);
+ form_manager()->GetPreferredMatch()->password_value);
PasswordForm login(*observed_form());
login.username_value = saved_match()->username_value;
login.password_value = ASCIIToUTF16("third");
login.preferred = true;
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(login);
EXPECT_FALSE(form_manager()->IsNewLogin());
@@ -1999,8 +2043,7 @@ TEST_F(PasswordFormManagerTest, UploadFormData_NewPassword) {
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, false, expected_available_field_types, _, true));
- form_manager.ProvisionallySave(
- form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(form_to_save);
form_manager.Save();
}
@@ -2071,8 +2114,7 @@ TEST_F(PasswordFormManagerTest, CorrectlySavePasswordWithoutUsernameFields) {
login.password_value = ASCIIToUTF16("password");
login.preferred = true;
- form_manager()->ProvisionallySave(
- login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(login);
EXPECT_TRUE(form_manager()->IsNewLogin());
@@ -2117,7 +2159,7 @@ TEST_F(PasswordFormManagerTest, DriverDeletedBeforeStoreDone) {
}
TEST_F(PasswordFormManagerTest, PreferredMatchIsUpToDate) {
- // Check that preferred_match() is always a member of best_matches().
+ // Check that GetPreferredMatch() is always a member of GetBestMatches().
PasswordForm form = *observed_form();
form.username_value = ASCIIToUTF16("username");
form.password_value = ASCIIToUTF16("password1");
@@ -2130,17 +2172,17 @@ TEST_F(PasswordFormManagerTest, PreferredMatchIsUpToDate) {
fake_form_fetcher()->SetNonFederated({&form, &generated_form}, 0u);
- EXPECT_EQ(1u, form_manager()->best_matches().size());
- EXPECT_EQ(form_manager()->preferred_match(),
- form_manager()->best_matches().begin()->second);
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
+ EXPECT_EQ(form_manager()->GetPreferredMatch(),
+ form_manager()->GetBestMatches().begin()->second);
// Make sure to access all fields of preferred_match; this way if it was
// deleted, ASAN might notice it.
- PasswordForm dummy(*form_manager()->preferred_match());
+ PasswordForm dummy(*form_manager()->GetPreferredMatch());
}
TEST_F(PasswordFormManagerTest, PasswordToSave_NoElements) {
PasswordForm form;
- EXPECT_TRUE(PasswordFormManager::PasswordToSave(form).empty());
+ EXPECT_TRUE(PasswordFormManager::PasswordToSave(form).first.empty());
}
TEST_F(PasswordFormManagerTest, PasswordToSave_NoNewElement) {
@@ -2148,7 +2190,7 @@ TEST_F(PasswordFormManagerTest, PasswordToSave_NoNewElement) {
form.password_element = base::ASCIIToUTF16("pwd");
base::string16 kValue = base::ASCIIToUTF16("val");
form.password_value = kValue;
- EXPECT_EQ(kValue, PasswordFormManager::PasswordToSave(form));
+ EXPECT_EQ(kValue, PasswordFormManager::PasswordToSave(form).first);
}
TEST_F(PasswordFormManagerTest, PasswordToSave_NoOldElement) {
@@ -2156,7 +2198,7 @@ TEST_F(PasswordFormManagerTest, PasswordToSave_NoOldElement) {
form.new_password_element = base::ASCIIToUTF16("new_pwd");
base::string16 kNewValue = base::ASCIIToUTF16("new_val");
form.new_password_value = kNewValue;
- EXPECT_EQ(kNewValue, PasswordFormManager::PasswordToSave(form));
+ EXPECT_EQ(kNewValue, PasswordFormManager::PasswordToSave(form).first);
}
TEST_F(PasswordFormManagerTest, PasswordToSave_BothButNoNewValue) {
@@ -2165,7 +2207,7 @@ TEST_F(PasswordFormManagerTest, PasswordToSave_BothButNoNewValue) {
form.new_password_element = base::ASCIIToUTF16("new_pwd");
base::string16 kValue = base::ASCIIToUTF16("val");
form.password_value = kValue;
- EXPECT_EQ(kValue, PasswordFormManager::PasswordToSave(form));
+ EXPECT_EQ(kValue, PasswordFormManager::PasswordToSave(form).first);
}
TEST_F(PasswordFormManagerTest, PasswordToSave_NewValue) {
@@ -2175,7 +2217,7 @@ TEST_F(PasswordFormManagerTest, PasswordToSave_NewValue) {
form.password_value = base::ASCIIToUTF16("val");
base::string16 kNewValue = base::ASCIIToUTF16("new_val");
form.new_password_value = kNewValue;
- EXPECT_EQ(kNewValue, PasswordFormManager::PasswordToSave(form));
+ EXPECT_EQ(kNewValue, PasswordFormManager::PasswordToSave(form).first);
}
TEST_F(PasswordFormManagerTest, TestSuggestingPasswordChangeForms) {
@@ -2198,7 +2240,7 @@ TEST_F(PasswordFormManagerTest, TestSuggestingPasswordChangeForms) {
PasswordForm result = CreateSavedMatch(false);
fetcher.SetNonFederated({&result}, 0u);
- EXPECT_EQ(1u, manager_creds.best_matches().size());
+ EXPECT_EQ(1u, manager_creds.GetBestMatches().size());
EXPECT_EQ(0u, fill_data.additional_logins.size());
EXPECT_TRUE(fill_data.wait_for_username);
}
@@ -2213,15 +2255,6 @@ TEST_F(PasswordFormManagerTest, TestUpdateMethod) {
field.form_control_type = "password";
observed_form()->form_data.fields.push_back(field);
- // Given that |observed_form| was most likely a change password form, it
- // should not serve as a source for updating meta-information stored with the
- // old credentials, such as element names, as they are likely going to be
- // different between change password and login forms. To test this in depth,
- // forcibly wipe |submit_element|, which should normally trigger updating
- // this field from |observed_form| during updating as a special case. We will
- // verify in the end that this did not happen.
- saved_match()->submit_element.clear();
-
FakeFormFetcher fetcher;
fetcher.Fetch();
PasswordFormManager form_manager(password_manager(), client(),
@@ -2236,8 +2269,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateMethod) {
credentials.password_value = saved_match()->password_value;
credentials.new_password_value = ASCIIToUTF16("test2");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -2250,8 +2282,8 @@ TEST_F(PasswordFormManagerTest, TestUpdateMethod) {
// already to be the current password, and should no longer maintain any info
// about the new password value.
EXPECT_EQ(credentials.new_password_value,
- form_manager.pending_credentials().password_value);
- EXPECT_TRUE(form_manager.pending_credentials().new_password_value.empty());
+ form_manager.GetPendingCredentials().password_value);
+ EXPECT_TRUE(form_manager.GetPendingCredentials().new_password_value.empty());
// Trigger saving to exercise some special case handling during updating.
PasswordForm new_credentials;
@@ -2260,7 +2292,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateMethod) {
form_manager.Update(*saved_match());
- // No meta-information should be updated, only the password.
+ // The password is updated.
EXPECT_EQ(credentials.new_password_value, new_credentials.password_value);
EXPECT_EQ(saved_match()->username_element, new_credentials.username_element);
EXPECT_EQ(saved_match()->password_element, new_credentials.password_element);
@@ -2278,15 +2310,6 @@ TEST_F(PasswordFormManagerTest, TestUpdateNoUsernameTextfieldPresent) {
field.form_control_type = "password";
observed_form()->form_data.fields.push_back(field);
- // Given that |observed_form| was most likely a change password form, it
- // should not serve as a source for updating meta-information stored with the
- // old credentials, such as element names, as they are likely going to be
- // different between change password and login forms. To test this in depth,
- // forcibly wipe |submit_element|, which should normally trigger updating this
- // field from |observed_form| during updating as a special case. We
- // will verify in the end that this did not happen.
- saved_match()->submit_element.clear();
-
FakeFormFetcher fetcher;
fetcher.Fetch();
PasswordFormManager form_manager(password_manager(), client(),
@@ -2302,8 +2325,7 @@ TEST_F(PasswordFormManagerTest, TestUpdateNoUsernameTextfieldPresent) {
credentials.password_value = saved_match()->password_value;
credentials.new_password_value = ASCIIToUTF16("test2");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -2315,20 +2337,19 @@ TEST_F(PasswordFormManagerTest, TestUpdateNoUsernameTextfieldPresent) {
// already to be the current password, and should no longer maintain any info
// about the new password value.
EXPECT_EQ(saved_match()->username_value,
- form_manager.pending_credentials().username_value);
+ form_manager.GetPendingCredentials().username_value);
EXPECT_EQ(credentials.new_password_value,
- form_manager.pending_credentials().password_value);
- EXPECT_TRUE(form_manager.pending_credentials().new_password_value.empty());
+ form_manager.GetPendingCredentials().password_value);
+ EXPECT_TRUE(form_manager.GetPendingCredentials().new_password_value.empty());
// Trigger saving to exercise some special case handling during updating.
PasswordForm new_credentials;
EXPECT_CALL(MockFormSaver::Get(&form_manager), Update(_, _, _, nullptr))
.WillOnce(SaveArg<0>(&new_credentials));
- form_manager.Update(form_manager.pending_credentials());
+ form_manager.Update(form_manager.GetPendingCredentials());
- // No other information than password value should be updated. In particular
- // not the username.
+ // The password should be updated, but the username should not.
EXPECT_EQ(saved_match()->username_value, new_credentials.username_value);
EXPECT_EQ(credentials.new_password_value, new_credentials.password_value);
EXPECT_EQ(saved_match()->username_element, new_credentials.username_element);
@@ -2373,16 +2394,15 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_ValueOfAnotherField) {
credential.other_possible_usernames.push_back(
ValueElementPair(ASCIIToUTF16("edited_username"),
ASCIIToUTF16("correct_username_element")));
- form_manager.ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credential);
// User edits username in a prompt.
form_manager.UpdateUsername(ASCIIToUTF16("edited_username"));
- EXPECT_EQ(form_manager.pending_credentials().username_value,
+ EXPECT_EQ(form_manager.GetPendingCredentials().username_value,
ASCIIToUTF16("edited_username"));
- EXPECT_EQ(form_manager.pending_credentials().username_element,
+ EXPECT_EQ(form_manager.GetPendingCredentials().username_element,
ASCIIToUTF16("correct_username_element"));
- EXPECT_EQ(form_manager.pending_credentials().password_value,
+ EXPECT_EQ(form_manager.GetPendingCredentials().password_value,
ASCIIToUTF16("password"));
EXPECT_TRUE(form_manager.IsNewLogin());
@@ -2396,14 +2416,15 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_ValueOfAnotherField) {
expected_types[ASCIIToUTF16("correct_username_element")] =
autofill::USERNAME;
expected_types[ASCIIToUTF16("Passwd")] = autofill::PASSWORD;
+ VoteTypeMap expected_vote_types = {
+ {ASCIIToUTF16("correct_username_element"),
+ autofill::AutofillUploadContents::Field::USERNAME_EDITED}};
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- autofill::FormStructure(observed.form_data)
- .FormSignatureAsStr(),
- expected_types, false /* expect_generation_vote */,
- autofill::AutofillUploadContents::Field::USERNAME_EDITED),
+ AllOf(SignatureIsSameAs(observed),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(false), VoteTypesAre(expected_vote_types)),
_, Contains(autofill::USERNAME), _, _));
form_manager.Save();
@@ -2438,19 +2459,18 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_ValueSavedInStore) {
: ASCIIToUTF16("different_username");
credential.password_value = ASCIIToUTF16("different_pass");
credential.preferred = true;
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credential);
// User edits username in a prompt to one already existing.
form_manager()->UpdateUsername(saved_match()->username_value);
// The username in credentials is expected to be updated.
EXPECT_EQ(saved_match()->username_value,
- form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().username_value);
EXPECT_EQ(saved_match()->username_element,
- form_manager()->pending_credentials().username_element);
+ form_manager()->GetPendingCredentials().username_element);
EXPECT_EQ(ASCIIToUTF16("different_pass"),
- form_manager()->pending_credentials().password_value);
+ form_manager()->GetPendingCredentials().password_value);
EXPECT_FALSE(form_manager()->IsNewLogin());
// Create the expected credential to be saved.
@@ -2472,14 +2492,15 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_ValueSavedInStore) {
expected_types[expected_pending.username_element] = autofill::USERNAME;
expected_types[expected_pending.password_element] =
autofill::ACCOUNT_CREATION_PASSWORD;
+ VoteTypeMap expected_vote_types = {
+ {expected_pending.username_element,
+ autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED}};
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- autofill::FormStructure(expected_pending.form_data)
- .FormSignatureAsStr(),
- expected_types, false /* expect_generation_vote */,
- autofill::AutofillUploadContents::Field::CREDENTIALS_REUSED),
+ AllOf(SignatureIsSameAs(expected_pending),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(false), VoteTypesAre(expected_vote_types)),
_, Contains(autofill::USERNAME), _, _));
form_manager()->Save();
}
@@ -2508,19 +2529,18 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_NoMatchNeitherOnFormNorInStore) {
: ASCIIToUTF16("captured_username");
credential.password_value = ASCIIToUTF16("different_pass");
credential.preferred = true;
- form_manager.ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credential);
// User edits username. The username doesn't exist neither in the store nor
// on the form.
form_manager.UpdateUsername(ASCIIToUTF16("new_username"));
// As there is no match on the form, |username_element| is empty.
- EXPECT_TRUE(form_manager.pending_credentials().username_element.empty());
+ EXPECT_TRUE(form_manager.GetPendingCredentials().username_element.empty());
EXPECT_EQ(ASCIIToUTF16("new_username"),
- form_manager.pending_credentials().username_value);
+ form_manager.GetPendingCredentials().username_value);
EXPECT_EQ(ASCIIToUTF16("different_pass"),
- form_manager.pending_credentials().password_value);
+ form_manager.GetPendingCredentials().password_value);
EXPECT_TRUE(form_manager.IsNewLogin());
PasswordForm expected_pending(credential);
@@ -2568,14 +2588,13 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_UserRemovedUsername) {
credential.password_value = ASCIIToUTF16("password");
credential.other_possible_usernames.push_back(
ValueElementPair(base::string16(), ASCIIToUTF16("empty_field")));
- form_manager.ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credential);
// The user clears the username value in the prompt.
form_manager.UpdateUsername(base::string16());
- EXPECT_TRUE(form_manager.pending_credentials().username_value.empty());
- EXPECT_TRUE(form_manager.pending_credentials().username_element.empty());
- EXPECT_EQ(form_manager.pending_credentials().password_value,
+ EXPECT_TRUE(form_manager.GetPendingCredentials().username_value.empty());
+ EXPECT_TRUE(form_manager.GetPendingCredentials().username_element.empty());
+ EXPECT_EQ(form_manager.GetPendingCredentials().password_value,
ASCIIToUTF16("password"));
EXPECT_TRUE(form_manager.IsNewLogin());
@@ -2604,16 +2623,15 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_PslMatch) {
PasswordForm credential(*observed_form());
credential.username_value = ASCIIToUTF16("some_username");
credential.password_value = ASCIIToUTF16("some_pass");
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credential);
// The user edits the username to match the PSL entry.
form_manager()->UpdateUsername(psl_saved_match()->username_value);
EXPECT_EQ(psl_saved_match()->username_value,
- form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().username_value);
EXPECT_TRUE(form_manager()->IsNewLogin());
EXPECT_EQ(ASCIIToUTF16("some_pass"),
- form_manager()->pending_credentials().password_value);
+ form_manager()->GetPendingCredentials().password_value);
// The user clicks save, the edited username is saved.
PasswordForm saved_result;
@@ -2631,32 +2649,99 @@ TEST_F(PasswordFormManagerTest, UpdateUsername_PslMatch) {
EXPECT_EQ(ASCIIToUTF16("some_pass"), saved_result.password_value);
}
-// Test that when user selects a password, the pending credentials is updated
-// accordingly.
+// Test that when user selects a password in the bubble, the pending credentials
+// are updated accordingly.
TEST_F(PasswordFormManagerTest, TestSelectPasswordMethod) {
- fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
-
- // User enters credential in the form.
- PasswordForm credential(*observed_form());
- credential.username_value = ASCIIToUTF16("username");
- credential.password_value = ASCIIToUTF16("password");
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- // User selects another password in a prompt.
- form_manager()->UpdatePasswordValue(ASCIIToUTF16("newpassword"));
- EXPECT_EQ(form_manager()->pending_credentials().username_value,
- ASCIIToUTF16("username"));
- EXPECT_EQ(form_manager()->pending_credentials().password_value,
- ASCIIToUTF16("newpassword"));
- EXPECT_TRUE(form_manager()->IsNewLogin());
+ for (bool has_password : {true, false}) {
+ for (bool has_new_password : {true, false}) {
+ for (bool has_passwords_revealed : {true, false}) {
+ if (!has_password && !has_new_password)
+ continue;
+ SCOPED_TRACE(testing::Message() << "has_password=" << has_password);
+ SCOPED_TRACE(testing::Message()
+ << "has_new_password=" << has_new_password);
+ SCOPED_TRACE(testing::Message()
+ << "has_passwords_revealed=" << has_passwords_revealed);
+
+ PasswordForm observed(*observed_form());
+ // Observe two password fields, between which we must select.
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("correct_password_element");
+ field.form_control_type = "password";
+ observed.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("other_password_element");
+ field.form_control_type = "password";
+ observed.form_data.fields.push_back(field);
+
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), observed,
+ std::make_unique<NiceMock<MockFormSaver>>(), fake_form_fetcher());
+ form_manager.Init(nullptr);
+ fake_form_fetcher()->SetNonFederated(std::vector<const PasswordForm*>(),
+ 0u);
+
+ // User enters credential in the form. We autodetect the wrong password
+ // field.
+ PasswordForm credential(observed);
+ if (has_password) {
+ credential.password_value = ASCIIToUTF16("not-a-password");
+ credential.password_element = ASCIIToUTF16("other_password_element");
+ }
+ if (has_new_password) {
+ credential.new_password_value = ASCIIToUTF16("not-a-password");
+ credential.new_password_element =
+ ASCIIToUTF16("other_password_element");
+ }
+ credential.all_possible_passwords = {
+ {ASCIIToUTF16("p4ssword"),
+ ASCIIToUTF16("correct_password_element")},
+ {ASCIIToUTF16("not-a-password"),
+ ASCIIToUTF16("other_password_element")}};
+ form_manager.ProvisionallySave(credential);
+
+ // Pending credentials have the wrong values.
+ EXPECT_EQ(form_manager.GetPendingCredentials().password_value,
+ ASCIIToUTF16("not-a-password"));
+ EXPECT_EQ(form_manager.GetPendingCredentials().password_element,
+ ASCIIToUTF16("other_password_element"));
+ // User selects another password in a prompt.
+ if (has_passwords_revealed)
+ form_manager.OnPasswordsRevealed();
+ form_manager.UpdatePasswordValue(ASCIIToUTF16("p4ssword"));
+ // Pending credentials are also corrected.
+ EXPECT_EQ(form_manager.GetPendingCredentials().password_value,
+ ASCIIToUTF16("p4ssword"));
+ EXPECT_EQ(form_manager.GetPendingCredentials().password_element,
+ ASCIIToUTF16("correct_password_element"));
+ EXPECT_TRUE(form_manager.IsNewLogin());
+
+ // User clicks save, selected password is saved.
+ PasswordForm saved_result;
+ EXPECT_CALL(MockFormSaver::Get(&form_manager), Save(_, IsEmpty()))
+ .WillOnce(SaveArg<0>(&saved_result));
+ // Expect a password edited vote.
+ FieldTypeMap expected_types;
+ expected_types[ASCIIToUTF16("correct_password_element")] =
+ autofill::PASSWORD;
+ expected_types[ASCIIToUTF16("other_password_element")] =
+ autofill::UNKNOWN_TYPE;
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(observed),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(false),
+ PasswordsWereRevealed(has_passwords_revealed)),
+ _, Contains(autofill::PASSWORD), _, _));
+ form_manager.Save();
- // User clicks save, selected password is saved.
- PasswordForm saved_result;
- EXPECT_CALL(MockFormSaver::Get(form_manager()), Save(_, IsEmpty()))
- .WillOnce(SaveArg<0>(&saved_result));
- form_manager()->Save();
- EXPECT_EQ(ASCIIToUTF16("username"), saved_result.username_value);
- EXPECT_EQ(ASCIIToUTF16("newpassword"), saved_result.password_value);
+ EXPECT_EQ(ASCIIToUTF16("p4ssword"), saved_result.password_value);
+ EXPECT_EQ(ASCIIToUTF16("correct_password_element"),
+ saved_result.password_element);
+ EXPECT_EQ(base::string16(), saved_result.new_password_value);
+ EXPECT_EQ(base::string16(), saved_result.new_password_element);
+ }
+ }
+ }
}
// Test that if WipeStoreCopyIfOutdated is called before password store
@@ -2676,12 +2761,11 @@ TEST_F(PasswordFormManagerTest, WipeStoreCopyIfOutdated_BeforeStoreCallback) {
PasswordForm submitted_form(form);
submitted_form.password_value += ASCIIToUTF16("add stuff, make it different");
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
base::HistogramTester histogram_tester;
EXPECT_CALL(MockFormSaver::Get(&form_manager),
- WipeOutdatedCopies(form_manager.pending_credentials(), _, _));
+ WipeOutdatedCopies(form_manager.GetPendingCredentials(), _, _));
form_manager.WipeStoreCopyIfOutdated();
histogram_tester.ExpectUniqueSample("PasswordManager.StoreReadyWhenWiping", 0,
1);
@@ -2699,8 +2783,7 @@ TEST_F(PasswordFormManagerTest, GenerationStatusChangedWithPassword) {
fake_form_fetcher()->SetNonFederated({&generated_form}, 0u);
- form_manager()->ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(submitted_form);
PasswordForm new_credentials;
EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
@@ -2723,8 +2806,7 @@ TEST_F(PasswordFormManagerTest, GenerationStatusNotUpdatedIfPasswordUnchanged) {
fake_form_fetcher()->SetNonFederated({&generated_form}, 0u);
- form_manager()->ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(submitted_form);
PasswordForm new_credentials;
EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
@@ -2832,8 +2914,7 @@ TEST_F(PasswordFormManagerTest, TestUpdatePSLMatchedCredentials) {
credentials.username_value = saved_match()->username_value;
credentials.password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -2886,8 +2967,7 @@ TEST_F(PasswordFormManagerTest,
credentials.username_value = saved_match()->username_value;
credentials.password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -2928,8 +3008,7 @@ TEST_F(PasswordFormManagerTest,
credentials.username_value = saved_match()->username_value;
credentials.password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, and since this is an update, it should know not to save as a new
@@ -2968,8 +3047,7 @@ TEST_F(PasswordFormManagerTest, TestNotUpdateWhenOnlyPslMatched) {
credentials.username_value = saved_match()->username_value;
credentials.password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
EXPECT_TRUE(form_manager.IsNewLogin());
@@ -3002,8 +3080,7 @@ TEST_F(PasswordFormManagerTest,
credentials.new_password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
form_manager()->PresaveGeneratedPassword(credentials);
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to save, which should know this is a new login.
@@ -3011,19 +3088,20 @@ TEST_F(PasswordFormManagerTest,
// Make sure the credentials that would be submitted on successful login
// are going to match submitted form.
EXPECT_EQ(observed_form()->origin.spec(),
- form_manager()->pending_credentials().origin.spec());
+ form_manager()->GetPendingCredentials().origin.spec());
EXPECT_EQ(observed_form()->signon_realm,
- form_manager()->pending_credentials().signon_realm);
+ form_manager()->GetPendingCredentials().signon_realm);
EXPECT_EQ(observed_form()->action,
- form_manager()->pending_credentials().action);
- EXPECT_TRUE(form_manager()->pending_credentials().preferred);
+ form_manager()->GetPendingCredentials().action);
+ EXPECT_TRUE(form_manager()->GetPendingCredentials().preferred);
EXPECT_EQ(ASCIIToUTF16("new_password"),
- form_manager()->pending_credentials().password_value);
+ form_manager()->GetPendingCredentials().password_value);
EXPECT_EQ(base::string16(),
- form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().username_value);
EXPECT_TRUE(
- form_manager()->pending_credentials().new_password_element.empty());
- EXPECT_TRUE(form_manager()->pending_credentials().new_password_value.empty());
+ form_manager()->GetPendingCredentials().new_password_element.empty());
+ EXPECT_TRUE(
+ form_manager()->GetPendingCredentials().new_password_value.empty());
}
TEST_F(PasswordFormManagerTest, TestUpdatingOnChangePasswordFormGeneration) {
@@ -3039,26 +3117,26 @@ TEST_F(PasswordFormManagerTest, TestUpdatingOnChangePasswordFormGeneration) {
credentials.new_password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
form_manager()->PresaveGeneratedPassword(credentials);
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
EXPECT_FALSE(form_manager()->IsNewLogin());
// Make sure the credentials that would be submitted on successful login
// are going to match the stored entry in the db.
EXPECT_EQ(saved_match()->origin.spec(),
- form_manager()->pending_credentials().origin.spec());
+ form_manager()->GetPendingCredentials().origin.spec());
EXPECT_EQ(saved_match()->signon_realm,
- form_manager()->pending_credentials().signon_realm);
+ form_manager()->GetPendingCredentials().signon_realm);
EXPECT_EQ(observed_form()->action,
- form_manager()->pending_credentials().action);
- EXPECT_TRUE(form_manager()->pending_credentials().preferred);
+ form_manager()->GetPendingCredentials().action);
+ EXPECT_TRUE(form_manager()->GetPendingCredentials().preferred);
EXPECT_EQ(ASCIIToUTF16("new_password"),
- form_manager()->pending_credentials().password_value);
+ form_manager()->GetPendingCredentials().password_value);
EXPECT_EQ(saved_match()->username_value,
- form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().username_value);
+ EXPECT_TRUE(
+ form_manager()->GetPendingCredentials().new_password_element.empty());
EXPECT_TRUE(
- form_manager()->pending_credentials().new_password_element.empty());
- EXPECT_TRUE(form_manager()->pending_credentials().new_password_value.empty());
+ form_manager()->GetPendingCredentials().new_password_value.empty());
}
TEST_F(PasswordFormManagerTest,
@@ -3076,26 +3154,26 @@ TEST_F(PasswordFormManagerTest,
credentials.new_password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
form_manager()->PresaveGeneratedPassword(credentials);
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
EXPECT_TRUE(form_manager()->IsNewLogin());
// Make sure the credentials that would be submitted on successful login
// are going to match submitted form.
EXPECT_EQ(observed_form()->origin.spec(),
- form_manager()->pending_credentials().origin.spec());
+ form_manager()->GetPendingCredentials().origin.spec());
EXPECT_EQ(observed_form()->signon_realm,
- form_manager()->pending_credentials().signon_realm);
+ form_manager()->GetPendingCredentials().signon_realm);
EXPECT_EQ(observed_form()->action,
- form_manager()->pending_credentials().action);
- EXPECT_TRUE(form_manager()->pending_credentials().preferred);
+ form_manager()->GetPendingCredentials().action);
+ EXPECT_TRUE(form_manager()->GetPendingCredentials().preferred);
EXPECT_EQ(ASCIIToUTF16("new_password"),
- form_manager()->pending_credentials().password_value);
+ form_manager()->GetPendingCredentials().password_value);
EXPECT_EQ(base::string16(),
- form_manager()->pending_credentials().username_value);
+ form_manager()->GetPendingCredentials().username_value);
EXPECT_TRUE(
- form_manager()->pending_credentials().new_password_element.empty());
- EXPECT_TRUE(form_manager()->pending_credentials().new_password_value.empty());
+ form_manager()->GetPendingCredentials().new_password_element.empty());
+ EXPECT_TRUE(
+ form_manager()->GetPendingCredentials().new_password_value.empty());
}
TEST_F(PasswordFormManagerTest,
@@ -3127,8 +3205,7 @@ TEST_F(PasswordFormManagerTest,
submitted_form.password_value = saved_match()->password_value;
submitted_form.new_password_value = ASCIIToUTF16("test2");
submitted_form.preferred = true;
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
// Successful login. The PasswordManager would instruct PasswordFormManager
// to update.
@@ -3139,8 +3216,8 @@ TEST_F(PasswordFormManagerTest,
// value already to be the current password, and should no longer maintain
// any info about the new password value.
EXPECT_EQ(submitted_form.new_password_value,
- form_manager.pending_credentials().password_value);
- EXPECT_TRUE(form_manager.pending_credentials().new_password_value.empty());
+ form_manager.GetPendingCredentials().password_value);
+ EXPECT_TRUE(form_manager.GetPendingCredentials().new_password_value.empty());
std::map<base::string16, autofill::ServerFieldType> expected_types;
expected_types[observed_form()->password_element] = autofill::PASSWORD;
@@ -3151,22 +3228,22 @@ TEST_F(PasswordFormManagerTest,
expected_available_field_types.insert(autofill::PASSWORD);
expected_available_field_types.insert(autofill::NEW_PASSWORD);
- std::string observed_form_signature =
- autofill::FormStructure(observed_form()->form_data).FormSignatureAsStr();
-
std::string expected_login_signature =
autofill::FormStructure(saved_match()->form_data).FormSignatureAsStr();
+ // First login vote.
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(submitted_form), _, _, _, _));
+ // Password change vote.
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- observed_form_signature, expected_types,
- false /* expect_generation_vote */,
- autofill::AutofillUploadContents::Field::NO_INFORMATION
- /* expected_username_vote_type */),
- false, expected_available_field_types,
- expected_login_signature, true));
+ StartUploadRequest(AllOf(UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(false),
+ SignatureIsSameAs(*observed_form())),
+ false, expected_available_field_types,
+ expected_login_signature, true));
+ EXPECT_CALL(MockFormSaver::Get(&form_manager), Update(_, _, _, _));
form_manager.Update(*saved_match());
}
@@ -3246,12 +3323,11 @@ TEST_F(PasswordFormManagerTest, FormClassifierVoteUpload) {
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(CheckUploadedFormClassifierVote(
+ StartUploadRequest(UploadedFormClassifierVoteIs(
found_generation_element, generation_element),
false, _, _, true));
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
form_manager.Save();
}
}
@@ -3288,10 +3364,9 @@ TEST_F(PasswordFormManagerTest, FieldPropertiesMasksUpload) {
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(
- CheckFieldPropertiesMasksUpload(expected_field_properties),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
false, _, _, true));
- form_manager.ProvisionallySave(
- submitted_form, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(submitted_form);
form_manager.Save();
}
@@ -3318,8 +3393,7 @@ TEST_F(PasswordFormManagerTest, TestSavingAPIFormsWithSamePassword) {
credentials.password_value = saved_match()->password_value;
credentials.preferred = true;
- form_manager.ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(credentials);
EXPECT_TRUE(form_manager.IsNewLogin());
@@ -3340,15 +3414,14 @@ TEST_F(PasswordFormManagerTest, SkipZeroClickIntact) {
saved_match()->skip_zero_click = true;
psl_saved_match()->skip_zero_click = true;
fake_form_fetcher()->SetNonFederated({saved_match(), psl_saved_match()}, 0u);
- EXPECT_EQ(1u, form_manager()->best_matches().size());
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
// User submits a credentials with an old username and a new password.
PasswordForm credentials(*observed_form());
credentials.username_value = saved_match()->username_value;
credentials.password_value = ASCIIToUTF16("new_password");
credentials.preferred = true;
- form_manager()->ProvisionallySave(
- credentials, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credentials);
// Trigger saving to exercise some special case handling during updating.
PasswordForm new_credentials;
@@ -3365,58 +3438,6 @@ TEST_F(PasswordFormManagerTest, SkipZeroClickIntact) {
EXPECT_TRUE(credentials_to_update[0].skip_zero_click);
}
-TEST_F(PasswordFormManagerTest, ProbablyAccountCreationUpload) {
- PasswordForm form(*observed_form());
- form.form_data = saved_match()->form_data;
- form.other_possible_usernames = saved_match()->other_possible_usernames;
-
- FakeFormFetcher fetcher;
- fetcher.Fetch();
- PasswordFormManager form_manager(
- password_manager(), client(), client()->driver(), form,
- std::make_unique<NiceMock<MockFormSaver>>(), &fetcher);
- form_manager.Init(nullptr);
-
- PasswordForm form_to_save(form);
- form_to_save.preferred = true;
- form_to_save.username_element = ASCIIToUTF16("observed-username-field");
- form_to_save.username_value = saved_match()->username_value;
- form_to_save.password_value = saved_match()->password_value;
- form_to_save.does_look_like_signup_form = true;
-
- fetcher.SetNonFederated(std::vector<const PasswordForm*>(), 0u);
-
- // A user submits a form and edits the username in the prompt.
- form_manager.ProvisionallySave(
- form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- form_manager.UpdateUsername(ASCIIToUTF16("test2@gmail.com"));
-
- autofill::FormStructure pending_structure(form_to_save.form_data);
- autofill::ServerFieldTypeSet expected_available_field_types;
- std::map<base::string16, autofill::ServerFieldType> expected_types;
- expected_types[saved_match()->username_element] = autofill::UNKNOWN_TYPE;
- expected_types[ASCIIToUTF16("full_name")] = autofill::USERNAME;
- expected_types[saved_match()->password_element] =
- autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD;
- expected_available_field_types.insert(
- autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD);
- expected_available_field_types.insert(autofill::USERNAME);
-
- autofill::AutofillUploadContents::Field::UsernameVoteType
- expected_username_vote_type =
- autofill::AutofillUploadContents::Field::USERNAME_EDITED;
-
- EXPECT_CALL(
- *client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- pending_structure.FormSignatureAsStr(), expected_types,
- false /* expect_generation_vote */, expected_username_vote_type),
- false, expected_available_field_types, std::string(), true));
-
- form_manager.Save();
-}
-
TEST_F(PasswordFormManagerFillOnAccountSelectTest, ProcessFrame) {
EXPECT_CALL(*client()->mock_driver(),
ShowInitialPasswordAccountSuggestions(_));
@@ -3431,8 +3452,7 @@ TEST_F(PasswordFormManagerTest, ReportProcessingUpdate) {
PasswordForm pending = *observed_form();
pending.username_value = saved_match()->username_value;
pending.password_value = saved_match()->password_value;
- form_manager()->ProvisionallySave(
- pending, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(pending);
EXPECT_FALSE(form_manager()->IsNewLogin());
EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
@@ -3485,16 +3505,16 @@ TEST_F(PasswordFormManagerTest, RemoveResultsWithWrongScheme_ObservingHTML) {
// First try putting the correct scheme first in returned matches.
fetcher.SetNonFederated({&match, &non_match}, 0);
- EXPECT_EQ(1u, form_manager.best_matches().size());
+ EXPECT_EQ(1u, form_manager.GetBestMatches().size());
EXPECT_EQ(kCorrectScheme,
- form_manager.best_matches().begin()->second->scheme);
+ form_manager.GetBestMatches().begin()->second->scheme);
// Now try putting the correct scheme last in returned matches.
fetcher.SetNonFederated({&non_match, &match}, 0);
- EXPECT_EQ(1u, form_manager.best_matches().size());
+ EXPECT_EQ(1u, form_manager.GetBestMatches().size());
EXPECT_EQ(kCorrectScheme,
- form_manager.best_matches().begin()->second->scheme);
+ form_manager.GetBestMatches().begin()->second->scheme);
}
}
}
@@ -3548,7 +3568,6 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
field.name = ASCIIToUTF16("full_name");
field.form_control_type = "text";
new_login.form_data.fields.push_back(field);
- new_login.does_look_like_signup_form = true;
}
field.label = ASCIIToUTF16("Email");
field.name = ASCIIToUTF16("observed-username-field");
@@ -3574,8 +3593,7 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
base::HistogramTester histogram_tester;
fake_form_fetcher()->SetNonFederated({saved_credential}, 0u);
- form_manager.ProvisionallySave(
- new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(new_login);
histogram_tester.ExpectUniqueSample(
"PasswordManager.UsernameCorrectionFound", 1, 1);
// No match found (because usernames are different).
@@ -3586,19 +3604,12 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
expected_username_vote.username_element =
saved_credential->other_possible_usernames[0].second;
- // Checks the type of the username vote is saved.
- autofill::AutofillUploadContents::Field::UsernameVoteType
- expected_username_vote_type =
- autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN;
-
// Checks the upload.
autofill::ServerFieldTypeSet expected_available_field_types;
expected_available_field_types.insert(autofill::USERNAME);
expected_available_field_types.insert(
autofill::ACCOUNT_CREATION_PASSWORD);
- FormStructure expected_upload(expected_username_vote.form_data);
-
std::string expected_login_signature =
FormStructure(form_manager.observed_form().form_data)
.FormSignatureAsStr();
@@ -3610,6 +3621,11 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
autofill::ACCOUNT_CREATION_PASSWORD;
expected_types[ASCIIToUTF16("Email")] = autofill::UNKNOWN_TYPE;
+ // Checks the type of the username vote is saved.
+ VoteTypeMap expected_vote_types = {
+ {expected_username_vote.username_element,
+ autofill::AutofillUploadContents::Field::USERNAME_OVERWRITTEN}};
+
InSequence s;
std::unique_ptr<FormStructure> signin_vote_form_structure;
if (is_form_with_2_fields) {
@@ -3617,25 +3633,25 @@ TEST_F(PasswordFormManagerTest, UploadUsernameCorrectionVote) {
// for upload.
auto* mock_autofill_manager =
client()->mock_driver()->mock_autofill_manager();
- EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, true))
+ EXPECT_CALL(*mock_autofill_manager,
+ MaybeStartVoteUploadProcessPtr(_, _, true))
.WillOnce(WithArg<0>(SaveToUniquePtr(&signin_vote_form_structure)));
} else {
- // The observed form has 2 text fields and 1 password field,
- // PROBABLY_ACCOUNT_CREATION_PASSWORD should be uploaded.
autofill::ServerFieldTypeSet field_types;
- field_types.insert(autofill::PROBABLY_ACCOUNT_CREATION_PASSWORD);
+ field_types.insert(autofill::PASSWORD);
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, false, field_types, std::string(), true));
}
- EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
- StartUploadRequest(
- CheckUploadedAutofillTypesAndSignature(
- expected_upload.FormSignatureAsStr(), expected_types,
- false, expected_username_vote_type),
- false, expected_available_field_types,
- expected_login_signature, true));
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(AllOf(SignatureIsSameAs(expected_username_vote),
+ UploadedAutofillTypesAre(expected_types),
+ HasGenerationVote(false),
+ VoteTypesAre(expected_vote_types)),
+ false, expected_available_field_types,
+ expected_login_signature, true));
form_manager.Save();
}
}
@@ -3650,8 +3666,7 @@ TEST_F(PasswordFormManagerTest, NoUsernameCorrectionVote) {
new_login.password_value = ASCIIToUTF16("newpass");
base::HistogramTester histogram_tester;
- form_manager()->ProvisionallySave(
- new_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(new_login);
histogram_tester.ExpectUniqueSample("PasswordManager.UsernameCorrectionFound",
0, 1);
@@ -3685,8 +3700,7 @@ TEST_F(PasswordFormManagerTest,
PasswordForm credential(*saved_match());
credential.username_value.clear();
credential.preferred = true;
- form_manager()->ProvisionallySave(
- credential, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(credential);
EXPECT_FALSE(form_manager()->IsNewLogin());
// Create the expected credential to be saved.
@@ -3702,6 +3716,8 @@ TEST_F(PasswordFormManagerTest,
ElementsAre(Pair(saved_match()->username_value,
Pointee(*saved_match()))),
Pointee(IsEmpty()), nullptr));
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, _, _, _));
EXPECT_CALL(
*client()->mock_driver()->mock_autofill_download_manager(),
StartUploadRequest(_, _, Not(Contains(autofill::USERNAME)), _, _));
@@ -3731,15 +3747,14 @@ TEST_F(PasswordFormManagerTest, ResetStoredMatches) {
fake_form_fetcher()->SetNonFederated(
{&best_match1, &best_match2, &non_best_match, &blacklisted}, 0u);
- EXPECT_EQ(2u, form_manager()->best_matches().size());
- EXPECT_TRUE(form_manager()->preferred_match());
- EXPECT_EQ(1u, form_manager()->blacklisted_matches().size());
+ EXPECT_EQ(2u, form_manager()->GetBestMatches().size());
+ EXPECT_TRUE(form_manager()->GetPreferredMatch());
+ EXPECT_EQ(1u, form_manager()->GetBlacklistedMatches().size());
// Trigger Update to verify that there is a non-best match.
PasswordForm updated(best_match1);
updated.password_value = ASCIIToUTF16("updated password");
- form_manager()->ProvisionallySave(
- updated, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(updated);
std::vector<PasswordForm> credentials_to_update;
EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
.WillOnce(SaveArgPointee<2>(&credentials_to_update));
@@ -3751,17 +3766,16 @@ TEST_F(PasswordFormManagerTest, ResetStoredMatches) {
form_manager()->ResetStoredMatches();
- EXPECT_THAT(form_manager()->best_matches(), IsEmpty());
- EXPECT_FALSE(form_manager()->preferred_match());
- EXPECT_THAT(form_manager()->blacklisted_matches(), IsEmpty());
+ EXPECT_THAT(form_manager()->GetBestMatches(), IsEmpty());
+ EXPECT_FALSE(form_manager()->GetPreferredMatch());
+ EXPECT_THAT(form_manager()->GetBlacklistedMatches(), IsEmpty());
// Simulate updating a saved credential again, but this time without non-best
// matches. Verify that the old non-best matches are no longer present.
fake_form_fetcher()->Fetch();
fake_form_fetcher()->SetNonFederated({&best_match1}, 0u);
- form_manager()->ProvisionallySave(
- updated, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager()->ProvisionallySave(updated);
credentials_to_update.clear();
EXPECT_CALL(MockFormSaver::Get(form_manager()), Update(_, _, _, nullptr))
.WillOnce(SaveArgPointee<2>(&credentials_to_update));
@@ -3803,7 +3817,7 @@ TEST_F(PasswordFormManagerTest, GrabFetcher_Same) {
// There will be a RemoveConsumer call as soon as form_manager goes out of
// scope, but the test needs to ensure that there is none as a result of
// GrabFetcher.
- Mock::VerifyAndClearExpectations(form_manager.form_fetcher());
+ Mock::VerifyAndClearExpectations(form_manager.GetFormFetcher());
}
// Check that if asked to take ownership of a different FormFetcher than which
@@ -3814,18 +3828,18 @@ TEST_F(PasswordFormManagerTest, GrabFetcher_Different) {
old_match.username_value = ASCIIToUTF16("user1");
old_match.password_value = ASCIIToUTF16("pass");
fake_form_fetcher()->SetNonFederated({&old_match}, 0u);
- EXPECT_EQ(1u, form_manager()->best_matches().size());
- EXPECT_EQ(&old_match, form_manager()->best_matches().begin()->second);
+ EXPECT_EQ(1u, form_manager()->GetBestMatches().size());
+ EXPECT_EQ(&old_match, form_manager()->GetBestMatches().begin()->second);
- // |form_manager()| uses |fake_form_fetcher()|, which is an instance different
- // from |fetcher| below.
+ // |form_manager()| uses |fake_form_fetcher()|, which is an instance
+ // different from |fetcher| below.
auto fetcher = std::make_unique<MockFormFetcher>();
fetcher->Fetch();
fetcher->SetNonFederated(std::vector<const PasswordForm*>(), 0u);
EXPECT_CALL(*fetcher, AddConsumer(form_manager()));
form_manager()->GrabFetcher(std::move(fetcher));
- EXPECT_EQ(0u, form_manager()->best_matches().size());
+ EXPECT_EQ(0u, form_manager()->GetBestMatches().size());
}
// Check that on changing FormFetcher, the PasswordFormManager removes itself
@@ -3875,10 +3889,10 @@ TEST_F(PasswordFormManagerTest, UploadSignInForm_WithAutofillTypes) {
std::unique_ptr<FormStructure> uploaded_form_structure;
auto* mock_autofill_manager =
client()->mock_driver()->mock_autofill_manager();
- EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, true))
+ EXPECT_CALL(*mock_autofill_manager,
+ MaybeStartVoteUploadProcessPtr(_, _, true))
.WillOnce(WithArg<0>(SaveToUniquePtr(&uploaded_form_structure)));
- form_manager.ProvisionallySave(
- form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager.ProvisionallySave(form_to_save);
form_manager.Save();
ASSERT_EQ(2u, uploaded_form_structure->field_count());
@@ -3911,9 +3925,9 @@ TEST_F(PasswordFormManagerTest, NoUploadsForSubmittedFormWithOnlyOneField) {
auto* mock_autofill_manager =
client()->mock_driver()->mock_autofill_manager();
- EXPECT_CALL(*mock_autofill_manager, StartUploadProcessPtr(_, _, _)).Times(0);
- form_manager.ProvisionallySave(
- form_to_save, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ EXPECT_CALL(*mock_autofill_manager, MaybeStartVoteUploadProcessPtr(_, _, _))
+ .Times(0);
+ form_manager.ProvisionallySave(form_to_save);
form_manager.Save();
}
@@ -4177,10 +4191,9 @@ TEST_F(PasswordFormManagerTest, Clone_OnSave) {
PasswordForm saved_login = *observed_form();
saved_login.username_value = ASCIIToUTF16("newuser");
saved_login.password_value = ASCIIToUTF16("newpass");
- form_manager->ProvisionallySave(
- saved_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager->ProvisionallySave(saved_login);
- const PasswordForm pending = form_manager->pending_credentials();
+ const PasswordForm pending = form_manager->GetPendingCredentials();
std::unique_ptr<PasswordFormManager> clone = form_manager->Clone();
@@ -4206,8 +4219,7 @@ TEST_F(PasswordFormManagerTest, Clone_OnNeverClicked) {
PasswordForm saved_login = *observed_form();
saved_login.username_value = ASCIIToUTF16("newuser");
saved_login.password_value = ASCIIToUTF16("newpass");
- form_manager->ProvisionallySave(
- saved_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager->ProvisionallySave(saved_login);
std::unique_ptr<PasswordFormManager> clone = form_manager->Clone();
@@ -4229,10 +4241,9 @@ TEST_F(PasswordFormManagerTest, Clone_SurvivesOriginal) {
PasswordForm saved_login = *observed_form();
saved_login.username_value = ASCIIToUTF16("newuser");
saved_login.password_value = ASCIIToUTF16("newpass");
- form_manager->ProvisionallySave(
- saved_login, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager->ProvisionallySave(saved_login);
- const PasswordForm pending = form_manager->pending_credentials();
+ const PasswordForm pending = form_manager->GetPendingCredentials();
std::unique_ptr<PasswordFormManager> clone = form_manager->Clone();
form_manager.reset();
@@ -4371,4 +4382,557 @@ TEST_F(PasswordFormManagerTest,
fake_form_fetcher()->SetNonFederated({&simulated_result}, 0u);
}
+TEST_F(PasswordFormManagerTest, FirstLoginVote) {
+
+ PasswordForm old_without_username = *saved_match();
+ old_without_username.username_value.clear();
+ old_without_username.username_element.clear();
+ old_without_username.times_used = 2;
+ struct {
+ std::vector<const autofill::PasswordForm*> stored_creds;
+ std::string description;
+ } test_cases[] = {
+ {{saved_match()}, "Credential reused"},
+ {{psl_saved_match()}, "PSL credential reused"},
+ {{&old_without_username},
+ "Submitted credential adds a username to a stored credential without "
+ "one"},
+ };
+
+ for (auto test_case : test_cases) {
+ SCOPED_TRACE(testing::Message()
+ << "Stored credentials: " << test_case.description);
+
+ fake_form_fetcher()->SetNonFederated(test_case.stored_creds, 0u);
+
+ PasswordForm submitted_form =
+ CreateMinimalCrowdsourcableForm(*observed_form());
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.form_data.fields[0].value = submitted_form.username_value;
+ submitted_form.form_data.fields[1].value = submitted_form.password_value;
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ // The username and password fields contain stored values. This should be
+ // signaled in the vote.
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties = {{submitted_form.username_element,
+ FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.password_element,
+ FieldPropertiesFlags::KNOWN_VALUE}};
+
+ // All votes should be FIRST_USE.
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>
+ expected_vote_types = {
+ {submitted_form.username_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE},
+ {submitted_form.password_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE}};
+
+ // Unrelated vote
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(*test_case.stored_creds.front()),
+ _, _, _, _))
+ .Times(AtMost(1));
+ // First login vote
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedAutofillTypesAre(FieldTypeMap(
+ {{submitted_form.username_element, autofill::USERNAME},
+ {submitted_form.password_element, autofill::PASSWORD},
+ {ASCIIToUTF16("petname"), autofill::UNKNOWN_TYPE}})),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
+ VoteTypesAre(expected_vote_types)),
+ _,
+ autofill::ServerFieldTypeSet(
+ {autofill::USERNAME, autofill::PASSWORD}),
+ _, true));
+
+ form_manager()->Save();
+
+ Mock::VerifyAndClearExpectations(
+ client()->mock_driver()->mock_autofill_download_manager());
+ }
+}
+
+// Tests scenarios where no vote should be uploaded.
+TEST_F(PasswordFormManagerTest, FirstLoginVote_NoVote) {
+ PasswordForm old_credential(*saved_match());
+ old_credential.times_used = 1;
+
+ // A new username means a new credential. We will vote on it the next time it
+ // is used, not now.
+ PasswordForm different_username(*saved_match());
+ different_username.username_value = ASCIIToUTF16("DifferentUsername");
+
+ struct {
+ std::vector<const autofill::PasswordForm*> stored_creds;
+ std::string description;
+ } test_cases[] = {
+ {{}, "No credentials stored"},
+ {{&old_credential}, "Not first use"},
+ {{&different_username}, "Different username"},
+ };
+
+ for (auto test_case : test_cases) {
+ SCOPED_TRACE(testing::Message()
+ << "Stored credentials: " << test_case.description);
+
+ fake_form_fetcher()->SetNonFederated(test_case.stored_creds, 0u);
+
+ // User submits credentials for the observed form.
+ PasswordForm submitted_form =
+ CreateMinimalCrowdsourcableForm(*observed_form());
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.form_data.fields[0].value = submitted_form.username_value;
+ submitted_form.form_data.fields[1].value = submitted_form.password_value;
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(_, _, _, _, _))
+ .Times(0);
+
+ form_manager()->Save();
+
+ Mock::VerifyAndClearExpectations(
+ client()->mock_driver()->mock_autofill_download_manager());
+ }
+}
+
+// If we update an existing credential with a new password, only the username is
+// a known value.
+TEST_F(PasswordFormManagerTest,
+ FirstLoginVote_UpdatePasswordVotesOnlyForUsername) {
+ PasswordForm different_password(*saved_match());
+ different_password.password_value = ASCIIToUTF16("DifferentPassword");
+ fake_form_fetcher()->SetNonFederated({&different_password}, 0u);
+
+ PasswordForm submitted_form =
+ CreateMinimalCrowdsourcableForm(*observed_form());
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.form_data.fields[0].value = submitted_form.username_value;
+ submitted_form.form_data.fields[1].value = submitted_form.password_value;
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ // The username and password fields contain stored values. This should be
+ // signaled in the vote.
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties = {
+ {submitted_form.username_element, FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.password_element, 0}};
+
+ // All votes should be FIRST_USE.
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>
+ expected_vote_types = {
+ {submitted_form.username_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE}};
+
+ // Unrelated vote
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(different_password), _, _, _, _))
+ .Times(AtMost(1));
+ // First login vote
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedAutofillTypesAre(FieldTypeMap(
+ {{submitted_form.username_element, autofill::USERNAME},
+ {submitted_form.password_element, autofill::UNKNOWN_TYPE},
+ {ASCIIToUTF16("petname"), autofill::UNKNOWN_TYPE}})),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
+ VoteTypesAre(expected_vote_types)),
+ _, autofill::ServerFieldTypeSet({autofill::USERNAME}), _, true));
+
+ form_manager()->Save();
+}
+
+// Values on a submitted form should be marked as KNOWN_VALUE only if they match
+// values from the credential which was used to log in. Other stored credentials
+// are ignored.
+TEST_F(PasswordFormManagerTest, FirstLoginVote_MatchOnlySubmittedCredentials) {
+ PasswordForm alternative_credential = *saved_match();
+ alternative_credential.username_value = ASCIIToUTF16("flatmate");
+ alternative_credential.password_value = ASCIIToUTF16("p@ssword");
+ fake_form_fetcher()->SetNonFederated({&alternative_credential, saved_match()},
+ 0u);
+
+ // User submits credentials for the observed form.
+ PasswordForm submitted_form =
+ CreateMinimalCrowdsourcableForm(*observed_form());
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.form_data.fields[0].value = submitted_form.username_value;
+ submitted_form.form_data.fields[1].value = submitted_form.password_value;
+ // Use a value from an alternative credential. It should not be voted as a
+ // known value.
+ submitted_form.form_data.fields[2].value =
+ alternative_credential.username_value;
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ // The username and password fields contain stored values. This should be
+ // signaled in the vote.
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties = {
+ {submitted_form.username_element, FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.password_element, FieldPropertiesFlags::KNOWN_VALUE},
+ {ASCIIToUTF16("petname"), 0}};
+
+ // All votes should be FIRST_USE.
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>
+ expected_vote_types = {
+ {submitted_form.username_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE},
+ {submitted_form.password_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE}};
+
+ // Unrelated vote.
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(*saved_match()), _, _, _, _))
+ .Times(1);
+ // First login vote.
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedAutofillTypesAre(FieldTypeMap(
+ {{submitted_form.username_element, autofill::USERNAME},
+ {submitted_form.password_element, autofill::PASSWORD},
+ {ASCIIToUTF16("petname"), autofill::UNKNOWN_TYPE}})),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
+ VoteTypesAre(expected_vote_types)),
+ _,
+ autofill::ServerFieldTypeSet(
+ {autofill::USERNAME, autofill::PASSWORD}),
+ _, true));
+
+ form_manager()->Save();
+}
+
+TEST_F(PasswordFormManagerTest, FirstLoginVote_NoUsernameSaved) {
+ // We have a credential without a username saved.
+ saved_match()->username_element.clear();
+ saved_match()->username_value.clear();
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+
+ // User submits credentials for the observed form.
+ PasswordForm submitted_form =
+ CreateMinimalCrowdsourcableForm(*observed_form());
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.form_data.fields[0].value = submitted_form.username_value;
+ submitted_form.form_data.fields[1].value = submitted_form.password_value;
+ // An empty field should not be a known username, even if we have no username.
+ submitted_form.form_data.fields[2].value.clear();
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ // The password field contains stored values. This should be signaled in the
+ // vote.
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties = {
+ {submitted_form.username_element, 0}, // Don't match empty values.
+ {submitted_form.password_element, FieldPropertiesFlags::KNOWN_VALUE}};
+
+ // All votes should be FIRST_USE.
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>
+ expected_vote_types = {
+ {submitted_form.username_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE},
+ {submitted_form.password_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE},
+ {ASCIIToUTF16("petname"),
+ autofill::AutofillUploadContents::Field::NO_INFORMATION}};
+
+ // Unrelated vote.
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(*saved_match()), _, _, _, _))
+ .Times(1);
+ // First login vote.
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedAutofillTypesAre(FieldTypeMap(
+ {{submitted_form.username_element, autofill::USERNAME},
+ {submitted_form.password_element, autofill::PASSWORD},
+ {ASCIIToUTF16("petname"), autofill::UNKNOWN_TYPE}})),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
+ VoteTypesAre(expected_vote_types)),
+ _,
+ autofill::ServerFieldTypeSet(
+ {autofill::USERNAME, autofill::PASSWORD}),
+ _, true));
+
+ form_manager()->Save();
+}
+
+// Upload a first login (i.e. first use) vote when the form has no username
+// field.
+TEST_F(PasswordFormManagerTest, FirstLoginVote_NoUsernameSubmitted) {
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+
+ // User submits credentials for the observed form.
+ PasswordForm submitted_form = *observed_form();
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("password1");
+ field.form_control_type = "password";
+ submitted_form.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("password2");
+ field.form_control_type = "new-password";
+ submitted_form.form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("password3");
+ field.form_control_type = "new-password";
+ submitted_form.form_data.fields.push_back(field);
+
+ submitted_form.username_value.clear();
+ submitted_form.username_element.clear();
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.password_element = ASCIIToUTF16("password1");
+ submitted_form.form_data.fields[0].value = saved_match()->password_value;
+ submitted_form.form_data.fields[1].value = ASCIIToUTF16("newpassword");
+ submitted_form.form_data.fields[2].value = ASCIIToUTF16("newpassword");
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties = {
+ {submitted_form.password_element, FieldPropertiesFlags::KNOWN_VALUE}};
+
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>
+ expected_vote_types = {
+ {submitted_form.password_element,
+ autofill::AutofillUploadContents::Field::FIRST_USE}};
+
+ FieldTypeMap expected_votes = {
+ {submitted_form.form_data.fields[0].name, autofill::PASSWORD},
+ {submitted_form.form_data.fields[1].name, autofill::UNKNOWN_TYPE},
+ {submitted_form.form_data.fields[2].name, autofill::UNKNOWN_TYPE}};
+
+ // Unrelated vote.
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(*saved_match()), _, _, _, _))
+ .Times(1);
+ // First login vote.
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedAutofillTypesAre(expected_votes),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
+ VoteTypesAre(expected_vote_types)),
+ _, autofill::ServerFieldTypeSet({autofill::PASSWORD}), _, true));
+
+ form_manager()->Save();
+}
+
+// All fields with a known value should have the KNOWN_VALUE flag.
+TEST_F(PasswordFormManagerTest, FirstLoginVote_KnownValue) {
+ fake_form_fetcher()->SetNonFederated({saved_match()}, 0u);
+
+ autofill::FormFieldData field;
+ field.name = ASCIIToUTF16("email");
+ field.form_control_type = "text";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("petname");
+ field.form_control_type = "text";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("pin");
+ field.form_control_type = "password";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("password");
+ field.form_control_type = "password";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("repeat password");
+ field.form_control_type = "password";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("repeat email");
+ field.form_control_type = "text";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("empty password");
+ field.form_control_type = "password";
+ observed_form()->form_data.fields.push_back(field);
+ field.name = ASCIIToUTF16("empty text");
+ field.form_control_type = "text";
+ observed_form()->form_data.fields.push_back(field);
+ observed_form()->username_element = ASCIIToUTF16("email");
+ observed_form()->password_element = ASCIIToUTF16("password");
+ // User submits credentials for the observed form.
+ PasswordForm submitted_form = *observed_form();
+ submitted_form.username_value = saved_match()->username_value;
+ submitted_form.password_value = saved_match()->password_value;
+ submitted_form.form_data.fields[0].value = submitted_form.username_value;
+ submitted_form.form_data.fields[1].value = ASCIIToUTF16("Snoop");
+ submitted_form.form_data.fields[2].value = ASCIIToUTF16("1234");
+ submitted_form.form_data.fields[3].value = submitted_form.password_value;
+ submitted_form.form_data.fields[4].value = submitted_form.password_value;
+ submitted_form.form_data.fields[5].value = submitted_form.username_value;
+ submitted_form.form_data.fields[6].value.clear();
+ submitted_form.form_data.fields[7].value.clear();
+ submitted_form.preferred = true;
+ EXPECT_TRUE(FormStructure(submitted_form.form_data).ShouldBeUploaded());
+
+ form_manager()->ProvisionallySave(submitted_form);
+
+ std::map<base::string16, autofill::FieldPropertiesMask>
+ expected_field_properties = {
+ {submitted_form.form_data.fields[0].name,
+ FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.form_data.fields[1].name, 0},
+ {submitted_form.form_data.fields[2].name, 0},
+ {submitted_form.form_data.fields[3].name,
+ FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.form_data.fields[4].name,
+ FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.form_data.fields[5].name,
+ FieldPropertiesFlags::KNOWN_VALUE},
+ {submitted_form.form_data.fields[6].name, 0},
+ {submitted_form.form_data.fields[7].name, 0}};
+
+ // Only the detected username_element and password_element fields should have
+ // a USERNAME and PASSWORD vote.
+ std::map<base::string16, autofill::AutofillUploadContents::Field::VoteType>
+ expected_vote_types = {
+ {submitted_form.form_data.fields[0].name,
+ autofill::AutofillUploadContents::Field::FIRST_USE},
+ {submitted_form.form_data.fields[1].name,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION},
+ {submitted_form.form_data.fields[2].name,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION},
+ {submitted_form.form_data.fields[3].name,
+ autofill::AutofillUploadContents::Field::FIRST_USE},
+ {submitted_form.form_data.fields[4].name,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION},
+ {submitted_form.form_data.fields[5].name,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION},
+ {submitted_form.form_data.fields[6].name,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION},
+ {submitted_form.form_data.fields[7].name,
+ autofill::AutofillUploadContents::Field::NO_INFORMATION}};
+
+ FieldTypeMap expected_votes = {
+ {submitted_form.username_element, autofill::USERNAME},
+ {submitted_form.form_data.fields[1].name, autofill::UNKNOWN_TYPE},
+ {submitted_form.form_data.fields[2].name, autofill::UNKNOWN_TYPE},
+ {submitted_form.password_element, autofill::PASSWORD},
+ {submitted_form.form_data.fields[4].name, autofill::UNKNOWN_TYPE},
+ {submitted_form.form_data.fields[5].name, autofill::UNKNOWN_TYPE},
+ {submitted_form.form_data.fields[6].name, autofill::UNKNOWN_TYPE},
+ {submitted_form.form_data.fields[7].name, autofill::UNKNOWN_TYPE}};
+
+ // Unrelated vote.
+ EXPECT_CALL(*client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(SignatureIsSameAs(*saved_match()), _, _, _, _))
+ .Times(1);
+ // First login vote.
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(
+ AllOf(SignatureIsSameAs(submitted_form),
+ UploadedAutofillTypesAre(expected_votes),
+ UploadedFieldPropertiesMasksAre(expected_field_properties),
+ VoteTypesAre(expected_vote_types)),
+ _,
+ autofill::ServerFieldTypeSet(
+ {autofill::USERNAME, autofill::PASSWORD}),
+ _, true));
+
+ form_manager()->Save();
+}
+
+TEST_F(PasswordFormManagerTest, GeneratePasswordAttributesVote) {
+ // Checks that randomization distorts information about present and missed
+ // character classess, but a true value is still restorable with aggregation
+ // of many distorted reports.
+ const char* kPasswordSnippets[] = {"abc", "XYZ", "123", "*-_"};
+ for (int test_case = 0; test_case < 10; ++test_case) {
+ bool has_password_attribute[kNumberOfPasswordAttributes];
+ base::string16 password_value;
+ for (int i = 0; i < kNumberOfPasswordAttributes; ++i) {
+ has_password_attribute[i] = base::RandGenerator(2);
+ if (has_password_attribute[i])
+ password_value += ASCIIToUTF16(kPasswordSnippets[i]);
+ }
+ if (password_value.empty())
+ continue;
+
+ autofill::FormData form;
+ autofill::FormStructure form_structure(form);
+ int reported_false[kNumberOfPasswordAttributes] = {0, 0, 0, 0};
+ int reported_true[kNumberOfPasswordAttributes] = {0, 0, 0, 0};
+
+ for (int i = 0; i < 1000; ++i) {
+ form_manager()->GeneratePasswordAttributesVote(password_value,
+ &form_structure);
+ base::Optional<std::pair<autofill::PasswordAttribute, bool>> vote =
+ form_structure.get_password_attributes_vote_for_testing();
+ int attribute_index = static_cast<int>(vote->first);
+ if (vote->second)
+ reported_true[attribute_index]++;
+ else
+ reported_false[attribute_index]++;
+ }
+ for (int i = 0; i < kNumberOfPasswordAttributes; i++) {
+ EXPECT_LT(0, reported_false[i]);
+ EXPECT_LT(0, reported_true[i]);
+
+ // If the actual value is |true|, then it should report more |true|s than
+ // |false|s.
+ if (has_password_attribute[i]) {
+ EXPECT_LT(reported_false[i], reported_true[i])
+ << "Wrong distribution for attribute " << i
+ << ". password_value = " << password_value;
+ } else {
+ EXPECT_GT(reported_false[i], reported_true[i])
+ << "Wrong distribution for attribute " << i
+ << ". password_value = " << password_value;
+ }
+ }
+ }
+}
+
+TEST_F(PasswordFormManagerTest, UploadPasswordAttributesVote) {
+ PasswordForm credentials = *observed_form();
+ // Set FormData to enable crowdsourcing.
+ credentials.form_data = saved_match()->form_data;
+ FakeFormFetcher fetcher;
+ PasswordFormManager form_manager(
+ password_manager(), client(), client()->driver(), credentials,
+ std::make_unique<NiceMock<MockFormSaver>>(), &fetcher);
+ form_manager.Init(nullptr);
+ fetcher.SetNonFederated(std::vector<const PasswordForm*>(), 0u);
+
+ credentials.username_value = saved_match()->username_value;
+ credentials.password_value = ASCIIToUTF16("12345");
+ form_manager.ProvisionallySave(credentials);
+
+ EXPECT_CALL(
+ *client()->mock_driver()->mock_autofill_download_manager(),
+ StartUploadRequest(HasPasswordAttributesVote(true /* is_vote_expected */),
+ _, _, _, _));
+ form_manager.Save();
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
index 858ba912052..576f4c3dbc9 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.cc
@@ -39,14 +39,14 @@ PasswordFormMetricsRecorder::BubbleDismissalReason GetBubbleDismissalReason(
// Ignore these for metrics collection:
case metrics_util::CLICKED_MANAGE:
- case metrics_util::CLICKED_DONE:
- case metrics_util::CLICKED_OK:
case metrics_util::CLICKED_BRAND_NAME:
case metrics_util::CLICKED_PASSWORDS_DASHBOARD:
case metrics_util::AUTO_SIGNIN_TOAST_TIMEOUT:
break;
// These should not reach here:
+ case metrics_util::CLICKED_DONE_OBSOLETE:
+ case metrics_util::CLICKED_OK_OBSOLETE:
case metrics_util::CLICKED_UNBLACKLIST_OBSOLETE:
case metrics_util::CLICKED_CREDENTIAL_OBSOLETE:
case metrics_util::AUTO_SIGNIN_TOAST_CLICKED_OBSOLETE:
@@ -118,17 +118,20 @@ PasswordFormMetricsRecorder::~PasswordFormMetricsRecorder() {
ukm_entry_builder_.SetUser_Action_TriggeredManualFallbackForSaving(
action.second);
break;
- case DetailedUserAction::kTriggeredManualFallbackForUpdating:
- ukm_entry_builder_.SetUser_Action_TriggeredManualFallbackForUpdating(
- action.second);
- break;
case DetailedUserAction::kCorrectedUsernameInForm:
ukm_entry_builder_.SetUser_Action_CorrectedUsernameInForm(
action.second);
break;
+ case DetailedUserAction::kObsoleteTriggeredManualFallbackForUpdating:
+ NOTREACHED();
+ break;
}
}
+ if (showed_manual_fallback_for_saving_) {
+ ukm_entry_builder_.SetSaving_ShowedManualFallbackForSaving(
+ showed_manual_fallback_for_saving_.value());
+ }
ukm_entry_builder_.Record(ukm::UkmRecorder::Get());
}
@@ -200,6 +203,11 @@ void PasswordFormMetricsRecorder::SetSubmittedFormType(
submitted_form_type_ = form_type;
}
+void PasswordFormMetricsRecorder::SetSubmissionIndicatorEvent(
+ autofill::PasswordForm::SubmissionIndicatorEvent event) {
+ ukm_entry_builder_.SetSubmission_Indicator(static_cast<int>(event));
+}
+
int PasswordFormMetricsRecorder::GetActionsTakenNew() const {
// Merge kManagerActionNone and kManagerActionBlacklisted_Obsolete. This
// lowers the number of histogram buckets used by 33%.
@@ -231,6 +239,13 @@ void PasswordFormMetricsRecorder::RecordFormSignature(
HashFormSignature(form_signature));
}
+void PasswordFormMetricsRecorder::RecordShowManualFallbackForSaving(
+ bool has_generated_password,
+ bool is_update) {
+ showed_manual_fallback_for_saving_ =
+ 1 + (has_generated_password ? 2 : 0) + (is_update ? 4 : 0);
+}
+
int PasswordFormMetricsRecorder::GetActionsTaken() const {
return static_cast<int>(user_action_) +
static_cast<int>(UserAction::kMax) *
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
index 6679d806b9e..4f82cc73e1d 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder.h
@@ -151,7 +151,7 @@ class PasswordFormMetricsRecorder
kEditedUsernameInBubble = 100,
kSelectedDifferentPasswordInBubble = 101,
kTriggeredManualFallbackForSaving = 102,
- kTriggeredManualFallbackForUpdating = 103,
+ kObsoleteTriggeredManualFallbackForUpdating = 103, // unused
// Interactions with form.
kCorrectedUsernameInForm = 200,
@@ -194,6 +194,11 @@ class PasswordFormMetricsRecorder
// Call this once the submitted form type has been determined.
void SetSubmittedFormType(SubmittedFormType form_type);
+ // Call this when a password is saved to indicate which path led to
+ // submission.
+ void SetSubmissionIndicatorEvent(
+ autofill::PasswordForm::SubmissionIndicatorEvent event);
+
// Records all histograms in the PasswordManager.SuppressedAccount.* family.
// Takes the FormFetcher intance which owns the login data from PasswordStore.
// |pending_credentials| stores credentials when the form was submitted but
@@ -231,6 +236,11 @@ class PasswordFormMetricsRecorder
// distinguish two forms on the same site.
void RecordFormSignature(autofill::FormSignature form_signature);
+ // Records that Chrome noticed that it should show a manual fallback for
+ // saving.
+ void RecordShowManualFallbackForSaving(bool has_generated_password,
+ bool is_update);
+
private:
friend class base::RefCounted<PasswordFormMetricsRecorder>;
@@ -317,6 +327,12 @@ class PasswordFormMetricsRecorder
// PasswordFormManager. Reported upon destruction.
std::map<DetailedUserAction, int64_t> detailed_user_actions_counts_;
+ // Bitmap of whether and why a manual fallback for saving was shown:
+ // 1 = the fallback was shown.
+ // 2 = the password was generated.
+ // 4 = this was an update prompt.
+ base::Optional<uint32_t> showed_manual_fallback_for_saving_;
+
DISALLOW_COPY_AND_ASSIGN(PasswordFormMetricsRecorder);
};
diff --git a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
index 589c89f36a4..58ccf1d0a87 100644
--- a/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_form_metrics_recorder_unittest.cc
@@ -612,4 +612,68 @@ TEST(PasswordFormMetricsRecorder, RecordDetailedUserAction) {
}
}
+// Verify that the the mapping is correct and that metrics are actually
+// recorded.
+TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSaving) {
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ struct {
+ bool has_generated_password;
+ bool is_update;
+ int expected_value;
+ } kTests[] = {
+ {false, false, 1},
+ {true, false, 1 + 2},
+ {false, true, 1 + 4},
+ {true, true, 1 + 2 + 4},
+ };
+ for (const auto& test : kTests) {
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ true /*is_main_frame_secure*/, &test_ukm_recorder);
+ recorder->RecordShowManualFallbackForSaving(test.has_generated_password,
+ test.is_update);
+ }
+ auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ EXPECT_EQ(kTestSourceId, entries[0]->source_id);
+ test_ukm_recorder.ExpectEntryMetric(
+ entries[0], UkmEntry::kSaving_ShowedManualFallbackForSavingName,
+ test.expected_value);
+ }
+}
+
+// Verify that no 0 is recorded if now fallback icon is shown.
+TEST(PasswordFormMetricsRecorder, NoRecordShowManualFallbackForSaving) {
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ true /*is_main_frame_secure*/, &test_ukm_recorder);
+ }
+ auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ EXPECT_EQ(kTestSourceId, entries[0]->source_id);
+ EXPECT_FALSE(test_ukm_recorder.EntryHasMetric(
+ entries[0], UkmEntry::kSaving_ShowedManualFallbackForSavingName));
+}
+
+// Verify that only the latest value is recorded
+TEST(PasswordFormMetricsRecorder, RecordShowManualFallbackForSavingLatestOnly) {
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ {
+ auto recorder = CreatePasswordFormMetricsRecorder(
+ true /*is_main_frame_secure*/, &test_ukm_recorder);
+ recorder->RecordShowManualFallbackForSaving(true, false);
+ recorder->RecordShowManualFallbackForSaving(true, true);
+ }
+ auto entries = test_ukm_recorder.GetEntriesByName(UkmEntry::kEntryName);
+ ASSERT_EQ(1u, entries.size());
+ EXPECT_EQ(kTestSourceId, entries[0]->source_id);
+ test_ukm_recorder.ExpectEntryMetric(
+ entries[0], UkmEntry::kSaving_ShowedManualFallbackForSavingName,
+ 1 + 2 + 4);
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_generation_manager.cc b/chromium/components/password_manager/core/browser/password_generation_manager.cc
index 80dffd1440a..f089ae1dd64 100644
--- a/chromium/components/password_manager/core/browser/password_generation_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_generation_manager.cc
@@ -46,11 +46,10 @@ void PasswordGenerationManager::DetectFormsEligibleForGeneration(
const AutofillField* generation_field = nullptr;
const AutofillField* confirmation_field = nullptr;
for (const std::unique_ptr<AutofillField>& field : *form) {
- if (field->overall_server_type() == autofill::ACCOUNT_CREATION_PASSWORD ||
- field->overall_server_type() == autofill::NEW_PASSWORD) {
+ if (field->server_type() == autofill::ACCOUNT_CREATION_PASSWORD ||
+ field->server_type() == autofill::NEW_PASSWORD) {
generation_field = field.get();
- } else if (field->overall_server_type() ==
- autofill::CONFIRMATION_PASSWORD) {
+ } else if (field->server_type() == autofill::CONFIRMATION_PASSWORD) {
confirmation_field = field.get();
}
}
diff --git a/chromium/components/password_manager/core/browser/password_manager.cc b/chromium/components/password_manager/core/browser/password_manager.cc
index c8f8805d14e..b5383eb386e 100644
--- a/chromium/components/password_manager/core/browser/password_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_manager.cc
@@ -20,11 +20,11 @@
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/common/form_data_predictions.h"
#include "components/autofill/core/common/password_form_field_prediction_map.h"
-#include "components/password_manager/core/browser/android_affiliation/affiliation_utils.h"
#include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
#include "components/password_manager/core/browser/form_saver_impl.h"
#include "components/password_manager/core/browser/keychain_migration_status_mac.h"
#include "components/password_manager/core/browser/log_manager.h"
+#include "components/password_manager/core/browser/new_password_form_manager.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_form_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
@@ -37,12 +37,14 @@
#include "components/password_manager/core/common/password_manager_pref_names.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
+#include "google_apis/gaia/gaia_auth_util.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#if defined(OS_WIN)
#include "components/prefs/pref_registry_simple.h"
#endif
+using autofill::FormData;
using autofill::PasswordForm;
namespace password_manager {
@@ -159,24 +161,6 @@ bool IsPredictedTypeNotPasswordPrediction(
field_type == autofill::CREDIT_CARD_VERIFICATION_CODE;
}
-bool PreferredRealmIsFromAndroid(
- const autofill::PasswordFormFillData& fill_data) {
- return FacetURI::FromPotentiallyInvalidSpec(
- fill_data.preferred_realm).IsValidAndroidFacetURI();
-}
-
-bool ContainsAndroidCredentials(
- const autofill::PasswordFormFillData& fill_data) {
- for (const auto& login : fill_data.additional_logins) {
- if (FacetURI::FromPotentiallyInvalidSpec(
- login.second.realm).IsValidAndroidFacetURI()) {
- return true;
- }
- }
-
- return PreferredRealmIsFromAndroid(fill_data);
-}
-
bool AreAllFieldsEmpty(const PasswordForm& form) {
return form.username_value.empty() && form.password_value.empty() &&
form.new_password_value.empty();
@@ -185,10 +169,10 @@ bool AreAllFieldsEmpty(const PasswordForm& form) {
// Helper function that determines whether update or save prompt should be
// shown for credentials in |provisional_save_manager|.
bool IsPasswordUpdate(const PasswordFormManager& provisional_save_manager) {
- return (!provisional_save_manager.best_matches().empty() &&
+ return (!provisional_save_manager.GetBestMatches().empty() &&
provisional_save_manager
.is_possible_change_password_form_without_username()) ||
- provisional_save_manager.password_overridden() ||
+ provisional_save_manager.IsPasswordOverridden() ||
provisional_save_manager.retry_password_form_password_update();
}
@@ -263,6 +247,8 @@ void PasswordManager::RegisterProfilePrefs(
prefs::kKeychainMigrationStatus,
static_cast<int>(MigrationStatus::MIGRATED_DELETED));
#endif
+ registry->RegisterListPref(prefs::kPasswordHashDataList,
+ PrefRegistry::NO_REGISTRATION_FLAGS);
}
#if defined(OS_WIN)
@@ -376,8 +362,8 @@ void PasswordManager::ProvisionallySavePassword(
return;
}
- // No password to save? Then don't.
- if (PasswordFormManager::PasswordToSave(form).empty()) {
+ // No password value to save? Then don't.
+ if (PasswordFormManager::PasswordToSave(form).first.empty()) {
client_->GetMetricsRecorder().RecordProvisionalSaveFailure(
PasswordManagerMetricsRecorder::EMPTY_PASSWORD, main_frame_url_,
form.origin, logger.get());
@@ -441,12 +427,13 @@ void PasswordManager::ProvisionallySavePassword(
void PasswordManager::UpdateFormManagers() {
for (const auto& form_manager : pending_login_managers_) {
- form_manager->form_fetcher()->Fetch();
+ form_manager->GetFormFetcher()->Fetch();
}
}
void PasswordManager::DropFormManagers() {
pending_login_managers_.clear();
+ form_managers_.clear();
provisional_save_manager_.reset();
all_visible_forms_.clear();
}
@@ -455,11 +442,6 @@ bool PasswordManager::IsPasswordFieldDetectedOnPage() {
return !pending_login_managers_.empty();
}
-void PasswordManager::AddSubmissionCallback(
- const PasswordSubmittedCallback& callback) {
- submission_callbacks_.push_back(callback);
-}
-
void PasswordManager::AddObserverAndDeliverCredentials(
LoginModelObserver* observer,
const PasswordForm& observed_form) {
@@ -482,17 +464,16 @@ void PasswordManager::RemoveObserver(LoginModelObserver* observer) {
void PasswordManager::DidNavigateMainFrame() {
entry_to_check_ = NavigationEntryToCheck::LAST_COMMITTED;
pending_login_managers_.clear();
+ form_managers_.clear();
}
void PasswordManager::OnPasswordFormSubmitted(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& password_form) {
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kNewPasswordFormParsing))
+ ProcessSubmittedForm(password_form.form_data, driver);
ProvisionallySavePassword(password_form, driver);
- for (size_t i = 0; i < submission_callbacks_.size(); ++i) {
- submission_callbacks_[i].Run(password_form);
- }
-
- pending_login_managers_.clear();
}
void PasswordManager::OnPasswordFormSubmittedNoChecks(
@@ -503,6 +484,9 @@ void PasswordManager::OnPasswordFormSubmittedNoChecks(
logger.LogMessage(Logger::STRING_ON_SAME_DOCUMENT_NAVIGATION);
}
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kNewPasswordFormParsing))
+ ProcessSubmittedForm(password_form.form_data, driver);
ProvisionallySavePassword(password_form, driver);
if (CanProvisionalManagerSave())
@@ -524,7 +508,8 @@ void PasswordManager::ShowManualFallbackForSaving(
password_manager::PasswordManagerDriver* driver,
const PasswordForm& password_form) {
if (!client_->IsSavingAndFillingEnabledForCurrentPage() ||
- ShouldBlockPasswordForSameOriginButDifferentScheme(password_form))
+ ShouldBlockPasswordForSameOriginButDifferentScheme(password_form) ||
+ !client_->GetStoreResultFilter()->ShouldSave(password_form))
return;
PasswordFormManager* matched_manager = FindMatchedManager(
@@ -533,7 +518,7 @@ void PasswordManager::ShowManualFallbackForSaving(
return;
// TODO(crbug.com/741537): Process manual saving request even if there is
// still no response from the store.
- if (matched_manager->form_fetcher()->GetState() ==
+ if (matched_manager->GetFormFetcher()->GetState() ==
FormFetcher::State::WAITING) {
return;
}
@@ -547,6 +532,8 @@ void PasswordManager::ShowManualFallbackForSaving(
bool is_update = IsPasswordUpdate(*provisional_save_manager_);
client_->ShowManualFallbackForSaving(std::move(provisional_save_manager_),
has_generated_password, is_update);
+ matched_manager->GetMetricsRecorder()->RecordShowManualFallbackForSaving(
+ has_generated_password, is_update);
} else {
HideManualFallbackForSaving();
}
@@ -572,6 +559,11 @@ void PasswordManager::CreatePendingLoginManagers(
logger->LogMessage(Logger::STRING_CREATE_LOGIN_MANAGERS_METHOD);
}
+ if (base::FeatureList::IsEnabled(
+ password_manager::features::kNewPasswordFormParsing)) {
+ CreateFormManagers(driver, forms);
+ }
+
const PasswordForm::Scheme effective_form_scheme =
forms.empty() ? PasswordForm::SCHEME_HTML : forms.front().scheme;
switch (effective_form_scheme) {
@@ -671,8 +663,51 @@ void PasswordManager::CreatePendingLoginManagers(
}
}
-bool PasswordManager::OtherPossibleUsernamesEnabled() const {
- return false;
+void PasswordManager::CreateFormManagers(
+ password_manager::PasswordManagerDriver* driver,
+ const std::vector<autofill::PasswordForm>& forms) {
+ // Find new forms.
+ std::vector<const FormData*> new_forms;
+ for (const autofill::PasswordForm& form : forms) {
+ bool form_manager_exists =
+ std::any_of(form_managers_.begin(), form_managers_.end(),
+ [&form, driver](const auto& form_manager) {
+ return form_manager->DoesManage(form.form_data, driver);
+ });
+ if (!form_manager_exists)
+ new_forms.push_back(&form.form_data);
+ }
+
+ // Create form manager for new forms.
+ for (const FormData* new_form : new_forms) {
+ form_managers_.push_back(std::make_unique<NewPasswordFormManager>(
+ client_,
+ driver ? driver->AsWeakPtr() : base::WeakPtr<PasswordManagerDriver>(),
+ *new_form, nullptr));
+ }
+}
+
+void PasswordManager::ProcessSubmittedForm(
+ const FormData& submitted_form,
+ const PasswordManagerDriver* driver) {
+ NewPasswordFormManager* matching_form_manager = nullptr;
+ for (const auto& manager : form_managers_) {
+ if (manager->SetSubmittedFormIfIsManaged(submitted_form, driver)) {
+ matching_form_manager = manager.get();
+ break;
+ }
+ }
+ if (!matching_form_manager) {
+ // TODO(https://crbug.com/831123). Add metrics and implement more robust
+ // handling when |matching_form_manager| is not found.
+ return;
+ }
+
+ // Set all other form managers to no submission state.
+ for (const auto& manager : form_managers_) {
+ if (manager.get() != matching_form_manager)
+ matching_form_manager->set_not_submitted();
+ }
}
void PasswordManager::ProvisionallySaveManager(
@@ -688,16 +723,7 @@ void PasswordManager::ProvisionallySaveManager(
logger->LogPasswordForm(Logger::STRING_PROVISIONALLY_SAVED_FORM,
submitted_form);
}
- PasswordFormManager::OtherPossibleUsernamesAction action =
- PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES;
- if (OtherPossibleUsernamesEnabled())
- action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES;
- if (logger) {
- logger->LogBoolean(
- Logger::STRING_IGNORE_POSSIBLE_USERNAMES,
- action == PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
- }
- manager->ProvisionallySave(submitted_form, action);
+ manager->ProvisionallySave(submitted_form);
provisional_save_manager_.swap(manager);
}
@@ -716,13 +742,13 @@ bool PasswordManager::CanProvisionalManagerSave() {
return false;
}
- if (provisional_save_manager_->form_fetcher()->GetState() ==
+ if (provisional_save_manager_->GetFormFetcher()->GetState() ==
FormFetcher::State::WAITING) {
// We have a provisional save manager, but it didn't finish matching yet.
// We just give up.
client_->GetMetricsRecorder().RecordProvisionalSaveFailure(
PasswordManagerMetricsRecorder::MATCHING_NOT_COMPLETE, main_frame_url_,
- provisional_save_manager_->observed_form().origin, logger.get());
+ provisional_save_manager_->GetOrigin(), logger.get());
provisional_save_manager_.reset();
return false;
}
@@ -743,7 +769,7 @@ bool PasswordManager::ShouldPromptUserToSavePassword() const {
provisional_save_manager_
->is_possible_change_password_form_without_username() ||
provisional_save_manager_->retry_password_form_password_update() ||
- provisional_save_manager_->password_overridden()) &&
+ provisional_save_manager_->IsPasswordOverridden()) &&
!(provisional_save_manager_->has_generated_password() &&
provisional_save_manager_->IsNewLogin()) &&
!provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch();
@@ -786,7 +812,7 @@ void PasswordManager::OnPasswordFormsRendered(
// If we see the login form again, then the login failed.
if (did_stop_loading) {
- if (provisional_save_manager_->pending_credentials().scheme ==
+ if (provisional_save_manager_->GetPendingCredentials().scheme ==
PasswordForm::SCHEME_HTML) {
for (size_t i = 0; i < all_visible_forms_.size(); ++i) {
// TODO(vabr): The similarity check is just action equality up to
@@ -795,7 +821,7 @@ void PasswordManager::OnPasswordFormsRendered(
// PasswordFormManager::DoesManage for it.
if (IsPasswordFormReappeared(
all_visible_forms_[i],
- provisional_save_manager_->pending_credentials())) {
+ provisional_save_manager_->GetPendingCredentials())) {
if (provisional_save_manager_
->is_possible_change_password_form_without_username() &&
AreAllFieldsEmpty(all_visible_forms_[i]))
@@ -854,35 +880,15 @@ void PasswordManager::OnLoginSuccessful() {
}
DCHECK(provisional_save_manager_->submitted_form());
+
+ MaybeSavePasswordHash();
+
if (!client_->GetStoreResultFilter()->ShouldSave(
*provisional_save_manager_->submitted_form())) {
-#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
- // When |username_value| is empty, it's not clear whether the submitted
- // credentials are really sync credentials. Don't save sync password hash
- // in that case.
- if (!provisional_save_manager_->submitted_form()->username_value.empty()) {
- password_manager::PasswordStore* store = client_->GetPasswordStore();
- // May be null in tests.
- if (store) {
- bool is_sync_password_change =
- !provisional_save_manager_->submitted_form()
- ->new_password_element.empty();
- if (is_sync_password_change) {
- store->SaveSyncPasswordHash(
- provisional_save_manager_->submitted_form()->new_password_value,
- metrics_util::SyncPasswordHashChange::CHANGED_IN_CONTENT_AREA);
- } else {
- store->SaveSyncPasswordHash(
- provisional_save_manager_->submitted_form()->password_value,
- metrics_util::SyncPasswordHashChange::SAVED_IN_CONTENT_AREA);
- }
- }
- }
-#endif
provisional_save_manager_->WipeStoreCopyIfOutdated();
client_->GetMetricsRecorder().RecordProvisionalSaveFailure(
PasswordManagerMetricsRecorder::SYNC_CREDENTIAL, main_frame_url_,
- provisional_save_manager_->observed_form().origin, logger.get());
+ provisional_save_manager_->GetOrigin(), logger.get());
provisional_save_manager_.reset();
return;
}
@@ -892,11 +898,11 @@ void PasswordManager::OnLoginSuccessful() {
RecordWhetherTargetDomainDiffers(main_frame_url_, client_->GetMainFrameURL());
// If the form is eligible only for saving fallback, it shouldn't go here.
- DCHECK(!provisional_save_manager_->pending_credentials()
+ DCHECK(!provisional_save_manager_->GetPendingCredentials()
.only_for_fallback_saving);
if (ShouldPromptUserToSavePassword()) {
- bool empty_password =
- provisional_save_manager_->pending_credentials().username_value.empty();
+ bool empty_password = provisional_save_manager_->GetPendingCredentials()
+ .username_value.empty();
UMA_HISTOGRAM_BOOLEAN("PasswordManager.EmptyUsernames.OfferedToSave",
empty_password);
if (logger)
@@ -914,7 +920,7 @@ void PasswordManager::OnLoginSuccessful() {
if (!provisional_save_manager_->IsNewLogin()) {
client_->NotifySuccessfulLoginWithExistingPassword(
- provisional_save_manager_->pending_credentials());
+ provisional_save_manager_->GetPendingCredentials());
}
if (provisional_save_manager_->has_generated_password()) {
@@ -925,62 +931,40 @@ void PasswordManager::OnLoginSuccessful() {
}
}
-void PasswordManager::Autofill(
- password_manager::PasswordManagerDriver* driver,
- const PasswordForm& form_for_autofill,
- const std::map<base::string16, const PasswordForm*>& best_matches,
- const std::vector<const PasswordForm*>& federated_matches,
- const PasswordForm& preferred_match,
- bool wait_for_username) const {
- DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
-
- std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
- if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
- logger->LogMessage(Logger::STRING_PASSWORDMANAGER_AUTOFILL);
- }
-
- autofill::PasswordFormFillData fill_data;
- InitPasswordFormFillData(form_for_autofill, best_matches, &preferred_match,
- wait_for_username, OtherPossibleUsernamesEnabled(),
- &fill_data);
- if (logger)
- logger->LogBoolean(Logger::STRING_WAIT_FOR_USERNAME, wait_for_username);
- UMA_HISTOGRAM_BOOLEAN(
- "PasswordManager.FillSuggestionsIncludeAndroidAppCredentials",
- ContainsAndroidCredentials(fill_data));
- metrics_util::LogFilledCredentialIsFromAndroidApp(
- PreferredRealmIsFromAndroid(fill_data));
- driver->FillPasswordForm(fill_data);
-
- client_->PasswordWasAutofilled(best_matches, form_for_autofill.origin,
- &federated_matches);
-}
-
-void PasswordManager::ShowInitialPasswordAccountSuggestions(
- password_manager::PasswordManagerDriver* driver,
- const PasswordForm& form_for_autofill,
- const std::map<base::string16, const PasswordForm*>& best_matches,
- const PasswordForm& preferred_match,
- bool wait_for_username) const {
- DCHECK_EQ(PasswordForm::SCHEME_HTML, preferred_match.scheme);
-
- std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
- if (password_manager_util::IsLoggingActive(client_)) {
- logger.reset(
- new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
- logger->LogMessage(
- Logger::
- STRING_PASSWORDMANAGER_SHOW_INITIAL_PASSWORD_ACCOUNT_SUGGESTIONS);
+void PasswordManager::MaybeSavePasswordHash() {
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+ if (client_->GetStoreResultFilter()->ShouldSavePasswordHash(
+ *provisional_save_manager_->submitted_form())) {
+ // When |username_value| is empty, it's not clear whether the submitted
+ // credentials are really sync credentials. Don't save sync password hash
+ // in that case.
+ std::string username = base::UTF16ToUTF8(
+ provisional_save_manager_->submitted_form()->username_value);
+ if (username.empty())
+ return;
+
+ password_manager::PasswordStore* store = client_->GetPasswordStore();
+ // May be null in tests.
+ if (!store)
+ return;
+ bool is_sync_password_change = !provisional_save_manager_->submitted_form()
+ ->new_password_element.empty();
+ // Canonicalizes username if it is an email.
+ if (username.find('@') != std::string::npos)
+ username = gaia::CanonicalizeEmail(username);
+
+ if (is_sync_password_change) {
+ store->SaveSyncPasswordHash(
+ username,
+ provisional_save_manager_->submitted_form()->new_password_value,
+ metrics_util::SyncPasswordHashChange::CHANGED_IN_CONTENT_AREA);
+ } else {
+ store->SaveSyncPasswordHash(
+ username, provisional_save_manager_->submitted_form()->password_value,
+ metrics_util::SyncPasswordHashChange::SAVED_IN_CONTENT_AREA);
+ }
}
- autofill::PasswordFormFillData fill_data;
- InitPasswordFormFillData(form_for_autofill, best_matches, &preferred_match,
- wait_for_username, OtherPossibleUsernamesEnabled(),
- &fill_data);
- if (logger)
- logger->LogBoolean(Logger::STRING_WAIT_FOR_USERNAME, wait_for_username);
- driver->ShowInitialPasswordAccountSuggestions(fill_data);
+#endif
}
void PasswordManager::AutofillHttpAuth(
@@ -1013,8 +997,7 @@ void PasswordManager::ProcessAutofillPredictions(
new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
// Leave only forms that contain fields that are useful for password manager.
- std::map<autofill::FormData, autofill::PasswordFormFieldPredictionMap>
- predictions;
+ std::map<FormData, autofill::PasswordFormFieldPredictionMap> predictions;
for (const autofill::FormStructure* form : forms) {
if (logger)
logger->LogFormStructure(Logger::STRING_SERVER_PREDICTIONS, *form);
diff --git a/chromium/components/password_manager/core/browser/password_manager.h b/chromium/components/password_manager/core/browser/password_manager.h
index e463ad56dbe..5e02b70745c 100644
--- a/chromium/components/password_manager/core/browser/password_manager.h
+++ b/chromium/components/password_manager/core/browser/password_manager.h
@@ -28,6 +28,7 @@ class PrefRegistrySyncable;
}
namespace autofill {
+struct FormData;
class FormStructure;
}
@@ -37,6 +38,7 @@ class BrowserSavePasswordProgressLogger;
class PasswordManagerClient;
class PasswordManagerDriver;
class PasswordFormManager;
+class NewPasswordFormManager;
// Per-tab password manager. Handles creation and management of UI elements,
// receiving password form data from the renderer and managing the password
@@ -55,40 +57,6 @@ class PasswordManager : public LoginModel {
explicit PasswordManager(PasswordManagerClient* client);
~PasswordManager() override;
- typedef base::Callback<void(const autofill::PasswordForm&)>
- PasswordSubmittedCallback;
-
- // There is no corresponding remove function as currently all of the
- // owners of these callbacks have sufficient lifetimes so that the callbacks
- // should always be valid when called.
- void AddSubmissionCallback(const PasswordSubmittedCallback& callback);
-
- // Called by a PasswordFormManager when it decides a form can be autofilled
- // on the page.
- void Autofill(
- password_manager::PasswordManagerDriver* driver,
- const autofill::PasswordForm& form_for_autofill,
- const std::map<base::string16, const autofill::PasswordForm*>&
- best_matches,
- const std::vector<const autofill::PasswordForm*>& federated_matches,
- const autofill::PasswordForm& preferred_match,
- bool wait_for_username) const;
-
- // Called by a PasswordFormManager when a page initially loads and it decides
- // that a form can be autofilled on the page, but a menu of account options
- // should be shown instead. Similar to Autofill() above, but does not fill; it
- // only shows a selection of accounts.
- //
- // Currently used by the fill-on-account-select experiment only. See
- // https://crbug.com/568713.
- void ShowInitialPasswordAccountSuggestions(
- password_manager::PasswordManagerDriver* driver,
- const autofill::PasswordForm& form_for_autofill,
- const std::map<base::string16, const autofill::PasswordForm*>&
- best_matches,
- const autofill::PasswordForm& preferred_match,
- bool wait_for_username) const;
-
// Called by a PasswordFormManager when it decides a HTTP auth dialog can be
// autofilled.
void AutofillHttpAuth(
@@ -204,6 +172,10 @@ class PasswordManager : public LoginModel {
pending_login_managers() {
return pending_login_managers_;
}
+
+ const std::vector<std::unique_ptr<NewPasswordFormManager>>& form_managers() {
+ return form_managers_;
+ }
#endif
NavigationEntryToCheck entry_to_check() const { return entry_to_check_; }
@@ -213,10 +185,6 @@ class PasswordManager : public LoginModel {
PasswordManagerTest,
ShouldBlockPasswordForSameOriginButDifferentSchemeTest);
- // Returns true if we can show possible usernames to users in cases where
- // the username for the form is ambigious.
- bool OtherPossibleUsernamesEnabled() const;
-
// Clones |matched_manager| and keeps it as |provisional_save_manager_|.
// |form| is saved provisionally to |provisional_save_manager_|.
void ProvisionallySaveManager(const autofill::PasswordForm& form,
@@ -246,12 +214,27 @@ class PasswordManager : public LoginModel {
// appropriate.
void OnLoginSuccessful();
- // Checks for every from in |forms| whether |pending_login_managers_| already
+ // Helper function called inside OnLoginSuccessful() to save password hash
+ // data for password reuse detection purpose.
+ void MaybeSavePasswordHash();
+
+ // Checks for every form in |forms| whether |pending_login_managers_| already
// contain a manager for that form. If not, adds a manager for each such form.
void CreatePendingLoginManagers(
password_manager::PasswordManagerDriver* driver,
const std::vector<autofill::PasswordForm>& forms);
+ // Checks for every form in |forms| whether |form_managers_| already contain a
+ // manager for that form. If not, adds a manager for each such form.
+ void CreateFormManagers(password_manager::PasswordManagerDriver* driver,
+ const std::vector<autofill::PasswordForm>& forms);
+
+ // Passes |submitted_form| to NewPasswordManager that manages it for using it
+ // after detecting submission success for saving. |driver| is needed to
+ // determine the match.
+ void ProcessSubmittedForm(const autofill::FormData& submitted_form,
+ const PasswordManagerDriver* driver);
+
// Returns the best match in |pending_login_managers_| for |form|. May return
// nullptr if no match exists.
PasswordFormManager* GetMatchingPendingManager(
@@ -281,6 +264,9 @@ class PasswordManager : public LoginModel {
// time a user submits a login form and gets to the next page.
std::unique_ptr<PasswordFormManager> provisional_save_manager_;
+ // Contains one NewPasswordFormManager per each form on the page.
+ std::vector<std::unique_ptr<NewPasswordFormManager>> form_managers_;
+
// The embedder-level client. Must outlive this class.
PasswordManagerClient* const client_;
@@ -288,9 +274,6 @@ class PasswordManager : public LoginModel {
// notification in const member functions.
mutable base::ObserverList<LoginModelObserver> observers_;
- // Callbacks to be notified when a password form has been submitted.
- std::vector<PasswordSubmittedCallback> submission_callbacks_;
-
// Records all visible forms seen during a page load, in all frames of the
// page. When the page stops loading, the password manager checks if one of
// the recorded forms matches the login form from the previous page
diff --git a/chromium/components/password_manager/core/browser/password_manager_client.h b/chromium/components/password_manager/core/browser/password_manager_client.h
index 2a63313a03f..6f39847ed68 100644
--- a/chromium/components/password_manager/core/browser/password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/password_manager_client.h
@@ -32,7 +32,7 @@ class PasswordProtectionService;
namespace password_manager {
class LogManager;
-class PasswordFormManager;
+class PasswordFormManagerForUI;
class PasswordManager;
class PasswordManagerMetricsRecorder;
class PasswordStore;
@@ -86,24 +86,24 @@ class PasswordManagerClient {
// updated. Returns true if the prompt was indeed displayed.
// There are 3 different cases when |update_password| == true:
// 1.A change password form was submitted and the user has only one stored
- // credential. Then form_to_save.pending_credentials() should correspond to
+ // credential. Then form_to_save.GetPendingCredentials() should correspond to
// the unique element from |form_to_save.best_matches_|.
// 2.A change password form was submitted and the user has more than one
// stored credential. Then we shouldn't expect anything from
- // form_to_save.pending_credentials() except correct origin, since we don't
+ // form_to_save.GetPendingCredentials() except correct origin, since we don't
// know which credentials should be updated.
// 3.A sign-in password form was submitted with a password different from
- // the stored one. In this case form_to_save.password_overridden() == true
- // and form_to_save.pending_credentials() should correspond to the credential
- // that was overidden.
+ // the stored one. In this case form_to_save.IsPasswordOverridden() == true
+ // and form_to_save.GetPendingCredentials() should correspond to the
+ // credential that was overidden.
virtual bool PromptUserToSaveOrUpdatePassword(
- std::unique_ptr<PasswordFormManager> form_to_save,
+ std::unique_ptr<PasswordFormManagerForUI> form_to_save,
bool is_update) = 0;
// Informs the embedder that the user started typing a password and a password
// prompt should be available on click on the omnibox icon.
virtual void ShowManualFallbackForSaving(
- std::unique_ptr<PasswordFormManager> form_to_save,
+ std::unique_ptr<PasswordFormManagerForUI> form_to_save,
bool has_generated_password,
bool is_update) = 0;
@@ -153,7 +153,7 @@ class PasswordManagerClient {
// Called when a password is saved in an automated fashion. Embedder may
// inform the user that this save has occured.
virtual void AutomaticPasswordSave(
- std::unique_ptr<PasswordFormManager> saved_form_manager) = 0;
+ std::unique_ptr<PasswordFormManagerForUI> saved_form_manager) = 0;
// Called when a password is autofilled. |best_matches| contains the
// PasswordForm into which a password was filled: the client may choose to
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
index fc38608f3ca..a6e6827c071 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.cc
@@ -162,19 +162,6 @@ void LogPasswordReuse(int password_length,
PASSWORD_REUSE_PASSWORD_FIELD_DETECTED_COUNT);
}
-void LogShowedHttpNotSecureExplanation() {
- base::RecordAction(base::UserMetricsAction(
- "PasswordManager_ShowedHttpNotSecureExplanation"));
-}
-
-void LogShowedFormNotSecureWarningOnCurrentNavigation() {
- // Always record 'true': this is a counter of the number of times the warning
- // is shown, to gather metrics such as the number of times the warning is
- // shown per million page loads.
- UMA_HISTOGRAM_BOOLEAN(
- "PasswordManager.ShowedFormNotSecureWarningOnCurrentNavigation", true);
-}
-
void LogContextOfShowAllSavedPasswordsShown(
ShowAllSavedPasswordsContext context) {
UMA_HISTOGRAM_ENUMERATION("PasswordManager.ShowAllSavedPasswordsShownContext",
diff --git a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
index 33ed6c37382..66b8f724c93 100644
--- a/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_metrics_util.h
@@ -50,10 +50,10 @@ enum UIDismissalReason {
CLICKED_CANCEL,
CLICKED_NEVER,
CLICKED_MANAGE,
- CLICKED_DONE,
+ CLICKED_DONE_OBSOLETE, // obsolete
CLICKED_UNBLACKLIST_OBSOLETE, // obsolete.
- CLICKED_OK,
- CLICKED_CREDENTIAL_OBSOLETE, // obsolete.
+ CLICKED_OK_OBSOLETE, // obsolete
+ CLICKED_CREDENTIAL_OBSOLETE, // obsolete.
AUTO_SIGNIN_TOAST_TIMEOUT,
AUTO_SIGNIN_TOAST_CLICKED_OBSOLETE, // obsolete.
CLICKED_BRAND_NAME,
@@ -208,7 +208,8 @@ enum class SyncPasswordHashChange {
enum class IsSyncPasswordHashSaved {
NOT_SAVED,
- SAVED,
+ SAVED_VIA_STRING_PREF,
+ SAVED_VIA_LIST_PREF,
IS_SYNC_PASSWORD_HASH_SAVED_COUNT
};
#endif
@@ -320,14 +321,6 @@ void LogPasswordReuse(int password_length,
int number_matches,
bool password_field_detected);
-// Log when the user selects the "Login not secure" warning in the password
-// autofill dropdown to show more information about the warning.
-void LogShowedHttpNotSecureExplanation();
-
-// Log that the Form-Not-Secure warning was shown. Should be called at most once
-// per main-frame navigation.
-void LogShowedFormNotSecureWarningOnCurrentNavigation();
-
// Log the context in which the "Show all saved passwords" fallback was shown.
void LogContextOfShowAllSavedPasswordsShown(
ShowAllSavedPasswordsContext context);
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
index 3d9d3073a90..0a48ae2b922 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.cc
@@ -12,6 +12,7 @@
#include "base/feature_list.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "components/password_manager/core/browser/hash_password_manager.h"
using autofill::PasswordForm;
@@ -110,6 +111,38 @@ MockPasswordStoreObserver::~MockPasswordStoreObserver() {}
MockPasswordReuseDetectorConsumer::MockPasswordReuseDetectorConsumer() {}
MockPasswordReuseDetectorConsumer::~MockPasswordReuseDetectorConsumer() {}
+
+PasswordHashDataMatcher::PasswordHashDataMatcher(
+ base::Optional<PasswordHashData> expected)
+ : expected_(expected) {}
+
+bool PasswordHashDataMatcher::MatchAndExplain(
+ base::Optional<PasswordHashData> hash_data,
+ ::testing::MatchResultListener* listener) const {
+ if (expected_ == base::nullopt)
+ return hash_data == base::nullopt;
+
+ if (hash_data == base::nullopt)
+ return false;
+
+ return expected_->username == hash_data->username &&
+ expected_->length == hash_data->length &&
+ expected_->is_gaia_password == hash_data->is_gaia_password;
+}
+
+void PasswordHashDataMatcher::DescribeTo(::std::ostream* os) const {
+ *os << "matches password hash data for " << expected_->username;
+}
+
+void PasswordHashDataMatcher::DescribeNegationTo(::std::ostream* os) const {
+ *os << "doesn't match password hash data for " << expected_->username;
+}
+
+::testing::Matcher<base::Optional<PasswordHashData>> Matches(
+ base::Optional<PasswordHashData> expected) {
+ return ::testing::MakeMatcher(new PasswordHashDataMatcher(expected));
+}
+
#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_test_utils.h b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
index d1e714c42e5..7c35735e688 100644
--- a/chromium/components/password_manager/core/browser/password_manager_test_utils.h
+++ b/chromium/components/password_manager/core/browser/password_manager_test_utils.h
@@ -89,8 +89,33 @@ class MockPasswordReuseDetectorConsumer : public PasswordReuseDetectorConsumer {
~MockPasswordReuseDetectorConsumer() override;
MOCK_METHOD4(OnReuseFound,
- void(size_t, bool, const std::vector<std::string>&, int));
+ void(size_t,
+ base::Optional<PasswordHashData>,
+ const std::vector<std::string>&,
+ int));
};
+
+// Matcher class used to compare PasswordHashData in tests.
+class PasswordHashDataMatcher
+ : public ::testing::MatcherInterface<base::Optional<PasswordHashData>> {
+ public:
+ explicit PasswordHashDataMatcher(base::Optional<PasswordHashData> expected);
+ virtual ~PasswordHashDataMatcher() {}
+
+ // ::testing::MatcherInterface overrides
+ virtual bool MatchAndExplain(base::Optional<PasswordHashData> hash_data,
+ ::testing::MatchResultListener* listener) const;
+ virtual void DescribeTo(::std::ostream* os) const;
+ virtual void DescribeNegationTo(::std::ostream* os) const;
+
+ private:
+ const base::Optional<PasswordHashData> expected_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordHashDataMatcher);
+};
+
+::testing::Matcher<base::Optional<PasswordHashData>> Matches(
+ base::Optional<PasswordHashData> expected);
#endif
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
index e58c5d7638b..1d72f8fdeec 100644
--- a/chromium/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_unittest.cc
@@ -20,6 +20,7 @@
#include "build/build_config.h"
#include "components/password_manager/core/browser/form_fetcher_impl.h"
#include "components/password_manager/core/browser/mock_password_store.h"
+#include "components/password_manager/core/browser/new_password_form_manager.h"
#include "components/password_manager/core/browser/password_autofill_manager.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_reuse_defines.h"
@@ -30,7 +31,10 @@
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "components/password_manager/core/common/password_manager_features.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "components/ukm/test_ukm_recorder.h"
+#include "components/ukm/ukm_source.h"
#include "net/cert/cert_status_flags.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -50,6 +54,8 @@ namespace {
class MockStoreResultFilter : public StubCredentialsFilter {
public:
MOCK_CONST_METHOD1(ShouldSave, bool(const autofill::PasswordForm& form));
+ MOCK_CONST_METHOD1(ShouldSavePasswordHash,
+ bool(const autofill::PasswordForm& form));
MOCK_CONST_METHOD1(ReportFormLoginSuccess,
void(const PasswordFormManager& form_manager));
};
@@ -61,6 +67,7 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
.Times(AnyNumber())
.WillRepeatedly(Return(&filter_));
ON_CALL(filter_, ShouldSave(_)).WillByDefault(Return(true));
+ ON_CALL(filter_, ShouldSavePasswordHash(_)).WillByDefault(Return(false));
}
MOCK_CONST_METHOD0(IsSavingAndFillingEnabledForCurrentPage, bool());
@@ -82,19 +89,22 @@ class MockPasswordManagerClient : public StubPasswordManagerClient {
// Workaround for std::unique_ptr<> lacking a copy constructor.
bool PromptUserToSaveOrUpdatePassword(
- std::unique_ptr<PasswordFormManager> manager,
+ std::unique_ptr<PasswordFormManagerForUI> manager,
bool update_password) override {
- PromptUserToSaveOrUpdatePasswordPtr(manager.release());
+ PromptUserToSaveOrUpdatePasswordPtr(
+ static_cast<PasswordFormManager*>(manager.release()));
return false;
}
- void ShowManualFallbackForSaving(std::unique_ptr<PasswordFormManager> manager,
- bool has_generated_password,
- bool is_update) override {
- ShowManualFallbackForSavingPtr(manager.release(), has_generated_password,
- is_update);
+ void ShowManualFallbackForSaving(
+ std::unique_ptr<PasswordFormManagerForUI> manager,
+ bool has_generated_password,
+ bool is_update) override {
+ ShowManualFallbackForSavingPtr(
+ static_cast<PasswordFormManager*>(manager.release()),
+ has_generated_password, is_update);
}
void AutomaticPasswordSave(
- std::unique_ptr<PasswordFormManager> manager) override {
+ std::unique_ptr<PasswordFormManagerForUI> manager) override {
AutomaticPasswordSaveIndicator();
}
@@ -261,13 +271,6 @@ class PasswordManagerTest : public testing::Test {
manager()->OnPasswordFormSubmitted(&driver_, form);
}
- PasswordManager::PasswordSubmittedCallback SubmissionCallback() {
- return base::Bind(&PasswordManagerTest::FormSubmitted,
- base::Unretained(this));
- }
-
- void FormSubmitted(const PasswordForm& form) { submitted_form_ = form; }
-
const GURL test_url_;
base::MessageLoop message_loop_;
scoped_refptr<MockPasswordStore> store_;
@@ -292,8 +295,7 @@ MATCHER_P(FormMatches, form, "") {
TEST_F(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
// Test that when a form only contains a "new password" field, the form gets
// saved and in password store, the new password value is saved as a current
- // password value, without specifying the password field name (so that
- // credentials from sign-up forms can be filled in login forms).
+ // password value.
std::vector<PasswordForm> observed;
PasswordForm form(MakeFormWithOnlyNewPasswordField());
observed.push_back(form);
@@ -325,6 +327,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyNewPasswordField) {
// to the password store as the current password.
PasswordForm expected_form(form);
expected_form.password_value.swap(expected_form.new_password_value);
+ expected_form.password_element.swap(expected_form.new_password_element);
EXPECT_THAT(saved_form, FormMatches(expected_form));
}
@@ -369,15 +372,13 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
// When the password store already contains credentials for a given form, new
// credentials get still added, as long as they differ in username from the
// stored ones.
- std::vector<std::unique_ptr<PasswordForm>> result;
PasswordForm existing_different(MakeSimpleForm());
existing_different.username_value = ASCIIToUTF16("google2");
- std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
- observed.push_back(form);
+ std::vector<PasswordForm> observed = {form};
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
- EXPECT_CALL(*store_, GetLogins(_, _))
+ EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(form), _))
.WillOnce(WithArg<1>(InvokeConsumer(existing_different)));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -392,6 +393,7 @@ TEST_F(PasswordManagerTest, FormSubmitNoGoodMatch) {
// Now the password manager waits for the navigation to complete.
observed.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -512,9 +514,8 @@ TEST_F(PasswordManagerTest, DontSaveAlreadySavedCredential) {
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
- std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
- observed.push_back(form);
+ std::vector<PasswordForm> observed = {form};
EXPECT_CALL(*store_, GetLogins(_, _))
.WillOnce(WithArg<1>(InvokeConsumer(form)));
EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
@@ -531,7 +532,7 @@ TEST_F(PasswordManagerTest, DontSaveAlreadySavedCredential) {
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->ShowManualFallbackForSaving(&driver_, incomplete_match);
ASSERT_TRUE(form_manager_to_save);
- EXPECT_THAT(form_manager_to_save->pending_credentials(),
+ EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
FormMatches(incomplete_match));
base::UserActionTester user_action_tester;
@@ -548,12 +549,42 @@ TEST_F(PasswordManagerTest, DontSaveAlreadySavedCredential) {
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, UpdateLogin(_));
observed.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
EXPECT_EQ(1,
user_action_tester.GetActionCount("PasswordManager_LoginPassed"));
}
+// Tests that on Chrome sign-in form credentials are not saved.
+TEST_F(PasswordManagerTest, DoNotSaveOnChromeSignInForm) {
+ EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
+ .WillRepeatedly(Return(true));
+
+ PasswordForm form(MakeSimpleForm());
+ form.is_gaia_with_skip_save_password_form = true;
+ std::vector<PasswordForm> observed = {form};
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+
+ EXPECT_CALL(*client_.GetStoreResultFilter(), ShouldSave(_))
+ .WillRepeatedly(Return(false));
+ // The user is typing a credential. No fallback should be available.
+ PasswordForm typed_credentials(form);
+ typed_credentials.password_value = ASCIIToUTF16("pw");
+ EXPECT_CALL(client_, ShowManualFallbackForSavingPtr(_, _, _)).Times(0);
+ manager()->ShowManualFallbackForSaving(&driver_, form);
+
+ // The user submits the form. No prompt should pop up.
+ OnPasswordFormSubmitted(form);
+ EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
+ observed.clear();
+ manager()->DidNavigateMainFrame();
+ manager()->OnPasswordFormsRendered(&driver_, observed, true);
+}
+
// Tests that a UKM metric "Login Passed" is sent when the submitted credentials
// are already in the store and OnPasswordFormsParsed is called multiple times.
TEST_F(PasswordManagerTest,
@@ -612,9 +643,8 @@ TEST_F(PasswordManagerTest, FormSeenThenLeftPage) {
TEST_F(PasswordManagerTest, FormSubmit) {
// Test that a plain form submit results in offering to save passwords.
- std::vector<PasswordForm> observed;
PasswordForm form(MakeSimpleForm());
- observed.push_back(form);
+ std::vector<PasswordForm> observed = {form};
EXPECT_CALL(*store_, GetLogins(_, _))
.WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
@@ -633,7 +663,6 @@ TEST_F(PasswordManagerTest, FormSubmit) {
observed.clear();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
- EXPECT_FALSE(manager()->IsPasswordFieldDetectedOnPage());
// Simulate saving the form, as if the info bar was accepted.
EXPECT_CALL(*store_, AddLogin(FormMatches(form)));
@@ -749,18 +778,6 @@ TEST_F(PasswordManagerTest, FillPasswordsOnDisabledManager) {
manager()->OnPasswordFormsParsed(&driver_, observed);
}
-TEST_F(PasswordManagerTest, SubmissionCallbackTest) {
- manager()->AddSubmissionCallback(SubmissionCallback());
- PasswordForm form = MakeSimpleForm();
- // Prefs are needed for failure logging about having no matching observed
- // form.
- EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
- EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
- .WillRepeatedly(Return(true));
- OnPasswordFormSubmitted(form);
- EXPECT_EQ(form, submitted_form_);
-}
-
TEST_F(PasswordManagerTest, PasswordFormReappearance) {
// If the password form reappears after submit, PasswordManager should deduce
// that the login failed and not offer saving.
@@ -803,7 +820,10 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotSaved) {
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_)).Times(0);
EXPECT_CALL(*store_, AddLogin(_)).Times(0);
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
- EXPECT_CALL(*store_, SaveSyncPasswordHash(form.password_value, _));
+ ON_CALL(*client_.GetStoreResultFilter(), ShouldSavePasswordHash(_))
+ .WillByDefault(Return(true));
+ EXPECT_CALL(*store_,
+ SaveSyncPasswordHash("googleuser", form.password_value, _));
#endif
// Prefs are needed for failure logging about sync credentials.
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
@@ -881,7 +901,10 @@ TEST_F(PasswordManagerTest, SyncCredentialsNotDroppedIfUpToDate) {
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
- EXPECT_CALL(*store_, SaveSyncPasswordHash(form.password_value, _));
+ ON_CALL(*client_.GetStoreResultFilter(), ShouldSavePasswordHash(_))
+ .WillByDefault(Return(true));
+ EXPECT_CALL(*store_,
+ SaveSyncPasswordHash("googleuser", form.password_value, _));
#endif
manager()->ProvisionallySavePassword(form, nullptr);
@@ -917,7 +940,10 @@ TEST_F(PasswordManagerTest, SyncCredentialsDroppedWhenObsolete) {
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
- EXPECT_CALL(*store_, SaveSyncPasswordHash(ASCIIToUTF16("n3w passw0rd"), _));
+ ON_CALL(*client_.GetStoreResultFilter(), ShouldSavePasswordHash(_))
+ .WillByDefault(Return(true));
+ EXPECT_CALL(*store_, SaveSyncPasswordHash("googleuser",
+ ASCIIToUTF16("n3w passw0rd"), _));
#endif
manager()->ProvisionallySavePassword(updated_form, nullptr);
@@ -1082,7 +1108,7 @@ TEST_F(PasswordManagerTest, AttemptedSavePasswordSameOriginInsecureScheme) {
// Make sure that the form saved by the user is indeed the secure form.
ASSERT_TRUE(form_manager_to_save);
- EXPECT_THAT(form_manager_to_save->pending_credentials(),
+ EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
FormMatches(secure_form));
}
@@ -1119,7 +1145,8 @@ TEST_F(PasswordManagerTest, DoNotSaveWithEmptyNewPasswordAndNonemptyPassword) {
ASSERT_TRUE(form_manager_to_save);
EXPECT_EQ(form.password_value,
PasswordFormManager::PasswordToSave(
- form_manager_to_save->pending_credentials()));
+ form_manager_to_save->GetPendingCredentials())
+ .first);
}
TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
@@ -1147,6 +1174,7 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
// Now the password manager waits for the navigation to complete.
observed.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1156,17 +1184,85 @@ TEST_F(PasswordManagerTest, FormSubmitWithOnlyPasswordField) {
form_manager_to_save->Save();
}
-TEST_F(PasswordManagerTest, FillPasswordOnManyFrames) {
- // A password form should be filled in all frames it appears in.
- PasswordForm form(MakeSimpleForm()); // The observed and saved form.
+// Test that if there are two "similar" forms in different frames, both get
+// filled. This means slightly different things depending on whether the
+// kNewPasswordFormParsing feature is enabled or not, so it is covered by two
+// tests below.
+
+// If kNewPasswordFormParsing is enabled, then "similar" is governed by
+// NewPasswordFormManager::DoesManage, which in turn delegates to the unique
+// renderer ID of the forms being the same. Note, however, that such ID is only
+// unique within one renderer process. If different frames on the page are
+// rendered by different processes, two unrelated forms can end up with the same
+// ID. The test checks that nevertheless each of them gets assigned its own
+// NewPasswordFormManager and filled as expected.
+TEST_F(PasswordManagerTest, FillPasswordOnManyFrames_SameId) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kNewPasswordFormParsing);
+
+ // Two unrelated forms...
+ FormData form_data;
+ form_data.origin = GURL("http://www.google.com/a/LoginAuth");
+ form_data.action = GURL("http://www.google.com/a/Login");
+ form_data.fields.resize(2);
+ form_data.fields[0].name = ASCIIToUTF16("Email");
+ form_data.fields[0].value = ASCIIToUTF16("googleuser");
+ form_data.fields[0].form_control_type = "text";
+ form_data.fields[1].name = ASCIIToUTF16("Passwd");
+ form_data.fields[1].value = ASCIIToUTF16("p4ssword");
+ form_data.fields[1].form_control_type = "password";
+ PasswordForm first_form;
+ first_form.form_data = form_data;
+
+ form_data.origin = GURL("http://www.example.com/");
+ form_data.action = GURL("http://www.example.com/");
+ form_data.fields[0].name = ASCIIToUTF16("User");
+ form_data.fields[0].value = ASCIIToUTF16("exampleuser");
+ form_data.fields[1].name = ASCIIToUTF16("Pwd");
+ form_data.fields[1].value = ASCIIToUTF16("1234");
+ PasswordForm second_form;
+ second_form.form_data = form_data;
+
+ // Make the forms be "similar".
+ first_form.form_data.unique_renderer_id =
+ second_form.form_data.unique_renderer_id = 7654;
+
+ // The following expectation covers the calls from the old
+ // PasswordFormManager.
+ EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(PasswordForm()), _))
+ .Times(2);
+
+ // Observe the form in the first frame.
+ EXPECT_CALL(*store_,
+ GetLogins(PasswordStore::FormDigest(first_form.form_data), _))
+ .WillOnce(WithArg<1>(InvokeConsumer(first_form)));
+ EXPECT_CALL(driver_, FillPasswordForm(_));
+ manager()->OnPasswordFormsParsed(&driver_, {first_form});
+
+ // Observe the form in the second frame.
+ MockPasswordManagerDriver driver_b;
+ EXPECT_CALL(*store_,
+ GetLogins(PasswordStore::FormDigest(second_form.form_data), _))
+ .WillOnce(WithArg<1>(InvokeConsumer(second_form)));
+ EXPECT_CALL(driver_b, FillPasswordForm(_));
+ manager()->OnPasswordFormsParsed(&driver_b, {second_form});
+}
+
+// If kNewPasswordFormParsing is disabled, "similar" is governed by
+// PasswordFormManager::DoesManage and is related to actual similarity of the
+// forms, including having the same signon realm (and hence origin). Should a
+// page have two frames with the same origin and a form, and those two forms be
+// similar, then it is important to ensure that the single governing
+// PasswordFormManager knows about both PasswordManagerDriver instances and
+// instructs them to fill.
+TEST_F(PasswordManagerTest, FillPasswordOnManyFrames_SameForm) {
+ PasswordForm same_form = MakeSimpleForm();
// Observe the form in the first frame.
- std::vector<PasswordForm> observed;
- observed.push_back(form);
EXPECT_CALL(driver_, FillPasswordForm(_));
EXPECT_CALL(*store_, GetLogins(_, _))
- .WillOnce(WithArg<1>(InvokeConsumer(form)));
- manager()->OnPasswordFormsParsed(&driver_, observed);
+ .WillOnce(WithArg<1>(InvokeConsumer(same_form)));
+ manager()->OnPasswordFormsParsed(&driver_, {same_form});
// Now the form will be seen the second time, in a different frame. The driver
// for that frame should be told to fill it, but the store should not be asked
@@ -1174,7 +1270,7 @@ TEST_F(PasswordManagerTest, FillPasswordOnManyFrames) {
MockPasswordManagerDriver driver_b;
EXPECT_CALL(driver_b, FillPasswordForm(_));
EXPECT_CALL(*store_, GetLogins(_, _)).Times(0);
- manager()->OnPasswordFormsParsed(&driver_b, observed);
+ manager()->OnPasswordFormsParsed(&driver_b, {same_form});
}
TEST_F(PasswordManagerTest, SameDocumentNavigation) {
@@ -1279,11 +1375,9 @@ TEST_F(PasswordManagerTest, SavingSignupForms_NoHTMLMatch) {
// PasswordManager observed two forms, and should have associate the saved one
// with the observed form with a matching action.
EXPECT_EQ(form.action, form_to_save.action);
- // Password values are always saved as the current password value, but the
- // current password field name should be empty if the value comes from the new
- // password field.
+ // Password values are always saved as the current password value.
EXPECT_EQ(submitted_form.new_password_value, form_to_save.password_value);
- EXPECT_TRUE(form_to_save.password_element.empty());
+ EXPECT_EQ(submitted_form.new_password_element, form_to_save.password_element);
}
TEST_F(PasswordManagerTest, SavingSignupForms_NoActionMatch) {
@@ -1406,6 +1500,7 @@ TEST_F(PasswordManagerTest, FormSubmittedUnchangedNotifiesClient) {
// Now the password manager waits for the navigation to complete.
observed.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1683,9 +1778,8 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
for (bool found_matched_logins_in_store : kFalseTrue) {
SCOPED_TRACE(testing::Message("found_matched_logins_in_store = ")
<< found_matched_logins_in_store);
- std::vector<PasswordForm> observed;
PasswordForm form(MakeFormWithOnlyNewPasswordField());
- observed.push_back(form);
+ std::vector<PasswordForm> observed = {form};
if (found_matched_logins_in_store) {
EXPECT_CALL(*store_, GetLogins(_, _))
.WillRepeatedly(WithArg<1>(InvokeConsumer(form)));
@@ -1717,6 +1811,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form));
OnPasswordFormSubmitted(form);
observed.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -1725,7 +1820,7 @@ TEST_F(PasswordManagerTest, PasswordGenerationPresavePasswordAndLogin) {
// Credentials should be updated only when the user explicitly chooses.
ASSERT_TRUE(form_manager);
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, form));
- form_manager->Update(form_manager->pending_credentials());
+ form_manager->Update(form_manager->GetPendingCredentials());
}
}
}
@@ -1776,7 +1871,8 @@ TEST_F(PasswordManagerTest, ForceSavingPasswords) {
ASSERT_TRUE(form_manager_to_save);
EXPECT_EQ(form.password_value,
PasswordFormManager::PasswordToSave(
- form_manager_to_save->pending_credentials()));
+ form_manager_to_save->GetPendingCredentials())
+ .first);
}
// Forcing Chrome to save an empty passwords should fail without a crash.
@@ -1816,7 +1912,7 @@ TEST_F(PasswordManagerTest, UpdateFormManagers) {
// The first GetLogins should have fired, but to unblock the second, we need
// to first send a response from the store (to be ignored).
- static_cast<FormFetcherImpl*>(form_manager->form_fetcher())
+ static_cast<FormFetcherImpl*>(form_manager->GetFormFetcher())
->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
EXPECT_CALL(*store_, GetLogins(_, _));
manager()->UpdateFormManagers();
@@ -1880,6 +1976,7 @@ TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
EXPECT_CALL(*store_, UpdateLoginWithPrimaryKey(_, _)).Times(0);
observed_forms.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed_forms);
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
EXPECT_THAT(saved_form, FormMatches(android_form));
@@ -1892,15 +1989,12 @@ TEST_F(PasswordManagerTest, AutofillingOfAffiliatedCredentials) {
TEST_F(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
PasswordForm android_form(MakeAndroidCredential());
PasswordForm observed_form(MakeSimpleForm());
- std::vector<PasswordForm> observed_forms;
- observed_forms.push_back(observed_form);
+ std::vector<PasswordForm> observed_forms = {observed_form};
- autofill::PasswordFormFillData form_data;
- EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&form_data));
+ EXPECT_CALL(driver_, FillPasswordForm(_)).Times(2);
EXPECT_CALL(*store_, GetLogins(_, _))
.WillOnce(WithArg<1>(InvokeConsumer(android_form)));
manager()->OnPasswordFormsParsed(&driver_, observed_forms);
- observed_forms.clear();
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
@@ -1916,6 +2010,7 @@ TEST_F(PasswordManagerTest, UpdatePasswordOfAffiliatedCredential) {
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
observed_forms.clear();
+ manager()->DidNavigateMainFrame();
manager()->OnPasswordFormsParsed(&driver_, observed_forms);
manager()->OnPasswordFormsRendered(&driver_, observed_forms, true);
@@ -1937,11 +2032,10 @@ TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
PasswordForm form(MakeFormWithOnlyNewPasswordField());
form.username_element.clear();
form.username_value.clear();
- std::vector<PasswordForm> observed;
- observed.push_back(form);
+ std::vector<PasswordForm> observed = {form};
// Emulate page load.
- EXPECT_CALL(*store_, GetLogins(_, _)).Times(2);
+ EXPECT_CALL(*store_, GetLogins(PasswordStore::FormDigest(form), _));
manager()->OnPasswordFormsParsed(&driver_, observed);
manager()->OnPasswordFormsRendered(&driver_, observed, true);
ASSERT_EQ(1u, manager()->pending_login_managers().size());
@@ -1952,7 +2046,7 @@ TEST_F(PasswordManagerTest, ClearedFieldsSuccessCriteria) {
PasswordFormManager* form_manager =
manager()->pending_login_managers().front().get();
ASSERT_TRUE(form_manager);
- static_cast<FormFetcherImpl*>(form_manager->form_fetcher())
+ static_cast<FormFetcherImpl*>(form_manager->GetFormFetcher())
->OnGetPasswordStoreResults(std::vector<std::unique_ptr<PasswordForm>>());
OnPasswordFormSubmitted(form);
@@ -1993,7 +2087,7 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NoUsername) {
client_.FilterAllResultsForSaving();
// Check that no sync credential password hash is saved.
- EXPECT_CALL(*store_, SaveSyncPasswordHash(_, _)).Times(0);
+ EXPECT_CALL(*store_, SaveSyncPasswordHash(_, _, _)).Times(0);
OnPasswordFormSubmitted(form);
observed.clear();
manager()->OnPasswordFormsRendered(&driver_, observed, true);
@@ -2015,7 +2109,7 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NotSyncCredentials) {
// Check that no sync credential password hash is saved since these
// credentials are eligible for saving.
- EXPECT_CALL(*store_, SaveSyncPasswordHash(_, _)).Times(0);
+ EXPECT_CALL(*store_, SaveSyncPasswordHash(_, _, _)).Times(0);
std::unique_ptr<PasswordFormManager> form_manager_to_save;
EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
@@ -2028,6 +2122,8 @@ TEST_F(PasswordManagerTest, NotSavingSyncPasswordHash_NotSyncCredentials) {
#endif
TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+
EXPECT_CALL(client_, IsSavingAndFillingEnabledForCurrentPage())
.WillRepeatedly(Return(true));
@@ -2048,7 +2144,7 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->ShowManualFallbackForSaving(&driver_, form);
ASSERT_TRUE(form_manager_to_save);
- EXPECT_THAT(form_manager_to_save->pending_credentials(), FormMatches(form));
+ EXPECT_THAT(form_manager_to_save->GetPendingCredentials(), FormMatches(form));
// The username of the stored form is different, there should be save bubble.
PasswordForm new_form = form;
@@ -2057,12 +2153,28 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving) {
.WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
manager()->ShowManualFallbackForSaving(&driver_, new_form);
ASSERT_TRUE(form_manager_to_save);
- EXPECT_THAT(form_manager_to_save->pending_credentials(),
+ EXPECT_THAT(form_manager_to_save->GetPendingCredentials(),
FormMatches(new_form));
// Hide the manual fallback.
EXPECT_CALL(client_, HideManualFallbackForSaving());
manager()->HideManualFallbackForSaving();
+
+ // Two PasswordFormManagers instances hold references to a shared
+ // PasswordFormMetrics recorder. These need to be freed to flush the metrics
+ // into the test_ukm_recorder.
+ manager_.reset();
+ form_manager_to_save.reset();
+
+ // Verify that the last state is recorded.
+ std::vector<const ukm::mojom::UkmEntry*> ukm_entries =
+ test_ukm_recorder.GetEntriesByName(
+ ukm::builders::PasswordForm::kEntryName);
+ ASSERT_EQ(1u, ukm_entries.size());
+ test_ukm_recorder.ExpectEntryMetric(
+ ukm_entries[0],
+ ukm::builders::PasswordForm::kSaving_ShowedManualFallbackForSavingName,
+ 1);
}
// Tests that the manual fallback for saving isn't shown if there is no response
@@ -2114,7 +2226,7 @@ TEST_F(PasswordManagerTest, ManualFallbackForSaving_GeneratedPassword) {
manager()->OnPresaveGeneratedPassword(form);
manager()->ShowManualFallbackForSaving(&driver_, form);
ASSERT_TRUE(form_manager_to_save);
- EXPECT_THAT(form_manager_to_save->pending_credentials(), FormMatches(form));
+ EXPECT_THAT(form_manager_to_save->GetPendingCredentials(), FormMatches(form));
// A user edits the generated password. And again it causes password presaving
// and showing manual fallback.
@@ -2244,10 +2356,12 @@ TEST_F(PasswordManagerTest, SaveSyncPasswordHashOnChangePasswordPage) {
.WillRepeatedly(Return(true));
EXPECT_CALL(client_, GetPrefs()).WillRepeatedly(Return(nullptr));
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+ ON_CALL(*client_.GetStoreResultFilter(), ShouldSavePasswordHash(_))
+ .WillByDefault(Return(true));
EXPECT_CALL(
*store_,
SaveSyncPasswordHash(
- form.new_password_value,
+ "googleuser", form.new_password_value,
metrics_util::SyncPasswordHashChange::CHANGED_IN_CONTENT_AREA));
#endif
client_.FilterAllResultsForSaving();
@@ -2315,4 +2429,26 @@ TEST_F(PasswordManagerTest, CertErrorReported) {
}
}
+TEST_F(PasswordManagerTest, CreatingFormManagers) {
+ // Add the NewPasswordFormParsing feature.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndEnableFeature(features::kNewPasswordFormParsing);
+
+ PasswordForm form(MakeSimpleForm());
+ std::vector<PasswordForm> observed;
+ observed.push_back(form);
+ EXPECT_CALL(*store_, GetLogins(_, _))
+ .WillRepeatedly(WithArg<1>(InvokeEmptyConsumerWithForms()));
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ // Check that the form manager is created.
+ EXPECT_EQ(1u, manager()->form_managers().size());
+ EXPECT_TRUE(manager()->form_managers()[0]->DoesManage(form.form_data,
+ client_.GetDriver()));
+
+ // Check that receiving the same form the second time does not lead to
+ // creating new form manager.
+ manager()->OnPasswordFormsParsed(&driver_, observed);
+ EXPECT_EQ(1u, manager()->form_managers().size());
+}
+
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.cc b/chromium/components/password_manager/core/browser/password_manager_util.cc
index 6ed8101cff9..8471ae39eb4 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util.cc
@@ -21,6 +21,8 @@
#include "components/prefs/pref_service.h"
#include "components/sync/driver/sync_service.h"
+using autofill::PasswordForm;
+
namespace password_manager_util {
namespace {
@@ -72,6 +74,15 @@ void StartCleaningBlacklisted(
new BlacklistedCredentialsCleaner(store.get(), prefs);
}
+// Return true if
+// 1.|lhs| is non-PSL match, |rhs| is PSL match or
+// 2.|lhs| and |rhs| have the same value of |is_public_suffix_match|, and |lhs|
+// is preferred while |rhs| is not preferred.
+bool IsBetterMatch(const PasswordForm* lhs, const PasswordForm* rhs) {
+ return std::make_pair(!lhs->is_public_suffix_match, lhs->preferred) >
+ std::make_pair(!rhs->is_public_suffix_match, rhs->preferred);
+}
+
} // namespace
password_manager::PasswordSyncState GetPasswordSyncState(
@@ -202,4 +213,37 @@ void CleanUserDataInBlacklistedCredentials(
}
}
+void FindBestMatches(
+ std::vector<const PasswordForm*> matches,
+ std::map<base::string16, const PasswordForm*>* best_matches,
+ std::vector<const PasswordForm*>* not_best_matches,
+ const PasswordForm** preferred_match) {
+ DCHECK(std::all_of(
+ matches.begin(), matches.end(),
+ [](const PasswordForm* match) { return !match->blacklisted_by_user; }));
+ DCHECK(best_matches);
+ DCHECK(not_best_matches);
+ DCHECK(preferred_match);
+
+ *preferred_match = nullptr;
+ best_matches->clear();
+ not_best_matches->clear();
+
+ if (matches.empty())
+ return;
+
+ // Sort matches using IsBetterMatch predicate.
+ std::sort(matches.begin(), matches.end(), IsBetterMatch);
+ for (const auto* match : matches) {
+ const base::string16& username = match->username_value;
+ // The first match for |username| in the sorted array is best match.
+ if (best_matches->find(username) == best_matches->end())
+ best_matches->insert(std::make_pair(username, match));
+ else
+ not_best_matches->push_back(match);
+ }
+
+ *preferred_match = *matches.begin();
+}
+
} // namespace password_manager_util
diff --git a/chromium/components/password_manager/core/browser/password_manager_util.h b/chromium/components/password_manager/core/browser/password_manager_util.h
index 07620f0e8d8..c989c9239fb 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util.h
+++ b/chromium/components/password_manager/core/browser/password_manager_util.h
@@ -5,10 +5,12 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_UTIL_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_UTIL_H_
+#include <map>
#include <memory>
#include <vector>
#include "base/callback.h"
+#include "base/strings/string16.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "ui/gfx/native_widget_types.h"
@@ -81,6 +83,18 @@ void CleanUserDataInBlacklistedCredentials(
PrefService* prefs,
int delay_in_seconds);
+// Given all non-blacklisted |matches|, finds and populates
+// |best_matches_|, |preferred_match_| and |non_best_matches_| accordingly.
+// For comparing credentials the following rule is used: non-psl match is better
+// than psl match, preferred match is better than non-preferred match. In case
+// of tie, an arbitrary credential from the tied ones is chosen for
+// |best_matches| and preferred_match.
+void FindBestMatches(
+ std::vector<const autofill::PasswordForm*> matches,
+ std::map<base::string16, const autofill::PasswordForm*>* best_matches,
+ std::vector<const autofill::PasswordForm*>* not_best_matches,
+ const autofill::PasswordForm** preferred_match);
+
} // namespace password_manager_util
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_MANAGER_UTIL_H_
diff --git a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
index 3301b891d26..6918382e69d 100644
--- a/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_manager_util_unittest.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
+#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
@@ -17,6 +18,8 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using autofill::PasswordForm;
+
namespace password_manager_util {
namespace {
@@ -128,4 +131,119 @@ TEST(PasswordManagerUtil, CleanBlacklistedUsernamePassword) {
password_store->ShutdownOnUIThread();
}
+TEST(PasswordManagerUtil, FindBestMatches) {
+ const int kNotFound = -1;
+ struct TestMatch {
+ bool is_psl_match;
+ bool preferred;
+ std::string username;
+ };
+ struct TestCase {
+ const char* description;
+ std::vector<TestMatch> matches;
+ int expected_preferred_match_index;
+ std::map<std::string, size_t> expected_best_matches_indices;
+ } test_cases[] = {
+ {"Empty matches", {}, kNotFound, {}},
+ {"1 preferred non-psl match",
+ {{.is_psl_match = false, .preferred = true, .username = "u"}},
+ 0,
+ {{"u", 0}}},
+ {"1 non-preferred psl match",
+ {{.is_psl_match = true, .preferred = false, .username = "u"}},
+ 0,
+ {{"u", 0}}},
+ {"2 matches with the same username",
+ {{.is_psl_match = false, .preferred = false, .username = "u"},
+ {.is_psl_match = false, .preferred = true, .username = "u"}},
+ 1,
+ {{"u", 1}}},
+ {"2 matches with different usernames, preferred taken",
+ {{.is_psl_match = false, .preferred = false, .username = "u1"},
+ {.is_psl_match = false, .preferred = true, .username = "u2"}},
+ 1,
+ {{"u1", 0}, {"u2", 1}}},
+ {"2 matches with different usernames, non-psl much taken",
+ {{.is_psl_match = false, .preferred = false, .username = "u1"},
+ {.is_psl_match = true, .preferred = true, .username = "u2"}},
+ 0,
+ {{"u1", 0}, {"u2", 1}}},
+ {"8 matches, 3 usernames",
+ {{.is_psl_match = false, .preferred = false, .username = "u2"},
+ {.is_psl_match = true, .preferred = false, .username = "u3"},
+ {.is_psl_match = true, .preferred = false, .username = "u1"},
+ {.is_psl_match = false, .preferred = true, .username = "u3"},
+ {.is_psl_match = true, .preferred = false, .username = "u1"},
+ {.is_psl_match = false, .preferred = false, .username = "u2"},
+ {.is_psl_match = true, .preferred = true, .username = "u3"},
+ {.is_psl_match = false, .preferred = false, .username = "u1"}},
+ 3,
+ {{"u1", 7}, {"u2", 0}, {"u3", 3}}},
+
+ };
+
+ for (const TestCase& test_case : test_cases) {
+ SCOPED_TRACE(testing::Message("Test description: ")
+ << test_case.description);
+ // Convert TestMatch to PasswordForm.
+ std::vector<PasswordForm> owning_matches;
+ for (const TestMatch match : test_case.matches) {
+ PasswordForm form;
+ form.is_public_suffix_match = match.is_psl_match;
+ form.preferred = match.preferred;
+ form.username_value = base::ASCIIToUTF16(match.username);
+ owning_matches.push_back(form);
+ }
+ std::vector<const PasswordForm*> matches;
+ for (const PasswordForm& match : owning_matches)
+ matches.push_back(&match);
+
+ std::map<base::string16, const PasswordForm*> best_matches;
+ std::vector<const PasswordForm*> not_best_matches;
+ const PasswordForm* preferred_match = nullptr;
+
+ FindBestMatches(matches, &best_matches, &not_best_matches,
+ &preferred_match);
+
+ if (test_case.expected_preferred_match_index == kNotFound) {
+ // Case of empty |matches|.
+ EXPECT_FALSE(preferred_match);
+ EXPECT_TRUE(best_matches.empty());
+ EXPECT_TRUE(not_best_matches.empty());
+ } else {
+ // Check |preferred_match|.
+ EXPECT_EQ(matches[test_case.expected_preferred_match_index],
+ preferred_match);
+ // Check best matches.
+ ASSERT_EQ(test_case.expected_best_matches_indices.size(),
+ best_matches.size());
+
+ for (const auto& username_match : best_matches) {
+ std::string username = base::UTF16ToUTF8(username_match.first);
+ ASSERT_NE(test_case.expected_best_matches_indices.end(),
+ test_case.expected_best_matches_indices.find(username));
+ size_t expected_index =
+ test_case.expected_best_matches_indices.at(username);
+ size_t actual_index = std::distance(
+ matches.begin(),
+ std::find(matches.begin(), matches.end(), username_match.second));
+ EXPECT_EQ(expected_index, actual_index);
+ }
+
+ // Check non-best matches.
+ ASSERT_EQ(matches.size(), best_matches.size() + not_best_matches.size());
+ for (const PasswordForm* form : not_best_matches) {
+ // A non-best match form must not be in |best_matches|.
+ EXPECT_NE(best_matches[form->username_value], form);
+
+ matches.erase(std::remove(matches.begin(), matches.end(), form),
+ matches.end());
+ }
+ // Expect that all non-best matches were found in |matches| and only best
+ // matches left.
+ EXPECT_EQ(best_matches.size(), matches.size());
+ }
+ }
+}
+
} // namespace password_manager_util
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
index 0fff42d45d4..ac53aa59813 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -74,11 +74,13 @@ void PasswordReuseDetectionManager::OnKeyPressed(const base::string16& text) {
void PasswordReuseDetectionManager::OnReuseFound(
size_t password_length,
- bool matches_sync_password,
+ base::Optional<PasswordHashData> reused_protected_password_hash,
const std::vector<std::string>& matching_domains,
int saved_passwords) {
reuse_on_this_page_was_found_ = true;
std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
+ bool matches_sync_password = reused_protected_password_hash &&
+ reused_protected_password_hash->is_gaia_password;
if (password_manager_util::IsLoggingActive(client_)) {
logger.reset(
new BrowserSavePasswordProgressLogger(client_->GetLogManager()));
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
index 02eb8546e92..990c59e77c9 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager.h
@@ -30,10 +30,11 @@ class PasswordReuseDetectionManager : public PasswordReuseDetectorConsumer {
void OnKeyPressed(const base::string16& text);
// PasswordReuseDetectorConsumer implementation
- void OnReuseFound(size_t password_length,
- bool matches_sync_password,
- const std::vector<std::string>& matching_domains,
- int saved_passwords) override;
+ void OnReuseFound(
+ size_t password_length,
+ base::Optional<PasswordHashData> reused_protected_password_hash,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) override;
void SetClockForTesting(base::Clock* clock);
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
index 094c0583080..7e7efda3667 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detection_manager_unittest.cc
@@ -137,7 +137,7 @@ TEST_F(PasswordReuseDetectionManagerTest, NoReuseCheckingAfterReuseFound) {
PasswordReuseDetectionManager manager(&client_);
// Simulate that reuse found.
- manager.OnReuseFound(0ul, true, {}, 0);
+ manager.OnReuseFound(0ul, base::nullopt, {}, 0);
// Expect no checking of reuse.
EXPECT_CALL(*store_, CheckReuse(_, _, _)).Times(0);
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector.cc b/chromium/components/password_manager/core/browser/password_reuse_detector.cc
index cf8cbb9fbe8..5fda9755626 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector.cc
@@ -11,6 +11,7 @@
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_reuse_detector_consumer.h"
#include "components/password_manager/core/browser/psl_matching_helper.h"
+#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "url/origin.h"
@@ -34,6 +35,23 @@ bool IsSuffix(const base::string16& str,
str.rbegin());
}
+// Helper function to returns matching PasswordHashData from a list.
+base::Optional<PasswordHashData> FindPasswordReuse(
+ const base::string16& input,
+ const std::vector<PasswordHashData>& password_hash_list) {
+ for (const PasswordHashData& hash_data : password_hash_list) {
+ if (input.size() < hash_data.length)
+ continue;
+ size_t offset = input.size() - hash_data.length;
+ base::string16 reuse_candidate = input.substr(offset);
+ if (HashPasswordManager::CalculatePasswordHash(
+ reuse_candidate, hash_data.salt) == hash_data.hash) {
+ return hash_data;
+ }
+ }
+ return base::nullopt;
+}
+
} // namespace
bool ReverseStringLess::operator()(const base::string16& lhs,
@@ -42,7 +60,7 @@ bool ReverseStringLess::operator()(const base::string16& lhs,
rhs.rend());
}
-PasswordReuseDetector::PasswordReuseDetector() {}
+PasswordReuseDetector::PasswordReuseDetector() : prefs_(nullptr) {}
PasswordReuseDetector::~PasswordReuseDetector() {}
@@ -69,46 +87,82 @@ void PasswordReuseDetector::CheckReuse(
if (input.size() < kMinPasswordLengthToCheck)
return;
- size_t sync_reused_password_length = CheckSyncPasswordReuse(input, domain);
+ base::Optional<PasswordHashData> reused_gaia_password_hash =
+ CheckGaiaPasswordReuse(input, domain);
+ size_t gaia_reused_password_length = reused_gaia_password_hash.has_value()
+ ? reused_gaia_password_hash->length
+ : 0;
+
+ base::Optional<PasswordHashData> reused_enterprise_password_hash =
+ CheckNonGaiaEnterprisePasswordReuse(input, domain);
+ size_t enterprise_reused_password_length =
+ reused_enterprise_password_hash.has_value()
+ ? reused_enterprise_password_hash->length
+ : 0;
std::vector<std::string> matching_domains;
size_t saved_reused_password_length =
CheckSavedPasswordReuse(input, domain, &matching_domains);
size_t max_reused_password_length =
- std::max(sync_reused_password_length, saved_reused_password_length);
+ std::max({saved_reused_password_length, gaia_reused_password_length,
+ enterprise_reused_password_length});
+
+ if (max_reused_password_length == 0)
+ return;
- if (max_reused_password_length != 0) {
- consumer->OnReuseFound(
- max_reused_password_length,
- sync_reused_password_length != 0 /* matches_sync_password */,
- matching_domains, saved_passwords_);
+ if (gaia_reused_password_length == 0 &&
+ enterprise_reused_password_length == 0) {
+ consumer->OnReuseFound(max_reused_password_length, base::nullopt,
+ matching_domains, saved_passwords_);
+ } else if (gaia_reused_password_length > enterprise_reused_password_length) {
+ consumer->OnReuseFound(max_reused_password_length,
+ reused_gaia_password_hash, matching_domains,
+ saved_passwords_);
+ } else {
+ consumer->OnReuseFound(max_reused_password_length,
+ reused_enterprise_password_hash, matching_domains,
+ saved_passwords_);
}
}
-size_t PasswordReuseDetector::CheckSyncPasswordReuse(
+base::Optional<PasswordHashData> PasswordReuseDetector::CheckGaiaPasswordReuse(
const base::string16& input,
const std::string& domain) {
- if (!sync_password_data_.has_value())
- return 0;
+ if (!gaia_password_hash_data_list_.has_value() ||
+ gaia_password_hash_data_list_->empty()) {
+ return base::nullopt;
+ }
+ // Skips password reuse check if |domain| matches Gaia origin.
const Origin gaia_origin =
Origin::Create(GaiaUrls::GetInstance()->gaia_url().GetOrigin());
if (Origin::Create(GURL(domain)).IsSameOriginWith(gaia_origin))
- return 0;
+ return base::nullopt;
- if (input.size() < sync_password_data_->length)
- return 0;
+ return FindPasswordReuse(input, gaia_password_hash_data_list_.value());
+}
- size_t offset = input.size() - sync_password_data_->length;
- base::string16 reuse_candidate = input.substr(offset);
+base::Optional<PasswordHashData>
+PasswordReuseDetector::CheckNonGaiaEnterprisePasswordReuse(
+ const base::string16& input,
+ const std::string& domain) {
+ if (!enterprise_password_hash_data_list_.has_value() ||
+ enterprise_password_hash_data_list_->empty()) {
+ return base::nullopt;
+ }
- if (HashPasswordManager::CalculateSyncPasswordHash(
- reuse_candidate, sync_password_data_->salt) ==
- sync_password_data_->hash) {
- return reuse_candidate.size();
+ // Skips password reuse check if |domain| matches enterprise login URL or
+ // enterprise change password URL.
+ GURL page_url(domain);
+ if (!prefs_ ||
+ safe_browsing::MatchesPasswordProtectionLoginURL(page_url, *prefs_) ||
+ safe_browsing::MatchesPasswordProtectionChangePasswordURL(page_url,
+ *prefs_)) {
+ return base::nullopt;
}
- return 0;
+
+ return FindPasswordReuse(input, enterprise_password_hash_data_list_.value());
}
size_t PasswordReuseDetector::CheckSavedPasswordReuse(
@@ -150,12 +204,44 @@ size_t PasswordReuseDetector::CheckSavedPasswordReuse(
}
void PasswordReuseDetector::UseSyncPasswordHash(
- base::Optional<SyncPasswordData> sync_password_data) {
- sync_password_data_ = std::move(sync_password_data);
+ base::Optional<PasswordHashData> sync_password_data) {
+ // TODO(crbug.com/841438): Remove this function when the migration is done.
+ if (sync_password_data) {
+ gaia_password_hash_data_list_ =
+ base::make_optional<std::vector<PasswordHashData>>();
+ gaia_password_hash_data_list_->push_back(sync_password_data.value());
+ }
+}
+
+void PasswordReuseDetector::UseGaiaPasswordHash(
+ base::Optional<std::vector<PasswordHashData>> password_hash_data_list) {
+ gaia_password_hash_data_list_ = std::move(password_hash_data_list);
+}
+
+void PasswordReuseDetector::UseNonGaiaEnterprisePasswordHash(
+ base::Optional<std::vector<PasswordHashData>> password_hash_data_list) {
+ enterprise_password_hash_data_list_ = std::move(password_hash_data_list);
+}
+
+void PasswordReuseDetector::ClearGaiaPasswordHash(const std::string& username) {
+ if (!gaia_password_hash_data_list_)
+ return;
+
+ gaia_password_hash_data_list_->erase(
+ std::remove_if(gaia_password_hash_data_list_->begin(),
+ gaia_password_hash_data_list_->end(),
+ [&username](const PasswordHashData& data) {
+ return data.username == username;
+ }),
+ gaia_password_hash_data_list_->end());
+}
+
+void PasswordReuseDetector::ClearAllGaiaPasswordHash() {
+ gaia_password_hash_data_list_.reset();
}
-void PasswordReuseDetector::ClearSyncPasswordHash() {
- sync_password_data_.reset();
+void PasswordReuseDetector::ClearAllEnterprisePasswordHash() {
+ enterprise_password_hash_data_list_.reset();
}
void PasswordReuseDetector::AddPassword(const autofill::PasswordForm& form) {
@@ -182,7 +268,7 @@ PasswordReuseDetector::FindFirstSavedPassword(const base::string16& input) {
return passwords_.end();
// lower_bound returns the first key that is bigger or equal to input.
- auto it = passwords_.lower_bound(input);
+ passwords_iterator it = passwords_.lower_bound(input);
if (it != passwords_.end() && it->first == input) {
// If the key is equal then a saved password is found.
return it;
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector.h b/chromium/components/password_manager/core/browser/password_reuse_detector.h
index 0f260930a0d..1397120c9b0 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector.h
@@ -55,10 +55,23 @@ class PasswordReuseDetector : public PasswordStoreConsumer {
PasswordReuseDetectorConsumer* consumer);
// Stores internal |sync_password_data| for password reuse checking.
- void UseSyncPasswordHash(base::Optional<SyncPasswordData> sync_password_data);
+ void UseSyncPasswordHash(base::Optional<PasswordHashData> sync_password_data);
- // Clears a sync password hash if it was saved.
- void ClearSyncPasswordHash();
+ // Stores a vector of PasswordHashData for Gaia password reuse checking.
+ void UseGaiaPasswordHash(
+ base::Optional<std::vector<PasswordHashData>> password_hash_data_list);
+
+ // Stores a vector of PasswordHashData for enterprise password reuse checking.
+ void UseNonGaiaEnterprisePasswordHash(
+ base::Optional<std::vector<PasswordHashData>> password_hash_data_list);
+
+ void ClearGaiaPasswordHash(const std::string& username);
+
+ void ClearAllGaiaPasswordHash();
+
+ void ClearAllEnterprisePasswordHash();
+
+ void SetPrefs(PrefService* prefs) { prefs_ = prefs; }
private:
using passwords_iterator = std::map<base::string16,
@@ -68,10 +81,17 @@ class PasswordReuseDetector : public PasswordStoreConsumer {
// Add password from |form| to |passwords_|.
void AddPassword(const autofill::PasswordForm& form);
- // If sync-password reuse is found, return the length of the reused
- // password. If no reuse is found, return 0.
- size_t CheckSyncPasswordReuse(const base::string16& input,
- const std::string& domain);
+ // If Gaia password reuse is found, return the PasswordHashData of the reused
+ // password. If no reuse is found, return |base::nullopt|.
+ base::Optional<PasswordHashData> CheckGaiaPasswordReuse(
+ const base::string16& input,
+ const std::string& domain);
+
+ // If Non-Gaia enterprise password reuse is found, return the PasswordHashData
+ // of the the reused password. If no reuse is found, return |base::nullopt|.
+ base::Optional<PasswordHashData> CheckNonGaiaEnterprisePasswordReuse(
+ const base::string16& input,
+ const std::string& domain);
// If saved-password reuse is found, fill in the registry-controlled
// domains that match any reused password, and return the length of the
@@ -102,7 +122,12 @@ class PasswordReuseDetector : public PasswordStoreConsumer {
// of times how many different sites it's saved on.
int saved_passwords_ = 0;
- base::Optional<SyncPasswordData> sync_password_data_;
+ base::Optional<std::vector<PasswordHashData>> gaia_password_hash_data_list_;
+
+ base::Optional<std::vector<PasswordHashData>>
+ enterprise_password_hash_data_list_;
+
+ PrefService* prefs_;
DISALLOW_COPY_AND_ASSIGN(PasswordReuseDetector);
};
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h b/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h
index 0c9779099ac..16c1981e976 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector_consumer.h
@@ -10,7 +10,9 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/strings/string16.h"
+#include "components/password_manager/core/browser/hash_password_manager.h"
namespace password_manager {
@@ -23,14 +25,17 @@ class PasswordReuseDetectorConsumer
// Called when a password reuse is found.
// |password_length| is the length of the re-used password, or the max length
- // if multiple passwords were matched. |matching_domains| is the list of
- // domains for which |password| is saved (may be empty if
- // |matches_sync_password| == true), |saved_passwords| is the total number
- // of passwords (with unique domains) stored in Password Manager.
- virtual void OnReuseFound(size_t password_length,
- bool matches_sync_password,
- const std::vector<std::string>& matching_domains,
- int saved_passwords) = 0;
+ // if multiple passwords were matched. |reused_protected_password_hash| is the
+ // Gaia or enterprise password that matches the reuse. |matching_domains| is
+ // the list of domains for which |password| is saved (may be empty if
+ // |reused_protected_password_hash| is not null), |saved_passwords|
+ // is the total number of passwords (with unique domains) stored in Password
+ // Manager.
+ virtual void OnReuseFound(
+ size_t password_length,
+ base::Optional<PasswordHashData> reused_protected_password_hash,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) = 0;
};
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc b/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
index 760f35a38c9..7fff3e93650 100644
--- a/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_reuse_detector_unittest.cc
@@ -10,9 +10,14 @@
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/hash_password_manager.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/safe_browsing/common/safe_browsing_prefs.h"
+#include "components/safe_browsing/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,8 +32,8 @@ namespace {
using StringVector = std::vector<std::string>;
// Constants to make the tests more readable.
-const bool SYNC_REUSE_NO = false;
-const bool SYNC_REUSE_YES = true;
+const base::Optional<PasswordHashData> NO_GAIA_OR_ENTERPRISE_REUSE =
+ base::nullopt;
std::vector<std::pair<std::string, std::string>> GetTestDomainsPasswords() {
return {
@@ -75,13 +80,39 @@ PasswordStoreChangeList GetChangeList(
return changes;
}
-SyncPasswordData GetSyncPasswordData(const std::string& sync_password) {
- SyncPasswordData sync_password_data;
- sync_password_data.salt = "1234567890123456";
- sync_password_data.length = sync_password.size();
- sync_password_data.hash = HashPasswordManager::CalculateSyncPasswordHash(
- base::ASCIIToUTF16(sync_password), sync_password_data.salt);
- return sync_password_data;
+std::vector<PasswordHashData> PrepareGaiaPasswordData(
+ const std::vector<std::string>& passwords) {
+ std::vector<PasswordHashData> result;
+ for (const auto& password : passwords) {
+ PasswordHashData password_hash("username_" + password,
+ base::ASCIIToUTF16(password),
+ /*is_gaia_password=*/true);
+ result.push_back(password_hash);
+ }
+ return result;
+}
+
+std::vector<PasswordHashData> PrepareEnterprisePasswordData(
+ const std::vector<std::string>& passwords) {
+ std::vector<PasswordHashData> result;
+ for (const auto& password : passwords) {
+ PasswordHashData password_hash("enterprise_username_" + password,
+ base::ASCIIToUTF16(password),
+ /*is_gaia_password=*/false);
+ result.push_back(password_hash);
+ }
+ return result;
+}
+
+void ConfigureEnterprisePasswordProtection(TestingPrefServiceSimple* prefs) {
+ prefs->registry()->RegisterStringPref(
+ prefs::kPasswordProtectionChangePasswordURL, "");
+ prefs->registry()->RegisterListPref(prefs::kPasswordProtectionLoginURLs);
+ prefs->SetString(prefs::kPasswordProtectionChangePasswordURL,
+ "https://changepassword.example.com/");
+ base::ListValue login_urls;
+ login_urls.AppendString("https://login.example.com");
+ prefs->Set(prefs::kPasswordProtectionLoginURLs, login_urls);
}
TEST(PasswordReuseDetectorTest, TypingPasswordOnDifferentSite) {
@@ -96,24 +127,25 @@ TEST(PasswordReuseDetectorTest, TypingPasswordOnDifferentSite) {
"https://evil.com", &mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
- EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
- StringVector({"google.com"}), 5));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("saved_password"),
+ Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
+ StringVector({"google.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("123saved_password"),
"https://evil.com", &mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
- EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
- StringVector({"google.com"}), 5));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("saved_password"),
+ Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
+ StringVector({"google.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("saved_password"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
- EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("secretword"), SYNC_REUSE_NO,
- StringVector({"example1.com", "example2.com"}), 5));
+ EXPECT_CALL(
+ mockConsumer,
+ OnReuseFound(strlen("secretword"), Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
+ StringVector({"example1.com", "example2.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("abcdsecretword"), "https://evil.com",
&mockConsumer);
}
@@ -135,7 +167,8 @@ TEST(PasswordReuseDetectorTest, NoPSLMatchReuseEvent) {
// a.appspot.com and b.appspot.com are not PSL matches. So reuse event should
// be raised.
- EXPECT_CALL(mockConsumer, OnReuseFound(strlen("abcdefghi"), SYNC_REUSE_NO,
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("abcdefghi"),
+ Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
StringVector({"a.appspot.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("abcdefghi"), "https://b.appspot.com",
&mockConsumer);
@@ -176,7 +209,8 @@ TEST(PasswordReuseDetectorTest, OnLoginsChanged) {
EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
} else {
EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
+ OnReuseFound(strlen("saved_password"),
+ Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
StringVector({"google.com"}), 5));
}
reuse_detector.CheckReuse(ASCIIToUTF16("123saved_password"),
@@ -202,15 +236,16 @@ TEST(PasswordReuseDetectorTest, MatchMultiplePasswords) {
EXPECT_CALL(
mockConsumer,
OnReuseFound(
- strlen("01234567890"), SYNC_REUSE_NO,
+ strlen("01234567890"), Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
StringVector({"a.com", "all.com", "b.com", "b2.com", "c.com"}), 8));
reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
- EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("1234567890"), SYNC_REUSE_NO,
- StringVector({"a.com", "all.com", "c.com"}), 8));
+ EXPECT_CALL(
+ mockConsumer,
+ OnReuseFound(strlen("1234567890"), Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
+ StringVector({"a.com", "all.com", "c.com"}), 8));
reuse_detector.CheckReuse(ASCIIToUTF16("1234567890"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
@@ -220,56 +255,131 @@ TEST(PasswordReuseDetectorTest, MatchMultiplePasswords) {
&mockConsumer);
}
-TEST(PasswordReuseDetectorTest, SyncPasswordNoReuse) {
+TEST(PasswordReuseDetectorTest, GaiaPasswordNoReuse) {
PasswordReuseDetector reuse_detector;
reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
MockPasswordReuseDetectorConsumer mockConsumer;
- std::string sync_password = "sync_password";
- reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+ reuse_detector.UseGaiaPasswordHash(
+ PrepareGaiaPasswordData({"gaia_pw1", "gaia_pw2"}));
EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
- // Typing sync password on https://accounts.google.com is OK.
- reuse_detector.CheckReuse(ASCIIToUTF16("123sync_password"),
+ // Typing gaia password on https://accounts.google.com is OK.
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw1"),
+ "https://accounts.google.com", &mockConsumer);
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw2"),
"https://accounts.google.com", &mockConsumer);
// Only suffixes are verifed.
reuse_detector.CheckReuse(ASCIIToUTF16("sync_password123"),
"https://evil.com", &mockConsumer);
+ reuse_detector.CheckReuse(ASCIIToUTF16("other_password"), "https://evil.com",
+ &mockConsumer);
+}
+
+TEST(PasswordReuseDetectorTest, GaiaPasswordReuseFound) {
+ PasswordReuseDetector reuse_detector;
+ reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
+ MockPasswordReuseDetectorConsumer mockConsumer;
+
+ std::vector<PasswordHashData> gaia_password_hashes =
+ PrepareGaiaPasswordData({"gaia_pw1", "gaia_pw2"});
+ base::Optional<PasswordHashData> expected_reused_password_hash(
+ gaia_password_hashes[0]);
+ reuse_detector.UseGaiaPasswordHash(gaia_password_hashes);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("gaia_pw1"),
+ Matches(expected_reused_password_hash),
+ StringVector(), 5));
+
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw1"),
+ "https://phishing.example.com", &mockConsumer);
}
-TEST(PasswordReuseDetectorTest, SyncPasswordReuseFound) {
+TEST(PasswordReuseDetectorTest, EnterprisePasswordNoReuse) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ safe_browsing::kEnterprisePasswordProtectionV1);
+ TestingPrefServiceSimple prefs;
+ ConfigureEnterprisePasswordProtection(&prefs);
+
PasswordReuseDetector reuse_detector;
+ reuse_detector.SetPrefs(&prefs);
reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
MockPasswordReuseDetectorConsumer mockConsumer;
- std::string sync_password = "sync_password";
- reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+ std::vector<PasswordHashData> enterprise_password_hashes =
+ PrepareEnterprisePasswordData({"enterprise_pw1", "enterprise_pw2"});
+ base::Optional<PasswordHashData> expected_reused_password_hash(
+ enterprise_password_hashes[1]);
+ reuse_detector.UseNonGaiaEnterprisePasswordHash(enterprise_password_hashes);
- EXPECT_CALL(mockConsumer, OnReuseFound(strlen("sync_password"),
- SYNC_REUSE_YES, StringVector(), 5));
- reuse_detector.CheckReuse(ASCIIToUTF16("sync_password"), "https://evil.com",
+ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
+ // Typing enterprise password on change password page is OK.
+ reuse_detector.CheckReuse(ASCIIToUTF16("enterprise_pw1"),
+ "https://changepassword.example.com/",
+ &mockConsumer);
+ reuse_detector.CheckReuse(ASCIIToUTF16("enterprise_pw2"),
+ "https://changepassword.example.com/",
&mockConsumer);
+
+ // Suffix match is not reuse.
+ reuse_detector.CheckReuse(ASCIIToUTF16("enterprise"), "https://evil.com",
+ &mockConsumer);
+ reuse_detector.CheckReuse(ASCIIToUTF16("other_password"), "https://evil.com",
+ &mockConsumer);
+}
+
+TEST(PasswordReuseDetectorTest, EnterprisePasswordReuseFound) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ safe_browsing::kEnterprisePasswordProtectionV1);
+ TestingPrefServiceSimple prefs;
+ ConfigureEnterprisePasswordProtection(&prefs);
+
+ PasswordReuseDetector reuse_detector;
+ reuse_detector.SetPrefs(&prefs);
+ reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
+ MockPasswordReuseDetectorConsumer mockConsumer;
+
+ std::vector<PasswordHashData> enterprise_password_hashes =
+ PrepareEnterprisePasswordData({"enterprise_pw1", "enterprise_pw2"});
+ base::Optional<PasswordHashData> expected_reused_password_hash(
+ enterprise_password_hashes[1]);
+ reuse_detector.UseNonGaiaEnterprisePasswordHash(enterprise_password_hashes);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("enterprise_pw2"),
+ Matches(expected_reused_password_hash),
+ StringVector(), 5));
+ reuse_detector.CheckReuse(ASCIIToUTF16("enterprise_pw2"),
+ "https://phishing.com", &mockConsumer);
}
-TEST(PasswordReuseDetectorTest, MatchSyncAndMultiplePasswords) {
+TEST(PasswordReuseDetectorTest, MatchGaiaAndMultipleSavedPasswords) {
const std::vector<std::pair<std::string, std::string>> domain_passwords = {
{"https://a.com", "34567890"}, {"https://b.com", "01234567890"},
};
PasswordReuseDetector reuse_detector;
reuse_detector.OnGetPasswordStoreResults(GetForms(domain_passwords));
- std::string sync_password = "1234567890";
- reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+ std::string gaia_password = "1234567890";
+ std::vector<PasswordHashData> gaia_password_hashes =
+ PrepareGaiaPasswordData({gaia_password});
+ ASSERT_EQ(1u, gaia_password_hashes.size());
+ base::Optional<PasswordHashData> expected_reused_password_hash(
+ gaia_password_hashes[0]);
+ reuse_detector.UseGaiaPasswordHash(gaia_password_hashes);
MockPasswordReuseDetectorConsumer mockConsumer;
- EXPECT_CALL(mockConsumer, OnReuseFound(strlen("01234567890"), SYNC_REUSE_YES,
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("01234567890"),
+ Matches(expected_reused_password_hash),
StringVector({"a.com", "b.com"}), 2));
reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com",
&mockConsumer);
testing::Mock::VerifyAndClearExpectations(&mockConsumer);
- EXPECT_CALL(mockConsumer, OnReuseFound(strlen("1234567890"), SYNC_REUSE_YES,
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("1234567890"),
+ Matches(expected_reused_password_hash),
StringVector(), 2));
reuse_detector.CheckReuse(ASCIIToUTF16("xyz1234567890"), "https://evil.com",
&mockConsumer);
@@ -280,51 +390,159 @@ TEST(PasswordReuseDetectorTest, MatchSyncAndMultiplePasswords) {
&mockConsumer);
}
-TEST(PasswordReuseDetectorTest, SavedPasswordsReuseSyncPasswordAvailable) {
- // Check that reuse of saved passwords is detected also if the sync password
- // hash is saved.
+TEST(PasswordReuseDetectorTest, MatchSavedPasswordButNotGaiaPassword) {
PasswordReuseDetector reuse_detector;
reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
MockPasswordReuseDetectorConsumer mockConsumer;
- std::string sync_password = "sync_password";
- reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+ std::string gaia_password = "gaia_password";
+ reuse_detector.UseGaiaPasswordHash(PrepareGaiaPasswordData({gaia_password}));
- EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("saved_password"), SYNC_REUSE_NO,
- StringVector({"google.com"}), 5));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("saved_password"),
+ Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
+ StringVector({"google.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("saved_password"), "https://evil.com",
&mockConsumer);
}
-TEST(PasswordReuseDetectorTest, SavedPasswordAndSyncPasswordReuse) {
- // Verify we can detect that a password matches BOTH the sync password
- // and saved password.
+TEST(PasswordReuseDetectorTest, MatchEnterpriseAndMultipleSavedPasswords) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ safe_browsing::kEnterprisePasswordProtectionV1);
+ TestingPrefServiceSimple prefs;
+ ConfigureEnterprisePasswordProtection(&prefs);
+
+ const std::vector<std::pair<std::string, std::string>> domain_passwords = {
+ {"https://a.com", "34567890"}, {"https://b.com", "01234567890"},
+ };
PasswordReuseDetector reuse_detector;
+ reuse_detector.SetPrefs(&prefs);
+ reuse_detector.OnGetPasswordStoreResults(GetForms(domain_passwords));
+
+ std::string enterprise_password = "1234567890";
+ std::vector<PasswordHashData> enterprise_password_hashes =
+ PrepareEnterprisePasswordData({enterprise_password});
+ ASSERT_EQ(1u, enterprise_password_hashes.size());
+ base::Optional<PasswordHashData> expected_reused_password_hash(
+ enterprise_password_hashes[0]);
+ reuse_detector.UseNonGaiaEnterprisePasswordHash(enterprise_password_hashes);
+
+ MockPasswordReuseDetectorConsumer mockConsumer;
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("01234567890"),
+ Matches(expected_reused_password_hash),
+ StringVector({"a.com", "b.com"}), 2));
+ reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("1234567890"),
+ Matches(expected_reused_password_hash),
+ StringVector(), 2));
+ reuse_detector.CheckReuse(ASCIIToUTF16("xyz1234567890"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
+ reuse_detector.CheckReuse(ASCIIToUTF16("4567890"), "https://evil.com",
+ &mockConsumer);
+}
+
+TEST(PasswordReuseDetectorTest, MatchSavedPasswordButNotEnterprisePassword) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ safe_browsing::kEnterprisePasswordProtectionV1);
+ TestingPrefServiceSimple prefs;
+ ConfigureEnterprisePasswordProtection(&prefs);
+
+ PasswordReuseDetector reuse_detector;
+ reuse_detector.SetPrefs(&prefs);
reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
MockPasswordReuseDetectorConsumer mockConsumer;
- std::string sync_password = "saved_password"; // matches saved password
- reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
+ std::string enterprise_password = "enterprise_password";
+ reuse_detector.UseNonGaiaEnterprisePasswordHash(
+ PrepareEnterprisePasswordData({enterprise_password}));
- EXPECT_CALL(mockConsumer,
- OnReuseFound(strlen("saved_password"), SYNC_REUSE_YES,
- StringVector({"google.com"}), 5));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("saved_password"),
+ Matches(NO_GAIA_OR_ENTERPRISE_REUSE),
+ StringVector({"google.com"}), 5));
reuse_detector.CheckReuse(ASCIIToUTF16("saved_password"), "https://evil.com",
&mockConsumer);
}
-TEST(PasswordReuseDetectorTest, ClearSyncPasswordHash) {
+TEST(PasswordReuseDetectorTest, MatchGaiaEnterpriseAndSavedPassword) {
+ base::test::ScopedFeatureList feature_list;
+ feature_list.InitAndEnableFeature(
+ safe_browsing::kEnterprisePasswordProtectionV1);
+ TestingPrefServiceSimple prefs;
+ ConfigureEnterprisePasswordProtection(&prefs);
+
+ const std::vector<std::pair<std::string, std::string>> domain_passwords = {
+ {"https://a.com", "34567890"}, {"https://b.com", "01234567890"},
+ };
+ PasswordReuseDetector reuse_detector;
+ reuse_detector.SetPrefs(&prefs);
+ reuse_detector.OnGetPasswordStoreResults(GetForms(domain_passwords));
+
+ std::string gaia_password = "123456789";
+ reuse_detector.UseGaiaPasswordHash(PrepareGaiaPasswordData({gaia_password}));
+
+ std::string enterprise_password = "1234567890";
+ std::vector<PasswordHashData> enterprise_password_hashes =
+ PrepareEnterprisePasswordData({enterprise_password});
+ ASSERT_EQ(1u, enterprise_password_hashes.size());
+ base::Optional<PasswordHashData> expected_reused_password_hash(
+ enterprise_password_hashes[0]);
+ reuse_detector.UseNonGaiaEnterprisePasswordHash(enterprise_password_hashes);
+
+ MockPasswordReuseDetectorConsumer mockConsumer;
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("01234567890"),
+ Matches(expected_reused_password_hash),
+ StringVector({"a.com", "b.com"}), 2));
+ reuse_detector.CheckReuse(ASCIIToUTF16("abcd01234567890"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("1234567890"),
+ Matches(expected_reused_password_hash),
+ StringVector(), 2));
+ reuse_detector.CheckReuse(ASCIIToUTF16("xyz1234567890"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
+ reuse_detector.CheckReuse(ASCIIToUTF16("4567890"), "https://evil.com",
+ &mockConsumer);
+}
+
+TEST(PasswordReuseDetectorTest, ClearGaiaPasswordHash) {
PasswordReuseDetector reuse_detector;
reuse_detector.OnGetPasswordStoreResults(GetForms(GetTestDomainsPasswords()));
MockPasswordReuseDetectorConsumer mockConsumer;
- std::string sync_password = "sync_password";
- reuse_detector.UseSyncPasswordHash(GetSyncPasswordData(sync_password));
- reuse_detector.ClearSyncPasswordHash();
+ reuse_detector.UseGaiaPasswordHash(
+ PrepareGaiaPasswordData({"gaia_pw1", "gaia_pw12"}));
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("gaia_pw1"), _, _, _));
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw1"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ EXPECT_CALL(mockConsumer, OnReuseFound(strlen("gaia_pw12"), _, _, _));
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw12"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
+
+ reuse_detector.ClearGaiaPasswordHash("username_gaia_pw1");
+ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw1"), "https://evil.com",
+ &mockConsumer);
+ testing::Mock::VerifyAndClearExpectations(&mockConsumer);
- // Check that no reuse is found, since hash is cleared.
- reuse_detector.CheckReuse(ASCIIToUTF16("sync_password"), "https://evil.com",
+ reuse_detector.ClearAllGaiaPasswordHash();
+ EXPECT_CALL(mockConsumer, OnReuseFound(_, _, _, _)).Times(0);
+ reuse_detector.CheckReuse(ASCIIToUTF16("gaia_pw12"), "https://evil.com",
&mockConsumer);
}
diff --git a/chromium/components/password_manager/core/browser/password_store.cc b/chromium/components/password_manager/core/browser/password_store.cc
index 66d0eb2dd97..ec111d1d2be 100644
--- a/chromium/components/password_manager/core/browser/password_store.cc
+++ b/chromium/components/password_manager/core/browser/password_store.cc
@@ -17,6 +17,7 @@
#include "base/task_scheduler/post_task.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
+#include "components/autofill/core/common/form_data.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
#include "components/password_manager/core/browser/password_manager_metrics_util.h"
@@ -76,14 +77,14 @@ PasswordStore::CheckReuseRequest::~CheckReuseRequest() {}
void PasswordStore::CheckReuseRequest::OnReuseFound(
size_t password_length,
- bool matches_sync_password,
+ base::Optional<PasswordHashData> reused_protected_password_hash,
const std::vector<std::string>& matching_domains,
int saved_passwords) {
origin_task_runner_->PostTask(
FROM_HERE,
base::Bind(&PasswordReuseDetectorConsumer::OnReuseFound, consumer_weak_,
- password_length, matches_sync_password, matching_domains,
- saved_passwords));
+ password_length, reused_protected_password_hash,
+ matching_domains, saved_passwords));
}
#endif
@@ -97,6 +98,11 @@ PasswordStore::FormDigest::FormDigest(const PasswordForm& form)
signon_realm(form.signon_realm),
origin(form.origin) {}
+PasswordStore::FormDigest::FormDigest(const autofill::FormData& form)
+ : scheme(PasswordForm::SCHEME_HTML),
+ signon_realm(form.origin.GetOrigin().spec()),
+ origin(form.origin) {}
+
PasswordStore::FormDigest::FormDigest(const FormDigest& other) = default;
PasswordStore::FormDigest::FormDigest(FormDigest&& other) = default;
@@ -127,9 +133,6 @@ bool PasswordStore::Init(const syncer::SyncableService::StartSyncFlare& flare,
base::Bind(&PasswordStore::InitOnBackgroundSequence, this, flare));
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
hash_password_manager_.set_prefs(prefs);
- ScheduleTask(
- base::Bind(&PasswordStore::SaveSyncPasswordHashImpl, this,
- base::Passed(hash_password_manager_.RetrievePasswordHash())));
#endif
return true;
}
@@ -280,8 +283,11 @@ void PasswordStore::ReportMetrics(const std::string& sync_username,
if (!sync_username.empty()) {
auto hash_password_state =
hash_password_manager_.HasPasswordHash()
- ? metrics_util::IsSyncPasswordHashSaved::SAVED
- : metrics_util::IsSyncPasswordHashSaved::NOT_SAVED;
+ ? metrics_util::IsSyncPasswordHashSaved::SAVED_VIA_STRING_PREF
+ : hash_password_manager_.HasPasswordHash(sync_username,
+ /*is_gaia_password=*/true)
+ ? metrics_util::IsSyncPasswordHashSaved::SAVED_VIA_LIST_PREF
+ : metrics_util::IsSyncPasswordHashSaved::NOT_SAVED;
metrics_util::LogIsSyncPasswordHashSaved(hash_password_state);
}
#endif
@@ -353,12 +359,26 @@ void PasswordStore::CheckReuse(const base::string16& input,
#endif
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+void PasswordStore::PrepareSyncPasswordHashData(
+ const std::string& sync_username) {
+ // TODO(crbug.com/841438): Delete migration code when most users complete
+ // the migration.
+ hash_password_manager_.MaybeMigrateExistingSyncPasswordHash(sync_username);
+ ScheduleTask(base::BindRepeating(
+ &PasswordStore::SaveSyncPasswordHashImpl, this,
+ base::Passed(hash_password_manager_.RetrievePasswordHash(
+ sync_username, /*is_gaia_password=*/true))));
+}
+
void PasswordStore::SaveSyncPasswordHash(
+ const std::string& username,
const base::string16& password,
metrics_util::SyncPasswordHashChange event) {
- if (hash_password_manager_.SavePasswordHash(password)) {
- base::Optional<SyncPasswordData> sync_password_data =
- hash_password_manager_.RetrievePasswordHash();
+ if (hash_password_manager_.SavePasswordHash(username, password,
+ /*is_gaia_password=*/true)) {
+ base::Optional<PasswordHashData> sync_password_data =
+ hash_password_manager_.RetrievePasswordHash(username,
+ /*is_gaia_password=*/true);
metrics_util::LogSyncPasswordHashChange(event);
ScheduleTask(base::BindRepeating(&PasswordStore::SaveSyncPasswordHashImpl,
this, std::move(sync_password_data)));
@@ -366,7 +386,7 @@ void PasswordStore::SaveSyncPasswordHash(
}
void PasswordStore::SaveSyncPasswordHash(
- const SyncPasswordData& sync_password_data,
+ const PasswordHashData& sync_password_data,
metrics_util::SyncPasswordHashChange event) {
if (hash_password_manager_.SavePasswordHash(sync_password_data)) {
metrics_util::LogSyncPasswordHashChange(event);
@@ -375,8 +395,9 @@ void PasswordStore::SaveSyncPasswordHash(
}
}
-void PasswordStore::ClearSyncPasswordHash() {
- hash_password_manager_.ClearSavedPasswordHash();
+void PasswordStore::ClearPasswordHash(const std::string& username) {
+ hash_password_manager_.ClearSavedPasswordHash(username,
+ /*is_gaia_password=*/true);
ScheduleTask(base::Bind(&PasswordStore::ClearSyncPasswordHashImpl, this));
}
@@ -486,14 +507,16 @@ void PasswordStore::CheckReuseImpl(std::unique_ptr<CheckReuseRequest> request,
}
void PasswordStore::SaveSyncPasswordHashImpl(
- base::Optional<SyncPasswordData> sync_password_data) {
+ base::Optional<PasswordHashData> sync_password_data) {
if (reuse_detector_)
reuse_detector_->UseSyncPasswordHash(std::move(sync_password_data));
}
void PasswordStore::ClearSyncPasswordHashImpl() {
+ // TODO(crbug.com/844134): Find a way to clear corresponding Gaia password
+ // hash when user logs out individual Gaia account in content area.
if (reuse_detector_)
- reuse_detector_->ClearSyncPasswordHash();
+ reuse_detector_->ClearAllGaiaPasswordHash();
}
#endif
diff --git a/chromium/components/password_manager/core/browser/password_store.h b/chromium/components/password_manager/core/browser/password_store.h
index 4c0b4bce1f6..f6fa997e927 100644
--- a/chromium/components/password_manager/core/browser/password_store.h
+++ b/chromium/components/password_manager/core/browser/password_store.h
@@ -34,6 +34,7 @@
class PrefService;
namespace autofill {
+struct FormData;
struct PasswordForm;
}
@@ -82,6 +83,7 @@ class PasswordStore : protected PasswordStoreSync,
const std::string& signon_realm,
const GURL& origin);
explicit FormDigest(const autofill::PasswordForm& form);
+ explicit FormDigest(const autofill::FormData& form);
FormDigest(const FormDigest& other);
FormDigest(FormDigest&& other);
FormDigest& operator=(const FormDigest& other);
@@ -250,6 +252,10 @@ class PasswordStore : protected PasswordStoreSync,
// TODO(crbug.com/706392): Fix password reuse detection for Android.
#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+ // Immediately called after |Init()| to retrieve sync password hash data for
+ // reuse detection.
+ void PrepareSyncPasswordHashData(const std::string& sync_username);
+
// Checks that some suffix of |input| equals to a password saved on another
// registry controlled domain than |domain|.
// If such suffix is found, |consumer|->OnReuseFound() is called on the same
@@ -259,22 +265,24 @@ class PasswordStore : protected PasswordStoreSync,
const std::string& domain,
PasswordReuseDetectorConsumer* consumer);
- // Saves a hash of |password| for password reuse checking.
+ // Saves |sync_username| and a hash of |password| for password reuse checking.
// |event| is used for metric logging.
- virtual void SaveSyncPasswordHash(const base::string16& password,
+ virtual void SaveSyncPasswordHash(const std::string& sync_username,
+ const base::string16& password,
metrics_util::SyncPasswordHashChange event);
// Saves |sync_password_data| for password reuse checking.
// |event| is used for metric logging.
- virtual void SaveSyncPasswordHash(const SyncPasswordData& sync_password_data,
+ virtual void SaveSyncPasswordHash(const PasswordHashData& sync_password_data,
metrics_util::SyncPasswordHashChange event);
- // Clears the saved sync password hash.
- virtual void ClearSyncPasswordHash();
+ // Clears the saved password hash for |username|.
+ virtual void ClearPasswordHash(const std::string& username);
// Shouldn't be called more than once, |notifier| must be not nullptr.
void SetPasswordStoreSigninNotifier(
std::unique_ptr<PasswordStoreSigninNotifier> notifier);
+
#endif
protected:
@@ -324,10 +332,11 @@ class PasswordStore : protected PasswordStoreSync,
~CheckReuseRequest() override;
// PasswordReuseDetectorConsumer
- void OnReuseFound(size_t password_length,
- bool matches_sync_password,
- const std::vector<std::string>& matches_domains,
- int saved_passwords) override;
+ void OnReuseFound(
+ size_t password_length,
+ base::Optional<PasswordHashData> reused_protected_password_hash,
+ const std::vector<std::string>& matching_domains,
+ int saved_passwords) override;
private:
const scoped_refptr<base::SequencedTaskRunner> origin_task_runner_;
@@ -448,7 +457,7 @@ class PasswordStore : protected PasswordStoreSync,
// Synchronous implementation of SaveSyncPasswordHash().
void SaveSyncPasswordHashImpl(
- base::Optional<SyncPasswordData> sync_password_data);
+ base::Optional<PasswordHashData> sync_password_data);
// Synchronous implementation of ClearSyncPasswordHash().
void ClearSyncPasswordHashImpl();
diff --git a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
index b241c016b65..15a5b4322c8 100644
--- a/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_default_unittest.cc
@@ -16,6 +16,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
#include "base/time/time.h"
+#include "components/os_crypt/os_crypt_mocker.h"
#include "components/password_manager/core/browser/login_database.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/password_store_change.h"
@@ -106,6 +107,7 @@ class PasswordStoreDefaultTestDelegate {
PasswordStoreDefaultTestDelegate::PasswordStoreDefaultTestDelegate()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {
+ OSCryptMocker::SetUp();
SetupTempDir();
store_ = CreateInitializedStore(
std::make_unique<LoginDatabase>(test_login_db_file_path()));
@@ -115,12 +117,14 @@ PasswordStoreDefaultTestDelegate::PasswordStoreDefaultTestDelegate(
std::unique_ptr<LoginDatabase> database)
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI) {
+ OSCryptMocker::SetUp();
SetupTempDir();
store_ = CreateInitializedStore(std::move(database));
}
PasswordStoreDefaultTestDelegate::~PasswordStoreDefaultTestDelegate() {
ClosePasswordStore();
+ OSCryptMocker::TearDown();
}
void PasswordStoreDefaultTestDelegate::FinishAsyncProcessing() {
diff --git a/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc b/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc
index de487acd78a..405267a1a12 100644
--- a/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc
+++ b/chromium/components/password_manager/core/browser/password_store_signin_notifier.cc
@@ -13,19 +13,20 @@ PasswordStoreSigninNotifier::PasswordStoreSigninNotifier() {}
PasswordStoreSigninNotifier::~PasswordStoreSigninNotifier() {}
-void PasswordStoreSigninNotifier::NotifySignin(const std::string& password) {
+void PasswordStoreSigninNotifier::NotifySignin(const std::string& username,
+ const std::string& password) {
if (store_) {
store_->SaveSyncPasswordHash(
- base::UTF8ToUTF16(password),
+ username, base::UTF8ToUTF16(password),
metrics_util::SyncPasswordHashChange::SAVED_ON_CHROME_SIGNIN);
}
}
-void PasswordStoreSigninNotifier::NotifySignedOut() {
+void PasswordStoreSigninNotifier::NotifySignedOut(const std::string& username) {
metrics_util::LogSyncPasswordHashChange(
metrics_util::SyncPasswordHashChange::CLEARED_ON_CHROME_SIGNOUT);
if (store_)
- store_->ClearSyncPasswordHash();
+ store_->ClearPasswordHash(username);
}
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/browser/password_store_signin_notifier.h b/chromium/components/password_manager/core/browser/password_store_signin_notifier.h
index 65e8c89b9d2..ebe892f55ed 100644
--- a/chromium/components/password_manager/core/browser/password_store_signin_notifier.h
+++ b/chromium/components/password_manager/core/browser/password_store_signin_notifier.h
@@ -31,10 +31,10 @@ class PasswordStoreSigninNotifier {
void set_store(PasswordStore* store) { store_ = store; }
// Passes sign-in to |store_|.
- void NotifySignin(const std::string& password);
+ void NotifySignin(const std::string& username, const std::string& password);
// Passes signed-out to |store_|.
- void NotifySignedOut();
+ void NotifySignedOut(const std::string& username);
private:
PasswordStore* store_ = nullptr; // weak
diff --git a/chromium/components/password_manager/core/browser/password_store_unittest.cc b/chromium/components/password_manager/core/browser/password_store_unittest.cc
index 20ffc81702a..f732337d28b 100644
--- a/chromium/components/password_manager/core/browser/password_store_unittest.cc
+++ b/chromium/components/password_manager/core/browser/password_store_unittest.cc
@@ -139,6 +139,16 @@ class PasswordStoreTest : public testing::Test {
DISALLOW_COPY_AND_ASSIGN(PasswordStoreTest);
};
+base::Optional<PasswordHashData> GetSyncPasswordFromPref(
+ const std::string& username,
+ PrefService* prefs) {
+ HashPasswordManager hash_password_manager;
+ hash_password_manager.set_prefs(prefs);
+
+ return hash_password_manager.RetrievePasswordHash(username,
+ /*is_gaia_password=*/true);
+}
+
TEST_F(PasswordStoreTest, IgnoreOldWwwGoogleLogins) {
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
std::make_unique<LoginDatabase>(test_login_db_file_path())));
@@ -895,8 +905,7 @@ TEST_F(PasswordStoreTest, CheckPasswordReuse) {
if (test_data.reused_password_len != 0) {
EXPECT_CALL(
mock_consumer,
- OnReuseFound(test_data.reused_password_len,
- false /* matches_sync_password */,
+ OnReuseFound(test_data.reused_password_len, Matches(base::nullopt),
std::vector<std::string>({test_data.reuse_domain}), 2));
} else {
EXPECT_CALL(mock_consumer, OnReuseFound(_, _, _, _)).Times(0);
@@ -917,35 +926,34 @@ TEST_F(PasswordStoreTest, SavingClearingSyncPassword) {
std::make_unique<LoginDatabase>(test_login_db_file_path())));
TestingPrefServiceSimple prefs;
- prefs.registry()->RegisterStringPref(prefs::kSyncPasswordHash, std::string(),
- PrefRegistry::NO_REGISTRATION_FLAGS);
- prefs.registry()->RegisterStringPref(prefs::kSyncPasswordLengthAndHashSalt,
- std::string(),
- PrefRegistry::NO_REGISTRATION_FLAGS);
+ prefs.registry()->RegisterListPref(prefs::kPasswordHashDataList,
+ PrefRegistry::NO_REGISTRATION_FLAGS);
ASSERT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
store->Init(syncer::SyncableService::StartSyncFlare(), &prefs);
const base::string16 sync_password = base::ASCIIToUTF16("password");
const base::string16 input = base::ASCIIToUTF16("123password");
store->SaveSyncPasswordHash(
- sync_password,
+ "sync_username", sync_password,
metrics_util::SyncPasswordHashChange::SAVED_ON_CHROME_SIGNIN);
WaitForPasswordStore();
- EXPECT_TRUE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
+ EXPECT_TRUE(prefs.HasPrefPath(prefs::kPasswordHashDataList));
+ base::Optional<PasswordHashData> sync_password_hash =
+ GetSyncPasswordFromPref("sync_username", &prefs);
// Check that sync password reuse is found.
MockPasswordReuseDetectorConsumer mock_consumer;
- EXPECT_CALL(mock_consumer, OnReuseFound(sync_password.size(),
- true /* matches_sync_password */,
- std::vector<std::string>(), 0));
+ EXPECT_CALL(mock_consumer,
+ OnReuseFound(sync_password.size(), Matches(sync_password_hash),
+ std::vector<std::string>(), 0));
store->CheckReuse(input, "https://facebook.com", &mock_consumer);
WaitForPasswordStore();
testing::Mock::VerifyAndClearExpectations(&mock_consumer);
// Check that no sync password reuse is found after clearing the saved sync
// password hash.
- store->ClearSyncPasswordHash();
- EXPECT_FALSE(prefs.HasPrefPath(prefs::kSyncPasswordHash));
+ store->ClearPasswordHash("sync_username");
+ EXPECT_EQ(0u, prefs.GetList(prefs::kPasswordHashDataList)->GetList().size());
EXPECT_CALL(mock_consumer, OnReuseFound(_, _, _, _)).Times(0);
store->CheckReuse(input, "https://facebook.com", &mock_consumer);
WaitForPasswordStore();
diff --git a/chromium/components/password_manager/core/browser/stub_credentials_filter.cc b/chromium/components/password_manager/core/browser/stub_credentials_filter.cc
index 8782cc324f9..32549cd49d9 100644
--- a/chromium/components/password_manager/core/browser/stub_credentials_filter.cc
+++ b/chromium/components/password_manager/core/browser/stub_credentials_filter.cc
@@ -22,6 +22,11 @@ bool StubCredentialsFilter::ShouldSave(
return true;
}
+bool StubCredentialsFilter::ShouldSavePasswordHash(
+ const autofill::PasswordForm& form) const {
+ return false;
+}
+
void StubCredentialsFilter::ReportFormLoginSuccess(
const PasswordFormManager& form_manager) const {}
diff --git a/chromium/components/password_manager/core/browser/stub_credentials_filter.h b/chromium/components/password_manager/core/browser/stub_credentials_filter.h
index 03fcd34c671..7424c55f056 100644
--- a/chromium/components/password_manager/core/browser/stub_credentials_filter.h
+++ b/chromium/components/password_manager/core/browser/stub_credentials_filter.h
@@ -23,6 +23,8 @@ class StubCredentialsFilter : public CredentialsFilter {
std::vector<std::unique_ptr<autofill::PasswordForm>> results)
const override;
bool ShouldSave(const autofill::PasswordForm& form) const override;
+ bool ShouldSavePasswordHash(
+ const autofill::PasswordForm& form) const override;
void ReportFormLoginSuccess(
const PasswordFormManager& form_manager) const override;
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
index e7e2d204f92..9fb9378f691 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "components/password_manager/core/browser/credentials_filter.h"
-#include "components/password_manager/core/browser/password_form_manager.h"
+#include "components/password_manager/core/browser/password_form_manager_for_ui.h"
namespace password_manager {
@@ -17,13 +17,13 @@ StubPasswordManagerClient::StubPasswordManagerClient()
StubPasswordManagerClient::~StubPasswordManagerClient() {}
bool StubPasswordManagerClient::PromptUserToSaveOrUpdatePassword(
- std::unique_ptr<PasswordFormManager> form_to_save,
+ std::unique_ptr<PasswordFormManagerForUI> form_to_save,
bool update_password) {
return false;
}
void StubPasswordManagerClient::ShowManualFallbackForSaving(
- std::unique_ptr<PasswordFormManager> form_to_save,
+ std::unique_ptr<PasswordFormManagerForUI> form_to_save,
bool has_generated_password,
bool update_password) {}
@@ -49,7 +49,7 @@ void StubPasswordManagerClient::NotifySuccessfulLoginWithExistingPassword(
void StubPasswordManagerClient::NotifyStorePasswordCalled() {}
void StubPasswordManagerClient::AutomaticPasswordSave(
- std::unique_ptr<PasswordFormManager> saved_manager) {}
+ std::unique_ptr<PasswordFormManagerForUI> saved_manager) {}
PrefService* StubPasswordManagerClient::GetPrefs() const {
return nullptr;
diff --git a/chromium/components/password_manager/core/browser/stub_password_manager_client.h b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
index bd8b0b78f5f..a4e9cb66124 100644
--- a/chromium/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/chromium/components/password_manager/core/browser/stub_password_manager_client.h
@@ -24,10 +24,10 @@ class StubPasswordManagerClient : public PasswordManagerClient {
// PasswordManagerClient:
bool PromptUserToSaveOrUpdatePassword(
- std::unique_ptr<PasswordFormManager> form_to_save,
+ std::unique_ptr<PasswordFormManagerForUI> form_to_save,
bool update_password) override;
void ShowManualFallbackForSaving(
- std::unique_ptr<PasswordFormManager> form_to_save,
+ std::unique_ptr<PasswordFormManagerForUI> form_to_save,
bool has_generated_password,
bool update_password) override;
void HideManualFallbackForSaving() override;
@@ -44,7 +44,7 @@ class StubPasswordManagerClient : public PasswordManagerClient {
const autofill::PasswordForm& form) override;
void NotifyStorePasswordCalled() override;
void AutomaticPasswordSave(
- std::unique_ptr<PasswordFormManager> saved_manager) override;
+ std::unique_ptr<PasswordFormManagerForUI> saved_manager) override;
PrefService* GetPrefs() const override;
PasswordStore* GetPasswordStore() const override;
const GURL& GetLastCommittedEntryURL() const override;
diff --git a/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc b/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc
index b31083916ff..e5b0ca223f8 100644
--- a/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc
+++ b/chromium/components/password_manager/core/browser/suppressed_form_fetcher_unittest.cc
@@ -54,7 +54,7 @@ class PasswordManagerClientWithMockStore : public StubPasswordManagerClient {
mock_store_->ShutdownOnUIThread();
}
- MockPasswordStore& mock_password_store() const { return *mock_store_.get(); }
+ MockPasswordStore& mock_password_store() const { return *mock_store_; }
protected:
// StubPasswordManagerClient:
diff --git a/chromium/components/password_manager/core/browser/test_password_store.h b/chromium/components/password_manager/core/browser/test_password_store.h
index 1c89ade8d8c..c61793e5c48 100644
--- a/chromium/components/password_manager/core/browser/test_password_store.h
+++ b/chromium/components/password_manager/core/browser/test_password_store.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
#include "components/password_manager/core/browser/password_store.h"
namespace password_manager {
diff --git a/chromium/components/password_manager/core/common/BUILD.gn b/chromium/components/password_manager/core/common/BUILD.gn
index 47976880d50..7046d614fba 100644
--- a/chromium/components/password_manager/core/common/BUILD.gn
+++ b/chromium/components/password_manager/core/common/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/buildflag_header.gni")
+
static_library("common") {
sources = [
"credential_manager_types.cc",
@@ -15,6 +17,13 @@ static_library("common") {
"password_manager_ui.h",
]
+ if (is_ios) {
+ sources += [
+ "passwords_directory_util_ios.cc",
+ "passwords_directory_util_ios.h",
+ ]
+ }
+
deps = [
"//base",
"//components/autofill/core/common",
@@ -28,9 +37,15 @@ source_set("unit_tests") {
sources = [
"credential_manager_types_unittest.cc",
]
+
+ if (is_ios) {
+ sources += [ "passwords_directory_util_ios_unittest.cc" ]
+ }
+
deps = [
":common",
"//base",
+ "//base/test:test_support",
"//components/autofill/core/common",
"//sql",
"//testing/gtest",
diff --git a/chromium/components/password_manager/core/common/password_manager_features.cc b/chromium/components/password_manager/core/common/password_manager_features.cc
index 19a68849ce8..3491aec200a 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.cc
+++ b/chromium/components/password_manager/core/common/password_manager_features.cc
@@ -69,10 +69,18 @@ const base::Feature kPasswordImport = {"PasswordImport",
const base::Feature kPasswordSearchMobile = {"PasswordSearchMobile",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Adds password-related features to the keyboard accessory on mobile devices.
+const base::Feature kPasswordsKeyboardAccessory = {
+ "PasswordsKeyboardAccessory", base::FEATURE_DISABLED_BY_DEFAULT};
+
// Enables the experiment for the password manager to only fill on account
// selection, rather than autofilling on page load, with highlighting of fields.
const base::Feature kFillOnAccountSelect = {"fill-on-account-select",
base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables new password form parsing mechanism, details in
+// go/new-cpm-design-refactoring.
+const base::Feature kNewPasswordFormParsing = {
+ "new-password-form-parsing", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
diff --git a/chromium/components/password_manager/core/common/password_manager_features.h b/chromium/components/password_manager/core/common/password_manager_features.h
index 98ebb044ba3..87e3e469a96 100644
--- a/chromium/components/password_manager/core/common/password_manager_features.h
+++ b/chromium/components/password_manager/core/common/password_manager_features.h
@@ -26,9 +26,11 @@ extern const base::Feature kEnableManualPasswordGeneration;
extern const base::Feature kPasswordForceSaving;
extern const base::Feature kEnableShowAllSavedPasswordsContextMenu;
extern const base::Feature kFillOnAccountSelect;
+extern const base::Feature kNewPasswordFormParsing;
extern const base::Feature kPasswordExport;
extern const base::Feature kPasswordImport;
extern const base::Feature kPasswordSearchMobile;
+extern const base::Feature kPasswordsKeyboardAccessory;
extern const base::Feature kProtectSyncCredential;
extern const base::Feature kProtectSyncCredentialOnReauth;
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.cc b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
index 6b982af6718..914e6cc153f 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.cc
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.cc
@@ -42,5 +42,7 @@ const char kSyncPasswordLengthAndHashSalt[] =
const char kBlacklistedCredentialsStripped[] =
"profile.blacklisted_credentials_stripped";
+const char kPasswordHashDataList[] = "profile.password_hash_data_list";
+
} // namespace prefs
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/password_manager_pref_names.h b/chromium/components/password_manager/core/common/password_manager_pref_names.h
index 4565ae8c083..16f581ae0dd 100644
--- a/chromium/components/password_manager/core/common/password_manager_pref_names.h
+++ b/chromium/components/password_manager/core/common/password_manager_pref_names.h
@@ -65,6 +65,9 @@ extern const char kSyncPasswordLengthAndHashSalt[];
// Whether Chrome cleaned up username/password in the blacklisted credentials.
extern const char kBlacklistedCredentialsStripped[];
+// List that contains captured password hashes.
+extern const char kPasswordHashDataList[];
+
} // namespace prefs
} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/passwords_directory_util_ios.cc b/chromium/components/password_manager/core/common/passwords_directory_util_ios.cc
new file mode 100644
index 00000000000..830796f382a
--- /dev/null
+++ b/chromium/components/password_manager/core/common/passwords_directory_util_ios.cc
@@ -0,0 +1,43 @@
+// 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 "components/password_manager/core/common/passwords_directory_util_ios.h"
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/thread_restrictions.h"
+
+namespace password_manager {
+
+namespace {
+// Synchronously deletes passwords directoy.
+void DeletePasswordsDirectorySync() {
+ base::AssertBlockingAllowed();
+ base::FilePath downloads_directory;
+ if (GetPasswordsDirectory(&downloads_directory)) {
+ // It is assumed that deleting the directory always succeeds.
+ DeleteFile(downloads_directory, /*recursive=*/true);
+ }
+}
+} // namespace
+
+bool GetPasswordsDirectory(base::FilePath* directory_path) {
+ if (!GetTempDir(directory_path)) {
+ return false;
+ }
+ *directory_path = directory_path->Append(FILE_PATH_LITERAL("passwords"));
+ return true;
+}
+
+void DeletePasswordsDirectory() {
+ base::PostTaskWithTraits(FROM_HERE,
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
+ base::BindOnce(&DeletePasswordsDirectorySync));
+}
+
+} // namespace password_manager
diff --git a/chromium/components/password_manager/core/common/passwords_directory_util_ios.h b/chromium/components/password_manager/core/common/passwords_directory_util_ios.h
new file mode 100644
index 00000000000..f15be4fae04
--- /dev/null
+++ b/chromium/components/password_manager/core/common/passwords_directory_util_ios.h
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORDS_DIRECTORY_UTIL_IOS_H_
+#define COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORDS_DIRECTORY_UTIL_IOS_H_
+
+namespace base {
+class FilePath;
+}
+
+namespace password_manager {
+
+// Fills |directory_path| with the FilePath to the passwords temporary
+// directory used for exporting passwords on iOS.
+// Returns true if this is successful.
+bool GetPasswordsDirectory(base::FilePath* directory_path);
+
+// Asynchronously deletes the temporary passwords directory.
+void DeletePasswordsDirectory();
+
+} // namespace password_manager
+
+#endif // COMPONENTS_PASSWORD_MANAGER_CORE_COMMON_PASSWORDS_DIRECTORY_UTIL_IOS_H_
diff --git a/chromium/components/password_manager/core/common/passwords_directory_util_ios_unittest.cc b/chromium/components/password_manager/core/common/passwords_directory_util_ios_unittest.cc
new file mode 100644
index 00000000000..dc0dda18fcb
--- /dev/null
+++ b/chromium/components/password_manager/core/common/passwords_directory_util_ios_unittest.cc
@@ -0,0 +1,32 @@
+// 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 "components/password_manager/core/common/passwords_directory_util_ios.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/test/scoped_task_environment.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Tests that DeletePasswordsDirectory() actually deletes the directory.
+TEST(PasswordsDirectoryUtilTest, Deletion) {
+ base::test::ScopedTaskEnvironment environment;
+ base::FilePath dir;
+ ASSERT_TRUE(password_manager::GetPasswordsDirectory(&dir));
+ ASSERT_TRUE(CreateDirectory(dir));
+ base::FilePath file = dir.Append(FILE_PATH_LITERAL("TestPasswords.csv"));
+ EXPECT_EQ(0, WriteFile(file, "", 0));
+
+ // Verify that the file was created in the passwords directory.
+ ASSERT_TRUE(base::PathExists(file));
+
+ // Delete download directory.
+ password_manager::DeletePasswordsDirectory();
+
+ environment.RunUntilIdle();
+
+ // Verify passwords directory deletion.
+ EXPECT_FALSE(base::PathExists(dir));
+}
diff --git a/chromium/components/password_manager/public/interfaces/DEPS b/chromium/components/password_manager/public/interfaces/DEPS
deleted file mode 100644
index 7924dbee465..00000000000
--- a/chromium/components/password_manager/public/interfaces/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Allow the typemaps to access their dependencies.
-include_rules = [
- "+components/password_manager/core/browser/hash_password_manager.h",
-]
diff --git a/chromium/components/password_manager/public/interfaces/OWNERS b/chromium/components/password_manager/public/interfaces/OWNERS
deleted file mode 100644
index caf25210c8a..00000000000
--- a/chromium/components/password_manager/public/interfaces/OWNERS
+++ /dev/null
@@ -1,11 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
-per-file *.typemap=set noparent
-per-file *.typemap=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
-
-for files:
- components/password_manager/public/interfaces/sync_password_data.mojom
- components/password_manager/public/interfaces/sync_password_data_struct_traits.h
- components/password_manager/public/interfaces/sync_password_data.typemap
diff --git a/chromium/components/password_manager/public/interfaces/sync_password_data.typemap b/chromium/components/password_manager/public/interfaces/sync_password_data.typemap
deleted file mode 100644
index 8ee67acda80..00000000000
--- a/chromium/components/password_manager/public/interfaces/sync_password_data.typemap
+++ /dev/null
@@ -1,16 +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.
-
-mojom =
- "//components/password_manager/public/interfaces/sync_password_data.mojom"
-public_headers =
- [ "//components/password_manager/core/browser/hash_password_manager.h" ]
-traits_headers = [ "//components/password_manager/public/interfaces/sync_password_data_struct_traits.h" ]
-public_deps = [
- "//components/password_manager/core/browser:hash_password_manager",
-]
-
-type_mappings = [
- "password_manager.mojom.SyncPasswordData=password_manager::SyncPasswordData",
-]
diff --git a/chromium/components/password_manager/public/interfaces/sync_password_data_struct_traits.h b/chromium/components/password_manager/public/interfaces/sync_password_data_struct_traits.h
deleted file mode 100644
index 97fe4812847..00000000000
--- a/chromium/components/password_manager/public/interfaces/sync_password_data_struct_traits.h
+++ /dev/null
@@ -1,45 +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 COMPONENTS_PASSWORD_MANAGER_PUBLIC_INTERFACES_SYNC_PASSWORD_DATA_STRUCT_TRAITS_H_
-#define COMPONENTS_PASSWORD_MANAGER_PUBLIC_INTERFACES_SYNC_PASSWORD_DATA_STRUCT_TRAITS_H_
-
-#include <string>
-
-#include "components/password_manager/core/browser/hash_password_manager.h"
-#include "components/password_manager/public/interfaces/sync_password_data.mojom.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<password_manager::mojom::SyncPasswordDataDataView,
- password_manager::SyncPasswordData> {
- static uint32_t length(const password_manager::SyncPasswordData& r) {
- return r.length;
- }
- static const std::string& salt(const password_manager::SyncPasswordData& r) {
- return r.salt;
- }
- static uint64_t hash(const password_manager::SyncPasswordData& r) {
- return r.hash;
- }
-
- static bool force_update(const password_manager::SyncPasswordData& r) {
- return r.force_update;
- }
-
- static bool Read(password_manager::mojom::SyncPasswordDataDataView data,
- password_manager::SyncPasswordData* out) {
- if (!data.ReadSalt(&out->salt))
- return false;
- out->length = data.length();
- out->hash = data.hash();
- out->force_update = data.force_update();
- return true;
- }
-};
-
-} // namespace mojo
-
-#endif // COMPONENTS_PASSWORD_MANAGER_PUBLIC_INTERFACES_SYNC_PASSWORD_DATA_STRUCT_TRAITS_H_
diff --git a/chromium/components/password_manager/sync/browser/password_data_type_controller.cc b/chromium/components/password_manager/sync/browser/password_data_type_controller.cc
index 49213ea44b8..eff4f693dd4 100644
--- a/chromium/components/password_manager/sync/browser/password_data_type_controller.cc
+++ b/chromium/components/password_manager/sync/browser/password_data_type_controller.cc
@@ -32,7 +32,7 @@ bool PasswordDataTypeController::PostTaskOnModelThread(
const base::Location& from_here,
const base::Closure& task) {
DCHECK(CalledOnValidThread());
- if (!password_store_.get())
+ if (!password_store_)
return false;
return password_store_->ScheduleTask(task);
}
@@ -45,7 +45,7 @@ bool PasswordDataTypeController::StartModels() {
OnStateChanged(sync_client_->GetSyncService());
- return !!password_store_.get();
+ return !!password_store_;
}
void PasswordDataTypeController::StopModels() {
diff --git a/chromium/components/password_manager/sync/browser/password_model_worker.cc b/chromium/components/password_manager/sync/browser/password_model_worker.cc
index 14e10a4975b..cdb261feffe 100644
--- a/chromium/components/password_manager/sync/browser/password_model_worker.cc
+++ b/chromium/components/password_manager/sync/browser/password_model_worker.cc
@@ -13,7 +13,7 @@ namespace browser_sync {
PasswordModelWorker::PasswordModelWorker(
const scoped_refptr<password_manager::PasswordStore>& password_store)
: password_store_(password_store) {
- DCHECK(password_store.get());
+ DCHECK(password_store);
}
syncer::ModelSafeGroup PasswordModelWorker::GetModelSafeGroup() {
diff --git a/chromium/components/password_manager/sync/browser/password_sync_util.cc b/chromium/components/password_manager/sync/browser/password_sync_util.cc
index 86977477eeb..26cf165a3fa 100644
--- a/chromium/components/password_manager/sync/browser/password_sync_util.cc
+++ b/chromium/components/password_manager/sync/browser/password_sync_util.cc
@@ -7,13 +7,14 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_reuse_defines.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_urls.h"
#include "url/origin.h"
-#if !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
#include "components/safe_browsing/common/safe_browsing_prefs.h"
-#endif // !OS_IOS
+#endif // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
using autofill::PasswordForm;
using url::Origin;
@@ -43,9 +44,9 @@ std::string GetSyncUsernameIfSyncingPasswords(
return signin_manager->GetAuthenticatedAccountInfo().email;
}
-bool IsGoogleSyncAccount(const autofill::PasswordForm& form,
- const syncer::SyncService* sync_service,
- const SigninManagerBase* signin_manager) {
+bool IsSyncAccountCredential(const autofill::PasswordForm& form,
+ const syncer::SyncService* sync_service,
+ const SigninManagerBase* signin_manager) {
const Origin gaia_origin =
Origin::Create(GaiaUrls::GetInstance()->gaia_url().GetOrigin());
if (!Origin::Create(GURL(form.signon_realm)).IsSameOriginWith(gaia_origin) &&
@@ -64,36 +65,36 @@ bool IsGoogleSyncAccount(const autofill::PasswordForm& form,
GetSyncUsernameIfSyncingPasswords(sync_service, signin_manager));
}
-bool IsSyncAccountCredential(const autofill::PasswordForm& form,
- const syncer::SyncService* sync_service,
- const SigninManagerBase* signin_manager,
- PrefService* prefs) {
-#if defined(OS_IOS)
- return IsGoogleSyncAccount(form, sync_service, signin_manager);
-#else
- if (safe_browsing::MatchesPasswordProtectionLoginURL(form.origin, *prefs) ||
+bool ShouldSavePasswordHash(const autofill::PasswordForm& form,
+ const SigninManagerBase* signin_manager,
+ PrefService* prefs) {
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
+ bool is_protected_credential_url =
+ gaia::IsGaiaSignonRealm(GURL(form.signon_realm)) ||
+ form.signon_realm == kGoogleChangePasswordSignonRealm ||
+ safe_browsing::MatchesPasswordProtectionLoginURL(form.origin, *prefs) ||
safe_browsing::MatchesPasswordProtectionChangePasswordURL(form.origin,
- *prefs)) {
- // Form is on one of the enterprise configured password protection URLs,
- // then we need to check its user name field.
- std::string sync_user_name =
- GetSyncUsernameIfSyncingPasswords(sync_service, signin_manager);
-
- // User is not signed in or is not syncing password.
- if (sync_user_name.empty())
- return false;
-
- // For some SSO case, username might not be the complete email address.
- // It might be the email prefix before '@'.
- std::string username = base::UTF16ToUTF8(form.username_value);
- if (username.find('@') == std::string::npos) {
- username += "@";
- username += gaia::ExtractDomainName(sync_user_name);
- }
- return gaia::AreEmailsSame(username, sync_user_name);
- }
- return IsGoogleSyncAccount(form, sync_service, signin_manager);
-#endif
+ *prefs);
+
+ if (!is_protected_credential_url)
+ return false;
+
+ std::string sync_email = signin_manager->GetAuthenticatedAccountInfo().email;
+ std::string username = base::UTF16ToUTF8(form.username_value);
+
+ if (sync_email.empty() || username.empty())
+ return false;
+
+ // Add @domain.name to the username if it is absent.
+ std::string email =
+ username + (username.find('@') == std::string::npos
+ ? "@" + gaia::ExtractDomainName(sync_email)
+ : std::string());
+
+ return email == sync_email;
+#else
+ return false;
+#endif // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
}
} // namespace sync_util
diff --git a/chromium/components/password_manager/sync/browser/password_sync_util.h b/chromium/components/password_manager/sync/browser/password_sync_util.h
index 9b1b0410e2e..38f0c94cb11 100644
--- a/chromium/components/password_manager/sync/browser/password_sync_util.h
+++ b/chromium/components/password_manager/sync/browser/password_sync_util.h
@@ -24,20 +24,19 @@ std::string GetSyncUsernameIfSyncingPasswords(
const syncer::SyncService* sync_service,
const SigninManagerBase* signin_manager);
-// If |form| doesn't match GAIA sign-on realm or enterprise-specified password
-// protection URL, returns false. Otherwise, checks if the username
-// in |form| matches sync account.
-bool IsSyncAccountCredential(const autofill::PasswordForm& form,
- const syncer::SyncService* sync_service,
- const SigninManagerBase* signin_manager,
- PrefService* prefs);
-
// Returns true if |form| corresponds to the account specified by
// GetSyncUsernameIfSyncingPasswords. Returns false if
// GetSyncUsernameIfSyncingPasswords does not specify any account.
-bool IsGoogleSyncAccount(const autofill::PasswordForm& form,
- const syncer::SyncService* sync_service,
- const SigninManagerBase* signin_manager);
+bool IsSyncAccountCredential(const autofill::PasswordForm& form,
+ const syncer::SyncService* sync_service,
+ const SigninManagerBase* signin_manager);
+
+// If |form| doesn't match GAIA sign-on realm or enterprise-specified password
+// protection URL, returns false. Otherwise, checks if the username
+// in |form| matches sign-in account (no syncing passwords are required).
+bool ShouldSavePasswordHash(const autofill::PasswordForm& form,
+ const SigninManagerBase* signin_manager,
+ PrefService* prefs);
} // namespace sync_util
} // namespace password_manager
diff --git a/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc b/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc
index cbc556973a6..c90545f8a3a 100644
--- a/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc
+++ b/chromium/components/password_manager/sync/browser/password_sync_util_unittest.cc
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "build/build_config.h"
#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/password_reuse_defines.h"
#include "components/password_manager/sync/browser/sync_username_test_base.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/testing_pref_service.h"
@@ -70,7 +71,7 @@ TEST_F(PasswordSyncUtilTest, GetSyncUsernameIfSyncingPasswords) {
}
}
-TEST_F(PasswordSyncUtilTest, IsGoogleSyncAccount) {
+TEST_F(PasswordSyncUtilTest, IsSyncAccountCredential) {
const struct {
PasswordForm form;
std::string fake_sync_username;
@@ -91,12 +92,12 @@ TEST_F(PasswordSyncUtilTest, IsGoogleSyncAccount) {
SetSyncingPasswords(true);
FakeSigninAs(kTestCases[i].fake_sync_username);
EXPECT_EQ(kTestCases[i].expected_result,
- IsGoogleSyncAccount(kTestCases[i].form, sync_service(),
- signin_manager()));
+ IsSyncAccountCredential(kTestCases[i].form, sync_service(),
+ signin_manager()));
}
}
-#if !defined(OS_IOS)
+#if defined(SYNC_PASSWORD_REUSE_DETECTION_ENABLED)
class PasswordSyncUtilEnterpriseTest : public SyncUsernameTestBase {
public:
void SetUp() override {
@@ -113,8 +114,7 @@ class PasswordSyncUtilEnterpriseTest : public SyncUsernameTestBase {
base::test::ScopedFeatureList feature_list_;
};
-TEST_F(PasswordSyncUtilEnterpriseTest,
- IsSyncAccountCredentialForEnterpriseSSO) {
+TEST_F(PasswordSyncUtilEnterpriseTest, ShouldSavePasswordHash) {
prefs_.SetString(prefs::kPasswordProtectionChangePasswordURL,
"https://pwchange.mydomain.com/");
base::ListValue login_url;
@@ -155,16 +155,18 @@ TEST_F(PasswordSyncUtilEnterpriseTest,
"sync_user@mydomain.com", false},
};
- for (size_t i = 0; i < arraysize(kTestCases); ++i) {
- SCOPED_TRACE(testing::Message() << "i=" << i);
- SetSyncingPasswords(true);
- FakeSigninAs(kTestCases[i].fake_sync_username);
- EXPECT_EQ(kTestCases[i].expected_result,
- IsSyncAccountCredential(kTestCases[i].form, sync_service(),
- signin_manager(), &prefs_));
+ for (bool syncing_passwords : {false, true}) {
+ for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+ SCOPED_TRACE(testing::Message() << "i=" << i);
+ SetSyncingPasswords(syncing_passwords);
+ FakeSigninAs(kTestCases[i].fake_sync_username);
+ EXPECT_EQ(kTestCases[i].expected_result,
+ ShouldSavePasswordHash(kTestCases[i].form, signin_manager(),
+ &prefs_));
+ }
}
}
-#endif // !OS_IOS
+#endif // SYNC_PASSWORD_REUSE_DETECTION_ENABLED
} // namespace sync_util
} // namespace password_manager
diff --git a/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc b/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc
index 0be855ea6a6..04eb1cd3acc 100644
--- a/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc
+++ b/chromium/components/password_manager/sync/browser/sync_credentials_filter.cc
@@ -77,18 +77,25 @@ std::vector<std::unique_ptr<PasswordForm>> SyncCredentialsFilter::FilterResults(
bool SyncCredentialsFilter::ShouldSave(
const autofill::PasswordForm& form) const {
- return !sync_util::IsSyncAccountCredential(
- form, sync_service_factory_function_.Run(),
- signin_manager_factory_function_.Run(), client_->GetPrefs());
+ return !form.is_gaia_with_skip_save_password_form &&
+ !sync_util::IsSyncAccountCredential(
+ form, sync_service_factory_function_.Run(),
+ signin_manager_factory_function_.Run());
+}
+
+bool SyncCredentialsFilter::ShouldSavePasswordHash(
+ const autofill::PasswordForm& form) const {
+ return sync_util::ShouldSavePasswordHash(
+ form, signin_manager_factory_function_.Run(), client_->GetPrefs());
}
void SyncCredentialsFilter::ReportFormLoginSuccess(
const PasswordFormManager& form_manager) const {
if (!form_manager.IsNewLogin() &&
- sync_util::IsSyncAccountCredential(form_manager.pending_credentials(),
- sync_service_factory_function_.Run(),
- signin_manager_factory_function_.Run(),
- client_->GetPrefs())) {
+ sync_util::IsSyncAccountCredential(
+ form_manager.GetPendingCredentials(),
+ sync_service_factory_function_.Run(),
+ signin_manager_factory_function_.Run())) {
base::RecordAction(base::UserMetricsAction(
"PasswordManager_SyncCredentialFilledAndLoginSuccessfull"));
}
diff --git a/chromium/components/password_manager/sync/browser/sync_credentials_filter.h b/chromium/components/password_manager/sync/browser/sync_credentials_filter.h
index ecabd5e0ae4..2c0571f848a 100644
--- a/chromium/components/password_manager/sync/browser/sync_credentials_filter.h
+++ b/chromium/components/password_manager/sync/browser/sync_credentials_filter.h
@@ -44,6 +44,8 @@ class SyncCredentialsFilter : public CredentialsFilter {
std::vector<std::unique_ptr<autofill::PasswordForm>> results)
const override;
bool ShouldSave(const autofill::PasswordForm& form) const override;
+ bool ShouldSavePasswordHash(
+ const autofill::PasswordForm& form) const override;
void ReportFormLoginSuccess(
const PasswordFormManager& form_manager) const override;
diff --git a/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
index a6a3759f930..cfbc0b9a337 100644
--- a/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
+++ b/chromium/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
@@ -138,8 +138,7 @@ class CredentialsFilterTest : public SyncUsernameTestBase {
}
fetcher_.SetNonFederated(matches, 0u);
- form_manager_.ProvisionallySave(
- pending_, PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES);
+ form_manager_.ProvisionallySave(pending_);
}
protected:
@@ -350,6 +349,14 @@ TEST_F(CredentialsFilterTest, ShouldSave_SyncCredential) {
EXPECT_FALSE(filter_.ShouldSave(form));
}
+TEST_F(CredentialsFilterTest, ShouldSave_SignIn_Form) {
+ PasswordForm form = SimpleGaiaForm("user@example.org");
+ form.is_gaia_with_skip_save_password_form = true;
+
+ SetSyncingPasswords(false);
+ EXPECT_FALSE(filter_.ShouldSave(form));
+}
+
TEST_F(CredentialsFilterTest, ShouldSave_SyncCredential_NotSyncingPasswords) {
PasswordForm form = SimpleGaiaForm("user@example.org");
diff --git a/chromium/components/payments/content/DEPS b/chromium/components/payments/content/DEPS
index dea6d3ef610..a1853f1bc10 100644
--- a/chromium/components/payments/content/DEPS
+++ b/chromium/components/payments/content/DEPS
@@ -12,6 +12,7 @@ include_rules = [
"+net",
"+services/data_decoder/public/cpp",
"+sql",
+ "+third_party/blink/public/common",
"+third_party/blink/public/platform/modules/payments",
"+third_party/skia/include/core/SkBitmap.h",
"+ui/base",
diff --git a/chromium/components/payments/content/android/currency_formatter_android.cc b/chromium/components/payments/content/android/currency_formatter_android.cc
index 89eae59b06f..a1c4efa40c3 100644
--- a/chromium/components/payments/content/android/currency_formatter_android.cc
+++ b/chromium/components/payments/content/android/currency_formatter_android.cc
@@ -21,14 +21,10 @@ CurrencyFormatterAndroid::CurrencyFormatterAndroid(
JNIEnv* env,
jobject jcaller,
const JavaParamRef<jstring>& currency_code,
- const JavaParamRef<jstring>& currency_system,
const JavaParamRef<jstring>& locale_name) {
- std::string currency_system_str =
- ConvertJavaStringToUTF8(env, currency_system);
-
- currency_formatter_.reset(new CurrencyFormatter(
- ConvertJavaStringToUTF8(env, currency_code), currency_system_str,
- ConvertJavaStringToUTF8(env, locale_name)));
+ currency_formatter_.reset(
+ new CurrencyFormatter(ConvertJavaStringToUTF8(env, currency_code),
+ ConvertJavaStringToUTF8(env, locale_name)));
}
CurrencyFormatterAndroid::~CurrencyFormatterAndroid() {}
@@ -59,11 +55,9 @@ static jlong JNI_CurrencyFormatter_InitCurrencyFormatterAndroid(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& currency_code,
- const JavaParamRef<jstring>& currency_system,
const JavaParamRef<jstring>& locale_name) {
CurrencyFormatterAndroid* currency_formatter_android =
- new CurrencyFormatterAndroid(env, obj, currency_code, currency_system,
- locale_name);
+ new CurrencyFormatterAndroid(env, obj, currency_code, locale_name);
return reinterpret_cast<intptr_t>(currency_formatter_android);
}
diff --git a/chromium/components/payments/content/android/currency_formatter_android.h b/chromium/components/payments/content/android/currency_formatter_android.h
index 886388dc512..76b1577d604 100644
--- a/chromium/components/payments/content/android/currency_formatter_android.h
+++ b/chromium/components/payments/content/android/currency_formatter_android.h
@@ -22,7 +22,6 @@ class CurrencyFormatterAndroid {
JNIEnv* env,
jobject jcaller,
const base::android::JavaParamRef<jstring>& currency_code,
- const base::android::JavaParamRef<jstring>& currency_system,
const base::android::JavaParamRef<jstring>& locale_name);
~CurrencyFormatterAndroid();
diff --git a/chromium/components/payments/content/installable_payment_app_crawler.cc b/chromium/components/payments/content/installable_payment_app_crawler.cc
index dba2b202b31..324fb68bc0c 100644
--- a/chromium/components/payments/content/installable_payment_app_crawler.cc
+++ b/chromium/components/payments/content/installable_payment_app_crawler.cc
@@ -11,11 +11,12 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/manifest_icon_downloader.h"
#include "content/public/browser/manifest_icon_selector.h"
+#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/permission_manager.h"
#include "content/public/browser/permission_type.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/console_message_level.h"
-#include "content/public/common/manifest.h"
+#include "third_party/blink/public/common/manifest/manifest.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
#include "url/origin.h"
@@ -211,6 +212,14 @@ bool InstallablePaymentAppCrawler::CompleteAndStorePaymentWebAppInfoIfValid(
app_info->sw_scope = absolute_scope.spec();
}
+ std::string error_message;
+ if (!content::PaymentAppProvider::GetInstance()->IsValidInstallablePaymentApp(
+ web_app_manifest_url, GURL(app_info->sw_js_url),
+ GURL(app_info->sw_scope), &error_message)) {
+ WarnIfPossible(error_message);
+ return false;
+ }
+
// TODO(crbug.com/782270): Support multiple installable payment apps for a
// payment method.
if (installable_apps_.find(method_manifest_url) != installable_apps_.end())
@@ -228,7 +237,7 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
if (icons == nullptr || icons->empty())
return;
- std::vector<content::Manifest::Icon> manifest_icons;
+ std::vector<blink::Manifest::Icon> manifest_icons;
for (const auto& icon : *icons) {
if (icon.src.empty() || !base::IsStringUTF8(icon.src)) {
WarnIfPossible(
@@ -248,10 +257,10 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
}
}
- content::Manifest::Icon manifest_icon;
+ blink::Manifest::Icon manifest_icon;
manifest_icon.src = icon_src;
manifest_icon.type = base::UTF8ToUTF16(icon.type);
- manifest_icon.purpose.emplace_back(content::Manifest::Icon::ANY);
+ manifest_icon.purpose.emplace_back(blink::Manifest::Icon::ANY);
// TODO(crbug.com/782270): Parse icon sizes.
manifest_icon.sizes.emplace_back(gfx::Size());
manifest_icons.emplace_back(manifest_icon);
@@ -268,7 +277,7 @@ void InstallablePaymentAppCrawler::DownloadAndDecodeWebAppIcon(
const int kPaymentAppMinimumIconSize = 0;
GURL best_icon_url = content::ManifestIconSelector::FindBestMatchingIcon(
manifest_icons, kPaymentAppIdealIconSize, kPaymentAppMinimumIconSize,
- content::Manifest::Icon::ANY);
+ blink::Manifest::Icon::ANY);
if (!best_icon_url.is_valid()) {
WarnIfPossible(
"No suitable icon found in the installabble payment app's manifest (" +
diff --git a/chromium/components/payments/content/payment_request.cc b/chromium/components/payments/content/payment_request.cc
index 050b9503eb7..a791237f311 100644
--- a/chromium/components/payments/content/payment_request.cc
+++ b/chromium/components/payments/content/payment_request.cc
@@ -18,6 +18,7 @@
#include "components/payments/core/features.h"
#include "components/payments/core/payment_details.h"
#include "components/payments/core/payment_details_validation.h"
+#include "components/payments/core/payment_instrument.h"
#include "components/payments/core/payment_prefs.h"
#include "components/prefs/pref_service.h"
#include "components/url_formatter/elide_url.h"
@@ -265,11 +266,16 @@ void PaymentRequest::Complete(mojom::PaymentComplete result) {
}
void PaymentRequest::CanMakePayment() {
- state()->CanMakePayment(base::BindOnce(
- &PaymentRequest::CanMakePaymentCallback, weak_ptr_factory_.GetWeakPtr()));
-
if (observer_for_testing_)
observer_for_testing_->OnCanMakePaymentCalled();
+
+ if (!delegate_->GetPrefService()->GetBoolean(kCanMakePaymentEnabled)) {
+ CanMakePaymentCallback(/*can_make_payment=*/false);
+ } else {
+ state()->CanMakePayment(
+ base::BindOnce(&PaymentRequest::CanMakePaymentCallback,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
}
void PaymentRequest::OnPaymentResponseAvailable(
@@ -342,7 +348,24 @@ void PaymentRequest::OnConnectionTerminated() {
void PaymentRequest::Pay() {
journey_logger_.SetEventOccurred(JourneyLogger::EVENT_PAY_CLICKED);
- journey_logger_.SetEventOccurred(JourneyLogger::EVENT_SELECTED_CREDIT_CARD);
+
+ // Log the correct "selected instrument" metric according to type.
+ DCHECK(state_->selected_instrument());
+ JourneyLogger::Event selected_event =
+ JourneyLogger::Event::EVENT_SELECTED_OTHER;
+ switch (state_->selected_instrument()->type()) {
+ case PaymentInstrument::Type::AUTOFILL:
+ selected_event = JourneyLogger::Event::EVENT_SELECTED_CREDIT_CARD;
+ break;
+ case PaymentInstrument::Type::SERVICE_WORKER_APP:
+ selected_event = JourneyLogger::Event::EVENT_SELECTED_OTHER;
+ break;
+ case PaymentInstrument::Type::NATIVE_MOBILE_APP:
+ NOTREACHED();
+ break;
+ }
+ journey_logger_.SetEventOccurred(selected_event);
+
state_->GeneratePaymentResponse();
}
@@ -394,12 +417,6 @@ void PaymentRequest::CanMakePaymentCallback(bool can_make_payment) {
void PaymentRequest::RespondToCanMakePaymentQuery(bool can_make_payment,
bool warn_localhost_or_file) {
- if (delegate_->IsIncognito()) {
- can_make_payment =
- spec()->HasBasicCardMethodName() ||
- base::FeatureList::IsEnabled(::features::kServiceWorkerPaymentApps);
- }
-
mojom::CanMakePaymentQueryResult positive =
warn_localhost_or_file
? mojom::CanMakePaymentQueryResult::WARNING_CAN_MAKE_PAYMENT
diff --git a/chromium/components/payments/content/payment_request_spec.cc b/chromium/components/payments/content/payment_request_spec.cc
index 8b48157fd4a..ef18c44e0a0 100644
--- a/chromium/components/payments/content/payment_request_spec.cc
+++ b/chromium/components/payments/content/payment_request_spec.cc
@@ -155,15 +155,15 @@ bool PaymentRequestSpec::IsMethodSupportedThroughBasicCard(
base::string16 PaymentRequestSpec::GetFormattedCurrencyAmount(
const mojom::PaymentCurrencyAmountPtr& currency_amount) {
- CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
- currency_amount->currency, currency_amount->currency_system, app_locale_);
+ CurrencyFormatter* formatter =
+ GetOrCreateCurrencyFormatter(currency_amount->currency, app_locale_);
return formatter->Format(currency_amount->value);
}
std::string PaymentRequestSpec::GetFormattedCurrencyCode(
const mojom::PaymentCurrencyAmountPtr& currency_amount) {
- CurrencyFormatter* formatter = GetOrCreateCurrencyFormatter(
- currency_amount->currency, currency_amount->currency_system, app_locale_);
+ CurrencyFormatter* formatter =
+ GetOrCreateCurrencyFormatter(currency_amount->currency, app_locale_);
return formatter->formatted_currency_code();
}
@@ -214,10 +214,6 @@ PaymentRequestSpec::GetShippingOptions() const {
return details_->shipping_options;
}
-bool PaymentRequestSpec::HasBasicCardMethodName() const {
- return !supported_card_networks_set_.empty();
-}
-
const mojom::PaymentDetailsModifierPtr*
PaymentRequestSpec::GetApplicableModifier(
PaymentInstrument* selected_instrument) const {
@@ -306,14 +302,13 @@ void PaymentRequestSpec::NotifyOnSpecUpdated() {
CurrencyFormatter* PaymentRequestSpec::GetOrCreateCurrencyFormatter(
const std::string& currency_code,
- const std::string& currency_system,
const std::string& locale_name) {
// Create a currency formatter for |currency_code|, or if already created
// return the cached version.
std::pair<std::map<std::string, CurrencyFormatter>::iterator, bool>
emplace_result = currency_formatters_.emplace(
std::piecewise_construct, std::forward_as_tuple(currency_code),
- std::forward_as_tuple(currency_code, currency_system, locale_name));
+ std::forward_as_tuple(currency_code, locale_name));
return &(emplace_result.first->second);
}
diff --git a/chromium/components/payments/content/payment_request_spec.h b/chromium/components/payments/content/payment_request_spec.h
index 9bb5b2799b4..9baf9b61590 100644
--- a/chromium/components/payments/content/payment_request_spec.h
+++ b/chromium/components/payments/content/payment_request_spec.h
@@ -151,10 +151,6 @@ class PaymentRequestSpec : public PaymentOptionsProvider {
return method_data_;
}
- // Returns whether any of the payment method names are "basic-card" or one of
- // the networks ("visa", "amex", "mastercard", etc).
- bool HasBasicCardMethodName() const;
-
private:
// Returns the first applicable modifier in the Payment Request for the
// |selected_instrument|.
@@ -178,7 +174,6 @@ class PaymentRequestSpec : public PaymentOptionsProvider {
// the CurrencyFormatter is cached here.
CurrencyFormatter* GetOrCreateCurrencyFormatter(
const std::string& currency_code,
- const std::string& currency_system,
const std::string& locale_name);
mojom::PaymentOptionsPtr options_;
diff --git a/chromium/components/payments/content/service_worker_payment_app_factory.cc b/chromium/components/payments/content/service_worker_payment_app_factory.cc
index 67772a371e1..75458892b5d 100644
--- a/chromium/components/payments/content/service_worker_payment_app_factory.cc
+++ b/chromium/components/payments/content/service_worker_payment_app_factory.cc
@@ -16,6 +16,7 @@
#include "components/payments/content/manifest_verifier.h"
#include "components/payments/content/payment_manifest_web_data_service.h"
#include "components/payments/content/utility/payment_manifest_parser.h"
+#include "components/payments/core/features.h"
#include "components/payments/core/payment_manifest_downloader.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -112,7 +113,9 @@ class SelfDeletingServiceWorkerPaymentAppFactory {
cache_ = cache;
verifier_ = std::make_unique<ManifestVerifier>(
web_contents, downloader_.get(), parser_.get(), cache_.get());
- if (may_crawl_for_installable_payment_apps) {
+ if (may_crawl_for_installable_payment_apps &&
+ base::FeatureList::IsEnabled(
+ features::kWebPaymentsJustInTimePaymentApp)) {
// Construct crawler in constructor to allow it observe the web_contents.
crawler_ = std::make_unique<InstallablePaymentAppCrawler>(
web_contents, downloader_.get(), parser_.get(), cache_.get());
diff --git a/chromium/components/payments/content/service_worker_payment_instrument.cc b/chromium/components/payments/content/service_worker_payment_instrument.cc
index f9ea72eccdb..3e84fcdfdb5 100644
--- a/chromium/components/payments/content/service_worker_payment_instrument.cc
+++ b/chromium/components/payments/content/service_worker_payment_instrument.cc
@@ -13,6 +13,7 @@
#include "content/public/browser/payment_app_provider.h"
#include "content/public/browser/web_contents.h"
#include "ui/gfx/image/image_skia.h"
+#include "url/origin.h"
namespace payments {
@@ -20,14 +21,14 @@ namespace payments {
// resource Id.
ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
content::BrowserContext* browser_context,
- const GURL& top_level_origin,
+ const GURL& top_origin,
const GURL& frame_origin,
const PaymentRequestSpec* spec,
std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info,
PaymentRequestDelegate* payment_request_delegate)
: PaymentInstrument(0, PaymentInstrument::Type::SERVICE_WORKER_APP),
browser_context_(browser_context),
- top_level_origin_(top_level_origin),
+ top_origin_(top_origin),
frame_origin_(frame_origin),
spec_(spec),
stored_payment_app_info_(std::move(stored_payment_app_info)),
@@ -37,7 +38,7 @@ ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
needs_installation_(false),
weak_ptr_factory_(this) {
DCHECK(browser_context_);
- DCHECK(top_level_origin_.is_valid());
+ DCHECK(top_origin_.is_valid());
DCHECK(frame_origin_.is_valid());
DCHECK(spec_);
@@ -55,14 +56,14 @@ ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
// resource Id.
ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
content::WebContents* web_contents,
- const GURL& top_level_origin,
+ const GURL& top_origin,
const GURL& frame_origin,
const PaymentRequestSpec* spec,
std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info,
const std::string& enabled_method,
PaymentRequestDelegate* payment_request_delegate)
: PaymentInstrument(0, PaymentInstrument::Type::SERVICE_WORKER_APP),
- top_level_origin_(top_level_origin),
+ top_origin_(top_origin),
frame_origin_(frame_origin),
spec_(spec),
delegate_(nullptr),
@@ -74,7 +75,7 @@ ServiceWorkerPaymentInstrument::ServiceWorkerPaymentInstrument(
installable_enabled_method_(enabled_method),
weak_ptr_factory_(this) {
DCHECK(web_contents_);
- DCHECK(top_level_origin_.is_valid());
+ DCHECK(top_origin_.is_valid());
DCHECK(frame_origin_.is_valid());
DCHECK(spec_);
@@ -109,6 +110,13 @@ void ServiceWorkerPaymentInstrument::ValidateCanMakePayment(
return;
}
+ // Returns true if we are in incognito (avoiding sending the event to the
+ // payment handler).
+ if (payment_request_delegate_->IsIncognito()) {
+ OnCanMakePayment(std::move(callback), true);
+ return;
+ }
+
// Do not send CanMakePayment event to payment apps that have not been
// explicitly verified.
if (!stored_payment_app_info_->has_explicitly_verified_methods) {
@@ -156,7 +164,7 @@ ServiceWorkerPaymentInstrument::CreateCanMakePaymentEventData() {
mojom::CanMakePaymentEventDataPtr event_data =
mojom::CanMakePaymentEventData::New();
- event_data->top_level_origin = top_level_origin_;
+ event_data->top_origin = top_origin_;
event_data->payment_request_origin = frame_origin_;
for (const auto& modifier : spec_->details().modifiers) {
@@ -228,7 +236,7 @@ ServiceWorkerPaymentInstrument::CreatePaymentRequestEventData() {
mojom::PaymentRequestEventDataPtr event_data =
mojom::PaymentRequestEventData::New();
- event_data->top_level_origin = top_level_origin_;
+ event_data->top_origin = top_origin_;
event_data->payment_request_origin = frame_origin_;
if (spec_->details().id.has_value())
@@ -323,9 +331,10 @@ base::string16 ServiceWorkerPaymentInstrument::GetSublabel() const {
if (needs_installation_) {
DCHECK(GURL(installable_web_app_info_->sw_scope).is_valid());
return base::UTF8ToUTF16(
- GURL(installable_web_app_info_->sw_scope).GetOrigin().spec());
+ url::Origin::Create(GURL(installable_web_app_info_->sw_scope)).host());
}
- return base::UTF8ToUTF16(stored_payment_app_info_->scope.GetOrigin().spec());
+ return base::UTF8ToUTF16(
+ url::Origin::Create(stored_payment_app_info_->scope).host());
}
bool ServiceWorkerPaymentInstrument::IsValidForModifier(
diff --git a/chromium/components/payments/content/service_worker_payment_instrument.h b/chromium/components/payments/content/service_worker_payment_instrument.h
index 9af6cc4cc64..0f5dc8c127b 100644
--- a/chromium/components/payments/content/service_worker_payment_instrument.h
+++ b/chromium/components/payments/content/service_worker_payment_instrument.h
@@ -28,7 +28,7 @@ class ServiceWorkerPaymentInstrument : public PaymentInstrument {
// Chrome.
ServiceWorkerPaymentInstrument(
content::BrowserContext* browser_context,
- const GURL& top_level_origin,
+ const GURL& top_origin,
const GURL& frame_origin,
const PaymentRequestSpec* spec,
std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info,
@@ -38,7 +38,7 @@ class ServiceWorkerPaymentInstrument : public PaymentInstrument {
// Chrome but can be installed when paying with it.
ServiceWorkerPaymentInstrument(
content::WebContents* web_contents,
- const GURL& top_level_origin,
+ const GURL& top_origin,
const GURL& frame_origin,
const PaymentRequestSpec* spec,
std::unique_ptr<WebAppInstallationInfo> installable_payment_app_info,
@@ -87,7 +87,7 @@ class ServiceWorkerPaymentInstrument : public PaymentInstrument {
void OnCanMakePayment(ValidateCanMakePaymentCallback callback, bool result);
content::BrowserContext* browser_context_;
- GURL top_level_origin_;
+ GURL top_origin_;
GURL frame_origin_;
const PaymentRequestSpec* spec_;
std::unique_ptr<content::StoredPaymentApp> stored_payment_app_info_;
diff --git a/chromium/components/payments/content/service_worker_payment_instrument_unittest.cc b/chromium/components/payments/content/service_worker_payment_instrument_unittest.cc
index ef43c6bf802..76d7e782777 100644
--- a/chromium/components/payments/content/service_worker_payment_instrument_unittest.cc
+++ b/chromium/components/payments/content/service_worker_payment_instrument_unittest.cc
@@ -175,8 +175,7 @@ TEST_F(ServiceWorkerPaymentInstrumentTest, InstrumentInfo) {
EXPECT_TRUE(GetInstrument()->IsExactlyMatchingMerchantRequest());
EXPECT_EQ(base::UTF16ToUTF8(GetInstrument()->GetLabel()), "bobpay");
- EXPECT_EQ(base::UTF16ToUTF8(GetInstrument()->GetSublabel()),
- "https://bobpay.com/");
+ EXPECT_EQ(base::UTF16ToUTF8(GetInstrument()->GetSublabel()), "bobpay.com");
EXPECT_NE(GetInstrument()->icon_image_skia(), nullptr);
}
@@ -188,7 +187,7 @@ TEST_F(ServiceWorkerPaymentInstrumentTest, CreatePaymentRequestEventData) {
mojom::PaymentRequestEventDataPtr event_data =
CreatePaymentRequestEventData();
- EXPECT_EQ(event_data->top_level_origin.spec(), "https://testmerchant.com/");
+ EXPECT_EQ(event_data->top_origin.spec(), "https://testmerchant.com/");
EXPECT_EQ(event_data->payment_request_origin.spec(),
"https://testmerchant.com/bobpay");
@@ -228,7 +227,7 @@ TEST_F(ServiceWorkerPaymentInstrumentTest, CreateCanMakePaymentEvent) {
event_data = CreateCanMakePaymentEventData();
EXPECT_FALSE(event_data.is_null());
- EXPECT_EQ(event_data->top_level_origin.spec(), "https://testmerchant.com/");
+ EXPECT_EQ(event_data->top_origin.spec(), "https://testmerchant.com/");
EXPECT_EQ(event_data->payment_request_origin.spec(),
"https://testmerchant.com/bobpay");
diff --git a/chromium/components/payments/content/utility/payment_manifest_parser.cc b/chromium/components/payments/content/utility/payment_manifest_parser.cc
index 1ad3989f110..2b792a19404 100644
--- a/chromium/components/payments/content/utility/payment_manifest_parser.cc
+++ b/chromium/components/payments/content/utility/payment_manifest_parser.cc
@@ -449,7 +449,7 @@ void PaymentManifestParser::OnWebAppParseInstallationInfo(
std::unique_ptr<base::Value> value) {
// TODO(crbug.com/782270): Move this function into a static function for unit
// test.
- if (value->FindKey({kServiceWorker}) == nullptr) {
+ if (!value || value->FindKey({kServiceWorker}) == nullptr) {
return std::move(callback).Run(nullptr, nullptr);
}
diff --git a/chromium/components/payments/core/currency_formatter.cc b/chromium/components/payments/core/currency_formatter.cc
index dae2383c932..2766fa6f709 100644
--- a/chromium/components/payments/core/currency_formatter.cc
+++ b/chromium/components/payments/core/currency_formatter.cc
@@ -14,8 +14,6 @@
namespace payments {
-const char kIso4217CurrencySystem[] = "urn:iso:std:iso:4217";
-
namespace {
// Support a maximum of 10 fractional digits, similar to the ISO20022 standard.
@@ -33,11 +31,8 @@ const static size_t kMaxCurrencyCodeDisplayedChars = 6;
const char kEllipsis[] = "\xE2\x80\xA6";
// Returns whether the |currency_code| is valid to be used in ICU.
-bool ShouldUseCurrencyCode(const std::string& currency_code,
- const std::string& currency_system) {
- return (currency_system.empty() ||
- currency_system == kIso4217CurrencySystem) &&
- !currency_code.empty() &&
+bool ShouldUseCurrencyCode(const std::string& currency_code) {
+ return !currency_code.empty() &&
currency_code.size() <= kMaxCurrencyCodeLength;
}
@@ -51,7 +46,6 @@ std::string FormatCurrencyCode(const std::string& currency_code) {
} // namespace
CurrencyFormatter::CurrencyFormatter(const std::string& currency_code,
- const std::string& currency_system,
const std::string& locale_name)
: locale_(locale_name.c_str()),
formatted_currency_code_(FormatCurrencyCode(currency_code)) {
@@ -64,7 +58,7 @@ CurrencyFormatter::CurrencyFormatter(const std::string& currency_code,
return;
}
- if (ShouldUseCurrencyCode(currency_code, currency_system)) {
+ if (ShouldUseCurrencyCode(currency_code)) {
currency_code_.reset(new icu::UnicodeString(
currency_code.c_str(),
base::checked_cast<int32_t>(currency_code.size())));
diff --git a/chromium/components/payments/core/currency_formatter.h b/chromium/components/payments/core/currency_formatter.h
index eec9d66bf17..26443e18e92 100644
--- a/chromium/components/payments/core/currency_formatter.h
+++ b/chromium/components/payments/core/currency_formatter.h
@@ -16,20 +16,14 @@
namespace payments {
-// URI specifying the ISO4217 currency code specification. See for details:
-// https://w3c.github.io/browser-payment-api/#paymentcurrencyamount-dictionary
-extern const char kIso4217CurrencySystem[];
-
// Currency formatter for amounts, according to a currency code, which typically
// adheres to [ISO4217] (for example, "USD" for US Dollars).
class CurrencyFormatter {
public:
// Initializes the CurrencyFormatter for a given |currency_code|,
- // |currency_system| and |locale_name|. Note that |currency_code| and
- // |currency_system| should have been validated (as part of
- // payment_details_validation.h) before this is created.
+ // |locale_name|. Note that |currency_code| should have been validated
+ // (as part of payment_details_validation.h) before this is created.
CurrencyFormatter(const std::string& currency_code,
- const std::string& currency_system,
const std::string& locale_name);
~CurrencyFormatter();
diff --git a/chromium/components/payments/core/currency_formatter_unittest.cc b/chromium/components/payments/core/currency_formatter_unittest.cc
index 705c23a74a0..2d0de367629 100644
--- a/chromium/components/payments/core/currency_formatter_unittest.cc
+++ b/chromium/components/payments/core/currency_formatter_unittest.cc
@@ -16,14 +16,12 @@ struct TestCase {
const char* currency_code,
const char* locale_name,
const std::string& expected_amount,
- const char* expected_currency_code,
- const char* currency_system = kIso4217CurrencySystem)
+ const char* expected_currency_code)
: amount(amount),
currency_code(currency_code),
locale_name(locale_name),
expected_amount(expected_amount),
- expected_currency_code(expected_currency_code),
- currency_system(currency_system) {}
+ expected_currency_code(expected_currency_code) {}
~TestCase() {}
const char* const amount;
@@ -31,7 +29,6 @@ struct TestCase {
const char* const locale_name;
const std::string expected_amount;
const char* const expected_currency_code;
- const char* const currency_system;
};
class PaymentsCurrencyFormatterTest : public testing::TestWithParam<TestCase> {
@@ -39,7 +36,6 @@ class PaymentsCurrencyFormatterTest : public testing::TestWithParam<TestCase> {
TEST_P(PaymentsCurrencyFormatterTest, IsValidCurrencyFormat) {
CurrencyFormatter formatter(GetParam().currency_code,
- GetParam().currency_system,
GetParam().locale_name);
base::string16 output_amount = formatter.Format(GetParam().amount);
@@ -135,61 +131,5 @@ INSTANTIATE_TEST_CASE_P(
"123 456 789 012 345 678 901 234 567 890,123456789 $",
"USD")));
-INSTANTIATE_TEST_CASE_P(
- CurrencySystems,
- PaymentsCurrencyFormatterTest,
- testing::Values(
- // When the currency system is not ISO4217, only the amount is formatted
- // using the locale (there is no other indication of currency).
- TestCase("55.00",
- "USD",
- "en_CA",
- "55.00",
- "USD",
- "http://currsystem.com"),
- TestCase("55.00",
- "USD",
- "fr_CA",
- "55,00",
- "USD",
- "http://currsystem.com"),
- TestCase("55.00",
- "USD",
- "fr_FR",
- "55,00",
- "USD",
- "http://currsystem.com"),
- TestCase("1234",
- "USD",
- "fr_FR",
- "1 234,00",
- "USD",
- "http://currsystem.com"),
- TestCase("55.5",
- "USD",
- "en_US",
- "55.50",
- "USD",
- "http://currsystem.com"),
- TestCase("55", "CAD", "en_US", "55.00", "CAD", "http://currsystem.com"),
- TestCase("123",
- "BTC",
- "en_US",
- "123.00",
- "BTC",
- "http://currsystem.com"),
- TestCase("1234",
- "JPY",
- "en_US",
- "1,234.00",
- "JPY",
- "http://currsystem.com"),
- TestCase("0.1234",
- "USD",
- "en_US",
- "0.1234",
- "USD",
- "http://currsystem.com")));
-
} // namespace
} // namespace payments
diff --git a/chromium/components/payments/core/features.cc b/chromium/components/payments/core/features.cc
index 73e143ec9b8..bda32a2f0d6 100644
--- a/chromium/components/payments/core/features.cc
+++ b/chromium/components/payments/core/features.cc
@@ -29,5 +29,7 @@ const base::Feature kWebPaymentsSingleAppUiSkip{
"WebPaymentsSingleAppUiSkip", base::FEATURE_DISABLED_BY_DEFAULT};
#endif
+const base::Feature kWebPaymentsJustInTimePaymentApp{
+ "WebPaymentsJustInTimePaymentApp", base::FEATURE_DISABLED_BY_DEFAULT};
} // namespace features
} // namespace payments
diff --git a/chromium/components/payments/core/features.h b/chromium/components/payments/core/features.h
index fe66a9f7f87..279475cfd9d 100644
--- a/chromium/components/payments/core/features.h
+++ b/chromium/components/payments/core/features.h
@@ -31,6 +31,9 @@ extern const base::Feature kWebPaymentsModifiers;
// with a single URL based payment app and no other info requested.
extern const base::Feature kWebPaymentsSingleAppUiSkip;
+// Used to control whether allow crawling just-in-time installable payment app.
+extern const base::Feature kWebPaymentsJustInTimePaymentApp;
+
} // namespace features
} // namespace payments
diff --git a/chromium/components/payments/core/journey_logger.cc b/chromium/components/payments/core/journey_logger.cc
index b14cb2c8521..b306f492381 100644
--- a/chromium/components/payments/core/journey_logger.cc
+++ b/chromium/components/payments/core/journey_logger.cc
@@ -19,7 +19,7 @@ namespace {
std::string GetHistogramNameSuffix(
int section,
JourneyLogger::CompletionStatus completion_status) {
- std::string name_suffix = "";
+ std::string name_suffix;
switch (section) {
case JourneyLogger::SECTION_SHIPPING_ADDRESS:
diff --git a/chromium/components/payments/core/payment_currency_amount.cc b/chromium/components/payments/core/payment_currency_amount.cc
index 213b34681d4..39443eccb03 100644
--- a/chromium/components/payments/core/payment_currency_amount.cc
+++ b/chromium/components/payments/core/payment_currency_amount.cc
@@ -12,7 +12,6 @@ namespace {
// These are defined as part of the spec at:
// https://w3c.github.io/browser-payment-api/#dom-paymentcurrencyamount
-static const char kPaymentCurrencyAmountCurrencySystem[] = "currencySystem";
static const char kPaymentCurrencyAmountCurrency[] = "currency";
static const char kPaymentCurrencyAmountValue[] = "value";
@@ -31,10 +30,6 @@ bool PaymentCurrencyAmountFromDictionaryValue(
return false;
}
- // Currency_system is optional
- dictionary_value.GetString(kPaymentCurrencyAmountCurrencySystem,
- &amount->currency_system);
-
return true;
}
@@ -43,10 +38,6 @@ std::unique_ptr<base::DictionaryValue> PaymentCurrencyAmountToDictionaryValue(
auto result = std::make_unique<base::DictionaryValue>();
result->SetString(kPaymentCurrencyAmountCurrency, amount.currency);
result->SetString(kPaymentCurrencyAmountValue, amount.value);
- if (!amount.currency_system.empty()) {
- result->SetString(kPaymentCurrencyAmountCurrencySystem,
- amount.currency_system);
- }
return result;
}
diff --git a/chromium/components/payments/core/payment_currency_amount_unittest.cc b/chromium/components/payments/core/payment_currency_amount_unittest.cc
index af9a4ff1e8a..ec9b5f9c365 100644
--- a/chromium/components/payments/core/payment_currency_amount_unittest.cc
+++ b/chromium/components/payments/core/payment_currency_amount_unittest.cc
@@ -25,8 +25,6 @@ TEST(PaymentRequestTest, PaymentCurrencyAmountFromDictionaryValueSuccess) {
EXPECT_TRUE(expected.Equals(actual));
- expected.currency_system = "urn:iso:std:iso:123456789";
- amount_dict.SetString("currencySystem", "urn:iso:std:iso:123456789");
EXPECT_TRUE(PaymentCurrencyAmountFromDictionaryValue(amount_dict, &actual));
EXPECT_TRUE(expected.Equals(actual));
}
@@ -78,7 +76,6 @@ TEST(PaymentRequestTest, EmptyPaymentCurrencyAmountDictionary) {
expected_value.SetString("currency", "");
expected_value.SetString("value", "");
- expected_value.SetString("currencySystem", "urn:iso:std:iso:4217");
mojom::PaymentCurrencyAmount payment_currency_amount;
EXPECT_TRUE(expected_value.Equals(
@@ -92,12 +89,10 @@ TEST(PaymentRequestTest, PopulatedCurrencyAmountDictionary) {
expected_value.SetString("currency", "AUD");
expected_value.SetString("value", "-438.23");
- expected_value.SetString("currencySystem", "urn:iso:std:iso:123456789");
mojom::PaymentCurrencyAmount payment_currency_amount;
payment_currency_amount.currency = "AUD";
payment_currency_amount.value = "-438.23";
- payment_currency_amount.currency_system = "urn:iso:std:iso:123456789";
EXPECT_TRUE(expected_value.Equals(
PaymentCurrencyAmountToDictionaryValue(payment_currency_amount).get()));
diff --git a/chromium/components/payments/core/payment_details_modifier_unittest.cc b/chromium/components/payments/core/payment_details_modifier_unittest.cc
index 46e52ebb3ae..fd9679c7da0 100644
--- a/chromium/components/payments/core/payment_details_modifier_unittest.cc
+++ b/chromium/components/payments/core/payment_details_modifier_unittest.cc
@@ -44,7 +44,6 @@ TEST(PaymentRequestTest, PopulatedDetailsModifierDictionary) {
std::make_unique<base::DictionaryValue>();
amount_dict->SetString("currency", "USD");
amount_dict->SetString("value", "139.99");
- amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
item_dict->SetDictionary("amount", std::move(amount_dict));
item_dict->SetBoolean("pending", false);
expected_value.SetDictionary("total", std::move(item_dict));
diff --git a/chromium/components/payments/core/payment_details_validation.cc b/chromium/components/payments/core/payment_details_validation.cc
index 7227ecc4972..1d9085da32f 100644
--- a/chromium/components/payments/core/payment_details_validation.cc
+++ b/chromium/components/payments/core/payment_details_validation.cc
@@ -34,13 +34,8 @@ bool ValidateShippingOptionOrPaymentItem(const T& item,
return false;
}
- if (item.amount->currency_system.empty()) {
- *error_message = "Currency system can't be empty";
- return false;
- }
-
if (!payments::PaymentsValidators::IsValidCurrencyCodeFormat(
- item.amount->currency, item.amount->currency_system, error_message)) {
+ item.amount->currency, error_message)) {
return false;
}
diff --git a/chromium/components/payments/core/payment_item_unittest.cc b/chromium/components/payments/core/payment_item_unittest.cc
index a1fa1ca8830..c5b68b5c2ca 100644
--- a/chromium/components/payments/core/payment_item_unittest.cc
+++ b/chromium/components/payments/core/payment_item_unittest.cc
@@ -87,7 +87,6 @@ TEST(PaymentRequestTest, EmptyPaymentItemDictionary) {
std::make_unique<base::DictionaryValue>();
amount_dict->SetString("currency", "");
amount_dict->SetString("value", "");
- amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
expected_value.SetDictionary("amount", std::move(amount_dict));
expected_value.SetBoolean("pending", false);
@@ -104,7 +103,6 @@ TEST(PaymentRequestTest, PopulatedPaymentItemDictionary) {
std::make_unique<base::DictionaryValue>();
amount_dict->SetString("currency", "NZD");
amount_dict->SetString("value", "2,242,093.00");
- amount_dict->SetString("currencySystem", "urn:iso:std:iso:4217");
expected_value.SetDictionary("amount", std::move(amount_dict));
expected_value.SetBoolean("pending", true);
diff --git a/chromium/components/payments/core/payment_manifest_downloader.cc b/chromium/components/payments/core/payment_manifest_downloader.cc
index 6795f5c0e81..6a19aee7d19 100644
--- a/chromium/components/payments/core/payment_manifest_downloader.cc
+++ b/chromium/components/payments/core/payment_manifest_downloader.cc
@@ -73,6 +73,29 @@ GURL ParseResponseHeader(const net::URLFetcher* source) {
return GURL();
}
+bool IsValidManifestUrl(const GURL& url) {
+ return url.is_valid() &&
+ (url.SchemeIs(url::kHttpsScheme) ||
+ (url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url)));
+}
+
+GURL ParseRedirectUrlFromResponseHeader(const net::URLFetcher* source) {
+ // Do not follow net::HTTP_MULTIPLE_CHOICES, net::HTTP_NOT_MODIFIED and
+ // net::HTTP_USE_PROXY redirects.
+ if (source->GetResponseCode() != net::HTTP_MOVED_PERMANENTLY &&
+ source->GetResponseCode() != net::HTTP_FOUND &&
+ source->GetResponseCode() != net::HTTP_SEE_OTHER &&
+ source->GetResponseCode() != net::HTTP_TEMPORARY_REDIRECT &&
+ source->GetResponseCode() != net::HTTP_PERMANENT_REDIRECT) {
+ return GURL();
+ }
+
+ if (!IsValidManifestUrl(source->GetURL()))
+ return GURL();
+
+ return source->GetURL();
+}
+
std::string ParseResponseContent(const net::URLFetcher* source) {
std::string content;
if (source->GetResponseCode() != net::HTTP_OK) {
@@ -99,14 +122,17 @@ void PaymentManifestDownloader::DownloadPaymentMethodManifest(
const GURL& url,
PaymentManifestDownloadCallback callback) {
DCHECK(IsValidManifestUrl(url));
- InitiateDownload(url, net::URLFetcher::HEAD, std::move(callback));
+ // Restrict number of redirects for efficiency and breaking circle.
+ InitiateDownload(url, net::URLFetcher::HEAD,
+ /*allowed_number_of_redirects=*/3, std::move(callback));
}
void PaymentManifestDownloader::DownloadWebAppManifest(
const GURL& url,
PaymentManifestDownloadCallback callback) {
DCHECK(IsValidManifestUrl(url));
- InitiateDownload(url, net::URLFetcher::GET, std::move(callback));
+ InitiateDownload(url, net::URLFetcher::GET, /*allowed_number_of_redirects=*/0,
+ std::move(callback));
}
PaymentManifestDownloader::Download::Download() {}
@@ -122,13 +148,25 @@ void PaymentManifestDownloader::OnURLFetchComplete(
downloads_.erase(download_it);
if (download->request_type == net::URLFetcher::HEAD) {
+ // Manually follow some type of redirects.
+ if (download->allowed_number_of_redirects > 0) {
+ GURL redirect_url = ParseRedirectUrlFromResponseHeader(source);
+ if (!redirect_url.is_empty()) {
+ InitiateDownload(redirect_url, net::URLFetcher::HEAD,
+ --download->allowed_number_of_redirects,
+ std::move(download->callback));
+ return;
+ }
+ }
+
GURL url = ParseResponseHeader(source);
if (IsValidManifestUrl(url)) {
InitiateDownload(url, net::URLFetcher::GET,
+ /*allowed_number_of_redirects=*/0,
std::move(download->callback));
} else {
- // If the URL is empty, then ParseResponseHeader() has already printed an
- // explanation.
+ // If the URL is empty, then ParseResponseHeader() has already printed
+ // an explanation.
if (!url.is_empty())
LOG(ERROR) << url << " is not a valid payment method manifest URL.";
std::move(download->callback).Run(std::string());
@@ -141,6 +179,7 @@ void PaymentManifestDownloader::OnURLFetchComplete(
void PaymentManifestDownloader::InitiateDownload(
const GURL& url,
net::URLFetcher::RequestType request_type,
+ int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback) {
DCHECK(IsValidManifestUrl(url));
@@ -178,6 +217,7 @@ void PaymentManifestDownloader::InitiateDownload(
download->request_type = request_type;
download->fetcher = std::move(fetcher);
download->callback = std::move(callback);
+ download->allowed_number_of_redirects = allowed_number_of_redirects;
const net::URLFetcher* identifier = download->fetcher.get();
auto insert_result =
@@ -185,10 +225,4 @@ void PaymentManifestDownloader::InitiateDownload(
DCHECK(insert_result.second); // Whether the insert has succeeded.
}
-bool PaymentManifestDownloader::IsValidManifestUrl(const GURL& url) {
- return url.is_valid() &&
- (url.SchemeIs(url::kHttpsScheme) ||
- (url.SchemeIs(url::kHttpScheme) && net::IsLocalhost(url)));
-}
-
} // namespace payments
diff --git a/chromium/components/payments/core/payment_manifest_downloader.h b/chromium/components/payments/core/payment_manifest_downloader.h
index 0e2f38d5b8d..ef41decc9a4 100644
--- a/chromium/components/payments/core/payment_manifest_downloader.h
+++ b/chromium/components/payments/core/payment_manifest_downloader.h
@@ -88,6 +88,7 @@ class PaymentManifestDownloader : public net::URLFetcherDelegate {
Download();
~Download();
+ int allowed_number_of_redirects = 0;
net::URLFetcher::RequestType request_type;
std::unique_ptr<net::URLFetcher> fetcher;
PaymentManifestDownloadCallback callback;
@@ -98,8 +99,8 @@ class PaymentManifestDownloader : public net::URLFetcherDelegate {
void InitiateDownload(const GURL& url,
net::URLFetcher::RequestType request_type,
+ int allowed_number_of_redirects,
PaymentManifestDownloadCallback callback);
- bool IsValidManifestUrl(const GURL& url);
scoped_refptr<net::URLRequestContextGetter> context_;
diff --git a/chromium/components/payments/core/payment_manifest_downloader_unittest.cc b/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
index b84cfc4f592..99c3d6bccc4 100644
--- a/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
+++ b/chromium/components/payments/core/payment_manifest_downloader_unittest.cc
@@ -218,6 +218,145 @@ TEST_F(PaymentMethodManifestDownloaderTest, AbsoluteHttpHeaderLinkUrl) {
fetcher()->delegate()->OnURLFetchComplete(fetcher());
}
+TEST_F(PaymentMethodManifestDownloaderTest, 300IsUnsupportedRedirect) {
+ fetcher()->set_response_code(300);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+
+ EXPECT_CALL(*this, OnManifestDownload(std::string()));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, 301And302AreSupportedRedirects) {
+ fetcher()->set_response_code(301);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));
+
+ fetcher()->set_response_code(302);
+ fetcher()->set_url(GURL("https://charliepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));
+
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+ fetcher()->SetResponseString("manifest content");
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownload("manifest content"));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, 302And303AreSupportedRedirects) {
+ fetcher()->set_response_code(302);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));
+
+ fetcher()->set_response_code(303);
+ fetcher()->set_url(GURL("https://charliepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));
+
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+ fetcher()->SetResponseString("manifest content");
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownload("manifest content"));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, 304IsUnsupportedRedirect) {
+ fetcher()->set_response_code(304);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+
+ EXPECT_CALL(*this, OnManifestDownload(std::string()));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, 305IsUnsupportedRedirect) {
+ fetcher()->set_response_code(305);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+
+ EXPECT_CALL(*this, OnManifestDownload(std::string()));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, 307And308AreSupportedRedirects) {
+ fetcher()->set_response_code(307);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));
+
+ fetcher()->set_response_code(308);
+ fetcher()->set_url(GURL("https://charliepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));
+
+ scoped_refptr<net::HttpResponseHeaders> headers(
+ new net::HttpResponseHeaders(std::string()));
+ headers->AddHeader("Link: <manifest.json>; rel=payment-method-manifest");
+ fetcher()->set_response_headers(headers);
+ fetcher()->set_response_code(200);
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+ fetcher()->SetResponseString("manifest content");
+ fetcher()->set_response_code(200);
+
+ EXPECT_CALL(*this, OnManifestDownload("manifest content"));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, NoMoreThanThreeRediects) {
+ fetcher()->set_response_code(301);
+ fetcher()->set_url(GURL("https://alicepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://alicepay.com"));
+
+ fetcher()->set_response_code(302);
+ fetcher()->set_url(GURL("https://charliepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_EQ(fetcher()->GetOriginalURL(), GURL("https://charliepay.com"));
+
+ fetcher()->set_response_code(308);
+ fetcher()->set_url(GURL("https://davepay.com"));
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+
+ EXPECT_CALL(*this, OnManifestDownload(std::string()));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
+TEST_F(PaymentMethodManifestDownloaderTest, InvalidRedirectUrlIsFailure) {
+ fetcher()->set_response_code(308);
+ fetcher()->set_url(GURL("alicepay.com"));
+
+ EXPECT_CALL(*this, OnManifestDownload(std::string()));
+
+ fetcher()->delegate()->OnURLFetchComplete(fetcher());
+}
+
class WebAppManifestDownloaderTest : public testing::Test {
public:
WebAppManifestDownloaderTest()
diff --git a/chromium/components/payments/core/payment_prefs.cc b/chromium/components/payments/core/payment_prefs.cc
index 854769dad25..9590d9494ed 100644
--- a/chromium/components/payments/core/payment_prefs.cc
+++ b/chromium/components/payments/core/payment_prefs.cc
@@ -11,8 +11,13 @@ namespace payments {
const char kPaymentsFirstTransactionCompleted[] =
"payments.first_transaction_completed";
+const char kCanMakePaymentEnabled[] = "payments.can_make_payment_enabled";
+
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterBooleanPref(kPaymentsFirstTransactionCompleted, false);
+ registry->RegisterBooleanPref(
+ kCanMakePaymentEnabled, true,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
}
} // namespace payments
diff --git a/chromium/components/payments/core/payment_prefs.h b/chromium/components/payments/core/payment_prefs.h
index 1d5917ff2ac..65f6b9a7999 100644
--- a/chromium/components/payments/core/payment_prefs.h
+++ b/chromium/components/payments/core/payment_prefs.h
@@ -15,6 +15,10 @@ namespace payments {
// request transaction.
extern const char kPaymentsFirstTransactionCompleted[];
+// True if the user has allowed canMakePayment to return a truthful value, false
+// if canMakePayment should always return false regardless.
+extern const char kCanMakePaymentEnabled[];
+
void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
} // namespace payments
diff --git a/chromium/components/payments/core/payments_validators.cc b/chromium/components/payments/core/payments_validators.cc
index e4c21724f50..590f21c11eb 100644
--- a/chromium/components/payments/core/payments_validators.cc
+++ b/chromium/components/payments/core/payments_validators.cc
@@ -18,33 +18,16 @@ static const size_t maximumStringLength = 2048;
// static
bool PaymentsValidators::IsValidCurrencyCodeFormat(
const std::string& code,
- const std::string& system,
std::string* optional_error_message) {
- if (system == "urn:iso:std:iso:4217") {
- if (RE2::FullMatch(code, "[A-Z]{3}"))
- return true;
-
- if (optional_error_message)
- *optional_error_message =
- "'" + code +
- "' is not a valid ISO 4217 currency code, should "
- "be well-formed 3-letter alphabetic code.";
-
- return false;
- }
-
- if (code.size() > maximumStringLength) {
- if (optional_error_message)
- *optional_error_message =
- "The currency code should be at most 2048 characters long";
- return false;
- }
- if (!GURL(system).is_valid()) {
- if (optional_error_message)
- *optional_error_message = "The system should be a valid URL";
- return false;
- }
- return true;
+ if (RE2::FullMatch(code, "[A-Z]{3}"))
+ return true;
+
+ if (optional_error_message)
+ *optional_error_message = "'" + code +
+ "' is not a valid ISO 4217 currency code, should "
+ "be well-formed 3-letter alphabetic code.";
+
+ return false;
}
// static
diff --git a/chromium/components/payments/core/payments_validators.h b/chromium/components/payments/core/payments_validators.h
index 4fed720d4e5..72553b90deb 100644
--- a/chromium/components/payments/core/payments_validators.h
+++ b/chromium/components/payments/core/payments_validators.h
@@ -14,14 +14,8 @@ namespace payments {
class PaymentsValidators {
public:
// The most common identifiers are three-letter alphabetic codes as
- // defined by [ISO4217] (for example, "USD" for US Dollars). |system| is
- // a URL that indicates the currency system that the currency identifier
- // belongs to. By default, the value is urn:iso:std:iso:4217 indicating
- // that currency is defined by [[ISO4217]], however any string of at most
- // 2048 characters is considered valid in other currencySystem. Returns
- // false if currency |code| is too long (greater than 2048).
+ // defined by [ISO4217] (for example, "USD" for US Dollars).
static bool IsValidCurrencyCodeFormat(const std::string& code,
- const std::string& system,
std::string* optional_error_message);
// Returns true if |amount| is a valid currency code as defined in ISO 20022
diff --git a/chromium/components/payments/core/payments_validators_unittest.cc b/chromium/components/payments/core/payments_validators_unittest.cc
index 4e459b92878..c10085b6564 100644
--- a/chromium/components/payments/core/payments_validators_unittest.cc
+++ b/chromium/components/payments/core/payments_validators_unittest.cc
@@ -11,14 +11,11 @@ namespace payments {
namespace {
struct CurrencyCodeTestCase {
- CurrencyCodeTestCase(const char* code,
- const char* system,
- bool expected_valid)
- : code(code), system(system), expected_valid(expected_valid) {}
+ CurrencyCodeTestCase(const char* code, bool expected_valid)
+ : code(code), expected_valid(expected_valid) {}
~CurrencyCodeTestCase() {}
const char* code;
- const char* system;
bool expected_valid;
};
@@ -33,25 +30,17 @@ const char* longString2048() {
return long_string;
}
-const char* longString2049() {
- static char long_string[2050];
- for (int i = 0; i < 2049; i++)
- long_string[i] = 'a';
- long_string[2049] = '\0';
- return long_string;
-}
-
TEST_P(PaymentsCurrencyValidatorTest, IsValidCurrencyCodeFormat) {
std::string error_message;
EXPECT_EQ(GetParam().expected_valid,
payments::PaymentsValidators::IsValidCurrencyCodeFormat(
- GetParam().code, GetParam().system, &error_message))
+ GetParam().code, &error_message))
<< error_message;
EXPECT_EQ(GetParam().expected_valid, error_message.empty()) << error_message;
EXPECT_EQ(GetParam().expected_valid,
payments::PaymentsValidators::IsValidCurrencyCodeFormat(
- GetParam().code, GetParam().system, nullptr));
+ GetParam().code, nullptr));
}
INSTANTIATE_TEST_CASE_P(
@@ -66,24 +55,14 @@ INSTANTIATE_TEST_CASE_P(
// by [[ISO4217]], however any string of at most 2048
// characters is considered valid in other currencySystem. Returns false
// if currency |code| is too long (greater than 2048).
- CurrencyCodeTestCase("USD", "urn:iso:std:iso:4217", true),
- CurrencyCodeTestCase("US1", "http://www.example.com", true),
- CurrencyCodeTestCase("US1", "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase("US", "http://www.example.com", true),
- CurrencyCodeTestCase("US", "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase("USDO", "http://www.example.com", true),
- CurrencyCodeTestCase("USDO", "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase("usd", "http://www.example.com", true),
- CurrencyCodeTestCase("usd", "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase("ANYSTRING", "http://www.example.com", true),
- CurrencyCodeTestCase("ANYSTRING", "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase("", "http://www.example.com", true),
- CurrencyCodeTestCase("", "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase(longString2048(), "http://www.example.com", true),
- CurrencyCodeTestCase(longString2048(), "urn:iso:std:iso:4217", false),
- CurrencyCodeTestCase(longString2049(),
- "http://www.example.com",
- false)));
+ CurrencyCodeTestCase("USD", true),
+ CurrencyCodeTestCase("US1", false),
+ CurrencyCodeTestCase("US", false),
+ CurrencyCodeTestCase("USDO", false),
+ CurrencyCodeTestCase("usd", false),
+ CurrencyCodeTestCase("ANYSTRING", false),
+ CurrencyCodeTestCase("", false),
+ CurrencyCodeTestCase(longString2048(), false)));
struct TestCase {
TestCase(const char* input, bool expected_valid)
diff --git a/chromium/components/payments/core/test_payment_request_delegate.h b/chromium/components/payments/core/test_payment_request_delegate.h
index 382fad4646c..e7bb00217e8 100644
--- a/chromium/components/payments/core/test_payment_request_delegate.h
+++ b/chromium/components/payments/core/test_payment_request_delegate.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/message_loop/message_loop.h"
+#include "base/single_thread_task_runner.h"
#include "components/autofill/core/browser/payments/full_card_request.h"
#include "components/autofill/core/browser/payments/payments_client.h"
#include "components/autofill/core/browser/test_address_normalizer.h"
diff --git a/chromium/components/payments/mojom/payment_request_data.mojom b/chromium/components/payments/mojom/payment_request_data.mojom
index 6b9f2ffa5c2..a9cdb281de7 100644
--- a/chromium/components/payments/mojom/payment_request_data.mojom
+++ b/chromium/components/payments/mojom/payment_request_data.mojom
@@ -43,10 +43,4 @@ struct PaymentCurrencyAmount {
// ISO 20022 CurrencyAnd30Amount. Up to 30 total digits. Up to 10 fraction
// digits. Separated by a dot.
string value;
-
- // currency_system is a URL that indicates the currency system that the
- // currency identifier belongs to. By default, the value is
- // urn:iso:std:iso:4217 indicating that currency is defined by [ISO4217]
- // (for example, USD for US Dollars).
- string currency_system = "urn:iso:std:iso:4217";
-}; \ No newline at end of file
+};
diff --git a/chromium/components/payments_strings.grdp b/chromium/components/payments_strings.grdp
index f730cfaa2b6..0af9b3b4579 100644
--- a/chromium/components/payments_strings.grdp
+++ b/chromium/components/payments_strings.grdp
@@ -384,6 +384,9 @@
<message name="IDS_PAYMENTS_CARD_AND_ADDRESS_SETTINGS_SIGNED_OUT" desc="Label of the section containing the origin description and the link to go to the settings page for card and address options. This label is used when the user is not signed in." formatter_data="android_java">
Cards and addresses are from Chrome. You can manage them in <ph name="BEGIN_LINK">BEGIN_LINK</ph>Settings<ph name="END_LINK">END_LINK</ph>.
</message>
+ <message name="IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL" desc="Label of the toggle which disables canMakePayment" formatter_data="android_java">
+ Allow sites to check if you have payment methods saved
+ </message>
<!-- iOS Credit Card form -->
<if expr="is_ios">
diff --git a/chromium/components/payments_strings_grdp/IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL.png.sha1 b/chromium/components/payments_strings_grdp/IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL.png.sha1
new file mode 100644
index 00000000000..2253092ed26
--- /dev/null
+++ b/chromium/components/payments_strings_grdp/IDS_SETTINGS_CAN_MAKE_PAYMENT_TOGGLE_LABEL.png.sha1
@@ -0,0 +1 @@
+8cffb2c454760d101b26ff199ca21cf0032b4c16 \ No newline at end of file
diff --git a/chromium/components/payments_strings_grdp/OWNERS b/chromium/components/payments_strings_grdp/OWNERS
new file mode 100644
index 00000000000..616d55333e6
--- /dev/null
+++ b/chromium/components/payments_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/payments/OWNERS
diff --git a/chromium/components/payments_strings_grdp/README.md b/chromium/components/payments_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/payments_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/pdf/renderer/OWNERS b/chromium/components/pdf/renderer/OWNERS
index 70fce223441..f4a68b99265 100644
--- a/chromium/components/pdf/renderer/OWNERS
+++ b/chromium/components/pdf/renderer/OWNERS
@@ -1,4 +1,4 @@
-per-file pdf_accessibility_tree.*=dmazzoni@chromium.org
+per-file pdf_accessibility_tree*=dmazzoni@chromium.org
per-file pepper_pdf_host.*=bbudge@chromium.org
per-file pepper_pdf_host.*=raymes@chromium.org
diff --git a/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc b/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
index 742815d76a0..a727b4cf793 100644
--- a/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
+++ b/chromium/components/pdf/renderer/pdf_accessibility_tree_browsertest.cc
@@ -83,7 +83,7 @@ class PdfAccessibilityTreeTest : public content::RenderViewTest {
content::RenderViewTest::SetUp();
base::FilePath pak_dir;
- PathService::Get(base::DIR_MODULE, &pak_dir);
+ base::PathService::Get(base::DIR_MODULE, &pak_dir);
base::FilePath pak_file =
pak_dir.Append(FILE_PATH_LITERAL("components_tests_resources.pak"));
ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
@@ -92,6 +92,10 @@ class PdfAccessibilityTreeTest : public content::RenderViewTest {
viewport_info_.zoom = 1.0;
viewport_info_.scroll = {0, 0};
viewport_info_.offset = {0, 0};
+ viewport_info_.selection_start_page_index = 0;
+ viewport_info_.selection_start_char_index = 0;
+ viewport_info_.selection_end_page_index = 0;
+ viewport_info_.selection_end_char_index = 0;
doc_info_.page_count = 1;
page_info_.page_index = 0;
page_info_.text_run_count = 0;
diff --git a/chromium/components/pdf_strings_grdp/OWNERS b/chromium/components/pdf_strings_grdp/OWNERS
new file mode 100644
index 00000000000..db781ac5adc
--- /dev/null
+++ b/chromium/components/pdf_strings_grdp/OWNERS
@@ -0,0 +1 @@
+raymes@chromium.org
diff --git a/chromium/components/pdf_strings_grdp/README.md b/chromium/components/pdf_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/pdf_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/physical_web/OWNERS b/chromium/components/physical_web/OWNERS
deleted file mode 100644
index 2f1afa43365..00000000000
--- a/chromium/components/physical_web/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-mattreynolds@chromium.org
-olivierrobin@chromium.org
diff --git a/chromium/components/physical_web/data_source/BUILD.gn b/chromium/components/physical_web/data_source/BUILD.gn
deleted file mode 100644
index 5e1c9620310..00000000000
--- a/chromium/components/physical_web/data_source/BUILD.gn
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("data_source") {
- sources = [
- "physical_web_data_source.cc",
- "physical_web_data_source.h",
- "physical_web_data_source_impl.cc",
- "physical_web_data_source_impl.h",
- "physical_web_listener.h",
- ]
-
- public_deps = [
- "//base",
- "//url",
- ]
-}
-
-source_set("test_support") {
- testonly = true
- sources = [
- "fake_physical_web_data_source.cc",
- "fake_physical_web_data_source.h",
- ]
- deps = [
- ":data_source",
- "//base",
- "//url",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "physical_web_data_source_impl_unittest.cc",
- ]
-
- deps = [
- ":data_source",
- "//base",
- "//testing/gtest",
- "//url",
- ]
-}
diff --git a/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc b/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc
deleted file mode 100644
index 2447a4bcadf..00000000000
--- a/chromium/components/physical_web/data_source/fake_physical_web_data_source.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/physical_web/data_source/fake_physical_web_data_source.h"
-
-#include <memory>
-
-#include "base/strings/string_number_conversions.h"
-#include "components/physical_web/data_source/physical_web_listener.h"
-#include "url/gurl.h"
-
-namespace physical_web {
-
-std::unique_ptr<Metadata> CreatePhysicalWebPage(
- const std::string& resolved_url,
- double distance_estimate,
- const std::string& group_id,
- int scan_timestamp,
- const std::string& title,
- const std::string& description,
- const std::string& scanned_url) {
- auto page = std::make_unique<Metadata>();
- page->resolved_url = GURL(resolved_url);
- page->distance_estimate = distance_estimate;
- page->group_id = group_id;
- page->scan_timestamp = base::Time::FromJavaTime(scan_timestamp);
- page->title = title;
- page->description = description;
- page->scanned_url = GURL(scanned_url);
- return page;
-}
-
-std::unique_ptr<Metadata> CreateDummyPhysicalWebPage(int id,
- double distance,
- int timestamp) {
- const std::string id_string = base::IntToString(id);
- return CreatePhysicalWebPage("https://resolved_url.com/" + id_string,
- distance, /*group_id=*/std::string(), timestamp,
- "title " + id_string, "description " + id_string,
- "https://scanned_url.com/" + id_string);
-}
-
-std::unique_ptr<MetadataList> CreateDummyPhysicalWebPages(
- const std::vector<int>& ids) {
- int distance = 1;
- int timestamp = static_cast<int>(ids.size());
- auto list = std::make_unique<MetadataList>();
- for (int id : ids) {
- std::unique_ptr<Metadata> page =
- CreateDummyPhysicalWebPage(id, distance, timestamp);
- list->push_back(*page);
- ++distance;
- --timestamp;
- }
- return list;
-}
-
-FakePhysicalWebDataSource::FakePhysicalWebDataSource() {}
-
-FakePhysicalWebDataSource::~FakePhysicalWebDataSource() = default;
-
-void FakePhysicalWebDataSource::StartDiscovery(bool network_request_enabled) {
- // Ignored.
-}
-
-void FakePhysicalWebDataSource::StopDiscovery() {
- // Ignored.
-}
-
-std::unique_ptr<MetadataList> FakePhysicalWebDataSource::GetMetadataList() {
- return std::make_unique<MetadataList>(*metadata_list_.get());
-}
-
-bool FakePhysicalWebDataSource::HasUnresolvedDiscoveries() {
- return false;
-}
-
-void FakePhysicalWebDataSource::RegisterListener(
- PhysicalWebListener* physical_web_listener, ScanMode scan_mode) {
- observer_list_.AddObserver(physical_web_listener);
-}
-
-void FakePhysicalWebDataSource::UnregisterListener(
- PhysicalWebListener* physical_web_listener) {
- observer_list_.RemoveObserver(physical_web_listener);
-}
-
-void FakePhysicalWebDataSource::SetMetadataList(
- std::unique_ptr<MetadataList> metadata_list) {
- metadata_list_ = std::move(metadata_list);
-}
-
-void FakePhysicalWebDataSource::NotifyOnFound(const GURL& url) {
- for (PhysicalWebListener& observer : observer_list_)
- observer.OnFound(url);
-}
-
-void FakePhysicalWebDataSource::NotifyOnLost(const GURL& url) {
- for (PhysicalWebListener& observer : observer_list_)
- observer.OnLost(url);
-}
-
-void FakePhysicalWebDataSource::NotifyOnDistanceChanged(
- const GURL& url,
- double distance_estimate) {
- for (PhysicalWebListener& observer : observer_list_)
- observer.OnDistanceChanged(url, distance_estimate);
-}
-
-} // namespace physical_web
diff --git a/chromium/components/physical_web/data_source/fake_physical_web_data_source.h b/chromium/components/physical_web/data_source/fake_physical_web_data_source.h
deleted file mode 100644
index 52c152bcf2f..00000000000
--- a/chromium/components/physical_web/data_source/fake_physical_web_data_source.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_FAKE_PHYSICAL_WEB_DATA_SOURCE_H_
-#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_FAKE_PHYSICAL_WEB_DATA_SOURCE_H_
-
-#include <memory>
-
-#include "base/observer_list.h"
-#include "components/physical_web/data_source/physical_web_data_source.h"
-
-class GURL;
-
-namespace physical_web {
-
-std::unique_ptr<Metadata> CreatePhysicalWebPage(
- const std::string& resolved_url,
- double distance_estimate,
- const std::string& group_id,
- int scan_timestamp,
- const std::string& title,
- const std::string& description,
- const std::string& scanned_url);
-
-std::unique_ptr<Metadata>
-CreateDummyPhysicalWebPage(int id, double distance, int timestamp);
-
-std::unique_ptr<MetadataList> CreateDummyPhysicalWebPages(
- const std::vector<int>& ids);
-
-class FakePhysicalWebDataSource : public PhysicalWebDataSource {
- public:
- FakePhysicalWebDataSource();
- ~FakePhysicalWebDataSource() override;
-
- void StartDiscovery(bool network_request_enabled) override;
- void StopDiscovery() override;
-
- std::unique_ptr<MetadataList> GetMetadataList() override;
-
- bool HasUnresolvedDiscoveries() override;
-
- void RegisterListener(PhysicalWebListener* physical_web_listener,
- ScanMode scan_mode) override;
- void UnregisterListener(PhysicalWebListener* physical_web_listener) override;
-
- // for testing
- void SetMetadataList(std::unique_ptr<MetadataList> metadata_list);
- void NotifyOnFound(const GURL& url);
- void NotifyOnLost(const GURL& url);
- void NotifyOnDistanceChanged(const GURL& url, double distance_estimate);
-
- private:
- std::unique_ptr<MetadataList> metadata_list_;
- base::ObserverList<PhysicalWebListener> observer_list_;
-
- DISALLOW_COPY_AND_ASSIGN(FakePhysicalWebDataSource);
-};
-
-} // namespace physical_web
-
-#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_FAKE_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source.cc b/chromium/components/physical_web/data_source/physical_web_data_source.cc
deleted file mode 100644
index f3fea842ee3..00000000000
--- a/chromium/components/physical_web/data_source/physical_web_data_source.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/physical_web/data_source/physical_web_data_source.h"
-
-namespace physical_web {
-
-Metadata::Metadata() {}
-
-Metadata::Metadata(const Metadata& other) = default;
-
-Metadata::~Metadata() {}
-
-} // namespace physical_web
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source.h b/chromium/components/physical_web/data_source/physical_web_data_source.h
deleted file mode 100644
index 1fc8f333a3b..00000000000
--- a/chromium/components/physical_web/data_source/physical_web_data_source.h
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
-#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "base/time/time.h"
-#include "url/gurl.h"
-
-namespace physical_web {
-
-class PhysicalWebListener;
-
-// Enum describing scan policies.
-enum ScanMode {
- // Request no particular scan policy. Opportunistic listeners will receive
- // notifications when any other listener requests a scan.
- OPPORTUNISTIC = 0,
- // Request a scan that runs occassionally, even when Chrome is not in the
- // foreground. Android only.
- BACKGROUND_INTERMITTENT = 1 << 0,
-};
-
-// Metadata struct for associating data with Physical Web URLs.
-struct Metadata {
- Metadata();
- Metadata(const Metadata& other);
- ~Metadata();
- // The URL broadcasted by the beacon and scanned by the client device.
- // REQUIRED
- GURL scanned_url;
- // The URL that the scanned_url redirects to.
- // This is the URL that users should be directed to.
- // REQUIRED
- GURL resolved_url;
- // The favicon URL.
- // OPTIONAL
- GURL icon_url;
- // The title of the web page.
- // REQUIRED
- std::string title;
- // The description of the web page.
- // OPTIONAL: When the website has not specified a description, the PWS
- // generates one based on the initial text of the site, but this is not
- // guaranteed behavior.
- std::string description;
- // An identifier that associates multiple resolved URLs. These URLs will
- // most typically be associated because their metadata is near-identical
- // (same icon, title, description, URL minus the fragment). e.g.,
- // https://mymuseum/exhibits#e1
- // https://mymuseum/exhibits#e2
- // If two URLs have the same group id, only one should be shown (typically,
- // the one with the smallest distance estimate).
- // OPTIONAL: Treat the item as its own unique group if this is empty.
- std::string group_id;
- // The estimated distance between the user and the Physical Web device (e.g.,
- // beacon) in meters.
- // OPTIONAL: This will be a value <= 0 if no distance estimate has been
- // calculated. The distance may not be calculated if we aren't able to
- // receive an estimate from the underlying scanning service in time, or if
- // (in the future) we begin sourcing Physical Web URLs from a non-BLE
- // transport (e.g. mDNS).
- double distance_estimate;
- // The timestamp corresponding to when this URL was last scanned.
- // REQUIRED
- base::Time scan_timestamp;
-};
-
-using MetadataList = std::vector<Metadata>;
-
-// Helper class for accessing Physical Web metadata and controlling the scanner.
-class PhysicalWebDataSource {
- public:
- virtual ~PhysicalWebDataSource() {}
-
- // Starts scanning for Physical Web URLs. If |network_request_enabled| is
- // true, discovered URLs will be sent to a resolution service.
- virtual void StartDiscovery(bool network_request_enabled) = 0;
-
- // Stops scanning for Physical Web URLs and clears cached URL content.
- virtual void StopDiscovery() = 0;
-
- // Returns a list of resolved URLs and associated page metadata. If network
- // requests are disabled or if discovery is not active, the list will be
- // empty. The method can be called at any time to receive the current metadata
- // list.
- virtual std::unique_ptr<MetadataList> GetMetadataList() = 0;
-
- // Returns boolean |true| if network requests are disabled and there are one
- // or more discovered URLs that have not been sent to the resolution service.
- // The method can be called at any time to check for unresolved discoveries.
- // If discovery is inactive or network requests are enabled, it will always
- // return false.
- virtual bool HasUnresolvedDiscoveries() = 0;
-
- // Register for changes to Physical Web URLs and associated page metadata.
- // This may be called multiple times in order to change the associated scan
- // mode.
- virtual void RegisterListener(PhysicalWebListener* physical_web_listener,
- ScanMode scan_mode) = 0;
-
- // Unregister for changes to Physical Web URLs and associated page metadata.
- virtual void UnregisterListener(
- PhysicalWebListener* physical_web_listener) = 0;
-};
-
-} // namespace physical_web
-
-#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_H_
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc b/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
deleted file mode 100644
index 1f75d054793..00000000000
--- a/chromium/components/physical_web/data_source/physical_web_data_source_impl.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/observer_list.h"
-#include "components/physical_web/data_source/physical_web_data_source.h"
-#include "components/physical_web/data_source/physical_web_data_source_impl.h"
-#include "components/physical_web/data_source/physical_web_listener.h"
-
-namespace physical_web {
-
-PhysicalWebDataSourceImpl::PhysicalWebDataSourceImpl() {}
-
-PhysicalWebDataSourceImpl::~PhysicalWebDataSourceImpl() {}
-
-void PhysicalWebDataSourceImpl::RegisterListener(
- PhysicalWebListener* physical_web_listener, ScanMode scan_mode) {
- if (!observer_list_.HasObserver(physical_web_listener)) {
- observer_list_.AddObserver(physical_web_listener);
- }
- scan_modes_[physical_web_listener] = scan_mode;
-}
-
-void PhysicalWebDataSourceImpl::UnregisterListener(
- PhysicalWebListener* physical_web_listener) {
- if (!observer_list_.HasObserver(physical_web_listener)) return;
-
- observer_list_.RemoveObserver(physical_web_listener);
- scan_modes_.erase(physical_web_listener);
-}
-
-void PhysicalWebDataSourceImpl::NotifyOnFound(const GURL& url) {
- for (PhysicalWebListener& observer : observer_list_)
- observer.OnFound(url);
-}
-
-void PhysicalWebDataSourceImpl::NotifyOnLost(const GURL& url) {
- for (PhysicalWebListener& observer : observer_list_)
- observer.OnLost(url);
-}
-
-void PhysicalWebDataSourceImpl::NotifyOnDistanceChanged(
- const GURL& url,
- double distance_estimate) {
- for (PhysicalWebListener& observer : observer_list_)
- observer.OnDistanceChanged(url, distance_estimate);
-}
-
-} // namespace physical_web
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl.h b/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
deleted file mode 100644
index 0930d50a5b4..00000000000
--- a/chromium/components/physical_web/data_source/physical_web_data_source_impl.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#ifndef COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_IMPL_H_
-#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_IMPL_H_
-
-#include "base/observer_list.h"
-#include "components/physical_web/data_source/physical_web_data_source.h"
-
-class GURL;
-
-namespace physical_web {
-
-class PhysicalWebListener;
-
-class PhysicalWebDataSourceImpl : public PhysicalWebDataSource {
- public:
- PhysicalWebDataSourceImpl();
- ~PhysicalWebDataSourceImpl() override;
-
- // Register for changes to Physical Web URLs and associated page metadata.
- void RegisterListener(PhysicalWebListener* physical_web_listener,
- ScanMode scan_mode) override;
-
- // Unregister for changes to Physical Web URLs and associated page metadata.
- void UnregisterListener(PhysicalWebListener* physical_web_listener) override;
-
- // Notify all registered listeners that a URL has been found.
- void NotifyOnFound(const GURL& url);
-
- // Notify all registered listeners that a URL has been lost.
- void NotifyOnLost(const GURL& url);
-
- // Notify all registered listeners that a distance has changed for a URL.
- void NotifyOnDistanceChanged(const GURL& url, double distance_estimate);
-
- private:
- base::ObserverList<PhysicalWebListener> observer_list_;
- std::unordered_map<PhysicalWebListener*, ScanMode> scan_modes_;
-};
-
-} // namespace physical_web
-
-#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_DATA_SOURCE_IMPL_H_
diff --git a/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc b/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
deleted file mode 100644
index 566df3ae600..00000000000
--- a/chromium/components/physical_web/data_source/physical_web_data_source_impl_unittest.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/values.h"
-#include "components/physical_web/data_source/physical_web_data_source_impl.h"
-#include "components/physical_web/data_source/physical_web_listener.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace physical_web {
-
-// Test Values ----------------------------------------------------------------
-GURL kUrl = GURL("https://www.google.com");
-
-// TestPhysicalWebDataSource --------------------------------------------------
-
-class TestPhysicalWebDataSource : public PhysicalWebDataSourceImpl {
- public:
- TestPhysicalWebDataSource() {}
- ~TestPhysicalWebDataSource() override {}
-
- void StartDiscovery(bool network_request_enabled) override;
- void StopDiscovery() override;
- std::unique_ptr<MetadataList> GetMetadataList() override;
- bool HasUnresolvedDiscoveries() override;
-};
-void TestPhysicalWebDataSource::StartDiscovery(bool network_request_enabled) {}
-
-void TestPhysicalWebDataSource::StopDiscovery() {}
-
-std::unique_ptr<MetadataList> TestPhysicalWebDataSource::GetMetadataList() {
- return nullptr;
-}
-
-bool TestPhysicalWebDataSource::HasUnresolvedDiscoveries() {
- return false;
-}
-
-// TestPhysicalWebListener ----------------------------------------------------
-
-class TestPhysicalWebListener : public PhysicalWebListener {
- public:
- TestPhysicalWebListener()
- : on_found_notified_(false),
- on_lost_notified_(false),
- on_distance_changed_notified_(false) {}
-
- ~TestPhysicalWebListener() {}
-
- void OnFound(const GURL& url) override {
- on_found_notified_ = true;
- last_event_url_ = url;
- }
-
- void OnLost(const GURL& url) override {
- on_lost_notified_ = true;
- last_event_url_ = url;
- }
-
- void OnDistanceChanged(const GURL& url, double distance_estimate) override {
- on_distance_changed_notified_ = true;
- last_event_url_ = url;
- }
-
- bool OnFoundNotified() { return on_found_notified_; }
-
- bool OnLostNotified() { return on_lost_notified_; }
-
- bool OnDistanceChangedNotified() { return on_distance_changed_notified_; }
-
- GURL LastEventUrl() { return last_event_url_; }
-
- private:
- bool on_found_notified_;
- bool on_lost_notified_;
- bool on_distance_changed_notified_;
- GURL last_event_url_;
-};
-
-// PhysicalWebDataSourceImplTest ----------------------------------------------
-
-class PhysicalWebDataSourceImplTest : public ::testing::Test {
- public:
- PhysicalWebDataSourceImplTest() {}
- ~PhysicalWebDataSourceImplTest() override {}
-
- // testing::Test
- void SetUp() override;
- void TearDown() override;
-
- protected:
- TestPhysicalWebDataSource data_source_;
- TestPhysicalWebListener listener_;
-};
-
-void PhysicalWebDataSourceImplTest::SetUp() {
- data_source_.RegisterListener(&listener_, physical_web::OPPORTUNISTIC);
-}
-
-void PhysicalWebDataSourceImplTest::TearDown() {
- data_source_.UnregisterListener(&listener_);
-}
-
-// Tests ----------------------------------------------------------------------
-
-TEST_F(PhysicalWebDataSourceImplTest, OnFound) {
- data_source_.NotifyOnFound(kUrl);
- EXPECT_TRUE(listener_.OnFoundNotified());
- EXPECT_FALSE(listener_.OnLostNotified());
- EXPECT_FALSE(listener_.OnDistanceChangedNotified());
- EXPECT_EQ(kUrl, listener_.LastEventUrl());
-}
-
-TEST_F(PhysicalWebDataSourceImplTest, OnLost) {
- data_source_.NotifyOnLost(kUrl);
- EXPECT_FALSE(listener_.OnFoundNotified());
- EXPECT_TRUE(listener_.OnLostNotified());
- EXPECT_FALSE(listener_.OnDistanceChangedNotified());
- EXPECT_EQ(kUrl, listener_.LastEventUrl());
-}
-
-TEST_F(PhysicalWebDataSourceImplTest, OnDistanceChanged) {
- data_source_.NotifyOnDistanceChanged(kUrl, 0.0);
- EXPECT_FALSE(listener_.OnFoundNotified());
- EXPECT_FALSE(listener_.OnLostNotified());
- EXPECT_TRUE(listener_.OnDistanceChangedNotified());
- EXPECT_EQ(kUrl, listener_.LastEventUrl());
-}
-
-TEST_F(PhysicalWebDataSourceImplTest, OnFoundNotRegistered) {
- data_source_.UnregisterListener(&listener_);
- data_source_.NotifyOnFound(kUrl);
- EXPECT_FALSE(listener_.OnFoundNotified());
- EXPECT_FALSE(listener_.OnLostNotified());
- EXPECT_FALSE(listener_.OnDistanceChangedNotified());
- EXPECT_TRUE(listener_.LastEventUrl().is_empty());
-}
-
-TEST_F(PhysicalWebDataSourceImplTest, OnLostNotRegistered) {
- data_source_.UnregisterListener(&listener_);
- data_source_.NotifyOnLost(kUrl);
- EXPECT_FALSE(listener_.OnFoundNotified());
- EXPECT_FALSE(listener_.OnLostNotified());
- EXPECT_FALSE(listener_.OnDistanceChangedNotified());
- EXPECT_TRUE(listener_.LastEventUrl().is_empty());
-}
-
-TEST_F(PhysicalWebDataSourceImplTest, OnDistanceChangedNotRegistered) {
- data_source_.UnregisterListener(&listener_);
- data_source_.NotifyOnDistanceChanged(kUrl, 0.0);
- EXPECT_FALSE(listener_.OnFoundNotified());
- EXPECT_FALSE(listener_.OnLostNotified());
- EXPECT_FALSE(listener_.OnDistanceChangedNotified());
- EXPECT_TRUE(listener_.LastEventUrl().is_empty());
-}
-
-} // namespace physical_web
diff --git a/chromium/components/physical_web/data_source/physical_web_listener.h b/chromium/components/physical_web/data_source/physical_web_listener.h
deleted file mode 100644
index 3e74bc159e9..00000000000
--- a/chromium/components/physical_web/data_source/physical_web_listener.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_LISTENER_H_
-#define COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_LISTENER_H_
-
-class GURL;
-
-namespace physical_web {
-
-// Class for being notified when Physical Web data changes.
-class PhysicalWebListener {
- public:
-
- // OnFound(url) will be called when a new URL has been found.
- virtual void OnFound(const GURL& url) = 0;
-
- // OnLost(url) will be called when a URL can no longer be seen.
- virtual void OnLost(const GURL& url) = 0;
-
- // OnDistanceChagned(url, distance_estimate) will be called when the distance
- // estimate is changed for the URL.
- virtual void OnDistanceChanged(const GURL& url, double distance_estimate) = 0;
-};
-
-} // namespace physical_web
-
-#endif // COMPONENTS_PHYSICAL_WEB_DATA_SOURCE_PHYSICAL_WEB_LISTENER_H_
diff --git a/chromium/components/physical_web/resources/ic_link_grey600_36dp.png b/chromium/components/physical_web/resources/ic_link_grey600_36dp.png
deleted file mode 100644
index 6e39fc76fb1..00000000000
--- a/chromium/components/physical_web/resources/ic_link_grey600_36dp.png
+++ /dev/null
Binary files differ
diff --git a/chromium/components/physical_web/webui/BUILD.gn b/chromium/components/physical_web/webui/BUILD.gn
deleted file mode 100644
index a2fc20a4cae..00000000000
--- a/chromium/components/physical_web/webui/BUILD.gn
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-source_set("webui") {
- sources = [
- "physical_web_base_message_handler.cc",
- "physical_web_base_message_handler.h",
- "physical_web_ui_constants.cc",
- "physical_web_ui_constants.h",
- ]
-
- deps = [
- "//base",
- "//components/physical_web/data_source",
- ]
-}
diff --git a/chromium/components/physical_web/webui/physical_web_base_message_handler.cc b/chromium/components/physical_web/webui/physical_web_base_message_handler.cc
deleted file mode 100644
index 17b089b4ff2..00000000000
--- a/chromium/components/physical_web/webui/physical_web_base_message_handler.cc
+++ /dev/null
@@ -1,124 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/physical_web/webui/physical_web_base_message_handler.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/metrics/histogram_macros.h"
-#include "base/metrics/user_metrics.h"
-#include "components/physical_web/data_source/physical_web_data_source.h"
-#include "components/physical_web/webui/physical_web_ui_constants.h"
-
-namespace physical_web_ui {
-
-PhysicalWebBaseMessageHandler::PhysicalWebBaseMessageHandler()
- : data_source_(nullptr) {}
-
-PhysicalWebBaseMessageHandler::~PhysicalWebBaseMessageHandler() {
- if (data_source_)
- data_source_->UnregisterListener(this);
-}
-
-void PhysicalWebBaseMessageHandler::OnFound(const GURL& url) {
- PushNearbyURLs();
-}
-
-void PhysicalWebBaseMessageHandler::OnLost(const GURL& url) {
- // do nothing
-}
-
-void PhysicalWebBaseMessageHandler::OnDistanceChanged(
- const GURL& url,
- double distance_estimate) {
- // do nothing
-}
-
-void PhysicalWebBaseMessageHandler::RegisterMessages() {
- RegisterMessageCallback(
- kPhysicalWebPageLoaded,
- base::BindRepeating(
- &PhysicalWebBaseMessageHandler::HandlePhysicalWebPageLoaded,
- base::Unretained(this)));
-
- RegisterMessageCallback(
- kPhysicalWebItemClicked,
- base::BindRepeating(
- &PhysicalWebBaseMessageHandler::HandlePhysicalWebItemClicked,
- base::Unretained(this)));
-
- data_source_ = GetPhysicalWebDataSource();
- if (data_source_)
- data_source_->RegisterListener(this, physical_web::OPPORTUNISTIC);
-}
-
-void PhysicalWebBaseMessageHandler::PushNearbyURLs() {
- base::DictionaryValue results;
-
- std::unique_ptr<physical_web::MetadataList> metadata_list =
- GetPhysicalWebDataSource()->GetMetadataList();
-
- // Append new metadata at the end of the list.
- for (const auto& metadata_list_item : *metadata_list) {
- const std::string& group_id = metadata_list_item.group_id;
- if (metadata_map_.find(group_id) == metadata_map_.end()) {
- ordered_group_ids_.push_back(group_id);
- metadata_map_.insert(std::make_pair(group_id, metadata_list_item));
- }
- }
-
- auto metadata = std::make_unique<base::ListValue>();
- int index = 0;
- for (const auto& group_id : ordered_group_ids_) {
- auto metadata_list_item = metadata_map_[group_id];
- auto metadata_item = std::make_unique<base::DictionaryValue>();
- metadata_item->SetString(physical_web_ui::kResolvedUrl,
- metadata_list_item.resolved_url.spec());
- metadata_item->SetString(physical_web_ui::kPageInfoIcon,
- metadata_list_item.icon_url.spec());
- metadata_item->SetString(physical_web_ui::kPageInfoTitle,
- metadata_list_item.title);
- metadata_item->SetString(physical_web_ui::kPageInfoDescription,
- metadata_list_item.description);
- // Add the item index so when an item is selected, the index can be recorded
- // in a UMA histogram.
- metadata_item->SetInteger(physical_web_ui::kIndex, index);
- metadata->Append(std::move(metadata_item));
- ++index;
- }
-
- results.Set(physical_web_ui::kMetadata, std::move(metadata));
-
- // Pass the list of Physical Web URL metadata to the WebUI. A jstemplate will
- // create a list view with an item for each URL.
- CallJavaScriptFunction(physical_web_ui::kPushNearbyUrls, results);
-}
-
-void PhysicalWebBaseMessageHandler::HandlePhysicalWebPageLoaded(
- const base::ListValue* args) {
- PushNearbyURLs();
- UMA_HISTOGRAM_EXACT_LINEAR("PhysicalWeb.TotalUrls.OnInitialDisplay",
- (int)ordered_group_ids_.size(), 50);
-}
-
-void PhysicalWebBaseMessageHandler::HandlePhysicalWebItemClicked(
- const base::ListValue* args) {
- int index = 0;
- if (!args->GetInteger(0, &index)) {
- DLOG(ERROR) << "Invalid selection index";
- return;
- }
-
- // Record the index of the selected item.
- UMA_HISTOGRAM_EXACT_LINEAR("PhysicalWeb.WebUI.ListViewUrlPosition", index,
- 50);
-
- // Count the number of selections.
- base::RecordAction(
- base::UserMetricsAction("PhysicalWeb.WebUI.ListViewUrlSelected"));
-}
-
-} // namespace physical_web_ui
diff --git a/chromium/components/physical_web/webui/physical_web_base_message_handler.h b/chromium/components/physical_web/webui/physical_web_base_message_handler.h
deleted file mode 100644
index 0aa2d819e70..00000000000
--- a/chromium/components/physical_web/webui/physical_web_base_message_handler.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_BASE_MESSAGE_HANDLER_H_
-#define COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_BASE_MESSAGE_HANDLER_H_
-
-#include <map>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/values.h"
-#include "components/physical_web/data_source/physical_web_data_source.h"
-#include "components/physical_web/data_source/physical_web_listener.h"
-
-namespace physical_web {
-
-class PhysicalWebDataSource;
-
-} // namespace physical_web
-
-namespace physical_web_ui {
-
-// This is the equivalent of content::WebUI::MessageCallback.
-using MessageCallback = base::RepeatingCallback<void(const base::ListValue*)>;
-
-// The base handler for Javascript messages for the chrome://physical-web page.
-// This does not implement WebUIMessageHandler or register its methods.
-class PhysicalWebBaseMessageHandler : physical_web::PhysicalWebListener {
- public:
- PhysicalWebBaseMessageHandler();
- virtual ~PhysicalWebBaseMessageHandler();
-
- // PhysicalWebListener
- void OnFound(const GURL& url) override;
- void OnLost(const GURL& url) override;
- void OnDistanceChanged(const GURL& url, double distance_estimate) override;
-
- // Push URLs that are currently being broadcasted by Physical Web
- // transports to WebUI.
- void PushNearbyURLs();
-
- // Push nearby URLs to WebUI and log UMA.
- void HandlePhysicalWebPageLoaded(const base::ListValue* args);
-
- // Handles a click on a Physical Web URL, recording the click and
- // directing the user appropriately.
- void HandlePhysicalWebItemClicked(const base::ListValue* args);
-
- // Registers the messages that this MessageHandler can handle.
- void RegisterMessages();
-
- protected:
- // Subclasses should implement these protected methods as a pass through to
- // the similarly named methods of the appropriate WebUI object (the exact
- // WebUI class differs per platform).
- virtual void RegisterMessageCallback(const std::string& message,
- const MessageCallback& callback) = 0;
- virtual void CallJavaScriptFunction(const std::string& function,
- const base::Value& arg) = 0;
- virtual physical_web::PhysicalWebDataSource* GetPhysicalWebDataSource() = 0;
-
- private:
- physical_web::PhysicalWebDataSource* data_source_;
- std::vector<std::string> ordered_group_ids_;
- std::map<std::string, physical_web::Metadata> metadata_map_;
-
- DISALLOW_COPY_AND_ASSIGN(PhysicalWebBaseMessageHandler);
-};
-
-} // namespace physical_web_ui
-
-#endif // COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_BASE_MESSAGE_HANDLER_H_
diff --git a/chromium/components/physical_web/webui/physical_web_ui_constants.cc b/chromium/components/physical_web/webui/physical_web_ui_constants.cc
deleted file mode 100644
index 3e7728c578b..00000000000
--- a/chromium/components/physical_web/webui/physical_web_ui_constants.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/physical_web/webui/physical_web_ui_constants.h"
-
-namespace physical_web_ui {
-
-// Resource paths.
-const char kPhysicalWebJS[] = "physical_web.js";
-const char kPhysicalWebCSS[] = "physical_web.css";
-const char kPhysicalWebLinkIcon[] = "ic_link_grey600_36dp.png";
-
-// Message handlers.
-const char kPhysicalWebPageLoaded[] = "physicalWebPageLoaded";
-const char kPhysicalWebItemClicked[] = "physicalWebItemClicked";
-
-// Strings.
-const char kTitle[] = "title";
-const char kEmptyMessage[] = "emptyMessage";
-const char kPageInfoDescription[] = "pageInfoDescription";
-const char kPageInfoIcon[] = "pageInfoIcon";
-const char kPageInfoTitle[] = "pageInfoTitle";
-const char kResolvedUrl[] = "resolvedUrl";
-const char kIndex[] = "index";
-const char kPushNearbyUrls[] = "pushNearbyURLs";
-const char kMetadata[] = "metadata";
-
-} // namespace physical_web_ui
diff --git a/chromium/components/physical_web/webui/physical_web_ui_constants.h b/chromium/components/physical_web/webui/physical_web_ui_constants.h
deleted file mode 100644
index 6b18bbaf1bf..00000000000
--- a/chromium/components/physical_web/webui/physical_web_ui_constants.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_UI_CONSTANTS_H_
-#define COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_UI_CONSTANTS_H_
-
-namespace physical_web_ui {
-
-// Resource paths.
-// Must match the resource file names.
-extern const char kPhysicalWebJS[];
-extern const char kPhysicalWebCSS[];
-extern const char kPhysicalWebLinkIcon[];
-
-// Message handlers.
-// Must match the constants used in the resource files.
-extern const char kPhysicalWebPageLoaded[];
-extern const char kPhysicalWebItemClicked[];
-
-// Strings.
-// Must match the constants used in the resource files.
-extern const char kTitle[];
-extern const char kEmptyMessage[];
-extern const char kPageInfoDescription[];
-extern const char kPageInfoIcon[];
-extern const char kPageInfoTitle[];
-extern const char kResolvedUrl[];
-extern const char kIndex[];
-extern const char kPushNearbyUrls[];
-extern const char kMetadata[];
-
-} // namespace physical_web_ui
-
-#endif // COMPONENTS_PHYSICAL_WEB_WEBUI_PHYSICAL_WEB_UI_CONSTANTS_H_
diff --git a/chromium/components/physical_web/webui/resources/physical_web.css b/chromium/components/physical_web/webui/resources/physical_web.css
deleted file mode 100644
index 29298209538..00000000000
--- a/chromium/components/physical_web/webui/resources/physical_web.css
+++ /dev/null
@@ -1,52 +0,0 @@
-/* Copyright (c) 2016 The Chromium Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file. */
-
-body {
- font-family: Sans-Serif;
- font-size: .9em;
-}
-.physicalWebTemplate {
- display: flex;
- width: 100%;
- margin-bottom: .8em;
- text-decoration: none;
-}
-.physicalWebIcon {
- flex: 0 0 2.5em;
- padding-left: .2em;
-}
-.physicalWebIcon img {
- width: 75%;
-}
-.physicalWebText {
- flex: 1;
- padding-top: .2em;
- min-width: 0;
-}
-.physicalWebText .title {
- display: block;
- color: #222;
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- margin-bottom: .2em;
-}
-.physicalWebText .resolvedUrl {
- display: block;
- width: 100%;
- font-size: 80%;
- color: #888;
- margin-bottom: .1em;
- word-wrap: break-word;
- word-break: break-all;
-}
-.physicalWebText .description {
- display: block;
- height: 2.5em;
- line-height: 1.25;
- font-size: 90%;
- color: #444;
- overflow: hidden;
- text-overflow: ellipsis;
-}
diff --git a/chromium/components/physical_web/webui/resources/physical_web.html b/chromium/components/physical_web/webui/resources/physical_web.html
deleted file mode 100644
index a873271a69d..00000000000
--- a/chromium/components/physical_web/webui/resources/physical_web.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!doctype html>
-<html dir="$i18n{textdirection}" lang="$i18n{language}">
-<head>
-<meta charset="utf-8">
-<title>$i18n{title}</title>
-<if expr="is_android or is_ios">
-<meta name="viewport" content="width=device-width, user-scalable=no">
-</if>
-<link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-<link rel="stylesheet" href="chrome://physical-web/physical_web.css">
-
-<if expr="is_ios">
-<!-- TODO(crbug.com/487000): Remove this once injected by web. -->
-<script src="chrome://resources/js/ios/web_ui.js"></script>
-</if>
-
-<script src="chrome://resources/js/load_time_data.js"></script>
-<script src="chrome://resources/js/util.js"></script>
-<script src="chrome://physical-web/physical_web.js"></script>
-<script src="chrome://physical-web/strings.js"></script>
-</head>
-<body>
-
-<div id="body-container" hidden>
- <h1>$i18n{title}</h1>
- <div id="render-container"></div>
- <div id="empty-list-container">$i18n{emptyMessage}</div>
-</div>
-
-<a hidden id="render-template" class="physicalWebTemplate" jsselect="metadata"
- jsvalues="href:resolvedUrl;onclick:'physicalWebItemClicked(' + index + ')'">
- <div class="physicalWebIcon">
- <img jsvalues="src:pageInfoIcon" />
- </div>
- <div class="physicalWebText">
- <div class="title" jscontent="pageInfoTitle"></div>
- <div class="resolvedUrl" jscontent="resolvedUrl"></div>
- <div class="description" jscontent="pageInfoDescription"></div>
- </div>
-</a>
-
-<script src="chrome://resources/js/i18n_template.js"></script>
-<script src="chrome://resources/js/jstemplate_compiled.js"></script>
-</body>
-</html>
diff --git a/chromium/components/physical_web/webui/resources/physical_web.js b/chromium/components/physical_web/webui/resources/physical_web.js
deleted file mode 100644
index 86002dd5027..00000000000
--- a/chromium/components/physical_web/webui/resources/physical_web.js
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-/**
- * Takes the |nearbyUrlsData| input argument which holds metadata for web pages
- * broadcast by nearby devices.
- * @param {Object} nearbyUrlsData Information about web pages broadcast by
- * nearby devices
- */
-function renderTemplate(nearbyUrlsData) {
- if (nearbyUrlsData['metadata'].length != 0) {
- $('empty-list-container').hidden = true;
- }
- // This is a workaround with jstemplate. Jstemplate render only works on empty
- // node. When we need to rerender things, we have to remove previous nodes.
- let renderContainer = document.getElementById('render-container');
- // Remove existing childNode.
- while (renderContainer.hasChildNodes()) {
- renderContainer.removeChild(renderContainer.lastChild);
- }
- let templateDiv = document.getElementById('render-template').cloneNode(true);
- renderContainer.appendChild(templateDiv);
-
- // This is the javascript code that processes the template:
- jstProcess(new JsEvalContext(nearbyUrlsData), templateDiv);
-
- assignImageLoadErrorHandlers();
-
- let bodyContainer = $('body-container');
- bodyContainer.hidden = false;
-}
-
-function physicalWebPageLoaded() {
- chrome.send('physicalWebPageLoaded');
-}
-
-function physicalWebItemClicked(index) {
- chrome.send('physicalWebItemClicked', [index]);
-}
-
-function pushNearbyURLs(nearbyUrlsData) {
- renderTemplate(nearbyUrlsData);
-}
-
-function assignImageLoadErrorHandlers() {
- var pwIcons = document.querySelectorAll('.physicalWebIcon');
- pwIcons.forEach(function(e) {
- let img = e.getElementsByTagName('img')[0];
- img.addEventListener('error', function() {
- img.src =
- 'chrome://physical-web/ic_link_grey600_36dp.png';
- });
- });
-}
-
-document.addEventListener('DOMContentLoaded', physicalWebPageLoaded);
diff --git a/chromium/components/physical_web_ui_strings.grdp b/chromium/components/physical_web_ui_strings.grdp
deleted file mode 100644
index cc5e09f494b..00000000000
--- a/chromium/components/physical_web_ui_strings.grdp
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
- <message name="IDS_PHYSICAL_WEB_UI_TITLE" desc="Title of a built-in page that displays a list of Physical Web URLs (URLs broadcast by nearby devices).">
- Physical Web
- </message>
- <message name="IDS_PHYSICAL_WEB_UI_EMPTY_MESSAGE" desc="The message displayed in place of a list of nearby URLs when there are no URLs to display.">
- No Physical Web pages to show
- </message>
- <message name="IDS_PHYSICAL_WEB_UI_SCANNING_MESSAGE" desc="The message displayed in place of a list of nearby URLs while still scanning for nearby URLs.">
- Looking for nearby Physical Web pages
- </message>
-</grit-part>
diff --git a/chromium/components/plugins/renderer/plugin_placeholder.cc b/chromium/components/plugins/renderer/plugin_placeholder.cc
index 90c76fbba72..4e48cfc5578 100644
--- a/chromium/components/plugins/renderer/plugin_placeholder.cc
+++ b/chromium/components/plugins/renderer/plugin_placeholder.cc
@@ -75,14 +75,14 @@ void PluginPlaceholderBase::HidePlugin() {
// 4) Seems to have a good / low false negative rate at this time.
if (element.HasAttribute("width") && element.HasAttribute("height")) {
std::string width_str("width:[\\s]*");
- width_str += element.GetAttribute("width").Utf8().data();
+ width_str += element.GetAttribute("width").Utf8();
if (base::EndsWith(width_str, "px", base::CompareCase::INSENSITIVE_ASCII)) {
width_str = width_str.substr(0, width_str.length() - 2);
}
base::TrimWhitespaceASCII(width_str, base::TRIM_TRAILING, &width_str);
width_str += "[\\s]*px";
std::string height_str("height:[\\s]*");
- height_str += element.GetAttribute("height").Utf8().data();
+ height_str += element.GetAttribute("height").Utf8();
if (base::EndsWith(height_str, "px",
base::CompareCase::INSENSITIVE_ASCII)) {
height_str = height_str.substr(0, height_str.length() - 2);
diff --git a/chromium/components/plugins/renderer/webview_plugin.cc b/chromium/components/plugins/renderer/webview_plugin.cc
index 90055bd362e..804fdd933c9 100644
--- a/chromium/components/plugins/renderer/webview_plugin.cc
+++ b/chromium/components/plugins/renderer/webview_plugin.cc
@@ -249,7 +249,7 @@ void WebViewPlugin::DidFinishLoading() {
}
void WebViewPlugin::DidFailLoading(const WebURLError& error) {
- DCHECK(!error_.get());
+ DCHECK(!error_);
error_.reset(new WebURLError(error));
}
diff --git a/chromium/components/policy/core/common/BUILD.gn b/chromium/components/policy/core/common/BUILD.gn
index a63fb69b25c..922f57ef261 100644
--- a/chromium/components/policy/core/common/BUILD.gn
+++ b/chromium/components/policy/core/common/BUILD.gn
@@ -66,6 +66,7 @@ source_set("internal") {
"cloud/external_policy_data_updater.h",
"cloud/machine_level_user_cloud_policy_manager.cc",
"cloud/machine_level_user_cloud_policy_manager.h",
+ "cloud/machine_level_user_cloud_policy_metrics.h",
"cloud/machine_level_user_cloud_policy_store.cc",
"cloud/machine_level_user_cloud_policy_store.h",
"cloud/policy_header_io_helper.cc",
@@ -90,6 +91,8 @@ source_set("internal") {
"external_data_fetcher.cc",
"external_data_fetcher.h",
"external_data_manager.h",
+ "plist_writer.cc",
+ "plist_writer.h",
"policy_bundle.cc",
"policy_bundle.h",
"policy_details.h",
@@ -146,15 +149,16 @@ source_set("internal") {
deps = [
"//base:i18n",
"//base/third_party/dynamic_annotations",
+ "//components/account_id",
"//components/crash/core/common:crash_key", # Remove once https://crbug.com/685996 is fixed.
"//components/data_use_measurement/core",
"//components/json_schema",
"//components/prefs",
- "//components/signin/core/account_id",
"//components/version_info",
"//extensions/buildflags",
"//google_apis",
"//net",
+ "//third_party/libxml",
"//third_party/re2",
"//url",
]
@@ -210,6 +214,7 @@ source_set("internal") {
"cloud/cloud_policy_client_registration_helper.h",
"cloud/machine_level_user_cloud_policy_manager.cc",
"cloud/machine_level_user_cloud_policy_manager.h",
+ "cloud/machine_level_user_cloud_policy_metrics.h",
"cloud/machine_level_user_cloud_policy_store.cc",
"cloud/machine_level_user_cloud_policy_store.h",
"cloud/user_cloud_policy_manager.cc",
@@ -279,9 +284,9 @@ static_library("test_support") {
# Explicitly link in the generated policy target into the test support
# so it will be linked to dependent targets. Otherwise in component
# build, it will be hidden inside the policy component.
+ "//components/account_id",
"//components/policy:generated",
"//components/policy/proto",
- "//components/signin/core/account_id",
"//crypto",
"//net",
"//testing/gmock",
@@ -304,6 +309,7 @@ source_set("unit_tests") {
"cloud/policy_header_service_unittest.cc",
"cloud/user_info_fetcher_unittest.cc",
"generate_policy_source_unittest.cc",
+ "plist_writer_unittest.cc",
"policy_bundle_unittest.cc",
"policy_loader_ios_unittest.mm",
"policy_loader_mac_unittest.cc",
@@ -365,14 +371,15 @@ source_set("unit_tests") {
":test_support",
"//base",
"//base/test:test_support",
+ "//components/account_id",
"//components/policy:generated",
"//components/prefs:test_support",
- "//components/signin/core/account_id",
"//extensions/buildflags",
"//google_apis",
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
+ "//third_party/libxml",
]
}
diff --git a/chromium/components/policy_strings.grdp b/chromium/components/policy_strings.grdp
index e9cf57456cd..3a3d70f7d9b 100644
--- a/chromium/components/policy_strings.grdp
+++ b/chromium/components/policy_strings.grdp
@@ -241,6 +241,10 @@
in linux format.">
Export Linux
</message>
+ <message name="IDS_EXPORT_POLICIES_MAC" desc="Button that exports the current session policy
+ in mac format (.plist).">
+ Export MacOS
+ </message>
<message name="IDS_POLICY_TOOL_EDIT" desc="Label for the button to change policy value in current session.">
Edit
</message>
@@ -259,6 +263,9 @@
<message name="IDS_POLICY_TOOL_SESSION_NAME_PLACEHOLDER" desc="Placeholder for the input field that lets the user change policy management sessions.">
Session name
</message>
+ <message name="IDS_POLICY_TOOL_INVALID_TYPE" desc="The text displayed in the status column when the value type doesn't match the actual policy type.">
+ The policy type is invalid.
+ </message>
<message name="IDS_POLICY_TOOL_SAVING_DISABLED" desc="A message that is shown to the user when there is some problem that prevents saving the session to disk.">
There was a problem accessing the session files. Saving to disk is currently disabled. Please reload the page to try again.
</message>
@@ -317,6 +324,9 @@
<message name="IDS_POLICY_LABEL_USERNAME" desc="Label for the username in the user policy status box.">
User:
</message>
+ <message name="IDS_POLICY_LABEL_GAIA_ID" desc="Label for the user GAIA ID in the user policy status box.">
+ Gaia ID:
+ </message>
<message name="IDS_POLICY_LABEL_CLIENT_ID" desc="Label for the client IDs in the policy status boxes.">
Client ID:
</message>
diff --git a/chromium/components/policy_strings_grdp/IDS_EXPORT_POLICIES_MAC.png.sha1 b/chromium/components/policy_strings_grdp/IDS_EXPORT_POLICIES_MAC.png.sha1
new file mode 100644
index 00000000000..ad4b85df104
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/IDS_EXPORT_POLICIES_MAC.png.sha1
@@ -0,0 +1 @@
+6a4b039557da663d5e2db4c9a5afd094dd9b4047 \ No newline at end of file
diff --git a/chromium/components/policy_strings_grdp/OWNERS b/chromium/components/policy_strings_grdp/OWNERS
new file mode 100644
index 00000000000..f22fa361bed
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/policy/OWNERS
diff --git a/chromium/components/policy_strings_grdp/README.md b/chromium/components/policy_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/policy_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/pref_registry/pref_registry_syncable.h b/chromium/components/pref_registry/pref_registry_syncable.h
index 17f72434578..7eef955c9d5 100644
--- a/chromium/components/pref_registry/pref_registry_syncable.h
+++ b/chromium/components/pref_registry/pref_registry_syncable.h
@@ -47,9 +47,11 @@ class PrefRegistrySyncable : public PrefRegistrySimple {
SYNCABLE_PREF = 1 << 0,
// The pref will be synced. The pref will never be encrypted and will be
- // synced before other datatypes. Because they're never encrypted, on first
- // sync, they can be synced down before the user is prompted for a
- // passphrase.
+ // synced before other datatypes.
+ // Because they're never encrypted:
+ // -- they can be synced down on first sync before the user is prompted for
+ // a passphrase.
+ // -- they are preferred for receiving server-provided data.
SYNCABLE_PRIORITY_PREF = 1 << 1,
};
diff --git a/chromium/components/password_manager/public/interfaces/BUILD.gn b/chromium/components/prefs/ios/BUILD.gn
index 497c66641f0..82aa654591a 100644
--- a/chromium/components/password_manager/public/interfaces/BUILD.gn
+++ b/chromium/components/prefs/ios/BUILD.gn
@@ -2,13 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
+source_set("ios") {
+ configs += [ "//build/config/compiler:enable_arc" ]
sources = [
- "sync_password_data.mojom",
+ "pref_observer_bridge.h",
+ "pref_observer_bridge.mm",
]
deps = [
- "//mojo/common:common_custom_types",
+ "//base",
+ "//components/prefs",
]
}
diff --git a/chromium/components/prefs/ios/pref_observer_bridge.h b/chromium/components/prefs/ios/pref_observer_bridge.h
new file mode 100644
index 00000000000..425ef87027b
--- /dev/null
+++ b/chromium/components/prefs/ios/pref_observer_bridge.h
@@ -0,0 +1,32 @@
+// Copyright 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PREFS_IOS_PREF_OBSERVER_BRIDGE_H_
+#define COMPONENTS_PREFS_IOS_PREF_OBSERVER_BRIDGE_H_
+
+#import <Foundation/Foundation.h>
+
+#include <string>
+
+class PrefChangeRegistrar;
+
+@protocol PrefObserverDelegate
+- (void)onPreferenceChanged:(const std::string&)preferenceName;
+@end
+
+class PrefObserverBridge {
+ public:
+ explicit PrefObserverBridge(id<PrefObserverDelegate> delegate);
+ virtual ~PrefObserverBridge();
+
+ virtual void ObserveChangesForPreference(const std::string& pref_name,
+ PrefChangeRegistrar* registrar);
+
+ private:
+ virtual void OnPreferenceChanged(const std::string& pref_name);
+
+ __weak id<PrefObserverDelegate> delegate_ = nil;
+};
+
+#endif // COMPONENTS_PREFS_IOS_PREF_OBSERVER_BRIDGE_H_
diff --git a/chromium/components/prefs/ios/pref_observer_bridge.mm b/chromium/components/prefs/ios/pref_observer_bridge.mm
new file mode 100644
index 00000000000..852309ff240
--- /dev/null
+++ b/chromium/components/prefs/ios/pref_observer_bridge.mm
@@ -0,0 +1,29 @@
+// Copyright 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.
+
+#import "components/prefs/ios/pref_observer_bridge.h"
+
+#include "base/bind.h"
+#include "components/prefs/pref_change_registrar.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+PrefObserverBridge::PrefObserverBridge(id<PrefObserverDelegate> delegate)
+ : delegate_(delegate) {}
+
+PrefObserverBridge::~PrefObserverBridge() {}
+
+void PrefObserverBridge::ObserveChangesForPreference(
+ const std::string& pref_name,
+ PrefChangeRegistrar* registrar) {
+ PrefChangeRegistrar::NamedChangeCallback callback = base::BindRepeating(
+ &PrefObserverBridge::OnPreferenceChanged, base::Unretained(this));
+ registrar->Add(pref_name.c_str(), callback);
+}
+
+void PrefObserverBridge::OnPreferenceChanged(const std::string& pref_name) {
+ [delegate_ onPreferenceChanged:pref_name];
+}
diff --git a/chromium/components/prefs/json_pref_store.cc b/chromium/components/prefs/json_pref_store.cc
index 5c6cad1bd5b..1de21862e01 100644
--- a/chromium/components/prefs/json_pref_store.cc
+++ b/chromium/components/prefs/json_pref_store.cc
@@ -408,7 +408,7 @@ void JsonPrefStore::OnFileRead(std::unique_ptr<ReadResult> read_result) {
read_only_ = true;
break;
case PREF_READ_ERROR_NONE:
- DCHECK(read_result->value.get());
+ DCHECK(read_result->value);
unfiltered_prefs.reset(
static_cast<base::DictionaryValue*>(read_result->value.release()));
break;
diff --git a/chromium/components/prefs/pref_change_registrar_unittest.cc b/chromium/components/prefs/pref_change_registrar_unittest.cc
index 5cfaa2b3b43..b02b13a5bbe 100644
--- a/chromium/components/prefs/pref_change_registrar_unittest.cc
+++ b/chromium/components/prefs/pref_change_registrar_unittest.cc
@@ -28,7 +28,7 @@ const char kApplicationLocale[] = "intl.app_locale";
class MockPrefService : public TestingPrefServiceSimple {
public:
MockPrefService() {}
- virtual ~MockPrefService() {}
+ ~MockPrefService() override {}
MOCK_METHOD2(AddPrefObserver, void(const std::string&, PrefObserver*));
MOCK_METHOD2(RemovePrefObserver, void(const std::string&, PrefObserver*));
@@ -126,7 +126,7 @@ TEST_F(PrefChangeRegistrarTest, RemoveAll) {
class ObserveSetOfPreferencesTest : public testing::Test {
public:
- virtual void SetUp() {
+ void SetUp() override {
pref_service_.reset(new TestingPrefServiceSimple);
PrefRegistrySimple* registry = pref_service_->registry();
registry->RegisterStringPref(kHomePage, "http://google.com");
diff --git a/chromium/components/prefs/pref_notifier_impl_unittest.cc b/chromium/components/prefs/pref_notifier_impl_unittest.cc
index 06ab053045c..a76c9338442 100644
--- a/chromium/components/prefs/pref_notifier_impl_unittest.cc
+++ b/chromium/components/prefs/pref_notifier_impl_unittest.cc
@@ -49,7 +49,7 @@ class MockPrefNotifier : public PrefNotifierImpl {
public:
explicit MockPrefNotifier(PrefService* pref_service)
: PrefNotifierImpl(pref_service) {}
- virtual ~MockPrefNotifier() {}
+ ~MockPrefNotifier() override {}
MOCK_METHOD1(FireObservers, void(const std::string& path));
diff --git a/chromium/components/prefs/pref_service.cc b/chromium/components/prefs/pref_service.cc
index ab9b9e5d36f..7254d0b582e 100644
--- a/chromium/components/prefs/pref_service.cc
+++ b/chromium/components/prefs/pref_service.cc
@@ -276,6 +276,17 @@ bool PrefService::IsUserModifiablePreference(
return pref && pref->IsUserModifiable();
}
+const base::Value* PrefService::Get(const std::string& path) const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ const base::Value* value = GetPreferenceValue(path);
+ if (!value) {
+ NOTREACHED() << "Trying to read an unregistered pref: " << path;
+ return nullptr;
+ }
+ return value;
+}
+
const base::DictionaryValue* PrefService::GetDictionary(
const std::string& path) const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
diff --git a/chromium/components/prefs/pref_service.h b/chromium/components/prefs/pref_service.h
index 8047b3b17b9..39525525f81 100644
--- a/chromium/components/prefs/pref_service.h
+++ b/chromium/components/prefs/pref_service.h
@@ -216,6 +216,7 @@ class COMPONENTS_PREFS_EXPORT PrefService {
// Returns the branch if it exists, or the registered default value otherwise.
// Note that |path| must point to a registered preference. In that case, these
// functions will never return NULL.
+ const base::Value* Get(const std::string& path) const;
const base::DictionaryValue* GetDictionary(const std::string& path) const;
const base::ListValue* GetList(const std::string& path) const;
diff --git a/chromium/components/prefs/pref_value_store.cc b/chromium/components/prefs/pref_value_store.cc
index 8f9e704042a..0db795a982b 100644
--- a/chromium/components/prefs/pref_value_store.cc
+++ b/chromium/components/prefs/pref_value_store.cc
@@ -14,7 +14,7 @@ PrefValueStore::PrefStoreKeeper::PrefStoreKeeper()
: pref_value_store_(nullptr), type_(PrefValueStore::INVALID_STORE) {}
PrefValueStore::PrefStoreKeeper::~PrefStoreKeeper() {
- if (pref_store_.get()) {
+ if (pref_store_) {
pref_store_->RemoveObserver(this);
pref_store_ = nullptr;
}
@@ -25,14 +25,14 @@ void PrefValueStore::PrefStoreKeeper::Initialize(
PrefValueStore* store,
PrefStore* pref_store,
PrefValueStore::PrefStoreType type) {
- if (pref_store_.get()) {
+ if (pref_store_) {
pref_store_->RemoveObserver(this);
DCHECK(!pref_store_->HasObservers());
}
type_ = type;
pref_value_store_ = store;
pref_store_ = pref_store;
- if (pref_store_.get())
+ if (pref_store_)
pref_store_->AddObserver(this);
}
diff --git a/chromium/components/previews/content/previews_content_util_unittest.cc b/chromium/components/previews/content/previews_content_util_unittest.cc
index 5d0c259a3e2..0f3aa8db25c 100644
--- a/chromium/components/previews/content/previews_content_util_unittest.cc
+++ b/chromium/components/previews/content/previews_content_util_unittest.cc
@@ -72,7 +72,7 @@ class PreviewEnabledPreviewsDecider : public PreviewsDecider {
class PreviewsContentUtilTest : public testing::Test {
public:
- PreviewsContentUtilTest() : enabled_previews_decider_(), context_() {}
+ PreviewsContentUtilTest() {}
~PreviewsContentUtilTest() override {}
PreviewsDecider* enabled_previews_decider() {
diff --git a/chromium/components/previews/core/previews_black_list_item.cc b/chromium/components/previews/core/previews_black_list_item.cc
index 9fd6ad17878..8f0d016102f 100644
--- a/chromium/components/previews/core/previews_black_list_item.cc
+++ b/chromium/components/previews/core/previews_black_list_item.cc
@@ -17,10 +17,10 @@ PreviewsBlackListItem::OptOutRecord::OptOutRecord(base::Time entry_time,
PreviewsBlackListItem::OptOutRecord::~OptOutRecord() {}
-PreviewsBlackListItem::OptOutRecord::OptOutRecord(OptOutRecord&&) = default;
-
+PreviewsBlackListItem::OptOutRecord::OptOutRecord(OptOutRecord&&) noexcept =
+ default;
PreviewsBlackListItem::OptOutRecord& PreviewsBlackListItem::OptOutRecord::
-operator=(OptOutRecord&&) = default;
+operator=(OptOutRecord&&) noexcept = default;
bool PreviewsBlackListItem::OptOutRecord::operator<(
const OptOutRecord& other) const {
diff --git a/chromium/components/previews/core/previews_black_list_item.h b/chromium/components/previews/core/previews_black_list_item.h
index 22d8c442e8a..8c23c8f9de7 100644
--- a/chromium/components/previews/core/previews_black_list_item.h
+++ b/chromium/components/previews/core/previews_black_list_item.h
@@ -53,8 +53,8 @@ class PreviewsBlackListItem {
public:
OptOutRecord(base::Time entry_time, bool opt_out);
~OptOutRecord();
- OptOutRecord(OptOutRecord&&);
- OptOutRecord& operator=(OptOutRecord&&);
+ OptOutRecord(OptOutRecord&&) noexcept;
+ OptOutRecord& operator=(OptOutRecord&&) noexcept;
// Used to determine eviction priority.
bool operator<(const OptOutRecord& other) const;
diff --git a/chromium/components/previews/core/previews_opt_out_store_sql.cc b/chromium/components/previews/core/previews_opt_out_store_sql.cc
index 88bb76b6cca..5cddd0b823f 100644
--- a/chromium/components/previews/core/previews_opt_out_store_sql.cc
+++ b/chromium/components/previews/core/previews_opt_out_store_sql.cc
@@ -421,7 +421,7 @@ PreviewsOptOutStoreSQL::PreviewsOptOutStoreSQL(
PreviewsOptOutStoreSQL::~PreviewsOptOutStoreSQL() {
DCHECK(io_task_runner_->BelongsToCurrentThread());
- if (db_.get()) {
+ if (db_) {
background_task_runner_->DeleteSoon(FROM_HERE, db_.release());
}
}
@@ -431,7 +431,7 @@ void PreviewsOptOutStoreSQL::AddPreviewNavigation(bool opt_out,
PreviewsType type,
base::Time now) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
- DCHECK(db_.get());
+ DCHECK(db_);
background_task_runner_->PostTask(
FROM_HERE, base::Bind(&AddPreviewNavigationSync, opt_out, host_name, type,
now, db_.get()));
@@ -440,7 +440,7 @@ void PreviewsOptOutStoreSQL::AddPreviewNavigation(bool opt_out,
void PreviewsOptOutStoreSQL::ClearBlackList(base::Time begin_time,
base::Time end_time) {
DCHECK(io_task_runner_->BelongsToCurrentThread());
- DCHECK(db_.get());
+ DCHECK(db_);
background_task_runner_->PostTask(
FROM_HERE,
base::Bind(&ClearBlackListSync, db_.get(), begin_time, end_time));
diff --git a/chromium/components/previews/core/previews_user_data_unittest.cc b/chromium/components/previews/core/previews_user_data_unittest.cc
index d8f557ac097..61d4c246af8 100644
--- a/chromium/components/previews/core/previews_user_data_unittest.cc
+++ b/chromium/components/previews/core/previews_user_data_unittest.cc
@@ -41,7 +41,7 @@ TEST_F(PreviewsUserDataTest, AddToURLRequest) {
std::unique_ptr<net::URLRequest> fake_request(context->CreateRequest(
GURL("http://www.google.com"), net::RequestPriority::IDLE, nullptr,
TRAFFIC_ANNOTATION_FOR_TESTS));
- PreviewsUserData* data = PreviewsUserData::GetData(*fake_request.get());
+ PreviewsUserData* data = PreviewsUserData::GetData(*fake_request);
EXPECT_FALSE(data);
data = PreviewsUserData::Create(fake_request.get(), 1u);
diff --git a/chromium/components/printing/browser/BUILD.gn b/chromium/components/printing/browser/BUILD.gn
index d7e30dd9df8..48576977c77 100644
--- a/chromium/components/printing/browser/BUILD.gn
+++ b/chromium/components/printing/browser/BUILD.gn
@@ -21,7 +21,7 @@ static_library("browser") {
deps = [
"//base",
"//components/printing/common",
- "//components/printing/service/public/interfaces",
+ "//components/services/pdf_compositor/public/interfaces",
"//printing",
"//printing/common:common",
"//services/service_manager/public/cpp",
diff --git a/chromium/components/printing/browser/DEPS b/chromium/components/printing/browser/DEPS
index 8dc6d21d04f..9adac877b96 100644
--- a/chromium/components/printing/browser/DEPS
+++ b/chromium/components/printing/browser/DEPS
@@ -1,6 +1,6 @@
include_rules = [
- "+components/printing/service/public/cpp",
- "+components/printing/service/public/interfaces",
+ "+components/services/pdf_compositor/public/cpp",
+ "+components/services/pdf_compositor/public/interfaces",
"+content/public/browser",
"+mojo/public/cpp/system",
"+services/service_manager/public/cpp",
diff --git a/chromium/components/printing/browser/print_composite_client.cc b/chromium/components/printing/browser/print_composite_client.cc
index 65f66357993..4f4d8a1df7a 100644
--- a/chromium/components/printing/browser/print_composite_client.cc
+++ b/chromium/components/printing/browser/print_composite_client.cc
@@ -201,7 +201,7 @@ void PrintCompositeClient::DoCompositeDocumentToPdf(
void PrintCompositeClient::OnDidCompositePageToPdf(
printing::mojom::PdfCompositor::CompositePageToPdfCallback callback,
printing::mojom::PdfCompositor::Status status,
- mojo::ScopedSharedBufferHandle handle) {
+ base::ReadOnlySharedMemoryRegion region) {
// Due to https://crbug.com/742517, we can not add and use COUNT for enums in
// mojo.
UMA_HISTOGRAM_ENUMERATION(
@@ -209,14 +209,14 @@ void PrintCompositeClient::OnDidCompositePageToPdf(
static_cast<int32_t>(
printing::mojom::PdfCompositor::Status::COMPOSTING_FAILURE) +
1);
- std::move(callback).Run(status, std::move(handle));
+ std::move(callback).Run(status, std::move(region));
}
void PrintCompositeClient::OnDidCompositeDocumentToPdf(
int document_cookie,
printing::mojom::PdfCompositor::CompositeDocumentToPdfCallback callback,
printing::mojom::PdfCompositor::Status status,
- mojo::ScopedSharedBufferHandle handle) {
+ base::ReadOnlySharedMemoryRegion region) {
RemoveCompositeRequest(document_cookie);
// Clear all stored printed subframes.
printed_subframes_.erase(document_cookie);
@@ -228,7 +228,7 @@ void PrintCompositeClient::OnDidCompositeDocumentToPdf(
static_cast<int32_t>(
printing::mojom::PdfCompositor::Status::COMPOSTING_FAILURE) +
1);
- std::move(callback).Run(status, std::move(handle));
+ std::move(callback).Run(status, std::move(region));
}
ContentToFrameMap PrintCompositeClient::ConvertContentInfoMap(
diff --git a/chromium/components/printing/browser/print_composite_client.h b/chromium/components/printing/browser/print_composite_client.h
index 2d23b45e64e..8718f321fd2 100644
--- a/chromium/components/printing/browser/print_composite_client.h
+++ b/chromium/components/printing/browser/print_composite_client.h
@@ -10,8 +10,8 @@
#include "base/containers/flat_set.h"
#include "base/optional.h"
-#include "components/printing/service/public/cpp/pdf_service_mojo_types.h"
-#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h"
+#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "printing/common/pdf_metafile_utils.h"
@@ -95,13 +95,13 @@ class PrintCompositeClient
void OnDidCompositePageToPdf(
printing::mojom::PdfCompositor::CompositePageToPdfCallback callback,
printing::mojom::PdfCompositor::Status status,
- mojo::ScopedSharedBufferHandle handle);
+ base::ReadOnlySharedMemoryRegion region);
void OnDidCompositeDocumentToPdf(
int document_cookie,
printing::mojom::PdfCompositor::CompositeDocumentToPdfCallback callback,
printing::mojom::PdfCompositor::Status status,
- mojo::ScopedSharedBufferHandle handle);
+ base::ReadOnlySharedMemoryRegion region);
// Get the request or create a new one if none exists.
// Since printed pages always share content with it document, they share the
diff --git a/chromium/components/printing/browser/print_manager_utils.cc b/chromium/components/printing/browser/print_manager_utils.cc
index 59b9ca8642f..a38d8ab661b 100644
--- a/chromium/components/printing/browser/print_manager_utils.cc
+++ b/chromium/components/printing/browser/print_manager_utils.cc
@@ -68,6 +68,7 @@ void RenderParamsFromPrintSettings(const PrintSettings& settings,
params->url = settings.url();
params->printed_doc_type =
IsOopifEnabled() ? SkiaDocumentType::MSKP : SkiaDocumentType::PDF;
+ params->num_pages_per_sheet = settings.num_pages_per_sheet();
}
} // namespace printing
diff --git a/chromium/components/printing/common/print_messages.cc b/chromium/components/printing/common/print_messages.cc
index b308dc410ff..8b6f52b3f80 100644
--- a/chromium/components/printing/common/print_messages.cc
+++ b/chromium/components/printing/common/print_messages.cc
@@ -73,12 +73,8 @@ namespace IPC {
} // namespace IPC
PrintMsg_Print_Params::PrintMsg_Print_Params()
- : page_size(),
- content_size(),
- printable_area(),
- margin_top(0),
+ : margin_top(0),
margin_left(0),
- dpi(),
scale_factor(1.0f),
rasterize_pdf(false),
document_cookie(0),
@@ -90,13 +86,10 @@ PrintMsg_Print_Params::PrintMsg_Print_Params()
print_scaling_option(blink::kWebPrintScalingOptionSourceSize),
print_to_pdf(false),
display_header_footer(false),
- title(),
- url(),
- header_template(),
- footer_template(),
should_print_backgrounds(false),
printed_doc_type(printing::SkiaDocumentType::PDF),
- prefer_css_page_size(false) {}
+ prefer_css_page_size(false),
+ num_pages_per_sheet(1) {}
PrintMsg_Print_Params::PrintMsg_Print_Params(
const PrintMsg_Print_Params& other) = default;
@@ -128,11 +121,10 @@ void PrintMsg_Print_Params::Reset() {
should_print_backgrounds = false;
printed_doc_type = printing::SkiaDocumentType::PDF;
prefer_css_page_size = false;
+ num_pages_per_sheet = 1;
}
-PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params()
- : pages() {
-}
+PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params() {}
PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params(
const PrintMsg_PrintPages_Params& other) = default;
diff --git a/chromium/components/printing/common/print_messages.h b/chromium/components/printing/common/print_messages.h
index 0f1e59167b2..cd3fe2986af 100644
--- a/chromium/components/printing/common/print_messages.h
+++ b/chromium/components/printing/common/print_messages.h
@@ -63,6 +63,7 @@ struct PrintMsg_Print_Params {
bool should_print_backgrounds;
printing::SkiaDocumentType printed_doc_type;
bool prefer_css_page_size;
+ int num_pages_per_sheet;
};
struct PrintMsg_PrintPages_Params {
@@ -191,6 +192,11 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// True if page size defined by css should be preferred.
IPC_STRUCT_TRAITS_MEMBER(prefer_css_page_size)
+
+ // Number of pages per sheet. This parameter is for N-up mode.
+ // Defaults to 1 if the feature is disabled, and some number greater
+ // than 1 otherwise. See printing::NupParameters for supported values.
+ IPC_STRUCT_TRAITS_MEMBER(num_pages_per_sheet)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(printing::PageRange)
@@ -354,7 +360,7 @@ IPC_MESSAGE_ROUTED1(PrintMsg_InitiatePrintPreview, bool /* has_selection */)
// node, depending on which mode the RenderFrame is in.
IPC_MESSAGE_ROUTED0(PrintMsg_PrintNodeUnderContextMenu)
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
+#if BUILDFLAG(ENABLE_PRINTING)
// Tells the RenderFrame to switch the CSS to print media type, renders every
// requested pages and switch back the CSS to display media type.
IPC_MESSAGE_ROUTED0(PrintMsg_PrintPages)
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.cc b/chromium/components/printing/renderer/print_render_frame_helper.cc
index 1c914fd1ba3..af18233bc50 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper.cc
@@ -286,9 +286,18 @@ void EnsureOrientationMatches(const PrintMsg_Print_Params& css_params,
void ComputeWebKitPrintParamsInDesiredDpi(
const PrintMsg_Print_Params& print_params,
+ bool source_is_pdf,
blink::WebPrintParams* webkit_print_params) {
int dpi = GetDPI(&print_params);
webkit_print_params->printer_dpi = dpi;
+ if (source_is_pdf) {
+ // The |scale_factor| in print_params comes from the |scale_factor| in
+ // PrintSettings, which converts an integer percentage between 10 and 200
+ // to a float in PrintSettingsFromJobSettings. As a result, it can be
+ // converted back safely for the integer |scale_factor| in WebPrintParams.
+ webkit_print_params->scale_factor =
+ static_cast<int>(print_params.scale_factor * 100);
+ }
webkit_print_params->rasterize_pdf = print_params.rasterize_pdf;
webkit_print_params->print_scaling_option = print_params.print_scaling_option;
@@ -310,6 +319,9 @@ void ComputeWebKitPrintParamsInDesiredDpi(
ConvertUnit(print_params.page_size.width(), dpi, kPointsPerInch);
webkit_print_params->paper_size.height =
ConvertUnit(print_params.page_size.height(), dpi, kPointsPerInch);
+
+ // The following settings is for N-up mode.
+ webkit_print_params->num_pages_per_sheet = print_params.num_pages_per_sheet;
}
blink::WebPlugin* GetPlugin(const blink::WebLocalFrame* frame) {
@@ -395,7 +407,6 @@ bool PDFShouldDisableScaling(blink::WebLocalFrame* frame,
}
#endif
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
MarginType GetMarginsForPdf(blink::WebLocalFrame* frame,
const blink::WebNode& node,
const PrintMsg_Print_Params& params) {
@@ -403,7 +414,6 @@ MarginType GetMarginsForPdf(blink::WebLocalFrame* frame,
? NO_MARGINS
: PRINTABLE_AREA_MARGINS;
}
-#endif
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
bool FitToPageEnabled(const base::DictionaryValue& job_settings) {
@@ -571,6 +581,14 @@ blink::WebView* FrameReference::view() {
return view_;
}
+// static
+double PrintRenderFrameHelper::GetScaleFactor(double input_scale_factor,
+ bool is_pdf) {
+ if (input_scale_factor >= PrintRenderFrameHelper::kEpsilon && !is_pdf)
+ return input_scale_factor;
+ return 1.0f;
+}
+
// static - Not anonymous so that platform implementations can use it.
void PrintRenderFrameHelper::PrintHeaderAndFooter(
blink::WebCanvas* canvas,
@@ -614,7 +632,7 @@ void PrintRenderFrameHelper::PrintHeaderAndFooter(
base::Value html(base::UTF8ToUTF16(
ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_PRINT_PREVIEW_PAGE)));
+ IDR_PRINT_HEADER_FOOTER_TEMPLATE_PAGE)));
// Load page with script to avoid async operations.
ExecuteScript(frame, kPageLoadScriptFormat, html);
@@ -744,20 +762,21 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
is_printing_started_(false),
weak_ptr_factory_(this) {
PrintMsg_Print_Params print_params = params;
- if (!should_print_selection_only_ ||
- !PrintingNodeOrPdfFrame(frame, node_to_print_)) {
+ bool source_is_pdf = PrintingNodeOrPdfFrame(frame, node_to_print_);
+ if (!should_print_selection_only_ || !source_is_pdf) {
bool fit_to_page =
ignore_css_margins && IsWebPrintScalingOptionFitToPage(print_params);
- ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_);
+ ComputeWebKitPrintParamsInDesiredDpi(params, source_is_pdf,
+ &web_print_params_);
frame->PrintBegin(web_print_params_, node_to_print_);
- double scale_factor = 1.0f;
- if (print_params.scale_factor >= PrintRenderFrameHelper::kEpsilon)
- scale_factor = print_params.scale_factor;
+ double scale_factor = PrintRenderFrameHelper::GetScaleFactor(
+ print_params.scale_factor, source_is_pdf);
print_params = CalculatePrintParamsForCss(
frame, 0, print_params, ignore_css_margins, fit_to_page, &scale_factor);
frame->PrintEnd();
}
- ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_);
+ ComputeWebKitPrintParamsInDesiredDpi(print_params, source_is_pdf,
+ &web_print_params_);
}
PrepareFrameAndViewForPrint::~PrepareFrameAndViewForPrint() {
@@ -1017,7 +1036,6 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
RequestPrintPreview(PRINT_PREVIEW_SCRIPTED);
#endif
} else {
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
auto weak_this = weak_ptr_factory_.GetWeakPtr();
web_frame->DispatchBeforePrintEvent();
if (!weak_this)
@@ -1025,7 +1043,6 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
Print(web_frame, blink::WebNode(), true /* is_scripted? */);
if (weak_this)
web_frame->DispatchAfterPrintEvent();
-#endif
}
// WARNING: |this| may be gone at this point. Do not do any more work here and
// just return.
@@ -1043,10 +1060,8 @@ bool PrintRenderFrameHelper::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintRenderFrameHelper, message)
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages)
IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog)
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview, OnInitiatePrintPreview)
IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview)
@@ -1073,7 +1088,6 @@ void PrintRenderFrameHelper::OnDestruct() {
delete this;
}
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
void PrintRenderFrameHelper::OnPrintPages() {
if (ipc_nesting_level_ > 1)
return;
@@ -1109,7 +1123,6 @@ void PrintRenderFrameHelper::OnPrintForSystemDialog() {
// WARNING: |this| may be gone at this point. Do not do any more work here and
// just return.
}
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
void PrintRenderFrameHelper::GetPageSizeAndContentAreaFromPageLayout(
const PageSizeMargins& page_layout_in_points,
@@ -1227,8 +1240,8 @@ bool PrintRenderFrameHelper::CreatePreviewDocument() {
}
PageSizeMargins default_page_layout;
- double scale_factor =
- print_params.scale_factor >= kEpsilon ? print_params.scale_factor : 1.0f;
+ double scale_factor = GetScaleFactor(print_params.scale_factor,
+ !print_preview_context_.IsModifiable());
ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(), 0,
print_params, ignore_css_margins_,
@@ -1319,14 +1332,15 @@ bool PrintRenderFrameHelper::CreatePreviewDocument() {
return true;
}
-#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
bool PrintRenderFrameHelper::RenderPreviewPage(
int page_number,
const PrintMsg_Print_Params& print_params) {
PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
base::TimeTicks begin_time = base::TimeTicks::Now();
+ double scale_factor = GetScaleFactor(print_params.scale_factor,
+ !print_preview_context_.IsModifiable());
PrintPageInternal(print_params, page_number,
- print_preview_context_.total_page_count(),
+ print_preview_context_.total_page_count(), scale_factor,
print_preview_context_.prepared_frame(),
initial_render_metafile, nullptr, nullptr);
print_preview_context_.RenderedPreviewPage(base::TimeTicks::Now() -
@@ -1347,7 +1361,6 @@ bool PrintRenderFrameHelper::RenderPreviewPage(
print_params.printed_doc_type);
return PreviewPageRendered(page_number, std::move(metafile));
}
-#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
bool PrintRenderFrameHelper::FinalizePrintReadyDocument() {
DCHECK(!is_print_ready_metafile_sent_);
@@ -1503,7 +1516,6 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE);
#endif
} else {
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
// Make a copy of the node, in case RenderView::OnContextMenuClosed() resets
// its |context_menu_node_|.
blink::WebNode duplicate_node(node);
@@ -1514,13 +1526,11 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
// Check if |this| is still valid.
if (!self)
return;
-#endif
}
print_node_in_progress_ = false;
}
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
const blink::WebNode& node,
bool is_scripted) {
@@ -1576,7 +1586,6 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
}
scripting_throttler_.Reset();
}
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
void PrintRenderFrameHelper::DidFinishPrinting(PrintingResult result) {
int cookie =
@@ -1619,7 +1628,6 @@ void PrintRenderFrameHelper::DidFinishPrinting(PrintingResult result) {
notify_browser_of_print_failure_ = true;
}
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
void PrintRenderFrameHelper::OnFramePreparedForPrintPages() {
PrintPages();
FinishFramePrinting();
@@ -1653,7 +1661,9 @@ void PrintRenderFrameHelper::PrintPages() {
UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count);
}
- if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) {
+ bool is_pdf = PrintingNodeOrPdfFrame(prep_frame_view_->frame(),
+ prep_frame_view_->node());
+ if (!PrintPagesNative(prep_frame_view_->frame(), page_count, is_pdf)) {
LOG(ERROR) << "Printing failed.";
return DidFinishPrinting(FAIL_PRINT);
}
@@ -1661,7 +1671,8 @@ void PrintRenderFrameHelper::PrintPages() {
#if defined(OS_MACOSX) || defined(OS_WIN)
bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
- int page_count) {
+ int page_count,
+ bool is_pdf) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
@@ -1674,11 +1685,12 @@ bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
CHECK(metafile.Init());
PrintHostMsg_DidPrintDocument_Params page_params;
- PrintPageInternal(print_params, printed_pages[0], page_count, frame,
- &metafile, &page_params.page_size,
- &page_params.content_area);
+ PrintPageInternal(print_params, printed_pages[0], page_count,
+ print_params.scale_factor, frame, &metafile,
+ &page_params.page_size, &page_params.content_area);
for (size_t i = 1; i < printed_pages.size(); ++i) {
- PrintPageInternal(print_params, printed_pages[i], page_count, frame,
+ PrintPageInternal(print_params, printed_pages[i], page_count,
+ GetScaleFactor(print_params.scale_factor, is_pdf), frame,
&metafile, nullptr, nullptr);
}
@@ -1703,7 +1715,6 @@ bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
void PrintRenderFrameHelper::FinishFramePrinting() {
prep_frame_view_.reset();
}
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
// static - Not anonymous so that platform implementations can use it.
void PrintRenderFrameHelper::ComputePageLayoutInPointsForCss(
@@ -1878,7 +1889,6 @@ bool PrintRenderFrameHelper::UpdatePrintSettings(
}
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
void PrintRenderFrameHelper::GetPrintSettingsFromUser(
blink::WebLocalFrame* frame,
const blink::WebNode& node,
@@ -1925,19 +1935,18 @@ bool PrintRenderFrameHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
weak_ptr_factory_.GetWeakPtr()));
return true;
}
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
#if !defined(OS_MACOSX)
void PrintRenderFrameHelper::PrintPageInternal(
const PrintMsg_Print_Params& params,
int page_number,
int page_count,
+ double scale_factor,
blink::WebLocalFrame* frame,
PdfMetafileSkia* metafile,
gfx::Size* page_size_in_dpi,
gfx::Rect* content_area_in_dpi) {
- double css_scale_factor =
- params.scale_factor >= kEpsilon ? params.scale_factor : 1.0f;
+ double css_scale_factor = scale_factor;
// Save the original page size here to avoid rounding errors incurred by
// converting to pixels and back and by scaling the page for reflow and
@@ -1970,13 +1979,13 @@ void PrintRenderFrameHelper::PrintPageInternal(
// TODO(thestig): Figure out why Linux is different.
#if defined(OS_WIN)
float webkit_page_shrink_factor = frame->GetPrintPageShrink(page_number);
- float scale_factor = css_scale_factor * webkit_page_shrink_factor;
+ float final_scale_factor = css_scale_factor * webkit_page_shrink_factor;
#else
- float scale_factor = css_scale_factor;
+ float final_scale_factor = css_scale_factor;
#endif
- cc::PaintCanvas* canvas =
- metafile->GetVectorCanvasForNewPage(page_size, canvas_area, scale_factor);
+ cc::PaintCanvas* canvas = metafile->GetVectorCanvasForNewPage(
+ page_size, canvas_area, final_scale_factor);
if (!canvas)
return;
@@ -1992,12 +2001,13 @@ void PrintRenderFrameHelper::PrintPageInternal(
#endif
// |page_number| is 0-based, so 1 is added.
PrintHeaderAndFooter(canvas, page_number + 1, page_count, *frame,
- scale_factor / fudge_factor, page_layout_in_points,
- params);
+ final_scale_factor / fudge_factor,
+ page_layout_in_points, params);
}
- float webkit_scale_factor = RenderPageContent(
- frame, page_number, canvas_area, content_area, scale_factor, canvas);
+ float webkit_scale_factor =
+ RenderPageContent(frame, page_number, canvas_area, content_area,
+ final_scale_factor, canvas);
DCHECK_GT(webkit_scale_factor, 0.0f);
// Done printing. Close the canvas to retrieve the compiled metafile.
diff --git a/chromium/components/printing/renderer/print_render_frame_helper.h b/chromium/components/printing/renderer/print_render_frame_helper.h
index b1b1a18dd6a..46da03048df 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper.h
+++ b/chromium/components/printing/renderer/print_render_frame_helper.h
@@ -127,6 +127,10 @@ class PrintRenderFrameHelper
void PrintNode(const blink::WebNode& node);
+ // Get the scale factor. Returns |input_scale_factor| if it is valid and
+ // |is_pdf| is false, and 1.0f otherwise.
+ static double GetScaleFactor(double input_scale_factor, bool is_pdf);
+
private:
friend class PrintRenderFrameHelperTestBase;
FRIEND_TEST_ALL_PREFIXES(MAYBE_PrintRenderFrameHelperPreviewTest,
@@ -182,10 +186,8 @@ class PrintRenderFrameHelper
bool OnMessageReceived(const IPC::Message& message) override;
// Message handlers ---------------------------------------------------------
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
void OnPrintPages();
void OnPrintForSystemDialog();
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
void OnInitiatePrintPreview(bool has_selection);
void OnPrintPreview(const base::DictionaryValue& settings);
@@ -228,14 +230,12 @@ class PrintRenderFrameHelper
// Main printing code -------------------------------------------------------
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
// Print with the system dialog.
// |is_scripted| should be true when the call is coming from window.print().
// WARNING: |this| may be gone after this method returns.
void Print(blink::WebLocalFrame* frame,
const blink::WebNode& node,
bool is_scripted);
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
// Notification when printing is done - signal tear-down/free resources.
void DidFinishPrinting(PrintingResult result);
@@ -264,7 +264,6 @@ class PrintRenderFrameHelper
const base::DictionaryValue& passed_job_settings);
#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW)
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
// Get final print settings from the user.
// WARNING: |this| may be gone after this method returns.
void GetPrintSettingsFromUser(blink::WebLocalFrame* frame,
@@ -272,24 +271,24 @@ class PrintRenderFrameHelper
int expected_pages_count,
bool is_scripted,
PrintMsg_PrintPages_Params* print_settings);
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
// Page Printing / Rendering ------------------------------------------------
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
void OnFramePreparedForPrintPages();
void PrintPages();
- bool PrintPagesNative(blink::WebLocalFrame* frame, int page_count);
+ bool PrintPagesNative(blink::WebLocalFrame* frame,
+ int page_count,
+ bool is_pdf);
void FinishFramePrinting();
// Render the frame for printing.
bool RenderPagesForPrint(blink::WebLocalFrame* frame,
const blink::WebNode& node);
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
// Platform-specific helper function for rendering page(s) to |metafile|.
void PrintPageInternal(const PrintMsg_Print_Params& params,
int page_number,
int page_count,
+ double scale_factor,
blink::WebLocalFrame* frame,
PdfMetafileSkia* metafile,
gfx::Size* page_size_in_dpi,
diff --git a/chromium/components/printing/renderer/print_render_frame_helper_linux.cc b/chromium/components/printing/renderer/print_render_frame_helper_linux.cc
index 9da5b9553c7..73050eb4402 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper_linux.cc
+++ b/chromium/components/printing/renderer/print_render_frame_helper_linux.cc
@@ -43,9 +43,9 @@ bool SaveToFD(const printing::Metafile& metafile,
namespace printing {
-#if BUILDFLAG(ENABLE_BASIC_PRINTING)
bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
- int page_count) {
+ int page_count,
+ bool is_pdf) {
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
const PrintMsg_Print_Params& print_params = params.params;
@@ -58,8 +58,9 @@ bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
CHECK(metafile.Init());
for (int page_number : printed_pages) {
- PrintPageInternal(print_params, page_number, page_count, frame, &metafile,
- nullptr, nullptr);
+ PrintPageInternal(print_params, page_number, page_count,
+ GetScaleFactor(print_params.scale_factor, is_pdf), frame,
+ &metafile, nullptr, nullptr);
}
// blink::printEnd() for PDF should be called before metafile is closed.
@@ -92,6 +93,5 @@ bool PrintRenderFrameHelper::PrintPagesNative(blink::WebLocalFrame* frame,
return true;
#endif // defined(OS_ANDROID)
}
-#endif // BUILDFLAG(ENABLE_BASIC_PRINTING)
} // namespace printing
diff --git a/chromium/components/printing/renderer/print_render_frame_helper_mac.mm b/chromium/components/printing/renderer/print_render_frame_helper_mac.mm
index 1d55557dc63..9e6eb4768aa 100644
--- a/chromium/components/printing/renderer/print_render_frame_helper_mac.mm
+++ b/chromium/components/printing/renderer/print_render_frame_helper_mac.mm
@@ -24,13 +24,12 @@ void PrintRenderFrameHelper::PrintPageInternal(
const PrintMsg_Print_Params& params,
int page_number,
int page_count,
+ double scale_factor,
blink::WebLocalFrame* frame,
PdfMetafileSkia* metafile,
gfx::Size* page_size_in_dpi,
gfx::Rect* content_rect_in_dpi) {
- double css_scale_factor =
- params.scale_factor >= kEpsilon ? params.scale_factor : 1.0f;
-
+ double css_scale_factor = scale_factor;
PageSizeMargins page_layout_in_points;
ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &css_scale_factor,
@@ -51,20 +50,20 @@ void PrintRenderFrameHelper::PrintPageInternal(
params.display_header_footer ? gfx::Rect(page_size) : content_area;
double webkit_page_shrink_factor = frame->GetPrintPageShrink(page_number);
- float scale_factor = css_scale_factor * webkit_page_shrink_factor;
+ float final_scale_factor = css_scale_factor * webkit_page_shrink_factor;
- cc::PaintCanvas* canvas =
- metafile->GetVectorCanvasForNewPage(page_size, canvas_area, scale_factor);
+ cc::PaintCanvas* canvas = metafile->GetVectorCanvasForNewPage(
+ page_size, canvas_area, final_scale_factor);
if (!canvas)
return;
MetafileSkiaWrapper::SetMetafileOnCanvas(canvas, metafile);
if (params.display_header_footer) {
PrintHeaderAndFooter(canvas, page_number + 1, page_count, *frame,
- scale_factor, page_layout_in_points, params);
+ final_scale_factor, page_layout_in_points, params);
}
- RenderPageContent(frame, page_number, canvas_area, content_area, scale_factor,
- canvas);
+ RenderPageContent(frame, page_number, canvas_area, content_area,
+ final_scale_factor, canvas);
// Done printing. Close the canvas to retrieve the compiled metafile.
bool ret = metafile->FinishPage();
diff --git a/chromium/components/printing/resources/print_preview_page.html b/chromium/components/printing/resources/print_header_footer_template_page.html
index e53c845afdf..e53c845afdf 100644
--- a/chromium/components/printing/resources/print_preview_page.html
+++ b/chromium/components/printing/resources/print_header_footer_template_page.html
diff --git a/chromium/components/printing/service/public/cpp/pdf_service_mojo_types.h b/chromium/components/printing/service/public/cpp/pdf_service_mojo_types.h
deleted file mode 100644
index 05828cd09c2..00000000000
--- a/chromium/components/printing/service/public/cpp/pdf_service_mojo_types.h
+++ /dev/null
@@ -1,17 +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 COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_TYPES_H_
-#define COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_TYPES_H_
-
-#include <unordered_map>
-
-namespace printing {
-
-// Create an alias for map<uint32, uint64> type.
-using ContentToFrameMap = std::unordered_map<uint32_t, uint64_t>;
-
-} // namespace printing
-
-#endif // COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_TYPES_H_
diff --git a/chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.h b/chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.h
deleted file mode 100644
index d7b5547ebdc..00000000000
--- a/chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
-#define COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
-
-#include <memory>
-
-#include "base/memory/scoped_refptr.h"
-#include "mojo/public/cpp/system/buffer.h"
-
-namespace base {
-class RefCountedMemory;
-class SharedMemory;
-} // namespace base
-
-namespace printing {
-
-std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
- mojo::ScopedSharedBufferHandle handle);
-
-scoped_refptr<base::RefCountedMemory> GetDataFromMojoHandle(
- mojo::ScopedSharedBufferHandle handle);
-
-} // namespace printing
-
-#endif // COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
diff --git a/chromium/components/printing_strings.grdp b/chromium/components/printing_component_strings.grdp
index f157cbaec42..f157cbaec42 100644
--- a/chromium/components/printing_strings.grdp
+++ b/chromium/components/printing_component_strings.grdp
diff --git a/chromium/components/printing_component_strings_grdp/OWNERS b/chromium/components/printing_component_strings_grdp/OWNERS
new file mode 100644
index 00000000000..21ccd7b227f
--- /dev/null
+++ b/chromium/components/printing_component_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/printing/OWNERS
diff --git a/chromium/components/printing_component_strings_grdp/README.md b/chromium/components/printing_component_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/printing_component_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/profile_metrics/counts.cc b/chromium/components/profile_metrics/counts.cc
index 364857a66e0..b7531fdc497 100644
--- a/chromium/components/profile_metrics/counts.cc
+++ b/chromium/components/profile_metrics/counts.cc
@@ -19,6 +19,7 @@ void LogProfileMetricsCounts(const Counts& counts) {
100 * counts.supervised / counts.total);
UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSignedInProfiles",
counts.signedin);
+ UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfActiveProfiles", counts.active);
UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfUnusedProfiles", counts.unused);
UMA_HISTOGRAM_COUNTS_100("Profile.NumberOfSignedInProfilesWithGAIAIcons",
counts.gaia_icon);
diff --git a/chromium/components/profile_metrics/counts.h b/chromium/components/profile_metrics/counts.h
index a02a9725a0f..ef5b8ccf8cb 100644
--- a/chromium/components/profile_metrics/counts.h
+++ b/chromium/components/profile_metrics/counts.h
@@ -13,6 +13,7 @@ struct Counts {
base::HistogramBase::Sample total;
base::HistogramBase::Sample signedin;
base::HistogramBase::Sample supervised;
+ base::HistogramBase::Sample active;
base::HistogramBase::Sample unused;
base::HistogramBase::Sample gaia_icon;
base::HistogramBase::Sample auth_errors;
@@ -21,6 +22,7 @@ struct Counts {
: total(0),
signedin(0),
supervised(0),
+ active(0),
unused(0),
gaia_icon(0),
auth_errors(0) {}
diff --git a/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc b/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
index aee58b46b27..547203147a9 100644
--- a/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
+++ b/chromium/components/proxy_config/pref_proxy_config_tracker_impl.cc
@@ -88,7 +88,7 @@ ProxyConfigServiceImpl::GetLatestProxyConfig(
net::ProxyConfigWithAnnotation system_config;
ConfigAvailability system_availability =
net::ProxyConfigService::CONFIG_UNSET;
- if (base_service_.get())
+ if (base_service_)
system_availability = base_service_->GetLatestProxyConfig(&system_config);
ProxyPrefs::ConfigState config_state;
@@ -98,7 +98,7 @@ ProxyConfigServiceImpl::GetLatestProxyConfig(
}
void ProxyConfigServiceImpl::OnLazyPoll() {
- if (base_service_.get())
+ if (base_service_)
base_service_->OnLazyPoll();
}
diff --git a/chromium/components/rappor/BUILD.gn b/chromium/components/rappor/BUILD.gn
index 763a05a14c2..8a0dfea10e7 100644
--- a/chromium/components/rappor/BUILD.gn
+++ b/chromium/components/rappor/BUILD.gn
@@ -43,6 +43,7 @@ static_library("rappor") {
"//components/variations",
"//crypto",
"//net",
+ "//services/network/public/cpp:cpp",
"//third_party/smhasher:cityhash",
]
}
@@ -104,6 +105,8 @@ source_set("unit_tests") {
"//components/metrics",
"//components/prefs:test_support",
"//net:test_support",
+ "//services/network:test_support",
+ "//services/network/public/cpp:cpp",
"//testing/gtest",
"//url",
]
diff --git a/chromium/components/rappor/DEPS b/chromium/components/rappor/DEPS
index dd4584652a0..96d1bd520d6 100644
--- a/chromium/components/rappor/DEPS
+++ b/chromium/components/rappor/DEPS
@@ -6,5 +6,6 @@ include_rules = [
"+crypto",
"+mojo/public/cpp",
"+net",
+ "+services/network",
"+third_party/smhasher",
]
diff --git a/chromium/components/rappor/log_uploader.cc b/chromium/components/rappor/log_uploader.cc
index f957858af53..cf6b7e9bb1f 100644
--- a/chromium/components/rappor/log_uploader.cc
+++ b/chromium/components/rappor/log_uploader.cc
@@ -14,7 +14,9 @@
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
namespace {
@@ -51,17 +53,17 @@ void RecordDiscardReason(DiscardReason reason) {
namespace rappor {
-LogUploader::LogUploader(const GURL& server_url,
- const std::string& mime_type,
- net::URLRequestContextGetter* request_context)
+LogUploader::LogUploader(
+ const GURL& server_url,
+ const std::string& mime_type,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: server_url_(server_url),
mime_type_(mime_type),
- request_context_(request_context),
+ url_loader_factory_(std::move(url_loader_factory)),
is_running_(false),
has_callback_pending_(false),
- upload_interval_(base::TimeDelta::FromSeconds(
- kUnsentLogsIntervalSeconds)) {
-}
+ upload_interval_(
+ base::TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds)) {}
LogUploader::~LogUploader() {}
@@ -140,18 +142,23 @@ void LogUploader::StartScheduledUpload() {
}
}
})");
- current_fetch_ = net::URLFetcher::Create(server_url_, net::URLFetcher::POST,
- this, traffic_annotation);
- data_use_measurement::DataUseUserData::AttachToFetcher(
- current_fetch_.get(), data_use_measurement::DataUseUserData::RAPPOR);
- current_fetch_->SetRequestContext(request_context_.get());
- current_fetch_->SetUploadData(mime_type_, queued_logs_.front());
+ auto resource_request = std::make_unique<network::ResourceRequest>();
+ resource_request->url = server_url_;
// We already drop cookies server-side, but we might as well strip them out
// client-side as well.
- current_fetch_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES |
- net::LOAD_DO_NOT_SEND_COOKIES);
- current_fetch_->Start();
+ resource_request->load_flags =
+ net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SEND_COOKIES;
+ resource_request->method = "POST";
+ simple_url_loader_ = network::SimpleURLLoader::Create(
+ std::move(resource_request), traffic_annotation);
+ simple_url_loader_->AttachStringForUpload(queued_logs_.front(), mime_type_);
+ // TODO re-add data use measurement once SimpleURLLoader supports it.
+ // ID=data_use_measurement::DataUseUserData::RAPPOR
+ simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ url_loader_factory_.get(),
+ base::BindOnce(&LogUploader::OnSimpleLoaderComplete,
+ base::Unretained(this)));
}
// static
@@ -165,31 +172,27 @@ base::TimeDelta LogUploader::BackOffUploadInterval(base::TimeDelta interval) {
return interval > max_interval ? max_interval : interval;
}
-void LogUploader::OnURLFetchComplete(const net::URLFetcher* source) {
- // We're not allowed to re-use the existing |URLFetcher|s, so free them here.
- // Note however that |source| is aliased to the fetcher, so we should be
- // careful not to delete it too early.
- DCHECK_EQ(current_fetch_.get(), source);
- std::unique_ptr<net::URLFetcher> fetch(std::move(current_fetch_));
-
- const net::URLRequestStatus& request_status = source->GetStatus();
-
- const int response_code = source->GetResponseCode();
+void LogUploader::OnSimpleLoaderComplete(
+ std::unique_ptr<std::string> response_body) {
+ int response_code = -1;
+ if (simple_url_loader_->ResponseInfo() &&
+ simple_url_loader_->ResponseInfo()->headers) {
+ response_code =
+ simple_url_loader_->ResponseInfo()->headers->response_code();
+ }
DVLOG(2) << "Upload fetch complete response code: " << response_code;
- if (request_status.status() != net::URLRequestStatus::SUCCESS) {
- base::UmaHistogramSparse("Rappor.FailedUploadErrorCode",
- -request_status.error());
- DVLOG(1) << "Rappor server upload failed with error: "
- << request_status.error() << ": "
- << net::ErrorToString(request_status.error());
- DCHECK_EQ(-1, response_code);
+ int net_error = simple_url_loader_->NetError();
+ if (net_error != net::OK && (response_code == -1 || response_code == 200)) {
+ base::UmaHistogramSparse("Rappor.FailedUploadErrorCode", -net_error);
+ DVLOG(1) << "Rappor server upload failed with error: " << net_error << ": "
+ << net::ErrorToString(net_error);
} else {
// Log a histogram to track response success vs. failure rates.
base::UmaHistogramSparse("Rappor.UploadResponseCode", response_code);
}
- const bool upload_succeeded = response_code == 200;
+ const bool upload_succeeded = !!response_body;
// Determine whether this log should be retransmitted.
DiscardReason reason = NUM_DISCARD_REASONS;
diff --git a/chromium/components/rappor/log_uploader.h b/chromium/components/rappor/log_uploader.h
index 06a0fc0764b..a44ce544ec0 100644
--- a/chromium/components/rappor/log_uploader.h
+++ b/chromium/components/rappor/log_uploader.h
@@ -11,16 +11,16 @@
#include "base/compiler_specific.h"
#include "base/containers/queue.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/rappor/log_uploader_interface.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h"
-namespace net {
-class URLFetcher;
-}
+namespace network {
+class SimpleURLLoader;
+class SharedURLLoaderFactory;
+} // namespace network
namespace rappor {
@@ -29,15 +29,15 @@ namespace rappor {
// at a fixed interval after the successful upload of the previous logs. If an
// upload fails, the uploader will keep retrying the upload with an exponential
// backoff interval.
-class LogUploader : public net::URLFetcherDelegate,
- public LogUploaderInterface {
+class LogUploader : public LogUploaderInterface {
public:
// Constructor takes the |server_url| that logs should be uploaded to, the
// |mime_type| of the uploaded data, and |request_context| to create uploads
// with.
- LogUploader(const GURL& server_url,
- const std::string& mime_type,
- net::URLRequestContextGetter* request_context);
+ LogUploader(
+ const GURL& server_url,
+ const std::string& mime_type,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
// If the object is destroyed (or the program terminates) while logs are
// queued, the logs are lost.
@@ -70,9 +70,8 @@ class LogUploader : public net::URLFetcherDelegate,
// Drops excess logs until we are under the size limit.
void DropExcessLogs();
- // Implements net::URLFetcherDelegate. Called after transmission completes
- // (whether successful or not).
- void OnURLFetchComplete(const net::URLFetcher* source) override;
+ // Called after transmission completes (whether successful or not).
+ void OnSimpleLoaderComplete(std::unique_ptr<std::string> response_body);
// Called when the upload is completed.
void OnUploadFinished(bool server_is_healthy);
@@ -83,14 +82,14 @@ class LogUploader : public net::URLFetcherDelegate,
// The mime type to specify on uploaded logs.
const std::string mime_type_;
- // The request context used to send uploads.
- scoped_refptr<net::URLRequestContextGetter> request_context_;
+ // The URL loader factory used to send uploads.
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
// True if the uploader is currently running.
bool is_running_;
- // The outstanding transmission that appears as a URL Fetch operation.
- std::unique_ptr<net::URLFetcher> current_fetch_;
+ // The outstanding transmission.
+ std::unique_ptr<network::SimpleURLLoader> simple_url_loader_;
// The logs that still need to be uploaded.
base::queue<std::string> queued_logs_;
diff --git a/chromium/components/rappor/log_uploader_unittest.cc b/chromium/components/rappor/log_uploader_unittest.cc
index 8d91e15661f..56c87cf9e1a 100644
--- a/chromium/components/rappor/log_uploader_unittest.cc
+++ b/chromium/components/rappor/log_uploader_unittest.cc
@@ -9,8 +9,12 @@
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace rappor {
@@ -22,8 +26,9 @@ const char kTestMimeType[] = "text/plain";
class TestLogUploader : public LogUploader {
public:
- explicit TestLogUploader(net::URLRequestContextGetter* request_context) :
- LogUploader(GURL(kTestServerURL), kTestMimeType, request_context) {
+ explicit TestLogUploader(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+ : LogUploader(GURL(kTestServerURL), kTestMimeType, url_loader_factory) {
Start();
}
@@ -63,27 +68,23 @@ class LogUploaderTest : public testing::Test {
LogUploaderTest()
: scoped_task_environment_(
base::test::ScopedTaskEnvironment::MainThreadType::UI),
- request_context_(new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get())),
- factory_(nullptr) {}
+ test_shared_loader_factory_(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+ &test_url_loader_factory_)) {}
protected:
// Required for base::ThreadTaskRunnerHandle::Get().
base::test::ScopedTaskEnvironment scoped_task_environment_;
- scoped_refptr<net::TestURLRequestContextGetter> request_context_;
- net::FakeURLFetcherFactory factory_;
+ network::TestURLLoaderFactory test_url_loader_factory_;
+ scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
private:
DISALLOW_COPY_AND_ASSIGN(LogUploaderTest);
};
TEST_F(LogUploaderTest, Success) {
- TestLogUploader uploader(request_context_.get());
-
- factory_.SetFakeResponse(GURL(kTestServerURL),
- std::string(),
- net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
+ TestLogUploader uploader(test_shared_loader_factory_);
+ test_url_loader_factory_.AddResponse(kTestServerURL, "");
uploader.QueueLog("log1");
base::RunLoop().RunUntilIdle();
@@ -92,12 +93,15 @@ TEST_F(LogUploaderTest, Success) {
}
TEST_F(LogUploaderTest, Rejection) {
- TestLogUploader uploader(request_context_.get());
+ TestLogUploader uploader(test_shared_loader_factory_);
- factory_.SetFakeResponse(GURL(kTestServerURL),
- std::string(),
- net::HTTP_BAD_REQUEST,
- net::URLRequestStatus::SUCCESS);
+ network::ResourceResponseHead response_head;
+ std::string headers("HTTP/1.1 400 Bad Request\nContent-type: text/html\n\n");
+ response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+ net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+ response_head.mime_type = "text/html";
+ test_url_loader_factory_.AddResponse(GURL(kTestServerURL), response_head, "",
+ network::URLLoaderCompletionStatus());
uploader.QueueLog("log1");
base::RunLoop().RunUntilIdle();
@@ -106,12 +110,16 @@ TEST_F(LogUploaderTest, Rejection) {
}
TEST_F(LogUploaderTest, Failure) {
- TestLogUploader uploader(request_context_.get());
+ TestLogUploader uploader(test_shared_loader_factory_);
- factory_.SetFakeResponse(GURL(kTestServerURL),
- std::string(),
- net::HTTP_INTERNAL_SERVER_ERROR,
- net::URLRequestStatus::SUCCESS);
+ network::ResourceResponseHead response_head;
+ std::string headers(
+ "HTTP/1.1 500 Internal Server Error\nContent-type: text/html\n\n");
+ response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+ net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size()));
+ response_head.mime_type = "text/html";
+ test_url_loader_factory_.AddResponse(GURL(kTestServerURL), response_head, "",
+ network::URLLoaderCompletionStatus());
uploader.QueueLog("log1");
base::RunLoop().RunUntilIdle();
@@ -129,10 +137,7 @@ TEST_F(LogUploaderTest, Failure) {
base::RunLoop().RunUntilIdle();
EXPECT_GT(uploader.last_interval_set(), error_interval);
- factory_.SetFakeResponse(GURL(kTestServerURL),
- std::string(),
- net::HTTP_OK,
- net::URLRequestStatus::SUCCESS);
+ test_url_loader_factory_.AddResponse(kTestServerURL, "");
// A success should revert to base interval while queue is not empty.
for (int i = 0; i < 9; i++) {
diff --git a/chromium/components/rappor/rappor_service_impl.cc b/chromium/components/rappor/rappor_service_impl.cc
index 7b4c68475be..976e0376276 100644
--- a/chromium/components/rappor/rappor_service_impl.cc
+++ b/chromium/components/rappor/rappor_service_impl.cc
@@ -16,6 +16,7 @@
#include "components/rappor/rappor_pref_names.h"
#include "components/rappor/rappor_prefs.h"
#include "components/variations/variations_associated_data.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace rappor {
@@ -54,7 +55,7 @@ void RapporServiceImpl::AddDailyObserver(
}
void RapporServiceImpl::Initialize(
- net::URLRequestContextGetter* request_context) {
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!IsInitialized());
const GURL server_url = GURL(kDefaultServerUrl);
@@ -65,7 +66,7 @@ void RapporServiceImpl::Initialize(
}
DVLOG(1) << "RapporServiceImpl reporting to " << server_url.spec();
InitializeInternal(
- std::make_unique<LogUploader>(server_url, kMimeType, request_context),
+ std::make_unique<LogUploader>(server_url, kMimeType, url_loader_factory),
internal::LoadCohort(pref_service_), internal::LoadSecret(pref_service_));
}
diff --git a/chromium/components/rappor/rappor_service_impl.h b/chromium/components/rappor/rappor_service_impl.h
index 540eb44a0d2..11c91f89f9d 100644
--- a/chromium/components/rappor/rappor_service_impl.h
+++ b/chromium/components/rappor/rappor_service_impl.h
@@ -13,6 +13,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "components/metrics/daily_event.h"
@@ -24,8 +25,8 @@
class PrefRegistrySimple;
class PrefService;
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
}
namespace rappor {
@@ -52,7 +53,8 @@ class RapporServiceImpl : public RapporService {
// Initializes the rappor service, including loading the cohort and secret
// preferences from disk.
- void Initialize(net::URLRequestContextGetter* context);
+ void Initialize(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
// Updates the settings for metric recording and uploading.
// The RapporServiceImpl must be initialized before this method is called.
diff --git a/chromium/components/reading_list/core/reading_list_store.cc b/chromium/components/reading_list/core/reading_list_store.cc
index 91a6666a440..e8fad377613 100644
--- a/chromium/components/reading_list/core/reading_list_store.cc
+++ b/chromium/components/reading_list/core/reading_list_store.cc
@@ -125,7 +125,7 @@ void ReadingListStore::OnDatabaseLoad(
auto loaded_entries =
std::make_unique<ReadingListStoreDelegate::ReadingListEntries>();
- for (const syncer::ModelTypeStore::Record& r : *entries.get()) {
+ for (const syncer::ModelTypeStore::Record& r : *entries) {
reading_list::ReadingListLocal proto;
if (!proto.ParseFromString(r.value)) {
continue;
@@ -156,7 +156,7 @@ void ReadingListStore::OnReadAllMetadata(
if (error) {
change_processor()->ReportError({FROM_HERE, "Failed to read metadata."});
} else {
- change_processor()->ModelReadyToSync(this, std::move(metadata_batch));
+ change_processor()->ModelReadyToSync(std::move(metadata_batch));
}
}
diff --git a/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc b/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc
index d9519705ff2..b5312c48c3a 100644
--- a/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc
+++ b/chromium/components/renderer_context_menu/views/toolkit_delegate_views.cc
@@ -35,7 +35,7 @@ void ToolkitDelegateViews::Init(ui::SimpleMenuModel* menu_model) {
}
void ToolkitDelegateViews::Cancel() {
- DCHECK(menu_runner_.get());
+ DCHECK(menu_runner_);
menu_runner_->Cancel();
}
diff --git a/chromium/components/renderer_context_menu/views/toolkit_delegate_views.h b/chromium/components/renderer_context_menu/views/toolkit_delegate_views.h
index 9ee4d0f86cd..eb3ef326b4c 100644
--- a/chromium/components/renderer_context_menu/views/toolkit_delegate_views.h
+++ b/chromium/components/renderer_context_menu/views/toolkit_delegate_views.h
@@ -35,9 +35,12 @@ class ToolkitDelegateViews : public RenderViewContextMenuBase::ToolkitDelegate {
const gfx::Point& point,
ui::MenuSourceType type);
- private:
+ protected:
// ToolkitDelegate:
void Init(ui::SimpleMenuModel* menu_model) override;
+
+ private:
+ // ToolkitDelegate:
void Cancel() override;
void UpdateMenuItem(int command_id,
bool enabled,
diff --git a/chromium/components/reset_password_strings.grdp b/chromium/components/reset_password_strings.grdp
index bd8b3bc83f2..00117ea39b7 100644
--- a/chromium/components/reset_password_strings.grdp
+++ b/chromium/components/reset_password_strings.grdp
@@ -1,12 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
- <message name="IDS_RESET_PASSWORD_WARNING_HEADING" desc="Title of the reset password page.">
+ <message name="IDS_RESET_PASSWORD_TITLE" desc="Title in the reset password page header.">
+ Reset Password
+ </message>
+ <message name="IDS_RESET_PASSWORD_WARNING_HEADING" desc="Heading of the reset password page.">
Reset your password now
</message>
- <message name="IDS_RESET_PASSWORD_HEADING" desc="Title of the reset password page when the user manually navigates to this page.">
+ <message name="IDS_RESET_PASSWORD_HEADING" desc="Heading of the reset password page when the user manually navigates to this page.">
Reset password?
</message>
<message name="IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH" desc="The primary explanatory paragraph for the reset password page.">
+ You entered your password on a site that’s not managed by your organization. To protect your account, don’t reuse your password on other apps and sites.
+ </message>
+ <message name="IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH_WITH_ORG_NAME" desc="The primary explanatory paragraph for the reset password page.">
You entered your password on a site that’s not managed by <ph name="ORG_NAME">$1<ex>Google</ex></ph>. To protect your account, don’t reuse your password on other apps and sites.
</message>
<message name="IDS_RESET_PASSWORD_BUTTON" desc="The text for the button that takes the user to reset their password.">
@@ -14,11 +20,17 @@
</message>
<if expr="_google_chrome">
<message name="IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH" desc="The primary explanatory paragraph for the reset password page when the user manually navigates to this page.">
+ Chrome recommends resetting your password if you reused it on other sites.
+ </message>
+ <message name="IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME" desc="The primary explanatory paragraph for the reset password page when the user manually navigates to this page.">
Chrome recommends resetting your <ph name="ORG_NAME">$1<ex>Google</ex></ph> password if you reused it on other sites.
</message>
</if>
<if expr="not _google_chrome">
- <message name="IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH" desc="The primary explanatory paragraph for the reset password page when the user manually navigates to this page.">
+ <message name="IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH" desc="The primary explanatory paragraph for the reset password page when the user manually navigates to this page.">
+ Chromium recommends resetting your password if you reused it on other sites.
+ </message>
+ <message name="IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME" desc="The primary explanatory paragraph for the reset password page when the user manually navigates to this page.">
Chromium recommends resetting your <ph name="ORG_NAME">$1<ex>Google</ex></ph> password if you reused it on other sites.
</message>
</if>
diff --git a/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH.png.sha1 b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH.png.sha1
new file mode 100644
index 00000000000..13c7f2577c9
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH.png.sha1
@@ -0,0 +1 @@
+fb5b509fe162ac6fe911bc4e9bf76470de47f980 \ No newline at end of file
diff --git a/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha1 b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha1
new file mode 100644
index 00000000000..13e6e80ebbf
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha1
@@ -0,0 +1 @@
+52a089d54f25559bdc5a7b6d4d39d66de1e171f9 \ No newline at end of file
diff --git a/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_HEADING.png.sha1 b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_HEADING.png.sha1
new file mode 100644
index 00000000000..f0b8b594f25
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_HEADING.png.sha1
@@ -0,0 +1 @@
+06eee4b9acf1ae18acc5bc5fce731397b5743a18 \ No newline at end of file
diff --git a/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH.png.sha1 b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH.png.sha1
new file mode 100644
index 00000000000..c2a6fdfdce0
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH.png.sha1
@@ -0,0 +1 @@
+1a1f39cae3232cc58acbb06b3ffbbc798e661bea \ No newline at end of file
diff --git a/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha1 b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha1
new file mode 100644
index 00000000000..8860f982603
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_EXPLANATION_PARAGRAPH_WITH_ORG_NAME.png.sha1
@@ -0,0 +1 @@
+a3703bd734cad0c2cb27fae9937103fe7564f74c \ No newline at end of file
diff --git a/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_HEADING.png.sha1 b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_HEADING.png.sha1
new file mode 100644
index 00000000000..779b7c1e4ad
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/IDS_RESET_PASSWORD_WARNING_HEADING.png.sha1
@@ -0,0 +1 @@
+c4d6a1a3b4ef562491505e5e1bed131197621343 \ No newline at end of file
diff --git a/chromium/components/reset_password_strings_grdp/OWNERS b/chromium/components/reset_password_strings_grdp/OWNERS
new file mode 100644
index 00000000000..5225674f443
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/safe_browsing/OWNERS
diff --git a/chromium/components/reset_password_strings_grdp/README.md b/chromium/components/reset_password_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/reset_password_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/resources/OWNERS b/chromium/components/resources/OWNERS
index 511b189b471..1bde68de71e 100644
--- a/chromium/components/resources/OWNERS
+++ b/chromium/components/resources/OWNERS
@@ -20,6 +20,7 @@ per-file neterror*=mmenke@chromium.org
per-file ntp_tiles_resources.grdp=file://components/ntp_tiles/OWNERS
per-file offline_pages_resources.grdp=file://components/offline_pages/OWNERS
per-file proximity_auth*=tengs@chromium.org
+per-file printing_resources.grdp=file://printing/OWNERS
per-file security_interstitials_resources.grdp=file://components/security_interstitials/OWNERS
per-file supervised_user_error_page_resources.grdp=file://components/supervised_user_error_page/OWNERS
per-file sync_driver_resources.grdp=file://components/sync/OWNERS
diff --git a/chromium/components/resources/autofill_scaled_resources.grdp b/chromium/components/resources/autofill_scaled_resources.grdp
index 43690fec126..97db3335d35 100644
--- a/chromium/components/resources/autofill_scaled_resources.grdp
+++ b/chromium/components/resources/autofill_scaled_resources.grdp
@@ -22,6 +22,7 @@
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_CREATE" file="autofill/cc-generic.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_HTTP_WARNING" file="autofill/cc-generic.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_HTTPS_INVALID_WARNING" file="autofill/cc-generic.png" />
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER" file="autofill/cc-generic.png" />
</if>
<structure type="chrome_scaled_image" name="IDR_CREDIT_CARD_CVC_HINT" file="autofill/credit_card_cvc_hint.png" />
@@ -30,6 +31,7 @@
<structure type="chrome_scaled_image" name="IDR_INFOBAR_AUTOFILL_CC" file="autofill/infobar_autofill_cc.png" />
</if>
<if expr="is_ios">
+ <structure type="chrome_scaled_image" name="IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER" file="autofill/infobar_autofill_googlepay_with_divider.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON" file="autofill/autofill_tooltip_icon.png" />
<structure type="chrome_scaled_image" name="IDR_AUTOFILL_TOOLTIP_ICON_H" file="autofill/autofill_tooltip_icon_hover.png" />
</if>
diff --git a/chromium/components/resources/components_resources.grd b/chromium/components/resources/components_resources.grd
index a9741749e73..4623e36e0d2 100644
--- a/chromium/components/resources/components_resources.grd
+++ b/chromium/components/resources/components_resources.grd
@@ -18,7 +18,6 @@
<part file="ntp_tiles_resources.grdp" />
<part file="offline_pages_resources.grdp" />
<part file="password_manager_internals_resources.grdp" />
- <part file="physical_web_ui_resources.grdp" />
<part file="printing_resources.grdp" />
<part file="safe_browsing_resources.grdp" />
<part file="security_interstitials_resources.grdp" />
diff --git a/chromium/components/resources/default_100_percent/autofill/cc-generic.png b/chromium/components/resources/default_100_percent/autofill/cc-generic.png
index 43d77c214bb..68ceaf6c865 100644
--- a/chromium/components/resources/default_100_percent/autofill/cc-generic.png
+++ b/chromium/components/resources/default_100_percent/autofill/cc-generic.png
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/autofill/infobar_autofill_cc.png b/chromium/components/resources/default_100_percent/autofill/infobar_autofill_cc.png
index e0f8fc80484..b73362709f6 100644
--- a/chromium/components/resources/default_100_percent/autofill/infobar_autofill_cc.png
+++ b/chromium/components/resources/default_100_percent/autofill/infobar_autofill_cc.png
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/autofill/infobar_autofill_googlepay_with_divider.png b/chromium/components/resources/default_100_percent/autofill/infobar_autofill_googlepay_with_divider.png
new file mode 100644
index 00000000000..3aed9daf64d
--- /dev/null
+++ b/chromium/components/resources/default_100_percent/autofill/infobar_autofill_googlepay_with_divider.png
Binary files differ
diff --git a/chromium/components/resources/default_100_percent/crash/favicon_sad_tab.png b/chromium/components/resources/default_100_percent/crash/favicon_sad_tab.png
index 38e510076ec..9781cd1af39 100644
--- a/chromium/components/resources/default_100_percent/crash/favicon_sad_tab.png
+++ b/chromium/components/resources/default_100_percent/crash/favicon_sad_tab.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/autofill/cc-generic.png b/chromium/components/resources/default_200_percent/autofill/cc-generic.png
index 559aa2864c1..5eab89ee498 100644
--- a/chromium/components/resources/default_200_percent/autofill/cc-generic.png
+++ b/chromium/components/resources/default_200_percent/autofill/cc-generic.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/autofill/infobar_autofill_cc.png b/chromium/components/resources/default_200_percent/autofill/infobar_autofill_cc.png
index 49cffc62537..6cdb9ce685c 100644
--- a/chromium/components/resources/default_200_percent/autofill/infobar_autofill_cc.png
+++ b/chromium/components/resources/default_200_percent/autofill/infobar_autofill_cc.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/autofill/infobar_autofill_googlepay_with_divider.png b/chromium/components/resources/default_200_percent/autofill/infobar_autofill_googlepay_with_divider.png
new file mode 100644
index 00000000000..067ceee61ab
--- /dev/null
+++ b/chromium/components/resources/default_200_percent/autofill/infobar_autofill_googlepay_with_divider.png
Binary files differ
diff --git a/chromium/components/resources/default_200_percent/crash/favicon_sad_tab.png b/chromium/components/resources/default_200_percent/crash/favicon_sad_tab.png
index 6dd619d2208..551d3c10601 100644
--- a/chromium/components/resources/default_200_percent/crash/favicon_sad_tab.png
+++ b/chromium/components/resources/default_200_percent/crash/favicon_sad_tab.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/cc-generic.png b/chromium/components/resources/default_300_percent/autofill/cc-generic.png
index 5827ec26ee8..8861bbc0d91 100644
--- a/chromium/components/resources/default_300_percent/autofill/cc-generic.png
+++ b/chromium/components/resources/default_300_percent/autofill/cc-generic.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/infobar_autofill_cc.png b/chromium/components/resources/default_300_percent/autofill/infobar_autofill_cc.png
new file mode 100644
index 00000000000..870022b318e
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/infobar_autofill_cc.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/autofill/infobar_autofill_googlepay_with_divider.png b/chromium/components/resources/default_300_percent/autofill/infobar_autofill_googlepay_with_divider.png
new file mode 100644
index 00000000000..4f6c9eb6924
--- /dev/null
+++ b/chromium/components/resources/default_300_percent/autofill/infobar_autofill_googlepay_with_divider.png
Binary files differ
diff --git a/chromium/components/resources/default_300_percent/crash/favicon_sad_tab.png b/chromium/components/resources/default_300_percent/crash/favicon_sad_tab.png
index 8ca9ee8afa7..4d054f2d354 100644
--- a/chromium/components/resources/default_300_percent/crash/favicon_sad_tab.png
+++ b/chromium/components/resources/default_300_percent/crash/favicon_sad_tab.png
Binary files differ
diff --git a/chromium/components/resources/physical_web_ui_resources.grdp b/chromium/components/resources/physical_web_ui_resources.grdp
deleted file mode 100644
index ba5e4cc1be3..00000000000
--- a/chromium/components/resources/physical_web_ui_resources.grdp
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<grit-part>
- <if expr="is_android or is_ios">
- <include name="IDR_PHYSICAL_WEB_UI_HTML" file="../physical_web/webui/resources/physical_web.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
- <include name="IDR_PHYSICAL_WEB_UI_JS" file="../physical_web/webui/resources/physical_web.js" type="BINDATA" compress="gzip" />
- <include name="IDR_PHYSICAL_WEB_UI_CSS" file="../physical_web/webui/resources/physical_web.css" type="BINDATA" compress="gzip" />
- <include name="IDR_PHYSICAL_WEB_UI_LINK_ICON" file="../physical_web/resources/ic_link_grey600_36dp.png" type="BINDATA" compress="gzip" />
- </if>
-</grit-part>
diff --git a/chromium/components/resources/printing_resources.grdp b/chromium/components/resources/printing_resources.grdp
index 26e300c0496..27a993ee20b 100644
--- a/chromium/components/resources/printing_resources.grdp
+++ b/chromium/components/resources/printing_resources.grdp
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
- <if expr="enable_basic_printing or enable_print_preview">
- <include name="IDR_PRINT_PREVIEW_PAGE" file="../printing/resources/print_preview_page.html" flattenhtml="true" allowexternalscript="false" type="BINDATA" />
+ <if expr="enable_basic_printing">
+ <include name="IDR_PRINT_HEADER_FOOTER_TEMPLATE_PAGE" file="../printing/resources/print_header_footer_template_page.html" flattenhtml="true" allowexternalscript="false" type="BINDATA" />
</if>
</grit-part>
diff --git a/chromium/components/safe_browsing/DEPS b/chromium/components/safe_browsing/DEPS
index 3e4ec38aa94..8b4e3a64490 100644
--- a/chromium/components/safe_browsing/DEPS
+++ b/chromium/components/safe_browsing/DEPS
@@ -7,6 +7,7 @@ include_rules = [
"+google_apis",
"+mojo/public/cpp",
"+net/base",
+ "+net/net_buildflags.h",
"+net/http",
"+net/log",
"+net/traffic_annotation",
diff --git a/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
index 2d798650d2c..e18eaa415f3 100644
--- a/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
+++ b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.cc
@@ -10,14 +10,8 @@
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
-#include "base/bind.h"
-#include "base/bind_helpers.h"
#include "base/containers/flat_set.h"
-#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
-#include "base/task_scheduler/post_task.h"
-#include "base/task_scheduler/task_traits.h"
-#include "base/threading/scoped_blocking_call.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/trace_event/trace_event.h"
@@ -152,62 +146,13 @@ void JNI_SafeBrowsingApiBridge_OnUrlCheckDone(
//
// SafeBrowsingApiHandlerBridge
//
-SafeBrowsingApiHandlerBridge::SafeBrowsingApiHandlerBridge() {}
+SafeBrowsingApiHandlerBridge::SafeBrowsingApiHandlerBridge()
+ : checked_api_support_(false) {}
-SafeBrowsingApiHandlerBridge::~SafeBrowsingApiHandlerBridge() {
- if (api_task_runner_)
- api_task_runner_->DeleteSoon(FROM_HERE, core_.release());
-}
+SafeBrowsingApiHandlerBridge::~SafeBrowsingApiHandlerBridge() {}
-void SafeBrowsingApiHandlerBridge::Initialize() {
- DCHECK(!core_);
- core_ = std::make_unique<Core>();
- if (base::FeatureList::IsEnabled(kDispatchSafetyNetCheckOffThread)) {
- api_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
- }
-}
-
-void SafeBrowsingApiHandlerBridge::StartURLCheck(
- std::unique_ptr<SafeBrowsingApiHandler::URLCheckCallbackMeta> callback,
- const GURL& url,
- const SBThreatTypeSet& threat_types) {
+bool SafeBrowsingApiHandlerBridge::CheckApiIsSupported() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- // Initialize on the first URL check, when the feature list API is ready to be
- // used.
- if (!core_)
- Initialize();
-
- // Note: it turns out in practice that dispatching the IPC to Google Play
- // Services can be quite expensive in terms of wall time, often due to thread
- // descheduling. Since this task runs in an extremely performance critical
- // place (it blocks navigation and subresource requests), dispatch it on a
- // worker thread. In high percentiles it seems like the dispatching can take
- // >100ms, so use base::MayBlock even though we aren't technically doing
- // blocking IO.
- if (!api_task_runner_) {
- core_->StartURLCheck(std::move(callback), url, threat_types);
- return;
- }
- // Unretained is safe because the task to delete |core_| will be sequenced
- // after any task posted here.
- api_task_runner_->PostTask(
- FROM_HERE,
- base::BindOnce(&SafeBrowsingApiHandlerBridge::Core::StartURLCheck,
- base::Unretained(core_.get()), std::move(callback), url,
- threat_types));
-}
-
-SafeBrowsingApiHandlerBridge::Core::Core() {
- // The sequence checker is constructed on a different sequence from where it
- // is used.
- DETACH_FROM_SEQUENCE(sequence_checker_);
-}
-
-SafeBrowsingApiHandlerBridge::Core::~Core() = default;
-
-bool SafeBrowsingApiHandlerBridge::Core::CheckApiIsSupported() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!checked_api_support_) {
DVLOG(1) << "Checking API support.";
j_api_handler_ = base::android::ScopedJavaGlobalRef<jobject>(
@@ -217,13 +162,10 @@ bool SafeBrowsingApiHandlerBridge::Core::CheckApiIsSupported() {
return j_api_handler_.obj() != nullptr;
}
-void SafeBrowsingApiHandlerBridge::Core::StartURLCheck(
- std::unique_ptr<URLCheckCallbackMeta> callback,
+void SafeBrowsingApiHandlerBridge::StartURLCheck(
+ std::unique_ptr<SafeBrowsingApiHandler::URLCheckCallbackMeta> callback,
const GURL& url,
const SBThreatTypeSet& threat_types) {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- TRACE_EVENT0("safe_browsing",
- "SafeBrowsingApiHandlerBridge::StartURLCheckAsync");
if (!CheckApiIsSupported()) {
// Mark all requests as safe. Only users who have an old, broken GMSCore or
// have sideloaded Chrome w/o PlayStore should land here.
@@ -237,7 +179,6 @@ void SafeBrowsingApiHandlerBridge::Core::StartURLCheck(
// releases ownership, we will re-own this callback when the response is
// received in JNI_SafeBrowsingApiBridge_OnUrlCheckDone.
intptr_t callback_id = reinterpret_cast<intptr_t>(callback.release());
-
DVLOG(1) << "Starting check " << callback_id << " for URL " << url;
DCHECK(!threat_types.empty());
@@ -247,13 +188,13 @@ void SafeBrowsingApiHandlerBridge::Core::StartURLCheck(
ScopedJavaLocalRef<jintArray> j_threat_types =
SBThreatTypeSetToJavaArray(env, threat_types);
- // Increase parallelism by indicating that the lookup may block. Only the long
- // tail of these calls block for more than 10ms, which is the current
- // threshold for increasing worker capacity.
- base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
base::ElapsedTimer check_timer;
Java_SafeBrowsingApiBridge_startUriLookup(env, j_api_handler_, callback_id,
j_url, j_threat_types);
+ // TODO(vakh): The following metric isn't very useful now since the
+ // |startUriLookup| method simply posts a task and adds listeners now.
+ // Continue to monitor it to ensure that it keeps falling and then remove it
+ // when it is consistently a low value. (https://crbug.com/839190)
UMA_HISTOGRAM_COUNTS_10M("SB2.RemoteCall.CheckDispatchTime",
check_timer.Elapsed().InMicroseconds());
}
diff --git a/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
index 8794fea9811..4ccf0721f5e 100644
--- a/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
+++ b/chromium/components/safe_browsing/android/safe_browsing_api_handler_bridge.h
@@ -9,15 +9,11 @@
#include <jni.h>
-#include <memory>
#include <string>
#include <vector>
#include "base/android/jni_android.h"
#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/sequence_checker.h"
-#include "base/sequenced_task_runner.h"
#include "components/safe_browsing/android/safe_browsing_api_handler.h"
#include "components/safe_browsing/db/v4_protocol_manager_util.h"
#include "url/gurl.h"
@@ -34,42 +30,15 @@ class SafeBrowsingApiHandlerBridge : public SafeBrowsingApiHandler {
const SBThreatTypeSet& threat_types) override;
private:
- void Initialize();
+ // Creates the |j_api_handler_| if it hasn't been already. If the API is not
+ // supported, this will return false and j_api_handler_ will remain nullptr.
+ bool CheckApiIsSupported();
- // Responsible for calling into Java from a separate sequence than the
- // SafeBrowsingApiHandlerBridge.
- class Core {
- public:
- Core();
- ~Core();
+ // The Java-side SafeBrowsingApiHandler. Must call CheckApiIsSupported first.
+ base::android::ScopedJavaGlobalRef<jobject> j_api_handler_;
- void StartURLCheck(std::unique_ptr<URLCheckCallbackMeta> callback,
- const GURL& url,
- const SBThreatTypeSet& threat_types);
-
- private:
- // Creates the j_api_handler_ if it hasn't been already. If the API is not
- // supported, this will return false and j_api_handler_ will remain NULL.
- bool CheckApiIsSupported();
-
- // The Java-side SafeBrowsingApiHandler. Must call CheckApiIsSupported
- // first.
- base::android::ScopedJavaGlobalRef<jobject> j_api_handler_;
-
- // True if we've once tried to create the above object.
- bool checked_api_support_ = false;
-
- SEQUENCE_CHECKER(sequence_checker_);
- DISALLOW_COPY_AND_ASSIGN(Core);
- };
-
- // nullptr if |this| and |core_| should live on the same sequence. Otherwise
- // it will be the sequence that |core_| lives on.
- scoped_refptr<base::SequencedTaskRunner> api_task_runner_;
-
- // Lives on |api_task_runner_|, unless DispatchSafetyNetCheckOffThread is
- // disabled.
- std::unique_ptr<Core> core_;
+ // True if we've once tried to create the above object.
+ bool checked_api_support_;
DISALLOW_COPY_AND_ASSIGN(SafeBrowsingApiHandlerBridge);
};
diff --git a/chromium/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc b/chromium/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc
index d0a28411b60..df742bcc58b 100644
--- a/chromium/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc
+++ b/chromium/components/safe_browsing/browser/base_parallel_resource_throttle_unittest.cc
@@ -126,6 +126,9 @@ class TestUrlCheckerDelegate : public UrlCheckerDelegate {
return false;
}
+ void NotifySuspiciousSiteDetected(
+ const base::RepeatingCallback<content::WebContents*()>&
+ web_contents_getter) override {}
const SBThreatTypeSet& GetThreatTypes() override { return threat_types_; }
SafeBrowsingDatabaseManager* GetDatabaseManager() override {
return database_manager_.get();
diff --git a/chromium/components/safe_browsing/browser/referrer_chain_provider.h b/chromium/components/safe_browsing/browser/referrer_chain_provider.h
new file mode 100644
index 00000000000..66b9476f18f
--- /dev/null
+++ b/chromium/components/safe_browsing/browser/referrer_chain_provider.h
@@ -0,0 +1,39 @@
+// 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 COMPONENTS_SAFE_BROWSING_BROWSER_REFERRER_CHAIN_PROVIDER_H_
+#define COMPONENTS_SAFE_BROWSING_BROWSER_REFERRER_CHAIN_PROVIDER_H_
+
+#include "components/safe_browsing/proto/csd.pb.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace safe_browsing {
+using ReferrerChain =
+ google::protobuf::RepeatedPtrField<safe_browsing::ReferrerChainEntry>;
+
+class ReferrerChainProvider {
+ public:
+ // For UMA histogram counting. Do NOT change order.
+ enum AttributionResult {
+ SUCCESS = 1, // Identified referrer chain is not empty.
+ SUCCESS_LANDING_PAGE = 2, // Successfully identified landing page.
+ SUCCESS_LANDING_REFERRER = 3, // Successfully identified landing referrer.
+ INVALID_URL = 4,
+ NAVIGATION_EVENT_NOT_FOUND = 5,
+
+ // Always at the end.
+ ATTRIBUTION_FAILURE_TYPE_MAX
+ };
+
+ virtual AttributionResult IdentifyReferrerChainByWebContents(
+ content::WebContents* web_contents,
+ int user_gesture_count_limit,
+ ReferrerChain* out_referrer_chain) = 0;
+};
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_BROWSER_REFERRER_CHAIN_PROVIDER_H_ \ No newline at end of file
diff --git a/chromium/components/safe_browsing/browser/safe_browsing_network_context.cc b/chromium/components/safe_browsing/browser/safe_browsing_network_context.cc
index de778823075..1dcc1cd5ea0 100644
--- a/chromium/components/safe_browsing/browser/safe_browsing_network_context.cc
+++ b/chromium/components/safe_browsing/browser/safe_browsing_network_context.cc
@@ -4,9 +4,17 @@
#include "components/safe_browsing/browser/safe_browsing_network_context.h"
+#include <memory>
+#include <utility>
+
#include "base/bind.h"
+#include "components/safe_browsing/common/safebrowsing_constants.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/network_service_instance.h"
+#include "net/net_buildflags.h"
+#include "net/url_request/url_request_context_getter.h"
#include "services/network/network_context.h"
+#include "services/network/public/cpp/features.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
namespace safe_browsing {
@@ -14,9 +22,14 @@ namespace safe_browsing {
class SafeBrowsingNetworkContext::SharedURLLoaderFactory
: public network::SharedURLLoaderFactory {
public:
- explicit SharedURLLoaderFactory(
- scoped_refptr<net::URLRequestContextGetter> request_context_getter)
- : request_context_getter_(request_context_getter) {}
+ SharedURLLoaderFactory(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ const base::FilePath& user_data_dir,
+ NetworkContextParamsFactory network_context_params_factory)
+ : request_context_getter_(request_context_getter),
+ user_data_dir_(user_data_dir),
+ network_context_params_factory_(
+ std::move(network_context_params_factory)) {}
void Reset() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -32,21 +45,27 @@ class SafeBrowsingNetworkContext::SharedURLLoaderFactory
network::mojom::NetworkContext* GetNetworkContext() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (!network_context_) {
- internal_state_ = base::MakeRefCounted<InternalState>();
- internal_state_->Initialize(request_context_getter_,
- MakeRequest(&network_context_));
+ if (!network_context_ || network_context_.encountered_error()) {
+ if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ content::GetNetworkService()->CreateNetworkContext(
+ MakeRequest(&network_context_), CreateNetworkContextParams());
+ } else {
+ internal_state_ = base::MakeRefCounted<InternalState>();
+ internal_state_->Initialize(request_context_getter_,
+ MakeRequest(&network_context_));
+ }
}
return network_context_.get();
}
- protected:
- // network::SharedURLLoaderFactory implementation:
- std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override {
- NOTREACHED();
- return nullptr;
+ void FlushForTesting() {
+ if (network_context_)
+ network_context_.FlushForTesting();
+ if (url_loader_factory_)
+ url_loader_factory_.FlushForTesting();
}
+ protected:
// network::URLLoaderFactory implementation:
void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
int32_t routing_id,
@@ -62,11 +81,25 @@ class SafeBrowsingNetworkContext::SharedURLLoaderFactory
std::move(client), traffic_annotation);
}
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+ GetURLLoaderFactory()->Clone(std::move(request));
+ }
+
+ // network::SharedURLLoaderFactory implementation:
+ std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override {
+ NOTREACHED();
+ return nullptr;
+ }
+
network::mojom::URLLoaderFactory* GetURLLoaderFactory() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (!url_loader_factory_) {
+ if (!url_loader_factory_ || url_loader_factory_.encountered_error()) {
+ network::mojom::URLLoaderFactoryParamsPtr params =
+ network::mojom::URLLoaderFactoryParams::New();
+ params->process_id = network::mojom::kBrowserProcessId;
+ params->is_corb_enabled = false;
GetNetworkContext()->CreateURLLoaderFactory(
- MakeRequest(&url_loader_factory_), 0);
+ MakeRequest(&url_loader_factory_), std::move(params));
}
return url_loader_factory_.get();
}
@@ -89,6 +122,7 @@ class SafeBrowsingNetworkContext::SharedURLLoaderFactory
void Reset() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
network_context_impl_.reset();
+ request_context_getter_ = nullptr;
}
private:
@@ -98,10 +132,13 @@ class SafeBrowsingNetworkContext::SharedURLLoaderFactory
void InitOnIO(
scoped_refptr<net::URLRequestContextGetter> request_context_getter,
network::mojom::NetworkContextRequest network_context_request) {
+ request_context_getter_ = std::move(request_context_getter);
network_context_impl_ = std::make_unique<network::NetworkContext>(
- nullptr, std::move(network_context_request), request_context_getter);
+ content::GetNetworkServiceImpl(), std::move(network_context_request),
+ request_context_getter_->GetURLRequestContext());
}
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
std::unique_ptr<network::NetworkContext> network_context_impl_;
DISALLOW_COPY_AND_ASSIGN(InternalState);
@@ -110,7 +147,36 @@ class SafeBrowsingNetworkContext::SharedURLLoaderFactory
friend class base::RefCounted<SharedURLLoaderFactory>;
~SharedURLLoaderFactory() override = default;
+ network::mojom::NetworkContextParamsPtr CreateNetworkContextParams() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ network::mojom::NetworkContextParamsPtr network_context_params =
+ network_context_params_factory_.Run();
+
+ network_context_params->context_name = std::string("safe_browsing");
+
+ network_context_params->http_cache_enabled = false;
+
+ // These are needed for PAC scripts that use file, data or FTP URLs.
+ network_context_params->enable_data_url_support = true;
+ network_context_params->enable_file_url_support = true;
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ network_context_params->enable_ftp_url_support = true;
+#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+
+ base::FilePath cookie_path = user_data_dir_.Append(
+ base::FilePath::StringType(kSafeBrowsingBaseFilename) + kCookiesFile);
+ network_context_params->cookie_path = cookie_path;
+
+ base::FilePath channel_id_path = user_data_dir_.Append(
+ base::FilePath::StringType(kSafeBrowsingBaseFilename) + kChannelIDFile);
+ network_context_params->channel_id_path = channel_id_path;
+
+ return network_context_params;
+ }
+
scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+ base::FilePath user_data_dir_;
+ NetworkContextParamsFactory network_context_params_factory_;
network::mojom::NetworkContextPtr network_context_;
network::mojom::URLLoaderFactoryPtr url_loader_factory_;
scoped_refptr<InternalState> internal_state_;
@@ -119,10 +185,13 @@ class SafeBrowsingNetworkContext::SharedURLLoaderFactory
};
SafeBrowsingNetworkContext::SafeBrowsingNetworkContext(
- scoped_refptr<net::URLRequestContextGetter> request_context_getter) {
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ const base::FilePath& user_data_dir,
+ NetworkContextParamsFactory network_context_params_factory) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- url_loader_factory_ =
- base::MakeRefCounted<SharedURLLoaderFactory>(request_context_getter);
+ url_loader_factory_ = base::MakeRefCounted<SharedURLLoaderFactory>(
+ request_context_getter, user_data_dir,
+ std::move(network_context_params_factory));
}
SafeBrowsingNetworkContext::~SafeBrowsingNetworkContext() {
@@ -141,6 +210,11 @@ SafeBrowsingNetworkContext::GetNetworkContext() {
return url_loader_factory_->GetNetworkContext();
}
+void SafeBrowsingNetworkContext::FlushForTesting() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ url_loader_factory_->FlushForTesting();
+}
+
void SafeBrowsingNetworkContext::ServiceShuttingDown() {
url_loader_factory_->Reset();
}
diff --git a/chromium/components/safe_browsing/browser/safe_browsing_network_context.h b/chromium/components/safe_browsing/browser/safe_browsing_network_context.h
index d558ef10725..8d8bbee26e1 100644
--- a/chromium/components/safe_browsing/browser/safe_browsing_network_context.h
+++ b/chromium/components/safe_browsing/browser/safe_browsing_network_context.h
@@ -5,8 +5,11 @@
#ifndef COMPONENTS_SAFE_BROWSING_BROWSER_SAFE_BROWSING_NETWORK_CONTEXT_H_
#define COMPONENTS_SAFE_BROWSING_BROWSER_SAFE_BROWSING_NETWORK_CONTEXT_H_
+#include "base/callback.h"
+#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/network_service.mojom.h"
namespace net {
class URLRequestContextGetter;
@@ -29,8 +32,15 @@ namespace safe_browsing {
// create the NetworkContext directly. http://crbug.com/825242
class SafeBrowsingNetworkContext {
public:
- explicit SafeBrowsingNetworkContext(
- scoped_refptr<net::URLRequestContextGetter> request_context_getter);
+ // |request_context_getter| is used only if network service is disabled.
+ // Otherwise |user_dtaa_dir| and |network_context_params_factory| are used
+ // to construct a URLRequestContext through the network service.
+ using NetworkContextParamsFactory =
+ base::RepeatingCallback<network::mojom::NetworkContextParamsPtr()>;
+ SafeBrowsingNetworkContext(
+ scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+ const base::FilePath& user_data_dir,
+ NetworkContextParamsFactory network_context_params_factory);
~SafeBrowsingNetworkContext();
// Returns a SharedURLLoaderFactory.
@@ -39,6 +49,9 @@ class SafeBrowsingNetworkContext {
// Returns a NetworkContext.
network::mojom::NetworkContext* GetNetworkContext();
+ // Flushes NetworkContext and URLLoaderFactory pipes.
+ void FlushForTesting();
+
// Called at shutdown to ensure that the URLRequestContextGetter reference is
// destroyed..
void ServiceShuttingDown();
diff --git a/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc b/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
index e6c49ac5768..f857f3658af 100644
--- a/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
+++ b/chromium/components/safe_browsing/browser/safe_browsing_url_checker_impl.cc
@@ -134,9 +134,14 @@ void SafeBrowsingUrlCheckerImpl::OnCheckBrowseUrlResult(
"safe_browsing", "CheckUrl", this, "result",
threat_type == SB_THREAT_TYPE_SAFE ? "safe" : "unsafe");
- if (threat_type == SB_THREAT_TYPE_SAFE) {
+ if (threat_type == SB_THREAT_TYPE_SAFE ||
+ threat_type == SB_THREAT_TYPE_SUSPICIOUS_SITE) {
state_ = STATE_NONE;
+ if (threat_type == SB_THREAT_TYPE_SUSPICIOUS_SITE) {
+ url_checker_delegate_->NotifySuspiciousSiteDetected(web_contents_getter_);
+ }
+
if (!RunNextCallback(true, false))
return;
diff --git a/chromium/components/safe_browsing/browser/threat_details.cc b/chromium/components/safe_browsing/browser/threat_details.cc
index bf3fc8dafb2..7842af3eee8 100644
--- a/chromium/components/safe_browsing/browser/threat_details.cc
+++ b/chromium/components/safe_browsing/browser/threat_details.cc
@@ -18,6 +18,7 @@
#include "base/strings/string_util.h"
#include "components/history/core/browser/history_service.h"
#include "components/safe_browsing/base_ui_manager.h"
+#include "components/safe_browsing/browser/referrer_chain_provider.h"
#include "components/safe_browsing/browser/threat_details_cache.h"
#include "components/safe_browsing/browser/threat_details_history.h"
#include "components/safe_browsing/db/hit_report.h"
@@ -51,6 +52,9 @@ namespace {
// An element ID indicating that an HTML Element has no parent.
const int kElementIdNoParent = -1;
+// The number of user gestures to trace back for the referrer chain.
+const int kThreatDetailsUserGestureLimit = 2;
+
typedef std::unordered_set<std::string> StringSet;
// A set of HTTPS headers that are allowed to be collected. Contains both
// request and response headers. All entries in this list should be lower-case
@@ -272,11 +276,13 @@ class ThreatDetailsFactoryImpl : public ThreatDetailsFactory {
const security_interstitials::UnsafeResource& unsafe_resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) override {
return new ThreatDetails(ui_manager, web_contents, unsafe_resource,
url_loader_factory, history_service,
- trim_to_ad_tags, done_callback);
+ referrer_chain_provider, trim_to_ad_tags,
+ done_callback);
}
private:
@@ -298,15 +304,16 @@ ThreatDetails* ThreatDetails::NewThreatDetails(
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) {
// Set up the factory if this has not been done already (tests do that
// before this method is called).
if (!factory_)
factory_ = g_threat_details_factory_impl.Pointer();
- return factory_->CreateThreatDetails(ui_manager, web_contents, resource,
- url_loader_factory, history_service,
- trim_to_ad_tags, done_callback);
+ return factory_->CreateThreatDetails(
+ ui_manager, web_contents, resource, url_loader_factory, history_service,
+ referrer_chain_provider, trim_to_ad_tags, done_callback);
}
// Create a ThreatDetails for the given tab. Runs in the UI thread.
@@ -316,12 +323,14 @@ ThreatDetails::ThreatDetails(
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback)
: content::WebContentsObserver(web_contents),
url_loader_factory_(url_loader_factory),
ui_manager_(ui_manager),
resource_(resource),
+ referrer_chain_provider_(referrer_chain_provider),
cache_result_(false),
did_proceed_(false),
num_visits_(0),
@@ -675,10 +684,6 @@ void ThreatDetails::FinishCollection(bool did_proceed, int num_visit) {
}
}
- if (trim_to_ad_tags_) {
- TrimElements(trimmed_dom_element_ids_, &elements_, &resources_);
- }
-
did_proceed_ = did_proceed;
num_visits_ = num_visit;
std::vector<GURL> urls;
@@ -713,6 +718,18 @@ void ThreatDetails::AddRedirectUrlList(const std::vector<GURL>& urls) {
void ThreatDetails::OnCacheCollectionReady() {
DVLOG(1) << "OnCacheCollectionReady.";
+
+ // All URLs have been collected, trim the report if necessary.
+ if (trim_to_ad_tags_) {
+ TrimElements(trimmed_dom_element_ids_, &elements_, &resources_);
+ // If trimming the report removed all the elements then don't bother
+ // sending it.
+ if (elements_.empty()) {
+ AllDone();
+ return;
+ }
+ }
+
// Add all the urls in our |resources_| maps to the |report_| protocol buffer.
for (auto& resource_pair : resources_) {
ClientSafeBrowsingReportRequest::Resource* pb_resource =
@@ -747,6 +764,9 @@ void ThreatDetails::OnCacheCollectionReady() {
report_->mutable_client_properties()->set_url_api_type(
GetUrlApiTypeForThreatSource(resource_.threat_source));
+ // Fill the referrer chain if applicable.
+ MaybeFillReferrerChain();
+
// Send the report, using the SafeBrowsingService.
std::string serialized;
if (!report_->SerializeToString(&serialized)) {
@@ -774,6 +794,20 @@ void ThreatDetails::OnCacheCollectionReady() {
AllDone();
}
+void ThreatDetails::MaybeFillReferrerChain() {
+ if (!referrer_chain_provider_)
+ return;
+
+ if (!report_ ||
+ report_->type() != ClientSafeBrowsingReportRequest::URL_SUSPICIOUS) {
+ return;
+ }
+
+ referrer_chain_provider_->IdentifyReferrerChainByWebContents(
+ web_contents(), kThreatDetailsUserGestureLimit,
+ report_->mutable_referrer_chain());
+}
+
void ThreatDetails::AllDone() {
is_all_done_ = true;
BrowserThread::PostTask(
diff --git a/chromium/components/safe_browsing/browser/threat_details.h b/chromium/components/safe_browsing/browser/threat_details.h
index c1c519c06e0..84469f5db0c 100644
--- a/chromium/components/safe_browsing/browser/threat_details.h
+++ b/chromium/components/safe_browsing/browser/threat_details.h
@@ -38,6 +38,7 @@ class SharedURLLoaderFactory;
namespace safe_browsing {
class BaseUIManager;
+class ReferrerChainProvider;
// Maps a URL to its Resource.
class ThreatDetailsCacheCollector;
@@ -78,6 +79,7 @@ class ThreatDetails : public base::RefCounted<ThreatDetails>,
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback);
@@ -109,6 +111,7 @@ class ThreatDetails : public base::RefCounted<ThreatDetails>,
const UnsafeResource& resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback);
@@ -176,6 +179,11 @@ class ThreatDetails : public base::RefCounted<ThreatDetails>,
const std::vector<mojom::AttributeNameValuePtr> attributes,
const ClientSafeBrowsingReportRequest::Resource* resource);
+ // Populates the referrer chain data in |report_|. This may be skipped if the
+ // referrer chain provider isn't available, or the type of report doesn't
+ // include the referrer chain.
+ void MaybeFillReferrerChain();
+
// Called when the report is complete. Runs |done_callback_|.
void AllDone();
@@ -183,6 +191,8 @@ class ThreatDetails : public base::RefCounted<ThreatDetails>,
const UnsafeResource resource_;
+ ReferrerChainProvider* referrer_chain_provider_;
+
// For every Url we collect we create a Resource message. We keep
// them in a map so we can avoid duplicates.
ResourceMap resources_;
@@ -255,6 +265,8 @@ class ThreatDetails : public base::RefCounted<ThreatDetails>,
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HTTPCacheNoEntries);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, HTTPCache);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_AmbiguousDOM);
+ FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest,
+ ThreatDOMDetails_EmptyReportNotSent);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_MultipleFrames);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails_TrimToAdTags);
FRIEND_TEST_ALL_PREFIXES(ThreatDetailsTest, ThreatDOMDetails);
@@ -273,6 +285,7 @@ class ThreatDetailsFactory {
const security_interstitials::UnsafeResource& unsafe_resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) = 0;
};
diff --git a/chromium/components/safe_browsing/browser/threat_details_cache.cc b/chromium/components/safe_browsing/browser/threat_details_cache.cc
index 5f9d575f413..d8ee18a7c47 100644
--- a/chromium/components/safe_browsing/browser/threat_details_cache.cc
+++ b/chromium/components/safe_browsing/browser/threat_details_cache.cc
@@ -135,7 +135,7 @@ void ThreatDetailsCacheCollector::OnURLLoaderComplete(
std::unique_ptr<std::string> response_body) {
DVLOG(1) << "OnURLLoaderComplete";
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- DCHECK(current_load_.get());
+ DCHECK(current_load_);
if (current_load_->NetError() == net::ERR_CACHE_MISS) {
// Cache miss, skip this resource.
DVLOG(1) << "Cache miss for url: " << current_load_->GetFinalURL();
@@ -164,7 +164,7 @@ void ThreatDetailsCacheCollector::OnURLLoaderComplete(
ReadResponse(resource);
std::string data;
if (response_body)
- data = *response_body.get();
+ data = *response_body;
ReadData(resource, data);
AdvanceEntry();
}
diff --git a/chromium/components/safe_browsing/browser/url_checker_delegate.h b/chromium/components/safe_browsing/browser/url_checker_delegate.h
index 5c3dcc05d88..29b41492063 100644
--- a/chromium/components/safe_browsing/browser/url_checker_delegate.h
+++ b/chromium/components/safe_browsing/browser/url_checker_delegate.h
@@ -68,6 +68,13 @@ class UrlCheckerDelegate
int render_frame_id,
bool originated_from_service_worker) = 0;
+ // Notifies the SafeBrowsing Trigger Manager that a suspicious site has been
+ // detected. |web_contents_getter| is used to determine which tab the site
+ // was detected on.
+ virtual void NotifySuspiciousSiteDetected(
+ const base::RepeatingCallback<content::WebContents*()>&
+ web_contents_getter) = 0;
+
virtual const SBThreatTypeSet& GetThreatTypes() = 0;
virtual SafeBrowsingDatabaseManager* GetDatabaseManager() = 0;
virtual BaseUIManager* GetUIManager() = 0;
diff --git a/chromium/components/safe_browsing/common/BUILD.gn b/chromium/components/safe_browsing/common/BUILD.gn
index 0d963a83820..4a3c89195d3 100644
--- a/chromium/components/safe_browsing/common/BUILD.gn
+++ b/chromium/components/safe_browsing/common/BUILD.gn
@@ -17,6 +17,8 @@ source_set("common") {
deps = [
"//base",
+ "//components/policy/core/browser:browser",
+ "//components/safe_browsing:csd_proto",
"//crypto:crypto",
"//ipc",
"//url/ipc:url_ipc",
diff --git a/chromium/components/safe_browsing/common/DEPS b/chromium/components/safe_browsing/common/DEPS
index 0e7f7e169f5..bb334b19fa5 100644
--- a/chromium/components/safe_browsing/common/DEPS
+++ b/chromium/components/safe_browsing/common/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/policy/core/browser",
"+components/pref_registry",
"+components/prefs",
"+content/public/test",
diff --git a/chromium/components/safe_browsing/common/safe_browsing_prefs.cc b/chromium/components/safe_browsing/common/safe_browsing_prefs.cc
index 2db1241efe2..8f66cdbffc0 100644
--- a/chromium/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/chromium/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -174,22 +174,18 @@ const char kSafeBrowsingScoutGroupSelected[] =
"safebrowsing.scout_group_selected";
const char kSafeBrowsingScoutReportingEnabled[] =
"safebrowsing.scout_reporting_enabled";
+const char kSafeBrowsingTriggerEventTimestamps[] =
+ "safebrowsing.trigger_event_timestamps";
const char kSafeBrowsingUnhandledSyncPasswordReuses[] =
"safebrowsing.unhandled_sync_password_reuses";
const char kSafeBrowsingWhitelistDomains[] =
"safebrowsing.safe_browsing_whitelist_domains";
const char kPasswordProtectionChangePasswordURL[] =
"safebrowsing.password_protection_change_password_url";
-const char kPasswordProtectionEnterpriseName[] =
- "safebrowsing.password_protection_enterprise_name";
-const char kPasswordProtectionEnterpriseEmailDomain[] =
- "safebrowsing.password_protection_enterprise_email_domain";
const char kPasswordProtectionLoginURLs[] =
"safebrowsing.password_protection_login_urls";
const char kPasswordProtectionWarningTrigger[] =
"safebrowsing.password_protection_warning_trigger";
-const char kPasswordProtectionRiskTrigger[] =
- "safebrowsing.password_protection_risk_trigger";
} // namespace prefs
namespace safe_browsing {
@@ -385,14 +381,13 @@ void RegisterProfilePrefs(PrefRegistrySimple* registry) {
prefs::kSafeBrowsingUnhandledSyncPasswordReuses);
registry->RegisterListPref(prefs::kSafeBrowsingWhitelistDomains);
registry->RegisterStringPref(prefs::kPasswordProtectionChangePasswordURL, "");
- registry->RegisterStringPref(prefs::kPasswordProtectionEnterpriseName, "");
- registry->RegisterStringPref(prefs::kPasswordProtectionEnterpriseEmailDomain,
- "");
registry->RegisterListPref(prefs::kPasswordProtectionLoginURLs);
registry->RegisterIntegerPref(prefs::kPasswordProtectionWarningTrigger,
PASSWORD_PROTECTION_OFF);
- registry->RegisterIntegerPref(prefs::kPasswordProtectionRiskTrigger,
- PASSWORD_PROTECTION_OFF);
+}
+
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
+ registry->RegisterDictionaryPref(prefs::kSafeBrowsingTriggerEventTimestamps);
}
void SetExtendedReportingPrefAndMetric(
@@ -536,10 +531,9 @@ void CanonicalizeDomainList(
bool IsURLWhitelistedByPolicy(const GURL& url,
StringListPrefMember* pref_member) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (!pref_member ||
- !base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1)) {
+ if (!pref_member)
return false;
- }
+
std::vector<std::string> sb_whitelist_domains = pref_member->GetValue();
return std::find_if(sb_whitelist_domains.begin(), sb_whitelist_domains.end(),
[&url](const std::string& domain) {
@@ -549,9 +543,6 @@ bool IsURLWhitelistedByPolicy(const GURL& url,
bool IsURLWhitelistedByPolicy(const GURL& url, const PrefService& pref) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (!base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1))
- return false;
-
if (!pref.HasPrefPath(prefs::kSafeBrowsingWhitelistDomains))
return false;
const base::ListValue* whitelist =
diff --git a/chromium/components/safe_browsing/common/safe_browsing_prefs.h b/chromium/components/safe_browsing/common/safe_browsing_prefs.h
index 43ff1f40e91..d6cd6be18d4 100644
--- a/chromium/components/safe_browsing/common/safe_browsing_prefs.h
+++ b/chromium/components/safe_browsing/common/safe_browsing_prefs.h
@@ -51,6 +51,10 @@ extern const char kSafeBrowsingScoutGroupSelected[];
// collects data for malware detection.
extern const char kSafeBrowsingScoutReportingEnabled[];
+// Dictionary containing safe browsing triggers and the list of times they have
+// fired recently.
+extern const char kSafeBrowsingTriggerEventTimestamps[];
+
// Dictionary that records the origin and navigation ID pairs of unhandled sync
// password reuses.
extern const char kSafeBrowsingUnhandledSyncPasswordReuses[];
@@ -65,14 +69,6 @@ extern const char kSafeBrowsingWhitelistDomains[];
// also captures new password on this page in a change password event.
extern const char kPasswordProtectionChangePasswordURL[];
-// String indicating the organization name that should be include in the
-// password reuse warning text.
-extern const char kPasswordProtectionEnterpriseName[];
-
-// String indicating the enterprise email domain that is covered by password
-// protection.
-extern const char kPasswordProtectionEnterpriseEmailDomain[];
-
// List of string indicating the URL(s) users use to log in. Password protection
// service will capture passwords on these URLs.
// This is managed by enterprise policy and has no effect on users who are not
@@ -83,11 +79,6 @@ extern const char kPasswordProtectionLoginURLs[];
// by enterprise policy and has no effect on users who are not managed by
// enterprise policy.
extern const char kPasswordProtectionWarningTrigger[];
-
-// Integer indicating the password protection at-risk account flagging trigger.
-// This is managed by enterprise policy and has no effect on users who are not
-// managed by enterprise policy.
-extern const char kPasswordProtectionRiskTrigger[];
}
namespace safe_browsing {
@@ -195,6 +186,9 @@ void RecordExtendedReportingMetrics(const PrefService& prefs);
// Registers user preferences related to Safe Browsing.
void RegisterProfilePrefs(PrefRegistrySimple* registry);
+// Registers local state prefs related to Safe Browsing.
+void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
+
// Sets the currently active Safe Browsing Extended Reporting preference to the
// specified value. The |location| indicates the UI where the change was
// made.
diff --git a/chromium/components/safe_browsing/common/safe_browsing_prefs_unittest.cc b/chromium/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
index afe3ba8231d..e3c1ac9d5a8 100644
--- a/chromium/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
+++ b/chromium/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -438,8 +438,6 @@ TEST_F(SafeBrowsingPrefsTest, IsExtendedReportingPolicyManaged) {
}
TEST_F(SafeBrowsingPrefsTest, VerifyIsURLWhitelistedByPolicy) {
- EnableEnterprisePasswordProtectionFeature();
-
GURL target_url("https://www.foo.com");
// When PrefMember is null, URL is not whitelisted.
EXPECT_FALSE(IsURLWhitelistedByPolicy(target_url, nullptr));
diff --git a/chromium/components/safe_browsing/common/utils.cc b/chromium/components/safe_browsing/common/utils.cc
index 3e823e115ee..2d17295d15f 100644
--- a/chromium/components/safe_browsing/common/utils.cc
+++ b/chromium/components/safe_browsing/common/utils.cc
@@ -6,8 +6,14 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
#include "crypto/sha2.h"
+#if defined(OS_WIN)
+#include "base/win/win_util.h"
+#endif
+
namespace safe_browsing {
std::string ShortURLForReporting(const GURL& url) {
@@ -27,4 +33,20 @@ void LogNoUserActionResourceLoadingDelay(base::TimeDelta time) {
UMA_HISTOGRAM_LONG_TIMES("SB2.NoUserActionResourceLoadingDelay", time);
}
+ChromeUserPopulation::ProfileManagementStatus GetProfileManagementStatus(
+ const policy::BrowserPolicyConnector* bpc) {
+#if defined(OS_WIN)
+ if (base::win::IsEnterpriseManaged())
+ return ChromeUserPopulation::ENTERPRISE_MANAGED;
+ else
+ return ChromeUserPopulation::NOT_MANAGED;
+#elif defined(OS_CHROMEOS)
+ if (!bpc || !bpc->IsEnterpriseManaged())
+ return ChromeUserPopulation::NOT_MANAGED;
+ return ChromeUserPopulation::ENTERPRISE_MANAGED;
+#else
+ return ChromeUserPopulation::UNAVAILABLE;
+#endif // #if defined(OS_WIN) || defined(OS_CHROMEOS)
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/common/utils.h b/chromium/components/safe_browsing/common/utils.h
index ca6495542ab..484272e1527 100644
--- a/chromium/components/safe_browsing/common/utils.h
+++ b/chromium/components/safe_browsing/common/utils.h
@@ -8,8 +8,13 @@
#define COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_
#include "base/time/time.h"
+#include "components/safe_browsing/proto/csd.pb.h"
#include "url/gurl.h"
+namespace policy {
+class BrowserPolicyConnector;
+} // namespace policy
+
namespace safe_browsing {
// Shorten URL by replacing its contents with its SHA256 hash if it has data
@@ -23,6 +28,12 @@ std::string ShortURLForReporting(const GURL& url);
// a load, the sum of all the delays will be reported.
void LogNoUserActionResourceLoadingDelay(base::TimeDelta time);
+// Gets the |ProfileManagementStatus| for the current machine. The method
+// currently works only on Windows and ChromeOS. The |bpc| parameter is used
+// only on ChromeOS, and may be |nullptr|.
+ChromeUserPopulation::ProfileManagementStatus GetProfileManagementStatus(
+ const policy::BrowserPolicyConnector* bpc);
+
} // namespace safe_browsing
#endif // COMPONENTS_SAFE_BROWSING_COMMON_UTILS_H_
diff --git a/chromium/components/safe_browsing/db/database_manager_unittest.cc b/chromium/components/safe_browsing/db/database_manager_unittest.cc
index 3994d668c4a..01ef6b0eaaa 100644
--- a/chromium/components/safe_browsing/db/database_manager_unittest.cc
+++ b/chromium/components/safe_browsing/db/database_manager_unittest.cc
@@ -23,10 +23,10 @@
#include "components/safe_browsing/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/db/v4_test_util.h"
#include "content/public/browser/browser_thread.h"
-#include "content/public/common/weak_wrapper_shared_url_loader_factory.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "crypto/sha2.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -70,7 +70,7 @@ class SafeBrowsingDatabaseManagerTest : public testing::Test {
protected:
void SetUp() override {
test_shared_loader_factory_ =
- base::MakeRefCounted<content::WeakWrapperSharedURLLoaderFactory>(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
db_manager_ = new TestSafeBrowsingDatabaseManager();
diff --git a/chromium/components/safe_browsing/db/prefix_set.cc b/chromium/components/safe_browsing/db/prefix_set.cc
index b6155207b15..2e28565664b 100644
--- a/chromium/components/safe_browsing/db/prefix_set.cc
+++ b/chromium/components/safe_browsing/db/prefix_set.cc
@@ -369,7 +369,7 @@ PrefixSetBuilder::~PrefixSetBuilder() {}
std::unique_ptr<const PrefixSet> PrefixSetBuilder::GetPrefixSet(
const std::vector<SBFullHash>& hashes) {
- DCHECK(prefix_set_.get());
+ DCHECK(prefix_set_);
// Flush runs until buffered data is gone.
while (!buffer_.empty()) {
@@ -392,7 +392,7 @@ std::unique_ptr<const PrefixSet> PrefixSetBuilder::GetPrefixSetNoHashes() {
}
void PrefixSetBuilder::EmitRun() {
- DCHECK(prefix_set_.get());
+ DCHECK(prefix_set_);
SBPrefix prev_prefix = buffer_[0];
uint16_t run[PrefixSet::kMaxRun];
@@ -421,7 +421,7 @@ void PrefixSetBuilder::EmitRun() {
}
void PrefixSetBuilder::AddPrefix(SBPrefix prefix) {
- DCHECK(prefix_set_.get());
+ DCHECK(prefix_set_);
if (buffer_.empty()) {
DCHECK(prefix_set_->index_.empty());
diff --git a/chromium/components/safe_browsing/db/prefix_set_unittest.cc b/chromium/components/safe_browsing/db/prefix_set_unittest.cc
index 68fb30bdb50..c890deab0bb 100644
--- a/chromium/components/safe_browsing/db/prefix_set_unittest.cc
+++ b/chromium/components/safe_browsing/db/prefix_set_unittest.cc
@@ -185,7 +185,7 @@ class PrefixSetTest : public PlatformTest {
base::FilePath TestFilePath() {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
@@ -458,7 +458,7 @@ TEST_F(PrefixSetTest, CorruptionHelpers) {
IncrementIntAt(file.get(), kPayloadOffset, 1);
file.reset();
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
// Fix up the checksum and it will read successfully (though the
// data will be wrong).
@@ -476,7 +476,7 @@ TEST_F(PrefixSetTest, CorruptionMagic) {
ASSERT_NO_FATAL_FAILURE(ModifyAndCleanChecksum(filename, kMagicOffset, 1));
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Bad version is caught by the sanity check.
@@ -486,7 +486,7 @@ TEST_F(PrefixSetTest, CorruptionVersion) {
ASSERT_NO_FATAL_FAILURE(ModifyAndCleanChecksum(filename, kVersionOffset, 10));
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Bad |index_| size is caught by the sanity check.
@@ -497,7 +497,7 @@ TEST_F(PrefixSetTest, CorruptionIndexSize) {
ASSERT_NO_FATAL_FAILURE(
ModifyAndCleanChecksum(filename, kIndexSizeOffset, 1));
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Bad |deltas_| size is caught by the sanity check.
@@ -508,7 +508,7 @@ TEST_F(PrefixSetTest, CorruptionDeltasSize) {
ASSERT_NO_FATAL_FAILURE(
ModifyAndCleanChecksum(filename, kDeltasSizeOffset, 1));
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Bad |full_hashes_| size is caught by the sanity check.
@@ -519,7 +519,7 @@ TEST_F(PrefixSetTest, CorruptionFullHashesSize) {
ASSERT_NO_FATAL_FAILURE(
ModifyAndCleanChecksum(filename, kFullHashesSizeOffset, 1));
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Test that the digest catches corruption in the middle of the file
@@ -532,7 +532,7 @@ TEST_F(PrefixSetTest, CorruptionPayload) {
ASSERT_NO_FATAL_FAILURE(IncrementIntAt(file.get(), 666, 1));
file.reset();
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Test corruption in the digest itself.
@@ -547,7 +547,7 @@ TEST_F(PrefixSetTest, CorruptionDigest) {
ASSERT_NO_FATAL_FAILURE(IncrementIntAt(file.get(), digest_offset, 1));
file.reset();
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Test excess data after the digest (fails the size test).
@@ -561,7 +561,7 @@ TEST_F(PrefixSetTest, CorruptionExcess) {
ASSERT_EQ(strlen(buf), fwrite(buf, 1, strlen(buf), file.get()));
file.reset();
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Test that files which had 64-bit size_t are discarded.
@@ -603,7 +603,7 @@ TEST_F(PrefixSetTest, SizeTRecovery) {
file.reset(); // Flush updates.
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Test Exists() against full hashes passed to builder.
@@ -684,7 +684,7 @@ TEST_F(PrefixSetTest, ReadSigned) {
file.reset(); // Flush updates.
std::unique_ptr<const PrefixSet> prefix_set = PrefixSet::LoadFile(filename);
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
// Test that a golden v2 file is discarded on read. All platforms generating v2
@@ -700,7 +700,7 @@ TEST_F(PrefixSetTest, Version2) {
golden_path = golden_path.AppendASCII(kBasename);
std::unique_ptr<const PrefixSet> prefix_set(PrefixSet::LoadFile(golden_path));
- ASSERT_FALSE(prefix_set.get());
+ ASSERT_FALSE(prefix_set);
}
#endif
diff --git a/chromium/components/safe_browsing/db/safebrowsing.proto b/chromium/components/safe_browsing/db/safebrowsing.proto
index 989cd2d2bd0..5116de4a4ba 100644
--- a/chromium/components/safe_browsing/db/safebrowsing.proto
+++ b/chromium/components/safe_browsing/db/safebrowsing.proto
@@ -286,6 +286,9 @@ enum ThreatType {
// Patterns to be used for activating the subresource filter. Interstitial
// will not be shown for patterns from this list.
SUBRESOURCE_FILTER = 13;
+
+ // Entities that are suspected to present a threat.
+ SUSPICIOUS = 14;
}
// Types of platforms.
diff --git a/chromium/components/safe_browsing/db/v4_embedded_test_server_util.cc b/chromium/components/safe_browsing/db/v4_embedded_test_server_util.cc
index 0008377ef5e..0204cbb92ef 100644
--- a/chromium/components/safe_browsing/db/v4_embedded_test_server_util.cc
+++ b/chromium/components/safe_browsing/db/v4_embedded_test_server_util.cc
@@ -59,6 +59,7 @@ std::vector<HashPrefix> GetPrefixesForRequest(const GURL& url) {
// predetermined responses.
std::unique_ptr<net::test_server::HttpResponse> HandleFullHashRequest(
const std::map<GURL, ThreatMatch>& response_map,
+ const std::map<GURL, base::TimeDelta>& delay_map,
const net::test_server::HttpRequest& request) {
if (!(net::test_server::ShouldHandle(request, "/v4/fullHashes:find")))
return nullptr;
@@ -72,12 +73,17 @@ std::unique_ptr<net::test_server::HttpResponse> HandleFullHashRequest(
// that match the prefix.
std::vector<HashPrefix> request_prefixes =
GetPrefixesForRequest(request.GetURL());
+ const base::TimeDelta* delay = nullptr;
for (const HashPrefix& prefix : request_prefixes) {
for (const auto& response : response_map) {
FullHash full_hash = GetFullHash(response.first);
if (V4ProtocolManagerUtil::FullHashMatchesHashPrefix(full_hash, prefix)) {
ThreatMatch* match = find_full_hashes_response.add_matches();
*match = response.second;
+ auto it = delay_map.find(response.first);
+ if (it != delay_map.end()) {
+ delay = &(it->second);
+ }
}
}
}
@@ -85,7 +91,9 @@ std::unique_ptr<net::test_server::HttpResponse> HandleFullHashRequest(
std::string serialized_response;
find_full_hashes_response.SerializeToString(&serialized_response);
- auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
+ auto http_response =
+ (delay ? std::make_unique<net::test_server::DelayedHttpResponse>(*delay)
+ : std::make_unique<net::test_server::BasicHttpResponse>());
http_response->set_content(serialized_response);
return http_response;
}
@@ -94,13 +102,14 @@ std::unique_ptr<net::test_server::HttpResponse> HandleFullHashRequest(
void StartRedirectingV4RequestsForTesting(
const std::map<GURL, ThreatMatch>& response_map,
- net::test_server::EmbeddedTestServer* embedded_test_server) {
+ net::test_server::EmbeddedTestServer* embedded_test_server,
+ const std::map<GURL, base::TimeDelta>& delay_map) {
// Static so accessing the underlying buffer won't cause use-after-free.
static std::string url_prefix;
url_prefix = embedded_test_server->GetURL("/v4").spec();
SetSbV4UrlPrefixForTesting(url_prefix.c_str());
embedded_test_server->RegisterRequestHandler(
- base::Bind(&HandleFullHashRequest, response_map));
+ base::BindRepeating(&HandleFullHashRequest, response_map, delay_map));
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/db/v4_embedded_test_server_util.h b/chromium/components/safe_browsing/db/v4_embedded_test_server_util.h
index 68d27e3af29..14183a8da30 100644
--- a/chromium/components/safe_browsing/db/v4_embedded_test_server_util.h
+++ b/chromium/components/safe_browsing/db/v4_embedded_test_server_util.h
@@ -7,6 +7,7 @@
#include <map>
+#include "base/time/time.h"
#include "components/safe_browsing/db/safebrowsing.pb.h"
#include "url/gurl.h"
@@ -18,12 +19,15 @@ class EmbeddedTestServer;
namespace safe_browsing {
-// This method does two things:
+// This method does three things:
// 1. Rewrites the global V4 server URL prefix to point to the test server.
// 2. Registers the FullHash request handler with the server.
+// 3. (Optionally) associates some delay with the resulting http response.
void StartRedirectingV4RequestsForTesting(
const std::map<GURL, ThreatMatch>& response_map,
- net::test_server::EmbeddedTestServer* embedded_test_server);
+ net::test_server::EmbeddedTestServer* embedded_test_server,
+ const std::map<GURL, base::TimeDelta>& delay_map =
+ std::map<GURL, base::TimeDelta>());
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager.cc b/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager.cc
index a0e9fb5a58f..e3589ea35ec 100644
--- a/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager.cc
+++ b/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager.cc
@@ -227,8 +227,7 @@ std::unique_ptr<V4GetHashProtocolManager> V4GetHashProtocolManager::Create(
// static
void V4GetHashProtocolManager::RegisterFactory(
std::unique_ptr<V4GetHashProtocolManagerFactory> factory) {
- if (factory_)
- delete factory_;
+ delete factory_;
factory_ = factory.release();
}
@@ -779,7 +778,7 @@ void V4GetHashProtocolManager::OnURLLoaderComplete(
std::string data;
if (response_body)
- data = *response_body.get();
+ data = *response_body;
OnURLLoaderCompleteInternal(url_loader, url_loader->NetError(), response_code,
data);
diff --git a/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager_unittest.cc b/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager_unittest.cc
index 90c541d1022..92a253fab24 100644
--- a/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager_unittest.cc
+++ b/chromium/components/safe_browsing/db/v4_get_hash_protocol_manager_unittest.cc
@@ -16,12 +16,12 @@
#include "components/safe_browsing/db/safebrowsing.pb.h"
#include "components/safe_browsing/db/util.h"
#include "components/safe_browsing/db/v4_test_util.h"
-#include "content/public/common/weak_wrapper_shared_url_loader_factory.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/platform_test.h"
@@ -68,7 +68,7 @@ class V4GetHashProtocolManagerTest : public PlatformTest {
PlatformTest::SetUp();
callback_called_ = false;
test_shared_loader_factory_ =
- base::MakeRefCounted<content::WeakWrapperSharedURLLoaderFactory>(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
}
diff --git a/chromium/components/safe_browsing/db/v4_local_database_manager.cc b/chromium/components/safe_browsing/db/v4_local_database_manager.cc
index bab16ca3ccd..786b7a324b5 100644
--- a/chromium/components/safe_browsing/db/v4_local_database_manager.cc
+++ b/chromium/components/safe_browsing/db/v4_local_database_manager.cc
@@ -42,7 +42,8 @@ const char* const kV3Suffix = ".V3.";
// safely deleted from the disk. There's no overlap allowed between the files
// on this list and the list returned by GetListInfos().
const char* const kStoreFileNamesToDelete[] = {
- "AnyIpMalware.store", "ChromeFilenameClientIncident.store"};
+ "AnyIpMalware.store", "ChromeFilenameClientIncident.store",
+ "UrlSuspiciousSiteId.store"};
ListInfos GetListInfos() {
// NOTE(vakh): When adding a store here, add the corresponding store-specific
@@ -62,14 +63,8 @@ ListInfos GetListInfos() {
const bool kSyncAlways = true;
const bool kSyncNever = false;
return ListInfos({
- ListInfo(kSyncOnlyOnChromeBuilds, "CertCsdDownloadWhitelist.store",
- GetCertCsdDownloadWhitelistId(), SB_THREAT_TYPE_UNUSED),
ListInfo(kSyncAlways, "IpMalware.store", GetIpMalwareId(),
SB_THREAT_TYPE_UNUSED),
- ListInfo(kSyncOnlyOnChromeBuilds, "UrlCsdDownloadWhitelist.store",
- GetUrlCsdDownloadWhitelistId(), SB_THREAT_TYPE_UNUSED),
- ListInfo(kSyncOnlyOnChromeBuilds, "UrlCsdWhitelist.store",
- GetUrlCsdWhitelistId(), SB_THREAT_TYPE_CSD_WHITELIST),
ListInfo(kSyncAlways, "UrlSoceng.store", GetUrlSocEngId(),
SB_THREAT_TYPE_URL_PHISHING),
ListInfo(kSyncAlways, "UrlMalware.store", GetUrlMalwareId(),
@@ -80,12 +75,20 @@ ListInfos GetListInfos() {
SB_THREAT_TYPE_URL_BINARY_MALWARE),
ListInfo(kSyncAlways, "ChromeExtMalware.store", GetChromeExtMalwareId(),
SB_THREAT_TYPE_EXTENSION),
+ ListInfo(kSyncOnlyOnChromeBuilds, "CertCsdDownloadWhitelist.store",
+ GetCertCsdDownloadWhitelistId(), SB_THREAT_TYPE_UNUSED),
ListInfo(kSyncOnlyOnChromeBuilds, "ChromeUrlClientIncident.store",
GetChromeUrlClientIncidentId(),
SB_THREAT_TYPE_BLACKLISTED_RESOURCE),
- ListInfo(kSyncNever, "", GetChromeUrlApiId(), SB_THREAT_TYPE_API_ABUSE),
+ ListInfo(kSyncOnlyOnChromeBuilds, "UrlCsdDownloadWhitelist.store",
+ GetUrlCsdDownloadWhitelistId(), SB_THREAT_TYPE_UNUSED),
+ ListInfo(kSyncOnlyOnChromeBuilds, "UrlCsdWhitelist.store",
+ GetUrlCsdWhitelistId(), SB_THREAT_TYPE_CSD_WHITELIST),
ListInfo(kSyncOnlyOnChromeBuilds, "UrlSubresourceFilter.store",
GetUrlSubresourceFilterId(), SB_THREAT_TYPE_SUBRESOURCE_FILTER),
+ ListInfo(kSyncOnlyOnChromeBuilds, "UrlSuspiciousSite.store",
+ GetUrlSuspiciousSiteId(), SB_THREAT_TYPE_SUSPICIOUS_SITE),
+ ListInfo(kSyncNever, "", GetChromeUrlApiId(), SB_THREAT_TYPE_API_ABUSE),
});
// NOTE(vakh): IMPORTANT: Please make sure that the server already supports
// any list before adding it to this list otherwise the prefix updates break
@@ -108,6 +111,8 @@ ThreatSeverity GetThreatSeverity(const ListIdentifier& list_id) {
return 2;
case CSD_WHITELIST:
return 3;
+ case SUSPICIOUS:
+ return 4;
default:
NOTREACHED() << "Unexpected ThreatType encountered: "
<< list_id.threat_type();
@@ -127,6 +132,9 @@ ListIdentifier GetUrlIdFromSBThreatType(SBThreatType sb_threat_type) {
case SB_THREAT_TYPE_URL_UNWANTED:
return GetUrlUwsId();
+ case SB_THREAT_TYPE_SUSPICIOUS_SITE:
+ return GetUrlSuspiciousSiteId();
+
default:
NOTREACHED();
// Compiler requires a return statement here.
@@ -854,7 +862,7 @@ void V4LocalDatabaseManager::RespondSafeToQueuedChecks() {
void V4LocalDatabaseManager::RespondToClient(
std::unique_ptr<PendingCheck> check) {
- DCHECK(check.get());
+ DCHECK(check);
switch (check->client_callback_type) {
case ClientCallbackType::CHECK_BROWSE_URL:
diff --git a/chromium/components/safe_browsing/db/v4_local_database_manager.h b/chromium/components/safe_browsing/db/v4_local_database_manager.h
index c2f95a6a764..d7399b97902 100644
--- a/chromium/components/safe_browsing/db/v4_local_database_manager.h
+++ b/chromium/components/safe_browsing/db/v4_local_database_manager.h
@@ -12,6 +12,7 @@
#include <unordered_set>
#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
#include "components/safe_browsing/db/database_manager.h"
#include "components/safe_browsing/db/hit_report.h"
#include "components/safe_browsing/db/v4_database.h"
diff --git a/chromium/components/safe_browsing/db/v4_local_database_manager_unittest.cc b/chromium/components/safe_browsing/db/v4_local_database_manager_unittest.cc
index 477cdcb2771..76099d7042b 100644
--- a/chromium/components/safe_browsing/db/v4_local_database_manager_unittest.cc
+++ b/chromium/components/safe_browsing/db/v4_local_database_manager_unittest.cc
@@ -9,18 +9,19 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/safe_browsing/db/v4_database.h"
#include "components/safe_browsing/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/db/v4_test_util.h"
-#include "content/public/common/weak_wrapper_shared_url_loader_factory.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "content/public/test/test_utils.h"
#include "crypto/sha2.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/platform_test.h"
@@ -105,7 +106,7 @@ class FakeV4Database : public V4Database {
bool stores_available) {
// Mimics V4Database::Create
const scoped_refptr<base::SingleThreadTaskRunner>& callback_task_runner =
- base::MessageLoop::current()->task_runner();
+ base::MessageLoopCurrent::Get()->task_runner();
db_task_runner->PostTask(
FROM_HERE, base::BindOnce(&FakeV4Database::CreateOnTaskRunner,
db_task_runner, std::move(store_map),
@@ -285,7 +286,7 @@ class V4LocalDatabaseManagerTest : public PlatformTest {
PlatformTest::SetUp();
test_shared_loader_factory_ =
- base::MakeRefCounted<content::WeakWrapperSharedURLLoaderFactory>(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
ASSERT_TRUE(base_dir_.CreateUniqueTempDir());
diff --git a/chromium/components/safe_browsing/db/v4_protocol_manager_util.cc b/chromium/components/safe_browsing/db/v4_protocol_manager_util.cc
index e3966ce20d6..6c6b300ffb6 100644
--- a/chromium/components/safe_browsing/db/v4_protocol_manager_util.cc
+++ b/chromium/components/safe_browsing/db/v4_protocol_manager_util.cc
@@ -38,11 +38,7 @@ std::string Unescape(const std::string& url) {
int loop_var = 0;
do {
old_size = unescaped_str.size();
- unescaped_str = net::UnescapeURLComponent(
- unescaped_str,
- net::UnescapeRule::SPOOFING_AND_CONTROL_CHARS |
- net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
- net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
+ unescaped_str = net::UnescapeBinaryURLComponent(unescaped_str);
} while (old_size != unescaped_str.size() &&
++loop_var <= kMaxLoopIterations);
@@ -143,6 +139,10 @@ ListIdentifier GetUrlSubresourceFilterId() {
return ListIdentifier(GetCurrentPlatformType(), URL, SUBRESOURCE_FILTER);
}
+ListIdentifier GetUrlSuspiciousSiteId() {
+ return ListIdentifier(GetCurrentPlatformType(), URL, SUSPICIOUS);
+}
+
ListIdentifier GetUrlUwsId() {
return ListIdentifier(GetCurrentPlatformType(), URL, UNWANTED_SOFTWARE);
}
@@ -180,6 +180,7 @@ bool SBThreatTypeSetIsValidForCheckBrowseUrl(const SBThreatTypeSet& set) {
case SB_THREAT_TYPE_URL_PHISHING:
case SB_THREAT_TYPE_URL_MALWARE:
case SB_THREAT_TYPE_URL_UNWANTED:
+ case SB_THREAT_TYPE_SUSPICIOUS_SITE:
break;
default:
diff --git a/chromium/components/safe_browsing/db/v4_protocol_manager_util.h b/chromium/components/safe_browsing/db/v4_protocol_manager_util.h
index 0bd71db320e..53033ae3955 100644
--- a/chromium/components/safe_browsing/db/v4_protocol_manager_util.h
+++ b/chromium/components/safe_browsing/db/v4_protocol_manager_util.h
@@ -196,6 +196,7 @@ ListIdentifier GetUrlMalBinId();
ListIdentifier GetUrlMalwareId();
ListIdentifier GetUrlSocEngId();
ListIdentifier GetUrlSubresourceFilterId();
+ListIdentifier GetUrlSuspiciousSiteId();
ListIdentifier GetUrlUwsId();
// Returns the basename of the store file, without the ".store" extension.
diff --git a/chromium/components/safe_browsing/db/v4_store.cc b/chromium/components/safe_browsing/db/v4_store.cc
index c3b669daadb..818dec972e6 100644
--- a/chromium/components/safe_browsing/db/v4_store.cc
+++ b/chromium/components/safe_browsing/db/v4_store.cc
@@ -37,7 +37,6 @@ const char kReadFromDisk[] = "SafeBrowsing.V4ReadFromDisk";
const char kApplyUpdate[] = ".ApplyUpdate";
const char kDecodeAdditions[] = ".DecodeAdditions";
const char kDecodeRemovals[] = ".DecodeRemovals";
-const char kMergeUpdate[] = ".MergeUpdate";
// Part 3: Represent the unit of value being measured and logged.
const char kResult[] = ".Result";
const char kTime[] = ".Time";
@@ -104,10 +103,6 @@ void RecordEnumWithAndWithoutSuffix(const std::string& metric,
}
}
-void RecordAddUnlumpedHashesTime(base::TimeDelta time) {
- UMA_HISTOGRAM_LONG_TIMES("SafeBrowsing.V4AddUnlumpedHashes.Time", time);
-}
-
void RecordApplyUpdateResult(const std::string& base_metric,
ApplyUpdateResult result,
const base::FilePath& file_path) {
@@ -149,12 +144,6 @@ void RecordDecodeRemovalsTime(const std::string& base_metric,
file_path);
}
-void RecordMergeUpdateTime(const std::string& base_metric,
- base::TimeDelta time,
- const base::FilePath& file_path) {
- RecordTimeWithAndWithoutSuffix(base_metric + kMergeUpdate, time, file_path);
-}
-
void RecordStoreReadResult(StoreReadResult result) {
UMA_HISTOGRAM_ENUMERATION("SafeBrowsing.V4StoreRead.Result", result,
STORE_READ_RESULT_MAX);
@@ -329,7 +318,6 @@ ApplyUpdateResult V4Store::ProcessUpdate(
expected_checksum = response->checksum().sha256();
}
- TimeTicks before = TimeTicks::Now();
if (delay_checksum_check) {
DCHECK(hash_prefix_map_old.empty());
DCHECK(!raw_removals);
@@ -350,7 +338,6 @@ ApplyUpdateResult V4Store::ProcessUpdate(
return apply_update_result;
}
}
- RecordMergeUpdateTime(metric, TimeTicks::Now() - before, store_path_);
state_ = response->new_client_state();
return APPLY_UPDATE_SUCCESS;
@@ -483,11 +470,9 @@ ApplyUpdateResult V4Store::AddUnlumpedHashes(PrefixSize prefix_size,
return ADDITIONS_SIZE_UNEXPECTED_FAILURE;
}
- TimeTicks before = TimeTicks::Now();
// TODO(vakh): Figure out a way to avoid the following copy operation.
(*additions_map)[prefix_size] =
std::string(raw_hashes_begin, raw_hashes_begin + raw_hashes_length);
- RecordAddUnlumpedHashesTime(TimeTicks::Now() - before);
return APPLY_UPDATE_SUCCESS;
}
diff --git a/chromium/components/safe_browsing/db/v4_update_protocol_manager.cc b/chromium/components/safe_browsing/db/v4_update_protocol_manager.cc
index e5e715290cd..e58ff911338 100644
--- a/chromium/components/safe_browsing/db/v4_update_protocol_manager.cc
+++ b/chromium/components/safe_browsing/db/v4_update_protocol_manager.cc
@@ -306,7 +306,7 @@ void V4UpdateProtocolManager::IssueUpdateRequest() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// If an update request is already pending, record and return silently.
- if (request_.get()) {
+ if (request_) {
RecordUpdateResult(V4OperationResult::ALREADY_PENDING_ERROR);
return;
}
@@ -376,7 +376,7 @@ void V4UpdateProtocolManager::OnURLLoaderComplete(
std::string data;
if (response_body)
- data = *response_body.get();
+ data = *response_body;
OnURLLoaderCompleteInternal(request_->NetError(), response_code, data);
}
diff --git a/chromium/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc b/chromium/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc
index 0027d569f52..b0213c44e66 100644
--- a/chromium/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc
+++ b/chromium/components/safe_browsing/db/v4_update_protocol_manager_unittest.cc
@@ -16,12 +16,12 @@
#include "components/safe_browsing/db/safebrowsing.pb.h"
#include "components/safe_browsing/db/util.h"
#include "components/safe_browsing/db/v4_test_util.h"
-#include "content/public/common/weak_wrapper_shared_url_loader_factory.h"
#include "net/base/escape.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_status_code.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -37,7 +37,7 @@ class V4UpdateProtocolManagerTest : public PlatformTest {
SetupStoreStates();
test_shared_loader_factory_ =
- base::MakeRefCounted<content::WeakWrapperSharedURLLoaderFactory>(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_);
}
@@ -302,7 +302,7 @@ TEST_F(V4UpdateProtocolManagerTest, TestDisableAutoUpdates) {
runner->RunPendingTasks();
EXPECT_FALSE(pm->IsUpdateScheduled());
- DCHECK(!pm->request_.get());
+ DCHECK(!pm->request_);
}
TEST_F(V4UpdateProtocolManagerTest, TestGetUpdatesHasTimeout) {
diff --git a/chromium/components/safe_browsing/db/whitelist_checker_client_unittest.cc b/chromium/components/safe_browsing/db/whitelist_checker_client_unittest.cc
index 161b1005327..3110d8a7ba1 100644
--- a/chromium/components/safe_browsing/db/whitelist_checker_client_unittest.cc
+++ b/chromium/components/safe_browsing/db/whitelist_checker_client_unittest.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/test/test_mock_time_task_runner.h"
@@ -55,7 +56,7 @@ class WhitelistCheckerClientTest : public testing::Test {
base::TimeTicks::Now());
message_loop_.reset(new base::MessageLoop);
io_thread_ = std::make_unique<content::TestBrowserThread>(
- content::BrowserThread::IO, base::MessageLoop::current());
+ content::BrowserThread::IO, base::MessageLoopCurrent::Get());
message_loop_->SetTaskRunner(task_runner_);
}
@@ -81,7 +82,7 @@ class WhitelistCheckerClientTest : public testing::Test {
};
TEST_F(WhitelistCheckerClientTest, TestMatch) {
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url_, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
.WillOnce(Return(AsyncMatch::MATCH));
MockBoolCallback callback;
@@ -91,7 +92,7 @@ TEST_F(WhitelistCheckerClientTest, TestMatch) {
}
TEST_F(WhitelistCheckerClientTest, TestNoMatch) {
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url_, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
.WillOnce(Return(AsyncMatch::NO_MATCH));
MockBoolCallback callback;
@@ -102,7 +103,7 @@ TEST_F(WhitelistCheckerClientTest, TestNoMatch) {
TEST_F(WhitelistCheckerClientTest, TestAsyncNoMatch) {
SafeBrowsingDatabaseManager::Client* client;
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url_, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
.WillOnce(DoAll(SaveArg<1>(&client), Return(AsyncMatch::ASYNC)));
MockBoolCallback callback;
@@ -117,9 +118,9 @@ TEST_F(WhitelistCheckerClientTest, TestAsyncNoMatch) {
TEST_F(WhitelistCheckerClientTest, TestAsyncTimeout) {
SafeBrowsingDatabaseManager::Client* client;
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url_, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url_, _))
.WillOnce(DoAll(SaveArg<1>(&client), Return(AsyncMatch::ASYNC)));
- EXPECT_CALL(*database_manager_.get(), CancelCheck(_)).Times(1);
+ EXPECT_CALL(*database_manager_, CancelCheck(_)).Times(1);
MockBoolCallback callback;
WhitelistCheckerClient::StartCheckCsdWhitelist(database_manager_, target_url_,
diff --git a/chromium/components/safe_browsing/features.cc b/chromium/components/safe_browsing/features.cc
index 323eb971bc5..605f52b3926 100644
--- a/chromium/components/safe_browsing/features.cc
+++ b/chromium/components/safe_browsing/features.cc
@@ -30,10 +30,6 @@ const base::Feature kAdSamplerTriggerFeature{"SafeBrowsingAdSamplerTrigger",
// If enabled in pre-network-service world, SafeBrowsing URL checks are done by
// applying SafeBrowsing's URLLoaderThrottle subclasses to ThrottlingURLLoader.
-// It affects:
-// - subresource loading from renderers;
-// - frame resource loading from the browser, if
-// content::IsNavigationMojoResponseEnabled() is true.
//
// This flag has no effect if network service is enabled. With network service,
// SafeBrowsing URL checks are always done by SafeBrowsing's URLLoaderThrottle
@@ -42,32 +38,26 @@ const base::Feature kCheckByURLLoaderThrottle{
"S13nSafeBrowsingCheckByURLLoaderThrottle",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kGaiaPasswordReuseReporting{
- "SyncPasswordReuseEvent", base::FEATURE_DISABLED_BY_DEFAULT};
-
-const base::Feature kGoogleBrandedPhishingWarning{
- "PasswordProtectionGoogleBrandedPhishingWarning",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kThreatDomDetailsTagAndAttributeFeature{
"ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kSuspiciousSiteTriggerQuotaFeature{
+ "SafeBrowsingSuspiciousSiteTriggerQuota",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
const base::Feature kTriggerThrottlerDailyQuotaFeature{
"SafeBrowsingTriggerThrottlerDailyQuota",
base::FEATURE_DISABLED_BY_DEFAULT};
-const base::Feature kDispatchSafetyNetCheckOffThread{
- "DispatchSafetyNetCheckOffThread", base::FEATURE_ENABLED_BY_DEFAULT};
-
-const base::Feature kAppendRecentNavigationEvents{
- "AppendRecentNavigationEvents", base::FEATURE_DISABLED_BY_DEFAULT};
-
const base::Feature kInspectDownloadedRarFiles{
"InspectDownloadedRarFiles", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kEnterprisePasswordProtectionV1{
"EnterprisePasswordProtectionV1", base::FEATURE_DISABLED_BY_DEFAULT};
+const base::Feature kForceEnableResetPasswordWebUI{
+ "ForceEnableResetPasswordWebUI", base::FEATURE_DISABLED_BY_DEFAULT};
+
namespace {
// List of experimental features. Boolean value for each list member should be
// set to true if the experiment is currently running at a probability other
@@ -79,12 +69,9 @@ constexpr struct {
} kExperimentalFeatures[]{
{&kAdSamplerCollectButDontSendFeature, false},
{&kAdSamplerTriggerFeature, false},
- {&kAppendRecentNavigationEvents, true},
{&kCheckByURLLoaderThrottle, true},
- {&kDispatchSafetyNetCheckOffThread, false},
{&kEnterprisePasswordProtectionV1, true},
- {&kGaiaPasswordReuseReporting, true},
- {&kGoogleBrandedPhishingWarning, true},
+ {&kForceEnableResetPasswordWebUI, false},
{&kInspectDownloadedRarFiles, true},
{&kThreatDomDetailsTagAndAttributeFeature, false},
{&kTriggerThrottlerDailyQuotaFeature, false},
diff --git a/chromium/components/safe_browsing/features.h b/chromium/components/safe_browsing/features.h
index 3a8ba49d58f..dd913aa6920 100644
--- a/chromium/components/safe_browsing/features.h
+++ b/chromium/components/safe_browsing/features.h
@@ -22,9 +22,6 @@ namespace safe_browsing {
extern const base::Feature kAdSamplerCollectButDontSendFeature;
extern const base::Feature kAdSamplerTriggerFeature;
extern const base::Feature kCheckByURLLoaderThrottle;
-// Gates logging of GaiaPasswordReuse user events.
-extern const base::Feature kGaiaPasswordReuseReporting;
-extern const base::Feature kGoogleBrandedPhishingWarning;
// Specifies which non-resource HTML Elements to collect based on their tag and
// attributes. It's a single param containing a comma-separated list of pairs.
@@ -34,27 +31,30 @@ extern const base::Feature kGoogleBrandedPhishingWarning;
// be lower case.
extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
+// Controls the daily quota for the suspicious site trigger.
+extern const base::Feature kSuspiciousSiteTriggerQuotaFeature;
+
// Controls the daily quota for data collection triggers. It's a single param
// containing a comma-separated list of pairs. The format of the param is
// "T1,Q1,T2,Q2,...Tn,Qn", where Tx is a TriggerType and Qx is how many reports
// that trigger is allowed to send per day.
+// TODO(crbug.com/744869): This param should be deprecated after ad sampler
+// launch in favour of having a unique quota feature and param per trigger.
+// Having a single shared feature makes it impossible to run multiple trigger
+// trials simultaneously.
extern const base::Feature kTriggerThrottlerDailyQuotaFeature;
-// Controls whether to dispatch the SafetyNet check on a worker thread. Android
-// only.
-extern const base::Feature kDispatchSafetyNetCheckOffThread;
-
-// Controls whether to add recent navigation events to referrer chain for SBER
-// users if referrer chain is incomplete.
-extern const base::Feature kAppendRecentNavigationEvents;
-
// Controls whether .rar files downloaded by the user are inspected for being
// unsafe.
extern const base::Feature kInspectDownloadedRarFiles;
-// Control the Password Protection for Enterprise V1 feature;
+// Controls the Password Protection for Enterprise V1 feature;
extern const base::Feature kEnterprisePasswordProtectionV1;
+// Forces the chrome://reset-password page to be shown for review or testing
+// purpose.
+extern const base::Feature kForceEnableResetPasswordWebUI;
+
base::ListValue GetFeatureStatusList();
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/password_protection/BUILD.gn b/chromium/components/safe_browsing/password_protection/BUILD.gn
index f898a9124d1..d219c28f91b 100644
--- a/chromium/components/safe_browsing/password_protection/BUILD.gn
+++ b/chromium/components/safe_browsing/password_protection/BUILD.gn
@@ -25,6 +25,7 @@ source_set("password_protection") {
"//components/password_manager/core/browser:browser",
"//components/safe_browsing:csd_proto",
"//components/safe_browsing:features",
+ "//components/safe_browsing/common:common",
"//components/safe_browsing/common:safe_browsing_prefs",
"//components/safe_browsing/db:database_manager",
"//components/safe_browsing/db:v4_protocol_manager_util",
@@ -44,6 +45,7 @@ source_set("password_protection_unittest") {
"password_protection_service_unittest.cc",
]
deps = [
+ ":mock_password_protection",
":password_protection",
"//base",
"//base/test:test_support",
@@ -62,3 +64,23 @@ source_set("password_protection_unittest") {
]
}
}
+
+source_set("mock_password_protection") {
+ testonly = true
+ if (!is_android && !is_ios) {
+ sources = [
+ "mock_password_protection_service.cc",
+ "mock_password_protection_service.h",
+ ]
+ deps = [
+ ":password_protection",
+ "//base",
+ "//components/content_settings/core/browser:browser",
+ "//components/safe_browsing/db:database_manager",
+ "//net:test_support",
+ "//services/network/public/cpp:cpp",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/chromium/components/safe_browsing/password_protection/mock_password_protection_service.cc b/chromium/components/safe_browsing/password_protection/mock_password_protection_service.cc
new file mode 100644
index 00000000000..3c372d0e596
--- /dev/null
+++ b/chromium/components/safe_browsing/password_protection/mock_password_protection_service.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/safe_browsing/password_protection/mock_password_protection_service.h"
+
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/safe_browsing/db/database_manager.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+namespace safe_browsing {
+
+MockPasswordProtectionService::MockPasswordProtectionService()
+ : PasswordProtectionService(nullptr, nullptr, nullptr, nullptr) {}
+
+MockPasswordProtectionService::MockPasswordProtectionService(
+ const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ scoped_refptr<HostContentSettingsMap> content_setting_map)
+ : PasswordProtectionService(database_manager,
+ url_loader_factory,
+ nullptr,
+ content_setting_map.get()) {}
+
+MockPasswordProtectionService::~MockPasswordProtectionService() {}
+
+} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/password_protection/mock_password_protection_service.h b/chromium/components/safe_browsing/password_protection/mock_password_protection_service.h
new file mode 100644
index 00000000000..7accf1edb73
--- /dev/null
+++ b/chromium/components/safe_browsing/password_protection/mock_password_protection_service.h
@@ -0,0 +1,78 @@
+// 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 COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_MOCK_PASSWORD_PROTECTION_SERVICE_H_
+#define COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_MOCK_PASSWORD_PROTECTION_SERVICE_H_
+
+#include "base/macros.h"
+#include "components/safe_browsing/password_protection/password_protection_service.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace safe_browsing {
+
+class MockPasswordProtectionService : public PasswordProtectionService {
+ public:
+ MockPasswordProtectionService();
+ MockPasswordProtectionService(
+ const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ scoped_refptr<HostContentSettingsMap> content_setting_map);
+ ~MockPasswordProtectionService() override;
+
+ // safe_browsing::PasswordProtectionService
+ MOCK_CONST_METHOD0(GetSyncAccountType,
+ safe_browsing::LoginReputationClientRequest::
+ PasswordReuseEvent::SyncAccountType());
+ MOCK_CONST_METHOD0(GetBrowserPolicyConnector,
+ const policy::BrowserPolicyConnector*());
+ MOCK_CONST_METHOD0(GetPasswordProtectionWarningTriggerPref,
+ safe_browsing::PasswordProtectionTrigger());
+ MOCK_CONST_METHOD2(IsURLWhitelistedForPasswordEntry,
+ bool(const GURL&, RequestOutcome*));
+
+ MOCK_METHOD0(IsExtendedReporting, bool());
+ MOCK_METHOD0(IsIncognito, bool());
+ MOCK_METHOD0(IsHistorySyncEnabled, bool());
+ MOCK_METHOD0(OnPolicySpecifiedPasswordChanged, void());
+ MOCK_METHOD1(MaybeLogPasswordReuseDetectedEvent, void(content::WebContents*));
+ MOCK_METHOD1(UserClickedThroughSBInterstitial, bool(content::WebContents*));
+ MOCK_METHOD1(ShowInterstitial, void(content::WebContents*));
+ MOCK_METHOD2(IsPingingEnabled,
+ bool(safe_browsing::LoginReputationClientRequest::TriggerType,
+ RequestOutcome*));
+ MOCK_METHOD2(ShowModalWarning,
+ void(content::WebContents*, const std::string&));
+ MOCK_METHOD2(UpdateSecurityState,
+ void(safe_browsing::SBThreatType, content::WebContents*));
+ MOCK_METHOD2(RemoveUnhandledSyncPasswordReuseOnURLsDeleted,
+ void(bool, const history::URLRows&));
+ MOCK_METHOD2(OnPolicySpecifiedPasswordReuseDetected, void(const GURL&, bool));
+ MOCK_METHOD3(FillReferrerChain,
+ void(const GURL&,
+ SessionID,
+ safe_browsing::LoginReputationClientRequest::Frame*));
+ MOCK_METHOD3(MaybeLogPasswordReuseLookupEvent,
+ void(content::WebContents*,
+ PasswordProtectionService::RequestOutcome,
+ const safe_browsing::LoginReputationClientResponse*));
+ MOCK_METHOD3(OnUserAction,
+ void(content::WebContents*, WarningUIType, WarningAction));
+
+ MOCK_METHOD4(
+ MaybeStartPasswordFieldOnFocusRequest,
+ void(content::WebContents*, const GURL&, const GURL&, const GURL&));
+ MOCK_METHOD5(MaybeStartProtectedPasswordEntryRequest,
+ void(content::WebContents*,
+ const GURL&,
+ bool,
+ const std::vector<std::string>&,
+ bool));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockPasswordProtectionService);
+};
+
+} // namespace safe_browsing
+
+#endif // COMPONENTS_SAFE_BROWSING_PASSWORD_PROTECTION_MOCK_PASSWORD_PROTECTION_SERVICE_H_
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_request.cc b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
index 903784f2904..06345bf5500 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_request.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_request.cc
@@ -257,13 +257,13 @@ void PasswordProtectionRequest::SendRequest() {
cookies_store: "Safe Browsing Cookie Store"
setting:
"Users can control this feature via 'Protect you and your device "
- "from dangerous sites' or 'Automatically report details of "
- "possible security incidents to Google' setting under 'Privacy'. "
- "By default, the first setting is enabled and the second is not."
+ "from dangerous sites'. By default, this setting is enabled."
+ "Alternatively, you can turn it off via "
+ "'PasswordProtectionWarningTrigger' enterprise policy setting."
chrome_policy {
- SafeBrowsingExtendedReportingOptInAllowed {
+ PasswordProtectionWarningTrigger {
policy_options {mode: MANDATORY}
- SafeBrowsingExtendedReportingOptInAllowed: false
+ PasswordProtectionWarningTrigger: 2
}
}
})");
@@ -316,11 +316,11 @@ void PasswordProtectionRequest::OnURLLoaderComplete(
std::unique_ptr<LoginReputationClientResponse> response =
std::make_unique<LoginReputationClientResponse>();
- DCHECK(response_body.get());
+ DCHECK(response_body);
url_loader_.reset(); // We don't need it anymore.
UMA_HISTOGRAM_TIMES("PasswordProtection.RequestNetworkDuration",
base::TimeTicks::Now() - request_start_time_);
- if (response_body.get() && response->ParseFromString(*response_body.get()))
+ if (response_body && response->ParseFromString(*response_body))
Finish(PasswordProtectionService::SUCCEEDED, std::move(response));
else
Finish(PasswordProtectionService::RESPONSE_MALFORMED, nullptr);
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service.cc b/chromium/components/safe_browsing/password_protection/password_protection_service.cc
index a963a01bb67..d393546c3cf 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service.cc
@@ -14,13 +14,14 @@
#include "base/callback.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/field_trial_params.h"
-#include "base/metrics/histogram_macros.h"
+#include "base/metrics/histogram_functions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "components/history/core/browser/history_service.h"
#include "components/password_manager/core/browser/password_reuse_detector.h"
+#include "components/safe_browsing/common/utils.h"
#include "components/safe_browsing/db/database_manager.h"
#include "components/safe_browsing/db/whitelist_checker_client.h"
#include "components/safe_browsing/features.h"
@@ -95,6 +96,8 @@ const char kSyncPasswordPageInfoHistogram[] =
"PasswordProtection.PageInfoAction.SyncPasswordEntry";
const char kSyncPasswordChromeSettingsHistogram[] =
"PasswordProtection.ChromeSettingsAction.SyncPasswordEntry";
+const char kSyncPasswordInterstitialHistogram[] =
+ "PasswordProtection.InterstitialAction.SyncPasswordEntry";
PasswordProtectionService::PasswordProtectionService(
const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
@@ -133,19 +136,22 @@ void PasswordProtectionService::RecordWarningAction(WarningUIType ui_type,
WarningAction action) {
switch (ui_type) {
case PAGE_INFO:
- UMA_HISTOGRAM_ENUMERATION(kSyncPasswordPageInfoHistogram, action,
- MAX_ACTION);
+ base::UmaHistogramEnumeration(kSyncPasswordPageInfoHistogram, action,
+ MAX_ACTION);
break;
case MODAL_DIALOG:
- UMA_HISTOGRAM_ENUMERATION(kSyncPasswordWarningDialogHistogram, action,
- MAX_ACTION);
+ base::UmaHistogramEnumeration(kSyncPasswordWarningDialogHistogram, action,
+ MAX_ACTION);
break;
case CHROME_SETTINGS:
- UMA_HISTOGRAM_ENUMERATION(kSyncPasswordChromeSettingsHistogram, action,
- MAX_ACTION);
+ base::UmaHistogramEnumeration(kSyncPasswordChromeSettingsHistogram,
+ action, MAX_ACTION);
+ break;
+ case INTERSTITIAL:
+ base::UmaHistogramEnumeration(kSyncPasswordInterstitialHistogram, action,
+ MAX_ACTION);
break;
case NOT_USED:
- case MAX_UI_TYPE:
NOTREACHED();
break;
}
@@ -163,18 +169,10 @@ bool PasswordProtectionService::ShouldShowModalWarning(
}
return (verdict_type == LoginReputationClientResponse::PHISHING ||
- (verdict_type == LoginReputationClientResponse::LOW_REPUTATION &&
- base::GetFieldTrialParamByFeatureAsBool(
- kGoogleBrandedPhishingWarning, "warn_on_low_reputation",
- false))) &&
+ verdict_type == LoginReputationClientResponse::LOW_REPUTATION) &&
IsWarningEnabled();
}
-bool PasswordProtectionService::ShouldShowSofterWarning() {
- return base::GetFieldTrialParamByFeatureAsBool(kGoogleBrandedPhishingWarning,
- "softer_warning", false);
-}
-
// We cache both types of pings under the same content settings type (
// CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION). Since UNFAMILIAR_LOGIN_PAGE
// verdicts are only enabled on extended reporting users, we cache them one
@@ -202,7 +200,7 @@ PasswordProtectionService::GetCachedVerdict(
hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
std::string(), nullptr));
- if (!cache_dictionary.get() || cache_dictionary->empty())
+ if (!cache_dictionary || cache_dictionary->empty())
return LoginReputationClientResponse::VERDICT_TYPE_UNSPECIFIED;
base::DictionaryValue* verdict_dictionary = nullptr;
@@ -282,7 +280,7 @@ void PasswordProtectionService::CacheVerdict(
hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
std::string(), nullptr));
- if (!cache_dictionary || !cache_dictionary.get())
+ if (!cache_dictionary || !cache_dictionary)
cache_dictionary = std::make_unique<base::DictionaryValue>();
std::unique_ptr<base::DictionaryValue> verdict_entry(
@@ -389,8 +387,9 @@ void PasswordProtectionService::MaybeStartPasswordFieldOnFocusRequest(
const GURL& password_form_action,
const GURL& password_form_frame_url) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RequestOutcome reason;
if (CanSendPing(LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
- main_frame_url, false)) {
+ main_frame_url, false, &reason)) {
StartRequest(web_contents, main_frame_url, password_form_action,
password_form_frame_url,
false, /* matches_sync_password: not used for this type */
@@ -406,26 +405,33 @@ void PasswordProtectionService::MaybeStartProtectedPasswordEntryRequest(
const std::vector<std::string>& matching_domains,
bool password_field_exists) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+ RequestOutcome reason;
if (CanSendPing(LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- main_frame_url, matches_sync_password)) {
+ main_frame_url, matches_sync_password, &reason)) {
StartRequest(web_contents, main_frame_url, GURL(), GURL(),
matches_sync_password, matching_domains,
LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
password_field_exists);
+ } else {
+ MaybeLogPasswordReuseLookupEvent(web_contents, reason, nullptr);
+ if (reason == PASSWORD_ALERT_MODE && matches_sync_password) {
+ ShowInterstitial(web_contents);
+ }
}
}
bool PasswordProtectionService::CanSendPing(
LoginReputationClientRequest::TriggerType trigger_type,
const GURL& main_frame_url,
- bool matches_sync_password) {
- RequestOutcome request_outcome = URL_NOT_VALID_FOR_REPUTATION_COMPUTING;
- if (IsPingingEnabled(trigger_type, &request_outcome) &&
- !IsURLWhitelistedForPasswordEntry(main_frame_url, &request_outcome) &&
+ bool matches_sync_password,
+ RequestOutcome* reason) {
+ *reason = URL_NOT_VALID_FOR_REPUTATION_COMPUTING;
+ if (IsPingingEnabled(trigger_type, reason) &&
+ !IsURLWhitelistedForPasswordEntry(main_frame_url, reason) &&
CanGetReputationOfURL(main_frame_url)) {
return true;
}
- RecordNoPingingReason(trigger_type, request_outcome, matches_sync_password);
+ RecordNoPingingReason(trigger_type, *reason, matches_sync_password);
return false;
}
@@ -546,24 +552,25 @@ void PasswordProtectionService::FillUserPopulation(
user_population->set_user_population(
IsExtendedReporting() ? ChromeUserPopulation::EXTENDED_REPORTING
: ChromeUserPopulation::SAFE_BROWSING);
+ user_population->set_profile_management_status(
+ GetProfileManagementStatus(GetBrowserPolicyConnector()));
user_population->set_is_history_sync_enabled(IsHistorySyncEnabled());
}
void PasswordProtectionService::OnURLsDeleted(
history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
+ const history::DeletionInfo& deletion_info) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PasswordProtectionService::RemoveContentSettingsOnURLsDeleted,
- GetWeakPtr(), all_history, deleted_rows));
+ GetWeakPtr(), deletion_info.IsAllHistory(),
+ deletion_info.deleted_rows()));
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PasswordProtectionService::
RemoveUnhandledSyncPasswordReuseOnURLsDeleted,
- GetWeakPtr(), all_history, deleted_rows));
+ GetWeakPtr(), deletion_info.IsAllHistory(),
+ deletion_info.deleted_rows()));
}
void PasswordProtectionService::HistoryServiceBeingDeleted(
@@ -619,7 +626,7 @@ int PasswordProtectionService::GetVerdictCountForURL(
base::DictionaryValue::From(content_settings_->GetWebsiteSetting(
url, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION, std::string(),
nullptr));
- if (!cache_dictionary.get() || cache_dictionary->empty())
+ if (!cache_dictionary || cache_dictionary->empty())
return 0;
if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
@@ -772,8 +779,8 @@ void PasswordProtectionService::RecordNoPingingReason(
trigger_type == LoginReputationClientRequest::PASSWORD_REUSE_EVENT);
if (trigger_type == LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE) {
- UMA_HISTOGRAM_ENUMERATION(kPasswordOnFocusRequestOutcomeHistogram, reason,
- MAX_OUTCOME);
+ base::UmaHistogramEnumeration(kPasswordOnFocusRequestOutcomeHistogram,
+ reason, MAX_OUTCOME);
return;
}
@@ -784,14 +791,14 @@ void PasswordProtectionService::RecordNoPingingReason(
void PasswordProtectionService::LogPasswordEntryRequestOutcome(
RequestOutcome reason,
bool matches_sync_password) {
- UMA_HISTOGRAM_ENUMERATION(kAnyPasswordEntryRequestOutcomeHistogram, reason,
- MAX_OUTCOME);
+ base::UmaHistogramEnumeration(kAnyPasswordEntryRequestOutcomeHistogram,
+ reason, MAX_OUTCOME);
if (matches_sync_password) {
- UMA_HISTOGRAM_ENUMERATION(kSyncPasswordEntryRequestOutcomeHistogram, reason,
- MAX_OUTCOME);
+ base::UmaHistogramEnumeration(kSyncPasswordEntryRequestOutcomeHistogram,
+ reason, MAX_OUTCOME);
} else {
- UMA_HISTOGRAM_ENUMERATION(kProtectedPasswordEntryRequestOutcomeHistogram,
- reason, MAX_OUTCOME);
+ base::UmaHistogramEnumeration(
+ kProtectedPasswordEntryRequestOutcomeHistogram, reason, MAX_OUTCOME);
}
}
@@ -841,15 +848,12 @@ bool PasswordProtectionService::IsModalWarningShowingInWebContents(
}
bool PasswordProtectionService::IsWarningEnabled() {
- return base::FeatureList::IsEnabled(kGoogleBrandedPhishingWarning) &&
- GetPasswordProtectionTriggerPref(
- prefs::kPasswordProtectionWarningTrigger) == PHISHING_REUSE;
+ return GetPasswordProtectionWarningTriggerPref() == PHISHING_REUSE;
}
bool PasswordProtectionService::IsEventLoggingEnabled() {
- return base::FeatureList::IsEnabled(kGaiaPasswordReuseReporting) &&
- GetPasswordProtectionTriggerPref(
- prefs::kPasswordProtectionRiskTrigger) == PHISHING_REUSE;
+ return GetSyncAccountType() !=
+ LoginReputationClientRequest::PasswordReuseEvent::NOT_SIGNED_IN;
}
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service.h b/chromium/components/safe_browsing/password_protection/password_protection_service.h
index b4ae0a3326a..c1f4f43a84a 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service.h
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service.h
@@ -34,6 +34,10 @@ namespace history {
class HistoryService;
}
+namespace policy {
+class BrowserPolicyConnector;
+}
+
class GURL;
class HostContentSettingsMap;
@@ -79,6 +83,11 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
MATCHED_ENTERPRISE_WHITELIST = 15,
MATCHED_ENTERPRISE_CHANGE_PASSWORD_URL = 16,
MATCHED_ENTERPRISE_LOGIN_URL = 17,
+ // No request is ever sent if the admin configures password protection to
+ // warn on ALL password reuses (rather than just phishing sites).
+ PASSWORD_ALERT_MODE = 18,
+ // No request is event sent if the admin turns off password protection.
+ TURNED_OFF_BY_ADMIN = 19,
MAX_OUTCOME
};
@@ -110,7 +119,7 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
PAGE_INFO = 1,
MODAL_DIALOG = 2,
CHROME_SETTINGS = 3,
- MAX_UI_TYPE
+ INTERSTITIAL = 4
};
PasswordProtectionService(
@@ -198,14 +207,14 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
virtual void ShowModalWarning(content::WebContents* web_contents,
const std::string& verdict_token) = 0;
+ // Shows chrome://reset-password interstitial.
+ virtual void ShowInterstitial(content::WebContents* web_contens) = 0;
+
// Called when user interacts with warning UIs.
virtual void OnUserAction(content::WebContents* web_contents,
WarningUIType ui_type,
WarningAction action) = 0;
- // If we want to show softer warnings based on Finch parameters.
- static bool ShouldShowSofterWarning();
-
virtual void UpdateSecurityState(safe_browsing::SBThreatType threat_type,
content::WebContents* web_contents) = 0;
@@ -231,9 +240,9 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// Returns if the event logging is enabled.
bool IsEventLoggingEnabled();
- // Returns the pref value of password protection trigger.
- virtual PasswordProtectionTrigger GetPasswordProtectionTriggerPref(
- const std::string& pref_name) const = 0;
+ // Returns the pref value of password protection warning trigger.
+ virtual PasswordProtectionTrigger GetPasswordProtectionWarningTriggerPref()
+ const = 0;
// If |url| matches Safe Browsing whitelist domains, password protection
// change password URL, or password protection login URLs in the enterprise
@@ -242,16 +251,27 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
const GURL& url,
RequestOutcome* reason) const = 0;
+ // Called when password reuse warning or phishing reuse warning is shown.
+ // Must be called on UI thread.
+ virtual void OnPolicySpecifiedPasswordReuseDetected(const GURL& url,
+ bool is_phishing_url) = 0;
+
+ // Called when a protected password change is detected. Must be called on
+ // UI thread.
+ virtual void OnPolicySpecifiedPasswordChanged() = 0;
+
protected:
friend class PasswordProtectionRequest;
// Chrome can send password protection ping if it is allowed by Finch config
// and if Safe Browsing can compute reputation of |main_frame_url| (e.g.
// Safe Browsing is not able to compute reputation of a private IP or
- // a local host). |matches_sync_password| is used for UMA metric recording.
+ // a local host). Update |reason| if sending ping is not allowed.
+ // |matches_sync_password| is used for UMA metric recording.
bool CanSendPing(LoginReputationClientRequest::TriggerType trigger_type,
const GURL& main_frame_url,
- bool matches_sync_password);
+ bool matches_sync_password,
+ RequestOutcome* reason);
// Called by a PasswordProtectionRequest instance when it finishes to remove
// itself from |requests_|.
@@ -269,6 +289,10 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
virtual int GetStoredVerdictCount(
LoginReputationClientRequest::TriggerType trigger_type);
+ // Gets an unowned |BrowserPolicyConnector| for the current platform.
+ virtual const policy::BrowserPolicyConnector* GetBrowserPolicyConnector()
+ const = 0;
+
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory() {
return url_loader_factory_;
}
@@ -338,10 +362,7 @@ class PasswordProtectionService : public history::HistoryServiceObserver {
// Overridden from history::HistoryServiceObserver.
void OnURLsDeleted(history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const history::DeletionInfo& deletion_info) override;
void HistoryServiceBeingDeleted(
history::HistoryService* history_service) override;
diff --git a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 3db8e9e11b4..9c2f2f6d3ab 100644
--- a/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/chromium/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -15,10 +15,11 @@
#include "components/password_manager/core/browser/password_reuse_detector.h"
#include "components/safe_browsing/db/test_database_manager.h"
#include "components/safe_browsing/features.h"
+#include "components/safe_browsing/password_protection/mock_password_protection_service.h"
#include "components/safe_browsing/password_protection/password_protection_request.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
-#include "content/public/common/weak_wrapper_shared_url_loader_factory.h"
#include "content/public/test/test_browser_thread_bundle.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -56,22 +57,15 @@ class MockSafeBrowsingDatabaseManager : public TestSafeBrowsingDatabaseManager {
DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
};
-class TestPasswordProtectionService : public PasswordProtectionService {
+class TestPasswordProtectionService : public MockPasswordProtectionService {
public:
TestPasswordProtectionService(
const scoped_refptr<SafeBrowsingDatabaseManager>& database_manager,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
scoped_refptr<HostContentSettingsMap> content_setting_map)
- : PasswordProtectionService(database_manager,
- url_loader_factory,
- nullptr,
- content_setting_map.get()),
- is_extended_reporting_(true),
- is_incognito_(false),
- latest_request_(nullptr),
- password_protection_trigger_(PASSWORD_PROTECTION_OFF),
- sync_account_type_(
- LoginReputationClientRequest::PasswordReuseEvent::NOT_SIGNED_IN) {}
+ : MockPasswordProtectionService(database_manager,
+ url_loader_factory,
+ content_setting_map.get()) {}
void RequestFinished(
PasswordProtectionRequest* request,
@@ -82,38 +76,6 @@ class TestPasswordProtectionService : public PasswordProtectionService {
run_loop_.Quit();
}
- bool IsExtendedReporting() override { return is_extended_reporting_; }
-
- bool IsIncognito() override { return is_incognito_; }
-
- void set_extended_reporting(bool enabled) {
- is_extended_reporting_ = enabled;
- }
-
- void set_incognito(bool enabled) { is_incognito_ = enabled; }
-
- bool IsPingingEnabled(LoginReputationClientRequest::TriggerType trigger_type,
- RequestOutcome* reason) override {
- return true;
- }
-
- void MaybeLogPasswordReuseLookupEvent(
- content::WebContents* web_contents,
- PasswordProtectionService::RequestOutcome,
- const LoginReputationClientResponse*) override {}
-
- bool IsHistorySyncEnabled() override { return false; }
-
- LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType
- GetSyncAccountType() const override {
- return sync_account_type_;
- }
-
- void set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType type) {
- sync_account_type_ = type;
- }
-
LoginReputationClientResponse* latest_response() {
return latest_response_.get();
}
@@ -128,44 +90,10 @@ class TestPasswordProtectionService : public PasswordProtectionService {
return latest_request_ ? latest_request_->request_proto() : nullptr;
}
- void set_password_protection_trigger(PasswordProtectionTrigger trigger) {
- password_protection_trigger_ = trigger;
- }
-
- PasswordProtectionTrigger GetPasswordProtectionTriggerPref(
- const std::string& pref_name_unused) const override {
- return password_protection_trigger_;
- }
-
- bool IsURLWhitelistedForPasswordEntry(const GURL& url,
- RequestOutcome* reason) const override {
- return false;
- }
-
- MOCK_METHOD3(FillReferrerChain,
- void(const GURL&,
- SessionID,
- LoginReputationClientRequest::Frame*));
- MOCK_METHOD1(MaybeLogPasswordReuseDetectedEvent, void(content::WebContents*));
- MOCK_METHOD2(ShowModalWarning,
- void(content::WebContents*, const std::string&));
- MOCK_METHOD3(OnUserAction,
- void(content::WebContents*, WarningUIType, WarningAction));
- MOCK_METHOD2(UpdateSecurityState,
- void(safe_browsing::SBThreatType, content::WebContents*));
- MOCK_METHOD1(UserClickedThroughSBInterstitial, bool(content::WebContents*));
- MOCK_METHOD2(RemoveUnhandledSyncPasswordReuseOnURLsDeleted,
- void(bool, const history::URLRows&));
-
private:
- bool is_extended_reporting_;
- bool is_incognito_;
PasswordProtectionRequest* latest_request_;
base::RunLoop run_loop_;
std::unique_ptr<LoginReputationClientResponse> latest_response_;
- PasswordProtectionTrigger password_protection_trigger_;
- LoginReputationClientRequest::PasswordReuseEvent::SyncAccountType
- sync_account_type_;
DISALLOW_COPY_AND_ASSIGN(TestPasswordProtectionService);
};
@@ -194,13 +122,24 @@ class PasswordProtectionServiceTest
password_protection_service_ =
std::make_unique<TestPasswordProtectionService>(
database_manager_,
- base::MakeRefCounted<content::WeakWrapperSharedURLLoaderFactory>(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_),
content_setting_map_);
ASSERT_EQ(2ul, GetParam().size());
- password_protection_service_->set_extended_reporting(GetParam()[0]);
- password_protection_service_->set_incognito(GetParam()[1]);
+ EXPECT_CALL(*password_protection_service_, IsExtendedReporting())
+ .WillRepeatedly(Return(GetParam()[0]));
+ EXPECT_CALL(*password_protection_service_, IsIncognito())
+ .WillRepeatedly(Return(GetParam()[1]));
+ EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+ .WillRepeatedly(Return(
+ LoginReputationClientRequest::PasswordReuseEvent::NOT_SIGNED_IN));
+ EXPECT_CALL(*password_protection_service_,
+ IsURLWhitelistedForPasswordEntry(_, _))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*password_protection_service_,
+ GetPasswordProtectionWarningTriggerPref())
+ .WillRepeatedly(Return(PASSWORD_PROTECTION_OFF));
url_ = PasswordProtectionService::GetPasswordProtectionRequestUrl();
}
@@ -210,7 +149,7 @@ class PasswordProtectionServiceTest
void InitializeAndStartPasswordOnFocusRequest(bool match_whitelist,
int timeout_in_ms) {
GURL target_url(kTargetUrl);
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url, _))
.WillRepeatedly(
Return(match_whitelist ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH));
@@ -228,7 +167,7 @@ class PasswordProtectionServiceTest
bool match_whitelist,
int timeout_in_ms) {
GURL target_url(kTargetUrl);
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url, _))
.WillRepeatedly(
Return(match_whitelist ? AsyncMatch::MATCH : AsyncMatch::NO_MATCH));
@@ -268,7 +207,7 @@ class PasswordProtectionServiceTest
invalid_hostname, GURL(), CONTENT_SETTINGS_TYPE_PASSWORD_PROTECTION,
std::string(), nullptr));
- if (!verdict_dictionary.get())
+ if (!verdict_dictionary)
verdict_dictionary = std::make_unique<base::DictionaryValue>();
std::unique_ptr<base::DictionaryValue> invalid_verdict_entry =
@@ -813,7 +752,7 @@ TEST_P(PasswordProtectionServiceTest,
TEST_P(PasswordProtectionServiceTest, TestTearDownWithPendingRequests) {
histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
GURL target_url(kTargetUrl);
- EXPECT_CALL(*database_manager_.get(), CheckCsdWhitelistUrl(target_url, _))
+ EXPECT_CALL(*database_manager_, CheckCsdWhitelistUrl(target_url, _))
.WillRepeatedly(Return(AsyncMatch::NO_MATCH));
password_protection_service_->StartRequest(
nullptr, target_url, GURL("http://foo.com/submit"),
@@ -1016,150 +955,85 @@ TEST_P(PasswordProtectionServiceTest,
}
TEST_P(PasswordProtectionServiceTest, VerifyShouldShowModalWarning) {
- {
- base::test::ScopedFeatureList scoped_feature_list1;
- scoped_feature_list1.InitAndDisableFeature(
- safe_browsing::kGoogleBrandedPhishingWarning);
- // Don't show modal warning if feature is disabled.
- EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
- }
+ EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+ .WillRepeatedly(
+ Return(LoginReputationClientRequest::PasswordReuseEvent::GMAIL));
+ EXPECT_CALL(*password_protection_service_,
+ GetPasswordProtectionWarningTriggerPref())
+ .WillRepeatedly(Return(PHISHING_REUSE));
+
+ // Don't show modal warning if it is not a password reuse ping.
+ EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
+ LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
+ /*matches_sync_password=*/true, LoginReputationClientResponse::PHISHING));
+
+ // Don't show modal warning if it is not a sync password reuse.
+ EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ /*matches_sync_password=*/false,
+ LoginReputationClientResponse::PHISHING));
- {
- base::test::ScopedFeatureList scoped_feature_list2;
- scoped_feature_list2.InitAndEnableFeatureWithParameters(
- safe_browsing::kGoogleBrandedPhishingWarning,
- {{"softer_warning", "true"}, {"warn_on_low_reputation", "false"}});
- password_protection_service_->set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::GMAIL);
- password_protection_service_->set_password_protection_trigger(
- PHISHING_REUSE);
-
- // Don't show modal warning if it is not a password reuse ping.
- EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::UNFAMILIAR_LOGIN_PAGE,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
-
- // Don't show modal warning if it is not a sync password reuse.
- EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/false,
- LoginReputationClientResponse::PHISHING));
-
- // Show modal warning otherwise
- EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
-
- // For a GSUITE account, don't show warning if password protection is off.
- password_protection_service_->set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::GSUITE);
- password_protection_service_->set_password_protection_trigger(
- PASSWORD_PROTECTION_OFF);
- EXPECT_EQ(PASSWORD_PROTECTION_OFF,
- password_protection_service_->GetPasswordProtectionTriggerPref(
- prefs::kPasswordProtectionWarningTrigger));
- EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
-
- // For a GSUITE account, show warning if password protection is set to
- // PHISHING_REUSE.
- password_protection_service_->set_password_protection_trigger(
- PHISHING_REUSE);
- EXPECT_EQ(PHISHING_REUSE,
- password_protection_service_->GetPasswordProtectionTriggerPref(
- prefs::kPasswordProtectionWarningTrigger));
- EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
-
- // When "warn_on_low_reputation" is set to false, don't show modal warning
- // on LOW_REPUTATION verdict, only show on PHISHING verdict.
- password_protection_service_->set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::GMAIL);
- EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::LOW_REPUTATION));
- EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
- }
- {
- base::test::ScopedFeatureList scoped_feature_list3;
- // When "warn_on_low_reputation" is set to true, show modal warning on both
- // LOW_REPUTATION and PHISHING verdict.
- scoped_feature_list3.InitAndEnableFeatureWithParameters(
- safe_browsing::kGoogleBrandedPhishingWarning,
- {{"softer_warning", "true"}, {"warn_on_low_reputation", "true"}});
- EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::LOW_REPUTATION));
- EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
- LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
- /*matches_sync_password=*/true,
- LoginReputationClientResponse::PHISHING));
- }
+ // Show modal warning otherwise
+ EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ /*matches_sync_password=*/true, LoginReputationClientResponse::PHISHING));
+
+ // For a GSUITE account, don't show warning if password protection is off.
+ EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+ .WillRepeatedly(
+ Return(LoginReputationClientRequest::PasswordReuseEvent::GSUITE));
+ EXPECT_CALL(*password_protection_service_,
+ GetPasswordProtectionWarningTriggerPref())
+ .WillRepeatedly(Return(PASSWORD_PROTECTION_OFF));
+ EXPECT_EQ(
+ PASSWORD_PROTECTION_OFF,
+ password_protection_service_->GetPasswordProtectionWarningTriggerPref());
+ EXPECT_FALSE(password_protection_service_->ShouldShowModalWarning(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ /*matches_sync_password=*/true, LoginReputationClientResponse::PHISHING));
+
+ // For a GSUITE account, show warning if password protection is set to
+ // PHISHING_REUSE.
+ EXPECT_CALL(*password_protection_service_,
+ GetPasswordProtectionWarningTriggerPref())
+ .WillRepeatedly(Return(PHISHING_REUSE));
+ EXPECT_EQ(
+ PHISHING_REUSE,
+ password_protection_service_->GetPasswordProtectionWarningTriggerPref());
+ EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ /*matches_sync_password=*/true, LoginReputationClientResponse::PHISHING));
+
+ // Modal dialog warning is also shown on LOW_REPUTATION verdict.
+ EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+ .WillRepeatedly(
+ Return(LoginReputationClientRequest::PasswordReuseEvent::GMAIL));
+ EXPECT_TRUE(password_protection_service_->ShouldShowModalWarning(
+ LoginReputationClientRequest::PASSWORD_REUSE_EVENT,
+ /*matches_sync_password=*/true,
+ LoginReputationClientResponse::LOW_REPUTATION));
}
TEST_P(PasswordProtectionServiceTest, VerifyIsEventLoggingEnabled) {
- {
- // Event logging should be disabled if feature is disabled.
- base::test::ScopedFeatureList scoped_feature_list1;
- scoped_feature_list1.InitAndDisableFeature(kGaiaPasswordReuseReporting);
- EXPECT_FALSE(password_protection_service_->IsEventLoggingEnabled());
- }
-
- {
- base::test::ScopedFeatureList scoped_feature_list2;
- scoped_feature_list2.InitAndEnableFeature(
- safe_browsing::kGaiaPasswordReuseReporting);
-
- // For user who is not signed-in, event logging should be disabled.
- EXPECT_EQ(LoginReputationClientRequest::PasswordReuseEvent::NOT_SIGNED_IN,
- password_protection_service_->GetSyncAccountType());
- EXPECT_FALSE(password_protection_service_->IsEventLoggingEnabled());
-
- // Event logging should be enable for all signed-in users, if
- // password protection trigger is set to PHISHING_REUSE.
- password_protection_service_->set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::GMAIL);
- password_protection_service_->set_password_protection_trigger(
- PHISHING_REUSE);
- EXPECT_EQ(LoginReputationClientRequest::PasswordReuseEvent::GMAIL,
- password_protection_service_->GetSyncAccountType());
- EXPECT_TRUE(password_protection_service_->IsEventLoggingEnabled());
-
- password_protection_service_->set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::GSUITE);
- EXPECT_EQ(LoginReputationClientRequest::PasswordReuseEvent::GSUITE,
- password_protection_service_->GetSyncAccountType());
- EXPECT_TRUE(password_protection_service_->IsEventLoggingEnabled());
-
- // If password protection trigger is sent to off, then event logging
- // should be disabled.
- password_protection_service_->set_password_protection_trigger(
- PASSWORD_PROTECTION_OFF);
- EXPECT_EQ(PASSWORD_PROTECTION_OFF,
- password_protection_service_->GetPasswordProtectionTriggerPref(
- prefs::kPasswordProtectionRiskTrigger));
- EXPECT_FALSE(password_protection_service_->IsEventLoggingEnabled());
- password_protection_service_->set_sync_account_type(
- LoginReputationClientRequest::PasswordReuseEvent::GMAIL);
- EXPECT_FALSE(password_protection_service_->IsEventLoggingEnabled());
-
- // TODO(jialiul): update test when we start to introduce PASSWORD_REUSE
- // trigger.
- }
+ // For user who is not signed-in, event logging should be disabled.
+ EXPECT_EQ(LoginReputationClientRequest::PasswordReuseEvent::NOT_SIGNED_IN,
+ password_protection_service_->GetSyncAccountType());
+ EXPECT_FALSE(password_protection_service_->IsEventLoggingEnabled());
+
+ // Event logging should be enable for all signed-in users..
+ EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+ .WillRepeatedly(
+ Return(LoginReputationClientRequest::PasswordReuseEvent::GMAIL));
+ EXPECT_EQ(LoginReputationClientRequest::PasswordReuseEvent::GMAIL,
+ password_protection_service_->GetSyncAccountType());
+ EXPECT_TRUE(password_protection_service_->IsEventLoggingEnabled());
+
+ EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+ .WillRepeatedly(
+ Return(LoginReputationClientRequest::PasswordReuseEvent::GSUITE));
+ EXPECT_EQ(LoginReputationClientRequest::PasswordReuseEvent::GSUITE,
+ password_protection_service_->GetSyncAccountType());
+ EXPECT_TRUE(password_protection_service_->IsEventLoggingEnabled());
}
INSTANTIATE_TEST_CASE_P(
diff --git a/chromium/components/safe_browsing/proto/csd.proto b/chromium/components/safe_browsing/proto/csd.proto
index 79e3264c280..b314be984fc 100644
--- a/chromium/components/safe_browsing/proto/csd.proto
+++ b/chromium/components/safe_browsing/proto/csd.proto
@@ -42,6 +42,23 @@ message ChromeUserPopulation {
// defined by finch trial name and group name. Trial name and group name are
// concatenated with separator "|", e.g. "PingOnlyTrial|DefaultGroup".
repeated string finch_active_groups = 4;
+
+ // Whether and how the current Chrome profile is being managed.
+ enum ProfileManagementStatus {
+ // Value not set.
+ UNKNOWN = 0;
+
+ // Profile management status is unavailable.
+ UNAVAILABLE = 1;
+
+ // The profile is not managed.
+ NOT_MANAGED = 2;
+
+ // Chrome is being managed by enterprise policies.
+ ENTERPRISE_MANAGED = 3;
+ }
+ optional ProfileManagementStatus profile_management_status = 5
+ [default = UNKNOWN];
}
message ClientPhishingRequest {
@@ -551,7 +568,16 @@ message ClientDownloadRequest {
// https://opensource.apple.com/source/xnu/xnu-2782.1.97/bsd/sys/codesign.h
optional bytes udif_code_signature = 40;
- // next available tag number: 51;
+ // Mac-only. A detached code signature contains the DER-encoded PKCS7 data
+ // of a codesigned artifact. Detached signatures are used for signing files
+ // that are not Mach-O and thus cannot have a LC_CODE_SIGNATURE load command.
+ message DetachedCodeSignature {
+ required string file_name = 1;
+ required bytes contents = 2;
+ }
+ repeated DetachedCodeSignature detached_code_signature = 59;
+
+ // next available tag number: 60;
}
message ReferrerChainOptions {
@@ -957,7 +983,7 @@ message DownloadMetadata {
// A Detailed Safebrowsing Report from clients. Chrome safebrowsing reports are
// only sent by Chrome users who have opted into extended Safe Browsing.
// This proto is replacing ClientMalwareReportRequest.
-// Next tag: 19
+// Next tag: 24
message ClientSafeBrowsingReportRequest {
// Note: A lot of the "optional" fields would make sense to be
// "required" instead. However, having them as optional allows the
@@ -1092,6 +1118,12 @@ message ClientSafeBrowsingReportRequest {
// False means user directly executed this download via download shelf or
// other download UIs.
optional bool show_download_in_folder = 18;
+
+ // If we can find the complete referrer chain, this field will contains URLs
+ // transitions from landing referrer to event in reverse chronological
+ // order, i.e. event url comes first in this list, and landing referrer
+ // comes last.
+ repeated ReferrerChainEntry referrer_chain = 23;
}
// An HTML Element on the page (eg: iframe, div, script, etc).
diff --git a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
index 8ac8364d80f..8f6c4b177b9 100644
--- a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
+++ b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.cc
@@ -22,8 +22,10 @@
namespace safe_browsing {
WebSocketSBHandshakeThrottle::WebSocketSBHandshakeThrottle(
- mojom::SafeBrowsing* safe_browsing)
- : callbacks_(nullptr),
+ mojom::SafeBrowsing* safe_browsing,
+ int render_frame_id)
+ : render_frame_id_(render_frame_id),
+ callbacks_(nullptr),
safe_browsing_(safe_browsing),
result_(Result::UNKNOWN),
weak_factory_(this) {}
@@ -45,22 +47,15 @@ WebSocketSBHandshakeThrottle::~WebSocketSBHandshakeThrottle() {
void WebSocketSBHandshakeThrottle::ThrottleHandshake(
const blink::WebURL& url,
- blink::WebLocalFrame* web_local_frame,
blink::WebCallbacks<void, const blink::WebString&>* callbacks) {
DCHECK(!callbacks_);
DCHECK(!url_checker_);
callbacks_ = callbacks;
url_ = url;
- int render_frame_id = MSG_ROUTING_NONE;
- if (web_local_frame) {
- auto* render_frame = content::RenderFrame::FromWebFrame(web_local_frame);
- if (render_frame)
- render_frame_id = render_frame->GetRoutingID();
- }
int load_flags = 0;
start_time_ = base::TimeTicks::Now();
safe_browsing_->CreateCheckerAndCheck(
- render_frame_id, mojo::MakeRequest(&url_checker_), url, "GET",
+ render_frame_id_, mojo::MakeRequest(&url_checker_), url, "GET",
net::HttpRequestHeaders(), load_flags,
content::RESOURCE_TYPE_SUB_RESOURCE, false /* has_user_gesture */,
false /* originated_from_service_worker */,
diff --git a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
index bdbb1734c2d..2ead098f545 100644
--- a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
+++ b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle.h
@@ -16,7 +16,7 @@
#include "components/safe_browsing/common/safe_browsing.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "third_party/blink/public/platform/web_callbacks.h"
-#include "third_party/blink/public/platform/web_socket_handshake_throttle.h"
+#include "third_party/blink/public/platform/websocket_handshake_throttle.h"
#include "url/gurl.h"
namespace safe_browsing {
@@ -24,12 +24,12 @@ namespace safe_browsing {
class WebSocketSBHandshakeThrottle : public blink::WebSocketHandshakeThrottle,
public mojom::UrlCheckNotifier {
public:
- explicit WebSocketSBHandshakeThrottle(mojom::SafeBrowsing* safe_browsing);
+ WebSocketSBHandshakeThrottle(mojom::SafeBrowsing* safe_browsing,
+ int render_frame_id);
~WebSocketSBHandshakeThrottle() override;
void ThrottleHandshake(
const blink::WebURL& url,
- blink::WebLocalFrame* web_local_frame,
blink::WebCallbacks<void, const blink::WebString&>* callbacks) override;
private:
@@ -51,6 +51,7 @@ class WebSocketSBHandshakeThrottle : public blink::WebSocketHandshakeThrottle,
bool showed_interstitial);
void OnConnectionError();
+ const int render_frame_id_;
GURL url_;
blink::WebCallbacks<void, const blink::WebString&>* callbacks_;
mojom::SafeBrowsingUrlCheckerPtr url_checker_;
diff --git a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc
index c2a2c14e663..3a4ad11f4a6 100644
--- a/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc
+++ b/chromium/components/safe_browsing/renderer/websocket_sb_handshake_throttle_unittest.cc
@@ -106,7 +106,7 @@ class WebSocketSBHandshakeThrottleTest : public ::testing::Test {
WebSocketSBHandshakeThrottleTest() : mojo_binding_(&safe_browsing_) {
mojo_binding_.Bind(mojo::MakeRequest(&safe_browsing_ptr_));
throttle_ = std::make_unique<WebSocketSBHandshakeThrottle>(
- safe_browsing_ptr_.get());
+ safe_browsing_ptr_.get(), MSG_ROUTING_NONE);
}
base::test::ScopedTaskEnvironment message_loop_;
@@ -120,10 +120,8 @@ class WebSocketSBHandshakeThrottleTest : public ::testing::Test {
TEST_F(WebSocketSBHandshakeThrottleTest, Construction) {}
TEST_F(WebSocketSBHandshakeThrottleTest, CheckArguments) {
- throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
+ throttle_->ThrottleHandshake(GURL(kTestUrl), &fake_callbacks_);
safe_browsing_.RunUntilCalled();
- // TODO(ricea): Find a way to create a WebLocalFrame in a unit test so that
- // the code that looks up the render_frame_id can be tested.
EXPECT_EQ(MSG_ROUTING_NONE, safe_browsing_.render_frame_id_);
EXPECT_EQ(GURL(kTestUrl), safe_browsing_.url_);
EXPECT_EQ("GET", safe_browsing_.method_);
@@ -136,7 +134,7 @@ TEST_F(WebSocketSBHandshakeThrottleTest, CheckArguments) {
}
TEST_F(WebSocketSBHandshakeThrottleTest, Safe) {
- throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
+ throttle_->ThrottleHandshake(GURL(kTestUrl), &fake_callbacks_);
safe_browsing_.RunUntilCalled();
std::move(safe_browsing_.callback_).Run(nullptr, true, false);
fake_callbacks_.RunUntilCalled();
@@ -144,7 +142,7 @@ TEST_F(WebSocketSBHandshakeThrottleTest, Safe) {
}
TEST_F(WebSocketSBHandshakeThrottleTest, Unsafe) {
- throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
+ throttle_->ThrottleHandshake(GURL(kTestUrl), &fake_callbacks_);
safe_browsing_.RunUntilCalled();
std::move(safe_browsing_.callback_).Run(nullptr, false, false);
fake_callbacks_.RunUntilCalled();
@@ -156,7 +154,7 @@ TEST_F(WebSocketSBHandshakeThrottleTest, Unsafe) {
}
TEST_F(WebSocketSBHandshakeThrottleTest, SlowCheckNotifier) {
- throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
+ throttle_->ThrottleHandshake(GURL(kTestUrl), &fake_callbacks_);
safe_browsing_.RunUntilCalled();
mojom::UrlCheckNotifierPtr slow_check_notifier;
@@ -172,7 +170,7 @@ TEST_F(WebSocketSBHandshakeThrottleTest, SlowCheckNotifier) {
TEST_F(WebSocketSBHandshakeThrottleTest, MojoServiceNotThere) {
mojo_binding_.Close();
- throttle_->ThrottleHandshake(GURL(kTestUrl), nullptr, &fake_callbacks_);
+ throttle_->ThrottleHandshake(GURL(kTestUrl), &fake_callbacks_);
fake_callbacks_.RunUntilCalled();
EXPECT_EQ(FakeWebCallbacks::RESULT_SUCCESS, fake_callbacks_.result_);
}
diff --git a/chromium/components/safe_browsing/triggers/BUILD.gn b/chromium/components/safe_browsing/triggers/BUILD.gn
index 9237896a1fe..2831c3cd3ff 100644
--- a/chromium/components/safe_browsing/triggers/BUILD.gn
+++ b/chromium/components/safe_browsing/triggers/BUILD.gn
@@ -32,7 +32,9 @@ source_set("trigger_throttler") {
]
deps = [
"//base:base",
+ "//components/prefs:prefs",
"//components/safe_browsing:features",
+ "//components/safe_browsing/common:safe_browsing_prefs",
]
}
diff --git a/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc b/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc
index b873dd206e0..24b0cfaa18b 100644
--- a/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc
+++ b/chromium/components/safe_browsing/triggers/ad_sampler_trigger.cc
@@ -10,6 +10,7 @@
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
+#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "components/safe_browsing/features.h"
#include "components/safe_browsing/triggers/trigger_manager.h"
diff --git a/chromium/components/safe_browsing/triggers/mock_trigger_manager.cc b/chromium/components/safe_browsing/triggers/mock_trigger_manager.cc
index 3e3f14b2cfb..4443c264426 100644
--- a/chromium/components/safe_browsing/triggers/mock_trigger_manager.cc
+++ b/chromium/components/safe_browsing/triggers/mock_trigger_manager.cc
@@ -6,7 +6,8 @@
namespace safe_browsing {
-MockTriggerManager::MockTriggerManager() : TriggerManager(nullptr) {}
+MockTriggerManager::MockTriggerManager()
+ : TriggerManager(nullptr, nullptr, nullptr) {}
MockTriggerManager::~MockTriggerManager() {}
diff --git a/chromium/components/safe_browsing/triggers/mock_trigger_manager.h b/chromium/components/safe_browsing/triggers/mock_trigger_manager.h
index 40449ae9735..8fb7a417cd6 100644
--- a/chromium/components/safe_browsing/triggers/mock_trigger_manager.h
+++ b/chromium/components/safe_browsing/triggers/mock_trigger_manager.h
@@ -15,7 +15,7 @@ namespace safe_browsing {
class MockTriggerManager : public TriggerManager {
public:
MockTriggerManager();
- virtual ~MockTriggerManager();
+ ~MockTriggerManager() override;
MOCK_METHOD6(
StartCollectingThreatDetails,
@@ -25,6 +25,15 @@ class MockTriggerManager : public TriggerManager {
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
const SBErrorOptions& error_display_options));
+ MOCK_METHOD7(
+ StartCollectingThreatDetailsWithReason,
+ bool(TriggerType trigger_type,
+ content::WebContents* web_contents,
+ const security_interstitials::UnsafeResource& resource,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ history::HistoryService* history_service,
+ const SBErrorOptions& error_display_options,
+ TriggerManagerReason* out_reason));
MOCK_METHOD6(FinishCollectingThreatDetails,
bool(TriggerType trigger_type,
@@ -40,4 +49,4 @@ class MockTriggerManager : public TriggerManager {
} // namespace safe_browsing
-#endif // MOCK_TRIGGER_MANAGER_H_ \ No newline at end of file
+#endif // MOCK_TRIGGER_MANAGER_H_
diff --git a/chromium/components/safe_browsing/triggers/suspicious_site_trigger.cc b/chromium/components/safe_browsing/triggers/suspicious_site_trigger.cc
index 38cfd937aca..96e4e45b117 100644
--- a/chromium/components/safe_browsing/triggers/suspicious_site_trigger.cc
+++ b/chromium/components/safe_browsing/triggers/suspicious_site_trigger.cc
@@ -4,6 +4,8 @@
#include "components/safe_browsing/triggers/suspicious_site_trigger.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/single_thread_task_runner.h"
#include "components/history/core/browser/history_service.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/triggers/trigger_manager.h"
@@ -26,15 +28,39 @@ namespace {
const int64_t kSuspiciousSiteCollectionPeriodMilliseconds = 5000;
} // namespace
+const char kSuspiciousSiteTriggerEventMetricName[] =
+ "SafeBrowsing.Triggers.SuspiciousSite.Event";
+
+const char kSuspiciousSiteTriggerReportRejectionMetricName[] =
+ "SafeBrowsing.Triggers.SuspiciousSite.ReportRejectionReason";
+
+const char kSuspiciousSiteTriggerReportDelayStateMetricName[] =
+ "SafeBrowsing.Triggers.SuspiciousSite.DelayTimerState";
+
+void NotifySuspiciousSiteTriggerDetected(
+ const base::RepeatingCallback<content::WebContents*()>&
+ web_contents_getter) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ content::WebContents* web_contents = web_contents_getter.Run();
+ if (web_contents) {
+ safe_browsing::SuspiciousSiteTrigger* trigger =
+ safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents);
+ if (trigger)
+ trigger->SuspiciousSiteDetected();
+ }
+}
+
SuspiciousSiteTrigger::SuspiciousSiteTrigger(
content::WebContents* web_contents,
TriggerManager* trigger_manager,
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- history::HistoryService* history_service)
+ history::HistoryService* history_service,
+ bool monitor_mode)
: content::WebContentsObserver(web_contents),
finish_report_delay_ms_(kSuspiciousSiteCollectionPeriodMilliseconds),
- current_state_(TriggerState::IDLE),
+ current_state_(monitor_mode ? TriggerState::MONITOR_MODE
+ : TriggerState::IDLE),
trigger_manager_(trigger_manager),
prefs_(prefs),
url_loader_factory_(url_loader_factory),
@@ -51,12 +77,13 @@ void SuspiciousSiteTrigger::CreateForWebContents(
TriggerManager* trigger_manager,
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- history::HistoryService* history_service) {
+ history::HistoryService* history_service,
+ bool monitor_mode) {
if (!FromWebContents(web_contents)) {
- web_contents->SetUserData(UserDataKey(),
- base::WrapUnique(new SuspiciousSiteTrigger(
- web_contents, trigger_manager, prefs,
- url_loader_factory, history_service)));
+ web_contents->SetUserData(
+ UserDataKey(), base::WrapUnique(new SuspiciousSiteTrigger(
+ web_contents, trigger_manager, prefs,
+ url_loader_factory, history_service, monitor_mode)));
}
}
@@ -71,9 +98,14 @@ bool SuspiciousSiteTrigger::MaybeStartReport() {
web_contents()->GetMainFrame()->GetProcess()->GetID(),
web_contents()->GetMainFrame()->GetRoutingID());
- if (!trigger_manager_->StartCollectingThreatDetails(
+ TriggerManagerReason reason;
+ if (!trigger_manager_->StartCollectingThreatDetailsWithReason(
TriggerType::SUSPICIOUS_SITE, web_contents(), resource,
- url_loader_factory_, history_service_, error_options)) {
+ url_loader_factory_, history_service_, error_options, &reason)) {
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::REPORT_START_FAILED);
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerReportRejectionMetricName,
+ reason);
return false;
}
@@ -81,22 +113,46 @@ bool SuspiciousSiteTrigger::MaybeStartReport() {
// to complete.
task_runner_->PostDelayedTask(
FROM_HERE,
- base::BindOnce(&SuspiciousSiteTrigger::FinishReport,
+ base::BindOnce(&SuspiciousSiteTrigger::ReportDelayTimerFired,
weak_ptr_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(finish_report_delay_ms_));
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::REPORT_STARTED);
return true;
}
void SuspiciousSiteTrigger::FinishReport() {
SBErrorOptions error_options =
TriggerManager::GetSBErrorDisplayOptions(*prefs_, *web_contents());
- trigger_manager_->FinishCollectingThreatDetails(
- TriggerType::SUSPICIOUS_SITE, web_contents(), base::TimeDelta(),
- /*did_proceed=*/false, /*num_visits=*/0, error_options);
+ if (trigger_manager_->FinishCollectingThreatDetails(
+ TriggerType::SUSPICIOUS_SITE, web_contents(), base::TimeDelta(),
+ /*did_proceed=*/false, /*num_visits=*/0, error_options)) {
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::REPORT_FINISHED);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::REPORT_FINISH_FAILED);
+ }
+}
+
+void SuspiciousSiteTrigger::SuspiciousSiteDetectedWhenMonitoring() {
+ DCHECK_EQ(TriggerState::MONITOR_MODE, current_state_);
+ SBErrorOptions error_options =
+ TriggerManager::GetSBErrorDisplayOptions(*prefs_, *web_contents());
+ TriggerManagerReason reason;
+ if (trigger_manager_->CanStartDataCollectionWithReason(
+ error_options, TriggerType::SUSPICIOUS_SITE, &reason) ||
+ reason == TriggerManagerReason::DAILY_QUOTA_EXCEEDED) {
+ UMA_HISTOGRAM_ENUMERATION(
+ kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::REPORT_POSSIBLE_BUT_SKIPPED);
+ }
}
void SuspiciousSiteTrigger::DidStartLoading() {
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::PAGE_LOAD_START);
switch (current_state_) {
case TriggerState::IDLE:
// Load started, move to loading state.
@@ -111,6 +167,9 @@ void SuspiciousSiteTrigger::DidStartLoading() {
// This happens if the user leaves the suspicious page before it
// finishes loading. A report can't be created in this case since the
// page is now gone.
+ UMA_HISTOGRAM_ENUMERATION(
+ kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::PENDING_REPORT_CANCELLED_BY_LOAD);
current_state_ = TriggerState::LOADING;
return;
@@ -122,10 +181,17 @@ void SuspiciousSiteTrigger::DidStartLoading() {
current_state_ = TriggerState::LOADING;
FinishReport();
return;
+
+ case TriggerState::MONITOR_MODE:
+ // No-op, monitoring only.
+ return;
}
}
void SuspiciousSiteTrigger::DidStopLoading() {
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH);
+
switch (current_state_) {
case TriggerState::IDLE:
// No-op, load stopped and we're already idle.
@@ -150,11 +216,19 @@ void SuspiciousSiteTrigger::DidStopLoading() {
case TriggerState::REPORT_STARTED:
// No-op. Let the report continue running.
return;
+
+ case TriggerState::MONITOR_MODE:
+ // No-op, monitoring only.
+ return;
}
}
void SuspiciousSiteTrigger::SuspiciousSiteDetected() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ UMA_HISTOGRAM_ENUMERATION(
+ kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED);
+
switch (current_state_) {
case TriggerState::IDLE:
// Suspicious site detected while idle, start a report immediately.
@@ -180,14 +254,24 @@ void SuspiciousSiteTrigger::SuspiciousSiteDetected() {
case TriggerState::REPORT_STARTED:
// No-op. The current report should capture all suspicious sites.
return;
+
+ case TriggerState::MONITOR_MODE:
+ // We monitor how often a suspicious site hit could result in a report.
+ SuspiciousSiteDetectedWhenMonitoring();
+ return;
}
}
void SuspiciousSiteTrigger::ReportDelayTimerFired() {
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerEventMetricName,
+ SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER);
+ UMA_HISTOGRAM_ENUMERATION(kSuspiciousSiteTriggerReportDelayStateMetricName,
+ current_state_);
switch (current_state_) {
case TriggerState::IDLE:
case TriggerState::LOADING:
case TriggerState::LOADING_WILL_REPORT:
+ case TriggerState::MONITOR_MODE:
// Invalid, expecting to be in REPORT_STARTED state.
return;
diff --git a/chromium/components/safe_browsing/triggers/suspicious_site_trigger.h b/chromium/components/safe_browsing/triggers/suspicious_site_trigger.h
index 1f4e49c84fb..5b9f05e7120 100644
--- a/chromium/components/safe_browsing/triggers/suspicious_site_trigger.h
+++ b/chromium/components/safe_browsing/triggers/suspicious_site_trigger.h
@@ -23,6 +23,59 @@ class SharedURLLoaderFactory;
namespace safe_browsing {
class TriggerManager;
+// Metric for tracking what the Suspicious Site trigger does on each event.
+extern const char kSuspiciousSiteTriggerEventMetricName[];
+
+// Metric for tracking how often reports from this trigger are rejected by the
+// trigger manager, and for what reason.
+extern const char kSuspiciousSiteTriggerReportRejectionMetricName[];
+
+// Metric for tracking the state of the trigger when the report delay timer
+// fires.
+extern const char kSuspiciousSiteTriggerReportDelayStateMetricName[];
+
+// Tracks events this trigger listens for or actions it performs. These values
+// are written to logs. New enum values can be added, but existing enums must
+// never be renumbered or deleted and reused.
+enum class SuspiciousSiteTriggerEvent {
+ // A page load started.
+ PAGE_LOAD_START = 0,
+ // A page load finished.
+ PAGE_LOAD_FINISH = 1,
+ // A suspicious site was detected.
+ SUSPICIOUS_SITE_DETECTED = 2,
+ // The report delay timer fired.
+ REPORT_DELAY_TIMER = 3,
+ // A suspicious site report was started.
+ REPORT_STARTED = 4,
+ // A suspicious site report was created and sent.
+ REPORT_FINISHED = 5,
+ // The trigger was waiting for a load to finish before creating a report but
+ // a new load started before the previous load could finish, so the report
+ // was cancelled.
+ PENDING_REPORT_CANCELLED_BY_LOAD = 6,
+ // The trigger tried to start the report but it was rejected by the trigger
+ // manager.
+ REPORT_START_FAILED = 7,
+ // The trigger tried to finish the report but it was rejected by the trigger
+ // manager.
+ REPORT_FINISH_FAILED = 8,
+ // The trigger could have sent a report but it was skipped, typically because
+ // the trigger was out of quota.
+ REPORT_POSSIBLE_BUT_SKIPPED = 9,
+ // New events must be added before kMaxValue, and the value of kMaxValue
+ // updated.
+ kMaxValue = REPORT_POSSIBLE_BUT_SKIPPED
+};
+
+// Notify a suspicious site trigger on a particular tab that a suspicious site
+// was detected. |web_contents_getter| specifies the tab where the site was
+// detected.
+// Must be called on UI thread.
+void NotifySuspiciousSiteTriggerDetected(
+ const base::RepeatingCallback<content::WebContents*()>&
+ web_contents_getter);
+
// This class watches tab-level events such as the start and end of a page
// load, and also listens for events from the SuspiciousSiteURLThrottle that
// indicate there was a hit on the suspicious site list. This trigger is
@@ -32,6 +85,28 @@ class SuspiciousSiteTrigger
: public content::WebContentsObserver,
public content::WebContentsUserData<SuspiciousSiteTrigger> {
public:
+ // The different states the trigger could be in.
+ // These values are written to logs. New enum values can be added, but
+ // existing enums must never be renumbered or deleted and reused.
+ enum class TriggerState {
+ // Trigger is idle, page is not loading, no report requested.
+ IDLE = 0,
+ // Page load has started, no report requested.
+ LOADING = 1,
+ // Page load has started and a report is requested. The report will be
+ // created when the page load finishes.
+ LOADING_WILL_REPORT = 2,
+ // A page load finished and a report for the page has started.
+ REPORT_STARTED = 3,
+ // The trigger is in monitoring mode where it listens for events and
+ // increments some metrics but never sends reports. The trigger will never
+ // leave this state.
+ MONITOR_MODE = 4,
+ // New states must be added before kMaxValue and the value of kMaxValue
+ // updated.
+ kMaxValue = MONITOR_MODE
+ };
+
~SuspiciousSiteTrigger() override;
static void CreateForWebContents(
@@ -39,7 +114,8 @@ class SuspiciousSiteTrigger
TriggerManager* trigger_manager,
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- history::HistoryService* history_service);
+ history::HistoryService* history_service,
+ bool monitor_mode);
// content::WebContentsObserver implementations.
void DidStartLoading() override;
@@ -53,25 +129,13 @@ class SuspiciousSiteTrigger
friend class content::WebContentsUserData<SuspiciousSiteTrigger>;
friend class SuspiciousSiteTriggerTest;
- // The different states the trigger could be in.
- enum class TriggerState {
- // Trigger is idle, page is not loading, no report requested.
- IDLE,
- // Page load has started, no report requested.
- LOADING,
- // Page load has started and a report is requested. The report will be
- // created when the page load finishes.
- LOADING_WILL_REPORT,
- // A page load finished and a report for the page has started.
- REPORT_STARTED,
- };
-
SuspiciousSiteTrigger(
content::WebContents* web_contents,
TriggerManager* trigger_manager,
PrefService* prefs,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
- history::HistoryService* history_service);
+ history::HistoryService* history_service,
+ bool monitor_mode);
// Tries to start a report. Returns whether a report started successfully.
// If a report is started, a delayed callback will also begin to notify
@@ -81,6 +145,11 @@ class SuspiciousSiteTrigger
// Calls into the trigger manager to finish the active report and send it.
void FinishReport();
+ // Called when a suspicious site is detected while in monitor mode. We update
+ // metrics if we determine that a report could have been sent had the trigger
+ // been active.
+ void SuspiciousSiteDetectedWhenMonitoring();
+
// Called when the report delay timer fires, indicating that the active
// report should be completed and sent.
void ReportDelayTimerFired();
diff --git a/chromium/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc b/chromium/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc
index 3b5a6842c1a..4473c9fb1a8 100644
--- a/chromium/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc
+++ b/chromium/components/safe_browsing/triggers/suspicious_site_trigger_unittest.cc
@@ -4,6 +4,7 @@
#include "components/safe_browsing/triggers/suspicious_site_trigger.h"
+#include "base/test/histogram_tester.h"
#include "base/test/test_simple_task_runner.h"
#include "components/prefs/testing_pref_service.h"
#include "components/safe_browsing/common/safe_browsing_prefs.h"
@@ -18,7 +19,9 @@ using content::RenderFrameHost;
using content::RenderFrameHostTester;
using testing::_;
+using testing::DoAll;
using testing::Return;
+using testing::SetArgPointee;
namespace safe_browsing {
@@ -42,9 +45,10 @@ class SuspiciousSiteTriggerTest : public content::RenderViewHostTestHarness {
prefs_.SetBoolean(prefs::kSafeBrowsingScoutGroupSelected, true);
}
- void CreateTrigger() {
+ void CreateTrigger(bool monitor_mode) {
safe_browsing::SuspiciousSiteTrigger::CreateForWebContents(
- web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr);
+ web_contents(), &trigger_manager_, &prefs_, nullptr, nullptr,
+ monitor_mode);
safe_browsing::SuspiciousSiteTrigger* trigger =
safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents());
// Give the trigger a test task runner that we can synchronize on.
@@ -76,6 +80,13 @@ class SuspiciousSiteTriggerTest : public content::RenderViewHostTestHarness {
return NavigateFrame(url, subframe);
}
+ void StartNewFakeLoad() {
+ // This fakes a new LoadStart event in the trigger, since the navigation
+ // simulator doesn't restart the load when we start a new navigation.
+ safe_browsing::SuspiciousSiteTrigger::FromWebContents(web_contents())
+ ->DidStartLoading();
+ }
+
void FinishAllNavigations() {
// Call the trigger's DidStopLoading event handler directly since it is not
// called as part of the navigating individual frames.
@@ -94,21 +105,57 @@ class SuspiciousSiteTriggerTest : public content::RenderViewHostTestHarness {
base::RunLoop().RunUntilIdle();
}
+ // Checks the trigger event histogram and ensures that |event| happened
+ // |count| times.
+ void ExpectEventHistogramCount(const SuspiciousSiteTriggerEvent event,
+ int count) {
+ histograms_.ExpectBucketCount(kSuspiciousSiteTriggerEventMetricName,
+ static_cast<int>(event), count);
+ }
+
+ // Checks the histogram that tracks what state the trigger was in when the
+ // delay timer fired. Ensures that the trigger was in |state| and occured
+ // |count| times.
+ void ExpectDelayStateHistogramCount(
+ const SuspiciousSiteTrigger::TriggerState state,
+ int count) {
+ histograms_.ExpectBucketCount(
+ kSuspiciousSiteTriggerReportDelayStateMetricName,
+ static_cast<int>(state), count);
+ }
+
+ // Checks the report rejection histogram and makes sure that |count| reports
+ // were rejected for |reason|.
+ void ExpectReportRejectionHistogramCount(const TriggerManagerReason reason,
+ int count) {
+ histograms_.ExpectBucketCount(
+ kSuspiciousSiteTriggerReportRejectionMetricName,
+ static_cast<int>(reason), count);
+ }
+
+ // Checks the report rejection histogram and makes sure it was empty,
+ // indicating no errors occurred.
+ void ExpectNoReportRejection() {
+ histograms_.ExpectTotalCount(
+ kSuspiciousSiteTriggerReportRejectionMetricName, 0);
+ }
+
MockTriggerManager* get_trigger_manager() { return &trigger_manager_; }
private:
TestingPrefServiceSimple prefs_;
MockTriggerManager trigger_manager_;
+ base::HistogramTester histograms_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
};
TEST_F(SuspiciousSiteTriggerTest, RegularPageNonSuspicious) {
// In a normal case where there are no suspicious URLs on the page, the
// trigger should not fire.
- CreateTrigger();
+ CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetails(_, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
@@ -118,20 +165,29 @@ TEST_F(SuspiciousSiteTriggerTest, RegularPageNonSuspicious) {
CreateAndNavigateSubFrame(kCleanUrl, main_frame);
CreateAndNavigateSubFrame(kCleanUrl, main_frame);
FinishAllNavigations();
+
+ // One page load start and finish. No suspicious sites and no reports sent.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0);
+ ExpectNoReportRejection();
}
TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitDuringLoad) {
// When a suspicious site is detected in the middle of a page load, a report
// is created after the page load has finished.
- CreateTrigger();
+ CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetails(_, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
- .Times(1);
+ .Times(1)
+ .WillOnce(Return(true));
RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame);
@@ -140,20 +196,36 @@ TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitDuringLoad) {
FinishAllNavigations();
WaitForTaskRunnerIdle();
+
+ // One page load start and finish. One suspicious site detected and one
+ // report started and sent after the page finished loading.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 1);
+
+ // Ensure the delay timer fired and it happened in the REPORT_STARTED state
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 1);
+ ExpectDelayStateHistogramCount(
+ SuspiciousSiteTrigger::TriggerState::REPORT_STARTED, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 1);
+ ExpectNoReportRejection();
}
TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitAfterLoad) {
// When a suspicious site is detected in after a page load, a report is
// created immediately.
- CreateTrigger();
+ CreateTrigger(/*monitor_mode=*/false);
EXPECT_CALL(*get_trigger_manager(),
- StartCollectingThreatDetails(_, _, _, _, _, _))
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
.Times(1)
.WillOnce(Return(true));
EXPECT_CALL(*get_trigger_manager(),
FinishCollectingThreatDetails(_, _, _, _, _, _))
- .Times(1);
+ .Times(1)
+ .WillOnce(Return(true));
RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame);
@@ -162,6 +234,193 @@ TEST_F(SuspiciousSiteTriggerTest, SuspiciousHitAfterLoad) {
TriggerSuspiciousSite();
WaitForTaskRunnerIdle();
+
+ // One page load start and finish. One suspicious site detected and one
+ // report started and sent.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 1);
+
+ // Ensure the delay timer fired and it happened in the REPORT_STARTED state
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 1);
+ ExpectDelayStateHistogramCount(
+ SuspiciousSiteTrigger::TriggerState::REPORT_STARTED, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 1);
+ ExpectNoReportRejection();
+}
+
+TEST_F(SuspiciousSiteTriggerTest, ReportRejectedByTriggerManager) {
+ // If the trigger manager rejects the report then no report is sent.
+ CreateTrigger(/*monitor_mode=*/false);
+
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(
+ DoAll(SetArgPointee<6>(TriggerManagerReason::DAILY_QUOTA_EXCEEDED),
+ Return(false)));
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
+ CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame);
+ TriggerSuspiciousSite();
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ FinishAllNavigations();
+
+ WaitForTaskRunnerIdle();
+
+ // One page load start and finish. One suspicious site detected but no report
+ // is sent because it's rejected. Error stats should reflect the rejection.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1);
+
+ // Ensure no report was started or finished, and no delay timer fired.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 0);
+
+ // Ensure that starting a report failed, and it was rejected for the
+ // expected reason (quota).
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_START_FAILED, 1);
+ ExpectReportRejectionHistogramCount(
+ TriggerManagerReason::DAILY_QUOTA_EXCEEDED, 1);
+}
+
+TEST_F(SuspiciousSiteTriggerTest, NewNavigationMidLoad_NotSuspicious) {
+ // Exercise what happens when a new navigation begins in the middle of a page
+ // load when no suspicious site is detected.
+ CreateTrigger(/*monitor_mode=*/false);
+
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ // Begin a brand new load before the first one is finished.
+ StartNewFakeLoad();
+ FinishAllNavigations();
+
+ // Two page load start events, but only one finish. No suspicious sites
+ // detected and no reports sent.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 2);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0);
+ ExpectNoReportRejection();
+}
+
+TEST_F(SuspiciousSiteTriggerTest, NewNavigationMidLoad_Suspicious) {
+ // Exercise what happens when a new navigation begins in the middle of a page
+ // load when a suspicious site was detected. The report of the first site
+ // must be cancelled because we were waiting for the first load to finish
+ // before beginning the report.
+ CreateTrigger(/*monitor_mode=*/false);
+
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ // Trigger a suspicious site. We wait for this page load to finish before
+ // creating the report.
+ TriggerSuspiciousSite();
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ // Begin a brand new load before the first one is finished. This will cancel
+ // the report that is queued.
+ StartNewFakeLoad();
+ FinishAllNavigations();
+
+ // Two page load start events, but only one finish. One suspicious site
+ // detected but no reports created because the report gets cancelled.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 2);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0);
+ ExpectNoReportRejection();
+
+ // Ensure that the repot got cancelled by the second load.
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::PENDING_REPORT_CANCELLED_BY_LOAD, 1);
+}
+
+TEST_F(SuspiciousSiteTriggerTest, MonitorMode_NotSuspicious) {
+ // Testing the trigger in monitoring mode, it should never send reports.
+ // In a normal case where there are no suspicious URLs on the page, the
+ // trigger should not fire.
+ CreateTrigger(/*monitor_mode=*/true);
+
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ FinishAllNavigations();
+
+ // One page load start and finish. No suspicious sites and no reports sent.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0);
+ ExpectNoReportRejection();
}
+TEST_F(SuspiciousSiteTriggerTest, MonitorMode_SuspiciousHitDuringLoad) {
+ // Testing the trigger in monitoring mode, it should never send reports.
+ // When a suspicious site is detected in the middle of a page load, a report
+ // is created after the page load has finished.
+ CreateTrigger(/*monitor_mode=*/true);
+
+ EXPECT_CALL(*get_trigger_manager(),
+ StartCollectingThreatDetailsWithReason(_, _, _, _, _, _, _))
+ .Times(0);
+ EXPECT_CALL(*get_trigger_manager(),
+ FinishCollectingThreatDetails(_, _, _, _, _, _))
+ .Times(0);
+
+ RenderFrameHost* main_frame = NavigateMainFrame(kCleanUrl);
+ CreateAndNavigateSubFrame(kSuspiciousUrl, main_frame);
+ TriggerSuspiciousSite();
+ CreateAndNavigateSubFrame(kCleanUrl, main_frame);
+ FinishAllNavigations();
+
+ WaitForTaskRunnerIdle();
+
+ // One page load start and finish. One suspicious site detected and one
+ // possible report that gets skipped.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_START, 1);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::PAGE_LOAD_FINISH, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::SUSPICIOUS_SITE_DETECTED, 1);
+ ExpectEventHistogramCount(
+ SuspiciousSiteTriggerEvent::REPORT_POSSIBLE_BUT_SKIPPED, 1);
+
+ // No reports are started or finished, no delay timer fired.
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_STARTED, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_FINISHED, 0);
+ ExpectEventHistogramCount(SuspiciousSiteTriggerEvent::REPORT_DELAY_TIMER, 0);
+ ExpectNoReportRejection();
+}
} // namespace safe_browsing \ No newline at end of file
diff --git a/chromium/components/safe_browsing/triggers/trigger_manager.cc b/chromium/components/safe_browsing/triggers/trigger_manager.cc
index fabe0cacbad..46fc4d0798f 100644
--- a/chromium/components/safe_browsing/triggers/trigger_manager.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_manager.cc
@@ -93,9 +93,12 @@ bool CanSendReport(const SBErrorOptions& error_display_options,
DataCollectorsContainer::DataCollectorsContainer() {}
DataCollectorsContainer::~DataCollectorsContainer() {}
-TriggerManager::TriggerManager(BaseUIManager* ui_manager)
+TriggerManager::TriggerManager(BaseUIManager* ui_manager,
+ ReferrerChainProvider* referrer_chain_provider,
+ PrefService* local_state_prefs)
: ui_manager_(ui_manager),
- trigger_throttler_(new TriggerThrottler()),
+ referrer_chain_provider_(referrer_chain_provider),
+ trigger_throttler_(new TriggerThrottler(local_state_prefs)),
weak_factory_(this) {}
TriggerManager::~TriggerManager() {}
@@ -123,6 +126,16 @@ SBErrorOptions TriggerManager::GetSBErrorDisplayOptions(
bool TriggerManager::CanStartDataCollection(
const SBErrorOptions& error_display_options,
const TriggerType trigger_type) {
+ TriggerManagerReason unused_reason;
+ return CanStartDataCollectionWithReason(error_display_options, trigger_type,
+ &unused_reason);
+}
+
+bool TriggerManager::CanStartDataCollectionWithReason(
+ const SBErrorOptions& error_display_options,
+ const TriggerType trigger_type,
+ TriggerManagerReason* out_reason) {
+ *out_reason = TriggerManagerReason::NO_REASON;
// If the |kAdSamplerCollectButDontSendFeature| feature is enabled then we
// will overlook other checks to force the report to be created (which is safe
// because we ensure it will be discarded downstream).
@@ -148,12 +161,18 @@ bool TriggerManager::CanStartDataCollection(
// change the Extended Reporting opt-in, and the |trigger_type| has available
// quota. For some triggers we also require Scout or extended reporting opt-in
// in order to start data collection.
- return !error_display_options.is_off_the_record &&
- error_display_options.is_extended_reporting_opt_in_allowed &&
- optin_required_check_ok && scout_check_ok &&
- trigger_throttler_->TriggerCanFire(trigger_type);
+ if (!error_display_options.is_off_the_record &&
+ error_display_options.is_extended_reporting_opt_in_allowed &&
+ optin_required_check_ok && scout_check_ok) {
+ bool quota_ok = trigger_throttler_->TriggerCanFire(trigger_type);
+ if (!quota_ok)
+ *out_reason = TriggerManagerReason::DAILY_QUOTA_EXCEEDED;
+ return quota_ok;
+ } else {
+ *out_reason = TriggerManagerReason::USER_PREFERENCES;
+ return false;
+ }
}
-
bool TriggerManager::StartCollectingThreatDetails(
const TriggerType trigger_type,
content::WebContents* web_contents,
@@ -161,8 +180,23 @@ bool TriggerManager::StartCollectingThreatDetails(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
const SBErrorOptions& error_display_options) {
+ TriggerManagerReason unused_reason;
+ return StartCollectingThreatDetailsWithReason(
+ trigger_type, web_contents, resource, url_loader_factory, history_service,
+ error_display_options, &unused_reason);
+}
+
+bool TriggerManager::StartCollectingThreatDetailsWithReason(
+ const TriggerType trigger_type,
+ content::WebContents* web_contents,
+ const security_interstitials::UnsafeResource& resource,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ history::HistoryService* history_service,
+ const SBErrorOptions& error_display_options,
+ TriggerManagerReason* reason) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (!CanStartDataCollection(error_display_options, trigger_type))
+ if (!CanStartDataCollectionWithReason(error_display_options, trigger_type,
+ reason))
return false;
// Ensure we're not already collecting ThreatDetails on this tab. Create an
@@ -175,7 +209,7 @@ bool TriggerManager::StartCollectingThreatDetails(
collectors->threat_details =
scoped_refptr<ThreatDetails>(ThreatDetails::NewThreatDetails(
ui_manager_, web_contents, resource, url_loader_factory,
- history_service, should_trim_threat_details,
+ history_service, referrer_chain_provider_, should_trim_threat_details,
base::Bind(&TriggerManager::ThreatDetailsDone,
weak_factory_.GetWeakPtr())));
return true;
diff --git a/chromium/components/safe_browsing/triggers/trigger_manager.h b/chromium/components/safe_browsing/triggers/trigger_manager.h
index 833028b3d87..346deb810ce 100644
--- a/chromium/components/safe_browsing/triggers/trigger_manager.h
+++ b/chromium/components/safe_browsing/triggers/trigger_manager.h
@@ -9,6 +9,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "components/safe_browsing/browser/referrer_chain_provider.h"
#include "components/safe_browsing/triggers/trigger_throttler.h"
#include "components/security_interstitials/content/unsafe_resource.h"
#include "components/security_interstitials/core/base_safe_browsing_error_ui.h"
@@ -56,6 +57,25 @@ using DataCollectorsMap =
using SBErrorOptions =
security_interstitials::BaseSafeBrowsingErrorUI::SBErrorDisplayOptions;
+// The reasons that trigger manager fails to create or finish a report.
+// These values are written to logs. New enum values can be added, but
+// existing enums must never be renumbered or deleted and reused.
+enum class TriggerManagerReason {
+ // Default value, used when there is no failure.
+ NO_REASON = 0,
+ // User preferences do not allow the report to be started or finished.
+ USER_PREFERENCES = 1,
+ // A report is already started on this tab, so no new report is started.
+ REPORT_ALREADY_STARTED = 2,
+ // There is no report to finish on this tab.
+ NO_REPORT_TO_FINISH = 3,
+ // No report is started because the user has exceeded their daily quota.
+ DAILY_QUOTA_EXCEEDED = 4,
+ // New reasons must be added before kMaxValue and the value of kMaxValue
+ // updated.
+ kMaxValue = DAILY_QUOTA_EXCEEDED
+};
+
// This class manages SafeBrowsing data-reporting triggers. Triggers are
// activated for users opted-in to Extended Reporting and when security-related
// data collection is required.
@@ -65,7 +85,9 @@ using SBErrorOptions =
// tracking how often triggers fire and throttling them when necessary.
class TriggerManager {
public:
- TriggerManager(BaseUIManager* ui_manager);
+ TriggerManager(BaseUIManager* ui_manager,
+ ReferrerChainProvider* referrer_chain_provider,
+ PrefService* local_state_prefs);
virtual ~TriggerManager();
// Returns a SBErrorDisplayOptions struct containing user state that is
@@ -78,6 +100,14 @@ class TriggerManager {
// Returns whether data collection can be started for the |trigger_type| based
// on the settings specified in |error_display_options| as well as quota.
+ // If false is returned, |out_reason| will be specify the reason.
+ bool CanStartDataCollectionWithReason(
+ const SBErrorOptions& error_display_options,
+ const TriggerType trigger_type,
+ TriggerManagerReason* out_reason);
+
+ // Simplified signature for |CanStartDataCollectionWithReason| for callers
+ // that don't care about the reason.
bool CanStartDataCollection(const SBErrorOptions& error_display_options,
const TriggerType trigger_type);
@@ -89,6 +119,19 @@ class TriggerManager {
// preferences. We use this object for interop with WebView, in Chrome it
// should be created by TriggerManager::GetSBErrorDisplayOptions().
// Returns true if the collection began, or false if it didn't.
+ // If false is returned, |out_reason| is set to the reason the report didn't
+ // start.
+ virtual bool StartCollectingThreatDetailsWithReason(
+ TriggerType trigger_type,
+ content::WebContents* web_contents,
+ const security_interstitials::UnsafeResource& resource,
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+ history::HistoryService* history_service,
+ const SBErrorOptions& error_display_options,
+ TriggerManagerReason* out_reason);
+
+ // Simplified signature for |StartCollectingThreatDetailsWithReason| for
+ // callers that don't care about the reason.
virtual bool StartCollectingThreatDetails(
TriggerType trigger_type,
content::WebContents* web_contents,
@@ -133,6 +176,10 @@ class TriggerManager {
// TODO(lpz): we may only need a the PingManager here.
BaseUIManager* ui_manager_;
+ // The Referrer Chain Provider is used to retrieve the referrer chain for
+ // reports that require it. Not owned.
+ ReferrerChainProvider* referrer_chain_provider_;
+
// Map of the data collectors running on each tabs. New keys are added the
// first time any trigger tries to collect data on a tab and are removed when
// the tab is destroyed. The values can be null if a trigger has finished on
diff --git a/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc b/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc
index 50fe5df96df..77230aef016 100644
--- a/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_manager_unittest.cc
@@ -28,7 +28,7 @@ namespace safe_browsing {
// Mock ThreatDetails class that makes FinishCollection a no-op.
class MockThreatDetails : public ThreatDetails {
public:
- MockThreatDetails() : ThreatDetails() {}
+ MockThreatDetails() {}
MOCK_METHOD2(FinishCollection, void(bool did_proceed, int num_visits));
private:
@@ -46,6 +46,7 @@ class MockThreatDetailsFactory : public ThreatDetailsFactory {
const security_interstitials::UnsafeResource& unsafe_resource,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
history::HistoryService* history_service,
+ ReferrerChainProvider* referrer_chain_provider,
bool trim_to_ad_tags,
ThreatDetailsDoneCallback done_callback) override {
MockThreatDetails* threat_details = new MockThreatDetails();
@@ -55,12 +56,13 @@ class MockThreatDetailsFactory : public ThreatDetailsFactory {
class MockTriggerThrottler : public TriggerThrottler {
public:
+ MockTriggerThrottler() : TriggerThrottler(nullptr) {}
MOCK_CONST_METHOD1(TriggerCanFire, bool(TriggerType trigger_type));
};
class TriggerManagerTest : public ::testing::Test {
public:
- TriggerManagerTest() : trigger_manager_(/*ui_manager=*/nullptr) {}
+ TriggerManagerTest() : trigger_manager_(nullptr, nullptr, nullptr) {}
~TriggerManagerTest() override {}
void SetUp() override {
diff --git a/chromium/components/safe_browsing/triggers/trigger_throttler.cc b/chromium/components/safe_browsing/triggers/trigger_throttler.cc
index 335f91d3045..0afce2d270b 100644
--- a/chromium/components/safe_browsing/triggers/trigger_throttler.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_throttler.cc
@@ -10,11 +10,14 @@
#include "base/strings/string_split.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
+#include "components/prefs/pref_service.h"
+#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/safe_browsing/features.h"
namespace safe_browsing {
-const char kTriggerTypeAndQuotaParam[] = "trigger_type_and_quota_csv";
const size_t kAdSamplerTriggerDefaultQuota = 10;
+const char kSuspiciousSiteTriggerQuotaParam[] = "suspicious_site_trigger_quota";
+const char kTriggerTypeAndQuotaParam[] = "trigger_type_and_quota_csv";
namespace {
const size_t kUnlimitedTriggerQuota = std::numeric_limits<size_t>::max();
@@ -35,13 +38,22 @@ class TriggerTypeIs {
void ParseTriggerTypeAndQuotaParam(
std::vector<TriggerTypeAndQuotaItem>* trigger_type_and_quota_list) {
DCHECK(trigger_type_and_quota_list);
+ trigger_type_and_quota_list->clear();
+
+ // First, handle the trigger-specific features.
+ int suspicious_site_quota = base::GetFieldTrialParamByFeatureAsInt(
+ kSuspiciousSiteTriggerQuotaFeature, kSuspiciousSiteTriggerQuotaParam, 0);
+ if (suspicious_site_quota > 0) {
+ trigger_type_and_quota_list->push_back(
+ std::make_pair(TriggerType::SUSPICIOUS_SITE, suspicious_site_quota));
+ }
+
// If the feature is disabled we just use the default list. Otherwise the list
// from the Finch param will be the one used.
if (!base::FeatureList::IsEnabled(kTriggerThrottlerDailyQuotaFeature)) {
return;
}
- trigger_type_and_quota_list->clear();
const std::string& trigger_and_quota_csv_param =
base::GetFieldTrialParamValueByFeature(kTriggerThrottlerDailyQuotaFeature,
kTriggerTypeAndQuotaParam);
@@ -93,9 +105,11 @@ bool TryFindQuotaForTrigger(
} // namespace
-TriggerThrottler::TriggerThrottler()
- : clock_(base::DefaultClock::GetInstance()) {
+TriggerThrottler::TriggerThrottler(PrefService* local_state_prefs)
+ : local_state_prefs_(local_state_prefs),
+ clock_(base::DefaultClock::GetInstance()) {
ParseTriggerTypeAndQuotaParam(&trigger_type_and_quota_list_);
+ LoadTriggerEventsFromPref();
}
TriggerThrottler::~TriggerThrottler() {}
@@ -120,7 +134,7 @@ bool TriggerThrottler::TriggerCanFire(const TriggerType trigger_type) const {
if (!base::ContainsKey(trigger_events_, trigger_type))
return true;
- const std::vector<time_t>& timestamps = trigger_events_.at(trigger_type);
+ const std::vector<base::Time>& timestamps = trigger_events_.at(trigger_type);
// More quota is available, so the trigger can fire again.
if (trigger_quota > timestamps.size())
return true;
@@ -131,7 +145,7 @@ bool TriggerThrottler::TriggerCanFire(const TriggerType trigger_type) const {
// the current day or earlier.
base::Time min_timestamp = clock_->Now() - kOneDayTimeDelta;
const size_t pos = timestamps.size() - trigger_quota;
- return timestamps.at(pos) < min_timestamp.ToTimeT();
+ return timestamps.at(pos) < min_timestamp;
}
void TriggerThrottler::TriggerFired(const TriggerType trigger_type) {
@@ -143,30 +157,33 @@ void TriggerThrottler::TriggerFired(const TriggerType trigger_type) {
return;
// Otherwise, record that the trigger fired.
- std::vector<time_t>* timestamps = &trigger_events_[trigger_type];
- timestamps->push_back(clock_->Now().ToTimeT());
+ std::vector<base::Time>* timestamps = &trigger_events_[trigger_type];
+ timestamps->push_back(clock_->Now());
// Clean up the trigger events map.
CleanupOldEvents();
+
+ // Update the pref
+ WriteTriggerEventsToPref();
}
void TriggerThrottler::CleanupOldEvents() {
for (const auto& map_iter : trigger_events_) {
const TriggerType trigger_type = map_iter.first;
const size_t trigger_quota = GetDailyQuotaForTrigger(trigger_type);
- const std::vector<time_t>& trigger_times = map_iter.second;
+ const std::vector<base::Time>& trigger_times = map_iter.second;
// Skip the cleanup if we have quota room, quotas should generally be small.
if (trigger_times.size() < trigger_quota)
return;
- std::vector<time_t> tmp_trigger_times;
+ std::vector<base::Time> tmp_trigger_times;
base::Time min_timestamp = clock_->Now() - kOneDayTimeDelta;
// Go over the event times for this trigger and keep timestamps which are
// newer than |min_timestamp|. We put timestamps in a temp vector that will
// get swapped into the map in place of the existing vector.
- for (const time_t timestamp : trigger_times) {
- if (timestamp > min_timestamp.ToTimeT())
+ for (const base::Time timestamp : trigger_times) {
+ if (timestamp > min_timestamp)
tmp_trigger_times.push_back(timestamp);
}
@@ -174,6 +191,52 @@ void TriggerThrottler::CleanupOldEvents() {
}
}
+void TriggerThrottler::LoadTriggerEventsFromPref() {
+ trigger_events_.clear();
+ if (!local_state_prefs_)
+ return;
+
+ const base::DictionaryValue* event_dict = local_state_prefs_->GetDictionary(
+ prefs::kSafeBrowsingTriggerEventTimestamps);
+ for (const auto& trigger_pair : event_dict->DictItems()) {
+ // Check that the first item in the pair is convertible to a trigger type
+ // and that the second item is a list.
+ int trigger_type_int;
+ if (!base::StringToInt(trigger_pair.first, &trigger_type_int) ||
+ trigger_type_int < static_cast<int>(TriggerType::kMinTriggerType) ||
+ trigger_type_int > static_cast<int>(TriggerType::kMaxTriggerType)) {
+ continue;
+ }
+ if (!trigger_pair.second.is_list())
+ continue;
+
+ const TriggerType trigger_type = static_cast<TriggerType>(trigger_type_int);
+ for (const auto& timestamp : trigger_pair.second.GetList()) {
+ if (timestamp.is_double())
+ trigger_events_[trigger_type].push_back(
+ base::Time::FromDoubleT(timestamp.GetDouble()));
+ }
+ }
+}
+
+void TriggerThrottler::WriteTriggerEventsToPref() {
+ if (!local_state_prefs_)
+ return;
+
+ base::DictionaryValue trigger_dict;
+ for (const auto& trigger_item : trigger_events_) {
+ base::Value* pref_timestamps = trigger_dict.SetKey(
+ base::IntToString(static_cast<int>(trigger_item.first)),
+ base::Value(base::Value::Type::LIST));
+ for (const base::Time timestamp : trigger_item.second) {
+ pref_timestamps->GetList().push_back(base::Value(timestamp.ToDoubleT()));
+ }
+ }
+
+ local_state_prefs_->Set(prefs::kSafeBrowsingTriggerEventTimestamps,
+ trigger_dict);
+}
+
size_t TriggerThrottler::GetDailyQuotaForTrigger(
const TriggerType trigger_type) const {
size_t quota_from_finch = 0;
@@ -204,4 +267,9 @@ size_t TriggerThrottler::GetDailyQuotaForTrigger(
return 0;
}
+void TriggerThrottler::ResetPrefsForTesting(PrefService* local_state_prefs) {
+ local_state_prefs_ = local_state_prefs;
+ LoadTriggerEventsFromPref();
+}
+
} // namespace safe_browsing
diff --git a/chromium/components/safe_browsing/triggers/trigger_throttler.h b/chromium/components/safe_browsing/triggers/trigger_throttler.h
index 6de4d538d15..0ce7c36b96d 100644
--- a/chromium/components/safe_browsing/triggers/trigger_throttler.h
+++ b/chromium/components/safe_browsing/triggers/trigger_throttler.h
@@ -13,20 +13,31 @@
#include "base/macros.h"
#include "base/time/clock.h"
+class PrefService;
+
namespace safe_browsing {
+// Default quota for ad sampler trigger.
+extern const size_t kAdSamplerTriggerDefaultQuota;
+
+// Param name of the finch param containing the quota for the suspicious site
+// trigger.
+extern const char kSuspiciousSiteTriggerQuotaParam[];
// Param name of the finch param containing the comma-separated list of trigger
// types and daily quotas.
+// TODO(crbug.com/744869): This param should be deprecated after ad sampler
+// launch in favour of having a unique quota feature and param per trigger.
+// Having a single shared feature makes it impossible to run multiple trigger
+// trials simultaneously.
extern const char kTriggerTypeAndQuotaParam[];
-// Default quota for ad sampler trigger.
-extern const size_t kAdSamplerTriggerDefaultQuota;
-
enum class TriggerType {
SECURITY_INTERSTITIAL = 1,
AD_SAMPLE = 2,
GAIA_PASSWORD_REUSE = 3,
SUSPICIOUS_SITE = 4,
+ kMinTriggerType = SECURITY_INTERSTITIAL,
+ kMaxTriggerType = SUSPICIOUS_SITE,
};
struct TriggerTypeHash {
@@ -37,7 +48,7 @@ struct TriggerTypeHash {
// A map for storing a list of event timestamps for different trigger types.
using TriggerTimestampMap =
- std::unordered_map<TriggerType, std::vector<time_t>, TriggerTypeHash>;
+ std::unordered_map<TriggerType, std::vector<base::Time>, TriggerTypeHash>;
// A pair containing a TriggerType and its associated daily report quota.
using TriggerTypeAndQuotaItem = std::pair<TriggerType, int>;
@@ -46,7 +57,7 @@ using TriggerTypeAndQuotaItem = std::pair<TriggerType, int>;
// and throttles them if they fire too often.
class TriggerThrottler {
public:
- TriggerThrottler();
+ TriggerThrottler(PrefService* local_state_prefs);
virtual ~TriggerThrottler();
// Check if the the specified |trigger_type| has quota available and is
@@ -67,9 +78,23 @@ class TriggerThrottler {
// Called to periodically clean-up the list of event timestamps.
void CleanupOldEvents();
+ // Loads trigger events that have been stored in preferences and adds them
+ // to |trigger_events_|.
+ void LoadTriggerEventsFromPref();
+
+ // Updates preferences with current contents of |trigger_events_|.
+ void WriteTriggerEventsToPref();
+
// Returns the daily quota for the specified trigger.
size_t GetDailyQuotaForTrigger(const TriggerType trigger_type) const;
+ // Resets |local_state_prefs_|. For testing.
+ void ResetPrefsForTesting(PrefService* local_state_prefs);
+
+ // Pref service for accessing local state prefs (ie: unsynced, tied to the
+ // browser not to a profile). Used to persist quota.
+ PrefService* local_state_prefs_;
+
// Can be set for testing.
base::Clock* clock_;
diff --git a/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc b/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc
index e0288d761f6..ca3d5d46df5 100644
--- a/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc
+++ b/chromium/components/safe_browsing/triggers/trigger_throttler_unittest.cc
@@ -8,6 +8,8 @@
#include "base/strings/stringprintf.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/simple_test_clock.h"
+#include "components/prefs/testing_pref_service.h"
+#include "components/safe_browsing/common/safe_browsing_prefs.h"
#include "components/safe_browsing/features.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,8 +20,21 @@ namespace safe_browsing {
class TriggerThrottlerTest : public ::testing::Test {
public:
+ TriggerThrottlerTest() : trigger_throttler_(nullptr) {}
+
+ void SetUp() override {
+ safe_browsing::RegisterLocalStatePrefs(pref_service_.registry());
+ trigger_throttler_.ResetPrefsForTesting(&pref_service_);
+ }
+
void SetQuotaForTriggerType(TriggerType trigger_type, size_t max_quota) {
- trigger_throttler_.trigger_type_and_quota_list_.push_back(
+ SetQuotaForTriggerType(&trigger_throttler_, trigger_type, max_quota);
+ }
+
+ void SetQuotaForTriggerType(TriggerThrottler* throttler,
+ TriggerType trigger_type,
+ size_t max_quota) {
+ throttler->trigger_type_and_quota_list_.push_back(
std::make_pair(trigger_type, max_quota));
}
@@ -29,12 +44,15 @@ class TriggerThrottlerTest : public ::testing::Test {
trigger_throttler_.SetClockForTesting(clock);
}
- std::vector<time_t> GetEventTimestampsForTriggerType(
+ std::vector<base::Time> GetEventTimestampsForTriggerType(
TriggerType trigger_type) {
return trigger_throttler_.trigger_events_[trigger_type];
}
+ PrefService* get_pref_service() { return &pref_service_; }
+
private:
+ TestingPrefServiceSimple pref_service_;
TriggerThrottler trigger_throttler_;
};
@@ -100,7 +118,7 @@ TEST_F(TriggerThrottlerTest, TriggerQuotaResetsAfterOneDay) {
// available again.
base::SimpleTestClock test_clock;
test_clock.SetNow(base::Time::Now() - base::TimeDelta::FromDays(10));
- time_t base_ts = test_clock.Now().ToTimeT();
+ base::Time base_ts = test_clock.Now();
SetTestClock(&test_clock);
SetQuotaForTriggerType(TriggerType::AD_SAMPLE, 2);
@@ -124,7 +142,7 @@ TEST_F(TriggerThrottlerTest, TriggerQuotaResetsAfterOneDay) {
// quota should be available now.
test_clock.Advance(base::TimeDelta::FromDays(1) +
base::TimeDelta::FromSeconds(1));
- time_t advanced_ts = test_clock.Now().ToTimeT();
+ base::Time advanced_ts = test_clock.Now();
EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
// The previous time stamps should remain in the throttler.
@@ -138,26 +156,74 @@ TEST_F(TriggerThrottlerTest, TriggerQuotaResetsAfterOneDay) {
ElementsAre(advanced_ts));
}
+TEST_F(TriggerThrottlerTest, TriggerQuotaPersistence) {
+ // Test that trigger quota is persisted in prefs when triggers fire, and
+ // retrieved from prefs on startup.
+
+ // Set some low quotas for two triggers
+ SetQuotaForTriggerType(TriggerType::AD_SAMPLE, 3);
+ SetQuotaForTriggerType(TriggerType::SUSPICIOUS_SITE, 3);
+
+ // Ensure each trigger can fire.
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::SUSPICIOUS_SITE));
+
+ // Fire each trigger twice to store some events.
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+ throttler()->TriggerFired(TriggerType::AD_SAMPLE);
+ throttler()->TriggerFired(TriggerType::SUSPICIOUS_SITE);
+ throttler()->TriggerFired(TriggerType::SUSPICIOUS_SITE);
+
+ // The AD_SAMPLE trigger is now out of quota, while SUSPICIOUS_SITE can still
+ // fire one more time.
+ EXPECT_FALSE(throttler()->TriggerCanFire(TriggerType::AD_SAMPLE));
+ EXPECT_TRUE(throttler()->TriggerCanFire(TriggerType::SUSPICIOUS_SITE));
+
+ // Check the pref directly, it should reflect the events for each trigger.
+ PrefService* prefs = get_pref_service();
+ const base::DictionaryValue* event_dict =
+ prefs->GetDictionary(prefs::kSafeBrowsingTriggerEventTimestamps);
+
+ const std::string kAdSampleKey = "2";
+ const base::Value* ad_sample_events = event_dict->FindKey(kAdSampleKey);
+ EXPECT_EQ(3u, ad_sample_events->GetList().size());
+
+ const std::string kSuspiciousSiteKey = "4";
+ const base::Value* suspicious_site_events =
+ event_dict->FindKey(kSuspiciousSiteKey);
+ EXPECT_EQ(2u, suspicious_site_events->GetList().size());
+
+ // To simulate a new startup of the browser, we can create another throttler
+ // using the same quota configuration and pref store. It should read the
+ // events from prefs and and reflect the same status for each trigger.
+ TriggerThrottler throttler2(prefs);
+ SetQuotaForTriggerType(&throttler2, TriggerType::AD_SAMPLE, 3);
+ SetQuotaForTriggerType(&throttler2, TriggerType::SUSPICIOUS_SITE, 3);
+ EXPECT_FALSE(throttler2.TriggerCanFire(TriggerType::AD_SAMPLE));
+ EXPECT_TRUE(throttler2.TriggerCanFire(TriggerType::SUSPICIOUS_SITE));
+}
+
class TriggerThrottlerTestFinch : public ::testing::Test {
public:
std::unique_ptr<base::FeatureList> SetupQuotaInFinch(
const TriggerType trigger_type,
const std::string& group_name,
int quota) {
- base::FieldTrial* trial = base::FieldTrialList::CreateFieldTrial(
- safe_browsing::kTriggerThrottlerDailyQuotaFeature.name, group_name);
+ std::string feature_name = "";
+ std::string param_name = "";
+ GetFeatureAndParamForTrigger(trigger_type, &feature_name, &param_name);
+
+ base::FieldTrial* trial =
+ base::FieldTrialList::CreateFieldTrial(feature_name, group_name);
std::map<std::string, std::string> feature_params;
- feature_params[std::string(safe_browsing::kTriggerTypeAndQuotaParam)] =
- base::StringPrintf("%d,%d", trigger_type, quota);
- base::AssociateFieldTrialParams(
- safe_browsing::kTriggerThrottlerDailyQuotaFeature.name, group_name,
- feature_params);
+ feature_params[param_name] =
+ GetQuotaParamValueForTrigger(trigger_type, quota);
+ base::AssociateFieldTrialParams(feature_name, group_name, feature_params);
std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
- feature_list->InitializeFromCommandLine(
- safe_browsing::kTriggerThrottlerDailyQuotaFeature.name, std::string());
+ feature_list->InitializeFromCommandLine(feature_name, std::string());
feature_list->AssociateReportingFieldTrial(
- safe_browsing::kTriggerThrottlerDailyQuotaFeature.name,
- base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
+ feature_name, base::FeatureList::OVERRIDE_ENABLE_FEATURE, trial);
return feature_list;
}
@@ -165,6 +231,35 @@ class TriggerThrottlerTestFinch : public ::testing::Test {
const TriggerType trigger_type) {
return throttler.GetDailyQuotaForTrigger(trigger_type);
}
+
+ private:
+ void GetFeatureAndParamForTrigger(const TriggerType trigger_type,
+ std::string* out_feature,
+ std::string* out_param) {
+ switch (trigger_type) {
+ case TriggerType::AD_SAMPLE:
+ *out_feature = safe_browsing::kTriggerThrottlerDailyQuotaFeature.name;
+ *out_param = safe_browsing::kTriggerTypeAndQuotaParam;
+ break;
+
+ case TriggerType::SUSPICIOUS_SITE:
+ *out_feature = safe_browsing::kSuspiciousSiteTriggerQuotaFeature.name;
+ *out_param = safe_browsing::kSuspiciousSiteTriggerQuotaParam;
+ break;
+
+ default:
+ NOTREACHED() << "Unhandled trigger type: "
+ << static_cast<int>(trigger_type);
+ }
+ }
+
+ std::string GetQuotaParamValueForTrigger(const TriggerType trigger_type,
+ int quota) {
+ if (trigger_type == TriggerType::AD_SAMPLE)
+ return base::StringPrintf("%d,%d", trigger_type, quota);
+ else
+ return base::StringPrintf("%d", quota);
+ }
};
TEST_F(TriggerThrottlerTestFinch, ConfigureQuotaViaFinch) {
@@ -176,7 +271,7 @@ TEST_F(TriggerThrottlerTestFinch, ConfigureQuotaViaFinch) {
// The throttler has been configured (above) to allow ad samples to fire three
// times per day.
- TriggerThrottler throttler;
+ TriggerThrottler throttler(nullptr);
// First three triggers should work
EXPECT_TRUE(throttler.TriggerCanFire(TriggerType::AD_SAMPLE));
@@ -193,7 +288,7 @@ TEST_F(TriggerThrottlerTestFinch, ConfigureQuotaViaFinch) {
TEST_F(TriggerThrottlerTestFinch, AdSamplerDefaultQuota) {
// Make sure that the ad sampler gets its own default quota when no finch
// config exists, but the quota can be overwritten through Finch.
- TriggerThrottler throttler_default;
+ TriggerThrottler throttler_default(nullptr);
EXPECT_EQ(kAdSamplerTriggerDefaultQuota,
GetDailyQuotaForTrigger(throttler_default, TriggerType::AD_SAMPLE));
EXPECT_TRUE(throttler_default.TriggerCanFire(TriggerType::AD_SAMPLE));
@@ -202,14 +297,14 @@ TEST_F(TriggerThrottlerTestFinch, AdSamplerDefaultQuota) {
base::test::ScopedFeatureList scoped_feature_list;
scoped_feature_list.InitWithFeatureList(SetupQuotaInFinch(
TriggerType::AD_SAMPLE, "Group_AdSamplerDefaultQuota", 4));
- TriggerThrottler throttler_finch;
+ TriggerThrottler throttler_finch(nullptr);
EXPECT_EQ(4u,
GetDailyQuotaForTrigger(throttler_finch, TriggerType::AD_SAMPLE));
}
TEST_F(TriggerThrottlerTestFinch, SuspiciousSiteTriggerDefaultQuota) {
// Ensure that suspicious site trigger is disabled by default.
- TriggerThrottler throttler_default;
+ TriggerThrottler throttler_default(nullptr);
EXPECT_EQ(0u, GetDailyQuotaForTrigger(throttler_default,
TriggerType::SUSPICIOUS_SITE));
EXPECT_FALSE(throttler_default.TriggerCanFire(TriggerType::SUSPICIOUS_SITE));
@@ -219,7 +314,7 @@ TEST_F(TriggerThrottlerTestFinch, SuspiciousSiteTriggerDefaultQuota) {
scoped_feature_list.InitWithFeatureList(
SetupQuotaInFinch(TriggerType::SUSPICIOUS_SITE,
"Group_SuspiciousSiteTriggerDefaultQuota", 5));
- TriggerThrottler throttler_finch;
+ TriggerThrottler throttler_finch(nullptr);
EXPECT_EQ(5u, GetDailyQuotaForTrigger(throttler_finch,
TriggerType::SUSPICIOUS_SITE));
}
diff --git a/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc b/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc
index 6dfff9fb04e..b6bbd413c0e 100644
--- a/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc
+++ b/chromium/components/safe_browsing/web_ui/safe_browsing_ui.cc
@@ -366,7 +366,7 @@ void SafeBrowsingUIHandler::GetSentThreatDetails(const base::ListValue* args) {
for (const auto& report : reports) {
sent_reports.GetList().push_back(
- base::Value(ParseThreatDetailsInfo(*report.get())));
+ base::Value(ParseThreatDetailsInfo(*report)));
AllowJavascript();
std::string callback_id;
diff --git a/chromium/components/search_engines/default_search_manager.cc b/chromium/components/search_engines/default_search_manager.cc
index b787870afc9..07f30687e40 100644
--- a/chromium/components/search_engines/default_search_manager.cc
+++ b/chromium/components/search_engines/default_search_manager.cc
@@ -227,6 +227,7 @@ void DefaultSearchManager::MergePrefsDataWithPrepopulated() {
engine->date_created = prefs_default_search_->date_created;
engine->last_modified = prefs_default_search_->last_modified;
engine->last_visited = prefs_default_search_->last_visited;
+ engine->favicon_url = prefs_default_search_->favicon_url;
prefs_default_search_ = std::move(engine);
}
diff --git a/chromium/components/search_engines/default_search_manager_unittest.cc b/chromium/components/search_engines/default_search_manager_unittest.cc
index 5277c1921b8..05f596b484c 100644
--- a/chromium/components/search_engines/default_search_manager_unittest.cc
+++ b/chromium/components/search_engines/default_search_manager_unittest.cc
@@ -137,7 +137,7 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByUserPref) {
// Setting a user pref overrides the pre-populated values.
std::unique_ptr<TemplateURLData> data = GenerateDummyTemplateURLData("user");
- manager.SetUserSelectedDefaultSearchEngine(*data.get());
+ manager.SetUserSelectedDefaultSearchEngine(*data);
ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source));
EXPECT_EQ(DefaultSearchManager::FROM_USER, source);
@@ -148,7 +148,7 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByUserPref) {
GenerateDummyTemplateURLData("user2");
DefaultSearchManager other_manager(pref_service(),
DefaultSearchManager::ObserverCallback());
- other_manager.SetUserSelectedDefaultSearchEngine(*new_data.get());
+ other_manager.SetUserSelectedDefaultSearchEngine(*new_data);
ExpectSimilar(new_data.get(), manager.GetDefaultSearchEngine(&source));
EXPECT_EQ(DefaultSearchManager::FROM_USER, source);
@@ -196,7 +196,7 @@ TEST_F(DefaultSearchManagerTest, DefaultSearchSetByPolicy) {
DefaultSearchManager manager(pref_service(),
DefaultSearchManager::ObserverCallback());
std::unique_ptr<TemplateURLData> data = GenerateDummyTemplateURLData("user");
- manager.SetUserSelectedDefaultSearchEngine(*data.get());
+ manager.SetUserSelectedDefaultSearchEngine(*data);
DefaultSearchManager::Source source = DefaultSearchManager::FROM_FALLBACK;
ExpectSimilar(data.get(), manager.GetDefaultSearchEngine(&source));
diff --git a/chromium/components/search_engines/prepopulated_engines.json b/chromium/components/search_engines/prepopulated_engines.json
index b575eb845b5..4571a4ca4f3 100644
--- a/chromium/components/search_engines/prepopulated_engines.json
+++ b/chromium/components/search_engines/prepopulated_engines.json
@@ -32,7 +32,7 @@
// Increment this if you change the data in ways that mean users with
// existing data should get a new version.
- "kCurrentDataVersion": 100
+ "kCurrentDataVersion": 102
},
// The following engines are included in country lists and are added to the
@@ -94,7 +94,7 @@
"bing": {
"name": "Bing",
"keyword": "bing.com",
- "favicon_url": "https://www.bing.com/s/a/bing_p.ico",
+ "favicon_url": "https://www.bing.com/sa/simg/bing_p_rr_teal_min.ico",
"search_url": "https://www.bing.com/search?q={searchTerms}&PC=U316&FORM=CHROMN",
"suggest_url": "https://www.bing.com/osjson.aspx?query={searchTerms}&language={language}&PC=U316",
"image_url": "https://www.bing.com/images/detail/search?iss=sbi&FORM=CHROMI#enterInsights",
@@ -108,8 +108,8 @@
"name": "Daum",
"keyword": "daum.net",
"favicon_url": "https://search.daum.net/favicon.ico",
- "search_url": "https://search.daum.net/search?ie={inputEncoding}&q={searchTerms}",
- "suggest_url": "https://sug.search.daum.net/search_nsuggest?mod=fxjson&ie={inputEncoding}&code=utf_in_out&q={searchTerms}",
+ "search_url": "https://search.daum.net/search?w=tot&DA=JU5&q={searchTerms}",
+ "suggest_url": "https://suggest.search.daum.net/sushi/opensearch/pc?q={searchTerms}&DA=JU6",
"type": "SEARCH_ENGINE_DAUM",
"id": 68
},
@@ -117,7 +117,7 @@
"google": {
"name": "Google",
"keyword": "google.com",
- "favicon_url": "https://www.google.com/favicon.ico",
+ "favicon_url": "https://www.google.com/images/branding/product/ico/googleg_lodp.ico",
"search_url": "{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchFieldtrialParameter}{google:iOSSearchLanguage}{google:searchClient}{google:sourceId}{google:contextualSearchVersion}ie={inputEncoding}",
"suggest_url": "{google:baseSuggestURL}search?{google:searchFieldtrialParameter}client={google:suggestClient}&gs_ri={google:suggestRid}&xssi=t&q={searchTerms}&{google:inputType}{google:cursorPosition}{google:currentPageUrl}{google:pageClassification}{google:searchVersion}{google:sessionToken}{google:prefetchQuery}sugkey={google:suggestAPIKeyParameter}",
"image_url": "{google:baseURL}searchbyimage/upload",
diff --git a/chromium/components/search_engines/search_host_to_urls_map.cc b/chromium/components/search_engines/search_host_to_urls_map.cc
index adb1ed26524..fd28f185114 100644
--- a/chromium/components/search_engines/search_host_to_urls_map.cc
+++ b/chromium/components/search_engines/search_host_to_urls_map.cc
@@ -16,7 +16,7 @@ SearchHostToURLsMap::~SearchHostToURLsMap() {
}
void SearchHostToURLsMap::Init(
- const TemplateURLService::OwnedTemplateURLVector& template_urls,
+ const TemplateURL::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data) {
DCHECK(!initialized_);
initialized_ = true; // Set here so Add doesn't assert.
@@ -73,7 +73,7 @@ SearchHostToURLsMap::TemplateURLSet* SearchHostToURLsMap::GetURLsForHost(
}
void SearchHostToURLsMap::Add(
- const TemplateURLService::OwnedTemplateURLVector& template_urls,
+ const TemplateURL::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data) {
for (const auto& turl : template_urls)
Add(turl.get(), search_terms_data);
diff --git a/chromium/components/search_engines/search_host_to_urls_map.h b/chromium/components/search_engines/search_host_to_urls_map.h
index 5afd62600df..dbf86b8aaa8 100644
--- a/chromium/components/search_engines/search_host_to_urls_map.h
+++ b/chromium/components/search_engines/search_host_to_urls_map.h
@@ -12,7 +12,7 @@
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/strings/string_piece.h"
-#include "components/search_engines/template_url_service.h"
+#include "components/search_engines/template_url.h"
// Holds the host to template url mappings for the search providers. WARNING:
// This class does not own any TemplateURLs passed to it and it is up to the
@@ -25,7 +25,7 @@ class SearchHostToURLsMap {
~SearchHostToURLsMap();
// Initializes the map.
- void Init(const TemplateURLService::OwnedTemplateURLVector& template_urls,
+ void Init(const TemplateURL::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data);
// Adds a new TemplateURL to the map. Since |template_url| is owned
@@ -50,7 +50,7 @@ class SearchHostToURLsMap {
typedef std::map<std::string, TemplateURLSet, std::less<>> HostToURLsMap;
// Adds many URLs to the map.
- void Add(const TemplateURLService::OwnedTemplateURLVector& template_urls,
+ void Add(const TemplateURL::OwnedTemplateURLVector& template_urls,
const SearchTermsData& search_terms_data);
// Maps from host to set of TemplateURLs whose search url host is host.
diff --git a/chromium/components/search_engines/template_url.cc b/chromium/components/search_engines/template_url.cc
index c7c416859ee..bcb27362724 100644
--- a/chromium/components/search_engines/template_url.cc
+++ b/chromium/components/search_engines/template_url.cc
@@ -248,27 +248,13 @@ TemplateURLRef::SearchTermsArgs::ContextualSearchParams::EstimateMemoryUsage()
// TemplateURLRef -------------------------------------------------------------
TemplateURLRef::TemplateURLRef(const TemplateURL* owner, Type type)
- : owner_(owner),
- type_(type),
- index_in_owner_(0),
- parsed_(false),
- valid_(false),
- supports_replacements_(false),
- search_term_key_location_(url::Parsed::QUERY),
- prepopulated_(false) {
+ : owner_(owner), type_(type) {
DCHECK(owner_);
DCHECK_NE(INDEXED, type_);
}
TemplateURLRef::TemplateURLRef(const TemplateURL* owner, size_t index_in_owner)
- : owner_(owner),
- type_(INDEXED),
- index_in_owner_(index_in_owner),
- parsed_(false),
- valid_(false),
- supports_replacements_(false),
- search_term_key_location_(url::Parsed::QUERY),
- prepopulated_(false) {
+ : owner_(owner), type_(INDEXED), index_in_owner_(index_in_owner) {
DCHECK(owner_);
DCHECK_LT(index_in_owner_, owner_->alternate_urls().size());
}
@@ -318,11 +304,13 @@ size_t TemplateURLRef::EstimateMemoryUsage() const {
res += base::trace_event::EstimateMemoryUsage(replacements_);
res += base::trace_event::EstimateMemoryUsage(host_);
res += base::trace_event::EstimateMemoryUsage(port_);
- res += base::trace_event::EstimateMemoryUsage(path_);
+ res += base::trace_event::EstimateMemoryUsage(path_prefix_);
+ res += base::trace_event::EstimateMemoryUsage(path_suffix_);
res += base::trace_event::EstimateMemoryUsage(search_term_key_);
res += base::trace_event::EstimateMemoryUsage(search_term_value_prefix_);
res += base::trace_event::EstimateMemoryUsage(search_term_value_suffix_);
res += base::trace_event::EstimateMemoryUsage(post_params_);
+ res += sizeof(path_wildcard_present_);
return res;
}
@@ -445,10 +433,10 @@ const std::string& TemplateURLRef::GetHost(
return host_;
}
-const std::string& TemplateURLRef::GetPath(
+std::string TemplateURLRef::GetPath(
const SearchTermsData& search_terms_data) const {
ParseIfNecessary(search_terms_data);
- return path_;
+ return path_prefix_ + path_suffix_;
}
const std::string& TemplateURLRef::GetSearchTermKey(
@@ -534,10 +522,8 @@ bool TemplateURLRef::ExtractSearchTermsFromURL(
return false;
// Host, port, and path must match.
- if ((url.host() != host_) ||
- (url.port() != port_) ||
- ((url.path() != path_) &&
- (search_term_key_location_ != url::Parsed::PATH))) {
+ if ((url.host() != host_) || (url.port() != port_) ||
+ (!PathIsEqual(url) && (search_term_key_location_ != url::Parsed::PATH))) {
return false;
}
@@ -606,10 +592,11 @@ bool TemplateURLRef::ExtractSearchTermsFromURL(
}
void TemplateURLRef::InvalidateCachedValues() const {
- supports_replacements_ = valid_ = parsed_ = false;
+ supports_replacements_ = valid_ = parsed_ = path_wildcard_present_ = false;
host_.clear();
port_.clear();
- path_.clear();
+ path_prefix_.clear();
+ path_suffix_.clear();
search_term_key_.clear();
search_term_key_location_ = url::Parsed::QUERY;
search_term_value_prefix_.clear();
@@ -688,6 +675,8 @@ bool TemplateURLRef::ParseParameter(size_t start,
start));
} else if (parameter == "google:pageClassification") {
replacements->push_back(Replacement(GOOGLE_PAGE_CLASSIFICATION, start));
+ } else if (parameter == "google:pathWildcard") {
+ // Do nothing, we just want the path wildcard removed from the URL.
} else if (parameter == "google:prefetchQuery") {
replacements->push_back(Replacement(GOOGLE_PREFETCH_QUERY, start));
} else if (parameter == "google:RLZ") {
@@ -837,6 +826,28 @@ void TemplateURLRef::ParseIfNecessary(
}
}
+void TemplateURLRef::ParsePath(const std::string& path) const {
+ // Wildcard string used when matching URLs.
+ const std::string wildcard_escaped = "%7Bgoogle:pathWildcard%7D";
+
+ // We only search for the escaped wildcard because we're only replacing it in
+ // the path, and GURL's constructor escapes { and }.
+ size_t wildcard_start = path.find(wildcard_escaped);
+ path_wildcard_present_ = wildcard_start != std::string::npos;
+ path_prefix_ = path.substr(0, wildcard_start);
+ path_suffix_ = path_wildcard_present_
+ ? path.substr(wildcard_start + wildcard_escaped.length())
+ : std::string();
+}
+
+bool TemplateURLRef::PathIsEqual(const GURL& url) const {
+ base::StringPiece path = url.path_piece();
+ if (!path_wildcard_present_)
+ return path == path_prefix_;
+ return ((path.length() >= path_prefix_.length() + path_suffix_.length()) &&
+ path.starts_with(path_prefix_) && path.ends_with(path_suffix_));
+}
+
void TemplateURLRef::ParseHostAndSearchTermKey(
const SearchTermsData& search_terms_data) const {
std::string url_string(GetURL());
@@ -869,13 +880,13 @@ void TemplateURLRef::ParseHostAndSearchTermKey(
search_term_key_ = query_result.key();
search_term_value_prefix_ = query_result.value_prefix();
search_term_value_suffix_ = query_result.value_suffix();
- path_ = url.path();
+ ParsePath(url.path());
} else if (in_ref) {
search_term_key_location_ = url::Parsed::REF;
search_term_key_ = ref_result.key();
search_term_value_prefix_ = ref_result.value_prefix();
search_term_value_suffix_ = ref_result.value_suffix();
- path_ = url.path();
+ ParsePath(url.path());
} else {
DCHECK(in_path);
search_term_key_location_ = url::Parsed::PATH;
@@ -1293,7 +1304,6 @@ bool TemplateURL::MatchesData(const TemplateURL* t_url,
(t_url->suggestions_url_post_params() ==
data->suggestions_url_post_params) &&
(t_url->image_url_post_params() == data->image_url_post_params) &&
- (t_url->favicon_url() == data->favicon_url) &&
(t_url->safe_for_autoreplace() == data->safe_for_autoreplace) &&
(t_url->input_encodings() == data->input_encodings) &&
(t_url->alternate_urls() == data->alternate_urls);
diff --git a/chromium/components/search_engines/template_url.h b/chromium/components/search_engines/template_url.h
index 4fa09c5ef8d..b2411b1474c 100644
--- a/chromium/components/search_engines/template_url.h
+++ b/chromium/components/search_engines/template_url.h
@@ -230,7 +230,7 @@ class TemplateURLRef {
// If this TemplateURLRef is valid and contains one search term, this returns
// the host/path of the URL, otherwise this returns an empty string.
const std::string& GetHost(const SearchTermsData& search_terms_data) const;
- const std::string& GetPath(const SearchTermsData& search_terms_data) const;
+ std::string GetPath(const SearchTermsData& search_terms_data) const;
// If this TemplateURLRef is valid and contains one search term
// in its query or ref, this returns the key of the search term,
@@ -396,6 +396,18 @@ class TemplateURLRef {
// search_offset_.
void ParseIfNecessary(const SearchTermsData& search_terms_data) const;
+ // Parses a wildcard out of |path|, putting the parsed path in |path_prefix_|
+ // and |path_suffix_| and setting |path_wildcard_present_| to true.
+ // In the absence of a wildcard, the full path will be contained in
+ // |path_prefix_| and |path_wildcard_present_| will be false.
+ void ParsePath(const std::string& path) const;
+
+ // Returns whether the path portion of this template URL is equal to the path
+ // in |url|, checking that URL is prefixed/suffixed by
+ // |path_prefix_|/|path_suffix_| if |path_wildcard_present_| is true, or equal
+ // to |path_prefix_| otherwise.
+ bool PathIsEqual(const GURL& url) const;
+
// Extracts the query key and host from the url.
void ParseHostAndSearchTermKey(
const SearchTermsData& search_terms_data) const;
@@ -431,39 +443,44 @@ class TemplateURLRef {
// If |type_| is |INDEXED|, this |index_in_owner_| is used instead to refer to
// a url within our owner.
- size_t index_in_owner_;
+ size_t index_in_owner_ = 0;
// Whether the URL has been parsed.
- mutable bool parsed_;
+ mutable bool parsed_ = false;
// Whether the url was successfully parsed.
- mutable bool valid_;
+ mutable bool valid_ = false;
// The parsed URL. All terms have been stripped out of this with
// replacements_ giving the index of the terms to replace.
mutable std::string parsed_url_;
// Do we support search term replacement?
- mutable bool supports_replacements_;
+ mutable bool supports_replacements_ = false;
// The replaceable parts of url (parsed_url_). These are ordered by index
// into the string, and may be empty.
mutable Replacements replacements_;
+ // Whether the path contains a wildcard.
+ mutable bool path_wildcard_present_ = false;
+
// Host, port, path, key and location of the search term. These are only set
// if the url contains one search term.
mutable std::string host_;
mutable std::string port_;
- mutable std::string path_;
+ mutable std::string path_prefix_;
+ mutable std::string path_suffix_;
mutable std::string search_term_key_;
- mutable url::Parsed::ComponentType search_term_key_location_;
+ mutable url::Parsed::ComponentType search_term_key_location_ =
+ url::Parsed::QUERY;
mutable std::string search_term_value_prefix_;
mutable std::string search_term_value_suffix_;
mutable PostParams post_params_;
// Whether the contained URL is a pre-populated URL.
- bool prepopulated_;
+ bool prepopulated_ = false;
};
@@ -481,6 +498,9 @@ class TemplateURLRef {
// is made a friend so that it can be the exception to this pattern.
class TemplateURL {
public:
+ using TemplateURLVector = std::vector<TemplateURL*>;
+ using OwnedTemplateURLVector = std::vector<std::unique_ptr<TemplateURL>>;
+
enum Type {
// Regular search engine.
NORMAL,
diff --git a/chromium/components/search_engines/template_url_fetcher.cc b/chromium/components/search_engines/template_url_fetcher.cc
index 211e69f9d63..47a8a7904db 100644
--- a/chromium/components/search_engines/template_url_fetcher.cc
+++ b/chromium/components/search_engines/template_url_fetcher.cc
@@ -119,7 +119,7 @@ TemplateURLFetcher::RequestDelegate::RequestDelegate(
void TemplateURLFetcher::RequestDelegate::OnLoaded() {
template_url_subscription_.reset();
- if (!template_url_.get())
+ if (!template_url_)
return;
AddSearchProvider();
// WARNING: AddSearchProvider deletes us.
@@ -146,7 +146,7 @@ void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
template_url_ = TemplateURLParser::Parse(
fetcher_->template_url_service_->search_terms_data(), data.data(),
data.length(), nullptr);
- if (!template_url_.get() ||
+ if (!template_url_ ||
!template_url_->url_ref().SupportsReplacement(
fetcher_->template_url_service_->search_terms_data())) {
fetcher_->RequestCompleted(this);
@@ -162,7 +162,7 @@ void TemplateURLFetcher::RequestDelegate::OnURLFetchComplete(
}
void TemplateURLFetcher::RequestDelegate::AddSearchProvider() {
- DCHECK(template_url_.get());
+ DCHECK(template_url_);
DCHECK(!keyword_.empty());
TemplateURLService* model = fetcher_->template_url_service_;
DCHECK(model);
diff --git a/chromium/components/search_engines/template_url_service.cc b/chromium/components/search_engines/template_url_service.cc
index b1f13701fbb..6ad8d799d05 100644
--- a/chromium/components/search_engines/template_url_service.cc
+++ b/chromium/components/search_engines/template_url_service.cc
@@ -4,36 +4,24 @@
#include "components/search_engines/template_url_service.h"
-#include <algorithm>
-#include <utility>
-
#include "base/auto_reset.h"
#include "base/callback.h"
-#include "base/command_line.h"
-#include "base/compiler_specific.h"
#include "base/debug/crash_logging.h"
#include "base/format_macros.h"
#include "base/guid.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/time/default_clock.h"
-#include "base/time/time.h"
#include "components/omnibox/browser/omnibox_field_trial.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
#include "components/rappor/rappor_service_impl.h"
#include "components/search_engines/search_engines_pref_names.h"
-#include "components/search_engines/search_host_to_urls_map.h"
#include "components/search_engines/search_terms_data.h"
-#include "components/search_engines/template_url.h"
#include "components/search_engines/template_url_prepopulate_data.h"
#include "components/search_engines/template_url_service_client.h"
#include "components/search_engines/template_url_service_observer.h"
#include "components/search_engines/util.h"
-#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_error_factory.h"
#include "components/sync/protocol/search_engine_specifics.pb.h"
#include "components/sync/protocol/sync.pb.h"
@@ -46,13 +34,6 @@ typedef TemplateURLService::SyncDataMap SyncDataMap;
namespace {
-bool IdenticalSyncGUIDs(const TemplateURLData* data, const TemplateURL* turl) {
- if (!data || !turl)
- return !data && !turl;
-
- return data->sync_guid == turl->sync_guid();
-}
-
const char kDeleteSyncedEngineHistogramName[] =
"Search.DeleteSyncedSearchEngine";
@@ -285,57 +266,26 @@ TemplateURLService::TemplateURLService(
google_url_tracker_(google_url_tracker),
rappor_service_(rappor_service),
dsp_change_callback_(dsp_change_callback),
- provider_map_(new SearchHostToURLsMap),
- loaded_(false),
- load_failed_(false),
- disable_load_(false),
- load_handle_(0),
- default_search_provider_(nullptr),
- next_id_(kInvalidTemplateURLID + 1),
- clock_(new base::DefaultClock),
- models_associated_(false),
- processing_syncer_changes_(false),
- dsp_change_origin_(DSP_CHANGE_OTHER),
default_search_manager_(
prefs_,
- base::BindRepeating(&TemplateURLService::OnDefaultSearchChange,
- base::Unretained(this))),
- outstanding_scoper_handles_(0),
- model_mutated_notification_pending_(false) {
+ base::BindRepeating(&TemplateURLService::ApplyDefaultSearchChange,
+ base::Unretained(this))) {
DCHECK(search_terms_data_);
Init(nullptr, 0);
}
TemplateURLService::TemplateURLService(const Initializer* initializers,
const int count)
- : prefs_(nullptr),
- search_terms_data_(new SearchTermsData),
- web_data_service_(nullptr),
- google_url_tracker_(nullptr),
- rappor_service_(nullptr),
- provider_map_(new SearchHostToURLsMap),
- loaded_(false),
- load_failed_(false),
- disable_load_(false),
- load_handle_(0),
- default_search_provider_(nullptr),
- next_id_(kInvalidTemplateURLID + 1),
- clock_(new base::DefaultClock),
- models_associated_(false),
- processing_syncer_changes_(false),
- dsp_change_origin_(DSP_CHANGE_OTHER),
- default_search_manager_(
+ : default_search_manager_(
prefs_,
- base::BindRepeating(&TemplateURLService::OnDefaultSearchChange,
- base::Unretained(this))),
- outstanding_scoper_handles_(0),
- model_mutated_notification_pending_(false) {
+ base::BindRepeating(&TemplateURLService::ApplyDefaultSearchChange,
+ base::Unretained(this))) {
Init(initializers, count);
}
TemplateURLService::~TemplateURLService() {
// |web_data_service_| should be deleted during Shutdown().
- DCHECK(!web_data_service_.get());
+ DCHECK(!web_data_service_);
}
// static
@@ -505,13 +455,22 @@ void TemplateURLService::Remove(const TemplateURL* template_url) {
template_urls_.erase(i);
if (template_url->type() == TemplateURL::NORMAL) {
- if (web_data_service_.get())
+ if (web_data_service_)
web_data_service_->RemoveKeyword(template_url->id());
// Inform sync of the deletion.
ProcessTemplateURLChange(FROM_HERE, template_url,
syncer::SyncChange::ACTION_DELETE);
+ // The default search engine can't be deleted. But the user defined DSE can
+ // be hidden by an extension or policy and then deleted. Clean up the user
+ // prefs then.
+ if (prefs_ &&
+ (template_url->sync_guid() ==
+ prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID))) {
+ prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID, std::string());
+ }
+
UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
DELETE_ENGINE_USER_ACTION, DELETE_ENGINE_MAX);
}
@@ -600,7 +559,7 @@ void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
return;
++url->data_.usage_count;
- if (web_data_service_.get())
+ if (web_data_service_)
web_data_service_->UpdateKeyword(url->data());
}
@@ -624,6 +583,33 @@ void TemplateURLService::ResetTemplateURL(TemplateURL* url,
Update(url, TemplateURL(data));
}
+void TemplateURLService::UpdateProviderFavicons(
+ const GURL& potential_search_url,
+ const GURL& favicon_url) {
+ DCHECK(loaded_);
+ DCHECK(potential_search_url.is_valid());
+
+ const TemplateURLSet* urls_for_host =
+ provider_map_->GetURLsForHost(potential_search_url.host());
+ if (!urls_for_host)
+ return;
+
+ // Make a copy of the container of the matching TemplateURLs, as the original
+ // container is invalidated as we update the contained TemplateURLs.
+ TemplateURLSet urls_for_host_copy(*urls_for_host);
+
+ Scoper scoper(this);
+ for (TemplateURL* turl : urls_for_host_copy) {
+ if (!IsCreatedByExtension(turl) &&
+ turl->IsSearchURL(potential_search_url, search_terms_data()) &&
+ turl->favicon_url() != favicon_url) {
+ TemplateURLData data(turl->data());
+ data.favicon_url = favicon_url;
+ Update(turl, TemplateURL(data));
+ }
+ }
+}
+
bool TemplateURLService::CanMakeDefault(const TemplateURL* url) const {
return
((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
@@ -649,8 +635,8 @@ void TemplateURLService::SetUserSelectedDefaultSearchProvider(
DefaultSearchManager::FROM_USER);
}
} else {
- // We rely on the DefaultSearchManager to call OnDefaultSearchChange if, in
- // fact, the effective DSE changes.
+ // We rely on the DefaultSearchManager to call ApplyDefaultSearchChange if,
+ // in fact, the effective DSE changes.
if (url)
default_search_manager_.SetUserSelectedDefaultSearchEngine(url->data());
else
@@ -764,14 +750,15 @@ void TemplateURLService::Load() {
if (loaded_ || load_handle_ || disable_load_)
return;
- if (web_data_service_.get())
+ if (web_data_service_)
load_handle_ = web_data_service_->GetKeywords(this);
else
ChangeToLoadedState();
}
std::unique_ptr<TemplateURLService::Subscription>
-TemplateURLService::RegisterOnLoadedCallback(const base::Closure& callback) {
+TemplateURLService::RegisterOnLoadedCallback(
+ const base::RepeatingClosure& callback) {
return loaded_ ? std::unique_ptr<TemplateURLService::Subscription>()
: on_loaded_callbacks_.Add(callback);
}
@@ -872,7 +859,7 @@ void TemplateURLService::Shutdown() {
// that no clients of KeywordWebDataService are holding ptrs to it after the
// first phase of the KeyedService Shutdown() process.
if (load_handle_) {
- DCHECK(web_data_service_.get());
+ DCHECK(web_data_service_);
web_data_service_->CancelRequest(load_handle_);
}
web_data_service_ = nullptr;
@@ -931,7 +918,7 @@ syncer::SyncError TemplateURLService::ProcessSyncChanges(
CreateTemplateURLFromTemplateURLAndSyncData(
client_.get(), prefs_, search_terms_data(), existing_turl,
iter->sync_data(), &new_changes));
- if (!turl.get())
+ if (!turl)
continue;
// Explicitly don't check for conflicts against extension keywords; in this
@@ -1001,7 +988,7 @@ syncer::SyncError TemplateURLService::ProcessSyncChanges(
std::make_unique<TemplateURL>(data);
TemplateURL* added = added_ptr.get();
if (Add(std::move(added_ptr)))
- MaybeUpdateDSEAfterSync(added);
+ MaybeUpdateDSEViaPrefs(added);
} else if (iter->change_type() == syncer::SyncChange::ACTION_UPDATE) {
if (!existing_turl) {
error = sync_error_factory_->CreateAndUploadError(
@@ -1016,7 +1003,7 @@ syncer::SyncError TemplateURLService::ProcessSyncChanges(
&new_changes);
}
if (Update(existing_turl, *turl))
- MaybeUpdateDSEAfterSync(existing_turl);
+ MaybeUpdateDSEViaPrefs(existing_turl);
} else {
// We've unexpectedly received an ACTION_INVALID.
error = sync_error_factory_->CreateAndUploadError(
@@ -1043,9 +1030,9 @@ syncer::SyncMergeResult TemplateURLService::MergeDataAndStartSyncing(
std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) {
DCHECK(loaded_);
DCHECK_EQ(type, syncer::SEARCH_ENGINES);
- DCHECK(!sync_processor_.get());
- DCHECK(sync_processor.get());
- DCHECK(sync_error_factory.get());
+ DCHECK(!sync_processor_);
+ DCHECK(sync_processor);
+ DCHECK(sync_error_factory);
syncer::SyncMergeResult merge_result(type);
// Disable sync if we failed to load.
@@ -1086,7 +1073,7 @@ syncer::SyncMergeResult TemplateURLService::MergeDataAndStartSyncing(
CreateTemplateURLFromTemplateURLAndSyncData(
client_.get(), prefs_, search_terms_data(), local_turl,
iter->second, &new_changes));
- if (!sync_turl.get())
+ if (!sync_turl)
continue;
if (pre_sync_deletes_.find(sync_turl->sync_guid()) !=
@@ -1667,11 +1654,10 @@ bool TemplateURLService::Update(TemplateURL* existing_turl,
syncer::SyncChange::ACTION_UPDATE);
}
- if (default_search_provider_ == existing_turl &&
- default_search_provider_source_ == DefaultSearchManager::FROM_USER) {
- default_search_manager_.SetUserSelectedDefaultSearchEngine(
- default_search_provider_->data());
- }
+ // Even if the DSE is controlled by an extension or policy, update the user
+ // preferences as they may take over later.
+ if (default_search_provider_source_ != DefaultSearchManager::FROM_FALLBACK)
+ MaybeUpdateDSEViaPrefs(existing_turl);
DCHECK(!HasDuplicateKeywords());
return true;
@@ -1696,7 +1682,7 @@ void TemplateURLService::UpdateTemplateURLIfPrepopulated(
}
}
-void TemplateURLService::MaybeUpdateDSEAfterSync(TemplateURL* synced_turl) {
+void TemplateURLService::MaybeUpdateDSEViaPrefs(TemplateURL* synced_turl) {
if (prefs_ &&
(synced_turl->sync_guid() ==
prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID))) {
@@ -1836,17 +1822,6 @@ void TemplateURLService::GoogleBaseURLChanged() {
}
}
-void TemplateURLService::OnDefaultSearchChange(
- const TemplateURLData* data,
- DefaultSearchManager::Source source) {
- if (prefs_ && (source == DefaultSearchManager::FROM_USER) &&
- ((source != default_search_provider_source_) ||
- !IdenticalSyncGUIDs(data, GetDefaultSearchProvider()))) {
- prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID, data->sync_guid);
- }
- ApplyDefaultSearchChange(data, source);
-}
-
void TemplateURLService::ApplyDefaultSearchChange(
const TemplateURLData* data,
DefaultSearchManager::Source source) {
@@ -2012,7 +1987,7 @@ TemplateURL* TemplateURLService::Add(std::unique_ptr<TemplateURL> template_url,
AddToMaps(template_url_ptr);
if (newly_adding && (template_url_ptr->type() == TemplateURL::NORMAL)) {
- if (web_data_service_.get())
+ if (web_data_service_)
web_data_service_->AddKeyword(template_url_ptr->data());
// Inform sync of the addition. Note that this will assign a GUID to
@@ -2062,7 +2037,7 @@ void TemplateURLService::UpdateProvidersCreatedByPolicy(
TemplateURLID id = template_url->id();
RemoveFromMaps(template_url);
i = template_urls->erase(i);
- if (web_data_service_.get())
+ if (web_data_service_)
web_data_service_->RemoveKeyword(id);
} else {
++i;
@@ -2284,7 +2259,7 @@ void TemplateURLService::MergeInSyncTemplateURL(
base::AutoReset<DefaultSearchChangeOrigin> change_origin(
&dsp_change_origin_, DSP_CHANGE_SYNC_ADD);
if (Add(std::move(added_ptr)))
- MaybeUpdateDSEAfterSync(added);
+ MaybeUpdateDSEViaPrefs(added);
merge_result->set_num_items_added(merge_result->num_items_added() + 1);
}
}
@@ -2297,7 +2272,7 @@ void TemplateURLService::PatchMissingSyncGUIDs(
if (template_url->sync_guid().empty() &&
(template_url->type() == TemplateURL::NORMAL)) {
template_url->data_.sync_guid = base::GenerateGUID();
- if (web_data_service_.get())
+ if (web_data_service_)
web_data_service_->UpdateKeyword(template_url->data());
}
}
diff --git a/chromium/components/search_engines/template_url_service.h b/chromium/components/search_engines/template_url_service.h
index 2e9ebc74c79..605bce55082 100644
--- a/chromium/components/search_engines/template_url_service.h
+++ b/chromium/components/search_engines/template_url_service.h
@@ -7,36 +7,26 @@
#include <stddef.h>
-#include <list>
-#include <map>
-#include <memory>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
#include "base/callback_list.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
-#include "base/time/clock.h"
+#include "base/time/default_clock.h"
#include "components/google/core/browser/google_url_tracker.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/search_engines/default_search_manager.h"
#include "components/search_engines/keyword_web_data_service.h"
+#include "components/search_engines/search_host_to_urls_map.h"
+#include "components/search_engines/search_terms_data.h"
#include "components/search_engines/template_url.h"
-#include "components/search_engines/template_url_id.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/syncable_service.h"
#include "components/webdata/common/web_data_service_consumer.h"
class GURL;
class PrefService;
-class SearchHostToURLsMap;
-class SearchTermsData;
-class TemplateURL;
class TemplateURLServiceClient;
class TemplateURLServiceObserver;
struct TemplateURLData;
@@ -78,8 +68,8 @@ class TemplateURLService : public WebDataServiceConsumer,
public syncer::SyncableService {
public:
using QueryTerms = std::map<std::string, std::string>;
- using TemplateURLVector = std::vector<TemplateURL*>;
- using OwnedTemplateURLVector = std::vector<std::unique_ptr<TemplateURL>>;
+ using TemplateURLVector = TemplateURL::TemplateURLVector;
+ using OwnedTemplateURLVector = TemplateURL::OwnedTemplateURLVector;
using SyncDataMap = std::map<std::string, syncer::SyncData>;
using Subscription = base::CallbackList<void(void)>::Subscription;
@@ -111,7 +101,7 @@ class TemplateURLService : public WebDataServiceConsumer,
std::unique_ptr<TemplateURLServiceClient> client,
GoogleURLTracker* google_url_tracker,
rappor::RapporServiceImpl* rappor_service,
- const base::Closure& dsp_change_callback);
+ const base::RepeatingClosure& dsp_change_callback);
// The following is for testing.
TemplateURLService(const Initializer* initializers, const int count);
~TemplateURLService() override;
@@ -248,6 +238,11 @@ class TemplateURLService : public WebDataServiceConsumer,
const base::string16& keyword,
const std::string& search_url);
+ // Updates any search providers matching |potential_search_url| with the new
+ // favicon location |favicon_url|.
+ void UpdateProviderFavicons(const GURL& potential_search_url,
+ const GURL& favicon_url);
+
// Return true if the given |url| can be made the default. This returns false
// regardless of |url| if the default search provider is managed by policy or
// controlled by an extension.
@@ -310,7 +305,7 @@ class TemplateURLService : public WebDataServiceConsumer,
//
// If the service has already loaded, this function does nothing.
std::unique_ptr<Subscription> RegisterOnLoadedCallback(
- const base::Closure& callback);
+ const base::RepeatingClosure& callback);
#if defined(UNIT_TEST)
void set_loaded(bool value) { loaded_ = value; }
@@ -534,11 +529,6 @@ class TemplateURLService : public WebDataServiceConsumer,
// Transitions to the loaded state.
void ChangeToLoadedState();
- // Called by DefaultSearchManager when the effective default search engine has
- // changed.
- void OnDefaultSearchChange(const TemplateURLData* new_dse_data,
- DefaultSearchManager::Source source);
-
// Applies a DSE change and reports metrics if appropriate.
void ApplyDefaultSearchChange(const TemplateURLData* new_dse_data,
DefaultSearchManager::Source source);
@@ -579,9 +569,9 @@ class TemplateURLService : public WebDataServiceConsumer,
PrefService* prefs);
// If the TemplateURL's sync GUID matches the kSyncedDefaultSearchProviderGUID
- // preference it will be used to update the DSE in memory and as persisted in
- // preferences.
- void MaybeUpdateDSEAfterSync(TemplateURL* synced_turl);
+ // preference it will be used to update the DSE in prefs.
+ // OnDefaultSearchChange may be triggered as a result.
+ void MaybeUpdateDSEViaPrefs(TemplateURL* synced_turl);
// Iterates through the TemplateURLs to see if one matches the visited url.
// For each TemplateURL whose url matches the visited url
@@ -720,24 +710,24 @@ class TemplateURLService : public WebDataServiceConsumer,
bool HasDuplicateKeywords() const;
// ---------- Browser state related members ---------------------------------
- PrefService* prefs_;
+ PrefService* prefs_ = nullptr;
- std::unique_ptr<SearchTermsData> search_terms_data_;
+ std::unique_ptr<SearchTermsData> search_terms_data_ =
+ std::make_unique<SearchTermsData>();
// ---------- Dependencies on other components ------------------------------
// Service used to store entries.
- scoped_refptr<KeywordWebDataService> web_data_service_;
+ scoped_refptr<KeywordWebDataService> web_data_service_ = nullptr;
std::unique_ptr<TemplateURLServiceClient> client_;
- GoogleURLTracker* google_url_tracker_;
+ GoogleURLTracker* google_url_tracker_ = nullptr;
// ---------- Metrics related members ---------------------------------------
- rappor::RapporServiceImpl* rappor_service_;
+ rappor::RapporServiceImpl* rappor_service_ = nullptr;
// This closure is run when the default search provider is set to Google.
- base::Closure dsp_change_callback_;
-
+ base::RepeatingClosure dsp_change_callback_;
PrefChangeRegistrar pref_change_registrar_;
@@ -763,23 +753,22 @@ class TemplateURLService : public WebDataServiceConsumer,
base::ObserverList<TemplateURLServiceObserver> model_observers_;
// Maps from host to set of TemplateURLs whose search url host is host.
- // NOTE: This is always non-NULL; we use a std::unique_ptr<> to avoid circular
- // header dependencies.
- std::unique_ptr<SearchHostToURLsMap> provider_map_;
+ std::unique_ptr<SearchHostToURLsMap> provider_map_ =
+ std::make_unique<SearchHostToURLsMap>();
// Whether the keywords have been loaded.
- bool loaded_;
+ bool loaded_ = false;
// Set when the web data service fails to load properly. This prevents
// further communication with sync or writing to prefs, so we don't persist
// inconsistent state data anywhere.
- bool load_failed_;
+ bool load_failed_ = false;
// Whether Load() is disabled. True only in testing contexts.
- bool disable_load_;
+ bool disable_load_ = false;
// If non-zero, we're waiting on a load.
- KeywordWebDataService::Handle load_handle_;
+ KeywordWebDataService::Handle load_handle_ = 0;
// All visits that occurred before we finished loading. Once loaded
// UpdateKeywordSearchTermsForURL is invoked for each element of the vector.
@@ -787,7 +776,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// Once loaded, the default search provider. This is a pointer to a
// TemplateURL owned by |template_urls_|.
- TemplateURL* default_search_provider_;
+ TemplateURL* default_search_provider_ = nullptr;
// A temporary location for the DSE until Web Data has been loaded and it can
// be merged into |template_urls_|.
@@ -798,20 +787,20 @@ class TemplateURLService : public WebDataServiceConsumer,
// ID assigned to next TemplateURL added to this model. This is an ever
// increasing integer that is initialized from the database.
- TemplateURLID next_id_;
+ TemplateURLID next_id_ = kInvalidTemplateURLID + 1;
// Used to retrieve the current time, in base::Time units.
- std::unique_ptr<base::Clock> clock_;
+ std::unique_ptr<base::Clock> clock_ = std::make_unique<base::DefaultClock>();
// Do we have an active association between the TemplateURLs and sync models?
// Set in MergeDataAndStartSyncing, reset in StopSyncing. While this is not
// set, we ignore any local search engine changes (when we start syncing we
// will look up the most recent values anyways).
- bool models_associated_;
+ bool models_associated_ = false;
// Whether we're currently processing changes from the syncer. While this is
// true, we ignore any local search engine changes, since we triggered them.
- bool processing_syncer_changes_;
+ bool processing_syncer_changes_ = false;
// Sync's syncer::SyncChange handler. We push all our changes through this.
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
@@ -829,7 +818,7 @@ class TemplateURLService : public WebDataServiceConsumer,
// This is used to log the origin of changes to the default search provider.
// We set this value to increasingly specific values when we know what is the
// cause/origin of a default search change.
- DefaultSearchChangeOrigin dsp_change_origin_;
+ DefaultSearchChangeOrigin dsp_change_origin_ = DSP_CHANGE_OTHER;
// Stores a list of callbacks to be run after TemplateURLService has loaded.
base::CallbackList<void(void)> on_loaded_callbacks_;
@@ -843,12 +832,12 @@ class TemplateURLService : public WebDataServiceConsumer,
// This tracks how many Scoper handles exist. When the number of handles drops
// to zero, a notification is made to observers if
// |model_mutated_notification_pending_| is true.
- int outstanding_scoper_handles_;
+ int outstanding_scoper_handles_ = 0;
// Used to track if a notification is necessary due to the model being
// mutated. The outermost Scoper handles, can be used to defer notifications,
// but if no model mutation occurs, the deferred notification can be skipped.
- bool model_mutated_notification_pending_;
+ bool model_mutated_notification_pending_ = false;
DISALLOW_COPY_AND_ASSIGN(TemplateURLService);
};
diff --git a/chromium/components/search_engines/template_url_unittest.cc b/chromium/components/search_engines/template_url_unittest.cc
index 0c69f957ab6..cf40cb3bade 100644
--- a/chromium/components/search_engines/template_url_unittest.cc
+++ b/chromium/components/search_engines/template_url_unittest.cc
@@ -1843,3 +1843,54 @@ TEST_F(TemplateURLTest, InvalidateCachedValues) {
search_terms_data_.set_google_base_url("http://www.google.com/");
}
+
+// Tests the use of wildcards in the path to ensure both extracting search terms
+// and generating a search URL work correctly.
+TEST_F(TemplateURLTest, PathWildcard) {
+ TemplateURLData data;
+ data.SetURL(
+ "https://www.google.com/search{google:pathWildcard}?q={searchTerms}");
+ TemplateURL url(data);
+
+ // Test extracting search terms from a URL.
+ base::string16 search_terms;
+ url.ExtractSearchTermsFromURL(GURL("https://www.google.com/search?q=testing"),
+ search_terms_data_, &search_terms);
+ EXPECT_EQ(base::ASCIIToUTF16("testing"), search_terms);
+ url.ExtractSearchTermsFromURL(
+ GURL("https://www.google.com/search;_this_is_a_test;_?q=testing"),
+ search_terms_data_, &search_terms);
+ EXPECT_EQ(base::ASCIIToUTF16("testing"), search_terms);
+
+ // Tests overlapping prefix/suffix.
+ data.SetURL(
+ "https://www.google.com/search{google:pathWildcard}rch?q={searchTerms}");
+ TemplateURL overlap_url(data);
+ overlap_url.ExtractSearchTermsFromURL(
+ GURL("https://www.google.com/search?q=testing"), search_terms_data_,
+ &search_terms);
+ EXPECT_TRUE(search_terms.empty());
+
+ // Tests wildcard at beginning of path so we only have a suffix.
+ data.SetURL(
+ "https://www.google.com/{google:pathWildcard}rch?q={searchTerms}");
+ TemplateURL suffix_url(data);
+ suffix_url.ExtractSearchTermsFromURL(
+ GURL("https://www.google.com/search?q=testing"), search_terms_data_,
+ &search_terms);
+ EXPECT_EQ(base::ASCIIToUTF16("testing"), search_terms);
+
+ // Tests wildcard between prefix/suffix.
+ overlap_url.ExtractSearchTermsFromURL(
+ GURL("https://www.google.com/search_testing_rch?q=testing"),
+ search_terms_data_, &search_terms);
+ EXPECT_EQ(base::ASCIIToUTF16("testing"), search_terms);
+
+ // Test generating a URL.
+ TemplateURLRef::SearchTermsArgs search_terms_args(ASCIIToUTF16("foo"));
+ GURL generated_url;
+ url.ReplaceSearchTermsInURL(url.GenerateSearchURL(search_terms_data_),
+ search_terms_args, search_terms_data_,
+ &generated_url);
+ EXPECT_EQ("https://www.google.com/search?q=foo", generated_url.spec());
+}
diff --git a/chromium/components/search_provider_logos/google_logo_api_unittest.cc b/chromium/components/search_provider_logos/google_logo_api_unittest.cc
index c856e5923ff..c35b4a0e42e 100644
--- a/chromium/components/search_provider_logos/google_logo_api_unittest.cc
+++ b/chromium/components/search_provider_logos/google_logo_api_unittest.cc
@@ -317,7 +317,7 @@ TEST(GoogleNewLogoApiTest, ParsesCapturedApiResult) {
const GURL base_url("https://base.doo/");
base::FilePath test_data_dir;
- ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+ ASSERT_TRUE(base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
test_data_dir = test_data_dir.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/search_provider_logos/logo_cache.cc b/chromium/components/search_provider_logos/logo_cache.cc
index 7336f0f44e7..f4f6eceb16e 100644
--- a/chromium/components/search_provider_logos/logo_cache.cc
+++ b/chromium/components/search_provider_logos/logo_cache.cc
@@ -263,7 +263,7 @@ void LogoCache::WriteLogo(scoped_refptr<base::RefCountedMemory> encoded_image) {
if (!EnsureCacheDirectoryExists())
return;
- if (!metadata_ || !encoded_image.get()) {
+ if (!metadata_ || !encoded_image) {
DeleteLogoAndMetadata();
return;
}
diff --git a/chromium/components/search_provider_logos/logo_cache_unittest.cc b/chromium/components/search_provider_logos/logo_cache_unittest.cc
index cc1b4575151..39f0fe06914 100644
--- a/chromium/components/search_provider_logos/logo_cache_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_cache_unittest.cc
@@ -137,7 +137,7 @@ class LogoCacheTest : public ::testing::Test {
ASSERT_TRUE(retrieved_logo.get());
ExpectLogosEqual(*expected_logo, *retrieved_logo);
} else {
- ASSERT_FALSE(retrieved_logo.get());
+ ASSERT_FALSE(retrieved_logo);
}
}
diff --git a/chromium/components/search_provider_logos/logo_common.cc b/chromium/components/search_provider_logos/logo_common.cc
index ff761679918..05aae77a8a8 100644
--- a/chromium/components/search_provider_logos/logo_common.cc
+++ b/chromium/components/search_provider_logos/logo_common.cc
@@ -11,18 +11,25 @@ namespace search_provider_logos {
const int64_t kMaxTimeToLiveMS = INT64_C(30 * 24 * 60 * 60 * 1000); // 30 days
LogoMetadata::LogoMetadata() = default;
-LogoMetadata::LogoMetadata(const LogoMetadata& other) = default;
+LogoMetadata::LogoMetadata(const LogoMetadata&) = default;
+LogoMetadata::LogoMetadata(LogoMetadata&&) noexcept = default;
+LogoMetadata& LogoMetadata::operator=(const LogoMetadata&) = default;
+LogoMetadata& LogoMetadata::operator=(LogoMetadata&&) noexcept = default;
LogoMetadata::~LogoMetadata() = default;
EncodedLogo::EncodedLogo() = default;
-EncodedLogo::EncodedLogo(const EncodedLogo& other) = default;
+EncodedLogo::EncodedLogo(const EncodedLogo&) = default;
+EncodedLogo::EncodedLogo(EncodedLogo&&) noexcept = default;
+EncodedLogo& EncodedLogo::operator=(const EncodedLogo&) = default;
+EncodedLogo& EncodedLogo::operator=(EncodedLogo&&) noexcept = default;
EncodedLogo::~EncodedLogo() = default;
Logo::Logo() = default;
Logo::~Logo() = default;
LogoCallbacks::LogoCallbacks() = default;
-LogoCallbacks::LogoCallbacks(LogoCallbacks&&) = default;
+LogoCallbacks::LogoCallbacks(LogoCallbacks&&) noexcept = default;
+LogoCallbacks& LogoCallbacks::operator=(LogoCallbacks&&) noexcept = default;
LogoCallbacks::~LogoCallbacks() = default;
} // namespace search_provider_logos
diff --git a/chromium/components/search_provider_logos/logo_common.h b/chromium/components/search_provider_logos/logo_common.h
index c0d4a6308c8..dd3f4c582e3 100644
--- a/chromium/components/search_provider_logos/logo_common.h
+++ b/chromium/components/search_provider_logos/logo_common.h
@@ -33,7 +33,10 @@ enum class LogoType {
// serialize and deserialize that field.
struct LogoMetadata {
LogoMetadata();
- LogoMetadata(const LogoMetadata& other);
+ LogoMetadata(const LogoMetadata&);
+ LogoMetadata(LogoMetadata&&) noexcept;
+ LogoMetadata& operator=(const LogoMetadata&);
+ LogoMetadata& operator=(LogoMetadata&&) noexcept;
~LogoMetadata();
// For use by the client ----------------------------------------------------
@@ -116,7 +119,10 @@ enum class LogoCallbackReason {
struct EncodedLogo {
EncodedLogo();
- EncodedLogo(const EncodedLogo& other);
+ EncodedLogo(const EncodedLogo&);
+ EncodedLogo(EncodedLogo&&) noexcept;
+ EncodedLogo& operator=(const EncodedLogo& other);
+ EncodedLogo& operator=(EncodedLogo&& other) noexcept;
~EncodedLogo();
// The jpeg- or png-encoded image.
@@ -147,7 +153,8 @@ struct LogoCallbacks {
LogoCallback on_fresh_decoded_logo_available;
LogoCallbacks();
- LogoCallbacks(LogoCallbacks&&);
+ LogoCallbacks(LogoCallbacks&&) noexcept;
+ LogoCallbacks& operator=(LogoCallbacks&&) noexcept;
~LogoCallbacks();
};
diff --git a/chromium/components/search_provider_logos/logo_service_impl_unittest.cc b/chromium/components/search_provider_logos/logo_service_impl_unittest.cc
index 8a6040e93d8..83ac25aff14 100644
--- a/chromium/components/search_provider_logos/logo_service_impl_unittest.cc
+++ b/chromium/components/search_provider_logos/logo_service_impl_unittest.cc
@@ -17,7 +17,6 @@
#include "base/json/json_writer.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/components/search_provider_logos/logo_tracker.cc b/chromium/components/search_provider_logos/logo_tracker.cc
index 1324ddffa9d..4c48e4f3fe3 100644
--- a/chromium/components/search_provider_logos/logo_tracker.cc
+++ b/chromium/components/search_provider_logos/logo_tracker.cc
@@ -8,7 +8,6 @@
#include <utility>
#include "base/bind_helpers.h"
-#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram_macros.h"
#include "base/task_runner_util.h"
#include "base/task_scheduler/post_task.h"
@@ -287,7 +286,7 @@ void LogoTracker::OnFreshLogoParsed(bool* parsing_failed,
if (logo)
logo->metadata.source_url = logo_url_;
- if (!logo || !logo->encoded_image.get()) {
+ if (!logo || !logo->encoded_image) {
OnFreshLogoAvailable(std::move(logo), /*download_failed=*/false,
*parsing_failed, from_http_cache, SkBitmap());
} else {
@@ -317,8 +316,8 @@ void LogoTracker::OnFreshLogoAvailable(
if (download_failed) {
download_outcome = DOWNLOAD_OUTCOME_DOWNLOAD_FAILED;
- } else if (encoded_logo && !encoded_logo->encoded_image.get() &&
- cached_logo_ && !encoded_logo->metadata.fingerprint.empty() &&
+ } else if (encoded_logo && !encoded_logo->encoded_image && cached_logo_ &&
+ !encoded_logo->metadata.fingerprint.empty() &&
encoded_logo->metadata.fingerprint ==
cached_logo_->metadata.fingerprint) {
// The cached logo was revalidated, i.e. its fingerprint was verified.
@@ -353,8 +352,8 @@ void LogoTracker::OnFreshLogoAvailable(
LogoCallbackReason callback_type = LogoCallbackReason::FAILED;
switch (download_outcome) {
case DOWNLOAD_OUTCOME_NEW_LOGO_SUCCESS:
- DCHECK(encoded_logo.get());
- DCHECK(logo.get());
+ DCHECK(encoded_logo);
+ DCHECK(logo);
callback_type = LogoCallbackReason::DETERMINED;
break;
@@ -362,8 +361,8 @@ void LogoTracker::OnFreshLogoAvailable(
case DOWNLOAD_OUTCOME_NO_LOGO_TODAY:
// Clear the cached logo if it was non-null. Otherwise, report this as a
// revalidation of "no logo".
- DCHECK(!encoded_logo.get());
- DCHECK(!logo.get());
+ DCHECK(!encoded_logo);
+ DCHECK(!logo);
if (cached_logo_) {
callback_type = LogoCallbackReason::DETERMINED;
} else {
@@ -374,14 +373,14 @@ void LogoTracker::OnFreshLogoAvailable(
case DOWNLOAD_OUTCOME_DOWNLOAD_FAILED:
// In the download failed, don't notify the callback at all, since the
// callback should continue to use the cached logo.
- DCHECK(!encoded_logo.get());
- DCHECK(!logo.get());
+ DCHECK(!encoded_logo);
+ DCHECK(!logo);
callback_type = LogoCallbackReason::FAILED;
break;
case DOWNLOAD_OUTCOME_DECODING_FAILED:
- DCHECK(encoded_logo.get());
- DCHECK(!logo.get());
+ DCHECK(encoded_logo);
+ DCHECK(!logo);
encoded_logo.reset();
callback_type = LogoCallbackReason::FAILED;
break;
@@ -390,8 +389,8 @@ void LogoTracker::OnFreshLogoAvailable(
// In the server reported that the cached logo is still current, don't
// notify the callback at all, since the callback should continue to use
// the cached logo.
- DCHECK(encoded_logo.get());
- DCHECK(!logo.get());
+ DCHECK(encoded_logo);
+ DCHECK(!logo);
callback_type = LogoCallbackReason::REVALIDATED;
break;
diff --git a/chromium/components/security_interstitials/content/BUILD.gn b/chromium/components/security_interstitials/content/BUILD.gn
index b3f383efe07..7b6d5b3eefc 100644
--- a/chromium/components/security_interstitials/content/BUILD.gn
+++ b/chromium/components/security_interstitials/content/BUILD.gn
@@ -10,6 +10,8 @@ static_library("security_interstitial_page") {
"security_interstitial_controller_client.h",
"security_interstitial_page.cc",
"security_interstitial_page.h",
+ "security_interstitial_tab_helper.cc",
+ "security_interstitial_tab_helper.h",
"unsafe_resource.cc",
"unsafe_resource.h",
"urls.cc",
@@ -33,3 +35,23 @@ static_library("security_interstitial_page") {
"//content/public/common",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "security_interstitial_tab_helper_unittest.cc",
+ ]
+
+ deps = [
+ ":security_interstitial_page",
+ "//base",
+ "//base/test:test_support",
+ "//components/security_interstitials/core:core",
+ "//content/public/browser",
+ "//content/public/common",
+ "//content/test:test_support",
+ "//net:",
+ "//net:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/security_interstitials/content/DEPS b/chromium/components/security_interstitials/content/DEPS
index 3cd103b13b9..84d5909b858 100644
--- a/chromium/components/security_interstitials/content/DEPS
+++ b/chromium/components/security_interstitials/content/DEPS
@@ -6,4 +6,7 @@ include_rules = [
"+components/security_interstitials/core",
"+content/public/browser",
"+content/public/common",
+ "+content/public/test",
+ "+net",
+ "+net/test",
]
diff --git a/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc b/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc
new file mode 100644
index 00000000000..bf942f1c953
--- /dev/null
+++ b/chromium/components/security_interstitials/content/security_interstitial_tab_helper.cc
@@ -0,0 +1,160 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
+#include "base/strings/string_number_conversions.h"
+#include "components/security_interstitials/content/security_interstitial_page.h"
+#include "components/security_interstitials/core/controller_client.h"
+#include "content/public/browser/navigation_handle.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(
+ security_interstitials::SecurityInterstitialTabHelper);
+
+namespace security_interstitials {
+
+SecurityInterstitialTabHelper::~SecurityInterstitialTabHelper() {}
+
+void SecurityInterstitialTabHelper::DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) {
+ if (navigation_handle->IsSameDocument()) {
+ return;
+ }
+
+ auto it = blocking_pages_for_navigations_.find(
+ navigation_handle->GetNavigationId());
+
+ if (navigation_handle->HasCommitted()) {
+ if (blocking_page_for_currently_committed_navigation_) {
+ blocking_page_for_currently_committed_navigation_
+ ->OnInterstitialClosing();
+ }
+
+ if (it == blocking_pages_for_navigations_.end()) {
+ blocking_page_for_currently_committed_navigation_.reset();
+ } else {
+ blocking_page_for_currently_committed_navigation_ = std::move(it->second);
+ }
+ }
+
+ if (it != blocking_pages_for_navigations_.end()) {
+ blocking_pages_for_navigations_.erase(it);
+ }
+}
+
+void SecurityInterstitialTabHelper::WebContentsDestroyed() {
+ if (blocking_page_for_currently_committed_navigation_) {
+ blocking_page_for_currently_committed_navigation_->OnInterstitialClosing();
+ }
+}
+
+// static
+void SecurityInterstitialTabHelper::AssociateBlockingPage(
+ content::WebContents* web_contents,
+ int64_t navigation_id,
+ std::unique_ptr<security_interstitials::SecurityInterstitialPage>
+ blocking_page) {
+ // CreateForWebContents() creates a tab helper if it doesn't exist for
+ // |web_contents| yet.
+ SecurityInterstitialTabHelper::CreateForWebContents(web_contents);
+
+ SecurityInterstitialTabHelper* helper =
+ SecurityInterstitialTabHelper::FromWebContents(web_contents);
+ helper->SetBlockingPage(navigation_id, std::move(blocking_page));
+}
+
+security_interstitials::SecurityInterstitialPage*
+SecurityInterstitialTabHelper::
+ GetBlockingPageForCurrentlyCommittedNavigationForTesting() {
+ return blocking_page_for_currently_committed_navigation_.get();
+}
+
+SecurityInterstitialTabHelper::SecurityInterstitialTabHelper(
+ content::WebContents* web_contents)
+ : WebContentsObserver(web_contents), binding_(web_contents, this) {}
+
+void SecurityInterstitialTabHelper::SetBlockingPage(
+ int64_t navigation_id,
+ std::unique_ptr<security_interstitials::SecurityInterstitialPage>
+ blocking_page) {
+ blocking_pages_for_navigations_[navigation_id] = std::move(blocking_page);
+}
+
+void SecurityInterstitialTabHelper::HandleCommand(
+ security_interstitials::SecurityInterstitialCommand cmd) {
+ if (blocking_page_for_currently_committed_navigation_) {
+ // Currently commands need to be converted to strings before passing them
+ // to CommandReceived, which then turns them into integers again, this
+ // redundant conversion will be removed once commited interstitials are the
+ // only supported codepath.
+ blocking_page_for_currently_committed_navigation_->CommandReceived(
+ base::NumberToString(cmd));
+ }
+}
+
+void SecurityInterstitialTabHelper::DontProceed() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_DONT_PROCEED);
+}
+
+void SecurityInterstitialTabHelper::Proceed() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_PROCEED);
+}
+
+void SecurityInterstitialTabHelper::ShowMoreSection() {
+ HandleCommand(security_interstitials::SecurityInterstitialCommand::
+ CMD_SHOW_MORE_SECTION);
+}
+
+void SecurityInterstitialTabHelper::OpenHelpCenter() {
+ HandleCommand(security_interstitials::SecurityInterstitialCommand::
+ CMD_OPEN_HELP_CENTER);
+}
+
+void SecurityInterstitialTabHelper::OpenDiagnostic() {
+ // SSL error pages do not implement this.
+ NOTREACHED();
+}
+
+void SecurityInterstitialTabHelper::Reload() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_RELOAD);
+}
+
+void SecurityInterstitialTabHelper::OpenDateSettings() {
+ HandleCommand(security_interstitials::SecurityInterstitialCommand::
+ CMD_OPEN_DATE_SETTINGS);
+}
+
+void SecurityInterstitialTabHelper::OpenLogin() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_OPEN_LOGIN);
+}
+
+void SecurityInterstitialTabHelper::DoReport() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_DO_REPORT);
+}
+
+void SecurityInterstitialTabHelper::DontReport() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_DONT_REPORT);
+}
+
+void SecurityInterstitialTabHelper::OpenReportingPrivacy() {
+ HandleCommand(security_interstitials::SecurityInterstitialCommand::
+ CMD_OPEN_REPORTING_PRIVACY);
+}
+
+void SecurityInterstitialTabHelper::OpenWhitepaper() {
+ HandleCommand(
+ security_interstitials::SecurityInterstitialCommand::CMD_OPEN_WHITEPAPER);
+}
+
+void SecurityInterstitialTabHelper::ReportPhishingError() {
+ // SSL error pages do not implement this.
+ NOTREACHED();
+}
+
+} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/content/security_interstitial_tab_helper.h b/chromium/components/security_interstitials/content/security_interstitial_tab_helper.h
new file mode 100644
index 00000000000..bd13124dc38
--- /dev/null
+++ b/chromium/components/security_interstitials/content/security_interstitial_tab_helper.h
@@ -0,0 +1,97 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_SECURITY_INTERSTITIAL_TAB_HELPER_H_
+#define COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_SECURITY_INTERSTITIAL_TAB_HELPER_H_
+
+#include <map>
+
+#include "components/security_interstitials/core/common/interfaces/interstitial_commands.mojom.h"
+#include "components/security_interstitials/core/controller_client.h"
+#include "content/public/browser/web_contents_binding_set.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class NavigationHandle;
+class WebContents;
+} // namespace content
+
+namespace security_interstitials {
+class SecurityInterstitialPage;
+
+// Long-lived helper associated with a WebContents, for owning blocking pages.
+class SecurityInterstitialTabHelper
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<SecurityInterstitialTabHelper>,
+ public security_interstitials::mojom::InterstitialCommands {
+ public:
+ ~SecurityInterstitialTabHelper() override;
+
+ // WebContentsObserver:
+ void DidFinishNavigation(
+ content::NavigationHandle* navigation_handle) override;
+ void WebContentsDestroyed() override;
+
+ // Associates |blocking_page| with an SecurityInterstitialTabHelper for the
+ // given |web_contents| and |navigation_id|, to manage the |blocking_page|'s
+ // lifetime.
+ static void AssociateBlockingPage(
+ content::WebContents* web_contents,
+ int64_t navigation_id,
+ std::unique_ptr<security_interstitials::SecurityInterstitialPage>
+ blocking_page);
+
+ security_interstitials::SecurityInterstitialPage*
+ GetBlockingPageForCurrentlyCommittedNavigationForTesting();
+
+ private:
+ explicit SecurityInterstitialTabHelper(content::WebContents* web_contents);
+ friend class content::WebContentsUserData<SecurityInterstitialTabHelper>;
+
+ void SetBlockingPage(
+ int64_t navigation_id,
+ std::unique_ptr<security_interstitials::SecurityInterstitialPage>
+ blocking_page);
+
+ void HandleCommand(security_interstitials::SecurityInterstitialCommand cmd);
+
+ // security_interstitials::mojom::InterstitialCommands::
+ void DontProceed() override;
+ void Proceed() override;
+ void ShowMoreSection() override;
+ void OpenHelpCenter() override;
+ void OpenDiagnostic() override;
+ void Reload() override;
+ void OpenDateSettings() override;
+ void OpenLogin() override;
+ void DoReport() override;
+ void DontReport() override;
+ void OpenReportingPrivacy() override;
+ void OpenWhitepaper() override;
+ void ReportPhishingError() override;
+
+ // Keeps track of blocking pages for navigations that have encountered
+ // certificate errors in this WebContents. When a navigation commits, the
+ // corresponding blocking page is moved out and stored in
+ // |blocking_page_for_currently_committed_navigation_|.
+ std::map<int64_t,
+ std::unique_ptr<security_interstitials::SecurityInterstitialPage>>
+ blocking_pages_for_navigations_;
+ // Keeps track of the blocking page for the current committed navigation, if
+ // there is one. The value is replaced (if the new committed navigation has a
+ // blocking page) or reset on every committed navigation.
+ std::unique_ptr<security_interstitials::SecurityInterstitialPage>
+ blocking_page_for_currently_committed_navigation_;
+
+ content::WebContentsFrameBindingSet<
+ security_interstitials::mojom::InterstitialCommands>
+ binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(SecurityInterstitialTabHelper);
+};
+
+} // namespace security_interstitials
+
+#endif // COMPONENTS_SECURITY_INTERSTITIALS_CONTENT_SECURITY_INTERSTITIAL_TAB_HELPER_H_
diff --git a/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc b/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
new file mode 100644
index 00000000000..1725aa04376
--- /dev/null
+++ b/chromium/components/security_interstitials/content/security_interstitial_tab_helper_unittest.cc
@@ -0,0 +1,210 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/security_interstitials/content/security_interstitial_tab_helper.h"
+
+#include <memory>
+
+#include "base/bind.h"
+#include "base/i18n/rtl.h"
+#include "base/time/time.h"
+#include "components/security_interstitials/content/security_interstitial_controller_client.h"
+#include "components/security_interstitials/content/security_interstitial_page.h"
+#include "components/security_interstitials/core/controller_client.h"
+#include "components/security_interstitials/core/metrics_helper.h"
+#include "content/public/browser/certificate_request_result_type.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/common/browser_side_navigation_policy.h"
+#include "content/public/test/test_renderer_host.h"
+#include "net/base/net_errors.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/test_data_directory.h"
+#include "url/gurl.h"
+
+namespace security_interstitials {
+
+const char kTestSslMetricsName[] = "test_blocking_page";
+
+std::unique_ptr<security_interstitials::MetricsHelper> CreateTestMetricsHelper(
+ content::WebContents* web_contents) {
+ MetricsHelper::ReportDetails report_details;
+ report_details.metric_prefix = kTestSslMetricsName;
+ return std::make_unique<security_interstitials::MetricsHelper>(
+ GURL(), report_details, nullptr);
+}
+
+class TestInterstitialPage : public SecurityInterstitialPage {
+ public:
+ // |*destroyed_tracker| is set to true in the destructor.
+ TestInterstitialPage(content::WebContents* web_contents,
+ const GURL& request_url,
+ bool* destroyed_tracker)
+ : SecurityInterstitialPage(
+ web_contents,
+ request_url,
+ std::make_unique<SecurityInterstitialControllerClient>(
+ web_contents,
+ CreateTestMetricsHelper(web_contents),
+ nullptr,
+ base::i18n::GetConfiguredLocale(),
+ GURL())),
+ destroyed_tracker_(destroyed_tracker) {}
+
+ ~TestInterstitialPage() override { *destroyed_tracker_ = true; }
+
+ void OnInterstitialClosing() override {}
+
+ protected:
+ bool ShouldCreateNewNavigation() const override { return false; }
+
+ void PopulateInterstitialStrings(
+ base::DictionaryValue* load_time_data) override {}
+
+ private:
+ bool* destroyed_tracker_;
+};
+
+class SecurityInterstitialTabHelperTest
+ : public content::RenderViewHostTestHarness {
+ protected:
+ std::unique_ptr<content::NavigationHandle> CreateHandle(
+ bool committed,
+ bool is_same_document) {
+ return content::NavigationHandle::CreateNavigationHandleForTesting(
+ GURL(), main_rfh(), committed, net::OK, is_same_document);
+ }
+
+ // The lifetime of the blocking page is managed by the
+ // SecurityInterstitialTabHelper for the test's web_contents.
+ // |destroyed_tracker| will be set to true when the corresponding blocking
+ // page is destroyed.
+ void CreateAssociatedBlockingPage(content::NavigationHandle* handle,
+ bool* destroyed_tracker) {
+ SecurityInterstitialTabHelper::AssociateBlockingPage(
+ web_contents(), handle->GetNavigationId(),
+ std::make_unique<TestInterstitialPage>(web_contents(), GURL(),
+ destroyed_tracker));
+ }
+};
+
+// Tests that the helper properly handles the lifetime of a single blocking
+// page, interleaved with other navigations.
+TEST_F(SecurityInterstitialTabHelperTest, SingleBlockingPage) {
+ std::unique_ptr<content::NavigationHandle> blocking_page_handle =
+ CreateHandle(true, false);
+ bool blocking_page_destroyed = false;
+ CreateAssociatedBlockingPage(blocking_page_handle.get(),
+ &blocking_page_destroyed);
+ SecurityInterstitialTabHelper* helper =
+ SecurityInterstitialTabHelper::FromWebContents(web_contents());
+
+ // Test that a same-document navigation doesn't destroy the blocking page if
+ // its navigation hasn't committed yet.
+ std::unique_ptr<content::NavigationHandle> same_document_handle =
+ CreateHandle(true, true);
+ helper->DidFinishNavigation(same_document_handle.get());
+ EXPECT_FALSE(blocking_page_destroyed);
+
+ // Test that a committed (non-same-document) navigation doesn't destroy the
+ // blocking page if its navigation hasn't committed yet.
+ std::unique_ptr<content::NavigationHandle> committed_handle1 =
+ CreateHandle(true, false);
+ helper->DidFinishNavigation(committed_handle1.get());
+ EXPECT_FALSE(blocking_page_destroyed);
+
+ // Simulate comitting the interstitial.
+ helper->DidFinishNavigation(blocking_page_handle.get());
+ EXPECT_FALSE(blocking_page_destroyed);
+
+ // Test that a subsequent committed navigation releases the blocking page
+ // stored for the currently committed navigation.
+ std::unique_ptr<content::NavigationHandle> committed_handle2 =
+ CreateHandle(true, false);
+ helper->DidFinishNavigation(committed_handle2.get());
+ EXPECT_TRUE(blocking_page_destroyed);
+}
+
+// Tests that the helper properly handles the lifetime of multiple blocking
+// pages, committed in a different order than they are created.
+TEST_F(SecurityInterstitialTabHelperTest, MultipleBlockingPages) {
+ // Simulate associating the first interstitial.
+ std::unique_ptr<content::NavigationHandle> handle1 =
+ CreateHandle(true, false);
+ bool blocking_page1_destroyed = false;
+ CreateAssociatedBlockingPage(handle1.get(), &blocking_page1_destroyed);
+
+ // We can directly retrieve the helper for testing once
+ // CreateAssociatedBlockingPage() was called.
+ SecurityInterstitialTabHelper* helper =
+ SecurityInterstitialTabHelper::FromWebContents(web_contents());
+
+ // Simulate commiting the first interstitial.
+ helper->DidFinishNavigation(handle1.get());
+ EXPECT_FALSE(blocking_page1_destroyed);
+
+ // Associate the second interstitial.
+ std::unique_ptr<content::NavigationHandle> handle2 =
+ CreateHandle(true, false);
+ bool blocking_page2_destroyed = false;
+ CreateAssociatedBlockingPage(handle2.get(), &blocking_page2_destroyed);
+ EXPECT_FALSE(blocking_page1_destroyed);
+ EXPECT_FALSE(blocking_page2_destroyed);
+
+ // Associate the third interstitial.
+ std::unique_ptr<content::NavigationHandle> handle3 =
+ CreateHandle(true, false);
+ bool blocking_page3_destroyed = false;
+ CreateAssociatedBlockingPage(handle3.get(), &blocking_page3_destroyed);
+ EXPECT_FALSE(blocking_page1_destroyed);
+ EXPECT_FALSE(blocking_page2_destroyed);
+ EXPECT_FALSE(blocking_page3_destroyed);
+
+ // Simulate commiting the third interstitial.
+ helper->DidFinishNavigation(handle3.get());
+ EXPECT_TRUE(blocking_page1_destroyed);
+ EXPECT_FALSE(blocking_page2_destroyed);
+ EXPECT_FALSE(blocking_page3_destroyed);
+
+ // Simulate commiting the second interstitial.
+ helper->DidFinishNavigation(handle2.get());
+ EXPECT_TRUE(blocking_page1_destroyed);
+ EXPECT_FALSE(blocking_page2_destroyed);
+ EXPECT_TRUE(blocking_page3_destroyed);
+}
+
+// Tests that the helper properly handles a navigation that finishes without
+// committing.
+TEST_F(SecurityInterstitialTabHelperTest, NavigationDoesNotCommit) {
+ std::unique_ptr<content::NavigationHandle> committed_handle =
+ CreateHandle(true, false);
+ bool committed_blocking_page_destroyed = false;
+ CreateAssociatedBlockingPage(committed_handle.get(),
+ &committed_blocking_page_destroyed);
+ SecurityInterstitialTabHelper* helper =
+ SecurityInterstitialTabHelper::FromWebContents(web_contents());
+ helper->DidFinishNavigation(committed_handle.get());
+ EXPECT_FALSE(committed_blocking_page_destroyed);
+
+ // Simulate a navigation that does not commit.
+ std::unique_ptr<content::NavigationHandle> non_committed_handle =
+ CreateHandle(false, false);
+ bool non_committed_blocking_page_destroyed = false;
+ CreateAssociatedBlockingPage(non_committed_handle.get(),
+ &non_committed_blocking_page_destroyed);
+ helper->DidFinishNavigation(non_committed_handle.get());
+
+ // The blocking page for the non-committed navigation should have been cleaned
+ // up, but the one for the previous committed navigation should still be
+ // around.
+ EXPECT_TRUE(non_committed_blocking_page_destroyed);
+ EXPECT_FALSE(committed_blocking_page_destroyed);
+
+ // When a navigation does commit, the previous one should be cleaned up.
+ std::unique_ptr<content::NavigationHandle> next_committed_handle =
+ CreateHandle(true, false);
+ helper->DidFinishNavigation(next_committed_handle.get());
+ EXPECT_TRUE(committed_blocking_page_destroyed);
+}
+
+} // namespace security_interstitials
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html b/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html
index e60f2253ea5..cdb7392a5e7 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_large.html
@@ -2,6 +2,7 @@
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
+ <meta name="theme-color" content="#fff">
<meta name="viewport"
content="initial-scale=1, minimum-scale=1, width=device-width">
<title>$i18n{tabTitle}</title>
@@ -31,6 +32,9 @@
<div id="error-debugging-info" class="hidden"></div>
</div>
</div>
+ <div id="recurrent-error-message">
+ $i18nRaw{recurrentErrorParagraph}
+ </div>
<div id="extended-reporting-opt-in" class="hidden">
<label>
<div class="checkboxes">
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_large.js b/chromium/components/security_interstitials/core/browser/resources/interstitial_large.js
index 0fa7dbf5ecf..d57ec6945a3 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_large.js
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_large.js
@@ -69,6 +69,8 @@ function setupEvents() {
var captivePortal = interstitialType == 'CAPTIVE_PORTAL';
var badClock = ssl && loadTimeData.getBoolean('bad_clock');
var hidePrimaryButton = loadTimeData.getBoolean('hide_primary_button');
+ var showRecurrentErrorParagraph = loadTimeData.getBoolean(
+ 'show_recurrent_error_paragraph');
if (ssl) {
$('body').classList.add(badClock ? 'bad-clock' : 'ssl');
@@ -78,6 +80,9 @@ function setupEvents() {
$('body').classList.add('captive-portal');
} else {
$('body').classList.add('safe-browsing');
+ // Override the default theme color.
+ document.querySelector('meta[name=theme-color]').setAttribute('content',
+ 'rgb(206, 52, 38)');
}
$('icon').classList.add('icon');
@@ -123,6 +128,12 @@ function setupEvents() {
$('proceed-link').classList.add('small-link');
}
+ if (!ssl || !showRecurrentErrorParagraph) {
+ $('recurrent-error-message').classList.add(HIDDEN_CLASS);
+ } else {
+ $('body').classList.add('showing-recurrent-error-message');
+ }
+
if ($('diagnostic-link')) {
$('diagnostic-link').addEventListener('click', function(event) {
sendCommand(SecurityInterstitialCommandId.CMD_OPEN_DIAGNOSTIC);
diff --git a/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css b/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css
index fe9ff5de784..a25aa8a8480 100644
--- a/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css
+++ b/chromium/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css
@@ -3,6 +3,7 @@
* found in the LICENSE file. */
body {
+ background-color: rgb(247, 247, 247);
margin: 0;
}
diff --git a/chromium/components/security_interstitials/core/common/resources/interstitial_common.css b/chromium/components/security_interstitials/core/common/resources/interstitial_common.css
index bb1ca4f6502..51a5b7102f2 100644
--- a/chromium/components/security_interstitials/core/common/resources/interstitial_common.css
+++ b/chromium/components/security_interstitials/core/common/resources/interstitial_common.css
@@ -188,6 +188,18 @@ input[type=checkbox]:checked ~ .checkbox::before {
opacity: 1;
}
+#recurrent-error-message {
+ background: #ededed;
+ border-radius: 4px;
+ padding: 12px 16px;
+ margin-top: 12px;
+ margin-bottom: 16px;
+}
+
+.showing-recurrent-error-message #extended-reporting-opt-in {
+ margin-top: 16px;
+}
+
@media (max-width: 700px) {
.interstitial-wrapper {
padding: 0 10%;
@@ -268,9 +280,9 @@ input[type=checkbox]:checked ~ .checkbox::before {
(min-width: 421px) and (min-height: 240px) and
(max-height: 560px) {
body .nav-wrapper {
- background: #f7f7f7;
+ background: #fff;
bottom: 0;
- box-shadow: 0 -22px 40px rgb(247, 247, 247);
+ box-shadow: 0 -22px 40px #fff;
left: 0;
margin: 0 auto;
max-width: 736px;
diff --git a/chromium/components/security_interstitials/core/common/resources/interstitial_core.css b/chromium/components/security_interstitials/core/common/resources/interstitial_core.css
index 5ec9a2ba1fb..925722e2bac 100644
--- a/chromium/components/security_interstitials/core/common/resources/interstitial_core.css
+++ b/chromium/components/security_interstitials/core/common/resources/interstitial_core.css
@@ -7,7 +7,7 @@ a {
}
body {
- background-color: rgb(247, 247, 247);
+ background-color: #fff;
color: rgb(100, 100, 100);
word-wrap: break-word;
}
diff --git a/chromium/components/security_interstitials/core/common_string_util.cc b/chromium/components/security_interstitials/core/common_string_util.cc
index 6c36f648cb2..bf218065dfc 100644
--- a/chromium/components/security_interstitials/core/common_string_util.cc
+++ b/chromium/components/security_interstitials/core/common_string_util.cc
@@ -31,6 +31,10 @@ void PopulateSSLLayoutStrings(int cert_error,
"openDetails", l10n_util::GetStringUTF16(IDS_SSL_OPEN_DETAILS_BUTTON));
load_time_data->SetString(
"closeDetails", l10n_util::GetStringUTF16(IDS_SSL_CLOSE_DETAILS_BUTTON));
+ // Not used by most interstitials; can be overridden by individual
+ // interstitials as needed.
+ load_time_data->SetString("recurrentErrorParagraph", "");
+ load_time_data->SetBoolean("show_recurrent_error_paragraph", false);
}
void PopulateSSLDebuggingStrings(const net::SSLInfo ssl_info,
diff --git a/chromium/components/security_interstitials/core/controller_client.cc b/chromium/components/security_interstitials/core/controller_client.cc
index 09fa690c303..e416177aec9 100644
--- a/chromium/components/security_interstitials/core/controller_client.cc
+++ b/chromium/components/security_interstitials/core/controller_client.cc
@@ -68,6 +68,10 @@ void ControllerClient::OpenURL(bool open_links_in_new_tab, const GURL& url) {
}
}
+bool ControllerClient::HasSeenRecurrentError() {
+ return false;
+}
+
GURL ControllerClient::GetBaseHelpCenterUrl() const {
return help_center_url_;
}
diff --git a/chromium/components/security_interstitials/core/controller_client.h b/chromium/components/security_interstitials/core/controller_client.h
index 25fdd9c10e7..603bd595aea 100644
--- a/chromium/components/security_interstitials/core/controller_client.h
+++ b/chromium/components/security_interstitials/core/controller_client.h
@@ -100,6 +100,10 @@ class ControllerClient {
virtual const std::string& GetApplicationLocale() const = 0;
+ // Returns true if the error page should display a message to account for the
+ // fact that the user has seen the same error multiple times.
+ virtual bool HasSeenRecurrentError();
+
GURL GetBaseHelpCenterUrl() const;
void SetBaseHelpCenterUrlForTesting(const GURL& test_url);
diff --git a/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc b/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
index 4e40f5c59f9..06f0b5c6dde 100644
--- a/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
+++ b/chromium/components/security_interstitials/core/safe_browsing_loud_error_ui.cc
@@ -105,6 +105,10 @@ void SafeBrowsingLoudErrorUI::PopulateStringsForHtml(
break;
}
+ // Not used by this interstitial.
+ load_time_data->SetString("recurrentErrorParagraph", base::string16());
+ load_time_data->SetBoolean("show_recurrent_error_paragraph", false);
+
PopulateExtendedReportingOption(load_time_data);
}
diff --git a/chromium/components/security_interstitials/core/safe_browsing_quiet_error_ui.cc b/chromium/components/security_interstitials/core/safe_browsing_quiet_error_ui.cc
index 5953562cc05..65ad7085104 100644
--- a/chromium/components/security_interstitials/core/safe_browsing_quiet_error_ui.cc
+++ b/chromium/components/security_interstitials/core/safe_browsing_quiet_error_ui.cc
@@ -81,6 +81,10 @@ void SafeBrowsingQuietErrorUI::PopulateStringsForHtml(
} else {
NOTREACHED();
}
+
+ // Not used by this interstitial.
+ load_time_data->SetString("recurrentErrorParagraph", base::string16());
+ load_time_data->SetBoolean("show_recurrent_error_paragraph", false);
}
void SafeBrowsingQuietErrorUI::SetGiantWebViewForTesting(
diff --git a/chromium/components/security_interstitials/core/ssl_error_ui.cc b/chromium/components/security_interstitials/core/ssl_error_ui.cc
index 3f9165c904d..23bdac6ef74 100644
--- a/chromium/components/security_interstitials/core/ssl_error_ui.cc
+++ b/chromium/components/security_interstitials/core/ssl_error_ui.cc
@@ -47,8 +47,7 @@ SSLErrorUI::SSLErrorUI(const GURL& request_url,
controller_->metrics_helper()->RecordUserInteraction(
MetricsHelper::TOTAL_VISITS);
ssl_errors::RecordUMAStatistics(soft_override_enabled_, time_triggered_,
- request_url, cert_error_,
- *ssl_info_.cert.get());
+ request_url, cert_error_, *ssl_info_.cert);
}
SSLErrorUI::~SSLErrorUI() {
@@ -81,6 +80,11 @@ void SSLErrorUI::PopulateStringsForHTML(base::DictionaryValue* load_time_data) {
l10n_util::GetStringFUTF16(
IDS_SSL_V2_PRIMARY_PARAGRAPH,
common_string_util::GetFormattedHostName(request_url_)));
+ load_time_data->SetString(
+ "recurrentErrorParagraph",
+ l10n_util::GetStringUTF16(IDS_SSL_V2_RECURRENT_ERROR_PARAGRAPH));
+ load_time_data->SetBoolean("show_recurrent_error_paragraph",
+ controller_->HasSeenRecurrentError());
if (soft_override_enabled_)
PopulateOverridableStrings(load_time_data);
diff --git a/chromium/components/security_interstitials/core/superfish_error_ui.cc b/chromium/components/security_interstitials/core/superfish_error_ui.cc
index 912f36acbcf..1389bcc3f38 100644
--- a/chromium/components/security_interstitials/core/superfish_error_ui.cc
+++ b/chromium/components/security_interstitials/core/superfish_error_ui.cc
@@ -59,6 +59,8 @@ void SuperfishErrorUI::PopulateStringsForHTML(
load_time_data->SetString("finalParagraph", std::string());
load_time_data->SetString("openDetails", base::string16());
load_time_data->SetString("closeDetails", base::string16());
+ load_time_data->SetString("recurrentErrorParagraph", base::string16());
+ load_time_data->SetBoolean("show_recurrent_error_paragraph", false);
}
void SuperfishErrorUI::HandleCommand(SecurityInterstitialCommand command) {
diff --git a/chromium/components/security_interstitials_strings.grdp b/chromium/components/security_interstitials_strings.grdp
index 1dca2b26cff..7cd2c265d6d 100644
--- a/chromium/components/security_interstitials_strings.grdp
+++ b/chromium/components/security_interstitials_strings.grdp
@@ -115,6 +115,9 @@
<message name="IDS_SSL_V2_PRIMARY_PARAGRAPH" desc="The primary explanatory paragraph for the SSL interstitial.">
Attackers might be trying to steal your information from <ph name="BEGIN_BOLD">&lt;strong&gt;</ph><ph name="SITE">$1<ex>google.com</ex></ph><ph name="END_BOLD">&lt;/strong&gt;</ph> (for example, passwords, messages, or credit cards). <ph name="BEGIN_LEARN_MORE_LINK">&lt;a href="#" id="learn-more-link"&gt;</ph>Learn more<ph name="END_LEARN_MORE_LINK">&lt;/a&gt;</ph>
</message>
+ <message name="IDS_SSL_V2_RECURRENT_ERROR_PARAGRAPH" desc="A paragraph for an SSL interstitial that the user has seen multiple times in a browsing session.">
+ Warnings may be common while websites update their security. This should improve soon.
+ </message>
<!-- SSL error page: Superfish-specific -->
<if expr="_google_chrome">
diff --git a/chromium/components/security_state/core/features.cc b/chromium/components/security_state/core/features.cc
index c7fa7c82c71..e9598812f76 100644
--- a/chromium/components/security_state/core/features.cc
+++ b/chromium/components/security_state/core/features.cc
@@ -8,7 +8,7 @@ namespace security_state {
namespace features {
const base::Feature kMarkHttpAsFeature{"MarkHttpAs",
- base::FEATURE_DISABLED_BY_DEFAULT};
+ base::FEATURE_ENABLED_BY_DEFAULT};
const char kMarkHttpAsFeatureParameterName[] = "treatment";
const char kMarkHttpAsParameterWarning[] = "warning";
const char kMarkHttpAsParameterDangerous[] = "dangerous";
diff --git a/chromium/components/security_state/core/security_state.cc b/chromium/components/security_state/core/security_state.cc
index 54531e28f4a..4ce6f6f3e21 100644
--- a/chromium/components/security_state/core/security_state.cc
+++ b/chromium/components/security_state/core/security_state.cc
@@ -19,6 +19,18 @@ namespace security_state {
namespace {
+// Returns true if |url| is a blob: URL and its path parses as a GURL with a
+// nonsecure origin, and false otherwise. See
+// https://url.spec.whatwg.org/#origin.
+bool IsNonsecureBlobUrl(
+ const GURL& url,
+ const IsOriginSecureCallback& is_origin_secure_callback) {
+ if (!url.SchemeIs(url::kBlobScheme))
+ return false;
+ GURL inner_url(url.path());
+ return !is_origin_secure_callback.Run(inner_url);
+}
+
// For nonsecure pages, sets |security_level| in |*security_info| based on the
// provided information and the kMarkHttpAsFeature field trial. Also sets the
// explanatory fields |incognito_downgraded_security_level| and
@@ -38,11 +50,6 @@ void SetSecurityLevelAndRelatedFieldsForNonSecureFieldTrial(
return;
}
- if (parameter == features::kMarkHttpAsParameterWarning) {
- security_info->security_level = HTTP_SHOW_WARNING;
- return;
- }
-
if (parameter ==
features::kMarkHttpAsParameterWarningAndDangerousOnFormEdits) {
security_info->security_level =
@@ -63,6 +70,11 @@ void SetSecurityLevelAndRelatedFieldsForNonSecureFieldTrial(
: HTTP_SHOW_WARNING;
return;
}
+
+ // By default, if the feature is enabled, show a warning on all http://
+ // pages.
+ security_info->security_level = HTTP_SHOW_WARNING;
+ return;
}
// No warning treatment is configured via field trial. Default to warning on
@@ -152,7 +164,8 @@ void SetSecurityLevelAndRelatedFields(
if (!is_cryptographic_with_certificate) {
if (!visible_security_state.is_error_page &&
!is_origin_secure_callback.Run(url) &&
- (url.IsStandard() || url.SchemeIs(url::kBlobScheme))) {
+ (url.IsStandard() ||
+ IsNonsecureBlobUrl(url, is_origin_secure_callback))) {
SetSecurityLevelAndRelatedFieldsForNonSecureFieldTrial(
visible_security_state.is_incognito,
visible_security_state.is_error_page,
@@ -280,9 +293,6 @@ void SecurityInfoForRequest(
} // namespace
-const base::Feature kHttpFormWarningFeature{"HttpFormWarning",
- base::FEATURE_DISABLED_BY_DEFAULT};
-
SecurityInfo::SecurityInfo()
: security_level(NONE),
malicious_content_status(MALICIOUS_CONTENT_STATUS_NONE),
@@ -313,10 +323,6 @@ void GetSecurityInfo(
is_origin_secure_callback, result);
}
-bool IsHttpWarningInFormEnabled() {
- return base::FeatureList::IsEnabled(kHttpFormWarningFeature);
-}
-
VisibleSecurityState::VisibleSecurityState()
: malicious_content_status(MALICIOUS_CONTENT_STATUS_NONE),
connection_info_initialized(false),
diff --git a/chromium/components/security_state/core/security_state.h b/chromium/components/security_state/core/security_state.h
index 4ca022bea15..4e6002adf8f 100644
--- a/chromium/components/security_state/core/security_state.h
+++ b/chromium/components/security_state/core/security_state.h
@@ -27,10 +27,6 @@
// the form of a VisibleSecurityState struct.
namespace security_state {
-// A feature for showing a warning in autofill dropdowns for password
-// and credit cards fields when the top-level page is not HTTPS.
-extern const base::Feature kHttpFormWarningFeature;
-
// Describes the overall security state of the page.
//
// These values are persisted to logs. Entries should not be renumbered and
diff --git a/chromium/components/security_state/core/security_state_unittest.cc b/chromium/components/security_state/core/security_state_unittest.cc
index c93aa0d2bf9..b3276ba1033 100644
--- a/chromium/components/security_state/core/security_state_unittest.cc
+++ b/chromium/components/security_state/core/security_state_unittest.cc
@@ -339,16 +339,14 @@ TEST(SecurityStateTest, PasswordFieldWarning) {
EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
}
-// Tests that password fields cause the security level to be downgraded
-// to HTTP_SHOW_WARNING on pseudo URLs.
-TEST(SecurityStateTest, PasswordFieldWarningOnPseudoUrls) {
+// Tests that the security level is downgraded to HTTP_SHOW_WARNING on pseudo
+// URLs.
+TEST(SecurityStateTest, WarningOnPseudoUrls) {
for (const char* const url : kPseudoUrls) {
TestSecurityStateHelper helper;
helper.SetUrl(GURL(url));
- helper.set_password_field_shown(true);
SecurityInfo security_info;
helper.GetSecurityInfo(&security_info);
- EXPECT_TRUE(security_info.insecure_input_events.password_field_shown);
EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
}
}
@@ -365,20 +363,6 @@ TEST(SecurityStateTest, CreditCardFieldWarning) {
EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
}
-// Tests that credit card fields cause the security level to be downgraded
-// to HTTP_SHOW_WARNING on pseudo URLs.
-TEST(SecurityStateTest, CreditCardFieldWarningOnPseudoUrls) {
- for (const char* const url : kPseudoUrls) {
- TestSecurityStateHelper helper;
- helper.SetUrl(GURL(url));
- helper.set_credit_card_field_edited(true);
- SecurityInfo security_info;
- helper.GetSecurityInfo(&security_info);
- EXPECT_TRUE(security_info.insecure_input_events.credit_card_field_edited);
- EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
- }
-}
-
// Tests that neither |password_field_shown| nor
// |credit_card_field_edited| is set when the corresponding
// VisibleSecurityState flags are not set.
@@ -389,7 +373,7 @@ TEST(SecurityStateTest, PrivateUserDataNotSet) {
helper.GetSecurityInfo(&security_info);
EXPECT_FALSE(security_info.insecure_input_events.password_field_shown);
EXPECT_FALSE(security_info.insecure_input_events.credit_card_field_edited);
- EXPECT_EQ(NONE, security_info.security_level);
+ EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
}
// Tests that neither |password_field_shown| nor
@@ -403,7 +387,7 @@ TEST(SecurityStateTest, PrivateUserDataNotSetOnPseudoUrls) {
helper.GetSecurityInfo(&security_info);
EXPECT_FALSE(security_info.insecure_input_events.password_field_shown);
EXPECT_FALSE(security_info.insecure_input_events.credit_card_field_edited);
- EXPECT_EQ(NONE, security_info.security_level);
+ EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
}
}
@@ -441,14 +425,22 @@ TEST(SecurityStateTest, IncognitoFlagPropagates) {
helper.SetUrl(GURL(kHttpUrl));
SecurityInfo security_info;
- // Test the default non-secure-while-incognito-or-editing configuration.
- helper.set_is_incognito(false);
- helper.GetSecurityInfo(&security_info);
- EXPECT_FALSE(security_info.incognito_downgraded_security_level);
+ {
+ // Disable the feature, which shows the warning on all incognito http pages
+ // by default.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(
+ security_state::features::kMarkHttpAsFeature);
- helper.set_is_incognito(true);
- helper.GetSecurityInfo(&security_info);
- EXPECT_TRUE(security_info.incognito_downgraded_security_level);
+ // Test the default non-secure-while-incognito-or-editing configuration.
+ helper.set_is_incognito(false);
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_FALSE(security_info.incognito_downgraded_security_level);
+
+ helper.set_is_incognito(true);
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_TRUE(security_info.incognito_downgraded_security_level);
+ }
{
// Disable the "non-secure-while-incognito" configuration.
@@ -574,21 +566,29 @@ TEST(SecurityStateTest, FieldEdit) {
TestSecurityStateHelper helper;
helper.SetUrl(GURL(kHttpUrl));
- SecurityInfo no_field_edit_security_info;
- helper.GetSecurityInfo(&no_field_edit_security_info);
- EXPECT_FALSE(
- no_field_edit_security_info.insecure_input_events.insecure_field_edited);
- EXPECT_FALSE(
- no_field_edit_security_info.field_edit_downgraded_security_level);
- EXPECT_EQ(NONE, no_field_edit_security_info.security_level);
+ {
+ // Test the configuration that warns on field edits (the default behavior
+ // when the feature is disabled).
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitAndDisableFeature(
+ security_state::features::kMarkHttpAsFeature);
- helper.set_insecure_field_edit(true);
+ SecurityInfo no_field_edit_security_info;
+ helper.GetSecurityInfo(&no_field_edit_security_info);
+ EXPECT_FALSE(no_field_edit_security_info.insecure_input_events
+ .insecure_field_edited);
+ EXPECT_FALSE(
+ no_field_edit_security_info.field_edit_downgraded_security_level);
+ EXPECT_EQ(NONE, no_field_edit_security_info.security_level);
- SecurityInfo security_info;
- helper.GetSecurityInfo(&security_info);
- EXPECT_TRUE(security_info.insecure_input_events.insecure_field_edited);
- EXPECT_TRUE(security_info.field_edit_downgraded_security_level);
- EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
+ helper.set_insecure_field_edit(true);
+
+ SecurityInfo security_info;
+ helper.GetSecurityInfo(&security_info);
+ EXPECT_TRUE(security_info.insecure_input_events.insecure_field_edited);
+ EXPECT_TRUE(security_info.field_edit_downgraded_security_level);
+ EXPECT_EQ(HTTP_SHOW_WARNING, security_info.security_level);
+ }
{
// Test the "dangerous" configuration.
@@ -598,6 +598,7 @@ TEST(SecurityStateTest, FieldEdit) {
{{security_state::features::kMarkHttpAsFeatureParameterName,
security_state::features::kMarkHttpAsParameterDangerous}});
+ SecurityInfo security_info;
helper.GetSecurityInfo(&security_info);
EXPECT_TRUE(security_info.insecure_input_events.insecure_field_edited);
EXPECT_FALSE(security_info.field_edit_downgraded_security_level);
@@ -652,7 +653,6 @@ TEST(SecurityStateTest, IncognitoErrorPage) {
helper.set_is_error_page(false);
helper.GetSecurityInfo(&security_info);
EXPECT_EQ(SecurityLevel::HTTP_SHOW_WARNING, security_info.security_level);
- EXPECT_TRUE(security_info.incognito_downgraded_security_level);
}
// Tests that HTTP_SHOW_WARNING is set when the 'warning' field trial
diff --git a/chromium/components/security_state_strings_grdp/OWNERS b/chromium/components/security_state_strings_grdp/OWNERS
new file mode 100644
index 00000000000..9e98e488b99
--- /dev/null
+++ b/chromium/components/security_state_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/security_state/OWNERS
diff --git a/chromium/components/security_state_strings_grdp/README.md b/chromium/components/security_state_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/security_state_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/services/filesystem/BUILD.gn b/chromium/components/services/filesystem/BUILD.gn
index a28630b38f2..504758b2784 100644
--- a/chromium/components/services/filesystem/BUILD.gn
+++ b/chromium/components/services/filesystem/BUILD.gn
@@ -27,7 +27,6 @@ static_library("lib") {
deps = [
"//base",
"//components/services/filesystem/public/interfaces",
- "//mojo/common",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//services/service_manager/public/mojom",
@@ -48,7 +47,6 @@ if (!is_ios) {
":lib",
"//base",
"//components/services/filesystem/public/interfaces",
- "//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
@@ -73,7 +71,6 @@ if (!is_ios) {
deps = [
"//base",
"//components/services/filesystem/public/interfaces",
- "//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
diff --git a/chromium/components/services/filesystem/DEPS b/chromium/components/services/filesystem/DEPS
index 776080079ba..541d16a8a62 100644
--- a/chromium/components/services/filesystem/DEPS
+++ b/chromium/components/services/filesystem/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+components/prefs",
- "+mojo/common",
"+mojo/public",
"+mojo/util",
"+services/service_manager",
diff --git a/chromium/components/services/filesystem/file_system_app.cc b/chromium/components/services/filesystem/file_system_app.cc
index d5a24f001c3..047645f49d3 100644
--- a/chromium/components/services/filesystem/file_system_app.cc
+++ b/chromium/components/services/filesystem/file_system_app.cc
@@ -70,11 +70,11 @@ base::FilePath FileSystemApp::GetUserDataDir() {
path = command_line->GetSwitchValuePath(kUserDataDir);
} else {
#if defined(OS_WIN)
- CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path));
+ CHECK(base::PathService::Get(base::DIR_LOCAL_APP_DATA, &path));
#elif defined(OS_MACOSX)
- CHECK(PathService::Get(base::DIR_APP_DATA, &path));
+ CHECK(base::PathService::Get(base::DIR_APP_DATA, &path));
#elif defined(OS_ANDROID)
- CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &path));
+ CHECK(base::PathService::Get(base::DIR_ANDROID_APP_DATA, &path));
#elif defined(OS_LINUX)
std::unique_ptr<base::Environment> env(base::Environment::Create());
path = base::nix::GetXDGDirectory(
diff --git a/chromium/components/services/filesystem/manifest.json b/chromium/components/services/filesystem/manifest.json
index 1bc538a0d53..5e2e1647432 100644
--- a/chromium/components/services/filesystem/manifest.json
+++ b/chromium/components/services/filesystem/manifest.json
@@ -5,7 +5,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "filesystem:filesystem": [ "filesystem::mojom::FileSystem" ]
+ "filesystem:filesystem": [ "filesystem.mojom.FileSystem" ]
},
"requires": {
"*": [ "app" ]
diff --git a/chromium/components/services/filesystem/public/interfaces/BUILD.gn b/chromium/components/services/filesystem/public/interfaces/BUILD.gn
index 2e5cc65b686..0547016173b 100644
--- a/chromium/components/services/filesystem/public/interfaces/BUILD.gn
+++ b/chromium/components/services/filesystem/public/interfaces/BUILD.gn
@@ -12,7 +12,6 @@ mojom("interfaces") {
"types.mojom",
]
public_deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
]
}
diff --git a/chromium/components/services/filesystem/util.cc b/chromium/components/services/filesystem/util.cc
index 475dd25e13d..7ed11a28446 100644
--- a/chromium/components/services/filesystem/util.cc
+++ b/chromium/components/services/filesystem/util.cc
@@ -98,10 +98,10 @@ base::File::Error ValidatePath(const std::string& raw_path,
if (!base::IsStringUTF8(raw_path))
return base::File::Error::FILE_ERROR_INVALID_OPERATION;
-#if defined(OS_POSIX)
- base::FilePath::StringType path = raw_path;
-#elif defined(OS_WIN)
+#if defined(OS_WIN)
base::FilePath::StringType path = base::UTF8ToUTF16(raw_path);
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ base::FilePath::StringType path = raw_path;
#endif
// TODO(erg): This isn't really what we want. FilePath::AppendRelativePath()
diff --git a/chromium/components/services/font/DEPS b/chromium/components/services/font/DEPS
index 5504d41f9a2..dccac320689 100644
--- a/chromium/components/services/font/DEPS
+++ b/chromium/components/services/font/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+services/service_manager",
- "+mojo/common",
"+mojo/public",
"+skia",
"+third_party/skia/include",
diff --git a/chromium/components/services/font/manifest.json b/chromium/components/services/font/manifest.json
index 2fd8207280a..434a7ff30d7 100644
--- a/chromium/components/services/font/manifest.json
+++ b/chromium/components/services/font/manifest.json
@@ -5,7 +5,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "app": [ "font_service::mojom::FontService" ]
+ "app": [ "font_service.mojom.FontService" ]
},
"requires": {
"*": [ "app" ]
diff --git a/chromium/components/services/font/public/cpp/BUILD.gn b/chromium/components/services/font/public/cpp/BUILD.gn
index 667d32ad6a6..da5ce239c02 100644
--- a/chromium/components/services/font/public/cpp/BUILD.gn
+++ b/chromium/components/services/font/public/cpp/BUILD.gn
@@ -15,7 +15,6 @@ source_set("cpp") {
deps = [
"../interfaces",
"//base",
- "//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
diff --git a/chromium/components/services/heap_profiling/BUILD.gn b/chromium/components/services/heap_profiling/BUILD.gn
index 16f128cc3bb..0b98f99baed 100644
--- a/chromium/components/services/heap_profiling/BUILD.gn
+++ b/chromium/components/services/heap_profiling/BUILD.gn
@@ -26,8 +26,6 @@ static_library("heap_profiling") {
"receiver.h",
"receiver_pipe.cc",
"receiver_pipe.h",
- "receiver_pipe_posix.cc",
- "receiver_pipe_posix.h",
"receiver_pipe_win.cc",
"receiver_pipe_win.h",
"stream_parser.cc",
@@ -42,6 +40,13 @@ static_library("heap_profiling") {
"//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
"//third_party/zlib",
]
+
+ if (is_posix) {
+ sources += [
+ "receiver_pipe_posix.cc",
+ "receiver_pipe_posix.h",
+ ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/services/heap_profiling/connection_manager.cc b/chromium/components/services/heap_profiling/connection_manager.cc
index ec472ae945b..5f0797c7f2f 100644
--- a/chromium/components/services/heap_profiling/connection_manager.cc
+++ b/chromium/components/services/heap_profiling/connection_manager.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/stringprintf.h"
#include "base/threading/sequenced_task_runner_handle.h"
@@ -150,14 +151,14 @@ void ConnectionManager::OnNewConnection(base::ProcessId pid,
CHECK_EQ(MOJO_RESULT_OK, mojo::UnwrapPlatformFile(
std::move(receiver_pipe_end), &receiver_handle));
scoped_refptr<ReceiverPipe> new_pipe =
- new ReceiverPipe(mojo::edk::ScopedPlatformHandle(
- mojo::edk::PlatformHandle(receiver_handle)));
+ new ReceiverPipe(mojo::edk::ScopedInternalPlatformHandle(
+ mojo::edk::InternalPlatformHandle(receiver_handle)));
// The allocation tracker will call this on a background thread, so thunk
// back to the current thread with weak pointers.
AllocationTracker::CompleteCallback complete_cb =
base::BindOnce(&ConnectionManager::OnConnectionCompleteThunk,
- base::MessageLoop::current()->task_runner(),
+ base::MessageLoopCurrent::Get()->task_runner(),
weak_factory_.GetWeakPtr(), pid);
auto connection = std::make_unique<Connection>(
@@ -251,7 +252,7 @@ void ConnectionManager::DumpProcessesForTracing(
tracking->results.reserve(connections_.size());
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
- base::MessageLoop::current()->task_runner();
+ base::MessageLoopCurrent::Get()->task_runner();
for (auto& it : connections_) {
base::ProcessId pid = it.first;
@@ -364,7 +365,7 @@ void ConnectionManager::DoDumpOneProcessForTracing(
std::move(buffer)));
},
- reply_size, base::MessageLoop::current()->task_runner(),
+ reply_size, base::MessageLoopCurrent::Get()->task_runner(),
std::move(finished_callback)));
}
diff --git a/chromium/components/services/heap_profiling/connection_manager.h b/chromium/components/services/heap_profiling/connection_manager.h
index 55db159564f..c2c74dfd71b 100644
--- a/chromium/components/services/heap_profiling/connection_manager.h
+++ b/chromium/components/services/heap_profiling/connection_manager.h
@@ -33,8 +33,8 @@ class SequencedTaskRunner;
namespace heap_profiling {
using VmRegions =
- std::unordered_map<base::ProcessId,
- std::vector<memory_instrumentation::mojom::VmRegionPtr>>;
+ base::flat_map<base::ProcessId,
+ std::vector<memory_instrumentation::mojom::VmRegionPtr>>;
// Manages all connections and logging for each process. Pipes are supplied by
// the pipe server and this class will connect them to a parser and logger.
diff --git a/chromium/components/services/heap_profiling/heap_profiling_manifest.json b/chromium/components/services/heap_profiling/heap_profiling_manifest.json
index 40d94cb3818..4c77773c9b8 100644
--- a/chromium/components/services/heap_profiling/heap_profiling_manifest.json
+++ b/chromium/components/services/heap_profiling/heap_profiling_manifest.json
@@ -5,8 +5,8 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "profiling": [ "heap_profiling::mojom::ProfilingService" ],
- "heap_profiler": [ "memory_instrumentation::mojom::HeapProfiler" ]
+ "profiling": [ "heap_profiling.mojom.ProfilingService" ],
+ "heap_profiler": [ "memory_instrumentation.mojom.HeapProfiler" ]
},
"requires": {
"*": [ "app" ],
diff --git a/chromium/components/services/heap_profiling/public/cpp/BUILD.gn b/chromium/components/services/heap_profiling/public/cpp/BUILD.gn
index 97cce651008..6c826fd2e81 100644
--- a/chromium/components/services/heap_profiling/public/cpp/BUILD.gn
+++ b/chromium/components/services/heap_profiling/public/cpp/BUILD.gn
@@ -11,7 +11,6 @@ static_library("cpp") {
"controller.cc",
"controller.h",
"sender_pipe.h",
- "sender_pipe_posix.cc",
"sender_pipe_win.cc",
"settings.cc",
"settings.h",
@@ -31,6 +30,10 @@ static_library("cpp") {
"//services/resource_coordinator/public/mojom:",
"//services/service_manager/public/cpp",
]
+
+ if (is_posix) {
+ sources += [ "sender_pipe_posix.cc" ]
+ }
}
source_set("unit_tests") {
diff --git a/chromium/components/services/heap_profiling/public/cpp/OWNERS b/chromium/components/services/heap_profiling/public/cpp/OWNERS
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/chromium/components/services/heap_profiling/public/cpp/OWNERS
+++ /dev/null
diff --git a/chromium/components/services/heap_profiling/public/cpp/allocator_shim.cc b/chromium/components/services/heap_profiling/public/cpp/allocator_shim.cc
index 076a845c3d8..729d2119b41 100644
--- a/chromium/components/services/heap_profiling/public/cpp/allocator_shim.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/allocator_shim.cc
@@ -20,7 +20,6 @@
#include "base/threading/thread_local.h"
#include "base/threading/thread_local_storage.h"
#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
-#include "base/trace_event/heap_profiler_allocation_register.h"
#include "base/trace_event/heap_profiler_event_filter.h"
#include "base/trace_event/memory_dump_manager.h"
#include "build/build_config.h"
@@ -45,39 +44,53 @@ using CaptureMode = base::trace_event::AllocationContextTracker::CaptureMode;
namespace heap_profiling {
-namespace {
-
-// In the very unlikely scenario where a thread has grabbed the SendBuffer lock,
-// and then performs a heap allocation/free, ignore the allocation. Failing to
-// do so will cause non-deterministic deadlock, depending on whether the
-// allocation is dispatched to the same SendBuffer.
+// A ScopedAllowLogging instance must be instantiated in the scope of all hooks.
+// AllocatorShimLogAlloc/AllocatorShimLogFree must only be called if it
+// evaluates to true.
+//
+// There are two reasons why logging may be disabled.
+// 1) To prevent reentrancy from logging code.
+// 2) During thread destruction, Chrome TLS has been destroyed and it can no
+// longer be used to determine if reentrancy is occurring. Attempting to
+// access Chrome TLS after it has been destroyed is disallowed.
+//
+// Failure to prevent reentrancy can cause non-deterministic deadlock. This
+// happens if a thread has grabbed the SendBuffer lock, then performs a heap
+// allocation/free, which in turn tries to grab the SendBuffer lock.
//
-// On macOS, this flag is also used to prevent double-counting during sampling.
+// On macOS, this guard is also used to prevent double-counting during sampling.
// The implementation of libmalloc will sometimes call malloc [from
-// one zone to another] - without this flag, the allocation would get two
+// one zone to another] - without this guard, the allocation would get two
// chances of being sampled.
-base::LazyInstance<base::ThreadLocalBoolean>::Leaky g_prevent_reentrancy =
- LAZY_INSTANCE_INITIALIZER;
-
-} // namespace
-
-// This class is friended by ThreadLocalStorage.
-class MemlogAllocatorShimInternal {
+class ScopedAllowLogging {
public:
- static bool ShouldLogAllocationOnCurrentThread() {
- // Thread is being destroyed and TLS is no longer available.
- if (UNLIKELY(base::ThreadLocalStorage::HasBeenDestroyed()))
- return false;
-
- // Prevent re-entrancy.
- return !g_prevent_reentrancy.Pointer()->Get();
+ ScopedAllowLogging()
+ : allowed_(LIKELY(!base::ThreadLocalStorage::HasBeenDestroyed()) &&
+ LIKELY(!prevent_reentrancy_.Pointer()->Get())) {
+ if (allowed_)
+ prevent_reentrancy_.Pointer()->Set(true);
+ }
+ ~ScopedAllowLogging() {
+ if (allowed_)
+ prevent_reentrancy_.Pointer()->Set(false);
}
+ explicit operator bool() const { return allowed_; }
+
+ private:
+ const bool allowed_;
+ static base::LazyInstance<base::ThreadLocalBoolean>::Leaky
+ prevent_reentrancy_;
};
+base::LazyInstance<base::ThreadLocalBoolean>::Leaky
+ ScopedAllowLogging::prevent_reentrancy_;
+
namespace {
using base::allocator::AllocatorDispatch;
+bool g_initialized_ = false;
+base::LazyInstance<base::Lock>::Leaky g_on_init_allocator_shim_lock_;
base::LazyInstance<base::OnceClosure>::Leaky g_on_init_allocator_shim_callback_;
base::LazyInstance<scoped_refptr<base::TaskRunner>>::Leaky
g_on_init_allocator_shim_task_runner_;
@@ -149,15 +162,14 @@ void DestructShimState(void* shim_state) {
// Technically, this code could be called after Thread destruction and we would
// need to guard this with ThreadLocalStorage::HasBeenDestroyed(), but all calls
-// to this are guarded behind ShouldLogAllocationOnCurrentThread, which already
-// makes the check.
+// to this are guarded behind ScopedAllowLogging, which already makes the check.
base::ThreadLocalStorage::Slot& ShimStateTLS() {
static base::NoDestructor<base::ThreadLocalStorage::Slot> shim_state_tls(
&DestructShimState);
return *shim_state_tls;
}
-// We don't need to worry about re-entrancy because g_prevent_reentrancy
+// We don't need to worry about re-entrancy because ScopedAllowLogging
// already guards against that.
ShimState* GetShimState() {
ShimState* state = static_cast<ShimState*>(ShimStateTLS().Get());
@@ -246,8 +258,9 @@ class SendBuffer {
void SendCurrentBuffer() {
SenderPipe::Result result = g_sender_pipe->Send(buffer_, used_, kTimeoutMs);
used_ = 0;
- if (result == SenderPipe::Result::kError)
+ if (result == SenderPipe::Result::kError) {
StopAllocatorShimDangerous();
+ }
if (result == SenderPipe::Result::kTimeout) {
StopAllocatorShimDangerous();
// TODO(erikchen): Emit a histogram. https://crbug.com/777546.
@@ -286,32 +299,35 @@ class AtomicallyConsistentSendBufferArray {
// nullptr.
AtomicallyConsistentSendBufferArray g_send_buffers;
+size_t HashAddress(const void* address) {
+ // The multiplicative hashing scheme from [Knuth 1998].
+ // |a| is the first prime after 2^17.
+ const uintptr_t key = reinterpret_cast<uintptr_t>(address);
+ const uintptr_t a = 131101;
+ const uintptr_t shift = 15;
+ const uintptr_t h = (key * a) >> shift;
+ return h;
+}
+
// "address" is the address in question, which is used to select which send
// buffer to use.
void DoSend(const void* address,
const void* data,
size_t size,
SendBuffer* send_buffers) {
- base::trace_event::AllocationRegister::AddressHasher hasher;
- int bin_to_use = hasher(address) % kNumSendBuffers;
+ int bin_to_use = HashAddress(address) % kNumSendBuffers;
send_buffers[bin_to_use].Send(data, size);
}
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
void* HookAlloc(const AllocatorDispatch* self, size_t size, void* context) {
- const AllocatorDispatch* const next = self->next;
-
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ const AllocatorDispatch* const next = self->next;
void* ptr = next->alloc_function(next, size, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, size, nullptr);
- g_prevent_reentrancy.Pointer()->Set(false);
}
return ptr;
@@ -321,19 +337,13 @@ void* HookZeroInitAlloc(const AllocatorDispatch* self,
size_t n,
size_t size,
void* context) {
- const AllocatorDispatch* const next = self->next;
-
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ const AllocatorDispatch* const next = self->next;
void* ptr = next->alloc_zero_initialized_function(next, n, size, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, n * size, nullptr);
- g_prevent_reentrancy.Pointer()->Set(false);
}
return ptr;
}
@@ -342,19 +352,13 @@ void* HookAllocAligned(const AllocatorDispatch* self,
size_t alignment,
size_t size,
void* context) {
- const AllocatorDispatch* const next = self->next;
-
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ const AllocatorDispatch* const next = self->next;
void* ptr = next->alloc_aligned_function(next, alignment, size, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, size, nullptr);
- g_prevent_reentrancy.Pointer()->Set(false);
}
return ptr;
}
@@ -363,39 +367,28 @@ void* HookRealloc(const AllocatorDispatch* self,
void* address,
size_t size,
void* context) {
- const AllocatorDispatch* const next = self->next;
-
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ const AllocatorDispatch* const next = self->next;
void* ptr = next->realloc_function(next, address, size, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
AllocatorShimLogFree(address);
if (size > 0) // realloc(size == 0) means free()
AllocatorShimLogAlloc(AllocatorType::kMalloc, ptr, size, nullptr);
- g_prevent_reentrancy.Pointer()->Set(false);
}
return ptr;
}
void HookFree(const AllocatorDispatch* self, void* address, void* context) {
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
const AllocatorDispatch* const next = self->next;
next->free_function(next, address, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
AllocatorShimLogFree(address);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
@@ -411,20 +404,15 @@ unsigned HookBatchMalloc(const AllocatorDispatch* self,
void** results,
unsigned num_requested,
void* context) {
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
const AllocatorDispatch* const next = self->next;
unsigned count =
next->batch_malloc_function(next, size, results, num_requested, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
for (unsigned i = 0; i < count; ++i)
AllocatorShimLogAlloc(AllocatorType::kMalloc, results[i], size, nullptr);
- g_prevent_reentrancy.Pointer()->Set(false);
}
return count;
}
@@ -433,19 +421,14 @@ void HookBatchFree(const AllocatorDispatch* self,
void** to_be_freed,
unsigned num_to_be_freed,
void* context) {
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
const AllocatorDispatch* const next = self->next;
next->batch_free_function(next, to_be_freed, num_to_be_freed, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
for (unsigned i = 0; i < num_to_be_freed; ++i)
AllocatorShimLogFree(to_be_freed[i]);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
@@ -453,18 +436,13 @@ void HookFreeDefiniteSize(const AllocatorDispatch* self,
void* ptr,
size_t size,
void* context) {
- // If this is our first time passing through, set the reentrancy bit.
- bool should_log =
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread();
- if (LIKELY(should_log))
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
const AllocatorDispatch* const next = self->next;
next->free_definite_size_function(next, ptr, size, context);
- if (LIKELY(should_log)) {
+ if (LIKELY(allow_logging)) {
AllocatorShimLogFree(ptr);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
@@ -483,40 +461,30 @@ AllocatorDispatch g_hooks = {
#endif // BUILDFLAG(USE_ALLOCATOR_SHIM)
void HookPartitionAlloc(void* address, size_t size, const char* type) {
- // If this is our first time passing through, set the reentrancy bit.
- if (LIKELY(
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ if (LIKELY(allow_logging)) {
AllocatorShimLogAlloc(AllocatorType::kPartitionAlloc, address, size, type);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
void HookPartitionFree(void* address) {
- // If this is our first time passing through, set the reentrancy bit.
- if (LIKELY(
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ if (LIKELY(allow_logging)) {
AllocatorShimLogFree(address);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
void HookGCAlloc(uint8_t* address, size_t size, const char* type) {
- if (LIKELY(
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ if (LIKELY(allow_logging)) {
AllocatorShimLogAlloc(AllocatorType::kOilpan, address, size, type);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
void HookGCFree(uint8_t* address) {
- if (LIKELY(
- MemlogAllocatorShimInternal::ShouldLogAllocationOnCurrentThread())) {
- g_prevent_reentrancy.Pointer()->Set(true);
+ ScopedAllowLogging allow_logging;
+ if (LIKELY(allow_logging)) {
AllocatorShimLogFree(address);
- g_prevent_reentrancy.Pointer()->Set(false);
}
}
@@ -621,7 +589,7 @@ class FrameSerializer {
} // namespace
void InitTLSSlot() {
- ignore_result(g_prevent_reentrancy.Pointer()->Get());
+ { ScopedAllowLogging allow_logging; }
ignore_result(ShimStateTLS());
}
@@ -694,10 +662,14 @@ void InitAllocatorShim(SenderPipe* sender_pipe,
g_hook_gc_free(&HookGCFree);
}
- if (*g_on_init_allocator_shim_callback_.Pointer()) {
- (*g_on_init_allocator_shim_task_runner_.Pointer())
- ->PostTask(FROM_HERE,
- std::move(*g_on_init_allocator_shim_callback_.Pointer()));
+ {
+ base::AutoLock lock(*g_on_init_allocator_shim_lock_.Pointer());
+ g_initialized_ = true;
+ if (*g_on_init_allocator_shim_callback_.Pointer()) {
+ (*g_on_init_allocator_shim_task_runner_.Pointer())
+ ->PostTask(FROM_HERE,
+ std::move(*g_on_init_allocator_shim_callback_.Pointer()));
+ }
}
}
@@ -886,11 +858,15 @@ void SetGCHeapAllocationHookFunctions(SetGCAllocHookFunction hook_alloc,
}
}
-void SetOnInitAllocatorShimCallbackForTesting(
+bool SetOnInitAllocatorShimCallbackForTesting(
base::OnceClosure callback,
scoped_refptr<base::TaskRunner> task_runner) {
+ base::AutoLock lock(*g_on_init_allocator_shim_lock_.Pointer());
+ if (g_initialized_)
+ return true;
*g_on_init_allocator_shim_callback_.Pointer() = std::move(callback);
*g_on_init_allocator_shim_task_runner_.Pointer() = task_runner;
+ return false;
}
} // namespace heap_profiling
diff --git a/chromium/components/services/heap_profiling/public/cpp/allocator_shim.h b/chromium/components/services/heap_profiling/public/cpp/allocator_shim.h
index 0ee3b46c8b0..8004d3239f1 100644
--- a/chromium/components/services/heap_profiling/public/cpp/allocator_shim.h
+++ b/chromium/components/services/heap_profiling/public/cpp/allocator_shim.h
@@ -55,9 +55,11 @@ using SetGCFreeHookFunction = void (*)(void (*)(uint8_t*));
void SetGCHeapAllocationHookFunctions(SetGCAllocHookFunction hook_alloc,
SetGCFreeHookFunction hook_free);
-// Exists for testing only. |callback| is called on |task_runner| after the
-// allocator shim is initialized.
-void SetOnInitAllocatorShimCallbackForTesting(
+// Exists for testing only.
+// A return value of |true| means that the allocator shim was already
+// initialized and |callback| will never be called. Otherwise, |callback| will
+// be called on |task_runner| after the allocator shim is initialized.
+bool SetOnInitAllocatorShimCallbackForTesting(
base::OnceClosure callback,
scoped_refptr<base::TaskRunner> task_runner);
diff --git a/chromium/components/services/heap_profiling/public/cpp/client.cc b/chromium/components/services/heap_profiling/public/cpp/client.cc
index 3e9b7d1b106..cebff10d057 100644
--- a/chromium/components/services/heap_profiling/public/cpp/client.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/client.cc
@@ -6,6 +6,7 @@
#include "base/allocator/allocator_interception_mac.h"
#include "base/files/platform_file.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "base/trace_event/malloc_dump_provider.h"
@@ -43,15 +44,17 @@ void EnsureCFIInitializedOnBackgroundThread(
Client::Client() : started_profiling_(false), weak_factory_(this) {}
Client::~Client() {
- StopAllocatorShimDangerous();
+ if (started_profiling_) {
+ StopAllocatorShimDangerous();
- base::trace_event::MallocDumpProvider::GetInstance()->EnableMetrics();
+ base::trace_event::MallocDumpProvider::GetInstance()->EnableMetrics();
- // The allocator shim cannot be synchronously, consistently stopped. We leak
- // the sender_pipe_, with the idea that very few future messages will
- // be sent to it. This happens at shutdown, so resources will be reclaimed by
- // the OS after the process is terminated.
- sender_pipe_.release();
+ // The allocator shim cannot be synchronously, consistently stopped. We leak
+ // the sender_pipe_, with the idea that very few future messages will
+ // be sent to it. This happens at shutdown, so resources will be reclaimed
+ // by the OS after the process is terminated.
+ sender_pipe_.release();
+ }
}
void Client::BindToInterface(mojom::ProfilingClientRequest request) {
diff --git a/chromium/components/services/heap_profiling/public/cpp/sender_pipe.h b/chromium/components/services/heap_profiling/public/cpp/sender_pipe.h
index 95cd2791597..97c41d42af8 100644
--- a/chromium/components/services/heap_profiling/public/cpp/sender_pipe.h
+++ b/chromium/components/services/heap_profiling/public/cpp/sender_pipe.h
@@ -32,14 +32,16 @@ class SenderPipe {
// |kPipeSize|.
PipePair();
PipePair(PipePair&&);
- mojo::edk::ScopedPlatformHandle PassSender() { return std::move(sender_); }
- mojo::edk::ScopedPlatformHandle PassReceiver() {
+ mojo::edk::ScopedInternalPlatformHandle PassSender() {
+ return std::move(sender_);
+ }
+ mojo::edk::ScopedInternalPlatformHandle PassReceiver() {
return std::move(receiver_);
}
private:
- mojo::edk::ScopedPlatformHandle sender_;
- mojo::edk::ScopedPlatformHandle receiver_;
+ mojo::edk::ScopedInternalPlatformHandle sender_;
+ mojo::edk::ScopedInternalPlatformHandle receiver_;
DISALLOW_COPY_AND_ASSIGN(PipePair);
};
diff --git a/chromium/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc b/chromium/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc
index 2db7f480f69..363226a0447 100644
--- a/chromium/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/sender_pipe_posix.cc
@@ -31,8 +31,8 @@ SenderPipe::PipePair::PipePair() {
PCHECK(fcntl(fds[0], F_SETNOSIGPIPE, 1) == 0);
PCHECK(fcntl(fds[1], F_SETNOSIGPIPE, 1) == 0);
#endif
- receiver_.reset(mojo::edk::PlatformHandle(fds[0]));
- sender_.reset(mojo::edk::PlatformHandle(fds[1]));
+ receiver_.reset(mojo::edk::InternalPlatformHandle(fds[0]));
+ sender_.reset(mojo::edk::InternalPlatformHandle(fds[1]));
}
SenderPipe::PipePair::PipePair(PipePair&& other) = default;
diff --git a/chromium/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc b/chromium/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc
index edd5215892d..3e3a14c6178 100644
--- a/chromium/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/sender_pipe_unittest.cc
@@ -22,7 +22,7 @@ using Result = SenderPipe::Result;
class SenderPipeTest : public testing::Test {
public:
void SetUp() override {
- mojo::edk::ScopedPlatformHandle write_handle;
+ mojo::edk::ScopedInternalPlatformHandle write_handle;
SenderPipe::PipePair pipes;
read_handle_ = pipes.PassReceiver();
@@ -52,7 +52,7 @@ class SenderPipeTest : public testing::Test {
}
private:
- mojo::edk::ScopedPlatformHandle read_handle_;
+ mojo::edk::ScopedInternalPlatformHandle read_handle_;
std::unique_ptr<SenderPipe> sender_pipe_;
std::vector<char> buffer_;
};
diff --git a/chromium/components/services/heap_profiling/public/cpp/sender_pipe_win.cc b/chromium/components/services/heap_profiling/public/cpp/sender_pipe_win.cc
index 3776a841feb..a12e1465563 100644
--- a/chromium/components/services/heap_profiling/public/cpp/sender_pipe_win.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/sender_pipe_win.cc
@@ -69,7 +69,7 @@ SenderPipe::PipePair::PipePair() {
// nothing to do with Send() timeout.
nullptr);
PCHECK(handle != INVALID_HANDLE_VALUE);
- receiver_.reset(mojo::edk::PlatformHandle(handle));
+ receiver_.reset(mojo::edk::InternalPlatformHandle(handle));
// Allow the handle to be inherited by child processes.
SECURITY_ATTRIBUTES security_attributes;
@@ -84,7 +84,7 @@ SenderPipe::PipePair::PipePair() {
SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS | FILE_FLAG_OVERLAPPED,
nullptr);
PCHECK(handle != INVALID_HANDLE_VALUE);
- sender_.reset(mojo::edk::PlatformHandle(handle));
+ sender_.reset(mojo::edk::InternalPlatformHandle(handle));
// Since a client has connected, ConnectNamedPipe() should return zero and
// GetLastError() should return ERROR_PIPE_CONNECTED.
diff --git a/chromium/components/services/heap_profiling/public/cpp/settings.cc b/chromium/components/services/heap_profiling/public/cpp/settings.cc
index 1d4bbc2c900..72525f4c161 100644
--- a/chromium/components/services/heap_profiling/public/cpp/settings.cc
+++ b/chromium/components/services/heap_profiling/public/cpp/settings.cc
@@ -42,17 +42,15 @@ bool RecordAllAllocationsForStartup() {
Mode GetModeForStartup() {
const base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
#if BUILDFLAG(USE_ALLOCATOR_SHIM)
+ if (cmdline->HasSwitch("enable-heap-profiling")) {
+ LOG(ERROR) << "--enable-heap-profiling is no longer supported. Use "
+ "--memlog instead. See documentation at "
+ "docs/memory/debugging_memory_issues.md";
+ return Mode::kNone;
+ }
+
if (cmdline->HasSwitch(kMemlog) ||
base::FeatureList::IsEnabled(kOOPHeapProfilingFeature)) {
- if (cmdline->HasSwitch(switches::kEnableHeapProfiling)) {
- // PartitionAlloc doesn't support chained allocation hooks so we can't
- // run both heap profilers at the same time.
- LOG(ERROR) << "--" << switches::kEnableHeapProfiling
- << " specified with --" << kMemlog
- << "which are not compatible. Memlog will be disabled.";
- return Mode::kNone;
- }
-
std::string mode;
// Respect the commandline switch above the field trial.
if (cmdline->HasSwitch(kMemlog)) {
diff --git a/chromium/components/services/heap_profiling/public/mojom/BUILD.gn b/chromium/components/services/heap_profiling/public/mojom/BUILD.gn
index 05b22689c53..fa28fe7f4bf 100644
--- a/chromium/components/services/heap_profiling/public/mojom/BUILD.gn
+++ b/chromium/components/services/heap_profiling/public/mojom/BUILD.gn
@@ -11,7 +11,6 @@ mojom("mojom") {
"heap_profiling_service.mojom",
]
deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
]
}
diff --git a/chromium/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom b/chromium/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom
index 04ee1f5df05..78269cfbaa1 100644
--- a/chromium/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom
+++ b/chromium/components/services/heap_profiling/public/mojom/heap_profiling_service.mojom
@@ -6,7 +6,6 @@ module heap_profiling.mojom;
import "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom";
import "mojo/public/mojom/base/process_id.mojom";
-import "mojo/common/values.mojom";
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
diff --git a/chromium/components/services/heap_profiling/receiver_pipe.cc b/chromium/components/services/heap_profiling/receiver_pipe.cc
index 1a5f2561694..a2add075b2d 100644
--- a/chromium/components/services/heap_profiling/receiver_pipe.cc
+++ b/chromium/components/services/heap_profiling/receiver_pipe.cc
@@ -10,7 +10,8 @@
namespace heap_profiling {
-ReceiverPipeBase::ReceiverPipeBase(mojo::edk::ScopedPlatformHandle handle)
+ReceiverPipeBase::ReceiverPipeBase(
+ mojo::edk::ScopedInternalPlatformHandle handle)
: handle_(std::move(handle)) {}
ReceiverPipeBase::~ReceiverPipeBase() = default;
diff --git a/chromium/components/services/heap_profiling/receiver_pipe.h b/chromium/components/services/heap_profiling/receiver_pipe.h
index cff4bfa3a29..e4e9ee36141 100644
--- a/chromium/components/services/heap_profiling/receiver_pipe.h
+++ b/chromium/components/services/heap_profiling/receiver_pipe.h
@@ -29,7 +29,7 @@ class ReceiverPipeBase : public base::RefCountedThreadSafe<ReceiverPipeBase> {
protected:
friend class base::RefCountedThreadSafe<ReceiverPipeBase>;
- explicit ReceiverPipeBase(mojo::edk::ScopedPlatformHandle handle);
+ explicit ReceiverPipeBase(mojo::edk::ScopedInternalPlatformHandle handle);
virtual ~ReceiverPipeBase();
// Callback that indicates an error has occurred and the connection should
@@ -46,7 +46,7 @@ class ReceiverPipeBase : public base::RefCountedThreadSafe<ReceiverPipeBase> {
scoped_refptr<base::TaskRunner> receiver_task_runner_;
scoped_refptr<StreamReceiver> receiver_;
- mojo::edk::ScopedPlatformHandle handle_;
+ mojo::edk::ScopedInternalPlatformHandle handle_;
};
} // namespace heap_profiling
diff --git a/chromium/components/services/heap_profiling/receiver_pipe_posix.cc b/chromium/components/services/heap_profiling/receiver_pipe_posix.cc
index 2c49007eef1..35baa5dfb91 100644
--- a/chromium/components/services/heap_profiling/receiver_pipe_posix.cc
+++ b/chromium/components/services/heap_profiling/receiver_pipe_posix.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
@@ -18,7 +18,7 @@
namespace heap_profiling {
-ReceiverPipe::ReceiverPipe(mojo::edk::ScopedPlatformHandle handle)
+ReceiverPipe::ReceiverPipe(mojo::edk::ScopedInternalPlatformHandle handle)
: ReceiverPipeBase(std::move(handle)),
controller_(FROM_HERE),
read_buffer_(new char[SenderPipe::kPipeSize]) {}
@@ -26,7 +26,7 @@ ReceiverPipe::ReceiverPipe(mojo::edk::ScopedPlatformHandle handle)
ReceiverPipe::~ReceiverPipe() {}
void ReceiverPipe::StartReadingOnIOThread() {
- base::MessageLoopForIO::current()->WatchFileDescriptor(
+ base::MessageLoopCurrentForIO::Get()->WatchFileDescriptor(
handle_.get().handle, true, base::MessagePumpForIO::WATCH_READ,
&controller_, this);
OnFileCanReadWithoutBlocking(handle_.get().handle);
@@ -35,16 +35,17 @@ void ReceiverPipe::StartReadingOnIOThread() {
void ReceiverPipe::OnFileCanReadWithoutBlocking(int fd) {
ssize_t bytes_read = 0;
do {
- base::circular_deque<mojo::edk::PlatformHandle> dummy_for_receive;
+ base::circular_deque<mojo::edk::InternalPlatformHandle> dummy_for_receive;
bytes_read = HANDLE_EINTR(
read(handle_.get().handle, read_buffer_.get(), SenderPipe::kPipeSize));
if (bytes_read > 0) {
receiver_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&ReceiverPipe::OnStreamDataThunk, this,
- base::MessageLoop::current()->task_runner(),
- std::move(read_buffer_),
- static_cast<size_t>(bytes_read)));
+ FROM_HERE,
+ base::BindOnce(&ReceiverPipe::OnStreamDataThunk, this,
+ base::MessageLoopCurrent::Get()->task_runner(),
+ std::move(read_buffer_),
+ static_cast<size_t>(bytes_read)));
read_buffer_.reset(new char[SenderPipe::kPipeSize]);
return;
} else if (bytes_read == 0) {
diff --git a/chromium/components/services/heap_profiling/receiver_pipe_posix.h b/chromium/components/services/heap_profiling/receiver_pipe_posix.h
index 9f7a616fd46..f5eb08f9db2 100644
--- a/chromium/components/services/heap_profiling/receiver_pipe_posix.h
+++ b/chromium/components/services/heap_profiling/receiver_pipe_posix.h
@@ -18,7 +18,7 @@ namespace heap_profiling {
class ReceiverPipe : public ReceiverPipeBase,
public base::MessagePumpForIO::FdWatcher {
public:
- explicit ReceiverPipe(mojo::edk::ScopedPlatformHandle handle);
+ explicit ReceiverPipe(mojo::edk::ScopedInternalPlatformHandle handle);
// Must be called on the IO thread.
void StartReadingOnIOThread();
diff --git a/chromium/components/services/heap_profiling/receiver_pipe_win.cc b/chromium/components/services/heap_profiling/receiver_pipe_win.cc
index 05ff5daaf59..8f14087d565 100644
--- a/chromium/components/services/heap_profiling/receiver_pipe_win.cc
+++ b/chromium/components/services/heap_profiling/receiver_pipe_win.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread.h"
@@ -16,12 +16,12 @@
namespace heap_profiling {
-ReceiverPipe::ReceiverPipe(mojo::edk::ScopedPlatformHandle handle)
+ReceiverPipe::ReceiverPipe(mojo::edk::ScopedInternalPlatformHandle handle)
: ReceiverPipeBase(std::move(handle)),
read_buffer_(new char[SenderPipe::kPipeSize]) {
ZeroOverlapped();
- base::MessageLoopForIO::current()->RegisterIOHandler(handle_.get().handle,
- this);
+ base::MessageLoopCurrentForIO::Get()->RegisterIOHandler(handle_.get().handle,
+ this);
}
ReceiverPipe::~ReceiverPipe() {}
@@ -72,10 +72,11 @@ void ReceiverPipe::OnIOCompleted(base::MessagePumpForIO::IOContext* context,
if (bytes_transfered && receiver_) {
receiver_task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&ReceiverPipe::OnStreamDataThunk, this,
- base::MessageLoop::current()->task_runner(),
- std::move(read_buffer_),
- static_cast<size_t>(bytes_transfered)));
+ FROM_HERE,
+ base::BindOnce(&ReceiverPipe::OnStreamDataThunk, this,
+ base::MessageLoopCurrent::Get()->task_runner(),
+ std::move(read_buffer_),
+ static_cast<size_t>(bytes_transfered)));
read_buffer_.reset(new char[SenderPipe::kPipeSize]);
}
ReadUntilBlocking();
diff --git a/chromium/components/services/heap_profiling/receiver_pipe_win.h b/chromium/components/services/heap_profiling/receiver_pipe_win.h
index 9612c7adb2d..cd6adfb3fbd 100644
--- a/chromium/components/services/heap_profiling/receiver_pipe_win.h
+++ b/chromium/components/services/heap_profiling/receiver_pipe_win.h
@@ -21,7 +21,7 @@ namespace heap_profiling {
class ReceiverPipe : public ReceiverPipeBase,
public base::MessagePumpForIO::IOHandler {
public:
- explicit ReceiverPipe(mojo::edk::ScopedPlatformHandle handle);
+ explicit ReceiverPipe(mojo::edk::ScopedInternalPlatformHandle handle);
// Must be called on the IO thread.
void StartReadingOnIOThread();
diff --git a/chromium/components/services/leveldb/BUILD.gn b/chromium/components/services/leveldb/BUILD.gn
index e69401ec9b5..7fc6bd01c7c 100644
--- a/chromium/components/services/leveldb/BUILD.gn
+++ b/chromium/components/services/leveldb/BUILD.gn
@@ -27,7 +27,6 @@ static_library("lib") {
]
deps = [
- "//mojo/common",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
"//third_party/leveldatabase",
@@ -44,7 +43,6 @@ service("leveldb") {
deps = [
":lib",
"//components/services/leveldb/public/interfaces",
- "//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
@@ -70,7 +68,6 @@ service_test("leveldb_service_unittests") {
"//components/services/filesystem/public/interfaces",
"//components/services/leveldb/public/cpp",
"//components/services/leveldb/public/interfaces",
- "//mojo/common",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
diff --git a/chromium/components/services/leveldb/DEPS b/chromium/components/services/leveldb/DEPS
index 048eb8af426..031b4cc4a72 100644
--- a/chromium/components/services/leveldb/DEPS
+++ b/chromium/components/services/leveldb/DEPS
@@ -1,6 +1,5 @@
include_rules = [
"+components/services/filesystem/public/interfaces",
- "+mojo/common",
"+mojo/public",
"+mojo/util",
"+services/service_manager",
diff --git a/chromium/components/services/leveldb/leveldb_service_impl.cc b/chromium/components/services/leveldb/leveldb_service_impl.cc
index 7e4c61283f8..f1fd13a93c7 100644
--- a/chromium/components/services/leveldb/leveldb_service_impl.cc
+++ b/chromium/components/services/leveldb/leveldb_service_impl.cc
@@ -7,6 +7,7 @@
#include <memory>
#include <utility>
+#include "base/sequenced_task_runner.h"
#include "components/services/leveldb/env_mojo.h"
#include "components/services/leveldb/leveldb_database_impl.h"
#include "components/services/leveldb/public/cpp/util.h"
@@ -74,14 +75,14 @@ void LevelDBServiceImpl::OpenWithOptions(
void LevelDBServiceImpl::OpenInMemory(
const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
+ const std::string& tracking_name,
leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
OpenCallback callback) {
leveldb_env::Options options;
options.create_if_missing = true;
options.max_open_files = 0; // Use minimum.
- std::unique_ptr<leveldb::Env> env(
- leveldb_chrome::NewMemEnv(leveldb::Env::Default()));
+ auto env = leveldb_chrome::NewMemEnv(tracking_name);
options.env = env.get();
std::unique_ptr<leveldb::DB> db;
diff --git a/chromium/components/services/leveldb/leveldb_service_impl.h b/chromium/components/services/leveldb/leveldb_service_impl.h
index 8eb0ebf7ba6..9deb661648d 100644
--- a/chromium/components/services/leveldb/leveldb_service_impl.h
+++ b/chromium/components/services/leveldb/leveldb_service_impl.h
@@ -43,6 +43,7 @@ class LevelDBServiceImpl : public mojom::LevelDBService {
void OpenInMemory(
const base::Optional<base::trace_event::MemoryAllocatorDumpGuid>&
memory_dump_id,
+ const std::string& tracking_name,
leveldb::mojom::LevelDBDatabaseAssociatedRequest database,
OpenInMemoryCallback callback) override;
void Destroy(filesystem::mojom::DirectoryPtr directory,
diff --git a/chromium/components/services/leveldb/leveldb_service_unittest.cc b/chromium/components/services/leveldb/leveldb_service_unittest.cc
index 514144ee839..8f6f8b1b0e7 100644
--- a/chromium/components/services/leveldb/leveldb_service_unittest.cc
+++ b/chromium/components/services/leveldb/leveldb_service_unittest.cc
@@ -108,7 +108,7 @@ void LevelDBSyncOpenInMemory(mojom::LevelDBService* leveldb,
mojom::LevelDBDatabaseAssociatedRequest database,
mojom::DatabaseError* out_error) {
base::RunLoop run_loop;
- leveldb->OpenInMemory(base::nullopt, std::move(database),
+ leveldb->OpenInMemory(base::nullopt, "LevelDBSync", std::move(database),
Capture(out_error, run_loop.QuitClosure()));
run_loop.Run();
}
diff --git a/chromium/components/services/leveldb/manifest.json b/chromium/components/services/leveldb/manifest.json
index 2b5c39a2c8f..41102cc4aef 100644
--- a/chromium/components/services/leveldb/manifest.json
+++ b/chromium/components/services/leveldb/manifest.json
@@ -5,7 +5,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "leveldb:leveldb": [ "leveldb::mojom::LevelDBService" ]
+ "leveldb:leveldb": [ "leveldb.mojom.LevelDBService" ]
},
"requires": {
"*": [ "app" ]
diff --git a/chromium/components/services/leveldb/public/cpp/BUILD.gn b/chromium/components/services/leveldb/public/cpp/BUILD.gn
index b43e96d8c55..aab9403a9ab 100644
--- a/chromium/components/services/leveldb/public/cpp/BUILD.gn
+++ b/chromium/components/services/leveldb/public/cpp/BUILD.gn
@@ -13,7 +13,6 @@ static_library("cpp") {
deps = [
"//base",
"//components/services/leveldb/public/interfaces",
- "//mojo/common",
"//services/service_manager/public/cpp",
"//third_party/leveldatabase",
]
diff --git a/chromium/components/services/leveldb/public/cpp/util.cc b/chromium/components/services/leveldb/public/cpp/util.cc
index 63c36bd1dd7..0bcdcfe4309 100644
--- a/chromium/components/services/leveldb/public/cpp/util.cc
+++ b/chromium/components/services/leveldb/public/cpp/util.cc
@@ -4,6 +4,7 @@
#include "components/services/leveldb/public/cpp/util.h"
+#include "base/containers/span.h"
#include "third_party/leveldatabase/env_chromium.h"
#include "third_party/leveldatabase/src/include/leveldb/status.h"
@@ -90,4 +91,24 @@ std::vector<uint8_t> StdStringToUint8Vector(const std::string& input) {
return std::vector<uint8_t>(data, data + input.size());
}
+base::StringPiece Uint8VectorToStringPiece(const std::vector<uint8_t>& input) {
+ return base::StringPiece(reinterpret_cast<const char*>(input.data()),
+ input.size());
+}
+
+std::vector<uint8_t> StringPieceToUint8Vector(base::StringPiece input) {
+ base::span<const uint8_t> data = base::as_bytes(base::make_span(input));
+ return std::vector<uint8_t>(data.begin(), data.end());
+}
+
+base::string16 Uint8VectorToString16(const std::vector<uint8_t>& input) {
+ return base::string16(reinterpret_cast<const base::char16*>(input.data()),
+ input.size() * sizeof(base::char16) / sizeof(uint8_t));
+}
+
+std::vector<uint8_t> String16ToUint8Vector(const base::string16& input) {
+ base::span<const uint8_t> data = base::as_bytes(base::make_span(input));
+ return std::vector<uint8_t>(data.begin(), data.end());
+}
+
} // namespace leveldb
diff --git a/chromium/components/services/leveldb/public/cpp/util.h b/chromium/components/services/leveldb/public/cpp/util.h
index 9c1a71890bb..1986f37af8d 100644
--- a/chromium/components/services/leveldb/public/cpp/util.h
+++ b/chromium/components/services/leveldb/public/cpp/util.h
@@ -5,6 +5,10 @@
#ifndef COMPONENTS_SERVICES_LEVELDB_PUBLIC_CPP_UTIL_H_
#define COMPONENTS_SERVICES_LEVELDB_PUBLIC_CPP_UTIL_H_
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
#include "components/services/leveldb/public/interfaces/leveldb.mojom.h"
#include "third_party/leveldatabase/env_chromium.h"
@@ -39,6 +43,15 @@ std::string Uint8VectorToStdString(const std::vector<uint8_t>& input);
std::vector<uint8_t> StdStringToUint8Vector(const std::string& input);
+base::StringPiece Uint8VectorToStringPiece(const std::vector<uint8_t>& input);
+
+std::vector<uint8_t> StringPieceToUint8Vector(base::StringPiece input);
+
+// The input size MUST be divisable by 2.
+base::string16 Uint8VectorToString16(const std::vector<uint8_t>& input);
+
+std::vector<uint8_t> String16ToUint8Vector(const base::string16& input);
+
} // namespace leveldb
#endif // COMPONENTS_SERVICES_LEVELDB_PUBLIC_CPP_UTIL_H_
diff --git a/chromium/components/services/leveldb/public/interfaces/leveldb.mojom b/chromium/components/services/leveldb/public/interfaces/leveldb.mojom
index cb359133061..ab3312a6f46 100644
--- a/chromium/components/services/leveldb/public/interfaces/leveldb.mojom
+++ b/chromium/components/services/leveldb/public/interfaces/leveldb.mojom
@@ -91,8 +91,10 @@ interface LevelDBService {
associated LevelDBDatabase& database) => (DatabaseError status);
// Opens a database stored purely in memory.
+ // "tracking_name" will be used for memory-infra reporting to associate memory
+ // use with its origin.
OpenInMemory(mojo_base.mojom.MemoryAllocatorDumpCrossProcessUid?
- memory_dump_id,
+ memory_dump_id, string tracking_name,
associated LevelDBDatabase& database) => (DatabaseError status);
// Destroys the contents of the specified database. Returns OK if the database
diff --git a/chromium/components/services/leveldb/remote_iterator_unittest.cc b/chromium/components/services/leveldb/remote_iterator_unittest.cc
index e7637364e47..34e75b71485 100644
--- a/chromium/components/services/leveldb/remote_iterator_unittest.cc
+++ b/chromium/components/services/leveldb/remote_iterator_unittest.cc
@@ -52,7 +52,8 @@ class RemoteIteratorTest : public service_manager::test::ServiceTest {
mojom::DatabaseError error;
base::RunLoop run_loop;
- leveldb()->OpenInMemory(base::nullopt, MakeRequest(&database_),
+ leveldb()->OpenInMemory(base::nullopt, "RemoteIteratorTest",
+ MakeRequest(&database_),
Capture(&error, run_loop.QuitClosure()));
run_loop.Run();
EXPECT_EQ(mojom::DatabaseError::OK, error);
diff --git a/chromium/components/services/patch/manifest.json b/chromium/components/services/patch/manifest.json
index 5afcc10927e..f69b1a237e5 100644
--- a/chromium/components/services/patch/manifest.json
+++ b/chromium/components/services/patch/manifest.json
@@ -5,7 +5,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "patch_file": [ "patch::mojom::FilePatcher" ]
+ "patch_file": [ "patch.mojom.FilePatcher" ]
},
"requires": {
"service_manager": [ "service_manager:all_users" ]
diff --git a/chromium/components/printing/service/BUILD.gn b/chromium/components/services/pdf_compositor/BUILD.gn
index 6f7b8af6547..32b899386c2 100644
--- a/chromium/components/printing/service/BUILD.gn
+++ b/chromium/components/services/pdf_compositor/BUILD.gn
@@ -7,7 +7,7 @@ import("//services/service_manager/public/cpp/service.gni")
import("//services/service_manager/public/service_manifest.gni")
import("//services/service_manager/public/tools/test/service_test.gni")
-static_library("service") {
+static_library("pdf_compositor") {
sources = [
"pdf_compositor_impl.cc",
"pdf_compositor_impl.h",
@@ -24,13 +24,14 @@ static_library("service") {
"//content/public/common:service_names",
"//content/public/utility",
"//printing/common",
+ "//services/ui/public/interfaces",
"//skia",
"//third_party/blink/public:blink_headers",
]
public_deps = [
- "//components/printing/service/public/cpp:utils",
- "//components/printing/service/public/interfaces",
+ "//components/services/pdf_compositor/public/cpp:utils",
+ "//components/services/pdf_compositor/public/interfaces",
"//services/service_manager/public/cpp",
]
}
@@ -40,7 +41,7 @@ service_manifest("pdf_compositor_manifest") {
source = "pdf_compositor_manifest.json"
}
-if (enable_basic_printing || enable_print_preview) {
+if (enable_basic_printing) {
source_set("unit_tests") {
testonly = true
sources = [
@@ -54,12 +55,11 @@ if (enable_basic_printing || enable_print_preview) {
"//third_party/skia/include/core",
]
deps = [
- ":service",
+ ":pdf_compositor",
"//base/test:test_support",
"//cc/paint:paint",
"//components/crash/core/common:crash_key",
- "//components/printing/service/public/interfaces",
- "//mojo/common",
+ "//components/services/pdf_compositor/public/interfaces",
"//services/service_manager/public/cpp:service_test_support",
"//skia",
"//testing/gmock",
diff --git a/chromium/components/printing/service/DEPS b/chromium/components/services/pdf_compositor/DEPS
index f050f3531cc..952a2798ac8 100644
--- a/chromium/components/printing/service/DEPS
+++ b/chromium/components/services/pdf_compositor/DEPS
@@ -3,12 +3,15 @@ include_rules = [
"+components/crash/core/common/crash_key.h",
"+components/discardable_memory/client",
"+content/public/child", # Windows direct write proxy access.
+ "+content/public/common",
"+content/public/utility",
"+mojo/public/cpp",
"+printing/common",
"+services/service_manager/public/cpp",
"+services/service_manager/public/mojom",
+ "+services/ui/public/interfaces/constants.mojom.h", # UI service name.
"+skia",
"+third_party/skia",
"+third_party/blink/public/platform", # Test web sandbox support.
+ "+ui/base/ui_base_features.h", # UI features.
]
diff --git a/chromium/components/printing/service/OWNERS b/chromium/components/services/pdf_compositor/OWNERS
index c44174f6ef4..3fb8863170f 100644
--- a/chromium/components/printing/service/OWNERS
+++ b/chromium/components/services/pdf_compositor/OWNERS
@@ -1,3 +1,5 @@
+file://printing/OWNERS
+
per-file pdf_compositor_manifest.json=set noparent
per-file pdf_compositor_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/printing/service/README.md b/chromium/components/services/pdf_compositor/README.md
index 6ce9c170a85..6ce9c170a85 100644
--- a/chromium/components/printing/service/README.md
+++ b/chromium/components/services/pdf_compositor/README.md
diff --git a/chromium/components/printing/service/pdf_compositor_impl.cc b/chromium/components/services/pdf_compositor/pdf_compositor_impl.cc
index 387e8334267..072a78b90ec 100644
--- a/chromium/components/printing/service/pdf_compositor_impl.cc
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_impl.cc
@@ -2,16 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/printing/service/pdf_compositor_impl.h"
+#include "components/services/pdf_compositor/pdf_compositor_impl.h"
+#include <algorithm>
#include <tuple>
+#include <utility>
#include "base/logging.h"
#include "base/memory/shared_memory_handle.h"
#include "base/stl_util.h"
#include "components/crash/core/common/crash_key.h"
-#include "components/printing/service/public/cpp/pdf_service_mojo_types.h"
-#include "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "printing/common/pdf_metafile_utils.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -197,7 +199,7 @@ mojom::PdfCompositor::Status PdfCompositorImpl::CompositeToPdf(
base::Optional<uint32_t> page_num,
std::unique_ptr<base::SharedMemory> shared_mem,
const ContentToFrameMap& subframe_content_map,
- mojo::ScopedSharedBufferHandle* handle) {
+ base::ReadOnlySharedMemoryRegion* region) {
DeserializationContext subframes =
GetDeserializationContext(subframe_content_map);
@@ -226,14 +228,15 @@ mojom::PdfCompositor::Status PdfCompositorImpl::CompositeToPdf(
}
doc->close();
- *handle = mojo::SharedBufferHandle::Create(wstream.bytesWritten());
- DCHECK((*handle).is_valid());
-
- mojo::ScopedSharedBufferMapping mapping =
- (*handle)->Map(wstream.bytesWritten());
- DCHECK(mapping);
- wstream.copyToAndReset(mapping.get());
+ base::MappedReadOnlyRegion region_mapping =
+ CreateReadOnlySharedMemoryRegion(wstream.bytesWritten());
+ if (!region_mapping.IsValid()) {
+ DLOG(ERROR) << "CompositeToPdf: Cannot create new shared memory region.";
+ return mojom::PdfCompositor::Status::HANDLE_MAP_ERROR;
+ }
+ wstream.copyToAndReset(region_mapping.mapping.memory());
+ *region = std::move(region_mapping.region);
return mojom::PdfCompositor::Status::SUCCESS;
}
@@ -282,11 +285,11 @@ void PdfCompositorImpl::FulfillRequest(
std::unique_ptr<base::SharedMemory> serialized_content,
const ContentToFrameMap& subframe_content_map,
CompositeToPdfCallback callback) {
- mojo::ScopedSharedBufferHandle handle;
+ base::ReadOnlySharedMemoryRegion region;
auto status =
CompositeToPdf(frame_guid, page_num, std::move(serialized_content),
- subframe_content_map, &handle);
- std::move(callback).Run(status, std::move(handle));
+ subframe_content_map, &region);
+ std::move(callback).Run(status, std::move(region));
}
PdfCompositorImpl::FrameContentInfo::FrameContentInfo(
diff --git a/chromium/components/printing/service/pdf_compositor_impl.h b/chromium/components/services/pdf_compositor/pdf_compositor_impl.h
index 72960244de0..4fe2d80a040 100644
--- a/chromium/components/printing/service/pdf_compositor_impl.h
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_impl.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 COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_
-#define COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_
+#ifndef COMPONENTS_SERVICES_PDF_COMPOSITOR_PDF_COMPOSITOR_IMPL_H_
+#define COMPONENTS_SERVICES_PDF_COMPOSITOR_PDF_COMPOSITOR_IMPL_H_
#include <map>
#include <memory>
@@ -13,12 +13,12 @@
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/shared_memory.h"
#include "base/optional.h"
-#include "components/printing/service/public/cpp/pdf_service_mojo_types.h"
-#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
-#include "mojo/public/cpp/system/buffer.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h"
+#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -57,7 +57,7 @@ class PdfCompositorImpl : public mojom::PdfCompositor {
// mojom::PdfCompositor::CompositeDocumentToPdfCallback.
using CompositeToPdfCallback =
base::OnceCallback<void(PdfCompositor::Status,
- mojo::ScopedSharedBufferHandle)>;
+ base::ReadOnlySharedMemoryRegion)>;
// Make this function virtual so tests can override it.
virtual void FulfillRequest(
@@ -164,7 +164,7 @@ class PdfCompositorImpl : public mojom::PdfCompositor {
base::Optional<uint32_t> page_num,
std::unique_ptr<base::SharedMemory> shared_mem,
const ContentToFrameMap& subframe_content_map,
- mojo::ScopedSharedBufferHandle* handle);
+ base::ReadOnlySharedMemoryRegion* region);
// Composite the content of a subframe.
sk_sp<SkPicture> CompositeSubframe(uint64_t frame_guid);
@@ -188,4 +188,4 @@ class PdfCompositorImpl : public mojom::PdfCompositor {
} // namespace printing
-#endif // COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_IMPL_H_
+#endif // COMPONENTS_SERVICES_PDF_COMPOSITOR_PDF_COMPOSITOR_IMPL_H_
diff --git a/chromium/components/printing/service/pdf_compositor_impl_unittest.cc b/chromium/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc
index f2b24b99004..cc68640562c 100644
--- a/chromium/components/printing/service/pdf_compositor_impl_unittest.cc
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_impl_unittest.cc
@@ -3,13 +3,14 @@
// found in the LICENSE file.
#include <memory>
+#include <utility>
#include "base/callback.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "components/crash/core/common/crash_key.h"
-#include "components/printing/service/pdf_compositor_impl.h"
-#include "components/printing/service/public/cpp/pdf_service_mojo_types.h"
+#include "components/services/pdf_compositor/pdf_compositor_impl.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -52,7 +53,7 @@ class PdfCompositorImplTest : public testing::Test {
}
void OnCompositeToPdfCallback(mojom::PdfCompositor::Status status,
- mojo::ScopedSharedBufferHandle handle) {
+ base::ReadOnlySharedMemoryRegion region) {
// A stub for testing, no implementation.
}
diff --git a/chromium/components/printing/service/pdf_compositor_manifest.json b/chromium/components/services/pdf_compositor/pdf_compositor_manifest.json
index 6e3443f5379..ecbad4346d6 100644
--- a/chromium/components/printing/service/pdf_compositor_manifest.json
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_manifest.json
@@ -5,12 +5,13 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "compositor": [ "printing::mojom::PdfCompositor" ]
+ "compositor": [ "printing.mojom.PdfCompositor" ]
},
"requires": {
"*": [ "app" ],
"content_browser": [ "font_loader" ],
- "service_manager": [ "service_manager:all_users" ]
+ "service_manager": [ "service_manager:all_users" ],
+ "ui": [ "discardable_memory" ]
}
}
}
diff --git a/chromium/components/printing/service/pdf_compositor_service.cc b/chromium/components/services/pdf_compositor/pdf_compositor_service.cc
index 867e55c6161..e71b72ab482 100644
--- a/chromium/components/printing/service/pdf_compositor_service.cc
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_service.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/printing/service/pdf_compositor_service.h"
+#include "components/services/pdf_compositor/pdf_compositor_service.h"
#include <utility>
@@ -11,13 +11,15 @@
#include "base/lazy_instance.h"
#include "base/memory/discardable_memory.h"
#include "build/build_config.h"
-#include "components/printing/service/pdf_compositor_impl.h"
-#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#include "components/services/pdf_compositor/pdf_compositor_impl.h"
+#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
#include "content/public/common/service_names.mojom.h"
#include "content/public/utility/utility_thread.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service_context.h"
+#include "services/ui/public/interfaces/constants.mojom.h"
+#include "ui/base/ui_base_features.h"
#if defined(OS_WIN)
#include "content/public/child/dwrite_font_proxy_init_win.h"
@@ -64,8 +66,17 @@ std::unique_ptr<service_manager::Service> PdfCompositorService::Create(
void PdfCompositorService::PrepareToStart() {
// Set up discardable memory manager.
discardable_memory::mojom::DiscardableSharedMemoryManagerPtr manager_ptr;
- context()->connector()->BindInterface(content::mojom::kBrowserServiceName,
- &manager_ptr);
+ if (features::IsMashEnabled()) {
+#if defined(USE_AURA)
+ context()->connector()->BindInterface(ui::mojom::kServiceName,
+ &manager_ptr);
+#else
+ NOTREACHED();
+#endif
+ } else {
+ context()->connector()->BindInterface(content::mojom::kBrowserServiceName,
+ &manager_ptr);
+ }
discardable_shared_memory_manager_ = std::make_unique<
discardable_memory::ClientDiscardableSharedMemoryManager>(
std::move(manager_ptr), content::UtilityThread::Get()->GetIOTaskRunner());
diff --git a/chromium/components/printing/service/pdf_compositor_service.h b/chromium/components/services/pdf_compositor/pdf_compositor_service.h
index 4c1bb5dae00..48ec8fb848d 100644
--- a/chromium/components/printing/service/pdf_compositor_service.h
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_service.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 COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_SERVICE_H_
-#define COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_SERVICE_H_
+#ifndef COMPONENTS_SERVICES_PDF_COMPOSITOR_PDF_COMPOSITOR_SERVICE_H_
+#define COMPONENTS_SERVICES_PDF_COMPOSITOR_PDF_COMPOSITOR_SERVICE_H_
#include <memory>
#include <string>
@@ -11,7 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/discardable_memory/client/client_discardable_shared_memory_manager.h"
-#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
@@ -52,4 +52,4 @@ class PdfCompositorService : public service_manager::Service {
} // namespace printing
-#endif // COMPONENTS_PRINTING_SERVICE_PDF_COMPOSITOR_SERVICE_H_
+#endif // COMPONENTS_SERVICES_PDF_COMPOSITOR_PDF_COMPOSITOR_SERVICE_H_
diff --git a/chromium/components/printing/service/pdf_compositor_service_unittest.cc b/chromium/components/services/pdf_compositor/pdf_compositor_service_unittest.cc
index 98751856f3b..ccdc45dd33d 100644
--- a/chromium/components/printing/service/pdf_compositor_service_unittest.cc
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_service_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <memory>
+#include <utility>
#include "base/callback.h"
#include "base/files/file_path.h"
@@ -13,9 +14,9 @@
#include "base/test/test_discardable_memory_allocator.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/skia_paint_canvas.h"
-#include "components/printing/service/pdf_compositor_service.h"
-#include "components/printing/service/public/cpp/pdf_service_mojo_types.h"
-#include "components/printing/service/public/interfaces/pdf_compositor.mojom.h"
+#include "components/services/pdf_compositor/pdf_compositor_service.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h"
+#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "services/service_manager/public/cpp/binder_registry.h"
@@ -88,12 +89,13 @@ class PdfCompositorServiceTest : public service_manager::test::ServiceTest {
PdfCompositorServiceTest() : ServiceTest("pdf_compositor_service_unittest") {}
~PdfCompositorServiceTest() override {}
- MOCK_METHOD1(CallbackOnCompositeSuccess, void(mojo::SharedBufferHandle));
+ MOCK_METHOD1(CallbackOnCompositeSuccess,
+ void(const base::ReadOnlySharedMemoryRegion&));
MOCK_METHOD1(CallbackOnCompositeStatus, void(mojom::PdfCompositor::Status));
void OnCompositeToPdfCallback(mojom::PdfCompositor::Status status,
- mojo::ScopedSharedBufferHandle handle) {
+ base::ReadOnlySharedMemoryRegion region) {
if (status == mojom::PdfCompositor::Status::SUCCESS)
- CallbackOnCompositeSuccess(handle.get());
+ CallbackOnCompositeSuccess(region);
else
CallbackOnCompositeStatus(status);
run_loop_->Quit();
@@ -141,7 +143,7 @@ class PdfCompositorServiceTest : public service_manager::test::ServiceTest {
size_t len = stream.bytesWritten();
base::MappedReadOnlyRegion memory =
base::ReadOnlySharedMemoryRegion::Create(len);
- CHECK(memory.mapping.IsValid());
+ CHECK(memory.IsValid());
stream.copyTo(memory.mapping.memory());
return mojo::WrapReadOnlySharedMemoryRegion(std::move(memory.region));
}
diff --git a/chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json b/chromium/components/services/pdf_compositor/pdf_compositor_service_unittest_manifest.json
index 02be317f208..19a847f67ce 100644
--- a/chromium/components/printing/service/pdf_compositor_service_unittest_manifest.json
+++ b/chromium/components/services/pdf_compositor/pdf_compositor_service_unittest_manifest.json
@@ -5,7 +5,7 @@
"service_manager:connector": {
"provides": {
"service_manager:service_factory": [
- "service_manager::mojom::ServiceFactory"
+ "service_manager.mojom.ServiceFactory"
]
},
"requires": {
diff --git a/chromium/components/printing/service/public/cpp/BUILD.gn b/chromium/components/services/pdf_compositor/public/cpp/BUILD.gn
index dc0e09d66ca..414da314966 100644
--- a/chromium/components/printing/service/public/cpp/BUILD.gn
+++ b/chromium/components/services/pdf_compositor/public/cpp/BUILD.gn
@@ -11,13 +11,13 @@ source_set("factory") {
]
deps = [
- "//components/printing/service/",
+ "//components/services/pdf_compositor/",
"//content/public/common",
"//content/public/utility",
]
public_deps = [
- "//components/printing/service/public/interfaces",
+ "//components/services/pdf_compositor/public/interfaces",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc b/chromium/components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.cc
index 62b038dfcd2..0af223b62b1 100644
--- a/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.cc
+++ b/chromium/components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.cc
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/printing/service/public/cpp/pdf_compositor_service_factory.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.h"
#include "build/build_config.h"
-#include "components/printing/service/pdf_compositor_service.h"
+#include "components/services/pdf_compositor/pdf_compositor_service.h"
#include "content/public/utility/utility_thread.h"
#include "third_party/blink/public/platform/web_image_generator.h"
#include "third_party/skia/include/core/SkGraphics.h"
diff --git a/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.h b/chromium/components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.h
index 10d06bab09b..371f47294a0 100644
--- a/chromium/components/printing/service/public/cpp/pdf_compositor_service_factory.h
+++ b/chromium/components/services/pdf_compositor/public/cpp/pdf_compositor_service_factory.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 COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_
-#define COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_
+#ifndef COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_
+#define COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_
#include <memory>
#include <string>
@@ -17,4 +17,4 @@ std::unique_ptr<service_manager::Service> CreatePdfCompositorService(
} // namespace printing
-#endif // COMPONENTS_PRINTING_SERVICE_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_
+#endif // COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_COMPOSITOR_SERVICE_FACTORY_H_
diff --git a/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h b/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h
new file mode 100644
index 00000000000..dfc3b5f8e15
--- /dev/null
+++ b/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_types.h
@@ -0,0 +1,17 @@
+// 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 COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_SERVICE_MOJO_TYPES_H_
+#define COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_SERVICE_MOJO_TYPES_H_
+
+#include "base/containers/flat_map.h"
+
+namespace printing {
+
+// Create an alias for map<uint32, uint64> type.
+using ContentToFrameMap = base::flat_map<uint32_t, uint64_t>;
+
+} // namespace printing
+
+#endif // COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_SERVICE_MOJO_TYPES_H_
diff --git a/chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.cc b/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.cc
index 01ec77f7a67..b814cf60dfe 100644
--- a/chromium/components/printing/service/public/cpp/pdf_service_mojo_utils.cc
+++ b/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.cc
@@ -2,16 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/printing/service/public/cpp/pdf_service_mojo_utils.h"
+#include "components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.h"
#include <utility>
-#include "base/memory/ref_counted_memory.h"
#include "base/memory/shared_memory.h"
+#include "base/memory/writable_shared_memory_region.h"
#include "mojo/public/cpp/system/platform_handle.h"
namespace printing {
+base::MappedReadOnlyRegion CreateReadOnlySharedMemoryRegion(size_t size) {
+ mojo::ScopedSharedBufferHandle handle =
+ mojo::SharedBufferHandle::Create(size);
+ base::WritableSharedMemoryRegion writable_region =
+ UnwrapWritableSharedMemoryRegion(std::move(handle));
+ base::WritableSharedMemoryMapping mapping = writable_region.Map();
+ if (!mapping.IsValid())
+ return {};
+
+ base::ReadOnlySharedMemoryRegion readonly_region =
+ base::WritableSharedMemoryRegion::ConvertToReadOnly(
+ std::move(writable_region));
+ return {std::move(readonly_region), std::move(mapping)};
+}
+
std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
mojo::ScopedSharedBufferHandle handle) {
base::SharedMemoryHandle memory_handle;
@@ -35,16 +50,4 @@ std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
return shm;
}
-scoped_refptr<base::RefCountedMemory> GetDataFromMojoHandle(
- mojo::ScopedSharedBufferHandle handle) {
- std::unique_ptr<base::SharedMemory> shm =
- GetShmFromMojoHandle(std::move(handle));
- if (!shm)
- return nullptr;
-
- size_t size = shm->mapped_size();
- return base::MakeRefCounted<base::RefCountedSharedMemory>(std::move(shm),
- size);
-}
-
} // namespace printing
diff --git a/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.h b/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.h
new file mode 100644
index 00000000000..1e0bd92fe1e
--- /dev/null
+++ b/chromium/components/services/pdf_compositor/public/cpp/pdf_service_mojo_utils.h
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
+#define COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
+
+#include <memory>
+
+#include "base/memory/read_only_shared_memory_region.h"
+#include "mojo/public/cpp/system/buffer.h"
+
+namespace base {
+class SharedMemory;
+} // namespace base
+
+namespace printing {
+
+// Similar to base::ReadOnlySharedMemoryRegion::Create(), except it works inside
+// sandboxed environments.
+base::MappedReadOnlyRegion CreateReadOnlySharedMemoryRegion(size_t size);
+
+std::unique_ptr<base::SharedMemory> GetShmFromMojoHandle(
+ mojo::ScopedSharedBufferHandle handle);
+
+} // namespace printing
+
+#endif // COMPONENTS_SERVICES_PDF_COMPOSITOR_PUBLIC_CPP_PDF_SERVICE_MOJO_UTILS_H_
diff --git a/chromium/components/printing/service/public/interfaces/BUILD.gn b/chromium/components/services/pdf_compositor/public/interfaces/BUILD.gn
index b9162a6367c..804ccb4a828 100644
--- a/chromium/components/printing/service/public/interfaces/BUILD.gn
+++ b/chromium/components/services/pdf_compositor/public/interfaces/BUILD.gn
@@ -9,6 +9,7 @@ mojom("interfaces") {
"pdf_compositor.mojom",
]
public_deps = [
+ "//mojo/public/mojom/base",
"//url/mojom:url_mojom_gurl",
]
}
diff --git a/chromium/components/printing/service/public/interfaces/OWNERS b/chromium/components/services/pdf_compositor/public/interfaces/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/components/printing/service/public/interfaces/OWNERS
+++ b/chromium/components/services/pdf_compositor/public/interfaces/OWNERS
diff --git a/chromium/components/printing/service/public/interfaces/pdf_compositor.mojom b/chromium/components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom
index 202d289a4cd..934b04e83ae 100644
--- a/chromium/components/printing/service/public/interfaces/pdf_compositor.mojom
+++ b/chromium/components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom
@@ -4,6 +4,7 @@
module printing.mojom;
+import "mojo/public/mojom/base/shared_memory.mojom";
import "url/mojom/url.mojom";
const string kServiceName = "pdf_compositor";
@@ -44,14 +45,16 @@ interface PdfCompositor {
CompositePageToPdf(uint64 frame_guid, uint32 page_num,
handle<shared_buffer> sk_handle,
map<uint32, uint64> subframe_content_info)
- => (Status status, handle<shared_buffer>? pdf_handle);
+ => (Status status,
+ mojo_base.mojom.ReadOnlySharedMemoryRegion? pdf_region);
// Requests to composite the entire document and convert it into a PDF file.
// All the arguments carry the same meaning as CompositePageToPdf() above,
// except this call doesn't have |page_num|.
CompositeDocumentToPdf(uint64 frame_guid, handle<shared_buffer> sk_handle,
map<uint32, uint64> subframe_content_info)
- => (Status status, handle<shared_buffer>? pdf_handle);
+ => (Status status,
+ mojo_base.mojom.ReadOnlySharedMemoryRegion? pdf_region);
// Sets the URL which is committed in the main frame of the WebContents,
// for use in crash diagnosis.
diff --git a/chromium/components/services/unzip/manifest.json b/chromium/components/services/unzip/manifest.json
index b21cb3767e7..2cfc345fa3f 100644
--- a/chromium/components/services/unzip/manifest.json
+++ b/chromium/components/services/unzip/manifest.json
@@ -5,7 +5,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "unzip_file": [ "unzip::mojom::Unzipper" ]
+ "unzip_file": [ "unzip.mojom.Unzipper" ]
},
"requires": {
"service_manager": [ "service_manager:all_users" ]
diff --git a/chromium/components/session_manager/BUILD.gn b/chromium/components/session_manager/BUILD.gn
index cb6f68743ef..19b9aeeed3c 100644
--- a/chromium/components/session_manager/BUILD.gn
+++ b/chromium/components/session_manager/BUILD.gn
@@ -9,6 +9,6 @@ source_set("base") {
]
public_deps = [
- "//components/signin/core/account_id",
+ "//components/account_id",
]
}
diff --git a/chromium/components/session_manager/DEPS b/chromium/components/session_manager/DEPS
index e59a6f2ae1a..9c0cd539f1a 100644
--- a/chromium/components/session_manager/DEPS
+++ b/chromium/components/session_manager/DEPS
@@ -1,3 +1,3 @@
include_rules = [
- "+components/signin/core/account_id",
+ "+components/account_id",
]
diff --git a/chromium/components/session_manager/core/BUILD.gn b/chromium/components/session_manager/core/BUILD.gn
index da1cb9bbf92..8287824fa21 100644
--- a/chromium/components/session_manager/core/BUILD.gn
+++ b/chromium/components/session_manager/core/BUILD.gn
@@ -10,8 +10,8 @@ component("core") {
]
deps = [
"//base",
+ "//components/account_id",
"//components/session_manager:base",
- "//components/signin/core/account_id",
"//components/user_manager",
"//skia",
]
diff --git a/chromium/components/session_manager/session_manager_types.h b/chromium/components/session_manager/session_manager_types.h
index 43191ff9579..0c10be0a755 100644
--- a/chromium/components/session_manager/session_manager_types.h
+++ b/chromium/components/session_manager/session_manager_types.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_SESSION_MANAGER_SESSION_MANAGER_TYPES_H_
#define COMPONENTS_SESSION_MANAGER_SESSION_MANAGER_TYPES_H_
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
namespace session_manager {
diff --git a/chromium/components/sessions/content/content_serialized_navigation_builder.cc b/chromium/components/sessions/content/content_serialized_navigation_builder.cc
index 57944fc57c7..ee523af094d 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_builder.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_builder.cc
@@ -95,7 +95,8 @@ ContentSerializedNavigationBuilder::ToNavigationEntry(
// increase the typed count.
ui::PAGE_TRANSITION_RELOAD, false,
// The extra headers are not sync'ed across sessions.
- std::string(), browser_context));
+ std::string(), browser_context,
+ nullptr /* blob_url_loader_factory */));
entry->SetTitle(navigation->title_);
entry->SetPageState(content::PageState::CreateFromEncodedData(
diff --git a/chromium/components/sessions/content/content_serialized_navigation_driver.cc b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
index 4e37fe884d5..d832666bd42 100644
--- a/chromium/components/sessions/content/content_serialized_navigation_driver.cc
+++ b/chromium/components/sessions/content/content_serialized_navigation_driver.cc
@@ -81,7 +81,7 @@ void ContentSerializedNavigationDriver::RegisterExtendedInfoHandler(
std::unique_ptr<ExtendedInfoHandler> handler) {
DCHECK(!key.empty());
DCHECK(!extended_info_handler_map_.count(key));
- DCHECK(handler.get());
+ DCHECK(handler);
extended_info_handler_map_[key] = std::move(handler);
}
diff --git a/chromium/components/sessions/core/base_session_service.cc b/chromium/components/sessions/core/base_session_service.cc
index 3e76628e6a2..df7d44bb09e 100644
--- a/chromium/components/sessions/core/base_session_service.cc
+++ b/chromium/components/sessions/core/base_session_service.cc
@@ -59,7 +59,7 @@ BaseSessionService::BaseSessionService(SessionType type,
{base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
weak_factory_(this) {
backend_ = new SessionBackend(type, path);
- DCHECK(backend_.get());
+ DCHECK(backend_);
}
BaseSessionService::~BaseSessionService() {}
diff --git a/chromium/components/sessions/core/base_session_service_commands.cc b/chromium/components/sessions/core/base_session_service_commands.cc
index b6029a7f941..42b1e9d7549 100644
--- a/chromium/components/sessions/core/base_session_service_commands.cc
+++ b/chromium/components/sessions/core/base_session_service_commands.cc
@@ -123,7 +123,7 @@ bool RestoreUpdateTabNavigationCommand(
sessions::SerializedNavigationEntry* navigation,
SessionID* tab_id) {
std::unique_ptr<base::Pickle> pickle(command.PayloadAsPickle());
- if (!pickle.get())
+ if (!pickle)
return false;
base::PickleIterator iterator(*pickle);
return ReadSessionIdFromPickle(&iterator, tab_id) &&
@@ -134,7 +134,7 @@ bool RestoreSetTabExtensionAppIDCommand(const SessionCommand& command,
SessionID* tab_id,
std::string* extension_app_id) {
std::unique_ptr<base::Pickle> pickle(command.PayloadAsPickle());
- if (!pickle.get())
+ if (!pickle)
return false;
base::PickleIterator iterator(*pickle);
@@ -146,7 +146,7 @@ bool RestoreSetTabUserAgentOverrideCommand(const SessionCommand& command,
SessionID* tab_id,
std::string* user_agent_override) {
std::unique_ptr<base::Pickle> pickle(command.PayloadAsPickle());
- if (!pickle.get())
+ if (!pickle)
return false;
base::PickleIterator iterator(*pickle);
@@ -158,7 +158,7 @@ bool RestoreSetWindowAppNameCommand(const SessionCommand& command,
SessionID* window_id,
std::string* app_name) {
std::unique_ptr<base::Pickle> pickle(command.PayloadAsPickle());
- if (!pickle.get())
+ if (!pickle)
return false;
base::PickleIterator iterator(*pickle);
diff --git a/chromium/components/sessions/core/persistent_tab_restore_service.cc b/chromium/components/sessions/core/persistent_tab_restore_service.cc
index f46f5878adb..7c14b49384b 100644
--- a/chromium/components/sessions/core/persistent_tab_restore_service.cc
+++ b/chromium/components/sessions/core/persistent_tab_restore_service.cc
@@ -237,7 +237,7 @@ CreateWindowEntryFromCommand(const SessionCommand* command,
if (command->id() == kCommandWindow) {
std::unique_ptr<base::Pickle> pickle(command->PayloadAsPickle());
- if (!pickle.get())
+ if (!pickle)
return nullptr;
base::PickleIterator it(*pickle);
diff --git a/chromium/components/sessions/core/session_backend.cc b/chromium/components/sessions/core/session_backend.cc
index 07a807f942b..41936d7230c 100644
--- a/chromium/components/sessions/core/session_backend.cc
+++ b/chromium/components/sessions/core/session_backend.cc
@@ -222,7 +222,7 @@ void SessionBackend::AppendCommands(
Init();
// Make sure and check current_session_file_, if opening the file failed
// current_session_file_ will be NULL.
- if ((reset_first && !empty_file_) || !current_session_file_.get() ||
+ if ((reset_first && !empty_file_) || !current_session_file_ ||
!current_session_file_->IsValid()) {
ResetFile();
}
@@ -320,7 +320,7 @@ bool SessionBackend::AppendCommandsToFile(
}
SessionBackend::~SessionBackend() {
- if (current_session_file_.get()) {
+ if (current_session_file_) {
// Destructor performs file IO because file is open in sync mode.
// crbug.com/112512.
base::ThreadRestrictions::ScopedAllowIO allow_io;
@@ -330,7 +330,7 @@ SessionBackend::~SessionBackend() {
void SessionBackend::ResetFile() {
DCHECK(inited_);
- if (current_session_file_.get()) {
+ if (current_session_file_) {
// File is already open, truncate it. We truncate instead of closing and
// reopening to avoid the possibility of scanners locking the file out
// from under us once we close it. If truncation fails, we'll try to
@@ -341,7 +341,7 @@ void SessionBackend::ResetFile() {
!current_session_file_->SetLength(header_size))
current_session_file_.reset(nullptr);
}
- if (!current_session_file_.get())
+ if (!current_session_file_)
current_session_file_.reset(OpenAndWriteHeader(GetCurrentSessionPath()));
empty_file_ = true;
}
diff --git a/chromium/components/sessions/core/session_service_commands.cc b/chromium/components/sessions/core/session_service_commands.cc
index 5d40ee29561..1de12aae6fb 100644
--- a/chromium/components/sessions/core/session_service_commands.cc
+++ b/chromium/components/sessions/core/session_service_commands.cc
@@ -548,7 +548,7 @@ bool CreateTabsAndWindows(
command->PayloadAsPickle());
SessionID::id_type command_tab_id;
std::string session_storage_persistent_id;
- base::PickleIterator iter(*command_pickle.get());
+ base::PickleIterator iter(*command_pickle);
if (!iter.ReadInt(&command_tab_id) ||
!iter.ReadString(&session_storage_persistent_id))
return true;
diff --git a/chromium/components/signin/core/account_id/DEPS b/chromium/components/signin/core/account_id/DEPS
deleted file mode 100644
index 48e88750d4a..00000000000
--- a/chromium/components/signin/core/account_id/DEPS
+++ /dev/null
@@ -1,2 +0,0 @@
-include_rules = [
-]
diff --git a/chromium/components/signin/core/browser/BUILD.gn b/chromium/components/signin/core/browser/BUILD.gn
index 9f7fb37b111..98eed32048c 100644
--- a/chromium/components/signin/core/browser/BUILD.gn
+++ b/chromium/components/signin/core/browser/BUILD.gn
@@ -26,6 +26,9 @@ static_library("account_info") {
"account_info.cc",
"account_info.h",
]
+ deps = [
+ "//components/account_id",
+ ]
}
# Split into its own target to allow browser clients of the Identity Service to
@@ -125,12 +128,12 @@ static_library("browser") {
":signin_buildflags",
":signin_metrics",
"//base",
+ "//components/account_id",
"//components/content_settings/core/browser",
"//components/content_settings/core/common",
"//components/invalidation/public",
"//components/keyed_service/core",
"//components/prefs",
- "//components/signin/core/account_id",
"//google_apis",
"//net",
"//ui/gfx",
@@ -193,6 +196,8 @@ static_library("test_support") {
"fake_signin_manager.h",
"scoped_account_consistency.cc",
"scoped_account_consistency.h",
+ "scoped_unified_consent.cc",
+ "scoped_unified_consent.h",
"test_signin_client.cc",
"test_signin_client.h",
]
diff --git a/chromium/components/signin/core/browser/DEPS b/chromium/components/signin/core/browser/DEPS
index 88087707fcd..c946f6c1aa9 100644
--- a/chromium/components/signin/core/browser/DEPS
+++ b/chromium/components/signin/core/browser/DEPS
@@ -1,4 +1,5 @@
include_rules = [
+ "+components/account_id",
"+components/data_use_measurement/core",
"+components/image_fetcher/core",
"+components/invalidation/public",
diff --git a/chromium/components/signin/core/browser/about_signin_internals.cc b/chromium/components/signin/core/browser/about_signin_internals.cc
index c0ae1ef02d5..b8b2c880cc0 100644
--- a/chromium/components/signin/core/browser/about_signin_internals.cc
+++ b/chromium/components/signin/core/browser/about_signin_internals.cc
@@ -480,7 +480,7 @@ AboutSigninInternals::TokenInfo::ToValue() const {
token_expired = false;
expiration_time_string = "Expiration time not available";
}
- std::string status_str = "";
+ std::string status_str;
if (token_expired)
status_str = "<p style=\"color: #ffffff; background-color: #ff0000\">";
base::StringAppendF(&status_str, "Received token at %s. Expire at %s",
diff --git a/chromium/components/signin/core/browser/account_info.cc b/chromium/components/signin/core/browser/account_info.cc
index 326350ba4c7..0527cdc0f46 100644
--- a/chromium/components/signin/core/browser/account_info.cc
+++ b/chromium/components/signin/core/browser/account_info.cc
@@ -21,16 +21,7 @@ bool UpdateField(bool* field, bool new_value) {
}
}
-AccountInfo::AccountInfo()
- : account_id(),
- gaia(),
- email(),
- full_name(),
- given_name(),
- hosted_domain(),
- locale(),
- picture_url(),
- is_child_account(false) {}
+AccountInfo::AccountInfo() : is_child_account(false) {}
AccountInfo::AccountInfo(const AccountInfo& other) = default;
AccountInfo::~AccountInfo() {}
@@ -63,3 +54,10 @@ bool AccountInfo::UpdateWith(const AccountInfo& other) {
return modified;
}
+
+AccountId AccountInfo::GetAccountId() const {
+ if (IsEmpty())
+ return EmptyAccountId();
+ DCHECK(!email.empty() && !gaia.empty());
+ return AccountId::FromUserEmailGaiaId(email, gaia);
+} \ No newline at end of file
diff --git a/chromium/components/signin/core/browser/account_info.h b/chromium/components/signin/core/browser/account_info.h
index e54e9849229..457c1a15722 100644
--- a/chromium/components/signin/core/browser/account_info.h
+++ b/chromium/components/signin/core/browser/account_info.h
@@ -7,6 +7,8 @@
#include <string>
+#include "components/account_id/account_id.h"
+
// Information about a specific account.
struct AccountInfo {
AccountInfo();
@@ -32,6 +34,9 @@ struct AccountInfo {
// Updates the empty fields of |this| with |other|. Returns whether at least
// one field was updated.
bool UpdateWith(const AccountInfo& other);
+
+ // Returns AccountId populated from the account info.
+ AccountId GetAccountId() const;
};
#endif // COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_INFO_H_
diff --git a/chromium/components/signin/core/browser/account_reconcilor.cc b/chromium/components/signin/core/browser/account_reconcilor.cc
index 46f6ae05c21..8d62b9f3c17 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor.cc
@@ -31,9 +31,6 @@ using signin::AccountReconcilorDelegate;
namespace {
-// String used for source parameter in GAIA cookie manager calls.
-const char kSource[] = "ChromiumAccountReconcilor";
-
class AccountEqualToFunc {
public:
explicit AccountEqualToFunc(const gaia::ListedAccount& account)
@@ -95,7 +92,7 @@ AccountReconcilor::AccountReconcilor(
registered_with_content_settings_(false),
is_reconcile_started_(false),
first_execution_(true),
- error_during_last_reconcile_(false),
+ error_during_last_reconcile_(GoogleServiceAuthError::AuthErrorNone()),
reconcile_is_noop_(true),
chrome_accounts_changed_(false),
account_reconcilor_lock_count_(0),
@@ -213,7 +210,8 @@ void AccountReconcilor::UnregisterWithCookieManagerService() {
signin_metrics::AccountReconcilorState AccountReconcilor::GetState() {
if (!is_reconcile_started_) {
- return error_during_last_reconcile_
+ return (error_during_last_reconcile_.state() !=
+ GoogleServiceAuthError::State::NONE)
? signin_metrics::ACCOUNT_RECONCILOR_ERROR
: signin_metrics::ACCOUNT_RECONCILOR_OK;
}
@@ -273,7 +271,7 @@ void AccountReconcilor::OnAuthErrorChanged(
// This should cover well the Mirror and Desktop Identity Consistency cases as
// the cookies are always bound to the refresh tokens in these cases.
if (error != GoogleServiceAuthError::AuthErrorNone())
- cookie_manager_service_->TriggerListAccounts(kSource);
+ cookie_manager_service_->TriggerListAccounts(delegate_->GetGaiaApiSource());
}
void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
@@ -283,7 +281,8 @@ void AccountReconcilor::PerformMergeAction(const std::string& account_id) {
return;
}
VLOG(1) << "AccountReconcilor::PerformMergeAction: " << account_id;
- cookie_manager_service_->AddAccountToCookie(account_id, kSource);
+ cookie_manager_service_->AddAccountToCookie(account_id,
+ delegate_->GetGaiaApiSource());
}
void AccountReconcilor::PerformLogoutAllAccountsAction() {
@@ -291,7 +290,7 @@ void AccountReconcilor::PerformLogoutAllAccountsAction() {
if (!delegate_->IsAccountConsistencyEnforced())
return;
VLOG(1) << "AccountReconcilor::PerformLogoutAllAccountsAction";
- cookie_manager_service_->LogOutAllAccounts(kSource);
+ cookie_manager_service_->LogOutAllAccounts(delegate_->GetGaiaApiSource());
}
void AccountReconcilor::StartReconcile() {
@@ -318,6 +317,15 @@ void AccountReconcilor::StartReconcile() {
return;
}
+ // Begin reconciliation. Reset initial states.
+ for (auto& observer : observer_list_)
+ observer.OnStartReconcile();
+ add_to_cookie_.clear();
+ reconcile_start_time_ = base::Time::Now();
+ is_reconcile_started_ = true;
+ error_during_last_reconcile_ = GoogleServiceAuthError::AuthErrorNone();
+ reconcile_is_noop_ = true;
+
if (!timeout_.is_max()) {
// This is NOT a repeating callback but to test it, we need a |MockTimer|,
// which mocks |Timer| and not |OneShotTimer|. |Timer| currently does not
@@ -328,26 +336,20 @@ void AccountReconcilor::StartReconcile() {
base::Unretained(this)));
}
- if (token_service_->RefreshTokenHasError(
- signin_manager_->GetAuthenticatedAccountId()) &&
+ const std::string& account_id = signin_manager_->GetAuthenticatedAccountId();
+ if (token_service_->RefreshTokenHasError(account_id) &&
delegate_->ShouldAbortReconcileIfPrimaryHasError()) {
VLOG(1) << "AccountReconcilor::StartReconcile: primary has error, abort.";
+ error_during_last_reconcile_ = token_service_->GetAuthError(account_id);
+ AbortReconcile();
return;
}
- for (auto& observer : observer_list_)
- observer.OnStartReconcile();
- add_to_cookie_.clear();
- reconcile_start_time_ = base::Time::Now();
- is_reconcile_started_ = true;
- error_during_last_reconcile_ = false;
- reconcile_is_noop_ = true;
-
// Rely on the GCMS to manage calls to and responses from ListAccounts.
std::vector<gaia::ListedAccount> accounts;
std::vector<gaia::ListedAccount> signed_out_accounts;
if (cookie_manager_service_->ListAccounts(&accounts, &signed_out_accounts,
- kSource)) {
+ delegate_->GetGaiaApiSource())) {
OnGaiaAccountsInCookieUpdated(
accounts, signed_out_accounts,
GoogleServiceAuthError(GoogleServiceAuthError::NONE));
@@ -405,15 +407,21 @@ void AccountReconcilor::OnGaiaAccountsInCookieUpdated(
if (delegate_->ShouldAbortReconcileIfPrimaryHasError() &&
token_service_->RefreshTokenHasError(primary_account)) {
VLOG(1) << "Primary account has error, abort.";
- is_reconcile_started_ = false;
+ DCHECK(is_reconcile_started_);
+ AbortReconcile();
return;
}
FinishReconcile(primary_account, LoadValidAccountsFromTokenService(),
std::move(verified_gaia_accounts));
} else {
- if (is_reconcile_started_)
- error_during_last_reconcile_ = true;
+ // We may have seen a series of errors during reconciliation. Delegates may
+ // rely on the severity of the last seen error (see |OnReconcileError|) and
+ // hence do not override a persistent error, if we have seen one.
+ if (is_reconcile_started_ &&
+ !error_during_last_reconcile_.IsPersistentError()) {
+ error_during_last_reconcile_ = error;
+ }
AbortReconcile();
}
}
@@ -446,7 +454,7 @@ std::vector<std::string> AccountReconcilor::LoadValidAccountsFromTokenService()
void AccountReconcilor::OnReceivedManageAccountsResponse(
signin::GAIAServiceType service_type) {
if (service_type == signin::GAIA_SERVICE_TYPE_ADDSESSION) {
- cookie_manager_service_->TriggerListAccounts(kSource);
+ cookie_manager_service_->TriggerListAccounts(delegate_->GetGaiaApiSource());
}
}
@@ -457,16 +465,7 @@ void AccountReconcilor::FinishReconcile(
VLOG(1) << "AccountReconcilor::FinishReconcile";
DCHECK(add_to_cookie_.empty());
- std::string first_account = delegate_->GetFirstGaiaAccountForReconcile(
- chrome_accounts, gaia_accounts, primary_account, first_execution_);
- // |first_account| must be in |chrome_accounts|.
- DCHECK(first_account.empty() ||
- (std::find(chrome_accounts.begin(), chrome_accounts.end(),
- first_account) != chrome_accounts.end()));
size_t number_gaia_accounts = gaia_accounts.size();
- bool first_account_mismatch =
- (number_gaia_accounts > 0) && (first_account != gaia_accounts[0].id);
-
// If there are any accounts in the gaia cookie but not in chrome, then
// those accounts need to be removed from the cookie. This means we need
// to blow the cookie away.
@@ -480,6 +479,12 @@ void AccountReconcilor::FinishReconcile(
}
}
+ std::string first_account = delegate_->GetFirstGaiaAccountForReconcile(
+ chrome_accounts, gaia_accounts, primary_account, first_execution_,
+ removed_from_cookie > 0);
+ bool first_account_mismatch =
+ (number_gaia_accounts > 0) && (first_account != gaia_accounts[0].id);
+
bool rebuild_cookie = first_account_mismatch || (removed_from_cookie > 0);
std::vector<gaia::ListedAccount> original_gaia_accounts = gaia_accounts;
if (rebuild_cookie) {
@@ -493,13 +498,18 @@ void AccountReconcilor::FinishReconcile(
if (first_account.empty()) {
DCHECK(!delegate_->ShouldAbortReconcileIfPrimaryHasError());
- // Gaia cookie has been cleared or was already empty.
- DCHECK((first_account_mismatch && rebuild_cookie) ||
- (number_gaia_accounts == 0));
RevokeAllSecondaryTokens(primary_account, chrome_accounts);
} else {
// Create a list of accounts that need to be added to the Gaia cookie.
- add_to_cookie_.push_back(first_account);
+ if (base::ContainsValue(chrome_accounts, first_account)) {
+ add_to_cookie_.push_back(first_account);
+ } else {
+ // If the first account is not empty and not in chrome_accounts, it is
+ // impossible to rebuild it. It must be already the current default
+ // account, and no logout can happen.
+ DCHECK_EQ(gaia_accounts[0].gaia_id, first_account);
+ DCHECK(!rebuild_cookie);
+ }
for (size_t i = 0; i < chrome_accounts.size(); ++i) {
if (chrome_accounts[i] != first_account)
add_to_cookie_.push_back(chrome_accounts[i]);
@@ -544,15 +554,34 @@ void AccountReconcilor::AbortReconcile() {
VLOG(1) << "AccountReconcilor::AbortReconcile: try again later";
add_to_cookie_.clear();
CalculateIfReconcileIsDone();
+
+ DCHECK(!is_reconcile_started_);
+ DCHECK(!timer_->IsRunning());
}
void AccountReconcilor::CalculateIfReconcileIsDone() {
base::TimeDelta duration = base::Time::Now() - reconcile_start_time_;
// Record the duration if reconciliation was underway and now it is over.
if (is_reconcile_started_ && add_to_cookie_.empty()) {
- signin_metrics::LogSigninAccountReconciliationDuration(duration,
- !error_during_last_reconcile_);
+ bool was_last_reconcile_successful =
+ (error_during_last_reconcile_.state() ==
+ GoogleServiceAuthError::State::NONE);
+ signin_metrics::LogSigninAccountReconciliationDuration(
+ duration, was_last_reconcile_successful);
+
+ // Reconciliation has actually finished (and hence stop the timer), but it
+ // may have ended in some failures. Pass this information to the
+ // |delegate_|.
timer_->Stop();
+ if (!was_last_reconcile_successful) {
+ // Note: This is the only call to |OnReconcileError| in this file. We MUST
+ // make sure that we do not call |OnReconcileError| multiple times in the
+ // same reconciliation batch.
+ // The enclosing if-condition |is_reconcile_started_ &&
+ // add_to_cookie_.empty()| represents the halting condition for one batch
+ // of reconciliation.
+ delegate_->OnReconcileError(error_during_last_reconcile_);
+ }
}
is_reconcile_started_ = !add_to_cookie_.empty();
@@ -623,8 +652,13 @@ void AccountReconcilor::OnAddAccountToCookieCompleted(
<< "Error was " << error.ToString();
// Always listens to GaiaCookieManagerService. Only proceed if reconciling.
if (is_reconcile_started_ && MarkAccountAsAddedToCookie(account_id)) {
- if (error.state() != GoogleServiceAuthError::State::NONE)
- error_during_last_reconcile_ = true;
+ // We may have seen a series of errors during reconciliation. Delegates may
+ // rely on the severity of the last seen error (see |OnReconcileError|) and
+ // hence do not override a persistent error, if we have seen one.
+ if (error.state() != GoogleServiceAuthError::State::NONE &&
+ !error_during_last_reconcile_.IsPersistentError()) {
+ error_during_last_reconcile_ = error;
+ }
CalculateIfReconcileIsDone();
ScheduleStartReconcileIfChromeAccountsChanged();
}
@@ -677,7 +711,17 @@ void AccountReconcilor::set_timer_for_testing(
}
void AccountReconcilor::HandleReconcileTimeout() {
+ // A reconciliation was still succesfully in progress but could not complete
+ // in the given time. For a delegate, this is equivalent to a
+ // |GoogleServiceAuthError::State::CONNECTION_FAILED|.
+ if (error_during_last_reconcile_.state() ==
+ GoogleServiceAuthError::State::NONE) {
+ error_during_last_reconcile_ = GoogleServiceAuthError(
+ GoogleServiceAuthError::State::CONNECTION_FAILED);
+ }
+
+ // Will stop reconciliation and inform |delegate_| about
+ // |error_during_last_reconcile_|, through |CalculateIfReconcileIsDone|.
AbortReconcile();
- delegate_->OnReconcileError(
- GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
+ DCHECK(!timer_->IsRunning());
}
diff --git a/chromium/components/signin/core/browser/account_reconcilor.h b/chromium/components/signin/core/browser/account_reconcilor.h
index 7aaed2aec30..8d17ff05150 100644
--- a/chromium/components/signin/core/browser/account_reconcilor.h
+++ b/chromium/components/signin/core/browser/account_reconcilor.h
@@ -159,7 +159,7 @@ class AccountReconcilor : public KeyedService,
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileBadPrimary);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileOnlyOnce);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, Lock);
- FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+ FRIEND_TEST_ALL_PREFIXES(AccountReconcilorMethodParamTest,
StartReconcileWithSessionInfoExpiredDefault);
FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
AddAccountToCookieCompletedWithBogusAccount);
@@ -271,8 +271,15 @@ class AccountReconcilor : public KeyedService,
// True iff this is the first time the reconcilor is executing.
bool first_execution_;
- // True iff an error occured during the last attempt to reconcile.
- bool error_during_last_reconcile_;
+ // 'Most severe' error encountered during the last attempt to reconcile. If
+ // the last reconciliation attempt was successful, this will be
+ // |GoogleServiceAuthError::State::NONE|.
+ // Severity of an error is defined on the basis of
+ // |GoogleServiceAuthError::IsPersistentError()| only, i.e. any persistent
+ // error is considered more severe than all non-persistent errors, but
+ // persistent (or non-persistent) errors do not have an internal severity
+ // ordering among themselves.
+ GoogleServiceAuthError error_during_last_reconcile_;
// Used for Dice migration: migration can happen if the accounts are
// consistent, which is indicated by reconcile being a no-op.
@@ -292,7 +299,13 @@ class AccountReconcilor : public KeyedService,
base::ObserverList<Observer, true> observer_list_;
// A timer to set off reconciliation timeout handlers, if account
- // reconciliation does not happen in a given timeout duration.
+ // reconciliation does not happen in a given |timeout_| duration.
+ // Any delegate that wants to use this feature must override
+ // |AccountReconcilorDelegate::GetReconcileTimeout|.
+ // Note: This is intended as a safeguard for delegates that want a 'guarantee'
+ // of reconciliation completing within a finite time. It is technically
+ // possible for account reconciliation to be running/waiting forever in cases
+ // such as a network connection not being present.
std::unique_ptr<base::Timer> timer_;
base::TimeDelta timeout_;
diff --git a/chromium/components/signin/core/browser/account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/account_reconcilor_delegate.cc
index 00ac6dde298..867040f4c1f 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor_delegate.cc
@@ -4,6 +4,7 @@
#include "components/signin/core/browser/account_reconcilor_delegate.h"
+#include "base/logging.h"
#include "base/time/time.h"
#include "google_apis/gaia/google_service_auth_error.h"
@@ -17,6 +18,11 @@ bool AccountReconcilorDelegate::IsAccountConsistencyEnforced() const {
return false;
}
+std::string AccountReconcilorDelegate::GetGaiaApiSource() const {
+ NOTREACHED() << "Reconcile is not enabled, no Gaia API calls should be made.";
+ return "ChromiumAccountReconcilorInvalidSource";
+}
+
bool AccountReconcilorDelegate::ShouldAbortReconcileIfPrimaryHasError() const {
return false;
}
@@ -25,7 +31,8 @@ std::string AccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const {
+ bool first_execution,
+ bool will_logout) const {
return std::string();
}
diff --git a/chromium/components/signin/core/browser/account_reconcilor_delegate.h b/chromium/components/signin/core/browser/account_reconcilor_delegate.h
index 03553a98cee..d4bdd202954 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/account_reconcilor_delegate.h
@@ -41,6 +41,9 @@ class AccountReconcilorDelegate {
// changes to the accounts are made. Defaults to false.
virtual bool IsAccountConsistencyEnforced() const;
+ // Returns the value to set in the "source" parameter for Gaia API calls.
+ virtual std::string GetGaiaApiSource() const;
+
// Returns true if Reconcile should be aborted when the primary account is in
// error state. Defaults to false.
virtual bool ShouldAbortReconcileIfPrimaryHasError() const;
@@ -48,11 +51,15 @@ class AccountReconcilorDelegate {
// Returns the first account to add in the Gaia cookie.
// If this returns an empty string, the user must be logged out of all
// accounts.
+ // |first_execution| is true for the first reconciliation after startup.
+ // |will_logout| is true if the reconcilor will perform a logout no matter
+ // what is returned by this function.
virtual std::string GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const;
+ bool first_execution,
+ bool will_logout) const;
// Returns whether secondary accounts should be cleared at the beginning of
// the reconcile.
@@ -60,17 +67,22 @@ class AccountReconcilorDelegate {
const std::vector<gaia::ListedAccount>& gaia_accounts);
// Called when reconcile is finished.
+ // |OnReconcileFinished| is always called at the end of reconciliation, even
+ // when there is an error (except in cases where reconciliation times out
+ // before finishing, see |GetReconcileTimeout|).
virtual void OnReconcileFinished(const std::string& first_account,
bool reconcile_is_noop) {}
// Returns the desired timeout for account reconciliation. If reconciliation
// does not happen within this time, it is aborted and |this| delegate is
- // informed via |OnReconcileError|, with an error state of
- // GoogleServiceAuthError::CONNECTION_FAILED. If a delegate does not wish to
- // set a timeout for account reconciliation, it should not override this
- // method. Default: |base::TimeDelta::Max()|.
+ // informed via |OnReconcileError|, with the 'most severe' error that occurred
+ // during this time (see |AccountReconcilor::error_during_last_reconcile_|).
+ // If a delegate does not wish to set a timeout for account reconciliation, it
+ // should not override this method. Default: |base::TimeDelta::Max()|.
virtual base::TimeDelta GetReconcileTimeout() const;
+ // Called when account reconciliation ends in an error.
+ // |OnReconcileError| is called before |OnReconcileFinished|.
virtual void OnReconcileError(const GoogleServiceAuthError& error);
void set_reconcilor(AccountReconcilor* reconcilor) {
diff --git a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
index de00a76dc77..101b94aa35c 100644
--- a/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/chromium/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <algorithm>
#include <cstring>
#include <map>
#include <memory>
@@ -78,13 +79,16 @@ class SpyReconcilorDelegate : public signin::AccountReconcilorDelegate {
bool IsAccountConsistencyEnforced() const override { return true; }
+ std::string GetGaiaApiSource() const override { return "TestSource"; }
+
bool ShouldAbortReconcileIfPrimaryHasError() const override { return true; }
std::string GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const override {
+ bool first_execution,
+ bool will_logout) const override {
return primary_account;
}
@@ -285,6 +289,25 @@ class AccountReconcilorTest : public ::testing::Test {
DISALLOW_COPY_AND_ASSIGN(AccountReconcilorTest);
};
+// For tests that must be run with multiple account consistency methods.
+class AccountReconcilorMethodParamTest
+ : public AccountReconcilorTest,
+ public ::testing::WithParamInterface<signin::AccountConsistencyMethod> {
+ public:
+ AccountReconcilorMethodParamTest() = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AccountReconcilorMethodParamTest);
+};
+
+INSTANTIATE_TEST_CASE_P(Dice_Mirror,
+ AccountReconcilorMethodParamTest,
+ ::testing::Values(
+#if BUILDFLAG(ENABLE_DICE_SUPPORT)
+ signin::AccountConsistencyMethod::kDice,
+#endif
+ signin::AccountConsistencyMethod::kMirror));
+
AccountReconcilorTest::AccountReconcilorTest()
: account_consistency_(signin::AccountConsistencyMethod::kDisabled),
test_signin_client_(&pref_service_),
@@ -471,6 +494,7 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
// x: The next account has a token error.
// - Cookies:
// A, B, C: Accounts in the Gaia cookie (returned by ListAccounts).
+ // x: The next cookie is marked "invalid".
// - First Run: true if this is the first reconcile (i.e. Chrome startup).
// - API calls:
// X: Logout all accounts.
@@ -581,6 +605,30 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
{ "xAxB", "B", false, "X", "", ""},
{ "xAxB", "", false, "", "", ""},
+ // Account marked as invalid in cookies.
+ // Do not logout. Regression tests for http://crbug.com/854799
+ { "", "xA", false, "", "", "xA"},
+ { "", "xAxB", false, "", "", "xAxB"},
+ { "xA", "xA", false, "", "", "xA"},
+ { "xAB", "xAB", false, "", "B", "xAB"},
+ { "AxB", "AxC", false, "", "A", "AxC"},
+ { "B", "xAB", false, "", "B", "xAB"},
+ { "*xA", "xA", false, "", "*xA", "xA"},
+ { "*xA", "xB", false, "", "*xA", "xB"},
+ { "*xAB", "xAB", false, "", "*xAB", "xAB"},
+ // Appending a new cookie after the invalid one.
+ { "B", "xA", false, "B", "B", "xAB"},
+ { "xAB", "xA", false, "B", "B", "xAB"},
+ // Cookies can be refreshed in pace, without logout.
+ { "AB", "xAB", false, "A", "AB", "AB"},
+ { "*AB", "xBxA", false, "BA", "*AB", "BA"},
+ // Logout when necessary.
+ { "", "xAB", false, "X", "", ""},
+ { "xAB", "xAC", false, "X", "", ""},
+ { "xAB", "AxC", false, "X", "", ""},
+ { "*xAB", "xABC", false, "X", "*xA", ""},
+ { "xAB", "xABC", false, "X", "", ""},
+
// Miscellaneous cases.
// Check that unknown Gaia accounts are signed out.
{ "", "A", true, "X", "", ""},
@@ -597,6 +645,7 @@ const AccountReconcilorTestDiceParam kDiceParams[] = {
{ "B", "B", false, "", "B", "B"},
{ "*xA", "", false, "", "*xA", ""},
{ "*xAB", "B", false, "", "*xAB", "B"},
+ { "A", "AxC", false, "", "A", "AxC"},
};
// clang-format on
@@ -617,6 +666,15 @@ class AccountReconcilorTestDice
bool has_error;
};
+ struct Cookie {
+ std::string gaia_id;
+ bool is_valid;
+
+ bool operator==(const Cookie& other) const {
+ return gaia_id == other.gaia_id && is_valid == other.is_valid;
+ }
+ };
+
AccountReconcilorTestDice() {
accounts_['A'] = {"a@gmail.com", "A"};
accounts_['B'] = {"b@gmail.com", "B"};
@@ -647,6 +705,22 @@ class AccountReconcilorTestDice
return parsed_tokens;
}
+ // Build Cookies from string.
+ std::vector<Cookie> ParseCookieString(const char* cookie_string) {
+ std::vector<Cookie> parsed_cookies;
+ bool valid = true;
+ for (int i = 0; cookie_string[i] != '\0'; ++i) {
+ char cookie_code = cookie_string[i];
+ if (cookie_code == 'x') {
+ valid = false;
+ continue;
+ }
+ parsed_cookies.push_back({accounts_[cookie_code].gaia_id, valid});
+ valid = true;
+ }
+ return parsed_cookies;
+ }
+
// Checks that the tokens in the TokenService match the tokens.
void VerifyCurrentTokens(const std::vector<Token>& tokens) {
EXPECT_EQ(token_service()->GetAccounts().size(), tokens.size());
@@ -685,21 +759,15 @@ class AccountReconcilorTestDice
ADD_FAILURE() << "Could not check that reconcile is idempotent.";
}
- void ConfigureCookieManagerService(const std::string& cookies) {
- if (cookies.size() == 0) {
- cookie_manager_service()->SetListAccountsResponseNoAccounts();
- } else if (cookies.size() == 1) {
- cookie_manager_service()->SetListAccountsResponseOneAccount(
- accounts_[cookies[0]].email.c_str(),
- accounts_[cookies[0]].gaia_id.c_str());
- } else {
- ASSERT_EQ(2u, cookies.size());
- cookie_manager_service()->SetListAccountsResponseTwoAccounts(
- accounts_[cookies[0]].email.c_str(),
- accounts_[cookies[0]].gaia_id.c_str(),
- accounts_[cookies[1]].email.c_str(),
- accounts_[cookies[1]].gaia_id.c_str());
+ void ConfigureCookieManagerService(const std::vector<Cookie>& cookies) {
+ std::vector<FakeGaiaCookieManagerService::CookieParams> cookie_params;
+ for (const auto& cookie : cookies) {
+ std::string gaia_id = cookie.gaia_id;
+ cookie_params.push_back({accounts_[gaia_id[0]].email, gaia_id,
+ cookie.is_valid, false /* signed_out */,
+ true /* verified */});
}
+ cookie_manager_service()->SetListAccountsResponseWithParams(cookie_params);
cookie_manager_service()->set_list_accounts_stale_for_testing(true);
}
@@ -734,7 +802,7 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
VerifyCurrentTokens(tokens_before_reconcile);
// Setup cookies.
- std::string cookies(GetParam().cookies);
+ std::vector<Cookie> cookies = ParseCookieString(GetParam().cookies);
ConfigureCookieManagerService(cookies);
// Call list accounts now so that the next call completes synchronously.
@@ -754,7 +822,13 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
}
std::string cookie(1, GetParam().gaia_api_calls[i]);
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(cookie)).Times(1);
- cookies += cookie;
+ // MergeSession fixes an existing cookie or appends it at the end.
+ std::vector<Cookie>::iterator it = std::find(
+ cookies.begin(), cookies.end(), Cookie{cookie, false /* is_valid */});
+ if (it == cookies.end())
+ cookies.push_back({cookie, true});
+ else
+ it->is_valid = true;
}
if (!logout_action) {
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
@@ -762,7 +836,9 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
}
// Check the expected cookies after reconcile.
- ASSERT_EQ(GetParam().cookies_after_reconcile, cookies);
+ std::vector<Cookie> expected_cookies =
+ ParseCookieString(GetParam().cookies_after_reconcile);
+ ASSERT_EQ(expected_cookies, cookies);
// Reconcile.
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -790,7 +866,7 @@ TEST_P(AccountReconcilorTestDice, TableRowTest) {
.WillRepeatedly(testing::Return());
EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction())
.WillRepeatedly(testing::Return());
- ConfigureCookieManagerService("");
+ ConfigureCookieManagerService({});
base::RunLoop().RunUntilIdle();
}
@@ -972,8 +1048,8 @@ TEST_F(AccountReconcilorTest, UnverifiedAccountNoop) {
// Add a unverified account to the Gaia cookie.
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- "user@gmail.com", "12345", true /* is_email_valid */,
- false /* signed_out */, false /* verified */);
+ {"user@gmail.com", "12345", true /* valid */, false /* signed_out */,
+ false /* verified */});
// Check that nothing happens.
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(testing::_)).Times(0);
@@ -995,8 +1071,8 @@ TEST_F(AccountReconcilorTest, UnverifiedAccountMerge) {
// Add a unverified account to the Gaia cookie.
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- "user@gmail.com", "12345", true /* is_email_valid */,
- false /* signed_out */, false /* verified */);
+ {"user@gmail.com", "12345", true /* valid */, false /* signed_out */,
+ false /* verified */});
// Add a token to Chrome.
const std::string chrome_account_id =
@@ -1238,8 +1314,8 @@ TEST_F(AccountReconcilorTest, GetAccountsFromCookieSuccess) {
const std::string account_id =
ConnectProfileToAccount("12345", "user@gmail.com");
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- "user@gmail.com", "12345", false /* is_email_valid */,
- false /* signed_out */, true /* verified */);
+ {"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
+ true /* verified */});
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
AccountReconcilor* reconcilor = GetMockReconcilor();
@@ -1801,15 +1877,21 @@ TEST_F(AccountReconcilorTest, Lock) {
EXPECT_FALSE(reconcilor->is_reconcile_started_);
}
-TEST_F(AccountReconcilorTest, StartReconcileWithSessionInfoExpiredDefault) {
- SetAccountConsistency(signin::AccountConsistencyMethod::kMirror);
+// Checks that an "invalid" Gaia account can be refreshed in place, without
+// performing a full logout.
+TEST_P(AccountReconcilorMethodParamTest,
+ StartReconcileWithSessionInfoExpiredDefault) {
+ SetAccountConsistency(GetParam());
const std::string account_id =
ConnectProfileToAccount("12345", "user@gmail.com");
const std::string account_id2 =
PickAccountIdForAccount("67890", "other@gmail.com");
token_service()->UpdateCredentials(account_id2, "refresh_token");
- cookie_manager_service()->SetListAccountsResponseTwoAccountsWithExpiry(
- "user@gmail.com", "12345", true, "other@gmail.com", "67890", false);
+ cookie_manager_service()->SetListAccountsResponseWithParams(
+ {{"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
+ true /* verified */},
+ {"other@gmail.com", "67890", true /* valid */, false /* signed_out */,
+ true /* verified */}});
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -1831,8 +1913,8 @@ TEST_F(AccountReconcilorTest, AddAccountToCookieCompletedWithBogusAccount) {
const std::string account_id =
ConnectProfileToAccount("12345", "user@gmail.com");
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- "user@gmail.com", "12345", false /* is_email_valid */,
- false /* signed_out */, true /* verified */);
+ {"user@gmail.com", "12345", false /* valid */, false /* signed_out */,
+ true /* verified */});
EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id));
@@ -1870,8 +1952,8 @@ TEST_F(AccountReconcilorTest, NoLoopWithBadPrimary) {
// The primary account is in auth error, so it is not in the cookie.
cookie_manager_service()->SetListAccountsResponseOneAccountWithParams(
- "other@gmail.com", "67890", false /* is_email_valid */,
- false /* signed_out */, true /* verified */);
+ {"other@gmail.com", "67890", false /* valid */, false /* signed_out */,
+ true /* verified */});
AccountReconcilor* reconcilor = GetMockReconcilor();
ASSERT_TRUE(reconcilor);
@@ -1889,7 +1971,8 @@ TEST_F(AccountReconcilorTest, NoLoopWithBadPrimary) {
GoogleServiceAuthError::AuthErrorNone());
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(reconcilor->is_reconcile_started_);
- ASSERT_TRUE(reconcilor->error_during_last_reconcile_);
+ ASSERT_NE(GoogleServiceAuthError::State::NONE,
+ reconcilor->error_during_last_reconcile_.state());
testing::Mock::VerifyAndClearExpectations(GetMockReconcilor());
// Now that we've tried once, the token service knows that the primary
@@ -1936,7 +2019,8 @@ TEST_F(AccountReconcilorTest, WontMergeAccountsWithError) {
GoogleServiceAuthError::AuthErrorNone());
base::RunLoop().RunUntilIdle();
ASSERT_FALSE(reconcilor->is_reconcile_started_);
- ASSERT_FALSE(reconcilor->error_during_last_reconcile_);
+ ASSERT_EQ(GoogleServiceAuthError::State::NONE,
+ reconcilor->error_during_last_reconcile_.state());
}
// Test that delegate timeout is called when the delegate offers a valid
diff --git a/chromium/components/signin/core/browser/account_tracker_service.h b/chromium/components/signin/core/browser/account_tracker_service.h
index c734d9c11c9..510512ae17e 100644
--- a/chromium/components/signin/core/browser/account_tracker_service.h
+++ b/chromium/components/signin/core/browser/account_tracker_service.h
@@ -40,9 +40,8 @@ class AccountTrackerService : public KeyedService {
// tracked by this service.
static const char kAccountInfoPref[];
- // TODO(mlerman): Remove all references to Profile::kNoHostedDomainFound in
- // favour of this.
- // Value representing no hosted domain in the kProfileHostedDomain preference.
+ // Value representing no hosted domain in the kGoogleServicesHostedDomain
+ // preference.
static const char kNoHostedDomainFound[];
// Value representing no picture URL associated with an account.
diff --git a/chromium/components/signin/core/browser/account_tracker_service_unittest.cc b/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
index 99b8e645d33..bb6516c8a4a 100644
--- a/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/chromium/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -286,9 +286,8 @@ class AccountTrackerServiceTest : public testing::Test {
pref_service_.registry()->RegisterInt64Pref(
AccountFetcherService::kLastUpdatePref, 0);
signin_client_.reset(new TestSigninClient(&pref_service_));
- signin_client_.get()->SetURLRequestContext(
- new net::TestURLRequestContextGetter(
- scoped_task_environment_.GetMainThreadTaskRunner()));
+ signin_client_->SetURLRequestContext(new net::TestURLRequestContextGetter(
+ scoped_task_environment_.GetMainThreadTaskRunner()));
account_tracker_.reset(new AccountTrackerService());
account_tracker_->Initialize(signin_client_.get());
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
index 9da846066c5..ef109b6ccd7 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.cc
@@ -31,6 +31,10 @@ bool DiceAccountReconcilorDelegate::IsAccountConsistencyEnforced() const {
return account_consistency_ == AccountConsistencyMethod::kDice;
}
+std::string DiceAccountReconcilorDelegate::GetGaiaApiSource() const {
+ return "ChromiumAccountReconcilorDice";
+}
+
// - On first execution, the candidates are examined in this order:
// 1. The primary account
// 2. The current first Gaia account
@@ -45,16 +49,14 @@ std::string DiceAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const {
- if (chrome_accounts.empty())
- return std::string(); // No Chrome account, log out.
-
- bool valid_primary_account =
+ bool first_execution,
+ bool will_logout) const {
+ bool primary_account_has_token =
!primary_account.empty() &&
base::ContainsValue(chrome_accounts, primary_account);
if (gaia_accounts.empty()) {
- if (valid_primary_account)
+ if (primary_account_has_token)
return primary_account;
// Try the last known account. This happens when the cookies are cleared
@@ -63,36 +65,44 @@ std::string DiceAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
return last_known_first_account_;
// As a last resort, use the first Chrome account.
- return chrome_accounts[0];
+ return chrome_accounts.empty() ? std::string() : chrome_accounts[0];
}
const std::string& first_gaia_account = gaia_accounts[0].id;
- bool first_gaia_account_is_valid =
- gaia_accounts[0].valid &&
+ bool first_gaia_account_has_token =
base::ContainsValue(chrome_accounts, first_gaia_account);
- if (!first_gaia_account_is_valid && (primary_account == first_gaia_account)) {
- // The primary account is also the first Gaia account, and is invalid.
+ if (!first_gaia_account_has_token &&
+ (primary_account == first_gaia_account) && gaia_accounts[0].valid) {
+ // The primary account is also the first Gaia account, and has no token.
// Logout everything.
return std::string();
}
+ // If the primary Chrome account and the default Gaia account are both in
+ // error, then the first gaia account can be kept, to avoid logging the user
+ // out of their other accounts.
+ // It's only possible when the reconcilor will not perform a logout, because
+ // that account cannot be rebuilt.
+ if (!primary_account_has_token && !gaia_accounts[0].valid && !will_logout)
+ return first_gaia_account;
+
if (first_execution) {
// On first execution, try the primary account, and then the first Gaia
// account.
- if (valid_primary_account)
+ if (primary_account_has_token)
return primary_account;
- if (first_gaia_account_is_valid)
+ if (first_gaia_account_has_token)
return first_gaia_account;
// As a last resort, use the first Chrome account.
- return chrome_accounts[0];
+ return chrome_accounts.empty() ? std::string() : chrome_accounts[0];
}
// While Chrome is running, try the first Gaia account, and then the
// primary account.
- if (first_gaia_account_is_valid)
+ if (first_gaia_account_has_token)
return first_gaia_account;
- if (valid_primary_account)
+ if (primary_account_has_token)
return primary_account;
// Changing the first Gaia account while Chrome is running would be
diff --git a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
index b4cb70586b2..e6f628c05b2 100644
--- a/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/dice_account_reconcilor_delegate.h
@@ -25,11 +25,13 @@ class DiceAccountReconcilorDelegate : public AccountReconcilorDelegate {
// AccountReconcilorDelegate:
bool IsReconcileEnabled() const override;
bool IsAccountConsistencyEnforced() const override;
+ std::string GetGaiaApiSource() const override;
std::string GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const override;
+ bool first_execution,
+ bool will_logout) const override;
RevokeTokenOption ShouldRevokeSecondaryTokensBeforeReconcile(
const std::vector<gaia::ListedAccount>& gaia_accounts) override;
void OnReconcileFinished(const std::string& first_account,
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
index 897b8739b66..ed87b82fb00 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
@@ -4,6 +4,7 @@
#include "components/signin/core/browser/fake_gaia_cookie_manager_service.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "google_apis/gaia/gaia_constants.h"
@@ -37,78 +38,58 @@ void FakeGaiaCookieManagerService::SetListAccountsResponseWebLoginRequired() {
"Info=WebLoginRequired", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
}
-void FakeGaiaCookieManagerService::SetListAccountsResponseNoAccounts() {
+void FakeGaiaCookieManagerService::SetListAccountsResponseWithParams(
+ const std::vector<CookieParams>& params) {
DCHECK(url_fetcher_factory_);
+
+ std::vector<std::string> response_body;
+ for (const auto& param : params) {
+ std::string response_part = base::StringPrintf(
+ "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"",
+ param.email.c_str(), param.valid ? 1 : 0, param.gaia_id.c_str());
+ if (param.signed_out || !param.verified) {
+ response_part +=
+ base::StringPrintf(", null, null, null, %d, %d",
+ param.signed_out ? 1 : 0, param.verified ? 1 : 0);
+ }
+ response_part += "]";
+ response_body.push_back(response_part);
+ }
+
url_fetcher_factory_->SetFakeResponse(
GaiaUrls::GetInstance()->ListAccountsURLWithSource(
GaiaConstants::kChromeSource),
- "[\"f\", []]", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]",
+ net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+}
+
+void FakeGaiaCookieManagerService::SetListAccountsResponseNoAccounts() {
+ SetListAccountsResponseWithParams({});
}
void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccount(
- const char* email,
- const char* gaia_id) {
- DCHECK(url_fetcher_factory_);
- url_fetcher_factory_->SetFakeResponse(
- GaiaUrls::GetInstance()->ListAccountsURLWithSource(
- GaiaConstants::kChromeSource),
- base::StringPrintf(
- "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"%s\"]]]",
- email, gaia_id),
- net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ const std::string& email,
+ const std::string& gaia_id) {
+ CookieParams params = {email, gaia_id, true /* valid */,
+ false /* signed_out */, true /* verified */};
+ SetListAccountsResponseWithParams({params});
}
void FakeGaiaCookieManagerService::SetListAccountsResponseOneAccountWithParams(
- const char* email,
- const char* gaia_id,
- bool is_email_valid,
- bool signed_out,
- bool verified) {
- DCHECK(url_fetcher_factory_);
- url_fetcher_factory_->SetFakeResponse(
- GaiaUrls::GetInstance()->ListAccountsURLWithSource(
- GaiaConstants::kChromeSource),
- base::StringPrintf(
- "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\", "
- "null, null, null, %d, %d]]]",
- email, is_email_valid ? 1 : 0, gaia_id, signed_out ? 1 : 0,
- verified ? 1 : 0),
- net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ const CookieParams& params) {
+ SetListAccountsResponseWithParams({params});
}
void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccounts(
- const char* email1,
- const char* gaia_id1,
- const char* email2,
- const char* gaia_id2) {
- DCHECK(url_fetcher_factory_);
- url_fetcher_factory_->SetFakeResponse(
- GaiaUrls::GetInstance()->ListAccountsURLWithSource(
- GaiaConstants::kChromeSource),
- base::StringPrintf(
- "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"%s\"], "
- "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, 1, \"%s\"]]]",
- email1, gaia_id1, email2, gaia_id2),
- net::HTTP_OK, net::URLRequestStatus::SUCCESS);
-}
-
-void FakeGaiaCookieManagerService::SetListAccountsResponseTwoAccountsWithExpiry(
- const char* email1,
- const char* gaia_id1,
- bool account1_expired,
- const char* email2,
- const char* gaia_id2,
- bool account2_expired) {
- DCHECK(url_fetcher_factory_);
- url_fetcher_factory_->SetFakeResponse(
- GaiaUrls::GetInstance()->ListAccountsURLWithSource(
- GaiaConstants::kChromeSource),
- base::StringPrintf(
- "[\"f\", [[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"], "
- "[\"b\", 0, \"n\", \"%s\", \"p\", 0, 0, 0, 0, %d, \"%s\"]]]",
- email1, account1_expired ? 0 : 1, gaia_id1, email2,
- account2_expired ? 0 : 1, gaia_id2),
- net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+ const std::string& email1,
+ const std::string& gaia_id1,
+ const std::string& email2,
+ const std::string& gaia_id2) {
+ SetListAccountsResponseWithParams(
+ {{email1, gaia_id1, true /* valid */, false /* signed_out */,
+ true /* verified */},
+ {email2, gaia_id2, true /* valid */, false /* signed_out */,
+ true /* verified */}});
}
std::string FakeGaiaCookieManagerService::GetSourceForRequest(
diff --git a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
index 002ae78af47..a4b06205521 100644
--- a/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
+++ b/chromium/components/signin/core/browser/fake_gaia_cookie_manager_service.h
@@ -13,6 +13,15 @@
class FakeGaiaCookieManagerService : public GaiaCookieManagerService {
public:
+ // Parameters for the fake ListAccounts response.
+ struct CookieParams {
+ std::string email;
+ std::string gaia_id;
+ bool valid;
+ bool signed_out;
+ bool verified;
+ };
+
FakeGaiaCookieManagerService(OAuth2TokenService* token_service,
const std::string& source,
SigninClient* client);
@@ -21,24 +30,18 @@ class FakeGaiaCookieManagerService : public GaiaCookieManagerService {
void SetListAccountsResponseHttpNotFound();
void SetListAccountsResponseWebLoginRequired();
+ void SetListAccountsResponseWithParams(
+ const std::vector<CookieParams>& params);
+
+ // Helper methods, equivalent to calling SetListAccountsResponseWithParams().
void SetListAccountsResponseNoAccounts();
- void SetListAccountsResponseOneAccount(const char* email,
- const char* gaia_id);
- void SetListAccountsResponseOneAccountWithParams(const char* account,
- const char* gaia_id,
- bool is_email_valid,
- bool is_signed_out,
- bool verified);
- void SetListAccountsResponseTwoAccounts(const char* email1,
- const char* gaia_id1,
- const char* email2,
- const char* gaia_id2);
- void SetListAccountsResponseTwoAccountsWithExpiry(const char* email1,
- const char* gaia_id1,
- bool account1_expired,
- const char* email2,
- const char* gaia_id2,
- bool account2_expired);
+ void SetListAccountsResponseOneAccount(const std::string& email,
+ const std::string& gaia_id);
+ void SetListAccountsResponseOneAccountWithParams(const CookieParams& params);
+ void SetListAccountsResponseTwoAccounts(const std::string& email1,
+ const std::string& gaia_id1,
+ const std::string& email2,
+ const std::string& gaia_id2);
private:
std::string GetSourceForRequest(
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
index 68124de94a7..b308c7ec0ca 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -66,13 +66,6 @@ const int kMaxFetcherRetries = 8;
// accounts have changed in the content-area.
const char* const kGaiaCookieName = "APISID";
-enum GaiaCookieRequestType {
- ADD_ACCOUNT,
- LOG_OUT_ALL_ACCOUNTS,
- LOG_OUT_ONE_ACCOUNT,
- LIST_ACCOUNTS
-};
-
} // namespace
GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
@@ -90,8 +83,7 @@ GaiaCookieManagerService::GaiaCookieRequest::CreateAddAccountRequest(
const std::string& account_id,
const std::string& source) {
return GaiaCookieManagerService::GaiaCookieRequest(
- GaiaCookieManagerService::GaiaCookieRequestType::ADD_ACCOUNT, account_id,
- source);
+ GaiaCookieRequestType::ADD_ACCOUNT, account_id, source);
}
// static
@@ -99,8 +91,7 @@ GaiaCookieManagerService::GaiaCookieRequest
GaiaCookieManagerService::GaiaCookieRequest::CreateLogOutRequest(
const std::string& source) {
return GaiaCookieManagerService::GaiaCookieRequest(
- GaiaCookieManagerService::GaiaCookieRequestType::LOG_OUT, std::string(),
- source);
+ GaiaCookieRequestType::LOG_OUT, std::string(), source);
}
// static
@@ -108,8 +99,7 @@ GaiaCookieManagerService::GaiaCookieRequest
GaiaCookieManagerService::GaiaCookieRequest::CreateListAccountsRequest(
const std::string& source) {
return GaiaCookieManagerService::GaiaCookieRequest(
- GaiaCookieManagerService::GaiaCookieRequestType::LIST_ACCOUNTS,
- std::string(), source);
+ GaiaCookieRequestType::LIST_ACCOUNTS, std::string(), source);
}
GaiaCookieManagerService::ExternalCcResultFetcher::ExternalCcResultFetcher(
diff --git a/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
index 63645420f9d..b0f29d9ac15 100644
--- a/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
+++ b/chromium/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -39,7 +39,7 @@ class MockObserver : public GaiaCookieManagerService::Observer {
helper_->AddObserver(this);
}
- ~MockObserver() { helper_->RemoveObserver(this); }
+ ~MockObserver() override { helper_->RemoveObserver(this); }
MOCK_METHOD2(OnAddAccountToCookieCompleted,
void(const std::string&, const GoogleServiceAuthError&));
@@ -94,7 +94,7 @@ class InstrumentedGaiaCookieManagerService : public GaiaCookieManagerService {
total++;
}
- virtual ~InstrumentedGaiaCookieManagerService() { total--; }
+ ~InstrumentedGaiaCookieManagerService() override { total--; }
MOCK_METHOD0(StartFetchingUbertoken, void());
MOCK_METHOD0(StartFetchingListAccounts, void());
@@ -249,7 +249,7 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetried) {
DCHECK(helper.is_running());
// Transient error incurs a retry after 1 second.
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
base::TimeDelta::FromMilliseconds(1100));
base::RunLoop().Run();
SimulateMergeSessionSuccess(&helper, "token");
@@ -273,7 +273,7 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetriedTwice) {
EXPECT_LT(helper.GetBackoffEntry()->GetTimeUntilRelease(),
base::TimeDelta::FromMilliseconds(1100));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
base::TimeDelta::FromMilliseconds(1100));
base::RunLoop().Run();
SimulateMergeSessionFailure(&helper, canceled());
@@ -282,7 +282,7 @@ TEST_F(GaiaCookieManagerServiceTest, MergeSessionRetriedTwice) {
EXPECT_LT(helper.GetBackoffEntry()->GetTimeUntilRelease(),
base::TimeDelta::FromMilliseconds(3100));
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated(),
base::TimeDelta::FromMilliseconds(3100));
base::RunLoop().Run();
SimulateMergeSessionSuccess(&helper, "token");
diff --git a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
index 32bb0bea760..519c572cf3b 100644
--- a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
+++ b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.cc
@@ -28,6 +28,10 @@ bool MirrorAccountReconcilorDelegate::IsAccountConsistencyEnforced() const {
return true;
}
+std::string MirrorAccountReconcilorDelegate::GetGaiaApiSource() const {
+ return "ChromiumAccountReconcilor";
+}
+
bool MirrorAccountReconcilorDelegate::ShouldAbortReconcileIfPrimaryHasError()
const {
return true;
@@ -37,7 +41,8 @@ std::string MirrorAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const {
+ bool first_execution,
+ bool will_logout) const {
// Mirror only uses the primary account, and it is never empty.
DCHECK(!primary_account.empty());
DCHECK(base::ContainsValue(chrome_accounts, primary_account));
diff --git a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
index b3514798f74..1a9e3c84c19 100644
--- a/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
+++ b/chromium/components/signin/core/browser/mirror_account_reconcilor_delegate.h
@@ -22,12 +22,14 @@ class MirrorAccountReconcilorDelegate : public AccountReconcilorDelegate,
// AccountReconcilorDelegate:
bool IsReconcileEnabled() const override;
bool IsAccountConsistencyEnforced() const override;
+ std::string GetGaiaApiSource() const override;
bool ShouldAbortReconcileIfPrimaryHasError() const override;
std::string GetFirstGaiaAccountForReconcile(
const std::vector<std::string>& chrome_accounts,
const std::vector<gaia::ListedAccount>& gaia_accounts,
const std::string& primary_account,
- bool first_execution) const override;
+ bool first_execution,
+ bool will_logout) const override;
// SigninManagerBase::Observer:
void GoogleSigninSucceeded(const std::string& account_id,
diff --git a/chromium/components/signin/core/browser/profile_identity_provider.cc b/chromium/components/signin/core/browser/profile_identity_provider.cc
index a537d4b718a..797236db602 100644
--- a/chromium/components/signin/core/browser/profile_identity_provider.cc
+++ b/chromium/components/signin/core/browser/profile_identity_provider.cc
@@ -4,16 +4,12 @@
#include "components/signin/core/browser/profile_identity_provider.h"
-#include "base/callback.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
ProfileIdentityProvider::ProfileIdentityProvider(
SigninManagerBase* signin_manager,
- ProfileOAuth2TokenService* token_service,
- const base::Closure& request_login_callback)
- : signin_manager_(signin_manager),
- token_service_(token_service),
- request_login_callback_(request_login_callback) {
+ ProfileOAuth2TokenService* token_service)
+ : signin_manager_(signin_manager), token_service_(token_service) {
signin_manager_->AddObserver(this);
}
@@ -33,13 +29,6 @@ OAuth2TokenService* ProfileIdentityProvider::GetTokenService() {
return token_service_;
}
-bool ProfileIdentityProvider::RequestLogin() {
- if (request_login_callback_.is_null())
- return false;
- request_login_callback_.Run();
- return true;
-}
-
void ProfileIdentityProvider::GoogleSigninSucceeded(
const std::string& account_id,
const std::string& username) {
diff --git a/chromium/components/signin/core/browser/profile_identity_provider.h b/chromium/components/signin/core/browser/profile_identity_provider.h
index eef7e346787..9d4cdb31a9f 100644
--- a/chromium/components/signin/core/browser/profile_identity_provider.h
+++ b/chromium/components/signin/core/browser/profile_identity_provider.h
@@ -5,7 +5,6 @@
#ifndef COMPONENTS_SIGNIN_CORE_BROWSER_PROFILE_IDENTITY_PROVIDER_H_
#define COMPONENTS_SIGNIN_CORE_BROWSER_PROFILE_IDENTITY_PROVIDER_H_
-#include "base/callback_forward.h"
#include "base/macros.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "google_apis/gaia/identity_provider.h"
@@ -17,18 +16,14 @@ class ProfileOAuth2TokenService;
class ProfileIdentityProvider : public IdentityProvider,
public SigninManagerBase::Observer {
public:
- // |request_login_callback| may be null, in which case login attempts are
- // ignored.
ProfileIdentityProvider(SigninManagerBase* signin_manager,
- ProfileOAuth2TokenService* token_service,
- const base::Closure& request_login_callback);
+ ProfileOAuth2TokenService* token_service);
~ProfileIdentityProvider() override;
// IdentityProvider:
std::string GetActiveUsername() override;
std::string GetActiveAccountId() override;
OAuth2TokenService* GetTokenService() override;
- bool RequestLogin() override;
// SigninManagerBase::Observer:
void GoogleSigninSucceeded(const std::string& account_id,
@@ -39,7 +34,6 @@ class ProfileIdentityProvider : public IdentityProvider,
private:
SigninManagerBase* const signin_manager_;
ProfileOAuth2TokenService* const token_service_;
- base::Closure request_login_callback_;
DISALLOW_COPY_AND_ASSIGN(ProfileIdentityProvider);
};
diff --git a/chromium/components/signin/core/browser/profile_management_switches.cc b/chromium/components/signin/core/browser/profile_management_switches.cc
index a26592c75da..301da575ed8 100644
--- a/chromium/components/signin/core/browser/profile_management_switches.cc
+++ b/chromium/components/signin/core/browser/profile_management_switches.cc
@@ -76,6 +76,7 @@ const char kAccountConsistencyFeatureMethodDice[] = "dice";
const base::Feature kUnifiedConsent{"UnifiedConsent",
base::FEATURE_DISABLED_BY_DEFAULT};
+const char kUnifiedConsentShowBumpParameter[] = "show_consent_bump";
bool DiceMethodGreaterOrEqual(AccountConsistencyMethod a,
AccountConsistencyMethod b) {
@@ -212,4 +213,14 @@ void SetGaiaOriginIsolatedCallback(
*GetIsGaiaIsolatedCallback() = is_gaia_isolated;
}
+UnifiedConsentFeatureState GetUnifiedConsentFeatureState() {
+ if (!base::FeatureList::IsEnabled(signin::kUnifiedConsent))
+ return UnifiedConsentFeatureState::kDisabled;
+
+ std::string show_bump = base::GetFieldTrialParamValueByFeature(
+ kUnifiedConsent, kUnifiedConsentShowBumpParameter);
+ return show_bump.empty() ? UnifiedConsentFeatureState::kEnabledNoBump
+ : UnifiedConsentFeatureState::kEnabledWithBump;
+}
+
} // namespace signin
diff --git a/chromium/components/signin/core/browser/profile_management_switches.h b/chromium/components/signin/core/browser/profile_management_switches.h
index abc74d67ade..281effab049 100644
--- a/chromium/components/signin/core/browser/profile_management_switches.h
+++ b/chromium/components/signin/core/browser/profile_management_switches.h
@@ -39,6 +39,17 @@ extern const char kAccountConsistencyFeatureMethodDice[];
// Improved and unified consent for privacy-related features.
extern const base::Feature kUnifiedConsent;
+extern const char kUnifiedConsentShowBumpParameter[];
+
+// State of the "Unified Consent" feature.
+enum class UnifiedConsentFeatureState {
+ // Unified consent is disabled.
+ kDisabled,
+ // Unified consent is enabled, but the bump is not shown.
+ kEnabledNoBump,
+ // Unified consent is enabled and the bump is shown.
+ kEnabledWithBump
+};
// TODO(https://crbug.com/777774): Cleanup this enum and remove related
// functions once Dice is fully rolled out, and/or Mirror code is removed on
@@ -144,6 +155,9 @@ bool IsExtensionsMultiAccount();
void SetGaiaOriginIsolatedCallback(
const base::RepeatingCallback<bool()>& is_gaia_isolated);
+// Returns the state of the "Unified Consent" feature.
+UnifiedConsentFeatureState GetUnifiedConsentFeatureState();
+
} // namespace signin
#endif // COMPONENTS_SIGNIN_CORE_BROWSER_PROFILE_MANAGEMENT_SWITCHES_H_
diff --git a/chromium/components/signin/core/browser/profile_management_switches_unittest.cc b/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
index c0f40463050..5efa1cc3ef0 100644
--- a/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
+++ b/chromium/components/signin/core/browser/profile_management_switches_unittest.cc
@@ -9,8 +9,10 @@
#include "base/bind.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "build/buildflag.h"
#include "components/prefs/pref_member.h"
#include "components/signin/core/browser/scoped_account_consistency.h"
+#include "components/signin/core/browser/scoped_unified_consent.h"
#include "components/signin/core/browser/signin_buildflags.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -132,4 +134,18 @@ TEST(ProfileManagementSwitchesTest, GaiaSiteIsolation) {
#endif // BUILDFLAG(ENABLE_MIRROR)
+TEST(ProfileManagementSwitchesTest, UnifiedConsent) {
+ // Unified consent is disabled by default.
+ EXPECT_EQ(UnifiedConsentFeatureState::kDisabled,
+ GetUnifiedConsentFeatureState());
+
+ for (UnifiedConsentFeatureState state :
+ {UnifiedConsentFeatureState::kDisabled,
+ UnifiedConsentFeatureState::kEnabledNoBump,
+ UnifiedConsentFeatureState::kEnabledWithBump}) {
+ ScopedUnifiedConsent scoped_state(state);
+ EXPECT_EQ(state, GetUnifiedConsentFeatureState());
+ }
+}
+
} // namespace signin
diff --git a/chromium/components/signin/core/browser/scoped_unified_consent.cc b/chromium/components/signin/core/browser/scoped_unified_consent.cc
new file mode 100644
index 00000000000..8c19fa1c9e9
--- /dev/null
+++ b/chromium/components/signin/core/browser/scoped_unified_consent.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/signin/core/browser/scoped_unified_consent.h"
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/test/scoped_feature_list.h"
+
+namespace signin {
+
+ScopedUnifiedConsent::ScopedUnifiedConsent(UnifiedConsentFeatureState state) {
+ switch (state) {
+ case UnifiedConsentFeatureState::kDisabled:
+ scoped_feature_list_.InitAndDisableFeature(kUnifiedConsent);
+ break;
+ case UnifiedConsentFeatureState::kEnabledNoBump:
+ scoped_feature_list_.InitAndEnableFeature(kUnifiedConsent);
+ break;
+ case UnifiedConsentFeatureState::kEnabledWithBump: {
+ std::map<std::string, std::string> feature_params;
+ feature_params[kUnifiedConsentShowBumpParameter] = "true";
+ scoped_feature_list_.InitAndEnableFeatureWithParameters(kUnifiedConsent,
+ feature_params);
+ break;
+ }
+ }
+
+ DCHECK_EQ(state, GetUnifiedConsentFeatureState());
+}
+
+ScopedUnifiedConsent::~ScopedUnifiedConsent() {}
+
+} // namespace signin
diff --git a/chromium/components/signin/core/browser/scoped_unified_consent.h b/chromium/components/signin/core/browser/scoped_unified_consent.h
new file mode 100644
index 00000000000..69e55dce8e1
--- /dev/null
+++ b/chromium/components/signin/core/browser/scoped_unified_consent.h
@@ -0,0 +1,31 @@
+// 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 COMPONENTS_SIGNIN_CORE_BROWSER_SCOPED_UNIFIED_CONSENT_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_SCOPED_UNIFIED_CONSENT_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
+#include "components/signin/core/browser/profile_management_switches.h"
+
+namespace signin {
+
+// Changes the unified consent feature state while it is in scope. Useful for
+// tests.
+class ScopedUnifiedConsent {
+ public:
+ explicit ScopedUnifiedConsent(UnifiedConsentFeatureState state);
+ ~ScopedUnifiedConsent();
+
+ private:
+ base::test::ScopedFeatureList scoped_feature_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedUnifiedConsent);
+};
+
+} // namespace signin
+
+#endif // COMPONENTS_SIGNIN_CORE_BROWSER_SCOPED_UNIFIED_CONSENT_H_
diff --git a/chromium/components/signin/core/browser/signin_manager.cc b/chromium/components/signin/core/browser/signin_manager.cc
index 5b92a3473b2..2791801d2dc 100644
--- a/chromium/components/signin/core/browser/signin_manager.cc
+++ b/chromium/components/signin/core/browser/signin_manager.cc
@@ -380,6 +380,10 @@ const std::string& SigninManager::GetAccountIdForAuthInProgress() const {
return possibly_invalid_account_id_;
}
+const std::string& SigninManager::GetGaiaIdForAuthInProgress() const {
+ return possibly_invalid_gaia_id_;
+}
+
const std::string& SigninManager::GetUsernameForAuthInProgress() const {
return possibly_invalid_email_;
}
diff --git a/chromium/components/signin/core/browser/signin_manager.h b/chromium/components/signin/core/browser/signin_manager.h
index 8b7d54cf9a8..5170a22a304 100644
--- a/chromium/components/signin/core/browser/signin_manager.h
+++ b/chromium/components/signin/core/browser/signin_manager.h
@@ -170,6 +170,10 @@ class SigninManager : public SigninManagerBase,
// authenticated. Returns an empty string if no auth is in progress.
const std::string& GetAccountIdForAuthInProgress() const;
+ // If an authentication is in progress, return the gaia id being
+ // authenticated. Returns an empty string if no auth is in progress.
+ const std::string& GetGaiaIdForAuthInProgress() const;
+
// If an authentication is in progress, return the username being
// authenticated. Returns an empty string if no auth is in progress.
const std::string& GetUsernameForAuthInProgress() const;
diff --git a/chromium/components/signin/core/browser/signin_metrics.cc b/chromium/components/signin/core/browser/signin_metrics.cc
index 21f5feee326..33dae6f6b12 100644
--- a/chromium/components/signin/core/browser/signin_metrics.cc
+++ b/chromium/components/signin/core/browser/signin_metrics.cc
@@ -235,7 +235,7 @@ void RecordSigninNotDefaultUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
NOTREACHED() << "Signin_SigninNotDefault_From* user actions"
- << " are not recorded for access_point "
+ << " are not recorded for access point "
<< static_cast<int>(access_point)
<< " as it does not support a personalized sign-in promo.";
break;
@@ -299,10 +299,17 @@ void RecordSigninNewAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_RESIGNIN_INFOBAR:
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
- NOTREACHED() << "Signin_SigninNewAccount_From* user actions"
- << " are not recorded for access_point "
- << static_cast<int>(access_point)
- << " as it does not support a personalized sign-in promo.";
+ // These access points do not support personalized sign-in promos, so
+ // |Signin_SigninNewAccount_From*| user actions should not be recorded
+ // for them.
+ // Note: To avoid bloating the sign-in APIs, the sign-in metrics simply
+ // ignore if the caller passes |PROMO_ACTION_NEW_ACCOUNT| when a the
+ // sign-in flow is started from any access point instead of treating it
+ // and an error like in the other cases (|WithDefault| and |NotDefault|).
+ VLOG(1) << "Signin_SigninNewAccount_From* user actions"
+ << " are not recorded for access point "
+ << static_cast<int>(access_point)
+ << " as it does not support a personalized sign-in promo.";
break;
case AccessPoint::ACCESS_POINT_MAX:
NOTREACHED();
@@ -685,7 +692,7 @@ void RecordSigninImpressionUserActionForAccessPoint(AccessPoint access_point) {
case AccessPoint::ACCESS_POINT_USER_MANAGER:
case AccessPoint::ACCESS_POINT_UNKNOWN:
NOTREACHED() << "Signin_Impression_From* user actions"
- << " are not recorded for access_point "
+ << " are not recorded for access point "
<< static_cast<int>(access_point);
break;
case AccessPoint::ACCESS_POINT_MAX:
@@ -795,7 +802,7 @@ void RecordSigninImpressionWithAccountUserActionForAccessPoint(
case AccessPoint::ACCESS_POINT_UNKNOWN:
case AccessPoint::ACCESS_POINT_FORCE_SIGNIN_WARNING:
NOTREACHED() << "Signin_Impression{With|WithNo}Account_From* user actions"
- << " are not recorded for access_point "
+ << " are not recorded for access point "
<< static_cast<int>(access_point)
<< " as it does not support a personalized sign-in promo.";
break;
diff --git a/chromium/components/signin/core/browser/signin_metrics_unittest.cc b/chromium/components/signin/core/browser/signin_metrics_unittest.cc
index 5361634a935..ddadafbdb76 100644
--- a/chromium/components/signin/core/browser/signin_metrics_unittest.cc
+++ b/chromium/components/signin/core/browser/signin_metrics_unittest.cc
@@ -113,6 +113,13 @@ class SigninMetricsTest : public ::testing::Test {
}
return access_points;
}
+
+ static bool AccessPointSupportsPersonalizedPromo(AccessPoint access_point) {
+ return std::find(std::begin(kAccessPointsThatSupportPersonalizedPromos),
+ std::end(kAccessPointsThatSupportPersonalizedPromos),
+ access_point) !=
+ std::end(kAccessPointsThatSupportPersonalizedPromos);
+ }
};
TEST_F(SigninMetricsTest, RecordSigninUserActionForAccessPoint) {
@@ -145,14 +152,22 @@ TEST_F(SigninMetricsTest, RecordSigninUserActionWithPromoAction) {
1, user_action_tester.GetActionCount("Signin_SigninNotDefault_From" +
GetAccessPointDescription(ap)));
}
- {
- // PROMO_ACTION_NEW_ACCOUNT promo action
- base::UserActionTester user_action_tester;
- RecordSigninUserActionForAccessPoint(
- ap, signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT);
+ }
+}
+
+TEST_F(SigninMetricsTest, RecordSigninUserActionWithNewPromoAction) {
+ for (const AccessPoint& ap : GetAllAccessPoints()) {
+ base::UserActionTester user_action_tester;
+ RecordSigninUserActionForAccessPoint(
+ ap, signin_metrics::PromoAction::PROMO_ACTION_NEW_ACCOUNT);
+ if (AccessPointSupportsPersonalizedPromo(ap)) {
EXPECT_EQ(
1, user_action_tester.GetActionCount("Signin_SigninNewAccount_From" +
GetAccessPointDescription(ap)));
+ } else {
+ EXPECT_EQ(
+ 0, user_action_tester.GetActionCount("Signin_SigninNewAccount_From" +
+ GetAccessPointDescription(ap)));
}
}
}
diff --git a/chromium/components/signin/core/browser/signin_pref_names.cc b/chromium/components/signin/core/browser/signin_pref_names.cc
index efc5bf6d9c3..0215ef02439 100644
--- a/chromium/components/signin/core/browser/signin_pref_names.cc
+++ b/chromium/components/signin/core/browser/signin_pref_names.cc
@@ -33,17 +33,14 @@ const char kGaiaCookieChangedTime[] = "gaia_cookie.changed_time";
// double that should be converted into base::Time.
const char kGaiaCookiePeriodicReportTime[] = "gaia_cookie.periodic_report_time";
-// The profile's hosted domain; empty if unset;
-// AccountTrackerService::kNoHostedDomainFound if there is none.
-
// Typically contains an obfuscated gaiaid and will match the value of
// kGoogleServicesUserAccountId. Some platforms and legacy clients may have
// an email stored in this preference instead. This is transitional and will
// eventually be fixed, allowing the removal of kGoogleServicesUserAccountId.
const char kGoogleServicesAccountId[] = "google.services.account_id";
-// The profile's hosted domain; empty if unset; Profile::kNoHostedDomainFound
-// if there is none.
+// The profile's hosted domain; empty if unset;
+// AccountTrackerService::kNoHostedDomainFound if there is none.
const char kGoogleServicesHostedDomain[] = "google.services.hosted_domain";
// Similar to kGoogleServicesLastUsername, this is the corresponding version of
diff --git a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h b/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h
index bd3287cc52e..9fabc729041 100644
--- a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h
+++ b/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.h
@@ -23,7 +23,6 @@ class FakeProfileOAuth2TokenServiceIOSProvider
// ProfileOAuth2TokenServiceIOSProvider
void GetAccessToken(const std::string& account_id,
const std::string& client_id,
- const std::string& client_secret,
const std::set<std::string>& scopes,
const AccessTokenCallback& callback) override;
std::vector<AccountInfo> GetAllAccounts() const override;
diff --git a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm b/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm
index cffec890989..ceed68ee896 100644
--- a/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm
+++ b/chromium/components/signin/ios/browser/fake_profile_oauth2_token_service_ios_provider.mm
@@ -24,7 +24,6 @@ FakeProfileOAuth2TokenServiceIOSProvider::
void FakeProfileOAuth2TokenServiceIOSProvider::GetAccessToken(
const std::string& account_id,
const std::string& client_id,
- const std::string& client_secret,
const std::set<std::string>& scopes,
const AccessTokenCallback& callback) {
requests_.push_back(AccessTokenRequest(account_id, callback));
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
index a34d4127db6..f3089c309b5 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -13,7 +13,6 @@
#include "base/bind.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
@@ -114,11 +113,11 @@ SSOAccessTokenFetcher::~SSOAccessTokenFetcher() {
}
void SSOAccessTokenFetcher::Start(const std::string& client_id,
- const std::string& client_secret,
+ const std::string& client_secret_unused,
const std::vector<std::string>& scopes) {
std::set<std::string> scopes_set(scopes.begin(), scopes.end());
provider_->GetAccessToken(
- account_.gaia, client_id, client_secret, scopes_set,
+ account_.gaia, client_id, scopes_set,
base::Bind(&SSOAccessTokenFetcher::OnAccessTokenResponse,
weak_factory_.GetWeakPtr()));
}
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h
index 4bd55c36d44..2696f19c368 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.h
@@ -60,7 +60,6 @@ class ProfileOAuth2TokenServiceIOSProvider {
// the given |scopes|. Once the token is obtained, |callback| is called.
virtual void GetAccessToken(const std::string& gaia_id,
const std::string& client_id,
- const std::string& client_secret,
const std::set<std::string>& scopes,
const AccessTokenCallback& callback);
diff --git a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm
index 0ddcca0b5fa..f7b511916d3 100644
--- a/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm
+++ b/chromium/components/signin/ios/browser/profile_oauth2_token_service_ios_provider.mm
@@ -16,7 +16,6 @@ ProfileOAuth2TokenServiceIOSProvider::GetAllAccounts() const {
void ProfileOAuth2TokenServiceIOSProvider::GetAccessToken(
const std::string& gaia_id,
const std::string& client_id,
- const std::string& client_secret,
const std::set<std::string>& scopes,
const AccessTokenCallback& callback) {}
diff --git a/chromium/components/signin/public/interfaces/OWNERS b/chromium/components/signin/public/interfaces/OWNERS
deleted file mode 100644
index 08850f42120..00000000000
--- a/chromium/components/signin/public/interfaces/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file *.mojom=set noparent
-per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
index bfc0165d307..1c173bd5301 100644
--- a/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
+++ b/chromium/components/spellcheck/browser/spellchecker_session_bridge_android.cc
@@ -139,4 +139,8 @@ SpellCheckerSessionBridge::SpellingRequest::SpellingRequest(
RequestTextCheckCallback callback)
: text_(text), callback_(std::move(callback)) {}
-SpellCheckerSessionBridge::SpellingRequest::~SpellingRequest() {}
+SpellCheckerSessionBridge::SpellingRequest::~SpellingRequest() {
+ // Ensure that we don't clear an uncalled RequestTextCheckCallback
+ if (callback_)
+ std::move(callback_).Run(std::vector<SpellCheckResult>());
+}
diff --git a/chromium/components/spellcheck/browser/spelling_service_client.cc b/chromium/components/spellcheck/browser/spelling_service_client.cc
index e8afa352631..b86eb56de37 100644
--- a/chromium/components/spellcheck/browser/spelling_service_client.cc
+++ b/chromium/components/spellcheck/browser/spelling_service_client.cc
@@ -233,7 +233,7 @@ bool SpellingServiceClient::ParseResponse(
static_cast<base::DictionaryValue*>(
base::JSONReader::Read(data, base::JSON_ALLOW_TRAILING_COMMAS)
.release()));
- if (!value.get() || !value->is_dict())
+ if (!value || !value->is_dict())
return false;
// Check for errors from spelling service.
diff --git a/chromium/components/spellcheck/common/BUILD.gn b/chromium/components/spellcheck/common/BUILD.gn
index 9bc49dafaac..cf40a73972c 100644
--- a/chromium/components/spellcheck/common/BUILD.gn
+++ b/chromium/components/spellcheck/common/BUILD.gn
@@ -41,7 +41,6 @@ mojom("interfaces") {
}
public_deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
]
diff --git a/chromium/components/spellcheck/common/spellcheck.mojom b/chromium/components/spellcheck/common/spellcheck.mojom
index 6627292626d..5587d26fc62 100644
--- a/chromium/components/spellcheck/common/spellcheck.mojom
+++ b/chromium/components/spellcheck/common/spellcheck.mojom
@@ -12,7 +12,7 @@ import "mojo/public/mojom/base/string16.mojom";
//
interface SpellChecker {
// Initialize the render process spellchecker. Called after startup and
- // also in response to a renderer's spellcheck::mojom::SpellCheckHost
+ // also in response to a renderer's spellcheck.mojom.SpellCheckHost
// RequestDictionary request.
Initialize(array<SpellCheckBDictLanguage> dictionaries,
array<string> custom_words,
@@ -34,7 +34,7 @@ struct SpellCheckBDictLanguage {
//
interface SpellCheckHost {
// Asks the browser to initialize the renderer's spellcheck system. The
- // initialize call arrives on interface spellcheck::mojom::SpellChecker
+ // initialize call arrives on interface spellcheck.mojom.SpellChecker
// in async response to this request.
RequestDictionary();
diff --git a/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc b/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc
index 635316cacfa..0e945cdfa82 100644
--- a/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc
+++ b/chromium/components/spellcheck/renderer/custom_dictionary_engine_unittest.cc
@@ -10,18 +10,16 @@ TEST(CustomDictionaryTest, HandlesEmptyWordWithInvalidSubstring) {
CustomDictionaryEngine engine;
std::set<std::string> custom_words;
engine.Init(custom_words);
- EXPECT_FALSE(engine.SpellCheckWord(base::string16().c_str(), 15, 23));
+ EXPECT_FALSE(engine.SpellCheckWord(base::string16(), 15, 23));
}
TEST(CustomDictionaryTest, Basic) {
CustomDictionaryEngine engine;
- EXPECT_FALSE(engine.SpellCheckWord(base::ASCIIToUTF16("helllo").c_str(),
- 0, 6));
+ EXPECT_FALSE(engine.SpellCheckWord(base::ASCIIToUTF16("helllo"), 0, 6));
std::set<std::string> custom_words;
custom_words.insert("helllo");
engine.Init(custom_words);
- EXPECT_TRUE(engine.SpellCheckWord(base::ASCIIToUTF16("helllo").c_str(),
- 0, 6));
+ EXPECT_TRUE(engine.SpellCheckWord(base::ASCIIToUTF16("helllo"), 0, 6));
}
TEST(CustomDictionaryTest, HandlesNullCharacters) {
diff --git a/chromium/components/spellcheck/renderer/hunspell_engine.cc b/chromium/components/spellcheck/renderer/hunspell_engine.cc
index e8b0ef079a7..78d62802755 100644
--- a/chromium/components/spellcheck/renderer/hunspell_engine.cc
+++ b/chromium/components/spellcheck/renderer/hunspell_engine.cc
@@ -66,7 +66,7 @@ void HunspellEngine::Init(base::File file) {
}
void HunspellEngine::InitializeHunspell() {
- if (hunspell_.get())
+ if (hunspell_)
return;
bdict_file_.reset(new base::MemoryMappedFile);
@@ -90,7 +90,7 @@ bool HunspellEngine::CheckSpelling(const base::string16& word_to_check,
if (word_to_check_utf8.length() <= kMaxCheckedLen) {
// If |hunspell_| is NULL here, an error has occurred, but it's better
// to check rather than crash.
- if (hunspell_.get()) {
+ if (hunspell_) {
// |hunspell_->spell| returns 0 if the word is misspelled.
word_correct = (hunspell_->spell(word_to_check_utf8) != 0);
}
@@ -109,7 +109,7 @@ void HunspellEngine::FillSuggestionList(
// If |hunspell_| is NULL here, an error has occurred, but it's better
// to check rather than crash.
// TODO(groby): Technically, it's not. We should track down the issue.
- if (!hunspell_.get())
+ if (!hunspell_)
return;
std::vector<std::string> suggestions =
diff --git a/chromium/components/spellcheck/renderer/spellcheck.cc b/chromium/components/spellcheck/renderer/spellcheck.cc
index 097917cb9ea..67e8aa823ea 100644
--- a/chromium/components/spellcheck/renderer/spellcheck.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck.cc
@@ -65,29 +65,12 @@ bool UpdateSpellcheckEnabled::Visit(content::RenderFrame* render_frame) {
return true;
}
-class DocumentMarkersRemover : public content::RenderFrameVisitor {
- public:
- explicit DocumentMarkersRemover(const std::set<std::string>& words);
- ~DocumentMarkersRemover() override {}
- bool Visit(content::RenderFrame* render_frame) override;
-
- private:
- WebVector<WebString> words_;
- DISALLOW_COPY_AND_ASSIGN(DocumentMarkersRemover);
-};
-
-DocumentMarkersRemover::DocumentMarkersRemover(
- const std::set<std::string>& words)
- : words_(words.size()) {
- std::transform(words.begin(), words.end(), words_.begin(),
+WebVector<WebString> ConvertToWebStringFromUtf8(
+ const std::set<std::string>& words) {
+ WebVector<WebString> result(words.size());
+ std::transform(words.begin(), words.end(), result.begin(),
[](const std::string& w) { return WebString::FromUTF8(w); });
-}
-
-bool DocumentMarkersRemover::Visit(content::RenderFrame* render_frame) {
- // TODO(xiaochengh): Both nullptr checks seem unnecessary.
- if (render_frame && render_frame->GetWebFrame())
- render_frame->GetWebFrame()->RemoveSpellingMarkersUnderWords(words_);
- return true;
+ return result;
}
bool IsApostrophe(base::char16 c) {
@@ -245,14 +228,9 @@ void SpellCheck::CustomDictionaryChanged(
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) {
const std::set<std::string> added(words_added.begin(), words_added.end());
-
+ NotifyDictionaryObservers(ConvertToWebStringFromUtf8(added));
custom_dictionary_.OnCustomDictionaryChanged(
added, std::set<std::string>(words_removed.begin(), words_removed.end()));
- if (added.empty())
- return;
-
- DocumentMarkersRemover markersRemover(added);
- content::RenderFrame::ForEach(&markersRemover);
}
// TODO(groby): Make sure we always have a spelling engine, even before
@@ -411,7 +389,7 @@ void SpellCheck::RequestTextChecking(
const base::string16& text,
blink::WebTextCheckingCompletion* completion) {
// Clean up the previous request before starting a new request.
- if (pending_request_param_.get())
+ if (pending_request_param_)
pending_request_param_->completion()->DidCancelCheckingText();
pending_request_param_.reset(new SpellcheckRequest(
@@ -533,3 +511,20 @@ bool SpellCheck::IsSpellcheckEnabled() {
#endif
return spellcheck_enabled_;
}
+
+void SpellCheck::AddDictionaryUpdateObserver(
+ DictionaryUpdateObserver* observer) {
+ return dictionary_update_observers_.AddObserver(observer);
+}
+
+void SpellCheck::RemoveDictionaryUpdateObserver(
+ DictionaryUpdateObserver* observer) {
+ return dictionary_update_observers_.RemoveObserver(observer);
+}
+
+void SpellCheck::NotifyDictionaryObservers(
+ const WebVector<WebString>& words_added) {
+ for (auto& observer : dictionary_update_observers_) {
+ observer.OnDictionaryUpdated(words_added);
+ }
+}
diff --git a/chromium/components/spellcheck/renderer/spellcheck.h b/chromium/components/spellcheck/renderer/spellcheck.h
index f5617c68f45..58debac3fb1 100644
--- a/chromium/components/spellcheck/renderer/spellcheck.h
+++ b/chromium/components/spellcheck/renderer/spellcheck.h
@@ -14,6 +14,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/observer_list.h"
#include "base/strings/string16.h"
#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/spellcheck/renderer/custom_dictionary_engine.h"
@@ -28,12 +29,22 @@ namespace blink {
class WebTextCheckingCompletion;
struct WebTextCheckingResult;
template <typename T> class WebVector;
+class WebString;
}
namespace service_manager {
class LocalInterfaceProvider;
}
+class DictionaryUpdateObserver {
+ public:
+ virtual ~DictionaryUpdateObserver() = default;
+ // |words_added| is newly added words to dictionary as correct words.
+ // OnDictionaryUpdated should be called even if |words_added| empty.
+ virtual void OnDictionaryUpdated(
+ const blink::WebVector<blink::WebString>& words_added) = 0;
+};
+
// TODO(morrita): Needs reorg with SpellCheckProvider.
// See http://crbug.com/73699.
// Shared spellchecking logic/data for a RenderProcess. All RenderViews use
@@ -109,6 +120,11 @@ class SpellCheck : public base::SupportsWeakPtr<SpellCheck>,
bool IsSpellcheckEnabled();
+ // Add observer on dictionary update event.
+ void AddDictionaryUpdateObserver(DictionaryUpdateObserver* observer);
+ // Remove observer on dictionary update event.
+ void RemoveDictionaryUpdateObserver(DictionaryUpdateObserver* observer);
+
private:
friend class SpellCheckTest;
FRIEND_TEST_ALL_PREFIXES(SpellCheckTest, GetAutoCorrectionWord_EN_US);
@@ -135,6 +151,10 @@ class SpellCheck : public base::SupportsWeakPtr<SpellCheck>,
const std::vector<std::string>& words_added,
const std::vector<std::string>& words_removed) override;
+ // Performs dictionary update notification.
+ void NotifyDictionaryObservers(
+ const blink::WebVector<blink::WebString>& words_added);
+
#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER)
// Posts delayed spellcheck task and clear it if any.
// Takes ownership of |request|.
@@ -166,6 +186,9 @@ class SpellCheck : public base::SupportsWeakPtr<SpellCheck>,
// Remember state for spellchecking.
bool spellcheck_enabled_;
+ // Observers of update dictionary events.
+ base::ObserverList<DictionaryUpdateObserver> dictionary_update_observers_;
+
base::WeakPtrFactory<SpellCheck> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SpellCheck);
diff --git a/chromium/components/spellcheck/renderer/spellcheck_language.cc b/chromium/components/spellcheck/renderer/spellcheck_language.cc
index 1068d894847..a518c43cac6 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_language.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_language.cc
@@ -19,7 +19,7 @@ SpellcheckLanguage::~SpellcheckLanguage() {
}
void SpellcheckLanguage::Init(base::File file, const std::string& language) {
- DCHECK(platform_spelling_engine_.get());
+ DCHECK(platform_spelling_engine_);
platform_spelling_engine_->Init(std::move(file));
character_attributes_.SetDefaultLanguage(language);
@@ -28,7 +28,7 @@ void SpellcheckLanguage::Init(base::File file, const std::string& language) {
}
bool SpellcheckLanguage::InitializeIfNeeded() {
- DCHECK(platform_spelling_engine_.get());
+ DCHECK(platform_spelling_engine_);
return platform_spelling_engine_->InitializeIfNeeded();
}
@@ -51,8 +51,7 @@ SpellcheckLanguage::SpellcheckWordResult SpellcheckLanguage::SpellCheckWord(
return IS_CORRECT;
// Do nothing if spell checking is disabled.
- if (!platform_spelling_engine_.get() ||
- !platform_spelling_engine_->IsEnabled())
+ if (!platform_spelling_engine_ || !platform_spelling_engine_->IsEnabled())
return IS_CORRECT;
*skip_or_misspelling_start = 0;
@@ -71,7 +70,7 @@ SpellcheckLanguage::SpellcheckWordResult SpellcheckLanguage::SpellCheckWord(
}
text_iterator_.SetText(text_begin + position_in_text, remaining_text_len);
- DCHECK(platform_spelling_engine_.get());
+ DCHECK(platform_spelling_engine_);
for (SpellcheckWordIterator::WordIteratorStatus status =
text_iterator_.GetNextWord(&word, &word_start, &word_length);
status != SpellcheckWordIterator::IS_END_OF_TEXT;
@@ -130,7 +129,7 @@ bool SpellcheckLanguage::IsValidContraction(const base::string16& contraction,
int word_start;
int word_length;
- DCHECK(platform_spelling_engine_.get());
+ DCHECK(platform_spelling_engine_);
for (SpellcheckWordIterator::WordIteratorStatus status =
contraction_iterator_.GetNextWord(&word, &word_start, &word_length);
status != SpellcheckWordIterator::IS_END_OF_TEXT;
@@ -146,6 +145,6 @@ bool SpellcheckLanguage::IsValidContraction(const base::string16& contraction,
}
bool SpellcheckLanguage::IsEnabled() {
- DCHECK(platform_spelling_engine_.get());
+ DCHECK(platform_spelling_engine_);
return platform_spelling_engine_->IsEnabled();
}
diff --git a/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
index 117d65ba47d..622e4a60b71 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_multilingual_unittest.cc
@@ -37,7 +37,7 @@ struct SpellcheckTestCase {
base::FilePath GetHunspellDirectory() {
base::FilePath hunspell_directory;
- if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory))
+ if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory))
return base::FilePath();
hunspell_directory = hunspell_directory.AppendASCII("third_party");
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.cc b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
index 8bf21f69f6d..1e255d2a6a7 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.cc
@@ -38,6 +38,44 @@ static_assert(int(blink::kWebTextDecorationTypeGrammar) ==
int(SpellCheckResult::GRAMMAR),
"mismatching enums");
+class SpellCheckProvider::DictionaryUpdateObserverImpl
+ : public DictionaryUpdateObserver {
+ public:
+ explicit DictionaryUpdateObserverImpl(SpellCheckProvider* owner);
+ ~DictionaryUpdateObserverImpl() override;
+
+ // DictionaryUpdateObserver:
+ void OnDictionaryUpdated(const WebVector<WebString>& words_added) override;
+
+ private:
+ SpellCheckProvider* owner_;
+};
+
+SpellCheckProvider::DictionaryUpdateObserverImpl::DictionaryUpdateObserverImpl(
+ SpellCheckProvider* owner)
+ : owner_(owner) {
+ owner_->spellcheck_->AddDictionaryUpdateObserver(this);
+}
+
+SpellCheckProvider::DictionaryUpdateObserverImpl::
+ ~DictionaryUpdateObserverImpl() {
+ owner_->spellcheck_->RemoveDictionaryUpdateObserver(this);
+}
+
+void SpellCheckProvider::DictionaryUpdateObserverImpl::OnDictionaryUpdated(
+ const WebVector<WebString>& words_added) {
+ // Clear only cache. Current pending requests should continue as they are.
+ owner_->last_request_.clear();
+ owner_->last_results_.Assign(
+ blink::WebVector<blink::WebTextCheckingResult>());
+
+ // owner_->render_frame() is nullptr in unit tests.
+ if (auto* render_frame = owner_->render_frame()) {
+ DCHECK(render_frame->GetWebFrame());
+ render_frame->GetWebFrame()->RemoveSpellingMarkersUnderWords(words_added);
+ }
+}
+
SpellCheckProvider::SpellCheckProvider(
content::RenderFrame* render_frame,
SpellCheck* spellcheck,
@@ -51,11 +89,18 @@ SpellCheckProvider::SpellCheckProvider(
DCHECK(embedder_provider);
if (render_frame) // NULL in unit tests.
render_frame->GetWebFrame()->SetTextCheckClient(this);
+
+ dictionary_update_observer_ =
+ std::make_unique<DictionaryUpdateObserverImpl>(this);
}
SpellCheckProvider::~SpellCheckProvider() {
}
+void SpellCheckProvider::ResetDictionaryUpdateObserverForTesting() {
+ dictionary_update_observer_.reset();
+}
+
spellcheck::mojom::SpellCheckHost& SpellCheckProvider::GetSpellCheckHost() {
if (spell_check_host_)
return *spell_check_host_;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider.h b/chromium/components/spellcheck/renderer/spellcheck_provider.h
index 79b55aa041b..d14270743fb 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_H_
#define COMPONENTS_SPELLCHECK_RENDERER_SPELLCHECK_PROVIDER_H_
+#include <memory>
#include <vector>
#include "base/containers/id_map.h"
@@ -63,12 +64,16 @@ class SpellCheckProvider
private:
friend class TestingSpellCheckProvider;
+ class DictionaryUpdateObserverImpl;
// Sets the SpellCheckHost (for unit tests).
void SetSpellCheckHostForTesting(spellcheck::mojom::SpellCheckHostPtr host) {
spell_check_host_ = std::move(host);
}
+ // Reset dictionary_update_observer_ in TestingSpellCheckProvider dtor.
+ void ResetDictionaryUpdateObserverForTesting();
+
// Returns the SpellCheckHost.
spellcheck::mojom::SpellCheckHost& GetSpellCheckHost();
@@ -129,6 +134,9 @@ class SpellCheckProvider
// Interface to the SpellCheckHost.
spellcheck::mojom::SpellCheckHostPtr spell_check_host_;
+ // Dictionary updated observer.
+ std::unique_ptr<DictionaryUpdateObserverImpl> dictionary_update_observer_;
+
base::WeakPtrFactory<SpellCheckProvider> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SpellCheckProvider);
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
index b82647b6986..94fb1eb4273 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.cc
@@ -7,6 +7,7 @@
#include <memory>
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "components/spellcheck/common/spellcheck.mojom.h"
#include "components/spellcheck/common/spellcheck_result.h"
@@ -43,13 +44,15 @@ TestingSpellCheckProvider::TestingSpellCheckProvider(
TestingSpellCheckProvider::~TestingSpellCheckProvider() {
binding_.Close();
+ // dictionary_update_observer_ must be released before deleting spellcheck_.
+ ResetDictionaryUpdateObserverForTesting();
delete spellcheck_;
}
void TestingSpellCheckProvider::RequestTextChecking(
const base::string16& text,
blink::WebTextCheckingCompletion* completion) {
- if (!loop_ && !base::MessageLoop::current())
+ if (!loop_ && !base::MessageLoopCurrent::Get())
loop_ = std::make_unique<base::MessageLoop>();
if (!binding_.is_bound()) {
spellcheck::mojom::SpellCheckHostPtr host_proxy;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
index 5e0cfbf0675..9e8534e46b3 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_test.h
@@ -70,6 +70,9 @@ class TestingSpellCheckProvider : public SpellCheckProvider,
std::vector<RequestTextCheckParams> text_check_requests_;
#endif
+ // Returns |spellcheck|.
+ SpellCheck* spellcheck() { return spellcheck_; }
+
private:
// spellcheck::mojom::SpellCheckHost:
void RequestDictionary() override;
diff --git a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
index 555e7183c31..64d9f3c5a92 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_provider_unittest.cc
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/strings/utf_string_conversions.h"
#include "components/spellcheck/renderer/spellcheck_provider_test.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/spellcheck/renderer/spellcheck.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
@@ -12,7 +14,17 @@
namespace {
-class SpellCheckProviderCacheTest : public SpellCheckProviderTest {};
+class SpellCheckProviderCacheTest : public SpellCheckProviderTest {
+ protected:
+ void UpdateCustomDictionary() {
+ SpellCheck* spellcheck = provider_.spellcheck();
+ EXPECT_NE(spellcheck, nullptr);
+ // Skip adding friend class - use public CustomDictionaryChanged from
+ // |spellcheck::mojom::SpellChecker|
+ static_cast<spellcheck::mojom::SpellChecker*>(spellcheck)
+ ->CustomDictionaryChanged({}, {});
+ }
+};
TEST_F(SpellCheckProviderCacheTest, SubstringWithoutMisspellings) {
FakeTextCheckingCompletion completion;
@@ -49,4 +61,17 @@ TEST_F(SpellCheckProviderCacheTest, ShorterTextNotSubstring) {
EXPECT_EQ(completion.completion_count_, 0U);
}
+TEST_F(SpellCheckProviderCacheTest, ResetCacheOnCustomDictionaryUpdate) {
+ FakeTextCheckingCompletion completion;
+
+ blink::WebVector<blink::WebTextCheckingResult> last_results;
+ provider_.SetLastResults(base::ASCIIToUTF16("This is a test"), last_results);
+
+ UpdateCustomDictionary();
+
+ EXPECT_FALSE(provider_.SatisfyRequestFromCache(
+ base::ASCIIToUTF16("This is a"), &completion));
+ EXPECT_EQ(completion.completion_count_, 0U);
+}
+
} // namespace
diff --git a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
index 9cf02513416..5de044a05fc 100644
--- a/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
+++ b/chromium/components/spellcheck/renderer/spellcheck_unittest.cc
@@ -37,7 +37,7 @@ const int kNoTag = 0;
base::FilePath GetHunspellDirectory() {
base::FilePath hunspell_directory;
- if (!PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory))
+ if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &hunspell_directory))
return base::FilePath();
hunspell_directory = hunspell_directory.AppendASCII("third_party");
diff --git a/chromium/components/ssl_config/BUILD.gn b/chromium/components/ssl_config/BUILD.gn
deleted file mode 100644
index 4f3bca7933f..00000000000
--- a/chromium/components/ssl_config/BUILD.gn
+++ /dev/null
@@ -1,38 +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.
-
-static_library("ssl_config") {
- sources = [
- "ssl_config_prefs.cc",
- "ssl_config_prefs.h",
- "ssl_config_service_manager.h",
- "ssl_config_service_manager_pref.cc",
- "ssl_config_switches.cc",
- "ssl_config_switches.h",
- ]
-
- deps = [
- "//base",
- "//components/content_settings/core/browser",
- "//components/content_settings/core/common",
- "//components/prefs",
- "//net",
- ]
-}
-
-source_set("unit_tests") {
- testonly = true
- sources = [
- "ssl_config_service_manager_pref_unittest.cc",
- ]
- deps = [
- ":ssl_config",
- "//base",
- "//base/test:test_support",
- "//components/prefs:test_support",
- "//components/variations:test_support",
- "//net",
- "//testing/gtest",
- ]
-}
diff --git a/chromium/components/ssl_config/DEPS b/chromium/components/ssl_config/DEPS
deleted file mode 100644
index 35579bbf62b..00000000000
--- a/chromium/components/ssl_config/DEPS
+++ /dev/null
@@ -1,9 +0,0 @@
-include_rules = [
- "+components/content_settings/core/browser",
- "+components/content_settings/core/common",
- "+components/prefs",
- "+components/variations",
- "+net/socket",
- "+net/ssl",
-]
-
diff --git a/chromium/components/ssl_config/OWNERS b/chromium/components/ssl_config/OWNERS
deleted file mode 100644
index 019db92cacc..00000000000
--- a/chromium/components/ssl_config/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-agl@chromium.org
-davidben@chromium.org
-rsleevi@chromium.org
-
-# COMPONENT: Internals>Network>SSL
diff --git a/chromium/components/ssl_config/ssl_config_prefs.cc b/chromium/components/ssl_config/ssl_config_prefs.cc
deleted file mode 100644
index 790159d7228..00000000000
--- a/chromium/components/ssl_config/ssl_config_prefs.cc
+++ /dev/null
@@ -1,23 +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 "components/ssl_config/ssl_config_prefs.h"
-
-namespace ssl_config {
-namespace prefs {
-
-// Prefs for SSLConfigServicePref.
-const char kCertRevocationCheckingEnabled[] = "ssl.rev_checking.enabled";
-const char kCertRevocationCheckingRequiredLocalAnchors[] =
- "ssl.rev_checking.required_for_local_anchors";
-const char kCertEnableSha1LocalAnchors[] = "ssl.sha1_enabled_for_local_anchors";
-const char kCertEnableSymantecLegacyInfrastructure[] =
- "ssl.enable_symantec_legacy_infrastructure";
-const char kSSLVersionMin[] = "ssl.version_min";
-const char kSSLVersionMax[] = "ssl.version_max";
-const char kTLS13Variant[] = "ssl.tls13_variant";
-const char kCipherSuiteBlacklist[] = "ssl.cipher_suites.blacklist";
-
-} // namespace prefs
-} // namespace ssl_config
diff --git a/chromium/components/ssl_config/ssl_config_prefs.h b/chromium/components/ssl_config/ssl_config_prefs.h
deleted file mode 100644
index 3f3b8b83960..00000000000
--- a/chromium/components/ssl_config/ssl_config_prefs.h
+++ /dev/null
@@ -1,23 +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 COMPONENTS_SSL_CONFIG_SSL_CONFIG_PREFS_H_
-#define COMPONENTS_SSL_CONFIG_SSL_CONFIG_PREFS_H_
-
-namespace ssl_config {
-namespace prefs {
-
-extern const char kCertRevocationCheckingEnabled[];
-extern const char kCertRevocationCheckingRequiredLocalAnchors[];
-extern const char kCertEnableSha1LocalAnchors[];
-extern const char kCertEnableSymantecLegacyInfrastructure[];
-extern const char kSSLVersionMin[];
-extern const char kSSLVersionMax[];
-extern const char kTLS13Variant[];
-extern const char kCipherSuiteBlacklist[];
-
-} // namespace prefs
-} // namespace ssl_config
-
-#endif // COMPONENTS_SSL_CONFIG_SSL_CONFIG_PREFS_H_
diff --git a/chromium/components/ssl_config/ssl_config_service_manager.h b/chromium/components/ssl_config/ssl_config_service_manager.h
deleted file mode 100644
index 30bc1c08959..00000000000
--- a/chromium/components/ssl_config/ssl_config_service_manager.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_SSL_CONFIG_SSL_CONFIG_SERVICE_MANAGER_H_
-#define COMPONENTS_SSL_CONFIG_SSL_CONFIG_SERVICE_MANAGER_H_
-
-#include "base/memory/ref_counted.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace net {
-class SSLConfigService;
-} // namespace net
-
-class PrefService;
-class PrefRegistrySimple;
-
-namespace ssl_config {
-
-// An interface for creating SSLConfigService objects.
-class SSLConfigServiceManager {
- public:
- // Create an instance of the SSLConfigServiceManager. The lifetime of the
- // PrefService objects must be longer than that of the manager. Get SSL
- // preferences from local_state object.
- static SSLConfigServiceManager* CreateDefaultManager(
- PrefService* local_state,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
-
- static void RegisterPrefs(PrefRegistrySimple* registry);
-
- virtual ~SSLConfigServiceManager() {}
-
- // Get an SSLConfigService instance. It may be a new instance or the manager
- // may return the same instance multiple times.
- // The caller should hold a reference as long as it needs the instance (eg,
- // using scoped_refptr.)
- virtual net::SSLConfigService* Get() = 0;
-};
-
-} // namespace ssl_config
-#endif // COMPONENTS_SSL_CONFIG_SSL_CONFIG_SERVICE_MANAGER_H_
diff --git a/chromium/components/ssl_config/ssl_config_service_manager_pref.cc b/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
deleted file mode 100644
index bd0ba311df2..00000000000
--- a/chromium/components/ssl_config/ssl_config_service_manager_pref.cc
+++ /dev/null
@@ -1,351 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-#include "components/ssl_config/ssl_config_service_manager.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/location.h"
-#include "base/macros.h"
-#include "base/metrics/field_trial_params.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_util.h"
-#include "base/values.h"
-#include "components/content_settings/core/browser/content_settings_utils.h"
-#include "components/content_settings/core/common/content_settings.h"
-#include "components/prefs/pref_change_registrar.h"
-#include "components/prefs/pref_member.h"
-#include "components/prefs/pref_registry_simple.h"
-#include "components/prefs/pref_service.h"
-#include "components/ssl_config/ssl_config_prefs.h"
-#include "components/ssl_config/ssl_config_switches.h"
-#include "net/ssl/ssl_cipher_suite_names.h"
-#include "net/ssl/ssl_config_service.h"
-
-namespace base {
-class SingleThreadTaskRunner;
-}
-
-namespace {
-
-// Converts a ListValue of StringValues into a vector of strings. Any Values
-// which cannot be converted will be skipped.
-std::vector<std::string> ListValueToStringVector(const base::ListValue* value) {
- std::vector<std::string> results;
- results.reserve(value->GetSize());
- std::string s;
- for (base::ListValue::const_iterator it = value->begin(); it != value->end();
- ++it) {
- if (!it->GetAsString(&s))
- continue;
- results.push_back(s);
- }
- return results;
-}
-
-// Parses a vector of cipher suite strings, returning a sorted vector
-// containing the underlying SSL/TLS cipher suites. Unrecognized/invalid
-// cipher suites will be ignored.
-std::vector<uint16_t> ParseCipherSuites(
- const std::vector<std::string>& cipher_strings) {
- std::vector<uint16_t> cipher_suites;
- cipher_suites.reserve(cipher_strings.size());
-
- for (std::vector<std::string>::const_iterator it = cipher_strings.begin();
- it != cipher_strings.end(); ++it) {
- uint16_t cipher_suite = 0;
- if (!net::ParseSSLCipherString(*it, &cipher_suite)) {
- LOG(ERROR) << "Ignoring unrecognized or unparsable cipher suite: " << *it;
- continue;
- }
- cipher_suites.push_back(cipher_suite);
- }
- std::sort(cipher_suites.begin(), cipher_suites.end());
- return cipher_suites;
-}
-
-// Returns the SSL protocol version (as a uint16_t) represented by a string.
-// Returns 0 if the string is invalid.
-uint16_t SSLProtocolVersionFromString(const std::string& version_str) {
- uint16_t version = 0; // Invalid.
- if (version_str == switches::kSSLVersionTLSv1) {
- version = net::SSL_PROTOCOL_VERSION_TLS1;
- } else if (version_str == switches::kSSLVersionTLSv11) {
- version = net::SSL_PROTOCOL_VERSION_TLS1_1;
- } else if (version_str == switches::kSSLVersionTLSv12) {
- version = net::SSL_PROTOCOL_VERSION_TLS1_2;
- } else if (version_str == switches::kSSLVersionTLSv13) {
- version = net::SSL_PROTOCOL_VERSION_TLS1_3;
- }
- return version;
-}
-
-const char kTLS13VariantExperimentName[] = "TLS13Variant";
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// SSLConfigServicePref
-
-// An SSLConfigService which stores a cached version of the current SSLConfig
-// prefs, which are updated by SSLConfigServiceManagerPref when the prefs
-// change.
-class SSLConfigServicePref : public net::SSLConfigService {
- public:
- explicit SSLConfigServicePref(
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
-
- // Store SSL config settings in |config|. Must only be called from IO thread.
- void GetSSLConfig(net::SSLConfig* config) override;
-
- private:
- // Allow the pref watcher to update our internal state.
- friend class SSLConfigServiceManagerPref;
-
- ~SSLConfigServicePref() override {}
-
- // This method is posted to the IO thread from the browser thread to carry the
- // new config information.
- void SetNewSSLConfig(const net::SSLConfig& new_config);
-
- // Cached value of prefs, should only be accessed from IO thread.
- net::SSLConfig cached_config_;
-
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLConfigServicePref);
-};
-
-SSLConfigServicePref::SSLConfigServicePref(
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
- : io_task_runner_(io_task_runner) {}
-
-void SSLConfigServicePref::GetSSLConfig(net::SSLConfig* config) {
- DCHECK(io_task_runner_->BelongsToCurrentThread());
- *config = cached_config_;
-}
-
-void SSLConfigServicePref::SetNewSSLConfig(const net::SSLConfig& new_config) {
- net::SSLConfig orig_config = cached_config_;
- cached_config_ = new_config;
- ProcessConfigUpdate(orig_config, new_config);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SSLConfigServiceManagerPref
-
-// The manager for holding and updating an SSLConfigServicePref instance.
-class SSLConfigServiceManagerPref : public ssl_config::SSLConfigServiceManager {
- public:
- SSLConfigServiceManagerPref(
- PrefService* local_state,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
- ~SSLConfigServiceManagerPref() override {}
-
- // Register local_state SSL preferences.
- static void RegisterPrefs(PrefRegistrySimple* registry);
-
- net::SSLConfigService* Get() override;
-
- private:
- // Callback for preference changes. This will post the changes to the IO
- // thread with SetNewSSLConfig.
- void OnPreferenceChanged(PrefService* prefs, const std::string& pref_name);
-
- // Store SSL config settings in |config|, directly from the preferences. Must
- // only be called from UI thread.
- void GetSSLConfigFromPrefs(net::SSLConfig* config);
-
- // Processes changes to the disabled cipher suites preference, updating the
- // cached list of parsed SSL/TLS cipher suites that are disabled.
- void OnDisabledCipherSuitesChange(PrefService* local_state);
-
- PrefChangeRegistrar local_state_change_registrar_;
-
- // The local_state prefs (should only be accessed from UI thread)
- BooleanPrefMember rev_checking_enabled_;
- BooleanPrefMember rev_checking_required_local_anchors_;
- BooleanPrefMember sha1_local_anchors_enabled_;
- BooleanPrefMember symantec_legacy_infrastructure_enabled_;
- StringPrefMember ssl_version_min_;
- StringPrefMember ssl_version_max_;
- StringPrefMember tls13_variant_;
-
- // The cached list of disabled SSL cipher suites.
- std::vector<uint16_t> disabled_cipher_suites_;
-
- scoped_refptr<SSLConfigServicePref> ssl_config_service_;
-
- scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
-
- DISALLOW_COPY_AND_ASSIGN(SSLConfigServiceManagerPref);
-};
-
-SSLConfigServiceManagerPref::SSLConfigServiceManagerPref(
- PrefService* local_state,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
- : ssl_config_service_(new SSLConfigServicePref(io_task_runner)),
- io_task_runner_(io_task_runner) {
- DCHECK(local_state);
-
- const std::string tls13_variant =
- base::GetFieldTrialParamValue(kTLS13VariantExperimentName, "variant");
- const char* tls13_value = nullptr;
- const char* version_value = nullptr;
- if (tls13_variant == "disabled") {
- tls13_value = switches::kTLS13VariantDisabled;
- } else if (tls13_variant == "draft23") {
- tls13_value = switches::kTLS13VariantDraft23;
- version_value = switches::kSSLVersionTLSv13;
- }
-
- if (tls13_value) {
- local_state->SetDefaultPrefValue(ssl_config::prefs::kTLS13Variant,
- base::Value(tls13_value));
- }
- if (version_value) {
- local_state->SetDefaultPrefValue(ssl_config::prefs::kSSLVersionMax,
- base::Value(version_value));
- }
-
- PrefChangeRegistrar::NamedChangeCallback local_state_callback =
- base::Bind(&SSLConfigServiceManagerPref::OnPreferenceChanged,
- base::Unretained(this), local_state);
-
- rev_checking_enabled_.Init(ssl_config::prefs::kCertRevocationCheckingEnabled,
- local_state, local_state_callback);
- rev_checking_required_local_anchors_.Init(
- ssl_config::prefs::kCertRevocationCheckingRequiredLocalAnchors,
- local_state, local_state_callback);
- sha1_local_anchors_enabled_.Init(
- ssl_config::prefs::kCertEnableSha1LocalAnchors, local_state,
- local_state_callback);
- symantec_legacy_infrastructure_enabled_.Init(
- ssl_config::prefs::kCertEnableSymantecLegacyInfrastructure, local_state,
- local_state_callback);
- ssl_version_min_.Init(ssl_config::prefs::kSSLVersionMin, local_state,
- local_state_callback);
- ssl_version_max_.Init(ssl_config::prefs::kSSLVersionMax, local_state,
- local_state_callback);
- tls13_variant_.Init(ssl_config::prefs::kTLS13Variant, local_state,
- local_state_callback);
-
- local_state_change_registrar_.Init(local_state);
- local_state_change_registrar_.Add(ssl_config::prefs::kCipherSuiteBlacklist,
- local_state_callback);
-
- OnDisabledCipherSuitesChange(local_state);
-
- // Initialize from UI thread. This is okay as there shouldn't be anything on
- // the IO thread trying to access it yet.
- GetSSLConfigFromPrefs(&ssl_config_service_->cached_config_);
-}
-
-// static
-void SSLConfigServiceManagerPref::RegisterPrefs(PrefRegistrySimple* registry) {
- net::SSLConfig default_config;
- registry->RegisterBooleanPref(
- ssl_config::prefs::kCertRevocationCheckingEnabled,
- default_config.rev_checking_enabled);
- registry->RegisterBooleanPref(
- ssl_config::prefs::kCertRevocationCheckingRequiredLocalAnchors,
- default_config.rev_checking_required_local_anchors);
- registry->RegisterBooleanPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
- false);
- registry->RegisterBooleanPref(
- ssl_config::prefs::kCertEnableSymantecLegacyInfrastructure,
- default_config.symantec_enforcement_disabled);
- registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMin,
- std::string());
- registry->RegisterStringPref(ssl_config::prefs::kSSLVersionMax,
- std::string());
- registry->RegisterStringPref(ssl_config::prefs::kTLS13Variant, std::string());
- registry->RegisterListPref(ssl_config::prefs::kCipherSuiteBlacklist);
-}
-
-net::SSLConfigService* SSLConfigServiceManagerPref::Get() {
- return ssl_config_service_.get();
-}
-
-void SSLConfigServiceManagerPref::OnPreferenceChanged(
- PrefService* prefs,
- const std::string& pref_name_in) {
- DCHECK(prefs);
- if (pref_name_in == ssl_config::prefs::kCipherSuiteBlacklist)
- OnDisabledCipherSuitesChange(prefs);
-
- net::SSLConfig new_config;
- GetSSLConfigFromPrefs(&new_config);
-
- // Post a task to |io_loop| with the new configuration, so it can
- // update |cached_config_|.
- io_task_runner_->PostTask(FROM_HERE,
- base::Bind(&SSLConfigServicePref::SetNewSSLConfig,
- ssl_config_service_, new_config));
-}
-
-void SSLConfigServiceManagerPref::GetSSLConfigFromPrefs(
- net::SSLConfig* config) {
- // rev_checking_enabled was formerly a user-settable preference, but now
- // it is managed-only.
- if (rev_checking_enabled_.IsManaged())
- config->rev_checking_enabled = rev_checking_enabled_.GetValue();
- else
- config->rev_checking_enabled = false;
- config->rev_checking_required_local_anchors =
- rev_checking_required_local_anchors_.GetValue();
- config->sha1_local_anchors_enabled = sha1_local_anchors_enabled_.GetValue();
- config->symantec_enforcement_disabled =
- symantec_legacy_infrastructure_enabled_.GetValue();
- std::string version_min_str = ssl_version_min_.GetValue();
- std::string version_max_str = ssl_version_max_.GetValue();
- std::string tls13_variant_str = tls13_variant_.GetValue();
- config->version_min = net::kDefaultSSLVersionMin;
- config->version_max = net::kDefaultSSLVersionMax;
- uint16_t version_min = SSLProtocolVersionFromString(version_min_str);
- uint16_t version_max = SSLProtocolVersionFromString(version_max_str);
- if (version_min) {
- config->version_min = version_min;
- }
- if (version_max && version_max >= net::SSL_PROTOCOL_VERSION_TLS1_2) {
- config->version_max = version_max;
- }
-
- if (tls13_variant_str == switches::kTLS13VariantDisabled) {
- if (config->version_max > net::SSL_PROTOCOL_VERSION_TLS1_2)
- config->version_max = net::SSL_PROTOCOL_VERSION_TLS1_2;
- } else if (tls13_variant_str == switches::kTLS13VariantDraft23) {
- config->tls13_variant = net::kTLS13VariantDraft23;
- }
-
- config->disabled_cipher_suites = disabled_cipher_suites_;
-}
-
-void SSLConfigServiceManagerPref::OnDisabledCipherSuitesChange(
- PrefService* local_state) {
- const base::ListValue* value =
- local_state->GetList(ssl_config::prefs::kCipherSuiteBlacklist);
- disabled_cipher_suites_ = ParseCipherSuites(ListValueToStringVector(value));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// SSLConfigServiceManager
-
-namespace ssl_config {
-// static
-SSLConfigServiceManager* SSLConfigServiceManager::CreateDefaultManager(
- PrefService* local_state,
- const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) {
- return new SSLConfigServiceManagerPref(local_state, io_task_runner);
-}
-
-// static
-void SSLConfigServiceManager::RegisterPrefs(PrefRegistrySimple* registry) {
- SSLConfigServiceManagerPref::RegisterPrefs(registry);
-}
-} // namespace ssl_config
diff --git a/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc b/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
deleted file mode 100644
index fb1a4ad6d31..00000000000
--- a/chromium/components/ssl_config/ssl_config_service_manager_pref_unittest.cc
+++ /dev/null
@@ -1,474 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <memory>
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/values.h"
-#include "components/prefs/testing_pref_service.h"
-#include "components/ssl_config/ssl_config_prefs.h"
-#include "components/ssl_config/ssl_config_service_manager.h"
-#include "components/ssl_config/ssl_config_switches.h"
-#include "components/variations/variations_params_manager.h"
-#include "net/ssl/ssl_config.h"
-#include "net/ssl/ssl_config_service.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using base::ListValue;
-using net::SSLConfig;
-using net::SSLConfigService;
-using ssl_config::SSLConfigServiceManager;
-
-class SSLConfigServiceManagerPrefTest : public testing::Test {
- public:
- SSLConfigServiceManagerPrefTest() {}
-
- protected:
- base::MessageLoop message_loop_;
-};
-
-// Test channel id with no user prefs.
-TEST_F(SSLConfigServiceManagerPrefTest, ChannelIDWithoutUserPrefs) {
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig config;
- config_service->GetSSLConfig(&config);
- EXPECT_TRUE(config.channel_id_enabled);
-}
-
-// Test that cipher suites can be disabled. "Good" refers to the fact that
-// every value is expected to be successfully parsed into a cipher suite.
-TEST_F(SSLConfigServiceManagerPrefTest, GoodDisabledCipherSuites) {
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig old_config;
- config_service->GetSSLConfig(&old_config);
- EXPECT_TRUE(old_config.disabled_cipher_suites.empty());
-
- auto list_value = std::make_unique<base::ListValue>();
- list_value->AppendString("0x0004");
- list_value->AppendString("0x0005");
- local_state.SetUserPref(ssl_config::prefs::kCipherSuiteBlacklist,
- std::move(list_value));
-
- // Pump the message loop to notify the SSLConfigServiceManagerPref that the
- // preferences changed.
- base::RunLoop().RunUntilIdle();
-
- SSLConfig config;
- config_service->GetSSLConfig(&config);
-
- EXPECT_NE(old_config.disabled_cipher_suites, config.disabled_cipher_suites);
- ASSERT_EQ(2u, config.disabled_cipher_suites.size());
- EXPECT_EQ(0x0004, config.disabled_cipher_suites[0]);
- EXPECT_EQ(0x0005, config.disabled_cipher_suites[1]);
-}
-
-// Test that cipher suites can be disabled. "Bad" refers to the fact that
-// there are one or more non-cipher suite strings in the preference. They
-// should be ignored.
-TEST_F(SSLConfigServiceManagerPrefTest, BadDisabledCipherSuites) {
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig old_config;
- config_service->GetSSLConfig(&old_config);
- EXPECT_TRUE(old_config.disabled_cipher_suites.empty());
-
- auto list_value = std::make_unique<base::ListValue>();
- list_value->AppendString("0x0004");
- list_value->AppendString("TLS_NOT_WITH_A_CIPHER_SUITE");
- list_value->AppendString("0x0005");
- list_value->AppendString("0xBEEFY");
- local_state.SetUserPref(ssl_config::prefs::kCipherSuiteBlacklist,
- std::move(list_value));
-
- // Pump the message loop to notify the SSLConfigServiceManagerPref that the
- // preferences changed.
- base::RunLoop().RunUntilIdle();
-
- SSLConfig config;
- config_service->GetSSLConfig(&config);
-
- EXPECT_NE(old_config.disabled_cipher_suites, config.disabled_cipher_suites);
- ASSERT_EQ(2u, config.disabled_cipher_suites.size());
- EXPECT_EQ(0x0004, config.disabled_cipher_suites[0]);
- EXPECT_EQ(0x0005, config.disabled_cipher_suites[1]);
-}
-
-// Test that without command-line settings for minimum and maximum SSL versions,
-// TLS versions from 1.0 up to 1.1 or 1.2 are enabled.
-TEST_F(SSLConfigServiceManagerPrefTest, NoCommandLinePrefs) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- // In the absence of command-line options, the default TLS version range is
- // enabled.
- EXPECT_EQ(net::kDefaultSSLVersionMin, ssl_config.version_min);
- EXPECT_EQ(net::kDefaultSSLVersionMax, ssl_config.version_max);
- EXPECT_EQ(net::kDefaultTLS13Variant, ssl_config.tls13_variant);
-
- // The settings should not be added to the local_state.
- EXPECT_FALSE(local_state.HasPrefPath(ssl_config::prefs::kSSLVersionMin));
- EXPECT_FALSE(local_state.HasPrefPath(ssl_config::prefs::kSSLVersionMax));
- EXPECT_FALSE(local_state.HasPrefPath(ssl_config::prefs::kTLS13Variant));
-
- // Explicitly double-check the settings are not in the preference store.
- std::string version_min_str;
- std::string version_max_str;
- std::string tls13_variant_str;
- EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kSSLVersionMin,
- &version_min_str));
- EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kSSLVersionMax,
- &version_max_str));
- EXPECT_FALSE(local_state_store->GetString(ssl_config::prefs::kTLS13Variant,
- &tls13_variant_str));
-}
-
-// Tests that "ssl3" is not treated as a valid minimum version.
-TEST_F(SSLConfigServiceManagerPrefTest, NoSSL3) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kSSLVersionMin,
- std::make_unique<base::Value>("ssl3"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- // The command-line option must not have been honored.
- EXPECT_LE(net::SSL_PROTOCOL_VERSION_TLS1, ssl_config.version_min);
-}
-
-// Tests that SSLVersionMin correctly sets the minimum version.
-TEST_F(SSLConfigServiceManagerPrefTest, SSLVersionMin) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kSSLVersionMin,
- std::make_unique<base::Value>("tls1.1"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_1, ssl_config.version_min);
-}
-
-// Tests that SSL max version correctly sets the maximum version.
-TEST_F(SSLConfigServiceManagerPrefTest, SSLVersionMax) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- std::make_unique<base::Value>("tls1.3"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
-}
-
-// Tests that SSL max version can not be set below TLS 1.2.
-TEST_F(SSLConfigServiceManagerPrefTest, NoTLS11Max) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- std::make_unique<base::Value>("tls1.1"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- // The command-line option must not have been honored.
- EXPECT_LE(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
-}
-
-// Tests that TLS 1.3 can be disabled via field trials.
-TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantFeatureDisabled) {
- // Toggle the field trial.
- variations::testing::VariationParamsManager variation_params(
- "TLS13Variant", {{"variant", "disabled"}});
-
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
-}
-
-// Tests that Draft23 TLS 1.3 can be enabled via field trials.
-TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantFeatureDraft23) {
- // Toggle the field trial.
- variations::testing::VariationParamsManager variation_params(
- "TLS13Variant", {{"variant", "draft23"}});
-
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
- EXPECT_EQ(net::kTLS13VariantDraft23, ssl_config.tls13_variant);
-}
-
-// Tests that the SSLVersionMax preference overwites the TLS 1.3 variant
-// field trial.
-TEST_F(SSLConfigServiceManagerPrefTest, TLS13SSLVersionMax) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- // Toggle the field trial.
- variations::testing::VariationParamsManager variation_params(
- "TLS13Variant", {{"variant", "draft23"}});
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- std::make_unique<base::Value>("tls1.2"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
-}
-
-// Tests that disabling TLS 1.3 by preference overwrites the TLS 1.3 field
-// trial.
-TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantOverrideDisable) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- // Toggle the field trial.
- variations::testing::VariationParamsManager variation_params(
- "TLS13Variant", {{"variant", "draft23"}});
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kTLS13Variant,
- std::make_unique<base::Value>("disabled"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_2, ssl_config.version_max);
-}
-
-// Tests that enabling TLS 1.3 by preference overwrites the TLS 1.3 field trial.
-TEST_F(SSLConfigServiceManagerPrefTest, TLS13VariantOverrideEnable) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- // Toggle the field trial.
- variations::testing::VariationParamsManager variation_params(
- "TLS13Variant", {{"variant", "disabled"}});
-
- TestingPrefServiceSimple local_state;
- local_state.SetUserPref(ssl_config::prefs::kSSLVersionMax,
- std::make_unique<base::Value>("tls1.3"));
- local_state.SetUserPref(ssl_config::prefs::kTLS13Variant,
- std::make_unique<base::Value>("draft23"));
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager.get());
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service.get());
-
- SSLConfig ssl_config;
- config_service->GetSSLConfig(&ssl_config);
- EXPECT_EQ(net::SSL_PROTOCOL_VERSION_TLS1_3, ssl_config.version_max);
- EXPECT_EQ(net::kTLS13VariantDraft23, ssl_config.tls13_variant);
-}
-
-// Tests that SHA-1 signatures for local trust anchors can be enabled.
-TEST_F(SSLConfigServiceManagerPrefTest, SHA1ForLocalAnchors) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager);
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service);
-
- // By default, SHA-1 local trust anchors should not be enabled when not
- // not using any pref service.
- SSLConfig config1;
- EXPECT_FALSE(config1.sha1_local_anchors_enabled);
-
- // Using a pref service without any preference set should result in
- // SHA-1 local trust anchors being disabled.
- SSLConfig config2;
- config_service->GetSSLConfig(&config2);
- EXPECT_FALSE(config2.sha1_local_anchors_enabled);
-
- // Enabling the local preference should result in SHA-1 local trust anchors
- // being enabled.
- local_state.SetUserPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
- std::make_unique<base::Value>(true));
- // Pump the message loop to notify the SSLConfigServiceManagerPref that the
- // preferences changed.
- base::RunLoop().RunUntilIdle();
-
- SSLConfig config3;
- config_service->GetSSLConfig(&config3);
- EXPECT_TRUE(config3.sha1_local_anchors_enabled);
-
- // Disabling the local preference should result in SHA-1 local trust
- // anchors being disabled.
- local_state.SetUserPref(ssl_config::prefs::kCertEnableSha1LocalAnchors,
- std::make_unique<base::Value>(false));
- // Pump the message loop to notify the SSLConfigServiceManagerPref that the
- // preferences changed.
- base::RunLoop().RunUntilIdle();
-
- SSLConfig config4;
- config_service->GetSSLConfig(&config4);
- EXPECT_FALSE(config4.sha1_local_anchors_enabled);
-}
-
-// Tests that Symantec's legacy infrastructure can be enabled.
-TEST_F(SSLConfigServiceManagerPrefTest, SymantecLegacyInfrastructure) {
- scoped_refptr<TestingPrefStore> local_state_store(new TestingPrefStore());
-
- TestingPrefServiceSimple local_state;
- SSLConfigServiceManager::RegisterPrefs(local_state.registry());
-
- std::unique_ptr<SSLConfigServiceManager> config_manager(
- SSLConfigServiceManager::CreateDefaultManager(
- &local_state, base::ThreadTaskRunnerHandle::Get()));
- ASSERT_TRUE(config_manager);
- scoped_refptr<SSLConfigService> config_service(config_manager->Get());
- ASSERT_TRUE(config_service);
-
- // By default, Symantec's legacy infrastructure should be disabled when
- // not using any pref service.
- SSLConfig config1;
- EXPECT_FALSE(config1.symantec_enforcement_disabled);
-
- // Using a pref service without any preference set should result in
- // Symantec's legacy infrastructure being disabled.
- SSLConfig config2;
- config_service->GetSSLConfig(&config2);
- EXPECT_FALSE(config2.symantec_enforcement_disabled);
-
- // Enabling the local preference should result in Symantec's legacy
- // infrastructure being enabled.
- local_state.SetUserPref(
- ssl_config::prefs::kCertEnableSymantecLegacyInfrastructure,
- std::make_unique<base::Value>(true));
- // Pump the message loop to notify the SSLConfigServiceManagerPref that the
- // preferences changed.
- base::RunLoop().RunUntilIdle();
-
- SSLConfig config3;
- config_service->GetSSLConfig(&config3);
- EXPECT_TRUE(config3.symantec_enforcement_disabled);
-
- // Disabling the local preference should result in Symantec's legacy
- // infrastructure being disabled.
- local_state.SetUserPref(
- ssl_config::prefs::kCertEnableSymantecLegacyInfrastructure,
- std::make_unique<base::Value>(false));
- // Pump the message loop to notify the SSLConfigServiceManagerPref that the
- // preferences changed.
- base::RunLoop().RunUntilIdle();
-
- SSLConfig config4;
- config_service->GetSSLConfig(&config4);
- EXPECT_FALSE(config4.symantec_enforcement_disabled);
-}
diff --git a/chromium/components/ssl_config/ssl_config_switches.cc b/chromium/components/ssl_config/ssl_config_switches.cc
deleted file mode 100644
index e1b350bf1f9..00000000000
--- a/chromium/components/ssl_config/ssl_config_switches.cc
+++ /dev/null
@@ -1,30 +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 "components/ssl_config/ssl_config_switches.h"
-
-namespace switches {
-
-// Specifies the maximum SSL/TLS version ("tls1", "tls1.1", "tls1.2", or
-// "tls1.3").
-const char kSSLVersionMax[] = "ssl-version-max";
-
-// Specifies the minimum SSL/TLS version ("tls1", "tls1.1", "tls1.2", or
-// "tls1.3").
-const char kSSLVersionMin[] = "ssl-version-min";
-
-// Specifies the enabled TLS 1.3 variant ("disabled", "draft", "experiment").
-const char kTLS13Variant[] = "tls13-variant";
-
-// These values aren't switches, but rather the values that kSSLVersionMax and
-// kSSLVersionMin can have.
-const char kSSLVersionTLSv1[] = "tls1";
-const char kSSLVersionTLSv11[] = "tls1.1";
-const char kSSLVersionTLSv12[] = "tls1.2";
-const char kSSLVersionTLSv13[] = "tls1.3";
-
-const char kTLS13VariantDisabled[] = "disabled";
-const char kTLS13VariantDraft23[] = "draft23";
-
-} // namespace switches
diff --git a/chromium/components/ssl_config/ssl_config_switches.h b/chromium/components/ssl_config/ssl_config_switches.h
deleted file mode 100644
index 9916b6fdeaf..00000000000
--- a/chromium/components/ssl_config/ssl_config_switches.h
+++ /dev/null
@@ -1,22 +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 COMPONENTS_SSL_CONFIG_SSL_CONFIG_SWITCHES_H_
-#define COMPONENTS_SSL_CONFIG_SSL_CONFIG_SWITCHES_H_
-
-namespace switches {
-
-extern const char kSSLVersionMax[];
-extern const char kSSLVersionMin[];
-extern const char kTLS13Variant[];
-extern const char kSSLVersionTLSv1[];
-extern const char kSSLVersionTLSv11[];
-extern const char kSSLVersionTLSv12[];
-extern const char kSSLVersionTLSv13[];
-extern const char kTLS13VariantDisabled[];
-extern const char kTLS13VariantDraft23[];
-
-} // namespace switches
-
-#endif // COMPONENTS_SSL_CONFIG_SSL_CONFIG_SWITCHES_H_
diff --git a/chromium/components/ssl_errors_strings_grdp/OWNERS b/chromium/components/ssl_errors_strings_grdp/OWNERS
new file mode 100644
index 00000000000..877ebf5aaff
--- /dev/null
+++ b/chromium/components/ssl_errors_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/ssl_errors/OWNERS
diff --git a/chromium/components/ssl_errors_strings_grdp/README.md b/chromium/components/ssl_errors_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/ssl_errors_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
index a6ef802aeaf..64b435671ca 100644
--- a/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
+++ b/chromium/components/startup_metric_utils/browser/startup_metric_utils.cc
@@ -14,6 +14,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/process/process_info.h"
#include "base/profiler/stack_sampling_profiler.h"
@@ -319,6 +320,18 @@ void RecordSystemUptimeHistogram() {
GetSystemUptimeOnProcessLaunch());
}
+void RecordTimeOfDayGMTHistogram() {
+ base::Time::Exploded now_exploded;
+ base::Time::Now().UTCExplode(&now_exploded);
+
+ // We log the time as sparse histogram because we should only be recording a
+ // single value per Chrome lifetime. The format of the time is HHMM.
+ // Log the time in 10 minute intervals to make the histogram easier to read.
+ base::UmaHistogramSparse(
+ "Startup.TimeOfDayGMT",
+ 100 * now_exploded.hour + 10 * (now_exploded.minute / 10));
+}
+
// On Windows, records the number of hard-faults that have occurred in the
// current chrome.exe process since it was started. This is a nop on other
// platforms.
@@ -602,6 +615,7 @@ void RecordBrowserMainMessageLoopStart(base::TimeTicks ticks,
AddStartupEventsForTelemetry();
RecordTimeSinceLastStartup(pref_service);
RecordSystemUptimeHistogram();
+ RecordTimeOfDayGMTHistogram();
// Record timings between process creation, the main() in the executable being
// reached and the main() in the shared library being reached.
diff --git a/chromium/components/storage_monitor/BUILD.gn b/chromium/components/storage_monitor/BUILD.gn
index 87f15eb336a..a3d29880292 100644
--- a/chromium/components/storage_monitor/BUILD.gn
+++ b/chromium/components/storage_monitor/BUILD.gn
@@ -42,6 +42,8 @@ static_library("storage_monitor") {
deps = [
"//base",
"//content/public/browser",
+ "//mojo/public/cpp/bindings",
+ "//services/service_manager/public/cpp",
"//ui/base",
]
@@ -54,14 +56,10 @@ static_library("storage_monitor") {
}
if (is_chromeos && use_dbus) {
- deps += [
- "//device/media_transfer_protocol",
- "//device/media_transfer_protocol:mtp_file_entry_proto",
- "//device/media_transfer_protocol:mtp_storage_info_proto",
- ]
+ deps += [ "//services/device/public/mojom" ]
sources += [
- "media_transfer_protocol_device_observer_chromeos.cc",
- "media_transfer_protocol_device_observer_chromeos.h",
+ "mtp_manager_client_chromeos.cc",
+ "mtp_manager_client_chromeos.h",
"storage_info_utils.cc",
"storage_info_utils.h",
]
@@ -115,9 +113,7 @@ static_library("test_support") {
if (is_chromeos && use_dbus) {
deps = [
- "//device/media_transfer_protocol",
- "//device/media_transfer_protocol:mtp_file_entry_proto",
- "//device/media_transfer_protocol:mtp_storage_info_proto",
+ "//services/device/public/mojom",
]
}
@@ -133,7 +129,6 @@ source_set("unit_tests") {
sources = [
"image_capture_device_manager_unittest.mm",
"media_storage_util_unittest.cc",
- "media_transfer_protocol_device_observer_chromeos_unittest.cc",
"storage_info_unittest.cc",
"storage_monitor_mac_unittest.mm",
"storage_monitor_unittest.cc",
@@ -150,12 +145,13 @@ source_set("unit_tests") {
if (use_dbus) {
if (is_chromeos) {
deps += [
- "//device/media_transfer_protocol",
- "//device/media_transfer_protocol:mtp_file_entry_proto",
- "//device/media_transfer_protocol:mtp_storage_info_proto",
+ "//services/device/public/mojom",
"//testing/gmock",
]
- sources += [ "storage_monitor_chromeos_unittest.cc" ]
+ sources += [
+ "mtp_manager_client_chromeos_unittest.cc",
+ "storage_monitor_chromeos_unittest.cc",
+ ]
} else if (is_linux) {
sources += [ "storage_monitor_linux_unittest.cc" ]
}
diff --git a/chromium/components/storage_monitor/DEPS b/chromium/components/storage_monitor/DEPS
index e560e0bd0e5..ded49cc0278 100644
--- a/chromium/components/storage_monitor/DEPS
+++ b/chromium/components/storage_monitor/DEPS
@@ -2,7 +2,9 @@ include_rules = [
"+chromeos/disks",
"+content/public/browser",
"+content/public/test",
- "+device/media_transfer_protocol",
"+device/udev_linux",
+ "+mojo/public/cpp/bindings",
+ "+services/device/public",
+ "+services/service_manager/public",
"+ui/base",
]
diff --git a/chromium/components/storage_monitor/media_storage_util_unittest.cc b/chromium/components/storage_monitor/media_storage_util_unittest.cc
index 0bb998a0a33..2c5f7de204e 100644
--- a/chromium/components/storage_monitor/media_storage_util_unittest.cc
+++ b/chromium/components/storage_monitor/media_storage_util_unittest.cc
@@ -7,7 +7,6 @@
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/post_task.h"
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
deleted file mode 100644
index a008b667aaf..00000000000
--- a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.cc
+++ /dev/null
@@ -1,151 +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 "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
-
-#include <vector>
-
-#include "base/strings/utf_string_conversions.h"
-#include "components/storage_monitor/storage_info.h"
-#include "components/storage_monitor/storage_info_utils.h"
-
-namespace storage_monitor {
-
-MediaTransferProtocolDeviceObserverChromeOS::
- MediaTransferProtocolDeviceObserverChromeOS(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager)
- : mtp_manager_(mtp_manager),
- get_mtp_storage_info_cb_(base::BindRepeating(
- &device::MediaTransferProtocolManager::GetStorageInfo,
- base::Unretained(mtp_manager_))),
- notifications_(receiver),
- weak_ptr_factory_(this) {
- mtp_manager_->AddObserverAndEnumerateStorages(
- this,
- base::BindOnce(
- &MediaTransferProtocolDeviceObserverChromeOS::OnReceivedStorages,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-// This constructor is only used by unit tests.
-MediaTransferProtocolDeviceObserverChromeOS::
- MediaTransferProtocolDeviceObserverChromeOS(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager,
- const GetMtpStorageInfoCallback& get_mtp_storage_info_cb)
- : mtp_manager_(mtp_manager),
- get_mtp_storage_info_cb_(get_mtp_storage_info_cb),
- notifications_(receiver),
- weak_ptr_factory_(this) {}
-
-MediaTransferProtocolDeviceObserverChromeOS::
- ~MediaTransferProtocolDeviceObserverChromeOS() {
- mtp_manager_->RemoveObserver(this);
-}
-
-bool MediaTransferProtocolDeviceObserverChromeOS::GetStorageInfoForPath(
- const base::FilePath& path,
- StorageInfo* storage_info) const {
- DCHECK(storage_info);
-
- if (!path.IsAbsolute())
- return false;
-
- std::vector<base::FilePath::StringType> path_components;
- path.GetComponents(&path_components);
- if (path_components.size() < 2)
- return false;
-
- // First and second component of the path specifies the device location.
- // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the
- // device location.
- StorageLocationToInfoMap::const_iterator info_it =
- storage_map_.find(GetDeviceLocationFromStorageName(path_components[1]));
- if (info_it == storage_map_.end())
- return false;
-
- *storage_info = info_it->second;
- return true;
-}
-
-void MediaTransferProtocolDeviceObserverChromeOS::EjectDevice(
- const std::string& device_id,
- base::Callback<void(StorageMonitor::EjectStatus)> callback) {
- std::string location;
- if (!GetLocationForDeviceId(device_id, &location)) {
- callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE);
- return;
- }
-
- // TODO(thestig): Change this to tell the mtp manager to eject the device.
-
- StorageDetached(location);
- callback.Run(StorageMonitor::EJECT_OK);
-}
-
-// device::MediaTransferProtocolManager::Observer override.
-void MediaTransferProtocolDeviceObserverChromeOS::StorageAttached(
- const device::mojom::MtpStorageInfo& mtp_storage_info) {
- DoAttachStorage(&mtp_storage_info);
-}
-
-// device::MediaTransferProtocolManager::Observer override.
-void MediaTransferProtocolDeviceObserverChromeOS::StorageDetached(
- const std::string& storage_name) {
- DCHECK(!storage_name.empty());
-
- StorageLocationToInfoMap::iterator it =
- storage_map_.find(GetDeviceLocationFromStorageName(storage_name));
- if (it == storage_map_.end())
- return;
- notifications_->ProcessDetach(it->second.device_id());
- storage_map_.erase(it);
-}
-
-void MediaTransferProtocolDeviceObserverChromeOS::DoAttachStorage(
- const device::mojom::MtpStorageInfo* mtp_storage_info) {
- if (!mtp_storage_info)
- return;
-
- std::string device_id = GetDeviceIdFromStorageInfo(*mtp_storage_info);
- base::string16 storage_label =
- GetDeviceLabelFromStorageInfo(*mtp_storage_info);
- std::string location =
- GetDeviceLocationFromStorageName(mtp_storage_info->storage_name);
- base::string16 vendor_name = base::UTF8ToUTF16(mtp_storage_info->vendor);
- base::string16 product_name = base::UTF8ToUTF16(mtp_storage_info->product);
-
- if (device_id.empty() || storage_label.empty())
- return;
-
- DCHECK(!base::ContainsKey(storage_map_, location));
-
- StorageInfo storage_info(device_id, location, storage_label, vendor_name,
- product_name, 0);
- storage_map_[location] = storage_info;
- notifications_->ProcessAttach(storage_info);
-}
-
-void MediaTransferProtocolDeviceObserverChromeOS::OnReceivedStorages(
- std::vector<const device::mojom::MtpStorageInfo*> storage_info_list) {
- for (const auto* storage_info : storage_info_list) {
- DoAttachStorage(storage_info);
- }
-}
-
-bool MediaTransferProtocolDeviceObserverChromeOS::GetLocationForDeviceId(
- const std::string& device_id,
- std::string* location) const {
- for (StorageLocationToInfoMap::const_iterator it = storage_map_.begin();
- it != storage_map_.end(); ++it) {
- if (it->second.device_id() == device_id) {
- *location = it->first;
- return true;
- }
- }
- return false;
-}
-
-} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h b/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h
deleted file mode 100644
index 23f7074a906..00000000000
--- a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_CHROMEOS_H_
-#define COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_CHROMEOS_H_
-
-#include <map>
-#include <string>
-
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/strings/string16.h"
-#include "components/storage_monitor/storage_monitor.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
-
-namespace base {
-class FilePath;
-}
-
-namespace storage_monitor {
-
-// Gets the mtp device information given a |storage_name|.
-using GetMtpStorageInfoCallback = base::RepeatingCallback<void(
- const std::string&,
- device::MediaTransferProtocolManager::GetStorageInfoCallback)>;
-
-// Helper class to send MTP storage attachment and detachment events to
-// StorageMonitor.
-class MediaTransferProtocolDeviceObserverChromeOS
- : public device::MediaTransferProtocolManager::Observer {
- public:
- MediaTransferProtocolDeviceObserverChromeOS(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager);
- ~MediaTransferProtocolDeviceObserverChromeOS() override;
-
- // Finds the storage that contains |path| and populates |storage_info|.
- // Returns false if unable to find the storage.
- bool GetStorageInfoForPath(const base::FilePath& path,
- StorageInfo* storage_info) const;
-
- void EjectDevice(const std::string& device_id,
- base::Callback<void(StorageMonitor::EjectStatus)> callback);
-
- protected:
- // Only used in unit tests.
- MediaTransferProtocolDeviceObserverChromeOS(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager,
- const GetMtpStorageInfoCallback& get_mtp_storage_info_cb);
-
- // device::MediaTransferProtocolManager::Observer implementation.
- // Exposed for unit tests.
- void StorageAttached(
- const device::mojom::MtpStorageInfo& storage_info) override;
- void StorageDetached(const std::string& storage_name) override;
-
- private:
- // Mapping of storage location and mtp storage info object.
- typedef std::map<std::string, StorageInfo> StorageLocationToInfoMap;
-
- // The async handler for newly attached storage.
- void DoAttachStorage(const device::mojom::MtpStorageInfo* mtp_storage_info);
-
- // Enumerate existing mtp storage devices.
- void OnReceivedStorages(
- std::vector<const device::mojom::MtpStorageInfo*> storage_info_list);
-
- // Find the |storage_map_| key for the record with this |device_id|. Returns
- // true on success, false on failure.
- bool GetLocationForDeviceId(const std::string& device_id,
- std::string* location) const;
-
- // Pointer to the MTP manager. Not owned. Client must ensure the MTP
- // manager outlives this object.
- device::MediaTransferProtocolManager* mtp_manager_;
-
- // Map of all attached mtp devices.
- StorageLocationToInfoMap storage_map_;
-
- // Callback to get MTP storage information.
- // This is useful to set a mock handler for unit testing.
- GetMtpStorageInfoCallback get_mtp_storage_info_cb_;
-
- // The notifications object to use to signal newly attached devices.
- // Guaranteed to outlive this class.
- StorageMonitor::Receiver* const notifications_;
-
- base::WeakPtrFactory<MediaTransferProtocolDeviceObserverChromeOS>
- weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDeviceObserverChromeOS);
-};
-
-} // namespace storage_monitor
-
-#endif // COMPONENTS_STORAGE_MONITOR_MEDIA_TRANSFER_PROTOCOL_DEVICE_OBSERVER_CHROMEOS_H_
diff --git a/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc b/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc
new file mode 100644
index 00000000000..1d4beaa622a
--- /dev/null
+++ b/chromium/components/storage_monitor/mtp_manager_client_chromeos.cc
@@ -0,0 +1,133 @@
+// 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 "components/storage_monitor/mtp_manager_client_chromeos.h"
+
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/storage_monitor/storage_info.h"
+#include "components/storage_monitor/storage_info_utils.h"
+
+namespace storage_monitor {
+
+MtpManagerClientChromeOS::MtpManagerClientChromeOS(
+ StorageMonitor::Receiver* receiver,
+ device::mojom::MtpManager* mtp_manager)
+ : mtp_manager_(mtp_manager),
+ binding_(this),
+ notifications_(receiver),
+ weak_ptr_factory_(this) {
+ device::mojom::MtpManagerClientAssociatedPtrInfo client;
+ binding_.Bind(mojo::MakeRequest(&client));
+ mtp_manager_->EnumerateStoragesAndSetClient(
+ std::move(client),
+ base::BindOnce(&MtpManagerClientChromeOS::OnReceivedStorages,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+MtpManagerClientChromeOS::~MtpManagerClientChromeOS() {}
+
+bool MtpManagerClientChromeOS::GetStorageInfoForPath(
+ const base::FilePath& path,
+ StorageInfo* storage_info) const {
+ DCHECK(storage_info);
+
+ if (!path.IsAbsolute())
+ return false;
+
+ std::vector<base::FilePath::StringType> path_components;
+ path.GetComponents(&path_components);
+ if (path_components.size() < 2)
+ return false;
+
+ // First and second component of the path specifies the device location.
+ // E.g.: If |path| is "/usb:2,2:65537/DCIM/Folder_a", "/usb:2,2:65537" is the
+ // device location.
+ const auto info_it =
+ storage_map_.find(GetDeviceLocationFromStorageName(path_components[1]));
+ if (info_it == storage_map_.end())
+ return false;
+
+ *storage_info = info_it->second;
+ return true;
+}
+
+void MtpManagerClientChromeOS::EjectDevice(
+ const std::string& device_id,
+ base::Callback<void(StorageMonitor::EjectStatus)> callback) {
+ std::string location;
+ if (!GetLocationForDeviceId(device_id, &location)) {
+ callback.Run(StorageMonitor::EJECT_NO_SUCH_DEVICE);
+ return;
+ }
+
+ // TODO(thestig): Change this to tell the MTP manager to eject the device.
+
+ StorageDetached(location);
+ callback.Run(StorageMonitor::EJECT_OK);
+}
+
+// device::mojom::MtpManagerClient override.
+void MtpManagerClientChromeOS::StorageAttached(
+ device::mojom::MtpStorageInfoPtr mtp_storage_info) {
+ if (!mtp_storage_info)
+ return;
+
+ // Create StorageMonitor format StorageInfo and update the local map.
+ std::string device_id = GetDeviceIdFromStorageInfo(*mtp_storage_info);
+ base::string16 storage_label =
+ GetDeviceLabelFromStorageInfo(*mtp_storage_info);
+ std::string location =
+ GetDeviceLocationFromStorageName(mtp_storage_info->storage_name);
+ base::string16 vendor_name = base::UTF8ToUTF16(mtp_storage_info->vendor);
+ base::string16 product_name = base::UTF8ToUTF16(mtp_storage_info->product);
+
+ if (device_id.empty() || storage_label.empty())
+ return;
+
+ DCHECK(!base::ContainsKey(storage_map_, location));
+
+ StorageInfo storage_info(device_id, location, storage_label, vendor_name,
+ product_name, 0);
+ storage_map_[location] = storage_info;
+
+ // Notify StorageMonitor observers about the event.
+ notifications_->ProcessAttach(storage_info);
+}
+
+// device::mojom::MtpManagerClient override.
+void MtpManagerClientChromeOS::StorageDetached(
+ const std::string& storage_name) {
+ DCHECK(!storage_name.empty());
+
+ StorageLocationToInfoMap::iterator it =
+ storage_map_.find(GetDeviceLocationFromStorageName(storage_name));
+ if (it == storage_map_.end())
+ return;
+
+ // Notify StorageMonitor observers about the event.
+ notifications_->ProcessDetach(it->second.device_id());
+ storage_map_.erase(it);
+}
+
+void MtpManagerClientChromeOS::OnReceivedStorages(
+ std::vector<device::mojom::MtpStorageInfoPtr> storage_info_list) {
+ for (auto& storage_info : storage_info_list)
+ StorageAttached(std::move(storage_info));
+}
+
+bool MtpManagerClientChromeOS::GetLocationForDeviceId(
+ const std::string& device_id,
+ std::string* location) const {
+ for (const auto& it : storage_map_) {
+ if (it.second.device_id() == device_id) {
+ *location = it.first;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/mtp_manager_client_chromeos.h b/chromium/components/storage_monitor/mtp_manager_client_chromeos.h
new file mode 100644
index 00000000000..d7716b35372
--- /dev/null
+++ b/chromium/components/storage_monitor/mtp_manager_client_chromeos.h
@@ -0,0 +1,78 @@
+// 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 COMPONENTS_STORAGE_MONITOR_MTP_MANAGER_CLIENT_CHROMEOS_H_
+#define COMPONENTS_STORAGE_MONITOR_MTP_MANAGER_CLIENT_CHROMEOS_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/memory/weak_ptr.h"
+#include "components/storage_monitor/storage_monitor.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "services/device/public/mojom/mtp_manager.mojom.h"
+
+namespace base {
+class FilePath;
+}
+
+namespace storage_monitor {
+
+// This client listens for MTP storage attachment and detachment events
+// from MtpManager and forwards them to StorageMonitor.
+class MtpManagerClientChromeOS : public device::mojom::MtpManagerClient {
+ public:
+ MtpManagerClientChromeOS(StorageMonitor::Receiver* receiver,
+ device::mojom::MtpManager* mtp_manager);
+ ~MtpManagerClientChromeOS() override;
+
+ // Finds the storage that contains |path| and populates |storage_info|.
+ // Returns false if unable to find the storage.
+ bool GetStorageInfoForPath(const base::FilePath& path,
+ StorageInfo* storage_info) const;
+
+ void EjectDevice(const std::string& device_id,
+ base::Callback<void(StorageMonitor::EjectStatus)> callback);
+
+ protected:
+ // device::mojom::MtpManagerClient implementation.
+ // Exposed for unit tests.
+ void StorageAttached(device::mojom::MtpStorageInfoPtr storage_info) override;
+ void StorageDetached(const std::string& storage_name) override;
+
+ private:
+ // Mapping of storage location and MTP storage info object.
+ using StorageLocationToInfoMap = std::map<std::string, StorageInfo>;
+
+ // Enumerate existing MTP storage devices.
+ void OnReceivedStorages(
+ std::vector<device::mojom::MtpStorageInfoPtr> storage_info_list);
+
+ // Find the |storage_map_| key for the record with this |device_id|. Returns
+ // true on success, false on failure.
+ bool GetLocationForDeviceId(const std::string& device_id,
+ std::string* location) const;
+
+ // Map of all attached MTP devices.
+ StorageLocationToInfoMap storage_map_;
+
+ // Pointer to the MTP manager. Not owned. Client must ensure the MTP
+ // manager outlives this object.
+ device::mojom::MtpManager* const mtp_manager_;
+
+ mojo::AssociatedBinding<device::mojom::MtpManagerClient> binding_;
+
+ // The notifications object to use to signal newly attached devices.
+ // Guaranteed to outlive this class.
+ StorageMonitor::Receiver* const notifications_;
+
+ base::WeakPtrFactory<MtpManagerClientChromeOS> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(MtpManagerClientChromeOS);
+};
+
+} // namespace storage_monitor
+
+#endif // COMPONENTS_STORAGE_MONITOR_MTP_MANAGER_CLIENT_CHROMEOS_H_
diff --git a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc b/chromium/components/storage_monitor/mtp_manager_client_chromeos_unittest.cc
index 17aaaf97ceb..38455ea524c 100644
--- a/chromium/components/storage_monitor/media_transfer_protocol_device_observer_chromeos_unittest.cc
+++ b/chromium/components/storage_monitor/mtp_manager_client_chromeos_unittest.cc
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
-// MediaTransferProtocolDeviceObserverChromeOS unit tests.
+// MtpManagerClientChromeOS unit tests.
-#include "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
+#include "components/storage_monitor/mtp_manager_client_chromeos.h"
#include <memory>
#include <string>
+#include <utility>
#include "base/lazy_instance.h"
#include "base/macros.h"
@@ -19,14 +20,14 @@
#include "components/storage_monitor/storage_monitor.h"
#include "components/storage_monitor/test_storage_monitor.h"
#include "content/public/test/test_browser_thread_bundle.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
+#include "services/device/public/mojom/mtp_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace storage_monitor {
namespace {
-// Sample mtp device storage information.
+// Sample MTP device storage information.
const char kStorageWithInvalidInfo[] = "usb:2,3:11111";
const char kStorageWithValidInfo[] = "usb:2,2:88888";
const char kStorageVendor[] = "ExampleVendor";
@@ -44,7 +45,7 @@ const char kStorageDescription[] = "ExampleDescription";
const char kStorageVolumeIdentifier[] = "ExampleVolumeId";
base::LazyInstance<std::map<std::string, device::mojom::MtpStorageInfo>>::Leaky
- g_fake_storage_info_map = LAZY_INSTANCE_INITIALIZER;
+ g_fake_storage_info_map = LAZY_INSTANCE_INITIALIZER;
const device::mojom::MtpStorageInfo* GetFakeMtpStorageInfoSync(
const std::string& storage_name) {
@@ -71,65 +72,50 @@ const device::mojom::MtpStorageInfo* GetFakeMtpStorageInfoSync(
return it != g_fake_storage_info_map.Get().end() ? &it->second : nullptr;
}
-// Helper function to get fake MTP device details.
-void GetFakeMtpStorageInfo(
- const std::string& storage_name,
- device::MediaTransferProtocolManager::GetStorageInfoCallback callback) {
- std::move(callback).Run(GetFakeMtpStorageInfoSync(storage_name));
-}
-
-class TestMediaTransferProtocolDeviceObserverChromeOS
- : public MediaTransferProtocolDeviceObserverChromeOS {
+class FakeMtpManagerClientChromeOS : public MtpManagerClientChromeOS {
public:
- TestMediaTransferProtocolDeviceObserverChromeOS(
- StorageMonitor::Receiver* receiver,
- device::MediaTransferProtocolManager* mtp_manager)
- : MediaTransferProtocolDeviceObserverChromeOS(
- receiver,
- mtp_manager,
- base::BindRepeating(&GetFakeMtpStorageInfo)) {}
-
- // Notifies MediaTransferProtocolDeviceObserverChromeOS about the attachment
- // of
- // mtp storage device given the |storage_name|.
+ FakeMtpManagerClientChromeOS(StorageMonitor::Receiver* receiver,
+ device::mojom::MtpManager* mtp_manager)
+ : MtpManagerClientChromeOS(receiver, mtp_manager) {}
+
+ // Notifies MtpManagerClientChromeOS about the attachment of MTP storage
+ // device given the |storage_name|.
void MtpStorageAttached(const std::string& storage_name) {
auto* storage_info = GetFakeMtpStorageInfoSync(storage_name);
DCHECK(storage_info);
- StorageAttached(*storage_info);
+ StorageAttached(storage_info->Clone());
base::RunLoop().RunUntilIdle();
}
- // Notifies MediaTransferProtocolDeviceObserverChromeOS about the detachment
- // of
- // mtp storage device given the |storage_name|.
+ // Notifies MtpManagerClientChromeOS about the detachment of MTP storage
+ // device given the |storage_name|.
void MtpStorageDetached(const std::string& storage_name) {
StorageDetached(storage_name);
base::RunLoop().RunUntilIdle();
}
private:
- DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolDeviceObserverChromeOS);
+ DISALLOW_COPY_AND_ASSIGN(FakeMtpManagerClientChromeOS);
};
} // namespace
-// A class to test the functionality of
-// MediaTransferProtocolDeviceObserverChromeOS member functions.
-class MediaTransferProtocolDeviceObserverChromeOSTest : public testing::Test {
+// A class to test the functionality of MtpManagerClientChromeOS member
+// functions.
+class MtpManagerClientChromeOSTest : public testing::Test {
public:
- MediaTransferProtocolDeviceObserverChromeOSTest()
+ MtpManagerClientChromeOSTest()
: thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) {}
- ~MediaTransferProtocolDeviceObserverChromeOSTest() override {}
+ ~MtpManagerClientChromeOSTest() override {}
protected:
void SetUp() override {
mock_storage_observer_.reset(new MockRemovableStorageObserver);
TestStorageMonitor* monitor = TestStorageMonitor::CreateAndInstall();
- mtp_device_observer_.reset(
- new TestMediaTransferProtocolDeviceObserverChromeOS(
- monitor->receiver(), monitor->media_transfer_protocol_manager()));
+ mtp_device_observer_ = std::make_unique<FakeMtpManagerClientChromeOS>(
+ monitor->receiver(), monitor->media_transfer_protocol_manager());
monitor->AddObserver(mock_storage_observer_.get());
}
@@ -143,26 +129,25 @@ class MediaTransferProtocolDeviceObserverChromeOSTest : public testing::Test {
// Returns the device changed observer object.
MockRemovableStorageObserver& observer() { return *mock_storage_observer_; }
- TestMediaTransferProtocolDeviceObserverChromeOS* mtp_device_observer() {
+ FakeMtpManagerClientChromeOS* mtp_device_observer() {
return mtp_device_observer_.get();
}
private:
content::TestBrowserThreadBundle thread_bundle_;
- std::unique_ptr<TestMediaTransferProtocolDeviceObserverChromeOS>
- mtp_device_observer_;
+ std::unique_ptr<FakeMtpManagerClientChromeOS> mtp_device_observer_;
std::unique_ptr<MockRemovableStorageObserver> mock_storage_observer_;
- DISALLOW_COPY_AND_ASSIGN(MediaTransferProtocolDeviceObserverChromeOSTest);
+ DISALLOW_COPY_AND_ASSIGN(MtpManagerClientChromeOSTest);
};
-// Test to verify basic mtp storage attach and detach notifications.
-TEST_F(MediaTransferProtocolDeviceObserverChromeOSTest, BasicAttachDetach) {
+// Test to verify basic MTP storage attach and detach notifications.
+TEST_F(MtpManagerClientChromeOSTest, BasicAttachDetach) {
auto* mtpStorageInfo = GetFakeMtpStorageInfoSync(kStorageWithValidInfo);
std::string device_id = GetDeviceIdFromStorageInfo(*mtpStorageInfo);
- // Attach a mtp storage.
+ // Attach a MTP storage.
mtp_device_observer()->MtpStorageAttached(kStorageWithValidInfo);
EXPECT_EQ(1, observer().attach_calls());
@@ -183,11 +168,10 @@ TEST_F(MediaTransferProtocolDeviceObserverChromeOSTest, BasicAttachDetach) {
EXPECT_EQ(device_id, observer().last_detached().device_id());
}
-// When a mtp storage device with invalid storage label and id is
+// When a MTP storage device with invalid storage label and id is
// attached/detached, there should not be any device attach/detach
// notifications.
-TEST_F(MediaTransferProtocolDeviceObserverChromeOSTest,
- StorageWithInvalidInfo) {
+TEST_F(MtpManagerClientChromeOSTest, StorageWithInvalidInfo) {
// Attach the mtp storage with invalid storage info.
mtp_device_observer()->MtpStorageAttached(kStorageWithInvalidInfo);
diff --git a/chromium/components/storage_monitor/portable_device_watcher_win.cc b/chromium/components/storage_monitor/portable_device_watcher_win.cc
index 13a9a370073..6fea011ba4f 100644
--- a/chromium/components/storage_monitor/portable_device_watcher_win.cc
+++ b/chromium/components/storage_monitor/portable_device_watcher_win.cc
@@ -70,7 +70,7 @@ bool GetFriendlyName(const base::string16& pnp_device_id,
DCHECK(name);
DWORD name_len = 0;
HRESULT hr = device_manager->GetDeviceFriendlyName(pnp_device_id.c_str(),
- NULL, &name_len);
+ nullptr, &name_len);
if (FAILED(hr))
return false;
@@ -88,7 +88,7 @@ bool GetManufacturerName(const base::string16& pnp_device_id,
DCHECK(name);
DWORD name_len = 0;
HRESULT hr = device_manager->GetDeviceManufacturer(pnp_device_id.c_str(),
- NULL, &name_len);
+ nullptr, &name_len);
if (FAILED(hr))
return false;
@@ -106,8 +106,8 @@ bool GetDeviceDescription(const base::string16& pnp_device_id,
DCHECK(device_manager);
DCHECK(description);
DWORD desc_len = 0;
- HRESULT hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(), NULL,
- &desc_len);
+ HRESULT hr = device_manager->GetDeviceDescription(pnp_device_id.c_str(),
+ nullptr, &desc_len);
if (FAILED(hr))
return false;
@@ -121,7 +121,7 @@ bool GetDeviceDescription(const base::string16& pnp_device_id,
// application that communicates with the device.
bool GetClientInformation(
Microsoft::WRL::ComPtr<IPortableDeviceValues>* client_info) {
- HRESULT hr = ::CoCreateInstance(__uuidof(PortableDeviceValues), NULL,
+ HRESULT hr = ::CoCreateInstance(__uuidof(PortableDeviceValues), nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(client_info->GetAddressOf()));
if (FAILED(hr)) {
@@ -150,9 +150,9 @@ bool SetUp(const base::string16& pnp_device_id,
if (!GetClientInformation(&client_info))
return false;
- HRESULT hr =
- ::CoCreateInstance(__uuidof(PortableDevice), NULL, CLSCTX_INPROC_SERVER,
- IID_PPV_ARGS(device->GetAddressOf()));
+ HRESULT hr = ::CoCreateInstance(__uuidof(PortableDevice), nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(device->GetAddressOf()));
if (FAILED(hr)) {
DPLOG(ERROR) << "Failed to create an instance of IPortableDevice";
return false;
@@ -180,7 +180,7 @@ bool PopulatePropertyKeyCollection(
const base::string16& object_id,
Microsoft::WRL::ComPtr<IPortableDeviceKeyCollection>* properties_to_read) {
HRESULT hr = ::CoCreateInstance(
- __uuidof(PortableDeviceKeyCollection), NULL, CLSCTX_INPROC_SERVER,
+ __uuidof(PortableDeviceKeyCollection), nullptr, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(properties_to_read->GetAddressOf()));
if (FAILED(hr)) {
DPLOG(ERROR) << "Failed to create IPortableDeviceKeyCollection instance";
@@ -286,7 +286,7 @@ bool GetRemovableStorageObjectIds(
base::win::ScopedPropVariant object_id;
hr = storage_ids->GetAt(index, object_id.Receive());
if (SUCCEEDED(hr) && object_id.get().vt == VT_LPWSTR &&
- object_id.get().pwszVal != NULL) {
+ object_id.get().pwszVal != nullptr) {
storage_object_ids->push_back(object_id.get().pwszVal);
}
}
@@ -388,7 +388,7 @@ bool GetPortableDeviceManager(
Microsoft::WRL::ComPtr<IPortableDeviceManager>* portable_device_mgr) {
base::AssertBlockingAllowed();
HRESULT hr = ::CoCreateInstance(
- __uuidof(PortableDeviceManager), NULL, CLSCTX_INPROC_SERVER,
+ __uuidof(PortableDeviceManager), nullptr, CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(portable_device_mgr->GetAddressOf()));
if (SUCCEEDED(hr))
return true;
@@ -412,7 +412,7 @@ bool EnumerateAttachedDevicesOnBlockingThread(
// Get the total number of devices found on the system.
DWORD pnp_device_count = 0;
- HRESULT hr = portable_device_mgr->GetDevices(NULL, &pnp_device_count);
+ HRESULT hr = portable_device_mgr->GetDevices(nullptr, &pnp_device_count);
if (FAILED(hr))
return false;
@@ -457,7 +457,7 @@ HDEVNOTIFY RegisterPortableDeviceNotification(HWND hwnd) {
GUID dev_interface_guid = GUID_NULL;
HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &dev_interface_guid);
if (FAILED(hr))
- return NULL;
+ return nullptr;
DEV_BROADCAST_DEVICEINTERFACE db = {
sizeof(DEV_BROADCAST_DEVICEINTERFACE),
DBT_DEVTYP_DEVICEINTERFACE,
@@ -489,10 +489,9 @@ PortableDeviceWatcherWin::DeviceDetails::~DeviceDetails() {
}
PortableDeviceWatcherWin::PortableDeviceWatcherWin()
- : notifications_(NULL),
- storage_notifications_(NULL),
- weak_ptr_factory_(this) {
-}
+ : notifications_(nullptr),
+ storage_notifications_(nullptr),
+ weak_ptr_factory_(this) {}
PortableDeviceWatcherWin::~PortableDeviceWatcherWin() {
UnregisterDeviceNotification(notifications_);
@@ -581,7 +580,7 @@ void PortableDeviceWatcherWin::EjectDevice(
}
void PortableDeviceWatcherWin::EnumerateAttachedDevices() {
- DCHECK(media_task_runner_.get());
+ DCHECK(media_task_runner_);
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Devices* devices = new Devices;
base::PostTaskAndReplyWithResult(
@@ -605,7 +604,7 @@ void PortableDeviceWatcherWin::OnDidEnumerateAttachedDevices(
void PortableDeviceWatcherWin::HandleDeviceAttachEvent(
const base::string16& pnp_device_id) {
- DCHECK(media_task_runner_.get());
+ DCHECK(media_task_runner_);
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DeviceDetails* device_details = new DeviceDetails;
base::PostTaskAndReplyWithResult(
diff --git a/chromium/components/storage_monitor/storage_info_utils.h b/chromium/components/storage_monitor/storage_info_utils.h
index b471f1c3fdb..037937b243c 100644
--- a/chromium/components/storage_monitor/storage_info_utils.h
+++ b/chromium/components/storage_monitor/storage_info_utils.h
@@ -11,7 +11,7 @@
#include <string>
#include "base/strings/string16.h"
-#include "device/media_transfer_protocol/public/mojom/mtp_storage_info.mojom.h"
+#include "services/device/public/mojom/mtp_storage_info.mojom.h"
namespace storage_monitor {
diff --git a/chromium/components/storage_monitor/storage_monitor.cc b/chromium/components/storage_monitor/storage_monitor.cc
index d862a38eefc..6f3871cec72 100644
--- a/chromium/components/storage_monitor/storage_monitor.cc
+++ b/chromium/components/storage_monitor/storage_monitor.cc
@@ -4,6 +4,8 @@
#include "components/storage_monitor/storage_monitor.h"
+#include <utility>
+
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "components/storage_monitor/removable_storage_observer.h"
@@ -50,9 +52,15 @@ void StorageMonitor::ReceiverImpl::MarkInitialized() {
}
// static
-void StorageMonitor::Create() {
+void StorageMonitor::Create(
+ std::unique_ptr<service_manager::Connector> connector) {
delete g_storage_monitor;
g_storage_monitor = CreateInternal();
+ g_storage_monitor->connector_ = std::move(connector);
+}
+
+service_manager::Connector* StorageMonitor::GetConnector() {
+ return connector_.get();
}
// static
diff --git a/chromium/components/storage_monitor/storage_monitor.h b/chromium/components/storage_monitor/storage_monitor.h
index ade2f2e5d80..250a5ed1de5 100644
--- a/chromium/components/storage_monitor/storage_monitor.h
+++ b/chromium/components/storage_monitor/storage_monitor.h
@@ -18,16 +18,17 @@
#include "base/synchronization/lock.h"
#include "build/build_config.h"
#include "components/storage_monitor/storage_info.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+#if defined(OS_CHROMEOS)
+#include "services/device/public/mojom/mtp_manager.mojom.h"
+#endif
class MediaFileSystemRegistryTest;
class MediaGalleriesPlatformAppBrowserTest;
class SystemStorageApiTest;
class SystemStorageEjectApiTest;
-namespace device {
-class MediaTransferProtocolManager;
-}
-
namespace storage_monitor {
class RemovableStorageObserver;
@@ -71,7 +72,7 @@ class StorageMonitor {
// Instantiates the StorageMonitor singleton. This function does not
// guarantee the complete initialization of the object. For that, see
// |EnsureInitialized|.
- static void Create();
+ static void Create(std::unique_ptr<service_manager::Connector> connector);
// Destroys the StorageMonitor singleton.
static void Destroy();
@@ -121,8 +122,7 @@ class StorageMonitor {
#endif
#if defined(OS_CHROMEOS)
- virtual device::MediaTransferProtocolManager*
- media_transfer_protocol_manager() = 0;
+ virtual device::mojom::MtpManager* media_transfer_protocol_manager() = 0;
#endif
// Returns information for all known storages on the system,
@@ -147,6 +147,9 @@ class StorageMonitor {
StorageMonitor();
+ // Provides the connector for service access.
+ service_manager::Connector* GetConnector();
+
virtual Receiver* receiver() const;
// Called to initialize the storage monitor.
@@ -186,6 +189,8 @@ class StorageMonitor {
// Map of all known storage devices,including fixed and removable storages.
StorageMap storage_map_;
+ std::unique_ptr<service_manager::Connector> connector_;
+
std::unique_ptr<TransientDeviceIds> transient_device_ids_;
};
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.cc b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
index 5fe15f96e30..6e1b98ee2dc 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.cc
@@ -8,6 +8,7 @@
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
@@ -19,10 +20,11 @@
#include "base/task_scheduler/task_traits.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "components/storage_monitor/media_storage_util.h"
-#include "components/storage_monitor/media_transfer_protocol_device_observer_chromeos.h"
+#include "components/storage_monitor/mtp_manager_client_chromeos.h"
#include "components/storage_monitor/removable_device_constants.h"
#include "content/public/browser/browser_thread.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
using chromeos::disks::DiskMountManager;
@@ -113,13 +115,16 @@ void StorageMonitorCros::Init() {
CheckExistingMountPoints();
// Tests may have already set a MTP manager.
- if (!media_transfer_protocol_manager_) {
- media_transfer_protocol_manager_ =
- device::MediaTransferProtocolManager::Initialize();
+ if (!mtp_device_manager_) {
+ // Set up the connection with mojofied MtpManager.
+ DCHECK(GetConnector());
+ GetConnector()->BindInterface(device::mojom::kServiceName,
+ mojo::MakeRequest(&mtp_device_manager_));
}
- media_transfer_protocol_device_observer_ =
- std::make_unique<MediaTransferProtocolDeviceObserverChromeOS>(
- receiver(), media_transfer_protocol_manager_.get());
+ // |mtp_manager_client_| needs to be initialized for both tests and
+ // production code, so keep it out of the if condition.
+ mtp_manager_client_ = std::make_unique<MtpManagerClientChromeOS>(
+ receiver(), mtp_device_manager_.get());
}
void StorageMonitorCros::CheckExistingMountPoints() {
@@ -239,9 +244,9 @@ void StorageMonitorCros::OnRenameEvent(DiskMountManager::RenameEvent event,
const std::string& device_path) {}
void StorageMonitorCros::SetMediaTransferProtocolManagerForTest(
- device::MediaTransferProtocolManager* test_manager) {
- DCHECK(!media_transfer_protocol_manager_);
- media_transfer_protocol_manager_.reset(test_manager);
+ device::mojom::MtpManagerPtr test_manager) {
+ DCHECK(!mtp_device_manager_);
+ mtp_device_manager_ = std::move(test_manager);
}
bool StorageMonitorCros::GetStorageInfoForPath(
@@ -249,8 +254,7 @@ bool StorageMonitorCros::GetStorageInfoForPath(
StorageInfo* device_info) const {
DCHECK(device_info);
- if (media_transfer_protocol_device_observer_->GetStorageInfoForPath(
- path, device_info)) {
+ if (mtp_manager_client_->GetStorageInfoForPath(path, device_info)) {
return true;
}
@@ -292,7 +296,7 @@ void StorageMonitorCros::EjectDevice(
}
if (type == StorageInfo::MTP_OR_PTP) {
- media_transfer_protocol_device_observer_->EjectDevice(device_id, callback);
+ mtp_manager_client_->EjectDevice(device_id, callback);
return;
}
@@ -318,9 +322,9 @@ void StorageMonitorCros::EjectDevice(
base::Bind(NotifyUnmountResult, callback));
}
-device::MediaTransferProtocolManager*
+device::mojom::MtpManager*
StorageMonitorCros::media_transfer_protocol_manager() {
- return media_transfer_protocol_manager_.get();
+ return mtp_device_manager_.get();
}
void StorageMonitorCros::AddMountedPath(
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos.h b/chromium/components/storage_monitor/storage_monitor_chromeos.h
index 8fb718254d9..7786be42151 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos.h
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos.h
@@ -23,10 +23,11 @@
#include "build/build_config.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "components/storage_monitor/storage_monitor.h"
+#include "services/device/public/mojom/mtp_manager.mojom.h"
namespace storage_monitor {
-class MediaTransferProtocolDeviceObserverChromeOS;
+class MtpManagerClientChromeOS;
class StorageMonitorCros : public StorageMonitor,
public chromeos::disks::DiskMountManager::Observer {
@@ -42,7 +43,7 @@ class StorageMonitorCros : public StorageMonitor,
protected:
void SetMediaTransferProtocolManagerForTest(
- device::MediaTransferProtocolManager* test_manager);
+ device::mojom::MtpManagerPtr test_manager);
// chromeos::disks::DiskMountManager::Observer implementation.
void OnAutoMountableDiskEvent(
@@ -69,8 +70,7 @@ class StorageMonitorCros : public StorageMonitor,
StorageInfo* device_info) const override;
void EjectDevice(const std::string& device_id,
base::Callback<void(EjectStatus)> callback) override;
- device::MediaTransferProtocolManager* media_transfer_protocol_manager()
- override;
+ device::mojom::MtpManager* media_transfer_protocol_manager() override;
private:
// Mapping of mount path to removable mass storage info.
@@ -99,10 +99,9 @@ class StorageMonitorCros : public StorageMonitor,
// Mapping of relevant mount points and their corresponding mount devices.
MountMap mount_map_;
- std::unique_ptr<device::MediaTransferProtocolManager>
- media_transfer_protocol_manager_;
- std::unique_ptr<MediaTransferProtocolDeviceObserverChromeOS>
- media_transfer_protocol_device_observer_;
+ device::mojom::MtpManagerPtr mtp_device_manager_;
+
+ std::unique_ptr<MtpManagerClientChromeOS> mtp_manager_client_;
base::WeakPtrFactory<StorageMonitorCros> weak_ptr_factory_;
diff --git a/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc b/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
index e433f212c6f..8168cbf0daf 100644
--- a/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_chromeos_unittest.cc
@@ -8,12 +8,12 @@
#include <memory>
#include <utility>
+#include <vector>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_task_environment.h"
@@ -68,8 +68,12 @@ class TestStorageMonitorCros : public StorageMonitorCros {
~TestStorageMonitorCros() override {}
void Init() override {
- SetMediaTransferProtocolManagerForTest(
- new TestMediaTransferProtocolManagerChromeOS());
+ device::mojom::MtpManagerPtr fake_mtp_manager_ptr;
+ auto* fake_mtp_manager =
+ TestMediaTransferProtocolManagerChromeOS::GetFakeMtpManager();
+ fake_mtp_manager->AddBinding(mojo::MakeRequest(&fake_mtp_manager_ptr));
+ SetMediaTransferProtocolManagerForTest(std::move(fake_mtp_manager_ptr));
+
StorageMonitorCros::Init();
}
diff --git a/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc b/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
index 14b11f6f14d..e46f7b6cba0 100644
--- a/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_linux_unittest.cc
@@ -18,7 +18,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_scheduler/task_scheduler.h"
@@ -143,7 +142,7 @@ class TestStorageMonitorLinux : public StorageMonitorLinux {
// Once the storage monitor picks up the changes to the fake mtab file,
// exit the RunLoop that should be blocking the main test thread.
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
DISALLOW_COPY_AND_ASSIGN(TestStorageMonitorLinux);
diff --git a/chromium/components/storage_monitor/storage_monitor_unittest.cc b/chromium/components/storage_monitor/storage_monitor_unittest.cc
index ef56ffeb515..f9fa9ffba64 100644
--- a/chromium/components/storage_monitor/storage_monitor_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_unittest.cc
@@ -2,12 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "components/storage_monitor/storage_monitor.h"
+
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
+#include "base/test/scoped_task_environment.h"
#include "components/storage_monitor/mock_removable_storage_observer.h"
-#include "components/storage_monitor/storage_monitor.h"
#include "components/storage_monitor/test_storage_monitor.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -22,6 +24,7 @@ void SetLatch(bool* called) {
namespace storage_monitor {
TEST(StorageMonitorTest, TestInitialize) {
+ base::MessageLoop message_loop;
TestStorageMonitor::Destroy();
TestStorageMonitor monitor;
EXPECT_FALSE(monitor.init_called());
diff --git a/chromium/components/storage_monitor/storage_monitor_win.cc b/chromium/components/storage_monitor/storage_monitor_win.cc
index c006b6f7b0a..add16c6be65 100644
--- a/chromium/components/storage_monitor/storage_monitor_win.cc
+++ b/chromium/components/storage_monitor/storage_monitor_win.cc
@@ -26,8 +26,8 @@ StorageMonitorWin::StorageMonitorWin(
VolumeMountWatcherWin* volume_mount_watcher,
PortableDeviceWatcherWin* portable_device_watcher)
: window_class_(0),
- instance_(NULL),
- window_(NULL),
+ instance_(nullptr),
+ window_(nullptr),
shell_change_notify_id_(0),
volume_mount_watcher_(volume_mount_watcher),
portable_device_watcher_(portable_device_watcher) {
@@ -40,8 +40,8 @@ StorageMonitorWin::StorageMonitorWin(
StorageMonitorWin::~StorageMonitorWin() {
if (shell_change_notify_id_)
SHChangeNotifyDeregister(shell_change_notify_id_);
- volume_mount_watcher_->SetNotifications(NULL);
- portable_device_watcher_->SetNotifications(NULL);
+ volume_mount_watcher_->SetNotifications(nullptr);
+ portable_device_watcher_->SetNotifications(nullptr);
if (window_)
DestroyWindow(window_);
@@ -54,15 +54,14 @@ void StorageMonitorWin::Init() {
WNDCLASSEX window_class;
base::win::InitializeWindowClass(
L"Chrome_StorageMonitorWindow",
- &base::win::WrappedWindowProc<StorageMonitorWin::WndProcThunk>,
- 0, 0, 0, NULL, NULL, NULL, NULL, NULL,
- &window_class);
+ &base::win::WrappedWindowProc<StorageMonitorWin::WndProcThunk>, 0, 0, 0,
+ nullptr, nullptr, nullptr, nullptr, nullptr, &window_class);
instance_ = window_class.hInstance;
window_class_ = RegisterClassEx(&window_class);
DCHECK(window_class_);
- window_ = CreateWindow(MAKEINTATOM(window_class_), 0, 0, 0, 0, 0, 0, 0, 0,
- instance_, 0);
+ window_ = CreateWindow(MAKEINTATOM(window_class_), nullptr, 0, 0, 0, 0, 0,
+ nullptr, nullptr, instance_, nullptr);
SetWindowLongPtr(window_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
volume_mount_watcher_->Init();
portable_device_watcher_->Init(window_);
@@ -106,7 +105,7 @@ void StorageMonitorWin::EjectDevice(
const std::string& device_id,
base::Callback<void(EjectStatus)> callback) {
StorageInfo::Type type;
- if (!StorageInfo::CrackDeviceId(device_id, &type, NULL)) {
+ if (!StorageInfo::CrackDeviceId(device_id, &type, nullptr)) {
callback.Run(EJECT_FAILURE);
return;
}
@@ -124,7 +123,7 @@ bool StorageMonitorWin::GetMTPStorageInfoFromDeviceId(
base::string16* device_location,
base::string16* storage_object_id) const {
StorageInfo::Type type;
- StorageInfo::CrackDeviceId(storage_device_id, &type, NULL);
+ StorageInfo::CrackDeviceId(storage_device_id, &type, nullptr);
return ((type == StorageInfo::MTP_OR_PTP) &&
portable_device_watcher_->GetMTPStorageInfoFromDeviceId(
storage_device_id, device_location, storage_object_id));
@@ -158,7 +157,7 @@ LRESULT CALLBACK StorageMonitorWin::WndProc(HWND hwnd, UINT message,
void StorageMonitorWin::MediaChangeNotificationRegister() {
LPITEMIDLIST id_list;
- if (SHGetSpecialFolderLocation(NULL, CSIDL_DRIVES, &id_list) == NOERROR) {
+ if (SHGetSpecialFolderLocation(nullptr, CSIDL_DRIVES, &id_list) == NOERROR) {
SHChangeNotifyEntry notify_entry;
notify_entry.pidl = id_list;
notify_entry.fRecursive = TRUE;
diff --git a/chromium/components/storage_monitor/storage_monitor_win_unittest.cc b/chromium/components/storage_monitor/storage_monitor_win_unittest.cc
index 4ead7d182c0..ef4ba5a8ec6 100644
--- a/chromium/components/storage_monitor/storage_monitor_win_unittest.cc
+++ b/chromium/components/storage_monitor/storage_monitor_win_unittest.cc
@@ -201,7 +201,7 @@ void StorageMonitorWinTest::DoMTPDeviceTest(const base::string16& pnp_device_id,
std::unique_ptr<DEV_BROADCAST_DEVICEINTERFACE, base::FreeDeleter>
dev_interface_broadcast(
static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size)));
- DCHECK(dev_interface_broadcast.get());
+ DCHECK(dev_interface_broadcast);
ZeroMemory(dev_interface_broadcast.get(), size);
dev_interface_broadcast->dbcc_size = size;
dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
diff --git a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc
index a8c6ac2010f..823b4852f53 100644
--- a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc
+++ b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.cc
@@ -4,70 +4,78 @@
#include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/no_destructor.h"
+
namespace storage_monitor {
+// static
+TestMediaTransferProtocolManagerChromeOS*
+TestMediaTransferProtocolManagerChromeOS::GetFakeMtpManager() {
+ static base::NoDestructor<TestMediaTransferProtocolManagerChromeOS>
+ fake_mtp_manager;
+ return fake_mtp_manager.get();
+}
+
TestMediaTransferProtocolManagerChromeOS::
TestMediaTransferProtocolManagerChromeOS() {}
TestMediaTransferProtocolManagerChromeOS::
~TestMediaTransferProtocolManagerChromeOS() {}
-void TestMediaTransferProtocolManagerChromeOS::AddObserverAndEnumerateStorages(
- Observer* observer,
- EnumerateStoragesCallback callback) {
- std::move(callback).Run(std::vector<const device::mojom::MtpStorageInfo*>());
+void TestMediaTransferProtocolManagerChromeOS::AddBinding(
+ device::mojom::MtpManagerRequest request) {
+ bindings_.AddBinding(this, std::move(request));
}
-void TestMediaTransferProtocolManagerChromeOS::RemoveObserver(
- Observer* observer) {}
-
-void TestMediaTransferProtocolManagerChromeOS::GetStorages(
- GetStoragesCallback callback) const {
- std::move(callback).Run(std::vector<std::string>());
+void TestMediaTransferProtocolManagerChromeOS::EnumerateStoragesAndSetClient(
+ device::mojom::MtpManagerClientAssociatedPtrInfo client,
+ EnumerateStoragesAndSetClientCallback callback) {
+ std::move(callback).Run(std::vector<device::mojom::MtpStorageInfoPtr>());
}
void TestMediaTransferProtocolManagerChromeOS::GetStorageInfo(
const std::string& storage_name,
- GetStorageInfoCallback callback) const {
+ GetStorageInfoCallback callback) {
std::move(callback).Run(nullptr);
}
void TestMediaTransferProtocolManagerChromeOS::GetStorageInfoFromDevice(
const std::string& storage_name,
- const GetStorageInfoFromDeviceCallback& callback) {
- device::mojom::MtpStorageInfo mtp_storage_info;
- callback.Run(mtp_storage_info, true /* error */);
+ GetStorageInfoFromDeviceCallback callback) {
+ std::move(callback).Run(device::mojom::MtpStorageInfo::New(),
+ true /* error */);
}
void TestMediaTransferProtocolManagerChromeOS::OpenStorage(
const std::string& storage_name,
const std::string& mode,
- const OpenStorageCallback& callback) {
- callback.Run("", true);
+ OpenStorageCallback callback) {
+ std::move(callback).Run("", true);
}
void TestMediaTransferProtocolManagerChromeOS::CloseStorage(
const std::string& storage_handle,
- const CloseStorageCallback& callback) {
- callback.Run(true);
+ CloseStorageCallback callback) {
+ std::move(callback).Run(true);
}
void TestMediaTransferProtocolManagerChromeOS::CreateDirectory(
const std::string& storage_handle,
- const uint32_t parent_id,
+ uint32_t parent_id,
const std::string& directory_name,
- const CreateDirectoryCallback& callback) {
- callback.Run(true /* error */);
+ CreateDirectoryCallback callback) {
+ std::move(callback).Run(true /* error */);
}
-void TestMediaTransferProtocolManagerChromeOS::ReadDirectory(
+void TestMediaTransferProtocolManagerChromeOS::ReadDirectoryEntryIds(
const std::string& storage_handle,
- const uint32_t file_id,
- const size_t max_size,
- const ReadDirectoryCallback& callback) {
- callback.Run(std::vector<device::mojom::MtpFileEntry>(),
- false /* no more entries*/,
- true /* error */);
+ uint32_t file_id,
+ ReadDirectoryEntryIdsCallback callback) {
+ std::move(callback).Run(std::vector<uint32_t>(), /*error=*/true);
}
void TestMediaTransferProtocolManagerChromeOS::ReadFileChunk(
@@ -75,39 +83,41 @@ void TestMediaTransferProtocolManagerChromeOS::ReadFileChunk(
uint32_t file_id,
uint32_t offset,
uint32_t count,
- const ReadFileCallback& callback) {
- callback.Run(std::string(), true);
+ ReadFileChunkCallback callback) {
+ std::move(callback).Run(std::string(), true);
}
void TestMediaTransferProtocolManagerChromeOS::GetFileInfo(
const std::string& storage_handle,
- uint32_t file_id,
- const GetFileInfoCallback& callback) {
- callback.Run(device::mojom::MtpFileEntry(), true);
+ const std::vector<uint32_t>& file_ids,
+ uint32_t offset,
+ uint32_t entries_to_read,
+ GetFileInfoCallback callback) {
+ std::move(callback).Run(std::vector<device::mojom::MtpFileEntryPtr>(), true);
}
void TestMediaTransferProtocolManagerChromeOS::RenameObject(
const std::string& storage_handle,
- const uint32_t object_id,
+ uint32_t object_id,
const std::string& new_name,
- const RenameObjectCallback& callback) {
- callback.Run(true /* error */);
+ RenameObjectCallback callback) {
+ std::move(callback).Run(true /* error */);
}
void TestMediaTransferProtocolManagerChromeOS::CopyFileFromLocal(
const std::string& storage_handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
+ int64_t source_file_descriptor,
+ uint32_t parent_id,
const std::string& file_name,
- const CopyFileFromLocalCallback& callback) {
- callback.Run(true /* error */);
+ CopyFileFromLocalCallback callback) {
+ std::move(callback).Run(true /* error */);
}
void TestMediaTransferProtocolManagerChromeOS::DeleteObject(
const std::string& storage_handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback) {
- callback.Run(true /* error */);
+ uint32_t object_id,
+ DeleteObjectCallback callback) {
+ std::move(callback).Run(true /* error */);
}
} // namespace storage_monitor
diff --git a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h
index 4db023fdd29..5097b074871 100644
--- a/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h
+++ b/chromium/components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h
@@ -8,63 +8,70 @@
#include <stddef.h>
#include <stdint.h>
+#include <string>
+
#include "base/macros.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/device/public/mojom/mtp_manager.mojom.h"
namespace storage_monitor {
// A dummy MediaTransferProtocolManager implementation.
class TestMediaTransferProtocolManagerChromeOS
- : public device::MediaTransferProtocolManager {
+ : public device::mojom::MtpManager {
public:
+ static TestMediaTransferProtocolManagerChromeOS* GetFakeMtpManager();
TestMediaTransferProtocolManagerChromeOS();
~TestMediaTransferProtocolManagerChromeOS() override;
+ void AddBinding(device::mojom::MtpManagerRequest request);
+
private:
- // device::MediaTransferProtocolManager implementation.
- void AddObserverAndEnumerateStorages(
- Observer* observer,
- EnumerateStoragesCallback callback) override;
- void RemoveObserver(Observer* observer) override;
- void GetStorages(GetStoragesCallback callback) const override;
+ // device::mojom::MtpManager implementation.
+ void EnumerateStoragesAndSetClient(
+ device::mojom::MtpManagerClientAssociatedPtrInfo client,
+ EnumerateStoragesAndSetClientCallback callback) override;
void GetStorageInfo(const std::string& storage_name,
- GetStorageInfoCallback callback) const override;
+ GetStorageInfoCallback callback) override;
void GetStorageInfoFromDevice(
const std::string& storage_name,
- const GetStorageInfoFromDeviceCallback& callback) override;
+ GetStorageInfoFromDeviceCallback callback) override;
void OpenStorage(const std::string& storage_name,
const std::string& mode,
- const OpenStorageCallback& callback) override;
+ OpenStorageCallback callback) override;
void CloseStorage(const std::string& storage_handle,
- const CloseStorageCallback& callback) override;
+ CloseStorageCallback callback) override;
void CreateDirectory(const std::string& storage_handle,
- const uint32_t parent_id,
+ uint32_t parent_id,
const std::string& directory_name,
- const CreateDirectoryCallback& callback) override;
- void ReadDirectory(const std::string& storage_handle,
- const uint32_t file_id,
- const size_t max_size,
- const ReadDirectoryCallback& callback) override;
+ CreateDirectoryCallback callback) override;
+ void ReadDirectoryEntryIds(const std::string& storage_handle,
+ uint32_t file_id,
+ ReadDirectoryEntryIdsCallback callback) override;
void ReadFileChunk(const std::string& storage_handle,
uint32_t file_id,
uint32_t offset,
uint32_t count,
- const ReadFileCallback& callback) override;
+ ReadFileChunkCallback callback) override;
void GetFileInfo(const std::string& storage_handle,
- uint32_t file_id,
- const GetFileInfoCallback& callback) override;
+ const std::vector<uint32_t>& file_ids,
+ uint32_t offset,
+ uint32_t entries_to_read,
+ GetFileInfoCallback callback) override;
void RenameObject(const std::string& storage_handle,
- const uint32_t object_id,
+ uint32_t object_id,
const std::string& new_name,
- const RenameObjectCallback& callback) override;
+ RenameObjectCallback callback) override;
void CopyFileFromLocal(const std::string& storage_handle,
- const int source_file_descriptor,
- const uint32_t parent_id,
+ int64_t source_file_descriptor,
+ uint32_t parent_id,
const std::string& file_name,
- const CopyFileFromLocalCallback& callback) override;
+ CopyFileFromLocalCallback callback) override;
void DeleteObject(const std::string& storage_handle,
- const uint32_t object_id,
- const DeleteObjectCallback& callback) override;
+ uint32_t object_id,
+ DeleteObjectCallback callback) override;
+
+ mojo::BindingSet<device::mojom::MtpManager> bindings_;
DISALLOW_COPY_AND_ASSIGN(TestMediaTransferProtocolManagerChromeOS);
};
diff --git a/chromium/components/storage_monitor/test_storage_monitor.cc b/chromium/components/storage_monitor/test_storage_monitor.cc
index e606f8a097e..b13eee16e4d 100644
--- a/chromium/components/storage_monitor/test_storage_monitor.cc
+++ b/chromium/components/storage_monitor/test_storage_monitor.cc
@@ -13,17 +13,16 @@
#if defined(OS_CHROMEOS)
#include "components/storage_monitor/test_media_transfer_protocol_manager_chromeos.h"
-#include "device/media_transfer_protocol/media_transfer_protocol_manager.h" // nogncheck
#endif
namespace storage_monitor {
-TestStorageMonitor::TestStorageMonitor()
- : StorageMonitor(),
- init_called_(false) {
+TestStorageMonitor::TestStorageMonitor() : init_called_(false) {
#if defined(OS_CHROMEOS)
- media_transfer_protocol_manager_.reset(
- new TestMediaTransferProtocolManagerChromeOS());
+ auto* fake_mtp_manager =
+ TestMediaTransferProtocolManagerChromeOS::GetFakeMtpManager();
+ fake_mtp_manager->AddBinding(
+ mojo::MakeRequest(&media_transfer_protocol_manager_));
#endif
}
@@ -116,7 +115,7 @@ bool TestStorageMonitor::GetMTPStorageInfoFromDeviceId(
#endif
#if defined(OS_CHROMEOS)
-device::MediaTransferProtocolManager*
+device::mojom::MtpManager*
TestStorageMonitor::media_transfer_protocol_manager() {
return media_transfer_protocol_manager_.get();
}
diff --git a/chromium/components/storage_monitor/test_storage_monitor.h b/chromium/components/storage_monitor/test_storage_monitor.h
index df3c57a4240..ead83604607 100644
--- a/chromium/components/storage_monitor/test_storage_monitor.h
+++ b/chromium/components/storage_monitor/test_storage_monitor.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
+#include <vector>
#include "build/build_config.h"
#include "components/storage_monitor/storage_monitor.h"
@@ -47,8 +48,7 @@ class TestStorageMonitor : public StorageMonitor {
#endif
#if defined(OS_CHROMEOS)
- device::MediaTransferProtocolManager* media_transfer_protocol_manager()
- override;
+ device::mojom::MtpManager* media_transfer_protocol_manager() override;
#endif
Receiver* receiver() const override;
@@ -74,8 +74,7 @@ class TestStorageMonitor : public StorageMonitor {
std::vector<base::FilePath> removable_paths_;
#if defined(OS_CHROMEOS)
- std::unique_ptr<device::MediaTransferProtocolManager>
- media_transfer_protocol_manager_;
+ device::mojom::MtpManagerPtr media_transfer_protocol_manager_;
#endif
};
diff --git a/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc b/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc
index 79521095a34..0c314bd85ce 100644
--- a/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/test_volume_mount_watcher_win.cc
@@ -111,7 +111,7 @@ void TestVolumeMountWatcherWin::SetAttachedDevicesFake() {
void TestVolumeMountWatcherWin::DeviceCheckComplete(
const base::FilePath& device_path) {
devices_checked_.push_back(device_path);
- if (device_check_complete_event_.get())
+ if (device_check_complete_event_)
device_check_complete_event_->Wait();
VolumeMountWatcherWin::DeviceCheckComplete(device_path);
}
diff --git a/chromium/components/storage_monitor/volume_mount_watcher_win.cc b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
index b8b29fa9352..1be2c3be683 100644
--- a/chromium/components/storage_monitor/volume_mount_watcher_win.cc
+++ b/chromium/components/storage_monitor/volume_mount_watcher_win.cc
@@ -161,7 +161,7 @@ bool GetDeviceDetails(const base::FilePath& device_path, StorageInfo* info) {
base::string16 volume_label;
GetVolumeInformationW(device_path.value().c_str(),
base::WriteInto(&volume_label, kMaxPathBufLen),
- kMaxPathBufLen, NULL, NULL, NULL, NULL, 0);
+ kMaxPathBufLen, nullptr, nullptr, nullptr, nullptr, 0);
uint64_t total_size_in_bytes = GetVolumeSize(mount_path);
std::string device_id =
@@ -231,9 +231,8 @@ void EjectDeviceInThreadPool(
base::SStringPrintf(&volume_name, L"\\\\.\\%lc:", drive_letter);
base::win::ScopedHandle volume_handle(CreateFile(
- volume_name.c_str(),
- GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, 0, NULL));
+ volume_name.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ nullptr, OPEN_EXISTING, 0, nullptr));
if (!volume_handle.IsValid()) {
BrowserThread::PostTask(
@@ -248,8 +247,8 @@ void EjectDeviceInThreadPool(
// files on it). If this fails, it means some other process has files
// open on the device. Note that the lock is released when the volume
// handle is closed, and this is done by the ScopedHandle above.
- BOOL locked = DeviceIoControl(volume_handle.Get(), FSCTL_LOCK_VOLUME,
- NULL, 0, NULL, 0, &bytes_returned, NULL);
+ BOOL locked = DeviceIoControl(volume_handle.Get(), FSCTL_LOCK_VOLUME, nullptr,
+ 0, nullptr, 0, &bytes_returned, nullptr);
if (!locked) {
const int kNumLockRetries = 1;
const base::TimeDelta kLockRetryInterval =
@@ -273,15 +272,16 @@ void EjectDeviceInThreadPool(
// Unmount the device from the filesystem -- this will remove it from
// the file picker, drive enumerations, etc.
- BOOL dismounted = DeviceIoControl(volume_handle.Get(), FSCTL_DISMOUNT_VOLUME,
- NULL, 0, NULL, 0, &bytes_returned, NULL);
+ BOOL dismounted =
+ DeviceIoControl(volume_handle.Get(), FSCTL_DISMOUNT_VOLUME, nullptr, 0,
+ nullptr, 0, &bytes_returned, nullptr);
// Reached if we acquired a lock, but could not dismount. This might
// occur if another process unmounted without locking. Call this OK,
// since the volume is now unreachable.
if (!dismounted) {
- DeviceIoControl(volume_handle.Get(), FSCTL_UNLOCK_VOLUME,
- NULL, 0, NULL, 0, &bytes_returned, NULL);
+ DeviceIoControl(volume_handle.Get(), FSCTL_UNLOCK_VOLUME, nullptr, 0,
+ nullptr, 0, &bytes_returned, nullptr);
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(callback, StorageMonitor::EJECT_OK));
return;
@@ -291,8 +291,8 @@ void EjectDeviceInThreadPool(
pmr_buffer.PreventMediaRemoval = FALSE;
// Mark the device as safe to remove.
if (!DeviceIoControl(volume_handle.Get(), IOCTL_STORAGE_MEDIA_REMOVAL,
- &pmr_buffer, sizeof(PREVENT_MEDIA_REMOVAL),
- NULL, 0, &bytes_returned, NULL)) {
+ &pmr_buffer, sizeof(PREVENT_MEDIA_REMOVAL), nullptr, 0,
+ &bytes_returned, nullptr)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(callback, StorageMonitor::EJECT_FAILURE));
@@ -300,8 +300,8 @@ void EjectDeviceInThreadPool(
}
// Physically eject or soft-eject the device.
- if (!DeviceIoControl(volume_handle.Get(), IOCTL_STORAGE_EJECT_MEDIA,
- NULL, 0, NULL, 0, &bytes_returned, NULL)) {
+ if (!DeviceIoControl(volume_handle.Get(), IOCTL_STORAGE_EJECT_MEDIA, nullptr,
+ 0, nullptr, 0, &bytes_returned, nullptr)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(callback, StorageMonitor::EJECT_FAILURE));
diff --git a/chromium/components/strings/components_strings_am.xtb b/chromium/components/strings/components_strings_am.xtb
index 753121e5073..674f9e7e129 100644
--- a/chromium/components/strings/components_strings_am.xtb
+++ b/chromium/components/strings/components_strings_am.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">ለ<ph name="PERMISSION_NAME" /> ፈቃድ አቀናብር</translation>
<translation id="1111153019813902504">የቅርብ ጊዜ ዕልባቶች</translation>
<translation id="1113869188872983271">&amp;እንደገና ደርድርን ቀልብስ</translation>
+<translation id="1125573121925420732">ማስጠንቀቂያዎች ድርጣቢያዎች የእነርሱን ደህንነት በሚያዘምኑበት ጊዜ የተለመዱ ሊሆኑ ይችላሉ። ይህ በቅርቡ መሻሻል አለበት።</translation>
<translation id="1126551341858583091">የአካባቢያዊ ማከማቻው መጠን <ph name="CRASH_SIZE" /> ነው።</translation>
<translation id="112840717907525620">የመምሪያ መሸጎጫ እሺ</translation>
<translation id="1150979032973867961">ይህ አገልጋይ <ph name="DOMAIN" /> መሆኑን ሊያረጋግጥ አልቻለም፤ የደህንነት እውቅና ማረጋገጫው በኮምፒውተርዎ ስርዓተ ክወና የሚታመን አይደለም። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;የበይነመረብ ግንኙነትዎን በአግባቡ እየሰራ መሆኑን ያረጋግጡ።&lt;/li&gt;
&lt;li&gt;የድር ጣቢያውን ባለቤት ያነጋግሩ።&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">የእርስዎን የይለፍ ቃል በድርጅትዎ በማይተዳደር ጣቢያ ላይ አስገብተዋል። የእርስዎን መለያ ለመጠበቅ ሲባል የእርስዎን የይለፍ ቃል በሌሎች መተግበሪያዎች እና ጣቢያዎች ላይ አይጠቀሙበት።</translation>
<translation id="1263231323834454256">የንባብ ዝርዝር</translation>
<translation id="1264126396475825575">በ<ph name="CRASH_TIME" /> ላይ የብልሽት ሪፖርት ተይዟል (እስካሁን አልተሰቀለም ወይም ችላ አልተባለም)</translation>
<translation id="1270502636509132238">የመውሰጃ ስልት</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">ምረጥ</translation>
<translation id="1620510694547887537">ካሜራ</translation>
<translation id="1623104350909869708">ይህ ገጽ ተጨማሪ መገናኛዎችን እንዳይፈጥር አግድ</translation>
-<translation id="1629803312968146339">ይህን ካርድ Chrome እንዲያስቀምጥልዎት ይፈልጋሉ?</translation>
<translation id="1639239467298939599">በመጫን ላይ</translation>
<translation id="1640180200866533862">የተጠቃሚ መምሪያዎች</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />የጣቢያውን መነሻ ገጽ ለመጎብኘት<ph name="END_LINK" /> ይሞክሩ።</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />የWindows አውታረ መረብ መመርመሪያውን ለማሄድ ይሞክሩ<ph name="END_LINK" />።</translation>
<translation id="1783075131180517613">እባክዎ የማመሳሰል ይለፍ ሐረግዎን ያዘምኑ።</translation>
<translation id="1787142507584202372">የእርስዎ ክፍት ትሮች እዚህ ይመጣሉ</translation>
-<translation id="1789575671122666129">ብቅ-ባዮች</translation>
<translation id="1791429645902722292">Google ዘመናዊ ቁልፍ</translation>
<translation id="1803264062614276815">የካርድ ያዢው ስም</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> ላይ ታክሏል</translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">ኮምፒውተርዎን ዳግም ያስጀምሩት</translation>
<translation id="2113977810652731515">ካርታ</translation>
<translation id="2114841414352855701">በ<ph name="POLICY_NAME" /> ስለተሻረ ችላ ተብሏል።</translation>
-<translation id="2138201775715568214">በአቅራቢያ ያሉ አካላዊ ድረ-ገጾችን በመፈለግ ላይ</translation>
<translation id="213826338245044447">የተንቀሳቃሽ ስልክ ዕልባቶች</translation>
<translation id="214556005048008348">ክፍያን ሰርዝ</translation>
<translation id="2147827593068025794">የጀርባ ስምረት</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">መመሪያ አልተገኘም</translation>
<translation id="2213606439339815911">ግቤቶችን በማምጣት ላይ...</translation>
<translation id="2218879909401188352">በ<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ አሁን ያሉ አጥቂዎች የእርስዎን መሣሪያ የሚያበላሹ አደገኛ መተግበሪያዎችን ሊጭኑ፣ በእርስዎ ሞባይል ክፍያ መጠየቂያ ላይ የተደበቁ ክፍያ መጠየቂያዎችን ሊያክሉ ወይም የእርስዎን የግል መረጃ ሊሰርቁ ይችላሉ። <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ምንም በይነመረብ የለም</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />የመመርመሪያ መተግበሪያውን<ph name="END_LINK" /> በመጠቀም ግንኙነትዎን ያስተካክሉት</translation>
<translation id="2239100178324503013">አሁን ላክ</translation>
<translation id="225207911366869382">ይህ ዋጋ ለዚህ መመሪያ ተቋርጧል።</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">የተመረጡትን ንጥሎች አስወግድ</translation>
<translation id="277133753123645258">የመላኪያ ዘዴ</translation>
<translation id="277499241957683684">የሚጎድል የመሣሪያ መዝገብ</translation>
+<translation id="2781030394888168909">MacOSን ወደ ውጭ ይላኩ</translation>
<translation id="2784949926578158345">ግንኙነቱ ዳግም እንዲጀምር ተደርጓል።</translation>
<translation id="2788784517760473862">ተቀባይነት ያላቸው ክሬዲት ካርዶች</translation>
<translation id="2794233252405721443">ጣቢያ ታግዷል</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome በዚህ ጊዜ የእርስዎን ካርድ ማረጋገጥ አልቻለም። እባክዎ ቆይተው እንደገና ይሞክሩ።</translation>
<translation id="3064966200440839136">በውጫዊ ማከማቻ በኩል ለማጫወት ማንነት ከማያሳውቅ ሁነታ በመውጣት ላይ። ይቀጥል?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ምንም}=1{1 የይለፍ ቃል}one{# የይለፍ ቃሎች}other{# የይለፍ ቃሎች}}</translation>
-<translation id="3093245981617870298">ከመስመር ውጪ ነዎት።</translation>
<translation id="3096100844101284527">የመውሰጃ አድራሻ ያክሉ</translation>
<translation id="3105172416063519923">የእሴት መታወቂያ፦</translation>
<translation id="3109728660330352905">ይህን ገጽ ለማየት ፍቃድ የለዎትም።</translation>
@@ -361,6 +361,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> አሁን ላይ ሊደረስበት አይችልም።</translation>
<translation id="3427092606871434483">ፍቀድ (ነባሪ)</translation>
<translation id="3427342743765426898">&amp;አርትዕን ድገም</translation>
+<translation id="342781501876943858">Chromium የእርስዎን ይለፍ ቃል በሌሎች ጣቢያዎች ላይ ዳግም ከተጠቀሙበት እንደገና እንዲያዋቅሩት ይመክራል።</translation>
<translation id="3431636764301398940">ይህን ካርድ ወደዚህ መሣሪያ አስቀምጥ</translation>
<translation id="3447661539832366887">የዚህ መሣሪያ ባለቤት የዳይኖሰር ጨዋታውን አጥፍቶታል።</translation>
<translation id="3447884698081792621">የእውቅና ማረጋገጫን አሳይ (በ<ph name="ISSUER" /> የሚሰጥ)</translation>
@@ -397,7 +398,6 @@
<translation id="3678529606614285348">ገጹን ማንነት በማያሳውቅ አዲስ መስኮት ውስጥ ይክፈቱ (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">የብልሽት ሪፖርት <ph name="CRASH_TIME" /> ላይ ተይዟል፣ <ph name="UPLOAD_TIME" /> ላይ ተሰቅሏል</translation>
<translation id="3681007416295224113">የሰርቲፊኬት መረጃ</translation>
-<translation id="3690164694835360974">መግቢያ ደህንነቱ የተጠበቀ አይደለም</translation>
<translation id="3704162925118123524">እየተጠቀሙ ያሉት አውታረ መረብ በመለያ መግቢያ ገጹን እንዲጎበኙ ሊጠይቅዎት ይችላል።</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">በመጫን ላይ…</translation>
@@ -457,7 +457,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">ሁለገብ ነባሪን ተጠቀም (አግኝ)</translation>
<translation id="4165986682804962316">የጣቢያ ቅንብሮች</translation>
-<translation id="4169947484918424451">Chromium ይህን ካርድ እንዲያስቀምጥልዎት ይፈልጋሉ?</translation>
<translation id="4171400957073367226">መጥፎ የማረጋገጫ ፊርማ</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> ተጨማሪ ንጥል}one{<ph name="ITEM_COUNT" /> ተጨማሪ ንጥሎች}other{<ph name="ITEM_COUNT" /> ተጨማሪ ንጥሎች}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -494,6 +493,7 @@
<translation id="4275830172053184480">መሣሪያዎን ዳግም ያስጀምሩ</translation>
<translation id="4277028893293644418">የይለፍ ቃል ዳግም አቀናብር</translation>
<translation id="4280429058323657511">፣ አገልግሎቱ የሚያበቃው በ<ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">ቀይር</translation>
<translation id="4312866146174492540">አግድ (ነባሪ)</translation>
<translation id="4325863107915753736">ጽሑፉን ማግኘት አልተቻለም</translation>
<translation id="4326324639298822553">የእርስዎን የአገልግሎት ማብቂያ ቀን ይመልከቱ እና እንደገና ይሞክሩ</translation>
@@ -501,6 +501,7 @@
<translation id="4340982228985273705">ይህ ኮምፒውተር እንደ በድርጅት የሚተዳደር ሆኖ አይታይም፣ ስለዚህ መመሪያ በChrome የድር ማከማቻ ላይ የሚስተናገዱ ቅጥያዎችን ብቻ በራስ-ሰር ነው መጫን የሚችለው። የChrome ድር ማከማቻው ዝማኔ ዩአርኤል «<ph name="CWS_UPDATE_URL" />» ነው።</translation>
<translation id="4346197816712207223">ተቀባይነት ያላቸው ክሬዲት ካርዶች</translation>
<translation id="4356973930735388585">በዚህ ጣቢያ ላይ ያሉ አጥቂዎች መረጃዎን (ለምሳሌ፦ ፎቶዎች፣ የይለፍ ቃላት፣ መልዕክቶች እና ክሬዲት ካርዶች) ሊሰርቁ ወይም ሊሰርዙ የሚችሉ አደገኛ ፕሮግራሞችን በኮምፒውተርዎ ላይ ለመጫን ሊሞክሩ ይችላሉ።</translation>
+<translation id="4358461427845829800">የመክፈያ ዘዴዎችን ያቀናብሩ...</translation>
<translation id="4372948949327679948">የተጠበቀው የ<ph name="VALUE_TYPE" /> ዋጋ ነው።</translation>
<translation id="4377125064752653719"><ph name="DOMAIN" />ን ለመድረስ ሞክረዋል፣ ነገር ግን አገልጋዩ ያቀረበው የእውቅና ማረጋገጫ በሰጪው ተሽሯል። ይህ ማለት አገልጋዩ ያቀረበው የደህንነት ምስክርነቶች ፈጽሞ ሊታመኑ አይገባም። ከአጥቂ ጋር እየተገናኙ ሊሆን ይችላል።</translation>
<translation id="4406896451731180161">የፍለጋ ውጤቶች</translation>
@@ -508,6 +509,7 @@
<translation id="4415426530740016218">የመውሰጃ አድራሻ</translation>
<translation id="4424024547088906515">ይህ አገልጋይ <ph name="DOMAIN" /> መሆኑን ሊያረጋግጥ አልቻለም፤ የደህንነት እውቅና ማረጋገጫው በChrome የሚታመን አይደለም። ይሄ በተሳሳተ አወቃቀር ወይም አንድ አጥቂ ግንኙነትዎን በመጥለፉ የተከሰተ ሊሆን ይችላል።</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> የመግቢያ እውቅና ማረጋገጫዎን አልተቀበለም፣ ወይም ገና አልተሰጠዎት ይሆናል።</translation>
+<translation id="4434045419905280838">ብቅ-ባዮች እና አቅጣጫ ማዞሮች</translation>
<translation id="443673843213245140">የተኪ መጠቀም ተሰናክሏል ግን ግልጽ የሆነ የተኪ ውቅር ተገልጿል።</translation>
<translation id="445100540951337728">ተቀባይነት ያላቸው ዴቢት ካርዶች</translation>
<translation id="4506176782989081258">የማረጋገጥ ስህተት፦ <ph name="VALIDATION_ERROR" /></translation>
@@ -542,13 +544,13 @@
<translation id="4759118997339041434">የክፍያ ራስ-መሙላት ተሰናክሏል</translation>
<translation id="4764776831041365478"><ph name="URL" /> ላይ ያለው ድረ-ገጽ ለጊዜው የማይሰራ ወይም እስከመጨረሻው ወደ አዲስ የድር አድራሻ ተዛውሮ ሊሆን ይችላል።</translation>
<translation id="4771973620359291008">ያልታወቀ ስህተት ተከስቷል።</translation>
+<translation id="4785689107224900852">ወደዚህ ትር ቀይር</translation>
<translation id="4792143361752574037">የክፍለ-ጊዜ ፋይሎችን መድረስ ላይ አንድ ችግር ነበር። ወደ ዲስክ ማስቀመጥ በአሁኑ ጊዜ ተሰናክሏል። እንደገና ለመሞከር እባክዎ ገጹን ዳግም ይጫኑት።</translation>
<translation id="4800132727771399293">የእርስዎን የአገልግሎት ማብቂያ ቀን እና CVC ይፈትሹ እና እንደገና ይሞክሩ</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102"><ph name="SITE" /> Google Chrome ሊሰራባቸው የማይችላቸው የተዘበራረቁ ምስክርነቶችን ስለላከ ድር ጣቢያውን አሁን መጎብኘት አይችሉም። የአውታረ መረብ ስህተቶች እና ጥቃቶች አብዛኛው ጊዜ ጊዜያዊ ናቸው፣ ስለዚህ ይህ ገጽ በኋላ ላይ ሊሰራ ይችላል።</translation>
<translation id="4813512666221746211">የአውታረ መረብ ስህተት</translation>
<translation id="4816492930507672669">ገጹን አመጣጥን</translation>
-<translation id="483020001682031208">ምንም የሚታዩ አካላዊ ድረ-ገጾች የሉም</translation>
<translation id="4850886885716139402">አሳይ</translation>
<translation id="4854362297993841467">የማድረሻ ዘዴው አይገኝም። የተለየ ዘዴ ይሞክሩ።</translation>
<translation id="4858792381671956233">ይህን ገጽ መጎብኘት ችግር ካለው ወላጆችዎንጠይቀዋል</translation>
@@ -588,6 +590,7 @@
<translation id="5115563688576182185">(64-ቢት)</translation>
<translation id="5121084798328133320">ካረጋገጡ በኋላ የGoogle Payments መለያዎ ካርድ ዝርዝሮች ለዚህ ጣቢያ ይጋራሉ።</translation>
<translation id="5128122789703661928">ይህ ስም ያለው ክፍለ-ጊዜ ለስረዛ ልክ ያልሆነ ነው።</translation>
+<translation id="5135404736266831032">አድራሻዎችን ያቀናብሩ...</translation>
<translation id="5141240743006678641">የተመሳሰሉ የይለፍ ቃላት ከGoogle ምስክርነቶችዎ ጋር ያመሳስሉ</translation>
<translation id="5145883236150621069">የስህተት ኮድ በመምሪያው ምላሽ ውስጥ አለ</translation>
<translation id="5159010409087891077">ገጹን ማንነት በማያሳውቅ አዲስ መስኮት ውስጥ ይክፈቱ (⇧⌘N)</translation>
@@ -599,7 +602,6 @@
<translation id="5201306358585911203">በዚህ ድረ-ገጽ ላይ ያለ የተካተተ ገጽ እንዲህ ይላል፦</translation>
<translation id="5205222826937269299">ስም ያስፈልጋል</translation>
<translation id="5222812217790122047">ኢሜይል ያስፈልጋል</translation>
-<translation id="522700295135997067">ይህ ጣቢያ አሁን የይለፍ ቃልዎን ሰርቆት ሊሆን ይችላል</translation>
<translation id="5230733896359313003">የሚላክበት አድራሻ</translation>
<translation id="5250209940322997802">«ከአውታረ መረብ ጋር ይገናኙ»</translation>
<translation id="5251803541071282808">ደመና</translation>
@@ -643,7 +645,6 @@
<translation id="5492298309214877701">በኩባንያ፣ በድርጅት ወይም በትምህርት ቤት ውስጠ መረብ ውስጥ ያለው ይህ ጣቢያ እንደ ውጫዊ የድር ጣቢያ ተመሳሳይ ዩአርኤል አለው።
<ph name="LINE_BREAK" />
የእርስዎን የስርዓት አስተዳዳሪ ለማነጋገር ይሞክሩ።</translation>
-<translation id="5499929369096410817">የ<ph name="CREDIT_CARD" /> ደህንነት ኮድ ያስገቡ። ይህ ኮድ አይቀመጥም።</translation>
<translation id="5509780412636533143">የተዳደሩ እልባቶች</translation>
<translation id="5510766032865166053">ተወስዶ ወይም ተሰርዞ ሊሆን ይችላል።</translation>
<translation id="5523118979700054094">የመምሪያ ስም</translation>
@@ -674,9 +675,11 @@
<translation id="5685654322157854305">የመላኪያ አድራሻ ያክሉ</translation>
<translation id="5689199277474810259">ወደ JSON ላክ</translation>
<translation id="5689516760719285838">አካባቢ</translation>
+<translation id="570530837424789914">ያቀናብሩ...</translation>
<translation id="5710435578057952990">የዚህ ድረ-ገጽ ማንነት አልተረጋገጠም።</translation>
<translation id="5719499550583120431">የቅድመ-ክፍያ ካርዶች ተቀባይነት አላቸው።</translation>
<translation id="5720705177508910913">የአሁኑ ተጠቃሚ</translation>
+<translation id="5730040223043577876">Chrome የእርስዎን ይለፍ ቃል በሌሎች ጣቢያዎች ላይ ዳግም ከተጠቀሙበት እንደገና እንዲያዋቅሩት ይመክራል።</translation>
<translation id="5732392974455271431">የእርስዎ ወላጆች እገዳውን ሊያነሱልዎ ይችላሉ</translation>
<translation id="5763042198335101085">ትክክለኛ የኢሜይል አድራሻ ያስገቡ</translation>
<translation id="5765072501007116331">የማድረሻ ዘዴዎችን እና መስፈርቶችን ለመመልከት አድራሻ ይምረጡ</translation>
@@ -700,9 +703,7 @@
<translation id="5959728338436674663">አደገኛ መተግበሪያዎችን እና ጣቢያዎችን ማግኘት እንዲያግዝ አንዳንድ <ph name="BEGIN_WHITEPAPER_LINK" />የሥርዓት መረጃ እና የገጽ ይዘት<ph name="END_WHITEPAPER_LINK" />ን በራስ-ሰር ወደ Google ይላኩ። <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">የዕውቂያ መረጃን ያርትዑ</translation>
<translation id="5967867314010545767">ከታሪክ አስወግድ</translation>
-<translation id="5972020793760134803">ወደ ትር ቀይር</translation>
<translation id="5975083100439434680">አሳንስ</translation>
-<translation id="597552863672748783">የደህነንት ኮድ ያረጋግጡ</translation>
<translation id="598637245381783098">የክፍያ መተግበሪያን መክፈት አይቻልም</translation>
<translation id="5989320800837274978">ቋሚ ተኪ አገልጋዮችም ሆኑ የ.pac ስክሪፕት ዩአርኤል አልተገለጹም።</translation>
<translation id="5990559369517809815">ወደ አገልጋዩ የተላኩ ጥያቄዎች በአንድ ቅጥያ ታግደዋል።</translation>
@@ -718,6 +719,7 @@
<translation id="6047927260846328439">ይህ ይዘት ሶፍትዌር እንዲጭኑ ወይም የግል መረጃ ገልጸው እንዲያሳዩ እርስዎን ለማሳሳት ሊሞክር ይችል ይሆናል። <ph name="BEGIN_LINK" />የሆነው ሆኖ አሳይ<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> የዕውቅና ማረጋገጫ ሚስማር መሰካትን ስለሚጠቀም ድር ጣቢያውን አሁን መጎብኘት አይችሉም። የአውታረ መረብ ስህተቶች እና ጥቃቶች ብዙውን ጊዜ ጊዜያዊ ስለሆኑ ይህ ገጽ በኋላ ላይ ሊሠራ ይችላል።</translation>
<translation id="6059925163896151826">የዩኤስቢ መሣሪያዎች</translation>
+<translation id="6071091556643036997">የመመሪያው አይነት ልክ ያልሆነ ነው።</translation>
<translation id="6080696365213338172">በአስተዳዳሪ የቀረበ የእውቅና ማረጋገጫ በመጠቀም ይዘት ደርሰዋል። ለ<ph name="DOMAIN" /> የሚያቀርቡት ውሂብ በአስተዳዳሪዎ ሊያዝ ይችላል።</translation>
<translation id="610911394827799129">የእርስዎ Google መለያ <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> ላይ ሌሎች የአሰሳ ታሪክ ዓይነቶች ሊኖረው ይችላል።</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ምንም}=1{1 የይለፍ ቃል (የተሰመረ)}one{# የይለፍ ቃሎች (የተሰመሩ)}other{# የይለፍ ቃሎች (የተሰመሩ)}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">ተጨማሪ መረጃ ያክሉ</translation>
<translation id="6447842834002726250">ኩኪዎች</translation>
<translation id="6451458296329894277">እንደገና ለማስገባት የማረጋገጫ ቅጽ</translation>
+<translation id="6465306955648956876">የይለፍ ቃላትን ያቀናብሩ...</translation>
<translation id="647261751007945333">የመሣሪያ መምሪያዎች</translation>
<translation id="6477321094435799029">Chrome በዚህ ገጽ ላይ ያልተለመደ ኮድ አግኝቷል፣ እና የእርስዎን የግል መረጃ (ለምሳሌ፦ የይለፍ ቃላት፣ ስልክ ቁጥሮች እና ክሬዲት ካርዶች) ለመጠበቅ ሲባል አግዶታል።</translation>
<translation id="6489534406876378309">ድምስሶችን መስቀል ጀምር</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> ፍለጋ</translation>
<translation id="6630809736994426279">አሁን <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ላይ የሚገኙ አጥቂዎች የእርስዎን መረጃ (ለምሳሌ፦ ፎቶዎች፣ የይለፍ ቃላት፣ መልዕክቶች፣ እና ክሬዲት ካርዶች የመሳሰሉ) የሚሰርቁ ወይም የሚሰርዙ አደገኛ ፕሮግራሞችን በእርስዎ Mac ላይ ለመጫን እየሞከሩ ሊሆኑ ይችላሉ። <ph name="BEGIN_LEARN_MORE_LINK" />የበለጠ ለመረዳት<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">ይህ መመሪያ ተቋርጧል።</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{ምንም}=1{ከ1 ጣቢያ (ከእርስዎ የGoogle መለያ ዘግተው እንዲወጡ አይደረጉም)}one{ከ# ጣቢያዎች (ከእርስዎ የGoogle መለያ ዘግተው እንዲወጡ አይደረጉም)}other{ከ# ጣቢያዎች (ከእርስዎ የGoogle መለያ ዘግተው እንዲወጡ አይደረጉም)}}</translation>
<translation id="6657585470893396449">የይለፍ ቃል፦</translation>
<translation id="6671697161687535275">የአስተያየት ጥቆማ ከChromium ይወገድ?</translation>
<translation id="6685834062052613830">ዘግተው ይውጡ እና ቅንብርን ያጠናቅቁ</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">ተጠቃሚ፦</translation>
<translation id="6945221475159498467">ይምረጡ</translation>
<translation id="6948701128805548767">የመውሰጃ ዘዴዎችን እና መስፈርቶችን ለመመልከት አድራሻ ይምረጡ</translation>
+<translation id="6949872517221025916">የይለፍ ቃል ዳግም ያስገቡ</translation>
<translation id="6957887021205513506">የአገልጋዩ እውቅና ማረጋገጫ የተጭበረበረ ይመስላል።</translation>
<translation id="6965382102122355670">እሺ</translation>
<translation id="6965978654500191972">መሣሪያ</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">የማድረሻ ስልት</translation>
<translation id="7139724024395191329">ኤሚሬት</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ተጨማሪ}one{<ph name="PAYMENT_METHOD_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ተጨማሪ}other{<ph name="PAYMENT_METHOD_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ተጨማሪ}}</translation>
-<translation id="7155487117670177674">ክፍያ ደህንነቱ የተጠበቀ አይደለም</translation>
+<translation id="717330890047184534">የGaia መታወቂያ፦</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ተጨማሪ}one{<ph name="SHIPPING_OPTION_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ተጨማሪ}other{<ph name="SHIPPING_OPTION_PREVIEW" /> እና <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ተጨማሪ}}</translation>
<translation id="7180611975245234373">አድስ</translation>
<translation id="7182878459783632708">ምንም መምሪያዎች አልተዋቀሩም</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">ሁለንተናዊ ነባሪውን ተጠቀም (አግድ)</translation>
<translation id="7460163899615895653">ከሌሎች መሣሪያዎች የመጡ የቅርብ ጊዜ ትሮችዎ እዚህ ይመጣሉ</translation>
<translation id="7469372306589899959">ካርድን በማረጋገጥ ላይ</translation>
+<translation id="7473891865547856676">አይ፣ አመሰግናለሁ</translation>
<translation id="7481312909269577407">ወደ ፊት</translation>
<translation id="7485870689360869515">ምንም ውሂብ አልተገኘም።</translation>
<translation id="7508255263130623398">የተመላሽ መመሪያ መሣሪያ መታወቂያ ባዶ ነው ወይም ከአሁኑ የመሣሪያ መታወቂያ ጋር አይዛመድም</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">ክሬዲት ካርድ ከChrome ይወገድ?</translation>
<translation id="7575800019233204241">«የእርስዎ ግንኙነት ግላዊ አይደለም» ወይም «&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;» ወይም «&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;» ወይም «&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" or "SSL certificate error»</translation>
<translation id="7578104083680115302">Google ላይ ያስቀመጧቸውን ካርዶች በመጠቀም በሁሉም መሣሪያዎች ላይ በጣቢያዎችና መተግበሪያዎች ላይ በፍጥነት ይክፈሉ።</translation>
-<translation id="7588950540487816470">አካላዊ ድር</translation>
<translation id="7592362899630581445">የአገልጋዩ እውቅና ማረጋገጫ አንዳንድ ገደቦችን ይጥሳል።</translation>
<translation id="7598391785903975535">ከ<ph name="UPPER_ESTIMATE" /> በታች</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> በአሁኑ ጊዜ ይህን ጥያቄ ተቀብሎ ለማስተናገድ አይችልም።</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;አርትዕን ቀልብስ</translation>
<translation id="9154194610265714752">የተዘመነ</translation>
<translation id="9157595877708044936">በማዋቀር ላይ…</translation>
+<translation id="9168814207360376865">የተቀመጡ የመክፈያ ዘዴዎች ካልዎት ጣቢያዎች እንዲፈትሹ ይፍቀዱ</translation>
<translation id="9169664750068251925">ሁልጊዜ በዚህ ጣቢያ ላይ አግድ</translation>
<translation id="9170848237812810038">&amp;ቀልብስ</translation>
<translation id="917450738466192189">የአገልጋይ እውቅና ማረጋገጫ ልክ ያልኾነ ነው።</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">ጽሑፍ ማከል አልተቻለም።</translation>
<translation id="9215416866750762878">አንድ መተግበሪያ Chrome ከዚህ ጣቢያ ጋር ደህንነቱ በተጠበቀ ሁኔታ እንዳይገናኝ እያቆመው ነው</translation>
<translation id="9219103736887031265">ምስሎች</translation>
-<translation id="933612690413056017">ምንም የበይነመረብ ግንኙነት የለም</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ቅጽን አጽዳ</translation>
<translation id="939736085109172342">አዲስ ዓቃፊ</translation>
diff --git a/chromium/components/strings/components_strings_ar.xtb b/chromium/components/strings/components_strings_ar.xtb
index f659bd4bc26..0da3f3c71d5 100644
--- a/chromium/components/strings/components_strings_ar.xtb
+++ b/chromium/components/strings/components_strings_ar.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">اختيار إذن لـ <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">الإشارات الجديدة</translation>
<translation id="1113869188872983271">تراجع عن إعادة الت&amp;رتيب</translation>
+<translation id="1125573121925420732">قد يكثر ظهور التحذيرات أثناء إجراء مواقع الويب لتحديثات الأمان، لكنّ هذه المسألة ستتحسَّن قريبًا.</translation>
<translation id="1126551341858583091">يمثل الحجم على سعة التخزين المحلية <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ذاكرة التخزين المؤقت للسياسة بحالة جيدة</translation>
<translation id="1150979032973867961">هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان غير موثقة من خلال نظام تشغيل الكمبيوتر. وربما يكون السبب في ذلك خطأ في التكوين أو مهاجمًا يعترض الاتصال.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;تأكّد من أن اتصالك بالإنترنت يعمل بشكل طبيعي.&lt;/li&gt;
&lt;li&gt;اتصل بمالك موقع الويب.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">لقد أدخلتَ كلمة المرور في موقع ويب لا تديره مؤسستك. ينصح بعدم استخدام كلمة المرور مجددًا في التطبيقات ومواقع الويب الأخرى لحماية حسابك.</translation>
<translation id="1263231323834454256">قائمة القراءة</translation>
<translation id="1264126396475825575">تقرير الأعطال الذي تم الحصول عليه في <ph name="CRASH_TIME" /> (لم يتم تحميله بعد أو تجاهله)</translation>
<translation id="1270502636509132238">طريقة الاستلام</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">اختيار</translation>
<translation id="1620510694547887537">الكاميرا</translation>
<translation id="1623104350909869708">منع هذه الصفحة من إنشاء مربعات حوار إضافية.</translation>
-<translation id="1629803312968146339">‏هل تريد من Chrome حفظ هذه البطاقة؟</translation>
<translation id="1639239467298939599">جارٍ التحميل.</translation>
<translation id="1640180200866533862">سياسات المستخدم</translation>
<translation id="1640244768702815859">جرّب <ph name="BEGIN_LINK" />الانتقال إلى الصفحة الرئيسية للموقع<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159">‏<ph name="BEGIN_LINK" />تجربة تشغيل بيانات التشخيص لشبكة Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">يُرجى تحديث عبارة مرور المزامنة.</translation>
<translation id="1787142507584202372">تظهر علامات التبويب المفتوحة هنا</translation>
-<translation id="1789575671122666129">النوافذ المنبثقة</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">اسم حامل البطاقة</translation>
<translation id="1806541873155184440">تمت الإضافة في <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">إعادة تشغيل جهاز الكمبيوتر</translation>
<translation id="2113977810652731515">البطاقة</translation>
<translation id="2114841414352855701">تم تجاهلها نظرًا لتجاوزها بواسطة <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">جارٍ البحث عن صفحات الشبكة المادية المجاورة</translation>
<translation id="213826338245044447">الإشارات المرجعية على الجوال</translation>
<translation id="214556005048008348">إلغاء الدفع</translation>
<translation id="2147827593068025794">مزامنة الخلفية</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">تعذر العثور على السياسة</translation>
<translation id="2213606439339815911">جارٍ جلب الإدخالات...</translation>
<translation id="2218879909401188352">يمكن حاليًا للمهاجمين على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> تثبيت تطبيقات خطيرة تدمر الجهاز أو تضيف رسومًا إلى فاتورة الجوّال أو تسرق المعلومات الشخصية. <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">الاتصال بالإنترنت مقطوع</translation>
<translation id="2230458221926704099">إصلاح الاتصال باستخدام <ph name="BEGIN_LINK" />تطبيق بيانات التشخيص<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">إرسال الآن</translation>
<translation id="225207911366869382">تم تجاهل القيمة لهذه السياسة.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">إزالة العناصر المحددة</translation>
<translation id="277133753123645258">طريقة الشحن</translation>
<translation id="277499241957683684">سجِلّ الجهاز مفقود</translation>
+<translation id="2781030394888168909">‏تصدير نظام التشغيل MacOS</translation>
<translation id="2784949926578158345">تمت إعادة تعيين الاتصال.</translation>
<translation id="2788784517760473862">بطاقات الائتمان المقبولة</translation>
<translation id="2794233252405721443">تم حظر الموقع</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">‏لم يتمكن Chrome من التأكد من بطاقتك في الوقت الحالي. يُرجى إعادة المحاولة في وقت لاحق.</translation>
<translation id="3064966200440839136">ستتم مغادرة وضع التصفح المتخفي للدفع عبر تطبيق خارجي. هل تريد المتابعة؟</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{بدون}=1{كلمة مرور واحدة}two{كلمتا مرور (#)}few{# كلمات مرور}many{# كلمة مرور}other{# كلمة مرور}}</translation>
-<translation id="3093245981617870298">أنت غير متصل.</translation>
<translation id="3096100844101284527">إضافة عنوان الاستلام من المستخدم</translation>
<translation id="3105172416063519923">رقم تعريف الأصل:</translation>
<translation id="3109728660330352905">ليس لديك إذن بعرض هذه الصفحة.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">يتعذر الوصول إلى <ph name="HOST_NAME" /> حاليًا.</translation>
<translation id="3427092606871434483">السماح (تلقائي)</translation>
<translation id="3427342743765426898">إعادة الت&amp;حرير</translation>
+<translation id="342781501876943858">‏يُوصي Chromium بإعادة تحديد كلمة المرور في حال إعادة استخدامها في مواقع ويب أخرى.</translation>
<translation id="3431636764301398940">حفظ هذه البطاقة إلى هذا الجهاز</translation>
<translation id="3447661539832366887">أوقف مالك هذا الجهاز تشغيل لعبة الديناصور.</translation>
<translation id="3447884698081792621">عرض الشهادة (من إصدار <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">‏يمكنك فتح الصفحة في نافذة جديدة للتصفح المتخفي (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">تم تسجيل تقرير الأعطال في <ph name="CRASH_TIME" />، وتم تحميله في <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">معلومات الشهادة</translation>
-<translation id="3690164694835360974">عملية تسجيل الدخول غير آمنة</translation>
<translation id="3704162925118123524">قد تتطلب الشبكة التي تستخدمها زيارة صفحة تسجيل الدخول.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">جارٍ التحميل...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">استخدام الإعدادات العمومية التلقائية (كشف)</translation>
<translation id="4165986682804962316">إعدادات الموقع</translation>
-<translation id="4169947484918424451">‏هل تريد من Chromium حفظ هذه البطاقة؟</translation>
<translation id="4171400957073367226">توقيع تحقق سيئ</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{عنصر (<ph name="ITEM_COUNT" />) آخر}zero{<ph name="ITEM_COUNT" /> عنصر آخر}two{عنصران (<ph name="ITEM_COUNT" />) آخران}few{<ph name="ITEM_COUNT" /> عناصر أخرى}many{<ph name="ITEM_COUNT" /> عنصرًا آخر}other{<ph name="ITEM_COUNT" /> عنصر آخر}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">إعادة تشغيل جهازك</translation>
<translation id="4277028893293644418">إعادة تعيين كلمة المرور</translation>
<translation id="4280429058323657511">، تاريخ انتهاء الصلاحية <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">تبديل</translation>
<translation id="4312866146174492540">حظر (تلقائي)</translation>
<translation id="4325863107915753736">تعذّر العثور على المقالة</translation>
<translation id="4326324639298822553">تحقق من تاريخ انتهاء الصلاحية وأعِد المحاولة مرة أخرى</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">‏لا يتم رصد جهاز الكمبيوتر هذا كمؤسسة مُدارة حتى تتمكن السياسة فقط من التثبيت التلقائي للإضافات التي تمت استضافتها في سوق Chrome الإلكتروني. ويكون عنوان URL للتحديث في سوق Chrome الإلكتروني هو "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">بطاقات الائتمان المقبولة</translation>
<translation id="4356973930735388585">قد يحاول المهاجمون الموجودون على هذا الموقع تثبيت برامج خطيرة على الكمبيوتر التابع لك تسرق معلوماتك أو تحذفها (على سبيل المثال، الصور وكلمات المرور والرسائل وبطاقات الائتمان).</translation>
+<translation id="4358461427845829800">إدارة طرق الدفع...</translation>
<translation id="4372948949327679948">القيمة <ph name="VALUE_TYPE" /> المتوقعة.</translation>
<translation id="4377125064752653719">لقد حاولت الوصول إلى <ph name="DOMAIN" />، ولكن جهة إصدار الشهادة التي قدمها الخادم قد أبطلت الشهادة. وهذا يعني أن بيانات اعتماد الأمان التي قدمها الخادم يجب عدم الوثوق بها مطلقًا. فقد تكون على اتصال بأحد المهاجمين.</translation>
<translation id="4406896451731180161">نتائج البحث</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">عنوان الاستلام</translation>
<translation id="4424024547088906515">‏هذا الخادم لم يتمكن من إثبات أن ذلك <ph name="DOMAIN" />؛ بل إنه شهادة أمان غير موثوقة من قبل Chrome. وربما يكون السبب في ذلك خطأ في التكوين أو مهاجمًا يعترض الاتصال.</translation>
<translation id="4432688616882109544">لم يقبل <ph name="HOST_NAME" /> شهادة تسجيل الدخول أو من المحتمل ألا يكون قد تم تقديم واحدة.</translation>
+<translation id="4434045419905280838">النوافذ المنبثقة وإعادة التوجيه</translation>
<translation id="443673843213245140">تم إيقاف استخدام الخادم الوكيل ولكن تم تحديد تهيئة صريحة للخادم الوكيل.</translation>
<translation id="445100540951337728">بطاقات السحب الآلي المقبولة</translation>
<translation id="4506176782989081258">خطأ في عملية التحقق: <ph name="VALIDATION_ERROR" />.</translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">تم إيقاف الملء التلقائي لعملية الدفع</translation>
<translation id="4764776831041365478">قد تكون صفحة الويب على العنوان <ph name="URL" /> غير متاحة مؤقتًا أو قد يكون تم نقلها نهائيًا إلى عنوان ويب جديد.</translation>
<translation id="4771973620359291008">حدث خطأ غير محدّد.</translation>
+<translation id="4785689107224900852">التبديل إلى علامة التبويب هذه</translation>
<translation id="4792143361752574037">حدثت مشكلة أثناء الوصول إلى ملفات الجلسة. ويتم حاليًا إيقاف الحفظ إلى القرص. يُرجى إعادة تحميل الصفحة للمحاولة مرة أخرى.</translation>
<translation id="4800132727771399293">‏تحقق من تاريخ انتهاء الصلاحية ورمز التحقق من البطاقة (CVC) وأعد المحاولة مرة أخرى.</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">‏لا يمكنك زيارة <ph name="SITE" /> الآن نظرًا لأن موقع الويب أرسل بيانات اعتماد مختلطة يتعذر على Google Chrome معالجتها. وعادةً ما تكون أخطاء الشبكة والهجمات عليها مؤقتة؛ لذا ستعمل هذه الصفحة لاحقًا على الأرجح.</translation>
<translation id="4813512666221746211">حدث خطأ في الشبكة</translation>
<translation id="4816492930507672669">احتواء ضمن الصفحة</translation>
-<translation id="483020001682031208">لا توجد صفحات شبكة مادية متاحة للعرض</translation>
<translation id="4850886885716139402">عرض</translation>
<translation id="4854362297993841467">طريقة التسليم هذه غير متاحة. جرِّب طريقة أخرى.</translation>
<translation id="4858792381671956233">لقد سألت والديك ما إذا كانت زيارة هذا الموقع مناسبةً لك</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 بت)</translation>
<translation id="5121084798328133320">‏بعد التأكيد، ستتم مشاركة تفاصيل البطاقة من حساب دفعات Google مع هذا الموقع.</translation>
<translation id="5128122789703661928">الجلسة التي تحمل هذا الاسم غير صالحة للحذف.</translation>
+<translation id="5135404736266831032">إدارة العناوين...</translation>
<translation id="5141240743006678641">‏تشفير كلمات المرور المتزامنة باستخدام بيانات اعتماد Google</translation>
<translation id="5145883236150621069">يوجد رمز خطأ في استجابة السياسة</translation>
<translation id="5159010409087891077">‏يمكنك فتح الصفحة في نافذة جديدة للتصفح المتخفي (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">تعرض صفحة مضمّنة في هذه الصفحة</translation>
<translation id="5205222826937269299">الاسم مطلوب</translation>
<translation id="5222812217790122047">البريد الإلكتروني مطلوب</translation>
-<translation id="522700295135997067">من المحتمل أن يكون موقع الويب هذا قد سرق كلمة مرورك للتو</translation>
<translation id="5230733896359313003">عنوان الشحن</translation>
<translation id="5250209940322997802">"الاتصال بالشبكة"</translation>
<translation id="5251803541071282808">السحاب</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">‏يكون لموقع الويب هذا على الشبكة الداخلية للشركة أو المؤسسة أو المدرسة نفس عنوان URL لأحد مواقع الويب الخارجية.
<ph name="LINE_BREAK" />
حاول الاتصال بمشرف النظام.</translation>
-<translation id="5499929369096410817">أدخل رمز الأمان لبطاقة <ph name="CREDIT_CARD" />. لن يتم حفظ هذا الرمز.</translation>
<translation id="5509780412636533143">الإشارات المرجعية المُدارة</translation>
<translation id="5510766032865166053">ربما يكون تم نقله أو حذفه.</translation>
<translation id="5523118979700054094">اسم السياسة</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">إضافة عنوان الشحن</translation>
<translation id="5689199277474810259">‏تصدير إلى JSON</translation>
<translation id="5689516760719285838">الموقع</translation>
+<translation id="570530837424789914">إدارة...</translation>
<translation id="5710435578057952990">لم يتمّ التحقق من هوية هذا الموقع.</translation>
<translation id="5719499550583120431">يتم قبول بطاقات الدفع المسبق.</translation>
<translation id="5720705177508910913">المستخدم الحالي</translation>
+<translation id="5730040223043577876">‏يُوصي Chrome بإعادة تحديد كلمة المرور في حال إعادة استخدامها في مواقع ويب أخرى.</translation>
<translation id="5732392974455271431">يمكن لوالديك إلغاء الحظر لك</translation>
<translation id="5763042198335101085">أدخِل عنوان بريد إلكتروني صحيحًا</translation>
<translation id="5765072501007116331">لعرض طرق التسليم ومتطلباته، حدِّد عنوانًا</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">‏يمكنك إرسال بعض <ph name="BEGIN_WHITEPAPER_LINK" />معلومات النظام ومحتوى الصفحة<ph name="END_WHITEPAPER_LINK" /> إلى Google تلقائيًا للمساعدة في اكتشاف التطبيقات والمواقع الضارة. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">تعديل معلومات الاتصال</translation>
<translation id="5967867314010545767">إزالة من السجل</translation>
-<translation id="5972020793760134803">التبديل إلى علامة التبويب أخرى</translation>
<translation id="5975083100439434680">تصغير</translation>
-<translation id="597552863672748783">تأكيد رمز الأمان</translation>
<translation id="598637245381783098">لا يمكن فتح تطبيق الدفع</translation>
<translation id="5989320800837274978">‏لم يتم تحديد أي من الخوادم الوكيلة الثابتة ولا عنوان URL للنص البرمجي pac.</translation>
<translation id="5990559369517809815">تم حظر الطلبات المقدمة إلى الخادم بواسطة إحدى الإضافات.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">قد يحاول هذا المحتوى خداعك لتثبيت برامج أو الكشف عن معلومات شخصية. <ph name="BEGIN_LINK" />عرض على أي حال<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">لا يمكنك زيارة <ph name="SITE" /> في الوقت الحالي لأن الموقع يستخدم أداة التحقق من صحة الشهادات. أخطاء الشبكة والهجمات عليها عادةً ما تكون مؤقتة، لذا ستعمل هذه الصفحة في وقت لاحق على الأرجح.</translation>
<translation id="6059925163896151826">‏أجهزة USB</translation>
+<translation id="6071091556643036997">نوع السياسة غير صالح.</translation>
<translation id="6080696365213338172">لقد دخلت إلى المحتوى باستخدام شهادة وفرها المشرف. ويمكن أن يعترض المشرف طريق البيانات التي تقدمها إلى <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">‏قد يتضمن حسابك على Google نماذج أخرى من سجل التصفح على <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{بدون}=1{ كلمة مرور واحدة (تمت مزامنتها)}two{كلمتا مرور (#) (تمت مزامنتهما)}few{# كلمات مرور (تمت مزامنتها)}many{# كلمة مرور (تمت مزامنتها)}other{# كلمة مرور (تمت مزامنتها)}}</translation>
@@ -755,7 +757,7 @@
<translation id="6355080345576803305">إلغاء الجلسة العامة</translation>
<translation id="6358450015545214790">ماذا تعني هذه الأقسام؟</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{اقتراح واحد آخر}zero{# اقتراح آخر}two{اقتراحان آخران (#)}few{# اقتراحات أخرى}many{# اقتراحًا آخر}other{# اقتراح آخر}}</translation>
-<translation id="6387754724289022810">‏للدفع بشكلٍ أسرع في المرة القادمة، يجب حفظ البطاقة وعنوان إرسال الفواتير في حسابك على Google وهذا الجهاز.</translation>
+<translation id="6387754724289022810">‏للدفع بشكلٍ أسرع في المرة القادمة، يجب حفظ تفاصيل البطاقة المصرفية وعنوان إرسال الفواتير في حسابك على Google وعلى هذا الجهاز.</translation>
<translation id="6397451950548600259">‏تعمل البرامج على جهاز الكمبيوتر على منع اتصال Chrome بأمان بالويب</translation>
<translation id="6404511346730675251">تعديل إشارة مرجعية</translation>
<translation id="6410264514553301377">‏أدخِل تاريخ انتهاء الصلاحية ورمز التحقق من البطاقة (CVC) لـ <ph name="CREDIT_CARD" /></translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">إضافة مزيد من المعلومات</translation>
<translation id="6447842834002726250">ملفّات تعريف الارتباط</translation>
<translation id="6451458296329894277">تأكيد إعادة إرسال النموذج</translation>
+<translation id="6465306955648956876">إدارة كلمات المرور...</translation>
<translation id="647261751007945333">سياسات الأجهزة</translation>
<translation id="6477321094435799029">‏اكتشف Chrome وجود رمز غير عادي على هذه الصفحة وأجرى حظرًا لهذا الرمز لحماية معلوماتك الشخصية (على سبيل المثال، كلمات المرور، وأرقام الهواتف، وبطاقات الائتمان).</translation>
<translation id="6489534406876378309">بدء تحميل الأعطال</translation>
@@ -779,12 +782,13 @@
<translation id="6563469144985748109">لم يوافق عليه مديرك حتى الآن</translation>
<translation id="6569060085658103619">أنت تعرض صفحة إضافة</translation>
<translation id="6596325263575161958">خيارات التشفير</translation>
-<translation id="6604181099783169992">حساسات الإضاءة والحركة</translation>
+<translation id="6604181099783169992">أجهزة استشعار الإضاءة والحركة</translation>
<translation id="6624427990725312378">معلومات الاتصال</translation>
<translation id="6626291197371920147">إضافة رقم بطاقة صالح</translation>
<translation id="6628463337424475685">بحث <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">‏قد يحاول المهاجمون حاليًا على <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> تثبيت برامج خطيرة على جهاز Mac تؤدي إلى سرقة أو حذف معلوماتك (على سبيل المثال، الصور، وكلمات المرور، والرسائل، وبطاقات الائتمان) <ph name="BEGIN_LEARN_MORE_LINK" />مزيد من المعلومات<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">تم تجاهل هذه السياسة.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{بدون}=1{‏من موقع ويب واحد (لن يتم تسجيل خروجك من حسابك على Google)}two{‏من موقعي ويب (#) (لن يتم تسجيل خروجك من حسابك على Google)}few{‏من # مواقع ويب (لن يتم تسجيل خروجك من حسابك على Google)}many{‏من # موقع ويب (لن يتم تسجيل خروجك من حسابك على Google)}other{‏من # موقع ويب (لن يتم تسجيل خروجك من حسابك على Google)}}</translation>
<translation id="6657585470893396449">كلمة المرور</translation>
<translation id="6671697161687535275">‏هل تريد إزالة اقتراح النموذج من Chromium؟</translation>
<translation id="6685834062052613830">الخروج وإكمال الإعداد</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">المستخدم:</translation>
<translation id="6945221475159498467">تحديد</translation>
<translation id="6948701128805548767">لعرض طرق الاستلام ومتطلباته، حدِّد عنوانًا</translation>
+<translation id="6949872517221025916">إعادة تحديد كلمة المرور</translation>
<translation id="6957887021205513506">يبدو أن شهادة الخادم مزيفة.</translation>
<translation id="6965382102122355670">موافق</translation>
<translation id="6965978654500191972">جهاز</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">طريقة التسليم</translation>
<translation id="7139724024395191329">الإمارة</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> وطريقة دفع <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> أخرى}two{<ph name="PAYMENT_METHOD_PREVIEW" /> وطريقتا دفع <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> أخريان}few{<ph name="PAYMENT_METHOD_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> طرق دفع أخرى}many{<ph name="PAYMENT_METHOD_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> طريقة دفع أخرى}other{<ph name="PAYMENT_METHOD_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> طريقة دفع أخرى}}</translation>
-<translation id="7155487117670177674">عملية الدفع غير آمنة</translation>
+<translation id="717330890047184534">‏معرّف GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> وخيار <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> آخر}two{<ph name="SHIPPING_OPTION_PREVIEW" /> وخياران (<ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />) آخران}few{<ph name="SHIPPING_OPTION_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> خيارات أخرى}many{<ph name="SHIPPING_OPTION_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> خيارًا آخر}other{<ph name="SHIPPING_OPTION_PREVIEW" /> و<ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> خيار آخر}}</translation>
<translation id="7180611975245234373">تحديث</translation>
<translation id="7182878459783632708">لم يتم تعيين أي سياسات</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">استخدام الإعداد التلقائي العمومي (حظر)</translation>
<translation id="7460163899615895653">تظهر علامات التبويب الأخيرة من الأجهزة الأخرى هنا</translation>
<translation id="7469372306589899959">جارٍ التاكد من البطاقة</translation>
+<translation id="7473891865547856676">لا، شكرًا</translation>
<translation id="7481312909269577407">إلى الأمام</translation>
<translation id="7485870689360869515">لم يتم العثور على بيانات.</translation>
<translation id="7508255263130623398">رقم تعريف الجهاز المعروض للسياسة فارغ أو لا يتطابق مع رقم تعريف الجهاز الحالي</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">‏هل تريد إزالة بطاقة الائتمان من Chrome؟</translation>
<translation id="7575800019233204241">‏"لا يتمتع اتصالك بالخصوصية" أو "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" أو "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" أو "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" أو "خطأ في شهادة طبقة المقابس الآمنة (SSL)"</translation>
<translation id="7578104083680115302">‏الدفع سريعًا على المواقع والتطبيقات على جميع الأجهزة باستخدام البطاقات التي حفظتها في Google.</translation>
-<translation id="7588950540487816470">الشبكة المادية</translation>
<translation id="7592362899630581445">تنتهك شهادة الخادم القيود المفروضة على الاسم.</translation>
<translation id="7598391785903975535">أقل من <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">يتعذر على <ph name="HOST_NAME" /> معالجة هذا الطلب حاليًا.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">تراجع عن ا&amp;لتحرير</translation>
<translation id="9154194610265714752">تم التحديث</translation>
<translation id="9157595877708044936">جارٍ الإعداد...</translation>
+<translation id="9168814207360376865">السماح للمواقع بالتحقُّق ممّا إذا كانت لديك طرق دفع محفوظة أم لا</translation>
<translation id="9169664750068251925">الحظر دومًا على هذا الموقع</translation>
<translation id="9170848237812810038">&amp;إلغاء</translation>
<translation id="917450738466192189">شهادة الخادم غير صالحة.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">تعذّرت إضافة مقالة.</translation>
<translation id="9215416866750762878">‏يعمل أحد التطبيقات على منع اتصال Chrome بموقع الويب هذا على نحو آمن</translation>
<translation id="9219103736887031265">صور</translation>
-<translation id="933612690413056017">لا يوجد اتصال بالإنترنت</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">محو النموذج</translation>
<translation id="939736085109172342">مجلد جديد</translation>
diff --git a/chromium/components/strings/components_strings_bg.xtb b/chromium/components/strings/components_strings_bg.xtb
index c5161595841..d4a2bff21d5 100644
--- a/chromium/components/strings/components_strings_bg.xtb
+++ b/chromium/components/strings/components_strings_bg.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Избиране на разрешението за <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Скорошни отметки</translation>
<translation id="1113869188872983271">&amp;Отмяна на пренареждането</translation>
+<translation id="1125573121925420732">Възможно е да виждате предупреждения често, докато уебсайтовете актуализират мерките си за сигурност. Това би трябвало скоро да се подобри.</translation>
<translation id="1126551341858583091">Размерът на локалното хранилище е <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Кешът на правилото е в добро състояние</translation>
<translation id="1150979032973867961">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; операционната система на компютъра ви няма доверие на сертификата му за сигурност. Това може да се дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Уверете се, че връзката ви с интернет работи нормално.&lt;/li&gt;
&lt;li&gt;Свържете се със собственика на уебсайта.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Въведохте паролата си на сайт, който не се управлява от организацията ви. За да защитите профила си, не използвайте паролата си повторно в други приложения и сайтове.</translation>
<translation id="1263231323834454256">Списък за четене</translation>
<translation id="1264126396475825575">Сигнал за срив, записан в/ъв <ph name="CRASH_TIME" /> (още не е качен или пренебрегнат)</translation>
<translation id="1270502636509132238">Начин на вземане</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Избор</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1623104350909869708">Да не се създават допълнителни диалогови прозорци от тази страница</translation>
-<translation id="1629803312968146339">Искате ли Chrome да запази тази карта?</translation>
<translation id="1639239467298939599">Зарежда се</translation>
<translation id="1640180200866533862">Правила за потребителите</translation>
<translation id="1640244768702815859">Опитайте да <ph name="BEGIN_LINK" />отворите началната страница на сайта<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Опитайте да стартирате мрежова диагностика в Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Моля, актуализирайте пропуска си за синхронизиране.</translation>
<translation id="1787142507584202372">Тук ще се показват отворените ви раздели</translation>
-<translation id="1789575671122666129">Изскачащи прозорци</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Име на титуляря на картата</translation>
<translation id="1806541873155184440">Добавено: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Рестартирайте компютъра си.</translation>
<translation id="2113977810652731515">Карта</translation>
<translation id="2114841414352855701">Бе пренебрегнато, защото бе отменено от <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Търсят се намиращи се в близост страници във Физическата мрежа</translation>
<translation id="213826338245044447">Мобилни отметки</translation>
<translation id="214556005048008348">Анулиране на плащането</translation>
<translation id="2147827593068025794">Синхронизиране на заден план</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Правилото не е намерено</translation>
<translation id="2213606439339815911">Записите се извличат...</translation>
<translation id="2218879909401188352">Понастоящем извършители на атака срещу <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могат да инсталират опасни приложения, които да повредят устройството ви, да добавят скрити такси към сметката ви за мобилни услуги или да откраднат личната ви информация. <ph name="BEGIN_LEARN_MORE_LINK" />Научете повече<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Няма достъп до интернет</translation>
<translation id="2230458221926704099">Поправете връзката си посредством <ph name="BEGIN_LINK" />приложението за диагностика<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Изпращане сега</translation>
<translation id="225207911366869382">Стойността е оттеглена за това правило.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Премахване на избраните елементи</translation>
<translation id="277133753123645258">Начин на доставка</translation>
<translation id="277499241957683684">Липсващ запис за устройството</translation>
+<translation id="2781030394888168909">Експортиране за Mac OS</translation>
<translation id="2784949926578158345">Връзката бе възстановена.</translation>
<translation id="2788784517760473862">Приемани кредитни карти</translation>
<translation id="2794233252405721443">Сайтът е блокиран</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome не можа да потвърди картата ви. Моля, опитайте отново по-късно.</translation>
<translation id="3064966200440839136">Ще напуснете режим „инкогнито“, за да платите във външно приложение. Искате ли да продължите?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Няма}=1{1 парола}other{# пароли}}</translation>
-<translation id="3093245981617870298">Понастоящем сте офлайн.</translation>
<translation id="3096100844101284527">Добавяне на адрес за вземане</translation>
<translation id="3105172416063519923">ID на актива:</translation>
<translation id="3109728660330352905">Нямате пълномощия за преглед на тази страница.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Понастоящем няма достъп до <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Разрешаване (по подразбиране)</translation>
<translation id="3427342743765426898">&amp;Възстановяване на редактирането</translation>
+<translation id="342781501876943858">Chromium препоръчва да зададете повторно паролата си, ако сте я използвали и на други сайтове.</translation>
<translation id="3431636764301398940">Запазване на картата на това устройство</translation>
<translation id="3447661539832366887">Собственикът на това устройство е изключил играта с динозавъра.</translation>
<translation id="3447884698081792621">Показване на сертификата (издаден от <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Отворете страницата в нов прозорец в режим „инкогнито“ (Ctrl-Shift-N).</translation>
<translation id="3679803492151881375">Сигналът за срив е записан в/ъв <ph name="CRASH_TIME" /> и качен в/ъв <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Информация за сертификата</translation>
-<translation id="3690164694835360974">Страницата за вход не е защитена</translation>
<translation id="3704162925118123524">Използваната от вас мрежа може да изисква да посетите страницата й за вход.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> „<ph name="TITLE" />“ <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Зарежда се...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Използване на глобалната стандартна стойност (Откриване)</translation>
<translation id="4165986682804962316">Настройки за сайта</translation>
-<translation id="4169947484918424451">Искате ли Chromium да запази тази карта?</translation>
<translation id="4171400957073367226">Невалиден подпис за потвърждаване</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{още <ph name="ITEM_COUNT" /> елемент}other{още <ph name="ITEM_COUNT" /> елемента}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> – <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Рестартиране на устройството ви</translation>
<translation id="4277028893293644418">Повторно задаване на паролата</translation>
<translation id="4280429058323657511">, изтича: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Превключване</translation>
<translation id="4312866146174492540">Блокиране (по подразбиране)</translation>
<translation id="4325863107915753736">Намирането на статията не бе успешно</translation>
<translation id="4326324639298822553">Проверете датата на валидност и опитайте отново</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Този компютър не се управлява корпоративно, така че правилото може да инсталира автоматично само разширения от уеб магазина на Chrome. URL адресът за актуализация за уеб магазина на Chrome е <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Приемани кредитни карти</translation>
<translation id="4356973930735388585">Извършители на атака, използващи този сайт, може да опитат да инсталират опасни програми на компютъра ви, които крадат или изтриват информацията ви (например снимки, пароли, съобщения и номера на кредитни карти).</translation>
+<translation id="4358461427845829800">Управление на начините на плащане...</translation>
<translation id="4372948949327679948">Очаквана е стойност от тип <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Направихте опит да се свържете с/ъс <ph name="DOMAIN" />, но сървърът предoстави сертификат, анулиран от издателя си. Това означава, че в никакъв случай не трябва да се доверявате на представените от сървъра идентификационни данни за сигурност. Възможно е да сте се свързали с извършител на атака.</translation>
<translation id="4406896451731180161">резултата от търсенето</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Адрес за вземане</translation>
<translation id="4424024547088906515">Сървърът не можа да докаже, че е <ph name="DOMAIN" />; Chrome няма доверие на сертификата му за сигурност. Това може да се дължи на неправилно конфигуриране или на прихващане на връзката ви от атакуващ.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> не прие сертификата ви за вход или е възможно да не е предоставен такъв.</translation>
+<translation id="4434045419905280838">Изскач. прозорци и пренасочвания</translation>
<translation id="443673843213245140">Използването на прокси сървър е деактивирано, но е посочена изрична негова конфигурация.</translation>
<translation id="445100540951337728">Приемани дебитни карти</translation>
<translation id="4506176782989081258">Грешка при потвърждаването: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Автоматичното попълване на данните за плащане е деактивирано</translation>
<translation id="4764776831041365478">До уеб страницата на адрес <ph name="URL" /> може временно да няма достъп или да е преместена за постоянно на нов уеб адрес.</translation>
<translation id="4771973620359291008">Възникна неизвестна грешка.</translation>
+<translation id="4785689107224900852">Превключване към този раздел</translation>
<translation id="4792143361752574037">Възникна проблем при осъществяването на достъп до файловете от сесията. Понастоящем запазването на диска е деактивирано. Моля, презаредете страницата, за да опитате отново.</translation>
<translation id="4800132727771399293">Прегледайте датата на валидност и кода за проверка и оптитайте отново</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">В момента не можете да посетите <ph name="SITE" />, защото уебсайтът изпрати кодирани идентификационни данни, които Google Chrome не може да обработи. Обикновено грешките в мрежата и атаките срещу нея са временни, така че тази страница вероятно ще работи по-късно.</translation>
<translation id="4813512666221746211">Грешка в мрежата</translation>
<translation id="4816492930507672669">Да се побере в страницата</translation>
-<translation id="483020001682031208">Няма страници във Физическата мрежа, които да ви покажем</translation>
<translation id="4850886885716139402">Изглед</translation>
<translation id="4854362297993841467">Този начин на бърза доставка не се поддържа. Опитайте с друг.</translation>
<translation id="4858792381671956233">Попитахте родителите си дали може да посетите този сайт</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 бита)</translation>
<translation id="5121084798328133320">След като потвърдите картата си, данните за нея от профила ви в Google Payments ще бъдат споделени с този сайт.</translation>
<translation id="5128122789703661928">Сесията с това име не е валидна за изтриване.</translation>
+<translation id="5135404736266831032">Управление на адресите...</translation>
<translation id="5141240743006678641">Синхронизираните пароли да се шифроват с идентификационните ви данни за Google</translation>
<translation id="5145883236150621069">В отговора за правилото присъства код на грешка</translation>
<translation id="5159010409087891077">Отворете страницата в нов прозорец в режим „инкогнито“ (⇧⌘N).</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Страница, вградена в тази страница, изпраща съобщение</translation>
<translation id="5205222826937269299">Името е задължително</translation>
<translation id="5222812217790122047">Имейл адресът е задължителен</translation>
-<translation id="522700295135997067">Възможно е този сайт току-що да е откраднал паролата ви</translation>
<translation id="5230733896359313003">Адрес за доставка</translation>
<translation id="5250209940322997802">„Свързване с мрежа“</translation>
<translation id="5251803541071282808">Облак</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Този интранет сайт на фирмата, организацията или училището има същия URL адрес като на външен уебсайт.
<ph name="LINE_BREAK" />
Опитайте да се свържете със системния си администратор.</translation>
-<translation id="5499929369096410817">Въведете кода за сигурност за <ph name="CREDIT_CARD" />. Той няма да бъде запазен.</translation>
<translation id="5509780412636533143">Управлявани отметки</translation>
<translation id="5510766032865166053">Възможно е да е преместен или изтрит.</translation>
<translation id="5523118979700054094">Име на правилото</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Добавяне на адрес за доставка</translation>
<translation id="5689199277474810259">Експортиране във формат JSON</translation>
<translation id="5689516760719285838">Местоположение</translation>
+<translation id="570530837424789914">Управление...</translation>
<translation id="5710435578057952990">Самоличността на този уебсайт не е потвърдена.</translation>
<translation id="5719499550583120431">Приемат се предплатени карти.</translation>
<translation id="5720705177508910913">Текущият потребител</translation>
+<translation id="5730040223043577876">Chrome препоръчва да зададете повторно паролата си, ако сте я използвали и на други сайтове.</translation>
<translation id="5732392974455271431">Родителите ви могат да го отблокират за вас</translation>
<translation id="5763042198335101085">Въведете валиден имейл адрес</translation>
<translation id="5765072501007116331">За да видите начините на бърза доставка и изискванията, изберете адрес</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Автоматично изпращане до Google на <ph name="BEGIN_WHITEPAPER_LINK" />системна информация и част от съдържанието на страниците<ph name="END_WHITEPAPER_LINK" /> с цел по-лесно откриване на опасни приложения и сайтове. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Редактиране на информацията за връзка</translation>
<translation id="5967867314010545767">Премахване от историята</translation>
-<translation id="5972020793760134803">Превключване към раздел</translation>
<translation id="5975083100439434680">Намаляване на мащаба</translation>
-<translation id="597552863672748783">Потвърдете кода за сигурност</translation>
<translation id="598637245381783098">Приложението за плащане не може да се отвори</translation>
<translation id="5989320800837274978">Не са посочени нито фиксирани прокси сървъри, нито URL адрес на скрипт във формат .pac.</translation>
<translation id="5990559369517809815">Заявките към сървъра са блокирани от разширение.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Въпросното съдържание може да се опита да ви подведе да инсталирате софтуер или да разкриете лична информация. <ph name="BEGIN_LINK" />Показване въпреки това<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">В момента не можете да посетите <ph name="SITE" />, защото уебсайтът използва метод за допълнително потвърждаване на сертификатите. Обикновено грешките в мрежата и атаките срещу нея са временни, така че тази страница вероятно ще работи по-късно.</translation>
<translation id="6059925163896151826">USB устройства</translation>
+<translation id="6071091556643036997">Типът на правилата е невалиден.</translation>
<translation id="6080696365213338172">Осъществихте достъп до съдържанието посредством осигурен от администратора сертификат. Данните, които предоставите на <ph name="DOMAIN" />, могат да бъдат прихванати от администратора ви.</translation>
<translation id="610911394827799129">В профила ви в Google може да има други видове история на сърфиране, съхранявани на адрес <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Няма}=1{1 парола (синхронизирана)}other{# пароли (синхронизирани)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Добавяне на още информация</translation>
<translation id="6447842834002726250">„Бисквитки“</translation>
<translation id="6451458296329894277">Потвърдете повторното изпращане на формуляра</translation>
+<translation id="6465306955648956876">Управление на паролите...</translation>
<translation id="647261751007945333">Правила за устройството</translation>
<translation id="6477321094435799029">Chrome откри необичаен код на тази страница и я блокира, за да защити личната ви информация (например пароли, телефонни номера и номера на кредитни карти).</translation>
<translation id="6489534406876378309">Стартиране на качването на сривове</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Търсене с/ъс <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Извършители на атака, понастоящем използващи <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, може да опитат да инсталират опасни програми на компютъра ви Mac, които крадат или изтриват информацията ви (например снимки, пароли, съобщения и номера на кредитни карти). <ph name="BEGIN_LEARN_MORE_LINK" />Научете повече<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Това правило е оттеглено.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Няма}=1{От 1 сайт (няма да излезете от профила си в Google)}other{От # сайта (няма да излезете от профила си в Google)}}</translation>
<translation id="6657585470893396449">Парола</translation>
<translation id="6671697161687535275">Предложението за формуляри да се премахне ли от Chromium?</translation>
<translation id="6685834062052613830">Излизане от профила и завършване на настройването</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Потребител:</translation>
<translation id="6945221475159498467">Изберете</translation>
<translation id="6948701128805548767">За да видите начините на вземане и изискванията, изберете адрес</translation>
+<translation id="6949872517221025916">Задаване на нова парола</translation>
<translation id="6957887021205513506">Изглежда, че сертификатът на сървъра е подправен.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Устройство</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Начин на бърза доставка</translation>
<translation id="7139724024395191329">Емирство</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Страницата за плащане не е защитена</translation>
+<translation id="717330890047184534">Идентификатор в GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> и още <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Опресняване</translation>
<translation id="7182878459783632708">Няма зададени правила</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Използване на глобалната стандартна стойност (блокиране)</translation>
<translation id="7460163899615895653">Тук се показват скорошните раздели от други устройства</translation>
<translation id="7469372306589899959">Картата се потвърждава</translation>
+<translation id="7473891865547856676">Не, благодаря</translation>
<translation id="7481312909269577407">Препращане</translation>
<translation id="7485870689360869515">Няма намерени данни.</translation>
<translation id="7508255263130623398">Върнатият от правилата идентификационен номер на устройството е празен или не съответства на текущия</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Кредитната карта да се премахне ли от Chrome?</translation>
<translation id="7575800019233204241">„Връзката ви не е частна“, „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;“, „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;“, „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;“ или „Грешка при SSL сертификатите“</translation>
<translation id="7578104083680115302">Извършвайте бързи плащания в сайтове и приложения от всякакви устройства посредством картите, които сте запазили в Google.</translation>
-<translation id="7588950540487816470">Физическа мрежа</translation>
<translation id="7592362899630581445">Сертификатът на сървъра нарушава ограниченията за име.</translation>
<translation id="7598391785903975535">По-малко от <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Понастоящем <ph name="HOST_NAME" /> не може да обработи тази заявка.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Отмяна на редактирането</translation>
<translation id="9154194610265714752">Актуализирано</translation>
<translation id="9157595877708044936">Настройва се...</translation>
+<translation id="9168814207360376865">Разрешаване на сайтовете да проверяват дали имате запазени начини на плащане</translation>
<translation id="9169664750068251925">Блокиране винаги на този сайт</translation>
<translation id="9170848237812810038">&amp;Отмяна</translation>
<translation id="917450738466192189">Сертификатът на сървъра е невалиден.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Добавянето на статията не бе успешно.</translation>
<translation id="9215416866750762878">Приложение пречи на Chrome да се свърже безопасно с този сайт</translation>
<translation id="9219103736887031265">Изображения</translation>
-<translation id="933612690413056017">Няма връзка с интернет</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ИЗЧИСТВАНЕ НА ФОРМУЛЯРА</translation>
<translation id="939736085109172342">Нова папка</translation>
diff --git a/chromium/components/strings/components_strings_bn.xtb b/chromium/components/strings/components_strings_bn.xtb
index 76fa33ab90a..91b140b21cb 100644
--- a/chromium/components/strings/components_strings_bn.xtb
+++ b/chromium/components/strings/components_strings_bn.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> এর জন্য অনুমতি বেছে নিন</translation>
<translation id="1111153019813902504">সাম্প্রতিক ঘুরে দেখা বুকমার্কগুলি</translation>
<translation id="1113869188872983271">&amp;পুনর্বিন্যাসকে পূর্বাবস্থায় ফেরান</translation>
+<translation id="1125573121925420732">ওয়েবসাইটগুলির নিরাপত্তা আপডেট করার সময় সতর্কতা দেখানো খুবই স্বভাবিক। এটি শীঘ্রই উন্নত করা উচিত।</translation>
<translation id="1126551341858583091">স্থানীয় সঞ্চয়স্থানের আকার হলো <ph name="CRASH_SIZE" />।</translation>
<translation id="112840717907525620">নীতি ক্যাশেটি ঠিক আছে</translation>
<translation id="1150979032973867961">এই সার্ভার প্রমাণ করতে পারেনি যে এটি <ph name="DOMAIN" />; এর নিরাপত্তা শংসাপত্রটি আপনার কম্পিউটারের নিকট বিশ্বাসযোগ্য নয়। কোনো ভুল কনফিগারেশনের কারণে অথবা কোনো আক্রমণকারী আপনার সংযোগ মাঝপথে আটকে দিচ্ছে বলে এমনটা হতে পারে।</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;ইন্টারনেট কানেকশন ঠিক আছে কিনা দেখুন।&lt;/li&gt;
&lt;li&gt;ওয়েবসাইটের মালিকের সাথে যোগাযোগ করুন।&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">আপনার প্রতিষ্ঠানের নয় এমন একটি সাইটে আপনার পাসওয়ার্ড লিখেছেন। আপনার অ্যাকাউন্টের সুরক্ষার জন্য অন্যান্য অ্যাপ এবং সাইটগুলিতে আপনার এই পাসওয়ার্ডটি ব্যবহার করবেন না।</translation>
<translation id="1263231323834454256">পড়ার তালিকা</translation>
<translation id="1264126396475825575">ক্র্যাশ প্রতিবেদন <ph name="CRASH_TIME" /> এ ক্যাপচার করা হয়েছে (এখনো আপলোড করা বা উপেক্ষা করা হয়নি)</translation>
<translation id="1270502636509132238">পিক-আপের পদ্ধতি</translation>
@@ -59,7 +61,7 @@
<translation id="129863573139666797"><ph name="BEGIN_LINK" />আপনার কুকিজ সাফ করে দেখুন<ph name="END_LINK" /></translation>
<translation id="1314614906530272393">বেছে নেওয়া সেশনটির অস্তিত্ব নেই।</translation>
<translation id="1323433172918577554">আরও দেখুন</translation>
-<translation id="1333989956347591814">এগুলিতে আপনার কার্যকলাপ <ph name="BEGIN_EMPHASIS" />এখনও দেখা যেতে পারে<ph name="END_EMPHASIS" />:
+<translation id="1333989956347591814">এগুলিতে আপনার অ্যাক্টিভিটি <ph name="BEGIN_EMPHASIS" />এখনও দেখা যেতে পারে<ph name="END_EMPHASIS" />:
<ph name="BEGIN_LIST" />
<ph name="LIST_ITEM" />যে ওয়েবসাইট আপনি দেখেছেন
<ph name="LIST_ITEM" />আপনার নিয়োগকর্তা অথবা স্কুল
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">বেছে নিন</translation>
<translation id="1620510694547887537">ক্যামেরা</translation>
<translation id="1623104350909869708">এই পৃষ্ঠাটিকে অতিরিক্ত কথোপকথন তৈরি করা থেকে বাধা দিন</translation>
-<translation id="1629803312968146339">আপনি কি চান যে Chrome এই কার্ড সংরক্ষণ করুক?</translation>
<translation id="1639239467298939599">লোড হচ্ছে</translation>
<translation id="1640180200866533862">ব্যবহারকারীর নীতিসমূহ</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />এই সাইটের হোমপেজটি ঘুরে দেখুন<ph name="END_LINK" />।</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows নেটওয়ার্ক ডায়গনিস্টিক্স চালিয়ে দেখুন<ph name="END_LINK" />।</translation>
<translation id="1783075131180517613">দয়া করে আপনার সিঙ্ক পাসফ্রেজ আপডেট করুন৷</translation>
<translation id="1787142507584202372">আপনার খোলা ট্যাবগুলি এখানে দেখা যাবে</translation>
-<translation id="1789575671122666129">পপআপ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">কার্ড হোল্ডারের নাম</translation>
<translation id="1806541873155184440">যোগ করা হয়েছে <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -172,7 +172,6 @@
<translation id="2108755909498034140">আপনার কম্পিউটার পুনরায় চালু করুন</translation>
<translation id="2113977810652731515">কার্ড</translation>
<translation id="2114841414352855701">এড়িয়ে যাওয়া হয়েছে কারণ এটি <ph name="POLICY_NAME" />-দ্বারা ওভাররাইড করা হয়েছিল৷</translation>
-<translation id="2138201775715568214">আশেপাশের বাস্তবিক ওয়েব পৃষ্ঠাগুলি খুঁজছে</translation>
<translation id="213826338245044447">মোবাইল বুকমার্ক</translation>
<translation id="214556005048008348">পেমেন্ট বাতিল করুন</translation>
<translation id="2147827593068025794">পটভূমি সিঙ্ক</translation>
@@ -189,6 +188,7 @@
<translation id="2212735316055980242">নীতি পাওয়া যায়নি</translation>
<translation id="2213606439339815911">এন্ট্রিগুলি আনা হচ্ছে...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> এ যে আক্রমণকারীরা এই মুহূর্তে সক্রিয় আছে, তারা এমন বিপজ্জনক অ্যাপ ইনস্টল করে দিতে পারে যেগুলি আপনার ডিভাইসের ক্ষতি করতে, আপনার মোবাইলের বিলে লুকানো চার্জ যোগ করতে, বা আপনার ব্যক্তিগত তথ্য চুরি করতে পারে৷ <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানুন<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ইন্টারনেট কানেকশন নেই</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ডায়াগনস্টিক অ্যাপ্লিকেশান<ph name="END_LINK" /> ব্যবহার করে আপনার সংযোগ ঠিক করুন</translation>
<translation id="2239100178324503013">এখনই পাঠান</translation>
<translation id="225207911366869382">এই মান এই নীতির জন্য অসমর্থিত হয়েছে৷</translation>
@@ -217,7 +217,7 @@
<translation id="2463739503403862330">পূরণ করুন</translation>
<translation id="2465655957518002998">ডেলিভারি পদ্ধতি বেছে নিন</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />নেটওয়ার্ক ডায়গনিস্টিক্স চালান<ph name="END_LINK" /></translation>
-<translation id="2479410451996844060">অবৈধ অনুসন্ধানের URL৷</translation>
+<translation id="2479410451996844060">অবৈধ সার্চের URL৷</translation>
<translation id="2482878487686419369">বিজ্ঞপ্তিগুলি</translation>
<translation id="2491120439723279231">সার্ভারের শংসাপত্রে ত্রুটি আছে৷</translation>
<translation id="2495083838625180221">JSON বিশ্লেষক</translation>
@@ -263,12 +263,13 @@
<translation id="2742870351467570537">নির্বাচিত আইটেমগুলি সরান</translation>
<translation id="277133753123645258">শিপিংয়ের পদ্ধতি</translation>
<translation id="277499241957683684">ডিভাইস রেকর্ড অনুপস্থিত</translation>
+<translation id="2781030394888168909">MacOS এক্সপোর্ট করুন</translation>
<translation id="2784949926578158345">সংযোগ পুনঃসেট করা হয়েছে৷</translation>
<translation id="2788784517760473862">ক্রেডিট কার্ড গ্রহণ করা হয়</translation>
<translation id="2794233252405721443">সাইট অবরুদ্ধ করা হয়েছে</translation>
<translation id="2799020568854403057">যে সাইট খুলতে চলেছেন সেটিতে ক্ষতিকারক অ্যাপ আছে</translation>
<translation id="2803306138276472711">Google নিরাপদ ব্রাউজিং সাম্প্রতিক <ph name="SITE" /> এ <ph name="BEGIN_LINK" />ম্যালওয়্যার শনাক্ত করেছে<ph name="END_LINK" />। যেসব ওয়েবসাইট সাধারণত নিরাপদ থাকে, সেগুলি কখনও কখনও ম্যালওয়্যার দ্বারা আক্রান্ত হয়।</translation>
-<translation id="2824775600643448204">ঠিকানা এবং অনুসন্ধান দণ্ড</translation>
+<translation id="2824775600643448204">ঠিকানা এবং সার্চ দণ্ড</translation>
<translation id="2826760142808435982"><ph name="CIPHER" /> ব্যবহার করে এই সংযোগটি এনক্রিপ্টেড এবং প্রমাণীকৃত করা হয়েছে এবং কী এক্সচেঞ্জ প্রক্রিয়া হিসাবে <ph name="KX" /> ব্যবহার করে৷</translation>
<translation id="2835170189407361413">ফর্ম সাফ করুন</translation>
<translation id="2851634818064021665">এই সাইট দেখার জন্য আপনার অনুমতির প্রয়োজন</translation>
@@ -304,7 +305,6 @@
<translation id="3063697135517575841">Chrome এই মুহূর্তে আপনার কার্ড নিশ্চিত করতে পারছে না৷ অনুগ্রহ করে পরে আবার চেষ্টা করুন৷</translation>
<translation id="3064966200440839136">বহিরাগত অ্যাপ্লিকেশানের মাধ্যমে অর্থপ্রদান করার জন্য ছদ্মবেশী মোড থেকে বেরিয়ে যাচ্ছে। চালিয়ে যাবেন?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{কিছুই নয়}=1{১টি পাসওয়ার্ড}one{#টি পাসওয়ার্ড}other{#টি পাসওয়ার্ড}}</translation>
-<translation id="3093245981617870298">আপনি অফলাইনে আছেন৷</translation>
<translation id="3096100844101284527">পিক-আপের ঠিকানা যোগ করুন</translation>
<translation id="3105172416063519923">সম্পদ আইডি:</translation>
<translation id="3109728660330352905">আপনার এই পৃষ্ঠাটি দেখার জন্য অনুমোদন নেই।</translation>
@@ -315,7 +315,7 @@
<translation id="3154506275960390542">এই পৃষ্ঠাতে একটি ফর্ম আছে যেটি জমা দেওয়া নিরাপদ নাও হতে পারে। আপনার পাঠানো ডেটা সার্ভারে পৌঁছানোর আগে অন্যরা সেটি দেখতে পেতে পারেন, অথবা কেউ সেটি পরিবর্তন করে দিতে পারেন যাতে আপনার ডেটা সঠিকভাবে সার্ভারে না পৌঁছায়।</translation>
<translation id="3157931365184549694">পুনরুদ্ধার করুন</translation>
<translation id="3162559335345991374">আপনি যে Wi-Fiটি ব্যবহার করছেন সেটির জন্য অপনাকে এটির লগ ইন পৃষ্ঠাতে যেতে হতে পরে৷</translation>
-<translation id="3167968892399408617">ছদ্মবেশী ট্যাবগুলিতে আপনি যে পৃষ্ঠাগুলি দেখেন সেগুলি আপনার সব ছদ্মবেশী ট্যাব বন্ধ করে দেওয়ার পর ব্রাউজারের ইতিহাস, কুকি স্টোর বা অনুসন্ধান ইতিহাসে থাকবে না। আপনি ডাউনলোড করেছেন এমন ফাইল বা বুকমার্ক তৈরি করছেন এমন সবগুলি রেখে দেওয়া হবে।</translation>
+<translation id="3167968892399408617">ছদ্মবেশী ট্যাবগুলিতে আপনি যে পৃষ্ঠাগুলি দেখেন সেগুলি আপনার সব ছদ্মবেশী ট্যাব বন্ধ করে দেওয়ার পর ব্রাউজারের ইতিহাস, কুকি স্টোর বা সার্চ ইতিহাসে থাকবে না। আপনি ডাউনলোড করেছেন এমন ফাইল বা বুকমার্ক তৈরি করছেন এমন সবগুলি রেখে দেওয়া হবে।</translation>
<translation id="3169472444629675720">আবিষ্কার করুন</translation>
<translation id="3174168572213147020">দ্বীপ</translation>
<translation id="3176929007561373547">প্রক্সী সার্ভার কাজ করছে কি না, তা নিশ্চিত করতে আপনার প্রক্সী সেটিংস পরীক্ষা করুন
@@ -338,7 +338,7 @@
<translation id="3282497668470633863">কার্ডে থাকা নাম যোগ করুন</translation>
<translation id="3287510313208355388">যখন অনলাইন হবেন তখন ডাউনলোড করবেন</translation>
<translation id="3293642807462928945"><ph name="POLICY_NAME" /> নীতি সম্পর্কে আরও জানুন</translation>
-<translation id="3303855915957856445">কোনো অনুসন্ধান ফলাফল পাওয়া যায়নি</translation>
+<translation id="3303855915957856445">কোনো সার্চ ফলাফল পাওয়া যায়নি</translation>
<translation id="3305707030755673451">আপনার ডেটা আপনার সিঙ্ক পাসফ্রেজ দিয়ে <ph name="TIME" /> এ এনক্রিপ্ট করা হয়েছে। সিঙ্ক শুরু করার জন্য এটি লিখুন।</translation>
<translation id="3320021301628644560">বিলিংয়ের ঠিকানা যোগ করুন</translation>
<translation id="3338095232262050444">সুরক্ষিত</translation>
@@ -363,6 +363,7 @@
<translation id="3422472998109090673">বর্তমানে <ph name="HOST_NAME" /> পাওয়া যাচ্ছে না।</translation>
<translation id="3427092606871434483">মঞ্জুরি দিন (ডিফল্ট)</translation>
<translation id="3427342743765426898">&amp;সম্পাদনাকে আবার করুন</translation>
+<translation id="342781501876943858">Chromium-এর নীতি অনুযায়ী আপনার পাসওয়ার্ড বদলে ফেলা উচিত যদি আপনি সেটি অন্য কোনও সাইটে ব্যবহার করে থাকেন।</translation>
<translation id="3431636764301398940">এই ডিভাইসে এই কার্ডটি সেভ করুন</translation>
<translation id="3447661539832366887">এই ডিভাইসের মালিক ডাইনোসর গেমটি বন্ধ করেছেন৷</translation>
<translation id="3447884698081792621">সার্টিফিকেট দেখান (<ph name="ISSUER" /> এর দ্বারা জারি করা)</translation>
@@ -399,7 +400,6 @@
<translation id="3678529606614285348">নতুন ছদ্মবেশী উইন্ডোতে (Ctrl-Shift-N) করে একটি পৃষ্ঠা খুলুন</translation>
<translation id="3679803492151881375">ক্র্যাশ প্রতিবেদন <ph name="CRASH_TIME" /> এ ক্যাপচার করা হয়েছে, <ph name="UPLOAD_TIME" /> এ আপলোড করা হয়েছে</translation>
<translation id="3681007416295224113">শংসাপত্র তথ্য</translation>
-<translation id="3690164694835360974">লগইন সুরক্ষিত নয়</translation>
<translation id="3704162925118123524">আপনি যে নেটওয়ার্কটি ব্যবহার করছেন সেটির জন্য অপনাকে এটির লগ ইন পৃষ্ঠাতে যেতে হতে পরে৷</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">লোড হচ্ছে...</translation>
@@ -459,7 +459,6 @@
<translation id="4148925816941278100">আমেরিকান এক্সপ্রেস</translation>
<translation id="4151403195736952345">গ্লোবাল ডিফল্ট (শনাক্ত করুন) ব্যবহার করুন</translation>
<translation id="4165986682804962316">সাইটের সেটিংস</translation>
-<translation id="4169947484918424451">আপনি কি চান যে Chromium এই কার্ড সংরক্ষণ করুক?</translation>
<translation id="4171400957073367226">খারাপ যাচাইকরণের স্বাক্ষর</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{আরও <ph name="ITEM_COUNT" />টি আইটেম}one{আরও <ph name="ITEM_COUNT" />টি আইটেম}other{আরও <ph name="ITEM_COUNT" />টি আইটেম}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -496,6 +495,7 @@
<translation id="4275830172053184480">আপনার ডিভাইস বন্ধ করে চালু করুন</translation>
<translation id="4277028893293644418">পাসওয়ার্ড রিসেট করুন</translation>
<translation id="4280429058323657511">, মেয়াদ শেষ <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">পাল্টান</translation>
<translation id="4312866146174492540">অবরুদ্ধ করুন (ডিফল্ট)</translation>
<translation id="4325863107915753736">নিবন্ধ খুঁজে পেতে ব্যর্থ হয়েছে</translation>
<translation id="4326324639298822553">আপনার মেয়াদ শেষের তারিখ পরীক্ষা করে আবার চেষ্টা করুন</translation>
@@ -503,13 +503,15 @@
<translation id="4340982228985273705">এই কম্পিউটারটি এন্টারপ্রাইজ স্তরে পরিচালনা করা হচ্ছে হিসেবে শনাক্ত করা যায়নি, তাই নীতিটি শুধুমাত্র Chrome ওয়েবস্টোরে হোস্ট করা এক্সটেনশন নিজে থেকে ইনস্টল করতে পারবে। Chrome ওয়েবস্টোর আপডেটের ইউআরএল হল "<ph name="CWS_UPDATE_URL" />"।</translation>
<translation id="4346197816712207223">এই ক্রেডিট কার্ডগুলি গ্রহণ করা হয়</translation>
<translation id="4356973930735388585">এই সাইটে আক্রমণকারীরা আপনার কম্পিউটারে ক্ষতিকারক প্রোগ্রাম ইনস্টল করতে পারে যা আপনার তথ্য (উদাহরণস্বরুপ, ফটো, পাসওয়ার্ড, বার্তা এবং ক্রেডিট কার্ড) চুরি করতে বা মুছে দিতে পারে।</translation>
+<translation id="4358461427845829800">পেমেন্ট পদ্ধতিগুলি পরিচালনা করুন...</translation>
<translation id="4372948949327679948">প্রত্যাশিত <ph name="VALUE_TYPE" /> মান৷</translation>
<translation id="4377125064752653719">আপনি <ph name="DOMAIN" />-এ পৌঁছানোর প্রচেষ্টা করেছেন, তবে সার্ভারটি যে শংসাপত্রটি উপস্থাপন করেছে সেটির জারিকর্তা সেটিকে প্রত্যাহার করেছে৷ এর অর্থ হ'ল সার্ভারটি যে সুরক্ষা প্রমানপত্র উপস্থাপন করেছে তা কোনওমতেই বিশ্বাসযোগ্য নয়৷ হতে পারে আপনি একজন আক্রমণকারীর সাথে যোগাযোগ করছেন৷</translation>
-<translation id="4406896451731180161">অনুসন্ধানের ফলাফলগুলি</translation>
+<translation id="4406896451731180161">সার্চের ফলাফলগুলি</translation>
<translation id="4408413947728134509"><ph name="NUM_COOKIES" />টি কুকিজ</translation>
<translation id="4415426530740016218">পিক-আপের ঠিকানা</translation>
<translation id="4424024547088906515">এই সার্ভার প্রমাণ করতে পারেনি যে এটি <ph name="DOMAIN" />; এর নিরাপত্তা শংসাপত্র Chrome এর নিকট বিশ্বাসযোগ্য নয়। কোনো ভুল কনফিগারেশনের কারণে অথবা কোনো আক্রমণকারী আপনার সংযোগ মাঝপথে আটকে দিচ্ছে বলে এমনটা হতে পারে।</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> আপনার লগইন শংসাপত্রটি স্বীকার করেনি, অথবা কোনো শংসাপত্র দেওয়া হয়নি।</translation>
+<translation id="4434045419905280838">পপ-আপ এবং রিডাইরেক্ট</translation>
<translation id="443673843213245140">প্রক্সির ব্যবহার অক্ষম করা হয়েছে কিন্তু কোনো স্পষ্ট প্রক্সি কনফিগারেশান নির্দিষ্ট করা হয়েছে৷</translation>
<translation id="445100540951337728">ডেবিট কার্ড গ্রহণ করা হয়</translation>
<translation id="4506176782989081258">যাচাইকরণের ত্রুটি: <ph name="VALIDATION_ERROR" /></translation>
@@ -544,13 +546,13 @@
<translation id="4759118997339041434">পেমেন্ট স্বতঃপূর্ণকরণ অক্ষম করা হয়েছে</translation>
<translation id="4764776831041365478"><ph name="URL" />-এ ওয়েবপৃষ্ঠাটি হতে পারে অস্থায়ীভাবে ডাউন আছে অথবা হতে পারে এটি স্থায়ীভাবে কোনো নতুন ওয়েব ঠিকানাতে সরানো হয়েছে৷</translation>
<translation id="4771973620359291008">একটি অজানা ত্রুটি ঘটেছে৷</translation>
+<translation id="4785689107224900852">এই ট্যাবে পরিবর্তন করুন</translation>
<translation id="4792143361752574037">সেশন ফাইলগুলি অ্যাক্সেস করার ক্ষেত্রে সমস্যা ছিল। ডিস্কে সেভ করা এখন অক্ষম করা আছে। আবার চেষ্টা করার জন্য, অনুগ্রহ করে পৃষ্ঠাটিকে আবার লোড করুন।</translation>
<translation id="4800132727771399293">আপনার মেয়াদ শেষের তারিখ এবং CVC পরীক্ষা করুন এবং আবার চেষ্টা করুন</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">এই মুহূর্তে আপনি <ph name="SITE" /> এ যেতে পারবেন না কারণ ওয়েবসাইটটি অবোধ্য শংসাপত্র পাঠিয়েছে যেটি Google Chrome প্রক্রিয়া করতে পারছে না। নেটওয়ার্ক ত্রুটি এবং আক্রমণ সাধারণত সাময়িকভাবে হয়, তাই এই পৃষ্ঠা সম্ভবত পরে কাজ করবে।</translation>
<translation id="4813512666221746211">নেটওয়ার্ক ত্রুটি</translation>
<translation id="4816492930507672669">পৃষ্ঠাতে মানানসই</translation>
-<translation id="483020001682031208">দেখানোর মতো কোনো বাস্তবিক ওয়েব পৃষ্ঠা নেই</translation>
<translation id="4850886885716139402">দেখুন</translation>
<translation id="4854362297993841467">এই পদ্ধতিতে ডেলিভারি করা যাবে না। অন্য পদ্ধতি ব্যবহার করুন।</translation>
<translation id="4858792381671956233">এই সাইটটি দেখার জন্য উপযুক্ত কিনা তা আপনি আপনার পিতামাতাকে জিজ্ঞাসা করেছেন</translation>
@@ -590,6 +592,7 @@
<translation id="5115563688576182185">(৬৪-বিট)</translation>
<translation id="5121084798328133320">আপনি নিশ্চিত করার পর আপনার Google অর্থ প্রদান অ্যাকাউন্ট থেকে কার্ডের বিবরণ এই সাইটে শেয়ার করা হবে।</translation>
<translation id="5128122789703661928">এই নামের সেশনটি মুছে ফেলার জন্য সঠিক নয়।</translation>
+<translation id="5135404736266831032">ঠিকানাগুলি পরিচালনা করুন...</translation>
<translation id="5141240743006678641">আপনার Google শংসাপত্রের সাথে সিঙ্ক করা পাসওয়ার্ডগুলি এনক্রিপ্ট করুন৷</translation>
<translation id="5145883236150621069">নীতি প্রতিক্রিয়ার মধ্যে ত্রুটি কোড উপস্থিত</translation>
<translation id="5159010409087891077">নতুন ছদ্মবেশী উইন্ডোতে (⇧⌘N) করে একটি পৃষ্ঠা খুলুন</translation>
@@ -601,14 +604,13 @@
<translation id="5201306358585911203">এই পৃষ্ঠার এম্বেডেড করা একটি পৃষ্ঠায় এটি দেখানো হচ্ছে</translation>
<translation id="5205222826937269299">নাম প্রয়োজন</translation>
<translation id="5222812217790122047">ইমেল প্রয়োজন</translation>
-<translation id="522700295135997067">এই সাইট হয়ত আপনার পাসওয়ার্ড চুরি করেছে</translation>
<translation id="5230733896359313003">শিপিংয়ের ঠিকানা</translation>
<translation id="5250209940322997802">"নেটওয়ার্কে কানেক্ট করুন"</translation>
<translation id="5251803541071282808">ক্লাউড</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />সফ্টওয়্যারটি সাময়িকভাবে নিষ্ক্রিয় করার জন্য এই পদক্ষেপগুলি অনুসরণ করুন যাতে আপনি ওয়েবে যেতে পারেন। আপনার প্রশাসকের অধিকার প্রয়োজন হবে।<ph name="END_PARAGRAPH" />
<ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />শুরু করুন<ph name="END_BOLD" /> এ ক্লিক করুন, এবং তারপর <ph name="BEGIN_BOLD" />"স্থানীয় পরিষেবা দেখুন"<ph name="END_BOLD" /> অনুসন্ধান করে বেছে নিন
+ <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />শুরু করুন<ph name="END_BOLD" /> এ ক্লিক করুন, এবং তারপর <ph name="BEGIN_BOLD" />"স্থানীয় পরিষেবা দেখুন"<ph name="END_BOLD" /> সার্চ করে বেছে নিন
<ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />VisualDiscovery<ph name="END_BOLD" /> বেছে নিন
<ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />শুরু করার ধরন<ph name="END_BOLD" /> এর অধীনে <ph name="BEGIN_BOLD" />অক্ষম করুন <ph name="END_BOLD" /> বেছে নিন
<ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />পরিষেবা স্থিতির<ph name="END_BOLD" /> অধীনে <ph name="BEGIN_BOLD" />বন্ধ করুন <ph name="END_BOLD" /> এ ক্লিক করুন
@@ -645,7 +647,6 @@
<translation id="5492298309214877701">কোম্পানী, সংস্থা বা স্কুল ইন্ট্রানেটে এই সাইটটির একটি বাহ্যিক ওয়েবসাইটের মতো একই URL আছে।
<ph name="LINE_BREAK" />
আপনার সিস্টেম প্রশাসকের সাথে যোগাযোগের চেষ্টা করুন।</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> এর নিরাপত্তা কোড লিখুন। এই কোডটি সেভ করা হবে না।</translation>
<translation id="5509780412636533143">পরিচালিত বুকমার্কগুলি</translation>
<translation id="5510766032865166053">এটি হয়ত সরানো বা মুছে ফেলা হয়েছে।</translation>
<translation id="5523118979700054094">নীতি নাম</translation>
@@ -676,9 +677,11 @@
<translation id="5685654322157854305">শিপিং ঠিকানা যোগ করুন</translation>
<translation id="5689199277474810259">JSON এ রপ্তানি করুন</translation>
<translation id="5689516760719285838">লোকেশন</translation>
+<translation id="570530837424789914">পরিচালনা করুন...</translation>
<translation id="5710435578057952990">এই ওয়েবসাইটির পরিচয় যাচাই করা হয় নি৷</translation>
<translation id="5719499550583120431">প্রিপেড কার্ড গ্রহণ করা হয়।</translation>
<translation id="5720705177508910913">বর্তমান ব্যবহারকারী</translation>
+<translation id="5730040223043577876">Chrome-এর নীতি অনুযায়ী আপনার পাসওয়ার্ড বদলে ফেলা উচিত যদি আপনি সেটি অন্য কোনও সাইটে ব্যবহার করে থাকেন।</translation>
<translation id="5732392974455271431">আপনার পিতামাতা এটি আপনার জন্য অবরোধ মুক্ত করতে পারবেন</translation>
<translation id="5763042198335101085">একটি সঠিক ইমেল ঠিকানা লিখুন</translation>
<translation id="5765072501007116331">ডেলিভারির পদ্ধতি এবং প্রয়োজনীয়তাগুলি দেখতে একটি ঠিকানা বেছে নিন</translation>
@@ -702,9 +705,7 @@
<translation id="5959728338436674663">বিপজ্জনক অ্যাপ্লিকেশান ও সাইটগুলি শনাক্ত করতে Google এর কাছে কিছু<ph name="BEGIN_WHITEPAPER_LINK" /> সিস্টেম তথ্য ও পৃষ্ঠার সামগ্রী<ph name="END_WHITEPAPER_LINK" /> স্বয়ংক্রিয়ভাবে পাঠান। <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">পরিচিতির তথ্য সম্পাদনা করুন</translation>
<translation id="5967867314010545767">ইতিহাস থেকে সরান</translation>
-<translation id="5972020793760134803">ট্যাবে পরিবর্তন করুন</translation>
<translation id="5975083100439434680">জুম কমান</translation>
-<translation id="597552863672748783">নিরাপত্তা কোড নিশ্চিত করুন</translation>
<translation id="598637245381783098">পেমেন্ট অ্যাপ খোলা যাচ্ছে না</translation>
<translation id="5989320800837274978">কোনো নির্ধারিত প্রক্সি সার্ভার অথবা একটি.pac স্ক্রিপ্ট UR সুর্নিদিষ্টভাবে উল্লেখ করা হয়নি৷</translation>
<translation id="5990559369517809815">সার্ভারে অনুরোধগুলি একটি এক্সটেনশান দিয়ে অবরুদ্ধ করা আছে৷</translation>
@@ -720,6 +721,7 @@
<translation id="6047927260846328439">এই কন্টেন্ট প্রতারণার মাধ্যমে আপনাকে দিয়ে কোনও সফ্টওয়্যার ইনস্টল করাতে অথবা আপনার ব্যক্তিগত তথ্য জেনে নেওয়ার চেষ্টা করতে পারে। <ph name="BEGIN_LINK" />তবুও এটি দেখতে চাই<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ওয়েবসাইটটি পিন করা শংসাপত্র ব্যবহার করার কারণে আপনি এখন <ph name="SITE" /> এ যেতে পারবেন না। নেটওয়ার্ক ত্রুটি এবং আক্রমণ সাধারণত সাময়িকভাবে হয়, তাই এই পৃষ্ঠাটি সম্ভবত পরে কাজ করবে।</translation>
<translation id="6059925163896151826">USB ডিভাইসগুলি</translation>
+<translation id="6071091556643036997">নীতির এই ধরনটি ব্যবহার করা যাবে না।</translation>
<translation id="6080696365213338172">প্রশাসকের দ্বারা সরবরাহ করা শংসাপত্রের ব্যবহার করে আপনি সামগ্রী ব্যবহার করেছেন৷ <ph name="DOMAIN" /> কে আপনি যে ডেটা সরবরাহ করেন তা আপনার প্রশাসক বাধা দিতে পারে৷</translation>
<translation id="610911394827799129"><ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> এ আপনার Google অ্যাকাউন্টের অন্যান্য ধরনের ব্রাউজিংয়ের ইতিহাস থাকতে পারে</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{কিছুই নয়}=1{১টি পাসওয়ার্ড (সিঙ্ক করা হয়েছে)}one{#টি পাসওয়ার্ড (সিঙ্ক করা হয়েছে)}other{#টি পাসওয়ার্ড (সিঙ্ক করা হয়েছে)}}</translation>
@@ -728,7 +730,7 @@
<translation id="6151417162996330722">সার্ভারের শংসাপত্রের বৈধতার সময়সীমা আছে যা খুবই দীর্ঘ।</translation>
<translation id="6157877588268064908">শিপিং এর পদ্ধতি এবং প্রয়োজনীয়তা দেখতে একটি ঠিকানা বেছে নিন</translation>
<translation id="6165508094623778733">আরও জানুন</translation>
-<translation id="6169916984152623906">এখন আপনি গোপনভাবে ব্রাউজ করতে পারেন, এবং অন্য যেসব বক্তি এই ডিভাইস ব্যবহার করেন তারা আপনার কার্যকলাপ দেখতে পাবেন না। তবে, আপনার ডাউনলোড এবং বুকমার্কগুলি সংরক্ষণ করা হবে।</translation>
+<translation id="6169916984152623906">এখন আপনি গোপনভাবে ব্রাউজ করতে পারেন, এবং অন্য যেসব বক্তি এই ডিভাইস ব্যবহার করেন তারা আপনার অ্যাক্টিভিটি দেখতে পাবেন না। তবে, আপনার ডাউনলোড এবং বুকমার্কগুলি সংরক্ষণ করা হবে।</translation>
<translation id="6177128806592000436">এই সাইটে আপনার সংযোগ নিরাপদ নয়</translation>
<translation id="6203231073485539293">আপনার ইন্টারনেট সংযোগ পরীক্ষা করুন</translation>
<translation id="6218753634732582820">Chromium থেকে ঠিকানা সরাবেন?</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">আরও তথ্য যোগ করুন</translation>
<translation id="6447842834002726250">কুকিজ</translation>
<translation id="6451458296329894277">ফর্ম পুনঃজমা নিশ্চিত করুন</translation>
+<translation id="6465306955648956876">পাসওয়ার্ড পরিচালনা করুন...</translation>
<translation id="647261751007945333">ডিভাইস নীতিগুলি</translation>
<translation id="6477321094435799029">Chrome এই পৃষ্ঠাতে অস্বাভাবিক কোড পেয়েছে এবং আপনার ব্যক্তিগত তথ্যের (উদাহরণস্বরূপ, পাসওয়ার্ড, ফোন নম্বর, এবং ক্রেডিট কার্ড) সুরক্ষার জন্য এটি অবরুদ্ধ করেছে।</translation>
<translation id="6489534406876378309">ক্র্যাশগুলি আপলোড করা শুরু করুন</translation>
@@ -782,14 +785,15 @@
<translation id="6604181099783169992">মোশন বা হাল্কা সেন্সর</translation>
<translation id="6624427990725312378">পরিচিতির তথ্য</translation>
<translation id="6626291197371920147">বৈধ কার্ড নম্বর যোগ করুন</translation>
-<translation id="6628463337424475685"><ph name="ENGINE" /> অনুসন্ধান</translation>
+<translation id="6628463337424475685"><ph name="ENGINE" /> সার্চ</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> এ যে আক্রমণকারীরা এই মুহূর্তে সক্রিয় আছে, তারা আপনার Mac এ এমন বিপজ্জনক প্রোগ্রাম ইনস্টল করে দিতে পারে যেগুলি আপনার তথ্যের (যেমন ফটো, পাসওয়ার্ড, মেসেজ এবং ক্রেডিট কার্ড) ক্ষতি করতে বা সেগুলি চুরি করতে পারে। <ph name="BEGIN_LEARN_MORE_LINK" />আরও জানুন<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">এই নীতিটি অসমর্থিত হয়েছে৷</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{কিছুই নয়}=1{১টি সাইট থেকে (আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না)}one{#টি সাইট থেকে (আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না)}other{#টি সাইট থেকে (আপনাকে আপনার Google অ্যাকাউন্ট থেকে সাইন-আউট করা হবে না)}}</translation>
<translation id="6657585470893396449">পাসওয়ার্ড</translation>
<translation id="6671697161687535275">Chromium থেকে ফর্ম প্রস্তাবনা সরাবেন?</translation>
<translation id="6685834062052613830">প্রস্থান করুন করে সেটআপ সম্পূর্ণ করুন</translation>
<translation id="6710213216561001401">পূর্ববর্তী</translation>
-<translation id="6710594484020273272">&lt;অনুসন্ধানের পদ লিখুন&gt;</translation>
+<translation id="6710594484020273272">&lt;সার্চের পদ লিখুন&gt;</translation>
<translation id="6711464428925977395">প্রক্সী সার্ভারের কোনো সমস্যা হয়েছে, অথবা ঠিকানাটি ভুল।</translation>
<translation id="674375294223700098">অজানা সার্ভার শংসাপত্র ত্রুটি৷</translation>
<translation id="6753269504797312559">নীতি মান</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">ব্যবহারকারী:</translation>
<translation id="6945221475159498467">নির্বাচন</translation>
<translation id="6948701128805548767">পিকআপ এর পদ্ধতি এবং প্রয়োজনীয়তা দেখতে একটি ঠিকানা বেছে নিন</translation>
+<translation id="6949872517221025916">পাসওয়ার্ড রিসেট করুন</translation>
<translation id="6957887021205513506">সার্ভারটির শংসাপত্রটি একটি জাল হিসাবে উপস্থিত হয়েছে৷</translation>
<translation id="6965382102122355670">ঠিক আছে</translation>
<translation id="6965978654500191972">ডিভাইস</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">ডেলিভারির পদ্ধতি</translation>
<translation id="7139724024395191329">এমিরেট</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />টি}one{<ph name="PAYMENT_METHOD_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />টি}other{<ph name="PAYMENT_METHOD_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />টি}}</translation>
-<translation id="7155487117670177674">পেমেন্ট সুরক্ষিত নয়</translation>
+<translation id="717330890047184534">Gaia আইডি:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />টি}one{<ph name="SHIPPING_OPTION_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />টি}other{<ph name="SHIPPING_OPTION_PREVIEW" /> এবং আরও <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />টি}}</translation>
<translation id="7180611975245234373">রিফ্রেশ করুন</translation>
<translation id="7182878459783632708">কোন নীতি সেট করা নেই</translation>
@@ -862,6 +867,16 @@
<translation id="7378810950367401542">/</translation>
<translation id="7390545607259442187">কার্ড নিশ্চিত করুন</translation>
<translation id="7400418766976504921">URL</translation>
+<translation id="7407424307057130981">&lt;p&gt;আপনার Windows কম্পিউটারে Superfish সফ্টওয়্যারটি ইনস্টল করা থাকলে এই সমস্যাটি হবে।&lt;/p&gt;
+ &lt;p&gt;ইন্টারনেটে কানেক্ট করার জন্য এই সফ্টওয়্যারটি সাময়িকভাবে বন্ধ রাখতে এই ধাপগুলি অনুসরণ করুন। এর জন্য অ্যাডমিনিস্ট্রেটরের সুবিধা থাকতে হবে।&lt;/p&gt;
+ &lt;ol&gt;
+ &lt;li&gt;প্রথমে&lt;strong&gt;শুরু করুন&lt;/strong&gt;বোতামে ক্লিক করুন, তারপর &lt;strong&gt;"স্থানীয় পরিষেবা দেখুন"&lt;/strong&gt; বিকল্পটি বেছে নিন
+ &lt;li&gt;&lt;strong&gt;VisualDiscovery&lt;/strong&gt; বেছে নিন
+ &lt;li&gt;&lt;strong&gt;স্টার্ট-আপের ধরন&lt;/strong&gt;, বিকল্পে গিয়ে&lt;strong&gt;বন্ধ আছে&lt;/strong&gt; বিকল্পটি বেছে নিন
+ &lt;li&gt;&lt;strong&gt;পরিষেবার স্ট্যাটাসে&lt;/strong&gt; গিয়ে, &lt;strong&gt;থামান&lt;/strong&gt; বোতামে ক্লিক করুন
+ &lt;li&gt;&lt;strong&gt;প্রয়োগ করুন&lt;/strong&gt;-এ ক্লিক করে, &lt;strong&gt;ঠিক আছে&lt;/strong&gt;বোতামে ক্লিক করুন
+ &lt;li&gt;কম্পিউটার থেকে সফ্টওয়্যারটি স্থায়ীভাবে সরিয়ে দেওয়ার পদ্ধতি জানতে &lt;a href="https://support.google.com/chrome/answer/6098869"&gt;Chrome সহায়তা কেন্দ্রে&lt;/a&gt; যান
+ &lt;/ol&gt;</translation>
<translation id="7419106976560586862">প্রোফাইল পথ</translation>
<translation id="7437289804838430631">পরিচিতির তথ্য যোগ করুন</translation>
<translation id="7441627299479586546">ভুল বিষয় বিশিষ্ট নীতি</translation>
@@ -871,6 +886,7 @@
<translation id="7455133967321480974">বিশ্বব্যাপী ডিফল্ট ব্যবহার করুন (অবরোধ করুন)</translation>
<translation id="7460163899615895653">অন্যান্য ডিভাইসগুলি থেকে আপনার সাম্প্রতিক ট্যাবগুলি এখানে দেখা যাবে</translation>
<translation id="7469372306589899959">কার্ড নিশ্চিত করা হচ্ছে</translation>
+<translation id="7473891865547856676">না থাক</translation>
<translation id="7481312909269577407">ফরওয়ার্ড</translation>
<translation id="7485870689360869515">কোনো ডেটা পাওয়া যায়নি৷</translation>
<translation id="7508255263130623398">ফিরে পাওয়া নীতির ডিভাইস আইডি খালি অথবা বর্তমান ডিভাইস আইডির সাথে মিলছে না</translation>
@@ -893,7 +909,6 @@
<translation id="7569952961197462199">Chrome থেকে ক্রেডিট কার্ড সরাবেন?</translation>
<translation id="7575800019233204241">"আপনার কানেকশন গোপন নয়" অথবা "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" অথবা "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" বা "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" অথবা "SSL সার্টিফিকেটে সমস্যা"</translation>
<translation id="7578104083680115302">আপনি Google এর সাথে সংরক্ষণ করেছেন এমন কার্ড ব্যবহার করে ডিভাইস জুড়ে সাইট এবং অ্যাপ্লিকেশানগুলিতে দ্রুত অর্থ পরিশোধ করুন।</translation>
-<translation id="7588950540487816470">বাস্তবিক ওয়েব</translation>
<translation id="7592362899630581445">সার্ভারের শংসাপত্র, নামের সীমাবদ্ধতাগুলি লঙ্ঘন করে৷</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> এর কম</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> বর্তমানে এই অনুরোধটি পরিচালনা করতে অক্ষম।</translation>
@@ -1046,7 +1061,7 @@
<translation id="8790007591277257123">&amp;মুছে ফেলাকে আবার করুন</translation>
<translation id="8792621596287649091">আপনি নিজের <ph name="ORG_NAME" /> অ্যাকাউন্টের অ্যাক্সেস হারাতে পারেন অথবা আপনার পরিচয় চুরি হয়ে যেতে পারে। Chromium এখনই আপনার পাসওয়ার্ড পরিবর্তন করার আর্জি জানাচ্ছে।</translation>
<translation id="8800988563907321413">আপনার জন্য আশেপাশের প্রস্তাবনাগুলি এখানে দেখা যাবে</translation>
-<translation id="8820817407110198400">বুকমার্ক</translation>
+<translation id="8820817407110198400">বুকমার্কস</translation>
<translation id="883848425547221593">অন্যান্য বুকমার্ক</translation>
<translation id="884264119367021077">শিপিং ঠিকানা</translation>
<translation id="884923133447025588">কোন প্রত্যাহার নির্মাণকৌশল পাওয়া যায় নি৷</translation>
@@ -1096,6 +1111,7 @@
<translation id="9148507642005240123">&amp;সম্পাদনাকে পূর্বাবস্থায় ফেরান</translation>
<translation id="9154194610265714752">আপডেট রয়েছে</translation>
<translation id="9157595877708044936">সেট আপ হচ্ছে...</translation>
+<translation id="9168814207360376865">আপনি কোনও পেমেন্ট পদ্ধতি সেভ করেছেন কিনা তা সাইটগুলিকে যাচাই করতে দিন</translation>
<translation id="9169664750068251925">এই সাইটে সর্বদা অবরোধ করুন</translation>
<translation id="9170848237812810038">&amp;পূর্বাবস্থায় ফিরুন</translation>
<translation id="917450738466192189">সার্ভারের শংসাপত্র অকার্যকর৷</translation>
@@ -1104,7 +1120,6 @@
<translation id="9207861905230894330">নিবন্ধ যোগ করতে ব্যর্থ হয়েছে৷</translation>
<translation id="9215416866750762878">একটি অ্যাপ্লিকেশন Chrome কে এই সাইটের সাথে নিরাপদভাবে সংযুক্ত হতে বাধা দিচ্ছে</translation>
<translation id="9219103736887031265">ছবিগুলি</translation>
-<translation id="933612690413056017">কোনো ইন্টারনেট সংযোগ নেই</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ফর্ম সাফ করুন</translation>
<translation id="939736085109172342">নতুন ফোল্ডার</translation>
diff --git a/chromium/components/strings/components_strings_ca.xtb b/chromium/components/strings/components_strings_ca.xtb
index b9e0b73398b..f59b00f58ff 100644
--- a/chromium/components/strings/components_strings_ca.xtb
+++ b/chromium/components/strings/components_strings_ca.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Selecciona un permís per a <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Adreces d'interès recents</translation>
<translation id="1113869188872983271">&amp;Desfés el canvi d'ordre</translation>
+<translation id="1125573121925420732">És probable que rebis advertiments mentre s'actualitza la seguretat als llocs web, però això millorarà aviat.</translation>
<translation id="1126551341858583091">La mida de l'emmagatzematge local és de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">La memòria cau de la política està en bon estat</translation>
<translation id="1150979032973867961">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè el sistema operatiu del vostre ordinador considera que el seu certificat de seguretat no és de confiança. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Comproveu que la connexió a Internet funcioni amb normalitat.&lt;/li&gt;
&lt;li&gt;Contacteu amb el propietari del lloc web.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Has introduït la contrasenya en un lloc web que no està gestionat per la teva organització. Per protegir el teu compte, no facis servir la mateixa contrasenya en altres aplicacions ni llocs web.</translation>
<translation id="1263231323834454256">Llista de lectura</translation>
<translation id="1264126396475825575">S'ha capturat un informe d'error (<ph name="CRASH_TIME" />) (encara no s'ha penjat ni ignorat)</translation>
<translation id="1270502636509132238">Mètode de recollida</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Tria</translation>
<translation id="1620510694547887537">Càmera</translation>
<translation id="1623104350909869708">Impedeix que aquesta pàgina creï diàlegs addicionals.</translation>
-<translation id="1629803312968146339">Voleu que Chrome desi aquesta targeta?</translation>
<translation id="1639239467298939599">S'està carregant</translation>
<translation id="1640180200866533862">Polítiques d'usuari</translation>
<translation id="1640244768702815859">Prova d'<ph name="BEGIN_LINK" />anar a la pàgina d'inici del lloc<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Proveu d'executar el Diagnòstic de xarxa de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualitzeu la frase de contrasenya de sincronització.</translation>
<translation id="1787142507584202372">Les pestanyes obertes es mostren aquí</translation>
-<translation id="1789575671122666129">Finestres emergents</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nom del titular de la targeta</translation>
<translation id="1806541873155184440">Afegida el dia <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Reinicia l'ordinador</translation>
<translation id="2113977810652731515">Targeta</translation>
<translation id="2114841414352855701">S'ha ignorat perquè <ph name="POLICY_NAME" /> l'ha substituït.</translation>
-<translation id="2138201775715568214">S'estan cercant pàgines del Web físic a prop</translation>
<translation id="213826338245044447">Adreces d'interès per a mòbils</translation>
<translation id="214556005048008348">Cancel·la el pagament</translation>
<translation id="2147827593068025794">Sincronització en segon pla</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">No es troba la política</translation>
<translation id="2213606439339815911">S'estan recuperant les entrades...</translation>
<translation id="2218879909401188352">És possible que els atacants que es troben a <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instal·lin aplicacions perilloses que malmetin el teu dispositiu, afegeixin càrrecs amagats a la teva factura telefònica o et robin informació personal. <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Sense connexió a Internet</translation>
<translation id="2230458221926704099">Repareu la connexió amb l'<ph name="BEGIN_LINK" />aplicació de diagnòstic<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Envia ara</translation>
<translation id="225207911366869382">El valor d'aquesta política és obsolet.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Suprimeix els elements seleccionats</translation>
<translation id="277133753123645258">Mètode d'enviament</translation>
<translation id="277499241957683684">Falta el registre del dispositiu</translation>
+<translation id="2781030394888168909">Exporta a MacOS</translation>
<translation id="2784949926578158345">S'ha restablert la connexió.</translation>
<translation id="2788784517760473862">Targetes de crèdit acceptades</translation>
<translation id="2794233252405721443">Lloc bloquejat</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome no ha pogut confirmar la teva targeta. Torna-ho a provar més tard.</translation>
<translation id="3064966200440839136">Per pagar amb una aplicació externa sortiràs del mode d'incògnit. Vols continuar?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Cap}=1{1 contrasenya}other{# contrasenyes}}</translation>
-<translation id="3093245981617870298">No tens connexió</translation>
<translation id="3096100844101284527">Afegeix l'adreça de recollida</translation>
<translation id="3105172416063519923">Identificador de l'element:</translation>
<translation id="3109728660330352905">No teniu permís per veure aquesta pàgina.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Actualment no es pot accedir a <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Permet (opció predeterminada)</translation>
<translation id="3427342743765426898">&amp;Refés la modificació</translation>
+<translation id="342781501876943858">Chromium et recomana que restableixis la contrasenya si l'has fet servir en altres llocs web.</translation>
<translation id="3431636764301398940">Desa aquesta targeta al dispositiu</translation>
<translation id="3447661539832366887">El propietari d'aquest dispositiu ha desactivat el joc de dinosaures.</translation>
<translation id="3447884698081792621">Mostra el certificat (emès per <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Obre la pàgina en una finestra d'incògnit nova (Ctrl+Maj+N)</translation>
<translation id="3679803492151881375">Informe d'error generat el <ph name="CRASH_TIME" /> i enviat el <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informació del certificat</translation>
-<translation id="3690164694835360974">L'inici de sessió no és segur</translation>
<translation id="3704162925118123524">És possible que la xarxa que esteu fent servir requereixi que visiteu la pàgina d'inici de sessió.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">S'està carregant...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilitza el valor predeterminat global (detecta)</translation>
<translation id="4165986682804962316">Configuració del lloc web</translation>
-<translation id="4169947484918424451">Voleu que Chromium desi aquesta targeta?</translation>
<translation id="4171400957073367226">La signatura de verificació és incorrecta</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> element més}other{<ph name="ITEM_COUNT" /> elements més}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Reinici del dispositiu</translation>
<translation id="4277028893293644418">Restableix la contrasenya</translation>
<translation id="4280429058323657511">, caduca el dia <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Canvia</translation>
<translation id="4312866146174492540">Bloqueja (opció predeterminada)</translation>
<translation id="4325863107915753736">No s'ha pogut trobar l'article</translation>
<translation id="4326324639298822553">Comprova la data de caducitat i torna-ho a provar</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">No ens consta que aquest ordinador estigui gestionat per una empresa. Per tant, la política només pot instal·lar automàticament extensions allotjades a Chrome Web Store. L'URL d'actualització de Chrome Web Store és <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Targetes de crèdit acceptades</translation>
<translation id="4356973930735388585">Els atacants d'aquest lloc poden provar d'instal·lar programes perillosos a l'ordinador per robar o suprimir la teva informació (per exemple, les fotos, les contrasenyes, els missatges i les targetes de crèdit).</translation>
+<translation id="4358461427845829800">Gestiona les formes de pagament...</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperat.</translation>
<translation id="4377125064752653719">Heu provat d'accedir a <ph name="DOMAIN" />, però l'emissor ha revocat el certificat que ha presentat el servidor. Això vol dir que no heu de confiar gens en les credencials de seguretat que ha presentat el servidor. És possible que us estigueu comunicant amb un atacant.</translation>
<translation id="4406896451731180161">resultats de la cerca</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Adreça de recollida</translation>
<translation id="4424024547088906515">Aquest servidor no ha pogut comprovar que sigui <ph name="DOMAIN" /> perquè Chrome considera que el seu certificat de seguretat no és de confiança. Això pot ser a causa d'una configuració incorrecta o d'un atacant que intercepta la vostra connexió.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha acceptat el certificat d'inici de sessió o pot ser que no se n'hagi proporcionat cap.</translation>
+<translation id="4434045419905280838">Finest. emergents i redireccions</translation>
<translation id="443673843213245140">L'ús d'un servidor intermediari no està activat, però s'ha especificat una configuració explícita d'un servidor intermediari.</translation>
<translation id="445100540951337728">Targetes de dèbit acceptades</translation>
<translation id="4506176782989081258">Error de validació: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">S'ha desactivat l'emplenament automàtic de pagaments</translation>
<translation id="4764776831041365478">És possible que la pàgina web de <ph name="URL" /> estigui temporalment inactiva o que s'hagi desplaçat permanentment a una nova adreça web.</translation>
<translation id="4771973620359291008">S'ha produït un error desconegut.</translation>
+<translation id="4785689107224900852">Canvia a aquesta pestanya</translation>
<translation id="4792143361752574037">Hi ha hagut un problema en accedir als fitxers de la sessió. En aquests moments no es poden desar al disc. Torna a carregar la pàgina per provar-ho de nou.</translation>
<translation id="4800132727771399293">Comproveu la data de caducitat i el CVC i torneu-ho a provar</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">En aquest moment no podeu visitar <ph name="SITE" /> perquè el lloc web ha enviat credencials aleatòries que Google Chrome no pot processar. Els errors i els atacs de xarxa solen ser temporals, de manera que és probable que aquesta pàgina torni a funcionar més tard.</translation>
<translation id="4813512666221746211">Error de xarxa</translation>
<translation id="4816492930507672669">Ajusta a la mida de la pàgina</translation>
-<translation id="483020001682031208">No es pot mostrar cap pàgina del Web físic</translation>
<translation id="4850886885716139402">Mostra</translation>
<translation id="4854362297993841467">Aquest mètode d'entrega no està disponible. Prova'n un altre.</translation>
<translation id="4858792381671956233">Has demanat permís als teus pares per visitar aquest lloc</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bits)</translation>
<translation id="5121084798328133320">Un cop confirmada, els detalls de la targeta del teu compte de pagaments de Google es compartiran amb aquest lloc web.</translation>
<translation id="5128122789703661928">La sessió amb aquest nom no es pot suprimir.</translation>
+<translation id="5135404736266831032">Gestiona les adreces...</translation>
<translation id="5141240743006678641">Encripta contrasenyes sincronitzades amb les vostres credencials de Google</translation>
<translation id="5145883236150621069">Hi ha un codi d'error en la resposta a la política</translation>
<translation id="5159010409087891077">Obre la pàgina en una finestra d'incògnit nova (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Una pàgina inserida en aquesta pàgina diu</translation>
<translation id="5205222826937269299">El nom és obligatori</translation>
<translation id="5222812217790122047">El correu electrònic és obligatori</translation>
-<translation id="522700295135997067">És possible que aquest lloc web t'acabi de robar la contrasenya</translation>
<translation id="5230733896359313003">Adreça d'enviament</translation>
<translation id="5250209940322997802">"Connecteu-vos a la xarxa"</translation>
<translation id="5251803541071282808">Núvol</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Aquest lloc de la intranet de l'empresa, l'organització o el centre educatiu té el mateix URL que un lloc web extern.
<ph name="LINE_BREAK" />
Proveu de contactar amb l'administrador del sistema.</translation>
-<translation id="5499929369096410817">Introdueix el codi de seguretat de la targeta <ph name="CREDIT_CARD" />. Aquest codi no es desarà.</translation>
<translation id="5509780412636533143">Adreces d'interès gestionades</translation>
<translation id="5510766032865166053">És possible que s'hagi mogut o s'hagi suprimit.</translation>
<translation id="5523118979700054094">Nom de la política</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Afegeix una adreça d'enviament</translation>
<translation id="5689199277474810259">Exporta a JSON</translation>
<translation id="5689516760719285838">Ubicació</translation>
+<translation id="570530837424789914">Gestiona...</translation>
<translation id="5710435578057952990">La identitat d'aquest lloc web no ha estat verificada.</translation>
<translation id="5719499550583120431">S'accepten targetes de prepagament.</translation>
<translation id="5720705177508910913">Usuari actual</translation>
+<translation id="5730040223043577876">Chrome et recomana que restableixis la contrasenya si l'has fet servir en altres llocs web.</translation>
<translation id="5732392974455271431">Els teus pares te'l poden desbloquejar</translation>
<translation id="5763042198335101085">Introdueix una adreça electrònica vàlida</translation>
<translation id="5765072501007116331">Per veure els mètodes i els requisits d'entrega, selecciona una adreça</translation>
@@ -689,7 +692,7 @@
<translation id="5803412860119678065">Vols emplenar la informació de la teva targeta <ph name="CARD_DETAIL" />?</translation>
<translation id="5810442152076338065">La connexió a <ph name="DOMAIN" /> s'ha encriptat amb un sistema de xifratge obsolet.</translation>
<translation id="5813119285467412249">&amp;Refés l'addició</translation>
-<translation id="5838278095973806738">No introdueixis informació confidencial en aquest lloc (com ara contrasenyes o targetes de crèdit), ja que alguns atacants podrien robar-la.</translation>
+<translation id="5838278095973806738">No introdueixis informació sensible en aquest lloc (com ara contrasenyes o targetes de crèdit), ja que alguns atacants podrien robar-la.</translation>
<translation id="5866257070973731571">Afegeix un número de telèfon</translation>
<translation id="5869405914158311789">No es pot accedir a aquest lloc</translation>
<translation id="5869522115854928033">Contrasenyes desades</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Envia automàticament algunes <ph name="BEGIN_WHITEPAPER_LINK" />dades del sistema i contingut de les pàgines<ph name="END_WHITEPAPER_LINK" /> a Google per ajudar a detectar les aplicacions i els llocs web perillosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edita la informació de contacte</translation>
<translation id="5967867314010545767">Elimina de l'historial</translation>
-<translation id="5972020793760134803">Canvia a la pestanya</translation>
<translation id="5975083100439434680">Redueix</translation>
-<translation id="597552863672748783">Confirma el codi de seguretat</translation>
<translation id="598637245381783098">No es pot obrir l'aplicació de pagament</translation>
<translation id="5989320800837274978">No s'especifiquen servidors intermediaris ni URL d'script .pac.</translation>
<translation id="5990559369517809815">Una extensió ha bloquejat les peticions al servidor.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Aquest contingut pot provar d'enganyar-te perquè instal·lis programari o proporcionis informació personal. <ph name="BEGIN_LINK" />Mostra igualment<ph name="END_LINK" />.</translation>
<translation id="6051221802930200923">En aquests moments no pots visitar <ph name="SITE" /> perquè el lloc web fa servir una fixació de certificat. Els atacs i els errors de xarxa acostumen a ser temporals, o sigui que probablement la pàgina funcionarà més endavant.</translation>
<translation id="6059925163896151826">Dispositius USB</translation>
+<translation id="6071091556643036997">El tipus de política no és vàlid.</translation>
<translation id="6080696365213338172">Heu accedit a contingut mitjançant un certificat proporcionat per l'administrador. Per tant, l'administrador por interceptar les dades que proporcioneu a <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">A <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />, trobaràs altres maneres d'explorar l'historial del teu compte de Google</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Cap}=1{1 contrasenya (sincronitzada)}other{# contrasenyes (sincronitzades)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Afegeix més informació</translation>
<translation id="6447842834002726250">Galetes</translation>
<translation id="6451458296329894277">Confirma el reenviament del formulari</translation>
+<translation id="6465306955648956876">Gestiona les contrasenyes...</translation>
<translation id="647261751007945333">Polítiques de dispositius</translation>
<translation id="6477321094435799029">Chrome ha detectat codi poc comú en aquesta pàgina i, per tant, l'ha bloquejat per protegir la teva informació personal (per exemple, contrasenyes, números de telèfon i targetes de crèdit).</translation>
<translation id="6489534406876378309">Comença a penjar els errors</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Cerca de <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">És possible que els atacants que es troben a <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> provin d'instal·lar programes perillosos a l'ordinador Mac per robar-te o suprimir-te informació (per exemple, fotos, contrasenyes, missatges i targetes de crèdit). <ph name="BEGIN_LEARN_MORE_LINK" />Més informació<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Aquesta política ha quedat obsoleta.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Cap}=1{D'1 lloc web (no se't tancarà la sessió del compte de Google)}other{De # llocs web (no se't tancarà la sessió del compte de Google)}}</translation>
<translation id="6657585470893396449">Contrasenya</translation>
<translation id="6671697161687535275">Voleu suprimir el suggeriment de formulari de Chromium?</translation>
<translation id="6685834062052613830">Tanqueu la sessió i completeu la configuració</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Usuari:</translation>
<translation id="6945221475159498467">Selecciona</translation>
<translation id="6948701128805548767">Per veure els mètodes i els requisits de recollida, selecciona una adreça</translation>
+<translation id="6949872517221025916">Restableix la contrasenya</translation>
<translation id="6957887021205513506">Sembla que el certificat del servidor és una falsificació.</translation>
<translation id="6965382102122355670">D'acord</translation>
<translation id="6965978654500191972">Dispositiu</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Mètode d'entrega</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> més}other{<ph name="PAYMENT_METHOD_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> més}}</translation>
-<translation id="7155487117670177674">El pagament no és segur</translation>
+<translation id="717330890047184534">Identificador de Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> més}other{<ph name="SHIPPING_OPTION_PREVIEW" /> i <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> més}}</translation>
<translation id="7180611975245234373">Actualitza</translation>
<translation id="7182878459783632708">Cap política definida</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Utilitza l'opció predeterminada global (Bloqueja)</translation>
<translation id="7460163899615895653">Les teves pestanyes recents d'altres dispositius es mostraran aquí</translation>
<translation id="7469372306589899959">S'està confirmant la targeta</translation>
+<translation id="7473891865547856676">No, gràcies</translation>
<translation id="7481312909269577407">Endavant</translation>
<translation id="7485870689360869515">No s'han trobat dades.</translation>
<translation id="7508255263130623398">L'identificador de dispositiu de la política que s'ha tornat és buit o no coincideix amb l'actual</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Voleu suprimir la targeta de crèdit de Chrome?</translation>
<translation id="7575800019233204241">"La vostra connexió no és privada", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" o "Error de certificat SSL"</translation>
<translation id="7578104083680115302">Agilitzeu els pagaments en llocs i en aplicacions des de qualsevol dispositiu mitjançant les targetes que hàgiu desat a Google.</translation>
-<translation id="7588950540487816470">El Web físic</translation>
<translation id="7592362899630581445">El certificat del servidor incompleix les restriccions de nom.</translation>
<translation id="7598391785903975535">Menys de: <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> no pot gestionar la sol·licitud en aquest moment.</translation>
@@ -1015,7 +1020,7 @@
<translation id="8363502534493474904">Desactiva el mode d'avió.</translation>
<translation id="8364627913115013041">No s'ha definit.</translation>
<translation id="8368476060205742148">Serveis de Google Play</translation>
-<translation id="8380941800586852976">Perillosa</translation>
+<translation id="8380941800586852976">Perillós</translation>
<translation id="8382348898565613901">Les adreces d'interès que has visitat fa poc es mostren aquí</translation>
<translation id="8398259832188219207">Informe d'error penjat el <ph name="UPLOAD_TIME" /></translation>
<translation id="8412145213513410671">Bloqueigs (<ph name="CRASH_COUNT" />)</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Desfés la modificació</translation>
<translation id="9154194610265714752">S'ha actualitzat.</translation>
<translation id="9157595877708044936">S'està configurant...</translation>
+<translation id="9168814207360376865">Permet que els llocs web comprovin si tens formes de pagament desades</translation>
<translation id="9169664750068251925">Bloqueja sempre en aquest lloc</translation>
<translation id="9170848237812810038">&amp;Desfés</translation>
<translation id="917450738466192189">El certificat del servidor no és vàlid.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">No s'ha pogut afegir l'article.</translation>
<translation id="9215416866750762878">Una aplicació impedeix que Chrome es connecti de manera segura a aquest lloc web</translation>
<translation id="9219103736887031265">Imatges</translation>
-<translation id="933612690413056017">No hi ha connexió a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ESBORRA EL FORMULARI</translation>
<translation id="939736085109172342">Carpeta nova</translation>
diff --git a/chromium/components/strings/components_strings_cs.xtb b/chromium/components/strings/components_strings_cs.xtb
index 5937f758e4a..43c93caa826 100644
--- a/chromium/components/strings/components_strings_cs.xtb
+++ b/chromium/components/strings/components_strings_cs.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Vyberte oprávnění pro <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Nejnovější záložky</translation>
<translation id="1113869188872983271">&amp;Vrátit změnu uspořádání zpět</translation>
+<translation id="1125573121925420732">Během aktualizace zabezpečení na webech mohou být upozornění běžná. Brzy by se to mělo zlepšit.</translation>
<translation id="1126551341858583091">Velikost místního úložiště je <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Mezipaměť zásady je v pořádku</translation>
<translation id="1150979032973867961">Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Operační systém vašeho počítače nedůvěřuje jeho bezpečnostnímu certifikátu.Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Zkontrolujte, zda připojení k internetu normálně funguje.&lt;/li&gt;
&lt;li&gt;Kontaktujte vlastníka webu.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Zadali jste své heslo na webu, který není spravován vaší organizací. Kvůli ochraně účtu nepoužívejte jeho heslo v jiných aplikacích a na jiných webech.</translation>
<translation id="1263231323834454256">Seznam četby</translation>
<translation id="1264126396475825575">Zpráva o selhání pořízená <ph name="CRASH_TIME" /> (dosud nenahrána nebo ignorována)</translation>
<translation id="1270502636509132238">Způsob vyzvednutí</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Zvolit</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Bránit této stránce ve vytváření dalších dialogových oken</translation>
-<translation id="1629803312968146339">Chcete, aby Chrome tuto kartu uložil?</translation>
<translation id="1639239467298939599">Načítání</translation>
<translation id="1640180200866533862">Zásady pro uživatele</translation>
<translation id="1640244768702815859">Zkuste <ph name="BEGIN_LINK" />navštívit domovskou stránku webu<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Zkuste spustit Diagnostiku sítě systému Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Aktualizujte prosím heslovou frázi pro synchronizaci.</translation>
<translation id="1787142507584202372">Zde se zobrazí otevřené karty</translation>
-<translation id="1789575671122666129">Vyskakovací okna</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Jméno držitele karty</translation>
<translation id="1806541873155184440">Přidáno <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Restartujte počítač</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Zásada ignorována, protože bylo přepsána zásadou <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Vyhledávání stránek fyzického webu v okolí</translation>
<translation id="213826338245044447">Mobilní záložky</translation>
<translation id="214556005048008348">Zrušit platbu</translation>
<translation id="2147827593068025794">Synchronizace na pozadí</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Zásada nebyla nalezena</translation>
<translation id="2213606439339815911">Načítání záznamů...</translation>
<translation id="2218879909401188352">Útočníci, kteří na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> aktuálně působí, by vám do zařízení mohli nainstalovat nebezpečné aplikace, které jej poškodí, přidat skryté poplatky na účet za mobilní služby nebo odcizit osobní údaje. <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Nejste připojeni k internetu</translation>
<translation id="2230458221926704099">Opravte připojení pomocí <ph name="BEGIN_LINK" />diagnostické aplikace<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Odeslat</translation>
<translation id="225207911366869382">Tato hodnota již pro tuto zásadu není podporována.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Odstranit vybrané položky</translation>
<translation id="277133753123645258">Způsob dopravy</translation>
<translation id="277499241957683684">Chybějící záznam zařízení</translation>
+<translation id="2781030394888168909">Exportovat pro MacOS</translation>
<translation id="2784949926578158345">Připojení bylo resetováno.</translation>
<translation id="2788784517760473862">Přijímané kreditní karty</translation>
<translation id="2794233252405721443">Web je blokován</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome vaši kartu aktuálně nemohl ověřit. Zkuste to prosím znovu později.</translation>
<translation id="3064966200440839136">Chystáte se opustit anonymní režim, abyste mohli zaplatit v externí aplikaci. Chcete pokračovat?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Žádné}=1{1 heslo}few{# hesla}many{# hesla}other{# hesel}}</translation>
-<translation id="3093245981617870298">Nejste připojeni k síti.</translation>
<translation id="3096100844101284527">Přidat adresu vyzvednutí</translation>
<translation id="3105172416063519923">ID díla:</translation>
<translation id="3109728660330352905">K zobrazení této stránky nemáte oprávnění.</translation>
@@ -359,6 +359,7 @@
<translation id="3422472998109090673">Web <ph name="HOST_NAME" /> momentálně není dostupný.</translation>
<translation id="3427092606871434483">Povolit (výchozí)</translation>
<translation id="3427342743765426898">&amp;Opakovat úpravy</translation>
+<translation id="342781501876943858">Pokud jste heslo použili na jiném webu, doporučujeme vám ho resetovat.</translation>
<translation id="3431636764301398940">Uložit tuto kartu do zařízení</translation>
<translation id="3447661539832366887">Vlastník tohoto zařízení hru s dinosaurem vypnul.</translation>
<translation id="3447884698081792621">Zobrazit certifikát (vydavatel: <ph name="ISSUER" />)</translation>
@@ -394,7 +395,6 @@
<translation id="3678529606614285348">Otevřete stránku v novém anonymním okně (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Zpráva o selhání pořízená <ph name="CRASH_TIME" /> byla nahrána <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informace o certifikátu</translation>
-<translation id="3690164694835360974">Přihlášení není zabezpečené</translation>
<translation id="3704162925118123524">Síť, kterou používáte, může vyžadovat, abyste navštívili její stránku přihlášení.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Načítání...</translation>
@@ -454,7 +454,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Použít globální výchozí nastavení (zjistit)</translation>
<translation id="4165986682804962316">Nastavení webu</translation>
-<translation id="4169947484918424451">Chcete, aby prohlížeč Chromium tuto kartu uložil?</translation>
<translation id="4171400957073367226">Chybný ověřovací podpis</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> další položka}few{<ph name="ITEM_COUNT" /> další položky}many{<ph name="ITEM_COUNT" /> další položky}other{<ph name="ITEM_COUNT" /> dalších položek}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -491,6 +490,7 @@
<translation id="4275830172053184480">Restartovat zařízení</translation>
<translation id="4277028893293644418">Resetovat heslo</translation>
<translation id="4280429058323657511">s platností do <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Přepínač</translation>
<translation id="4312866146174492540">Blokovat (výchozí)</translation>
<translation id="4325863107915753736">Článek nebyl nalezen</translation>
<translation id="4326324639298822553">Zkontrolujte datum vypršení platnosti a zkuste to znovu.</translation>
@@ -498,6 +498,7 @@
<translation id="4340982228985273705">Tento počítač nebyl rozpoznán jako spravovaný organizací, proto lze pomocí zásad automaticky instalovat pouze rozšíření hostovaná v Internetovém obchodě Chrome. Adresa URL Internetového obchodu Chrome pro aktualizace je <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Přijímané kreditní karty</translation>
<translation id="4356973930735388585">Útočníci, kteří se aktuálně nacházejí na tomto webu, se mohou pokusit nainstalovat vám do počítače nebezpečné programy, které mohou ukrást nebo smazat vaše informace (například fotky, hesla, zprávy nebo platební karty).</translation>
+<translation id="4358461427845829800">Spravovat platební metody...</translation>
<translation id="4372948949327679948">Očekávána hodnota <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Pokusili jste se přejít na web <ph name="DOMAIN" />, ale certifikát prezentovaný tímto webem byl vydavatelem certifikátu zrušen. To znamená, že bezpečnostním pověřením, která web prezentoval, nelze zcela důvěřovat. Je možné, že komunikujete s útočníkem.</translation>
<translation id="4406896451731180161">výsledky vyhledávání</translation>
@@ -505,6 +506,7 @@
<translation id="4415426530740016218">Adresa vyzvednutí</translation>
<translation id="4424024547088906515">Server nedokázal prokázat, že patří doméně <ph name="DOMAIN" />. Chrome jeho bezpečnostnímu certifikátu nedůvěřuje. Může to být způsobeno nesprávnou konfigurací nebo tím, že vaše připojení zachytává útočník.</translation>
<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> nepřijal přihlašovací certifikát, případně žádný certifikát nebyl poskytnut.</translation>
+<translation id="4434045419905280838">Vyskakovací okna a přesměrování</translation>
<translation id="443673843213245140">Využití proxy serveru je zakázáno, je však určena explicitní konfigurace proxy serveru.</translation>
<translation id="445100540951337728">Přijímané debetní karty</translation>
<translation id="4506176782989081258">Chyba ověřování: <ph name="VALIDATION_ERROR" />.</translation>
@@ -539,13 +541,13 @@
<translation id="4759118997339041434">Automatické vyplňování informací o platebních kartách je zakázáno</translation>
<translation id="4764776831041365478">Webové stránky na adrese <ph name="URL" /> jsou možná dočasně nedostupné nebo mohly být přemístěny na novou webovou adresu.</translation>
<translation id="4771973620359291008">Došlo k neznámé chybě.</translation>
+<translation id="4785689107224900852">Přejít na tuto kartu</translation>
<translation id="4792143361752574037">Při pokusu o přístup k souborům došlo k chybě. Ukládání na disk je v současné době zakázáno. Chcete-li to zkusit znovu, obnovte stránku.</translation>
<translation id="4800132727771399293">Zkontrolujte datum vypršení platnosti a kód CVC a zkuste to znovu.</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Web <ph name="SITE" /> teď nemůžete navštívit, protože webové stránky odeslaly zakódované identifikační údaje, které Chrome nedokáže zpracovat. Síťové chyby a útoky jsou obvykle dočasné, tato stránka pravděpodobně později bude fungovat.</translation>
<translation id="4813512666221746211">Chyba sítě</translation>
<translation id="4816492930507672669">Přizpůsobit na stránku</translation>
-<translation id="483020001682031208">Nejsou k dispozici žádné stránky fyzického webu, které by bylo možné zobrazit</translation>
<translation id="4850886885716139402">Zobrazit</translation>
<translation id="4854362297993841467">Tento způsob doručení není k dispozici. Zkuste použít jiný způsob.</translation>
<translation id="4858792381671956233">Požádal(a) jsi rodiče o povolení návštěvy tohoto webu.</translation>
@@ -585,6 +587,7 @@
<translation id="5115563688576182185">(64bitový)</translation>
<translation id="5121084798328133320">Po ověření budou údaje o kartě z vašeho účtu Google Payments poskytnuty tomuto webu.</translation>
<translation id="5128122789703661928">Relace s tímto názvem není pro smazání platná.</translation>
+<translation id="5135404736266831032">Spravovat adresy...</translation>
<translation id="5141240743006678641">Šifrovat synchronizovaná hesla pomocí hesla k účtu Google</translation>
<translation id="5145883236150621069">Odpověď zásady obsahuje kód chyby</translation>
<translation id="5159010409087891077">Otevřete stránku v novém anonymním okně (⇧⌘N)</translation>
@@ -596,7 +599,6 @@
<translation id="5201306358585911203">Stránka vložená na této stránce říká</translation>
<translation id="5205222826937269299">Je nutné zadat jméno</translation>
<translation id="5222812217790122047">Je nutné zadat e-mail</translation>
-<translation id="522700295135997067">Tento web vám možná právě odcizil heslo</translation>
<translation id="5230733896359313003">Dodací adresa</translation>
<translation id="5250209940322997802">Připojit k síti</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -640,7 +642,6 @@
<translation id="5492298309214877701">Tato stránka v intranetu společnosti, organizace nebo školy má stejnou adresu URL jako externí web.
<ph name="LINE_BREAK" />
Kontaktujte administrátora systému.</translation>
-<translation id="5499929369096410817">Zadejte bezpečnostní kód pro kartu <ph name="CREDIT_CARD" />. Tento kód se neuloží.</translation>
<translation id="5509780412636533143">Spravované záložky</translation>
<translation id="5510766032865166053">Soubor mohl být přesunut nebo smazán.</translation>
<translation id="5523118979700054094">Název zásady</translation>
@@ -671,9 +672,11 @@ Kontaktujte administrátora systému.</translation>
<translation id="5685654322157854305">Přidat dodací adresu</translation>
<translation id="5689199277474810259">Exportovat do formátu JSON</translation>
<translation id="5689516760719285838">Poloha</translation>
+<translation id="570530837424789914">Spravovat...</translation>
<translation id="5710435578057952990">Identita těchto webových stránek nebyla ověřena.</translation>
<translation id="5719499550583120431">Obchodník přijímá předplacené karty.</translation>
<translation id="5720705177508910913">Aktuální uživatel</translation>
+<translation id="5730040223043577876">Pokud jste heslo použili na jiném webu, doporučujeme vám ho resetovat.</translation>
<translation id="5732392974455271431">Rodiče ti jej mohou odblokovat.</translation>
<translation id="5763042198335101085">Zadejte platnou e-mailovou adresu</translation>
<translation id="5765072501007116331">Chcete-li zobrazit způsoby doručení a požadavky, vyberte adresu</translation>
@@ -697,9 +700,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="5959728338436674663">Automaticky odesílat část <ph name="BEGIN_WHITEPAPER_LINK" />informací o systému a obsahu stránek<ph name="END_WHITEPAPER_LINK" /> do Googlu s cílem pomoci rozpoznávat nebezpečné aplikace a weby. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Úprava kontaktních údajů</translation>
<translation id="5967867314010545767">Odstranit z historie</translation>
-<translation id="5972020793760134803">Přepnout na kartu</translation>
<translation id="5975083100439434680">Oddálit</translation>
-<translation id="597552863672748783">Potvrzení bezpečnostního kódu</translation>
<translation id="598637245381783098">Platební aplikaci nelze otevřít</translation>
<translation id="5989320800837274978">Nejsou určeny pevně dané servery proxy ani adresa URL skriptu PAC.</translation>
<translation id="5990559369517809815">Žádosti na tento server jsou blokovány rozšířením.</translation>
@@ -715,6 +716,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6047927260846328439">Tento obsah by se vás podvodem mohl pokusit přimět k instalaci softwaru nebo odhalení osobních údajů. <ph name="BEGIN_LINK" />Přesto zobrazit<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Web <ph name="SITE" /> teď nemůžete navštívit, protože používá připínání certifikátů. Síťové chyby a útoky jsou obvykle dočasné, tato stránka pravděpodobně později bude fungovat.</translation>
<translation id="6059925163896151826">Zařízení USB</translation>
+<translation id="6071091556643036997">Typ zásady je neplatný.</translation>
<translation id="6080696365213338172">Získali jste přístup k obsahu pomocí certifikátu poskytnutého správcem. Údaje poskytovaná doméně <ph name="DOMAIN" /> bude správce moci zachytit.</translation>
<translation id="610911394827799129">Na stránce <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> mohou být k dispozici další druhy historie prohlížení zaznamenané ve vašem účtu Google.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Žádné}=1{1 heslo (synchronizováno)}few{# hesla (synchronizováno)}many{# hesla (synchronizováno)}other{# hesel (synchronizováno)}}</translation>
@@ -761,6 +763,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6446608382365791566">Přidání dalších informací</translation>
<translation id="6447842834002726250">Soubory cookie</translation>
<translation id="6451458296329894277">Potvrdit nové odeslání formuláře</translation>
+<translation id="6465306955648956876">Spravovat hesla...</translation>
<translation id="647261751007945333">Zásady zařízení</translation>
<translation id="6477321094435799029">Chrome na této stránce zjistil neobvyklý kód a z důvodu ochrany vašich osobních údajů (například hesel, telefonních čísel a platebních karet) ji zablokoval.</translation>
<translation id="6489534406876378309">Začít nahrávat zprávy o selhání</translation>
@@ -780,6 +783,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6628463337424475685">Vyhledávání <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Útočníci, kteří se aktuálně nacházejí na webu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, se mohou pokusit nainstalovat do vašeho počítače Mac nebezpečné programy, které mohou ukrást nebo smazat vaše informace (například fotky, hesla, zprávy nebo platební karty). <ph name="BEGIN_LEARN_MORE_LINK" />Další informace<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Tato zásada se již nepoužívá.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Žádné}=1{Z 1 webu (nebudete odhlášeni z účtu Google)}few{Ze # webů (nebudete odhlášeni z účtu Google)}many{Z # webu (nebudete odhlášeni z účtu Google)}other{Z # webů (nebudete odhlášeni z účtu Google)}}</translation>
<translation id="6657585470893396449">Heslo</translation>
<translation id="6671697161687535275">Odstranit návrh položky formuláře z prohlížeče Chromium?</translation>
<translation id="6685834062052613830">Odhlaste se a dokončete nastavení</translation>
@@ -806,6 +810,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="6915804003454593391">Uživatel:</translation>
<translation id="6945221475159498467">Vybrat</translation>
<translation id="6948701128805548767">Chcete-li zobrazit způsoby vyzvednutí a požadavky, vyberte adresu</translation>
+<translation id="6949872517221025916">Resetovat heslo</translation>
<translation id="6957887021205513506">Zdá se, že certifikát serveru je podvrh.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Zařízení</translation>
@@ -827,7 +832,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7138472120740807366">Způsob doručení</translation>
<translation id="7139724024395191329">Emirát</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> další}few{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> další}many{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> další}other{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> dalších}}</translation>
-<translation id="7155487117670177674">Platba není zabezpečená</translation>
+<translation id="717330890047184534">ID Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> další}few{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> další}many{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> další}other{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> dalších}}</translation>
<translation id="7180611975245234373">Obnovit</translation>
<translation id="7182878459783632708">Nebyly nastaveny žádné zásady</translation>
@@ -876,6 +881,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="7455133967321480974">Použít výchozí globální hodnotu (Blokovat)</translation>
<translation id="7460163899615895653">Zde se zobrazují nedávno otevřené karty z jiných zařízení.</translation>
<translation id="7469372306589899959">Ověřování karty</translation>
+<translation id="7473891865547856676">Ne, děkuji</translation>
<translation id="7481312909269577407">Vpřed</translation>
<translation id="7485870689360869515">Nebyla nalezena žádná data.</translation>
<translation id="7508255263130623398">Vrácené ID zařízení pro zásady je prázdné nebo neodpovídá aktuálnímu ID zařízení</translation>
@@ -898,7 +904,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="7569952961197462199">Odstranit platební kartu z Chromu?</translation>
<translation id="7575800019233204241">Vaše připojení není soukromé nebo &lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt; nebo &lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt; nebo &lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt; nebo Chyba certifikátu SSL</translation>
<translation id="7578104083680115302">Plaťte na webech a v aplikacích v různých zařízeních rychle pomocí karet uložených na Googlu.</translation>
-<translation id="7588950540487816470">Fyzický web</translation>
<translation id="7592362899630581445">Certifikát serveru porušuje omezení názvů domén.</translation>
<translation id="7598391785903975535">Méně než <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Web <ph name="HOST_NAME" /> momentálně tento požadavek nemůže zpracovat.</translation>
@@ -1102,6 +1107,7 @@ Kontaktujte administrátora systému.</translation>
<translation id="9148507642005240123">&amp;Vrátit úpravy zpět</translation>
<translation id="9154194610265714752">Aktualizováno</translation>
<translation id="9157595877708044936">Nastavování...</translation>
+<translation id="9168814207360376865">Povolit webům zjišťovat, zda máte uložené platební metody</translation>
<translation id="9169664750068251925">Blokovat vždy na tomto webu</translation>
<translation id="9170848237812810038">Z&amp;pět</translation>
<translation id="917450738466192189">Certifikát serveru je neplatný.</translation>
@@ -1110,7 +1116,6 @@ Kontaktujte administrátora systému.</translation>
<translation id="9207861905230894330">Přidání článku se nezdařilo.</translation>
<translation id="9215416866750762878">Nějaká aplikace Chromu brání v bezpečném připojení k tomuto webu.</translation>
<translation id="9219103736887031265">Obrázky</translation>
-<translation id="933612690413056017">Připojení k internetu není k dispozici</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">VYMAZAT FORMULÁŘ</translation>
<translation id="939736085109172342">Nová složka</translation>
diff --git a/chromium/components/strings/components_strings_da.xtb b/chromium/components/strings/components_strings_da.xtb
index d23fd2acc46..78b98c00c69 100644
--- a/chromium/components/strings/components_strings_da.xtb
+++ b/chromium/components/strings/components_strings_da.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Vælg tilladelse til <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Seneste bogmærker</translation>
<translation id="1113869188872983271">&amp;Fortryd omarrangering</translation>
+<translation id="1125573121925420732">Advarsler kan almindeligt forekomme, når websites opdaterer deres sikkerhed. Dette forbedres snart.</translation>
<translation id="1126551341858583091">Størrelsen på den lokale lagerplads er <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache for politik er OK</translation>
<translation id="1150979032973867961">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da operativsystemet på din computer ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Tjek, at din internetforbindelse fungerer normalt.&lt;/li&gt;
&lt;li&gt;Kontakt ejeren af websitet.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Du indtastede din adgangskode på et website, der ikke administreres af din organisation. Du kan beskytte din konto ved at undgå at bruge din adgangskode i andre apps og på andre websites.</translation>
<translation id="1263231323834454256">Læseliste</translation>
<translation id="1264126396475825575">Der blev registreret en nedbrudsrapport <ph name="CRASH_TIME" /> (endnu ikke uploadet eller ignoreret)</translation>
<translation id="1270502636509132238">Afhentningsmetode</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Vælg</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Undgå, at denne side opretter yderligere dialogbokse</translation>
-<translation id="1629803312968146339">Skal Chrome gemme dette kort?</translation>
<translation id="1639239467298939599">Indlæser...</translation>
<translation id="1640180200866533862">Brugerpolitikker</translation>
<translation id="1640244768702815859">Prøv at <ph name="BEGIN_LINK" />gå til websitets startside<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prøv at køre Windows Netværksdiagnosticering<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Opdater din adgangssætning til synkronisering.</translation>
<translation id="1787142507584202372">Dine åbne faner vises her</translation>
-<translation id="1789575671122666129">Pop op-vinduer</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kortindehaverens navn</translation>
<translation id="1806541873155184440">Tilføjet <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Genstart computeren</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Ignoreret, da den blev tilsidesat af <ph name="POLICY_NAME" /> .</translation>
-<translation id="2138201775715568214">Leder efter Fysisk web-sider i nærheden</translation>
<translation id="213826338245044447">Bogmærker på mobil</translation>
<translation id="214556005048008348">Annuller betaling</translation>
<translation id="2147827593068025794">Synkronisering i baggrunden</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Politikken blev ikke fundet</translation>
<translation id="2213606439339815911">Indlæg hentes...</translation>
<translation id="2218879909401188352">Hackere, der i øjeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan installere farlige apps, som kan skade din enhed, føje skjulte gebyrer til din mobilregning eller stjæle dine personlige oplysninger. <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Der er ingen internetforbindelse</translation>
<translation id="2230458221926704099">Ret problemerne med din forbindelse ved hjælp af <ph name="BEGIN_LINK" />diagnoseappen<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Send nu</translation>
<translation id="225207911366869382">Denne værdi er forældet for denne politik.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Fjern valgte elementer</translation>
<translation id="277133753123645258">Forsendelsesmetode</translation>
<translation id="277499241957683684">Manglende enhedsregistrering</translation>
+<translation id="2781030394888168909">Eksportér MacOS</translation>
<translation id="2784949926578158345">Forbindelsen blev nulstillet.</translation>
<translation id="2788784517760473862">Accepterede kreditkort</translation>
<translation id="2794233252405721443">Websitet er blokeret</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome kan ikke bekræfte dit kort i øjeblikket. Prøv igen senere.</translation>
<translation id="3064966200440839136">Du forlader inkognitotilstand for at betale via en ekstern applikation. Vil du fortsætte?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ingen}=1{1 adgangskode}one{# adgangskode}other{# adgangskoder}}</translation>
-<translation id="3093245981617870298">Du er offline.</translation>
<translation id="3096100844101284527">Tilføj afhentningsadresse</translation>
<translation id="3105172416063519923">Aktiv-id:</translation>
<translation id="3109728660330352905">Du har ikke tilladelse til at se denne side.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> kan ikke læses i øjeblikket.</translation>
<translation id="3427092606871434483">Tillad (standardindstilling)</translation>
<translation id="3427342743765426898">&amp;Annuller fortryd redigering</translation>
+<translation id="342781501876943858">Chromium anbefaler, at du nulstiller din adgangskode, hvis du har brugt den på andre websites.</translation>
<translation id="3431636764301398940">Gem dette kort på denne enhed</translation>
<translation id="3447661539832366887">Ejeren af denne enhed har lukket dinosaurspillet.</translation>
<translation id="3447884698081792621">Vis certifikat (udstedt af <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Åbn siden i et nyt inkognitovindue (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Nedbrud registreret <ph name="CRASH_TIME" />, uploadet <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certifikatoplysninger</translation>
-<translation id="3690164694835360974">Login er ikke sikkert</translation>
<translation id="3704162925118123524">Det netværk, du bruger, kan kræve, at du går til netværkets loginside.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Indlæser...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Brug globale standardindstillinger (registrer)</translation>
<translation id="4165986682804962316">Indstillinger for website</translation>
-<translation id="4169947484918424451">Skal Chromium gemme dette kort?</translation>
<translation id="4171400957073367226">Ugyldig verifikationssignatur</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> element mere}one{<ph name="ITEM_COUNT" /> element mere}other{<ph name="ITEM_COUNT" /> elementer mere}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Genstart din enhed</translation>
<translation id="4277028893293644418">Nulstil adgangskoden</translation>
<translation id="4280429058323657511">udløber <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Skift</translation>
<translation id="4312866146174492540">Bloker (standardindstilling)</translation>
<translation id="4325863107915753736">Artiklen blev ikke fundet.</translation>
<translation id="4326324639298822553">Kontrollér, om udløbsdatoen er korrekt, og prøv igen.</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Denne computer registreres ikke som virksomhedsadministreret, så politikken kan kun automatisk installere udvidelser, der hostes i Chrome Webshop. Opdateringswebadressen til Chrome Webshop er "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Accepterede kreditkort</translation>
<translation id="4356973930735388585">Hackere på dette website vil muligvis forsøge at installere skadelige programmer på din computer, som stjæler eller sletter dine oplysninger (f.eks. billeder, adgangskoder, beskeder og kreditkortoplysninger).</translation>
+<translation id="4358461427845829800">Administrer betalingsmetoder...</translation>
<translation id="4372948949327679948">Forventet <ph name="VALUE_TYPE" />-værdi.</translation>
<translation id="4377125064752653719">Du har forsøgt at få fat på <ph name="DOMAIN" />, men serverens certifikat er blevet tilbagekaldt af udgiveren. Det betyder, at du bestemt ikke bør have tillid til serverens sikkerhedsoplysninger. Du kommunikerer muligvis med en hacker.</translation>
<translation id="4406896451731180161">søgeresultater</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Afhentningsadresse</translation>
<translation id="4424024547088906515">Denne server kunne ikke bevise, at den er <ph name="DOMAIN" />, da Chrome ikke har tillid til sikkerhedscertifikatet. Dette kan skyldes en fejlkonfiguration, eller at en hacker har opfanget din forbindelse.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> accepterede ikke dit logincertifikat, eller der er ikke angivet et.</translation>
+<translation id="4434045419905280838">Pop op-vinduer og omdirigeringer</translation>
<translation id="443673843213245140">Brug af en proxy er deaktiveret, men en eksplicit proxykonfiguration er angivet.</translation>
<translation id="445100540951337728">Accepterede debetkort</translation>
<translation id="4506176782989081258">Valideringsfejl: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Autofyld af betalingsoplysninger er deaktiveret</translation>
<translation id="4764776831041365478">Websiden på <ph name="URL" /> kan være midlertidigt nede, eller også er den permanent flyttet til en ny webadresse.</translation>
<translation id="4771973620359291008">Der er opstået en ukendt fejl.</translation>
+<translation id="4785689107224900852">Skift til denne fane</translation>
<translation id="4792143361752574037">Der var ikke adgang til sessionsfilerne. Det er i øjeblikket ikke muligt at gemme på disken. Genindlæs siden for at prøve igen.</translation>
<translation id="4800132727771399293">Kontrollér, om din kontrolkode og udløbsdato er korrekte, og prøv igen.</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Du kan ikke gå til <ph name="SITE" /> lige nu, da websitet sendte krypterede legitimationsoplysninger, som Google Chrome ikke kan håndtere. Netværksfejl og angreb er normalt midlertidige, så denne side vil sandsynligvis fungere senere.</translation>
<translation id="4813512666221746211">Netværksfejl</translation>
<translation id="4816492930507672669">Tilpas til siden</translation>
-<translation id="483020001682031208">Der er ingen Fysisk web-sider at vise</translation>
<translation id="4850886885716139402">Vis</translation>
<translation id="4854362297993841467">Denne leveringsmetode er ikke tilgængelig. Prøv en anden metode.</translation>
<translation id="4858792381671956233">Du har spurgt dine forældre, om det er i orden at besøge dette website.</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bit)</translation>
<translation id="5121084798328133320">Når du bekræfter, deles kortoplysningerne på din konto i Google Payments med dette website.</translation>
<translation id="5128122789703661928">Sessionen med dette navn kan ikke slettes.</translation>
+<translation id="5135404736266831032">Administrer adresser...</translation>
<translation id="5141240743006678641">Krypter synkroniserede adgangskoder med dine Google-loginoplysninger</translation>
<translation id="5145883236150621069">Fejlkode til stede i politiksvar</translation>
<translation id="5159010409087891077">Åbn siden i et nyt inkognitovindue (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">En integreret side på denne side siger</translation>
<translation id="5205222826937269299">Navn påkrævet</translation>
<translation id="5222812217790122047">Mail påkrævet</translation>
-<translation id="522700295135997067">Dette website kan have stjålet din adgangskode</translation>
<translation id="5230733896359313003">Leveringsadresse</translation>
<translation id="5250209940322997802">"Opret forbindelse til netværk"</translation>
<translation id="5251803541071282808">Skyen</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Dette website på virksomhedens, organisationens eller skolens intranet har samme webadresse som et eksternt website.
<ph name="LINE_BREAK" />
Prøv at kontakte din systemadministrator.</translation>
-<translation id="5499929369096410817">Angiv sikkerhedskoden for <ph name="CREDIT_CARD" />. Koden gemmes ikke.</translation>
<translation id="5509780412636533143">Administrerede bogmærker</translation>
<translation id="5510766032865166053">Den kan være blevet flyttet eller slettet.</translation>
<translation id="5523118979700054094">Navn på politik</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Tilføj leveringsadresse</translation>
<translation id="5689199277474810259">Eksportér i JSON</translation>
<translation id="5689516760719285838">Placering</translation>
+<translation id="570530837424789914">Administrer...</translation>
<translation id="5710435578057952990">Dette websites identitet er ikke blevet bekræftet.</translation>
<translation id="5719499550583120431">Forudbetalte kort accepteres.</translation>
<translation id="5720705177508910913">Aktuel bruger</translation>
+<translation id="5730040223043577876">Chrome anbefaler, at du nulstiller din adgangskode, hvis du har brugt den på andre websites.</translation>
<translation id="5732392974455271431">Dine forældre kan fjerne blokeringen for dig</translation>
<translation id="5763042198335101085">Angiv en gyldig mailadresse</translation>
<translation id="5765072501007116331">Vælg en adresse for at se leveringsmetoder og -krav</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Send automatisk <ph name="BEGIN_WHITEPAPER_LINK" />nogle systemoplysninger og noget sideindhold<ph name="END_WHITEPAPER_LINK" /> til Google som en hjælp til at registrere skadelige apps og websites. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Rediger kontaktoplysninger</translation>
<translation id="5967867314010545767">Fjern fra historik</translation>
-<translation id="5972020793760134803">Skift til fanen</translation>
<translation id="5975083100439434680">Zoom ud</translation>
-<translation id="597552863672748783">Bekræft sikkerhedskoden</translation>
<translation id="598637245381783098">Betalingsappen kan ikke åbnes</translation>
<translation id="5989320800837274978">Der er hverken angivet faste proxyservere eller en .pac-scriptwebadresse.</translation>
<translation id="5990559369517809815">Anmodninger til serveren er blokeret af en udvidelse.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Dette indhold forsøger muligvis at narre dig til at installere software eller afsløre personlige oplysninger. <ph name="BEGIN_LINK" />Vis alligevel<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Du kan ikke besøge <ph name="SITE" /> lige nu, da websitet bruger certifikatlåsning. Netværksfejl og angreb er normalt midlertidige, så siden vil sandsynligvis fungere igen senere.</translation>
<translation id="6059925163896151826">USB-enheder</translation>
+<translation id="6071091556643036997">Politiktypen er ugyldig.</translation>
<translation id="6080696365213338172">Du har opnår adgang til indhold vha. et administratorcertifikat. De data, du angiver til <ph name="DOMAIN" />, kan indhentes af din administrator.</translation>
<translation id="610911394827799129">Din Google-konto kan have andre former for browserhistorik på <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ingen}=1{1 adgangskode (synkroniseret)}one{# adgangskode (synkroniseret)}other{# adgangskoder (synkroniseret)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Tilføj flere oplysninger</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Bekræft genindsendelse af formular</translation>
+<translation id="6465306955648956876">Administrer adgangskoder...</translation>
<translation id="647261751007945333">Enhedspolitikker</translation>
<translation id="6477321094435799029">Chrome registrerede usædvanlig kode på denne side og blokerede den for at beskytte dine personlige oplysninger (f.eks. adgangskoder, telefonnumre eller kreditkort).</translation>
<translation id="6489534406876378309">Start upload af nedbrud</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> -søgning</translation>
<translation id="6630809736994426279">Brugere med ondsindede hensigter, der i øjeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan forsøge at installere farlige programmer på din Mac, som stjæler eller sletter dine oplysninger (f.eks. fotos, adgangskoder, beskeder og kreditkort). <ph name="BEGIN_LEARN_MORE_LINK" />Få flere oplysninger<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Denne politik er forældet.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ingen}=1{Fra 1 website (du logges ikke ud af din Google-konto)}one{Fra # website (du logges ikke ud af din Google-konto)}other{Fra # websites (du logges ikke ud af din Google-konto)}}</translation>
<translation id="6657585470893396449">Adgangskode</translation>
<translation id="6671697161687535275">Vil du fjerne formularforslag fra Chromium?</translation>
<translation id="6685834062052613830">Log ud, og fuldfør konfigurationen</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Bruger:</translation>
<translation id="6945221475159498467">Vælg</translation>
<translation id="6948701128805548767">Vælg en adresse for at se afhentningsmetoder og -krav</translation>
+<translation id="6949872517221025916">Nulstil adgangskode</translation>
<translation id="6957887021205513506">Serverens certifikat ser ud til at være en forfalskning.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Enhed</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Leveringsmetode</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> anden}one{<ph name="PAYMENT_METHOD_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> anden}other{<ph name="PAYMENT_METHOD_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> andre}}</translation>
-<translation id="7155487117670177674">Betaling er ikke sikkert</translation>
+<translation id="717330890047184534">Gaia-id:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> anden}one{<ph name="SHIPPING_OPTION_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> anden}other{<ph name="SHIPPING_OPTION_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> andre}}</translation>
<translation id="7180611975245234373">Opdater</translation>
<translation id="7182878459783632708">Ingen politikker er indstillet</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Brug global standard (bloker)</translation>
<translation id="7460163899615895653">Dine seneste faner fra andre enheder vises her</translation>
<translation id="7469372306589899959">Bekræfter kort</translation>
+<translation id="7473891865547856676">Nej tak</translation>
<translation id="7481312909269577407">Frem</translation>
<translation id="7485870689360869515">Der blev ikke fundet nogen data.</translation>
<translation id="7508255263130623398">Det returnerede enheds-id for politikken er tomt eller stemmer ikke overens med det nuværende enheds-id</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Vil du fjerne kreditkortet fra Chrome?</translation>
<translation id="7575800019233204241">"Din forbindelse er ikke privat" eller "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" eller "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" eller "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" eller "SSL-certifikatfejl"</translation>
<translation id="7578104083680115302">Betal hurtigt på websites og i apps på alle enheder ved hjælp af kort, du har gemt med Google.</translation>
-<translation id="7588950540487816470">Fysisk web</translation>
<translation id="7592362899630581445">Begrænsningerne for serverens certifikatnavn er overtrådt.</translation>
<translation id="7598391785903975535">Mindre end <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan i øjeblikket ikke behandle denne anmodning.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;Fortryd redigering</translation>
<translation id="9154194610265714752">Opdateret</translation>
<translation id="9157595877708044936">Konfigurerer...</translation>
+<translation id="9168814207360376865">Tillad, at websites tjekker, om du har nogen gemte betalingsmetoder</translation>
<translation id="9169664750068251925">Bloker altid på dette website</translation>
<translation id="9170848237812810038">&amp;Fortryd</translation>
<translation id="917450738466192189">Serverens certifikat er ugyldigt.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Artiklen kunne ikke tilføjes.</translation>
<translation id="9215416866750762878">En app forhindrer Chrome i at oprette sikker forbindelse til dette website</translation>
<translation id="9219103736887031265">Billeder</translation>
-<translation id="933612690413056017">Der er ingen internetforbindelse</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">RYD FORMULAREN</translation>
<translation id="939736085109172342">Ny mappe</translation>
diff --git a/chromium/components/strings/components_strings_de.xtb b/chromium/components/strings/components_strings_de.xtb
index 91c11676086..901826b4e7e 100644
--- a/chromium/components/strings/components_strings_de.xtb
+++ b/chromium/components/strings/components_strings_de.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Berechtigung für <ph name="PERMISSION_NAME" /> auswählen</translation>
<translation id="1111153019813902504">Vor Kurzem aufgerufene Lesezeichen</translation>
<translation id="1113869188872983271">&amp;Neu anordnen rückgängig machen</translation>
+<translation id="1125573121925420732">Wenn die Sicherheitsfunktionen von Websites aktualisiert werden, können Warnungen häufiger auftreten. Dies sollte sich bald verbessern.</translation>
<translation id="1126551341858583091">Die Größe auf dem lokalen Speicher ist <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Richtlinien-Cache einwandfrei</translation>
<translation id="1150979032973867961">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird vom Betriebssystem Ihres Computers als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Prüfen Sie, ob Ihre Internetverbindung richtig funktioniert.&lt;/li&gt;
&lt;li&gt;Wenden Sie sich an den Websiteinhaber.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Sie haben Ihr Passwort auf einer Website eingegeben, die nicht von Ihrer Organisation verwaltet wird. Zum Schutz Ihres Kontos sollten Sie das Passwort nicht für andere Apps und Websites verwenden.</translation>
<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264126396475825575">Absturzbericht erfasst am <ph name="CRASH_TIME" />, wurde noch nicht hochgeladen oder wurde ignoriert</translation>
<translation id="1270502636509132238">Abholoption</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Auswählen</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Keine weiteren Dialogfelder auf dieser Seite zulassen</translation>
-<translation id="1629803312968146339">Möchten Sie, dass Chrome diese Karte speichert?</translation>
<translation id="1639239467298939599">Wird geladen...</translation>
<translation id="1640180200866533862">Nutzerrichtlinien</translation>
<translation id="1640244768702815859">Versuchen Sie, <ph name="BEGIN_LINK" />die Startseite aufzurufen<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Versuchen Sie, die Windows-Netzwerkdiagnose auszuführen.<ph name="END_LINK" /></translation>
<translation id="1783075131180517613">Synchronisierungs-Passphrase aktualisieren</translation>
<translation id="1787142507584202372">Hier werden Ihre offenen Tabs angezeigt</translation>
-<translation id="1789575671122666129">Pop-ups</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Name des Karteninhabers</translation>
<translation id="1806541873155184440">Hinzugefügt: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Computer neu starten</translation>
<translation id="2113977810652731515">Karte</translation>
<translation id="2114841414352855701">Wird ignoriert, da sie von <ph name="POLICY_NAME" /> außer Kraft gesetzt wurde.</translation>
-<translation id="2138201775715568214">Nach Physical Web-Seiten zu Objekten in der Nähe wird gesucht.</translation>
<translation id="213826338245044447">Mobile Lesezeichen</translation>
<translation id="214556005048008348">Zahlung abbrechen</translation>
<translation id="2147827593068025794">Hintergrundsynchronisierung</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Richtlinie nicht gefunden</translation>
<translation id="2213606439339815911">Einträge werden abgerufen...</translation>
<translation id="2218879909401188352">Angreifer auf der Website <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> könnten gefährliche Apps installieren, die Ihr Gerät beschädigen, Ihrer Mobilfunkrechnung versteckte Kosten hinzufügen oder Ihre personenbezogenen Daten stehlen könnten. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Kein Internet</translation>
<translation id="2230458221926704099">Beheben Sie den Verbindungsfehler mithilfe der <ph name="BEGIN_LINK" />Diagnose-App<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Jetzt senden</translation>
<translation id="225207911366869382">Dieser Wert für die Richtlinie ist veraltet.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Ausgewählte Einträge entfernen</translation>
<translation id="277133753123645258">Versandart</translation>
<translation id="277499241957683684">Fehlender Gerätedatensatz</translation>
+<translation id="2781030394888168909">Im Mac OS-Format exportieren</translation>
<translation id="2784949926578158345">Verbindung wurde zurückgesetzt.</translation>
<translation id="2788784517760473862">Akzeptierte Kreditkarten</translation>
<translation id="2794233252405721443">Website blockiert</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Ihre Karte kann von Chrome zurzeit nicht bestätigt werden. Bitte versuchen Sie es später noch einmal.</translation>
<translation id="3064966200440839136">Der Inkognitomodus wird beendet, um über eine externe Anwendung zu zahlen. Fortfahren?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Keine}=1{1 Passwort}other{# Passwörter}}</translation>
-<translation id="3093245981617870298">Sie sind offline</translation>
<translation id="3096100844101284527">Abholadresse hinzufügen</translation>
<translation id="3105172416063519923">Geräte-ID:</translation>
<translation id="3109728660330352905">Sie sind nicht zum Aufrufen dieser Seite autorisiert.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ist momentan nicht erreichbar.</translation>
<translation id="3427092606871434483">Zulassen (Standardeinstellung)</translation>
<translation id="3427342743765426898">&amp;Bearbeiten wiederholen</translation>
+<translation id="342781501876943858">Chromium empfiehlt, Ihr Passwort zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
<translation id="3431636764301398940">Diese Karte für dieses Gerät speichern</translation>
<translation id="3447661539832366887">Der Besitzer dieses Geräts hat das Dinosaurier-Spiel deaktiviert.</translation>
<translation id="3447884698081792621">Zertifikat anzeigen (ausgestellt von <ph name="ISSUER" />)</translation>
@@ -397,7 +398,6 @@
<translation id="3678529606614285348">Seite in einem neuen Inkognitofenster öffnen (Strg + Umschalttaste + N)</translation>
<translation id="3679803492151881375">Absturz am <ph name="CRASH_TIME" /> erfasst und am <ph name="UPLOAD_TIME" /> hochgeladen</translation>
<translation id="3681007416295224113">Zertifikatinformationen</translation>
-<translation id="3690164694835360974">Log-in nicht sicher</translation>
<translation id="3704162925118123524">Eventuell müssen Sie die Anmeldeseite des verwendeten Netzwerks aufrufen.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Wird geladen...</translation>
@@ -457,7 +457,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Globalen Standard verwenden (Erkennen)</translation>
<translation id="4165986682804962316">Website-Einstellungen</translation>
-<translation id="4169947484918424451">Möchten Sie, dass Chromium diese Karte speichert?</translation>
<translation id="4171400957073367226">Ungültige Bestätigungssignatur</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> weiteres Element}other{<ph name="ITEM_COUNT" /> weitere Elemente}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
@@ -487,13 +486,14 @@
<translation id="4235360514405112390">Gültig</translation>
<translation id="4250431568374086873">Die Verbindung zu dieser Website ist nicht uneingeschränkt sicher</translation>
<translation id="4250680216510889253">Nein</translation>
-<translation id="425582637250725228">Die von Ihnen vorgenommenen Änderungen werden möglicherweise nicht gespeichert.</translation>
+<translation id="425582637250725228">Ihre Änderungen werden eventuell nicht gespeichert.</translation>
<translation id="4258748452823770588">Fehlerhafte Signatur</translation>
<translation id="4265872034478892965">Von Ihrem Administrator zugelassen</translation>
<translation id="4269787794583293679">(Kein Nutzername)</translation>
<translation id="4275830172053184480">Gerät neu starten</translation>
<translation id="4277028893293644418">Passwort zurücksetzen</translation>
<translation id="4280429058323657511">Gültig bis: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Wechseln</translation>
<translation id="4312866146174492540">Blockieren (Standardeinstellung)</translation>
<translation id="4325863107915753736">Der Artikel wurde nicht gefunden.</translation>
<translation id="4326324639298822553">Prüfen Sie Ihr Ablaufdatum und versuchen Sie es dann erneut</translation>
@@ -501,6 +501,7 @@
<translation id="4340982228985273705">Dieser Computer wird nicht als von einem Unternehmen verwaltet erkannt, sodass nur Erweiterungen, die im Chrome Web Store gehostet sind, automatisch durch die Richtlinie installiert werden können. Die Update-URL des Chrome Web Store lautet "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Akzeptierte Kreditkarten</translation>
<translation id="4356973930735388585">Unbefugte Dritte auf dieser Website versuchen unter Umständen, gefährliche Programme auf Ihrem Computer zu installieren, um Ihre Daten zu stehlen oder zu löschen, zum Beispiel Fotos, Passwörter, Nachrichten und Kreditkartendaten.</translation>
+<translation id="4358461427845829800">Zahlungsmethoden verwalten…</translation>
<translation id="4372948949327679948">Erwarteter <ph name="VALUE_TYPE" />-Wert</translation>
<translation id="4377125064752653719">Sie haben versucht, auf <ph name="DOMAIN" /> zuzugreifen, das vom Server übermittelte Zertifikat wurde jedoch vom entsprechenden Aussteller widerrufen. Das bedeutet, dass die vom Server übermittelten Sicherheitsinformationen nicht vertrauenswürdig sind. Möglicherweise kommunizieren Sie mit einem Hacker.</translation>
<translation id="4406896451731180161">Suchergebnisse</translation>
@@ -508,6 +509,7 @@
<translation id="4415426530740016218">Abholadresse</translation>
<translation id="4424024547088906515">Dieser Server konnte nicht beweisen, dass er <ph name="DOMAIN" /> ist. Sein Sicherheitszertifikat wird von Chrome als nicht vertrauenswürdig eingestuft. Mögliche Gründe sind eine fehlerhafte Konfiguration oder ein Angreifer, der Ihre Verbindung abfängt.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> hat Ihr Anmeldezertifikat nicht akzeptiert oder es wurde keines bereitgestellt.</translation>
+<translation id="4434045419905280838">Pop-ups und Weiterleitungen</translation>
<translation id="443673843213245140">Die Proxy-Nutzung ist deaktiviert, es ist jedoch eine explizite Proxy-Konfiguration festgelegt.</translation>
<translation id="445100540951337728">Akzeptierte Debitkarten</translation>
<translation id="4506176782989081258">Fehler bei der Überprüfung: <ph name="VALIDATION_ERROR" /></translation>
@@ -542,13 +544,13 @@
<translation id="4759118997339041434">AutoFill für Zahlung deaktiviert</translation>
<translation id="4764776831041365478">Die Webseite unter <ph name="URL" /> ist möglicherweise vorübergehend nicht verfügbar oder wurde dauerhaft an eine neue Webadresse verschoben.</translation>
<translation id="4771973620359291008">Ein unbekannter Fehler ist aufgetreten.</translation>
+<translation id="4785689107224900852">Zu diesem Tab wechseln</translation>
<translation id="4792143361752574037">Beim Zugreifen auf die Sitzungsdateien ist ein Problem aufgetreten. Momentan können keine Dateien auf der Festplatte gespeichert werden. Bitte laden Sie die Seite neu und versuchen Sie es noch einmal.</translation>
<translation id="4800132727771399293">Prüfen Sie Ihr Ablaufdatum und Ihren CVC und versuchen Sie es dann erneut.</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, da die Website verschlüsselte Anmeldedaten gesendet hat, die von Google Chrome nicht verarbeitet werden können. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="4813512666221746211">Netzwerkfehler</translation>
<translation id="4816492930507672669">An Seite anpassen</translation>
-<translation id="483020001682031208">Keine Physical Web-Seiten verfügbar</translation>
<translation id="4850886885716139402">Anzeigen</translation>
<translation id="4854362297993841467">Diese Lieferoption ist nicht verfügbar. Bitte wählen Sie eine andere Option aus.</translation>
<translation id="4858792381671956233">Du hast deine Eltern gefragt, ob du diese Website besuchen darfst</translation>
@@ -588,6 +590,7 @@
<translation id="5115563688576182185">(64-Bit)</translation>
<translation id="5121084798328133320">Nach erfolgter Bestätigung werden die Kartendetails Ihres Google Payments-Kontos an diese Website weitergegeben.</translation>
<translation id="5128122789703661928">Die Sitzung mit diesem Namen kann nicht gelöscht werden.</translation>
+<translation id="5135404736266831032">Adressen verwalten…</translation>
<translation id="5141240743006678641">Synchronisierte Passwörter mit Ihren Google-Anmeldeinformationen verschlüsseln</translation>
<translation id="5145883236150621069">Fehlercode in der Richtlinienantwort</translation>
<translation id="5159010409087891077">Seite in einem neuen Inkognitofenster öffnen (⇧⌘N)</translation>
@@ -599,7 +602,6 @@
<translation id="5201306358585911203">Auf einer in dieser Seite eingebetteten Seite wird Folgendes angezeigt</translation>
<translation id="5205222826937269299">Name erforderlich</translation>
<translation id="5222812217790122047">E-Mail-Adresse erforderlich</translation>
-<translation id="522700295135997067">Diese Website hat möglicherweise gerade Ihr Passwort gestohlen</translation>
<translation id="5230733896359313003">Versandadresse</translation>
<translation id="5250209940322997802">"Mit Netzwerk verbinden"</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -643,7 +645,6 @@
<translation id="5492298309214877701">Diese Website im Intranet des Unternehmens, der Organisation oder der Schule hat die gleiche URL wie eine externe Website.
<ph name="LINE_BREAK" />
Wenden Sie sich an Ihren Systemadministrator.</translation>
-<translation id="5499929369096410817">Geben Sie den Sicherheitscode für <ph name="CREDIT_CARD" /> ein. Dieser Code wird nicht gespeichert.</translation>
<translation id="5509780412636533143">Verwaltete Lesezeichen</translation>
<translation id="5510766032865166053">Möglicherweise wurde sie verschoben oder gelöscht.</translation>
<translation id="5523118979700054094">Richtlinienname</translation>
@@ -674,9 +675,11 @@
<translation id="5685654322157854305">Versandadresse hinzufügen</translation>
<translation id="5689199277474810259">Als JSON exportieren</translation>
<translation id="5689516760719285838">Ort</translation>
+<translation id="570530837424789914">Verwalten…</translation>
<translation id="5710435578057952990">Die Identität dieser Website wurde nicht verifiziert.</translation>
<translation id="5719499550583120431">Prepaidkarten werden akzeptiert.</translation>
<translation id="5720705177508910913">Aktueller Nutzer</translation>
+<translation id="5730040223043577876">Chrome empfiehlt, Ihr Passwort zurückzusetzen, wenn Sie es auf anderen Websites verwendet haben.</translation>
<translation id="5732392974455271431">Deine Eltern können die Blockierung aufheben</translation>
<translation id="5763042198335101085">Geben Sie eine gültige E-Mail-Adresse ein</translation>
<translation id="5765072501007116331">Wählen Sie eine Adresse aus, um Lieferoptionen und -anforderungen zu sehen</translation>
@@ -700,9 +703,7 @@
<translation id="5959728338436674663"><ph name="BEGIN_WHITEPAPER_LINK" />Ich möchte automatisch einige Systeminformationen und Seiteninhalte an Google senden<ph name="END_WHITEPAPER_LINK" />, um bei der Erfassung schädlicher Apps und Websites zu helfen. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Kontaktdaten bearbeiten</translation>
<translation id="5967867314010545767">Aus Verlauf entfernen</translation>
-<translation id="5972020793760134803">Zu folgendem Tab wechseln:</translation>
<translation id="5975083100439434680">Verkleinern</translation>
-<translation id="597552863672748783">Sicherheitscode bestätigen</translation>
<translation id="598637245381783098">Fehler beim Öffnen der Zahlungs-App</translation>
<translation id="5989320800837274978">Weder feste Proxyserver noch eine PAC-Skript-URL sind festgelegt.</translation>
<translation id="5990559369517809815">Anfragen an den Server wurden durch eine Erweiterung blockiert.</translation>
@@ -718,6 +719,7 @@
<translation id="6047927260846328439">Mit diesen Inhalten wird möglicherweise versucht, Sie zu täuschen und so zur Installation von Software oder der Offenlegung personenbezogener Daten zu bringen. <ph name="BEGIN_LINK" />Trotzdem anzeigen<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Sie können <ph name="SITE" /> zurzeit nicht aufrufen, weil die Website das Zertifikats-Pinning nutzt. Netzwerkfehler und Angriffe sind in der Regel nur vorübergehend, sodass die Seite wahrscheinlich später wieder funktioniert.</translation>
<translation id="6059925163896151826">USB-Geräte</translation>
+<translation id="6071091556643036997">Der Richtlinientyp ist ungültig.</translation>
<translation id="6080696365213338172">Sie haben über ein vom Administrator bereitgestelltes Zertifikat auf Inhalte zugegriffen. Die Daten, die Sie innerhalb von <ph name="DOMAIN" /> bereitstellen, können von Ihrem Administrator abgefangen werden.</translation>
<translation id="610911394827799129">Möglicherweise verfügt Ihr Google-Konto unter <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> über andere Browserverläufe.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Keine}=1{1 Passwort (synchronisiert)}other{# Passwörter (synchronisiert)}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">Weitere Informationen hinzufügen</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Erneute Formular-Übermittlung bestätigen</translation>
+<translation id="6465306955648956876">Passwörter verwalten…</translation>
<translation id="647261751007945333">Geräterichtlinien</translation>
<translation id="6477321094435799029">Chrome hat auf dieser Seite ungewöhnlichen Code erfasst und diese Seite daher blockiert, um Ihre personenbezogenen Daten wie Passwörter, Telefonnummern oder Kreditkarteninformationen zu schützen.</translation>
<translation id="6489534406876378309">Hochladen von Abstürzen starten</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" />-Suche</translation>
<translation id="6630809736994426279">Zurzeit auf <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> befindliche Hacker könnten versuchen, gefährliche Programme auf Ihrem Mac zu installieren, um Daten wie Fotos, Passwörter, Nachrichten und Kreditkartendaten zu stehlen oder zu löschen. <ph name="BEGIN_LEARN_MORE_LINK" />Weitere Informationen<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Diese Richtlinie ist veraltet.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Keine}=1{1 Website (Anmeldung in Google-Konto bleibt erhalten)}other{# Websites (Anmeldung in Google-Konto bleibt erhalten)}}</translation>
<translation id="6657585470893396449">Passwort</translation>
<translation id="6671697161687535275">Vorschlag für das Formular aus Chromium entfernen?</translation>
<translation id="6685834062052613830">Abmelden und Einrichtung abschließen</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">Nutzer:</translation>
<translation id="6945221475159498467">Auswählen</translation>
<translation id="6948701128805548767">Wählen Sie eine Adresse aus, um Abholoptionen und -anforderungen zu sehen</translation>
+<translation id="6949872517221025916">Passwort zurücksetzen</translation>
<translation id="6957887021205513506">Das Zertifikat des Servers ist möglicherweise eine Fälschung.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Gerät</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">Lieferoption</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> weitere}other{<ph name="PAYMENT_METHOD_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> weitere}}</translation>
-<translation id="7155487117670177674">Zahlung nicht sicher</translation>
+<translation id="717330890047184534">GAIA-ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> weitere}other{<ph name="SHIPPING_OPTION_PREVIEW" /> und <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> weitere}}</translation>
<translation id="7180611975245234373">Aktualisieren</translation>
<translation id="7182878459783632708">Keine Richtlinien festgelegt</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">Globalen Standard verwenden (Blockieren)</translation>
<translation id="7460163899615895653">Ihre zuletzt geöffneten Tabs von anderen Geräten erscheinen hier</translation>
<translation id="7469372306589899959">Karte wird bestätigt</translation>
+<translation id="7473891865547856676">Nein danke</translation>
<translation id="7481312909269577407">Vorwärts</translation>
<translation id="7485870689360869515">Keine Daten gefunden</translation>
<translation id="7508255263130623398">Zurückgegebene Geräte-ID der Richtlinie ist leer oder entspricht nicht der aktuellen Geräte-ID</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Kreditkarte aus Chrome entfernen?</translation>
<translation id="7575800019233204241">"Dies ist keine sichere Verbindung", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" oder "SSL-Zertifikatfehler"</translation>
<translation id="7578104083680115302">Mit Karten, die Sie bei Google gespeichert haben, können Sie schnell und geräteübergreifend auf Websites und in Apps bezahlen.</translation>
-<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Das Serverzertifikat verstößt gegen Namensbeschränkungen.</translation>
<translation id="7598391785903975535">Weniger als <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kann diese Anfrage momentan nicht verarbeiten.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;Bearbeiten rückgängig machen</translation>
<translation id="9154194610265714752">Aktualisiert</translation>
<translation id="9157595877708044936">Einrichtung läuft...</translation>
+<translation id="9168814207360376865">Ermöglicht Websites zu überprüfen, ob Sie eine Zahlungsmethode gespeichert haben</translation>
<translation id="9169664750068251925">Auf dieser Website immer blockieren</translation>
<translation id="9170848237812810038">&amp;Rückgängig</translation>
<translation id="917450738466192189">Das Serverzertifikat ist ungültig.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Der Artikel konnte nicht hinzugefügt werden.</translation>
<translation id="9215416866750762878">Eine Anwendung verhindert, dass Chrome eine sichere Internetverbindung zu dieser Website herstellt</translation>
<translation id="9219103736887031265">Bilder</translation>
-<translation id="933612690413056017">Keine Internetverbindung</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">Formular leeren</translation>
<translation id="939736085109172342">Neuer Ordner</translation>
diff --git a/chromium/components/strings/components_strings_el.xtb b/chromium/components/strings/components_strings_el.xtb
index 2ee18ac5a42..4b100738e36 100644
--- a/chromium/components/strings/components_strings_el.xtb
+++ b/chromium/components/strings/components_strings_el.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Επιλέξτε άδεια για <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Πρόσφατοι σελιδοδείκτες</translation>
<translation id="1113869188872983271">&amp;Αναίρεση αναδιάταξης</translation>
+<translation id="1125573121925420732">Οι προειδοποιήσεις μπορεί να είναι συνήθεις ενώ οι ιστότοποι ενημερώνουν την ασφάλειά τους. Αυτό αναμένεται να βελτιωθεί σύντομα.</translation>
<translation id="1126551341858583091">Το μέγεθος του τοπικού αποθηκευτικού χώρου είναι <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Η προσωρινή μνήμη της πολιτικής είναι εντάξει</translation>
<translation id="1150979032973867961">Ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωρείται έμπιστο από το λειτουργικό σύστημα της συσκευής σας. Αυτό μπορεί να οφείλεται σε λανθασμένη ρύθμιση ή σε κάποιον τρίτο που επιτίθεται στη σύνδεσή σας.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Βεβαιωθείτε ότι η σύνδεσή σας στο διαδίκτυο λειτουργεί κανονικά.&lt;/li&gt;
&lt;li&gt;Επικοινωνήστε με τον κάτοχο του ιστοτόπου.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Έχετε εισαγάγει τον κωδικό πρόσβασής σας σε έναν ιστότοπο τον οποίο δεν διαχειρίζεται ο οργανισμός σας. Για να προστατεύσετε τον λογαριασμό σας, μην χρησιμοποιήσετε ξανά αυτόν τον κωδικό πρόσβασης σε άλλες εφαρμογές και ιστοτόπους.</translation>
<translation id="1263231323834454256">Λίστα ανάγνωσης</translation>
<translation id="1264126396475825575">Καταγράφηκαν αναφορές σφαλμάτων <ph name="CRASH_TIME" /> (δεν έχουν ακόμη μεταφορτωθεί ή παραβλεφθεί)</translation>
<translation id="1270502636509132238">Τρόπος παραλαβής</translation>
@@ -63,7 +65,7 @@
<ph name="BEGIN_LIST" />
<ph name="LIST_ITEM" />Στους ιστοτόπους που επισκέπτεστε
<ph name="LIST_ITEM" />Στον εργοδότη ή στο σχολείο σας
- <ph name="LIST_ITEM" />Στον παροχέα υπηρεσιών διαδικτύου σας
+ <ph name="LIST_ITEM" />Στον πάροχο υπηρεσιών διαδικτύου σας
<ph name="END_LIST" /></translation>
<translation id="1339601241726513588">Τομέας εγγραφής:</translation>
<translation id="1340482604681802745">Διεύθυνση παραλαβής</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Επιλογή</translation>
<translation id="1620510694547887537">Κάμερα</translation>
<translation id="1623104350909869708">Αποτροπή δημιουργίας πρόσθετων παραθύρων διαλόγου από αυτήν τη σελίδα</translation>
-<translation id="1629803312968146339">Θέλετε το Chrome να αποθηκεύσει αυτήν την κάρτα;</translation>
<translation id="1639239467298939599">Γίνεται φόρτωση</translation>
<translation id="1640180200866533862">Πολιτικές χρηστών</translation>
<translation id="1640244768702815859">Δοκιμάστε να <ph name="BEGIN_LINK" />επισκεφτείτε την αρχική σελίδα του ιστότοπου<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Δοκιμάστε να εκτελέσετε τον Διαγνωστικό έλεγχο δικτύου των Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Ενημερώστε την κωδική φράση πρόσβασης συγχρονισμού.</translation>
<translation id="1787142507584202372">Οι ανοιχτές καρτέλες σας εμφανίζονται εδώ</translation>
-<translation id="1789575671122666129">Αναδυόμενα παράθυρα</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Όνομα κατόχου κάρτας</translation>
<translation id="1806541873155184440">Προστέθηκε <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Επανεκκινήστε τον υπολογιστή σας</translation>
<translation id="2113977810652731515">Παιχνίδια με κάρτες</translation>
<translation id="2114841414352855701">Αγνοήθηκε επειδή αντικαταστάθηκε από την πολιτική <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Αναζήτηση κοντινών σελίδων Φυσικού δικτύου</translation>
<translation id="213826338245044447">Σελιδοδείκτες κινητής συσκευής</translation>
<translation id="214556005048008348">Ακύρωση πληρωμής</translation>
<translation id="2147827593068025794">Συγχρονισμός παρασκηνίου</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Η πολιτική δε βρέθηκε</translation>
<translation id="2213606439339815911">Ανάκτηση καταχωρίσεων…</translation>
<translation id="2218879909401188352">Οι εισβολείς στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> θα μπορούσαν να εγκαταστήσουν επικίνδυνες εφαρμογές που προκαλούν ζημιά στη συσκευή σας, να προσθέσουν κρυφές χρεώσεις στον λογαριασμό του κινητού σας ή να κλέψουν τα προσωπικά στοιχεία σας. <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε περισσότερα<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Χωρίς σύνδεση στο διαδίκτυο</translation>
<translation id="2230458221926704099">Επιδιορθώστε τη σύνδεσή σας χρησιμοποιώντας την <ph name="BEGIN_LINK" />εφαρμογή διαγνωστικών ελέγχων<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Αποστολή τώρα</translation>
<translation id="225207911366869382">Αυτή η πολιτική έχει καταργηθεί για τη συγκεκριμένη πολιτική.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Κατάργηση επιλεγμένων στοιχείων</translation>
<translation id="277133753123645258">Τρόπος αποστολής</translation>
<translation id="277499241957683684">Λείπει κάποιο αρχείο συσκευής</translation>
+<translation id="2781030394888168909">Εξαγωγή για MacOS</translation>
<translation id="2784949926578158345">Έγινε επαναφορά της σύνδεσης.</translation>
<translation id="2788784517760473862">Αποδεκτές πιστωτικές κάρτες</translation>
<translation id="2794233252405721443">Ο ιστότοπος έχει αποκλειστεί</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Δεν ήταν δυνατή η επιβεβαίωση της κάρτας σας από το Chrome αυτήν τη στιγμή. Δοκιμάστε ξανά αργότερα.</translation>
<translation id="3064966200440839136">Αποχώρηση από την κατάσταση ανώνυμης περιήγησης για πληρωμή μέσω εξωτερικής εφαρμογής. Συνέχεια;</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Κανένας}=1{1 κωδικός πρόσβασης}other{# κωδικοί πρόσβασης}}</translation>
-<translation id="3093245981617870298">Είστε εκτός σύνδεσης.</translation>
<translation id="3096100844101284527">Προσθήκη διεύθυνσης παραλαβής</translation>
<translation id="3105172416063519923">Αναγνωριστικό στοιχείο:</translation>
<translation id="3109728660330352905">Δεν έχετε εξουσιοδότηση για την προβολή αυτής της σελίδας.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Προς το παρόν, δεν είναι δυνατή η πρόσβαση στον κεντρικό υπολογιστή <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Να επιτρέπεται (προεπιλογή)</translation>
<translation id="3427342743765426898">&amp;Επανάληψη επεξεργασίας</translation>
+<translation id="342781501876943858">Το Chromium συνιστά την επαναφορά του κωδικού πρόσβασης, εάν τον έχετε χρησιμοποιήσει και σε άλλους ιστοτόπους.</translation>
<translation id="3431636764301398940">Αποθήκευση αυτής της κάρτας στη συγκεκριμένη συσκευή</translation>
<translation id="3447661539832366887">Ο κάτοχος αυτής της συσκευής απενεργοποίησε το παιχνίδι με τους δεινοσαύρους.</translation>
<translation id="3447884698081792621">Εμφάνιση πιστοποιητικού (εκδόθηκε από <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Ανοίξτε τη σελίδα σε ένα νέο παράθυρο ανώνυμης περιήγησης (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Η αναφορά σφαλμάτων καταγράφηκε στις <ph name="CRASH_TIME" /> και μεταφορτώθηκε στις <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Πληροφορίες πιστοποιητικού</translation>
-<translation id="3690164694835360974">Μη ασφαλής σύνδεση</translation>
<translation id="3704162925118123524">Το δίκτυο που χρησιμοποιείτε ενδέχεται να σας ζητήσει να επισκεφτείτε τη σελίδα σύνδεσης του.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Φόρτωση...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Χρήση καθολικής προεπιλογής (Εντοπισμός)</translation>
<translation id="4165986682804962316">Ρυθμίσεις ιστότοπου</translation>
-<translation id="4169947484918424451">Θέλετε το Chromium να αποθηκεύσει αυτήν την κάρτα;</translation>
<translation id="4171400957073367226">Εσφαλμένη υπογραφή επαλήθευσης</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> ακόμη στοιχείο}other{<ph name="ITEM_COUNT" /> ακόμη στοιχεία}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -496,6 +495,7 @@
<translation id="4275830172053184480">Επανεκκινήστε τη συσκευή σας</translation>
<translation id="4277028893293644418">Επαναφορά κωδικού πρόσβασης</translation>
<translation id="4280429058323657511">, λήξη <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Εναλλαγή</translation>
<translation id="4312866146174492540">Αποκλεισμός (προεπιλογή)</translation>
<translation id="4325863107915753736">Αποτυχία εύρεσης άρθρου</translation>
<translation id="4326324639298822553">Ελέγξτε την ημερομηνία λήξης σας και δοκιμάστε ξανά</translation>
@@ -503,6 +503,7 @@
<translation id="4340982228985273705">Αυτός ο υπολογιστής δεν έχει εντοπιστεί ως διαχειριζόμενος από επιχείρηση. Συνεπώς, η πολιτική μπορεί να εγκαθιστά αυτόματα μόνο επεκτάσεις οι οποίες φιλοξενούνται στο Chrome Webstore. Το URL ενημέρωσης του Chrome Webstore είναι το "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Αποδεκτές πιστωτικές κάρτες</translation>
<translation id="4356973930735388585">Οι εισβολείς σε αυτόν τον ιστότοπο μπορεί να επιχειρήσουν να εγκαταστήσουν επικίνδυνα προγράμματα στον υπολογιστή σας, τα οποία μπορούν να υποκλέψουν ή να διαγράψουν τα δεδομένα σας (για παράδειγμα, φωτογραφίες, κωδικούς πρόσβασης, μηνύματα και στοιχεία πιστωτικών καρτών).</translation>
+<translation id="4358461427845829800">Διαχείριση τρόπων πληρωμής…</translation>
<translation id="4372948949327679948">Αναμενόμενη τιμή <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Προσπαθήσατε να μεταβείτε στον τομέα <ph name="DOMAIN" />, όμως το πιστοποιητικό που παρουσιάστηκε από το διακομιστή ανακλήθηκε από τον εκδότη του. Αυτό σημαίνει ότι τα διαπιστευτήρια ασφαλείας που παρουσιάστηκαν από το διακομιστή δεν πρέπει σε καμία περίπτωση να θεωρηθούν αξιόπιστα. Ενδέχεται να επικοινωνείτε με κάποιον εισβολέα.</translation>
<translation id="4406896451731180161">αποτελέσματα αναζήτησης</translation>
@@ -510,6 +511,7 @@
<translation id="4415426530740016218">Διεύθυνση παραλαβής</translation>
<translation id="4424024547088906515">Ο διακομιστής δεν μπόρεσε να αποδείξει ότι είναι <ph name="DOMAIN" />. Το πιστοποιητικό ασφαλείας του δεν θεωρείται έμπιστο από τον Chrome. Αυτό μπορεί να οφείλεται σε λανθασμένη ρύθμιση ή σε κάποιον τρίτο που επιτίθεται στη σύνδεσή σας.</translation>
<translation id="4432688616882109544">Ο κεντρικός υπολογιστής <ph name="HOST_NAME" /> δεν αποδέχτηκε το πιστοποιητικό σύνδεσής σας ή μπορεί να μην διατέθηκε πιστοποιητικό σύνδεσης.</translation>
+<translation id="4434045419905280838">Αναδυόμενα παράθυρα και ανακατευθύνσεις</translation>
<translation id="443673843213245140">Η χρήση ενός διακομιστή μεσολάβησης είναι απενεργοποιημένη, αλλά έχει καθοριστεί μια ρητή διαμόρφωση διακομιστή μεσολάβησης.</translation>
<translation id="445100540951337728">Αποδεκτές χρεωστικές κάρτες</translation>
<translation id="4506176782989081258">Σφάλμα επικύρωσης: <ph name="VALIDATION_ERROR" /></translation>
@@ -544,13 +546,13 @@
<translation id="4759118997339041434">Η αυτόματη συμπλήρωση στοιχείων πληρωμής είναι απενεργοποιημένη</translation>
<translation id="4764776831041365478">Η ιστοσελίδα στη διεύθυνση <ph name="URL" /> μπορεί να βρίσκεται προσωρινά εκτός λειτουργίας ή ίσως έχει μεταφερθεί μόνιμα σε νέα διεύθυνση ιστού.</translation>
<translation id="4771973620359291008">Παρουσιάστηκε άγνωστο σφάλμα.</translation>
+<translation id="4785689107224900852">Εναλλαγή σε αυτήν την καρτέλα</translation>
<translation id="4792143361752574037">Παρουσιάστηκε κάποιο πρόβλημα κατά την πρόσβαση στα αρχεία περιόδου λειτουργίας. Η αποθήκευση στον δίσκο είναι προς το παρόν απενεργοποιημένη. Επαναλάβετε τη φόρτωση της σελίδας για να δοκιμάσετε ξανά.</translation>
<translation id="4800132727771399293">Ελέγξτε την ημερομηνία λήξης και τον κωδικό σας CVC και δοκιμάστε ξανά</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Δεν μπορείτε να επισκεφτείτε το <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος έστειλε κωδικοποιημένα διαπιστευτήρια τα οποία δεν μπορεί να επεξεργαστεί το Google Chrome. Τα σφάλματα δικτύου και οι επιθέσεις είναι συνήθως προσωρινά, συνεπώς αυτή η σελίδα πιθανότατα θα λειτουργήσει αργότερα.</translation>
<translation id="4813512666221746211">Σφάλμα δικτύου</translation>
<translation id="4816492930507672669">Προσαρμογή στη σελίδα</translation>
-<translation id="483020001682031208">Δεν υπάρχουν σελίδες του Φυσικού δικτύου για εμφάνιση</translation>
<translation id="4850886885716139402">Προβολή</translation>
<translation id="4854362297993841467">Αυτός ο τρόπος παράδοσης δεν είναι διαθέσιμος. Δοκιμάστε έναν άλλο τρόπο.</translation>
<translation id="4858792381671956233">Ρώτησες τους γονείς σου εάν σου επιτρέπουν να επισκεφτείς αυτόν τον ιστότοπο</translation>
@@ -590,6 +592,7 @@
<translation id="5115563688576182185">(64-bit)</translation>
<translation id="5121084798328133320">Μετά την επιβεβαίωση, τα στοιχεία της κάρτας από τον λογαριασμό πληρωμών Google θα κοινοποιηθούν σε αυτόν τον ιστότοπο.</translation>
<translation id="5128122789703661928">Η περίοδος σύνδεσης με αυτό το όνομα δεν είναι έγκυρη για διαγραφή.</translation>
+<translation id="5135404736266831032">Διαχείριση διευθύνσεων…</translation>
<translation id="5141240743006678641">Κρυπτογραφήστε συγχρονισμένους κωδικούς πρόσβασης με τα διαπιστευτήριά σας Google.</translation>
<translation id="5145883236150621069">Βρέθηκε κωδικός σφάλματος στην απόκριση πολιτικής</translation>
<translation id="5159010409087891077">Ανοίξτε τη σελίδα σε ένα νέο παράθυρο ανώνυμης περιήγησης (⇧⌘N)</translation>
@@ -601,7 +604,6 @@
<translation id="5201306358585911203">Μια ενσωματωμένη σελίδα σε αυτήν τη σελίδα λέει</translation>
<translation id="5205222826937269299">Απαιτείται όνομα</translation>
<translation id="5222812217790122047">Απαιτείται διεύθυνση ηλεκτρονικού ταχυδρομείου</translation>
-<translation id="522700295135997067">Αυτός ο ιστότοπος μπορεί να έχει υποκλέψει τον κωδικό πρόσβασής σας</translation>
<translation id="5230733896359313003">Διεύθυνση αποστολής</translation>
<translation id="5250209940322997802">"Σύνδεση σε δίκτυο"</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -645,7 +647,6 @@
<translation id="5492298309214877701">Αυτός ο ιστότοπος που βρίσκεται στο εσωτερικό δίκτυο της εταιρείας, του οργανισμού ή του σχολείου έχει το ίδιο URL με έναν εξωτερικό ιστότοπο.
<ph name="LINE_BREAK" />
Δοκιμάστε να επικοινωνήσετε με το διαχειριστή δικτύου σας.</translation>
-<translation id="5499929369096410817">Εισαγάγετε τον κωδικό ασφαλείας για την πιστωτική κάρτα <ph name="CREDIT_CARD" />. Αυτός ο κωδικός δεν θα αποθηκευτεί.</translation>
<translation id="5509780412636533143">Διαχειριζόμενοι σελιδοδείκτες</translation>
<translation id="5510766032865166053">Ενδέχεται να έχει μετακινηθεί ή να έχει διαγραφεί.</translation>
<translation id="5523118979700054094">Όνομα πολιτικής</translation>
@@ -676,9 +677,11 @@
<translation id="5685654322157854305">Προσθήκη διεύθυνσης αποστολής</translation>
<translation id="5689199277474810259">Εξαγωγή σε JSON</translation>
<translation id="5689516760719285838">Τοποθεσία</translation>
+<translation id="570530837424789914">Διαχείριση…</translation>
<translation id="5710435578057952990">Η ταυτότητα αυτού του ιστότοπου δεν έχει επαληθευτεί.</translation>
<translation id="5719499550583120431">Οι προπληρωμένες κάρτες γίνονται δεκτές.</translation>
<translation id="5720705177508910913">Τρέχων χρήστης</translation>
+<translation id="5730040223043577876">Το Chrome συνιστά την επαναφορά του κωδικού πρόσβασης, εάν τον έχετε χρησιμοποιήσει και σε άλλους ιστοτόπους.</translation>
<translation id="5732392974455271431">Οι γονείς σου μπορούν να καταργήσουν τον αποκλεισμό του</translation>
<translation id="5763042198335101085">Εισαγάγετε μια έγκυρη διεύθυνση ηλεκτρονικού ταχυδρομείου</translation>
<translation id="5765072501007116331">Για να δείτε τρόπους και απαιτήσεις παράδοσης, επιλέξτε μια διεύθυνση</translation>
@@ -702,9 +705,7 @@
<translation id="5959728338436674663">Αυτόματη αποστολή ορισμένων <ph name="BEGIN_WHITEPAPER_LINK" />πληροφοριών συστήματος και περιεχομένου σελίδων<ph name="END_WHITEPAPER_LINK" /> στην Google για διευκόλυνση του εντοπισμού επικίνδυνων εφαρμογών και ιστοτόπων<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Επεξεργασία στοιχείων επικοινωνίας</translation>
<translation id="5967867314010545767">Κατάργηση από το ιστορικό</translation>
-<translation id="5972020793760134803">Εναλλαγή σε καρτέλα</translation>
<translation id="5975083100439434680">Σμίκρυνση</translation>
-<translation id="597552863672748783">Επιβεβαίωση κωδικού ασφαλείας</translation>
<translation id="598637245381783098">Δεν είναι δυνατό το άνοιγμα της εφαρμογής πληρωμής</translation>
<translation id="5989320800837274978">Δεν προσδιορίζονται ούτε οι σταθεροί διακομιστές μεσολάβησης ούτε μια διεύθυνση URL σεναρίου .pac.</translation>
<translation id="5990559369517809815">Τα αιτήματα για τον διακομιστή έχουν αποκλειστεί από μια επέκταση.</translation>
@@ -720,6 +721,7 @@
<translation id="6047927260846328439">Αυτό το περιεχόμενο μπορεί να προσπαθήσει να σας εξαπατήσει έτσι ώστε να εγκαταστήσετε λογισμικό ή να αποκαλύψετε προσωπικά στοιχεία. <ph name="BEGIN_LINK" />Εμφάνιση ούτως ή άλλως<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Δεν μπορείτε να επισκεφτείτε το <ph name="SITE" /> αυτήν τη στιγμή επειδή ο ιστότοπος χρησιμοποιεί certificate pinning (κλείδωμα πιστοποιητικών). Τα σφάλματα δικτύου και οι επιθέσεις είναι συνήθως προσωρινά, συνεπώς αυτή η σελίδα πιθανότατα θα λειτουργήσει αργότερα.</translation>
<translation id="6059925163896151826">Συσκευές USB</translation>
+<translation id="6071091556643036997">Ο τύπος πολιτικής δεν είναι έγκυρος.</translation>
<translation id="6080696365213338172">Η πρόσβασή σας στο περιεχόμενο πραγματοποιήθηκε με τη χρήση ενός πιστοποιητικού που παρασχέθηκε από διαχειριστή. Τα δεδομένα που παρέχετε στο <ph name="DOMAIN" /> μπορεί να ελέγχονται από το διαχειριστή σας.</translation>
<translation id="610911394827799129">Ο Λογαριασμός Google ενδέχεται να διαθέτει άλλες μορφές ιστορικού περιήγησης στη διεύθυνση <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Κανένας}=1{1 κωδικός πρόσβασης (συγχρονισμένος)}other{# κωδικοί πρόσβασης (συγχρονισμένοι)}}</translation>
@@ -767,6 +769,7 @@
<translation id="6446608382365791566">Προσθήκη περισσότερων πληροφοριών</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Επιβεβαίωση νέας υποβολής φόρμας</translation>
+<translation id="6465306955648956876">Διαχείριση κωδικών πρόσβασης…</translation>
<translation id="647261751007945333">Πολιτικές συσκευών </translation>
<translation id="6477321094435799029">Το Chrome εντόπισε ασυνήθιστο κώδικα σε αυτήν τη σελίδα και τον απέκλεισε για να προστατεύσει τα προσωπικά σας στοιχεία (για παράδειγμα, κωδικούς πρόσβασης, αριθμούς τηλεφώνου ή πιστωτικές κάρτες).</translation>
<translation id="6489534406876378309">Έναρξη μεταφόρτωσης σφαλμάτων</translation>
@@ -786,6 +789,7 @@
<translation id="6628463337424475685">Αναζήτηση <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Οι εισβολείς που βρίσκονται αυτήν τη στιγμή στον ιστότοπο <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ενδέχεται να επιχειρήσουν να εγκαταστήσουν επικίνδυνα προγράμματα στον υπολογιστή σας Mac, για να υποκλέψουν ή να διαγράψουν τα δεδομένα σας (για παράδειγμα, φωτογραφίες, κωδικούς πρόσβασης, μηνύματα και πιστωτικές κάρτες). <ph name="BEGIN_LEARN_MORE_LINK" />Μάθετε περισσότερα<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Αυτή η πολιτική έχει αποσυρθεί.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Κανένας}=1{Από 1 ιστότοπο (δεν θα αποσυνδεθείτε από τον Λογαριασμό σας Google)}other{Από # ιστοτόπους (δεν θα αποσυνδεθείτε από τον Λογαριασμό σας Google)}}</translation>
<translation id="6657585470893396449">Κωδικός πρόσβασης</translation>
<translation id="6671697161687535275">Να καταργηθεί η πρόταση φόρμας από το Chromium;</translation>
<translation id="6685834062052613830">Αποσυνδεθείτε και ολοκληρώστε την εγκατάσταση</translation>
@@ -812,6 +816,7 @@
<translation id="6915804003454593391">Χρήστης</translation>
<translation id="6945221475159498467">Επιλογή</translation>
<translation id="6948701128805548767">Για να δείτε τρόπους και απαιτήσεις παραλαβής, επιλέξτε μια διεύθυνση</translation>
+<translation id="6949872517221025916">Επαναφορά κωδικού πρόσβασης</translation>
<translation id="6957887021205513506">Το πιστοποιητικό του διακομιστή φαίνεται να είναι πλαστό.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Συσκευή</translation>
@@ -833,7 +838,7 @@
<translation id="7138472120740807366">Μέθοδος προβολής</translation>
<translation id="7139724024395191329">Εμιράτο</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ακόμη}other{<ph name="PAYMENT_METHOD_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ακόμη}}</translation>
-<translation id="7155487117670177674">Μη ασφαλής πληρωμή</translation>
+<translation id="717330890047184534">Αναγνωριστικό Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ακόμη}other{<ph name="SHIPPING_OPTION_PREVIEW" /> και <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ακόμη}}</translation>
<translation id="7180611975245234373">Ανανέωση</translation>
<translation id="7182878459783632708">Δεν έχουν οριστεί πολιτικές</translation>
@@ -882,6 +887,7 @@
<translation id="7455133967321480974">Χρήση καθολικής προεπιλεγμένης ρύθμισης (Αποκλεισμός)</translation>
<translation id="7460163899615895653">Οι πρόσφατες καρτέλες σας από άλλες συσκευές εμφανίζονται εδώ</translation>
<translation id="7469372306589899959">Επιβεβαίωση κάρτας</translation>
+<translation id="7473891865547856676">Όχι, ευχαριστώ</translation>
<translation id="7481312909269577407">Προώθηση</translation>
<translation id="7485870689360869515">Δεν βρέθηκαν δεδομένα</translation>
<translation id="7508255263130623398">Η εμφανιζόμενη συσκευή πολιτικής είναι κενή ή δεν αντιστοιχεί στο τρέχον αναγνωριστικό συσκευής</translation>
@@ -904,7 +910,6 @@
<translation id="7569952961197462199">Κατάργηση πιστωτικής κάρτας από το Chrome;</translation>
<translation id="7575800019233204241">"Η σύνδεσή σας δεν είναι ιδιωτική" ή "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" ή "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" ή "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" ή "Σφάλμα πιστοποιητικού SSL"</translation>
<translation id="7578104083680115302">Κάντε γρήγορες πληρωμές σε ιστότοπους και εφαρμογές σε διαφορετικές συσκευές χρησιμοποιώντας κάρτες που έχετε αποθηκεύσει στο Google.</translation>
-<translation id="7588950540487816470">Φυσικό δίκτυο</translation>
<translation id="7592362899630581445">Το πιστοποιητικό του διακομιστή παραβαίνει τους περιορισμούς ονόματος.</translation>
<translation id="7598391785903975535">Λιγότερο από <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Αυτήν τη στιγμή, ο κεντρικός υπολογιστής <ph name="HOST_NAME" /> δεν μπορεί να διαχειριστεί αυτό το αίτημα.</translation>
@@ -1108,6 +1113,7 @@
<translation id="9148507642005240123">&amp;Αναίρεση επεξεργασίας</translation>
<translation id="9154194610265714752">Ενημερώθηκε</translation>
<translation id="9157595877708044936">Ρύθμιση...</translation>
+<translation id="9168814207360376865">Να επιτρέπεται σε ιστοτόπους να ελέγχουν αν έχετε αποθηκεύσει τρόπους πληρωμής</translation>
<translation id="9169664750068251925">Να γίνεται πάντα αποκλεισμός σε αυτόν τον ιστότοπο</translation>
<translation id="9170848237812810038">Αναί&amp;ρεση</translation>
<translation id="917450738466192189">Το πιστοποιητικό του διακομιστή δεν είναι έγκυρο.</translation>
@@ -1116,7 +1122,6 @@
<translation id="9207861905230894330">Αποτυχία προσθήκης άρθρου.</translation>
<translation id="9215416866750762878">Μια εφαρμογή παρεμποδίζει την ασφαλή σύνδεση του Chrome σε αυτόν τον ιστότοπο</translation>
<translation id="9219103736887031265">Εικόνες</translation>
-<translation id="933612690413056017">Δεν υπάρχει σύνδεση στο διαδίκτυο</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ΔΙΑΓΡΑΦΗ ΦΟΡΜΑΣ</translation>
<translation id="939736085109172342">Νέος φάκελος</translation>
diff --git a/chromium/components/strings/components_strings_en-GB.xtb b/chromium/components/strings/components_strings_en-GB.xtb
index 86a45609c86..df604897e69 100644
--- a/chromium/components/strings/components_strings_en-GB.xtb
+++ b/chromium/components/strings/components_strings_en-GB.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Select permission for <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Recent bookmarks</translation>
<translation id="1113869188872983271">&amp;Undo reorder</translation>
+<translation id="1125573121925420732">Warnings may be common while websites update their security. This should improve soon.</translation>
<translation id="1126551341858583091">The size on the local storage is <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Policy cache OK</translation>
<translation id="1150979032973867961">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by your computer's operating system. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Make sure that your Internet connection is working normally.&lt;/li&gt;
&lt;li&gt;Contact the website owner.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">You entered your password on a site that’s not managed by your organisation. To protect your account, don’t reuse your password on other apps and sites.</translation>
<translation id="1263231323834454256">Reading list</translation>
<translation id="1264126396475825575">Crash report captured on <ph name="CRASH_TIME" /> (not yet uploaded or ignored)</translation>
<translation id="1270502636509132238">Pickup Method</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Choose</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1623104350909869708">Prevent this page from creating additional dialogues</translation>
-<translation id="1629803312968146339">Do you want Chrome to save this card?</translation>
<translation id="1639239467298939599">Loading</translation>
<translation id="1640180200866533862">User policies</translation>
<translation id="1640244768702815859">Try <ph name="BEGIN_LINK" />visiting the site's homepage<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Try running Windows Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Please update your sync passphrase.</translation>
<translation id="1787142507584202372">Your open tabs appear here</translation>
-<translation id="1789575671122666129">Popups</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Cardholder Name</translation>
<translation id="1806541873155184440">Added <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Restart your computer</translation>
<translation id="2113977810652731515">Card</translation>
<translation id="2114841414352855701">Ignored because it was overridden by <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Looking for nearby Physical Web pages</translation>
<translation id="213826338245044447">Mobile Bookmarks</translation>
<translation id="214556005048008348">Cancel payment</translation>
<translation id="2147827593068025794">Background Sync</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Policy not found</translation>
<translation id="2213606439339815911">Fetching entries...</translation>
<translation id="2218879909401188352">Attackers currently on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> could install dangerous apps that damage your device, add hidden charges to your mobile bill or steal your personal information. <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">No Internet</translation>
<translation id="2230458221926704099">Fix your connection using the <ph name="BEGIN_LINK" />diagnostics app<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Send now</translation>
<translation id="225207911366869382">This value is deprecated for this policy.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Remove selected items</translation>
<translation id="277133753123645258">Delivery method</translation>
<translation id="277499241957683684">Missing device record</translation>
+<translation id="2781030394888168909">Export MacOS</translation>
<translation id="2784949926578158345">The connection was reset.</translation>
<translation id="2788784517760473862">Accepted credit cards</translation>
<translation id="2794233252405721443">Site blocked</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome was unable to confirm your card at this time. Please try again later.</translation>
<translation id="3064966200440839136">Leaving incognito mode to pay via an external application. Continue?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{None}=1{1 password}other{# passwords}}</translation>
-<translation id="3093245981617870298">You are offline</translation>
<translation id="3096100844101284527">Add pickup address</translation>
<translation id="3105172416063519923">Asset ID:</translation>
<translation id="3109728660330352905">You don't have authorisation to view this page.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> is currently unreachable.</translation>
<translation id="3427092606871434483">Allow (default)</translation>
<translation id="3427342743765426898">&amp;Redo Edit</translation>
+<translation id="342781501876943858">Chromium recommends resetting your password if you reused it on other sites.</translation>
<translation id="3431636764301398940">Save this card to this device</translation>
<translation id="3447661539832366887">The owner of this device turned off the dinosaur game.</translation>
<translation id="3447884698081792621">Show certificate (issued by <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Open page in a new Incognito window (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Crash report captured on <ph name="CRASH_TIME" />, uploaded on <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certificate information</translation>
-<translation id="3690164694835360974">Login not secure</translation>
<translation id="3704162925118123524">The network that you are using may require you to visit its log-in page.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Loading...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Use global default (Detect)</translation>
<translation id="4165986682804962316">Site settings</translation>
-<translation id="4169947484918424451">Do you want Chromium to save this card?</translation>
<translation id="4171400957073367226">Bad verification signature</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> more item}other{<ph name="ITEM_COUNT" /> more items}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Restart your device</translation>
<translation id="4277028893293644418">Reset password</translation>
<translation id="4280429058323657511">, exp <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Switch</translation>
<translation id="4312866146174492540">Block (default)</translation>
<translation id="4325863107915753736">Failed to find article</translation>
<translation id="4326324639298822553">Check your expiry date and try again</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">This computer is not detected as enterprise managed, so policy can only automatically install extensions hosted on the Chrome Web Store. The Chrome Web Store update URL is '<ph name="CWS_UPDATE_URL" />'.</translation>
<translation id="4346197816712207223">Accepted Credit Cards</translation>
<translation id="4356973930735388585">Attackers on this site might attempt to install dangerous programs on your computer that steal or delete your information (for example, photos, passwords, messages and credit cards).</translation>
+<translation id="4358461427845829800">Manage payment methods...</translation>
<translation id="4372948949327679948">Expected <ph name="VALUE_TYPE" /> value.</translation>
<translation id="4377125064752653719">You attempted to reach <ph name="DOMAIN" />, but the certificate that the server presented has been revoked by its issuer. This means that the security credentials the server presented absolutely should not be trusted. You may be communicating with an attacker.</translation>
<translation id="4406896451731180161">search results</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Pickup Address</translation>
<translation id="4424024547088906515">This server could not prove that it is <ph name="DOMAIN" />; its security certificate is not trusted by Chrome. This may be caused by a misconfiguration or an attacker intercepting your connection.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> didn’t accept your login certificate, or one may not have been provided.</translation>
+<translation id="4434045419905280838">Pop-ups and redirects</translation>
<translation id="443673843213245140">Use of a proxy is disabled but an explicit proxy configuration is specified.</translation>
<translation id="445100540951337728">Accepted debit cards</translation>
<translation id="4506176782989081258">Validation error: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Payment autofilling disabled</translation>
<translation id="4764776831041365478">The web page at <ph name="URL" /> might be temporarily down or it may have moved permanently to a new web address.</translation>
<translation id="4771973620359291008">An unknown error has occurred.</translation>
+<translation id="4785689107224900852">Switch to this tab</translation>
<translation id="4792143361752574037">There was a problem accessing the session files. Saving to disk is currently disabled. Please reload the page to try again.</translation>
<translation id="4800132727771399293">Check your expiration date and CVC and try again</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">You cannot visit <ph name="SITE" /> at the moment because the website sent scrambled credentials that Google Chrome cannot process. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="4813512666221746211">Network error</translation>
<translation id="4816492930507672669">Fit to page</translation>
-<translation id="483020001682031208">No Physical Web pages to show</translation>
<translation id="4850886885716139402">View</translation>
<translation id="4854362297993841467">This delivery method isn’t available. Try a different method.</translation>
<translation id="4858792381671956233">You asked your parents if it's OK to visit this site</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bit)</translation>
<translation id="5121084798328133320">After you confirm, card details from your Google Payments account will be shared with this site.</translation>
<translation id="5128122789703661928">The session with this name is not valid for deletion.</translation>
+<translation id="5135404736266831032">Manage addresses...</translation>
<translation id="5141240743006678641">Encrypt synced passwords with your Google credentials</translation>
<translation id="5145883236150621069">Error code present in the policy response</translation>
<translation id="5159010409087891077">Open page in a new Incognito window (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">An embedded page on this page says</translation>
<translation id="5205222826937269299">Name required</translation>
<translation id="5222812217790122047">Email (required)</translation>
-<translation id="522700295135997067">This site may have just stolen your password</translation>
<translation id="5230733896359313003">Delivery Address</translation>
<translation id="5250209940322997802">'Connect to network'</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">This site on the company, organisation or school intranet has the same URL as an external website.
<ph name="LINE_BREAK" />
Try contacting your system administrator.</translation>
-<translation id="5499929369096410817">Enter the security code for <ph name="CREDIT_CARD" />. This code won't be saved.</translation>
<translation id="5509780412636533143">Managed bookmarks</translation>
<translation id="5510766032865166053">It may have been moved or deleted.</translation>
<translation id="5523118979700054094">Policy name</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Add delivery address</translation>
<translation id="5689199277474810259">Export to JSON</translation>
<translation id="5689516760719285838">Location</translation>
+<translation id="570530837424789914">Manage...</translation>
<translation id="5710435578057952990">The identity of this website has not been verified.</translation>
<translation id="5719499550583120431">Prepaid cards are accepted.</translation>
<translation id="5720705177508910913">Current user</translation>
+<translation id="5730040223043577876">Chrome recommends resetting your password if you reused it on other sites.</translation>
<translation id="5732392974455271431">Your parents can unblock it for you</translation>
<translation id="5763042198335101085">Enter a valid email address</translation>
<translation id="5765072501007116331">To see delivery methods and requirements, select an address</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Automatically send some <ph name="BEGIN_WHITEPAPER_LINK" />system information and page content<ph name="END_WHITEPAPER_LINK" /> to Google to help detect dangerous apps and sites. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edit Contact Info</translation>
<translation id="5967867314010545767">Remove from history</translation>
-<translation id="5972020793760134803">Switch to tab</translation>
<translation id="5975083100439434680">Zoom out</translation>
-<translation id="597552863672748783">Confirm security code</translation>
<translation id="598637245381783098">Can’t open payment app</translation>
<translation id="5989320800837274978">Neither fixed proxy servers nor a .pac script URL are specified.</translation>
<translation id="5990559369517809815">Requests to the server have been blocked by an extension.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">This content might try to trick you into installing software or revealing personal information. <ph name="BEGIN_LINK" />Show anyway<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">You cannot visit <ph name="SITE" /> right now because the website uses certificate pinning. Network errors and attacks are usually temporary, so this page will probably work later.</translation>
<translation id="6059925163896151826">USB devices</translation>
+<translation id="6071091556643036997">The policy type is invalid.</translation>
<translation id="6080696365213338172">You have accessed content using an administrator-provided certificate. Data you provide to <ph name="DOMAIN" /> can be intercepted by your administrator.</translation>
<translation id="610911394827799129">Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{None}=1{1 password (synced)}other{# passwords (synced)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Add more information</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Confirm Form Resubmission</translation>
+<translation id="6465306955648956876">Manage passwords...</translation>
<translation id="647261751007945333">Device policies</translation>
<translation id="6477321094435799029">Chrome detected unusual code on this page and blocked it to protect your personal information (for example, passwords, phone numbers and credit cards).</translation>
<translation id="6489534406876378309">Start uploading crashes</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Search</translation>
<translation id="6630809736994426279">Attackers currently on <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> might attempt to install dangerous programs on your Mac that steal or delete your information (for example, photos, passwords, messages and credit cards). <ph name="BEGIN_LEARN_MORE_LINK" />Learn more<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">This policy has been deprecated.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{None}=1{From 1 site (you won't be signed out of your Google account)}other{From # sites (you won't be signed out of your Google account)}}</translation>
<translation id="6657585470893396449">Password</translation>
<translation id="6671697161687535275">Remove form suggestion from Chromium?</translation>
<translation id="6685834062052613830">Sign out and complete setup</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">User:</translation>
<translation id="6945221475159498467">Select</translation>
<translation id="6948701128805548767">To see pickup methods and requirements, select an address</translation>
+<translation id="6949872517221025916">Reset password</translation>
<translation id="6957887021205513506">The server's certificate appears to be a forgery.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Device</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Delivery method</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> more}other{<ph name="PAYMENT_METHOD_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> more}}</translation>
-<translation id="7155487117670177674">Payment not secure</translation>
+<translation id="717330890047184534">Gaia ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> more}other{<ph name="SHIPPING_OPTION_PREVIEW" /> and <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> more}}</translation>
<translation id="7180611975245234373">Refresh</translation>
<translation id="7182878459783632708">No policies set</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Use global default (Block)</translation>
<translation id="7460163899615895653">Your recent tabs from other devices appear here</translation>
<translation id="7469372306589899959">Confirming card</translation>
+<translation id="7473891865547856676">No Thanks</translation>
<translation id="7481312909269577407">Forward</translation>
<translation id="7485870689360869515">No data found.</translation>
<translation id="7508255263130623398">Returned policy device ID is empty or doesn't match current device ID</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Remove credit card from Chrome?</translation>
<translation id="7575800019233204241">'Your connection is not private' or "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" or "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" or "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" or 'SSL certificate error'</translation>
<translation id="7578104083680115302">Pay quickly on sites and apps across devices using cards that you have saved with Google.</translation>
-<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Server's certificate violates name constraints.</translation>
<translation id="7598391785903975535">Less than <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> is currently unable to handle this request.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Undo edit</translation>
<translation id="9154194610265714752">Updated</translation>
<translation id="9157595877708044936">Setting up...</translation>
+<translation id="9168814207360376865">Allow sites to check if you have payment methods saved</translation>
<translation id="9169664750068251925">Always block on this site</translation>
<translation id="9170848237812810038">&amp;Undo</translation>
<translation id="917450738466192189">Server's certificate is invalid.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Failed to add article.</translation>
<translation id="9215416866750762878">An application is stopping Chrome from safely connecting to this site</translation>
<translation id="9219103736887031265">Images</translation>
-<translation id="933612690413056017">There is no Internet connection</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">CLEAR FORM</translation>
<translation id="939736085109172342">New folder</translation>
diff --git a/chromium/components/strings/components_strings_es-419.xtb b/chromium/components/strings/components_strings_es-419.xtb
index b04f5b75a36..b0e7e8f92e6 100644
--- a/chromium/components/strings/components_strings_es-419.xtb
+++ b/chromium/components/strings/components_strings_es-419.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Selecciona el permiso para <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Favoritos recientes</translation>
<translation id="1113869188872983271">&amp;Deshacer Reorganizar</translation>
+<translation id="1125573121925420732">Las advertencias pueden ser habituales cuando las páginas web actualizan su seguridad. Esto debería mejorar pronto.</translation>
<translation id="1126551341858583091">El tamaño del almacenamiento local es <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="1150979032973867961">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; el sistema operativo de la computadora no confía en el certificado de seguridad. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Comprueba que tu conexión a Internet funcione correctamente.&lt;/li&gt;
&lt;li&gt;Comunícate con el propietario del sitio web.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Ingresaste tu contraseña en un sitio que no administra tu organización. Para proteger tu cuenta, no vuelvas a usar tu contraseña en otras apps y sitios.</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
<translation id="1264126396475825575">El informe de fallos se capturó el <ph name="CRASH_TIME" /> (todavía no se cargó ni se ignoró)</translation>
<translation id="1270502636509132238">Método de retiro</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Seleccionar</translation>
<translation id="1620510694547887537">Cámara</translation>
<translation id="1623104350909869708">Evitar que esta página cree cuadros de diálogo adicionales</translation>
-<translation id="1629803312968146339">¿Quieres que Chrome guarde esta tarjeta?</translation>
<translation id="1639239467298939599">Cargando</translation>
<translation id="1640180200866533862">Políticas de usuario</translation>
<translation id="1640244768702815859">Intenta <ph name="BEGIN_LINK" />visitar la página principal del sitio<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Intenta ejecutar el Diagnóstico de red de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronización.</translation>
<translation id="1787142507584202372">Tus pestañas abiertas aparecen aquí</translation>
-<translation id="1789575671122666129">Ventanas emergentes</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nombre del titular de la tarjeta</translation>
<translation id="1806541873155184440">Agregada: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Reinicia la computadora.</translation>
<translation id="2113977810652731515">Tarjeta</translation>
<translation id="2114841414352855701">Se ignoró porque fue anulada por <ph name="POLICY_NAME" /> .</translation>
-<translation id="2138201775715568214">Buscando páginas web físicas cercanas</translation>
<translation id="213826338245044447">Favoritos del celular</translation>
<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">No se encontró la política.</translation>
<translation id="2213606439339815911">Recuperando entradas…</translation>
<translation id="2218879909401188352">Es posible que los atacantes que se encuentran actualmente en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> instalen apps peligrosas que dañen tu dispositivo, agreguen cargos ocultos en la factura de tu servicio móvil o roben tu información personal. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Sin Internet</translation>
<translation id="2230458221926704099">Corregir la conexión con la <ph name="BEGIN_LINK" />app de diagnóstico<ph name="END_LINK" />.</translation>
<translation id="2239100178324503013">Enviar ahora</translation>
<translation id="225207911366869382">Este valor ya no se utiliza para esta política.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Eliminar elementos seleccionados</translation>
<translation id="277133753123645258">Método de envío</translation>
<translation id="277499241957683684">Falta un registro de dispositivo.</translation>
+<translation id="2781030394888168909">Exportar para Mac OS</translation>
<translation id="2784949926578158345">Se ha restablecido la conexión.</translation>
<translation id="2788784517760473862">Tarjetas de crédito aceptadas</translation>
<translation id="2794233252405721443">Sitio bloqueado</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome no pudo confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
<translation id="3064966200440839136">Saldrás del modo de navegación incógnito para pagar mediante una aplicación externa. ¿Deseas continuar?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ninguna}=1{1 contraseña}other{# contraseñas}}</translation>
-<translation id="3093245981617870298">No estás conectado.</translation>
<translation id="3096100844101284527">Agregar dirección de retiro</translation>
<translation id="3105172416063519923">ID de recurso:</translation>
<translation id="3109728660330352905">No tienes autorización para ver esta página.</translation>
@@ -363,6 +363,7 @@
<translation id="3422472998109090673">No se puede acceder a <ph name="HOST_NAME" /> en este momento.</translation>
<translation id="3427092606871434483">Permitir (predeterminado)</translation>
<translation id="3427342743765426898">&amp;Rehacer Editar</translation>
+<translation id="342781501876943858">Chromium te recomienda que restablezcas tu contraseña si la volviste a usar en otros sitios.</translation>
<translation id="3431636764301398940">Guardar esta tarjeta para este dispositivo</translation>
<translation id="3447661539832366887">El propietario del dispositivo desactivó el juego de dinosaurios.</translation>
<translation id="3447884698081792621">Mostrar certificado (emitido por <ph name="ISSUER" />)</translation>
@@ -399,7 +400,6 @@
<translation id="3678529606614285348">Abre la página en una nueva ventana de incógnito (Ctrl-mayúscula-N).</translation>
<translation id="3679803492151881375">El informe de fallos se capturó el <ph name="CRASH_TIME" /> y se cargó el <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Información sobre el certificado</translation>
-<translation id="3690164694835360974">Acceso no seguro</translation>
<translation id="3704162925118123524">Es posible que la red que estás usando requiera que visites la página de acceso.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Cargando...</translation>
@@ -459,7 +459,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizar opción predeterminada global (detectar)</translation>
<translation id="4165986682804962316">Configuración del sitio</translation>
-<translation id="4169947484918424451">¿Quieres que Chromium guarde esta tarjeta?</translation>
<translation id="4171400957073367226">La firma de verificación no es válida.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> elemento más}other{<ph name="ITEM_COUNT" /> elementos más}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -496,6 +495,7 @@
<translation id="4275830172053184480">Reiniciar tu dispositivo</translation>
<translation id="4277028893293644418">Restablecer contraseña</translation>
<translation id="4280429058323657511">, exp <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Cambiar</translation>
<translation id="4312866146174492540">Bloquear (predeterminado)</translation>
<translation id="4325863107915753736">No se pudo encontrar el artículo</translation>
<translation id="4326324639298822553">Comprueba la fecha de vencimiento y vuelve a intentarlo</translation>
@@ -503,6 +503,7 @@
<translation id="4340982228985273705">Esta computadora no se detectó como una empresa administrada, por lo que la política solo puede instalar automáticamente las extensiones alojadas en Chrome Web Store. La URL de actualización de Chrome Web Store es "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Tarjetas de crédito aceptadas</translation>
<translation id="4356973930735388585">Es posible que los atacantes que se encuentren en este sitio intenten instalar programas peligrosos en tu computadora con el fin de robarte información o borrarla (p. ej., fotos, contraseñas, mensajes y tarjetas de crédito).</translation>
+<translation id="4358461427845829800">Administrar formas de pago…</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperado.</translation>
<translation id="4377125064752653719">Intentaste acceder a <ph name="DOMAIN" />, pero el emisor anuló el certificado que presentó el servidor. Esto significa que no se debe confiar en absoluto en las credenciales de seguridad que presentó el servidor. Te puedes estar comunicando con un atacante.</translation>
<translation id="4406896451731180161">resultados de búsqueda</translation>
@@ -510,6 +511,7 @@
<translation id="4415426530740016218">Dirección de retiro</translation>
<translation id="4424024547088906515">Este servidor no pudo probar que su dominio es <ph name="DOMAIN" />; Chrome no confía en el certificado de seguridad. Es posible que esto se deba a una configuración incorrecta o a que un atacante interceptó la conexión.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no aceptó tu certificado de acceso o es posible que no se haya proporcionado.</translation>
+<translation id="4434045419905280838">Ventanas emergentes y redirec.</translation>
<translation id="443673843213245140">Se inhabilitó el uso de un proxy, pero se especificó una configuración explícita de proxy.</translation>
<translation id="445100540951337728">Tarjetas de débito aceptadas</translation>
<translation id="4506176782989081258">Error de validación: <ph name="VALIDATION_ERROR" /></translation>
@@ -544,13 +546,13 @@
<translation id="4759118997339041434">Se inhabilitó la función Autocompletar en los pagos</translation>
<translation id="4764776831041365478">Es posible que la página web en <ph name="URL" /> no funcione temporalmente o se haya trasladado de manera permanente a una nueva dirección web.</translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
+<translation id="4785689107224900852">Cambiar a esta pestaña</translation>
<translation id="4792143361752574037">Se produjo un error al acceder a los archivos de la sesión. Por el momento, no se pueden guardar en el disco. Vuelve a cargar la página para intentarlo de nuevo.</translation>
<translation id="4800132727771399293">Verifica la fecha de vencimiento y el CVC, y vuelve a intentarlo.</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">No puedes visitar <ph name="SITE" /> ahora porque el sitio web envió credenciales confusas que Google Chrome no puede procesar. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde.</translation>
<translation id="4813512666221746211">Error de red</translation>
<translation id="4816492930507672669">Ajustar a la página</translation>
-<translation id="483020001682031208">No hay páginas web físicas para mostrar</translation>
<translation id="4850886885716139402">Ver</translation>
<translation id="4854362297993841467">Este método de entrega no está disponible. Prueba otro método.</translation>
<translation id="4858792381671956233">Les preguntaste a tus padres si puedes visitar este sitio</translation>
@@ -590,6 +592,7 @@
<translation id="5115563688576182185">(64 bits)</translation>
<translation id="5121084798328133320">Después de que confirmes esta acción, los datos de tu cuenta de Google Payments se compartirán con este sitio.</translation>
<translation id="5128122789703661928">La sesión con este nombre no se puede borrar.</translation>
+<translation id="5135404736266831032">Administrar direcciones…</translation>
<translation id="5141240743006678641">Encriptar contraseñas sincronizadas con tus credenciales de Google</translation>
<translation id="5145883236150621069">Código de error en la respuesta de la política</translation>
<translation id="5159010409087891077">Abre la página en una nueva ventana de incógnito (⇧⌘N).</translation>
@@ -601,7 +604,6 @@
<translation id="5201306358585911203">Una página incorporada en esta página dice</translation>
<translation id="5205222826937269299">Nombre (obligatorio)</translation>
<translation id="5222812217790122047">Correo electrónico (obligatorio)</translation>
-<translation id="522700295135997067">Es posible que este sitio haya robado tu contraseña</translation>
<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5250209940322997802">"Conectarse a una red"</translation>
<translation id="5251803541071282808">Nube</translation>
@@ -645,7 +647,6 @@
<translation id="5492298309214877701">En la intranet de la compañía, organización o escuela, este sitio tiene la misma URL que un sitio web externo
<ph name="LINE_BREAK" />
Intenta contactar al administrador de tu sistema.</translation>
-<translation id="5499929369096410817">Ingresa el código de seguridad de la tarjeta <ph name="CREDIT_CARD" />. Este código no se guardará.</translation>
<translation id="5509780412636533143">Favoritos administrados</translation>
<translation id="5510766032865166053">Es posible que lo hayan movido o borrado.</translation>
<translation id="5523118979700054094">Nombre de la política</translation>
@@ -676,9 +677,11 @@
<translation id="5685654322157854305">Agregar dirección de envío</translation>
<translation id="5689199277474810259">Exportar a JSON</translation>
<translation id="5689516760719285838">Ubicación</translation>
+<translation id="570530837424789914">Administrar…</translation>
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5719499550583120431">Se aceptan tarjetas de prepago.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
+<translation id="5730040223043577876">Chrome te recomienda que restablezcas tu contraseña si la volviste a usar en otros sitios.</translation>
<translation id="5732392974455271431">Tus padres pueden desbloquearlo por ti</translation>
<translation id="5763042198335101085">Escribe una dirección de correo electrónico válida</translation>
<translation id="5765072501007116331">Para ver los requisitos y métodos de entrega, selecciona una dirección</translation>
@@ -702,9 +705,7 @@
<translation id="5959728338436674663">Enviar automáticamente <ph name="BEGIN_WHITEPAPER_LINK" />determinado contenido de la página e información del sistema<ph name="END_WHITEPAPER_LINK" /> a Google para detectar apps y sitios peligrosos <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Editar la información de contacto</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
-<translation id="5972020793760134803">Cambiar a la pestaña</translation>
<translation id="5975083100439434680">Alejar</translation>
-<translation id="597552863672748783">Confirmar código de seguridad</translation>
<translation id="598637245381783098">No se puede abrir la app de pago</translation>
<translation id="5989320800837274978">No se especifican servidores proxy fijos ni URL de secuencias de comandos .pac.</translation>
<translation id="5990559369517809815">Una extensión bloqueó las solicitudes al servidor.</translation>
@@ -720,6 +721,7 @@
<translation id="6047927260846328439">Es posible que este contenido trate de engañarte para que instales software o reveles información personal. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">No puedes visitar <ph name="SITE" /> ahora porque el sitio web usa la fijación de certificados. Los ataques y errores de red suelen ser temporales, por lo que es posible que esta página funcione más tarde.</translation>
<translation id="6059925163896151826">Dispositivos USB</translation>
+<translation id="6071091556643036997">El tipo de política no es válido.</translation>
<translation id="6080696365213338172">Accediste al contenido mediante un certificado proporcionado por el administrador. Los datos que proporciones a <ph name="DOMAIN" /> pueden ser interceptados por tu administrador.</translation>
<translation id="610911394827799129">Es posible que tu cuenta de Google tenga otros formularios del historial de navegación en <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ninguna}=1{1 contraseña (sincronizada)}other{# contraseñas (sincronizadas)}}</translation>
@@ -767,6 +769,7 @@
<translation id="6446608382365791566">Agregar más información</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Confirmar reenvío del formulario</translation>
+<translation id="6465306955648956876">Administrar contraseñas…</translation>
<translation id="647261751007945333">Políticas de dispositivos</translation>
<translation id="6477321094435799029">Chrome detectó código inusual en esta página y la bloqueó para proteger tu información personal (p. ej.: contraseñas, números de teléfono y tarjetas de crédito).</translation>
<translation id="6489534406876378309">Comenzar a cargar fallos</translation>
@@ -786,6 +789,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Búsqueda</translation>
<translation id="6630809736994426279">Es posible que los atacantes que actualmente se encuentran en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten instalar programas peligrosos en tu Mac para robar o borrar información (p. ej., fotos, contraseñas, mensajes y tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Esta política no ha sido aprobada.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ninguno}=1{De 1 sitio (no saldrás de tu cuenta de Google)}other{De # sitios (no saldrás de tu cuenta de Google)}}</translation>
<translation id="6657585470893396449">Contraseña</translation>
<translation id="6671697161687535275">¿Confirmas que quieres quitar la sugerencia de formulario de Chromium?</translation>
<translation id="6685834062052613830">Salir y completar la configuración</translation>
@@ -812,6 +816,7 @@
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6948701128805548767">Para ver los requisitos y métodos de retiro, selecciona una dirección</translation>
+<translation id="6949872517221025916">Restablecer contraseña</translation>
<translation id="6957887021205513506">El certificado del servidor parece falso.</translation>
<translation id="6965382102122355670">Aceptar</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -833,14 +838,14 @@
<translation id="7138472120740807366">Método de entrega</translation>
<translation id="7139724024395191329">Emirato</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> más}other{<ph name="PAYMENT_METHOD_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> más}}</translation>
-<translation id="7155487117670177674">Pago no seguro</translation>
+<translation id="717330890047184534">ID de GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> más}other{<ph name="SHIPPING_OPTION_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> más}}</translation>
<translation id="7180611975245234373">Actualizar</translation>
<translation id="7182878459783632708">No hay políticas establecidas.</translation>
<translation id="7186367841673660872">Esta página se tradujo de<ph name="ORIGINAL_LANGUAGE" />a<ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="7192203810768312527">Esta acción libera hasta <ph name="SIZE" />. Es posible que algunos sitios carguen más lento en tu próxima visita.</translation>
<translation id="719464814642662924">Visa</translation>
-<translation id="7210863904660874423"><ph name="HOST_NAME" /> no cumple con los estándares de seguridad.</translation>
+<translation id="7210863904660874423"><ph name="HOST_NAME" /> no cumple con las normas de seguridad.</translation>
<translation id="721197778055552897"><ph name="BEGIN_LINK" />Más información<ph name="END_LINK" /> acerca de este problema.</translation>
<translation id="7219179957768738017">La conexión usa <ph name="SSL_VERSION" />.</translation>
<translation id="7220786058474068424">Procesando</translation>
@@ -882,6 +887,7 @@
<translation id="7455133967321480974">Usar configuración global predeterminada (Bloquear)</translation>
<translation id="7460163899615895653">Aquí aparecen tus pestañas recientes de otros dispositivos</translation>
<translation id="7469372306589899959">Confirmando la tarjeta</translation>
+<translation id="7473891865547856676">No, gracias</translation>
<translation id="7481312909269577407">Reenviar</translation>
<translation id="7485870689360869515">No se encontró ningún dato.</translation>
<translation id="7508255263130623398">El ID de dispositivo de la política que se muestra está vacío o no coincide con el ID de dispositivo actual</translation>
@@ -904,7 +910,6 @@
<translation id="7569952961197462199">¿Confirmas que quieres quitar la tarjeta de crédito de Chrome?</translation>
<translation id="7575800019233204241">"La conexión no es privada" o "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" o "Error de certificado SSL"</translation>
<translation id="7578104083680115302">Paga con rapidez en sitios y apps a través de varios dispositivos con tarjetas que guardaste en Google.</translation>
-<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">El certificado del servidor no cumple con las restricciones de nombre.</translation>
<translation id="7598391785903975535">Menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> no puede procesar esta solicitud en este momento.</translation>
@@ -1108,6 +1113,7 @@
<translation id="9148507642005240123">&amp;Deshacer Editar</translation>
<translation id="9154194610265714752">Actualizado</translation>
<translation id="9157595877708044936">Configurando...</translation>
+<translation id="9168814207360376865">Permitir que los sitios determinen si tienes formas de pago guardadas</translation>
<translation id="9169664750068251925">Bloquear siempre en este sitio</translation>
<translation id="9170848237812810038">&amp;Deshacer</translation>
<translation id="917450738466192189">El certificado del servidor no es válido.</translation>
@@ -1116,7 +1122,6 @@
<translation id="9207861905230894330">Error al agregar artículo</translation>
<translation id="9215416866750762878">Una aplicación impide que Chrome se conecte de forma segura a este sitio</translation>
<translation id="9219103736887031265">Imágenes</translation>
-<translation id="933612690413056017">No hay conexión a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">BORRAR FORMULARIO</translation>
<translation id="939736085109172342">Nueva carpeta</translation>
diff --git a/chromium/components/strings/components_strings_es.xtb b/chromium/components/strings/components_strings_es.xtb
index 18bfa3774bb..746d440b8d9 100644
--- a/chromium/components/strings/components_strings_es.xtb
+++ b/chromium/components/strings/components_strings_es.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Seleccionar permiso de <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Marcadores visitados recientemente</translation>
<translation id="1113869188872983271">&amp;Deshacer reorganización</translation>
+<translation id="1125573121925420732">Es probable que se muestren advertencias mientras se actualiza la seguridad de los sitios web, pero pronto se solucionará.</translation>
<translation id="1126551341858583091">El tamaño del almacenamiento local es de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Caché de política correcta</translation>
<translation id="1150979032973867961">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, el sistema operativo de tu ordenador no confía en su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Comprueba que tu conexión a Internet funcione con normalidad.&lt;/li&gt;
&lt;li&gt;Ponte en contacto con el propietario del sitio web.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Has introducido tu contraseña en un sitio web que no está gestionado por tu organización. Para proteger tu cuenta, no vuelvas a utilizar tu contraseña en otras aplicaciones ni en otros sitios web.</translation>
<translation id="1263231323834454256">Lista de lectura</translation>
<translation id="1264126396475825575">Informe sobre fallos registrado el <ph name="CRASH_TIME" /> (todavía no se ha subido ni ignorado)</translation>
<translation id="1270502636509132238">Método de recogida</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Seleccionar</translation>
<translation id="1620510694547887537">Cámara</translation>
<translation id="1623104350909869708">Evitar que esta página cree cuadros de diálogo adicionales</translation>
-<translation id="1629803312968146339">¿Quieres que Chrome guarde esta tarjeta?</translation>
<translation id="1639239467298939599">Cargando</translation>
<translation id="1640180200866533862">Políticas de usuario</translation>
<translation id="1640244768702815859">Prueba a <ph name="BEGIN_LINK" />acceder a la página principal del sitio web<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prueba a ejecutar Diagnósticos de red de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualiza tu frase de contraseña de sincronización.</translation>
<translation id="1787142507584202372">Las pestañas abiertas aparecen aquí</translation>
-<translation id="1789575671122666129">Ventanas emergentes</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nombre del titular de la tarjeta</translation>
<translation id="1806541873155184440">Añadida el <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Reinicia el ordenador</translation>
<translation id="2113977810652731515">Tarjeta</translation>
<translation id="2114841414352855701">Se ha ignorado la política porque la anula <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Buscando páginas de la Web física cercanas</translation>
<translation id="213826338245044447">Marcadores del móvil</translation>
<translation id="214556005048008348">Cancelar pago</translation>
<translation id="2147827593068025794">Sincronización en segundo plano</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Política no encontrada</translation>
<translation id="2213606439339815911">Recuperando entradas...</translation>
<translation id="2218879909401188352">Se ha detectado la presencia de atacantes en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> que podrían instalar aplicaciones peligrosas que dañen tu dispositivo, añadir cargos ocultos a tu factura del móvil o robar tu información personal. <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Sin conexión a Internet</translation>
<translation id="2230458221926704099">Soluciona los problemas de tu conexión con la <ph name="BEGIN_LINK" />aplicación de diagnóstico<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Enviar ahora</translation>
<translation id="225207911366869382">Este valor ya no se utiliza para esta política.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Eliminar elementos seleccionados</translation>
<translation id="277133753123645258">Método de envío</translation>
<translation id="277499241957683684">Falta un registro de dispositivo.</translation>
+<translation id="2781030394888168909">Exportar para MacOS</translation>
<translation id="2784949926578158345">Se ha restablecido la conexión.</translation>
<translation id="2788784517760473862">Tarjetas de crédito aceptadas</translation>
<translation id="2794233252405721443">Sito web bloqueado</translation>
@@ -298,12 +299,11 @@
<translation id="3010559122411665027">Entrada de lista "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">Bloqueado automáticamente</translation>
<translation id="3024663005179499861">Tipo de política incorrecto</translation>
-<translation id="3037605927509011580">¡Oh, no!</translation>
+<translation id="3037605927509011580">¡Vaya!</translation>
<translation id="3041612393474885105">Datos del certificado</translation>
<translation id="3063697135517575841">Chrome no ha podido confirmar tu tarjeta en este momento. Vuelve a intentarlo más tarde.</translation>
-<translation id="3064966200440839136">Saldrás del modo incógnito para realizar un pago en una aplicación externa. ¿Quieres continuar?</translation>
+<translation id="3064966200440839136">Saldrás del modo de incógnito para realizar un pago en una aplicación externa. ¿Quieres continuar?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ninguna}=1{1 contraseña}other{# contraseñas}}</translation>
-<translation id="3093245981617870298">No tienes conexión.</translation>
<translation id="3096100844101284527">Añadir dirección de recogida</translation>
<translation id="3105172416063519923">ID de recurso:</translation>
<translation id="3109728660330352905">No tienes autorización para ver esta página.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">No se puede acceder a la página <ph name="HOST_NAME" /> en este momento.</translation>
<translation id="3427092606871434483">Permitir (predeterminado)</translation>
<translation id="3427342743765426898">&amp;Rehacer edición</translation>
+<translation id="342781501876943858">Chromium te recomienda que cambies tu contraseña si la has vuelto a utilizar en otros sitios web.</translation>
<translation id="3431636764301398940">Guardar esta tarjeta en el dispositivo</translation>
<translation id="3447661539832366887">El propietario de este dispositivo ha desactivado el juego del dinosaurio.</translation>
<translation id="3447884698081792621">Mostrar certificado (emitido por <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Abre una página en una nueva ventana de incógnito (Ctrl + Mayús + N).</translation>
<translation id="3679803492151881375">Informe sobre fallos registrado el <ph name="CRASH_TIME" /> y subido el <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Datos del certificado</translation>
-<translation id="3690164694835360974">Inicio de sesión no seguro</translation>
<translation id="3704162925118123524">La red que estás utilizando puede requerir el acceso a su página de inicio de sesión.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Cargando...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizar valor predeterminado global (por defecto)</translation>
<translation id="4165986682804962316">Configuración de sitios web</translation>
-<translation id="4169947484918424451">¿Quieres que Chromium guarde esta tarjeta?</translation>
<translation id="4171400957073367226">La firma de verificación no es válida</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> elemento más}other{<ph name="ITEM_COUNT" /> elementos más}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -473,7 +472,7 @@
&lt;li&gt;Accede a cualquier sitio web que empiece por &lt;code&gt;http://&lt;/code&gt;, como &lt;a href="http://example.com" target="_blank"&gt;http://example.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;En la página de inicio de sesión que se abre, inicia sesión para utilizar la conexión a Internet.&lt;/li&gt;
&lt;/ol&gt;
- &lt;h4&gt;Paso 2: Abre la página en modo incógnito (solo en ordenadores)&lt;/h4&gt;
+ &lt;h4&gt;Paso 2: Abre la página en modo de incógnito (solo en ordenadores)&lt;/h4&gt;
&lt;p&gt;Abre la página que estabas visitando en una ventana de incógnito.&lt;/p&gt;
&lt;p&gt;Si la página se abre, significa que una extensión de Chrome no funciona correctamente. Para solucionarlo, desactiva esa extensión.&lt;/p&gt;
&lt;h4&gt;Paso 3: Actualiza tu sistema operativo&lt;/h4&gt;
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Reiniciar tu dispositivo</translation>
<translation id="4277028893293644418">Cambiar contraseña</translation>
<translation id="4280429058323657511">Vcto. <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Cambiar</translation>
<translation id="4312866146174492540">Bloquear (predeterminado)</translation>
<translation id="4325863107915753736">Error al buscar el artículo</translation>
<translation id="4326324639298822553">Consulta la fecha de vencimiento y vuelve a intentarlo</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">No se ha detectado que este ordenador esté administrado por la empresa, por lo que la política solo puede instalar automáticamente extensiones alojadas en Chrome Webstore. La URL de actualización de Chrome Webstore es "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Tarjetas de crédito aceptadas</translation>
<translation id="4356973930735388585">Es posible que los atacantes que se encuentren en este sitio web intenten instalar programas peligrosos en tu ordenador para robar o eliminar tu información (por ejemplo, fotos, contraseñas, mensajes y tarjetas de crédito).</translation>
+<translation id="4358461427845829800">Gestiona tus métodos de pago...</translation>
<translation id="4372948949327679948">Se esperaba un valor <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Has intentado acceder a <ph name="DOMAIN" />, pero el emisor ha revocado el certificado mostrado por el servidor, lo que significa que las credenciales de seguridad presentadas por el servidor no son de confianza. Es posible que hayas accedido a la página de un atacante.</translation>
<translation id="4406896451731180161">resultados de la búsqueda</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Dirección de recogida</translation>
<translation id="4424024547088906515">Este servidor no ha podido probar que su dominio es <ph name="DOMAIN" />, Chrome no confía en su certificado de seguridad. Este problema puede deberse a una configuración incorrecta o a que un atacante haya interceptado la conexión.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> no ha aceptado el certificado de inicio de sesión o es posible que no se haya proporcionado ninguno.</translation>
+<translation id="4434045419905280838">Ventanas emergentes y redirecciones</translation>
<translation id="443673843213245140">Se ha inhabilitado el uso de un servidor proxy, pero se han especificado ajustes de proxy explícitos.</translation>
<translation id="445100540951337728">Tarjetas de débito aceptadas</translation>
<translation id="4506176782989081258">Error de validación: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Opción de autocompletar pagos inhabilitada</translation>
<translation id="4764776831041365478">Es posible que la página web <ph name="URL" /> esté temporalmente inactiva o que se haya trasladado definitivamente a otra dirección.</translation>
<translation id="4771973620359291008">Se ha producido un error desconocido.</translation>
+<translation id="4785689107224900852">Cambiar a esta pestaña</translation>
<translation id="4792143361752574037">No se ha podido acceder a los archivos de la sesión. La opción para guardar contenido en el disco está inhabilitada. Vuelve a cargar la página para intentarlo de nuevo.</translation>
<translation id="4800132727771399293">Comprueba la fecha de caducidad y el código CVC, y vuelve a intentarlo</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web ha enviado credenciales codificadas que Google Chrome no puede procesar. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta página funcione más tarde.</translation>
<translation id="4813512666221746211">Error de red</translation>
<translation id="4816492930507672669">Ajustar a página</translation>
-<translation id="483020001682031208">No hay páginas de la Web física para mostrarse.</translation>
<translation id="4850886885716139402">Ver</translation>
<translation id="4854362297993841467">Este método de entrega no está disponible. Selecciona otro.</translation>
<translation id="4858792381671956233">Has solicitado permiso a tus padres para poder acceder a este sitio web</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bits)</translation>
<translation id="5121084798328133320">Una vez que confirmes esta acción, la información de la tarjeta de tu cuenta de pagos de Google se compartirá con este sitio web.</translation>
<translation id="5128122789703661928">No se puede eliminar la sesión con este nombre.</translation>
+<translation id="5135404736266831032">Gestiona tus direcciones...</translation>
<translation id="5141240743006678641">Cifrar contraseñas sincronizadas con tus credenciales de Google</translation>
<translation id="5145883236150621069">Código de error presente en respuesta de la política</translation>
<translation id="5159010409087891077">Abre una página en una nueva ventana de incógnito (⇧ + ⌘ + N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Una página insertada en esta dice</translation>
<translation id="5205222826937269299">Nombre obligatorio</translation>
<translation id="5222812217790122047">Correo electrónico obligatorio</translation>
-<translation id="522700295135997067">Es posible que este sitio web te acabe de robar la contraseña</translation>
<translation id="5230733896359313003">Dirección de envío</translation>
<translation id="5250209940322997802">"Conectarse a la red"</translation>
<translation id="5251803541071282808">Nube</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Este sitio web de la intranet del centro educativo, de la organización o de la empresa tiene la misma URL que un sitio web externo.
<ph name="LINE_BREAK" />
Ponte en contacto con el administrador del sistema.</translation>
-<translation id="5499929369096410817">Introduce el código de seguridad de la tarjeta <ph name="CREDIT_CARD" />. Este código no se guardará.</translation>
<translation id="5509780412636533143">Marcadores administrados</translation>
<translation id="5510766032865166053">Es posible que se haya movido o eliminado.</translation>
<translation id="5523118979700054094">Nombre de la política</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Añadir dirección de envío</translation>
<translation id="5689199277474810259">Exportar a JSON</translation>
<translation id="5689516760719285838">Ubicación</translation>
+<translation id="570530837424789914">Gestionar...</translation>
<translation id="5710435578057952990">No se ha verificado la identidad de este sitio web.</translation>
<translation id="5719499550583120431">Se aceptan tarjetas prepago.</translation>
<translation id="5720705177508910913">Usuario actual</translation>
+<translation id="5730040223043577876">Chrome te recomienda que cambies tu contraseña si la has vuelto a utilizar en otros sitios web.</translation>
<translation id="5732392974455271431">Tus padres pueden desbloquearlo</translation>
<translation id="5763042198335101085">Introduce una dirección de correo electrónico válida</translation>
<translation id="5765072501007116331">Selecciona una dirección para ver los métodos de entrega y los requisitos</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Enviar automáticamente <ph name="BEGIN_WHITEPAPER_LINK" />información del sistema y contenido de las páginas<ph name="END_WHITEPAPER_LINK" /> a Google para facilitar la detección de aplicaciones y sitios web peligrosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edita la información de contacto</translation>
<translation id="5967867314010545767">Eliminar del historial</translation>
-<translation id="5972020793760134803">Cambia a la pestaña</translation>
<translation id="5975083100439434680">Reducir</translation>
-<translation id="597552863672748783">Confirmar código de seguridad</translation>
<translation id="598637245381783098">No se ha podido abrir la aplicación de pago</translation>
<translation id="5989320800837274978">No se han especificado servidores proxy fijos ni una URL de secuencia de comandos .pac.</translation>
<translation id="5990559369517809815">Una extensión ha bloqueado el envío de solicitudes al servidor.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Es posible que este contenido intente engañarte para que instales software o reveles información personal. <ph name="BEGIN_LINK" />Mostrar de todos modos<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">No puedes acceder a <ph name="SITE" /> en este momento porque el sitio web utiliza la fijación de certificados. Los ataques y los errores de red suelen ser temporales, por lo que es probable que esta página funcione más tarde.</translation>
<translation id="6059925163896151826">Dispositivos USB</translation>
+<translation id="6071091556643036997">El tipo de política no es válido.</translation>
<translation id="6080696365213338172">Has accedido al contenido mediante un certificado proporcionado por el administrador. Los datos que proporciones a <ph name="DOMAIN" /> pueden ser interceptados por tu administrador.</translation>
<translation id="610911394827799129">Es posible que tu cuenta de Google tenga otros tipos de historial de navegación en la página <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ninguna}=1{1 contraseña (sincronizada)}other{# contraseñas (sincronizadas)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Añadir más información</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Confirmar reenvío del formulario</translation>
+<translation id="6465306955648956876">Gestiona tus contraseñas...</translation>
<translation id="647261751007945333">Políticas de dispositivos</translation>
<translation id="6477321094435799029">Chrome ha detectado un código inusual en esta página y lo ha bloqueado para proteger tu información personal (por ejemplo, contraseñas, números de teléfono y tarjetas de crédito).</translation>
<translation id="6489534406876378309">Empezar a subir errores</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Búsqueda de <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Es posible que los atacantes que se encuentren en <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> intenten instalar programas peligrosos en tu Mac para robar o eliminar tu información (por ejemplo, fotos, contraseñas, mensajes y tarjetas de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Más información<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Esta política está obsoleta.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ninguno}=1{De 1 sitio web (no se cerrará la sesión en tu cuenta de Google)}other{De # sitios web (no se cerrará la sesión en tu cuenta de Google)}}</translation>
<translation id="6657585470893396449">Contraseña</translation>
<translation id="6671697161687535275">¿Quitar sugerencia de formulario de Chromium?</translation>
<translation id="6685834062052613830">Cierra sesión y completa la configuración</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Usuario:</translation>
<translation id="6945221475159498467">Seleccionar</translation>
<translation id="6948701128805548767">Selecciona una dirección para ver los métodos de recogida y los requisitos</translation>
+<translation id="6949872517221025916">Cambiar contraseña</translation>
<translation id="6957887021205513506">El certificado del servidor parece ser falso.</translation>
<translation id="6965382102122355670">Aceptar</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Método de entrega</translation>
<translation id="7139724024395191329">Emirato</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> más}other{<ph name="PAYMENT_METHOD_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> más}}</translation>
-<translation id="7155487117670177674">Pago no seguro</translation>
+<translation id="717330890047184534">ID de GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> más}other{<ph name="SHIPPING_OPTION_PREVIEW" /> y <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> más}}</translation>
<translation id="7180611975245234373">Actualizar</translation>
<translation id="7182878459783632708">No hay políticas establecidas.</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Utilizar valor predeterminado global (Bloquear)</translation>
<translation id="7460163899615895653">Las pestañas recientes de otros dispositivos aparecen aquí</translation>
<translation id="7469372306589899959">Confirmando tarjeta</translation>
+<translation id="7473891865547856676">No, gracias</translation>
<translation id="7481312909269577407">Adelante</translation>
<translation id="7485870689360869515">No se han encontrado datos.</translation>
<translation id="7508255263130623398">El ID de dispositivo de política devuelto está vacío o no coincide con el ID de dispositivo actual</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">¿Eliminar tarjeta de crédito de Chrome?</translation>
<translation id="7575800019233204241">"La conexión no es privada" o "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" o "Error de certificado SSL"</translation>
<translation id="7578104083680115302">Paga rápidamente en aplicaciones y sitios web desde tus dispositivos utilizando las tarjetas que has guardado en Google.</translation>
-<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">El certificado del servidor incluye un nombre que está fuera de su cobertura.</translation>
<translation id="7598391785903975535">Menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">La página <ph name="HOST_NAME" /> no puede procesar esta solicitud ahora.</translation>
@@ -948,7 +953,7 @@
<translation id="7815407501681723534">Se han encontrado <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> de <ph name="SEARCH_STRING" /></translation>
<translation id="7818867226424560206">Gestión de políticas</translation>
<translation id="782886543891417279">La red Wi-Fi que estás utilizando (<ph name="WIFI_NAME" />) puede requerir que accedas a su página de inicio de sesión.</translation>
-<translation id="785549533363645510">Ten en cuenta que tus acciones no serán totalmente invisibles. El uso del modo incógnito no te permite ocultar tu actividad de navegación a tu empresa, a tu proveedor de servicios de Internet o a los sitios web que visites.</translation>
+<translation id="785549533363645510">Ten en cuenta que tus acciones no serán totalmente invisibles. El uso del modo de incógnito no te permite ocultar tu actividad de navegación a tu empresa, a tu proveedor de servicios de Internet o a los sitios web que visites.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="7862185352068345852">¿Quieres salir del sitio web?</translation>
<translation id="7878176543348854470">Se aceptan tarjetas prepago y de débito.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Deshacer edición</translation>
<translation id="9154194610265714752">Actualizado</translation>
<translation id="9157595877708044936">Configurando...</translation>
+<translation id="9168814207360376865">Permitir a los sitios web saber si tienes métodos de pago guardados</translation>
<translation id="9169664750068251925">Bloquear siempre en este sitio</translation>
<translation id="9170848237812810038">&amp;Deshacer</translation>
<translation id="917450738466192189">El certificado del servidor no es válido.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Se ha producido un error al añadir el artículo.</translation>
<translation id="9215416866750762878">Hay una aplicación que impide que Chrome se conecte a este sitio web de forma segura</translation>
<translation id="9219103736887031265">Imágenes</translation>
-<translation id="933612690413056017">No hay conexión a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">BORRAR FORMULARIO</translation>
<translation id="939736085109172342">Nueva carpeta</translation>
diff --git a/chromium/components/strings/components_strings_et.xtb b/chromium/components/strings/components_strings_et.xtb
index 40df743fdc7..6cbb8fa70ec 100644
--- a/chromium/components/strings/components_strings_et.xtb
+++ b/chromium/components/strings/components_strings_et.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Valige luba üksuse <ph name="PERMISSION_NAME" /> jaoks</translation>
<translation id="1111153019813902504">Hiljuti kasutatud järjehoidjad</translation>
<translation id="1113869188872983271">&amp;Võta korrastamine tagasi</translation>
+<translation id="1125573121925420732">Sel ajal kui veebisaidid värskendavad turvafunktsioone, võite sageli hoiatusi näha. See olukord peaks varsti lahenema.</translation>
<translation id="1126551341858583091">Kohaliku salvestusruumi maht on <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Reegli vahemälu töötab probleemideta</translation>
<translation id="1150979032973867961">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, arvuti operatsioonisüsteem ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Veenduge, et Interneti-ühendus töötaks tavapäraselt.&lt;/li&gt;
&lt;li&gt;Võtke ühendust veebisaidi omanikuga.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Sisestasite oma parooli saidile, mida ei halda teie organisatsioon. Oma konto kaitsmiseks ärge kasutage oma parooli muudes rakendustes ega saitidel.</translation>
<translation id="1263231323834454256">Lugemisloend</translation>
<translation id="1264126396475825575">Krahhiaruanne talletati <ph name="CRASH_TIME" /> (ei ole veel üles laaditud ega eiratud)</translation>
<translation id="1270502636509132238">Kättesaamisviis</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Vali</translation>
<translation id="1620510694547887537">Kaamera</translation>
<translation id="1623104350909869708">Keela sellel lehel lisadialoogide loomine</translation>
-<translation id="1629803312968146339">Kas soovite, et Chrome salvestaks selle kaardi?</translation>
<translation id="1639239467298939599">Laadimine</translation>
<translation id="1640180200866533862">Kasutajareeglid</translation>
<translation id="1640244768702815859">Proovige <ph name="BEGIN_LINK" />külastada saidi avalehte<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Proovige käitada Windowsi võrgudiagnostika tööriista<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Värskendage sünkroonimise parooli.</translation>
<translation id="1787142507584202372">Teie avatud vahelehed kuvatakse siin</translation>
-<translation id="1789575671122666129">Hüpikaknad</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kaardiomaniku nimi</translation>
<translation id="1806541873155184440">Lisati kuupäeval <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Taaskäivitage oma arvuti</translation>
<translation id="2113977810652731515">Kaart</translation>
<translation id="2114841414352855701">Seda ignoreeritakse, kuna reegel <ph name="POLICY_NAME" /> alistab selle.</translation>
-<translation id="2138201775715568214">Lähedalasuvate füüsilise veebi lehtede otsimine</translation>
<translation id="213826338245044447">Mobiili järjehoidjad</translation>
<translation id="214556005048008348">Tühista makse</translation>
<translation id="2147827593068025794">Taustal sünkroonimine</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Reeglit ei leitud</translation>
<translation id="2213606439339815911">Kirjete toomine ...</translation>
<translation id="2218879909401188352">Saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> olevad ründajad võivad installida ohtlikke rakendusi, mis kahjustavad teie seadet, lisavad mobiiliarvele varjatud kulusid või varastavad teie isiklikke andmeid. <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Interneti-ühendus puudub</translation>
<translation id="2230458221926704099">Parandage oma ühendus <ph name="BEGIN_LINK" />diagnostikarakenduse<ph name="END_LINK" /> abil</translation>
<translation id="2239100178324503013">Saada kohe</translation>
<translation id="225207911366869382">Väärtus on eeskirjade jaoks aegunud.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Eemalda valitud üksused</translation>
<translation id="277133753123645258">Tarneviis</translation>
<translation id="277499241957683684">Seadme kirje puudub</translation>
+<translation id="2781030394888168909">Ekspordi MacOS-i jaoks</translation>
<translation id="2784949926578158345">Ühendus lähtestati.</translation>
<translation id="2788784517760473862">Aktsepteeritavad krediitkaardid</translation>
<translation id="2794233252405721443">Sait on blokeeritud</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome ei saanud praegu teie kaarti kinnitada. Proovige hiljem uuesti.</translation>
<translation id="3064966200440839136">Väljute inkognito režiimist, et välise rakenduse kaudu maksta. Kas soovite jätkata?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ühtegi}=1{1 parool}other{# parooli}}</translation>
-<translation id="3093245981617870298">Olete võrguühenduseta.</translation>
<translation id="3096100844101284527">Lisage kättesaamisaadress</translation>
<translation id="3105172416063519923">Vara ID:</translation>
<translation id="3109728660330352905">Teil pole volitust selle lehe vaatamiseks.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Hostiga <ph name="HOST_NAME" /> ei saa praegu ühendust.</translation>
<translation id="3427092606871434483">Luba (vaikimisi)</translation>
<translation id="3427342743765426898">&amp;Muuda uuesti</translation>
+<translation id="342781501876943858">Chromium soovitab teil parooli lähtestada, kui kasutasite seda ka muudel saitidel.</translation>
<translation id="3431636764301398940">Salvesta kaart sellesse seadmesse</translation>
<translation id="3447661539832366887">Seadme omanik lülitas dinosaurusemängu välja.</translation>
<translation id="3447884698081792621">Kuva sertifikaat (väljastas <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Avage leht uues inkognito aknas (Ctrl + tõstuklahv + N)</translation>
<translation id="3679803492151881375">Krahhiaruanne jäädvustati ajal <ph name="CRASH_TIME" />, see laaditi üles ajal <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikaadi andmed</translation>
-<translation id="3690164694835360974">Sisselogimine pole turvaline</translation>
<translation id="3704162925118123524">Võrk, mida kasutate, võib nõuda sisselogimislehe külastamist.</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laadimine...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Kasuta üldist vaikevalikut (tuvasta)</translation>
<translation id="4165986682804962316">Saidi seaded</translation>
-<translation id="4169947484918424451">Kas soovite, et Chromium salvestaks selle kaardi?</translation>
<translation id="4171400957073367226">Sobimatu kinnitusallkiri</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Veel <ph name="ITEM_COUNT" /> üksus}other{Veel <ph name="ITEM_COUNT" /> üksust}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Taaskäivitage seade</translation>
<translation id="4277028893293644418">Lähtesta parool</translation>
<translation id="4280429058323657511">, aegub <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Lüliti</translation>
<translation id="4312866146174492540">Blokeeri (vaikimisi)</translation>
<translation id="4325863107915753736">Artiklit ei leitud</translation>
<translation id="4326324639298822553">Kontrollige aegumiskuupäeva ja proovige uuesti</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Tuvastati, et tegemist ei ole ettevõtte hallatava arvutiga, seega saab reegel installida ainult Chrome'i veebipoes hostitavaid laiendusi. Chrome'i veebipoe värskenduse URL on „<ph name="CWS_UPDATE_URL" />”.</translation>
<translation id="4346197816712207223">Aktsepteeritavad krediitkaardid</translation>
<translation id="4356973930735388585">Saidil olevad ründajad võivad proovida installida teie arvutisse ohtlikke programme, mis varastavad teie teavet või kustutavad selle (nt fotod, paroolid, sõnumid ja krediitkaardiandmed).</translation>
+<translation id="4358461427845829800">Halda makseviise …</translation>
<translation id="4372948949327679948">Oodatud väärtus: <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Püüdsite jõuda saidile <ph name="DOMAIN" />, kuid sertifikaadi väljaandja on serveri esitatud sertifikaadi tagasi võtnud. See tähendab, et serveri esitatud turvamandaate ei tohiks mingil juhul usaldada. Võimalik, et suhtlete ründajaga.</translation>
<translation id="4406896451731180161">otsingutulemused</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Kättesaamisaadress</translation>
<translation id="4424024547088906515">Server ei suutnud tõestada, et see on domeen <ph name="DOMAIN" />, Chrome ei usalda selle turvasertifikaati. Selle põhjuseks võib olla vale seadistus või ründaja, kes on sekkunud teie ühendusse.</translation>
<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> ei aktsepteerinud teie sisselogimise sertifikaati või te ei esitanud seda.</translation>
+<translation id="4434045419905280838">Hüpikaknad ja ümbersuunamised</translation>
<translation id="443673843213245140">Puhverserveri kasutamine on keelatud, kuid määratud on ka konkreetne puhverserveri konfigureerimine.</translation>
<translation id="445100540951337728">Aktsepteeritavad deebetkaardid</translation>
<translation id="4506176782989081258">Valideerimisviga: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Makse automaatne täitmine on keelatud</translation>
<translation id="4764776831041365478">Veebileht aadressil <ph name="URL" /> võib olla ajutiselt maas või jäädavalt uuele veebiaadressile teisaldatud.</translation>
<translation id="4771973620359291008">Tekkis tundmatu viga.</translation>
+<translation id="4785689107224900852">Lülitage sellele vahelehele</translation>
<translation id="4792143361752574037">Seansi failidele juurdepääsemisel ilmnes probleem. Kettale salvestamine on praegu keelatud. Veel kord proovimiseks laadige leht uuesti.</translation>
<translation id="4800132727771399293">Kontrollige aegumiskuupäeva ja CVC-d ning proovige uuesti</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Te ei saa saiti <ph name="SITE" /> praegu külastada, sest veebisait saatis tagasi arusaamatud mandaadid, mida Google Chrome ei saa töödelda. Võrguvead ja -rünnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="4813512666221746211">Võrgu viga</translation>
<translation id="4816492930507672669">Sobita lehele</translation>
-<translation id="483020001682031208">Kuvamiseks pole ühtegi füüsilise veebi lehte</translation>
<translation id="4850886885716139402">Kuva</translation>
<translation id="4854362297993841467">See kohaletoimetamisviis pole saadaval. Proovige mõnda teist kohaletoimetamisviisi.</translation>
<translation id="4858792381671956233">Küsisite oma vanematelt, kas võite seda lehte külastada</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bitine)</translation>
<translation id="5121084798328133320">Pärast kinnitamist jagatakse teie Google Paymentsi konto kaardi üksikasju selle saidiga.</translation>
<translation id="5128122789703661928">Selle nimega seanssi ei saa kustutada.</translation>
+<translation id="5135404736266831032">Halda aadresse …</translation>
<translation id="5141240743006678641">Krüpteerige sünkroonitud paroolid oma Google'i mandaadiga</translation>
<translation id="5145883236150621069">Reegli vastuses sisaldus veakood</translation>
<translation id="5159010409087891077">Avage leht uues inkognito aknas (⇧ ⌘ N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Selle lehe manustatud leht ütleb</translation>
<translation id="5205222826937269299">Nimi on nõutav</translation>
<translation id="5222812217790122047">E-posti aadress on nõutav</translation>
-<translation id="522700295135997067">See sait võis äsja varastada teie parooli</translation>
<translation id="5230733896359313003">Tarneaadress</translation>
<translation id="5250209940322997802">„Looge võrguühendus”</translation>
<translation id="5251803541071282808">Pilv</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Sellel ettevõtte, organisatsiooni või kooli intranetis oleval saidil on sama URL mis välisel veebisaidil.
<ph name="LINE_BREAK" />
Võtke ühendust süsteemiadministraatoriga.</translation>
-<translation id="5499929369096410817">Sisestage krediitkaardi <ph name="CREDIT_CARD" /> turvakood. Seda koodi ei salvestata.</translation>
<translation id="5509780412636533143">Hallatud järjehoidjad</translation>
<translation id="5510766032865166053">See võidi teisaldada või kustutada.</translation>
<translation id="5523118979700054094">Reegli nimi</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Lisage tarneaadress</translation>
<translation id="5689199277474810259">Ekspordi JSON-vormingus</translation>
<translation id="5689516760719285838">Asukoht</translation>
+<translation id="570530837424789914">Halda …</translation>
<translation id="5710435578057952990">Selle veebisaidi identiteeti pole kinnitanud.</translation>
<translation id="5719499550583120431">Kaupmees aktsepteerib ettemakstud kaarte.</translation>
<translation id="5720705177508910913">Praegune kasutaja</translation>
+<translation id="5730040223043577876">Chrome soovitab teil parooli lähtestada, kui kasutasite seda ka muudel saitidel.</translation>
<translation id="5732392974455271431">Vanemad saavad blokeeringu teie eest tühistada</translation>
<translation id="5763042198335101085">Sisestage kehtiv e-posti aadress</translation>
<translation id="5765072501007116331">Kohaletoimetamisviiside ja nõuete nägemiseks valige aadress</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Saatke Google'ile automaatselt <ph name="BEGIN_WHITEPAPER_LINK" />süsteemiteavet ja lehe sisu<ph name="END_WHITEPAPER_LINK" />, et aidata tuvastada ohtlikke rakendusi ja saite. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Kontaktteabe muutmine</translation>
<translation id="5967867314010545767">Eemalda ajaloost</translation>
-<translation id="5972020793760134803">Lülitu vahelehele</translation>
<translation id="5975083100439434680">Suumib välja</translation>
-<translation id="597552863672748783">Turvakoodi kinnitamine</translation>
<translation id="598637245381783098">Makserakendust ei saa avada</translation>
<translation id="5989320800837274978">Määratud ei ole fikseeritud puhverservereid ega pac-skriptiga URL-i.</translation>
<translation id="5990559369517809815">Laiendus blokeeris serverisse saadetavad päringud.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">See sisu võib meelitada teid installima tarkvara või avaldama isiklikke andmeid. <ph name="BEGIN_LINK" />Kuva ikkagi<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Te ei saa saiti <ph name="SITE" /> praegu külastada, sest veebisait kasutab sertifikaadi kinnitamist. Võrguvead ja -rünnakud on tavaliselt ajutised, nii et leht tõenäoliselt hiljem töötab.</translation>
<translation id="6059925163896151826">USB-seadmed</translation>
+<translation id="6071091556643036997">Reegli tüüp on sobimatu.</translation>
<translation id="6080696365213338172">Olete sisule juurde pääsenud administraatori antud sertifikaadiga. Administraator saab domeenile <ph name="DOMAIN" /> edastatavaid andmeid kinni pidada.</translation>
<translation id="610911394827799129">Aadressil <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> võib teie Google'i kontol olla muus vormis sirvimisajalugu</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ühtegi}=1{1 parool (sünkroonitud)}other{# parooli (sünkroonitud)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Lisateabe lisamine</translation>
<translation id="6447842834002726250">Küpsised</translation>
<translation id="6451458296329894277">Kinnita vormi uuestiesitamist</translation>
+<translation id="6465306955648956876">Halda paroole …</translation>
<translation id="647261751007945333">Seadme reeglid</translation>
<translation id="6477321094435799029">Chrome tuvastas sellel lehel ebatavalise koodi ja blokeeris selle, et teie isiklikke andmeid (nt paroolid, telefoninumbrid ja krediitkaardiandmed) kaitsta.</translation>
<translation id="6489534406876378309">Krahhide üleslaadimise alustamine</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" />'i otsing</translation>
<translation id="6630809736994426279">Saidil <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> olevad ründajad võivad proovida installida teie Maci ohtlikke programme, mis varastavad teie teavet või kustutavad selle (nt fotod, paroolid, sõnumid ja krediitkaarditeave). <ph name="BEGIN_LEARN_MORE_LINK" />Lisateave<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">See reegel on aegunud.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Mitte ükski}=1{1 saidilt (teid ei logita Google'i kontolt välja)}other{# saidilt (teid ei logita Google'i kontolt välja)}}</translation>
<translation id="6657585470893396449">Parool</translation>
<translation id="6671697161687535275">Kas eemaldada Chromiumist vormi soovitus?</translation>
<translation id="6685834062052613830">Logige välja ja viige seadistus lõpule</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Kasutaja:</translation>
<translation id="6945221475159498467">Vali</translation>
<translation id="6948701128805548767">Kättesaamisviiside ja nõuete nägemiseks valige aadress</translation>
+<translation id="6949872517221025916">Lähtestage parool</translation>
<translation id="6957887021205513506">Serveri sertifikaat näib olevat võltsing.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Seade</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Kohaletoimetamisviis</translation>
<translation id="7139724024395191329">Emiraat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Makse pole turvaline</translation>
+<translation id="717330890047184534">Gaia ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> ja veel <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Värskenda</translation>
<translation id="7182878459783632708">Reegleid pole määratud</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Kasuta globaalset vaikeseadet (blokeeri)</translation>
<translation id="7460163899615895653">Siin kuvatakse teie hiljutised vahelehed teistest seadmetest</translation>
<translation id="7469372306589899959">Kaarti kinnitatakse</translation>
+<translation id="7473891865547856676">Tänan, ei</translation>
<translation id="7481312909269577407">Edasta</translation>
<translation id="7485870689360869515">Andmeid ei leitud.</translation>
<translation id="7508255263130623398">Tagastatud reegli seadme-ID on tühi või ei kattu praeguse seadme-ID-ga</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Kas eemaldada Chrome'ist krediitkaart?</translation>
<translation id="7575800019233204241">„Teie ühendus ei ole privaatne” või „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;” või „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;” või „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;” või „SSL-i sertifikaadi viga”</translation>
<translation id="7578104083680115302">Google'i salvestatud kaartide abil saate eri seadmetes saitidel ja rakendustes kiirelt maksta.</translation>
-<translation id="7588950540487816470">Füüsiline veeb</translation>
<translation id="7592362899630581445">Serveri sertifikaat rikub nime piiranguid.</translation>
<translation id="7598391785903975535">Alla <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Host <ph name="HOST_NAME" /> ei saa praegu seda taotlust töödelda.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Võta muudatus tagasi</translation>
<translation id="9154194610265714752">Värskendatud</translation>
<translation id="9157595877708044936">Seadistamine...</translation>
+<translation id="9168814207360376865">Luba saitidel kontrollida, kas olete makseviisid salvestanud</translation>
<translation id="9169664750068251925">Blokeeri sellel saidil alati</translation>
<translation id="9170848237812810038">&amp;Võta tagasi</translation>
<translation id="917450738466192189">Serveri sertifikaat on kehtetu.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Artikli lisamine ebaõnnestus.</translation>
<translation id="9215416866750762878">Rakendus ei luba Chrome'il selle saidiga ohutult ühendust luua</translation>
<translation id="9219103736887031265">Pildid</translation>
-<translation id="933612690413056017">Interneti-ühendus puudub</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">TÜHJENDA VORM</translation>
<translation id="939736085109172342">Uus kaust</translation>
diff --git a/chromium/components/strings/components_strings_fa.xtb b/chromium/components/strings/components_strings_fa.xtb
index 3def66da1f6..331d98a79e6 100644
--- a/chromium/components/strings/components_strings_fa.xtb
+++ b/chromium/components/strings/components_strings_fa.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">مجوز <ph name="PERMISSION_NAME" /> را انتخاب کنید</translation>
<translation id="1111153019813902504">نشانک‌های اخیر</translation>
<translation id="1113869188872983271">&amp;واگرد ترتیب‌بندی مجدد</translation>
+<translation id="1125573121925420732">در مدتی که وب‌سایت‌ها امنیتشان را به‌روزرسانی می‌کنند، ممکن است به‌طور معمول اخطارهایی دریافت کنید. این مورد به‌زودی اصلاح می‌شود.</translation>
<translation id="1126551341858583091">اندازه در فضای ذخیره‌سازی محلی <ph name="CRASH_SIZE" /> است.</translation>
<translation id="112840717907525620">حافظه پنهان خط‌مشی مورد تأیید است</translation>
<translation id="1150979032973867961">این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد سیستم عامل رایانه شما نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;مطمئن شوید اتصال اینترنت درست برقرار باشد.&lt;/li&gt;
&lt;li&gt;با مالک وب‌سایت تماس بگیرید.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">گذرواژه‌تان را در سایتی که توسط سازمانتان مدیریت نمی‌شود وارد کردید. برای محافظت از حسابتان، از گذرواژه‌تان در سایر برنامه‌ها و سایت‌ها مجدداً استفاده نکنید.</translation>
<translation id="1263231323834454256">فهرست خواندن</translation>
<translation id="1264126396475825575">گزارش خرابی ثبت‌شده در <ph name="CRASH_TIME" /> (هنوز بارگذاری نشده است یا نادیده‌ گرفته شده است)</translation>
<translation id="1270502636509132238">روش تحویل گرفتن</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">انتخاب</translation>
<translation id="1620510694547887537">دوربین</translation>
<translation id="1623104350909869708">جلوگیری از ایجاد پنجره‌های اضافی توسط این صفحه</translation>
-<translation id="1629803312968146339">‏می‌خواهید Chrome این کارت را ذخیره کند؟</translation>
<translation id="1639239467298939599">بارگیری</translation>
<translation id="1640180200866533862">خط‌مشی‌های کاربر</translation>
<translation id="1640244768702815859">از<ph name="BEGIN_LINK" />صفحه اصلی سایت دیدن کنید<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159">‏<ph name="BEGIN_LINK" />Windows Network Diagnostics را اجرا کنید<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">لطفاً «رمز عبارتی همگام‌سازی» خود را به‌روزرسانی کنید.</translation>
<translation id="1787142507584202372">برگه‌های بازتان در اینجا نشان داده می‌شوند</translation>
-<translation id="1789575671122666129">پنجره‌های بازشو</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">نام صاحب کارت</translation>
<translation id="1806541873155184440">تاریخ اضافه شدن: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">رایانه را راه‌اندازی مجدد کنید</translation>
<translation id="2113977810652731515">کارت</translation>
<translation id="2114841414352855701">نادیده گرفته شد زیرا <ph name="POLICY_NAME" /> آن را لغو می‌کند.</translation>
-<translation id="2138201775715568214">در حال جستجوی صفحات وب فیزیکی اطراف</translation>
<translation id="213826338245044447">نشانک‌های تلفن‌ همراه</translation>
<translation id="214556005048008348">لغو پرداخت</translation>
<translation id="2147827593068025794">همگام‌سازی پس‌زمینه</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">خط‌مشی یافت نشد</translation>
<translation id="2213606439339815911">در حال واکشی موارد...</translation>
<translation id="2218879909401188352">درحال‌حاضر مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> می‌توانند برنامه‌های خطرناکی نصب کنند که به دستگاهتان آسیب می‌زنند، هزینه‌های پنهانی به صورت‌حساب دستگاه همراهتان اضافه می‌کنند یا اطلاعات شخصی‌تان را سرقت می‌کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">اتصال اینترنت وجود ندارد</translation>
<translation id="2230458221926704099">با استفاده از <ph name="BEGIN_LINK" />برنامه عیب‌یابی<ph name="END_LINK" />، مشکل اتصالتان را برطرف کنید</translation>
<translation id="2239100178324503013">اکنون ارسال شود</translation>
<translation id="225207911366869382">این مقدار برای این خط‌مشی منسوخ شده است؟</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">حذف آیتم های انتخاب شده</translation>
<translation id="277133753123645258">روش ارسال</translation>
<translation id="277499241957683684">ثبت دستگاه موجود نیست</translation>
+<translation id="2781030394888168909">‏صادر کردن سیستم‌عامل Mac</translation>
<translation id="2784949926578158345">اتصال مجدداً برقرار شد.</translation>
<translation id="2788784517760473862">کارت‌های اعتباری قابل‌قبول</translation>
<translation id="2794233252405721443">سایت مسدودشده</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">‏Chrome درحال حاضر نمی‌تواند کارت شما را تأیید کند. لطفاً بعداً دوباره امتحان کنید.</translation>
<translation id="3064966200440839136">درحال خروج از حالت ناشناس، برای پرداخت ازطریق یک برنامه خارجی. ادامه می‌دهید؟</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{هیچ‌کدام}=1{۱ گذرواژه}one{# گذرواژه}other{# گذرواژه}}</translation>
-<translation id="3093245981617870298">شما آفلاین هستید.</translation>
<translation id="3096100844101284527">افزودن نشانی تحویل گرفتن</translation>
<translation id="3105172416063519923">شناسه دارایی:</translation>
<translation id="3109728660330352905">شما اجازه مشاهده این صفحه را ندارید.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">دسترسی به <ph name="HOST_NAME" /> درحال حاضر امکان‌پذیر نیست.</translation>
<translation id="3427092606871434483">اجازه (پیش‌فرض)</translation>
<translation id="3427342743765426898">&amp;انجام مجدد ویرایش</translation>
+<translation id="342781501876943858">‏Chromium توصیه می‌کند اگر از گذرواژه‌تان در سایت‌های دیگری استفاده کردید آن را بازنشانی کنید.</translation>
<translation id="3431636764301398940">این کارت را در این دستگاه ذخیره کنید</translation>
<translation id="3447661539832366887">مالک این دستگاه بازی دایناسور را خاموش کرده است</translation>
<translation id="3447884698081792621">نمایش گواهی (صادرشده توسط <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">‏صفحه را در پنجره‌ «ناشناس» جدیدی باز کنید (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">گزارش خرابی در <ph name="CRASH_TIME" /> ثبت شد، در <ph name="UPLOAD_TIME" /> بارگذاری شد</translation>
<translation id="3681007416295224113">اطلاعات گواهی</translation>
-<translation id="3690164694835360974">ورود به سیستم امن نیست</translation>
<translation id="3704162925118123524">شاید شبکه‌ای که استفاده می‌کنید، بازدید از صفحه ورود به سیستم خودش را برای شما ضروری کرده باشد.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> ‏<ph name="BOOKMARKED" /> ‏<ph name="TITLE" /> ‏<ph name="DOMAIN" /></translation>
<translation id="370665806235115550">در حال بارکردن…</translation>
@@ -424,7 +424,7 @@
<translation id="3884278016824448484">شناسه دستگاه یکسان نیست</translation>
<translation id="3885155851504623709">استان</translation>
<translation id="3886446263141354045">درخواست شما برای دسترسی به این سایت برای <ph name="NAME" /> ارسال شده است</translation>
-<translation id="3890664840433101773">افزودن رایانامه</translation>
+<translation id="3890664840433101773">افزودن ایمیل</translation>
<translation id="3901925938762663762">کارت منقضی شده است</translation>
<translation id="3909695131102177774"><ph name="LABEL" /> <ph name="ERROR" /></translation>
<translation id="3945915738023014686">شناسه گزارش خرابی بارگذاری‌شده <ph name="CRASH_ID" /> (شناسه خرابی محلی: <ph name="CRASH_LOCAL_ID" />)</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">استفاده از پیش‌فرض کلی (تشخیص)</translation>
<translation id="4165986682804962316">تنظیمات سایت</translation>
-<translation id="4169947484918424451">‏می‌خواهید Chromium این کارت را ذخیره کند؟</translation>
<translation id="4171400957073367226">امضای تأیید نامناسب</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> مورد دیگر}one{<ph name="ITEM_COUNT" /> مورد دیگر}other{<ph name="ITEM_COUNT" /> مورد دیگر}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">راه‌اندازی دستگاه خود</translation>
<translation id="4277028893293644418">بازنشانی گذرواژه</translation>
<translation id="4280429058323657511">، انقضا <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">جابه‌جایی</translation>
<translation id="4312866146174492540">مسدود کردن (پیش‌فرض)</translation>
<translation id="4325863107915753736">مقاله یافت نشد.</translation>
<translation id="4326324639298822553">تاریخ انقضا را بررسی و دوباره امتحان کنید</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">‏این رایانه به‌صورت سازمانی مدیریت نمی‌شود، بنابراین خط‌مشی تنها می‌تواند به‌صورت خودکار افزونه‌های میزبانی‌شده در «نت‌بازار Chrome» را نصب کند. نشانی وب به‌روزرسانی «نت‌بازار Chrome» «<ph name="CWS_UPDATE_URL" />» است.</translation>
<translation id="4346197816712207223">کارت‌های اعتباری قابل‌‌قبول</translation>
<translation id="4356973930735388585">مهاجم‌ها در این سایت ممکن است تلاش کنند برنامه‌های خطرناکی در رایانه شما نصب کنند که اطلاعات شما (مانند عکس‌ها، گذرواژه‌ها، پیام‌ها و کارت‌های اعتباری) را به سرقت می‌برند یا حذف می‌کنند.</translation>
+<translation id="4358461427845829800">مدیریت روش‌های پرداخت…</translation>
<translation id="4372948949327679948">مقدار مورد انتظار <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">شما سعی در دسترسی به <ph name="DOMAIN" /> را داشتید، اما صادر کننده، گواهی ارائه شده از سوی سرور را باطل کرده است. یعنی اصلاً نباید به اطلاعات کاربری که این سرور ارائه می‌کند اطمینان کرد. ممکن است شما با مهاجمی در ارتباط باشید.</translation>
<translation id="4406896451731180161">نتایج جستجو</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">نشانی تحویل گرفتن</translation>
<translation id="4424024547088906515">‏این سرور نتوانست اثبات کند که این <ph name="DOMAIN" /> است؛ گواهی امنیتی آن مورداعتماد Chrome نیست. ممکن است علت این موضوع پیکربندی اشتباه باشد یا مهاجی اتصال شما را قطع کرده است.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> گواهی ورود به سیستمتان را نپذیرفت یا ممکن است گواهی‌ای ارائه نشده باشد.</translation>
+<translation id="4434045419905280838">پنجره‌های بازشو و هدایت‌ها</translation>
<translation id="443673843213245140">استفاده از پروکسی غیرفعال است اما یک پیکربندی خاص برای پروکسی تعیین شده است.</translation>
<translation id="445100540951337728">کارت‌های نقدی قابل‌قبول</translation>
<translation id="4506176782989081258">خطای ارزیابی: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">تکمیل خودکار پرداخت غیرفعال شد</translation>
<translation id="4764776831041365478">ممکن است صفحهٔ وب <ph name="URL" /> موقتاً خراب باشد یا ممکن است برای همیشه به آدرس وب جدید منتقل شده باشد.</translation>
<translation id="4771973620359291008">خطای ناشناخته‌ای رخ داد.</translation>
+<translation id="4785689107224900852">جابجا شدن به این برگه</translation>
<translation id="4792143361752574037">مشکلی در دسترسی به فایل‌های جلسه وجود داشت. درحال‌حاضر ذخیره‌سازی در دیسک غیرفعال است. لطفاً برای امتحان مجدد، صفحه را تازه‌سازی کنید.</translation>
<translation id="4800132727771399293">‏تاریخ انقضا و CVC را بررسی کرده و دوباره امتحان کنید</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">‏در این لحظه نمی‌توانید از <ph name="SITE" /> دیدن کنید زیرا این وب‌سایت اعتبارنامه‌های درهمی ارسال کرده است که Google Chrome نمی‌تواند پردازش کند. خطاهای شبکه و حمله‌ها معمولاً موقتی هستند، بنابراین احتمالاً این صفحه بعداً کار خواهد کرد.</translation>
<translation id="4813512666221746211">خطای شبکه</translation>
<translation id="4816492930507672669">متناسب با صفحه</translation>
-<translation id="483020001682031208">هیچ صفحه «وب فیزیکی» برای نمایش وجود ندارد</translation>
<translation id="4850886885716139402">نما</translation>
<translation id="4854362297993841467">این روش تحویل در دسترس نیست. روش دیگری را امتحان کنید.</translation>
<translation id="4858792381671956233">از والدینتان پرسیدید آیا اجازه بازدید از این سایت را دارید</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(۶۴ بیت)</translation>
<translation id="5121084798328133320">‏بعد از تأیید، جزئیات کارت از حساب «پرداخت‌های Google» با این سایت هم‌رسانی می‌شود.</translation>
<translation id="5128122789703661928">جلسه‌ای با این نام، برای حذف معتبر نیست.</translation>
+<translation id="5135404736266831032">مدیریت نشانی‌ها…</translation>
<translation id="5141240743006678641">‏رمزگذاری گذرواژه‌های همگام‌سازی شده با اطلاعات کاربری Google شما</translation>
<translation id="5145883236150621069">کد خطا در پاسخ خط‌مشی موجود است</translation>
<translation id="5159010409087891077">‏صفحه را در پنجره «ناشناس» جدیدی باز کنید (N⌘⇧)</translation>
@@ -599,8 +602,7 @@
<translation id="5190835502935405962">نوار نشانک‌ها</translation>
<translation id="5201306358585911203">صفحه جاسازی‌شده‌ای در این صفحه می‌گوید</translation>
<translation id="5205222826937269299">نام ضروری است</translation>
-<translation id="5222812217790122047">رایانامه ضروری است</translation>
-<translation id="522700295135997067">ممکن است این سایت اخیراً گذرواژه‌تان را سرقت کرده باشد</translation>
+<translation id="5222812217790122047">ایمیل ضروری است</translation>
<translation id="5230733896359313003">نشانی تحویل کالا</translation>
<translation id="5250209940322997802">«به شبکه متصل شوید»</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -644,13 +646,12 @@
<translation id="5492298309214877701">نشانی وب این سایت در اینترانت شرکت، سازمان یا محل تحصیل با نشانی وب یک وب‌سایت خارجی یکسان است.
<ph name="LINE_BREAK" />
با سرپرست سیستم تماس بگیرید.</translation>
-<translation id="5499929369096410817">کد امنیتی <ph name="CREDIT_CARD" /> را وارد کنید. این کد ذخیره نمی‌شود.</translation>
<translation id="5509780412636533143">نشانک‌های مدیریت شده</translation>
<translation id="5510766032865166053">ممکن است جابه‌جا یا حذف شده باشد.</translation>
<translation id="5523118979700054094">نام خط‌مشی</translation>
<translation id="552553974213252141">آیا نوشتار به درستی استخراج شده است؟</translation>
<translation id="5540224163453853">مقاله درخواستی یافت نشد.</translation>
-<translation id="5541546772353173584">افزودن رایانامه</translation>
+<translation id="5541546772353173584">افزودن ایمیل</translation>
<translation id="5545756402275714221">مقاله‌هایی برای شما</translation>
<translation id="5556459405103347317">تازه‌سازی</translation>
<translation id="5560088892362098740">تاریخ انقضا</translation>
@@ -670,16 +671,18 @@
<translation id="5631439013527180824">نشانه مدیریت دستگاه نامعتبر است</translation>
<translation id="5633066919399395251">شاید درحال‌حاضر مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> در تلاش باشند برنامه‌های خطرناکی در رایانه‌تان نصب کنند که اطلاعات شما (مانند عکس‌ها، گذرواژه‌ها، پیام‌ها و کارت‌های اعتباری) را به سرقت می‌برند یا حذف می‌کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="563324245173044180">محتوای فریب‌دهنده مسدود شد.</translation>
-<translation id="5659593005791499971">رایانامه</translation>
+<translation id="5659593005791499971">ایمیل</translation>
<translation id="5675650730144413517">این صفحه کار نمی‌کند</translation>
<translation id="5685654322157854305">افزودن نشانی تحویل کالا</translation>
<translation id="5689199277474810259">‏صادر کردن به JSON</translation>
<translation id="5689516760719285838">مکان</translation>
+<translation id="570530837424789914">مدیریت…</translation>
<translation id="5710435578057952990">هویت این وب سایت تأیید نشده است.</translation>
<translation id="5719499550583120431">کارت‌های پیش‌پرداخت پذیرفته می‌شوند.</translation>
<translation id="5720705177508910913">کاربر کنونی</translation>
+<translation id="5730040223043577876">‏Chrome توصیه می‌کند اگر از گذرواژه‌تان در سایت‌های دیگری استفاده کردید آن را بازنشانی کنید.</translation>
<translation id="5732392974455271431">والدینتان می‌توانند این سایت را برای شما بگشایند</translation>
-<translation id="5763042198335101085">نشانی رایانامه معتبری وارد کنید</translation>
+<translation id="5763042198335101085">نشانی ایمیل معتبری وارد کنید</translation>
<translation id="5765072501007116331">برای دیدن روش‌های تحویل و شرایط موردنیاز، یک نشانی انتخاب کنید</translation>
<translation id="5770114862687765385">به نظر می‌رسد فایل خراب شده باشد. برای بازنشانی جلسه، روی دکمه «بازنشانی» کلیک کنید.</translation>
<translation id="5778550464785688721">‏کنترل کامل دستگاه‌های MIDI</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">‏ارسال خودکار برخی از <ph name="BEGIN_WHITEPAPER_LINK" />اطلاعات سیستم و محتوای صفحه<ph name="END_WHITEPAPER_LINK" /> به Google برای کمک به شناسایی برنامه‌ها و سایت‌های خطرناک. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">ویرایش اطلاعات تماس</translation>
<translation id="5967867314010545767">حذف از سابقه</translation>
-<translation id="5972020793760134803">رفتن به برگه</translation>
<translation id="5975083100439434680">کوچک نمایی</translation>
-<translation id="597552863672748783">تأیید کد امنیتی</translation>
<translation id="598637245381783098">برنامه پرداخت باز نشد</translation>
<translation id="5989320800837274978">‏سرور پروکسی ثابت و URL اسکریپت pac. تعیین نشده‌اند.</translation>
<translation id="5990559369517809815">درخواست‌های ارسالی به سرور توسط یک برنامهٔ افزودنی مسدود شد.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">شاید محتوای این صفحه تلاش کند شما را فریب دهد تا نرم‌افزاری نصب کنید یا اطلاعات شخصی را افشا سازید. <ph name="BEGIN_LINK" />درهرصورت نمایش داده شود<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">درحال‌حاضر نمی‌توانید از <ph name="SITE" /> دیدن کنید، زیرا وب‌سایت از پین کردن گواهینامه استفاده می‌کند. خطاهای شبکه و حمله‌ها موقتی هستند، بنابراین احتمالاً این صفحه بعداً کار خواهد کرد.</translation>
<translation id="6059925163896151826">‏دستگاه‌های USB</translation>
+<translation id="6071091556643036997">نوع خط‌مشی نامعتبر است.</translation>
<translation id="6080696365213338172">شما با استفاده از گواهی ارائه شده توسط سرپرست سیستم به محتوا دسترسی پیدا کرده‌اید. داده‌هایی که به <ph name="DOMAIN" /> ارائه می‌کنید ممکن است توسط سرپرست سیستم رهگیری شوند.</translation>
<translation id="610911394827799129">‏ممکن است حساب Google شما اشکال دیگری از سابقه مرور در <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> داشته باشد</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{هیچ‌کدام}=1{۱ گذرواژه (همگام‌سازی‌شده)}one{# گذرواژه (همگام‌سازی‌شده)}other{# گذرواژه (همگام‌سازی‌شده)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">افزودن اطلاعات بیشتر</translation>
<translation id="6447842834002726250">کوکی‌ها</translation>
<translation id="6451458296329894277">تأیید ارسال مجدد فرم</translation>
+<translation id="6465306955648956876">مدیریت گذرواژه‌ها…</translation>
<translation id="647261751007945333">خط‌‌مشی‌های دستگاه</translation>
<translation id="6477321094435799029">‏Chrome کد نامعمول در این این صفحه شناسایی کرده و برای محافظت از اطلاعات شخصی‌تان (مثلاً گذرواژه‌ها، شماره تلفن‌‌ها و کارت‌های اعتباری) آن را مسدود کرده است.</translation>
<translation id="6489534406876378309">شروع بارگذاری کردن خرابی‌ها</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">جستجوی <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">‏شاید درحال‌حاضر مهاجم‌ها در <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> در تلاش باشند برنامه‌های خطرناکی در Mac شما نصب کنند که اطلاعاتتان (مانند عکس‌ها، گذرواژه‌ها، پیام‌ها و کارت‌های اعتباری) را به سرقت می‌برند یا حذف می‌کنند. <ph name="BEGIN_LEARN_MORE_LINK" />بیشتر بدانید<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">این قانون قدیمی شده است.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{هیچ‌کدام}=1{‏از ۱ سایت (از سیستم حساب Google خود خارج نخواهید شد)}one{‏از # سایت (از سیستم حساب Google خود خارج نخواهید شد)}other{‏از # سایت (از سیستم حساب Google خود خارج نخواهید شد)}}</translation>
<translation id="6657585470893396449">گذرواژه</translation>
<translation id="6671697161687535275">‏پیشنهاد فرم از Chromium پاک شود؟</translation>
<translation id="6685834062052613830">خروج از سیستم و تکمیل راه‌اندازی</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">کاربر:</translation>
<translation id="6945221475159498467">انتخاب</translation>
<translation id="6948701128805548767">برای دیدن روش‌های تحویل گرفتن و شرایط موردنیاز، یک نشانی انتخاب کنید</translation>
+<translation id="6949872517221025916">بازنشانی گذرواژه</translation>
<translation id="6957887021205513506">به نظر می‌رسد که گواهی سرور جعلی باشد.</translation>
<translation id="6965382102122355670">قبول</translation>
<translation id="6965978654500191972">دستگاه</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">روش تحویل</translation>
<translation id="7139724024395191329">امارت</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> روش دیگر}one{<ph name="PAYMENT_METHOD_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> روش دیگر}other{<ph name="PAYMENT_METHOD_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> روش دیگر}}</translation>
-<translation id="7155487117670177674">پرداخت امن نیست</translation>
+<translation id="717330890047184534">‏شناسه Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> گزینه دیگر}one{<ph name="SHIPPING_OPTION_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> گزینه دیگر}other{<ph name="SHIPPING_OPTION_PREVIEW" /> و <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> گزینه دیگر}}</translation>
<translation id="7180611975245234373">بازخوانی</translation>
<translation id="7182878459783632708">هیچ خط‌مشی‌ای تنظیم نشده است</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">استفاده از پیش‌فرض جهانی (مسدود)</translation>
<translation id="7460163899615895653">برگه‌های اخیر شما از دیگر دستگاه‌ها اینجا نشان داده می‌شوند</translation>
<translation id="7469372306589899959">درحال تایید کارت</translation>
+<translation id="7473891865547856676">نه متشکرم</translation>
<translation id="7481312909269577407">ارسال کردن</translation>
<translation id="7485870689360869515">هیچ داده‌ای یافت نشد.</translation>
<translation id="7508255263130623398">شناسه دستگاه خط‌مشی برگردانده‌شده خالی است یا با شناسه کنونی دستگاه مطابقت ندارد</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">‏کارت اعتباری از Chrome پاک شود؟</translation>
<translation id="7575800019233204241">‏«اتصالتان خصوصی نیست» یا «&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;» یا «&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;» یا «&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;» یا «خطای گواهینامه SSL»</translation>
<translation id="7578104083680115302">‏با استفاده از کارت‌هایی که با Google ذخیره کرده‌اید به‌سرعت در همه دستگاه‌هایتان پرداخت‌های سایت‌ها و برنامه‌ها را انجام دهید.</translation>
-<translation id="7588950540487816470">وب فیزیکی</translation>
<translation id="7592362899630581445">گواهی سرور محدودیت‌های نام را نقض می‌کند.</translation>
<translation id="7598391785903975535">کمتر از <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> درحال حاضر نمی‌تواند این درخواست را انجام دهد.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;واگرد ویرایش</translation>
<translation id="9154194610265714752">به‌روزرسانی ‌شد</translation>
<translation id="9157595877708044936">در حال راه‌اندازی...</translation>
+<translation id="9168814207360376865">سایت‌ها بتوانند بررسی کنند روش پرداخت ذخیره‌شده‌ای دارید یا نه</translation>
<translation id="9169664750068251925">همیشه مسدود در این سایت</translation>
<translation id="9170848237812810038">&amp;واگرد</translation>
<translation id="917450738466192189">گواهی سرور نامعتبر است.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">افزودن مقاله ناموفق بود.</translation>
<translation id="9215416866750762878">‏برنامه‌ای مانع از اتصال ایمن Chrome به این سایت می‌شود</translation>
<translation id="9219103736887031265">تصاویر</translation>
-<translation id="933612690413056017">اتصال اینترنت قطع است</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">پاک کردن فرم</translation>
<translation id="939736085109172342">پوشهٔ جدید</translation>
diff --git a/chromium/components/strings/components_strings_fi.xtb b/chromium/components/strings/components_strings_fi.xtb
index b413b4c6068..b743ae069ea 100644
--- a/chromium/components/strings/components_strings_fi.xtb
+++ b/chromium/components/strings/components_strings_fi.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Valitse käyttöoikeus kohteelle <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Uusimmat kirjanmerkit</translation>
<translation id="1113869188872983271">K&amp;umoa uudelleenjärjestely</translation>
+<translation id="1125573121925420732">Varoituksia voi esiintyä usein, kun verkkosivustot päivittävät suojaustaan. Asian pitäisi korjaantua pian.</translation>
<translation id="1126551341858583091">Paikallisen tallennustilan koko on <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Käytännön välimuisti on OK</translation>
<translation id="1150979032973867961">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; tietokoneesi käyttöjärjestelmä ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Varmista, että internetyhteytesi toimii.&lt;/li&gt;
&lt;li&gt;Ota yhteyttä verkkosivuston omistajaan.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Kirjoitit salasanan sivustolle, joka ei ole organisaatiosi hallinnoima. Älä käytä samaa salasanaa muissa sovelluksissa tai muilla sivustoilla tilisi turvallisuuden vuoksi.</translation>
<translation id="1263231323834454256">Lukulista</translation>
<translation id="1264126396475825575">Kaatumisraportti tallennettu <ph name="CRASH_TIME" /> (ei vielä lähetetty tai ohitettu)</translation>
<translation id="1270502636509132238">Noutotapa</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Valitse</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Estä tätä sivua luomasta muita viestejä</translation>
-<translation id="1629803312968146339">Haluatko, että Chrome tallentaa tämän kortin?</translation>
<translation id="1639239467298939599">Ladataan</translation>
<translation id="1640180200866533862">Käyttäjäkäytännöt</translation>
<translation id="1640244768702815859">Kokeile <ph name="BEGIN_LINK" />siirtyä sivuston etusivulle<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Kokeile Windowsin verkon diagnostiikkaa<ph name="END_LINK" /></translation>
<translation id="1783075131180517613">Päivitä synkronoinnin tunnuslause.</translation>
<translation id="1787142507584202372">Avoimet välilehdet näkyvät tässä.</translation>
-<translation id="1789575671122666129">Ponnahdusikkunat</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kortinhaltijan nimi</translation>
<translation id="1806541873155184440">Lisätty: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Käynnistä tietokone uudelleen.</translation>
<translation id="2113977810652731515">Kortti</translation>
<translation id="2114841414352855701">Ei käytetä – käytännön <ph name="POLICY_NAME" /> ohittama.</translation>
-<translation id="2138201775715568214">Etsitään lähistöllä olevia Fyysisen webin sivuja</translation>
<translation id="213826338245044447">Mobiilikirjanmerkit</translation>
<translation id="214556005048008348">Peruuta maksu</translation>
<translation id="2147827593068025794">Taustasynkronointi</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Käytäntöä ei löydy</translation>
<translation id="2213606439339815911">Noudetaan merkintöjä…</translation>
<translation id="2218879909401188352">Sivustolla <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> tällä hetkellä olevat hyökkääjät voivat asentaa vaarallisia laitettasi vahingoittavia sovelluksia, lisätä piilomaksuja puhelinlaskuusi tai varastaa henkilökohtaisia tietojasi. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Ei internetyhteyttä</translation>
<translation id="2230458221926704099">Korjaa yhteytesi käyttämällä <ph name="BEGIN_LINK" />diagnostiikkasovellusta<ph name="END_LINK" />.</translation>
<translation id="2239100178324503013">Lähetä nyt</translation>
<translation id="225207911366869382">Tämän käytännön arvo on vanhentunut.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Poista valitut kohteet</translation>
<translation id="277133753123645258">Lähetystapa</translation>
<translation id="277499241957683684">Laitetallenne puuttuu</translation>
+<translation id="2781030394888168909">Vie MacOS-muodossa</translation>
<translation id="2784949926578158345">Yhteys katkaistiin.</translation>
<translation id="2788784517760473862">Hyväksytyt luottokortit</translation>
<translation id="2794233252405721443">Sivusto estetty</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome ei voinut vahvistaa korttiasi. Yritä myöhemmin uudelleen.</translation>
<translation id="3064966200440839136">Incognito-tilasta poistutaan ulkoisessa sovelluksessa maksamisen vuoksi. Haluatko jatkaa?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ei mitään}=1{1 salasana}other{# salasanaa}}</translation>
-<translation id="3093245981617870298">Olet offline-tilassa.</translation>
<translation id="3096100844101284527">Lisää noutopaikan osoite</translation>
<translation id="3105172416063519923">Laitteen tunnus:</translation>
<translation id="3109728660330352905">Sinulla ei ole oikeutta tarkastella tätä sivua.</translation>
@@ -363,6 +363,7 @@
<translation id="3422472998109090673">Sivustoon <ph name="HOST_NAME" /> ei saada tällä hetkellä yhteyttä.</translation>
<translation id="3427092606871434483">Salli (oletus)</translation>
<translation id="3427342743765426898">&amp;Toista muokkaus</translation>
+<translation id="342781501876943858">Chromium suosittelee salasanan vaihtamista, jos olet käyttänyt sitä myös muilla sivustoilla.</translation>
<translation id="3431636764301398940">Tallenna kortti tälle laitteelle</translation>
<translation id="3447661539832366887">Tämän laitteen omistaja on poistanut dinosauruspelin käytöstä.</translation>
<translation id="3447884698081792621">Näytä varmenne (myöntäjä: <ph name="ISSUER" />)</translation>
@@ -399,7 +400,6 @@
<translation id="3678529606614285348">Avaa sivu uudessa incognito-ikkunassa (Ctrl + Vaihto + N).</translation>
<translation id="3679803492151881375">Kaatumisraportti tallennettu <ph name="CRASH_TIME" />, lähetetty <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Varmenteen tiedot</translation>
-<translation id="3690164694835360974">Sisäänkirjautuminen ei ole turvallinen</translation>
<translation id="3704162925118123524">Käyttämäsi verkko saattaa edellyttää kirjautumista.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Ladataan...</translation>
@@ -459,7 +459,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Käytä yleistä oletusta (havaitse)</translation>
<translation id="4165986682804962316">Sivustoasetukset</translation>
-<translation id="4169947484918424451">Haluatko, että Chromium tallentaa tämän kortin?</translation>
<translation id="4171400957073367226">Virheellinen vahvistusallekirjoitus.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> toinen kohde}other{<ph name="ITEM_COUNT" /> muuta kohdetta}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -496,6 +495,7 @@
<translation id="4275830172053184480">Käynnistä laite uudelleen</translation>
<translation id="4277028893293644418">Pyydä uusi salasana</translation>
<translation id="4280429058323657511">, vanhentumispäivä <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Vaihda</translation>
<translation id="4312866146174492540">Estä (oletus)</translation>
<translation id="4325863107915753736">Artikkelia ei löydy</translation>
<translation id="4326324639298822553">Tarkista vanhentumispäivä ja yritä uudelleen.</translation>
@@ -503,6 +503,7 @@
<translation id="4340982228985273705">Havaintojen mukaan tämä tietokone ei ole yrityksen hallinnoima, joten käytäntö voi asentaa automaattisesti vain Chrome Web Storessa hostattuja laajennuksia. Chrome Web Storen päivitys-URL-osoite on <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Hyväksytyt luottokortit</translation>
<translation id="4356973930735388585">Tälle sivustolle hyökännyt taho voi yrittää asentaa tietokoneellesi vaarallisia ohjelmia, jotka varastavat tai poistavat tietojasi, kuten kuviasi, salasanojasi, viestejäsi ja luottokorttiesi tietoja.</translation>
+<translation id="4358461427845829800">Hallinnoi maksutapoja…</translation>
<translation id="4372948949327679948">Odotettu <ph name="VALUE_TYPE" />-arvo.</translation>
<translation id="4377125064752653719">Yritit yhdistää sivustoon <ph name="DOMAIN" />, mutta varmenteen myöntäjä on kumonnut palvelimen esittämän varmenteen. Palvelimen esittämiin suojaustietoihin ei siis tule luottaa. Saatat olla tekemisissä hakkerin kanssa.</translation>
<translation id="4406896451731180161">hakutulokset</translation>
@@ -510,6 +511,7 @@
<translation id="4415426530740016218">Nouto-osoite</translation>
<translation id="4424024547088906515">Palvelin ei voinut todistaa olevansa <ph name="DOMAIN" />; Chrome ei luota sen suojausvarmenteeseen. Tämä voi johtua määritysvirheestä tai verkkoyhteytesi siepanneesta hyökkääjästä.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ei hyväksynyt kirjautumisvarmennettasi, tai varmennetta ei annettu.</translation>
+<translation id="4434045419905280838">Ponnahdusikk. ja uudelleenohj.</translation>
<translation id="443673843213245140">Välityspalvelinta ei saa käyttää, mutta erilliset välityspalvelimen asetukset on määritetty.</translation>
<translation id="445100540951337728">Hyväksytyt maksukortit</translation>
<translation id="4506176782989081258">Todennusvirhe: <ph name="VALIDATION_ERROR" /></translation>
@@ -544,13 +546,13 @@
<translation id="4759118997339041434">Maksujen automaattinen täyttö pois käytöstä</translation>
<translation id="4764776831041365478">Osoitteessa <ph name="URL" /> oleva sivu saattaa olla väliaikaisesti pois käytöstä tai se on voitu siirtää pysyvästi uuteen osoitteeseen.</translation>
<translation id="4771973620359291008">Tapahtui tuntematon virhe.</translation>
+<translation id="4785689107224900852">Siirry tälle välilehdelle</translation>
<translation id="4792143361752574037">Käyntitiedostoja käytettäessä tapahtui virhe. Tietojen tallentaminen levylle on tällä hetkellä poistettu käytöstä. Päivitä sivu ja yritä uudelleen.</translation>
<translation id="4800132727771399293">Tarkista vanhenemispäivä ja CVC ja yritä uudelleen.</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Et voi siirtyä sivustoon <ph name="SITE" /> juuri nyt, koska sivusto lähetti sekoitetut kirjautumistiedot, joita Google Chrome ei voi käsitellä. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="4813512666221746211">Verkkovirhe</translation>
<translation id="4816492930507672669">Sovita sivulle</translation>
-<translation id="483020001682031208">Ei näytettäviä Fyysinen web ‑sivuja</translation>
<translation id="4850886885716139402">Näytä</translation>
<translation id="4854362297993841467">Tämä toimitustapa ei ole käytettävissä. Kokeile toista tapaa.</translation>
<translation id="4858792381671956233">Pyysit vanhemmiltasi lupaa käydä tällä sivustolla.</translation>
@@ -590,6 +592,7 @@
<translation id="5115563688576182185">(64-bittinen)</translation>
<translation id="5121084798328133320">Vahvistamisen jälkeen Google-maksutilisi korttitiedot jaetaan tämän sivuston kanssa.</translation>
<translation id="5128122789703661928">Tämännimistä käyttökertaa ei voi poistaa.</translation>
+<translation id="5135404736266831032">Hallinnoi osoitteita…</translation>
<translation id="5141240743006678641">Salaa synkronoidut salasanat Google-kirjautumistietojesi avulla</translation>
<translation id="5145883236150621069">Käytäntövastaus sisältää virhekoodin</translation>
<translation id="5159010409087891077">Avaa sivu uudessa incognito-ikkunassa (⇧ + ⌘ + N).</translation>
@@ -601,7 +604,6 @@
<translation id="5201306358585911203">Viesti tälle sivulle upotetulta sivulta</translation>
<translation id="5205222826937269299">Nimi vaaditaan</translation>
<translation id="5222812217790122047">Sähköposti vaaditaan</translation>
-<translation id="522700295135997067">Tämä sivusto saattoi juuri varastaa salasanasi.</translation>
<translation id="5230733896359313003">Toimitusosoite</translation>
<translation id="5250209940322997802">Yhdistä verkkoon</translation>
<translation id="5251803541071282808">Pilvi</translation>
@@ -645,7 +647,6 @@
<translation id="5492298309214877701">Tällä yrityksen, organisaation tai oppilaitoksen intranetissä olevalla sivustolla on sama URL-osoite kuin ulkoisella verkkosivustolla.
<ph name="LINE_BREAK" />
Ota yhteyttä järjestelmänvalvojaasi.</translation>
-<translation id="5499929369096410817">Anna kortin <ph name="CREDIT_CARD" /> turvakoodi. Tätä koodia ei tallenneta.</translation>
<translation id="5509780412636533143">Hallinnoidut kirjanmerkit</translation>
<translation id="5510766032865166053">Se on voitu siirtää tai poistaa.</translation>
<translation id="5523118979700054094">Käytännön nimi</translation>
@@ -676,9 +677,11 @@
<translation id="5685654322157854305">Lisää toimitusosoite</translation>
<translation id="5689199277474810259">Vie JSON-tiedostoon</translation>
<translation id="5689516760719285838">Sijainti</translation>
+<translation id="570530837424789914">Hallinnoi…</translation>
<translation id="5710435578057952990">Tämän sivuston identiteettiä ei ole vahvistettu.</translation>
<translation id="5719499550583120431">Prepaid-kortit hyväksytään.</translation>
<translation id="5720705177508910913">Nykyinen käyttäjä</translation>
+<translation id="5730040223043577876">Chrome suosittelee salasanan vaihtamista, jos olet käyttänyt sitä myös muilla sivustoilla.</translation>
<translation id="5732392974455271431">Vanhempasi voivat kumota eston puolestasi.</translation>
<translation id="5763042198335101085">Anna voimassa oleva sähköpostiosoite.</translation>
<translation id="5765072501007116331">Valitse osoite, niin näet toimitustavat ja vaatimukset.</translation>
@@ -702,9 +705,7 @@
<translation id="5959728338436674663"><ph name="BEGIN_WHITEPAPER_LINK" />Lähetä automaattisesti<ph name="END_WHITEPAPER_LINK" /> joitain järjestelmän tietoja ja sivujen sisältöjä Googlelle auttaaksesi sitä havaitsemaan vaarallisia sovelluksia ja sivustoja. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Muokkaa yhteystietoja</translation>
<translation id="5967867314010545767">Poista historiasta</translation>
-<translation id="5972020793760134803">Vaihda välilehdelle</translation>
<translation id="5975083100439434680">Loitonna</translation>
-<translation id="597552863672748783">Vahvista turvakoodi</translation>
<translation id="598637245381783098">Maksusovelluksen avaaminen ei onnistu.</translation>
<translation id="5989320800837274978">Kiinteitä välityspalvelimia tai .pac-URL-osoitetta ei ole määritetty.</translation>
<translation id="5990559369517809815">Laajennus esti palvelinpyynnöt.</translation>
@@ -720,6 +721,7 @@
<translation id="6047927260846328439">Tämä sisältö saattaa yrittää huijata sinua asentamaan ohjelmistoja tai paljastamaan henkilökohtaisia tietoja. <ph name="BEGIN_LINK" />Näytä silti<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> ei juuri nyt ole käytettävissä, koska se käyttää varmenteiden kiinnittämistä. Verkkovirheet ja hyökkäykset ovat yleensä väliaikaisia, joten sivu luultavasti toimii myöhemmin.</translation>
<translation id="6059925163896151826">USB-laitteet</translation>
+<translation id="6071091556643036997">Käytäntötyyppi on virheellinen.</translation>
<translation id="6080696365213338172">Käytät sisältöä järjestelmänvalvojan myöntämällä varmenteella. Järjestelmänvalvoja voi käyttää verkkotunnukselle <ph name="DOMAIN" /> lähettämiäsi tietoja.</translation>
<translation id="610911394827799129">Google-tililläsi voi olla muita selaushistoriatietoja osoitteessa <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ei mitään}=1{1 salasana (synkronoitu)}other{# salasanaa (synkronoitu)}}</translation>
@@ -767,6 +769,7 @@
<translation id="6446608382365791566">Lisää tietoja</translation>
<translation id="6447842834002726250">Evästeet</translation>
<translation id="6451458296329894277">Vahvista lomakkeen uudelleenlähetys</translation>
+<translation id="6465306955648956876">Hallinnoi salasanoja…</translation>
<translation id="647261751007945333">Laitekäytännöt</translation>
<translation id="6477321094435799029">Chrome havaitsi tällä sivulla epätavallista koodia ja esti sen suojellakseen henkilötietojasi (esimerkiksi salasanoja, puhelinnumeroita tai luottokorttitietoja).</translation>
<translation id="6489534406876378309">Aloita kaatumistietojen lähettäminen</translation>
@@ -786,6 +789,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" />-haku</translation>
<translation id="6630809736994426279">Sivustolle <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hyökännyt taho voi yrittää asentaa Maciisi vaarallisia ohjelmia, jotka varastavat tai poistavat tietojasi, esimerkiksi kuvia, salasanoja, viestejä tai luottokorttitietoja. <ph name="BEGIN_LEARN_MORE_LINK" />Lisätietoja<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Tämä käytäntö on vanhentunut.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ei mitään}=1{1 sivustolta (sinua ei kirjata ulos Google-tililtäsi)}other{# sivustolta (sinua ei kirjata ulos Google-tililtäsi)}}</translation>
<translation id="6657585470893396449">Salasana</translation>
<translation id="6671697161687535275">Poistetaanko lomake-ehdotus Chromiumista?</translation>
<translation id="6685834062052613830">Kirjaudu ulos ja suorita määritys loppuun.</translation>
@@ -812,6 +816,7 @@
<translation id="6915804003454593391">Käyttäjä:</translation>
<translation id="6945221475159498467">Valitse</translation>
<translation id="6948701128805548767">Valitse osoite, niin näet noutotavat ja vaatimukset.</translation>
+<translation id="6949872517221025916">Pyydä uusi salasana</translation>
<translation id="6957887021205513506">Palvelimen varmenne näyttää olevan väärennös.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Laite</translation>
@@ -833,7 +838,7 @@
<translation id="7138472120740807366">Toimitustapa</translation>
<translation id="7139724024395191329">Emiirikunta</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> ja <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> toinen}other{<ph name="PAYMENT_METHOD_PREVIEW" /> ja <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> muuta}}</translation>
-<translation id="7155487117670177674">Maksu ei ole turvallinen</translation>
+<translation id="717330890047184534">Gaia-tunnus:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> ja <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> toinen}other{<ph name="SHIPPING_OPTION_PREVIEW" /> ja <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> muuta}}</translation>
<translation id="7180611975245234373">Päivitä</translation>
<translation id="7182878459783632708">Käytäntöjä ei ole asetettu</translation>
@@ -882,6 +887,7 @@
<translation id="7455133967321480974">Käytä yleistä oletusasetusta (estä)</translation>
<translation id="7460163899615895653">Muiden laitteidesi viimeisimmät välilehdet näkyvät täällä.</translation>
<translation id="7469372306589899959">Vahvistetaan korttia</translation>
+<translation id="7473891865547856676">Ei kiitos</translation>
<translation id="7481312909269577407">Seuraava</translation>
<translation id="7485870689360869515">Tietoja ei löydy.</translation>
<translation id="7508255263130623398">Palautettu käytännön laitetunnus on tyhjä tai ei vastaa nykyistä laitetunnusta.</translation>
@@ -904,7 +910,6 @@
<translation id="7569952961197462199">Poistetaanko luottokortti Chromen tiedoista?</translation>
<translation id="7575800019233204241">"Yhteytesi ei ole salattu", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" tai "SSL-varmennevirhe"</translation>
<translation id="7578104083680115302">Voit maksaa sivustoilla ja sovelluksissa nopeasti eri laitteillasi käyttämällä Googleen tallennettuja kortteja.</translation>
-<translation id="7588950540487816470">Fyysinen web</translation>
<translation id="7592362899630581445">Palvelimen varmenne rikkoo nimirajoituksia.</translation>
<translation id="7598391785903975535">Alle <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ei voi käsitellä tätä pyyntöä tällä hetkellä.</translation>
@@ -1108,6 +1113,7 @@
<translation id="9148507642005240123">K&amp;umoa muokkaus</translation>
<translation id="9154194610265714752">Päivitetty</translation>
<translation id="9157595877708044936">Valmistellaan...</translation>
+<translation id="9168814207360376865">Salli sivustojen tarkastaa, oletko tallentanut maksutapoja</translation>
<translation id="9169664750068251925">Estä aina tämä sivusto</translation>
<translation id="9170848237812810038">K&amp;umoa</translation>
<translation id="917450738466192189">Palvelimen varmenne ei kelpaa.</translation>
@@ -1116,7 +1122,6 @@
<translation id="9207861905230894330">Artikkelin lisääminen epäonnistui.</translation>
<translation id="9215416866750762878">Sovellus estää Chromea muodostamasta turvallista yhteyttä tähän sivustoon</translation>
<translation id="9219103736887031265">Kuvat</translation>
-<translation id="933612690413056017">Ei internetyhteyttä</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">TYHJENNÄ LOMAKE</translation>
<translation id="939736085109172342">Uusi kansio</translation>
diff --git a/chromium/components/strings/components_strings_fil.xtb b/chromium/components/strings/components_strings_fil.xtb
index 729115a3e09..60bc1e8d9ee 100644
--- a/chromium/components/strings/components_strings_fil.xtb
+++ b/chromium/components/strings/components_strings_fil.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Pumili ng pahintulot para sa <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Mga kamakailang bookmark</translation>
<translation id="1113869188872983271">&amp;I-undo ang pagbabago sa ayos</translation>
+<translation id="1125573121925420732">Maaaring karaniwang may mga babala habang nag-a-update para sa seguridad ang mga website. Maaayos din ito sa lalong madaling panahon.</translation>
<translation id="1126551341858583091">Ang laki sa lokal na storage ay <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">OK ang cache ng patakaran</translation>
<translation id="1150979032973867961">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng operating system ng iyong computer ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Tiyaking normal na gumagana ang iyong koneksyon sa internet.&lt;/li&gt;
&lt;li&gt;Makipag-ugnayan sa may-ari ng website.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Inilagay mo ang iyong password sa site na hindi pinamamahalaan ng iyong organisasyon. Para protektahan ang account mo, huwag gamiting muli ang iyong password sa iba pang app at site.</translation>
<translation id="1263231323834454256">Listahan ng babasahin</translation>
<translation id="1264126396475825575">Ulat ng pag-crash na nakuha noong <ph name="CRASH_TIME" /> (hindi pa naa-upload o nababalewala)</translation>
<translation id="1270502636509132238">Paraan sa Pag-pick up</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Pumili</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1623104350909869708">Pigilan ang pahinang ito sa paggawa ng mga karagdagang dialog</translation>
-<translation id="1629803312968146339">Gusto mo bang i-save ng Chrome ang card na ito?</translation>
<translation id="1639239467298939599">Naglo-load</translation>
<translation id="1640180200866533862">Mga patakaran ng user</translation>
<translation id="1640244768702815859">Subukang <ph name="BEGIN_LINK" />bisitahin ang homepage ng site<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Subukang patakbuhin ang Windows Network Diagnostics<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Mangyaring i-update ang iyong passphrase ng pag-sync.</translation>
<translation id="1787142507584202372">Lalabas dito ang iyong mga bukas na tab</translation>
-<translation id="1789575671122666129">Mga Popup</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Pangalan ng Cardholder</translation>
<translation id="1806541873155184440">Idinagdag noong <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">I-restart ang iyong computer</translation>
<translation id="2113977810652731515">Card</translation>
<translation id="2114841414352855701">Binalewala dahil na-override ito ng <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Naghahanap ng mga kalapit na page sa Pisikal na Web</translation>
<translation id="213826338245044447">Mga Bookmark sa Mobile</translation>
<translation id="214556005048008348">Kanselahin ang pagbabayad</translation>
<translation id="2147827593068025794">Pag-sync sa Background</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Hindi nahanap ang patakaran</translation>
<translation id="2213606439339815911">Kinukuha ang mga entry...</translation>
<translation id="2218879909401188352">Ang mga umaatake na kasalukuyang nasa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ay maaaring mag-install ng mga mapanganib na app na makakapinsala sa iyong device, magdagdag ng mga hindi alam na singil sa mobile bill mo, o magnakaw ng iyong personal na impormasyon. <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Walang internet</translation>
<translation id="2230458221926704099">Ayusin ang iyong koneksyon gamit ang <ph name="BEGIN_LINK" />diagnostics app<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Ipadala ngayon</translation>
<translation id="225207911366869382">Hindi na gimagamit ang halagang ito para sa patakarang ito.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Alisin ang mga napiling item</translation>
<translation id="277133753123645258">Pamamaraan ng pagpapadala</translation>
<translation id="277499241957683684">Nawawalang tala ng device</translation>
+<translation id="2781030394888168909">I-export para sa MacOS</translation>
<translation id="2784949926578158345">Na-reset ang koneksyon.</translation>
<translation id="2788784517760473862">Mga tinatanggap na credit card</translation>
<translation id="2794233252405721443">Naka-block ang site</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Hindi nakumpirma ng Chrome ang iyong card sa pagkakataong ito. Pakisubukang muli sa ibang pagkakataon.</translation>
<translation id="3064966200440839136">Aalis sa incognito mode upang magbayad sa pamamagitan ng external na application. Magpatuloy?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Wala}=1{1 password}one{# password}other{# na password}}</translation>
-<translation id="3093245981617870298">Offline ka.</translation>
<translation id="3096100844101284527">Magdagdag ng Address sa Pag-pick up</translation>
<translation id="3105172416063519923">Asset ID:</translation>
<translation id="3109728660330352905">Wala kang pahintulot na tingnan ang page na ito.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Hindi makakonekta sa <ph name="HOST_NAME" /> sa kasalukuyan.</translation>
<translation id="3427092606871434483">Payagan (default)</translation>
<translation id="3427342743765426898">&amp;Gawing Muli ang Pag-e-edit</translation>
+<translation id="342781501876943858">Inirerekomenda ng Chromium na i-reset ang iyong password kung ginamit mo ito sa iba pang site.</translation>
<translation id="3431636764301398940">I-save ang card na ito sa device na ito</translation>
<translation id="3447661539832366887">Na-off ng may-ari ng device na ito ang larong dinosaur.</translation>
<translation id="3447884698081792621">Ipakita ang certificate (ibinigay ng <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Buksan ang page sa bagong Incognito window (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Nakuha ang ulat ng pag-crash noong <ph name="CRASH_TIME" />, na-upload noong <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Impormasyon sa certificate</translation>
-<translation id="3690164694835360974">Hindi ligtas ang pag-log in</translation>
<translation id="3704162925118123524">Ang network na ginagamit mo ay maaaring humiling sa iyo na bisitahin ang page ng pag-login nito.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Naglo-load...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Gamitin ang pangkalahatang default (Tukuyin)</translation>
<translation id="4165986682804962316">Mga setting ng site</translation>
-<translation id="4169947484918424451">Gusto mo bang i-save ng Chromium ang card na ito?</translation>
<translation id="4171400957073367226">Hindi wasto ang signature sa pag-verify</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> pang item}one{<ph name="ITEM_COUNT" /> pang item}other{<ph name="ITEM_COUNT" /> pang item}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">I-restart ang iyong device</translation>
<translation id="4277028893293644418">I-reset ang password</translation>
<translation id="4280429058323657511">, exp <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Lumipat</translation>
<translation id="4312866146174492540">I-block (default)</translation>
<translation id="4325863107915753736">Hindi nahanap ang artikulo</translation>
<translation id="4326324639298822553">Tingnan ang iyong petsa ng pag-expire at subukang muli</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Hindi na-detect ang computer na ito bilang pinamamahalaan ng enterprise kaya awtomatiko lang na mai-install ng patakaran ang mga extension na hino-host sa Chrome Webstore. Ang URL ng pag-update ng Chrome Webstore ay "<ph name="CWS_UPDATE_URL" />."</translation>
<translation id="4346197816712207223">Mga Tinatanggap na Credit Card</translation>
<translation id="4356973930735388585">Maaaring subukan ng mga attacker sa site na ito na mag-install ng mga mapanganib na program sa iyong computer na magnanakaw o magde-delete ng impormasyon mo (halimbawa, mga larawan, password, mensahe at credit card).</translation>
+<translation id="4358461427845829800">Pamahalaan ang mga paraan ng pagbabayad...</translation>
<translation id="4372948949327679948">Inaasahang <ph name="VALUE_TYPE" /> na halaga.</translation>
<translation id="4377125064752653719">Tinangka mong maabot ang <ph name="DOMAIN" />, subalit ang certificate na ipinakita ng server ay binawi ng nagbigay nito. Nangangahulugan ito na ang mga kredensyal sa seguridad na ipinakita ng server ay talagang hindi dapat pagkatiwalaan. Maaaring nakikipag-ugnay ka sa isang nang-aatake.</translation>
<translation id="4406896451731180161">mga resulta ng paghahanap</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Address sa Pag-pick up</translation>
<translation id="4424024547088906515">Hindi mapatunayan ng server na ito na ito ay <ph name="DOMAIN" />; hindi pinagkakatiwalaan ng Chrome ang certificate ng seguridad nito. Maaaring dulot ito ng maling configuration o isang umaatake na hinahadlangan ang iyong koneksyon.</translation>
<translation id="4432688616882109544">Hindi tinanggap ng <ph name="HOST_NAME" /> ang iyong certificate sa pag-log in o maaaring walang ibinigay.</translation>
+<translation id="4434045419905280838">Mga pop-up at pag-redirect</translation>
<translation id="443673843213245140">Hindi pinagana ang paggamit ng isang proxy ngunit tinutukoy ang isang tahasang configuration ng proxy.</translation>
<translation id="445100540951337728">Mga tinatanggap na debit card</translation>
<translation id="4506176782989081258">Error sa pagpapatunay: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Naka-disable ang pag-autofill sa pagbabayad</translation>
<translation id="4764776831041365478">Ang webpage sa <ph name="URL" /> ay maaaring pansamantalang hindi gumagana o maaaring permanente itong inilipat sa isang bagong web address.</translation>
<translation id="4771973620359291008">Isang hindi alam na error ang nangyari.</translation>
+<translation id="4785689107224900852">Lumipat sa tab na ito</translation>
<translation id="4792143361752574037">Nagkaproblema sa pag-access sa mga session file. Kasalukuyang naka-disable ang pag-save sa disk. Paki-reload ang page upang subukang muli.</translation>
<translation id="4800132727771399293">Tingnan ang iyong petsa ng pag-expire at CVC at subukang muli</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil nagpadala ang website ng mga gulu-gulong kredensyal na hindi maproseso ng Google Chrome. Kadalasang pansamantala lang ang mga error at atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="4813512666221746211">Error sa network</translation>
<translation id="4816492930507672669">Pagkasyahin sa pahina</translation>
-<translation id="483020001682031208">Walang maipakitang page ng Pisikal na Web</translation>
<translation id="4850886885716139402">View</translation>
<translation id="4854362297993841467">Hindi available ang pamamaraan ng paghahatid na ito. Sumubok ng ibang pamamaraan.</translation>
<translation id="4858792381671956233">Tinanong mo sa iyong mga magulang kung maaari mong bisitahin ang site na ito</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bit)</translation>
<translation id="5121084798328133320">Pagkatapos mong magkumpirma, ibabahagi sa site na ito ang mga detalye ng card mula sa iyong Google Payments account.</translation>
<translation id="5128122789703661928">Hindi valid ang session na may ganitong pangalan upang ma-delete.</translation>
+<translation id="5135404736266831032">Pamahalaan ang mga address...</translation>
<translation id="5141240743006678641">I-encrypt ang mga naka-sync na password gamit ang iyong mga kredensyal sa Google</translation>
<translation id="5145883236150621069">May code ng error sa tugon sa patakaran</translation>
<translation id="5159010409087891077">Buksan ang page sa bagong Incognito window (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Isinasaad ng naka-embed na page sa page na ito na</translation>
<translation id="5205222826937269299">Kailangan ng pangalan</translation>
<translation id="5222812217790122047">Kailangan ng email</translation>
-<translation id="522700295135997067">Maaaring ninakaw ng site na ito ang iyong password</translation>
<translation id="5230733896359313003">Address na Padadalhan</translation>
<translation id="5250209940322997802">"Kumonekta sa network"</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Ang URL ng site na ito sa intranet ng kumpanya, organisasyon o paaralan ay kapareho ng URL ng isang external na website.
<ph name="LINE_BREAK" />
Subukang makipag-ugnayan sa iyong system administrator.</translation>
-<translation id="5499929369096410817">Ilagay ang panseguridad na code na para sa <ph name="CREDIT_CARD" />. Hindi ise-save ang code na ito.</translation>
<translation id="5509780412636533143">Mga pinamamahalaang bookmark</translation>
<translation id="5510766032865166053">Maaaring inilipat o na-delete ito.</translation>
<translation id="5523118979700054094">Pangalan ng patakaran</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Magdagdag ng Address sa Pagpapadala</translation>
<translation id="5689199277474810259">I-export sa JSON</translation>
<translation id="5689516760719285838">Lokasyon</translation>
+<translation id="570530837424789914">Pamahalaan...</translation>
<translation id="5710435578057952990">Ang pagkilala ng website na ito ay hindi natukoy.</translation>
<translation id="5719499550583120431">Tinatanggap ang mga prepaid card.</translation>
<translation id="5720705177508910913">Kasalukuyang user</translation>
+<translation id="5730040223043577876">Inirerekomenda ng Chrome na i-reset ang iyong password kung ginamit mo ito sa iba pang site.</translation>
<translation id="5732392974455271431">Maaari itong i-unblock ng iyong mga magulang para sa iyo</translation>
<translation id="5763042198335101085">Maglagay ng wastong email address</translation>
<translation id="5765072501007116331">Upang makita ang mga pamamaraan at kinakailangan sa paghahatid, pumili ng address</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Awtomatikong magpadala ng ilang <ph name="BEGIN_WHITEPAPER_LINK" />impormasyon sa system at content ng page<ph name="END_WHITEPAPER_LINK" /> sa Google upang makatulong na tumukoy ng mapapanganib na app at site. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">I-edit ang Impormasyon ng Contact</translation>
<translation id="5967867314010545767">Alisin sa history</translation>
-<translation id="5972020793760134803">Lumipat sa tab</translation>
<translation id="5975083100439434680">Mag-zoom out</translation>
-<translation id="597552863672748783">Kumpirmahin ang panseguridad na code</translation>
<translation id="598637245381783098">Hindi mabuksan ang app sa pagbabayad</translation>
<translation id="5989320800837274978">Hindi tunukoy ang alinman sa mga hindi nababagong proxy server o isang .pac script URL.</translation>
<translation id="5990559369517809815">Na-block ng isang extension ang mga kahilingan sa server.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Maaaring subukan ng content na ito na linlangin kang mag-install ng software o maghayag ng personal na impormasyon. <ph name="BEGIN_LINK" />Ipakita pa rin<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Hindi mo maaaring bisitahin ang <ph name="SITE" /> sa ngayon dahil gumagamit ng pag-pin ng certificate ang website. Karaniwang pansamantala lang ang mga error at pag-atake sa network, kaya malamang na gagana ang page na ito sa ibang pagkakataon.</translation>
<translation id="6059925163896151826">Mga USB device</translation>
+<translation id="6071091556643036997">Invalid ang uri ng patakaran.</translation>
<translation id="6080696365213338172">Nag-access ka ng nilalaman gamit ang isang certificate na ibinigay ng administrator. Maaaring harangin ng iyong administrator ang data na ibibigay mo sa <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">Maaaring may iba pang anyo ng history ng pag-browse ang iyong Google Account sa <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Wala}=1{1 password (naka-sync)}one{# password (naka-sync)}other{# na password (naka-sync)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Magdagdag ng higit pang impormasyon</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Muling pagsusumite ng Form sa Pagkumpirma</translation>
+<translation id="6465306955648956876">Pamahalaan ang mga password...</translation>
<translation id="647261751007945333">Mga patakaran sa device</translation>
<translation id="6477321094435799029">May natukoy na kakaibang code ang Chrome sa page na ito at na-block ito upang protektahan ang iyong personal na impormasyon (halimbawa, mga password, numero ng telepono at credit card).</translation>
<translation id="6489534406876378309">Simulang mag-upload ng mga pag-crash</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Paghahanap ng <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Maaaring magtangka ang mga attacker na kasalukuyang nasa <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> na mag-install ng mga mapanganib na program sa iyong Mac na magnanakaw o magde-delete ng impormasyon mo (halimbawa, mga larawan, password, mensahe, at credit card). <ph name="BEGIN_LEARN_MORE_LINK" />Matuto pa<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Hindi na ginagamit ang patakarang ito.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Wala}=1{Mula sa 1 site (hindi ka masa-sign out sa iyong Google Account)}one{Mula sa # site (hindi ka masa-sign out sa iyong Google Account)}other{Mula sa # na site (hindi ka masa-sign out sa iyong Google Account)}}</translation>
<translation id="6657585470893396449">Password</translation>
<translation id="6671697161687535275">Gusto mo bang alisin ang form para sa suhestyon sa Chromium?</translation>
<translation id="6685834062052613830">Mag-sign out at kumpletuhin ang setup</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">User:</translation>
<translation id="6945221475159498467">Pumili</translation>
<translation id="6948701128805548767">Upang makita ang mga pamamaraan at kinakailangan sa pag-pick up, pumili ng address</translation>
+<translation id="6949872517221025916">I-reset ang Password</translation>
<translation id="6957887021205513506">Lumilitaw na isang pamamalsipika ang certificate ng server.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Device</translation>
@@ -820,7 +825,7 @@
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7029809446516969842">Mga Password</translation>
<translation id="7050187094878475250">Sinubukan mong puntahan ang <ph name="DOMAIN" />, ngunit nagpakita ang server ng certificate na masyadong mahaba ang panahon ng pagkakaroon ng bisa upang maging mapagkakatiwalaan.</translation>
-<translation id="7053983685419859001">Harangan</translation>
+<translation id="7053983685419859001">I-block</translation>
<translation id="7064851114919012435">Impormasyon sa pakikipag-ugnayan</translation>
<translation id="7079718277001814089">Naglalaman ng malware ang site na ito</translation>
<translation id="7087282848513945231">County</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Pamamaraan ng paghahatid</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> pa}one{<ph name="PAYMENT_METHOD_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> pa}other{<ph name="PAYMENT_METHOD_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> pa}}</translation>
-<translation id="7155487117670177674">Hindi ligtas ang pagbabayad</translation>
+<translation id="717330890047184534">Gaia ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> pa}one{<ph name="SHIPPING_OPTION_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> pa}other{<ph name="SHIPPING_OPTION_PREVIEW" /> at <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> pa}}</translation>
<translation id="7180611975245234373">I-refresh</translation>
<translation id="7182878459783632708">Walang nakatakdang mga patakaran</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Gamitin ang pangkalahatang default (I-block)</translation>
<translation id="7460163899615895653">Lumalabas dito ang mga kamakailan mong tab mula sa iba pang mga device</translation>
<translation id="7469372306589899959">Kinukumpirma ang card</translation>
+<translation id="7473891865547856676">Hindi, Salamat</translation>
<translation id="7481312909269577407">Sumulong</translation>
<translation id="7485870689360869515">Walang nahanap na data.</translation>
<translation id="7508255263130623398">Walang laman ang ibinalik na device id ng patakaran o hindi ito tumutugma sa kasalukuyang device id</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Alisin ang credit card sa Chrome?</translation>
<translation id="7575800019233204241">"Hindi pribado ang iyong koneksyon" o "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" o "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" o "Error sa SSL certificate"</translation>
<translation id="7578104083680115302">Magbayad nang mabilis sa mga site at app sa iba't ibang device gamit ang mga card na na-save mo sa Google.</translation>
-<translation id="7588950540487816470">Pisikal na Web</translation>
<translation id="7592362899630581445">Lumabag ang certificate ng server sa limitasyon sa pangalan.</translation>
<translation id="7598391785903975535">Wala pang <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Sa kasalukuyan, hindi magagawa ng <ph name="HOST_NAME" /> ang kahilingang ito.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;I-undo ang pag-e-edit</translation>
<translation id="9154194610265714752">Na-update</translation>
<translation id="9157595877708044936">Nagse-set up...</translation>
+<translation id="9168814207360376865">Payagan ang mga site na tingnan kung may mga naka-save kang paraan ng pagbabayad</translation>
<translation id="9169664750068251925">Palaging i-block sa site na ito</translation>
<translation id="9170848237812810038">&amp;I-undo</translation>
<translation id="917450738466192189">Di-wastong certificate ng server.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Hindi naidagdag ang artikulo.</translation>
<translation id="9215416866750762878">Pinipigilan ng isang application na makakonekta nang ligtas ang Chrome sa site na ito</translation>
<translation id="9219103736887031265">Mga Larawan</translation>
-<translation id="933612690413056017">Walang koneksyon sa Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">CLEAR FORM</translation>
<translation id="939736085109172342">Bagong folder</translation>
diff --git a/chromium/components/strings/components_strings_fr.xtb b/chromium/components/strings/components_strings_fr.xtb
index 7f8b2e301e5..3c8a644f7f7 100644
--- a/chromium/components/strings/components_strings_fr.xtb
+++ b/chromium/components/strings/components_strings_fr.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Sélectionnez une autorisation pour <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Favoris consultés récemment</translation>
<translation id="1113869188872983271">&amp;Annuler la réorganisation</translation>
+<translation id="1125573121925420732">Les avertissements peuvent être fréquents en attendant que les sites Web finissent de mettre à jour leurs systèmes de sécurité. Ce problème devrait être bientôt résolu.</translation>
<translation id="1126551341858583091">La taille sur l'espace de stockage local est de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache de la règle valide.</translation>
<translation id="1150979032973867961">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité n'est pas considéré comme fiable par le système d'exploitation de votre ordinateur. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Assurez-vous que votre connexion Internet fonctionne normalement.&lt;/li&gt;
&lt;li&gt;Contactez le propriétaire du site.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Vous avez saisi votre mot de passe sur un site qui n'est pas géré par votre organisation. Pour protéger votre compte, ne réutilisez pas ce mot de passe dans d'autres applications ni sur d'autres sites.</translation>
<translation id="1263231323834454256">Liste de lecture</translation>
<translation id="1264126396475825575">Rapport d'erreur enregistré le <ph name="CRASH_TIME" /> (pas encore importé ou ignoré)</translation>
<translation id="1270502636509132238">Mode d'enlèvement</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Sélectionner</translation>
<translation id="1620510694547887537">Appareil photo</translation>
<translation id="1623104350909869708">Empêcher cette page de générer des boîtes de dialogue supplémentaires</translation>
-<translation id="1629803312968146339">Voulez-vous que cette carte soit enregistrée dans Chrome ?</translation>
<translation id="1639239467298939599">Chargement en cours</translation>
<translation id="1640180200866533862">Règles relatives aux utilisateurs</translation>
<translation id="1640244768702815859">Essayez de <ph name="BEGIN_LINK" />consulter la page d'accueil du site<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Essayez d'exécuter les diagnostics réseau de Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Mettre à jour votre phrase secrète de synchronisation</translation>
<translation id="1787142507584202372">Les onglets ouverts s'affichent ici</translation>
-<translation id="1789575671122666129">Fenêtres pop-up</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nom du titulaire de la carte</translation>
<translation id="1806541873155184440">Date d'ajout : <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Redémarrez l'ordinateur</translation>
<translation id="2113977810652731515">Carte</translation>
<translation id="2114841414352855701">Ignorée parce que remplacée par <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Recherche de pages Web physique à proximité</translation>
<translation id="213826338245044447">Favoris sur mobile</translation>
<translation id="214556005048008348">Annuler le paiement</translation>
<translation id="2147827593068025794">Synchronisation en arrière-plan</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Règle introuvable.</translation>
<translation id="2213606439339815911">Obtention des entrées en cours…</translation>
<translation id="2218879909401188352">Les pirates informatiques qui contrôlent le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> peuvent installer des applications dangereuses qui endommagent votre appareil, ajoutent des frais cachés à votre facture de téléphonie mobile ou dérobent vos informations personnelles. <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Aucun accès à Internet</translation>
<translation id="2230458221926704099">Vérifiez la connexion à l'aide de l'<ph name="BEGIN_LINK" />application de diagnostic<ph name="END_LINK" />.</translation>
<translation id="2239100178324503013">Envoyer maintenant</translation>
<translation id="225207911366869382">Cette valeur n'est plus utilisée dans le cadre de cette règle.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Supprimer les éléments sélectionnés</translation>
<translation id="277133753123645258">Mode d'expédition</translation>
<translation id="277499241957683684">Enregistrement de l'appareil manquant.</translation>
+<translation id="2781030394888168909">Exporter pour MacOS</translation>
<translation id="2784949926578158345">La connexion a été réinitialisée.</translation>
<translation id="2788784517760473862">Cartes de crédit acceptées</translation>
<translation id="2794233252405721443">Site bloqué</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Impossible de valider votre carte dans Chrome pour le moment. Veuillez réessayer plus tard.</translation>
<translation id="3064966200440839136">En payant via une application externe, vous allez quitter le mode navigation privée. Voulez-vous continuer ?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Aucun}=1{1 mot de passe}one{# mot de passe}other{# mots de passe}}</translation>
-<translation id="3093245981617870298">Vous êtes actuellement hors connexion</translation>
<translation id="3096100844101284527">Ajouter une adresse d'enlèvement</translation>
<translation id="3105172416063519923">ID d'élément :</translation>
<translation id="3109728660330352905">Vous n'êtes pas autorisé à consulter cette page.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> est actuellement inaccessible.</translation>
<translation id="3427092606871434483">Autoriser (par défaut)</translation>
<translation id="3427342743765426898">&amp;Rétablir la modification</translation>
+<translation id="342781501876943858">L'équipe Chromium vous recommande de réinitialiser votre mot de passe si vous l'avez réutilisé sur d'autres sites.</translation>
<translation id="3431636764301398940">Enregistrer cette carte sur cet appareil</translation>
<translation id="3447661539832366887">Le propriétaire de cet appareil a désactivé le jeu avec le dinosaure.</translation>
<translation id="3447884698081792621">Afficher le certificat (émis par <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Ouvrir la page dans une nouvelle fenêtre de navigation privée (Ctrl+Maj+N)</translation>
<translation id="3679803492151881375">Rapport d'erreur enregistré le <ph name="CRASH_TIME" /> et importé le <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informations relatives au certificat</translation>
-<translation id="3690164694835360974">Connexion non sécurisée</translation>
<translation id="3704162925118123524">Pour utiliser ce réseau, il est possible que vous deviez vous rendre sur la page de connexion correspondante.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Chargement en cours...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utiliser la valeur par défaut globale (Détection)</translation>
<translation id="4165986682804962316">Paramètres du site</translation>
-<translation id="4169947484918424451">Voulez-vous que cette carte soit enregistrée dans Chromium ?</translation>
<translation id="4171400957073367226">Signature de validation non valide.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> élément supplémentaire}one{<ph name="ITEM_COUNT" /> élément supplémentaire}other{<ph name="ITEM_COUNT" /> éléments supplémentaires}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Redémarrer l'appareil</translation>
<translation id="4277028893293644418">Réinitialiser le mot de passe</translation>
<translation id="4280429058323657511">, expiration le <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Changer</translation>
<translation id="4312866146174492540">Bloquer (par défaut)</translation>
<translation id="4325863107915753736">Échec de la recherche de l'article.</translation>
<translation id="4326324639298822553">Veuillez vérifier la date d'expiration, puis réessayer</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Cet ordinateur n'est pas détecté comme étant géré par une entreprise. Selon la règle définie, seules les extensions hébergées par le Chrome Web Store peuvent y être installées. L'URL de mise à jour du Chrome Web Store est "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Cartes de crédit acceptées</translation>
<translation id="4356973930735388585">Des individus malveillants à l'œuvre sur ce site pourraient tenter d'installer des applications dangereuses sur votre ordinateur afin de récupérer ou de supprimer certaines informations : photos, mots de passe, messages, numéros de carte de paiement, etc.</translation>
+<translation id="4358461427845829800">Gérer les modes de paiement…</translation>
<translation id="4372948949327679948">Valeur attendue : <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Vous avez tenté d'accéder à <ph name="DOMAIN" />, mais le certificat présenté par le serveur a été révoqué par son émetteur. Cela signifie que le certificat présenté par le serveur ne doit pas être approuvé. Il est donc possible que vous communiquiez avec un pirate informatique.</translation>
<translation id="4406896451731180161">résultats de recherche</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Adresse d'enlèvement</translation>
<translation id="4424024547088906515">Impossible de vérifier sur le serveur qu'il s'agit bien du domaine <ph name="DOMAIN" />, car son certificat de sécurité n'est pas considéré comme fiable par Chrome. Cela peut être dû à une mauvaise configuration ou bien à l'interception de votre connexion par un pirate informatique.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> n'a pas accepté votre certificat de connexion, ou vous ne l'avez pas fourni.</translation>
+<translation id="4434045419905280838">Pop-ups et redirections</translation>
<translation id="443673843213245140">L'utilisation d'un proxy est désactivée, mais une configuration de proxy explicite est spécifiée.</translation>
<translation id="445100540951337728">Cartes de débit acceptées</translation>
<translation id="4506176782989081258">Erreur de validation : <ph name="VALIDATION_ERROR" />.</translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Saisie automatique des cartes de paiement désactivée</translation>
<translation id="4764776831041365478">Il se peut que la page Web à l'adresse <ph name="URL" /> soit temporairement inaccessible ou qu'elle ait été déplacée de façon permanente à une autre adresse Web.</translation>
<translation id="4771973620359291008">Une erreur inconnue s'est produite.</translation>
+<translation id="4785689107224900852">Passer à cet onglet</translation>
<translation id="4792143361752574037">Un problème est survenu lors de l'accès aux fichiers de session. L'enregistrement sur disque est actuellement désactivé. Veuillez actualiser la page pour réessayer.</translation>
<translation id="4800132727771399293">Veuillez vérifier la date d'expiration et le code CVC, puis réessayez.</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102"><ph name="SITE" /> est actuellement inaccessible. Le site Web a envoyé des identifiants brouillés inutilisables par Google Chrome. Les erreurs de réseau et les attaques étant généralement temporaires, cette page devrait à nouveau fonctionner ultérieurement.</translation>
<translation id="4813512666221746211">Erreur réseau.</translation>
<translation id="4816492930507672669">Ajuster à la page</translation>
-<translation id="483020001682031208">Aucune page Web physique à afficher</translation>
<translation id="4850886885716139402">Afficher</translation>
<translation id="4854362297993841467">Mode de livraison non disponible. Choisissez-en un autre.</translation>
<translation id="4858792381671956233">Une demande d'autorisation a été envoyée à tes parents pour la consultation de ce site</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bits)</translation>
<translation id="5121084798328133320">Une fois la validation terminée, les informations relatives à la carte de votre compte Google Payments seront partagées avec ce site.</translation>
<translation id="5128122789703661928">Impossible de supprimer la session qui porte ce nom.</translation>
+<translation id="5135404736266831032">Gérer les adresses…</translation>
<translation id="5141240743006678641">Chiffrer les mots de passe synchronisés avec vos informations de connexion Google</translation>
<translation id="5145883236150621069">Code d'erreur présent dans la réponse de la règle.</translation>
<translation id="5159010409087891077">Ouvrir la page dans une nouvelle fenêtre de navigation privée (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Une page intégrée à cette page Web indique</translation>
<translation id="5205222826937269299">Veuillez saisir un nom</translation>
<translation id="5222812217790122047">Veuillez saisir une adresse e-mail</translation>
-<translation id="522700295135997067">Ce site vient peut-être de dérober votre mot de passe</translation>
<translation id="5230733896359313003">Adresse de livraison</translation>
<translation id="5250209940322997802">"Se connecter au réseau"</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Ce site situé sur l'intranet de l'entreprise, de l'organisation ou de l'établissement scolaire possède la même URL qu'un site Web externe.
<ph name="LINE_BREAK" />
Essayez de contacter votre administrateur système.</translation>
-<translation id="5499929369096410817">Saisissez le code de sécurité de la carte <ph name="CREDIT_CARD" />. Ce code ne sera pas enregistré.</translation>
<translation id="5509780412636533143">Favoris gérés</translation>
<translation id="5510766032865166053">Il a peut-être été déplacé ou supprimé.</translation>
<translation id="5523118979700054094">Nom de la règle</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Ajouter une adresse de livraison</translation>
<translation id="5689199277474810259">Exporter au format JSON</translation>
<translation id="5689516760719285838">Position</translation>
+<translation id="570530837424789914">Gérer…</translation>
<translation id="5710435578057952990">L'identité de ce site Web n'a pas été vérifiée.</translation>
<translation id="5719499550583120431">Les cartes prépayées sont acceptées.</translation>
<translation id="5720705177508910913">Utilisateur actuel</translation>
+<translation id="5730040223043577876">L'équipe Chrome vous recommande de réinitialiser votre mot de passe si vous l'avez réutilisé sur d'autres sites.</translation>
<translation id="5732392974455271431">Tes parents peuvent te le débloquer</translation>
<translation id="5763042198335101085">Saisissez une adresse e-mail valide</translation>
<translation id="5765072501007116331">Sélectionnez une adresse pour consulter les modes et conditions de livraison disponibles</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Envoyer automatiquement <ph name="BEGIN_WHITEPAPER_LINK" />des informations système et du contenu de page<ph name="END_WHITEPAPER_LINK" /> à Google afin de faciliter la détection d'applications et de sites dangereux. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Modifier les coordonnées</translation>
<translation id="5967867314010545767">Supprimer de l'historique</translation>
-<translation id="5972020793760134803">Ouvrir un autre onglet</translation>
<translation id="5975083100439434680">Zoom arrière</translation>
-<translation id="597552863672748783">Confirmer le code de sécurité</translation>
<translation id="598637245381783098">Impossible d'ouvrir l'application de paiement</translation>
<translation id="5989320800837274978">Aucun serveur proxy déterminé ou URL de script .pac n'a été indiqué.</translation>
<translation id="5990559369517809815">Les requêtes vers le serveur ont été bloquées par une extension.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Ce contenu peut vous inciter à installer un logiciel ou vous soutirer des informations personnelles. <ph name="BEGIN_LINK" />Je souhaite y accéder malgré tout.<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Le site <ph name="SITE" /> est actuellement inaccessible, car il utilise l'épinglage des certificats. Les erreurs réseau et les attaques sont généralement temporaires. Vous devriez donc pouvoir accéder à cette page plus tard.</translation>
<translation id="6059925163896151826">Appareils USB</translation>
+<translation id="6071091556643036997">Ce type de règle n'est pas valide.</translation>
<translation id="6080696365213338172">Vous avez accédé à du contenu à l'aide d'un certificat fourni par l'administrateur. Les données que vous fournissez à <ph name="DOMAIN" /> peuvent être interceptées par votre administrateur.</translation>
<translation id="610911394827799129">Votre compte Google conserve peut-être d'autres contenus d'historique de navigation sur la page <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Aucun}=1{1 mot de passe (synchronisé)}one{# mot de passe (synchronisé)}other{# mots de passe (synchronisés)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Ajouter d'autres informations</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Confirmer le nouvel envoi du formulaire</translation>
+<translation id="6465306955648956876">Gérer les mots de passe…</translation>
<translation id="647261751007945333">Règles relatives aux appareils</translation>
<translation id="6477321094435799029">Chrome a détecté un code inhabituel sur cette page et a bloqué cette dernière pour protéger vos informations personnelles (mots de passe, numéros de téléphone et de cartes de paiement).</translation>
<translation id="6489534406876378309">Lancer l'importation des plantages</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Recherche <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Des individus malveillants à l'œuvre sur le site <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pourraient tenter d'installer des programmes dangereux sur votre Mac afin de récupérer ou de supprimer certaines informations (photos, mots de passe, messages ou numéros de carte de crédit, par exemple). <ph name="BEGIN_LEARN_MORE_LINK" />En savoir plus<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Cette règle est obsolète.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Aucun}=1{De 1 site (vous ne serez pas déconnecté de votre compte Google)}one{De # site (vous ne serez pas déconnecté de votre compte Google)}other{De # sites (vous ne serez pas déconnecté de votre compte Google)}}</translation>
<translation id="6657585470893396449">Mot de passe</translation>
<translation id="6671697161687535275">Supprimer la suggestion de saisie de formulaire de Chromium ?</translation>
<translation id="6685834062052613830">Déconnectez-vous et complétez la configuration.</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Utilisateur :</translation>
<translation id="6945221475159498467">Sélectionner</translation>
<translation id="6948701128805548767">Sélectionnez une adresse pour consulter les modes et conditions d'enlèvement disponibles</translation>
+<translation id="6949872517221025916">Réinitialiser le mot de passe</translation>
<translation id="6957887021205513506">Le certificat du serveur semble être contrefait.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Périphérique</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Mode de livraison</translation>
<translation id="7139724024395191329">Émirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> autre}one{<ph name="PAYMENT_METHOD_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> autre}other{<ph name="PAYMENT_METHOD_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> autres}}</translation>
-<translation id="7155487117670177674">Paiement non sécurisé</translation>
+<translation id="717330890047184534">Identifiant GAIA :</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> autre}one{<ph name="SHIPPING_OPTION_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> autre}other{<ph name="SHIPPING_OPTION_PREVIEW" /> et <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> autres}}</translation>
<translation id="7180611975245234373">Actualiser</translation>
<translation id="7182878459783632708">Aucune règle n'est définie</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Utiliser le paramètre global par défaut ("Bloquer")</translation>
<translation id="7460163899615895653">Les onglets que vous avez utilisés récemment sur d'autres appareils s'affichent ici</translation>
<translation id="7469372306589899959">Validation de la carte…</translation>
+<translation id="7473891865547856676">Non, merci</translation>
<translation id="7481312909269577407">Avancer</translation>
<translation id="7485870689360869515">Aucune donnée n'a été trouvée.</translation>
<translation id="7508255263130623398">L'ID d'appareil de la règle renvoyé est vide ou ne correspond pas à l'ID d'appareil actuel.</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Supprimer les données de carte de paiement de Chrome ?</translation>
<translation id="7575800019233204241">"Votre connexion n'est pas privée", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" ou "SSL certificate error"</translation>
<translation id="7578104083680115302">Payez rapidement sur des sites et dans des applications sur tous vos appareils au moyen de cartes que vous avez enregistrées sur Google.</translation>
-<translation id="7588950540487816470">Web physique</translation>
<translation id="7592362899630581445">Le certificat du serveur ne respecte pas les restrictions de noms.</translation>
<translation id="7598391785903975535">Moins de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Impossible de traiter cette demande via <ph name="HOST_NAME" /> à l'heure actuelle.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Annuler la modification</translation>
<translation id="9154194610265714752">Mis à jour</translation>
<translation id="9157595877708044936">Configuration en cours...</translation>
+<translation id="9168814207360376865">Autoriser les sites à vérifier si vous avez enregistré des modes de paiement</translation>
<translation id="9169664750068251925">Toujours bloquer sur ce site</translation>
<translation id="9170848237812810038">Ann&amp;uler</translation>
<translation id="917450738466192189">Le certificat du serveur n'est pas valide.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Échec de l'ajout de l'article.</translation>
<translation id="9215416866750762878">Une application empêche Chrome de se connecter à ce site de manière sécurisée</translation>
<translation id="9219103736887031265">Images</translation>
-<translation id="933612690413056017">Aucune connexion Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">EFFACER LE FORMULAIRE</translation>
<translation id="939736085109172342">Nouveau dossier</translation>
diff --git a/chromium/components/strings/components_strings_gu.xtb b/chromium/components/strings/components_strings_gu.xtb
index 3ae425ce4a5..982957da719 100644
--- a/chromium/components/strings/components_strings_gu.xtb
+++ b/chromium/components/strings/components_strings_gu.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> માટે પરવાનગી પસંદ કરો</translation>
<translation id="1111153019813902504">હાલનાં બુકમાર્ક્સ</translation>
<translation id="1113869188872983271">&amp;પુનઃક્રમાંકિત કરવું પૂર્વવત્ કરો</translation>
+<translation id="1125573121925420732">વેબસાઇટ તેમની સુરક્ષા અપડેટ કરી રહ્યાં હોય ત્યારે ચેતવણીઓ દેખાવી સામાન્ય બાબત છે. ટૂંક સમયમાં જ આમાં સુધારો કરવામાં આવશે.</translation>
<translation id="1126551341858583091">સ્થાનિક સ્ટોરેજ પરનું કદ <ph name="CRASH_SIZE" /> છે.</translation>
<translation id="112840717907525620">નીતિ કેશ ઓકે</translation>
<translation id="1150979032973867961">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર તમારા કમ્પ્યુટરની ઑપરેટિંગ સિસ્ટમ દ્વારા વિશ્વસનીય નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;ખાતરી કરો કે તમારું ઇન્ટરનેટ કનેક્શન બરાબર કાર્ય કરી રહ્યું છે.&lt;/li&gt;
&lt;li&gt;વેબસાઇટના માલિકનો સંપર્ક કરો.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">તમે એવી સાઇટ પર તમારો પાસવર્ડ દાખલ કર્યો છે જે તમારી સંસ્થા દ્વારા મેનેજ કરવામાં આવતી નથી. તમારા એકાઉન્ટને સુરક્ષિત કરવા માટે, અન્ય ઍપ અને સાઇટ પર તમારા પાસવર્ડનો ફરી ઉપયોગ કરશો નહીં.</translation>
<translation id="1263231323834454256">વાચન સૂચિ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> એ ક્રેશ રિપોર્ટ કૅપ્ચર કરવામાં આવી (હજી સુધી અપલોડ કરવામાં કે અવગણવામાં આવેલ નથી)</translation>
<translation id="1270502636509132238">પિકઅપ પદ્ધતિ</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">પસંદ કરો</translation>
<translation id="1620510694547887537">કૅમેરો</translation>
<translation id="1623104350909869708">આ પૃષ્ઠને વધારાના સંવાદો બનાવતા અટકાવો</translation>
-<translation id="1629803312968146339">શું તમે ઇચ્છો છો કે Chrome આ કાર્ડ સાચવે?</translation>
<translation id="1639239467298939599">લોડ કરી રહ્યું છે</translation>
<translation id="1640180200866533862">વપરાશકર્તા નીતિઓ</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />સાઇટના હોમપેજની મુલાકાત લેવાનો<ph name="END_LINK" /> પ્રયાસ કરો.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows નેટવર્ક ડાયગ્નોસ્ટિક્સ ચલાવવાનો પ્રયાસ કરો<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">કૃપા કરી તમારા સમન્વયન પાસફ્રેઝને અપડેટ કરો.</translation>
<translation id="1787142507584202372">તમારા ખુલ્લા ટૅબ્સ અહીં દેખાય છે</translation>
-<translation id="1789575671122666129">પૉપઅપ્સ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">કાર્ડધારકનું નામ</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> ના રોજ ઉમેર્યું</translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">તમારું કમ્પ્યુટર પુનઃપ્રારંભ કરો</translation>
<translation id="2113977810652731515">કાર્ડ</translation>
<translation id="2114841414352855701">અવગણ્યું કારણ કે તે <ph name="POLICY_NAME" /> દ્વારા ઓવરરાઇડ થયું હતું.</translation>
-<translation id="2138201775715568214">નજીકના વાસ્તવિક વેબ પૃષ્ઠોને શોધી રહ્યાં છો</translation>
<translation id="213826338245044447">મોબાઇલ બુકમાર્ક્સ</translation>
<translation id="214556005048008348">ચુકવણી રદ કરો</translation>
<translation id="2147827593068025794">પૃષ્ઠભૂમિ સમન્વયન</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">નીતિ મળી નથી</translation>
<translation id="2213606439339815911">પ્રવિષ્ટિઓનું આનયન કરી રહ્યાં છે...</translation>
<translation id="2218879909401188352">હાલમાં હુમલાખોરો <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પર જોખમકારક ઍપ્લિકેશન ઇન્સ્ટૉલ કરી શકે છે જે તમારા ઉપકરણને નુકસાન પહોંચાડે છે, તમારા મોબાઇલ બિલમાં છુપાયેલા ચાર્જ ઉમેરી શકે છે અથવા તમારી વ્યક્તિગત માહિતી ચોરી શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધુ જાણો<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ઇન્ટરનેટ ઍક્સેસ નથી</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ડાયગ્નોસ્ટિક્સ ઍપ્લિકેશન<ph name="END_LINK" />નો ઉપયોગ કરીને તમારું કનેક્શન ઠીક કરો</translation>
<translation id="2239100178324503013">હમણાં મોકલો</translation>
<translation id="225207911366869382">આ નીતિ માટે આ મૂલ્યને નાપસંદ કરેલું છે.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">પસંદ કરેલી આઇટમ્સને દૂર કરો</translation>
<translation id="277133753123645258">વિતરણ પદ્ધતિ</translation>
<translation id="277499241957683684">ઉપકરણ રેકોર્ડ ખૂટે છે</translation>
+<translation id="2781030394888168909">MacOSના ફૉર્મેટમાં નિકાસ કરો</translation>
<translation id="2784949926578158345">કનેક્શન ફરીથી સેટ થયું.</translation>
<translation id="2788784517760473862">સ્વીકૃત ક્રેડિટ કાર્ડ</translation>
<translation id="2794233252405721443">સાઇટ અવરોધિત કરી</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">આ સમયે Chrome તમારા કાર્ડની પુષ્ટિ કરવામાં અસમર્થ હતું. કૃપા કરીને પછીથી ફરી પ્રયાસ કરો.</translation>
<translation id="3064966200440839136">બાહ્ય ઍપ્લિકેશન મારફતે ચુકવણી કરવા માટે છુપો મોડ છોડી રહ્યાં છીએ. તો ચાલુ રાખીએ?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{કોઈ નહીં}=1{1 પાસવર્ડ}one{# પાસવર્ડ}other{# પાસવર્ડ}}</translation>
-<translation id="3093245981617870298">તમે ઑફલાઇન છો</translation>
<translation id="3096100844101284527">પિકઅપ માટેનું સરનામું ઉમેરો</translation>
<translation id="3105172416063519923">સંપત્તિ ID:</translation>
<translation id="3109728660330352905">તમને આ પૃષ્ઠને જોવાની અધિકૃતિ નથી.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> હાલમાં પહોંચવા યોગ્ય નથી.</translation>
<translation id="3427092606871434483">મંજૂરી આપો (ડિફૉલ્ટ)</translation>
<translation id="3427342743765426898">&amp;સંપાદિત કરવું ફરી કરો</translation>
+<translation id="342781501876943858">જો તમે અન્ય સાઇટ પર તમારા પાસવર્ડનો ફરી ઉપયોગ કર્યો હોય, તો Chromium તેને રીસેટ કરવાનો સુઝાવ આપે છે.</translation>
<translation id="3431636764301398940">આ ઉપકરણ પર આ કાર્ડ સાચવો</translation>
<translation id="3447661539832366887">આ ઉપકરણના માલિકે ડાયનાસોર રમત બંધ કરી છે.</translation>
<translation id="3447884698081792621">(<ph name="ISSUER" /> દ્વારા રજૂ થયેલ) પ્રમાણપત્ર બતાવો</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">એક નવી છુપી વિંડોમાં પેજ ખોલો (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> એ ક્રેશ રિપોર્ટ કૅપ્ચર કરી અને <ph name="UPLOAD_TIME" /> એ અપલોડ કર્યો હતો</translation>
<translation id="3681007416295224113">પ્રમાણપત્ર માહિતી</translation>
-<translation id="3690164694835360974">લોગિન સુરક્ષિત નથી</translation>
<translation id="3704162925118123524">તમે ઉપયોગમાં લઈ રહ્યાં છો તે નેટવર્ક માટે, તમારે તેના લોગિન પૃષ્ઠની મુલાકાત લેવાની જરૂર હોઈ શકે છે.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">લોડ કરી રહ્યું છે...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">વૈશ્વિક ડિફોલ્ટનો ઉપયોગ કરો (શોધો)</translation>
<translation id="4165986682804962316">સાઇટ સેટિંગ્સ</translation>
-<translation id="4169947484918424451">શું તમે ઇચ્છો છો કે Chromium આ કાર્ડ સાચવે?</translation>
<translation id="4171400957073367226">ખોટી ચકાસણી સહી</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{વધુ <ph name="ITEM_COUNT" /> આઇટમ}one{વધુ <ph name="ITEM_COUNT" /> આઇટમ}other{વધુ <ph name="ITEM_COUNT" /> આઇટમ}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">તમારું ઉપકરણ પુનઃપ્રારંભ કરો</translation>
<translation id="4277028893293644418">પાસવર્ડ રીસેટ કરો</translation>
<translation id="4280429058323657511">, સમાપ્તિ તારીખ <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">સ્વિચ</translation>
<translation id="4312866146174492540">અવરોધિત કરો (ડિફૉલ્ટ)</translation>
<translation id="4325863107915753736">લેખ શોધવામાં નિષ્ફળ થયાં</translation>
<translation id="4326324639298822553">તમારી સમાપ્તિ તારીખ તપાસો અને ફરી પ્રયાસ કરો</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">આ કમ્પ્યુટર એન્ટરપ્રાઇઝ દ્વારા મેનેજ થતું હોય તેવું જણાયું નથી, તેથી નીતિ માત્ર Chrome Webstore પર હોસ્ટ થયેલા એક્સ્ટેન્શનો આપમેળે ઇન્સ્ટૉલ કરી શકશે. Chrome Webstore અપડેટનું URL "<ph name="CWS_UPDATE_URL" />" છે.</translation>
<translation id="4346197816712207223">સ્વીકૃત ક્રેડિટ કાર્ડ</translation>
<translation id="4356973930735388585">આ સાઇટ પરના હુમલાખોરો તમારા કમ્પ્યુટર પર તમારી માહિતી (ઉદાહરણ તરીકે, ફોટો, પાસવર્ડ્સ, સંદેશા અને ક્રેડિટ કાર્ડ્સ) ને ચોરી શકે કે કાઢી નાખે તેવા જોખમી પ્રોગ્રામ્સને ઇન્સ્ટોલ કરવાનો પ્રયાસ કરી શકે છે.</translation>
+<translation id="4358461427845829800">ચુકવણી પદ્ધતિઓ મેનેજ કરો…</translation>
<translation id="4372948949327679948">અપેક્ષિત <ph name="VALUE_TYPE" /> મૂલ્ય.</translation>
<translation id="4377125064752653719">તમે <ph name="DOMAIN" /> પર પહોંચવાનો પ્રયાસ કર્યો, પણ સર્વર દ્વારા પ્રસ્તુત કરવામાં આવેલું પ્રમાણપત્ર તેના રજૂકર્તા દ્વારા જ રદ કરવામાં આવ્યું છે. આનો અર્થ છે કે સર્વરે પ્રસ્તુત કરેલા સુરક્ષા પ્રમાણપત્રો પૂર્ણપણે વિશ્વસનીય નથી. તમે કોઈ હુમલાખોર જોડે વાત કરતા હોઈ શકો છો.</translation>
<translation id="4406896451731180161">શોધ પરિણામો</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">પિકઅપ માટેનું સરનામું</translation>
<translation id="4424024547088906515">આ સર્વર સાબિત કરી શક્યું નથી કે તે <ph name="DOMAIN" /> છે; તેનું સુરક્ષા પ્રમાણપત્ર Chrome દ્વારા વિશ્વસનીય નથી. આ કોઈ ખોટી ગોઠવણીને કારણે થયું હશે અથવા કોઈ હુમલાખોર તમારા કનેક્શનને અટકાવી રહ્યો છે.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> એ તમારું લોગિન પ્રમાણપત્ર સ્વીકાર્યું ન હતું અથવા કદાચ કોઈ એક પ્રદાન કરવામાં આવ્યું નથી.</translation>
+<translation id="4434045419905280838">પૉપ-અપ અને રીડાયરેક્ટ</translation>
<translation id="443673843213245140">પ્રોક્સીનો ઉપયોગ અક્ષમ કરેલો છે પણ એક સ્પષ્ટ પ્રોક્સી ગોઠવણી ઉલ્લેખિત છે.</translation>
<translation id="445100540951337728">સ્વીકૃત ડેબિટ કાર્ડ</translation>
<translation id="4506176782989081258">માન્યતા ભૂલ: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">ચુકવણી સ્વતઃભરણ અક્ષમ કરેલ છે</translation>
<translation id="4764776831041365478"><ph name="URL" /> પરનાં વેબપેજ અસ્થાયી ધોરણે બંધ હોઈ શકે છે અથવા તે કાયમ માટે નવા વેબ સરનામાં પર ખસેડવામાં આવ્યા હોઈ શકે છે.</translation>
<translation id="4771973620359291008">કોઈ અજ્ઞાત ભૂલ આવી.</translation>
+<translation id="4785689107224900852">આ ટૅબ પર સ્વિચ કરો</translation>
<translation id="4792143361752574037">સત્ર ફાઇલોને ઍક્સેસ કરવામાં સમસ્યા હતી. ડિસ્કમાં સાચવવાનું અત્યારે બંધ કરેલું છે. ફરીથી પ્રયાસ કરવા માટે, કૃપા કરીને પેજને ફરીથી લોડ કરો.</translation>
<translation id="4800132727771399293">તમારી સમાપ્તિ તારીખ અને CVC તપાસો અને ફરીથી પ્રયાસ કરો</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">તમે અત્યારે <ph name="SITE" /> ની મુલાકાત લઈ શકતાં નથી કારણ કે વેબસાઇટે સમજાય નહીં તેવા ઓળખપત્ર મોકલ્યાં છે જેની પર Google Chrome પ્રક્રિયા કરી શકતું નથી. નેટવર્ક ભૂલો અને હુમલા સામાન્ય રીતે અસ્થાયી છે, તેથી આ પૃષ્ઠ સંભવિત રૂપે પછીથી કાર્ય કરશે.</translation>
<translation id="4813512666221746211">નેટવર્ક ભૂલ</translation>
<translation id="4816492930507672669">પૃષ્ઠ પર ફિટ</translation>
-<translation id="483020001682031208">બતાવવા માટે કોઇ ભૌતિક વેબ પૃષ્ઠો નથી</translation>
<translation id="4850886885716139402">જુઓ</translation>
<translation id="4854362297993841467">વિતરણની આ પદ્ધતિ ઉપલબ્ધ નથી. કોઈ ભિન્ન પદ્ધતિ અજમાવો.</translation>
<translation id="4858792381671956233">તમે આ સાઇટની મુલાકાત લો છો તે ઠીક છે કે કેમ તેવું તમે તમારા માતાપિતાને પૂછ્યું</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-બિટ)</translation>
<translation id="5121084798328133320">તમે પુષ્ટિ કરી લો પછી, આ સાઇટ સાથે તમારા Google Payments એકાઉન્ટમાંથી કાર્ડની વિગતો શેર કરવામાં આવશે.</translation>
<translation id="5128122789703661928">આ નામવાળું સત્ર ડિલીટ કરવા માટે માન્ય નથી.</translation>
+<translation id="5135404736266831032">સરનામા મેનેજ કરો…</translation>
<translation id="5141240743006678641">તમારા Google ઓળખપત્રો સાથે સમન્વયિત પાસવર્ડ્સને એન્ક્રિપ્ટ કરો</translation>
<translation id="5145883236150621069">નીતિ પ્રતિક્રિયામાં ભૂલ કોડ હાજર</translation>
<translation id="5159010409087891077">એક નવી છુપી વિંડોમાં પેજ ખોલો (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">આ પેજ પરનું શામેલ કરેલ પેજ કહે છે કે</translation>
<translation id="5205222826937269299">નામ આવશ્યક છે</translation>
<translation id="5222812217790122047">ઇમેઇલ આવશ્યક છે</translation>
-<translation id="522700295135997067">આ સાઇટે હમણાં જ તમારો પાસવર્ડ ચોર્યો હોઈ શકે છે</translation>
<translation id="5230733896359313003">વિતરણ માટેનું સરનામું</translation>
<translation id="5250209940322997802">"નેટવર્ક સાથે કનેક્ટ કરો"</translation>
<translation id="5251803541071282808">મેઘ</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">કંપની, સંસ્થા અથવા શાળા ઇન્ટ્રાનેટ પર આ સાઇટ બાહ્ય વેબસાઇટ જેવું જ URL ધરાવે છે.
<ph name="LINE_BREAK" />
તમારા સિસ્ટમ વ્યવસ્થાપકનો સંપર્ક કરવાનો પ્રયાસ કરો.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> માટે સુરક્ષા કોડ દાખલ કરો. આ કોડ સાચવવામાં આવશે નહીં.</translation>
<translation id="5509780412636533143">સંચાલિત બુકમાર્ક્સ</translation>
<translation id="5510766032865166053">તે કદાચ ખસેડવામાં કે કાઢી નાખવામાં આવી છે</translation>
<translation id="5523118979700054094">નીતિનું નામ</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">વિતરણ માટેનું સરનામું ઉમેરો</translation>
<translation id="5689199277474810259">JSON પર નિકાસ કરો</translation>
<translation id="5689516760719285838">સ્થાન</translation>
+<translation id="570530837424789914">મેનેજ કરો…</translation>
<translation id="5710435578057952990">આ વેબસાઇટની ઓળખ ચકાસવામાં આવી નથી.</translation>
<translation id="5719499550583120431">પ્રીપેઇડ કાર્ડ સ્વીકારવામાં આવે છે.</translation>
<translation id="5720705177508910913">વર્તમાન વપરાશકર્તા</translation>
+<translation id="5730040223043577876">જો તમે અન્ય સાઇટ પર તમારા પાસવર્ડનો ફરી ઉપયોગ કર્યો હોય, તો Chrome તેને રીસેટ કરવાનો સુઝાવ આપે છે.</translation>
<translation id="5732392974455271431">તમારા માટે તમારા માતાપિતા તેને અનાવરોધિત કરી શકે છે</translation>
<translation id="5763042198335101085">એક માન્ય ઇમેઇલ ઍડ્રેસ ઉમેરો</translation>
<translation id="5765072501007116331">વિતરણ પદ્ધતિઓ અને આવશ્યકતાઓ જોવા માટે, એક સરનામું પસંદ કરો</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">જોખમી અ‍ૅપ્લિકેશનો અને સાઇટ્સ શોધવામાં સહાય કરવા માટે Google ને કેટલીક <ph name="BEGIN_WHITEPAPER_LINK" />સિસ્ટમ માહિતી અને પૃષ્ઠ સામગ્રી<ph name="END_WHITEPAPER_LINK" /> આપમેળે મોકલો. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">સંપર્ક માહિતીમાં ફેરફાર કરો</translation>
<translation id="5967867314010545767">ઇતિહાસમાંથી દૂર કરો</translation>
-<translation id="5972020793760134803">ટૅબ પર સ્વિચ કરો</translation>
<translation id="5975083100439434680">ઝૂમ ઘટાડો</translation>
-<translation id="597552863672748783">સુરક્ષા કોડની પુષ્ટિ કરો</translation>
<translation id="598637245381783098">ચુકવણી ઍપ્લિકેશન ખોલી શકાતી નથી</translation>
<translation id="5989320800837274978">નિયત પ્રોક્સી સર્વર્સ અથવા .pac સ્ક્રિપ્ટનો URL નો ઉલ્લેખ કરેલો નથી.</translation>
<translation id="5990559369517809815">સર્વર પરની વિનંતિઓને એક્સ્ટેંશન દ્વારા અવરોધિત કરવામાં આવી છે.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">આ કન્ટેન્ટ કદાચ સૉફ્ટવેર ઇન્સ્ટૉલ કરવા માટે અથવા વ્યક્તિગત માહિતી કઢાવવા માટે તમારી સાથે કપટ કરવાનો પ્રયાસ કરી શકે છે. <ph name="BEGIN_LINK" />છતાં પણ બતાવો<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">તમે અત્યારે આ <ph name="SITE" />ની મુલાકાત લઈ શકતાં નથી કારણ કે આ વેબસાઇટ પ્રમાણપત્ર પિનિંગનો ઉપયોગ કરે છે. નેટવર્કમાં ભૂલ આવવી અને હુમલા થવા સામાન્ય રીતે અસ્થાયી હોય છે, તેથી આ પેજ સંભવિત રૂપે થોડા સમય પછી કાર્ય કરશે.</translation>
<translation id="6059925163896151826">USB ઉપકરણો</translation>
+<translation id="6071091556643036997">નીતિ પ્રકાર અમાન્ય છે.</translation>
<translation id="6080696365213338172">તમે વ્યવસ્થાપક-પ્રદત્ત પ્રમાણપત્રનો ઉપયોગ કરીને સામગ્રી ઍક્સેસ કરી છે. તમે <ph name="DOMAIN" /> ને પ્રદાન કરેલ ડેટા તમારા વ્યવસ્થાપક દ્વારા ઇન્ટરસેપ્ટ થઈ શકે છે.</translation>
<translation id="610911394827799129">તમારા Google એકાઉન્ટમાં <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> પર બ્રાઉઝિંગ ઇતિહાસના અન્ય સ્વરૂપો હોઈ શકે છે</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{કોઈ નહીં}=1{1 પાસવર્ડ (સિંક કરેલ)}one{# પાસવર્ડ (સિંક કરેલ)}other{# પાસવર્ડ (સિંક કરેલ)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">વધુ માહિતી ઉમેરો</translation>
<translation id="6447842834002726250">કૂકીઝ</translation>
<translation id="6451458296329894277">ફોર્મનાં ફરી સબમિશનની પુષ્ટિ કરો</translation>
+<translation id="6465306955648956876">બધા પાસવર્ડ મેનેજ કરો…</translation>
<translation id="647261751007945333">ઉપકરણ નીતિઓ</translation>
<translation id="6477321094435799029">Chrome ને આ પૃષ્ઠ પર અસામાન્ય કોડ મળ્યો અને તમારી વ્યક્તિગત માહિતી (ઉદાહરણ તરીકે, પાસવર્ડ્સ, ફોન નંબર્સ અને ક્રેડિટ કાર્ડ્સ)ની સુરક્ષા કરવા માટે તેને અવરોધિત કરેલ છે.</translation>
<translation id="6489534406876378309">ક્રેશ અપલોડ કરવાનું શરૂ કરો</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> શોધ</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> પરના હુમલાખોરો કદાચ હાલમાં તમારા Mac પર જોખમી પ્રોગ્રામ ઇન્સ્ટૉલ કરવાનો પ્રયાસ કરે છે કે જે તમારી માહિતી (ઉદાહરણ તરીકે, ફોટો, પાસવર્ડ, સંદેશા અને ક્રેડિટ કાર્ડ) ચોરી અથવા કાઢી નાખી શકે છે. <ph name="BEGIN_LEARN_MORE_LINK" />વધુ જાણો<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">આ નીતિ દૂર કરવામાં આવેલી છે.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{કોઈ નહીં}=1{1 સાઇટમાંથી (તમે તમારા Google એકાઉન્ટમાંથી સાઇન આઉટ થશો નહીં)}one{# સાઇટમાંથી (તમે તમારા Google એકાઉન્ટમાંથી સાઇન આઉટ થશો નહીં)}other{# સાઇટમાંથી (તમે તમારા Google એકાઉન્ટમાંથી સાઇન આઉટ થશો નહીં)}}</translation>
<translation id="6657585470893396449">પાસવર્ડ</translation>
<translation id="6671697161687535275">Chromium માંથી ફોર્મ સૂચન દૂર કરીએ?</translation>
<translation id="6685834062052613830">સાઇન આઉટ કરો અને સેટઅપ પૂર્ણ કરો</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">વપરાશકર્તા: </translation>
<translation id="6945221475159498467">પસંદ કરો</translation>
<translation id="6948701128805548767">પિકઅપ પદ્ધતિ અને આવશ્યકતાઓ જોવા માટે, એક સરનામું પસંદ કરો</translation>
+<translation id="6949872517221025916">પાસવર્ડ રીસેટ કરો</translation>
<translation id="6957887021205513506">સર્વરનું પ્રમાણપત્ર બનાવટી હોય એવું લાગે છે.</translation>
<translation id="6965382102122355670">બરાબર, સમજાઇ ગયું</translation>
<translation id="6965978654500191972">ઉપકરણ</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">વિતરણ પદ્ધતિ</translation>
<translation id="7139724024395191329">એમિરાત</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> વધુ}one{<ph name="PAYMENT_METHOD_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> વધુ}other{<ph name="PAYMENT_METHOD_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> વધુ}}</translation>
-<translation id="7155487117670177674">ચુકવણી સુરક્ષિત નથી</translation>
+<translation id="717330890047184534">Gaia ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> વધુ}one{<ph name="SHIPPING_OPTION_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> વધુ}other{<ph name="SHIPPING_OPTION_PREVIEW" /> અને <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> વધુ}}</translation>
<translation id="7180611975245234373">તાજું કરો</translation>
<translation id="7182878459783632708">કોઈ નીતિઓ સેટ નથી</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">વૈશ્વિક ડિફોલ્ટનો ઉપયોગ કરો (અવરોધિત કરો)</translation>
<translation id="7460163899615895653">અન્ય ઉપકરણોમાંના તમારા તાજેતરના ટૅબ્સ અહીં દેખાય છે</translation>
<translation id="7469372306589899959">કાર્ડની પુષ્ટિ કરી રહ્યાં છે</translation>
+<translation id="7473891865547856676">નહીં આભાર</translation>
<translation id="7481312909269577407">ફોર્વર્ડ કરો</translation>
<translation id="7485870689360869515">કોઈ ડેટા મળ્યો નથી.</translation>
<translation id="7508255263130623398">પરત થયેલ નીતિ ઉપકરણ id ખાલી છે અથવા વર્તમાન ટોકન સાથે મેળ ખાતું નથી</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Chrome માંથી ક્રેડિટ કાર્ડ દૂર કરીએ?</translation>
<translation id="7575800019233204241">"તમારું કનેક્શન ખાનગી નથી" અથવા "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" અથવા "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" અથવા "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" અથવા "SSL પ્રમાણપત્ર ભૂલ"</translation>
<translation id="7578104083680115302">તમે Google સાથે સાચવ્યાં છે તે કાર્ડ્સનો ઉપયોગ કરીને સમગ્ર ઉપકરણોમાં સાઇટ્સ અને ઍપ્લિકેશનો પર ઝડપથી ચુકવણી કરો.</translation>
-<translation id="7588950540487816470">વાસ્તવિક વેબ</translation>
<translation id="7592362899630581445">સર્વરનું પ્રમાણપત્ર, નામ નિગ્રહોનું ઉલ્લંઘન કરે છે.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> કરતા ઓછું</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" />, હાલમાં આ વિનંતીને હેન્ડલ કરવામાં અસમર્થ છે.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;સંપાદિત કરવું પૂર્વવત્‌ કરો</translation>
<translation id="9154194610265714752">અપડેટેડ</translation>
<translation id="9157595877708044936">સેટિંગ અપ...</translation>
+<translation id="9168814207360376865">તમારી ચુકવણી પદ્ધતિઓ સાચવવામાં આવી છે કે કેમ તે ચેક કરવાની સાઇટને મંજૂરી આપો</translation>
<translation id="9169664750068251925">હંમેશા આ સાઇટ પર અવરોધિત કરો</translation>
<translation id="9170848237812810038">&amp;પૂર્વવત્ કરો</translation>
<translation id="917450738466192189">સર્વરનું પ્રમાણપત્ર અમાન્ય છે.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">લેખ ઉમેરવામાં નિષ્ફળ થયાં.</translation>
<translation id="9215416866750762878">કોઈ ઍપ્લિકેશન Chromeને આ સાઇટ સાથે સુરક્ષિત રીતે કનેક્ટ થવાથી અટકાવી રહી છે</translation>
<translation id="9219103736887031265">છબીઓ</translation>
-<translation id="933612690413056017">કોઈ ઇન્ટરનેટ કનેક્શન નથી</translation>
<translation id="933712198907837967">ડાઇનર્સ ક્લબ</translation>
<translation id="935608979562296692">ફોર્મ સાફ કરો</translation>
<translation id="939736085109172342">નવું ફોલ્ડર</translation>
diff --git a/chromium/components/strings/components_strings_hi.xtb b/chromium/components/strings/components_strings_hi.xtb
index 34a592f260b..c89426b62a1 100644
--- a/chromium/components/strings/components_strings_hi.xtb
+++ b/chromium/components/strings/components_strings_hi.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> के लिए अनुमति चुनें</translation>
<translation id="1111153019813902504">हाल के बुकमार्क</translation>
<translation id="1113869188872983271">&amp;पुन: क्रमित करना वापस लाएं</translation>
+<translation id="1125573121925420732">जब वेबसाइटें अपनी सुरक्षा अपडेट कर रही होती हैं तब चेतावनियां आम हो सकती हैं. इसमें जल्दी ही सुधार होगा.</translation>
<translation id="1126551341858583091">स्थानीय जगह का आकार <ph name="CRASH_SIZE" /> है.</translation>
<translation id="112840717907525620">नीति संचय ठीक है</translation>
<translation id="1150979032973867961">यह सर्वर यह नहीं प्रमाणित कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र आपके कंप्यूटर के ऑपरेटिंग सिस्टम द्वारा विश्वसनीय नहीं है. ऐसा गलत कॉन्फ़िगरेशन या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
@@ -43,27 +44,28 @@
<translation id="1228893227497259893">गलत इकाई पहचानकर्ता</translation>
<translation id="1232569758102978740">शीर्षक रहित</translation>
<translation id="1253921432148366685"><ph name="TYPE_1" />, <ph name="TYPE_2" /> (सिंक किए गए)</translation>
-<translation id="1256368399071562588">&lt;p&gt;अगर आप किसी वेबसाइट पर जाने की कोशिश करते हैं और वह नहीं खुलती है, तो पहले इन समस्या को हल करने के कदमों से गड़बड़ी को ठीक करके देखें:&lt;/p&gt;
+<translation id="1256368399071562588">&lt;p&gt;अगर आप किसी वेबसाइट पर जाने की कोशिश करते हैं और वह नहीं खुलती है तो, कृपया गड़बड़ी ठीक करने संबंधी इन कदमों के ज़रिए समस्या का हल करने की कोशिश करें:&lt;/p&gt;
&lt;ol&gt;
- &lt;li&gt;देखें कि वेब पता लिखने में कोई गलती तो नहीं हुई है.&lt;/li&gt;
+ &lt;li&gt;देखें कि वेब पता लिखने में टाइपिंग की कोई गलती तो नहीं हुई है.&lt;/li&gt;
&lt;li&gt;पक्का करें कि आपका इंटरनेट कनेक्शन ठीक से काम कर रहा है.&lt;/li&gt;
&lt;li&gt;वेबसाइट के मालिक से संपर्क करें.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">आपने अपना पासवर्ड ऐसी साइट पर डाला है जिसे आपका संगठन प्रबंधित नहीं करता है. अपना खाता सुरक्षित करने के लिए, दूसरे ऐप्लिकेशन और साइटों पर अपना पासवर्ड दोबारा इस्तेमाल न करें.</translation>
<translation id="1263231323834454256">पठन सूची</translation>
<translation id="1264126396475825575">ख़राबी रिपोर्ट <ph name="CRASH_TIME" /> पर कैप्चर की गई (अभी तक अपलोड नहीं की गई या उसे अनदेखा किया गया)</translation>
<translation id="1270502636509132238">पिकअप का तरीका</translation>
<translation id="1285320974508926690">कभी भी इस साइट का अनुवाद न करें</translation>
<translation id="1292701964462482250">"आपके कंप्यूटर पर मौजूद सॉफ़्टवेयर Chrome को सुरक्षित रूप से वेब से कनेक्ट होने से रोक रहा है" (केवल Windows कंप्यूटर)</translation>
-<translation id="1294154142200295408">कमांड लाइन की विविधताएं</translation>
+<translation id="1294154142200295408">अलग-अलग तरह की कमांड-लाइन</translation>
<translation id="129553762522093515">हाल ही में बंद किए गए</translation>
<translation id="129863573139666797"><ph name="BEGIN_LINK" />अपनी कुकी साफ़ करके देखें<ph name="END_LINK" /></translation>
<translation id="1314614906530272393">चुना गया सत्र मौजूद नहीं है.</translation>
<translation id="1323433172918577554">और दिखाएं</translation>
-<translation id="1333989956347591814">आपकी गतिविधि इन्हें <ph name="BEGIN_EMPHASIS" />अभी भी दिखाई दे सकती है<ph name="END_EMPHASIS" />:
+<translation id="1333989956347591814">आपकी गतिविधि <ph name="BEGIN_EMPHASIS" />अभी भी इन्हें दिखाई दे सकती है<ph name="END_EMPHASIS" />:
<ph name="BEGIN_LIST" />
<ph name="LIST_ITEM" />जिन वेबसाइट पर आप जाते हैं
- <ph name="LIST_ITEM" />आपका नियोक्ता या विद्यालय
- <ph name="LIST_ITEM" />आपका इंटरनेट सेवा प्रदाता
+ <ph name="LIST_ITEM" />आपका नियोक्ता या स्कूल
+ <ph name="LIST_ITEM" />आपको इंटरनेट सेवा देने वाली कंपनी
<ph name="END_LIST" /></translation>
<translation id="1339601241726513588">नामांकन डोमेन:</translation>
<translation id="1340482604681802745">पिकअप पता</translation>
@@ -100,11 +102,10 @@
<translation id="1594030484168838125">चुनें</translation>
<translation id="1620510694547887537">कैमरा</translation>
<translation id="1623104350909869708">इस पेज को अतिरिक्त डॉयलॉग बनाने से रोकें</translation>
-<translation id="1629803312968146339">क्या आप चाहते हैं कि Chrome इस कार्ड को सहेजे?</translation>
<translation id="1639239467298939599">लोड हो रहा है</translation>
<translation id="1640180200866533862">उपयोगकर्ता नीतियां</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />साइट के मुखपृष्ठ पर विज़िट करके<ph name="END_LINK" /> देखें.</translation>
-<translation id="1644184664548287040">नेटवर्क कॉन्फ़िगरेशन अमान्य है और उसे आयात नहीं किया जा सकेगा.</translation>
+<translation id="1644184664548287040">नेटवर्क कॉन्फ़िगरेशन अमान्य है और उसे मंगाया नहीं जा सकेगा.</translation>
<translation id="1644574205037202324">इतिहास</translation>
<translation id="1645368109819982629">असमर्थित प्रोटोकॉल</translation>
<translation id="1655462015569774233">{1,plural, =1{यह सर्वर प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सुरक्षा प्रमाणपत्र की समय सीमा कल समाप्त हो गई थी. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन को बाधित करने के कारण हो सकता है. आपके कंप्यूटर की घड़ी वर्तमान में <ph name="CURRENT_DATE" /> पर सेट है. क्‍या यह सही है? यदि नहीं, तो आपको अपने सिस्टम की घड़ी सही करनी चाहिए और फिर इस पेज को रीफ्रेश करना चाहिए.}one{यह सर्वर प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सुरक्षा प्रमाणपत्र की समय सीमा # दिन पहले समाप्त हो गई है. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन को बाधित करने के कारण हो सकता है. आपके कंप्यूटर की घड़ी वर्तमान में <ph name="CURRENT_DATE" /> पर सेट है. क्‍या यह सही है? यदि नहीं, तो आपको अपने सिस्टम की घड़ी सही करनी चाहिए और फिर इस पेज को रीफ्रेश करना चाहिए.}other{यह सर्वर प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसके सुरक्षा प्रमाणपत्र की समय सीमा # दिन पहले समाप्त हो गई है. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन को बाधित करने के कारण हो सकता है. आपके कंप्यूटर की घड़ी वर्तमान में <ph name="CURRENT_DATE" /> पर सेट है. क्‍या यह सही है? यदि नहीं, तो आपको अपने सिस्टम की घड़ी सही करनी चाहिए और फिर इस पेज को रीफ्रेश करना चाहिए.}}</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows नेटवर्क निदान चलाकर देखें<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">कृपया अपना समन्‍वयन पासफ्रेज़ अपडेट करें.</translation>
<translation id="1787142507584202372">आपके द्वारा खोले गए टैब, यहां दिखाई देंगे</translation>
-<translation id="1789575671122666129">पॉपअप</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">कार्ड के मालिक का नाम</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> को जोड़ा गया</translation>
@@ -137,8 +137,8 @@
<translation id="1834321415901700177">इस साइट में हानिकारक प्रोग्राम हैं</translation>
<translation id="1840414022444569775">इस कार्ड नंबर का उपयोग पहले ही किया जा चुका है</translation>
<translation id="1842969606798536927">भुगतान करें</translation>
-<translation id="1871208020102129563">प्रॉक्‍सी को फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर का उपयोग करने के लिए सेट किया गया है, .pac स्‍क्रिप्‍ट फ़ाइल का उपयोग करने के लिए नहीं.</translation>
-<translation id="1871284979644508959">आवश्यक फ़ील्ड</translation>
+<translation id="1871208020102129563">प्रॉक्‍सी की सेटिंग इस तरह से की गई है कि वह फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर इस्तेमाल करे, न कि .pac स्‍क्रिप्‍ट यूआरअल.</translation>
+<translation id="1871284979644508959">ज़रूरी फ़ील्ड</translation>
<translation id="1874765382782611674">स्वीकार किए जाने वाले डेबिट कार्ड</translation>
<translation id="187918866476621466">शुरुआती पन्ना खोलें</translation>
<translation id="1883255238294161206">सूची संक्षिप्त करें</translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">अपना कंप्यूटर फिर से चालू करें</translation>
<translation id="2113977810652731515">कार्ड</translation>
<translation id="2114841414352855701">ध्यान नहीं दिया गया क्योंकि यह <ph name="POLICY_NAME" /> द्वारा ओवरराइड की गई थी.</translation>
-<translation id="2138201775715568214">आस-पास के जीते-जागते वेब पृष्‍ठ खोजे जा रहे हैं</translation>
<translation id="213826338245044447">मोबाइल बुकमार्क</translation>
<translation id="214556005048008348">भुगतान न करें</translation>
<translation id="2147827593068025794">पृष्ठभूमि समन्वयन</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">नीति नहीं मिली</translation>
<translation id="2213606439339815911">प्रविष्टियां फ़ेच की जा रही हैं...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर इस समय मौजूद हमलावर ऐसे खतरनाक ऐप्लिकेशन इंस्टॉल कर सकते हैं जो आपके डिवाइस को नुकसान पहुंचा सकते हैं और आपके मोबाइल बिल में अनजाने खर्चे जोड़ सकते हैं या आपकी व्‍यक्‍तिगत जानकारी चुरा सकते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">इंटरनेट कनेक्शन नहीं है</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />निदान ऐप्लिकेशन<ph name="END_LINK" /> का उपयोग करके अपने कनेक्शन को ठीक करें</translation>
<translation id="2239100178324503013">अभी भेजें</translation>
<translation id="225207911366869382">यह मान इस नीति के लिए हटा दिया गया है.</translation>
@@ -195,7 +195,7 @@
<translation id="2270484714375784793">फ़ोन नंबर</translation>
<translation id="2292556288342944218">आपका इंटरनेट कनेक्शन अवरुद्ध है</translation>
<translation id="230155334948463882">नया कार्ड?</translation>
-<translation id="2316887270356262533">1 MB से भी कम जगह खाली करता है. आपकी अगली विज़िट पर कुछ साइटें और भी धीमे लोड हो सकती हैं.</translation>
+<translation id="2316887270356262533">1 MB से भी कम जगह खाली करता है. जब आप अगली बार विज़िट करेंगे तो, कुछ साइटें और धीमे लोड हो सकती हैं.</translation>
<translation id="2317259163369394535"><ph name="DOMAIN" /> के लिए उपयोगकर्ता नाम और पासवर्ड आवश्यक है.</translation>
<translation id="2317583587496011522">डेबिट कार्ड स्वीकार किए जाते हैं.</translation>
<translation id="2337852623177822836">वह सेटिंग जिसे आपका व्यवस्थापक नियंत्रित करता है</translation>
@@ -216,7 +216,7 @@
<translation id="2463739503403862330">भरें</translation>
<translation id="2465655957518002998">डिलीवरी का तरीका चुनें</translation>
<translation id="2467694685043708798"><ph name="BEGIN_LINK" />नेटवर्क निदान चलाकर देखें<ph name="END_LINK" /></translation>
-<translation id="2479410451996844060">अमान्‍य खोज URL.</translation>
+<translation id="2479410451996844060">गलत खोज यूआरएल.</translation>
<translation id="2482878487686419369">अधिसूचनाएं</translation>
<translation id="2491120439723279231">सर्वर के प्रमाणपत्र में त्रुटियां हैं.</translation>
<translation id="2495083838625180221">JSON पार्सर</translation>
@@ -228,16 +228,16 @@
<translation id="2524461107774643265">ज़्यादा जानकारी जोड़ें</translation>
<translation id="2536110899380797252">पता जोड़ें</translation>
<translation id="2539524384386349900">पता लगाएं</translation>
-<translation id="255002559098805027"><ph name="HOST_NAME" /> ने एक अमान्य प्रतिसाद भेजा है.</translation>
+<translation id="255002559098805027"><ph name="HOST_NAME" /> ने एक गलत जवाब भेजा है.</translation>
<translation id="2556876185419854533">&amp;संपादन वापस लाएं</translation>
<translation id="2586657967955657006">क्लिपबोर्ड</translation>
<translation id="2587730715158995865"><ph name="ARTICLE_PUBLISHER" /> की ओर से. यह और <ph name="OTHER_ARTICLE_COUNT" /> दूसरे समाचार पढ़ें.</translation>
-<translation id="2587841377698384444">निर्देशिका API आईडी:</translation>
+<translation id="2587841377698384444">निर्देशिका API (एपीआई) आईडी:</translation>
<translation id="2597378329261239068">यह दस्तावेज़ पासवर्ड सुरक्षित है. कृपया पासवर्ड डालें.</translation>
<translation id="2609632851001447353">विविधताएं</translation>
<translation id="262424810616849754">{COUNT,plural, =0{कुछ नहीं}=1{1 ऐप्लिकेशन ($1)}=2{2 ऐप्लिकेशन ($1, $2)}one{# ऐप्लिकेशन ($1, $2, $3)}other{# ऐप्लिकेशन ($1, $2, $3)}}</translation>
<translation id="2625385379895617796">आपकी घड़ी आगे है</translation>
-<translation id="2634124572758952069"><ph name="HOST_NAME" /> का सर्वर IP पता नहीं मिल सका.</translation>
+<translation id="2634124572758952069"><ph name="HOST_NAME" /> का सर्वर आईपी पता नहीं मिल सका.</translation>
<translation id="2639739919103226564">स्थिति:</translation>
<translation id="2649204054376361687"><ph name="CITY" />, <ph name="COUNTRY" /></translation>
<translation id="2650446666397867134">फ़ाइल तक पहुंच अस्वीकृत थी</translation>
@@ -254,7 +254,7 @@
<translation id="2710942282213947212">आपके कंप्यूटर पर मौजूद सॉफ़्टवेयर क्रोमियम को सुरक्षित तरीके से वेब से जुड़ने से रोक रहा है</translation>
<translation id="2712173769900027643">अनुमति मांगें</translation>
<translation id="2720342946869265578">आस-पास</translation>
-<translation id="2721148159707890343">अनुरोध सफल रहा</translation>
+<translation id="2721148159707890343">अनुरोध कामयाब रहा</translation>
<translation id="2728127805433021124">सर्वर का प्रमाणपत्र एक कमज़ोर हस्ताक्षर एल्गोरिदम का उपयोग करके हस्ताक्षरित किया गया है.</translation>
<translation id="2730326759066348565"><ph name="BEGIN_LINK" />नेटवर्क कनेक्टिविटी चलाकर देखें<ph name="END_LINK" /></translation>
<translation id="2738330467931008676">पिकअप का पता चुनें</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">चयनित आइटम निकालें</translation>
<translation id="277133753123645258">शिपिंग का तरीका</translation>
<translation id="277499241957683684">डिवाइस का रिकॉर्ड लापता है</translation>
+<translation id="2781030394888168909">MacOS निर्यात करें</translation>
<translation id="2784949926578158345">कनेक्‍शन रीसेट किया गया था.</translation>
<translation id="2788784517760473862">स्वीकृत क्रेडिट कार्ड</translation>
<translation id="2794233252405721443">साइट अवरोधित है</translation>
@@ -280,7 +281,7 @@
<translation id="2928905813689894207">बिलिंग पता</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" /> अन्य}}</translation>
<translation id="2941952326391522266">यह सर्वर यह प्रमाणित नहीं कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र <ph name="DOMAIN2" /> की ओर से है. ऐसा गलत कॉन्फ़िगरेशन के कारण या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
-<translation id="2948083400971632585">आप किसी कनेक्शन के लिए कॉन्फ़िगर की गई किसी भी प्रॉक्सी को सेटिंग पेज से अक्षम कर सकते हैं.</translation>
+<translation id="2948083400971632585">आप किसी कनेक्शन के लिए कॉन्फ़िगर की गई किसी भी प्रॉक्सी को सेटिंग पेज से बंद कर सकते हैं.</translation>
<translation id="2955913368246107853">खोज बार बंद करें</translation>
<translation id="2958431318199492670">नेटवर्क कॉन्फ़िगरेशन ONC मानक का पालन नहीं करता. कॉन्फ़िगरेशन के कुछ भाग आयात नहीं किए जा सकते हैं.</translation>
<translation id="2966678944701946121">खत्म होने की तारीख: <ph name="EXPIRATION_DATE_ABBR" />, <ph name="ADDED_TO_AUTOFILL_MONTH" /> को जोड़ा गया</translation>
@@ -292,9 +293,9 @@
<translation id="2985398929374701810">मान्य पता डालें</translation>
<translation id="2986368408720340940">पिकअप का यह तरीका उपलब्ध नहीं है. कोई दूसरा तरीका आज़माएं.</translation>
<translation id="2991174974383378012">वेबसाइटों के साथ साझाकरण</translation>
-<translation id="2991571918955627853">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि वेबसाइट HSTS का उपयोग करती है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ समय के लिए होते हैं, इसलिए पेज शायद बाद में ठीक से काम करेगा.</translation>
+<translation id="2991571918955627853">आप इस समय <ph name="SITE" /> पर नहीं जा सकते क्योंकि वेबसाइट एचएसटीएस का उपयोग करती है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ समय के लिए होते हैं इसलिए यह पेज शायद बाद में ठीक से काम करेगा.</translation>
<translation id="3005723025932146533">सहेजी गई कॉपी दिखाएं</translation>
-<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> का CVC डालें. आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ साझा किए जाएंगे.</translation>
+<translation id="3008447029300691911"><ph name="CREDIT_CARD" /> का CVC डालें. आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ शेयर किए जाएंगे.</translation>
<translation id="3010559122411665027">सूची प्रविष्ट‍ि "<ph name="ENTRY_INDEX" />": <ph name="ERROR" /></translation>
<translation id="301521992641321250">ऑटोमैटिक रूप से ब्लॉक है</translation>
<translation id="3024663005179499861">गलत नीति प्रकार</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome इस समय आपके कार्ड की पुष्टि नहीं कर सका. कृपया बाद में पुन: प्रयास करें.</translation>
<translation id="3064966200440839136">किसी बाहरी ऐप्लिकेशन के ज़रिए भुगतान करने के लिए गुप्त मोड छोड़ रहे हैं. जारी रखना चाहते हैं?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{कुछ नहीं}=1{1 पासवर्ड}one{# पासवर्ड}other{# पासवर्ड}}</translation>
-<translation id="3093245981617870298">आप ऑफ़लाइन हैं.</translation>
<translation id="3096100844101284527">पिकअप का पता जोड़ें</translation>
<translation id="3105172416063519923">एसेट आईडी:</translation>
<translation id="3109728660330352905">आपके पास इस पेज को देखने के लिए प्राधिकरण नहीं है.</translation>
@@ -313,7 +313,7 @@
<translation id="3150653042067488994">अस्थायी सर्वर गड़बड़ी</translation>
<translation id="3154506275960390542">इस पेज में ऐसा फ़ॉर्म शामिल है, जो सुरक्षित रूप से सबमिट नहीं किया जा सकता है. ट्रांज़िट में होने के दौरान आपके भेजे जाने वाले डेटा को दूसरे लोग देख सकते हैं या सर्वर को मिलने वाली सामग्री में बदलाव करने के लिए कोई आक्रमणकर्ता उसे संशोधित कर सकता है.</translation>
<translation id="3157931365184549694">पुनर्स्थापित करें</translation>
-<translation id="3162559335345991374">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं उसके लिए आपको प्रवेश पृष्‍ठ पर जाने की आवश्‍यकता हो सकती है.</translation>
+<translation id="3162559335345991374">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं, आपको उसके लॉगिन पेज पर जाने की ज़रूरत पड़ सकती है.</translation>
<translation id="3167968892399408617">आपके द्वारा गुप्त टैब में देखे जाने वाले पेज, आपके द्वारा अपने सभी गुप्त टैब बंद कर देने के बाद आपके ब्राउज़र के इतिहास, कुकी संग्रह, या खोज इतिहास में नहीं रहेंगे. आपके द्वारा डाउनलोड की गईं सभी फ़ाइलें या बनाए गए बुकमार्क रख लिए जाएंगे.</translation>
<translation id="3169472444629675720">तलाश करें</translation>
<translation id="3174168572213147020">द्वीप</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> वर्तमान में पहुंच योग्य नहीं है.</translation>
<translation id="3427092606871434483">अनुमति दें (डिफ़ॉल्ट)</translation>
<translation id="3427342743765426898">&amp;संपादित करना फिर से करें</translation>
+<translation id="342781501876943858">अगर आपने अपने पासवर्ड का दूसरी साइटों पर दोबारा इस्तेमाल किया है, तो क्रोमियम आपको उसे रीसेट करने का सुझाव देता है.</translation>
<translation id="3431636764301398940">इस कार्ड को इस डिवाइस पर सहेजें</translation>
<translation id="3447661539832366887">इस डिवाइस के मालिक ने डायनासोर गेम को बंद कर दिया है.</translation>
<translation id="3447884698081792621">प्रमाणपत्र (<ph name="ISSUER" /> की ओर से जारी किया गया) दिखाएं</translation>
@@ -398,8 +399,7 @@
<translation id="3678529606614285348">पेज को नई गुप्त विंडो में खोलें (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">ख़राबी रिपोर्ट <ph name="CRASH_TIME" /> पर कैप्चर की गई, <ph name="UPLOAD_TIME" /> पर अपलोड की गई</translation>
<translation id="3681007416295224113">प्रमाणपत्र जानकारी</translation>
-<translation id="3690164694835360974">लॉगिन सुरक्षित नहीं है</translation>
-<translation id="3704162925118123524">आप जिस नेटवर्क का उपयोग कर रहे हैं उसके लिए आपको प्रवेश पृष्‍ठ पर जाने की आवश्‍यकता हो सकती है.</translation>
+<translation id="3704162925118123524">आप जिस नेटवर्क का उपयोग कर रहे हैं उसके लिए आपको लॉगिन पेज पर जाने की ज़रूरत हो सकती है.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">लोड हो रही हैं...</translation>
<translation id="3712624925041724820">लाइसेंस समाप्त हो गए</translation>
@@ -407,9 +407,9 @@
<translation id="3715597595485130451">वाई-फ़ाई से कनेक्ट करें</translation>
<translation id="3717027428350673159"><ph name="BEGIN_LINK" />प्रॉक्सी, फायरवॉल और DNS कॉन्फ़िगरेशन की जाँच करें<ph name="END_LINK" /></translation>
<translation id="372429172604983730">जिन ऐप्लिकेशन की वजह से यह गड़बड़ी हो सकती है उनमें एंटीवायरस, फ़ायरवॉल और वेब-फ़िल्टरिंग या प्रॉक्सी सॉफ़्टवेयर शामिल हैं.</translation>
-<translation id="3736520371357197498">यदि आप अपनी सुरक्षा में होने वाले जोखिमों को समझते हैं, तो आप खतरनाक प्रोग्राम निकाले जाने से पहले <ph name="BEGIN_LINK" />इस असुरक्षित साइट पर विज़िट<ph name="END_LINK" /> कर सकते हैं.</translation>
+<translation id="3736520371357197498">अगर आप अपनी सुरक्षा संबंधी जोखिमों को समझते हैं तो, खतरनाक प्रोग्राम हटाए जाने से पहले आप <ph name="BEGIN_LINK" />इस असुरक्षित साइट पर विज़िट<ph name="END_LINK" /> कर सकते हैं.</translation>
<translation id="3739623965217189342">काॅपी किया गया लिंक</translation>
-<translation id="3744899669254331632">आप इस समय <ph name="SITE" /> पर नहीं जा सकते क्‍योंकि वेबसाइट ने ऐसी अव्‍यवस्‍थित प्रमाणिकताएं भेजी थीं जिन्‍हें क्रोमियम संसाधित नहीं कर सकता. नेटवर्क की त्रुटियां और हमले आमतौर पर अस्‍थायी होते हैं, इसलिए संभवत: यह पृष्‍ठ बाद में काम करेगा.</translation>
+<translation id="3744899669254331632">आप इस समय <ph name="SITE" /> पर नहीं जा सकते क्‍योंकि वेबसाइट ने ऐसे अव्‍यवस्‍थित क्रेडेंशियल भेजे हैं जिन्‍हें क्रोमियम प्रोसेस नहीं कर सकता. नेटवर्क की गड़बड़ी और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए मुमकिन है कि यह पेज बाद में काम करे.</translation>
<translation id="3748148204939282805"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर आपको सॉफ़्टवेयर इंस्टॉल करने या अपनी व्यक्तिगत जानकारी (उदाहरण के लिए, पासवर्ड, फ़ोन नंबर या क्रेडिट कार्ड) का खुलासा करने जैसा खतरनाक काम करने के लिए भ्रमित कर सकते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="375403751935624634">सर्वर गड़बड़ी के कारण अनुवाद विफल.</translation>
<translation id="3759461132968374835">आपके पास हाल ही में रिपोर्ट किए गए क्रैश नहीं हैं. क्रैश रिपोर्टिंग अक्षम होने के दौरान होने वाले क्रैश यहां दिखाई नहीं देंगे.</translation>
@@ -437,18 +437,18 @@
<translation id="397105322502079400">गणना की जा रही है...</translation>
<translation id="3973234410852337861"><ph name="HOST_NAME" /> अवरुद्ध है</translation>
<translation id="3984550557525787191">यह सत्र नाम पहले से मौजूद है.</translation>
-<translation id="3987940399970879459">1 MB से कम</translation>
+<translation id="3987940399970879459">एक एमबी से कम</translation>
<translation id="40103911065039147">{URL_count,plural, =1{आस-पास 1 वेब पेज है}one{आस-पास # वेब पेज हैं}other{आस-पास # वेब पेज हैं}}</translation>
<translation id="4030383055268325496">&amp;जोड़ना वापस लाएं</translation>
<translation id="4058922952496707368">कुंजी "<ph name="SUBKEY" />": <ph name="ERROR" /></translation>
<translation id="4067947977115446013">मान्य पता जोड़ें</translation>
<translation id="4072486802667267160">आपका आदेश संसाधित करते समय गड़बड़ी हुई. कृपया फिर से कोशिश करें.</translation>
<translation id="4075732493274867456">क्लाइंट और सर्वर, सामान्य SSL प्रोटोकॉल वर्शन या सिफ़र सुइट का समर्थन नहीं करते हैं.</translation>
-<translation id="4079302484614802869">प्रॉक्‍सी कॉन्‍फ़िगरेशन को .pac स्‍क्रिप्‍ट URL का उपयोग करने के लिए सेट किया जाता है, फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर के लिए नहीं.</translation>
+<translation id="4079302484614802869">प्रॉक्‍सी कॉन्‍फ़िगरेशन को .pac स्‍क्रिप्‍ट यूआरएल का उपयोग करने के लिए सेट किया जाता है, फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर के लिए नहीं.</translation>
<translation id="4098354747657067197">आगे भ्रामक साइट है</translation>
-<translation id="4103249731201008433">डिवाइस की क्रम संख्या अमान्य है</translation>
+<translation id="4103249731201008433">डिवाइस की क्रम संख्या गलत है</translation>
<translation id="410351446219883937">स्वतः चलाएं</translation>
-<translation id="4103763322291513355">काली सूची में डाले गए URL तथा आपके सिस्टम व्यवस्थापक द्वारा लागू की गई अन्य नीतियों को देखने के लिए &lt;strong&gt;chrome://policy&lt;/strong&gt; पर जाएं.</translation>
+<translation id="4103763322291513355">प्रतिबंधित किए गए यूआरएल और आपके सिस्टम ए़़डमिन ने जिन अन्य नीतियों को लागू किया है, उन्हें देखने के लिए &lt;strong&gt;chrome://policy&lt;/strong&gt; पर जाएं.</translation>
<translation id="4110652170750985508">अपना भुगतान देखें</translation>
<translation id="4116663294526079822">इस साइट पर हमेशा अनुमति दें</translation>
<translation id="4117700440116928470">नीति क्षेत्र समर्थित नहीं है.</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">वैश्‍विक डिफ़ॉल्‍ट का उपयोग करें (पता करें)</translation>
<translation id="4165986682804962316">साइट सेटिंग</translation>
-<translation id="4169947484918424451">क्या आप चाहते हैं कि क्रोमियम इस कार्ड को सहेजे?</translation>
<translation id="4171400957073367226">गलत सत्यापन हस्ताक्षर</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> और आइटम}one{<ph name="ITEM_COUNT" /> और आइटम}other{<ph name="ITEM_COUNT" /> और आइटम}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -466,24 +465,24 @@
<translation id="4196861286325780578">&amp;ले जाना फिर से करें</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />फायरवॉल और एंटीवायरस कॉन्फ़िगरेशन की जाँच करें<ph name="END_LINK" /></translation>
<translation id="4220128509585149162">क्रैश</translation>
-<translation id="422022731706691852"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर आपको ऐसे प्रोग्राम इंस्टॉल करने के लिए भ्रमित करने की कोशिश सकते हैं जिनसे आपके ब्राउज़िंग अनुभव को नुकसान पहुंच सकता है (उदाहरण के लिए, आपका होमपेज बदलकर या आप जिन साइटों पर जाते हैं उन पर अतिरिक्त विज्ञापन दिखाकर). <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="422022731706691852"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर धोखे से आपसे ऐसे प्रोग्राम इंस्टॉल करवाने की कोशिश कर सकते हैं, जिनसे आपके ब्राउज़िंग अनुभव को नुकसान पहुंच सकता है (उदाहरण के लिए, आपका होमपेज बदलकर या आप जिन साइटों पर जाते हैं उन पर ज़्यादा विज्ञापन दिखाकर). <ph name="BEGIN_LEARN_MORE_LINK" />ज़्यादा जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4221630205957821124">&lt;h4&gt;कदम 1: पोर्टल में साइन इन करें&lt;/h4&gt;
&lt;p&gt;कैफ़े या हवाई अड्डों जैसी जगहों पर मौजूद वाई-फ़ाई नेटवर्क के लिए आपको साइन इन करना होगा. साइन-इन पेज देखने के लिए, किसी ऐसे पेज पर जाएं जो &lt;code&gt;http://&lt;/code&gt; का इस्तेमाल करता है.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;li&gt;&lt;code&gt;http://&lt;/code&gt; से शुरू होने वाली किसी भी वेबसाइट, जैसे कि &lt;a href="http://example.com" target="_blank"&gt;http://example.com&lt;/a&gt; पर जाएं.&lt;/li&gt;
- &lt;li&gt;इंटरनेट का इस्तेमाल करने के लिए, खुलने वाले साइन-इन पेज पर साइन इन करें.&lt;/li&gt;
+ &lt;li&gt;इंटरनेट का इस्तेमाल करने के लिए, साइन-इन का जो पेज खुलता है वहां पर साइन इन करें.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;कदम 2: पेज को गुप्त मोड में खोलें (सिर्फ़ कंप्यूटर)&lt;/h4&gt;
- &lt;p&gt;वह पेज खोलें, जिस पर आप गुप्त विंडो में आए थे.&lt;/p&gt;
- &lt;p&gt;अगर पेज खुल जाता है, तो कोई Chrome एक्सटेंशन ठीक से काम नहीं कर रहा है. गड़बड़ी को ठीक करने के लिए, एक्सटेंशन बंद करें.&lt;/p&gt;
+ &lt;p&gt;वह पेज खोलें, जिस पर आप गुप्त विंडो के ज़रिए आए थे.&lt;/p&gt;
+ &lt;p&gt;अगर पेज खुल जाता है तो, इसका मतलब है कि कोई Chrome एक्सटेंशन ठीक से काम नहीं कर रहा है. गड़बड़ी को ठीक करने के लिए, एक्सटेंशन बंद करें.&lt;/p&gt;
&lt;h4&gt;कदम 3: अपना ऑपरेटिंग सिस्टम अपडेट करें&lt;/h4&gt;
- &lt;p&gt;पक्का करें कि आपका डिवाइस अप टू डेट है.&lt;/p&gt;
+ &lt;p&gt;पक्का करें कि आपका डिवाइस अप-टू-डेट है.&lt;/p&gt;
&lt;h4&gt;कदम 4: अपना एंटीवायरस कुछ देर के लिए बंद करें&lt;/h4&gt;
- &lt;p&gt;अगर आपके पास ऐसा एंटीवायरस सॉफ़्टवेयर है जो "HTTPS सुरक्षा" या "HTTPS स्कैनिंग" उपलब्ध कराता है, तो आपको यह गड़बड़ी दिखाई देती है. एंटीवायरस, सुरक्षा उपलब्ध कराने से Chrome को रोक रहा है.&lt;/p&gt;
- &lt;p&gt;समस्या को ठीक करने के लिए, अपना एंटीवायरस सॉफ़्टवेयर बंद करें. अगर सॉफ़्टवेयर बंद करने के बाद पेज काम करता है, तो सुरक्षित साइटों का इस्तेमाल करते समय इस सॉफ़्टवेयर को बंद कर दें.&lt;/p&gt;
+ &lt;p&gt;अगर आपके पास ऐसा एंटीवायरस सॉफ़्टवेयर है जो "HTTPS सुरक्षा" या "HTTPS स्कैनिंग" उपलब्ध कराता है तो, आपको यह गड़बड़ी दिखाई देती है. एंटीवायरस, Chrome को सुरक्षा उपलब्ध कराने से रोक रहा है.&lt;/p&gt;
+ &lt;p&gt;समस्या को ठीक करने के लिए, अपना एंटीवायरस सॉफ़्टवेयर बंद करें. अगर सॉफ़्टवेयर बंद करने के बाद पेज काम करता है तो, सुरक्षित साइटों का इस्तेमाल करते समय इस सॉफ़्टवेयर को बंद कर दें.&lt;/p&gt;
&lt;p&gt;जब आपका काम हो जाए तो अपना एंटीवायरस प्रोग्राम वापस चालू करना न भूलें.&lt;/p&gt;
&lt;h4&gt;कदम 5: ज़्यादा मदद पाएं&lt;/h4&gt;
- &lt;p&gt;अगर आपको अभी भी गड़बड़ी दिखाई दे रही है, तो वेबसाइट के मालिक से संपर्क करें.&lt;/p&gt;</translation>
+ &lt;p&gt;अगर आपको अभी भी गड़बड़ी दिखाई दे रही है तो, वेबसाइट के मालिक से संपर्क करें.&lt;/p&gt;</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />नेटवर्क निदान चलाकर देखें<ph name="END_LINK" />.</translation>
<translation id="4235360514405112390">मान्य</translation>
<translation id="4250431568374086873">इस साइट से आपका कनेक्शन पूरी तरह से सुरक्षित नहीं है</translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">अपना डिवाइस पुन: प्रारंभ करें</translation>
<translation id="4277028893293644418">पासवर्ड रीसेट करें</translation>
<translation id="4280429058323657511">, समाप्ति दिनांक <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">बदलें</translation>
<translation id="4312866146174492540">अवरुद्ध करें (डिफ़ॉल्ट)</translation>
<translation id="4325863107915753736">लेख ढूंढ़ने में विफल</translation>
<translation id="4326324639298822553">अपना समाप्ति दिनांक जाँचें और फिर से कोशिश करें</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">इस कंप्यूटर की पहचान एंटरप्राइज़ की ओर से प्रबंधित होने के रूप में नहीं की गई है इसलिए नीति सिर्फ़ Chrome वेबस्टोर पर होस्ट किए जाने वाले एक्सटेंशन ही अपने आप इंस्टॉल कर सकती है. Chrome वेबस्टोर अपडेट यूआरएल "<ph name="CWS_UPDATE_URL" />" है.</translation>
<translation id="4346197816712207223">स्वीकार किए जाने वाले क्रेडिट कार्ड</translation>
<translation id="4356973930735388585">इस साइट पर मौजूद हमलावर आपके कंप्यूटर पर ऐसे खतरनाक प्रोग्राम इंस्टॉल करने की कोशिश कर सकते हैं जो आपकी जानकारी (उदाहरण के लिए, फ़ोटो, पासवर्ड, संदेश और क्रेडिट कार्ड) चुरा लेते हैं या उसे हटा देते हैं.</translation>
+<translation id="4358461427845829800">भुगतान विधियां प्रबंधित करें...</translation>
<translation id="4372948949327679948">अपेक्षित <ph name="VALUE_TYPE" /> मान.</translation>
<translation id="4377125064752653719">आपने <ph name="DOMAIN" /> तक पहुंचने का प्रयास किया, लेकिन सर्वर द्वारा प्रस्तुत प्रमाणपत्र को उसके जारीकर्ता द्वारा रद्द कर दिया गया है. इसका अर्थ है कि सर्वर द्वारा प्रस्तुत सुरक्षा प्रमाणिकता पर पूर्णतया विश्वास नहीं करना चाहिए. हो सकता है कि आप किसी हमलावर से बातचीत कर रहे हों.</translation>
<translation id="4406896451731180161">खोज परिणाम</translation>
@@ -509,11 +510,12 @@
<translation id="4415426530740016218">पिकअप का पता</translation>
<translation id="4424024547088906515">यह सर्वर यह नहीं प्रमाणित कर सका कि यह <ph name="DOMAIN" /> है; इसका सुरक्षा प्रमाणपत्र Chrome द्वारा विश्वसनीय नहीं है. ऐसा गलत कॉन्फ़िगरेशन या किसी आक्रमणकर्ता द्वारा आपके कनेक्शन में अवरोध डालने के कारण हो सकता है.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपका लॉगिन प्रमाणपत्र स्वीकार नहीं किया है या हो सकता है कि प्रमाणपत्र उपलब्ध नहीं कराया गया हो.</translation>
+<translation id="4434045419905280838">पॉप-अप और रीडायरेक्ट</translation>
<translation id="443673843213245140">प्रॉक्‍सी का उपयोग अक्षम है लेकिन कोई स्‍पष्ट प्रॉक्‍सी कॉन्फ़िगरेशन निर्दिष्ट किया गया है.</translation>
<translation id="445100540951337728">स्वीकृत डेबिट कार्ड</translation>
<translation id="4506176782989081258">सत्‍यापन गड़बड़ी: <ph name="VALIDATION_ERROR" /></translation>
<translation id="4506599922270137252">सिस्टम व्यवस्थापक से संपर्क करें</translation>
-<translation id="450710068430902550">व्यवस्थापक के साथ साझा करना</translation>
+<translation id="450710068430902550">व्यवस्थापक के साथ शेयर करना</translation>
<translation id="4515275063822566619">कार्ड और पते Chrome और आपके Google खाते (<ph name="ACCOUNT_EMAIL" />) से मिलते हैं. आप उन्हें <ph name="BEGIN_LINK" />सेटिंग<ph name="END_LINK" /> में जाकर प्रबंधित कर सकते हैं.</translation>
<translation id="4522570452068850558">विवरण</translation>
<translation id="4552089082226364758">फ़्लैश</translation>
@@ -543,16 +545,16 @@
<translation id="4759118997339041434">भुगतान का ऑटोमैटिक भरना अक्षम</translation>
<translation id="4764776831041365478"><ph name="URL" /> पर मौजूद वेबपेज संभवतः अस्थायी रूप से बंद है या उसे स्थायी रूप से किसी नए वेब पते पर ले जाया गया है.</translation>
<translation id="4771973620359291008">अज्ञात गड़बड़ी आई.</translation>
+<translation id="4785689107224900852">इस टैब पर जाएं</translation>
<translation id="4792143361752574037">सत्र फ़ाइलें एक्सेस करते समय कोई समस्या हुई. फ़िलहाल डिस्क में सेव करने की सुविधा बंद है. दोबारा कोशिश करने के लिए कृपया पेज फिर से लोड करें.</translation>
<translation id="4800132727771399293">अपना अवधि समाप्‍ति दिनांक और CVC जाँचें और पुन: प्रयास करें</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
-<translation id="4807049035289105102">आप इस समय <ph name="SITE" /> पर विज़िट नहीं कर सकते हैं क्योंकि वेबसाइट ने ऐसे अव्यवस्थित क्रेडेंशियल भेजे हैं जिन्हें Google Chrome संसाधित नहीं कर सकता. नेटवर्क की त्रुटियां और हमले आमतौर पर अस्थायी होते हैं, इसलिए संभवत: यह पेज बाद में काम करेगा.</translation>
+<translation id="4807049035289105102">आप इस समय <ph name="SITE" /> पर नहीं जा सकते क्‍योंकि वेबसाइट ने ऐसे अव्‍यवस्‍थित क्रेडेंशियल भेजे हैं जिन्‍हें Google Chrome प्रोसेस नहीं कर सकता. नेटवर्क की गड़बड़ी और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए मुमकिन है कि यह पेज बाद में काम करे.</translation>
<translation id="4813512666221746211">नेटवर्क गड़बड़ी</translation>
<translation id="4816492930507672669">पेज में फ़िट करें</translation>
-<translation id="483020001682031208">दिखाने के लिए कोई जीता-जागता वेब पेज नहीं है</translation>
<translation id="4850886885716139402">देखें</translation>
<translation id="4854362297993841467">वितरण का यह तरीका उपलब्ध नहीं है. कोई दूसरा तरीका आज़माएं.</translation>
-<translation id="4858792381671956233">आपने अपने अभिभावकों से पूछा था कि इस साइट पर जाना ठीक है या नहीं</translation>
+<translation id="4858792381671956233">आपने अपने अभिभावकों से पूछा है कि इस साइट पर जाना ठीक है या नहीं</translation>
<translation id="4880827082731008257">खोज इतिहास</translation>
<translation id="4881695831933465202">खोलें</translation>
<translation id="4895877746940133817"><ph name="TYPE_1" />, <ph name="TYPE_2" />, <ph name="TYPE_3" /></translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-बिट)</translation>
<translation id="5121084798328133320">आपकी ओर से पुष्टि होने के बाद, आपके Google Payments खाते में मौजूद कार्ड के विवरण इस साइट से शेयर किए जाएंगे.</translation>
<translation id="5128122789703661928">इस नाम वाला सीज़न मिटाने के लिए मान्य नहीं है.</translation>
+<translation id="5135404736266831032">पते प्रबंधित करें...</translation>
<translation id="5141240743006678641">समन्वयित पासवर्ड अपने Google प्रमाणिकता के साथ एन्क्रिप्ट करें</translation>
<translation id="5145883236150621069">नीति प्रतिसाद में गड़बड़ी कोड मौजूद है</translation>
<translation id="5159010409087891077">पेज को नई गुप्त विंडो में खोलें (⇧⌘N)</translation>
@@ -600,19 +603,18 @@
<translation id="5201306358585911203">इस पेज पर एम्बेड किए गए पेज का कहना है कि</translation>
<translation id="5205222826937269299">नाम आवश्यक है</translation>
<translation id="5222812217790122047">ईमेल आवश्यक है</translation>
-<translation id="522700295135997067">शायद इस साइट ने अभी-अभी आपका पासवर्ड चुरा लिया है</translation>
<translation id="5230733896359313003">शिपिंग पता</translation>
<translation id="5250209940322997802">"नेटवर्क से कनेक्ट करें"</translation>
<translation id="5251803541071282808">क्लाउड</translation>
-<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />इन चरणों का पालन करके सॉफ़्टवेयर को कुछ समय के लिए अक्षम करें ताकि आप वेब पर जा सकें. आपको व्यावस्थापकीय विशेषाधिकारों की ज़रूरत होगी.<ph name="END_PARAGRAPH" />
+<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />नीचे दिए गए तरीके से सॉफ़्टवेयर को कुछ समय के लिए बंद करें ताकि आप वेब पर जा सकें. इसके लिए आपको एडमिन को मिलने वाले खास अधिकार चाहिए होंगे.<ph name="END_PARAGRAPH" />
<ph name="BEGIN_LIST" />
- <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />शुरू करें<ph name="END_BOLD" /> को क्लिक करें, फिर <ph name="BEGIN_BOLD" />"स्थानीय सेवाएं देखें"<ph name="END_BOLD" /> को खोजें और चुनें
+ <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />शुरू करें<ph name="END_BOLD" /> पर क्लिक करें, इसके बाद <ph name="BEGIN_BOLD" />"स्थानीय सेवाएं देखें"<ph name="END_BOLD" /> को खोजें और चुनें
<ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />VisualDiscovery<ph name="END_BOLD" /> चुनें
- <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />स्टार्टअप प्रकार<ph name="END_BOLD" /> के अंतर्गत, <ph name="BEGIN_BOLD" />अक्षम<ph name="END_BOLD" /> चुनें
- <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />सेवा स्थिति<ph name="END_BOLD" /> के अंतर्गत, <ph name="BEGIN_BOLD" />रोकें<ph name="END_BOLD" /> को क्लिक करें
- <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />लागू करें<ph name="END_BOLD" /> को क्लिक करें, फिर <ph name="BEGIN_BOLD" />ठीक है<ph name="END_BOLD" /> क्लिक करें
- <ph name="LIST_ITEM" />अपने कंप्यूटर से हमेशा के लिए सॉफ़्टवेयर को निकालने का तरीका जानने के लिए <ph name="BEGIN_LEARN_MORE_LINK" />Chrome सहायता केंद्र<ph name="END_LEARN_MORE_LINK" /> पर जाएं
+ <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />स्टार्टअप प्रकार<ph name="END_BOLD" /> में <ph name="BEGIN_BOLD" />बंद किया गया<ph name="END_BOLD" /> चुनें
+ <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />सेवा स्थिति<ph name="END_BOLD" /> में <ph name="BEGIN_BOLD" />रोकें<ph name="END_BOLD" /> पर क्लिक करें
+ <ph name="LIST_ITEM" /><ph name="BEGIN_BOLD" />लागू करें<ph name="END_BOLD" /> पर क्लिक करें, फिर <ph name="BEGIN_BOLD" />ठीक है<ph name="END_BOLD" /> पर क्लिक करें
+ <ph name="LIST_ITEM" />अपने कंप्यूटर से सॉफ़्टवेयर को हमेशा के लिए हटाने का तरीका जानने के लिए <ph name="BEGIN_LEARN_MORE_LINK" />Chrome सहायता केंद्र<ph name="END_LEARN_MORE_LINK" /> पर जाएं
<ph name="END_LIST" /></translation>
<translation id="5285570108065881030">सेव किए गए सभी पासवर्ड दिखाएं</translation>
<translation id="5287240709317226393">कुकी दिखाएं</translation>
@@ -624,7 +626,7 @@
<translation id="5324080437450482387">संपर्क जानकारी चुनें</translation>
<translation id="5327248766486351172">नाम</translation>
<translation id="5332219387342487447">शिपिंग का तरीका</translation>
-<translation id="5355557959165512791">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि उसका प्रमाणपत्र निरस्त कर दिया गया है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए यह पेज शायद बाद में ठीक से काम करेगा.</translation>
+<translation id="5355557959165512791">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि उसका प्रमाणपत्र रद्द कर दिया गया है. नेटवर्क की गड़बड़ी और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए मुमकिन है कि यह पेज बाद में काम करे.</translation>
<translation id="536296301121032821">नीति सेटिंग संग्रहित करने में विफल</translation>
<translation id="5377026284221673050">"आपकी घड़ी पीछे चल रही है" या "आपकी घड़ी आगे चल रही है" या "&lt;span class="error-code"&gt;NET::ERR_CERT_DATE_INVALID&lt;/span&gt;"</translation>
<translation id="5386426401304769735">इस साइट की प्रमाणपत्र श्रृंखला में, SHA-1 का उपयोग करके हस्ताक्षर किया गया प्रमाणपत्र शामिल है.</translation>
@@ -641,10 +643,9 @@
<translation id="5470861586879999274">&amp;संपादित करना फिर से करें</translation>
<translation id="5481076368049295676">यह सामग्री आपके डिवाइस पर ऐसा खतरनाक सॉफ़्टवेयर इंस्टॉल करने की कोशिश कर सकती है जो आपकी जानकारी चुरा सकता है या उसे हटा सकता है. <ph name="BEGIN_LINK" />फिर भी दिखाएं<ph name="END_LINK" /></translation>
<translation id="54817484435770891">मान्य पता जोड़ें</translation>
-<translation id="5492298309214877701">कंपनी, संगठन या विद्यालय के इंट्रानेट पर इस साइट का URL एक बाहरी वेबसाइट जैसा है.
+<translation id="5492298309214877701">किसी कंपनी, संगठन या स्कूल के इंट्रानेट पर इस साइट का URL एक बाहरी वेबसाइट जैसा है.
<ph name="LINE_BREAK" />
- अपने सिस्टम व्यस्थापक से संपर्क करने का प्रयास करें.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> का सुरक्षा कोड डालें. यह कोड सेव नहीं किया जाएगा.</translation>
+ अपने सिस्टम एडमिन से संपर्क करने की कोशिश करें.</translation>
<translation id="5509780412636533143">प्रबंधित बुकमार्क</translation>
<translation id="5510766032865166053">हो सकता है कि उसे ले जाया गया हो या हटा दिया गया हो.</translation>
<translation id="5523118979700054094">नीति का नाम</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">शिपिंग पता जोड़ें</translation>
<translation id="5689199277474810259">JSON में निर्यात करें</translation>
<translation id="5689516760719285838">स्थान</translation>
+<translation id="570530837424789914">प्रबंधित करें...</translation>
<translation id="5710435578057952990">इस वेबसाइट की पहचान सत्यापित नहीं की गई है.</translation>
<translation id="5719499550583120431">प्रीपेड कार्ड स्वीकार किए जाते हैं.</translation>
<translation id="5720705177508910913">वर्तमान उपयोगकर्ता</translation>
+<translation id="5730040223043577876">अगर आपने अपने पासवर्ड का दूसरी साइटों पर दोबारा इस्तेमाल किया है, तो Chrome आपको उसे रीसेट करने का सुझाव देता है.</translation>
<translation id="5732392974455271431">आपके अभिभावक इसे आपके लिए अनवरोधित कर सकते हैं</translation>
<translation id="5763042198335101085">मान्य ईमेल पता डालें</translation>
<translation id="5765072501007116331">वितरण के तरीके और ज़रूरतें देखने के लिए, कोई पता चुनें</translation>
@@ -701,11 +704,9 @@
<translation id="5959728338436674663">Google को कुछ <ph name="BEGIN_WHITEPAPER_LINK" />सिस्टम संबंधी जानकारी और पेज सामग्री<ph name="END_WHITEPAPER_LINK" /> अपने आप भेजें ताकि खतरनाक ऐप्लिकेशन और साइटों का पता लगाने में सहायता मिल सके. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">संपर्क जानकारी में बदलाव करें</translation>
<translation id="5967867314010545767">इतिहास से निकालें</translation>
-<translation id="5972020793760134803">टैब स्विच करें</translation>
<translation id="5975083100439434680">ज़ूम आउट</translation>
-<translation id="597552863672748783">सुरक्षा कोड की पुष्टि करें</translation>
<translation id="598637245381783098">भुगतान ऐप्लिकेशन नहीं खोला जा सकता</translation>
-<translation id="5989320800837274978">न तो कोई फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर और न ही कोई .pac स्क्रिप्ट URL निर्दिष्ट किए गए हैं.</translation>
+<translation id="5989320800837274978">न तो कोई फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर और न ही कोई .pac स्क्रिप्ट URL साफ़ तौर पर बताया गया है.</translation>
<translation id="5990559369517809815">सर्वर से किए गए अनुरोधों को एक्‍सटेंशन द्वारा अवरुद्ध कर दिया गया है.</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6015796118275082299">वर्ष</translation>
@@ -715,10 +716,11 @@
<translation id="6027201098523975773">नाम डालें</translation>
<translation id="6039846035001940113">अगर समस्या बनी रहती है, तो साइट के मालिक से संपर्क करें.</translation>
<translation id="6040143037577758943">बंद करें</translation>
-<translation id="6047233362582046994">अगर आप अपनी सुरक्षा में होने वाले जोखिमों को समझते हैं, तो खतरनाक ऐप्लिकेशन निकाले जाने से पहले आप <ph name="BEGIN_LINK" />इस साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
+<translation id="6047233362582046994">अगर आप अपनी सुरक्षा को होने वाले खतरों के बारे में जानते हैं तो, खतरनाक ऐप्लिकेशन हटाए जाने से पहले आप <ph name="BEGIN_LINK" />इस साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
<translation id="6047927260846328439">यह सामग्री आपसे धोखे से सॉफ़्टवेयर इंस्‍टॉल करवाने या व्यक्तिगत जानकारी का खुलासा करवाने की कोशिश कर सकती है. <ph name="BEGIN_LINK" />फिर भी दिखाएं<ph name="END_LINK" /></translation>
-<translation id="6051221802930200923">आप इस समय <ph name="SITE" /> पर नहीं जा सकते हैं क्योंकि वेबसाइट प्रमाणपत्र पिनिंग का उपयोग करती है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ देर के लिए होते हैं, इसलिए यह पेज शायद बाद में ठीक से काम करेगा.</translation>
+<translation id="6051221802930200923">आप इस समय <ph name="SITE" /> पर नहीं जा सकते क्योंकि वेबसाइट, प्रमाणपत्र पिनिंग का उपयोग करती है. नेटवर्क की गड़बड़ियां और हमले आमतौर पर कुछ समय के लिए होते हैं इसलिए यह पेज शायद बाद में ठीक से काम करेगा.</translation>
<translation id="6059925163896151826">USB डिवाइस</translation>
+<translation id="6071091556643036997">नीति का प्रकार गलत है.</translation>
<translation id="6080696365213338172">आपने व्यवस्थापक द्वारा प्रदत्त प्रमाणपत्र के उपयोग से सामग्री एक्सेस की है. आपके द्वारा <ph name="DOMAIN" /> को प्रदान किया गया डेटा आपके व्यवस्थापक द्वारा बीच में रोका जा सकता है.</translation>
<translation id="610911394827799129">आपके Google खाते में <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> पर दूसरी तरह के ब्राउज़िंग इतिहास हो सकते हैं</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{कुछ नहीं}=1{1 पासवर्ड (सिंक किया हुआ)}one{# पासवर्ड (सिंक किए हुए)}other{# पासवर्ड (सिंक किए हुए)}}</translation>
@@ -735,7 +737,7 @@
<translation id="6221345481584921695">Google सुरक्षित ब्राउज़िंग को <ph name="SITE" /> पर हाल ही में <ph name="BEGIN_LINK" />मैलवेयर का पता चला<ph name="END_LINK" /> है. आमतौर पर सुरक्षित रहने वाली वेबसाइटें कभी-कभी मैलेवयर से संक्रमित हो जाती हैं. दुर्भावनापूर्ण सामग्री <ph name="SUBRESOURCE_HOST" /> से आती है, जो कि एक ज्ञात मैलवेयर वितरक है.</translation>
<translation id="6251924700383757765">निजता नीति</translation>
<translation id="6254436959401408446">यह पेज खोलने के लिए ज़रूरी जगह नहीं है</translation>
-<translation id="625755898061068298">आपने इस साइट के लिए सुरक्षा चेतावनियों को अक्षम करना चुना है.</translation>
+<translation id="625755898061068298">आपने इस साइट के लिए सुरक्षा चेतावनियों को बंद करने का विकल्प चुना है.</translation>
<translation id="6259156558325130047">&amp;पुन: क्रमित करना फिर से करें</translation>
<translation id="6263376278284652872"><ph name="DOMAIN" /> बुकमार्क</translation>
<translation id="6264485186158353794">सुरक्षा पर वापस</translation>
@@ -749,7 +751,7 @@
<translation id="6321917430147971392">अपनी DNS सेटिंग जाँचें</translation>
<translation id="6328639280570009161">नेटवर्क पूर्वानुमान को अक्षम करके देखें</translation>
<translation id="6328786501058569169">यह साइट भ्रामक है</translation>
-<translation id="6337133576188860026"><ph name="SIZE" /> से कम जगह खाली करता है. आपकी अगली विज़िट पर कुछ साइटें और भी धीमे लोड हो सकती हैं.</translation>
+<translation id="6337133576188860026"><ph name="SIZE" /> से कम जगह खाली करता है. जब आप अगली बार विज़िट करेंगे तो, कुछ साइटें और धीमे लोड हो सकती हैं.</translation>
<translation id="6337534724793800597">नाम के अनुसार नीतियां फ़िल्टर करें</translation>
<translation id="6342069812937806050">अभी</translation>
<translation id="6355080345576803305">सार्वजनिक सत्र ओवरराइड</translation>
@@ -759,13 +761,14 @@
<translation id="6397451950548600259">आपके कंप्यूटर पर मौजूद सॉफ़्टवेयर Chrome को सुरक्षित रूप से वेब से कनेक्ट होने से रोक रहा है</translation>
<translation id="6404511346730675251">बुकमार्क संपादित करें</translation>
<translation id="6410264514553301377"><ph name="CREDIT_CARD" /> का समाप्ति दिनांक और CVC डालें</translation>
-<translation id="6414888972213066896">आपने अपने अभिभावक से पूछा था कि इस साइट पर जाना ठीक है या नहीं</translation>
+<translation id="6414888972213066896">आपने अपने अभिभावक से पूछा है कि इस साइट पर जाना ठीक है या नहीं</translation>
<translation id="6417515091412812850">प्रमाणपत्र को रद्द किया गया है या नहीं यह जाँच करने में असमरर्थ.</translation>
<translation id="6433490469411711332">संपर्क जानकारी संपादित करें</translation>
<translation id="6433595998831338502"><ph name="HOST_NAME" /> ने कनेक्ट करने से मना कर दिया है.</translation>
<translation id="6446608382365791566">और जानकारी जोड़ें</translation>
<translation id="6447842834002726250">कुकी</translation>
<translation id="6451458296329894277">फ़ार्म पुन: जमा करने की दुबारा पूछें</translation>
+<translation id="6465306955648956876">पासवर्ड प्रबंधित करें...</translation>
<translation id="647261751007945333">डिवाइस नीतियां</translation>
<translation id="6477321094435799029">Chrome को इस पेज पर असामान्य कोड मिला था और उसने आपकी व्यक्तिगत जानकारी (उदाहरण के लिए, पासवर्ड, फ़ोन नंबर और क्रेडिट कार्ड) की सुरक्षा करने के लिए उसे अवरुद्ध कर दिया है.</translation>
<translation id="6489534406876378309">क्रैश अपलोड करना प्रारंभ करें</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> खोज</translation>
<translation id="6630809736994426279">इस समय <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> पर मौजूद हमलावर आपके Mac पर ऐसे खतरनाक प्रोग्राम इंस्टॉल करने की कोशिश कर सकते हैं जो आपकी जानकारी (उदाहरण के लिए, फ़ोटो, पासवर्ड, संदेश और क्रेडिट कार्ड) चुराते हैं या उसे हटा देते हैं. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जानें<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">यह नीति हटा दी गई है.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{कोई नहीं}=1{1 साइट से (आप अपने Google खाते से साइन आउट नहीं होंगे)}one{# साइटों से (आप अपने Google खाते से साइन आउट नहीं होंगे)}other{# साइटों से (आप अपने Google खाते से साइन आउट नहीं होंगे)}}</translation>
<translation id="6657585470893396449">पासवर्ड</translation>
<translation id="6671697161687535275">क्रोमियम से फ़ॉर्म सुझाव निकालें?</translation>
<translation id="6685834062052613830">प्रस्थान करें और सेटअप पूरा करें</translation>
@@ -811,11 +815,12 @@
<translation id="6915804003454593391">उपयोगकर्ता:</translation>
<translation id="6945221475159498467">चुनें</translation>
<translation id="6948701128805548767">पिकअप के तरीके और ज़रूरतें देखने के लिए, कोई पता चुनें</translation>
+<translation id="6949872517221025916">पासवर्ड रीसेट करें</translation>
<translation id="6957887021205513506">सर्वर का प्रमाणपत्र फर्जी दिखाई देता है.</translation>
<translation id="6965382102122355670">ठीक है</translation>
<translation id="6965978654500191972">डिवाइस</translation>
<translation id="6970216967273061347">जिला</translation>
-<translation id="6973656660372572881">फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर और .pac स्‍क्रिप्‍ट URL दोनों ही निर्दिष्ट हैं.</translation>
+<translation id="6973656660372572881">फ़िक्‍स्‍ड प्रॉक्‍सी सर्वर और .pac स्‍क्रिप्‍ट URL दोनों ही बताए गए हैं.</translation>
<translation id="6989763994942163495">अतिरिक्त सेटिंग दिखाएं...</translation>
<translation id="7012363358306927923">China UnionPay</translation>
<translation id="7029809446516969842">पासवर्ड</translation>
@@ -832,29 +837,29 @@
<translation id="7138472120740807366">वितरण का तरीका</translation>
<translation id="7139724024395191329">अमीरात</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> अन्य}one{<ph name="PAYMENT_METHOD_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> अन्य}other{<ph name="PAYMENT_METHOD_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> अन्य}}</translation>
-<translation id="7155487117670177674">भुगतान सुरक्षित नहीं है</translation>
+<translation id="717330890047184534">Gaia आईडी:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> अन्य}one{<ph name="SHIPPING_OPTION_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> अन्य}other{<ph name="SHIPPING_OPTION_PREVIEW" /> और <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> अन्य}}</translation>
<translation id="7180611975245234373">रीफ्रेश करें</translation>
<translation id="7182878459783632708">कोई नीति सेट नहीं की गई है</translation>
<translation id="7186367841673660872">इस पेज का <ph name="ORIGINAL_LANGUAGE" />से<ph name="LANGUAGE_LANGUAGE" /> में अनुवाद कर दिया गया है</translation>
-<translation id="7192203810768312527"><ph name="SIZE" /> की जगह बनाता है. कुछ साइटें आपकी अगली विज़िट पर ज़्यादा धीमे लोड हो सकती हैं.</translation>
+<translation id="7192203810768312527"><ph name="SIZE" /> जगह खाली करता है. जब आप अगली बार विज़िट करेंगे तो, कुछ साइटें और धीमे लोड हो सकती हैं.</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> सुरक्षा मानकों का पालन नहीं करता.</translation>
<translation id="721197778055552897">इस समस्या के बारे में <ph name="BEGIN_LINK" />अधिक जानें<ph name="END_LINK" />.</translation>
<translation id="7219179957768738017">कनेक्‍शन <ph name="SSL_VERSION" /> का उपयोग करता है.</translation>
<translation id="7220786058474068424">संसाधित हो रहा है</translation>
<translation id="724691107663265825">साइट में आगे मैलवेयर हैं</translation>
-<translation id="724975217298816891">अपने कार्ड विवरण अपडेट करने के लिए <ph name="CREDIT_CARD" /> का समय समाप्ति दिनांक और CVC डालें. आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ साझा किए जाएंगे.</translation>
+<translation id="724975217298816891">अपने कार्ड विवरण अपडेट करने के लिए <ph name="CREDIT_CARD" /> का समय समाप्ति दिनांक और CVC डालें. आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ शेयर किए जाएंगे.</translation>
<translation id="725866823122871198"><ph name="BEGIN_BOLD" /><ph name="DOMAIN" /><ph name="END_BOLD" /> से एक निजी कनेक्‍शन स्‍थापित नहीं किया जा सकता क्‍योंकि आपके कंप्‍यूटर का दिनांक और समय (<ph name="DATE_AND_TIME" />) गलत है.</translation>
<translation id="7260504762447901703">एक्सेस निरस्त करें</translation>
<translation id="7271803869921933038">स्वीकार किए जाने वाले प्रीपेड कार्ड</translation>
<translation id="7275334191706090484">प्रबंधित बुकमार्क</translation>
<translation id="7298195798382681320">सुझाए गए</translation>
-<translation id="7309308571273880165">क्रैैश रिपोर्ट <ph name="CRASH_TIME" /> बजे कैप्चर की गई (उपयोगकर्ता द्वारा अपलोड करने का अनुरोध किया गया, अभी तक अपलोड नहीं किया गया)</translation>
+<translation id="7309308571273880165">खराबी की रिपोर्ट <ph name="CRASH_TIME" /> बजे दर्ज की गई (उपयोगकर्ता ने अपलोड करने का अनुरोध किया, अभी तक अपलोड नहीं किया गया)</translation>
<translation id="7320336641823683070">कनेक्शन संबंधी सहायता</translation>
<translation id="7334320624316649418">&amp;पुन: क्रमित करना फिर से करें</translation>
<translation id="733923710415886693">प्रमाणपत्र पारदर्शिता के माध्यम से सर्वर के प्रमाणपत्र को प्रकट नहीं किया गया.</translation>
-<translation id="7353601530677266744">आदेश पंक्ति</translation>
+<translation id="7353601530677266744">कमांड लाइन</translation>
<translation id="7365061714576910172">Linux में निर्यात करें</translation>
<translation id="7372973238305370288">खोज परिणाम</translation>
<translation id="7377249249140280793"><ph name="RELATIVE_DATE" /> - <ph name="FULL_DATE" /></translation>
@@ -862,8 +867,8 @@
<translation id="7378810950367401542">/</translation>
<translation id="7390545607259442187">कार्ड की पुष्टि करें</translation>
<translation id="7400418766976504921">URL</translation>
-<translation id="7407424307057130981">&lt;p&gt;अगर आपके Windows कंप्यूटर पर Superfish सॉफ़्टवेयर है, तो आपको यह गड़बड़ी दिखाई देगी.&lt;/p&gt;
- &lt;p&gt;आगे बताए गए कदम उठाकर सॉफ़्टवेयर को कुछ देर के लिए बंद कर दें ताकि आप वेब पर जा सकें. आपको एडमिन विशेषाधिकार चाहिए होंगे.&lt;/p&gt;
+<translation id="7407424307057130981">&lt;p&gt;अगर आपके Windows कंप्यूटर पर Superfish सॉफ़्टवेयर है तो, आपको यह गड़बड़ी दिखाई देगी.&lt;/p&gt;
+ &lt;p&gt;आगे बताए गए कदम उठाकर सॉफ़्टवेयर को कुछ देर के लिए बंद कर दें ताकि आप वेब पर जा सकें. आपको एडमिन विशेषाधिकार की ज़रूरत होगी.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;शुरू करें&lt;/strong&gt; पर क्लिक करें, उसके बाद &lt;strong&gt;"स्थानीय सेवाएं देखें"&lt;/strong&gt; को खोजें और चुनें
&lt;li&gt;&lt;strong&gt;VisualDiscovery&lt;/strong&gt; चुनें
@@ -881,16 +886,17 @@
<translation id="7455133967321480974">वैश्विक डिफ़ॉल्ट का उपयोग करें (अवरोधित करें)</translation>
<translation id="7460163899615895653">आपके अन्य डिवाइस के हाल ही के टैब यहां दिखाई देंगे</translation>
<translation id="7469372306589899959">कार्ड की पुष्टि की जा रही है</translation>
-<translation id="7481312909269577407">आगे भेजें</translation>
+<translation id="7473891865547856676">जी रहने दें</translation>
+<translation id="7481312909269577407">आगे जाएं</translation>
<translation id="7485870689360869515">कोई डेटा नहीं मिला</translation>
<translation id="7508255263130623398">वापस लौटाया हुआ नीति डिवाइस आईडी खाली है या उसका मिलान वर्तमान डिवाइस आईडी से नहीं होता है</translation>
-<translation id="7511955381719512146">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की आवश्‍यकता हो सकती है.</translation>
+<translation id="7511955381719512146">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं, उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की ज़रूरत पड़ सकती है.</translation>
<translation id="7514365320538308">डाउनलोड करें</translation>
<translation id="7518003948725431193">इस वेब पते के लिए कोई वेब पेज नहीं मिला था: <ph name="URL" /></translation>
<translation id="7521387064766892559">JavaScript</translation>
<translation id="7526934274050461096">इस साइट से आपका कनेक्‍शन निजी नहीं है</translation>
<translation id="7537536606612762813">आवश्यक</translation>
-<translation id="7542403920425041731">आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ साझा किए जाएंगे.</translation>
+<translation id="7542403920425041731">आपकी तरफ से पुष्टि हो जाने पर, आपके कार्ड के विवरण इस साइट के साथ शेयर किए जाएंगे.</translation>
<translation id="7542995811387359312">स्वतः क्रेडिट कार्ड भरना अक्षम किया गया है क्योंकि यह फ़ॉर्म किसी सुरक्षित कनेक्शन का उपयोग नहीं करता है.</translation>
<translation id="7543525346216957623">अपने अभिभावक से पूछें</translation>
<translation id="7548892272833184391">कनेक्शन गड़बड़ियां ठीक करना</translation>
@@ -903,10 +909,9 @@
<translation id="7569952961197462199">Chrome से क्रेडिट कार्ड निकालें?</translation>
<translation id="7575800019233204241">"आपका कनेक्शन निजी नहीं है" या "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" या "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" या "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" या "SSL प्रमाणपत्र गड़बड़ी"</translation>
<translation id="7578104083680115302">Google के साथ सहेजे गए कार्ड का उपयोग करके डिवाइसों में मौजूद साइटों और ऐप्‍स पर तुरंत भुगतान करें.</translation>
-<translation id="7588950540487816470">जीता-जागता वेब</translation>
<translation id="7592362899630581445">सर्वर का प्रमाणपत्र नाम संबंधी प्रतिबंधों का उल्लंघन करता है.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> से कम</translation>
-<translation id="759889825892636187"><ph name="HOST_NAME" /> वर्तमान में इस अनुरोध का प्रबंधन कर पाने में असमर्थ है.</translation>
+<translation id="759889825892636187"><ph name="HOST_NAME" /> फ़िलहाल इस अनुरोध का प्रबंधन नहीं कर सकता है.</translation>
<translation id="7600965453749440009">कभी भी <ph name="LANGUAGE" /> का अनुवाद न करें</translation>
<translation id="7610193165460212391"><ph name="VALUE" /> मान सीमा से बाहर है.</translation>
<translation id="7613889955535752492">समय-सीमा समाप्त: <ph name="EXPIRATION_MONTH" />/<ph name="EXPIRATION_YEAR" /></translation>
@@ -918,7 +923,7 @@
<translation id="7663736086183791259">प्रमाणपत्र <ph name="CERTIFICATE_VALIDITY" /></translation>
<translation id="7667346355482952095">वापस लौटा हुआ नीति टोकन खाली है या उसका मिलान वर्तमान टोकन से नहीं होता</translation>
<translation id="7668654391829183341">अज्ञात डिवाइस</translation>
-<translation id="7669271284792375604">इस साइट पर मौजूद हमलावर आपके ब्राउज़िंग अनुभव को हानि पहुंचा सकने वाले प्रोग्राम इंस्टॉल करने के लिए आपको भ्रमित कर सकते हैं (उदाहरण के लिए, आपके मुखपृष्ठ को बदलकर या आपकी विज़िट की जा रहीं साइट पर अतिरिक्त विज्ञापन दिखाकर).</translation>
+<translation id="7669271284792375604">इस साइट पर मौजूद हमलावर धोखे से आपसे ऐसे प्रोग्राम इंस्टॉल करवाने की कोशिश कर सकते हैं, जिनसे आपके ब्राउज़िंग अनुभव को नुकसान पहुंच सकता है (उदाहरण के लिए, आपका होमपेज बदलकर या आप जिन साइटों पर जाते हैं उन पर ज़्यादा विज्ञापन दिखाकर).</translation>
<translation id="7682287625158474539">शिपिंग</translation>
<translation id="7699293099605015246">फ़िलहाल लेख उपलब्ध नहीं हैं</translation>
<translation id="7701040980221191251">कुछ नहीं</translation>
@@ -932,7 +937,7 @@
<translation id="7755287808199759310">आपका अभिभावक इसे आपके लिए अनवरोधित कर सकता है</translation>
<translation id="7758069387465995638">हो सकता है कि फायरवॉल या एंटीवायरस द्वारा कनेक्शन अवरुद्ध हो.</translation>
<translation id="7759163816903619567">डोमेन प्रदर्शित करें:</translation>
-<translation id="7761701407923456692">सर्वर का प्रमाणपत्र URL से मेल नहीं हो रहा है.</translation>
+<translation id="7761701407923456692">सर्वर का प्रमाणपत्र यूआरएल से मेल नहीं खाता.</translation>
<translation id="7763386264682878361">भुगतान मेनिफ़ेस्ट पार्सर</translation>
<translation id="7764225426217299476">पता जोड़ें</translation>
<translation id="777702478322588152">प्रशासक प्रांत</translation>
@@ -947,8 +952,8 @@
<translation id="7813600968533626083">Chrome से फ़ॉर्म सुझाव को निकालें?</translation>
<translation id="7815407501681723534">'<ph name="SEARCH_STRING" />' के लिए <ph name="NUMBER_OF_RESULTS" /> <ph name="SEARCH_RESULTS" /> मिले</translation>
<translation id="7818867226424560206">नीति प्रबंधन</translation>
-<translation id="782886543891417279">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) उसके लिए आपको प्रवेश पृष्‍ठ पर जाने की आवश्‍यकता हो सकती है.</translation>
-<translation id="785549533363645510">हालांकि, आप अदृश्य नहीं हैं. गुप्त मोड में रहने से आपकी ब्राउज़िंग आपके नियोक्ता, आपके इंटरनेट सेवा प्रदाता या आपके द्वारा देखी जाने वाली वेबसाइट से छिपती नहीं है.</translation>
+<translation id="782886543891417279">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) आपको उसके लॉगिन पेज पर जाने की ज़रूरत पड़ सकती है.</translation>
+<translation id="785549533363645510">हालांकि, गुप्त मोड का मतलब यह नहीं है कि आपको कोई भी नहीं देख सकता. गुप्त मोड में आप जो भी ब्राउजिंग करते हैं उसे, आपके नियोक्ता, इंटरनेट सेवा देने वाली कंपनी या आप जिन वेबसाइटों को देखते हैं, वे देख सकते हैं.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="7862185352068345852">साइट छोड़ें?</translation>
<translation id="7878176543348854470">डेबिट और प्रीपेड कार्ड स्वीकार किए जाते हैं.</translation>
@@ -976,7 +981,7 @@
<translation id="8079031581361219619">साइट को फिर लोड करें?</translation>
<translation id="8088680233425245692">लेख देखने में विफल रहा.</translation>
<translation id="8091372947890762290">सर्वर पर सक्रियण लंबित है</translation>
-<translation id="8094917007353911263">आप जिस नेटवर्क का उपयोग कर रहे हैं उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की आवश्‍यकता हो सकती है.</translation>
+<translation id="8094917007353911263">आप जिस नेटवर्क का उपयोग कर रहे हैं उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की ज़रूरत पड़ सकती है.</translation>
<translation id="8103161714697287722">भुगतान विधि</translation>
<translation id="8118489163946903409">भुगतान विधि</translation>
<translation id="8127301229239896662">"<ph name="SOFTWARE_NAME" />" आपके कंप्यूटर या नेटवर्क पर ठीक से इंस्टॉल नहीं हुआ था. अपने आईटी व्यवस्थापक से इस समस्या को ठीक करने के लिए कहें.</translation>
@@ -986,7 +991,7 @@
<translation id="8184538546369750125">वैश्विक डिफ़ॉल्ट का उपयोग करें (अनुमति दें)</translation>
<translation id="8191494405820426728">स्थानीय क्रैश आईडी <ph name="CRASH_LOCAL_ID" /></translation>
<translation id="8194797478851900357">&amp;ले जाना वापस लाएं</translation>
-<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" आईडी वाले एक्‍सटेंशन का अमान्‍य अपडेट URL.</translation>
+<translation id="8201077131113104583">"<ph name="EXTENSION_ID" />" आईडी वाले एक्‍सटेंशन का गलत अपडेट यूआरएल.</translation>
<translation id="8202097416529803614">आदेश सारांश</translation>
<translation id="8205463626947051446">साइट तंग करने वाले विज्ञापन दिखाने के लिए जानी जाती है</translation>
<translation id="8211406090763984747">कनेक्शन सुरक्षित है</translation>
@@ -1006,11 +1011,11 @@
<translation id="8289355894181816810">यदि आप सुनिश्चित नहीं हैं कि इसका क्या मतलब है, तो अपने नेटवर्क व्यवस्थापक से संपर्क करें.</translation>
<translation id="8293206222192510085">बुकमार्क जोड़ें</translation>
<translation id="8294431847097064396">स्रोत</translation>
-<translation id="8298115750975731693">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की आवश्‍यकता हो सकती है.</translation>
+<translation id="8298115750975731693">आप जिस वाई-फ़ाई का उपयोग कर रहे हैं (<ph name="WIFI_NAME" />) उसके लिए आपको <ph name="BEGIN_BOLD" /><ph name="LOGIN_URL" /><ph name="END_BOLD" /> पर जाने की ज़रूरत हो सकती है.</translation>
<translation id="8308427013383895095">नेटवर्क कनेक्शन में कोई समस्या होने के कारण अनुवाद विफल हुआ.</translation>
<translation id="8311129316111205805">सत्र लोड करें</translation>
<translation id="8332188693563227489"><ph name="HOST_NAME" /> का एक्सेस अस्वीकृत किया गया</translation>
-<translation id="834457929814110454">यदि आप अपनी सुरक्षा में होने वाले जोखिमों को समझते हैं, तो खतरनाक प्रोग्राम निकाले जाने से पहले आप <ph name="BEGIN_LINK" />इस साइट पर विज़िट<ph name="END_LINK" /> कर सकते हैं.</translation>
+<translation id="834457929814110454">अगर आप अपनी सुरक्षा संबंधी जोखिमों को समझते हैं तो, खतरनाक प्रोग्राम हटाए जाने से पहले आप <ph name="BEGIN_LINK" />इस साइट पर विज़िट<ph name="END_LINK" /> कर सकते हैं.</translation>
<translation id="8349305172487531364">बुकमार्क बार</translation>
<translation id="8363502534493474904">हवाई जहाज़ मोड बंद करें</translation>
<translation id="8364627913115013041">सेट नहीं है.</translation>
@@ -1030,7 +1035,7 @@
<translation id="8498891568109133222"><ph name="HOST_NAME" /> को लोड होने में बहुत ज़्यादा समय लगा.</translation>
<translation id="8503559462189395349">Chrome पासवर्ड</translation>
<translation id="8503813439785031346">उपयोगकर्ता नाम</translation>
-<translation id="8543181531796978784">आप <ph name="BEGIN_ERROR_LINK" />पहचान संबंधी समस्‍या की रिपोर्ट<ph name="END_ERROR_LINK" /> कर सकते हैं या यदि आप अपनी सुरक्षा से जुड़े जोखिमों को समझते हैं, तो <ph name="BEGIN_LINK" />इस असुरक्षित साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
+<translation id="8543181531796978784">आप <ph name="BEGIN_ERROR_LINK" />पहचान संबंधी समस्‍या की रिपोर्ट<ph name="END_ERROR_LINK" /> कर सकते हैं या अगर आप अपनी सुरक्षा संबंधी जोखिमों को समझते हैं तो, <ph name="BEGIN_LINK" />इस असुरक्षित साइट पर जा<ph name="END_LINK" /> सकते हैं.</translation>
<translation id="8543556556237226809">प्रश्न पूछना चाहते हैं? तो उस व्यक्ति से संपर्क करें जो आपकी प्रोफ़ाइल की निगरानी करता है.</translation>
<translation id="8553075262323480129">अनुवाद विफल हो गया क्योंकि पेज की भाषा निर्धारित नहीं की जा सकी.</translation>
<translation id="8557066899867184262">कार्ड वेरीफ़िकेशन कोड (सीवीसी) आपके कार्ड के पीछे मौजूद होता है.</translation>
@@ -1061,7 +1066,7 @@
<translation id="883848425547221593">अन्य बुकमार्क</translation>
<translation id="884264119367021077">शिपिंग पता</translation>
<translation id="884923133447025588">कोई निरस्तीकरण प्रक्रिया प्राप्त नहीं हुई.</translation>
-<translation id="885730110891505394">Google के साथ साझा करना</translation>
+<translation id="885730110891505394">Google के साथ शेयर करना</translation>
<translation id="8866481888320382733">नीति सेटिंग पार्स करने में गड़बड़ी</translation>
<translation id="8870413625673593573">हाल ही में बंद किए गए</translation>
<translation id="8874824191258364635">मान्य कार्ड संख्या डालें</translation>
@@ -1090,7 +1095,7 @@
<translation id="9035022520814077154">सुरक्षा गड़बड़ी</translation>
<translation id="9038649477754266430">अधिक तेज़ी से पेज लोड करने के लिए किसी पूर्वानुमान सेवा का उपयोग करें</translation>
<translation id="9039213469156557790">इसके अतिरिक्त, इस पेज में ऐसे अन्य संसाधन भी शामिल हैं, जो सुरक्षित नहीं हैं. ट्रांज़िट में होने के दौरान ये संसाधन अन्य लोगों द्वारा देखे जा सकते हैं और पेज का व्यवहार बदलने के लिए किसी हमवलावर द्वारा इनमें बदलाव किए जा सकते हैं.</translation>
-<translation id="9049981332609050619">आपने <ph name="DOMAIN" /> पर पहुंचने का प्रयास किया, लेकिन सर्वर ने एक अमान्‍य प्रमाणपत्र प्रस्तुत किया.</translation>
+<translation id="9049981332609050619">आपने <ph name="DOMAIN" /> पर पहुंचने की कोशिश की लेकिन सर्वर ने एक अमान्‍य प्रमाणपत्र पेश किया.</translation>
<translation id="9050666287014529139">पासफ़्रेज़</translation>
<translation id="9065203028668620118">संपादित करें</translation>
<translation id="9069693763241529744">किसी एक्सटेंशन से अवरोधित है</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;संपादन वापस लाएं</translation>
<translation id="9154194610265714752">अपडेट किया गया</translation>
<translation id="9157595877708044936">सेट अप कर रहा है...</translation>
+<translation id="9168814207360376865">साइट को यह देखने दें कि आपके 'भुगतान के तरीके' सेव किए गए हैं या नहीं</translation>
<translation id="9169664750068251925">इस साइट पर हमेशा अवरोधित करें</translation>
<translation id="9170848237812810038">&amp;पूर्ववत् करें</translation>
<translation id="917450738466192189">सर्वर का प्रमाणपत्र अमान्य है.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">लेख जोड़ने में विफल रहा.</translation>
<translation id="9215416866750762878">एक ऐप्‍लिकेशन Chrome को इस साइट से सुरक्षित तरीके से कनेक्‍ट होने से रोक रहा है</translation>
<translation id="9219103736887031265">चित्र</translation>
-<translation id="933612690413056017">कोई इंटरनेट कनेक्शन नहीं है</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">फ़ॉर्म साफ़ करें</translation>
<translation id="939736085109172342">नया फ़ोल्डर</translation>
diff --git a/chromium/components/strings/components_strings_hr.xtb b/chromium/components/strings/components_strings_hr.xtb
index bdc49844ad6..b767b3c0d34 100644
--- a/chromium/components/strings/components_strings_hr.xtb
+++ b/chromium/components/strings/components_strings_hr.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Odaberite dopuštenje: <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Najnovije oznake</translation>
<translation id="1113869188872983271">&amp;Poništi promjenu rasporeda</translation>
+<translation id="1125573121925420732">Upozorenja mogu biti uobičajena dok web-lokacije ažuriraju sigurnost. To bi se uskoro trebalo poboljšati.</translation>
<translation id="1126551341858583091">Veličina na lokalnoj pohrani iznosi <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Predmemorija pravila ispravna je</translation>
<translation id="1150979032973867961">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; operativni sustav vašeg računala smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Provjerite jeste li povezani s internetom.&lt;/li&gt;
&lt;li&gt;Obratite se vlasniku web-lokacije.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Unijeli ste zaporku na web-lokaciju kojom ne upravlja vaša organizacija. Da biste zaštitili račun, nemojte upotrebljavati tu zaporku za druge aplikacije i web-lokacije.</translation>
<translation id="1263231323834454256">Popis za čitanje</translation>
<translation id="1264126396475825575">Izvješća o rušenju programa generirana <ph name="CRASH_TIME" /> (još nisu prenesena ili zanemarena)</translation>
<translation id="1270502636509132238">Način preuzimanja</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Odaberi</translation>
<translation id="1620510694547887537">Fotoaparat</translation>
<translation id="1623104350909869708">Spriječi da ova stranica stvori dodatne dijaloške okvire</translation>
-<translation id="1629803312968146339">Želite li da Chrome spremi tu karticu?</translation>
<translation id="1639239467298939599">Učitavanje</translation>
<translation id="1640180200866533862">Korisnička pravila</translation>
<translation id="1640244768702815859">Pokušajte <ph name="BEGIN_LINK" />otvoriti početnu stranicu web-lokacije<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Pokušajte pokrenuti Mrežnu dijagnostiku sustava Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Ažurirajte zaporku za sinkronizaciju.</translation>
<translation id="1787142507584202372">Ovdje se prikazuju vaše otvorene kartice</translation>
-<translation id="1789575671122666129">Skočni prozori</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Ime nositelja kartice</translation>
<translation id="1806541873155184440">Dodano <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Ponovo pokrenite računalo</translation>
<translation id="2113977810652731515">Kartica</translation>
<translation id="2114841414352855701">Zanemareno jer je nadjačano pravilom <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Traženje stranica Fizičkog weba u blizini</translation>
<translation id="213826338245044447">Mobilne oznake</translation>
<translation id="214556005048008348">Otkaži plaćanje</translation>
<translation id="2147827593068025794">Sinkronizacija u pozadini</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Pravilo nije pronađeno</translation>
<translation id="2213606439339815911">Dohvaćanje unosa...</translation>
<translation id="2218879909401188352">Napadači koji su trenutačno na web-lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogli bi instalirati opasne aplikacije koje će oštetiti uređaj, dodati skrivene troškove na račun za mobilne usluge ili ukrasti vaše osobne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Nema interneta</translation>
<translation id="2230458221926704099">Riješite problem s povezivanjem pomoću <ph name="BEGIN_LINK" />dijagnostičke aplikacije<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Pošalji sad</translation>
<translation id="225207911366869382">Ta je vrijednost obustavljena za to pravilo.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Ukloni odabrane stavke</translation>
<translation id="277133753123645258">Način dostave</translation>
<translation id="277499241957683684">Zapis uređaja nije prisutan</translation>
+<translation id="2781030394888168909">Izvezi za MacOS</translation>
<translation id="2784949926578158345">Veza je ponovo uspostavljena.</translation>
<translation id="2788784517760473862">Prihvaćene kreditne kartice</translation>
<translation id="2794233252405721443">Web-lokacija blokirana</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome nije uspio potvrditi vašu karticu. Pokušajte ponovo kasnije.</translation>
<translation id="3064966200440839136">Napuštate anonimni način rada da biste platili putem vanjske aplikacije. Želite li nastaviti?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nijedna}=1{1 zaporka}one{# zaporka}few{# zaporke}other{# zaporki}}</translation>
-<translation id="3093245981617870298">Izvan mreže ste.</translation>
<translation id="3096100844101284527">Dodajte adresu preuzimanja</translation>
<translation id="3105172416063519923">ID uređaja:</translation>
<translation id="3109728660330352905">Nemate ovlaštenje za prikaz te stranice.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Host <ph name="HOST_NAME" /> trenutačno nije dostupan.</translation>
<translation id="3427092606871434483">Dopusti (zadano)</translation>
<translation id="3427342743765426898">&amp;Ponovi uređivanje</translation>
+<translation id="342781501876943858">Chromium preporučuje poništavanje zaporke ako ste je upotrebljavali za druge web-lokacije.</translation>
<translation id="3431636764301398940">Spremi tu karticu na ovaj uređaj</translation>
<translation id="3447661539832366887">Vlasnik tog uređaja isključio je igru s dinosaurima.</translation>
<translation id="3447884698081792621">Prikaz certifikata (izdavač: <ph name="ISSUER" />)</translation>
@@ -397,7 +398,6 @@
<translation id="3678529606614285348">Otvorite stranicu u novom anonimnom prozoru (Ctrl – Shift – N)</translation>
<translation id="3679803492151881375">Izvješće o rušenju programa generirano u <ph name="CRASH_TIME" />, preneseno u <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Podaci o certifikatu</translation>
-<translation id="3690164694835360974">Prijava nije sigurna</translation>
<translation id="3704162925118123524">Mreža koju upotrebljavate može zahtijevati posjet stranici za prijavu.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Učitavanje...</translation>
@@ -457,7 +457,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Upotrijebi globalnu zadanu postavku (Otkrij)</translation>
<translation id="4165986682804962316">Postavke web-lokacije</translation>
-<translation id="4169947484918424451">Želite li da Chromium spremi tu karticu?</translation>
<translation id="4171400957073367226">Potpis za potvrdu nije ispravan.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Još <ph name="ITEM_COUNT" /> stavka}one{Još <ph name="ITEM_COUNT" /> stavka}few{Još <ph name="ITEM_COUNT" /> stavke}other{Još <ph name="ITEM_COUNT" /> stavki}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -494,6 +493,7 @@
<translation id="4275830172053184480">Ponovo pokrenite svoj uređaj</translation>
<translation id="4277028893293644418">Poništi zaporku</translation>
<translation id="4280429058323657511">, istek <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Prebaci</translation>
<translation id="4312866146174492540">Blokiraj (zadano)</translation>
<translation id="4325863107915753736">Članak nije pronađen</translation>
<translation id="4326324639298822553">Provjerite datum isteka, pa pokušajte ponovo</translation>
@@ -501,6 +501,7 @@
<translation id="4340982228985273705">Za ovo računalo nije otkriveno da njime upravlja tvrtka, pa pravilo može samo automatski instalirati proširenja hostirana u Chrome web-trgovini. URL za ažuriranje Chrome web-trgovine je "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Prihvaćene kreditne kartice</translation>
<translation id="4356973930735388585">Napadači na ovoj web-lokaciji mogu pokušati instalirati opasne programe na vaše računalo radi krađe ili brisanja vaših podataka (na primjer fotografija, zaporki, poruka i brojeva kreditnih kartica).</translation>
+<translation id="4358461427845829800">Upravljajte načinima plaćanja...</translation>
<translation id="4372948949327679948">Očekivana vrijednost vrste <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Pokušali ste doseći domenu <ph name="DOMAIN" />, ali certifikat koji je poslužitelj predstavio povučen je od strane izdavača. Prema tome nikako ne biste trebali vjerovati sigurnosnim certifikatima koje predstavlja poslužitelj. Možda komunicirate s napadačem.</translation>
<translation id="4406896451731180161">rezultati pretraživanja</translation>
@@ -508,6 +509,7 @@
<translation id="4415426530740016218">Adresa preuzimanja</translation>
<translation id="4424024547088906515">Poslužitelj nije mogao dokazati da je <ph name="DOMAIN" />; Chrome smatra da njegov sigurnosni certifikat nije pouzdan. To može biti uzrokovano pogrešnom konfiguracijom ili napadom na vašu vezu.</translation>
<translation id="4432688616882109544">Host <ph name="HOST_NAME" /> nije prihvatio vaš certifikat za prijavu ili certifikat nije poslan.</translation>
+<translation id="4434045419905280838">Skočni prozori i preusmjeravanja</translation>
<translation id="443673843213245140">Upotreba proxy poslužitelja onemogućena je, ali određena je izričita konfiguracija proxy poslužitelja.</translation>
<translation id="445100540951337728">Prihvaćene debitne kartice</translation>
<translation id="4506176782989081258">Pogreška pri provjeri valjanosti: <ph name="VALIDATION_ERROR" />.</translation>
@@ -542,13 +544,13 @@
<translation id="4759118997339041434">Automatsko popunjavanje podataka o plaćanju onemogućeno je</translation>
<translation id="4764776831041365478">Web-stranica na adresi <ph name="URL" /> možda privremeno nije dostupna ili je trajno preseljena na novu web-adresu.</translation>
<translation id="4771973620359291008">Došlo je do nepoznate pogreške.</translation>
+<translation id="4785689107224900852">Prijeđite na ovu karticu</translation>
<translation id="4792143361752574037">Pojavio se problem prilikom pristupa datotekama sesije. Spremanje na disk trenutačno je onemogućeno. Ponovo učitajte stranicu i pokušajte opet.</translation>
<translation id="4800132727771399293">Provjerite datum isteka i CVC pa pokušajte ponovo</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Trenutačno ne možete posjetiti <ph name="SITE" /> jer je web-lokacija poslala kodirane vjerodajnice koje Google Chrome ne može obraditi. Mrežne pogreške i napadi uglavnom su privremeni, tako da će ta stranica vjerojatno kasnije funkcionirati.</translation>
<translation id="4813512666221746211">Pogreška mreže</translation>
<translation id="4816492930507672669">Prilagodi stranici</translation>
-<translation id="483020001682031208">Nema nijedne stranice Fizičkog weba za prikazivanje</translation>
<translation id="4850886885716139402">Prikaz</translation>
<translation id="4854362297993841467">Taj način dostave nije dostupan. Pokušajte s nekim drugim načinom.</translation>
<translation id="4858792381671956233">Pitao si roditelje smiješ li otvoriti tu web-lokaciju</translation>
@@ -588,6 +590,7 @@
<translation id="5115563688576182185">(64-bitni)</translation>
<translation id="5121084798328133320">Nakon što ih potvrdite, podaci o kartici s računa usluge Google podijelit će se s ovom web-lokacijom.</translation>
<translation id="5128122789703661928">Brisanje sesije nije uspjelo jer naziv sesije nije važeći.</translation>
+<translation id="5135404736266831032">Upravljajte adresama...</translation>
<translation id="5141240743006678641">Šifriranje sinkroniziranih zaporki s vjerodajnicama za Google</translation>
<translation id="5145883236150621069">Odgovor na pravilo sadrži kôd pogreške</translation>
<translation id="5159010409087891077">Otvorite stranicu u novom anonimnom prozoru (⇧⌘N)</translation>
@@ -599,7 +602,6 @@
<translation id="5201306358585911203">Na ugrađenoj stranici na ovoj stranici navodi se sljedeće</translation>
<translation id="5205222826937269299">Ime je obavezno</translation>
<translation id="5222812217790122047">E-pošta (obavezno)</translation>
-<translation id="522700295135997067">Ova web-lokacija možda vam je upravo ukrala zaporku</translation>
<translation id="5230733896359313003">Adresa za dostavu</translation>
<translation id="5250209940322997802">"Povezivanje s mrežom"</translation>
<translation id="5251803541071282808">Oblak</translation>
@@ -643,7 +645,6 @@
<translation id="5492298309214877701">Web-lokacija na intranetu tvrtke, organizacije ili škole ima isti URL kao i vanjska web-lokacija.
<ph name="LINE_BREAK" />
Pokušajte se obratiti administratoru sustava.</translation>
-<translation id="5499929369096410817">Unesite sigurnosni kôd za karticu <ph name="CREDIT_CARD" />. Taj se kôd neće spremiti.</translation>
<translation id="5509780412636533143">Upravljane oznake</translation>
<translation id="5510766032865166053">Datoteka je možda premještena ili izbrisana.</translation>
<translation id="5523118979700054094">Naziv pravila</translation>
@@ -674,9 +675,11 @@
<translation id="5685654322157854305">Dodajte adresu za dostavu</translation>
<translation id="5689199277474810259">Izvezi u JSON</translation>
<translation id="5689516760719285838">Lokacija</translation>
+<translation id="570530837424789914">Upravljajte...</translation>
<translation id="5710435578057952990">Identitet ove web lokacije nije ovjeren.</translation>
<translation id="5719499550583120431">Prihvaćaju se pretplatne kartice.</translation>
<translation id="5720705177508910913">Trenutačni korisnik:</translation>
+<translation id="5730040223043577876">Chrome preporučuje poništavanje zaporke ako ste je upotrebljavali za druge web-lokacije.</translation>
<translation id="5732392974455271431">Tvoji je roditelji mogu deblokirati</translation>
<translation id="5763042198335101085">Unesite važeću e-adresu</translation>
<translation id="5765072501007116331">Odaberite adresu za prikaz načina dostave i zahtjeva za dostavu.</translation>
@@ -700,9 +703,7 @@
<translation id="5959728338436674663">Automatski šalji Googleu neke <ph name="BEGIN_WHITEPAPER_LINK" />podatke o sustavu i sadržaj stranice<ph name="END_WHITEPAPER_LINK" /> radi otkrivanja opasnih aplikacija i web-lokacija. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Uredite podatke za kontakt</translation>
<translation id="5967867314010545767">Ukloni iz povijesti</translation>
-<translation id="5972020793760134803">Prijeđi na karticu</translation>
<translation id="5975083100439434680">Smanji</translation>
-<translation id="597552863672748783">Potvrdite sigurnosni kôd</translation>
<translation id="598637245381783098">Aplikacija za plaćanje ne može se otvoriti</translation>
<translation id="5989320800837274978">Nisu određeni fiksni proxy poslužitelji ni URL .pac skripte.</translation>
<translation id="5990559369517809815">Zahtjevi poslužitelju blokirani su proširenjem.</translation>
@@ -718,6 +719,7 @@
<translation id="6047927260846328439">Ovaj vas sadržaj može na prijevaru pokušati navesti da instalirate softver ili odate svoje osobne podatke. <ph name="BEGIN_LINK" />Ipak prikaži<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Trenutačno ne možete otvoriti <ph name="SITE" /> jer web-lokacija upotrebljava prikvačivanje certifikata. Mrežne pogreške i napadi obično su privremeni, tako da će stranica kasnije vjerojatno funkcionirati.</translation>
<translation id="6059925163896151826">USB uređaji</translation>
+<translation id="6071091556643036997">Vrsta pravila nije važeća.</translation>
<translation id="6080696365213338172">Pristupili ste sadržaju pomoću certifikata koji je izdao administrator. Administrator može presresti podatke koje dostavljate domeni <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">Na vašem Google računu možda postoje drugi oblici povijesti pregledavanja na stranici <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nijedna}=1{1 zaporka (sinkronizirana)}one{# zaporka (sinkronizirana)}few{# zaporke (sinkronizirane)}other{# zaporki (sinkroniziranih)}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">Dodajte još podataka</translation>
<translation id="6447842834002726250">Kolačići</translation>
<translation id="6451458296329894277">Potvrdi ponovno slanje obrasca</translation>
+<translation id="6465306955648956876">Upravljajte zaporkama...</translation>
<translation id="647261751007945333">Pravila uređaja</translation>
<translation id="6477321094435799029">Chrome je otkrio neuobičajeni kôd na toj stranici i blokirao ju je radi zaštite vaših osobnih podataka (primjerice zaporki, telefonskih brojeva i kreditnih kartica).</translation>
<translation id="6489534406876378309">Pokreni prijenos rušenja</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Pretraživanje</translation>
<translation id="6630809736994426279">Napadači koji su trenutačno na web-lokaciji <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogu pokušati instalirati opasne programe na vaš Mac radi krađe ili brisanja vaših podataka (na primjer fotografija, zaporki, poruka i brojeva kreditnih kartica). <ph name="BEGIN_LEARN_MORE_LINK" />Saznajte više<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Ovo je pravilo zastarjelo.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nijedna}=1{S jedne web-lokacije (nećete se odjaviti s Google računa)}one{S # web-lokacije (nećete se odjaviti s Google računa)}few{S # web-lokacije (nećete se odjaviti s Google računa)}other{S # web-lokacija (nećete se odjaviti s Google računa)}}</translation>
<translation id="6657585470893396449">Zaporka</translation>
<translation id="6671697161687535275">Želite li ukloniti prijedlog iz Chromiuma?</translation>
<translation id="6685834062052613830">Odjavite se i dovršite postavljanje</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">Korisnik:</translation>
<translation id="6945221475159498467">Odaberi</translation>
<translation id="6948701128805548767">Odaberite adresu za prikaz načina preuzimanja i zahtjeva za preuzimanje</translation>
+<translation id="6949872517221025916">Poništite zaporku</translation>
<translation id="6957887021205513506">Certifikat poslužitelja izgleda kao falsifikat.</translation>
<translation id="6965382102122355670">U redu</translation>
<translation id="6965978654500191972">Uređaj</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">Način isporuke</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Plaćanje nije sigurno</translation>
+<translation id="717330890047184534">ID za GAIA-u:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> i još <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Osvježi</translation>
<translation id="7182878459783632708">Nije postavljeno nijedno pravilo</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">Upotrijebi globalnu zadanu vrijednost (blokiraj)</translation>
<translation id="7460163899615895653">Ovdje se prikazuju vaše nedavne kartice s drugih uređaja</translation>
<translation id="7469372306589899959">Potvrđivanje kartice</translation>
+<translation id="7473891865547856676">Ne, hvala</translation>
<translation id="7481312909269577407">Naprijed</translation>
<translation id="7485870689360869515">Nema pronađenih podataka.</translation>
<translation id="7508255263130623398">Vraćeni ID uređaja pravila prazan je ili ne odgovara trenutačnom ID-u uređaja</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Želite li s Chromea ukloniti kreditnu karticu?</translation>
<translation id="7575800019233204241">"Vaša veza nije privatna" ili "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" ili "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" ili "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" ili "Pogreška SSL certifikata"</translation>
<translation id="7578104083680115302">Plaćajte brzo na web-lokacijama i u aplikacijama na više uređaja karticama koje ste spremili na Google.</translation>
-<translation id="7588950540487816470">Fizički web</translation>
<translation id="7592362899630581445">Certifikat poslužitelja krši ograničenja naziva.</translation>
<translation id="7598391785903975535">Manje od <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Host <ph name="HOST_NAME" /> trenutačno ne može obraditi zahtjev.</translation>
@@ -1107,6 +1112,7 @@ i netočne vjerodajnice. To može značiti da se neki napadač pokušava predsta
<translation id="9148507642005240123">&amp;Poništi uređivanje</translation>
<translation id="9154194610265714752">Ažurirano</translation>
<translation id="9157595877708044936">Postavljanje...</translation>
+<translation id="9168814207360376865">Dopusti web-lokacijama da provjere imate li spremljene načine plaćanja</translation>
<translation id="9169664750068251925">Uvijek blokiraj na ovoj web-lokaciji</translation>
<translation id="9170848237812810038">&amp;Poništi</translation>
<translation id="917450738466192189">Certifikat poslužitelja nije valjan.</translation>
@@ -1115,7 +1121,6 @@ i netočne vjerodajnice. To može značiti da se neki napadač pokušava predsta
<translation id="9207861905230894330">Dodavanje članka nije uspjelo.</translation>
<translation id="9215416866750762878">Aplikacija sprječava sigurno povezivanje Chromea s ovom web-lokacijom</translation>
<translation id="9219103736887031265">Slike</translation>
-<translation id="933612690413056017">Nema internetske veze</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">IZBRIŠI OBRAZAC</translation>
<translation id="939736085109172342">Nova mapa</translation>
diff --git a/chromium/components/strings/components_strings_hu.xtb b/chromium/components/strings/components_strings_hu.xtb
index ca87a0cd61e..fc1ed875b97 100644
--- a/chromium/components/strings/components_strings_hu.xtb
+++ b/chromium/components/strings/components_strings_hu.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Engedély kiválasztása a következőhöz: <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Legutóbbi könyvjelzők</translation>
<translation id="1113869188872983271">&amp;Átrendezés visszavonása</translation>
+<translation id="1125573121925420732">Gyakran előfordulhatnak figyelmeztetések, amikor a webhelyek frissítik biztonsági megoldásaikat. Ez a helyzet hamarosan javulhat.</translation>
<translation id="1126551341858583091">A helyi tárolóban lévő fájl mérete <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Irányelv-gyorsítótár OK</translation>
<translation id="1150979032973867961">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa az Ön számítógépének operációs rendszere szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Győződjön meg arról, hogy internetkapcsolata megfelelően működik.&lt;/li&gt;
&lt;li&gt;Vegye fel a kapcsolatot a webhely tulajdonosával.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Olyan webhelyen adta meg a jelszavát, amelyet nem az Ön szervezete kezel. Fiókja védelme érdekében ne használja fel újra a jelszót más alkalmazásokban és webhelyeken.</translation>
<translation id="1263231323834454256">Olvasási lista</translation>
<translation id="1264126396475825575">Hibajelentés készült: <ph name="CRASH_TIME" /> (még nincs feltöltve vagy mellőzték)</translation>
<translation id="1270502636509132238">Átvételi mód</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Kiválaszt</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Akadályozza meg, hogy ez az oldal további párbeszédablakokat hozzon létre.</translation>
-<translation id="1629803312968146339">Szeretné, hogy a Chrome mentse ezt a kártyát?</translation>
<translation id="1639239467298939599">Betöltés</translation>
<translation id="1640180200866533862">Felhasználói házirendek</translation>
<translation id="1640244768702815859">Próbálja meg <ph name="BEGIN_LINK" />megnyitni a webhely főoldalát<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Próbálkozzon a Windows Hálózati diagnosztika futtatásával<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Kérjük, frissítse szinkronizálási összetett jelszavát.</translation>
<translation id="1787142507584202372">A megnyitott lapok helye</translation>
-<translation id="1789575671122666129">Előugró ablakok</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kártyatulajdonos neve</translation>
<translation id="1806541873155184440">Hozzáadva: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Indítsa újra a számítógépet</translation>
<translation id="2113977810652731515">Kártya</translation>
<translation id="2114841414352855701">A rendszer figyelmen kívül hagyja, mivel a(z) <ph name="POLICY_NAME" /> felülírta.</translation>
-<translation id="2138201775715568214">A Fizikai web közeli oldalainak keresése</translation>
<translation id="213826338245044447">Mobil könyvjelzők</translation>
<translation id="214556005048008348">Fizetés visszavonása</translation>
<translation id="2147827593068025794">Szinkronizálás a háttérben</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Nem találhatók irányelvek</translation>
<translation id="2213606439339815911">Bejegyzések lekérése...</translation>
<translation id="2218879909401188352">A(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhelyen lévő támadók veszélyes alkalmazásokat telepíthetnek, amelyek károsíthatják eszközét, rejtett költségeket okozhatnak a mobiltelefon-számlán, vagy ellophatják személyes adatait. <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="2224337661447660594">Nincs internet</translation>
<translation id="2230458221926704099">Javítsa meg kapcsolatát a <ph name="BEGIN_LINK" />diagnosztikai alkalmazás<ph name="END_LINK" /> segítségével</translation>
<translation id="2239100178324503013">Küldés most</translation>
<translation id="225207911366869382">Ez az érték elavult ennél a házirendnél.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">A kijelölt elemek eltávolítása</translation>
<translation id="277133753123645258">Szállítási mód</translation>
<translation id="277499241957683684">Hiányzó eszközrekord</translation>
+<translation id="2781030394888168909">Exportálás MacOS-formátumban</translation>
<translation id="2784949926578158345">A kapcsolat alaphelyzetbe állt.</translation>
<translation id="2788784517760473862">Elfogadott hitelkártyák</translation>
<translation id="2794233252405721443">A webhely le van tiltva</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">A Chrome ez alkalommal nem tudta ellenőrizni az Ön kártyáját. Próbálja újra később.</translation>
<translation id="3064966200440839136">Inkognitómód elhagyása külső alkalmazással történő fizetéshez. Folytatja?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nincs}=1{1 jelszó}other{# jelszó}}</translation>
-<translation id="3093245981617870298">Ön jelenleg offline.</translation>
<translation id="3096100844101284527">Átvételi cím hozzáadása</translation>
<translation id="3105172416063519923">Tartalomazonosító:</translation>
<translation id="3109728660330352905">Nincs jogosultsága az oldal megjelenítésére.</translation>
@@ -360,6 +360,7 @@
<translation id="3422472998109090673">A(z) <ph name="HOST_NAME" /> jelenleg nem érhető el.</translation>
<translation id="3427092606871434483">Engedélyezés (alapértelmezett)</translation>
<translation id="3427342743765426898">&amp;Szerkesztés újra</translation>
+<translation id="342781501876943858">A Chromium azt javasolja, hogy adjon meg új jelszót a régi helyett, ha azt más webhelyeken is használta.</translation>
<translation id="3431636764301398940">Kártya mentése az eszközre</translation>
<translation id="3447661539832366887">Az eszköz tulajdonosa kikapcsolta a dinoszauruszos játékot.</translation>
<translation id="3447884698081792621">Tanúsítvány megjelenítése (kibocsátó: <ph name="ISSUER" />)</translation>
@@ -396,7 +397,6 @@
<translation id="3678529606614285348">Oldal megnyitása új inkognitóablakban (Ctrl+Shift+N)</translation>
<translation id="3679803492151881375">A hibajelentés elkészítésének ideje: <ph name="CRASH_TIME" />; a feltöltés ideje: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Tanúsítvány adatai</translation>
-<translation id="3690164694835360974">A bejelentkezés nem biztonságos</translation>
<translation id="3704162925118123524">Előfordulhat, hogy az Ön által használt hálózat megköveteli a bejelentkezési oldalán történő bejelentkezést.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Betöltés...</translation>
@@ -456,7 +456,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Globális alapértelmezés használata (Észlelés)</translation>
<translation id="4165986682804962316">Webhelybeállítások</translation>
-<translation id="4169947484918424451">Szeretné, hogy a Chromium mentse ezt a kártyát?</translation>
<translation id="4171400957073367226">Hibás igazoló aláírás.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{ még <ph name="ITEM_COUNT" /> elem}other{ még <ph name="ITEM_COUNT" /> elem}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
@@ -493,6 +492,7 @@
<translation id="4275830172053184480">Indítsa újra az eszközt</translation>
<translation id="4277028893293644418">Jelszó visszaállítása</translation>
<translation id="4280429058323657511">, lejár: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Váltás</translation>
<translation id="4312866146174492540">Letiltás (alapértelmezett)</translation>
<translation id="4325863107915753736">Nem sikerült megtalálni a cikket</translation>
<translation id="4326324639298822553">Ellenőrizze a lejárati dátumot, majd próbálja újra</translation>
@@ -500,6 +500,7 @@
<translation id="4340982228985273705">A rendszer nem vállalat által kezeltként érzékeli ezt a számítógépet, ezért a házirend csak a Chrome Internetes áruházban tárolt bővítményeket tudja automatikusan telepíteni. A Chrome Internetes áruház frissítési URL-je: <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Elfogadott hitelkártyák</translation>
<translation id="4356973930735388585">Előfordulhat, hogy a webhely támadói olyan veszélyes programokat próbálnak telepíteni számítógépére, amelyek ellopják vagy törlik adatait (például fotóit, jelszavait, üzeneteit vagy hitelkártyaadatait).</translation>
+<translation id="4358461427845829800">Fizetési módok kezelése…</translation>
<translation id="4372948949327679948">Várt <ph name="VALUE_TYPE" /> érték.</translation>
<translation id="4377125064752653719">A(z) <ph name="DOMAIN" /> webhelyet próbálta megnyitni, de a kiállító visszavonta a szerver által bemutatott tanúsítványt. Ez azt jelenti, hogy a szerver biztonsági igazolásaiban egyáltalán nem lehet megbízni. Lehet, hogy egy támadóval áll kapcsolatban.</translation>
<translation id="4406896451731180161">keresési találat</translation>
@@ -507,6 +508,7 @@
<translation id="4415426530740016218">Átvételi cím</translation>
<translation id="4424024547088906515">A szerver nem tudta bizonyítani, hogy valóban a(z) <ph name="DOMAIN" /> domainbe tartozik; biztonsági tanúsítványa a Chrome szerint nem megbízható. Ennek oka lehet konfigurációs hiba, vagy hogy egy támadó eltérítette az Ön kapcsolódását.</translation>
<translation id="4432688616882109544">A(z) <ph name="HOST_NAME" /> nem fogadta el az Ön bejelentkezési tanúsítványát, vagy nem talált ilyet.</translation>
+<translation id="4434045419905280838">Előugró ablakok és átirányítások</translation>
<translation id="443673843213245140">A proxy használata le van tiltva, de kifejezett proxykonfiguráció van megadva.</translation>
<translation id="445100540951337728">Elfogadott bankkártyák</translation>
<translation id="4506176782989081258">Érvényesítési hiba: <ph name="VALIDATION_ERROR" /></translation>
@@ -541,13 +543,13 @@
<translation id="4759118997339041434">A fizetési adatok automatikus kitöltése ki van kapcsolva</translation>
<translation id="4764776831041365478">A <ph name="URL" /> weboldal lehet, hogy ideiglenesen nem érhető el, vagy véglegesen új címre költözött.</translation>
<translation id="4771973620359291008">Ismeretlen hiba történt.</translation>
+<translation id="4785689107224900852">Váltás erre a lapra</translation>
<translation id="4792143361752574037">Hiba történt a munkamenetfájlok elérésekor. A lemezre történő mentés jelenleg nem lehetséges. Töltse be újra az oldalt, és próbálja meg ismét.</translation>
<translation id="4800132727771399293">Ellenőrizze a lejárati dátumot és a CVC-t, majd próbálja újra</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel az olyan titkosított hitelesítési adatokat küldött, amelyeket a Google Chrome nem tud feldolgozni. A hálózati hibák és támadások rendszerint átmenetiek, ezért az említett oldal később valószínűleg már működni fog.</translation>
<translation id="4813512666221746211">Hálózati hiba</translation>
<translation id="4816492930507672669">Igazítás az oldalmérethez</translation>
-<translation id="483020001682031208">Nem jeleníthetők meg oldalak a Fizikai webről</translation>
<translation id="4850886885716139402">Nézet</translation>
<translation id="4854362297993841467">Ez a kézbesítési mód nem áll rendelkezésre. Próbálkozzon másik móddal.</translation>
<translation id="4858792381671956233">Megkérdezted a szüleidet, hogy meg szabad-e látogatnod ezt a webhelyet</translation>
@@ -587,6 +589,7 @@
<translation id="5115563688576182185">(64 bites)</translation>
<translation id="5121084798328133320">A megerősítést követően a böngésző megosztja az Ön Google Payments-fiókjából származó kártyaadatokat ezzel a webhellyel.</translation>
<translation id="5128122789703661928">Ez a munkamenetnév nem érvényes, ezért nem törölhető.</translation>
+<translation id="5135404736266831032">Címek kezelése…</translation>
<translation id="5141240743006678641">A szinkronizált jelszavak titkosítása a Google hitelesítési adataival</translation>
<translation id="5145883236150621069">Az irányelv válasza hibakódot tartalmaz</translation>
<translation id="5159010409087891077">Oldal megnyitása új inkognitóablakban (⇧⌘N)</translation>
@@ -598,7 +601,6 @@
<translation id="5201306358585911203">Az oldal egyik beágyazott oldalának közlendője</translation>
<translation id="5205222826937269299">A név megadása kötelező</translation>
<translation id="5222812217790122047">Az e-mail-cím megadása kötelező</translation>
-<translation id="522700295135997067">Előfordulhat, hogy a webhely éppen most lopta el a jelszavát</translation>
<translation id="5230733896359313003">Szállítási cím</translation>
<translation id="5250209940322997802">„Csatlakozás a hálózathoz”</translation>
<translation id="5251803541071282808">Felhő</translation>
@@ -642,7 +644,6 @@
<translation id="5492298309214877701">Ennek a vállalati, szervezeti vagy iskolai intraneten található webhelynek az URL-címe megegyezik egy külső webhely URL-címével.
<ph name="LINE_BREAK" />
Javasoljuk, hogy forduljon a rendszergazdához.</translation>
-<translation id="5499929369096410817">Adja meg a következő kártya biztonsági kódját: <ph name="CREDIT_CARD" />. A kódot nem menti a rendszer.</translation>
<translation id="5509780412636533143">Kezelt könyvjelzők</translation>
<translation id="5510766032865166053">Előfordulhat, hogy át lett helyezve, vagy törölve lett.</translation>
<translation id="5523118979700054094">Az irányelv neve</translation>
@@ -673,9 +674,11 @@
<translation id="5685654322157854305">Szállítási cím hozzáadása</translation>
<translation id="5689199277474810259">Exportálás JSON formátumba</translation>
<translation id="5689516760719285838">Tartózkodási hely</translation>
+<translation id="570530837424789914">Kezelés…</translation>
<translation id="5710435578057952990">A webhely valódiságát nem ellenőriztük.</translation>
<translation id="5719499550583120431">Elfogadott feltöltőkártyák.</translation>
<translation id="5720705177508910913">Jelenlegi felhasználó</translation>
+<translation id="5730040223043577876">A Chrome azt javasolja, hogy adjon meg új jelszót a régi helyett, ha azt más webhelyeken is használta.</translation>
<translation id="5732392974455271431">A letiltást a szüleid oldhatják fel</translation>
<translation id="5763042198335101085">Érvényes e-mail-címet adjon meg</translation>
<translation id="5765072501007116331">A kézbesítési módok és követelmények megtekintéséhez válassza ki a címet</translation>
@@ -699,9 +702,7 @@
<translation id="5959728338436674663">Bizonyos <ph name="BEGIN_WHITEPAPER_LINK" />rendszer-információk és oldaltartalmak<ph name="END_WHITEPAPER_LINK" /> automatikus küldése a Google-nak a veszélyes alkalmazások és webhelyek felderítése érdekében. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Kapcsolattartási adatok szerkesztése</translation>
<translation id="5967867314010545767">Eltávolítás az előzmények közül</translation>
-<translation id="5972020793760134803">Váltás lapra</translation>
<translation id="5975083100439434680">Kicsinyítés</translation>
-<translation id="597552863672748783">Biztonsági kód megerősítése</translation>
<translation id="598637245381783098">Nem sikerült megnyitni a fizetőalkalmazást</translation>
<translation id="5989320800837274978">Sem fix proxyszerver, sem pedig .pac típusú szkript URL-címe nincs megadva.</translation>
<translation id="5990559369517809815">A szerver felé irányuló kéréseket egy bővítmény blokkolja.</translation>
@@ -717,6 +718,7 @@
<translation id="6047927260846328439">Lehet, hogy ez a tartalom megpróbálja rávenni Önt szoftver telepítésére vagy személyes adatok kiadására. <ph name="BEGIN_LINK" />Megjelenítés mindenképpen<ph name="END_LINK" />.</translation>
<translation id="6051221802930200923">Pillanatnyilag nem tudja felkeresni a(z) <ph name="SITE" /> webhelyet, mivel a webhely tanúsítványrögzítést használ. A hálózati hibák és támadások rendszerint átmenetiek, ezért az említett oldal működése később valószínűleg helyreáll.</translation>
<translation id="6059925163896151826">USB-eszközök</translation>
+<translation id="6071091556643036997">A házirend típusa érvénytelen.</translation>
<translation id="6080696365213338172">A tartalmat egy rendszergazda által biztosított tanúsítványon keresztül érte el. A(z) <ph name="DOMAIN" /> számára megadott adatok a rendszergazda számára is elérhetők.</translation>
<translation id="610911394827799129">Előfordulhat, hogy a böngészési előzmények más formái még megtalálhatók Google-fiókjában a <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> webhelyen</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nincs}=1{1 jelszó (szinkronizálva)}other{# jelszó (szinkronizálva)}}</translation>
@@ -764,6 +766,7 @@
<translation id="6446608382365791566">További adatok hozzáadása</translation>
<translation id="6447842834002726250">Cookie-k</translation>
<translation id="6451458296329894277">Képernyő újraküldésének megerősítése</translation>
+<translation id="6465306955648956876">Jelszavak kezelése…</translation>
<translation id="647261751007945333">Eszközházirendek</translation>
<translation id="6477321094435799029">A Chrome szokatlan kódot észlelt az oldalon, ezért letiltotta az Ön személyes adatainak (például jelszavak, telefonszámok és hitelkártyaszámok) védelme érdekében.</translation>
<translation id="6489534406876378309">Feltöltési összeomlások indítása</translation>
@@ -783,6 +786,7 @@
<translation id="6628463337424475685">Keresés: <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Előfordulhat, hogy a(z) <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> webhely támadói olyan veszélyes programokat kísérelnek meg telepíteni az Ön Mac típusú számítógépére, amelyek ellopják vagy törlik adatait (például fotóit, jelszavait, üzeneteit és hitelkártyaadatait). <ph name="BEGIN_LEARN_MORE_LINK" />További információ<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6644283850729428850">Ez a házirend már elavult.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nincs}=1{1 webhelyről (a böngésző nem jelentkezteti ki Google-fiókjából)}other{# webhelyről (a böngésző nem jelentkezteti ki Google-fiókjából)}}</translation>
<translation id="6657585470893396449">Jelszó</translation>
<translation id="6671697161687535275">Eltávolítja az űrlapjavaslatot a Chromiumból?</translation>
<translation id="6685834062052613830">Kijelentkezés és a beállítás befejezése</translation>
@@ -809,6 +813,7 @@
<translation id="6915804003454593391">Felhasználó:</translation>
<translation id="6945221475159498467">Kiválasztás</translation>
<translation id="6948701128805548767">Az átvételi módok és követelmények megtekintéséhez válassza ki a címet</translation>
+<translation id="6949872517221025916">Jelszó visszaállítása</translation>
<translation id="6957887021205513506">A szerver tanúsítványa hamisítványnak tűnik.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Készülék</translation>
@@ -830,7 +835,7 @@
<translation id="7138472120740807366">Kézbesítési mód</translation>
<translation id="7139724024395191329">Emírség</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">A fizetés nem biztonságos</translation>
+<translation id="717330890047184534">Gaia-azonosító:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> és további <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Frissítés</translation>
<translation id="7182878459783632708">Nincsenek beállított házirendek</translation>
@@ -879,6 +884,7 @@
<translation id="7455133967321480974">Globális alapértelmezés használata (Tiltás)</translation>
<translation id="7460163899615895653">A többi eszközön legutoljára megtekintett lapok láthatók itt</translation>
<translation id="7469372306589899959">Kártya igazolása…</translation>
+<translation id="7473891865547856676">Nem, köszönöm</translation>
<translation id="7481312909269577407">Előre</translation>
<translation id="7485870689360869515">Nem található adat.</translation>
<translation id="7508255263130623398">A visszakapott házirend eszközazonosítója üres, vagy nem felel meg a jelenlegi eszközazonosítónak</translation>
@@ -901,7 +907,6 @@
<translation id="7569952961197462199">Eltávolítja a hitelkártyát a Chrome-ból?</translation>
<translation id="7575800019233204241">„Az Ön kapcsolata nem privát”, „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;”, „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;”, „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;” vagy „SSL-tanúsítványhiba”</translation>
<translation id="7578104083680115302">A Google rendszerében mentett kártyákkal gyorsan fizethet webhelyeken és alkalmazásokban bármelyik eszközén.</translation>
-<translation id="7588950540487816470">Fizikai web</translation>
<translation id="7592362899630581445">A szervertanúsítvány sérti a névre vonatkozó megkötéseket.</translation>
<translation id="7598391785903975535">Kevesebb, mint <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">A(z) <ph name="HOST_NAME" /> jelenleg nem tudja kezelni ezt a kérést.</translation>
@@ -1105,6 +1110,7 @@
<translation id="9148507642005240123">&amp;Szerkesztés visszavonása</translation>
<translation id="9154194610265714752">Frissítve</translation>
<translation id="9157595877708044936">Előkészítés...</translation>
+<translation id="9168814207360376865">Engedélyezés a webhelyek számára, hogy ellenőrizzék, van-e elmentett fizetési módja</translation>
<translation id="9169664750068251925">Mindig tiltsa ezen az oldalon</translation>
<translation id="9170848237812810038">&amp;Visszavonás</translation>
<translation id="917450738466192189">A szerver tanúsítványa érvénytelen.</translation>
@@ -1113,7 +1119,6 @@
<translation id="9207861905230894330">A cikk hozzáadása sikertelen.</translation>
<translation id="9215416866750762878">Valamelyik alkalmazás megakadályozza a Chrome-ot abban, hogy biztonságosan csatlakozzon a webhelyhez</translation>
<translation id="9219103736887031265">Képek</translation>
-<translation id="933612690413056017">Nincs internetkapcsolat</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ŰRLAP TÖRLÉSE</translation>
<translation id="939736085109172342">Új mappa</translation>
diff --git a/chromium/components/strings/components_strings_id.xtb b/chromium/components/strings/components_strings_id.xtb
index 10331a4909e..69e5de491f8 100644
--- a/chromium/components/strings/components_strings_id.xtb
+++ b/chromium/components/strings/components_strings_id.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Pilih izin untuk <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Bookmark yang baru dibuka</translation>
<translation id="1113869188872983271">&amp;Urungkan pengaturan ulang</translation>
+<translation id="1125573121925420732">Peringatan mungkin akan sering ditampilkan selama situs mengupdate keamanannya. Situasi ini akan segera diperbaiki.</translation>
<translation id="1126551341858583091">Ukuran di penyimpanan lokal adalah <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache kebijakan Oke</translation>
<translation id="1150979032973867961">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh sistem operasi komputer Anda. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Pastikan sambungan internet berfungsi normal.&lt;/li&gt;
&lt;li&gt;Hubungi pemilik situs.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Anda memasukkan sandi di situs yang tidak dikelola oleh organisasi. Untuk melindungi akun, jangan gunakan sandi yang sama di aplikasi dan situs lain.</translation>
<translation id="1263231323834454256">Daftar bacaan</translation>
<translation id="1264126396475825575">Laporan kerusakan diambil pada pukul <ph name="CRASH_TIME" /> (belum diupload atau diabaikan)</translation>
<translation id="1270502636509132238">Metode Pengambilan</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Pilih</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Cegah dialog lain dari halaman ini.</translation>
-<translation id="1629803312968146339">Ingin Chrome menyimpan kartu ini?</translation>
<translation id="1639239467298939599">Memuat</translation>
<translation id="1640180200866533862">Kebijakan pengguna</translation>
<translation id="1640244768702815859">Coba <ph name="BEGIN_LINK" />buka beranda situs<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Coba jalankan Diagnostik Jaringan Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Perbarui frasa sandi sinkronisasi Anda.</translation>
<translation id="1787142507584202372">Tab yang terbuka muncul di sini</translation>
-<translation id="1789575671122666129">Pop-up</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nama Pemegang Kartu</translation>
<translation id="1806541873155184440">Ditambahkan pada <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Mulai ulang komputer</translation>
<translation id="2113977810652731515">Kartu</translation>
<translation id="2114841414352855701">Diabaikan karena diganti dengan <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Mencari halaman Web Fisik di sekitar</translation>
<translation id="213826338245044447">Bookmark Seluler</translation>
<translation id="214556005048008348">Batalkan pembayaran</translation>
<translation id="2147827593068025794">Sinkronisasi Latar Belakang</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Kebijakan tidak ditemukan</translation>
<translation id="2213606439339815911">Mengambil entri...</translation>
<translation id="2218879909401188352">Saat ini, penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> dapat menginstal aplikasi berbahaya yang dapat merusak perangkat, menambahkan biaya tersembunyi ke tagihan seluler, atau mencuri informasi pribadi Anda. <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Tidak ada internet</translation>
<translation id="2230458221926704099">Perbaiki sambungan menggunakan <ph name="BEGIN_LINK" />aplikasi diagnosis<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Kirim sekarang</translation>
<translation id="225207911366869382">Nilai ini sudah usang untuk kebijakan ini.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Hapus item yang dipilih</translation>
<translation id="277133753123645258">Metode pengiriman</translation>
<translation id="277499241957683684">Catatan perangkat hilang</translation>
+<translation id="2781030394888168909">Ekspor MacOS</translation>
<translation id="2784949926578158345">Sambungan disetel ulang.</translation>
<translation id="2788784517760473862">Kartu kredit yang diterima</translation>
<translation id="2794233252405721443">Situs diblokir</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Saat ini Chrome tidak dapat mengonfirmasi kartu. Coba lagi nanti.</translation>
<translation id="3064966200440839136">Keluar dari mode penyamaran untuk membayar melalui aplikasi eksternal. Lanjutkan?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Tidak ada}=1{1 sandi}other{# sandi}}</translation>
-<translation id="3093245981617870298">Anda sedang offline.</translation>
<translation id="3096100844101284527">Tambahkan Alamat Pengambilan</translation>
<translation id="3105172416063519923">ID Aset:</translation>
<translation id="3109728660330352905">Anda tidak memiliki otorisasi untuk melihat halaman ini.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> saat ini tidak dapat dijangkau.</translation>
<translation id="3427092606871434483">Izinkan (default)</translation>
<translation id="3427342743765426898">&amp;Ulangi Pengeditan</translation>
+<translation id="342781501876943858">Chromium menyarankan untuk menyetel ulang sandi jika Anda juga menggunakannya di situs lain.</translation>
<translation id="3431636764301398940">Simpan kartu ini ke perangkat ini</translation>
<translation id="3447661539832366887">Pemilik perangkat ini menonaktifkan game dinosaurus.</translation>
<translation id="3447884698081792621">Tampilkan sertifikat (diterbitkan oleh <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Buka halaman dalam Jendela samaran baru (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Laporan kerusakan direkam pada <ph name="CRASH_TIME" />, diupload pada <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informasi sertifikat</translation>
-<translation id="3690164694835360974">Proses masuk tidak aman</translation>
<translation id="3704162925118123524">Jaringan yang digunakan mungkin mewajibkan Anda mengunjungi halaman masuk jaringan.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Memuat...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Gunakan default global (Deteksi)</translation>
<translation id="4165986682804962316">Setelan situs</translation>
-<translation id="4169947484918424451">Ingin Chromium menyimpan kartu ini?</translation>
<translation id="4171400957073367226">Tanda tangan verifikasi tidak valid</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> item lainnya}other{<ph name="ITEM_COUNT" /> item lainnya}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Mulai ulang perangkat Anda</translation>
<translation id="4277028893293644418">Setel ulang sandi</translation>
<translation id="4280429058323657511">, kedaluwarsa <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Alihkan</translation>
<translation id="4312866146174492540">Blokir (default)</translation>
<translation id="4325863107915753736">Gagal menemukan artikel</translation>
<translation id="4326324639298822553">Periksa tanggal kedaluwarsa dan coba lagi</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Komputer ini tidak terdeteksi sebagai dikelola perusahaan sehingga kebijakan hanya dapat secara otomatis menginstal ekstensi yang dihosting di Chrome Webstore. URL update Chrome Webstore-nya adalah "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Kartu Kredit yang Diterima</translation>
<translation id="4356973930735388585">Penyerang di situs ini mungkin berusaha memasang program berbahaya di komputer Anda yang dapat mencuri atau menghapus informasi (misalnya, foto, sandi, pesan, dan kartu kredit).</translation>
+<translation id="4358461427845829800">Kelola metode pembayaran...</translation>
<translation id="4372948949327679948">Nilai <ph name="VALUE_TYPE" /> yang diharapkan.</translation>
<translation id="4377125064752653719">Anda berusaha menjangkau <ph name="DOMAIN" />, tetapi sertifikat yang disajikan oleh server telah dibatalkan oleh penerbitnya. Artinya informasi rahasia keamanan yang disajikan tidak dapat dipercaya. Anda mungkin sedang berkomunikasi dengan penyerang.</translation>
<translation id="4406896451731180161">hasil penelusuran</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Alamat Pengambilan</translation>
<translation id="4424024547088906515">Server ini tidak dapat membuktikan bahwa ini adalah <ph name="DOMAIN" />; sertifikat keamanannya tidak dipercaya oleh Chrome. Hal ini dapat disebabkan oleh kesalahan konfigurasi atau penyerang memotong sambungan Anda.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sertifikat masuk Anda, atau sertifikat masuk mungkin tidak diberikan.</translation>
+<translation id="4434045419905280838">Pop-up dan pengalihan</translation>
<translation id="443673843213245140">Penggunaan proxy dinonaktifkan tetapi konfigurasi proxy yang eksplisit ditentukan.</translation>
<translation id="445100540951337728">Kartu kredit yang diterima</translation>
<translation id="4506176782989081258">Kesalahan validasi: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">IsiOtomatis pembayaran dinonaktifkan</translation>
<translation id="4764776831041365478">Halaman web di <ph name="URL" /> mungkin sedang tidak aktif untuk sementara atau dipindahkan secara permanen ke alamat web baru.</translation>
<translation id="4771973620359291008">Terjadi kesalahan yang tidak diketahui.</translation>
+<translation id="4785689107224900852">Alihkan ke tab ini</translation>
<translation id="4792143361752574037">Terjadi masalah saat mengakses file sesi. Fitur menyimpan ke disk saat ini dinonaktifkan. Harap muat ulang halaman untuk mencoba lagi.</translation>
<translation id="4800132727771399293">Periksa tanggal masa berlaku habis dan CVC, lalu coba lagi</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Saat ini Anda tidak dapat mengunjungi <ph name="SITE" /> karena situs web tersebut mengirim kredensial acak yang tidak dapat diproses oleh Google Chrome. Kesalahan jaringan dan serangan biasanya bersifat sementara, jadi halaman ini mungkin akan bekerja nanti.</translation>
<translation id="4813512666221746211">Kesalahan jaringan</translation>
<translation id="4816492930507672669">Paskan dengan halaman</translation>
-<translation id="483020001682031208">Tidak ada halaman Web Fisik untuk ditampilkan</translation>
<translation id="4850886885716139402">Lihat</translation>
<translation id="4854362297993841467">Metode pengiriman tidak tersedia. Coba metode lain.</translation>
<translation id="4858792381671956233">Kamu telah meminta izin kepada orang tua untuk mengunjungi situs ini</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bit)</translation>
<translation id="5121084798328133320">Setelah mengonfirmasi, detail kartu dari akun Pembayaran Google Anda akan dibagikan dengan situs ini.</translation>
<translation id="5128122789703661928">Sesi dengan nama ini tidak valid untuk dihapus.</translation>
+<translation id="5135404736266831032">Kelola alamat...</translation>
<translation id="5141240743006678641">Enkripsikan sandi yang disinkronkan dengan kredensial Google Anda</translation>
<translation id="5145883236150621069">Ada kode kesalahan dalam tanggapan kebijakan</translation>
<translation id="5159010409087891077">Buka halaman dalam Jendela samaran baru (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Halaman tersemat di halaman ini menyatakan</translation>
<translation id="5205222826937269299">Nama wajib diisi</translation>
<translation id="5222812217790122047">Email wajib diisi</translation>
-<translation id="522700295135997067">Situs ini mungkin telah mencuri sandi Anda</translation>
<translation id="5230733896359313003">Alamat Pengiriman</translation>
<translation id="5250209940322997802">"Sambungkan ke jaringan"</translation>
<translation id="5251803541071282808">Awan</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Situs yang ada di intranet perusahaan, organisasi, atau sekolah ini memiliki URL yang sama dengan situs web eksternal.
<ph name="LINE_BREAK" />
Coba hubungi administrator sistem Anda.</translation>
-<translation id="5499929369096410817">Masukkan kode keamanan untuk <ph name="CREDIT_CARD" />. Kode ini tidak akan disimpan.</translation>
<translation id="5509780412636533143">Mengelola bookmark</translation>
<translation id="5510766032865166053">File mungkin telah dipindahkan atau dihapus.</translation>
<translation id="5523118979700054094">Nama kebijakan</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Tambahkan Alamat Pengiriman</translation>
<translation id="5689199277474810259">Ekspor ke JSON</translation>
<translation id="5689516760719285838">Lokasi</translation>
+<translation id="570530837424789914">Kelola...</translation>
<translation id="5710435578057952990">Identitas situs Web ini belum diverifikasi.</translation>
<translation id="5719499550583120431">Kartu prabayar diterima.</translation>
<translation id="5720705177508910913">Pengguna saat ini</translation>
+<translation id="5730040223043577876">Chrome menyarankan untuk menyetel ulang sandi jika Anda juga menggunakannya di situs lain.</translation>
<translation id="5732392974455271431">Orang tua dapat membuka blokirnya untukmu</translation>
<translation id="5763042198335101085">Masukkan alamat email yang valid</translation>
<translation id="5765072501007116331">Untuk melihat persyaratan dan metode pengiriman, pilih alamat</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Kirim beberapa <ph name="BEGIN_WHITEPAPER_LINK" />informasi sistem dan konten halaman<ph name="END_WHITEPAPER_LINK" /> secara otomatis ke Google untuk membantu mendeteksi aplikasi dan situs berbahaya. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edit Info Kontak</translation>
<translation id="5967867314010545767">Hapus dari histori</translation>
-<translation id="5972020793760134803">Ganti tab</translation>
<translation id="5975083100439434680">Perkecil</translation>
-<translation id="597552863672748783">Konfirmasi kode keamanan</translation>
<translation id="598637245381783098">Tidak dapat membuka aplikasi pembayaran</translation>
<translation id="5989320800837274978">Baik proxy server tetap ataupun URL skrip .pac tidak ditentukan.</translation>
<translation id="5990559369517809815">Permintaan ke server telah dicekal oleh ekstensi.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Konten ini mungkin mencoba mengelabui Anda agar menginstal software atau mengungkapkan informasi pribadi. <ph name="BEGIN_LINK" />Tetap tampilkan<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Anda tidak dapat membuka <ph name="SITE" /> sekarang karena situs menggunakan penyematan sertifikat. Error jaringan dan serangan biasanya bersifat sementara, sehingga halaman ini mungkin akan berfungsi nanti.</translation>
<translation id="6059925163896151826">Perangkat USB</translation>
+<translation id="6071091556643036997">Jenis kebijakan tidak valid.</translation>
<translation id="6080696365213338172">Anda telah mengakses konten menggunakan sertifikat yang diberikan oleh administrator. Data yang diberikan ke <ph name="DOMAIN" /> dapat dicegat oleh administrator Anda.</translation>
<translation id="610911394827799129">Akun Google Anda mungkin memiliki bentuk histori browsing lainnya di <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Tidak ada}=1{1 sandi (disinkronkan)}other{# sandi (disinkronkan)}}</translation>
@@ -755,7 +757,7 @@
<translation id="6355080345576803305">Diganti oleh sesi publik</translation>
<translation id="6358450015545214790">Apakah maksud ini?</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{1 saran lain}other{# saran lain}}</translation>
-<translation id="6387754724289022810">Untuk membayar lebih cepat di pembelian selanjutnya, simpan kartu dan alamat penagihan ke Akun Google Anda dan ke perangkat ini.</translation>
+<translation id="6387754724289022810">Untuk membayar lebih cepat di pembelian berikutnya, simpan kartu dan alamat penagihan ke akun Google Anda.</translation>
<translation id="6397451950548600259">Software di komputer menghentikan Chrome agar tidak terhubung dengan aman ke web</translation>
<translation id="6404511346730675251">Edit bookmark</translation>
<translation id="6410264514553301377">Masukkan tanggal kedaluwarsa dan CVC <ph name="CREDIT_CARD" /></translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Tambahkan informasi lainnya</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6451458296329894277">Konfirmasikan Pengiriman Ulang Formulir</translation>
+<translation id="6465306955648956876">Kelola sandi...</translation>
<translation id="647261751007945333">Kebijakan perangkat</translation>
<translation id="6477321094435799029">Chrome mendeteksi kode yang tidak biasa pada halaman ini dan memblokirnya untuk melindungi informasi pribadi Anda (misalnya, sandi, nomor telepon, dan kartu kredit).</translation>
<translation id="6489534406876378309">Mulai mengupload kerusakan</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Penelusuran</translation>
<translation id="6630809736994426279">Saat ini, penyerang di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin berusaha menginstal program berbahaya di Mac Anda yang dapat mencuri atau menghapus informasi Anda (misalnya, foto, sandi, pesan, dan kartu kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Pelajari lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Kebijakan ini telah usang.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Tidak ada}=1{Dari 1 situs (Anda tidak akan logout dari Akun Google)}other{Dari # situs (Anda tidak akan logout dari Akun Google)}}</translation>
<translation id="6657585470893396449">Sandi</translation>
<translation id="6671697161687535275">Hapus saran formulir dari Chromium?</translation>
<translation id="6685834062052613830">Keluar dan selesaikan penyiapan</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Pengguna:</translation>
<translation id="6945221475159498467">Pilih</translation>
<translation id="6948701128805548767">Untuk melihat persyaratan dan metode pengambilan, pilih alamat</translation>
+<translation id="6949872517221025916">Setel Ulang Sandi</translation>
<translation id="6957887021205513506">Sertifikat server tampaknya palsu.</translation>
<translation id="6965382102122355670">Oke</translation>
<translation id="6965978654500191972">Perangkat</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Metode pengiriman</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> lainnya}other{<ph name="PAYMENT_METHOD_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> lainnya}}</translation>
-<translation id="7155487117670177674">Pembayaran tidak aman</translation>
+<translation id="717330890047184534">ID GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> lainnya}other{<ph name="SHIPPING_OPTION_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> lainnya}}</translation>
<translation id="7180611975245234373">Segarkan</translation>
<translation id="7182878459783632708">Tidak ada kebijakan yang disetel</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Gunakan default global (Cekal)</translation>
<translation id="7460163899615895653">Tab terbaru dari perangkat lain muncul di sini</translation>
<translation id="7469372306589899959">Mengonfirmasi kartu</translation>
+<translation id="7473891865547856676">Lain Kali</translation>
<translation id="7481312909269577407">Maju</translation>
<translation id="7485870689360869515">Tidak ada data yang ditemukan.</translation>
<translation id="7508255263130623398">ID perangkat kebijakan yang dikembalikan kosong atau tidak cocok dengan ID perangkat saat ini</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Hapus kartu kredit dari Chrome?</translation>
<translation id="7575800019233204241">"Koneksi tidak bersifat pribadi" atau "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" atau "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" atau "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" atau "SSL certificate error"</translation>
<translation id="7578104083680115302">Bayar di situs dan aplikasi di semua perangkat dengan cepat menggunakan kartu yang disimpan dengan Google.</translation>
-<translation id="7588950540487816470">Web Fisik</translation>
<translation id="7592362899630581445">Sertifikat server melanggar batasan nama.</translation>
<translation id="7598391785903975535">Kurang dari <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> saat ini tidak dapat menangani permintaan ini.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Urungkan pengeditan</translation>
<translation id="9154194610265714752">Diperbarui</translation>
<translation id="9157595877708044936">Menyiapkan...</translation>
+<translation id="9168814207360376865">Izinkan situs memeriksa apakah Anda telah menyimpan metode pembayaran atau tidak</translation>
<translation id="9169664750068251925">Selalu cekal di situs ini</translation>
<translation id="9170848237812810038">&amp;Urung</translation>
<translation id="917450738466192189">Sertifikat server tidak valid.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Gagal menambahkan artikel.</translation>
<translation id="9215416866750762878">Aplikasi membuat Chrome tidak terhubung dengan aman ke situs ini</translation>
<translation id="9219103736887031265">Gambar</translation>
-<translation id="933612690413056017">Tidak ada koneksi Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">HAPUS FORMULIR</translation>
<translation id="939736085109172342">Folder baru</translation>
diff --git a/chromium/components/strings/components_strings_it.xtb b/chromium/components/strings/components_strings_it.xtb
index fa00a864be9..2226bbd77a7 100644
--- a/chromium/components/strings/components_strings_it.xtb
+++ b/chromium/components/strings/components_strings_it.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Seleziona l'autorizzazione per <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Preferiti aggiunti di recente</translation>
<translation id="1113869188872983271">&amp;Annulla ridisposizione</translation>
+<translation id="1125573121925420732">Gli avvisi potrebbero essere frequenti durante l'aggiornamento della sicurezza dei siti web. La situazione dovrebbe migliorare a breve.</translation>
<translation id="1126551341858583091">Le dimensioni nello spazio di archiviazione locale sono pari a <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache dei criteri integra</translation>
<translation id="1150979032973867961">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile dal sistema operativo del computer. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Verifica che la connessione a Internet funzioni correttamente.&lt;/li&gt;
&lt;li&gt;Contatta il proprietario del sito web.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Hai inserito la password su un sito non gestito dalla tua organizzazione. Per proteggere il tuo account, non riutilizzare la password su altri siti e app.</translation>
<translation id="1263231323834454256">Elenco di lettura</translation>
<translation id="1264126396475825575">Rapporto sugli arresti anomali generato il giorno <ph name="CRASH_TIME" /> (non ancora caricato o ignorato)</translation>
<translation id="1270502636509132238">Metodo di ritiro</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Scegli</translation>
<translation id="1620510694547887537">Videocamera</translation>
<translation id="1623104350909869708">Impedisci la creazione di altre finestre di dialogo in questa pagina</translation>
-<translation id="1629803312968146339">Vuoi che Chrome salvi questa carta?</translation>
<translation id="1639239467298939599">Caricamento</translation>
<translation id="1640180200866533862">Criteri utente</translation>
<translation id="1640244768702815859">Prova a <ph name="BEGIN_LINK" />visitare la home page del sito<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prova a eseguire lo strumento Diagnostica di rete Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Aggiorna la tua passphrase di sincronizzazione.</translation>
<translation id="1787142507584202372">Le tue schede aperte vengono visualizzate qui</translation>
-<translation id="1789575671122666129">Popup</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nome del titolare della carta</translation>
<translation id="1806541873155184440">Data di aggiunta: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Riavvia il computer</translation>
<translation id="2113977810652731515">Carta</translation>
<translation id="2114841414352855701">Ignorata perché è stata sostituita da <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Ricerca di pagine Physical Web nelle vicinanze in corso</translation>
<translation id="213826338245044447">Preferiti su disp. mobili</translation>
<translation id="214556005048008348">Annulla pagamento</translation>
<translation id="2147827593068025794">Sincronizzazione in background</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Criterio non trovato</translation>
<translation id="2213606439339815911">Recupero voci...</translation>
<translation id="2218879909401188352">Gli utenti malintenzionati attualmente presenti sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> potrebbero installare app pericolose che danneggiano il tuo dispositivo, generano addebiti nascosti sulla fattura del cellulare o si impossessano delle tue informazioni personali. <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Nessuna connessione a Internet</translation>
<translation id="2230458221926704099">Correggi la connessione con l'<ph name="BEGIN_LINK" />app diagnostica<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Invia ora</translation>
<translation id="225207911366869382">Il valore specificato per la norma è obsoleto.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Rimuovi gli elementi selezionati</translation>
<translation id="277133753123645258">Metodo di spedizione</translation>
<translation id="277499241957683684">Record del dispositivo mancante</translation>
+<translation id="2781030394888168909">Esporta Mac OS</translation>
<translation id="2784949926578158345">La connessione è stata reimpostata.</translation>
<translation id="2788784517760473862">Carte di credito accettate</translation>
<translation id="2794233252405721443">Sito bloccato</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Al momento non è possibile confermare la carta in Chrome. Riprova più tardi.</translation>
<translation id="3064966200440839136">Per procedere al pagamento tramite un'applicazione esterna, uscirai dalla modalità di navigazione in incognito. Continuare?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nessuna}=1{1 password}other{# password}}</translation>
-<translation id="3093245981617870298">Sei offline.</translation>
<translation id="3096100844101284527">Aggiungi l'indirizzo di ritiro</translation>
<translation id="3105172416063519923">ID asset:</translation>
<translation id="3109728660330352905">Non sei autorizzato a visualizzare questa pagina.</translation>
@@ -359,6 +359,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> non è attualmente raggiungibile.</translation>
<translation id="3427092606871434483">Consenti (predefinita)</translation>
<translation id="3427342743765426898">&amp;Ripeti modifica</translation>
+<translation id="342781501876943858">Chromium ti consiglia di reimpostare la password, se l'hai utilizzata su altri siti.</translation>
<translation id="3431636764301398940">Salva la carta per questo dispositivo</translation>
<translation id="3447661539832366887">Il proprietario del dispositivo ha disattivato il gioco dei dinosauri.</translation>
<translation id="3447884698081792621">Mostra certificato (rilasciato da <ph name="ISSUER" />)</translation>
@@ -395,7 +396,6 @@
<translation id="3678529606614285348">Apri la pagina in un'altra finestra di navigazione in incognito (CTRL-MAIUSC-N)</translation>
<translation id="3679803492151881375">Rapporto sugli arresti anomali generato in data <ph name="CRASH_TIME" />, caricato in data <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informazioni certificato</translation>
-<translation id="3690164694835360974">Accesso non sicuro</translation>
<translation id="3704162925118123524">La rete che stai utilizzando può richiedere di visitare la relativa pagina di accesso.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Caricamento in corso...</translation>
@@ -455,7 +455,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizza impostazioni predefinite globali (Rileva)</translation>
<translation id="4165986682804962316">Impostazioni sito</translation>
-<translation id="4169947484918424451">Vuoi che Chromium salvi questa carta?</translation>
<translation id="4171400957073367226">Firma di verifica non valida</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> altro elemento}other{Altri <ph name="ITEM_COUNT" /> elementi}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -492,6 +491,7 @@
<translation id="4275830172053184480">Riavvia il dispositivo</translation>
<translation id="4277028893293644418">Reimposta password</translation>
<translation id="4280429058323657511">, scad.: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Cambia</translation>
<translation id="4312866146174492540">Blocca (predefinita)</translation>
<translation id="4325863107915753736">Impossibile trovare l'articolo</translation>
<translation id="4326324639298822553">Controlla la data di scadenza e riprova</translation>
@@ -499,6 +499,7 @@
<translation id="4340982228985273705">Questo computer sembra non essere gestito dall'azienda, pertanto la norma consente di installare automaticamente soltanto le estensioni ospitate sul Chrome Web Store. L'URL di aggiornamento del Chrome Web Store è "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Carte di credito accettate</translation>
<translation id="4356973930735388585">I malintenzionati su questo sito potrebbero tentare di installare sul tuo computer programmi pericolosi che scoprono o eliminano i tuoi dati (ad esempio foto, password, messaggi e carte di credito).</translation>
+<translation id="4358461427845829800">Gestisci metodi di pagamento…</translation>
<translation id="4372948949327679948">È previsto il valore <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Hai tentato di accedere a <ph name="DOMAIN" /> ma il server ha presentato un certificato revocato dall'autorità di certificazione. Ciò significa che le credenziali di sicurezza presentate dal server non sono assolutamente attendibili. Potresti avere stabilito una comunicazione con un utente malintenzionato.</translation>
<translation id="4406896451731180161">risultati di ricerca</translation>
@@ -506,6 +507,7 @@
<translation id="4415426530740016218">Indirizzo di ritiro</translation>
<translation id="4424024547088906515">Questo server non è riuscito a dimostrare che si tratta di <ph name="DOMAIN" />; il relativo certificato di sicurezza non è considerato attendibile da Chrome. Il problema potrebbe essere dovuto a un'errata configurazione o a un malintenzionato che intercetta la connessione.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> non ha accettato il certificato di accesso oppure non ne è stato fornito uno.</translation>
+<translation id="4434045419905280838">Popup e reindirizzamenti</translation>
<translation id="443673843213245140">L'utilizzo di un proxy è stato disattivato ma è stata specificata una configurazione proxy esplicita.</translation>
<translation id="445100540951337728">Carte di debito accettate</translation>
<translation id="4506176782989081258">Errore di convalida. <ph name="VALIDATION_ERROR" /></translation>
@@ -540,13 +542,13 @@
<translation id="4759118997339041434">Compilazione automatica del pagamento disabilitata</translation>
<translation id="4764776831041365478">La pagina web all'indirizzo <ph name="URL" /> potrebbe essere temporaneamente non disponibile oppure è stata permanentemente spostata a un nuovo indirizzo web.</translation>
<translation id="4771973620359291008">Si è verificato un errore sconosciuto.</translation>
+<translation id="4785689107224900852">Passa a questa scheda</translation>
<translation id="4792143361752574037">Si è verificato un problema durante l'accesso ai file di sessione. Il salvataggio su disco è attualmente disattivato. Ricarica la pagina e riprova.</translation>
<translation id="4800132727771399293">Controlla la data di scadenza e il codice CVC, poi riprova</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Al momento non puoi visitare il sito web <ph name="SITE" /> perché ha inviato strane credenziali che Google Chrome non riesce a elaborare. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare più tardi.</translation>
<translation id="4813512666221746211">Errore di rete</translation>
<translation id="4816492930507672669">Adatta alla pagina</translation>
-<translation id="483020001682031208">Nessuna pagina di Physical Web da mostrare</translation>
<translation id="4850886885716139402">Visualizza</translation>
<translation id="4854362297993841467">Questo metodo di consegna non è disponibile. Prova un metodo diverso.</translation>
<translation id="4858792381671956233">Hai chiesto ai tuoi genitori se puoi visitare questo sito</translation>
@@ -586,6 +588,7 @@
<translation id="5115563688576182185">(a 64 bit)</translation>
<translation id="5121084798328133320">Dopo essere stati confermati, i dati della carta del tuo account Google Payments saranno condivisi con questo sito.</translation>
<translation id="5128122789703661928">Impossibile eliminare la sessione perché il nome specificato non è valido.</translation>
+<translation id="5135404736266831032">Gestisci indirizzi…</translation>
<translation id="5141240743006678641">Cripta le password sincronizzate con le tue credenziali Google</translation>
<translation id="5145883236150621069">Codice di errore presente nella risposta del criterio</translation>
<translation id="5159010409087891077">Apri la pagina in un'altra finestra di navigazione in incognito (⇧⌘N)</translation>
@@ -597,7 +600,6 @@
<translation id="5201306358585911203">Una pagina incorporata in questa pagina dice</translation>
<translation id="5205222826937269299">Nome obbligatorio</translation>
<translation id="5222812217790122047">Email obbligatoria</translation>
-<translation id="522700295135997067">Questo sito potrebbe avere appena rubato la tua password</translation>
<translation id="5230733896359313003">Indirizzo di spedizione</translation>
<translation id="5250209940322997802">"Collegati alla rete"</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -641,7 +643,6 @@
<translation id="5492298309214877701">Il sito nell'Intranet dell'azienda, dell'organizzazione o della scuola ha lo stesso URL del sito web esterno.
<ph name="LINE_BREAK" />
Prova a contattare l'amministratore di sistema.</translation>
-<translation id="5499929369096410817">Inserisci il codice di sicurezza della carta <ph name="CREDIT_CARD" />. Il codice non verrà salvato.</translation>
<translation id="5509780412636533143">Preferiti gestiti</translation>
<translation id="5510766032865166053">Potrebbe essere stato spostato o eliminato.</translation>
<translation id="5523118979700054094">Nome norma</translation>
@@ -672,9 +673,11 @@
<translation id="5685654322157854305">Aggiungi l'indirizzo di spedizione</translation>
<translation id="5689199277474810259">Esporta in JSON</translation>
<translation id="5689516760719285838">Posizione</translation>
+<translation id="570530837424789914">Gestisci…</translation>
<translation id="5710435578057952990">L'identità di questo sito web non è stata verificata.</translation>
<translation id="5719499550583120431">Le carte prepagate sono accettate.</translation>
<translation id="5720705177508910913">Utente corrente</translation>
+<translation id="5730040223043577876">Chrome ti consiglia di reimpostare la password, se l'hai utilizzata su altri siti.</translation>
<translation id="5732392974455271431">I tuoi genitori possono sbloccarlo per te</translation>
<translation id="5763042198335101085">Inserisci un indirizzo email valido</translation>
<translation id="5765072501007116331">Seleziona un indirizzo per conoscere i requisiti e i metodi di consegna</translation>
@@ -698,9 +701,7 @@
<translation id="5959728338436674663">Invia automaticamente a Google <ph name="BEGIN_WHITEPAPER_LINK" />alcune informazioni sul sistema e alcuni contenuti delle pagine<ph name="END_WHITEPAPER_LINK" /> per contribuire a rilevare app e siti pericolosi. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Modifica informazioni di contatto</translation>
<translation id="5967867314010545767">Rimuovi da cronologia</translation>
-<translation id="5972020793760134803">Passa alla scheda</translation>
<translation id="5975083100439434680">Diminuisci lo zoom</translation>
-<translation id="597552863672748783">Conferma codice di sicurezza</translation>
<translation id="598637245381783098">Impossibile aprire l'app per i pagamenti</translation>
<translation id="5989320800837274978">Non sono stati specificati né server proxy fissi né un URL script .pac.</translation>
<translation id="5990559369517809815">Le richieste al server sono state bloccate da un'estensione.</translation>
@@ -716,6 +717,7 @@
<translation id="6047927260846328439">Questi contenuti potrebbero cercare di indurti con l'inganno a installare software o a rivelare informazioni personali. <ph name="BEGIN_LINK" />Mostra comunque<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Al momento non puoi visitare il sito web <ph name="SITE" /> perché utilizza il blocco dei certificati. In genere gli errori di rete e gli attacchi sono temporanei, pertanto questa pagina potrebbe funzionare più tardi.</translation>
<translation id="6059925163896151826">Dispositivi USB</translation>
+<translation id="6071091556643036997">Il tipo di norma non è valido.</translation>
<translation id="6080696365213338172">Hai raggiunto i contenuti utilizzando un certificato fornito dall'amministratore. I dati che fornisci a <ph name="DOMAIN" /> possono essere intercettati dal tuo amministratore.</translation>
<translation id="610911394827799129">Il tuo account Google potrebbe avere altri tipi di cronologia di navigazione all'indirizzo <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nessuna}=1{1 password (sincronizzata)}other{# password (sincronizzate)}}</translation>
@@ -762,6 +764,7 @@
<translation id="6446608382365791566">Aggiungi altre informazioni</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6451458296329894277">Conferma reinvio modulo</translation>
+<translation id="6465306955648956876">Gestisci password…</translation>
<translation id="647261751007945333">Norme dispositivo</translation>
<translation id="6477321094435799029">Chrome ha rilevato un codice insolito su questa pagina e l'ha bloccata per proteggere le tue informazioni personali (ad esempio password, numeri di telefono e carte di credito).</translation>
<translation id="6489534406876378309">Avvia caricamento arresti anomali</translation>
@@ -781,6 +784,7 @@
<translation id="6628463337424475685">Ricerca <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Gli utenti malintenzionati attualmente presenti sul sito <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> potrebbero cercare di installare sul tuo Mac programmi pericolosi che carpiscono o eliminano le tue informazioni (ad esempio, foto, password, messaggi e carte di credito). <ph name="BEGIN_LEARN_MORE_LINK" />Ulteriori informazioni<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Questa norma è obsoleta.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nessuno}=1{Da 1 sito (non verrai scollegato dal tuo account Google)}other{Da # siti (non verrai scollegato dal tuo account Google)}}</translation>
<translation id="6657585470893396449">Password</translation>
<translation id="6671697161687535275">Rimuovere il suggerimento per i moduli da Chromium?</translation>
<translation id="6685834062052613830">Esci e completa la configurazione</translation>
@@ -807,6 +811,7 @@
<translation id="6915804003454593391">Utente:</translation>
<translation id="6945221475159498467">Seleziona</translation>
<translation id="6948701128805548767">Seleziona un indirizzo per conoscere i requisiti e i metodi di ritiro</translation>
+<translation id="6949872517221025916">Reimposta la password</translation>
<translation id="6957887021205513506">Il certificato del server risulta essere un falso.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -828,7 +833,7 @@
<translation id="7138472120740807366">Metodo di consegna</translation>
<translation id="7139724024395191329">Emirato</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> altro}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e altri <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Pagamento non sicuro</translation>
+<translation id="717330890047184534">ID GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> altra}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e altre <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Aggiorna</translation>
<translation id="7182878459783632708">Nessuna norma impostata</translation>
@@ -877,6 +882,7 @@
<translation id="7455133967321480974">Usa predefinita globale (Blocca)</translation>
<translation id="7460163899615895653">Le schede recenti di altri dispositivi sono mostrate qui</translation>
<translation id="7469372306589899959">Conferma della carta…</translation>
+<translation id="7473891865547856676">No grazie</translation>
<translation id="7481312909269577407">Avanti</translation>
<translation id="7485870689360869515">Nessun dato trovato.</translation>
<translation id="7508255263130623398">L'ID dispositivo della norma restituito è vuoto o non corrisponde all'ID dispositivo corrente</translation>
@@ -899,7 +905,6 @@
<translation id="7569952961197462199">Rimuovere la carta di credito da Chrome?</translation>
<translation id="7575800019233204241">"La connessione non è privata", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" o "Errore certificato SSL"</translation>
<translation id="7578104083680115302">Paga velocemente su siti e app su più dispositivi utilizzando le carte salvate su Google.</translation>
-<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Il certificato del server vìola i vincoli relativi ai nomi.</translation>
<translation id="7598391785903975535">Meno di <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> al momento non è in grado di gestire la richiesta.</translation>
@@ -1102,6 +1107,7 @@
<translation id="9148507642005240123">&amp;Annulla modifica</translation>
<translation id="9154194610265714752">Aggiornato</translation>
<translation id="9157595877708044936">Configurazione in corso...</translation>
+<translation id="9168814207360376865">Consenti ai siti di controllare se hai metodi di pagamento salvati</translation>
<translation id="9169664750068251925">Blocca sempre su questo sito</translation>
<translation id="9170848237812810038">&amp;Annulla</translation>
<translation id="917450738466192189">Il certificato del server non è valido.</translation>
@@ -1110,7 +1116,6 @@
<translation id="9207861905230894330">Impossibile aggiungere l'articolo.</translation>
<translation id="9215416866750762878">Un'applicazione sta impedendo a Chrome di connettersi in sicurezza a questo sito.</translation>
<translation id="9219103736887031265">Immagini</translation>
-<translation id="933612690413056017">Connessione Internet assente</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">CANCELLA MODULO</translation>
<translation id="939736085109172342">Nuova cartella</translation>
diff --git a/chromium/components/strings/components_strings_iw.xtb b/chromium/components/strings/components_strings_iw.xtb
index b25fe991ec8..af9e7724dcb 100644
--- a/chromium/components/strings/components_strings_iw.xtb
+++ b/chromium/components/strings/components_strings_iw.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">צריך לבחור את ההרשאה של <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">סימניות אחרונות</translation>
<translation id="1113869188872983271">&amp;ביטול של שינוי סדר</translation>
+<translation id="1125573121925420732">לפעמים מופיעות אזהרות בזמן שאתרים מעדכנים את האבטחה שלהם. זה אמור להיפסק בקרוב.</translation>
<translation id="1126551341858583091">גודל האחסון המקומי הוא <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">המטמון של המדיניות תקין</translation>
<translation id="1150979032973867961">השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />. אישור האבטחה שלו לא נחשב כמהימן על ידי מערכת ההפעלה של המחשב. ייתכן שהסיבה לכך היא תצורה שגויה או תוקף המיירט את החיבור שלך.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;מוודאים שהחיבור לאינטרנט תקין.&lt;/li&gt;
&lt;li&gt;פונים אל הבעלים של האתר.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">הזנת את הסיסמה באתר שאינו מנוהל על-ידי הארגון שלך. כדי להגן על החשבון, אין לעשות שימוש חוזר בסיסמה באפליקציות ובאתרים אחרים.</translation>
<translation id="1263231323834454256">רשימת קריאה</translation>
<translation id="1264126396475825575">דוח הקריסה תועד ב-<ph name="CRASH_TIME" /> (עדיין לא העלית אותו או בחרת להתעלם ממנו)</translation>
<translation id="1270502636509132238">שיטת איסוף</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">בחר</translation>
<translation id="1620510694547887537">מצלמה</translation>
<translation id="1623104350909869708">מנע מהדף זה ליצור תיבות דו-שיח נוספות</translation>
-<translation id="1629803312968146339">‏האם תרצה ש-Chrome ישמור את הכרטיס הזה?</translation>
<translation id="1639239467298939599">טוען</translation>
<translation id="1640180200866533862">מדיניות משתמשים</translation>
<translation id="1640244768702815859">נסה <ph name="BEGIN_LINK" />להיכנס לדף הבית של האתר<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159">‏<ph name="BEGIN_LINK" />נסה להפעיל את אבחון הרשת של Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">עדכן את משפט-הסיסמה של הסינכרון.</translation>
<translation id="1787142507584202372">כאן מופיעות הכרטיסיות שאתה פותח</translation>
-<translation id="1789575671122666129">חלונות קופצים</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">שם בעל הכרטיס</translation>
<translation id="1806541873155184440">תאריך הוספה: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">אתחול המחשב</translation>
<translation id="2113977810652731515">כרטיס</translation>
<translation id="2114841414352855701">המערכת התעלמה משום שהמדיניות בוטלה על ידי <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">מחפש דפים של האינטרנט הווירטופיזי בקרבת מקום</translation>
<translation id="213826338245044447">סימניות לנייד</translation>
<translation id="214556005048008348">ביטול תשלום</translation>
<translation id="2147827593068025794">סינכרון ברקע</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">לא נמצאה מדיניות</translation>
<translation id="2213606439339815911">מאחזר רשומות...</translation>
<translation id="2218879909401188352">תוקפים שמשתמשים עכשיו ב-<ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> עלולים להתקין יישומים מסוכנים ולגרום נזק למכשיר שלך, להגדיל את החיובים שלך על החבילה לנייד או לגנוב את המידע האישי שלך. <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">אין אינטרנט</translation>
<translation id="2230458221926704099">תקן את החיבור באמצעות <ph name="BEGIN_LINK" />אפליקציית הבדיקה<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">שלח עכשיו</translation>
<translation id="225207911366869382">ערך זה הוצא משימוש עבור מדיניות זו.</translation>
@@ -221,7 +221,7 @@
<translation id="2491120439723279231">אישור השרת מכיל שגיאות.</translation>
<translation id="2495083838625180221">‏מנתח JSON</translation>
<translation id="2495093607237746763">‏אם האפשרות תסומן, Chromium ישמור עותק של הכרטיס במכשיר הזה כדי למלא טפסים במהירות רבה יותר.</translation>
-<translation id="2498091847651709837">סרוק כרטיס חדש</translation>
+<translation id="2498091847651709837">סריקת כרטיס חדש</translation>
<translation id="2501278716633472235">חזור</translation>
<translation id="2503184589641749290">כרטיסי חיוב וכרטיסים משולמים מראש שהסוחר מקבל</translation>
<translation id="2515629240566999685">לבדוק את האות באזור שלך</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">הסר פריטים שנבחרו</translation>
<translation id="277133753123645258">שיטת משלוח</translation>
<translation id="277499241957683684">חסרה רשומת מכשיר</translation>
+<translation id="2781030394888168909">‏ייצוא בפורמט ל-MacOS</translation>
<translation id="2784949926578158345">החיבור עבר איפוס.</translation>
<translation id="2788784517760473862">כרטיסי אשראי שהסוחר מקבל</translation>
<translation id="2794233252405721443">אתר חסום</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">‏Chrome לא הצליח לאשר את הכרטיס שלך הפעם. נסה שוב מאוחר יותר.</translation>
<translation id="3064966200440839136">בחרת לצאת ממצב גלישה בסתר כדי לשלם באמצעות יישום חיצוני. להמשיך?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ללא}=1{סיסמה אחת}two{שתי סיסמאות}many{# סיסמאות}other{# סיסמאות}}</translation>
-<translation id="3093245981617870298">אתה במצב לא מקוון.</translation>
<translation id="3096100844101284527">הוספת כתובת לאיסוף</translation>
<translation id="3105172416063519923">מזהה נכס:</translation>
<translation id="3109728660330352905">אין לך הרשאה להציג את הדף הזה.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">לא ניתן לגשת כרגע אל <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">התר (ברירת מחדל)</translation>
<translation id="3427342743765426898">&amp;ביצוע מחדש של עריכה</translation>
+<translation id="342781501876943858">‏אם הזנת את הסיסמה שלך באתרים אחרים, ההמלצה של Chromium היא לאפס אותה.</translation>
<translation id="3431636764301398940">שמור כרטיס זה במכשיר הנוכחי</translation>
<translation id="3447661539832366887">הבעלים של המכשיר הזה כיבה את משחק הדינוזאורים.</translation>
<translation id="3447884698081792621">הצגת אישור (נופק על-ידי <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">‏פתח את הדף בחלון חדש של גלישה בסתר (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">דוח קריסה תועד ב-<ph name="CRASH_TIME" />, הועלה ב-<ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">פרטי אישור</translation>
-<translation id="3690164694835360974">ההתחברות אינה מאובטחת</translation>
<translation id="3704162925118123524">ייתכן שתוצג דרישה להיכנס לדף ההתחברות של הרשת שבה אתה משתמש.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">טוען...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">השתמש בברירת מחדל גלובלית (זיהוי)</translation>
<translation id="4165986682804962316">הגדרות אתרים</translation>
-<translation id="4169947484918424451">‏האם תרצה ש-Chromium ישמור את הכרטיס הזה?</translation>
<translation id="4171400957073367226">חתימת אימות לא חוקית</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{פריט אחד (<ph name="ITEM_COUNT" />) נוסף}two{<ph name="ITEM_COUNT" /> פריטים נוספים}many{<ph name="ITEM_COUNT" /> פריטים נוספים}other{<ph name="ITEM_COUNT" /> פריטים נוספים}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">הפעלת המכשיר מחדש</translation>
<translation id="4277028893293644418">איפוס סיסמה</translation>
<translation id="4280429058323657511">, בתוקף עד <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">מעבר</translation>
<translation id="4312866146174492540">חסום (ברירת מחדל)</translation>
<translation id="4325863107915753736">לא ניתן היה למצוא את הפריט</translation>
<translation id="4326324639298822553">בדוק את תאריך התפוגה ונסה שוב</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">‏המחשב לא זוהה כמכשיר המנוהל על ידי הארגון, כך שלפי המדיניות מותר להתקין אוטומטית רק תוספים מחנות האינטרנט של Chrome. כתובת האתר לעדכונים מחנות האינטרנט של Chrome היא "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">כרטיסי אשראי שהסוחר מקבל</translation>
<translation id="4356973930735388585">תוקפים באתר הזה עשויים לנסות להתקין במחשב שלך תוכניות מסוכנות שגונבות או מוחקות מידע שלך (לדוגמה: תמונות, סיסמאות, הודעות ופרטי כרטיסי אשראי).</translation>
+<translation id="4358461427845829800">ניהול אמצעי תשלום...</translation>
<translation id="4372948949327679948">צפוי ערך מסוג <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">ניסית להשיג את <ph name="DOMAIN" />, אך האישור שהשרת הציג בוטל על ידי המנפיק שלו. פירוש הדבר שאין כל אפשרות לתת אמון באישורי האבטחה שהשרת הציג. ייתכן שאתה מתקשר עם תוקף.</translation>
<translation id="4406896451731180161">תוצאות חיפוש</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">כתובת איסוף</translation>
<translation id="4424024547088906515">‏השרת הזה לא הצליח להוכיח שהוא <ph name="DOMAIN" />. אישור האבטחה שלו לא נחשב כמהימן על ידי Chrome. ייתכן שהסיבה לכך היא תצורה שגויה או תוקף המיירט את החיבור שלך.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> לא אישר את אישור ההתחברות שלך, או שלא סופק אישור התחברות.</translation>
+<translation id="4434045419905280838">חלונות קופצים והפניות אוטומטיות</translation>
<translation id="443673843213245140">‏השימוש בשרת Proxy הושבת, אך צויינה תצורת שרת Proxy מפורשת.</translation>
<translation id="445100540951337728">כרטיסי חיוב שהסוחר מקבל</translation>
<translation id="4506176782989081258">שגיאת אימות: <ph name="VALIDATION_ERROR" /></translation>
@@ -547,13 +549,13 @@
1240185477879256427אתר
Del</translation>
+<translation id="4785689107224900852">החלפה לכרטיסייה זו</translation>
<translation id="4792143361752574037">הייתה בעיה בגישה אל קובצי ההפעלה. שמירה בדיסק מושבתת עכשיו. יש לטעון מחדש את הדף כדי לנסות שוב.</translation>
<translation id="4800132727771399293">‏בדוק את תאריך התפוגה ואת ה-CVC ונסה שוב</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">‏לא ניתן לבקר כעת באתר <ph name="SITE" /> מכיוון שהאתר שלח אישורים משובשים ש-Google Chrome אינו יכול לעבד. שגיאות רשת ותקיפות מתרחשות בדרך כלל לזמן מוגבל, כך שסביר להניח שהדף הזה יפעל מאוחר יותר.</translation>
<translation id="4813512666221746211">שגיאת רשת</translation>
<translation id="4816492930507672669">התאמה לדף</translation>
-<translation id="483020001682031208">אין דפים של האינטרנט הווירטופיזי שזמינים להצגה</translation>
<translation id="4850886885716139402">הצג</translation>
<translation id="4854362297993841467">שיטת המסירה הזו אינה זמינה. עליך לבחור שיטה אחרת.</translation>
<translation id="4858792381671956233">שאלת את ההורים שלך אם אתה יכול לגשת לאתר הזה</translation>
@@ -593,6 +595,7 @@ Del</translation>
<translation id="5115563688576182185">(64 סיביות)</translation>
<translation id="5121084798328133320">‏אחרי שנקבל ממך אישור, נשתף עם האתר הזה את פרטי הכרטיס מחשבון תשלומי Google.</translation>
<translation id="5128122789703661928">שם ההפעלה למחיקה אינו חוקי.</translation>
+<translation id="5135404736266831032">ניהול כתובות...</translation>
<translation id="5141240743006678641">‏הצפן סיסמאות מסונכרנות באמצעות פרטי הכניסה שלך ל-Google</translation>
<translation id="5145883236150621069">קיים קוד שגיאה בתגובת המדיניות</translation>
<translation id="5159010409087891077">‏פתח את הדף בחלון חדש של גלישה בסתר (‎⇧⌘N)</translation>
@@ -604,7 +607,6 @@ Del</translation>
<translation id="5201306358585911203">דף מוטמע בדף הזה אומר</translation>
<translation id="5205222826937269299">שם (חובה)</translation>
<translation id="5222812217790122047">אימייל (חובה)</translation>
-<translation id="522700295135997067">ייתכן שהאתר הזה גנב עכשיו את הזהות שלך</translation>
<translation id="5230733896359313003">כתובת למשלוח</translation>
<translation id="5250209940322997802">"יש להתחבר לרשת"</translation>
<translation id="5251803541071282808">ענן</translation>
@@ -649,7 +651,6 @@ Del</translation>
של אתר חיצוני.
<ph name="LINE_BREAK" />
נסה ליצור קשר עם מנהל המערכת.</translation>
-<translation id="5499929369096410817">יש להזין את קוד האבטחה של <ph name="CREDIT_CARD" />. המערכת לא תשמור את הקוד.</translation>
<translation id="5509780412636533143">סימניות מנוהלות</translation>
<translation id="5510766032865166053">ייתכן שהוא הועבר או נמחק.</translation>
<translation id="5523118979700054094">שם מדיניות</translation>
@@ -680,9 +681,11 @@ Del</translation>
<translation id="5685654322157854305">הוספת כתובת למשלוח</translation>
<translation id="5689199277474810259">‏ייצוא אל JSON</translation>
<translation id="5689516760719285838">מיקום</translation>
+<translation id="570530837424789914">ניהול...</translation>
<translation id="5710435578057952990">הזהות של אתר זה לא אומתה.</translation>
<translation id="5719499550583120431">אפשר לשלם באמצעות כרטיסים משולמים מראש.</translation>
<translation id="5720705177508910913">משתמש נוכחי:</translation>
+<translation id="5730040223043577876">‏אם הזנת את הסיסמה שלך באתרים אחרים, ההמלצה של Chrome היא לאפס אותה.</translation>
<translation id="5732392974455271431">ההורים שלך יכולים לבטל בשבילך את החסימה</translation>
<translation id="5763042198335101085">עליך להזין כתובת אימייל חוקית</translation>
<translation id="5765072501007116331">עליך לבחור כתובת כדי לראות שיטות מסירה ודרישות</translation>
@@ -706,9 +709,7 @@ Del</translation>
<translation id="5959728338436674663">‏שלח באופן אוטומטי <ph name="BEGIN_WHITEPAPER_LINK" />חלק מפרטי המערכת ותוכן הדף<ph name="END_WHITEPAPER_LINK" /> אל Google כדי לעזור בזיהוי של אפליקציות ואתרים מסוכנים. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">עריכת הפרטים ליצירת קשר</translation>
<translation id="5967867314010545767">הסר מההיסטוריה</translation>
-<translation id="5972020793760134803">מעבר לכרטיסייה</translation>
<translation id="5975083100439434680">התרחק</translation>
-<translation id="597552863672748783">אישור קוד אבטחה</translation>
<translation id="598637245381783098">לא ניתן לפתוח את אפליקציית התשלומים</translation>
<translation id="5989320800837274978">‏לא צוינו שרתי Proxy קבועים ולא כתובת אתר של סקריפט ‎.pac</translation>
<translation id="5990559369517809815">בקשות שנשלחו לשרת נחסמו על ידי תוסף.</translation>
@@ -724,6 +725,7 @@ Del</translation>
<translation id="6047927260846328439">ייתכן שבתוכן הזה יש מידע מטעה שנועד לגרום לך להתקין תוכנות או לחשוף מידע אישי. <ph name="BEGIN_LINK" />הצג בכל זאת<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">נכון לעכשיו אי אפשר לבקר באתר <ph name="SITE" />, מאחר שבאתר הזה נעשה שימוש בנעיצת אישורים. שגיאות רשת ומתקפות הן בדרך כלל זמניות, כך שהדף הזה יחזור כנראה לפעול מאוחר יותר.</translation>
<translation id="6059925163896151826">‏מכשירי USB</translation>
+<translation id="6071091556643036997">סוג המדיניות אינו חוקי.</translation>
<translation id="6080696365213338172">ניגשת לתוכן באמצעות אישור שהוענק על ידי מנהל מערכת. מנהל המערכת שלך עשוי ליירט נתונים שתספק ל-<ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">‏ייתכן שלחשבון Google שלך משויכים סוגים אחרים של היסטוריית גלישה בכתובת <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ללא}=1{סיסמה אחת (מסונכרנת)}two{שתי סיסמאות (מסונכרנות)}many{# סיסמאות (מסונכרנות)}other{# סיסמאות (מסונכרנות)}}</translation>
@@ -771,6 +773,7 @@ Del</translation>
<translation id="6446608382365791566">הוסף מידע</translation>
<translation id="6447842834002726250">‏קובצי Cookie</translation>
<translation id="6451458296329894277">אשר שליחה-מחדש של הטופס</translation>
+<translation id="6465306955648956876">ניהול סיסמאות...</translation>
<translation id="647261751007945333">מדיניות המכשיר</translation>
<translation id="6477321094435799029">‏Chrome זיהה קוד חריג בדף הזה וחסם אותו כדי להגן על המידע הפרטי שלך (כגון סיסמאות, מספרי טלפון ומספרי כרטיסי אשראי).</translation>
<translation id="6489534406876378309">התחל להעלות קריסות</translation>
@@ -790,6 +793,7 @@ Del</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> חיפוש</translation>
<translation id="6630809736994426279">‏תוקפים שנמצאים כרגע באתר <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> עלולים להתקין במחשב ה-MAC שלך תוכנות מסוכנות שגונבות מידע או מוחקות אותו (לדוגמה, תמונות, סיסמאות, הודעות וכרטיסי אשראי). <ph name="BEGIN_LEARN_MORE_LINK" />מידע נוסף<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">מדיניות זו אינה בתוקף.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{ללא}=1{‏מאתר אחד (לא תבוצע יציאה מחשבון Google שלך.)}two{‏מ-# אתרים (לא תבוצע יציאה מחשבון Google שלך.)}many{‏מ-# אתרים (לא תבוצע יציאה מחשבון Google שלך.)}other{‏מ-# אתרים (לא תבוצע יציאה מחשבון Google שלך.)}}</translation>
<translation id="6657585470893396449">סיסמה</translation>
<translation id="6671697161687535275">‏האם להסיר מ-Chromium הצעות לטפסים?</translation>
<translation id="6685834062052613830">צא והשלם את ההגדרה</translation>
@@ -816,6 +820,7 @@ Del</translation>
<translation id="6915804003454593391">משתמש:</translation>
<translation id="6945221475159498467">בחר</translation>
<translation id="6948701128805548767">עליך לבחור כתובת כדי לראות שיטות איסוף ודרישות</translation>
+<translation id="6949872517221025916">איפוס סיסמה</translation>
<translation id="6957887021205513506">נראה שהאישור של השרת מזויף.</translation>
<translation id="6965382102122355670">אישור</translation>
<translation id="6965978654500191972">התקן</translation>
@@ -837,7 +842,7 @@ Del</translation>
<translation id="7138472120740807366">שיטת מסירה</translation>
<translation id="7139724024395191329">אמירות</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}two{<ph name="PAYMENT_METHOD_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}many{<ph name="PAYMENT_METHOD_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">התשלום אינו מאובטח</translation>
+<translation id="717330890047184534">‏מזהה GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}two{<ph name="SHIPPING_OPTION_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}many{<ph name="SHIPPING_OPTION_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> ועוד <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">רענן</translation>
<translation id="7182878459783632708">לא הוגדרה מדיניות</translation>
@@ -886,6 +891,7 @@ Del</translation>
<translation id="7455133967321480974">השתמש בברירת המחדל הכללית (חסום)</translation>
<translation id="7460163899615895653">הכרטיסיות האחרונות שפתחת במכשירים אחרים מוצגות כאן</translation>
<translation id="7469372306589899959">מאשר את הכרטיס</translation>
+<translation id="7473891865547856676">לא, תודה</translation>
<translation id="7481312909269577407">קדימה</translation>
<translation id="7485870689360869515">לא נמצאו נתונים.</translation>
<translation id="7508255263130623398">מזהה המכשיר במדיניות שהוחזר ריק או שאינו תואם את מזהה המכשיר הנוכחי</translation>
@@ -908,7 +914,6 @@ Del</translation>
<translation id="7569952961197462199">‏האם להסיר את כרטיס האשראי מ-Chrome?</translation>
<translation id="7575800019233204241">‏"החיבור שלך אינך פרטי" או "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" או "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" או "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" או "שגיאת אישור SSL"</translation>
<translation id="7578104083680115302">‏שלם במהירות באתרים ובאפליקציות בכל המכשירים באמצעות כרטיסים ששמרת ב-Google.</translation>
-<translation id="7588950540487816470">האינטרנט הווירטופיזי</translation>
<translation id="7592362899630581445">אישור השרת מפר את אילוצי השמות.</translation>
<translation id="7598391785903975535">פחות מ-<ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> לא יכול לטפל כרגע בבקשה הזו.</translation>
@@ -1112,6 +1117,7 @@ Del</translation>
<translation id="9148507642005240123">&amp;ביטול עריכה</translation>
<translation id="9154194610265714752">עודכן</translation>
<translation id="9157595877708044936">מגדיר...</translation>
+<translation id="9168814207360376865">מתן הרשאה לאתרים לבדוק אם שמרת אמצעי תשלום</translation>
<translation id="9169664750068251925">חסום תמיד באתר זה</translation>
<translation id="9170848237812810038">&amp;ביטול</translation>
<translation id="917450738466192189">אישור השרת לא חוקי.</translation>
@@ -1120,7 +1126,6 @@ Del</translation>
<translation id="9207861905230894330">הוספת הפריט נכשלה.</translation>
<translation id="9215416866750762878">‏יישום כלשהו לא מאפשר ל-Chrome להתחבר באופן מאובטח לאתר זה</translation>
<translation id="9219103736887031265">תמונות</translation>
-<translation id="933612690413056017">אין חיבור לאינטרנט</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">נקה את הטופס</translation>
<translation id="939736085109172342">תיקייה חדשה</translation>
diff --git a/chromium/components/strings/components_strings_ja.xtb b/chromium/components/strings/components_strings_ja.xtb
index 60f6c76c281..7329e471caf 100644
--- a/chromium/components/strings/components_strings_ja.xtb
+++ b/chromium/components/strings/components_strings_ja.xtb
@@ -12,7 +12,7 @@
<translation id="10614374240317010">常に保存しない</translation>
<translation id="1066396345355680611"><ph name="SITE" /> と他の一部のサイトで、保護されたコンテンツにアクセスできなくなる可能性があります。</translation>
<translation id="106701514854093668">パソコンのブックマーク</translation>
-<translation id="1074497978438210769">保護されていません</translation>
+<translation id="1074497978438210769">保護されていない通信</translation>
<translation id="1080116354587839789">ウィンドウ幅に合わせる</translation>
<translation id="1088860948719068836">名義人名の追加</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" />を常に翻訳</translation>
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> の権限を選択します</translation>
<translation id="1111153019813902504">最近アクセスしたブックマーク</translation>
<translation id="1113869188872983271">順序変更の取り消し(&amp;U)</translation>
+<translation id="1125573121925420732">ウェブサイトのセキュリティ更新中は警告メッセージが表示されることがあります。これはまもなく改善される予定です。</translation>
<translation id="1126551341858583091">ローカル ストレージ上のサイズは <ph name="CRASH_SIZE" /> です。</translation>
<translation id="112840717907525620">ポリシー キャッシュは正常です</translation>
<translation id="1150979032973867961">このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。このサーバーのセキュリティ証明書は、ご使用のパソコンのオペレーティング システムによって信頼されているものではありません。原因としては、不適切な設定や、悪意のあるユーザーによる接続妨害が考えられます。</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;インターネット接続に問題がないことを確認します。&lt;/li&gt;
&lt;li&gt;ウェブサイトの所有者に問い合わせます。&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">組織が管理していないサイトでパスワードを入力しました。アカウントを保護するには、他のアプリやサイトでパスワードを再使用しないでください。</translation>
<translation id="1263231323834454256">リーディング リスト</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> にクラッシュ レポートが作成されました(まだアップロードされておらず、無視の指定もありません)</translation>
<translation id="1270502636509132238">集荷方法</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">選択</translation>
<translation id="1620510694547887537">カメラ</translation>
<translation id="1623104350909869708">このページで追加のダイアログが作成されないようにする</translation>
-<translation id="1629803312968146339">Chrome にこのカードを保存しますか?</translation>
<translation id="1639239467298939599">読み込み中</translation>
<translation id="1640180200866533862">ユーザー ポリシー</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />サイトのホームページにアクセス<ph name="END_LINK" />してみてください。</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ネットワーク診断ツールを実行してみてください<ph name="END_LINK" />。</translation>
<translation id="1783075131180517613">同期パスフレーズを更新してください。</translation>
<translation id="1787142507584202372">最近開いたタブがここに表示されます</translation>
-<translation id="1789575671122666129">ポップアップ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">カード名義人</translation>
<translation id="1806541873155184440">追加日: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">パソコンを再起動する</translation>
<translation id="2113977810652731515">カード</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> によって上書きされるため無視されます。</translation>
-<translation id="2138201775715568214">近くのフィジカル ウェブページを探しています</translation>
<translation id="213826338245044447">モバイルのブックマーク</translation>
<translation id="214556005048008348">支払いをキャンセル</translation>
<translation id="2147827593068025794">バックグラウンド同期</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">ポリシーが見つかりません</translation>
<translation id="2213606439339815911">エントリを取得しています...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> では現在、悪意のあるユーザーによって危険なアプリ(端末に問題を生じたり、モバイル利用料に不明瞭な請求を加えたり、個人情報を抜き取ったりするアプリ)がインストールされる可能性があります。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">インターネットに接続されていません</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />診断アプリ<ph name="END_LINK" />を使用して接続を修正してください</translation>
<translation id="2239100178324503013">送信</translation>
<translation id="225207911366869382">この値は、このポリシーではサポートが終了しています。</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">選択したアイテムを削除</translation>
<translation id="277133753123645258">配送方法</translation>
<translation id="277499241957683684">デバイス レコードがありません</translation>
+<translation id="2781030394888168909">Mac OS 形式でエクスポート</translation>
<translation id="2784949926578158345">接続がリセットされました。</translation>
<translation id="2788784517760473862">利用可能なクレジット カード</translation>
<translation id="2794233252405721443">サイトがブロックされています</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome でカードを確認できませんでした。しばらくしてからもう一度お試しください。</translation>
<translation id="3064966200440839136">外部アプリケーションを経由したお支払いの処理に進むため、シークレット モードを解除します。続行しますか?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{なし}=1{1 個のパスワード}other{# 個のパスワード}}</translation>
-<translation id="3093245981617870298">現在オフラインです。</translation>
<translation id="3096100844101284527">集荷先住所を追加</translation>
<translation id="3105172416063519923">アセット ID:</translation>
<translation id="3109728660330352905">このページを表示する権限がありません。</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> は現在アクセスできません。</translation>
<translation id="3427092606871434483">許可(デフォルト)</translation>
<translation id="3427342743765426898">編集のやり直し(&amp;R)</translation>
+<translation id="342781501876943858">パスワードを他のサイトで再使用した場合、Chromium ではパスワードの再設定を促すメッセージが表示されます。</translation>
<translation id="3431636764301398940">このカード情報をこの端末に保存する</translation>
<translation id="3447661539832366887">このデバイスの所有者が恐竜ゲームを無効にしています。</translation>
<translation id="3447884698081792621">証明書(発行元: <ph name="ISSUER" />)を表示</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">ページを新しいシークレット ウィンドウで開く(Ctrl-Shift-N)</translation>
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> にクラッシュ レポートが作成され、<ph name="UPLOAD_TIME" /> にアップロードされました</translation>
<translation id="3681007416295224113">証明書情報</translation>
-<translation id="3690164694835360974">ログイン情報は保護されません</translation>
<translation id="3704162925118123524">ご利用のネットワークでは、ログインページへのアクセスが必要な可能性があります。</translation>
<translation id="3704609568417268905"><ph name="TIME" />、<ph name="TITLE" />(<ph name="DOMAIN" />)を<ph name="BOOKMARKED" /></translation>
<translation id="370665806235115550">読み込んでいます...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">全体の既定値を使用(検出)</translation>
<translation id="4165986682804962316">サイトの設定</translation>
-<translation id="4169947484918424451">Chromium にこのカードを保存しますか?</translation>
<translation id="4171400957073367226">確認用の署名に問題があります</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{他 <ph name="ITEM_COUNT" /> 件のアイテム}other{他 <ph name="ITEM_COUNT" /> 件のアイテム}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">デバイスの再起動</translation>
<translation id="4277028893293644418">パスワードを再設定</translation>
<translation id="4280429058323657511">、有効期限: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">切り替え</translation>
<translation id="4312866146174492540">ブロック(デフォルト)</translation>
<translation id="4325863107915753736">記事が見つかりませんでした</translation>
<translation id="4326324639298822553">有効期限の「日」を確認してもう一度お試しください</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">このパソコンは企業の管理対象として検出されていないため、ポリシーで自動的にインストールできるのは Chrome ウェブストアでホストされている拡張機能のみとなります。Chrome ウェブストアの更新 URL は「<ph name="CWS_UPDATE_URL" />」です。</translation>
<translation id="4346197816712207223">利用可能なクレジット カード</translation>
<translation id="4356973930735388585">このサイトを利用すると、悪意のあるユーザーによって、危険なプログラム(写真、パスワード、メッセージ、クレジット カード番号などの情報を盗み取るか削除するプログラム)がお使いのパソコンにインストールされる可能性があります。</translation>
+<translation id="4358461427845829800">お支払い方法を管理...</translation>
<translation id="4372948949327679948"><ph name="VALUE_TYPE" /> 値が想定されます。</translation>
<translation id="4377125064752653719"><ph name="DOMAIN" /> にアクセスしようとしましたが、サーバーから提示された証明書は発行元により取り消されています。これは、サーバーから提示されたセキュリティ認証情報が信頼できないことを示しており、悪意のあるユーザーと通信しようとしている可能性があります。</translation>
<translation id="4406896451731180161">検索結果</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">集荷先住所</translation>
<translation id="4424024547088906515">このサーバーが <ph name="DOMAIN" /> であることを確認できませんでした。このサーバーのセキュリティ証明書は Chrome によって信頼されているものではありません。原因としては、不適切な設定や、悪意のあるユーザーによる接続妨害が考えられます。</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> でログイン証明書が承認されなかったか、ログイン証明書が提示されていない可能性があります。</translation>
+<translation id="4434045419905280838">ポップアップとリダイレクト</translation>
<translation id="443673843213245140">プロキシの使用は無効ですが、プロキシの設定が明示的に指定されています。</translation>
<translation id="445100540951337728">利用可能なデビットカード</translation>
<translation id="4506176782989081258">検証エラー: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">お支払い情報の自動入力は無効になっています</translation>
<translation id="4764776831041365478"><ph name="URL" /> のウェブページは一時的に停止しているか、新しいウェブアドレスに移動した可能性があります。</translation>
<translation id="4771973620359291008">不明なエラーが発生しました。</translation>
+<translation id="4785689107224900852">このタブに切り替え</translation>
<translation id="4792143361752574037">セッション ファイルにアクセスする際に問題が発生しました。現在、ディスクに保存することはできません。ページを再読み込みしてもう一度お試しください。</translation>
<translation id="4800132727771399293">有効期限と CVC を確認してからもう一度お試しください</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102"><ph name="SITE" /> から、Google Chrome で処理できない暗号化された認証情報が返されたため、現在このウェブサイトにはアクセスできません。通常、ネットワーク エラーや不正な操作は一時的なものです。少し時間をおくと、ページにアクセスできるようになる可能性があります。</translation>
<translation id="4813512666221746211">ネットワーク エラー</translation>
<translation id="4816492930507672669">ページサイズに合わせる</translation>
-<translation id="483020001682031208">表示できるフィジカル ウェブのページはありません</translation>
<translation id="4850886885716139402">表示</translation>
<translation id="4854362297993841467">この配達方法はご利用いただけません。別の方法を選択してください。</translation>
<translation id="4858792381671956233">このサイトを開いてもよいかの問い合わせを保護者に送信しました</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 ビット)</translation>
<translation id="5121084798328133320">確認後、Google Payments アカウントのカード情報がこのサイトと共有されます。</translation>
<translation id="5128122789703661928">セッションの名前が有効でないため、削除できません。</translation>
+<translation id="5135404736266831032">住所を管理...</translation>
<translation id="5141240743006678641">Google の認証情報で同期パスワードを暗号化する</translation>
<translation id="5145883236150621069">ポリシー応答内にエラー コードがあります</translation>
<translation id="5159010409087891077">ページを新しいシークレット ウィンドウで開く(⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">このページに埋め込まれているページの内容</translation>
<translation id="5205222826937269299">名前は必須です</translation>
<translation id="5222812217790122047">メールアドレスは必須です</translation>
-<translation id="522700295135997067">このサイトでパスワードを盗まれた可能性があります</translation>
<translation id="5230733896359313003">配送先住所</translation>
<translation id="5250209940322997802">「ネットワークに接続してください」</translation>
<translation id="5251803541071282808">クラウド</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">このサイトは企業、団体、または学校のイントラネット上にありますが、外部のウェブサイトと同じ URL が使用されています。
<ph name="LINE_BREAK" />
システム管理者にお問い合わせください。</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> のセキュリティ コードを入力してください。このコードは保存されません。</translation>
<translation id="5509780412636533143">管理対象のブックマーク</translation>
<translation id="5510766032865166053">移動または削除された可能性があります。</translation>
<translation id="5523118979700054094">ポリシー名</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">配送先住所を追加</translation>
<translation id="5689199277474810259">JSON にエクスポート</translation>
<translation id="5689516760719285838">現在地</translation>
+<translation id="570530837424789914">管理...</translation>
<translation id="5710435578057952990">このウェブサイトの ID は確認されていません。</translation>
<translation id="5719499550583120431">プリペイド カードをご利用いただけます。</translation>
<translation id="5720705177508910913">現在のユーザー</translation>
+<translation id="5730040223043577876">パスワードを他のサイトで再使用した場合、Chrome ではパスワードの再設定を促すメッセージが表示されます。</translation>
<translation id="5732392974455271431">ブロックの解除は保護者が行うことができます</translation>
<translation id="5763042198335101085">有効なメールアドレスを入力してください</translation>
<translation id="5765072501007116331">配達方法と要件を確認するには、住所を選択してください</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">危険なアプリやサイトの検出に役立てるために一部の<ph name="BEGIN_WHITEPAPER_LINK" />システム情報やページのコンテンツ<ph name="END_WHITEPAPER_LINK" />を Google に自動送信する。<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">連絡先情報の編集</translation>
<translation id="5967867314010545767">履歴から削除</translation>
-<translation id="5972020793760134803">タブを切り替え</translation>
<translation id="5975083100439434680">縮小する</translation>
-<translation id="597552863672748783">セキュリティ コードの確認</translation>
<translation id="598637245381783098">お支払いアプリを開けません</translation>
<translation id="5989320800837274978">固定プロキシ サーバーと .pac スクリプト URL のどちらも指定されていません。</translation>
<translation id="5990559369517809815">サーバーへのリクエストは拡張機能によってブロックされています。</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">アクセス先のコンテンツは、ユーザーをだましてソフトウェアをインストールさせようとしたり、個人情報を危険にさらしたりする可能性があります。<ph name="BEGIN_LINK" />危険性を理解したうえで表示する<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> では証明書ピンニングが使用されているため、現在アクセスできません。通常、ネットワーク エラーやネットワークへの攻撃は一時的なものです。しばらくするとページにアクセスできるようになります。</translation>
<translation id="6059925163896151826">USB デバイス</translation>
+<translation id="6071091556643036997">ポリシーのタイプが無効です。</translation>
<translation id="6080696365213338172">管理者が提供する証明書を使用してコンテンツにアクセスしています。<ph name="DOMAIN" /> に提供するデータは管理者によって傍受される可能性があります。</translation>
<translation id="610911394827799129">お使いの Google アカウントの <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> に、他の形式の閲覧履歴が記録されている場合があります</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{なし}=1{1 個のパスワード(同期済み)}other{# 個のパスワード(同期済み)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">他の情報を追加</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6451458296329894277">フォーム再送信の確認</translation>
+<translation id="6465306955648956876">パスワードを管理...</translation>
<translation id="647261751007945333">デバイス ポリシー</translation>
<translation id="6477321094435799029">このページで通常と異なるコードを検出したため、個人情報(例: パスワード、電話番号、クレジット カード番号)を保護するために、ページをブロックしました。</translation>
<translation id="6489534406876378309">クラッシュのアップロードを開始</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> 検索</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> では現在、悪意のあるユーザーによって、お使いの Mac 上に危険なプログラム(写真、パスワード、メッセージ、クレジット カードなどの情報を盗んだり削除したりするプログラム)がインストールされる可能性があります。<ph name="BEGIN_LEARN_MORE_LINK" />詳細<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">このポリシーは廃止されました。</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{なし}=1{1 件のサイトから(Google アカウントへのログイン状態は維持されます)}other{# 件のサイトから(Google アカウントへのログイン状態は維持されます)}}</translation>
<translation id="6657585470893396449">パスワード</translation>
<translation id="6671697161687535275">Chromium から候補を削除してもよろしいですか?</translation>
<translation id="6685834062052613830">ログアウトして設定を完了してください</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">ユーザー:</translation>
<translation id="6945221475159498467">選択</translation>
<translation id="6948701128805548767">受け取り方法と要件を確認するには、住所を選択してください</translation>
+<translation id="6949872517221025916">パスワードを再設定</translation>
<translation id="6957887021205513506">サーバーの証明書が偽造されたもののようです。</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">デバイス</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">配達方法</translation>
<translation id="7139724024395191329">管轄区域</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> 件)}other{<ph name="PAYMENT_METHOD_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> 件)}}</translation>
-<translation id="7155487117670177674">お支払い情報は保護されません</translation>
+<translation id="717330890047184534">GAIA ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> 件)}other{<ph name="SHIPPING_OPTION_PREVIEW" />(他 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> 件)}}</translation>
<translation id="7180611975245234373">更新</translation>
<translation id="7182878459783632708">ポリシーが設定されていません</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">グローバルのデフォルト値([ブロック])を使用</translation>
<translation id="7460163899615895653">他の端末で最近使ったタブがここに表示されます</translation>
<translation id="7469372306589899959">カードを確認中です</translation>
+<translation id="7473891865547856676">スキップ</translation>
<translation id="7481312909269577407">進む</translation>
<translation id="7485870689360869515">データが見つかりません。</translation>
<translation id="7508255263130623398">返されたポリシーの端末 ID が空であるか、現在の端末 ID と一致しません</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Chrome からクレジット カードを削除してもよろしいですか?</translation>
<translation id="7575800019233204241">「この接続ではプライバシーが保護されません」、「&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;」、「&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;」、「&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;」、「SSL 証明書エラー」</translation>
<translation id="7578104083680115302">どの端末でも、Google に保存したカードを使ってサイトやアプリの支払いをすばやく行うことができます。</translation>
-<translation id="7588950540487816470">フィジカルウェブ</translation>
<translation id="7592362899630581445">サーバーの証明書が名前の制約に違反しています。</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> 未満</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> では現在このリクエストを処理できません。</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">編集の取り消し(&amp;U)</translation>
<translation id="9154194610265714752">更新完了</translation>
<translation id="9157595877708044936">セットアップ中...</translation>
+<translation id="9168814207360376865">お支払い方法を保存しているかどうかの確認をサイトに許可する</translation>
<translation id="9169664750068251925">このサイトでは常にブロック</translation>
<translation id="9170848237812810038">取消(&amp;U)</translation>
<translation id="917450738466192189">サーバーの証明書が無効です。</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">記事を追加できませんでした。</translation>
<translation id="9215416866750762878">アプリケーションが原因で、Chrome からこのサイトに安全に接続することができません</translation>
<translation id="9219103736887031265">画像</translation>
-<translation id="933612690413056017">インターネット接続がありません</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">フォームをクリア</translation>
<translation id="939736085109172342">新しいフォルダ</translation>
diff --git a/chromium/components/strings/components_strings_kn.xtb b/chromium/components/strings/components_strings_kn.xtb
index c79a077ba0d..eb757427ee1 100644
--- a/chromium/components/strings/components_strings_kn.xtb
+++ b/chromium/components/strings/components_strings_kn.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> ಗಾಗಿ ಅನುಮತಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ</translation>
<translation id="1111153019813902504">ಇತ್ತೀಚಿನ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
<translation id="1113869188872983271">&amp;ಮರುಕ್ರಮಗೊಳಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
+<translation id="1125573121925420732">ವೆಬ್‌ಸೈಟ್‌ಗಳು ತಮ್ಮ ಸುರಕ್ಷತೆಯನ್ನು ಅಪ್‌ಡೇಟ್‌ ಮಾಡುವಾಗ, ಸಾಮಾನ್ಯವಾಗಿ ಎಚ್ಚರಿಕೆಗಳು ಕಾಣಿಸಿಕೊಳ್ಳಬಹುದು. ಇದನ್ನು ಶೀಘ್ರದಲ್ಲೇ ಸುಧಾರಿಸಲಾಗುವುದು.</translation>
<translation id="1126551341858583091">ಸ್ಥಳೀಯ ಸಂಗ್ರಹಣೆಯಲ್ಲಿರುವ ಗಾತ್ರ <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">ನೀತಿಯ ಸಂಗ್ರಹ ಸರಿಯಾಗಿದೆ</translation>
<translation id="1150979032973867961">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರವು ನಿಮ್ಮ ಸಾಧನದ ಆಪರೇಟಿಂಗ್ ಸಿಸ್ಟಂ‌ ಪ್ರಕಾರ ವಿಶ್ವಾಸಾರ್ಹವಾಗಿಲ್ಲ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;ನಿಮ್ಮ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕ ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡುತ್ತಿದೆಯೇ ಎಂದು ನೋಡಿ.&lt;/li&gt;
&lt;li&gt;ವೆಬ್‌ಸೈಟ್‌ನ ಮಾಲೀಕರನ್ನು ಸಂಪರ್ಕಿಸಿ.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">ನೀವು ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ನಿರ್ವಹಣೆ ಮಾಡದ ಸೈಟ್‌ನಲ್ಲಿ ನಮೂದಿಸಿದ್ದೀರಿ. ನಿಮ್ಮ ಖಾತೆಯನ್ನು ರಕ್ಷಿಸಲು, ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಲ್ಲಿ ಮತ್ತು ಸೈಟ್‌ಗಳಲ್ಲಿ ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಮರುಬಳಕೆ ಮಾಡಬೇಡಿ.</translation>
<translation id="1263231323834454256">ಓದುವ ಪಟ್ಟಿ</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> ನಲ್ಲಿ ಕ್ರ್ಯಾಶ್ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ (ಇನ್ನೂ ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗಿಲ್ಲ ಅಥವಾ ನಿರ್ಲಕ್ಷಿಸಲಾಗಿಲ್ಲ)</translation>
<translation id="1270502636509132238">ಪಿಕಪ್ ವಿಧಾನ</translation>
@@ -99,7 +101,6 @@
<translation id="1594030484168838125">ಆರಿಸಿ</translation>
<translation id="1620510694547887537">ಕ್ಯಾಮರಾ</translation>
<translation id="1623104350909869708">ಹೆಚ್ಚುವರಿ ಸಂವಾದಗಳನ್ನು ರಚಿಸದಂತೆ ಈ ಪುಟವನ್ನು ತಡೆಯಿರಿ</translation>
-<translation id="1629803312968146339">ಈ ಕಾರ್ಡ್ ಅನ್ನು Chrome ಉಳಿಸಬೇಕೆಂದು ನೀವು ಬಯಸುವಿರಾ?</translation>
<translation id="1639239467298939599">ಲೋಡ್ ಆಗುತ್ತಿದೆ</translation>
<translation id="1640180200866533862">ಬಳಕೆದಾರನ ನೀತಿಗಳು</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />ಸೈಟ್‌ನ ಮುಖಪುಟಕ್ಕೆ ಭೇಟಿ ನೀಡಲು<ph name="END_LINK" /> ಪ್ರಯತ್ನಿಸಿ.</translation>
@@ -127,7 +128,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows ನೆಟ್‌ವರ್ಕ್ ಡಯಾಗ್ನಾಸ್ಟಿಕ್ಸ್‌ ರನ್ ಮಾಡಲು ಪ್ರಯತ್ನಿಸಿ‌<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">ದಯವಿಟ್ಟು ನಿಮ್ಮ ಸಿಂಕ್ ಪಾಸ್‌ಫ್ರೇಸ್ ಅನ್ನು ನವೀಕರಿಸಿ.</translation>
<translation id="1787142507584202372">ನಿಮ್ಮ ತೆರೆಯಲಾದ ಟ್ಯಾಬ್‌ಗಳು ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತದೆ</translation>
-<translation id="1789575671122666129">ಪಾಪ್‌ಅಪ್‌ಗಳು</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">ಕಾರ್ಡ್‌ಹೋಲ್ಡರ್ ಹೆಸರು</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" /> ಸೇರಿಸಲಾಗಿದೆ</translation>
@@ -170,7 +170,6 @@
<translation id="2108755909498034140">ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್ ಮರುಪ್ರಾರಂಭಿಸಿ</translation>
<translation id="2113977810652731515">ಕಾರ್ಡ್</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ರಿಂದ ಅತಿಕ್ರಮಿಸಲಾಗಿರುವ ಕಾರಣ ಇದನ್ನು ನಿರ್ಲಕ್ಷಿಸಲಾಗಿದೆ.</translation>
-<translation id="2138201775715568214">ಹತ್ತಿರದ ಪ್ರತ್ಯಕ್ಷ ವೆಬ್ ಪುಟಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ</translation>
<translation id="213826338245044447">ಮೊಬೈಲ್ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
<translation id="214556005048008348">ಪಾವತಿಯನ್ನು ರದ್ದುಮಾಡಿ</translation>
<translation id="2147827593068025794">ಹಿನ್ನೆಲೆ ಸಿಂಕ್</translation>
@@ -187,6 +186,7 @@
<translation id="2212735316055980242">ನೀತಿ ಕಂಡು ಬಂದಿಲ್ಲ</translation>
<translation id="2213606439339815911">ನಮೂದುಗಳನ್ನು ಪಡೆಯಲಾಗುತ್ತಿದೆ...</translation>
<translation id="2218879909401188352">ದಾಳಿಕೋರರು ಪ್ರಸ್ತುತ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನಲ್ಲಿದ್ದಾರೆ ಮತ್ತು ನಿಮ್ಮ ಸಾಧನಕ್ಕೆ ಹಾನಿಯನ್ನುಂಟು ಮಾಡುವ ಅಪಾಯಕಾರಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಸ್ಥಾಪಿಸಬಹುದು, ನಿಮ್ಮ ಮೊಬೈಲ್ ಬಿಲ್‌ಗೆ ಮರೆಮಾಡಿದ ಶುಲ್ಕಗಳನ್ನು ಸೇರಿಸಬಹುದು, ಅಥವಾ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಕದಿಯಬಹುದು. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ಡಯಾಗ್ನಸ್ಟಿಕ್ಸ್‌‌ ಅಪ್ಲಿಕೇಶನ್‌<ph name="END_LINK" /> ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಸಂಪರ್ಕವನ್ನು ಸರಿಪಡಿಸಿ</translation>
<translation id="2239100178324503013">ಈಗ ಕಳುಹಿಸಿ</translation>
<translation id="225207911366869382">ಈ ನೀತಿಗಾಗಿ ಈ ಮೌಲ್ಯವನ್ನು ಅಸಮ್ಮತಿಸಲಾಗಿದೆ.</translation>
@@ -261,6 +261,7 @@
<translation id="2742870351467570537">ಆಯ್ಕೆಮಾಡಿದ ಐಟಂಗಳನ್ನು ತೆಗೆದುಹಾಕಿ</translation>
<translation id="277133753123645258">ಶಿಪ್ಪಿಂಗ್ ವಿಧಾನ</translation>
<translation id="277499241957683684">ಸಾಧನದ ರೆಕಾರ್ಡ್ ಕಾಣೆಯಾಗಿದೆ</translation>
+<translation id="2781030394888168909">MacOS ಅನ್ನು ರಫ್ತು ಮಾಡಿ</translation>
<translation id="2784949926578158345">ಸಂಪರ್ಕವನ್ನು ರೀಸೆಟ್ ಮಾಡಲಾಗಿದೆ.</translation>
<translation id="2788784517760473862">ಸ್ವೀಕೃತ ಕ್ರೆಡಿಟ್‌ ಕಾರ್ಡ್‌ಗಳು</translation>
<translation id="2794233252405721443">ಸೈಟ್ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ</translation>
@@ -302,7 +303,6 @@
<translation id="3063697135517575841">ಈ ಸಮಯದಲ್ಲಿ Chrome ಗೆ ನಿಮ್ಮ ಕಾರ್ಡ್ ಅನ್ನು ಖಚಿತಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ. ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="3064966200440839136">ಬಾಹ್ಯ ಅಪ್ಲಿಕೇಶನ್‌‌ ಮೂಲಕರ ಪಾವತಿಸಲು ಅದೃಶ್ಯ ಮೋಡ್‌‌ ತೊರೆಯಲಾಗುತ್ತಿದೆ. ಮುಂದುವರಿಸುವುದೇ?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ಯಾವುದೂ ಇಲ್ಲ}=1{1 ಪಾಸ್‌ವರ್ಡ್‌}one{# ಪಾಸ್‌ವರ್ಡ್‌ಗಳು}other{# ಪಾಸ್‌ವರ್ಡ್‌ಗಳು}}</translation>
-<translation id="3093245981617870298">ನೀವು ಆಫ್‌ಲೈನ್‌ನಲ್ಲಿರುವಿರಿ.</translation>
<translation id="3096100844101284527">ಪಿಕಪ್ ವಿಳಾಸವನ್ನು ಸೇರಿಸಿ</translation>
<translation id="3105172416063519923">ಸ್ವತ್ತು ID:</translation>
<translation id="3109728660330352905">ಈ ಪುಟ ವೀಕ್ಷಿಸುವ ಅಧಿಕಾರ ನಿಮಗಿಲ್ಲ</translation>
@@ -359,6 +359,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ಅನ್ನು ಪ್ರಸ್ತುತ ತಲುಪಲಾಗುತ್ತಿಲ್ಲ.</translation>
<translation id="3427092606871434483">ಅನುಮತಿಸಿ (ಡಿಫಾಲ್ಟ್)</translation>
<translation id="3427342743765426898">&amp;ಸಂಪಾದಿಸುವುದನ್ನು ಮತ್ತೆಮಾಡು</translation>
+<translation id="342781501876943858">ನೀವು ಇತರ ಸೈಟ್‌ಗಳಲ್ಲಿ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಮರುಬಳಕೆ ಮಾಡಿದ್ದಲ್ಲಿ Chromium ನಿಮ್ಮ ಪಾಸವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲು ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ.</translation>
<translation id="3431636764301398940">ಈ ಸಾಧನಕ್ಕೆ ಈ ಕಾರ್ಡ್ ಉಳಿಸಿ</translation>
<translation id="3447661539832366887">ಈ ಸಾಧನದ ಮಾಲೀಕರು ಡೈನೊಸಾರ್ ಆಟವನ್ನು ಆಫ್ ಮಾಡಿದ್ದಾರೆ.</translation>
<translation id="3447884698081792621">ಪ್ರಮಾಣಪತ್ರವನ್ನು ತೋರಿಸಿ (<ph name="ISSUER" /> ಇವರಿಂದ ನೀಡಲಾಗಿದೆ)</translation>
@@ -394,7 +395,6 @@
<translation id="3678529606614285348">ಪುಟವನ್ನು ಹೊಸ ಅದೃಶ್ಯ ವಿಂಡೋದಲ್ಲಿ ತೆರೆಯಿರಿ (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> ನಲ್ಲಿ ಕ್ರ್ಯಾಶ್ ವರದಿಯನ್ನು ಸೆರೆಹಿಡಿಯಲಾಗಿದೆ, <ph name="UPLOAD_TIME" /> ಸಮಯಕ್ಕೆ ಅಪ್‌ಲೋಡ್ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="3681007416295224113">ಪ್ರಮಾಣಪತ್ರ ಮಾಹಿತಿ</translation>
-<translation id="3690164694835360974">ಲಾಗಿನ್ ಸುರಕ್ಷಿತವಾಗಿಲ್ಲ</translation>
<translation id="3704162925118123524">ನೀವು ಬಳಸುತ್ತಿರುವ ನೆಟ್‌ವರ್ಕ್‌ನ ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ಭೇಟಿ ನೀಡಬೇಕಾದ ಅಗತ್ಯವಿದೆ.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ಲೋಡ್ ಆಗುತ್ತಿದೆ...</translation>
@@ -454,7 +454,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">ಜಾಗತಿಕ ಡಿಫಾಲ್ಟ್ ಬಳಸಿ (ಪತ್ತೆ ಮಾಡಿ)</translation>
<translation id="4165986682804962316">ಸೈಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು</translation>
-<translation id="4169947484918424451">ಈ ಕಾರ್ಡ್ ಅನ್ನು Chromium ಉಳಿಸಬೇಕೆಂದು ನೀವು ಬಯಸುವಿರಾ?</translation>
<translation id="4171400957073367226">ತಪ್ಪು ಪರಿಶೀಲನೆ ಸಹಿ</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> ಹೆಚ್ಚಿನ ಐಟಂ}one{<ph name="ITEM_COUNT" /> ಹೆಚ್ಚಿನ ಐಟಂಗಳು}other{<ph name="ITEM_COUNT" /> ಹೆಚ್ಚಿನ ಐಟಂಗಳು}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -491,6 +490,7 @@
<translation id="4275830172053184480">ನಿಮ್ಮ ಸಾಧನವನ್ನು ಮರುಪ್ರಾರಂಭಿಸಿ</translation>
<translation id="4277028893293644418">ಪಾಸ್‌ವರ್ಡ್ ಮರುಹೊಂದಿಸಿ</translation>
<translation id="4280429058323657511">, ಅವಧಿ ಮುಕ್ತಾಯ <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">ಬದಲಿಸಿ</translation>
<translation id="4312866146174492540">ನಿರ್ಬಂಧಿಸು (ಡಿಫಾಲ್ಟ್)</translation>
<translation id="4325863107915753736">ಲೇಖನ ಕಂಡುಬರಲಿಲ್ಲ</translation>
<translation id="4326324639298822553">ನಿಮ್ಮ ಮುಕ್ತಾಯ ದಿನಾಂಕವನ್ನು ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</translation>
@@ -498,6 +498,7 @@
<translation id="4340982228985273705">ಈ ಕಂಪ್ಯೂಟರ್‌ ಅನ್ನು ಎಂಟರ್‌ಪ್ರೈಸ್ ನಿರ್ವಹಣೆ ಮಾಡುತ್ತಿದೆ ಎಂದು ಪತ್ತೆಹಚ್ಚಲಾಗಿಲ್ಲ, ಆದ್ದರಿಂದ ಕಾರ್ಯನೀತಿಯು Chrome ವೆಬ್‌ ಸ್ಟೋರ್‌ನಲ್ಲಿ ಹೋಸ್ಟ್ ಮಾಡಲಾದ ವಿಸ್ತರಣೆಗಳನ್ನು ಮಾತ್ರ ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಬಹುದು. Chrome ವೆಬ್‌ ಸ್ಟೋರ್‌ ಅಪ್‌ಡೇಟ್‌ URL "<ph name="CWS_UPDATE_URL" />" ಆಗಿರುತ್ತದೆ.</translation>
<translation id="4346197816712207223">ಸ್ವೀಕೃತ ಕ್ರೆಡಿಟ್‌ ಕಾರ್ಡ್‌ಗಳು</translation>
<translation id="4356973930735388585">ಈ ಸೈಟ್‌ನಲ್ಲಿರುವ ದಾಳಿಕೋರರು ನಿಮ್ಮ ಕಂಪ್ಯೂಟರ್‌ನಲ್ಲಿರುವ ಮಾಹಿತಿ (ಉದಾಹರಣೆಗೆ, ಫೋಟೋಗಳು, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು ಮತ್ತು ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಮಾಹಿತಿಗಳು) ಕದಿಯಲು ಇಲ್ಲವೇ ಅಳಿಸಲು ಅಪಾಯಕಾರಿ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಸ್ಥಾಪಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರಬಹುದು.</translation>
+<translation id="4358461427845829800">ಪಾವತಿ ವಿಧಾನಗಳನ್ನು ನಿರ್ವಹಿಸಿ...</translation>
<translation id="4372948949327679948">ನಿರೀಕ್ಷಿತ <ph name="VALUE_TYPE" /> ಮೌಲ್ಯ.</translation>
<translation id="4377125064752653719">ನೀವು <ph name="DOMAIN" /> ಅನ್ನು ತಲುಪಲು ಪ್ರಯತ್ನಿಸಿದಿರಿ, ಆದರೆ ಸರ್ವರ್ ನೀಡಿದ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಅದರ ನೀಡುವವರು ಹಿಂತೆಗೆದುಕೊಂಡಿದ್ದಾರೆ. ಇದರರ್ಥ ಸರ್ವರ್ ನೀಡಿದ ಸುರಕ್ಷತೆ ರುಜುವಾತುಗಳನ್ನು ಖಂಡಿತವಾಗಿ ನಂಬಲಾಗುವುದಿಲ್ಲ. ನೀವು ಆಕ್ರಮಣಕಾರರೊಂದಿಗೆ ಸಂವಹಿಸುತ್ತಿರಬಹುದು.</translation>
<translation id="4406896451731180161">ಹುಡುಕಾಟದ ಫಲಿತಾಂಶಗಳು</translation>
@@ -505,6 +506,7 @@
<translation id="4415426530740016218">ಪಿಕಪ್ ವಿಳಾಸ</translation>
<translation id="4424024547088906515">ಈ ಸರ್ವರ್ <ph name="DOMAIN" /> ಆಗಿದೆ ಎಂಬುದನ್ನು ಸಾಬೀತುಪಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ; ಅದರ ಸುರಕ್ಷತಾ ಪ್ರಮಾಣಪತ್ರವು Chrome ಪಾಲಿಗೆ ವಿಶ್ವಾಸಾರ್ಹವಾಗಿಲ್ಲ. ಇದು ತಪ್ಪು ಕಾನ್ಫಿಗರೇಶನ್‌ನಿಂದ ಅಥವಾ ಆಕ್ರಮಣಕಾರರು ನಿಮ್ಮ ಸಂಪರ್ಕದಲ್ಲಿ ಒಳನುಸುಳಿರುವುದರಿಂದ ಆಗಿರಬಹುದು.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ನಿಮ್ಮ ಲಾಗಿನ್ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಸ್ವೀಕರಿಸಲಿಲ್ಲ ಅಥವಾ ಅದನ್ನು ಒದಗಿಸದೆ ಇರಬಹುದು.</translation>
+<translation id="4434045419905280838">ಪಾಪ್-ಅಪ್‌ಗಳು ಹಾಗೂ ಮರುನಿರ್ದೇಶನಗಳು</translation>
<translation id="443673843213245140">ಪ್ರಾಕ್ಸಿಯ ಬಳಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ ಆದರೆ ಬಹಿರಂಗ ಪ್ರಾಕ್ಸಿ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸಲಾಗಿದೆ.</translation>
<translation id="445100540951337728">ಸಮ್ಮತಿಸಲಾದ ಡೆಬಿಟ್ ಕಾರ್ಡ್‌ಗಳು</translation>
<translation id="4506176782989081258">ಮೌಲ್ಯೀಕರಿಸುವಿಕೆಯ ದೋಷ: <ph name="VALIDATION_ERROR" /></translation>
@@ -539,13 +541,13 @@
<translation id="4759118997339041434">ಪಾವತಿ ಸ್ವಯಂ ಭರ್ತಿ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ</translation>
<translation id="4764776831041365478"><ph name="URL" /> ನಲ್ಲಿರುವ ವೆಬ್‌ಪುಟವು ತಾತ್ಕಾಲಿಕವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸದೇ ಇರಬಹುದು ಅಥವಾ ಅದನ್ನು ಶಾಶ್ವತವಾಗಿ ಹೊಸ ವೆಬ್ ವಿಳಾಸಕ್ಕೆ ಸರಿಸಲಾಗಿರಬಹುದು.</translation>
<translation id="4771973620359291008">ಅಪರಿಚಿತ ದೋಷವೊಂದು ಎದುರಾಗಿದೆ.</translation>
+<translation id="4785689107224900852">ಈ ಟ್ಯಾಬ್‌ಗೆ ಬದಲಾಯಿಸಿ</translation>
<translation id="4792143361752574037">ಸೆಶನ್ ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸುವಲ್ಲಿ ಸಮಸ್ಯೆ ಇದೆ. ಡಿಸ್ಕ್‌ಗೆ ಉಳಿಸುವುದು ಪ್ರಸ್ತುತ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಪುನಃ ಪ್ರಯತ್ನಿಸಲು ಪುಟವನ್ನು ಮರುಲೋಡ್ ಮಾಡಿ.</translation>
<translation id="4800132727771399293">ನಿಮ್ಮ ಮುಕ್ತಾಯದ ದಿನಾಂಕ ಮತ್ತು CVC ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">ನಿಮಗೆ ಸದ್ಯಕ್ಕೆ <ph name="SITE" /> ವೆಬ್‌ಸೈಟ್‌‌ಗೆ ಭೇಟಿ ನೀಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಏಕೆಂದರೆ, ಈ ವೆಬ್‌ಸೈಟ್‌‌ Google Chrome ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಸಾಧ್ಯವಾಗದಂಥ ರುಜುವಾತುಗಳನ್ನು ರವಾನಿಸಿದೆ. ನೆಟ್‌ವರ್ಕ್ ದೋಷಗಳು ಮತ್ತು ಆಕ್ರಮಣಗಳು ತಾತ್ಕಾಲಿಕವಾಗಿರುತ್ತವೆ. ಹೀಗಾಗಿ ಈ ಪುಟವು ಬಹುಶಃ ನಂತರ ಕಾರ್ಯ ನಿರ್ವಹಿಸಬಹುದು.</translation>
<translation id="4813512666221746211">ನೆಟ್‌ವರ್ಕ್ ದೋಷ</translation>
<translation id="4816492930507672669">ಪುಟಕ್ಕೆ ಹೊಂದಿಸು</translation>
-<translation id="483020001682031208">ತೋರಿಸಲು ಯಾವುದೇ ಬೌದ್ಧಿಕ ವೆಬ್ ಪುಟಗಳಿಲ್ಲ</translation>
<translation id="4850886885716139402">ವೀಕ್ಷಣೆ</translation>
<translation id="4854362297993841467">ಈ ವಿತರಣೆಯ ವಿಧಾನ ಲಭ್ಯವಿಲ್ಲ. ಬೇರೊಂದು ವಿಧಾನವನ್ನು ಪ್ರಯತ್ನಿಸಿ.</translation>
<translation id="4858792381671956233">ಈ ಸೈಟ್ ಅನ್ನು ಭೇಟಿ ಮಾಡಬಹುದು ಎಂದು ನಿಮ್ಮ ಪೋಷಕರಿಗೆ ನೀವು ಕೇಳಿರುವಿರಿ.</translation>
@@ -585,6 +587,7 @@
<translation id="5115563688576182185">(64-ಬಿಟ್)</translation>
<translation id="5121084798328133320">ನೀವು ಖಚಿತಪಡಿಸಿದ ನಂತರ, ನಿಮ್ಮ Google ಪಾವತಿಗಳ ಖಾತೆಯಿಂದ ಕಾರ್ಡ್ ವಿವರಗಳನ್ನು ಈ ಸೈಟ್ ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.</translation>
<translation id="5128122789703661928">ಈ ಹೆಸರಿನ ಸೆಶನ್ ಅಳಿಸಲು ಮಾನ್ಯವಾಗಿಲ್ಲ.</translation>
+<translation id="5135404736266831032">ವಿಳಾಸಗಳನ್ನು ನಿರ್ವಹಿಸಿ...</translation>
<translation id="5141240743006678641">ನಿಮ್ಮ Google ರುಜುವಾತುಗಳ ಜೊತೆಗೆ ಸಿಂಕ್ ಮಾಡಿದ ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ಎನ್‌ಕ್ರಿಫ್ಟ್ ಮಾಡಿ</translation>
<translation id="5145883236150621069">ನೀತಿ ಪ್ರತಿಕ್ರಿಯೆಯಲ್ಲಿ ದೋಷದ ಕೋಡ್ ಅಸ್ತಿತ್ವದಲ್ಲಿದೆ</translation>
<translation id="5159010409087891077">ಪುಟವನ್ನು ಹೊಸ ಅದೃಶ್ಯ ವಿಂಡೋದಲ್ಲಿ ತೆರೆಯಿರಿ (⇧⌘N)</translation>
@@ -596,7 +599,6 @@
<translation id="5201306358585911203">ಈ ಪುಟದಲ್ಲಿ ಎಂಬೆಡ್ ಮಾಡಲಾದ ಪುಟವು ಹೀಗೆ ಹೇಳುತ್ತದೆ</translation>
<translation id="5205222826937269299">ಹೆಸರು ಅವಶ್ಯವಾಗಿದೆ</translation>
<translation id="5222812217790122047">ಇಮೇಲ್ ಅಗತ್ಯವಿದೆ</translation>
-<translation id="522700295135997067">ಈ ಸೈಟ್‌ ಕಳವು ಮಾಡಿರುವ ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಹೊಂದಿರಬಹುದು</translation>
<translation id="5230733896359313003">ಶಿಪ್ಪಿಂಗ್ ವಿಳಾಸ</translation>
<translation id="5250209940322997802">"ನೆಟ್‌ವರ್ಕ್‌ಗೆ ಸಂಪರ್ಕಿಸಿ"</translation>
<translation id="5251803541071282808">ಮೇಘ</translation>
@@ -639,7 +641,6 @@
<translation id="5492298309214877701">ಬಾಹ್ಯ ವೆಬ್‌ಸೈಟ್‌‌ನ URL ಅನ್ನೇ ಕಂಪನಿ, ಸಂಸ್ಥೆ ಅಥವಾ ಶಾಲೆಯ ಇಂಟ್ರಾನೆಟ್‌ನಲ್ಲಿನ ಈ ಸೈಟ್ ಹೊಂದಿದೆ.
<ph name="LINE_BREAK" />
ನಿಮ್ಮ ಸಿಸ್ಟಂ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಲು ಪ್ರಯತ್ನಿಸಿ.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> ಗೆ ಸುರಕ್ಷತೆ ಕೋಡ್‌ ಅನ್ನು ನಮೂದಿಸಿ. ಈ ಕೋರ್ಡ್‌ ಅನ್ನು ಉಳಿಸಲಾಗುವುದಿಲ್ಲ.</translation>
<translation id="5509780412636533143">ನಿರ್ವಹಿಸಿದ ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳು</translation>
<translation id="5510766032865166053">ಈ ಫೈಲನ್ನು ಬೇರೆಡೆಗೆ ಸರಿಸಿರಬಹುದು ಇಲ್ಲವೇ ಅಳಿಸಿರಬಹುದು.</translation>
<translation id="5523118979700054094">ನೀತಿ ಹೆಸರು</translation>
@@ -670,9 +671,11 @@
<translation id="5685654322157854305">ಶಿಪ್ಪಿಂಗ್ ವಿಳಾಸವನ್ನು ಸೇರಿಸಿ</translation>
<translation id="5689199277474810259">JSON ಗೆ ರಫ್ತು ಮಾಡಿ</translation>
<translation id="5689516760719285838">ಸ್ಥಳ</translation>
+<translation id="570530837424789914">ನಿರ್ವಹಿಸಿ...</translation>
<translation id="5710435578057952990">ಈ ವೆಬ್‌ಸೈಟ್‌ನ ಗುರುತಿಸುವಿಕೆಯನ್ನು ಇನ್ನೂ ಪರಿಶೀಲಿಸಲಾಗಿಲ್ಲ.</translation>
<translation id="5719499550583120431">ಪ್ರೀಪೇಯ್ಡ್ ಕಾರ್ಡ್‌ಗಳನ್ನು ಸಮ್ಮತಿಸಲಾಗಿದೆ.</translation>
<translation id="5720705177508910913">ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ</translation>
+<translation id="5730040223043577876">ನೀವು ಇತರ ಸೈಟ್‌ಗಳಲ್ಲಿ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಮರುಬಳಕೆ ಮಾಡಿದ್ದಲ್ಲಿ Chrome ನಿಮ್ಮ ಪಾಸವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲು ಶಿಫಾರಸು ಮಾಡುತ್ತದೆ.</translation>
<translation id="5732392974455271431">ನಿಮ್ಮ ಪೋಷಕರು ನಿಮಗಾಗಿ ಅದನ್ನು ಅನಿರ್ಬಂಧಿಸಬಹುದಾಗಿದೆ</translation>
<translation id="5763042198335101085">ಮಾನ್ಯವಾದ ಇಮೇಲ್ ವಿಳಾಸವನ್ನು ನಮೂದಿಸಿ</translation>
<translation id="5765072501007116331">ವಿತರಣೆಯ ವಿಧಾನಗಳು ಹಾಗೂ ಆವಶ್ಯಕತೆಗಳನ್ನು ನೋಡಲು, ಒಂದು ವಿಳಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ</translation>
@@ -696,9 +699,7 @@
<translation id="5959728338436674663">ಅಪಾಯಕಾರಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಸೈಟ್‌ಗಳ ಪತ್ತೆಗೆ ಸಹಾಯ ಮಾಡಲು Google ಗೆ ಕೆಲವು <ph name="BEGIN_WHITEPAPER_LINK" />ಸಿಸ್ಟಂ ಮಾಹಿತಿ ಮತ್ತು ಪುಟ ವಿಷಯ<ph name="END_WHITEPAPER_LINK" />ವನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಕಳುಹಿಸಿ. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">ಸಂಪರ್ಕ ಮಾಹಿತಿಯನ್ನು ಎಡಿಟ್ ಮಾಡಿ</translation>
<translation id="5967867314010545767">ಇತಿಹಾಸದಿಂದ ತೆಗೆದುಹಾಕಿ</translation>
-<translation id="5972020793760134803">ಟ್ಯಾಬ್‌ಗಾಗಿ ಬದಲಿಸಿ</translation>
<translation id="5975083100439434680">ಝೂಮ್ ಔಟ್</translation>
-<translation id="597552863672748783">ಸುರಕ್ಷತೆ ಕೋಡ್ ಅನ್ನು ದೃಢೀಕರಿಸಿ</translation>
<translation id="598637245381783098">ಪಾವತಿ ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಲು ಸಾಧ್ಯವಿಲ್ಲ</translation>
<translation id="5989320800837274978">ಹೊಂದಿಸಿದ ಪ್ರಾಕ್ಸಿ ಸರ್ವರ್‌ಗಳು ಆಗಲಿ ಅಥವಾ .pac ಸ್ಕ್ರಿಪ್ಟ್ URL ಅನ್ನು ನಿರ್ದಿಷ್ಟಪಡಿಸಿಲ್ಲ.</translation>
<translation id="5990559369517809815">ಸರ್ವರ್‌ಗಳ ವಿನಂತಿಗಳನ್ನು ವಿಸ್ತರಣೆಯಿಂದ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ.</translation>
@@ -714,6 +715,7 @@
<translation id="6047927260846328439">ಈ ಕಂಟೆಂಟ್‌ ಸಾಫ್ಟ್‌ವೇರ್ ಸ್ಥಾಪಿಸುವಂತೆ ಅಥವಾ ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು ಬಹಿರಂಗಪಡಿಸುವಂತೆ ನಿಮ್ಮನ್ನು ಮೋಸಗೊಳಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರಬಹುದು. <ph name="BEGIN_LINK" />ಹೇಗಿದ್ದರೂ ತೋರಿಸಿ<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ನೀವು ಸದ್ಯಕ್ಕೆ <ph name="SITE" /> ಗೆ ಭೇಟಿ ನೀಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಏಕೆಂದರೆ, ವೆಬ್‌ಸೈಟ್ ಪ್ರಮಾಣಪತ್ರ ಪಿನ್ ಮಾಡುವಿಕೆಯನ್ನು ಬಳಸುತ್ತದೆ. ನೆಟ್‌ವರ್ಕ್ ದೋಷಗಳು ಮತ್ತು ಆಕ್ರಮಣಗಳು ತಾತ್ಕಾಲಿಕವಾಗಿರುತ್ತವೆ, ಹೀಗಾಗಿ ಈ ಪುಟವು ಸ್ವಲ್ಪ ಸಮಯದ ನಂತರ ಕಾರ್ಯ ನಿರ್ವಹಿಸಬಹುದು.</translation>
<translation id="6059925163896151826">USB ಸಾಧನಗಳು</translation>
+<translation id="6071091556643036997">ಕಾರ್ಯನೀತಿಯ ವಿಧ ಅಮಾನ್ಯವಾಗಿದೆ.</translation>
<translation id="6080696365213338172">ನಿರ್ವಾಹಕರು-ಒದಗಿಸಿದ ಪ್ರಮಾಣಪತ್ರವನ್ನು ಬಳಸಿಕೊಂಡು ನೀವು ವಿಷಯವನ್ನು ಪ್ರವೇಶಿಸಿರುವಿರಿ. <ph name="DOMAIN" /> ಗೆ ನೀವು ಒದಗಿಸುವ ಡೇಟಾವನ್ನು ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ತಡೆಹಿಡಿಯಬಹುದಾಗಿದೆ.</translation>
<translation id="610911394827799129">ನಿಮ್ಮ Google ಖಾತೆಯು <ph name="BEGIN_LINK" />history.google.com<ph name="END_LINK" /> ನಲ್ಲಿ ಇತರ ವಿಧಗಳ ಬ್ರೌಸಿಂಗ್ ಇತಿಹಾಸವನ್ನು ಹೊಂದಿರಬಹುದು</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ಯಾವುದೂ ಇಲ್ಲ}=1{1 ಪಾಸ್‌ವರ್ಡ್ (ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆ)}one{# ಪಾಸ್‌ವರ್ಡ್‌ಗಳು (ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆ)}other{# ಪಾಸ್‌ವರ್ಡ್‌ಗಳು (ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆ)}}</translation>
@@ -760,6 +762,7 @@
<translation id="6446608382365791566">ಇನ್ನಷ್ಟು ಮಾಹಿತಿಯನ್ನು ಸೇರಿಸಿ</translation>
<translation id="6447842834002726250">ಕುಕೀಸ್</translation>
<translation id="6451458296329894277">ಮರುಸಲ್ಲಿಕೆ ಫಾರ್ಮ್ ಅನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ</translation>
+<translation id="6465306955648956876">ಪಾಸ್‌ವರ್ಡ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ...</translation>
<translation id="647261751007945333">ಸಾಧನ ನೀತಿಗಳು</translation>
<translation id="6477321094435799029">ಈ ಪುಟದಲ್ಲಿ ಅಸಹಜ ಕೋಡ್ ಅನ್ನು Chrome ಪತ್ತೆಹಚ್ಚಿದೆ ಮತ್ತು ನಿಮ್ಮ ವೈಯಕ್ತಿಕ ಮಾಹಿತಿಯನ್ನು (ಉದಾಹರಣೆಗೆ, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಫೋನ್‌ ಸಂಖ್ಯೆಗಳು ಮತ್ತು ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್‌ಗಳು) ರಕ್ಷಿಸಲು ಅದನ್ನು ನಿರ್ಬಂಧಿಸಿದೆ.</translation>
<translation id="6489534406876378309">ವಿಫಲತೆಗಳನ್ನು ಅಪ್‌ಲೋಡ್‌ ಮಾಡುವುದನ್ನು ಪ್ರಾರಂಭಿಸು</translation>
@@ -779,6 +782,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> ಹುಡುಕಾಟ</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ನ ದಾಳಿಕೋರರು ನಿಮ್ಮ Macನಲ್ಲಿ ಮಾಹಿತಿಯನ್ನು (ಉದಾಹರಣೆಗೆ, ಫೋಟೋಗಳು, ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ಮಾಹಿತಿಗಳು) ಕದಿಯಲು ಇಲ್ಲವೇ ಅಳಿಸಲು ಅಪಾಯಕಾರಿ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಸ್ಥಾಪಿಸಲು ಪ್ರಯತ್ನಿಸುತ್ತಿರಬಹುದು. <ph name="BEGIN_LEARN_MORE_LINK" />ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">ಈ ನೀತಿಯನ್ನು ವಿನಂತಿಸಲಾಗಿದೆ.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{ಯಾವುದೂ ಇಲ್ಲ}=1{1 ಸೈಟ್‌‍ನಿಂದ (ನಿಮ್ಮ Google ಖಾತೆಯಿಂದ ನಿಮ್ಮನ್ನು ಸೈನ್ ಔಟ್ ಮಾಡುವುದಿಲ್ಲ)}one{# ಸೈಟ್‌ಗಳಿಂದ (ನಿಮ್ಮ Google ಖಾತೆಯಿಂದ ನಿಮ್ಮನ್ನು ಸೈನ್ ಔಟ್ ಮಾಡುವುದಿಲ್ಲ)}other{# ಸೈಟ್‌ಗಳಿಂದ (ನಿಮ್ಮ Google ಖಾತೆಯಿಂದ ನಿಮ್ಮನ್ನು ಸೈನ್ ಔಟ್ ಮಾಡುವುದಿಲ್ಲ)}}</translation>
<translation id="6657585470893396449">ಪಾಸ್‌ವರ್ಡ್</translation>
<translation id="6671697161687535275">Chromium ನಿಂದ ಫಾರ್ಮ್ ಸಲಹೆಯನ್ನು ತೆಗೆದುಹಾಕುವುದೇ?</translation>
<translation id="6685834062052613830">ಸೈನ್‌ ಔಟ್‌ ಮಾಡಿ ಹಾಗೂ ಸೆಟಪ್ ಪೂರ್ಣಗೊಳಿಸಿ</translation>
@@ -805,6 +809,7 @@
<translation id="6915804003454593391">ಬಳಕೆದಾರ:</translation>
<translation id="6945221475159498467">ಆಯ್ಕೆಮಾಡಿ</translation>
<translation id="6948701128805548767">ಪಿಕಪ್ ವಿಧಾನಗಳು ಹಾಗೂ ಆವಶ್ಯಕತೆಗಳನ್ನು ನೋಡಲು, ಒಂದು ವಿಳಾಸವನ್ನು ಆಯ್ಕೆ ಮಾಡಿ</translation>
+<translation id="6949872517221025916">ಪಾಸ್‌ವರ್ಡ್ ಮರುಹೊಂದಿಸಿ</translation>
<translation id="6957887021205513506">ಸರ್ವರ್‌ಗಳ ಪ್ರಮಾಣಪತ್ರವು ನಕಲಿಯಾಗಿ ಗೋಚರಿಸುತ್ತದೆ.</translation>
<translation id="6965382102122355670">ಸರಿ</translation>
<translation id="6965978654500191972">ಸಾಧನ</translation>
@@ -826,7 +831,7 @@
<translation id="7138472120740807366">ವಿತರಣೆ ವಿಧಾನ</translation>
<translation id="7139724024395191329">ಎಮಿರೇಟ್</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ಇನ್ನಷ್ಟು}one{<ph name="PAYMENT_METHOD_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ಇನ್ನಷ್ಟು}other{<ph name="PAYMENT_METHOD_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ಇನ್ನಷ್ಟು}}</translation>
-<translation id="7155487117670177674">ಪಾವತಿ ಸುರಕ್ಷಿತವಾಗಿಲ್ಲ</translation>
+<translation id="717330890047184534">Gaia ಐಡಿ:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ಇನ್ನಷ್ಟು}one{<ph name="SHIPPING_OPTION_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ಇನ್ನಷ್ಟು}other{<ph name="SHIPPING_OPTION_PREVIEW" /> ಮತ್ತು <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ಇನ್ನಷ್ಟು}}</translation>
<translation id="7180611975245234373">ರಿಫ್ರೆಶ್ ಮಾಡಿ</translation>
<translation id="7182878459783632708">ಯಾವುದೇ ನೀತಿಗಳನ್ನು ಹೊಂದಿಸಿಲ್ಲ</translation>
@@ -874,6 +879,7 @@
<translation id="7455133967321480974">ಜಾಗತಿಕ ಡಿಫಾಲ್ಟ್ ಬಳಸಿ (ನಿರ್ಬಂಧಿಸಿ)</translation>
<translation id="7460163899615895653">ಇತರ ಸಾಧನಗಳಿಂದ ನಿಮ್ಮ ಇತ್ತೀಚಿನ ಟ್ಯಾಬ್‌ಗಳು ಇಲ್ಲಿ ಗೋಚರಿಸುತ್ತವೆ</translation>
<translation id="7469372306589899959">ಕಾರ್ಡ್‌ ದೃಢೀಕರಿಸಲಾಗುತ್ತಿದೆ</translation>
+<translation id="7473891865547856676">ಇಲ್ಲ, ಧನ್ಯವಾದಗಳು</translation>
<translation id="7481312909269577407">ಫಾರ್ವರ್ಡ್</translation>
<translation id="7485870689360869515">ಯಾವುದೇ ಡೇಟಾ ಕಂಡುಬಂದಿಲ್ಲ.</translation>
<translation id="7508255263130623398">ಹಿಂತಿರುಗಿಸಲಾದ ನೀತಿಯ ಸಾಧನ ಐಡಿ ಖಾಲಿ ಇದೆ ಅಥವಾ ಪ್ರಸ್ತುತ ಸಾಧನ ಐಡಿಗೆ ಹೊಂದಾಣಿಕೆಯಾಗುವುದಿಲ್ಲ</translation>
@@ -896,7 +902,6 @@
<translation id="7569952961197462199">Chrome ನಿಂದ ಕ್ರೆಡಿಟ್ ಕಾರ್ಡ್ ತೆಗೆದುಹಾಕುವುದೇ?</translation>
<translation id="7575800019233204241">"ನಿಮ್ಮ ಸಂಪರ್ಕವು ಖಾಸಗಿಯಲ್ಲ" ಅಥವಾ "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" ಅಥವಾ "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" ಅಥವಾ "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" ಅಥವಾ "SSL ಪ್ರಮಾಣಪತ್ರ ದೋಷ"</translation>
<translation id="7578104083680115302">Google ನೊಂದಿಗೆ ನೀವು ಉಳಿಸಲಾದ ಕಾರ್ಡ್‌ಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಸಾಧನಗಳಾದ್ಯಂತ ಸೈಟ್‌ಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್‌ಗಳಲ್ಲಿ ತ್ವರಿತವಾಗಿ ಪಾವತಿಸಿ.</translation>
-<translation id="7588950540487816470">ಭೌತಿಕ ವೆಬ್</translation>
<translation id="7592362899630581445">ಸರ್ವರ್ ಪ್ರಮಾಣಪತ್ರವು ಹೆಸರಿನ ನಿರ್ಬಂಧನೆಗಳನ್ನು ಉಲ್ಲಂಘಿಸುತ್ತದೆ.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> ಗಿಂತ ಕಡಿಮೆ</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ಗೆ ಪ್ರಸ್ತುತ ಈ ವಿನಂತಿಯನ್ನು ನಿರ್ವಹಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ.</translation>
@@ -1100,6 +1105,7 @@
<translation id="9148507642005240123">&amp;ಸಂಪಾದಿಸುವುದನ್ನು ರದ್ದುಗೊಳಿಸಿ</translation>
<translation id="9154194610265714752">ಅಪ್‌ಡೇಟ್‌ ಮಾಡಲಾಗಿದೆ</translation>
<translation id="9157595877708044936">ಹೊಂದಿಸಲಾಗುತ್ತಿದೆ...</translation>
+<translation id="9168814207360376865">ನೀವು ಪಾವತಿ ವಿಧಾನಗಳನ್ನು ಉಳಿಸಿದಲ್ಲಿ ಪರಿಶೀಲಿಸಲು ಸೈಟ್‌ಗಳನ್ನು ಅನುಮತಿಸಿ</translation>
<translation id="9169664750068251925">ಈ ಸೈಟ್ ಅನ್ನು ಯಾವಾಗಲೂ ನಿರ್ಬಂಧಿಸು</translation>
<translation id="9170848237812810038">&amp;ರದ್ದುಮಾಡು</translation>
<translation id="917450738466192189">ಸರ್ವರ್‌ನ ಪ್ರಮಾಣಪತ್ರವು ಅಮಾನ್ಯವಾಗಿದೆ.</translation>
@@ -1108,7 +1114,6 @@
<translation id="9207861905230894330">ಲೇಖನವನ್ನು ಸೇರಿಸಲು ವಿಫಲವಾಗಿದೆ.</translation>
<translation id="9215416866750762878">ಈ ಸೈಟ್‌ಗೆ ಸುರಕ್ಷಿತವಾಗಿ ಸಂಪರ್ಕಿಸುವ Chromeನ ಕಾರ್ಯವನ್ನು ಅಪ್ಲಿಕೇಶನ್‌ ಸ್ಥಗಿತಗೊಳಿಸಿದೆ</translation>
<translation id="9219103736887031265">ಚಿತ್ರಗಳು</translation>
-<translation id="933612690413056017">ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ಫಾರ್ಮ್ ತೆರವುಗೊಳಿಸಿ</translation>
<translation id="939736085109172342">ಹೊಸ ಫೋಲ್ಡರ್</translation>
diff --git a/chromium/components/strings/components_strings_ko.xtb b/chromium/components/strings/components_strings_ko.xtb
index 17455d72127..a3a577dba6b 100644
--- a/chromium/components/strings/components_strings_ko.xtb
+++ b/chromium/components/strings/components_strings_ko.xtb
@@ -12,7 +12,7 @@
<translation id="10614374240317010">저장되지 않음</translation>
<translation id="1066396345355680611"><ph name="SITE" /> 및 기타 일부 사이트의 보호된 콘텐츠에 액세스하지 못할 수 있습니다.</translation>
<translation id="106701514854093668">데스크톱 북마크</translation>
-<translation id="1074497978438210769">안전하지 않음</translation>
+<translation id="1074497978438210769">주의 요함</translation>
<translation id="1080116354587839789">너비에 맞춤</translation>
<translation id="1088860948719068836">카드 명의 추가</translation>
<translation id="1103523840287552314"><ph name="LANGUAGE" /> 항상 번역</translation>
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> 권한을 선택합니다</translation>
<translation id="1111153019813902504">최근 북마크</translation>
<translation id="1113869188872983271">재정렬 실행 취소(&amp;U)</translation>
+<translation id="1125573121925420732">웹사이트에서 보안을 업데이트하는 동안에는 경고가 자주 발생할 수 있습니다. 곧 개선될 것입니다.</translation>
<translation id="1126551341858583091">로컬 저장소는 <ph name="CRASH_SIZE" />입니다.</translation>
<translation id="112840717907525620">정책 캐시 확인</translation>
<translation id="1150979032973867961">이 서버가 <ph name="DOMAIN" />임을 입증할 수 없으며 컴퓨터의 운영체제에서 신뢰하는 보안 인증서가 아닙니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;인터넷 연결에 문제가 없는지 확인합니다.&lt;/li&gt;
&lt;li&gt;웹사이트 소유자에게 문의합니다.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">조직에서 관리하지 않는 사이트에 내 비밀번호를 입력했습니다. 계정을 안전하게 보호하려면 다른 앱과 사이트에서 동일한 비밀번호를 재사용하지 마세요.</translation>
<translation id="1263231323834454256">읽기 목록</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />에 캡처된 비정상 종료 보고서(아직 업로드 또는 무시되지 않음)</translation>
<translation id="1270502636509132238">픽업 방법</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">선택</translation>
<translation id="1620510694547887537">카메라</translation>
<translation id="1623104350909869708">이 페이지가 추가적인 대화를 생성하지 않도록 차단</translation>
-<translation id="1629803312968146339">Chrome에서 이 카드를 저장하도록 하시겠습니까?</translation>
<translation id="1639239467298939599">로드 중</translation>
<translation id="1640180200866533862">사용자 정책</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />사이트의 홈페이지를 방문<ph name="END_LINK" />해 보세요.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows 네트워크 진단 프로그램을 실행<ph name="END_LINK" />해 보세요.</translation>
<translation id="1783075131180517613">동기화 암호를 업데이트하세요.</translation>
<translation id="1787142507584202372">열린 탭이 여기에 표시됩니다.</translation>
-<translation id="1789575671122666129">팝업</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">카드 소유자 이름</translation>
<translation id="1806541873155184440">추가일: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">컴퓨터 다시 시작</translation>
<translation id="2113977810652731515">카드</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" />이(가) 우선 적용되었기 때문에 무시됩니다.</translation>
-<translation id="2138201775715568214">주변 피지컬 웹페이지 검색 중</translation>
<translation id="213826338245044447">모바일 북마크</translation>
<translation id="214556005048008348">결제 취소</translation>
<translation id="2147827593068025794">백그라운드 동기화</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">정책을 찾을 수 없음</translation>
<translation id="2213606439339815911">항목을 가져오는 중...</translation>
<translation id="2218879909401188352">현재 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />에 있는 공격자는 기기를 손상시키거나, 모바일 요금에 몰래 추가 요금을 부과하거나, 개인정보를 도용하는 위험한 앱을 설치할 수도 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />자세히 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">인터넷 연결 없음</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />진단 앱<ph name="END_LINK" />을 사용하여 연결 문제를 해결하세요.</translation>
<translation id="2239100178324503013">지금 보내기</translation>
<translation id="225207911366869382">이 값은 이 정책에 사용되지 않습니다.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">선택한 항목 삭제</translation>
<translation id="277133753123645258">배송 방법</translation>
<translation id="277499241957683684">기기 기록 없음</translation>
+<translation id="2781030394888168909">MacOS 내보내기</translation>
<translation id="2784949926578158345">연결이 재설정되었습니다.</translation>
<translation id="2788784517760473862">사용 가능한 신용카드</translation>
<translation id="2794233252405721443">차단된 사이트</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">현재 Chrome에서 카드를 확인할 수 없습니다. 나중에 다시 시도해 주세요.</translation>
<translation id="3064966200440839136">시크릿 모드를 종료하고 외부 애플리케이션에서 결제합니다. 계속하시겠습니까?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{없음}=1{비밀번호 1개}other{비밀번호 #개}}</translation>
-<translation id="3093245981617870298">오프라인 상태입니다.</translation>
<translation id="3096100844101284527">수령 주소 추가</translation>
<translation id="3105172416063519923">애셋 ID:</translation>
<translation id="3109728660330352905">이 페이지를 볼 수 있는 권한이 없습니다.</translation>
@@ -340,7 +340,7 @@
<translation id="3303855915957856445">검색결과 없음</translation>
<translation id="3305707030755673451"><ph name="TIME" />에 동기화 암호로 데이터가 암호화되었습니다. 동기화를 시작하려면 입력하세요.</translation>
<translation id="3320021301628644560">청구지 주소 추가</translation>
-<translation id="3338095232262050444">안전함</translation>
+<translation id="3338095232262050444">보안 연결</translation>
<translation id="3340978935015468852">설정</translation>
<translation id="3345135638360864351">이 사이트에 대한 액세스 요청을 <ph name="NAME" />님에게 보내지 못했습니다. 나중에 다시 시도해 주세요.</translation>
<translation id="3355823806454867987">프록시 설정 변경...</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">현재 <ph name="HOST_NAME" />에 연결할 수 없습니다.</translation>
<translation id="3427092606871434483">허용(기본값)</translation>
<translation id="3427342743765426898">수정 다시 실행(&amp;R)</translation>
+<translation id="342781501876943858">다른 사이트에서 비밀번호를 재사용했다면 비밀번호를 재설정하는 것이 좋습니다.</translation>
<translation id="3431636764301398940">기기에 카드 저장</translation>
<translation id="3447661539832366887">이 기기의 소유자가 공룡 게임을 사용 중지했습니다.</translation>
<translation id="3447884698081792621">인증서 표시(발급 기관: <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">새 시크릿 창에서 페이지 열기(Ctrl-Shift-N)</translation>
<translation id="3679803492151881375"><ph name="CRASH_TIME" />에 캡처된 비정상 종료 보고서가 <ph name="UPLOAD_TIME" />에 업로드됨</translation>
<translation id="3681007416295224113">인증서 정보</translation>
-<translation id="3690164694835360974">로그인이 안전하지 않음</translation>
<translation id="3704162925118123524">사용 중인 네트워크에서 로그인 페이지 방문을 요청할 수 있습니다.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">로드 중...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">글로벌 기본값 사용(감지)</translation>
<translation id="4165986682804962316">사이트 설정</translation>
-<translation id="4169947484918424451">Chromium에서 이 카드를 저장하도록 하시겠습니까?</translation>
<translation id="4171400957073367226">잘못된 인증 서명입니다.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{그 외 <ph name="ITEM_COUNT" />개 항목}other{그 외 <ph name="ITEM_COUNT" />개 항목}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -486,7 +485,7 @@
&lt;p&gt;계속해서 오류가 표시되면 웹사이트 소유자에게 문의하세요.&lt;/p&gt;</translation>
<translation id="4226937834893929579"><ph name="BEGIN_LINK" />네트워크 진단 프로그램을 실행<ph name="END_LINK" />해 보세요.</translation>
<translation id="4235360514405112390">유효</translation>
-<translation id="4250431568374086873">이 사이트에 대한 연결은 완벽하게 보안이 되지 않습니다.</translation>
+<translation id="4250431568374086873">이 사이트의 보안 연결(HTTPS)은 완벽하지 않습니다.</translation>
<translation id="4250680216510889253">아니요</translation>
<translation id="425582637250725228">변경사항이 저장되지 않을 수 있습니다.</translation>
<translation id="4258748452823770588">잘못된 서명</translation>
@@ -495,13 +494,15 @@
<translation id="4275830172053184480">기기 다시 시작</translation>
<translation id="4277028893293644418">비밀번호 재설정</translation>
<translation id="4280429058323657511">, 만료일 <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">전환</translation>
<translation id="4312866146174492540">차단(기본값)</translation>
<translation id="4325863107915753736">도움말을 찾지 못했습니다.</translation>
<translation id="4326324639298822553">만료일을 확인한 후 다시 시도해 주세요.</translation>
-<translation id="4331708818696583467">안전하지 않음</translation>
+<translation id="4331708818696583467">주의 요함</translation>
<translation id="4340982228985273705">이 컴퓨터는 기업에서 관리하는 기기가 아닌 것으로 파악되므로, Chrome 웹 스토어에 호스팅된 확장 프로그램만 정책을 통해 자동으로 설치할 수 있습니다. Chrome 웹 스토어의 업데이트 URL은 '<ph name="CWS_UPDATE_URL" />'입니다.</translation>
<translation id="4346197816712207223">사용 가능한 신용카드</translation>
<translation id="4356973930735388585">이 사이트의 공격자가 사용자 정보(예: 사진, 비밀번호, 메시지, 신용카드)를 도용하거나 삭제하는 위험한 프로그램을 컴퓨터에 설치하려고 시도할 수 있습니다.</translation>
+<translation id="4358461427845829800">결제 수단 관리...</translation>
<translation id="4372948949327679948">예상 <ph name="VALUE_TYPE" /> 값입니다.</translation>
<translation id="4377125064752653719"><ph name="DOMAIN" />에 접속하려 했으나 발행기관에서 서버가 전달한 인증서를 폐기했습니다. 이는 서버가 제시한 보안 자격증명 정보를 신뢰할 수 없음을 의미합니다. 사용자는 현재 공격자와 통신 중일 수도 있습니다.</translation>
<translation id="4406896451731180161">검색결과</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">픽업 주소</translation>
<translation id="4424024547088906515">이 서버가 <ph name="DOMAIN" />임을 입증할 수 없으며 Chrome에서 신뢰하는 보안 인증서가 아닙니다. 서버를 잘못 설정했거나 불법 사용자가 연결을 가로채고 있기 때문일 수 있습니다.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" />에서 로그인 인증서를 승인하지 않았거나 로그인 인증서가 제공되지 않았을 수 있습니다.</translation>
+<translation id="4434045419905280838">팝업 및 리디렉션</translation>
<translation id="443673843213245140">프록시 사용은 중지되었지만 명시적 프록시 설정이 지정되어 있습니다.</translation>
<translation id="445100540951337728">사용 가능한 직불카드</translation>
<translation id="4506176782989081258">유효성 검사 오류 <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">결제 자동완성 사용 중지</translation>
<translation id="4764776831041365478"><ph name="URL" />의 웹페이지가 일시적으로 다운되었거나 새 웹 주소로 완전히 이동했을 수 있습니다.</translation>
<translation id="4771973620359291008">알 수 없는 오류가 발생했습니다.</translation>
+<translation id="4785689107224900852">이 탭으로 전환</translation>
<translation id="4792143361752574037">세션 파일에 액세스하는 중에 문제가 발생했습니다. 현재 디스크에 저장할 수 없습니다. 페이지를 새로고침하여 다시 시도하세요.</translation>
<translation id="4800132727771399293">유효기간과 CVC를 확인한 후 다시 시도해 주세요.</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">현재 <ph name="SITE" />에서 Chrome이 처리할 수 없는 암호화된 자격증명 정보를 전송했기 때문에 방문할 수 없습니다. 네트워크 오류와 공격은 대부분 일시적이므로 잠시 후 페이지가 정상화될 것입니다.</translation>
<translation id="4813512666221746211">네트워크 오류</translation>
<translation id="4816492930507672669">페이지 맞춤</translation>
-<translation id="483020001682031208">표시할 피지컬 웹 페이지가 없습니다.</translation>
<translation id="4850886885716139402">보기</translation>
<translation id="4854362297993841467">사용할 수 없는 배달 방법입니다. 다른 방법을 선택하세요.</translation>
<translation id="4858792381671956233">이 사이트를 방문해도 괜찮은지 부모님께 문의했습니다.</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64비트)</translation>
<translation id="5121084798328133320">카드를 확인하면 Google Payments 계정의 카드 세부정보가 이 사이트와 공유됩니다.</translation>
<translation id="5128122789703661928">세션 이름이 잘못되어 삭제할 수 없습니다.</translation>
+<translation id="5135404736266831032">주소 관리...</translation>
<translation id="5141240743006678641">동기화 비밀번호를 Google 자격증명으로 암호화</translation>
<translation id="5145883236150621069">정책 응답에 오류 코드가 포함되어 있음</translation>
<translation id="5159010409087891077">새 시크릿 창에서 페이지 열기(⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">이 페이지에 삽입된 페이지 내용:</translation>
<translation id="5205222826937269299">이름은 필수입니다.</translation>
<translation id="5222812217790122047">이메일은 필수입니다.</translation>
-<translation id="522700295135997067">이 사이트에서 비밀번호를 도용했을 수 있음</translation>
<translation id="5230733896359313003">배송지 주소</translation>
<translation id="5250209940322997802">'네트워크에 연결'</translation>
<translation id="5251803541071282808">클라우드</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">회사, 조직, 학교 인트라넷의 해당 사이트가 외부 웹사이트와 동일한 URL을 갖고 있습니다.
<ph name="LINE_BREAK" />
시스템 관리자에게 문의하세요.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" />의 보안 코드를 입력하세요. 이 코드는 저장되지 않습니다.</translation>
<translation id="5509780412636533143">관리 북마크</translation>
<translation id="5510766032865166053">이동되었거나 삭제되었을 수 있습니다.</translation>
<translation id="5523118979700054094">정책 이름</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">배송지 주소 추가</translation>
<translation id="5689199277474810259">JSON 형식으로 내보내기</translation>
<translation id="5689516760719285838">위치</translation>
+<translation id="570530837424789914">관리...</translation>
<translation id="5710435578057952990">이 웹사이트의 주소가 확인되지 않았습니다.</translation>
<translation id="5719499550583120431">선불카드를 사용할 수 있습니다.</translation>
<translation id="5720705177508910913">현재 사용자</translation>
+<translation id="5730040223043577876">다른 사이트에서 비밀번호를 재사용했다면 비밀번호를 재설정하는 것이 좋습니다.</translation>
<translation id="5732392974455271431">부모님이 차단 해제할 수 있습니다.</translation>
<translation id="5763042198335101085">올바른 이메일 주소를 입력하세요.</translation>
<translation id="5765072501007116331">배달 방법과 요구사항을 확인하려면 주소를 선택하세요.</translation>
@@ -689,7 +692,7 @@
<translation id="5803412860119678065"><ph name="CARD_DETAIL" />을(를) 입력하시겠습니까?</translation>
<translation id="5810442152076338065"><ph name="DOMAIN" />에 대한 연결이 더 이상 사용되지 않는 암호화 기술을 사용하여 암호화됩니다.</translation>
<translation id="5813119285467412249">추가 다시 실행(&amp;R)</translation>
-<translation id="5838278095973806738">공격자에 의해 도난당할 수 있으므로 이 사이트에 비밀번호나 신용카드 등 민감한 정보를 입력해서는 안 됩니다.</translation>
+<translation id="5838278095973806738">이 사이트에 입력하는 비밀번호나 신용카드 번호 등의 정보는 공격자에 의해 도난당할 수 있습니다.</translation>
<translation id="5866257070973731571">전화번호 추가</translation>
<translation id="5869405914158311789">사이트에 연결할 수 없음</translation>
<translation id="5869522115854928033">저장된 비밀번호</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">위험한 앱과 사이트를 감지할 수 있도록 일부 <ph name="BEGIN_WHITEPAPER_LINK" />시스템 정보와 페이지 콘텐츠<ph name="END_WHITEPAPER_LINK" />를 Google로 자동 전송합니다. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">연락처 정보 수정</translation>
<translation id="5967867314010545767">기록에서 삭제</translation>
-<translation id="5972020793760134803">탭으로 전환</translation>
<translation id="5975083100439434680">축소</translation>
-<translation id="597552863672748783">보안 코드 확인</translation>
<translation id="598637245381783098">결제 앱을 열 수 없습니다.</translation>
<translation id="5989320800837274978">고정 프록시 서버와 .pac 스크립트 URL이 모두 지정되지 않았습니다.</translation>
<translation id="5990559369517809815">서버에 대한 요청이 확장 프로그램에 의해 차단되었습니다.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">이 콘텐츠는 사용자를 속여 소프트웨어를 설치하거나 개인정보를 유출할 수도 있습니다. <ph name="BEGIN_LINK" />표시하기<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">현재 <ph name="SITE" />에서 인증서 고정을 사용하기 때문에 방문할 수 없습니다. 네트워크 오류와 공격은 대부분 일시적이므로 나중에 이 페이지가 정상적으로 작동할 수 있습니다.</translation>
<translation id="6059925163896151826">USB 기기</translation>
+<translation id="6071091556643036997">잘못된 정책 유형입니다.</translation>
<translation id="6080696365213338172">관리자 제공 인증서를 사용하여 콘텐츠에 액세스했습니다. 사용자가 <ph name="DOMAIN" />에 제공한 데이터가 관리자에 의해 차단될 수 있습니다.</translation>
<translation id="610911394827799129">Google 계정의 내 활동(<ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />)에는 인터넷 방문 기록이 다른 형식으로 남아 있을 수도 있습니다</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{없음}=1{비밀번호 1개(동기화됨)}other{비밀번호 #개(동기화됨)}}</translation>
@@ -729,7 +731,7 @@
<translation id="6157877588268064908">배송 방법과 요구사항을 확인하려면 주소를 선택하세요.</translation>
<translation id="6165508094623778733">자세히 알아보기</translation>
<translation id="6169916984152623906">이제 비공개로 인터넷을 사용할 수 있으며, 이 기기를 사용하는 다른 사용자가 내 활동을 볼 수 없습니다. 하지만 다운로드한 항목과 북마크는 저장됩니다.</translation>
-<translation id="6177128806592000436">이 사이트에 대한 연결은 안전하지 않습니다.</translation>
+<translation id="6177128806592000436">이 사이트는 보안 연결(HTTPS)이 사용되지 않았습니다.</translation>
<translation id="6203231073485539293">인터넷 연결을 확인하세요.</translation>
<translation id="6218753634732582820">Chromium에서 주소를 삭제하시겠습니까?</translation>
<translation id="6221345481584921695">Google 세이프 브라우징이 최근 <ph name="SITE" />에서 <ph name="BEGIN_LINK" />멀웨어를 감지<ph name="END_LINK" />했습니다. 평소에 안전한 웹사이트도 멀웨어에 감염될 수가 있습니다. 악성 콘텐츠의 출처는 알려진 멀웨어 배포자인 <ph name="SUBRESOURCE_HOST" />입니다.</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">자세한 정보 추가</translation>
<translation id="6447842834002726250">쿠키</translation>
<translation id="6451458296329894277">양식 다시 제출 확인</translation>
+<translation id="6465306955648956876">비밀번호 관리...</translation>
<translation id="647261751007945333">기기 정책</translation>
<translation id="6477321094435799029">Chrome이 이 페이지에서 비정상적인 코드를 감지했으며 개인정보(예: 비밀번호, 전화번호, 신용카드) 보호를 위해 차단했습니다.</translation>
<translation id="6489534406876378309">비정상 종료 업로드 시작하기</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> 검색</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />의 공격자가 사용자 정보(예: 사진, 비밀번호, 메시지, 신용카드)를 도용하거나 삭제하는 위험한 프로그램을 Mac에 설치하려고 시도할 수 있습니다. <ph name="BEGIN_LEARN_MORE_LINK" />자세히 알아보기<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">이 정책은 사용되지 않습니다.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{없음}=1{사이트 1개(Google 계정에서 로그아웃되지 않음)}other{사이트 #개(Google 계정에서 로그아웃되지 않음)}}</translation>
<translation id="6657585470893396449">비밀번호</translation>
<translation id="6671697161687535275">Chromium에서 자동완성 항목 추천을 삭제하시겠습니까?</translation>
<translation id="6685834062052613830">로그아웃 후 설정 완료</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">사용자:</translation>
<translation id="6945221475159498467">선택</translation>
<translation id="6948701128805548767">수령 방법과 요구사항을 확인하려면 주소를 선택하세요.</translation>
+<translation id="6949872517221025916">비밀번호 재설정</translation>
<translation id="6957887021205513506">서버의 인증서가 위조된 것 같습니다.</translation>
<translation id="6965382102122355670">확인</translation>
<translation id="6965978654500191972">기기</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">배달 방법</translation>
<translation id="7139724024395191329">에미리트</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />개}other{<ph name="PAYMENT_METHOD_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />개}}</translation>
-<translation id="7155487117670177674">결제가 안전하지 않음</translation>
+<translation id="717330890047184534">GAIA ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />개}other{<ph name="SHIPPING_OPTION_PREVIEW" /> 외 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />개}}</translation>
<translation id="7180611975245234373">새로고침</translation>
<translation id="7182878459783632708">설정된 정책 없음</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">전체 기본값 사용(차단)</translation>
<translation id="7460163899615895653">다른 기기에서 최근에 사용한 탭이 여기에 표시됩니다.</translation>
<translation id="7469372306589899959">카드 확인 중</translation>
+<translation id="7473891865547856676">건너뛰기</translation>
<translation id="7481312909269577407">앞으로</translation>
<translation id="7485870689360869515">데이터 없음</translation>
<translation id="7508255263130623398">반환된 정책 기기 ID가 비었거나 현재 기기 ID와 일치하지 않음</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Chrome에서 신용카드를 삭제하시겠습니까?</translation>
<translation id="7575800019233204241">'연결이 비공개로 설정되어 있지 않습니다.', '&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;', '&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;', '&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;', 'SSL 인증서 오류'</translation>
<translation id="7578104083680115302">Google에 저장한 카드를 사용하여 어떤 기기에서든지 사이트 및 앱에서 빠르게 지불할 수 있습니다.</translation>
-<translation id="7588950540487816470">피지컬 웹</translation>
<translation id="7592362899630581445">서버의 인증서가 이름 제약 조건을 위반합니다.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> 미만</translation>
<translation id="759889825892636187">현재 <ph name="HOST_NAME" />에서 요청을 처리할 수 없습니다.</translation>
@@ -988,7 +993,7 @@
<translation id="8201077131113104583">ID가 '<ph name="EXTENSION_ID" />'인 확장 프로그램에 대한 잘못된 업데이트 URL</translation>
<translation id="8202097416529803614">주문 요약</translation>
<translation id="8205463626947051446">사이트에 방해가 되는 광고를 표시하는 경향이 있음</translation>
-<translation id="8211406090763984747">이 연결은 안전합니다.</translation>
+<translation id="8211406090763984747">이 사이트는 보안 연결(HTTPS)이 사용되었습니다.</translation>
<translation id="8218327578424803826">지정된 위치:</translation>
<translation id="8225771182978767009">컴퓨터를 설정한 사용자가 이 사이트를 차단했습니다.</translation>
<translation id="822964464349305906"><ph name="TYPE_1" />, <ph name="TYPE_2" /></translation>
@@ -1105,6 +1110,7 @@
<translation id="9148507642005240123">수정 실행 취소(&amp;U)</translation>
<translation id="9154194610265714752">업데이트됨</translation>
<translation id="9157595877708044936">설정 중...</translation>
+<translation id="9168814207360376865">사이트에서 저장된 결제 수단이 있는지 확인하도록 허용</translation>
<translation id="9169664750068251925">이 사이트에서 항상 차단</translation>
<translation id="9170848237812810038">실행 취소(&amp;U)</translation>
<translation id="917450738466192189">서버의 인증서가 유효하지 않습니다.</translation>
@@ -1113,7 +1119,6 @@
<translation id="9207861905230894330">글을 추가하지 못했습니다.</translation>
<translation id="9215416866750762878">애플리케이션으로 인해 Chrome이 안전하게 이 사이트에 접속할 수 없음</translation>
<translation id="9219103736887031265">이미지</translation>
-<translation id="933612690413056017">인터넷에 연결되지 않음</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">양식 지우기</translation>
<translation id="939736085109172342">새 폴더</translation>
diff --git a/chromium/components/strings/components_strings_lt.xtb b/chromium/components/strings/components_strings_lt.xtb
index d46ce8e7e2e..af7de131aa0 100644
--- a/chromium/components/strings/components_strings_lt.xtb
+++ b/chromium/components/strings/components_strings_lt.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" />: pasirinkite leidimą</translation>
<translation id="1111153019813902504">Naujausios žymės</translation>
<translation id="1113869188872983271">&amp;Anuliuoti pertvarkymą</translation>
+<translation id="1125573121925420732">Kol atnaujinami svetainių saugos nustatymai, gali būti dažnai rodomi įspėjimai. Netrukus tai turėtų būti išspręsta.</translation>
<translation id="1126551341858583091">Dydis vietinėje saugykloje yra <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Gera politikos talpykla</translation>
<translation id="1150979032973867961">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nėra patikimas kompiuterio operacinei sistemai. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Įsitikinkite, kad veikia interneto ryšys.&lt;/li&gt;
&lt;li&gt;Susisiekite su svetainės savininku.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Įvedėte slaptažodį svetainėje, kurios netvarko jūsų organizacija. Kad apsaugotumėte paskyrą, nenaudokite to paties slaptažodžio kitose programose ir svetainėse.</translation>
<translation id="1263231323834454256">Skaitymo sąrašas</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> užfiksuota strigčių ataskaita (dar neįkelta ar nepaisoma)</translation>
<translation id="1270502636509132238">Paėmimo metodas</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Pasirinkti</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Neleisti šiam puslapiui kurti papildomų dialogo langų</translation>
-<translation id="1629803312968146339">Ar norite, kad „Chrome“ išsaugotų šią kortelę?</translation>
<translation id="1639239467298939599">Įkeliama</translation>
<translation id="1640180200866533862">Naudotojo politika</translation>
<translation id="1640244768702815859">Pabandykite <ph name="BEGIN_LINK" />apsilankyti pagrindiniame svetainės puslapyje<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Pabandykite paleisti „Windows Network Diagnostics“<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Atnaujinkite sinchronizavimo slaptafrazę.</translation>
<translation id="1787142507584202372">Atidaryti skirtukai bus rodomi čia</translation>
-<translation id="1789575671122666129">Iššokantieji langai</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kortelės savininko vardas</translation>
<translation id="1806541873155184440">Pridėta <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Iš naujo paleiskite kompiuterį</translation>
<translation id="2113977810652731515">Kortelė</translation>
<translation id="2114841414352855701">Nepaisoma, nes buvo pakeista taikant „<ph name="POLICY_NAME" />“.</translation>
-<translation id="2138201775715568214">Ieškoma fizinių tinklalapių netoliese</translation>
<translation id="213826338245044447">Žymės mobiliesiems</translation>
<translation id="214556005048008348">Atšaukti mokėjimą</translation>
<translation id="2147827593068025794">Fono sinchronizavimas</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Politika nerasta</translation>
<translation id="2213606439339815911">Gaunami įrašai...</translation>
<translation id="2218879909401188352">Šiuo metu užpuolikai svetainėje <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> gali įdiegti pavojingų programų, kurios gali būti žalingos įrenginiui, atlikti nepageidaujamų veiksmų, dėl kurių padidės mobiliojo telefono sąskaita, arba pavogti asmens informaciją. <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Nėra interneto ryšio</translation>
<translation id="2230458221926704099">Išspręskite ryšio problemas naudodami <ph name="BEGIN_LINK" />diagnostikos programą<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Siųsti dabar</translation>
<translation id="225207911366869382">Pagal šią politiką ši vertė nepatvirtinta.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Pašalinti pasirinktus elementus</translation>
<translation id="277133753123645258">Pristatymo metodas</translation>
<translation id="277499241957683684">Trūksta įrenginio įrašo</translation>
+<translation id="2781030394888168909">Eksportuoti „Mac“ OS</translation>
<translation id="2784949926578158345">Ryšys atkurtas.</translation>
<translation id="2788784517760473862">Tinkamos kredito kortelės</translation>
<translation id="2794233252405721443">Svetainė užblokuota</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Šiuo metu „Chrome“ negali patvirtinti jūsų kortelės. Vėliau bandykite dar kartą.</translation>
<translation id="3064966200440839136">Išjungiate inkognito režimą, kad galėtumėte sumokėti naudodami išorinę programą. Tęsti?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nėra}=1{1 slaptažodis}one{# slaptažodis}few{# slaptažodžiai}many{# slaptažodžio}other{# slaptažodžių}}</translation>
-<translation id="3093245981617870298">Esate neprisijungę.</translation>
<translation id="3096100844101284527">Pridėti paėmimo adresą</translation>
<translation id="3105172416063519923">Ištekliaus ID:</translation>
<translation id="3109728660330352905">Neturite prieigos teisės žiūrėti šį puslapį.</translation>
@@ -363,6 +363,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> šiuo metu nepasiekiama.</translation>
<translation id="3427092606871434483">Leisti (numatytoji parinktis)</translation>
<translation id="3427342743765426898">&amp;Redaguoti dar kartą</translation>
+<translation id="342781501876943858">„Chromium“ rekomenduoja iš naujo nustatyti slaptažodį, jei naudojate jį kitose svetainėse.</translation>
<translation id="3431636764301398940">Išsaugoti šią kortelę šiame įrenginyje</translation>
<translation id="3447661539832366887">Įrenginio savininkas išjungė dinozauro žaidimą.</translation>
<translation id="3447884698081792621">Rodyti sertifikatą (išdavė „<ph name="ISSUER" />“)</translation>
@@ -399,7 +400,6 @@
<translation id="3678529606614285348">Atidarykite puslapį naujame inkognito lange („Ctrl“ – „Shift“ – N)</translation>
<translation id="3679803492151881375">Strigčių ataskaita užfiksuota <ph name="CRASH_TIME" />, įkelta <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikato informacija</translation>
-<translation id="3690164694835360974">Prisijungimas nesaugus</translation>
<translation id="3704162925118123524">Naudojant šį tinklą gali būti prašoma apsilankyti prisijungimo puslapyje.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Įkeliama...</translation>
@@ -459,7 +459,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Naudoti visuotinį numatytąjį nustatymą (nustatyti)</translation>
<translation id="4165986682804962316">Svetainės nustatymai</translation>
-<translation id="4169947484918424451">Ar norite, kad „Chromium“ išsaugotų šią kortelę?</translation>
<translation id="4171400957073367226">Netinkamas patvirtinimo parašas</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Dar <ph name="ITEM_COUNT" /> elementas}one{Dar <ph name="ITEM_COUNT" /> elementas}few{Dar <ph name="ITEM_COUNT" /> elementai}many{Dar <ph name="ITEM_COUNT" /> elemento}other{Dar <ph name="ITEM_COUNT" /> elementų}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -496,6 +495,7 @@
<translation id="4275830172053184480">Iš naujo paleisti įrenginį</translation>
<translation id="4277028893293644418">Iš naujo nustatyti slaptažodį</translation>
<translation id="4280429058323657511">, gal. pab. <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Perjungti</translation>
<translation id="4312866146174492540">Užblokuoti (numatytoji parinktis)</translation>
<translation id="4325863107915753736">Nepavyko rasti straipsnio</translation>
<translation id="4326324639298822553">Patikrinkite galiojimo pabaigos datą ir bandykite dar kartą</translation>
@@ -503,6 +503,7 @@
<translation id="4340982228985273705">Šis kompiuteris neaptinkamas kaip valdomas įmonės, todėl taikant politiką galima automatiškai įdiegti tik „Chrome“ internetinėje parduotuvėje priglobiamus plėtinius. „Chrome“ internetinės parduotuvės atnaujinimo URL yra „<ph name="CWS_UPDATE_URL" />“.</translation>
<translation id="4346197816712207223">Tinkamos kredito kortelės</translation>
<translation id="4356973930735388585">Šios svetainės užpuolėjai gali jūsų kompiuteryje bandyti įdiegti pavojingas programas, kurios vagia arba ištrina informaciją (pvz., nuotraukas, slaptažodžius, pranešimus ir kredito kortelių numerius).</translation>
+<translation id="4358461427845829800">Tvarkyti mokėjimo metodus...</translation>
<translation id="4372948949327679948">Numatyta „<ph name="VALUE_TYPE" />“ vertė.</translation>
<translation id="4377125064752653719">Bandėte pasiekti svetainę „<ph name="DOMAIN" />“, bet sertifikatą, kurį pateikė serveris, anuliavo jo išdavėjas. Tai reiškia, kad saugos kredencialais, kuriuos pateikė serveris, visiškai negalima pasitikėti. Galbūt bendraujate su užpuoliku.</translation>
<translation id="4406896451731180161">paieškos rezultatai</translation>
@@ -510,6 +511,7 @@
<translation id="4415426530740016218">Paėmimo adresas</translation>
<translation id="4424024547088906515">Šiam serveriui nepavyko patvirtinti, kad tai yra <ph name="DOMAIN" />; jo saugos sertifikatas nėra patikimas „Chrome“. Taip gali nutikti dėl netinkamos konfigūracijos ar dėl ryšį pertraukusio užgrobėjo.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepriėmė jūsų prisijungimo sertifikato arba prisijungimo sertifikatas nebuvo pateiktas.</translation>
+<translation id="4434045419905280838">Iššok. langai ir peradresavimai</translation>
<translation id="443673843213245140">Įgaliotojo serverio naudojimas neleidžiamas, bet nurodyta aiški įgaliotojo serverio konfigūracija.</translation>
<translation id="445100540951337728">Tinkamos debeto kortelės</translation>
<translation id="4506176782989081258">Tikrinimo klaida: <ph name="VALIDATION_ERROR" /></translation>
@@ -544,13 +546,13 @@
<translation id="4759118997339041434">Mokėjimo automatinis pildymas išjungtas</translation>
<translation id="4764776831041365478">Tinklalapis šiuo adresu <ph name="URL" /> gali laikinai neveikti arba visam laikui būti perkeltas kitu žiniatinklio adresu.</translation>
<translation id="4771973620359291008">Įvyko nežinoma klaida.</translation>
+<translation id="4785689107224900852">Perjungti į šį skirtuką</translation>
<translation id="4792143361752574037">Pasiekiant sesijos failus kilo problema. Išsaugojimo diske funkcija šiuo metu išjungta. Iš naujo įkelkite puslapį ir bandykite dar kartą.</translation>
<translation id="4800132727771399293">Patikrinkite kortelės galiojimo pabaigos datą bei saugos kodą (CVC) ir bandykite dar kart</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Negalite dabar apsilankyti svetainėje <ph name="SITE" />, nes ji atsiuntė užšifruotus prisijungimo duomenis, kurių „Google Chrome“ negali apdoroti. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
<translation id="4813512666221746211">Tinklo klaida</translation>
<translation id="4816492930507672669">Pritaikyti pagal puslapį</translation>
-<translation id="483020001682031208">Nėra rodytinų Fizinio žiniatinklio puslapių</translation>
<translation id="4850886885716139402">Žiūrėti</translation>
<translation id="4854362297993841467">Šis pristatymo metodas nepasiekiamas. Išbandykite kitą metodą.</translation>
<translation id="4858792381671956233">Paprašėte tėvų leidimo apsilankyti šiame puslapyje</translation>
@@ -590,6 +592,7 @@
<translation id="5115563688576182185">(64 bitų)</translation>
<translation id="5121084798328133320">Kai patvirtinsite, „Google“ mokamojoje paskyroje nurodyta išsami kortelės informacija bus bendrinama su šia svetaine.</translation>
<translation id="5128122789703661928">Sesijos šiuo pavadinimu negalima ištrinti.</translation>
+<translation id="5135404736266831032">Tvarkyti adresus...</translation>
<translation id="5141240743006678641">Šifruoti sinchronizuotus slaptažodžius naudojant „Google“ prisijungimo duomenis</translation>
<translation id="5145883236150621069">Politikos atsakyme yra klaidos kodas</translation>
<translation id="5159010409087891077">Atidarykite puslapį naujame inkognito lange (⇧⌘N)</translation>
@@ -601,7 +604,6 @@
<translation id="5201306358585911203">Šiame puslapyje įterptame puslapyje nurodyta:</translation>
<translation id="5205222826937269299">Būtina nurodyti pavadinimą</translation>
<translation id="5222812217790122047">Būtina nurodyti el. paštą</translation>
-<translation id="522700295135997067">Gali būti, kad ši svetainė ką tik pavogė jūsų slaptažodį</translation>
<translation id="5230733896359313003">Pristatymo adresas</translation>
<translation id="5250209940322997802">„Prisijungimas prie tinklo“</translation>
<translation id="5251803541071282808">Debesis</translation>
@@ -645,7 +647,6 @@
<translation id="5492298309214877701">Šios svetainės URL įmonės, organizacijos ar mokyklos intranete toks pat kaip išorinės svetainės URL.
<ph name="LINE_BREAK" />
Pabandykite susisiekti su sistemos administratoriumi.</translation>
-<translation id="5499929369096410817">Įveskite kortelės „<ph name="CREDIT_CARD" />“ saugos kodą. Šis kodas nebus išsaugotas.</translation>
<translation id="5509780412636533143">Tvarkomos žymės</translation>
<translation id="5510766032865166053">Galbūt jis perkeltas arba ištrintas.</translation>
<translation id="5523118979700054094">Politikos pavadinimas</translation>
@@ -676,9 +677,11 @@
<translation id="5685654322157854305">Pridėti pristatymo adresą</translation>
<translation id="5689199277474810259">Eksportuoti kaip JSON</translation>
<translation id="5689516760719285838">Vieta</translation>
+<translation id="570530837424789914">Tvarkyti...</translation>
<translation id="5710435578057952990">Šio tinklalapio tapatybė nenustatyta.</translation>
<translation id="5719499550583120431">Išankstinio mokėjimo kortelės tinkamos.</translation>
<translation id="5720705177508910913">Dabartinis naudotojas</translation>
+<translation id="5730040223043577876">„Chrome“ rekomenduoja iš naujo nustatyti slaptažodį, jei naudojate jį kitose svetainėse.</translation>
<translation id="5732392974455271431">Jūsų tėvai gali atblokuoti ją už jus</translation>
<translation id="5763042198335101085">Įveskite galiojantį el. pašto adresą</translation>
<translation id="5765072501007116331">Jei norite peržiūrėti pristatymo metodus ir reikalavimus, pasirinkite adresą.</translation>
@@ -702,9 +705,7 @@
<translation id="5959728338436674663">Automatiškai siųsti tam tikrą <ph name="BEGIN_WHITEPAPER_LINK" />sistemos informaciją ir puslapio turinį<ph name="END_WHITEPAPER_LINK" /> į sistemą „Google“ siekiant padėti aptikti pavojingas programas ir svetaines. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Kontaktinės informacijos redagavimas</translation>
<translation id="5967867314010545767">Pašalinti iš istorijos</translation>
-<translation id="5972020793760134803">Perjungti skirtuką</translation>
<translation id="5975083100439434680">Tolinti</translation>
-<translation id="597552863672748783">Patvirtinkite saugos kodą</translation>
<translation id="598637245381783098">Nepavyksta atidaryti mokėjimo programos</translation>
<translation id="5989320800837274978">Nenurodyti nei fiksuoti įgaliotieji serveriai, nei .pac scenarijaus URL.</translation>
<translation id="5990559369517809815">Plėtinys užblokavo serveriui teikiamas užklausas.</translation>
@@ -720,6 +721,7 @@
<translation id="6047927260846328439">Šiuo turiniu gali būti bandoma apgaule priversti jus įdiegti programinę įrangą arba atskleisti asmens informaciją. <ph name="BEGIN_LINK" />Rodyti vis tiek<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Šiuo metu negalite apsilankyti <ph name="SITE" />, nes svetainėje naudojamas sertifikatų prisegimas. Tinklo klaidos ir užpuolimai dažniausiai yra laikini, todėl šis puslapis vėliau tikriausiai veiks.</translation>
<translation id="6059925163896151826">USB įrenginiai</translation>
+<translation id="6071091556643036997">Politikos tipas netinkamas.</translation>
<translation id="6080696365213338172">Pasiekėte turinį naudodami administratoriaus pateiktą sertifikatą. Duomenys, kuriuos pateikiate <ph name="DOMAIN" />, gali būti perimti administratoriaus.</translation>
<translation id="610911394827799129">„Google“ paskyroje gali būti kito tipo naršymo istorijos, kuri pasiekiama adresu <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nėra}=1{1 slaptažodis (sinchronizuotas)}one{# slaptažodis (sinchronizuotas)}few{# slaptažodžiai (sinchronizuoti)}many{# slaptažodžio (sinchronizuota)}other{# slaptažodžių (sinchronizuota)}}</translation>
@@ -767,6 +769,7 @@
<translation id="6446608382365791566">Daugiau informacijos pridėjimas</translation>
<translation id="6447842834002726250">Slapukai</translation>
<translation id="6451458296329894277">Patvirtinkite pakartotiną formos pateikimą</translation>
+<translation id="6465306955648956876">Tvarkyti slaptažodžius...</translation>
<translation id="647261751007945333">Įrenginio politika</translation>
<translation id="6477321094435799029">„Chrome“ šiame puslapyje aptiko neįprastą kodą ir jį užblokavo, kad apsaugotų asmens informaciją (pvz., slaptažodžius, telefonų numerius ir kredito korteles).</translation>
<translation id="6489534406876378309">Pradėti įkelti strigtis</translation>
@@ -786,6 +789,7 @@
<translation id="6628463337424475685">„<ph name="ENGINE" />“ paieška</translation>
<translation id="6630809736994426279">Šiuo metu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> užpuolikai gali jūsų „Mac“ įrenginyje bandyti įdiegti pavojingas programas, kurios vagia arba ištrina informaciją (pvz., nuotraukas, slaptažodžius, pranešimus ir kredito kortelių duomenis). <ph name="BEGIN_LEARN_MORE_LINK" />Sužinokite daugiau<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Ši politika nepatvirtinta.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nėra}=1{Iš 1 svetainės (nebūsite atjungti nuo „Google“ paskyros)}one{Iš # svetainės (nebūsite atjungti nuo „Google“ paskyros)}few{Iš # svetainių (nebūsite atjungti nuo „Google“ paskyros)}many{Iš # svetainės (nebūsite atjungti nuo „Google“ paskyros)}other{Iš # svetainių (nebūsite atjungti nuo „Google“ paskyros)}}</translation>
<translation id="6657585470893396449">Slaptažodis</translation>
<translation id="6671697161687535275">Pašalinti formos pasiūlymą iš „Chromium“?</translation>
<translation id="6685834062052613830">Atsijunkite ir užbaikite sąranką</translation>
@@ -812,6 +816,7 @@
<translation id="6915804003454593391">Naudotojas:</translation>
<translation id="6945221475159498467">Pasirinkti</translation>
<translation id="6948701128805548767">Jei norite peržiūrėti paėmimo metodus ir reikalavimus, pasirinkite adresą</translation>
+<translation id="6949872517221025916">Slaptažodžio nustatymas iš naujo</translation>
<translation id="6957887021205513506">Panašu, kad serverio sertifikatas yra suklastotas.</translation>
<translation id="6965382102122355670">Gerai</translation>
<translation id="6965978654500191972">Įrenginys</translation>
@@ -833,7 +838,7 @@
<translation id="7138472120740807366">Pristatymo metodas</translation>
<translation id="7139724024395191329">Emyratas</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}many{<ph name="PAYMENT_METHOD_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Mokėjimas nesaugus</translation>
+<translation id="717330890047184534">„Gaia“ ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}many{<ph name="SHIPPING_OPTION_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> ir dar <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Atnaujinti</translation>
<translation id="7182878459783632708">Nenustatyta jokia politika</translation>
@@ -882,6 +887,7 @@
<translation id="7455133967321480974">Naudoti visuotinį numatytąjį nustatymą (blokuoti)</translation>
<translation id="7460163899615895653">Naujausi kitų įrenginių skirtukai rodomi čia</translation>
<translation id="7469372306589899959">Kortelė patvirtinama</translation>
+<translation id="7473891865547856676">Ne, ačiū</translation>
<translation id="7481312909269577407">Persiųsti</translation>
<translation id="7485870689360869515">Nerasta jokių duomenų.</translation>
<translation id="7508255263130623398">Sugrąžinto politikos įrenginio ID nenurodytas arba neatitinka dabartinio įrenginio ID</translation>
@@ -904,7 +910,6 @@
<translation id="7569952961197462199">Pašalinti kredito kortelės informaciją iš „Chrome“?</translation>
<translation id="7575800019233204241">„Ryšys nėra privatus“, „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;“, „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;“, „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;“ arba „SSL sertifikato klaida“</translation>
<translation id="7578104083680115302">Greitai mokėkite svetainėse ir programose įvairiuose įrenginiuose naudodami korteles, kurias išsaugojote „Google“.</translation>
-<translation id="7588950540487816470">Fizinis žiniatinklis</translation>
<translation id="7592362899630581445">Serverio sertifikatas pažeidžia pavadinimų apribojimus.</translation>
<translation id="7598391785903975535">Mažiau nei <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> šiuo metu negalima apdoroti šios užklausos.</translation>
@@ -1108,6 +1113,7 @@
<translation id="9148507642005240123">&amp;Anuliuoti redagavimą</translation>
<translation id="9154194610265714752">Atnaujinta</translation>
<translation id="9157595877708044936">Nustatoma...</translation>
+<translation id="9168814207360376865">Leisti svetainėms tikrinti, ar esate išsaugoję mokėjimo metodus</translation>
<translation id="9169664750068251925">Visada blokuoti šioje svetainėje</translation>
<translation id="9170848237812810038">&amp;Atšaukti</translation>
<translation id="917450738466192189">Serverio sertifikatas negalioja.</translation>
@@ -1116,7 +1122,6 @@
<translation id="9207861905230894330">Nepavyko pridėti straipsnio.</translation>
<translation id="9215416866750762878">Programa neleidžia „Chrome“ saugiai prisijungti prie svetainės</translation>
<translation id="9219103736887031265">Vaizdai</translation>
-<translation id="933612690413056017">Nėra interneto ryšio</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">CLEAR FORM</translation>
<translation id="939736085109172342">Naujas aplankas</translation>
diff --git a/chromium/components/strings/components_strings_lv.xtb b/chromium/components/strings/components_strings_lv.xtb
index c81ae0085d5..84060dce419 100644
--- a/chromium/components/strings/components_strings_lv.xtb
+++ b/chromium/components/strings/components_strings_lv.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Atlasiet atļauju: <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Nesenas grāmatzīmes</translation>
<translation id="1113869188872983271">&amp;Atsaukt pārkārtošanu</translation>
+<translation id="1125573121925420732">Tīmekļa vietņu drošības atjauninājumu laikā bieži var tikt rādīti brīdinājumi. Drīzumā tas tiks labots.</translation>
<translation id="1126551341858583091">Lielums vietējā krātuvē ir <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Politikas kešatmiņa ir labā stāvoklī.</translation>
<translation id="1150979032973867961">Šis serveris nevarēja pierādīt, ka šī ir vietne <ph name="DOMAIN" />; tās drošības sertifikāts netiek uzskatīts par uzticamu jūsu datora operētājsistēmā. Iespējams, tas ir nepareizas konfigurācijas dēļ vai arī kāds ir ļaunprātīgi izmantojis jūsu savienojumu.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Pārbaudiet, vai interneta savienojums darbojas pareizi.&lt;/li&gt;
&lt;li&gt;Sazinieties ar vietnes īpašnieku.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Jūs ievadījāt paroli vietnē, kuru nepārvalda jūsu organizācija. Lai aizsargātu savu kontu, neizmantojiet šo paroli citās lietotnēs un vietnēs.</translation>
<translation id="1263231323834454256">Lasīšanas saraksts</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> notverts ziņojums par avāriju (vēl nav augšupielādēts vai ignorēts)</translation>
<translation id="1270502636509132238">Saņemšanas veids</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Izvēlēties</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Neļaut šai lapai veidot papildu dialoglodziņus</translation>
-<translation id="1629803312968146339">Vai vēlaties, lai Chrome saglabātu šo karti?</translation>
<translation id="1639239467298939599">Notiek ielāde</translation>
<translation id="1640180200866533862">Lietotāja politikas</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />Apmeklējiet vietnes sākumlapu<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Mēģiniet palaist Windows tīkla diagnostiku<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Atjauniniet savu sinhronizācijas ieejas frāzi.</translation>
<translation id="1787142507584202372">Šeit tiks parādītas jūsu atvērtās cilnes</translation>
-<translation id="1789575671122666129">Uznirstošie logi</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kartes īpašnieka vārds, uzvārds</translation>
<translation id="1806541873155184440">Pievienota: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Restartējiet datoru</translation>
<translation id="2113977810652731515">Karte</translation>
<translation id="2114841414352855701">Ignorēta, jo to atcēla politika <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Notiek tuvumā esošu fiziskā tīmekļa lapu meklēšana</translation>
<translation id="213826338245044447">Mobilās grāmatzīmes</translation>
<translation id="214556005048008348">Atcelt maksājumu</translation>
<translation id="2147827593068025794">Sinhronizācija fonā</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Politika netika atrasta.</translation>
<translation id="2213606439339815911">Notiek ierakstu ienešana...</translation>
<translation id="2218879909401188352">Uzbrucēji vietnē <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> varētu instalēt bīstamas lietotnes, kas bojā jūsu ierīci, rada slēptas izmaksas mobilā tālruņa rēķinā vai zog jūsu personas informāciju. <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairāk<ph name="END_LEARN_MORE_LINK" />.</translation>
+<translation id="2224337661447660594">Nav interneta savienojuma</translation>
<translation id="2230458221926704099">Labojiet savienojumu, izmantojot <ph name="BEGIN_LINK" />diagnostikas lietotni<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Sūtīt tūlīt</translation>
<translation id="225207911366869382">Šī vērtība vairs netiek atbalstīta šai politikai.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Noņemt atlasītos vienumus</translation>
<translation id="277133753123645258">Nosūtīšanas veids</translation>
<translation id="277499241957683684">Trūkst ierīces ieraksta.</translation>
+<translation id="2781030394888168909">Eksportēt MacOS formātā</translation>
<translation id="2784949926578158345">Savienojums tika atiestatīts.</translation>
<translation id="2788784517760473862">Atbalstītās kredītkartes</translation>
<translation id="2794233252405721443">Vietne bloķēta</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Pārlūkā Chrome pašlaik nevar apstiprināt jūsu karti. Lūdzu, vēlāk mēģiniet vēlreiz.</translation>
<translation id="3064966200440839136">Ja maksāšanai tiks izmantota ārēja lietojumprogramma, tiks aizvērts inkognito režīms. Vai turpināt?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nav}=1{1 parole}zero{# paroles}one{# parole}other{# paroles}}</translation>
-<translation id="3093245981617870298">Esat bezsaistē</translation>
<translation id="3096100844101284527">Pievienot saņemšanas adresi</translation>
<translation id="3105172416063519923">Līdzekļa ID:</translation>
<translation id="3109728660330352905">Jums nav pilnvaru, lai skatītu šo lapu.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Vietne <ph name="HOST_NAME" /> pašlaik nav sasniedzama.</translation>
<translation id="3427092606871434483">Atļaut (pēc noklusējuma)</translation>
<translation id="3427342743765426898">&amp;Labojuma atsaukuma atcelšana</translation>
+<translation id="342781501876943858">Chromium iesaka atiestatīt jūsu paroli, ja izmantojāt to citās vietnēs.</translation>
<translation id="3431636764301398940">Saglabāt šo karti šajā ierīcē</translation>
<translation id="3447661539832366887">Šīs ierīces īpašnieks ir izslēdzis dinozauru spēli.</translation>
<translation id="3447884698081792621">Parādīt sertifikātu (izsniedza <ph name="ISSUER" />)</translation>
@@ -397,7 +398,6 @@
<translation id="3678529606614285348">Atvērt lapu jaunā inkognito režīma logā (Ctrl+Shift+N)</translation>
<translation id="3679803492151881375">Avāriju pārskats tverts: <ph name="CRASH_TIME" />; augšupielādēts: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikāta informācija</translation>
-<translation id="3690164694835360974">Pieteikšanās nav droša</translation>
<translation id="3704162925118123524">Iespējams, izmantotajā tīklā tiks pieprasīts apmeklēt pieteikšanās lapu.</translation>
<translation id="3704609568417268905"><ph name="TIME" />, <ph name="BOOKMARKED" />, <ph name="TITLE" />, <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Notiek ielāde...</translation>
@@ -457,7 +457,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Izmantot globālo noklusējuma vērtību (noteikt)</translation>
<translation id="4165986682804962316">Vietnes iestatījumi</translation>
-<translation id="4169947484918424451">Vai vēlaties, lai Chromium saglabātu šo karti?</translation>
<translation id="4171400957073367226">Verifikācijas paraksts nav derīgs.</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Vēl <ph name="ITEM_COUNT" /> vienums}zero{Vēl <ph name="ITEM_COUNT" /> vienumi}one{Vēl <ph name="ITEM_COUNT" /> vienums}other{Vēl <ph name="ITEM_COUNT" /> vienumi}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
@@ -494,6 +493,7 @@
<translation id="4275830172053184480">Ierīces restartēšana</translation>
<translation id="4277028893293644418">Atiestatīt paroli</translation>
<translation id="4280429058323657511">, derīga līdz <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Pāriet</translation>
<translation id="4312866146174492540">Bloķēt (pēc noklusējuma)</translation>
<translation id="4325863107915753736">Rakstu neizdevās atrast.</translation>
<translation id="4326324639298822553">Pārbaudiet derīguma termiņa datumu un mēģiniet vēlreiz.</translation>
@@ -501,6 +501,7 @@
<translation id="4340982228985273705">Šo datoru nepārvalda uzņēmums, tāpēc politika var automātiski instalēt tikai tos paplašinājumus, kas tiek mitināti Chrome interneta veikalā. Chrome interneta veikala atjauninājumu URL: <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Pieņemtās kredītkartes</translation>
<translation id="4356973930735388585">Šajā vietnē esošie uzbrucēji jūsu datorā var mēģināt instalēt bīstamas programmas, kuras var nozagt vai dzēst jūsu informāciju (piemēram, fotoattēlus, paroles, ziņojumus un informāciju par kredītkartēm).</translation>
+<translation id="4358461427845829800">Pārvaldīt maksājumu veidus...</translation>
<translation id="4372948949327679948">Tika gaidīta vērtība <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Jūs mēģinājāt sasniegt <ph name="DOMAIN" />, bet izdevējs atsauca servera uzrādīto sertifikātu. Tas nozīmē, ka servera uzrādītie drošības akreditācijas dati itin nemaz nav uzticami. Iespējams, jūs sazināties ar uzbrucēju.</translation>
<translation id="4406896451731180161">meklēšanas rezultāti</translation>
@@ -508,6 +509,7 @@
<translation id="4415426530740016218">Saņemšanas adrese</translation>
<translation id="4424024547088906515">Šis serveris nevarēja pierādīt, ka šī ir vietne <ph name="DOMAIN" />; tās drošības sertifikāts netiek uzskatīts par uzticamu pārlūkā Chrome. Iespējams, tas ir nepareizas konfigurācijas dēļ vai arī kāds ir ļaunprātīgi izmantojis jūsu savienojumu.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nepieņēma jūsu pieteikšanās sertifikātu, vai arī pieteikšanās sertifikāts netika iesniegts.</translation>
+<translation id="4434045419905280838">Uznirstošie elem. un novirzīšana</translation>
<translation id="443673843213245140">Starpniekservera lietošana ir atspējota, bet ir norādīta atklāta starpniekservera konfigurācija.</translation>
<translation id="445100540951337728">Atbalstītās debetkartes</translation>
<translation id="4506176782989081258">Validācijas kļūda: <ph name="VALIDATION_ERROR" /></translation>
@@ -542,13 +544,13 @@
<translation id="4759118997339041434">Maksājumu automātiska aizpilde ir atspējota</translation>
<translation id="4764776831041365478">Tīmekļa lapa vietnē <ph name="URL" /> var īslaicīgi nebūt pieejama, vai tā var būt pārvietota uz jaunu tīmekļa adresi.</translation>
<translation id="4771973620359291008">Radās nezināma kļūda.</translation>
+<translation id="4785689107224900852">Pāriet uz šo cilni</translation>
<translation id="4792143361752574037">Piekļūstot sesijas failiem, radās problēma. Saglabāšana diskā šobrīd ir atspējota. Lai mēģinātu vēlreiz, atkārtoti ielādējiet lapu.</translation>
<translation id="4800132727771399293">Pārbaudiet derīguma termiņu un CVC kodu un mēģiniet vēlreiz.</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Pašlaik nevarat apmeklēt vietni <ph name="SITE" />, jo tā nosūtīja bojātus akreditācijas datus, ko nevar apstrādāt pārlūkā Google Chrome. Tīkla kļūdas un uzbrukumi parasti ir īslaicīgi, tāpēc šī lapa vēlāk, visticamāk, darbosies.</translation>
<translation id="4813512666221746211">Tīkla kļūda</translation>
<translation id="4816492930507672669">Ietilpināt lapā</translation>
-<translation id="483020001682031208">Nav nevienas fiziskā tīmekļa lapas, ko parādīt.</translation>
<translation id="4850886885716139402">Skatīt</translation>
<translation id="4854362297993841467">Šis piegādes veids nav pieejams. Izmēģiniet citu veidu.</translation>
<translation id="4858792381671956233">Jūs lūdzāt vecākiem atļauju apmeklēt šo lapu</translation>
@@ -588,6 +590,7 @@
<translation id="5115563688576182185">(64 bitu)</translation>
<translation id="5121084798328133320">Pēc apstiprināšanas kartes informācija no Google maksājumu konta tiks kopīgota ar šo vietni.</translation>
<translation id="5128122789703661928">Sesija ar šādu nosaukumu nav dzēšama.</translation>
+<translation id="5135404736266831032">Pārvaldīt adreses...</translation>
<translation id="5141240743006678641">Šifrēt sinhronizētās paroles, izmantojot Google akreditācijas datus</translation>
<translation id="5145883236150621069">Politikas atbildē ir kļūdas kods.</translation>
<translation id="5159010409087891077">Atvērt lapu jaunā inkognito režīma logā (⇧⌘N)</translation>
@@ -599,7 +602,6 @@
<translation id="5201306358585911203">Šajā lapā iegultā lapā ir rakstīts</translation>
<translation id="5205222826937269299">Jānorāda vārds vai nosaukums.</translation>
<translation id="5222812217790122047">Jānorāda e-pasta adrese.</translation>
-<translation id="522700295135997067">Iespējams, šajā vietnē tikko tika nozagta jūsu parole</translation>
<translation id="5230733896359313003">Piegādes adrese</translation>
<translation id="5250209940322997802">“Izveidojiet savienojumu ar tīklu”</translation>
<translation id="5251803541071282808">Mākonis</translation>
@@ -643,7 +645,6 @@
<translation id="5492298309214877701">Šai vietnei uzņēmuma, organizācijas vai skolas iekštīklā ir tāds pats URL kā ārējai vietnei.
<ph name="LINE_BREAK" />
Sazinieties ar sistēmas administratoru.</translation>
-<translation id="5499929369096410817">Ievadiet kartes <ph name="CREDIT_CARD" /> drošības kodu. Šis kods netiks saglabāts.</translation>
<translation id="5509780412636533143">Pārvaldītās grāmatzīmes</translation>
<translation id="5510766032865166053">Iespējams, tas ir pārvietots vai izdzēsts.</translation>
<translation id="5523118979700054094">Politikas nosaukums</translation>
@@ -674,9 +675,11 @@
<translation id="5685654322157854305">Pievienot nosūtīšanas adresi</translation>
<translation id="5689199277474810259">Eksportēt JSON formātā</translation>
<translation id="5689516760719285838">Atrašanās vieta</translation>
+<translation id="570530837424789914">Pārvaldīt...</translation>
<translation id="5710435578057952990">Tīmekļa vietnes identitāte nav apstiprināta.</translation>
<translation id="5719499550583120431">Tiek pieņemtas priekšapmaksas kartes.</translation>
<translation id="5720705177508910913">Pašreizējais lietotājs</translation>
+<translation id="5730040223043577876">Chrome iesaka atiestatīt jūsu paroli, ja izmantojāt to citās vietnēs.</translation>
<translation id="5732392974455271431">Lai atbloķētu, vērsieties pie vecākiem</translation>
<translation id="5763042198335101085">Ievadiet derīgu e-pasta adresi</translation>
<translation id="5765072501007116331">Lai skatītu piegādes veidus un prasības, atlasiet adresi.</translation>
@@ -700,9 +703,7 @@
<translation id="5959728338436674663">Automātiski sūtīt Google serveriem noteiktu <ph name="BEGIN_WHITEPAPER_LINK" />sistēmas informāciju un lapu saturu<ph name="END_WHITEPAPER_LINK" />, lai palīdzētu noteikt bīstamas lietotnes un vietnes. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Kontaktinformācijas rediģēšana</translation>
<translation id="5967867314010545767">Noņemt no vēstures</translation>
-<translation id="5972020793760134803">Pārslēgties uz cilni</translation>
<translation id="5975083100439434680">Tālināt</translation>
-<translation id="597552863672748783">Drošības koda apstiprināšana</translation>
<translation id="598637245381783098">Nevar atvērt maksājumu lietotni</translation>
<translation id="5989320800837274978">Nav norādīti nedz fiksēti starpniekserveri, nedz .pac skripta URL.</translation>
<translation id="5990559369517809815">Paplašinājums ir bloķējis pieprasījumus serverim.</translation>
@@ -718,6 +719,7 @@
<translation id="6047927260846328439">Ar šo saturu jūs var maldināt un panākt, ka instalējat programmatūru vai atklājat personas informāciju. <ph name="BEGIN_LINK" />Tāpat rādīt<ph name="END_LINK" />.</translation>
<translation id="6051221802930200923">Pašlaik nevarat apmeklēt vietni <ph name="SITE" />, jo tajā tiek izmantota sertifikātu piespraušana. Tā kā tīkla kļūdas un uzbrukumi parasti ir īslaicīgi, visticamāk, šī lapa vēlāk darbosies.</translation>
<translation id="6059925163896151826">USB ierīces</translation>
+<translation id="6071091556643036997">Politikas veids nav derīgs.</translation>
<translation id="6080696365213338172">Jūs esat piekļuvis saturam, izmantojot administratora izsniegtu sertifikātu. Datus, kurus sniedzat domēnā <ph name="DOMAIN" />, var pārtvert jūsu administrators.</translation>
<translation id="610911394827799129">Jūsu Google kontam var būt citu veidu pārlūkošanas vēstures dati vietnē <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nav}=1{1 parole (sinhronizēta)}zero{# paroles (sinhronizētas)}one{# parole (sinhronizēta)}other{# paroles (sinhronizētas)}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">Papildu informācijas pievienošana</translation>
<translation id="6447842834002726250">Sīkfaili</translation>
<translation id="6451458296329894277">Apstiprināt veidlapas atkārtotu iesniegšanu</translation>
+<translation id="6465306955648956876">Pārvaldīt paroles...</translation>
<translation id="647261751007945333">Ierīces politikas</translation>
<translation id="6477321094435799029">Pārlūkā Chrome tika noteikts, ka šajā lapā ir neparasts kods. Lapa tika bloķēta, lai aizsargātu jūsu personas informāciju (piemēram, paroles, tālruņa numurus un kredītkaršu informāciju).</translation>
<translation id="6489534406876378309">Sākt avāriju datu augšupielādi</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> meklēšana</translation>
<translation id="6630809736994426279">Uzbrucēji vietnē <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> var mēģināt jūsu Mac datorā instalēt bīstamas programmas, kas zog vai izdzēš informāciju (piemēram, fotoattēlus, paroles, ziņojumus un kredītkaršu datus). <ph name="BEGIN_LEARN_MORE_LINK" />Uzziniet vairāk<ph name="END_LEARN_MORE_LINK" />.</translation>
<translation id="6644283850729428850">Šī politika ir izbeigta.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nav}=1{No 1 vietnes (jūs netiksiet izrakstīts no sava Google konta)}zero{No # vietnēm (jūs netiksiet izrakstīts no sava Google konta)}one{No # vietnes (jūs netiksiet izrakstīts no sava Google konta)}other{No # vietnēm (jūs netiksiet izrakstīts no sava Google konta)}}</translation>
<translation id="6657585470893396449">Parole</translation>
<translation id="6671697161687535275">Vai noņemt veidlapas ieteikumu no pārlūka Chromium?</translation>
<translation id="6685834062052613830">Izrakstieties un pabeidziet iestatīšanu</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">Lietotājs:</translation>
<translation id="6945221475159498467">Atlasīt</translation>
<translation id="6948701128805548767">Lai skatītu saņemšanas veidus un prasības, atlasiet adresi.</translation>
+<translation id="6949872517221025916">Paroles atiestatīšana</translation>
<translation id="6957887021205513506">Šķiet, ka servera sertifikāts ir viltojums.</translation>
<translation id="6965382102122355670">Labi</translation>
<translation id="6965978654500191972">Ierīce</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">Piegādes veids</translation>
<translation id="7139724024395191329">Emirāts</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}zero{<ph name="PAYMENT_METHOD_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Maksājums nav drošs</translation>
+<translation id="717330890047184534">GAIA ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}zero{<ph name="SHIPPING_OPTION_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> un vēl <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Atsvaidzināt</translation>
<translation id="7182878459783632708">Nav iestatīta neviena politika</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">Izmantot globālo noklusējumu (Bloķēt)</translation>
<translation id="7460163899615895653">Jūsu nesen izmantotās cilnes no citām ierīcēm tiek rādītas šeit</translation>
<translation id="7469372306589899959">Notiek kartes apstiprināšana</translation>
+<translation id="7473891865547856676">Nē, paldies!</translation>
<translation id="7481312909269577407">Pārsūtīt</translation>
<translation id="7485870689360869515">Dati netika atrasti.</translation>
<translation id="7508255263130623398">Atgrieztais politikas ierīces ID ir tukšs vai neatbilst pašreizējam ierīces ID.</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Vai noņemt kredītkarti no pārlūka Chrome?</translation>
<translation id="7575800019233204241">“Savienojums nav privāts”, “&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;”, “&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;”, “&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;” vai “SSL sertifikāta kļūda”</translation>
<translation id="7578104083680115302">Ātri apmaksājiet pirkumus vietnēs un lietotnēs no dažādām ierīcēm, izmantojot kartes, ko esat saglabājis Google sistēmā.</translation>
-<translation id="7588950540487816470">Fiziskais tīmeklis</translation>
<translation id="7592362899630581445">Servera sertifikātā ir pārkāpti nosaukuma ierobežojumi.</translation>
<translation id="7598391785903975535">Mazāk nekā <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> pašlaik nevar apstrādāt šo pieprasījumu.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Atsaukt labojumu</translation>
<translation id="9154194610265714752">Atjaunināts</translation>
<translation id="9157595877708044936">Notiek uzstādīšana...</translation>
+<translation id="9168814207360376865">Atļaut vietnēm pārbaudīt, vai jums ir saglabāti maksājumu veidi</translation>
<translation id="9169664750068251925">Vienmēr bloķēt šajā vietnē</translation>
<translation id="9170848237812810038">&amp;Atsaukt</translation>
<translation id="917450738466192189">Servera sertifikāts ir nederīgs.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Rakstu neizdevās pievienot.</translation>
<translation id="9215416866750762878">Lietojumprogrammas darbības dēļ pārlūkā Chrome nevar izveidot drošu savienojumu ar šo vietni</translation>
<translation id="9219103736887031265">Attēli</translation>
-<translation id="933612690413056017">Nav interneta savienojuma</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">NOTĪRĪT VEIDLAPU</translation>
<translation id="939736085109172342">Jauna mape</translation>
diff --git a/chromium/components/strings/components_strings_ml.xtb b/chromium/components/strings/components_strings_ml.xtb
index b861f51df65..7d00c2c2a71 100644
--- a/chromium/components/strings/components_strings_ml.xtb
+++ b/chromium/components/strings/components_strings_ml.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> എന്നതിന്‍റെ അനുമതി തിരഞ്ഞെടുക്കുക</translation>
<translation id="1111153019813902504">അടുത്തിടെ ഉപയോഗിച്ച ബുക്ക്‌മാർക്കുകൾ</translation>
<translation id="1113869188872983271">&amp;പുനഃക്രമീകരിക്കുന്നത് പഴയപടിയാക്കുക</translation>
+<translation id="1125573121925420732">വെബ്‌സൈറ്റുകൾ അവയുടെ സുരക്ഷ അപ്‌ഡേറ്റ് ചെയ്യുന്ന സമയത്ത് പൊതുവെ മുന്നറിയിപ്പുകൾ കാണിച്ചേക്കാം. ഇത് താമസിയാതെ മെച്ചപ്പെടും.</translation>
<translation id="1126551341858583091">ലോക്കൽ സ്‌‌റ്റോറേജിന്റെ വലുപ്പം <ph name="CRASH_SIZE" /> ആണ്.</translation>
<translation id="112840717907525620">നയ കാഷെ ശരി</translation>
<translation id="1150979032973867961">ഈ സെർവറിന് അത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; അതിന്റെ സുരക്ഷ സർട്ടിഫിക്കറ്റിനെ നിങ്ങളുടെ കമ്പ്യൂട്ടറിന്റെ ഓപ്പറേറ്റിംഗ് സിസ്‌റ്റത്തിന് പരിചയമില്ല. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു അക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;ഇന്റർനെറ്റ് കണക്ഷൻ സാധാരണ ഗതിയിൽ പ്രവർത്തിക്കുന്നുവെന്ന് ഉറപ്പാക്കുക.&lt;/li&gt;
&lt;li&gt;വെബ്‌സൈറ്റ് ഉടമയെ ബന്ധപ്പെടുക.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">നിങ്ങളുടെ സ്ഥാപനത്തിന് നിയന്ത്രണമില്ലാത്ത ഒരു സൈറ്റിലാണ് നിങ്ങൾ പാസ്‌വേഡ് നൽകിയിരിക്കുന്നത്. നിങ്ങളുടെ അക്കൗണ്ട് പരിരക്ഷിക്കാൻ, മറ്റ് ആപ്പുകളിലും സൈറ്റുകളിലും നിങ്ങളുടെ പാസ്‌വേഡ് പുനരുപയോഗിക്കരുത്.</translation>
<translation id="1263231323834454256">വായനാ ലിസ്റ്റ്</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />-ന് ക്യാപ്‌ച്ചർ ചെയ്‌ത ക്രാഷ് റിപ്പോർട്ട് (ഇതുവരെ അപ്‌ലോഡുചെയ്‌തിട്ടോ അവഗണിച്ചിട്ടോ ഇല്ല)</translation>
<translation id="1270502636509132238">പിക്കപ്പ് രീതി</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">തിരഞ്ഞെടുക്കുക</translation>
<translation id="1620510694547887537">ക്യാമറ</translation>
<translation id="1623104350909869708">കൂടുതൽ ഡയലോഗുകൾ സൃഷ്‌ടിക്കുന്നതിൽ നിന്നും ഈ പേജിനെ തടയുക</translation>
-<translation id="1629803312968146339">Chrome ഈ കാർഡ് സംരക്ഷിക്കണോ?</translation>
<translation id="1639239467298939599">ലോഡുചെയ്യുന്നു</translation>
<translation id="1640180200866533862">ഉപയോക്തൃ നയങ്ങൾ</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />സൈറ്റിന്റെ ഹോം പേജ് സന്ദർശിക്കുന്നത്<ph name="END_LINK" /> പരീക്ഷിച്ചുനോക്കൂ.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows നെറ്റ്‌വർക്ക് ഡയഗണോസ്‌റ്റിക്‌സ് റൺ ചെയ്‌തുനോക്കൂ<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">നിങ്ങളുടെ സമന്വയ പാസ്‌ഫ്രേസ് ദയവായി അപ്‌ഡേറ്റ് ചെയ്യുക.</translation>
<translation id="1787142507584202372">നിങ്ങൾ നിലവിൽ തുറന്നിട്ടുള്ള ടാബുകൾ ഇവിടെ ദൃശ്യമാകും</translation>
-<translation id="1789575671122666129">പോപ്പ്അപ്പുകൾ</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">കാർഡ് ഉടമയുടെ പേര്</translation>
<translation id="1806541873155184440"><ph name="ADDED_TO_AUTOFILL_MONTH" />-ന് ചേർത്തു</translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">നിങ്ങളുടെ കമ്പ്യൂട്ടർ റീസ്‌റ്റാർട്ടുചെയ്യുക</translation>
<translation id="2113977810652731515">കാർഡ്</translation>
<translation id="2114841414352855701"> <ph name="POLICY_NAME" /> എന്നതിനാൽ മറികടന്നതിനാൽ ഇത് അവഗണിച്ചു.</translation>
-<translation id="2138201775715568214">വിളിപ്പാടരികെയുള്ള ഫിസിക്കൽ വെബ് പേജുകൾ തിരയുന്നു</translation>
<translation id="213826338245044447">മൊബൈൽ ബുക്ക്‌മാർക്കുകൾ</translation>
<translation id="214556005048008348">പേയ്‌മെന്‍റ് റദ്ദാക്കുക</translation>
<translation id="2147827593068025794">പശ്ചാത്തലം സമന്വയിപ്പിക്കൽ</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">നയം കണ്ടെത്തിയില്ല</translation>
<translation id="2213606439339815911">എൻട്രികൾ ലഭ്യമാക്കുന്നു...</translation>
<translation id="2218879909401188352">നിലവിൽ <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> എന്നതിലുള്ള അക്രമികൾക്ക് നിങ്ങളുടെ ഉപകരണം കേടുവരുത്തുന്ന ആപ്പുകൾ ഇൻസ്‌റ്റാൾ ചെയ്യാനോ മൊബൈൽ ബില്ലിലേക്ക് നിങ്ങളറിയാതെ നിരക്കുകൾ ചേർക്കാനോ നിങ്ങളുടെ വ്യക്തിഗത വിവരങ്ങൾ മോഷ്‌ടിക്കാനോ കഴിയും. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടുതലറിയുക<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ഇന്റർനെറ്റ് ഇല്ല</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />ഡയഗണോസ്‌റ്റിക്‌സ് ആപ്പ്<ph name="END_LINK" /> ഉപയോഗിച്ച് കണകഷൻ പ്രശ്‌നം പരിഹരിക്കുക</translation>
<translation id="2239100178324503013">ഇപ്പോൾ അയയ്‌ക്കുക</translation>
<translation id="225207911366869382">ഈ നയത്തിനായി ഈ മൂല്യത്തെ ഒഴിവാക്കി.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">തിരഞ്ഞെടുത്ത ഇനങ്ങള്‍‌ നീക്കംചെയ്യുക </translation>
<translation id="277133753123645258">ഷിപ്പിംഗ് രീതി</translation>
<translation id="277499241957683684">ഉപകരണ റെക്കോർഡ് കാണുന്നില്ല</translation>
+<translation id="2781030394888168909">MacOS എക്‌സ്‌പോർട്ട് ചെയ്യുക</translation>
<translation id="2784949926578158345">കണക്ഷന്‍ പുനഃസജ്ജമാക്കിയതാണ്.</translation>
<translation id="2788784517760473862">ക്രെഡിറ്റ് കാർഡുകൾ സ്വീകരിക്കുന്നു</translation>
<translation id="2794233252405721443">സൈറ്റ് ബ്ലോക്കുചെയ്‌തു</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome-ന് ഇപ്പോൾ നിങ്ങളുടെ കാർഡ് സ്ഥിരീകരിക്കാനായില്ല. പിന്നീട് വീണ്ടും ശ്രമിക്കുക.</translation>
<translation id="3064966200440839136">ഒരു എക്‌സ്‌റ്റേണൽ അപ്ലിക്കേഷൻ വഴി പണമടയ്‌ക്കാൻ അദൃശ്യതാ സംവിധാനം ഒഴിവാക്കുന്നു. തുടരണോ?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ഒന്നുമില്ല}=1{ഒരു പാസ്‌വേഡ്}other{# പാസ്‌വേഡുകൾ}}</translation>
-<translation id="3093245981617870298">നിങ്ങൾ ഓഫ്‌ലൈനിലാണ്.</translation>
<translation id="3096100844101284527">പിക്കപ്പ് വിലാസം ചേർക്കുക</translation>
<translation id="3105172416063519923">അസറ്റ് ഐഡി:</translation>
<translation id="3109728660330352905">നിങ്ങൾക്ക് ഈ പേജ് കാണാനുള്ള അംഗീകാരമില്ല.</translation>
@@ -361,6 +361,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> നിലവിൽ ലഭ്യമല്ല.</translation>
<translation id="3427092606871434483">അനുവദിക്കുക (ഡിഫോൾട്ട്)</translation>
<translation id="3427342743765426898">&amp;എഡിറ്റുചെയ്യുന്നത് വീണ്ടും ചെയ്യുക</translation>
+<translation id="342781501876943858">മറ്റ് സൈറ്റുകളിൽ നിങ്ങളുടെ പാസ്‌വേഡ് പുനരുപയോഗിച്ചിട്ടുണ്ടെങ്കിൽ, അത് റീസെറ്റ് ചെയ്യാൻ Chromium ശുപാർശ ചെയ്യുന്നു.</translation>
<translation id="3431636764301398940">ഈ ഉപകരണത്തിൽ ഈ കാർഡ് സംരക്ഷിക്കുക</translation>
<translation id="3447661539832366887">ഈ ഉപകരണത്തിന്റെ ഉടമ ദിനോസർ ഗെയിം ഓഫാക്കി.</translation>
<translation id="3447884698081792621">സർട്ടിഫിക്കറ്റ് (<ph name="ISSUER" /> ഇഷ്യൂ ചെയ്‌തത്) കാണിക്കുക</translation>
@@ -397,7 +398,6 @@
<translation id="3678529606614285348">പുതിയ അദൃശ്യ വിൻഡോയിൽ പേജ് തുറക്കുക (കൺട്രോൾ-ഷിഫ്റ്റ്-N)</translation>
<translation id="3679803492151881375">ക്രാഷ് റിപ്പോർട്ട് <ph name="CRASH_TIME" />-ന് ക്യാപ്‌ചർ ചെയ്‌ത്, <ph name="UPLOAD_TIME" />-ന് അപ്‌ലോഡുചെയ്‌തു</translation>
<translation id="3681007416295224113">സര്‍‌ട്ടിഫിക്കറ്റ് വിവരങ്ങള്‍‌</translation>
-<translation id="3690164694835360974">ലോഗിൻ ചെയ്യുന്നത് സുരക്ഷിതമല്ല</translation>
<translation id="3704162925118123524">നിങ്ങൾ ഉപയോഗിക്കുന്ന നെറ്റ്‌വർക്കിനായി, ഇതിന്റെ ലോഗിൻ പേജ് സന്ദർശിക്കേണ്ടിവരാം.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ലോഡ്ചെയ്യുന്നു...</translation>
@@ -457,7 +457,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">ആഗോള സ്ഥിരശൈലി ഉപയോഗിക്കുക (കണ്ടെത്തുക)</translation>
<translation id="4165986682804962316">സൈറ്റ് ക്രമീകരണങ്ങൾ</translation>
-<translation id="4169947484918424451">Chromium ഈ കാർഡ് സംരക്ഷിക്കണോ?</translation>
<translation id="4171400957073367226">മോശം പരിശോധിച്ചുറപ്പിക്കൽ സിഗ്‌നേച്ചർ</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> ഇനം കൂടി}other{<ph name="ITEM_COUNT" /> ഇനങ്ങൾ കൂടി}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -494,6 +493,7 @@
<translation id="4275830172053184480">നിങ്ങളുടെ ഉപകരണം പുനരാരംഭിക്കുക</translation>
<translation id="4277028893293644418">പാസ്‌വേഡ് റീസെറ്റ് ചെയ്യുക</translation>
<translation id="4280429058323657511">, <ph name="EXPIRATION_DATE_ABBR" />-ന് കാലാവധി തീരുന്നു</translation>
+<translation id="4305817255990598646">സ്വിച്ച് ചെയ്യുക</translation>
<translation id="4312866146174492540">ബ്ലോക്കുചെയ്യുക (ഡിഫോൾട്ട്)</translation>
<translation id="4325863107915753736">ലേഖനം കണ്ടെത്തുന്നത് പരാജയപ്പെട്ടു</translation>
<translation id="4326324639298822553">കാലാവധി തീരുന്ന തീയതി പരിശോധിച്ച് വീണ്ടും ശ്രമിച്ചുനോക്കൂ</translation>
@@ -501,6 +501,7 @@
<translation id="4340982228985273705">എന്റർപ്രൈസ് നിയന്ത്രിക്കുന്ന തരത്തിൽ ഈ കമ്പ്യൂട്ടർ തിരിച്ചറിയപ്പെടുന്നില്ല, അതുകൊണ്ട് Chrome വെബ്‌സ്റ്റോറിൽ ഹോസ്റ്റ് ചെയ്‌തിട്ടുള്ള വിപുലീകരണങ്ങൾ മാത്രമാണ് നയത്തിന് സ്വമേധയാ ഇൻസ്റ്റാൾ ചെയ്യാനാവുക. Chrome വെബ്‌സ്റ്റോർ അപ്‌ഡേറ്റ് URL "<ph name="CWS_UPDATE_URL" />" ആണ്.</translation>
<translation id="4346197816712207223">സ്വീകരിക്കുന്ന ക്രെഡിറ്റ് കാർഡുകൾ</translation>
<translation id="4356973930735388585">ഈ സൈറ്റിലെ ആക്രമണകാരികൾ നിങ്ങളുടെ വിവരങ്ങൾ മോഷ്‌ടിക്കാനോ ഇല്ലാതാക്കാനോ ഇടയുള്ള (ഉദാഹരണത്തിന്, ഫോട്ടോകൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ, ക്രെഡിറ്റ് കാർഡുകൾ എന്നിവ) അപകടകരമായ പ്രോഗ്രാമുകൾ കമ്പ്യൂട്ടറിൽ ഇൻസ്‌റ്റാൾ ചെയ്യാൻ ശ്രമിച്ചേക്കാം.</translation>
+<translation id="4358461427845829800">പേയ്മെന്റ് രീതികൾ മാനേജ് ചെയ്യുക...</translation>
<translation id="4372948949327679948">പ്രതീക്ഷിച്ച <ph name="VALUE_TYPE" /> മൂല്യം.</translation>
<translation id="4377125064752653719">നിങ്ങള്‍‌ <ph name="DOMAIN" /> എന്നതില്‍‌ എത്താന്‍‌ ശ്രമിച്ചു, പക്ഷേ സെര്‍‌വര്‍‌ നൽകിയ സര്‍‌ട്ടിഫിക്കറ്റ് അത് നല്‍‌കിയ ആള്‍‌ അസാധുവാക്കി. സെര്‍‌വര്‍‌ നല്‍‌കിയ സുരക്ഷാ ക്രെഡന്‍‌ഷ്യലുകള്‍‌ തികച്ചും വിശ്വാ‍സയോഗ്യമല്ല എന്നാണ് ഇതിനര്‍‌ത്ഥം. നിങ്ങള്‍‌ ഒരു ആക്രമണകാരിയുമായിട്ടാകാം ആശയവിനിമയം നടത്തുന്നത്.</translation>
<translation id="4406896451731180161">തിരയൽ ഫലങ്ങൾ</translation>
@@ -508,6 +509,7 @@
<translation id="4415426530740016218">പിക്കപ്പ് വിലാസം</translation>
<translation id="4424024547088906515">ഈ സെർവറിന് അത് <ph name="DOMAIN" /> ആണെന്ന് തെളിയിക്കാനായില്ല; അതിന്റെ സുരക്ഷാ സർട്ടിഫിക്കറ്റ് Chrome-ന് പരിചയമില്ലാത്തതാണ്. തെറ്റായ കോൺഫിഗറേഷൻ കാരണമോ ഒരു അക്രമണകാരി നിങ്ങളുടെ കണക്ഷനെ തടസ്സപ്പെടുത്തുന്നത് കൊണ്ടോ ആയിരിക്കാം ഇത് സംഭവിച്ചത്.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" />, നിങ്ങളുടെ ലോഗിൻ സർട്ടിഫിക്കറ്റിന് അംഗീകരിച്ചിട്ടില്ല, അല്ലെങ്കിൽ അങ്ങനെയൊരെണ്ണം നൽകിയിട്ടില്ലായിരിക്കാം.</translation>
+<translation id="4434045419905280838">പോപ്-അപ്പുകളും റീഡയറക്‌റ്റുകളും</translation>
<translation id="443673843213245140">പ്രോക്‌സി ഉപയോഗം അപ്രാപ്‌തമാക്കി പക്ഷെ ഒരു വ്യക്തമായ പ്രോക്‌സി കോൺഫിഗറേഷൻ നിർദ്ദേശിച്ചു.</translation>
<translation id="445100540951337728">ഡെബിറ്റ് കാർഡുകൾ സ്വീകരിക്കുന്നു</translation>
<translation id="4506176782989081258">മൂല്യനിർണ്ണയ പിശക്: <ph name="VALIDATION_ERROR" /></translation>
@@ -542,13 +544,13 @@
<translation id="4759118997339041434">പേയ്‌മെന്റ് സ്വയമേവ പൂരിപ്പിക്കൽ പ്രവർത്തനരഹിതമാക്കി</translation>
<translation id="4764776831041365478"><ph name="URL" /> ലെ വെബ്‌പേജ് താല്‍‌ക്കാലികമായി പ്രവര്‍‌ത്തനരഹിതമായിരിക്കാം, അല്ലെങ്കില്‍‌ ഒരു പുതിയ വെബ് വിലാസത്തിലേക്ക് ശാശ്വതമായി നീക്കംചെയ്യപ്പെട്ടിരിക്കാം.</translation>
<translation id="4771973620359291008">ഒരു അജ്ഞാത പിശക് സംഭവിച്ചു.</translation>
+<translation id="4785689107224900852">ഈ ടാബിലേക്ക് സ്വിച്ച് ചെയ്യുക</translation>
<translation id="4792143361752574037">സെഷൻ ഫയലുകൾ ആക്‌സസ്സ് ചെയ്യുന്നതിൽ ഒരു പ്രശ്നം ഉണ്ടായിരുന്നു. ഡിസ്‌ക്കിലേക്ക് സംരക്ഷിക്കുന്നത് നിലവിൽ പ്രവർത്തനരഹിതമാക്കി. വീണ്ടും ശ്രമിക്കാൻ പേജ് റീലോഡ് ചെയ്യുക.</translation>
<translation id="4800132727771399293">നിങ്ങളുടെ കാലഹരണ തീയതിയും CVC യും പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Google Chrome-ന് പ്രോസസ്സുചെയ്യാനാകാത്ത രൂപമാറ്റം വരുത്തിയ ക്രെഡൻഷ്യലുകൾ വെബ്സൈറ്റ് അയയ്ക്കുന്നതിനാൽ നിങ്ങൾക്കിപ്പോൾ <ph name="SITE" /> സന്ദർശിക്കാനാകില്ല.നെറ്റ്‌വർക്ക് പിശകുകളും ആക്രമണങ്ങളും സാധാരണയായി താൽക്കാലികമായതിനാൽ, ഈ പേജ് മിക്കവാറും പിന്നീട് പ്രവർത്തിക്കും.</translation>
<translation id="4813512666221746211">നെറ്റ്‌വര്‍ക്ക് പിശക്</translation>
<translation id="4816492930507672669">പേജിന് യുക്തമാക്കുക</translation>
-<translation id="483020001682031208">കാണിക്കാൻ പ്രത്യക്ഷ വെബ് പേജുകളില്ല</translation>
<translation id="4850886885716139402">കാണുക</translation>
<translation id="4854362297993841467">ഈ ഡെലിവറി രീതി ലഭ്യമല്ല. മറ്റൊരു രീതി പരീക്ഷിക്കുക.</translation>
<translation id="4858792381671956233">ഈ സൈറ്റ് സന്ദർശിക്കുന്നതിന് നിങ്ങൾ രക്ഷിതാക്കളോട് അനുമതി ആവശ്യപ്പെട്ടു</translation>
@@ -588,6 +590,7 @@
<translation id="5115563688576182185">(64-ബിറ്റ്)</translation>
<translation id="5121084798328133320">സ്ഥിരീകരിച്ച് കഴിഞ്ഞാൽ, നിങ്ങളുടെ Google പേയ്‌മെന്‍റ് അക്കൗണ്ടിൽ നിന്നുള്ള കാർഡ് വിശദാംശങ്ങൾ ഈ സൈറ്റുമായി പങ്കിടും.</translation>
<translation id="5128122789703661928">സെഷന്‍റെ പേര് തെറ്റായതിനാൽ ഇല്ലാതാക്കാനായില്ല.</translation>
+<translation id="5135404736266831032">വിലാസങ്ങൾ മാനേജ് ചെയ്യുക...</translation>
<translation id="5141240743006678641">Google ക്രെഡൻഷ്യലുകൾ ഉപയോഗിച്ച് സമന്വിത പാസ്‌വേഡുകൾ എൻക്രിപ്റ്റുചെയ്യുക</translation>
<translation id="5145883236150621069">നയ പ്രതികരണത്തിൽ പിശക് കോഡ് ഉണ്ട്</translation>
<translation id="5159010409087891077">പുതിയൊരു അദൃശ്യ വിൻഡോയിൽ പേജ് തുറക്കുക (⇧⌘N)</translation>
@@ -599,7 +602,6 @@
<translation id="5201306358585911203">ഈ പേജിലെ ഉൾച്ചേർത്ത പേജ് പറയുന്നത്:</translation>
<translation id="5205222826937269299">പേര് ആവശ്യമാണ്</translation>
<translation id="5222812217790122047">ഇമെയിൽ ആവശ്യമാണ്</translation>
-<translation id="522700295135997067">നിങ്ങളുടെ പാസ്‍വേഡ് ഈ സൈറ്റ് ഇപ്പോൾ മോഷ്‌ടിച്ചിരിക്കാം</translation>
<translation id="5230733896359313003">ഷിപ്പിംഗ് വിലാസം</translation>
<translation id="5250209940322997802">"നെറ്റ്‌വർക്കിലേക്ക് കണക്‌റ്റ് ചെയ്യുക"</translation>
<translation id="5251803541071282808">ക്ലൗഡ്</translation>
@@ -643,7 +645,6 @@
<translation id="5492298309214877701">കമ്പനി, ഓർഗനൈസേഷൻ അല്ലെങ്കിൽ സ്‌കൂൾ ഇൻട്രാനെറ്റിലെ ഈ സൈറ്റിന്, ബാഹ്യ വെബ്‌സൈറ്റിന് സമാനമായ URL ആണുള്ളത്.
<ph name="LINE_BREAK" />
നിങ്ങളുടെ സിസ്‌റ്റം അഡ്‌മിനിസ്‌ട്രേറ്ററുമായി ബന്ധപ്പെടാൻ ശ്രമിക്കുക.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> കാർഡിനുള്ള സുരക്ഷാ കോഡ് നൽകുക. ഈ കോഡ് സംരക്ഷിക്കപ്പെടില്ല.</translation>
<translation id="5509780412636533143">നിയന്ത്രിത ബുക്കുമാർക്കുകൾ</translation>
<translation id="5510766032865166053">ഇത് നീക്കുകയോ ഇല്ലാതാക്കുകയോ ചെയ്‌തിരിക്കാം.</translation>
<translation id="5523118979700054094">നയത്തിന്റെ പേര്</translation>
@@ -674,9 +675,11 @@
<translation id="5685654322157854305">ഷിപ്പിംഗ് വിലാസം ചേർക്കുക</translation>
<translation id="5689199277474810259">JSON-ലേക്ക് ‌എക്‌സ്‌പോർട്ട് ചെയ്യുക</translation>
<translation id="5689516760719285838">ലൊക്കേഷൻ</translation>
+<translation id="570530837424789914">മാനേജ് ചെയ്യുക...</translation>
<translation id="5710435578057952990">ഈ വെബ്സൈറ്റിന്റെ വ്യക്തിത്വം പരിശോധിച്ചിട്ടില്ല.</translation>
<translation id="5719499550583120431">പ്രീപെയ്ഡ് കാർഡുകൾ സ്വീകരിക്കുന്നു.</translation>
<translation id="5720705177508910913">നിലവിലെ ഉപയോക്താവ്</translation>
+<translation id="5730040223043577876">മറ്റ് സൈറ്റുകളിൽ നിങ്ങളുടെ പാസ്‌വേഡ് പുനരുപയോഗിച്ചിട്ടുണ്ടെങ്കിൽ, അത് പുനഃസജ്ജീകരിക്കാൻ Chrome ശുപാർശ ചെയ്യുന്നു.</translation>
<translation id="5732392974455271431">നിങ്ങൾക്ക് വേണ്ടി ഇത് അൺബ്ലോക്കുചെയ്യാൻ രക്ഷിതാക്കൾക്ക് കഴിയും</translation>
<translation id="5763042198335101085">ശരിയായ ഇമെയിൽ വിലാസം നൽകുക</translation>
<translation id="5765072501007116331">ഡെലിവറി രീതികളും ആവശ്യകതകളും കാണാൻ ഒരു വിലാസം തിരഞ്ഞെടുക്കുക</translation>
@@ -700,9 +703,7 @@
<translation id="5959728338436674663">അപകടകരമായ ആപ്‌സുകളും സൈറ്റുകളും കണ്ടെത്താൻ സഹായിക്കുന്നതിന്‌ ചില <ph name="BEGIN_WHITEPAPER_LINK" />സിസ്‌റ്റം വിവരങ്ങളും പേജ്‌ ഉള്ളടക്കവും<ph name="END_WHITEPAPER_LINK" /> Google-ന്‌ സ്വയമേവ അയയ്‌ക്കുക. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">കോൺടാക്‌റ്റ് വിവരം എഡിറ്റുചെയ്യുക</translation>
<translation id="5967867314010545767">ചരിത്രത്തിൽ നിന്നും നീക്കംചെയ്യുക</translation>
-<translation id="5972020793760134803">ടാബിലേക്ക് മാറുക</translation>
<translation id="5975083100439434680">സൂം ഔട്ട്</translation>
-<translation id="597552863672748783">സുരക്ഷാ കോഡ് സ്ഥിരീകരിക്കുക</translation>
<translation id="598637245381783098">പേയ്‌മെന്റ് ആപ്പ് തുറക്കാനായില്ല</translation>
<translation id="5989320800837274978">ഒരു സ്ഥിരമായ പ്രോക്സി സെർവർ അല്ലെങ്കിൽ ഒരു .pac സ്‌ക്രിപ്റ്റ് URL വ്യക്തമാക്കിയിട്ടില്ല.</translation>
<translation id="5990559369517809815">സെർവറിലേക്കുള്ള അഭ്യർത്ഥനകൾ ഒരു വിപുലീകരണം തടഞ്ഞു.</translation>
@@ -718,6 +719,7 @@
<translation id="6047927260846328439">സോഫ്‌റ്റ്‌വെയർ ഇൻസ്‌റ്റാൾ ചെയ്യുന്നതിലേക്കോ വ്യക്തിഗത വിവരങ്ങൾ വെളിപ്പെടുത്തുന്നതിലേക്കോ നിങ്ങളെ തന്ത്രപൂർവ്വം നയിച്ചുകൊണ്ട്, ഈ ഉള്ളടക്കം നിങ്ങളെ കബളിപ്പിക്കാൻ ശ്രമിച്ചേക്കാം. <ph name="BEGIN_LINK" />എന്തായാലും കാണിക്കുക<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> എന്ന വെബ്‌സൈറ്റ് സർട്ടിഫിക്കറ്റ് പിന്നിംഗ് ഉപയോഗിക്കുന്നതിനാൽ നിങ്ങൾക്കിപ്പോൾ അത് സന്ദർശിക്കാനാകില്ല. നെറ്റ്‌വർക്ക് പിശകുകളും ആക്രമണങ്ങളും സാധാരണയായി താൽക്കാലികമായിരിക്കും, അതിനാൽ ഈ പേജ് മിക്കവാറും പിന്നീട് പ്രവർത്തിക്കും.</translation>
<translation id="6059925163896151826">USB ഉപകരണങ്ങൾ</translation>
+<translation id="6071091556643036997">സാധുതയില്ലാത്ത നയ തരം.</translation>
<translation id="6080696365213338172">അഡ്‌മിനിസ്‌ട്രേറ്റർ നൽകിയ സർട്ടിഫിക്കറ്റ് ഉപയോഗിച്ച് നിങ്ങൾ ഉള്ളടക്കം ആക്‌സസ്സുചെയ്‌തു. നിങ്ങൾ <ph name="DOMAIN" /> എന്നതിലേക്ക് നൽകുന്ന ഡാറ്റ അഡ്‌മിനിസ്‌ട്രേറ്റർക്ക് തടയാനാവും.</translation>
<translation id="610911394827799129">നിങ്ങളുടെ Google അക്കൗണ്ടിന് <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> എന്നതിൽ മറ്റ് തരത്തിലുള്ള ബ്രൗസിംഗ് ചരിത്രമുണ്ടായിരിക്കാം.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ഒന്നുമില്ല}=1{ഒരു പാസ്‌വേഡ് (സമന്വയിപ്പിച്ചത്)}other{# പാസ്‌വേഡുകൾ (സമന്വയിപ്പിച്ചത്)}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">കൂടുതൽ വിവരങ്ങൾ ചേർക്കുക</translation>
<translation id="6447842834002726250">കുക്കികള്‍</translation>
<translation id="6451458296329894277">വീണ്ടും സമര്‍പ്പിക്കല്‍ അപേക്ഷ ഉറപ്പാക്കുക</translation>
+<translation id="6465306955648956876">പാസ്‌വേഡുകൾ മാനേജ് ചെയ്യുക...</translation>
<translation id="647261751007945333">ഉപകരണ നയങ്ങൾ</translation>
<translation id="6477321094435799029">Chrome, ഈ പേജിൽ അസാധാരണമായ കോഡ് കണ്ടെത്തിയതിനാൽ നിങ്ങളുടെ വ്യക്തിഗത വിവരങ്ങൾ (ഉദാഹരണത്തിന്, പാസ്‌വേഡുകളും ഫോൺ നമ്പറുകളും ക്രെഡിറ്റ് കാർഡുകളും പോലുള്ളവ) പരിരക്ഷിക്കുന്നതിന് അതിനെ ബ്ലോക്കുചെയ്‌തു.</translation>
<translation id="6489534406876378309">ക്രാഷുകൾ അപ്‌ലോഡുചെയ്യുന്നത് ആരംഭിക്കുക</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> തിരയൽ</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> എന്ന സൈറ്റിലെ നിലവിലുള്ള ആക്രമികൾ നിങ്ങളുടെ വിവരങ്ങൾ ഇല്ലാതാക്കാനോ മോഷ്‌ടിക്കാനോ ഇടയുള്ള (ഉദാഹരണത്തിന്, ഫോട്ടോകൾ, പാസ്‌വേഡുകൾ, സന്ദേശങ്ങൾ, ക്രെഡിറ്റ് കാർഡുകൾ മുതലായവ) അപകടകരമായ പ്രോഗ്രാമുകൾ Mac-ൽ ഇൻസ്‌റ്റാളുചെയ്യാൻ ശ്രമിച്ചേക്കാം. <ph name="BEGIN_LEARN_MORE_LINK" />കൂടുതലറിയുക<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">ഈ നയം ഒഴിവാക്കി.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{ഒന്നുമില്ല}=1{ഒരു സൈറ്റിൽ നിന്ന് (നിങ്ങൾ Google അക്കൗണ്ടിൽ നിന്ന് സൈൻ ഔട്ട് ചെയ്യപ്പെടില്ല)}other{# സൈറ്റുകളിൽ നിന്ന് (നിങ്ങൾ Google അക്കൗണ്ടിൽ നിന്ന് സൈൻ ഔട്ട് ചെയ്യപ്പെടില്ല)}}</translation>
<translation id="6657585470893396449">പാസ്‌വേഡ്</translation>
<translation id="6671697161687535275">Chromium-ത്തിൽ നിന്ന് ഫോം നിർദ്ദേശം നീക്കംചെയ്യണോ?</translation>
<translation id="6685834062052613830">സൈൻ ഔട്ട് ചെയ്‌ത്, സജ്ജമാക്കൽ പൂർത്തിയാക്കുക</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">ഉപയോക്താവ്:</translation>
<translation id="6945221475159498467">തിരഞ്ഞെടുക്കുക</translation>
<translation id="6948701128805548767">പിക്ക്അപ്പ് രീതികളും ആവശ്യകതകളും കാണാൻ ഒരു വിലാസം തിരഞ്ഞെടുക്കുക</translation>
+<translation id="6949872517221025916">പാസ്‌വേഡ് പുനഃസജ്ജീകരിക്കുക</translation>
<translation id="6957887021205513506">സെർവറിന്റെ സർട്ടിഫിക്കറ്റ് വിശ്വസിക്കാൻ കൊള്ളാത്ത ഒന്നായി തോന്നുന്നു.</translation>
<translation id="6965382102122355670">ശരി</translation>
<translation id="6965978654500191972">ഉപാധി</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">ഡെലിവറി രീതി</translation>
<translation id="7139724024395191329">എമിറേറ്റ്</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> എണ്ണവും}other{<ph name="PAYMENT_METHOD_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> എണ്ണവും}}</translation>
-<translation id="7155487117670177674">പേയ്‌മെന്റ് സുരക്ഷിതമല്ല</translation>
+<translation id="717330890047184534">Gaia ഐഡി:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> എണ്ണവും}other{<ph name="SHIPPING_OPTION_PREVIEW" /> എന്നതും മറ്റ് <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> എണ്ണവും}}</translation>
<translation id="7180611975245234373">പുതുക്കുക</translation>
<translation id="7182878459783632708">നയങ്ങളൊന്നും സജ്ജമാക്കിയിട്ടില്ല</translation>
@@ -878,6 +883,7 @@
<translation id="7455133967321480974">ഗ്ലോബൽ ഡിഫോൾട്ട് ഉപയോഗിക്കുക (തടയുക)</translation>
<translation id="7460163899615895653">മറ്റ് ഉപകരണങ്ങളിൽ നിന്നുള്ള അടുത്തിടെയുള്ള നിങ്ങളുടെ ടാബുകൾ ഇവിടെ ദൃശ്യമാകും</translation>
<translation id="7469372306589899959">കാർഡ് സ്ഥിരീകരിക്കുന്നു</translation>
+<translation id="7473891865547856676">വേണ്ട, നന്ദി</translation>
<translation id="7481312909269577407">മുന്നോട്ട്</translation>
<translation id="7485870689360869515">ഡാറ്റകളൊന്നും കണ്ടെത്തിയില്ല.</translation>
<translation id="7508255263130623398">നൽകിയ നയ ഉപകരണ ഐഡി ശൂന്യമാണ് അല്ലെങ്കിൽ നിലവിലെ ഉപകരണ ഐഡിയുമായി യോജിക്കുന്നില്ല</translation>
@@ -900,7 +906,6 @@
<translation id="7569952961197462199">Chrome-ൽ നിന്ന് ക്രെഡിറ്റ് കാർഡ് നീക്കംചെയ്യണോ?</translation>
<translation id="7575800019233204241">"നിങ്ങളുടെ കണക്ഷൻ സ്വകാര്യമല്ല" അല്ലെങ്കിൽ "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" അല്ലെങ്കിൽ "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" അല്ലെങ്കിൽ "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" അല്ലെങ്കിൽ "SSL സർട്ടിഫിക്കറ്റ് പിശക്"</translation>
<translation id="7578104083680115302">നിങ്ങൾ Google-ൽ സംരക്ഷിച്ച കാർഡുകൾ ഉപയോഗിച്ച് ഉപകരണങ്ങളിലുടനീളമുള്ള സൈറ്റുകളിലും ആപ്‌സിലും പെട്ടെന്ന് പണമടയ്‌ക്കുക.</translation>
-<translation id="7588950540487816470">ഫിസിക്കൽ വെബ്</translation>
<translation id="7592362899630581445">സെർവറിന്റെ സർട്ടിഫിക്കറ്റ് പേരിന്റെ പരിധി ലംഘിക്കുന്നു.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" />-യിൽ താഴെ</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" />-ന് നിലവിൽ ഈ അഭ്യർത്ഥന കൈകാര്യം ചെയ്യാനാകുന്നില്ല.</translation>
@@ -1104,6 +1109,7 @@
<translation id="9148507642005240123">&amp;എഡിറ്റുചെയ്യുന്നത് പഴയപടിയാക്കുക</translation>
<translation id="9154194610265714752">അപ്‌ഡേറ്റുചെയ്‌തു</translation>
<translation id="9157595877708044936">സജ്ജീകരിക്കുന്നു...</translation>
+<translation id="9168814207360376865">നിങ്ങൾ പേയ്‌മെന്റ് രീതികൾ സംരക്ഷിച്ചിട്ടുണ്ടോ എന്ന് പരിശോധിക്കാൻ സൈറ്റുകളെ അനുവദിക്കുക</translation>
<translation id="9169664750068251925">ഈ സൈറ്റിൽ എല്ലായ്‌പ്പോഴും തടയുക</translation>
<translation id="9170848237812810038">‍&amp;പൂര്‍വാവസ്ഥയിലാക്കുക</translation>
<translation id="917450738466192189">സെര്‍വറിന്‍റെ സര്‍ട്ടിഫിക്കറ്റ് അസാധുവാണ്.</translation>
@@ -1112,7 +1118,6 @@
<translation id="9207861905230894330">ലേഖനം ചേർക്കുന്നത് പരാജയപ്പെട്ടു.</translation>
<translation id="9215416866750762878">ഈ സൈറ്റിലേക്ക് സുരക്ഷിതമായി കണക്റ്റുചെയ്യുന്നതിൽ നിന്ന് Chrome-നെ ഒരു ആപ്പ് തടയുന്നു</translation>
<translation id="9219103736887031265">ചിത്രങ്ങൾ‌</translation>
-<translation id="933612690413056017">ഇന്റർനെറ്റ്‌ കണക്ഷനില്ല</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ഫോം മായ്‌ക്കുക</translation>
<translation id="939736085109172342">പുതിയ ഫോള്‍ഡര്‍</translation>
diff --git a/chromium/components/strings/components_strings_mr.xtb b/chromium/components/strings/components_strings_mr.xtb
index 48ba7268b85..8e975a492c5 100644
--- a/chromium/components/strings/components_strings_mr.xtb
+++ b/chromium/components/strings/components_strings_mr.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> ची परवानगी निवडा</translation>
<translation id="1111153019813902504">अलीकडील बुकमार्क</translation>
<translation id="1113869188872983271">&amp;पुनर्क्रमित करा पूर्ववत करा</translation>
+<translation id="1125573121925420732">वेबसाइट त्यांची सुरक्षितता अपडेट करत असताना चेतावण्या सामान्य असू शकतात. यात लवकरच सुधारणा व्हावी.</translation>
<translation id="1126551341858583091">स्थानिक संचयावरील आकार <ph name="CRASH_SIZE" /> आहे.</translation>
<translation id="112840717907525620">धोरण कॅश ठीक</translation>
<translation id="1150979032973867961">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षितता प्रमाणपत्र आपल्या संगणकाच्या ऑपरेटिंग प्रणालीद्वारे विश्वसनीय नाही. हे कदाचित एका चुकीच्या कॉन्फिगरेशनमुळे किंवा आक्रमणकर्त्याने आपले कनेक्शन आंतरखंडित केल्यामुळे झाले असू शकते.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;तुमचे इंटरनेट कनेक्शन नेहमीप्रमाणे चालत असल्याची खात्री करा.&lt;/li&gt;
&lt;li&gt;वेबसाइटच्या मालकाशी संपर्क साधा.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">तुमच्या संस्थेद्वारे व्यवस्थापित केल्या न जाणाऱ्या साइटवर तुम्ही तुमचा पासवर्ड एंटर केला आहे. तुमचे खाते संरक्षित करण्यासाठी इतर अॅप्स आणि साइतवर तुमच्या पासवर्डचा पुन्हा वापर करू नका.</translation>
<translation id="1263231323834454256">वाचन सूची</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> वाजता क्रॅश अहवाल कॅप्चर केला (अद्याप अपलोड केलेला नाही किंवा दुर्लक्ष केले)</translation>
<translation id="1270502636509132238">घेण्याची पद्धत</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">निवडा</translation>
<translation id="1620510694547887537">कॅमेरा</translation>
<translation id="1623104350909869708">या पृष्ठास अतिरिक्त संवाद तयार करण्यापासून प्रतिबंधित करा</translation>
-<translation id="1629803312968146339">Chrome ने हे कार्ड सेव्ह करावे असे आपण इच्छिता?</translation>
<translation id="1639239467298939599">लोड करीत आहे</translation>
<translation id="1640180200866533862">वापरकर्ता धोरणे</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />साइटच्या मुख्यपृष्ठावर भेट देऊन<ph name="END_LINK" /> पहा.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows नेटवर्क निदान चालवून पहा<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">कृपया आपले संंकालित सांकेतिक वाक्यांश अपडेट करा.</translation>
<translation id="1787142507584202372">आपले खुले टॅब येथे दिसतात</translation>
-<translation id="1789575671122666129">पॉपअप</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">कार्डधारकाचे नाव</translation>
<translation id="1806541873155184440">जोडले: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">आपला कॉंप्युटर रीस्टार्ट करा</translation>
<translation id="2113977810652731515">कार्ड</translation>
<translation id="2114841414352855701">दुर्लक्ष केले कारण ते <ph name="POLICY_NAME" /> कडून अधिलिखित झाले होते.</translation>
-<translation id="2138201775715568214">जवळपासची वास्तविक वेब पेज शोधत आहात</translation>
<translation id="213826338245044447">Mobile बुकमार्क</translation>
<translation id="214556005048008348">पेमेंट रद्द करा</translation>
<translation id="2147827593068025794">पार्श्वभूमी संकालन</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">धोरण आढळले नाही</translation>
<translation id="2213606439339815911">प्रविष्ट्या आणत आहे...</translation>
<translation id="2218879909401188352">सध्या <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />वर असलेले आक्रमणकर्ता तुमच्या डिव्हाइसला हानी पोहोचवणारे धोकादायक अॅप इंस्टॉल करू शकतात, तुमच्या मोबाइल बिलामध्ये लपलेले शुल्क जोडू शकतात किंवा तुमची वैयक्तिक माहिती चोरू शकतात. <ph name="BEGIN_LEARN_MORE_LINK" />अधिक जाणून घ्या<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">इंटरनेट नाही</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />निदान अॅप<ph name="END_LINK" /> वापरून आपल्या कनेक्शनचे निराकरण करा</translation>
<translation id="2239100178324503013">आता पाठवा</translation>
<translation id="225207911366869382">हे मूल्य या धोरणासाठी नापसंत करण्‍यात आले आहे.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">निवडलेले आयटम काढा</translation>
<translation id="277133753123645258">शिपिंग पद्धत</translation>
<translation id="277499241957683684">डिव्हाइस रेकॉर्ड गहाळ</translation>
+<translation id="2781030394888168909">MacOS निर्यात करा</translation>
<translation id="2784949926578158345">कनेक्शन रीसेट केले.</translation>
<translation id="2788784517760473862">क्रेडिट कार्डे स्वीकारली जातात</translation>
<translation id="2794233252405721443">साइट अवरोधित केली</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome यावेळी आपल्या कार्डची पुष्टी करण्यात अक्षम होते. कृपया नंतर पुन्हा प्रयत्न करा.</translation>
<translation id="3064966200440839136">बाह्य अॅप्लिकेशन द्वारे देय देण्यासाठी गुप्त मोड सोडत आहे. सुरु ठेवायचे?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{काहीही नाही}=1{1 पासवर्ड}one{# पासवर्ड}other{# पासवर्ड}}</translation>
-<translation id="3093245981617870298">आपण ऑफलाइन आहात.</translation>
<translation id="3096100844101284527">पिकअप पत्ता जोडा</translation>
<translation id="3105172416063519923">मालमत्ता आयडी:</translation>
<translation id="3109728660330352905">हे पृष्ठ पाहण्यासाठी आपण प्राधिकृत नाही.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> सध्या आवाक्याबाहेर आहे.</translation>
<translation id="3427092606871434483">अनुमती द्या (डीफॉल्ट)</translation>
<translation id="3427342743765426898">&amp;संपादित करा पुन्हा करा</translation>
+<translation id="342781501876943858">जर तुम्ही तुमच्या पासवर्डचा इतर साइटवर पुन्हा वापर केला असेल तर Chromium तुम्हाला तो रीसेट करण्याची शिफारस करतो.</translation>
<translation id="3431636764301398940">या डिव्हाइसवर हे कार्ड सेव्ह करा</translation>
<translation id="3447661539832366887">या डिव्हाइसच्या मालकाने डायनासोर गेम बंद केला आहे.</translation>
<translation id="3447884698081792621">सर्टिफिकेट दाखवा (<ph name="ISSUER" /> ने जारी केलेले)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">पेज एका नवीन गुप्त विंडोमध्ये उघडा (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">क्रॅश अहवाल <ph name="CRASH_TIME" /> वाजता कॅप्चर केला, <ph name="UPLOAD_TIME" /> वाजता अपलोड केला</translation>
<translation id="3681007416295224113">प्रमाणपत्र माहिती...</translation>
-<translation id="3690164694835360974">लॉग इन सुरक्षित नाही</translation>
<translation id="3704162925118123524">आपण वापरत असलेल्या नेटवर्कला आपण त्याच्या लॉग इन पृष्ठास भेट देण्याची आवश्यकता असू शकते.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">लोड करीत आहे...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">जागतिक डीफॉल्‍ट (शोधणे) वापरा</translation>
<translation id="4165986682804962316">साइट सेटिंग्ज</translation>
-<translation id="4169947484918424451">Chromium ने हे कार्ड सेव्ह करावे असे आपण इच्छिता?</translation>
<translation id="4171400957073367226">खराब पडताळणी स्वाक्षरी</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{आणखी <ph name="ITEM_COUNT" /> आयटम}one{आणखी <ph name="ITEM_COUNT" /> आयटम}other{आणखी <ph name="ITEM_COUNT" /> आयटम}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">आपला डिव्हाइस रीस्टार्ट करा</translation>
<translation id="4277028893293644418">पासवर्ड रीसेट करा</translation>
<translation id="4280429058323657511">, कालबाह्यता <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">स्विच</translation>
<translation id="4312866146174492540">अवरोधित करा (डीफॉल्ट)</translation>
<translation id="4325863107915753736">लेख शोधण्यात अयशस्वी</translation>
<translation id="4326324639298822553">तुमची कालबाह्यता तारीख तपासा आणि पुन्हा प्रयत्न करा</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">हा कॉंम्पुटर एंटरप्राइझ व्यवस्थापित म्हणून आढळला नाही म्हणून धोरण फक्त Chrome वेबस्टोअरवर होस्ट केलेले एक्सटेंशन आपोआप इंस्टॉल करू शकते. Chrome वेबस्टोअर अपडेट URL <ph name="CWS_UPDATE_URL" /> ही आहे.</translation>
<translation id="4346197816712207223">स्वीकारली जाणारी क्रेडिट कार्डे</translation>
<translation id="4356973930735388585">या साइट वरील आक्रमणकर्ते तुमची माहिती (उदाहरणार्थ, फोटो, पासवर्ड, संदेश आणि क्रेडिट कार्ड) चोरणारे किंवा हटविणारे धोकादायक प्रोग्राम आपल्या संगणकावर इंस्टॉल करण्‍याचा प्रयत्न करू शकतात.</translation>
+<translation id="4358461427845829800">पेमेंट पद्धती व्यवस्थापित करा</translation>
<translation id="4372948949327679948">अपेक्षित <ph name="VALUE_TYPE" /> मूल्य.</translation>
<translation id="4377125064752653719">आपण <ph name="DOMAIN" /> वर पोहोचण्याचा प्रयत्न केला, परंतु सर्व्हरने सादर केलेले प्रमाणपत्र त्याच्या जारीकर्त्याद्वारे मागे घेतले गेले आहे. याचा अर्थ सर्व्हरने सादर केलेल्या सुरक्षा क्रेडेन्शियलवर अजिबात ठेवला जाऊ नये. आपण कदाचित आक्रमणकर्त्याशी संवाद प्रस्थापित करत आहात.</translation>
<translation id="4406896451731180161">शोध परिणाम</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">घेण्याचा पत्ता</translation>
<translation id="4424024547088906515">हा सर्व्हर हे <ph name="DOMAIN" /> असल्याचे सिद्ध करू शकला नाही; त्याचे सुरक्षितता प्रमाणपत्र Chrome द्वारे विश्वसनीय नाही. हे कदाचित एका चुकीच्या कॉन्फिगरेशनमुळे किंवा आक्रमणकर्त्याने आपले कनेक्शन आंतरखंडित केल्यामुळे झाले असू शकते.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ने आपले लॉग इन प्रमाणपत्र स्वीकारले नाही किंवा कदाचित प्रदान केले गेले नसावे.</translation>
+<translation id="4434045419905280838">पॉप-अप आणि रीडिरेक्ट</translation>
<translation id="443673843213245140">प्रॉक्सीचा वापर अक्षम करण्‍यात आला आहे पण एक सुस्पष्‍ट प्रॉक्सी कॉन्‍फिगरेशन निर्दिष्‍ट करण्‍यात आले आहे.</translation>
<translation id="445100540951337728">डेबिट कार्डे स्वीकारली जातात</translation>
<translation id="4506176782989081258">प्रमाणीकरण एरर: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">पेमेंट स्वयंभरण अक्षम केले</translation>
<translation id="4764776831041365478"><ph name="URL" /> येथील वेबपृष्ठ कदाचित तात्पुरते बंद आहे किंवा ते कदाचित कायमचे नवीन वेब पत्त्यावर हलवले आहे.</translation>
<translation id="4771973620359291008">एक अज्ञात एरर आली आहे.</translation>
+<translation id="4785689107224900852">या टॅबवर स्विच करा</translation>
<translation id="4792143361752574037">सेशन फायली अ‍ॅक्सेस करताना अडचण आली. डिस्कवर सेव्ह करणे सध्या बंद केलेले आहे. पुन्हा प्रयत्न करण्यासाठी कृपया पेज रीलोड करा.</translation>
<translation id="4800132727771399293">तुमची कालबाह्यता तारीख आणि CVC तपासा आणि पुन्हा प्रयत्न करा</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Google Chrome प्रक्रिया करू शकत नाही असे न समजणारे क्रेडेन्शियल वेबसाइटने पाठविल्यामुळे आपण आत्ता <ph name="SITE" /> ला भेट देऊ शकत नाही. नेटवर्क एरर आणि आक्रमण सामान्यतः तात्पुरते असतात, यामुळे हे पृष्ठ कदाचित नंतर कार्य करेल.</translation>
<translation id="4813512666221746211">नेटवर्क एरर</translation>
<translation id="4816492930507672669">पृष्‍ठानुरुप करा</translation>
-<translation id="483020001682031208">दर्शविण्यासाठी कोणतीही वास्तविक वेब पेज नाहीत</translation>
<translation id="4850886885716139402">पहा</translation>
<translation id="4854362297993841467">ही वितरण पद्धत उपलब्ध नाही. वेगळी पद्धत वापरून पहा.</translation>
<translation id="4858792381671956233">या साइटला भेट देणे ठीक आहे का ते आपण आपल्‍या पालकांना विचारले</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-बिट)</translation>
<translation id="5121084798328133320">तुम्ही निश्चित केल्यानंतर, तुमच्या Google पेमेंट खात्यावरील कार्ड तपशील या साइटसोबत शेअर केले जातील.</translation>
<translation id="5128122789703661928">हे नाव असलेले सेशन हटवण्यासाठी वैध नाही.</translation>
+<translation id="5135404736266831032">पत्ते व्यवस्थापित करा...</translation>
<translation id="5141240743006678641">आपल्या Google क्रेडेन्शियलसह संंकालित केलेले पासवर्ड कूटबद्ध करा</translation>
<translation id="5145883236150621069">धोरण प्रतिसादामध्ये एरर कोड अस्तित्वात आहे</translation>
<translation id="5159010409087891077">नवीन गुप्त विंडोमध्ये पेज उघडा (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">या पेजवरील एंबेड केलेल्‍या पेजचे म्हणणे हे आहे की</translation>
<translation id="5205222826937269299">नाव आवश्यक आहे</translation>
<translation id="5222812217790122047">ईमेल आवश्यक आहे</translation>
-<translation id="522700295135997067">या साइटने कदाचित तुमचा पासवर्ड चोरला असेल</translation>
<translation id="5230733896359313003">पाठविण्याचा पत्ता</translation>
<translation id="5250209940322997802">"नेटवर्कशी कनेक्ट करा"</translation>
<translation id="5251803541071282808">क्लाउड</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">कंपनी, संस्था किंवा शाळा इंट्रानेट वरील या साइटची URL बाह्य वेबसाइटसारखीच आहे.
<ph name="LINE_BREAK" />
सिस्टम प्रशासकाशी संपर्क साधण्याचा प्रयत्न करा.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> साठी सुरक्षा कोड टाका. हा कोड सेव्ह केला जाणार नाही.</translation>
<translation id="5509780412636533143">व्यवस्थापित केलेले बुकमार्क</translation>
<translation id="5510766032865166053">ती कदाचित हलविली किंवा हटविली गेली आहे.</translation>
<translation id="5523118979700054094">धोरणाचे नाव</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">पाठवण्याचा पत्ता जोडा</translation>
<translation id="5689199277474810259">JSON वर निर्यात करा</translation>
<translation id="5689516760719285838">स्थान</translation>
+<translation id="570530837424789914">व्यवस्थापित करा...</translation>
<translation id="5710435578057952990">या वेबसाइटची ओळख सत्यापित केली गेली नाही.</translation>
<translation id="5719499550583120431">प्रीपेड कार्डे स्वीकारली जातात.</translation>
<translation id="5720705177508910913">वर्तमान वापरकर्ता</translation>
+<translation id="5730040223043577876">जर तुम्ही तुमच्या पासवर्डचा इतर साइटवर पुन्हा वापर केला असेल तर Chrome तुम्हाला तो रीसेट करण्याची शिफारस करतो.</translation>
<translation id="5732392974455271431">आपले पालक तुमच्यासाठी ती अनावरोधित करू शकतात</translation>
<translation id="5763042198335101085">वैध ईमेल अॅड्रेस एंटर करा</translation>
<translation id="5765072501007116331">वितरण पद्धती आणि आवश्यकता पाहण्यासाठी, एक पत्ता निवडा</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">धोकादायक अॅप्स आणि साइट शोधण्यात मदत करण्‍यासाठी काही <ph name="BEGIN_WHITEPAPER_LINK" />सिस्टम माहिती आणि पृष्ठ सामग्री<ph name="END_WHITEPAPER_LINK" /> स्वयंचलितपणे Google कडे पाठवा. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">संपर्क माहिती संपादित करा</translation>
<translation id="5967867314010545767">इतिहासातून काढा</translation>
-<translation id="5972020793760134803">टॅबवर स्विच करा</translation>
<translation id="5975083100439434680">झूम कमी करा</translation>
-<translation id="597552863672748783">सुरक्षा कोड निश्चित करा</translation>
<translation id="598637245381783098">पेमेंट अॅप उघडू शकत नाही</translation>
<translation id="5989320800837274978">निश्चित प्रॉक्‍सी सर्व्हर किंवा .pac स्क्रिप्ट URL देखील निर्दिष्‍ट केलेली नाही.</translation>
<translation id="5990559369517809815">सर्व्हरला केल्या जाणार्‍या विनंत्या एका विस्ताराने अवरोधित केल्या गेल्या आहेत.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">हा आशय तुम्हाला सॉफ्टवेअर इंस्टॉल करण्याचा किंवा वैयक्तिक माहिती उघड करण्याचा फसवा प्रयत्न करू शकेल. <ph name="BEGIN_LINK" />तरीही दाखवा<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ही वेबसाइट प्रमाणपत्र पिनिंग वापरत असल्यामुळे तुम्ही आत्ता <ph name="SITE" /> पाहू शकणार नाही. नेटवर्क एरर आणि आक्रमणे शक्यतो तात्पुरती असतात, त्यामुळे हे पेज नंतर पाहता येईल.</translation>
<translation id="6059925163896151826">USB डिव्हाइसेस</translation>
+<translation id="6071091556643036997">धोरणाचा प्रकार चुकीचा आहे.</translation>
<translation id="6080696365213338172">आपण प्रशासकाने-प्रदान केलेले प्रमाणपत्र वापरून सामग्रीमध्ये प्रवेश केला. आपण <ph name="DOMAIN" /> वर प्रदान करता तो डेटा आपल्या प्रशासकाद्वारे अंतःखंडित केला जाऊ शकतो.</translation>
<translation id="610911394827799129">तुमच्या Google खात्यामध्ये <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> वर ब्राउझिंग इतिहासाची अन्य स्वरूपे असू शकतात.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{काहीही नाही}=1{1 पासवर्ड (सिंक केलेला)}one{# पासवर्ड (सिंक केलेला)}other{# पासवर्ड (सिंक केलेले)}}</translation>
@@ -767,6 +769,7 @@
<translation id="6446608382365791566">अधिक माहिती जोडा</translation>
<translation id="6447842834002726250">कुकीज</translation>
<translation id="6451458296329894277">फॉर्म रीसबमिशनची पुष्टी करा</translation>
+<translation id="6465306955648956876">पासवर्ड व्यवस्थापित करा...</translation>
<translation id="647261751007945333">डीव्हाइस धोरणे</translation>
<translation id="6477321094435799029">Chrome ला या पृष्‍ठावर असमान्य कोड सापडला आहे आणि तुमची वैयक्तिक माहिती (उदा, पासवर्ड, फोन नंबर आणि क्रेडिट कार्ड) संरक्षित करण्‍यासाठी अवरोधित केला आहे.</translation>
<translation id="6489534406876378309">क्रॅश अपलोड करणे प्रारंभ करा</translation>
@@ -786,6 +789,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> शोध</translation>
<translation id="6630809736994426279">सध्या <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> वर असलेले हल्लेखोर कदाचित तुमच्या मॅकमधील तुमची माहिती चोरू किंवा हटवू शकणारे धोकादायक प्रोग्राम (उदाहरणार्थ, फोटो, पासवर्ड, संदेश आणि क्रेडिट कार्डे) इंस्टॉल करण्याचा प्रयत्न करू शकतील. <ph name="BEGIN_LEARN_MORE_LINK" />आणखी जाणून घ्या<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">हे धोरण नापसंत आहे.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{काहीही नाही}=1{एका साइटवरून (तुम्हाला तुमच्या Google खात्यातून साइन आउट केले जाणार नाही)}one{# साइटवरून (तुम्हाला तुमच्या Google खात्यातून साइन आउट केले जाणार नाही)}other{# साइटवरून (तुम्हाला तुमच्या Google खात्यातून साइन आउट केले जाणार नाही)}}</translation>
<translation id="6657585470893396449">पासवर्ड</translation>
<translation id="6671697161687535275">Chromium वरून फॉर्म सूचना काढायच्या?</translation>
<translation id="6685834062052613830">साइन आउट करा आणि सेटअप पूर्ण करा</translation>
@@ -812,6 +816,7 @@
<translation id="6915804003454593391">वापरकर्ता:</translation>
<translation id="6945221475159498467">निवडा</translation>
<translation id="6948701128805548767">पिकअप पद्धती आणि आवश्यकता पाहण्यासाठी, एक पत्ता निवडा</translation>
+<translation id="6949872517221025916">पासवर्ड रीसेट करा</translation>
<translation id="6957887021205513506">सर्व्हरचे प्रमाणपत्र खोटे असल्याचे दिसून येते.</translation>
<translation id="6965382102122355670">ठीक आहे</translation>
<translation id="6965978654500191972">डिव्हाइस</translation>
@@ -833,7 +838,7 @@
<translation id="7138472120740807366">वितरण पद्धत</translation>
<translation id="7139724024395191329">अमिरात</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> आणखी}one{<ph name="PAYMENT_METHOD_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> आणखी}other{<ph name="PAYMENT_METHOD_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> आणखी}}</translation>
-<translation id="7155487117670177674">पेमेंट सुरक्षित नाही</translation>
+<translation id="717330890047184534">Gaia आयडी:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> आणखी}one{<ph name="SHIPPING_OPTION_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> आणखी}other{<ph name="SHIPPING_OPTION_PREVIEW" /> आणि <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> आणखी}}</translation>
<translation id="7180611975245234373">रिफ्रेश करा</translation>
<translation id="7182878459783632708">कोणतीही धोरणे सेट नाहीत</translation>
@@ -882,6 +887,7 @@
<translation id="7455133967321480974">सार्वत्रिक डीफॉल्‍ट वापरा (अवरोधित करा)</translation>
<translation id="7460163899615895653">अन्य डिव्हाइस वरील आपले अलीकडील टॅब येथे दिसतात</translation>
<translation id="7469372306589899959">कार्डची पुष्टी करीत आहे</translation>
+<translation id="7473891865547856676">नाही, नको</translation>
<translation id="7481312909269577407">पुढील</translation>
<translation id="7485870689360869515">डेटा आढळला नाही.</translation>
<translation id="7508255263130623398">परत केलेला धोरण डिव्हाइस आयडी रिक्त आहे किंवा वर्तमान डिव्हाइस आयडी शी जुळत नाही</translation>
@@ -904,7 +910,6 @@
<translation id="7569952961197462199">Chrome मधून क्रेडिट कार्ड काढायचे?</translation>
<translation id="7575800019233204241">"तुमचे कनेक्शन खाजगी नाही" किंवा "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" किंवा "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" किंवा "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" किंवा "SSL सर्टिफिकेट एरर"</translation>
<translation id="7578104083680115302">आपण Google सह सेव्ह केलेल्या कार्डचा वापर करून डिव्‍हाइसेसवरून द्रुतपणे साइट आणि अॅप्सवर देय द्या.</translation>
-<translation id="7588950540487816470">भौतिक वेब</translation>
<translation id="7592362899630581445">सर्व्हरचे प्रमाणपत्र नाव मर्यादांचे उल्लंघन करते.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> पेक्षा कमी</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> सध्या ही विनंती हाताळण्यात अक्षम आहे.</translation>
@@ -1046,7 +1051,7 @@
<translation id="8703575177326907206"><ph name="DOMAIN" /> चे आपले कनेक्शन कूटबद्ध केलेले नाही.</translation>
<translation id="8718314106902482036">पेमेंट पूर्ण झाले नाही</translation>
<translation id="8725066075913043281">पुन्हा प्रयत्न करा</translation>
-<translation id="8728672262656704056">आपण गुप्त मोडमध्ये आहात</translation>
+<translation id="8728672262656704056">तुम्ही गुप्त मोडमध्ये आहात</translation>
<translation id="8730621377337864115">पूर्ण झाले</translation>
<translation id="8738058698779197622">एक सुरक्षित कनेक्‍शन स्‍थापित करण्‍यापूर्वी, आपले घड्‍याळ योग्यरित्या सेट केले असणे आवश्यक आहे. कारण वेबसाइट त्यांना स्‍वत:ला ओळखण्‍यासाठी वापरतात ती प्रमाणपत्रे केवळ निर्दिष्‍ट केलेल्‍या कालावधीसाठी वैध असतात. आपल्‍या डिव्‍हाइसचे घड्‍याळ चुकीचे असल्‍यामुळे, Chromium ही प्रमाणपत्रे सत्यापित करू शकत नाही.</translation>
<translation id="8740359287975076522"><ph name="HOST_NAME" />चा &lt;abbr id="dnsDefinition"&gt;DNS पत्ता&lt;/abbr&gt; शोधणे शक्य झाले नाही. समस्येचे निराकरण करीत आहे.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;संपादित करा पूर्ववत करा</translation>
<translation id="9154194610265714752">अपडेट केलेले</translation>
<translation id="9157595877708044936">सेट अप करीत आहे...</translation>
+<translation id="9168814207360376865">तुम्ही पेमेंट पद्धती सेव्ह केल्या आहेत का हे तपासण्याची साइटला परवानगी द्या</translation>
<translation id="9169664750068251925">या साइटवर नेहमी अवरोधित करा</translation>
<translation id="9170848237812810038">&amp;पूर्ववत करा</translation>
<translation id="917450738466192189">सर्व्हरचे प्रमाणपत्र अवैध आहे.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">लेख जोडण्यात अयशस्वी.</translation>
<translation id="9215416866750762878">एक अॅप्लिकेशन Chrome ला या साइटशी सुरक्षितपणे कनेक्ट करण्यापासून थांबवत आहे</translation>
<translation id="9219103736887031265">इमेज</translation>
-<translation id="933612690413056017">इंटरनेट कनेक्शन नाही</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">फॉर्म साफ करा</translation>
<translation id="939736085109172342">नवीन फोल्‍डर</translation>
diff --git a/chromium/components/strings/components_strings_ms.xtb b/chromium/components/strings/components_strings_ms.xtb
index 885e810d651..73eb306cc47 100644
--- a/chromium/components/strings/components_strings_ms.xtb
+++ b/chromium/components/strings/components_strings_ms.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Pilih kebenaran untuk <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Penanda halaman terbaharu dilawati</translation>
<translation id="1113869188872983271">&amp;Buat asal susun semula</translation>
+<translation id="1125573121925420732">Amaran mungkin biasa dipaparkan semasa tapak web mengemas kini keselamatannya. Ini akan diperbaik tidak lama lagi.</translation>
<translation id="1126551341858583091">Saiz pada storan setempat ialah <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache dasar OK</translation>
<translation id="1150979032973867961">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh sistem pengendalian komputer anda. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang yang memintasi sambungan anda.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Pastikan sambungan Internet anda berfungsi seperti biasa.&lt;/li&gt;
&lt;li&gt;Hubungi pemilik tapak web.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Anda memasukkan kata laluan pada tapak yang tidak diurus oleh organisasi anda. Untuk melindungi akaun anda, jangan gunakan semula kata laluan anda pada apl dan tapak lain.</translation>
<translation id="1263231323834454256">Senarai bacaan</translation>
<translation id="1264126396475825575">Laporan ranap sistem dirakam pada <ph name="CRASH_TIME" /> (belum dimuat naik atau diabaikan)</translation>
<translation id="1270502636509132238">Kaedah Pengambilan</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Pilih</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Halang halaman ini daripada mencipta dialog tambahan</translation>
-<translation id="1629803312968146339">Adakah anda mahu Chrome menyimpan kad ini?</translation>
<translation id="1639239467298939599">Memuatkan</translation>
<translation id="1640180200866533862">Dasar pengguna</translation>
<translation id="1640244768702815859">Cuba <ph name="BEGIN_LINK" />lawat laman utama tapak<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Cuba jalankan Diagnostik Rangkaian Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Sila kemas kini frasa laluan segerak anda.</translation>
<translation id="1787142507584202372">Tab yang dibuka dipaparkan di sini</translation>
-<translation id="1789575671122666129">Pop timbul</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nama Pemegang Kad</translation>
<translation id="1806541873155184440">Ditambahkan <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Mulakan semula komputer anda</translation>
<translation id="2113977810652731515">Kad</translation>
<translation id="2114841414352855701">Diabaikan kerana ia telah diatasi oleh <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Mencari halaman Web Fizikal yang berdekatan</translation>
<translation id="213826338245044447">Penanda Halaman Mudah Alih</translation>
<translation id="214556005048008348">Batalkan pembayaran</translation>
<translation id="2147827593068025794">Penyegerakan Latar Belakang</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Dasar tidak dijumpai</translation>
<translation id="2213606439339815911">Mengambil entri…</translation>
<translation id="2218879909401188352">Penyerang yang berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> boleh memasang apl berbahaya yang boleh merosakkan peranti anda, menambahkan caj yang tersembunyi pada bil mudah alih anda atau mencuri maklumat peribadi anda. <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Tiada Internet</translation>
<translation id="2230458221926704099">Betulkan sambungan anda menggunakan <ph name="BEGIN_LINK" />apl diagnostik<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Hantar sekarang</translation>
<translation id="225207911366869382">Nilai ini tidak lagi digunakan untuk dasar ini.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Buang item yang dipilih</translation>
<translation id="277133753123645258">Kaedah penghantaran</translation>
<translation id="277499241957683684">Tiada rekod peranti</translation>
+<translation id="2781030394888168909">Eksport MacOS</translation>
<translation id="2784949926578158345">Sambungan ditetapkan semula.</translation>
<translation id="2788784517760473862">Kad kredit yang diterima</translation>
<translation id="2794233252405721443">Tapak disekat</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome tidak dapat mengesahkan kad anda pada masa ini. Sila cuba sebentar lagi.</translation>
<translation id="3064966200440839136">Meninggalkan mod inkognito untuk membayar melalui aplikasi luar. Teruskan?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Tiada}=1{1 kata laluan}other{# kata laluan}}</translation>
-<translation id="3093245981617870298">Anda di luar talian.</translation>
<translation id="3096100844101284527">Tambahkan Alamat Pengambilan</translation>
<translation id="3105172416063519923">ID Aset:</translation>
<translation id="3109728660330352905">Anda tidak mempunyai kebenaran untuk melihat halaman ini.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> tidak dapat dicapai pada masa ini.</translation>
<translation id="3427092606871434483">Benarkan (lalai)</translation>
<translation id="3427342743765426898">&amp;Buat Semula Edit</translation>
+<translation id="342781501876943858">Chromium mengesyorkan penetapan semula kata laluan jika anda menggunakan semula kata laluan itu di tapak lain.</translation>
<translation id="3431636764301398940">Simpan kad ini pada peranti ini</translation>
<translation id="3447661539832366887">Pemilik peranti ini telah mematikan permainan dinosaur.</translation>
<translation id="3447884698081792621">Tunjukkan sijil (yang dikeluarkan oleh <ph name="ISSUER" />)</translation>
@@ -399,7 +400,6 @@
<translation id="3678529606614285348">Buka halaman dalam tetingkap Inkognito baharu (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Laporan ranap sistem dirakam pada <ph name="CRASH_TIME" />, dimuat naik pada <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Maklumat sijil</translation>
-<translation id="3690164694835360974">Log masuk tidak selamat</translation>
<translation id="3704162925118123524">Rangkaian yang anda gunakan mungkin memerlukan anda untuk melawat halaman log masuknya.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Memuatkan...</translation>
@@ -459,7 +459,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Gunakan lalai global (Kesan)</translation>
<translation id="4165986682804962316">Tetapan tapak</translation>
-<translation id="4169947484918424451">Adakah anda mahu Chromium menyimpan kad ini?</translation>
<translation id="4171400957073367226">Tandatangan pengesahan tidak sah</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> lagi item}other{<ph name="ITEM_COUNT" /> lagi item}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -496,6 +495,7 @@
<translation id="4275830172053184480">Mulakan semula peranti anda</translation>
<translation id="4277028893293644418">Tetapkan semula kata laluan</translation>
<translation id="4280429058323657511">, tamat tempoh <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Tukar</translation>
<translation id="4312866146174492540">Sekat (lalai)</translation>
<translation id="4325863107915753736">Gagal menemui artikel</translation>
<translation id="4326324639298822553">Semak tarikh tamat tempoh anda dan cuba lagi</translation>
@@ -503,6 +503,7 @@
<translation id="4340982228985273705">Komputer ini tidak dikesan sebagai diurus perusahaan, jadi dasar hanya boleh memasang secara automatik sambungan yang dihoskan di Gedung Web Chrome. URL kemas kini Gedung Web Chrome ialah "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Kad Kredit yang Diterima</translation>
<translation id="4356973930735388585">Penyerang pada tapak ini mungkin cuba memasang atur cara berbahaya pada komputer anda yang mencuri atau memadamkan maklumat anda (sebagai contoh, foto, kata laluan, mesej dan kad kredit).</translation>
+<translation id="4358461427845829800">Urus kaedah pembayaran...</translation>
<translation id="4372948949327679948">Nilai <ph name="VALUE_TYPE" /> yang dijangka.</translation>
<translation id="4377125064752653719">Anda cuba untuk mencapai <ph name="DOMAIN" />, tetapi sijil yang diberi pelayan telah dibatalkan oleh pengeluarnya. Ini bermakna bahawa bukti kelayakan keselamatan yang diberi pelayan sememangnya tidak harus dipercayai. Anda mungkin berkomunikasi dengan penyerang.</translation>
<translation id="4406896451731180161">hasil carian</translation>
@@ -510,6 +511,7 @@
<translation id="4415426530740016218">Alamat Pengambilan</translation>
<translation id="4424024547088906515">Pelayan ini tidak dapat membuktikan bahawa domainnya ialah <ph name="DOMAIN" />; sijil keselamatannya tidak dipercayai oleh Chrome. Ini mungkin disebabkan oleh kesilapan konfigurasi atau penyerang memintasi sambungan anda.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> tidak menerima sijil log masuk anda atau sijil log masuk mungkin tidak diberikan.</translation>
+<translation id="4434045419905280838">Tetingkap timbul dan ubah hala</translation>
<translation id="443673843213245140">Penggunaan proksi dilumpuhkan tetapi konfigurasi proksi yang jelas dinyatakan.</translation>
<translation id="445100540951337728">Kad debit yang diterima</translation>
<translation id="4506176782989081258">Ralat pengesahan: <ph name="VALIDATION_ERROR" /></translation>
@@ -544,13 +546,13 @@
<translation id="4759118997339041434">Ciri autolengkap pembayaran dilumpuhkan</translation>
<translation id="4764776831041365478">Laman web di <ph name="URL" /> mungkin tergendala buat sementara waktu atau ia mungkin dpindahkan secara kekal ke alamat web baharu.</translation>
<translation id="4771973620359291008">Ralat tidak diketahui telah berlaku.</translation>
+<translation id="4785689107224900852">Beralih ke tab ini</translation>
<translation id="4792143361752574037">Terdapat masalah untuk mengakses fail sesi. Penyimpanan pada cakera dilumpuhkan pada masa ini. Sila muat semula halaman untuk mencuba lagi.</translation>
<translation id="4800132727771399293">Semak tarikh tamat tempoh serta CVC anda dan cuba lagi</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menghantar bukti kelayakan yang dicampuradukkan yang tidak boleh diproses oleh Google Chrome. Ralat rangkaian dan serangan biasanya bersifat sementara, oleh itu halaman ini mungkin akan berfungsi sebentar lagi.</translation>
<translation id="4813512666221746211">Ralat rangkaian</translation>
<translation id="4816492930507672669">Muat halaman</translation>
-<translation id="483020001682031208">Tiada halaman Web Fizikal yang hendak dipaparkan</translation>
<translation id="4850886885716139402">Lihat</translation>
<translation id="4854362297993841467">Kaedah penghantaran ini tidak tersedia. Cuba kaedah lain.</translation>
<translation id="4858792381671956233">Anda telah bertanya kepada ibu bapa anda sama ada OK untuk melawat tapak ini</translation>
@@ -590,6 +592,7 @@
<translation id="5115563688576182185">(64-bit)</translation>
<translation id="5121084798328133320">Setelah anda mengesahkan, butiran kad daripada akaun Google Payments anda akan dikongsi dengan tapak ini.</translation>
<translation id="5128122789703661928">Sesi dengan nama ini tidak sah untuk pemadaman.</translation>
+<translation id="5135404736266831032">Urus alamat...</translation>
<translation id="5141240743006678641">Sulitkan kata laluan yang disegerakkan dengan bukti kelayakan Google anda</translation>
<translation id="5145883236150621069">Terdapat kod ralat dalam balasan dasar</translation>
<translation id="5159010409087891077">Buka halaman dalam tetingkap Inkognito baharu (⇧⌘N)</translation>
@@ -601,7 +604,6 @@
<translation id="5201306358585911203">Halaman terbenam pada halaman ini menyatakan</translation>
<translation id="5205222826937269299">Nama diperlukan</translation>
<translation id="5222812217790122047">E-mel diperlukan</translation>
-<translation id="522700295135997067">Tapak ini mungkin baru sahaja mencuri kata laluan anda</translation>
<translation id="5230733896359313003">Alamat Penghantaran</translation>
<translation id="5250209940322997802">"Sambung kepada rangkaian"</translation>
<translation id="5251803541071282808">Awan</translation>
@@ -645,7 +647,6 @@
<translation id="5492298309214877701">Tapak ini yang berada di intranet syarikat, organisasi atau sekolah mempunyai URL yang sama dengan tapak web luar.
<ph name="LINE_BREAK" />
Cuba hubungi pentadbir sistem anda.</translation>
-<translation id="5499929369096410817">Masukkan kod keselamatan untuk <ph name="CREDIT_CARD" />. Kod ini tidak akan disimpan.</translation>
<translation id="5509780412636533143">Penanda halaman terurus</translation>
<translation id="5510766032865166053">Fail mungkin telah dipindahkan atau dipadamkan.</translation>
<translation id="5523118979700054094">Nama dasar</translation>
@@ -676,9 +677,11 @@
<translation id="5685654322157854305">Tambahkan Alamat Penghantaran</translation>
<translation id="5689199277474810259">Eksport ke JSON</translation>
<translation id="5689516760719285838">Lokasi</translation>
+<translation id="570530837424789914">Urus...</translation>
<translation id="5710435578057952990">Identiti tapak web ini belum disahkan.</translation>
<translation id="5719499550583120431">Kad prabayar diterima.</translation>
<translation id="5720705177508910913">Pengguna semasa</translation>
+<translation id="5730040223043577876">Chrome mengesyorkan penetapan semula kata laluan jika anda menggunakan semula kata laluan itu di tapak lain.</translation>
<translation id="5732392974455271431">Ibu bapa anda boleh menyahsekatnya untuk anda</translation>
<translation id="5763042198335101085">Masukkan alamat e-mel yang sah</translation>
<translation id="5765072501007116331">Pilih alamat untuk melihat kaedah dan syarat penghantaran</translation>
@@ -702,9 +705,7 @@
<translation id="5959728338436674663">Hantar secara automatik beberapa <ph name="BEGIN_WHITEPAPER_LINK" />maklumat sistem dan kandungan halaman<ph name="END_WHITEPAPER_LINK" /> kepada Google untuk membantu anda mengesan apl dan tapak yang berbahaya. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edit Maklumat Hubungan</translation>
<translation id="5967867314010545767">Buang daripada sejarah</translation>
-<translation id="5972020793760134803">Beralih ke tab</translation>
<translation id="5975083100439434680">Zum keluar</translation>
-<translation id="597552863672748783">Sahkan kod keselamatan</translation>
<translation id="598637245381783098">Tidak dapat membuka apl pembayaran</translation>
<translation id="5989320800837274978">Pelayan proksi tetap begitu juga URL skrip .pac, kedua-duanya tidak ditetapkan.</translation>
<translation id="5990559369517809815">Permintaan pada pelayan telah disekat oleh sambungan.</translation>
@@ -720,6 +721,7 @@
<translation id="6047927260846328439">Kandungan ini mungkin menggunakan tipu muslihat supaya anda memasang perisian atau mendedahkan maklumat peribadi. <ph name="BEGIN_LINK" />Tunjukkan juga<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Anda tidak boleh melawati <ph name="SITE" /> sekarang kerana tapak web ini menggunakan penyematan sijil. Ralat dan serangan rangkaian biasanya bersifat sementara. Oleh sebab itu, halaman ini mungkin akan berfungsi semula kemudian.</translation>
<translation id="6059925163896151826">Peranti USB</translation>
+<translation id="6071091556643036997">Jenis dasar tidak sah.</translation>
<translation id="6080696365213338172">Anda telah mengakses kandungan menggunakan perakuan yang disediakan oleh pentadbir. Data yang anda berikan kepada <ph name="DOMAIN" /> boleh dipintas oleh pentadbir anda.</translation>
<translation id="610911394827799129">Akaun Google anda mungkin mempunyai bentuk sejarah penyemakan imbas yang lain di <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Tiada}=1{1 kata laluan (disegerakkan)}other{# kata laluan (disegerakkan)}}</translation>
@@ -767,6 +769,7 @@
<translation id="6446608382365791566">Tambahkan maklumat lanjut</translation>
<translation id="6447842834002726250">Kuki</translation>
<translation id="6451458296329894277">Sahkan Penyerahan Semula Borang</translation>
+<translation id="6465306955648956876">Urus kata laluan...</translation>
<translation id="647261751007945333">Dasar peranti</translation>
<translation id="6477321094435799029">Chrome mengesan kod luar biasa pada halaman ini dan menyekatnya untuk melindungi maklumat peribadi anda (contohnya, kata laluan, nombor telefon dan maklumat kad kredit).</translation>
<translation id="6489534406876378309">Mulakan muat naik ranap sistem</translation>
@@ -786,6 +789,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Carian</translation>
<translation id="6630809736994426279">Penyerang yang sedang berada di <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mungkin cuba memasang atur cara berbahaya pada komputer Mac anda. Atur cara tersebut boleh mencuri atau memadamkan maklumat anda (contohnya, foto, kata laluan, mesej dan kad kredit). <ph name="BEGIN_LEARN_MORE_LINK" />Ketahui lebih lanjut<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Dasar ini telah dikecam.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Tiada}=1{Daripada 1 tapak (anda tidak akan dilog keluar daripada Akaun Google anda)}other{Daripada # tapak (anda tidak akan dilog keluar daripada Akaun Google anda)}}</translation>
<translation id="6657585470893396449">Kata laluan</translation>
<translation id="6671697161687535275">Alih keluar cadangan borang daripada Chromium?</translation>
<translation id="6685834062052613830">Log keluar dan selesaikan persediaan</translation>
@@ -812,6 +816,7 @@
<translation id="6915804003454593391">Pengguna:</translation>
<translation id="6945221475159498467">Pilih</translation>
<translation id="6948701128805548767">Pilih alamat untuk melihat kaedah dan syarat pengambilan</translation>
+<translation id="6949872517221025916">Tetapkan Semula Kata Laluan</translation>
<translation id="6957887021205513506">Sijil pelayan rupanya adalah pemalsuan.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Peranti</translation>
@@ -833,7 +838,7 @@
<translation id="7138472120740807366">Kaedah penghantaran</translation>
<translation id="7139724024395191329">Emiriah</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> lagi}other{<ph name="PAYMENT_METHOD_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> lagi}}</translation>
-<translation id="7155487117670177674">Pembayaran tidak selamat</translation>
+<translation id="717330890047184534">ID Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> lagi}other{<ph name="SHIPPING_OPTION_PREVIEW" /> dan <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> lagi}}</translation>
<translation id="7180611975245234373">Muat semula</translation>
<translation id="7182878459783632708">Tiada dasar ditetapkan</translation>
@@ -882,6 +887,7 @@
<translation id="7455133967321480974">Gunakan lalai global (Sekat)</translation>
<translation id="7460163899615895653">Tab terbaharu anda daripada peranti lain dipaparkan di sini</translation>
<translation id="7469372306589899959">Mengesahkan kad</translation>
+<translation id="7473891865547856676">Tidak, Terima Kasih</translation>
<translation id="7481312909269577407">Majukan</translation>
<translation id="7485870689360869515">Tiada data dijumpai.</translation>
<translation id="7508255263130623398">Id peranti yang dikembalikan kosong atau tidak sepadan dengan id peranti semasa</translation>
@@ -904,7 +910,6 @@
<translation id="7569952961197462199">Alih keluar kad kredit daripada Chrome?</translation>
<translation id="7575800019233204241">"Sambungan anda tidak peribadi" atau "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" atau "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" atau "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" atau "Ralat sijil SSL"</translation>
<translation id="7578104083680115302">Bayar dengan cepat di tapak dan apl merentas peranti menggunakan kad yang telah disimpan dengan Google.</translation>
-<translation id="7588950540487816470">Web Fizikal</translation>
<translation id="7592362899630581445">Sijil pelayan melanggar kekangan nama.</translation>
<translation id="7598391785903975535">Kurang daripada <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> tidak dapat mengendalikan permintaan ini pada masa ini.</translation>
@@ -1108,6 +1113,7 @@
<translation id="9148507642005240123">&amp;Buat asal edit</translation>
<translation id="9154194610265714752">Dikemas kini</translation>
<translation id="9157595877708044936">Menyediakan...</translation>
+<translation id="9168814207360376865">Benarkan tapak menyemak sama ada anda mempunyai kaedah pembayaran yang disimpan</translation>
<translation id="9169664750068251925">Sentiasa sekat di tapak ini</translation>
<translation id="9170848237812810038">&amp;Buat asal</translation>
<translation id="917450738466192189">Sijil pelayan tidak sah.</translation>
@@ -1116,7 +1122,6 @@
<translation id="9207861905230894330">Gagal menambahkan artikel.</translation>
<translation id="9215416866750762878">Satu aplikasi menghalang Chrome daripada menyambung ke tapak ini dengan selamat</translation>
<translation id="9219103736887031265">Imej</translation>
-<translation id="933612690413056017">Tiada sambungan Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">KOSONGKAN BORANG</translation>
<translation id="939736085109172342">Folder baharu</translation>
diff --git a/chromium/components/strings/components_strings_nl.xtb b/chromium/components/strings/components_strings_nl.xtb
index 4969ddce517..92a49329000 100644
--- a/chromium/components/strings/components_strings_nl.xtb
+++ b/chromium/components/strings/components_strings_nl.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Rechten selecteren voor <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Onlangs bezochte bladwijzers</translation>
<translation id="1113869188872983271">&amp;Volgorde wijzigen ongedaan maken</translation>
+<translation id="1125573121925420732">Wanneer de beveiliging van websites wordt geüpdatet, worden vaak waarschuwingen weergegeven. Dit wordt binnenkort verbeterd.</translation>
<translation id="1126551341858583091">De grootte in de lokale opslag is <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cachegeheugen van beleid is OK</translation>
<translation id="1150979032973867961">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door het besturingssysteem van je computer. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Controleer of je internetverbinding naar behoren werkt.&lt;/li&gt;
&lt;li&gt;Neem contact op met de eigenaar van deze website.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Je hebt je wachtwoord ingevoerd op een site die niet door je organisatie wordt beheerd. Hergebruik je wachtwoord niet voor andere apps en sites om je account te beschermen.</translation>
<translation id="1263231323834454256">Leeslijst</translation>
<translation id="1264126396475825575">Crashrapport vastgelegd op <ph name="CRASH_TIME" /> (nog niet geüpload of genegeerd)</translation>
<translation id="1270502636509132238">Ophaalmethode</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Kiezen</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1623104350909869708">Voorkomen dat deze pagina extra dialoogvensters weergeeft</translation>
-<translation id="1629803312968146339">Wil je dat Chrome deze kaart opslaat?</translation>
<translation id="1639239467298939599">Laden</translation>
<translation id="1640180200866533862">Gebruikersbeleid</translation>
<translation id="1640244768702815859">Probeer <ph name="BEGIN_LINK" />de homepage van de site te bezoeken<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Voer Windows Netwerkcontrole uit<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Update je wachtwoordzin voor synchronisatie.</translation>
<translation id="1787142507584202372">Je geopende tabbladen worden hier weergegeven</translation>
-<translation id="1789575671122666129">Pop-ups</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Naam kaarthouder</translation>
<translation id="1806541873155184440">Toegevoegd: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Je computer opnieuw opstarten</translation>
<translation id="2113977810652731515">Kaart</translation>
<translation id="2114841414352855701">Genegeerd omdat het werd overschreven door <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Bezig met zoeken naar Fysieke webpagina's in de buurt</translation>
<translation id="213826338245044447">Mobiele bladwijzers</translation>
<translation id="214556005048008348">Betaling annuleren</translation>
<translation id="2147827593068025794">Synchronisatie op de achtergrond</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Beleid niet gevonden</translation>
<translation id="2213606439339815911">Items ophalen…</translation>
<translation id="2218879909401188352">Aanvallers die zich momenteel op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> bevinden, kunnen gevaarlijke apps installeren die je apparaat beschadigen, verborgen kosten toevoegen aan je mobiele telefoonrekening of je persoonlijke gegevens stelen. <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Geen internet</translation>
<translation id="2230458221926704099">Los problemen met je verbinding op met de <ph name="BEGIN_LINK" />diagnose-app<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Nu verzenden</translation>
<translation id="225207911366869382">Deze waarde is verouderd voor dit beleid.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Geselecteerde items verwijderen</translation>
<translation id="277133753123645258">Verzendmethode</translation>
<translation id="277499241957683684">Apparaatrecord ontbreekt</translation>
+<translation id="2781030394888168909">Exporteren naar Mac OS</translation>
<translation id="2784949926578158345">De verbinding is opnieuw ingesteld.</translation>
<translation id="2788784517760473862">Geaccepteerde creditcards</translation>
<translation id="2794233252405721443">Site geblokkeerd</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome kan je creditcard momenteel niet bevestigen. Probeer het later opnieuw.</translation>
<translation id="3064966200440839136">Je verlaat de incognitomodus om te betalen via een externe app. Doorgaan?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Geen}=1{1 wachtwoord}other{# wachtwoorden}}</translation>
-<translation id="3093245981617870298">Je bent offline.</translation>
<translation id="3096100844101284527">Ophaaladres toevoegen</translation>
<translation id="3105172416063519923">Item-ID:</translation>
<translation id="3109728660330352905">Je hebt geen toestemming om deze pagina te bekijken.</translation>
@@ -359,6 +359,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> is momenteel niet bereikbaar.</translation>
<translation id="3427092606871434483">Toestaan (standaard)</translation>
<translation id="3427342743765426898">&amp;Opnieuw bewerken</translation>
+<translation id="342781501876943858">Chromium raadt je aan je wachtwoord te resetten als je het voor andere sites hebt hergebruikt.</translation>
<translation id="3431636764301398940">Deze creditcard opslaan op dit apparaat</translation>
<translation id="3447661539832366887">De eigenaar van dit apparaat heeft de dinosaurusgame uitgeschakeld.</translation>
<translation id="3447884698081792621">Certificaat weergeven (uitgegeven door <ph name="ISSUER" />)</translation>
@@ -394,7 +395,6 @@
<translation id="3678529606614285348">Pagina openen in een nieuw incognitovenster (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Crashrapport vastgelegd op <ph name="CRASH_TIME" />, geüpload op <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certificaatgegevens</translation>
-<translation id="3690164694835360974">Inloggen niet beveiligd</translation>
<translation id="3704162925118123524">Het is mogelijk dat je de inlogpagina moet bezoeken van het netwerk dat je gebruikt.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Bezig met laden...</translation>
@@ -454,7 +454,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Algemene standaard gebruiken (detecteren)</translation>
<translation id="4165986682804962316">Site-instellingen</translation>
-<translation id="4169947484918424451">Wil je dat Chromium deze kaart opslaat?</translation>
<translation id="4171400957073367226">Onjuiste verificatiehandtekening</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Nog <ph name="ITEM_COUNT" /> item}other{Nog <ph name="ITEM_COUNT" /> items}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -491,6 +490,7 @@
<translation id="4275830172053184480">Je apparaat opnieuw opstarten</translation>
<translation id="4277028893293644418">Wachtwoord opnieuw instellen</translation>
<translation id="4280429058323657511">, vervalt <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Overschakelen</translation>
<translation id="4312866146174492540">Blokkeren (standaard)</translation>
<translation id="4325863107915753736">Kan artikel niet vinden</translation>
<translation id="4326324639298822553">Controleer de vervaldatum en probeer het opnieuw</translation>
@@ -498,6 +498,7 @@
<translation id="4340982228985273705">Deze computer is niet gedetecteerd als een zakelijk beheerde computer. Overeenkomstig het beleid kunnen alleen automatisch extensies worden geïnstalleerd die worden gehost in de Chrome Web Store. De update-URL van de Chrome Web Store is <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Geaccepteerde creditcards</translation>
<translation id="4356973930735388585">Cybercriminelen op deze site proberen mogelijk gevaarlijke programma's op je computer te installeren waarmee je gegevens worden gestolen of verwijderd (bijvoorbeeld foto's, wachtwoorden, berichten en creditcards).</translation>
+<translation id="4358461427845829800">Betaalmethoden beheren...</translation>
<translation id="4372948949327679948">Verwachte <ph name="VALUE_TYPE" /> waarde.</translation>
<translation id="4377125064752653719">Je probeert <ph name="DOMAIN" /> te bereiken, maar het certificaat dat de server heeft geretourneerd, is ingetrokken door de uitgever. Dat betekent dat de veiligheidsgaranties die de server heeft geretourneerd, absoluut niet kunnen worden vertrouwd. Het kan zijn dat je met een hacker aan het communiceren bent.</translation>
<translation id="4406896451731180161">zoekresultaten</translation>
@@ -505,6 +506,7 @@
<translation id="4415426530740016218">Ophaaladres</translation>
<translation id="4424024547088906515">De server kan niet bewijzen dat dit <ph name="DOMAIN" /> is. Het beveiligingscertificaat van de server wordt niet vertrouwd door Chrome. Dit kan worden veroorzaakt door een verkeerde configuratie of een aanvaller die je verbinding onderschept.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> heeft je inlogcertificaat niet geaccepteerd of er is geen inlogcertificaat geleverd.</translation>
+<translation id="4434045419905280838">Pop-ups en omleidingen</translation>
<translation id="443673843213245140">Het gebruik van een proxy is uitgeschakeld, maar er is wel een expliciete proxyconfiguratie opgegeven.</translation>
<translation id="445100540951337728">Geaccepteerde betaalpassen</translation>
<translation id="4506176782989081258">Validatiefout: <ph name="VALIDATION_ERROR" /></translation>
@@ -539,13 +541,13 @@
<translation id="4759118997339041434">Automatisch aanvullen voor betalingen uitgeschakeld</translation>
<translation id="4764776831041365478">De webpagina op <ph name="URL" /> is mogelijk tijdelijk uitgeschakeld of permanent verplaatst naar een nieuw webadres.</translation>
<translation id="4771973620359291008">Er is een onbekende fout opgetreden.</translation>
+<translation id="4785689107224900852">Overschakelen naar dit tabblad</translation>
<translation id="4792143361752574037">Er is een probleem opgetreden bij het openen van de sessiebestanden. Opslaan op schijf is momenteel uitgeschakeld. Laad pagina opnieuw om het nogmaals te proberen.</translation>
<translation id="4800132727771399293">Controleer je vervaldatum en CVC-code en probeer het opnieuw</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Je kunt <ph name="SITE" /> op dit moment niet bezoeken, omdat de website gecodeerde inloggegevens heeft verzonden die niet door Google Chrome kunnen worden verwerkt. Netwerkfouten en aanvallen zijn meestal tijdelijk, dus deze pagina werkt later waarschijnlijk weer correct.</translation>
<translation id="4813512666221746211">Netwerkfout</translation>
<translation id="4816492930507672669">Aanpassen aan pagina</translation>
-<translation id="483020001682031208">Geen Fysieke webpagina's om weer te geven</translation>
<translation id="4850886885716139402">Weergave</translation>
<translation id="4854362297993841467">Deze bezorgingsmethode is niet beschikbaar. Kies een andere methode.</translation>
<translation id="4858792381671956233">Je hebt je ouders gevraagd of je deze site mag bezoeken</translation>
@@ -585,6 +587,7 @@
<translation id="5115563688576182185">(64-bits)</translation>
<translation id="5121084798328133320">Nadat je hebt bevestigd, worden de kaartgegevens van je Google-betalingsaccount gedeeld met deze site.</translation>
<translation id="5128122789703661928">De naam van deze sessie die je wilt verwijderen, is ongeldig.</translation>
+<translation id="5135404736266831032">Adressen beheren...</translation>
<translation id="5141240743006678641">Gesynchroniseerde wachtwoorden versleutelen met je Google-aanmeldingsgegevens</translation>
<translation id="5145883236150621069">Foutcode aanwezig in de beleidsreactie</translation>
<translation id="5159010409087891077">Pagina openen in een nieuw incognitovenster (⇧⌘N)</translation>
@@ -596,7 +599,6 @@
<translation id="5201306358585911203">Een ingesloten pagina op deze pagina meldt het volgende</translation>
<translation id="5205222826937269299">Naam vereist</translation>
<translation id="5222812217790122047">E-mailadres vereist</translation>
-<translation id="522700295135997067">Deze site heeft mogelijk zojuist je wachtwoord gestolen</translation>
<translation id="5230733896359313003">Verzendadres</translation>
<translation id="5250209940322997802">'Verbinding maken met netwerk'</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -640,7 +642,6 @@
<translation id="5492298309214877701">Deze site op het intranet van het bedrijf, de organisatie of de school heeft dezelfde URL als een externe website.
<ph name="LINE_BREAK" />
Neem contact op met je systeembeheerder.</translation>
-<translation id="5499929369096410817">Geef de beveiligingscode voor <ph name="CREDIT_CARD" /> op. Deze code wordt niet opgeslagen.</translation>
<translation id="5509780412636533143">Beheerde bladwijzers</translation>
<translation id="5510766032865166053">Het bestand is mogelijk verplaatst of verwijderd.</translation>
<translation id="5523118979700054094">Beleidsnaam</translation>
@@ -671,9 +672,11 @@
<translation id="5685654322157854305">Verzendadres toevoegen</translation>
<translation id="5689199277474810259">Exporteren naar JSON</translation>
<translation id="5689516760719285838">Locatie</translation>
+<translation id="570530837424789914">Beheren...</translation>
<translation id="5710435578057952990">De identiteit van deze website is niet geverifieerd.</translation>
<translation id="5719499550583120431">Prepaidkaarten worden geaccepteerd.</translation>
<translation id="5720705177508910913">Huidige gebruiker</translation>
+<translation id="5730040223043577876">Chrome raadt je aan je wachtwoord opnieuw in te stellen als je het voor andere sites hebt hergebruikt.</translation>
<translation id="5732392974455271431">Je ouders kunnen de blokkering van deze site opheffen</translation>
<translation id="5763042198335101085">Geef een geldig e-mailadres op</translation>
<translation id="5765072501007116331">Selecteer een adres om bezorgingsmethoden en vereisten te bekijken</translation>
@@ -697,9 +700,7 @@
<translation id="5959728338436674663">Bepaalde <ph name="BEGIN_WHITEPAPER_LINK" />systeeminformatie en paginacontent<ph name="END_WHITEPAPER_LINK" /> automatisch verzenden naar Google om te helpen bij de detectie van gevaarlijke apps en sites. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Contactgegevens bewerken</translation>
<translation id="5967867314010545767">Verwijderen uit geschiedenis</translation>
-<translation id="5972020793760134803">Overschakelen naar tabblad</translation>
<translation id="5975083100439434680">Uitzoomen</translation>
-<translation id="597552863672748783">Beveiligingscode bevestigen</translation>
<translation id="598637245381783098">Kan betaal-app niet openen</translation>
<translation id="5989320800837274978">Er worden geen vaste proxyservers en geen pac-script-URL gespecificeerd.</translation>
<translation id="5990559369517809815">Verzoeken aan de server zijn door een extensie geblokkeerd.</translation>
@@ -715,6 +716,7 @@
<translation id="6047927260846328439">Deze content probeert je mogelijk te misleiden om software te installeren of persoonlijke gegevens openbaar te maken. <ph name="BEGIN_LINK" />Toch weergeven<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Je kunt <ph name="SITE" /> momenteel niet bezoeken, omdat de website gebruikmaakt van certificaatpinning. Netwerkfouten en aanvallen zijn doorgaans tijdelijk, dus deze pagina werkt later waarschijnlijk correct.</translation>
<translation id="6059925163896151826">USB-apparaten</translation>
+<translation id="6071091556643036997">Het type beleid is ongeldig.</translation>
<translation id="6080696365213338172">Je hebt toegang tot content gekregen met behulp van een certificaat van je beheerder. Gegevens die je verstrekt aan <ph name="DOMAIN" />, kunnen door je beheerder worden onderschept.</translation>
<translation id="610911394827799129">Er kunnen andere vormen van browsegeschiedenis zijn opgeslagen voor je Google-account op <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Geen}=1{1 wachtwoord (gesynchroniseerd)}other{# wachtwoorden (gesynchroniseerd)}}</translation>
@@ -761,6 +763,7 @@
<translation id="6446608382365791566">Meer informatie toevoegen</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Opnieuw indienen bevestigen</translation>
+<translation id="6465306955648956876">Wachtwoorden beheren...</translation>
<translation id="647261751007945333">Apparaatbeleid</translation>
<translation id="6477321094435799029">Chrome heeft ongebruikelijke code op deze pagina gedetecteerd en heeft de code geblokkeerd om je persoonlijke gegevens (zoals wachtwoorden, telefoonnummers en creditcards) te beschermen.</translation>
<translation id="6489534406876378309">Uploaden van crashes starten</translation>
@@ -780,6 +783,7 @@
<translation id="6628463337424475685">Zoeken via <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Cybercriminelen op <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> proberen mogelijk gevaarlijke programma's op je Mac te installeren waarmee je gegevens kunnen worden gestolen of verwijderd (bijvoorbeeld foto's, wachtwoorden, berichten en creditcardgegevens). <ph name="BEGIN_LEARN_MORE_LINK" />Meer informatie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Dit beleid is verouderd.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Geen}=1{Van 1 site (je wordt niet uitgelogd bij je Google-account)}other{Van # sites (je wordt niet uitgelogd bij je Google-account)}}</translation>
<translation id="6657585470893396449">Wachtwoord</translation>
<translation id="6671697161687535275">Formuliersuggestie verwijderen uit Chromium?</translation>
<translation id="6685834062052613830">Uitloggen en configuratie voltooien</translation>
@@ -806,6 +810,7 @@
<translation id="6915804003454593391">Gebruiker:</translation>
<translation id="6945221475159498467">Selecteren</translation>
<translation id="6948701128805548767">Selecteer een adres om ophaalmethoden en vereisten te bekijken</translation>
+<translation id="6949872517221025916">Wachtwoord opnieuw instellen</translation>
<translation id="6957887021205513506">Het certificaat van de server lijkt vals te zijn.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Apparaat</translation>
@@ -827,7 +832,7 @@
<translation id="7138472120740807366">Bezorgingsmethode</translation>
<translation id="7139724024395191329">Emiraat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Betalen niet beveiligd</translation>
+<translation id="717330890047184534">Gaia-ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> en nog <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Vernieuwen</translation>
<translation id="7182878459783632708">Geen beleid ingesteld</translation>
@@ -876,6 +881,7 @@
<translation id="7455133967321480974">Algemene standaardinstelling gebruiken (Blokkeren)</translation>
<translation id="7460163899615895653">Je recente tabbladen van andere apparaten worden hier weergegeven</translation>
<translation id="7469372306589899959">Creditcard bevestigen</translation>
+<translation id="7473891865547856676">Nee, bedankt</translation>
<translation id="7481312909269577407">Vooruit</translation>
<translation id="7485870689360869515">Geen gegevens gevonden.</translation>
<translation id="7508255263130623398">Geretourneerde apparaat-ID voor beleid is leeg of komt niet overeen met de huidige apparaat-ID</translation>
@@ -898,7 +904,6 @@
<translation id="7569952961197462199">Creditcard verwijderen uit Chrome?</translation>
<translation id="7575800019233204241">'Je verbinding is niet privé' of '&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;' of '&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;' of '&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;' of 'SSL-certificaatfout'</translation>
<translation id="7578104083680115302">Betaal op verschillende apparaten snel op sites en in apps met kaarten die je hebt opgeslagen via Google.</translation>
-<translation id="7588950540487816470">Fysieke web</translation>
<translation id="7592362899630581445">Het certificaat van de server is in strijd met naambeperkingen.</translation>
<translation id="7598391785903975535">Minder dan <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan dit verzoek momenteel niet verwerken.</translation>
@@ -1101,6 +1106,7 @@
<translation id="9148507642005240123">&amp;Bewerken ongedaan maken</translation>
<translation id="9154194610265714752">Bijgewerkt</translation>
<translation id="9157595877708044936">Bezig met instellen...</translation>
+<translation id="9168814207360376865">Toestaan dat sites controleren of je betaalmethoden hebt opgeslagen</translation>
<translation id="9169664750068251925">Altijd blokkeren op deze site</translation>
<translation id="9170848237812810038">&amp;Ongedaan maken</translation>
<translation id="917450738466192189">Het servercertificaat is ongeldig.</translation>
@@ -1109,7 +1115,6 @@
<translation id="9207861905230894330">Kan artikel niet toevoegen.</translation>
<translation id="9215416866750762878">Een app voorkomt dat Chrome veilig verbinding kan maken met deze site</translation>
<translation id="9219103736887031265">Afbeeldingen</translation>
-<translation id="933612690413056017">Er is geen internetverbinding beschikbaar</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">FORMULIER LEEGMAKEN</translation>
<translation id="939736085109172342">Nieuwe map</translation>
diff --git a/chromium/components/strings/components_strings_no.xtb b/chromium/components/strings/components_strings_no.xtb
index 3bac252249f..f59c1015ec5 100644
--- a/chromium/components/strings/components_strings_no.xtb
+++ b/chromium/components/strings/components_strings_no.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Velg tillatelse for <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Nylige bokmerker</translation>
<translation id="1113869188872983271">&amp;Angre omorganiseringen</translation>
+<translation id="1125573121925420732">Det kan hende du ser mange advarsler mens nettstedene oppdaterer sikkerheten sin. Dette forbedres snart.</translation>
<translation id="1126551341858583091">Størrelsen på den lokale lagringsplassen er <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Bufferen for enhetsinnstillinger er OK</translation>
<translation id="1150979032973867961">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av datamaskinens operativsystem. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Sjekk at Internett-tilkoblingen din fungerer som den skal.&lt;/li&gt;
&lt;li&gt;Kontakt eieren av nettstedet.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Du har skrevet inn passordet ditt på et nettsted som ikke administreres av organisasjonen din. For å beskytte kontoen din må du ikke bruke det samme passordet i andre apper eller på andre nettsteder.</translation>
<translation id="1263231323834454256">Leseliste</translation>
<translation id="1264126396475825575">Programstopprapport fra <ph name="CRASH_TIME" /> (ignorert eller ikke lastet opp ennå)</translation>
<translation id="1270502636509132238">Hentemåte</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Velg</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Hindre denne siden i å opprette flere dialogruter</translation>
-<translation id="1629803312968146339">Vil du at Chrome skal lagre dette kortet?</translation>
<translation id="1639239467298939599">Laster inn</translation>
<translation id="1640180200866533862">Brukerretningslinjer</translation>
<translation id="1640244768702815859">Prøv <ph name="BEGIN_LINK" />å gå til startsiden for nettstedet<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Prøv å kjøre Windows Nettverksdiagnose<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Oppdater passordfrasen for synkronisering.</translation>
<translation id="1787142507584202372">De åpne fanene dine vises her</translation>
-<translation id="1789575671122666129">Forgrunnsvinduer</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kortinnehaverens navn</translation>
<translation id="1806541873155184440">Lagt til: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Start datamaskinen på nytt.</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Ignorert fordi det ble overstyrt av <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Leter etter Fysisk nett-sider i nærheten</translation>
<translation id="213826338245044447">Bokmerker for mobil</translation>
<translation id="214556005048008348">Avbryt betalingen</translation>
<translation id="2147827593068025794">Bakgrunnssynkronisering</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Innstillingene ble ikke funnet</translation>
<translation id="2213606439339815911">Henter oppføringer …</translation>
<translation id="2218879909401188352">Angripere som for øyeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan installere farlige apper som skader enheten din, legge til skjulte belastninger på mobilregningen din eller stjele personopplysningene dine. <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Ingen nettilkobling</translation>
<translation id="2230458221926704099">Løs tilkoblingsproblemene med <ph name="BEGIN_LINK" />diagnostikkappen<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Send nå</translation>
<translation id="225207911366869382">Denne verdien er foreldet for denne innstillingen.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Fjern valgte elementer</translation>
<translation id="277133753123645258">Leveringsmetode</translation>
<translation id="277499241957683684">Manglende enhetsoppføring</translation>
+<translation id="2781030394888168909">Eksportér til MacOS</translation>
<translation id="2784949926578158345">Tilkoblingen ble tilbakestilt.</translation>
<translation id="2788784517760473862">Godkjente kredittkort</translation>
<translation id="2794233252405721443">Nettstedet er blokkert</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome kunne ikke bekrefte kortet ditt akkurat nå. Prøv igjen senere.</translation>
<translation id="3064966200440839136">Går ut av inkognitomodus for å betale via en ekstern app. Vil du fortsette?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ingen}=1{1 passord}other{# passord}}</translation>
-<translation id="3093245981617870298">Du er ikke tilkoblet Internett.</translation>
<translation id="3096100844101284527">Legg til henteadresse</translation>
<translation id="3105172416063519923">Ressurs-ID:</translation>
<translation id="3109728660330352905">Du har ikke autorisasjon til å se denne siden.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> er ikke tilgjengelig for øyeblikket.</translation>
<translation id="3427092606871434483">Tillat (standard)</translation>
<translation id="3427342743765426898">&amp;Endre likevel</translation>
+<translation id="342781501876943858">Chromium anbefaler at du tilbakestiller passordet ditt hvis du også har brukt det på andre nettsteder.</translation>
<translation id="3431636764301398940">Lagre dette kortet på denne enheten</translation>
<translation id="3447661539832366887">Eieren av denne enheten har slått av dinosaurspillet.</translation>
<translation id="3447884698081792621">Vis sertifikat (utstedt av <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Åpne siden i et nytt inkognitovindu (Ctrl + Shift + N)</translation>
<translation id="3679803492151881375">Programstopprapport generert <ph name="CRASH_TIME" /> og lastet opp <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifikatinformasjon</translation>
-<translation id="3690164694835360974">Påloggingen er ikke trygg</translation>
<translation id="3704162925118123524">Det kan hende at det er et krav for nettverket du bruker, at du besøker påloggingssiden for nettverket.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Laster inn ...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Bruk global standard (oppdag)</translation>
<translation id="4165986682804962316">Nettstedsinnstillinger</translation>
-<translation id="4169947484918424451">Vil du at Chromium skal lagre dette kortet?</translation>
<translation id="4171400957073367226">Ugyldig bekreftelsessignatur</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> element til}other{<ph name="ITEM_COUNT" /> elementer til}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Start enheten din på nytt</translation>
<translation id="4277028893293644418">Tilbakestill passordet</translation>
<translation id="4280429058323657511">, utløper <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Bytt</translation>
<translation id="4312866146174492540">Blokkér (standard)</translation>
<translation id="4325863107915753736">Artikkelen ble ikke funnet</translation>
<translation id="4326324639298822553">Kontrollér utløpsdatoen, og prøv igjen</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Denne datamaskinen er ikke registrert som administrert av en bedrift, så regelen kan bare automatisk installere utvidelser som finnes på Chrome Nettmarked. Nettadressen for Chrome Nettmarked-oppdateringen er «<ph name="CWS_UPDATE_URL" />».</translation>
<translation id="4346197816712207223">Godkjente kredittkort</translation>
<translation id="4356973930735388585">Angripere på dette nettstedet kan prøve å installere farlige programmer på datamaskinen din. Disse kan stjele eller slette informasjonen din (for eksempel bilder, passord, e-post og kredittkortinformasjon).</translation>
+<translation id="4358461427845829800">Administrer betalingsmåter…</translation>
<translation id="4372948949327679948">Forventet <ph name="VALUE_TYPE" />-verdi.</translation>
<translation id="4377125064752653719">Du forsøkte å gå til <ph name="DOMAIN" />, men sertifikatet tjeneren presenterte har blitt trukket tilbake av utstederen. Dette innebærer at sikkerhetsinformasjonen tjeneren presenterte ikke er klarert. Det kan hende at du kommuniserer med en angriper.</translation>
<translation id="4406896451731180161">søkeresultater</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Henteadresse</translation>
<translation id="4424024547088906515">Denne tjeneren kunne ikke bevise at den er <ph name="DOMAIN" />. Sikkerhetssertifikatet til tjeneren er ikke klarert av Chrome. Dette kan være forårsaket av en feilkonfigurering eller en angriper som avskjærer tilkoblingen din.</translation>
<translation id="4432688616882109544">Enten godtok ikke <ph name="HOST_NAME" /> påloggingssertifikatet ditt, eller så ble det ikke oppgitt.</translation>
+<translation id="4434045419905280838">Forgrunnsvinduer/viderekoblinger</translation>
<translation id="443673843213245140">Bruk av mellomtjener er deaktivert, men det er angitt en uttrykkelig mellomtjenerkonfigurasjon.</translation>
<translation id="445100540951337728">Godkjente debetkort</translation>
<translation id="4506176782989081258">Valideringsfeil: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Autofyll av betalingsinformasjon er slått av</translation>
<translation id="4764776831041365478">Det kan hende at nettsiden på <ph name="URL" /> er midlertidig nede eller flyttet permanent til en ny nettadresse.</translation>
<translation id="4771973620359291008">Det har oppstått en ukjent feil.</translation>
+<translation id="4785689107224900852">Bytt til denne fanen</translation>
<translation id="4792143361752574037">Fikk ikke tilgang til øktfilene. Lagring til disk er for øyeblikket deaktivert. Last inn siden på nytt for å prøve igjen.</translation>
<translation id="4800132727771399293">Kontrollér utløpsdatoen og CVC-koden, og prøv igjen.</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Du kan ikke gå til <ph name="SITE" /> akkurat nå, fordi nettstedet sendte kryptert legitimasjon som Google Chrome ikke kan behandle. Nettverksfeil og -angrep er vanligvis forbigående, så siden kommer sikkert til å virke senere.</translation>
<translation id="4813512666221746211">Nettverksfeil</translation>
<translation id="4816492930507672669">Tilpass til siden</translation>
-<translation id="483020001682031208">Det finnes ingen sider på det fysiske nettet å vise</translation>
<translation id="4850886885716139402">Visning</translation>
<translation id="4854362297993841467">Denne leveringsmetoden er ikke tilgjengelig. Prøv en annen metode.</translation>
<translation id="4858792381671956233">Du har spurt foreldrene dine om det er greit å besøke dette nettstedet</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bit)</translation>
<translation id="5121084798328133320">Etter at du har bekreftet, deles kortopplysningene fra Google Payments-kontoen med dette nettstedet.</translation>
<translation id="5128122789703661928">Økten med dette navnet er ikke gyldig for sletting.</translation>
+<translation id="5135404736266831032">Adminstrer adresser…</translation>
<translation id="5141240743006678641">Kryptér synkroniserte passord med Google-legitimasjonen din</translation>
<translation id="5145883236150621069">Feilkode i responsen for enhetsinnstillinger</translation>
<translation id="5159010409087891077">Åpne siden i et nytt inkognitovindu (⇧ + ⌘ + N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">På en innebygd side på denne siden står det</translation>
<translation id="5205222826937269299">Navn er obligatorisk</translation>
<translation id="5222812217790122047">E-post er obligatorisk</translation>
-<translation id="522700295135997067">Dette nettstedet stjal muligens nettopp passordet ditt</translation>
<translation id="5230733896359313003">Leveringsadresse</translation>
<translation id="5250209940322997802">«Koble til nettverk»</translation>
<translation id="5251803541071282808">Nettsky</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Dette nettstedet på selskapets, organisasjonens eller skolens intranett har samme nettadresse som et eksternt nettsted.
<ph name="LINE_BREAK" />
Prøv å kontakte systemadministratoren din.</translation>
-<translation id="5499929369096410817">Skriv inn sikkerhetskoden for <ph name="CREDIT_CARD" />. Denne koden lagres ikke.</translation>
<translation id="5509780412636533143">Administrerte bokmerker</translation>
<translation id="5510766032865166053">Den kan ha blitt flyttet eller slettet.</translation>
<translation id="5523118979700054094">Navn på retningslinje</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Legg til leveringsadresse</translation>
<translation id="5689199277474810259">Eksportér til JSON</translation>
<translation id="5689516760719285838">Sted</translation>
+<translation id="570530837424789914">Administrer…</translation>
<translation id="5710435578057952990">Identiteten til dette nettstedet er ikke verifisert.</translation>
<translation id="5719499550583120431">Forhåndsbetalte kort godtas.</translation>
<translation id="5720705177508910913">Gjeldende bruker</translation>
+<translation id="5730040223043577876">Chrome anbefaler at du tilbakestiller passordet ditt hvis du også har brukt det på andre nettsteder.</translation>
<translation id="5732392974455271431">Foreldrene dine kan oppheve blokkeringen for deg</translation>
<translation id="5763042198335101085">Angi en gyldig e-postadresse</translation>
<translation id="5765072501007116331">For å se leveringsmetoder og -krav, velg en adresse</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Send automatisk noe <ph name="BEGIN_WHITEPAPER_LINK" />systeminformasjon og sideinnhold<ph name="END_WHITEPAPER_LINK" /> til Google for å bidra til å oppdage farlige apper og nettsteder. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Endre kontaktinformasjonen</translation>
<translation id="5967867314010545767">Fjern fra loggen</translation>
-<translation id="5972020793760134803">Bytt til fane</translation>
<translation id="5975083100439434680">Zoom ut</translation>
-<translation id="597552863672748783">Bekreft sikkerhetskoden</translation>
<translation id="598637245381783098">Kan ikke åpne betalingsappen</translation>
<translation id="5989320800837274978">Verken statiske proxytjenere eller en nettadresse med .pac-skript er angitt.</translation>
<translation id="5990559369517809815">Forespørsler til tjeneren har blitt blokkert av en utvidelse.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Dette innholdet kan prøve å lure deg til å installere programvare eller oppgi personopplysninger. <ph name="BEGIN_LINK" />Vis det likevel<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Du kan ikke gå til <ph name="SITE" /> akkurat nå, siden nettstedet bruker sertifikatfesting. Nettverksfeil og -angrep er vanligvis midlertidige, så denne siden fungerer sannsynligvis senere.</translation>
<translation id="6059925163896151826">USB-enheter</translation>
+<translation id="6071091556643036997">Regeltypen er ugyldig.</translation>
<translation id="6080696365213338172">Du har åpnet innhold via et administratorlevert sertifikat. Data du sender til <ph name="DOMAIN" /> kan stoppes av administratoren din.</translation>
<translation id="610911394827799129">Det kan hende Google-kontoen din har andre typer nettlesingslogger på <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ingen}=1{1 passord (synkronisert)}other{# passord (synkronisert)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Legg til mer informasjon</translation>
<translation id="6447842834002726250">Informasjonskapsler</translation>
<translation id="6451458296329894277">Bekreft ny innsending av skjema</translation>
+<translation id="6465306955648956876">Administrer passord…</translation>
<translation id="647261751007945333">Enhetsinnstillinger</translation>
<translation id="6477321094435799029">Chrome har oppdaget uvanlig kode på denne siden og blokkert den for å beskytte personopplysningene dine (for eksempel passord, telefonnumre og kredittkortinformasjon).</translation>
<translation id="6489534406876378309">Start opplastingen av krasj</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Søk</translation>
<translation id="6630809736994426279">Angripere som for øyeblikket er på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, kan prøve å installere farlige programmer på Macen du bruker, for å stjele eller slette informasjonen din (for eksempel bilder, passord, meldinger og kredittkortinformasjon). <ph name="BEGIN_LEARN_MORE_LINK" />Finn ut mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Denne retningslinjen er foreldet.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ingen}=1{Fra 1 nettsted (du blir ikke logget av Google-kontoen din)}other{Fra # nettsteder (du blir ikke logget av Google-kontoen din)}}</translation>
<translation id="6657585470893396449">Passord</translation>
<translation id="6671697161687535275">Vil du fjerne forslaget fra Chromium?</translation>
<translation id="6685834062052613830">Logg av og fullfør konfigurasjonen</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Bruker:</translation>
<translation id="6945221475159498467">Velg</translation>
<translation id="6948701128805548767">For å se hentemetoder og -krav, velg en adresse</translation>
+<translation id="6949872517221025916">Tilbakestill passordet</translation>
<translation id="6957887021205513506">Tjenersertifikatet ser ut til å være forfalsket.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Enhet</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Leveringsmetode</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> til}other{<ph name="PAYMENT_METHOD_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> til}}</translation>
-<translation id="7155487117670177674">Betalingen er ikke trygg</translation>
+<translation id="717330890047184534">Gaia-ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> til}other{<ph name="SHIPPING_OPTION_PREVIEW" /> og <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> til}}</translation>
<translation id="7180611975245234373">Last inn på nytt</translation>
<translation id="7182878459783632708">Ingen retningslinjer er angitt</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Bruk global standardinnstilling (Blokkér)</translation>
<translation id="7460163899615895653">De nylige fanene dine fra andre enheter vises her</translation>
<translation id="7469372306589899959">Bekrefter kortet</translation>
+<translation id="7473891865547856676">Nei takk</translation>
<translation id="7481312909269577407">Frem</translation>
<translation id="7485870689360869515">Ingen data ble funnet.</translation>
<translation id="7508255263130623398">Den returnerte enhets-ID-en for regelen er tom eller samsvarer ikke med den faktiske enhets-ID-en</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Vil du fjerne kredittkortet fra Chrome?</translation>
<translation id="7575800019233204241">«Tilkoblingen din er ikke privat», «&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;», «&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;», «&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;» eller «SSL-sertifikatfeil»</translation>
<translation id="7578104083680115302">Når du lagrer kort med Google, kan du bruke dem til å betale raskt på nettsteder og i apper – uansett hvilken enhet du bruker.</translation>
-<translation id="7588950540487816470">Fysisk nett</translation>
<translation id="7592362899630581445">Tjenerens sertifikat bryter navnereglene.</translation>
<translation id="7598391785903975535">Under <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan for øyeblikket ikke behandle denne forespørselen.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Angre endringen</translation>
<translation id="9154194610265714752">Oppdatert</translation>
<translation id="9157595877708044936">Konfigurerer ...</translation>
+<translation id="9168814207360376865">Tillatt nettsteder å sjekke om du har noen lagrede betalingsmåter</translation>
<translation id="9169664750068251925">Blokkér alltid på dette nettstedet</translation>
<translation id="9170848237812810038">&amp;Angre</translation>
<translation id="917450738466192189">Tjenerens sertifikat er ugyldig.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Kunne ikke legge til artikkelen.</translation>
<translation id="9215416866750762878">Et program hindrer Chrome i å koble trygt til dette nettstedet.</translation>
<translation id="9219103736887031265">Bilder</translation>
-<translation id="933612690413056017">Du er ikke koblet til Internett</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">SLETT INNHOLDET I SKJEMAET</translation>
<translation id="939736085109172342">Ny mappe</translation>
diff --git a/chromium/components/strings/components_strings_pl.xtb b/chromium/components/strings/components_strings_pl.xtb
index 2102c1912c4..fcbd57c5c63 100644
--- a/chromium/components/strings/components_strings_pl.xtb
+++ b/chromium/components/strings/components_strings_pl.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Wybierz uprawnienia dla: <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Ostatnio używane zakładki</translation>
<translation id="1113869188872983271">&amp;Cofnij zmianę kolejności</translation>
+<translation id="1125573121925420732">Ostrzeżenia mogą pojawiać się często, dopóki strony internetowe nie zaktualizują swoich zabezpieczeń. Wkrótce powinno się to poprawić.</translation>
<translation id="1126551341858583091">Rozmiar w pamięci lokalnej: <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Pamięć podręczna zasad: OK</translation>
<translation id="1150979032973867961">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest zaufany w systemie operacyjnym tego komputera. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Upewnij się, że połączenie internetowe działa prawidłowo.&lt;/li&gt;
&lt;li&gt;Skontaktuj się z właścicielem strony.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Wpisałeś swoje hasło na stronie, którą nie zarządza Twoja organizacja. Aby chronić konto, nie używaj swojego hasła w innych aplikacjach ani na innych stronach.</translation>
<translation id="1263231323834454256">Do przeczytania</translation>
<translation id="1264126396475825575">Utworzono raport o awarii w dniu: <ph name="CRASH_TIME" /> (nie został jeszcze przesłany ani zignorowany)</translation>
<translation id="1270502636509132238">Metoda odbioru</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Wybierz</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Zapobiegaj wyświetlaniu dodatkowych okien dialogowych na tej stronie</translation>
-<translation id="1629803312968146339">Czy Chrome ma zapisać tę kartę?</translation>
<translation id="1639239467298939599">Wczytuję</translation>
<translation id="1640180200866533862">Zasady dotyczące użytkowników</translation>
<translation id="1640244768702815859">Otwórz <ph name="BEGIN_LINK" />stronę główną witryny<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Uruchom Diagnostykę sieci systemu Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Zaktualizuj swoje hasło synchronizacji.</translation>
<translation id="1787142507584202372">Tutaj pojawiają się otwarte karty</translation>
-<translation id="1789575671122666129">Wyskakujące okienka</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Imię i nazwisko posiadacza karty</translation>
<translation id="1806541873155184440">Dodano: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Uruchom ponownie komputer</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Ignorowana, ponieważ jest zastąpiona przez <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Szukam stron internetu rzeczy w pobliżu</translation>
<translation id="213826338245044447">Zakładki na komórce</translation>
<translation id="214556005048008348">Anuluj płatność</translation>
<translation id="2147827593068025794">Synchronizacja w tle</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Nie znaleziono zasady</translation>
<translation id="2213606439339815911">Pobieram wpisy...</translation>
<translation id="2218879909401188352">Osoby obecnie atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą instalować niebezpieczne aplikacje, które mogą uszkodzić Twoje urządzenie, dodać ukryte opłaty do rachunku za usługi telefoniczne lub wykraść Twoje dane osobowe. <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Brak internetu</translation>
<translation id="2230458221926704099">Napraw połączenie, używając <ph name="BEGIN_LINK" />aplikacji diagnostycznej<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Wyślij teraz</translation>
<translation id="225207911366869382">Ta wartość tej zasady została wycofana.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Usuń wybrane elementy</translation>
<translation id="277133753123645258">Metoda wysyłki</translation>
<translation id="277499241957683684">Brak rekordu urządzenia</translation>
+<translation id="2781030394888168909">Eksportuj (MacOS)</translation>
<translation id="2784949926578158345">Połączenie zostało zresetowane.</translation>
<translation id="2788784517760473862">Akceptowane karty kredytowe</translation>
<translation id="2794233252405721443">Strona zablokowana</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome nie może obecnie potwierdzić karty. Spróbuj ponownie później.</translation>
<translation id="3064966200440839136">Opuszczasz tryb incognito, by zapłacić w aplikacji zewnętrznej. Kontynuować?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Brak}=1{1 hasło}few{# hasła}many{# haseł}other{# hasła}}</translation>
-<translation id="3093245981617870298">Jesteś offline.</translation>
<translation id="3096100844101284527">Dodaj adres odbioru</translation>
<translation id="3105172416063519923">Identyfikator zasobu:</translation>
<translation id="3109728660330352905">Nie masz uprawnień do wyświetlania tej strony.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Strona <ph name="HOST_NAME" /> jest obecnie nieosiągalna.</translation>
<translation id="3427092606871434483">Zezwalaj (domyślnie)</translation>
<translation id="3427342743765426898">&amp;Ponów edycję</translation>
+<translation id="342781501876943858">Chromium zaleca zresetowanie hasła, jeśli zostało użyte na innej stronie.</translation>
<translation id="3431636764301398940">Zapisz tę kartę na tym urządzeniu</translation>
<translation id="3447661539832366887">Właściciel tego urządzenia wyłączył grę z dinozaurem.</translation>
<translation id="3447884698081792621">Pokaż certyfikat (wydany przez: <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Otwórz stronę w nowym oknie incognito (Ctrl+Shift+N)</translation>
<translation id="3679803492151881375">Raport o awarii zarejestrowano: <ph name="CRASH_TIME" />, przesłano: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informacje o certyfikacie</translation>
-<translation id="3690164694835360974">Logowanie nie jest bezpieczne</translation>
<translation id="3704162925118123524">Sieć, której używasz, może wymagać otwarcia strony logowania.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Ładuję...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Użyj globalnego ustawienia domyślnego (Wykrywaj)</translation>
<translation id="4165986682804962316">Ustawienia witryn</translation>
-<translation id="4169947484918424451">Czy Chromium ma zapisać tę kartę?</translation>
<translation id="4171400957073367226">Nieprawidłowy podpis weryfikujący</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Jeszcze <ph name="ITEM_COUNT" /> element}few{Jeszcze <ph name="ITEM_COUNT" /> elementy}many{Jeszcze <ph name="ITEM_COUNT" /> elementów}other{Jeszcze <ph name="ITEM_COUNT" /> elementu}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Zrestartuj urządzenie</translation>
<translation id="4277028893293644418">Resetuj hasło</translation>
<translation id="4280429058323657511">, ważna do: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Przełącz</translation>
<translation id="4312866146174492540">Blokuj (domyślnie)</translation>
<translation id="4325863107915753736">Nie udało się znaleźć artykułu</translation>
<translation id="4326324639298822553">Sprawdź datę ważności i spróbuj ponownie</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Ten komputer nie został wykryty jako zarządzany przez firmę, przez co zasada może instalować automatycznie tylko rozszerzenia hostowane w Chrome Web Store. URL sklepu Chrome Web Store służący do aktualizacji to „<ph name="CWS_UPDATE_URL" />”.</translation>
<translation id="4346197816712207223">Akceptowane karty kredytowe</translation>
<translation id="4356973930735388585">Osoby atakujące tę stronę mogą próbować zainstalować na Twoim komputerze niebezpieczne programy przeznaczone do kradzieży lub usuwania Twoich danych (na przykład zdjęć, haseł, wiadomości czy numerów kart kredytowych).</translation>
+<translation id="4358461427845829800">Zarządzaj formami płatności…</translation>
<translation id="4372948949327679948">Oczekiwano wartości typu <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Próbujesz wejść na <ph name="DOMAIN" />, ale serwer przedstawił certyfikat unieważniony przez wystawcę. Oznacza to, że dane uwierzytelniające podane przez serwer są zupełnie niewiarygodne. Możliwe, że komunikujesz się z intruzem.</translation>
<translation id="4406896451731180161">wyniki wyszukiwania</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Adres odbioru</translation>
<translation id="4424024547088906515">Ten serwer nie mógł udowodnić, że należy do <ph name="DOMAIN" />. Jego certyfikat bezpieczeństwa nie jest zaufany w Chrome. Może to być spowodowane błędną konfiguracją lub przechwyceniem połączenia przez atakującego.</translation>
<translation id="4432688616882109544">Serwer <ph name="HOST_NAME" /> nie zaakceptował lub nie otrzymał Twojego certyfikatu logowania.</translation>
+<translation id="4434045419905280838">Pop-upy i przekierowania</translation>
<translation id="443673843213245140">Korzystanie z serwera proxy jest wyłączone, ale podano konfigurację proxy.</translation>
<translation id="445100540951337728">Akceptowane karty debetowe</translation>
<translation id="4506176782989081258">Błąd sprawdzania poprawności: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Autouzupełnianie danych o płatności jest wyłączone</translation>
<translation id="4764776831041365478">Strona internetowa pod adresem <ph name="URL" /> może być tymczasowo niedostępna lub została na stałe przeniesiona pod nowy adres internetowy.</translation>
<translation id="4771973620359291008">Wystąpił nieznany błąd.</translation>
+<translation id="4785689107224900852">Przełącz na tę kartę</translation>
<translation id="4792143361752574037">Podczas uzyskiwania dostępu do plików sesji wystąpił problem. Zapisywanie na dysku jest obecnie wyłączone. Załaduj stronę jeszcze i raz i spróbuj ponownie.</translation>
<translation id="4800132727771399293">Sprawdź datę ważności i kod CVC, a potem spróbuj ponownie</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Nie możesz teraz wejść na stronę <ph name="SITE" />, bo wysłała ona zaszyfrowane dane logowania, których Google Chrome nie może przetworzyć. Błędy sieci i ataki są zazwyczaj przejściowe, więc prawdopodobnie strona będzie wkrótce działać.</translation>
<translation id="4813512666221746211">Błąd sieci</translation>
<translation id="4816492930507672669">Dopasuj do strony</translation>
-<translation id="483020001682031208">Brak stron internetu rzeczy do pokazania</translation>
<translation id="4850886885716139402">Widok</translation>
<translation id="4854362297993841467">Ta metoda dostawy jest niedostępna. Wybierz inną.</translation>
<translation id="4858792381671956233">Zapytałeś rodziców, czy możesz wejść na tę stronę</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bitowa)</translation>
<translation id="5121084798328133320">Po potwierdzeniu szczegółowe dane karty z Twojego konta Google Payments zostaną udostępnione tej stronie.</translation>
<translation id="5128122789703661928">Nie możesz usunąć tej sesji, bo jej nazwa jest nieprawidłowa.</translation>
+<translation id="5135404736266831032">Zarządzaj adresami…</translation>
<translation id="5141240743006678641">Szyfruj synchronizowane hasła za pomocą danych logowania Google</translation>
<translation id="5145883236150621069">W odebranej polityce znajduje się kod błędu</translation>
<translation id="5159010409087891077">Otwórz stronę w nowym oknie incognito (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Komunikat z elementu umieszczonego na bieżącej stronie</translation>
<translation id="5205222826937269299">Nazwa jest wymagana</translation>
<translation id="5222812217790122047">E-mail jest wymagany</translation>
-<translation id="522700295135997067">Możliwe, że ta strona właśnie wykradła Twoje hasło</translation>
<translation id="5230733896359313003">Adres wysyłki</translation>
<translation id="5250209940322997802">„Połącz z siecią”</translation>
<translation id="5251803541071282808">Chmura</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Ta witryna w intranecie firmy, organizacji czy szkoły ma ten sam URL co zewnętrzna strona internetowa.
<ph name="LINE_BREAK" />
Skontaktuj się z administratorem systemu.</translation>
-<translation id="5499929369096410817">Podaj kod zabezpieczający dla karty <ph name="CREDIT_CARD" />. Nie zostanie on zapisany.</translation>
<translation id="5509780412636533143">Zakładki zarządzane</translation>
<translation id="5510766032865166053">Mógł zostać przeniesiony lub usunięty.</translation>
<translation id="5523118979700054094">Nazwa zasady</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Dodaj adres wysyłki</translation>
<translation id="5689199277474810259">Eksportuj w formacie JSON</translation>
<translation id="5689516760719285838">Lokalizacja</translation>
+<translation id="570530837424789914">Zarządzaj…</translation>
<translation id="5710435578057952990">Tożsamość witryny nie została zweryfikowana.</translation>
<translation id="5719499550583120431">Karty przedpłacone są akceptowane.</translation>
<translation id="5720705177508910913">Bieżący użytkownik</translation>
+<translation id="5730040223043577876">Chrome zaleca zresetowanie hasła, jeśli zostało użyte na innej stronie.</translation>
<translation id="5732392974455271431">Mogą ją dla Ciebie odblokować Twoi rodzice</translation>
<translation id="5763042198335101085">Wpisz prawidłowy adres e-mail</translation>
<translation id="5765072501007116331">Aby zobaczyć metody dostawy oraz wymagania, wybierz adres</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Automatycznie wysyłaj do Google niektóre <ph name="BEGIN_WHITEPAPER_LINK" />informacje o systemie i część zawartości stron<ph name="END_WHITEPAPER_LINK" />, by pomóc w wykrywaniu niebezpiecznych aplikacji i witryn. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edytuj dane kontaktowe</translation>
<translation id="5967867314010545767">Usuń z historii</translation>
-<translation id="5972020793760134803">Przełącz na kartę</translation>
<translation id="5975083100439434680">Pomniejsz</translation>
-<translation id="597552863672748783">Potwierdź kod zabezpieczający</translation>
<translation id="598637245381783098">Nie można otworzyć aplikacji do płatności</translation>
<translation id="5989320800837274978">Nie określono ani stałych serwerów proxy, ani adresu URL skryptu PAC.</translation>
<translation id="5990559369517809815">Żądania do serwera zostały zablokowane przez rozszerzenie.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Te treści mogą próbować podstępem nakłonić Cię do zainstalowania oprogramowania lub ujawnienia danych osobowych. <ph name="BEGIN_LINK" />Wyświetl mimo to<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Nie możesz teraz otworzyć strony <ph name="SITE" />, ponieważ stosuje ona przypinanie certyfikatów. Błędy sieciowe i ataki są zazwyczaj tymczasowe, więc prawdopodobnie strona będzie dostępna później.</translation>
<translation id="6059925163896151826">Urządzenia USB</translation>
+<translation id="6071091556643036997">Typ zasady jest nieprawidłowy.</translation>
<translation id="6080696365213338172">Masz dostęp do treści dzięki certyfikatowi dostarczonemu przez administratora. Administrator może odczytać dane, jakie udostępnisz w <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">Inne rodzaje historii przeglądania mogą być nadal dostępne na Twoim koncie Google na <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Brak}=1{1 hasło (synchronizowane)}few{# hasła (synchronizowane)}many{# haseł (synchronizowanych)}other{# hasła (synchronizowanego)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Dodaj więcej informacji</translation>
<translation id="6447842834002726250">Pliki cookie</translation>
<translation id="6451458296329894277">Potwierdź ponowne przesłanie formularza</translation>
+<translation id="6465306955648956876">Zarządzaj hasłami…</translation>
<translation id="647261751007945333">Zasady dotyczące urządzeń</translation>
<translation id="6477321094435799029">Chrome wykrył nietypowy kod na tej stronie i zablokował ją, by chronić Twoje dane osobowe (np. hasła, numery telefonu czy dane kart kredytowych).</translation>
<translation id="6489534406876378309">Rozpocznij przesyłanie informacji o awariach</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Wyszukiwarka <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Osoby obecnie atakujące stronę <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> mogą próbować zainstalować na Twoim komputerze Mac niebezpieczne programy wykradające lub usuwające informacje (na przykład zdjęcia, hasła, wiadomości lub dane kart kredytowych). <ph name="BEGIN_LEARN_MORE_LINK" />Więcej informacji<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Zasada jest przestarzała.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Brak}=1{Z 1 witryny (nie spowoduje to wylogowania z konta Google)}few{Z # witryn (nie spowoduje to wylogowania z konta Google)}many{Z # witryn (nie spowoduje to wylogowania z konta Google)}other{Z # witryny (nie spowoduje to wylogowania z konta Google)}}</translation>
<translation id="6657585470893396449">Hasło</translation>
<translation id="6671697161687535275">Usunąć tę podpowiedź do formularza z Chromium?</translation>
<translation id="6685834062052613830">Wyloguj się i dokończ konfigurację</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Użytkownik:</translation>
<translation id="6945221475159498467">Wybierz</translation>
<translation id="6948701128805548767">Aby zobaczyć metody odbioru oraz wymagania, wybierz adres</translation>
+<translation id="6949872517221025916">Resetuj hasło</translation>
<translation id="6957887021205513506">Certyfikat serwera wydaje się sfałszowany.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Urządzenie</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Metoda dostawy</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}many{<ph name="PAYMENT_METHOD_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Płatność nie jest bezpieczna</translation>
+<translation id="717330890047184534">Identyfikator GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}many{<ph name="SHIPPING_OPTION_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> i jeszcze <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Odśwież</translation>
<translation id="7182878459783632708">Brak ustawionych zasad</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Użyj globalnej wartości domyślnej (Blokuj)</translation>
<translation id="7460163899615895653">W tym miejscu pojawią się Twoje ostatnie karty z innych urządzeń</translation>
<translation id="7469372306589899959">Potwierdzam kartę</translation>
+<translation id="7473891865547856676">Nie, dziękuję</translation>
<translation id="7481312909269577407">Dalej</translation>
<translation id="7485870689360869515">Nie znaleziono danych.</translation>
<translation id="7508255263130623398">Zwrócony identyfikator urządzenia dla zasad jest pusty lub nie pasuje do bieżącego identyfikatora urządzenia</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Usunąć tę kartę kredytową z Chrome?</translation>
<translation id="7575800019233204241">„Połączenie nie jest prywatne” lub „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;” lub „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;” lub „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;” lub „Błąd certyfikatu SSL”</translation>
<translation id="7578104083680115302">Używaj swoich kart zapisanych w Google, by łatwiej dokonywać płatności na stronach i w aplikacjach na różnych urządzeniach.</translation>
-<translation id="7588950540487816470">Internet rzeczy</translation>
<translation id="7592362899630581445">Certyfikat serwera narusza ograniczenia dotyczące nazw.</translation>
<translation id="7598391785903975535">Mniej niż <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Serwer <ph name="HOST_NAME" /> nie może teraz obsłużyć tego żądania.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Cofnij edycję</translation>
<translation id="9154194610265714752">Zaktualizowano</translation>
<translation id="9157595877708044936">Konfigurowanie...</translation>
+<translation id="9168814207360376865">Zezwalaj stronom na sprawdzanie, czy masz zapisane formy płatności</translation>
<translation id="9169664750068251925">Zawsze blokuj w tej witrynie</translation>
<translation id="9170848237812810038">&amp;Cofnij</translation>
<translation id="917450738466192189">Certyfikat serwera jest nieprawidłowy.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Nie udało się dodać artykułu.</translation>
<translation id="9215416866750762878">Aplikacja uniemożliwia Chrome bezpieczne połączenie się z tą stroną</translation>
<translation id="9219103736887031265">Grafika</translation>
-<translation id="933612690413056017">Brak połączenia z internetem</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">WYCZYŚĆ FORMULARZ</translation>
<translation id="939736085109172342">Nowy folder</translation>
diff --git a/chromium/components/strings/components_strings_pt-BR.xtb b/chromium/components/strings/components_strings_pt-BR.xtb
index 76cbb456889..aed9dde45ae 100644
--- a/chromium/components/strings/components_strings_pt-BR.xtb
+++ b/chromium/components/strings/components_strings_pt-BR.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Selecione uma permissão para <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Favoritos recentes</translation>
<translation id="1113869188872983271">&amp;Desfazer reordenar</translation>
+<translation id="1125573121925420732">Avisos podem ser comuns enquanto os sites atualizam a segurança. Isso deve melhorar em breve.</translation>
<translation id="1126551341858583091">O tamanho no armazenamento local é de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache da política OK</translation>
<translation id="1150979032973867961">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança não é confiável para o sistema operacional do seu computador. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Verifique se sua conexão com a Internet está funcionando normalmente.&lt;/li&gt;
&lt;li&gt;Entre em contato com o proprietário do site.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Você informou sua senha em um site que não é gerenciado pela sua organização. Para proteger sua conta, não reutilize sua senha em outros apps e sites.</translation>
<translation id="1263231323834454256">Lista de leitura</translation>
<translation id="1264126396475825575">Relatório de erros registrado em <ph name="CRASH_TIME" /> (ainda não enviado ou ignorado)</translation>
<translation id="1270502636509132238">Método de Retirada</translation>
@@ -78,7 +80,7 @@
<translation id="14171126816530869">A identidade de <ph name="ORGANIZATION" /> em <ph name="LOCALITY" /> foi confirmada por <ph name="ISSUER" />.</translation>
<translation id="1426410128494586442">Sim</translation>
<translation id="1430915738399379752">Imprimir</translation>
-<translation id="1484290072879560759">Escolher endereço para envio</translation>
+<translation id="1484290072879560759">Escolher endereço de entrega</translation>
<translation id="1506687042165942984">Mostrar uma cópia salva (ou seja, reconhecidamente desatualizada) desta página.</translation>
<translation id="1507202001669085618">&lt;p&gt;Você verá esse erro se estiver usando um portal Wi-Fi em que precise fazer login para poder se conectar.&lt;/p&gt;
&lt;p&gt;Para corrigir o erro, clique em &lt;strong&gt;Conectar&lt;/strong&gt; na página que você está tentando abrir.&lt;/p&gt;</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Escolher</translation>
<translation id="1620510694547887537">Câmera</translation>
<translation id="1623104350909869708">Impedir que esta página crie caixas de diálogo adicionais</translation>
-<translation id="1629803312968146339">Quer que o Chrome salve este cartão?</translation>
<translation id="1639239467298939599">Carregando</translation>
<translation id="1640180200866533862">Políticas de usuário</translation>
<translation id="1640244768702815859">Tente <ph name="BEGIN_LINK" />visitar a página inicial do site<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Tente executar o Diagnóstico de Rede do Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Favor atualizar sua senha de sincronização.</translation>
<translation id="1787142507584202372">Suas guias abertas são exibidas aqui</translation>
-<translation id="1789575671122666129">Pop-ups</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nome do titular do cartão</translation>
<translation id="1806541873155184440">Adicionado em: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Reiniciar seu computador</translation>
<translation id="2113977810652731515">Cartão</translation>
<translation id="2114841414352855701">Ignorado porque foi substituído por <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Procurando páginas da Web física nas proximidades</translation>
<translation id="213826338245044447">Favoritos de dispositivos móveis</translation>
<translation id="214556005048008348">Cancelar pagamento</translation>
<translation id="2147827593068025794">Sincronização em segundo plano</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">Buscando entradas...</translation>
<translation id="2218879909401188352">Os invasores que estão em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> no momento podem instalar apps perigosos que danificam seu dispositivo, acrescentam cobranças ocultas junto à operadora ou roubam suas informações pessoais. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Sem Internet</translation>
<translation id="2230458221926704099">Corrija sua conexão usando o <ph name="BEGIN_LINK" />app de diagnóstico<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Enviar agora</translation>
<translation id="225207911366869382">Este valor está obsoleto para esta política.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Remover itens selecionados</translation>
<translation id="277133753123645258">Método de envio</translation>
<translation id="277499241957683684">Registro de dispositivo não encontrado</translation>
+<translation id="2781030394888168909">Exportar para MacOS</translation>
<translation id="2784949926578158345">A conexão foi redefinida.</translation>
<translation id="2788784517760473862">Cartões de crédito aceitos</translation>
<translation id="2794233252405721443">Site bloqueado</translation>
@@ -276,7 +277,7 @@
<translation id="2909946352844186028">Foi detectada uma alteração na rede.</translation>
<translation id="2916038427272391327">Fechar outros programas</translation>
<translation id="2922350208395188000">O certificado do servidor não pode ser verificado.</translation>
-<translation id="2925673989565098301">Método de Exibição</translation>
+<translation id="2925673989565098301">Método de envio</translation>
<translation id="2928905813689894207">Endereço de cobrança</translation>
<translation id="2929525460561903222">{SHIPPING_ADDRESS,plural, =0{<ph name="SHIPPING_ADDRESS_PREVIEW" />}=1{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}one{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}other{<ph name="SHIPPING_ADDRESS_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_ADDRESSES" />}}</translation>
<translation id="2941952326391522266">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança é de <ph name="DOMAIN2" />. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Não foi possível confirmar seu cartão com o Chrome no momento. Tente novamente mais tarde.</translation>
<translation id="3064966200440839136">Saindo do modo de navegação anônima para pagar usando um aplicativo externo. Continuar?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nenhuma}=1{1 senha}one{# senha}other{# senhas}}</translation>
-<translation id="3093245981617870298">Você está off-line.</translation>
<translation id="3096100844101284527">Adicionar endereço de retirada</translation>
<translation id="3105172416063519923">Código do recurso:</translation>
<translation id="3109728660330352905">Você não tem autorização para ver esta página.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">No momento, não é possível acessar <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Permitir (padrão)</translation>
<translation id="3427342743765426898">&amp;Refazer editar</translation>
+<translation id="342781501876943858">O Chromium recomenda redefinir sua senha se você a reutilizou em outros sites.</translation>
<translation id="3431636764301398940">Salvar este cartão neste dispositivo</translation>
<translation id="3447661539832366887">O proprietário deste dispositivo desativou o jogo do dinossauro.</translation>
<translation id="3447884698081792621">Mostrar certificado (emitido por <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Abrir página em uma nova janela anônima (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Relatório de erros registrado em <ph name="CRASH_TIME" />, enviado em <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informações do certificado</translation>
-<translation id="3690164694835360974">Login não seguro</translation>
<translation id="3704162925118123524">A rede que você está usando pode exigir que você visite a página de login.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Carregando...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Usar padrão global (Detectar)</translation>
<translation id="4165986682804962316">Configurações do site</translation>
-<translation id="4169947484918424451">Quer que o Chromium salve este cartão?</translation>
<translation id="4171400957073367226">Assinatura de verificação inválida</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Mais <ph name="ITEM_COUNT" /> item}one{Mais <ph name="ITEM_COUNT" /> item}other{Mais <ph name="ITEM_COUNT" /> itens}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Reiniciar seu dispositivo</translation>
<translation id="4277028893293644418">Redefinir senha</translation>
<translation id="4280429058323657511">, validade <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Alternar</translation>
<translation id="4312866146174492540">Bloquear (padrão)</translation>
<translation id="4325863107915753736">Falha ao encontrar artigo</translation>
<translation id="4326324639298822553">Verifique a data de validade e tente novamente</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Este computador não foi detectado como gerenciado por empresa, portanto, a política só pode instalar automaticamente as extensões hospedadas na Chrome Web Store. O URL de atualização da Chrome Web Store é o seguinte: <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Cartões de crédito aceitos</translation>
<translation id="4356973930735388585">Invasores nesse site podem tentar instalar programas perigosos no seu computador para roubar ou excluir informações (por exemplo, fotos, senhas, mensagens e cartões de crédito).</translation>
+<translation id="4358461427845829800">Gerenciar formas de pagamento…</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperado.</translation>
<translation id="4377125064752653719">Você tentou acessar <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo seu emissor. Isso significa que as credenciais de segurança que o servidor apresentou não são nem um pouco seguras. Talvez você esteja se comunicando com um invasor.</translation>
<translation id="4406896451731180161">resultados da pesquisa</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Endereço de Retirada</translation>
<translation id="4424024547088906515">Este servidor não conseguiu provar que é <ph name="DOMAIN" />. O certificado de segurança não é confiável para o Chrome. Isso pode ser causado por uma configuração incorreta ou pela interceptação da sua conexão por um invasor.</translation>
<translation id="4432688616882109544">O certificado de login não foi aceito por <ph name="HOST_NAME" /> ou não foi fornecido.</translation>
+<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
<translation id="443673843213245140">O uso de um proxy está desativado, mas uma configuração explícita de proxy é especificada.</translation>
<translation id="445100540951337728">Cartões de débito aceitos</translation>
<translation id="4506176782989081258">Erro de validação: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Preenchimento automático de pagamento desativado</translation>
<translation id="4764776831041365478">A página da web em <ph name="URL" /> pode estar temporariamente indisponível ou pode ter sido movida permanentemente para um novo endereço da Web.</translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
+<translation id="4785689107224900852">Alternar para esta guia</translation>
<translation id="4792143361752574037">Ocorreu um problema ao acessar os arquivos de sessão. O salvamento em disco está desativado no momento. Atualize a página e tente novamente.</translation>
<translation id="4800132727771399293">Verifique sua data de validade e seu CVC e tente novamente</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Não é possível acessar <ph name="SITE" /> no momento, porque o website enviou credenciais codificadas que o Google Chrome não pode processar. Ataques e erros de rede geralmente são temporários. Portanto, essa página provavelmente funcionará mais tarde.</translation>
<translation id="4813512666221746211">Erro na rede</translation>
<translation id="4816492930507672669">Ajustar à página</translation>
-<translation id="483020001682031208">Nenhuma página da Web física para exibição</translation>
<translation id="4850886885716139402">Visualizar</translation>
<translation id="4854362297993841467">Esse método de entrega não está disponível. Tente um método diferente.</translation>
<translation id="4858792381671956233">Você perguntou aos seus responsáveis se pode visitar este site</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">64 bits</translation>
<translation id="5121084798328133320">Depois da confirmação, os detalhes do cartão da sua conta do Google Payments serão compartilhados com esse site.</translation>
<translation id="5128122789703661928">A sessão com este nome não é válida para exclusão.</translation>
+<translation id="5135404736266831032">Gerenciar endereços…</translation>
<translation id="5141240743006678641">Criptografar senhas sincronizadas com suas credenciais do Google</translation>
<translation id="5145883236150621069">Código de erro presente na resposta da política</translation>
<translation id="5159010409087891077">Abrir página em uma nova janela anônima (⇧⌘N)</translation>
@@ -600,8 +603,7 @@
<translation id="5201306358585911203">Uma página incorporada nesta página diz</translation>
<translation id="5205222826937269299">Nome obrigatório</translation>
<translation id="5222812217790122047">E-mail obrigatório</translation>
-<translation id="522700295135997067">Este site pode ter acabado de roubar sua senha</translation>
-<translation id="5230733896359313003">Endereço para envio</translation>
+<translation id="5230733896359313003">Endereço de entrega</translation>
<translation id="5250209940322997802">"Conectar-se à rede"</translation>
<translation id="5251803541071282808">Nuvem</translation>
<translation id="5281113152797308730"><ph name="BEGIN_PARAGRAPH" />Siga estas etapas para desativar temporariamente o software e entrar na Web. Para isso, você precisará de privilégios de administrador.<ph name="END_PARAGRAPH" />
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Esse site na intranet da empresa, organização ou escola tem o mesmo URL de um website externo.
<ph name="LINE_BREAK" />
Tente entrar em contato com o administrador do sistema.</translation>
-<translation id="5499929369096410817">Insira o código de segurança do <ph name="CREDIT_CARD" />. Este código não será salvo.</translation>
<translation id="5509780412636533143">Favoritos gerenciados</translation>
<translation id="5510766032865166053">Talvez tenha sido movido ou excluído.</translation>
<translation id="5523118979700054094">Nome da política</translation>
@@ -672,12 +673,14 @@
<translation id="563324245173044180">Conteúdo enganoso bloqueado.</translation>
<translation id="5659593005791499971">E-mail</translation>
<translation id="5675650730144413517">Esta página não está funcionando</translation>
-<translation id="5685654322157854305">Adicionar endereço para envio</translation>
+<translation id="5685654322157854305">Adicionar endereço de entrega</translation>
<translation id="5689199277474810259">Exportar para JSON</translation>
<translation id="5689516760719285838">Local</translation>
+<translation id="570530837424789914">Gerenciar…</translation>
<translation id="5710435578057952990">A identidade deste site não foi confirmada.</translation>
<translation id="5719499550583120431">Cartões pré-pagos são aceitos.</translation>
<translation id="5720705177508910913">Usuário atual</translation>
+<translation id="5730040223043577876">O Chrome recomenda redefinir sua senha se você a reutilizou em outros sites.</translation>
<translation id="5732392974455271431">Seus responsáveis podem desbloqueá-lo para você</translation>
<translation id="5763042198335101085">Informe um endereço de e-mail válido.</translation>
<translation id="5765072501007116331">Para ver métodos e requisitos de entrega, selecione um endereço</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Enviar automaticamente <ph name="BEGIN_WHITEPAPER_LINK" />algumas informações do sistema e conteúdos de página<ph name="END_WHITEPAPER_LINK" /> ao Google para ajudar a detectar sites e apps perigosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Edite as Informações de Contato</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
-<translation id="5972020793760134803">Alternar guia</translation>
<translation id="5975083100439434680">Diminuir zoom</translation>
-<translation id="597552863672748783">Confirme o código de segurança</translation>
<translation id="598637245381783098">Não foi possível abrir app de pagamento</translation>
<translation id="5989320800837274978">Nem os servidores proxy fixos nem o URL de script .pac foram especificados.</translation>
<translation id="5990559369517809815">Solicitações ao servidor foram bloqueadas por uma extensão.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Este conteúdo pode tentar enganar você para que instale um software ou revele informações pessoais. <ph name="BEGIN_LINK" />Mostrar mesmo assim<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Não é possível acessar <ph name="SITE" /> no momento, porque o site usa bloqueio de certificados. Como os ataques e erros de rede são geralmente temporários, esta pagina provavelmente funcionará mais tarde.</translation>
<translation id="6059925163896151826">Dispositivos USB</translation>
+<translation id="6071091556643036997">O tipo de política é inválido.</translation>
<translation id="6080696365213338172">Você acessou conteúdo usando um certificado fornecido pelo administrador. Os dados fornecidos a <ph name="DOMAIN" /> podem ser interceptados por seu administrador.</translation>
<translation id="610911394827799129">Sua Conta do Google pode ter outras formas de histórico de navegação em <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nenhuma}=1{1 senha (sincronizada)}one{# senha (sincronizada)}other{# senhas (sincronizadas)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Adicionar mais informações</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Confirmar reenvio do formulário</translation>
+<translation id="6465306955648956876">Gerenciar senhas…</translation>
<translation id="647261751007945333">Políticas de dispositivos</translation>
<translation id="6477321094435799029">O Chrome detectou um código incomum nesta página e a bloqueou para proteger suas informações pessoais (por exemplo, senhas, números de telefone e cartões de crédito).</translation>
<translation id="6489534406876378309">Iniciar upload de falhas</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Pesquisa do <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Invasores presentes no momento em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar programas perigosos no seu Mac e roubar ou excluir suas informações (por exemplo, fotos, senhas, mensagens e cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Esta política foi encerrada.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nenhum}=1{Em 1 site (você não será desconectado da sua Conta do Google)}one{Em # site (você não será desconectado da sua Conta do Google)}other{Em # sites (você não será desconectado da sua Conta do Google)}}</translation>
<translation id="6657585470893396449">Senha</translation>
<translation id="6671697161687535275">Remover sugestão de formulário do Chromium?</translation>
<translation id="6685834062052613830">Saia e conclua a configuração</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Usuário:</translation>
<translation id="6945221475159498467">Selecionar</translation>
<translation id="6948701128805548767">Para ver métodos e requisitos de retirada, selecione um endereço</translation>
+<translation id="6949872517221025916">Redefinir senha</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser falsificado.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Método de entrega</translation>
<translation id="7139724024395191329">Emirado</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Pagamento não seguro</translation>
+<translation id="717330890047184534">Código Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Atualizar</translation>
<translation id="7182878459783632708">Não há políticas definidas</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Usar padrão global (Bloquear)</translation>
<translation id="7460163899615895653">Suas guias recentes de outros dispositivos são exibidas aqui</translation>
<translation id="7469372306589899959">Confirmando cartão</translation>
+<translation id="7473891865547856676">Não, obrigado</translation>
<translation id="7481312909269577407">Avançar</translation>
<translation id="7485870689360869515">Nenhum dado encontrado</translation>
<translation id="7508255263130623398">O código do dispositivo da política retornado está em branco ou não corresponde ao código do dispositivo atual</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Remover cartão de crédito do Chrome?</translation>
<translation id="7575800019233204241">"Sua conexão não é particular", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" ou "Erro de certificado SSL"</translation>
<translation id="7578104083680115302">Pague rapidamente em sites e aplicativos em vários dispositivos usando os cards que você salvou com o Google.</translation>
-<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">O certificado do servidor viola as restrições de nome.</translation>
<translation id="7598391785903975535">Menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> não consegue atender a esta solicitação no momento.</translation>
@@ -1108,6 +1113,7 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="9148507642005240123">&amp;Desfazer editar</translation>
<translation id="9154194610265714752">Atualizado</translation>
<translation id="9157595877708044936">Configurando...</translation>
+<translation id="9168814207360376865">Permitir que os sites verifiquem se você tem formas de pagamento salvas</translation>
<translation id="9169664750068251925">Sempre bloquear neste site</translation>
<translation id="9170848237812810038">&amp;Desfazer</translation>
<translation id="917450738466192189">O certificado do servidor é inválido.</translation>
@@ -1116,7 +1122,6 @@ incomuns e incorretas. Isso pode acontecer quando um invasor está fingindo ser
<translation id="9207861905230894330">Falha ao adicionar artigo.</translation>
<translation id="9215416866750762878">Um aplicativo está impedindo que o Chrome se conecte com segurança a este site</translation>
<translation id="9219103736887031265">Imagens</translation>
-<translation id="933612690413056017">Não há conexão com a Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">LIMPAR FORMULÁRIO</translation>
<translation id="939736085109172342">Nova pasta</translation>
diff --git a/chromium/components/strings/components_strings_pt-PT.xtb b/chromium/components/strings/components_strings_pt-PT.xtb
index 0f10ed8164d..a278095e400 100644
--- a/chromium/components/strings/components_strings_pt-PT.xtb
+++ b/chromium/components/strings/components_strings_pt-PT.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Selecionar autorização para <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Marcadores recentes</translation>
<translation id="1113869188872983271">&amp;Anular reordenação</translation>
+<translation id="1125573121925420732">Pode ser frequente a apresentação de avisos enquanto os Websites atualizam a respetiva segurança. Esta situação deve melhorar brevemente.</translation>
<translation id="1126551341858583091">O tamanho no armazenamento local é de <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cache da política OK</translation>
<translation id="1150979032973867961">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o sistema operativo do seu computador não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Certifique-se de que a ligação à Internet está a funcionar normalmente.&lt;/li&gt;
&lt;li&gt;Contacte o proprietário do Website.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Introduziu a palavra-passe num site que não é gerido pela sua organização. Para proteger a conta, não reutilize a sua palavra-passe noutras aplicações e sites.</translation>
<translation id="1263231323834454256">Lista de leitura</translation>
<translation id="1264126396475825575">Relatório de falhas capturado <ph name="CRASH_TIME" /> (ainda não carregado ou ignorado)</translation>
<translation id="1270502636509132238">Método de recolha</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Escolher</translation>
<translation id="1620510694547887537">Câmara</translation>
<translation id="1623104350909869708">Evitar que esta página crie caixas de diálogo adicionais</translation>
-<translation id="1629803312968146339">Pretende que o Chrome guarde este cartão?</translation>
<translation id="1639239467298939599">A carregar</translation>
<translation id="1640180200866533862">Políticas do utilizador</translation>
<translation id="1640244768702815859">Experimente <ph name="BEGIN_LINK" />aceder à página inicial do site<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Experimente executar o Diagnóstico de rede do Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Atualize a frase de acesso de sincronização.</translation>
<translation id="1787142507584202372">Os separadores abertos aparecem aqui</translation>
-<translation id="1789575671122666129">Pop-ups</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Nome do titular do cartão</translation>
<translation id="1806541873155184440">Adicionado a <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Reiniciar o computador</translation>
<translation id="2113977810652731515">Cartão</translation>
<translation id="2114841414352855701">Ignorada porque foi substituída por <ph name="POLICY_NAME" /> .</translation>
-<translation id="2138201775715568214">A procurar páginas da Web física próximas</translation>
<translation id="213826338245044447">Marcadores de Telemóvel</translation>
<translation id="214556005048008348">Cancelar pagamento</translation>
<translation id="2147827593068025794">Sincronização em segundo plano</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Política não encontrada</translation>
<translation id="2213606439339815911">A obter entradas...</translation>
<translation id="2218879909401188352">Os utilizadores mal-intencionados que se encontram em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem instalar aplicações perigosas que danificam o dispositivo, adicionam cobranças ocultas à fatura de dados móveis ou roubam as suas informações pessoais. <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Sem Internet</translation>
<translation id="2230458221926704099">Utilize a <ph name="BEGIN_LINK" />aplicação de diagnóstico<ph name="END_LINK" /> para corrigir a ligação</translation>
<translation id="2239100178324503013">Enviar agora</translation>
<translation id="225207911366869382">Este valor está desatualizado para esta política.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Remover itens seleccionados</translation>
<translation id="277133753123645258">Método de envio</translation>
<translation id="277499241957683684">Registo do dispositivo em falta</translation>
+<translation id="2781030394888168909">Exportar para MacOS</translation>
<translation id="2784949926578158345">A ligação foi reposta.</translation>
<translation id="2788784517760473862">Cartões de crédito admitidos</translation>
<translation id="2794233252405721443">Site bloqueado</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">O Chrome não conseguiu confirmar o seu cartão neste momento. Tente novamente mais tarde.</translation>
<translation id="3064966200440839136">Está a sair do modo de navegação anónima para pagar através de uma aplicação externa. Pretende continuar?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe}other{# palavras-passe}}</translation>
-<translation id="3093245981617870298">O utilizador está em modo offline.</translation>
<translation id="3096100844101284527">Adicionar endereço de levantamento</translation>
<translation id="3105172416063519923">ID de recurso:</translation>
<translation id="3109728660330352905">Não tem autorização para ver esta página.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> está inacessível de momento.</translation>
<translation id="3427092606871434483">Permitir (predefinição)</translation>
<translation id="3427342743765426898">&amp;Refazer edição</translation>
+<translation id="342781501876943858">O Chromium recomenda a reposição da palavra-passe se a tiver reutilizado noutros sites.</translation>
<translation id="3431636764301398940">Guardar este cartão neste dispositivo</translation>
<translation id="3447661539832366887">O proprietário deste dispositivo desativou o jogo do dinossauro.</translation>
<translation id="3447884698081792621">Mostrar certificado (emitido por <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Abrir a página numa nova janela de navegação anónima (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Relatório de falhas capturado no(a) <ph name="CRASH_TIME" /> e carregado no(a) <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informações do certificado</translation>
-<translation id="3690164694835360974">Início de sessão não seguro</translation>
<translation id="3704162925118123524">A rede que está a utilizar pode exigir que visite a respetivapágina de início de sessão.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">A carregar...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Utilizar predefinição global (Detetar)</translation>
<translation id="4165986682804962316">Definições de sites</translation>
-<translation id="4169947484918424451">Pretende que o Chromium guarde este cartão?</translation>
<translation id="4171400957073367226">Assinatura de verificação incorreta</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Mais <ph name="ITEM_COUNT" /> item}other{Mais <ph name="ITEM_COUNT" /> itens}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Reiniciar o dispositivo</translation>
<translation id="4277028893293644418">Repor palavra-passe</translation>
<translation id="4280429058323657511">, exp. <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Mudar</translation>
<translation id="4312866146174492540">Bloquear (predefinição)</translation>
<translation id="4325863107915753736">Falha ao encontrar o artigo</translation>
<translation id="4326324639298822553">Verifique a data de validade e tente novamente</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Este computador não é detetado como sendo gerido pela empresa, por isso, a política apenas pode instalar automaticamente extensões alojadas na Web Store do Chrome. O URL de atualização da Web Store do Chrome é "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Cartões de crédito aceites</translation>
<translation id="4356973930735388585">Os utilizadores mal intencionados neste site podem tentar instalar programas perigosos no seu computador que roubam ou eliminam as suas informações (por exemplo, fotos, palavras-passe, mensagens e cartões de crédito).</translation>
+<translation id="4358461427845829800">Gerir métodos de pagamento…</translation>
<translation id="4372948949327679948">Valor <ph name="VALUE_TYPE" /> esperado.</translation>
<translation id="4377125064752653719">Tentou aceder a <ph name="DOMAIN" />, mas o certificado que o servidor apresentou foi revogado pelo emissor. Isto significa que as credenciais de segurança apresentadas pelo servidor não deverão, em circunstância alguma, ser consideradas fidedignas. Pode estar a comunicar com um utilizador mal intencionado.</translation>
<translation id="4406896451731180161">resultados da pesquisa</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Endereço de recolha</translation>
<translation id="4424024547088906515">Este servidor não conseguiu provar que é o domínio <ph name="DOMAIN" />; o Chrome não confia no respetivo certificado de segurança. Isto pode ser o resultado de uma configuração incorreta ou de um invasor a intercetar a sua ligação.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> não aceitou o seu certificado de início de sessão ou este pode não ter sido fornecido.</translation>
+<translation id="4434045419905280838">Pop-ups e redirecionamentos</translation>
<translation id="443673843213245140">A utilização de um proxy está desativada, mas existe uma configuração de proxy explícita especificada.</translation>
<translation id="445100540951337728">Cartões de débito admitidos</translation>
<translation id="4506176782989081258">Erro de validação: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Preenchimento automático do pagamento desativado</translation>
<translation id="4764776831041365478">A página Web em <ph name="URL" /> poderá estar temporariamente inactiva ou poderá ter sido movida permanentemente para um novo endereço Web.</translation>
<translation id="4771973620359291008">Ocorreu um erro desconhecido.</translation>
+<translation id="4785689107224900852">Mudar para este separador</translation>
<translation id="4792143361752574037">Ocorreu um problema ao aceder aos ficheiros da sessão. A opção de guardar no disco está atualmente desativada. Recarregue a página para tentar novamente.</translation>
<translation id="4800132727771399293">Verifique a data de validade e o Código de Segurança/CVC e tente novamente</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">De momento, não pode aceder a <ph name="SITE" /> porque o Website enviou credenciais codificadas que o Google Chrome não consegue processar. Geralmente, os erros de rede e os ataques são temporários, pelo que é provável que esta página volte a funcionar mais tarde.</translation>
<translation id="4813512666221746211">Erro de rede</translation>
<translation id="4816492930507672669">Ajustar à página</translation>
-<translation id="483020001682031208">Sem páginas da Web física a apresentar</translation>
<translation id="4850886885716139402">Ver</translation>
<translation id="4854362297993841467">Este método de fornecimento não está disponível. Experimente um método diferente.</translation>
<translation id="4858792381671956233">Perguntaste aos teus pais se podes aceder a este site.</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bits)</translation>
<translation id="5121084798328133320">Depois de confirmar, os detalhes do cartão da conta do Google Payments são partilhados com este site.</translation>
<translation id="5128122789703661928">A sessão com este nome não é válida para eliminação.</translation>
+<translation id="5135404736266831032">Gerir endereços…</translation>
<translation id="5141240743006678641">Encriptar palavras-passe sincronizadas com as credenciais Google</translation>
<translation id="5145883236150621069">Código de erro presente na resposta da política</translation>
<translation id="5159010409087891077">Abrir a página numa nova janela de navegação anónima (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Uma página incorporada nesta página diz</translation>
<translation id="5205222826937269299">Nome obrigatório</translation>
<translation id="5222812217790122047">Email obrigatório</translation>
-<translation id="522700295135997067">Este site pode ter roubado a sua palavra-passe</translation>
<translation id="5230733896359313003">Endereço de envio</translation>
<translation id="5250209940322997802">"Ligar à rede"</translation>
<translation id="5251803541071282808">Nuvem</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Este site na intranet da empresa, da entidade ou da escola tem o mesmo URL que um Website externo.
<ph name="LINE_BREAK" />
Experimente contactar o gestor do sistema.</translation>
-<translation id="5499929369096410817">Introduza o código de segurança para o <ph name="CREDIT_CARD" />. Este código não é guardado.</translation>
<translation id="5509780412636533143">Marcadores geridos</translation>
<translation id="5510766032865166053">Pode ter sido movido ou eliminado.</translation>
<translation id="5523118979700054094">Nome da política</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Adicionar morada para envio</translation>
<translation id="5689199277474810259">Exportar para JSON</translation>
<translation id="5689516760719285838">Local</translation>
+<translation id="570530837424789914">Gerir…</translation>
<translation id="5710435578057952990">A identidade deste Web site não foi verificada.</translation>
<translation id="5719499550583120431">Os cartões pré-pagos são admitidos.</translation>
<translation id="5720705177508910913">Utilizador atual</translation>
+<translation id="5730040223043577876">O Chrome recomenda a reposição da palavra-passe se a tiver reutilizado noutros sites.</translation>
<translation id="5732392974455271431">Os teus pais podem desbloquear-te</translation>
<translation id="5763042198335101085">Introduza um endereço de email válido</translation>
<translation id="5765072501007116331">Para ver os métodos de fornecimento e os requisitos, selecione um endereço</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Enviar automaticamente algumas <ph name="BEGIN_WHITEPAPER_LINK" />informações do sistema e conteúdos de páginas<ph name="END_WHITEPAPER_LINK" /> para a Google de modo a ajudar a detetar aplicações e sites perigosos. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Editar informações de contacto</translation>
<translation id="5967867314010545767">Remover do histórico</translation>
-<translation id="5972020793760134803">Mudar para o separador</translation>
<translation id="5975083100439434680">Reduzir</translation>
-<translation id="597552863672748783">Confirmar o código de segurança</translation>
<translation id="598637245381783098">Não é possível abrir a aplicação de pagamento</translation>
<translation id="5989320800837274978">Não foram especificados servidores proxy fixos nem um URL de script .pac.</translation>
<translation id="5990559369517809815">Os pedidos para o servidor foram bloqueados por uma extensão.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Este conteúdo pode tentar enganá-lo de forma a que instale software ou revele informações pessoais. <ph name="BEGIN_LINK" />Mostrar mesmo assim<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Não pode visitar <ph name="SITE" /> neste momento, porque o Website utiliza a afixação de certificados. Os erros de rede e os ataques são geralmente temporários, pelo que esta página deverá funcionar mais tarde.</translation>
<translation id="6059925163896151826">Dispositivos USB</translation>
+<translation id="6071091556643036997">O tipo de política é inválido.</translation>
<translation id="6080696365213338172">Acedeu a conteúdos utilizando um certificado fornecido por um gestor. Os dados que fornecer a <ph name="DOMAIN" /> podem ser intercetados pelo seu gestor.</translation>
<translation id="610911394827799129">A sua Conta Google pode ter outras formas do histórico de navegação em <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Nenhuma}=1{1 palavra-passe (sincronizada)}other{# palavras-passe (sincronizadas)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Adicionar mais informações</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Confirmar nova submissão de formulário</translation>
+<translation id="6465306955648956876">Gerir palavras-passe…</translation>
<translation id="647261751007945333">Políticas do dispositivo</translation>
<translation id="6477321094435799029">O Chrome detetou código estranho nesta página e bloqueou-a para proteger as suas informações pessoais (por exemplo, palavras-passe, números de telefone e números de cartões de crédito).</translation>
<translation id="6489534406876378309">Começar a carregar falhas</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Pesquisar</translation>
<translation id="6630809736994426279">Os atacantes atualmente em <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> podem tentar instalar programas perigosos no seu Mac que roubam ou eliminam as suas informações (por exemplo, fotos, palavras-passe, mensagens e cartões de crédito). <ph name="BEGIN_LEARN_MORE_LINK" />Saiba mais<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Esta política está obsoleta.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nenhum}=1{De 1 site (a sessão na sua Conta Google não é terminada).}other{De # sites (a sessão na sua Conta Google não é terminada).}}</translation>
<translation id="6657585470893396449">Palavra-passe</translation>
<translation id="6671697161687535275">Pretende remover a sugestão do formulário do Chromium?</translation>
<translation id="6685834062052613830">Termine sessão e conclua a configuração</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Utilizador:</translation>
<translation id="6945221475159498467">Selecionar</translation>
<translation id="6948701128805548767">Para ver os métodos de recolha e os requisitos, selecione um endereço</translation>
+<translation id="6949872517221025916">Repor palavra-passe</translation>
<translation id="6957887021205513506">O certificado do servidor parece ser uma falsificação.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispositivo</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Método de fornecimento</translation>
<translation id="7139724024395191329">Emirado</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Pagamento não seguro</translation>
+<translation id="717330890047184534">ID Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> e mais <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Atualizar</translation>
<translation id="7182878459783632708">Não estão definidas políticas</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">Utilizar predefinição global (Bloquear)</translation>
<translation id="7460163899615895653">Os seus separadores recentes de outros dispositivos aparecem aqui</translation>
<translation id="7469372306589899959">A confirmar o cartão...</translation>
+<translation id="7473891865547856676">Não, obrigado</translation>
<translation id="7481312909269577407">Avançar</translation>
<translation id="7485870689360869515">Não foram encontrados dados.</translation>
<translation id="7508255263130623398">O ID do dispositivo da política devolvido está vazio ou não corresponde ao ID do dispositivo atual</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Pretende remover o cartão de crédito do Chrome?</translation>
<translation id="7575800019233204241">"A sua ligação não é privada" ou "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" ou "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" ou "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" ou "Erro de certificado SSL"</translation>
<translation id="7578104083680115302">Pague rapidamente em sites e aplicações em todos os dispositivos com cartões que tenha guardado com o Google.</translation>
-<translation id="7588950540487816470">Web física</translation>
<translation id="7592362899630581445">O certificado do servidor viola as restrições de nome.</translation>
<translation id="7598391785903975535">Menos de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> não consegue processar este pedido de momento.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Anular edição</translation>
<translation id="9154194610265714752">Atualizado</translation>
<translation id="9157595877708044936">A configurar...</translation>
+<translation id="9168814207360376865">Permitir que os sites verifiquem se tem métodos de pagamento guardados</translation>
<translation id="9169664750068251925">Bloquear sempre neste Website</translation>
<translation id="9170848237812810038">An&amp;ular</translation>
<translation id="917450738466192189">O certificado do servidor é inválido.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Falha ao adicionar o artigo.</translation>
<translation id="9215416866750762878">Uma aplicação está a impedir que o Chrome se ligue a este site em segurança</translation>
<translation id="9219103736887031265">Imagens</translation>
-<translation id="933612690413056017">Não existe ligação à Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">LIMPAR FORMULÁRIO</translation>
<translation id="939736085109172342">Nova pasta</translation>
diff --git a/chromium/components/strings/components_strings_ro.xtb b/chromium/components/strings/components_strings_ro.xtb
index a01108a079f..1b17bd00d1c 100644
--- a/chromium/components/strings/components_strings_ro.xtb
+++ b/chromium/components/strings/components_strings_ro.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Selectează permisiunea pentru <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Marcaje accesate recent</translation>
<translation id="1113869188872983271">&amp;Anulați reordonarea</translation>
+<translation id="1125573121925420732">Este posibil să apară frecvent avertismente pe durata actualizării setărilor de securitate ale site-urilor. Acest aspect va fi îmbunătățit în curând.</translation>
<translation id="1126551341858583091">Dimensiunea spațiului de stocare local este <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Memoria cache pentru politică este OK</translation>
<translation id="1150979032973867961">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; sistemul de operare al computerului nu consideră că certificatul său de securitate este de încredere. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;asigură-te de funcționarea normală a conexiunii la internet;&lt;/li&gt;
&lt;li&gt;contactează proprietarul site-ului.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Ai introdus parola pe un site care nu este gestionat de organizația ta. Pentru a proteja contul, nu folosi aceeași parolă pentru alte aplicații și site-uri.</translation>
<translation id="1263231323834454256">Lista de lectură</translation>
<translation id="1264126396475825575">Raport de blocare creat <ph name="CRASH_TIME" /> (nu a fost încă încărcat sau ignorat)</translation>
<translation id="1270502636509132238">Metodă de preluare</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Alegeți</translation>
<translation id="1620510694547887537">Camera</translation>
<translation id="1623104350909869708">Restricționați capacitatea acestei pagini de a crea casete de dialog suplimentare</translation>
-<translation id="1629803312968146339">Dorești ca acest card să fie salvat în Chrome?</translation>
<translation id="1639239467298939599">Se încarcă</translation>
<translation id="1640180200866533862">Politici privind utilizatorii</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />Accesează pagina de pornire a site-ului<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Rulează Diagnostice rețea Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Actualizează expresia de acces pentru sincronizare.</translation>
<translation id="1787142507584202372">Filele deschise sunt afișate aici</translation>
-<translation id="1789575671122666129">Ferestre de tip pop-up</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Numele titularului cardului</translation>
<translation id="1806541873155184440">Adăugat pe <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">repornește computerul;</translation>
<translation id="2113977810652731515">Card</translation>
<translation id="2114841414352855701">Politica este ignorată, deoarece a fost înlocuită de <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Se caută pagini din Webul material din apropiere</translation>
<translation id="213826338245044447">Marcaje mobile</translation>
<translation id="214556005048008348">Anulează plata</translation>
<translation id="2147827593068025794">Sincronizare în fundal</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Politica nu a fost găsită</translation>
<translation id="2213606439339815911">Se preiau intrările...</translation>
<translation id="2218879909401188352">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ar putea să instaleze aplicații periculoase care deteriorează dispozitivul, adaugă costuri ascunse pe factura de telefonie mobilă sau îți fură informațiile cu caracter personal. <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Fără conexiune la internet</translation>
<translation id="2230458221926704099">Remediază conexiunea folosind <ph name="BEGIN_LINK" />aplicația de diagnosticare<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Trimite acum</translation>
<translation id="225207911366869382">Valoarea este învechită pentru această politică.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Elimină elementele selectate</translation>
<translation id="277133753123645258">Metodă de expediere</translation>
<translation id="277499241957683684">Lipsește o înregistrare pentru gadget</translation>
+<translation id="2781030394888168909">Exportă în format MacOS</translation>
<translation id="2784949926578158345">Conexiunea a fost resetată.</translation>
<translation id="2788784517760473862">Carduri de credit acceptate</translation>
<translation id="2794233252405721443">Site blocat</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Momentan, Chrome nu a putut confirma cardul. Încearcă din nou mai târziu.</translation>
<translation id="3064966200440839136">Vei părăsi modul incognito pentru a plăti folosind o aplicație externă. Continui?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Niciuna}=1{1 parolă}few{# parole}other{# de parole}}</translation>
-<translation id="3093245981617870298">Ești offline.</translation>
<translation id="3096100844101284527">Adaugă o adresă de preluare</translation>
<translation id="3105172416063519923">ID articol:</translation>
<translation id="3109728660330352905">Nu ești autorizat(ă) să vezi această pagină.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Momentan, <ph name="HOST_NAME" /> nu poate fi accesat.</translation>
<translation id="3427092606871434483">Permite (în mod prestabilit)</translation>
<translation id="3427342743765426898">&amp;Repetați editarea</translation>
+<translation id="342781501876943858">Chromium îți recomandă să resetezi parola dacă ai folosit-o și pe alte site-uri.</translation>
<translation id="3431636764301398940">Salvează cardul pe acest dispozitiv</translation>
<translation id="3447661539832366887">Proprietarul acestui dispozitiv a dezactivat jocul cu dinozaurul.</translation>
<translation id="3447884698081792621">Afișează certificatul (emis de <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Deschide pagina într-o fereastră incognito nouă (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Raport de blocare creat <ph name="CRASH_TIME" /> și încărcat <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informații despre certificat</translation>
-<translation id="3690164694835360974">Conectarea nu este securizată</translation>
<translation id="3704162925118123524">Rețeaua pe care o folosești poate solicita accesarea paginii de conectare.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Se încarcă…</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Folosește global în mod prestabilit (detectează)</translation>
<translation id="4165986682804962316">Setări pentru site-uri</translation>
-<translation id="4169947484918424451">Dorești ca acest card să fie salvat în Chromium?</translation>
<translation id="4171400957073367226">Semnătură de verificare nevalidă</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Încă <ph name="ITEM_COUNT" /> articol}few{Încă <ph name="ITEM_COUNT" /> articole}other{Încă <ph name="ITEM_COUNT" /> de articole}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Reporniți gadgetul</translation>
<translation id="4277028893293644418">Resetează parola</translation>
<translation id="4280429058323657511">data expirării: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Comută</translation>
<translation id="4312866146174492540">Blochează (în mod prestabilit)</translation>
<translation id="4325863107915753736">Articolul nu a fost găsit</translation>
<translation id="4326324639298822553">Verifică data de expirare și încearcă din nou</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Acest computer nu este detectat ca fiind gestionat de companie, deci politica poate instala automat doar extensiile găzduite în Magazinul web Chrome. Adresa URL pentru actualizare din Magazinul web Chrome este „<ph name="CWS_UPDATE_URL" />”.</translation>
<translation id="4346197816712207223">Carduri de credit acceptate</translation>
<translation id="4356973930735388585">Atacatorii de pe acest site pot încerca să instaleze programe periculoase pe computerul tău, care să îți fure sau să îți șteargă informațiile (de exemplu, fotografiile, parolele, mesajele sau informațiile despre cardurile de credit).</translation>
+<translation id="4358461427845829800">Gestionează metodele de plată...</translation>
<translation id="4372948949327679948">Se aștepta valoarea <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Ați încercat să accesați <ph name="DOMAIN" />, dar certificatul furnizat de server a fost revocat de emitentul său. Aceasta înseamnă că acreditările de securitate furnizate de server nu sunt deloc de încredere. Este posibil să comunicați cu un atacator.</translation>
<translation id="4406896451731180161">rezultate ale căutării</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Adresă de preluare</translation>
<translation id="4424024547088906515">Acest server nu a putut dovedi că este <ph name="DOMAIN" />; Chrome nu consideră că certificatul său de securitate este de încredere. Cauza poate fi o configurare greșită sau interceptarea conexiunii de către un atacator.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> nu a acceptat certificatul de conectare sau un astfel de certificat nu a fost oferit.</translation>
+<translation id="4434045419905280838">Ferestre pop-up și redirecționări</translation>
<translation id="443673843213245140">Utilizarea unui proxy este dezactivată, dar o configurare proxy este specificată în mod explicit.</translation>
<translation id="445100540951337728">Carduri de debit acceptate</translation>
<translation id="4506176782989081258">Eroare de validare: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Completarea automată pentru plată este dezactivată</translation>
<translation id="4764776831041365478">Pagina web de la <ph name="URL" /> poate fi temporar nefuncțională sau a fost mutată definitiv la o nouă adresă web.</translation>
<translation id="4771973620359291008">A apărut o eroare necunoscută.</translation>
+<translation id="4785689107224900852">Comută la această filă</translation>
<translation id="4792143361752574037">A apărut o problemă la accesarea fișierelor de sesiune. Salvarea pe disc este dezactivată momentan. Reîncarcă pagina pentru a încerca din nou.</translation>
<translation id="4800132727771399293">Verifică data de expirare și codul CVC și încearcă din nou</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Nu poți accesa acum site-ul <ph name="SITE" />, deoarece acesta a trimis date de conectare într-un format necunoscut, pe care Google Chrome nu le poate procesa. Erorile de rețea și atacurile sunt de obicei temporare și probabil că această pagină va funcționa mai târziu.</translation>
<translation id="4813512666221746211">Eroare de rețea</translation>
<translation id="4816492930507672669">Încadrați în pagină</translation>
-<translation id="483020001682031208">Nu există pagini din Webul material de afișat</translation>
<translation id="4850886885716139402">Afișează</translation>
<translation id="4854362297993841467">Această metodă de livrare nu este disponibilă. Încearcă altă metodă.</translation>
<translation id="4858792381671956233">Ți-ai întrebat părinții dacă poți accesa acest site</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 de biți)</translation>
<translation id="5121084798328133320">După ce confirmi, acest site va avea acces la detaliile cardului tău din contul Google Payments.</translation>
<translation id="5128122789703661928">Sesiunea cu acest nume nu este validă pentru ștergere.</translation>
+<translation id="5135404736266831032">Gestionează adresele...</translation>
<translation id="5141240743006678641">Criptează parolele sincronizate cu datele de conectare Google</translation>
<translation id="5145883236150621069">Răspunsul pentru politică include un cod de eroare</translation>
<translation id="5159010409087891077">Deschide pagina într-o fereastră incognito nouă (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">O pagină încorporată de pe această pagină afișează mesajul</translation>
<translation id="5205222826937269299">Numele este obligatoriu</translation>
<translation id="5222812217790122047">Adresa de e-mail este obligatorie</translation>
-<translation id="522700295135997067">Este posibil ca acest site să îți fi furat chiar acum parola</translation>
<translation id="5230733896359313003">Adresă de expediere</translation>
<translation id="5250209940322997802">„Conectează-te la rețea”</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Acest site din rețeaua intranet a companiei, organizației sau școlii are aceeași adresă URL folosită de un site extern.
<ph name="LINE_BREAK" />
Contactează administratorul sistemului.</translation>
-<translation id="5499929369096410817">Introdu codul de securitate pentru <ph name="CREDIT_CARD" />. Acest cod nu va fi salvat.</translation>
<translation id="5509780412636533143">Marcaje gestionate</translation>
<translation id="5510766032865166053">Este posibil să fi fost mutat sau șters.</translation>
<translation id="5523118979700054094">Numele politicii</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Adaugă adresa de expediere</translation>
<translation id="5689199277474810259">Exportă în format JSON</translation>
<translation id="5689516760719285838">Locație</translation>
+<translation id="570530837424789914">Gestionează...</translation>
<translation id="5710435578057952990">Identitatea acestui site nu a fost confirmată.</translation>
<translation id="5719499550583120431">Se acceptă carduri preplătite.</translation>
<translation id="5720705177508910913">Utilizator curent</translation>
+<translation id="5730040223043577876">Chrome îți recomandă să resetezi parola dacă ai folosit-o și pe alte site-uri.</translation>
<translation id="5732392974455271431">Părinții tăi îl pot debloca pentru tine</translation>
<translation id="5763042198335101085">Introdu o adresă de e-mail validă</translation>
<translation id="5765072501007116331">Pentru a vedea metodele de livrare și cerințele, selectează o adresă</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Trimite automat anumite <ph name="BEGIN_WHITEPAPER_LINK" />informații despre sistem și conținutul paginii<ph name="END_WHITEPAPER_LINK" /> la Google pentru a detecta aplicațiile și site-urile periculoase. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Editează informațiile de contact</translation>
<translation id="5967867314010545767">Eliminați din istoric</translation>
-<translation id="5972020793760134803">Comută la fila</translation>
<translation id="5975083100439434680">Micșorează</translation>
-<translation id="597552863672748783">Confirmă codul de securitate</translation>
<translation id="598637245381783098">Nu se poate deschide aplicația de plată</translation>
<translation id="5989320800837274978">Nu sunt specificate nici servere proxy fixe și nici o adresă URL pentru scripturi .pac.</translation>
<translation id="5990559369517809815">Solicitările trimise la server au fost blocate de o extensie.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Acest conținut ar putea încerca să te păcălească să instalezi software sau să dezvălui informații cu caracter personal. <ph name="BEGIN_LINK" />Afișează oricum<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Nu poți accesa <ph name="SITE" /> acum, deoarece site-ul folosește fixarea certificatelor. Erorile de rețea și atacurile sunt de obicei temporare și probabil că această pagină va funcționa mai târziu.</translation>
<translation id="6059925163896151826">Dispozitive USB</translation>
+<translation id="6071091556643036997">Tipul de politică nu este valid.</translation>
<translation id="6080696365213338172">Ați accesat conținut utilizând un certificat oferit de administrator. Datele pe care le transmiteți către <ph name="DOMAIN" /> pot fi interceptate de administratorul dvs.</translation>
<translation id="610911394827799129">Contul Google poate să ofere alte forme ale istoricului de navigare la <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Niciuna}=1{1 parolă (sincronizată)}few{# parole (sincronizate)}other{# de parole (sincronizate)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Adaugă mai multe informații</translation>
<translation id="6447842834002726250">Cookie-uri</translation>
<translation id="6451458296329894277">Confirmă retrimiterea formularului</translation>
+<translation id="6465306955648956876">Gestionează parolele...</translation>
<translation id="647261751007945333">Politici privind dispozitivele</translation>
<translation id="6477321094435799029">Chrome a detectat un cod neobișnuit pe această pagină și l-a blocat pentru a-ți proteja informațiile cu caracter personal (de exemplu, parole, numere de telefon sau carduri de credit).</translation>
<translation id="6489534406876378309">Începeți încărcarea rapoartelor de blocare</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Căutare <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Atacatorii de pe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> pot încerca să instaleze programe periculoase pe computerul tău Mac, care să îți fure sau să îți șteargă informațiile (de exemplu, fotografii, parole, mesaje sau date despre cardurile de credit). <ph name="BEGIN_LEARN_MORE_LINK" />Află mai multe<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Această politică este învechită.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Niciunul}=1{De pe un site (nu te va deconecta de la Contul Google)}few{De pe # site-uri (nu te va deconecta de la Contul Google)}other{De pe # de site-uri (nu te va deconecta de la Contul Google)}}</translation>
<translation id="6657585470893396449">Parolă</translation>
<translation id="6671697161687535275">Elimini sugestia pentru formular din Chromium?</translation>
<translation id="6685834062052613830">Deconectează-te și finalizează configurarea</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Utilizator:</translation>
<translation id="6945221475159498467">Selectează</translation>
<translation id="6948701128805548767">Pentru a vedea metodele de preluare și cerințele, selectează o adresă</translation>
+<translation id="6949872517221025916">Resetează parola</translation>
<translation id="6957887021205513506">Certificatul serverului pare a fi un fals.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Dispozitiv</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Metodă de livrare</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Plata nu este securizată</translation>
+<translation id="717330890047184534">Cod Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> și încă <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Actualizați</translation>
<translation id="7182878459783632708">Nu au fost setate politici</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Utilizați setarea prestabilită la nivel global (Blocați)</translation>
<translation id="7460163899615895653">Filele recente de pe alte dispozitive sunt afișate aici</translation>
<translation id="7469372306589899959">Se confirmă cardul</translation>
+<translation id="7473891865547856676">Nu, mulțumesc</translation>
<translation id="7481312909269577407">Înainte</translation>
<translation id="7485870689360869515">Nu s-au găsit date.</translation>
<translation id="7508255263130623398">ID-ul de dispozitiv returnat pentru politică este gol sau nu corespunde cu ID-ul de dispozitiv actual</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Elimini cardul de credit din Chrome?</translation>
<translation id="7575800019233204241">„Conexiunea nu este privată”, „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;”, „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;”, „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;” sau „Eroare privind certificatul SSL”</translation>
<translation id="7578104083680115302">Plătește rapid pe site-uri și în aplicații pe diferite dispozitive folosind cardurile pe care le-ai salvat pe Google.</translation>
-<translation id="7588950540487816470">Web material</translation>
<translation id="7592362899630581445">Certificatul serverului încalcă limitările privind numele.</translation>
<translation id="7598391785903975535">Mai puțin de <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Momentan, <ph name="HOST_NAME" /> nu poate procesa această solicitare.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;Anulați editarea</translation>
<translation id="9154194610265714752">Actualizat</translation>
<translation id="9157595877708044936">Se configurează...</translation>
+<translation id="9168814207360376865">Permite site-urilor să verifice dacă ai salvat metode de plată</translation>
<translation id="9169664750068251925">Blocați întotdeauna pe acest site</translation>
<translation id="9170848237812810038">&amp;Anulează</translation>
<translation id="917450738466192189">Certificatul serverului nu este valid.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Articolul nu a fost adăugat.</translation>
<translation id="9215416866750762878">O aplicație împiedică browserul Chrome să se conecteze în siguranță la acest site</translation>
<translation id="9219103736887031265">Imagini</translation>
-<translation id="933612690413056017">Nu există conexiune la internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">GOLEȘTE FORMULARUL</translation>
<translation id="939736085109172342">Dosar nou</translation>
diff --git a/chromium/components/strings/components_strings_ru.xtb b/chromium/components/strings/components_strings_ru.xtb
index 3e9c5b38d4a..8e6426701b9 100644
--- a/chromium/components/strings/components_strings_ru.xtb
+++ b/chromium/components/strings/components_strings_ru.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" />: выберите разрешение</translation>
<translation id="1111153019813902504">Недавние закладки</translation>
<translation id="1113869188872983271">&amp;Отменить изменение порядка</translation>
+<translation id="1125573121925420732">Пока на сайтах обновляются сертификаты безопасности, предупреждения временно могут появляться чаще обычного.</translation>
<translation id="1126551341858583091">Место на карте памяти: <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">В кеше политики ошибок не найдено</translation>
<translation id="1150979032973867961">Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Операционная система компьютера не доверяет его сертификату безопасности. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Проверьте подключение к Интернету.&lt;/li&gt;
&lt;li&gt;Обратитесь к владельцу сайта.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Вы ввели пароль на сайте, которым не управляет ваша организация. Чтобы защитить свой аккаунт, не используйте этот пароль для других приложений и сайтов.</translation>
<translation id="1263231323834454256">Список для чтения</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" />: получен отчет о сбое (ещё не загружен или не отклонен)</translation>
<translation id="1270502636509132238">Способ получения</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Выбрать</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1623104350909869708">Запретить создание дополнительных диалоговых окон на этой странице</translation>
-<translation id="1629803312968146339">Сохранить эту карту в Chrome?</translation>
<translation id="1639239467298939599">Загрузка</translation>
<translation id="1640180200866533862">Пользовательские правила</translation>
<translation id="1640244768702815859">Попробуйте <ph name="BEGIN_LINK" />открыть главную страницу сайта<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Выполните диагностику сети в Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Обновите кодовую фразу для синхронизации.</translation>
<translation id="1787142507584202372">Здесь появятся открытые вкладки.</translation>
-<translation id="1789575671122666129">Всплывающие окна</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Владелец карты</translation>
<translation id="1806541873155184440">Добавлена <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Перезагрузите компьютер.</translation>
<translation id="2113977810652731515">Карта</translation>
<translation id="2114841414352855701">Игнорируется, так как правило <ph name="POLICY_NAME" /> имеет приоритет.</translation>
-<translation id="2138201775715568214">Поиск веб-страниц…</translation>
<translation id="213826338245044447">Закладки на мобильном</translation>
<translation id="214556005048008348">Отменить оплату</translation>
<translation id="2147827593068025794">Фоновая синхронизация</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Политика для устройства не найдена</translation>
<translation id="2213606439339815911">Извлечение записей…</translation>
<translation id="2218879909401188352">Злоумышленники могут использовать сайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, чтобы установить опасные приложения, которые причиняют вред устройствам, увеличивают расходы на мобильную связь и крадут личные данные. <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Нет подключения к Интернету</translation>
<translation id="2230458221926704099">Чтобы устранить неполадки, проведите <ph name="BEGIN_LINK" />диагностику<ph name="END_LINK" /> подключения.</translation>
<translation id="2239100178324503013">Отправить</translation>
<translation id="225207911366869382">Это значение для данного правила больше не используется.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Удалить выбранные элементы</translation>
<translation id="277133753123645258">Способ доставки</translation>
<translation id="277499241957683684">Устройство не зарегистрировано</translation>
+<translation id="2781030394888168909">Экспортировать для macOS</translation>
<translation id="2784949926578158345">Соединение сброшено.</translation>
<translation id="2788784517760473862">Кредитные карты, которые принимаются к оплате</translation>
<translation id="2794233252405721443">Сайт заблокирован</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Не удалось подтвердить данные карты. Повторите попытку позже.</translation>
<translation id="3064966200440839136">Вы выйдете из режима инкогнито, чтобы произвести оплату во внешнем приложении. Продолжить?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Нет}=1{1 пароль}one{# пароль}few{# пароля}many{# паролей}other{# пароля}}</translation>
-<translation id="3093245981617870298">Нет подключения к сети</translation>
<translation id="3096100844101284527">Добавить адрес получения</translation>
<translation id="3105172416063519923">Идентификатор объекта:</translation>
<translation id="3109728660330352905">У вас нет прав для просмотра этой страницы.</translation>
@@ -361,6 +361,7 @@
<translation id="3422472998109090673">Сайт <ph name="HOST_NAME" /> недоступен.</translation>
<translation id="3427092606871434483">Разрешать (по умолчанию)</translation>
<translation id="3427342743765426898">&amp;Повторить изменения</translation>
+<translation id="342781501876943858">Chromium рекомендует сбросить пароль, если вы использовали его на других сайтах.</translation>
<translation id="3431636764301398940">Сохранить карту на этом устройстве</translation>
<translation id="3447661539832366887">Владелец этого устройства отключил игру с динозавром.</translation>
<translation id="3447884698081792621">Показать сертификат (издатель: <ph name="ISSUER" />)</translation>
@@ -397,7 +398,6 @@
<translation id="3678529606614285348">Открыть страницу в новом окне в режиме инкогнито (Ctrl + Shift + N)</translation>
<translation id="3679803492151881375"><ph name="CRASH_TIME" />: отчет о сбоях сохранен. <ph name="UPLOAD_TIME" />: отчет о сбоях загружен.</translation>
<translation id="3681007416295224113">Данные сертификата</translation>
-<translation id="3690164694835360974">Незащищенный вход</translation>
<translation id="3704162925118123524">Возможно, вам нужно перейти на страницу входа используемой сети.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Загрузка...</translation>
@@ -457,14 +457,13 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Использовать глобальный параметр по умолчанию (находить)</translation>
<translation id="4165986682804962316">Настройки сайтов</translation>
-<translation id="4169947484918424451">Сохранить эту карту в Chromium?</translation>
<translation id="4171400957073367226">Подтверждающая подпись недействительна</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Ещё <ph name="ITEM_COUNT" /> товар}one{Ещё <ph name="ITEM_COUNT" /> товар}few{Ещё <ph name="ITEM_COUNT" /> товара}many{Ещё <ph name="ITEM_COUNT" /> товаров}other{Ещё <ph name="ITEM_COUNT" /> товара}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" />: <ph name="ROW_CONTENT" /></translation>
<translation id="4192549185358213268">Рекомендуем сбросить пароль в домене <ph name="ORG_NAME" />, если вы используете его на других сайтах.</translation>
<translation id="4196861286325780578">&amp;Повторить перемещение</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />Проверьте настройки брандмауэра и антивирусного ПО<ph name="END_LINK" />.</translation>
-<translation id="4220128509585149162">Завершение работы программы</translation>
+<translation id="4220128509585149162">Сбои в работе Chrome</translation>
<translation id="422022731706691852">Посещение сайта <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> может привести к установке вредоносного ПО, которое будет мешать вашей работе в браузере (например, менять стартовую страницу или показывать дополнительную рекламу на сайтах). <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4221630205957821124">&lt;h4&gt;Шаг 1. Войдите на портал&lt;/h4&gt;
&lt;p&gt;Чтобы воспользоваться общедоступной сетью Wi-Fi (например, в кафе или аэропорту), сначала подключитесь к ней, открыв любую веб-страницу с префиксом &lt;code&gt;http://&lt;/code&gt;.&lt;/p&gt;
@@ -494,6 +493,7 @@
<translation id="4275830172053184480">Перезапуск устройства</translation>
<translation id="4277028893293644418">Сбросить пароль</translation>
<translation id="4280429058323657511">, действует до <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Переключиться</translation>
<translation id="4312866146174492540">Блокировать (по умолчанию)</translation>
<translation id="4325863107915753736">Не удалось найти статью</translation>
<translation id="4326324639298822553">Проверьте срок действия и повторите попытку</translation>
@@ -501,6 +501,7 @@
<translation id="4340982228985273705">По нашим данным, этот компьютер не является корпоративным, поэтому в соответствии с правилом на него можно автоматически устанавливать только расширения из Интернет-магазина Chrome. URL для обновления: <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Кредитные карты, которые принимаются к оплате</translation>
<translation id="4356973930735388585">Злоумышленники могут использовать этот сайт, чтобы установить на ваш компьютер вредоносное ПО, которое крадет или удаляет личную информацию (например, фотографии, пароли, сообщения и реквизиты банковских карт).</translation>
+<translation id="4358461427845829800">Управление способами оплаты…</translation>
<translation id="4372948949327679948">Ожидаемое значение: <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Вы попытались перейти на сайт <ph name="DOMAIN" />, однако сертификат, предоставленный сервером, был отозван издателем. Это означает, что учетные данные безопасности, предоставленные сервером, не заслуживают доверия. Возможно, вы имеете дело со злоумышленниками.</translation>
<translation id="4406896451731180161">Результаты поиска</translation>
@@ -508,6 +509,7 @@
<translation id="4415426530740016218">Адрес получения</translation>
<translation id="4424024547088906515">Не удалось подтвердить, что это сервер <ph name="DOMAIN" />. Chrome не доверяет его сертификату безопасности. Возможно, сервер настроен неправильно или кто-то пытается перехватить ваши данные.</translation>
<translation id="4432688616882109544">Ваш сертификат отклонен сайтом <ph name="HOST_NAME" /> или не был выдан.</translation>
+<translation id="4434045419905280838">Всплывающие окна и переадресация</translation>
<translation id="443673843213245140">Прокси-сервер отключен, но при этом его конфигурация задана явным образом.</translation>
<translation id="445100540951337728">Дебетовые карты, которые принимаются к оплате</translation>
<translation id="4506176782989081258">Ошибка проверки: <ph name="VALIDATION_ERROR" /></translation>
@@ -542,13 +544,13 @@
<translation id="4759118997339041434">Автозаполнение данных для оплаты отключено</translation>
<translation id="4764776831041365478">Веб-страница по адресу <ph name="URL" />, возможно, временно недоступна или постоянно перемещена по новому адресу.</translation>
<translation id="4771973620359291008">Произошла неизвестная ошибка.</translation>
+<translation id="4785689107224900852">Переключиться на эту вкладку</translation>
<translation id="4792143361752574037">Не удалось получить доступ к файлам сеанса. Сохранение на диск пока недоступно. Обновите страницу и повторите попытку.</translation>
<translation id="4800132727771399293">Проверьте срок действия и CVC-код, а затем повторите попытку</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Перейти на сайт <ph name="SITE" /> невозможно, так как его идентификационные данные зашифрованы, и Google Chrome не может их обработать. Это могло произойти из-за ошибки сети или атаки на сайт. Скорее всего, он заработает через некоторое время.</translation>
<translation id="4813512666221746211">Ошибка сети</translation>
<translation id="4816492930507672669">По размеру страницы</translation>
-<translation id="483020001682031208">Нет веб-страниц для показа</translation>
<translation id="4850886885716139402">Посмотреть</translation>
<translation id="4854362297993841467">Этот способ доставки недоступен. Выберите другой.</translation>
<translation id="4858792381671956233">Запрос на просмотр сайта отправлен вашим родителям</translation>
@@ -588,6 +590,7 @@
<translation id="5115563688576182185">(64 бит)</translation>
<translation id="5121084798328133320">После подтверждения реквизиты карты из платежного аккаунта Google будут переданы этому сайту.</translation>
<translation id="5128122789703661928">Невозможно удалить сеанс с таким названием.</translation>
+<translation id="5135404736266831032">Управление адресами…</translation>
<translation id="5141240743006678641">Шифровать синхронизированные пароли с помощью учетных данных Google</translation>
<translation id="5145883236150621069">При проверке политики возвращен код ошибки</translation>
<translation id="5159010409087891077">Открыть страницу в новом окне в режиме инкогнито (⇧ + ⌘ + N)</translation>
@@ -599,7 +602,6 @@
<translation id="5201306358585911203">Подтвердите действие</translation>
<translation id="5205222826937269299">Введите имя или название</translation>
<translation id="5222812217790122047">Введите адрес электронной почты</translation>
-<translation id="522700295135997067">Через этот сайт могли похитить ваш пароль</translation>
<translation id="5230733896359313003">Адрес доставки</translation>
<translation id="5250209940322997802">"Подключитесь к сети"</translation>
<translation id="5251803541071282808">Облако</translation>
@@ -643,7 +645,6 @@
<translation id="5492298309214877701">Этот сайт в интранете организации или учебного заведения имеет тот же URL, что и сайт в Интернете.
<ph name="LINE_BREAK" />
Обратитесь к системному администратору.</translation>
-<translation id="5499929369096410817">Введите защитный код для карты <ph name="CREDIT_CARD" />. Он не будет сохранен.</translation>
<translation id="5509780412636533143">Управляемые закладки</translation>
<translation id="5510766032865166053">Возможно, он был перемещен или удален.</translation>
<translation id="5523118979700054094">Название правила</translation>
@@ -674,9 +675,11 @@
<translation id="5685654322157854305">Добавить адрес доставки посылок</translation>
<translation id="5689199277474810259">Экспортировать как JSON</translation>
<translation id="5689516760719285838">Геоданные</translation>
+<translation id="570530837424789914">Управление…</translation>
<translation id="5710435578057952990">Идентификационные данные этого сайта не проверены.</translation>
<translation id="5719499550583120431">Принимаются карты предоплаты.</translation>
<translation id="5720705177508910913">Текущий пользователь</translation>
+<translation id="5730040223043577876">Chrome рекомендует сбросить пароль, если вы использовали его на других сайтах.</translation>
<translation id="5732392974455271431">Для разблокировки обратитесь к родителям.</translation>
<translation id="5763042198335101085">Укажите действительный адрес электронной почты.</translation>
<translation id="5765072501007116331">Выберите адрес, чтобы посмотреть способы и условия доставки.</translation>
@@ -700,9 +703,7 @@
<translation id="5959728338436674663">Автоматически отправлять <ph name="BEGIN_WHITEPAPER_LINK" />системную информацию и контент страниц<ph name="END_WHITEPAPER_LINK" /> в Google, чтобы улучшить распознавание опасных приложений и сайтов. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Измените контактную информацию</translation>
<translation id="5967867314010545767">Удалить из истории</translation>
-<translation id="5972020793760134803">Переключиться на вкладку</translation>
<translation id="5975083100439434680">Уменьшить</translation>
-<translation id="597552863672748783">Подтвердите защитный код</translation>
<translation id="598637245381783098">Не удалось открыть Payments</translation>
<translation id="5989320800837274978">Ни фиксированные прокси-серверы, ни URL PAC-скриптов не указаны.</translation>
<translation id="5990559369517809815">Расширение заблокировало отправку запроса на сервер.</translation>
@@ -718,6 +719,7 @@
<translation id="6047927260846328439">Посещение этой страницы может привести к установке вредоносной программы или хищению вашей личной информации. <ph name="BEGIN_LINK" />Все равно продолжить<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Веб-сайт <ph name="SITE" /> использует механизм Certificate Pinning, поэтому на нем могла произойти подмена сертификата. Открыть сайт в настоящее время нельзя. Сбой мог быть вызван сетевой ошибкой или действиями злоумышленников. Скорее всего, сайт заработает через некоторое время.</translation>
<translation id="6059925163896151826">USB-устройства</translation>
+<translation id="6071091556643036997">Указан неверный тип правил.</translation>
<translation id="6080696365213338172">Вы используете сертификат, предоставленный администратором, поэтому он может заблокировать передачу данных на сайт <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">Информация о других ваших действиях в Интернете может также храниться на странице <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Нет}=1{1 синхронизированный пароль}one{# синхронизированный пароль}few{# синхронизированных пароля}many{# синхронизированных паролей}other{# синхронизированного пароля}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">Укажите дополнительную информацию</translation>
<translation id="6447842834002726250">Файлы сookie</translation>
<translation id="6451458296329894277">Подтвердите повторную отправку формы</translation>
+<translation id="6465306955648956876">Управление паролями…</translation>
<translation id="647261751007945333">Правила устройства</translation>
<translation id="6477321094435799029">Браузер Chrome обнаружил на этой странице необычный код и заблокировал его, чтобы защитить ваши данные (например, пароли, а также номера телефонов и банковских карт).</translation>
<translation id="6489534406876378309">Начать загрузку сведений об ошибках</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685">Поиск <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Сайт <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> может установить на ваш компьютер Mac вредоносное ПО, которое крадет или удаляет личную информацию (например, фотографии, пароли, сообщения и реквизиты банковских карт). <ph name="BEGIN_LEARN_MORE_LINK" />Подробнее…<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Правило устарело.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Нет}=1{С 1 сайта (вы останетесь в аккаунте Google)}one{С # сайта (вы останетесь в аккаунте Google)}few{С # сайтов (вы останетесь в аккаунте Google)}many{С # сайтов (вы останетесь в аккаунте Google)}other{С # сайта (вы останетесь в аккаунте Google)}}</translation>
<translation id="6657585470893396449">Пароль</translation>
<translation id="6671697161687535275">Удалить подсказку из Chromium?</translation>
<translation id="6685834062052613830">Выйдите из аккаунта и завершите настройку</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">Пользователь:</translation>
<translation id="6945221475159498467">Выбрать</translation>
<translation id="6948701128805548767">Выберите адрес, чтобы посмотреть способы и условия получения.</translation>
+<translation id="6949872517221025916">Сброс пароля</translation>
<translation id="6957887021205513506">Возможно, сертификат сервера фальсифицирован.</translation>
<translation id="6965382102122355670">ОК</translation>
<translation id="6965978654500191972">Устройство</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">Способ доставки</translation>
<translation id="7139724024395191329">Эмират</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> способ оплаты}one{<ph name="PAYMENT_METHOD_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> способ оплаты}few{<ph name="PAYMENT_METHOD_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> способа оплаты}many{<ph name="PAYMENT_METHOD_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> способов оплаты}other{<ph name="PAYMENT_METHOD_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> способа оплаты}}</translation>
-<translation id="7155487117670177674">Незащищенная оплата</translation>
+<translation id="717330890047184534">Идентификатор GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> вариант доставки}one{<ph name="SHIPPING_OPTION_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> вариант доставки}few{<ph name="SHIPPING_OPTION_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> варианта доставки}many{<ph name="SHIPPING_OPTION_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> вариантов доставки}other{<ph name="SHIPPING_OPTION_PREVIEW" /> и ещё <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> варианта доставки}}</translation>
<translation id="7180611975245234373">Обновить</translation>
<translation id="7182878459783632708">Правила не заданы</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">Использовать глобальный параметр по умолчанию (блокировать)</translation>
<translation id="7460163899615895653">Здесь появятся недавние вкладки с других устройств</translation>
<translation id="7469372306589899959">Подтверждение карты…</translation>
+<translation id="7473891865547856676">Пропустить</translation>
<translation id="7481312909269577407">Вперед</translation>
<translation id="7485870689360869515">Данные не найдены.</translation>
<translation id="7508255263130623398">Возвращенный идентификатор устройства пуст или не соответствует имеющемуся</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Удалить кредитную карту из Chrome?</translation>
<translation id="7575800019233204241">"Подключение не защищено", &lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;, &lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;, &lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt; или "Ошибка сертификата SSL"</translation>
<translation id="7578104083680115302">Быстро оплачивайте покупки на сайтах и в приложениях с помощью карт, сохраненных в Google Payments. Настройка будет действовать на всех ваших устройствах.</translation>
-<translation id="7588950540487816470">Интернет вокруг нас</translation>
<translation id="7592362899630581445">Сертификат сервера не соответствует ограничениям в отношении имен.</translation>
<translation id="7598391785903975535">Менее <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Сайт <ph name="HOST_NAME" /> пока не может обработать этот запрос.</translation>
@@ -1105,6 +1110,7 @@
<translation id="9148507642005240123">&amp;Отменить изменения</translation>
<translation id="9154194610265714752">Обновлено</translation>
<translation id="9157595877708044936">Настройка...</translation>
+<translation id="9168814207360376865">Разрешить сайтам проверять наличие сохраненных способов оплаты</translation>
<translation id="9169664750068251925">Всегда блокировать на этом сайте</translation>
<translation id="9170848237812810038">&amp;Отменить</translation>
<translation id="917450738466192189">Сертификат сервера недействителен</translation>
@@ -1113,7 +1119,6 @@
<translation id="9207861905230894330">Не удалось добавить статью</translation>
<translation id="9215416866750762878">Приложение не позволяет Chrome безопасно подключиться к этому сайту</translation>
<translation id="9219103736887031265">Картинки</translation>
-<translation id="933612690413056017">Нет подключения к Интернету</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ОЧИСТИТЬ ФОРМУ</translation>
<translation id="939736085109172342">Новая папка</translation>
diff --git a/chromium/components/strings/components_strings_sk.xtb b/chromium/components/strings/components_strings_sk.xtb
index 3f342594fb2..a8019e2c0bc 100644
--- a/chromium/components/strings/components_strings_sk.xtb
+++ b/chromium/components/strings/components_strings_sk.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Vyberte povolenie pre <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Najnovšie záložky</translation>
<translation id="1113869188872983271">&amp;Vrátiť späť zmenu poradia</translation>
+<translation id="1125573121925420732">Kým weby aktualizujú svoje zabezpečenie, môžu sa často zobrazovať upozornenia. Čoskoro by sa to malo zlepšiť.</translation>
<translation id="1126551341858583091">Veľkosť súboru v lokálnom úložisku je <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Vyrovnávacia pamäť pravidla je v poriadku</translation>
<translation id="1150979032973867961">Server nedokáže overiť, či ide o doménu <ph name="DOMAIN" />, operačný systém vášho počítača nedôveruje jej bezpečnostnému certifikátu. Môže to byť spôsobené nesprávnou konfiguráciou alebo tým, že vaše pripojenie zachytil útočník.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Skontrolujte, či internetové pripojenie funguje normálne.&lt;/li&gt;
&lt;li&gt;Kontaktujte vlastníka príslušného webu.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Zadali ste heslo na webe, ktorý nie je spravovaný vašou organizáciou. Ak chcete, aby bol váš účet chránený, nepoužívajte dané heslo pre iné aplikácie a weby.</translation>
<translation id="1263231323834454256">Čitateľský zoznam</translation>
<translation id="1264126396475825575">Správa o zlyhaní bola zaznamenaná v čase <ph name="CRASH_TIME" /> (ešte nebola nahraná ani ignorovaná)</translation>
<translation id="1270502636509132238">Spôsob vyzdvihnutia</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Zvoliť</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Zakázať tejto stránke otvárať ďalšie dialógové okná</translation>
-<translation id="1629803312968146339">Chcete, aby Chrome uložil túto kartu?</translation>
<translation id="1639239467298939599">Prebieha načítavanie</translation>
<translation id="1640180200866533862">Pravidlá pre používateľa</translation>
<translation id="1640244768702815859">Skúste <ph name="BEGIN_LINK" />navštíviť domovskú stránku webu<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Skúste spustiť nástroj Diagnostika siete systému Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Aktualizujte prístupovú frázu na synchronizáciu.</translation>
<translation id="1787142507584202372">Tu sa zobrazia otvorené karty</translation>
-<translation id="1789575671122666129">Kontextové okná</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Meno majiteľa karty</translation>
<translation id="1806541873155184440">Pridané <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Reštartujte počítač</translation>
<translation id="2113977810652731515">Karta</translation>
<translation id="2114841414352855701">Ignorované, pretože bolo prepísané pravidlom <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Vyhľadávajú sa stránky Fyzického webu v okolí</translation>
<translation id="213826338245044447">Záložky v mobile</translation>
<translation id="214556005048008348">Zrušiť platbu</translation>
<translation id="2147827593068025794">Synchronizácia na pozadí</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Pravidlo sa nenašlo</translation>
<translation id="2213606439339815911">Načítavanie záznamov...</translation>
<translation id="2218879909401188352">Útočníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> by mohli nainštalovať nebezpečné aplikácie, ktoré poškodia vaše zariadenia, pridať skryté poplatky do vašej faktúry za mobilné služby alebo ukradnúť vaše osobné informácie. <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Bez internetu</translation>
<translation id="2230458221926704099">Opravte svoje pripojenie pomocou <ph name="BEGIN_LINK" />diagnostickej aplikácie<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Odoslať</translation>
<translation id="225207911366869382">Táto hodnota už pre toto pravidlo nie je podporovaná.</translation>
@@ -244,7 +244,7 @@
<translation id="2653659639078652383">Odoslať</translation>
<translation id="2666117266261740852">Zavrite ostatné karty alebo aplikácie</translation>
<translation id="2674170444375937751">Naozaj chcete odstrániť tieto stránky zo svojej histórie?</translation>
-<translation id="2677748264148917807">Opustiť</translation>
+<translation id="2677748264148917807">Odísť</translation>
<translation id="2699302886720511147">Akceptované karty</translation>
<translation id="2702801445560668637">Čitateľský zoznam</translation>
<translation id="2704283930420550640">Hodnota nezodpovedá formátu.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Odstrániť vybraté položky</translation>
<translation id="277133753123645258">Spôsob dodania</translation>
<translation id="277499241957683684">Chýbajúci záznam zariadenia</translation>
+<translation id="2781030394888168909">Exportovať pre MacOS</translation>
<translation id="2784949926578158345">Spojenie bolo resetované.</translation>
<translation id="2788784517760473862">Akceptované kreditné karty</translation>
<translation id="2794233252405721443">Web je blokovaný</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chromu sa nepodarilo overiť vašu kartu. Skúste to znova neskôr.</translation>
<translation id="3064966200440839136">Ak zaplatíte pomocou externej aplikácie, opustíte režim inkognito. Chcete pokračovať?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Žiadne}=1{1 heslo}few{# heslá}many{# hesla}other{# hesiel}}</translation>
-<translation id="3093245981617870298">Ste v režime offline.</translation>
<translation id="3096100844101284527">Pridať adresu vyzdvihnutia</translation>
<translation id="3105172416063519923">Identifikátor obsahu:</translation>
<translation id="3109728660330352905">Nemáte povolenie na zobrazenie tejto stránky.</translation>
@@ -359,6 +359,7 @@
<translation id="3422472998109090673">Web <ph name="HOST_NAME" /> nie je momentálne k dispozícii.</translation>
<translation id="3427092606871434483">Povoliť (predvolené)</translation>
<translation id="3427342743765426898">&amp;Znova upraviť</translation>
+<translation id="342781501876943858">Ak ste heslo použili aj na iných weboch, Chromium ho odporúča obnoviť.</translation>
<translation id="3431636764301398940">Uložiť túto kartu na zariadení</translation>
<translation id="3447661539832366887">Vlastník tohto zariadenia vypol hru Dinosaur.</translation>
<translation id="3447884698081792621">Zobraziť certifikát (od vydavateľa <ph name="ISSUER" />)</translation>
@@ -394,7 +395,6 @@
<translation id="3678529606614285348">Otvorte stránku v novom okne inkognito (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Správa o zlyhaní zaznamenaná v čase <ph name="CRASH_TIME" /> bola nahraná o <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informácie o certifikáte</translation>
-<translation id="3690164694835360974">Prihlásenie nie je zabezpečené</translation>
<translation id="3704162925118123524">Sieť, ktorú používate, môže vyžadovať, aby ste navštívili jej prihlasovaciu stránku.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Načítava sa...</translation>
@@ -454,7 +454,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Použiť globálne predvolené nastavenie (zistiť)</translation>
<translation id="4165986682804962316">Nastavenia webu</translation>
-<translation id="4169947484918424451">Chcete, aby Chromium uložil túto kartu?</translation>
<translation id="4171400957073367226">Nesprávny overovací podpis</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> ďalšia položka}few{<ph name="ITEM_COUNT" /> ďalšie položky}many{<ph name="ITEM_COUNT" /> ďalšej položky}other{<ph name="ITEM_COUNT" /> ďalších položiek}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -491,6 +490,7 @@
<translation id="4275830172053184480">Reštart zariadenia</translation>
<translation id="4277028893293644418">Obnoviť heslo</translation>
<translation id="4280429058323657511">, dátum vypršania platnosti: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Prepnúť</translation>
<translation id="4312866146174492540">Blokovať (predvolené)</translation>
<translation id="4325863107915753736">Článok sa nepodarilo nájsť</translation>
<translation id="4326324639298822553">Skontrolujte dátum vypršania platnosti a skúste to znova</translation>
@@ -498,6 +498,7 @@
<translation id="4340982228985273705">Tento počítač nebol rozpoznaný ako spravovaný podnikom, takže pravidlá môžu automaticky inštalovať iba rozšírenia hostené v Internetovom obchode Chrome. Webová adresa aktualizácie z Internetového obchodu Chrome je <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Akceptované kreditné karty</translation>
<translation id="4356973930735388585">Útočníci na tomto webe sa možno pokúsia nainštalovať na váš počítač nebezpečné programy, ktoré ukradnú alebo odstránia vaše informácie, napríklad fotky, heslá, správy alebo kreditné karty.</translation>
+<translation id="4358461427845829800">Spravovať spôsoby platby…</translation>
<translation id="4372948949327679948">Očakávaná hodnota <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Pokúsili ste sa o prístup na stránky <ph name="DOMAIN" />, avšak certifikát poskytnutý serverom bol vydavateľom zrušený. Znamená to, že povereniam zabezpečenia, ktoré predložil server, sa celkom nedá dôverovať. Je možné, že komunikujete s útočníkom.</translation>
<translation id="4406896451731180161">výsledky vyhľadávania</translation>
@@ -505,6 +506,7 @@
<translation id="4415426530740016218">Adresa vyzdvihnutia</translation>
<translation id="4424024547088906515">Server nedokáže overiť, či ide o doménu <ph name="DOMAIN" />, Chrome nedôveruje jej bezpečnostnému certifikátu. Môže to byť spôsobené nesprávnou konfiguráciou alebo tým, že vaše pripojenie zachytil útočník.</translation>
<translation id="4432688616882109544">Web <ph name="HOST_NAME" /> neakceptoval váš prihlasovací certifikát alebo nebol žiadny poskytnutý.</translation>
+<translation id="4434045419905280838">Kontextové okná a presmerovania</translation>
<translation id="443673843213245140">Použitie servera proxy je zakázané, ale je určená explicitná konfigurácia servera proxy.</translation>
<translation id="445100540951337728">Akceptované debetné karty</translation>
<translation id="4506176782989081258">Chyba overenia: <ph name="VALIDATION_ERROR" /></translation>
@@ -539,13 +541,13 @@
<translation id="4759118997339041434">Automatické dopĺňanie platobných údajov je zakázané</translation>
<translation id="4764776831041365478">Webové stránky na adrese <ph name="URL" /> môžu byť dočasne nedostupné alebo sa mohli natrvalo premiestniť na novú webovú adresu.</translation>
<translation id="4771973620359291008">Vyskytla sa neznáma chyba.</translation>
+<translation id="4785689107224900852">Prepnite na túto kartu</translation>
<translation id="4792143361752574037">Pri pokuse o prístup k súborom relácie sa vyskytol problém. Ukladanie na disk je momentálne zakázané. Opakujte načítanie stránky a skúste to znova.</translation>
<translation id="4800132727771399293">Skontrolujte dátum vypršania platnosti aj kód CVC a skúste to znova</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Web <ph name="SITE" /> momentálne nemôžete navštíviť, pretože vrátil zakódované poverenia, ktoré Google Chrome nedokáže spracovať. Chyby siete a útoky sú zvyčajne dočasné, takže by táto stránka mala neskôr pravdepodobne fungovať.</translation>
<translation id="4813512666221746211">Chyba siete</translation>
<translation id="4816492930507672669">Prispôsobiť stránke</translation>
-<translation id="483020001682031208">K dispozícii nie sú žiadne stránky Fyzického webu</translation>
<translation id="4850886885716139402">Zobraziť</translation>
<translation id="4854362297993841467">Tento spôsob doručenia nie je k dispozícii. Skúste inú adresu.</translation>
<translation id="4858792381671956233">Požiadali ste rodičov o povolenie návštevy tohto webu.</translation>
@@ -558,7 +560,7 @@
<translation id="4923417429809017348">Táto stránka bola preložená z neznámeho jazyka do jazyka <ph name="LANGUAGE_LANGUAGE" /></translation>
<translation id="4923459931733593730">Platba</translation>
<translation id="4926049483395192435">Musí byť určená.</translation>
-<translation id="4926159001844873046">Web <ph name="SITE" /> hovorí</translation>
+<translation id="4926159001844873046">Správa z webu <ph name="SITE" /></translation>
<translation id="4926340098269537727"><ph name="ACTIVE_MATCH" />/<ph name="TOTAL_MATCHCOUNT" /></translation>
<translation id="495170559598752135">Akcie</translation>
<translation id="4958444002117714549">Rozbaliť zoznam</translation>
@@ -585,6 +587,7 @@
<translation id="5115563688576182185">(64-bitová verzia)</translation>
<translation id="5121084798328133320">Po potvrdení sa budú podrobnosti z účtu Google Payments zdieľať s týmto webom.</translation>
<translation id="5128122789703661928">Relácia s týmto názvom je neplatná a nedá sa odstrániť.</translation>
+<translation id="5135404736266831032">Spravovať adresy…</translation>
<translation id="5141240743006678641">Šifrovať synchronizované heslá pomocou poverení Google</translation>
<translation id="5145883236150621069">V odpovedi na pravidlo sa nachádza kód chyby</translation>
<translation id="5159010409087891077">Otvorte stránku v novom okne inkognito (⇧⌘N)</translation>
@@ -596,7 +599,6 @@
<translation id="5201306358585911203">Vložená stránka na tejto stránke hovorí</translation>
<translation id="5205222826937269299">Meno je povinný údaj</translation>
<translation id="5222812217790122047">E-mailová adresa je povinný údaj</translation>
-<translation id="522700295135997067">Tento web možno práve ukradol vaše heslo</translation>
<translation id="5230733896359313003">Dodacia adresa</translation>
<translation id="5250209940322997802">„Pripojte sa k sieti“</translation>
<translation id="5251803541071282808">Cloud</translation>
@@ -640,7 +642,6 @@
<translation id="5492298309214877701">Tento web v intranete danej spoločnosti, organizácie či školy má rovnakú webovú adresu ako externý web.
<ph name="LINE_BREAK" />
Skúste kontaktovať správcu systému.</translation>
-<translation id="5499929369096410817">Zadajte bezpečnostný kód karty <ph name="CREDIT_CARD" />. Tento kód sa neuloží.</translation>
<translation id="5509780412636533143">Spravované záložky</translation>
<translation id="5510766032865166053">Mohol byť prenesený alebo odstránený.</translation>
<translation id="5523118979700054094">Názov pravidla</translation>
@@ -671,9 +672,11 @@
<translation id="5685654322157854305">Pridať dodaciu adresu</translation>
<translation id="5689199277474810259">Exportovať vo formáte JSON</translation>
<translation id="5689516760719285838">Poloha</translation>
+<translation id="570530837424789914">Spravovať...</translation>
<translation id="5710435578057952990">Identita tejto webovej stránky nebola overená.</translation>
<translation id="5719499550583120431">Predplatené karty sú akceptované.</translation>
<translation id="5720705177508910913">Aktuálny používateľ</translation>
+<translation id="5730040223043577876">Ak ste heslo použili aj na iných weboch, Chrome ho odporúča obnoviť.</translation>
<translation id="5732392974455271431">Vaši rodičia ho môžu pre vás odblokovať</translation>
<translation id="5763042198335101085">Zadajte platnú e-mailovú adresu</translation>
<translation id="5765072501007116331">Ak chcete zobraziť spôsoby a požiadavky doručenia, vyberte adresu</translation>
@@ -697,9 +700,7 @@
<translation id="5959728338436674663">Automaticky odosielať <ph name="BEGIN_WHITEPAPER_LINK" />niektoré informácie o systéme a obsah stránok<ph name="END_WHITEPAPER_LINK" /> do Googlu s cieľom pomôcť rozpoznávať nebezpečné aplikácie a weby. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Úprava kontaktných informácií</translation>
<translation id="5967867314010545767">Odstrániť z histórie</translation>
-<translation id="5972020793760134803">Prepnúť na kartu</translation>
<translation id="5975083100439434680">Oddialiť</translation>
-<translation id="597552863672748783">Potvrdenie bezpečnostného kódu</translation>
<translation id="598637245381783098">Nie je možné otvoriť platobnú aplikáciu</translation>
<translation id="5989320800837274978">Nie sú určené pevne dané servery proxy ani skript PAC webovej adresy.</translation>
<translation id="5990559369517809815">Žiadosti odoslané serveru boli zablokované rozšírením.</translation>
@@ -715,6 +716,7 @@
<translation id="6047927260846328439">Tento obsah sa vás môže podvodom pokúsiť presvedčiť, aby ste si nainštalovali softvér alebo poskytli osobné informácie. <ph name="BEGIN_LINK" />Napriek tomu zobraziť<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Web <ph name="SITE" /> momentálne nemôžete navštíviť, pretože používa pripínanie certifikátov. Chyby siete a útoky sú zvyčajne dočasné, takže by táto stránka mala neskôr pravdepodobne fungovať.</translation>
<translation id="6059925163896151826">Zariadenia USB</translation>
+<translation id="6071091556643036997">Tento typ pravidiel je neplatný.</translation>
<translation id="6080696365213338172">K obsahu ste pristúpili pomocou certifikátu, ktorý poskytol správca. Údaje, ktoré poskytnete doméne <ph name="DOMAIN" /> môžu byť zachytené správcom.</translation>
<translation id="610911394827799129">Váš účet Google môže mať ďalšie formy histórie prehliadania na adrese <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Žiadne}=1{1 heslo (synchronizované)}few{# heslá (synchronizované)}many{# hesla (synchronizované)}other{# hesiel (synchronizované)}}</translation>
@@ -761,6 +763,7 @@
<translation id="6446608382365791566">Pridanie ďalších informácií</translation>
<translation id="6447842834002726250">Súbory cookie</translation>
<translation id="6451458296329894277">Potvrdiť opakované odoslanie formulára</translation>
+<translation id="6465306955648956876">Spravovať heslá…</translation>
<translation id="647261751007945333">Pravidlá zariadenia</translation>
<translation id="6477321094435799029">Chrome na tejto stránke zaznamenal nezvyčajný kód a v záujme ochrany vašich osobných informácií (napr. hesiel, telefónnych čísel a kreditných kariet) ho zablokoval.</translation>
<translation id="6489534406876378309">Spustiť nahrávanie správ o zlyhaní</translation>
@@ -780,6 +783,7 @@
<translation id="6628463337424475685">Vyhľadávanie <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Útočníci na webe <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sa môžu pokúsiť vo vašom počítači Mac nainštalovať nebezpečné programy, pomocou ktorých ukradnú alebo odstránia informácie (napríklad fotky, heslá, správy a kreditné karty). <ph name="BEGIN_LEARN_MORE_LINK" />Ďalšie informácie<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Toto pravidlo bolo označené ako zastarané.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Žiadne}=1{Z 1 webu (neodhlásime vás z účtu Google)}few{Z # webov (neodhlásime vás z účtu Google)}many{From # sites (you won't be signed out of your Google Account)}other{Z # webov (neodhlásime vás z účtu Google)}}</translation>
<translation id="6657585470893396449">Heslo</translation>
<translation id="6671697161687535275">Chcete návrh položky formulára odstrániť z prehliadača Chromium?</translation>
<translation id="6685834062052613830">Odhláste sa a dokončite nastavenie</translation>
@@ -806,6 +810,7 @@
<translation id="6915804003454593391">Používateľ:</translation>
<translation id="6945221475159498467">Vybrať</translation>
<translation id="6948701128805548767">Ak chcete zobraziť spôsoby a požiadavky vyzdvihnutia, vyberte adresu</translation>
+<translation id="6949872517221025916">Obnovenie hesla</translation>
<translation id="6957887021205513506">Zdá sa, že certifikát servera je falošný.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Zariadenie</translation>
@@ -827,7 +832,7 @@
<translation id="7138472120740807366">Spôsob doručenia</translation>
<translation id="7139724024395191329">Emirát</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ďalší}few{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ďalšie}many{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ďalšieho}other{<ph name="PAYMENT_METHOD_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> ďalších}}</translation>
-<translation id="7155487117670177674">Platba nie je zabezpečená</translation>
+<translation id="717330890047184534">ID služby Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ďalšia}few{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ďalšie}many{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ďalšej}other{<ph name="SHIPPING_OPTION_PREVIEW" /> a <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> ďalších}}</translation>
<translation id="7180611975245234373">Obnoviť</translation>
<translation id="7182878459783632708">Nie sú nastavené žiadne pravidlá</translation>
@@ -876,6 +881,7 @@
<translation id="7455133967321480974">Použiť predvolené všeobecné nastavenie (Blokovať)</translation>
<translation id="7460163899615895653">Vaše nedávne karty z iných zariadení sa zobrazia na tomto mieste</translation>
<translation id="7469372306589899959">Overovanie karty</translation>
+<translation id="7473891865547856676">Nie, ďakujem</translation>
<translation id="7481312909269577407">Dopredu</translation>
<translation id="7485870689360869515">Nenašli sa žiadne údaje.</translation>
<translation id="7508255263130623398">Identifikátor zariadenia vráteného v rámci záruky je prázdny alebo sa nezhoduje s identifikátorom aktuálneho zariadenia</translation>
@@ -898,7 +904,6 @@
<translation id="7569952961197462199">Chcete kreditnú kartu odstrániť z prehliadača Chrome?</translation>
<translation id="7575800019233204241">„Vaše pripojenie nie je súkromné“, „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;“, „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;“, „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;“ alebo „Chyba certifikátu SSL“</translation>
<translation id="7578104083680115302">Zaplaťte rýchlejšie na stránkach a v aplikáciách v rôznych službách pomocou kariet, ktoré ste si uložili na Googli.</translation>
-<translation id="7588950540487816470">Fyzický web</translation>
<translation id="7592362899630581445">Certifikát servera porušuje obmedzenia názvov.</translation>
<translation id="7598391785903975535">Menej ako <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Web <ph name="HOST_NAME" /> momentálne nemôže spracovať túto žiadosť.</translation>
@@ -945,7 +950,7 @@
<translation id="782886543891417279">Sieť Wi‑Fi (<ph name="WIFI_NAME" />), ktorú používate, môže vyžadovať, aby ste navštívili jej prihlasovaciu stránku</translation>
<translation id="785549533363645510">Nie ste však neviditeľný/-á. Prejdením do režimu inkognito neskryjete svoje prehliadanie pred zamestnávateľom, poskytovateľom internetových služieb ani pred navštívenými webmi.</translation>
<translation id="7855695075675558090"><ph name="TOTAL_LABEL" /> <ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
-<translation id="7862185352068345852">Opustiť web?</translation>
+<translation id="7862185352068345852">Chcete odísť z tohto webu?</translation>
<translation id="7878176543348854470">Debetné a predplatené karty sú akceptované.</translation>
<translation id="7878562273885520351">Vaše heslo mohlo byť napadnuté</translation>
<translation id="7887683347370398519">Skontrolujte svoj kód CVC a skúste to znova</translation>
@@ -1102,6 +1107,7 @@
<translation id="9148507642005240123">&amp;Vrátiť späť úpravu</translation>
<translation id="9154194610265714752">Aktualizované</translation>
<translation id="9157595877708044936">Prebieha nastavenie...</translation>
+<translation id="9168814207360376865">Povoliť webom zisťovať, či máte uložené spôsoby platby</translation>
<translation id="9169664750068251925">Vždy blokovať na tomto webe</translation>
<translation id="9170848237812810038">&amp;Naspäť</translation>
<translation id="917450738466192189">Certifikát servera je neplatný.</translation>
@@ -1110,7 +1116,6 @@
<translation id="9207861905230894330">Článok sa nepodarilo pridať.</translation>
<translation id="9215416866750762878">Bezpečnému pripojeniu Chromu k tomuto webu bráni aplikácia</translation>
<translation id="9219103736887031265">Obrázky</translation>
-<translation id="933612690413056017">Žiadne internetové pripojenie</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">VYMAZAŤ FORMULÁR</translation>
<translation id="939736085109172342">Nový priečinok</translation>
diff --git a/chromium/components/strings/components_strings_sl.xtb b/chromium/components/strings/components_strings_sl.xtb
index d7a20b2755e..a70b418d20f 100644
--- a/chromium/components/strings/components_strings_sl.xtb
+++ b/chromium/components/strings/components_strings_sl.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Izbira dovoljenja za: <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Nedavni zaznamki</translation>
<translation id="1113869188872983271">&amp;Razveljavi razvrstitev</translation>
+<translation id="1125573121925420732">Medtem ko spletne strani posodabljajo varnost, se lahko opozorila pogosto prikažejo. To se bo kmalu izboljšalo.</translation>
<translation id="1126551341858583091">Velikosti v lokalni shrambi je <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Predpomnilnik pravilnika ustrezen</translation>
<translation id="1150979032973867961">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; operacijski sistem vašega računalnika ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Preverite, ali internetna povezava deluje kot običajno.&lt;/li&gt;
&lt;li&gt;Obrnite se na lastnika spletnega mesta.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Vnesli ste geslo na spletnem mestu, ki ga ne upravlja vaša organizacija. Zaradi zaščite računa gesla ne uporabljajte za druge aplikacije in spletna mesta.</translation>
<translation id="1263231323834454256">Bralni seznam</translation>
<translation id="1264126396475825575">Poročilo o zrušitvi je bilo zajeto takrat: <ph name="CRASH_TIME" /> (ni še naloženo ali je prezrto)</translation>
<translation id="1270502636509132238">Način prevzema</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Izberi</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Tej strani prepreči, da bi ustvarila dodatna pogovorna okna</translation>
-<translation id="1629803312968146339">Ali želite, da Chrome shrani to kartico?</translation>
<translation id="1639239467298939599">Nalaganje</translation>
<translation id="1640180200866533862">Uporabniški pravilniki</translation>
<translation id="1640244768702815859">Poskusite <ph name="BEGIN_LINK" />obiskati domačo stran spletnega mesta<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Poskušajte zagnati orodje Omrežna diagnostika Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Posodobite geslo za sinhronizacijo.</translation>
<translation id="1787142507584202372">Tu so prikazani odprti zavihki</translation>
-<translation id="1789575671122666129">Pojavna okna</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Ime imetnika kartice</translation>
<translation id="1806541873155184440">Dodano: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Znova zaženite računalnik</translation>
<translation id="2113977810652731515">Kartica</translation>
<translation id="2114841414352855701">Prezrto, ker je to preglasil pravilnik <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Iskanje strani za Fizični splet v bližini</translation>
<translation id="213826338245044447">Zaznamki mobilne naprave</translation>
<translation id="214556005048008348">Prekliči plačilo</translation>
<translation id="2147827593068025794">Sinhroniziranje v ozadju</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Pravilnika ni mogoče najti</translation>
<translation id="2213606439339815911">Prenos vnosov ...</translation>
<translation id="2218879909401188352">Napadalci, ki so trenutno na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, bi lahko namestili nevarne aplikacije, ki poškodujejo napravo, dodali skrite stroške na račun za mobilno napravo ali ukradli osebne podatke. <ph name="BEGIN_LEARN_MORE_LINK" />Več o tem<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Brez internetne povezave</translation>
<translation id="2230458221926704099">Odpravite težave s povezavo z <ph name="BEGIN_LINK" />aplikacijo za diagnostiko<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Pošlji</translation>
<translation id="225207911366869382">Vrednost za ta pravilnik je zastarela.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Odstrani izbrane elemente</translation>
<translation id="277133753123645258">Način pošiljanja</translation>
<translation id="277499241957683684">Manjka zapis o napravi</translation>
+<translation id="2781030394888168909">Izvozi za macOS</translation>
<translation id="2784949926578158345">Povezava je bila obnovljena.</translation>
<translation id="2788784517760473862">Sprejete kreditne kartice</translation>
<translation id="2794233252405721443">Spletno mesto blokirano</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome trenutno ni mogel potrditi vaše kartice. Poskusite znova pozneje.</translation>
<translation id="3064966200440839136">Zaradi plačila v zunanji aplikaciji boste zapustili način brez beleženja zgodovine. Želite nadaljevati?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Brez}=1{1 geslo}one{# geslo}two{# gesli}few{# gesla}other{# gesel}}</translation>
-<translation id="3093245981617870298">Povezava ni vzpostavljena.</translation>
<translation id="3096100844101284527">Dodajanje naslova za prevzem</translation>
<translation id="3105172416063519923">ID sredstva:</translation>
<translation id="3109728660330352905">Nimate dovoljenja za ogled te strani.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Spletno mesto <ph name="HOST_NAME" /> trenutno ni dosegljivo.</translation>
<translation id="3427092606871434483">Dovoli (privzeto)</translation>
<translation id="3427342743765426898">&amp;Uveljavi urejanje</translation>
+<translation id="342781501876943858">Chromium priporoča, da ponastavite geslo, če ste ga uporabljali tudi na drugih spletnih mestih.</translation>
<translation id="3431636764301398940">Shrani to kartico v tej napravi</translation>
<translation id="3447661539832366887">Lastnik te naprave je izklopil igro z dinozavri</translation>
<translation id="3447884698081792621">Prikaz potrdila (izdal: <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Odpiranje strani v novem oknu brez beleženja zgodovine (Ctrl + Shift + N)</translation>
<translation id="3679803492151881375">Poročilo o zrušitvi je bilo zajeto takrat: <ph name="CRASH_TIME" />, naloženo takrat: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Informacije o potrdilu</translation>
-<translation id="3690164694835360974">Prijava ni varna</translation>
<translation id="3704162925118123524">Omrežje, ki ga uporabljate, morda zahteva, da obiščete stran za prijavo.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Nalaganje ...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Globalno uporabi privzete nastavitve (zaznavanje)</translation>
<translation id="4165986682804962316">Nastavitve spletnega mesta</translation>
-<translation id="4169947484918424451">Ali želite, da Chromium shrani to kartico?</translation>
<translation id="4171400957073367226">Neveljavni podpis za preverjanje</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Še <ph name="ITEM_COUNT" /> element}one{Še <ph name="ITEM_COUNT" /> element}two{Še <ph name="ITEM_COUNT" /> elementa}few{Še <ph name="ITEM_COUNT" /> elementi}other{Še <ph name="ITEM_COUNT" /> elementov}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Znova zaženite napravo.</translation>
<translation id="4277028893293644418">Ponastavi geslo</translation>
<translation id="4280429058323657511">, datum poteka veljavnosti: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Preklopi</translation>
<translation id="4312866146174492540">Blokira (privzeto)</translation>
<translation id="4325863107915753736">Članka ni bilo mogoče najti</translation>
<translation id="4326324639298822553">Preverite datum poteka veljavnosti in poskusite znova.</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Ta računalnik ni zaznan kot računalnik, ki ga upravlja podjetje, zato lahko pravilnik samodejno namesti samo razširitve, ki gostujejo v Spletni trgovini Chrome. URL za posodobitve v Spletni trgovini Chrome je »<ph name="CWS_UPDATE_URL" />«.</translation>
<translation id="4346197816712207223">Sprejete kreditne kartice</translation>
<translation id="4356973930735388585">Napadalci na tem spletnem mestu lahko poskusijo v vašem računalniku namestiti nevarne programe, ki kradejo ali brišejo podatke (na primer fotografije, gesla, sporočila in podatke kreditnih kartic).</translation>
+<translation id="4358461427845829800">Upravljanje plačilnih sredstev ...</translation>
<translation id="4372948949327679948">Pričakovana vrednost je vrste <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Poskusili ste dostopati do domene <ph name="DOMAIN" />, vendar je izdajatelj preklical potrdilo, ki ga je poslal strežnik. To pomeni, da varnostnim poverilnicam, ki jih je poslal strežnik, nikakor ne smete zaupati. Morda komunicirate z napadalcem.</translation>
<translation id="4406896451731180161">rezultati iskanja</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Naslov za prevzem</translation>
<translation id="4424024547088906515">Strežniku ni uspelo dokazati, da je <ph name="DOMAIN" />; Chrome ne zaupa njegovemu varnostnemu potrdilu. Razlog za to je lahko napačna konfiguracija ali napadalčevo prestrezanje povezave.</translation>
<translation id="4432688616882109544">Spletno mesto <ph name="HOST_NAME" /> ni sprejelo potrdila za prijavo ali pa to ni bilo posredovano.</translation>
+<translation id="4434045419905280838">Pojavna okna in preusmeritve</translation>
<translation id="443673843213245140">Uporaba strežnika proxy je onemogočena, vendar je njegova konfiguracija izrecno določena.</translation>
<translation id="445100540951337728">Sprejete debetne kartice</translation>
<translation id="4506176782989081258">Napaka pri preverjanju veljavnosti: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Samodejno izpolnjevanje podatkov za plačevanje je onemogočeno</translation>
<translation id="4764776831041365478">Spletna stran na naslovu <ph name="URL" /> morda začasno ne deluje ali pa je trajno premaknjena na novi spletni naslov.</translation>
<translation id="4771973620359291008">Prišlo je do neznane napake.</translation>
+<translation id="4785689107224900852">Preklop na ta zavihek</translation>
<translation id="4792143361752574037">Pri dostopanju do datotek seje je prišlo do težave. Shranjevanje na disk je trenutno onemogočeno. Znova naložite stran, če želite poskusiti znova.</translation>
<translation id="4800132727771399293">Preverite datum poteka in številko CVC ter poskusite znova</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Spletnega mesta <ph name="SITE" /> trenutno ne morete obiskati, saj je poslalo šifrirane poverilnice, ki jih Google Chrome ne more obdelati. Napake omrežja in napadi na omrežje so običajno začasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="4813512666221746211">Napaka v omrežju</translation>
<translation id="4816492930507672669">Prilagodi strani</translation>
-<translation id="483020001682031208">Ni strani za Fizični splet za prikaz</translation>
<translation id="4850886885716139402">Pogled</translation>
<translation id="4854362297993841467">Ta način pošiljanja ni na voljo. Poskusite uporabiti drugega.</translation>
<translation id="4858792381671956233">Starše si vprašal(-a), ali smeš obiskati to spletno mesto</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-bitno)</translation>
<translation id="5121084798328133320">Ko potrdite, bodo temu spletnemu mestu razkriti podatki o kreditni kartici iz računa za Google Payments.</translation>
<translation id="5128122789703661928">Seja s tem imenom ni veljavna za izbris.</translation>
+<translation id="5135404736266831032">Upravljanje naslovov ...</translation>
<translation id="5141240743006678641">Šifrirajte sinhronizirana gesla s poverilnicami za Google</translation>
<translation id="5145883236150621069">Koda napake v odzivu pravilnika</translation>
<translation id="5159010409087891077">Odpiranje strani v novem oknu brez beleženja zgodovine (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Vdelana stran na tej spletni strani sporoča:</translation>
<translation id="5205222826937269299">Ime je obvezno</translation>
<translation id="5222812217790122047">E-poštni naslov je obvezen</translation>
-<translation id="522700295135997067">To spletno mesto vam je morda pravkar ukradlo geslo</translation>
<translation id="5230733896359313003">Naslov za pošiljanje</translation>
<translation id="5250209940322997802">»Vzpostavite povezavo z omrežjem«</translation>
<translation id="5251803541071282808">Oblak</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">To spletno mesto v intranetu podjetja, organizacije ali šole ima enak URL kot zunanje spletno mesto.
<ph name="LINE_BREAK" />
Poskusite se obrniti na skrbnika sistema.</translation>
-<translation id="5499929369096410817">Vnesite varnostno kodo za kartico <ph name="CREDIT_CARD" />. Ta koda ne bo shranjena.</translation>
<translation id="5509780412636533143">Upravljani zaznamki</translation>
<translation id="5510766032865166053">Morda je premaknjena ali izbrisana.</translation>
<translation id="5523118979700054094">Ime pravilnika</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Dodajanje naslova za pošiljanje</translation>
<translation id="5689199277474810259">Izvozi v JSON</translation>
<translation id="5689516760719285838">Lokacija</translation>
+<translation id="570530837424789914">Upravljanje ...</translation>
<translation id="5710435578057952990">Identiteta tega spletnega mesta ni bila potrjena.</translation>
<translation id="5719499550583120431">Sprejema predplačniške kartice.</translation>
<translation id="5720705177508910913">Trenutni uporabnik</translation>
+<translation id="5730040223043577876">Chrome priporoča, da ponastavite geslo, če ste ga uporabljali na drugih spletnih mestih.</translation>
<translation id="5732392974455271431">Starši ga lahko odblokirajo</translation>
<translation id="5763042198335101085">Vnesite veljaven e-poštni naslov</translation>
<translation id="5765072501007116331">Če si želite ogledati načine dostave in zahteve, izberite naslov</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Samodejno pošlji Googlu nekatere <ph name="BEGIN_WHITEPAPER_LINK" />sistemske podatke in vsebino strani<ph name="END_WHITEPAPER_LINK" /> zaradi zaznavanja nevarnih aplikacij in spletnih mest. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Urejanje podatkov o stiku</translation>
<translation id="5967867314010545767">Odstrani iz zgodovine</translation>
-<translation id="5972020793760134803">Preklop na zavihek</translation>
<translation id="5975083100439434680">Pomanjšaj</translation>
-<translation id="597552863672748783">Potrditev varnostne kode</translation>
<translation id="598637245381783098">Plačilne aplikacije ni mogoče odpreti</translation>
<translation id="5989320800837274978">Določeni niso ne stalni strežniki proxy ne URL skripta .pac.</translation>
<translation id="5990559369517809815">Zahteve za strežnik je blokirala razširitev.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Ta vsebina vas morda poskuša zavesti, da namestite programsko opremo ali razkrijete osebne podatke. <ph name="BEGIN_LINK" />Vseeno prikaži<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Spletnega mesta <ph name="SITE" /> trenutno ni mogoče obiskati, ker uporablja pripenjanje potrdil. Napake omrežja in napadi na omrežje so običajno začasni, zato bo ta stran verjetno delovala pozneje.</translation>
<translation id="6059925163896151826">Naprave USB</translation>
+<translation id="6071091556643036997">Vrsta pravilnika je neveljavna.</translation>
<translation id="6080696365213338172">Do vsebine ste dostopali z geslom, ki ga je zagotovil skrbnik. Podatke, ki jih pošljete v <ph name="DOMAIN" />, lahko prestreže skrbnik.</translation>
<translation id="610911394827799129">V Google Računu so morda druge vrste zgodovine brskanja na <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Brez}=1{1 geslo (sinhronizirano)}one{# geslo (sinhronizirano)}two{# gesli (sinhronizirani)}few{# gesla (sinhronizirana)}other{# gesel (sinhroniziranih)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Dodajanje več podatkov</translation>
<translation id="6447842834002726250">Piškotki</translation>
<translation id="6451458296329894277">Potrdite ponovno pošiljanje obrazca</translation>
+<translation id="6465306955648956876">Upravljanje gesel ...</translation>
<translation id="647261751007945333">Pravilniki za naprave</translation>
<translation id="6477321094435799029">Chrome je zaznal nenavadno kodo na tej strani in jo zaradi zaščite vaših osebnih podatkov (na primer gesel, telefonskih številk in kreditnih kartic) blokiral.</translation>
<translation id="6489534406876378309">Začetek prenašanja zrušitev v storitev</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Iskanje</translation>
<translation id="6630809736994426279">Napadalci, ki so trenutno na spletnem mestu <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />, lahko poskusijo v vašem računalniku Mac namestiti nevarne programe, ki kradejo ali brišejo podatke (na primer fotografije, gesla, sporočila in podatke kreditnih kartic). <ph name="BEGIN_LEARN_MORE_LINK" />Več o tem<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Ta pravilnik je zastarel.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Nič}=1{Na 1 spletnem mestu (iz Google Računa ne boste odjavljeni)}one{Na # spletnem mestu (iz Google Računa ne boste odjavljeni)}two{Na # spletnih mestih (iz Google Računa ne boste odjavljeni)}few{Na # spletnih mestih (iz Google Računa ne boste odjavljeni)}other{Na # spletnih mestih (iz Google Računa ne boste odjavljeni)}}</translation>
<translation id="6657585470893396449">Geslo</translation>
<translation id="6671697161687535275">Želite predlog obrazca odstraniti iz Chromiuma?</translation>
<translation id="6685834062052613830">Odjavite se in dokončajte nastavitev</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Uporabnik:</translation>
<translation id="6945221475159498467">Izberi</translation>
<translation id="6948701128805548767">Če si želite ogledati načine prevzema in zahteve, izberite naslov</translation>
+<translation id="6949872517221025916">Ponastavitev gesla</translation>
<translation id="6957887021205513506">Potrdilo strežnika je očitno ponaredek.</translation>
<translation id="6965382102122355670">V redu</translation>
<translation id="6965978654500191972">Naprava</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Način dostave</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}two{<ph name="PAYMENT_METHOD_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Plačilo ni varno</translation>
+<translation id="717330890047184534">ID za Gaio:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}two{<ph name="SHIPPING_OPTION_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> in še <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Osveži</translation>
<translation id="7182878459783632708">Ni nastavljenih pravilnikov</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Uporabi globalno privzeto (Blokiraj)</translation>
<translation id="7460163899615895653">Tu so prikazani nedavni zavihki iz drugih naprav</translation>
<translation id="7469372306589899959">Potrjevanje kartice</translation>
+<translation id="7473891865547856676">Ne, hvala</translation>
<translation id="7481312909269577407">Naprej</translation>
<translation id="7485870689360869515">Ni podatkov.</translation>
<translation id="7508255263130623398">Vrnjen ID naprave pravilnika je prazen ali se ne ujema s trenutnim ID-jem naprave</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Želite odstraniti kreditno kartico iz Chroma?</translation>
<translation id="7575800019233204241">»Vaša povezava ni zasebna« ali »&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;« ali »&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;« ali »&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;« ali »Napaka v potrdilu SSL«</translation>
<translation id="7578104083680115302">Hitro plačevanje na spletnih mestih in v aplikacijah v vseh napravah s karticami, ki ste jih shranili v Googlu.</translation>
-<translation id="7588950540487816470">Fizični splet</translation>
<translation id="7592362899630581445">Strežnikovo potrdilo krši omejitve imen.</translation>
<translation id="7598391785903975535">Manj kot <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Spletno mesto <ph name="HOST_NAME" /> trenutno ne more obdelati te zahteve.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Razveljavi urejanje</translation>
<translation id="9154194610265714752">Posodobljeno</translation>
<translation id="9157595877708044936">Nastavljanje ...</translation>
+<translation id="9168814207360376865">Dovoli spletnim mestom, da preverijo, ali imate shranjena plačilna sredstva</translation>
<translation id="9169664750068251925">Vedno blokiraj na tem spletnem mestu</translation>
<translation id="9170848237812810038">&amp;Razveljavi</translation>
<translation id="917450738466192189">Potrdilo strežnika ni veljavno.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Članka ni bilo mogoče dodati.</translation>
<translation id="9215416866750762878">Aplikacija Chromu preprečuje vzpostavitev varne povezave s tem mestom</translation>
<translation id="9219103736887031265">Slike</translation>
-<translation id="933612690413056017">Ni internetne povezave</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">POČISTI OBRAZEC</translation>
<translation id="939736085109172342">Nova mapa</translation>
diff --git a/chromium/components/strings/components_strings_sr.xtb b/chromium/components/strings/components_strings_sr.xtb
index b51e00bbdaa..d778b52ab92 100644
--- a/chromium/components/strings/components_strings_sr.xtb
+++ b/chromium/components/strings/components_strings_sr.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Изаберите дозволу: <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Недавно коришћени обележивачи</translation>
<translation id="1113869188872983271">&amp;Опозови промену редоследа</translation>
+<translation id="1125573121925420732">Упозорења могу често да се приказују док веб-сајтови ажурирају безбедност. То би ускоро требало да се побољша.</translation>
<translation id="1126551341858583091">Величина у локалном меморијском простору је <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Кеш смерница је у реду</translation>
<translation id="1150979032973867961">Овај сервер не може да докаже да је <ph name="DOMAIN" />; оперативни систем рачунара нема поверења у његов безбедносни сертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Проверите да ли интернет веза исправно функционише.&lt;/li&gt;
&lt;li&gt;Контактирајте власника веб-сајта.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Унели сте лозинку на сајту којим не управља ваша организација. Да бисте заштитили налог, не користите лозинку поново у другим апликацијама ни на другим сајтовима.</translation>
<translation id="1263231323834454256">Листа за читање</translation>
<translation id="1264126396475825575">Извештај о отказивању је снимљен <ph name="CRASH_TIME" /> (још увек није отпремљен или игнорисан)</translation>
<translation id="1270502636509132238">Начин преузимања</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Одабери</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1623104350909869708">Спречи ову страницу да прави додатне дијалоге</translation>
-<translation id="1629803312968146339">Желите ли да Chrome сачува ову картицу?</translation>
<translation id="1639239467298939599">Учитавање</translation>
<translation id="1640180200866533862">Смернице за кориснике</translation>
<translation id="1640244768702815859">Покушајте да <ph name="BEGIN_LINK" />посетите почетну страницу сајта<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Покушајте да покренете Windows дијагностику мреже<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Ажурирај приступну фразу за синхронизацију</translation>
<translation id="1787142507584202372">Отворене картице се појављују овде</translation>
-<translation id="1789575671122666129">Искачући прозори</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Име власника картице</translation>
<translation id="1806541873155184440">Додато је: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Поново покрените рачунар</translation>
<translation id="2113977810652731515">Картица</translation>
<translation id="2114841414352855701">Занемарују се јер су замењене смерницама <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Тражимо странице Интернета око нас у околини</translation>
<translation id="213826338245044447">Обележивачи на мобилном уређају</translation>
<translation id="214556005048008348">Откажи плаћање</translation>
<translation id="2147827593068025794">Синхронизација у позадини</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Смернице нису пронађене</translation>
<translation id="2213606439339815911">Преузимање уноса...</translation>
<translation id="2218879909401188352">Нападачи који су тренутно на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> могу да инсталирају опасне апликације које ће вам оштетити уређај, додати нежељене трошкове код мобилног оператера или украсти личне податке. <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Нема интернета</translation>
<translation id="2230458221926704099">Поправите везу помоћу <ph name="BEGIN_LINK" />апликације за дијагностику<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Пошаљи одмах</translation>
<translation id="225207911366869382">Ова вредност је застарела за ове смернице.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Уклони изабране ставке</translation>
<translation id="277133753123645258">Начин слања</translation>
<translation id="277499241957683684">Недостаје евиденција уређаја</translation>
+<translation id="2781030394888168909">Извези за Mac OS</translation>
<translation id="2784949926578158345">Веза је враћена на почетне вредности.</translation>
<translation id="2788784517760473862">Кредитне картице које се прихватају</translation>
<translation id="2794233252405721443">Сајт је блокиран</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome није успео да потврди картицу. Пробајте поново касније.</translation>
<translation id="3064966200440839136">Напустићете режим без архивирања да бисте платили у спољној апликацији. Желите ли да наставите?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{None}=1{1 лозинка}one{# лозинка}few{# лозинке}other{# лозинки}}</translation>
-<translation id="3093245981617870298">Офлајн сте.</translation>
<translation id="3096100844101284527">Додај адресу преузимања</translation>
<translation id="3105172416063519923">ИД елемента:</translation>
<translation id="3109728660330352905">Немате овлашћење да прегледате ову страницу.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Хост <ph name="HOST_NAME" /> тренутно није доступан.</translation>
<translation id="3427092606871434483">Дозволи (подразумевано)</translation>
<translation id="3427342743765426898">&amp;Понови измену</translation>
+<translation id="342781501876943858">Chromium вам препоручује да ресетујете лозинку ако сте је користили на другим сајтовима.</translation>
<translation id="3431636764301398940">Сачувај ову картицу на овом уређају</translation>
<translation id="3447661539832366887">Власник овог уређаја је искључио ову застарелу игру.</translation>
<translation id="3447884698081792621">Прикажи сертификат (издаје <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Отворите страницу у ноцом прозору без архивирања (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Извештај о отказивању је снимљен <ph name="CRASH_TIME" />, а отпремљен <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Информације о сертификату</translation>
-<translation id="3690164694835360974">Пријављивање није безбедно</translation>
<translation id="3704162925118123524">Мрежа коју користите ће можда захтевати да посетите страницу за пријављивање.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Учитава се...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Користи глобалну подразумевану вредност (Откривај)</translation>
<translation id="4165986682804962316">Подешавања сајта</translation>
-<translation id="4169947484918424451">Желите ли да Chromium сачува ову картицу?</translation>
<translation id="4171400957073367226">Неисправан потпис за верификацију</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{још <ph name="ITEM_COUNT" /> ставка}one{још <ph name="ITEM_COUNT" /> ставка}few{још <ph name="ITEM_COUNT" /> ставке}other{још <ph name="ITEM_COUNT" /> ставки}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Поновно покретање уређаја</translation>
<translation id="4277028893293644418">Ресетујте лозинку</translation>
<translation id="4280429058323657511">, истиче <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Пређи</translation>
<translation id="4312866146174492540">Блокирај (подразумевано)</translation>
<translation id="4325863107915753736">Нисмо успели да пронађемо чланак</translation>
<translation id="4326324639298822553">Проверите датум истека и пробајте поново</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Откривено је да овим рачунаром не управља предузеће, па смернице могу аутоматски да инсталирају само додатке који се хостују у Chrome веб-продавници. URL ажурирања у Chrome веб-продавници је „<ph name="CWS_UPDATE_URL" />“.</translation>
<translation id="4346197816712207223">Кредитне картице које се прихватају</translation>
<translation id="4356973930735388585">Нападачи на овом сајту ће можда покушати да инсталирају опасне програме на рачунару који краду или бришу информације (на пример, слике, лозинке, поруке и бројеве кредитних картица).</translation>
+<translation id="4358461427845829800">Управљајте начинима плаћања...</translation>
<translation id="4372948949327679948">Очекивана вредност je <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Покушали сте да контактирате <ph name="DOMAIN" />, али је издавач опозвао сертификат који је сервер навео. То значи да никако не треба имати поверења у безбедносне акредитиве које је сервер навео. Могуће је да комуницирате са нападачем.</translation>
<translation id="4406896451731180161">резултати претраге</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Адреса преузимања</translation>
<translation id="4424024547088906515">Овај сервер не може да докаже да је <ph name="DOMAIN" />; Chrome нема поверења у његов безбедносни сертификат. Узрок томе је можда погрешна конфигурација или нападач који је прекинуо везу.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> није прихватио сертификат за пријављивање или сертификат за пријављивање није приложен.</translation>
+<translation id="4434045419905280838">Искачући прозори и преусмеравања</translation>
<translation id="443673843213245140">Коришћење проксија је онемогућено, али је наведена експлицитна конфигурација проксија.</translation>
<translation id="445100540951337728">Дебитне картице које се прихватају</translation>
<translation id="4506176782989081258">Грешка при потврди ваљаности: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Аутоматско попуњавање плаћања је онемогућено</translation>
<translation id="4764776831041365478">Могуће је да веб-страница на адреси <ph name="URL" /> привремено не функционише или да је трајно премештена на нову веб адресу.</translation>
<translation id="4771973620359291008">Дошло је до непознате грешке.</translation>
+<translation id="4785689107224900852">Пређите на ову картицу</translation>
<translation id="4792143361752574037">Дошло је до проблема при приступању датотекама сесије. Чување на диску је тренутно онемогућено. Учитајте поново страницу да бисте пробали поново.</translation>
<translation id="4800132727771399293">Проверите датум истека и CVC и покушајте поново</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Тренутно не можете да посетите <ph name="SITE" /> зато што је веб-сајт послао шифроване акредитиве које Google Chrome не може да обради. Грешке и напади на мрежи су обично привремени, па ће ова страница вероватно функционисати касније.</translation>
<translation id="4813512666221746211">Грешка на мрежи</translation>
<translation id="4816492930507672669">Уклопи у страницу</translation>
-<translation id="483020001682031208">Не постоје странице Интернета око нас за приказивање</translation>
<translation id="4850886885716139402">Приказ</translation>
<translation id="4854362297993841467">Овај начин испоруке није доступан. Испробајте неки други начин.</translation>
<translation id="4858792381671956233">Питао/ла си родитеље да ли смеш да посетиш овај сајт</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-битни)</translation>
<translation id="5121084798328133320">Када будете потврдили, подаци о картици са налога за Google плаћања ће бити послати овом сајту.</translation>
<translation id="5128122789703661928">Сесија са овим називом није доступна за брисање.</translation>
+<translation id="5135404736266831032">Управљајте адресама...</translation>
<translation id="5141240743006678641">Шифруј синхронизоване лозинке помоћу Google акредитива</translation>
<translation id="5145883236150621069">Кôд грешке је присутан у одговору на смернице</translation>
<translation id="5159010409087891077">Отворите страницу у новом прозору без архивирања (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Уграђена страница на овој веб-страници наводи:</translation>
<translation id="5205222826937269299">Име је обавезно</translation>
<translation id="5222812217790122047">Имејл је обавезан</translation>
-<translation id="522700295135997067">Овај сајт вам је можда управо украо лозинку</translation>
<translation id="5230733896359313003">Адреса за слање</translation>
<translation id="5250209940322997802">„Повежите се на мрежу“</translation>
<translation id="5251803541071282808">Клауд</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Овај сајт на интранету компаније, организације или школе има исти URL као и један спољни веб-сајт.
<ph name="LINE_BREAK" />
Покушајте да се обратите администратору система.</translation>
-<translation id="5499929369096410817">Унесите безбедносни кôд за картицу <ph name="CREDIT_CARD" />. Овај кôд се не чува.</translation>
<translation id="5509780412636533143">Обележивачи којим се управља</translation>
<translation id="5510766032865166053">Можда је премештен или избрисан.</translation>
<translation id="5523118979700054094">Назив смерница</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Додај адресу за испоруку</translation>
<translation id="5689199277474810259">Извези у JSON</translation>
<translation id="5689516760719285838">Локација</translation>
+<translation id="570530837424789914">Управљајте...</translation>
<translation id="5710435578057952990">Идентитет овог веб-сајта није верификован.</translation>
<translation id="5719499550583120431">Прихватају се припејд картице.</translation>
<translation id="5720705177508910913">Тренутни корисник</translation>
+<translation id="5730040223043577876">Chrome вам препоручује да ресетујете лозинку ако сте је користили на другим сајтовима.</translation>
<translation id="5732392974455271431">Родитељи могу да га деблокирају за тебе</translation>
<translation id="5763042198335101085">Унесите важећу имејл адресу</translation>
<translation id="5765072501007116331">Да бисте видели начине и захтеве за испоруку, изаберите адресу</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Аутоматски шаљите одређене <ph name="BEGIN_WHITEPAPER_LINK" />информације о систему и садржај страница<ph name="END_WHITEPAPER_LINK" /> Google-у да бисте нам помогли да откријемо опасне апликације и сајтове. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Измените контакт информације</translation>
<translation id="5967867314010545767">Уклони из историје</translation>
-<translation id="5972020793760134803">Пређи на картицу</translation>
<translation id="5975083100439434680">Умањивање</translation>
-<translation id="597552863672748783">Потврдите безбедносни кôд</translation>
<translation id="598637245381783098">Отварање апликације за плаћање није успело</translation>
<translation id="5989320800837274978">Нису наведени ни фиксни прокси сервери нити URL адреса .pac скрипте.</translation>
<translation id="5990559369517809815">Додатак је блокирао захтеве упућене серверу.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Овај садржај ће покушати да вас превари да инсталирате софтвер или откријете личне податке. <ph name="BEGIN_LINK" />Ипак прикажи<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Тренутно не можете да посетите <ph name="SITE" /> јер веб-сајт користи проверу сертификата. Грешке и напади на мрежи су обично привремени, па ће ова страница вероватно функционисати касније.</translation>
<translation id="6059925163896151826">USB уређаји</translation>
+<translation id="6071091556643036997">Овај тип смерница је неважећи.</translation>
<translation id="6080696365213338172">Приступали сте садржају помоћу сертификата који је обезбедио администратор. Администратор може да пресретне податке које обезбедите домену <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">Google налог може да има друге облике историје прегледања на <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{None}=1{1 лозинка (синхронизована)}one{# лозинка (синхронизована)}few{# лозинке (синхронизоване)}other{# лозинки (синхронизованих)}}</translation>
@@ -765,6 +767,7 @@
<translation id="6446608382365791566">Додајте још информација</translation>
<translation id="6447842834002726250">Колачићи</translation>
<translation id="6451458296329894277">Потврђивање поновног слања обрасца</translation>
+<translation id="6465306955648956876">Управљајте лозинкама...</translation>
<translation id="647261751007945333">Смернице за уређај</translation>
<translation id="6477321094435799029">Chrome је открио неуобичајени кôд на овој страници и блокирао је ради заштите ваших личних података (попут лозинки, бројева телефона или бројева кредитних картица).</translation>
<translation id="6489534406876378309">Покрени отпремање отказивања</translation>
@@ -784,6 +787,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> претрага</translation>
<translation id="6630809736994426279">Нападачи који су тренутно на <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> ће можда покушати да инсталирају опасне програме на Mac-у који краду или бришу податке (на пример, слике, лозинке, поруке и бројеве кредитних картица). <ph name="BEGIN_LEARN_MORE_LINK" />Сазнајте више<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Ове смернице су застареле.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{None}=1{Са 1 сајта (нећемо вас одјавити са Google налога)}one{Са # сајта (нећемо вас одјавити са Google налога)}few{Са # сајта (нећемо вас одјавити са Google налога)}other{Са # сајтова (нећемо вас одјавити са Google налога)}}</translation>
<translation id="6657585470893396449">Лозинка</translation>
<translation id="6671697161687535275">Желите ли да уклоните предлог из Chromium-а?</translation>
<translation id="6685834062052613830">Одјавите се и довршите подешавање</translation>
@@ -810,6 +814,7 @@
<translation id="6915804003454593391">Корисник:</translation>
<translation id="6945221475159498467">Изабери</translation>
<translation id="6948701128805548767">Да бисте видели начине и захтеве за преузимање, изаберите адресу</translation>
+<translation id="6949872517221025916">Ресетујте лозинку</translation>
<translation id="6957887021205513506">Изгледа да је сертификат сервера фалсификован.</translation>
<translation id="6965382102122355670">Потврди</translation>
<translation id="6965978654500191972">Уређај</translation>
@@ -831,7 +836,7 @@
<translation id="7138472120740807366">Начин испоруке</translation>
<translation id="7139724024395191329">Емират</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Плаћање није безбедно</translation>
+<translation id="717330890047184534">Gaia ИД:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> и још <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Освежи</translation>
<translation id="7182878459783632708">Нису подешене никакве смернице</translation>
@@ -880,6 +885,7 @@
<translation id="7455133967321480974">Користи глобалну подразумевану вредност (Блокирај)</translation>
<translation id="7460163899615895653">Недавне картице са других уређаја се приказују овде</translation>
<translation id="7469372306589899959">Потврђивање картице</translation>
+<translation id="7473891865547856676">Не, хвала</translation>
<translation id="7481312909269577407">Проследи</translation>
<translation id="7485870689360869515">Нису пронађени подаци.</translation>
<translation id="7508255263130623398">Враћени ИД уређаја за смернице је празан или се не подудара са актуелним ИД-ом уређаја</translation>
@@ -902,7 +908,6 @@
<translation id="7569952961197462199">Желите ли да уклоните кредитну картицу из Chrome-а?</translation>
<translation id="7575800019233204241">„Веза није приватна“ или „&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;“ или „&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;“ или „&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;“ или „Грешка са SSL сертификатом“</translation>
<translation id="7578104083680115302">Плаћајте брзо на сајтовима и у апликацијама на свим уређајима помоћу картица које сте сачували на Google-у.</translation>
-<translation id="7588950540487816470">Интернет око нас</translation>
<translation id="7592362899630581445">Сертификат сервера крши ограничења за име.</translation>
<translation id="7598391785903975535">Мање од <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Хост <ph name="HOST_NAME" /> тренутно не може да обради овај захтев.</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">&amp;Опозови измену</translation>
<translation id="9154194610265714752">Ажурирано</translation>
<translation id="9157595877708044936">Подешавање...</translation>
+<translation id="9168814207360376865">Дозволите сајтовима да проверавају да ли имате сачуване начине плаћања</translation>
<translation id="9169664750068251925">Увек блокирај на овом сајту</translation>
<translation id="9170848237812810038">&amp;Опозови</translation>
<translation id="917450738466192189">Сертификат сервера је неважећи.</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">Додавање чланка није успело.</translation>
<translation id="9215416866750762878">Апликација онемогућава Chrome-у да се безбедно повеже са овим сајтом</translation>
<translation id="9219103736887031265">Слике</translation>
-<translation id="933612690413056017">Није успостављена веза са интернетом</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ОБРИШИ ОБРАЗАЦ</translation>
<translation id="939736085109172342">Нови директоријум</translation>
diff --git a/chromium/components/strings/components_strings_sv.xtb b/chromium/components/strings/components_strings_sv.xtb
index b192305bdd4..bfc504e22cd 100644
--- a/chromium/components/strings/components_strings_sv.xtb
+++ b/chromium/components/strings/components_strings_sv.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Välj behörighet för <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Nya bokmärken</translation>
<translation id="1113869188872983271">&amp;Ångra Ändra ordning</translation>
+<translation id="1125573121925420732">Varningar kan förekomma medan en webbplats uppdaterar säkerheten. Detta förbättras inom kort.</translation>
<translation id="1126551341858583091">Storleken på det lokala lagringsutrymmet är <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Cacheminnet för policyn är OK</translation>
<translation id="1150979032973867961">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom datorns operativsystem inte litar på dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Kontrollera att internetanslutningen fungerar normalt.&lt;/li&gt;
&lt;li&gt;Kontakta ägaren av webbplatsen.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Du har angett ditt lösenord på en webbplats som inte hanteras av organisationen. Skydda kontot genom att inte återanvända lösenordet för andra appar och webbplatser.</translation>
<translation id="1263231323834454256">Läslista</translation>
<translation id="1264126396475825575">Felrapport skapades <ph name="CRASH_TIME" /> (har ännu inte laddats upp eller ignorerats)</translation>
<translation id="1270502636509132238">Alternativ för utlämning</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Välj</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Hindra sidan från att skapa fler dialogrutor</translation>
-<translation id="1629803312968146339">Vill du att Chrome sparar det här kortet?</translation>
<translation id="1639239467298939599">Läser in</translation>
<translation id="1640180200866533862">Användarpolicyer</translation>
<translation id="1640244768702815859">Testa att <ph name="BEGIN_LINK" />besöka webbplatsens startsida<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Testa att köra nätverksdiagnostik för Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Uppdatera lösenfrasen för synkroniseringen.</translation>
<translation id="1787142507584202372">Öppna flikar visas här</translation>
-<translation id="1789575671122666129">Popup-fönster</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Namn på kortinnehavare</translation>
<translation id="1806541873155184440">Lades till den <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Starta om datorn</translation>
<translation id="2113977810652731515">Kort</translation>
<translation id="2114841414352855701">Ignoreras eftersom den åsidosätts av <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Söker efter Physical Web-sidor i närheten</translation>
<translation id="213826338245044447">Bokmärken i mobilen</translation>
<translation id="214556005048008348">Avbryt betalningen</translation>
<translation id="2147827593068025794">Bakgrundssynkronisering</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Policyn hittades inte</translation>
<translation id="2213606439339815911">Hämtar poster …</translation>
<translation id="2218879909401188352">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> skulle kunna installera farliga appar som skadar enheten, lägger till dolda avgifter på din mobilfaktura eller stjäl personliga uppgifter. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Inget internet</translation>
<translation id="2230458221926704099">Åtgärda anslutningsproblemet med hjälp av <ph name="BEGIN_LINK" />diagnostiseringsappen<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Skicka nu</translation>
<translation id="225207911366869382">Värdet är inte längre giltigt för policyn.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Ta bort valda objekt</translation>
<translation id="277133753123645258">Fraktalternativ</translation>
<translation id="277499241957683684">Enhetsregister saknas</translation>
+<translation id="2781030394888168909">Exportera för MacOS</translation>
<translation id="2784949926578158345">Anslutningen återställdes.</translation>
<translation id="2788784517760473862">Godkända kreditkort</translation>
<translation id="2794233252405721443">Webbplatsen har blockerats</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Det gick inte att bekräfta kortet. Försök igen senare.</translation>
<translation id="3064966200440839136">Om du betalar i ett externt program sker inte det i inkognitoläge. Vill du fortsätta?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Ingen}=1{1 lösenord}other{# lösenord}}</translation>
-<translation id="3093245981617870298">Du är offline.</translation>
<translation id="3096100844101284527">Lägg till hämtningsadress</translation>
<translation id="3105172416063519923">Tillgångs-id:</translation>
<translation id="3109728660330352905">Du är inte behörig att se den här sidan.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> kan inte nås för tillfället.</translation>
<translation id="3427092606871434483">Tillåt (standard)</translation>
<translation id="3427342743765426898">&amp;Gör om Redigera</translation>
+<translation id="342781501876943858">Du rekommenderas att återställa lösenordet om du har återanvänt det på andra webbplatser.</translation>
<translation id="3431636764301398940">Spara kortet på enheten</translation>
<translation id="3447661539832366887">Enhetens ägare har stängt av dinosauriespelet.</translation>
<translation id="3447884698081792621">Visa certifikat (utfärdat av <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Öppna sidan i ett nytt inkognitofönster (Ctrl-Skift-N)</translation>
<translation id="3679803492151881375">Kraschrapporten skapades den <ph name="CRASH_TIME" /> och laddades upp den <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Certifikatinformation</translation>
-<translation id="3690164694835360974">Osäker inloggning</translation>
<translation id="3704162925118123524">Nätverket du använder kanske kräver att du besöker dess inloggningssida.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Läser in...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Använd global standardinställning (Upptäck)</translation>
<translation id="4165986682804962316">Platsinställningar</translation>
-<translation id="4169947484918424451">Vill du att Chromium sparar det här kortet?</translation>
<translation id="4171400957073367226">Felaktig verifieringssignatur</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> objekt till}other{<ph name="ITEM_COUNT" /> objekt till}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Starta om enheten</translation>
<translation id="4277028893293644418">Återställ lösenord</translation>
<translation id="4280429058323657511">, utgångsdatum <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Byt</translation>
<translation id="4312866146174492540">Blockera (standard)</translation>
<translation id="4325863107915753736">Det gick inte att hitta artikeln</translation>
<translation id="4326324639298822553">Kontrollera utgångsdatum och försök igen</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Den här datorn har inte identifierats som företagshanterad, så bara tillägg på Chrome Web Store kan installeras automatiskt med principen. Uppdateringsadressen på Chrome Web Store är <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Godkända kreditkort</translation>
<translation id="4356973930735388585">Det kan hända att angripare på den här webbplatsen försöker installera skadliga program på datorn som stjäl eller raderar dina uppgifter (t.ex. foton, lösenord, meddelanden och kreditkort).</translation>
+<translation id="4358461427845829800">Hantera betalningsmetoder …</translation>
<translation id="4372948949327679948">Ett <ph name="VALUE_TYPE" />-värde förväntades.</translation>
<translation id="4377125064752653719">Du försökte öppna <ph name="DOMAIN" />, men servern visade ett certifikat som har återkallats av utfärdaren. Det innebär att säkerhetsuppgifterna som servern visar inte är absolut tillförlitliga. Du kanske kommunicerar med en skadlig server.</translation>
<translation id="4406896451731180161">sökresultat</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Hämtningsadress</translation>
<translation id="4424024547088906515">Servern kunde inte bevisa att den är <ph name="DOMAIN" /> eftersom Chrome inte litar på dess säkerhetscertifikat. Detta kan orsakas av en felaktig konfigurering eller att någon spärrar anslutningen.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> godkände inte inloggningscertifikatet eller så har inget inloggningscertifikat angetts.</translation>
+<translation id="4434045419905280838">Popup-fönster och omdirigeringar</translation>
<translation id="443673843213245140">Användning av proxy är inaktiverad men en explicit proxykonfiguration har angetts.</translation>
<translation id="445100540951337728">Godkända betalkort</translation>
<translation id="4506176782989081258">Valideringsfel: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Autofyll för betalning har inaktiverats</translation>
<translation id="4764776831041365478">Webbsidan på <ph name="URL" /> kan ligga nere för tillfället eller kan ha flyttats permanent till en ny webbadress.</translation>
<translation id="4771973620359291008">Ett okänt fel uppstod.</translation>
+<translation id="4785689107224900852">Byt till den här fliken</translation>
<translation id="4792143361752574037">Det gick inte att få åtkomst till sessionsfilerna. Det går för närvarande inte att spara till enheten. Läs in sidan igen och gör ett nytt försök.</translation>
<translation id="4800132727771399293">Kontrollera utgångsdatum och CVC-kod och försök igen</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Du kan inte besöka <ph name="SITE" /> just nu eftersom webbplatsen skickade krypterade användaruppgifter som Chromium inte kan bearbeta. Nätverksfel och attacker är ofta tillfälliga, så sidan fungerar förmodligen senare.</translation>
<translation id="4813512666221746211">Nätverksfel</translation>
<translation id="4816492930507672669">Anpassa till sida</translation>
-<translation id="483020001682031208">Det finns inga Physical Web-sidor att visa</translation>
<translation id="4850886885716139402">Visa</translation>
<translation id="4854362297993841467">Det här leveranssättet är inte tillgängligt. Testa ett annat alternativ.</translation>
<translation id="4858792381671956233">Du har frågat dina föräldrar om lov att besöka den här webbplatsen.</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bitar)</translation>
<translation id="5121084798328133320">När du bekräftar delas kortuppgifter från Google Payments-konto med webbplatsen.</translation>
<translation id="5128122789703661928">Sessionen med det här namnet går inte att radera.</translation>
+<translation id="5135404736266831032">Hantera adresser …</translation>
<translation id="5141240743006678641">Kryptera synkroniserade lösenord med dina inloggningsuppgifter för Google</translation>
<translation id="5145883236150621069">Felkoden ingår i policysvaret</translation>
<translation id="5159010409087891077">Öppna sidan i ett nytt inkognitofönster (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">På en inbäddad sida på den här sidan står det</translation>
<translation id="5205222826937269299">Namn måste anges</translation>
<translation id="5222812217790122047">E-postadress måste anges</translation>
-<translation id="522700295135997067">Webbplatsen kan ha stulit ditt lösenord</translation>
<translation id="5230733896359313003">Leveransadress</translation>
<translation id="5250209940322997802">Anslut till ett nätverk</translation>
<translation id="5251803541071282808">Moln</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Webbplatsen på företagets, organisationens eller skolans intranät har samma webbadress som en extern webbplats.
<ph name="LINE_BREAK" />
Testa med att kontakta systemadministratören.</translation>
-<translation id="5499929369096410817">Ange säkerhetskoden för <ph name="CREDIT_CARD" />. Koden sparas inte.</translation>
<translation id="5509780412636533143">Hanterade bokmärken</translation>
<translation id="5510766032865166053">Den kan ha flyttats eller tagits bort.</translation>
<translation id="5523118979700054094">Policynamn</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Lägg till leveransadress</translation>
<translation id="5689199277474810259">Exportera som JSON</translation>
<translation id="5689516760719285838">Plats</translation>
+<translation id="570530837424789914">Hantera …</translation>
<translation id="5710435578057952990">Webbplatsens identitet har inte verifierats.</translation>
<translation id="5719499550583120431">Förbetalda kort kan användas.</translation>
<translation id="5720705177508910913">Aktuell användare</translation>
+<translation id="5730040223043577876">Du rekommenderas att återställa lösenordet om du har återanvänt det på andra webbplatser.</translation>
<translation id="5732392974455271431">Dina föräldrar kan ta bort blockeringen</translation>
<translation id="5763042198335101085">Ange en giltig e-postadress</translation>
<translation id="5765072501007116331">Välj en adress för att visa leveranssätt och krav</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Skicka automatiskt viss <ph name="BEGIN_WHITEPAPER_LINK" />information om systemet och innehåll på sidan<ph name="END_WHITEPAPER_LINK" /> för att hjälpa Google att identifiera skadliga appar och webbplatser. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Redigera kontaktuppgifter</translation>
<translation id="5967867314010545767">Ta bort från historiken</translation>
-<translation id="5972020793760134803">Byta flik</translation>
<translation id="5975083100439434680">Zooma ut</translation>
-<translation id="597552863672748783">Bekräfta säkerhetskoden</translation>
<translation id="598637245381783098">Det gick inte att öppna betalningsappen</translation>
<translation id="5989320800837274978">Varken fasta proxyservrar eller en webbadress med PAC-skript har angetts.</translation>
<translation id="5990559369517809815">Förfrågningar till servern har blockerats av ett tillägg.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Sidan kan ha till syfte att försöka lura dig att installera programvara eller avslöja personliga uppgifter. <ph name="BEGIN_LINK" />Visa ändå<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Du kan inte besöka <ph name="SITE" /> just nu eftersom tekniken att fästa certifikat används på webbplatsen. Nätverksfel och attacker är ofta tillfälliga, så sidan kommer förmodligen att fungera senare.</translation>
<translation id="6059925163896151826">USB-enheter</translation>
+<translation id="6071091556643036997">Ogiltig policytyp.</translation>
<translation id="6080696365213338172">Du har visat innehåll med hjälp av ett certifikat från en administratör. Det innebär att data som du har angett på <ph name="DOMAIN" /> även kan visas av administratören.</translation>
<translation id="610911394827799129">Det kan finnas andra former av webbhistorik i Google-kontot på <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Ingen}=1{1 lösenord (synkroniserat)}other{# lösenord (synkroniserade)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Lägg till mer information</translation>
<translation id="6447842834002726250">Cookies</translation>
<translation id="6451458296329894277">Bekräfta återsändning av formulär</translation>
+<translation id="6465306955648956876">Hantera lösenord …</translation>
<translation id="647261751007945333">Enhetspolicyer</translation>
<translation id="6477321094435799029">Chrome har identifierat ovanlig kod på sidan och blockerat den för att skydda dina personliga uppgifter (som lösenord, telefonnummer och kreditkortsuppgifter).</translation>
<translation id="6489534406876378309">Börja överföra information om krascher</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Sök</translation>
<translation id="6630809736994426279">Angripare på <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> kan försöka installera skadliga program som stjäl eller raderar information (t.ex. foton, lösenord, meddelanden och kreditkortsuppgifter) på din Mac. <ph name="BEGIN_LEARN_MORE_LINK" />Läs mer<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Policyn är föråldrad.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Ingen}=1{Från 1 webbplats (du loggas inte ut från Google-kontot)}other{Från # webbplatser (du loggas inte ut från Google-kontot)}}</translation>
<translation id="6657585470893396449">Lösenord</translation>
<translation id="6671697161687535275">Vill du ta bort formulärförslaget från Chromium?</translation>
<translation id="6685834062052613830">Logga ut och slutför konfigureringen</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Användare:</translation>
<translation id="6945221475159498467">Välj</translation>
<translation id="6948701128805548767">Välj en adress för att visa alternativ för utlämning och krav</translation>
+<translation id="6949872517221025916">Återställ lösenord</translation>
<translation id="6957887021205513506">Serverns certifikat verkar vara falskt.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Enhet</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Leveranssätt</translation>
<translation id="7139724024395191329">Emirat</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> till}other{<ph name="PAYMENT_METHOD_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> till}}</translation>
-<translation id="7155487117670177674">Osäker betalning</translation>
+<translation id="717330890047184534">Gaia-id:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> till}other{<ph name="SHIPPING_OPTION_PREVIEW" /> och <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> till}}</translation>
<translation id="7180611975245234373">Uppdatera</translation>
<translation id="7182878459783632708">Inga policyer har ställts in</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Använd global standardinställning (Blockera)</translation>
<translation id="7460163899615895653">De senaste flikarna från andra enheter visas här</translation>
<translation id="7469372306589899959">Kortet bekräftas</translation>
+<translation id="7473891865547856676">Nej tack</translation>
<translation id="7481312909269577407">Framåt</translation>
<translation id="7485870689360869515">Ingen data hittades.</translation>
<translation id="7508255263130623398">Enhets-id för returnerad princip är tomt eller matchar inte nuvarande enhets-id</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Vill du ta bort kreditkortet från Chrome?</translation>
<translation id="7575800019233204241">Anslutningen är inte privat eller &lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt; eller &lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt; eller &lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt; eller SSL-certifikatfel.</translation>
<translation id="7578104083680115302">Betala snabbt på webbplatser och i appar på olika enheter med kort som du har sparat hos Google.</translation>
-<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">Serverns certifikat strider mot namnrestriktionerna.</translation>
<translation id="7598391785903975535">Mindre än <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> kan för närvarande inte hantera förfrågan.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;Ångra Redigera</translation>
<translation id="9154194610265714752">Uppdaterat</translation>
<translation id="9157595877708044936">Konfigurerar...</translation>
+<translation id="9168814207360376865">Tillåt att webbplatser kontrollerar om du har sparade betalningsmetoder</translation>
<translation id="9169664750068251925">Blockera alltid den här webbplatsen</translation>
<translation id="9170848237812810038">&amp;Ångra</translation>
<translation id="917450738466192189">Servercertifikatet är ogiltigt.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Det gick inte att lägga till artikeln.</translation>
<translation id="9215416866750762878">Ett program förhindrar att Chrome ansluter till den här webbplatsen på ett säkert sätt</translation>
<translation id="9219103736887031265">Bilder</translation>
-<translation id="933612690413056017">Det finns ingen internetanslutning</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">RENSA FORMULÄRET</translation>
<translation id="939736085109172342">Ny mapp</translation>
diff --git a/chromium/components/strings/components_strings_sw.xtb b/chromium/components/strings/components_strings_sw.xtb
index 8b96d8e1c6b..bc7d123f7ac 100644
--- a/chromium/components/strings/components_strings_sw.xtb
+++ b/chromium/components/strings/components_strings_sw.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Chagua ruhusa ya <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Alamisho za hivi majuzi</translation>
<translation id="1113869188872983271">Tendua kupanga upya</translation>
+<translation id="1125573121925420732">Huenda onyo zikawa nyingi wakati tovuti zinasasisha usalama. Hali hii itaboreshwa hivi karibuni.</translation>
<translation id="1126551341858583091">Ukubwa kwenye nafasi ya hifadhi ya ndani ya kifaa ni <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Akiba ya sera ni SAWA</translation>
<translation id="1150979032973867961">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na mfumo wa uendeshaji wa kompyuta yako. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Hakikisha kuwa muunganisho wako wa intaneti unafanya kazi kama kawaida.&lt;/li&gt;
&lt;li&gt;Wasiliana na mmiliki wa tovuti.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Umeweka nenosiri kwenye tovuti ambayo haidhibitiwi na shirika lako. Ili ulinde akaunti yako, usitumie tena nenosiri lako kwenye tovuti na programu zingine.</translation>
<translation id="1263231323834454256">Orodha ya kusoma</translation>
<translation id="1264126396475825575">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> (haijapakiwa au imepuuzwa)</translation>
<translation id="1270502636509132238">Mbinu ya Kuchukua</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Chagua</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Zuia ukurasa huu usiunde vidadisi zaidi</translation>
-<translation id="1629803312968146339">Je, unataka Chrome ihifadhi kadi hii?</translation>
<translation id="1639239467298939599">Inapakia</translation>
<translation id="1640180200866533862">Sera za mtumiaji</translation>
<translation id="1640244768702815859">Jaribu <ph name="BEGIN_LINK" />kutembelea ukurasa wa kwanza wa tovuti<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Jaribu kutumia zana ya Kuchunguza Mtandao wa Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Tafadhali sasisha kaulisiri yako iliyolandanishwa.</translation>
<translation id="1787142507584202372">Vichupo vyako vilivyo wazi huonekana hapa</translation>
-<translation id="1789575671122666129">Ibukizi</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Jina la mwenye kadi</translation>
<translation id="1806541873155184440">Iliongezwa <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Zima na uwashe kompyuta yako</translation>
<translation id="2113977810652731515">Kadi</translation>
<translation id="2114841414352855701">Imepuuzwa kwa sababu ilifutwa na <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Inatafuta kurasa za Wavuti Kila Mahali zilizo karibu</translation>
<translation id="213826338245044447">Alamisho kwenye Simu</translation>
<translation id="214556005048008348">Ghairi malipo</translation>
<translation id="2147827593068025794">Usawazishaji wa Chini Chini</translation>
@@ -183,11 +182,12 @@
<translation id="2181821976797666341">Sera</translation>
<translation id="2183608646556468874">Nambari ya Simu</translation>
<translation id="2184405333245229118">{COUNT,plural, =1{Anwani 1}other{Anwani #}}</translation>
-<translation id="2187317261103489799">Gundua (chaguo msingi)</translation>
+<translation id="2187317261103489799">Gundua (chaguomsingi)</translation>
<translation id="2202020181578195191">Andika mwaka sahihi wa kuisha kwa muda wa matumizi</translation>
<translation id="2212735316055980242">Sera haikupatikana</translation>
<translation id="2213606439339815911">Inachukua viingizo...</translation>
<translation id="2218879909401188352">Wavamizi walio kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> hivi sasa, wanaweza kusakinisha programu hatari zinazoweza kukiharibu kifaa chako, kuongeza gharama fiche kwenye malipo yako ya simu, au kuiba maelezo yako ya binafsi. <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Hakuna intaneti</translation>
<translation id="2230458221926704099">Weka muunganisho wako kwa kutumia <ph name="BEGIN_LINK" />programu ya kuchunguza<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Tuma sasa</translation>
<translation id="225207911366869382">Thamani hii inapingwa kwa sera hii.</translation>
@@ -207,7 +207,7 @@
<translation id="2359808026110333948">Endelea</translation>
<translation id="2365563543831475020">Ripoti ya kuacha kufanya kazi iliyochukuliwa <ph name="CRASH_TIME" /> haikupakiwa</translation>
<translation id="2367567093518048410">Kiwango</translation>
-<translation id="2384307209577226199">Biashara chaguo msingi</translation>
+<translation id="2384307209577226199">Biashara chaguomsingi</translation>
<translation id="2386255080630008482">Cheti cha seva kimebatilishwa.</translation>
<translation id="2392959068659972793">Onyesha sera zisizowekwa thamani</translation>
<translation id="239429038616798445">Mbinu hii ya usafirishaji haipatikani. Jaribu mbinu tofauti.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Ondoa vipengee vilivyochaguliwa</translation>
<translation id="277133753123645258">Mbinu ya usafirishaji</translation>
<translation id="277499241957683684">Rekodi ya kifaa inayokosekana</translation>
+<translation id="2781030394888168909">Hamisha katika muundo wa MacOS</translation>
<translation id="2784949926578158345">Muunganisho uliwekwa upya.</translation>
<translation id="2788784517760473862">Kadi za malipo zinazokubaliwa</translation>
<translation id="2794233252405721443">Tovuti imezuiwa</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome haikuweza kuthibitisha kadi yako wakati huu. Tafadhali jaribu tena baadaye.</translation>
<translation id="3064966200440839136">Inaacha hali fiche ili kulipa kupitia programu ya nje. Je, ungependa kuendelea?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Hamna}=1{Nenosiri 1}other{Manenosiri #}}</translation>
-<translation id="3093245981617870298">Uko nje ya mtandao.</translation>
<translation id="3096100844101284527">Ongeza Anwani ya Mahali pa Kuchukulia Bidhaa</translation>
<translation id="3105172416063519923">Kitambulisho cha Kipengee:</translation>
<translation id="3109728660330352905">Huna idhini ya kuona ukurasa huu.</translation>
@@ -360,8 +360,9 @@
<translation id="3399952811970034796">Mahali Bidhaa Itapelekwa</translation>
<translation id="3422248202833853650">Jaribu kuondoka kwenye programu nyingine ili upate nafasi zaidi.</translation>
<translation id="3422472998109090673"><ph name="HOST_NAME" /> haiwezi kufikiwa kwa sasa.</translation>
-<translation id="3427092606871434483">Ruhusu (chaguo msingi)</translation>
+<translation id="3427092606871434483">Ruhusu (chaguomsingi)</translation>
<translation id="3427342743765426898">Rudia Kuhariri</translation>
+<translation id="342781501876943858">Chromium inapendekeza ubadilishe nenosiri lako ikiwa ulilitumia tena kwenye tovuti zingine.</translation>
<translation id="3431636764301398940">Hifadhi kadi hii kwenye kifaa hiki</translation>
<translation id="3447661539832366887">Mmiliki wa kifaa hiki amezima mchezo wa dinosau.</translation>
<translation id="3447884698081792621">Onyesha cheti (kilitolewa na <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Fungua ukurasa kwenye dirisha fiche jipya (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Ripoti ya kuacha kufanya kazi ilitolewa <ph name="CRASH_TIME" /> na kupakiwa <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Maelezo ya cheti</translation>
-<translation id="3690164694835360974">Kuingia katika akaunti si salama</translation>
<translation id="3704162925118123524">Mtandao unaotumia unaweza kukuhitaji kuutembelea ukurasa wake wa kuingia katika akaunti.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Inapakia...</translation>
@@ -456,9 +456,8 @@
<translation id="4130226655945681476">Kukagua kebo za mtandao, modemu au kisambaza data</translation>
<translation id="413544239732274901">Pata maelezo zaidi</translation>
<translation id="4148925816941278100">American Express</translation>
-<translation id="4151403195736952345">Tumia chaguo msingi la kimataifa (Gundua)</translation>
+<translation id="4151403195736952345">Tumia chaguomsingi la kimataifa (Gundua)</translation>
<translation id="4165986682804962316">Mipangilio ya tovuti</translation>
-<translation id="4169947484918424451">Je, unataka Chromium ihifadhi kadi hii?</translation>
<translation id="4171400957073367226">Sahihi mbaya ya uthibitishaji</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{Kipengee kingine <ph name="ITEM_COUNT" />}other{Vipengee vingine <ph name="ITEM_COUNT" />}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,13 +494,15 @@
<translation id="4275830172053184480">Washa upya kifaa chako</translation>
<translation id="4277028893293644418">Badilisha nenosiri</translation>
<translation id="4280429058323657511">, muda wa kutumika utakwisha <ph name="EXPIRATION_DATE_ABBR" /></translation>
-<translation id="4312866146174492540">Zuia (chaguo msingi)</translation>
+<translation id="4305817255990598646">Badilisha</translation>
+<translation id="4312866146174492540">Zuia (chaguomsingi)</translation>
<translation id="4325863107915753736">Haikupata makala</translation>
<translation id="4326324639298822553">Angalia tarehe kuisha kwa muda wa matumizi halafu ujajibu tena</translation>
<translation id="4331708818696583467">Si Salama</translation>
<translation id="4340982228985273705">Kompyuta hii haitambuliwi kama inayodhibitiwa na biashara. Kwa hivyo, sera inaweza tu kusakinisha viendelezi vinavyopangishwa kwenye Duka la Chrome kwenye Wavuti. URL ya kusasisha Duka la Chrome kwenye Wavuti ni "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Kadi za Mikopo Zinazokubaliwa</translation>
<translation id="4356973930735388585">Huenda wavamizi walio kwenye tovuti hii wakajaribu kusakinisha programu hatari inayoiba au kufuta maelezo yako yaliyo kwenye kompyuta yako (kwa mfano, picha, manenosiri, ujumbe, na kadi za mikopo).</translation>
+<translation id="4358461427845829800">Dhibiti njia za kulipa...</translation>
<translation id="4372948949327679948">Thamani <ph name="VALUE_TYPE" /> inayotarajiwa.</translation>
<translation id="4377125064752653719">Ulijaribu kufikia <ph name="DOMAIN" />, lakini cheti kilichowasilishwa na seva kimebatilishwa na mtoaji wacho. Huku ni kumaanisha kuwa stakabadhi za usalama zilizowasilishwa na seva hii hazifai kuaminiwa kabisa. Huenda ukawa unawasiliana na mshabulizi.</translation>
<translation id="4406896451731180161">matokeo ya utafutaji</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Anwani ya Mahali pa Kuchukulia Bidhaa</translation>
<translation id="4424024547088906515">Seva hii haikuweza kuthibitisha kuwa ni <ph name="DOMAIN" />; cheti chake cha usalama hakiaminiwi na Chrome. Hii inaweza kusababishwa na usanidi usiofaa au mvamizi kuingilia muunganisho wako.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> haikukubali cheti chako cha kuingia katika akaunti, au huenda hukutoa cheti.</translation>
+<translation id="4434045419905280838">Madirisha ibukizi/kuelekeza kwingine</translation>
<translation id="443673843213245140">Matumizi ya proksi yamelemazwa lakini usanidi wa proksi wazi umebainishwa.</translation>
<translation id="445100540951337728">Kadi za malipo zinazokubaliwa</translation>
<translation id="4506176782989081258">Hitilafu ya uthibitishaji: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Kujaza maelezo ya kadi ya mikopo kiotomatiki kumezimwa</translation>
<translation id="4764776831041365478">Ukurasa wa wavuti ulio <ph name="URL" /> unaweza kuwa haupatikani kwa muda au unaweza kuwa umehamishwa kabisa hadi anwani mpya ya wavuti.</translation>
<translation id="4771973620359291008">Hitilafu isiyojulikana imetokea.</translation>
+<translation id="4785689107224900852">Badili utumie kichupo hiki</translation>
<translation id="4792143361752574037">Hitilafu imetokea wakati wa kufikia faili za kipindi. Kuhifadhia kwenye diski kwa sasa kumezimwa. Tafadhali pakia ukurasa upya na ujaribu tena.</translation>
<translation id="4800132727771399293">Angalia tarehe yako ya kuisha muda na CVC na ujaribu tena</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti ilituma kitambulisho kilichoharibika ambacho Google Chrome haiwezi kushughulikia. Hitilafu na uvamizi wa mtandao kwa kawaida huwa vya muda, kwa hivyo ukurasa huu huenda ukafanya kazi baadaye.</translation>
<translation id="4813512666221746211">Hitilafu ya mtandao</translation>
<translation id="4816492930507672669">Sawazisha kwenye ukurasa</translation>
-<translation id="483020001682031208">Hakuna Kurasa za Wavuti kila Mahali za kuonyesha</translation>
<translation id="4850886885716139402">Mwonekano</translation>
<translation id="4854362297993841467">Njia hii ya kusafirisha haitumiki. Jaribu njia tofauti.</translation>
<translation id="4858792381671956233">Umewaomba wazazi wako ruhusa ya kuutembelea ukurasa huu.</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(biti 64)</translation>
<translation id="5121084798328133320">Baada ya kuthibitisha, maelezo ya kadi kutoka akaunti yako ya malipo ya Google yatashirikiwa na tovuti hii.</translation>
<translation id="5128122789703661928">Huruhusiwi kufuta kipindi kilicho na jina hili.</translation>
+<translation id="5135404736266831032">Dhibiti anwani...</translation>
<translation id="5141240743006678641">Simba kwa njia fiche manenosiri yaliyosawazishwa ukitumia stakabadhi zako za Google</translation>
<translation id="5145883236150621069">Msimbo wa hitilafu uko katika jibu la sera</translation>
<translation id="5159010409087891077">Fungua ukurasa kwenye dirisha fiche jipya (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Ukurasa uliopachikwa kwenye ukurasa huu unasema</translation>
<translation id="5205222826937269299">Jina linahitajika</translation>
<translation id="5222812217790122047">Anwani ya barua pepe inahitajika</translation>
-<translation id="522700295135997067">Huenda tovuti hii imeiba nenosiri lako</translation>
<translation id="5230733896359313003">Anwani ya Mahali Bidhaa Zitakapopelekwa</translation>
<translation id="5250209940322997802">"Unganisha kwenye mtandao"</translation>
<translation id="5251803541071282808">Wingu</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Tovuti hii kwenye intraneti ya kampuni, shirika au shule ina URL sawa na tovuti ya nje.
<ph name="LINE_BREAK" />
Jaribu kuwasiliana na msimamizi wa mfumo wako.</translation>
-<translation id="5499929369096410817">Weka msimbo wa usalama wa <ph name="CREDIT_CARD" />. Msimbo huu hautahifadhiwa.</translation>
<translation id="5509780412636533143">Alamisho zinazosimamiwa</translation>
<translation id="5510766032865166053">Huenda imehamishwa au imefutwa.</translation>
<translation id="5523118979700054094">Jina la sera</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Ongeza mahali zitakapopelekwa</translation>
<translation id="5689199277474810259">Tuma katika mfumo wa JSON</translation>
<translation id="5689516760719285838">Mahali</translation>
+<translation id="570530837424789914">Dhibiti...</translation>
<translation id="5710435578057952990">Utambulisho wa tovuti hii haujathibitishwa.</translation>
<translation id="5719499550583120431">Kadi za kulipia awali zinakubaliwa.</translation>
<translation id="5720705177508910913">Mtumiaji wa sasa</translation>
+<translation id="5730040223043577876">Chrome inapendekeza ubadilishe nenosiri lako ikiwa ulilitumia tena kwenye tovuti zingine.</translation>
<translation id="5732392974455271431">Wazazi wako wanaweza kukuondolea kizuizi</translation>
<translation id="5763042198335101085">Andika anwani sahihi ya barua pepe</translation>
<translation id="5765072501007116331">Chagua mahali ili uone njia za kusafirisha na mahitaji</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Tuma kiotomatiki <ph name="BEGIN_WHITEPAPER_LINK" />maelezo ya mfumo na maudhui kadha ya ukurasa<ph name="END_WHITEPAPER_LINK" /> kwa Google ili kusaidia kugundua programu na tovuti hatari. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Badilisha Maelezo ya Mawasiliano</translation>
<translation id="5967867314010545767">Ondoa kwenye historia</translation>
-<translation id="5972020793760134803">Nenda kwenye kichupo</translation>
<translation id="5975083100439434680">Fifiza</translation>
-<translation id="597552863672748783">Thibitisha nambari ya usalama</translation>
<translation id="598637245381783098">Imeshindwa kufungua programu ya kulipa</translation>
<translation id="5989320800837274978">Siyo seva proksi za kudumu wala URL ya hati ya .pac zimebainishwa.</translation>
<translation id="5990559369517809815">Maombi katika seva yamezuiwa kwa kiendelezi.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Maudhui haya yanaweza kukuhadaa kusakinisha programu au kuonyesha maelezo yako ya binafsi. <ph name="BEGIN_LINK" />Onyesha tu<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Huwezi kutembelea <ph name="SITE" /> sasa hivi kwa sababu tovuti hii inatumia ubandikaji cheti. Hitilafu na uvamizi wa mtandao kwa kawaida huwa vya muda, kwa hivyo ukurasa huu huenda utafanya kazi baadaye.</translation>
<translation id="6059925163896151826">Vifaa vya USB</translation>
+<translation id="6071091556643036997">Aina ya sera si sahihi.</translation>
<translation id="6080696365213338172">Umefikia maudhui kwa kutumia cheti kilichotolewa cha msimamizi. Data unayotoa katika <ph name="DOMAIN" /> inaweza kuzuiliwa na msimamizi wako.</translation>
<translation id="610911394827799129">Huenda Akaunti yako ya Google ina aina nyingine za historia ya kuvinjari katika <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />.</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Hamna}=1{Nenosiri 1 (limesawazishwa)}other{Manenosiri # (yamesawazishwa)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Ongeza maelezo zaidi</translation>
<translation id="6447842834002726250">Vidakuzi</translation>
<translation id="6451458296329894277">Thibitisha kuwa Fomu Iwasilishwe Tena</translation>
+<translation id="6465306955648956876">Dhibiti manenosiri...</translation>
<translation id="647261751007945333">Sera za kifaa</translation>
<translation id="6477321094435799029">Chrome imegundua nambari ya kuthibitisha isiyo ya kawaida kwenye ukurasa huu na ikaizuia ili kulinda maelezo ya binafsi (kwa mfano, manenosiri, nambari za simu na kadi za mikopo).</translation>
<translation id="6489534406876378309">Anza kupakia matukio ya kuacha kufanya kazi</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Utafutaji wa <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Wavamizi ambao sasa wako kwenye <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> huenda wakajaribu kusakinisha programu hatari kwenye Mac yako ambazo zinaiba au kufuta maelezo yako (kwa mfano, picha, manenosiri, ujumbe na kadi za mikopo). <ph name="BEGIN_LEARN_MORE_LINK" />Pata maelezo zaidi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Sera hii imepingwa.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Hamna}=1{Kutoka tovuti 1 (hutaondolewa kwenye Akaunti ya Google)}other{Kutoka tovuti # (hutaondolewa kwenye Akaunti ya Google)}}</translation>
<translation id="6657585470893396449">Nenosiri</translation>
<translation id="6671697161687535275">Je, ungependa kuondoa pendekezo la fomu kwenye Chromium?</translation>
<translation id="6685834062052613830">Ondoka na ukamilishe kuweka mipangilio</translation>
@@ -795,7 +799,7 @@
<translation id="6753269504797312559">Thamani ya sera</translation>
<translation id="6757797048963528358">Kifaa chako kiko katika hali tuli.</translation>
<translation id="6778737459546443941">Mzazi wako bado hajaiidhinisha</translation>
-<translation id="679355240208270552">Imepuuzwa kwa sababu utafutaji chaguo msingi umezimwa na sera.</translation>
+<translation id="679355240208270552">Imepuuzwa kwa sababu utafutaji chaguomsingi umezimwa na sera.</translation>
<translation id="681021252041861472">Sehemu Hii Sharti Ijazwe</translation>
<translation id="6810899417690483278">Kitambulisho cha kubadilisha ili kukufaa</translation>
<translation id="6820686453637990663">CVC</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Mtumiaji:</translation>
<translation id="6945221475159498467">Chagua</translation>
<translation id="6948701128805548767">Chagua anwani ili uone mbinu za kuchukua na mahitaji</translation>
+<translation id="6949872517221025916">Weka Nenosiri Jipya</translation>
<translation id="6957887021205513506">Cheti cha seva kinaonekana kuwa ghushi.</translation>
<translation id="6965382102122355670">Sawa</translation>
<translation id="6965978654500191972">Kifaa</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Njia ya kusafirisha</translation>
<translation id="7139724024395191329">Emirate</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Malipo si salama</translation>
+<translation id="717330890047184534">Kitambulisho cha Gaia</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> na nyingine <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Onyesha upya</translation>
<translation id="7182878459783632708">Hakuna sera zilizowekwa</translation>
@@ -878,9 +883,10 @@
<translation id="7444046173054089907">Tovuti hii imezuiwa</translation>
<translation id="7445762425076701745">Utambulisho wa seva ambayo umejiunga kwayo hauwezi kuhalalishwa kikamilifu. Umeunganishwa kwenye seva kwa kutumia jina ambalo ni halali tu katika mtandao wako, ambalo mamlaka ya cheti cha nje hayana njia ya kuhalalisha umiliki wake. Kama baadhi ya mamlaka ya cheti yatatoa vyeti vya majina haya bila kujali, hakuna njia ya kuhakikisha umeunganishwa kwenye tovuti inayohitajika na sio mshambulizi.</translation>
<translation id="7451311239929941790"><ph name="BEGIN_LINK" />Pata maelezo zaidi<ph name="END_LINK" /> kuhusu hitilafu hii.</translation>
-<translation id="7455133967321480974">Tumia chaguo msingi la duniani (Zuia)</translation>
+<translation id="7455133967321480974">Tumia chaguomsingi la duniani (Zuia)</translation>
<translation id="7460163899615895653">Vichupo vyako vya hivi majuzi kutoka kwenye vifaa vingine vitaonekana hapa</translation>
<translation id="7469372306589899959">Inathibitisha kadi</translation>
+<translation id="7473891865547856676">La Asante</translation>
<translation id="7481312909269577407">Mbele</translation>
<translation id="7485870689360869515">Hakuna data iliyopatikana.</translation>
<translation id="7508255263130623398">Kitambulisho cha sera ya kifaa kilichorejeshwa hakina kitu au hakilingani na kitambulisho cha kifaa kilichopo</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Ungependa kuondoa kadi ya malipo kutoka kwenye Chrome?</translation>
<translation id="7575800019233204241">"Muunganisho wako si wa faragha" au "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" au "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" au "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" au "hitilafu ya cheti cha SSL"</translation>
<translation id="7578104083680115302">Lipa haraka kwenye tovuti na programu katika vifaa vyote ukitumia kadi ulizohifadhi kwenye Google.</translation>
-<translation id="7588950540487816470">Wavuti Kila Mahali</translation>
<translation id="7592362899630581445">Cheti cha seva kinakiuka vikwazo vya jina.</translation>
<translation id="7598391785903975535">Chini ya MB <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> haiwezi kushughulikia ombi hili kwa sasa.</translation>
@@ -968,9 +973,9 @@
<translation id="8012647001091218357">Hatukuweza kuwafikia wazazi wako wakati huu. Tafadhali jaribu tena.</translation>
<translation id="8025119109950072390">Wavamizi kwenye tovuti hii wanaweza kukulaghai ili ufanye kitu hatari kama vile kusakinisha programu au kuonyesha maelezo yako binafsi (kwa mfano, manenosiri, nambari za simu au kadi za mikopo).</translation>
<translation id="8034522405403831421">Ukurasa huu ni wa lugha ya <ph name="SOURCE_LANGUAGE" />. Je, ungependa kuutasfiri kuwa <ph name="TARGET_LANGUAGE" />?</translation>
-<translation id="8037357227543935929">Uliza (chaguo msingi)</translation>
+<translation id="8037357227543935929">Uliza (chaguomsingi)</translation>
<translation id="8041089156583427627">Tuma Maoni</translation>
-<translation id="8041940743680923270">Tumia chaguo msingi la duniani (Uliza)</translation>
+<translation id="8041940743680923270">Tumia chaguomsingi la duniani (Uliza)</translation>
<translation id="8042918947222776840">Chagua Mbinu ya Kuchukua Bidhaa</translation>
<translation id="8057711352706143257">Haikuweka mipangilio ya "<ph name="SOFTWARE_NAME" />" kwa njia sahihi. Kwa kawaida, kuondoa "<ph name="SOFTWARE_NAME" />" hurekebisha tatizo hili. <ph name="FURTHER_EXPLANATION" /></translation>
<translation id="8079031581361219619">Ungependa kupakia upya tovuti?</translation>
@@ -983,7 +988,7 @@
<translation id="8131740175452115882">Thibitisha</translation>
<translation id="8149426793427495338">Kompyuta yako iko katika hali tuli.</translation>
<translation id="8150722005171944719">Faili katika <ph name="URL" /> haisomeki. Huenda imeondolewa, kusogezwa, au idhini za faili huenda zinazuia ufikiaji.</translation>
-<translation id="8184538546369750125">Tumia chaguo msingi la duniani (Ruhusu)</translation>
+<translation id="8184538546369750125">Tumia chaguomsingi la duniani (Ruhusu)</translation>
<translation id="8191494405820426728">Kitambulisho cha Kuacha Kufanya Kazi <ph name="CRASH_LOCAL_ID" /></translation>
<translation id="8194797478851900357">Tendua hatua</translation>
<translation id="8201077131113104583">URL ya sasisho si sahihi kwa kiendelezi chenye Kitambulisho "<ph name="EXTENSION_ID" />".</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">Tendua kuhariri</translation>
<translation id="9154194610265714752">Imesasishwa</translation>
<translation id="9157595877708044936">Inasanidi...</translation>
+<translation id="9168814207360376865">Ruhusu tovuti zikague ikiwa umehifadhi njia ya kulipa</translation>
<translation id="9169664750068251925">Zuia kila wakati kwenye tovuti hii</translation>
<translation id="9170848237812810038">&amp;Tendua</translation>
<translation id="917450738466192189">Cheti cha seva ni batili.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Haikufaulu kuongeza makala.</translation>
<translation id="9215416866750762878">Programu kwenye kompyuta yako inazuia Chrome kuunganisha salama kwenye tovuti hii</translation>
<translation id="9219103736887031265">Picha</translation>
-<translation id="933612690413056017">Hakuna muunganisho wa Intaneti</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">FUTA FOMU</translation>
<translation id="939736085109172342">Folda mpya</translation>
diff --git a/chromium/components/strings/components_strings_ta.xtb b/chromium/components/strings/components_strings_ta.xtb
index 3092640687c..1d54d6e4ac8 100644
--- a/chromium/components/strings/components_strings_ta.xtb
+++ b/chromium/components/strings/components_strings_ta.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" />க்கான அனுமதியைத் தேர்ந்தெடுக்கவும்</translation>
<translation id="1111153019813902504">சமீபத்திய புத்தகக்குறிகள்</translation>
<translation id="1113869188872983271">&amp;மறுவரிசைப்படுத்தலைச் செயல்தவிர்</translation>
+<translation id="1125573121925420732">இணையதளங்கள் தங்கள் பாதுகாப்பைப் புதுப்பிக்கும் போது, எச்சரிக்கைகளைக் காண்பிப்பது வழக்கம் தான். இந்த நிலை விரைவில் மேம்படும்.</translation>
<translation id="1126551341858583091">அகச் சேமிப்பகத்தில் <ph name="CRASH_SIZE" /> அளவு உள்ளது.</translation>
<translation id="112840717907525620">கொள்கை தற்காலிக சேமிப்பு சரியாக உள்ளது</translation>
<translation id="1150979032973867961">இது <ph name="DOMAIN" /> தான் என்பதை இந்தச் சேவையகம் உறுதிப்படுத்தவில்லை; இதன் பாதுகாப்புச் சான்றிதழை உங்கள் கணினியின் இயக்க முறைமை நம்பவில்லை. இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;உங்கள் இணைய இணைப்பு வழக்கம் போல செயல்படுகிறதா என்பதைச் சரிபார்க்கவும்.&lt;/li&gt;
&lt;li&gt;இணையதள உரிமையாளரைத் தொடர்புகொள்ளவும்.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">உங்கள் நிறுவனம் நிர்வகிக்காத தளத்தில் உங்கள் கடவுச்சொல்லை உள்ளிட்டீர்கள். உங்கள் கணக்கைப் பாதுகாக்க, பிற பயன்பாடுகளிலும் தளங்களிலும் கடவுச்சொல்லை மீண்டும் பயன்படுத்த வேண்டாம்.</translation>
<translation id="1263231323834454256">வாசிப்புப் பட்டியல்</translation>
<translation id="1264126396475825575"><ph name="CRASH_TIME" /> அன்று சிதைவு அறிக்கை பெறப்பட்டது (இன்னும் பதிவேற்றப்படவில்லை அல்லது புறக்கணிக்கப்படவில்லை)</translation>
<translation id="1270502636509132238">பிக்அப் முறை</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">தேர்வுசெய்</translation>
<translation id="1620510694547887537">கேமரா</translation>
<translation id="1623104350909869708">கூடுதல் உரையாடல்களை உருவாக்குவதிலிருந்து இந்தப் பக்கத்தைத் தடு</translation>
-<translation id="1629803312968146339">இந்தக் கார்டை Chrome சேமிக்க வேண்டுமா?</translation>
<translation id="1639239467298939599">ஏற்றுகிறது</translation>
<translation id="1640180200866533862">பயனர் கொள்கைகள்</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />தளத்தின் முகப்புப் பக்கத்திற்குச் செல்லவும்<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows நெட்வொர்க் டயக்னஸ்டிக்ஸ் கருவியை இயக்கவும்<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">உங்களின் ஒத்திசை சொற்றொடரைப் புதுப்பிக்கவும்.</translation>
<translation id="1787142507584202372">உங்கள் தாவல்கள் இங்கே தோன்றும்</translation>
-<translation id="1789575671122666129">பாப் அப்கள்</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">கார்டு உரிமையாளரின் பெயர்</translation>
<translation id="1806541873155184440">சேர்த்தது: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">கணினியை மீண்டும் தொடங்கவும்</translation>
<translation id="2113977810652731515">கார்டு</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> ஆல் கொள்கை மேலெழுதப்பட்டுள்ளதால் புறக்கணிக்கப்பட்டது.</translation>
-<translation id="2138201775715568214">அருகிலுள்ள இயல்நிலை இணையப் பக்கங்களைத் தேடுகிறது</translation>
<translation id="213826338245044447">மொபைல் புக்மார்க்குகள்</translation>
<translation id="214556005048008348">பேமண்ட்டை ரத்துசெய்</translation>
<translation id="2147827593068025794">பின்புல ஒத்திசைவு</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">கொள்கை காணப்படவில்லை</translation>
<translation id="2213606439339815911">உள்ளீடுகளைப் பெறுகிறது...</translation>
<translation id="2218879909401188352">தற்போது <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> எனும் தளத்தில் உள்ள தீங்கிழைப்பவர்கள் உங்கள் சாதனத்தைச் சேதப்படுத்தும் ஆபத்தான பயன்பாடுகளை நிறுவலாம், மொபைல் கட்டணத்தில் மறைமுகக் கட்டணங்களைச் சேர்க்கலாம் அல்லது உங்கள் தனிப்பட்ட தகவலைத் திருடலாம். <ph name="BEGIN_LEARN_MORE_LINK" />மேலும் அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">இணைய இணைப்பு இல்லை</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />கண்டறியும் பயன்பாட்டைப்<ph name="END_LINK" /> பயன்படுத்தி இணைப்பைச் சரிசெய்யவும்</translation>
<translation id="2239100178324503013">இப்போதே அனுப்பு</translation>
<translation id="225207911366869382">இந்த கொள்கைக்கான மதிப்பு தடுக்கப்பட்டது.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">தேர்ந்தெடுத்த உருப்படிகளை அகற்றுக</translation>
<translation id="277133753123645258">ஷிப்பிங் முறை</translation>
<translation id="277499241957683684">சாதனப் பதிவு இல்லை</translation>
+<translation id="2781030394888168909">MacOS வடிவமைப்பில் பதிவிறக்கு</translation>
<translation id="2784949926578158345">இணைப்பு மீட்டமைக்கப்பட்டது.</translation>
<translation id="2788784517760473862">ஏற்கப்படும் கிரெடிட் கார்டுகள்</translation>
<translation id="2794233252405721443">தளம் தடுக்கப்பட்டது</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">இப்போது உங்கள் கார்டை உறுதிசெய்ய முடியவில்லை. பிறகு முயலவும்.</translation>
<translation id="3064966200440839136">வெளிப்புறப் பயன்பாட்டின் மூலம் பணத்தை செலுத்த, மறைநிலையிலிருந்து வெளியேறுகிறீர்கள். தொடரவா?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ஏதுமில்லை}=1{1 கடவுச்சொல்}other{# கடவுச்சொற்கள்}}</translation>
-<translation id="3093245981617870298">ஆஃப்லைனில் உள்ளீர்கள்.</translation>
<translation id="3096100844101284527">பிக்அப் முகவரியைச் சேர்</translation>
<translation id="3105172416063519923">பண்பு ஐடி:</translation>
<translation id="3109728660330352905">இந்தப் பக்கத்தைக் காண உங்களுக்கு அங்கீகாரம் அளிக்கப்படவில்லை.</translation>
@@ -359,6 +359,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" />ஐத் தற்போது அணுக முடியவில்லை.</translation>
<translation id="3427092606871434483">அனுமதி (இயல்பு)</translation>
<translation id="3427342743765426898">&amp;திருத்தலை மீண்டும் செய்</translation>
+<translation id="342781501876943858">பிற தளங்களில் உங்கள் கடவுச்சொல்லை மீண்டும் பயன்படுத்தினால், அதை மீட்டமைக்கும்படி Chromium பரிந்துரைக்கிறது.</translation>
<translation id="3431636764301398940">இந்தச் சாதனத்தில் கார்டைச் சேமி</translation>
<translation id="3447661539832366887">சாதனத்தின் உரிமையாளர் டைனோசர் கேமை முடக்கியுள்ளார்.</translation>
<translation id="3447884698081792621">சான்றிதழைக் காட்டு (வழங்கியது: <ph name="ISSUER" />)</translation>
@@ -395,7 +396,6 @@
<translation id="3678529606614285348">புதிய மறைநிலைச் சாளரத்தில் பக்கத்தைத் திறக்கவும் (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375"><ph name="CRASH_TIME" /> அன்று சிதைவு அறிக்கை பதிவுசெய்யப்பட்டு, <ph name="UPLOAD_TIME" /> அன்று பதிவேற்றப்பட்டது</translation>
<translation id="3681007416295224113">சான்றிதழ் தகவல்</translation>
-<translation id="3690164694835360974">உள்நுழைவது பாதுகாப்பானது அல்ல</translation>
<translation id="3704162925118123524">நீங்கள் பயன்படுத்திக் கொண்டிருக்கும் நெட்வொர்க், அதன் உள்நுழைவுப் பக்கத்தை நீங்கள் பார்க்க வேண்டலாம்.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">ஏற்றுகிறது…</translation>
@@ -455,7 +455,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">குளோபல் இயல்பைப் பயன்படுத்து (கண்டறிதல்)</translation>
<translation id="4165986682804962316">தள அமைப்புகள்</translation>
-<translation id="4169947484918424451">இந்தக் கார்டை Chromium சேமிக்க வேண்டுமா?</translation>
<translation id="4171400957073367226">தவறான சரிபார்ப்பு கையொப்பம்</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{மேலும் <ph name="ITEM_COUNT" /> உருப்படி}other{மேலும் <ph name="ITEM_COUNT" /> உருப்படிகள்}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -492,6 +491,7 @@
<translation id="4275830172053184480">உங்கள் சாதனத்தை மீண்டும் தொடங்கவும்</translation>
<translation id="4277028893293644418">கடவுச்சொல்லை மீட்டமை</translation>
<translation id="4280429058323657511">, காலாவதித் தேதி: <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">மாறு</translation>
<translation id="4312866146174492540">தடு (இயல்பு)</translation>
<translation id="4325863107915753736">கட்டுரையைக் கண்டறிய முடியவில்லை</translation>
<translation id="4326324639298822553">காலாவதித் தேதியைச் சரிபார்த்து, மீண்டும் முயலவும்</translation>
@@ -499,6 +499,7 @@
<translation id="4340982228985273705">இந்தக் கணினியானது நிறுவனத்தால் நிர்வகிக்கப்படுவதாகக் கண்டறியப்படவில்லை. எனவே, கொள்கையால் Chrome இணைய அங்காடியில் ஹோஸ்ட் செய்யப்படும் நீட்டிப்புகளை மட்டும் தானாக நிறுவ முடியும். "<ph name="CWS_UPDATE_URL" />" என்பது Chrome இணைய அங்காடிப் புதுப்பிப்பு URL ஆகும்.</translation>
<translation id="4346197816712207223">ஏற்கப்படும் கிரெடிட் கார்டுகள்</translation>
<translation id="4356973930735388585">இந்தத் தளத்தில் உள்ள தீங்கிழைப்பவர்கள், உங்கள் தகவலைத் (எடுத்துக்காட்டு: படங்கள், கடவுச்சொற்கள், செய்திகள் மற்றும் கிரெடிட் கார்டுகள்) திருடக்கூடிய அல்லது நீக்கக்கூடிய தீங்கிழைக்கும் நிரல்களை உங்கள் கணினியில் நிறுவ முயலலாம்.</translation>
+<translation id="4358461427845829800">கட்டண முறைகளை நிர்வகி...</translation>
<translation id="4372948949327679948">எதிர்பார்த்த <ph name="VALUE_TYPE" /> மதிப்பு.</translation>
<translation id="4377125064752653719"><ph name="DOMAIN" /> ஐ அடைய முயற்சி செய்தீர்கள். ஆனால் சேவையகம் வழங்கிய சான்றிதழானது அதன் வழங்குநரால் நிராகரிக்கப்பட்டது. அதாவது, சேவையகம் வழங்கிய பாதுகாப்பு நம்பிக்கைச்சான்றுகளை நிச்சயமாக எக்காரணத்தைக்கொண்டும் நம்பக்கூடாது. போலியான ஒன்றுடன் நீங்கள் தகவல் பரிமாற்றம் செய்துகொண்டிருக்கக்கூடும்.</translation>
<translation id="4406896451731180161">தேடல் முடிவுகள்</translation>
@@ -506,6 +507,7 @@
<translation id="4415426530740016218">பிக்அப் முகவரி</translation>
<translation id="4424024547088906515">இது <ph name="DOMAIN" /> தான் என்பதை இந்தச் சேவையகம் உறுதிப்படுத்தவில்லை; இதன் பாதுகாப்புச் சான்றிதழை Chrome நம்பவில்லை. இது தவறான உள்ளமைவால் ஏற்பட்டிருக்கலாம் அல்லது தீங்கிழைப்பவர் உங்கள் இணைப்பில் குறுக்கிட்டிருக்கலாம்.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> உங்கள் உள்நுழைவுச் சான்றிதழை ஏற்கவில்லை அல்லது சான்றிதழ் வழங்கப்படாமல் இருக்கக்கூடும்.</translation>
+<translation id="4434045419905280838">பாப் அப்கள் &amp; திசைதிருப்புதல்கள்</translation>
<translation id="443673843213245140">ப்ராக்ஸி பயன்பாடு முடக்கப்பட்டுள்ளது. ஆனால் வெளிப்படையான ப்ராக்ஸி உள்ளமைவு குறிப்பிடப்பட்டுள்ளது.</translation>
<translation id="445100540951337728">ஏற்கப்படும் டெபிட் கார்டுகள்</translation>
<translation id="4506176782989081258">சரிபார்ப்புப் பிழை: <ph name="VALIDATION_ERROR" /></translation>
@@ -540,13 +542,13 @@
<translation id="4759118997339041434">கட்டணத்தைத் தானாக நிரப்புவது முடக்கப்பட்டுள்ளது</translation>
<translation id="4764776831041365478"><ph name="URL" /> இல் உள்ள வலைப்பக்கமானது தற்காலிகமாக இயங்காமல் இருக்கலாம் அல்லது அது ஒரு புதிய வலை முகவரிக்கு நிரந்தரமாக நகர்த்தப்பட்டிருக்கலாம்.</translation>
<translation id="4771973620359291008">அறியப்படாத பிழை ஏற்பட்டுள்ளது.</translation>
+<translation id="4785689107224900852">இந்தத் தாவலுக்கு மாற்றும்</translation>
<translation id="4792143361752574037">அமர்வுக் கோப்புகளை அணுகும் போது சிக்கல் ஏற்பட்டது. வட்டில் சேமிப்பது தற்போது முடக்கப்பட்டுள்ளது. மீண்டும் முயல, பக்கத்தை மீண்டும் ஏற்றவும்.</translation>
<translation id="4800132727771399293">காலாவதியாகும் நேரத்தையும், CVCஐயும் சரிபார்த்து, மீண்டும் முயற்சிக்கவும்</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">இணையதளமானது Google Chrome ஆல் செயல்படுத்த முடியாத சிதைந்த நற்சான்றுகளை அனுப்பியுள்ளதால், நீங்கள் இப்போது <ph name="SITE" />க்குச் செல்ல முடியாது, பொதுவாக நெட்வொர்க் பிழைகளும் தாக்குதல்களும் தற்காலிகமானவையே, எனவே இந்தப் பக்கம் சிறிது நேரம் கழித்து செயல்படும்.</translation>
<translation id="4813512666221746211">பிணைய பிழை</translation>
<translation id="4816492930507672669">பக்கத்தில் பொருத்து</translation>
-<translation id="483020001682031208">காட்டுவதற்கு இயல்நிலை இணையப் பக்கங்கள் எதுவுமில்லை</translation>
<translation id="4850886885716139402">காட்சி</translation>
<translation id="4854362297993841467">இந்த டெலிவரி முறை இல்லை. வேறு முறையைப் பயன்படுத்திப் பார்க்கவும்.</translation>
<translation id="4858792381671956233">இந்தத் தளத்தைப் பார்வையிடலாமா என, நீங்கள் பெற்றோரிடம் கேட்டுள்ளீர்கள்</translation>
@@ -586,6 +588,7 @@
<translation id="5115563688576182185">(64-பிட்)</translation>
<translation id="5121084798328133320">உறுதிசெய்த பின்னர், உங்கள் Google Payments கணக்கிலிருக்கும் கார்டு விவரங்கள் இந்தத் தளத்துடன் பகிரப்படும்.</translation>
<translation id="5128122789703661928">இந்தப் பெயரைக் கொண்ட அமர்வானது நீக்குவதற்குத் தகுதியானதல்ல.</translation>
+<translation id="5135404736266831032">முகவரிகளை நிர்வகி...</translation>
<translation id="5141240743006678641">ஒத்திசைக்கப்பட்ட கடவுச்சொற்களை உங்கள் Google நற்சான்றுகள் மூலம் என்க்ரிப்ட் செய்யவும்</translation>
<translation id="5145883236150621069">கொள்கைப் பதிலில் பிழைக் குறியீடு உள்ளது</translation>
<translation id="5159010409087891077">புதிய மறைநிலைச் சாளரத்தில் பக்கத்தைத் திறக்கவும் (⇧⌘N)</translation>
@@ -597,7 +600,6 @@
<translation id="5201306358585911203">இந்தப் பக்கத்திலுள்ள உட்பொதிக்கப்பட்ட பக்கம் தெரிவிப்பது:</translation>
<translation id="5205222826937269299">பெயர் தேவை</translation>
<translation id="5222812217790122047">மின்னஞ்சல் தேவை</translation>
-<translation id="522700295135997067">உங்கள் கடவுச்சொல்லை இந்தத் தளம் திருடியிருக்கலாம்</translation>
<translation id="5230733896359313003">ஷிப்பிங் முகவரி</translation>
<translation id="5250209940322997802">"நெட்வொர்க்குடன் இணைக்கவும்"</translation>
<translation id="5251803541071282808">கிளவுடு</translation>
@@ -641,7 +643,6 @@
<translation id="5492298309214877701">நிறுவனம், அமைப்பு அல்லது பள்ளி அக இணையத்தில் உள்ள இந்தத் தளம் வெளிப்புற இணையதளம் ஒன்றின் அதே URLஐக் கொண்டிருக்கிறது.
<ph name="LINE_BREAK" />
உங்கள் முறைமை நிர்வாகியைத் தொடர்புகொள்ள முயலவும்.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> கிரெடிட் கார்டிற்கான பாதுகாப்புக் குறியீட்டை உள்ளிடவும். இந்தக் குறியீடு சேமிக்கப்படாது.</translation>
<translation id="5509780412636533143">நிர்வகிக்கப்படும் புக்மார்க்குகள்</translation>
<translation id="5510766032865166053">அது நகர்த்தப்பட்டிருக்கலாம் அல்லது நீக்கப்பட்டிருக்கலாம்.</translation>
<translation id="5523118979700054094">கொள்கைப் பெயர்</translation>
@@ -672,9 +673,11 @@
<translation id="5685654322157854305">ஷிப்பிங் முகவரியைச் சேர்</translation>
<translation id="5689199277474810259">JSONக்கு ஏற்று</translation>
<translation id="5689516760719285838">இருப்பிடம்</translation>
+<translation id="570530837424789914">நிர்வகி...</translation>
<translation id="5710435578057952990">இந்த தளத்தின் அடையாளம் சரிபார்க்கப்படவில்லை.</translation>
<translation id="5719499550583120431">ப்ரீபெய்டு கார்டுகள் ஏற்கப்படுகின்றன.</translation>
<translation id="5720705177508910913">நடப்புப் பயனர்</translation>
+<translation id="5730040223043577876">பிற தளங்களில் உங்கள் கடவுச்சொல்லை மீண்டும் பயன்படுத்தினால், அதை மீட்டமைக்கும்படி Chrome பரிந்துரைக்கிறது.</translation>
<translation id="5732392974455271431">உங்களுக்காக, தளத்தின் தடுப்பை உங்கள் பெற்றோர் நீக்க முடியும்</translation>
<translation id="5763042198335101085">சரியான மின்னஞ்சல் முகவரியை உள்ளிடவும்</translation>
<translation id="5765072501007116331">டெலிவரி முறைகளையும் தேவைகளையும் பார்க்க, முகவரியைத் தேர்ந்தெடுக்கவும்</translation>
@@ -698,9 +701,7 @@
<translation id="5959728338436674663">ஆபத்தான பயன்பாடுகளையும் தளங்களையும் கண்டறிவதற்கு உதவியாக, சில <ph name="BEGIN_WHITEPAPER_LINK" />சாதனத் தகவலையும் பக்க உள்ளடக்கத்தையும்<ph name="END_WHITEPAPER_LINK" /> Googleக்குத் தானாக அனுப்பு. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">தொடர்புத் தகவலைத் திருத்தவும்</translation>
<translation id="5967867314010545767">வரலாற்றிலிருந்து அகற்று</translation>
-<translation id="5972020793760134803">தாவலுக்கு மாறு</translation>
<translation id="5975083100439434680">சிறிதாக்கு</translation>
-<translation id="597552863672748783">பாதுகாப்புக் குறியீட்டை உறுதிப்படுத்தவும்</translation>
<translation id="598637245381783098">பேமெண்ட் பயன்பாட்டைத் திறக்க முடியவில்லை</translation>
<translation id="5989320800837274978">ப்ராக்ஸி சேவையகம் சரிசெய்யப்படவும் இல்லை .pac ஸ்கிரிப்ட் URL குறிப்பிடப்படவுமில்லை.</translation>
<translation id="5990559369517809815">சேவையகத்திற்கான கோரிக்கைகள் நீட்டிப்பினால் தடுக்கப்பட்டது.</translation>
@@ -716,6 +717,7 @@
<translation id="6047927260846328439">இந்த உள்ளடக்கம், உங்களை ஏமாற்றி மென்பொருளை நிறுவ வைக்கலாம் அல்லது தனிப்பட்ட தகவலை வெளிப்படுத்தச் செய்யலாம். <ph name="BEGIN_LINK" />பரவாயில்லை, காட்டு<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> தளமானது சர்டிஃபிகேட் பின்னிங்கைப் பயன்படுத்துவதால், தற்போது அதைப் பார்க்க முடியாது. பொதுவாக நெட்வொர்க் பிழைகளும் பாதிப்புகளும் தற்காலிகமானவை என்பதால், இந்தப் பக்கம் பின்னர் சரியாகச் செயல்படக்கூடும்.</translation>
<translation id="6059925163896151826">USB சாதனங்கள்</translation>
+<translation id="6071091556643036997">கொள்கை வகை செல்லுபடியாகவில்லை.</translation>
<translation id="6080696365213338172">நிர்வாகி வழங்கிய சான்றிதழைப் பயன்படுத்தி உள்ளடக்கத்தை அணுகியுள்ளீர்கள். <ph name="DOMAIN" /> க்கு நீங்கள் வழங்கிய தரவானது உங்கள் நிர்வாகியால் இடைமறிக்கப்படலாம்.</translation>
<translation id="610911394827799129"><ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> என்ற முகவரியில், உங்கள் Google கணக்கிற்கான பிற வகை உலாவல் வரலாறும் இருக்கக்கூடும்</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ஏதுமில்லை}=1{1 கடவுச்சொல் (ஒத்திசைத்தது)}other{# கடவுச்சொற்கள் (ஒத்திசைத்தவை)}}</translation>
@@ -762,6 +764,7 @@
<translation id="6446608382365791566">மேலும் தகவலைச் சேர்க்கவும்</translation>
<translation id="6447842834002726250">குக்கீகள்</translation>
<translation id="6451458296329894277">படிவ மறுசமர்ப்பிப்பை உறுதிசெய்க</translation>
+<translation id="6465306955648956876">கடவுச்சொற்களை நிர்வகி...</translation>
<translation id="647261751007945333">சாதனக் கொள்கைகள்</translation>
<translation id="6477321094435799029">இந்தப் பக்கத்தில் வழக்கத்திற்கு மாறான குறியீடு இருப்பதை Chrome கண்டறிந்துள்ளது, மேலும் உங்கள் தனிப்பட்ட தகவலை (எடுத்துக்காட்டு: கடவுச்சொற்கள், ஃபோன் எண்கள் மற்றும் கிரெடிட் கார்டுகள்) பாதுகாக்க அதைத் தடுத்துள்ளது.</translation>
<translation id="6489534406876378309">சிதைவுகளைப் பதிவேற்றுவதைத் தொடங்கு</translation>
@@ -781,6 +784,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> தேடல்</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> தளத்தில் தற்போதுள்ள ஹேக்கர்கள் உங்கள் தனிப்பட்ட தகவலை (எடுத்துக்காட்டாக, படங்கள், கடவுச்சொற்கள், செய்திகள் மற்றும் கிரெடிட் கார்டுகள்) திருடக்கூடிய அல்லது நீக்கக்கூடிய ஆபத்தான நிரல்களை உங்கள் Mac இல் நிறுவ முயற்சிக்கக்கூடும். <ph name="BEGIN_LEARN_MORE_LINK" />மேலும் அறிக<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">இந்தக் கொள்கை தவிர்க்கப்பட்டது.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{எதுவுமில்லை}=1{1 தளத்திலிருந்து (உங்கள் Google கணக்கிலிருந்து வெளியேறமாட்டீர்கள்)}other{# தளங்களிலிருந்து (உங்கள் Google கணக்கிலிருந்து வெளியேறமாட்டீர்கள்)}}</translation>
<translation id="6657585470893396449">கடவுச்சொல்</translation>
<translation id="6671697161687535275">Chromium இலிருந்து படிவப் பரிந்துரையை அகற்றவா?</translation>
<translation id="6685834062052613830">வெளியேறி, அமைப்பை முடிக்கவும்</translation>
@@ -807,6 +811,7 @@
<translation id="6915804003454593391">பயனர்:</translation>
<translation id="6945221475159498467">தேர்ந்தெடு</translation>
<translation id="6948701128805548767">பிக்அப் முறைகளையும் தேவைகளையும் பார்க்க, முகவரியைத் தேர்ந்தெடுக்கவும்</translation>
+<translation id="6949872517221025916">கடவுச்சொல்லை மீட்டமைக்கவும்</translation>
<translation id="6957887021205513506">சேவையகத்தின் சான்றிதழ் போலியானது போல் தெரிகிறது.</translation>
<translation id="6965382102122355670">சரி</translation>
<translation id="6965978654500191972">சாதனம்</translation>
@@ -828,7 +833,7 @@
<translation id="7138472120740807366">டெலிவரி முறை</translation>
<translation id="7139724024395191329">எமிரேட்</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">கட்டணம் செலுத்துவது பாதுகாப்பானது அல்ல</translation>
+<translation id="717330890047184534">Gaia ஐடி:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" />, மேலும் <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">புதுப்பி</translation>
<translation id="7182878459783632708">கொள்கைகள் அமைக்கப்படவில்லை</translation>
@@ -877,6 +882,7 @@
<translation id="7455133967321480974">முழுமையான இயல்புநிலையைப் பயன்படுத்து (தடு)</translation>
<translation id="7460163899615895653">பிற சாதனங்களிலிருக்கும் உங்கள் சமீபத்திய தாவல்கள் இங்கே தோன்றும்</translation>
<translation id="7469372306589899959">கார்டை உறுதிசெய்கிறது</translation>
+<translation id="7473891865547856676">வேண்டாம் நன்றி</translation>
<translation id="7481312909269577407">அடுத்த பக்கம்</translation>
<translation id="7485870689360869515">தரவு எதுவும் இல்லை.</translation>
<translation id="7508255263130623398">கிடைத்த பாலிசி சாதன ஐடி காலியாக உள்ளது அல்லது தற்போதைய சாதன ஐடியுடன் பொருந்தவில்லை</translation>
@@ -899,7 +905,6 @@
<translation id="7569952961197462199">Chrome இலிருந்து கிரெடிட் கார்டை அகற்றவா?</translation>
<translation id="7575800019233204241">"உங்கள் இணைப்பு தனிப்பட்டது அல்ல" அல்லது "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" அல்லது "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" அல்லது "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" அல்லது "SSL சான்றிதழ் பிழை"</translation>
<translation id="7578104083680115302">Google இல் நீங்கள் சேமித்துள்ள கார்டுகளைப் பயன்படுத்தி பல தளங்களிலும் பயன்பாடுகளிலும் உங்களுடைய சாதனங்களில் அனைத்திலும் விரைவாகப் பணம் செலுத்தலாம்.</translation>
-<translation id="7588950540487816470">இயல்நிலை இணையம்</translation>
<translation id="7592362899630581445">பெயர் கட்டுப்பாடுகளைச் சேவையகத்தின் சான்றிதழ் மீறுகிறது.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> அளவை விடக் குறைவாக உள்ளது</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ஆல் தற்போது இந்தக் கோரிக்கையைக் கையாள முடியவில்லை.</translation>
@@ -1103,6 +1108,7 @@
<translation id="9148507642005240123">&amp;திருத்தலைச் செயல்தவிர்</translation>
<translation id="9154194610265714752">புதுப்பிக்கப்பட்டது</translation>
<translation id="9157595877708044936">அமைக்கிறது...</translation>
+<translation id="9168814207360376865">சேமித்துள்ள உங்கள் கட்டண முறைகளைப் பார்க்க தளங்களை அனுமதிக்கவும்</translation>
<translation id="9169664750068251925">இந்தத் தளத்தில் எப்போதும் தடு</translation>
<translation id="9170848237812810038">&amp;செயல்தவிர்</translation>
<translation id="917450738466192189">சேவையகச் சான்றிதழ் செல்லுபடியானதல்ல.</translation>
@@ -1111,7 +1117,6 @@
<translation id="9207861905230894330">கட்டுரையைச் சேர்ப்பதில் தோல்வி.</translation>
<translation id="9215416866750762878">இந்தத் தளத்துடன் Chrome பாதுகாப்பாக இணைவதை, பயன்பாடு தடுக்கிறது</translation>
<translation id="9219103736887031265">படங்கள்</translation>
-<translation id="933612690413056017">இணைய இணைப்பு இல்லை</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">படிவத்தை அழி</translation>
<translation id="939736085109172342">புதிய கோப்புறை</translation>
diff --git a/chromium/components/strings/components_strings_te.xtb b/chromium/components/strings/components_strings_te.xtb
index 37204d8cb39..56150499e9b 100644
--- a/chromium/components/strings/components_strings_te.xtb
+++ b/chromium/components/strings/components_strings_te.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> కోసం అనుమతిని ఎంచుకోండి</translation>
<translation id="1111153019813902504">ఇటీవలి బుక్‌మార్క్‌లు</translation>
<translation id="1113869188872983271">&amp;మళ్లీ క్రమం చేయడాన్ని రద్దు చేయి</translation>
+<translation id="1125573121925420732">వెబ్‌సైట్‌ల యొక్క భద్రతను అప్‌డేట్ చేస్తున్నప్పుడు హెచ్చరికలు కనిపించడం సాధారణమే. ఇది త్వరలోనే మెరుగుపరచబడుతుంది.</translation>
<translation id="1126551341858583091">స్థానిక నిల్వలో పరిమాణం <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">విధాన కాష్ సరిపోయింది</translation>
<translation id="1150979032973867961">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రాన్ని మీ కంప్యూటర్ ఆపరేటింగ్ సిస్టమ్ విశ్వసించలేదు. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కి అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
@@ -30,7 +31,7 @@
<translation id="1165039591588034296">లోపం</translation>
<translation id="1173894706177603556">పేరుమార్చు</translation>
<translation id="1175364870820465910">&amp;ముద్రించు...</translation>
-<translation id="1181037720776840403">తొలగించు</translation>
+<translation id="1181037720776840403">తీసివేయి</translation>
<translation id="1184214524891303587">సంభావ్య భద్రతా సంఘటనల గురించిన వివరాలను Googleకి <ph name="BEGIN_WHITEPAPER_LINK" />స్వయంచాలకంగా నివేదిస్తుంది<ph name="END_WHITEPAPER_LINK" />. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="1201402288615127009">తదుపరి</translation>
<translation id="1201895884277373915">ఈ సైట్ నుండి మరింత</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;మీ ఇంటర్నెట్ కనెక్షన్ సరిగ్గానే పని చేస్తున్నట్లు నిర్ధారించుకోండి.&lt;/li&gt;
&lt;li&gt;వెబ్‌సైట్ యజమానిని సంప్రదించండి.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">మీ సంస్థ నిర్వహించని ఒక సైట్‌లో మీరు మీ పాస్‌వర్డ్‌ని నమోదు చేసారు. మీ ఖాతాని రక్షించడం కోసం, మీ పాస్‌వర్డ్‌ని ఇతర యాప్‌లు మరియు సైట్‌లలో తిరిగి ఉపయోగించవద్దు.</translation>
<translation id="1263231323834454256">పఠన జాబితా</translation>
<translation id="1264126396475825575">క్రాష్ నివేదిక <ph name="CRASH_TIME" />కి సంగ్రహించబడింది (ఇంకా అప్‌లోడ్ చేయలేదు లేదా విస్మరించబడింది)</translation>
<translation id="1270502636509132238">పికప్ పద్ధతి</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">ఎంచుకోండి</translation>
<translation id="1620510694547887537">కెమెరా</translation>
<translation id="1623104350909869708">ఈ పేజీని అదనపు డైలాగ్‌లు సృష్టించనీయకుండా నిరోధించు</translation>
-<translation id="1629803312968146339">Chrome ఈ కార్డ్‌ను సేవ్ చేయాలని మీరు కోరుకుంటున్నారా?</translation>
<translation id="1639239467298939599">లోడ్ అవుతోంది</translation>
<translation id="1640180200866533862">వినియోగదారు విధానాలు</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />సైట్ యొక్క హోమ్‌పేజీని సందర్శించడం<ph name="END_LINK" /> ప్రయత్నించండి.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows నెట్‌వర్క్ సమస్య విశ్లేషణలను అమలు చేయడం ప్రయత్నించండి<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">దయచేసి మీ సమకాలీకరణ పాస్‌ఫ్రేజ్‌ను నవీకరించండి.</translation>
<translation id="1787142507584202372">మీ తెరవబడిన ట్యాబ్‌లు ఇక్కడ కనిపిస్తాయి</translation>
-<translation id="1789575671122666129">పాప్అప్‌లు</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">కార్డుదారుని పేరు</translation>
<translation id="1806541873155184440">జోడించినది <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">మీ కంప్యూటర్‌ను పునఃప్రారంభించండి</translation>
<translation id="2113977810652731515">కార్డ్</translation>
<translation id="2114841414352855701">ఇది <ph name="POLICY_NAME" /> ద్వారా భర్తీ చేయబడినందున విస్మరించబడింది.</translation>
-<translation id="2138201775715568214">సమీప భౌతిక వెబ్ పేజీల కోసం శోధిస్తోంది</translation>
<translation id="213826338245044447">మొబైల్ బుక్‌మార్క్‌లు</translation>
<translation id="214556005048008348">చెల్లింపును రద్దు చేయి</translation>
<translation id="2147827593068025794">నేపథ్య సమకాలీకరణ</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">విధానం కనుగొనబడలేదు</translation>
<translation id="2213606439339815911">నమోదులను పొందుతోంది...</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />లోని హ్యాకర్‌లు మీ పరికరంలో హానికరమైన యాప్‌లను ఇన్‌స్టాల్ చేయవచ్చు మరియు మీ మొబైల్ బిల్‌లో అదృశ్య ఛార్జీలకు కారణం కావచ్చు లేదా మీ వ్యక్తిగత సమాచారాన్ని దొంగిలించవచ్చు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ఇంటర్నెట్ లేదు</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />విశ్లేషణల అనువర్తనాన్ని<ph name="END_LINK" /> ఉపయోగించి మీ కనెక్షన్‌ను సరి చేయండి</translation>
<translation id="2239100178324503013">ఇప్పుడే పంపండి</translation>
<translation id="225207911366869382">ఈ విధానం కోసం ఈ విలువ తగ్గించబడింది.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">ఎంచుకున్న అంశాలను తీసివేయండి</translation>
<translation id="277133753123645258">రవాణా పద్ధతి</translation>
<translation id="277499241957683684">పరికరం రికార్డ్ లేదు</translation>
+<translation id="2781030394888168909">MacOS ఫార్మాట్‌లో ఎగుమతి చేయి</translation>
<translation id="2784949926578158345">కనెక్షన్ మళ్ళీ సెట్ చెయ్యబడింది.</translation>
<translation id="2788784517760473862">ఆమోదించబడిన క్రెడిట్ కార్డ్‌లు</translation>
<translation id="2794233252405721443">సైట్ బ్లాక్ చేయబడింది</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome ప్రస్తుతం మీ కార్డ్‌ను నిర్ధారించలేకపోయింది. దయచేసి తర్వాత మళ్లీ ప్రయత్నించండి.</translation>
<translation id="3064966200440839136">బాహ్య అనువర్తనం ద్వారా చెల్లించడానికి అజ్ఞాత మోడ్ నుండి నిష్క్రమిస్తోంది. కొనసాగించాలా?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ఏమీ లేవు}=1{1 పాస్‌వర్డ్}other{# పాస్‌వర్డ్‌లు}}</translation>
-<translation id="3093245981617870298">మీరు ఆఫ్‌లైన్‌లో ఉన్నారు.</translation>
<translation id="3096100844101284527">పికప్ చిరునామాను జోడించండి</translation>
<translation id="3105172416063519923">అసెట్ ID:</translation>
<translation id="3109728660330352905">మీకు ఈ పేజీని వీక్షించడానికి అధికారం లేదు.</translation>
@@ -352,7 +352,7 @@
<ph name="END_LIST" /></translation>
<translation id="3369192424181595722">గడియారం లోపం</translation>
<translation id="337363190475750230">కేటాయింపు తీసివేయబడింది</translation>
-<translation id="3377188786107721145">విధాన అన్వయ లోపం</translation>
+<translation id="3377188786107721145">విధాన అన్వయ ఎర్రర్</translation>
<translation id="3380365263193509176">తెలియని లోపం</translation>
<translation id="3380864720620200369">క్లయింట్ ID:</translation>
<translation id="3391030046425686457">బట్వాడా చిరునామా</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" />ని ప్రస్తుతం చేరుకోవడం సాధ్యపడదు.</translation>
<translation id="3427092606871434483">అనుమతించు (డిఫాల్ట్)</translation>
<translation id="3427342743765426898">&amp;సవరించడాన్ని పునరావృతం చేయి</translation>
+<translation id="342781501876943858">మీరు మీ పాస్‌వర్డ్‌ని ఇతర సైట్‌లలో తిరిగి ఉపయోగించినట్లయితే దీనిని రీసెట్ చేయాల్సిందిగా Chromium సిఫార్సు చేస్తోంది.</translation>
<translation id="3431636764301398940">ఈ కార్డ్‌ను ఈ పరికరానికి సేవ్ చేయి</translation>
<translation id="3447661539832366887">ఈ పరికర యజమాని డైనోసార్ ఆటను ఆఫ్ చేసారు.</translation>
<translation id="3447884698081792621">సర్టిఫికేట్‌ని చూపు (<ph name="ISSUER" /> ద్వారా జారీ చేయబడింది)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">కొత్త అజ్ఞాత విండోలో పేజీని తెరవండి (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">క్రాష్ నివేదిక <ph name="CRASH_TIME" />కి సంగ్రహించబడింది, <ph name="UPLOAD_TIME" />కి అప్‌లోడ్ చేయబడింది</translation>
<translation id="3681007416295224113">సర్టిఫికెట్ సమాచారం</translation>
-<translation id="3690164694835360974">లాగిన్ సురక్షితం కాదు</translation>
<translation id="3704162925118123524">మీరు ఉపయోగించే నెట్‌వర్క్‌కి మీరు దాని లాగిన్ పేజీని సందర్శించడం అవసరం కావచ్చు.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">లోడ్ అవుతోంది...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">అమెరికన్ ఎక్స్‌ప్రెస్</translation>
<translation id="4151403195736952345">భౌగోళిక డిఫాల్ట్‌ను ఉపయోగించు (గుర్తించు)</translation>
<translation id="4165986682804962316">సైట్ సెట్టింగ్‌లు</translation>
-<translation id="4169947484918424451">Chromium ఈ కార్డ్‌ను సేవ్ చేయాలని మీరు కోరుకుంటున్నారా?</translation>
<translation id="4171400957073367226">ధృవీకరణ సంతకం చెల్లదు</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{మరో <ph name="ITEM_COUNT" /> అంశం}other{మరో <ph name="ITEM_COUNT" /> అంశాలు}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">మీ పరికరాన్ని పునఃప్రారంభించండి</translation>
<translation id="4277028893293644418">పాస్‌వర్డ్‌ను రీసెట్ చేయి</translation>
<translation id="4280429058323657511">, గడువు ముగింపు <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">స్విచ్</translation>
<translation id="4312866146174492540">బ్లాక్ చేయి (డిఫాల్ట్)</translation>
<translation id="4325863107915753736">కథనాన్ని కనుగొనడం విఫలమైంది</translation>
<translation id="4326324639298822553">మీ గడువు ముగింపు తేదీని తనిఖీ చేసి, ఆపై మళ్లీ ప్రయత్నించండి</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">ఈ కంప్యూటర్‌ని ఎంటర్‌ప్రైజ్ నిర్వహిస్తున్నట్లు గుర్తించబడలేదు, కనుక Chrome వెబ్‌స్టోర్‌లో హోస్ట్ చేయబడిన ఎక్స్‌టెన్షన్‌లను మాత్రమే విధానం ఆటోమేటిక్‌గా ఇన్‌స్టాల్ చేస్తుంది. Chrome వెబ్‌స్టోర్ అప్‌డేట్ URL "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">ఆమోదించే క్రెడిట్ కార్డ్‌లు</translation>
<translation id="4356973930735388585">ఈ సైట్‌లోని దాడి చేసేవారు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, సందేశాలు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించడం కోసం లేదా తొలగించడం కోసం మీ కంప్యూటర్‌లో ప్రమాదకరమైన ప్రోగ్రామ్‌లను ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు.</translation>
+<translation id="4358461427845829800">చెల్లింపు పద్ధతులను నిర్వహించండి...</translation>
<translation id="4372948949327679948">ఆశిస్తున్న <ph name="VALUE_TYPE" /> విలువ.</translation>
<translation id="4377125064752653719"><ph name="DOMAIN" />ను చేరుకోవడానికి మీరు ప్రయత్నించారు, కానీ సర్వర్ అందించిన ప్రమాణపత్రాన్ని దాన్ని జారీ చేసినవారు రద్దు చేసారు. సర్వర్ అందించిన భద్రత ఆధారాలు ఖచ్చితంగా విశ్వసించబడలేదని దీని అర్థం. మీరు దాడి చేసే వారితో కమ్యూనికేట్ చేస్తూ ఉండవచ్చు.</translation>
<translation id="4406896451731180161">శోధన ఫలితాలు</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">పికప్ చిరునామా</translation>
<translation id="4424024547088906515">ఈ సర్వర్ <ph name="DOMAIN" /> అని నిరూపించుకోలేకపోయింది; దీని భద్రతా ప్రమాణపత్రాన్ని Chrome విశ్వసించలేదు. ఇది తప్పుగా కాన్ఫిగర్ చేయడం వలన లేదా దాడిచేసే వ్యక్తి మీ కనెక్షన్‌కి అంతరాయం కలిగించడం వలన జరిగి ఉండవచ్చు.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> మీ లాగిన్ ప్రమాణపత్రాన్ని ఆమోదించలేదు లేదా ఏదీ అందించి ఉండకపోవచ్చు.</translation>
+<translation id="4434045419905280838">పాప్-అప్‌లు మరియు మళ్లింపులు</translation>
<translation id="443673843213245140">ప్రాక్సీని ఉపయోగించడం ఆపివేయబడింది కానీ స్పష్టమైన ప్రాక్సీ కాన్ఫిగరేషన్ పేర్కొనబడింది.</translation>
<translation id="445100540951337728">ఆమోదించబడిన డెబిట్ కార్డ్‌లు</translation>
<translation id="4506176782989081258">ధృవీకరణ లోపం: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">చెల్లింపు స్వీయపూరణ నిలిపివేయబడింది</translation>
<translation id="4764776831041365478"><ph name="URL" /> వద్ద వెబ్‌పేజీ తాత్కాలికంగా తెరుచుకోవటం లేదు లేదా అది క్రొత్త వెబ్ చిరునామాకు శాశ్వతంగా తరలించబడి ఉండవచ్చు.</translation>
<translation id="4771973620359291008">తెలియని లోపం ఒకటి ఏర్పడింది.</translation>
+<translation id="4785689107224900852">ఈ టాబ్‌కు మారండి</translation>
<translation id="4792143361752574037">సెషన్ ఫైల్‌లను యాక్సెస్ చేస్తున్నప్పుడు సమస్య ఏర్పడింది. ప్రస్తుతానికి డిస్క్‌లో సేవ్ చేయడం నిలిపివేయబడింది. దయచేసి మళ్లీ ప్రయత్నించడం కోసం పేజీని తిరిగి లోడ్ చేయండి.</translation>
<translation id="4800132727771399293">మీ గడువు ముగింపు తేదీ మరియు CVCని తనిఖీ చేసి, మళ్లీ ప్రయత్నించండి</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">వెబ్‌సైట్ Google Chrome ప్రాసెస్ చేయలేని, గజిబిజిగా ఉండే ఆధారాలను పంపినందున మీరు ప్రస్తుతం <ph name="SITE" />ని సందర్శించలేరు. నెట్‌వర్క్ లోపాలు మరియు దాడులు సాధారణంగా తాత్కాలికంగానే ఉంటాయి, కనుక ఈ పేజీ కాసేపటి తర్వాత పని చేసే అవకాశం ఉంది.</translation>
<translation id="4813512666221746211">నెట్‌వర్క్ లోపం</translation>
<translation id="4816492930507672669">పేజీకి తగినట్లు అమర్చు</translation>
-<translation id="483020001682031208">చూపడానికి సహజసిద్ధ వెబ్ పేజీలేవీ లేవు</translation>
<translation id="4850886885716139402">వీక్షణ</translation>
<translation id="4854362297993841467">ఈ బట్వాడా పద్ధతి అందుబాటులో లేదు. వేరే పద్ధతిని ప్రయత్నించండి.</translation>
<translation id="4858792381671956233">ఈ సైట్‌ను సందర్శించడానికి అనుమతించమని కోరుతూ మీ తల్లిదండ్రులకు అభ్యర్థన పంపారు</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-బిట్)</translation>
<translation id="5121084798328133320">మీరు నిర్ధారించిన తర్వాత, మీ Google చెల్లింపుల ఖాతా నుండి కార్డ్ వివరాలు ఈ సైట్‌తో షేర్ చేయబడతాయి.</translation>
<translation id="5128122789703661928">ఈ పేరు కలిగిన సెషన్‌ని తొలగించలేరు.</translation>
+<translation id="5135404736266831032">చిరునామాలను నిర్వహించండి...</translation>
<translation id="5141240743006678641">మీ Google ఆధారాలతో సమకాలీకరించబడిన పాస్‌వర్డ్‌లను గుప్తీకరించండి</translation>
<translation id="5145883236150621069">విధాన ప్రతిస్పందనలో లోపం కోడ్ ఉంది</translation>
<translation id="5159010409087891077">కొత్త అజ్ఞాత విండోలో పేజీని తెరవండి (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">ఈ పేజీలోని పొందుపరిచిన పేజీ ఇలా చెబుతోంది</translation>
<translation id="5205222826937269299">పేరు ఆవశ్యకం</translation>
<translation id="5222812217790122047">ఇమెయిల్ ఆవశ్యకం</translation>
-<translation id="522700295135997067">ఈ సైట్ ఇప్పుడే మీ పాస్‌వర్డ్‌ను దొంగిలించి ఉండటానికి ఆస్కారం ఉంది</translation>
<translation id="5230733896359313003">బట్వాడా చిరునామా</translation>
<translation id="5250209940322997802">"నెట్‌వర్క్‌కు కనెక్ట్ చేయండి"</translation>
<translation id="5251803541071282808">క్లౌడ్</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">కంపెనీ, సంస్థ లేదా పాఠశాల ఇంట్రానెట్‌లోని ఈ సైట్ బాహ్య వెబ్‌సైట్ కలిగి ఉన్న అదే URLని కలిగి ఉంది.
<ph name="LINE_BREAK" />
మీ సిస్టమ్ నిర్వాహకుడిని సంప్రదించడానికి ప్రయత్నించండి.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> యొక్క భద్రతా కోడ్‌ని నమోదు చేయండి. ఈ కోడ్ సేవ్ చేయబడదు.</translation>
<translation id="5509780412636533143">నిర్వహించబడిన బుక్‌మార్క్‌లు</translation>
<translation id="5510766032865166053">ఇది తరలించబడి ఉండవచ్చు లేదా తొలగించబడి ఉండవచ్చు.</translation>
<translation id="5523118979700054094">విధానం పేరు</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">షిప్పింగ్ చిరునామాను జోడించండి</translation>
<translation id="5689199277474810259">JSONకు ఎగుమతి చేయి</translation>
<translation id="5689516760719285838">స్థానం</translation>
+<translation id="570530837424789914">నిర్వహించండి...</translation>
<translation id="5710435578057952990">ఈ వెబ్‍‌సైట్ యొక్క గుర్తింపు నిర్థారించబడలేదు.</translation>
<translation id="5719499550583120431">ప్రీపెయిడ్ కార్డ్‌లు ఆమోదించబడతాయి.</translation>
<translation id="5720705177508910913">ప్రస్తుత వినియోగదారు</translation>
+<translation id="5730040223043577876">మీరు మీ పాస్‌వర్డ్‌ని ఇతర సైట్‌లలో తిరిగి ఉపయోగించినట్లయితే దీనిని రీసెట్ చేయాల్సిందిగా Chrome సిఫార్సు చేస్తోంది.</translation>
<translation id="5732392974455271431">మీ తల్లిదండ్రులు దీన్ని మీ కోసం అన్‌బ్లాక్ చేయగలరు</translation>
<translation id="5763042198335101085">చెల్లుబాటు అయ్యే ఇమెయిల్ చిరునామాని నమోదు చేయండి</translation>
<translation id="5765072501007116331">బట్వాడా పద్ధతులు మరియు అవసరాలను చూడాలంటే, చిరునామాని ఎంచుకోండి</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">హానికరమైన అనువర్తనాలు మరియు సైట్‌లను గుర్తించడంలో సహాయపడటానికి కొంత <ph name="BEGIN_WHITEPAPER_LINK" />సిస్టమ్ సమాచారాన్ని మరియు పేజీ కంటెంట్<ph name="END_WHITEPAPER_LINK" />ను Googleకు స్వయంచాలకంగా పంపుతుంది. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">సంప్రదింపు సమాచారాన్ని సవరించండి</translation>
<translation id="5967867314010545767">చరిత్ర నుండి తీసివేయి</translation>
-<translation id="5972020793760134803">ట్యాబ్‌కు మారండి</translation>
<translation id="5975083100439434680">దూరంగా జూమ్ చెయ్యి</translation>
-<translation id="597552863672748783">భద్రతా కోడ్‌ని నిర్ధారించండి</translation>
<translation id="598637245381783098">చెల్లింపు ఆప్‌ని తెరవడం సాధ్యం కాదు</translation>
<translation id="5989320800837274978">స్థిర ప్రాక్సీ సర్వర్‌లు లేదా ఒక .pac స్క్రిప్ట్ URL పేర్కొనబడలేదు.</translation>
<translation id="5990559369517809815">సర్వర్‌కు అభ్యర్థనలను ఒక పొడిగింపు బ్లాక్ చేయబడ్డాయి.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">ఈ కంటెంట్ సాఫ్ట్‌వేర్‌ని ఇన్‌స్టాల్ చేయడానికి లేదా వ్యక్తిగత సమాచారాన్ని బహిర్గతం చేయడానికి పురిగొల్పేలా మిమ్మల్ని మాయ చేయడానికి ప్రయత్నించవచ్చు. <ph name="BEGIN_LINK" />ఏదేమైనా చూపు<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">ప్రమాణపత్రాన్ని పిన్ చేసే పద్ధతిని వెబ్‌సైట్ ఉపయోగిస్తుంది కనుక మీరు ప్రస్తుతానికి <ph name="SITE" />ని సందర్శించలేరు. నెట్‌వర్క్ లోపాలు మరియు దాడులు సాధారణంగా తాత్కాలికమే, కనుక ఈ పేజీ తర్వాత పని చేయవచ్చు.</translation>
<translation id="6059925163896151826">USB పరికరాలు</translation>
+<translation id="6071091556643036997">విధాన రకం చెల్లదు.</translation>
<translation id="6080696365213338172">మీరు నిర్వాహకుని ద్వారా అందించబడిన ప్రమాణపత్రాన్ని ఉపయోగించి కంటెంట్‌ను ప్రాప్యత చేసారు. మీరు <ph name="DOMAIN" />కు అందించే డేటాకు మీ నిర్వాహకుని ద్వారా అంతరాయం ఏర్పడవచ్చు.</translation>
<translation id="610911394827799129">మీ Google ఖాతా <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" />లో ఇతర రూపాల్లో ఉన్న బ్రౌజింగ్ చరిత్రను కలిగి ఉండవచ్చు</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ఏమీ లేవు}=1{1 పాస్‌వర్డ్ (సమకాలీకరించబడింది)}other{# పాస్‌వర్డ్‌లు (సమకాలీకరించబడ్డాయి)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">మరింత సమాచారాన్ని జోడించండి</translation>
<translation id="6447842834002726250">కుక్కీలు</translation>
<translation id="6451458296329894277">ఫారమ్ పునఃసమర్పణను నిర్థారించండి</translation>
+<translation id="6465306955648956876">పాస్‌వర్డ్‌లను నిర్వహించండి...</translation>
<translation id="647261751007945333">పరికర విధానాలు</translation>
<translation id="6477321094435799029">Chrome ఈ పేజీలో అసాధారణ కోడ్‌ను గుర్తించింది మరియు మీ వ్యక్తిగత సమాచారం (ఉదాహరణకు, పాస్‌వర్డ్‌లు, ఫోన్ నంబర్‌లు మరియు క్రెడిట్ కార్డ్‌లు) రక్షించడానికి దాన్ని బ్లాక్ చేసింది.</translation>
<translation id="6489534406876378309">క్రాష్‌లను అప్‌లోడ్ చేయడాన్ని ప్రారంభించండి</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> శోధన</translation>
<translation id="6630809736994426279"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" />లో హ్యాకర్‌లు మీ సమాచారాన్ని (ఉదాహరణకు, ఫోటోలు, పాస్‌వర్డ్‌లు, సందేశాలు మరియు క్రెడిట్ కార్డ్‌లు) దొంగిలించగల లేదా తొలగించగల హానికరమైన ప్రోగ్రామ్‌లను మీ Macలో ఇన్‌స్టాల్ చేయడానికి ప్రయత్నించవచ్చు. <ph name="BEGIN_LEARN_MORE_LINK" />మరింత తెలుసుకోండి<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">ఈ విధానం విలువ తగ్గించబడింది.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{ఏమీ లేవు}=1{1 సైట్ నుండి (మీరు మీ Google ఖాతా నుండి సైన్ అవుట్ చేయబడరు)}other{# సైట్‌ల నుండి (మీరు మీ Google ఖాతా నుండి సైన్ అవుట్ చేయబడరు)}}</translation>
<translation id="6657585470893396449">పాస్‌వర్డ్</translation>
<translation id="6671697161687535275">Chromium నుండి ఫారమ్ సూచనను తీసివేయాలా?</translation>
<translation id="6685834062052613830">సైన్ అవుట్ చేసి, సెటప్‌ను పూర్తి చేయండి</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">వినియోగదారు:</translation>
<translation id="6945221475159498467">ఎంచుకోండి</translation>
<translation id="6948701128805548767">పికప్ పద్ధతులు మరియు అవసరాలను చూడాలంటే, చిరునామాని ఎంచుకోండి</translation>
+<translation id="6949872517221025916">పాస్‌వర్డ్‌ను రీసెట్ చేయండి</translation>
<translation id="6957887021205513506">సర్వర్ ధృవీకరణ పత్రం చెల్లదు.</translation>
<translation id="6965382102122355670">సరే</translation>
<translation id="6965978654500191972">పరికరం</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">బట్వాడా పద్ధతి</translation>
<translation id="7139724024395191329">ఎమిరేట్</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">చెల్లింపు సురక్షితం కాదు</translation>
+<translation id="717330890047184534">Gaia ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> మరియు మరో <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">రీఫ్రెష్ చేయి</translation>
<translation id="7182878459783632708">విధానాలను సెట్ చేయలేదు</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">సార్వజనీన డిఫాల్ట్‌ను ఉపయోగించు (బ్లాక్ చేయి)</translation>
<translation id="7460163899615895653">ఇతర పరికరాల్లో మీ ఇటీవలి ట్యాబ్‌లు ఇక్కడ కనిపిస్తాయి</translation>
<translation id="7469372306589899959">కార్డ్‌ని నిర్ధారిస్తోంది</translation>
+<translation id="7473891865547856676">వద్దు, ధన్యవాదాలు</translation>
<translation id="7481312909269577407">ఫార్వార్డ్</translation>
<translation id="7485870689360869515">డేటా కనుగొనబడలేదు.</translation>
<translation id="7508255263130623398">అందించబడిన విధాన పరికర id ఖాళీగా ఉంది లేదా ప్రస్తుత పరికర idకి సరిపోలలేదు</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Chrome నుండి క్రెడిట్ కార్డ్‌ను తీసివేయాలా?</translation>
<translation id="7575800019233204241">"మీ కనెక్షన్ ప్రైవేట్‌గా లేదు" లేదా "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" లేదా "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" లేదా "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" లేదా "SSL సర్టిఫికేట్ ఎర్రర్"</translation>
<translation id="7578104083680115302">మీరు Googleతో సేవ్ చేసిన కార్డ్‌లను ఉపయోగించి పరికరాల్లోని సైట్‌లు మరియు అనువర్తనాల్లో శీఘ్రంగా చెల్లించండి.</translation>
-<translation id="7588950540487816470">భౌతిక వెబ్</translation>
<translation id="7592362899630581445">సర్వర్ యొక్క ప్రమాణపత్రం పేరు పరిమితులను ఉల్లంఘిస్తోంది.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" /> కంటే తక్కువ</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ప్రస్తుతం ఈ అభ్యర్థనను నిర్వహించలేదు.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;సవరించడాన్ని రద్దు చేయి</translation>
<translation id="9154194610265714752">నవీకరించబడింది</translation>
<translation id="9157595877708044936">అమర్చుతోంది...</translation>
+<translation id="9168814207360376865">మీ వద్ద సేవ్ చేయబడిన చెల్లింపు పద్ధతులు ఉన్నాయో లేదో తనిఖీ చేయడానికి సైట్‌లను అనుమతించండి</translation>
<translation id="9169664750068251925">ఈ సైట్‌లో ఎల్లప్పుడూ బ్లాక్ చేయి</translation>
<translation id="9170848237812810038">&amp;అన్డు</translation>
<translation id="917450738466192189">సర్వర్ యొక్క ప్రమాణపత్రం చెల్లుబాటు కాదు.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">కథనాన్ని జోడించడంలో విఫలమైంది.</translation>
<translation id="9215416866750762878">ఒక అప్లికేషన్ కారణంగా Chrome ఈ సైట్‌కు సురక్షితంగా కనెక్ట్ కాలేకపోతోంది</translation>
<translation id="9219103736887031265">చిత్రాలు</translation>
-<translation id="933612690413056017">ఇంటర్నెట్ కనెక్షన్ లేదు</translation>
<translation id="933712198907837967">డైనర్స్ క్లబ్</translation>
<translation id="935608979562296692">ఫారమ్‌ను తీసివేయండి</translation>
<translation id="939736085109172342">క్రొత్త ఫోల్డర్</translation>
diff --git a/chromium/components/strings/components_strings_th.xtb b/chromium/components/strings/components_strings_th.xtb
index a4993beb0ca..98d64532eca 100644
--- a/chromium/components/strings/components_strings_th.xtb
+++ b/chromium/components/strings/components_strings_th.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">เลือกสิทธิ์สำหรับ<ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">บุ๊กมาร์กที่เพิ่งดู</translation>
<translation id="1113869188872983271">&amp;เลิกทำการจัดลำดับใหม่</translation>
+<translation id="1125573121925420732">คุณอาจเห็นคำเตือนอยู่บ่อยๆ ระหว่างที่เว็บไซต์อัปเดตความปลอดภัย เราจะปรับปรุงเร็วๆ นี้</translation>
<translation id="1126551341858583091">ขนาดบนพื้นที่เก็บข้อมูลในเครื่องคือ <ph name="CRASH_SIZE" /></translation>
<translation id="112840717907525620">แคชนโยบายใช้ได้</translation>
<translation id="1150979032973867961">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะระบบปฏิบัติการของคอมพิวเตอร์ของคุณไม่เชื่อถือใบรับรองความปลอดภัย โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;ตรวจสอบว่าการเชื่อมต่ออินเทอร์เน็ตใช้งานได้ปกติ&lt;/li&gt;
&lt;li&gt;ติดต่อเจ้าของเว็บไซต์&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">คุณป้อนรหัสผ่านในเว็บไซต์ที่องค์กรไม่ได้จัดการ เพื่อปกป้องบัญชี โปรดอย่าใช้รหัสผ่านซ้ำในแอปและเว็บไซต์อื่นๆ</translation>
<translation id="1263231323834454256">เรื่องรออ่าน</translation>
<translation id="1264126396475825575">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> (ยังไม่ได้อัปโหลดหรือละเว้น)</translation>
<translation id="1270502636509132238">วิธีการรับสินค้า</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">เลือก</translation>
<translation id="1620510694547887537">กล้องถ่ายรูป</translation>
<translation id="1623104350909869708">ป้องกันหน้าเว็บนี้จากการสร้างการโต้ตอบเพิ่มเติม</translation>
-<translation id="1629803312968146339">คุณต้องการให้ Chrome บันทึกบัตรนี้ไหม</translation>
<translation id="1639239467298939599">กำลังโหลด</translation>
<translation id="1640180200866533862">นโยบายผู้ใช้</translation>
<translation id="1640244768702815859">ลอง<ph name="BEGIN_LINK" />ไปที่หน้าแรกของเว็บไซต์<ph name="END_LINK" /></translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />ลองเรียกใช้การวินิจฉัยเครือข่ายของ Windows<ph name="END_LINK" /></translation>
<translation id="1783075131180517613">โปรดอัปเดตข้อความรหัสผ่านที่ซิงค์ของคุณ</translation>
<translation id="1787142507584202372">แท็บที่คุณเปิดไว้จะปรากฏที่นี่</translation>
-<translation id="1789575671122666129">ป๊อปอัป</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">ชื่อผู้ถือบัตร</translation>
<translation id="1806541873155184440">วันที่เพิ่ม <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">รีสตาร์ทคอมพิวเตอร์</translation>
<translation id="2113977810652731515">บัตร</translation>
<translation id="2114841414352855701">ไม่สนใจเพราะถูกแทนที่โดย <ph name="POLICY_NAME" /></translation>
-<translation id="2138201775715568214">กำลังมองหาหน้า Physical Web ที่อยู่ใกล้เคียง</translation>
<translation id="213826338245044447">บุ๊กมาร์กบนมือถือ</translation>
<translation id="214556005048008348">ยกเลิกการชำระเงิน</translation>
<translation id="2147827593068025794">การซิงค์ในแบ็กกราวด์</translation>
@@ -187,7 +186,8 @@
<translation id="2202020181578195191">ป้อนปีที่หมดอายุที่ถูกต้อง</translation>
<translation id="2212735316055980242">ไม่พบนโยบาย</translation>
<translation id="2213606439339815911">กำลังดึงรายการ...</translation>
-<translation id="2218879909401188352">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> สามารถติดตั้งแอปอันตรายที่ทำลายอุปกรณ์ของคุณ เพิ่มค่าใช้จ่ายแฝงในใบแจ้งยอดมือถือ หรือขโมยข้อมูลส่วนบุคคล <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2218879909401188352">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> สามารถติดตั้งแอปอันตรายที่ทำลายอุปกรณ์ของคุณ เพิ่มค่าใช้จ่ายแฝงในใบแจ้งยอดมือถือ หรือขโมยข้อมูลส่วนบุคคล <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">ไม่มีอินเทอร์เน็ต</translation>
<translation id="2230458221926704099">แก้ไขการเชื่อมต่อของคุณด้วย<ph name="BEGIN_LINK" />แอปการวินิจฉัย<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">ส่งเลย</translation>
<translation id="225207911366869382">เลิกใช้งานค่านี้กับนโยบายนี้</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">นำรายการที่เลือกออก </translation>
<translation id="277133753123645258">วิธีการจัดส่งสินค้า</translation>
<translation id="277499241957683684">ไม่มีอุปกรณ์บันทึก</translation>
+<translation id="2781030394888168909">ส่งออก MacOS</translation>
<translation id="2784949926578158345">การเชื่อมต่อได้รับการรีเซ็ตแล้ว</translation>
<translation id="2788784517760473862">บัตรเครดิตที่ยอมรับ</translation>
<translation id="2794233252405721443">เว็บไซต์ที่ถูกบล็อก</translation>
@@ -271,7 +272,7 @@
<translation id="2826760142808435982">การเชื่อมต่อถูกเข้ารหัสและรับรองความถูกต้องโดยใช้ <ph name="CIPHER" /> และใช้ <ph name="KX" /> เป็นกลไกการแลกเปลี่ยนคีย์</translation>
<translation id="2835170189407361413">ล้างฟอร์ม</translation>
<translation id="2851634818064021665">คุณต้องได้รับสิทธิ์เพื่อเข้าชมไซต์นี้</translation>
-<translation id="2856444702002559011">ผู้โจมตีอาจพยายามขโมยข้อมูลจาก <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ตัวอย่างเช่น รหัสผ่าน ข้อความ หรือบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2856444702002559011">ผู้โจมตีอาจพยายามขโมยข้อมูลจาก <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> (ตัวอย่างเช่น รหัสผ่าน ข้อความ หรือบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="2881276955470682203">บันทึกบัตรไหม</translation>
<translation id="2909946352844186028">ตรวจพบการเปลี่ยนแปลงเครือข่าย</translation>
<translation id="2916038427272391327">ปิดโปรแกรมอื่นๆ</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome ไม่สามารถยืนยันบัตรของคุณได้ในขณะนี้ โปรดลองอีกครั้งในภายหลัง</translation>
<translation id="3064966200440839136">ออกจากโหมดไม่ระบุตัวตนเพื่อชำระเงินผ่านแอปพลิเคชันภายนอก ดำเนินการต่อไหม</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{ไม่มี}=1{รหัสผ่าน 1 รายการ}other{รหัสผ่าน # รายการ}}</translation>
-<translation id="3093245981617870298">คุณออฟไลน์อยู่</translation>
<translation id="3096100844101284527">เพิ่มที่อยู่สำหรับรับสินค้า</translation>
<translation id="3105172416063519923">รหัสสินทรัพย์:</translation>
<translation id="3109728660330352905">คุณไม่มีสิทธิ์ดูหน้านี้</translation>
@@ -336,7 +336,7 @@
<translation id="3270847123878663523">&amp;เลิกทำการจัดลำดับใหม่</translation>
<translation id="3282497668470633863">เพิ่มชื่อบนบัตร</translation>
<translation id="3287510313208355388">ดาวน์โหลดเมื่อออนไลน์</translation>
-<translation id="3293642807462928945">เรียนรู้เพิ่มเติมเกี่ยวกับนโยบาย <ph name="POLICY_NAME" /></translation>
+<translation id="3293642807462928945">ดูข้อมูลเพิ่มเติมเกี่ยวกับนโยบาย <ph name="POLICY_NAME" /></translation>
<translation id="3303855915957856445">ไม่พบผลการค้นหา</translation>
<translation id="3305707030755673451">ข้อมูลของคุณได้รับการเข้ารหัสด้วยรหัสผ่านการซิงค์เมื่อวันที่ <ph name="TIME" /> โปรดป้อนรหัสผ่านเพื่อเริ่มซิงค์</translation>
<translation id="3320021301628644560">เพิ่มที่อยู่สำหรับการเรียกเก็บเงิน</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">ไม่สามารถเข้าถึง <ph name="HOST_NAME" /> ได้ในขณะนี้</translation>
<translation id="3427092606871434483">อนุญาต (ค่าเริ่มต้น)</translation>
<translation id="3427342743765426898">&amp;ทำซ้ำการแก้ไข</translation>
+<translation id="342781501876943858">Chromium ขอแนะนำให้รีเซ็ตรหัสผ่านหากคุณใช้รหัสผ่านนี้ซ้ำในเว็บไซต์อื่น</translation>
<translation id="3431636764301398940">บันทึกบัตรนี้ลงในอุปกรณ์นี้</translation>
<translation id="3447661539832366887">เจ้าของอุปกรณ์นี้ปิดเกมไดโนเสาร์</translation>
<translation id="3447884698081792621">แสดงใบรับรอง (ออกโดย <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">เปิดหน้าเว็บในหน้าต่างที่ไม่ระบุตัวตนใหม่ (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">รายงานข้อขัดข้องเมื่อ <ph name="CRASH_TIME" /> อัปโหลดเมื่อ <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">ข้อมูลในใบรับรอง</translation>
-<translation id="3690164694835360974">การเข้าสู่ระบบไม่ปลอดภัย</translation>
<translation id="3704162925118123524">เครือข่ายที่คุณใช้อาจต้องการให้คุณไปที่หน้าการเข้าสู่ระบบ</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">กำลังโหลด ...</translation>
@@ -410,7 +410,7 @@
<translation id="3736520371357197498">หากคุณเข้าใจความเสี่ยงต่อความปลอดภัย คุณสามารถ<ph name="BEGIN_LINK" />ไปยังไซต์ที่ไม่ปลอดภัยนี้<ph name="END_LINK" /> ก่อนจะมีการนำโปรแกรมอันตรายออก</translation>
<translation id="3739623965217189342">ลิงก์ที่คุณคัดลอกมา</translation>
<translation id="3744899669254331632">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจากเว็บไซต์ได้ส่งข้อมูลรับรองที่มีการแปลงข้อมูลซึ่ง Chromium ไม่สามารถดำเนินการได้ ข้อผิดพลาดของเครือข่ายและการโจมตีมักจะเกิดขึ้นชั่วคราว ดังนั้นหน้านี้อาจจะใช้งานได้ในภายหลัง</translation>
-<translation id="3748148204939282805">ผู้โจมตีที่อยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจหลอกล่อให้คุณทำบางสิ่งที่อันตราย เช่น การติดตั้งซอฟต์แวร์หรือเปิดเผยข้อมูลส่วนบุคคล (ตัวอย่างเช่น รหัสผ่าน หมายเลขโทรศัพท์ หรือบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="3748148204939282805">ผู้โจมตีที่อยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจหลอกล่อให้คุณทำบางสิ่งที่อันตราย เช่น การติดตั้งซอฟต์แวร์หรือเปิดเผยข้อมูลส่วนบุคคล (ตัวอย่างเช่น รหัสผ่าน หมายเลขโทรศัพท์ หรือบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="375403751935624634">การแปลล้มเหลวเนื่องจากข้อผิดพลาดของเซิร์ฟเวอร์</translation>
<translation id="3759461132968374835">คุณไม่ได้รายงานข้อขัดข้องเมื่อเร็วๆ นี้ ข้อขัดข้องที่เกิดขึ้นเมื่อปิดใช้งานการรายงานข้อขัดข้อง จะไม่ปรากฏที่นี่</translation>
<translation id="3765032636089507299">หน้า Google Safe Browsing อยู่ในระหว่างการปรับปรุง</translation>
@@ -454,11 +454,10 @@
<translation id="4117700440116928470">ขอบข่ายนโยบายไม่ได้รับการสนับสนุน</translation>
<translation id="4129401438321186435">{COUNT,plural, =1{อีก 1 รายการ}other{อีก # รายการ}}</translation>
<translation id="4130226655945681476">ตรวจสอบสายเครือข่าย โมเด็ม และเราเตอร์</translation>
-<translation id="413544239732274901">เรียนรู้เพิ่มเติม</translation>
+<translation id="413544239732274901">ดูข้อมูลเพิ่มเติม</translation>
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">ใช้ค่าเริ่มต้นส่วนกลาง (ตรวจหา)</translation>
<translation id="4165986682804962316">การตั้งค่าไซต์</translation>
-<translation id="4169947484918424451">คุณต้องการให้ Chromium บันทึกบัตรนี้ไหม</translation>
<translation id="4171400957073367226">ลายเซ็นยืนยันไม่ถูกต้อง</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{อีก <ph name="ITEM_COUNT" /> รายการ}other{อีก <ph name="ITEM_COUNT" /> รายการ}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -466,7 +465,7 @@
<translation id="4196861286325780578">&amp;ทำซ้ำการย้าย</translation>
<translation id="4203896806696719780"><ph name="BEGIN_LINK" />ตรวจสอบไฟร์วอลล์และการกำหนดค่าการป้องกันไวรัส<ph name="END_LINK" /></translation>
<translation id="4220128509585149162">การขัดข้อง</translation>
-<translation id="422022731706691852">ผู้โจมตีที่อยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามหลอกล่อให้คุณติดตั้งโปรแกรมที่ทำให้การท่องเว็บเป็นเรื่องอันตราย (ตัวอย่างเช่น การเปลี่ยนหน้าแรกหรือการแสดงโฆษณาเพิ่มเติมในไซต์ที่คุณเข้าชม) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="422022731706691852">ผู้โจมตีที่อยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามหลอกล่อให้คุณติดตั้งโปรแกรมที่ทำให้การท่องเว็บเป็นเรื่องอันตราย (ตัวอย่างเช่น การเปลี่ยนหน้าแรกหรือการแสดงโฆษณาเพิ่มเติมในไซต์ที่คุณเข้าชม) <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="4221630205957821124">&lt;h4&gt;ขั้นตอนที่ 1: ลงชื่อเข้าใช้พอร์ทัล&lt;/h4&gt;
&lt;p&gt;เครือข่าย Wi-Fi ในสถานที่หลายแห่งอย่างร้านกาแฟหรือสนามบินจำเป็นต้องให้คุณลงชื่อเข้าใช้ หากต้องการดูหน้าลงชื่อเข้าใช้ โปรดไปที่หน้าเว็บที่ใช้ &lt;code&gt;http://&lt;/code&gt;&lt;/p&gt;
&lt;ol&gt;
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">รีสตาร์ทอุปกรณ์ของคุณ</translation>
<translation id="4277028893293644418">รีเซ็ตรหัสผ่าน</translation>
<translation id="4280429058323657511">หมดอายุ <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">สลับ</translation>
<translation id="4312866146174492540">บล็อก (ค่าเริ่มต้น)</translation>
<translation id="4325863107915753736">การค้นหาบทความล้มเหลว</translation>
<translation id="4326324639298822553">ตรวจสอบวันหมดอายุแล้วลองอีกครั้ง</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">ไม่มีการตรวจพบว่าคอมพิวเตอร์เครื่องนี้ได้รับการจัดการโดยองค์กร ดังนั้นนโยบายจะติดตั้งเฉพาะส่วนขยายที่โฮสต์ใน Chrome เว็บสโตร์โดยอัตโนมัติ URL การอัปเดตของ Chrome เว็บสโตร์คือ "<ph name="CWS_UPDATE_URL" />"</translation>
<translation id="4346197816712207223">บัตรเครดิตที่ยอมรับ</translation>
<translation id="4356973930735388585">ผู้โจมตีในเว็บไซต์นี้อาจพยายามติดตั้งโปรแกรมอันตรายซึ่งจะขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ และบัตรเครดิต) ลงในคอมพิวเตอร์ของคุณ</translation>
+<translation id="4358461427845829800">จัดการวิธีการชำระเงิน...</translation>
<translation id="4372948949327679948">ค่า <ph name="VALUE_TYPE" /> ที่คาดไว้</translation>
<translation id="4377125064752653719">คุณพยายามเข้าถึง <ph name="DOMAIN" /> แต่ใบรับรองที่เซิร์ฟเวอร์แจ้งมาถูกเพิกถอนโดยผู้ออกใบรับรอง ซึ่งหมายความว่าข้อมูลรับรองด้านความปลอดภัยที่เซิร์ฟเวอร์แจ้งมานั้นไม่สามารถเชื่อถือได้ คุณอาจกำลังติดต่อกับคนที่คิดจะโจมตีคุณ</translation>
<translation id="4406896451731180161">ผลการค้นหา</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">ที่อยู่ในการรับ</translation>
<translation id="4424024547088906515">เซิร์ฟเวอร์นี้ไม่สามารถพิสูจน์ได้ว่าเป็น <ph name="DOMAIN" /> เพราะ Chrome ไม่เชื่อถือใบรับรองความปลอดภัย โดยอาจเกิดจากการกำหนดค่าผิดหรือผู้บุกรุกที่ขัดขวางการเชื่อมต่อของคุณ</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> ไม่ยอมรับใบรับรองการเข้าสู่ระบบหรือไม่ได้ให้ใบรับรองไว้</translation>
+<translation id="4434045419905280838">ป๊อปอัปและการเปลี่ยนเส้นทาง</translation>
<translation id="443673843213245140">การใช้พร็อกซีถูกปิดใช้งาน แต่มีการระบุการกำหนดค่าพร็อกซีอย่างชัดเจน</translation>
<translation id="445100540951337728">บัตรเดบิตที่ยอมรับ</translation>
<translation id="4506176782989081258">ข้อผิดพลาดในการตรวจสอบ: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">ปิดใช้การป้อนการชำระเงินอัตโนมัติแล้ว</translation>
<translation id="4764776831041365478">หน้าเว็บใน <ph name="URL" /> อาจหยุดให้บริการชั่วคราวหรืออาจถูกย้ายไปยังที่อยู่เว็บใหม่อย่างถาวร</translation>
<translation id="4771973620359291008">มีข้อผิดพลาดที่ไม่ทราบเกิดขึ้น</translation>
+<translation id="4785689107224900852">เปลี่ยนเป็นแท็บนี้</translation>
<translation id="4792143361752574037">เกิดปัญหาในการเข้าถึงไฟล์เซสชัน ขณะนี้ระบบปิดใช้การบันทึกลงในดิสก์ โปรดโหลดหน้าใหม่เพื่อลองอีกครั้ง</translation>
<translation id="4800132727771399293">ตรวจสอบวันหมดอายุและ CVC แล้วลองอีกครั้ง</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้ เนื่องจากเว็บไซต์ดังกล่าวส่งข้อมูลรับรองที่เข้ารหัส ซึ่ง Google Chrome ไม่สามารถประมวลผลได้ โดยปกติข้อผิดพลาดของเครือข่ายและการบุกรุกจะเกิดขึ้นเพียงชั่วคราว หน้านี้จึงอาจใช้งานได้ในภายหลัง</translation>
<translation id="4813512666221746211">ข้อผิดพลาดของเครือข่าย</translation>
<translation id="4816492930507672669">พอดีกับหน้า</translation>
-<translation id="483020001682031208">ไม่มีหน้า Physical Web ที่จะแสดง</translation>
<translation id="4850886885716139402">มุมมอง</translation>
<translation id="4854362297993841467">วิธีการนำส่งสินค้านี้ไม่พร้อมให้บริการ โปรดลองใช้วิธีการอื่น</translation>
<translation id="4858792381671956233">คุณถามผู้ปกครองแล้วว่าสามารถเข้าชมเว็บไซต์นี้ได้ไหม</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 บิต)</translation>
<translation id="5121084798328133320">เมื่อยืนยันแล้ว ระบบจะแชร์รายละเอียดของบัตรจากบัญชี Google Payments กับเว็บไซต์นี้</translation>
<translation id="5128122789703661928">ลบเซสชันที่ใช้ชื่อนี้ไม่ได้</translation>
+<translation id="5135404736266831032">จัดการที่อยู่...</translation>
<translation id="5141240743006678641">เข้ารหัสผ่านที่ซิงค์ด้วยข้อมูลรับรอง Google ของคุณ</translation>
<translation id="5145883236150621069">มีรหัสข้อผิดพลาดในการตอบกลับนโยบาย</translation>
<translation id="5159010409087891077">เปิดหน้าเว็บในหน้าต่างที่ไม่ระบุตัวตนใหม่ (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">หน้าที่ฝังไว้ในหน้าเว็บนี้บอกว่า</translation>
<translation id="5205222826937269299">ต้องระบุชื่อ</translation>
<translation id="5222812217790122047">ต้องระบุอีเมล</translation>
-<translation id="522700295135997067">ไซต์นี้อาจเพิ่งขโมยรหัสผ่านของคุณไป</translation>
<translation id="5230733896359313003">ที่อยู่ในการจัดส่ง</translation>
<translation id="5250209940322997802">"เชื่อมต่อกับเครือข่าย"</translation>
<translation id="5251803541071282808">ระบบคลาวด์</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">เว็บไซต์นี้บนอินทราเน็ตของบริษัท องค์กร หรือโรงเรียนมี URL เหมือนกับเว็บไซต์ภายนอก
<ph name="LINE_BREAK" />
โปรดลองติดต่อผู้ดูแลระบบของคุณ</translation>
-<translation id="5499929369096410817">ป้อนรหัสความปลอดภัยสำหรับ <ph name="CREDIT_CARD" /> ระบบจะไม่บันทึกรหัสนี้ไว้</translation>
<translation id="5509780412636533143">บุ๊กมาร์กที่มีการจัดการ</translation>
<translation id="5510766032865166053">ไฟล์อาจถูกย้ายหรือลบไปแล้ว</translation>
<translation id="5523118979700054094">ชื่อนโยบาย</translation>
@@ -668,16 +669,18 @@
<translation id="5617949217645503996"><ph name="HOST_NAME" /> เปลี่ยนเส้นทางของคุณบ่อยเกินไป</translation>
<translation id="5629630648637658800">ไม่สามารถโหลดการตั้งค่านโยบาย</translation>
<translation id="5631439013527180824">โทเค็นการจัดการอุปกรณ์ไม่ถูกต้อง</translation>
-<translation id="5633066919399395251">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามติดตั้งโปรแกรมอันตรายซึ่งจะขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ และบัตรเครดิต) ลงในคอมพิวเตอร์ของคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="5633066919399395251">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามติดตั้งโปรแกรมอันตรายซึ่งจะขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ และบัตรเครดิต) ลงในคอมพิวเตอร์ของคุณ <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="563324245173044180">บล็อกเนื้อหาที่หลอกลวงแล้ว</translation>
<translation id="5659593005791499971">อีเมล</translation>
<translation id="5675650730144413517">หน้านี้ใช้ไม่ได้</translation>
<translation id="5685654322157854305">เพิ่มที่อยู่สำหรับจัดส่ง</translation>
<translation id="5689199277474810259">ส่งออกไปยัง JSON</translation>
<translation id="5689516760719285838">ตำแหน่ง</translation>
+<translation id="570530837424789914">จัดการ...</translation>
<translation id="5710435578057952990">ข้อมูลประจำตัวของเว็บไซต์นี้ยังไม่ได้รับการยืนยัน</translation>
<translation id="5719499550583120431">รับบัตรเติมเงิน</translation>
<translation id="5720705177508910913">ผู้ใช้ปัจจุบัน</translation>
+<translation id="5730040223043577876">Chrome ขอแนะนำให้รีเซ็ตรหัสผ่านหากคุณใช้รหัสผ่านนี้ซ้ำในเว็บไซต์อื่น</translation>
<translation id="5732392974455271431">ผู้ปกครองสามารถเลิกบล็อกเว็บไซต์ให้คุณ</translation>
<translation id="5763042198335101085">ป้อนที่อยู่อีเมลที่ถูกต้อง</translation>
<translation id="5765072501007116331">หากต้องการดูวิธีการนำส่งสินค้าและข้อกำหนด โปรดเลือกที่อยู่</translation>
@@ -701,16 +704,14 @@
<translation id="5959728338436674663">ส่ง<ph name="BEGIN_WHITEPAPER_LINK" />ข้อมูลบางอย่างของระบบและเนื้อหาของหน้าเว็บ<ph name="END_WHITEPAPER_LINK" />ไปยัง Google เพื่อช่วยตรวจหาแอปและเว็บไซต์ที่เป็นอันตรายโดยอัตโนมัติ<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">แก้ไขข้อมูลติดต่อ</translation>
<translation id="5967867314010545767">ลบจากประวัติการเข้าชม</translation>
-<translation id="5972020793760134803">เปลี่ยนเป็นแท็บ</translation>
<translation id="5975083100439434680">ย่อ</translation>
-<translation id="597552863672748783">ยืนยันรหัสความปลอดภัย</translation>
<translation id="598637245381783098">ไม่สามารถเปิดแอปการชำระเงิน</translation>
<translation id="5989320800837274978">ไม่มีการระบุทั้งพร็อกซีเซิร์ฟเวอร์แบบคงที่หรือ URL สคริปต์ .pac</translation>
<translation id="5990559369517809815">คำขอไปยังเซิร์ฟเวอร์ถูกบล็อกโดยส่วนขยาย</translation>
<translation id="6008256403891681546">JCB</translation>
<translation id="6015796118275082299">ปี</translation>
<translation id="6016158022840135739">{COUNT,plural, =1{หน้า 1}other{หน้า #}}</translation>
-<translation id="6017850046339264347">ผู้โจมตี <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> สามารถติดตั้งแอปที่หลอกลวงซึ่งปลอมเป็นเนื้อหาอย่างอื่นหรือรวบรวมข้อมูลที่อาจนำไปใช้ติดตามคุณ <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="6017850046339264347">ผู้โจมตี <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> สามารถติดตั้งแอปที่หลอกลวงซึ่งปลอมเป็นเนื้อหาอย่างอื่นหรือรวบรวมข้อมูลที่อาจนำไปใช้ติดตามคุณ <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6025416945513303461"><ph name="TYPE_1" /> <ph name="TYPE_2" /> <ph name="TYPE_3" /> (ซิงค์แล้ว)</translation>
<translation id="6027201098523975773">ป้อนชื่อ</translation>
<translation id="6039846035001940113">หากยังคงพบปัญหา ให้ติดต่อเจ้าของเว็บไซต์</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">เนื้อหานี้อาจพยายามหลอกล่อให้คุณติดตั้งซอฟต์แวร์หรือเปิดเผยข้อมูลส่วนบุคคล <ph name="BEGIN_LINK" />แสดงเนื้อหา<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">คุณไม่สามารถไปที่ <ph name="SITE" /> ได้ในขณะนี้เนื่องจากเว็บไซต์ใช้การตรึงใบรับรอง โดยปกติข้อผิดพลาดของเครือข่ายและการโจมตีจะเกิดขึ้นเพียงชั่วคราว หน้านี้จึงอาจใช้งานได้ในภายหลัง</translation>
<translation id="6059925163896151826">อุปกรณ์ USB</translation>
+<translation id="6071091556643036997">ประเภทนโยบายไม่ถูกต้อง</translation>
<translation id="6080696365213338172">คุณเข้าถึงเนื้อหาโดยใช้ใบรับรองที่ผู้ดูแลระบบออกให้ ข้อมูลที่คุณให้กับ <ph name="DOMAIN" /> อาจถูกสกัดกั้นโดยผู้ดูแลระบบ</translation>
<translation id="610911394827799129">บัญชี Google อาจมีประวัติการท่องเว็บรูปแบบอื่นๆ ที่ <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{ไม่มี}=1{รหัสผ่าน (ที่ซิงค์) 1 รายการ}other{รหัสผ่าน (ที่ซิงค์) # รายการ}}</translation>
@@ -755,7 +757,7 @@
<translation id="6355080345576803305">การลบล้างเซสชันสาธารณะ</translation>
<translation id="6358450015545214790">นี่หมายถึงอะไร</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{อีก 1 คำแนะนำ}other{อีก # คำแนะนำ}}</translation>
-<translation id="6387754724289022810">เพื่อให้ชำระเงินได้เร็วขึ้นในครั้งถัดไป โปรดบันทึกบัตรและที่อยู่สำหรับการเรียกเก็บเงินไว้ในบัญชี Google และในอุปกรณ์เครื่องนี้</translation>
+<translation id="6387754724289022810">เพื่อความสะดวกในการชำระเงินในครั้งถัดไป โปรดบันทึกบัตรและที่อยู่สำหรับการเรียกเก็บเงินไว้ในบัญชี Google สำหรับอุปกรณฺ์นี้</translation>
<translation id="6397451950548600259">ซอฟต์แวร์ในคอมพิวเตอร์ของคุณทำให้ Chrome ไม่สามารถเชื่อมต่อกับเว็บอย่างปลอดภัย</translation>
<translation id="6404511346730675251">แก้ไขบุ๊กมาร์ก</translation>
<translation id="6410264514553301377">ป้อนวันหมดอายุและ CVC ของ <ph name="CREDIT_CARD" /></translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">เพิ่มข้อมูลเพิ่มเติม</translation>
<translation id="6447842834002726250">คุกกี้</translation>
<translation id="6451458296329894277">ยืนยันการส่งแบบฟอร์มอีกครั้ง</translation>
+<translation id="6465306955648956876">จัดการรหัสผ่าน...</translation>
<translation id="647261751007945333">นโยบายอุปกรณ์</translation>
<translation id="6477321094435799029">Chrome ได้ตรวจพบรหัสที่ผิดปกติบนหน้านี้และได้บล็อกรหัสดังกล่าวเพื่อปกป้องข้อมูลส่วนบุคคลของคุณ (เช่น รหัสผ่าน หมายเลขโทรศัพท์ และบัตรเครดิต)</translation>
<translation id="6489534406876378309">เริ่มอัปโหลดข้อขัดข้อง</translation>
@@ -783,8 +786,9 @@
<translation id="6624427990725312378">ข้อมูลติดต่อ</translation>
<translation id="6626291197371920147">เพิ่มหมายเลขบัตรที่ถูกต้อง</translation>
<translation id="6628463337424475685"><ph name="ENGINE" /> ค้นหา</translation>
-<translation id="6630809736994426279">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามติดตั้งโปรแกรมอันตรายลงในเครื่อง Mac ของคุณ เพื่อขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ และบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="6630809736994426279">ผู้โจมตีที่กำลังอยู่ใน <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> อาจพยายามติดตั้งโปรแกรมอันตรายลงในเครื่อง Mac ของคุณ เพื่อขโมยหรือลบข้อมูล (ตัวอย่างเช่น รูปภาพ รหัสผ่าน ข้อความ และบัตรเครดิต) <ph name="BEGIN_LEARN_MORE_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">นโยบายนี้ถูกยกเลิกแล้ว</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{ไม่มี}=1{จาก 1 เว็บไซต์ (คุณจะไม่ออกจากระบบบัญชี Google)}other{จาก # เว็บไซต์ (คุณจะไม่ออกจากระบบบัญชี Google)}}</translation>
<translation id="6657585470893396449">รหัสผ่าน</translation>
<translation id="6671697161687535275">ต้องการนำคำแนะนำสำหรับแบบฟอร์มออกจาก Chromium ใช่ไหม</translation>
<translation id="6685834062052613830">ออกจากระบบและตั้งค่าให้เสร็จสมบูรณ์</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">ผู้ใช้:</translation>
<translation id="6945221475159498467">เลือก</translation>
<translation id="6948701128805548767">หากต้องการดูวิธีการรับสินค้าและข้อกำหนด โปรดเลือกที่อยู่</translation>
+<translation id="6949872517221025916">รีเซ็ตรหัสผ่าน</translation>
<translation id="6957887021205513506">ใบรับรองของเซิร์ฟเวอร์น่าจะเป็นของปลอม</translation>
<translation id="6965382102122355670">ตกลง</translation>
<translation id="6965978654500191972">อุปกรณ์</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">วิธีการนำส่งสินค้า</translation>
<translation id="7139724024395191329">เอมิเรต</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> รายการ}other{<ph name="PAYMENT_METHOD_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> รายการ}}</translation>
-<translation id="7155487117670177674">การชำระเงินไม่ปลอดภัย</translation>
+<translation id="717330890047184534">รหัส GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> วิธี}other{<ph name="SHIPPING_OPTION_PREVIEW" /> และอีก <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> วิธี}}</translation>
<translation id="7180611975245234373">รีเฟรช</translation>
<translation id="7182878459783632708">ไม่ได้กำหนดนโยบายไว้</translation>
@@ -840,7 +845,7 @@
<translation id="7192203810768312527">เพิ่มพื้นที่ว่าง <ph name="SIZE" /> เว็บไซต์บางแห่งอาจโหลดช้าลงเมื่อคุณเข้าชมครั้งถัดไป</translation>
<translation id="719464814642662924">Visa</translation>
<translation id="7210863904660874423"><ph name="HOST_NAME" /> ไม่เป็นไปตามมาตรฐานความปลอดภัย</translation>
-<translation id="721197778055552897"><ph name="BEGIN_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LINK" /> เกี่ยวกับปัญหานี้</translation>
+<translation id="721197778055552897"><ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK" /> เกี่ยวกับปัญหานี้</translation>
<translation id="7219179957768738017">การเชื่อมต่อใช้ <ph name="SSL_VERSION" /></translation>
<translation id="7220786058474068424">กำลังดำเนินการ</translation>
<translation id="724691107663265825">ไซต์ที่จะเปิดมีมัลแวร์</translation>
@@ -877,10 +882,11 @@
<translation id="7441627299479586546">หัวเรื่องนโยบายไม่ถูกต้อง</translation>
<translation id="7444046173054089907">เว็บไซต์นี้ถูกบล็อก</translation>
<translation id="7445762425076701745">ไม่สามารถตรวจสอบความถูกต้องของข้อมูลประจำตัวของเซิร์ฟเวอร์ที่คุณเชื่อมต่ออยู่ได้ทั้งหมด คุณกำลังเชื่อมต่อกับเซิร์ฟเวอร์ที่ใช้ชื่อที่ใช้ได้เฉพาะในเครือข่ายของคุณ ซึ่งผู้ออกใบรับรองภายนอกไม่สามารถตรวจสอบการเป็นเจ้าของได้ เนื่องจากผู้ออกใบรับรองบางรายจะยังคงออกใบรับรองให้กับชื่อเหล่านี้อยู่ คุณจึงไม่มีทางมั่นใจได้ว่ากำลังเชื่อมต่อกับเว็บไซต์ที่คุณต้องการดูโดยไม่ใช่ผู้โจมตี</translation>
-<translation id="7451311239929941790"><ph name="BEGIN_LINK" />เรียนรู้เพิ่มเติม<ph name="END_LINK" />เกี่ยวกับปัญหานี้</translation>
+<translation id="7451311239929941790"><ph name="BEGIN_LINK" />ดูข้อมูลเพิ่มเติม<ph name="END_LINK" />เกี่ยวกับปัญหานี้</translation>
<translation id="7455133967321480974">ใช้ค่าเริ่มต้นสากล (บล็อก)</translation>
<translation id="7460163899615895653">แท็บล่าสุดจากอุปกรณ์อื่นๆ จะปรากฏที่นี่</translation>
<translation id="7469372306589899959">กำลังยืนยันบัตร</translation>
+<translation id="7473891865547856676">ไม่ ขอบคุณ</translation>
<translation id="7481312909269577407">ส่งต่อ</translation>
<translation id="7485870689360869515">ไม่พบข้อมูล</translation>
<translation id="7508255263130623398">รหัสอุปกรณ์นโยบายที่ส่งกลับว่างเปล่าหรือไม่ตรงกับรหัสอุปกรณ์ปัจจุบัน</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">นำบัตรเครดิตออกจาก Chrome ไหม</translation>
<translation id="7575800019233204241">"การเชื่อมต่อของคุณไม่เป็นส่วนตัว" หรือ "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" หรือ "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" หรือ "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" หรือ "ข้อผิดพลาดของใบรับรอง SSL"</translation>
<translation id="7578104083680115302">ชำระเงินบนเว็บไซต์และแอปในอุปกรณ์ต่างๆ ได้อย่างรวดเร็วด้วยบัตรที่คุณได้บันทึกไว้กับ Google</translation>
-<translation id="7588950540487816470">Physical Web</translation>
<translation id="7592362899630581445">ใบรับรองของเซิร์ฟเวอร์ละเมิดข้อกำหนดชื่อ</translation>
<translation id="7598391785903975535">ไม่ถึง <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> ไม่สามารถดำเนินการกับคำขอนี้ในขณะนี้</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;เลิกทำการแก้ไข</translation>
<translation id="9154194610265714752">อัปเดตแล้ว</translation>
<translation id="9157595877708044936">กำลังตั้งค่า...</translation>
+<translation id="9168814207360376865">อนุญาตให้เว็บไซต์ตรวจสอบว่าคุณได้บันทึกวิธีการชำระเงินไว้ไหม</translation>
<translation id="9169664750068251925">บล็อกบนไซต์นี้เสมอ</translation>
<translation id="9170848237812810038">เ&amp;ลิกทำ</translation>
<translation id="917450738466192189">ใบรับรองของเซิร์ฟเวอร์ไม่ถูกต้อง</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">การเพิ่มบทความล้มเหลว</translation>
<translation id="9215416866750762878">มีแอปพลิเคชันที่ห้ามไม่ให้ Chrome เชื่อมต่อกับไซต์นี้อย่างปลอดภัย</translation>
<translation id="9219103736887031265">ภาพ</translation>
-<translation id="933612690413056017">ไม่มีการเชื่อมต่ออินเทอร์เน็ต</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ล้างฟอร์ม</translation>
<translation id="939736085109172342">โฟลเดอร์ใหม่</translation>
diff --git a/chromium/components/strings/components_strings_tr.xtb b/chromium/components/strings/components_strings_tr.xtb
index 8618c521167..2fa60f4c785 100644
--- a/chromium/components/strings/components_strings_tr.xtb
+++ b/chromium/components/strings/components_strings_tr.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504"><ph name="PERMISSION_NAME" /> için izin seçin</translation>
<translation id="1111153019813902504">Son yer işaretleri</translation>
<translation id="1113869188872983271">Sıralama değişikliğini &amp;geri al</translation>
+<translation id="1125573121925420732">Web siteleri güvenliklerini güncellerken uyarılar yaygın olarak görülebilir. Yakında bu işlev iyileştirilecektir.</translation>
<translation id="1126551341858583091">Yerel depolama alanındaki boyut <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Politika önbelleği uygun</translation>
<translation id="1150979032973867961">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Bilgisayarınızın işletim sistemi, sunucunun güvenlik sertifikasına güvenmiyor. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;İnternet bağlantınızın normal bir şekilde çalıştığından emin olun.&lt;/li&gt;
&lt;li&gt;Web sitesinin sahibiyle iletişim kurun.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Şifrenizi kuruluşunuz tarafından yönetilmeyen bir sitede girdiniz. Hesabınızı korumak için şifrenizi başka uygulama ve sitelerde tekrar kullanmayın.</translation>
<translation id="1263231323834454256">Okuma listesi</translation>
<translation id="1264126396475825575">Kilitlenme raporu yakalanma zamanı: <ph name="CRASH_TIME" /> (henüz yüklenmedi veya yoksayıldı)</translation>
<translation id="1270502636509132238">Alma Yöntemi</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Seç</translation>
<translation id="1620510694547887537">Kamera</translation>
<translation id="1623104350909869708">Bu sayfanın daha fazla iletişim kutusu oluşturmasını önle</translation>
-<translation id="1629803312968146339">Chrome'un bu kartı kaydetmesini istiyor musunuz?</translation>
<translation id="1639239467298939599">Yükleniyor</translation>
<translation id="1640180200866533862">Kullanıcı politikaları</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />Sitenin ana sayfasını ziyaret etmeyi deneyin<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Windows Ağ Teşhislerini çalıştırmayı deneyin<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Lütfen senkronizasyon parolanızı güncelleyin.</translation>
<translation id="1787142507584202372">Açık sekmeleriniz burada görünür</translation>
-<translation id="1789575671122666129">Pop-up'lar</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Kart Sahibinin Adı</translation>
<translation id="1806541873155184440">Eklenme tarihi: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Bilgisayarınızı yeniden başlatın</translation>
<translation id="2113977810652731515">Kart</translation>
<translation id="2114841414352855701"><ph name="POLICY_NAME" /> tarafından geçersiz kılındığı için yoksayıldı.</translation>
-<translation id="2138201775715568214">Yakınlardaki Fiziksel Web sayfaları aranıyor</translation>
<translation id="213826338245044447">Mobil Yer İşaretleri</translation>
<translation id="214556005048008348">Ödemeyi iptal et</translation>
<translation id="2147827593068025794">Arka Plan Senkronizasyonu</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Politika bulunamadı</translation>
<translation id="2213606439339815911">Girişler getiriliyor...</translation>
<translation id="2218879909401188352">Şu anda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> öğesini kullanan saldırganlar cihazınıza zarar verebilecek uygulamalar yükleyebilir, sizden habersiz mobil faturanıza ücretler ekleyebilir veya kişisel bilgilerinizi çalabilirler. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">İnternet bağlantısı yok</translation>
<translation id="2230458221926704099"><ph name="BEGIN_LINK" />Tanılama uygulamasını<ph name="END_LINK" /> kullanarak bağlantınızı düzeltin</translation>
<translation id="2239100178324503013">Şimdi gönder</translation>
<translation id="225207911366869382">Bu değer bu politika için kullanımdan kaldırıldı.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Seçilen öğeleri kaldır</translation>
<translation id="277133753123645258">Gönderim yöntemi</translation>
<translation id="277499241957683684">Eksik cihaz kaydı</translation>
+<translation id="2781030394888168909">MacOS Biçiminde Dışa Aktar</translation>
<translation id="2784949926578158345">Bağlantı sıfırlandı.</translation>
<translation id="2788784517760473862">Kabul edilen kredi kartları</translation>
<translation id="2794233252405721443">Site engellenmiş</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome şu anda kartınızı onaylayamıyor. Lütfen daha sonra tekrar deneyin.</translation>
<translation id="3064966200440839136">Harici bir uygulama üzerinden ödeme gerçekleştirmek için gizli moddan çıkılacak. Devam edilsin mi?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Yok}=1{1 şifre}other{# şifre}}</translation>
-<translation id="3093245981617870298">Çevrimdışısınız.</translation>
<translation id="3096100844101284527">Alınacağı Adres Ekle</translation>
<translation id="3105172416063519923">Öğe Kimliği:</translation>
<translation id="3109728660330352905">Bu sayfayı görüntüleme yetkiniz yok.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673"><ph name="HOST_NAME" /> ana makinesine şu anda ulaşılamıyor.</translation>
<translation id="3427092606871434483">İzin ver (varsayılan)</translation>
<translation id="3427342743765426898">&amp;Düzenlemeyi Yeniden Yap</translation>
+<translation id="342781501876943858">Chromium, şifrenizi başka sitelerde kullandıysanız sıfırlamanızı önerir.</translation>
<translation id="3431636764301398940">Bu kartı bu cihaza kaydet</translation>
<translation id="3447661539832366887">Bu cihazın sahibi dinozor oyununu kapattı.</translation>
<translation id="3447884698081792621">Sertifikayı göster (yayınlayan: <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Sayfayı yeni Gizli pencerede açın (Ctrl-Üst Karakter-N)</translation>
<translation id="3679803492151881375">Kilitlenme raporunun oluşturulma zamanı: <ph name="CRASH_TIME" />, raporun yüklenme zamanı: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Sertifika bilgileri</translation>
-<translation id="3690164694835360974">Giriş yapma işlemi güvenli değil</translation>
<translation id="3704162925118123524">Kullandığınız ağ bir giriş sayfasını ziyaret etmenizi gerektiriyor olabilir.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Yükleniyor...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Genel varsayılanı kullan (Algıla)</translation>
<translation id="4165986682804962316">Site ayarları</translation>
-<translation id="4169947484918424451">Chromium'un bu kartı kaydetmesini istiyor musunuz?</translation>
<translation id="4171400957073367226">Geçersiz doğrulama imzası</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> öğe daha}other{<ph name="ITEM_COUNT" /> öğe daha}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Cihazınızı yeniden başlatın</translation>
<translation id="4277028893293644418">Şifreyi sıfırla</translation>
<translation id="4280429058323657511">, son kullanma tarihi <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Anahtar</translation>
<translation id="4312866146174492540">Engelle (varsayılan)</translation>
<translation id="4325863107915753736">Makale bulunamadı</translation>
<translation id="4326324639298822553">Son kullanma tarihini kontrol edip tekrar deneyin</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Bu bilgisayarın kurumsal olarak yönetilmediği algılandığı için politika yalnızca Chrome Web Mağazası'nda barındırılan uzantıları otomatik olarak yükleyebilir. Chrome Web Mağazası'nın güncelleme URL'si "<ph name="CWS_UPDATE_URL" />" şeklindedir.</translation>
<translation id="4346197816712207223">Kabul Edilen Kredi Kartları</translation>
<translation id="4356973930735388585">Bu sitedeki saldırganlar, bilgilerinizi (örneğin fotoğraflar, şifreler, mesajlar ve kredi kartları) çalacak veya silecek tehlikeli programları bilgisayarınıza yüklemeyi deneyebilir.</translation>
+<translation id="4358461427845829800">Ödeme yöntemlerini yönet...</translation>
<translation id="4372948949327679948">Beklenen <ph name="VALUE_TYPE" /> değeri.</translation>
<translation id="4377125064752653719"><ph name="DOMAIN" /> adresine ulaşmayı denediniz, ancak sunucunun sağladığı sertifika, sertifikayı veren tarafından iptal edildi. Bu, sunucunun sağladığı güvenlik kimlik bilgilerine kesinlikle güvenilmemesi gerektiği anlamına gelir. Bir saldırganla irtibat kuruyor olabilirsiniz.</translation>
<translation id="4406896451731180161">arama sonuçları</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Alınacağı Adres</translation>
<translation id="4424024547088906515">Bu sunucu <ph name="DOMAIN" /> olduğunu kanıtlayamadı. Chrome, sunucunun güvenlik sertifikasına güvenmiyor. Bu durum, bir yanlış yapılandırmadan veya bağlantıya müdahale eden bir saldırgandan kaynaklanıyor olabilir.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> giriş sertifikanızı kabul etmedi veya giriş sertifikası sağlanmamış olabilir.</translation>
+<translation id="4434045419905280838">Pop-up'lar ve yönlendirmeler</translation>
<translation id="443673843213245140">Proxy kullanımı devre dışı, ancak açık bir proxy yapılandırması belirtildi.</translation>
<translation id="445100540951337728">Kabul edilen banka kartları</translation>
<translation id="4506176782989081258">Doğrulama hatası: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Ödeme bilgilerini otomatik doldurma devre dışı</translation>
<translation id="4764776831041365478"><ph name="URL" /> adresindeki web sayfası, geçici olarak kullanılamıyor veya kalıcı olarak yeni bir web adresine taşınmış olabilir.</translation>
<translation id="4771973620359291008">Bilinmeyen bir hata oluştu.</translation>
+<translation id="4785689107224900852">Bu sekmeye geç</translation>
<translation id="4792143361752574037">Oturum dosyalarına erişimle ilgili bir sorun oluştu. Diske kaydetme şu anda devre dışı bırakıldı. Tekrar denemek için lütfen sayfayı yeniden yükleyin.</translation>
<translation id="4800132727771399293">Son kullanma tarihinizi ve CVC'nizi kontrol edip tekrar deneyin</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102"><ph name="SITE" /> web sitesi Google Chrome'un işleyemediği karışık kimlik bilgileri gönderdiği için bu siteyi şu anda ziyaret edemezsiniz. Ağ hataları ve saldırılar genellikle geçici olduğundan bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="4813512666221746211">Ağ hatası</translation>
<translation id="4816492930507672669">Sayfaya sığdır</translation>
-<translation id="483020001682031208">Gösterilecek Fiziksel Web sayfası yok</translation>
<translation id="4850886885716139402">Görüntüle</translation>
<translation id="4854362297993841467">Bu teslimat yöntemi kullanılamıyor. Farklı bir yöntem deneyin.</translation>
<translation id="4858792381671956233">Ebeveynlerinize bu siteyi ziyaret etmenizin uygun olup olmadığını sordunuz</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bit)</translation>
<translation id="5121084798328133320">Onayladığınızda Google Payments hesabınızdaki kart bilgileriniz bu siteyle paylaşılır.</translation>
<translation id="5128122789703661928">Silmek üzere gönderilen bu oturum adı geçerli değil.</translation>
+<translation id="5135404736266831032">Adresleri yönet...</translation>
<translation id="5141240743006678641">Senkronize edilen şifreleri Google kimlik bilgilerinizle şifreleyin</translation>
<translation id="5145883236150621069">Politika yanıtında hata kodu var</translation>
<translation id="5159010409087891077">Sayfayı yeni Gizli pencerede açın (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Bu sayfadaki yerleşik bir sayfanın mesajı</translation>
<translation id="5205222826937269299">Ad gerekli</translation>
<translation id="5222812217790122047">E-posta gerekli</translation>
-<translation id="522700295135997067">Bu site az önce şifrenizi çalmış olabilir</translation>
<translation id="5230733896359313003">Gönderim Adresi</translation>
<translation id="5250209940322997802">"Ağa bağlanın"</translation>
<translation id="5251803541071282808">Bulut</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Şirket, kuruluş veya okul intranet'indeki bu site harici bir web sitesiyle aynı URL'ye sahip.
<ph name="LINE_BREAK" />
Sistem yöneticinize başvurmayı deneyin.</translation>
-<translation id="5499929369096410817"><ph name="CREDIT_CARD" /> kartının güvenlik kodunu girin. Bu kod kaydedilmez.</translation>
<translation id="5509780412636533143">Yönetilen yer işaretleri</translation>
<translation id="5510766032865166053">Taşınmış veya silinmiş olabilir.</translation>
<translation id="5523118979700054094">Politika adı</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Gönderim Adresi Ekle</translation>
<translation id="5689199277474810259">JSON'a aktar</translation>
<translation id="5689516760719285838">Konum</translation>
+<translation id="570530837424789914">Yönet...</translation>
<translation id="5710435578057952990">Bu web sitesinin kimliği doğrulanmadı.</translation>
<translation id="5719499550583120431">Ön ödemeli kartlar kabul edilir.</translation>
<translation id="5720705177508910913">Geçerli kullanıcı</translation>
+<translation id="5730040223043577876">Chrome, şifrenizi başka sitelerde kullandıysanız sıfırlamanızı önerir.</translation>
<translation id="5732392974455271431">Ebeveynleriniz engellemeyi kaldırabilir</translation>
<translation id="5763042198335101085">Geçerli bir e-posta adresi girin</translation>
<translation id="5765072501007116331">Teslimat yöntemlerini ve gereksinimleri görmek için bir adres seçin</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Tehlikeli uygulamaların ve sitelerin tespit edilmesine yardımcı olmak için Google'a bazı <ph name="BEGIN_WHITEPAPER_LINK" />sistem bilgilerini ve sayfa içeriklerini<ph name="END_WHITEPAPER_LINK" /> otomatik olarak gönder.<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">İletişim Bilgilerini Düzenleyin</translation>
<translation id="5967867314010545767">Geçmişten kaldır.</translation>
-<translation id="5972020793760134803">Sekmeye geç</translation>
<translation id="5975083100439434680">Uzaklaştır</translation>
-<translation id="597552863672748783">Güvenlik kodunu onaylayın</translation>
<translation id="598637245381783098">Ödeme uygulaması açılamıyor</translation>
<translation id="5989320800837274978">Sabit proxy sunucular veya bir .pac komut dosyası URL'si belirtilmedi.</translation>
<translation id="5990559369517809815">Sunucuya gönderilen istekler bir uzantı tarafından engellendi.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Bu içerik sizi kandırarak yazılım yüklemenizi veya kişisel bilgilerinizi ifşa etmenizi sağlamaya çalışabilir. <ph name="BEGIN_LINK" />Yine de göster<ph name="END_LINK" /></translation>
<translation id="6051221802930200923"><ph name="SITE" /> sitesi sertifika sabitleme yöntemi kullandığından siteyi şu anda ziyaret edemezsiniz. Ağ hataları ve saldırılar genellikle geçici olduğundan bu sayfa muhtemelen daha sonra çalışacaktır.</translation>
<translation id="6059925163896151826">USB cihazları</translation>
+<translation id="6071091556643036997">Politika türü geçersiz.</translation>
<translation id="6080696365213338172">Yönetici tarafından sağlanmış bir sertifika kullanan içeriğe eriştiniz. <ph name="DOMAIN" /> alan adına sağladığınız verileri yöneticiniz görebilir ve bunlara müdahale edebilir.</translation>
<translation id="610911394827799129">Google Hesabınızın <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> adresinde başka biçimlerde tarama geçmişi olabilir</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Yok}=1{1 şifre (senkronize edildi)}other{# şifre (senkronize edildi)}}</translation>
@@ -755,7 +757,7 @@
<translation id="6355080345576803305">Herkese açık oturumu geçersiz kılma</translation>
<translation id="6358450015545214790">Bunlar ne anlama geliyor?</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{1 öneri daha}other{# öneri daha}}</translation>
-<translation id="6387754724289022810">Bir dahaki sefere daha hızlı ödeme yapmak için kartınızı ve fatura adresinizi Google Hesabınıza ve bu cihaza kaydedin.</translation>
+<translation id="6387754724289022810">Gelecek sefer daha hızlı ödeme yapabilmek için kartınızı ve fatura adresinizi Google hesabınıza kaydedin.</translation>
<translation id="6397451950548600259">Bilgisayarınızdaki yazılım, Chrome'un web'e güvenli bir şekilde bağlanmasını engelliyor</translation>
<translation id="6404511346730675251">Yer işaretini düzenle</translation>
<translation id="6410264514553301377"><ph name="CREDIT_CARD" /> numaralı kartın son kullanma tarihini ve CVC kodunu girin</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Daha fazla bilgi ekleyin</translation>
<translation id="6447842834002726250">Çerezler</translation>
<translation id="6451458296329894277">Yeniden Form Gönderme İşlemini Onayla</translation>
+<translation id="6465306955648956876">Şifreleri yönet...</translation>
<translation id="647261751007945333">Cihaz politikaları</translation>
<translation id="6477321094435799029">Chrome, bu sayfada olağan dışı kod tespit etti ve kişisel bilgilerinizi (örneğin, şifreler, telefon numaraları ve kredi kartları) korumak için sayfayı engelledi.</translation>
<translation id="6489534406876378309">Kilitlenmeleri yüklemeye başla</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> Arama</translation>
<translation id="6630809736994426279">Şu anda <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> sitesindeki saldırganlar bilgilerinizi (örneğin, fotoğraflar, şifreler, mesajlar ve kredi kartları) çalabilecek veya silebilecek tehlikeli programları Mac'inize yüklemeye çalışabilir. <ph name="BEGIN_LEARN_MORE_LINK" />Daha fazla bilgi<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Bu politika uygun bulunmadı.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Yok}=1{1 siteden (Google Hesabınızdan çıkış yapılmaz)}other{# siteden (Google Hesabınızdan çıkış yapılmaz)}}</translation>
<translation id="6657585470893396449">Şifre</translation>
<translation id="6671697161687535275">Form önerisi Chromium'dan kaldırılsın mı?</translation>
<translation id="6685834062052613830">Çıkış yapın ve kurulumu tamamlayın</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Kullanıcı:</translation>
<translation id="6945221475159498467">Seç</translation>
<translation id="6948701128805548767">Alım yöntemlerini ve gereksinimlerini görmek için bir adres seçin</translation>
+<translation id="6949872517221025916">Şifreyi Sıfırla</translation>
<translation id="6957887021205513506">Sunucunun sertifikası sahte görünüyor.</translation>
<translation id="6965382102122355670">Tamam</translation>
<translation id="6965978654500191972">Cihaz</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Teslimat yöntemi</translation>
<translation id="7139724024395191329">Emirlik</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> yöntem daha}other{<ph name="PAYMENT_METHOD_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> yöntem daha}}</translation>
-<translation id="7155487117670177674">Ödeme işlemi güvenli değil</translation>
+<translation id="717330890047184534">Gaia Kimliği:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> seçenek daha}other{<ph name="SHIPPING_OPTION_PREVIEW" /> ve <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> seçenek daha}}</translation>
<translation id="7180611975245234373">Yenile</translation>
<translation id="7182878459783632708">Hiçbir politika ayarlanmamış</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Genel varsayılanı kullan (Engelle)</translation>
<translation id="7460163899615895653">Diğer cihazlardan yeni tarihli sekmeleriniz burada görünür</translation>
<translation id="7469372306589899959">Kart onaylanıyor</translation>
+<translation id="7473891865547856676">Hayır, Teşekkürler</translation>
<translation id="7481312909269577407">İleri</translation>
<translation id="7485870689360869515">Hiçbir veri bulunamadı.</translation>
<translation id="7508255263130623398">Döndürülen politika cihaz kimliği boş veya mevcut cihaz kimliğiyle eşleşmiyor</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Kredi kartı Chrome'dan kaldırılsın mı?</translation>
<translation id="7575800019233204241">"Bağlantınız gizli değil", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" veya "SSL sertifika hatası"</translation>
<translation id="7578104083680115302">Google'a kaydettiğiniz kartları kullanarak farklı cihazlardan sitelerde ve uygulamalarda ödemelerinizi hızla yapabilirsiniz.</translation>
-<translation id="7588950540487816470">Fiziksel Web</translation>
<translation id="7592362899630581445">Sunucunun sertifikası ad sınırlamasını ihlal ediyor.</translation>
<translation id="7598391785903975535"><ph name="UPPER_ESTIMATE" />'tan az</translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> şu anda bu isteği işleme alamıyor.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">Düzenlemeyi &amp;geri al</translation>
<translation id="9154194610265714752">Güncellendi</translation>
<translation id="9157595877708044936">Ayarlanıyor...</translation>
+<translation id="9168814207360376865">Sitelerin, kayıtlı ödeme yöntemleriniz olup olmadığını kontrol etmesine izin verin</translation>
<translation id="9169664750068251925">Bu sitede her zaman engelle</translation>
<translation id="9170848237812810038">&amp;Geri al</translation>
<translation id="917450738466192189">Sunucunun sertifikası geçersiz.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Makale eklenemedi.</translation>
<translation id="9215416866750762878">Bir uygulama, Chrome'un bu siteye güvenli bir şekilde bağlanmasını engelliyor</translation>
<translation id="9219103736887031265">Resimler</translation>
-<translation id="933612690413056017">İnternet bağlantısı yok</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">FORMU TEMİZLE</translation>
<translation id="939736085109172342">Yeni klasör</translation>
diff --git a/chromium/components/strings/components_strings_uk.xtb b/chromium/components/strings/components_strings_uk.xtb
index 887bacde1f7..849916fc64a 100644
--- a/chromium/components/strings/components_strings_uk.xtb
+++ b/chromium/components/strings/components_strings_uk.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Виберіть тип для дозволу "<ph name="PERMISSION_NAME" />"</translation>
<translation id="1111153019813902504">Останні закладки</translation>
<translation id="1113869188872983271">&amp;Відмінити перевпорядкування</translation>
+<translation id="1125573121925420732">Можуть з’являтися застереження під час оновлення системи безпеки сайтів. Цю проблему буде незабаром виправлено.</translation>
<translation id="1126551341858583091">Обсяг локальної пам’яті – <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Кеш-пам’ять правила не пошкоджено</translation>
<translation id="1150979032973867961">Цей сервер не зміг довести, що він – домен <ph name="DOMAIN" />. Операційна система вашого комп’ютера не вважає його сертифікат безпеки надійним. Імовірні причини: неправильна конфігурація або хтось намагається перехопити ваше з’єднання.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Переконайтеся, що інтернет-з’єднання стабільне.&lt;/li&gt;
&lt;li&gt;Зв’яжіться з власником веб-сайту.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Ви ввели пароль на сайті, яким не керує ваша організація. Щоб захистити свій обліковий запис, не використовуйте цей пароль для інших додатків і сайтів.</translation>
<translation id="1263231323834454256">Список читання</translation>
<translation id="1264126396475825575">Звіт про аварійне завершення роботи о <ph name="CRASH_TIME" /> (ще не завантажено або пропущено)</translation>
<translation id="1270502636509132238">Спосіб отримання</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Вибрати</translation>
<translation id="1620510694547887537">Камера</translation>
<translation id="1623104350909869708">Заборонити цій сторінці створювати додаткові діалогові вікна</translation>
-<translation id="1629803312968146339">Зберегти цю картку в Chrome?</translation>
<translation id="1639239467298939599">Завантаження</translation>
<translation id="1640180200866533862">Правила користувача</translation>
<translation id="1640244768702815859"><ph name="BEGIN_LINK" />Відвідайте домашню сторінку цього сайту<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Проведіть діагностику мережі Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Оновіть парольну фразу для синхронізації.</translation>
<translation id="1787142507584202372">Тут відображатимуться ваші відкриті вкладки</translation>
-<translation id="1789575671122666129">Спливаючі вікна</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Ім’я та прізвище власника картки</translation>
<translation id="1806541873155184440">Додано <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Перезавантажте комп’ютер</translation>
<translation id="2113977810652731515">Картка</translation>
<translation id="2114841414352855701">Правило ігнорується, оскільки його замінено правилом <ph name="POLICY_NAME" />.</translation>
-<translation id="2138201775715568214">Пошук веб-сторінок у сервісі "Інтернет навколо нас"</translation>
<translation id="213826338245044447">Закладки для мобільних пристроїв</translation>
<translation id="214556005048008348">Скасувати оплату</translation>
<translation id="2147827593068025794">Фонова синхронізація</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Правило не знайдено</translation>
<translation id="2213606439339815911">Отримання записів…</translation>
<translation id="2218879909401188352">Зловмисники на сайті <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> можуть установити небезпечні додатки, які шкодять вашому пристрою, додають приховані платежі за мобільний зв’язок або викрадають особисту інформацію. <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Немає Інтернету</translation>
<translation id="2230458221926704099">Відновіть з’єднання за допомогою <ph name="BEGIN_LINK" />додатка для діагностики<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Надіслати</translation>
<translation id="225207911366869382">Дію цього значення припинено для цього правила</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Видалити вибрані елементи</translation>
<translation id="277133753123645258">Спосіб відправлення</translation>
<translation id="277499241957683684">Відсутній запис пристрою</translation>
+<translation id="2781030394888168909">Експортувати для ОС Mac</translation>
<translation id="2784949926578158345">З’єднання було скинуто.</translation>
<translation id="2788784517760473862">Прийнятні кредитні картки</translation>
<translation id="2794233252405721443">Сайт заблоковано</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome не вдалося підтвердити дані вашої картки. Спробуйте пізніше.</translation>
<translation id="3064966200440839136">Щоб оплатити в зовнішньому додатку, ви вийдете з режиму анонімного перегляду. Продовжити?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Немає}=1{1 пароль}one{# пароль}few{# паролі}many{# паролів}other{# пароля}}</translation>
-<translation id="3093245981617870298">Ви в режимі офлайн</translation>
<translation id="3096100844101284527">Додати адресу отримання</translation>
<translation id="3105172416063519923">Ідентифікатор об’єкта:</translation>
<translation id="3109728660330352905">У вас немає дозволу переглядати цю сторінку.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Хост <ph name="HOST_NAME" /> зараз недоступний.</translation>
<translation id="3427092606871434483">Дозволяти (за умовчанням)</translation>
<translation id="3427342743765426898">&amp;Повторити редагування</translation>
+<translation id="342781501876943858">Chromium радить скинути пароль, якщо ви застосовували його на інших сайтах.</translation>
<translation id="3431636764301398940">Зберегти цю картку на пристрої</translation>
<translation id="3447661539832366887">Власник цього пристрою вимкнув гру з динозавром.</translation>
<translation id="3447884698081792621">Показати сертифікат (видавець: <ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Відкрийте сторінку в анонімному вікні (Ctrl+Shift+N)</translation>
<translation id="3679803492151881375">Звіт про аварійне завершення роботи створено: <ph name="CRASH_TIME" />, завантажено: <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Інформація про сертифікат</translation>
-<translation id="3690164694835360974">Вхід не захищено</translation>
<translation id="3704162925118123524">Можливо, щоб з’єднатися з цією мережею, потрібно відвідати її сторінку входу.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Завантаження...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Використовувати загальне значення за умовчанням (визначати)</translation>
<translation id="4165986682804962316">Налаштування сайту</translation>
-<translation id="4169947484918424451">Зберегти цю картку в Chromium?</translation>
<translation id="4171400957073367226">Недійсний підпис для підтвердження</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{ще <ph name="ITEM_COUNT" /> елемент}one{ще <ph name="ITEM_COUNT" /> елемент}few{ще <ph name="ITEM_COUNT" /> елементи}many{ще <ph name="ITEM_COUNT" /> елементів}other{ще <ph name="ITEM_COUNT" /> елемента}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Перезапустіть пристрій</translation>
<translation id="4277028893293644418">Скинути пароль</translation>
<translation id="4280429058323657511">, дійсна до <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Перейти</translation>
<translation id="4312866146174492540">Блокувати (за умовчанням)</translation>
<translation id="4325863107915753736">Статтю не знайдено</translation>
<translation id="4326324639298822553">Перевірте дату закінчення терміну дії та повторіть спробу</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Цим комп’ютером не керує адміністратор підприємства, тому правило може лише автоматично встановити розширення, розміщені у Веб-магазині Chrome. URL-адреса для оновлення Веб-магазину Chrome: <ph name="CWS_UPDATE_URL" />.</translation>
<translation id="4346197816712207223">Кредитні картки, які приймаються до оплати</translation>
<translation id="4356973930735388585">Зловмисники на цьому сайті можуть намагатися встановити на ваш комп’ютер небезпечні програми, що викрадають або видаляють інформацію (наприклад, фотографії, паролі, повідомлення й дані кредитних карток).</translation>
+<translation id="4358461427845829800">Керувати способами оплати…</translation>
<translation id="4372948949327679948">Очікуване значення: <ph name="VALUE_TYPE" />.</translation>
<translation id="4377125064752653719">Ви пробували зв’язатися з доменом <ph name="DOMAIN" />, проте сервер надав сертифікат, відкликаний його видавцем. Це означає, що не варто довіряти обліковим даним системи захисту, наданим сервером. Можливо, ви обмінюєтеся даними зі зловмисником.</translation>
<translation id="4406896451731180161">результати пошуку</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Адреса отримання</translation>
<translation id="4424024547088906515">Цей сервер не зміг довести, що він – домен <ph name="DOMAIN" />. Chrome не вважає його сертифікат безпеки надійним. Імовірні причини: неправильна конфігурація або хтось намагається перехопити ваше з’єднання.</translation>
<translation id="4432688616882109544">Хост <ph name="HOST_NAME" /> не прийняв ваш сертифікат входу або ви не надали цей сертифікат.</translation>
+<translation id="4434045419905280838">Спливаючі вікна й переадресація</translation>
<translation id="443673843213245140">Використання проксі-сервера вимкнено, але чітко вказано налаштування проксі-сервера.</translation>
<translation id="445100540951337728">Прийнятні дебетові картки</translation>
<translation id="4506176782989081258">Помилка перевірки: <ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Автозаповнення платіжних даних вимкнено</translation>
<translation id="4764776831041365478">Веб-сторінка за адресою <ph name="URL" /> може бути тимчасово недоступною або її назавжди переміщено на нову веб-адресу.</translation>
<translation id="4771973620359291008">Виникла невідома помилка.</translation>
+<translation id="4785689107224900852">Перейти на цю вкладку</translation>
<translation id="4792143361752574037">Не вдалось отримати доступ до файлів сеансу. Наразі не можна зберегти сеанс на диску. Оновіть сторінку та повторіть спробу.</translation>
<translation id="4800132727771399293">Перевірте дату закінчення терміну дії та код CVC та повторіть спробу</translation>
<translation id="4803924862070940586"><ph name="FORMATTED_TOTAL_AMOUNT" /> <ph name="CURRENCY_CODE" /></translation>
<translation id="4807049035289105102">Зараз не можна перейти на сторінку <ph name="SITE" />, оскільки веб-сайт надіслав зашифровані облікові дані, які Google Chrome не може обробити. Помилки мережі й атаки зазвичай є тимчасовими, тому ця сторінка може працювати пізніше.</translation>
<translation id="4813512666221746211">Помилка мережі</translation>
<translation id="4816492930507672669">За розміром сторінки</translation>
-<translation id="483020001682031208">Немає сторінок сервісу "Інтернет навколо нас" для відображення</translation>
<translation id="4850886885716139402">Перегляд</translation>
<translation id="4854362297993841467">Цей спосіб доставки недоступний. Виберіть інший спосіб.</translation>
<translation id="4858792381671956233">Ви надіслали батькам запит на перегляд цього сайту</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64-розрядна версія)</translation>
<translation id="5121084798328133320">Щойно ви підтвердите дані картки з облікового запису Google Payments, цей сайт отримає доступ до них.</translation>
<translation id="5128122789703661928">Сеанс із цією назвою не можна видалити.</translation>
+<translation id="5135404736266831032">Керувати адресами…</translation>
<translation id="5141240743006678641">Шифрувати синхронізовані паролі за допомогою облікових даних Google</translation>
<translation id="5145883236150621069">Відповідь правила містить код помилки</translation>
<translation id="5159010409087891077">Відкрийте сторінку в анонімному вікні (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Повідомлення з вбудованої сторінки на цій сторінці</translation>
<translation id="5205222826937269299">Укажіть ім’я</translation>
<translation id="5222812217790122047">Укажіть електронну адресу</translation>
-<translation id="522700295135997067">Можливо, хтось на цьому сайті щойно викрав ваш пароль</translation>
<translation id="5230733896359313003">Адреса доставки</translation>
<translation id="5250209940322997802">"Під’єднайте пристрій до мережі"</translation>
<translation id="5251803541071282808">Хмара</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">URL-адреса цього сайту в інтранеті компанії, організації чи навчального закладу збігається з адресою зовнішнього веб-сайту.
<ph name="LINE_BREAK" />
Зв’яжіться зі своїм системним адміністратором.</translation>
-<translation id="5499929369096410817">Введіть код безпеки для картки <ph name="CREDIT_CARD" />. Цей код не буде збережено.</translation>
<translation id="5509780412636533143">Закладки, якими керує адміністратор</translation>
<translation id="5510766032865166053">Можливо, його переміщено або видалено.</translation>
<translation id="5523118979700054094">Назва правила</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Додати адресу доставки</translation>
<translation id="5689199277474810259">Експортувати у формат JSON</translation>
<translation id="5689516760719285838">Місцезнаходження</translation>
+<translation id="570530837424789914">Керувати…</translation>
<translation id="5710435578057952990">Ідентифікаційну інформацію цього веб-сайта не було перевірено.</translation>
<translation id="5719499550583120431">Передплачені картки, які приймаються.</translation>
<translation id="5720705177508910913">Поточний користувач</translation>
+<translation id="5730040223043577876">Chrome радить скинути пароль, якщо ви застосовували його на інших сайтах.</translation>
<translation id="5732392974455271431">Батьки можуть розблокувати його</translation>
<translation id="5763042198335101085">Введіть дійсну електронну адресу</translation>
<translation id="5765072501007116331">Укажіть адресу, щоб переглянути способи доставки та вимоги.</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Автоматично надсилати в Google деяку <ph name="BEGIN_WHITEPAPER_LINK" />інформацію про систему та вміст сторінок<ph name="END_WHITEPAPER_LINK" />, щоб допомогти виявляти небезпечні додатки й сайти<ph name="PRIVACY_PAGE_LINK" />.</translation>
<translation id="5967592137238574583">Змініть контактну інформацію</translation>
<translation id="5967867314010545767">Видалити з історії</translation>
-<translation id="5972020793760134803">Перейти на вкладку</translation>
<translation id="5975083100439434680">Зменшити масштаб</translation>
-<translation id="597552863672748783">Підтвердьте код безпеки</translation>
<translation id="598637245381783098">Неможливо відкрити додаток для платежів</translation>
<translation id="5989320800837274978">Не вказано ні фіксованих проксі-серверів, ні URL-адрес сценарію .pac.</translation>
<translation id="5990559369517809815">Надсилання запитів на сервер заблоковано розширенням.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Цей вміст може оманливим шляхом змусити вас установити програмну або надати особисту інформацію. <ph name="BEGIN_LINK" />Усе одно показати<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Зараз не можна перейти на сторінку <ph name="SITE" />, оскільки цей веб-сайт використовує закріплення сертифікатів. Помилки мережі й атаки зазвичай тимчасові, тому ця сторінка, скоріш за все, запрацює пізніше.</translation>
<translation id="6059925163896151826">Пристрої USB</translation>
+<translation id="6071091556643036997">Це правило недійсне.</translation>
<translation id="6080696365213338172">Ви отримали доступ до вмісту, використовуючи наданий адміністратором сертифікат. Адміністратор може перехоплювати дані, які ви надасте домену <ph name="DOMAIN" />.</translation>
<translation id="610911394827799129">У вашому обліковому записі Google на сторінці <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> можуть бути інші форми історії веб-перегляду</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Немає}=1{1 пароль (синхронізовано)}one{# пароль (синхронізовано)}few{# паролі (синхронізовано)}many{# паролів (синхронізовано)}other{# пароля (синхронізовано)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Додати більше інформації</translation>
<translation id="6447842834002726250">Cookie-файли</translation>
<translation id="6451458296329894277">Підтвердити повторне надсилання форми</translation>
+<translation id="6465306955648956876">Керувати паролями…</translation>
<translation id="647261751007945333">Правила пристрою</translation>
<translation id="6477321094435799029">Chrome виявив на цій сторінці незвичний код і заблокував його, щоб захистити вашу особисту інформацію (наприклад, паролі, номери телефонів або кредитних карток).</translation>
<translation id="6489534406876378309">Почати завантаження даних про аварійне завершення роботи</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Пошук <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Зловмисники на сайті <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> можуть установити на ваш комп’ютер Mac небезпечні програми, що викрадають або видаляють інформацію (як-от фотографії, паролі, повідомлення та дані кредитних карток). <ph name="BEGIN_LEARN_MORE_LINK" />Докладніше<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Це правило більше не використовується.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Немає}=1{З 1 сайту (ви не вийдете з облікового запису Google)}one{З # сайту (ви не вийдете з облікового запису Google)}few{З # сайтів (ви не вийдете з облікового запису Google)}many{З # сайтів (ви не вийдете з облікового запису Google)}other{З # сайту (ви не вийдете з облікового запису Google)}}</translation>
<translation id="6657585470893396449">Пароль</translation>
<translation id="6671697161687535275">Видалити пропозицію автозаповнення форм із Chromium?</translation>
<translation id="6685834062052613830">Вийдіть з облікового запису та завершіть процедуру налаштування</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Користувач:</translation>
<translation id="6945221475159498467">Вибрати</translation>
<translation id="6948701128805548767">Укажіть адресу, щоб переглянути способи отримання та вимоги.</translation>
+<translation id="6949872517221025916">Скидання пароля</translation>
<translation id="6957887021205513506">Схоже, що сертифікат сервера підроблено.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Пристрій</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Спосіб доставки</translation>
<translation id="7139724024395191329">Емірат</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}one{<ph name="PAYMENT_METHOD_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}few{<ph name="PAYMENT_METHOD_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}many{<ph name="PAYMENT_METHOD_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}other{<ph name="PAYMENT_METHOD_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" />}}</translation>
-<translation id="7155487117670177674">Платіж не захищено</translation>
+<translation id="717330890047184534">Ідентифікатор GAIA:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}one{<ph name="SHIPPING_OPTION_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}few{<ph name="SHIPPING_OPTION_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}many{<ph name="SHIPPING_OPTION_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}other{<ph name="SHIPPING_OPTION_PREVIEW" /> і ще <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" />}}</translation>
<translation id="7180611975245234373">Оновити</translation>
<translation id="7182878459783632708">Правила не встановлено</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Використовувати глобальне налаштування за умовчанням (Блокувати)</translation>
<translation id="7460163899615895653">Тут відображатимуться ваші останні вкладки з інших пристроїв</translation>
<translation id="7469372306589899959">Підтвердження даних картки</translation>
+<translation id="7473891865547856676">Ні, дякую</translation>
<translation id="7481312909269577407">Переслати</translation>
<translation id="7485870689360869515">Даних не знайдено.</translation>
<translation id="7508255263130623398">Отриманий ідентифікатор правил пристрою порожній або не збігається з поточним ідентифікатором пристрою</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Видалити дані кредитної картки з Chrome?</translation>
<translation id="7575800019233204241">"З’єднання не конфіденційне", "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;", "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" або "Помилка сертифіката SSL"</translation>
<translation id="7578104083680115302">Зберігайте картки в Google, щоб швидко платити на сайтах і в додатках на всіх своїх пристроях.</translation>
-<translation id="7588950540487816470">Інтернет навколо нас</translation>
<translation id="7592362899630581445">Сертифікат сервера порушує обмежувальні умови щодо імен.</translation>
<translation id="7598391785903975535">Менше <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187">Хост <ph name="HOST_NAME" /> зараз не може обробити цей запит.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;Відмінити редагування</translation>
<translation id="9154194610265714752">Оновлено</translation>
<translation id="9157595877708044936">Налаштування...</translation>
+<translation id="9168814207360376865">Дозволити сайтам перевіряти, чи у вас є збережені способи оплати</translation>
<translation id="9169664750068251925">Завжди блокувати на цьому сайті</translation>
<translation id="9170848237812810038">&amp;Скасувати</translation>
<translation id="917450738466192189">Сертифікат сервера недійсний.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Не вдалося додати статтю.</translation>
<translation id="9215416866750762878">Додаток перешкоджає Chrome безпечно під’єднуватися до цього сайту</translation>
<translation id="9219103736887031265">Зображення</translation>
-<translation id="933612690413056017">Немає з’єднання з Інтернетом</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">ОЧИСТИТИ ФОРМУ</translation>
<translation id="939736085109172342">Нова папка</translation>
diff --git a/chromium/components/strings/components_strings_vi.xtb b/chromium/components/strings/components_strings_vi.xtb
index 5ba7fabd909..1105fbdb011 100644
--- a/chromium/components/strings/components_strings_vi.xtb
+++ b/chromium/components/strings/components_strings_vi.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">Chọn quyền cho <ph name="PERMISSION_NAME" /></translation>
<translation id="1111153019813902504">Dấu trang gần đây</translation>
<translation id="1113869188872983271">&amp;Hoàn tác sắp xếp lại</translation>
+<translation id="1125573121925420732">Cảnh báo hiển thị khi trang web cập nhật bảo mật là điều bình thường. Việc này sẽ sớm được cải tiến.</translation>
<translation id="1126551341858583091">Kích thước trên bộ nhớ cục bộ là <ph name="CRASH_SIZE" />.</translation>
<translation id="112840717907525620">Bộ nhớ đệm chính sách OK</translation>
<translation id="1150979032973867961">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này không được hệ điều hành máy tính của bạn tin cậy. Điều này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;Đảm bảo kết nối Internet hoạt động bình thường.&lt;/li&gt;
&lt;li&gt;Liên hệ với chủ sở hữu trang web.&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">Bạn đã nhập mật khẩu của mình trên một trang web không thuộc quyền quản lý của tổ chức bạn. Để bảo vệ tài khoản, không sử dụng lại mật khẩu của bạn trên các ứng dụng và trang web khác.</translation>
<translation id="1263231323834454256">Danh sách đọc</translation>
<translation id="1264126396475825575">Báo cáo sự cố được ghi lại vào <ph name="CRASH_TIME" /> (nhưng chưa tải lên hoặc đã bị bỏ qua)</translation>
<translation id="1270502636509132238">Phương thức nhận hàng</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">Chọn</translation>
<translation id="1620510694547887537">Máy ảnh</translation>
<translation id="1623104350909869708">Ngăn trang này tạo hộp thoại bổ sung</translation>
-<translation id="1629803312968146339">Bạn có muốn Chrome lưu thẻ này không?</translation>
<translation id="1639239467298939599">Đang tải</translation>
<translation id="1640180200866533862">Chính sách người dùng</translation>
<translation id="1640244768702815859">Hãy thử <ph name="BEGIN_LINK" />truy cập trang chủ của trang web<ph name="END_LINK" />.</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />Thử chạy Chẩn đoán mạng của Windows<ph name="END_LINK" />.</translation>
<translation id="1783075131180517613">Vui lòng cập nhật cụm mật khẩu đồng bộ hóa của bạn.</translation>
<translation id="1787142507584202372">Tab đang mở của bạn xuất hiện ở đây</translation>
-<translation id="1789575671122666129">Cửa sổ bật lên</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">Tên chủ thẻ</translation>
<translation id="1806541873155184440">Ngày thêm: <ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">Khởi động lại máy tính của bạn</translation>
<translation id="2113977810652731515">Thẻ</translation>
<translation id="2114841414352855701">Bỏ qua vì đã bị <ph name="POLICY_NAME" /> ghi đè.</translation>
-<translation id="2138201775715568214">Đang tìm kiếm các trang Web trong cuộc sống lân cận</translation>
<translation id="213826338245044447">Dấu trang di động</translation>
<translation id="214556005048008348">Hủy thanh toán</translation>
<translation id="2147827593068025794">Đồng bộ hóa dưới nền</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">Không tìm thấy chính sách</translation>
<translation id="2213606439339815911">Đang tìm nạp các mục nhập...</translation>
<translation id="2218879909401188352">Những kẻ tấn công hiện ở trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cài đặt ứng dụng nguy hiểm làm hỏng thiết bị của bạn, thêm các khoản phí ẩn vào hóa đơn di động hoặc lấy cắp thông tin cá nhân của bạn. <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">Không có Internet</translation>
<translation id="2230458221926704099">Sửa kết nối bằng <ph name="BEGIN_LINK" />ứng dụng chẩn đoán<ph name="END_LINK" /></translation>
<translation id="2239100178324503013">Gửi bây giờ</translation>
<translation id="225207911366869382">Giá trị này không được dùng cho chính sách này nữa.</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">Xóa các mục đã chọn</translation>
<translation id="277133753123645258">Phương thức giao hàng</translation>
<translation id="277499241957683684">Thiếu hồ sơ thiết bị</translation>
+<translation id="2781030394888168909">Xuất ở định dạng MacOS</translation>
<translation id="2784949926578158345">Kết nối đã được đặt lại.</translation>
<translation id="2788784517760473862">Thẻ tín dụng được chấp nhận</translation>
<translation id="2794233252405721443">Trang web đã bị chặn</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome không thể xác nhận thẻ của bạn tại thời điểm này. Vui lòng thử lại sau.</translation>
<translation id="3064966200440839136">Rời khỏi chế độ ẩn danh để thanh toán qua một ứng dụng bên ngoài. Tiếp tục?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{Không có}=1{1 mật khẩu}other{# mật khẩu}}</translation>
-<translation id="3093245981617870298">Bạn đang ngoại tuyến.</translation>
<translation id="3096100844101284527">Thêm địa chỉ nhận hàng</translation>
<translation id="3105172416063519923">ID phần tử:</translation>
<translation id="3109728660330352905">Bạn không có quyền xem trang này.</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">Hiện không thể truy cập <ph name="HOST_NAME" />.</translation>
<translation id="3427092606871434483">Cho phép (mặc định)</translation>
<translation id="3427342743765426898">&amp;Làm lại chỉnh sửa</translation>
+<translation id="342781501876943858">Chromium khuyên bạn nên đặt lại mật khẩu của mình nếu đã sử dụng lại mật khẩu này trên các trang web khác.</translation>
<translation id="3431636764301398940">Lưu thẻ này vào thiết bị này</translation>
<translation id="3447661539832366887">Chủ sở hữu của thiết bị này đã tắt trò chơi khủng long.</translation>
<translation id="3447884698081792621">Hiển thị chứng chỉ (do <ph name="ISSUER" /> cấp)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">Mở trang trong cửa sổ Ẩn danh mới (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">Báo cáo sự cố được ghi lại vào <ph name="CRASH_TIME" />, được tải lên vào <ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">Thông tin chứng chỉ</translation>
-<translation id="3690164694835360974">Đăng nhập không an toàn</translation>
<translation id="3704162925118123524">Mạng mà bạn đang sử dụng có thể yêu cầu bạn phải truy cập trang đăng nhập của mạng đó.</translation>
<translation id="3704609568417268905"><ph name="TIME" /> <ph name="BOOKMARKED" /> <ph name="TITLE" /> <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">Đang tải...</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">Sử dụng cài đặt mặc định chung (Phát hiện)</translation>
<translation id="4165986682804962316">Cài đặt trang web</translation>
-<translation id="4169947484918424451">Bạn có muốn Chromium lưu thẻ này không?</translation>
<translation id="4171400957073367226">Chữ ký xác minh không hợp lệ</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{<ph name="ITEM_COUNT" /> mục khác}other{<ph name="ITEM_COUNT" /> mục khác}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">Khởi động lại thiết bị của bạn</translation>
<translation id="4277028893293644418">Đặt lại mật khẩu</translation>
<translation id="4280429058323657511">, hết hạn <ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">Chuyển</translation>
<translation id="4312866146174492540">Chặn (mặc định)</translation>
<translation id="4325863107915753736">Không tìm được bài viết</translation>
<translation id="4326324639298822553">Kiểm tra ngày hết hạn của bạn và thử lại</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">Máy tính này không được coi là máy tính do doanh nghiệp quản lý, vì vậy, chính sách này chỉ có thể tự động cài đặt các tiện ích được lưu trữ trên Cửa hàng Chrome trực tuyến. URL cập nhật Cửa hàng Chrome trực tuyến là "<ph name="CWS_UPDATE_URL" />".</translation>
<translation id="4346197816712207223">Thẻ tín dụng được chấp nhận</translation>
<translation id="4356973930735388585">Những kẻ tấn công trên trang web này có thể tìm cách cài đặt các chương trình nguy hiểm vào máy tính của bạn. Các chương trình này sẽ đánh cắp hoặc xóa thông tin của bạn (ví dụ: ảnh, mật khẩu, thư và thẻ tín dụng).</translation>
+<translation id="4358461427845829800">Quản lý phương thức thanh toán...</translation>
<translation id="4372948949327679948">Giá trị <ph name="VALUE_TYPE" /> mong đợi.</translation>
<translation id="4377125064752653719">Bạn đã cố truy cập vào <ph name="DOMAIN" /> nhưng chứng chỉ mà máy chủ xuất trình đã bị nhà phát hành thu hồi. Điều này có nghĩa là giấy ủy nhiệm bảo mật mà máy chủ xuất trình hoàn toàn không đáng tin cậy. Bạn có thể đang giao tiếp với kẻ tấn công.</translation>
<translation id="4406896451731180161">kết quả tìm kiếm</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">Địa chỉ nhận hàng</translation>
<translation id="4424024547088906515">Máy chủ này không chứng minh được rằng đó là <ph name="DOMAIN" />; chứng chỉ bảo mật của máy chủ này không được Chrome tin cậy. Điều này có thể do định cấu hình sai hoặc có kẻ tấn công chặn kết nối của bạn.</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> không chấp nhận chứng chỉ đăng nhập của bạn hoặc có thể bạn chưa cung cấp chứng chỉ đăng nhập.</translation>
+<translation id="4434045419905280838">Cửa sổ bật lên và liên kết chuyển hướng</translation>
<translation id="443673843213245140">Đã tắt sử dụng proxy nhưng cấu hình proxy rõ ràng được chỉ định.</translation>
<translation id="445100540951337728">Thẻ ghi nợ được chấp nhận</translation>
<translation id="4506176782989081258">Lỗi xác thực: <ph name="VALIDATION_ERROR" />.</translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">Đã tắt tự động điền thanh toán</translation>
<translation id="4764776831041365478">Trang web tại <ph name="URL" /> có thể tạm thời không hoạt động hay được chuyển vĩnh viễn sang địa chỉ web mới.</translation>
<translation id="4771973620359291008">Xảy ra lỗi chưa biết.</translation>
+<translation id="4785689107224900852">Chuyển sang tab này</translation>
<translation id="4792143361752574037">Đã xảy ra sự cố khi truy cập vào các tệp phiên. Tính năng lưu vào ổ đĩa hiện bị vô hiệu hóa. Vui lòng tải lại trang để thử lại.</translation>
<translation id="4800132727771399293">Kiểm tra ngày hết hạn và CVC của bạn rồi thử lại</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">Bạn không thể truy cập <ph name="SITE" /> ngay bây giờ do trang web gửi thông tin đăng nhập đã mã hóa mà Google Chrome không thể xử lý. Lỗi mạng và các cuộc tấn công mạng thường chỉ là tạm thời, do đó trang này có thể sẽ hoạt động lại sau.</translation>
<translation id="4813512666221746211">Lỗi mạng</translation>
<translation id="4816492930507672669">Vừa với trang</translation>
-<translation id="483020001682031208">Không có trang Web trong cuộc sống nào để hiển thị</translation>
<translation id="4850886885716139402">Xem</translation>
<translation id="4854362297993841467">Phương thức phân phối này không có sẵn. Hãy thử một phương thức khác.</translation>
<translation id="4858792381671956233">Bạn đã hỏi cha mẹ mình xem có thể truy cập vào trang này hay không</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 bit)</translation>
<translation id="5121084798328133320">Sau khi bạn xác nhận, thông tin chi tiết thẻ từ tài khoản thanh toán Google của bạn sẽ được chia sẻ với trang web này.</translation>
<translation id="5128122789703661928">Không thể xóa phiên do tên phiên không hợp lệ.</translation>
+<translation id="5135404736266831032">Quản lý địa chỉ...</translation>
<translation id="5141240743006678641">Mã hóa mật khẩu đã đồng bộ hóa với thông tin đăng nhập Google của bạn</translation>
<translation id="5145883236150621069">Mã lỗi có trong phản hồi chính sách</translation>
<translation id="5159010409087891077">Mở trang trong cửa sổ Ẩn danh mới (⇧⌘N)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">Một trang được nhúng trên trang này cho biết</translation>
<translation id="5205222826937269299">Cần có tên</translation>
<translation id="5222812217790122047">Cần có email</translation>
-<translation id="522700295135997067">Trang web này có thể vừa đánh cắp mật khẩu của bạn</translation>
<translation id="5230733896359313003">Địa chỉ giao hàng</translation>
<translation id="5250209940322997802">"Kết nối với mạng"</translation>
<translation id="5251803541071282808">Đám mây</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">Trang web trên mạng nội bộ của công ty, tổ chức hoặc trường học này có URL tương tự như trang web bên ngoài.
<ph name="LINE_BREAK" />
Hãy thử liên hệ với quản trị viên hệ thống của bạn.</translation>
-<translation id="5499929369096410817">Nhập mã bảo mật dành cho <ph name="CREDIT_CARD" />. Mã này sẽ không được lưu.</translation>
<translation id="5509780412636533143">Dấu trang được quản lý</translation>
<translation id="5510766032865166053">Tệp này có thể đã bị di chuyển hoặc xóa.</translation>
<translation id="5523118979700054094">Tên chính sách</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">Thêm địa chỉ giao hàng</translation>
<translation id="5689199277474810259">Xuất sang định dạng JSON</translation>
<translation id="5689516760719285838">Vị trí</translation>
+<translation id="570530837424789914">Quản lý...</translation>
<translation id="5710435578057952990">Nhận dạng trang web này chưa được xác minh.</translation>
<translation id="5719499550583120431">Thẻ trả trước được chấp nhận.</translation>
<translation id="5720705177508910913">Người dùng hiện tại</translation>
+<translation id="5730040223043577876">Chrome khuyên bạn nên đặt lại mật khẩu của mình nếu đã sử dụng lại mật khẩu này trên các trang web khác.</translation>
<translation id="5732392974455271431">Cha mẹ của bạn có thể bỏ chặn trang web cho bạn</translation>
<translation id="5763042198335101085">Nhập địa chỉ email hợp lệ</translation>
<translation id="5765072501007116331">Để xem các yêu cầu và phương thức phân phối, hãy chọn một địa chỉ</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">Tự động gửi một số <ph name="BEGIN_WHITEPAPER_LINK" />thông tin hệ thống và nội dung trang<ph name="END_WHITEPAPER_LINK" /> tới Google để giúp phát hiện các ứng dụng và trang web nguy hiểm. <ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">Chỉnh sửa thông tin liên hệ</translation>
<translation id="5967867314010545767">Xóa khỏi lịch sử</translation>
-<translation id="5972020793760134803">Chuyển tab</translation>
<translation id="5975083100439434680">Thu nhỏ</translation>
-<translation id="597552863672748783">Xác nhận mã bảo mật</translation>
<translation id="598637245381783098">Không thể mở ứng dụng thanh toán</translation>
<translation id="5989320800837274978">Cả máy chủ proxy cố định và URL tập lệnh .pac đều chưa được chỉ định.</translation>
<translation id="5990559369517809815">Tiện ích đã chặn yêu cầu tới máy chủ.</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">Nội dung này có thể tìm cách đánh lừa bạn cài đặt phần mềm hoặc tiết lộ thông tin cá nhân. <ph name="BEGIN_LINK" />Vẫn hiển thị<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">Bạn không thể truy cập vào <ph name="SITE" /> ngay bây giờ do trang web sử dụng tính năng ghim chứng chỉ. Lỗi mạng và các cuộc tấn công mạng thường chỉ là tạm thời nên trang này có thể sẽ hoạt động lại sau.</translation>
<translation id="6059925163896151826">Thiết bị USB</translation>
+<translation id="6071091556643036997">Loại chính sách là không hợp lệ.</translation>
<translation id="6080696365213338172">Bạn đã truy cập nội dung bằng chứng chỉ do quản trị viên cấp. Dữ liệu mà bạn cung cấp cho <ph name="DOMAIN" /> có thể bị quản trị viên của bạn chặn.</translation>
<translation id="610911394827799129">Tài khoản Google của bạn có thể có các dạng lịch sử duyệt web khác tại <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /></translation>
<translation id="6144381551823904650">{COUNT,plural, =0{Không có}=1{1 mật khẩu (đã đồng bộ hóa)}other{# mật khẩu (đã đồng bộ hóa)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">Thêm thông tin khác</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6451458296329894277">Xác nhận việc Gửi lại Biểu mẫu</translation>
+<translation id="6465306955648956876">Quản lý mật khẩu...</translation>
<translation id="647261751007945333">Chính sách thiết bị</translation>
<translation id="6477321094435799029">Chrome đã phát hiện mã bất thường trên trang này và đã chặn mã này để bảo vệ thông tin cá nhân của bạn (ví dụ như mật khẩu, số điện thoại và thẻ tín dụng).</translation>
<translation id="6489534406876378309">Bắt đầu tải lên sự cố</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685">Tìm kiếm trên <ph name="ENGINE" /></translation>
<translation id="6630809736994426279">Những kẻ tấn công hiện ở trên <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> có thể cố gắng cài đặt các chương trình nguy hiểm vào máy Mac của bạn. Các chương trình này sẽ đánh cắp hoặc xóa thông tin của bạn (ví dụ: ảnh, mật khẩu, thư và thẻ tín dụng). <ph name="BEGIN_LEARN_MORE_LINK" />Tìm hiểu thêm<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">Chính sách này không được chấp thuận.</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{Không có trang web nào}=1{Từ 1 trang web (bạn sẽ không bị đăng xuất khỏi Tài khoản Google của mình)}other{Từ # trang web (bạn sẽ không bị đăng xuất khỏi Tài khoản Google của mình)}}</translation>
<translation id="6657585470893396449">Mật khẩu</translation>
<translation id="6671697161687535275">Bạn muốn xóa đề xuất biểu mẫu khỏi Chromium?</translation>
<translation id="6685834062052613830">Đăng xuất và hoàn thành quá trình thiết lập</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">Người dùng:</translation>
<translation id="6945221475159498467">Chọn</translation>
<translation id="6948701128805548767">Để xem các yêu cầu và phương thức nhận hàng, hãy chọn một địa chỉ</translation>
+<translation id="6949872517221025916">Đặt lại mật khẩu</translation>
<translation id="6957887021205513506">Chứng chỉ của máy chủ dường như giả mạo.</translation>
<translation id="6965382102122355670">OK</translation>
<translation id="6965978654500191972">Thiết bị</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">Phương thức phân phối</translation>
<translation id="7139724024395191329">Tiểu vương quốc</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> phương thức thanh toán khác}other{<ph name="PAYMENT_METHOD_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> phương thức thanh toán khác}}</translation>
-<translation id="7155487117670177674">Thanh toán không an toàn</translation>
+<translation id="717330890047184534">ID Gaia:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> tùy chọn giao hàng khác}other{<ph name="SHIPPING_OPTION_PREVIEW" /> và <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> tùy chọn giao hàng khác}}</translation>
<translation id="7180611975245234373">Làm mới</translation>
<translation id="7182878459783632708">Không có chính sách nào được đặt</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">Sử dụng cài đặt mặc định chung (Chặn)</translation>
<translation id="7460163899615895653">Các tab gần đây của bạn từ các thiết bị khác xuất hiện ở đây</translation>
<translation id="7469372306589899959">Đang xác nhận thẻ</translation>
+<translation id="7473891865547856676">Không, cảm ơn</translation>
<translation id="7481312909269577407">Chuyển tiếp</translation>
<translation id="7485870689360869515">Không tìm thấy dữ liệu.</translation>
<translation id="7508255263130623398">ID thiết bị thuộc chính sách trả lại trống hoặc không khớp với ID của thiết bị hiện tại</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">Xóa thẻ tín dụng khỏi Chrome?</translation>
<translation id="7575800019233204241">"Kết nối của bạn không phải là kết nối riêng tư" hoặc "&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;" hoặc "&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;" hoặc "&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;" hoặc "lỗi chứng chỉ SSL"</translation>
<translation id="7578104083680115302">Thanh toán nhanh trên các trang web và ứng dụng trong mọi thiết bị nhờ sử dụng thẻ bạn đã lưu với Google.</translation>
-<translation id="7588950540487816470">Web trong cuộc sống</translation>
<translation id="7592362899630581445">Chứng chỉ của máy chủ vi phạm hạn chế tên.</translation>
<translation id="7598391785903975535">Dưới <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> hiện không thể xử lý yêu cầu này.</translation>
@@ -1107,6 +1112,7 @@
<translation id="9148507642005240123">&amp;Hoàn tác chỉnh sửa</translation>
<translation id="9154194610265714752">Đã cập nhật</translation>
<translation id="9157595877708044936">Đang thiết lập...</translation>
+<translation id="9168814207360376865">Cho phép các trang web kiểm tra xem bạn đã lưu phương thức thanh toán hay chưa</translation>
<translation id="9169664750068251925">Luôn chặn trên trang web này</translation>
<translation id="9170848237812810038">H&amp;oàn tác</translation>
<translation id="917450738466192189">Chứng chỉ của máy chủ không hợp lệ.</translation>
@@ -1115,7 +1121,6 @@
<translation id="9207861905230894330">Không thêm được bài viết.</translation>
<translation id="9215416866750762878">Một ứng dụng hiện không cho Chrome kết nối an toàn với trang web này</translation>
<translation id="9219103736887031265">Hình ảnh</translation>
-<translation id="933612690413056017">Không có kết nối Internet</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">XÓA BIỂU MẪU</translation>
<translation id="939736085109172342">Thư mục mới</translation>
diff --git a/chromium/components/strings/components_strings_zh-CN.xtb b/chromium/components/strings/components_strings_zh-CN.xtb
index aa0c96f28bb..ae9befc6aad 100644
--- a/chromium/components/strings/components_strings_zh-CN.xtb
+++ b/chromium/components/strings/components_strings_zh-CN.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">选择对<ph name="PERMISSION_NAME" />的权限</translation>
<translation id="1111153019813902504">最近用过的书签</translation>
<translation id="1113869188872983271">撤消顺序调整(&amp;U)</translation>
+<translation id="1125573121925420732">网站在更新其安全设置期间可能会经常显示警告。此问题应该很快就会得到改进。</translation>
<translation id="1126551341858583091">占用的本地存储空间为 <ph name="CRASH_SIZE" />。</translation>
<translation id="112840717907525620">策略缓存良好</translation>
<translation id="1150979032973867961">此服务器无法证明它是<ph name="DOMAIN" />;您计算机的操作系统不信任其安全证书。出现此问题的原因可能是配置有误或您的连接被拦截了。</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;确保您的互联网连接正常。&lt;/li&gt;
&lt;li&gt;与网站所有者联系。&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">您在一个不受贵单位管理的网站上输入了您的密码。为了保护您的帐号,请不要在其他应用和网站上重复使用您的密码。</translation>
<translation id="1263231323834454256">阅读清单</translation>
<translation id="1264126396475825575">崩溃报告获取时间:<ph name="CRASH_TIME" />(该报告尚未上传或已被忽略)</translation>
<translation id="1270502636509132238">取货方式</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">选择</translation>
<translation id="1620510694547887537">摄像头</translation>
<translation id="1623104350909869708">阻止此页创建其他对话框</translation>
-<translation id="1629803312968146339">您希望 Chrome 保存此信用卡吗?</translation>
<translation id="1639239467298939599">正在加载</translation>
<translation id="1640180200866533862">用户政策</translation>
<translation id="1640244768702815859">请尝试<ph name="BEGIN_LINK" />访问该网站的首页<ph name="END_LINK" />。</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />尝试运行 Windows 网络诊断<ph name="END_LINK" />。</translation>
<translation id="1783075131180517613">请更新您的同步密码。</translation>
<translation id="1787142507584202372">您打开的标签页会显示在此处</translation>
-<translation id="1789575671122666129">弹出式窗口</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">持卡人姓名</translation>
<translation id="1806541873155184440">添加日期:<ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">重新启动计算机</translation>
<translation id="2113977810652731515">信用卡</translation>
<translation id="2114841414352855701">由于已被 <ph name="POLICY_NAME" /> 替换,该政策已忽略。</translation>
-<translation id="2138201775715568214">正在查找附近的“实物网”网页</translation>
<translation id="213826338245044447">移动设备书签</translation>
<translation id="214556005048008348">取消付款</translation>
<translation id="2147827593068025794">后台同步</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">找不到策略</translation>
<translation id="2213606439339815911">正在获取条目…</translation>
<translation id="2218879909401188352"><ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的现有攻击者可能会安装危险应用来损害您的设备、给您的手机帐单增添隐含费用或窃取您的个人信息。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">未连接到互联网</translation>
<translation id="2230458221926704099">请使用<ph name="BEGIN_LINK" />诊断应用<ph name="END_LINK" />修复网络连接</translation>
<translation id="2239100178324503013">立即发送</translation>
<translation id="225207911366869382">适用于该政策的此值已弃用。</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">移除所选项</translation>
<translation id="277133753123645258">送货方式</translation>
<translation id="277499241957683684">缺少设备记录</translation>
+<translation id="2781030394888168909">以 MacOS 格式导出</translation>
<translation id="2784949926578158345">连接已重置。</translation>
<translation id="2788784517760473862">接受的信用卡</translation>
<translation id="2794233252405721443">网站已被屏蔽</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome 目前无法确认您的信用卡,请稍后重试。</translation>
<translation id="3064966200440839136">将要退出隐身模式,以便通过外部应用付款。是否继续?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{无}=1{1 个密码}other{# 个密码}}</translation>
-<translation id="3093245981617870298">您处于离线状态。</translation>
<translation id="3096100844101284527">添加取货地址</translation>
<translation id="3105172416063519923">资产 ID:</translation>
<translation id="3109728660330352905">您未获授权,无法查看此网页。</translation>
@@ -360,6 +360,7 @@
<translation id="3422472998109090673">目前无法访问 <ph name="HOST_NAME" />。</translation>
<translation id="3427092606871434483">允许(默认)</translation>
<translation id="3427342743765426898">恢复修改(&amp;R)</translation>
+<translation id="342781501876943858">如果您在其他网站上重复使用了您的密码,Chromium 建议您重置该密码。</translation>
<translation id="3431636764301398940">将此卡的信息保存到该设备</translation>
<translation id="3447661539832366887">此设备的所有者已关闭恐龙游戏。</translation>
<translation id="3447884698081792621">显示证书(由<ph name="ISSUER" />签发)</translation>
@@ -395,7 +396,6 @@
<translation id="3678529606614285348">在新的无痕式窗口中打开网页 (Ctrl-Shift-N)</translation>
<translation id="3679803492151881375">崩溃报告的获取时间:<ph name="CRASH_TIME" />;上传时间:<ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">证书信息</translation>
-<translation id="3690164694835360974">登录方式不安全</translation>
<translation id="3704162925118123524">您正在使用的网络可能会要求您访问其登录页面。</translation>
<translation id="3704609568417268905"><ph name="TIME" /> - <ph name="BOOKMARKED" /> - <ph name="TITLE" /> - <ph name="DOMAIN" /></translation>
<translation id="370665806235115550">正在加载...</translation>
@@ -455,7 +455,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">使用全局默认设置(检测)</translation>
<translation id="4165986682804962316">网站设置</translation>
-<translation id="4169947484918424451">您希望 Chromium 保存此信用卡吗?</translation>
<translation id="4171400957073367226">验证签名无效</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{另外 <ph name="ITEM_COUNT" /> 项}other{另外 <ph name="ITEM_COUNT" /> 项}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> - <ph name="ROW_CONTENT" /></translation>
@@ -492,6 +491,7 @@
<translation id="4275830172053184480">重启您的设备</translation>
<translation id="4277028893293644418">重置密码</translation>
<translation id="4280429058323657511">,到期日期:<ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">切换</translation>
<translation id="4312866146174492540">屏蔽(默认)</translation>
<translation id="4325863107915753736">找不到文章</translation>
<translation id="4326324639298822553">请检查您的信用卡到期日期,然后重试</translation>
@@ -499,6 +499,7 @@
<translation id="4340982228985273705">系统检测到,此计算机不是由企业管理,因此政策只能自动安装 Chrome 网上应用店中托管的扩展程序。对应的 Chrome 网上应用店更新网址为“<ph name="CWS_UPDATE_URL" />”。</translation>
<translation id="4346197816712207223">接受的信用卡</translation>
<translation id="4356973930735388585">此网站上的攻击者可能会试图在您的计算机上安装危险程序,以窃取或删除您的信息(例如:照片、密码、通讯内容和信用卡信息)。</translation>
+<translation id="4358461427845829800">管理付款方式…</translation>
<translation id="4372948949327679948">应使用<ph name="VALUE_TYPE" />值。</translation>
<translation id="4377125064752653719">您尝试访问的是 <ph name="DOMAIN" />,但服务器出示的证书已被其颁发者吊销。这表明绝对不应该信任此服务器出示的安全凭据。您可能正在与攻击者进行通信。</translation>
<translation id="4406896451731180161">搜索结果</translation>
@@ -506,6 +507,7 @@
<translation id="4415426530740016218">取货地址</translation>
<translation id="4424024547088906515">此服务器无法证明它是<ph name="DOMAIN" />;Chrome不信任其安全证书。出现此问题的原因可能是配置有误或您的连接被拦截了。</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> 不接受您的登录证书,或者您可能没有提供登录证书。</translation>
+<translation id="4434045419905280838">弹出式窗口和重定向</translation>
<translation id="443673843213245140">已停用代理,但是指定了明确的代理配置。</translation>
<translation id="445100540951337728">接受的借记卡</translation>
<translation id="4506176782989081258">验证错误:<ph name="VALIDATION_ERROR" /></translation>
@@ -540,13 +542,13 @@
<translation id="4759118997339041434">付款信息自动填充功能已停用</translation>
<translation id="4764776831041365478">网址为 <ph name="URL" /> 的网页可能暂时无法连接,或者它已永久性地移动到了新网址。</translation>
<translation id="4771973620359291008">发生未知错误。</translation>
+<translation id="4785689107224900852">切换到这个标签页</translation>
<translation id="4792143361752574037">访问会话文件时出问题了。“保存到磁盘”功能已被停用。请重新加载此页以重试。</translation>
<translation id="4800132727771399293">请检查您的到期日期和银行卡验证码 (CVC),然后重试</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">您目前无法访问 <ph name="SITE" />,因为此网站发送了 Google Chrome 无法处理的杂乱凭据。网络错误和攻击通常是暂时的,因此,此网页稍后可能会恢复正常。</translation>
<translation id="4813512666221746211">网络错误</translation>
<translation id="4816492930507672669">适合页面大小</translation>
-<translation id="483020001682031208">没有可显示的实物网网页</translation>
<translation id="4850886885716139402">视图</translation>
<translation id="4854362297993841467">该递送方式不可用。请另选一种方式。</translation>
<translation id="4858792381671956233">您已向父母发送请求,询问他们是否允许您访问此网站</translation>
@@ -586,6 +588,7 @@
<translation id="5115563688576182185">(64 位)</translation>
<translation id="5121084798328133320">在您确认之后,您的 Google Payments 帐号中的信用卡详细信息将会共享给该网站。</translation>
<translation id="5128122789703661928">无法删除此会话,因为它的名称无效。</translation>
+<translation id="5135404736266831032">管理地址…</translation>
<translation id="5141240743006678641">使用您的 Google 凭据加密已同步的密码</translation>
<translation id="5145883236150621069">策略响应中存在错误代码</translation>
<translation id="5159010409087891077">在新的无痕式窗口中打开网页 (⇧⌘N)</translation>
@@ -597,7 +600,6 @@
<translation id="5201306358585911203">此网页上的嵌入式页面显示</translation>
<translation id="5205222826937269299">需要提供名称</translation>
<translation id="5222812217790122047">需要提供电子邮件地址</translation>
-<translation id="522700295135997067">此网站可能刚刚盗取了您的密码</translation>
<translation id="5230733896359313003">送货地址</translation>
<translation id="5250209940322997802">“连接到网络”</translation>
<translation id="5251803541071282808">云端</translation>
@@ -641,7 +643,6 @@
<translation id="5492298309214877701">这个位于公司、组织或学校内网中的网站使用的网址与某个外部网站的网址相同。
<ph name="LINE_BREAK" />
请尝试与您的系统管理员联系。</translation>
-<translation id="5499929369096410817">请输入“<ph name="CREDIT_CARD" />”的安全码。系统不会保存该代码。</translation>
<translation id="5509780412636533143">受管理的书签</translation>
<translation id="5510766032865166053">该文件可能已被移至别处或遭到删除。</translation>
<translation id="5523118979700054094">政策名</translation>
@@ -672,9 +673,11 @@
<translation id="5685654322157854305">添加送货地址</translation>
<translation id="5689199277474810259">导出为 JSON 格式</translation>
<translation id="5689516760719285838">位置</translation>
+<translation id="570530837424789914">管理…</translation>
<translation id="5710435578057952990">此网站尚未经过身份验证。</translation>
<translation id="5719499550583120431">接受预付卡。</translation>
<translation id="5720705177508910913">当前用户</translation>
+<translation id="5730040223043577876">如果您在其他网站上重复使用了您的密码,Chrome 建议您重置该密码。</translation>
<translation id="5732392974455271431">您的父母可为您取消屏蔽此网站</translation>
<translation id="5763042198335101085">请输入有效的电子邮件地址</translation>
<translation id="5765072501007116331">要查看递送方式和要求,请选择相应地址</translation>
@@ -698,9 +701,7 @@
<translation id="5959728338436674663">自动向 Google 发送一些<ph name="BEGIN_WHITEPAPER_LINK" />系统信息和网页内容<ph name="END_WHITEPAPER_LINK" />,以帮助检测危险应用和网站。<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">修改联系信息</translation>
<translation id="5967867314010545767">从历史记录中移除</translation>
-<translation id="5972020793760134803">切换至标签页</translation>
<translation id="5975083100439434680">缩小</translation>
-<translation id="597552863672748783">请确认安全码</translation>
<translation id="598637245381783098">无法打开付款应用</translation>
<translation id="5989320800837274978">固定代理服务器和 .pac 脚本网址均未指定。</translation>
<translation id="5990559369517809815">对服务器的请求已遭到某个扩展程序的阻止。</translation>
@@ -716,6 +717,7 @@
<translation id="6047927260846328439">此内容可能会试图诱骗您安装软件或透露个人信息。<ph name="BEGIN_LINK" />仍然显示<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">您目前无法访问 <ph name="SITE" />,因为此网站使用了证书锁定。网络错误和攻击通常是暂时的,因此,此网页稍后可能会恢复正常。</translation>
<translation id="6059925163896151826">USB 设备</translation>
+<translation id="6071091556643036997">政策类型无效。</translation>
<translation id="6080696365213338172">您已使用管理员提供的证书访问了内容,因此管理员可以拦截您提供给 <ph name="DOMAIN" /> 的数据。</translation>
<translation id="610911394827799129">您的 Google 帐号在 <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> 上可能有其他形式的浏览记录</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{无}=1{1 个密码(已同步)}other{# 个密码(已同步)}}</translation>
@@ -751,7 +753,7 @@
<translation id="6355080345576803305">覆盖公用自助终端</translation>
<translation id="6358450015545214790">这分别意味着什么?</translation>
<translation id="6386120369904791316">{COUNT,plural, =1{1 条其他建议}other{# 条其他建议}}</translation>
-<translation id="6387754724289022810">若想在下次购物时更快捷地付款,请将您的付款卡信息和帐单邮寄地址保存到您的 Google 帐号和此设备中。</translation>
+<translation id="6387754724289022810">只要将您的付款卡信息和帐单邮寄地址保存到您的 Google 帐号和此设备,下次即可更便捷地完成付款。</translation>
<translation id="6397451950548600259">您计算机上的软件导致 Chrome 无法安全地连接到网络</translation>
<translation id="6404511346730675251">修改书签</translation>
<translation id="6410264514553301377">请输入“<ph name="CREDIT_CARD" />”的到期日期和银行卡验证码 (CVC)</translation>
@@ -762,6 +764,7 @@
<translation id="6446608382365791566">添加更多信息</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6451458296329894277">确认重新提交表单</translation>
+<translation id="6465306955648956876">管理密码…</translation>
<translation id="647261751007945333">设备政策</translation>
<translation id="6477321094435799029">Chrome 在此网页上检测到了异常代码。为保护您的个人信息(例如密码、电话号码和信用卡信息),Chrome 已将该网页拦截。</translation>
<translation id="6489534406876378309">开始上传崩溃数据</translation>
@@ -781,6 +784,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> 搜索</translation>
<translation id="6630809736994426279">攻击者可能会试图通过 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在您的 Mac 上安装危险程序,以窃取或删除您的信息(如照片、密码、通讯内容和信用卡信息)。<ph name="BEGIN_LEARN_MORE_LINK" />了解详情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">此政策已弃用。</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{无}=1{来自 1 个网站(这不会致使您退出自己的 Google 帐号)}other{来自 # 个网站(这不会致使您退出自己的 Google 帐号)}}</translation>
<translation id="6657585470893396449">密码</translation>
<translation id="6671697161687535275">要从 Chromium 中移除表单填写建议吗?</translation>
<translation id="6685834062052613830">请退出并完成设置</translation>
@@ -807,6 +811,7 @@
<translation id="6915804003454593391">用户:</translation>
<translation id="6945221475159498467">选择</translation>
<translation id="6948701128805548767">要查看取货方式和要求,请选择相应地址</translation>
+<translation id="6949872517221025916">重置密码</translation>
<translation id="6957887021205513506">该服务器的证书似乎是伪造的。</translation>
<translation id="6965382102122355670">确定</translation>
<translation id="6965978654500191972">设备</translation>
@@ -828,7 +833,7 @@
<translation id="7138472120740807366">递送方式</translation>
<translation id="7139724024395191329">酋长国</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> 种付款方式}other{<ph name="PAYMENT_METHOD_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> 种付款方式}}</translation>
-<translation id="7155487117670177674">付款方式不安全</translation>
+<translation id="717330890047184534">GAIA ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> 种送货方式}other{<ph name="SHIPPING_OPTION_PREVIEW" />以及另外 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> 种送货方式}}</translation>
<translation id="7180611975245234373">刷新</translation>
<translation id="7182878459783632708">未设置任何政策</translation>
@@ -877,6 +882,7 @@
<translation id="7455133967321480974">使用全局默认设置(阻止)</translation>
<translation id="7460163899615895653">此处将会显示您最近从其他设备打开的标签页</translation>
<translation id="7469372306589899959">确认信用卡</translation>
+<translation id="7473891865547856676">不,谢谢</translation>
<translation id="7481312909269577407">前进</translation>
<translation id="7485870689360869515">找不到数据。</translation>
<translation id="7508255263130623398">返回的政策设备 ID 为空,或与当前的设备 ID 不一致</translation>
@@ -899,7 +905,6 @@
<translation id="7569952961197462199">从 Chrome 中移除信用卡信息?</translation>
<translation id="7575800019233204241">“您的连接不是私密连接”、“&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;”、“&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;”、“&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;”或“SSL 证书错误”</translation>
<translation id="7578104083680115302">通过各种设备在网站和应用中购物时,您都可以使用 Google 为您保存的银行卡信息快速付款。</translation>
-<translation id="7588950540487816470">实物网</translation>
<translation id="7592362899630581445">服务器的证书违反了域名限制。</translation>
<translation id="7598391785903975535">少于 <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> 目前无法处理此请求。</translation>
@@ -1103,6 +1108,7 @@
<translation id="9148507642005240123">撤消修改(&amp;U)</translation>
<translation id="9154194610265714752">已更新</translation>
<translation id="9157595877708044936">正在设置...</translation>
+<translation id="9168814207360376865">允许网站检查您是否已保存付款方式</translation>
<translation id="9169664750068251925">在此网站上始终阻止</translation>
<translation id="9170848237812810038">撤消(&amp;U)</translation>
<translation id="917450738466192189">服务器证书无效。</translation>
@@ -1111,7 +1117,6 @@
<translation id="9207861905230894330">无法添加文章。</translation>
<translation id="9215416866750762878">有一款应用正在阻止 Chrome 安全地连接到此网站</translation>
<translation id="9219103736887031265">图片</translation>
-<translation id="933612690413056017">未连接到互联网</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">清除表单内容</translation>
<translation id="939736085109172342">新建文件夹</translation>
diff --git a/chromium/components/strings/components_strings_zh-TW.xtb b/chromium/components/strings/components_strings_zh-TW.xtb
index 09e1a38b767..750d0201bbd 100644
--- a/chromium/components/strings/components_strings_zh-TW.xtb
+++ b/chromium/components/strings/components_strings_zh-TW.xtb
@@ -20,6 +20,7 @@
<translation id="1110994991967754504">選取<ph name="PERMISSION_NAME" />權限設定</translation>
<translation id="1111153019813902504">最近使用過的書籤</translation>
<translation id="1113869188872983271">復原重新排序(&amp;U)</translation>
+<translation id="1125573121925420732">網站更新安全性設定期間,可能會經常顯示警告。這項行為將於近期內改善。</translation>
<translation id="1126551341858583091">佔用的本機儲存空間大小:<ph name="CRASH_SIZE" />。</translation>
<translation id="112840717907525620">政策快取正確</translation>
<translation id="1150979032973867961">伺服器無法證明其屬於 <ph name="DOMAIN" /> 網域;其安全性憑證未取得你電腦作業系統的信任。這可能是因為設定錯誤,或有攻擊者攔截你的連線所致。</translation>
@@ -49,6 +50,7 @@
&lt;li&gt;確認您的網際網路連線正常運作。&lt;/li&gt;
&lt;li&gt;與網站擁有者聯絡。&lt;/li&gt;
&lt;/ol&gt;</translation>
+<translation id="1257286744552378071">你在不是由貴機構管理的網站上輸入了你的密碼。為確保帳戶安全,請勿在其他應用程式和網站上重複使用你的密碼。</translation>
<translation id="1263231323834454256">閱讀清單</translation>
<translation id="1264126396475825575">當機報告擷取時間:<ph name="CRASH_TIME" /> (尚未上傳或略過)</translation>
<translation id="1270502636509132238">取件方式</translation>
@@ -100,7 +102,6 @@
<translation id="1594030484168838125">選擇</translation>
<translation id="1620510694547887537">攝影機</translation>
<translation id="1623104350909869708">防止這個網頁產生其他對話方塊</translation>
-<translation id="1629803312968146339">您希望 Chrome 儲存這張信用卡嗎?</translation>
<translation id="1639239467298939599">載入中</translation>
<translation id="1640180200866533862">使用者政策</translation>
<translation id="1640244768702815859">請嘗試<ph name="BEGIN_LINK" />造訪網站首頁<ph name="END_LINK" />。</translation>
@@ -128,7 +129,6 @@
<translation id="1768211456781949159"><ph name="BEGIN_LINK" />嘗試執行 Windows 網路診斷<ph name="END_LINK" />。</translation>
<translation id="1783075131180517613">請更新你的同步通關密語。</translation>
<translation id="1787142507584202372">這裡會顯示你最近開啟的分頁</translation>
-<translation id="1789575671122666129">彈出式視窗</translation>
<translation id="1791429645902722292">Google Smart Lock</translation>
<translation id="1803264062614276815">持卡人姓名</translation>
<translation id="1806541873155184440">新增日期:<ph name="ADDED_TO_AUTOFILL_MONTH" /></translation>
@@ -171,7 +171,6 @@
<translation id="2108755909498034140">重新啟動電腦</translation>
<translation id="2113977810652731515">信用卡</translation>
<translation id="2114841414352855701">由於政策被「<ph name="POLICY_NAME" />」覆寫了,因此遭到略過。</translation>
-<translation id="2138201775715568214">正在尋找附近的實體化網路網頁</translation>
<translation id="213826338245044447">行動版書籤</translation>
<translation id="214556005048008348">取消付款</translation>
<translation id="2147827593068025794">背景同步處理</translation>
@@ -188,6 +187,7 @@
<translation id="2212735316055980242">找不到政策</translation>
<translation id="2213606439339815911">正在擷取項目...</translation>
<translation id="2218879909401188352">目前在 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 上的攻擊者可能會讓你安裝不安全的應用程式,導致裝置受損、手機帳單中多出隱藏費用,或是個人資訊遭竊。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
+<translation id="2224337661447660594">沒有網際網路連線</translation>
<translation id="2230458221926704099">請使用<ph name="BEGIN_LINK" />診斷應用程式<ph name="END_LINK" />修正連線問題</translation>
<translation id="2239100178324503013">立即傳送</translation>
<translation id="225207911366869382">這個政策值已遭汰換。</translation>
@@ -262,6 +262,7 @@
<translation id="2742870351467570537">移除選取的項目</translation>
<translation id="277133753123645258">運送方式</translation>
<translation id="277499241957683684">沒有裝置記錄</translation>
+<translation id="2781030394888168909">匯出 MacOS</translation>
<translation id="2784949926578158345">連線已重設。</translation>
<translation id="2788784517760473862">接受的信用卡</translation>
<translation id="2794233252405721443">網站遭到封鎖</translation>
@@ -303,7 +304,6 @@
<translation id="3063697135517575841">Chrome 目前無法驗證您的信用卡,請稍後再試。</translation>
<translation id="3064966200440839136">即將離開無痕模式,改為使用外部應用程式付款,要繼續嗎?</translation>
<translation id="3083099961703215236">{COUNT,plural, =0{無}=1{1 組密碼}other{# 組密碼}}</translation>
-<translation id="3093245981617870298">你處於離線狀態。</translation>
<translation id="3096100844101284527">新增取件地址</translation>
<translation id="3105172416063519923">資產 ID:</translation>
<translation id="3109728660330352905">您未獲得授權,無法瀏覽這個網頁。</translation>
@@ -362,6 +362,7 @@
<translation id="3422472998109090673">目前無法連上 <ph name="HOST_NAME" />。</translation>
<translation id="3427092606871434483">允許 (預設)</translation>
<translation id="3427342743765426898">重做編輯(&amp;R)</translation>
+<translation id="342781501876943858">如果你在其他網站上重複使用過你的密碼,Chromium 會建議你重設密碼。</translation>
<translation id="3431636764301398940">將這張信用卡儲存到這個裝置</translation>
<translation id="3447661539832366887">這個裝置的擁有者已關閉恐龍遊戲。</translation>
<translation id="3447884698081792621">顯示憑證 (核發者:<ph name="ISSUER" />)</translation>
@@ -398,7 +399,6 @@
<translation id="3678529606614285348">在新的無痕式視窗中開啟網頁 (Ctrl + Shift + N 鍵)</translation>
<translation id="3679803492151881375">當機報告擷取時間:<ph name="CRASH_TIME" />,報告上傳時間:<ph name="UPLOAD_TIME" /></translation>
<translation id="3681007416295224113">憑證資訊</translation>
-<translation id="3690164694835360974">登入行為不安全</translation>
<translation id="3704162925118123524">您可能需要造訪目前所使用網路的登入網頁。</translation>
<translation id="3704609568417268905"><ph name="TIME" />,<ph name="BOOKMARKED" />,<ph name="TITLE" />,<ph name="DOMAIN" /></translation>
<translation id="370665806235115550">載入中…</translation>
@@ -458,7 +458,6 @@
<translation id="4148925816941278100">American Express</translation>
<translation id="4151403195736952345">使用全域預設設定 (偵測)</translation>
<translation id="4165986682804962316">網站設定</translation>
-<translation id="4169947484918424451">您希望 Chromium 儲存這張信用卡嗎?</translation>
<translation id="4171400957073367226">驗證簽名無效</translation>
<translation id="4173827307318847180">{MORE_ITEMS,plural, =1{還有另外 <ph name="ITEM_COUNT" /> 個項目}other{還有另外 <ph name="ITEM_COUNT" /> 個項目}}</translation>
<translation id="4179515394835346607"><ph name="ROW_NAME" /> <ph name="ROW_CONTENT" /></translation>
@@ -495,6 +494,7 @@
<translation id="4275830172053184480">重新啟動裝置</translation>
<translation id="4277028893293644418">重設密碼</translation>
<translation id="4280429058323657511">,到期日:<ph name="EXPIRATION_DATE_ABBR" /></translation>
+<translation id="4305817255990598646">切換</translation>
<translation id="4312866146174492540">封鎖 (預設)</translation>
<translation id="4325863107915753736">找不到文章</translation>
<translation id="4326324639298822553">請檢查信用卡到期日,然後再試一次</translation>
@@ -502,6 +502,7 @@
<translation id="4340982228985273705">系統偵測結果顯示這台電腦未受企業管理,因此政策只能自動安裝透過 Chrome 線上應用程式商店代管的擴充功能。Chrome 線上應用程式商店更新網址為「<ph name="CWS_UPDATE_URL" />」。</translation>
<translation id="4346197816712207223">接受的信用卡</translation>
<translation id="4356973930735388585">攻擊者可能會試圖透過這個網站在你的電腦上安裝危險程式,藉此竊取或刪除你的資訊 (例如相片、密碼、郵件和信用卡資料)。</translation>
+<translation id="4358461427845829800">管理付款方式...</translation>
<translation id="4372948949327679948">預期的「<ph name="VALUE_TYPE" />」值。</translation>
<translation id="4377125064752653719">你嘗試前往 <ph name="DOMAIN" />,但是發行者已撤銷伺服器提供的憑證。在這種情況下,請勿信任伺服器提供的安全性憑證,因為你的連線對象可能是攻擊者的電腦。</translation>
<translation id="4406896451731180161">搜尋結果</translation>
@@ -509,6 +510,7 @@
<translation id="4415426530740016218">取件地址</translation>
<translation id="4424024547088906515">伺服器無法證明其屬於 <ph name="DOMAIN" /> 網域;其安全性憑證未取得 Chrome 的信任。這可能是因為設定錯誤,或有攻擊者攔截你的連線所致。</translation>
<translation id="4432688616882109544"><ph name="HOST_NAME" /> 不接受你的登入憑證,或是你可能未提供登入憑證。</translation>
+<translation id="4434045419905280838">彈出式視窗與重新導向</translation>
<translation id="443673843213245140">雖然已停用 Proxy,不過已指定明確 Proxy 設定。</translation>
<translation id="445100540951337728">接受的簽帳金融卡</translation>
<translation id="4506176782989081258">驗證錯誤:<ph name="VALIDATION_ERROR" /></translation>
@@ -543,13 +545,13 @@
<translation id="4759118997339041434">付款資訊自動填入功能已停用</translation>
<translation id="4764776831041365478"><ph name="URL" /> 的網頁可能暫時無法使用或被永久移至新網址。</translation>
<translation id="4771973620359291008">發生不明的錯誤。</translation>
+<translation id="4785689107224900852">切換至這個分頁</translation>
<translation id="4792143361752574037">存取工作階段檔案時發生問題,目前無法將檔案儲存到磁碟。請重新載入網頁,然後再試一次。</translation>
<translation id="4800132727771399293">請檢查您的有效期限和信用卡安全碼,然後再試一次</translation>
<translation id="4803924862070940586"><ph name="CURRENCY_CODE" /> <ph name="FORMATTED_TOTAL_AMOUNT" /></translation>
<translation id="4807049035289105102">您目前無法造訪 <ph name="SITE" />,因為這個網站傳送的憑證是亂碼,Google Chrome 無法處理。網路錯誤和攻擊行為通常是暫時性的,因此這個網頁可能稍後就會正常運作。</translation>
<translation id="4813512666221746211">網路錯誤</translation>
<translation id="4816492930507672669">依頁面大小自動調整</translation>
-<translation id="483020001682031208">沒有可顯示的實體化網路頁面</translation>
<translation id="4850886885716139402">檢視</translation>
<translation id="4854362297993841467">不支援所選的快遞方式,請改選其他方式。</translation>
<translation id="4858792381671956233">你已詢問家長是否同意你造訪這個網站</translation>
@@ -589,6 +591,7 @@
<translation id="5115563688576182185">(64 位元)</translation>
<translation id="5121084798328133320">完成驗證後,這個網站就會取得你 Google 付款帳戶中的信用卡詳細資料。</translation>
<translation id="5128122789703661928">無法將使用這個名稱的工作階段刪除。</translation>
+<translation id="5135404736266831032">管理地址...</translation>
<translation id="5141240743006678641">使用你的 Google 憑證對已同步處理的密碼進行加密</translation>
<translation id="5145883236150621069">政策回應中存在錯誤代碼</translation>
<translation id="5159010409087891077">在新的無痕式視窗中開啟網頁 (⇧ + ⌘ + N 鍵)</translation>
@@ -600,7 +603,6 @@
<translation id="5201306358585911203">這個網頁上的嵌入式網頁顯示</translation>
<translation id="5205222826937269299">請輸入名稱</translation>
<translation id="5222812217790122047">請輸入電子郵件地址</translation>
-<translation id="522700295135997067">這個網站剛剛可能竊取了你的密碼</translation>
<translation id="5230733896359313003">運送地址</translation>
<translation id="5250209940322997802">「連線至網路」</translation>
<translation id="5251803541071282808">雲端</translation>
@@ -644,7 +646,6 @@
<translation id="5492298309214877701">這個位於公司、機構或學校內部網路的網站使用的網址與某個外部網站相同。
<ph name="LINE_BREAK" />
請與您的系統管理員聯絡。</translation>
-<translation id="5499929369096410817">輸入 <ph name="CREDIT_CARD" /> 的安全碼 (系統不會加以儲存)。</translation>
<translation id="5509780412636533143">受管理書籤</translation>
<translation id="5510766032865166053">檔案可能已移至其他位置或遭到刪除。</translation>
<translation id="5523118979700054094">政策名稱</translation>
@@ -675,9 +676,11 @@
<translation id="5685654322157854305">新增運送地址</translation>
<translation id="5689199277474810259">以 JSON 格式匯出</translation>
<translation id="5689516760719285838">位置</translation>
+<translation id="570530837424789914">管理...</translation>
<translation id="5710435578057952990">此網頁的身分未經驗證。</translation>
<translation id="5719499550583120431">接受預付卡。</translation>
<translation id="5720705177508910913">目前使用者</translation>
+<translation id="5730040223043577876">如果你在其他網站上重複使用過你的密碼,Chrome 會建議你重設密碼。</translation>
<translation id="5732392974455271431">你的家長可以為你解除封鎖這個網站</translation>
<translation id="5763042198335101085">請輸入有效的電子郵件地址</translation>
<translation id="5765072501007116331">如要查看快遞方式和相關規定,請選取一個地址</translation>
@@ -701,9 +704,7 @@
<translation id="5959728338436674663">自動傳送部分<ph name="BEGIN_WHITEPAPER_LINK" />系統資訊和網頁內容<ph name="END_WHITEPAPER_LINK" />給 Google,協助偵測危險的應用程式和網站。<ph name="PRIVACY_PAGE_LINK" /></translation>
<translation id="5967592137238574583">編輯聯絡資訊</translation>
<translation id="5967867314010545767">從記錄中移除</translation>
-<translation id="5972020793760134803">切換至分頁</translation>
<translation id="5975083100439434680">縮小</translation>
-<translation id="597552863672748783">確認安全碼</translation>
<translation id="598637245381783098">無法開啟付款應用程式</translation>
<translation id="5989320800837274978">沒有指定固定的 Proxy 伺服器和 .pac 指令碼網址。</translation>
<translation id="5990559369517809815">擴充功能已封鎖要傳送至伺服器的要求。</translation>
@@ -719,6 +720,7 @@
<translation id="6047927260846328439">這項內容可能會試圖誘使你安裝軟體或提供個人資訊。<ph name="BEGIN_LINK" />仍要顯示<ph name="END_LINK" /></translation>
<translation id="6051221802930200923">目前無法造訪 <ph name="SITE" />,因為這個網站使用憑證鎖定功能。網路錯誤和攻擊行為通常是暫時性的,因此這個網頁可能稍後就會恢復正常狀態。</translation>
<translation id="6059925163896151826">USB 裝置</translation>
+<translation id="6071091556643036997">政策類型無效。</translation>
<translation id="6080696365213338172">你使用了管理員提供的憑證存取內容,因此管理員可攔截你傳送至「<ph name="DOMAIN" />」的資料。</translation>
<translation id="610911394827799129">你的 Google 帳戶仍可能保留了其他類型的瀏覽記錄 (可前往 <ph name="BEGIN_LINK" />myactivity.google.com<ph name="END_LINK" /> 查詢)。</translation>
<translation id="6144381551823904650">{COUNT,plural, =0{無}=1{1 組密碼 (保持同步)}other{# 組密碼 (保持同步)}}</translation>
@@ -766,6 +768,7 @@
<translation id="6446608382365791566">新增詳細資訊</translation>
<translation id="6447842834002726250">Cookie</translation>
<translation id="6451458296329894277">確認重新提交表單</translation>
+<translation id="6465306955648956876">管理密碼...</translation>
<translation id="647261751007945333">裝置政策</translation>
<translation id="6477321094435799029">Chrome 在這個網頁上偵測到異常代碼。為了保護你的個人資訊 (包括密碼、電話號碼或信用卡資料),Chrome 已封鎖這個網頁。</translation>
<translation id="6489534406876378309">開始上傳當機報告</translation>
@@ -785,6 +788,7 @@
<translation id="6628463337424475685"><ph name="ENGINE" /> 搜尋</translation>
<translation id="6630809736994426279">攻擊者目前可能會試圖透過 <ph name="BEGIN_BOLD" /><ph name="SITE" /><ph name="END_BOLD" /> 在你的 Mac 上安裝危險程式,藉此竊取或刪除你的資訊 (例如相片、密碼、郵件和信用卡資料)。<ph name="BEGIN_LEARN_MORE_LINK" />瞭解詳情<ph name="END_LEARN_MORE_LINK" /></translation>
<translation id="6644283850729428850">這項政策已遭取代。</translation>
+<translation id="6646269444027925224">{COUNT,plural, =0{無}=1{1 個網站 (你不會因此登出 Google 帳戶)}other{# 個網站 (你不會因此登出 Google 帳戶)}}</translation>
<translation id="6657585470893396449">密碼</translation>
<translation id="6671697161687535275">要從 Chromium 中移除表單填寫建議嗎?</translation>
<translation id="6685834062052613830">請登出並完成設定程序</translation>
@@ -811,6 +815,7 @@
<translation id="6915804003454593391">使用者:</translation>
<translation id="6945221475159498467">選取</translation>
<translation id="6948701128805548767">如要查看取件方式和相關規定,請選取一個地址</translation>
+<translation id="6949872517221025916">重設密碼</translation>
<translation id="6957887021205513506">伺服器憑證疑似偽造。</translation>
<translation id="6965382102122355670">確定</translation>
<translation id="6965978654500191972">裝置</translation>
@@ -832,7 +837,7 @@
<translation id="7138472120740807366">快遞方式</translation>
<translation id="7139724024395191329">大公國</translation>
<translation id="7153549335910886479">{PAYMENT_METHOD,plural, =0{<ph name="PAYMENT_METHOD_PREVIEW" />}=1{<ph name="PAYMENT_METHOD_PREVIEW" /> 和另外 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> 種付款方式}other{<ph name="PAYMENT_METHOD_PREVIEW" /> 和另外 <ph name="NUMBER_OF_ADDITIONAL_PAYMENT_METHODS" /> 種付款方式}}</translation>
-<translation id="7155487117670177674">付款行為不安全</translation>
+<translation id="717330890047184534">GAIA ID:</translation>
<translation id="7175401108899573750">{SHIPPING_OPTIONS,plural, =0{<ph name="SHIPPING_OPTION_PREVIEW" />}=1{<ph name="SHIPPING_OPTION_PREVIEW" />和另外 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> 種選項}other{<ph name="SHIPPING_OPTION_PREVIEW" />和另外 <ph name="NUMBER_OF_ADDITIONAL_SHIPPING_OPTIONS" /> 種選項}}</translation>
<translation id="7180611975245234373">重新整理</translation>
<translation id="7182878459783632708">沒有設定任何政策</translation>
@@ -881,6 +886,7 @@
<translation id="7455133967321480974">使用全域預設值 (封鎖)</translation>
<translation id="7460163899615895653">你最近在其他裝置上開啟的分頁會顯示在這裡</translation>
<translation id="7469372306589899959">正在驗證信用卡</translation>
+<translation id="7473891865547856676">不用了,謝謝</translation>
<translation id="7481312909269577407">往前</translation>
<translation id="7485870689360869515">找不到任何資料。</translation>
<translation id="7508255263130623398">傳回的政策裝置 ID 沒有任何內容,或是與目前的裝置 ID 不符</translation>
@@ -903,7 +909,6 @@
<translation id="7569952961197462199">要從 Chrome 中移除信用卡嗎?</translation>
<translation id="7575800019233204241">「你的連線不是私人連線」、「&lt;span class="error-code"&gt;NET::ERR_CERT_AUTHORITY_INVALID&lt;/span&gt;」、「&lt;span class="error-code"&gt;ERR_CERT_COMMON_NAME_INVALID&lt;/span&gt;」、「&lt;span class="error-code"&gt;NET::ERR_CERT_WEAK_SIGNATURE_ALGORITHM&lt;/span&gt;」或「SSL 憑證錯誤」</translation>
<translation id="7578104083680115302">在不同的裝置上透過各個網站和應用程式消費時,使用您讓 Google 儲存的信用卡資料即可快速付款。</translation>
-<translation id="7588950540487816470">實體化網路</translation>
<translation id="7592362899630581445">伺服器憑證的名稱不符合限制。</translation>
<translation id="7598391785903975535">不到 <ph name="UPPER_ESTIMATE" /></translation>
<translation id="759889825892636187"><ph name="HOST_NAME" /> 目前無法處理這項要求。</translation>
@@ -1106,6 +1111,7 @@
<translation id="9148507642005240123">復原編輯(&amp;U)</translation>
<translation id="9154194610265714752">已更新</translation>
<translation id="9157595877708044936">設定中...</translation>
+<translation id="9168814207360376865">允許網站檢查付款方式是否已成功儲存</translation>
<translation id="9169664750068251925">永遠禁止在這個網站執行</translation>
<translation id="9170848237812810038">取消(&amp;U)</translation>
<translation id="917450738466192189">伺服器憑證無效。</translation>
@@ -1114,7 +1120,6 @@
<translation id="9207861905230894330">無法新增文章。</translation>
<translation id="9215416866750762878">有應用程式阻止 Chrome 建立這個網站的安全連線</translation>
<translation id="9219103736887031265">圖片</translation>
-<translation id="933612690413056017">無法連上網際網路</translation>
<translation id="933712198907837967">Diners Club</translation>
<translation id="935608979562296692">清除表單</translation>
<translation id="939736085109172342">新增資料夾</translation>
diff --git a/chromium/components/subresource_filter/FILTER_LIST_GENERATION.md b/chromium/components/subresource_filter/FILTER_LIST_GENERATION.md
new file mode 100644
index 00000000000..95aff54cb74
--- /dev/null
+++ b/chromium/components/subresource_filter/FILTER_LIST_GENERATION.md
@@ -0,0 +1,91 @@
+# Generating a Smaller Filter List
+Filter lists can be quite large to store in memory, which is problematic on
+memory constrained devices. The following steps demonstrate how to generate a
+smaller filter list by filtering out the least-frequently-used rules on the top
+N websites (according to Alexa rankings).
+
+## 1. Gather the URL requests from the landing pages of the top N sites
+This data is made available by the [HttpArchive](https://httparchive.org/)
+project and is queryable via [BigQuery](https://bigquery.cloud.google.com/). A
+short introduction to querying HttpArchive data is available
+[here](https://www.igvita.com/2013/06/20/http-archive-bigquery-web-performance-answers/).
+Because the output of our query is typically quite large, it's necessary to
+have a Google Compute Engine account with a storage bucket created to write
+the resulting table to.
+
+The query to run is:
+```sql
+SELECT
+ pages.url AS origin,
+ requests.url AS request_url,
+ requests.type AS request_type
+FROM
+ [httparchive:summary_requests.$ARCHIVE_DATE_AND_TYPE] AS requests
+INNER JOIN (
+ SELECT
+ pageid,
+ url
+ FROM
+ [httparchive:summary_pages.$ARCHIVE_DATE_AND_TYPE]
+ WHERE
+ rank IS NOT NULL
+ AND rank <= $MAX_RANK) AS pages
+ON
+ requests.pageid = pages.pageid;
+```
+
+You'll need to replace `$ARCHIVE_DATE_AND_TYPE` with the table you're
+interested, such as `2018.04_15_mobile`. Replace `$MAX_RANK` with the highest
+ranked Alexa page you want to process (e.g., `100000`).
+
+In the above query, the URLs from the top 100,000 sites are output. Change
+100,000 to whichever value you wish. Since the output is too large to display
+on the page, the results will need to be written to a table in your Google
+Cloud Project. To do this, press the 'show options' button below your query, and press the
+'select table' button to create a table to write to in your project. You'll
+also want to check the 'allow large results' checkbox.
+
+Now run the query. The results should be available in the table you specified
+in your project. Find the table on the BigQuery page and export it in JSON
+format to a bucket that you create in your Google Cloud Storage. Since files
+in buckets are restricted to 1GB, you'll have to shard the file over many
+files. Select gzip compression and use `<your_bucket>/site_urls.*.json.gz` as
+your destination.
+
+Once exported, you can download the files from your bucket and extract them
+into a single file for processing:
+
+```sh
+ls site_urls.*.gz | xargs gunzip -c > site_urls
+```
+
+## 2. Acquire a filter list in the indexed format
+Chromium's tools are designed to work with a binary indexed version of filter
+lists. You can use the `subresource_indexing_tool` to convert a text based
+filter list to an indexed file.
+
+An example using [EasyList](https://easylist.to/easylist/easylist.txt) follows:
+
+```sh
+1. ninja -C out/Release/ subresource_filter_tools
+2. wget https://easylist.to/easylist/easylist.txt
+3. out/Release/ruleset_converter --input_format=filter-list --output_format=unindexed-ruleset --input_files=easylist.txt --output_file=easylist_unindexed
+4. out/Release/subresource_indexing_tool easylist_unindexed easylist_indexed
+```
+
+## 3. Generate the smaller filter list
+```sh
+1. ninja -C out/Release subresource_filter_tools
+2. out/Release/subresource_filter_tool --ruleset=easylist_indexed match_rules --input_file=site_urls --min_matches=1 > smaller_list.txt
+```
+
+With `min_matches=1`, the rule will be included if it's used at least once while testing each URL from site_urls.
+
+## 4. Turn the smaller list into a form usable by Chromium tools
+The smaller filterlist has been generated. If you'd like to convert it to Chromium's binary indexed format, proceed with the following steps:
+
+```sh
+1. ninja -C out/Release/ subresource_filter_tools
+2. out/Release/ruleset_converter --input_format=filter-list --output_format=unindexed-ruleset --input_files=smaller_list.txt --output_file=smaller_list_unindexed
+3. out/Release/subresource_indexing_tool smaller_list_unindexed smaller_list_indexed
+```
diff --git a/chromium/components/subresource_filter/OWNERS b/chromium/components/subresource_filter/OWNERS
index 2fadb14a6ee..6def5ee117f 100644
--- a/chromium/components/subresource_filter/OWNERS
+++ b/chromium/components/subresource_filter/OWNERS
@@ -1,5 +1,8 @@
battre@chromium.org
csharrison@chromium.org
engedy@chromium.org
+jkarlin@chromium.org
melandory@chromium.org
pkalinnikov@chromium.org
+
+# COMPONENT: UI>Browser>AdFilter \ No newline at end of file
diff --git a/chromium/components/subresource_filter/content/browser/BUILD.gn b/chromium/components/subresource_filter/content/browser/BUILD.gn
index cb859b74115..ae37f91fdda 100644
--- a/chromium/components/subresource_filter/content/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/content/browser/BUILD.gn
@@ -16,6 +16,8 @@ static_library("browser") {
"content_subresource_filter_driver_factory.h",
"content_subresource_filter_throttle_manager.cc",
"content_subresource_filter_throttle_manager.h",
+ "navigation_console_logger.cc",
+ "navigation_console_logger.h",
"page_load_statistics.cc",
"page_load_statistics.h",
"subframe_navigation_filtering_throttle.cc",
@@ -40,6 +42,7 @@ static_library("browser") {
"//components/subresource_filter/content/common",
"//components/subresource_filter/core/browser",
"//components/subresource_filter/core/common",
+ "//components/ukm:ukm",
"//content/public/browser",
"//content/public/common",
"//ipc",
@@ -47,6 +50,7 @@ static_library("browser") {
"//url",
]
public_deps = [
+ "//third_party/flatbuffers:flatbuffers",
"//ui/base",
]
}
@@ -82,6 +86,7 @@ source_set("unit_tests") {
"async_document_subresource_filter_unittest.cc",
"content_ruleset_service_unittest.cc",
"content_subresource_filter_throttle_manager_unittest.cc",
+ "navigation_console_logger_unittest.cc",
"subframe_navigation_filtering_throttle_unittest.cc",
"subresource_filter_safe_browsing_activation_throttle_unittest.cc",
"verified_ruleset_dealer_unittest.cc",
@@ -97,6 +102,8 @@ source_set("unit_tests") {
"//components/subresource_filter/core/browser:test_support",
"//components/subresource_filter/core/common",
"//components/subresource_filter/core/common:test_support",
+ "//components/ukm:test_support",
+ "//components/ukm/content:content",
"//content/test:test_support",
"//ipc",
"//ipc:test_support",
diff --git a/chromium/components/subresource_filter/content/browser/DEPS b/chromium/components/subresource_filter/content/browser/DEPS
index a5d03b57e1d..14df806edc7 100644
--- a/chromium/components/subresource_filter/content/browser/DEPS
+++ b/chromium/components/subresource_filter/content/browser/DEPS
@@ -1,6 +1,8 @@
include_rules = [
"+components/safe_browsing/db",
+ "+components/ukm",
"+content/public/browser",
"+net/base",
+ "+services/metrics/public/cpp",
"+ui/base/page_transition_types.h",
]
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
index a2719dae604..ca6da218883 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.cc
@@ -52,10 +52,7 @@ ActivationStateComputingNavigationThrottle::
weak_ptr_factory_(this) {}
ActivationStateComputingNavigationThrottle::
- ~ActivationStateComputingNavigationThrottle() {
- if (!destruction_closure_.is_null())
- std::move(destruction_closure_).Run();
-}
+ ~ActivationStateComputingNavigationThrottle() = default;
void ActivationStateComputingNavigationThrottle::
NotifyPageActivationWithRuleset(
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
index 98a08e1e3e4..a9f0dabdd7d 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h
@@ -67,10 +67,6 @@ class ActivationStateComputingNavigationThrottle
VerifiedRuleset::Handle* ruleset_handle,
const ActivationState& page_activation_state);
- void set_destruction_closure(base::OnceClosure closure) {
- destruction_closure_ = std::move(closure);
- }
-
// content::NavigationThrottle:
content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override;
content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest()
@@ -121,9 +117,6 @@ class ActivationStateComputingNavigationThrottle
// deferred.
std::unique_ptr<base::ElapsedTimer> defer_timer_;
- // Callback to be run in the destructor.
- base::OnceClosure destruction_closure_;
-
// Will become true when the throttle manager reaches ReadyToCommitNavigation.
// Makes sure a caller cannot take ownership of the subresource filter unless
// the throttle has reached this point. After this point the throttle manager
diff --git a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
index e8d85a80855..0a0142b7a7f 100644
--- a/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/activation_state_computing_navigation_throttle_unittest.cc
@@ -21,6 +21,7 @@
#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
#include "components/subresource_filter/core/common/activation_level.h"
#include "components/subresource_filter/core/common/activation_state.h"
+#include "components/subresource_filter/core/common/scoped_timers.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
#include "components/url_pattern_index/proto/rules.pb.h"
@@ -32,6 +33,19 @@
namespace subresource_filter {
+namespace {
+
+// Histogram name on thread timers. Please, use |ExpectThreadTimers| for
+// expectation calls corrections.
+constexpr char kActivationCPU[] =
+ "SubresourceFilter.DocumentLoad.Activation.CPUDuration";
+
+int ExpectThreadTimers(int expected) {
+ return ScopedThreadTimers::IsSupported() ? expected : 0;
+}
+
+} // namespace
+
namespace proto = url_pattern_index::proto;
// The tests are parameterized by a bool which enables speculative main frame
@@ -501,27 +515,28 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, DelayMetrics) {
TEST_P(ActivationStateComputingThrottleSubFrameTest, Speculation) {
// Use the activation performance metric as a proxy for how many times
// activation computation occurred.
- const char kActivationCPU[] =
- "SubresourceFilter.DocumentLoad.Activation.CPUDuration";
+ base::HistogramTester main_histogram_tester;
// Main frames don't do speculative lookups, a navigation commit should only
// trigger a single ruleset lookup.
- base::HistogramTester main_histogram_tester;
CreateTestNavigationForMainFrame(GURL("http://example.test/"));
SimulateStartAndExpectToProceed();
base::RunLoop().RunUntilIdle();
int main_frame_checks = dryrun_speculation() ? 1 : 0;
- main_histogram_tester.ExpectTotalCount(kActivationCPU, main_frame_checks);
+ main_histogram_tester.ExpectTotalCount(kActivationCPU,
+ ExpectThreadTimers(main_frame_checks));
SimulateRedirectAndExpectToProceed(GURL("http://example.test2/"));
base::RunLoop().RunUntilIdle();
main_frame_checks += dryrun_speculation() ? 1 : 0;
- main_histogram_tester.ExpectTotalCount(kActivationCPU, main_frame_checks);
+ main_histogram_tester.ExpectTotalCount(kActivationCPU,
+ ExpectThreadTimers(main_frame_checks));
NotifyPageActivation(ActivationState(ActivationLevel::ENABLED));
SimulateCommitAndExpectToProceed();
main_frame_checks += dryrun_speculation() ? 0 : 1;
- main_histogram_tester.ExpectTotalCount(kActivationCPU, main_frame_checks);
+ main_histogram_tester.ExpectTotalCount(kActivationCPU,
+ ExpectThreadTimers(main_frame_checks));
base::HistogramTester sub_histogram_tester;
CreateSubframeAndInitTestNavigation(GURL("http://example.test/"),
@@ -530,16 +545,16 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, Speculation) {
// For subframes, do a ruleset lookup at the start and every redirect.
SimulateStartAndExpectToProceed();
base::RunLoop().RunUntilIdle();
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, 1);
+ sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(1));
SimulateRedirectAndExpectToProceed(GURL("http://example.test2/"));
base::RunLoop().RunUntilIdle();
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, 2);
+ sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
// No ruleset lookup required at commit because we've already checked the
// latest URL.
SimulateCommitAndExpectToProceed();
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, 2);
+ sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
}
TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
@@ -548,8 +563,6 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
// Use the activation performance metric as a proxy for how many times
// activation computation occurred.
base::HistogramTester main_histogram_tester;
- const char kActivationCPU[] =
- "SubresourceFilter.DocumentLoad.Activation.CPUDuration";
// Main frames will do speculative lookup only in some cases.
auto simulator = content::NavigationSimulator::CreateRendererInitiated(
@@ -571,8 +584,8 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
simple_task_runner()->RunPendingTasks();
// If speculation was enabled for this test, will do a lookup at start and
// redirect.
- main_histogram_tester.ExpectTotalCount(kActivationCPU,
- dryrun_speculation() ? 2 : 1);
+ main_histogram_tester.ExpectTotalCount(
+ kActivationCPU, ExpectThreadTimers(dryrun_speculation() ? 2 : 1));
simulator->Wait();
EXPECT_FALSE(simulator->IsDeferred());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
@@ -611,7 +624,7 @@ TEST_P(ActivationStateComputingThrottleSubFrameTest, SpeculationWithDelay) {
EXPECT_FALSE(subframe_simulator->IsDeferred());
EXPECT_EQ(content::NavigationThrottle::PROCEED,
simulator->GetLastThrottleCheckResult());
- sub_histogram_tester.ExpectTotalCount(kActivationCPU, 2);
+ sub_histogram_tester.ExpectTotalCount(kActivationCPU, ExpectThreadTimers(2));
}
INSTANTIATE_TEST_CASE_P(,
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
index 9a84f384585..4122bd637f4 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.cc
@@ -7,8 +7,8 @@
#include <utility>
#include "base/metrics/histogram_macros.h"
-#include "base/rand_util.h"
#include "base/time/time.h"
+#include "components/subresource_filter/content/browser/navigation_console_logger.h"
#include "components/subresource_filter/content/browser/page_load_statistics.h"
#include "components/subresource_filter/content/browser/subresource_filter_client.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
@@ -32,14 +32,6 @@ namespace {
// Returns true with a probability given by |performance_measurement_rate| if
// ThreadTicks is supported, otherwise returns false.
-bool ShouldMeasurePerformanceForPageLoad(double performance_measurement_rate) {
- if (!base::ThreadTicks::IsSupported())
- return false;
- return performance_measurement_rate == 1 ||
- (performance_measurement_rate > 0 &&
- base::RandDouble() < performance_measurement_rate);
-}
-
} // namespace
// static
@@ -82,9 +74,12 @@ void ContentSubresourceFilterDriverFactory::NotifyPageActivationComputed(
matched_configuration_ = matched_configuration;
DCHECK_NE(activation_decision_, ActivationDecision::UNKNOWN);
+ ActivationLevel effective_activation_level =
+ matched_configuration_.activation_options.activation_level;
+
// ACTIVATION_DISABLED implies DISABLED activation level.
DCHECK(activation_decision_ != ActivationDecision::ACTIVATION_DISABLED ||
- activation_options().activation_level == ActivationLevel::DISABLED);
+ effective_activation_level == ActivationLevel::DISABLED);
// Ensure the matched config is in our config list. If it wasn't then this
// must be a forced activation via devtools.
@@ -95,35 +90,24 @@ void ContentSubresourceFilterDriverFactory::NotifyPageActivationComputed(
forced_activation_via_devtools)
<< matched_configuration;
- ActivationState state =
- ActivationState(activation_options().activation_level);
- state.measure_performance = ShouldMeasurePerformanceForPageLoad(
- activation_options().performance_measurement_rate);
-
- // This bit keeps track of BAS enforcement-style logging, not warning logging.
- state.enable_logging =
- activation_options().activation_level == ActivationLevel::ENABLED &&
- !activation_options().should_suppress_notifications &&
- matched_configuration != Configuration::MakeForForcedActivation() &&
- base::FeatureList::IsEnabled(
- kSafeBrowsingSubresourceFilterExperimentalUI);
-
- if (warning &&
- activation_options().activation_level == ActivationLevel::ENABLED) {
- DCHECK(on_commit_warning_messages_.empty());
- SetOnCommitWarningMessages();
+ if (warning && effective_activation_level == ActivationLevel::ENABLED) {
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation_handle, content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ kActivationWarningConsoleMessage);
+
// Do not disallow enforcement if activated via devtools.
if (!forced_activation_via_devtools) {
activation_decision_ = ActivationDecision::ACTIVATION_DISABLED;
- state.activation_level = ActivationLevel::DISABLED;
- matched_configuration_.activation_options.activation_level =
- ActivationLevel::DISABLED;
+ effective_activation_level = ActivationLevel::DISABLED;
}
}
+ matched_configuration_.activation_options.activation_level =
+ effective_activation_level;
SubresourceFilterObserverManager::FromWebContents(web_contents())
->NotifyPageActivationComputed(navigation_handle, activation_decision_,
- state);
+ matched_configuration_.GetActivationState(
+ effective_activation_level));
}
void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
@@ -132,13 +116,6 @@ void ContentSubresourceFilterDriverFactory::OnFirstSubresourceLoadDisallowed() {
"SubresourceFilter.PageLoad.ForcedActivation.DisallowedLoad", true);
return;
}
- if (activation_options().should_suppress_notifications)
- return;
- // This shouldn't happen normally, but in the rare case that an IPC from a
- // previous page arrives late we should guard against it.
- if (activation_options().activation_level != ActivationLevel::ENABLED) {
- return;
- }
client_->ShowNotification();
}
@@ -154,38 +131,14 @@ void ContentSubresourceFilterDriverFactory::DidStartNavigation(
void ContentSubresourceFilterDriverFactory::DidFinishNavigation(
content::NavigationHandle* navigation_handle) {
if (!navigation_handle->IsInMainFrame() ||
- navigation_handle->IsSameDocument()) {
+ navigation_handle->IsSameDocument() ||
+ !navigation_handle->HasCommitted()) {
return;
}
- std::vector<std::string> log_messages =
- std::move(on_commit_warning_messages_);
-
- if (!navigation_handle->HasCommitted())
- return;
-
- DCHECK(on_commit_warning_messages_.empty());
-
if (activation_decision_ == ActivationDecision::UNKNOWN) {
activation_decision_ = ActivationDecision::ACTIVATION_DISABLED;
matched_configuration_ = Configuration();
- return;
- }
-
- content::RenderFrameHost* frame_host =
- navigation_handle->GetRenderFrameHost();
- for (auto& warning_message : log_messages) {
- frame_host->AddMessageToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING,
- warning_message);
- }
-}
-
-void ContentSubresourceFilterDriverFactory::SetOnCommitWarningMessages() {
- DCHECK_EQ(ActivationLevel::ENABLED, activation_options().activation_level);
- // If the matched configuration *would have* triggered resource blocking,
- // log a warning.
- if (!activation_options().should_suppress_notifications) {
- on_commit_warning_messages_.push_back(kActivationWarningConsoleMessage);
}
}
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
index 3073dc6765b..0659e573e1d 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h
@@ -53,15 +53,6 @@ class ContentSubresourceFilterDriverFactory
const Configuration& matched_configuration,
bool warning);
- // Returns whether or not the current WebContents is allowed to create a new
- // window.
- bool ShouldDisallowNewWindow(const content::OpenURLParams* open_url_params);
-
- // Returns the Configuration for the current main frame document.
- const Configuration& GetMatchedConfigurationForLastCommittedPageLoad() const {
- return matched_configuration_;
- }
-
// ContentSubresourceFilterThrottleManager::Delegate:
void OnFirstSubresourceLoadDisallowed() override;
@@ -75,18 +66,12 @@ class ContentSubresourceFilterDriverFactory
friend class ContentSubresourceFilterDriverFactoryTest;
friend class safe_browsing::SafeBrowsingServiceTest;
- const Configuration::ActivationOptions& activation_options() const {
- return matched_configuration_.activation_options;
- }
-
// content::WebContentsObserver:
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
- void SetOnCommitWarningMessages();
-
// Must outlive this class.
SubresourceFilterClient* client_;
@@ -116,11 +101,6 @@ class ContentSubresourceFilterDriverFactory
// changing the config (e.g. for forcing devtools activation).
Configuration matched_configuration_;
- // Messages to be logged if the most recently _committed_ non-same-document
- // navigation in the main frame was in an activation list with warning bit
- // set. Has the same lifetime as |matched_configuration_|.
- std::vector<std::string> on_commit_warning_messages_;
-
DISALLOW_COPY_AND_ASSIGN(ContentSubresourceFilterDriverFactory);
};
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
index 14defcccc6a..e6467a0e399 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.cc
@@ -15,8 +15,8 @@
#include "base/trace_event/trace_event_argument.h"
#include "components/subresource_filter/content/browser/activation_state_computing_navigation_throttle.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
+#include "components/subresource_filter/content/browser/navigation_console_logger.h"
#include "components/subresource_filter/content/browser/page_load_statistics.h"
-#include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/common/subresource_filter_messages.h"
#include "components/subresource_filter/content/common/subresource_filter_utils.h"
@@ -67,6 +67,25 @@ void ContentSubresourceFilterThrottleManager::RenderFrameDeleted(
// of subframe navigations.
void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
content::NavigationHandle* navigation_handle) {
+ // Since the frame hasn't yet committed, GetCurrentRenderFrameHost() points
+ // to the initial RFH.
+ // TODO(crbug.com/843646): Use an API that NavigationHandle supports rather
+ // than trying to infer what the NavigationHandle is doing.
+ content::RenderFrameHost* previous_rfh =
+ navigation_handle->GetWebContents()->UnsafeFindFrameByFrameTreeNodeId(
+ navigation_handle->GetFrameTreeNodeId());
+
+ // If a known ad RenderFrameHost has moved to a new host, update ad_frames_.
+ bool transferred_ad_frame = false;
+ if (previous_rfh && previous_rfh != navigation_handle->GetRenderFrameHost()) {
+ auto previous_rfh_it = ad_frames_.find(previous_rfh);
+ if (previous_rfh_it != ad_frames_.end()) {
+ ad_frames_.erase(previous_rfh_it);
+ ad_frames_.insert(navigation_handle->GetRenderFrameHost());
+ transferred_ad_frame = true;
+ }
+ }
+
if (navigation_handle->GetNetErrorCode() != net::OK)
return;
@@ -74,13 +93,9 @@ void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
if (it == ongoing_activation_throttles_.end())
return;
- // TODO(crbug.com/736249): Remove CHECKs in this file when the root cause of
- // the crash is found.
- ActivationStateComputingNavigationThrottle* throttle = it->second.throttle;
- CHECK_EQ(navigation_handle, throttle->navigation_handle());
-
// Main frame throttles with disabled page-level activation will not have
// associated filters.
+ ActivationStateComputingNavigationThrottle* throttle = it->second;
AsyncDocumentSubresourceFilter* filter = throttle->filter();
if (!filter)
return;
@@ -97,17 +112,12 @@ void ContentSubresourceFilterThrottleManager::ReadyToCommitNavigation(
throttle->WillSendActivationToRenderer();
- // is_ad_subframe is guaranteed to have the correct value at this point since
- // the ruleset checking and its notification is done before the navigation is
- // resumed.
- bool is_ad_subframe = it->second.is_ad_subframe;
- DCHECK(!is_ad_subframe || level == ActivationLevel::DRYRUN);
- DCHECK(!is_ad_subframe || !navigation_handle->IsInMainFrame());
-
content::RenderFrameHost* frame_host =
navigation_handle->GetRenderFrameHost();
- if (is_ad_subframe)
- ad_frames_.insert(frame_host);
+
+ bool is_ad_subframe =
+ transferred_ad_frame || base::ContainsKey(ad_frames_, frame_host);
+ DCHECK(!is_ad_subframe || !navigation_handle->IsInMainFrame());
frame_host->Send(new SubresourceFilterMsg_ActivateForNextCommittedLoad(
frame_host->GetRoutingID(), filter->activation_state(), is_ad_subframe));
@@ -126,8 +136,7 @@ void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
auto throttle_it = ongoing_activation_throttles_.find(navigation_handle);
std::unique_ptr<AsyncDocumentSubresourceFilter> filter;
if (throttle_it != ongoing_activation_throttles_.end()) {
- ActivationStateComputingNavigationThrottle* throttle =
- throttle_it->second.throttle;
+ ActivationStateComputingNavigationThrottle* throttle = throttle_it->second;
CHECK_EQ(navigation_handle, throttle->navigation_handle());
filter = throttle->ReleaseFilter();
ongoing_activation_throttles_.erase(throttle_it);
@@ -144,8 +153,9 @@ void ContentSubresourceFilterThrottleManager::DidFinishNavigation(
if (filter->activation_state().enable_logging) {
DCHECK(filter->activation_state().activation_level !=
ActivationLevel::DISABLED);
- frame_host->AddMessageToConsole(content::CONSOLE_MESSAGE_LEVEL_WARNING,
- kActivationConsoleMessage);
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation_handle, content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ kActivationConsoleMessage);
}
}
ActivationLevel level = filter ? filter->activation_state().activation_level
@@ -186,6 +196,16 @@ bool ContentSubresourceFilterThrottleManager::OnMessageReceived(
const IPC::Message& message,
content::RenderFrameHost* render_frame_host) {
bool handled = true;
+
+ IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(ContentSubresourceFilterThrottleManager,
+ message, render_frame_host)
+ IPC_MESSAGE_HANDLER(SubresourceFilterHostMsg_FrameIsAdSubframe,
+ OnFrameIsAdSubframe)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ if (handled)
+ return true;
+
IPC_BEGIN_MESSAGE_MAP(ContentSubresourceFilterThrottleManager, message)
IPC_MESSAGE_HANDLER(SubresourceFilterHostMsg_DidDisallowFirstSubresource,
MaybeCallFirstDisallowedLoad)
@@ -212,31 +232,29 @@ void ContentSubresourceFilterThrottleManager::OnPageActivationComputed(
auto it = ongoing_activation_throttles_.find(navigation_handle);
if (it != ongoing_activation_throttles_.end()) {
- it->second.throttle->NotifyPageActivationWithRuleset(EnsureRulesetHandle(),
- activation_state);
+ it->second->NotifyPageActivationWithRuleset(EnsureRulesetHandle(),
+ activation_state);
}
}
void ContentSubresourceFilterThrottleManager::OnSubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy) {
+ LoadPolicy load_policy,
+ bool is_ad_subframe) {
DCHECK(!navigation_handle->IsInMainFrame());
+
auto it = ongoing_activation_throttles_.find(navigation_handle);
if (it == ongoing_activation_throttles_.end())
return;
- // Note that is_ad_subframe is only relevant for
- // LoadPolicy:WOULD_DISALLOW(dryrun mode), although also setting it for
- // DISALLOW for completeness.
- it->second.is_ad_subframe = load_policy != LoadPolicy::ALLOW;
-
- // If this frame was not identified as an ad via ruleset matching, tag it
- // based on whether its parent frame is an ad or not.
- if (!it->second.is_ad_subframe) {
- content::RenderFrameHost* parent_frame =
- navigation_handle->GetParentFrame();
- if (parent_frame && base::ContainsKey(ad_frames_, parent_frame))
- it->second.is_ad_subframe = true;
+ if (is_ad_subframe) {
+ // TODO(crbug.com/843646): Use an API that NavigationHandle supports rather
+ // than trying to infer what the NavigationHandle is doing.
+ content::RenderFrameHost* starting_rfh =
+ navigation_handle->GetWebContents()->UnsafeFindFrameByFrameTreeNodeId(
+ navigation_handle->GetFrameTreeNodeId());
+ DCHECK(starting_rfh);
+ ad_frames_.insert(starting_rfh);
}
}
@@ -254,17 +272,26 @@ void ContentSubresourceFilterThrottleManager::MaybeAppendNavigationThrottles(
DCHECK(!base::ContainsKey(ongoing_activation_throttles_, navigation_handle));
if (auto activation_throttle =
MaybeCreateActivationStateComputingThrottle(navigation_handle)) {
- ongoing_activation_throttles_[navigation_handle].throttle =
+ ongoing_activation_throttles_[navigation_handle] =
activation_throttle.get();
- activation_throttle->set_destruction_closure(base::BindOnce(
- &ContentSubresourceFilterThrottleManager::OnActivationThrottleDestroyed,
- weak_ptr_factory_.GetWeakPtr(), base::Unretained(navigation_handle)));
throttles->push_back(std::move(activation_throttle));
}
}
+bool ContentSubresourceFilterThrottleManager::CalculateIsAdSubframe(
+ content::RenderFrameHost* frame_host,
+ LoadPolicy load_policy) {
+ DCHECK(frame_host);
+ content::RenderFrameHost* parent_frame = frame_host->GetParent();
+ DCHECK(parent_frame);
+
+ return load_policy != LoadPolicy::ALLOW ||
+ base::ContainsKey(ad_frames_, frame_host) ||
+ base::ContainsKey(ad_frames_, parent_frame);
+}
+
bool ContentSubresourceFilterThrottleManager::IsFrameTaggedAsAdForTesting(
- content::RenderFrameHost* frame_host) {
+ content::RenderFrameHost* frame_host) const {
return base::ContainsKey(ad_frames_, frame_host);
}
@@ -277,7 +304,7 @@ ContentSubresourceFilterThrottleManager::
AsyncDocumentSubresourceFilter* parent_filter =
GetParentFrameFilter(navigation_handle);
return parent_filter ? std::make_unique<SubframeNavigationFilteringThrottle>(
- navigation_handle, parent_filter)
+ navigation_handle, parent_filter, this)
: nullptr;
}
@@ -323,7 +350,7 @@ ContentSubresourceFilterThrottleManager::GetParentFrameFilter(
if (it == activated_frame_hosts_.end())
return nullptr;
- if (it->second.get())
+ if (it->second)
return it->second.get();
parent = it->first->GetParent();
}
@@ -338,6 +365,15 @@ ContentSubresourceFilterThrottleManager::GetParentFrameFilter(
void ContentSubresourceFilterThrottleManager::MaybeCallFirstDisallowedLoad() {
if (current_committed_load_has_notified_disallowed_load_)
return;
+
+ // This shouldn't happen normally, but in the rare case that an IPC from a
+ // previous page arrives late we should guard against it.
+ auto it = activated_frame_hosts_.find(web_contents()->GetMainFrame());
+ if (it == activated_frame_hosts_.end() ||
+ it->second->activation_state().activation_level !=
+ ActivationLevel::ENABLED) {
+ return;
+ }
delegate_->OnFirstSubresourceLoadDisallowed();
current_committed_load_has_notified_disallowed_load_ = true;
}
@@ -363,10 +399,11 @@ void ContentSubresourceFilterThrottleManager::OnDocumentLoadStatistics(
statistics_->OnDocumentLoadStatistics(statistics);
}
-void ContentSubresourceFilterThrottleManager::OnActivationThrottleDestroyed(
- content::NavigationHandle* navigation_handle) {
- size_t num_erased = ongoing_activation_throttles_.erase(navigation_handle);
- CHECK_EQ(0u, num_erased);
+void ContentSubresourceFilterThrottleManager::OnFrameIsAdSubframe(
+ content::RenderFrameHost* render_frame_host) {
+ DCHECK(render_frame_host);
+
+ ad_frames_.insert(render_frame_host);
}
void ContentSubresourceFilterThrottleManager::MaybeActivateSubframeSpecialUrls(
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
index fdfec2fb79f..e8500b2b401 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h
@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h"
#include "base/stl_util.h"
+#include "components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer.h"
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
#include "components/subresource_filter/core/common/activation_decision.h"
@@ -34,7 +35,6 @@ namespace subresource_filter {
class AsyncDocumentSubresourceFilter;
class ActivationStateComputingNavigationThrottle;
-class SubframeNavigationFilteringThrottle;
class SubresourceFilterObserverManager;
class PageLoadStatistics;
struct DocumentLoadStatistics;
@@ -50,7 +50,8 @@ struct DocumentLoadStatistics;
// navgation, and has veto power for frame activation.
class ContentSubresourceFilterThrottleManager
: public content::WebContentsObserver,
- public SubresourceFilterObserver {
+ public SubresourceFilterObserver,
+ public SubframeNavigationFilteringThrottle::Delegate {
public:
// It is expected that the Delegate outlives |this|, and manages the lifetime
// of this class.
@@ -86,7 +87,11 @@ class ContentSubresourceFilterThrottleManager
return ruleset_handle_.get();
}
- bool IsFrameTaggedAsAdForTesting(content::RenderFrameHost* frame_host);
+ // SubframeNavigationFilteringThrottle::Delegate:
+ bool CalculateIsAdSubframe(content::RenderFrameHost* frame_host,
+ LoadPolicy load_policy) override;
+
+ bool IsFrameTaggedAsAdForTesting(content::RenderFrameHost* frame_host) const;
protected:
// content::WebContentsObserver:
@@ -108,9 +113,18 @@ class ContentSubresourceFilterThrottleManager
const ActivationState& activation_state) override;
void OnSubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy) override;
+ LoadPolicy load_policy,
+ bool is_ad_subframe) override;
private:
+ FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
+ SubframeNavigationTaggedAsAdByRenderer);
+ FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
+ GrandchildNavigationTaggedAsAdByRenderer);
+ FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
+ AdTagCarriesAcrossProcesses);
+ FRIEND_TEST_ALL_PREFIXES(ContentSubresourceFilterThrottleManagerTest,
+ FirstDisallowedLoadCalledOutOfOrder);
std::unique_ptr<SubframeNavigationFilteringThrottle>
MaybeCreateSubframeNavigationFilteringThrottle(
content::NavigationHandle* navigation_handle);
@@ -132,10 +146,9 @@ class ContentSubresourceFilterThrottleManager
void OnDocumentLoadStatistics(const DocumentLoadStatistics& statistics);
- // The navigation handle ptr will be in an invalid state, do not access any
- // members on it. This method is only for debugging crbug.com/736249.
- void OnActivationThrottleDestroyed(
- content::NavigationHandle* navigation_handle);
+ // Registers |render_frame_host| as an ad frame. If the frame later moves to
+ // a new process its RenderHost will be told that it's an ad.
+ void OnFrameIsAdSubframe(content::RenderFrameHost* render_frame_host);
// Adds the navigation's RenderFrameHost to activated_frame_hosts_ if it is a
// special navigation which did not go through navigation throttles and its
@@ -154,18 +167,17 @@ class ContentSubresourceFilterThrottleManager
// For each ongoing navigation that requires activation state computation,
// keeps track of the throttle that is carrying out that computation, so that
// the result can be retrieved when the navigation is ready to commit.
- // is_ad_subframe is set if SubframeNavigationFilteringThrottle finds that the
- // subframe URL matches the ruleset.
- struct OngoingThrottleInfo {
- ActivationStateComputingNavigationThrottle* throttle = nullptr;
- bool is_ad_subframe = false;
- };
-
- std::map<content::NavigationHandle*, OngoingThrottleInfo>
+ std::map<content::NavigationHandle*,
+ ActivationStateComputingNavigationThrottle*>
ongoing_activation_throttles_;
- // Set of frames that have been identified as ads, either through matching the
- // ruleset or if their parent frame was an ad frame.
+ // Set of RenderFrameHosts that have been identified as ads. An RFH is an ad
+ // subframe if any of the following conditions are met:
+ // 1. Its navigation URL is in the filter list
+ // 2. Its parent is a known ad subframe
+ // 3. The RenderFrame declares the frame is an ad (see AdTracker in Blink)
+ // 4. It's the result of moving an old ad subframe RFH to a new RFH (e.g.,
+ // OOPIF)
std::set<content::RenderFrameHost*> ad_frames_;
ScopedObserver<SubresourceFilterObserverManager, SubresourceFilterObserver>
diff --git a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
index 58380426126..710d1ed79ec 100644
--- a/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/content_subresource_filter_throttle_manager_unittest.cc
@@ -9,8 +9,9 @@
#include <tuple>
#include <utility>
+#include "base/command_line.h"
#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
@@ -30,6 +31,7 @@
#include "content/public/test/mock_render_process_host.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/test_utils.h"
#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/url_constants.h"
@@ -114,8 +116,7 @@ class ContentSubresourceFilterThrottleManagerTest
public ContentSubresourceFilterThrottleManager::Delegate,
public ::testing::WithParamInterface<PageActivationNotificationTiming> {
public:
- ContentSubresourceFilterThrottleManagerTest()
- : ContentSubresourceFilterThrottleManager::Delegate() {}
+ ContentSubresourceFilterThrottleManagerTest() {}
~ContentSubresourceFilterThrottleManagerTest() override {}
// content::RenderViewHostTestHarness:
@@ -137,7 +138,7 @@ class ContentSubresourceFilterThrottleManagerTest
// tests, to ensure that the NavigationSimulator properly runs all necessary
// tasks while waiting for throttle checks to finish.
dealer_handle_ = std::make_unique<VerifiedRulesetDealer::Handle>(
- base::MessageLoop::current()->task_runner());
+ base::MessageLoopCurrent::Get()->task_runner());
dealer_handle_->TryOpenAndSetRulesetFile(test_ruleset_pair_.indexed.path,
base::DoNothing());
@@ -742,6 +743,113 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
true /* is_ad_subframe */);
}
+// If the RenderFrame determines that the frame is an ad, then any navigation
+// for that frame should be considered an ad.
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ SubframeNavigationTaggedAsAdByRenderer) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */,
+ false /* is_ad_subframe */);
+
+ content::RenderFrameHost* subframe = CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/allowed.html"), main_rfh());
+
+ EXPECT_FALSE(throttle_manager()->IsFrameTaggedAsAdForTesting(subframe));
+ throttle_manager()->OnFrameIsAdSubframe(subframe);
+ EXPECT_TRUE(throttle_manager()->IsFrameTaggedAsAdForTesting(subframe));
+
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+
+ subframe =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ EXPECT_TRUE(subframe);
+
+ ExpectActivationSignalForFrame(subframe, true /* expect_activation */,
+ true /* is_ad_subframe */);
+
+ // A non-ad navigation for the same frame should be considered an ad
+ // subframe as well.
+ CreateTestNavigation(GURL("https://example.com/allowed2.html"), subframe);
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe, true /* expect_activation */,
+ true /* is_ad_subframe */);
+}
+
+// If the RenderFrame determines that the frame is an ad, and the frame changes
+// processes, then the new frame host should still be considered an ad.
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ AdTagCarriesAcrossProcesses) {
+ content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
+
+ NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */,
+ false /* is_ad_subframe */);
+
+ // Create a subframe to a different site. It will start as a same-process
+ // frame but transition to a cross-process frame just before commit (after
+ // the throttle has marked the frame as an ad.)
+ content::RenderFrameHost* initial_subframe = CreateSubframeWithTestNavigation(
+ GURL("https://www.example2.com/allowed.html"), main_rfh());
+
+ // Simulate the render process telling the manager that the frame is an ad.
+ throttle_manager()->OnFrameIsAdSubframe(initial_subframe);
+ EXPECT_TRUE(
+ throttle_manager()->IsFrameTaggedAsAdForTesting(initial_subframe));
+
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+
+ content::RenderFrameHost* final_subframe =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ EXPECT_TRUE(final_subframe);
+ EXPECT_NE(initial_subframe, final_subframe);
+
+ EXPECT_TRUE(throttle_manager()->IsFrameTaggedAsAdForTesting(final_subframe));
+ EXPECT_FALSE(
+ throttle_manager()->IsFrameTaggedAsAdForTesting(initial_subframe));
+ ExpectActivationSignalForFrame(final_subframe, true /* expect_activation */,
+ true /* is_ad_subframe */);
+}
+
+// If the RenderFrame determines that the frame is an ad, then its child frames
+// should also be considered ads.
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ GrandchildNavigationTaggedAsAdByRenderer) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */,
+ false /* is_ad_subframe */);
+
+ // Create a subframe that's marked as an ad by the render process.
+ content::RenderFrameHost* subframe = CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/allowed.html"), main_rfh());
+
+ // Simulate the render process telling the manager that the frame is an ad.
+ throttle_manager()->OnFrameIsAdSubframe(subframe);
+
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+
+ subframe =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe, true /* expect_activation */,
+ true /* is_ad_subframe */);
+
+ // Create a grandchild frame that is marked as an ad because its parent is.
+ content::RenderFrameHost* grandchild_frame = CreateSubframeWithTestNavigation(
+ GURL("https://www.example.com/foo/allowed.html"), subframe);
+ SimulateStartAndExpectResult(content::NavigationThrottle::PROCEED);
+ grandchild_frame =
+ SimulateCommitAndExpectResult(content::NavigationThrottle::PROCEED);
+ ExpectActivationSignalForFrame(subframe, true /* expect_activation */,
+ true /* is_ad_subframe */);
+ EXPECT_TRUE(
+ throttle_manager()->IsFrameTaggedAsAdForTesting(grandchild_frame));
+}
+
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ DryRun_FrameTaggingDeleted) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
+ ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
+}
+
TEST_P(ContentSubresourceFilterThrottleManagerTest,
DryRun_FrameTaggingAsAdPropagatesToChildFrame) {
NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
@@ -788,7 +896,7 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
}
TEST_P(ContentSubresourceFilterThrottleManagerTest,
- DryRun_AllowedsFrameNotTaggedAsAd) {
+ DryRun_AllowedFrameNotTaggedAsAd) {
NavigateAndCommitMainFrame(GURL(kTestURLWithDryRun));
ExpectActivationSignalForFrame(main_rfh(), true /* expect_activation */);
@@ -817,6 +925,21 @@ TEST_P(ContentSubresourceFilterThrottleManagerTest,
EXPECT_EQ(0, disallowed_notification_count());
}
+TEST_P(ContentSubresourceFilterThrottleManagerTest,
+ FirstDisallowedLoadCalledOutOfOrder) {
+ NavigateAndCommitMainFrame(GURL(kTestURLWithActivation));
+ NavigateAndCommitMainFrame(GURL(kTestURLWithNoActivation));
+
+ // Simulate the previous navigation sending an IPC that a load was disallowed.
+ // This could happen e.g. for cross-process navigations, which have no
+ // ordering guarantees.
+ throttle_manager()->OnMessageReceived(
+ SubresourceFilterHostMsg_DidDisallowFirstSubresource(
+ main_rfh()->GetRoutingID()),
+ main_rfh());
+ EXPECT_EQ(0, disallowed_notification_count());
+}
+
// TODO(csharrison): Make sure the following conditions are exercised in tests:
//
// - Synchronous navigations to about:blank. These hit issues with the
diff --git a/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc b/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc
new file mode 100644
index 00000000000..dbafdf84e0f
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/navigation_console_logger.cc
@@ -0,0 +1,64 @@
+// 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 "components/subresource_filter/content/browser/navigation_console_logger.h"
+
+#include "base/memory/ptr_util.h"
+#include "content/public/browser/navigation_handle.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(subresource_filter::NavigationConsoleLogger);
+
+namespace subresource_filter {
+
+// static
+void NavigationConsoleLogger::LogMessageOnCommit(
+ content::NavigationHandle* handle,
+ content::ConsoleMessageLevel level,
+ const std::string& message) {
+ DCHECK(handle->IsInMainFrame());
+ if (handle->HasCommitted() && !handle->IsErrorPage()) {
+ handle->GetRenderFrameHost()->AddMessageToConsole(level, message);
+ } else {
+ NavigationConsoleLogger::CreateIfNeededForNavigation(handle)
+ ->commit_messages_.emplace_back(level, message);
+ }
+}
+
+// static
+NavigationConsoleLogger* NavigationConsoleLogger::CreateIfNeededForNavigation(
+ content::NavigationHandle* handle) {
+ DCHECK(handle->IsInMainFrame());
+ content::WebContents* contents = handle->GetWebContents();
+ auto* logger = FromWebContents(contents);
+ if (!logger) {
+ auto new_logger = base::WrapUnique(new NavigationConsoleLogger(handle));
+ logger = new_logger.get();
+ contents->SetUserData(UserDataKey(), std::move(new_logger));
+ }
+ return logger;
+}
+
+NavigationConsoleLogger::~NavigationConsoleLogger() = default;
+
+NavigationConsoleLogger::NavigationConsoleLogger(
+ content::NavigationHandle* handle)
+ : content::WebContentsObserver(handle->GetWebContents()), handle_(handle) {}
+
+void NavigationConsoleLogger::DidFinishNavigation(
+ content::NavigationHandle* handle) {
+ if (handle != handle_)
+ return;
+
+ // The main frame navigation has finished.
+ if (handle->HasCommitted() && !handle->IsErrorPage()) {
+ for (const auto& message : commit_messages_) {
+ handle->GetRenderFrameHost()->AddMessageToConsole(message.first,
+ message.second);
+ }
+ }
+ // Deletes |this|.
+ web_contents()->RemoveUserData(UserDataKey());
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/navigation_console_logger.h b/chromium/components/subresource_filter/content/browser/navigation_console_logger.h
new file mode 100644
index 00000000000..abc4414bf57
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/navigation_console_logger.h
@@ -0,0 +1,68 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_NAVIGATION_CONSOLE_LOGGER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_NAVIGATION_CONSOLE_LOGGER_H_
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "content/public/common/console_message_level.h"
+
+namespace content {
+class NavigationHandle;
+} // namespace content
+
+namespace subresource_filter {
+
+// This class provides a static API to log console messages when an ongoing
+// navigation successfully commits.
+// - This class only supports main frame navigations.
+// - This class should be replaced with a class scoped to the NavigationHandle
+// if it ever starts supporting user data.
+class NavigationConsoleLogger
+ : public content::WebContentsObserver,
+ public content::WebContentsUserData<NavigationConsoleLogger> {
+ public:
+ // Creates a NavigationConsoleLogger object if it does not already exist for
+ // |handle|'s WebContents. It will be scoped until the current main frame
+ // navigation in |contents| commits its next navigation. If |handle| has
+ // already committed, logs the message immediately.
+ static void LogMessageOnCommit(content::NavigationHandle* handle,
+ content::ConsoleMessageLevel level,
+ const std::string& message);
+
+ ~NavigationConsoleLogger() override;
+
+ private:
+ explicit NavigationConsoleLogger(content::NavigationHandle* handle);
+
+ // Creates a new NavigationConsoleLogger scoped to |handle|'s WebContents if
+ // one doesn't exist. Returns the NavigationConsoleLogger associated with
+ // |handle|'s WebContents.
+ //
+ // Note: |handle| must be associated with a main frame navigation.
+ static NavigationConsoleLogger* CreateIfNeededForNavigation(
+ content::NavigationHandle* handle);
+
+ // content::WebContentsObserver:
+ void DidFinishNavigation(content::NavigationHandle* handle) override;
+
+ using Message = std::pair<content::ConsoleMessageLevel, std::string>;
+ std::vector<Message> commit_messages_;
+
+ // |handle_| must outlive this class. This is guaranteed because the object
+ // tears itself down with |handle_|'s navigation finishes.
+ const content::NavigationHandle* handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(NavigationConsoleLogger);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_NAVIGATION_CONSOLE_LOGGER_H_
diff --git a/chromium/components/subresource_filter/content/browser/navigation_console_logger_unittest.cc b/chromium/components/subresource_filter/content/browser/navigation_console_logger_unittest.cc
new file mode 100644
index 00000000000..7e3214e8308
--- /dev/null
+++ b/chromium/components/subresource_filter/content/browser/navigation_console_logger_unittest.cc
@@ -0,0 +1,138 @@
+// 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 "components/subresource_filter/content/browser/navigation_console_logger.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/stl_util.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/test/navigation_simulator.h"
+#include "content/public/test/test_renderer_host.h"
+#include "net/base/net_errors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+const std::vector<std::string>& GetConsoleMessages(
+ content::RenderFrameHost* rfh) {
+ return content::RenderFrameHostTester::For(rfh)->GetConsoleMessages();
+}
+
+} // namespace
+
+using NavigationConsoleLoggerTest = content::RenderViewHostTestHarness;
+
+using NavigationCallback =
+ base::RepeatingCallback<void(content::NavigationHandle*)>;
+class NavigationFinishCaller : public content::WebContentsObserver {
+ public:
+ NavigationFinishCaller(content::WebContents* contents,
+ const NavigationCallback& callback)
+ : content::WebContentsObserver(contents), callback_(callback) {}
+ ~NavigationFinishCaller() override = default;
+
+ // content::WebContentsObserver:
+ void DidFinishNavigation(content::NavigationHandle* handle) override {
+ callback_.Run(handle);
+ }
+
+ private:
+ NavigationCallback callback_;
+};
+
+TEST_F(NavigationConsoleLoggerTest, NavigationFails_NoLog) {
+ auto navigation = content::NavigationSimulator::CreateRendererInitiated(
+ GURL("http://example.test/"), main_rfh());
+ navigation->Start();
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation->GetNavigationHandle(), content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ "foo");
+ navigation->Fail(net::ERR_ABORTED);
+
+ EXPECT_TRUE(GetConsoleMessages(main_rfh()).empty());
+}
+
+TEST_F(NavigationConsoleLoggerTest, NavigationCommitsToErrorPage_NoLog) {
+ auto navigation = content::NavigationSimulator::CreateRendererInitiated(
+ GURL("http://example.test/"), main_rfh());
+ navigation->Start();
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation->GetNavigationHandle(), content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ "foo");
+ navigation->Fail(net::ERR_TIMED_OUT);
+
+ EXPECT_TRUE(GetConsoleMessages(main_rfh()).empty());
+}
+
+TEST_F(NavigationConsoleLoggerTest, NavigationCommitsSuccessfully_Logs) {
+ auto navigation = content::NavigationSimulator::CreateRendererInitiated(
+ GURL("http://example.test/"), main_rfh());
+ navigation->Start();
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation->GetNavigationHandle(), content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ "foo");
+
+ EXPECT_TRUE(GetConsoleMessages(main_rfh()).empty());
+ navigation->Commit();
+
+ EXPECT_TRUE(base::ContainsValue(GetConsoleMessages(main_rfh()), "foo"));
+}
+
+TEST_F(NavigationConsoleLoggerTest, NavigationAlreadyCommit_Logs) {
+ auto on_finish = [](content::NavigationHandle* handle) {
+ NavigationConsoleLogger::LogMessageOnCommit(
+ handle, content::CONSOLE_MESSAGE_LEVEL_WARNING, "foo");
+ };
+ NavigationFinishCaller caller(web_contents(), base::BindRepeating(on_finish));
+ NavigateAndCommit(GURL("http://example.test/"));
+ EXPECT_TRUE(base::ContainsValue(GetConsoleMessages(main_rfh()), "foo"));
+}
+
+TEST_F(NavigationConsoleLoggerTest, NavigationAlreadyFailed_NoLog) {
+ auto on_finish = [](content::NavigationHandle* handle) {
+ NavigationConsoleLogger::LogMessageOnCommit(
+ handle, content::CONSOLE_MESSAGE_LEVEL_WARNING, "foo");
+ };
+ NavigationFinishCaller caller(web_contents(), base::BindRepeating(on_finish));
+ content::NavigationSimulator::NavigateAndFailFromBrowser(
+ web_contents(), GURL("http://example.test/"), net::ERR_TIMED_OUT);
+ EXPECT_TRUE(GetConsoleMessages(main_rfh()).empty());
+}
+
+TEST_F(NavigationConsoleLoggerTest, MultipleNavigations_OneLog) {
+ {
+ auto navigation = content::NavigationSimulator::CreateRendererInitiated(
+ GURL("http://example.test/"), main_rfh());
+ navigation->Start();
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation->GetNavigationHandle(),
+ content::CONSOLE_MESSAGE_LEVEL_WARNING, "foo");
+ navigation->Commit();
+ }
+ NavigateAndCommit(GURL("http://example.test/"));
+ EXPECT_EQ(1u, GetConsoleMessages(main_rfh()).size());
+}
+
+TEST_F(NavigationConsoleLoggerTest, MultipleMessages) {
+ auto navigation = content::NavigationSimulator::CreateRendererInitiated(
+ GURL("http://example.test/"), main_rfh());
+ navigation->Start();
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation->GetNavigationHandle(), content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ "foo");
+ NavigationConsoleLogger::LogMessageOnCommit(
+ navigation->GetNavigationHandle(), content::CONSOLE_MESSAGE_LEVEL_WARNING,
+ "bar");
+
+ EXPECT_TRUE(GetConsoleMessages(main_rfh()).empty());
+ navigation->Commit();
+
+ EXPECT_EQ(2u, GetConsoleMessages(main_rfh()).size());
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
index 99f4d744a55..5162a01fb79 100644
--- a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
@@ -21,9 +21,11 @@ namespace subresource_filter {
SubframeNavigationFilteringThrottle::SubframeNavigationFilteringThrottle(
content::NavigationHandle* handle,
- AsyncDocumentSubresourceFilter* parent_frame_filter)
+ AsyncDocumentSubresourceFilter* parent_frame_filter,
+ Delegate* delegate)
: content::NavigationThrottle(handle),
parent_frame_filter_(parent_frame_filter),
+ delegate_(delegate),
weak_ptr_factory_(this) {
DCHECK(!handle->IsInMainFrame());
DCHECK(parent_frame_filter_);
@@ -111,12 +113,23 @@ void SubframeNavigationFilteringThrottle::OnCalculatedLoadPolicy(
}
void SubframeNavigationFilteringThrottle::NotifyLoadPolicy() const {
- if (auto* observer_manager =
- SubresourceFilterObserverManager::FromWebContents(
- navigation_handle()->GetWebContents())) {
- observer_manager->NotifySubframeNavigationEvaluated(navigation_handle(),
- load_policy_);
- }
+ auto* observer_manager = SubresourceFilterObserverManager::FromWebContents(
+ navigation_handle()->GetWebContents());
+ if (!observer_manager)
+ return;
+
+ // TODO(crbug.com/843646): Use an API that NavigationHandle supports rather
+ // than trying to infer what the NavigationHandle is doing.
+ content::RenderFrameHost* starting_rfh =
+ navigation_handle()->GetWebContents()->UnsafeFindFrameByFrameTreeNodeId(
+ navigation_handle()->GetFrameTreeNodeId());
+ DCHECK(starting_rfh);
+
+ bool is_ad_subframe =
+ delegate_->CalculateIsAdSubframe(starting_rfh, load_policy_);
+
+ observer_manager->NotifySubframeNavigationEvaluated(
+ navigation_handle(), load_policy_, is_ad_subframe);
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h
index c79c1daf69f..d9597805017 100644
--- a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h
+++ b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h
@@ -14,6 +14,7 @@
namespace content {
class NavigationHandle;
+class RenderFrameHost;
} // namespace content
namespace subresource_filter {
@@ -30,9 +31,25 @@ class AsyncDocumentSubresourceFilter;
// therefore an associated (Async)DocumentSubresourceFilter.
class SubframeNavigationFilteringThrottle : public content::NavigationThrottle {
public:
+ class Delegate {
+ public:
+ // Given what is known about the frame's load policy, its parent frame, and
+ // what it's learned from ad tagging, determine if it's an ad subframe.
+ virtual bool CalculateIsAdSubframe(content::RenderFrameHost* frame_host,
+ LoadPolicy load_policy) = 0;
+
+ protected:
+ Delegate() = default;
+ virtual ~Delegate() = default;
+
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ // |delegate| must outlive this object.
SubframeNavigationFilteringThrottle(
content::NavigationHandle* handle,
- AsyncDocumentSubresourceFilter* parent_frame_filter);
+ AsyncDocumentSubresourceFilter* parent_frame_filter,
+ Delegate* delegate);
~SubframeNavigationFilteringThrottle() override;
// content::NavigationThrottle:
@@ -56,6 +73,10 @@ class SubframeNavigationFilteringThrottle : public content::NavigationThrottle {
base::TimeDelta total_defer_time_;
LoadPolicy load_policy_ = LoadPolicy::ALLOW;
+ // As specified in the constructor comment, |delegate_| must outlive this
+ // object.
+ Delegate* delegate_;
+
base::WeakPtrFactory<SubframeNavigationFilteringThrottle> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SubframeNavigationFilteringThrottle);
diff --git a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
index 538fc8adcc4..f96ccfa942c 100644
--- a/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle_unittest.cc
@@ -7,12 +7,13 @@
#include <memory>
#include "base/callback.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/test/histogram_tester.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter.h"
#include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h"
+#include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h"
#include "components/subresource_filter/core/common/activation_level.h"
#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
@@ -24,6 +25,20 @@
namespace subresource_filter {
+class MockDelegate : public SubframeNavigationFilteringThrottle::Delegate {
+ public:
+ MockDelegate() = default;
+ ~MockDelegate() override = default;
+
+ // SubframeNavigationFilteringThrottle::Delegate:
+ bool CalculateIsAdSubframe(content::RenderFrameHost* frame_host,
+ LoadPolicy load_policy) override {
+ return false;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(MockDelegate);
+};
+
class SubframeNavigationFilteringThrottleTest
: public content::RenderViewHostTestHarness,
public content::WebContentsObserver {
@@ -58,7 +73,7 @@ class SubframeNavigationFilteringThrottleTest
if (parent_filter_) {
navigation_handle->RegisterThrottleForTesting(
std::make_unique<SubframeNavigationFilteringThrottle>(
- navigation_handle, parent_filter_.get()));
+ navigation_handle, parent_filter_.get(), &mock_delegate_));
}
}
@@ -71,7 +86,7 @@ class SubframeNavigationFilteringThrottleTest
// tests, to ensure that the NavigationSimulator properly runs all necessary
// tasks while waiting for throttle checks to finish.
dealer_handle_ = std::make_unique<VerifiedRulesetDealer::Handle>(
- base::MessageLoop::current()->task_runner());
+ base::MessageLoopCurrent::Get()->task_runner());
dealer_handle_->TryOpenAndSetRulesetFile(test_ruleset_pair_.indexed.path,
base::DoNothing());
ruleset_handle_ =
@@ -131,6 +146,7 @@ class SubframeNavigationFilteringThrottleTest
testing::TestRulesetCreator test_ruleset_creator_;
testing::TestRulesetPair test_ruleset_pair_;
+ MockDelegate mock_delegate_;
std::unique_ptr<VerifiedRulesetDealer::Handle> dealer_handle_;
std::unique_ptr<VerifiedRuleset::Handle> ruleset_handle_;
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_client.h b/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
index 77dd18ed37b..bfd241cdf9b 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_client.h
@@ -8,8 +8,6 @@
#include "components/subresource_filter/content/browser/verified_ruleset_dealer.h"
#include "content/public/browser/web_contents.h"
-class GURL;
-
namespace content {
class NavigationHandle;
} // namespace content
@@ -35,11 +33,7 @@ class SubresourceFilterClient {
// Precondition: The navigation must be a main frame navigation.
virtual bool OnPageActivationComputed(
content::NavigationHandle* navigation_handle,
- bool activated,
- bool suppressing_notifications) = 0;
-
- // Adds |url| to a per-WebContents whitelist.
- virtual void WhitelistInCurrentWebContents(const GURL& url) = 0;
+ bool activated) = 0;
virtual VerifiedRulesetDealer::Handle* GetRulesetDealer() = 0;
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer.h b/chromium/components/subresource_filter/content/browser/subresource_filter_observer.h
index 3b8845cf6ae..fcf0d46a1e9 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer.h
@@ -48,10 +48,13 @@ class SubresourceFilterObserver {
const ActivationState& activation_state) {}
// Called before navigation commit, either at the WillStartRequest stage or
- // WillRedirectRequest stage.
+ // WillRedirectRequest stage. |is_ad_frame| is true if |load_policy| is
+ // ALLOW or WOULD_DISALLOW or if ad tagging has determined that the frame is
+ // an ad.
virtual void OnSubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy) {}
+ LoadPolicy load_policy,
+ bool is_ad_subframe) {}
};
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc
index 9c3811f56c5..649f4c915e5 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc
@@ -51,9 +51,11 @@ void SubresourceFilterObserverManager::NotifyPageActivationComputed(
void SubresourceFilterObserverManager::NotifySubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy) {
+ LoadPolicy load_policy,
+ bool is_ad_subframe) {
for (auto& observer : observers_)
- observer.OnSubframeNavigationEvaluated(navigation_handle, load_policy);
+ observer.OnSubframeNavigationEvaluated(navigation_handle, load_policy,
+ is_ad_subframe);
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.h b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.h
index 5a31d64f6a8..158491134e7 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_manager.h
@@ -49,9 +49,12 @@ class SubresourceFilterObserverManager
ActivationDecision activation_decision,
const ActivationState& activation_state);
+ // Called in WillStartRequest or WillRedirectRequest stage from a
+ // SubframeNavigationFilteringThrottle.
void NotifySubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy);
+ LoadPolicy load_policy,
+ bool is_ad_subframe);
private:
base::ObserverList<SubresourceFilterObserver> observers_;
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
index 18b42acfe7a..77a93659d2b 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
@@ -45,8 +45,10 @@ void TestSubresourceFilterObserver::OnPageActivationComputed(
void TestSubresourceFilterObserver::OnSubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy) {
+ LoadPolicy load_policy,
+ bool is_ad_subframe) {
subframe_load_evaluations_[navigation_handle->GetURL()] = load_policy;
+ ad_subframe_evaluations_[navigation_handle->GetURL()] = is_ad_subframe;
}
void TestSubresourceFilterObserver::DidFinishNavigation(
@@ -76,6 +78,14 @@ TestSubresourceFilterObserver::GetPageActivation(const GURL& url) const {
return base::Optional<ActivationDecision>();
}
+base::Optional<bool> TestSubresourceFilterObserver::GetIsAdSubframe(
+ const GURL& url) const {
+ auto it = ad_subframe_evaluations_.find(url);
+ if (it != ad_subframe_evaluations_.end())
+ return it->second;
+ return base::Optional<bool>();
+}
+
base::Optional<LoadPolicy> TestSubresourceFilterObserver::GetSubframeLoadPolicy(
const GURL& url) const {
auto it = subframe_load_evaluations_.find(url);
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
index 301f9e9984f..6e098bab759 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
@@ -48,7 +48,8 @@ class TestSubresourceFilterObserver : public SubresourceFilterObserver,
const ActivationState& activation_state) override;
void OnSubframeNavigationEvaluated(
content::NavigationHandle* navigation_handle,
- LoadPolicy load_policy) override;
+ LoadPolicy load_policy,
+ bool is_ad_subframe) override;
// content::WebContentsObserver
void DidFinishNavigation(
@@ -56,6 +57,7 @@ class TestSubresourceFilterObserver : public SubresourceFilterObserver,
base::Optional<ActivationDecision> GetPageActivation(const GURL& url) const;
base::Optional<LoadPolicy> GetSubframeLoadPolicy(const GURL& url) const;
+ base::Optional<bool> GetIsAdSubframe(const GURL& url) const;
base::Optional<ActivationDecision> GetPageActivationForLastCommittedLoad()
const;
@@ -66,6 +68,7 @@ class TestSubresourceFilterObserver : public SubresourceFilterObserver,
private:
std::map<GURL, LoadPolicy> subframe_load_evaluations_;
+ std::map<GURL, bool> ad_subframe_evaluations_;
std::map<GURL, ActivationDecision> page_activations_;
std::map<GURL, SafeBrowsingCheck> safe_browsing_checks_;
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
index c0c02aa3312..bd59e1542f9 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.cc
@@ -17,9 +17,12 @@
#include "components/subresource_filter/content/browser/subresource_filter_client.h"
#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h"
#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
+#include "components/ukm/ukm_source.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
+#include "services/metrics/public/cpp/ukm_recorder.h"
#include "ui/base/page_transition_types.h"
#include "url/gurl.h"
@@ -34,88 +37,32 @@ SubresourceFilterSafeBrowsingActivationThrottle::
database_manager)
: NavigationThrottle(handle),
io_task_runner_(std::move(io_task_runner)),
- // The throttle can be created without a valid database manager. If so, it
- // becomes a pass-through throttle and should never defer.
- database_client_(database_manager
- ? new SubresourceFilterSafeBrowsingClient(
- std::move(database_manager),
- AsWeakPtr(),
- io_task_runner_,
- base::ThreadTaskRunnerHandle::Get())
- : nullptr,
+ database_client_(new SubresourceFilterSafeBrowsingClient(
+ std::move(database_manager),
+ AsWeakPtr(),
+ io_task_runner_,
+ base::ThreadTaskRunnerHandle::Get()),
base::OnTaskRunnerDeleter(io_task_runner_)),
client_(client) {
DCHECK(handle->IsInMainFrame());
CheckCurrentUrl();
- DCHECK(!database_client_ || !check_results_.empty());
+ DCHECK(!check_results_.empty());
}
SubresourceFilterSafeBrowsingActivationThrottle::
- ~SubresourceFilterSafeBrowsingActivationThrottle() {
- // The last check could be ongoing when the navigation is cancelled.
- if (check_results_.empty() || !check_results_.back().finished)
- return;
- bool warning = false;
- ActivationList matched_list = GetListForThreatTypeAndMetadata(
- check_results_.back().threat_type, check_results_.back().threat_metadata,
- &warning);
- // TODO(csharrison): Log more metrics based on check_results_.
- UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.PageLoad.ActivationList",
- matched_list,
- static_cast<int>(ActivationList::LAST) + 1);
-
- size_t chain_size = check_results_.size();
- switch (matched_list) {
- case ActivationList::SOCIAL_ENG_ADS_INTERSTITIAL:
- UMA_HISTOGRAM_COUNTS(
- "SubresourceFilter.PageLoad.RedirectChainLength."
- "SocialEngineeringAdsInterstitial",
- chain_size);
- break;
- case ActivationList::PHISHING_INTERSTITIAL:
- UMA_HISTOGRAM_COUNTS(
- "SubresourceFilter.PageLoad.RedirectChainLength."
- "PhishingInterstitial",
- chain_size);
- break;
- case ActivationList::SUBRESOURCE_FILTER:
- UMA_HISTOGRAM_COUNTS(
- "SubresourceFilter.PageLoad.RedirectChainLength."
- "SubresourceFilterOnly",
- chain_size);
- break;
- case ActivationList::BETTER_ADS:
- UMA_HISTOGRAM_COUNTS(
- "SubresourceFilter.PageLoad.RedirectChainLength."
- "BetterAds",
- chain_size);
- break;
- default:
- break;
- }
-}
-
-bool SubresourceFilterSafeBrowsingActivationThrottle::NavigationIsPageReload(
- content::NavigationHandle* handle) {
- return ui::PageTransitionCoreTypeIs(handle->GetPageTransition(),
- ui::PAGE_TRANSITION_RELOAD) ||
- // Some pages 'reload' from JavaScript by navigating to themselves.
- handle->GetURL() == handle->GetReferrer().url;
-}
+ ~SubresourceFilterSafeBrowsingActivationThrottle() = default;
content::NavigationThrottle::ThrottleCheckResult
SubresourceFilterSafeBrowsingActivationThrottle::WillRedirectRequest() {
CheckCurrentUrl();
- DCHECK(!database_client_ || !check_results_.empty());
return PROCEED;
}
content::NavigationThrottle::ThrottleCheckResult
SubresourceFilterSafeBrowsingActivationThrottle::WillProcessResponse() {
- DCHECK(!database_client_ || !check_results_.empty());
// No need to defer the navigation if the check already happened.
- if (!database_client_ || check_results_.back().finished) {
+ if (HasFinishedAllSafeBrowsingChecks()) {
NotifyResult();
return PROCEED;
}
@@ -143,7 +90,7 @@ void SubresourceFilterSafeBrowsingActivationThrottle::OnCheckUrlResultOnUI(
UMA_HISTOGRAM_TIMES("SubresourceFilter.SafeBrowsing.TotalCheckTime",
base::TimeTicks::Now() - check_start_times_[request_id]);
- if (deferring_ && request_id == check_results_.size() - 1) {
+ if (deferring_ && HasFinishedAllSafeBrowsingChecks()) {
NotifyResult();
deferring_ = false;
@@ -152,8 +99,7 @@ void SubresourceFilterSafeBrowsingActivationThrottle::OnCheckUrlResultOnUI(
}
void SubresourceFilterSafeBrowsingActivationThrottle::CheckCurrentUrl() {
- if (!database_client_)
- return;
+ DCHECK(database_client_);
check_start_times_.push_back(base::TimeTicks::Now());
check_results_.emplace_back();
size_t id = check_results_.size() - 1;
@@ -166,31 +112,19 @@ void SubresourceFilterSafeBrowsingActivationThrottle::CheckCurrentUrl() {
void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
"SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult");
- auto* driver_factory = ContentSubresourceFilterDriverFactory::FromWebContents(
- navigation_handle()->GetWebContents());
- DCHECK(driver_factory);
- if (driver_factory->GetMatchedConfigurationForLastCommittedPageLoad()
- .activation_options.should_whitelist_site_on_reload &&
- NavigationIsPageReload(navigation_handle())) {
- // Whitelist this host for the current as well as subsequent navigations.
- client_->WhitelistInCurrentWebContents(navigation_handle()->GetURL());
- }
-
// Compute the matched list and notify observers of the check result.
- DCHECK(!database_client_ || !check_results_.empty());
+ DCHECK(!check_results_.empty());
ActivationList matched_list = ActivationList::NONE;
bool warning = false;
- if (!check_results_.empty()) {
- const auto& check_result = check_results_.back();
- DCHECK(check_result.finished);
- matched_list = GetListForThreatTypeAndMetadata(
- check_result.threat_type, check_result.threat_metadata, &warning);
- SubresourceFilterObserverManager::FromWebContents(
- navigation_handle()->GetWebContents())
- ->NotifySafeBrowsingCheckComplete(navigation_handle(),
- check_result.threat_type,
- check_result.threat_metadata);
- }
+ const auto& check_result = check_results_.back();
+ DCHECK(check_result.finished);
+ matched_list = GetListForThreatTypeAndMetadata(
+ check_result.threat_type, check_result.threat_metadata, &warning);
+ SubresourceFilterObserverManager::FromWebContents(
+ navigation_handle()->GetWebContents())
+ ->NotifySafeBrowsingCheckComplete(navigation_handle(),
+ check_result.threat_type,
+ check_result.threat_metadata);
Configuration matched_configuration;
ActivationDecision activation_decision = ActivationDecision::UNKNOWN;
@@ -199,8 +133,12 @@ void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
activation_decision = ActivationDecision::ACTIVATED;
matched_configuration = Configuration::MakeForForcedActivation();
} else {
- activation_decision =
- ComputeActivation(matched_list, &matched_configuration);
+ base::Optional<Configuration> config =
+ GetHighestPriorityConfiguration(matched_list);
+ if (config.has_value()) {
+ matched_configuration = config.value();
+ }
+ activation_decision = GetActivationDecision(config);
}
DCHECK_NE(activation_decision, ActivationDecision::UNKNOWN);
@@ -211,8 +149,7 @@ void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
bool whitelisted = client_->OnPageActivationComputed(
navigation_handle(),
!warning && matched_configuration.activation_options.activation_level ==
- ActivationLevel::ENABLED,
- matched_configuration.activation_options.should_suppress_notifications);
+ ActivationLevel::ENABLED);
// Only reset the activation decision reason if we would have activated.
if (whitelisted && activation_decision == ActivationDecision::ACTIVATED) {
@@ -221,8 +158,22 @@ void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
matched_configuration = Configuration();
}
+ LogMetricsOnChecksComplete(
+ matched_list, activation_decision,
+ matched_configuration.activation_options.activation_level);
+
+ auto* driver_factory = ContentSubresourceFilterDriverFactory::FromWebContents(
+ navigation_handle()->GetWebContents());
+ DCHECK(driver_factory);
driver_factory->NotifyPageActivationComputed(
navigation_handle(), activation_decision, matched_configuration, warning);
+}
+
+void SubresourceFilterSafeBrowsingActivationThrottle::
+ LogMetricsOnChecksComplete(ActivationList matched_list,
+ ActivationDecision decision,
+ ActivationLevel level) const {
+ DCHECK(HasFinishedAllSafeBrowsingChecks());
base::TimeDelta delay = defer_time_.is_null()
? base::TimeDelta::FromMilliseconds(0)
@@ -237,56 +188,78 @@ void SubresourceFilterSafeBrowsingActivationThrottle::NotifyResult() {
UMA_HISTOGRAM_TIMES(
"SubresourceFilter.PageLoad.SafeBrowsingDelay.NoRedirectSpeculation",
no_redirect_speculation_delay);
+
+ ukm::SourceId source_id = ukm::ConvertToSourceId(
+ navigation_handle()->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID);
+ ukm::builders::SubresourceFilter builder(source_id);
+ builder.SetActivationDecision(static_cast<int64_t>(decision));
+ if (level == subresource_filter::ActivationLevel::DRYRUN) {
+ DCHECK_EQ(subresource_filter::ActivationDecision::ACTIVATED, decision);
+ builder.SetDryRun(true);
+ }
+ builder.Record(ukm::UkmRecorder::Get());
+
+ UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.PageLoad.ActivationDecision",
+ decision,
+ ActivationDecision::ACTIVATION_DECISION_MAX);
+ UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.PageLoad.ActivationList",
+ matched_list,
+ static_cast<int>(ActivationList::LAST) + 1);
+}
+
+bool SubresourceFilterSafeBrowsingActivationThrottle::
+ HasFinishedAllSafeBrowsingChecks() const {
+ for (const auto& check_result : check_results_) {
+ if (!check_result.finished) {
+ return false;
+ }
+ }
+ return true;
+}
+
+base::Optional<Configuration> SubresourceFilterSafeBrowsingActivationThrottle::
+ GetHighestPriorityConfiguration(ActivationList matched_list) {
+ base::Optional<Configuration> selected_config;
+
+ // If it's http or https, find the best config.
+ if (navigation_handle()->GetURL().SchemeIsHTTPOrHTTPS()) {
+ const auto& decreasing_configs =
+ GetEnabledConfigurations()->configs_by_decreasing_priority();
+ const auto selected_config_itr =
+ std::find_if(decreasing_configs.begin(), decreasing_configs.end(),
+ [matched_list, this](const Configuration& config) {
+ return DoesMainFrameURLSatisfyActivationConditions(
+ config.activation_conditions, matched_list);
+ });
+ if (selected_config_itr != decreasing_configs.end()) {
+ selected_config = *selected_config_itr;
+ }
+ }
+ TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("loading"),
+ "SubresourceFilterSafeBrowsingActivationThrottle::"
+ "GetHighestPriorityConfiguration",
+ "selected_config",
+ selected_config.has_value()
+ ? selected_config->ToTracedValue()
+ : std::make_unique<base::trace_event::TracedValue>());
+ return selected_config;
}
ActivationDecision
-SubresourceFilterSafeBrowsingActivationThrottle::ComputeActivation(
- ActivationList matched_list,
- Configuration* configuration) {
- const GURL& url(navigation_handle()->GetURL());
- const auto config_list = GetEnabledConfigurations();
- bool scheme_is_http_or_https = url.SchemeIsHTTPOrHTTPS();
- const auto highest_priority_activated_config =
- std::find_if(config_list->configs_by_decreasing_priority().begin(),
- config_list->configs_by_decreasing_priority().end(),
- [&url, scheme_is_http_or_https, matched_list,
- this](const Configuration& config) {
- return DoesMainFrameURLSatisfyActivationConditions(
- url, scheme_is_http_or_https,
- config.activation_conditions, matched_list);
- });
-
- bool has_activated_config =
- highest_priority_activated_config !=
- config_list->configs_by_decreasing_priority().end();
- TRACE_EVENT1(
- TRACE_DISABLED_BY_DEFAULT("loading"),
- "SubresourceFilterSafeBrowsingActivationThrottle::ComputeActivation",
- "highest_priority_activated_config",
- has_activated_config
- ? highest_priority_activated_config->ToTracedValue()
- : std::make_unique<base::trace_event::TracedValue>());
-
- if (!has_activated_config)
+SubresourceFilterSafeBrowsingActivationThrottle::GetActivationDecision(
+ const base::Optional<Configuration>& config) {
+ if (!config.has_value()) {
return ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET;
-
- const Configuration::ActivationOptions& activation_options =
- highest_priority_activated_config->activation_options;
- if (!scheme_is_http_or_https &&
- activation_options.activation_level != ActivationLevel::DISABLED) {
- return ActivationDecision::UNSUPPORTED_SCHEME;
}
- *configuration = *highest_priority_activated_config;
- return activation_options.activation_level == ActivationLevel::DISABLED
+ auto activation_level = config->activation_options.activation_level;
+ return activation_level == ActivationLevel::DISABLED
? ActivationDecision::ACTIVATION_DISABLED
: ActivationDecision::ACTIVATED;
}
bool SubresourceFilterSafeBrowsingActivationThrottle::
DoesMainFrameURLSatisfyActivationConditions(
- const GURL& url,
- bool scheme_is_http_or_https,
const Configuration::ActivationConditions& conditions,
ActivationList matched_list) const {
// Avoid copies when tracing disabled.
@@ -304,9 +277,6 @@ bool SubresourceFilterSafeBrowsingActivationThrottle::
case ActivationScope::ALL_SITES:
return true;
case ActivationScope::ACTIVATION_LIST:
- // ACTIVATION_LIST does not support non http/s URLs.
- if (!scheme_is_http_or_https)
- return false;
if (matched_list == ActivationList::NONE)
return false;
if (conditions.activation_list == matched_list)
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
index 39df919f736..13e76882da4 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle.h
@@ -22,10 +22,6 @@
#include "components/subresource_filter/core/common/activation_list.h"
#include "content/public/browser/navigation_throttle.h"
-namespace base {
-class GURL;
-} // namespace base
-
namespace subresource_filter {
class SubresourceFilterClient;
@@ -46,10 +42,6 @@ class SubresourceFilterSafeBrowsingActivationThrottle
~SubresourceFilterSafeBrowsingActivationThrottle() override;
- // Returns whether the navigation handle is a page reload, based on the
- // transition type and referrer.
- static bool NavigationIsPageReload(content::NavigationHandle* handle);
-
// content::NavigationThrottle:
content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest()
override;
@@ -64,14 +56,22 @@ class SubresourceFilterSafeBrowsingActivationThrottle
void CheckCurrentUrl();
void NotifyResult();
- ActivationDecision ComputeActivation(ActivationList matched_list,
- Configuration* configuration);
-
- // Returns whether a main-frame navigation to the given |url| satisfies the
- // activation |conditions| of a given configuration, except for |priority|.
+ void LogMetricsOnChecksComplete(ActivationList matched_list,
+ ActivationDecision decision,
+ ActivationLevel level) const;
+ bool HasFinishedAllSafeBrowsingChecks() const;
+ // Gets the configuration with the highest priority among those activated.
+ // Returns it, or none if no valid activated configurations.
+ base::Optional<Configuration> GetHighestPriorityConfiguration(
+ ActivationList matched_list);
+ // Gets the ActivationDecision for the given Configuration.
+ // Returns it, or ACTIVATION_CONDITIONS_NOT_MET if no Configuration.
+ ActivationDecision GetActivationDecision(
+ const base::Optional<Configuration>& config);
+
+ // Returns whether a main-frame navigation satisfies the activation
+ // |conditions| of a given configuration, except for |priority|.
bool DoesMainFrameURLSatisfyActivationConditions(
- const GURL& url,
- bool scheme_is_http_or_https,
const Configuration::ActivationConditions& conditions,
ActivationList matched_list) const;
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
index f10a102982d..aeef18cfa94 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_activation_throttle_unittest.cc
@@ -11,7 +11,7 @@
#include <utility>
#include <vector>
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/metrics/field_trial.h"
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
@@ -33,6 +33,8 @@
#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "components/ukm/content/source_url_recorder.h"
+#include "components/ukm/test_ukm_recorder.h"
#include "components/url_pattern_index/proto/rules.pb.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_handle.h"
@@ -40,6 +42,7 @@
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/test_navigation_throttle.h"
#include "content/public/test/test_renderer_host.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -50,28 +53,19 @@ namespace {
const char kUrlA[] = "https://example_a.com";
const char kUrlB[] = "https://example_b.com";
const char kUrlC[] = "https://example_c.com";
-const char kUrlD[] = "https://example_d.com";
char kURL[] = "http://example.test/";
char kURLWithParams[] = "http://example.test/?v=10";
char kRedirectURL[] = "http://redirect.test/";
-// Names of navigation chain patterns histogram.
-const char kMatchesPatternHistogramNameSubresourceFilterSuffix[] =
- "SubresourceFilter.PageLoad.RedirectChainMatchPattern."
- "SubresourceFilterOnly";
-const char kNavigationChainSizeSubresourceFilterSuffix[] =
- "SubresourceFilter.PageLoad.RedirectChainLength.SubresourceFilterOnly";
const char kSafeBrowsingNavigationDelay[] =
"SubresourceFilter.PageLoad.SafeBrowsingDelay";
const char kSafeBrowsingNavigationDelayNoSpeculation[] =
"SubresourceFilter.PageLoad.SafeBrowsingDelay.NoRedirectSpeculation";
const char kSafeBrowsingCheckTime[] =
"SubresourceFilter.SafeBrowsing.CheckTime";
-const char kMatchesPatternHistogramName[] =
+const char kActivationListHistogram[] =
"SubresourceFilter.PageLoad.ActivationList";
-const char kNavigationChainSize[] =
- "SubresourceFilter.PageLoad.RedirectChainLength.";
class MockSubresourceFilterClient : public SubresourceFilterClient {
public:
@@ -85,17 +79,11 @@ class MockSubresourceFilterClient : public SubresourceFilterClient {
}
bool OnPageActivationComputed(content::NavigationHandle* handle,
- bool activated,
- bool suppress_notifications) override {
+ bool activated) override {
DCHECK(handle->IsInMainFrame());
return whitelisted_hosts_.count(handle->GetURL().host());
}
- void WhitelistInCurrentWebContents(const GURL& url) override {
- ASSERT_TRUE(url.SchemeIsHTTPOrHTTPS());
- whitelisted_hosts_.insert(url.host());
- }
-
VerifiedRulesetDealer::Handle* GetRulesetDealer() override {
return ruleset_dealer_.get();
}
@@ -104,6 +92,11 @@ class MockSubresourceFilterClient : public SubresourceFilterClient {
MOCK_METHOD0(OnNewNavigationStarted, void());
MOCK_METHOD0(ForceActivationInCurrentWebContents, bool());
+ void WhitelistInCurrentWebContents(const GURL& url) {
+ ASSERT_TRUE(url.SchemeIsHTTPOrHTTPS());
+ whitelisted_hosts_.insert(url.host());
+ }
+
void ClearWhitelist() { whitelisted_hosts_.clear(); }
private:
@@ -183,7 +176,7 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
ASSERT_NO_FATAL_FAILURE(test_ruleset_creator_.CreateRulesetWithRules(
rules, &test_ruleset_pair_));
auto ruleset_dealer = std::make_unique<VerifiedRulesetDealer::Handle>(
- base::MessageLoop::current()->task_runner());
+ base::MessageLoopCurrent::Get()->task_runner());
ruleset_dealer->TryOpenAndSetRulesetFile(test_ruleset_pair_.indexed.path,
base::DoNothing());
client_ =
@@ -221,11 +214,6 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
content::RenderViewHostTestHarness::TearDown();
}
- ContentSubresourceFilterDriverFactory* factory() {
- return ContentSubresourceFilterDriverFactory::FromWebContents(
- RenderViewHostTestHarness::web_contents());
- }
-
TestSubresourceFilterObserver* observer() { return observer_.get(); }
// content::WebContentsObserver:
@@ -238,7 +226,9 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
fake_safe_browsing_database_));
}
std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
- factory()->throttle_manager()->MaybeAppendNavigationThrottles(
+ auto* factory = ContentSubresourceFilterDriverFactory::FromWebContents(
+ navigation_handle->GetWebContents());
+ factory->throttle_manager()->MaybeAppendNavigationThrottles(
navigation_handle, &throttles);
for (auto& it : throttles) {
navigation_handle->RegisterThrottleForTesting(std::move(it));
@@ -338,9 +328,6 @@ class SubresourceFilterSafeBrowsingActivationThrottleTest
fake_safe_browsing_database_->RemoveAllBlacklistedUrls();
}
- // With a null database the throttle becomes pass-through.
- void UsePassThroughThrottle() { fake_safe_browsing_database_ = nullptr; }
-
void RunUntilIdle() {
base::RunLoop().RunUntilIdle();
test_io_task_runner_->RunUntilIdle();
@@ -474,26 +461,6 @@ class SubresourceFilterSafeBrowsingActivationThrottleScopeTest
SubresourceFilterSafeBrowsingActivationThrottleScopeTest);
};
-TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
- PassThroughThrottle) {
- UsePassThroughThrottle();
- SimulateNavigateAndCommit({GURL(kURL), GURL(kRedirectURL)}, main_rfh());
- EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- *observer()->GetPageActivationForLastCommittedLoad());
-
- scoped_configuration()->ResetConfiguration(
- Configuration(ActivationLevel::ENABLED, ActivationScope::ALL_SITES));
- SimulateNavigateAndCommit({GURL(kURL), GURL(kRedirectURL)}, main_rfh());
- EXPECT_EQ(ActivationDecision::ACTIVATED,
- *observer()->GetPageActivationForLastCommittedLoad());
-
- scoped_configuration()->ResetConfiguration(
- Configuration(ActivationLevel::ENABLED, ActivationScope::NO_SITES));
- SimulateNavigateAndCommit({GURL(kURL), GURL(kRedirectURL)}, main_rfh());
- EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
- *observer()->GetPageActivationForLastCommittedLoad());
-}
-
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, NoConfigs) {
scoped_configuration()->ResetConfiguration(std::vector<Configuration>());
SimulateNavigateAndCommit({GURL(kURL)}, main_rfh());
@@ -512,7 +479,6 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
config2.activation_conditions.priority = 1;
Configuration config3(ActivationLevel::ENABLED, ActivationScope::ALL_SITES);
- config3.activation_options.should_whitelist_site_on_reload = true;
config3.activation_conditions.priority = 0;
scoped_configuration()->ResetConfiguration({config1, config2, config3});
@@ -533,15 +499,6 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
SimulateNavigateAndCommit({non_match_url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATED,
*observer()->GetPageActivationForLastCommittedLoad());
-
- // Should match |config3|, but a reload, so this should get whitelisted.
- auto reload_simulator = content::NavigationSimulator::CreateRendererInitiated(
- non_match_url, main_rfh());
- reload_simulator->SetTransition(ui::PAGE_TRANSITION_RELOAD);
- reload_simulator->Start();
- SimulateCommit(reload_simulator.get());
- EXPECT_EQ(ActivationDecision::URL_WHITELISTED,
- *observer()->GetPageActivationForLastCommittedLoad());
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
@@ -561,7 +518,7 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
*observer()->GetPageActivationForLastCommittedLoad());
// Whitelisting occurs last, so the decision should still be DISABLED.
- factory()->client()->WhitelistInCurrentWebContents(url);
+ client()->WhitelistInCurrentWebContents(url);
SimulateNavigateAndCommit({url}, main_rfh());
EXPECT_EQ(ActivationDecision::ACTIVATION_DISABLED,
*observer()->GetPageActivationForLastCommittedLoad());
@@ -613,61 +570,6 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
}
TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
- SuppressNotificationVisibility) {
- Configuration config(ActivationLevel::ENABLED, ActivationScope::ALL_SITES);
- config.activation_options.should_suppress_notifications = true;
- scoped_configuration()->ResetConfiguration(std::move(config));
-
- GURL url(kURL);
- content::RenderFrameHost* rfh = SimulateNavigateAndCommit({url}, main_rfh());
- EXPECT_CALL(*client(), ShowNotification()).Times(0);
- EXPECT_CALL(*client(), OnNewNavigationStarted()).Times(0);
- EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(rfh));
-}
-
-TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
- WhitelistSiteOnReload) {
- const struct {
- content::Referrer referrer;
- ui::PageTransition transition;
- ActivationDecision expected_activation_decision;
- } kTestCases[] = {
- {content::Referrer(), ui::PAGE_TRANSITION_LINK,
- ActivationDecision::ACTIVATED},
- {content::Referrer(GURL(kUrlA), blink::kWebReferrerPolicyDefault),
- ui::PAGE_TRANSITION_LINK, ActivationDecision::ACTIVATED},
- {content::Referrer(GURL(kURL), blink::kWebReferrerPolicyDefault),
- ui::PAGE_TRANSITION_LINK, ActivationDecision::URL_WHITELISTED},
- {content::Referrer(), ui::PAGE_TRANSITION_RELOAD,
- ActivationDecision::URL_WHITELISTED}};
-
- Configuration config(ActivationLevel::ENABLED, ActivationScope::ALL_SITES);
- config.activation_options.should_whitelist_site_on_reload = true;
- scoped_configuration()->ResetConfiguration(std::move(config));
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(::testing::Message("referrer = \"")
- << test_case.referrer.url << "\""
- << " transition = \"" << test_case.transition << "\"");
-
- auto simulator = content::NavigationSimulator::CreateRendererInitiated(
- GURL(kURL), main_rfh());
- simulator->SetTransition(test_case.transition);
- simulator->SetReferrer(test_case.referrer);
- SimulateCommit(simulator.get());
- EXPECT_EQ(test_case.expected_activation_decision,
- *observer()->GetPageActivationForLastCommittedLoad());
- // Verify that if the first URL failed to activate, subsequent same-origin
- // navigations also fail to activate.
- simulator = content::NavigationSimulator::CreateRendererInitiated(
- GURL(kURLWithParams), main_rfh());
- SimulateCommit(simulator.get());
- EXPECT_EQ(test_case.expected_activation_decision,
- *observer()->GetPageActivationForLastCommittedLoad());
- }
-}
-
-TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
ActivateForFrameState) {
const struct {
ActivationDecision activation_decision;
@@ -803,8 +705,69 @@ TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
fake_safe_browsing_database()->set_synchronous_failure();
SimulateStartAndExpectProceed(url);
SimulateCommitAndExpectProceed();
- tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
- 0);
+ tester().ExpectUniqueSample(kActivationListHistogram, ActivationList::NONE,
+ 1);
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, LogsUkm) {
+ ukm::InitializeSourceUrlRecorderForWebContents(
+ RenderViewHostTestHarness::web_contents());
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ const GURL url(kURL);
+ ConfigureForMatch(url);
+ SimulateNavigateAndCommit({url}, main_rfh());
+ using SubresourceFilter = ukm::builders::SubresourceFilter;
+ const auto& entries =
+ test_ukm_recorder.GetEntriesByName(SubresourceFilter::kEntryName);
+ EXPECT_EQ(1u, entries.size());
+ for (const auto* entry : entries) {
+ test_ukm_recorder.ExpectEntrySourceHasUrl(entry, url);
+ test_ukm_recorder.ExpectEntryMetric(
+ entry, SubresourceFilter::kActivationDecisionName,
+ static_cast<int64_t>(ActivationDecision::ACTIVATED));
+ }
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest,
+ LogsUkmNoActivation) {
+ ukm::InitializeSourceUrlRecorderForWebContents(
+ RenderViewHostTestHarness::web_contents());
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ const GURL url(kURL);
+ SimulateNavigateAndCommit({url}, main_rfh());
+ using SubresourceFilter = ukm::builders::SubresourceFilter;
+ const auto& entries =
+ test_ukm_recorder.GetEntriesByName(SubresourceFilter::kEntryName);
+ EXPECT_EQ(1u, entries.size());
+ for (const auto* entry : entries) {
+ test_ukm_recorder.ExpectEntrySourceHasUrl(entry, url);
+ test_ukm_recorder.ExpectEntryMetric(
+ entry, SubresourceFilter::kActivationDecisionName,
+ static_cast<int64_t>(
+ ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET));
+ }
+}
+
+TEST_F(SubresourceFilterSafeBrowsingActivationThrottleTest, LogsUkmDryRun) {
+ scoped_configuration()->ResetConfiguration(
+ Configuration(ActivationLevel::DRYRUN, ActivationScope::ALL_SITES));
+ ukm::InitializeSourceUrlRecorderForWebContents(
+ RenderViewHostTestHarness::web_contents());
+ ukm::TestAutoSetUkmRecorder test_ukm_recorder;
+ const GURL url(kURL);
+ SimulateNavigateAndCommit({url}, main_rfh());
+ using SubresourceFilter = ukm::builders::SubresourceFilter;
+ const auto& entries =
+ test_ukm_recorder.GetEntriesByName(SubresourceFilter::kEntryName);
+ EXPECT_EQ(1u, entries.size());
+ for (const auto* entry : entries) {
+ test_ukm_recorder.ExpectEntrySourceHasUrl(entry, url);
+ test_ukm_recorder.ExpectEntryMetric(
+ entry, SubresourceFilter::kActivationDecisionName,
+ static_cast<int64_t>(ActivationDecision::ACTIVATED));
+ test_ukm_recorder.ExpectEntryMetric(entry, SubresourceFilter::kDryRunName,
+ true);
+ }
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
@@ -821,7 +784,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
EXPECT_EQ(test_data.expected_activation_decision,
*observer()->GetPageActivationForLastCommittedLoad());
if (test_data.url_matches_activation_list) {
- factory()->client()->WhitelistInCurrentWebContents(test_url);
+ client()->WhitelistInCurrentWebContents(test_url);
ActivationDecision expected_decision =
test_data.expected_activation_decision;
if (expected_decision == ActivationDecision::ACTIVATED)
@@ -852,16 +815,7 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
if (test_data.url_matches_activation_list)
ConfigureForMatch(GURL(url));
SimulateNavigateAndCommit({GURL(url)}, main_rfh());
- ActivationDecision expected_decision =
- ActivationDecision::UNSUPPORTED_SCHEME;
- // We only log UNSUPPORTED_SCHEME if the navigation would have otherwise
- // activated. Note that non http/s URLs will never match an activation list.
- if (test_data.expected_activation_decision ==
- ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET ||
- test_data.activation_scope == ActivationScope::ACTIVATION_LIST) {
- expected_decision = ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET;
- }
- EXPECT_EQ(expected_decision,
+ EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
*observer()->GetPageActivationForLastCommittedLoad());
}
@@ -877,21 +831,17 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleScopeTest,
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
ListNotMatched_NoActivation) {
- const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
SimulateStartAndExpectProceed(url);
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ tester().ExpectUniqueSample(kActivationListHistogram,
static_cast<int>(ActivationList::NONE), 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelay, 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
tester().ExpectTotalCount(kSafeBrowsingCheckTime, 1);
-
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- tester().ExpectTotalCount(kNavigationChainSize + suffix, 0);
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
@@ -903,27 +853,21 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ tester().ExpectUniqueSample(kActivationListHistogram,
static_cast<int>(test_data.activation_list_type),
1);
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- tester().ExpectUniqueSample(kNavigationChainSize + suffix, 1, 1);
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
ListNotMatchedAfterRedirect_NoActivation) {
- const ActivationListTestData& test_data = GetParam();
const GURL url(kURL);
SimulateStartAndExpectProceed(url);
SimulateRedirectAndExpectProceed(GURL(kRedirectURL));
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ tester().ExpectUniqueSample(kActivationListHistogram,
static_cast<int>(ActivationList::NONE), 1);
-
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- tester().ExpectTotalCount(kNavigationChainSize + suffix, 0);
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
@@ -936,12 +880,9 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ tester().ExpectUniqueSample(kActivationListHistogram,
static_cast<int>(test_data.activation_list_type),
1);
-
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- tester().ExpectUniqueSample(kNavigationChainSize + suffix, 2, 1);
}
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
@@ -964,9 +905,6 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
- 0);
- tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelay, 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
tester().ExpectTotalCount(kSafeBrowsingCheckTime, 1);
@@ -986,13 +924,10 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ tester().ExpectUniqueSample(kActivationListHistogram,
static_cast<int>(test_data.activation_list_type),
1);
- const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- tester().ExpectUniqueSample(kNavigationChainSize + suffix, 1, 1);
-
tester().ExpectTimeBucketCount(kSafeBrowsingNavigationDelay,
base::TimeDelta::FromMilliseconds(0), 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
@@ -1015,13 +950,11 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATED,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectUniqueSample(kMatchesPatternHistogramName,
+ tester().ExpectUniqueSample(kActivationListHistogram,
static_cast<int>(test_data.activation_list_type),
1);
const std::string suffix(GetSuffixForList(test_data.activation_list_type));
- tester().ExpectUniqueSample(kNavigationChainSize + suffix, 2, 1);
-
tester().ExpectTimeBucketCount(kSafeBrowsingNavigationDelay,
base::TimeDelta::FromMilliseconds(0), 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
@@ -1046,75 +979,11 @@ TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
SimulateCommitAndExpectProceed();
EXPECT_EQ(ActivationDecision::ACTIVATION_CONDITIONS_NOT_MET,
*observer()->GetPageActivationForLastCommittedLoad());
- tester().ExpectTotalCount(kMatchesPatternHistogramNameSubresourceFilterSuffix,
- 0);
- tester().ExpectTotalCount(kNavigationChainSizeSubresourceFilterSuffix, 0);
tester().ExpectTimeBucketCount(kSafeBrowsingNavigationDelay,
base::TimeDelta::FromMilliseconds(0), 1);
tester().ExpectTotalCount(kSafeBrowsingNavigationDelayNoSpeculation, 1);
}
-TEST_P(SubresourceFilterSafeBrowsingActivationThrottleParamTest,
- RedirectPatternTest) {
- struct RedirectRedirectChainMatchPatternTestData {
- std::vector<bool> blacklisted_urls;
- std::vector<GURL> navigation_chain;
- } kRedirectRecordedHistogramsTestData[] = {
- {{false}, {GURL(kUrlA)}},
- {{true}, {GURL(kUrlA)}},
- {{false, false}, {GURL(kUrlA), GURL(kUrlB)}},
- {{false, true}, {GURL(kUrlA), GURL(kUrlB)}},
- {{true, false}, {GURL(kUrlA), GURL(kUrlB)}},
- {{true, true}, {GURL(kUrlA), GURL(kUrlB)}},
- {{false, false, false}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{false, false, true}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{false, true, false}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{false, true, true}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{true, false, false}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{true, false, true}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{true, true, false}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{true, true, true}, {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC)}},
- {{false, true, false, false},
- {GURL(kUrlA), GURL(kUrlB), GURL(kUrlC), GURL(kUrlD)}},
- };
-
- for (const auto& test_data : kRedirectRecordedHistogramsTestData) {
- base::HistogramTester histogram_tester;
- ClearAllBlacklistedUrls();
- auto it = test_data.navigation_chain.begin();
- for (size_t i = 0u; i < test_data.blacklisted_urls.size(); ++i) {
- if (test_data.blacklisted_urls[i])
- ConfigureForMatchParam(test_data.navigation_chain[i]);
- }
- SimulateStartAndExpectProceed(*it);
- for (++it; it != test_data.navigation_chain.end(); ++it)
- SimulateRedirectAndExpectProceed(*it);
- SimulateCommitAndExpectProceed();
-
- // Verify histograms
- const std::string suffix_param(
- GetSuffixForList(GetParam().activation_list_type));
- auto check_histogram = [&](std::string suffix) {
- bool matches =
- suffix == suffix_param && test_data.blacklisted_urls.back();
- if (matches) {
- histogram_tester.ExpectUniqueSample(
- kMatchesPatternHistogramName,
- static_cast<int>(GetParam().activation_list_type), 1);
- histogram_tester.ExpectBucketCount(kNavigationChainSize + suffix,
- test_data.navigation_chain.size(),
- 1);
- } else {
- histogram_tester.ExpectTotalCount(kNavigationChainSize + suffix, 0);
- }
- };
-
- check_histogram("SocialEngineeringAdsInterstitial");
- check_histogram("PhishingInterstitial");
- check_histogram("SubresourceFilterOnly");
- }
-}
-
TEST_P(SubresourceFilterSafeBrowsingActivationThrottleTestWithCancelling,
Cancel) {
const GURL url(kURL);
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
index 64b7b47be47..5d45004d3f9 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.cc
@@ -37,7 +37,9 @@ SubresourceFilterSafeBrowsingClient::SubresourceFilterSafeBrowsingClient(
: database_manager_(std::move(database_manager)),
throttle_(std::move(throttle)),
io_task_runner_(std::move(io_task_runner)),
- throttle_task_runner_(std::move(throttle_task_runner)) {}
+ throttle_task_runner_(std::move(throttle_task_runner)) {
+ DCHECK(database_manager_);
+}
SubresourceFilterSafeBrowsingClient::~SubresourceFilterSafeBrowsingClient() {}
diff --git a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc
index b43fb8fdf1e..c390432617e 100644
--- a/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc
+++ b/chromium/components/subresource_filter/content/browser/subresource_filter_safe_browsing_client_request.cc
@@ -13,7 +13,6 @@
#include "base/metrics/histogram_macros.h"
#include "base/single_thread_task_runner.h"
#include "components/subresource_filter/content/browser/subresource_filter_safe_browsing_client.h"
-#include "components/subresource_filter/core/common/time_measurements.h"
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
@@ -47,10 +46,14 @@ SubresourceFilterSafeBrowsingClientRequest::
void SubresourceFilterSafeBrowsingClientRequest::Start(const GURL& url) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
start_time_ = base::TimeTicks::Now();
+
+ // Just return SAFE if the database is not supported.
+ // TODO(csharrison): Remove CanCheckSubresourceFilter now that V4 has fully
+ // shipped.
bool synchronous_finish =
+ !database_manager_->IsSupported() ||
+ !database_manager_->CanCheckSubresourceFilter() ||
database_manager_->CheckUrlForSubresourceFilter(url, this);
- UMA_HISTOGRAM_MICRO_TIMES("SubresourceFilter.SafeBrowsing.CheckDispatchTime",
- (base::TimeTicks::Now() - start_time_));
if (synchronous_finish) {
request_completed_ = true;
SendCheckResultToClient(false /* served_from_network */,
diff --git a/chromium/components/subresource_filter/content/common/ad_delay_throttle.cc b/chromium/components/subresource_filter/content/common/ad_delay_throttle.cc
index 3fa1bc82d4e..be5c04e4048 100644
--- a/chromium/components/subresource_filter/content/common/ad_delay_throttle.cc
+++ b/chromium/components/subresource_filter/content/common/ad_delay_throttle.cc
@@ -5,6 +5,7 @@
#include "components/subresource_filter/content/common/ad_delay_throttle.h"
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/feature_list.h"
@@ -14,6 +15,8 @@
#include "base/metrics/histogram_macros.h"
#include "base/sequenced_task_runner.h"
#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
#include "components/subresource_filter/core/common/common_features.h"
#include "url/gurl.h"
#include "url/url_constants.h"
@@ -26,7 +29,82 @@ void LogSecureInfo(AdDelayThrottle::SecureInfo info) {
UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.AdDelay.SecureInfo", info);
}
-} // namespace
+class InsecureCondition : public AdDelayThrottle::DeferCondition {
+ public:
+ InsecureCondition(base::TimeDelta delay,
+ AdDelayThrottle::MetadataProvider* provider)
+ : DeferCondition(delay, provider) {}
+ ~InsecureCondition() override {
+ if (provider()->IsAdRequest()) {
+ LogSecureInfo(was_condition_ever_satisfied()
+ ? AdDelayThrottle::SecureInfo::kInsecureAd
+ : AdDelayThrottle::SecureInfo::kSecureAd);
+ } else {
+ LogSecureInfo(was_condition_ever_satisfied()
+ ? AdDelayThrottle::SecureInfo::kInsecureNonAd
+ : AdDelayThrottle::SecureInfo::kSecureNonAd);
+ }
+ }
+
+ private:
+ // DeferCondition:
+ bool IsConditionSatisfied(const GURL& url) override {
+ // Note: this should probably be using content::IsOriginSecure which
+ // accounts for things like whitelisted origins, localhost, etc. This isn't
+ // used here because that function is quite expensive for insecure schemes,
+ // involving many allocations and string scans.
+ return url.SchemeIs(url::kHttpScheme);
+ }
+};
+
+class NonIsolatedCondition : public AdDelayThrottle::DeferCondition {
+ public:
+ NonIsolatedCondition(base::TimeDelta delay,
+ AdDelayThrottle::MetadataProvider* provider)
+ : DeferCondition(delay, provider) {}
+ ~NonIsolatedCondition() override {
+ if (provider()->IsAdRequest()) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "SubresourceFilter.AdDelay.IsolatedInfo",
+ was_condition_ever_satisfied()
+ ? AdDelayThrottle::IsolatedInfo::kNonIsolatedAd
+ : AdDelayThrottle::IsolatedInfo::kIsolatedAd);
+ }
+ }
+
+ private:
+ // DeferCondition:
+ bool IsConditionSatisfied(const GURL& url) override {
+ return provider()->RequestIsInNonIsolatedSubframe();
+ }
+};
+
+}; // namespace
+
+AdDelayThrottle::DeferCondition::DeferCondition(
+ base::TimeDelta delay,
+ AdDelayThrottle::MetadataProvider* provider)
+ : delay_(delay), provider_(provider) {
+ DCHECK(provider);
+}
+AdDelayThrottle::DeferCondition::~DeferCondition() = default;
+
+bool AdDelayThrottle::DeferCondition::ShouldDefer(const GURL& url) {
+ if (was_condition_applied_) {
+ DCHECK(was_condition_ever_satisfied_);
+ return false;
+ }
+ was_condition_ever_satisfied_ |= IsConditionSatisfied(url);
+ return was_condition_ever_satisfied_;
+}
+
+// The request will be deferred. Returns the amount of time to defer.
+base::TimeDelta AdDelayThrottle::DeferCondition::OnReadyToDefer() {
+ DCHECK(!was_condition_applied_);
+ DCHECK(was_condition_ever_satisfied_);
+ was_condition_applied_ = true;
+ return delay_;
+}
constexpr base::TimeDelta AdDelayThrottle::kDefaultDelay;
@@ -36,6 +114,11 @@ AdDelayThrottle::Factory::Factory()
kDelayUnsafeAds,
kInsecureDelayParam,
kDefaultDelay.InMilliseconds()))),
+ non_isolated_delay_(base::TimeDelta::FromMilliseconds(
+ base::GetFieldTrialParamByFeatureAsInt(
+ kDelayUnsafeAds,
+ kNonIsolatedDelayParam,
+ kDefaultDelay.InMilliseconds()))),
delay_enabled_(base::FeatureList::IsEnabled(kAdTagging) &&
base::FeatureList::IsEnabled(kDelayUnsafeAds)) {}
@@ -44,18 +127,16 @@ AdDelayThrottle::Factory::~Factory() = default;
std::unique_ptr<AdDelayThrottle> AdDelayThrottle::Factory::MaybeCreate(
std::unique_ptr<AdDelayThrottle::MetadataProvider> provider) const {
DCHECK(provider);
- return base::WrapUnique(new AdDelayThrottle(std::move(provider),
- insecure_delay_, delay_enabled_));
+ return base::WrapUnique(new AdDelayThrottle(std::move(provider), this));
}
-// TODO(csharrison): Log metrics for actual delay time.
AdDelayThrottle::~AdDelayThrottle() {
- if (provider_->IsAdRequest()) {
- LogSecureInfo(was_ever_insecure_ ? SecureInfo::kInsecureAd
- : SecureInfo::kSecureAd);
- } else {
- LogSecureInfo(was_ever_insecure_ ? SecureInfo::kInsecureNonAd
- : SecureInfo::kSecureNonAd);
+ if (!expected_delay_.is_zero()) {
+ UMA_HISTOGRAM_TIMES("SubresourceFilter.AdDelay.Delay", actual_delay_);
+ UMA_HISTOGRAM_TIMES("SubresourceFilter.AdDelay.Delay.Expected",
+ expected_delay_);
+ UMA_HISTOGRAM_TIMES("SubresourceFilter.AdDelay.Delay.Queuing",
+ actual_delay_ - expected_delay_);
}
}
@@ -80,42 +161,49 @@ void AdDelayThrottle::WillRedirectRequest(
}
bool AdDelayThrottle::MaybeDefer(const GURL& url) {
- if (has_deferred_)
- return false;
-
- // Note: this should probably be using content::IsOriginSecure which accounts
- // for things like whitelisted origins, localhost, etc. This isn't used here
- // because that function is quite expensive for insecure schemes, involving
- // many allocations and string scans.
- was_ever_insecure_ |= url.SchemeIs(url::kHttpScheme);
- if (!was_ever_insecure_ || !provider_->IsAdRequest())
- return false;
+ // Check for condition matching before checking if the feature is enabled, to
+ // ensure metrics can be reported.
+ std::vector<DeferCondition*> matched_conditions;
+ for (auto& condition : defer_conditions_) {
+ if (condition->ShouldDefer(url))
+ matched_conditions.push_back(condition.get());
+ }
- // Bail out right before we'd actually defer if the feature isn't enabled.
- if (!delay_enabled_)
+ if (!delay_enabled_ || matched_conditions.empty() ||
+ !provider_->IsAdRequest()) {
return false;
+ }
+ base::TimeDelta delay;
+ for (DeferCondition* condition : matched_conditions) {
+ delay += condition->OnReadyToDefer();
+ }
// TODO(csharrison): Consider logging to the console here that Chrome
// delayed this request.
- has_deferred_ = true;
+ expected_delay_ += delay;
base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
- base::BindOnce(&AdDelayThrottle::Resume, weak_factory_.GetWeakPtr()),
- insecure_delay_);
+ base::BindOnce(&AdDelayThrottle::Resume, weak_factory_.GetWeakPtr(),
+ tick_clock_->NowTicks()),
+ delay);
return true;
}
-void AdDelayThrottle::Resume() {
+void AdDelayThrottle::Resume(base::TimeTicks defer_start) {
+ actual_delay_ += tick_clock_->NowTicks() - defer_start;
delegate_->Resume();
}
AdDelayThrottle::AdDelayThrottle(std::unique_ptr<MetadataProvider> provider,
- base::TimeDelta insecure_delay,
- bool delay_enabled)
- : content::URLLoaderThrottle(),
- provider_(std::move(provider)),
- insecure_delay_(insecure_delay),
- delay_enabled_(delay_enabled),
- weak_factory_(this) {}
+ const AdDelayThrottle::Factory* factory)
+ : provider_(std::move(provider)),
+ tick_clock_(base::DefaultTickClock::GetInstance()),
+ delay_enabled_(factory->delay_enabled()),
+ weak_factory_(this) {
+ defer_conditions_.emplace_back(std::make_unique<InsecureCondition>(
+ factory->insecure_delay(), provider_.get()));
+ defer_conditions_.emplace_back(std::make_unique<NonIsolatedCondition>(
+ factory->non_isolated_delay(), provider_.get()));
+}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/common/ad_delay_throttle.h b/chromium/components/subresource_filter/content/common/ad_delay_throttle.h
index 02fb44f01df..3e6a6e999c5 100644
--- a/chromium/components/subresource_filter/content/common/ad_delay_throttle.h
+++ b/chromium/components/subresource_filter/content/common/ad_delay_throttle.h
@@ -15,8 +15,14 @@
class GURL;
+namespace base {
+class TickClock;
+} // namespace base
+
namespace subresource_filter {
+class DeferCondition;
+
// This class delays ad requests satisfying certain conditions.
// - The ad is insecure (e.g. uses http).
// TODO(csharrison): Add delays for when the request is in a same-origin iframe.
@@ -29,8 +35,10 @@ class AdDelayThrottle : public content::URLLoaderThrottle {
public:
virtual ~MetadataProvider() {}
virtual bool IsAdRequest() = 0;
- // TODO(csharrison): Add an interface for querying same-origin iframe
- // status.
+
+ // Whether the request is taking place in a non-isolated (e.g. same-domain)
+ // iframe. Should default to false if the isolation status is unknown.
+ virtual bool RequestIsInNonIsolatedSubframe() = 0;
};
// Mainly used for caching values that we don't want to compute for every
@@ -44,9 +52,12 @@ class AdDelayThrottle : public content::URLLoaderThrottle {
std::unique_ptr<MetadataProvider> provider) const;
base::TimeDelta insecure_delay() const { return insecure_delay_; }
+ base::TimeDelta non_isolated_delay() const { return non_isolated_delay_; }
+ bool delay_enabled() const { return delay_enabled_; }
private:
const base::TimeDelta insecure_delay_;
+ const base::TimeDelta non_isolated_delay_;
const bool delay_enabled_ = false;
DISALLOW_COPY_AND_ASSIGN(Factory);
@@ -68,8 +79,60 @@ class AdDelayThrottle : public content::URLLoaderThrottle {
kMaxValue = kInsecureNonAd
};
+ // This enum backs a histogram. Make sure to only append elements, and update
+ // enums.xml with new values.
+ enum class IsolatedInfo {
+ // Ad that was loaded isolated from the top-level page (e.g. from a
+ // cross-domain iframe).
+ kIsolatedAd = 0,
+
+ // Ad loaded from a non-isolated context.
+ kNonIsolatedAd = 1,
+
+ // Add new elements above kLast.
+ kMaxValue = kNonIsolatedAd
+ };
+ // The AdDelayThrottle has multiple possible conditions which can cause
+ // delays. These conditions will subclass DeferCondition and override
+ // IsConditionSatisfied.
+ class DeferCondition {
+ public:
+ DeferCondition(base::TimeDelta delay,
+ AdDelayThrottle::MetadataProvider* provider);
+ virtual ~DeferCondition();
+
+ bool ShouldDefer(const GURL& url);
+
+ // The request will be deferred. Returns the amount of time to defer. Should
+ // be called at most once after ShouldDefer returns true.
+ base::TimeDelta OnReadyToDefer();
+
+ bool was_condition_ever_satisfied() const {
+ return was_condition_ever_satisfied_;
+ }
+
+ AdDelayThrottle::MetadataProvider* provider() { return provider_; }
+
+ protected:
+ virtual bool IsConditionSatisfied(const GURL& url) = 0;
+
+ private:
+ base::TimeDelta delay_;
+
+ // Must outlive this object. Will always be non-nullptr.
+ AdDelayThrottle::MetadataProvider* provider_;
+
+ bool was_condition_applied_ = false;
+ bool was_condition_ever_satisfied_ = false;
+ DISALLOW_COPY_AND_ASSIGN(DeferCondition);
+ };
+
~AdDelayThrottle() override;
+ void set_tick_clock_for_testing(const base::TickClock* tick_clock) {
+ tick_clock_ = tick_clock;
+ }
+
private:
// content::URLLoaderThrottle:
void DetachFromCurrentSequence() override;
@@ -81,23 +144,23 @@ class AdDelayThrottle : public content::URLLoaderThrottle {
// Returns whether the request to |url| should be deferred.
bool MaybeDefer(const GURL& url);
- void Resume();
+ void Resume(base::TimeTicks defer_start);
AdDelayThrottle(std::unique_ptr<MetadataProvider> provider,
- base::TimeDelta insecure_delay,
- bool delay_enabled);
+ const Factory* factory);
// Will never be nullptr.
std::unique_ptr<MetadataProvider> provider_;
- // How long to delay an ad request that is insecure.
- const base::TimeDelta insecure_delay_;
+ // Must be destroyed before |provider_|.
+ std::vector<std::unique_ptr<DeferCondition>> defer_conditions_;
- // Only defer at most once per request.
- bool has_deferred_ = false;
+ // Must never be nullptr.
+ const base::TickClock* tick_clock_;
- // Tracks whether this request was ever insecure, across all its redirects.
- bool was_ever_insecure_ = false;
+ // Will be zero if no delay occurs.
+ base::TimeDelta expected_delay_;
+ base::TimeDelta actual_delay_;
// Whether to actually delay the request. If set to false, will operate in a
// dry-run style mode that only logs metrics.
diff --git a/chromium/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc b/chromium/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc
index eee934a34c1..04d10e381a4 100644
--- a/chromium/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc
+++ b/chromium/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc
@@ -5,6 +5,7 @@
#include "components/subresource_filter/content/common/ad_delay_throttle.h"
#include <memory>
+#include <string>
#include <utility>
#include <vector>
@@ -15,11 +16,12 @@
#include "base/test/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
+#include "base/test/simple_test_tick_clock.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/subresource_filter/core/common/common_features.h"
-#include "content/public/common/weak_wrapper_shared_url_loader_factory.h"
#include "content/public/test/throttling_url_loader_test_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/url_loader.mojom.h"
#include "services/network/test/test_url_loader_client.h"
#include "services/network/test/test_url_loader_factory.h"
@@ -36,7 +38,7 @@ class AdDelayThrottleTest : public testing::Test {
base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME),
client_(std::make_unique<network::TestURLLoaderClient>()),
shared_factory_(
- base::MakeRefCounted<content::WeakWrapperSharedURLLoaderFactory>(
+ base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&loader_factory_)) {
scoped_ad_tagging_.InitAndEnableFeature(kAdTagging);
}
@@ -61,10 +63,10 @@ class AdDelayThrottleTest : public testing::Test {
return loader;
}
- base::TimeDelta GetExpectedDelay() const {
+ base::TimeDelta GetExpectedDelay(const char* param) const {
return base::TimeDelta::FromMilliseconds(
base::GetFieldTrialParamByFeatureAsInt(
- kDelayUnsafeAds, kInsecureDelayParam,
+ kDelayUnsafeAds, param,
AdDelayThrottle::kDefaultDelay.InMilliseconds()));
}
@@ -79,24 +81,29 @@ class AdDelayThrottleTest : public testing::Test {
// InitAndEnableFeaturesWithParameters does not support enabling multiple
// features.
base::test::ScopedFeatureList scoped_ad_tagging_;
- scoped_refptr<content::WeakWrapperSharedURLLoaderFactory> shared_factory_;
+ scoped_refptr<network::WeakWrapperSharedURLLoaderFactory> shared_factory_;
DISALLOW_COPY_AND_ASSIGN(AdDelayThrottleTest);
};
// Metadata provider that by default, provides metadata indicating that the
-// request is an ad.
+// request is an isolated ad.
class MockMetadataProvider : public AdDelayThrottle::MetadataProvider {
public:
MockMetadataProvider() {}
void set_is_ad_request(bool is_ad_request) { is_ad_request_ = is_ad_request; }
+ void set_is_non_isolated(bool is_non_isolated) {
+ is_non_isolated_ = is_non_isolated;
+ }
// AdDelayThrottle::MetadataProvider:
bool IsAdRequest() override { return is_ad_request_; }
+ bool RequestIsInNonIsolatedSubframe() override { return is_non_isolated_; }
private:
bool is_ad_request_ = true;
+ bool is_non_isolated_ = false;
DISALLOW_COPY_AND_ASSIGN(MockMetadataProvider);
};
@@ -147,118 +154,112 @@ TEST_F(AdDelayThrottleTest, NoAdTagging_NoDelay) {
EXPECT_TRUE(client_->has_received_completion());
}
-TEST_F(AdDelayThrottleTest, InsecureNonAd_NoDelay) {
- AdDelayThrottle::Factory factory;
- auto metadata = std::make_unique<MockMetadataProvider>();
- metadata->set_is_ad_request(false);
- auto throttle = factory.MaybeCreate(std::move(metadata));
- EXPECT_NE(nullptr, throttle);
- std::string url = "http://example.test/ad.js";
- loader_factory_.AddResponse(url, "var ads = 1;");
- std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
- CreateLoaderAndStart(GURL(url), std::move(throttle));
- scoped_environment_.RunUntilIdle();
-
- EXPECT_TRUE(client_->has_received_completion());
-}
-
-TEST_F(AdDelayThrottleTest, SecureAdRequest_NoDelay) {
- AdDelayThrottle::Factory factory;
- auto throttle = factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
- EXPECT_NE(nullptr, throttle);
- std::string url = "https://example.test/ad.js";
- loader_factory_.AddResponse(url, "var ads = 1;");
- std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
- CreateLoaderAndStart(GURL(url), std::move(throttle));
- scoped_environment_.RunUntilIdle();
-
- EXPECT_TRUE(client_->has_received_completion());
-}
-
-TEST_F(AdDelayThrottleTest, InsecureAdRequest_Delay) {
- AdDelayThrottle::Factory factory;
- auto throttle = factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
- EXPECT_NE(nullptr, throttle);
- std::string url = "http://example.test/ad.js";
- loader_factory_.AddResponse(url, "var ads = 1;");
- std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
- CreateLoaderAndStart(GURL(url), std::move(throttle));
- scoped_environment_.RunUntilIdle();
-
- EXPECT_FALSE(client_->has_received_completion());
- scoped_environment_.FastForwardBy(GetExpectedDelay());
- EXPECT_TRUE(client_->has_received_completion());
-}
-
-TEST_F(AdDelayThrottleTest, DelayFromFieldTrialParam) {
+TEST_F(AdDelayThrottleTest, AdDelay) {
+ enum class IsNonIsolated { kYes, kNo };
+ enum class IsAd { kYes, kNo };
+ enum class WillFinish { kYes, kNo };
+ struct TestCase {
+ const char* first_url;
+ const char* redirect_url; // nullptr if no redirect.
+ IsNonIsolated is_non_isolated;
+ IsAd is_ad;
+ int fast_forward_ms;
+ WillFinish will_finish;
+ } kTestCases[] = {
+ // Isolated and secure -> no delay.
+ {"https://ad.test/", nullptr, IsNonIsolated::kNo, IsAd::kYes, 0,
+ WillFinish::kYes},
+
+ // Isolated and insecure -> delays 50ms.
+ {"http://ad.test/", nullptr, IsNonIsolated::kNo, IsAd::kYes, 49,
+ WillFinish::kNo},
+ {"http://ad.test/", nullptr, IsNonIsolated::kNo, IsAd::kYes, 50,
+ WillFinish::kYes},
+ {"http://ad.test/", nullptr, IsNonIsolated::kNo, IsAd::kNo, 0,
+ WillFinish::kYes},
+
+ // Non-isolated and secure -> delays 100ms.
+ {"https://ad.test/", nullptr, IsNonIsolated::kYes, IsAd::kYes, 99,
+ WillFinish::kNo},
+ {"https://ad.test/", nullptr, IsNonIsolated::kYes, IsAd::kYes, 100,
+ WillFinish::kYes},
+ {"https://ad.test/", nullptr, IsNonIsolated::kYes, IsAd::kNo, 0,
+ WillFinish::kYes},
+
+ // Non-isolated and insecure -> delays 150ms.
+ {"http://ad.test/", nullptr, IsNonIsolated::kYes, IsAd::kYes, 149,
+ WillFinish::kNo},
+ {"http://ad.test/", nullptr, IsNonIsolated::kYes, IsAd::kYes, 150,
+ WillFinish::kYes},
+ {"http://ad.test/", nullptr, IsNonIsolated::kYes, IsAd::kNo, 0,
+ WillFinish::kYes},
+
+ // Isolated and insecure redirect -> delays 50ms.
+ {"https://ad.test/", "http://ad.test/", IsNonIsolated::kNo, IsAd::kYes,
+ 49, WillFinish::kNo},
+ {"https://ad.test/", "http://ad.test/", IsNonIsolated::kNo, IsAd::kYes,
+ 50, WillFinish::kYes},
+ {"https://ad.test/", "http://ad.test/", IsNonIsolated::kNo, IsAd::kNo, 0,
+ WillFinish::kYes},
+
+ // Non-isolated and insecure redirect -> delays 150ms total.
+ {"https://ad.test/", "http://ad.test/", IsNonIsolated::kYes, IsAd::kYes,
+ 149, WillFinish::kNo},
+ {"https://ad.test/", "http://ad.test/", IsNonIsolated::kYes, IsAd::kYes,
+ 150, WillFinish::kYes},
+ {"https://ad.test/", "http://ad.test/", IsNonIsolated::kYes, IsAd::kNo, 0,
+ WillFinish::kYes},
+
+ // Isolated + insecure with insecure redirect -> delays 50ms only.
+ {"http://ad.test/", "http://ad.test/", IsNonIsolated::kNo, IsAd::kYes, 49,
+ WillFinish::kNo},
+ {"http://ad.test/", "http://ad.test/", IsNonIsolated::kNo, IsAd::kYes, 50,
+ WillFinish::kYes},
+ {"http://ad.test/", "http://ad.test/", IsNonIsolated::kNo, IsAd::kNo, 0,
+ WillFinish::kYes},
+ };
+ // Initialize delays so insecure and non-isolated are not equal.
base::test::ScopedFeatureList scoped_params;
scoped_params.InitAndEnableFeatureWithParameters(
- kDelayUnsafeAds, {{kInsecureDelayParam, "100"}});
- EXPECT_EQ(base::TimeDelta::FromMilliseconds(100), GetExpectedDelay());
-
- AdDelayThrottle::Factory factory;
- auto throttle = factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
- std::string url = "http://example.test/ad.js";
- loader_factory_.AddResponse(url, "var ads = 1;");
- std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
- CreateLoaderAndStart(GURL(url), std::move(throttle));
- scoped_environment_.RunUntilIdle();
-
- EXPECT_FALSE(client_->has_received_completion());
-
- // Ensure that we are using the greater delay here by first fast forwarding
- // just before the expected delay.
- base::TimeDelta non_triggering_delay = base::TimeDelta::FromMilliseconds(99);
- scoped_environment_.FastForwardBy(non_triggering_delay);
- EXPECT_FALSE(client_->has_received_completion());
- scoped_environment_.FastForwardBy(base::TimeDelta::FromMilliseconds(1));
- EXPECT_TRUE(client_->has_received_completion());
-}
-
-TEST_F(AdDelayThrottleTest, InsecureAdRequestRedirect_Delay) {
- AdDelayThrottle::Factory factory;
- auto throttle = factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
- EXPECT_NE(nullptr, throttle);
- const GURL url("https://example.test/ad.js");
-
- net::RedirectInfo redirect_info;
- redirect_info.status_code = 301;
- redirect_info.new_url = GURL("http://example.test/ad.js");
- network::TestURLLoaderFactory::Redirects redirects{
- {redirect_info, network::ResourceResponseHead()}};
- loader_factory_.AddResponse(url, network::ResourceResponseHead(),
- "var ads = 1;",
- network::URLLoaderCompletionStatus(), redirects);
- std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
- CreateLoaderAndStart(GURL(url), std::move(throttle));
- scoped_environment_.RunUntilIdle();
-
- EXPECT_FALSE(client_->has_received_completion());
- scoped_environment_.FastForwardBy(GetExpectedDelay());
- EXPECT_TRUE(client_->has_received_completion());
-}
-
-TEST_F(AdDelayThrottleTest, InsecureRedirectChain_DelaysOnce) {
- AdDelayThrottle::Factory factory;
- auto throttle = factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
- EXPECT_NE(nullptr, throttle);
- const GURL url("http://example.test/ad.js");
-
- net::RedirectInfo redirect_info;
- redirect_info.status_code = 301;
- redirect_info.new_url = GURL("http://example2.test/ad.js");
- network::TestURLLoaderFactory::Redirects redirects{
- {redirect_info, network::ResourceResponseHead()}};
- loader_factory_.AddResponse(url, network::ResourceResponseHead(),
- "var ads = 1;",
- network::URLLoaderCompletionStatus(), redirects);
- std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
- CreateLoaderAndStart(GURL(url), std::move(throttle));
- scoped_environment_.RunUntilIdle();
-
- EXPECT_FALSE(client_->has_received_completion());
- scoped_environment_.FastForwardBy(GetExpectedDelay());
- EXPECT_TRUE(client_->has_received_completion());
+ kDelayUnsafeAds,
+ {{kInsecureDelayParam, "50"}, {kNonIsolatedDelayParam, "100"}});
+ for (const auto& test : kTestCases) {
+ bool is_ad = test.is_ad == IsAd::kYes;
+ bool is_non_isolated = test.is_non_isolated == IsNonIsolated::kYes;
+ SCOPED_TRACE(testing::Message()
+ << test.first_url << " -> "
+ << (test.redirect_url ? test.redirect_url : "<nullptr>")
+ << " is_ad = " << is_ad
+ << " is_non_isolated = " << is_non_isolated
+ << " fast_forward_ms = " << test.fast_forward_ms);
+ AdDelayThrottle::Factory factory;
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto provider = std::make_unique<MockMetadataProvider>();
+ provider->set_is_non_isolated(is_non_isolated);
+ provider->set_is_ad_request(is_ad);
+ auto throttle = factory.MaybeCreate(std::move(provider));
+
+ ASSERT_TRUE(test.first_url);
+ if (test.redirect_url) {
+ net::RedirectInfo redirect_info;
+ redirect_info.status_code = 301;
+ redirect_info.new_url = GURL(test.redirect_url);
+ network::TestURLLoaderFactory::Redirects redirects{
+ {redirect_info, network::ResourceResponseHead()}};
+ loader_factory_.AddResponse(
+ GURL(test.first_url), network::ResourceResponseHead(), "foo",
+ network::URLLoaderCompletionStatus(), redirects);
+ } else {
+ loader_factory_.AddResponse(test.first_url, "foo");
+ }
+ std::unique_ptr<network::mojom::URLLoaderClient> loader_client =
+ CreateLoaderAndStart(GURL(test.first_url), std::move(throttle));
+ scoped_environment_.RunUntilIdle();
+ scoped_environment_.FastForwardBy(
+ base::TimeDelta::FromMilliseconds(test.fast_forward_ms));
+ EXPECT_EQ(test.will_finish == WillFinish::kYes,
+ client_->has_received_completion());
+ }
}
TEST_F(AdDelayThrottleTest, DestroyBeforeDelay) {
@@ -274,7 +275,7 @@ TEST_F(AdDelayThrottleTest, DestroyBeforeDelay) {
EXPECT_FALSE(client_->has_received_completion());
loader_client.reset();
- scoped_environment_.FastForwardBy(GetExpectedDelay());
+ scoped_environment_.FastForwardBy(GetExpectedDelay(kInsecureDelayParam));
}
TEST_F(AdDelayThrottleTest, AdDiscoveredAfterRedirect) {
@@ -300,7 +301,7 @@ TEST_F(AdDelayThrottleTest, AdDiscoveredAfterRedirect) {
raw_metadata->set_is_ad_request(true);
scoped_environment_.RunUntilIdle();
EXPECT_FALSE(client_->has_received_completion());
- scoped_environment_.FastForwardBy(GetExpectedDelay());
+ scoped_environment_.FastForwardBy(GetExpectedDelay(kInsecureDelayParam));
EXPECT_TRUE(client_->has_received_completion());
}
@@ -331,10 +332,108 @@ TEST_F(AdDelayThrottleTest, AdDiscoveredAfterSecureRedirect) {
raw_metadata->set_is_ad_request(true);
scoped_environment_.RunUntilIdle();
EXPECT_FALSE(client_->has_received_completion());
- scoped_environment_.FastForwardBy(GetExpectedDelay());
+ scoped_environment_.FastForwardBy(GetExpectedDelay(kInsecureDelayParam));
EXPECT_TRUE(client_->has_received_completion());
}
+TEST_F(AdDelayThrottleTest, DelayMetrics) {
+ AdDelayThrottle::Factory factory;
+ const GURL secure_url("https://example.test/ad.js");
+ const GURL insecure_url("http://example.test/ad.js");
+ loader_factory_.AddResponse(secure_url.spec(), "foo");
+ loader_factory_.AddResponse(insecure_url.spec(), "foo");
+
+ const base::TimeDelta kQueuingDelay = base::TimeDelta::FromMilliseconds(25);
+
+ const char kDelayHistogram[] = "SubresourceFilter.AdDelay.Delay";
+ const char kQueuingDelayHistogram[] =
+ "SubresourceFilter.AdDelay.Delay.Queuing";
+ const char kExpectedDelayHistogram[] =
+ "SubresourceFilter.AdDelay.Delay.Expected";
+ {
+ // Secure isolated ad -> no delay.
+ base::HistogramTester histograms;
+ {
+ auto throttle =
+ factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
+ throttle->set_tick_clock_for_testing(
+ scoped_environment_.GetMockTickClock());
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(secure_url, std::move(throttle));
+ scoped_environment_.FastForwardUntilNoTasksRemain();
+ }
+ histograms.ExpectTotalCount(kDelayHistogram, 0);
+ histograms.ExpectTotalCount(kQueuingDelayHistogram, 0);
+ histograms.ExpectTotalCount(kExpectedDelayHistogram, 0);
+ }
+ {
+ // Insecure isolated non-ad -> no delay.
+ base::HistogramTester histograms;
+ {
+ auto non_ad_metadata = std::make_unique<MockMetadataProvider>();
+ non_ad_metadata->set_is_ad_request(false);
+ auto throttle = factory.MaybeCreate(std::move(non_ad_metadata));
+ throttle->set_tick_clock_for_testing(
+ scoped_environment_.GetMockTickClock());
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(insecure_url, std::move(throttle));
+ scoped_environment_.FastForwardUntilNoTasksRemain();
+ }
+ histograms.ExpectTotalCount(kDelayHistogram, 0);
+ histograms.ExpectTotalCount(kQueuingDelayHistogram, 0);
+ histograms.ExpectTotalCount(kExpectedDelayHistogram, 0);
+ }
+
+ // Use a test clock instead of the scoped task environment's clock because the
+ // environment executes tasks as soon as it is able, and we want to simulate
+ // jank by advancing time more than the expected delay.
+ base::SimpleTestTickClock tick_clock;
+ {
+ // Insecure isolated ad -> delay.
+ base::HistogramTester histograms;
+ base::TimeDelta expected_delay = GetExpectedDelay(kInsecureDelayParam);
+ {
+ auto throttle =
+ factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
+ throttle->set_tick_clock_for_testing(&tick_clock);
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(insecure_url, std::move(throttle));
+
+ tick_clock.Advance(expected_delay + kQueuingDelay);
+ scoped_environment_.FastForwardBy(expected_delay + kQueuingDelay);
+ }
+ histograms.ExpectUniqueSample(
+ kDelayHistogram, (expected_delay + kQueuingDelay).InMilliseconds(), 1);
+ histograms.ExpectUniqueSample(kQueuingDelayHistogram,
+ kQueuingDelay.InMilliseconds(), 1);
+ histograms.ExpectUniqueSample(kExpectedDelayHistogram,
+ expected_delay.InMilliseconds(), 1);
+ }
+ {
+ // Insecure non-isolated ad -> delay.
+ base::HistogramTester histograms;
+ base::TimeDelta expected_delay = GetExpectedDelay(kInsecureDelayParam) +
+ GetExpectedDelay(kNonIsolatedDelayParam);
+ {
+ auto non_isolated_metadata = std::make_unique<MockMetadataProvider>();
+ non_isolated_metadata->set_is_non_isolated(true);
+ auto throttle = factory.MaybeCreate(std::move(non_isolated_metadata));
+ throttle->set_tick_clock_for_testing(&tick_clock);
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(insecure_url, std::move(throttle));
+
+ tick_clock.Advance(expected_delay + kQueuingDelay);
+ scoped_environment_.FastForwardBy(expected_delay + kQueuingDelay);
+ }
+ histograms.ExpectUniqueSample(
+ kDelayHistogram, (expected_delay + kQueuingDelay).InMilliseconds(), 1);
+ histograms.ExpectUniqueSample(kQueuingDelayHistogram,
+ kQueuingDelay.InMilliseconds(), 1);
+ histograms.ExpectUniqueSample(kExpectedDelayHistogram,
+ expected_delay.InMilliseconds(), 1);
+ }
+}
+
// Make sure metrics are logged when the feature is enabled and disabled.
TEST_P(AdDelayThrottleEnabledParamTest, SecureMetrics) {
AdDelayThrottle::Factory factory;
@@ -400,6 +499,66 @@ TEST_P(AdDelayThrottleEnabledParamTest, SecureMetrics) {
}
}
+TEST_P(AdDelayThrottleEnabledParamTest, IsolatedMetrics) {
+ AdDelayThrottle::Factory factory;
+ const GURL url("https://example.test/ad.js");
+ loader_factory_.AddResponse(url.spec(), "foo");
+
+ const char kIsolatedHistogram[] = "SubresourceFilter.AdDelay.IsolatedInfo";
+ {
+ base::HistogramTester histograms;
+ {
+ auto throttle =
+ factory.MaybeCreate(std::make_unique<MockMetadataProvider>());
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(url, std::move(throttle));
+ scoped_environment_.FastForwardUntilNoTasksRemain();
+ }
+ histograms.ExpectUniqueSample(
+ kIsolatedHistogram,
+ static_cast<int>(AdDelayThrottle::IsolatedInfo::kIsolatedAd), 1);
+ }
+ {
+ base::HistogramTester histograms;
+ {
+ auto metadata = std::make_unique<MockMetadataProvider>();
+ metadata->set_is_non_isolated(true);
+ auto throttle = factory.MaybeCreate(std::move(metadata));
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(url, std::move(throttle));
+ scoped_environment_.FastForwardUntilNoTasksRemain();
+ }
+ histograms.ExpectUniqueSample(
+ kIsolatedHistogram,
+ static_cast<int>(AdDelayThrottle::IsolatedInfo::kNonIsolatedAd), 1);
+ }
+ {
+ base::HistogramTester histograms;
+ {
+ auto non_ad_metadata = std::make_unique<MockMetadataProvider>();
+ non_ad_metadata->set_is_ad_request(false);
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto throttle = factory.MaybeCreate(std::move(non_ad_metadata));
+ auto loader = CreateLoaderAndStart(url, std::move(throttle));
+ scoped_environment_.FastForwardUntilNoTasksRemain();
+ }
+ histograms.ExpectTotalCount(kIsolatedHistogram, 0);
+ }
+ {
+ base::HistogramTester histograms;
+ {
+ auto non_ad_metadata = std::make_unique<MockMetadataProvider>();
+ non_ad_metadata->set_is_ad_request(false);
+ non_ad_metadata->set_is_non_isolated(true);
+ auto throttle = factory.MaybeCreate(std::move(non_ad_metadata));
+ client_ = std::make_unique<network::TestURLLoaderClient>();
+ auto loader = CreateLoaderAndStart(url, std::move(throttle));
+ scoped_environment_.FastForwardUntilNoTasksRemain();
+ }
+ histograms.ExpectTotalCount(kIsolatedHistogram, 0);
+ }
+}
+
INSTANTIATE_TEST_CASE_P(,
AdDelayThrottleEnabledParamTest,
::testing::Values(true, false));
diff --git a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
index 610310c05e8..a1b44e43427 100644
--- a/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
+++ b/chromium/components/subresource_filter/content/common/subresource_filter_messages.h
@@ -79,3 +79,9 @@ IPC_MESSAGE_ROUTED0(SubresourceFilterHostMsg_DidDisallowFirstSubresource)
// if performance measurements were disabled for the load.
IPC_MESSAGE_ROUTED1(SubresourceFilterHostMsg_DocumentLoadStatistics,
subresource_filter::DocumentLoadStatistics /* statistics */)
+
+// Sent to the browser when a RenderFrame is created and is tagged as an ad
+// subframe. The browser keeps track of this in case the frame later changes
+// processes, at which point it will inform the new RenderFrame that it has been
+// tagged as an ad via SubresourceFilterMsg_ActivateForNextCommittedLoad.
+IPC_MESSAGE_ROUTED0(SubresourceFilterHostMsg_FrameIsAdSubframe)
diff --git a/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.cc b/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.cc
index 5b61af1e7ba..11fab9d0c50 100644
--- a/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.cc
+++ b/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.cc
@@ -4,13 +4,21 @@
#include "components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.h"
+#include "base/logging.h"
+#include "content/public/renderer/render_frame.h"
+#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_url_request.h"
+#include "third_party/blink/public/web/web_frame.h"
+#include "third_party/blink/public/web/web_local_frame.h"
namespace subresource_filter {
AdDelayRendererMetadataProvider::AdDelayRendererMetadataProvider(
- const blink::WebURLRequest& request)
- : is_ad_request_(request.IsAdResource()) {}
+ const blink::WebURLRequest& request,
+ content::URLLoaderThrottleProviderType type,
+ int render_frame_id)
+ : is_ad_request_(request.IsAdResource()),
+ is_non_isolated_(IsSubframeAndNonIsolated(type, render_frame_id)) {}
AdDelayRendererMetadataProvider::~AdDelayRendererMetadataProvider() = default;
@@ -19,4 +27,28 @@ bool AdDelayRendererMetadataProvider::IsAdRequest() {
return is_ad_request_;
}
+bool AdDelayRendererMetadataProvider::RequestIsInNonIsolatedSubframe() {
+ return is_non_isolated_;
+}
+
+// static
+bool AdDelayRendererMetadataProvider::IsSubframeAndNonIsolated(
+ content::URLLoaderThrottleProviderType type,
+ int render_frame_id) {
+ // TODO(csharrison): Handle the worker case via threading information from the
+ // URLLoaderThrottleProvider's constructor.
+ if (type != content::URLLoaderThrottleProviderType::kFrame)
+ return false;
+
+ auto* render_frame = content::RenderFrame::FromRoutingID(render_frame_id);
+ if (!render_frame || render_frame->IsMainFrame())
+ return false;
+
+ blink::WebFrame* web_frame = render_frame->GetWebFrame();
+
+ // The frame is non-isolated if it can access the top frame.
+ return web_frame->GetSecurityOrigin().CanAccess(
+ web_frame->Top()->GetSecurityOrigin());
+}
+
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.h b/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.h
index 622ab65832e..68fd33f232f 100644
--- a/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.h
+++ b/chromium/components/subresource_filter/content/renderer/ad_delay_renderer_metadata_provider.h
@@ -7,6 +7,7 @@
#include "base/macros.h"
#include "components/subresource_filter/content/common/ad_delay_throttle.h"
+#include "content/public/renderer/url_loader_throttle_provider.h"
namespace blink {
class WebURLRequest;
@@ -17,14 +18,23 @@ namespace subresource_filter {
class AdDelayRendererMetadataProvider
: public AdDelayThrottle::MetadataProvider {
public:
- explicit AdDelayRendererMetadataProvider(const blink::WebURLRequest& request);
+ explicit AdDelayRendererMetadataProvider(
+ const blink::WebURLRequest& request,
+ content::URLLoaderThrottleProviderType type,
+ int render_frame_id);
~AdDelayRendererMetadataProvider() override;
// AdDelayThrottle::MetadataProvider:
bool IsAdRequest() override;
+ bool RequestIsInNonIsolatedSubframe() override;
private:
+ static bool IsSubframeAndNonIsolated(
+ content::URLLoaderThrottleProviderType type,
+ int render_frame_id);
+
const bool is_ad_request_ = false;
+ const bool is_non_isolated_ = false;
DISALLOW_COPY_AND_ASSIGN(AdDelayRendererMetadataProvider);
};
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
index 4ee2fa04534..ae9adb1c84e 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.cc
@@ -4,6 +4,7 @@
#include "components/subresource_filter/content/renderer/subresource_filter_agent.h"
+#include <utility>
#include <vector>
#include "base/feature_list.h"
@@ -37,8 +38,7 @@ SubresourceFilterAgent::SubresourceFilterAgent(
UnverifiedRulesetDealer* ruleset_dealer)
: content::RenderFrameObserver(render_frame),
content::RenderFrameObserverTracker<SubresourceFilterAgent>(render_frame),
- ruleset_dealer_(ruleset_dealer),
- is_ad_subframe_for_next_commit_(false) {
+ ruleset_dealer_(ruleset_dealer) {
DCHECK(ruleset_dealer);
}
@@ -70,6 +70,19 @@ void SubresourceFilterAgent::SendDocumentLoadStatistics(
render_frame()->GetRoutingID(), statistics));
}
+void SubresourceFilterAgent::SendFrameIsAdSubframe() {
+ render_frame()->Send(new SubresourceFilterHostMsg_FrameIsAdSubframe(
+ render_frame()->GetRoutingID()));
+}
+
+bool SubresourceFilterAgent::IsAdSubframe() {
+ return render_frame()->GetWebFrame()->IsAdSubframe();
+}
+
+void SubresourceFilterAgent::SetIsAdSubframe() {
+ render_frame()->GetWebFrame()->SetIsAdSubframe();
+}
+
// static
ActivationState SubresourceFilterAgent::GetParentActivationState(
content::RenderFrame* render_frame) {
@@ -88,7 +101,8 @@ void SubresourceFilterAgent::OnActivateForNextCommittedLoad(
const ActivationState& activation_state,
bool is_ad_subframe) {
activation_state_for_next_commit_ = activation_state;
- is_ad_subframe_for_next_commit_ = is_ad_subframe;
+ if (is_ad_subframe)
+ SetIsAdSubframe();
}
void SubresourceFilterAgent::RecordHistogramsOnLoadCommitted(
@@ -152,13 +166,25 @@ void SubresourceFilterAgent::RecordHistogramsOnLoadFinished() {
void SubresourceFilterAgent::ResetInfoForNextCommit() {
activation_state_for_next_commit_ =
ActivationState(ActivationLevel::DISABLED);
- is_ad_subframe_for_next_commit_ = false;
}
void SubresourceFilterAgent::OnDestruct() {
delete this;
}
+void SubresourceFilterAgent::DidCreateNewDocument() {
+ if (!first_document_)
+ return;
+ first_document_ = false;
+
+ // Local subframes will first navigate to kAboutBlankURL. Frames created by
+ // the browser initialize the LocalFrame before creating
+ // RenderFrameObservers, so the about:blank document isn't observed. We only
+ // care about local subframes.
+ if (IsAdSubframe() && GetDocumentURL() == url::kAboutBlankURL)
+ SendFrameIsAdSubframe();
+}
+
void SubresourceFilterAgent::DidCommitProvisionalLoad(
bool is_new_navigation,
bool is_same_document_navigation) {
@@ -176,7 +202,6 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad(
const ActivationState activation_state =
use_parent_activation ? GetParentActivationState(render_frame())
: activation_state_for_next_commit_;
- bool is_ad_subframe = is_ad_subframe_for_next_commit_;
ResetInfoForNextCommit();
@@ -202,7 +227,7 @@ void SubresourceFilterAgent::DidCommitProvisionalLoad(
AsWeakPtr()));
auto filter = std::make_unique<WebDocumentSubresourceFilterImpl>(
url::Origin::Create(url), activation_state, std::move(ruleset),
- std::move(first_disallowed_load_callback), is_ad_subframe);
+ std::move(first_disallowed_load_callback), IsAdSubframe());
filter_for_last_committed_load_ = filter->AsWeakPtr();
SetSubresourceFilterForCommittedLoad(std::move(filter));
@@ -240,11 +265,6 @@ void SubresourceFilterAgent::WillCreateWorkerFetchContext(
if (!ruleset_file.IsValid())
return;
- // Propagate the information to the worker whether this is associated with an
- // ad subframe.
- bool is_ad_subframe =
- render_frame()->GetWebFrame()->GetDocumentLoader()->GetIsAdSubframe();
-
worker_fetch_context->SetSubresourceFilterBuilder(
std::make_unique<WebDocumentSubresourceFilterImpl::BuilderImpl>(
url::Origin::Create(GetDocumentURL()),
@@ -253,7 +273,7 @@ void SubresourceFilterAgent::WillCreateWorkerFetchContext(
base::BindOnce(&SubresourceFilterAgent::
SignalFirstSubresourceDisallowedForCommittedLoad,
AsWeakPtr()),
- is_ad_subframe));
+ IsAdSubframe()));
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
index 5860bf6a704..83c71753622 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent.h
@@ -60,6 +60,13 @@ class SubresourceFilterAgent
virtual void SendDocumentLoadStatistics(
const DocumentLoadStatistics& statistics);
+ // Tells the browser that the frame is an ad subframe.
+ virtual void SendFrameIsAdSubframe();
+
+ // True if the frame has been heuristically determined to be an ad subframe.
+ virtual bool IsAdSubframe();
+ virtual void SetIsAdSubframe();
+
private:
// Assumes that the parent will be in a local frame relative to this one, upon
// construction.
@@ -74,6 +81,7 @@ class SubresourceFilterAgent
// content::RenderFrameObserver:
void OnDestruct() override;
+ void DidCreateNewDocument() override;
void DidCommitProvisionalLoad(bool is_new_navigation,
bool is_same_document_navigation) override;
void DidFailProvisionalLoad(const blink::WebURLError& error) override;
@@ -86,12 +94,9 @@ class SubresourceFilterAgent
ActivationState activation_state_for_next_commit_;
- // This is received along with activation state in the
- // SubresourceFilterMsg_ActivateForNextCommittedLoad IPC message. Specifies
- // whether this is a subframe which is identified as an ad. Note that this
- // will only be set in dry run mode because in blocking mode the frame would
- // have been blocked.
- bool is_ad_subframe_for_next_commit_;
+ // If a document has been created for this frame before. The first document
+ // for a new local subframe should be about:blank.
+ bool first_document_ = true;
base::WeakPtr<WebDocumentSubresourceFilterImpl>
filter_for_last_committed_load_;
diff --git a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
index a146c9f5a79..2d456c67e87 100644
--- a/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
+++ b/chromium/components/subresource_filter/content/renderer/subresource_filter_agent_unittest.cc
@@ -44,12 +44,13 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
explicit SubresourceFilterAgentUnderTest(
UnverifiedRulesetDealer* ruleset_dealer)
: SubresourceFilterAgent(nullptr /* RenderFrame */, ruleset_dealer) {}
- ~SubresourceFilterAgentUnderTest() = default;
+ ~SubresourceFilterAgentUnderTest() override = default;
MOCK_METHOD0(GetDocumentURL, GURL());
MOCK_METHOD0(OnSetSubresourceFilterForCommittedLoadCalled, void());
MOCK_METHOD0(SignalFirstSubresourceDisallowedForCommittedLoad, void());
MOCK_METHOD1(SendDocumentLoadStatistics, void(const DocumentLoadStatistics&));
+ MOCK_METHOD0(SendFrameIsAdSubframe, void());
bool IsMainFrame() override { return true; }
@@ -59,7 +60,10 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
OnSetSubresourceFilterForCommittedLoadCalled();
}
- bool GetIsAssociatedWithAdSubframe() {
+ bool IsAdSubframe() override { return is_ad_subframe_; }
+ void SetIsAdSubframe() override { is_ad_subframe_ = true; }
+
+ bool IsFilterAssociatedWithAdSubframe() {
return last_injected_filter_->GetIsAssociatedWithAdSubframe();
}
@@ -73,6 +77,7 @@ class SubresourceFilterAgentUnderTest : public SubresourceFilterAgent {
private:
std::unique_ptr<blink::WebDocumentSubresourceFilter> last_injected_filter_;
+ bool is_ad_subframe_ = false;
DISALLOW_COPY_AND_ASSIGN(SubresourceFilterAgentUnderTest);
};
@@ -175,6 +180,14 @@ class SubresourceFilterAgentTest : public ::testing::Test {
EXPECT_CALL(*agent(), SendDocumentLoadStatistics(::testing::_));
}
+ void ExpectSendFrameIsAdSubframe() {
+ EXPECT_CALL(*agent(), SendFrameIsAdSubframe());
+ }
+
+ void ExpectNoSendFrameIsAdSubframe() {
+ EXPECT_CALL(*agent(), SendFrameIsAdSubframe()).Times(0);
+ }
+
void ExpectLoadPolicy(
base::StringPiece url_spec,
blink::WebDocumentSubresourceFilter::LoadPolicy expected_policy) {
@@ -467,6 +480,9 @@ TEST_F(SubresourceFilterAgentTest, DryRun_ResourcesAreEvaluatedButNotFiltered) {
// Performance measurement is switched off.
histogram_tester.ExpectTotalCount(kEvaluationTotalWallDuration, 0);
histogram_tester.ExpectTotalCount(kEvaluationTotalCPUDuration, 0);
+
+ EXPECT_FALSE(agent()->IsFilterAssociatedWithAdSubframe());
+ EXPECT_FALSE(agent()->IsAdSubframe());
}
TEST_F(SubresourceFilterAgentTest,
@@ -522,6 +538,7 @@ TEST_F(SubresourceFilterAgentTest,
DryRun_IsAssociatedWithAdSubframeforDocumentOrDedicatedWorker) {
ASSERT_NO_FATAL_FAILURE(
SetTestRulesetToDisallowURLsWithPathSuffix(kTestFirstURLPathSuffix));
+
ExpectSubresourceFilterGetsInjected();
StartLoadAndSetActivationState(ActivationState(ActivationLevel::DRYRUN),
true /* is_associated_with_ad_subframe */);
@@ -532,7 +549,38 @@ TEST_F(SubresourceFilterAgentTest,
// For testing the flag passed to the dedicated worker filter, the unit test
// is not able to test the implementation of WillCreateWorkerFetchContext as
// that will require setup of a WebWorkerFetchContextImpl.
- EXPECT_TRUE(agent()->GetIsAssociatedWithAdSubframe());
+ EXPECT_TRUE(agent()->IsFilterAssociatedWithAdSubframe());
+ EXPECT_TRUE(agent()->IsAdSubframe());
+}
+
+TEST_F(SubresourceFilterAgentTest, DryRun_FrameAlreadyTaggedAsAd) {
+ agent()->SetIsAdSubframe();
+ ASSERT_NO_FATAL_FAILURE(
+ SetTestRulesetToDisallowURLsWithPathSuffix("somethingNotMatched"));
+ ExpectSubresourceFilterGetsInjected();
+ StartLoadAndSetActivationState(ActivationState(ActivationLevel::DRYRUN),
+ false /* is_associated_with_ad_subframe */);
+ ASSERT_TRUE(::testing::Mock::VerifyAndClearExpectations(agent()));
+
+ EXPECT_TRUE(agent()->IsFilterAssociatedWithAdSubframe());
+ EXPECT_TRUE(agent()->IsAdSubframe());
+}
+
+TEST_F(SubresourceFilterAgentTest, DryRun_SendsFrameIsAdSubframe) {
+ agent()->SetIsAdSubframe();
+ ExpectSendFrameIsAdSubframe();
+
+ // Call DidCreateNewDocument twice and verify that SendFrameIsAdSubframe is
+ // only called once.
+ EXPECT_CALL(*agent(), GetDocumentURL())
+ .WillOnce(::testing::Return(GURL("about:blank")));
+ agent_as_rfo()->DidCreateNewDocument();
+ agent_as_rfo()->DidCreateNewDocument();
+}
+
+TEST_F(SubresourceFilterAgentTest, DryRun_DoesNotSendFrameIsAdSubframe) {
+ ExpectNoSendFrameIsAdSubframe();
+ agent_as_rfo()->DidCreateNewDocument();
}
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc b/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
index 700a57af4d4..6124ac4cb34 100644
--- a/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
+++ b/chromium/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/load_policy.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
@@ -164,7 +164,7 @@ WebDocumentSubresourceFilterImpl::BuilderImpl::BuilderImpl(
ruleset_file_(std::move(ruleset_file)),
first_disallowed_load_callback_(
std::move(first_disallowed_load_callback)),
- main_task_runner_(base::MessageLoop::current()->task_runner()),
+ main_task_runner_(base::MessageLoopCurrent::Get()->task_runner()),
is_associated_with_ad_subframe_(is_associated_with_ad_subframe) {}
WebDocumentSubresourceFilterImpl::BuilderImpl::~BuilderImpl() {}
diff --git a/chromium/components/subresource_filter/core/browser/BUILD.gn b/chromium/components/subresource_filter/core/browser/BUILD.gn
index 4f2cbce6f9b..e82bd713275 100644
--- a/chromium/components/subresource_filter/core/browser/BUILD.gn
+++ b/chromium/components/subresource_filter/core/browser/BUILD.gn
@@ -4,6 +4,8 @@
static_library("browser") {
sources = [
+ "copying_file_stream.cc",
+ "copying_file_stream.h",
"ruleset_service.cc",
"ruleset_service.h",
"ruleset_service_delegate.h",
diff --git a/chromium/components/url_pattern_index/copying_file_stream.cc b/chromium/components/subresource_filter/core/browser/copying_file_stream.cc
index 7f6d6d1d838..072cefcb41a 100644
--- a/chromium/components/url_pattern_index/copying_file_stream.cc
+++ b/chromium/components/subresource_filter/core/browser/copying_file_stream.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/url_pattern_index/copying_file_stream.h"
+#include "components/subresource_filter/core/browser/copying_file_stream.h"
namespace url_pattern_index {
diff --git a/chromium/components/url_pattern_index/copying_file_stream.h b/chromium/components/subresource_filter/core/browser/copying_file_stream.h
index f8e3009327f..6df29e1ee3b 100644
--- a/chromium/components/url_pattern_index/copying_file_stream.h
+++ b/chromium/components/subresource_filter/core/browser/copying_file_stream.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 COMPONENTS_URL_PATTERN_INDEX_COPYING_FILE_STREAM_H_
-#define COMPONENTS_URL_PATTERN_INDEX_COPYING_FILE_STREAM_H_
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_COPYING_FILE_STREAM_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_COPYING_FILE_STREAM_H_
#include "base/files/file.h"
#include "base/macros.h"
@@ -48,4 +48,4 @@ class CopyingFileOutputStream
} // namespace url_pattern_index
-#endif // COMPONENTS_URL_PATTERN_INDEX_COPYING_FILE_STREAM_H_
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_BROWSER_COPYING_FILE_STREAM_H_
diff --git a/chromium/components/subresource_filter/core/browser/ruleset_service.cc b/chromium/components/subresource_filter/core/browser/ruleset_service.cc
index b0a521d9fc4..bb7b59d20a4 100644
--- a/chromium/components/subresource_filter/core/browser/ruleset_service.cc
+++ b/chromium/components/subresource_filter/core/browser/ruleset_service.cc
@@ -22,13 +22,13 @@
#include "base/threading/thread_restrictions.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
+#include "components/subresource_filter/core/browser/copying_file_stream.h"
#include "components/subresource_filter/core/browser/ruleset_service_delegate.h"
#include "components/subresource_filter/core/browser/subresource_filter_constants.h"
#include "components/subresource_filter/core/common/indexed_ruleset.h"
#include "components/subresource_filter/core/common/time_measurements.h"
-#include "components/url_pattern_index/copying_file_stream.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
#include "components/url_pattern_index/proto/rules.pb.h"
-#include "components/url_pattern_index/unindexed_ruleset.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
namespace subresource_filter {
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
index 11dda2e852a..92d0bbcdd77 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.cc
@@ -13,10 +13,12 @@
#include "base/lazy_instance.h"
#include "base/metrics/field_trial_params.h"
+#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
+#include "base/time/time.h"
#include "base/trace_event/trace_event_argument.h"
#include "components/subresource_filter/core/common/common_features.h"
@@ -96,6 +98,7 @@ ActivationList ParseActivationList(std::string activation_lists_string) {
return ActivationList::NONE;
}
+// Will return a value between 0 and 1 inclusive.
double ParsePerformanceMeasurementRate(const std::string& rate) {
double value = 0.0;
if (!base::StringToDouble(rate, &value) || value < 0)
@@ -103,10 +106,6 @@ double ParsePerformanceMeasurementRate(const std::string& rate) {
return value < 1 ? value : 1;
}
-bool ParseBool(const base::StringPiece value) {
- return base::LowerCaseEqualsASCII(value, "true");
-}
-
int ParseInt(const base::StringPiece value) {
int result = 0;
base::StringToInt(value, &result);
@@ -169,14 +168,6 @@ Configuration ParseExperimentalConfiguration(
ParsePerformanceMeasurementRate(TakeVariationParamOrReturnEmpty(
params, kPerformanceMeasurementRateParameterName));
- configuration.activation_options.should_suppress_notifications =
- ParseBool(TakeVariationParamOrReturnEmpty(
- params, kSuppressNotificationsParameterName));
-
- configuration.activation_options.should_whitelist_site_on_reload =
- ParseBool(TakeVariationParamOrReturnEmpty(
- params, kWhitelistSiteOnReloadParameterName));
-
// GeneralSettings:
configuration.general_settings.ruleset_flavor =
TakeVariationParamOrReturnEmpty(params, kRulesetFlavorParameterName);
@@ -265,8 +256,6 @@ const char kActivationPriorityParameterName[] = "activation_priority";
const char kPerformanceMeasurementRateParameterName[] =
"performance_measurement_rate";
-const char kSuppressNotificationsParameterName[] = "suppress_notifications";
-const char kWhitelistSiteOnReloadParameterName[] = "whitelist_site_on_reload";
const char kRulesetFlavorParameterName[] = "ruleset_flavor";
const char kEnablePresetsParameterName[] = "enable_presets";
@@ -337,8 +326,6 @@ bool Configuration::operator==(const Configuration& rhs) const {
config.activation_conditions.forced_activation,
config.activation_options.activation_level,
config.activation_options.performance_measurement_rate,
- config.activation_options.should_whitelist_site_on_reload,
- config.activation_options.should_suppress_notifications,
config.general_settings.ruleset_flavor);
};
return tie(*this) == tie(rhs);
@@ -367,15 +354,29 @@ std::unique_ptr<base::trace_event::TracedValue> Configuration::ToTracedValue()
StreamToString(activation_options.activation_level));
value->SetDouble("performance_measurement_rate",
activation_options.performance_measurement_rate);
- value->SetBoolean("should_suppress_notifications",
- activation_options.should_suppress_notifications);
- value->SetBoolean("should_whitelist_site_on_reload",
- activation_options.should_whitelist_site_on_reload);
value->SetString("ruleset_flavor",
StreamToString(general_settings.ruleset_flavor));
return value;
}
+ActivationState Configuration::GetActivationState(
+ ActivationLevel effective_activation_level) const {
+ ActivationState state = ActivationState(effective_activation_level);
+
+ double measurement_rate = activation_options.performance_measurement_rate;
+ state.measure_performance =
+ base::ThreadTicks::IsSupported() &&
+ (measurement_rate == 1 || base::RandDouble() < measurement_rate);
+
+ // This bit keeps track of BAS enforcement-style logging, not warning logging.
+ state.enable_logging =
+ effective_activation_level == ActivationLevel::ENABLED &&
+ *this != Configuration::MakeForForcedActivation() &&
+ base::FeatureList::IsEnabled(
+ kSafeBrowsingSubresourceFilterExperimentalUI);
+ return state;
+}
+
std::ostream& operator<<(std::ostream& os, const Configuration& config) {
os << config.ToTracedValue()->ToString();
return os;
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
index e16c5bb8e87..82d22c3037a 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features.h
@@ -16,6 +16,7 @@
#include "components/subresource_filter/core/common/activation_level.h"
#include "components/subresource_filter/core/common/activation_list.h"
#include "components/subresource_filter/core/common/activation_scope.h"
+#include "components/subresource_filter/core/common/activation_state.h"
namespace base {
namespace trace_event {
@@ -83,14 +84,6 @@ struct Configuration {
// A number in the range [0, 1], indicating the fraction of page loads that
// should have extended performance measurements enabled.
double performance_measurement_rate = 0.0;
-
- // Whether notifications indicating that a subresource was disallowed should
- // be suppressed in the UI.
- bool should_suppress_notifications = false;
-
- // Whether to whitelist a site when a page loaded from that site is
- // reloaded.
- bool should_whitelist_site_on_reload = false;
};
// General settings that apply outside of the scope of a navigation.
@@ -118,6 +111,13 @@ struct Configuration {
std::unique_ptr<base::trace_event::TracedValue> ToTracedValue() const;
+ // Returns the ActivationState that page loads that match this configuration
+ // should activate with. |effective_activation_level| can be different from
+ // this config's activation level due to things like warning mode or client
+ // whitelisting.
+ ActivationState GetActivationState(
+ ActivationLevel effective_activation_level) const;
+
// Factory methods for preset configurations.
//
// To add a new preset:
diff --git a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
index bf45c3fa436..0b8ed4fa05f 100644
--- a/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
+++ b/chromium/components/subresource_filter/core/browser/subresource_filter_features_unittest.cc
@@ -391,7 +391,8 @@ TEST_F(SubresourceFilterFeaturesTest, PerfMeasurementRate) {
{true, "1", 1},
{true, "1.0", 1},
{true, "0.333", 0.333},
- {true, "1e0", 1}};
+ {true, "1e0", 1},
+ {true, "5", 1}};
for (const auto& test_case : kTestCases) {
SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled);
@@ -416,84 +417,6 @@ TEST_F(SubresourceFilterFeaturesTest, PerfMeasurementRate) {
}
}
-TEST_F(SubresourceFilterFeaturesTest, SuppressNotifications) {
- const struct {
- bool feature_enabled;
- const char* suppress_notifications_param;
- bool expected_suppress_notifications_value;
- } kTestCases[] = {{false, "", false},
- {false, "true", false},
- {false, "false", false},
- {false, "invalid value", false},
- {true, "", false},
- {true, "false", false},
- {true, "invalid value", false},
- {true, "True", true},
- {true, "TRUE", true},
- {true, "true", true}};
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled);
- SCOPED_TRACE(::testing::Message("SuppressNotificationsParam = \"")
- << test_case.suppress_notifications_param << "\"");
-
- ScopedExperimentalStateToggle scoped_experimental_state(
- test_case.feature_enabled ? base::FeatureList::OVERRIDE_USE_DEFAULT
- : base::FeatureList::OVERRIDE_DISABLE_FEATURE,
- {{kSuppressNotificationsParameterName,
- test_case.suppress_notifications_param}});
-
- Configuration actual_configuration;
- if (test_case.feature_enabled) {
- ExpectAndRetrieveExactlyOneExtraEnabledConfig(&actual_configuration);
- } else {
- ExpectAndRetrieveExactlyOneEnabledConfig(&actual_configuration);
- }
- EXPECT_EQ(
- test_case.expected_suppress_notifications_value,
- actual_configuration.activation_options.should_suppress_notifications);
- }
-}
-
-TEST_F(SubresourceFilterFeaturesTest, WhitelistSiteOnReload) {
- const struct {
- bool feature_enabled;
- const char* whitelist_site_on_reload_param;
- bool expected_whitelist_site_on_reload_value;
- } kTestCases[] = {{false, "", false},
- {false, "true", false},
- {false, "false", false},
- {false, "invalid value", false},
- {true, "", false},
- {true, "false", false},
- {true, "invalid value", false},
- {true, "True", true},
- {true, "TRUE", true},
- {true, "true", true}};
-
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(::testing::Message("Enabled = ") << test_case.feature_enabled);
- SCOPED_TRACE(::testing::Message("WhitelistSiteOnReloadParam = \"")
- << test_case.whitelist_site_on_reload_param << "\"");
-
- ScopedExperimentalStateToggle scoped_experimental_state(
- test_case.feature_enabled ? base::FeatureList::OVERRIDE_USE_DEFAULT
- : base::FeatureList::OVERRIDE_DISABLE_FEATURE,
- {{kWhitelistSiteOnReloadParameterName,
- test_case.whitelist_site_on_reload_param}});
-
- Configuration actual_configuration;
- if (test_case.feature_enabled) {
- ExpectAndRetrieveExactlyOneExtraEnabledConfig(&actual_configuration);
- } else {
- ExpectAndRetrieveExactlyOneEnabledConfig(&actual_configuration);
- }
- EXPECT_EQ(test_case.expected_whitelist_site_on_reload_value,
- actual_configuration.activation_options
- .should_whitelist_site_on_reload);
- }
-}
-
TEST_F(SubresourceFilterFeaturesTest, RulesetFlavor) {
const struct {
bool feature_enabled;
@@ -618,8 +541,6 @@ TEST_F(SubresourceFilterFeaturesTest, PresetForLiveRunOnBetterAdsSites) {
EXPECT_EQ(ActivationLevel::ENABLED,
config.activation_options.activation_level);
EXPECT_EQ(0.0, config.activation_options.performance_measurement_rate);
- EXPECT_FALSE(config.activation_options.should_suppress_notifications);
- EXPECT_FALSE(config.activation_options.should_whitelist_site_on_reload);
}
TEST_F(SubresourceFilterFeaturesTest, ConfigurationPriorities) {
diff --git a/chromium/components/subresource_filter/core/common/BUILD.gn b/chromium/components/subresource_filter/core/common/BUILD.gn
index 1085d239866..c56add3dfed 100644
--- a/chromium/components/subresource_filter/core/common/BUILD.gn
+++ b/chromium/components/subresource_filter/core/common/BUILD.gn
@@ -27,6 +27,8 @@ static_library("common") {
"memory_mapped_ruleset.h",
"scoped_timers.h",
"time_measurements.h",
+ "unindexed_ruleset.cc",
+ "unindexed_ruleset.h",
]
public_deps = [
@@ -60,21 +62,6 @@ static_library("test_support") {
]
}
-static_library("tools_lib") {
- sources = [
- "tools/filter_tool.cc",
- "tools/filter_tool.h",
- "tools/indexing_tool.cc",
- "tools/indexing_tool.h",
- ]
- deps = [
- ":common",
- "//base",
- "//components/url_pattern_index:util",
- "//url",
- ]
-}
-
source_set("unit_tests") {
testonly = true
sources = [
@@ -82,13 +69,11 @@ source_set("unit_tests") {
"first_party_origin_unittest.cc",
"indexed_ruleset_unittest.cc",
"scoped_timers_unittest.cc",
- "tools/filter_tool_unittest.cc",
- "tools/indexing_tool_unittest.cc",
+ "unindexed_ruleset_unittest.cc",
]
deps = [
":common",
":test_support",
- ":tools_lib",
"//base",
"//base/test:test_support",
"//components/url_pattern_index:test_support",
@@ -97,27 +82,3 @@ source_set("unit_tests") {
"//url",
]
}
-
-if (is_linux || is_mac || is_win) {
- executable("subresource_filter_tool") {
- sources = [
- "tools/filter_tool_main.cc",
- ]
- deps = [
- ":tools_lib",
- "//base",
- "//build/config:exe_and_shlib_deps",
- ]
- }
-
- executable("subresource_indexing_tool") {
- sources = [
- "tools/indexing_tool_main.cc",
- ]
- deps = [
- ":tools_lib",
- "//base",
- "//build/config:exe_and_shlib_deps",
- ]
- }
-}
diff --git a/chromium/components/subresource_filter/core/common/PRESUBMIT.py b/chromium/components/subresource_filter/core/common/PRESUBMIT.py
index 79908dc38b3..9c2c65adcb4 100644
--- a/chromium/components/subresource_filter/core/common/PRESUBMIT.py
+++ b/chromium/components/subresource_filter/core/common/PRESUBMIT.py
@@ -17,11 +17,17 @@ def CheckIndexedRulesetVersion(input_api, output_api):
- components/url_pattern_index/url_pattern_index.cc
and kIndexedFormatVersion constant stays intact, this check returns a
presubmit warning to make sure the value should not be updated.
+
+ Additionally, checks to ensure the format version in
+ tools/perf/core/default_local_state.json stays up to date with
+ kIndexedFormatVersion.
"""
indexed_ruleset_changed = False
indexed_ruleset_version_changed = False
+ new_indexed_ruleset_version = None
+
for affected_file in input_api.AffectedFiles():
path = affected_file.LocalPath()
if (not 'components/subresource_filter/core/common' in path and
@@ -36,14 +42,37 @@ def CheckIndexedRulesetVersion(input_api, output_api):
for (_, line) in affected_file.ChangedContents():
if 'kIndexedFormatVersion =' in line:
indexed_ruleset_version_changed = True
+ new_indexed_ruleset_version = int(
+ indexed_ruleset_line.split()[-1].replace(';',''))
break
+ # If the indexed ruleset version changed, ensure the perf benchmarks are using
+ # the new format.
+ out = []
+ if indexed_ruleset_version_changed:
+ assert new_indexed_ruleset_version is not None
+ current_path = input_api.PresubmitLocalPath()
+ local_state_path = input_api.os_path.join(
+ current_path, '..', '..', '..', '..', 'tools', 'perf', 'core',
+ 'default_local_state.json')
+
+ assert input_api.os_path.exists(local_state_path)
+ with open(local_state_path, 'r') as f:
+ json_state = input_api.json.load(f)
+ version = json_state['subresource_filter']['ruleset_version']['format']
+ if new_indexed_ruleset_version != version:
+ out.append(output_api.PresubmitPromptWarning(
+ 'Please make sure that kIndexedFormatVersion (%d) and '
+ 'the format version in tools/perf/core/default_local_state.json '
+ '(%d) are in sync' % (new_indexed_ruleset_version, version)))
+
if indexed_ruleset_changed and not indexed_ruleset_version_changed:
- return [output_api.PresubmitPromptWarning(
+ out.append(output_api.PresubmitPromptWarning(
'Please make sure that UrlPatternIndex/IndexedRuleset modifications in '
'*.fbs and url_pattern_index.cc/indexed_ruleset.cc do not require '
- 'updating RulesetIndexer::kIndexedFormatVersion.')]
- return []
+ 'updating RulesetIndexer::kIndexedFormatVersion.'))
+
+ return out
def CheckChangeOnUpload(input_api, output_api):
return CheckIndexedRulesetVersion(input_api, output_api)
diff --git a/chromium/components/subresource_filter/core/common/activation_decision.h b/chromium/components/subresource_filter/core/common/activation_decision.h
index a232a3fc72d..43d06711152 100644
--- a/chromium/components/subresource_filter/core/common/activation_decision.h
+++ b/chromium/components/subresource_filter/core/common/activation_decision.h
@@ -10,29 +10,25 @@ namespace subresource_filter {
// NOTE: ActivationDecision backs a UMA histogram, so it is append-only.
enum class ActivationDecision : int {
// The activation decision is unknown, or not known yet.
- UNKNOWN,
+ UNKNOWN = 0,
// Subresource filtering was activated.
- ACTIVATED,
+ ACTIVATED = 1,
// Did not activate because subresource filtering was disabled by the
// highest priority configuration whose activation conditions were met.
- ACTIVATION_DISABLED,
-
- // Did not activate because the main frame document URL had an unsupported
- // scheme.
- UNSUPPORTED_SCHEME,
+ ACTIVATION_DISABLED = 2,
// Did not activate because although there was a configuration whose
// activation conditions were met, the main frame URL was whitelisted.
- URL_WHITELISTED,
+ URL_WHITELISTED = 4,
// Did not activate because the main frame document URL did not match the
// activation conditions of any of enabled configurations.
- ACTIVATION_CONDITIONS_NOT_MET,
+ ACTIVATION_CONDITIONS_NOT_MET = 5,
// Max value for enum.
- ACTIVATION_DECISION_MAX
+ ACTIVATION_DECISION_MAX = 6
};
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/common_features.cc b/chromium/components/subresource_filter/core/common/common_features.cc
index 8d3e1fadeb5..c48a0f1ee41 100644
--- a/chromium/components/subresource_filter/core/common/common_features.cc
+++ b/chromium/components/subresource_filter/core/common/common_features.cc
@@ -11,5 +11,6 @@ const base::Feature kAdTagging{"AdTagging", base::FEATURE_DISABLED_BY_DEFAULT};
const base::Feature kDelayUnsafeAds{"DelayUnsafeAds",
base::FEATURE_DISABLED_BY_DEFAULT};
const char kInsecureDelayParam[] = "insecure_delay";
+const char kNonIsolatedDelayParam[] = "non_isolated_delay";
} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/core/common/common_features.h b/chromium/components/subresource_filter/core/common/common_features.h
index 0bd9321e6a8..7bd63169d33 100644
--- a/chromium/components/subresource_filter/core/common/common_features.h
+++ b/chromium/components/subresource_filter/core/common/common_features.h
@@ -21,6 +21,10 @@ extern const base::Feature kDelayUnsafeAds;
// DelayUnsafeAds.
extern const char kInsecureDelayParam[];
+// Param which governs how much to delay non-isolated (i.e. in a same-origin
+// iframe) subresources for DelayUnsafeAds.
+extern const char kNonIsolatedDelayParam[];
+
} // namespace subresource_filter
#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_COMMON_FEATURES_H_
diff --git a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
index 3fab20bda5b..c036bab1067 100644
--- a/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
+++ b/chromium/components/subresource_filter/core/common/indexed_ruleset.cc
@@ -22,7 +22,9 @@ using FindRuleStrategy =
// RulesetIndexer --------------------------------------------------------------
// static
-const int RulesetIndexer::kIndexedFormatVersion = 19;
+// Keep this in sync with the version number in
+// tools/perf/core/default_local_state.json.
+const int RulesetIndexer::kIndexedFormatVersion = 20;
RulesetIndexer::RulesetIndexer()
: blacklist_(&builder_), whitelist_(&builder_), deactivation_(&builder_) {}
diff --git a/chromium/components/subresource_filter/core/common/perftests/data/http_archive_top_100_page_requests b/chromium/components/subresource_filter/core/common/perftests/data/http_archive_top_100_page_requests
new file mode 100644
index 00000000000..ec481829a2d
--- /dev/null
+++ b/chromium/components/subresource_filter/core/common/perftests/data/http_archive_top_100_page_requests
@@ -0,0 +1,6621 @@
+{"origin":"http://www.stackoverflow.com/","request_url":"https://sb.scorecardresearch.com/b2?c1=2&c2=17440561&ns__t=1523791908369&ns_c=UTF-8&cv=3.1m&c8=Stack%20Overflow%20-%20Where%20Developers%20Learn%2C%20Share%2C%20%26%20Build%20Careers&c7=https%3A%2F%2Fstackoverflow.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1&verify=true","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1127&dpuuid=AB-CISSWwC8r1L2iH4VRbT9Bw&redir=http%3A%2F%2Frs.gwallet.com%2Fr1%2Fucm%3Fid%3D%24%7BDD_UUID%7D%26r1s%3D8y8mie9jehqw54bpgpghffsh84cb9r39ktr6uqzxk33zgx7t4zqy","request_type":"other"}
+{"origin":"http://www.reddit.com/","request_url":"https://events.redditmedia.com/v1?key=Mweb2&mac=cc76f6ffc246f45d367dc5db82dba08d424fe77ab5dc5dcad82a7426c9a66ce3","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/i/noticons/noticons.css?v=20150727","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.adsafeprotected.com/mon?anId=928108&campId=1x2&pubId=38386957&chanId=71171677&placementId=4640152498&pubCreative=138230533060&pubOrder=237199237&cb=1636808466&custom=bnr_btf_01&custom2=&custom3=&adsafe_par&impId=&adsafe_url=https%3A%2F%2Fwww.cnn.com%2F&adsafe_type=abcedfq&adsafe_jsinfo=,id:aa7f89d4-6c96-e26f-d7d0-9342e39910a2,c:9OXV0G,sl:outOfView,em:true,fr:true,mn:app23sje,pt:1-5-15,wc:0.0.360.512,ac:0.0.0.0,am:i,cc:0.0.0.0,piv:0,obst:0,th:0,reas:l,cmps:1,br:c,fv:0,bv:na,dm:na,abv:na,an:n,fm:qPhNt7y+11|12|13|14|1511|1512|151311|151312|151313|151314|151315|151316|151317|151318|151319|15131a|15131b|15131c|15131d|15131e|15131f|15131g|15131h|15131i|15131j|15131k|15131l|1514|16|17|181|182|183|19*.928108|191|1a|1b1|1b21|1b31|1b4|1c|1d|1e1|1e2|1f|1g,idMap:19*,pl:,rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:1,fif:1,gm:1,uf:0,tt:jload,et:5450,oid:88eeb353-40a0-11e8-b786-00259086caac,v:17.4.90,sp:1,ct:13140,dtm:i,gtpl:0,wr:360.512,sr:360.512,mst:5213,ov:0","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixanalytics.com/pi.gif?t=pv&r=0.46234645233567173&document.referrer=&document.URL=https%3A%2F%2Fm.pixnet.net%2F&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https%3A%2F%2Fm.pixnet.net%2F&window.pageXOffset=0&window.pageYOffset=1&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180413.110452&window.devicePixelRatio=3&venue=pixnet-mainpage-mobile&visitor_id=&utm_source=&utm_medium=&utm_term=&utm_content=&utm_campaign=","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/ape/m/81f43c2/t.gif","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/load/similar-shop.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/83/BB349B.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_hand_2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/pu8DIkXffB3UIO_V_EUiraLkZ38Ha4IO9itLklE6OVRf81lFnSCt9ynF9e-4tg=w768","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/kuaidi083002.png","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Xp5t?ver=8d03&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=927&y=275&s=1189&d=668&aim=true","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/161031151042-clinton-comey-composite-1031-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/039/29f/175/big_lq/4326e633ab51c4f0322cbf1408b58a24.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/713rQq1bF6L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/n1/s124x124_jfs/t16954/351/753879668/147214/2a8f84ce/5aa5360dN0fe8e31f.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/mEwAAOSwLnlajD4w/s-l500.webp","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1xVp9QVXXXXa5XFXXXXXXXXXX-1035-500.png_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://ad004a31d7b34cc0f373b2715b7a514d1.profile.lax3-c1.cloudfront.net/test.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/home-illo-team.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/recaptcha__en.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=114&cm=df15cd07b951fcc4fdd7b6ce44a82a2943ca006222e61453670f6dba6b6406ab25abae5358c0e7bc","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v3/js/skins/min/require.static.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/","request_type":"html"}
+{"origin":"http://www.baidu.com/","request_url":"https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/itemrep/channelMgr/index_c70dc69.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1507848430&t=event&ni=1&_s=1&dl=http%3A%2F%2Fdiply.com%2F&ul=en-us&de=UTF-8&dt=Diply&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=Page%20Load%20Performance&ea=%2F&el=15.4&ev=15&_u=6GDAAEADQ~&jid=297431564&gjid=109626532&cid=541858476.1523791959&tid=UA-44184928-2&_gid=47841196.1523791959&_r=1&gtm=G465XJBR3B&cd2=&cd8=0&cd14=4%3A32%3A49%3A384am&cd15=N%2FA&cd25=2000&cd27=SANFRANCISCO&cd28=CA&cd36=US&cd38=&cd40=3g&cd41=&cd45=http&cd29=1&cd30=1072328379&cd31=1523791957&cd32=1523791957&cd33=1523791957&cm1=15.4&cm2=3.7&cm3=11.7&cm6=4.2&cm8=1.5&cm9=400&cm10=0.3&z=1325857718","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://www.tumblr.com/","request_type":"html"}
+{"origin":"http://www.uptodown.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_window_focus_non_hydra.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01KEEhMJ-KL.js?AUIClients/DetailPageAlohaAssets","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://match.prod.bidr.io/cookie-sync/demandbase","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"http://d.agkn.com/pixel/5500/?age=&gender=&st=&sk=&pd=&cbr=&mip=&dm=&py=&l0=http://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key=","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://pixel.advertising.com/ups/254/occ?verify=true","request_type":"other"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/styles/password_strength_meter.css?_v=78c1926d168e565836a2d002cde53866","request_type":"css"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/styles/form_classic_onboarding.css?_v=fe3efb74033ab61e2f2b6a8bac06924d","request_type":"css"}
+{"origin":"http://www.mail.ru/","request_url":"https://www.tns-counter.ru/V13a****mail_ru/ru/CP1251/tmsec=mail_main-mobile/","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://ib.adnxs.com/getuid?https://tags.bluekai.com/site/3085?id=&","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/9apps-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/vidmate-android.png:xl","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/sprites/web_2x_sprites-vflN8VDFL.png","request_type":"image"}
+{"origin":"http://www.weibo.com/","request_url":"https://passport.weibo.cn/images/weibo/signin/index-pic_2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/q9EDVvchfjgVyxzRhh2AGq_JF9UaRP5NiP_-oMSwaiKfkZfmDSlk6f5kI5jo_g=w768","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p2.qhmsg.com/t01946e38139012bf1a.png","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/zeroyaking/albumset/18282086/zoomcrop/75x75.jpg?v=1523339454","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/170330151115-gov-matt-bevin-file-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmrbfarenweibo.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/451038492e1e4f6e9384394f7d19576f.jpeg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1c/c2cfce15b8c7173dc052e97c2c6e1808_erotic_285x160.jpg?cno=a23f","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5281000/5281687/220x165/7.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/618mlGassEL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=869667063858&t=17&plc=MOBILE&tkn=*lAXCppQEsgUhFyFh6TPgZBPpXVU","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/mediamain.html?&cid=8CUNL3XVM&cpcd=NaEyhZu73BMxXJoVzER-IQ%3D%3D&crid=903352736&pid=8PO383B67&size=300x250&cpnet=yVb1sHm-0KKoFeunLBVJxQIq7tQvdLolbpWYR-zZN9c%3D&cme=KkKUG6JLaWptcd7ygVoZgW_gowIx32vSl5tlbUoHIlTwG_Hajq4qm8TPaunw8hu-gs5H0j_cu9dNg1SpNWSXZk_dUMBskfm26tBhbg8dZUZVZ7w2Pa9YysH-X4tKSnEn%7C%7CNDHRnZ9Gz3KXlI-i9OnZqQ%3D%3D%7C5gDUJdTGiJzedmq9hanWYg%3D%3D%7CfTACDBAb70YAH7VJEs6iY7FiuYJwPXfy%7CN7fu2vKt8_s%3D%7CYdjFvixrVaHKWoanJxQ7pIbs71hugNrT_zzfTnjrTk2DZtMcbrd3gqo-5BoyMDWX%7CsRBSg3CPSiQ%3D%7C&https=1&cc=US&bf=0&staticIframe=1&vif=1&vi=1523791837453272108&lw=1&ugd=3&ib=0&nb=1","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://browser.pipe.aria.microsoft.com/Collector/3.0/?qsp=true&content-type=application%2Fbond-compact-binary&client-id=NO_AUTH&sdk-version=ACT-Web-JS-2.8.1&x-apikey=ea6758984c4b43529f9929667d8d3198-c52d4a8b-47fe-4fdf-99b8-5f897ff4e33b-7365","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/atlasgrotesk/AtlasGrotesk-Regular-Web-vflg7ta4-.woff","request_type":"font"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://www.qchannel03.cn/m2.js","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-7c788da3aac/v3/js/jquery.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/ym.m2.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://m.jd.com/","request_type":"html"}
+{"origin":"http://www.alipay.com/","request_url":"https://gw.alipayobjects.com/os/??s/prod/i/common-fb480.js,s/prod/i/index-7734a.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/base/iphonex68.js?v=20180323","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static2.dditscdn.com/mbl/frontend_backbone/static/_common/js/ga/advertisement.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mjs.sinaimg.cn/umd/base-tools-SUDA/0.0.36/index.all.min.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm&ex=doubleclick.net","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/gw/ajax/card.html/260-2953656-0613235?ie=UTF8&opf_redir=1&rshVal=1523792019116","request_type":"html"}
+{"origin":"http://www.bongacams.com/","request_url":"http://bongacams.com/","request_type":"html"}
+{"origin":"http://www.alipay.com/","request_url":"https://ds.alipay.com/?from=pc","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/api/OxBannerService/getAdvertisements.jsonp?zone=461&category=&pageurl=http%3A%2F%2Fsp.nicovideo.jp%2F&pagevariant=&callback=ads_callback_2&_=1523791959332","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_js_controller.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/activeview/osd_listener.js","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/ActiveUserResource/create/","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://api.twitter.com/graphql","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/bundles/video.3b51e65e27268483defa.bundle.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://wq.360buyimg.com/js/version/201706/spdtimming.new.201710261058.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://connect.facebook.net/signals/config/731697573629176?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-be7afd80869374e8f9fd0c31859f748aaefbe2fd._V2_.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81pPtFtJAnL.js?AUIClients/GoldboxUDPAssets","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://at.atwola.com/addyn/3.0/5113.1/221794/0/-1/size=320x50;noperf=1;adclntid=1002;alias=MMSNUSEN12;kvmsft_providerid=7hd66fc;kvmsft_rid=e86f55f780704d568af4af783e3cb6c4;kvmsft_ext_inv_cd=us;kvmsft_muid=39041e2b94ed6ef00cb315f995be6f73;kvmsft_pagetype=homepage;kvpg=%2Fmsn;kvugc=0;kvmn=MMSNUSEN12;kvgrp=791833916;kvismob=1;extmirroring=0;kvtile=1;target=_blank;aduho=-420;grp=791833916","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://adobe-sync.dotomi.com/adobe/match?nuid=86070857378125119120981354726841823876&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=66&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A66%7D&logFlag=uaction_1523791857874&t=1523791923876","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://pcookie.taobao.com/app.gif?&cna=RiZaE+YPjyICAZUUPw3CLc3s","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WtM34wAACGMfPfyQ&C=1","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://wgo.mmstat.com/sb.sbp.action?cache=92d1aec&gmkey=EXP&gokey=platform%3DAndroid%26smbSid%3D_1523791823482%26apuri%3Dsb_load%26source%3Dsb%26bizKey%3Dtaobao%26rbbt%3Dundefined%26appkey%3D24585258%26logtype%3D2&cna=&spm-cnt=a223j.8443192.0.0.550f3dbeLF7YWD&logtype=2","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=269&dpuuid=3e325ad3-335f-4700-9ad6-802fe2402456&ddsuuid=86070857378125119120981354726841823876","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=49276&dpuuid=80ebe491-304b-4c38-9049-a743c12e518c","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/ibm-logo.png","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/images/logo/logo_large@2x.png?v=5e5e6b5d383cff6750ab11f96adf526a","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/F13JvZjM5cCjOttGTn7eJiqCW21EohcHoqhhoKzwvuJAY8QN0t9uOlgRE_PCug=w512","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://www.360.cn/","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2","request_type":"font"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFW50bf8pkAp6a.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/04/15/1523784351_20180415-00000164-sph-000-view-x104-y104.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s4.pimg.tw/album/misspixnet/element/319325594_1523413902-402295774/zoomcrop/590x393.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/az/hprichbg/rb/PaintedForest_EN-US5613568462_480x640.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/8225fdef20d7489a828fbd1ce04e619d.jpeg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/xba/Homedecor._CB503098438_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/514JesWg6VL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/29/1/0/325/x-amz-cf-id%3A1T9T9D4QKWyccvPPC95eIaFq_Qr5gqAO_i8NM9I4fXUfsmBajJqJzA%3D%3D%40via%3A1.1%206870f30e42907e5a7094c79c6acd0ec3.cloudfront.net%20(CloudFront)/0","request_type":"text"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17652/1/0/647/2087901/0","request_type":"text"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/apple/image_small.svg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/ipad/image_small.svg","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/js/pixlogger.min.js?v=e8869abe59f37ca1f0847c8fa8d65222","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=145&cm=39041E2B94ED6EF00CB315F995BE6F73","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://log.mmstat.com/eg.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-vv_ad_cta/td-applet-viewer-templates-vv_ad_cta-min.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/_h/975a7d20/webcore/externalscripts/jquery/jquery-2.1.1.min.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets","request_type":"css"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://www.jd.com/","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://sina.cn/?from=web","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://gql.twitch.tv/gql","request_type":"text"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://interface.sina.cn/auto/inner/getAutoDataByIp.d.json?callback=jsonp_08996008312237642&timestamp=1523791848733","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/abg.js","request_type":"script"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://sapi.sina.cn/ls/getCardDataV3?callback=jsonp_004364016688513539&timestamp=1523791845327&id=10000&card=sports,ent,finance,tech,auto&nopic=0&page=0","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-js-9a10b8f6/js/js/signup%7Chome%7Clite%7Cclient.js/2/4QgC0ogxgag84Egcgp0E0v4yghgB0s0S02gDgggjgd0Bgwgt4Igig5gm4L4K1x/l/true/none","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/bundles/one_tap.ba1f2869271973914d29.bundle.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"http://www.pornhub.com/","request_type":"other"}
+{"origin":"http://www.ok.ru/","request_url":"https://www.ok.ru/","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe-sync.dotomi.com/adobe/match?dtm_test=4a42208494300930&nuid=91191954147729940174299115411397659455&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com%26","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.bing.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=9174E7EAE8624D1A8C05A88CE491F949&RedC=c1.microsoft.com&MXFR=398FA6D04E55659D3C94AD024F0B64DD","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=spotx.com&id=a0166922-40a0-11e8-981d-180430d51c01","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://btrace.qq.com/kvcollect?BossId=4787&Pwd=1286385847&expo=pv&page=yaowen&channel=yaowen&qudao=&qq=&source=http%3A%2F%2Fwww.qq.com%2F&pac_uid=&openid=&xw_uid=9fc118b97&webview=Chrome&network=&_dc=32896","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=5c627885-3475-4ed8-a54e-8d0222f57cbe&d=MACRO&r=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d31%26uid%3d","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://cat.sv.us.criteo.com/delivery/lg.php?cppv=1&cpp=l4ryd3xEMTZnM28wV3V6SEZRZXFCejJUaEtFK2FQcFlNeStXak53RGMzNU9nS0dPZDdrR1grc0VjWnUyeWVQV0J4d0VtbUlGOHNZb210blVBQWQvenBOOGQrZ21uTTB4UjllTWZGV3g1N0Flbkd0VGYxUU9Ybks1bHEyRVp2cVZPR3NtQ1dWVnlob1F4cTFtMWpKNXZYNkRhY1l5MlJhV3lFeWhUMGNGU3F1NG9Da0ZaVTdFZDFvbjAxUkZTajdkU28yRG5HaXZKWTBZYm40NklhWGNYd2c4VjlwNlFSb2t2QW1WSUJvNnp4VjNwRll6V05HYStPektuajFackRlMllreURafA%3D%3D","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://p.skimresources.com/?provider_id=94AC3827-BDDB-436B-A363-D775FCA8DB42&skim_mapping=true","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/cv/ae/default/170721/wide-trans-16-9.gif","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/uvc_16.png","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/feed/20180414/488f7d7dd4da35c1c036e838fde83b8f.png","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://r.dmp.sina.cn/cm/sinaads_ck_wap.html","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://uhf.microsoft.com/_log?c=TUMxO01TMDtNU0ZQQztNVUlEO2FrYWNkX09uZVJGO29wdGltaXplbHlFbmRVc2VySWQ=&h=www.microsoft.com","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/roboto/Roboto-Medium-webfont-vflGvvuWg.woff2","request_type":"font"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/sports/transform/310/w710h400/20180415/mhvU-fzcyxmu7163400.jpg/w710h400z1l50t1c35.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=1002533252,1826946016&fm=173&app=25&f=JPEG?w=218&h=146&s=8020DD1658314680A39774F403007068","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2","request_type":"text"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://yjtag.yahoo.co.jp/tag?site=GKNjDO2&H=2ve9sua","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-analytics-0.1.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://data.cnn.com/jsonp/breaking_news/domestic.json?callback=CNNBreakingNewsCallback","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-loadable.min-vflgMa7be.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/se/static/js/service/index_seloader_release.js?v=25396530","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_2&relatedID=&news=0_0&SUV=null&_time_=15237919453346391866598626","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTEwMzkmdGw9NDMyMDA=&piggybackCookie=hwcv8085y0jp","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NBA_One-Play_Fultz_bucket/dm_180414_NBA_One-Play_Fultz_bucket.jpg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"http://www.qq.com/","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages.adobe.com/services/globalnav.json/www.adobe.com/en/all.json","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2","request_type":"font"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/scripts/registration/registration.js?_v=20fc81dc8a652825efe0fd8e2f1dff25","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe-sync.dotomi.com/adobe/match?nuid=91191954147729940174299115411397659455&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212284268","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"http://unid.go.com/v3/hit","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?id=iBbvH7EyvEvYZj30WglT0g==&ex=rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=44e6ca35a035ffdd156f","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=6&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A6%7D&logFlag=uaction_1523791857874&t=1523791863880","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.facebook.com/tr?id=1674696026155243&ev=ViewContent&noscript=1&cd[MerchantID]=&cd[MerchantTPV]=&cd[MerchantTransaction]=&cd[FPTICookie]=&cd[P2PTransaction]=&cd[P2PTPV]=","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DXZ4D3PPDB36HTEGXD7ZH%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D417%26cf0%3D2098%26pc0%3D2099%26ld0%3D2099%26t0%3D1523791912643%26sc1%3Dlg%26af1%3D2284%26pc1%3D2284%26ld1%3D2284%26t1%3D1523791912828%26sc2%3DcsmCELLSframework%26bb2%3D2340%26pc2%3D2340%26ld2%3D2341%26t2%3D1523791912885%26sc3%3DcsmCELLSpdm%26bb3%3D2341%26pc3%3D2343%26ld3%3D2343%26t3%3D1523791912887%26sc4%3DcsmCELLSvpm%26bb4%3D2343%26pc4%3D2343%26ld4%3D2343%26t4%3D1523791912887%26sc5%3DcsmCELLSfem%26bb5%3D2344%26pc5%3D2344%26ld5%3D2344%26t5%3D1523791912888%26sc6%3Dpc%26af6%3D2371%26cf6%3D2371%26pc6%3D2371%26ld6%3D2371%26t6%3D1523791912915%26sc7%3Dinteractivity%26cf7%3D4402%26pc7%3D4402%26ld7%3D4402%26t7%3D1523791914946%26sc8%3Ddata-store-1%26bb8%3D4644%26cf8%3D5404%26pc8%3D5404%26ld8%3D5404%26t8%3D1523791915948%26sc9%3Dcard-load-1%26bb9%3D5450%26cf9%3D6097%26pc9%3D6169%26ld9%3D6169%26t9%3D1523791916713%26ctb%3D1:9933","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://ib.adnxs.com/setuid?entity=158&code=WtM4gQAABibm4O17","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/duolingo-android.png:l","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/logos/watch_series_3_logo_medium_2x.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t5707/83/1407890143/14681/29321e2c/59263c71Nc7d16503.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/_i6FMmMDzrDTVkyCIJwbkZJulXtfrddhjL7-NZNeKg05kI_TgkL8K_zfBGd9Kmo=w192","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p2.ssl.qhimg.com/t01c4239d3c1e617adf.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938552_6763302643252&itemspaceid=15697&adps=4800640&apt=4&turn=2&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938552","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=3825186185","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/FIFA%2018-429x572.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201709/30/134985621/original/(m=eafTGgaaaa)(mh=aEElketUPfI2PNjd)7.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/7.3qwerty42.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/01c/235/2cd/big_lq/5b52daa14aad24b4482cf5a21a93652c.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_nS_ZECPWzZi1vICfSezF5w&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/2017/fashion/04_shoes/12Dec/M/1086112_shoes_sports_categorycard_sale_1050x1050_4._CB492471645_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51Ua5RfyCqL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/amazonservices/seller_success_stories/2018/03_Apprenticeships/apprenticeship_1242x450._SX414_CB501585757_.jpg","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-lightbox-0.1.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn-gl.imrworldwide.com/novms/js/2/configs/glcfg510.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/Bold/latest.woff2","request_type":"font"}
+{"origin":"http://www.sohu.com/","request_url":"https://static-alias-1.360buyimg.com/jzt/libs/behavior/v2/behavior.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/autocomplete-search.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-0bc3e845fbd/v3/js/skins/min/xnxx.footer.static.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/mit/td/td-applet-mobile-header-1.0.215/r-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/lib/atp.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTExMTMmdGw9NDMyMDA=&piggybackCookie=uaDO1r_5m9ShoMvWufCH1Or0koCho5Pc7_ABxs7Q","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAwXc1193FAUkfD4AcgdqMHqMw27K5tHuqHDGJmzORaJIHFYCIZM","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.linkedin.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-62256447-1&cid=489400867.1523791896&jid=1324324500&_v=j39&z=1618093907","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12278&impid=&at=1&mkey=&latcy=3678&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=6634895808833&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791941887","request_type":"html"}
+{"origin":"http://www.facebook.com/","request_url":"https://m.facebook.com/sem_campaigns/sem_pixel_test/?google_pixel_category=4&google_pixel_src=https%3A%2F%2Fgoogleads.g.doubleclick.net%2Fpagead%2Fviewthroughconversion%2F995153884%2F%3Fvalue%3D1.00%26currency_code%3DUSD%26label%3DszBrCMnWkWAQ3K_D2gM%26guid%3DON%26script%3D0&encoded_one=AQSId99sBTej_4BBG6GmQ_0gFCKS8ICwyNxMihTVLYFRxu33iCmzYifXJVLnwNlFw_liSFp2ljD9bnk3oqZ0qSnH&encoded_two=AQRLdDg1SONElfggwc7HIjQGd-8xmiuupzk4d_YKzsolFXOOGn3OHwhpZi-otPM7mUVNGslLi8DC40eFJ8kwWs3t","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://cdnssl.clicktale.net/www20/pcc/544fc825-311a-44c5-86f0-70581a36c216.js?DeploymentConfigName=Release_20180409&Version=1","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://content.jwplatform.com/libraries/gGf2YDZH.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://revee.outbrain.com/page/view","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2","request_type":"font"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yN/r/EhPVNgIAn7R.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://aax-fe.amazon-adsystem.com/s/ecm3?ex=intimatemerger.com&id=QeqsEWWHRf6bXx8r-Fq9bw","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=54&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A54%7D&logFlag=uaction_1523791857874&t=1523791911876","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/pixel/AMXnAQvnDBx5ZFsIn6C26byxx8HuWKr9lXwF2yJXlBiU2ipuXfFhkA4myPPcNZLvnlXq7GmEarE_VI3X6X4bmgYrDrZ4MLxBSpH8wshjHYJg8cbJPNMZOoVljpo1Ah9EoUM4nuS5cb8Z8ISf2ijPHUzQ0x5nWvaSefLQdyR-nZyGCMh9.gif","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss2.bdstatic.com/5eZ1dDebRNRTm2_p8IuM_a/img/1L/Aw/2F/mk/ch/o/blank.gif","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://rs.gwallet.com/r1/ucm?id=91191954147729940174299115411397659455&r1s=ajt76zisxpejy89rz51fbpuz8kcb9r39ktr6uqzxk33zgx7t4zqy","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://pixel.mathtag.com/event/img?mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/i/sign-pisces@x2-485845836f.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/EE/BFE3CC.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/5vjrG5sh3rxYqrSoYF-KYIVVRb3aq7Hz_WNbYy480yNV-IdDDuN4-moWedYS-s0=w384","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t01de40a82bcce44ec2.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/newicons/android-chrome-192x192.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/logo.png?1372079638","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1exaOLVXXXXXeXFXXXXXXXXXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/a1w_-jGQeeTclpilcZCCHw/009/341/235/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/EkrEvhyFSbRcPacHb5s3XA/009/162/619/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/9b/a7/11/9ba711b14545c758a718b6e5b8ea4892/9ba711b14545c758a718b6e5b8ea4892.21.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0406/dm_180406_nfl_dallas_americas_team/dm_180406_nfl_dallas_americas_team.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1Si1QJVXXXXa6XXXXq6xXFXXXg.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=4275366585,1117135669&fm=173&app=25&f=JPEG?w=218&h=146&s=653B1BD7106356B4AD2195CE0300F033","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/da5a6b33-5b00-41cc-9a77-7e3e73aaabcb/scale-to-width-down/366","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2/freeform/DebugEvent?source=www&action=jsSimplicityPrefetch&statusCode=200&startTime=1523791892007&endTime=1523791896506","request_type":"text"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-00000000004/v3/img/skins/xnxx/icons-sprite.svg","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://ssl.google-analytics.com/ga.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/gp/gw/ajax/dataStore.html/358-6685975-3653550?ie=UTF8&hmac=BA46D9D3312456EA27B6C708CE1A7174D6B974CF&opf_redir=1&relatedRequestId=QVRKZSEBR7BT5RF15TNH","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-content_body_mega/td-applet-viewer-templates-content_body_mega-min.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/jquery-2.2.0.min.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/login/sp/js/login_promo/1.0.3/login_promo_param-min.js?t=423275","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://r1.res.office365.com/owalanding/v2.7/landing.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTM2MiZ0bD00MzIwMA==&piggybackCookie=uid:4b9e5ad3-32b3-4100-aec0-634f1b8ae61e","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm&ex=doubleclick.net","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://idsync.rlcdn.com/365868.gif?partner_uid=86070857378125119120981354726841823876","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/en-us/homepage/_sc/js/f5956224-127422f6/direction=ltr.locales=en-us.themes=start.dpi=resolution1x/71-9c6b2e-539137f5/44-8eb50c-69c2a4f2/2f-12f6f9-5599dabd/37-d4b095-e76dbcc3/48-7b4036-68ddb2ab/82-07d121-cae48929/75-1cbb3e-d1f8fb43/61-1e52ae-f9c98504/8a-b2a26d-e5780970/47-1b2808-f1619368/81-18659d-3dbe5aa4/d6-04304d-68ddb2ab?ver=2.0.6673.337&fdhead=mmxios1cf&csopd=20180410192604&csopdb=20180413175909","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/io-form/io-form-min.js","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"http://b.scorecardresearch.com/b2?c1=2&c2=17985152&ns__t=1523791865822&ns_c=UTF-8&cv=3.1m&c8=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&c7=http%3A%2F%2Fcoccoc.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://trc.taboola.com/sg/amazon-a9-network/1/rtb","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"https://px.moatads.com/pixel.gif?e=25&q=2&hp=1&kq=3&lo=0&qs=1&ak=http%3A%2F%2Fwww.espn.com%2F-&i=ESPN1_SEGMENT&ue=0&uu=0&qm=420&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2BweM!%2CxnyAk_D2fQ%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=BmCCkSBBBBBBbBBBBq6YYNCu3NBBBwk0Bv34mCeCC4g6miE2wif6W0lBg1SfTBBBBBBeUIBCBBMBBvBUtBWx6jHdBBfXe8kBPB2kc3MMpFBTaBBBBBBBBBBBtsWaBBBHCZ5iWeWSBM31KJPlglCCFMWFpcxaBCNBZnuBBOFeBCBBbBBwxBHryaIGoXjTr93nNBBB3BBJBBzBPBBBlDDBCDCCDCDDDDDC0GuBeEES8DDBqBCKqeMFB&iv=5&vf=1&vg=100&gz=0&hh=0&hn=0&qt=0&bq=0&g=7&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=360&fy=0&gp=113&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&cm=0&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=0A8AF6A3-114D-4E90-CE93-928476B93005&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1523792042551&de=396947004824&cu=1523792042551&m=5556&ar=cf7e882-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=114&lb=8594&le=1&gm=1&io=1&ct=undefined&as=1&ag=5415&an=0&gi=1&gf=5415&gg=0&ez=1&ck=2514&kw=841&aj=1&pg=100&pf=0&ib=0&ic=4838&cc=1&bw=5415&bx=0&ci=2514&jz=841&dj=1&aa=1&ad=4838&cn=0&gn=1&gk=4838&gl=0&co=1937&cp=841&cq=1&im=1&in=1&pd=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=5266&cd=0&ah=5266&am=0&rf=0&re=0&wb=2&cl=0&at=0&d=52519497%3A2246459680%3A4601938233%3A138229376639&bo=104318097&bd=104335617&gw=espndfp832188684382&hv=Domsearch%20Late&zAudience=unclassified&ab=3&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=142625&zMoatSegments=38844%3B408098&na=1329009667&cs=0","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=rightmedia.com&xid=E0","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=411&dpuuid=WtM4gQAABibm4O17","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/clash-of-clans-android.png:xl","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/sc/h/3ubxfas73i6u9fn5k8w6hdxq4","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/R9YAAOSwyP5aTAxi/$_57.JPG","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/G0Ask1gVjQ0KgKhF8FoVNg/009/341/339/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://imageproxy.pimg.tw/zoomcrop?width=75&height=75&url=http%3A%2F%2Fpimg.pixnet.tv%2Fuser%2Fdatong888%2F136170557%2Fbg_000000%2F75x75%2Fdefault.jpg%3Fv%3D1523785694","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://d2x3bkdslnxkuj.cloudfront.net/2749587_300.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/c03fd5535e161c3d071a08.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4153.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61nrWDGVoOL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/32430/1/0/310/0/0","request_type":"text"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflUiilPi/noncore.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://unagi-eu.amazon.com/1/events/com.amazon.csm.nexusclient.prod","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-relatedvideos/td-applet-viewer-templates-relatedvideos-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-video_atomic_sm/td-applet-viewer-templates-video_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/y5/l/0,cross/H9-0Wn5Ol0z.css","request_type":"css"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://rules.quantcount.com/rules-p-c1rF4kxgLUzNc.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/evc____20180414_bou__liv_44d9f924_e50f_4834_abec_51082/evc____20180414_bou__liv_44d9f924_e50f_4834_abec_51082.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://interface.sina.cn/wap_api/ls/wap_ls_card_data_api.d.json?callback=jsonp_031188966767801585&timestamp=1523791845333&id=10000&card=searchbar,mil,blog,edu,fashion,life&nopic=0&page=0","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://www.googletagmanager.com/gtm.js?id=GTM-5XJBR3B","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3iYR44/y7/l/en_US/8ZD1qAgZLV9.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://connect.facebook.net/signals/config/130492214192672?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52772343&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792001403&fs=1&pvid=af8909f310077f891a5b6af5b4f0aa16&cg=db368744220fd480aeab9239e1ddf33f","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://usermatch.krxd.net/um/v2?partner=amzn","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://g.bing.com/uac/response?size=320x50;noperf=1;adclntid=1002;alias=MMSNUSEN12;kvmsft_providerid=7hd66fc;kvmsft_rid=e86f55f780704d568af4af783e3cb6c4;kvmsft_ext_inv_cd=us;kvmsft_muid=39041e2b94ed6ef00cb315f995be6f73;kvmsft_pagetype=homepage;kvpg=%2Fmsn;kvugc=0;kvmn=MMSNUSEN12;kvgrp=791833916;kvismob=1;extmirroring=0;kvtile=1;target=_blank;aduho=-420;grp=791833916","request_type":"other"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/css/aa4d7c5/photo-layer.core.css","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/thirdparty-new.min.fp-82c94a7b28ebafb87f108e6611d49a7c.css","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?p_user_id=7LOhZDOrTi2dZfi89QUpvw&ex=twca&id=7LOhZDOrTi2dZfi89QUpvw","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=adobe.com&id=30714613168148486272856061102473813453","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://www.facebook.com/tr/?id=1588263144793165&ev=ViewContent&dl=https%3A%2F%2Fimg.scupio.com%2Fhtml%2Fad.html%3Fv%3D1.2.14&rl=&if=true&ts=1523792026582&cd[SBST]=6&cd[PuID]=pixnet","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/984527532/?value=1&label=r_58CJXm0gIQw9iz3gM&guid=ON&script=0&data=ecomm_pagetype%3DMsite_Gateway%3BCURRENT_TIME%3D2018-04-15T11%3A33%3A40.072Z%3BSignedIn%3DN","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=cG1bOinjTTabalmvjg0qdrrc,0.2962277155546853&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04_ts%031523791947%04sec%035%04_E%03depicTime","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845943,aid=exp_video-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/exsync","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/container.gif","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/topic-spotlight-h2.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/cx_gaoxiao.png","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://universal.iperceptions.com/iFrame.html","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFWp0bf8pkAp6a.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5214000/5214955/220x165/10.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/489000/489059/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/eq4c5hdLaIwin_bjMztcKg/009/341/434/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-bg-cc-video-2018-mobile-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/136000/136319/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/2512000/2512420/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71cSa-wuJxL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/51EXPF5yQOL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51g4qr8fBNL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://www.360.cn/favicon.ico","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/shemalez.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-taptooltip/td-applet-viewer-templates-taptooltip-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-viewer-slideshow/td-viewer-slideshow-min.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1/t.js?ver=%272.1%27&name=%27Ms.Webi.PageView%27&time=%272018-04-15T11%3A30%3A36.138Z%27&os=%27Android%27&appId=%27JS%3AMicrosoftHP%27&cV=%27Ip%2BPRKmepUW3iJnr.4.1%27&-ver=%271.0%27&-impressionGuid=%27ec723f7c-079a-4e7d-8136-9b38930eaf8a%27&-pageName=%27Homepage%27&-uri=%27https%3A%2F%2Fwww.microsoft.com%2Fen-us%2F%27&-market=%27en-us%27&-pageType=%27HomePage%27&-resHeight=512&-resWidth=360&-pageTags=%27%7B%22browserGroup%22%3A%22uplevel.web.mobile.webkit.android%22%2C%22isTentedPage%22%3Afalse%2C%22tasId%22%3A%222f524406-9a14-4dec-ba16-609dc375d6ff%22%2C%22pageVersion%22%3A%220.1%22%2C%22isCachedPage%22%3Afalse%2C%22enabledFeatures%22%3A%22uhf_retailstore2%3A1%2CUhfPb%3A1%2CUhfUsePh%3A1%2CUseModuleTitleFromResolutionDocument%3A1%2CEnableLocaleDetection%3A1%2Cdisable_edge_crossorigin_attribute_script%3A1%2CUhfSwp%3A1%2Cenable_sasslib_minification_runtime%3A1%2Ccore_use_css_from_sp%3A1%2Ccore_cookiecompliance_enabled%3A1%2CMwfCss_1_22_4%3A1%2CDisableRobotsCacheSetting%3A1%2Ccore_akamai_im_enabled%3A1%2Ccoreui_hero_image_resize_90%3A1%2Cuhf_as_iris%3A1%2Ccore_statics_afs%3A1%2Ccore_use_coreui_mwf%3A1%2Ccoreui_makeimagebackgroundtransparent%3A1%2Ccore_render_assetid_primary%3A1%2CSetPicassoTimeOutTo10%3A1%2Cf_audiencemanager_disabled%3A1%2Ccore_BypassJWTValidation%3A1%2Ccore_revert_require_change%3A1%2CEnableInternalPicasso%3A1%2CMSADisableForceSignin%3A1%2Ccore_disableAADAtBeginRequest%3A1%2CDisableToSkipMarketdetectionforUknownRoutes%3A1%2Cf_video_uselegacyservice%3A1%2Csr_disable_cc%3A1%2Ccore_use_common_static_url%3A1%2Cuhf_magic_triangle%3A1%2CRelevanceOverride%3A1%2Cskiplowbarbrowse%3A1%2Cpipeline%3A1%2Ccoreui_videomodule_useflexsize%3A1%2Ci_uhf_ckrate__10000%3A1%2Ccore_enable_redtux%3A1%22%2C%22isOneRf%22%3Atrue%2C%22isCorpNet%22%3Afalse%2C%22dataVersion%22%3A%224%2F13%2F2018%2010%3A43%3A11%20AM%20%2B00%3A00%22%2C%22serviceName%22%3A%22marketingsites-wcus-prod%22%2C%22metaTags%22%3A%7B%7D%2C%22scripts%22%3A%22Optimizely%2CClickTale%2CAudienceManager%22%7D%27&-behavior=0&*baseType=%27Ms.Content.PageView%27&*cookieEnabled=true&*isJs=true&*title=%27Microsoft%20-%20Official%20Home%20Page%27&*isLoggedIn=false&*serverImpressionGuid=%272f524406-9a14-4dec-ba16-609dc375d6ff%27&ext-app-env=%27onerf_prod%27&ext-app-expId=%27EX%3Amuidflt285cf%2CEX%3Axboxcontentondesktop%2CEX%3Aopenxbl%2CEX%3A16057171c%27&ext-javascript-ver=%271.1%27&ext-javascript-libVer=%274.2.8%27&ext-javascript-domain=%27www.microsoft.com%27&ext-javascript-userConsent=false&ext-user-localId=%27t%3A398FA6D04E55659D3C94AD024F0B64DD%27&$mscomCookies=true","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://secure.quantserve.com/aquant.js?a=p-xLEyC0FLYFXAH","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/aw/mobile-ads/ajax/js?10","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/photo/2018/0413/r268281_2_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://googleads.g.doubleclick.net/pagead/drt/si","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12273&impid=&at=1&mkey=&latcy=2224&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=6671608107068&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791940339","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://staticxx.facebook.com/connect/xd_arbiter/r/FdM1l_dpErI.js?version=42","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791948293&yhlClientVer=3.30.2&yhlRnd=uBmfvdjwYL8Blghhjg0qds79&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.bongacams.com/","request_url":"https://rum-collector-2.pingdom.net/img/beacon.gif?id=5654525eabe53d8c6442edf2&sAW=360&sAH=512&bIW=360&bIH=512&pD=24&dPR=3&or=portrait-primary&nT=0&rC=0&nS=0&cS=2541&cE=3558&dLE=2541&dLS=2541&fS=4300&hS=2861&rE=-1&rS=-1&reS=3559&resS=4288&resE=4642&uEE=-1&uES=-1&dL=4313&dI=9326&dCLES=9327&dCLEE=10190&dC=14904&lES=14904&lEE=14910&s=nt&title=Free%20Live%20Sex%20Cams%20-%20Live%20Sex%20Chat%20and%20XXX%20Live%20Porn%20Shows&path=https%3A%2F%2Fbongacams.com%2F&ref=&sId=35f9h3jh&sST=1523791945&sIS=1&rV=0&v=1.3.3","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"http://m.vk.com/","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://platform.twitter.com/widgets.js","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/v/10341xh50yz21mhhydueu4m5wad.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://x.bidswitch.net/sync?dsp_id=108&expires=14&user_id=412363c8-fdfc-401b-9d8f-cf2311910b6c&ssp=pubmatic","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/styles/ac-globalnav.built.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/components/rebrand_plane-vflGHJ5Ou.css","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages.adobe.com/etc/beagle/public/globalnav/adobe-globalnav/latest/adobe-globalnav.min.css","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=aolvideo.com&id=62394494f452e1144d6bbc182fcee44ffb6f5c2a","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.facebook.com/tr?id=1939652716271841&ev=PageView&cd[order_id]=74158a0c-66dd-4985-981d-94fa6c4f8c8e","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/loading-icon.gif","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Porn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube&time=1523791992588&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fm.txxx.com%2F&random_number=27495434&sess_cookie=eacdc2b2162c914970caae02fd9&sess_cookie_flag=1&user_cookie=eacdc2b2162c914970caae02fd9&user_cookie_flag=1&dynamic=true&domain=txxx.com&account=wQ4ei1acVE00WL&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://fei.pro-market.net/engine?site=141472;size=1x1;mimetype=img;csync=di;du=67","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/gameguardian-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/hp-print-service-plugin-android.png:l","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/images/pornhub_logo_straight_mobile.png?cache=2018041212","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/pro770906520/albumset/6870581/zoomcrop/75x75.jpg?v=1515567829","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/9LvBDozBm5r8Ys3F3cYH2eFwwQJMo-uDsL-c3dqtmAYfTmF7hiHCNcRHmMZw=w256","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/images/mobile/android-mobile-196x196-1358942022._CB499613265_.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/i2/TB1nmqyFFXXXXcQbFXXE5jB3XXX-114-114.png","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://counter.yadro.ru/hit?uhttps%3A%2F%2Fm.vk.com%2F;rhttps%3A%2F%2Fm.vk.com%2F;74200331","request_type":"html"}
+{"origin":"http://www.weibo.com/","request_url":"https://m.weibo.cn/?&jumpfrom=weibocom","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/1745000/1745938/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://m.360buyimg.com//mobilecms/s276x276_jfs/t17857/165/1635464495/126287/70355e3d/5ad2331aN6bc5e9ff.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/aguiter/albumset/1064278/zoomcrop/75x75.jpg?v=1520568912","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/static/img/newzx/8.31qwerty46.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/UK-digital-music/2018/MarketingCampaigns/032318_MC_EltonJohn/032318_MC_EltonJohnProject__GW_M_1242x450_MU._SX1242_CB499558132_.jpg","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/js/v4/jquery-1.12.2.min.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-react-15.5.4-prod.min-vfl_selyY.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-reblog/td-applet-viewer-templates-reblog-min.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/vendor.d514d5f5a938995a3b3d.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/fetch/4.1.12/tool.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nfl.png&w=100&h=100&transparent=true","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://syndication.exosrv.com/splash.php?idzone=2060545&type=12&capping=2&sub=undefined","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"http://www.google.pl/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938246_1585511996896&itemspaceid=12288&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938246&plateid=1001000000,1003000000","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=en.uptodown.com","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20ImageFavorites/cj,nj/00a1b0e7/ede41f5b.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobeid-na1.services.adobe.com/ims/check/v4/token?jslClient=adobedotcom2&jslVersion=89ab5ef","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rtd-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.reddit.com/","request_url":"https://events.redditmedia.com/v1?key=Mweb2&mac=4bad8d7f7a6d97597355638b0cc17df7124d583cc1d637134c1da8fb3506ac9a","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/components/bubble_dropdown_v2-vflzxzIjM.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/fp/atomic-sm-css.49aaf51f.css","request_type":"css"}
+{"origin":"http://www.360.cn/","request_url":"http://haostat.qihoo.com/haouv.gif?b=chrome&a=1&u=http%3A%2F%2Fm.360.com%2Findex.html&id=59677681.1530397434986225400.1523791827187.1304&c=1&r=&t=1523791827221","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/tr/?id=348538655570151&ev=PageView&dl=https%3A%2F%2Fwww.pinterest.com%2F&rl=&if=false&ts=1523791923937&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=30&it=1523791918963","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/load/lazyload.gif","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://www.google-analytics.com/r/collect","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3DQVRKZSEBR7BT5RF15TNH%26ctb%3D1%26m%3D1%26sc%3DQVRKZSEBR7BT5RF15TNH%26pc%3D10847%26at%3D10847%26t%3D1523791976535%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQVRKZSEBR7BT5RF15TNH%26aftb%3D1:10848","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=1586146139&si=12423ecbc0e2ca965d84259063d35238&v=1.2.30&lv=1&ct=!!&tt=%E7%99%BE%E5%BA%A6%E4%B8%80%E4%B8%8B&sn=37540","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d23696737.gif?sz=5&rnd=207242809&ts=1523791836&sz=5","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=4222&nid=1512&put=4b9e5ad3-32b3-4100-aec0-634f1b8ae61e","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/whatsapp-messenger-android.png:l","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/logos/music_white_small_2x.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_ads_2x.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBm8qVB.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://img.scupio.com/ad/images/RBlogo-sh2.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/close_icon.png","request_type":"image"}
+{"origin":"http://www.office.com/","request_url":"https://uhf.microsoft.com/_log?c=TVNGUEM7TVVJRDtNaWNyb3NvZnRBcHBsaWNhdGlvbnNUZWxlbWV0cnlEZXZpY2VJZDtNaWNyb3NvZnRBcHBsaWNhdGlvbnNUZWxlbWV0cnlGaXJzdExhdW5jaFRpbWU=&h=www.office.com","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4584000/4584817/220x165/6.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/uk-sports/brands/AquaSphere/BrandStore/Marketing/Gateway_1050x1050_PennJuane._UX350_SX350_CB532265858_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61-xbfN4v6L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/7047452e/Images/favicon_metro.ico","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/favicon.ie9.ico","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/right.svg","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/js/main.min.js?v=1476060773","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_194.js?v=195","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/accessibility/tabbable.min-vfl-JKEFx.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/vap/video/airy2/prod/2.0.1459.0/skins/gemini._TTW_.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/nicoapi.js?747e620179aac500bd33d22d030d1bac","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://log.getdropbox.com/log/ocsp_expect_staple","request_type":"other"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/package/newsActivity_da394fd.js","request_type":"script"}
+{"origin":"http://www.google.com.ua/","request_url":"https://adservice.google.com.ua/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.google.com.tr/","request_url":"https://adservice.google.com.tr/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"https://staticxx.facebook.com/connect/xd_arbiter/r/FdM1l_dpErI.js?version=42","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938166_7279267430615&itemspaceid=12421&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938166&cnid=228312284,228178983,228304168,228315240,228263350,228326428","request_type":"script"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM4ZDDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF4zvosKLmL20h8tb6BywMWaKpmdQ","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Shared%20BingCore$fadeAnimation/cj,nj/8c497c38/f92a50a7.js","request_type":"script"}
+{"origin":"http://www.360.cn/","request_url":"https://p.ssl.qhmsg.com/d/inn/6ea3b7d2/pc/p_sd.png","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://sb.scorecardresearch.com/b2?c1=2&c2=15742520&ns__t=1523791926927&ns_c=UTF-8&cv=3.1m&c8=Sign%20up%20%7C%20Tumblr&c7=https%3A%2F%2Fwww.tumblr.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.linkedin.com/lite/platformtelemetry","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://d.agkn.com/pixel/8463/?che=1523791844&sk=164791502661000505577&puid=39041E2B94ED6EF00CB315F995BE6F73&l0=https://trc.taboola.com/sg/neustar/1/cm?taboola_hm=164791502661000505577","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://sync.crwdcntrl.net/map/ct=y/c=8545/tp=CKGY/tpid=WtM35B__DJPpGsQgT1fYqPHA/?https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D120%26cm%3D%24%7Bprofile_id%7D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://www.bizographics.com/collect/?fmt=gif&pid=7850","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://stags.bluekai.com/site/36841?dt=0&r=639278069&sig=2032588566&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmiRglWl1u3dep5hJEi0rvuNa028whzGcC3z3bh3gaqjG33LRr3ADZXAl5XSvQ7AsZVVQWDuLGoEzNmp9xoOQeP0hFr","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/pixel.gif?source=smarttag&fired=report&confid=KPSUiAKl&_kpid=44c1a380-770f-11df-93f2-0800200c9a66&_kcp_s=Fandom&_kcp_d=www.wikia.com&_knifr=3&_kua_kx_tz=420&geo_country=us&geo_region=ca&geo_dma=807&_kua_kx_lang=en-us&_kua_kx_tech_browser_language=en-us&_kua_kx_whistle=0&_kua_kx_tech_browser=Chrome%20Mobile&_kua_kx_tech_manufacturer=Google%20Inc.&_kua_kx_tech_device=Mobile&_kua_kx_tech_os=Android%206.x&_kua_kx_geo_country=us&_kua_kx_geo_region=ca&_kua_kx_geo_dma=807&_kpa_kruxDartParam_ageDELIM=%2C&_kpa_keywordsDELIM=%2C&_kpa_domain=wikia.com&t_navigation_type=0&t_dns=0&t_tcp=0&t_http_request=-1&t_http_response=453&t_content_ready=4775&t_window_load=14564&t_redirect=1255&interchange_ran=true&userdata_was_requested=true&userdata_did_respond=true&store_user_after=suoygvjkd&userdata_user=L6N7iig7%2Csuoygvjkd&sview=1&kplt2=21462&kplt3=21344&kplt4=21348&kplt5=21456&kplt6=21465&kplt7=21477&kplt8=21544&kplt9=21551&kplt10=21552&kplt11=21436&kplt13=21577&kplt14=21578&kplt15=21579&kplt16=21580&kplt17=21581&kplt18=21582&kplt19=21583&kplt20=21435&jsonp_requests=https%3A%2F%2Fbeacon.krxd.net%2Foptout_check%2CNaN%2Chttps%3A%2F%2Fcdn.krxd.net%2Fuserdata%2Fget%2C629","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://events.redditmedia.com/v1?key=Mweb2&mac=8346b5648ce14908d82f348d727b2344057aa5fa43f8441750742f7757756fa3","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/recaptcha_v2_challenge-vflYEW-GO.css","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=mplatform.com&id=11458846305006586543","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=56&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A56%7D&logFlag=uaction_1523791857874&t=1523791913876","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d26490428.gif?rnd=107581893&ts=1523791836","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://r3.mail.ru/k?ok_id=&t=obLD1AAAAAAIAAAA&src=mobile&bci=-1972681224995870980","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://popads-trustguard.cdn77-ssl.net/privacy-5270-mini.gif","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=477&dpuuid=79983fcc2efc65f767bb5028631873c202b5f654813205e2de39bcc8bc8b7312b0da87c991749652","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=129099&dpuuid=f3c8f6274511721ec88b2d83c7776078","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_Images/ic/ee308001/bff07120.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/ummy_icon_16.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t01bf749441a561f519.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/souhu20171024-56.png","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/favicon/128x128.png","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-01a49470266a51f632dab1aef2fc09112d280c1e._V2_.png","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/FzG4uDgje3M/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLACjvi7l-tkBdJpJCCoG14PYHZiow","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/u1QAAOSwbwJaTAtp/$_57.JPG","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d307589931c3a95355f.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_N1QSc5hJi5bSVblf2t2R0A&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BY2U4YjliMjYtOTYyYy00ZGUyLTkxNWYtOGMxNWQyNTJmZWU3XkEyXkFqcGdeQXVyMjA0MDQ0Mjc@._CR71,248,1977,1977_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/814L6pG1+CL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/n1/s124x124_jfs/t15049/87/1663809259/215478/4effd883/5a54725aNc2bfede3.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/log","request_type":"text"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/1/13960/30623/0/0/328/0/0","request_type":"text"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/33636/1/0/638/0/0","request_type":"text"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/bundles/base/en_US.js/248a6557c87e.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/wap/impress?5237=Y2FsbGJhY2s9c2F4X2pzb25wQ2FsbGJhY2tfMCZhZHVuaXRfaWQ9UERQUzAwMDAwMDA1Nzc5MyxQRFBTMDAwMDAwMDQwNTE5LEEyNUQyNTlCMDhFNixQRFBTMDAwMDAwMDQ5NjI5LFBEUFMwMDAwMDAwNTQ2NzEsUERQUzAwMDAwMDA1NTYyMixQRFBTMDAwMDAwMDU0NjcyLEU5RDZBQzRGMzQ4RSZwYWdlX3VybD1odHRwcyUzQSUyRiUyRnNpbmEuY24lMkYlM0Zmcm9tJTNEd2ViJnRpbWVzdGFtcD0xNTIzNzkxODI1MjM3JnJvdGF0ZV9jb3VudD00NjEmYW09JTdCJTIyZHMlMjIlM0ElMjIzNjAqNTEyJTIyJTJDJTIyb3YlMjIlM0ElMjJhbmRyb2lkJTIyJTdEJm5ldD1udWxs","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://bat.bing.com/bat.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/mtb/??lib-mtop/2.4.8/mtop.js,app-h5index/0.7.2/prepare.js,app-h5index/0.7.2/h5index.js?v=2000992104_451808","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/en-us/homepage/_sc/css/f5956224-81ea8d11/direction=ltr.locales=en-us.themes=start.dpi=resolution1x/63-238d64-ceb0c7d4/c0-c07ae0-d6318459/17-835982-68ddb2ab/fe-c22957-26d11eee/64-65e8e9-5fb40aaf/99-3ee4b7-2347cfa6/50-0349a9-f9d7be4e/c0-dace89-dbc6220a/68-16a2a6-5e17ba71/80-9c5866-725d65b7/d1-b1bb1e-3c427d05/49-aa0085-5960eecb/74-6dd793-813a2baa/49-5ff0a7-7394809d/fb-71155f-a4b3038c/9b-b89e7c-9ea6310d/42-8cd310-401ef942/49-a28919-4b5f58d3?ver=2.0.6673.337&fdhead=mmxios1cf&csopd=20180410192604&csopdb=20180413175909","request_type":"css"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/js/various.js?1516108355","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/photo/2018/0414/r356334_1296x518_5-2.jpg&w=686&h=275&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm=&ex=doubleclick.net&google_tc=","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://pagead2.googlesyndication.com/pagead/gen_204?id=sodar&v=24&t=2&bgai=BM05qqjjTWs-cCY68kwPq57SICAAAAAA4AeAEAg&bg=!MjGlMSlEiI6A-ezbaGQCAAAAvVIAAAAbmQFyJmmu7XvMcTQGNuuyBXE6jcfePfKk5ZDt6pHedbYFsFgbdlQ0M9d161YlYH2h42JPo8H4hnVucVAB8zW6zqSHF5eyP0ma2WVfsPL0Vo4jez2aNcycXYXr0u6IPcF_GmO_22Cpu1Yi0oAjjr6o11YjSvJL8_rz0ImHW4CRPOqI2oowFeB-3ejpMSdGPz7e-1qukrv8XborFuG1quuZiW53BdRuYfGxRsD_UR-t0tHvTmr4bLYVUX2HzSLEjM7m0Wh3ah4CU5baeL1Sbuvq-L2uDi85DVCXHWzISKXKwSRRyubSU7_aFFeJnFBhWNaGYu-N--o2AzJ5B4dNxvCB3ip3yO6cVKzE84pGpDi6xdbIoHor-xYeAXB6rQnjpYHKLU9VjE_nnz77u8JvQU95lFLLJrtTcb5gxoJufuUR3GT3d7balFOmgoEgyegP1D3Gyqlsx6Ti88RNs65zvGhWA7IK5fc-hTZzuuxTYw1b0jipYoHbjQ","request_type":"html"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/gen_204?atyp=csi&ei=ATjTWoTsCJGF8AO8wIjADg&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.431,dcl.425,iml.431,ol.2840,prt.234,xjs.1743,xjsee.1743,xjses.1576,xjsls.222,wsrt.2153,cst.707,dnst.0,rqst.831,rspt.443,sslt.379,rqstt.1696,unt.2095,cstt.989,dit.2577&zx=1523791876282","request_type":"html"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/gen_204?s=webaft&atyp=csi&ei=JTjTWsSsDefS0gLf1IfYBQ&rt=wsrt.2156,aft.438,prt.255","request_type":"html"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/gen_204?atyp=csi&ei=EjjTWr-7F4Ws8APa7aPACQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.378,dcl.368,iml.378,ol.2709,prt.215,xjs.1551,xjsee.1550,xjses.1335,xjsls.221,wsrt.2199,cst.708,dnst.0,rqst.795,rspt.405,sslt.382,rqstt.1710,unt.2113,cstt.997,dit.2567&zx=1523791893418","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA=&piggybackCookie=WtM4BQAAAGWhsjF0","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://idsync.rlcdn.com/395886.gif?partner_uid=5978151418385522803","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5api.m.taobao.com/h5/mtop.mt.getdatabyids/1.0/?jsv=2.4.8&appKey=12574478&t=1523791941041&sign=af8f27fa87c61c2e533644f6ce4293a0&api=mtop.mt.getDataByIds&v=1.0&type=originaljson&dataType=json&H5Request=true&data=%7B%22dataids%22%3A%22137%2C217%22%7D","request_type":"script"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/v/wrdqwb04t21o3bfw5fzdqxym0qw.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yj/r/pQwtiAv6JZT.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://d.agkn.com/pixel/8198/?che=1523791937&sk=164051302661000502281&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164051302661000502281&ex=neustar.biz","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://aw.dw.impact-ad.jp/c/ur/?oid=207d81ffda0cc019&rdr=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%7BAONEID%7D%26ex%3Daudienceone.com","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://token.rubiconproject.com/token?pid=2179&pt=n","request_type":"other"}
+{"origin":"http://www.tmall.com/","request_url":"https://pass.tmall.com/add?cookie2=17d978e92b1d4dbc5c435fd6598722a0&t=58bf73713835556317ee13b5e1a80e9d&_tb_token_=77b076736e7b5&tmsc=1523791823624000&opi=10.103.184.133&pacc=0-v-okg6KIBz0Pj2MdJjmg==&target=http%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.user.getusersimple%2F1.0%2F%3Ftbpm%3D1%26jsv%3D2.4.11%26appKey%3D12574478%26t%3D1523791821652%26sign%3D892d1785a3e46dd3882630f5b49ebb17%26api%3Dmtop.user.getUserSimple%26v%3D1.0%26H5Request%3Dtrue%26jsonpIncPrefix%3Dsmb_xc%26timeout%3D2000%26type%3Djsonp%26dataType%3Djsonp%26callback%3Dmtopjsonpsmb_xc2%26data%3D%257B%257D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.outbrain.com/ttd/pixel?user_id=e8421967-8d45-4775-ad7d-73402c438da0","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=fbca&id=tX6_9Xz4Qdmr5oo7UFnXXQ","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQ3AKTQX4Z8AX1W7T64V5%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26m%3D1%26sc%3DQ3AKTQX4Z8AX1W7T64V5%26ue%3D24%26bb%3D1825%26ns%3D1832%26cf%3D2011%26be%3D2065%26af%3D2096%26ne%3D2185%26pc%3D13181%26tc%3D-2261%26na_%3D-2261%26ul_%3D-1523791855869%26_ul%3D-1523791855869%26rd_%3D-1523791855869%26_rd%3D-1523791855869%26fe_%3D-36%26lk_%3D-2239%26_lk%3D-1875%26co_%3D-1875%26_co%3D-1167%26sc_%3D-1564%26rq_%3D-1158%26rs_%3D-50%26_rs%3D346%26dl_%3D-12%26di_%3D2087%26de_%3D2088%26_de%3D2089%26_dc%3D13181%26ld_%3D13181%26_ld%3D-1523791855869%26ntd%3D-1%26ty%3D0%26rc%3D0%26hob%3D19%26hoe%3D25%26ld%3D13183%26t%3D1523791869052%26ctb%3D1%26rt%3Dcf%3A4-0-4-0-1-0-0_af%3A4-0-4-0-1-0-0_ld%3A58-7-4-38-5-0-1%26csmtags%3Daui%7Caui%3Aaui_build_date%3A3.18.6-2018-04-06%7CgwImgNoCached%7Cfls-eu%7CgwmNoCardHistory%26viz%3Dvisible%3A24%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQ3AKTQX4Z8AX1W7T64V5%26aftb%3D1:13191","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://wgo.mmstat.com/sb.sbp.action?cache=4f232e4&gmkey=EXP&gokey=platform%3DAndroid%26smbSid%3D_1523791823482%26apuri%3Dsb_init%26source%3Dsb%26sceneType%3Ddefault%26page%3DmallIndex%26rbbt%3Dbc.mallIndex.1.0.0%26appkey%3D24585258%26logtype%3D2&cna=&spm-cnt=a223j.8443192.0.0.550f3dbeLF7YWD&logtype=2","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_top_nav-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WtM34wAACGMfPfyQ&img=1&__user_check__=1&sync_id=7557a7f1-40a0-11e8-981d-180430d51b01","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1957&dpuuid=0727743D5F426AAA0DB07FEF5B4269B3","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://secure.leadback.advertising.com/adcedge/lb?site=695501&betr=sslbet_1487351074=[+]ssprlb_1487351074[720]|sslbet_1487351090=[+]ssprlb_1487351090[8760]","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-incognito.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/btn-menubar@2x.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201710/W020171117635514372684.png","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/gno/sprites/sky_webnav_V1_sprite_2x._CB489388157_.png","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/8207f68f-b9b9-4c4c-b908-cf0a0b52f353_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://nicovideo.cdn.nimg.jp/uni/img/system/today/2018/04/13/20180413115519_ffe37.JPG","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSpdn.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=1903&y=1395","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180414162623-marla-maples-and-tiffany-trump-2016-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmy.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d30758a691c3a4db02d.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/b4/8a/68/b48a68fa15b958558599ea3f1037e6b3/b48a68fa15b958558599ea3f1037e6b3.14.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/59/ba/43/59ba432c416afa9b3ca056321d623ff9/59ba432c416afa9b3ca056321d623ff9.3.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BNDU1NzUxMzA4MF5BMl5BanBnXkFtZTgwODY4ODk5NDM@._CR18,66,1333,999_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/uk-sports/brands/AquaSphere/BrandStore/Marketing/Gateway_1050x1050_Lita2._CB532265858_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/ce0e29bb-ca45-4d21-897a-c15d4d1e7cb4/scale-to-height-down/82","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2/freeform/WebsiteScreen?source=wwwhead&fetchType=js&winw=360&winh=512&screenw=980&screenh=1394&ratio=3","request_type":"text"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/pingjs/ext2020/weather/mobile2.0/assets/weather/day/00.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_dark_blue.svg","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-cards_atomic_sm/td-applet-viewer-templates-cards_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/mtb/lib-smartbanner-plus-loader/smartbanner-loader.js?t=15237919","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/bundle.NetworkInstrument.27dfea89437d4682.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://i.alicdn.com/ae-msite-ui/common/font/iconfont.c9a05b18.ttf","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://ims-na1.adobelogin.com/favicon.ico?cache_bust=ea83dfc6a55c2","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/iscroll-lite5_59fbd1e.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/photo/2018/0413/r356085_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/gen_204?atyp=csi&ei=JTjTWsSsDefS0gLf1IfYBQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.437,dcl.422,iml.437,ol.2713,prt.255,xjs.1575,xjsee.1575,xjses.1366,xjsls.249,wsrt.2156,cst.706,dnst.0,rqst.827,rspt.441,sslt.381,rqstt.1700,unt.2095,cstt.992,dit.2579&zx=1523791912214","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/anchor?k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo&co=aHR0cHM6Ly93d3cuZHJvcGJveC5jb206NDQz&hl=en&v=v1523554879111&size=invisible&cb=shrftf7z4w0x","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://social-login.cnn.com/gscounters.sendReport?reports=%5B%7B%22name%22%3A%22loadc%22%2C%22time%22%3A%221523791874770%22%2C%22reportData%22%3A%7B%22sref%22%3A%22%22%7D%7D%5D&APIKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&sdk=js_latest&pageURL=https%3A%2F%2Fwww.cnn.com%2F&format=jsonp&callback=gigya.callback&context=R1991236889","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://match.taboola.com/sg/thetradedesk-network/1/rtb-h?taboola_hm=fcbd302d-2d51-4301-be01-c7741f15bde8&tbid=39041E2B94ED6EF00CB315F995BE6F73","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://bat.bing.com/action/0?ti=4074038&Ver=2&mid=e60e2ec1-ea60-690c-77a8-1be6089d93bd&evt=pageLoad&sid=e1fc2579-1&lt=8171&pi=0&lg=en-US&sw=360&sh=512&sc=24&tl=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&p=https%3A%2F%2Fwordpress.com%2F&r=&msclkid=N&rn=705302","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://g.bing.com/uac/request?size=320x50;noperf=1;adclntid=1002;alias=MMSNUSEN12;kvmsft_providerid=7hd66fc;kvmsft_rid=e86f55f780704d568af4af783e3cb6c4;kvmsft_ext_inv_cd=us;kvmsft_muid=39041e2b94ed6ef00cb315f995be6f73;kvmsft_pagetype=homepage;kvpg=%2Fmsn;kvugc=0;kvmn=MMSNUSEN12;kvgrp=791833916;kvismob=1;extmirroring=0;kvtile=1;target=_blank;aduho=-420;grp=791833916","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://ad.afy11.net/ad?mode=10&sspid=3585&google_gid=CAESEGXjCO7jidP2xrlsVNXReI8&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.linkedin.com/csp/dtag?_x=%2526s%253D1%2526url%253Dhttps%25253A%25252F%25252Fwordpress.com%25252F%2526pageUrl%253Dhttps%25253A%25252F%25252Fwordpress.com%25252F%2526ref%253D%2526cookiesTest%253Dtrue%2526opid%253D195308%2526fmt%253Djs%2526time%253D1523791843084&p=9","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive/check?partner_id=2474&partner_device_id=CAESENn8WiwRByhFKIjFxg01J-A","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=c0eb26a0-40a0-11e8-a9d2-1f9b1aff0601","request_type":"other"}
+{"origin":"http://www.onclkds.com/","request_url":"http://www.onclkds.com/style/style.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=104&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A104%7D&logFlag=uaction_1523791857874&t=1523791961876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=88&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A88%7D&logFlag=uaction_1523791857874&t=1523791945876","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=e540b3fc-777a-c6e7-2ce4-c831004aa3df","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=8981&nid=2307&put=2e68b153-5f6c-4bef-a554-4d86b35719b5&expires=30","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pub.pxl.ace.advertising.com/cfcm.ashx?providerId=1008&extMatch=1&rcode=1&ctst=1","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://securemetrics.apple.com/b/ss/appleglobal,applehome,applestoreww,applestoreus/1/JS-2.7.0/s148628913734?AQB=1&ndh=1&pf=1&t=15%2F3%2F2018%204%3A31%3A31%200%20420&fid=3E8E675443B3026F-0CEFB8E58966EE51&ce=UTF-8&pageName=apple%20-%20index%2Ftab%20%28us%29&g=https%3A%2F%2Fwww.apple.com%2F&cc=USD&h1=www.us.homepage&v4=D%3DpageName&v14=en-us&c34=apple%20-%20index%2Ftab%20-%20hero-product-red%20-%20section%20engaged%20.1&c35=0.07&v54=https%3A%2F%2Fwww.apple.com%2F&pe=lnk_o&pev2=apple%20-%20index%2Ftab%20-%20hero-product-red%20-%20section%20engaged%20.1&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://vivaki.demdex.net/event?d_vert=24&d_adsrc=54767&d_bu=57348&d_src=19908&d_campaign=20961954&d_placement=218069769&d_tactic=0&d_site=2311301&d_creative=92161433&d_adid=416623175&c_cookieid=1468081195&d_event=imp","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=1879354928&t=pageview&_s=1&dl=https%3A%2F%2Fwww.pornhub.com%2F&ul=en-us&de=UTF-8&dt=Free%20Porn%20Videos%20%26%20Sex%20Movies%20-%20Porno%2C%20XXX%2C%20Porn%20Tube%20%7C%20Pornhub&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IGBAiAABB~&jid=824515207&gjid=259805078&cid=164959871.1523791909&tid=UA-2623535-1&_gid=303671758.1523791909&z=1178770678","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.google.com/ads/user-lists/984527532/?value=1&label=r_58CJXm0gIQw9iz3gM&guid=ON&script=0&data=ecomm_pagetype%3DMsite_Gateway%3BCURRENT_TIME%3D2018-04-15T11%3A33%3A40.072Z%3BSignedIn%3DN&cdct=2&is_vtc=1&random=1513522200","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/mobdro-android.png:l","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/D0/B01E40.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t19183/49/696491919/3763/dec8cceb/5aa10cdbNa9cd0320.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e/img/3.0/global/misc/cnn-logo.png","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/ksk/promo/top_peron/170310.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=3451030006","request_type":"html"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f12/2cfe05c715413e02f96ea5af3c2ed83b_erotic_285x160.jpg?cno=bb43","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb2.qujishu.com/t7/e=s2579dcgko,qv1x0ae9if&z9=02?ldr=6az5uy_dfqo8_wbc","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51YZ6fP5wpL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31uzIgVilQL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://m.yahoo.co.jp/favicon.ico","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/_h/2532198d/coreui.statics/images/social/facebook.svg","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-position-observer-0.1.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/01/ape/sf/mobile/MAsf-1.19._V497204129_.js?csm_attribution=APE-SafeFrame","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/loader.SearchBox.6854382c216cc7b1.js","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/20170601mobile_common.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/common/inputs/checkbox.min-vflVTF9q_.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://mms.cnn.com/abjKDUmXSwqOSQ4LjkqJC84YjtgVEkmKCg0OjM5JC4pYFZVW0kmJzVgKyYxOCpJNyorKjc3KjdgSS87YFVRU1FcW1NJKCkoYDwuMyk0PFEkODUkUTI4LFEkLjM5KjczJjFRKCkoVEktNyorYC05OTU4SFZkSFVpSFVpPDw8USgzM1EoNDJIVWlJOUhYZT1IWGdgPg==","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://cdn.krxd.net/ctjs/controltag.js.dc955599a3976b2e658d60927793d9ea","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mtb/lib-smartbanner-plus-loader/smartbanner-loader.js?t=15237918","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/util.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-5627261764746d716d001396.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-5359ac4ecd812179a60007a7.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://js.sohu.com/pv.js?_t=20171214","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm&ex=doubleclick.net&","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12425&impid=&at=1&mkey=&latcy=3516&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=8046014059082&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791941702","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.in&slot=navFooter&a2=01014bfb7af69deee68af7a3dc115a1575786c271fe96fa28ed5381b37bbbb7c37f1&old_oo=0&cb=1523792012620&dcc=t","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://d.turn.com/r/dd/id/L21rdC84MTYvY2lkLzE3NDc0MzIzNDkvdC8w/kv/Pagename=wordpress.com/","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM4ZDDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oF0AFWqV2jVcquajfPP98rJrAzq3Q","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ssp-bidapi-n2.i-mobile.co.jp/jsonp/ssp_spot.ashx?pid=6107&asid=185725&asn=1&spec=1&dpr=3&sf=0&pos=0&imcallback=_imcallback_185725_1&cashid=1523791960793","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://social-login.cnn.com/accounts.webSdkBootstrap?apiKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&pageURL=https%3A%2F%2Fwww.cnn.com%2F&format=jsonp&callback=gigya.callback&context=R2622956826","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://sb.scorecardresearch.com/b?c1=2&c2=6034961&rn=0.7700663258524918&c7=https%3A%2F%2Fm.imdb.com%2F&c3=&c4=https%3A%2F%2Fm.imdb.com%2F&c5=&c6=&c10=&c15=&c16=&c8=IMDb%20-%20Movies%2C%20TV%20and%20Celebrities%20-%20IMDb&c9=&cv=1.7","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/iu3?d=amazon.com&slot=navFooter&a2=01010f1290735014d1dc37263c3c759ba6a5871252372bcd23221999ce60d83c6b3c&old_oo=0&cb=1523791910363","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/customized.min.fp-486ef3c5a9763b25fe6e8c65656b4012.css","request_type":"css"}
+{"origin":"http://www.alipay.com/","request_url":"https://kcart.alipay.com/web/1.do?&cna=3yVaE5jtrHgCAZUUPw0MkvH0","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.facebook.com/tr/?id=1097950916987081&ev=Microdata&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1523791872103&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22Dropbox%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=28&it=1523791867576","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://hpd.baidu.com/v.gif?logid=1811881676&ssid=0&sid=122436_100808_122154_114746_100097_120171_122489_118895_118870_118847_118830_118805_120550_107315_122862_117330_117433_122789_121142_122857_122886_123139_122496_114975_116407_122669_110085_122303&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=1&cst=1&logFrom=mid_news&logInfo=a2_l*&logExtra=%7B%22st%22%3A%22news%22%2C%22rid%22%3A%2210454203797378133144%22%2C%22isBaijiahao%22%3A1%2C%22extra%22%3A%22%7B%5C%22mark%5C%22%3A0%2C%5C%22mark_rec%5C%22%3A0%2C%5C%22rec_src%5C%22%3A%5B5%5D%2C%5C%22refresh_timestamp_ms%5C%22%3A1523791811927%2C%5C%22top%5C%22%3A1%2C%5C%22dispatch_time%5C%22%3A1523791812%2C%5C%22msrcid%5C%22%3A80001%2C%5C%22mthid%5C%22%3A%5C%221593743208952652%5C%22%2C%5C%22mrtype%5C%22%3A%5C%22text%5C%22%7D%22%2C%22title%22%3A%22%E4%B9%A0%E8%BF%91%E5%B9%B3%E7%AD%BE%E7%BD%B2%E5%91%BD%E4%BB%A4%20%E5%8F%91%E5%B8%83%E6%96%B0%E4%BF%AE%E8%AE%A2%E7%9A%84%E8%A7%A3%E6%94%BE%E5%86%9B%E5%85%B1%E5%90%8C%E6%9D%A1%E4%BB%A4%22%2C%22picNum%22%3A1%2C%22stype%22%3A0%2C%22itemType%22%3A%22typeNewsOne%22%2C%22pos%22%3A1%7D%2C%7B%22st%22%3A%22news%22%2C%22rid%22%3A%229892176849408070944%22%2C%22isBaijiahao%22%3A1%2C%22extra%22%3A%22%7B%5C%22ac%5C%22%3A0%2C%5C%22category%5C%22%3A1%2C%5C%22channel_id%5C%22%3A1%2C%5C%22city%5C%22%3A%5C%22%5C%22%2C%5C%22cs%5C%22%3A%5C%224147568925%203547710143%5C%22%2C%5C%22debug_red%5C%22%3A%7B%5C%22rank_q%5C%22%3A0.032710734754801%7D%2C%5C%22district%5C%22%3A%5C%22%5C%22%2C%5C%22mark%5C%22%3A0%2C%5C%22mark_rec%5C%22%3A0%2C%5C%22mthid%5C%22%3A%5C%221561192736257973%5C%22%2C%5C%22new_cat%5C%22%3A%5C%22%5C%5Cu5ba0%5C%5Cu7269%5C%22%2C%5C%22new_sub_cat%5C%22%3A%5C%22%5C%5Cu732b%5C%22%2C%5C%22news_attention%5C%22%3A%5B%5D%2C%5C%22predictor_result%5C%22%3A%5C%22CAEZAAA5Bq%5C%5C%2Fx30A%3D%5C%22%2C%5C%22province%5C%22%3A%5C%22%5C%22%2C%5C%22rec_src%5C%22%3A%5B69%5D%2C%5C%22recall_type%5C%22%3A0%2C%5C%22refresh_timestamp_ms%5C%22%3A1523791811927%2C%5C%22score%5C%22%3A32710.734754801%2C%5C%22srccat%5C%22%3A0%2C%5C%22srcid%5C%22%3A80001%2C%5C%22tag%5C%22%3A0%2C%5C%22tj_timeliness%5C%22%3A0%2C%5C%22ua%5C%22%3A%5C%220_0_android_6.0_0%5C%22%2C%5C%22user_profile%5C%22%3A0%2C%5C%22ut%5C%22%3A%5C%220_6.0_0_0%5C%22%2C%5C%22vertical_type%5C%22%3A0%2C%5C%22dispatch_time%5C%22%3A1523791812%2C%5C%22msrcid%5C%22%3A80001%2C%5C%22mrtype%5C%22%3A%5C%22text%5C%22%7D%22%2C%22title%22%3A%22%E7%94%B7%E5%AD%90%E4%B9%B0%E6%9D%A5%E4%B8%80%E6%9D%A1%E5%81%87%E8%9B%87%EF%BC%8C%E6%94%BE%E5%9C%A8%E7%86%9F%E7%9D%A1%E7%9A%84%E7%8C%AB%E8%BA%AB%E4%B8%8A%EF%BC%8C%E7%8C%AB%E7%9A%84%E5%8F%8D%E5%BA%94%E8%AE%A9%E4%BA%BA%E7%AC%91%E5%96%B7%22%2C%22picNum%22%3A3%2C%22stype%22%3A0%2C%22itemType%22%3A%22newsThree%22%2C%22pos%22%3A2%7D&r=l1523791820288","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://secure.leadback.advertising.com/adcedge/lb?site=695501&betr=sslbet_1472760417=[+]ssprlb_1472760417[720]|sslbet_1472760452=[+]ssprlb_1472760452[8760]","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/mobile/icons-36-black.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"http://mat1.gtimg.com/www/qq2018/imgs/qq_logo_2018x2.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/security_keys/insert@2x-vflTxG2RJ.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/bluelily03070521/albumset/5436600/zoomcrop/75x75.jpg?v=1523785742","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/cx_shipin.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/NBA_icon_180228.png","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://m.360.cn/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_13730&impid=&at=1&mkey=&latcy=3266&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=7528378837340&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&_time_=1523791946949","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/dd/83/c6/dd83c6848270c8be021233368a03dc35/dd83c6848270c8be021233368a03dc35.18.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/91/0d/a6/910da6ec4465acacdbca62331b6c5d6c/910da6ec4465acacdbca62331b6c5d6c.14.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/8b/68/c1/8b68c114403b0e49ca3c62ed8d7dc30a/8b68c114403b0e49ca3c62ed8d7dc30a.26.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/3104000/3104648/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTgxMDcyMzk0N15BMl5BanBnXkFtZTgwOTczNTYyNTM@._CR95,22,1520,1139_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/WPPVEHLHmYW0FNhJs3kBYw7G_KKK4KhVo3UyCt0Y5iM.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31MOwKIzA0L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/n1/s124x124_jfs/t14389/105/2661942038/67953/49e8c11a/5ab0aa54N4237510c.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/33636/0/0/311/0/0","request_type":"text"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/mobile/fonts/fontawesome-webfont.woff2?v=4.3.0","request_type":"font"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/i/favicon.ico?v=1447321881","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/home-illo-team-chaos.svg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-mustache-0.1.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn-gl.imrworldwide.com/novms/js/2/nlsSDK600.bundle.min.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://www.google-analytics.com/plugins/ua/linkid.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://fastlane.rubiconproject.com/a/api/fastlane.json?account_id=11078&rp_floor=0.01&rf=https%3A%2F%2Fwww.cnn.com%2F&p_screen_res=360x512&x_source.tid=ceffcb6d-e438-47aa-9b2a-b6cca793c897&tk_flint=plain&size_id=15&p_pos=atf&tg_fl.eid=ad_rect_atf_01&tg_fl.uname=%2F8664377%2FCNN%2Fhomepage&kw=CNN%2Fhomepage%2Crp.fastlane&tg_i.site=CNN&tg_i.section=homepage&tg_i.subsection=landing&tg_i.cap_topics=&tg_i.ssl=1&tg_i.pos=rect_atf_01&tg_fl.pr_acctid=11078&rp_secure=1&rand=0.42595178436199466","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/lib/ph-functions.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ssp-bidder.i-mobile.co.jp/script/sspcore_spot.js?20130501","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdn.navdmp.com/req?adID=86070857378125119120981354726841823876","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/list.xtpl.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/leaguelogos/soccer/500/23.png&transparent=true&w=288&h=288","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.facebook.com/fr/r.php?p=558293300959460&e=-AYFQvTfQS66Rccu-6kpkQ&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dfbca%26id%3D-AYFQvTfQS66Rccu-6kpkQ&s=1523791978&h=K0NxNUY3ampZblhMWUR1OU1vNVp7iYdsam5ieeqnJUBPoUgF","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://magnetic.t.domdex.com/37764/pix.gif?t=c&for=Adobe","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9Mjk0NSZ0bD0xMjk2MDA=&piggybackCookie=36970468-9dbf-4c0a-b6b0-b464a445bb09","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791944593&yhlClientVer=3.30.2&yhlRnd=PZO69pQbje7OoIi2jg0qdpch&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.espn.com/","request_url":"https://syndication.twitter.com/settings","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/BingCore.Bundle/cj,nj/7bd0f601/48d809c9.js?bu=rms+answers+Shared+BingCore%24ClientInstV2%24DuplicateXlsDefaultConfig%2cBingCore%24ClientInstV2%24SharedLocalStorageConfigDefault%2cBingCore%24shared%2cBingCore%24env.override%2cEmpty%2cBingCore%24event.custom.fix%2cBingCore%24event.native%2cBingCore%24onHTML%2cBingCore%24dom%2cBingCore%24cookies%2cBingCore%24rmsajax%2cBingCore%24ClientInstV2%24LogUploadCapFeatureDisabled%2cBingCore%24ClientInstV2%24ClientInstConfigSeparateOfflineQueue%2cBingCore%24clientinst%2cBingCore%24replay%2cBingCore%24Animation%2cBingCore%24fadeAnimation%2cBingCore%24framework","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo0OC4zMTIJMTJiZTQ3MTEtYWVlMi00MzI1LWI0MTUtMDc3YjZmYzAzN2VhCTMyNTY3NzYJMzEyMDYwOAk2MzMxNjg5NDM1X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc4MgkzNTQ1MzI1CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQkwZTczNGQ5NS01MzA5LTM3MzMtYTgxNC03ZmE4YTA4MTU2YjMJMzAwMDAJMC4wMDE2NjY2NjY3CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjA5NTk6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwNDowLjB8dXNlcl9nZW5kZXI6NTAwOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTMJMzAwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=4cf174cfb0db4c6e&p=DnNNlVMJNzOoFH%2BooIFWszQIuq%2B%2FVhM7l9FrXA%3D%3D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID","request_type":"other"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/premium/premium-modals.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-87b47eafbb2/v3/css/xnxx/front.css","request_type":"css"}
+{"origin":"http://www.reddit.com/","request_url":"https://alb.reddit.com/i.gif?q=CgADBQAbKUR6on8KAAUampD8jBRivgoABhqakPyMEmK-CAAHAAAABwoADAUAGypbieUWAA==&s=kdLeXD-gLy3K5Zgr-xx94gnBERpO05SqTH5xv-XLuyY=","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://hpd.baidu.com/v.gif?tid=13&ct=1&cst=1&logFrom=index&logInfo=index&ssid=0&from=844b&pu=sz%40320_1001%2Cta%40iphone_2_6.0_3_537&qid=1811881676&sid=122436_100808_122154_114746_100097_120171_122489_118895_118870_118847_118830_118805_120550_107315_122862_117330_117433_122789_121142_122857_122886_123139_122496_114975_116407_122669_110085_122303&logid=1811881676&ref=index_iphone&r=l1523791814415","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://log.mmstat.com/m.gif?logtype=1&title=%u5929%u732BTMALL&pre=&cache=b57a9a8&scr=360x512&spm-cnt=a223j.8443192.0.0.550f3dbeLF7YWD&category=&uidaplus=&pre=&req_url=http%3a%2f%2fwww%2etmall%2ecom%2f&aplus&udpid=&asid=AQAAAADJN9NaVgwYDQAAAAAY59Z+LzDodA==&sidx=BwqKFynJEBZvxA5z+0rvUM2J18lyxUzIEV324IzOnlX4hckyaLD98KWjmN7pVkJy9a2CSyK1qGZPfzhh4VLTo1s+ShD2xiast87K0YPSwlzWHRDSFwrw7cFQ1WwaeT80GBLG3NzX/RH62J5PNMOWl70pdcs4yQuWH32+Gjq5lEE=&ckx=|&p=1&o=android6.01&b=chrome58&s=360x512&w=webkit&ism=android&lver=8.3.14&jsver=aplus_std&pver=0.3.19&mansndlog=1&urlokey=%2Fmain&tag=0&stag=-2&lstag=-1","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/img/logo_new.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t5842/205/151189300/13247/a6de2d/591d94edNc42fb94d.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t5824/248/156712927/7215/1ad6be5f/591d94c6Nc4711ad2.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/flags.png?v=7","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/weizhang083002.png","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/ya/r/O2aKM2iSbOw.png","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/wv/images/alphatar_100x100_D_mr.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/index_banner/20170309wsyhxxjbzq_260x90.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=1316150204,834621492&fm=173&app=25&f=JPEG?w=218&h=146&s=62E0DC4B5B2323200C5504BC0300C042","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/380000/380385/220x165/6.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_922,h_614/os/news/ed32a76b9a59b8272a7186b0ecc47c9e.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img16/app/AppyHours/GW/Revised/1242x450_GW_02._SX414_CB500224812_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/91-lXBqc19L._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://rtax.criteo.com/delivery/rta/rta.js?netId=4606&cookieName=crtg_rta&rnd=43906048184&varName=crtg_content","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/safeframe/1-0-23/js/ext.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/listing/tool/yads/yads-stream-lib.js?3","request_type":"script"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.twitch.tv/","request_url":"https://www.twitch.tv/favicon.ico","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://b.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://m.media-amazon.com/images/G/01/csm/showads.v2.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NFL_DEZ_BRYANT_POTENTIAL_TEA/dm_180414_NFL_DEZ_BRYANT_POTENTIAL_TEA.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://facebook.com/security/hsts-pixel.gif?c=3.2","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-10673494-4&cid=1768394412.1523791839&jid=718787279&_gid=1457613602.1523791839&gjid=2016562638&_v=j66&z=1395298182","request_type":"html"}
+{"origin":"http://www.uptodown.com/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=4101564090667940&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fif&adsid=NT&eid=21061149%2C21061569&sc=0&sfv=1-0-23&iu=%2F1060150%2FLeaderboard_noadsense&sz=320x100%7C320x50&eri=1&cookie_enabled=1&abxe=1&lmt=1523791958&dt=1523791958682&frm=20&biw=360&bih=512&oid=3&adx=20&ady=330&adk=1062120734&gut=v2&ifi=1&u_tz=-420&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fen.uptodown.com%2F&ref=http%3A%2F%2Fwww.uptodown.com%2F&dssz=12&icsg=34&std=0&vrg=194&vis=1&scr_x=0&scr_y=0&psz=360x430&ga_vid=1005470225.1523791954&ga_sid=1523791959&ga_hid=129765439","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhmYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oEN5w4-mkKDzRtDyYVK9PjdMwfPoA","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"https://ext.baidu.com/rest/id-mapping/cuid?callback=_box_jsonp951","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/bundles/fave/theoplayer-798d8523/theoplayer","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.advertising.com/ups/28/sync?uid=86070857378125119120981354726841823876&_origin=1&redir=true&verify=true","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://dpm.demdex.net/ibs:dpid=139200&dpuuid=11vajjGjRK6qvB6r1y476A&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/mtop/5.6.0/styles/top.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?p_user_id=TuAeGoH2Tk-ooTaFluPLUw&ex=twca&id=TuAeGoH2Tk-ooTaFluPLUw","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=9c7a5d0a-239a-caef-250d-55d18ec94bb8","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ib.adnxs.com/getuid?https://beacon.krxd.net/usermatch.gif?adnxs_uid=$UID","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/msn-msn-home/log/3/visible","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://static.exosrv.com/library/209812/5feca57dd8f9957542093cbe42d0be729a79592c.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/clash-royale-android.png:l","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1x1","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/static/index/plus/public/icon_police.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/musicmusic105/albumset/16083158/zoomcrop/75x75.jpg?v=1523786035","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/Ez2JNPaTvHBmThI-ACqiyu5UesCLVrPSCUYsV5e5hSsz1xr3W5rQZy4jaI-mAMQ=w512","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-87b47eafbb2/v3/img/skins/xnxx/top-stripe.png","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/marketing/prime/dex/trafficdrivers/VXD-1095_GWMobileHero_1242x450_copy2._SX1242_CB508068870_.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f16/6dcf33f268d7cce3c6528ed6fdea5023_erotic_285x160.jpg?cno=14c","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f10/0ccd709f49f5a7092e9f2f0f8a07576b_erotic_445x250.jpg?cno=2322","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420350148844498.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://di.phncdn.com/videos/201405/14/26784931/original/(m=eafTGgaaaa)(mh=iyPis9FbQoPrqggA)12.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/lo/api/res/1.2/oI7VDUqMRWd2E4LUHXMcVA--/YXBwaWQ9eW15O3c9NjA-/https://ct.yimg.com/cy/4578/27240188179_caede4_192sq.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/v7oi6IqEK_gm8LjSPfXLgQ--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/homerun/the_huffington_post_584/5a22ef22d8d841f9383f4aeb6b639a65","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/kYHSCSSQnWyaa_rGFcLgabGiPx5Bu9tyOTaomHh1Qbk.jpg","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1Fq0QQFXXXXbOaXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/pornq.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-external.min-vflFw5u9L.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-mma.png&h=120&w=120&cquality=40","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/411MtgykU8L.css?AUIClients/GWMWebAssets","request_type":"css"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static.dditscdn.com/arms-datacollectorjs/arms-uslax-1.2.0.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/connect/ping?client_id=274266067164&domain=www.pinterest.com&origin=2&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FFdM1l_dpErI.js%3Fversion%3D42%23cb%3Df36c13f144a70c4%26domain%3Dwww.pinterest.com%26origin%3Dhttps%253A%252F%252Fwww.pinterest.com%252Ff5838e3059c2d8%26relation%3Dparent&response_type=token%2Csigned_request%2Ccode&sdk=joey","request_type":"html"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/gen_204?s=webaft&atyp=csi&ei=DjjTWvfeGYaB8AOat73oBA&rt=wsrt.2189,aft.408,prt.208","request_type":"html"}
+{"origin":"http://www.twitter.com/","request_url":"https://mobile.twitter.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/abg.js","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhmYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oECqDXRLDxGo5mVocVLAUHyi7MkOg","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.onclkds.com/","request_url":"https://www.google.com/recaptcha/api.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/reload?k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/2.75.8/js/cnn-header-second.min.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://b.scorecardresearch.com/b2?c1=2&c2=6177433&comscorekw=movies&ns__t=1523791980447&ns_c=UTF-8&cv=3.1m&c8=FANDOM&c7=http%3A%2F%2Fwww.wikia.com%2Ffandom&c9=","request_type":"other"}
+{"origin":"http://www.360.cn/","request_url":"http://p6.qhmsg.com/t01f8ae6ea3d7f727ff.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=https://beacon.krxd.net/data.gif?_kuid%3DL6N62llA%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive/check?partner_id=ADB&partner_url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=rubicon&partner_uid=JG0QC2PD-14-82AL","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/common.css?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"css"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/ffe/siteui/fonts/nf-icon-v1-93.woff","request_type":"font"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=mplatform.com&id=11458564830873942922","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.facebook.com/tr/?id=1559459634097838&ev=PageView&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1523791870655&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=30&it=1523791867576","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.facebook.com/tr/?id=1944925959056690&ev=PageView&dl=https%3A%2F%2Fwww.adobe.com%2F&rl=&if=false&ts=1523792016274&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=30&it=1523792015787","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://us-u.openx.net/w/1.0/sd?cc=1&id=537148856&val=WtM4gQAABibm4O17","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:146-2652873-2143838:6983MGHS2ZBMHXB1G0WS$uedata=s:%2Fuedata%3Fld%26v%3D0.200481.0%26id%3D6983MGHS2ZBMHXB1G0WS%26ctb%3D1%26sc0%3DAdbDisabled%26bb0%3D18441%26be0%3D18441%26pc0%3D18441%26ld0%3D18441%26t0%3D1523791944128%26tid%3D6983MGHS2ZBMHXB1G0WS%26aftb%3D1:18441","request_type":"image"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://pixel.quantserve.com/pixel;r=1753303338;rf=0;a=p-c1rF4kxgLUzNc;url=https%3A%2F%2Fstackoverflow.com%2F;fpan=1;fpa=P0-1760485276-1523791909993;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1523791909991;tzo=420;ogl=","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_mil-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_tech-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://hm.baidu.com/hm.gif?si=c42dc7b5fa22eba9c22b2ca4d8829372&et=0&v=pixel-1.0&u=https%3A%2F%2Fm.baidu.com%2Fexp%2Ffailed%3Fv%3D1.0.4&rnd=1417146646","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=540&dpuuid=b60eac03-40a0-11e8-b967-024257f42601","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/user-lists/949424158/?random=1523791866946&cv=9&fst=1523790000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=3952787813&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/messenger-lite-android.png:l","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/11.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/logo/logo-2.0.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://pingtas.qq.com/webview/pingd?dm=xw.qq.com&pvi=230541523791919458&si=s921541523791919463&url=/index.htm&arg=&ty=1&rdm=www.qq.com&rurl=/&rarg=&adt=&r2=500092411&scr=360x512&scl=24-bit&lg=en-us&tz=7&ext=version=2.0.6&random=1523791919485","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://sync.1rx.io/usersync2/rmpssp?sub=amazon&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%5BRX_UUID%5D%26ex%3Drhythmone.com","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=7bc4f310-40a0-11e8-8fa8-0242e5e63087%252C","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://fonts.gstatic.com/s/notosans/v7/o-0TIpQlx3QUlC5A4PNr4Az5ZuyDzW1IPrie.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/04/15/1523786059_20180415-00000042-jnn-000-thumb-x104-y104.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/transform/310/w710h400/20180415/vQCe-fzcyxmu8741717.jpg/w710h400z1l50t17d6.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/5e75bac5-2953-48eb-a5f1-1e3d3fc3669b_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/7ea085f4-566b-4ee0-b6af-7040d5cf88e8_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/home.logged-out/page-domain-only/img/blog-scene-2x.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/161031151042-clinton-comey-composite-1031-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=4097884528,3703051542&fm=173&app=25&f=JPEG?w=218&h=146&s=C8A408D68E1254D4470792B00300D00D","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/3NeYOlz8NsJO423ons5MIIRcq0lzKeFfi5ZUIsx1rsQ.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s220x220_1724/b57c26ce-b36f-47ec-92df-516faaa96209.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/google-logo-color-vflpJqkMT.svg","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://tags.bkrtx.com/js/bk-coretag.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://rtax.criteo.com/delivery/rta/rta.js?netId=4606&cookieName=crtg_rta&rnd=8540539865&varName=crtg_content","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/api/articles?type=new&category=home&shown_offset=1523791926859909&first_view=true","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://sp.auth.adobe.com/entitlement/js/AccessEnablerProxy.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-ads_story/td-applet-viewer-templates-ads_story-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-tilesad-model/td-tilesad-model-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/??mui/feloader/4.0.17/feloader-min.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/csm/showads.v2.js","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://adservice.google.com/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/gp/overlay/display.html","request_type":"html"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.facebook.com/connect/ping?client_id=124024574287414&domain=www.instagram.com&origin=2&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FFdM1l_dpErI.js%3Fversion%3D42%23cb%3Df2e95269ff75e2c%26domain%3Dwww.instagram.com%26origin%3Dhttps%253A%252F%252Fwww.instagram.com%252Ff6055d2410195%26relation%3Dparent&response_type=token%2Csigned_request%2Ccode&sdk=joey","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixel.everesttech.net/1/m?url=https%3A%2F%2Fcm.g.doubleclick.net%2Fpixel%3Fgoogle_nid%3Deverest%26google_hm%3D__EFGSURFER_USB64__%26google_push%3DAHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6&google_gid=CAESEA295koRah9ULpl8fsHxbhQ&google_cver=1","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/msn-msn-home/trc/3/json?tim=04%3A30%3A41.586&data=%7B%22id%22%3A18%2C%22ii%22%3A%22_homepage_%22%2C%22it%22%3A%22home%22%2C%22sd%22%3Anull%2C%22ui%22%3Anull%2C%22uifp%22%3Anull%2C%22vi%22%3A1523791841477%2C%22cv%22%3A%22301-1-RELEASE%22%2C%22uiv%22%3A%22default%22%2C%22u%22%3A%22https%3A%2F%2Fwww.msn.com%2F%22%2C%22did%22%3A%2239041E2B94ED6EF00CB315F995BE6F73%22%2C%22extpvid%22%3A%22e86f55f780704d568af4af783e3cb6c4%22%2C%22bv%22%3A%220%22%2C%22ul%22%3A%5B%22en-US%22%2C%22en%22%5D%2C%22btv%22%3A%220%22%2C%22bad%22%3A-1%2C%22bw%22%3A360%2C%22sw%22%3A360%2C%22sh%22%3A512%2C%22nsid%22%3A%22msn-home-network%22%2C%22r%22%3A%5B%7B%22li%22%3A%22rbox-h2m%22%2C%22s%22%3A4%2C%22uim%22%3A%22thumbnails-2x1%3Apub%3Dmsn-home-network%3Aabp%3D0%22%2C%22uip%22%3A%22Mid%20Infopane%20Thumbnails%20-%20Mobile%22%2C%22orig_uip%22%3A%22Mid%20Infopane%20Thumbnails%22%2C%22cd%22%3A262%2C%22mw%22%3A622%7D%2C%7B%22li%22%3A%22rbox-h2m%22%2C%22s%22%3A4%2C%22uim%22%3A%22thumbnails-2x1%3Apub%3Dmsn-home-network%3Aabp%3D0%22%2C%22uip%22%3A%22Mid%20Infopane%20Thumbnails%202nd%20-%20Mobile%22%2C%22orig_uip%22%3A%22Mid%20Infopane%20Thumbnails%202nd%22%2C%22cd%22%3A262%2C%22mw%22%3A320%7D%5D%2C%22cb%22%3A%22TRC.callbacks.recommendations_1%22%2C%22lt%22%3A%22normal%22%7D","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/11Muzrhwo6L._RC%7C41vNkR6eYDL.js,31XuHZCLcRL.js,11tPmvtDkXL.js,317hoZTRAgL.js,211oGttD+KL.js,31E+vLBB9PL.js,51Y-Tl+t96L.js,51nC-xYS8UL.js,21LeqsQWezL.js,31b+kJCBfzL.js,016DBHJkIYL.js,216ts510QRL.js,51sbZjM5VyL.js,21CxAwGolOL.js,611H10HEcuL.js,71JrGoJvISL.js,21isZW0aOgL.js,01hSssM6EML.js,216nH77ENDL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,11QIUl6VLbL.js,21jBAndZe0L.js,518h2Um1TpL.js,01tPYxCI2PL.js,01nKqcvaCIL.js,11f58pNTm7L.js,51B2QjAoAwL.js,01X5C8pWB1L.js,51tAEm6Zv9L.js,117xk5an6TL.js,21kjCAUM3nL.js,31egXBuM55L.js,01RHiyjONOL.js,31zYeTS++kL.js,21CrGn+akTL.js,51Vc417aBzL.js,31zob0zDCQL.js,11eSkH3Id-L.js,31c7RNhMLrL.js,01q0JZaOPlL.js,116kAgu6ebL.js,31ze7I-RWjL.js,21q3UdjiveL.js,21HlHGr1+aL.js,0193uyIciNL.js,01DShqNIDKL.js,51NhK1niNZL.js,71EZekNvMRL.js,01dIViFgwyL.js,01-Sz0ff1pL.js,21mtabjvdBL.js,315ZZQLne4L.js,21e16+5SkdL.js,11NHZnHlFmL.js,21CbPMxfA+L.js,015J4NGaO3L.js,11B4fwZPeqL.js,214q28gHRFL.js,113JOW7LkIL.js,01jqyAujTwL.js,01KcbtwkAOL.js,01-XJ1YSEXL.js,11+FwDesCML.js,01NAT+3p7KL.js,111vgqp2a0L.js,51TykIhlflL.js,01MZJG6lH8L.js,01VtYReatCL.js,21GM7TuvFKL.js,01mL-cPJ2YL.js,01RQtSMdG+L.js,11dIR51go1L.js,01UZjPg57RL.js,01l3c7okxRL.js,01c01jT1vpL.js,01qwoVEkKlL.js,011HXD1ky3L.js,011X+p22ALL.js,01k57x9vvBL.js,01rjsjeoEcL.js,01ZF+ovNflL.js,31JPVjZ0jGL.js,01S8y9NkxoL.js,415YJI4xh3L.js,21Mbb7ICCJL.js,01tJd4+VUOL.js,01MEbpLZWbL.js,51-wBjbbYrL.js,410QCZl6RQL.js,01RxP6MLBbL.js,01rg6Ce9FhL.js,01c1fUAHkJL.js_.js?AUIClients/DetailPageMobileWebMetaAsset","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81pPtFtJAnL.js?AUIClients/GoldboxUDPAssets","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://x.bidswitch.net/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/h0r58thg?redir=https%3A%2F%2Fsync.search.spotxchange.com%2Fpartner%3Fadv_id%3D6409%26uid%3D%24%7BUSER_ID%7D%26img%3D1","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://usermatch.krxd.net/um/v2?partner=vdna","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/components/button-vfl-_t7Pp.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/stencil/3.2.1/styles-ltr.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=30&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A30%7D&logFlag=uaction_1523791857874&t=1523791887876","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/terrarium-tv-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/peihsuan0729/albumset/16170704/zoomcrop/75x75.jpg?v=1523785959","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p7.qhmsg.com/t0192c6a682125e6cc9.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420346351066633.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns.gigya.com/gs/i/shareBar/button/mobile/buttonCenterImgUp.png","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/cce129d6-395c-4624-b4bf-dc987e710353_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Talk%20Shows-429x572.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-bg-ec-4pod-shoe-mobile-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/150611164327-cnnmoneyeggs-small-169.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spcdnsp.i-mobile.co.jp/ad_creative.ashx?advid=4623604&eid=14","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/categories.svg","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://uranus.jd.com/log/m?std=MO-J2011-1","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-bold.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-italic.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-cards/td-applet-viewer-templates-cards-min.js","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/js/mobile/b0ba10cc.xpops.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/index.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/login/sp/js/login_promo/1.1.8/login_promo-min.js","request_type":"script"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-585a5bfc64746d4e3d000cda.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/photo/2018/0410/r354555_1296x729_16-9.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsv-oe_6PMCmHGeP5wPWEuedIGJQLAYNp21qBZ_MZmEGC0uEMLkPj1Km7JFc4nIstbOSrfM7PevT5UWAjp5b41rETIfq7kRdbVWlWXqKDbf0PRhA_rurYw12GIL0H7847hCDUGM6bDN4Xm_gyi1QQcG3aMedAqzSs8i0-7ls6bB_MkMAyASuVAPmCOs0eZaKN8eQ0ycw1QDNWk0LUaVz0mEIUr9v56cTINVPWQVstrvcV-HXNv9qcA&sig=Cg0ArKJSzH1D5MKAdrEvEAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.netflix.com/","request_url":"https://4954221.fls.doubleclick.net/activityi;src=4954221;type=gl-nmh;cat=dcmgl0;u1=US;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=2789806431025.7275","request_type":"html"}
+{"origin":"http://www.qq.com/","request_url":"https://wis.qq.com/weather/common?weather_type=observe%7Cforecast_24h%7Cair%7Calarm&source=xw&province=%E5%8C%97%E4%BA%AC%E5%B8%82&city=%E5%8C%97%E4%BA%AC%E5%B8%82&callback=__jp0","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.pa4EfGZJtyM.O/m=client,plusone/rt=j/sv=1/d=1/ed=1/am=AQE/rs=AGLTcCNvuMxw8LpLrCWFeoIaET1OMP8dSQ/cb=gapi.loaded_0","request_type":"script"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/id/rd?d_visid_ver=2.5.0&d_fieldgroup=MC&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=9E1005A551ED61CA0A490D45%40AdobeOrg&d_nsid=0&ts=1523791992949","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/11Muzrhwo6L._RC%7C41vNkR6eYDL.js,31XuHZCLcRL.js,11tPmvtDkXL.js,317hoZTRAgL.js,211oGttD+KL.js,31E+vLBB9PL.js,51IRmSi4SAL.js,51nC-xYS8UL.js,21LeqsQWezL.js,31swJcQcmUL.js,016DBHJkIYL.js,216ts510QRL.js,51sbZjM5VyL.js,21CxAwGolOL.js,611H10HEcuL.js,71JrGoJvISL.js,21isZW0aOgL.js,01hSssM6EML.js,216nH77ENDL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,01CANZ8BqcL.js,21AuBaN+lVL.js,518h2Um1TpL.js,01tPYxCI2PL.js,01nKqcvaCIL.js,11f58pNTm7L.js,41Zib1oMoZL.js,01X5C8pWB1L.js,51tAEm6Zv9L.js,117xk5an6TL.js,21kjCAUM3nL.js,31egXBuM55L.js,01RHiyjONOL.js,31zYeTS++kL.js,21CrGn+akTL.js,51QrDHXq9ML.js,31zob0zDCQL.js,11eSkH3Id-L.js,21q5QmCNgJL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,01DShqNIDKL.js,51rCZ2WOe0L.js,71z9MYB3x9L.js,01dIViFgwyL.js,319kjuuQkzL.js,21mtabjvdBL.js,315ZZQLne4L.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,015J4NGaO3L.js,11B4fwZPeqL.js,214q28gHRFL.js,113JOW7LkIL.js,01jqyAujTwL.js,01jW+SjLRsL.js,01-XJ1YSEXL.js,11+FwDesCML.js,01NAT+3p7KL.js,111vgqp2a0L.js,51vGIS0VrtL.js,01MZJG6lH8L.js,01VtYReatCL.js,21vc9PfFLNL.js,01mL-cPJ2YL.js,01RQtSMdG+L.js,11ZcUC5H2zL.js,01UZjPg57RL.js,01l3c7okxRL.js,317HgF3eZLL.js,01qwoVEkKlL.js,011HXD1ky3L.js,011X+p22ALL.js,01k57x9vvBL.js,01rjsjeoEcL.js,01ZF+ovNflL.js,31JPVjZ0jGL.js,01S8y9NkxoL.js,019ztXtdUIL.js,11PT3daaHLL.js,01tJd4+VUOL.js,01MEbpLZWbL.js,51tlWANRbLL.js,01y-5aCXJyL.js,01rg6Ce9FhL.js,01c1fUAHkJL.js_.js?AUIClients/DetailPageMobileWebMetaAsset","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://cloudfront-labs.amazonaws.com/x.png","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=178b1244bea79c837529d598f65b58c31ea5a458&ex=aoldisplay.com","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=68&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A68%7D&logFlag=uaction_1523791857874&t=1523791925876","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://dc.ads.linkedin.com/collect/?pid=6883&fmt=gif&opid=7850&cookiesTest=true","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=1507848430&t=pageview&_s=1&dl=http%3A%2F%2Fdiply.com%2F&ul=en-us&de=UTF-8&dt=Diply&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=6GDAgEADQ~&jid=1581826687&gjid=1297575630&cid=541858476.1523791959&tid=UA-44184928-2&_gid=47841196.1523791959&gtm=G465XJBR3B&cd2=&cd8=0&cd14=4%3A32%3A40%3A408am&cd15=N%2FA&cd25=2000&cd27=SANFRANCISCO&cd28=CA&cd36=US&cd38=&cd40=3g&cd41=&cd44=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&cd45=http&cd13=541858476.1523791959&z=1014213023","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/coccoc-logo.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/kupohada/albumset/15888877/zoomcrop/75x75.jpg?v=1329994647","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_arabic.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/26eaRZ7AqYQFf7Zt3gBgwxiigJEz-1K4mcrIOb0bA4YjFbDnLQvMVt5VSQ7-=w384","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/weather80.png","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/310/w710h400/20180415/boKH-fzcyxmu7468912.jpg/w710h400z1l50t160c.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvTbaH.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=1458&y=1832","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/cnnic.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/019/04b/230/big_lq/37cfe5c214ada5f2f6b108b5e2c6b630.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/91V89Qmb5YL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61qvJZUsv3L._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/81OujN1auRL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61nrWDGVoOL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=866926771736&photoType=4","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/bg/YRKqPoIt_ONlxH2tUGnouQ_G4hFZfGHYM-YHumdPwHE.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://uranus.jd.com/log/m?std=MO-J2011-1","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-login-pages-externals.min-vfly3Q9OJ.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn-gl.imrworldwide.com/conf/P07264C85-15CD-4A80-8E56-B5BFA6D93296.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://scripts.demandbase.com/qQQxkRp0.min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy//nn/lib/metro/g/myy/video_manager_0.0.180.js","request_type":"script"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://usync.aws.rubiconproject.com/yahoo-brx","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://www.youtube.com/","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://www.msn.com/en-us/homepage/secure/silentpassport?secure=true&lc=1033","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage4.pubmatic.com/AdServer/SPug?partnerID=156736","request_type":"text"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://m.weibo.cn/openapi/sina/hotweibov8?callback=jsonp_08418992589214673&timestamp=1523791845326&&nopic=0&page=0&vid=9533882159274.413.1523791820192","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ssp-bidapi-n2.i-mobile.co.jp/jsonp/ssp_spot.ashx?pid=6107&asid=155353&asn=1&spec=1&dpr=3&sf=0&pos=0&imcallback=_imcallback_155353_1&cashid=1523791962685","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://statics-uhf-wus.akamaized.net/shell/_scrf/js/themes=default/6e-f7b37a/2b-23ae8a/28-a48c12/44-96d0e7/4e-78174a/9b-3a511e/48-4e5f26/52-5f76e8/14-443e69/43-fcbff1/7c-62f5d4/25-ec5b00/4f-70c548/d8-49942a/cc-64fcca/d8-303d3d/e9-b2e965/6d-14f2cc/7e-b39d59/5b-6cc700/de-ec2ad7/d2-77cd10/94-296ca0/e1-99fadf/dd-e76fb4/e7-9435a7/3d-5b16c7/8c-87074e/2a-84a817/2a-5e0a0a/d5-58230c/87-324cc8?ver=2.0&iife=1","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/11Muzrhwo6L._RC%7C41vNkR6eYDL.js,31XuHZCLcRL.js,11tPmvtDkXL.js,317hoZTRAgL.js,211oGttD+KL.js,31E+vLBB9PL.js,51Y-Tl+t96L.js,51nC-xYS8UL.js,21LeqsQWezL.js,31swJcQcmUL.js,016DBHJkIYL.js,216ts510QRL.js,51sbZjM5VyL.js,21CxAwGolOL.js,611H10HEcuL.js,71JrGoJvISL.js,21isZW0aOgL.js,01hSssM6EML.js,216nH77ENDL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,11QIUl6VLbL.js,21AuBaN+lVL.js,518h2Um1TpL.js,01tPYxCI2PL.js,01nKqcvaCIL.js,11f58pNTm7L.js,41n+LBe+hcL.js,01X5C8pWB1L.js,51tAEm6Zv9L.js,117xk5an6TL.js,21kjCAUM3nL.js,31egXBuM55L.js,01RHiyjONOL.js,31zYeTS++kL.js,21CrGn+akTL.js,51zsmGWyrFL.js,31zob0zDCQL.js,11eSkH3Id-L.js,21q5QmCNgJL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,01DShqNIDKL.js,51tR9VCi49L.js,71z9MYB3x9L.js,01dIViFgwyL.js,319kjuuQkzL.js,21mtabjvdBL.js,315ZZQLne4L.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,015J4NGaO3L.js,11B4fwZPeqL.js,214q28gHRFL.js,113JOW7LkIL.js,01jqyAujTwL.js,01jW+SjLRsL.js,01-XJ1YSEXL.js,11+FwDesCML.js,01NAT+3p7KL.js,01VbOIsFDdL.js,51vGIS0VrtL.js,01MZJG6lH8L.js,01VtYReatCL.js,21vc9PfFLNL.js,01mL-cPJ2YL.js,01RQtSMdG+L.js,11ZcUC5H2zL.js,01UZjPg57RL.js,01l3c7okxRL.js,31INbU+x5ML.js,01qwoVEkKlL.js,011HXD1ky3L.js,011X+p22ALL.js,01k57x9vvBL.js,01rjsjeoEcL.js,01ZF+ovNflL.js,31JPVjZ0jGL.js,01S8y9NkxoL.js,019ztXtdUIL.js,11PT3daaHLL.js,01tJd4+VUOL.js,01MEbpLZWbL.js,51tlWANRbLL.js,01y-5aCXJyL.js,01rg6Ce9FhL.js,01c1fUAHkJL.js_.js?AUIClients/DetailPageMobileWebMetaAsset","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://www.linkedin.com/csp/dtag?_x=%2526fmt%253Dgif%2526opid%253D7850%2526cookiesTest%253Dtrue&p=9","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/css/main-8b723dfa1b.css","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://us-u.openx.net/w/1.0/cm?id=19b05a3b-50b2-33ac-c6e0-9f21c5fbd143&r=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D4%26cm%3D","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://wgo.mmstat.com/sb.sbp.action?cache=4bc926a&gmkey=EXP&gokey=platform%3DAndroid%26smbSid%3DRiZaE%252BYPjyICAZUUPw3CLc3s_1523791946369%26apuri%3Dsb_init%26source%3Dsb%26sceneType%3Ddefault%26page%3DmainIndex%26rbbt%3Dbc.mainIndex.6.0.0%26appkey%3D24585258%26logtype%3D2&cna=RiZaE%2BYPjyICAZUUPw3CLc3s&spm-cnt=a215s.7406091.0.0&logtype=2","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://choices.trustarc.com/cap?aid=audible01&pid=spark01&cid=20961954_92161433_218069769&w=1&h=1&c=c97a","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/sword-art-online-integral-factor-android.png:l","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t5647/156/156583179/12255/981e942a/591d94a1Nfde63a47.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA9UODq.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=rp&google_hm=SkcwUUZCOVUtVC1JVTJZ&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://cpro.baidustatic.com/sync.htm?cproid=BA10B0AD56941711EBB64A90E732B742%3AFG%3D1","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791943673_6267415160377&itemspaceid=13730&adps=30000001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&suv=180415193221Z74L&appid=wapnews&_time_=1523791943673","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://rebrand.dropboxstatic.com/videos/homepage_paper_ui.mp4","request_type":"video"}
+{"origin":"http://www.msn.com/","request_url":"https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/f1c7f0a9a7d7397a7372dc5f33f66be0.png","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/feed/20180412/2ab0bf8e2e7c99e6996aa6559f22dd25.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/4ca33269-814a-406a-8c62-08b83f1f85a9/scale-to-height-down/82","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/sa/simg/bing_p_rr_teal_min.ico","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/hdzog.svg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/recaptcha__en.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/fonts/roboto-100.woff","request_type":"font"}
+{"origin":"http://www.pornhub.com/","request_url":"https://cdn1d-static-shared.phncdn.com/jquery-ui-1.10.3.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/wap/impress?23=Y2FsbGJhY2s9c2F4X2pzb25wQ2FsbGJhY2tfNCZhZHVuaXRfaWQ9UERQUzAwMDAwMDA1Nzc5MyxQRFBTMDAwMDAwMDQwNTE5LEEyNUQyNTlCMDhFNixQRFBTMDAwMDAwMDQ5NjI5LFBEUFMwMDAwMDAwNTQ2NzEsUERQUzAwMDAwMDA1NTYyMixQRFBTMDAwMDAwMDU0NjcyLEU5RDZBQzRGMzQ4RSZwYWdlX3VybD1odHRwcyUzQSUyRiUyRnNpbmEuY24lMkYlM0Zmcm9tJTNEd2ViJnR3aWNlPTEmdGltZXN0YW1wPTE1MjM3OTE4NTQxMzkmcm90YXRlX2NvdW50PTY1OSZhbT0lN0IlMjJkcyUyMiUzQSUyMjM2MCo1MTIlMjIlMkMlMjJvdiUyMiUzQSUyMmFuZHJvaWQlMjIlN0QmbmV0PW51bGw=","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"https://m.baidu.com/se/static/js/dep/ralltiir.min_1a3d103.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/vue_fbd12c9.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://id.rlcdn.com/464526.gif?redirect=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fexpires%3D30%26nid%3D2181%26put%3D__EFGSURFER__.__EFGCK__%26v%3D11782","request_type":"html"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-be7afd80869374e8f9fd0c31859f748aaefbe2fd._V2_.js","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://www.github.com/","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://usync.nexage.com/mapuser?providerid=29472&userid=D34DC539-63A7-4F27-8DFD-50E0EE1E218A","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/components/password_strength_meter-vflAqZDga.css","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://loadm.exelator.com/load/?p=204&g=1270&j=0&BUID=39041E2B94ED6EF00CB315F995BE6F73&xl8blockcheck=1","request_type":"image"}
+{"origin":"http://www.office.com/","request_url":"https://c1.microsoft.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=E5D96D49D2F0452CB6D06DC876AE25B2&MUID=14317DD20D9E63291C1D7600099E65CF","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/uedata/nvp/unsticky/144-4203505-1964949/NoPageType/ntpoffrw?at&v=0.200436.0&id=XZ4D3PPDB36HTEGXD7ZH&ctb=1&m=1&sc=XZ4D3PPDB36HTEGXD7ZH&pc=11528&at=11528&t=1523791922072&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile-unrec&tid=XZ4D3PPDB36HTEGXD7ZH&aftb=1","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQVRKZSEBR7BT5RF15TNH%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D9353%26cf0%3D9365%26pc0%3D9365%26ld0%3D9365%26t0%3D1523791975053%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQVRKZSEBR7BT5RF15TNH%26aftb%3D1:9365","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/956747825/?userId=uhco9tXJQEKHOlrv_6JpJQ&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-35860610-14&cid=1265310549.1523791856&jid=1172235258&_v=j66&z=1214592548","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://tags.bluekai.com/site/2981?id=&google_gid=CAESEGAW2dUYdN8o5cgquSk_cYQ&google_cver=1","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/images/mobile/auth_social_networks_2x.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/mobile/hd/blog_button.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/1421000/1421215/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/screen/13/wilderness-action-001.jpg:l","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/09ed4bdd-de29-4feb-b187-7d77165545a8_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://f12.baidu.com/it/u=3927711776,3925256482&fm=76","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/6d/2e/1e/6d2e1e8df5cd01dbfe84e77da5f8fc1a/6d2e1e8df5cd01dbfe84e77da5f8fc1a.10.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjAxODIzMjY3N15BMl5BanBnXkFtZTgwMzM5ODcwNTM@._CR166,31,1350,1350_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/713rQq1bF6L._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/n1/s124x124_jfs/t16246/242/382340436/205032/a7ea71f5/5a308435N6c4ebe3a.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/favicon.ico","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://aglobal.go.com/stat/cto-espn.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/register/name_fields.min-vfllXzodL.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-cyfd.min-vflB0QpHs.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-carousel/td-applet-viewer-templates-carousel-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/container.xtpl.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cms.analytics.yahoo.com/cms?partner_id=ADOBE","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://mc.yandex.ru/metrika/watch.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ads/advertising/ads._TTH_.js?cachebust=30302412","request_type":"script"}
+{"origin":"http://www.google.ru/","request_url":"https://adservice.google.ru/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://suggest.taobao.com/sug?area=tmall-hq&code=utf-8&src=mallfp..m&callback=jsonp_23456487","request_type":"html"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://m.livejasmin.com/en/list/","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://ads.yahoo.com/cms/v1?esig=1~6772d6d12bf5fd5c41ee5ef107d84db09124942a&nwid=10000936839&sigv=1","request_type":"text"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/v1/article/search/latest?pageSize=100","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/316nxKpnxGL._RC%7C51faQ1uINoL.js_.js?AUIClients/SharedShoppingCartMobileAsset","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://token.rubiconproject.com/token?pid=25470","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://trc.taboola.com/sg/amazon-a9-network/1/rtb","request_type":"other"}
+{"origin":"http://www.qq.com/","request_url":"https://trace.qq.com/collect?pj=1990&dm=www.xw.qq.com&url=/index.htm&arg=&rdm=www.qq.com&rurl=/&rarg=&icache=&uv=&nu=&ol=&loc=https%3A//xw.qq.com/index.htm&column=&subject=&nrnd=F9480881850&rnd=6748","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a67349c00005ad338814cf070f2d9fb&pid=mm_113716014_12970037_52768244&cid=258981&mid=244850&oid=376&productType=1&qytInfoMTime=1523728962&e=qq1nP4cbQsCMpq0A4M5XOxu%2BuDuQwZjv9QpmcsdCDulx6QaAhZafL88iZX5yYzDJ&k=65&cb=86342026","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/986255830/?value=0&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/img/flags.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/E3/9201AF.png","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/images/vmobile/main-sprite.png?cache=2018041212","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/dotted.png","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://twitch.tv/favicon.ico","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"http://www.pixnet.net/","request_type":"html"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201204/11/5030885/original/(m=eafTGgaaaa)(mh=1WQDKb_rkF6Wp8XM)6.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://timgmb03.bdimg.com/timg?searchbox_feed&quality=120&wh_rate=0&size=f648_364&ref=http%3A%2F%2Fwww.baidu.com&sec=0&di=59c76264db97821f11e5131e2e9d9ab9&src=http%3A%2F%2Ft12.baidu.com%2Fit%2Fu%3D2249309492%2C289114700%26fm%3D175%26app%3D25%26f%3DJPEG%3Fw%3D599%26h%3D337%26s%3DD9343FD076234AB82A25745F03008060","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://d2x3bkdslnxkuj.cloudfront.net/2686929_300.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180408/c03fd5535e9c1c33cded49.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/32b3500d5e7e61a1cf1fea5896a58558_erotic_445x250.jpg?cno=fb8","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjQyODcwODc0MF5BMl5BanBnXkFtZTgwODkxODIwNTM@._CR782,258,1016,761_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/619HSmLwTsL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51YZ6fP5wpL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://m.aliexpress.com/img/logo/favicon.ico","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/reskin/js/src/components/analytics.min.js?v=NbdkoZriHcMo2MSOk02Lkof9MISV768q0EXlGASAg7A","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/assets/compat-413dd2a0695c3dfaf7de158468a91646.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://static.inter1ads.com/templates/inapp/Custom/_gen-square-teasers-feed-new-layouts/js/script.js?v=1523281953440","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb2.qujishu.com/fnbexvb?byc=yxx&qcx=03x&xc=r0yz6y1z&fno=eqqmZ07ZzCZzCjZXvlrqeZX.kZzC&jm=5y0uyx&njl=y2z1y566y1434&xw=0&xcm=x&wyw=RQCY5&yrjm=yy3x05&xuc=y&jmm=03xuy323&jwm=03xu2yz&jul=03xu2yz&uhn=y&xlc=x&xng=EQJIXMLPQ&jcm=YyuYy&ulc=z&n5=0hdbf&08=9cuoc&59=g0qau&610=sjqwo&swt=1","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/eboxapps/js/e1/09a40607a48122a2661ef9cdff54c614ca32f6.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://inter1ads.com/?l=7imyMRmWBVyGapH&language=en&z=1617677&b=1858666&g=US&p=4&h=2018041506&target_url=https%3A%2F%2Fmobpushup.com%2Fck.php%3Fzoneid%3D1617677%26oaparams%3D2__bannerid%3D1858666__zoneid%3D1617677__OXLCA%3D1__cb%3De3fceae0f4__oadest%3D","request_type":"html"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/gen_204?s=webaft&atyp=csi&ei=xjfTWv2tGevT0gLU_p24CQ&rt=wsrt.2208,aft.446,prt.243","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/t_tkr/errlog?col=0&filename=&line=0&x=0&y=0&stime=1523791868616&etime=1523791868618&p=764344014241209959&page_url=https%3A%2F%2Fwww.cnn.com%2F&w=360&h=512&e=0&wh=SDKRE&location=https%3A%2F%2Fwww.cnn.com%2F&desc=Script%20error.&v=9.4.10-b-301","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-base/anim-base-min.js","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://platform.twitter.com/widgets.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/518e5yqTyZL.js?AUIClients/RetailSearchAutocompleteAssets","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212237748&puid=39041E2B94ED6EF00CB315F995BE6F73","request_type":"other"}
+{"origin":"http://www.savefrom.net/","request_url":"https://static.inter1ads.com/templates/inapp/Custom/_gen-square-teasers-feed-new-layouts/css/tiles/default.css?v=2","request_type":"css"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://www.qchannel03.cn/1.gif?domain=sina.cn&account=SinaNews&channel=compony&point=H5&platform=android&ts=1523791855795&dur=0","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=62&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A62%7D&logFlag=uaction_1523791857874&t=1523791919877","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEHt1RPZ4a534H1PHNb3iqGQ&google_cver=1","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a67349c00005ad338804cf270db7404&pid=mm_113716014_12970037_52768234&cid=258980&mid=3276&oid=376&productType=1&qytInfoMTime=1523728959&e=YT0xMRle6oyMpq0A4M5XOxu%2BuDuQwZjvfhWd6eAgDyR9SKhEUoZea6MxeeOy5eZ6&k=65&cb=574829386","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQ3AKTQX4Z8AX1W7T64V5%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D13200%26pc0%3D13200%26ld0%3D13200%26t0%3D1523791869069%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQ3AKTQX4Z8AX1W7T64V5%26aftb%3D1:13200","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=ZGVlNDAyNGUtYTlhOS0zNDg1LTg4ZjgtNDA4MWE1ZGNlZjgzCTQ1CVBEUFMwMDAwMDAwNTc2ODMJNTAJMzUzODc0OAkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=771&dpuuid=CAESEEafR7RMDJ7LlwMMWdT6FuY&google_cver=1","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/arrow_rt.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://front.pixfs.net/css/mobile/styles/images/sprite.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t9511/185/243002105/6399/cfe6874b/59ca07dcN9b1c275e.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/main/bottom.png","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://adtech.nflximg.net/adtech_iframe_target_03.html?data=%7B%22is_member%22%3A%22anonymous%22%2C%22membership_status%22%3A%22NON_REGISTERED_MEMBER%22%2C%22session%22%3A%22n%2Fa%22%2C%22country%22%3A%22US%22%2C%22referrer%22%3A%22nmLanding%22%2C%22source%22%3A%22%22%2C%22fbaId%22%3A%22f1fdc59c-9452-4167-a583-cc8ede9a2929%22%7D","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/92e32089-b4a5-468e-aabd-60f4728c5b56_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://nicolive.cdn.nimg.jp/live/simg/img/a464/1390355.baf806.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/JYn8nsDWmEZtb4s7DjfJdw/009/341/214/320x240.8.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1c/c23fd89294ece036611cd5f49ceb540b_erotic_285x160.jpg?cno=894","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2/freeform/WebsiteTTI?source=www&timeToInteractive=3116&firstByte=1278&wire=393&domReady=3116&docLoad=7437&shakti=991&previousPage=2624&navigateTTI=4453","request_type":"text"}
+{"origin":"http://www.twitch.tv/","request_url":"https://api.branch.io/v1/url","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/wnba.png&w=288&h=288&transparent=true","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fonts.googleapis.com/css?family=Slabo+27px:400&lang=zh-TW","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/411MtgykU8L.css?AUIClients/GWMWebAssets","request_type":"css"}
+{"origin":"http://www.baidu.com/","request_url":"https://s.bdstatic.com/common/openjs/amd/eslx.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://w88.espn.com/id?d_visid_ver=1.5.6&callback=s_c_il%5B0%5D._setAnalyticsFields&mcorgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&mid=27927265607529191862424128891858798724","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/pa/js/min/pa.js","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://collector.githubapp.com/github/page_view?dimensions[page]=https%3A%2F%2Fgithub.com%2F&dimensions[title]=The%20world%27s%20leading%20software%20development%20platform%20%C2%B7%20GitHub&dimensions[referrer]=&dimensions[user_agent]=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180413.110452&dimensions[screen_resolution]=360x512&dimensions[pixel_ratio]=3&dimensions[browser_resolution]=360x512&dimensions[tz_seconds]=-25200&dimensions[timestamp]=1523791941322&dimensions[request_id]=8118%3A6B74%3A2C4A963%3A3BF6025%3A5AD33838&dimensions[region_edge]=sea&dimensions[region_render]=iad&&measures[performance_timing]=1-3666-2993--7608-7597-7596-4160-2993-2690-4143---0---3666-4452-4131-3314--&&&dimensions[cid]=1112253761.1523791941","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.google.com/pagead/drt/ui","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://h5api.m.tmall.com/h5/mtop.tmall.tac.gateway.execute/1.0/?https=on&https=on&jsv=2.4.11&appKey=12574478&t=1523791819640&sign=8ab28eb896b2507753d64da9f48840a2&AntiCreep=true&api=mtop.tmall.tac.gateway.execute&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp1&data=%7B%22msCodes%22%3A%222017080800%22%2C%22params%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/js/head/294487c0/head.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-node-plugin/anim-node-plugin-min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://api.adsymptotic.com/d/px?_pid=10479&_psign=1e962a13c2bbb17776ade0119024edb3&_redirect=https%3A%2F%2Ftags.bluekai.com%2Fsite%2F20931%3Fid%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=ADB&partner_url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=91191954147729940174299115411397659455","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/font_atlas_grotesk-vflAiFY8v.css","request_type":"css"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/t.gif","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://ib.adnxs.com/getuid?https://tags.bluekai.com/site/3085?id=&","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://p1.zemanta.com/p/342/585/","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://geo.yahoo.com/p?s=1197228339&t=OaDfzm3ZntZhfzHj,0.16963859921004243&_I=&_AO=0&_NOL=0&_R=&_P=3.42.4%05_pl%031%04A_v%033.42.4%04test%03900%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03wv9iGO4YBhEcDjLL%04_w%03www.yahoo.com%2F%04_rid%039rcrpl9dd6e1s%04mrkt%03us%04pt%03home%04site%03fp%04ver%03ss%04uh_vw%030%04colo%03slw1027.fp.gq1.yahoo.com%04navtype%03server%04nob%031%04A_pfb%03621%04A_pbp%036205%04A_psr%036823%04A_pol%0319056%04A_pdi%0314784%04A_pdl%030%04A_psh%03398%04A_psc%03724%04A_pfe%0310530%04etrg%03backgroundPost%04outcm%03performance%04usergenf%030%04etag%03performance%04_E%03pageperf%04_ts%031523791949%04_ms%03654%04A_sr%03360x512%04A_vr%03360x512%04A_do%030","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/temple-run-2-android.png:l","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/icon-anjuke.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/members/bottom.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/i1/TB1c1FMIpXXXXawXpXXN4ls0XXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/i2/TB19BluIVXXXXX6XpXXN4ls0XXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/1bfd0b03-5d3c-4f6b-9588-40b9df717e60_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4242000/4242384/220x165/4.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/bc305bae436f1c3a62dd4c.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://aecpm.alicdn.com/simba/img/TB1CWf9KpXXXXbuXpXXSutbFXXX.jpg_q50.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p3.qhimg.com/t01fb225170c5a262ee.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71lh6TEliuL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/mobi/2017/image/section-title-24hours.svg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/search/image_small.svg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/search.svg","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/ajax/bz","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/icons/2.3.3/cnn-icons.woff","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://use.typekit.com/af/2d49e2/000000000000000000017701/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n4&v=3","request_type":"font"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/vendor.9ff841bd3f1df6cd.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-mcl-base.min-vflUZmZyI.js","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/gtm.aX_QHhLRPyo.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/ss/rapid-3.42.4.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/ys/l/0,cross/RWAN3d_LMcN.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/21SX%2BXnDsHL.css?AUIClients/RetailSearchAutocompleteAssets","request_type":"css"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=extremereach_adh&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6&google_hm=","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://ib.adnxs.com/async_usersync_file","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://fcast.us-west-2.espncdn.com/FastcastService/pubsub/profiles/12000/topic/event-topevents/message/5739158/checkpoint","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.go-mpulse.net/boomerang/9SLYA-PCQKP-CU56T-D2UD9-N4WJG","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel-a.sitescout.com/dmp/pixelSync?nid=3","request_type":"other"}
+{"origin":"http://www.office.com/","request_url":"https://c1.microsoft.com/c.gif?DI=4050&did=1&t=","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.advertising.com/ups/28/sync?uid=86070857378125119120981354726841823876&_origin=1&redir=true","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/min/browser-min.css?1523501963","request_type":"css"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a67349c00005ad3387b4cfb70cc7e61&pid=mm_113716014_12970037_52768241&cid=217738&mid=54295&oid=149&productType=1&qytInfoMTime=1523728959&cb=876414491","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://audible.sp1.convertro.com/view/vt/v1/audible/1/cvo.gif?cvosrc=display.2311301.92161433&cvo_cid=20961954&cvo_pid=218069769&cvo_adid=416623175&cvo_crid=92161433&actcode=AFAGBBN02221891M7","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_local-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://m.aliexpress.com/img/1x1.gif?type=amp-performance&pageType=home&cid=amp-50XQcMshov1NQ7I2bYC0LQ&content_load_time=3547&domain_lookup_time=0&dom_interactive_time=3544&nav_redirect_count=0&nav_type=0&page_download_time=217&page_load_time=16400&redirect_time=2980&server_response_time=365&tcp_connect_time=708","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/babel-tv-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/steven0717/albumset/1043177/zoomcrop/75x75.jpg?v=1297692028","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p2.qhimg.com/t01dfc013c7b3c21ac3.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/audio_black.png","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1KruLQFXXXXX.XpXXXXXXXXXX-60-57.png","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://img.cdn.nimg.jp/s/niconews/articles/images/3435823/6bec9b113b9092c00342a2ae7e88e575e9157f1e7f631302c112f0fb8f838ea9e889bc53d253ea396724cc19a74a3970786dfe02b82e96e665efade92e82a637/110x110s_FFFFFFFF?key=a5e5a9798a17274e8b3ee8e40d62cc88478f606e5785f6450063c6a8f9dd5300","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://secure-dcdn.cdn.nimg.jp/comch/channel-icon/128x128/ch222.jpg?1499706952","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/b4/4d/da/b44ddae83e379e16e97362269cd8fa58/b44ddae83e379e16e97362269cd8fa58.3.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://643108e7617ef.cdn.sohucs.com/90c462ec59b24d13ab832142883a5838.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p0.qhmsg.com/t01f025a32b676961bb.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31s2c9G8xRL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/n1/s124x124_jfs/t15904/262/2022447162/98697/1fc13d71/5a803cb3N0e2bbd8d.png!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/images/favicon/favicon-32x32.png?v=1","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://www.espn.com/core/l?a=false&t=false","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-bind-0.1.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_194.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-user-education-client.min-vflb8Ke04.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-vv_ad/td-applet-viewer-templates-vv_ad-min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nba/500/scoreboard/mia.png&h=312&w=312","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTI4NDkmdGw9MTI5NjAw&piggybackCookie=2e68b153-5f6c-4bef-a554-4d86b35719b5","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://adservice.google.com.hk/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://image6.pubmatic.com/AdServer/PugMaster?rnd=73107563&p=156736&s=269857&a=1318691&ptask=ALL&np=0&fp=0&mpc=0&spug=1&coppa=0&sec=1","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://idsync.rlcdn.com/379708.gif?partner_uid=L6N62llA","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/aw/mshop/qtips.html?page=gateway&url=https%3A%2F%2Fwww.amazon.in%2F&trafficType=DIRECT","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://analytics.twitter.com/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nyutn&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0&tpx_cb=twttr.conversion.loadPixels&tw_document_href=https%3A%2F%2Fwww.cnn.com%2F","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/dd?d_uuid=86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://p.rfihub.com/cm?in=1&pub=6919","request_type":"other"}
+{"origin":"http://www.live.com/","request_url":"http://www.live.com/","request_type":"other"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/assets/frameworks-592c4aa40e940d1b0607a3cf272916ff.css","request_type":"css"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/stylesheets/tpb-min.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=news-more&pn=1&cat=notls&staytime=4&t=1523791862477","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://segments.company-target.com/wtk?vendor=liveramp&lrid=Xc1297vBc3vUSZYw9tnDok-D_9GWBGYtwgT2ZY274rjFW2s4k","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/_td_api/beacon/error?os=android&rid=9rcrpl9dd6e1s&bucket=900&device=smartphone&site=fp&resource=contentList&operation=read&params=%7B%22uuids%22%3A%2290a44e65-46e9-30d2-8c16-82dc9982b802%2C29e38929-7899-3d94-8900-9a58c2cf3b9b%2Cac2766bb-6443-3d74-a2b7-a311a6e9b8fc%2Cf5c6ba7d-d894-33d8-af80-4c6fc4361649%2Cd8a79435-e96f-3828-8b2e-30a53721cfa3%2C8fc8da20-30b1-3020-a9ad-eaf57eb8e110%2C79808c55-cb7a-32e7-a905-3cd4f415d109%2C96368e89-fde4-3a0f-9328-58b3e99100b9%2Cd005ffb6-b19d-36d1-a5f1-8f0dd67220a3%2Ca8b4859c-516f-3046-8865-d8646a101ca1%2Ce8291bef-3809-3894-a397-c5bdc7ab967c%2Cc1b5e81d-e647-3ecd-81ea-e2980bd27cc8%2C5ee00263-bb83-3f33-a958-eaeb7fbb9158%2Cbb1273e7-c98e-3880-b15f-2df284ca6266%2C96ff8db0-033c-34b8-a9b6-b987bc69c4e0%22%2C%22category%22%3A%22%22%2C%22ad_meta%22%3Atrue%2C%22enable_vertical_video%22%3Atrue%2C%22curveball%22%3A%7B%22sectionId%22%3A5417125%2C%22positionThreshold%22%3A100%2C%22enabled%22%3Atrue%2C%22genericViewability%22%3Afalse%2C%22count%22%3A5%2C%22lowerBound%22%3A2%2C%22fromContentAPI%22%3A0%2C%22fromCurveballAPI%22%3A1%2C%22enableBeaconListenerOnly%22%3Afalse%2C%22enableVisibilityRect%22%3Afalse%2C%22adChoicesUrl%22%3A%22https%3A%2F%2Finfo.yahoo.com%2Fprivacy%2Fus%2Fyahoo%2Frelevantads.html%22%2C%22smad%22%3A%7B%22adsContentType%22%3A%22video%2Fmp4%22%2C%22bypassRedirect%22%3Afalse%2C%22count%22%3A1%2C%22cssClass%22%3A%22%22%2C%22disableCta%22%3Atrue%2C%22enabled%22%3Afalse%2C%22enableVideoAd%22%3Afalse%2C%22lowerBound%22%3A1%2C%22sectionId%22%3A%225556936%22%2C%22sm_ads_image_tag%22%3A%22img%3A360x640%7C2%7C90%22%2C%22sm_ads_screen_orientation%22%3A%22po%22%2C%22spaceId%22%3A%221197618805%22%2C%22type%22%3A%22STRM%22%7D%2C%22host%22%3A%22www.yahoo.com%22%2C%22bucketId%22%3A%22900%22%7D%2C%22commentsEnabled%22%3Atrue%2C%22linkYlk%22%3A%22sec%3Agiraffe_viewer%3Bitc%3A0%2Celm%3Acontext_link%3B%22%2C%22lazyLoad%22%3Atrue%2C%22offnetDeeplink%22%3Atrue%2C%22related_content_enabled%22%3Atrue%2C%22vertical_video_ar%22%3A%2203x04%22%7D&_appletType=viewer&code=403&message=&src=af-transport&_rdn=950678","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/subway-surfers-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/candy-crush-saga-android.png:l","request_type":"image"}
+{"origin":"http://www.office.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/images/vmobile/sprite-ui.png?cache=2018041212","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/png/site2/20180413/bc305bbef1b21c3a61d001.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p1.ssl.qhimg.com/t0112454b2ad89460e8.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/huochepiao083002.png","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1HQqFkH1YBuNjSsze761blFXax.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"http://www.tmall.com/","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/default/transform/266/w640h426/20180415/zcWf-fzcyxmu9307925.jpg/w200h134f1t10l50q90c55.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/marketing/prime/dex/trafficdrivers/VXD-1095_GWMobileHero_1242x450_copy2._SX414_CB508068870_.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/9a/58/48/9a58486a0b9eb9ec24672c15e1f477df/9a58486a0b9eb9ec24672c15e1f477df.26.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p.ssl.qhimg.com/t01610f98dd079cf948.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_77,y_0,w_459,h_306/os/news/c6bf77e0e43d34367c4b2bf45a3b6849.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20160816wljbAPP.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5232000/5232835/220x165/4.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/269df4d22336489d8ba37b86cadce349.jpeg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/N60eY-qiN3OD-RORA_kcZAwR-JY91pVIP75vha6T-gc.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/02.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/sprite.svg","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/sc/h/amcqj2dkvh3gabfiv8a9lht4t,8tacpq8nvaeobloto9zl3yjse","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://tpc.googlesyndication.com/safeframe/1-0-10/js/ext.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/??tb/tracker/4.2.1/p/index/index.js,mtb/lib-promise/3.0.1/polyfillB.js?v=3526935212_16518","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nhl.png?w=110&h=110&transparent=true&h=240&w=240","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/21SX%2BXnDsHL.css?AUIClients/RetailSearchAutocompleteAssets","request_type":"css"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/Fonts/Montserrat-Medium.woff2","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-59e8752e64746d7550001939.js","request_type":"script"}
+{"origin":"http://www.popads.net/","request_url":"https://www.popads.net/js/scambar.js?1516108355","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://www.msn.com/","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://su.addthis.com/red/usync?pid=16&puid=86070857378125119120981354726841823876&url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D420%26dpuuid%3D%7B%7Buid%7D%7D","request_type":"text"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://us-u.openx.net/w/1.0/cm?id=5c627885-3475-4ed8-a54e-8d0222f57cbe&d=MACRO&r=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d31%26uid%3d","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://x.bidswitch.net/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.paypal.com/","request_url":"https://t.myvisualiq.net/sync?prid=Test&ao=0&red=https%3A%2F%2Fad.doubleclick.net%2Fddm%2Ftrackimp%2FN426203.2426714VISUALIQ%2FB11035907.147164125%3Bdc_trk_aid%3D318650907%3Bdc_trk_cid%3D79651416%3Bsz%3D1x1%3Bu%3D%7CVIQ_%24%7BUUID%7D%7Chttps%253A%252F%252Fwww.paypal.com%252Fus%252Fhome;ord=1523791848365","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=dataxu&uid=38LfH5iL1F7FUa5","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/rebrand/elements/homepage_login_register_panel-vflzsQYcC.css","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.facebook.com/tr/?id=731697573629176&ev=PageView&dl=https%3A%2F%2Fwww.cnn.com%2F&rl=&if=false&ts=1523791886011&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=28&it=1523791885403","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-88451119-7&cid=213610430.1523791965&jid=265375760&_gid=1476326533.1523791965&gjid=1098642764&_v=j66&z=1625046190","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://us-u.openx.net/w/1.0/sd?id=537072991&val=CAESEBJTgzGd_t3a1OCRbopLVII&google_cver=1","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://yjtag.yahoo.co.jp/cs?btt=0&tp=8FzrfRY&uid=Ku7WP6Aowk5feRWXb9.5AxMX&uid2=&uid3=&uid4=&uid5=","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3DXZ4D3PPDB36HTEGXD7ZH%26ctb%3D1%26m%3D1%26sc%3DXZ4D3PPDB36HTEGXD7ZH%26pc%3D11528%26at%3D11528%26t%3D1523791922072%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DXZ4D3PPDB36HTEGXD7ZH%26aftb%3D1:11528","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://sstats.adobe.com/b/ss/adbhelpxprod/1/JS-2.5.0-D7QN/s16998918258190?AQB=1&ndh=1&pf=1&t=15%2F3%2F2018%204%3A33%3A26%200%20420&sdid=0F715D2B1317710A-3C141A64CA81D397&D=D%3D&mid=91347194757900030554314852707948543921&aid=2D699C4005031F55-600011820000562A&aamlh=9&ce=UTF-8&cdp=2&fpCookieDomainPeriods=2&pageName=adobe.com&g=https%3A%2F%2Fwww.adobe.com%2F&c.&hitType=pageView&.c&ch=adobe.com&server=www.adobe.com&v0=D%3Dv6&events=event61%3D19%2Cevent62&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&c1=Home%20Page%20Template&c3=www.adobe.com&c4=en_us&c5=en_us%3Aadobe.com&v16=D%3Dc12&v18=New&c20=D%3Doid&c21=D%3Dpid&v22=Sunday%20-%204%3A30AM&c27=NotSignedIn&v28=www.adobe.com%2F&c29=D%3Dv12&c31=en-us&c32=en-us%3Aadobe.com&v37=D%3Doid&v38=D%3Dpid&c52=unknown&c62=18.63&v65=Chrome%2058&v73=no%20value&v84=D%3Dc27&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&AQE=1","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/a.gif?V=2.3.1&CI=sz:360x512|dp:24|ac:Mozilla|an:Netscape|cpu:|pf:Linux%20x86_64|jv:1.3|ct:unkown|lg:en-US|tz:7|fv:|ja:0&PI=pid:|st:|et:2|ref:|hp:unkown|PGLS:|ZT:|MT:|keys:|dom:2606|ifr:0|nld:1523791823990|drd:0|url:|ch:&UI=sid:1654439800560.783.1523791824016|vid:9533882159274.413.1523791820192|lv::1:1:1|un:::::|uo:|ae:|su:|lu:|si:|rs:0|dm:0&MT=&EX=ex1:FEED__0|ex2:ustat-__149.20.63.13_1523791820_0.19234800,0,abt=80_162_173,xiding=0,twice&gUid_1523791854138","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://imp.optaim.com/201803/6ed56c41ee700959abef2a66e71836ab.php?a=0&adpid=beans_12274&impid=0f0dbcc288104b396_0_0&_time_=1523791942195","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/uedata/unsticky/262-9616072-1847409/NoPageType/ntpoffrw?at&v=0.200436.0&id=Q3AKTQX4Z8AX1W7T64V5&ctb=1&m=1&sc=Q3AKTQX4Z8AX1W7T64V5&pc=14740&at=14740&t=1523791870609&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=Q3AKTQX4Z8AX1W7T64V5&aftb=1","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/_td_api/beacon/error?os=android&rid=9rcrpl9dd6e1s&bucket=900&device=smartphone&site=fp&code=&message=Uncaught%20ReferenceError%3A%20Notification%20is%20not%20defined&url=https%3A%2F%2Fwww.yahoo.com%2F&line=1356&file=&src=rt&_rdn=950291","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://cdn.tsyndicate.com/images/f/c/dba7b92f93e85296d5b9dfa02d60dd8600aa9f.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/facebook-messenger-android.png:l","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/AwLUKnfIxjqCkWZw7vI3a2g7tqRUZ4Ne-b3KBTX8MikfBILxzL8nZrckfO_G=w512","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/gyao80.png","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://cs.nend.net/cs.php?nex_uid=144c9545-81c5-43e2-bd06-ca07be597cab","request_type":"html"}
+{"origin":"http://www.savefrom.net/","request_url":"https://go.mobtrks.com/notice.php?p=1617677&interstitial=1&_=1523791941896","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"http://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.gmw.cn/","request_url":"http://s.csbew.com/acookie.html","request_type":"html"}
+{"origin":"http://www.qq.com/","request_url":"https://xw.qq.com/index.htm","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://fonts.gstatic.com/s/rubik/v7/iJWHBXyIfDnIV7Eyjmmd8WD07oB-.woff2","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/sharpgrotesk/SharpGroteskDBMedium22-vflPPMtcG.woff2","request_type":"font"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/heroes/ipad/ipad_small_2x.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/pic/gmmlogo.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-3SbFSzWeVI8/AAAAAAAAAAI/AAAAAAAAAAA/UOWASplUwOU/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/42ca1e9b544a7d9a7e6fe1eda2da5394_erotic_285x160.jpg?cno=381","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1f/f1d83ce564a145cd4db94a590af22b42_erotic_285x160.jpg?cno=fb99","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMzcwMjkxMzQ3NV5BMl5BanBnXkFtZTgwMzgyNDA5MDI@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/JzYAAOSwx2dYCraY/s-l225.webp","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s720x352_jfs/t17101/38/1478340706/148981/7ccf2969/5acc8048N4bfd1c0b.jpg!cr_1125x549_0_72!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/slYAAOSwIJlaKtLX/s-l225.webp","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t01ce034aec61cf27aa.webp?size=640x905","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://m.pixnet.net/favicon.ico","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/music/image_small.svg","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://ssl.gstatic.com/accounts/o/25936583-postmessagerelay.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/wss/fonts/SF-Pro-Icons/v1/SFProIcons_regular.woff","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-video-manager-util/td-video-manager-util-min.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/lib/react-dom-15.4.2.min.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/handlebars-4.0.5.min.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yI/l/0,cross/R19JZiGQA8u.css","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/zepto_7eb941e.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjss19Zf0R1g4-FvtjFO-GV1byN84amvSEK5bvnZAVXjxwmHQb_wZzGjjmV2sut5Zbeid3PIzo2sSg8ARyOeqmWF4QbVXmpuPlR1hRd4RnUyJttGnzinXwDjQjCaYSw2OSz364y7fGriyLTgYV7VjhsGF7TpnV6-TjCsA0t0GuFlQErzNMtcoiSbGS_Q4VECkhXxbSO6n_xi-8R2LsGeWY8l_17zuYs3A3caFmaY7ZbEcVSc_uonsP5y1t_VBaNAe1kM&sig=Cg0ArKJSzFUkKPv_SvoKEAE&urlfix=1&adurl=https://secure.espncdn.com/ad/blank.gif","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/gw/ajax/card.html/260-2953656-0613235?ie=UTF8&opf_redir=1&rshVal=1523792017987","request_type":"html"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/gen_204?s=webaft&atyp=csi&ei=-DfTWqiNHYaC8AOtuL_YCg&rt=wsrt.2086,aft.370,prt.184","request_type":"html"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/gen_204?s=webaft&atyp=csi&ei=0jfTWsnyGs-h_wTqvIH4DQ&rt=wsrt.2135,aft.523,prt.372","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://www.tmall.com/","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js","request_type":"script"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.instagram.com/","request_url":"https://graph.instagram.com/logging_client_events","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://broadband.espn.com/espn3/auth/watchespn/user?partner=watchespn&platform=web","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/default/js/streamsense.5.2.0.160629.min.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://match.prod.bidr.io/cookie-sync/demandbase?_bee_ppp=1","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/b?c1=7&c2=14320224&c3=185&ns__t=1523791885173&ns_c=windows-1252&ns_if=1&cv=3.1m&c8=&c7=https%3A%2F%2Fwidgets.outbrain.com%2FnanoWidget%2Fexternals%2FobFrame%2FobFrame.htm%23pid%3D185%26dmpenabled%3Dtrue%26filterDMP%3DOEN%26csenabled%3Dtrue%26d%3Dy5aHeVC2r5fQ9ZMoYAPNfHtdXiYd-2eTxeFMgPo2VWbkXCREe-x-wuPg2njsTPLA&c9=https%3A%2F%2Fwww.cnn.com%2F","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/t_tkr/ev?type=r&v=9.4.10-b-301&plid=764344014241209959&pvid=1928825100107055743&x=0&y=0&pvt=1523791869849&pft=1523791867546&stime=1523791873675&etime=1523791873676","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://match.basebanner.com/match?tabid=39041E2B94ED6EF00CB315F995BE6F73&extuid=fcbd302d-2d51-4301-be01-c7741f15bde8&excid=85","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fimage2.pubmatic.com%252FAdServer%252FPug%253Fvcode%253Dbz0yJnR5cGU9MSZjb2RlPTI2NjgmdGw9NDMyMDA%253D%2526piggybackCookie%253D__EFGSURFER__.__EFGCK__&google_gid=CAESEPd4Jzcj87qgNvzrB164ELA&google_cver=1","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=7941&nid=2243&put=WtM4gQAABibm4O17&expires=90","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://bea4.cnn.com/ad/u?mode=echo&cr=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dfreewheel%26partner_uid%3D%23%7Buser.id%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://x.bidswitch.net/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/sg/storygize-network/1/rtb-h?taboola_hm=efb4bcbf-6600-4eec-bbfd-c46836b73bf2","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/b9pj45k4?redir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=6F8A010E-C957-44B1-91B4-86FA277A5A46&ex=pubmatic.com","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://s.amazon-adsystem.com/ecm3?id=164061102661000501341&ex=neustar.biz","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=58&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A58%7D&logFlag=uaction_1523791857874&t=1523791915876","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.facebook.com/tr/?id=823166884443641&ev=PageView&dl=https%3A%2F%2Fwordpress.com%2F&rl=&if=false&ts=1523791841273&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=28&it=1523791840811","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-71552437-1&cid=970841907.1523791982&jid=407822979&_gid=1459932104.1523791982&gjid=1321911993&_v=j66&z=1379469448","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://touchsplash.radar.imgsmail.ru/update?t=page&v=3775&i=all%3A3775%2Chead%3A2997%2Cserver%3A9%2CSplashjs%3A2986%2CJSLoad%3A2949%2CJSInit%3A36%2Cheadline%3A1%2Cportal-menu%3A4%2Csocial%3A226%2Csearch%3A12%2Cweather%3A111%2Cnews%3A71%2Cbanner-bottom%3A32%2Ccurrency%3A45%2Choro%3A53%2Ctv%3A1%2Cafisha%3A90%2Csport%3A55%2Cgames%3A2%2Capps-bottom%3A1%2Ccatalogue%3A1%2Cfooter%3A1%2Ccache_clearCache%3A1%2Cconnect%3A1542%2CdomainLookup0%3A0%2Crequest%3A1058%2Cresponse%3A137&p=touchsplash&rnd=0.7485992059344675&ver=touch&l=0&em=false%40null&a=0&xy=0","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3D3P95XKNQTYVQ066DW1Q8%26pty%3DShoppingCartAW%26spty%3DCart%26pti%3D:1000","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ib.adnxs.com/getuid?https://ads.yieldmo.com/v000/sync?userid=$UID&pn_id=an","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A4561%2C%22netDns%22%3A0%2C%22netTcp%22%3A1122%2C%22srv%22%3A1121%2C%22dom%22%3A5289%2C%22loadEvent%22%3A19849%7D&et=87&ja=0&ln=en-us&lo=0&rnd=1160146160&si=48c57cebc84275afcff127cd20c37e4b&v=1.2.30&lv=1","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=599700673&t=pageview&_s=1&dl=https%3A%2F%2Fm.txxx.com%2F&ul=en-us&de=UTF-8&dt=Porn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aGBAAAAj~&jid=1562442416&gjid=490235259&cid=205197444.1523791993&tid=UA-43982756-1&_gid=350041298.1523791993&_r=1&gtm=G46MDKJT8&z=1488579017","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://ssl.google-analytics.com/r/__utm.gif?utmwv=5.7.1&utms=1&utmn=1798030022&utmhn=www.popads.net&utmcs=UTF-8&utmsr=360x512&utmvp=980x1393&utmsc=24-bit&utmul=en-us&utmje=0&utmfl=-&utmdt=PopAds%20-%20Home&utmhid=416824934&utmr=-&utmp=%2Fapp%2Fwebroot%2F&utmht=1523791895661&utmac=UA-19696955-1&utmcc=__utma%3D89311364.1425070423.1523791896.1523791896.1523791896.1%3B%2B__utmz%3D89311364.1523791896.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmjid=582545050&utmredir=1&utmu=qBAAAAAAAAAAAAAAAAAAAAAE~","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/img/flagsx2.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/may0903/albumset/18281849/zoomcrop/75x75.jpg?v=1523335364","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem5YaGs126MiZpBA-UN7rgOXehpKKSTj5PW.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/1565000/1565158/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/4642000/4642863/220x165/6.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/e273c93c95da49e2bc501cc9468d2304.jpeg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31GOYH8A07L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fpr-bh.ybp.yahoo.com%2Fsync%2Fadaptv_ortb%2F%7Buid%7D","request_type":"text"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mjs.sinaimg.cn/wap/module/base/img/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://api.b2c.com/api/init-286421vngpqvy336hdu.js","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/shared.33227412e400efa4.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/phub.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/common.en.js?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/zepto/4.0.9/form.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/polyfill.min.js?v6.23.0","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://sp.analytics.yahoo.com/sp.pl?a=1000543649509&jsonp=YAHOO.ywa.I13N.handleJSONResponse&d=Sun%2C%2015%20Apr%202018%2011%3A31%3A07%20GMT&n=7d&b=Dropbox&.yp=25979&f=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&enc=windows-1252&isIframe=1","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://dsp-impr2.youdao.com/k.gif?yd_ewp=356&yd_ext=EqMBCgEwEiBkYzczZDM4NDI1YjJlNjMxMTA3MGM5MzUwM2M1MGI5NyJ6CKjslQoQiJfPAhjwjDIg8PoRKJPfAjAyODJlAACyQ3AAeACAAQCYAQGiAQtUcmFkaXRpb25hbLoBOXsiT1JERVJFRF9JRCI6IjEiLCJlbmFibGVfb2NwYyI6ImZhbHNlIiwiY3ZyX2FsZ19pZCI6IjAifeABwgSAAgAwAiIkYzJlZWYzMDktZGFhNC00ZTJlLTljZTctOTZlOWYyYWNjNDIzKG4wADoAQgBSDDIwOC43MC4zMS45M2oNMTUyMzc5MTkzOTM0N3gAggEAiAHkApABk47PyKwsqAEBsAEBuAEBwgEENTA2MNABBNoBIDkxNDhlNTY3OTRjZjA0MDdlMzE1ZDU4OWNjYzVkM2Yx4gEA6AHoCvIBBTEuMS4ygALLAYoCCnRoMDg0LTkwMTM&iid=%7B%221163318208763300816%22%3A4%7D&sid=12020&t=1523791941526","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://fandom.wikia.com/f2/api/public/hot-content-module?region=united-states","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://ml314.com/imsync.ashx?pi=5978151418383285727&data=eyJwaCI6MCwid2giOjAsInRicyI6MCwiZHQiOjE1LCJwaWQiOiIxNTIzNzkxODg0OTg2X2o2c3ZxeGxoNiJ9","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938219_6678390672046&itemspaceid=12279&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938219&plateid=1001500000,1001800000","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://m.livejasmin.com/en/window/get-over-eighteen-window","request_type":"text"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51LGid1qdxL._RC%7C01BL18zkkEL.js,31a72IenKyL.js_.js?AUIClients/NavMobileMetaAsset","request_type":"script"}
+{"origin":"http://www.360.cn/","request_url":"http://p8.qhmsg.com/t0105139de64586cf40.png","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://t.myvisualiq.net/ul_cb/sync?prid=123&ao=0&red=https%3A%2F%2Fwww.facebook.com%2Ftr%3Fid%3D1939652716271841%26ev%3DPageView%26cd%5Border_id%5D%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/recaptcha-vflIN6j39.css","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=cBE+ovHVOMNJrQVxRbZuYA==&ex=rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=fbca&id=-AYFQvTfQS66Rccu-6kpkQ","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.adaptv.advertising.com/sync?type=gif&key=pubmatic-55&uid=D34DC539-63A7-4F27-8DFD-50E0EE1E218A","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=aolvideo.com&id=4d62e714a2aadb476fd21950b59f46b769d07230","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://assets.alicdn.com/mw/webapp/fav/img/grey.gif","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://pixel.mathtag.com/event/img?mt_id=888356&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DXZ4D3PPDB36HTEGXD7ZH%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D10010%26cf0%3D10016%26pc0%3D10016%26ld0%3D10016%26t0%3D1523791920560%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DXZ4D3PPDB36HTEGXD7ZH%26aftb%3D1:10016","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DQVRKZSEBR7BT5RF15TNH%26pty%3Dgateway-phone-apps%26spty%3Dios-card%26pti%3Dmobile:1000","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/happy-chick-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/day-r-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/swift-logo.png","request_type":"image"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/resources/images/0/sprite1.narrow.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p4.qhmsg.com/t01e4c126e44c6e0e47.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/openx?oxid=000300ea-838a-3a75-7a55-91bf99a60944","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://servedby.flashtalking.com/container/10943;81912;8481;iframe/?ft_referrer=https%3A//www.adobe.com/&ns=&ftXRef=[%TRANSACTION_ID%]&ftXValue=[%TRANSACTION_VALUE%]&ftXType=[%TRANSACTION_TYPE%]&ftXName=[%TRANSACTION_NAME%]&ftXNumItems=[%TRANSACTION_QUANTITY%]&ftXCurrency=[%TRANSACTION_CURRENCY%]&U1=&U2=&U3=&U4=&U5=&U6=&u7=&U8=&U9=&U10=&U11=&U12=&U13=&U14=&U15=&U16=&U17&U18=&U19=&U20=&cb=6401664386550.001","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/sodar/6uQTKQJz.html","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/04/15/1523781784_20180415-00010001-norimono-000-view-x104-y104.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/67/e8/ac/67e8acd2e97eaabb1c06d3d8c9f281e8/67e8acd2e97eaabb1c06d3d8c9f281e8.4.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2404943836,2303286930&fm=173&app=12&f=JPEG?w=218&h=146&s=C4F420721B4A4D4944E525D60000E0B1","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/34dc9476d8e21bf9bb57e928f9ddda19_erotic_285x160.jpg?cno=2d91","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/415b60a630db2095c17b2c9d0b906feb_erotic_285x160.jpg?cno=ef4b","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/364750c894f44ed7b92b4f41c83d05cf.jpeg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=866778182688&t=17&plc=MOBILE&tkn=*X4_hDxzCBdijadWKjMSsqwtVF80","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1EoCAQFXXXXcWXXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1uDEXSFXXXXbkXVXXXXXXXXXX-1000-242.jpg_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://logx.optimizely.com/v1/events","request_type":"text"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-carousel-0.1.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/__media__/js/util/nrr.js?v=81","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://cdn1d-static-shared.phncdn.com/jquery/jquery.cookie-1.3.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/jquery-1.9.1.min.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/248aabf4443966cb0328876d5797f914.js?conditionId0=380088","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://8392543.fls.doubleclick.net/activityi;src=8392543;type=idsyn0;cat=uuidm0;u1=NotSignedIn;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;u4=;u5=;u6=adobe.com;u7=;u8=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=1;num=7017383513578.663","request_type":"html"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/gen_204?atyp=csi&ei=0jfTWsnyGs-h_wTqvIH4DQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.519,dcl.514,iml.519,ol.3059,prt.372,xjs.1947,xjsee.1947,xjses.1557,xjsls.391,wsrt.2135,cst.667,dnst.0,rqst.809,rspt.433,sslt.365,rqstt.1652,unt.2041,cstt.981,dit.2648&zx=1523791829841","request_type":"html"}
+{"origin":"http://www.office.com/","request_url":"https://www.office.com/","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/","request_type":"html"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5api.m.taobao.com/h5/mtop.taobao.baichuan.smb.get/1.0/?jsv=2.4.8&appKey=12574478&t=1523791946007&sign=cf99474d13d687be34c2abbcfb413b77&api=mtop.taobao.baichuan.smb.get&v=1.0&type=originaljson&dataType=jsonp&timeout=10000","request_type":"script"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/id?d_visid_ver=2.3.0&d_fieldgroup=AAM&d_rtbd=json&d_ver=2&d_orgid=EA76ADE95776D2EC7F000101%40AdobeOrg&d_nsid=0&d_mid=86352965276358834310953151770845862795&d_blob=6G1ynYcLPuiQxYZrsz_pkqfLG9yMXBpb2zX5dvJdYQJzPXImdj0y&d_cid_ic=MSFPC%01fbae62a858c942f989eb9eafc49b9bdb%012&d_cid_ic=MC1%01fbae62a858c942f989eb9eafc49b9bdb%012&ts=1523791842315","request_type":"script"}
+{"origin":"http://www.youtube.com/","request_url":"https://googleads.g.doubleclick.net/pagead/id?slf_rd=1","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/v1/article/search/tag/flawless?pageSize=3","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://pos.baidu.com/s?hei=100&wid=360&di=u3129142&ltu=http%3A%2F%2Fm.youth.cn%2F&chi=3&cfv=0&cpl=0&ant=0&dtm=HTML_POST&drs=3&dri=0&exps=116036&col=en-US&cce=true&pis=-1x-1&cmi=0&pss=360x1431&tcn=1524189915&pcs=360x512&tpr=1524189914767&dis=0&cdo=0&dai=1&cec=UTF-8&psr=360x512&dc=3&ccd=24&cja=false&tlm=1524189914&ps=813x10&ti=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&par=360x512&ari=2","request_type":"other"}
+{"origin":"http://www.csdn.net/","request_url":"https://experiment.appadhoc.com/get_flags_async","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&ph=2d1251ae-7f3a-47cf-bd2a-2f288854a0ba&plm=5&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ssp-bidder.i-mobile.co.jp/script/sspcore_spot.js?20130501","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/mobile/css/mobile.min.css?v=d514d5f5a938995a3b3d","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=bidswitch.com&id=12ca1195448e7bcb195638414a1b4dfa","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?id=718e7940-0012-48c0-bad4-b6ad54ecf52a&ex=audienceone.com","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://code.jquery.com/mobile/1.2.0/images/ajax-loader.gif","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.rubiconproject.com/tap.php?cookie_redirect=1&v=7941&nid=2243&put=WtM4gQAABibm4O17&expires=90","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/chuyin52/albumset/5983931/zoomcrop/75x75.jpg?v=1523729068","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/ss6es60330/albumset/16229318/zoomcrop/75x75.jpg?v=1523786007","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/index/taboo_7decb35.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=krux&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/63598286-489e-426a-b33d-4766aabc07f9_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://img.cdn.nimg.jp/s/niconews/articles/images/3435236/6d2352e3b8587fcea188c9f4873fa0859b0f89821d4b62870e52cab3e7ff7772eac609547515c30670eaf35b9cc049e7af683c28675123558b97d7dd14d5fb88/110x110s_FFFFFFFF?key=63f297503a41e44a70b43d99b81f5d126fded5b9de05ff83abe606de89218b7e","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f17/74885d16b0279f36457c7813bf986bc1_erotic_445x250.jpg?cno=58fa","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420345724372926.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BNzUyM2EzOTEtOTMwMi00NzMwLWEyYTAtZGYxYzMyZDgyNGUyXkEyXkFqcGdeQXVyODY3Nzc0OTk@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/DE-hq/2018/img/Health-_-Personal-Care/1106413_de_hpc_fibo18_29-3-18_r2_1242x450._SX414_CB497208892_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=868016673420&t=42&plc=MOBILE&tkn=*t945AIyvr1WNL-TKrBvg9n0z1Zw","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/star.svg","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/localeswitcher/2/en_US/content/localeswitcher.json","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://unagi-eu.amazon.com/1/events/com.amazon.csm.nexusclient.prod","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1/t.js?ver=%272.1%27&name=%27Ms.Webi.PageView%27&time=%272018-04-15T11%3A31%3A24.788Z%27&os=%27Android%27&appId=%27JS%3AOutlookCom%27&-ver=%271.0%27&-impressionGuid=%270e8bfc50-e1a8-4290-a5b8-167a3de67e07%27&-pageName=%27Home%27&-uri=%27https%3A%2F%2Foutlook.live.com%2Fowa%2F%27&-resHeight=512&-resWidth=360&-pageTags=%27%7B%22metaTags%22%3A%7B%7D%7D%27&-behavior=0&*baseType=%27Ms.Content.PageView%27&*cookieEnabled=true&*isJs=true&*title=%27Outlook.com%20-%20Microsoft%20free%20personal%20email%27&*isLoggedIn=false&*flashInstalled=false&ext-javascript-ver=%271.1%27&ext-javascript-libVer=%274.2.6%27&ext-javascript-domain=%27outlook.live.com%27&ext-javascript-userConsent=false&$mscomCookies=false","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://js1.nend.net/js/nendAdLoader.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://manychat.com/105722/assets/js/widget.js?914275167815","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"https://sv.bdstatic.com/static/fecommon/growth/release/core.js?_svt=20180415","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V3RNMzR3QUFDR01mUGZ5UQ&url=/1/gr%3furl=https%253A%252F%252Fpixel.rubiconproject.com%252Ftap.php%253Fexpires%253D30%2526nid%253D2181%2526put%253D__EFGSURFER__.__EFGCK__%2526v%253D11782","request_type":"html"}
+{"origin":"http://www.google.com/","request_url":"http://www.google.com/","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://u3s.mathtag.com/sync/img?adv=136505&uuid=c43d5ad3-3149-4800-a877-b7d8029eb189&mt_id=1017593&mt_nobot=1&passback=https://pixel.mathtag.com/sync/img%3Fsync%3Dauto%26stat%3Dbatch_supply_passback%26mt_nobot%3D1","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/csi_204?v=2&s=youtube_mobile&action=home&e=23707874,23708904,23708906,23708910,23710476,23712544,23713711,23716256,23716972,23718632,23721898,23723618,23724026,23724088,23725922,23731308,23732068,23732220,23732330,23732729,23733751,23734253,23735060,23736269,24630002,9406174,9422596,9440549,9449243,9479903,9485000&yt_sts=dhs&yt_vis=1&rc=&p=h2&t=tcp&yt_pt=html5&yt_nt=wifi&yt_lt=cold&rt=asr.6079,ol.6191,rsf_mbcj.2884,rse_mbcj.3970,rsf_mbc.2883,rse_mbc.3333,rsf_mblouj.2885,rse_mblouj.4324,rsf_mbnj.2884,rse_mbnj.4620,rsf_mbwj.2884,rse_mbwj.4909,aft.6191,nreqs.2420,nress.2807,nrese.2862,srt.2807","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"http://ocsp.godaddy.com/MGIwYDA%2BMDwwOjAJBgUrDgMCGgUABBQdI2%2BOBkuXH93foRUj4a7lAr4rGwQUOpqFBxBnKLbv9r0FQW4gwZTaD94CAQeiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.jd.com/","request_url":"https://so.m.jd.com/downLoad/closeUa.action?_format_=json","request_type":"script"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://secure.adnxs.com/ttj?id=12753689&size=320x50","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://m.imdb.com/uedata?at&v=0.200481.0&id=6983MGHS2ZBMHXB1G0WS&m=1&sc=adblk_no&pc=18749&at=18749&t=1523791944436&csmtags=adblk_no&tid=6983MGHS2ZBMHXB1G0WS&aftb=1","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fdsum-sec.casalemedia.com%252Frum%253Fcm_dsp_id%253D71%2526external_user_id%253D__EFGSURFER__.__EFGCK__&google_gid=CAESEPd4Jzcj87qgNvzrB164ELA&google_cver=1","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://d.agkn.com/pixel/5500/?age=&gender=&st=&sk=265040302661004446320&pd=&cbr=&mip=&dm=&py=&l0=https://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key=265040302661004446320","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://aw.dw.impact-ad.jp/c/u/?oid=207d81ffda0cc019&rdr=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%7BAONEID%7D%26ex%3Daudienceone.com","request_type":"other"}
+{"origin":"http://www.coccoc.com/","request_url":"https://mc.yandex.ru/watch/24497819/1?wmode=7&page-url=http%3A%2F%2Fcoccoc.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-420%3Ai%3A20180415043108%3Aet%3A1523791868%3Aen%3Autf-8%3Av%3A1072%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A1225906347662%3Arqn%3A1%3Arn%3A1031824494%3Ahid%3A1047608455%3Ads%3A342%2C473%2C499%2C46%2C2698%2C0%2C0%2C2228%2C52%2C17431%2C17433%2C7%2C4944%3Afp%3A4342%3Awn%3A12636%3Ahl%3A3%3Arqnl%3A1%3Ast%3A1523791868%3Au%3A1523791868847094136%3At%3ATr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/accessibility-vflMYBl-j.css","request_type":"css"}
+{"origin":"http://www.mail.ru/","request_url":"https://www.tns-counter.ru/V13b****mail_ru/ru/CP1251/tmsec=mail_main-mobile/","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=rightmedia.com&xid=E0","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=122E3C94-4810-4F00-A678-6F9EE0FEF6C0&ex=pubmatic.com","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://im-x.jd.com/dsp/np?log=rwi29WH6X8nEevRtv6Rj5zyoOHVixIAHrh2KcpckozYj1tiTGIw7jOxfRw7WseuZJTS0YQhBuey6E5Cq4zlK0GBxWu53OYTDirqwUREvbD6fPjkAP7F37dAc61Vnqt-qzT-s0_R1NR5MFKBcFH8V7AZA66KmnpAj78tqz4Q2b96tHsrRw2MZyEdg62GjcU4tMzr1yyUr7wGecFkpa2CdRIXVrYzuEzuppRFvCljMaAB0wJRMNlcAaBrAj6ylbCEETz5NxdmtSRWuAPXgtvV3xz7_ImZxK9XexlRwQuABiTOD2JI79VY7LjS65SngIRmrLRDToAod5-hTITqJaIbVATy1eyCfaVmIXljFYTPfr-f3SGsYLFRrtvTaiMVjMrKzRuIHWdNzFnhuKSA8qhHJvyMzNOlE_WJd7WeIVvGxy4lcF0NfrAiiZdX8xjPkCHENudZBMgIaNuRehFEFXR0bD-obMhF99RLQ81eFC5orr0M~&v=404&seq=1&n=pcwap","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://srv-2018-04-15-11.pixel.parsely.com/plogger/?rand=1523791986117&idsite=fandom.wikia.com&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&urlref=&screen=360x512%7C360x512%7C24&data=%7B%22parsely_uuid%22%3A%22540b3876-8bae-41e2-acd1-875528779878%22%2C%22parsely_site_uuid%22%3A%22cae1ee6a-be80-4cc8-bbdf-d9bcecbdcfea%22%7D&sid=1&surl=http%3A%2F%2Fwww.wikia.com%2Ffandom&sref=&sts=1523791986086&slts=0&title=FANDOM&date=Sun+Apr+15+2018+04%3A33%3A06+GMT-0700+(PDT)&action=pageview&u=cae1ee6a-be80-4cc8-bbdf-d9bcecbdcfea","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://sb.scorecardresearch.com/p2?c1=2&c2=20632726&cv=2.0&cj=1&c7=https://www.reddit.com/&c4=https://www.reddit.com/","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/sync?mm_user_id=4b9e5ad3-32b3-4100-aec0-634f1b8ae61e","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/uncivil-war-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/wattpad-android.png:l","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/76/BB0313.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p4.qhmsg.com/t0189741dcf6c159d34.png","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"http://xw.qq.com/index.htm","request_type":"html"}
+{"origin":"http://www.weibo.com/","request_url":"https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F%3F%26jumpfrom%3Dweibocom","request_type":"html"}
+{"origin":"http://www.blogspot.com/","request_url":"https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmSU5fBBc4AMP6lQ.woff2","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-cc-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan41510.jpg","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-form-0.1.js","request_type":"script"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/security_edge.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/fonts/roboto-400.woff","request_type":"font"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/pingjs/ext2020/xw-next/_next/8a6265c0-8cc2-4bd6-9b10-557557ae7372/page/_error/index.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/dust-helpers-0.0.154/intl-messageformat/intl-messageformat-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-drawer_feedback/td-applet-viewer-templates-drawer_feedback-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/crossimage/4.1.25/index.js","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i&subset=vietnamese","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/dp.mobile.min.js?v=-17637-17637","request_type":"script"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/gen_204?atyp=csi&ei=-DfTWqiNHYaC8AOtuL_YCg&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.369,dcl.334,iml.369,ol.2607,prt.184,xjs.1540,xjsee.1540,xjses.1331,xjsls.189,wsrt.2086,cst.667,dnst.0,rqst.756,rspt.379,sslt.364,rqstt.1625,unt.2010,cstt.957,dit.2420&zx=1523791867390","request_type":"html"}
+{"origin":"http://www.hao123.com/","request_url":"https://as1.m.hao123.com/bwofcvxcvzdec.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yx/r/2UF0SrjH0Fk.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/316nxKpnxGL._RC%7C51gvQ0ZsBLL.js_.js?AUIClients/SharedShoppingCartMobileAsset","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yS/r/uZQyby1VMSK.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770055&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791992676&fs=1&pvid=df5e800560a7e9a4279a3992d8fbff27&cg=a8ba89d983479a1fbfff5e65c031fc07","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1523791946620&yhlClientVer=3.42.4&yhlRnd=E9i3oU4yHtBBiqO9&yhlCompressed=0","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.advertising.com/ups/28/sync?uid=91191954147729940174299115411397659455&_origin=1&redir=true","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://rtd.tubemogul.com/migrate_et3/","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/ny75r2x0?redir=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537148856%26val%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/stylesheets/base-min.css","request_type":"css"}
+{"origin":"http://www.wikia.com/","request_url":"https://sb.scorecardresearch.com/p?c1=9&c2=8188709&cs_xi=L6N7iig7&rn=1523791989","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.facebook.com/tr/?id=1097950916987081&ev=PageView&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1523791868764&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=28&it=1523791867576","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DXZ4D3PPDB36HTEGXD7ZH%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D9959%26pc0%3D9959%26ld0%3D9959%26t0%3D1523791920503%26csmtags%3Daui%3Asw%3Aunregister%3Asupported%7Caui%3Asw%3Aunregister%3Aunsupported%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DXZ4D3PPDB36HTEGXD7ZH%26aftb%3D1:9959","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://www.hao123.com/images/track.gif?hjf=hao123wise&type=KTN&code=0&tn=&src=","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/qxx_R2lwF9JfNbtMoMyK2x73XezkYruSM6CVrLVpLqZ8CCxiWOdbIn8aR9kjsw=w384","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.weibo.com/","request_url":"http://www.weibo.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.1rx.io/usersync/tradedesk/2e68b153-5f6c-4bef-a554-4d86b35719b5","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/images/tpb.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvT5iN.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/d5/32/a3/d532a36c39ad7b7222f9e596cb8ea783/d532a36c39ad7b7222f9e596cb8ea783.6.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201708/30/130546331/original/(m=eafTGgaaaa)(mh=wexeyW8GiTjEkmTJ)14.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/814L6pG1+CL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/xba/Unrec_MD_1242x450_Men_Apparel_April18._SX1242_CB502495893_.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/images/favicon/favicon.ico?v=1","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/home-illo-team-tools.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://js-sec.indexww.com/ht/p/186948-60896576130421.js","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/runtime.2151fae21e83d945.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://log.mmstat.com/eg.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/template.js","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=MB94w7N&sid=yLIOFNP835fT4D41H3-W","request_type":"other"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12426&impid=&at=1&mkey=&latcy=3509&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=7719377039646&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791941707","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/secure/Passport.aspx?popup=1&ssl=1","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://cookiex.ngd.yahoo.com/ack?xid=okh7czkkiqBWuhfjRC2WCrKp&eid=JG0QC2PD-14-82AL","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns2.gigya.com/js/gigya.services.socialize.plugins.simpleshare.min.js?version=latest","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://ing-district.clicktale.net/ctn_v2/auth/?pid=100&as=1&m=1&2073882682&subsid=233200&msgsize=10","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://analytics.twitter.com/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvx41&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=1&tpx_cb=twttr.conversion.loadPixels&tw_document_href=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://pixel-a.sitescout.com/connectors/clickagy/usersync?redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D5%26cm%3D{userId}","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=32&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A32%7D&logFlag=uaction_1523791857874&t=1523791889876","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=doubleclick.net&google_gid=CAESEOW00xhK6Zfa7zKF3m-RdPQ&google_cver=1","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ping.chartbeat.net/ping?h=cnn.com&p=%2F&u=Bg-_S0CPI_zfC67xAZ&d=cnn.com&g=37612&n=1&f=00001&c=0&x=0&m=0&y=9427&o=360&w=512&j=45&R=1&W=0&I=0&E=0&e=0&r=&b=43447&t=CLOipOB46i75vfzaRBu0MQYD7tsX2&V=103&i=CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos&tz=420&sn=1&sv=f0HQNqdKEhCdqfBAN73aHDg_Q16&sd=1&im=067b2ff3&_","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=98&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A98%7D&logFlag=uaction_1523791857874&t=1523791955876","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://alb.reddit.com/i.gif?q=CgADBQAbKUR6on8KAAUampD8jBJivggABwAAAAEKAAwFABsqW4nlFgA=&s=hYo4Ma260PkKGBFEjI5b8nfdqKZtWu3GLAgkEfppl1s=","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/msn-msn-home/log/3/available?ri=6ace2f377fc832c6da1b1162c9b73c48&sd=v2_a839064e4dc128f89e336e1585d06e96_39041E2B94ED6EF00CB315F995BE6F73_1523791842_1523791842_CIi3jgYQy9c-GMWRycisLCABKAUw4QE&ui=39041E2B94ED6EF00CB315F995BE6F73&pi=/&wi=6400712663452445953&pt=home&vi=1523791841477&li=rbox-h2m&utm=16%2C1005%2C1223%2C1981&mgo=1&df=1&tim=04%3A30%3A42.827&id=6470&llvl=1&cv=301-1-RELEASE&fil=%5B%7B%22tii%22%3A%22%7E%7EV1%7E%7E-1273162598355568230%7E%7EsywQLJLG5-DX7BTGAsEBn9bQmahfdgbaU8izW4nQZB4SO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT5dYIwm9x5LE1ZLaf5R3jrk4uXCbI3L_AIvK5xufD_BzOaUNEGWW-aaMsKe7nktpFIred4j01i6FT7BrFdjZFiOaovLaBM-ASdloTYj_VHN1cviRZeZjJYk5ibISviXXm46zhr_uog6GC70OqLAd6RE%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E-8658081786023064260%7E%7Ec3p_OSL2SISi_ONehqCz7_BsirVTE1yczVypi12KbXoSO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT6v3u32iWirHrqPEmiXknc84uXCbI3L_AIvK5xufD_BzOaUNEGWW-aaMsKe7nktpFKIFsz9NieMLRzXehUQt9OdBTfF7GLq4QsCyjBbGu2CSACZ7srabkN9vYex-rkkiD9GZ-dH2cnCblbBNEGq-IcvTp4NGcPg_7MZQK_AqIrwa%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E-4781684930521836651%7E%7EDzf_FNvWWUImzzosa5RSEf0a1qrAIOsfaUliATunCQQgADLX0sCLI84lvxeYoNVBXtEiVLHvk6BFwXvQihx-5mB_GLQKpZ-E1961NN8l4cxMRcC1HUqLKGzVuQ0uTpxX3kjgZ-VSqH9qM20zEbbygaowzPcwqce1nMGnTHPSM2wkubBbs4TEeP_qZa1u1SU9reqEP7qdxfU45vG1sTgGYs3C2Ehmvbaik4h6tlTomGWe9ai2ANFMgxbNzFLyjdKe%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%5D&","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/uedata/unsticky/258-8151141-7687141/NoPageType/ntpoffrw?at&v=0.200436.0&id=49NGBMVT1ABRN6GGR916&ctb=1&m=1&sc=49NGBMVT1ABRN6GGR916&pc=14271&at=14272&t=1523792001117&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=49NGBMVT1ABRN6GGR916&aftb=1","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d12907924.gif?sz=21&rnd=326431878&ts=1523791836&sz=21","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1121&dpuuid=1188176249146601940","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/vi/shopping.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/security_keys/insert-vflkCfC4_.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/tirego/albumset/15456000/zoomcrop/75x75.jpg?v=1521076052","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_bleacher.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"http://www.so.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_15698&impid=&at=1&mkey=&latcy=3431&freq=&turn=2&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=1726717314434&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&_time_=1523791947133","request_type":"html"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"http://mail.ru/","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/04/15/1523785408_20180414-00000071-mai-000-view-x104-y104.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/32/64/84/326484f662a69575c3342d2b481b2f40/326484f662a69575c3342d2b481b2f40.12.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/03a/009/33e/big_lq/8b94f7d440cf51501360a9e9cbdbec83.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d78ee4522249258fc6c1a674f88dc72b_erotic_445x250.jpg?cno=a938","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/producer.svg","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://ssl.google-analytics.com/ga.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://d31qbv1cthcecs.cloudfront.net/atrk.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/js/bg/-AZv2KuCjcgKyHntfopJPbiyNz6ONfW7PV3A4azG2L0.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/mg_modal-1.0.0.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41DF6mj397L.css,31-8Mn1M1oL.css,31ZYydvXTIL.css,11tkAOwE6OL.css,21xItms32EL.css,11q7D6YoQCL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,01kwuiPOKIL.css,41SYzOsGaLL.css,017SKMFW8lL.css,21QwDiO8ycL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11ZLLOcO8BL.css,01D-B-OeNDL.css,21CNSKZ67ML.css,11rhPo030XL.css,11G8UP3P7ML.css,51oAYplAOyL.css,21LCBYGBqCL.css,21lDMA2J74L.css,31m2Sw3bVfL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21UuKlej9VL.css,61lDBjn6HPL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,01QRe-mUhyL.css,31LBzl8T3vL.css,21DFs8eEV-L.css,01YdhMxma0L.css,11cAYJlTEgL.css,018mGORJ7tL.css,11fvu+DzMxL.css,11iDQvZvByL.css,01lh9w-GYYL.css,21oomsDVWML.css,11Mso4bvY-L.css,01LCsoCesOL.css,01NEM4SRd9L.css,01qwEWNuxuL.css,21pnh6VHUzL.css,01YXqSisf3L.css_.css?AUIClients/DetailPageMobileWebMetaAsset","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/?vit=h123&from=3w123","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/icons/beta/CNNSansW04-Regular.woff2","request_type":"font"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://js.ptengine.jp/22c266ff.js","request_type":"script"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/gen_204?atyp=csi&ei=DjjTWvfeGYaB8AOat73oBA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.17,jhsl.2190&rt=aft.407,dcl.404,iml.407,ol.2817,prt.208,xjs.1581,xjsee.1581,xjses.1328,xjsls.214,wsrt.2189,cst.707,dnst.0,rqst.797,rspt.409,sslt.381,rqstt.1707,unt.2105,cstt.993,dit.2591&zx=1523791889557","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100100868&apid=beans_12290&impid=0cfb5d642e74493b6_0_0&at=1&mkey=0cfb5d642e74493b6_0_0&latcy=5081&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=6049.71875&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DtnCj%2F9anXG4vLMII9POpPKjvinbYz7muQ36Did%2FLZbR8eyfrMpt7XgPXYPv0PhAfy1anxpv9JadjgHr5D5YAJzf6bURoTS3ZBI4fmEbch%2Fhuh6gu3du2s6U5kg5aizXHDGHrC62J4SIPQc1ZBYQVuS3cpNMM%2BfNI0Q3M0cAAv%2B3IqILwzGOFEPmlFz7tJTwUjLOYq5j0BoJvd45I4ZMO9j93axywsvkOfTbTZ564%2BL3AqLwaHv7HzrFCaIBlg6g4Met1GCaQT0ZoDeMsVimzAO9r%2F9eX7JJKXdWBE0T%2BX0D7Nuanh4TrYM05bYqHYQg1eqgswdHpWdvRSxc3%2Bg5PtUtAnuKGicaGXlxD%2B3VpBsTYFj2TFuuOPQJGIJGI5BKEWCB1wlm4fJa%2F%2FUosZrl0EkrnIwrTkc%2FiAis5eh5IQIO0C7mVim7SCBJC88r0QtOYe0wFqWDSWra8GoaQui5dIaNaE08lHKjV9%2FXh91f4yOc1b3oTdNLHvtOwTp1K66iByn5RW8PqrCk2xKKB9U%2F%2Bd%2BeE54XN1CNAkyLIv7kt8DmKD9cLlkVC1UcBmzOG%2FpKrDJqhXT1bPODw8ZN%2BRQwERT6%2B1Hc3JB%2FBothBY9%2BKVXE%3D%09tt2%3D1523791943074%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=6038812923145&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791943363","request_type":"html"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/hao123_api/osc/report","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"http://vk.com/","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51LGid1qdxL._RC%7C01BL18zkkEL.js,31a72IenKyL.js_.js?AUIClients/NavMobileMetaAsset","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://cs.nex8.net/precs/nend","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mid.rkdms.com/bct?pid=8bc436aa-e0fc-4baa-9c9a-06fbeca87826&puid=86070857378125119120981354726841823876&_ct=img","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://c1.adform.net/serving/cookie/match?party=14&cid=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"https://tags.bluekai.com/site/24667?ret=html","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=mplatform.com&id=11459057411035310902","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://pcookie.tmall.com/app.gif?&cna=0CVaE5MQoWcCAdBGH10BYLR6","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cms.quantserve.com/dpixel?a=p-n5vvLvRdjg0ek&eid=0&qc_google_push=&google_gid=CAESEEOTwoBaRjPqNdk8kFjXrUo&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/summertime-saga-android.png:l","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/u1UAAOSwJtdaTAuZ/$_57.PNG","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/top-jdlogo.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/icons/rss.png?1372079637","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1FDOHLVXXXXcZXFXXXXXXXXXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://www.coccoc.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.krxd.net/partnerjs/xdi/proxy.3d2100fd7107262ecb55ce6847f01fa5.html","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmYUtfBBc4AMP6lQ.woff2","request_type":"font"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/OkUAAOSwUn9aTA7G/$_57.JPG","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1TPtnLVXXXXXwaXXXq6xXFXXXu.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180315070729-cnnmoneytoysrus1-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4156.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMzZhNjYyZDYtZmE4MC00M2RlLTlhOGItZDVkYTVlZTYxOWZlXkEyXkFqcGdeQXVyNTAyODkwOQ@@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_blue.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://www.googletagservices.com/tag/js/gpt.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://hotword.sogoucdn.com/hot_word.json?callback=_getjson&_=1523791937755","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yjtag.jp/tag.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/promo-banner.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v3/js/libs/jquery.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/nav-category/4.2.0/index.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://fonts.googleapis.com/css?family=Lato:600,500,400,300","request_type":"css"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/bannertext?bannerid=52375&zoneid=613&","request_type":"html"}
+{"origin":"http://www.twitter.com/","request_url":"https://api.twitter.com/1.1/jot/client_event.json","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/","request_type":"html"}
+{"origin":"http://www.linkedin.com/","request_url":"https://platform.linkedin.com/js/analytics.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://m.aliexpress.com/api/recommends?page=1&streamId=eb21c233-4835-3808-a4ff-4bd7c1b6e320&__amp_source_origin=https%3A%2F%2Fm.aliexpress.com","request_type":"script"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/scripts/vendor/yahoo/rapid/rapidworker-1.2.js?_v=70c488012831cd8276d74fd06a89ce09","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/js/scripts_1.19.js?v=1","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync-tm.everesttech.net/ct/upi/pid/NC4WTmcy?redir=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner_id%3Dcb276571-e0d9-4438-9fd4-80a1ff034b01%26puid%3D%24%7BTM_USER_ID%7D&_test=WtM4BQAAAGWhsjF0","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo1MC4xMzgJM2QzMzZkYjEtYWVhOS00NWY2LTk4OGUtMjUwZmUwZWZhYzEyCTMyMzUxNzIJMzExMDEyNgk1OTE4Mjg4Mzc0X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc4MAkzNTAwMDY5CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQk2Njk5MGYyNC04NzA2LTMwZjItOTdmMy01NzVjMGZlNDY4NDMJNDc4NTIJMC4wMDEJMTQ5LjIwLjYzLjEzCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAkwCXRydWUJTkFUSVZFCVdBUAktCTAJX18xNDkuMjAuNjMuMTNfMTUyMzc5MTgyMF8wLjE5MjM0ODAwCVdBUF9GRUVECS0Jbm9ybWFsfHV2Zm0tcnQJLQl1c2VyX3RhZzoyMDk1OTowLjB8d2FwX29zOjcwMTowLjB8dXNlcl9hZ2U6NjAyOjAuMHx1c2VyX2dlbmRlcjo1MDE6MC4wfHZfem9uZTo3NzcyODA6MC4wfG5ldF93aWZpOjExMDI6MC4wfGNyb3dkczp8X2Nyb3dkczoJNAk1MDAwMAkyMDAwMA==&userid=__149.20.63.13_1523791820_0.19234800&auth=d44ad670d8c1abc9&p=ZpkPJIcGMPKX81dcD%2BRoQ5qmM%2BCipe3nQ3XMlw%3D%3D","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=2682&partner_device_id=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/spectrum/index.web-vflCr8xOd.css","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/x/px/QhdWt-tWjhri7spkrnLywhsAAAFiyRTlPAMAAAGbASfNJR8/nii/%7B%22ni%22:true%7D","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://aax-us-east.amazon-adsystem.com/x/px/QuJYhs8MrEk8ipS4nCca2O8AAAFiyRNVyAEAAAGQAV3sMG0/nii/%7B%22ni%22:true%7D","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://rover.ebay.com/roverimp/0/0/9?imp=2046301&trknvp=cp%3D2380057%26ghi%3D96&1523791928074","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.facebook.com/tr?id=829253787145710&ev=NM_landing&cd[value]=9.99&cd[currency]=USD","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a671d6100015ad3387e3b6a70c073d3&pid=mm_113716014_12970037_52768233&cid=264978&mid=2582&oid=151&productType=1&qytInfoMTime=1523728959&e=U6R4%2FzvHSW2GJgTPtIvipov2AF8i9cmhIsrNrCuyMRA6DeY4QxOWrJhmDc7TdLie&k=65&cb=666386368","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://pcookie.aliexpress.com/app.gif?&cna=TSZaEz0rIjECAdBGH10HDyi3","request_type":"image"}
+{"origin":"http://www.onclkds.com/","request_url":"https://www.google.com/ads/user-lists/983473429/?random=1523791874579&cv=9&fst=1523790000000&num=2&label=0_cMCPultwYQlbr61AM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&fmt=3&cdct=2&is_vtc=1&random=1305995727&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://sp.analytics.yahoo.com/spp.pl?a=10000&.yp=10023913","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://m.jd.com/images/index/jd-news-tit.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/remote-play-android.png:l","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/vdp_16.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://img.alicdn.com/tfs/TB1Kxe8QFXXXXbSXVXXXXXXXXXX-183-129.png","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://sync.1rx.io/usersync/tradedesk/fa8c47ba-24f3-4aba-b46d-92ab3e0f2339","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://cdnetworks.cedexis-test.com/img/17653/iuni3.html?rnd=-1-1-13960-0-0-17653-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/370000/370329/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/B8/D37BFE.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-cc-stock-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/a8/49/19/a849190da25adb4c9699314a473ecee8/a849190da25adb4c9699314a473ecee8.24.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20160816index_260x50.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/039/117/36f/big_lq/e220d154796ea1d8d4ca04d7c2e6d927.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/01c/001/1e6/big_lq/d1fe5c0a8796e0b532ddd24894288f22.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/06/bf/38/06bf38372684239545c2e3564663a656/06bf38372684239545c2e3564663a656.6.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/csfNSln.9d4Q3j2ajPsyXA--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-GB/homerun/newsweek_europe_news_328/ae7a623843a87ab6fca99b5d46618d68","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/concat/common/js?h=69w33ou4umkyupw2uqgn7za7w","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_194.js","request_type":"script"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/MobileSiteBase/cc,nc/8d0342e9/e3492d89.css?bu=rms+serp+Mobile%24mobileSite_c%2cMobile%24mobilesiteandroidhigh","request_type":"css"}
+{"origin":"http://www.wordpress.com/","request_url":"https://pixel.rubiconproject.com/tap.php?cookie_redirect=1&v=8981&nid=2307&put=ecf97925-4f99-4dc2-9bf7-6775e63a3ba0&expires=30&next=https%3A%2F%2Fmatch.adsrvr.org%2Ftrack%2Fcmf%2Frubicon","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-534da2e96b8ae7c6840004b9.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://z.moatads.com/jwplayerplugin0938452/moatplugin.js","request_type":"script"}
+{"origin":"http://www.google.com.hk/","request_url":"http://www.google.com.hk/","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=963839304&t=pageview&_s=1&dl=https%3A%2F%2Fm.pixnet.net%2F&ul=en-us&de=UTF-8&dt=%E7%97%9E%E5%AE%A2%E9%82%A6%20PIXNET&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAEAB~&jid=1321578915&gjid=2122442467&cid=151777037.1523792004&tid=UA-20543617-6&_gid=373776111.1523792004&_r=1&z=90343270","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100272259&apid=beans_12282&impid=0465f38f22db3cc4b_0_0&at=1&mkey=0465f38f22db3cc4b_0_0&latcy=4644&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=5415.046875&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DHwvF1ZPDXjYxrDJwjSgO1q3namOkBU0CeIU5yEsMX16D%2B4S2htmjlkxL7S0q%2BzbomgqL%2FV2WmOyfTsHHrAP1icv7MByIWMRRrDhyHi%2FVVdSxtwUdthv6C3ZNVUdgNrTrgB%2FLLFbIW76xw4Pj%2B6iKxxbMLpkani84vG9d3vCBQMxmCQvk%2FBmfpl7mWJ78fenFU%2BzMEvxY4bZsoDNVS%2FwCNxO9kPdlWQEAM%2FFSsto8iwOmh8U%2B%2B6N3Wwiso7axvsEqgoUxV93HGHi4sWNrrNqZvBCXtaJlwaeVqn4xmszMOTbpo%2FBhwO1q6CbpNt7mz7MxigTwA5zkwWjO7RQ6wx8awbIFI3M7hE0J6NeLUzqhp8LZR4R9mGgu%2BwYy8GZtwerfzMLaC%2BAhfVColxwWUFe2H7z6m0sG14Rhm%2B7BNhtBGHHs2UgdUgF821dV%2FpCxZl2r3cUxHmd48BAEnuviHECwNRpromNf3peJPnXvfldNBgxwanGtyaifrNgYTLGUYMd9Z%2BBwqXMzTaph80KH0VfR7xfTIQnJIFdWth2BPO3UIRQ5l%2BVqZne4KBemU7kXQd7JvI%2Fk%2F%2BTTyJOP%2BaC6yQ7wPIwRFTAq8wVI12mokUUnEZw%3D%09tt2%3D1523791942596%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=2566080122728&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942905","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/t_tkr/errlog?col=0&filename=&line=0&x=0&y=0&pvt=1523791869849&stime=1523791889485&etime=1523791889485&p=764344014241209959&pv=1928825100107055743&page_url=https%3A%2F%2Fwww.cnn.com%2F&w=360&h=512&fmtid=6&crid=1921695025290282899%2C1918292139302716419%2C1916679378487477386%2C1915917157520115246%2C1902252717768542290&e=0&wh=SDKRE&location=https%3A%2F%2Fwww.cnn.com%2F&desc=Script%20error.&v=9.4.10-b-301","request_type":"script"}
+{"origin":"http://www.onclkds.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/995032169/?random=1523791874542&cv=9&fst=1523791874542&num=1&label=_iK6CP-_7xcQ6fi72gM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=9ff8d5e0-40a0-11e8-9a44-e3ec051157a6&ex=adelphic","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.de&slot=navFooter&a2=0101581c268c9590c381ec0d82e498caa555c5b075dc1f07a28c1ce2a20e87703072&old_oo=0&cb=1523791986634","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ps.eyeota.net/match?bid=6j5b2cv&uid=86070857378125119120981354726841823876&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30064%26dpuuid%3D%7BUUID_6j5b2cv%7D","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/css/collections/mobile/upsell-ad-988557879._CB499613550_.css","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/pms/img/st.gif?ts=9oe&sid=jg0qejmoia3&ht=3&fs=729&drt=2448&lt=11525&product_id=9&page_id=9_3252&browser=20&wtt=4882&dns=0&ct=1122&st=2244&tt=5159&dct=16405&olt=16411&_screen=360*512%7C360*512","request_type":"image"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-108242619-1&cid=1866685655.1523791909&jid=2034509058&_gid=1525920554.1523791909&gjid=1310802496&_v=j66&z=592075546","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://ib.adnxs.com/getuid?https://trc.taboola.com/sg/appnexus-network/1/rtb-h/?taboola_hm=$UID","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=1428&frame_width=1004&iframe=0&title=%E5%85%89%E6%98%8E%E7%BD%91_%E6%96%B0%E9%97%BB%E8%A7%86%E9%87%8E%E3%80%81%E6%96%87%E5%8C%96%E8%A7%86%E8%A7%92%E3%80%81%E6%80%9D%E6%83%B3%E6%B7%B1%E5%BA%A6%E3%80%81%E7%90%86%E8%AE%BA%E9%AB%98%E5%BA%A6&time=1523792008214&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fwww.gmw.cn%2F&random_number=8517962940&sess_cookie=6af870ac162c914d411cb11f1c7&sess_cookie_flag=1&user_cookie=6af870ac162c914d411cb11f1c7&user_cookie_flag=1&dynamic=true&domain=gmw.cn&account=4+gli1aUCm00OA&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/paypal-logo.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://m.360buyimg.com/img/jfs/t2977/335/1927273397/18081/64a032d5/5796df21N0c6edd4e.png","request_type":"image"}
+{"origin":"http://www.alipay.com/","request_url":"https://www.alipay.com/","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem5YaGs126MiZpBA-UNirkOXehpKKSTj5PW.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/7260a45a-895c-40f9-b496-fbcc91414cbf_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/f44d30758a0c1c3cf07707.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB14oinXq4441JjSZFsq6AB8pXa5.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://n.sinaimg.cn/default/transform/266/w640h426/20180415/Y-uS-fzcyxmu9462290.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/ef7044680f584144a3ace75802678615.jpeg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img17/movies-tv/Oct/280x280_Quadcard_2._CB514398926_.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/n3ja2Q-YKysLo9z0cwZYXK503p68nfubmNYc0sLXXsQ.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/digital/video/placement/Gateway/launch/Baywatch/non-exclusive/Baywatch_DE_NonExclusive_XSite_GWSuperhero_Mobile_1242x450._SX414_CB499100702_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71lh6TEliuL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://d31qbv1cthcecs.cloudfront.net/atrk.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.adsafeprotected.com/sca.17.4.72.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/common/inputs/text.min-vfll6Efz6.js","request_type":"script"}
+{"origin":"http://www.twitch.tv/","request_url":"https://player.twitch.tv/js/embed/v1.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-5916dd0864746d4ae6001259.js","request_type":"script"}
+{"origin":"http://www.google.fr/","request_url":"https://adservice.google.fr/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://cre-dp.sina.cn/api/v3/get?callback=jsonp_038638947826562764&timestamp=1523791825310&cateid=sina_all&cre=tianyi&mod=whome&merge=3&statics=1&up=0&down=0&ad={%22rotate_count%22:4162,%22page_url%22:%22https%3A%2F%2Fsina.cn%2F%3Ffrom%3Dweb%22,%22platform%22:%22wap%22,%22timestamp%22:1523791825000,%22net%22:null,%22channel%22:%2210000%22}&length=13&offset=0&action=0","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/televzr-mobile-02/js/main.min.js?v=2&_=1523791941890","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://dpm.demdex.net/ibs:dpid=139200&dpuuid=2M2U96GHS9OFQD_miznHhQ&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=doubleclick.net&google_gid=CAESEJ8kxTvb7FGIaG74EhC06VE&google_cver=1","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=adobe.com&id=48859258303208673192266743434695837752","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsswtuRyi0A9wt-KNn2XvCj0p0jRtLg11kvAJjQgiIuntwGEnUd9WDCVE-daqwGSrNv3c2BrJ4AQNcgqFdgVORFNLcBSjZCuJhI&sig=Cg0ArKJSzBiwtj8__8B-EAE&id=osdim&ti=1&r=z&adk=3275573252&tt=358&bs=360,512&mtos=0,0,0,0,0&tos=0,0,0,0,0&p=0,0,0,0&mcvt=0&rs=3&ht=0&mc=0&lte=-1&bas=0&bac=0&avms=geo&bos=360,512&ps=360,9427&ss=360,512&pt=-1&deb=1-0-3-8-3--1-2-1&tvt=282&op=1&uc=1&tgt=BODY&cl=1&cec=5&clc=0&cac=0&cd=0x0&v=r20180411","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_4%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D29582%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/quickshortcutmaker-android.png:l","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/vi/reader-mode.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p2.qhmsg.com/t01ecc3b6b24e7bdbd8.png","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=krux&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180404041615-youtube-headquarters-shooting-suspect-nasim-aghdam-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/71/1d/1c/711d1c6c94635cd9a9bee63548c8ebc5/711d1c6c94635cd9a9bee63548c8ebc5.29.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20170720_zggcsy728x90.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://z3.sinaimg.cn/auto/crop?img=https%3A%2F%2Fns.sinaimg.cn%2Fyn%2Ftransform%2F266%2Fw640h426%2F20180403%2FOIe1-fytnfyn7759168.jpg&size=200_134","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/Op56lEjpMcRT-JVLqYT8jw9Z0l0DzSw0xm1_C1FlZuk.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/DE-hq/2018/img/Health-_-Personal-Care/1106413_de_hpc_fibo18_29-3-18_r2_1242x450._SX1242_CB497208892_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31GOYH8A07L._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/iphone/image_small.svg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/logos/logo-black.svg","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-ad_fdb_thank_you/td-applet-viewer-templates-ad_fdb_thank_you-min.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-EmailSignupPage-c2f8d2034314e00b0354.js","request_type":"script"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/313s7mFtcqL.css?AUIClients/IDPMobileAssets","request_type":"css"}
+{"origin":"http://www.sohu.com/","request_url":"https://x.jd.com/mkt/pcwap?ad_ids=3272:5&adflag=0&clkmn=&expose=&ref=https%3A%2F%2Fimages.sohu.com%2Fbill%2Fs2017%2Fmaterials%2Fjd%2F0921%2F3272.html%3Fclkm%3D%252F%252Fi.go.sohu.com%252Fcount%252Fc%253Fappid%253Dwapnews%2526aid%253D100269248%2526apid%253Dbeans_12274%2526impid%253D0f0dbcc288104b396_0_0%2526at%253D1%2526mkey%253D0f0dbcc288104b396_0_0%2526latcy%253D3917%2526freq%253D0%2526turn%253D1%2526pgid%253Dsohu_index%2526ax%253D12.953125%2526ay%253D1701.671875%2526cx%253D%2526cy%253D%2526ed%253D%2526bucket%253D%2526supplyid%253D4%2526ext%253De%25253DOyygn03WYDL%25252BVv%25252F3mNEQdqFmyQMB%25252Fruy3%25252F1xRO6RNFfGs9qthLHF70DQ8pec15VHqZovbVXrzzco7XYsOegVBjcDCze1BpeCimHmb2LvXsKGB9oaN3%25252FU8uLXYHGVdGcROKCRJeS81hJEXPOJIIKfhh6l1THTruIiodwOjJDvGuqB2OztFDF12oTtnMx5oRDrYEuFktpJBq8%25252FvNUYK51Vvh8fiveh5womueMDFo3uJUuniRvire2hLbtfQwvXwBDP9Z%25252FRds5Il%25252Bg9bnkITnNoCyOMzKMhQXJH1qSAQiuwY4VAq7voRegM6gkSuQ0mY4sBtX69iAJOAoKwatrJU1mhZj37lZNqHevo3wzFLEd5LlLrIAADmwPsL1MEZW35%25252B8ppstU0qP7L1JzywfJ6%25252FL3U3LzQgusRb1%25252Fsi8eLgIaFbrbSHH0owgFPgRl7nBYWVzwMeYWcaxLPA3SXVgmHcQwr1wzpMrErZO%25252FDTJdBOcuFKgTp0QpGOBIkUUAe%25252BzBMWP9MzlXIVzma9N%25252BfvWLL344x%25252Fy1L3x0k8U3KXfkA3ICrOJYNAdBtiFsQ3GQQW%25252BC9vfhNbChkAbyKFIKoZGM6C50xrQ%25253D%25253D%252509tt2%25253D1523791941847%252509turn%25253D1%252509geoid1%25253D1410000000%252509geoid2%25253D0%252509source%25253Dshjtsybxpsyq%2526rsln%253D360*512%2526sf%253D0%2526r%253D2927770983255%2526uloc%253D%2526newschn%253D1000000000%2526subchannelid%253D%2526ch_trans%253D%2526jsv%253D%2526ipos%253D1%2526shbd_monitor_ext%253Dc%2526c%253D%2526e%253D%2526pagerefer%253D%2526suv%253D180415193221Z74L%2526source%253D0%2526_time_%253D1523791942196&callback=dsp_1523791946207&r=1523791946209","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://stats.wp.com/w.js?56","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/dd6797289466fcafceda54ba0fd683a6.js?conditionId0=422975","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mjs.sinaimg.cn/wap/project/homev8/8.2.96/homev8/homev8.min.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ml314.com/utsync.ashx?eid=50112&et=0&return=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D22052%26dpuuid%3D[PersonID]","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://adservice.google.com.tw/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://insight.adsrvr.org/tags/l8hfnf9/4gktlyq/iframe","request_type":"html"}
+{"origin":"http://www.google.it/","request_url":"http://www.google.it/","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjstO6-5dJ7w2cugp3v1Nmz8JMQYdQpYKKF5cdvFrig4aL2WeaxCadAWcjFt2PQpRENTmUnbAYcy8UaARDD7jlBgjAjG6GnGIbX9khcYpPyCgxjW5KSRHbT50wVg4eli0LjNsT4UHDjEKqzEGt4r402EhnXv1rGohdM_oAiTzqjfx3WXkx0nKFiVK63vgoHhMQWXypZUOFg9uAZJTTcRIiYXYNJ9HgQ&sig=Cg0ArKJSzMCroA0NehMiEAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/gen_204?s=webaft&atyp=csi&ei=CTjTWq-WFMuh0wKXmq3ADQ&rt=wsrt.2252,aft.414,prt.282","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://staticxx.facebook.com/connect/xd_arbiter/r/FdM1l_dpErI.js?version=42","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://odr.mookie1.com/t/v2?tagid=V2_393725&AMAZON_REGION_SPECIFIC_ENDPOINT=s.amazon-adsystem.com&src.visitorID=IrLEQPU3QJ-Ak-wYxxiWdA","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMxNjAmdGw9MTI5NjAw&piggybackCookie=uid:93d0a0f7-7faf-4e41-a5ce-957bfce40aae-tuct1ccbd91&excid=23&cijs=0","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production//public/content/query/v1/article/search/tag/living?pageSize=12","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://www.googletagmanager.com/gtm.js?id=GTM-KXT7G5G&l=NicoGoogleTagManagerDataLayer","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3ipIu4/y5/l/en_US/0ETmgkbro2p.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://sb.scorecardresearch.com/b?c1=2&c2=17462746&ns__t=1523791960475&ns_c=UTF-8&c8=Diply&c7=http%3A%2F%2Fdiply.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sc.iasds01.com/dtc?ias_callback=__IntegralAS_1cd9a40238057f683cd07d66358c863f_4410&advEntityId=143441&asid=1cd9a402-3805-7f68-3cd0-7d66358c863f","request_type":"other"}
+{"origin":"http://www.ebay.com/","request_url":"http://www.ebay.com/","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D191940%26nid%3D3778%26put%3D%24%7BUSER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://stags.bluekai.com/site/36841?dt=0&r=41309935&sig=266897515&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmih1xvl5HuFzEzhvgXwBlWkmnvTonDUnlAda0QjeWxo0q7s3LSrtVZ3O3f3O3jhe+8hTKsKQvjj3APxvsA7BnDf1H1i9Rp9W1JcNA=","request_type":"other"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static2.dditscdn.com/mbl/frontend_backbone/static/_common/css/armageddon-client-42b1d.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=92&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A92%7D&logFlag=uaction_1523791857874&t=1523791949876","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=fbca&id=KoauPan-R6uDjUaB1jdliw","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://pixel.quantserve.com/pixel;r=736694146;labels=_fp.event.OGtitle.WordPress%20com%3A%20Create%20a%20free%20website%20or%20blog%2C_fp.event.Homepage;rf=3;a=p-3Ma3jHaQMB_bS;url=https%3A%2F%2Fwordpress.com%2F;fpan=1;fpa=P0-1956922903-1523791840672;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1523791840667;tzo=420;ogl=type.website%2Ctitle.WordPress%252Ecom%3A%20Create%20a%20free%20website%20or%20blog%2Cdescription.Create%20a%20free%20website%20or%20easily%20build%20a%20blog%20on%20WordPress%252Ecom%252E%20Dozens%20of%20free%252C%20c%2Curl.https%3A%2F%2Fwordpress%252Ecom%2F%2Csite_name.WordPress%252Ecom%2Cimage.https%3A%2F%2Fs1%252Ewp%252Ecom%2Fhome%252Elogged-out%2Fimages%2Fwpcom-withjetpack%252Ejpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://ib.adnxs.com/getuid?https://aax-eu.amazon-adsystem.com/s/ecm3?id=$UID&ex=appnexus.com&","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://d.turn.com/r/dd/id/L2NzaWQvMS9jaWQvMjg0OTE3NDgvdC8y/dpuid/L6N7iig7","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/barName.gif","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pr-bh.ybp.yahoo.com/sync/openx/94c466ae-1326-a83c-4b82-874a66f1c40d","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-news.png","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/TOYAAOSwB3BaTAuO/$_57.PNG","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t018cea1211d559d0f8.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1cniBJpXXXXataXXXXXXXXXXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1PlmNLVXXXXXEXFXXXXXXXXXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/bK0AAOSwX3FaTAxj/$_57.JPG","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB10Z3WSXXXXXX4XXXXq6xXFXXXz.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/3f7fc520-a649-424d-9a0f-8f9fc8c1f719_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180409/10bf48830cfa1c35045301.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420345085662919.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/016/1cf/0a0/big_lq/013c6698d6cbdbd9f943896c6271117e.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/020/05a/1c7/big_lq/f070ed2e55a3de50532bb7b60376754f.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BODQ0NDhjYWItYTMxZi00NTk2LWIzNDEtOWZiYWYxZjc2MTgxXkEyXkFqcGdeQXVyMTQxNzMzNDI@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/2018/x-site/spring_sale/traffic/1100037_spring_sale2018_traffic_3_mobile_billbord_1242x450._SX1242_CB502011901_.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/dmsmty/212_160_/t013b508d40c5673c53.webp","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17653/1/0/313/ht%20h0-s4003.p12-sjc.cdngp.net/0","request_type":"text"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/1/13960/30623/1/0/340/0/0","request_type":"text"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/sub.svg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://cl5.webterren.com/webdig.js?z=36","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/rtv/011523662348051/ww.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.googletagservices.com/tag/js/gpt.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://api.mixpanel.com/track/?data=eyJldmVudCI6ICJQYWdlIFZpZXciLCJwcm9wZXJ0aWVzIjogeyIkb3MiOiAiQW5kcm9pZCIsIiRicm93c2VyIjogIkNocm9tZSIsIiRkZXZpY2UiOiAiQW5kcm9pZCIsIiRjdXJyZW50X3VybCI6ICJodHRwOi8vd3d3LmVzcG4uY29tLyIsIiRicm93c2VyX3ZlcnNpb24iOiA1OCwiJHNjcmVlbl9oZWlnaHQiOiA1MTIsIiRzY3JlZW5fd2lkdGgiOiAzNjAsIm1wX2xpYiI6ICJ3ZWIiLCIkbGliX3ZlcnNpb24iOiAiMi4yMC4wIiwiZGlzdGluY3RfaWQiOiAiMTYyYzkxNTU4MTFlMjctMDhiNmM5MDEzMjdlYTctODY2NjQ3Zi0yZDAwMC0xNjJjOTE1NTgxMjE5NSIsIiRpbml0aWFsX3JlZmVycmVyIjogIiRkaXJlY3QiLCIkaW5pdGlhbF9yZWZlcnJpbmdfZG9tYWluIjogIiRkaXJlY3QiLCJFZGl0aW9uIE5hbWUiOiAiRW5nbGlzaCAvIFVuaXRlZCBTdGF0ZXMiLCJTcG9ydC9MZWFndWUiOiAiSG9tZSBQYWdlIiwiVVJMIjogImh0dHA6Ly93d3cuZXNwbi5jb20vIiwiQ29udGVudCBTcG9ydC9MZWFndWU6IjogImZyb250cGFnZSIsIlBhZ2UgVHlwZSI6ICJIb21lIFBhZ2UiLCJVc2VyIERldmljZSBMb2NhbCBUaW1lIjogIjA0OjM0OjA2IiwiU2Nyb2xsIERlcHRoIjogMSwidG9rZW4iOiAiNmIzNDdjMzlmMGY1NzA2N2EzNmFjYzZhYTYwMGEwOTQiLCIkZHVyYXRpb24iOiA0LjgwMn19&ip=1&_=1523792046835","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-home-full.min-vflHlqdtu.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-relatedvideo-model/td-relatedvideo-model-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/lib/index.js","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static2.dditscdn.com/mbl/frontend_backbone/static/_common/script/mobile.browser-b3f51.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mjs.sinaimg.cn/wap/online/home/v8/trunk/js/utp-jssdk-1.6.4.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"http://en.uptodown.com/","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"http://www.xhamster.com/","request_type":"html"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://img.scupio.com/html/ls.html","request_type":"html"}
+{"origin":"http://www.live.com/","request_url":"https://outlook.live.com/owa/","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/whatsapp-logo.svg?v=9bd4dace1","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/StatsLogResource/create/","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://trends.revcontent.com/api/v1/?api_key=5f0ad9cae460c2427d2b4e2c9b1729284619dd99&api_source=api_52&domain=propellerads.com&format=json&pub_id=82512&referer=www.revcontent.com&sponsored_count=3&sponsored_offset=0&user_agent=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&user_ip=208.70.31.226&widget_id=94789&revsub[idata]=z1617677zb1858666bcUScp4ph2018041506h","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/11Muzrhwo6L._RC%7C41vNkR6eYDL.js,31XuHZCLcRL.js,11tPmvtDkXL.js,317hoZTRAgL.js,211oGttD+KL.js,31E+vLBB9PL.js,51JVHNZoGKL.js,51nC-xYS8UL.js,21qA3LYJRbL.js,31swJcQcmUL.js,016DBHJkIYL.js,216ts510QRL.js,51byRoBM5yL.js,216nH77ENDL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,51bwJiNVqnL.js,11QIUl6VLbL.js,21AuBaN+lVL.js,518h2Um1TpL.js,01eOSV7qiVL.js,01nKqcvaCIL.js,11f58pNTm7L.js,41cpQgEE+CL.js,01wYyhYnnFL.js,51tAEm6Zv9L.js,117xk5an6TL.js,21kjCAUM3nL.js,31egXBuM55L.js,01RHiyjONOL.js,31zYeTS++kL.js,21CrGn+akTL.js,51MY-BpcKZL.js,31zob0zDCQL.js,11eSkH3Id-L.js,21q5QmCNgJL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,01DShqNIDKL.js,51rCZ2WOe0L.js,71z9MYB3x9L.js,01dIViFgwyL.js,319kjuuQkzL.js,21mtabjvdBL.js,41Y-zbR9+BL.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,110DjWMGeAL.js,11B4fwZPeqL.js,214q28gHRFL.js,113JOW7LkIL.js,01jqyAujTwL.js,01jW+SjLRsL.js,01ajh3SwkiL.js,11+FwDesCML.js,01NAT+3p7KL.js,111vgqp2a0L.js,51vGIS0VrtL.js,01MZJG6lH8L.js,01VtYReatCL.js,21vc9PfFLNL.js,41R8mzOgv0L.js,01RQtSMdG+L.js,11ZcUC5H2zL.js,21QpjYSxZxL.js,31TWUyCwSsL.js,01c01jT1vpL.js,01qwoVEkKlL.js,011HXD1ky3L.js,211-EFs8MpL.js,01IfU37ic3L.js,31MKsGjr-cL.js,01ZF+ovNflL.js,31JPVjZ0jGL.js,01S8y9NkxoL.js,019ztXtdUIL.js,117+VK79ITL.js,01JP6NKfZOL.js,01MEbpLZWbL.js,51tlWANRbLL.js,01y-5aCXJyL.js,01rg6Ce9FhL.js,01c1fUAHkJL.js_.js?AUIClients/DetailPageMobileWebMetaAsset","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C41PsXsu4WrL.js,118Wk-h2B-L.js_.js?AUIClients/GWMWebAssets","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ads.scorecardresearch.com/p2?c1=9&c2=6034944&c3=2&cs_xi=86070857378125119120981354726841823876&rn=1523791842111&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D73426%26dpuuid%3D86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.xhamster.com/","request_url":"https://collector.xhamster.com/?log=stats&ref=&_=1523791853004","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://m.imdb.com/uedata?ld&v=0.200481.0&id=6983MGHS2ZBMHXB1G0WS&sw=360&sh=512&vw=360&vh=512&m=1&sc=6983MGHS2ZBMHXB1G0WS&ue=16&bb=1850&ns=1939&ne=2041&cf=2042&af=2074&be=5146&pc=17425&tc=-2821&na_=-2821&ul_=-1523791925687&_ul=-1523791925687&rd_=-1523791925687&_rd=-1523791925687&fe_=-61&lk_=-1761&_lk=-1414&co_=-1414&_co=-625&sc_=-1044&rq_=-625&rs_=-75&_rs=233&dl_=-46&di_=5189&de_=5189&_de=5484&_dc=17424&ld_=17424&_ld=-1523791925687&ntd=-2&ty=0&rc=0&hob=9&hoe=17&ld=17431&t=1523791943118&ctb=1&rt=cf:4-2-2-0-2-0-1_af:4-2-2-0-2-0-1_ld:62-8-3-44-8-0-0&csmtags=fls-na&viz=visible:16&tid=6983MGHS2ZBMHXB1G0WS&aftb=1","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://dpm.demdex.net/ibs:dpid=139200&dpuuid=VsMmnoFtTsW43_GKdn8B2A&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://dpm.demdex.net/ibs:dpid=79908&dpuuid=WtM35B__DJPpGsQgT1fYqPHA&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D124%26cm%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/usermatch.gif?_kuid=L6N62llA&partner=bluekai&bk_uuid=968BnMRR99e2U%2BBS","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=d118fa19-40a0-11e8-8b25-11aafaffedcc&ex=adelphic","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://log.mmstat.com/w.gif?logtype=1&pre=http%3A%2F%2Fwww.gmw.cn%2F&cache=27489db&scr=360x512&cna=&isbeta=7&","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://tags.bluekai.com/site/2981?id=&google_gid=CAESEOhqmnqewDPUlQu1liH9rv8&google_cver=1","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=MGU3MzRkOTUtNTMwOS0zNzMzLWE4MTQtN2ZhOGEwODE1NmIzCTQ1CVBEUFMwMDAwMDAwNTc3ODMJNTAJMzUzMTk4NwkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=147592?dpuuid=2795ec11-ed6c-4da1-bd05-c3dc38544d7b-tuct1ccbd6d","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.google.com/ads/user-lists/961332156/?value=1.00&currency_code=USD&label=ovrQCMHWrWAQvIezygM&guid=ON&script=0&cdct=2&is_vtc=1&random=3935002955","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://sp.analytics.yahoo.com/spp.pl?a=10000&.yp=10014088","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://sp.analytics.yahoo.com/spp.pl?a=10000&.yp=10023913&ec=AllPages","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-price.png","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/v/mhunzsi4yi3fvpe5seocmathp2l.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/yun_70x70.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/pfOxQQNkn-S8TN9jPb-jAEtOF-caZWj-yZQDzp4GPFx2N8pGCdHv_7kajYOr8Q=w768","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p.ssl.qhmsg.com/t0108746fb9d4417925.png","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/img/tutorial-app.png","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://www.taobao.com/","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/ZMNINrKGRozDOl69yIe5fQ/009/337/002/320x240.7.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/gaYAAOSwUM5aTA7F/$_57.JPG","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/default/transform/266/w640h426/20180415/AS8R-fzcyxmu9504398.jpg/w200h134f1t10l50q90c55.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=32974461","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0413/dm_180412_WNBA_Sky_picks22/dm_180412_WNBA_Sky_picks22.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/f44d305ea1ac1c3cfea81f.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/b2/1c/e2/b21ce2e45372c90546511706e4ff3a0f/b21ce2e45372c90546511706e4ff3a0f.23.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5434000/5434447/220x165/2.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41Wo77ejldL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51Ua5RfyCqL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/01.svg","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://www.gstatic.com/feedback/js/help/prod/service/lazy.min.js","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1?$mscomCookies=false&ext-javascript-msfpc=%27GUID%3D78a15c66eb9241ffb31f843be8718945%26HASH%3D78a1%26LV%3D201804%26V%3D4%26LU%3D1523791886397%27","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-legacy-af.min-vflctNlny.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.livefyre.com/Livefyre.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/adobe-head.min.fp-cbcb780889b36325ce240b828aae3bf5.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31LiSGwXxjL.css_.css?AUIClients/SharedShoppingCartMobileAsset","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/satelliteLib-46e65db5bb0c375f8f64619be31cc9b29acf4867.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/gajs/analytics.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://ml314.com/utsync.ashx?eid=50112&et=0&return=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D22052%26dpuuid%3D[PersonID]","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_13455&impid=&at=1&mkey=&latcy=5155&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=1196596735373&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791943447","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100100868&apid=beans_12418&impid=05405a86280e92895_0_0&at=1&mkey=05405a86280e92895_0_0&latcy=2888&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=2046.1875&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DtnCj%2F9anXG4vLMII9POpPKjvinbYz7muQ36Did%2FLZbR8eyfrMpt7XgPXYPv0PhAfy1anxpv9JadjgHr5D5YAJzf6bURoTS3ZBI4fmEbch%2Fhuh6gu3du2s6U5kg5aizXHDGHrC62J4SIPQc1ZBYQVuS3cpNMM%2BfNI0Q3M0cAAv%2B3IqILwzGOFEPmlFz7tJTwUjLOYq5j0BoJvd45I4ZMO9j93axywsvkOfTbTZ564%2BL3AqLwaHv7HzrFCaIBlg6g4Met1GCaQT0ZoDeMsVimzAO9r%2F9eX7JJKXdWBE0T%2BX0D7Nuanh4TrYM05bYqHYQg1eqgswdHpWdvRSxc3%2Bg5PtUtAnuKGicaGXlxD%2B3VpBsTYFj2TFuuOPQJGIJGI5BKEROTaP7w2P8MVY%2BZkQB6OJ4lfipNTDqsXIjuEey4ww6t5ZoA7cH5z0kqM1DXlU%2FsothyGWomcB01Q%2B8HtvpRJ%2F1%2B0eFJ6U4nzZD9J13SNmM6RDqaUKkb94fnYGPEPBkU3avX7bBLRGcx%2BugJENu9ELr4XUycocG2%2BtscSTiw4TSdxWJgROKJ9726d0Ndo6vQHFKFBUasuQxH9KOSUrv%2Bpy8ssttXUmIyYX69n%2BOyfKwA%3D%09tt2%3D1523791940630%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=3257210735415&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791941048","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://secure.adnxs.com/async_usersync?cbfn=AN_async_load","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/anchor?k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo&co=aHR0cHM6Ly93d3cuZHJvcGJveC5jb206NDQz&hl=en&v=v1523554879111&size=invisible&cb=5kzwsemb9jyc","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://cdn.registerdisney.go.com/v2/ESPN-ONESITE.WEB-PROD/en-US?include=config,l10n,js,html&scheme=http&postMessageOrigin=http%3A%2F%2Fwww.espn.com%2F&cookieDomain=www.espn.com&config=PROD&logLevel=INFO&topHost=www.espn.com&cssOverride=https%3A%2F%2Fsecure.espncdn.com%2Fcombiner%2Fc%3Fcss%3Ddisneyid%2Fcore.css&responderPage=https%3A%2F%2Fwww.espn.com%2Flogin%2Fresponder%2Findex.html&buildId=16297c29c33","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938238_7350288561745&itemspaceid=12280&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938238&plateid=1001700000,1001500000","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/api/OxBannerService/logImpression?bannerid=37964&zoneid=614&_=1523791956596","request_type":"text"}
+{"origin":"http://www.twitter.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cookiex.ngd.yahoo.com/ack?xid=E0&eid=WtM34wAACGMfPfyQ","request_type":"text"}
+{"origin":"http://www.imdb.com/","request_url":"https://m.imdb.com/_json/video/ls053181649","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5api.m.taobao.com/h5/mtop.user.getusersimple/1.0/?jsv=2.4.8&appKey=12574478&t=1523791945875&sign=e84676bd547982ceda2ae26189cb6bd2&api=mtop.user.getUserSimple&v=1.0&H5Request=true&type=jsonp&dataType=jsonp&callback=mtopjsonp2&data=%7B%22isSec%22%3A%220%22%7D","request_type":"script"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google.com/recaptcha/api2/webworker.js?hl=vi&v=v1523554879111","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/data/ocs/section/index3.html:homepage-magellan-zone-2/views/zones/common/zone-manager.izl","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://sb.scorecardresearch.com/b?c1=2&c2=17440561&ns__t=1523791908369&ns_c=UTF-8&cv=3.1m&c8=Stack%20Overflow%20-%20Where%20Developers%20Learn%2C%20Share%2C%20%26%20Build%20Careers&c7=https%3A%2F%2Fstackoverflow.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fus-u.openx.net%252Fw%252F1.0%252Fsd%253Fid%253D537072980%2526val%253D__EFGSURFER__.__EFGCK__&google_gid=CAESEPd4Jzcj87qgNvzrB164ELA&google_cver=1","request_type":"other"}
+{"origin":"http://www.twitch.tv/","request_url":"https://video-edge-79f98b.sjc01.hls.ttvnw.net/v1/segment/CrjMzQCf9iogts520o-nIvojRGdI1meYSvwcjr0VnkQ6CrVFxW7lEKnvYLrQ2BGTfJ69YDpyMzw9686uDe0rX51yRxrT3TUe2LnDRCVASvKVbXcaHR0S70LM7PQW7gkGei3cmVUiXYcjforH8U13uB4WHCiNs7LbOQnChHV6k5Qw25AM0ZJFUHoW6LlBTJlcG1HqPbWgxHmV5EWVcyPvRqLmbKa_n4ZJHMl7NvlJ5KpDSV5F3rfryEe-CtMDjTnii3Jp6dYfoKzJZGz6T3ln7noce8m1Hu0rZuIdVnHPk7sS64ETWkiEVn4LtlCOtFxFwfJHiuRt3uBWrKsE89GdSSkM1cSfH5nyKi2dVadbEL1-GxS2d1TweAD1OzsAIop000JGDFJQA14L54nxRCK1UrtvHpQt2JIQBofHxADk-MRkiMo5jYksdSjZn1rSiJwLrjykYK6yy-tn-28JnoW_IeJ0tpKVijxoh53YL_V0z7ExWsMo19qxO4p8xjDe63cs6nj7hXy3r4d24hXh2x8oEmRgOpbU2Q.ts","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://dpm.demdex.net/ibs:dpid=139200&dpuuid=yNo9rhBXTJWOsGNHkfdUjA&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.youth.cn/","request_url":"http://api.share.baidu.com/s.gif?l=http://m.youth.cn/","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://counter.yadro.ru/hit?q;uhttp://m.odnoklassniki.ru/","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:146-2652873-2143838:6983MGHS2ZBMHXB1G0WS$uedata=s:%2Fuedata%3Fstaticb%26id%3D6983MGHS2ZBMHXB1G0WS:0","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/uedata/unsticky/258-8151141-7687141/NoPageType/ntpoffrw?ld&v=0.200436.0&id=49NGBMVT1ABRN6GGR916&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=49NGBMVT1ABRN6GGR916&ue=12&bb=2000&ns=2008&cf=2211&be=2271&af=2293&ne=2364&pc=12721&tc=-1733&na_=-1733&ul_=-1523791986845&_ul=-1523791986845&rd_=-1523791986845&_rd=-1523791986845&fe_=-34&lk_=-1724&_lk=-1422&co_=-1422&_co=-724&sc_=-1115&rq_=-704&rs_=-43&_rs=617&dl_=-5&di_=2287&de_=2287&_de=2287&_dc=12720&ld_=12720&_ld=-1523791986845&ntd=-1&ty=0&rc=0&hob=6&hoe=12&ld=12722&t=1523791999567&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:51-7-4-33-4-0-1&csmtags=aui|aui:aui_build_date:3.18.6-2018-04-06|gwImgNoCached|fls-eu|gwmNoCardHistory&viz=visible:11&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=49NGBMVT1ABRN6GGR916&aftb=1","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/E9/AB2AEB.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=extendtv&google_push=AHNF13KmTePGbbNkw4ua1CWY1YR6KSKyw4nZZZrdYYlEOxXt","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/input/members/left.png?1372079638","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/UqXywnAK0iFScs4XGLCtJQ/009/338/566/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/E9/3D2E9D.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/1b5137a7-5222-44f0-922e-9a55a84ac813_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/81OujN1auRL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://www.ebay.com/scl/js/ScandalLoader.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-footer/td-applet-viewer-templates-footer-min.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://hm.baidu.com/hm.js?48c57cebc84275afcff127cd20c37e4b","request_type":"script"}
+{"origin":"http://www.google.pl/","request_url":"https://adservice.google.pl/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/gp/gw/ajax/card.html/262-9616072-1847409?ie=UTF8&opf_redir=1&rshVal=1523791861745","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://pagead2.googlesyndication.com/pagead/osd.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://quriosity.yahoo.co.jp/v1/recommend/list?output=jsonp&cassette=stm_top&cat=all&crumb=-100&start=1&results=20&lvt=0&crop=on&imgx=192&imgy=192&imgx2=718&imgy2=298&movie_imgx=296&movie_imgy=168&movie_imgx2=608&movie_imgy2=342&lgcode=&extra=off&vtestid=&contentsLoopInterval=5&autoplay=on&autoplayTotal=3&digest=on&digestResults=6&callback=reqwest_1523791947485","request_type":"script"}
+{"origin":"http://www.so.com/","request_url":"https://s.ssl.qhres.com/callback/c8b7de8c67377042/_c8b7de8c67377042/novaWidget.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3iuJp4/yD/l/en_US/371IMf4YfJl.js","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/client/prod/app/global.build.css?_v=b23d43412b37d2eaf065c2f57121e1c0","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/liveperson.min.fp-0232b34deadc0421a8b6a57415f16562.css","request_type":"css"}
+{"origin":"http://www.gmw.cn/","request_url":"http://cl3.webterren.com/1.gif?z=7&a=162c9148979&b=%u5149%u660E%u7F51_%u65B0%u95FB%u89C6%u91CE%u3001%u6587%u5316%u89C6%u89D2%u3001%u601D%u60F3%u6DF1%u5EA6%u3001%u7406%u8BBA%u9AD8%u5EA6&B=UTF-8&c=http%3A//www.gmw.cn/%3F_wdxid%3D000000000000000000000000000000000000000000%26_wdc%3D0%26_wdt%3D012%26&d=&e=10&f=0895c5b17dad3d96&H=www.gmw.cn&E=0&r=6c6af2fea49ca41c&s=0&t=0&u=1&i=en-US&j=0&k=360x512&l=24&m=&n=&o=-7","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQVRKZSEBR7BT5RF15TNH%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D9777%26pc0%3D9783%26ld0%3D9784%26t0%3D1523791975472%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQVRKZSEBR7BT5RF15TNH%26aftb%3D1:9784","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D3P95XKNQTYVQ066DW1Q8%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D12564%26cf0%3D12570%26pc0%3D12570%26ld0%3D12570%26t0%3D1523792025416%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D3P95XKNQTYVQ066DW1Q8%26aftb%3D1:12570","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/uedata/unsticky/260-2953656-0613235/NoPageType/ntpoffrw?at&v=0.200436.0&id=3P95XKNQTYVQ066DW1Q8&m=1&sc=adblk_no&pc=12908&at=12908&t=1523792025754&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=3P95XKNQTYVQ066DW1Q8&aftb=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=30646?dpuuid=E0","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/img/baiduappAdClose2_487e9e9.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t19573/117/1614627888/102825/134b22bf/5ad0563eN7f0ff0db.png!q70.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/static/index/plus/public/tab_news.png","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://hwcdnssl.cedexis-test.com/img/17000/iuni3.html?rnd=-1-1-13960-0-0-17000-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://imageproxy.pimg.tw/zoomcrop?url=https%3A%2F%2Fi.ytimg.com%2Fvi%2FFZhUXOJKoZA%2Fmaxresdefault.jpg&width=90&height=65","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180412120717-granholm-eldred-pic-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2296939556,2935188612&fm=173&app=12&f=JPEG?w=218&h=146&s=1E8A702395CEECEB0EDCD1CA0100C0B1","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://theta.sogoucdn.com/wap/images/ifeng_pic_9.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/311k6OfaSdL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/41WMGzVqRdL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://r.dmp.sina.cn/cm/sinaads_ck_wap.js","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/16999/1/0/310/ECAcc%20(saa%2F8352)/0","request_type":"text"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/mobi/2017/image/elevator_icons_v1.svg","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-captcha.min-vflHcXvEe.js","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-7c788da3aac/v3/js/skins/min/xnxx.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://bat.bing.com/bat.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/mlb/500/scoreboard/atl.png&h=312&w=312","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://syndication.twitter.com/i/jot","request_type":"html"}
+{"origin":"http://www.google.es/","request_url":"https://adservice.google.es/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6865528665029394&output=html&h=280&slotname=5654494760&adk=4108093734&adf=2231601519&w=336&lmt=1523792014&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&flash=0&wgl=1&dt=1523792013440&bpp=46&bdt=11332&fdt=950&idt=1018&shv=r20180411&cbv=r20170110&saldr=aa&prev_fmts=336x280&correlator=5842617019658&frm=20&ga_vid=151777037.1523792004&ga_sid=1523792014&ga_hid=963839304&ga_fc=0&pv=1&iag=3&icsg=2&nhd=1&dssz=3&mdo=0&mso=0&u_tz=-420&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=12&ady=1196&biw=360&bih=512&abxe=1&scr_x=0&scr_y=1&eid=21061122%2C20040069&oid=3&rx=0&eae=0&fc=656&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C360%2C512&vis=1&rsz=%7C%7CoeEbr%7C&abl=CS&ppjl=f&pfx=0&fu=8208&bc=5&osw_key=2111767646&ifi=2&xpc=VpnUcwfyCq&p=https%3A//m.pixnet.net&dtd=1072","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"http://www.msn.com/","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/ImageResolution.aspx?w=360&h=512&hash=99e2f70c0787602dfbe34d372ff08d7a?hpdri","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://idsync.rlcdn.com/382399.gif?partner_uid=39041E2B94ED6EF00CB315F995BE6F73&redirect=1","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.espn.com/core/index?tab=3&render=true&xhr=1&device=mobile&country=us&lang=en&region=us&site=espn&edition-host=espn.com&one-site=true&site-type=full&userab=0","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/bundles/fave/freewheel-dafd4458/freewheel","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/propellerads/js/init.min.js?v=4","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://d.agkn.com/pixel/8198/?che=1523792030&sk=164061102661000501341&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164061102661000501341&ex=neustar.biz","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://sync-tm.everesttech.net/ct/upi/pid/b9pj45k4?redir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D&_test=WtM38gAAAE3-YTsD","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://px.adhigh.net/p/cm/bsw?bidswitch_ssp_id=yieldmo","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://px.adhigh.net/p/cm/pubmatic","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?google_gid=&google_gid=CAESENxzud97JzGBNBoaWQC8R9M&google_cver=1","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=86&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A86%7D&logFlag=uaction_1523791857874&t=1523791943876","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=4&mt_ec=64ws&mt_exuid=&google_gid=CAESEGrWD-U6m29Ij2smNC7PmWU&google_cver=1","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_searchbar-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/images/icons/blue_arrow_2x.png","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_13413&impid=&at=1&mkey=&latcy=567&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=8552409664064&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&_time_=1523791947511","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/uk-sports/brands/AquaSphere/BrandStore/Marketing/Gateway_1050x1050_Lita2._UX350_SX350_CB532265858_.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/034/26e/116/big_lq/481db47af162ee3b3a0b61ac910385b7.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/33/2f/d8/332fd8cb6d0f903347f825f9d3f44079/332fd8cb6d0f903347f825f9d3f44079.11.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2/freeform/WebsiteDetect?source=wwwhead&fetchType=css&modalView=nmLanding","request_type":"text"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_cherry.svg","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/libs/t/finalboss-lite/0.1.7/finalboss-lite.min.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/flipbook.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/alameda_bundle/alameda_bundle.envified.min-vfliR8lKl.js","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-330a38ae1d0/v3/js/skins/min/xnxx.header.static.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/entryChunk-webpack-2a3d5e734628fb962e40.js","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://az725175.vo.msecnd.net/scripts/jsll-4.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/mobile/website/img/flm-onehouse-apptile-180.png&w=240&h=240&transparent=true","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41DF6mj397L.css,31-8Mn1M1oL.css,31ZYydvXTIL.css,11tkAOwE6OL.css,21xItms32EL.css,11q7D6YoQCL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,01kwuiPOKIL.css,41SYzOsGaLL.css,017SKMFW8lL.css,11V6-eXxKOL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11ZLLOcO8BL.css,01CCLEN08lL.css,21CNSKZ67ML.css,11rhPo030XL.css,11G8UP3P7ML.css,51oAYplAOyL.css,21LCBYGBqCL.css,21lDMA2J74L.css,31m2Sw3bVfL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21f0r7D13IL.css,61lDBjn6HPL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,01QRe-mUhyL.css,31LBzl8T3vL.css,21c4cPN57WL.css,01YdhMxma0L.css,11cAYJlTEgL.css,018mGORJ7tL.css,11fvu+DzMxL.css,11iDQvZvByL.css,01lh9w-GYYL.css,21oomsDVWML.css,11Mso4bvY-L.css,01LCsoCesOL.css,01NEM4SRd9L.css,01qwEWNuxuL.css,21pnh6VHUzL.css,01YXqSisf3L.css_.css?AUIClients/DetailPageMobileWebMetaAsset","request_type":"css"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://js.ptengine.jp/pta.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gpsfront.aliexpress.com/getRecommendingResults.do?widget_id=5063232&phase=1&limit=6&imageSize=220x220&platform=msite&__amp_source_origin=https%3A%2F%2Fm.aliexpress.com","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://sb.scorecardresearch.com/p?c1=2&c2=7241469&c5=1197228339&c7=https%3A%2F%2Fwww.yahoo.com%2F&ns__t=1523791945716&ns_c=UTF-8","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.amazon-adsystem.com/iu3?cm3ppd=1&d=dtb-pub&csif=t&dl=rbd_ox_pm_an","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fwww.facebook.com%2Ffr%2Fb.php%3Fp%3D1531105787105294%26e%3D%24%7BTM_USER_ID%7D%26t%3D2592000%26o%3D0","request_type":"other"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/css/front_set.css?1391017485","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=106&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A106%7D&logFlag=uaction_1523791857874&t=1523791963876","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/uedata/unsticky/358-6685975-3653550/NoPageType/ntpoffrw?at&v=0.200436.0&id=QVRKZSEBR7BT5RF15TNH&m=1&sc=adblk_no&pc=9790&at=9790&t=1523791975478&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=QVRKZSEBR7BT5RF15TNH&aftb=1","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=540&dpuuid=35117910-40a1-11e8-a553-0242acc1cc07","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=880546608&t=event&ni=1&_s=4&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=card&ea=69286&el=view.item-0&_u=aEDAAEAB~&jid=&gjid=&cid=970841907.1523791982&tid=UA-71552437-1&_gid=1459932104.1523791982&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&cd11=US&cd8=0&z=1869845550","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/show-box-android.png:l","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/extension/info_new_yt/screenshot_en.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p3.ssl.qhimg.com/t015eebd58e3c9362f7.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/fortune80.png","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"http://www.sina.com.cn/","request_type":"html"}
+{"origin":"http://www.taobao.com/","request_url":"https://img.alicdn.com/imgextra/i1/10/TB2rOe.c0knBKNjSZKPXXX6OFXa_!!10-0-yamato.jpg_q50.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/1dfde7b6e5c3405e9dbfa599273ee4ba.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2/freeform/DebugEvent?source=www&action=cssSimplicityPrefetch&statusCode=200&startTime=1523791892015&endTime=1523791893393","request_type":"text"}
+{"origin":"http://www.mail.ru/","request_url":"https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/05.svg","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/register/google_register_button.min-vfla38kXS.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/yaft/yaft-plugin-aftnoad-0.1.5.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/template/list.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://analytics.twitter.com/i/adsct?txn_id=l4umf&p_id=Twitter","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://m.aliexpress.com/?tracelog=wwwhome2mobilesitehome","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=TuAeGoH2Tk-ooTaFluPLUw&twitter_redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dtwca%26id%3DTuAeGoH2Tk-ooTaFluPLUw%26","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://www.tumblr.com/services/cslog","request_type":"other"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/lib/invoke/invokeBox_1b7c9e6.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/built/scripts/main.built.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMTQmdGw9MTI5NjAw&piggybackCookie=8YMH1zEIIKK","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://ad.mail.ru/adi/78733?rnd=117101971","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://image4.pubmatic.com/AdServer/SPug?partnerID=27&partnerUID=028a5ad3-32a6-4100-9482-79136ecc84fb","request_type":"text"}
+{"origin":"http://www.espn.com/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=1635687540398929&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fifs&adsid=NT&json_a=1&eid=21061884%2C21061149%2C21061569&sc=0&sfv=1-0-23&iu_parts=6444%2Cespn.com%2Cfrontpage%2Cindex&enc_prev_ius=%2F0%2F1%2F2%2F3%2C%2F0%2F1%2F2%2F3&prev_iu_szs=1x2%2C1x1&ists=1&prev_scp=pos%3Dexclusions%7CslotId%3Dad-slot-overlay-533379%26pos%3Doutofpage&eri=1&cust_params=ed%3Dus%26sp%3Despn%26pgtyp%3Despnfrontpage%26swid%3D0A8AF6A3-114D-4E90-CE93-928476B93005%26mnr%3Df%26espn_yxbk%3DJvY4nr%25252Fn99YfE5BS%26prof%3Ds&cookie_enabled=1&abxe=1&lmt=1523792032&dt=1523792032896&frm=20&biw=360&bih=512&oid=3&adxs=0%2C0&adys=0%2C0&adks=3266571609%2C4233223152&gut=v2&ifi=1&u_tz=-420&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.espn.com%2F&dssz=34&icsg=524800&std=0&vrg=194&vis=1&scr_x=0&scr_y=0&psz=360x3233%7C360x3233&ga_vid=1381963191.1523792033&ga_sid=1523792033&ga_hid=98984504","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=www.espn.com","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://b.scorecardresearch.com/b2?c1=2&c2=3000005&ns__t=1523792055712&ns_c=UTF-8&cv=3.1m&c8=ESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&c7=http%3A%2F%2Fwww.espn.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://x.bidswitch.net/sync?dsp_id=9&user_id=8YMH1zEIIKK&expires=30&ssp=yieldmo","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://token.rubiconproject.com/token?pid=2179&pt=n","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://px.ads.linkedin.com/collect/?time=1523791843084&pid=195308&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&fmt=js&s=1","request_type":"other"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/css/44afbd07.page.css","request_type":"css"}
+{"origin":"http://www.youth.cn/","request_url":"http://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=1063541226&si=969516094b342230ceaf065c844d82f3&v=1.2.30&lv=1&ct=!!&tt=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&sn=42405","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/991179584/?value=0&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=3&redir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTM2MiZ0bD00MzIwMA%3D%3D%26piggybackCookie%3Duid%3A%5BMM_UUID%5D&mm_bnc&mm_bct","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixanalytics.com/pi.gif?t=et&r=0.722304583545867&document.referrer=&document.URL=https%3A%2F%2Fm.pixnet.net%2F&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https%3A%2F%2Fm.pixnet.net%2F&window.pageXOffset=0&window.pageYOffset=1&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180413.110452&window.devicePixelRatio=3&venue=pixnet-mainpage-mobile&visitor_id=&utm_source=&utm_medium=&utm_term=&utm_content=&utm_campaign=&e_category=fingerprinting_test&e_action=%2352350&e_label=1318864f390c1a72b9e95f0b30e4181f4cedca1f84a19eca6cc6940a17477181","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=MGU3MzRkOTUtNTMwOS0zNzMzLWE4MTQtN2ZhOGEwODE1NmIzCTQ1CVBEUFMwMDAwMDAwNTc3ODIJNTAJMzU0NTMyNQkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=73426&dpuuid=86070857378125119120981354726841823876","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.google.com/ads/user-lists/1067250390/?random=1523791839044&cv=9&fst=1523790000000&num=1&guid=ON&eid=376635470&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=0&url=https%3A%2F%2Fwordpress.com%2F&tiba=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&async=1&fmt=3&cdct=2&is_vtc=1&random=629528224&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/mobile-PIXNET-logo@2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/V02lmzeK6QFkTNAFssnGgriS6KjgNLl2evPSXHtLdEHiyihTPaVVdpzERZKaiA=w256","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/Y1IHnQ0sM4cWJzRXAPAUA81jkwPmNDEq4nqhjUZN_oYhsyO-_UsuWx20Oy16acE=w192","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t01bf4bb5936bdceddc.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/btns/sign_in.png","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://www.taobao.com/","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://b95.yahoo.co.jp/s?s=bt&csurl=https%3A%2F%2Fyjtag.yahoo.co.jp%2Fcs&tp=8FzrfRY&btt=0","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/55cb5ffb-df46-4612-8c76-9b9badf92301_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/55/6b/96/556b9669c7607cbc87fa6bad30e0a5cf/556b9669c7607cbc87fa6bad30e0a5cf.19.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/014/02d/378/big_lq/f4957d492402a6e0617b203381f48a9c.jpg","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/feed/20180412/7ab18af8cc4b5e387c7147d250305f5d.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BYTYyMzU3ODktZDFmYi00Y2ZlLTliODktOGM1NmYzNGIwYjg0XkEyXkFqcGdeQXVyODAzODU1NDQ@._CR561,29,1274,1274_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img17/movies-tv/Oct/280x280_Quadcard_4._CB514398926_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81l6zbSjSzL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/311k6OfaSdL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/AmazonPickupLocations/1095756_uk_locker_011618_gateway_GW_MobileBillboard_1242x450._SX1242_CB487756012_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/AmazonPickupLocations/1095756_uk_locker_011618_gateway_GW_MobileBillboard_1242x450._SX414_CB487756012_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ape/sf/mobile/MAsf-1.19._V497204129_.js?csm_attribution=APE-SafeFrame","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/i18n/en.847daaa176904521.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/react/index/components/rebrand_plane.min-vflDBvPSo.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-exception-reporting.min-vflkyfmP8.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/approach/jslib/deeplink-1.4.3.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nba.png?w=110&h=110&transparent=true&h=240&w=240","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://fonts.googleapis.com/css?family=Noto+Serif:400,400i,700,700i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/css/2.75.8/wp-video.css","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"http://wq.jd.com/webmonitor/collect/badjs.json?Content=%22Script%20error.%22&t=0.4053289703426497","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://sb.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/js/omniture/tracking.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/drt/si","request_type":"html"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/gen_204?atyp=csi&ei=CTjTWq-WFMuh0wKXmq3ADQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.12,tjhs.17,jhsl.2190&rt=aft.414,dcl.412,iml.414,ol.3125,prt.282,xjs.2025,xjsee.2025,xjses.1502,xjsls.307,wsrt.2252,cst.707,dnst.0,rqst.824,rspt.422,sslt.382,rqstt.1722,unt.2160,cstt.1004,dit.2663&zx=1523791884843","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/v3/pr?exlist=pp_mp_sx_ns_kr_g_bsw_bk_ox_index_aold_an_rb_fbca_aolv_twca_y_pm_adelphic_rlsa_adb&fv=1.0&ex-pl-fbca=tX6_9Xz4Qdmr5oo7UFnXXQ&ex-pl-twca=HYc9c1dpSLWqgzShMqE45A&a=cm&ep=xUZG6up-KmBFk372JVMfVXzgolFfBxt3dxfqmMX190kLbowQKkK_Mz53UJrXtE3aYXVWrVxLK_0MD5oE9mSJDsEE5GnL4F1Vd57-XGvb4yX9TLRvhIqYuXWtaD4adE1Za0pUcb2CBZAdVDwn3wFbldlJ2D0pon-X1qX2xX-kMJj_aXKvOZFxChdNQ2iZOWzZ6FvCt888z4eLtn0OVFXkgw","request_type":"html"}
+{"origin":"http://www.so.com/","request_url":"https://m.so.com/position?_=1523791857848","request_type":"script"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://b92.yahoo.co.jp/search/?p=0GPI4UYVBZ&label=&ref=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rref=&pt=&item=&cat=&price=&quantity=&r=1523791867.3884804&pvid=rnxwb7iajg0qc1l8&req=1","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=m.pixnet.net","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"http://m.ok.ru/","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"http://dpm.demdex.net/id?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_cb=s_c_il%5B0%5D._setMarketingCloudFields","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=a01667c2-40a0-11e8-981d-180430d51c01","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=debd7e1a-40a0-11e8-9a4e-1e286a820301","request_type":"other"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/widgets-premium_promo_banner.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=112&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A112%7D&logFlag=uaction_1523791857874&t=1523791969896","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=rightmedia.com&xid=E0","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a671d5f00015ad3387df52870831a80&pid=mm_113716014_12970037_52768242&cid=143140&mid=74920&oid=149&productType=1&qytInfoMTime=1523728959&e=Y9iAAsWB1KaGJgTPtIviph%2BDa9ZR4%2FTlM6%2BG%2FVqMhsjfxQ4oiMXBR3tOmmtFPKdQ&k=65&cb=550499083","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d22199634.gif?sz=1&rnd=116116226&ts=1523791836&sz=1","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d1290389.gif?&rnd=607262346","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA2YAWO.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/spacer40.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/claudialin33/albumset/18790094/zoomcrop/75x75.jpg?v=1523786147","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5199000/5199577/220x165/8.jpg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1XB7U?ver=6c63&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=0&y=230&s=1391&d=782&aim=true","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/f5/a6/dd/f5a6dd993538f812a2170820697c99d2/f5a6dd993538f812a2170820697c99d2.16.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180409233811-mexico-us-migration-caravan-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1b/b6909313932292e82ea277626b857e3f_erotic_285x160.jpg?cno=07a","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjQxNjU4Mjg3MF5BMl5BanBnXkFtZTgwODg5MTg1MzI@._V1_SX100_CR0,0,100,150_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/amazonlaunchpad/de/Gateway/2018_02/iolandac_2018-02-05T15-59_0ebc52_1099615_de_launchpad_gw_quadcard_feb18_420x420._CB487250278_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/964caeca-2de3-447c-a55a-9587d8e00671/scale-to-height-down/100","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/j/s-5de2177f83.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://cdnssl.clicktale.net/www/WR109b.js","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/js/script-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-ads-model/td-ads-model-min.js","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://c.amazon-adsystem.com/aax2/apstag.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/native/impress?52379=Y2FsbGJhY2s9c2F4X2pzb25wQ2FsbGJhY2tfMyZhZHVuaXRfaWQ9UERQUzAwMDAwMDA1Nzc4MCxQRFBTMDAwMDAwMDY1ODAxLFBEUFMwMDAwMDAwNjAxMDQsUERQUzAwMDAwMDA2NTgwMixQRFBTMDAwMDAwMDU3NzgxLFBEUFMwMDAwMDAwNTk5NDksUERQUzAwMDAwMDA1OTk1MCZwYWdlX3VybD1odHRwcyUzQSUyRiUyRnNpbmEuY24lMkYlM0Zmcm9tJTNEd2ViJnRpbWVzdGFtcD0xNTIzNzkxODI1MjM3JnJvdGF0ZV9jb3VudD04ODgmYW09JTdCJTIyZHMlMjIlM0ElMjIzNjAqNTEyJTIyJTJDJTIyb3YlMjIlM0ElMjJhbmRyb2lkJTIyJTdEJm5ldD1udWxs","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/mtb/lib-smb-wake/0.0.42/wake.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/login/sp/js/login_promo/1.0.4/login_promo_dom-min.js?d=201512","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-00000000023/v3/fonts/skins/default/iconfont/iconfont.woff2?ds3hrf","request_type":"font"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/monkey.mobile.min.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://static.adobelogin.com/imslib/imslib.min.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/G/01/imdbads/js/collections/ads-mobileweb-2800827130._CB487184057_.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=pubmatic&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&glade_req=1&glv=26&dt=1523791849487&output=html&iu=%2F205338224%2FMail.ru_mobile_320x50&sz=320x50&sfv=1-0-10&correlator=4073452669305138&adk=3471309403&biw=-12245933&bih=-12245933&adx=0&ady=0&oid=3&u_sd=3&ifi=1&click=%25%25CLICK_URL_UNESC%25%25&nhd=1&url=https%3A%2F%2Fmail.ru&top=mail.ru&loc=https%3A%2F%2Fad.mail.ru%2Fadi%2F78733%3Frnd%3D117101971","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.espn.com/core/api/v0/nav/index?&device=mobile&country=us&lang=en&region=us&site=espn&edition-host=espn.com&one-site=true&site-type=full","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.googleadservices.com/pagead/conversion/981179826/?random=1523791902733&cv=9&fst=1523791902733&num=1&label=40zWCLqP1XUQsrvu0wM&bg=ffffff&hl=en&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=2&url=https%3A%2F%2Fs.thebrighttag.com%2Ftag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26session%3Dn%252Fa%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Df1fdc59c-9452-4167-a583-cc8ede9a2929&ref=https%3A%2F%2Fadtech.nflximg.net%2Fadtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522f1fdc59c-9452-4167-a583-cc8ede9a2929%2522%257D&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://www.google-analytics.com/gtm/js?id=GTM-K2Q3RJP&cid=750147261.1523791927","request_type":"script"}
+{"origin":"http://www.so.com/","request_url":"https://notify.ssl.so.com/v1/report?device_type=mso&action=normal&tmp=1523791858&token=f3a65a786eb9288a308b702b3794fdd28c2f76b2&callback=jsonp2","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"http://b.scorecardresearch.com/b?c1=2&c2=17985152&ns__t=1523791865822&ns_c=UTF-8&cv=3.1m&c8=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&c7=http%3A%2F%2Fcoccoc.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/sg/thetradedesk-network/1/rtb-h/?taboola_hm=fcbd302d-2d51-4301-be01-c7741f15bde8","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://px.ads.linkedin.com/collect/?time=1523791843084&pid=195308&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&fmt=js&s=1&cookiesTest=true","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1063929773/?userId=SBrLLYJkShGT4YAgqXAH6A&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/925133270/?value=1.00&currency_code=USD&label=IEQNCNXH9GcQ1tORuQM&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=645755483&si=6bcd52f51e9b3dce32bec4a3997715ac&v=1.2.30&lv=1&ct=!!&tt=CSDN-%E4%B8%93%E4%B8%9AIT%E6%8A%80%E6%9C%AF%E7%A4%BE%E5%8C%BA&sn=37647","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-53389718-2&cid=31773146.1523791847&jid=424931812&_v=j46&z=1780281530","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j46&a=660400026&t=pageview&_s=1&dl=https%3A%2F%2Fwww.paypal.com%2Fus%2Fhome&ul=en-us&de=UTF-8&dt=Send%20Money%2C%20Pay%20Online%20or%20Set%20Up%20a%20Merchant%20Account%20-%20PayPal&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=SGCAiEABB~&jid=424931812&cid=31773146.1523791847&uid=&tid=UA-53389718-2&cd1=%20UTC-7&cd2=Sun%20Apr%2015%202018%2004%3A30%3A52%20GMT-0700%20(PDT)&cd3=31773146.1523791847&z=365440652","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1FEsePXXXXXcqXXXXXXXXXXXX-80-80.gif","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t11425/73/2288282326/13451/e11c7697/5a14d167Ne5414496.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/sophieie2003/albumset/5754649/zoomcrop/75x75.jpg?v=1523785673","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://www.so.com/","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/11/f2/30/11f23084a611f02b0c1f397698af3816/11f23084a611f02b0c1f397698af3816.8.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://t1.focus-img.cn/sh340x226sh/xf/xc/FS58f3y3rZNxMSsi6FeJtr7JDzeGMzyE.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-k_GkTGK0POM/AAAAAAAAAAI/AAAAAAAAAAA/0GrhY5eKm4I/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51oHUvYzbsL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/7bd00c2f-0fe3-42bc-925d-befd5d7e1818/scale-to-width-down/366","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D","request_type":"text"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/cobalt/arrow-right.svg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=120&cm=10a67c0689ddd434a319a4869b0bd7c8","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-slideshow_atomic_sm/td-applet-viewer-templates-slideshow_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-thumbnail_items/td-applet-viewer-templates-thumbnail_items-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-lightbox_mega/td-applet-viewer-templates-lightbox_mega-min.js","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/static/fonts/roboto/roboto-light.woff","request_type":"font"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/node_modules/espn-lazysizes/lazysizes.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://watch.graph.api.espn.com/api?query={networks(countryCode:%20%22US%22)%20{id%20name%20adobeResource%20isIpAuth}}&apiKey=0dbf88e8-cc6d-41da-aa83-18b5c630bc5c","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://srv-2018-04-15-11.config.parsely.com/config/fandom.wikia.com","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yp/r/UfReaA2ci9t.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://px.ads.linkedin.com/collect/?fmt=gif&pid=7850","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/h0r58thg?redir=https%3A%2F%2Fsync.search.spotxchange.com%2Fpartner%3Fadv_id%3D6409%26uid%3D%24%7BUSER_ID%7D%26img%3D1","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D7941%26nid%3D2243%26put%3D%24%7BUSER_ID%7D%26expires%3D90","request_type":"other"}
+{"origin":"http://www.twitter.com/","request_url":"https://api.twitter.com/graphql","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=a768cddb-40a0-11e8-81e4-1a79d3e61a01","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=108&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A108%7D&logFlag=uaction_1523791857874&t=1523791965876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=34&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A34%7D&logFlag=uaction_1523791857874&t=1523791891876","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://c1.adform.net/serving/cookie/match?CC=1&party=14&cid=D34DC539-63A7-4F27-8DFD-50E0EE1E218A","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://media.trafficfactory.biz//banners/da/78/5e/2adb6a27ebc1347c438ec69bac221c69.gif","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3D3P95XKNQTYVQ066DW1Q8%26m%3D1%26sc%3Dadblk_no%26pc%3D12908%26at%3D12908%26t%3D1523792025754%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D3P95XKNQTYVQ066DW1Q8%26aftb%3D1:12911","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d368066.gif","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d905013.gif?sz=12&rnd=186396599&ts=1523791836&sz=12","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/uedata/unsticky/260-2953656-0613235/NoPageType/ntpoffrw?at&v=0.200436.0&id=3P95XKNQTYVQ066DW1Q8&ctb=1&m=1&sc=3P95XKNQTYVQ066DW1Q8&pc=14024&at=14024&t=1523792026870&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=3P95XKNQTYVQ066DW1Q8&aftb=1","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/sprites/social-24/5123af535080e661fcf0ebc4bb077b2d@2x.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/uptodown-android-android.png:xl","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/developers/yyx990803.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA42Hq5.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/webstatic/icon/pp32.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/GF-5w3cTsh0HnBwp1DLBaMCAwrPCwojFUPyOkvvk47RyFqVsxT6qKkdWnbz4=w512","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/mobile/sohu-logo-d.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://www.popads.net/app/webroot/","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1DgSAbmFRMKJjy0Fhq6x.xpXaf.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/8e/1b/84/8e1b84bd5b21f7bc69637e070000fdca/8e1b84bd5b21f7bc69637e070000fdca.29.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSCUe.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=707&y=364","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/wv/images/alphatar_100x100_M_ald.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/008/27d/28b/big_lq/73d35a629f532ad24fcda27cab231e9a.jpg","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1woHWSFXXXXcPaXXXXXXXXXXX-1000-441.jpg_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://logx.optimizely.com/v1/events","request_type":"text"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://static.criteo.net/js/ld/publishertag.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_194.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ape/sf/mobile/MAsf-1.19._V497204129_.js?csm_attribution=APE-SafeFrame","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://www.qchannel03.cn/m2.js?w=sohunews","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-index-rebrand.min-vflfUlJqq.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-modules-unneeded-for-home.min-vflu29_Aj.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-pipe-0.0.65/comet/comet-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-header_ads/td-applet-viewer-templates-header_ads-min.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://dc.ads.linkedin.com/collect/?pid=6883&s=1&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&cookiesTest=true&opid=4373&fmt=js&time=1523791867534","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://media.trafficjunky.net/delivery/js/abp/js1.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/sizo/eris.js?v=2","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cdn.aralego.net/ucfad/sdk/ucfad_min_e7ce911be17355a60b3f68d3253b98f22465e59f.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://sb.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.google.com.au/","request_url":"http://www.google.com.au/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/","request_type":"html"}
+{"origin":"http://www.twitter.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAs%2FtxexOGVLEkvH5vEO0wGiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/v3/pr?exlist=pp_mp_sx_ns_rx_kr_g_bsw_bk_ox_index_aold_an_rb_fbca_aolv_twca_y_pm_adelphic_rlsa_adb_tbl&fv=1.0&ex-pl-fbca=Z2VZffBGTkq5k_VXFnQLdg&ex-pl-twca=pavVoOCiQGy08CEOlgWPZQ&a=cm&ep=JINzIeCcW3c6VDJwFC-53gYUJtpxY5pSDGi8EHWmmWD-doAfa4V64C_IA1SWCMTSnNxL9XTTIfqwnZw0Inq_4RYYwv_PtbNThpX9Y_SIJh39TLRvhIqYuXWtaD4adE1Z7md4sGqVtARDmu7qrn1zUUf6JgaO4aLg_nopIEvR0P__aXKvOZFxChdNQ2iZOWzZ2ff6dXzBAp0e9COm6PL0hQ","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdnssl.clicktale.net/www32/pcc/755cc4ab-c4bf-46d8-a608-d3c5d66fabac.js?DeploymentConfigName=Release_20180413&Version=2","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20MultimediaFavorites%20Core$MMFaves/cj,nj/56b755ce/802fbfb7.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://connect.facebook.net/en_US/fbevents.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/11QXqf0G81L.js?AUIClients/RetailWebsiteOverlayAUIAssets","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rtd.tubemogul.com/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/lsp.aspx","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/components/rebrand_hero-vflkvw3uD.css","request_type":"css"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.media-imdb.com/twilight/?PageType=homepage&Geo=US&tw_ord=04452aa6825bbf784219ea894cc601c70374e344&timestamp=2018-04-15T11%3A32%3A05GMT&Client=chrome&Site=mobile&Operation.1=csm_top_ad_iframe.none&OperationTiming.1=1834&Operation.2=csm_top_ad_request.none&OperationTiming.2=1910&Operation.3=page_load&OperationTiming.3=1551&ord=8965773199915128","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=42&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A42%7D&logFlag=uaction_1523791857874&t=1523791899876","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=B39F0168-A648-41E8-BACA-CEB073D9B569&ex=pubmatic.com","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://d.agkn.com/pixel/8697/?che=1523791885&sk=265040302661004446320&puid=g9e51602ae03bce4bdfa","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v3/img/skins/default/xv-inline-loader.gif","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/p.gif?beaconType=saready&timeFromNavigationStart=19200&timeFromDomLoading=16843&bucket=900","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/wangzhidaquan.gif","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/sync?pn_id=z&userid=5or2whJaOglVvyyD69Mc","request_type":"image"}
+{"origin":"http://www.onclkds.com/","request_url":"https://www.google.com/ads/user-lists/995032169/?random=1523791874542&cv=9&fst=1523790000000&num=1&label=_iK6CP-_7xcQ6fi72gM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&fmt=3&cdct=2&is_vtc=1&random=1533485142&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-cc74e8bbc07/v3/img/flags/flat/flags-16.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/gz9btiN62BwKFzOWZO-DmTZDlraq172rVXTZ_TQwRDy8hT-VrzOVVfMp1nzupJY=w384","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/dongfangcaifu0106.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/pic/weizhanlogo_GMWindex.png","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/gno/sprites/sky_webnav_V1_sprite_1x._CB515271932_.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://m.so.com/","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ape/sf/mobile/msf-1.19._V497204134_.html","request_type":"html"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/X4HjzdHgPhr2zU0AFRYf0w--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/https://media.zenfs.com/creatr-images/GLB/2018-04-14/37542b70-4004-11e8-8bdb-51c880f867da_Screen-Shot-2018-04-14-at-12-40-29-PM.png.cf.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://images-llnw.xvideos-cdn.com/videos/thumbs169ll/80/8c/3d/808c3de615a35a5275b87d3634e453b7/808c3de615a35a5275b87d3634e453b7.15.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-dc-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/79/12/08/7912081be33c886c55d94815bb007ef8/7912081be33c886c55d94815bb007ef8.5.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20160809jkbj260.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/377955dcda8ec2faf5cd9397fbac4e71_erotic_285x160.jpg?cno=a5b0","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/transform/310/w710h400/20180415/tD_0-fzcyxmu7338212.jpg/w710h400z1l50t1aa7.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/985000/985397/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/2f613030-e3e3-4824-86cf-2d164a67a8fd/scale-to-height-down/82","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.s-microsoft.com/favicon.ico?v2","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/common/utils.min-vfle5xEAs.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/jquery.inview.min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/fonts/1.0.56/ESPNIcons/ESPNIcons.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/Fonts/Montserrat-Regular.woff2","request_type":"font"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://notification.nicovideo.jp/res/notify.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://dup.baidustatic.com/tpl/wh.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://shared.ydstatic.com/js/yatdk/3.0.0/stream.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/f424d2932e2b5ebf7a30cd6b997cdcf5.js?conditionId0=380088","request_type":"script"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/static/favicon/wikipedia.ico","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://adservice.google.com/ddm/fls/i/src=8166291;type=dpbxg0;cat=dpbx_0;ord=4439324672617;gtm=G46;_dc_1=1;~oref=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D","request_type":"html"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/?rinli=1","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/gp/gw/ajax/card.html/144-4203505-1964949?ie=UTF8&opf_redir=1&rshVal=1523791915994","request_type":"html"}
+{"origin":"http://www.facebook.com/","request_url":"https://fbcdn.net/security/hsts-pixel.gif?c=2","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted10.svg","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://us-pxl.trafficstars.com/api/v1/p/p.js?r=1&s=c9a0669116dc062826948911c805cfa03eaf6899c9c811f613f7b28465f534041523791854&p=e0SEGUNHhI4YLAbWGXNQBJkxY2CMMVMjRosyNmjgaEHjhpgbLcSUuQGjhRkcMm7UKBNDjA0cNXCIUBiGjJmDKhXOgWNQBw4aCsW4cXOwBg0aNo4qrCOHzUGlMmDQmMFUhkM0dOjA0fHiBZk0cujkoZPGDZkyclyMYVNHzIsxL8rgKDNSDBkZNMLECHODZJgfc2L0kFHjS5s3Yr7UmRPmy5w2Y77cKcOGzRcYM-RwqQMDhgwbc2T0OJr0KGfPoOfU6DEjBkWIMsi0gJFjRo6OMsKYaZHjaJgWOCqKiWFGjEczY64qHNMGDtQZM27YqEnGjlGgNeE81zEDhkI4bqEqJPOmjcM2LvCgCdNmDp20a83TFEHnPMIaMqTniBEzqAg45GhIBxhc8MwzHHA4cEEGYUhIBDnKuI5AAw-MYQYZFJLDDu5iqEGhMsaA474CYUiwQRQfrKOONBwaA4cccpBBDBwuYunCjsiAYbYcyuixBRtsgKGMMGbQMS_l6JujjDkcGs47G2JsgQwbwrCho7pw262GMaasq4yK-CruNvoicqiKKehjY0ARinCCvjS4E0EqHFwoyQXXXLCNvjrCcKiJN_RIw7IwXqjBQBBQYMKsOvDYAYQgzpLjjTTIAMEGA12I4VFA6XgDhCMSpSEFEIRgkQ0yXmgCCiXy0vQ2IEeFdDs2yriiriXSoMNQ6fC0IdElkKCiCSZYAIGNNNYoA9QQ13iD1CHQmLSNMgyts0DvZMjBhRpBAFSMQZedYrcw5EiD1xt8BQEKKqag4oX-poIB0wunkmEm8iQ86EEyJs1JoTea1IEqheg4wyHXYFNuttpgpUE33nzTK7jhijvuhuSWE-EOh2IwEQb60Oi4hhlsUHJDhyalIwxP5aAvQpx0ECGrrebo6oX01mvvvfjGMO8F-uCIwSGQwbtK5j3YCOO9Pspk-aAtPpQhhi7IYxNNEfpQICA=&d=1500&priv=false&w=t","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/mscomhp/_scrf/js/themes=default/da-89df93/a8-024abc?ver=2.0","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production//public/content/query/v1/article/search/tag/good-vibes?pageSize=12","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://connect.facebook.net/signals/config/1944925959056690?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://px.adhigh.net/p/cm/pubmatic","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=82&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A82%7D&logFlag=uaction_1523791857874&t=1523791939876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=48&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A48%7D&logFlag=uaction_1523791857874&t=1523791905877","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=52&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A52%7D&logFlag=uaction_1523791857874&t=1523791909876","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=index&id=E4EPtYH4q1pwUnRlpRJuNTdpcCE4ZgIC","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/loading.gif","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://pixel.mathtag.com/event/img?01AD=3fGJtGPwq0wFofHarmBuaiyUZsopIpLmjFaEs0dOF-gjJxk6dtS-HBA&01RI=D77E4971F3F64FB&01NA=&mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=&mm_bnc&mm_bct","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.facebook.com/impression.php/fac5bde284dbb4/?api_key=80401312489&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_blog-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/uedata/unsticky/260-2953656-0613235/NoPageType/ntpoffrw?ld&v=0.200436.0&id=3P95XKNQTYVQ066DW1Q8&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=3P95XKNQTYVQ066DW1Q8&ue=27&bb=1852&ns=1870&cf=2054&be=2103&af=2129&ne=2209&pc=12478&tc=-2533&na_=-2533&ul_=-1523792012846&_ul=-1523792012846&rd_=-1523792012846&_rd=-1523792012846&fe_=-30&lk_=-1405&_lk=-1405&co_=-1405&_co=-709&sc_=-1101&rq_=-706&rs_=-53&_rs=822&dl_=-10&di_=2121&de_=2121&_de=2121&_dc=12478&ld_=12478&_ld=-1523792012846&ntd=-1&ty=0&rc=0&hob=21&hoe=30&ld=12479&t=1523792025325&ctb=1&rt=cf:1-0-1-0-1-0-0_af:1-0-1-0-1-0-0_ld:88-10-2-65-5-0-1&csmtags=aui|aui:aui_build_date:3.18.6-2018-04-06|gwImgNoCached|fls-eu|gwmNoCardHistory|aui:ajax&viz=visible:27&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=3P95XKNQTYVQ066DW1Q8&aftb=1","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/2010/2011search.gif","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://e.nexac.com/e/a-1189/s-3614/s-3614.xgi?google_gid=CAESEN4k0zzA-yIduwaxogB9W5w&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6&rd=Y","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.google.com/ads/user-lists/968413686/?value=0&guid=ON&script=0&data=aam=4933391&cdct=2&is_vtc=1&random=2651341732","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/btn-android.png","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/play-button-hover._CB318667374_.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_tech.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fonts.gstatic.com/s/slabo27px/v4/mFT0WbgBwKPR_Z4hGN2qgx8D1WB4m9w.woff2","request_type":"font"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB12GqIXPgy_uJjSZKbq6xXkXXap.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_mobile_tablet_UI_2.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/09/07/7e/09077eef61aa8b26a07c544378b7f0fb/09077eef61aa8b26a07c544378b7f0fb.12.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BY2JiYTNmZTctYTQ1OC00YjU4LWEwMjYtZjkwY2Y5MDI0OTU3XkEyXkFqcGdeQXVyNTI4MzE4MDU@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/s/a/hp/bing.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/logo_catalog/logotype_m1-vfltuHich.svg","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://sp.auth.adobe.com/adobe-services/config/ESPN?_=1523792047654&noflash=true","request_type":"xml"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/vap/video/airy2/prod/2.0.1459.0/js/airy.ads._TTW_.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-lightbox_atomic_sm/td-applet-viewer-templates-lightbox_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/listing/tool/yads/impl/yads-stream-conf-top_smp.js?2018041501","request_type":"script"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://www.espn.com/","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"http://b.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/common/commonH_bottom/mCommonFooter.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=mediamath&google_cm&google_hm=xD1a0zFJSACod7fYAp6xiQ","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://x.skimresources.com/?provider_id=94AC3827-BDDB-436B-A363-D775FCA8DB42&provider=pbin&skim_mapping=true","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-17640202-1&cid=amp-50XQcMshov1NQ7I2bYC0LQ&jid=0.9569944429846904&_v=a1&z=0.25131427119327143","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://idsync.rlcdn.com/379708.gif?partner_uid=L6N7iig7","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://idsync.rlcdn.com/379708.gif?partner_uid=L6N7iig7&redirect=1","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=183716&cb=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dcasale%26partner_uid%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.googleadservices.com/pagead/conversion_async.js","request_type":"script"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/bundles/cnn-header.8611f19a46d99cd2c2f9-first-bundle.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-be7afd80869374e8f9fd0c31859f748aaefbe2fd._V2_.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768241&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791995261&fs=1&pvid=aa7acfd80fea7375d5ef5ad2dcfed0ee&cg=a72620b27bcf090289ad970244007122","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=quky68qukyi81&ru=https://beacon.krxd.net/data.gif?_kuid%3DL6N62llA%26_kdpid%3D4e3f8627-26fa-484d-bd95-a1f8f09d95a6%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://x.bidswitch.net/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1&verify=true","request_type":"other"}
+{"origin":"http://www.twitch.tv/","request_url":"https://www.twitch.tv/","request_type":"other"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/merchant-mobile-hero.jpg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/built/styles/main.built.css","request_type":"css"}
+{"origin":"http://www.csdn.net/","request_url":"https://shared.ydstatic.com/js/yatdk/3.0.0/stream.css","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=fbca&id=yv2UNYixS52k7Ba5Hrdpyw","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=f19ed524b17d2489d79b2d0a12dcf613f946d3db&ex=aoldisplay.com","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQVRKZSEBR7BT5RF15TNH%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D285%26cf0%3D1986%26pc0%3D1989%26ld0%3D1989%26t0%3D1523791967677%26sc1%3Dgwm%26cf1%3D2134%26af1%3D6105%26pc1%3D6105%26ld1%3D6105%26t1%3D1523791971793%26sc2%3Dlg%26af2%3D2309%26pc2%3D2309%26ld2%3D2309%26t2%3D1523791967997%26sc3%3DcsmCELLSframework%26bb3%3D2402%26pc3%3D2404%26ld3%3D2405%26t3%3D1523791968093%26sc4%3DcsmCELLSpdm%26bb4%3D2405%26pc4%3D2415%26ld4%3D2415%26t4%3D1523791968103%26sc5%3DcsmCELLSvpm%26bb5%3D2415%26pc5%3D2415%26ld5%3D2415%26t5%3D1523791968103%26sc6%3DcsmCELLSfem%26bb6%3D2416%26pc6%3D2418%26ld6%3D2418%26t6%3D1523791968106%26sc7%3Dpc%26af7%3D2483%26cf7%3D2483%26pc7%3D2483%26ld7%3D2483%26t7%3D1523791968171%26sc8%3Dinteractivity%26cf8%3D4503%26pc8%3D4503%26ld8%3D4503%26t8%3D1523791970191%26sc9%3Ddata-store-1%26bb9%3D4689%26cf9%3D5463%26pc9%3D5463%26ld9%3D5463%26t9%3D1523791971151%26sc10%3Dcard-load-1%26bb10%3D5480%26cf10%3D6055%26pc10%3D6100%26ld10%3D6100%26t10%3D1523791971788%26ctb%3D1:9298","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3DQVRKZSEBR7BT5RF15TNH%26m%3D1%26sc%3Dadblk_no%26pc%3D9790%26at%3D9790%26t%3D1523791975478%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQVRKZSEBR7BT5RF15TNH%26aftb%3D1:9790","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/vi/news.png","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/img/baiduappLogo_603e1ff.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/mobi/2017/image/logo/v0/192.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/tadli/albumset/5982902/zoomcrop/75x75.jpg?v=1523455055","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/tianqi20171026-56.png","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/RwoAAOSwLMlaTA7F/$_57.JPG","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/b4d183b1-ee68-46e3-ad28-3572d86dacbb_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/20121123sp.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img17/AmazonDevices/Neel/April/1106694_IN_Digital_Devices_Bundle_Mob-BJ-Hero_1242X450_2-final._SX1242_CB498941862_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61oosK63kOL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/2f251574-2278-4cf7-8089-fd044b2bdec9/scale-to-height-down/82","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/img/crtv/2018/03/1916679378487477386/1ac7a0bbe455ccf825a11f96a668b509_120.webp","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=139&cm=RX-e525c0cb-80de-4658-83b9-fd77d4e46729","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdnssl.clicktale.net/www/ChangeMonitor-latest.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.livefyre.com/libs/Livefyre/v1.1.12/builds/1523571466828/Livefyre.min.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://top-fwz1.mail.ru/js/code.js","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/Js/stub.en.js?v=4a8ae4b6747a","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/lq/lib/3pm/cs_0.2.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/commands.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_13821&impid=&at=1&mkey=&latcy=4863&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=1676260634957&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791943130","request_type":"html"}
+{"origin":"http://www.csdn.net/","request_url":"https://gorgon.youdao.com/gorgon/request.s?udid=VzvXcpEUv6yHR7Tm9ZqYMtGY702ukWkZ&id=dc73d38425b2e6311070c93503c50b97&hideAdLabel=0&isSecure=1&ct=3&dct=13&reqfrom=web&webos=3&nsv=1.1.2&ran=2&callback=_yad_jsonp_0&_1523791936896","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25&C=1","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WtM34wAACGMfPfyQ","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"https://connect.facebook.net/signals/config/969519813086003?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/316nxKpnxGL._RC%7C51faQ1uINoL.js_.js?AUIClients/SharedShoppingCartMobileAsset","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768132&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792002425&fs=4&pvid=e1b4877af0c8977778f690863ca453aa&cg=c6c90f7ddbbb6bc9e5b0149fb34238b4","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://top-fwz1.mail.ru/counter?id=2579437;pid=0;r=https%3A%2F%2Fm.vk.com%2F","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=9CF3CD18-8630-4432-855C-A5E665F14273&ex=pubmatic.com","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d1315113.gif?rnd=167330934&ts=1523791836&sz=12","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20serp%20Homepage$bgLogoBingTeal/ic/23b397af/f2e8bbe3.png","request_type":"image"}
+{"origin":"http://www.live.com/","request_url":"https://r1.res.office365.com/owalanding/v2.7/images/landing-outlookappicon.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t5656/351/153181074/12227/e35aa8d/591d9456Naa85e195.png","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v3/img/skins/xnxx/logo-xnxx.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p.ssl.qhmsg.com/d/inn/6ea3b7d2/pc/p_weishi.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/jiudian083002.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/mail80.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/DC/5F782B.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/46/23/92/4623921e9f382ddae6da859b93ef7b4f/4623921e9f382ddae6da859b93ef7b4f.22.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-MVdjAAJ9Tj8/AAAAAAAAAAI/AAAAAAAAAAA/W5oQNFrqnAQ/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/payload?c=03AJIzXZ63OUc5zt4YRJ7yhe6W2DpTYi4lAlKozCdT1EHMkkFDxtY28nRNN50t1zP7FQgKUmLC70dGqZSLXSlSO0FiVgD8RtkltxrDUFGexCH0v1GtKWrzTcejCTYr4FEJx2ScToQpZQY_oLiKSBLTtyFRrRn6yT_W3CbAtuFygYSW03JEtu4rCHhL4L19AdHqEXQC-W8PbAu1rzKisr6pefJxtlr3Z3dR4MNrJOwP1nEZXPg_NUGuoTkzgZiPaWcbFos_gED8-HHTf7eF0C1eApXwwbVx_O3WPeDOdJMLN--7XdIcJeNGr_rEKgqKi_uPilpjn7sMJ5Qa4Q626K7Cgec0dBHlPvB_n6J3_AFr8Xvkak2yf4yx0xjhlL7TzylLbDfXYv8oFjnWU0dHpEK-cu4OSl27veJCbXJGb4LxvnH0s-U-RUCCryMpnwV6CNzecYw5HYoD7UBsa42dYG14b4wayaZ2baej26GKf-Rb5OCpht65q6dYKPdigPQ7WEPKyKY69FH0ncitBnLVYUmKcClXiioxqN7sbaGRSaPAHnTVIzaEOFfdS60Nd61IMydleSDb97tWpizhWXx7H-YrsgrUbGe5TRbMpouVJ8ZCRGisysNKO8mv331pLWDBXVRgphgWdTvhGCcfJKsNJjv5CEpzQrYPogI_gv_LbwHOI3SQ7ENVVV_g-ZWWq5uJ8-F7QCO9mwLpXJta9kCQC7opVTnjD5JzrsyEDIZ-BKbhtriKbFPE5H9DtH3lZ13wWJcsZLUR7nDTgZ5Bnk6dc2c9IVxKwuOZB1EYnoklpOILgc4IQiKR6v-s6C50yk6NN5lFqfa7T8zBC6o1QjpSsHQw5p7fCr5rwYot0b2zETEvbNW1-4nuQhjcg6-wruENXk3ncoSZpx91qcM3dxq0p4D9JKt4OwL3OdmGdmZZO8JQC9JdKL09oQL_TxGAxl-voyOweCZnAnwNeTVpirLs-Gfzc8WNxLw4RFpfiMDiSFOaX0-nBbCuzfIZt3JpENtKfr5U0YISkr5V64n6jaOS38HS7-eyoF0KQeB9pWzo6xOUxjUzqebkAthcjelXUKhZxelRfbcAQhhmODfREk6eK8GR-8R7mIv_hUk2HeKPFy22EehhDBHRYLn4pjsFIKWkr7R2SBfA-FZ3kPLBQiBJTFVVAmZTyijSRe4GNwXyYsE_8Jtuqa-RZBUy6t_2l6KFPReP8ORYbz2GT2f2ls2no5YIjZWmmYbXFgfrt2ii-pM9Z_XZnTwn8OSTGwk&k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/eec8ed2b-1fc2-423a-9ca7-c49e7eaf4474/scale-to-height-down/100","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://vz-cdn.contentabc.com/ads/rk_300x250_742537/uploadMVideo.mpg","request_type":"video"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-pipe-0.0.65/af-comet/af-comet-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/dust-helpers-0.0.154/dust-helper-intl/dust-helper-intl-min.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/news-and-stories.en.js?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"script"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/portal/wikipedia.org/assets/js/gt-ie9-011f8dbfa9.js","request_type":"script"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/gp/gw/ajax/card.html/258-8151141-7687141?ie=UTF8&opf_redir=1&rshVal=1523791992481","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"http://www.wikia.com/fandom","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12279&impid=&at=1&mkey=&latcy=4063&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=8065847903741&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942293","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://data.api.cnn.io/weather/graphql?query=%7BwsiForecast(zip%3A%2294118%22%2Ccelsius%3A%22false%22)%7BcurrentConditions%7Btemperature%2Cdescription%2Cicon%7D%2Clocation%7Bcity%2CstateOrCountry%7D%7D%7D","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/propellerads/js/main.min.js?v=4&_=1523791941893","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768238&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791994192&fs=1&pvid=fb82028409e1ef54c81acb34d5802a01&cg=a964798aae6ec2ab88950105323eb0ce","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://api.adsymptotic.com/d/px?_pid=10479&_psign=1e962a13c2bbb17776ade0119024edb3&_redirect=https%3A%2F%2Ftags.bluekai.com%2Fsite%2F20931%3Fid%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1&verify=true","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://d.company-target.com/pixel?type=js&id=1421361246&page=https%3A%2F%2Fwww.adobe.com%2F","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDoyOS4xMDAJYmM1NDUwMmUtZGFiMi00NTE4LWJiYmEtZjc2MDRkNDhmYzM3CTMyNDY0OTMJMzExNTQ3NAk1OTE4Mjg4Mzc0X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc3OAkzNTIzODMyCXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQliOTRkYmE2Yy1jYzVjLTM4ZTEtYjYyYi1iM2MwMTE5NWFkOGQJNjE4MjEJNy42OTIzMDc3RS00CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx0Zi1ydAktCXVzZXJfdGFnOjIxMTY3OjAuMHx3YXBfb3M6NzAxOjAuMHx1c2VyX2FnZTo2MDI6MC4wfHVzZXJfZ2VuZGVyOjUwMTowLjB8dl96b25lOjc3NzI4MDowLjB8bmV0X3dpZmk6MTEwMjowLjB8Y3Jvd2RzOnxfY3Jvd2RzOgk0CTY1MDAwCTIwMDAw&userid=__149.20.63.13_1523791820_0.19234800&auth=97decb3f6bf880cd&p=uU26bMxcOOG2K7PAEZWtjdsYC%2B%2FAFpf%2F9rIJuA%3D%3D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://c.bing.com/c.gif?aol_uid=noapid&uac_muid=39041e2b94ed6ef00cb315f995be6f73&cd=us&pg=/msn&Red3=MSAOL_pd","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rtd-tm.everesttech.net/migrate_et3/","request_type":"other"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/45aa9c62/Areas/Home/Content/js/build/bundles/sharedFontStyles.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=24&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A24%7D&logFlag=uaction_1523791857874&t=1523791881876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=18&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A18%7D&logFlag=uaction_1523791857874&t=1523791875876","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=3527AA39-0A31-4F03-BEC4-4E3DE9772C53&ex=pubmatic.com","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQ3AKTQX4Z8AX1W7T64V5%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D14389%26pc0%3D14393%26ld0%3D14393%26t0%3D1523791870262%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQ3AKTQX4Z8AX1W7T64V5%26aftb%3D1:14393","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/msn-msn-home/log/2/debug?tim=04%3A30%3A43.043&type=warn&msg=blocked%3A0-0-1-unknown&id=4981&cv=301-1-RELEASE","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/log/image/doubleclick/cm?referrer=netflix.com/bt/nmLanding&google_gid=CAESEL0xlNcAfnUgTmVUUs-HTkg&google_cver=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=575&dpuuid=2467993173356661009","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=625190312&t=pageview&_s=1&dl=http%3A%2F%2Fwww.gmw.cn%2F&ul=en-us&de=UTF-8&dt=%E5%85%89%E6%98%8E%E7%BD%91_%E6%96%B0%E9%97%BB%E8%A7%86%E9%87%8E%E3%80%81%E6%96%87%E5%8C%96%E8%A7%86%E8%A7%92%E3%80%81%E6%80%9D%E6%83%B3%E6%B7%B1%E5%BA%A6%E3%80%81%E7%90%86%E8%AE%BA%E9%AB%98%E5%BA%A6&sd=24-bit&sr=360x512&vp=980x1393&je=0&_u=IGBAgEAB~&jid=2122569356&gjid=401697157&cid=603572290.1523791991&tid=UA-20947729-1&_gid=1362978636.1523791991&z=828635576","request_type":"image"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1957211573&t=pageview&_s=1&dl=http%3A%2F%2Fm.thepiratebay.org%2F&ul=en-us&de=UTF-8&dt=Download%20music%2C%20movies%2C%20games%2C%20software!%20The%20Pirate%20Bay%20-%20The%20galaxy%27s%20most%20resilient%20BitTorrent%20site&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAEAB~&jid=1113683615&gjid=2139673251&cid=857343269.1523791898&tid=UA-50103908-5&_gid=196909174.1523791898&_r=1&z=1526079352","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/v/ey02vizpqa4gpkf3jafc2nnv4en.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/spacer40.png?t=1523791940221","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/css/images/find-job-56dcb6a5.png","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/website/logo/monogram/pp_bb_mg.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/newicons/favicon-194x194.png","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=krux&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/ImgFsILViGgxnGrcmavmHw/009/341/441/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/rD9eZpO1L9g/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLCkkMaAi5HyAostYENl2EwHpxVbMw","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/02/25/cf/0225cf2744ba875fa76855138090b7c4/0225cf2744ba875fa76855138090b7c4.20.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20180302_mlzgdmxm_728x90.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/f44d305ea1af1c3d7b4159.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BNjJhODYxMWEtZTk2My00YzQ3LWFjMDktZTYxNjQzMzkxYWJkXkEyXkFqcGdeQXVyMjMxOTE4Mzk@._CR142,33,555,555_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/EzQAAOSw8b1aTAxi/$_57.JPG","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51Ua5RfyCqL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/favicon/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/rtbspub?&prid=7PRFT79UO&cid=8CUNL3XVM&crid=144402028&size=414x74&rp=2&vi=1523791837719580622&ugd=3&requrl=https%3A%2F%2Fwww.msn.com%2F&useAppData=0&hlt=1&tr=0.9517221545293852","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/js/jquery.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/js/gmw_index.js","request_type":"script"}
+{"origin":"http://www.qq.com/","request_url":"https://pingjs.qq.com/h5/stats.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/js/espn-defer-low.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/gotop/js/goTop-v1.0.min.js?v20180326115028","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/01/ads/advertising/ads._TTH_.js?cachebust=67692765","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTI3MzkmdGw9MTI5NjAw&piggybackCookie=1977432084666094253&r=","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a3.espncdn.com/combiner/i?img=/photo/2018/0410/r354381_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/gp/gw/ajax/card.html/258-8151141-7687141?ie=UTF8&opf_redir=1&rshVal=1523791993239","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://platform.twitter.com/jot.html","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/feed?ajax=1&layout=mobile&tsp=1&utcoffset=-420","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=7091006584414&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fifs&adsid=NT&json_a=1&eid=21061277%2C21061149%2C21061569&tfcd=0&sc=1&sfv=1-0-23&iu_parts=8663477%2CCNN%2Chomepage%2Clanding%2Cpushdown%2Csuper-ad-zone&enc_prev_ius=%2F0%2F1%2F2%2F3%2F4%2C%2F0%2F1%2F2%2C%2F0%2F1%2F2%2F3%2F5%2C%2F0%2F1%2F2%2C%2F0%2F1%2F2&prev_iu_szs=1x1%7C1x2%2C1x2%2C1x2%7C1x1%2C300x252%7C300x250%7C1x2%7C1x1%2C1x2%7C1x1&ists=1&prev_scp=pos%3Dbnr_atf_02%26elemId%3Dad_mod_35731bb1e%7Cpos%3Dbnr_atf_01%26elemId%3Dad_bnr_atf_01%7Cpos%3Dbnr_btf_01%26elemId%3Dad_bnr_btf_01%7Cpos%3Drect_btf_02%26elemId%3Dad_rect_btf_02%26amznbid%3D1%26amzniid%3D%26amznsz%3D0x0%26amznp%3D1%7Cpos%3Doop_float_01%26elemId%3Dad_oop_float_01&eri=1&cust_params=transId%3D1523791858448543148946430%26iom_geo%3DUS%26prx_to%3D1%26guid%3D5ad337f701115d0a3c732e5b38006d32%26fln_pqto%3D1%26protocol%3Dssl%26refdom%3Dother&cookie_enabled=1&abxe=1&lmt=1523791871&dt=1523791871948&frm=20&biw=360&bih=512&oid=3&adxs=180%2C0%2C0%2C30%2C0&adys=73%2C0%2C0%2C5640%2C0&adks=1113343234%2C884486896%2C3275573252%2C2039529775%2C2831922974&gut=v2&ifi=1&u_tz=-420&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=https%3A%2F%2Fwww.cnn.com%2F&dssz=51&icsg=35184657891328&mso=2147484161&std=0&vrg=194&vis=1&dmc=4&scr_x=0&scr_y=0&psz=360x-1%7C360x-1%7C360x-1%7C340x-1%7C360x-1&ga_vid=1426148345.1523791872&ga_sid=1523791872&ga_hid=548487796","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/ActiveUserResource/create/","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.adsafeprotected.com/jload?anId=928108&campId=1x2&pubId=38386957&chanId=52063237&placementId=4640152498&pubCreative=138230533951&pubOrder=237199237&cb=185240709&custom=bnr_atf_01&custom2=&custom3=&adsafe_par&impId=","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://static.ads-twitter.com/uwt.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3iVIs4/yY/l/en_US/AacWJdkR52R.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/rsrc.php/v3iG-04/yH/l/en_US/fz7e0MOAAvd.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52766747&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792002917&fs=4&pvid=a93c9b4ed384431c84352b119e15fb8a&cg=af71da4b75ab08eafd560e5eecf2e1d9","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pubmatic-match.dotomi.com/match/bounce/current?networkId=17100&version=1&nuid=%3Cexchange-user-id%3E","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://px.ads.linkedin.com/collect/?fmt=gif&pid=7850&cookiesTest=true","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo1MC4xMzgJMmEwYTc3MzctZjQ1OC00YjJkLTk3NDEtMzdiZjdhNDBiZDU5CTMyNTY3NzYJMzEyMDYwOAk2MzMxNjg5NDM1X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc4MQkzNTQ1MzI1CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQk2Njk5MGYyNC04NzA2LTMwZjItOTdmMy01NzVjMGZlNDY4NDMJMjkwNzYJMC4wMDE2NjY2NjY3CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjA5NTk6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwNTowLjB8dXNlcl9nZW5kZXI6NTAwOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTMJMzAwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=ee2fac36da7455ea&p=ZpkPJIcGMPKX81dcD%2BRoQ5qmM%2BCipe3nQ3XMlw%3D%3D","request_type":"other"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/swiper.min.css","request_type":"css"}
+{"origin":"http://www.qq.com/","request_url":"http://mat1.gtimg.com/www/css/qq2012/hot_word_sogou.css","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=rightmedia.com&xid=E0","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://s.amazon-adsystem.com/ecm3?id=pCDNmfFCqAfIHf3IaR6KWMWWwYjZzChgQG1x/JmYjWc=&ex=rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://us-u.openx.net/w/1.0/sd?id=537072971&val=2e68b153-5f6c-4bef-a554-4d86b35719b5&ttd_puid=000300ea-838a-3a75-7a55-91bf99a60944","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://0914.global.ssl.fastly.net/ad2/img/x.gif?cb=1523791865018","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://stags.bluekai.com/site/35703?dt=0&r=565649178&sig=701806250&bkca=KJpnEnWN+Mxy1UxNzg/6zUDhzlDp1cOt1MR65qm6BcP0BU1pByR9ZZL/P9==","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/sync?pn_id=c&google_gid=CAESEI0KkLiEWiRg_43KEufWyk8&google_cver=1","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-ytb.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/qfL8w8HhVvq0PI9rsXZbjBc9gDZtNbE8km3C7-2jMje6Fq0WGWV7x2SNiqpK=w768","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/2997000/2997445/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s220x220_1724/b57c26ce-b36f-47ec-92df-516faaa96209.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/a1/7e/54/a17e54586b3b09ac5101b46ccb60e741/a17e54586b3b09ac5101b46ccb60e741.9.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BODk2NjQwMjYwMl5BMl5BanBnXkFtZTgwNTAzNzgyNTM@._CR243,93,991,991_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTc3Nzc3OTgxMl5BMl5BanBnXkFtZTgwNzgzNzk2MjI@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/img/uploader/plan/specialpickup/0413kokuchi_special03.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/41WMGzVqRdL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/upornia.svg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/gp/gw/ajax/dataStore.html/144-4203505-1964949?ie=UTF8&hmac=B3946F2259DE4257E6649576447E8F0735231AE8&opf_redir=1&relatedRequestId=XZ4D3PPDB36HTEGXD7ZH","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-i18n.min-vflztPuMn.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-story_cover/td-applet-viewer-templates-story_cover-min.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-8-3964d35633c91b66c5a6.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/hybrid/api/4.0.29/hybrid.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/fetch/4.1.12/fetch.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://fonts.googleapis.com/css?family=Open+Sans:400&lang=en","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/411MtgykU8L.css?AUIClients/GWMWebAssets","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://sstats.adobe.com/b/ss/adbadobenonacdcprod/10/JS-2.5.0-D7QN/s19637421670077?AQB=1&ndh=1&pf=1&callback=s_c_il[4].doPostbacks&et=1&t=15%2F3%2F2018%204%3A33%3A26%200%20420&d.&nsid=0&jsonv=1&.d&sdid=0F715D2B1317710A-3C141A64CA81D397&D=D%3D&mid=91347194757900030554314852707948543921&aid=2D699C4005031F55-600011820000562A&aamlh=9&ce=UTF-8&cdp=2&fpCookieDomainPeriods=2&pageName=adobe.com&g=https%3A%2F%2Fwww.adobe.com%2F&c.&hitType=pageView&s_dmdbase=18258689%3AInternet%20Archive%3ASoftware%20%26%20Technolog%3AData%20%26%20Technical%20Ser%3A100-499%3A%2425M%20-%20%2450M%3ASMB%3ASoftware%20%26%20Technolog&s_dmdbase_custom=archive.org%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3Atrue%3Afalse%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D&.c&ch=adobe.com&server=www.adobe.com&v0=D%3Dv6&events=event999%3D13600%2CprodView%2Cevent3%2Cevent19%2Cevent61%3D19%2Cevent62&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&c1=Home%20Page%20Template&c3=www.adobe.com&c4=en_us&c5=en_us%3Aadobe.com&v16=D%3Dc12&v18=New&c20=D%3Doid&c21=D%3Dpid&v22=Sunday%20-%204%3A30AM&c25=D%3Dc27&v28=www.adobe.com%2F&c29=D%3Dv12&c31=en-us&c32=en-us%3Aadobe.com&c34=D%3Daamlh&v37=D%3Doid&c38=2.5.0v%7C7QNv%20-%202018-04-12%2016%3A24%3A39%20UTC%7C6.12v%7C2.5.0v%7Cat.js-1.2.3v&v38=D%3Dpid&v51=18258689%3AInternet%20Archive%3ASoftware%20%26%20Technolog%3AData%20%26%20Technical%20Ser%3A100-499%3A%2425M%20-%20%2450M%3ASMB%3ASoftware%20%26%20Technolog&v52=archive.org%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3Atrue%3Afalse%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D&c56=VisitorAPI%20Present&c62=18.70&v65=Chrome%2058&c74=s.c27%3Dp%2Cs.c52%3Dp%2Cs.c59%3Dp%2Cs.v12%3Dp%2Cs.v111%3Dp%2Cs.v210%3Dp%2Cs.v216%3Dp&v84=D%3Dc27&v193=91347194757900030554314852707948543921&v250=setTimeout-10000&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&AQE=1","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzNDAmdGw9MTI5NjAw&u=D34DC539-63A7-4F27-8DFD-50E0EE1E218A&piggybackCookie=446F179DE67569BCA2F6EE82E4D8A588DE39EC92","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTI3MzkmdGw9MTI5NjAw&piggybackCookie=1184798549435024013&r=","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://adservice.google.com/ddm/fls/i/src=1295336;type=idsync;cat=uuidm0;u1=NotSignedIn;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;u4=;u5=;u6=adobe.com;u7=%%DC_rdid%%;u8=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=3254237940278.7236;_dc_1=1;~oref=https://www.adobe.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12424&impid=&at=1&mkey=&latcy=3352&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=2891161903570&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791941539","request_type":"html"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/StatsLogResource/create/","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Identity%20Mobile$MobileSnrWindowsLiveConnectBootstrap/cj,nj/8d784342/dbeb434c.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://sc.iasds01.com/dtc?ias_callback=__IntegralAS_1cd9a40238057f683cd07d66358c863f_4410&advEntityId=143441&asid=1cd9a402-3805-7f68-3cd0-7d66358c863f&second_pass=1","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixel.rubiconproject.com/exchange/sync.php?p=dfp&google_gid=CAESEPts9Ja8iDZmvobMY3keku4&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://c.bing.com/c.gif?uid=91191954147729940174299115411397659455&Red3=MSAdobe_pd","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/styles__ltr.css","request_type":"css"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-313498-1&cid=1005470225.1523791954&jid=586465558&_gid=743993530.1523791954&gjid=232247467&_v=j66&z=1891371743","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/gif/site2/20180415/f44d305ea1af1c3d6eae1e.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/img/imagelogo.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/node-logo.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/sap-logo.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://img.alicdn.com/imgextra/i3/27/TB21MzojFXXXXXbXpXXXXXXXXXX_!!27-2-subaru.png","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/gno/sprites/sky_webnav_V1_sprite_2x._CB515272527_.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"http://www.taobao.com/","request_type":"html"}
+{"origin":"http://www.savefrom.net/","request_url":"https://fonts.gstatic.com/s/roboto/v18/Hgo13k-tfSpn0qi1SFdUfVtXRa8TVwTICgirnJhmVJw.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/09ed4bdd-de29-4feb-b187-7d77165545a8_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33031341","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20151222_150x47.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0413/dm_180413_SECCOM_SEC_NCF_Feature_UF_Mullen_on_life_as_a_Gator/dm_180413_SECCOM_SEC_NCF_Feature_UF_Mullen_on_life_as_a_Gator.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/c57380eab829458197ac1c639e6dcd85.jpeg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/ac/3d/bc/ac3dbca90b3750b603a1c0849e383979/ac3dbca90b3750b603a1c0849e383979.7.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/4429000/4429279/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/515gm+OYDtL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/favicon.ico","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/support/image_small.svg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1?$mscomCookies=true&ext-javascript-msfpc=%27GUID%3Dfbae62a858c942f989eb9eafc49b9bdb%26HASH%3Dfbae%26LV%3D201804%26V%3D4%26LU%3D1523791838101%27","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/swiper_index.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/metrics/ac-analytics/2.3/scripts/ac-analytics.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/se/static/amd_modules/vip-server-renderer/js/atom.min_c85df26.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTM2MiZ0bD00MzIwMA==&piggybackCookie=uid:028a5ad3-32a6-4100-9482-79136ecc84fb","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://www.nicovideo.jp/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938214_4485914366835&itemspaceid=12274&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938214&plateid=1000800000,1001900000","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"http://s2.symcb.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBS56bKHAoUD%2BOyl%2B0LhPg9JxyQm4gQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMCEH7hSm9v7%2FLTfz%2BtZU062rSiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://ing-district.clicktale.net/ctn_v2/wr/?1699375031091421&100&10&0&0&0&8&subsid=233200&msgsize=10","request_type":"text"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gpsfront.aliexpress.com/getRecommendingResults.do?widget_id=5307381&limit=6&imageSize=220x220&platform=msite&__amp_source_origin=https%3A%2F%2Fm.aliexpress.com","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2","request_type":"font"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770080&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791993699&fs=1&pvid=a238502950abec9ea59b2de24080b9e9&cg=a5287eb6754e8b710126eb1c4f639690","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com%26","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=fbca&id=Z2VZffBGTkq5k_VXFnQLdg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=7430&nid=2238&put=83ba1816-e424-472e-984e-1c18903c50f8&expires=360","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/uedata/unsticky/358-6685975-3653550/NoPageType/ntpoffrw?ld&v=0.200436.0&id=QVRKZSEBR7BT5RF15TNH&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=QVRKZSEBR7BT5RF15TNH&ue=17&bb=2005&ns=2011&cf=2309&be=2423&af=2477&ne=2716&pc=9290&tc=-1654&na_=-1654&ul_=-1523791965688&_ul=-1523791965688&rd_=-1523791965688&_rd=-1523791965688&fe_=-29&lk_=-1639&_lk=-1254&co_=-1254&_co=-578&sc_=-947&rq_=-573&rs_=-45&_rs=811&dl_=-13&di_=2455&de_=2456&_de=2457&_dc=9288&ld_=9288&_ld=-1523791965688&ntd=-1&ty=0&rc=0&hob=15&hoe=17&ld=9291&t=1523791974979&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:38-7-4-21-4-0-1&csmtags=aui|aui:aui_build_date:3.18.6-2018-04-06|gwImgNoCached|fls-fe|gwmNoCardHistory&viz=visible:16&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=QVRKZSEBR7BT5RF15TNH&aftb=1","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif?evt=impr&js=1&rid=e86f55f780704d568af4af783e3cb6c4&cts=1523791836833&idx=1&clid=39041E2B94ED6EF00CB315F995BE6F73&rf=&cu=https%3A%2F%2Fwww.msn.com%2F&scr=360x512&bh=512&bw=360&dv.Title1=MSN+%7C+Outlook%2C+Office%2C+Skype%2C+Bing%2C+Breaking+News%2C+and+Latest+Videos&viewType=size1column&di=340&mkt=en-us&pn=startpage&su=https%253A%252F%252Fwww.msn.com%252F&pid=startpage&cv.product=prime_mobile&flightid=mmxios1cf&activityId=e86f55f780704d568af4af783e3cb6c4&cvs=Browser&subcvs=homepage&pg.n=startpage&pg.t=hp&pg.p=prime_mobile&st.dpt=&st.sdpt=&cv.partner=&cv.publcat=&cv.author=&cv.entityId=&cv.entitySrc=&cv.parentId=&provid=&ar=0&d.dgk=tmx.mobile.webkit.android&d.imd=1&tmpl=EAggMo%3A0%3BIP%3ACb%3BRV%3ACb%3Binfopane%3A0%3Bcat%3A0%3BEP%3A0%3BCI%3A0%3BmIpH%3A2%3BmRvH%3A2&isStaticPage=False&pgIdx=&pgTot=&pp=False&pb=%7B%7D","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/uc-browser-mini-for-android-android.png:l","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-cc74e8bbc07/v3/img/flags/flat/flags-32.png","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=pubmatic&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/3264000/3264403/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-lr-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/6c/ab/a8/6caba85cb15877b8e2648bc6eba9e9c2/6caba85cb15877b8e2648bc6eba9e9c2.17.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180412/f44d30758a831c3965b601.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d305ea4881c3a513b21.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f17/7415340c7dc674f9367cb980dd170e54_erotic_285x160.jpg?cno=4f3a","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/404000/404176/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41Wo77ejldL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/515gm+OYDtL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/618mlGassEL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/LWgAAOSweZJaS-oh/s-l225.webp","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/images/favicons/favicon.ico?_v=b45846535fb3e72144f09ddd9ad69b4b","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/ape/sf/mobile/MAsf-1.19._V497204129_.js?csm_attribution=APE-SafeFrame","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-timing.min-vfl0qQ5fP.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/listing/tool/yads/yads-stream-conf-top_smp.js?3","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/assets/fave/fonts/2.0.15/cnn-icons.woff","request_type":"font"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.wordpress.com/","request_url":"https://getrockerbox.com/assets/xyz.js","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/gen_204?s=webaft&atyp=csi&ei=ATjTWoLBGqiB0wKB2ajIBQ&rt=wsrt.1837,aft.527,prt.383","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://accounts.google.com/o/oauth2/iframe","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938199_1917499056920&itemspaceid=12428&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938199&cnid=","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log/ux_analytics","request_type":"text"}
+{"origin":"http://www.amazon.de/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2","request_type":"font"}
+{"origin":"http://www.amazon.in/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://magnetic.t.domdex.com/37764/pix.gif?t=c&for=Adobe&cc=1","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=cf42b83e187424bde06252a3b51877fb323ff814&ex=aoldisplay.com","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://sync.adaptv.advertising.com/sync?type=gif&key=thetradedesk&uid=ecf97925-4f99-4dc2-9bf7-6775e63a3ba0","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://www.facebook.com/tr/?id=969519813086003&ev=PageView&dl=http%3A%2F%2Fdiply.com%2F&rl=&if=false&ts=1523791968815&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=28&it=1523791965948","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D49NGBMVT1ABRN6GGR916%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D12797%26cf0%3D12803%26pc0%3D12803%26ld0%3D12803%26t0%3D1523791999648%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D49NGBMVT1ABRN6GGR916%26aftb%3D1:12803","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb2.qujishu.com/haq/z?c=d25pZD1iNTQ4NmExOTYzMDc5ZTY2AHM9YjU0ODZhMTk2MzA3OWU2NgB0PTE1MjQxODk5MTcAc2U9MQBidT00AHByaWNlPVd0bEszUUFNZ09oN2pFcGdXNUlBOG56dGVGc0RLVjNqMC02bnpnAGNoYXJnZV9wcmljZT0yNDEzAHNoYXJpbmdfcHJpY2U9MjQxMzAwMAB3aW5fZHNwPTQAY2htZD0xAGJkaWQ9AGNwcm9pZD0Ad2Q9MAB0dT11MzEyOTE0MgBwb3M9MABiY2htZD0wAHY9MQBpPWZkODJhMjdi","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d29940694.gif?sz=7&rnd=428307203&ts=1523791836&sz=7","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/img/lightbox/lightbox-blank.gif","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/customers/mapbox.png","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://pos.baidu.com/wh/o.htm?ltr=","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5190000/5190826/220x165/12.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/fc/c3/31/fcc33154166ce4f3c8ea4ede76aae03d/fcc33154166ce4f3c8ea4ede76aae03d.28.jpg","request_type":"image"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/bd34d329/images/hero-still-image-mobile.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180415094235-damon-refugee-camp-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://production.mtm-cdn.com/filmer/archives/907/5435/15.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_27,y_20,w_770,h_513/os/news/990737e9f003744ce37acc71f4ca2fb1.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/kindle/merch/2017/TAB/Dec/KET_2P/VX_1414_8KET2P_GW_MobileHero_1242x450._SX1242_CB491668365_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/51cvHPU2FZL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/xba/Watch._CB503098439_.jpg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/n1/0/1523791919998/0/0/0/0/1523791921485/1523791920014/1523791920312/1523791920312/1523791921017/1523791920636/1523791921027/1523791921473/1523791921522/1523791921534/1523791928974/1523791928975/1523791929148/1523791929228/1523791929233/1523791929249/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/1523791925158","request_type":"text"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/images/icons/favicons/fav_logo_2x.ico?8","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn-gl.imrworldwide.com/novms/js/2/ggcmb510.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://geo.qualaroo.com/json/","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-light.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/gizmo/js/src/components/videoPlayer.min.js?v=1wsJgAcb598T1KyJT8jGSbX_QoOLr0OfJ_UipCNUjxw","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.rubiconproject.com/header/11078.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://c.amazon-adsystem.com/aax2/apstag.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/alog.min.js?v=-17637-17637","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/8db46309e6349886335823942737f697.js?conditionId0=378623","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/lib/metro/g/myy/rapidworker_1_2_0.0.5.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/photo/2018/0403/r351024_1296x518_5-2.jpg&w=686&h=275&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/gp/navigation/ajax/hmdata.html?pageType=gateway-phone-web&rid=XZ4D3PPDB36HTEGXD7ZH&hmDataAjaxHint=1&currentUri=%2F","request_type":"html"}
+{"origin":"http://www.google.com.mx/","request_url":"http://www.google.com.mx/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100166121&apid=beans_15690&impid=0faccd381acd576c1_0_0&at=1&mkey=0faccd381acd576c1_0_0&latcy=2259&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=982.359375&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DYp5WGmNW9i0qFPx4uhVpLvgpTsvJFHWAMoGHaVZbCESEmn9YZspBnofJ1O8wHJ1ye%2BOuV7kx7ljjfM1RRtCv6eyH9BoYUBQnGoI%2F%2F12krKk0p%2Fwr5cSpKUBZ1In7RA1JkFpmXSut4OMdwfNGg2%2F4wI4LSix0rdKnBpL5KqRh4RCIRJEJxphx8cxIsDf%2FheRQPoWmCdXN36%2FPOBbkntkPBFBoJMH65yd7k9tmL0IVJpTdJKQZTWxWnf1unUpNT3lD86IAo5hIGY3rny1phvsC%2FGQ7z%2BujBohSvqeTvdjQcG6yNd898hZiEzelnvlbb1VFTqQIoPjZ0sM%2FuA9LftCZXJdX3%2BoY9A1vywyY8T%2FOTfI4yAoVhJani7VzMF9aoQwfchsJRQ%2FukLWSqgtjS5qNjeH5XYjmPjyVGvEuRw6d8GljPQFfEHRsCwfn4E3STX9v8igTbZanQU0Z4uf0ztV81sWzya2RX2CaqBmQVkqcbfUqrwWppRF8NelAoXvEqLJsxHAiDHXj7FAdMgBTb5HrjkxBZVE3oYY2vSJlpdA7%2B2szsHx55ULKG1FdWdfM7tpN0mJAer0q5xvVp0CTe2tIaH08fDcU%2BgafcgHqhcnEJtA%3D%09tt2%3D1523791940108%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=4553768616825&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791940434","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938146_1317234159342&itemspaceid=12418&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938146&cnid=228329268,228300063","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://aax-us-east.amazon-adsystem.com/x/getad?pk=%5B%22p%3Dtop%22%2C%22p%3Dt%22%2C%22c%3D1%22%2C%22pi%3Dhomepage%22%5D&src=401&c=100&sz=320x50&ec=0&u=https%3A%2F%2Fm.imdb.com%2F&slot=TOP_AD&site=m.imdb.com&pt=homepage&jscb=aax_render_ad_top_ad&rnd=332843615559","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/977748509/?random=1523791866918&cv=9&fst=1523791866918&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://sb.scorecardresearch.com/p?c1=2&c2=13765216&c3=&c4=https%3A%2F%2Fm.vk.com%2F&c5=&c9=https%3A%2F%2Fm.vk.com%2F&c15=&cv=2.0&cj=1&rn=74200331","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://idpix.media6degrees.com/orbserv/hbpix?pixId=16873&pcv=70&ptid=66&tpuv=01&tpu=86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com%26","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo1MC4xMzgJOWRkZTg4ZWMtMjdjZS00ZDAzLWEzNzctMGQ2M2VkYWNmNjcxCTMyNTM5NDAJMzExOTM2Nwk2MzI2NzYyNzA2X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA2MDEwNAkzNTM4NzQ4CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQk2Njk5MGYyNC04NzA2LTMwZjItOTdmMy01NzVjMGZlNDY4NDMJODM2NDMJNS45NDI5NThFLTQJMTQ5LjIwLjYzLjEzCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAkwCXRydWUJTkFUSVZFCVdBUAktCTAJX18xNDkuMjAuNjMuMTNfMTUyMzc5MTgyMF8wLjE5MjM0ODAwCVdBUF9GRUVECS0Jbm9ybWFsfHV2Zm0tcnQJLQl1c2VyX3RhZzoyMDIxMjowLjB8d2FwX29zOjcwMTowLjB8dXNlcl9hZ2U6NjAwOjAuMHx1c2VyX2dlbmRlcjo1MDA6MC4wfHZfem9uZTo3NzcyODA6MC4wfG5ldF93aWZpOjExMDI6MC4wfGNyb3dkczp8X2Nyb3dkczoJMwkxMDUwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=d127393561e43f77&p=ZpkPJIcGMPKX81dcD%2BRoQ5qmM%2BCipe3nQ3XMlw%3D%3D","request_type":"other"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://cs.nex8.net/cs/nend?uid=f761de7be649e4b6ecf2d55db1364b70","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://px.moatads.com/pixel.gif?e=25&q=2&hp=1&kq=3&lo=0&qs=1&ak=http%3A%2F%2Fwww.espn.com%2F-&i=ESPN1&ue=0&uu=0&qm=420&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2BweM!%2CxnyAk_D2fQ%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=BmCCkSBBBBBBbBBBBq6YYNCu3NBBBwk0Bv34mCeCC4g6miE2wif6W0lBg1SfTBBBBBBeUIBCBBMBBvBUtBWx6jHdBBfXe8kBPB2kc3MMpFBTaBBBBBBBBBBBtsWaBBBHCZ5iWeWSBM31KJPlglCCFMWFpcxaBCNBZnuBBOFeBCBBbBBwxBHryaIGoXjTr93nNBBB3BBJBBzBPBBBlDDBCDCCDCDDDDDC0GuBeEES8DDBqBCKqeMFB&iv=5&vf=1&vg=100&gz=0&hh=0&hn=0&qt=0&bq=0&g=7&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=360&fy=0&gp=113&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&cm=0&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=0A8AF6A3-114D-4E90-CE93-928476B93005&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1523792042551&de=396947004824&cu=1523792042551&m=5556&ar=cf7e882-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=114&lb=8594&le=1&gm=1&io=1&ct=undefined&as=1&ag=5415&an=5201&gi=1&gf=5415&gg=5201&ez=1&ck=2514&kw=841&aj=1&pg=100&pf=100&ib=0&ic=4838&cc=1&bw=5415&bx=5201&ci=2514&jz=841&dj=1&aa=1&ad=4838&cn=4624&gn=1&gk=4838&gl=4624&co=1937&cp=841&cq=1&im=1&in=1&pd=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=5266&cd=5060&ah=5266&am=5060&rf=0&re=0&wb=2&cl=0&at=0&d=52519497%3A2246459680%3A4601938233%3A138229376639&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&hv=Domsearch%20Late&zAudience=unclassified&ab=3&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=142625&na=1557365486&cs=0","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://px.surveywall-api.survata.com/k","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://cl3.webterren.com/1.gif?z=36&a=162e0cc6cfb&b=%u4E2D%u56FD%u9752%u5E74%u7F51&B=UTF-8&c=http%3A//m.youth.cn/%3F_wdxid%3D000000000000000000000000000000000000000000%26_wdc%3D%26_wdt%3D000%26&d=&e=10&f=58c136dbc9653b7f&H=m.youth.cn&E=0&r=78d376f80342107c&s=0&t=0&u=1&i=en-US&j=0&k=360x512&l=24&m=&n=&o=-7","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ib.adnxs.com/setuid?entity=158&code=WtM34wAACGMfPfyQ","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ad.doubleclick.net/ddm/ad/puzgxeftxpy/ozwu/mrtjmfeqy/zkmubiiik/;ord=1523791865134","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/headerBg.gif","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=782&dpuuid=WtM34wAACGMfPfyQ","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/pokemon-go-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/uc-browser-android.png:l","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/images/logo/hover-animations/4@2x.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/vivi0010/albumset/5984090/zoomcrop/75x75.jpg?v=1523786401","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_money.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/newicons/favicon-16x16.png","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://i.redditmedia.com/zPLtJsViXQhYGfnwnSuSMTtkyhQqqtlukyJ1zvt5Gow.png?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=c02b20b0a0cd74620042de25372b2b77","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/i3/TB12wM3HXXXXXbxapXXdFmWHFXX-207-60.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://login.taobao.com/jump?target=http%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.user.getusersimple%2F1.0%2F%3Ftbpm%3D1%26jsv%3D2.4.11%26appKey%3D12574478%26t%3D1523791821652%26sign%3D892d1785a3e46dd3882630f5b49ebb17%26api%3Dmtop.user.getUserSimple%26v%3D1.0%26H5Request%3Dtrue%26jsonpIncPrefix%3Dsmb_xc%26timeout%3D2000%26type%3Djsonp%26dataType%3Djsonp%26callback%3Dmtopjsonpsmb_xc2%26data%3D%257B%257D","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/F6/85DC85.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/sports/2_img/vcg/4f160954/104/w1024h680/20180415/NS8H-fytnfyp5066034.jpg/w710h400z1l50t122e.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://d5.sinaimg.cn/pfpghc2/201804/13/0a2afc974edc4e75aba8e7fd30676624.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33047406","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180414102350-14-syrian-airstrike-041418-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f11/14f39ce3d4eb4e428ce7df4ce4f798ef_erotic_285x160.jpg?cno=16d","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/e7/76/67/e776679dd59b50116bdfad268310b2e5/e776679dd59b50116bdfad268310b2e5.22.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/12/35/a2/1235a262130eac19cea24956cd700a5e/1235a262130eac19cea24956cd700a5e.23.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afp.alicdn.com/afp-creative/creative/u113716014/90b26769846bb1a165033a1c426b93f8.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_q6A0_9LbBFSFchKXdkNElA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4157.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BYWRjNTczNjYtMGM4Mi00ODA3LWI1YmEtOWUyZDZkNTcxZGRhXkEyXkFqcGdeQXVyNDU4Njg2MzM@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41Wo77ejldL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/amazonservices/seller_success_stories/2018/03_Apprenticeships/apprenticeship_1242x450._SX1242_CB501585757_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=853446045808&photoType=4","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/favicon.ico","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/close2.svg","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://d31qbv1cthcecs.cloudfront.net/atrk.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/common/types.min-vflzbELvV.js","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NBA_One-Play_Simmons_huge_dunk/dm_180414_NBA_One-Play_Simmons_huge_dunk.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://r.nexac.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=https://beacon.krxd.net/data.gif?_kuid%3DL6N7iig7%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6865528665029394&output=html&h=280&slotname=4177786880&adk=3456403227&adf=646570834&w=336&lmt=1523792014&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&flash=0&wgl=1&dt=1523792013357&bpp=53&bdt=11250&fdt=82&idt=882&shv=r20180411&cbv=r20170110&saldr=aa&correlator=5842617019658&frm=20&ga_vid=151777037.1523792004&ga_sid=1523792014&ga_hid=963839304&ga_fc=0&pv=2&iag=3&icsg=2&nhd=1&dssz=3&mdo=0&mso=0&u_tz=-420&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=12&ady=410&biw=360&bih=512&abxe=1&scr_x=0&scr_y=1&eid=21061122%2C20040069&oid=3&rx=0&eae=0&fc=656&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C360%2C512&vis=1&rsz=%7C%7CeE%7C&abl=CS&ppjl=f&pfx=0&fu=8208&bc=5&osw_key=1763479670&ifi=1&xpc=AWm3HUN5tZ&p=https%3A//m.pixnet.net&dtd=961","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fm.youtube.com%2Fsignin%3Fnoapp%3D1%26app%3Dm%26action_handle_signin%3Dtrue%26next%3Dhttps%253A%252F%252Fm.youtube.com%252Fsignin_passive%253Foriginal_url%253Dhttps%25253A%25252F%25252Fm.youtube.com%25252F%26feature%3Dmobile_passive%26hl%3Den&passive=true&service=youtube&hl=en&uilel=3&ltmpl=mobile","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypal.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/data/ocs/section/index3.html:homepage-magellan-zone-1/views/zones/common/zone-manager.izl","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo1NC40MDgJZWFkYjNhNDMtNDRhNy00MTFkLTk5ZTItZDkxNWYzMGM4MTQxCTMyNjE4MzEJMzEyMjgwNAk1OTE4Mjg4Mzc0X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc3OAkzNTU3NzkzCXh4bAkxCS0JV0FQCS0JMQkyMGI3YTA0YTUzNWViYzE3ODA5ZTVlNWQ3OWE4NzQ4NAkyNWEyYzgwNy0zMjM4LTMzYzQtOTFhZC03OWYyZDZlN2JiOGQJNDIzMjIJMC4wMDExMTExMTExCTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjAzMjE6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwMjowLjB8dXNlcl9nZW5kZXI6NTAxOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTQJNDUwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=5a49377c6ceb65e6&p=JaLIBzI4M8SRrXny1ue7jdRfXi3H3yjcuvuYJg%3D%3D","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/modal-vfls56Rdx.css","request_type":"css"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/tr/?id=130492214192672&ev=Microdata&dl=https%3A%2F%2Fwww.pinterest.com%2F&rl=&if=false&ts=1523791924437&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Asite_name%22%3A%22Pinterest%22%2C%22og%3Adescription%22%3A%22Discover%20recipes%2C%20home%20ideas%2C%20style%20inspiration%20and%20other%20ideas%20to%20try.%22%2C%22og%3Aimage%22%3A%22https%3A%2F%2Fs.pinimg.com%2Fimages%2Ffacebook_share_image.png%22%2C%22og%3Atitle%22%3A%22Pinterest%22%2C%22og%3Atype%22%3A%22website%22%2C%22og%3Aurl%22%3A%22https%3A%2F%2Fwww.pinterest.com%2F%22%2C%22twitter%3Aapp%3Aandroid%22%3A%22com.pinterest%22%2C%22twitter%3Aapp%3Aid%3Aipad%22%3A%22429047995%22%2C%22twitter%3Aapp%3Aid%3Aiphone%22%3A%22429047995%22%2C%22twitter%3Acard%22%3A%22summary_large_image%22%2C%22twitter%3Asite%22%3A%22%40pinterest%22%7D&cd[Meta]=%7B%22title%22%3A%22Pinterest%22%2C%22meta%3Adescription%22%3A%22Discover%20recipes%2C%20home%20ideas%2C%20style%20inspiration%20and%20other%20ideas%20to%20try.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=30&it=1523791918963","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://touchsplash.radar.imgsmail.ru/update?t=nav&v=1&i=all%3A1%2Cnavigate%3A1&p=touchsplash&rnd=0.04390433907531044","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/shadow_y.gif","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/a.gif?V=2.3.1&CI=sz:360x512|dp:24|ac:Mozilla|an:Netscape|cpu:|pf:Linux%20x86_64|jv:1.3|ct:unkown|lg:en-US|tz:7|fv:|ja:0&PI=pid:|st:|et:1|ref:|hp:unkown|PGLS:|ZT:|MT:|keys:|dom:749|ifr:0|nld:1523791823990|drd:0|url:|ch:&UI=sid:1654439800560.783.1523791824016|vid:9533882159274.413.1523791820192|lv::1:1:1|un:::::|uo:|ae:|su:|lu:|si:|rs:0|dm:0&MT=&EX=ex1:FEED__0|ex2:ustat-__149.20.63.13_1523791820_0.19234800,0,abt=80_162_173,xiding=0&gUid_1523791824035","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/uptodown-android-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/she081363/albumset/10105026/zoomcrop/75x75.jpg?v=1523126674","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/Nygft4j6luNxOMjZm4cONKyAqpva8Gn1YfDEQGB0Qhx3sN8cT_vPGm4tF1bjuvQ=w384","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420347173841482.png","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/assets/img/logos/logo-espn-82x20@2x.png","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://tpc.googlesyndication.com/safeframe/1-0-23/html/container.html","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=icco6m5&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/wss/fonts/SF-Pro-Text/v1/sf-pro-text_regular.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/46135cfe-333c-4b55-9fa7-dc4b8e5e917f_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://m.360buyimg.com//mobilecms/s276x276_jfs/t17455/127/841179967/72035/3b3005e7/5aab90daNce6daad7.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0414/dm_180414_CFB_FLORIDA_FRANKS_60_YARD_RUSH_TD/dm_180414_CFB_FLORIDA_FRANKS_60_YARD_RUSH_TD.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/lbt/201804/W020180420293219617659.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20170918/408d5cef628d1b29753e01.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTQ0OTQwMTQyN15BMl5BanBnXkFtZTcwOTI2OTk2OQ@@._UY500_CR210,80,402,402_SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/img/uploader/pickupselection/SP%20%E6%9C%AC%E6%97%A5%E6%9E%A0_13%E6%97%A5%E5%89%8D01.jpg","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflUiilPi/pubsub.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"https://d31qbv1cthcecs.cloudfront.net/atrk.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.googletagservices.com/tag/js/gpt.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/_h/975a7d20/coreui.statics/externalscripts/jquery/jquery-2.1.1.min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-share_btns_lead_mega/td-applet-viewer-templates-share_btns_lead_mega-min.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.krxd.net/ctjs/controltag.js.09a5e91f12425e5066daa6d1e2a6a6c9","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"http://m.hao123.com/?vit=h123&from=3w123","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/Fonts/Montserrat-SemiBold.woff2","request_type":"font"}
+{"origin":"http://www.hao123.com/","request_url":"https://cpro.baidustatic.com/cpro/ui/pr.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm=&ex=doubleclick.net&google_tc=","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjstKzDRlgk_NEZliqseg1k_rtpO_JRkKBuDE7MyPcIH1ia5wsRsCC_RyDkPE7qRfxIZgQNOlo-qddGEqgZ195NEqSJ1O31iEfkYCeS8C88CFGE0YHGVuv8jq7YF-JoE_ae0yucNlZhvkb86-3SENlCN5uwcrpULDUmdi2KpkKNBA64uL_GVSihQLbmlRa89abGmzWn3G1TccV3VRw4eE3HttSt8bwESc_5p41Eq3F9BZRqk7P8hbkY2TkKrWGWk6HBaQ&sig=Cg0ArKJSzG8Lo1z5-RFHEAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-279179-2&cid=10481343.1523791867&jid=194842542&gjid=457813373&_gid=1131671526.1523791867&_u=aGBAgUAj~&z=1958789321","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12428&impid=&at=1&mkey=&latcy=3511&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=5059068254527&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791941713","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://odr.mookie1.com/t/v2/sync?tagid=V2_4531&src.visitorid=CAESEAemuSFjUSB24bh_nc4opjk&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6&google_cver=1","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/fcmdynet.js?&cid=8CUNL3XVM&cpcd=NaEyhZu73BMxXJoVzER-IQ%3D%3D&crid=144402028&size=414x74&cc=US&sc=CA&wsip=2886781043&https=1&vif=1&requrl=https%3A%2F%2Fwww.msn.com%2F&vi=1523791837719580622&lw=1&ugd=3&chnm3=startPage&re=1&dma=807&msa=2&rtbs=1&nb=1","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/v1/article/search/tag/trending?pageSize=100","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"http://www.vk.com/","request_type":"html"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/io-queue/io-queue-min.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://px.ads.linkedin.com/collect/?time=1523791867534&pid=4373&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&fmt=js&s=1","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://stags.bluekai.com/site/36841?dt=0&r=1633875998&sig=2032588566&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmiRglWl1u3dep5hJEi0rvuNa028whzGcC3z3bh3gaqjG33LRr3ADZXAl5XSvQ7AsZVVQWDuLGoEzNmp9xoOQeP0hFr","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://bat.bing.com/action/0?ti=5637027&Ver=2","request_type":"other"}
+{"origin":"http://www.txxx.com/","request_url":"https://mc.yandex.ru/watch/23578849?wmode=7&page-url=https%3A%2F%2Fm.txxx.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-420%3Ai%3A20180415043312%3Aet%3A1523791993%3Aen%3Autf-8%3Av%3A1072%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A1396006951435%3Arqn%3A1%3Arn%3A1045535901%3Ahid%3A19071466%3Ads%3A0%2C0%2C632%2C319%2C3862%2C0%2C0%2C4900%2C328%2C%2C%2C%2C8782%3Afp%3A5928%3Awn%3A34150%3Ahl%3A3%3Arqnl%3A1%3Ast%3A1523791993%3Au%3A1523791993707055678%3At%3APorn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/obsidian/typography-vfl1B2M2Y.css","request_type":"css"}
+{"origin":"http://www.reddit.com/","request_url":"https://alb.reddit.com/i.gif?q=CgADAAAAAAAHad4KAAUampD8jABivggABwAAAAEA&s=Gf-m8oubfWvFZO2YViGxOMpMvmnu5ikWMf4t_qCbJtE=","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/_h/9be151e5/coreui.statics/images/1x1clear.gif","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://ib.adnxs.com/getuid?https://aax-eu.amazon-adsystem.com/s/ecm3?id=$UID&ex=appnexus.com&","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=qXEKf9uYMy9IFdfcjg0qdt7q,0.9928193123616662&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031523791949%04viewtime%03%2BheaderBody%3A1%231523791945.603%2BheaderBody%3A1~1523791948.370%2BheaderBody%3A2%231523791945.603%2BheaderBody%3A2~1523791948.370%2BheaderBody%3A3%231523791945.603%2BheaderBody%3A3~1523791948.370%2BheaderBody%3A4%231523791945.603%2BheaderBody%3A4~1523791948.370%2BLifetool%3A1%231523791945.603%2BLifetool%3A2%231523791945.603%04_E%03l_viewtime","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://deazs14tb5j7o.cloudfront.net/img/29/r20.gif?rnd=0-1-13960-0-0-29-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=NjY5OTBmMjQtODcwNi0zMGYyLTk3ZjMtNTc1YzBmZTQ2ODQzCTQ1CVBEUFMwMDAwMDAwNTk5NTAJNTAJMzU0MDczNgkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=470&dpuuid=3134965336564981658","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/imo-messenger-android.png:l","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/static/search/clear.png","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/images/mobile/AppUpsell/IMDbLogo-842911133._CB499603753_.png","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"http://h5api.m.tmall.com/h5/mtop.user.getusersimple/1.0/?tbpm=1&jsv=2.4.11&appKey=12574478&t=1523791821652&sign=892d1785a3e46dd3882630f5b49ebb17&api=mtop.user.getUserSimple&v=1.0&H5Request=true&jsonpIncPrefix=smb_xc&timeout=2000&type=jsonp&dataType=jsonp&callback=mtopjsonpsmb_xc2&data=%7B%7D","request_type":"html"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/QMMAAOSwl9RaTA7G/$_57.JPG","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/daca_images/simgad/1528772358884547459?sqp=-oaymwEKCNgEELoCIAFISA&rs=AOga4qm_V3uD42Vt7aOLT6P8egzI248BPg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/022/107/102/big_lq/21b380396689d3dca9ac34b7e63c2e20.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_z4f8FPr9Nuxn5BgKXWQPOA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://643108e7617ef.cdn.sohucs.com/198e951a4ee84b42be7d48b38bf5cfa8.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/uW88n4q0uRTV6qh_xB4VrBOF99TXwPS6K63dUHE7-OA.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/uk-sports/brands/AquaSphere/BrandStore/Marketing/Gateway_1050x1050_PennJuane._CB532265858_.jpg","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/bundles/base/LandingPage.js/02e07ac4770d.js","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/concat/common/js?h=ed29nkjpsa16bhrjq4na16owq-1mucgfycc664m7vmhpjgqse65-1l5rurej3h44qodo5rn0cdvyn-8om6v2ckrxsbnwf40t9ta8a7e-8jlhg6lqacthgadello7fgxzm-28w7d5j2k2jtil9ncckolke4m-9jzlwicvu376y9q4vjq77y5ks-1m0whdrwis44c1hoa9mrwhlt4-1uvutm1mpyov7rqhtcf8fksby-aac54ic1fmca5xz1yvc5t9nfe-1hn40w0bomeivihj9lopp4hp2-c0121povror81d0xao0yez4gy","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/atlasgrotesk/AtlasGrotesk-Light-Web-vfl5CyyQq.woff","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/hi_res.min-vflf-Wbx9.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/js/chartbeat.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/se/static/js/base/ala/util_e135ec4.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/802b93f0fe41b41869a2e449e704709d.js?conditionId0=378623","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"https://mc.yandex.ru/metrika/watch.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTIxNzcmdGw9MTI5NjAw&piggybackCookie=CAESELxF6tFqKyAII2LyRG8Ithg&google_cver=1","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/icon-android.svg","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted7.svg","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/js/en.v10.260.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api.js?onload=recaptchaOnloadCallback&render=explicit","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ml314.com/tag.aspx?1532018","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://connect.facebook.net/signals/config/1097950916987081?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61zG8AVQjOL.js?AUIClients/IDPMobileAssets","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3iuD54/yK/l/en_US/uWsTnmkea35.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/sg/google-network/1/rtb-h/?taboola_hm=CAESEPPS6R5WHeMwb_EQlCFBPBA&google_cver=1","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com","request_type":"other"}
+{"origin":"http://www.paypal.com/","request_url":"https://tapestry.tapad.com/tapestry/1?ta_partner_id=950&ta_redirect=https%3A%2F%2Ft.myvisualiq.net%2Fsync%3Fprid%3D1001%26ao%3D0%26pruuid%3DTAPAD_%24%7BIDS%3Akey%7D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=cf1ec655-40a0-11e8-9605-1fdd5b850201","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixanalytics.com/pa.gif?t=mainpage_index_new&ver=1.0&random=0.11378384345225401&document.referrer=&document.URL=https://m.pixnet.net/?&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https://m.pixnet.net/?&window.pageXOffset=0&window.pageYOffset=0&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla/5.0%20(Linux;%20Android%206.0.1;%20Moto%20G%20(4)%20Build/MPJ24.139-64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180413.110452&window.devicePixelRatio=3&_pix.login_name=a41f026f52b53327abdd6961a40522b0&_pix.owner=undefined&_pix.visitor=&_pix.openid=undefined","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-shopping.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/home-illo-business.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t16849/271/702371255/4462/d55edd83/5aa10cf6Nee5122a5.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/69/D15B73.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/jieming20171026-56.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/huangli083002.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb2.qujishu.com/m.html?mediaid=0c29cbf60d19f75820469bd7d48deda1fae793d7300e3b14b667a3d4532cfea910a2d3e0978cb4b67f27a9bf9778a3e2&cookie_version=2&timestamp=1524189919&ext_data=","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.1rx.io/usersync2/pubmatic","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://www.pixnet.net/","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5478000/5478383/220x165/10.jpg","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Hearthstone-429x572.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180315070729-cnnmoneytoysrus1-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://f11.baidu.com/it/u=307895155,2113518322&fm=76","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img16/app/AppyHours/GW/Revised/1242x450_GW_02._SX1242_CB500224812_.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/i2/TB1nQXGJVXXXXcEXXXXKKOh2VXX-432-567.jpg_q50.jpg?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/02/amazonservices/seller_success_stories/2018/02_Pampered_gardens/pampered-gardens_1242x450._CB487532345_.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/dmsmty/212_160_/t0169bae74b42a1cbae.webp","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://a942dd96f9614de5104a06f7c9c5646bb.profile.vie50.cloudfront.net/test.png","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/sc/h/5ndxqp5qfiw8dfhnuwft3nunh","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/vap/video/airy2/prod/2.0.1283.0/images/beacon._TTW_.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/optout_check?callback=Krux.ns._default.kxjsonp_optOutCheck","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/Bold/latest.woff2","request_type":"font"}
+{"origin":"http://www.msn.com/","request_url":"https://sb.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-579b419764746d06c7000ab4.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/05b46749107d596578bf95b28da72a59.js?conditionId0=474093","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMjYmdGw9MTI5NjAw&piggybackCookie=18072662329610053966","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://m.xhamster.com/","request_type":"html"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://stackoverflow.com/","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://wordpress.com/","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://platform.twitter.com/widgets/tweet_button.73a792b0fbc7ab73a8e3b3db9c36a8ac.en.html","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted3.svg","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted11.svg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://use.typekit.com/glm4yoq.js","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhmYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oECqDXRLDxGo5mVocVLAUHyi7MkOg?xjs=s1","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/playerjs/js/init.min.js?v=6","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://aa.agkn.com/adscores/g.js?sid=9212244187&_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/5w3jqr4k?redir=https%3A%2F%2Fcm.g.doubleclick.net%2Fpixel%3Fgoogle_nid%3Dg8f47s39e399f3fe%26google_push%26google_sc%26google_hm%3D%24%7BTM_USER_ID_BASE64ENC_URLENC%7D","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=10&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A10%7D&logFlag=uaction_1523791857874&t=1523791867876","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://wgo.mmstat.com/sb.sbp.action?cache=eb2ad14&gmkey=EXP&gokey=platform%3DAndroid%26smbSid%3DRiZaE%252BYPjyICAZUUPw3CLc3s_1523791946369%26apuri%3Dsb_show%26source%3Dsb%26bizKey%3Dtaobao%26linkKey%3Dtaobao%26sceneType%3Ddefault%26page%3DmainIndex%26uiKey%3DtbBanner%26rbbt%3Dbc.mainIndex.6.0.0%26appkey%3D24585258%26logtype%3D2&cna=RiZaE%2BYPjyICAZUUPw3CLc3s&spm-cnt=a215s.7406091.0.0&logtype=2","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=NjY5OTBmMjQtODcwNi0zMGYyLTk3ZjMtNTc1YzBmZTQ2ODQzCTQ1CVBEUFMwMDAwMDAwNTk5NDkJNTAJMzUzMTk4NwkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/avatar/cxrc/0/0/resize/65x0.png?v=","request_type":"image"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://www.facebook.com/rsrc.php/v3/yn/r/lH1ibRl5GKq.png","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.gstatic.com/recaptcha/api2/logo_48.png","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1LNMxPXXXXXbhaXXXXXXXXXXX-183-129.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://www.360.cn/","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://xid.i-mobile.co.jp/RestoreXidToMediaStorage.html","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=krux&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/01/ape/sf/mobile/msf-1.19._V497204134_.html","request_type":"html"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201802/25/156017662/thumbs_25/(m=eafTGgaaaa)(mh=-gsBFOkMI8REzxuM)4.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/02/12/66/021266940fb1ad0ffe667e5e2269cb74/021266940fb1ad0ffe667e5e2269cb74.1.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s2.pimg.tw/album/nonie610/element/69757882_1366731678-60109239/zoomcrop/90x65.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/CPwAAOSwTmtZ78kL/s-l500.webp","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://img1.360buyimg.com/da/s720x352_jfs/t17359/232/1623763178/194540/5a28a9a4/5ad0a9f5N913d48df.jpg!cr_1125x549_0_72.dpg.webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/6d28bed7-e2b7-4873-866c-67f6ef96ec48/scale-to-width-down/100","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://imasdk.googleapis.com/js/sdkloader/ima3.js?_=1523791941895","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/fonts/roboto-900.woff","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-coreui-with-i18n.min-vflHW2l16.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-debug/td-applet-viewer-templates-debug-min.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://cdn.krxd.net/ctjs/controltag.js.dc955599a3976b2e658d60927793d9ea","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nfl.png?w=110&h=110&transparent=true&h=240&w=240","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://widget.manychat.com/726265994430459.js?_=1523791941894","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://rva.outbrain.com/analytics-v1.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/floors/floor06005.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/itemrep/BdrainswDislike/dist/index_ea990c4.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://x.skimresources.com/?provider=tbin&provider_id=39041E2B94ED6EF00CB315F995BE6F73&skim_mapping=true","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsubMLobpQyKgJa3kLf2E1c52pEH6J1ZboEyJdb01kCTRCpU78ZBql5ZDLQIV-QXVtCM3dA27TGAEevyBfNjra5q05dBZeLjultKtQr3r402sOkQBL_3djIl68nidLFkaVVClFeizRqis6NE9znjyft9wXSGCe8gJpNC1Ul4AYLDlGlTlf6CNOrbeNA1ETF4UYIVesapjF1iYLAbd562IImEPe4CiuXyWOfOVTC9PZwa3EgGIMlLY3e8pr93YQ7p&sig=Cg0ArKJSzIPlsjGJlfa_EAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/gen_204?s=webaft&atyp=csi&ei=FzjTWu61BIe28AOtqITQCw&rt=wsrt.2186,aft.523,prt.262","request_type":"html"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://accounts.google.com/o/oauth2/postmessageRelay?parent=https%3A%2F%2Fwww.pinterest.com&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en_US.pa4EfGZJtyM.O%2Fm%3D__features__%2Fam%3DAQE%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCNvuMxw8LpLrCWFeoIaET1OMP8dSQ","request_type":"html"}
+{"origin":"http://www.github.com/","request_url":"https://api.github.com/_private/browser/stats","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2","request_type":"font"}
+{"origin":"http://www.instagram.com/","request_url":"https://connect.facebook.net/en_US/sdk.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61WZygn8wbL.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,513EDHaa7SL.js,11sT42sZnQL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61x-Yxr2raL.js,318CMPRminL.js,11dYToHZZ0L.js,21TDqwIsfQL.js,01qkmZhGmAL.js,012YXvM7lUL.js_.js?AUIClients/AmazonUI","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/us/shop/bag/status?apikey=SFX9YPYY9PPXCU9KH","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://sb.scorecardresearch.com/b2?c1=2&c2=6034961&rn=0.7700663258524918&c7=https%3A%2F%2Fm.imdb.com%2F&c3=&c4=https%3A%2F%2Fm.imdb.com%2F&c5=&c6=&c10=&c15=&c16=&c8=IMDb%20-%20Movies%2C%20TV%20and%20Celebrities%20-%20IMDb&c9=&cv=1.7","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://w.usabilla.com/0649ef72a7be.js?lv=1","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.advertising.com/ups/28/sync?uid=91191954147729940174299115411397659455&_origin=1&redir=true&verify=true","request_type":"other"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spad.i-mobile.co.jp/script/adcore_sp_inline-0.2.js?20110201","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.facebook.com/tr/?id=731697573629176&ev=Microdata&dl=https%3A%2F%2Fwww.cnn.com%2F&rl=&if=false&ts=1523791886534&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Apubdate%22%3A%222014-02-19T19%3A15%3A05Z%22%2C%22og%3Aurl%22%3A%22https%3A%2F%2Fwww.cnn.com%22%2C%22og%3Atitle%22%3A%22CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos%22%2C%22og%3Adescription%22%3A%22View%20the%20latest%20news%20and%20breaking%20news%20today%20for%20U.S.%2C%20world%2C%20weather%2C%20entertainment%2C%20politics%20and%20health%20at%20CNN.com.%22%2C%22og%3Asite_name%22%3A%22CNN%22%2C%22og%3Atype%22%3A%22website%22%7D&cd[Meta]=%7B%22title%22%3A%22CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos%22%2C%22meta%3Adescription%22%3A%22View%20the%20latest%20news%20and%20breaking%20news%20today%20for%20U.S.%2C%20world%2C%20weather%2C%20entertainment%2C%20politics%20and%20health%20at%20CNN.com.%22%2C%22meta%3Akeywords%22%3A%22cnn%20news%2C%20daily%20news%2C%20breaking%20news%2C%20news%20today%2C%20current%20events%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=28&it=1523791885403","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-2623535-1&cid=164959871.1523791909&jid=824515207&gjid=259805078&_gid=303671758.1523791909&_u=IGBAiAABB~&z=1593280762","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DXZ4D3PPDB36HTEGXD7ZH%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec:1000","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845943,aid=exp_shehui-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://mobpushup.com/lg.php?bannerid=1858666&campaignid=1165302&zoneid=1617677&OACBLOCK=3600&OACCAP=1&loc=https%3A%2F%2Fen.savefrom.net%2F&cb=e3fceae0f4&ttl=1523792550&hash=562164009482ce0abc79d8e48d1fcb5f&co=1&rf=1&xref=ZW4uc2F2ZWZyb20ubmV0&fs=0&cf=0&sw=360&sh=512&sah=512&wx=0&wy=0&ww=360&wh=512&wiw=360&wih=512&wfc=3&pl=https%3A%2F%2Fen.savefrom.net%2F&drf=&np=0&pt=0&nb=1&ng=1&ix=0&nw=0","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=75557&dpuuid=R1B342_A3207491_1929738A&redir=https://abp.mxptint.net/sn.ashx?ak=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=420&dpuuid=5ad337e4986a9549","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/sprites/main/b5e8f97bb00117930721753843eec5b5@2x.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/olx-android.png:l","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/logos/tv_4k_small_2x.png","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/images/vmobile/sprite-mobile_menu.png?cache=2018041212","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hjesmmnb657274/albumset/7410806/zoomcrop/75x75.jpg?v=1523785806","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=2e68b153-5f6c-4bef-a554-4d86b35719b5&ttd_puid=879ae321-40a0-11e8-a40f-0242033f0d7d%2C","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938303_9694733815651&itemspaceid=13713&adps=6400320&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938303","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://fonts.gstatic.com/s/notoserif/v6/ga6Law1J5X9T9RW6j9bNdOwzfReece9LOoc.woff2","request_type":"font"}
+{"origin":"http://www.wordpress.com/","request_url":"https://fonts.gstatic.com/s/notosans/v7/o-0NIpQlx3QUlC5A4PNjXhFVZNyBx2pqPA.woff2","request_type":"font"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31uzIgVilQL._AC_SY160_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/619HSmLwTsL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/vk4AAOSwUUxavDvt/s-l500.webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/29db90a6-36c9-413d-a76c-35ed93b9dde4/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/static-images/v2/ico/favicon.ico","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://s.thebrighttag.com/tag?site=voKfK9l&H=-2cvf10o&referrer=netflix.com%2Fbt%2FnmLanding&docReferrer=https%3A%2F%2Fadtech.nflximg.net%2Fadtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522f1fdc59c-9452-4167-a583-cc8ede9a2929%2522%257D&mode=v2&cf=1968499%2C2766978%2C2812541&_cb_bt_data(%27gclid%27)=&btpdb.voKfK9l.dGZjLjI3ODY5NTI=VVNFUg","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-rebrand-core.min-vflwkMCYh.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://t.co/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvx41&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=1","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://39d0825d09f05.cdn.sohucs.com/sdk/passport-4.0.3.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/media/motion/2018/0413/dm_180413_nfl_amendola_on_belichick/dm_180413_nfl_amendola_on_belichick.jpg&w=686&h=386&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/tc?tcreq4log=1&r=1523791826025&logid=1811881676&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=10&cst=2&ref=index_iphone&logFrom=callbaidu&logInfo=defaul_try","request_type":"text"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://adv-sv-show.focus.cn/be_fox_say3?cityCode=UM&adposId=50&callback=jQuery33107277789616181776_1523791937756&_=1523791937759","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61WZygn8wbL.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,513EDHaa7SL.js,11sT42sZnQL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61x-Yxr2raL.js,318CMPRminL.js,11dYToHZZ0L.js,21TDqwIsfQL.js,01qkmZhGmAL.js,012YXvM7lUL.js_.js?AUIClients/AmazonUI","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768230&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791996144&fs=2&pvid=a192e51b0d9a84c3363b377651f8d0f2&cg=ce12410f6ac803dda75935f34a3e8c5a","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1&verify=true","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/pixel.gif?source=smarttag&fired=user_data_timeout&confid=ITb_4eqO&_kpid=e9eaedd3-c1da-4334-82f0-d7e3ff883c87&_kcp_s=CNN&_kcp_d=www.cnn.com&_knifr=15&_kua_kx_tz=420&_kua_kx_lang=en-us&_kua_kx_tech_browser_language=en-us&_kua_user_agent=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&_kua_turner_guid=5ad337f701115d0a3c732e5b38006d32&_kua_aa_id=2D699BFD851D2AAF-600001710000D60D&_kua_af_id=4BEA7D18C905084D-3799DBF4B8681903&_kpa_cnn_site=cnn&_kpa_cnn_rollup=homepage&_kpa_keywords=cnn%20news%2C%20daily%20news%2C%20breaking%20news%2C%20news%20today%2C%20current%20events&_kpa_cnn_lob=news&_kpa_cnn_brand=cnn&_kpa_cnn_bizunit=cnn%20domestic&_kpa_cnn_sitename=cnn.com&_kpa_cnn_sitesectionlevel1=cnn%20homepage&_kpa_cnn_sitesectionlevel2=cnn%20homepage%3Anvs&_kpa_domain=cnn.com&_kpa_cnn.com_meta_keywords=cnn%20news%2C%20daily%20news%2C%20breaking%20news%2C%20news%20today%2C%20current%20events&t_navigation_type=0&t_dns=0&t_tcp=681&t_http_request=-1&t_http_response=448&t_content_ready=8315&t_window_load=0&t_redirect=0&interchange_ran=true&userdata_was_requested=true&userdata_did_respond=false&store_user_after=suox90laq&_kurl_=https%3A%2F%2Fwww.cnn.com&sview=1&kplt2=23410&kplt3=23412&kplt4=23428&kplt5=23438&kplt6=23445&kplt7=23464&kplt8=23474&kplt9=23477&kplt12=23409&kplt14=23511&kplt15=23548&kplt16=23645&kplt17=23647&kplt18=26137&kplt19=26604&kplt20=32631&kplt21=32696&kplt22=33127&kplt23=33132&jsonp_requests=https%3A%2F%2Fbeacon.krxd.net%2Foptout_check%2CNaN%2Chttps%3A%2F%2Fcdn.krxd.net%2Fuserdata%2Fget%2CNaN","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/premium/launch-banner.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/components/rebrand_sidekick-vfl9tCZlF.css","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEFaeJ3fSAKYAYOswo3ncNGI&google_cver=1","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=rightmedia.com&xid=E0","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://d.agkn.com/pixel/2387/?%g&che=%n&col=%ebuy!,%esid!,%epid!,%eaid!,%ecid!","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=76&redir=https%3A%2F%2Fads.yieldmo.com%2Fv000%2Fsync%3Fmm_user_id%3D%5BMM_UUID%5D&mm_bnc&mm_bct","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://t.myvisualiq.net/sync?prid=1001&ao=0&pruuid=TAPAD_7307dbc1-40a0-11e8-830d-0a580a02023f","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/ED/169401.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/CE/6FAE42.png","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/images/vmobile/sprite-flag-icons.png?cache=2018041212","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/ummyradio/icon_16.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/r/image/2018-02-09/5eff465843790328c268ba050c7fb07f.png","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/gno/sprites/new-nav-sm-smile-sprite-global-2x_blueheaven._CB487546343_.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://fw.qq.com/ipwhere?callback=jsonp_2961483089200","request_type":"html"}
+{"origin":"http://www.weibo.com/","request_url":"http://m.weibo.cn/?&jumpfrom=weibocom","request_type":"html"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201803/01/156425852/original/(m=eafTGgaaaa)(mh=xaV14QWomSF07lIp)5.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://ct.yimg.com/cy/1768/39361574426_98028a_48sq.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1e/e90ec6eb9a1d3cb4d827d56cd2a7cf66_erotic_285x160.jpg?cno=9edd","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/I/91Nw5vN+CQL._AC_SR300,300_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/eec8ed2b-1fc2-423a-9ca7-c49e7eaf4474/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.wikia-services.com/__track/special/adengadinfo?a=&ad_status=collapse&beacon=NyiV-67qg0&browser=Android%20Chrome%2058&c=1452001&cb=1523791986611&client_ip=208.70.31.93&country=US&dev=false&dev_cat=mobile&event_ts=1523791986&f=Home&kv_abi=&kv_ah=&kv_esrb=teen&kv_lang=en&kv_pos=TOP_LEADERBOARD&kv_ref=&kv_rv=&kv_s0=fandom&kv_s0v=home&kv_s1=_fandom&kv_s2=home&kv_skin=fandom_mobile&kv_top=&kv_wsi=dlh1&labrador=&lc=en&page_width=360&pg_type=home&pv=1&pv_number=1&pv_number_global=1&pv_unique_id=af377f25-1ffc-4914-9834-c80ec4217531&r=direct&r_type=direct&s=fandom_mobile&session=Q4ulawcgCl&session_id=5d21d0a7-b14a-4f7f-ac4b-8ba9846d26f7&site=web&t=event&time_bucket=4&timestamp=1523791986606&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&viewport_height=512","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_194.js?cb=195","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/main.f9af3485554223a4.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-videocluster/td-applet-viewer-templates-videocluster-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-content_body/td-applet-viewer-templates-content_body-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/listing/tool/yads/impl/yads-stream-lib.js?2018041501","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.ru/","request_url":"http://www.google.ru/","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://staticxx.facebook.com/connect/xd_arbiter/r/FdM1l_dpErI.js?version=42","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/css/s_zgt.css?211","request_type":"css"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://cas.criteo.com/delivery/ajs.php?ptv=48&zoneid=773528&cb=38994372435&nodis=1&charset=UTF-8&dc=2&loc=https%3A%2F%2Fmail.ru%2F","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://snap.licdn.com/li.lms-analytics/insight.min.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixanalytics.com/js/c.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://connect.facebook.net/en_US/sdk.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://connect.facebook.net/en_US/sdk.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/r?c2=6035748&d.c=gif&d.o=cnn-adbp-domestic&d.x=180293245&d.t=page&d.u=https%3A%2F%2Fwww.cnn.com%2F","request_type":"other"}
+{"origin":"http://www.360.cn/","request_url":"http://p6.qhmsg.com/t01a03df1ddec4c9046.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://sync.ipredictive.com/d/sync/cookie/generic?https://s.amazon-adsystem.com/ecm3?id=${ADELPHIC_CUID}&ex=adelphic","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://token.rubiconproject.com/token?pid=2179&pt=n","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/ZMAwryCI?redir=https%3A%2F%2Fdsum-sec.casalemedia.com%2Frum%3Fcm_dsp_id%3D88%26external_user_id%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=mplatform.com&id=11458705567757192604","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a671c9100015ad3387a18b370d51763&pid=mm_113716014_12970037_52768238&cid=268282&mid=87911&oid=446&productType=1&qytInfoMTime=1523728959&cb=828226750","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://top-fwz1.mail.ru/counter?js=13;id=110605;u=https%3A//mail.ru/touch;st=1523791840769;title=Mail.Ru;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=8444bcd29777bf8d;ver=60;lvid=1523791844609%3A1523791844617%3A2%3Ae5d8a31e801c4e17a79c5b7f63693070;opts=sec;_=0.4183867311965488","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1175&dpuuid=Yz_rmWVp6pJ7PemTNGiimTVut5t7be6aN2-GZdRs","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://inews.gtimg.com/newsapp_ls/0/3274503921_294195/0?tp=webp","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/kristin0126/albumset/5979167/zoomcrop/75x75.jpg?v=1522684620","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/lTnzFEVNkSc8tN6TzpIOYtfs0_u9FK3d3xiJUmOm9Ca1nsHS9sKLnzAocQ5kOg=w192","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/chinaso.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/members/bg.png","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/ce8d6ffb-38fd-479f-9249-03f68073caa5_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-QaBhCQZp8CY/AAAAAAAAAAI/AAAAAAAAAAA/_g1qmmKDRXc/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/43/3d/67/433d670c1c426aac65ee4aaa2a40795b/433d670c1c426aac65ee4aaa2a40795b.6.jpg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://inews.gtimg.com/newsapp_ls/0/3273680108_294195/0?tp=webp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/microphone.svg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/thegay.svg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflUiilPi/watch.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://securepubads.g.doubleclick.net/static/glade.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.woff2","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-login-and-register-pages.min-vflGGJcwS.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/stencil-3.2.1/stencil-imageloader/stencil-imageloader-min.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/mobile/js/jquery-2.1.4.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/babel-polyfill/6.2.6/index.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm=&ex=doubleclick.net&google_tc=","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j39&a=702571807&t=pageview&_s=1&dl=https%3A%2F%2Fwww.linkedin.com%2Funo-reg-guest-home-mobile&dr=&dp=uno-reg-guest-home-mobile&ul=en-us&de=UTF-8&dt=LinkedIn&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=SEAAAAABM~&jid=1324324500&cid=489400867.1523791896&tid=UA-62256447-1&_r=1&z=1618093907","request_type":"html"}
+{"origin":"http://www.xvideos.com/","request_url":"https://www.xvideos.com/","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://a3698060313.cdn.optimizely.com/client_storage/a3698060313.html","request_type":"html"}
+{"origin":"http://www.twitter.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/favicon.ico?2","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.amazon-adsystem.com/v3/pr?exlist=ox_rbd_pm_an&fv=1.0&a=cm&cm3ppd=1","request_type":"html"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5api.m.taobao.com/h5/mtop.mt.getdatabyids/1.0/?jsv=2.4.8&appKey=12574478&t=1523791942744&sign=860d54a5f55ba40d3568efdf5a1aca3a&api=mtop.mt.getDataByIds&v=1.0&type=originaljson&dataType=json&H5Request=true&data=%7B%22dataids%22%3A%22137%2C217%22%7D","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://www.google.com/recaptcha/api.js?hl=en&onload=rcReady","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://www.zergnet.com/zerg.js?id=50277","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768242&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791997192&fs=2&pvid=aaead2f2ccd8e7f8fea93a90740dbae7&cg=a26f5aaee7e9fddcba424e4623df54b3","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770104&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792005432&fs=2&pvid=a6300741a8f469c0df9d7c7acf2348ea&cg=d9ce2f3a425bbf906cc7f4322189e43e","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://54.191.38.35:9571/FastcastService/pubsub/profiles/12000?TrafficManager-Token=MTUyMzc5MTk5ODIyMQ==:TcIosYYOSXBs3ZPicScYuvL/zLw=","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.in&slot=navFooter&a2=01014bfb7af69deee68af7a3dc115a1575786c271fe96fa28ed5381b37bbbb7c37f1&old_oo=0&cb=1523792012620","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/sg/neustar/1/cm?taboola_hm=164791502661000505577","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://px.adhigh.net/p/cm/bsw?bidswitch_ssp_id=yieldmo&bounced=1","request_type":"other"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/assets/site-348211d27070b0d7bb5d31b1ac3d265b.css","request_type":"css"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a671c9100015ad3387c18ad70fdeff6&pid=mm_113716014_12970037_52768230&cid=263940&mid=229046&oid=32786&productType=1&qytInfoMTime=1523728961&e=6oaUynO1A6m0LVip4%2BMlAUIexOqiEPrXkc2%2FXFLB0xHMZu4gV7luO7WaVCeDrTWA&k=65&cb=470914211","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://log.mmstat.com/w.gif?logtype=1&pre=http%3A%2F%2Fwww.gmw.cn%2F&cache=799c050&scr=360x512&cna=&isbeta=7&","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://s.pinimg.com/_/_/r20.gif?rnd=0-1-13960-0-0-34022-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://ad.doubleclick.net/ddm/activity/src=6386697;type=mppmz0;cat=pphom0;u1=;u2=;u3=;u4=;u5=;u6=mobile:mktg:personal::home:::;u7=www.paypal.com/us/home%20;u8=;u9=;u10=us;u11=;u12=;u13=;u14=;u15=;u16=;u17=;u18=;u19=;u20=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=1","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/kingsoft-android-office-international-android.png:xl","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/se/static/img/iphone/logo.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/tm.PNG","request_type":"image"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2@2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/favicon/favicon-96x96.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/rubicon","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://vdms-ssl.cedexis-test.com/img/16999/iuni3.html?rnd=-1-1-13960-0-0-16999-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/4ebfa4bb-fae7-4de7-9737-699242f7c343_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/385000/385087/220x165/4.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/f44d305ea1ac1c3d054522.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/0ne0AiNtGen4gMNsSetva4YOO-Dys3hSCLVBLTJ2pxc.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_aqua.svg","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/paypal-ui/fonts/PayPalSansSmall-Regular.woff2","request_type":"font"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/template/banner.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/secdev/sufei_data/3.3.5/index.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://az452423.vo.msecnd.net/ius-76ebdeea04cf3415fce2e5af20c935b7/29293_636592294208300877","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css","request_type":"css"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/6be72975/Areas/Home/Content/js/build/bundles/sharedScripts.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://d1z2jf7jlzjs58.cloudfront.net/p.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/29a5567ef4e201afc0084cf6bf0cf984.js?conditionId0=472867","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/asdf/async-1.0.1.js","request_type":"script"}
+{"origin":"http://www.google.co.id/","request_url":"https://adservice.google.co.id/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://googleads4.g.doubleclick.net/pcs/view?xai=AKAOjss1pWE2rg7uV-CzI6OuyHnMPtVGKpJG6RndB26qzBnmq0Jmn-9PbsjV04nzGEy5hO2gHSqKK3xMcm0hnB4wK_5E3K2RFkzCBlSWYMl56DmBw1wNFiNmvptgknDjG-RR&sig=Cg0ArKJSzMIAGyHHdV9qEAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=457803595&t=pageview&_s=1&dl=https%3A%2F%2Fwordpress.com%2F&ul=en-us&de=UTF-8&dt=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAEAB~&jid=718787279&gjid=2016562638&cid=1768394412.1523791839&tid=UA-10673494-4&_gid=1457613602.1523791839&_r=1&z=1395298182","request_type":"html"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/gen_204?s=webaft&atyp=csi&ei=CTjTWt_vBumQ0wLAv4jgBQ&rt=wsrt.2168,aft.417,prt.230","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdnssl.clicktale.net/www32/ptc/755cc4ab-c4bf-46d8-a608-d3c5d66fabac.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2","request_type":"font"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/518e5yqTyZL.js?AUIClients/RetailSearchAutocompleteAssets","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C41PsXsu4WrL.js,118Wk-h2B-L.js_.js?AUIClients/GWMWebAssets","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://pr-bh.ybp.yahoo.com/sync/rubicon/qkTgUU6BnkE3pDVp4qXxfcn5EUdSAgOZEtemQ7w0kco=?csrc=","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://e.visualdna.com/conversion?api_key=krux&id=sync&_kdpid=8f95f20d-4acf-43fc-9832-3f5174a166cc&partner_user_id=L6N7iig7&bust=1523791991133","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://usermatch.krxd.net/um/v2?partner=google","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://px.adhigh.net/p/cm/pubmatic?bounced=1","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://sync-tm.everesttech.net/upi/pid/b9pj45k4?redir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=100&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A100%7D&logFlag=uaction_1523791857874&t=1523791957876","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://cm.pos.baidu.com/gpixel?google_gid=CAESEDckVv_DsS8iM_jChhcsB94&google_cver=1","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://ml314.com/csync.ashx?fp=422b50dada7e115e6b51cf2a3c0fa7e3d32375dff8e89583263ab1e4d6afb255f4cb09cee1a4f8eb&person_id=5978151418385522803&eid=50082","request_type":"image"}
+{"origin":"http://www.alipay.com/","request_url":"https://log.mmstat.com/5.gif?url=https://kcart.alipay.com/web/1.do?","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3DXZ4D3PPDB36HTEGXD7ZH%26m%3D1%26sc%3Dadblk_no%26pc%3D11048%26at%3D11049%26t%3D1523791921593%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DXZ4D3PPDB36HTEGXD7ZH%26aftb%3D1:11049","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://top-fwz1.mail.ru/tracker?js=13;id=110605;u=https%3A//mail.ru/touch;st=1523791840769;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=8444bcd29777bf8d;ver=60;nt=0/0/1523791832347/////5292/2672/2672/2672/4214/3168/4215/5273/5410/5325/9210/9210/9210/28142/28142/;detect=0;lvid=1523791844609%3A1523791860494%3A4%3Ae5d8a31e801c4e17a79c5b7f63693070;opts=sec;_=0.5732585734339912;e=RT/load;et=1523791860490","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_nav_bottom.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/9cbUVdUGgINO5xuTvk_SxU2eiZPu1PtRFMi3JhSMvYO7AOQnPBVpALNJnb8P=w1024","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/dmsmty/44_44_/t0195091a0d8d62b8f1.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/fenghuang20171024-56.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://www.taobao.com/","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/2a218eb5-eb08-4ff4-8cfe-3a49c2f70706_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/9QLgh1emlFKYVEf6mm3_8w/009/339/459/320x240.4.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1dFxFPpXXXXXxaXXXq6xXFXXXv.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/home.logged-out/page-domain-only/img/website-scene-2x.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvS63z.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=600&y=229","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/amazonlaunchpad/de/Gateway/2018_02/iolandac_2018-02-05T15-59_0ebc52_1099615_de_launchpad_gw_quadcard_feb18_420x420_3._CB487250278_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/digital/video/placement/Gateway/launch/Baywatch/non-exclusive/Baywatch_DE_NonExclusive_XSite_GWSuperhero_Mobile_1242x450._SX1242_CB499100702_.jpg","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://api.branch.io/v1/open","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://unagi-eu.amazon.com/1/events/com.amazon.csm.nexusclient.prod","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/assets/github-d19623a69cc756b5a2cbda89154a69e9.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/front-index.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/external/zxcvbn.min-vflXrsFxo.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-viewer-ads/td-viewer-ads-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-modal_lrecs_mega/td-applet-viewer-templates-modal_lrecs_mega-min.js","request_type":"script"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/bannertext?bannerid=35106&zoneid=461&","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://sp.analytics.yahoo.com/sp.pl?a=10000&jsonp=YAHOO.ywa.I13N.handleJSONResponse&d=Sun%2C%2015%20Apr%202018%2011%3A31%3A06%20GMT&n=7d&b=Dropbox&.yp=10030786&f=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&enc=windows-1252&isIframe=1","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"http://www.google.es/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100282982&apid=beans_12416&impid=0e79d2fc52a66ff31_0_0&at=1&mkey=0e79d2fc52a66ff31_0_0&latcy=2388&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=731.578125&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DHwvF1ZPDXjYxrDJwjSgO1ssh0qP8wt3Pa%2F0pCpcLtqQjvUIE9%2FKHE0tsFs7zn%2FzWA6EGsJ8NitxZ03ZIWboAEmvGAh%2FftQgF1rIZDpomvP9qjzjLN2JKqHUJhlPhgCcedjLG9vqLkkPGyoPk3trFL%2F7A7g%2FymEovWE3mS4nLNJ048Y0lFw3V66yDUkSnh8T25reLIpW0D28dVABi3M8G2RwEPdWa8R4ppOqvyQMANUkO7mjKzIPtGEoitfiZq%2F03LhtKKLLtlpu7PnEglrT8GtcuOyuURtNTCS%2BVNH6%2FoAaocJ6VG0DjiqT8SEqWWpeXB%2BgyxIsYDms8tlJDQ9w6%2FM%2BdI7mfZseOsZYPRe9VoZVZeAxsVjUytbatjugZTW%2B5unxhN77%2FxyixZK3TuMpCi0ksweVdtdLkBYB6e2WwuSAe8Wcf0sDcfBvPNeXOCdjIYih%2FzAsZ7%2FOAN791M2aTPu2ADLMfFPVwYnaXNOBwlBS3EEjcBxj6Bd1Ahrr%2FhEGtHSnAdR93OdG%2FFEH9bGPWZsKgM6D%2BF%2FR7L9XLIHp23D10%2BEGjY3iTgkz8As4c4XQTr8KDuK5qlHlFsURHHCtz8canNpnSdyyg55pS1uECl1U%3D%09tt2%3D1523791940191%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=5836330902656&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791940527","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://platform.twitter.com/widgets/widget_iframe.73a792b0fbc7ab73a8e3b3db9c36a8ac.html?origin=http%3A%2F%2Fm.thepiratebay.org","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://www.tumblr.com/yahoo_cookie_receiver.html?SIG=112kkc248;x-cookie=SnxreGungfAbgNErnyOPBBXVR","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://odb.outbrain.com/utils/get?url=https%3A%2F%2Fwww.cnn.com&settings=true&recs=true&widgetJSId=TR_1&key=NANOWDGT01&idx=1&version=01002504&ref=&apv=false&sig=NpGpNWuG&format=html&rand=91538&lsd=0035a749-74b3-4e1b-af9c-23ecd9c9a6b8&t=MV9hODQ2ZjVkZDBjNWNjYzdiNGY1MjYxYTJjMjI1NzJiNF8w&winW=360&winH=512&adblck=false&secured=true","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.linkedin.com/lite/rum-track?csrfToken=ajax%3A2466944813834571155","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/webworker.js?hl=en&v=v1523554879111","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/complete/search?q&cp=0&client=mobile-gws-hp&xssi=t&gs_ri=mobile-gws-wiz-hp&hl=en&psi=EjjTWr-7F4Ws8APa7aPACQ.1523791893051","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://log.outbrain.com/loggerServices/widgetGlobalEvent?eT=0&tm=6105&pid=185&sid=185984&wId=117&wRV=01002504&rId=5f6173ac3591a32552db6ec019ed51a3&idx=1&pvId=a846f5dd0c5ccc7b4f5261a2c22572b4&org=0&pad=0&pVis=0&eIdx=&ab=0&wl=0","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://x.bidswitch.net/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel-us-east.rubiconproject.com/exchange/sync.php?p=a9us","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://stags.bluekai.com/site/26358?dt=0&r=1006365599&sig=553643676&bkca=KJpnEncN141ppXh1BNzguAlJnnnBvYAovnquN62vEDpmp2wnn3o/6z+nn5WFnDT+0A6LuzfxuX21LTdwnLN1DEPtQVkVBE/guYy30DL+9QGZ8juZji5Z9LVuLrBn/xoPMDpi7qpMx612Ux92I05i","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/mfp/view?type=3&t=MjAxOC0wNC0xNSAxOTozMDoyOAkxNDkuMjAuNjMuMTMJX18xNDkuMjAuNjMuMTNfMTUyMzc5MTgyMF8wLjE5MjM0ODAwCWh0dHA6Ly9zaW5hLmNuLwlQRFBTMDAwMDAwMDU3NzkzCTRkYjk4NjZhLTdlZDYtNGJjMS1iZDUxLTJiZGM0ZGJhOTM4NAk4MDE3XzY5MzIJMTI3NTUJYXV0b19sZXZlbDoxODAxMDB8dXNlcl9ncm91cDo5MDB8d2FwX29zOjcwMXx1c2VyX2FnZTo2MDB8dXNlcl9nZW5kZXI6NTAwfF92X3pvbmU6Nzc3MDAwLDc3NzI4MHxhdXRvX3ByaWNlOjE4MDIwMHxtb2JpbGVfYnJhbmQ6MTIwOXxuZXRfd2lmaToxMTAyfGNhcnJpZXI6MTgwNDAwfHBvczpQRFBTMDAwMDAwMDU3NzkzLFBEUFMwMDAwMDAwNDA1MTksQTI1RDI1OUIwOEU2LFBEUFMwMDAwMDAwNDk2MjksUERQUzAwMDAwMDA1NDY3MSxQRFBTMDAwMDAwMDU1NjIyLFBEUFMwMDAwMDAwNTQ2NzIsRTlENkFDNEYzNDhFfHZfem9uZTo3NzcwMDAsNzc3MjgwfG1vYmlsZV9icm93c2VyOjgwNXx2ZXJzaW9uOmRlZmF1bHQJCTc3NzAwMHw3NzcyODAJNTgyNzkxODI3MAlNQjE4MDMxMzE4CS0JODAxNwlXQVAJLQkyNwktCS0JLQktCS0JLQktCS0JLQktCXN0cmF0ZWd5X2xyX2N0cl9pZGVhX3VtYwkyCTkJaWRlYW51bToyfHJiR3JvdXA6MTYzNnxhZ2VudDpudWxsfG1vcmVJbXByZXNzOjB8cmJfYWQ6MCwwfG9zOmxpbnV4fGJyb3dzZXI6Y2hyb21lfHBsYXRmb3JtOmFuZHJvaWR8ZGV2aWNlOm90aGVyfGFkUGxhdEZvcm06Mwkw&userid=__149.20.63.13_1523791820_0.19234800&viewlog=false&hashCode=80223ba7ae02ea2a87fda4ca672ea215","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/css/2014/index/index.other.css","request_type":"css"}
+{"origin":"http://www.sohu.com/","request_url":"https://www.qchannel03.cn/1.gif?domain=m.sohu.com&account=sohunews&channel=&point=&platform=android&ts=1523791940564&dur=0","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a671c9100015ad3387a18b370d51763&pid=mm_113716014_12970037_52768238&cid=268282&mid=87911&oid=446&productType=1&qytInfoMTime=1523728959&e=7e%2Bh0CSAYgW0LVip4%2BMlAUIexOqiEPrXmn3JR%2BZ%2FoMMvoDeL64%2FZFi713c7jp2SZ&k=65&cb=999334766","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://pixel.quantserve.com/pixel;r=1481087034;labels=Fandom.Article.FANDOM;rf=0;a=p-8bG6eLqkH6Avk;url=http%3A%2F%2Fwww.wikia.com%2Ffandom;fpan=1;fpa=P0-1341828012-1523791983364;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1523791983319;tzo=420;ogl=locale.en_US%2Ctype.feed%2Ctitle.FANDOM%2Cdescription.The%20entertainment%20site%20where%20fans%20come%20first%252E%20Your%20daily%20source%20for%20all%20things%20T%2Curl.http%3A%2F%2Ffandom%252Ewikia%252Ecom%2Csite_name.FANDOM%2Cimage.https%3A%2F%2Fvignette%252Ewikia%252Enocookie%252Enet%2F48c4c991-2051-4ced-81ba-a3a69062cd19%2Fthumbna%2Cimage%3Awidth.1280%2Cimage%3Aheight.720","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://wordpress.com/home.logged-out/page-domain-only/img/placeholder.gif","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_ent-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/uedata/unsticky/358-6685975-3653550/NoPageType/ntpoffrw?at&v=0.200436.0&id=QVRKZSEBR7BT5RF15TNH&ctb=1&m=1&sc=QVRKZSEBR7BT5RF15TNH&pc=10847&at=10847&t=1523791976535&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=QVRKZSEBR7BT5RF15TNH&aftb=1","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=80119&dpuuid=3996c3b5-4652-42c0-8784-381f80a2c7f3","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.google.com/ads/user-lists/986255830/?value=0&guid=ON&script=0&cdct=2&is_vtc=1&random=2211456850","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/developers/jessfraz.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_espaniol.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/6GftHp2q8zrjTzGG0Xz0zQZYGRh0YuUPyxNwVQLiaLjZboXhWs_TOfTzvxI9DLc=w256","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://theta.sogoucdn.com/wap/images/sg_logo.png","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn-gl.imrworldwide.com/novms/html/ls.html","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4117000/4117073/220x165/8.jpg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/heroes/product-red/hero_small_2x.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1eMnwXHGYBuNjy0Foq6AiBFXae.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1SXsJheSSBuNjy0Flq6zBpVXaw.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33047974","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/94/31/63/943163c665404a071624f66a6a7a0f68/943163c665404a071624f66a6a7a0f68.22.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0414/dm_180414_NCF_CLEMSON_HIGGINS_TD/dm_180414_NCF_CLEMSON_HIGGINS_TD.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180102061632-carrie-underwood-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/00e/056/20a/big_lq/874629039b832246b9fbf2af09f7cfbb.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71OIwcnLvOL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/heroes/simple-codelines.svg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/mobi/2017/image/image-placeholder-logo.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.wikia-services.com/__track/special/adengadinfo?a=&ad_status=collapse&beacon=NyiV-67qg0&browser=Android%20Chrome%2058&c=1452001&cb=1523791986622&client_ip=208.70.31.93&country=US&dev=false&dev_cat=mobile&event_ts=1523791986&f=Home&kv_abi=&kv_ah=&kv_esrb=teen&kv_lang=en&kv_pos=TOP_BOXAD&kv_ref=&kv_rv=&kv_s0=fandom&kv_s0v=home&kv_s1=_fandom&kv_s2=home&kv_skin=fandom_mobile&kv_top=&kv_wsi=dmh1&labrador=&lc=en&page_width=360&pg_type=home&pv=1&pv_number=1&pv_number_global=1&pv_unique_id=af377f25-1ffc-4914-9834-c80ec4217531&r=direct&r_type=direct&s=fandom_mobile&session=Q4ulawcgCl&session_id=5d21d0a7-b14a-4f7f-ac4b-8ba9846d26f7&site=web&t=event&time_bucket=4&timestamp=1523791986622&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&viewport_height=512","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://cdnssl.clicktale.net/www/monitor-latest.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-legacy-ab.min-vflFzdo4B.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/mit/td/td-applet-breakingnews-atomic-0.0.57/r-min.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://t.co/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvzbs&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/package/superframe_5b7bdae.js","request_type":"script"}
+{"origin":"http://www.google.com.br/","request_url":"https://adservice.google.com.br/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V3RNMzR3QUFDR01mUGZ5UQ&url=/1/gr%3furl=https%253A%252F%252Fdsum-sec.casalemedia.com%252Frum%253Fcm_dsp_id%253D71%2526external_user_id%253D__EFGSURFER__.__EFGCK__","request_type":"html"}
+{"origin":"http://www.savefrom.net/","request_url":"https://staticxx.facebook.com/connect/xd_arbiter/r/FdM1l_dpErI.js?version=42","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://log.sina.cn/fp/","request_type":"text"}
+{"origin":"http://www.diply.com/","request_url":"https://goviral-engine-bus.servicebus.windows.net/views-in-hub/messages/?timeout=60","request_type":"xml"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/yui/yui-min.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://connect.facebook.net/en_US/fbevents.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://bea4.v.fwmrm.net/ad/u?mode=echo&cr=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dfreewheel%26partner_uid%3D%23%7Buser.id%7D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://x.bidswitch.net/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://dpm.demdex.net/ibs:dpid=139200&dpuuid=41EqZTuPQ8CtigNwg-5W9A&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=d5f79ddd-8bf8-4068-872b-68d142980aef&ttd_puid=35117910-40a1-11e8-a553-0242acc1cc07%2Chttps%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D35117910-40a1-11e8-a553-0242acc1cc07","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.bing.com/c.gif?uid=86070857378125119120981354726841823876&Red3=MSAdobe_pd","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://c.bing.com/c.gif?udc=true&rid=e86f55f780704d568af4af783e3cb6c4&rnd=636593886315667499&rf=&tp=https%253A%252F%252Fwww.msn.com%252F&di=340&lng=en-us&cv.product=prime_mobile&pn=startpage&activityId=e86f55f780704d568af4af783e3cb6c4&d.dgk=tmx.mobile.webkit.android&d.imd=1&st.dpt=&st.sdpt=&subcvs=homepage&pg.n=startpage&ctsa=mr&CtsSyncId=6FFC77522C924D75BC8F8250FD085A47&RedC=c.msn.com&MXFR=39041E2B94ED6EF00CB315F995BE6F73","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/sc/h/8z5xqy266agx6fxeb5g3gpxy3,76dd0jdknaesubfisiymvqoa2","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=spotx.com&id=818869a1-40a0-11e8-9c58-1fdd5b850e01","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=94&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A94%7D&logFlag=uaction_1523791857874&t=1523791951876","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=D34DC539-63A7-4F27-8DFD-50E0EE1E218A&ex=pubmatic.com","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://us-u.openx.net/w/1.0/sd?id=537148856&val=WtM4BQAAAGWhsjF0","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://securemetrics.apple.com/b/ss/appleglobal,applehome,applestoreww,applestoreus/1/JS-2.7.0/s14726981874948?AQB=1&pccr=true&vidn=2D699C0A852E25DF-40000CBF6063700D&&ndh=1&pf=1&t=15%2F3%2F2018%204%3A31%3A31%200%20420&fid=3E8E675443B3026F-0CEFB8E58966EE51&ce=UTF-8&pageName=apple%20-%20index%2Ftab%20%28us%29&g=https%3A%2F%2Fwww.apple.com%2F&cc=USD&ch=www.us.homepage&server=new%20approach%20ac-analytics&events=event220%3D2.997%2Cevent221%3D600%2Cevent222%3D0.000%2Cevent223%3D1.660%2Cevent224%3D0.353%2Cevent225%3D0.010%2Cevent226%3D3.240%2Cevent227%3D0.010%2Cevent228%3D2.194%2Cevent229%3D5.444%2Cevent230%3D0.142%2Cevent231%3D8.599%2Cevent232&h1=www.us.homepage&c2=g%40%20google%20swiftshader&v3=aos%3A%20us&c4=D%3Dg&v4=D%3DpageName&c5=linux%20x86_64%202x&c9=android%206.0.1&v14=en-us&c19=aos%3A%20us%3A%20apple%20-%20index%2Ftab%20%28us%29&c20=aos%3A%20us&c25=direct%20entry&c48=1&c49=D%3Ds_vi&v54=https%3A%2F%2Fwww.apple.com%2F&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/google-play-games-android.png:l","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_hand_2x.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/icons/icon_caps_lock@2x-vflz_EymR.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://static-alias-1.360buyimg.com/jzt/tpl/sspPicH5.html?ad_ids=3272:5&adflag=0&clkmn=&expose=","request_type":"html"}
+{"origin":"http://www.taobao.com/","request_url":"http://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://fonts.gstatic.com/s/rubik/v7/iJWHBXyIfDnIV7FCimmd8WD07oB-.woff2","request_type":"font"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$2048/ic/3e32adef/2889f0f1.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://img1.360buyimg.com/da/jfs/t17359/232/1623763178/194540/5a28a9a4/5ad0a9f5N913d48df.jpg!cr_1125x549_0_72","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/f5/b7/b2/f5b7b2eee940ae986b3d52cb2c3315e2/f5b7b2eee940ae986b3d52cb2c3315e2.15.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/product/paper/paper_ui_desktop@2x-vflj8awd7.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180324141803-14-march-for-our-lives-unfurled-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://643108e7617ef.cdn.sohucs.com/1c1a43c7b64045bf8ef2f3607604c6c6.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTk1MTg1NjUyNV5BMl5BanBnXkFtZTgwNzYwNTkxMDI@._CR1134,392,943,943_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1Le05bYGYBuNjy0Foq6AiBFXaz.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51g4qr8fBNL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/9e8c0ce8-1613-472a-a0a0-7b4c30b93111/scale-to-height-down/82","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/bg/YRKqPoIt_ONlxH2tUGnouQ_G4hFZfGHYM-YHumdPwHE.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://uranus.jd.com/log/m?std=MO-J2011-1","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://hm.baidu.com/h.js?969516094b342230ceaf065c844d82f3","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/custom-event/4.0.3/index.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/dipbid/delta.js?ver=4/13/2018","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/411MtgykU8L.css?AUIClients/GWMWebAssets","request_type":"css"}
+{"origin":"http://www.diply.com/","request_url":"https://secure.quantserve.com/quant.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ads/advertising/ads._TTH_.js?cachebust=37813631","request_type":"script"}
+{"origin":"http://www.alipay.com/","request_url":"https://gw.alipayobjects.com/os/rmsportal/WpGrtMXlamAjMGBnDmvF.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=yieldmo_dbm&google_cm&pn_id=c","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google.com/recaptcha/api2/anchor?k=6LeTvAoUAAAAADj3Cr1Onbp4OIH1gzywMUJaefT0&co=aHR0cDovL2NvY2NvYy5jb206ODA.&hl=vi&v=v1523554879111&size=normal&cb=5t7h0f7cm4vp","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791948263&yhlClientVer=3.30.2&yhlRnd=rcXZYZuM0zKpnrrVjg0qds6f&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted8.svg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.txxx.com/","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://traffic.trafficposse.com/in/tpb-dialog-js.php","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5api.m.taobao.com/h5/mtop.taobao.wireless.homepage.ac.loadpagecontent/5.0/?jsv=2.4.8&appKey=12574478&t=1523791943218&sign=10befc1214ea6cc910bed92d4fc61bb6&api=mtop.taobao.wireless.homepage.ac.loadPageContent&v=5.0&H5Request=true&type=jsonp&dataType=jsonp&callback=mtopjsonp1&data=%7B%22platform%22%3A%22h5%22%2C%22acookie%22%3A%22%22%2C%22userInfoFrom%22%3A%22cache%22%2C%22isPosition%22%3Afalse%7D","request_type":"script"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://connect.facebook.net/signals/config/823166884443641?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDoyNy41NDIJNjkzZjUwNGYtZTFiMi00MTc5LTg2NWMtMzg2MWIwMmRiNDdlCTMyNTM5NDAJMzExOTM2Nwk2MzI2NzYyNzA2X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1NzY4MwkzNTM4NzQ4CXh4bAkxCS0JV0FQCS0JMQk2MGIxMzYwOWVkNjI4NjNjMDE0YzhiNDM4MWVlNTY4ZglkZWU0MDI0ZS1hOWE5LTM0ODUtODhmOC00MDgxYTVkY2VmODMJOTU5MzYJMC4wMDQ2MzAyOTM3CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjAyMTI6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwMDowLjB8dXNlcl9nZW5kZXI6NTAxOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTMJMTA1MDAwCTIwMDAw&userid=__149.20.63.13_1523791820_0.19234800&auth=ab48cc1bf32693c3&p=3uQCTqmpNIWI%2BECBpdzvg40Ov91U84Nht3m1IQ%3D%3D","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=601&dpuuid=76509812831766&random=1523791845","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/spotify-logo.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/84/B16060.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t15145/137/2502885754/3106/de5e0b14/5aa10cd2N46f18ce6.png","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/gno/sprites/new-nav-sm-smile-sprite-global-1x_blueheaven._CB487546343_.png","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/NTgxWDE2MDA=/z/NSAAAOSwEBpaxVac/$_57.JPG","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/co_create/mobile/dropbox_digital_mobile_02@2x-vflHbuTFv.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/f1/77/bf/f177bf1afdee293f40a9937b6aa55cf7/f177bf1afdee293f40a9937b6aa55cf7.9.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51WWPA21koL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51Ua5RfyCqL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/assets/fave/svg/go-live.svg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/html5-canvas.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://dc.ads.linkedin.com/collect/?pid=6883&s=1&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&cookiesTest=true&opid=195308&fmt=js&time=1523791843084","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://s.bdstatic.com/common/openjs/openBox.js?_v=2018-04-15-4","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9ap&google_cm=&ex=doubleclick.net&google_tc=","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/gen_204?s=webaft&atyp=csi&ei=CzjTWs7PD4jU0gLzgKmgDA&rt=wsrt.2088,aft.384,prt.238","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/hpmob?IG=2E674091B80D41D497ED8B2E88AE58C9&IID=SERP.5000","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"http://s2.symcb.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBS56bKHAoUD%2BOyl%2B0LhPg9JxyQm4gQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMCEH7hSm9v7%2FLTfz%2BtZU062rSiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.uptodown.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_qs_click_protection.js","request_type":"script"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/youtubei/v1/log_event?alt=json&key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/autocomplete-list/autocomplete-list-min.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://connect.facebook.net/en_US/fbevents.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://xid.i-mobile.co.jp/RestoreXidToMediaStorage.html","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=2M2U96GHS9OFQD_miznHhQ&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://ad.afy11.net/ad?mode=10&sspid=3585&coxcheck=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=aolvideo.com&id=af1ba93e51cb27e68d964f97c70533bc93becf96","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/817714641/?label=oPQ0CPiMhoABENGr9YUD&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://wgo.mmstat.com/sb.sbp.action?cache=611fdc1&gmkey=CLK&gokey=platform%3DAndroid%26smbSid%3DRiZaE%252BYPjyICAZUUPw3CLc3s_1523791946369%26apuri%3Dsb_redirect_auto%26source%3Dsb%26bizKey%3Dtaobao%26linkKey%3Dtaobao%26sceneType%3Ddefault%26page%3DmainIndex%26wkt%3DportListen%26rbbt%3Dbc.mainIndex.6.0.0%26appkey%3D24585258%26logtype%3D2&cna=RiZaE%2BYPjyICAZUUPw3CLc3s&spm-cnt=a215s.7406091.0.0&logtype=2","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://secure-dcr.imrworldwide.com/cgi-bin/gn?prd=session&c9=devid,&c13=asid,P07264C85-15CD-4A80-8E56-B5BFA6D93296&sessionId=lmjy9NsjglodU0uYNqHzQ7WSc1o591523792035&C16=sdkv,bj.6.0.0&retry=0","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=782&dpuuid=WtM34wAACGMfPfyQ","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/google-maps-android.png:l","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/newtab/img/fetch_ing_8_0.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_style_new.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/btns/sign_up.png?1372079637","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://m.pixnet.net/","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/paper-atlasgrotesk/AtlasGrotesk-Regular-Web-vflk7bxjs.woff2","request_type":"font"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Fortnite-429x572.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/default/transform/266/w640h426/20180415/z6Yj-fytnfyp5354883.jpg/w200h134f1t10l50q90c55.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/0d/9d/1a/0d9d1a4f35ada5e5a82890303948b0e4/0d9d1a4f35ada5e5a82890303948b0e4.4.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0406/dm_180406_NFL_We_the_fans_Cowboys/dm_180406_NFL_We_the_fans_Cowboys.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmpic.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/10/4e/d8/104ed895386f5ac41ad3232f649ea8f5/104ed895386f5ac41ad3232f649ea8f5.2.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTA0NzczNTAzNDdeQTJeQWpwZ15BbWU4MDk0NDc1MjUz._CR15,566,1356,1356_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/Q9MAAOSw-wJaRVyo/s-l500.webp","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/us/ffe/siteui/common/icons/nficon2016.ico","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflUiilPi/core.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-sidebar-0.1.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yS/l/0,cross/eBFqYkgdeXM.css","request_type":"css"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/mrt.gif?{%22_pk%22:%22187524%22,%22_src%22:%22web%22,%22_rk%22:%221523791853912_0.8405727545877539%22,%22_v%22:%221.0%22,%22_cp%22:{%22os%22:%22android%22,%22uid%22:%22%22,%22accesstype%22:%22%22,%22device_id%22:%22__149.20.63.13_1523791820_0.19234800%22},%22_ep%22:[{%22attribute%22:{%22attr%22:%221523791%22,%22cE%22:%22820126%22,%22cS%22:%22818675%22,%22dC%22:%22853790%22,%22dCLE%22:%22827428%22,%22dCLS%22:%22827428%22,%22dI%22:%22827428%22,%22dL%22:%22820753%22,%22dLE%22:%22818675%22,%22dLS%22:%22818371%22,%22fS%22:%22820735%22,%22lEE%22:%22853826%22,%22lES%22:%22853790%22,%22rE%22:%220%22,%22rS%22:%220%22,%22nS%22:%22817105%22,%22reS%22:%22820126%22,%22rsS%22:%22820725%22,%22rsE%22:%22821182%22,%22sCS%22:%22819143%22,%22uEE%22:%220%22,%22uES%22:%220%22,%22ext%22:{%22fs%22:%22820763%22,%22frS%22:%22820763%22,%22fiS%22:%22823565%22,%22fw%22:%22823938%22,%22fiE%22:%22827568%22},%22uid%22:%22;__149.20.63.13_1523791820_0.19234800%22},%22channel%22:%22%22,%22ek%22:%22_load%22,%22ref%22:%22%22,%22et%22:%22custom%22,%22src%22:%22home%22,%22method%22:%22%22,%22timestamp%22:1523791853914}]}","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://z.moatads.com/adtechmsftstaging299008436443/moatad.js","request_type":"script"}
+{"origin":"http://www.google.com.pk/","request_url":"https://adservice.google.com.pk/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm&ex=doubleclick.net&","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938151_6049689264997&itemspaceid=12419&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938151&cnid=228307883,228307496,228303762,228306576,228293793,228338005","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://gcs.extremereach.io/gcs?google_gid=CAESEE9GJFsnTcL2quqq8NA2Z98&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"text"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdn.optimizely.com/public/3698060313/s/home.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mscom.demdex.net/event?_ts=1523791840610","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://tmm.m.taobao.com/member/user_login_info.mobile?callback=jsonp_22393749","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.adsafeprotected.com/jload?anId=928108&campId=1x2&pubId=38386957&chanId=71171677&placementId=4640152498&pubCreative=138230533060&pubOrder=237199237&cb=1636808466&custom=bnr_btf_01&custom2=&custom3=&adsafe_par&impId=","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://sb.scorecardresearch.com/b2?c1=2&c2=17462746&ns__t=1523791960475&ns_c=UTF-8&c8=Diply&c7=http%3A%2F%2Fdiply.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://i.liadm.com/s/32441?bidder_id=88068&bidder_uuid=39041E2B94ED6EF00CB315F995BE6F73","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212284268","request_type":"other"}
+{"origin":"http://www.twitch.tv/","request_url":"https://video-edge-79f98b.sjc01.hls.ttvnw.net/v1/segment/CrjMzQCf9iogts520o-nIvojRGdI1meYSvwcjr0VnkQ6CrVFxW7lEKnvYLrQ2BGTfJ69YDpyMzw9686uDe0rX51yRxrT3TUe2LnDRCVASvKVbXcaHR0S70LM7PQW7gkGei3cmVUiXYcjforH8U13uB4WHCiNs7LbOQnChHV6k5Qw25AM0ZJFUHoW6LlBTJlcG1HqPbWgxHmV5EWVcyPvRqLmbKa_n4ZJHMl7NvlJ5KpDSV5F3rfryEe-CtMDjTnii3Jp6dYfoKzJZGz6T3ln7noce8m1Hu0rZuIdVnHPk7sS64ETWkiEVn4LtlCOtFxFwfJHiuRt3uBWrKsE89GdSSkM1cSfH5nyKi2dVadbEL1-GxS2d1TweAD1OzsAIop000JGDFJQA14L54nxRCK1UrtvHpQt2JIQBofHxADk-MRkiMo5jYksdSjZn1rSiJwLrjykYK6yy-tn-28JnoW_IeJ0tpKVijxoh53YL_V0z7ExWsMo19qxO4p8xjDe63cs6nj7hXy3r4d24hXh2x8oEmRgOpbU2Q.ts","request_type":"other"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/ac-films/5.2.0/styles/modal.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/components/login_form-vflGEg_N8.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/components/rebrand_media-vflU5svEh.css","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/icon-close-banner.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/monkey61208/albumset/6190356/zoomcrop/75x75.jpg?v=1523785526","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/LvXV_ldpiygyiAI5R-Nqw8_zdNvmvLEH9jGIie7dycK-TtJO_SdUgmgxAdGtdjM=w128","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p9.qhmsg.com/t01dc430e8c4fbc2aee.png","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/favicon/64x64.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1Y_JslqmWBuNjy1Xaq6xCbXXac.jpg_q70.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2702969531,2047398953&fm=173&app=25&f=JPEG?w=218&h=146&s=6AA0DC4D420827720C11953503001043","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmrbapp_index_logo.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/01c/22e/151/big_lq/d28200b3244fa82dfd4ec7d196ad2dc6.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTQ3ODE2NTMxMV5BMl5BanBnXkFtZTgwOTIzOTQzMjE@._V1_SY345_CR23,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/gays.svg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://m.so.com/index.php?c=home&a=data&fmt=json&types=Weather","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-login-pages.min-vfltz8e5U.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-share_btns/td-applet-viewer-templates-share_btns-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/mit/td/aperollup-min-409bd34a_smartphone.js","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://media.licdn.com/cdo/rum/id?1523791896695","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-58bd3c7a64746d400000ab25.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=%2Fphoto%2F2018%2F0414%2Fr356455_1296x729_16%2D9.jpg&w=320&h=180&scale=crop&cquality=40&location=center","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/aw/mobile-ads/ajax","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100262188&apid=beans_13820&impid=027a0399477a97d05_0_0&at=1&mkey=027a0399477a97d05_0_0&latcy=4810&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=7128.515625&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DR3srqV9h5f1%2BiY8jhbNlkmPUxw0DlToEZnrbgaeUW%2FQnqbKAOHwI%2FE6enwCK4be91Mf7glU2kzfX7Jg69Nqh1pivFZh5ZgbP9dwOqEywuQJcrRft0EiajwTKQMx58ipP4aneA5jJXLcr3bNJwOLiXlxIbJtSRiHcFBKQ9MKBDsXGnZ6btCvscQhh8Gu%2BVGd%2FSEQH3cwt3B%2Ft%2FerEAXtJkBTvTVDKCCIqgwOqgHYsvbPopneWkcPNXISMcreVXns1e1llq8iDI3JCkeMYPPxMnCpKW%2B4%2F%2BrfRGnJJvTpQsEdTJnJX1rvav7Dg0RRWTCkdwE1A6L%2B0SspbVmcAszmXnY8w9Bv2NvHeNEfjg9NuS7nqt%2FtUT238DeRXwGxxxAN5mw3LIkT4JrEq0Vkc1%2BCgZZkonAYmWTIxWkGBtvbV5pZqyTppx%2FJmHfe4Ds%2BFyyCxInNAiOHmzXaatvpnnk3fAchfXptXV5BzJO0wa1hfKNhiDftsWi9uxJN15MRMz%2BOzQ6PWAeiHZB07ffjdf4vtgQj%2FLLn3eOfde3W3jX3%2FbA7z2DsPPIG%2FM0Vm92DeVM2mWeyefShRT56smFCA0JM%2BZWvBDqwIqEbJiX%2Fnub6Mo%2FM%3D%09tt2%3D1523791942788%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=0030028504353&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791943084","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://platform.twitter.com/jot.html","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/api/OxBannerService/logImpression?bannerid=52375&zoneid=613&_=1523791960326","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://idsync.rlcdn.com/379708.gif?partner_uid=L6N62llA&redirect=1","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/jsonp-url/jsonp-url-min.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2","request_type":"font"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/client/prod/app/context/loginandregister/index.build.js?_v=55bc477fb9237b7e235aee05aac0b172","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/bundles/fave/2.1.3/app","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212284268","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212284268","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://secure-us.imrworldwide.com/cgi-bin/m?ci=us-204044h&cg=0&cc=1&si=https%3A//www.cnn.com/&rp=&ts=compact&rnd=1523791864270","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D7941%26nid%3D2243%26put%3D%24%7BUSER_ID%7D%26expires%3D90","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/login_or_register-vfl9esD0O.css","request_type":"css"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rs.gwallet.com/r1/ucm?id=86070857378125119120981354726841823876&r1s=8y8mie9jehqw54bpgpghffsh84cb9r39ktr6uqzxk33zgx7t4zqy","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_9%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D29962%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://wgo.mmstat.com/sb.sbp.action?cache=288bc06&gmkey=EXP&gokey=platform%3DAndroid%26smbSid%3DRiZaE%252BYPjyICAZUUPw3CLc3s_1523791946369%26apuri%3Dsb_load%26source%3Dsb%26bizKey%3Dtaobao%26rbbt%3Dundefined%26appkey%3D24585258%26logtype%3D2&cna=RiZaE%2BYPjyICAZUUPw3CLc3s&spm-cnt=a215s.7406091.0.0&logtype=2","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://v.admaster.com.cn/i/a105788,b2430618,c211,i0,m202,8a2,8b2,j4db9866a-7ed6-4bc1-bd51-2bdc4dba9384,h","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/54/87A7DF.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/code_gmrbwx_s.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/images/20170601header_logo.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/lpnI6G9VekY80fLOIqhM09I-jDZJOPg32OHvPq3aLnmSAoKf_5Dt6chjBPvGug=w768","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/icons/financial.png","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/gno/sprites/sky_webnav_V1_sprite_1x._CB515272527_.png","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://falcon.pixanalytics.com/ad/embed/1812","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1nu_ISXXXXXbRaXXXq6xXFXXXi.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/36/9b/a1/369ba1442b205b28795fc3e78d27f1e3/369ba1442b205b28795fc3e78d27f1e3.30.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/26/62/55/2662557c3a784423072bb2bdeace6716/2662557c3a784423072bb2bdeace6716.5.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/583000/583182/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/common/u/images/logos/favicons/v1/favicon.ico","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://mp.sohu.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/pingjs/ext2020/xw-next/_next/77436cd9027f4c6c941ebc8108fd95f0/app.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-lightbox/td-applet-viewer-templates-lightbox-min.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1/t.js?ver=%272.1%27&name=%27Ms.Webi.PageView%27&time=%272018-04-15T11%3A30%3A37.583Z%27&os=%27Android%27&appId=%27JS%3Awww.office.com-unauth%27&*baseType=%27Ms.Content.PageView%27&-ver=%271.0%27&-impressionGuid=%272fa516e0-666d-493d-82d6-5fbe07b46915%27&-pageName=%27UnauthOhp%27&-uri=%27https%3A%2F%2Fwww.office.com%2F%27&-pageTags=%27%7B%22metaTags%22%3A%7B%22ver%22%3A%225%22%2C%22ms.lang%22%3A%22en%22%2C%22ms.loc%22%3A%22US%22%2C%22ms.ocpub.assetid%22%3A%22UnauthOhp%22%2C%22ms.env%22%3A%22prod%22%2C%22ms.sitever%22%3A%225%22%2C%22ms.flightid%22%3A%22sharepoint%7Crecentnewbutton%22%7D%7D%27&-behavior=0&-resHeight=512&-resWidth=360&-market=%27en-US%27&*cookieEnabled=true&*flashInstalled=false&*isJs=true&*title=%27Office%20365%20Login%20%7C%20Microsoft%20Office%27&*isLoggedIn=false&ext-javascript-ver=%271.1%27&ext-javascript-libVer=%274.1.0%27&ext-javascript-domain=%27www.office.com%27&ext-user-localId=%27t%3A049F61EEB6C66C9F1DAE6A3CB7996D9E%27","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/secdev/sufei_data/3.3.5/index.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/lib/mustache.min.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51chvDI28JL._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/mbox-contents-f3808f72f280c66c15bd81363d6f55f0659a684d.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/ads/advertising/ads._TTH_.js?cachebust=95130154","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://bttrack.com/dmp/adobe/user?dd_uuid=86070857378125119120981354726841823876","request_type":"html"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://gum.criteo.com/sync?r=2&c=160&j=_ccb","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/js/csdn_feed_m.min.js?1521697078","request_type":"script"}
+{"origin":"http://www.so.com/","request_url":"https://s.ssl.qhres.com/callback/a2dfa3a44932bdaf/_a2dfa3a44932bdaf/float-search.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/51LGid1qdxL._RC%7C01BL18zkkEL.js,31a72IenKyL.js_.js?AUIClients/NavMobileMetaAsset","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://sync.ipredictive.com/d/sync/cookie/generic?https://aax-eu.amazon-adsystem.com/s/ecm3?id=${ADELPHIC_CUID}&ex=adelphic","request_type":"other"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/client/prod/app/context/loginandregister/index.build.css?_v=93ab8ea6fcd14c5d1d4bd3b35dc897a8","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=46&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A46%7D&logFlag=uaction_1523791857874&t=1523791903876","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/images/feedLoading.gif","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://cat.sv.us.criteo.com/delivery/lg.php?cppv=1&cpp=BegYU3xodXBTYTRHWmlQZkoxeGl2SlEyVWNMRkVORHordm8vdnE3KzlBRjlONHFVM3l5M2ZBcFVRZDFHOWJnUVUycC9JaFpLdys3R05aSjE4cWJqa25memNrMUZFQldXYk11eTM2V2FOdGhHMWxPL2l1QStKdk9YTXhBRUdnajRNamk0S09NRlp5NmpBNFNLRWVNQXFBVGhzc3NqWlpsREM0Mm5rb3h6NFlBaXJYR2QxZW5JOUYxZGdpNWFSYmJ6QjJHeGdrdFBxdXlkRURiZWd2aVRBMnpHMXA4TXI2WktGSS9ITmlWZUhRcjE3TWduRXNjUDNSM2ZKN0NtdC9JV1RuQzd6fA%3D%3D","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=3&redir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTM2MiZ0bD00MzIwMA%3D%3D%26piggybackCookie%3Duid%3A%5BMM_UUID%5D","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_8%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D29741%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_sports-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_finance-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=ZGVlNDAyNGUtYTlhOS0zNDg1LTg4ZjgtNDA4MWE1ZGNlZjgzCTQ1CVBEUFMwMDAwMDAwNTc3NzkJNTAJMzUwMDA3MQkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/officesuite-pro-7-android.png:l","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/bongacams_logo3_header.png","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/gno/sprites/sky_webnav_V1_sprite_1x._CB489388130_.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/sports80.png","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://cdn.krxd.net/partnerjs/xdi/proxy.3d2100fd7107262ecb55ce6847f01fa5.html","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://articleimage.nicoblomaga.jp/thumb/258/2018/0/1/47101.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/default/transform/266/w640h426/20180415/gEBp-fzcyxmu9388999.jpg/w200h134f1t10l50q90c55.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/c03fd5535e161c3d066806.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-hqAculmZ2BM/AAAAAAAAAAI/AAAAAAAAAAA/ifJCfKFSja8/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/00b/148/398/big_lq/c5a191c1fb329a65c231f636bdd2d08a.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/016/068/3bd/big_lq/dd27be48631f036d8dee88c7b91b51cd.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/f4/b3/9a/f4b39a6b1c98bb053b5fc4bafef4234e/f4b39a6b1c98bb053b5fc4bafef4234e.6.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1oaeMhx9YBuNjy0Ffq6xIsVXa1.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/CcmgGFvr9CuN2-AhgRoxBdJUCT0R8kgEHLMope_XE-s.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/ojgAAOSwLfNaz2yl/s-l225.webp","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17652/0/0/313/2087901/0","request_type":"text"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/logo_catalog/glyph_m1-vflCrXgzt.svg","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/mit/td/td-applet-stream-atomic-2.0.1605/r-min.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-locale-en_US-mobile-4e193dda1251a94e11e1.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nba.png&w=100&h=100&transparent=true","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/613f8nmqOVL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,11B0Us3dmsL.css,21pknbpyIxL.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,31B945bG3dL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21s7MLn4blL.css,11X2-nh0PYL.css,01h2e2BEitL.css,114wDplwccL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31VU7Pt5U6L.css,01b7OI3r44L.css,11mmd1QliNL.css,01cbS3UK11L.css,21pKFuuDucL.css,01EjbsDjo-L.css_.css?AUIClients/AmazonUI","request_type":"css"}
+{"origin":"http://www.csdn.net/","request_url":"https://goutong.baidu.com/site/279/6bcd52f51e9b3dce32bec4a3997715ac/b.js?siteId=6583558","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://4968236.fls.doubleclick.net/activityi;src=4968236;type=naanz-nm;cat=dcmna0;u1=US;ord=8829946326844.074","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/gen_204?atyp=csi&ei=CzjTWs7PD4jU0gLzgKmgDA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.384,dcl.355,iml.384,ol.2640,prt.238,xjs.1595,xjsee.1591,xjses.1349,xjsls.243,wsrt.2088,cst.666,dnst.0,rqst.759,rspt.386,sslt.364,rqstt.1621,unt.2007,cstt.954,dit.2443&zx=1523791886225","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938132_5610448259130&itemspaceid=15690&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938132&cnid=228336498,228313454,228331114","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://m.imdb.com/tr/","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/pagead/osd.js","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/js/26347c5c/googleSignIn.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"http://www.txxx.com/","request_type":"other"}
+{"origin":"http://www.tumblr.com/","request_url":"https://deazs14tb5j7o.cloudfront.net/img/29/iuni3.html?rnd=-1-1-13960-0-0-29-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"html"}
+{"origin":"http://www.weibo.com/","request_url":"https://passport.weibo.cn/css/weibo/signin/login.css?id=201406091907","request_type":"css"}
+{"origin":"http://www.microsoft.com/","request_url":"https://us-u.openx.net/w/1.0/sd?cc=1&id=537148856&val=WtM34wAACGMfPfyQ","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:146-2652873-2143838:6983MGHS2ZBMHXB1G0WS$uedata=s:%2Fuedata%3Fat%26v%3D0.200481.0%26id%3D6983MGHS2ZBMHXB1G0WS%26m%3D1%26sc%3Dadblk_no%26pc%3D18749%26at%3D18749%26t%3D1523791944436%26csmtags%3Dadblk_no%26tid%3D6983MGHS2ZBMHXB1G0WS%26aftb%3D1:18750","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/images/mobile/transparent.gif","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-10673494-4&cid=1768394412.1523791839&jid=718787279&_v=j66&z=1395298182","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=57282&dpuuid=5068399D4D7720D882478FB00B577098","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/snaptube-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/snapchat-android.png:l","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/apple-touch-icon-144x144.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/a0905535666/albumset/7400771/zoomcrop/75x75.jpg?v=1523695925","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmrb_wb_logo.png","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://d1eoo1tco6rr5e.cloudfront.net/l8hfnf9/4gktlyq/iframe","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://img.cdn.nimg.jp/s/niconews/articles/images/3435146/be4ef19d3cdd85a88df82d85ee64124f4d2d1e0ce3de6e12fd3f0c7f4c552b8b610878c6bc8a509eba0e81ecc990103b62acd7d7944089ec431284adef795914/110x110s_FFFFFFFF?key=f5bcc7ec072d576154314333b78584d7a4fe5a00684641bce65b2d89e5f5fc34","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://a.thumbs.redditmedia.com/pSWgCeC8A4qPI5aR5TdpZDqhQ5YZoXkk8KtY0RGFR10.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81hPQdwaSKL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51oHUvYzbsL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/71mi0QkRETL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/91V89Qmb5YL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t0174f09d4d782500c5.webp?size=550x351","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/1dd40158-93af-49aa-8715-7fedf05d3f80/scale-to-width-down/100","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google-analytics.com/plugins/ua/linkid.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://mtm.nicovideo.jp/api/v1/pickup_articles/3","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-medium.woff2","request_type":"font"}
+{"origin":"http://www.youth.cn/","request_url":"http://www.youth.cn/images/jquery-index-1.9.1.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/localeswitcher/2/en_US/scripts/localeswitcher.built.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/plugin/baiduappButton_83b553a.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a2.espncdn.com/combiner/i?img=/photo/2018/0413/r355949_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&glade_req=1&glv=26&dt=1523791849451&output=html&iu=%2F205338224%2FMail.ru_mobile_320x50&sz=320x50&sfv=1-0-10&correlator=853336767280731&adk=3471309403&biw=-12245933&bih=-12245933&adx=0&ady=0&oid=3&u_sd=3&ifi=1&click=%25%25CLICK_URL_UNESC%25%25&nhd=1&url=https%3A%2F%2Fmail.ru&top=mail.ru&loc=https%3A%2F%2Fad.mail.ru%2Fadi%2F100590%3Frnd%3D107581893","request_type":"html"}
+{"origin":"http://www.netflix.com/","request_url":"https://4954221.fls.doubleclick.net/activityi;src=4954221;type=gl-cs;cat=dcmgl0;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=2487956173460.919","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938140_5891319849815&itemspaceid=12417&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938140&cnid=228309828,228324316,228338641,228330743,228315627,228332321","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://pagead2.googlesyndication.com/pagead/osd.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.pa4EfGZJtyM.O/m=signin_annotation/exm=client,plusone/rt=j/sv=1/d=1/ed=1/am=AQE/rs=AGLTcCNvuMxw8LpLrCWFeoIaET1OMP8dSQ/cb=gapi.loaded_1","request_type":"script"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM4ZDDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oF0AFWqV2jVcquajfPP98rJrAzq3Q?xjs=s1","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://us-pxl.trafficstars.com/api/v1/p/p.js?r=1&s=06b4c6ebc5a3a6a05faccd057f530a36db6f0e58dcc2ba3a3cd575737724d66f1523791854&p=e0SEGUNHhI4YLAbWGXNQRA0aZG6IgVGxhZkaZcS0oHFDxo0WYmLMiHGRBowZZsbIwDGjBkQRCsOQMXMwoYg5cAzqwFFDoRg3bg5CvIEDxw2FdeSwOWjjpQwYOZLKcIiGDh04c3S8eHHmzcU3clrMKYPHxZg3bV7QITPnB9s5Scj0OJNjxkcxZdh8kcOlTkUZNuB-GROmDZwwac64oWsXr16_gG3UodPmy5w3SseU6UGGTJjIMAJTttymDJk0ddr0aPNGTOjRlQkbRqyYMR05c76IaQN7smw6ZeSsbi3myx03suvMCfOl7t2Jer-0wYPmixk6X47aheGbNOE3ycsk70HU6A3fcGKwdlHd8Jzgcs6mTS-jRxA3ZOS8SUMmPY0e0quhhyZcS4ONMlYw4o034kvPhh6GQGM_00AoUIwDy0gvhx6oKGO8FUpgSUQhYsBBxBxEHOIKjQprYw7f8JijB6hwcOEGGFwgyQW7fMOtBxtikCEMM0ys4SLPQKJBhhpAwiGGGHJoYYYczAijBhnGgGgMHGpSaIzDDtpuBhhkIsOOg2bAocyB4IAjTTbhqEOMphQiIy2H2mgPjffim6-NmESozCYsZ7ghByNpUAgOORrSIceKKrKrhkgrtfQmOcpA81EXKo3hJCYVksOONxHySYQyxoADUE6jcslSWGG4qY460nCIhlRlKKNIkO5yiSMbxoChBRzKgMGGFsoIY6YnxchhSBu8xKmMORwS41AzaBhjBhpaEPYkYIlsYVnRLhIDhyvFEIMMYWvIIdAxHBWhiikCZUPeIpwINI1SRajxxhx3tCvQOsJwqEA9DmQjjBdq6BQEFJhIw4068NgBBPz0448MEGzo1IUYLi6QjjdAOAJiGlIAQYha2SDjhSagUEIGGkCmsgUbUsbYTQRZFGOJNOho2FAdbYB4CSSoaIIJFkBgI401yjA51TXeUFlCCsto2MaARcvBhSctNBBBEKYgMgw50hj6hqJBgIKKKah4wUQYTvJ4pLpZCpQMTW2yc7-DZFDojWp1oGEGheg4w6EghyyyJyQl4ohJJ6GUkkorsdRS2y4DvcOhGGBYM1A0QK9hBhsCnWNUh_ajIwyS5Qg005p0EMEqrLTiSk_3XvQTLbUCVc8hGISnyvbiv4T9oC18kiGGLuyUl14R-lAgIA==&d=1224&priv=false&w=t","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://cdnssl.clicktale.net/www20/ptc/544fc825-311a-44c5-86f0-70581a36c216.js","request_type":"script"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/complete/search?q&cp=0&client=mobile-gws-hp&xssi=t&gs_ri=mobile-gws-wiz-hp&hl=en&psi=1DfTWsDQNeqB0wKXjYPQBw.1523791831656","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/51LGid1qdxL._RC%7C01BL18zkkEL.js,31a72IenKyL.js_.js?AUIClients/NavMobileMetaAsset","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9211132908&aam=86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/ny75r2x0?redir=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537148856%26val%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=mediamath&mmuuid=dc855ad3-3170-4100-bb84-4e532726c642","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/css/95b55ef0.index.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=38&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A38%7D&logFlag=uaction_1523791857874&t=1523791895876","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://dis.criteo.com/rex/match.aspx?c=25&uid=WtM36dHM4SIAADb8vFcAAABK%26445","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DQ3AKTQX4Z8AX1W7T64V5%26pty%3DOfferListing%26spty%3DAll%26pti%3DB00O18AJE4:1000","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/icons/ajax-loading-small-vfl3Wt7C_.gif","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=NjY5OTBmMjQtODcwNi0zMGYyLTk3ZjMtNTc1YzBmZTQ2ODQzCTQ1CVBEUFMwMDAwMDAwNjAxMDQJNTAJMzUzODc0OAkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.google.com/ads/user-lists/1064110624/?userId=Yotka6hnTlOGvGgrxT09Cg&guid=ON&script=0&cdct=2&is_vtc=1&random=3877411100","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/madlipz-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s1.pimg.tw/avatar/applechang1225/0/0/resize/65x0.png?v=1523775036","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=g8f47s39e399f3fe&google_push&google_sc&google_hm=V3RNMzR3QUFDR01mUGZ5UQ==","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p4.ssl.qhimg.com/t01a334284ab2c07df4.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/cx_remenyouxi.png","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yr/r/hDF9QRJiuzm.png","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://www.facebook.com/brandlift.php?sessionId=lmjy9NsjglodU0uYNqHzQ7WSc1o591523792035&media_type=dcr&advertiser_id=NA","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/favicon/favicon-32x32.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p2.qhmsg.com/t01e2a809acc329ae82.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"http://m.pixnet.net/","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://m.360buyimg.com//mobilecms/s276x276_jfs/t13993/181/1468327997/358849/217d9be5/5a49a61cNad2b0d6c.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/product/core/core_ui_desktop@2x-vflLsWztX.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71N5hSP49AL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://securepubads.g.doubleclick.net/static/glade/extra_26.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/legacy_pyxl_controllers/async_cyberfend_util.min-vflv_BSS6.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-browse-core.min-vfldehF3N.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.livefyre.com/libs/fyre.conv/v3.0.0/livefyre.min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nba/500/scoreboard/phi.png&h=312&w=312","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://fonts.googleapis.com/css?family=Open+Sans:400,600,700,300&subset=latin,cyrillic","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31L-%2BMYhz%2BL._RC%7C31DlXN4JLlL.css_.css?AUIClients/SharedShoppingCartMobileAsset","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://cms.analytics.yahoo.com/cms?partner_id=MSFT","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/basics/recommend7.1.js?v=20180323","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a2.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NFL_STEELERS_SHAZIER_WITH_MARTY_SMITH/dm_180414_NFL_STEELERS_SHAZIER_WITH_MARTY_SMITH.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://googleads.g.doubleclick.net/pagead/id","request_type":"html"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/gen_204?atyp=csi&ei=GTjTWtyLFcXe0wLprqPwBA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.384,dcl.390,iml.384,ol.2852,prt.241,xjs.1776,xjsee.1776,xjses.1364,xjsls.239,wsrt.2142,cst.698,dnst.0,rqst.789,rspt.408,sslt.373,rqstt.1690,unt.2078,cstt.990,dit.2533&zx=1523791900481","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted9.svg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://id.rlcdn.com/464526.gif","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fpixel.everesttech.net%2F1x1%3F","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/971301452/?random=1523791866950&cv=9&fst=1523791866950&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1000051215/?random=1523791866937&cv=9&fst=1523791866937&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.360.cn/","request_url":"http://s0.qhmsg.com/static/24fee17ef5eeefee/zepto_touch_fx.112.js","request_type":"script"}
+{"origin":"http://www.360.cn/","request_url":"http://s1.qhmsg.com/static/c8b7de8c67377042/widget.1.0.2.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1523791950672&yhlClientVer=3.42.4&yhlRnd=9CGFu3n2bi1ReRyB&yhlCompressed=3","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c1.microsoft.com/c.gif?DI=4050&did=1&t=","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://token.rubiconproject.com/token?pid=2179&pt=n","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=76&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A76%7D&logFlag=uaction_1523791857874&t=1523791933876","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=mplatform.com&id=11459127779631990605","request_type":"image"}
+{"origin":"http://www.alipay.com/","request_url":"https://kcart.alipay.com/s.gif?data=eyJ3aW5fdmFyIjpbXSwicmVmZXJyZXIiOiIiLCJvcmlfaW5mbyI6eyJhbHBoYSI6eyJhdmciOjAsImRldiI6MH0sImJldGEiOnsiYXZnIjowLCJkZXYiOjB9LCJnYW1tYSI6eyJhdmciOjAsImRldiI6MH0sIm51bSI6MH19","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://dishdigital.sp1.convertro.com/view/vt/v1/dishdigital/15/cvo.gif?cvosrc=display.yieldmo.crdcut&cvo_cid=91234&cvo_creative=yieldmolifestyle&cvo_pid=SLGD_ACQ_MTAGAXX_COUSA_YM_NA_WTCP_CRDCU_000000XXX_XXXX_XXXX_YMxLIFESTYLEx_XXXXX_COUSA_HWXEN_WWWXOA_YLSL_EV_EN_H5_CRLinks","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=RHrw3K3wOn4CvLbMjg0qdt7y,0.09509710795005222&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031523791949%04viewtime%03%2Bstream%3A116%231523791948.383%2Bstream%3A117%231523791948.383%2Bstream%3A118%231523791948.383%2Bstream%3A119%231523791948.383%04_E%03l_viewtime","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&aip=1&a=1629002796&t=pageview&_s=1&dl=https%3A%2F%2Fwww.blogger.com%2Fabout%2F%3Fr%3D1-null_user&ul=en-us&de=UTF-8&dt=Blogger.com%20-%20Create%20a%20unique%20and%20beautiful%20blog.%20It%E2%80%99s%20easy%20and%20free.&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAAAB~&jid=1604521254&gjid=1189720053&cid=308373565.1523791962&tid=UA-18003-38&_gid=2125341841.1523791962&_r=1&z=1325615589","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/youtube-mp3-download-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/head-ball-2-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/circleci.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/atom.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/customers/mailchimp.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB10eZQQpXXXXXRXVXX760XFXXXO.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://img1.gtimg.com/rcdimg/20180110/09/30442229.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/arrows.png?v=3","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/external-button-hover._CB304896345_.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/refresh_black.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/87IAAOSwEEBaTA7G/$_57.JPG","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-ec-not-a-hotel-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/GETTY_IMAGES/SKP/827661730__Qbgzti6N.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f10/07526bcfbc289b82f5368b25a0950bab_erotic_285x160.jpg?cno=e51e","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/14/65/19/146519f6af4f807b43c14f605be2c5b6/146519f6af4f807b43c14f605be2c5b6.3.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1L9UEkkyWBuNjy0Fpq6yssXXaU.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s720x352_jfs/t16804/166/1630000797/263975/a0155cef/5ad06b15N0dc9b37c.jpg!cr_1125x549_0_72!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s720x352_jfs/t18658/326/1509428118/116204/7b1d53b7/5acb3c84Nae711028.jpg!cr_1125x549_0_72!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D","request_type":"text"}
+{"origin":"http://www.apple.com/","request_url":"https://securemetrics.apple.com/b/ss/appleglobal,applehome,applestoreww,applestoreus/1/JS-2.7.0/s14726981874948?AQB=1&ndh=1&pf=1&t=15%2F3%2F2018%204%3A31%3A31%200%20420&fid=3E8E675443B3026F-0CEFB8E58966EE51&ce=UTF-8&pageName=apple%20-%20index%2Ftab%20%28us%29&g=https%3A%2F%2Fwww.apple.com%2F&cc=USD&ch=www.us.homepage&server=new%20approach%20ac-analytics&events=event220%3D2.997%2Cevent221%3D600%2Cevent222%3D0.000%2Cevent223%3D1.660%2Cevent224%3D0.353%2Cevent225%3D0.010%2Cevent226%3D3.240%2Cevent227%3D0.010%2Cevent228%3D2.194%2Cevent229%3D5.444%2Cevent230%3D0.142%2Cevent231%3D8.599%2Cevent232&h1=www.us.homepage&c2=g%40%20google%20swiftshader&v3=aos%3A%20us&c4=D%3Dg&v4=D%3DpageName&c5=linux%20x86_64%202x&c9=android%206.0.1&v14=en-us&c19=aos%3A%20us%3A%20apple%20-%20index%2Ftab%20%28us%29&c20=aos%3A%20us&c25=direct%20entry&c48=1&c49=D%3Ds_vi&v54=https%3A%2F%2Fwww.apple.com%2F&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"text"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17653/0/0/312/ht%20h0-s4003.p12-sjc.cdngp.net/0","request_type":"text"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/bundles/base/Vendor.js/0b34a2e2f7c2.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.wikia-services.com/__track/special/trackingevent?a=&beacon=NyiV-67qg0&c=1452001&cb=1523791981595&client_ip=208.70.31.93&dev=false&dev_cat=mobile&event_ts=1523791981&f=Home&ga_action=impression&ga_category=ns-fandom-app-smart-banner&ga_label=view&lc=en&pg_type=home&pv_number=1&pv_number_global=1&pv_unique_id=af377f25-1ffc-4914-9834-c80ec4217531&r=direct&r_type=direct&s=fandom_mobile&session=Q4ulawcgCl&session_id=5d21d0a7-b14a-4f7f-ac4b-8ba9846d26f7&site=web&t=event&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&url=http%3A%2F%2Fwww.wikia.com%2Ffandom","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-a299f42da18/v3/js/i18n/front/english.json","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://d3qdfnco3bamip.cloudfront.net/wjs/v3.0.1523571279/javascripts/livefyre_base.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-carousel_atomic_sm/td-applet-viewer-templates-carousel_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/dust-helpers-0.0.154/intl-helper/intl-helper-min.js","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/Js/full-anon.en.js?v=a5cca6d848a4","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-SignupPage-cb26127d6ee85fa1b9bc.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/infiniteScroll.min.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/lib/invoke/serverDataFactory_e0af113.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/prom_ev.gif?posId=10080201&itemId=6027&SUV=null&_time_=15237919383362821134742249","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/photo/2018/0414/r356541_1296x729_16-9.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://ad.doubleclick.net/ddm/activity/src=1295336;type=adobe994;cat=aamuuid;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=880546608&t=pageview&_s=1&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEDAAEAB~&jid=396986874&gjid=1671281732&cid=970841907.1523791982&tid=UA-32129070-1&_gid=1459932104.1523791982&_r=1&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=584488678","request_type":"html"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/gen_204?s=webaft&atyp=csi&ei=_jfTWubELYmh0wKW3pXgBw&rt=wsrt.2153,aft.457,prt.238","request_type":"html"}
+{"origin":"http://www.savefrom.net/","request_url":"https://mobpushup.com/interstitial.php?zoneid=1617677&fs=0&cf=0&sw=360&sh=512&sah=512&wx=0&wy=0&ww=360&wh=512&wiw=360&wih=512&wfc=1&pl=https%3A%2F%2Fen.savefrom.net%2F&drf=&np=0&pt=0&nb=1&ng=1&ix=0&nw=0","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.googleadservices.com/pagead/conversion.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_window_focus_non_hydra.js","request_type":"script"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://cdn.krxd.net/controltag?confid=KPSUiAKl","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobeid-na1.services.adobe.com/ims/check/v4/token?jslClient=adobedotcom2&jslVersion=89ab5ef","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/js/libs/share42_en_2.js?v=2","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212284268","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.quantserve.com/pixel/p-vj4AYjBqd6VJ2.gif?idmatch=0","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixel.rubiconproject.com/sync.php?cookie_redirect=1&p=dfp&google_gid=CAESEPts9Ja8iDZmvobMY3keku4&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"http://pespn.chartbeat.net/ping?h=espn.com&p=%2F&u=CVBZZMDElqi1BfM5Op&d=espn.com&g=22222&g0=frontpage&g1=index&n=1&f=00001&c=0&x=1&m=1&y=8807&o=360&w=512&j=45&R=1&W=0&I=0&E=0&e=0&r=&b=35124&t=CqtxJinkxhzDVS54lCezh7VB1tndr&V=103&i=ESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&tz=420&sn=1&sv=DknOEDBMYM-cBIPB6VC9wap6BQuzUI&sd=1&im=047b2ff3&_","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://sync.adaptv.advertising.com/sync?type=gif&key=yahoous&uid=5560327129300825001&nsync=0","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=20&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A20%7D&logFlag=uaction_1523791857874&t=1523791877876","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://www.facebook.com/tr/?id=969519813086003&ev=Microdata&dl=http%3A%2F%2Fdiply.com%2F&rl=&if=false&ts=1523791969428&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Aurl%22%3A%22http%3A%2F%2Fdiply.com%2F%22%2C%22og%3Atype%22%3A%22website%22%2C%22og%3Atitle%22%3A%22Diply%22%2C%22og%3Aimage%22%3A%22http%3A%2F%2Fcdn.diply.com%2Fstatic-images%2Fv2%2Fico%2Fapple-touch-icon-210-precomposed.jpg%22%2C%22og%3Aimage%3Awidth%22%3A%221200%22%2C%22og%3Aimage%3Aheight%22%3A%22630%22%2C%22og%3Adescription%22%3A%22Diply%20is%20a%20leading%20social%20entertainment%20publisher%20that%20creates%20captivating%20content%20for%20millennials.%20We%20are%20a%20ComScore%20Top%2010%20Lifestyle%20property%20with%201%20billion%20video%20views%20monthly.%22%2C%22og%3Asite_name%22%3A%22Diply%22%7D&cd[Meta]=%7B%22title%22%3A%22Diply%22%2C%22meta%3Adescription%22%3A%22Diply%20is%20a%20leading%20social%20entertainment%20publisher%20that%20creates%20captivating%20content%20for%20millennials.%20We%20are%20a%20ComScore%20Top%2010%20Lifestyle%20property%20with%201%20billion%20video%20views%20monthly.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=28&it=1523791965948","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://0914.global.ssl.fastly.net/ad2/img/x.gif?cb=1523791865145","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_fashion-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/realm-defense-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/netflix-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/codeclimate.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/XLIzvEbVuqXvYxUK0lfilYg612zc4qFnhLWASre2oS1HYZkKrPuMG54By3CJ1A=w256","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/home-phone-mobile.png?v=9bd4dace1","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p9.qhimg.com/t01bccedbc0d45dd194.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tfs/TB1jorbepOWBuNjy0FiXXXFxVXa-183-129.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938123_1362960178626&itemspaceid=12781&adps=6400320&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938122","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://login.taobao.com/jump?target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.tmall.tac.gateway.execute%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.11%26appKey%3D12574478%26t%3D1523791819640%26sign%3D8ab28eb896b2507753d64da9f48840a2%26AntiCreep%3Dtrue%26api%3Dmtop.tmall.tac.gateway.execute%26v%3D1.0%26ttid%3Dh5ttid%26type%3Djsonp%26dataType%3Djsonp%26timeout%3D2000%26callback%3Dmtopjsonp1%26data%3D%257B%2522msCodes%2522%253A%25222017080800%2522%252C%2522params%2522%253A%2522%257B%255C%2522isH5%255C%2522%253A%255C%2522true%255C%2522%252C%255C%2522h5ttid%255C%2522%253A%255C%2522TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%255C%2522%252C%255C%2522pageCode%255C%2522%253A%255C%2522SELECT_FRONT_PAGE%255C%2522%257D%2522%257D","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=b60eac03-40a0-11e8-b967-024257f42601%252Chttps%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253Db60eac03-40a0-11e8-b967-024257f42601","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://fonts.gstatic.com/s/rubik/v7/iJWHBXyIfDnIV7F6iGmd8WD07oB-.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5238000/5238550/220x165/6.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/SaGGwAPQ45lfBMK2Y4gnlQ/009/123/973/320x240.8.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/AustinBundle-Mobile_billboard-a-de-1242x450._SX1242_CB507116531_.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/2d/2e/28/2d2e28701b93669ee449105bc2cd1c7b/2d2e28701b93669ee449105bc2cd1c7b.1.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/036/007/32d/big_lq/f11cd1ff9f08d1ee5faae9fc91a17071.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f19/9d2a3b80109cecd3c799fb0bbe7e08ae_erotic_285x160.jpg?cno=798","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f15/590b4a2f89eb0c98dd4adee551cc5771_erotic_285x160.jpg?cno=48b5","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f11/156e1a709cb2611fbbb27be894fd5782_erotic_285x160.jpg?cno=e3fd","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjE0MzgxNjYzOV5BMl5BanBnXkFtZTgwMzk3NDUyNTM@._V1_SY345_CR7,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/subscribe_save/gw/mobile/1049516_gw_mobilebillboard_02_1242x450._SX1242_CB507792628_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/2018/x-site/spring_sale/traffic/1100037_spring_sale2018_traffic_3_mobile_billbord_1242x450._SX414_CB502011901_.png","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/kindle/merch/2018/Product/15811392/gw/vx190_bj_echo_evergreen_grey_1242x450._SX1242_CB499110103_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/xba/Unrec_MD_1242x450_Men_Apparel_April18._SX414_CB502495893_.jpg","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://z.cdn.turner.com/xslo/aspen/config/theo/cnn/aspenanalytics.json?_=1458","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://fastlane.rubiconproject.com/a/api/fastlane.json?account_id=11078&rp_floor=0.01&rf=https%3A%2F%2Fwww.cnn.com%2F&p_screen_res=360x512&x_source.tid=ceffcb6d-e438-47aa-9b2a-b6cca793c897&tk_flint=plain&size_id=15&p_pos=btf&tg_fl.eid=ad_rect_btf_03&tg_fl.uname=%2F8664377%2FCNN%2Fhomepage&kw=CNN%2Fhomepage%2Crp.fastlane&tg_i.site=CNN&tg_i.section=homepage&tg_i.subsection=landing&tg_i.cap_topics=&tg_i.ssl=1&tg_i.pos=rect_btf_03&tg_fl.pr_acctid=11078&rp_secure=1&rand=0.7376698115040861","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://api.ero-advertising.com/get.php","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/common/recaptcha.min-vflQavfWi.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/adobe.min.fp-d4b63fc3beac0a84488453a586b501f3.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://edge.quantserve.com/quant.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/activities/curtain/curtain.js","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static3.dditscdn.com/mbl/frontend_backbone/static/_common/member-client/script/armageddon-client.min-0739a.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/","request_type":"html"}
+{"origin":"http://www.google.it/","request_url":"https://adservice.google.it/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://cdn.krxd.net/controltag/KPSUiAKl.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://usermatch.krxd.net/um/v2?partner=amzn","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=index&id=E4EPXIH4q1pwUnX70BRuNTcBcJw4ZgAC","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=50&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A50%7D&logFlag=uaction_1523791857874&t=1523791907876","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=4e0ebfc0d2c5062f75b4618e84f1dbe6422b612e&ex=aoldisplay.com","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://level3ssl.optimicdn.com/img/13070/r20.gif?rnd=1-1-13960-0-0-33636-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=5KliiqJVwND3Ya02jg0qdt7v,0.45749670638073714&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031523791949%04viewtime%03%2BheaderBody%3A7%231523791948.383%2BheaderBody%3A8%231523791948.383%2BLifetool%3A11%231523791948.383%2BLifetool%3A12%231523791948.383%2BsideMenu%3A1%231523791948.383%2Bsearch%3A9%231523791948.383%2Bstream%3A111%231523791948.383%2Bstream%3A112%231523791948.383%2Bstream%3A113%231523791948.383%2Bstream%3A114%231523791948.383%2Bstream%3A115%231523791948.383%04_E%03l_viewtime","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://tags.bluekai.com/site/2981?id=&google_gid=CAESEPMBUarz4y883bCIEG4fmDQ&google_cver=1","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=880546608&t=event&ni=0&_s=3&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=ads-babdetector-detection&ea=impression&el=No&ev=0&_u=YEDAAEAB~&jid=&gjid=&cid=970841907.1523791982&tid=UA-71552437-1&_gid=1459932104.1523791982&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=No&cd7=&cd11=US&z=713358090","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/overlay.png","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://static-alias-1.360buyimg.com/jzt/temp/conermark/ad_jd.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/vJpXUm7SIjPhi4C1k_XRNxbJgUXQd2xiOQvOA_F1zyE8zD5HodQT6OEkUos-=w128","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://tpc.googlesyndication.com/safeframe/1-0-23/html/container.html","request_type":"html"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/wss/fonts/SF-Pro-Display/v1/sf-pro-display_regular.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/2568000/2568831/220x165/9.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/b9185dc6-12f0-49a5-b585-1089a5adb294_desktop.png?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20130828whsz.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_XuFZvc0Et2X-CGVswlEgJw&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://img1.360buyimg.com/da/s720x352_jfs/t19507/59/1594056368/98032/7d4a6bad/5ad0687cN2b1e3bed.jpg!cr_1125x549_0_72.dpg.webp","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://beacon.tingyun.com/pf?pvid=c5f0d6a8-d452-4523-9ca8-4a0813517a9a&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=fad86f04-fa3a-4f2f-a92a-15fae388816e&sid=676406ea-440a-48bc-820a-57146ad87968&f=2741&qs=2215&rs=2729&re=2750&os=7664&oe=7771&oi=7662&oc=15363&ls=15364&le=15396&tus=0&tue=0&cs=1260&ce=2215&fp=5125&sl=1721&je=0&sh=512&sw=360&dr=7665&fs=9885&trflag=1111&__r=1523791939832","request_type":"text"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/menu.svg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/hclips.svg","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://cdn.krxd.net/userdata/get?pub=44c1a380-770f-11df-93f2-0800200c9a66&technographics=1&callback=Krux.ns._default.kxjsonp_userdata","request_type":"script"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/security_edge.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-main/td-applet-viewer-templates-main-min.js","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/Js/mobile.en.js?v=2a46ccd0c25d","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/analytics/cnnexpan/jsmd.min.js","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/scripts/boot.worldwide.0.narrow.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://rules.quantcount.com/rules-p-z0zMG4nCgXzzj.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/01f999dbe8972e3f86979480467b4c57.js?conditionId0=379384","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/pagead/s/cookie_push.html","request_type":"html"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditmedia.com/gtm?id=GTM-W7RKT4&cb=null","request_type":"html"}
+{"origin":"http://www.bongacams.com/","request_url":"https://bongacams.com/load-promo-m/b4728/nn/us_en/0/1/0/2176/straight","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100225076&apid=beans_12420&impid=0f534ad1d8bcea4d0_0_0&at=1&mkey=0f534ad1d8bcea4d0_0_0&latcy=2919&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=4491.3125&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DZr9NjNQzpgF%2FiZEYL%2BrWKGEVc26xI7%2FLqX0dIQ7UqZnroej10%2Fpkj%2BeQL4qA7ARlWRcm%2FDmZmjCqb3p57HqgvWAQmujSPKKHh6gunta5TjRxXlhDh%2Fxafdk%2F1emkjOZurtkO7aJVl%2BYGpe38TZl8yFN8sGGk7pS%2F8hlEvaDwudvyeYfDIfAsuhs2Gn9vEjaKdMb4mutx8noVgDNv9SF6YJCtDpuTzm8Yu%2Fxfj9JqFagUjM8jr09Y1TiYL%2B8%2BOuDzJ3t%2BzBjnd4ZQEplKDH8t%2F68fUbBLXoX48CPBh2n9Ch2ZGLjHfbk2qOgGw8dmUD4S7BfRNer26QcBsiZmImTchaq9ff8uir177jN0G2vkenDS1oOfD24h0oymv1wQIchgNsKgFVIoPfUcbKfjR0OfeolyloQu2rapZ3Vd%2FkQysLaTGSViO4uaphDy7uuzzrR5BzjpJ5%2FncXE3Lg9hcz%2FYFz9JEZ6PYGp%2BdgWqAWmyCpuaVhGzxhPRZkPJL%2FDloGJzi1zCGLOYufEulzVhmYl2909d8Jsufj9ygho95%2FIBpSJ4Z5wfh0KwLE8tIL%2BOwGuBJO7%2Fv4cETZUx5vPiWE%2BUYZtljEffYP5moHArje8XHJM%3D%09tt2%3D1523791940689%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=3788234932909&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791941083","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://mail.ru/","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=adobe-global-mbox&mboxSession=9bacdabf39b7406b83ce178a57242400&mboxPC=&mboxPage=5ededb5d3e024eab82d38d46617d12fd&mboxVersion=1.2.3&mboxCount=1&mboxTime=1523766796099&mboxHost=www.adobe.com&mboxURL=https%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-420&screenHeight=512&screenWidth=360&colorDepth=24&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=0F715D2B1317710A-3C141A64CA81D397&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id=","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/t_tkr/errlog?col=0&filename=&line=0&x=0&y=0&stime=1523791868629&etime=1523791868630&p=764344014241209959&page_url=https%3A%2F%2Fwww.cnn.com%2F&w=360&h=512&e=0&wh=SDKRE&location=https%3A%2F%2Fwww.cnn.com%2F&desc=Script%20error.&v=9.4.10-b-301","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/id?d_visid_ver=2.5.0&d_fieldgroup=AAM&d_rtbd=json&d_ver=2&d_orgid=9E1005A551ED61CA0A490D45%40AdobeOrg&d_nsid=0&d_mid=91347194757900030554314852707948543921&d_blob=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&d_cid_ic=AVID%012D699C4005031F55-600011820000562A&ts=1523792001667","request_type":"script"}
+{"origin":"http://www.twitch.tv/","request_url":"https://gql.twitch.tv/gql","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/delivery/cdn.json","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2","request_type":"font"}
+{"origin":"http://www.amazon.de/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/2.75.8/js/gigya-sharebar.min.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3iQB64/yU/l/en_US/irm7bGrjF_W.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmwply.gif","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BB6QDrH.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/kellyku/albumset/18193107/zoomcrop/75x75.jpg?v=1521184893","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33050677","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/6e/48/16/6e48161d7b460fcb576221ac95ca5547/6e48161d7b460fcb576221ac95ca5547.19.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201803/18/158581322/thumbs_5/(m=eafTGgaaaa)(mh=4mJ5wzeIFtfsGINJ)12.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/00b/369/306/big_lq/5770622f3e5a224c17f552049ff125d9.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/435000/435338/220x165/11.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjc5Njg2MzU0N15BMl5BanBnXkFtZTgwNTM2OTYyNTM@._CR470,1239,581,581_UX402_UY402._SY233_SX233_AL_.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/i/favicon-e5142de215.ico","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/mobi/2017/image/logo-text-color_v2.svg","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://use.typekit.com/af/573c5d/000000000000000000017703/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n7&v=3","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-api_v2.min-vflZZOnd8.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-55e442fd3961370014000784.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdbads/custom/test/index/js/show_ads.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/js/main-bd51b0c3ef.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/media/motion/2018/0415/dm_180415_mma_poirier_gaethje_hl/dm_180415_mma_poirier_gaethje_hl.jpg&w=686&h=386&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/ImageResolution.aspx?w=360&h=512&hash=99e2f70c0787602dfbe34d372ff08d7a","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dptr.areyouahuman.com/ping/adobe/%5BPARTNER_USER_ID%5D?rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D58051%26dpuuid%3D%25%25AYAH_UID%25%25","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://odb.outbrain.com/utils/get?url=https%3A%2F%2Fwww.cnn.com%2F&settings=true&recs=true&widgetJSId=MB_12&key=NANOWDGT01&idx=0&version=01002504&ref=&apv=false&sig=NpGpNWuG&format=html&rand=39935&winW=360&winH=512&adblck=false&secured=true","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v002/t_ads/ads?bust=1523791867546&ae=0&_s=1&e=0&v=9.4.10-b-301&page_url=https%3A%2F%2Fwww.cnn.com%2F&p=764344014241209959&description=View%20the%20latest%20news%20and%20breaking%20news%20today%20for%20U.S.%2C%20world%2C%20weather%2C%20entertainment%2C%20politics%20and%20health%20at%20CNN.com.&title=CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos&dnt=false&scrd=3&h=512&w=360&pft=1523791867546&ct=1523791867432","request_type":"script"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://quriosity.yahoo.co.jp/v1/recommend/list?output=jsonp&cassette=stm_top&cat=sports&crumb=-100&start=1&results=20&lvt=0&crop=on&imgx=192&imgy=192&imgx2=718&imgy2=298&movie_imgx=296&movie_imgy=168&movie_imgx2=608&movie_imgy2=342&lgcode=&extra=on&vtestid=&contentsLoopInterval=5&callback=reqwest_1523791947485","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://b.scorecardresearch.com/b?c1=2&c2=6177433&comscorekw=movies&ns__t=1523791980447&ns_c=UTF-8&cv=3.1m&c8=FANDOM&c7=http%3A%2F%2Fwww.wikia.com%2Ffandom&c9=","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.quantserve.com/pixel/p-vj4AYjBqd6VJ2.gif?idmatch=0","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://m.fg8dgt.com/sync?ssp=bidswitch&bidswitch_ssp_id=pubmatic","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://d.turn.com/r/dd/id/L2NzaWQvMS9jaWQvMjM2NTYzMjkvdC8y/url/https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D470%26dpuuid%3D%24!%7BTURN_UUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com%26","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDoyNy41NDIJOWE1NDFhNDEtZjlkNi00M2VmLWI4M2EtODQ3MTI1MjZjYjlhCTMyNTAyNDUJMzExNzM2Mwk1OTE4NDAzMzAxX1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1ODExOAkzNTMxOTg3CXh4bAkxCS0JV0FQCS0JMQk2MGIxMzYwOWVkNjI4NjNjMDE0YzhiNDM4MWVlNTY4ZglkZWU0MDI0ZS1hOWE5LTM0ODUtODhmOC00MDgxYTVkY2VmODMJMzAwMDAJMC4wMDE2NjY2NjY3CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjAzMTc6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwMjowLjB8dXNlcl9nZW5kZXI6NTAxOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTMJMzAwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=5f457f3ac7f214ff&p=3uQCTqmpNIWI%2BECBpdzvg40Ov91U84Nht3m1IQ%3D%3D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://rtd-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=44&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A44%7D&logFlag=uaction_1523791857874&t=1523791901876","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://pixel.quantserve.com/pixel;r=202785889;a=p-xLEyC0FLYFXAH;labels=;rf=0;fpan=1;fpa=P0-140943962-1523791955405;ns=1;ce=1;cm=;je=0;sr=360x512x24;enc=n;dst=1;et=1523791955402;tzo=420;ref=;url=https%3A%2F%2Fwww.redditmedia.com%2Fgtm%3Fid%3DGTM-W7RKT4%26cb%3Dnull;ogl=","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=4&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A4%7D&logFlag=uaction_1523791857874&t=1523791861883","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=31950&nid=2974&put=2921392519752984044","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://rum-collector.pingdom.net/img/beacon.gif?id=5654525eabe53d8c6442edf2&sAW=360&sAH=512&bIW=360&bIH=512&pD=24&dPR=3&or=portrait-primary&nT=0&rC=0&nS=0&cS=2541&cE=3558&dLE=2541&dLS=2541&fS=4300&hS=2861&rE=-1&rS=-1&reS=3559&resS=4288&resE=4642&uEE=-1&uES=-1&dL=4313&dI=9326&dCLES=9327&dCLEE=10190&dC=14904&lES=14904&lEE=14910&s=nt&title=Free%20Live%20Sex%20Cams%20-%20Live%20Sex%20Chat%20and%20XXX%20Live%20Porn%20Shows&path=https%3A%2F%2Fbongacams.com%2F&ref=&sId=35f9h3jh&sST=1523791945&sIS=1&rV=0&v=1.3.3","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.google.com/ads/user-lists/925133270/?value=1.00&currency_code=USD&label=IEQNCNXH9GcQ1tORuQM&guid=ON&script=0&cdct=2&is_vtc=1&random=3873416410","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/pdf-reader-android.png:l","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/sprites/photolayer/6e408f2fa6508d62e47b219299eceb67@2x.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/ymusic-android.png:l","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_Videos/ic/495b665f/14f67787.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/apple_icons/apple-touch-icon.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/h0_380xSF1bvqkrxX4gIfgUAYvhzVC2a9BcenHEeq786W-kSCb-_sVpvI1Zc=w512","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://counter.yadro.ru/hit?uhttp://m.odnoklassniki.ru/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel/attr?d=AHNF13JNnCbkEwL-o3U1Ik9m39aGO8gfhTWc","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://stags.bluekai.com/site/24668?dt=0&r=1481875026&sig=2770883054&bkca=KJyguithpuMJpxW9eGRewQ==","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/b7OlvYdiPxIYq12nHeReOQ/009/341/250/320x240.7.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/BE/80A1C3.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/xba/ELECTRONIC._CB503098439_.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://tags.tiqcdn.com/utag/tiqapp/utag.v.js?a=disney/disneyid/201804042254&cb=1523792047101","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/assets/js/adsSimple-1.3.0.min.js","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/min/browser-min.js?1523501950","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdnssl.clicktale.net/www/monitor-latest.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-home.min-vflgMVE5G.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/global_constants.min-vflxItXmN.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://s.aolcdn.com/ads/adswrappermsni.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-viewer-mainview/td-viewer-mainview-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/yaft/yaft-0.3.11.min.js","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://rules.quantcount.com/rules-p-xLEyC0FLYFXAH.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mm.markandmini.com/Pixel/8tthgyykyv","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"http://sr.symcd.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBR0JBRnBp%2F14Jg%2FXj4aa6BlKlQVdQQUAVmr5906C1mmZGPWzyAHV9WR52oCECxqpDaJyq%2F%2BD0ZiblxvnRKiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://odr.mookie1.com/t/v2?tagid=V2_393725&AMAZON_REGION_SPECIFIC_ENDPOINT=aax-eu.amazon-adsystem.com/s&src.visitorID=fB4PTJA_R_ej18cgihHVoQ","request_type":"text"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://www.googletagmanager.com/gtm.js?id=GTM-MJ29FD7","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/color-base/color-base-min.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/11Muzrhwo6L._RC%7C41vNkR6eYDL.js,31XuHZCLcRL.js,11tPmvtDkXL.js,317hoZTRAgL.js,211oGttD+KL.js,31E+vLBB9PL.js,51Y-Tl+t96L.js,51nC-xYS8UL.js,21LeqsQWezL.js,31swJcQcmUL.js,016DBHJkIYL.js,216ts510QRL.js,51byRoBM5yL.js,216nH77ENDL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,11eu-Mk7IDL.js,21AuBaN+lVL.js,518h2Um1TpL.js,01tPYxCI2PL.js,01nKqcvaCIL.js,11f58pNTm7L.js,41i3QyGewtL.js,01X5C8pWB1L.js,51tAEm6Zv9L.js,117xk5an6TL.js,21kjCAUM3nL.js,31egXBuM55L.js,01RHiyjONOL.js,31zYeTS++kL.js,21CrGn+akTL.js,51QrDHXq9ML.js,31zob0zDCQL.js,11eSkH3Id-L.js,21q5QmCNgJL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,01DShqNIDKL.js,51rCZ2WOe0L.js,71z9MYB3x9L.js,01dIViFgwyL.js,319kjuuQkzL.js,21mtabjvdBL.js,41Eexuqvf6L.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,015J4NGaO3L.js,11B4fwZPeqL.js,214q28gHRFL.js,113JOW7LkIL.js,01jqyAujTwL.js,01KcbtwkAOL.js,01-XJ1YSEXL.js,11+FwDesCML.js,01NAT+3p7KL.js,111vgqp2a0L.js,51vGIS0VrtL.js,01MZJG6lH8L.js,01VtYReatCL.js,21vc9PfFLNL.js,01mL-cPJ2YL.js,01RQtSMdG+L.js,11ZcUC5H2zL.js,01UZjPg57RL.js,01l3c7okxRL.js,01qwoVEkKlL.js,318hHRose9L.js,011X+p22ALL.js,01k57x9vvBL.js,01rjsjeoEcL.js,01ZF+ovNflL.js,31JPVjZ0jGL.js,01S8y9NkxoL.js,019ztXtdUIL.js,11AzyvmKmOL.js,01tJd4+VUOL.js,01MEbpLZWbL.js,51tlWANRbLL.js,01y-5aCXJyL.js,01rg6Ce9FhL.js,01c1fUAHkJL.js_.js?AUIClients/DetailPageMobileWebMetaAsset","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/lsp.aspx","request_type":"other"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/cssbin/mobile-html5-player-mweb-2x-mangled-vflj6jMCO.css","request_type":"css"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/styles/global.css?_v=c0749b447abc55ec8dfc3325016b8bcb","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=90&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A90%7D&logFlag=uaction_1523791857874&t=1523791947876","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=rightmedia.com&xid=E0","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=e0bb0cbf-40a0-11e8-91bf-bfc17a0f74ff&ex=adelphic","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://dis.criteo.com/rex/match.aspx?c=31&uid=5aa5ccf9-c0f2-4c69-b91b-8a0fbee20368","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D49NGBMVT1ABRN6GGR916%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D293%26cf0%3D1980%26pc0%3D1980%26ld0%3D1980%26t0%3D1523791988825%26sc1%3Dgwm%26cf1%3D2175%26af1%3D6405%26pc1%3D6405%26ld1%3D6405%26t1%3D1523791993250%26sc2%3Dlg%26af2%3D2211%26pc2%3D2211%26ld2%3D2211%26t2%3D1523791989056%26sc3%3DcsmCELLSframework%26bb3%3D2261%26pc3%3D2261%26ld3%3D2261%26t3%3D1523791989106%26sc4%3DcsmCELLSpdm%26bb4%3D2261%26pc4%3D2265%26ld4%3D2265%26t4%3D1523791989110%26sc5%3DcsmCELLSvpm%26bb5%3D2265%26pc5%3D2266%26ld5%3D2266%26t5%3D1523791989111%26sc6%3DcsmCELLSfem%26bb6%3D2266%26pc6%3D2267%26ld6%3D2267%26t6%3D1523791989112%26sc7%3Dinteractivity%26cf7%3D4594%26pc7%3D4594%26ld7%3D4594%26t7%3D1523791991439%26sc8%3Ddata-store-1%26bb8%3D4819%26cf8%3D5605%26pc8%3D5605%26ld8%3D5605%26t8%3D1523791992450%26sc9%3Dcard-load-1%26bb9%3D5636%26cf9%3D6361%26pc9%3D6393%26ld9%3D6393%26t9%3D1523791993238%26sc10%3Dcard-load-2%26bb10%3D6394%26cf10%3D7308%26pc10%3D7333%26ld10%3D7333%26t10%3D1523791994178%26ctb%3D1:12730","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://ib.adnxs.com/getuid?https://beacon.krxd.net/usermatch.gif?adnxs_uid=$UID","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://pixel.mathtag.com/sync/img?sync=auto&stat=batch_supply_passback&mt_nobot=1","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=19360&dpuuid=91191954147729940174299115411397659455","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/airbnb-logo.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/jd-sprites.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/next_s.png","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/images/mobile/logo/logo_2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/WrBvOY07H7-s7HBXAjxwftmhbRC9E6U0jFl-84rniR1UIJVDY4V9El19hkEWtA=w512","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://tpc.googlesyndication.com/sodar/6uQTKQJz.html","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=aam","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem5YaGs126MiZpBA-UNirkOXOhpKKSTj5PW.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5443000/5443809/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180323/f44d307589141c1ef28c02.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/41/d9/56/41d956923ebf3fb0f0d5b91ee8155e3c/41d956923ebf3fb0f0d5b91ee8155e3c.22.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81hPQdwaSKL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/kindle/merch/2017/TAB/Dec/KET_2P/VX_1414_8KET2P_GW_MobileHero_1242x450._SX414_CB491668365_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/RQkAAOSwi6JavqDZ/s-l500.webp","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://d.webterren.com/webdigsource.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/mtop/5.6.0/scripts/Main.bundle.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-mag_slideshow/td-applet-viewer-templates-mag_slideshow-min.js","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/gtm-jail.jTMwZME_TT8.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/css/home.es.260.css","request_type":"css"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/stylesheet.css","request_type":"css"}
+{"origin":"http://www.wikia.com/","request_url":"http://rules.quantcount.com/rules-p-8bG6eLqkH6Avk.js","request_type":"script"}
+{"origin":"http://www.google.fr/","request_url":"http://www.google.fr/","request_type":"html"}
+{"origin":"http://www.uptodown.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&aip=1&a=129765439&t=pageview&_s=1&dl=http%3A%2F%2Fen.uptodown.com%2F&dr=http%3A%2F%2Fwww.uptodown.com%2F&ul=en-us&de=UTF-8&dt=App%20Downloads%20for%20Android%20-%20Download%2C%20Discover%2C%20Share%20on%20Uptodown&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAEAB~&jid=586465558&gjid=232247467&cid=1005470225.1523791954&tid=UA-313498-1&_gid=743993530.1523791954&_r=1&z=1891371743","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dptr.areyouahuman.com/dptr?dpn=adobe&dpi=%5BPARTNER_USER_ID%5D&aoc=d3427dff-e86a-4268-a13d-dbd731c5921d&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D58051%26dpuuid%3Dd3427dff-e86a-4268-a13d-dbd731c5921d","request_type":"text"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://connect.facebook.net/en_US/fbevents.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1523791949824&yhlClientVer=3.42.4&yhlRnd=ay2hUpwDmCHhdQPV&yhlCompressed=0","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://sjs.bizographics.com/insight.min.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://dpm.demdex.net/ibs:dpid=139200&dpuuid=3aRbLDlTRaCBObjGc-4glA&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://tags.bluekai.com/site/35702?id=39041E2B94ED6EF00CB315F995BE6F73","request_type":"other"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/css/2014/layout/layout2015.css?v=jd201802175619","request_type":"css"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mjs.sinaimg.cn/wap/project/homev8/8.2.83/homev8/homev8.min.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/nn/lib/metro/g/myy/advance_sm_0.0.56.css","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=openx.com&id=b0942bfb-cb27-cfc7-13fc-b8e5a397b3df","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://level3.cedexis-test.com/img/17652/r20.gif?rnd=0-1-13960-0-0-17652-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A2215%2C%22netDns%22%3A0%2C%22netTcp%22%3A955%2C%22srv%22%3A514%2C%22dom%22%3A4921%2C%22loadEvent%22%3A15396%7D&et=87&ja=0&ln=en-us&lo=0&rnd=984689438&si=6bcd52f51e9b3dce32bec4a3997715ac&v=1.2.30&lv=1","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://pixel.mathtag.com/sync/img?redir=https:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dmediamath%26mmuuid%3D%5BMM_UUID%5D","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/2012indexBg.gif","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=49191&dpuuid=1261453737550","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/bloomberg-logo.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/murksnow/albumset/7387793/zoomcrop/75x75.jpg?v=1523437696","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://t2.focus-img.cn/sh340x226sh/esf/2018-01-11/05733fcdc6ac4e4eadd9c327b20987cc.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/9bifoOJ8M_y35VWf_46xDZ8duvOfNHeHcQbNhss6sx7_-cUKG7zWSaYH4lfS=d","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/images/mobile/mobile_sprite_x2-266880991._V_.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/newicons/favicon-32x32.png","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/3eea0440-5294-487f-ab20-ee15aadd181c_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/ee0ebeaf-2503-48ee-80e5-627ad98304f8_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://imageproxy.pimg.tw/zoomcrop?width=75&height=75&url=http%3A%2F%2Fpimg.pixnet.tv%2Fuser%2Fsukioooru%2F708131171%2Fbg_000000%2F75x75%2Fdefault.jpg%3Fv%3D1523786092","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180413112751-comey-trump-book-2-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20151222_150x50.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://production.mtm-cdn.com/filmer/archives/922/5551/13.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/vPkF1bFVwpjpBNTDEpU5yA/009/338/951/320x240.c.jpg.v1523607361","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/de-certifiedrefurbished/2017/Public-Launch/1076789_de_certified_refurbished_renewed_11-10-2017_GW_MobileBillboard_1242x450._SX1242_CB512923933_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/pantry/AwarenessCampaigns17/2018/ganeg_2018-03-15T11-00_8bd114_1102919_DE--Amazon-Pantry-Spring_Selection_2018_1242x450._SX1242_CB499147738_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41bQWuQrFXL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://img1.360buyimg.com/da/s720x352_jfs/t19327/15/1590447600/62948/9e917003/5ad055c0N50139675.jpg!cr_1125x549_0_72.dpg.webp","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.adsafeprotected.com/main.17.4.90.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-embedded_app.min-vflYOX20T.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-story/td-applet-viewer-templates-story-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-slideshow/td-applet-viewer-templates-slideshow-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/native.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/fetch/4.1.12/jsonp.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/51chvDI28JL._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset","request_type":"css"}
+{"origin":"http://www.pixnet.net/","request_url":"https://img.scupio.com/html/ad.html?v=1.2.14","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/notifications/render?bnptrigger=%7B%22PartnerId%22%3A%22HomePage%22%2C%22IID%22%3A%22SERP.2000%22%2C%22Attributes%22%3A%7B%22RawRequestURL%22%3A%22%2F%22%7D%7D&IG=2E674091B80D41D497ED8B2E88AE58C9&IID=SERP.2000","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://m.jd.com/index/curtains.json?ts=1523792000385","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMoZDDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHU8HEAkCh-aMUsm8MIvLVSTjLj3A","request_type":"script"}
+{"origin":"http://www.bongacams.com/","request_url":"https://www.google.com/recaptcha/api.js?onload=recaptchaInit&render=explicit&hl=en&t=1523791934","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://log.outbrain.com/loggerServices/widgetGlobalEvent?eT=0&tm=4386&pid=185&sid=185984&wId=569&wRV=01002504&rId=a846f5dd0c5ccc7b4f5261a2c22572b4&idx=0&pvId=a846f5dd0c5ccc7b4f5261a2c22572b4&org=0&pad=0&pVis=0&eIdx=&ab=0&wl=0","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.adobe.com/index.loggedin.json","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/AutoSug/cj,nj/9ea8ead6/c054ef80.js?bu=rms+answers+AutoSuggest+Service%2cWeb%24Utils%2cWeb%24EventRegisterer%2cWeb%24EventRegistration%2cEmpty%2cEmpty%2cEmpty%2cWeb%24WebCore%2cWeb%24DataProvider%2cEmpty%2cEmpty%2cWeb%24Canvas%2cEmpty%2cWeb%24Layout%2cWeb%24SearchForm%2cEmpty%2cEmpty%2cWeb%24PrefixThrottling%2cEmpty%2cEmpty%2cWeb%24DeleteHistorySuggestionHandler%2cWeb%24Init","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768243&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791999082&fs=2&pvid=c6693d7f889bf4ac7b7c822f0e97dff0&cg=a6121978c7f96f7282ccf14f1722e4a8","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://www.youth.cn/","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://token.rubiconproject.com/token?pid=2179&pt=n","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=11vajjGjRK6qvB6r1y476A&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/Fonts/Font-Montserrat.min.css","request_type":"css"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/css/styles.min.css?v=1476060772","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=bidswitch.com&id=30609271d53b707244da9ac7c0671704","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://pixel.quantserve.com/pixel/p-P7x87XHnVfbWr.gif?labels=Campaign.269857,Publisher.156736","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=1467928967&si=48c57cebc84275afcff127cd20c37e4b&v=1.2.30&lv=1&ct=!!&tt=hao123%E5%AF%BC%E8%88%AA-%E4%B8%8A%E7%BD%91%E4%BB%8E%E8%BF%99%E9%87%8C%E5%BC%80%E5%A7%8B&sn=37700","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/g.gif?cna=&spm-cnt=a2g0n.home%2damp.0.0.1523791931973&pre=&aplus&ali_apache_track=&dmtrack_c={ali%5fresin%5ftrace%3dws%5fab%5ftest%3d%7caep%5fusuc%5ff%3d}&hn=ae%2dmsite011133198079%2eus%2eot7&pageid=8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973&s=360x512&viewer=","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://dt.adsafeprotected.com/dt?anId=928108&asId=3e804f8a-8ce8-5c2f-4eaf-599092bc7429&tv={c:9OXVrC,pingTime:-10,time:6815,type:s,mvn:ZnNjPTExLHNkPTMsbm89Nyxhc3A9MQ--,fsc:17.4.72v220002022020220000022002222000022220202020222200222220002222022022222200002220222022222222222000220200220002220222220222222222222202222222222222222222222222222222222222200000022022020020000002002202022022022222222000000000022222202022022222000000020000000000000000000220002220000022200222202220022200200222022202220222222220020222202000220000222202222202222000002002002222222222220022202200222002222222202,sd:MTcuNC43MnY1MTJ8fDM2MHx8MXx8MXx8MjR8fDUxMnx8MHx8MHx8MXx8cG9ydHJhaXQtcHJpbWFyeXx8MjR8fHx8fHwxfHwzNjA-,no:MTcuNC43MnZNb3ppbGxhfHxOZXRzY2FwZXx8bnx8Mnx8bnx8MXx8bnx8TGludXggeDg2XzY0fHxHZWNrb3x8MjAwMzAxMDd8fDQyMHx8TW96aWxsYS81LjAgKExpbnV4OyBBbmRyb2lkIDYuMC4xOyBNb3RvIEcgKDQpIEJ1aWxkL01QSjI0LjEzOS02NCkgQXBwbGVXZWJLaXQvNTM3LjM2IChLSFRNTCwgbGlrZSBHZWNrbykgQ2hyb21lLzU4LjAuMzAyOS44MSBNb2JpbGUgU2FmYXJpLzUzNy4zNiBQVFNULzE4MDQwNi4xMzA0Mjh8fDF8fDF8fEdvb2dsZSBJbmMufHxu,asp:1523791894455||0073d09b84bec50f18fa99cd7b6d3481||700df66f90284f988d5d4a7a24373a5f||7d55e215cef1207acd9f9afd5519c59e||9e6a0d715a8a63c2855218d1424985d1||01e48e2f43cb14b970ff382748539d74||0e2ff110253fa8d69d35c3b048a2687e||b0a6fdfa6a96151d290fe524cd219acc||1520626246}","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://hwcdnssl.cedexis-test.com/img/r20.gif?rnd=1-1-13960-0-0-17000-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/user-lists/971301452/?random=1523791867108&cv=9&fst=1523790000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&fmt=3&cdct=2&is_vtc=1&random=20415082&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hopeyear/albumset/15082419/zoomcrop/75x75.jpg?v=1297725272","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/assets/img/logos/espnplus/ePlus.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"http://www.sohu.com/","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/AB/F088BA.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/310/w710h400/20180415/QHgb-fzcyxmu7631566.jpg/w710h400z1l50t1902.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/88/68/ab/8868ab5f501fec03bb189a4e4d76b0df/8868ab5f501fec03bb189a4e4d76b0df.23.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180415033653-01-beyonce-coachella-0415-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/c2/36/06/c23606226ed06f8f2af7a85703b18dc4/c23606226ed06f8f2af7a85703b18dc4.21.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5506000/5506765/220x165/12.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/Gateway/Mobile/COM._SX870_CB273074709_.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/51EXPF5yQOL.jpg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://inews.gtimg.com/newsapp_ls/0/3274141701_640330/0?tp=webp","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://310987714.log.optimizely.com/event?a=310987714&d=310987714&y=false&src=js&s310954789=none&s311043393=true&s311047346=gc&s311052307=direct&s793783561=true&s806111078=none&s806950111=mobile&tsent=1523792026.106&n=http%3A%2F%2Fwww.espn.com%2F&u=oeu1523792025971r0.47098347521900563&wxhr=true&time=1523792026.106&f=8448890495,9262875135,9263073801,8792134866,8483651062&g=&cx2=6284c1d5","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-coreui-forms.min-vflL9ha6v.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://fonts.googleapis.com/css?family=Open+Sans:300,400&subset=latin,latin-ext","request_type":"css"}
+{"origin":"http://www.coccoc.com/","request_url":"https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-35860610-14&cid=1265310549.1523791856&jid=1172235258&gjid=1611549489&_gid=1916280616.1523791856&_u=IGBAgAAB~&z=1214592548","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://bttrack.com/pixel/cookiesync?source=6f15a88d-e42c-4017-8276-dff2b21d7926&secure=1","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=11&ct=1523791833&rver=6.0.5286.0&wp=MBI&wreply=https:%2F%2fwww.bing.com%2Fsecure%2FPassport.aspx%3Fpopup%3D1%26ssl%3D1&lc=1033&id=264960&checkda=1","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://odr.mookie1.com/t/v2?tagid=V2_393725&AMAZON_REGION_SPECIFIC_ENDPOINT=aax-eu.amazon-adsystem.com/s&src.visitorID=sieRdeQEQ1K-H7G332GC4w","request_type":"text"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/images/Pasted5.svg","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://cdn.taboola.com/libtrc/msn-home-network/loader.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/FWCIMAssets.8fb36ba62a66c4e98b199c5edf2a05ccceadd1f1._V2_.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync.ipredictive.com/d/sync/cookie/generic?https://dpm.demdex.net/ibs:dpid=2340&dpuuid=${ADELPHIC_CUID}","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://p.rfihub.com/cm?in=1&pub=7085","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://pub.pxl.ace.advertising.com/cfcm.ashx?providerId=1008&extMatch=1&rcode=1","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=41EqZTuPQ8CtigNwg-5W9A&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/wss/fonts?families=SF+Pro,v1|SF+Pro+Icons,v1","request_type":"css"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cdn.aralego.net/css/dev/ucfad-formats.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=74&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A74%7D&logFlag=uaction_1523791857874&t=1523791931876","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d22199766.gif?sz=3&rnd=913930272&ts=1523791836&sz=3","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=6835&dpuuid=UPab98c1d4-40a0-11e8-aa25-06b4b18950f6","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/microsoft-word-preview-android.png:l","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/browser-theme/oklogo.png","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/imgbin/mobile-inverted_phone-set-vhigh-vflX17Zn4.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/tenyears/10.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/topic-spotlight-flip-left.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/EVaQo9gv2ko6xNWFWPFO8DKv-3RqK8J4g0yDcI0P3-hmf-uLSsYOMvRGqicF=w384","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t013513ef4a86e91ef7.png","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/images/mobile/mobile_sprite-2129284076._V_.png","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/images/mobile/imdb-logo-responsive@2-868559777._CB499603820_.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/pic/index_hotnews_next.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://counter.yadro.ru/hit;mail-splash/touch?r;uhttp%3A%2F%2Fm.mail.ru%2f;","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"http://www.aliexpress.com/","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/ape/sf/mobile/msf-1.19._V497204134_.html","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/bhri8yZJq7OO_lsAf2LV2g/009/333/238/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/29/466100.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33052074","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/022/22d/0e8/big_lq/2e2c44b6b4d762901b4fdbe895f70fa3.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/38/4a/d5/384ad50d6cca4def1685ea76e920ac05/384ad50d6cca4def1685ea76e920ac05.2.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTEzNzY0OTg0NTdeQTJeQWpwZ15BbWU4MDU3OTg3MjUz._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTYwMTI2NTc0OV5BMl5BanBnXkFtZTgwMDMwODgyNTM@._CR9,52,1991,1491_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/xrn0ksO3FN72PBJ_sbpgm9f3cxDTsvo5U6pJTxeiqDo.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41BMyAk8duL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/a3deea18-f50a-45cd-8345-76503f76461b/scale-to-height-down/100","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D","request_type":"text"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D","request_type":"text"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico?v=4f32ecc8f43d","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/straight.svg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://tpc.googlesyndication.com/sodar/V6zvOIoD.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://ssl.gstatic.com/accounts/o/3723580519-idpiframe.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_194.js?v=195","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-regular.woff2","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-54d24ba23337620019760100.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/34991b7ef71f70aea175b18646183b7c.js?conditionId0=380088","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.adobe.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100240376&apid=beans_12293&impid=04bb09941b49aeb22_0_0&at=1&mkey=04bb09941b49aeb22_0_0&latcy=5592&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=6628.453125&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DRK9vKEBy6q2ymoAS2yZ8NgFLoISM8SkXcNIWK%2BtzRaWmW%2FIrh6lDq%2BE5pCBwa5KqOX5elCQkEgix3Kl5xyIajVagkozbEsrXd6rx4%2BJcmiMWfsFMze%2BrZxOS9DjJsPyVitOZHUZnaXBFLHenZwbvFHNK5sLZKZQo%2B2I91WV5t8zreXq03shu5k4dZ2ZCUbvP9%2BvzdyUGbYaBL9j8fXS9TV8xiwcbugC2XNvHWmyeNoKZIrKhE%2Fs1snIfIp3snPXiZRVH0h6uevcyhrljS4Z2hpbJro8A6gXef8MZSI4OInvHu1HH1q9YyFp%2B5FIEizzIbFn%2BuU4jFeo36pvpOAqUU0WpPk9iUsQhD4B3KIRORZv%2BU7n%2FcG56lgWvIUYXNyiweJ6CemriMcwzYVz%2BJxCF9onRPTrhiPGc%2F4rCywKKsB%2BaQ4ClX%2FWPWrGWgeDDWFbZPiF%2Fc8ttKjOZ3R0uPB58QLLffWG2%2BjxSeWWx1wHliRYTjX5f5ebdyEcVGd7ELpzpf3Wjz3iRb8cIDBWUZHktxDuwvdgPOUtxh3mvKy9Zm0Xs5Tq5rGGCGgKgyBdHu8tgxjK5kK7%2FzpV%2B9kKhQbx7UgwZAzmuX6p9ik8NHW64%2FxI%3D%09tt2%3D1523791943594%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=7426429097246&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791943886","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://ad.mail.ru/adi/100590?rnd=107581893","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://login.live.com/me.srf?wa=wsignin1.0&wreply=https%3A%2F%2Fwww.microsoft.com&uaid=a73f36b2-7e62-45a8-0729-ca27c0d18f51&partnerId=mshomepage","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938258_4338749486994&itemspaceid=12291&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938258&plateid=1001300000,1001200000","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25","request_type":"html"}
+{"origin":"http://www.linkedin.com/","request_url":"https://platform.linkedin.com/js/px.js?ch=2","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.linkedin.com/lite/platformtelemetry","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ad.doubleclick.net/ddm/trackimpj/N265001.2005704YIELDMO/B20961954.218069769;dc_trk_aid=416623175;dc_trk_cid=92161433;kw=764344014241209959-1918292139302716419;ord=4710690767369208835;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=","request_type":"script"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.krxd.net/controltag?confid=ITb_4eqO","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/hao123_api/osc/tasks?uri=%2F","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://d.agkn.com/pixel/8198/?che=1523791874&sk=164751602661000505378&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164751602661000505378&ex=neustar.biz","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner_id=cb276571-e0d9-4438-9fd4-80a1ff034b01&puid=WtM4BQAAAGWhsjF0&_test=WtM4BQAAAGWhsjF0","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/c/index-44722c.css","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://us-u.openx.net/w/1.0/sd?cc=1&id=537073026&val=WtM35B__DJPpGsQgT1fYqPHA&r=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fcm%3Fid%3D19b05a3b-50b2-33ac-c6e0-9f21c5fbd143%26r%3Dhttps%253A%252F%252Faorta.clickagy.com%252Fpixel.gif%253Fch%253D4%2526cm%253D","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsuAO-zqcR9p0Ig6q6zkCJAKEWVeiQgzuLS4MXGfnh8x6OGlOW0rc_pBeyOa8mp1jpNWhGWS1M0DtnXFfiGbATAbzLvQ_prPYtI&sig=Cg0ArKJSzMHoCb5LMEjREAE&id=osdim&ti=1&adk=1062120734&tt=1438&bs=360,512&mtos=1032,1032,1032,1032,1032&tos=1032,0,0,0,0&p=330,20,430,340&mcvt=1032&rs=3&ht=0&tfs=408&tls=1440&mc=1&lte=1&bas=0&bac=0&avms=geo&bos=360,512&ps=360,7646&ss=360,512&pt=3&deb=1-1-1-18-14-97-19-12&tvt=1350&op=1&r=v&uc=19&tgt=DIV&cl=1&cec=5&clc=1&cac=0&cd=320x100&v=r20180411","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.summerhamster.com/bcn?fe=1523791897075&y=2.0.980&elg=913831702&flg=328&x=zzz.fqq.frp%2F&vqwo=1&deo=0&g0=vg%3A%3Aer%2Cxd%3A%3Aqexd%3A%3Aqsu%7Cvg%3A%3Ask%3A%3Aqsk%3A%3Aqsu%7Clq%3A%3Adm%2Clp%2Clqi%2Cqh%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2F0914.joredo.vvo.idvwob.qhw%2Fdg2%2Flpj%2Fa.jli%3Ffe%3D1523791865018%7Clq%3A%3Adm%2Clqi%2Cqh%2Cvf%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2F0914.joredo.vvo.idvwob.qhw%2Fdg2%2Fvfulsw%2Fa.mv%3Ffe%3D1523791865025%7Clq%3A%3Adm%2Clqi%2Cqh%2Cvf%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2Ffgq3.rswlplchob.frp%2Fmv%2Fjhr2.mv%3Ffe%3D1523791865131%7Cgisl%3A%3Alp%2Clqi%2Cqh%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2Fdg.grxeohfolfn.qhw%2Fggp%2Fdg%2Fsxcjahiwasb%2Frczx%2Fpuwmpihtb%2Fcnpxellln%2F%3Brug%3D1523791865134%3F%7Cjdg%3A%3Aho%2Ckl%2Cklg%2Clqi%3A%3Aqhk%3A%3Aqsu%3A%3Avho%3D.sodlqDg%7Cjdg%3A%3Akl%2Clp%2Clqi%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2F0914.joredo.vvo.idvwob.qhw%2Fdg2%2Flpj%2Fa.jli%3Ffe%3D1523791865145%7Cjdg%3A%3Aho%2Ckl%2Cklg%2Clqi%3A%3Aqhk%3A%3Aqsu%3A%3Avho%3D.sodlqDg%7Cddg%2Cjdg%3A%3Aho%2Ckl%2Cklg%2Clqi%3A%3Aqhk%3A%3Aqsu%3A%3Avho%3D.des_re_halvw&hu=0&g2=0%3A%3A0%3A%3A0%3A%3A0%3A%3A0","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3D49NGBMVT1ABRN6GGR916%26ctb%3D1%26m%3D1%26sc%3D49NGBMVT1ABRN6GGR916%26pc%3D14271%26at%3D14272%26t%3D1523792001117%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D49NGBMVT1ABRN6GGR916%26aftb%3D1:14273","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://pub.pxl.ace.advertising.com/cfcm.ashx?providerId=1008&extMatch=1&rcode=1&ctst=1","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20131115zhang.gif","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&time=1523791866209&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fcoccoc.com%2F&random_number=3950776410&sess_cookie=17538980162c912a95f06ba420e&sess_cookie_flag=1&user_cookie=17538980162c912a95f06ba420e&user_cookie_flag=1&dynamic=true&domain=coccoc.com&account=/MRDh1aAod00OU&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/top.png","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/images/touch-icon-iphone.png?cache=2018041212","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/bundles/base/sprite_core_2x.png/9cb60114e6c0.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_15697&impid=&at=1&mkey=&latcy=5132&freq=&turn=2&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=6545335216854&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&_time_=1523791943701","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s220x220_jfs/t5725/339/9007878255/424280/8c083797/59819709Nd61baf4e.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://img.cdn.nimg.jp/s/niconews/articles/images/3435543/f4e0a8ce8a09a8bbe0d6c55cab9d1c2a5851dc516cda914656418bf1f53b7a82a3c81df2fb332c22b2a3bf6c84f43be0e45ec7c9aefa4547184d67331c78e1b4/110x110s_FFFFFFFF?key=055843bc208fc8f5ba17549c11c347f1a68625b05497ab22cce7925ea9cc52a6","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180415094235-damon-refugee-camp-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://oimagec1.ydstatic.com/image?id=1163318208763300816&product=adpublish&w=640&h=384&sc=0&rm=2&gsb=0&gsbd=60","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/img/uploader/pickupselection/0415_1_d.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/B3IAAOSwMPxaurDS/s-l500.webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/640323cb-cb09-4def-907d-71e29e636342/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://smetrics.cnn.com/b/ss/cnn-adbp-domestic/1/H.26.1/s12549212069593?AQB=1&pccr=true&vidn=2D699BFD851D2AAF-600001710000D60D&&ndh=1&t=15%2F3%2F2018%204%3A31%3A4%200%20420&fid=4BEA7D18C905084D-3799DBF4B8681903&ce=UTF-8&ns=cnn&pageName=cnn%3Ain%3A%2F&g=https%3A%2F%2Fwww.cnn.com%2F&cc=USD&ch=cnn%20homepage&server=cnn.com&events=event26&c5=nvs&v5=D%3Dc5&c8=new%3A1&v8=D%3Dc8&c9=nvs&v9=D%3Dc9&c13=section&v13=D%3Dc13&v15=0853&c17=anonymous&v17=D%3Dc17&v22=0&c26=www.cnn.com%2F&v26=D%3DpageName&v27=D%3Dch&c28=cnn%20homepage%3Anvs&v28=D%3Dc28&v29=cnn.com&c30=cnn%20domestic&v30=D%3Dc30&c32=adbp%3Aindex&v32=D%3Dc32&c33=adbp%3Anone&v33=D%3Dc33&c35=cnn.24.1-0-0.20180329%3A0&v35=D%3Dc35&c37=smartphone&v37=D%3Dc37&c46=1523791858448543148946430&v46=D%3Dc46&c56=portrait&v56=D%3Dc56&c57=no%20mvpd%20set&v57=D%3Dc57&c59=no%20mvpd%20set&v59=D%3Dc59&c64=cnn%20news&v64=D%3Dc64&c65=nvs&c75=nvs&v75=D%3Dc75&h1=news%7Ccnn%7Ccnn%20domestic%7Ccnn.com%7Ccnn%20homepage%7Ccnn%20homepage%3Anvs&l1=D%3Dc65&l2=&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"text"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/ads.min.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51chvDI28JL._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset","request_type":"css"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/i18n-min/1522745649/en.js","request_type":"script"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.youth.cn/","request_url":"http://cm.g.doubleclick.net/pixel?google_nid=baidu&google_cm=&google_tc=","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fcmatch.google.com/pixel?google_gm=AMnCDoqu-LJCT5yKgmmb5mHt74bOwaR_tx2ICRv7rHnBu4I6HBp-8XiBDK7oDy74NJhrxPT1lk58hoJnpYtXWvWO0NQAOfsrLfRDUdgDeq2I2GVkoupgoM0","request_type":"html"}
+{"origin":"http://www.twitter.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEA5nVynmckb3Gl3lxhei%2BVGiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://idsync.rlcdn.com/395886.gif?partner_uid=5978151418385522803&redirect=1","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cnn.bounceexchange.com/bounce/init1.js?tojQ=function&cts=1523791876292&tzo=420&is_preview=false&website_id=340&resolution=360x512&referrer=&is_google_pla=0&calling_url=https%3A%2F%2Fwww.cnn.com%2F&visit_cookie=%7B%22lp%22%3A%22https%253A%252F%252Fwww.cnn.com%252F%22%2C%22r%22%3A%22%22%7D&cookie=%7B%22v%22%3A%7B%22completed_signup%22%3Afalse%7D%2C%22sid%22%3A1%7D&vars[desktop_ad_visible]=false&vars[mobile_ad_visible]=false&vars[article_page]=false&vars[home_or_section_page]=true&vars[flagship_domain]=true&vars[video_playing_and_large]=0&vars[video_playing_in_rail]=0&vars[video_playing_and_visible]=0&vars[money_article_page]=false&vars[section_name]=homepage&vars[tos]=true&vars[completed_signup]=false&vars[dfp_exclusion]=false&vars[dfp_rblock]=allow&vars[video_playing]=false&vars[breaking_news_present]=false&vars[money_section_page]=false&vars[max_overlays_reached]=false&vars[spa_event_emitter]=false&cookie_too_large=false&bp=0&pts=","request_type":"script"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/node-scroll-info/node-scroll-info-min.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/81pPtFtJAnL.js?AUIClients/GoldboxUDPAssets","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://www.diply.com/","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/UH6TUt9n?redir=https%3A%2F%2Fib.adnxs.com%2Fsetuid%3Fentity%3D158%26code%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.office.com/","request_url":"https://statics-uhf-wus.akamaized.net/statics/override.css?c=1","request_type":"css"}
+{"origin":"http://www.wikia.com/","request_url":"https://loadm.exelator.com/load?_kdpid=e4942ff0-4070-4896-a7ef-e6a5a30ce9f9&buid=L6N7iig7&p=204&g=270&j=0&xl8blockcheck=1","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D49NGBMVT1ABRN6GGR916%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D12745%26pc0%3D12745%26ld0%3D12745%26t0%3D1523791999590%26csmtags%3Daui%3Asw%3Aunregister%3Asupported%7Caui%3Asw%3Aunregister%3Aunsupported%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D49NGBMVT1ABRN6GGR916%26aftb%3D1:12745","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/pictures/aw/pics/s_1x2.gif","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://tags.bluekai.com/site/20931?id=fa49bdb775fb67ef652fba4559e55606","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.facebook.com/images/spacer.gif?5276946464253758","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://mc.yandex.ru/webvisor/24497819?wv-type=1&page-url=http%3A%2F%2Fcoccoc.com%2F&wv-hit=1047608455&browser-info=ti%3A7%3Az%3A-420%3Ai%3A20180415043108%3Apct%3Atext%2Fhtml%3Bcharset%3Dutf-8%3Ast%3A1523791870%3Au%3A1523791868847094136","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://ds.reson8.com/insights.gif?rand=405939413&t=0&pixt=resonate&advkey=0010M00001RV2QuQAL&opptykey=MASW0517A&evkey=163211&evtype=custom","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/facebook-lite-android.png:l","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/smart_search/search_icon_32.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p9.qhmsg.com/t01ac094f0e7138f4c1.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/nav/left.png?1372079637","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/input/members/right.png?1372079638","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-dc-esh-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/4a/34/d0/4a34d0afe478ef6768dab0795f079853/4a34d0afe478ef6768dab0795f079853.3.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/8f/ee/d9/8feed9eed67616d5855bc24c091e1005/8feed9eed67616d5855bc24c091e1005.3.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img18/Watches/April/WRS/GW_blackjack_billboard_1242x450-WomenWatches._SX414_CB497220605_.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/img/uploader/pickupselection/sp_180415_isekai.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/51D8NXwQfvL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/img/favicon64.ico","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/pingjs/ext2020/xw-next/_next/8a6265c0-8cc2-4bd6-9b10-557557ae7372/page/index.js","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/js/5bac963c.page.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_3&relatedID=&news=0_0&SUV=null&_time_=15237919473344873046786082","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/b9pj45k4?redir=https%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=UpbDBTBMvJcZ&ex=pulsepoint.com&&ev=&pid=557477","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=index&id=E4EPc4H4q1pwUnQBtrtuNTdzc2o4ZgAC","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://d.agkn.com/pixel/2387/?ct=US&st=CA&city=13358&dma=197&zp=&bw=4&che=2354632686&col=20912526,2920918,217082534,416280703,67442974","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://ib.adnxs.com/pxj?bidder=140&seg=381342&action=setuid(%27L6N7iig7%27)&bust=1523791989","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d22199461.gif?sz=4&rnd=152218038&ts=1523791836&sz=4","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=2005658453&t=pageview&_s=1&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ul=en-us&de=windows-1252&dt=Dropbox&sd=24-bit&sr=360x512&vp=&je=0&_u=aGBAgUAj~&jid=194842542&gjid=457813373&cid=10481343.1523791867&tid=UA-279179-2&_gid=1131671526.1523791867&gtm=G46K8WT2R&cd47=en&z=2007395603","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/videoder-android.png:l","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/images/ico/favicon-192.png/b407fa101800.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/youxi20170914icon.png","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-01a49470266a51f632dab1aef2fc09112d280c1e._V2_.png","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/CZEPHeUjGNXx7yGwzO8guA/009/341/408/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/018/051/2e4/big_lq/e7337263ecc182a5e8f885c1637ac5e1.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420347574455947.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_elt6J_CldErWcybS4I3v2A&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/x9otm3yAhJSuztAcnYkx_g/009/342/493/320x240.c.jpg.v1523661725","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/swiper.min.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/mtb/lib-smb-wake/0.0.42/??ui-tbBanner.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalfooter/3/en_US/scripts/ac-globalfooter.built.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/d57a027c/Areas/Home/Content/js/build/bundles/unauth-vendor.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/a8eabdcf/Areas/Home/Content/js/build/bundles/unauth.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://widgets.outbrain.com/nanoWidget/01002504/module/swipeLayout.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://m.media-amazon.com/images/G/01/csm/showads.v2.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://sstats.adobe.com/b/ss/adbadobenonacdcprod/10/JS-2.5.0-D7QN/s15574495103820?AQB=1&ndh=1&pf=1&callback=s_c_il[4].doPostbacks&et=1&t=15%2F3%2F2018%204%3A33%3A41%200%20420&d.&nsid=0&jsonv=1&.d&sdid=52ED17672A35D87F-5AEFE73070D3C67A&D=D%3D&mid=91347194757900030554314852707948543921&aid=2D699C4005031F55-600011820000562A&aamlh=9&ce=UTF-8&cdp=2&fpCookieDomainPeriods=2&pageName=adobe.com&g=https%3A%2F%2Fwww.adobe.com%2F&v73=1699375031091421.100&pe=lnk_o&pev2=Clicktale%20ID&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&AQE=1","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=rubicon&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.netflix.com/","request_url":"https://adservice.google.com/ddm/fls/i/src=4954221;type=gl-cs;cat=dcmgl0;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=2487956173460.919;_dc_1=1;~oref=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Df1fdc59c-9452-4167-a583-cc8ede9a2929","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsvV_4U6dkn9nnJVs97dG4uZqiZ6OVVr4JpngYGn2jhJ3pozEqlW7lYutWumAkHuPq0IwJMZpCG3TMFIWFU7w69J3WCetL7fTAJDk1_XdjcBvJYtVwCqWVbMTqo5v-vMA1WgslrmIHfXMBPn4FAiToTYTgiWAS1UYCb91_Nwq-iiG-vlhrcornA5MdkN6TOHofIAwNnXzsXa9f5TqFdNUNFygf1eloaAdJFzXjQkRFn20pAGhr3mH3Ebisku72b6&sig=Cg0ArKJSzEIeR0iyIo_OEAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/gen_204?atyp=csi&ei=xjfTWv2tGevT0gLU_p24CQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.445,dcl.453,iml.445,ol.2733,prt.242,xjs.1605,xjsee.1605,xjses.1351,xjsls.234,wsrt.2208,cst.715,dnst.0,rqst.855,rspt.467,sslt.387,rqstt.1737,unt.2140,cstt.1017,dit.2661&zx=1523791817449","request_type":"html"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/gen_204?atyp=csi&ei=_jfTWubELYmh0wKW3pXgBw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.456,dcl.449,iml.456,ol.2727,prt.238,xjs.1586,xjsee.1586,xjses.1331,xjsls.222,wsrt.2153,cst.703,dnst.0,rqst.834,rspt.447,sslt.378,rqstt.1695,unt.2091,cstt.991,dit.2602&zx=1523791873769","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://interface.sina.cn/wap_api/ls/wap_ls_card_data_api.d.json?callback=jsonp_05767429240400075&timestamp=1523791845339&id=10000&card=video,games,travel,book,shehui&nopic=0&page=0","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://ads.yahoo.com/cms/v1?esig=1~6772d6d12bf5fd5c41ee5ef107d84db09124942a&nwid=10000936839&sigv=1","request_type":"text"}
+{"origin":"http://www.amazon.com/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__","request_type":"html"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.google.com.hk/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.google.com.ua/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://www.google-analytics.com/gtm/js?id=GTM-M6BDP4F&cid=541858476.1523791959","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/arraylist/arraylist-min.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://ad.mail.ru/adq/?q=3334&q=152408&q=163851&callback=__jsonp_0&_=1524554559940","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://unid.go.com/v3/hit","request_type":"other"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/Shared/stacks.css?v=5a9c7c94db05","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=index&id=E4EPr4H4q1pwUnsoZnVuNTcccJI4ZgIC","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=3adcc5bc01b02ab83256","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=49276&dpuuid=3fd16658-b19f-4ce4-84f5-60b78f007eb9","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://m.baidu.com/static/index/plus/plus_logo.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hjcceko77826/albumset/7410800/zoomcrop/75x75.jpg?v=1523785650","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://a.tribalfusion.com/z/i.match?p=b11&redirect=https%3A//simage2.pubmatic.com/AdServer/Pug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTMzMjYmdGw9MTI5NjAw%26piggybackCookie%3D%24TF_USER_ID_ENC%24&u=${PUBMATIC_UID}","request_type":"html"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/18/e4/19/18e4195fa7a8b532e2346c586786b4d6/18e4195fa7a8b532e2346c586786b4d6.29.jpg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1WUwM?ver=6a54&q=90&m=6&h=276&w=494&b=%23FFFFFFFF&l=f&o=t&aim=true","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTc3Nzc3OTgxMl5BMl5BanBnXkFtZTgwNzgzNzk2MjI@._V1_UX184_CR0%2C0%2C184%2C274_AL_.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/log","request_type":"text"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/tubepornclassic.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://tag.bounceexchange.com/340/i.js","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://myashot.txxx.com/txxx_pass/vanload6.1.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/xtemplate/4.0.11/runtime.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://www.hao123.com/api/searchrecom?c=B0D85202A91BCAC471DDDAE647334BC6&type=wise&dataType=rs&pageid=index_cxv2&cue=1&qnum=15&sid=10001&u_query=&_=1523791989030&callback=jsonp1","request_type":"html"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/js/trustguard.js?1443008335","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://securepubads.g.doubleclick.net/pagead/adview?ai=C5M76ADjTWvDpEoXckwOm3Zf4A4TWkINR5_j9_JsH6b_VfBABIJrd5B9gyfb4hoCAoBmgAbDT5JcDyAEG4AIAqAMByAMCqgSsAU_Qzpyf_qR18-3jeypZWvaPmAjyreYwLpUk9sEm9oV6i6l1MkHFhtocQCovx0TwEVC2kCr5_Uj7iH8sBhFxcrTTE8H6BconYlCV62P0MLnF4YRuNanI1_8u253CfB9-kp8Z7v8ic1mn6er0C8KsgZ4T5JcWBqZZAVwzbMsVZqcZTkYeVeSz7jZdsID4Rnj0Dq4witIMdQ59XXOAuT2Nj9gec503DAetPo8MqS3ABLjGkbLTAeAEAYgFkPTB6gOSBQQIBBgBkgUECAUYBKAGN9gGAoAHuKybaKgHjs4bqAfVyRuoB6a-G9gHAfIHBBD2niOgCM3zPbAIAtIIBwiAYRABGAGACgPYEwKCFAkaB2Nubi5jb20&sigh=Ac5LKXGwZrg&template_id=492","request_type":"html"}
+{"origin":"http://www.uptodown.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/activeview/osd_listener.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/2.75.8/js/cnn-footer-lib.min.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/518e5yqTyZL.js?AUIClients/RetailSearchAutocompleteAssets","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61WZygn8wbL.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,513EDHaa7SL.js,11sT42sZnQL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61x-Yxr2raL.js,318CMPRminL.js,11dYToHZZ0L.js,21TDqwIsfQL.js,01qkmZhGmAL.js,012YXvM7lUL.js_.js?AUIClients/AmazonUI","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/css/mobile-64892.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/nn/lib/metro/g/myy/polyvore_0.0.3.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=26&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A26%7D&logFlag=uaction_1523791857874&t=1523791883876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=8&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A8%7D&logFlag=uaction_1523791857874&t=1523791865876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=96&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A96%7D&logFlag=uaction_1523791857874&t=1523791953876","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:144-4203505-1964949:XZ4D3PPDB36HTEGXD7ZH$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F144-4203505-1964949%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DXZ4D3PPDB36HTEGXD7ZH%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D10345%26pc0%3D10348%26ld0%3D10348%26t0%3D1523791920892%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DXZ4D3PPDB36HTEGXD7ZH%26aftb%3D1:10348","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://www.facebook.com/impression.php/f1d11f898c2a924/?api_key=532160876956612&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/assets/img/icons/shim2.gif","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/img/crtv/2018/03/bui/6d71994b73e870e8e587dc258dc56c5c.gif","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/AB/01FF8B.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_travel.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1HWNORFXXXXciaXXXXXXXXXXX-800-140.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/18/D34F7A.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/product/core/core_ui_mobile@2x-vflEs81im.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/170220151024-electrical-storm-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/01a/2e2/23d/big_lq/4ee00fceda7c7f0ac3b73bc8af032f44.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/432ad11dfbb361873ba16279d0cef025_erotic_445x250.jpg?cno=9639","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/ac/3c/61/ac3c616c697186e973f014279ada9c89/ac3c616c697186e973f014279ada9c89.11.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/de-certifiedrefurbished/2017/Public-Launch/1076789_de_certified_refurbished_renewed_11-10-2017_GW_MobileBillboard_1242x450._SX414_CB512923933_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/BaMAAOSwhiZacUpY/s-l225.webp","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t019f1f167f77a44b26.webp?size=410x247","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D","request_type":"text"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/images/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-lightit.woff2","request_type":"font"}
+{"origin":"http://www.taobao.com/","request_url":"https://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.csdn.net/","request_url":"https://shared.ydstatic.com/js/yadk/1.1.2.js","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/scripts/boot.worldwide.1.narrow.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ads/advertising/ads._TTH_.js?cachebust=52287364","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMTQmdGw9MTI5NjAw&piggybackCookie=hrDlS9cgOn","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=xaxis_dmp&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6&google_hm=MTE0NTg5MTY2NzM3MjgyMjY0OTQ","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://www.yahoo.co.jp/","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=a1&ds=AMP&aip&_s=1&dt=Global%20Online%20Shopping%20for%20Apparel%2C%20Phones%2C%20Computers%2C%20Electronics%2C%20Fashion%20and%20more%20on%20Aliexpress&sr=360x512&_utmht=1523791939928&cid=amp-50XQcMshov1NQ7I2bYC0LQ&tid=UA-17640202-1&dl=https%3A%2F%2Fm.aliexpress.com%2F%3Ftracelog%3Dwwwhome2mobilesitehome&dr=&sd=24&ul=en-us&de=UTF-8&t=pageview&jid=0.9569944429846904&_r=1&a=8054&z=0.25131427119327143","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100289895&apid=beans_12421&impid=02122ccf5b115e28a_0_0&at=1&mkey=02122ccf5b115e28a_0_0&latcy=2886&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=5974.109375&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DiRhLXDWfNYFtVbdJo3XRhlbt6AmPdOBxovzUNwtlS4bQFW3msvaZXbq8e2C5Ns7f66PTnk2N5Jjj7gUx0PWhCGyJw%2BdbWkeUXJx3Lecb6R7WMgIoor9p%2Far29YA30rREvzngjFoUyXF%2BvuAO2SCfHM51UCBh7UUSKZB5nXI6O7qtnHizCQFwYteNdDTuiDTUam7nrLcC6XFC4%2BQ%2FRoCi2agIWxAUD6TvqmMUbSW4mOTdBBo%2FmV4OAzQAI1wFVUaCvRKLusgpLl44gKrcUc4rWcO9DmAsQ1XuDaNxLraYi4Zw5gC1kay%2BilEe%2B7EcmmvZLAEYZuOL5%2BCZE%2FEBQ6u7guxX0SSkSI%2BHqataOHvokPxvs4tTeiovHmYrQRbEV%2BIX40FhQEG88Wl4eOShe9OuVjZTXLmtsJnuaNCM1cmdx%2FPZ5Q0QS%2FcYka7ISTmeK94%2BLkKRbV4YwQcn3jWdThdiO%2Bf6RhLusoU0yzgwuBdKd6cGjTw8qUUZDDHBtl1vpO550Yv5YlQmThcniY1y2EwWZzSFMmQCXZtIlTN1rpBz0NIREopjq8Wg3D68cHM0ScjEzZ0rOg908N1SGOPhU4j7PBbc%2Ftdx3ijLi6f%2Fjp85YEQ%3D%09tt2%3D1523791940732%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=9461904962996&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791941065","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://geo2.adobe.com/json/?callback=ajpRsp&","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://idsync.rlcdn.com/362248.gif?partner_uid=35586261218113811292146848081187597150","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/client/prod/app/header.build.js?_v=71130ad58ee2803ad72f10c3674ccfa2","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://secure.adnxs.com/ttj?id=12753689&size=320x50","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://apis.google.com/js/rpc:shindig_random.js?onload=init","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yo/r/GLJ-byVLnTb.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://us-u.openx.net/w/1.0/sd?id=537073026&val=WtM35B__DJPpGsQgT1fYqPHA&r=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fcm%3Fid%3D19b05a3b-50b2-33ac-c6e0-9f21c5fbd143%26r%3Dhttps%253A%252F%252Faorta.clickagy.com%252Fpixel.gif%253Fch%253D4%2526cm%253D","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?_kuid=L6N7iig7&partner=bluekai&bk_uuid=brCj1ERR99YBU%2BBS","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key=","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=CI7JDs0QodSa&ex=pulsepoint.com&&ev=&pid=557477","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://secure.adnxs.com/getuid?%2fseg%3fadd%3d7920770%26redir%3dhttps%253a%252f%252fgetrockerbox.com%252fpixel.gif%253fadnxs_uid%253d$UID%2526pageReferrer%253dhttps%25253A%25252F%25252Fwordpress.com%25252F%2526action%253dview%2526source%253dwordpress%2526an_seg%253d7920770%2526type%253dimp","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://dt.adsafeprotected.com/dt?anId=928108&asId=3e804f8a-8ce8-5c2f-4eaf-599092bc7429&tv={c:9OXV53,pingTime:-2,time:5416,type:a,sca:{dfp:{df:4,sz:100.100,dom:div},ha1:{res1:1,ps:1,ts:1523791892872,psfr:1}},env:{sf:0,pom:1},rt:1,cb:0,th:0,es:0,sa:1,sc:1,ha:1,fif:1,gm:1,slTimes:{i:0,o:5418,n:0,pp:0,pm:0},slEvents:[{sl:o,t:4789,wc:0.0.360.512,ac:0.0.0.0,am:i,cc:0.0.0.0,piv:0,obst:0,th:0,reas:l,cmps:1,bkn:{piv:[770~0],as:[770~0.0]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:jload,dtt:0,fm:qPhNt7y+11|12|13|14|1511|1512|151311|151312|151313|151314|151315|151316|151317|151318|151319|15131a|15131b|15131c|15131d|15131e|15131f|15131g|15131h|15131i|15131j|15131k|15131l|1514|16|17|18*.928108|181|19.928108|191|1a|1b1|1b21|1b31|1b4|1c|1d|1e1|1e2|1f|1g,idMap:18*,slid:[google_ads_iframe_/8663477/CNN/homepage_0,google_ads_iframe_/8663477/CNN/homepage_0__container__,ad_bnr_atf_01],sinceFw:609,readyFired:true}&br=c","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d9130777.gif?sz=4&rnd=112045273&ts=1523791836&sz=4","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/_td_api/beacon/perf?os=android&rid=9rcrpl9dd6e1s&bucket=900&device=smartphone&site=fp&navT=0&navS=1523791930575&fetS=2336&dluS=976&dluE=976&conS=976&conE=1700&reqS=1703&resS=2321&resE=8526&domL=2357&domI=14784&domS=14832&domE=14918&domC=19056&lodS=19056&lodE=-1523791930575&secS=1302&code=pageload&time=-1523791930575&src=af-beacon&_rdn=949639","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.facebook.com/impression.php/fd71bd2bc2be98/?api_key=124024574287414&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/4liker-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/google-logo.png","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/developers/kris-nova.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/panda5412/albumset/16229033/zoomcrop/75x75.jpg?v=1523766771","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/momoko121212/albumset/14211048/zoomcrop/75x75.jpg?v=1522554165","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/.a/2.75.8/assets/sprite-chrome.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/tengxun20171024-56.png","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://sp.auth.adobe.com/entitlement/js/AccessEnablerProxy.html?ba8d85b7b308fbea7ac5","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://e.nexac.com/e/a-1189/s-3614/s-3614.xgi?google_gid=CAESEN4k0zzA-yIduwaxogB9W5w&google_cver=1&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/HP-MbfHFUqs/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLAjdUAhvqL3bFVYRHxRqwPjGvinag","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/04/15/1523781921_20180415-00000114-spnannex-000-view-x104-y104.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/ae/c6/f1/aec6f1e0df8e6e8cccf9ca6d96dffcf3/aec6f1e0df8e6e8cccf9ca6d96dffcf3.28.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180409/f44d307589141c355adb03.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d307589931c3a51ce4b.jpg","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yv/l/0,cross/R29j_7IKY6u.css","request_type":"css"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/built/scripts/head.built.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/prom_ev.gif?posId=undefined&itemId=undefined&SUV=null&_time_=15237919383354130834058580","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/photo/2018/0413/r356166_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://secure.adnxs.com/ttj?ttjb=1&bdc=1523791857&bdh=ew08qiGNop5CrfKveGyKAKgjqNU.&&bdref=https%3A%2F%2Fmail.ru&bdtop=false&bdifs=2&bstk=https%3A%2F%2Fmail.ru,https%3A%2F%2Fad.mail.ru%2Fadi%2F100590%3Frnd%3D107581893,https%3A%2F%2Fsecurepubads.g.doubleclick.net%2Fgampad%2Fads%3Fgdfp_req%3D1%26glade_req%3D1%26glv%3D26%26dt%3D1523791849451%26output%3Dhtml%26iu%3D%252F205338224%252FMail.ru_mobile_320x50%26sz%3D320x50%26sfv%3D1-0-10%26correlator%3D853336767280731%26adk%3D3471309403%26biw%3D-12245933%26bih%3D-12245933%26adx%3D0%26ady%3D0%26oid%3D3%26u_sd%3D3%26ifi%3D1%26click%3D%2525%2525CLICK_URL_UNESC%2525%2525%26nhd%3D1%26url%3Dhttps%253A%252F%252Fmail.ru%26top%3Dmail.ru%26loc%3Dhttps%253A%252F%252Fad.mail.ru%252Fadi%252F100590%253Frnd%253D107581893&&id=12753689&size=320x50","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA=&piggybackCookie=WtM4gQAABibm4O17","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938194_3449045585397&itemspaceid=12426&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938194&cnid=228336229,228344844,228321439,228327706,228319050,228319603","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.co.uk&slot=navFooter&a2=0101264bea73f7f0a15d445ceba12c12b857d9ceb1efa65d37a4620a87e44f56c1ef&old_oo=0&cb=1523791855593&dcc=t","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/rq/darla/3-1-1/js/g-r-min.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/css/styles.css?v=1.123","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"https://im-x.jd.com/dsp/np?log=kKWpPGny-Mglmy4fCUUYoP8sFAUXX9bSQZ6Of-red0lSNXYAyC2AnRZVceqZFz0NVaqlaSRqF11vYbEmPRawFeZbFyARv5VXL9eoj2YyIop-29WaYQu8TkmnkagbIgMWOtltf8Fo801GO-C01UNIt4gZoqNV4BBV9RMOU0BXTzX-cZiXiqtxQiImWBseTzbarRs7n9uvCMHupCwNdftXBJmOzzrar1q-mBRK6kWBf3Bdezvzk-5xIXfpStgzgt-9A6JIb5I2X7dYR__uDwwvo-0GZal1oSAFJXbBis_bzx2ChLfPSRrIRzXmEibA7lcQ16Jg8zYoNPwfJDR8ap6F2eur6cJHYnoqstpDwc-2Fh0B-RHo2pdUVtFNN2F1dRtB&v=404&_=1523792002411","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-44184928-2&cid=541858476.1523791959&jid=297431564&_gid=47841196.1523791959&gjid=109626532&_v=j66&z=1325857718","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:146-2652873-2143838:6983MGHS2ZBMHXB1G0WS$uedata=s:%2Fuedata%3Fld%26v%3D0.200481.0%26id%3D6983MGHS2ZBMHXB1G0WS%26sc0%3DMobileAppUpsellWidget%26bb0%3D2043%26pc0%3D2044%26ld0%3D2044%26t0%3D1523791927731%26sc1%3DHeroWidget%26bb1%3D2045%26pc1%3D2072%26ld1%3D2072%26t1%3D1523791927759%26sc2%3DNinjaWidget%26bb2%3D2234%26pc2%3D2238%26ld2%3D2238%26t2%3D1523791927925%26sc3%3DNewsDeskWidget%26bb3%3D2146%26pc3%3D2176%26ld3%3D2176%26t3%3D1523791927863%26sc4%3DBornTodayWidget%26bb4%3D2192%26pc4%3D2205%26ld4%3D2205%26t4%3D1523791927892%26sc5%3DPollWidget%26bb5%3D2233%26pc5%3D2234%26ld5%3D2234%26t5%3D1523791927921%26sc6%3DZergnetWidget%26bb6%3D2239%26pc6%3D2260%26ld6%3D2260%26t6%3D1523791927947%26sc7%3DLoadSis%26bb7%3D5077%26be7%3D5128%26pc7%3D17424%26ld7%3D17424%26t7%3D1523791943111%26sc8%3DcsmCELLSframework%26bb8%3D5159%26pc8%3D5160%26ld8%3D5160%26t8%3D1523791930847%26sc9%3DcsmCELLSpdm%26bb9%3D5160%26pc9%3D5181%26ld9%3D5183%26t9%3D1523791930870%26sc10%3DcsmCELLSvpm%26bb10%3D5183%26pc10%3D5185%26ld10%3D5186%26t10%3D1523791930873%26sc11%3DcsmCELLSfem%26bb11%3D5187%26pc11%3D5187%26ld11%3D5187%26t11%3D1523791930874%26sc12%3Dimdb_comscore_request%26pc12%3D9234%26ld12%3D9234%26t12%3D1523791934921%26ctb%3D1:17434","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/961332156/?value=1.00&currency_code=USD&label=ovrQCMHWrWAQvIezygM&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/995153884/?value=1.00&currency_code=USD&label=szBrCMnWkWAQ3K_D2gM&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://mc.yandex.ru/metrika/advert.gif","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=w7AqE8pkXEhXSD2ljg0qdt7n,0.8876056869101518&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031523791949%04scrnpos%03%231523791944.558%400%3A0~0%04_E%03scrnpos","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1121&dpuuid=1974054384951196314","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=629920737&t=pageview&_s=1&dl=https%3A%2F%2Fwww.whatsapp.com%2F&ul=en-us&de=UTF-8&dt=WhatsApp&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAAAB~&jid=1999178474&gjid=1419369433&cid=222124185.1523791918&tid=UA-8707243-1&_gid=1425844565.1523791918&_r=1&z=1347029220","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/hJBD51rYjUbo1v-5HRbsZYl8Op971aX1JwwB4GFFeqdxhriI3JSW1VnB50JtqA=w128","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/W0R6Lf3Id13mEqJu9di9w-or4BARQoZLIEpesrMvKGwc6kBw2sfygoy2vWzkcA=w512","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/favicon/192x192.png","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://mc.yandex.ru/metrika/watch.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://falcon.pixanalytics.com/ad/embed/3027","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/53c15218-9f10-447f-8d8c-45a61848ff16_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1N9PCIpXXXXXBaXXXq6xXFXXXh.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20170727/f44d307589141ae3d98618.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/41PyBz-KWWL._SCLZZZZZZZ__AC_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/YakAAOSwn3VavQNN/s-l225.webp","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://af013c7a3b27b4e5ac7439c2564ad4252.profile.phx50-c1.cloudfront.net/test.png","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/plugins/superslide/js/jquery.SuperSlide.2.1.1.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://www.tmall.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938263_8145837968779&itemspaceid=13820&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938263&plateid=1001300000,1001200000","request_type":"script"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://cdn.registerdisney.go.com/v2/responder/responder.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://bw.scupio.com/adpinline/adcall.aspx?cb=0.086028644776869&cid1=13940","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Shared%20BingCore$Animation/cj,nj/c9ce19fd/92e3c570.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/518e5yqTyZL.js?AUIClients/RetailSearchAutocompleteAssets","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61WZygn8wbL.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,513EDHaa7SL.js,11sT42sZnQL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61x-Yxr2raL.js,318CMPRminL.js,11dYToHZZ0L.js,21TDqwIsfQL.js,01qkmZhGmAL.js,012YXvM7lUL.js_.js?AUIClients/AmazonUI","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/js/s_z.js?1","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=taboola.com&id=b58f4680-fc0f-4cd1-be0d-115dc83562ff-tuct1ccbdc5","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=taboola.com&id=27c43a8b-912f-4aa5-aa86-85748d5837bf-tuct1ccbdb6","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://yjtag.yahoo.co.jp/cs?tp=GvIpabp&btt=0&uid=fae3d06196974c92743ce599778789db","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://secure-us.imrworldwide.com/cgi-bin/m?ci=us-204044h&cg=0&cc=1&si=https%3A//www.cnn.com/&rp=&ts=compact&rnd=1523791864270&ja=1","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://fbsbx.com/security/hsts-pixel.gif","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/F1/3F5B6D.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/g15zvfM9ccRqjI8oFWNH4tdgvMF-BQEEpXwSEDRJnyvaJTTx7bI2XJ1bVWh9Vz8=w512","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://tr.outbrain.com/pixel?marketerId=006eb1f8dded486e0974a6b4a7b9805f5f&obApiVersion=1.0.4&name=PAGE_VIEW&dl=https%3A%2F%2Fwww.cnn.com%2F&bust=07193842477300758","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5494000/5494567/220x165/7.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1TYKdXVuWBuNjSszbq6AS7FXaV.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1NV51cMoQMeJjy0Fnq6z8gFXai.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSMaA.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/images/huidi_pic_banner.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/3459000/3459577/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/dmsmty/212_160_/t01e2460f9909e62128.webp","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://falcon.pixanalytics.com/ad/js?fields[]=ad-1150,1150&fields[]=ad-1152,1152&fields[]=ad-1153,1153&_=1523792006810","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-golf.png&h=240&w=240&scale=crop&cquality=40","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/west-european/mscomhp/_scrf/css/themes=default.device=uplevel_web_mobile_webkit_android/71-e64aff/3a-4871f4/84-f3ce22/5a-86eb17?ver=2.0","request_type":"css"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/ac-films/5.2.0/scripts/autofilms.built.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://r.nexac.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=https://beacon.krxd.net/data.gif?_kuid%3DL6N62llA%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://adservice.google.com/ddm/fls/i/src=8392543;type=idsyn0;cat=uuidm0;u1=NotSignedIn;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;u4=;u5=;u6=adobe.com;u7=;u8=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=1;num=7017383513578.663;_dc_1=1;~oref=https://www.adobe.com/","request_type":"html"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/gen_204?s=webaft&atyp=csi&ei=-DfTWri-EumB0wK74IagAg&rt=wsrt.2175,aft.438,prt.253","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791944674&yhlClientVer=3.30.2&yhlRnd=UEmIbhkQwvOm8tgSjg0qdpeq&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.imdb.com/","request_url":"https://ads.yahoo.com/cms/v1?esig=1~b9bada6fffbf45c1ffda7783879fb5715486894a&nwid=10000922750&sigv=1","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.amazon-adsystem.com/iu3?cm3ppd=1&d=dtb-pub&csif=t&dl=rbd_ox_pm_an&dcc=t","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ing-district.clicktale.net/ctn_v2/auth/?pid=1001&as=1&m=1&1981549263&subsid=233396&msgsize=10","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-easing/anim-easing-min.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/81pPtFtJAnL.js?AUIClients/GoldboxUDPAssets","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://api.adsymptotic.com/d/px?_pid=10479&_psign=1e962a13c2bbb17776ade0119024edb3&_redirect=https%3A%2F%2Ftags.bluekai.com%2Fsite%2F20931%3Fid%3D%24%7BUUID%7D&_expected_cookie=fa49bdb775fb67ef652fba4559e55606","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://tag.clrstm.com/ul_cb/sync?dmp=adobe","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=adobe.com&id=27629303070893196980343805210192818429","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://pixel.mathtag.com/sync/img?redir=https:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dmediamath%26mmuuid%3D%5BMM_UUID%5D&mm_bnc&mm_bct","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://d.liadm.com/segment?s=17031","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=269&dpuuid=0ee15ad3-329d-4e00-9707-904295c4fec1&ddsuuid=91191954147729940174299115411397659455","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1nrM9kmCWBuNjy0Fh7626EVXal.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/csddm/albumset/5983415/zoomcrop/75x75.jpg?v=1523609226","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmrb_wx_logo.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/cx_youliao.png","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/webapp/style/images/favicon-9f8f9adf.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/input/members/bg.png","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://getrockerbox.com/pixel.gif?pageReferrer=https%3A%2F%2Fwordpress.com%2F&action=view&source=wordpress&an_seg=7920770&type=imp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/Y4MeJ1N8O6YctNVfKoBh7Q/009/342/210/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180207151920-01-sophia-weaver-twitter-troll-small-tease.jpeg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180414102350-14-syrian-airstrike-041418-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s134x134_jfs/t3664/213/2212841326/143271/e8b78b47/58453027N6e97b8be.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=865230016511&t=17&plc=MOBILE&tkn=*Kino6MBJTWE8vT1C864qt_dVFzY","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/pub-config/r20160913/ca-pub-2647689032095179.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/mtop/5.6.0/fonts/icon.woff","request_type":"font"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/fonts/uptodown.woff","request_type":"font"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/application.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://auth.gfx.ms/16.000.27744.4/MeControl.js","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-bce1c4976aa/v3/js/skins/min/default.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/usa.png&h=60&w=60","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static2.dditscdn.com/mbl/frontend_backbone/static/_common/fonts/roboto-regular-webfont-71f67.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy//nn/lib/metro/g/myy/myy_viewer_atomic_0.0.2.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/G/01/imdbads/js/beacon-1792157672._CB514933407_.js","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=netflix_dmp&referrer=netflix.com/bt/nmLanding&google_cm=&google_tc=","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.pubmatic.com/AdServer/js/showad.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/pagead/js/r20180411/r20170110/show_ads_impl.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/mscomhp/_scrf/js/themes=default/f1-a4981f/48-38ad72/67-b6cda3/f2-4f13f3/8d-e6244e/c7-95bf02/7b-eade91/f6-d16ccf/7e-9bc997/61-edc7a4/c2-9140b0/54-59e534/d8-a75e10/68-e9a977/fe-45536d/f0-4646be/cf-593c1a/92-ac04dd/73-064100/9a-201284/23-23492d/c4-4cc58f/ae-7b3cef/4e-54e265/6f-fb7eb8/10-c010f6?ver=2.0","request_type":"script"}
+{"origin":"http://www.twitch.tv/","request_url":"https://app.link/_r?sdk=web2.33.1&branch_key=key_live_jgBdao5vVtyZ3hdckxy8jlkkzqooQltZ&callback=branch_callback__0","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://dpm.demdex.net/id?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_mid=27927265607529191862424128891858798724&d_blob=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&d_cid_ic=AVID%012D699C4E850322B8-60001196800666E8&d_cb=s_c_il%5B0%5D._setAudienceManagerFields","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yr/r/ibdTRRlB_qH.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768233&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791998038&fs=2&pvid=c32daead2d9d44a90175f1805bac9647&cg=ac5d0045d9f513d33bb3436aea29ec34","request_type":"script"}
+{"origin":"http://www.qq.com/","request_url":"https://pingfore.qq.com/pingd?dm=www.xw.qq.com&url=/index.htm&rdm=www.qq.com&rurl=/&rarg=&pvid=9480881850&scr=360x512&scl=24-bit&lang=en-us&java=0&pf=Linux%20x86_64&tz=7&flash=-&ct=-&column=&subject=&vs=tcsso.3.1.5&ext=nw%3D1%3Btm%3D41%3Bch%3D2&hurlcn=ad%3Dxw.qq.com&rand=64182&reserved1=-1&tt=","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://www.storygize.net/ccm/4b560cdd-91f9-422b-adb7-e9dff26bc3ad?u=39041E2B94ED6EF00CB315F995BE6F73","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/l?IG=2E674091B80D41D497ED8B2E88AE58C9&CID=15398167FE80640C2D1F8AB5FFD365B8&Type=Event.CPT&DATA={%22pp%22:{%22S%22:%22L%22,%22FC%22:-1,%22BC%22:-1,%22SE%22:-1,%22TC%22:-1,%22H%22:-1,%22BP%22:426,%22CT%22:435,%22IL%22:2},%22ad%22:[-1,-1,360,512,360,512,0],%22net%22:%22undefined%22}&P=SERP&DA=CO4&MN=SERP","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://usermatch.krxd.net/um/v2?partner=google","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=2474&partner_device_id=CAESENn8WiwRByhFKIjFxg01J-A","request_type":"other"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/assets/common/normalize.css?ba65b1d2869363dc014f45ef38b34229","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://pubmatic2waycm-atl.netmng.com/cm/","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/load/bg01.gif","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D3P95XKNQTYVQ066DW1Q8%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D12498%26pc0%3D12498%26ld0%3D12499%26t0%3D1523792025345%26csmtags%3Daui%3Asw%3Aunregister%3Asupported%7Caui%3Asw%3Aunregister%3Aunsupported%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D3P95XKNQTYVQ066DW1Q8%26aftb%3D1:12501","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/981179826/?random=642328750&cv=9&fst=*&num=1&label=40zWCLqP1XUQsrvu0wM&bg=ffffff&hl=en&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=2&url=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26session%3Dn%252Fa%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Df1fdc59c-9452-4167-a583-cc8ede9a2929&ref=https://adtech.nflximg.net/adtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522f1fdc59c-9452-4167-a583-cc8ede9a2929%2522%257D&fmt=3&ctc_id=CAIVAgAAAB0CAAAA&ct_cookie_present=false&ocp_id=HjjTWoG_OYSkigOvzoHACw","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=91191954147729940174299115411397659455&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d91191954147729940174299115411397659455","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/G/01/imdb/images/mobile/mobile_sprite_x2-27452193._V_.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/chingcc123/albumset/15858585/zoomcrop/75x75.jpg?v=1522506939","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=cox&google_hm=ChUIgZfx8fzamODYARCqmbq3s_PfoQU%3d&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/bkZfwpDRL1PEZ8W8gZFb4C2j-m2b6OafU7pe4KIfxhkyFsZXNAFRTAQ-zPyWFA=w512","request_type":"image"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/img/share-sprite-new.png?v=e1b8bd67bc12","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/icon/search_985e3e7.png","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/World%20of%20Warcraft-429x572.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/5D/A1AAB2.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB19Q3UlgvD8KJjy0Flq6ygBFXaf.jpg_q70.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/ffe/siteui/vlv3/2c0f37cf-c835-47f2-9fc3-9253b5bc8930/71ee9688-d6dd-4177-aac7-8ef8945c9c6e/US-en-20180409-popsignuptwoweeks-perspective_alpha_website_small.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/02/89/be/0289be1e33d82dbb161ace0fa967ae7b/0289be1e33d82dbb161ace0fa967ae7b.20.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0406/dm_180406_nfl_cowboys_martinez_family/dm_180406_nfl_cowboys_martinez_family.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-oSAbz46-1qw/AAAAAAAAAAI/AAAAAAAAAAA/UzFF1NAQRSo/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/dfbad95915e77b7a04b05c4914c5b8fb_erotic_285x160.jpg?cno=2e7","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/KlONyRDg-_Ep4RbnfUKnSp3XMgG8DyT33iO2jWGmsUk.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://a.thumbs.redditmedia.com/FRFBXBSolP2GKwkge9HlTNBoXAhxoULjuaOzYSUMFc8.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://conductor.clicktale.net/monitor?t=preinit&p=147&2=2927199622326975&v=1.4.86&7=https%3A%2F%2Fwww.adobe.com%2F&3=6253213492942417&4=3980987688945493&5=0","request_type":"text"}
+{"origin":"http://www.microsoft.com/","request_url":"https://conductor.clicktale.net/monitor?t=preinit&p=162&2=8342295539382868&v=1.4.86&7=https%3A%2F%2Fwww.microsoft.com%2Fen-us%2F&3=7180669596827813&4=2927741616705801&5=0","request_type":"text"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.krxd.net/userdata/get?pub=e9eaedd3-c1da-4334-82f0-d7e3ff883c87&technographics=1&callback=Krux.ns._default.kxjsonp_userdata","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://cl.webterren.com/webdig.js?z=7","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_194.js?cb=195","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ads.trafficjunky.net/ads_batch?format=json&clientType=mobile&data=%5B%7B%22spots%22%3A%5B%7B%22zone%22%3A981%2C%22site%22%3A23%7D%5D%7D%5D&cache=1523791902&channel%5Bsite%5D=pornhub&channel[context_page_type]=home","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/register/form.min-vflaFePKR.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/login/sp/js/login_promo/1.0.5/login_promo_core-min.js?t=423275","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.chartbeat.com/js/chartbeat.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0415/dm_180415_Enhanced_Sixers_fun_win/dm_180415_Enhanced_Sixers_fun_win.jpg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/","request_type":"html"}
+{"origin":"http://www.google.co.in/","request_url":"http://www.google.co.in/","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/images/favorites/manage?action=getStatus&sid=0F48E41F26BD6C4538C7EFCD27EE6DA3","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA=&piggybackCookie=WtM38gAAAE3-YTsD&_test=WtM38gAAAE3-YTsD","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://abp.mxptint.net/sn.ashx","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://odr.mookie1.com/t/v2?tagid=V2_393725&AMAZON_REGION_SPECIFIC_ENDPOINT=s.amazon-adsystem.com&src.visitorID=szS75lIHR5WWYF4w_1kgmg","request_type":"text"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/v3/pr?exlist=pp_mp_sx_ns_rx_kr_g_bsw_bk_ox_index_aold_an_rb_aolv_y_pm_adelphic_adb_tbl&fv=1.0&a=cm&ep=_y5gfmPslP0oehftrPLWXNy3ywrbpVe04rrwnVMsWFdzccwItQjYOqz1iI7Bf9QVV-R-fE_3yO-ypMafoDPJPE16GHNGVOvFdbwzujPbU4s","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/scripts/tumblr/utils/exceptions.js?_v=6480337ee2259189f7dc54042bdc671a","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770682&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791989157&fs=4&pvid=e8a6ec7aa1ca351969368d8ac9d1421b&cg=afde1ed1c8f8a7691b02083daca7492f","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://pubmatic-match.dotomi.com/match/bounce/current?networkId=17100&version=1&nuid=%3Cexchange-user-id%3E","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://sync.ipredictive.com/d/sync/cookie/generic?https://s.amazon-adsystem.com/ecm3?id=${ADELPHIC_CUID}&ex=adelphic","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1&verify=true","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://bidder.criteo.com/cdb?ptv=48&profileId=184&cb=82048345300","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=c20543831008edf87d0dbbc6c63bc828969917ff&ex=aoldisplay.com","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://wn.pos.baidu.com/adx.php?c=d25pZD0xOTI3MGU3NmVmYTAyZmRjAHM9MTkyNzBlNzZlZmEwMmZkYwB0PTE1MjQxODk5MTYAc2U9MQBidT00AHByaWNlPVd0bEszQUFBQ1Z0N2pFcGdXNUlBOHJCekpIN0wyRHZWTHJCelJRAGNoYXJnZV9wcmljZT03NTAAc2hhcmluZ19wcmljZT03NTAwMDAAd2luX2RzcD00AGNobWQ9MQBiZGlkPUJBMTBCMEFENTY5NDE3MTFFQkI2NEE5MEU3MzJCNzQyAGNwcm9pZD0Ad2Q9MAB0dT11MzAxODg4MQBwb3M9MABiY2htZD0wAHY9MQBpPTQwNmI3NGYz","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://media.trafficfactory.biz//banners/da/78/5e/2adb6a27ebc1347c438ec69bac221c69.gif","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a67342300005ad3387f10ed70f38aa5&pid=mm_113716014_12970037_52768243&cid=92223&mid=70785&oid=149&productType=1&qytInfoMTime=1523728959&e=sG3UV53q1cuMpq0A4M5XO0%2BGD8pewqZW8yRWCWdXMNuusqzyJ98R02ohxUgfTEvw&k=65&cb=940377688","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/impression.php/f6805c2416ea28/?api_key=274266067164&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://popads-trustguard.cdn77-ssl.net/business-5270-mini.gif","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://pos.baidu.com/sync_pos.htm?cproid=BA10B0AD56941711EBB64A90E732B742%3AFG%3D1","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/1a4fe3ee-0d0d-4d28-96d9-d08bd4fc5e41_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/10/d0/5c/10d05c3277ef5966d372e47488b3dbb3/10d05c3277ef5966d372e47488b3dbb3.8.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41BMyAk8duL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"http://www.instagram.com/","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/sc/2b/a5ea21.ico","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://as2.m.hao123.com/xtomvxlcyq?tqu=a.&iup=Z.W&pu=QZXW.aW.&xfg=DPPLO5Zd5Yi5YiI53D6KXYZ538KI5Yi5ZiREP5ZgDXYZ5Y.BNKI5ZgZSXYZ&bmd=Z.WT-XY&pfy=kwpo3srvw&qjbe=XXXWWY&oqo=xwi4b&mzf=X&fbd=X-YZacXcb-YXc&be=aX.TW&bdaf=Y&pdu=W&po=Z&boe=Z.WT-XY&pue=W&mdu=Y&bue=4XT4X&bee=Z.WTac-&pmu=X&95=kqxvc&m3=2ofvq&u4=gu22&69=2awb&swt=1","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://z.moatads.com/espndfp832188684382/moatad.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/favicons/favicon.ico?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100166121&apid=beans_12288&impid=06a61a3b9f54e737a_0_0&at=1&mkey=06a61a3b9f54e737a_0_0&latcy=4574&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=5371.984375&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DYp5WGmNW9i0qFPx4uhVpLvgpTsvJFHWAMoGHaVZbCESEmn9YZspBnofJ1O8wHJ1ye%2BOuV7kx7ljjfM1RRtCv6eyH9BoYUBQnGoI%2F%2F12krKk0p%2Fwr5cSpKUBZ1In7RA1JkFpmXSut4OMdwfNGg2%2F4wI4LSix0rdKnBpL5KqRh4RCIRJEJxphx8cxIsDf%2FheRQPoWmCdXN36%2FPOBbkntkPBFBoJMH65yd7k9tmL0IVJpTdJKQZTWxWnf1unUpNT3lD86IAo5hIGY3rny1phvsC%2FGQ7z%2BujBohSvqeTvdjQcG6yNd898hZiEzelnvlbb1VFTqQIoPjZ0sM%2FuA9LftCZXJdX3%2BoY9A1vywyY8T%2FOTfI4yAoVhJani7VzMF9aoQwfZssDM7mG6bFWhQ5qjbZpG9CaKqxaahSH%2B%2FtlV0HvjAVfjXvlYifFDohHt1EmMF9oqsOcrBAUH1IbPFVcpBGVwb0AWwQ9hvbGyYAMrmiP4gqcnIbr95u5ZQkiEsRGussCybivRhlqjyPI2TMGrsrRtK6WGx7e0TPu1Xd7exMkdIGMoflFsh63R8q1YLUrR60vjxjDkpSasG%2Fz0QRKWwNVcW%2FknphtDXtVC8v2Q18y7Xg%3D%09tt2%3D1523791942523%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=2513903548877&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942833","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100229752&apid=beans_12291&impid=07df4ed7a3dc9a04e_0_0&at=1&mkey=07df4ed7a3dc9a04e_0_0&latcy=4599&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=6990.390625&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DMK3qiCSC8Tis9Y48kp%2BL9DZ%2B%2B80jJsq5Gp7mE58tcdzEn%2BYy0L6Gh889XuI6%2F4Y%2FFOZpu46b1ime0AMVfbcEjSNTkCV7LSIQPStktAmqs5uAJjW%2F0njopVpMdpZ3%2BusbbPFIR3zgSjJ%2Bqoyoyrb5zg7lxVr%2BAGf2z7NjS2Qc7pgdyqTUWom9t8sTUkDzm%2FL04X609HIYvGHoLdJXYFASLnixHhRV1xcOHm%2BPVvkB2jqeP5zuranuEowAtjJJawYlU4friVibWcepz5FGuWNqkVzEHJ4Hozk5DxrJZxtDD6pKK%2B92xDS0X%2BzQDy3V8iF7ptRlmWGzWGzc9MjU1%2FYBLycZbwXutXvtxN3TqlG3aj2oTurvMsx3y9VOrKUVke%2F8%2B7RzgOyKRublFLziLKcam63dE%2F4n4LRScapxK1fzxehOl4rRYjJCNr30E0yznFhnzT5LXXlYPGFmtcbmID2FhYy5txIvb%2B8nqQgH01mpT7GO51e7WxYdhSScOFkJhVBtMUzlkvFM1i9N8zw8utgs%2FuPaQh5su7fyshIcfzW7TQx%2BCGgxFXa5u8LjP3w2gZtmM757VzOTGGXRzGOrprnJ%2BwkK%2F50I8UudQzRrh2w%2FKtw%3D%09tt2%3D1523791942569%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=5699657826792&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942868","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/v3/pr?exlist=pp_mp_sx_ns_kr_g_bsw_bk_ox_index_aold_an_rb_fbca_aolv_twca_y_pm_adelphic_rlsa_adb&fv=1.0&ex-pl-fbca=yv2UNYixS52k7Ba5Hrdpyw&ex-pl-twca=-yalcI9yS-6iePfINjDv7Q&a=cm&ep=mnPNm_OU3BFF7sfzJIWqqji0D-K5HF7yBLc4BHuSz6QG_2qkzzsKcE5tNaWbmDG1iUcUEd8zBbNeNU5iFHD6Dvpfdo_lVdqMxtzWulMrsj39TLRvhIqYuXWtaD4adE1ZYAjJHGXrO_bvlXcnxBTbOPNf8xh4TQtE5CFLqc-EccX_aXKvOZFxChdNQ2iZOWzZZYmi8urB8ypyJsRBYzkngw","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/mwf/js/MWF_20180410_9005042/alert/autosuggest/cards/contentplacement/contentplacementitem/glyph/heading/hero/heroitem/hyperlinkgroup/image/list/mediagallery/pagebehaviors/singleslidecarousel/skiptomain/social?apiVersion=1.0","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1&verify=true","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://stags.bluekai.com/site/36841?dt=0&r=831997411&sig=2032588566&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmiRglWl1u3dep5hJEi0rvuNa028whzGcC3z3bh3gaqjG33LRr3ADZXAl5XSvQ7AsZVVQWDuLGoEzNmp9xoOQeP0hFr","request_type":"other"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/20170601mobile_index.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/nn/lib/metro/g/myy/font_rc4_0.0.69.css","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=8f33ce0734a31209c367","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://level3.cedexis-test.com/img/17652/r20.gif?rnd=1-1-13960-0-0-17652-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/968413686/?value=0&guid=ON&script=0&data=aam=4933391","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/voot-android.png:l","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t15076/226/2372445198/4768/4b9c36de/5aa10ce2N848e2dbd.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/logo_48.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"http://www.savefrom.net/","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1GfzJRFXXXXbVXVXXq6xXFXXX8.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/zzIMggwbWr4/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLDErZV5htScAGjxHsTIpHYgNE6vBA","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/256c0d77-7603-4d60-be6e-a9cb412de301_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-bg-dc-4pod-work-4u-mobile-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/94c69122e6f11c3a47b215.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/02b/0c7/02b/big_lq/dcd0af647abb5bc18c1af42d9ab52245.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BOTIzNzM3ODM1Ml5BMl5BanBnXkFtZTcwMjQzNDMzMw@@._CR596,136,1127,844_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=867566692206&t=17&plc=MOBILE&tkn=*M6jJkZeM4VdY4mAbqg-qXqGUMe0","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://sync.adap.tv/sync?type=gif&key=thetradedesk&uid=ecf97925-4f99-4dc2-9bf7-6775e63a3ba0","request_type":"text"}
+{"origin":"http://www.microsoft.com/","request_url":"https://logx.optimizely.com/v1/events","request_type":"text"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/concat/common/js?h=ebbt2vixcc5qz0otts5io08xv","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/cr/v/c1/market-sans/v1.0/MarketSans-SemiBold-WebS.woff2","request_type":"font"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/j/common-33531e2af1.js","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/20170606data_read.js?timestamp","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-content_body_atomic_sm/td-applet-viewer-templates-content_body_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-UnauthPageWrapper-27bc87df6615a716dc4e.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/mlb.png?w=110&h=110&transparent=true&h=240&w=240","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31LiSGwXxjL.css_.css?AUIClients/SharedShoppingCartMobileAsset","request_type":"css"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/plugin/safariicon_6bd009a.js","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://cpro.baidustatic.com/cpro/expire/time2.js","request_type":"script"}
+{"origin":"http://www.google.ca/","request_url":"https://adservice.google.ca/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/icon-wp.svg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=cms-adobecom_us_index_BottomOfBody&mboxSession=9bacdabf39b7406b83ce178a57242400&mboxPC=&mboxPage=5ededb5d3e024eab82d38d46617d12fd&mboxVersion=1.2.3&mboxCount=3&mboxTime=1523766798997&mboxHost=www.adobe.com&mboxURL=https%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-420&screenHeight=512&screenWidth=360&colorDepth=24&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=0F715D2B1317710A-3C141A64CA81D397&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id=","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://twitter.com/i/js_inst?c_name=ui_metrics","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/bundles/usabilla.eaa177bb58d5c07f82a4.bundle.js","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/v/aezttni0eu0k1cdolp2welcsw2c.js","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/js/s_z.js?1","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://insight.adsrvr.org/track/conv/?adv=l8hfnf9&ct=0:4gktlyq&fmt=3","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=yNo9rhBXTJWOsGNHkfdUjA&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/lsp.aspx","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=ttd&partner_uid=8c99d41e-370c-4b26-8e99-c0a29e5698e1","request_type":"image"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/stylesheets/layout-min.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/sprites/web_sprites-vflv2MHAO.css","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=83933e60-40a0-11e8-8dc2-e75f2aae293b&ex=adelphic","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=JG0QC2PD-14-82AL&ex=d-rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/spn16_1.gif","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/imp?bid=0a67349c00005ad3387b4cfb70cc7e61&pid=mm_113716014_12970037_52768241&cid=217738&mid=54295&oid=149&productType=1&qytInfoMTime=1523728959&e=03FUTRUIqj6Mpq0A4M5XOxu%2BuDuQwZjvAGQFGRMhhOzPD2%2FvNftHqS60uGbHPyj9&k=65&cb=916366700","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjstN0JTyAgecNhmrUTA1YurjCw3d8xzHYjZeH7Q4W4OBhZ8j51_JkQ3L86FhMp_vxhd8qAAM2NMMP7HG_l9ayvSljoZDf_jyhPY&sig=Cg0ArKJSzJsQuKpSI-UXEAE&id=osdim&ti=1&r=z&adk=884486896&tt=358&bs=360,512&mtos=0,0,0,0,0&tos=0,0,0,0,0&p=0,0,0,0&mcvt=0&rs=3&ht=0&mc=0&lte=-1&bas=0&bac=0&avms=geo&bos=360,512&ps=360,9427&ss=360,512&pt=-1&deb=1-0-3-8-3--1-2-1&tvt=282&op=1&uc=1&tgt=BODY&cl=1&cec=5&clc=0&cac=0&cd=0x0&v=r20180411","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://c.msn.com/c.gif?udc=true&rid=e86f55f780704d568af4af783e3cb6c4&rnd=636593886315667499&rf=&tp=https%253A%252F%252Fwww.msn.com%252F&di=340&lng=en-us&cv.product=prime_mobile&pn=startpage&activityId=e86f55f780704d568af4af783e3cb6c4&d.dgk=tmx.mobile.webkit.android&d.imd=1&st.dpt=&st.sdpt=&subcvs=homepage&pg.n=startpage&ctsa=mr&CtsSyncId=6FFC77522C924D75BC8F8250FD085A47&MUID=00688DBF065369162420866D02536ACA","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/mobile/ajax-loader.gif","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3D3P95XKNQTYVQ066DW1Q8%26ctb%3D1%26m%3D1%26sc%3D3P95XKNQTYVQ066DW1Q8%26pc%3D14024%26at%3D14024%26t%3D1523792026870%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D3P95XKNQTYVQ066DW1Q8%26aftb%3D1:14025","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=7751&nid=2249&expires=30&put=CAESEN24tVSA0p0PI9yt4kPXE0o&google_cver=1","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p15.qhmsg.com/t01c5bfd5968d038a63.png","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"http://www.bongacams.com/","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdnssl.clicktale.net/www/tc/crossdomainInclCEC.html","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=3029559553","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://widgets.outbrain.com/nanoWidget/externals/obFrame/obFrame.htm","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4920000/4920025/220x165/10.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201803/17/158471182/original/(m=eafTGgaaaa)(mh=DyQIXzmA_eN27TGq)5.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/019/2a8/104/big_lq/8c1ee96cd649d0816332a6a3d93fc578.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/97/ba/3f/97ba3ff10000fd31ed5ae9418cbb081c/97ba3ff10000fd31ed5ae9418cbb081c.30.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/6f/a4/33/6fa4335f3b360f37b50f263d63c9f939/6fa4335f3b360f37b50f263d63c9f939.1.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5193000/5193073/220x165/8.jpg","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://cdn.registerdisney.go.com/v2/inner/tealium/utag.49.js?utv=ut4.44.201802141900","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/cr/v/c1/market-sans/v1.0/MarketSans-Regular-WebS.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-story_atomic_sm/td-applet-viewer-templates-story_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/native/impress?523791=Y2FsbGJhY2s9c2F4X2pzb25wQ2FsbGJhY2tfNSZhZHVuaXRfaWQ9UERQUzAwMDAwMDA1Nzc3OCZwYWdlX3VybD1odHRwcyUzQSUyRiUyRnNpbmEuY24lMkYlM0Zmcm9tJTNEd2ViJnRpbWVzdGFtcD0xNTIzNzkxODU0MTM5JnJvdGF0ZV9jb3VudD00NTgmYW09JTdCJTIyZHMlMjIlM0ElMjIzNjAqNTEyJTIyJTJDJTIyb3YlMjIlM0ElMjJhbmRyb2lkJTIyJTdEJm5ldD1udWxs","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/mobile/js/main.min.js?v=20180405","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/hotquery.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/js.cookie.min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/espn%2B/E%2B.png&h=240&w=240","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/61xVoot0QBL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,11B0Us3dmsL.css,21nwB+Kd2tL.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,31EvLS3U6zL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21s7MLn4blL.css,11X2-nh0PYL.css,01h2e2BEitL.css,114wDplwccL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31VU7Pt5U6L.css,01b7OI3r44L.css,11mmd1QliNL.css,01cbS3UK11L.css,21pKFuuDucL.css,01EjbsDjo-L.css_.css?AUIClients/AmazonUI","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://a3.espncdn.com/combiner/i?img=/photo/2018/0412/r355644_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://ads.pubmatic.com/AdServer/js/showad.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsuO2wEh8ddXnah5HrWRsBlJ4r_NaeaiMgZrCGBb5EMhH6R4je1XPwnUkegfdhugjvrAbonmPYdyJ1OdAcPG_AYhPakaksJRJXpwfdVrbN-SuE-9oHxFHzYZbP_HVJY7qy0SP37uCzsT1yiggt5Y6VuWpTTjvo3KDQcYt8aNumoOPRA8nFsj7LWwJzrGoPbk5zkcawmCcbCMq_EnKJgv04QDcXchwwxHJJgbzCisisCB424e-zXMMyxnk4kEsxTcgGJRQ45MZ8m4HbSKRRBnQn0UG7c&sig=Cg0ArKJSzMLpqK-CJjEWEAE&adurl=","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://polyfill.twitchsvc.net/v2/polyfill.min.js?unknown=polyfill&features=fetch%2CSet%2CMap%2CObject.assign%2CURL%2CUserTiming%2CString.prototype.startsWith%2CArray.prototype.includes%2CString.prototype.includes%2CObject.values%2CObject.entries%2CIntl.~locale.en&flags=gated","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-color/anim-color-min.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768072&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791990708&fs=0&pvid=a078222e3f3aa4251c9aeebbaead648e&cg=a198a389e17a353650a0e6e79cae96d3","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://level3.cedexis-test.com/img/17652/iuni3.html?rnd=-1-1-13960-0-0-17652-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/yh","request_type":"other"}
+{"origin":"http://www.alipay.com/","request_url":"https://gw.alipayobjects.com/os/s/prod/i/index-bd57f.css","request_type":"css"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/ProductionClient.d2d26e9934266b226d3575f29d1b855a.css","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D3P95XKNQTYVQ066DW1Q8%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D296%26cf0%3D1837%26pc0%3D1838%26ld0%3D1838%26t0%3D1523792014684%26sc1%3Dlg%26af1%3D2054%26pc1%3D2054%26ld1%3D2054%26t1%3D1523792014900%26sc2%3DcsmCELLSframework%26bb2%3D2092%26pc2%3D2093%26ld2%3D2093%26t2%3D1523792014939%26sc3%3DcsmCELLSpdm%26bb3%3D2093%26pc3%3D2096%26ld3%3D2096%26t3%3D1523792014942%26sc4%3DcsmCELLSvpm%26bb4%3D2096%26pc4%3D2097%26ld4%3D2097%26t4%3D1523792014943%26sc5%3DcsmCELLSfem%26bb5%3D2098%26pc5%3D2101%26ld5%3D2101%26t5%3D1523792014947%26sc6%3Dinteractivity%26cf6%3D4167%26pc6%3D4167%26ld6%3D4167%26t6%3D1523792017013%26sc7%3Ddata-store-1%26bb7%3D4288%26cf7%3D5037%26pc7%3D5037%26ld7%3D5037%26t7%3D1523792017883%26sc8%3Dcard-load-1%26bb8%3D5141%26cf8%3D6192%26pc8%3D6268%26ld8%3D6268%26t8%3D1523792019114%26sc9%3Dcard-load-2%26bb9%3D6270%26cf9%3D7085%26pc9%3D7160%26ld9%3D7160%26t9%3D1523792020006%26sc10%3Dmobileadsajaxfired%3Agrid-9%26pc10%3D6764%26ld10%3D6764%26t10%3D1523792019610%26sc11%3Dmobileadsajaxinject%3Agrid-9%26pc11%3D7552%26ld11%3D7552%26t11%3D1523792020398%26ctb%3D1:12483","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://img30.360buyimg.com/popshop/jfs/t2170/4/1852891769/2681/e983a4c/5678b480N0c241b93.gif","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1064110564/?userId=T8END0GPSW-I-45Xox-rSQ&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/m-home-pic-new.png","request_type":"image"}
+{"origin":"http://www.weibo.com/","request_url":"https://passport.weibo.cn/images/weibo/signin/icon_2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/G8OwqoI4B9v3T6npbcEpcDeAoSN3fpkFcKPkb5e0hzdm5HewaG3PaSGmTUyblnQ=w48","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p4.qhmsg.com/t01f9b7903b471806d0.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"http://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/","request_type":"html"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/wss/fonts/SF-Pro-Display/v1/sf-pro-display_semibold.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5478000/5478411/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/7oMAAOSwUMxaTAxi/$_57.JPG","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$celebrityquiz/ic/86deb1b6/5ccac8d2.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_website_UI.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201403/14/24303582/original/(m=eafTGgaaaa)(mh=UM_QdhxScaI2Nayy)4.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://d2x3bkdslnxkuj.cloudfront.net/2750560_300.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://img.alicdn.com/tps/TB19RaGLpXXXXcDXpXXXXXXXXXX-333-261.jpg_q50.jpg?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/amazonlaunchpad/de/Gateway/2018_02/iolandac_2018-02-05T15-59_0ebc52_1099615_de_launchpad_gw_quadcard_feb18_420x420_8._CB487250273_.jpg","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/default/browser/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/alilog/oneplus/entry.js?t=211637","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/alilog/??s/7.5.8/plugin/aplus_windvane2.js,s/7.6.8/plugin/aplus_client.js,aplus_cplugin/0.1.2/monitor.js,s/7.6.8/aplus_wap.js,aplus_cplugin/0.1.2/aol.js,s/7.6.8/plugin/aplus_spmact.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/L3H3CWomUsd.css","request_type":"css"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://swch.nimg.jp/img/system/article_thumbnail/ch2584365/1470116","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"http://pagead2.googlesyndication.com/pagead/js/r20180411/r20110914/activeview/lidar.js","request_type":"script"}
+{"origin":"http://www.so.com/","request_url":"https://notify.ssl.so.com/v1/list-messages?longitude=&latitude=&src=mso&tmp=1523791858&jshow=1&token=79f0830dc97a826840da53c9fc0922f05888e252&callback=jsonp1","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://dpm.demdex.net/ibs:dpid=66757&&dpuuid=L6N62llA&redir=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dadobe%26partner_uid%3D$%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/ny75r2x0?redir=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537148856%26val%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=14&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A14%7D&logFlag=uaction_1523791857874&t=1523791871876","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=9&redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D4222%26nid%3D1512%26put%3D%5BMM_UUID%5D","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pixanalytics.com/pa.gif?t=mainpage_index_mobile&ver=1.0&random=0.7477627814995631&document.referrer=&document.URL=https://m.pixnet.net/?&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https://m.pixnet.net/?&window.pageXOffset=0&window.pageYOffset=0&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla/5.0%20(Linux;%20Android%206.0.1;%20Moto%20G%20(4)%20Build/MPJ24.139-64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180413.110452&window.devicePixelRatio=3&_pix.login_name=a41f026f52b53327abdd6961a40522b0&_pix.owner=undefined&_pix.visitor=&_pix.openid=undefined","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://load77.exelator.com/pixel.gif","request_type":"image"}
+{"origin":"http://www.onclkds.com/","request_url":"http://www.onclkds.com/images/main.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/clash-of-clans-android.png:l","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"http://mat1.gtimg.com/www/images/qq2012/sogouSearchLogo20140629.png","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/undo_black.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/bao/uploaded/TB1FjNySpXXXXc8aXXXXXXXXXXX-200-200.png","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://hubt.pornhub.com/htcheck.html?site_id=3","request_type":"html"}
+{"origin":"http://www.alipay.com/","request_url":"http://www.alipay.com/","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/5f/90/f7/5f90f72a99448486625f5ba94e7f478c/5f90f72a99448486625f5ba94e7f478c.22.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d305ea0731c3b0d1f14.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/2017/campaign/1951620/181515/GW/181515-GW_1242x450-de-v1._SX1242_CB489581203_.jpg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/34022/1/0/1319/0/0","request_type":"text"}
+{"origin":"http://www.live.com/","request_url":"https://outlook.live.com/owa/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflUiilPi/logged_out_users.js","request_type":"script"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/edge_includes/edge.6.0.0.min.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_194.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://mem.gfx.ms/meversion?partner=office&market=en-us","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/hybrid/4.2.18/index.js","request_type":"script"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/css/v4/style.build.css?v=9bd4dace1","request_type":"css"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=MB94veh&sid=yLIOFNP835fT4D41H3-W","request_type":"other"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/base/JdBase69.min.js?v=jd201802175619","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/8c024cb0043360c0a183ef86569e5a97.js?conditionId0=422975","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTIxNzcmdGw9MTI5NjAw&piggybackCookie=CAESEDKTSR_83QQWyTtPvQPrDRg&google_cver=1","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/global/1.2.35/file/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"http://www.google.com.tw/","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://www.facebook.com/plugins/like.php?locale=en_US&href=http%3A%2F%2Fm.thepiratebay.se%2F&width=109&layout=button_count&action=like&show_faces=false&share=false&height=26","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100229752&apid=beans_13702&impid=05b38d2c323f33ffb_0_0&at=1&mkey=05b38d2c323f33ffb_0_0&latcy=2334&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=1567.515625&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DMK3qiCSC8Tis9Y48kp%2BL9DZ%2B%2B80jJsq5Gp7mE58tcdzEn%2BYy0L6Gh889XuI6%2F4Y%2FFOZpu46b1ime0AMVfbcEjSNTkCV7LSIQPStktAmqs5uAJjW%2F0njopVpMdpZ3%2BusbbPFIR3zgSjJ%2Bqoyoyrb5zg7lxVr%2BAGf2z7NjS2Qc7pgdyqTUWom9t8sTUkDzm%2FL04X609HIYvGHoLdJXYFASLnixHhRV1xcOHm%2BPVvkB2jqeP5zuranuEowAtjJJawYlU4friVibWcepz5FGuWNqkVzEHJ4Hozk5DxrJZxtDD6pKK%2B92xDS0X%2BzQDy3V8iF7ptRlmWGzWGzc9MjU1%2FYBLycZbwXutXvtxN3TqlG3aj2oTurvMsx3y9VOrKUVke%2F8dULsAaeytit%2F87pDqQzxIgHgbhdSX%2BnowDu67oJ38dACUoUeYldE9EVuXs%2FGBuKLs0IhBfsxmQGA36cczyq9ixEo%2FaeikomLjg68VuHf8U21ACsnQ9YQr0z4Ti6PsL9tlBUimm2Gv9vpfFDU49xK1bUjRrjF9GHXYu%2FyeSzo3HLKLwSzLAscXoQYAuVxBASyLcxyYN3L4WZumxra%2BPDJZTeLYDSlryfRCXU7FSS9jGI%3D%09tt2%3D1523791940118%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=4804819905898&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791940493","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=13&checkda=1&rver=6.7.6643.0&wp=MBI_SSL&wreply=https%3a%2f%2fwww.microsoft.com%2fen-us%2fmscomhp%2fonerf%2fMeSilentPassport%3fSilentAuth%3d1&lc=1033&id=74335","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://an.facebook.com/v2/placementbid.json?sdk=5.5.web&placementids[]=123410111540958_149188285629807&adformats[]=300x250&pageurl=https%3A%2F%2Fwww.msn.com%2F","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://ampcid.google.com/v1/publisher:getClientId?key=AIzaSyA65lEHUEizIsNtlbNo-l2K18dT680nsaM","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=www.wikia.com","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://h5.m.taobao.com/?sprefer=sypc00","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://p.rfihub.com/cm?in=1&pub=7085","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/b9pj45k4?redir=https%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D","request_type":"other"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/resources/images/0/sprite1.narrow.x2.css","request_type":"css"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/assets/page/Top/Top.css?de458c8765e3ad31deab7e1f4a4a7d02","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://s.amazon-adsystem.com/ecm3?id=164801102661000507459&ex=neustar.biz","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=74da20a019edb060273a","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://c1.adform.net/serving/cookie/match?CC=1&party=14&cid=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A776%2C%22netDns%22%3A304%2C%22netTcp%22%3A464%2C%22srv%22%3A742%2C%22dom%22%3A3548%2C%22loadEvent%22%3A15134%7D&et=87&ja=0&ln=en-us&lo=0&rnd=787321139&si=12423ecbc0e2ca965d84259063d35238&v=1.2.30&lv=1","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://segments.company-target.com/log?vendor=choca&user_id=AAD37E61pnEAAARIWdD9Bw","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/dragon-nest-m-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/zenhubio.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BB6Dp75.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fcmatch.youtube.com/pixel?google_gm=AMnCDophMBgwnebV5L2A8Y4SjOPNrQt2TuaYeI3zraD2oZAhmmB8iyR4EM7D-SNBs6WhaBHOBFo7pdB6IBlYHcLZZnXcJiiK1EAV-8qjZdgkoqF0CwQ68Ec","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p0.qhmsg.com/t01f222be1309c2fd7f.png","request_type":"image"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/icon-default.882fa4ccf6539401.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=icco6m5&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=3029559553","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/home.logged-out/page-domain-only/img/domain-first-background-2x.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/005/259/10c/big_lq/d8ac48a3c9f6e3c077647df21a34d95f.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1e/e2b0b711f26aa23615f017992faf7caf_erotic_285x160.jpg?cno=b6a","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/f5/f1/62/f5f16254de23337bff0f34d30a27a0ac/f5f16254de23337bff0f34d30a27a0ac.21.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/imgextra/i4/98/TB2wGBUfH5YBuNjSspoXXbeNFXa_!!98-0-luban.jpg_q50.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/AustinBundle-Mobile_billboard-a-de-1242x450._SX414_CB507116531_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=867653871984&t=17&plc=MOBILE&tkn=*smVgOBAkmzsofBLxtrpL1prtAFI","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/34022/0/0/337/0/0","request_type":"text"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://rec.scupio.com/recweb/ggid.aspx?layout=js&google_gid=CAESEBKxcYd1Ou9D2gc3ugimK6M&google_cver=1&google_ula=3918219,0","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_194.js?v=195","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/20170524zepto.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://universal.iperceptions.com/core/IpEngine_v77.1.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-fallback/td-applet-viewer-templates-fallback-min.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://cdn1d-static-shared.phncdn.com/jquery-2.0.3.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.onclkds.com/","request_url":"http://fonts.googleapis.com/css?family=PT+Sans&subset=latin,cyrillic-ext","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://a2.espncdn.com/combiner/i?img=%2Fphoto%2F2018%2F0414%2Fr356726_1296x864_3%2D2.jpg&w=750&h=500&scale=crop&cquality=40&location=center","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=yieldmo&google_hm=ZzllNTE2MDJhZTAzYmNlNGJkZmE=","request_type":"html"}
+{"origin":"http://www.blogspot.com/","request_url":"http://www.blogspot.com/","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j46&tid=UA-53389718-2&cid=31773146.1523791847&jid=424931812&_u=SGCAiEABB~&z=1780281530","request_type":"html"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/css/s_yzg.css?196","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://invocation.combotag.com/controller.js","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"https://mc.yandex.ru/watch/23969905?wmode=7&page-url=http%3A%2F%2Fcoccoc.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A2%3Aw%3A360x512%3Az%3A-420%3Ai%3A20180415043108%3Aet%3A1523791868%3Aen%3Autf-8%3Av%3A1072%3Ac%3A1%3Ala%3Aen-us%3Awh%3A1%3Apv%3A1%3Als%3A202063798655%3Arqn%3A1%3Arn%3A1005486478%3Ahid%3A1047608455%3Ads%3A342%2C473%2C499%2C46%2C2698%2C0%2C0%2C2228%2C52%2C17431%2C17433%2C7%2C4944%3Afp%3A4342%3Arqnl%3A1%3Ast%3A1523791869%3Au%3A1523791868847094136%3At%3ATr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/bundles/weather.952f6a9b7cc5a236ee07.bundle.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://img.scupio.com/js/ad.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://stags.bluekai.com/site/36841?dt=0&r=1131335851&sig=266897515&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmih1xvl5HuFzEzhvgXwBlWkmnvTonDUnlAda0QjeWxo0q7s3LSrtVZ3O3f3O3jhe+8hTKsKQvjj3APxvsA7BnDf1H1i9Rp9W1JcNA=","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:146-2652873-2143838:6983MGHS2ZBMHXB1G0WS$uedata=s:%2Fuedata%3Fld%26v%3D0.200481.0%26id%3D6983MGHS2ZBMHXB1G0WS%26sw%3D360%26sh%3D512%26vw%3D360%26vh%3D512%26m%3D1%26sc%3D6983MGHS2ZBMHXB1G0WS%26ue%3D16%26bb%3D1850%26ns%3D1939%26ne%3D2041%26cf%3D2042%26af%3D2074%26be%3D5146%26pc%3D17425%26tc%3D-2821%26na_%3D-2821%26ul_%3D-1523791925687%26_ul%3D-1523791925687%26rd_%3D-1523791925687%26_rd%3D-1523791925687%26fe_%3D-61%26lk_%3D-1761%26_lk%3D-1414%26co_%3D-1414%26_co%3D-625%26sc_%3D-1044%26rq_%3D-625%26rs_%3D-75%26_rs%3D233%26dl_%3D-46%26di_%3D5189%26de_%3D5189%26_de%3D5484%26_dc%3D17424%26ld_%3D17424%26_ld%3D-1523791925687%26ntd%3D-2%26ty%3D0%26rc%3D0%26hob%3D9%26hoe%3D17%26ld%3D17431%26t%3D1523791943118%26ctb%3D1%26rt%3Dcf%3A4-2-2-0-2-0-1_af%3A4-2-2-0-2-0-1_ld%3A62-8-3-44-8-0-0%26csmtags%3Dfls-na%26viz%3Dvisible%3A16%26tid%3D6983MGHS2ZBMHXB1G0WS%26aftb%3D1:17434","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://t.paypal.com/ts?v=1.2.1&t=1523791851865&g=420&e=im&pgrp=mobile%3Amktg%3Apersonal%3A%3Ahome&page=mobile%3Amktg%3Apersonal%3A%3Ahome%3A%3A%3A&tmpl=home.dust&pgst=Unknown&calc=3bed060a56ffb&rsta=en_US&pgtf=Nodejs&s=ci&csci=a48171c74be7404188bafb47a9d2f7f1&comp=mppnodeweb&tsrce=mppnodeweb&pgld=Unknown&ccpg=us&bzsr=main&bchn=mktg&pgsf=personal&lgin=out&shir=mobile_mktg_personal_&pros=3&lgcook=0&gacook=31773146.1523791847&akdc=phx-origin-www-2.paypal.com&pt=Send%20Money%2C%20Pay%20Online%20or%20Set%20Up%20a%20Merchant%20Account%20-%20PayPal&cd=24&sw=360&sh=512&dw=1080&dh=1536&bw=360&bh=512&ce=1&t1=0&t1c=0&t1d=0&t1s=0&t2=799&t3=55&t4d=8821&t4=8821&t4e=0&tt=12535&view=%7B%22t10%22%3A2869%2C%22t11%22%3A12535%2C%22t14%22%3A1523791839308%7D&res=%7B%22css%22%3A%7B%22t9%22%3A2385.2%2C%22t12%22%3A2385.2%2C%22t13%22%3A0%2C%22cnt%22%3A1%7D%2C%22scr%22%3A%7B%22t9%22%3A5633.5%2C%22t12%22%3A3419.2%2C%22t13%22%3A0%2C%22cnt%22%3A22%7D%2C%22img%22%3A%7B%22t9%22%3A8723.4%2C%22t12%22%3A2479.7%2C%22t13%22%3A0%2C%22cnt%22%3A7%7D%2C%22othr%22%3A%7B%22t9%22%3Anull%2C%22t12%22%3A0%2C%22t13%22%3A0%2C%22cnt%22%3A2%7D%2C%22xhr%22%3A%5B%7B%22nm%22%3A%22nexus.ensighten.com%2F...%2FserverComponent.php%22%2C%22t4%22%3A7358.9%2C%22t5%22%3A7674.6%2C%22t6%22%3A8313%2C%22t7%22%3A7358.9%2C%22t8%22%3A7358.9%2C%22t9%22%3A1281.5%2C%22ta%22%3A7355.7%2C%22tb%22%3A0%2C%22tc%22%3A0%2C%22td%22%3A8313.8%2C%22te%22%3A8634.8%2C%22tf%22%3A8637.2%2C%22t10%22%3A7355.7%7D%5D%7D","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/icons/af-beta/f1438875-9677-4b63-ad78-daa91a21cc71.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/uber-android.png:xl","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/arDown@2x.png","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/play-button._CB318667375_.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/d/inn/626458d9/pull-down-icon.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://wuliao.epro.sogou.com/ask/?callback=jsonp_1523791938310_1652009886992&id=563067&_time_=1523791938307","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/4ebfa4bb-fae7-4de7-9737-699242f7c343_desktop.png?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180412171406-01-wendy-vitter-0411-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f12/2a3612eb5d3072f5c8c5812c5daea90b_erotic_285x160.jpg?cno=01a","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/wABYO5k_FBr6TXEz96zIijs2myHGcSkXd7bcf_nlMQk.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51WWPA21koL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51WWPA21koL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/A1tSbR5LGZL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/I/719QfP+EF5L._AC_SR300,300_.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://conductor.clicktale.net/monitor?t=init&p=147&2=2927199622326975&v=1.4.86","request_type":"text"}
+{"origin":"http://www.gmw.cn/","request_url":"http://www.gmw.cn/favicon.ico","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/trans.svg","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-ExplorePage-64cc9fdf08d1739cc652.js","request_type":"script"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/portal/wikipedia.org/assets/js/index-47f5f07682.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/bannertext?bannerid=37964&zoneid=614&","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE1xHWh","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_nba_heat_76ers_hl/dm_180414_nba_heat_76ers_hl.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/html/r20180411/r20170110/zrt_lookup.html","request_type":"html"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1305711254&t=pageview&_s=1&dl=https%3A%2F%2Fstackoverflow.com%2F&ul=en-us&de=UTF-8&dt=Stack%20Overflow%20-%20Where%20Developers%20Learn%2C%20Share%2C%20%26%20Build%20Careers&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAEAB~&jid=2034509058&gjid=1310802496&cid=1866685655.1523791909&tid=UA-108242619-1&_gid=1525920554.1523791909&_r=1&cd3=Home%2FIndex&z=592075546","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://ads.yahoo.com/cms/v1?esig=1~b9bada6fffbf45c1ffda7783879fb5715486894a&nwid=10000922750&sigv=1","request_type":"text"}
+{"origin":"http://www.mail.ru/","request_url":"https://id.rlcdn.com/463496.gif?credir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAw&redirect=1","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://mapi.m.jd.com/config/display.action?_format_=json&domain=http%3A%2F%2Fwww.jd.com%2F","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/js/es.v10.260.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://ad.doubleclick.net/ddm/adj/N4427.ESPN/B20928537.217269349;dc_ver=41.108;dc_eid=40004001;sz=320x50;u_sd=3;dc_adk=2035887584;ord=qga90u;click=https%3A%2F%2Fadclick.g.doubleclick.net%2Fpcs%2Fclick%3Fxai%3DAKAOjsskQ5rxJ20jr8hAUaM8_LqEojxhslY4XYJ8HlY0VtHT6PyKLQYnGXI7pKg5AHJNrYoIl39Ip7l2cWEWi8Un5ZgI0mE0iuyYrXKVmvUxATwYpON2modY53q_NhaX5anle-zvx15SOqkjiJtnk0TJ7fPbrh7sn2rWHcEVC3jCegN2hIRLR-_FKbWgHXCuvYmAde7YRsATVrWozgYODYn5KoafeF5qYAjF8pv85F7Ch-6rIHOGlAIK6mtAfakdnXol%26sig%3DCg0ArKJSzC2kEMEIA8bcEAE%26urlfix%3D1%26adurl%3D;dc_rfl=1,http%3A%2F%2Fwww.espn.com%2F$0;xdt=0;crlt=X-GMH'M_rY;osda=2;sttr=2219;prcl=s","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://syndication.twitter.com/settings","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/_td_api?_appletType=viewer&_p=p1&authed=0&browserName=CH&browserVersion=58&bucket=900&cookieCapCount=2&crumb=&default_appletinit=now&default_page=p1&device=smartphone&enable_dd=&guid=&lang=en-US&locdrop_crumb=&mcCrumb=&messageCookieName=pmc&osName=Android&osVersion=6.0.1&region=US&rid=9rcrpl9dd6e1s&site=fp&ssl=1&ucsCrumb=&woeid=2487956","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://c.msn.com/c.gif?udc=true&rid=e86f55f780704d568af4af783e3cb6c4&rnd=636593886315667499&rf=&tp=https%253A%252F%252Fwww.msn.com%252F&di=340&lng=en-us&cv.product=prime_mobile&pn=startpage&activityId=e86f55f780704d568af4af783e3cb6c4&d.dgk=tmx.mobile.webkit.android&d.imd=1&st.dpt=&st.sdpt=&subcvs=homepage&pg.n=startpage","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/lsp.aspx","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://i.liadm.com/s/32441?bidder_id=88068&bidder_uuid=39041E2B94ED6EF00CB315F995BE6F73&_li_chk=true&previous_uuid=c95ab964aa8741ffbc7fef142f95d8fe","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://pixel.wp.com/t.gif?lp_name=logged-out-homepage&lp_variation=&do_not_track=0&country=US&locale=en&platform=Android&utm_source=&utm_campaign=&ref=homepage&affiliate=&_en=wpcom_homepage_view&_ui=zDW8PEy7OW5KBlV2LVBtGlDi&_ut=anon&_ts=1523791844016&_tz=7&_lg=en-US&_pf=Linux%20x86_64&_ht=512&_wd=360&_sx=0&_sy=0&_dl=https%3A%2F%2Fwordpress.com%2F&_dr=&_rt=1523791844025&_=_","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d9131731.gif?sz=10&rnd=264337554&ts=1523791836&sz=10","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://e.visualdna.com/conversion?partner_user_id=L6N7iig7&bust=1523791991133&id=sync&_kdpid=8f95f20d-4acf-43fc-9832-3f5174a166cc&api_key=krux&do_not_cookie=1","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://popads-trustguard.cdn77-ssl.net/security-5270-mini.gif","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/sprites/toolbar-set/83b18f0a8ee581427f77ef40fc876b5c@2x.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/vidmate-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/scroll-bar-mask@2x.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://static.exosrv.com/images/close-icon-circle.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/yingxun20171026-56.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/juhuasuan1222icon.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB14STmirGYBuNjy0Fo763iBFXaB.png","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/tcbox?service=bdbox&action=pblog&ctv=2&cen=uid_ua_ut&data=%7B%22appid%22%3A%221%22%2C%22dataid%22%3A%222%22%2C%22actiontype%22%3A%221%22%2C%22actionid%22%3A%222%22%2C%22actiondata%22%3A%7B%22ref%22%3A%22%22%2C%22gmv%22%3A%22%22%2C%22source%22%3A%22%22%2C%22boxVersion%22%3A0%2C%22boxPlatform%22%3A%22android%22%2C%22evtName%22%3A%22openBox%22%2C%22evtType%22%3A%221021206d%22%2C%22evtTag%22%3A%7B%22source%22%3A%221021206d%22%2C%22from%22%3A%22openbox%22%2C%22page%22%3A%22chrome%22%2C%22type%22%3A%22%22%2C%22value%22%3A%22%22%2C%22channel%22%3A%221021206r%22%2C%22extlog%22%3A%22%22%2C%22baiduId%22%3A%221E50D7162CFCE685997D1E1338B1437B%3AFG%3D1%22%2C%22app_now%22%3A%22chrome_1523791826034_3691567195%22%2C%22yyb_pkg%22%3A%22com.baidu.searchbox%22%2C%22idmData%22%3A%7B%22firstOpen%22%3A%22lite%22%2C%22secondOpen%22%3A%22main%22%2C%22status%22%3A%220%22%2C%22timeout%22%3A1523878220839%7D%2C%22matrix%22%3A%22lite%22%7D%7D%2C%22cateid%22%3A14%7D&_rnd=195175721","request_type":"html"}
+{"origin":"http://www.blogspot.com/","request_url":"https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2","request_type":"font"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuBP1G.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2770476040,3160935778&fm=173&app=25&f=JPEG?w=218&h=146&s=BD226D9158617A8426295D620300E0F0","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/8V4GEfpKEbqSHj6kNAPTuvaaYFaNq-G1yi45UzfSiBM.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/61N6V2GDTAL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/log","request_type":"text"}
+{"origin":"http://www.google.com/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=124&cm=35586261218113811292146848081187597150","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/gizmo/js/home.min.js?v=ZXwYl5FOGo6fOqaYod13H35-JXTXgGl8FE-2JN7NCN0","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://hm.baidu.com/hm.js?6bcd52f51e9b3dce32bec4a3997715ac","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://images.apple.com/metrics/ac-analytics/2.2/scripts/gpu.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/js/lib-d97d6747f8.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V3RNMzR3QUFDR01mUGZ5UQ&url=/1/gr%3furl=https%253A%252F%252Fimage2.pubmatic.com%252FAdServer%252FPug%253Fvcode%253Dbz0yJnR5cGU9MSZjb2RlPTI2NjgmdGw9NDMyMDA%253D%2526piggybackCookie%253D__EFGSURFER__.__EFGCK__","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V3RNMzR3QUFDR01mUGZ5UQ&url=/1/gr%3furl=https%253A%252F%252Fpixel.everesttech.net%252F1x1%253F","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/","request_type":"html"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/gen_204?atyp=csi&ei=1DfTWsDQNeqB0wKXjYPQBw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.17,jhsl.2190&rt=aft.373,dcl.362,iml.373,ol.2816,prt.223,xjs.1694,xjsee.1694,xjses.1391,xjsls.243,wsrt.2245,cst.712,dnst.0,rqst.812,rspt.410,sslt.385,rqstt.1736,unt.2144,cstt.1016,dit.2608&zx=1523791832050","request_type":"html"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpssp.alimama.com/acookie.html","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://platform.twitter.com/widgets/widget_iframe.73a792b0fbc7ab73a8e3b3db9c36a8ac.html?origin=http%3A%2F%2Fwww.espn.com","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WtM4gQAABibm4O17","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://d.company-target.com/ul_cb/pixel?type=js&id=1421361246&page=https%3A%2F%2Fwww.adobe.com%2F","request_type":"script"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.krxd.net/controltag/ITb_4eqO.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/io-upload-iframe/io-upload-iframe-min.js","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-js-9a10b8f6/js/js/signup%7Csimplicity%7CsimpleSignupClient.js/2/4QgC0ogxgag84Egcgp0E0v4yghgB0s0S02gDgggjgd0Bgwgt4Igig5gm4L4K1x/l/true/none","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/scripts/vendor/yahoo/rapid/rapid-3.42.2.js?_v=5459b85e970537e82d0ae9fd51b0aa0e","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://stags.bluekai.com/site/26357?id=L6N7iig7&redir=https://beacon.krxd.net/usermatch.gif?_kuid%3DL6N7iig7%26partner%3Dbluekai%26bk_uuid%3D%24_BK_UUID","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/rebrand/elements/footer-vfldhsBW9.css","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/pkg/page/index/index.tpl_aio_466b034.css","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=adobe.com&id=00621027350807382491119119941113197141","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=110&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A110%7D&logFlag=uaction_1523791857874&t=1523791967876","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/tr/?id=348538655570151&ev=Microdata&dl=https%3A%2F%2Fwww.pinterest.com%2F&rl=&if=false&ts=1523791924446&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Asite_name%22%3A%22Pinterest%22%2C%22og%3Adescription%22%3A%22Discover%20recipes%2C%20home%20ideas%2C%20style%20inspiration%20and%20other%20ideas%20to%20try.%22%2C%22og%3Aimage%22%3A%22https%3A%2F%2Fs.pinimg.com%2Fimages%2Ffacebook_share_image.png%22%2C%22og%3Atitle%22%3A%22Pinterest%22%2C%22og%3Atype%22%3A%22website%22%2C%22og%3Aurl%22%3A%22https%3A%2F%2Fwww.pinterest.com%2F%22%2C%22twitter%3Aapp%3Aandroid%22%3A%22com.pinterest%22%2C%22twitter%3Aapp%3Aid%3Aipad%22%3A%22429047995%22%2C%22twitter%3Aapp%3Aid%3Aiphone%22%3A%22429047995%22%2C%22twitter%3Acard%22%3A%22summary_large_image%22%2C%22twitter%3Asite%22%3A%22%40pinterest%22%7D&cd[Meta]=%7B%22title%22%3A%22Pinterest%22%2C%22meta%3Adescription%22%3A%22Discover%20recipes%2C%20home%20ideas%2C%20style%20inspiration%20and%20other%20ideas%20to%20try.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=30&it=1523791918963","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a67342300005ad3387f10ed70f38aa5&pid=mm_113716014_12970037_52768243&cid=92223&mid=70785&oid=149&productType=1&qytInfoMTime=1523728959&cb=873856087","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://secure.adnxs.com/mapuid?member=1961&user=c9124a721620ac05558e318cffff4d04","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p3.qhmsg.com/t01abe6ce0386485d19.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/index/erjiicon/dushu_0b2a37e.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/main/home.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://sync.1rx.io/usersync/clickagy/WtM35B__DJPpGsQgT1fYqPHA?dspret=1&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D139%26cm%3D%5BRX_UUID%5D","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ape/sf/mobile/msf-1.19._V497204134_.html","request_type":"html"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/usUAAOSweM1aTA7G/$_57.JPG","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$slidingtiles/ic/b44fce8e/f5f36af7.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s1125x549_jfs/t18733/183/1623991221/147112/2d6c7314/5ad03b7fN5e43020a.jpg!cr_1125x549_0_72!q70.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/67f3ce5b-718e-4937-90b2-91e3988716c3_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0412/dm_180412_WNBA_Storm/dm_180412_WNBA_Storm.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180321154513-starbucks-igualdad-salarial-vo-portafolio-00000005-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1iiXZQFXXXXbeaXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/3cace201-0f77-43e4-ba7f-8f43abcffea9/scale-to-width-down/100","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-button-cheeseburger__black-vflOBpd_i.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/images/ad-choices.svg","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mem.gfx.ms/me/MeControl/9.18088.0/en-US/meBoot.min.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cdn.diply.com/resources/js/headroom-0.9.3.min.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/iconfont/iconfont_04b353e.woff","request_type":"font"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/speed.min.js?v=170721","request_type":"script"}
+{"origin":"http://www.popads.net/","request_url":"https://www.popads.net/js/did_challenge.js?1516108355","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/5bcf3389ad1a8863e6427f42ec6e0fab.js?conditionId0=597156","request_type":"script"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/js/jquery.popupoverlay.js?1516108355","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a2.espncdn.com/combiner/i?img=/media/motion/2018/0414/ss_20180414_174339493_10377671321/ss_20180414_174339493_10377671321.jpg&w=686&h=386&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_cm&google_nid=krux_digital&google_hm=TDZONjJsbEE%3D","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.pubmatic.com/AdServer/js/user_sync.html?p=156011&s=165626&predirect=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID","request_type":"html"}
+{"origin":"http://www.xvideos.com/","request_url":"http://www.xvideos.com/","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://bttrack.com/dmp/adobe/user?dd_uuid=91191954147729940174299115411397659455","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/en-us/","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://ads.yahoo.com/cms/v1?esig=1~6772d6d12bf5fd5c41ee5ef107d84db09124942a&nwid=10000936839&sigv=1","request_type":"text"}
+{"origin":"http://www.adobe.com/","request_url":"http://www.adobe.com/","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://api.branch.io/v1/event","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/js/7e545a0/vipModule.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"http://www.cnn.com/","request_type":"other"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalfooter/3/en_US/styles/ac-globalfooter.built.css","request_type":"css"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-cc74e8bbc07/v3/css/default/main.css","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://tag.researchnow.com/t/beacon?adn=3&ca=20912526&cr=67442974&ord=2354632686&pl=217082534&pr=12237&si=2920918","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://alb.reddit.com/i.gif?q=CgADAAAAAAAHad4KAAUampD8jAJivgoABhqakPyMAGK-CAAHAAAABwA=&s=vqMwpQcztmcrGwxaRtWPVx9_PB7Dx5Aezj7JtXmH_mo=","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://www.facebook.com/tr/?id=627392657291988&ev=fb_page_view&dl=http%3A%2F%2Fdiply.com%2F&rl=&if=false&ts=1523791965853&sw=360&sh=512","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1064110684/?userId=zRhX-wgESeaIgZSO5fmQkg&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/icons/ajax-loading-small@2x-vflAxdZTP.gif","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://top-fwz1.mail.ru/counter2?id=2579437;pid=0;r=https%3A%2F%2Fm.vk.com%2F","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t17509/324/1413437865/15080/f7029302/5ac98982Nf9710996.png","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe.demdex.net/dest5.html?d_nsid=0","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ape/sf/mobile/msf-1.19._V497204134_.html","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://amplifypixel.outbrain.com/pixel?mid=00f0f5287433c2851cc0cb917c7ff0465e&dl=https%3A%2F%2Fwordpress.com%2F&bust=0670437474071371","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$rewardsquiz/ic/62e26c9c/4d15d5bc.jpg","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://img.revcontent.com/?url=https://revcontent-p0.s3.amazonaws.com/content/images/15234607210796219104.jpg&static=true&pos=face&h=315&w=420&static=true&fmt=jpeg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/88/93/d8/8893d88308c51ad71a340447d941f39b/8893d88308c51ad71a340447d941f39b.28.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5506000/5506755/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BN2M3NmM3YTAtZmRmYy00OWQzLTg0ZDYtNWQ4ZDU1NTU0ZmE3XkEyXkFqcGdeQXVyNjQ4ODE4MzQ@._CR67,0,1019,573_UX1248_UY702._SX700_CR0,0,700,393_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/I/815uOE8DvAL._AC_SR300,300_.jpg","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://beacon.tingyun.com/xhr1?pvid=c5f0d6a8-d452-4523-9ca8-4a0813517a9a&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=fad86f04-fa3a-4f2f-a92a-15fae388816e&sid=676406ea-440a-48bc-820a-57146ad87968&__r=1523791933765","request_type":"text"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/menu.svg?v=1","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-button-close-vflzGggYo.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://serve2.combotag.com/show_pla?id=65349&url=https%3A%2F%2Fwww.cnn.com%2F&sf=0&k=cnn%2Bbreaking%2Bnews%2Blatest%2Bnews%2Band%2Bvideos%2Bview%2Bthe%2Blatest%2Bnews%2Band%2Bbreaking%2Bnews%2Btoday%2Bfor%2Bus%2Bworld%2Bweather%2Bentertainment%2Bpolitics%2Band%2Bhealth%2Bat%2Bcnncom%2Bcnn%2Bnews%2Bdaily%2Bnews%2Bbreaking%2Bnews%2Bnews%2Btoday%2Bcurrent%2Bevents&idx=0&tpi=&tpc=&ch=%7B%22publisherId%22%3A185%2C%22pvid%22%3A%22a846f5dd0c5ccc7b4f5261a2c22572b4%22%2C%22widgetIds%22%3A%22MB_12%2CTR_1%22%2C%22req_id%22%3A%22a846f5dd0c5ccc7b4f5261a2c22572b4%22%7D&cb=1523791878149","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/mediamain.html?&cid=8CUNL3XVM&cpcd=NaEyhZu73BMxXJoVzER-IQ%3D%3D&crid=144402028&pid=8PO87SA5G&size=414x74&cpnet=yVb1sHm-0KKoFeunLBVJxb3ZXfCH9IPr_ybE0RUc-8E%3D&cme=KkKUG6JLaWptcd7ygVoZgW_gowIx32vSl5tlbUoHIlTwG_Hajq4qm8TPaunw8hu-gs5H0j_cu9dNg1SpNWSXZk_dUMBskfm2DCZac_fs9rdNqOZacpYzAHiUO_JWt2C2%7C%7CNDHRnZ9Gz3KXlI-i9OnZqQ%3D%3D%7C5gDUJdTGiJzedmq9hanWYg%3D%3D%7CfTACDBAb70YAH7VJEs6iY7FiuYJwPXfy%7CN7fu2vKt8_s%3D%7CYdjFvixrVaHKWoanJxQ7pIbs71hugNrT_9Dy98sN7BVysk146vCoY0D8h8dpPPEv%7CsRBSg3CPSiQ%3D%7C&https=1&cc=US&bf=0&staticIframe=1&vif=1&vi=1523791837719580622&lw=1&ugd=3&ib=0&nb=1","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://rpc-php.trafficfactory.biz/json/footermobile-1///xvideos////content.json?v=0.33800689158206554","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-vertical-video-util/td-applet-viewer-vertical-video-util-min.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://native.sharethrough.com/assets/sfp-creative-hub-listener.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/asset/js/main/common/site_wide.min.js?b03653c9bf3c0a2b71c5b18adf9c4089","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-57d1b3c664746d361f00d3cc.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938170_9640836385932&itemspaceid=13784&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938170&cnid=228293500,228287633,228328502,228305798,228299913,228324890","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://v2.sohu.com/public-api/frag/bussiness_touch_index?callback=jQuery33107277789616181776_1523791937756&_=1523791937757","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://cdn.taboola.com/libtrc/impl.thin.301-1-RELEASE.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=https://beacon.krxd.net/data.gif?_kuid%3DL6N7iig7%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=477&dpuuid=0a86896aa120602416161f5fd48d117aadd02b8924497fd6eb1e7b45967c248bb0da87c991749652&redir=https%3A%2F%2Fidsync.rlcdn.com%2F362248.gif%3Fpartner_uid%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/obsidian/logo-vflM1D8V1.css","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/pms/img/st.gif?ts=9a3&t=pageview&sid=jg0qejmoia3&ver=5&pid=241&px=360*512&page=9_3252&p=9&dv=6&cmd=open&ps=360%2C926","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=adobe.com&id=72373945200313814400723130151706788186","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=80&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A80%7D&logFlag=uaction_1523791857874&t=1523791937876","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/msn-msn-home/log/2/debug?tim=04%3A30%3A43.057&type=warn&msg=blocked%3A0-0-1-unknown&id=5006&cv=301-1-RELEASE","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/sync?tdid=2e68b153-5f6c-4bef-a554-4d86b35719b5","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.google.com/ads/user-lists/1064110684/?userId=zRhX-wgESeaIgZSO5fmQkg&guid=ON&script=0&cdct=2&is_vtc=1&random=767551373","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/co_create/img_preload-vfll4wb7k.png","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"http://tpc.googlesyndication.com/safeframe/1-0-23/html/container.html","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=054f32o&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/G4_lGzMF6WUm2-Lzx4O4HA/009/340/869/320x240.1.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=67876451,2961783442&fm=173&app=25&f=JPEG?w=218&h=146&s=45A898F24C1B57D415A7F2B00300B005","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/017/1ef/325/big_lq/9e8d869ffd49644d5de1253f50f7af72.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/U7Naa3_svbZvfj-J6xc7e75rcnfMPlvl9VbNBHFT57A.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/6119FxRp37L._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t01e7d10a542b31b65f.webp?size=600x450","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://fastcast.espn.com/public/rotationip","request_type":"text"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ads.trafficjunky.net/ads_batch?format=json&clientType=mobile&data=%5B%7B%22spots%22%3A%5B%7B%22zone%22%3A1686541%2C%22site%22%3A23%7D%5D%7D%5D&cache=1523791902&channel%5Bsite%5D=pornhub&channel[context_page_type]=home","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.txxx.com/js/advertising.js?v=haosq","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/bcb41607f75ea330dedec9a4085353b5.js?conditionId0=422975","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"http://www.uptodown.com/","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=taboola_dbm&google_cm=&google_sc=&google_tc=","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://www.amazon.co.jp/gp/gw/ajax/card.html/358-6685975-3653550?ie=UTF8&opf_redir=1&rshVal=1523791971168","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.nicovideo.jp/api/recommended_video","request_type":"html"}
+{"origin":"http://www.livejasmin.com/","request_url":"http://www.livejasmin.com/","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.nicovideo.jp/","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/favorites/cfx","request_type":"html"}
+{"origin":"http://www.so.com/","request_url":"https://uflow.news.so.com/stream?src=so_h5&category=__all__&sign=search&ac=unknow&scene=so_mobi_home&https=0&version=1.0.0&idx=2&src=mso_home&s=q&ua=0&src=mso-home&action=1&u=34870781.245367792129314460.1523791856399.254&callback=jsonp4","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"http://h5api.m.tmall.com/h5/mtop.user.getusersimple/1.0/?jsv=2.4.11&appKey=12574478&t=1523791821652&sign=892d1785a3e46dd3882630f5b49ebb17&api=mtop.user.getUserSimple&v=1.0&H5Request=true&jsonpIncPrefix=smb_xc&timeout=2000&type=jsonp&dataType=jsonp&callback=mtopjsonpsmb_xc2&data=%7B%7D","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=2852445905525890&output=json_html&callback=googletag.impl.pubads.callbackProxy2&impl=fifs&adsid=NT&json_a=1&eid=21061884%2C21061149%2C21061569&sc=0&sfv=1-0-23&iu_parts=6444%2Cespn.com%2Cfrontpage%2Cindex&enc_prev_ius=%2F0%2F1%2F2%2F3%2C%2F0%2F1%2F2%2F3&prev_iu_szs=1x2%2C320x50&rcs=1%2C0&prev_scp=pos%3Dexclusions%7Cpos%3Dtop&eri=1&cust_params=ed%3Dus%26sp%3Despn%26pgtyp%3Despnfrontpage%26swid%3D0A8AF6A3-114D-4E90-CE93-928476B93005%26mnr%3Df%26espn_yxbk%3DJvY4nr%25252Fn99YfE5BS%26prof%3Ds&cookie=ID%3D7274245ad695631a%3AT%3D1523792033%3AS%3DALNI_MbUj4dYC4oEkl15LuxSTRGFKRbWsw&cookie_enabled=1&abxe=1&lmt=1523792035&dt=1523792035752&frm=20&biw=360&bih=512&oid=3&adxs=0%2C20&adys=0%2C114&adks=3266571609%2C1002300037&gut=v2&ifi=4&u_tz=-420&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.espn.com%2F&dssz=38&icsg=2684879360&std=0&vrg=194&vis=1&scr_x=0&scr_y=0&psz=360x3233%7C360x3233&ga_vid=1381963191.1523792033&ga_sid=1523792033&ga_hid=98984504","request_type":"script"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://api.iperceptions.com/InviteTriggers","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41R8mzOgv0L.js?AUIClients/QTipsMobileWebAssets","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://ak1s.abmr.net/is/www.paypalobjects.com?U=/digitalassets/c/website/marketing/na/us/home/merchant-mobile-hero.jpg&V=3-frtuSY9s31VRONlGQlhs3m+Eh+uF01B2vzk1%2fY1LzGh8Hx659IvZDozqzG+SS57d&I=53768DB0999C88E&D=paypalobjects.com&01AD=1&","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1127&dpuuid=AB-yFUSf254zpmJwzQ5uoSKBA&redir=http%3A%2F%2Frs.gwallet.com%2Fr1%2Fucm%3Fid%3D%24%7BDD_UUID%7D%26r1s%3Dajt76zisxpejy89rz51fbpuz8kcb9r39ktr6uqzxk33zgx7t4zqy","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com","request_type":"other"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/css/aa4d7c5/android.core.css","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://s.amazon-adsystem.com/ecm3?id=164751602661000505378&ex=neustar.biz","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=164051302661000502281&ex=neustar.biz","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://stags.bluekai.com/site/26980?limit=0&id=g9e51602ae03bce4bdfa","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=Yjk0ZGJhNmMtY2M1Yy0zOGUxLWI2MmItYjNjMDExOTVhZDhkCTQ1CVBEUFMwMDAwMDAwNTc3NzgJNTAJMzUyMzgzMgkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=22054","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$MobileHeaderSprite2x/ic/e445f98b/0759ba51.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://m.360.com/","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://so.m.jd.com/solocalocalstorage.html","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4539000/4539813/220x165/7.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/client/transform/20171023/D5ii-fymzqpq3362791.png/w710h400z1l50t16b8.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/fe/b6/80/feb680fa4642987b577dbca4129c50b2/feb680fa4642987b577dbca4129c50b2.21.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20170306jtjkez.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61nrWDGVoOL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/ADQAAOSw-xNazjZ0/s-l225.webp","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1uUKJQFXXXXb4XXXXXXXXXXXX-1500-76.png_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/black/gear.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/js/all.min.js?v=e8869abe59f37ca1f0847c8fa8d65222","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/concat/common/js?h=e2lgukqldpqool72t8g7tysag-3nuvxgwg15rbghxm1gpzfbya2-1nm61x5u7981e88m10hpaekkm-mv3v66b8q0h1hvgvd3yfjv5f-14k913qahq3mh0ac0lh0twk9v","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/assets/frameworks-d941de838fad400fb91238d23684a777.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i&subset=cyrillic,hebrew,latin-ext","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/411MtgykU8L.css?AUIClients/GWMWebAssets","request_type":"css"}
+{"origin":"http://www.sohu.com/","request_url":"https://m.sohu.com/?pvid=000115_3w_index&jump=front","request_type":"html"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/js/jquery-1.8.2.min.js?1516108355","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMyMDMmdGw9NDMyMDA=&piggybackCookie=RX-0ae04aa7-7e04-405a-883e-8fc7518e9cc0","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://image6.pubmatic.com/AdServer/PugMaster?rnd=80268961&p=156011&s=165626&a=0&ptask=ALL&np=0&fp=0&mpc=0&spug=1&coppa=0&sec=1&kdntuid=1","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938281_9305019278883&itemspaceid=12292&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938281&plateid=1001800000,1001000000","request_type":"script"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/widget-base/widget-base-min.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/user-auth-1/js/main.js?v=13&_=1523791941891","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://aa.agkn.com/adscores/g.js?sid=9212244187&_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?p_user_id=HYc9c1dpSLWqgzShMqE45A&ex=twca&id=HYc9c1dpSLWqgzShMqE45A","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_edu-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://benchmark.1e100cdn.net/r20.gif?rnd=1-1-13960-0-0-32430-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.google.com/ads/user-lists/961332156/?value=1.00&currency_code=USD&label=ovrQCMHWrWAQvIezygM&guid=ON&script=0&cdct=2&is_vtc=1&random=1230060343","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/xender-android.png:l","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/i/android-touch-icon-192x192-3329a9ff53.png","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/6f/c4/5c/6fc45ccfe80e4b0413a7c07613d0932c/6fc45ccfe80e4b0413a7c07613d0932c.12.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d305ea14a1c3a5bce28.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://di.phncdn.com/videos/201803/30/160113672/original/(m=qYM78RTbeafTGgaaaa)(mh=PBNaydcU75D5Mlp5)0.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/Blwn6h.xVcJKFw3w34BC8w--~B/Zmk9c3RyaW07aD00MzI7cHlvZmY9MDtxPTgwO3c9NzY4O3NtPTE7YXBwaWQ9eXRhY2h5b24-/https://media.zenfs.com/creatr-images/GLB/2018-04-15/4a1f5490-4087-11e8-9a3e-d98d75606323_image-1909","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://beacon.tingyun.com/xhr1?pvid=c5f0d6a8-d452-4523-9ca8-4a0813517a9a&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=fad86f04-fa3a-4f2f-a92a-15fae388816e&sid=676406ea-440a-48bc-820a-57146ad87968&__r=1523791937764","request_type":"text"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://js.ptengine.jp/pts.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/js/pixnet/checklogin.min.js?v=e8869abe59f37ca1f0847c8fa8d65222","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/fonts/roboto-300.woff","request_type":"font"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/_h/57566d09/webcore/fonts/SegoeUI/WestEuropean/Segoe-UI.woff2","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/authenticator.min-vflhisjse.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://statics-uhf-wus.akamaized.net/west-european/shell/_scrf/css/themes=default.device=uplevel_web_pc/2f-4d7bb3/16-2a8b93/a7-5fcd4e/e5-4543a3/ac-64ad48/d8-a01341/ca-4fb444/e6-7dc25c?ver=2.0","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://z.moatads.com/turner763610601596/moatad.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjstoD532l9lPj6J9Y1hUZyE3_x99qQsIlnaU597mw0AoZkCbl4sUXsw0K30FYgqKzw4YEtpy6OZJNnFbvtuQf8nMuvJ2kbGCMDR9qRBypIzAm-cs5p-KNFD0S-qcL7xEy-k4EXpyjP0BHBQ6T0Hdr2UNOM4ASvuScKK4bM7Uzt__rw1RVTehX9u9OPcBcazeIQaSWxzsDi-5qilOAYBT3PTSfbNfeAJUMinQzFQNhdhPHC-YQKd3u7-BGn6YjFTbqoYXf33jwsQUFXgzwfaK&sig=Cg0ArKJSzFZ80jYFen6rEAE&urlfix=1&adurl=","request_type":"html"}
+{"origin":"http://www.github.com/","request_url":"https://github.com/","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://accounts.google.com/o/oauth2/iframerpc?action=checkOrigin&origin=https%3A%2F%2Fwww.pinterest.com&client_id=694505692171-31closf3bcmlt59aeulg2j81ej68j6hk.apps.googleusercontent.com","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/promise/promise-min.js","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/js/savefrom_6.36.min.js?v=1","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/rebrand_page-vflAfgzip.css","request_type":"css"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/css/2012_index.css","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?p_user_id=pavVoOCiQGy08CEOlgWPZQ&ex=twca&id=pavVoOCiQGy08CEOlgWPZQ","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.media-imdb.com/twilight/?PageType=homepage&Geo=US&tw_ord=04452aa6825bbf784219ea894cc601c70374e344&timestamp=2018-04-15T11%3A32%3A05GMT&Client=chrome&Site=mobile&Operation.1=csm_ready&OperationTiming.1=5200&Operation.2=csm_server&OperationTiming.2=124&Operation.3=csm_core_ads_iframe&OperationTiming.3=1834&Operation.4=csm_core_ads_request&OperationTiming.4=1910&Operation.5=csm_top_ad_tagdeliver.none&OperationTiming.5=5651&Operation.6=csm_core_ads_tagdeliver&OperationTiming.6=5651&Operation.7=csm_load&OperationTiming.7=17429&ord=8965773199915128","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/jjwAAOSwXCBaTAuD/$_57.PNG","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB13SW3QFXXXXawaXXXXXXXXXXX-108-105.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=pubmatic&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/5f2134a0-f482-44e0-8e3e-e0259cd96cef_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d30758a2f1c3a51503b.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d17469bdd8e2ced55f706e646a1e6b25_erotic_285x160.jpg?cno=cdf1","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d246cfdb48f00dbae7c0c19bc4e49ec2_erotic_285x160.jpg?cno=329","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/merchant-mobile-hero.jpg?01AD=3_0mxE2vvJibWeaTftmqgWy5AqnlAFp-HrNIREC2QXkYdws1mI5Rvhw&01RI=53768DB0999C88E&01NA=na","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_32,y_58,w_640,h_426/os/news/24d6967659bb12df81f2a557e41129f3.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img17/movies-tv/Oct/280x280_Quadcard_3._CB514398926_.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/favicon-vfl8qSV2F.ico","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-arrow-aqua-vflrYQuro.svg","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://api.pixnet.cc/api/checklogin.php?js=1&unique=4028333897&timestamp=1523792001&type=3","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/pub-config/r20160913/ca-pub-6865528665029394.js","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.googletagservices.com/tag/js/gpt.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/mwf/_h/v2.75/mwf.app/fonts/mwfmdl2-v2.75.woff","request_type":"font"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/alilog/??s/8.3.14/plugin/aplus_client.js,aplus_cplugin/0.3.19/toolkit.js,aplus_cplugin/0.3.19/monitor.js,s/8.3.14/aplus_std.js,aplus_cplugin/0.3.19/aol.js,s/8.3.14/plugin/aplus_spmact.js?v=20180411214439","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/css/home.en.260.css","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/floors/floor06006.js","request_type":"script"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/js-min/1F6WLu/ml.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://wordpress.com/wp-content/themes/h4/landing/marketing/js/affiliate-referrals.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://z.moatads.com/turnerdfpcwrefresh475219962180/moatad.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NBA_76ers_Sotfull/dm_180414_NBA_76ers_Sotfull.jpg","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/gen_204?atyp=csi&ei=FzjTWu61BIe28AOtqITQCw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.17,jhsl.2190&rt=aft.523,dcl.406,iml.523,ol.2728,prt.262,xjs.1658,xjsee.1657,xjses.1402,xjsls.276,wsrt.2186,cst.713,dnst.0,rqst.801,rspt.418,sslt.387,rqstt.1713,unt.2106,cstt.996,dit.2591&zx=1523791898115","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://b1sync.zemanta.com/usersync/yieldmo/?&cb=https%3A%2F%2Fads.yieldmo.com%2Fv000%2Fsync%3Fpn_id%3Dz%26userid%3D__ZUID__","request_type":"html"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.linkedin.com/","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/badge-google-play-en.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/960612778/?random=1523791866872&cv=9&fst=1523791866872&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/activeview/osd_listener.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=3858918433371674&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fifs&adsid=NT&json_a=1&eid=21061884%2C21061149%2C21061568&sc=0&sfv=1-0-23&iu_parts=5441%2Cwka.fandom%2C_home%2CHOME_TOP_LEADERBOARD%2CHOME_TOP_BOXAD&enc_prev_ius=%2F0%2F1%2F2%2F3%2C%2F0%2F1%2F2%2F4&prev_iu_szs=320x50%7C320x480%7C2x2%2C300x250&prev_scp=loc%3Dtop%26uap%3Dnone%26wsi%3Ddlh1%26src%3Dns%26pos%3DTOP_LEADERBOARD%7Cloc%3Dtop%26uap%3Dnone%26wsi%3Ddmh1%26src%3Dns%26pos%3DTOP_BOXAD&eri=1&cust_params=host%3Dwww.wikia.com%26kuid%3D%26lang%3Den%26outstream%3Dnone%26post_id%3D-1%26skin%3Dfandom_mobile%26s0%3Dfandom%26s1%3D_fandom%26s2%3Dhome%26esrb%3Dteen%26vertical%3Dhome%26s0v%3Dhome%26wsi%3Ddxh1&cookie_enabled=1&abxe=1&lmt=1523791985&dt=1523791985887&frm=20&biw=360&bih=512&oid=3&adxs=0%2C30&adys=0%2C651&adks=3854150723%2C3769845389&gut=v2&ifi=1&u_tz=-420&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&dssz=29&icsg=8320&std=0&vrg=194&vis=1&scr_x=0&scr_y=0&psz=360x55405%7C323x-1&ga_vid=970841907.1523791982&ga_sid=1523791986&ga_hid=880546608","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/dmedianet.js?geo=en-us&property=homepage&device=mobile&https=1","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://service-auth.diply.com/api/v1/auth/view","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/mfp/view?type=3&t=MjAxOC0wNC0xNSAxOTozMDo1NAkxNDkuMjAuNjMuMTMJX18xNDkuMjAuNjMuMTNfMTUyMzc5MTgyMF8wLjE5MjM0ODAwCWh0dHA6Ly9zaW5hLmNuLwlQRFBTMDAwMDAwMDU3NzkzCTkwOTUyMTZmLTkwNzItNGE0YS04MmUyLWNlNTBiYTljZTFkZQk4MDE3XzY5MzIJMTI3NTUJYXV0b19sZXZlbDoxODAxMDB8dXNlcl9ncm91cDo5MDB8d2FwX29zOjcwMXx1c2VyX2FnZTo2MDB8dXNlcl9nZW5kZXI6NTAwfF92X3pvbmU6Nzc3MDAwLDc3NzI4MHxhdXRvX3ByaWNlOjE4MDIwMHxtb2JpbGVfYnJhbmQ6MTIwOXxuZXRfd2lmaToxMTAyfGNhcnJpZXI6MTgwNDAwfHBvczpQRFBTMDAwMDAwMDU3NzkzLFBEUFMwMDAwMDAwNDA1MTksQTI1RDI1OUIwOEU2LFBEUFMwMDAwMDAwNDk2MjksUERQUzAwMDAwMDA1NDY3MSxQRFBTMDAwMDAwMDU1NjIyLFBEUFMwMDAwMDAwNTQ2NzIsRTlENkFDNEYzNDhFfHZfem9uZTo3NzcwMDAsNzc3MjgwfG1vYmlsZV9icm93c2VyOjgwNXx2ZXJzaW9uOmRlZmF1bHQJCTc3NzAwMHw3NzcyODAJNTgyNzkxODI3MAlNQjE4MDMxMzE4CS0JODAxNwlXQVAJLQkyNwktCS0JLQktCS0JLQktCS0JLQktCXN0cmF0ZWd5X2xyX2N0cl9pZGVhX3VtYwkyCTkJaWRlYW51bToyfHJiR3JvdXA6MTYzNnxhZ2VudDpudWxsfG1vcmVJbXByZXNzOjB8cmJfYWQ6MCwyfG9zOmxpbnV4fGJyb3dzZXI6Y2hyb21lfHBsYXRmb3JtOmFuZHJvaWR8ZGV2aWNlOm90aGVyfGFkUGxhdEZvcm06Mwkw&userid=__149.20.63.13_1523791820_0.19234800&viewlog=false&hashCode=20b7a04a535ebc17809e5e5d79a87484","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ds.reson8.com/adb-ext.gif?puid=86070857378125119120981354726841823876","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://as2.m.hao123.com/ozall/bgb?c=d25pZD04ZTNlYjdmYTEwNDEzMzBkAHM9OGUzZWI3ZmExMDQxMzMwZAB0PTE1MjM3OTE5ODgAc2U9MQBidT00AHByaWNlPVd0TTRkQUFFQVlKN2pFcGdXNUlBOGpZMG0tRDdlcmVYdWhMZHVBAGNoYXJnZV9wcmljZT0xNABzaGFyaW5nX3ByaWNlPTE0MDAwAHdpbl9kc3A9NABjaG1kPTEAYmRpZD1CMEQ4NTIwMkE5MUJDQUM0NzFERERBRTY0NzMzNEJDNgBjcHJvaWQ9AHdkPTAAdHU9dTMxMDY3MDYAcG9zPTAAYmNobWQ9MAB2PTEAaT02ZmVjZDMxNw","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://cdnetworks.cedexis-test.com/img/17653/r20.gif?rnd=0-1-13960-0-0-17653-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=BvgAr34cTtG17JCcjg0qdt7s,0.7640636425369878&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031523791949%04viewtime%03%2BLifetool%3A3%231523791945.603%2BLifetool%3A4%231523791945.603%2BLifetool%3A5%231523791945.603%2BLifetool%3A6%231523791945.603%2BLifetool%3A7%231523791945.603%2BLifetool%3A7~1523791948.370%2BLifetool%3A8%231523791945.603%2BLifetool%3A9%231523791945.603%2BLifetool%3A10%231523791945.603%2BLifetool%3A10~1523791948.370%2Bsearch%3A5%231523791945.603%04_E%03l_viewtime","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://vdms-ssl.cedexis-test.com/img/16999/r20.gif?rnd=0-1-13960-0-0-16999-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=%E7%97%9E%E5%AE%A2%E9%82%A6%20PIXNET&time=1523792004083&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fm.pixnet.net%2F%3F&random_number=19218831901&sess_cookie=92da715f162c914c3ef1d90dc9f&sess_cookie_flag=1&user_cookie=92da715f162c914c3ef1d90dc9f&user_cookie_flag=1&dynamic=true&domain=pixnet.net&account=H00Mh1aIE700wg&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.google.com/ads/user-lists/983869946/?value=0&guid=ON&script=0&cdct=2&is_vtc=1&random=1892541338","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/mobile/hd/tw_button.png","request_type":"image"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/4fc774a3/images/google-play-badge.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_badge_2up.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p9.qhmsg.com/t010fa93a99715aad32.png","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/img/icon_share_ios_32.png","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://www.espn.com/login/responder/index.html?clientId=ESPN-ONESITE.WEB-PROD&scheme=http&postMessageOrigin=http%3A%2F%2Fwww.espn.com%2F&cookieDomain=www.espn.com&config=PROD&logLevel=INFO&topHost=www.espn.com&langPref=en-US&cssOverride=https%3A%2F%2Fsecure.espncdn.com%2Fcombiner%2Fc%3Fcss%3Ddisneyid%2Fcore.css&responderPage=https%3A%2F%2Fwww.espn.com%2Flogin%2Fresponder%2Findex.html&buildId=16297c29c33","request_type":"html"}
+{"origin":"http://www.savefrom.net/","request_url":"https://img.revcontent.com/?url=https://revcontent-p0.s3.amazonaws.com/content/images/15236192390385115638.jpg&static=true&pos=face&h=315&w=420&static=true&fmt=jpeg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/28/ee/4d/28ee4d4edca8fa8b418218d411230bca/28ee4d4edca8fa8b418218d411230bca.30.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_65,y_75,w_480,h_320/os/news/5342aabd34383f9cde79a7c928323489.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjA5NjM3NTk1M15BMl5BanBnXkFtZTgwMzg1MzU2NjE@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/Digital_Video/GW_HERO/GW_MobileBillboard_GhostInTheShell_1242x450_NonPrime._SX1242_CB486961678_.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v3/img/skins/default/xvideos.com.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-profile_services.min-vflVt9avS.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-main_atomic_sm/td-applet-viewer-templates-main_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/native/impress?23791=Y2FsbGJhY2s9c2F4X2pzb25wQ2FsbGJhY2tfMiZhZHVuaXRfaWQ9UERQUzAwMDAwMDA1Nzc4MixQRFBTMDAwMDAwMDU3NzgzJnBhZ2VfdXJsPWh0dHBzJTNBJTJGJTJGc2luYS5jbiUyRiUzRmZyb20lM0R3ZWImdGltZXN0YW1wPTE1MjM3OTE4MjUyMzcmcm90YXRlX2NvdW50PTgxMiZhbT0lN0IlMjJkcyUyMiUzQSUyMjM2MCo1MTIlMjIlMkMlMjJvdiUyMiUzQSUyMmFuZHJvaWQlMjIlN0QmbmV0PW51bGw=","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://cms.analytics.yahoo.com/cms?partner_id=KRUX","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://dropbox.com/hstsping","request_type":"other"}
+{"origin":"http://www.facebook.com/","request_url":"https://staticxx.facebook.com/common/referer_frame.php","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://ing-district.clicktale.net/ctn_v2/wr/?1699375031091421&100&10&2&1&1&105&subsid=233200&msgsize=10","request_type":"text"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/tc?tcreq4log=1&r=1523791817073&logid=1811881676&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=10&cst=1&ref=index_iphone&logFrom=index","request_type":"text"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__","request_type":"html"}
+{"origin":"http://www.linkedin.com/","request_url":"https://platform.linkedin.com/js/px.js?ch=1","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://api.company-target.com/api/v2/ip.json?referrer=&page=https%3A%2F%2Fwww.adobe.com%2F&page_title=Adobe%3A%20Creative%2C%20marketing%20and%20document%20management%20solutions&key=b561357daf8504abd0ca9cc239218ae0","request_type":"script"}
+{"origin":"http://www.onclkds.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/983473429/?random=1523791874579&cv=9&fst=1523791874542&num=2&label=0_cMCPultwYQlbr61AM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_qs_click_protection.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-curve/anim-curve-min.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://pixel.quantserve.com/pixel/p-5aWVS_roA1dVM.gif?idmatch=0","request_type":"image"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://cdn.sstatic.net/Sites/stackoverflow/mobile.css?v=89b29cbefeb9","request_type":"css"}
+{"origin":"http://www.hao123.com/","request_url":"https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/pms/img/st.gif?ts=asy&t=feature&sid=jg0qejmoia3&dv=4&page=9_3252&p=9&bdrs=y&bxsd=y&opat=y&txsd=y&anim=y&trsi=y&trfm=y&flex=y&3dtr=y&shpe=y&fltr=y&cavs=y&dgdp=y&locs=y&wctem=y&wcsdd=y&wccse=y&wchti=y&wsql=y&natm=y&ustm=y&arra=y&prms=n&xhr2=y&wbgl=y&geol=y&svg=y&work=y&wbsk=y&vido=y&audo=y&hsty=y&file=y&psmg=y&wknf=n&rqaf=y&json=y&flsc=n&i18n=y&cors=y&prog=y&metr=y&becn=y&mcrd=n&esrc=y&WebP-lossy=y&WebP-lossless=y&WebP-alpha=y&WebP-animation=y","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a671c9100015ad3387c18ad70fdeff6&pid=mm_113716014_12970037_52768230&cid=263940&mid=229046&oid=32786&productType=1&qytInfoMTime=1523728961&cb=843188010","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-32129070-1&cid=970841907.1523791982&jid=396986874&_gid=1459932104.1523791982&gjid=1671281732&_v=j66&z=584488678","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3D49NGBMVT1ABRN6GGR916%26pty%3DRegistry%26spty%3DwishlistHighUpsellPage%26pti%3D601:1000","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/983869946/?value=0&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/3720.files/images/logo.gif","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://pxl.connexity.net/c/cse?a=R&A=22c&D=569a&V=9&I0k=ptnrid&I0v=39041E2B94ED6EF00CB315F995BE6F73","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/developers/freakboy3742.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/flag_pack_retina_min.png","request_type":"image"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/images/appstore-install-badges/badge_android_english-en.png/f06b908907d5.png","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/gno/sprites/sky_webnav_V1_sprite_2x._CB515271932_.png","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://images-llnw.xvideos-cdn.com/videos/thumbs169ll/8a/fa/6d/8afa6df1beab3a28433624d6ba4fa2b4/8afa6df1beab3a28433624d6ba4fa2b4.8.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s4.pimg.tw/album/pixstyleme/element/135810614_1523348565-3844427391/zoomcrop/590x393.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180130/f44d305ea48e1bd9f41106.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/40/f5/e3/40f5e3675969a67807d1392dac5b7dc5/40f5e3675969a67807d1392dac5b7dc5.2.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/image?id=866395014846&t=17&plc=MOBILE&tkn=*p4n92uKQijQI9IRxjE_SpsjqXDI","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/305b9d80-07e2-4ab0-b3ca-708c3c8f5c6e/scale-to-height-down/82","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/ichnaea/cl2/freeform/WebsiteDetect?source=wwwhead&fetchType=js&modalView=nmLanding","request_type":"text"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-00000000019/v3/img/skins/default/xv-icons-sprite.svg","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://www.googletagservices.com/tag/js/gpt.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/css/images/sicon-1e5c02c2.woff","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/webauthn.min-vfl6TGvdp.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://fonts.googleapis.com/css?family=Open+Sans:300,400,700&subset=latin,latin-ext","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://b.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/basics/indexmin_7_1_0.js?v=jd201802175619","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/adview?ai=Csw_xkDjTWsD7C8LYkgOTs4GgDIW2z7RNtNnPh70EwI23ARABIN_X4gdgyQagAYi70eEDyAEBqAMByAPDBKoElgFP0NKoltiNCy710Vs87-uQfeYtED1I8a8LMUNhRo6PpEC5karyaCkiiTGxwda7iX2iHF3J3h_9a9v6ZrPelr_JeyZ2100iaiGfHKm7NtM6jZ_c4s2AO-ZNhZ8E59btMYB7ncTInq2Iw4YaXqSYYnd_2OJt_SzwpXfZL4xLcxuLAZTuhAQm20dIaqjTysBgUdK9Uw1SIVTABOjqiKwliAWImftNkgUECAQYAZIFBAgFGASgBlHYBgKAB-DErh6oB47OG6gH1ckbqAemvhvYBwHyBwMQ1FCgCJgWsAgC0ggHCIBhEAEYAoAKAdgTDIIUDhoMbS5waXhuZXQubmV0&sigh=5pNJ_6YIx0w","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.de&slot=navFooter&a2=0101581c268c9590c381ec0d82e498caa555c5b075dc1f07a28c1ce2a20e87703072&old_oo=0&cb=1523791986634&dcc=t","request_type":"html"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://app.link/_r?sdk=web2.31.0&branch_key=key_live_hoc05HaCXaME10UMwyj3filpqzfu2Ue6&callback=branch_callback__0","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.optimizely.com/js/131788053.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768073&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791991230&fs=0&pvid=adab9d6cc24a68cacd983a1d25109071&cg=ab428640f450c86c82a7edc542c07770","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/l?IG=2E674091B80D41D497ED8B2E88AE58C9&CID=15398167FE80640C2D1F8AB5FFD365B8&TYPE=Event.ClientInst&DATA=%5B%7B%22T%22%3A%22CI.Init%22%2C%22FID%22%3A%22CI%22%2C%22Name%22%3A%22Base%22%2C%22TS%22%3A1523791831306%7D%2C%7B%22T%22%3A%22CI.Show%22%2C%22FID%22%3A%22HpPortrait%22%2C%22Name%22%3A%22null%22%2C%22TS%22%3A1523791831306%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22WhatsApp%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Facebook%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Skype%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22WhatsApp%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Sms%22%2C%22TS%22%3A1523791833444%7D%5D","request_type":"other"}
+{"origin":"http://www.twitch.tv/","request_url":"http://www.twitch.tv/","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://usermatch.krxd.net/um/v2?partner=amzn","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://pr-bh.ybp.yahoo.com/sync/adaptv_ortb/8613693521231231297","request_type":"other"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/20170601mobile_common.css","request_type":"css"}
+{"origin":"http://www.qq.com/","request_url":"http://mat1.gtimg.com/www/qq_index/css/qq_5acbc2b4.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/components/exp_cards-vflJsYU3g.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://aax-fe.amazon-adsystem.com/x/px/QpjIRDdFpkqKl7XHZPGfRPkAAAFiyRQtMAcAAAGSAc3zOE4/nii/%7B%22ni%22:true%7D","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=2&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A2%7D&logFlag=uaction_1523791857874&t=1523791859876","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://perf.mmstat.com/p.gif?site=m&memberSeq=amp-50XQcMshov1NQ7I2bYC0LQ&pageType=amp-home&ns=1523791931973&ules=0&ulee=0&rs=0&re=0&fs=1523791934953&dls=1523791933859&dle=1523791933859&cs=1523791933859&ce=1523791934567&scs=1523791934163&resqs=1523791934572&resps=1523791934937&respe=1523791935154&dl=1523791934973&di=1523791935517&dcles=1523791935520&dclee=1523791935520&domc=1523791948372&les=1523791948373&lee=0&srt=1523791935517&fst=0","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845943,aid=exp_games-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WtM4gQAABibm4O17&img=1&__user_check__=1&sync_id=d7e6e980-40a0-11e8-a4da-16828f760201","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/img/logo_home.png","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/image/loader-white-9ee5b.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hj23hjqtkg/albumset/5984099/zoomcrop/75x75.jpg?v=1523785454","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/ytR9Qe3qeOc6qWzwP8N50Jew_RkP68A3gaH77GwUE4EA0fHhg5E6u0mihK6Tntc=w512","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/bUmhI8lzLM1TfnsTsBw6SDwD_SdJq6--zDXelMF90N-4WqWr_dCmIfJfmaJS=w256","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/ucenter/images/ic_home_photo_gray.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/newicons/favicon-96x96.png","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/favicon/favicon-16x16.png","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://nicolive.cdn.nimg.jp/live/simg/img/a468/1402312.687f54.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1468aNpXXXXXoXFXXq6xXFXXXh.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/08/41/70/0841708c1a6d2dc37d198f2f0f2786f1/0841708c1a6d2dc37d198f2f0f2786f1.23.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/74/53/aa/7453aac3bdb5cb4ddc8d87dc06f0ca44/7453aac3bdb5cb4ddc8d87dc06f0ca44.24.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/183e8ab690e740d99b7d0d31471243ce.jpeg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1YJqziN9YBuNjy0Ffq6xIsVXau.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31uzIgVilQL._AC_SY400_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/41DupeUDE2L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static2.dditscdn.com/mbl/frontend_backbone/static/livejasmin/image/favicon-838c4.ico","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/wordmarks/wordmark_white.svg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/arrowRightLittle.svg","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://unagi-na.amazon.com/1/events/com.amazon.csm.nexusclient.prod","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/abuse/invisible_recaptcha.min-vflJ2IeBo.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/toolbar/content_toolbar_css/m_toolbar-1.0.1.css","request_type":"css"}
+{"origin":"http://www.baidu.com/","request_url":"http://www.baidu.com/","request_type":"html"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=MB94vEr","request_type":"other"}
+{"origin":"http://www.espn.com/","request_url":"https://secure.espncdn.com/ad/doubleclick/hanfordCap.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/pubfooter/js/tracking-1.0.2.js","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=netflix_dmp&referrer=netflix.com/bt/nmLanding&google_cm","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm&ex=doubleclick.net&","request_type":"html"}
+{"origin":"http://www.google.co.id/","request_url":"http://www.google.co.id/","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.facebook.com/fr/r.php?p=558293300959460&e=tX6_9Xz4Qdmr5oo7UFnXXQ&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dfbca%26id%3DtX6_9Xz4Qdmr5oo7UFnXXQ&s=1523791870&h=RXRMUWR6UzNzUHNNK3JnROfDXkyHxKvHv2gyALJu52Stt1iZ","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=69080862&t=screenview&_s=1&cd=sp.nicovideo.jp&dl=http%3A%2F%2Fsp.nicovideo.jp%2F&ul=en-us&de=UTF-8&dt=niconico(%E3%83%8B%E3%82%B3%E3%83%8B%E3%82%B3)&sd=24-bit&sr=360x512&vp=360x512&je=0&an=%E3%83%8B%E3%82%B3%E3%83%8B%E3%82%B3%E5%8B%95%E7%94%BB%EF%BC%88Spweb%EF%BC%89&av=1.0.0&aid=nicovideo_spweb&_u=aGDACEIhB~&jid=265375760&gjid=1098642764&cid=213610430.1523791965&tid=UA-88451119-7&_gid=1476326533.1523791965&_r=1&cd1=%2F&cd25=not_login&cd49=&cd52=http%3A%2F%2Fsp.nicovideo.jp%2F&cd55=&cd58=sp.nicovideo.jp&cd61=null&cd70=sp.nicovideo.jp&cd73=%2F&cd118=mozilla%2F5.0%20(linux%3B%20android%206.0.1%3B%20moto%20g%20(4)%20build%2Fmpj24.139-64)%20applewebkit%2F537.36%20(khtml%2C%20like%20gecko)%20chrome%2F58.0.3029.81%20mobile%20safari%2F537.36%20ptst%2F180406.130428&z=1625046190","request_type":"html"}
+{"origin":"http://www.live.com/","request_url":"https://a3698060313.cdn.optimizely.com/client_storage/a3698060313.html","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/api/OxBannerService/getAdvertisements.jsonp?zone=613&category=&pageurl=http%3A%2F%2Fsp.nicovideo.jp%2F&pagevariant=&callback=ads_callback_0&_=1523791955386","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/css/s_cfmxwr.css?953","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/949424158/?random=1523791866946&cv=9&fst=1523791866946&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns.gigya.com/js/gigya.services.plugins.base.min.js?services=gigya.services.socialize.plugins.reactions&lang=en&version=latest","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/ActivateExperimentResource/create/","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://d9.flashtalking.com/d9core","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yV/r/-pEnveDSVt4.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-be7afd80869374e8f9fd0c31859f748aaefbe2fd._V2_.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/316nxKpnxGL._RC%7C51gvQ0ZsBLL.js_.js?AUIClients/SharedShoppingCartMobileAsset","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ads.scorecardresearch.com/p?c1=9&c2=6034944&c3=2&cs_xi=86070857378125119120981354726841823876&rn=1523791842111&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D73426%26dpuuid%3D86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://usermatch.krxd.net/um/v2?partner=amzn","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.linkedin.com/csp/dtag?_x=%2526s%253D1%2526url%253Dhttps%25253A%25252F%25252Fmarketing.dropbox.com%25252F%25253Freferrer%25253D%2526pageUrl%253Dhttps%25253A%25252F%25252Fmarketing.dropbox.com%25252F%25253Freferrer%25253D%2526ref%253D%2526cookiesTest%253Dtrue%2526opid%253D4373%2526fmt%253Djs%2526time%253D1523791867534&p=9","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_house-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.twitter.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&aip=1&a=1879116745&t=pageview&_s=1&dl=https%3A%2F%2Fmobile.twitter.com%2F&dp=%2Fanon%2Ffront%2F&ul=en-us&de=UTF-8&dt=Twitter&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAUAB~&jid=2076440235&gjid=402002681&cid=161642855.1523791919&tid=UA-30775-67&_gid=1567954787.1523791919&_r=1&z=812882985","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://www.google.com/ads/user-lists/817714641/?label=oPQ0CPiMhoABENGr9YUD&guid=ON&script=0&cdct=2&is_vtc=1&random=3552635272","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hjfgjcxjyf/albumset/7410815/zoomcrop/75x75.jpg?v=1523785914","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/suning_20170907.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=c0c8e822-f6df-43cc-b722-f0b7d8ba3258&ttd_puid=7bc4f310-40a0-11e8-8fa8-0242e5e63087%2C","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-01a49470266a51f632dab1aef2fc09112d280c1e._V2_.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4656000/4656181/220x165/5.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4849000/4849903/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$jigsaw/ic/da97cf8c/7988cc1c.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/039/0af/255/big_lq/8eef96fc3e93e19b66056f506cb53035.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/lbt/201804/W020180420292396681039.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/GETTY_IMAGES/WST/597067519__oFXq3QlG.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20171228_yatx_728x90_3.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1S2AChruWBuNjSszgq6z8jVXaW.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/PhsAAOSwtJZXUKJx/s-l225.webp","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1c2yCQFXXXXa7XXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/640323cb-cb09-4def-907d-71e29e636342/scale-to-height-down/100","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D","request_type":"text"}
+{"origin":"http://www.youth.cn/","request_url":"http://cl.webterren.com/common.js","request_type":"script"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/bundles/base/ConsumerCommons.js/e4f078188229.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/mobile/js/sub_id.js?v=0704","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/zepto/4.0.9/event.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpmm.alicdn.com/g/mm/afp-cdn/JS/k.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://t.co/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nyutn&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://ml314.com/utsync.ashx?eid=50077&et=0&fp=39041E2B94ED6EF00CB315F995BE6F73&return=https%3a%2f%2fidsync.rlcdn.com%2f395886.gif%3fpartner_uid%3d%5bPersonID%5d","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/gen_204?atyp=csi&ei=GjjTWsbuEOGC0wKDm7uACA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.368,dcl.356,iml.368,ol.2616,prt.251,xjs.1583,xjsee.1561,xjses.1295,xjsls.248,wsrt.2107,cst.671,dnst.0,rqst.779,rspt.401,sslt.368,rqstt.1632,unt.2017,cstt.958,dit.2463&zx=1523791901205","request_type":"html"}
+{"origin":"http://www.livejasmin.com/","request_url":"http://m.livejasmin.com/en/list/","request_type":"html"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/iu3?d=amazon.co.jp&slot=navFooter&a2=0101fbffefd5eda900ada4befaa692c782f834fd9f58245efcad8aa7970fac883fb5&old_oo=0&cb=1523791965573&dcc=t","request_type":"html"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://social-login.cnn.com/gscounters.sendReport?reports=%5B%7B%22name%22%3A%22load%22%2C%22time%22%3A%221523791891269%22%2C%22source%22%3A%22showShareBarUI%22%2C%22reportData%22%3A%7B%7D%7D%2C%7B%22name%22%3A%22load%22%2C%22time%22%3A%221523791893151%22%2C%22source%22%3A%22showShareBarUI%22%2C%22reportData%22%3A%7B%7D%7D%2C%7B%22name%22%3A%22load%22%2C%22time%22%3A%221523791893196%22%2C%22source%22%3A%22showShareBarUI%22%2C%22reportData%22%3A%7B%7D%7D%5D&APIKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&sdk=js_latest&pageURL=https%3A%2F%2Fwww.cnn.com%2F&format=jsonp&callback=gigya.callback&context=R2973121876","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/user-auth-1/js/init.min.js?v=11","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rtd.tubemogul.com/migrate_et3/","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=83face8557de1e08ab48","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=40&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A40%7D&logFlag=uaction_1523791857874&t=1523791897876","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://yj.p.adnxs.com/mapuid?member=3663&user=93625819-cbf4-4733-ba3b-11ac4270c753","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://s.pinimg.com/_/_/r20.gif?rnd=1-1-13960-0-0-34022-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_auto-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=782&dpuuid=WtM4gQAABibm4O17","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://hao123.baidu.com/static/mapping/bd.php?type=gif","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/tg02yAOuyOZJZcU5NDvZa1_J_1Ngk9P-CsLd8NWkLaMHVZXY-fPAKW6s1bkp8MI=w768","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/business/profile-main.png?v=9bd4dace1","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSNhe.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=519&y=307","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/KvIAAOSwj1Zahb26/s-l225.webp","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1cePtSFXXXXcWXFXXXXXXXXXX-1000-277.jpg_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/bag/image_small.svg","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://front.pixfs.net/js/fingerprint.min.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/langpack/en.json?17635","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cdnssl.clicktale.net/www/WR-latest.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/head.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/custom-hotquery.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://yads.c.yimg.jp/js/yads-async.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-football-college.png&h=120&w=120&cquality=40","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-css-9a10b8f6/css/css/pages%7Csignup%7Csimplicity%7Csimplicity.less/2/0H0W080P0e0R0O0_0X0Q0V/none/true/none","request_type":"css"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rp.gwallet.com/r1/cm/p50?check_uid_cookie","request_type":"other"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss3.bdstatic.com/5foUcz3n1MgCo2Kml5_Y_D3/graph/static/resource/sdk/v1.11.1/mms.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/v2.2/plugins/login_button.php?app_id=274266067164&auto_logout_link=false&button_type=continue_with&channel=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FFdM1l_dpErI.js%3Fversion%3D42%23cb%3Df11928fd00daeb4%26domain%3Dwww.pinterest.com%26origin%3Dhttps%253A%252F%252Fwww.pinterest.com%252Ff5838e3059c2d8%26relation%3Dparent.parent&container_width=328&locale=en_US&max_rows=1&scope=public_profile%2Cemail%2Cuser_likes%2Cuser_birthday%2Cuser_friends&sdk=joey&show_faces=false&size=large&use_continue_as=true&width=100%25","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100297765&apid=beans_12275&impid=07b7928b2a1c73cad_0_0&at=1&mkey=07b7928b2a1c73cad_0_0&latcy=4135&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=3755.5625&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3D5qBdtKaNqQu%2B1StuvWhg1bTiufW09KkoCe3PelKPHd35KUxTIF1OThmDmoUVMVoi0Hiy4OaEy705t1DFhp3KcVHLhjwoy8y7BSirJ9qP%2F7fXPDOJsC0wnsibmyvl4ffQa9n5YsmhHeIfDpnPUwygKzIN0TsicG7fi0K%2FYe3DTioxptjKxauL3nRyOjHHwQxQzek43gnPw6mZypEuGOYXs2%2FsNiOUpbOqSlYUI4l0YX%2FWWULKJIdFxajepXgA5QoV6Zw5W1vTOoHuCYFSaunO3Ybr5JyqkILs118pboLd1ILjPch%2BHNGm%2Fa3fftX37fXOCJTF9gG0AwHho%2FYbirPCxtlju6rsSsfvsT1B4va2AjXxHhkjYr4rzBfOkX6m66F9Sh3cDPFsgalh63jaOsarib%2FfOAdBw%2B5ukuabHkXb0vXtiChH7pk94ddsVUc7s0NgtRg%2F9gVy629wkxjYtn8ew2t1qSWVAhMUdwqHXgqgWsISLKfInorofPzmfrJrh8CuBL8qD9rxxplLZBJg0tnM9A14oplsEC1ticKDATcLOhhtlu67V4%2FDAj5rkkdpDluY0WuyyxFNNozl9eILk%2Bd1tWAveYsQjMDlB8KlbPbfJHk%3D%09tt2%3D1523791941975%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=9647958014490&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942416","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://tsyndicate.com/iframes2/088e288d72b1404ea62653e5192fec73.html?keywords=Watch,and,download,all,Porn,Videos,xHamster,for,Free,including,Browse,sex,photos,date,girls,fuck,have,fun,Live,Sex,Chat,only,xHamster,Free,Porn,Videos,Sex,Tube,Movies,xHamster&param1=0&param2={last}&adb=0&w=1080&h=1536","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://connect.facebook.net/en_US/sdk.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/his?callback=jsonp1&type=3&pic=1&lid=1811881676&ishome=1&net=1&islogin=0&hissid=122436,100808,122154,114746,1,120171,122489,118895,118870,118847,118830,118805,120550,107315,122862,117330,117433,122789,121142,122857,122886,123139,122496,114975,116407,122669,110085,122303&_=1523791817216","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://aax-fe.amazon-adsystem.com/s/iu3?d=amazon.co.jp&slot=navFooter&a2=0101fbffefd5eda900ada4befaa692c782f834fd9f58245efcad8aa7970fac883fb5&old_oo=0&cb=1523791965573","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=qsUcMWkhdSdbyfcwiyYrn8WWwYjZzChgQG1x/JmYjWc=&ex=rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://counter.yadro.ru/hit;mail-splash/touch?q;r;uhttp%3A%2F%2Fm.mail.ru%2f;","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://mc.yandex.ru/metrika/advert.gif","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d30050586.gif?sz=30&rnd=105129098&ts=1523791836&sz=30","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/img/lightbox/lightbox-blank.gif","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hjfgjftgjgh/albumset/7410830/zoomcrop/75x75.jpg?v=1523786129","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p1.ssl.qhimg.com/t01fcf996fd7f4e858c.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t01068da1826ad05875.png","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/cv/ae/notifications/push-promo-icon.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/members/top.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/finance80.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"http://m.aliexpress.com/?tracelog=wwwhome2mobilesitehome","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvTnFs.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=533&y=395","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/f44d305ea0a21c3c9e7702.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f12/2eee0b4ee713c63b752b34624be3a49d_erotic_285x160.jpg?cno=7c76","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTQ0NjgzNzcwNV5BMl5BanBnXkFtZTcwODExMDYxOQ@@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41BMyAk8duL._AC_SY400_.jpg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/_h/413bd4a8/coreui.statics/images/social/linkedin.svg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/_h/6f40299c/coreui.statics/images/social/twitter.svg","request_type":"image"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://cdn.branch.io/branch-latest.min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://cdn.registerdisney.go.com/v2/inner/tealium/utag.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://use.typekit.com/af/bac21d/0000000000000000000176ff/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n3&v=3","request_type":"font"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.woff2","request_type":"font"}
+{"origin":"http://www.netflix.com/","request_url":"https://s.btstatic.com/tag.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/gotop/css/goTop.min.css?v20180326104254","request_type":"css"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static2.dditscdn.com/mbl/frontend_backbone/static/_common/fonts/roboto-light-webfont-c0839.woff2","request_type":"font"}
+{"origin":"http://www.youth.cn/","request_url":"http://cpro.baidustatic.com/cpro/ui/pr.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/a1de3e3a01556d8ae2c39f1636a60691.js?conditionId0=379384","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://adservice.google.com.ar/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=adobe_dmp&google_cm=&google_tc=","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=777909432&t=pageview&_s=1&dl=https%3A%2F%2Fm.xhamster.com%2F&ul=en-us&de=UTF-8&dt=Free%20Porn%20Videos%20%26%20HD%20Sex%20Tube%20Movies%20at%20xHamster&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAEABAAQC~&jid=1339518023&gjid=481498379&cid=885864085.1523791857&tid=UA-23892695-1&sf=40&_gid=1294404763.1523791857&_r=1&cd5=straight&cd2=XH%20Mobile%20Site&z=1331474201","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791948307&yhlClientVer=3.30.2&yhlRnd=6oMmiqRf0lwn7b0Cjg0qds7n&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.onclkds.com/","request_url":"http://www.googleadservices.com/pagead/conversion.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.googleadservices.com/pagead/conversion_async.js","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/scripts/dashboard.js?_v=86d3003b56353d386274dbfc44bad8c6","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/client/prod/app/global.build.js?_v=988e9898053691d7e018496172babd33","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/_td_api/resource/notificationHistory;count=4;imageTag=img%3A40x40%7C2%7C80;lastUpdate=1523791949","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/t_tkr/ev?type=dl&dltime=3248&frmtversion=0.0.0&plid=764344014241209959&pvid=1928825100107055743&x=0&y=0&pvt=1523791869849&pft=1523791867546&stime=1523791876862&etime=1523791876871","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=adobe&partner_uid=53665343323329185184569542997441377211","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/srp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&ssl=1&t=1523791859633","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://haostat.qihoo.com/haopv.gif?b=chrome&a=1&u=http%3A%2F%2Fm.360.com%2Findex.html&id=59677681.269325834807300900.1523791827184.1177&c=1&r=&t=1523791827221","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ps.eyeota.net/match/bounce/?bid=6j5b2cv&uid=86070857378125119120981354726841823876&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30064%26dpuuid%3D%7BUUID_6j5b2cv%7D","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://media.trafficfactory.biz//banners/70/9b/f9/9998b2d4ace03b5f27b00dce0a6ae1bb.gif","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://wgo.mmstat.com/alihybrid.hybrid.call?cache=bfa3c66&gmkey=EXP&gokey=api%3Dnetwork_getType%26platform%3Dweb_Android&cna=&spm-cnt=a223j.8443192.0.0.550f3dbeLF7YWD&logtype=2","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://www.facebook.com/impression.php/fda7febd8d9708/?api_key=627392657291988&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=NjY5OTBmMjQtODcwNi0zMGYyLTk3ZjMtNTc1YzBmZTQ2ODQzCTQ1CVBEUFMwMDAwMDAwNTc3ODAJNTAJMzUwMDA2OQkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://ad.doubleclick.net/ddm/activity/src=1295336;type=adobe994;cat=aamuuid;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://cdn.tsyndicate.com/images/1/0/8521a8603c2bc363eb70f4573bef63724ce936.gif","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=880546608&t=pageview&_s=1&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEDAAEAB~&jid=1908172737&gjid=417471397&cid=970841907.1523791982&tid=UA-32132943-1&_gid=1459932104.1523791982&_r=1&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=2132827294","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/icons/af-beta/5563c80b-eb78-4e19-916e-3a4b7a1bcc98.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/yet-another-pixel-dungeon-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/facebook-logo.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/images/index/load/06003.png","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem5YaGs126MiZpBA-UNirkOUuhpKKSTjw.woff2","request_type":"font"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$crossword/ic/78b41b92/d4671a5c.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://img.cdn.nimg.jp/s/niconews/articles/images/3435075/4edb352c5b79093a72b411929fc5b440aec5961978a53d646db455304dd0251e249a12164cda61f243cd39e47dba56840c649dcf1cd6da2630fb7edacabc4e73/110x110s_FFFFFFFF?key=6a69acbfaf68189ad0d6672f453a86046082b6e55b403edde0c75127a735cd8f","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://imageproxy.pimg.tw/zoomcrop?url=https%3A%2F%2F2.bp.blogspot.com%2F-wHUsSM9QcvA%2FWsxcTUkk9dI%2FAAAAAAAAUrQ%2FAbyLPABcO0wIyKCk1L2sptk35Mj8iLoDgCLcBGAs%2Fs400%2F22930424305_91c55e3947_b.jpg&width=90&height=65","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0414/dm_180414_Watchfolder_Cuse_Football/dm_180414_Watchfolder_Cuse_Football.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/c03fd5535e161c3d07af09.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/amazonlaunchpad/de/Gateway/2018_02/iolandac_2018-02-05T15-59_0ebc52_1099615_de_launchpad_gw_quadcard_feb18_420x420_6._CB487250273_.jpg","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/bao/uploaded/bao/upload/TB1wfrdOpXXXXaEaVXXwu0bFXXX.png_320x5000Q50s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://bongacams.com/tools/js.php?_=1523791941348","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/01%2B4CxAE%2BiL.css?AUIClients/DetailPageAlohaAssets","request_type":"css"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/gGEGrJycWHa.css","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/floors/floor06013.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/libs/jquery/jquery-1.9.1.min.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://www.google.com/pagead/drt/ui","request_type":"html"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/gen_204?atyp=i&ct=ppm&cad=&lids=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi&ids=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc&am=gEXyM95DDkHGRjEhGYy_AAo4ERA&k=xjs.qs.en_US.OeOVYA94wZw.O&ei=-DfTWqiNHYaC8AOtuL_YCg&zx=1523791866298","request_type":"html"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/gen_204?atyp=csi&ei=ATjTWoLBGqiB0wKB2ajIBQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.17,jhsl.2190&rt=aft.524,dcl.489,iml.524,ol.2966,prt.383,xjs.1886,xjsee.1886,xjses.1566,xjsls.404,wsrt.1837,cst.697,dnst.0,rqst.791,rspt.410,sslt.389,rqstt.1364,unt.1762,cstt.664,dit.2325&zx=1523791876726","request_type":"html"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/ad_data_204","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938292_3796466828528&itemspaceid=13455&adps=6400120&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938292","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.googletagmanager.com/gtm.js?id=GTM-K8WT2R","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://connect.facebook.net/signals/config/348538655570151?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://us-u.openx.net/w/1.0/sd?id=537148856&val=WtM34wAACGMfPfyQ","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fpixel.rubiconproject.com%252Ftap.php%253Fexpires%253D30%2526nid%253D2181%2526put%253D__EFGSURFER__.__EFGCK__%2526v%253D11782&google_gid=CAESEPd4Jzcj87qgNvzrB164ELA&google_cver=1","request_type":"other"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://ip-109-71-163-131.dditscdn.com/v1/fingerprints","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/data.gif?_kuid=L6N7iig7&_kdpid=2dd640a6-6ebd-4d4f-af30-af8baa441a0d&dlxid=&dlxdata=","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/data.gif?_kuid=L6N62llA&_kdpid=2dd640a6-6ebd-4d4f-af30-af8baa441a0d&dlxid=&dlxdata=","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=casale&partner_uid=WtM4d9HM4SIAADgbHwMAAAAg%26455","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://s.mnet-ad.net/px.gif?ch=2&rn=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=22052&dpuuid=5978151418385522988","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://www.google.com/ads/user-lists/995153884/?value=1.00&currency_code=USD&label=szBrCMnWkWAQ3K_D2gM&guid=ON&script=0&cdct=2&is_vtc=1&random=3365796200","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/tb/loader@2x.png","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/se/static/img/iphone/tab_loading__bg_logo.png","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/images/fandom-app-icon.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p0.qhmsg.com/t01a1539e3423346062.png","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://sync.1rx.io/usersync/clickagy/WtM35B__DJPpGsQgT1fYqPHA?zcc=1&dspret=1&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D139%26cm%3D%5BRX_UUID%5D&cb=1523791852637","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5566000/5566355/220x165/6.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/9ZcAAOSw3RZaTA3D/$_57.JPG","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$rubix/ic/da45e62f/201dd8a2.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://d2x3bkdslnxkuj.cloudfront.net/2493831_300.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://t10.baidu.com/it/u=3518155788,1835107690&fm=76","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/4923000/4923067/220x165/7.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/13k0i91zbxeagEVqbbKnsF9fk3sCIqhzBNBh3EpQ5Sw.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s134x134_jfs/t5725/339/9007878255/424280/8c083797/59819709Nd61baf4e.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s124x124_jfs/t16843/25/1497962005/21053/5ccaadb5/5ace28aaNfd18ad77.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/vikAAOSwfQxavSw8/s-l500.webp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/langsRetina.png","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/32430/0/0/308/0/0","request_type":"text"}
+{"origin":"http://www.csdn.net/","request_url":"https://beacon.tingyun.com/xhr1?pvid=c5f0d6a8-d452-4523-9ca8-4a0813517a9a&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=fad86f04-fa3a-4f2f-a92a-15fae388816e&sid=676406ea-440a-48bc-820a-57146ad87968&__r=1523791935766","request_type":"text"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/img/favicon.ico","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"https://certify-js.alexametrics.com/atrk.js","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/concat/common/js?h=a06jpss2hf43xwxobn0gl598m-44hhbxag3hinac547ym9vby09-5jratctnqzzuc1057yivxswgf-9zz2lhu3eq1epk7sq1t8cdb5s-eound1d1xhqm86h7g2p57b94l-edgsl2z4e4gk56cy2m5kbpp1q-acgipb6zomeaovod456pb7yjs-bctwwqj7p01tcj2smshz2bboe-88ec8b078z4fzj5q3z4qowg63-bftaa82sjwcbrohoe28skni7b-58m2n4boqb1vxfd6hgd34auwd-8ycvggo1571xgrdka3utvcyml-cfabcg4u1cj0em4yissh5mfxu","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/api/articles?type=more&category=home&shown_offset=1523791926859909&first_view=false","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/utils.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-modal_aside_mega/td-applet-viewer-templates-modal_aside_mega-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-share_btns_mega/td-applet-viewer-templates-share_btns_mega-min.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/liveperson.min.fp-2de60b6bce08981642fd60d65915e25d.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-basketball.png&h=120&w=120&cquality=40","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61dthWUjS5L._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,11B0Us3dmsL.css,21pknbpyIxL.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,31B945bG3dL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21s7MLn4blL.css,11X2-nh0PYL.css,01h2e2BEitL.css,114wDplwccL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31VU7Pt5U6L.css,01b7OI3r44L.css,11mmd1QliNL.css,01cbS3UK11L.css,21pKFuuDucL.css,01EjbsDjo-L.css_.css?AUIClients/AmazonUI","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C3121NMERoYL.css_.css?AUIClients/SharedShoppingCartMobileAsset","request_type":"css"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/bs.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/js/espn-critical-mobile.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=taboola_dbm&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.pornhub.com/","request_url":"https://www.pornhub.com/","request_type":"html"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.co.jp/","request_url":"http://www.google.co.jp/","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://suggest.taobao.com/sug?area=tmall-hq&code=utf-8&src=mallfp..m&callback=jsonp_23463659","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://agent.aralego.com/sdk","request_type":"text"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fib.adnxs.com%2Fpxj%3Faction%3Dsetuid(%27__EFGSURFER__.__EFGCK__%27)%26bidder%3D51%26seg%3D2634060der%3D51%26seg%3D2634060","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://onefeed.fan.api.espn.com/apis/v3/cached/contentEngine/oneFeed/frontpage?source=ESPN.com%2B-%2BFAM&showfc=true&region=us&offset=10&limit=15&lang=en&featureFlags=hideTierII%2CnoTierII&editionKey=espn-en&device=mobile&showCarousel=true&pubkey=espn-en-frontpage-index&isPremium=true","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/js/common/9d3070aa/common.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://analytics.twitter.com/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvzbs&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0&tpx_cb=twttr.conversion.loadPixels&tw_document_href=https%3A%2F%2Fwordpress.com%2F","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://www.facebook.com/rsrc.php/v3ijLc4/yS/l/en_US/k_h9C8ZbX1R.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/UH6TUt9n?redir=https%3A%2F%2Fib.adnxs.com%2Fsetuid%3Fentity%3D158%26code%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.twitter.com/","request_url":"https://api.twitter.com/1.1/jot/client_event.json","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://fls-na.amazon.com/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=64&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A64%7D&logFlag=uaction_1523791857874&t=1523791921876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=72&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A72%7D&logFlag=uaction_1523791857874&t=1523791929876","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.facebook.com/tr/?id=1559459634097838&ev=Microdata&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1523791873355&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22Dropbox%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=30&it=1523791867576","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://cdnetworks.cedexis-test.com/img/17653/r20.gif?rnd=1-1-13960-0-0-17653-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://w88.espn.com/b/ss/wdgespcom,wdgespge/1/JS-1.6.1/s18874413170641?AQB=1&ndh=1&pf=1&t=15%2F3%2F2018%204%3A33%3A51%200%20420&mid=27927265607529191862424128891858798724&aid=2D699C4E850322B8-60001196800666E8&aamlh=9&ce=ISO-8859-1&ns=espn&cdp=2&pageName=espn%3Afrontpage&g=http%3A%2F%2Fwww.espn.com%2F&cc=USD&ch=espn%3Afrontpage&server=www.espn.com&events=event3&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&c1=espn&h1=espn%3Afrontpage&c2=D%3DSWID&l3=1-23133026p01%2CnoIde02%2C1-23159914p03&c4=index&c5=espn%3Afrontpage&c6=New&v7=unknown%3Aunknown%3Aanonymous%3Ainsider-no%3Apremium-no&v9=en_us&c11=insider-no%3Apremium-no&v11=index%3Aespn%3Afrontpage&v12=en-us&v13=espn%3Afrontpage&c16=en-us&c17=en_us&c21=unknown&v21=no%2Bleague&c22=unknown&v23=unknown&c24=First%20Visit&c26=no%2Bleague&c29=anonymous&c30=premium-no&c38=Portrait&v38=Portrait&c58=isIndex%3Dtrue&v70=favorites%3Ano%7Cfantasy%3Ano%7Cleague%20mgr%3Ano%7Calerts%3Ano%7Cautostart%3Ano&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/impression.php/f3c1ffce536aed8/?api_key=274266067164&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/browse.gif?pos=page_view&page=index_cxv2&level=1&ver=android&t=1523791986834","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/rsrc.php/v3/yC/r/aMltqKRlCHD.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=2682&partner_device_id=D34DC539-63A7-4F27-8DFD-50E0EE1E218A","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/favicons/favicon-16x16.png?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/html/zergnet-3826556079._CB499558523_.html?widgetId=50277","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://rebrand.dropboxstatic.com/videos/homepage_coredb_ui.mp4","request_type":"video"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://s3.pfp.sina.net/ea/ad/3/5/dbb0c188297eb052938dca4cf11bf9ae.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/GDABmQSxHOBD60a70bhTtg/009/341/348/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1KkyyeXmWBuNjSspdq6zugXXav.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/94/31/63/943163c665404a071624f66a6a7a0f68/943163c665404a071624f66a6a7a0f68.21.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180411232043-cnnmoney-zuckerberg-hearing-041118-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=1318614737,1374230137&fm=173&app=12&f=JPEG?w=218&h=146&s=60B072D9485BDC4D182DC34D030080D5","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=4162526360,3292246270&fm=173&app=25&f=JPEG?w=218&h=146&s=23C29C4D1B6323200CF5CD3C03001042","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/027/327/07f/big_lq/376f713bebd2c646ec5bd4dd5eb6f39c.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/01a/09d/117/big_lq/f728309100427fd3987158ff94fb3968.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/I/81if6n1QA2L._AC_SR300,300_.jpg","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-af-0.0.337/media-agof-tracking/media-agof-tracking-min.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAwXc1193a5DQVZgxVupfzxrOZ-zmwiyLUr_x_R4TLMYgsA1znuI","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://image6.pubmatic.com/AdServer/UCookieSetPug?oid=2&cb=PubMatic._uidCB","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/en-us/mscomhp/onerf/MeSilentPassport","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938155_4879167058583&itemspaceid=12420&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938155&cnid=228328065,228330921,228330894,228324455,228329944,228331619","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://t.mookie1.com/rsp?dnv=%3CCACHEBUSTER%3E&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30862%26dpuuid%3D%5BMOOKIE%5D%26redir=https%253A%252F%252Ft.mookie1.com%252Ft%252Fv1%252Fevent%253FmigClientId%253D7413%2526migAction%253Dsync%2526migSource%253Dmig%2526migParam1%253D91191954147729940174299115411397659455","request_type":"text"}
+{"origin":"http://www.microsoft.com/","request_url":"https://idsync.rlcdn.com/365868.gif?partner_uid=86070857378125119120981354726841823876&redirect=1","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/css/s_cf.css?747","request_type":"css"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/homepage/v3/current","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/js/libs/modernizr-2.8.3.min.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://mail.ru/cache","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://connect.facebook.net/en_US/fbevents.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://c.bing.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=E5D96D49D2F0452CB6D06DC876AE25B2&RedC=c1.microsoft.com&MXFR=111DEC71C07961C90502E7A3C47967C1","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.jd.com/","request_url":"https://im-x.jd.com/dsp/np?log=kKWpPGny-Mglmy4fCUUYoP8sFAUXX9bSQZ6Of-red0kBAmdqulhiu_MVnpYd1efkAC3s8xZ_BU-xMzekMCyICR5zHv7DTjYjoxlhT6jxRM-0HWbYBb25ammcHkqVZm2F9AukXJYqjiV59zLsJedRXsThr_7BswsN6IOccuZNbtcw7rNTxr0UTyWu8PcxTLox5w_Ujg6gUPRBpTLgv_LldX-h23PhLU-jeh_eeIili_0J5x9NDwRnMw_zrSepIC1gsdkOZXFH3baeNjFTvfQriij5izRpMRT6qMYG-zOFzm3Lw8V4egzsVXLhDz3nGot2JaH6YnkXQs8LUamMjwPKbE9hSA_VlRjWQW3eAx0EAeHB8Im2NMY0NR-3bTEoDHYm&v=404&_=1523792005409","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-10874655-24&cid=1755800624.1523791943&jid=982289640&_gid=877562822.1523791943&gjid=1006962145&_v=j66&z=1746376536","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:260-2953656-0613235:3P95XKNQTYVQ066DW1Q8$uedata=s:%2Fuedata%2Funsticky%2F260-2953656-0613235%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D3P95XKNQTYVQ066DW1Q8%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D12903%26pc0%3D12905%26ld0%3D12905%26t0%3D1523792025751%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D3P95XKNQTYVQ066DW1Q8%26aftb%3D1:12905","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/p.gif","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://vz-cdn.contentabc.com/ads/rk_300x250_742537/uploadMLogo.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/pic/index_hotnews_prev.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p4.qhmsg.com/t01d7427e1f6239b1b1.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p1.qhmsg.com/t01dd057241efdad2ad.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/favicon/android-chrome-192x192.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://a.tribalfusion.com/i.match?p=b11&redirect=https%3A//simage2.pubmatic.com/AdServer/Pug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTMzMjYmdGw9MTI5NjAw%26piggybackCookie%3D%24TF_USER_ID_ENC%24&u=${PUBMATIC_UID}","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem8YaGs126MiZpBA-UFVZ0bf8pkAg.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/d6b43ee1-5d05-41e7-b3ba-a933f0663733_desktop.jpg?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/b2/00/66/b20066f7c3b510c254e20f7f20e9b6ef/b20066f7c3b510c254e20f7f20e9b6ef.13.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/ba/8f/05/ba8f053e35b3684170a4a85efec9bfe8/ba8f053e35b3684170a4a85efec9bfe8.2.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSzp8.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=2111&y=1199","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_20,y_-4,w_555,h_370/os/news/8120c8c349cd72b61214050a810e417b.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/c1/d9/ea/c1d9ea3775ac175efaa729245f83c4ae/c1d9ea3775ac175efaa729245f83c4ae.24.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p9.qhimg.com/t01926a306f89be23f3.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/2017/fashion/04_shoes/12Dec/M/1086112_shoes_sports_categorycard_sale_1050x1050_4._UX350_SX350_CB492471645_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31s2c9G8xRL._AC_SY300_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/aae63e56-91a6-492e-9260-8f31faccda89/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/logo_small2.svg?v=1","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-video/td-applet-viewer-templates-video-min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mjs.sinaimg.cn/wap/project/homev8/8.2.83/homev8/fonts/SinaHomeFont.3eeedcb.ttf","request_type":"font"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://syndication.twitter.com/i/jot","request_type":"html"}
+{"origin":"http://www.hao123.com/","request_url":"https://graph.baidu.com/mms/graph/static/resource/sdk/mobile.js","request_type":"script"}
+{"origin":"http://www.twitch.tv/","request_url":"https://m.twitch.tv/?desktop-redirect=true","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"https://www.xnxx.com/","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log_js_sw_data","request_type":"text"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://cdn.optimizely.com/js/3181851295.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production//public/content/query/v1/article/search/tag/style?pageSize=12","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://cloudfront-labs.amazonaws.com/x.png","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://trc.taboola.com/sg/adobe/1/cm","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=3aRbLDlTRaCBObjGc-4glA&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/legacy_packages/components-vfl6LCw04.css","request_type":"css"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/css/collections/mobile/responsive-389185194._CB498399448_.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?id=85baa909058d3fa84a600acdc348f0856ab8b08d&ex=aoldisplay.com","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://pcookie.alimama.com/app.gif?&cna=fSZaE8UGdXMCAdBGH12gw1bn","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/ewm_gmym.gif","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.facebook.com/fr/b.php?p=1531105787105294&e=WtM4gQAABibm4O17&t=2592000&o=0","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://popads-trustguard.cdn77-ssl.net/certified-5270-mini.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/khan-academy-android.png:l","request_type":"image"}
+{"origin":"http://www.live.com/","request_url":"https://r1.res.office365.com/owalanding/v2.7/images/apps-googleplay.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/vr/vr_new_asset.png","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-87b47eafbb2/v3/img/flags/flat/flags-32.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://marketing.dropbox.com/?referrer=","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem5YaGs126MiZpBA-UN7rgOXOhpKKSTj5PW.woff2","request_type":"font"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1_hvIiL9TBuNjy1zbq6xpepXaN.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvTrAM.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=532&y=257","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/028/109/29e/big_lq/c0e45c5b902801690ffd603bcf524d82.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://production.mtm-cdn.com/filmer/archives/880/5011/410.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://production.mtm-cdn.com/filmer/archives/1154/8522/547.jpg","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/feed/20180413/4a333b7b59047e2c4c11e38c401b996e.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/9TUBf6l7FBg/hq720_live.jpg?sqp=CLjvzNYF-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLAdmi61QcNKN1CoZmK9ZoUWyRtghQ","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71XnZiOnQML._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=812761972479&photoType=4","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=855234345684&photoType=4","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/29/0/0/324/x-amz-cf-id%3A1T9T9D4QKWyccvPPC95eIaFq_Qr5gqAO_i8NM9I4fXUfsmBajJqJzA%3D%3D%40via%3A1.1%206870f30e42907e5a7094c79c6acd0ec3.cloudfront.net%20(CloudFront)/0","request_type":"text"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/left.svg","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=8&cm=CAESEDMywjNtkr7C0XLzGaYGZgg&google_cver=1","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-applet-0.0.210/ape-applet-templates-reload/ape-applet-templates-reload-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/alilog/mlog/aplus_v2.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/nav.xtpl.js","request_type":"script"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/bundles/fave/latest-2.x/css","request_type":"css"}
+{"origin":"http://www.youth.cn/","request_url":"http://pos.baidu.com/s?hei=110&wid=360&di=u3018881&ltu=http%3A%2F%2Fm.youth.cn%2F&psr=360x512&pcs=360x512&pis=-1x-1&ps=1246x349&tcn=1524189915&tpr=1524189914767&ant=0&dtm=HTML_POST&drs=3&cdo=0&dc=3&ti=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&col=en-US&cce=true&ccd=24&cmi=0&cec=UTF-8&dai=2&cja=false&par=360x512&exps=111000&pss=360x1537&dis=0&cfv=0&ari=2&tlm=1524189914&dri=0&cpl=0&chi=3","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://static.chartbeat.com/js/chartbeat_video.js","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"http://www.google.com.ar/","request_type":"html"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/gen_204?s=webaft&atyp=csi&ei=1DfTWsDQNeqB0wKXjYPQBw&rt=wsrt.2245,aft.387,prt.225","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12281&impid=&at=1&mkey=&latcy=4192&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=2851111713447&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942422","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://sshowads.pubmatic.com/AdServer/AdServerServlet?pubId=156736&siteId=269857&adId=1318691&kadwidth=320&kadheight=50&SAVersion=2&js=1&kdntuid=1&pageURL=https%3A%2F%2Fad.mail.ru%2Fadi%2F78733%3Frnd%3D117101971&inIframe=1&kadpageurl=https%3A%2F%2Fmail.ru&operId=3&sec=1&kltstamp=2018-4-15%204%3A30%3A53&timezone=-7&screenResolution=360x512&ranreq=0.2096902218198593&pmUniAdId=0&adVisibility=0&adPosition=-1x-1","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://api.demandbase.com/api/v2/ip.json?key=e4086fa3ea9d74ac2aae2719a0e5285dc7075d7b&rnd=2035&callback=Request_7279060","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51LGid1qdxL._RC%7C01BL18zkkEL.js,31a72IenKyL.js_.js?AUIClients/NavMobileMetaAsset","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://usync.nexage.com/mapuser?providerid=29472&userid=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"other"}
+{"origin":"http://www.tumblr.com/","request_url":"https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197719247&yhlCT=2&yhlBTMS=1523791925309&yhlClientVer=3.42.2&yhlRnd=xD96Aa4Vgd4BG9d3&yhlCompressed=0","request_type":"other"}
+{"origin":"http://www.diply.com/","request_url":"http://pixel.quantserve.com/pixel;r=2121193960;labels=Diply;rf=0;a=p-z0zMG4nCgXzzj;url=http%3A%2F%2Fdiply.com%2F;fpan=1;fpa=P0-1612267651-1523791967894;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1523791967893;tzo=420;ogl=url.http%3A%2F%2Fdiply%252Ecom%2F%2Ctype.website%2Ctitle.Diply%2Cimage.http%3A%2F%2Fcdn%252Ediply%252Ecom%2Fstatic-images%2Fv2%2Fico%2Fapple-touch-icon-210-precomposed%252Ejpg%2Cimage%3Awidth.1200%2Cimage%3Aheight.630%2Cdescription.Diply%20is%20a%20leading%20social%20entertainment%20publisher%20that%20creates%20captivating%20conte%2Csite_name.Diply","request_type":"image"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/images/kopimi.png","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/img/common/logo_jasrac.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://sync.1rx.io/usersync2/rmpssp?sub=amazon&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%5BRX_UUID%5D%26ex%3Drhythmone.com","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$sudoku/ic/0fc4e494/b41889c1.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/9f/3d/a2/9f3da2c3402a0330857f4b6b23e29b43/9f3da2c3402a0330857f4b6b23e29b43.25.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61qvJZUsv3L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71OIwcnLvOL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/6119FxRp37L._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/REoAAOSwsu9agytr/s-l225.webp","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/voyeurhit.svg","request_type":"image"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/portal/wikipedia.org/assets/img/sprite-556af1a5.svg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/01/ape/sf/mobile/MAsf-1.19._V497204129_.js?csm_attribution=APE-SafeFrame","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-af-0.0.337/af-history/af-history-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-header_atomic_sm/td-applet-viewer-templates-header_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/widget-base/assets/skins/sam/widget-base.css","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"https://s.secure.espncdn.com/stitcher/artwork/collections/media/e71ed10a-62fb-4228-8492-ab13547a3661/16x9.png?showBadge=true&package=ESPN_PLUS?showBadge=true&package=ESPN_PLUS","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://ssl.cdn.turner.com/ads/adfuel/modules/dhtmlxgrid.min.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/toolbar/js/m_toolbar-1.0.1.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTI4NDkmdGw9MTI5NjAw&piggybackCookie=c0c8e822-f6df-43cc-b722-f0b7d8ba3258","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1862787537&t=pageview&_s=1&dl=https%3A%2F%2Fbongacams.com%2F&ul=en-us&de=UTF-8&dt=Free%20Live%20Sex%20Cams%20-%20Live%20Sex%20Chat%20and%20XXX%20Live%20Porn%20Shows&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAAABC~&jid=982289640&gjid=1006962145&cid=1755800624.1523791943&tid=UA-10874655-24&_gid=877562822.1523791943&_r=1&cg1=General&cd1=guest&cd2=&cd3=102&z=1746376536","request_type":"html"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/gen_204?s=webaft&atyp=csi&ei=JjjTWrziKqGW0gLfrIuQDA&rt=wsrt.2160,aft.554,prt.372","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938266_6676789331214&itemspaceid=13821&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938266&plateid=1001200000,1002300000","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.linkedin.com/li/track","request_type":"text"}
+{"origin":"http://www.mail.ru/","request_url":"https://gum.criteo.com/sync?c=30&r=2&j=cr_handle_data_a","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://www.zergnet.com/output.js?id=50277&time=1523791935690&callback=json5976434","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/async-queue/async-queue-min.js","request_type":"script"}
+{"origin":"http://www.so.com/","request_url":"https://s.ssl.qhres.com/callback/255e30246a69d6ad/_255e30246a69d6ad/suggest.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81pPtFtJAnL.js?AUIClients/GoldboxUDPAssets","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://pixel.advertising.com/ups/136/sync?uid=%2C0578ED25960C6228154FE6F7920C61CE&_origin=1","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=spotx.com&id=c0eb2746-40a0-11e8-a9d2-1f9b1aff0601","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"http://srv-2018-04-15-11.pixel.parsely.com/plogger/?rand=1523791996595&idsite=fandom.wikia.com&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&urlref=&screen=360x512%7C360x512%7C24&data=%7B%22parsely_uuid%22%3A%22540b3876-8bae-41e2-acd1-875528779878%22%2C%22parsely_site_uuid%22%3A%22cae1ee6a-be80-4cc8-bbdf-d9bcecbdcfea%22%7D&sid=1&surl=http%3A%2F%2Fwww.wikia.com%2Ffandom&sref=&sts=1523791986086&slts=0&date=Sun+Apr+15+2018+04%3A33%3A16+GMT-0700+(PDT)&action=heartbeat&inc=5&tt=4900&u=cae1ee6a-be80-4cc8-bbdf-d9bcecbdcfea","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEFpU2GqsH60uOsT0JUqEXEE&google_cver=1","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=bidswitch.com&id=e81df0e35fff226b5845293453e76fcf","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3DQ3AKTQX4Z8AX1W7T64V5%26m%3D1%26sc%3Dadblk_no%26pc%3D13571%26at%3D13571%26t%3D1523791869440%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQ3AKTQX4Z8AX1W7T64V5%26aftb%3D1:13572","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://log.mmstat.com/m.gif?logtype=1&title=%u6DD8%u5B9D%u7F51%u89E6%u5C4F%u7248&pre=&cache=65e6f20&scr=360x512&spm-cnt=a215s.7406091.0.0&aplus&sidx=aplusSidex&lver=7.6.8&jsver=aplus_wap&tag=0&stag=-2","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://load77.exelator.com/pixel.gif","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/user-lists/960612778/?random=1523791866872&cv=9&fst=1523790000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=2628349615&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/respawnables-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/kingroot-android.png:l","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_News/ic/d61dcdf7/e7066e3c.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBiwNf.img?m=6&o=true&u=true&n=true&w=30&h=30","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://img-ads.csdn.net/2016/201608021757063065.png","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel/attr?d=AHNF13LlAh4YMdPok7nSKb8mCWL6UyeVDhgpBAQubx1nJuQVGc4Xy2XxRkQeKc3Z-kGG7OYyf1po","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=3825186185","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/default/transform/266/w640h426/20180415/7snV-fzcyxmu9317576.jpg/w200h134f1t10l50q90c55.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=1709604960,3481050662&fm=173&app=25&f=JPEG?w=218&h=146&s=B61D15C740F2B9F7DCDCD9B303004001","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f17/7586156f69855bf6314c4c284e715357_erotic_285x160.jpg?cno=4edf","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/icon/weath_bg/sunny_6345fbc.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4158.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180415/b0e799d4c2f04d2a9fa62eaa25ae6052.jpeg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/16999/0/0/307/ECAcc%20(saa%2F8352)/0","request_type":"text"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/home-illo-team-code.svg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/13.svg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://www.microsoft.com/mwf/_h/v1.17.3/mwf.app/fonts/mwfmdl2-v1.17.3.woff","request_type":"font"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages.adobe.com/etc/beagle/public/globalnav/adobe-globalnav/latest/adobe-globalnav.min.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-LoginPage-e93be3bed888bc20b54e.js","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/pjs-CloseupPage-bff6fa6b6ef10f3d2ae1.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/yvpub/player/js/player.js?v=201804152032","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/fonts/rfont.e32845c28279768f8ff1dfc728859640.woff","request_type":"font"}
+{"origin":"http://www.csdn.net/","request_url":"https://dup.baidustatic.com/tpl/fb.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V3RNMzR3QUFDR01mUGZ5UQ&url=/1/gr%3furl=https%253A%252F%252Fib.adnxs.com%252Fpxj%253Faction%253Dsetuid(%2527__EFGSURFER__.__EFGCK__%2527)%2526bidder%253D51%2526seg%253D2634060der%253D51%2526seg%253D2634060","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.extend.tv/r.gif?exchange=googleadx&google_gid=CAESEBAfCBNtDSJsvPKNHD4NXq8&google_cver=1&google_push=AHNF13KmTePGbbNkw4ua1CWY1YR6KSKyw4nZZZrdYYlEOxXt","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAv9tAkK17XmQMMLFslSmieiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://imageproxy.pimg.tw/zoomcrop?url=http%3A%2F%2Fg.udn.com.tw%2Fupfiles%2FB_HE%2Fhedy7103%2FPSN_PHOTO%2F897%2Ff_12316897_1.jpg&width=90&height=65","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://odr.mookie1.com/t/v2?tagid=V2_393725&AMAZON_REGION_SPECIFIC_ENDPOINT=aax-eu.amazon-adsystem.com/s&src.visitorID=7El2VzufSmCyxnWmPsbg_A","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yahoo.com/cms/v1?nwid=10000010181&eid=JG0QC2PD-14-82AL&sigv=1&esig=2~850dc61dee817b551815e100cd33199d9c846b4c","request_type":"text"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://cas.criteo.com/delivery/ajs.php?ptv=48&zoneid=647910&cb=86614917194&nodis=1&charset=UTF-8&dc=2&loc=https%3A%2F%2Fmail.ru%2F","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/v1/article/search/tag/crafty?pageSize=3","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"http://www.ok.ru/","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=818868a9-40a0-11e8-9c58-1fdd5b850e01","request_type":"other"}
+{"origin":"http://www.office.com/","request_url":"http://www.office.com/","request_type":"other"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/resources/styles/0/boot.worldwide.narrow.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/yc/css/bundle.c60a6d54.css","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=index&id=E4EPBoH4q1pwUnWB5hhuNTcmdFw4ZgAC","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a67349c00005ad338804cf270db7404&pid=mm_113716014_12970037_52768234&cid=258980&mid=3276&oid=376&productType=1&qytInfoMTime=1523728959&cb=754523295","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/un?uniq=WggBALi2dAABOAcB&euniq=WwgBAHsTAAAJCAAB&rnd=157104912","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-279179-2&cid=10481343.1523791867&jid=194842542&_v=j66&z=1958789321","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1z119kbGYBuNjy0Fo763iBFXaq.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/nnnmmm1255/albumset/16217543/zoomcrop/75x75.jpg?v=1523785716","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_politics.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/image_black.png","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&ph=2d1251ae-7f3a-47cf-bd2a-2f288854a0ba&plm=5&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://sync.1rx.io/usersync/tradedesk/c59859bc-6187-4823-9406-49cb7655b21f","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://servedby.flashtalking.com/container/10943;85008;8362;iframe/?spotName=Variables_Tag&ftXRef=&U1=91347194757900030554314852707948543921&U2=&U3=&U4=adobe.com&U5=&U6=&cachebuster=27481.63080445276","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://secure-dcdn.cdn.nimg.jp/comch/channel-icon/128x128/ch1038.jpg?1520941403","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/c03fd5535e161c3d06b507.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/017/2e2/080/big_lq/34fdbab112294e511ab2d609f6a35c5b.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/64/8e/b9/648eb9d1882b747c8297f12abd237b7a/648eb9d1882b747c8297f12abd237b7a.20.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4159.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_40,y_-2,w_589,h_393/os/news/140997982937dd429447e870ab559dda.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/amazonlaunchpad/de/Gateway/2018_02/iolandac_2018-02-05T15-59_0ebc52_1099615_de_launchpad_gw_quadcard_feb18_420x420_9._CB487250273_.jpg","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://stc.utdstc.com/fonts/roboto-900.woff","request_type":"font"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-54133e4209c7a707dc0001c5.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_1,m-index_top_news_1,m-index_top_news_2,m-index_top_news_3,m-index_tv_tg_1,m-index_tv_tg_2,m-index_top_pic_1&relatedID=&news=0_0,228338935_267106,228338785_585752,228317563_267106,0_0,0_0,0_0&SUV=null&_time_=15237919393348386980033631","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://a125375509.cdn.optimizely.com/client_storage/a125375509.html","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938182_5420134891159&itemspaceid=12424&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938182&cnid=228041976,228144587,228321611,228065618,228163124","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log_js_sw_data","request_type":"text"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fdsum-sec.casalemedia.com%2Frum%3Fcm_dsp_id%3D71%26external_user_id%3D__EFGSURFER__.__EFGCK__","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/aw/qtips/configs.html","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=www.reddit.com","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/js/tingyun-rum.js?1511847956","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01KEEhMJ-KL.js?AUIClients/DetailPageAlohaAssets","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://idpix.media6degrees.com/orbserv/hbpix?pixId=3715","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=VsMmnoFtTsW43_GKdn8B2A&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/css/shell-mobile.css","request_type":"css"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/pixel/AMXnASUQ_ymklEz0qLMr4nhLN0dY631pLoCVknqpxxAIT_oYLh0u1rSU6LzlajLQDfB1UCGVhVQgNK_ydp90YVEm0bxbAAQQiM_InWTKkJpnFPPD037x2XDJiP-537rA2h9gtUVk5k0KaW-WrTfyrud8sgqXGOQJrRlqGMQFOWtQl653.gif","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://s.amazon-adsystem.com/ecm3?id=x0nNYbCoROf9FpI+94uDGcWWwYjZzChgQG1x/JmYjWc=&ex=rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://pixel.wp.com/g.gif?x_stats-initial-visibility=visible&v=wpcom-no-pv&rand=0.11720122451176085","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://v.admaster.com.cn/i/a105788,b2430618,c211,i0,m202,8a2,8b2,j9095216f-9072-4a4a-82e2-ce50ba9ce1de,h","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_yaowen-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/hot1.gif","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.deepintent.com/usersync?p_id=109","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/img/ns_diff_color_v3_991d8b3.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/photomath-android.png:l","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=g8f47s39e399f3fe&google_push&google_sc&google_hm=V3RNNGdRQUFCaWJtNE8xNw==","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tps/TB1WIQfJFXXXXbqXFXXXXXXXXXX-88-88.png","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/3507000/3507334/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/VTL6bc_D6zsykk74L3Z33g/009/341/247/320x240.6.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://img1.360buyimg.com/pop/jfs/t18004/126/1431072735/26260/ab41940f/5ac9e94fNdf32329e.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvTwUN.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=748&y=265","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20171229_30qiang_728x90.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/ddf71d53-58d8-473d-bd3d-f708017337e5/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/vr.svg","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0","request_type":"font"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/Semibold/latest.woff2","request_type":"font"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/images/20170606data_get.js","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/js/a30116eb.pop.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/dal.png&w=288&h=288","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://m.ebay.com/?_mwBanner=1","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/basics/searchinfo7.1.js?v=20180323","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/element.min.js?v=160118","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://syndication.exosrv.com/ads-priv.php?i=0","request_type":"html"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.facebook.com/","request_url":"https://www.facebook.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938288_5125906155575&itemspaceid=12293&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938288&plateid=1004300000,1001300000","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gpsfront.aliexpress.com/getRecommendingResults.do?widget_id=5252019&numTopProducts=3&imageSize=220x220&platform=msite&__amp_source_origin=https%3A%2F%2Fm.aliexpress.com","request_type":"script"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/assets/scripts/vendor/cedexis/1-13960-radar10.min.js?_v=f7f836603c8f896d4c0a363f189d0441","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/5w3jqr4k?redir=https%3A%2F%2Fcm.g.doubleclick.net%2Fpixel%3Fgoogle_nid%3Dg8f47s39e399f3fe%26google_push%26google_sc%26google_hm%3D%24%7BTM_USER_ID_BASE64ENC_URLENC%7D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/data.gif?_kuid=L6N62llA&_kdpid=4e3f8627-26fa-484d-bd95-a1f8f09d95a6&dlxid=&dlxdata=","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/NC4WTmcy?redir=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner_id%3Dcb276571-e0d9-4438-9fd4-80a1ff034b01%26puid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/uedata/nvp/unsticky/144-4203505-1964949/NoPageType/ntpoffrw?ld&v=0.200436.0&id=XZ4D3PPDB36HTEGXD7ZH&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=XZ4D3PPDB36HTEGXD7ZH&ue=41&bb=2118&ns=2124&cf=2284&be=2346&af=2370&ne=2469&pc=9921&tc=-1827&na_=-1827&ul_=-1523791910544&_ul=-1523791910544&rd_=-1523791910544&_rd=-1523791910544&fe_=-30&lk_=-1813&_lk=-1365&co_=-1365&_co=-666&sc_=-1045&rq_=-661&rs_=-40&_rs=844&dl_=-11&di_=2358&de_=2358&_de=2358&_dc=9921&ld_=9921&_ld=-1523791910544&ntd=0&ty=0&rc=0&hob=33&hoe=41&ld=9924&t=1523791920468&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:46-8-4-24-5-0-1&csmtags=aui|aui:aui_build_date:3.18.6-2018-04-06|gwImgNoCached|fls-na|gwmNoCardHistory|aui:ajax&viz=visible:40&pty=gateway-phone-web&spty=smartphone-card&pti=mobile-unrec&tid=XZ4D3PPDB36HTEGXD7ZH&aftb=1","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/sync?userid=36970468-9dbf-4c0a-b6b0-b464a445bb09&pn_id=bsw","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/uedata/unsticky/262-9616072-1847409/NoPageType/ntpoffrw?at&v=0.200436.0&id=Q3AKTQX4Z8AX1W7T64V5&m=1&sc=adblk_no&pc=13571&at=13571&t=1523791869440&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=Q3AKTQX4Z8AX1W7T64V5&aftb=1","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/best-fiends-android.png:l","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/vi/movie.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/okasos/albumset/2285315/zoomcrop/75x75.jpg?v=1521298838","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://px.srvcs.tumblr.com/impixu?T=1523791921&J=eyJ0eXBlIjoidXJsIiwidXJsIjoiaHR0cDovL3d3dy50dW1ibHIuY29tLyIsInJlcXR5cGUiOjAsInJvdXRlIjoiLyJ9&U=FKAAILPOCK&K=fd25e46a34adf94ecf3a0906e71d238f7d0e00ca1a68eaa143d2c3b7f555aad1&R=","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/youxinicon_20170913.png","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"http://g-ecx.images-amazon.com/images/G/01/giveaway/confetti-v3.png","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/InternationalCustomerPreferencesNavAssets-icp_sprite_2x-391462dbcf09456cb0249b135186930d7e699c73._V2_.png","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=35117910-40a1-11e8-a553-0242acc1cc07%252Chttps%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253D35117910-40a1-11e8-a553-0242acc1cc07","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://interface.sina.cn/dfz/outside/wap/news/langshou_feed_data_routerv2.d.json?callback=jsonp_09223199579677122&timestamp=1523791845351&xc=1","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://fonts.gstatic.com/s/rubik/v7/iJWKBXyIfDnIV7nBrXyw023e.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/1708000/1708936/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_ylahTmYz5O7yJUm4d4PDtA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.googletagservices.com/tag/js/gpt.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=4&cm=68fd6aac-daef-322f-f884-f3a759a224a6","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1?$mscomCookies=true&ext-javascript-msfpc=%27GUID%3Dfbae62a858c942f989eb9eafc49b9bdb%26HASH%3Dfbae%26LV%3D201804%26V%3D4%26LU%3D1523791838101%27","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://cdn.registerdisney.go.com/v2/inner/tealium/utag.34.js?utv=ut4.44.201804042254","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn3.optimizely.com/js/geo2.js?cb=1523791865131","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/jquery.showMenu.js?20170420","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://analytics.twitter.com/i/adsct?p_user_id=86070857378125119120981354726841823876&p_id=38594","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fonts.googleapis.com/css?family=Open+Sans:400&lang=zh-CN","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/floors/floor06011.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/index/floors/floor06008.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/01/csm/showads.v2.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_Simmons_says_Philly_atmosphere_was_insane/dm_180414_Simmons_says_Philly_atmosphere_was_insane.jpg","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"http://www.google.ca/","request_type":"html"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/gen_204?s=webaft&atyp=csi&ei=zjfTWo-aD4mg8AOcoa_wCQ&rt=wsrt.2140,aft.369,prt.208","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/img/v4/animation/security/security_localized.html?v=9bd4dace1&l=en","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/icon-desktop.svg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"http://www.imdb.com/","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/navigation","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=m.txxx.com","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770090&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792003883&fs=2&pvid=e4044ee69fa407db83f3619bc07ab219&cg=a0fc6174a5e67bae4d4236e4f957dd1a","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://pv.csdn.net/csdnbi","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://rtd.tubemogul.com/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/modals_commons.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/adobe.min.fp-05a76ee0744b9a0bab6197a0316cac4a.css","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://events.bouncex.net/track.gif/eligible?uq=1&campaignid=701822&source=bouncex&agent=js&mode=0&websiteid=340&visitid=1523791884195281&deviceid=4982481126584822575&pageviewid=1&sequenceid=2&clienttimestamp=1523791891351&clientapiversion=tag2&device=p","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://hwcdnssl.cedexis-test.com/img/r20.gif?rnd=0-1-13960-0-0-17000-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/scary-chat-stories-android.png:l","request_type":"image"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://whatsapp.com/favicon.png","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1LoDOk1OSBuNjy0Fd762DnVXaQ.png","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://pingtas.qq.com/webview/pingd?dm=xw.qq.com&pvi=230541523791919458&si=s921541523791919463&url=/index.htm&arg=&ty=0&r2=500421382&scr=360x512&scl=24-bit&lg=en-us&tz=7&random=1523791923181&r3=574&ext=pfm=0_1067_972_560_555;version=2.0.6","request_type":"html"}
+{"origin":"http://www.hao123.com/","request_url":"http://as2.m.hao123.com/wp1d.htm?exl=on5naazj_g2xfj4sw2ev_54p&ppeyfx=HhDzj3odIu9AYTSj9qHEBVWpa0j6uYWt%0IKI%7Wf","request_type":"html"}
+{"origin":"http://www.netflix.com/","request_url":"https://s.thebrighttag.com/tag?site=voKfK9l&mode=iframe&is_member=anonymous&membership_status=NON_REGISTERED_MEMBER&session=n%2Fa&country=US&referrer=netflix.com%2Fbt%2FnmLanding&source=&fbaId=f1fdc59c-9452-4167-a583-cc8ede9a2929","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://wuliao.epro.sogou.com/wapxml?id=563067&hd=75&m=&if=16&ex=1&tmp_cdif=0&sohuurl=https%3A%2F%2Fm.sohu.com%2F%3Fpvid%3D000115_3w_index%26jump%3Dfront&refer=&ti=%E6%89%8B%E6%9C%BA%E6%90%9C%E7%8B%90%E7%BD%91&ua=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&rnd=87625502c17aab5b&z=af41a8a8e455278f&ssi0=1796&bs=360,512","request_type":"html"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1.bBghNGYBuNjy0Fnq6x5lpXa8.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_TV_UI.jpg","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_cancelanytime_withdevice.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSQfi.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=663&y=270","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSDGN.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=881&y=840","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/gps0000gps/albumset/13593043/zoomcrop/75x75.jpg?v=1517123334","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/e3/08/99/e3089934d88a1a9df1b881d55fae047c/e3089934d88a1a9df1b881d55fae047c.23.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/d1/a8/2d/d1a82d0a26eef25aab65ed6b76458603/d1a82d0a26eef25aab65ed6b76458603.8.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t01940e6dd1e2b74653.webp?size=588x422","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/avatar_ellip.svg","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/common/error.min-vflJ9NAP2.js","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/js/3f508ef0.index-video.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/rabbit/exposure-click/main_flume.js?v1.15.35","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12280&impid=&at=1&mkey=&latcy=4346&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=6895031744861&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942584","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/store/buy/cartcount","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/alternate_wtl_browser_performance_info","request_type":"text"}
+{"origin":"http://www.amazon.com/","request_url":"https://ads.yahoo.com/cms/v1?esig=1~b9bada6fffbf45c1ffda7783879fb5715486894a&nwid=10000922750&sigv=1","request_type":"text"}
+{"origin":"http://www.amazon.in/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://d.company-target.com/ul_cb/pixel?type=js&id=1421361512&page=https%3A%2F%2Fwww.adobe.com%2F","request_type":"script"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"http://cloudfront-labs.amazonaws.com/x.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://p.rfihub.com/cm?in=1&pub=224&getuid=https%3A//simage2.pubmatic.com/AdServer/Pug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTI3MzkmdGw9MTI5NjAw%26piggybackCookie%3D%24UID","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://x.bidswitch.net/ul_cb/sync?ssp=yieldmo","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=163911502661000498832&ex=neustar.biz","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/x/px/QuatP_kJk0XTvIxfxrwHiSYAAAFiyRR_wgMAAAGWASbfcLQ/nii/%7B%22ni%22:true%7D","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://pixel.mathtag.com/event/img?mt_id=888358&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c1.microsoft.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=9174E7EAE8624D1A8C05A88CE491F949&MUID=398FA6D04E55659D3C94AD024F0B64DD","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r3.mail.ru/k?81e4121baf7286eca0b199916eff4bfd","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://www.google.com/pagead/lvz?evtid=ALJwLvSbn6wR7buxDJ9XRyhpw3o8jNz6GnvkDl1fcky7501rjN01SZVvJJFk9-LNh8FVJW1wU1h2jHXaVJ0mysGoEODNKHXgRA&req_ts=1523791910&pg=feed&sigh=AD56X6uLh8mQXbnQWrQmocuNCBioviPRLg","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=1486958744&t=event&_s=2&dl=https%3A%2F%2Fen.savefrom.net%2F&ul=en-us&de=UTF-8&dt=Free%20Online%20YouTube%20Downloader%3A%20Download%20YouTube%20Videos%2C%20Facebook%20and%20many%20others!&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=biz-dev&ea=propellerads&el=show&_u=qGDAAAABC~&jid=&gjid=&cid=2145003528.1523791946&tid=UA-7055055-24&_gid=496215688.1523791946&cd1=2145003528.1523791946&z=1093387698","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/user-lists/977748509/?random=1523791866918&cv=9&fst=1523790000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=1874427928&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/approach/jslib/clear.gif?method=init&callback=mobiledeeplinkingcallback1523791948397","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/es-file-explorer-android.png:l","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/pic/ADtips.png","request_type":"image"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://lh3.googleusercontent.com/Ox0I1TTWHZU_TFva0ZaE4Jdsd1269KkdHBHawJwTE0k-MUmj7e5IO3u3ElNwMCxN2dQ=w300","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/xiecheng20171121wx.png","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://fonts.gstatic.com/s/opensans/v15/mem5YaGs126MiZpBA-UN7rgOUuhpKKSTjw.woff2","request_type":"font"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/screen/13/wilderness-action-001.jpg:l","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180415020123-ben-stiller-robert-de-niro-snl-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://yt3.ggpht.com/-KLfbkE3zovQ/AAAAAAAAAAI/AAAAAAAAAAA/gMZ_6qxvEXw/s68-c-k-no-mo-rj-c0xffffff/photo.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/b4/2d/08/b42d087dbd5f91fd67611fa2eae0d13e/b42d087dbd5f91fd67611fa2eae0d13e.8.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/c4/23/6a/c4236a4ee4981ad06cd5aac3c825f292/c4236a4ee4981ad06cd5aac3c825f292.30.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/lo/api/res/1.2/X8uSjAPUIQACpt7FruNSsg--/YXBwaWQ9eW15O3c9NjA-/https://ct.yimg.com/cy/4727/38214525430_30ae73_192sq.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/xLxfx-hURloRW9lOtFCJZ_cUH3VMRh4LQ6nHO2dqXVE.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://a.thumbs.redditmedia.com/9sL2uWFJTgtBoS0IJNnCutOBlqWNWsxWOendl3PgNP0.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71N5hSP49AL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.google-analytics.com/plugins/ua/linkid.js","request_type":"script"}
+{"origin":"http://www.onclkds.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/recaptcha__en.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://s3.amazonaws.com/ki.js/52510/bgJ.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/css/2.75.8/global.css","request_type":"css"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/font/JSMobile-86c0f.woff","request_type":"font"}
+{"origin":"http://www.wordpress.com/","request_url":"https://8017305.fls.doubleclick.net/activityi;src=8017305;type=invmedia;cat=obyv3klj;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=6423391887019.599","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://login.taobao.com/jump?target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.taobao.baichuan.smb.get%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.3%26appKey%3D12574478%26t%3D1523791823659%26sign%3D970aa63436f78b76c8fd5b5ce054e379%26api%3Dmtop.taobao.baichuan.smb.get%26v%3D1.0%26type%3Doriginaljson%26dataType%3Djsonp%26timeout%3D10000","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://ads.pubmatic.com/AdServer/js/showad.js","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/v3/pr?exlist=pp_mp_sx_ns_kr_g_bsw_bk_ox_index_aold_an_rb_fbca_aolv_twca_y_pm_adelphic_rlsa_adb&fv=1.0&ex-pl-fbca=KoauPan-R6uDjUaB1jdliw&ex-pl-twca=7LOhZDOrTi2dZfi89QUpvw&a=cm&ep=V9quwnq9fAvYL36O9pvFoLMDaVprqeAVc1q17uvvYJPcgFxeFb3SdJeBUcDGD_ITz53k6CcxyKthES7iFaJ2HrLMIK9UIeA2fKo6Mpc6Vhz9TLRvhIqYuXWtaD4adE1Z7PPSMSBjqtD0ePqTveRdQtTk24NOIMFFo5cEQlWx4B2gCyvuBwX3FwbuxLOra1OqT_xGBiAA8sjuYxtaa97ksQ","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google.com/recaptcha/api.js?hl=vi","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Identity%20Mobile$HamburgerMenu/cj,nj/867b6dc5/25e3d322.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://sb.scorecardresearch.com/b2?c1=8&c2=11473066&c3=2370896352948000006&ns__t=1523792027852&ns_c=UTF-8&ns_if=1&cv=3.1m&c8=&c7=https%3A%2F%2Fimg.scupio.com%2Fhtml%2Fad.html%3Fv%3D1.2.14&c9=","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://sync.ipredictive.com/d/sync/cookie/generic?https://aax-eu.amazon-adsystem.com/s/ecm3?id=${ADELPHIC_CUID}&ex=adelphic","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://bat.bing.com/action/0?ti=5637027&Ver=2","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=bidswitch.com&id=9ecc81da56bc2a150f96bb7b101fb55e","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.facebook.com/tr/?id=130492214192672&ev=PageView&dl=https%3A%2F%2Fwww.pinterest.com%2F&rl=&if=false&ts=1523791923931&sw=360&sh=512&v=2.8.12&r=stable&ec=0&o=30&it=1523791918963","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3DQ3AKTQX4Z8AX1W7T64V5%26ctb%3D1%26m%3D1%26sc%3DQ3AKTQX4Z8AX1W7T64V5%26pc%3D14740%26at%3D14740%26t%3D1523791870609%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQ3AKTQX4Z8AX1W7T64V5%26aftb%3D1:14741","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_ads_2x.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns2.gigya.com/gs/i/shareBar/button/mobile/buttonCenterImgUp.png","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/favicons/favicon-32x32.png?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fcmatch.youtube.com/pixel?google_gm=AMnCDoqu-LJCT5yKgmmb5mHt74bOwaR_tx2ICRv7rHnBu4I6HBp-8XiBDK7oDy74NJhrxPT1lk58hoJnpYtXWvWO0NQAOfsrLfRDUdgDeq2I2GVkoupgoM0","request_type":"image"}
+{"origin":"http://www.wikipedia.org/","request_url":"https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikinews-logo_sister@2x.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791943698_9833038976606&itemspaceid=15698&adps=6400320&apt=4&turn=2&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&suv=180415193221Z74L&appid=wapnews&_time_=1523791943698","request_type":"html"}
+{"origin":"http://www.gmw.cn/","request_url":"http://www.gmw.cn/","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/PLAYERUNKNOWN%27S%20BATTLEGROUNDS-429x572.jpg","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/consumer-mobile-hero.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180415033653-01-beyonce-coachella-0415-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://as2.m.hao123.com/mz/4=ggnqpvqy2z,2a7achejkp&1a=z0?ectw=kyvsxln_12c9s_ess","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_57,y_0,w_555,h_370/os/news/192b5f84f2233e13f3365c9a5551b383.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://aecpm.alicdn.com/simba/img/TB14ab1KpXXXXclXFXXSutbFXXX.jpg_q50.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/S7RrkRk3M3Dv7naDErZqkg--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/es-US/homerun/yahoo_view_839/27fb5bd4571c2d8f3a0f4c1999eb1c12","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/51D8NXwQfvL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://s0.2mdn.net/3071236/1-V4_FTWD_320x50.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/kindle/merch/2018/campaigns/Jan_Promo/qh-gw-d-uk-1242x450-v3._SX1242_CB488183538_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s134x134_jfs/t13519/289/570849623/290501/37fcc600/5a0e9a16N55e43e87.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.ugdturner.com/xd.sjs","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://log.mmstat.com/eg.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-app_install_sm/td-applet-viewer-templates-app_install_sm-min.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://txt.go.sohu.com/ip/soip?_=1523791937758","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/js/collections/mobile/upsell-ad-70887417._CB499613612_.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://sstats.adobe.com/id?d_visid_ver=2.5.0&d_fieldgroup=A&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&mid=91347194757900030554314852707948543921&ts=1523791996995","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1W0fx?ver=ade7&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=673&y=198&s=1436&d=808&aim=true","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://www.google.com/pagead/drt/ui","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://secure.adnxs.com/ttj?ttjb=1&bdc=1523791858&bdh=N5n2teqWfSHuiMM95Mn2CVCw32U.&&bdref=https%3A%2F%2Fmail.ru&bdtop=false&bdifs=2&bstk=https%3A%2F%2Fmail.ru,https%3A%2F%2Fad.mail.ru%2Fadi%2F78733%3Frnd%3D117101971,https%3A%2F%2Fsecurepubads.g.doubleclick.net%2Fgampad%2Fads%3Fgdfp_req%3D1%26glade_req%3D1%26glv%3D26%26dt%3D1523791849487%26output%3Dhtml%26iu%3D%252F205338224%252FMail.ru_mobile_320x50%26sz%3D320x50%26sfv%3D1-0-10%26correlator%3D4073452669305138%26adk%3D3471309403%26biw%3D-12245933%26bih%3D-12245933%26adx%3D0%26ady%3D0%26oid%3D3%26u_sd%3D3%26ifi%3D1%26click%3D%2525%2525CLICK_URL_UNESC%2525%2525%26nhd%3D1%26url%3Dhttps%253A%252F%252Fmail.ru%26top%3Dmail.ru%26loc%3Dhttps%253A%252F%252Fad.mail.ru%252Fadi%252F78733%253Frnd%253D117101971&&id=12753689&size=320x50","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MTk2OSZ0bD0yNTkyMDA=&piggybackCookie=ad5bfb2d-4c70-4b7d-b3aa-7ddce6ba8a99","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938138_4324309261251&itemspaceid=13702&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938137&cnid=228305282","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52772341&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791984058&fs=0&pvid=ac1996fee5a876531bc61707bfef8f17&cg=aae85e7aebd2cc1da85a6b7fd8963e1d","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com%26","request_type":"other"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/c/inception-789696.css","request_type":"css"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_10%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D29783%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845943,aid=exp_hotweibo-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://c.bing.com/c.gif?Red3=MSNLI_pd&rid=e86f55f7-8070-4d56-8af4-af783e3cb6c4&lang=en-us&dgk=tmx.mobile.webkit.android&imd=1&pn=startpage&rf=&tp=https://www.msn.com/","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/external-button._CB304896345_.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/Sp4ZzNq2eI5tylQz9NrBND3-VDG7XcKBr0PXMtqZFjvNywZSXRsOKmeCTxQ8lH4=w256","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p7.qhmsg.com/d/inn/2edf2228/aqrj/weishi_60.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/icons/on_time.png","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=054f32o&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/paper-atlasgrotesk/AtlasGrotesk-Medium-Web-vfl38XiTL.woff2","request_type":"font"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/heroes/iphone-x/iphone_x_small_2x.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/b1_rovincJc3w-JPGCDw3w/009/338/677/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afp.alicdn.com/afp-creative/creative/u113716014/92766f4e6e57bf7f4c75e3db723820be.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t01a432e2f8e781609d.webp?size=500x276","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google.com/js/bg/-AZv2KuCjcgKyHntfopJPbiyNz6ONfW7PV3A4azG2L0.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/popunder-build.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/vendor-mweb-356b91b07e2b9f847bd5.js","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/v/wcqazrf14y4d1kvrfdndn10c4qp.css?proc=DU:N","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/51chvDI28JL._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset","request_type":"css"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/lib/invoke/fnProvider_7f0901c.js","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/c/index-5e8674.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://widgets.outbrain.com/outbrain.js","request_type":"script"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.netflix.com/","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oHA42XtnKKVUxRreO5bpYmi7UqwDw","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://gha.ebay.com/nproxy/notification/v1/bullseye","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.adsafeprotected.com/rjss/st/143441/22764869/skeleton.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixanalytics.com/js/pi.min.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://x.bidswitch.net/sync?ssp=pubmatic","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/components/react_locale_selector-vflanx-FX.css","request_type":"css"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/styles__ltr.css","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=mplatform.com&id=11459127779632002834","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://cl3.webterren.com/3.gif?z=7&a=162c9148979&c=http%3A//www.gmw.cn/&d=1428&k=S&H=www.gmw.cn&r=6c6af2fea49ca41c","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/uedata/unsticky/262-9616072-1847409/NoPageType/ntpoffrw?ld&v=0.200436.0&id=Q3AKTQX4Z8AX1W7T64V5&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=Q3AKTQX4Z8AX1W7T64V5&ue=24&bb=1825&ns=1832&cf=2011&be=2065&af=2096&ne=2185&pc=13181&tc=-2261&na_=-2261&ul_=-1523791855869&_ul=-1523791855869&rd_=-1523791855869&_rd=-1523791855869&fe_=-36&lk_=-2239&_lk=-1875&co_=-1875&_co=-1167&sc_=-1564&rq_=-1158&rs_=-50&_rs=346&dl_=-12&di_=2087&de_=2088&_de=2089&_dc=13181&ld_=13181&_ld=-1523791855869&ntd=-1&ty=0&rc=0&hob=19&hoe=25&ld=13183&t=1523791869052&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:58-7-4-38-5-0-1&csmtags=aui|aui:aui_build_date:3.18.6-2018-04-06|gwImgNoCached|fls-eu|gwmNoCardHistory&viz=visible:24&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=Q3AKTQX4Z8AX1W7T64V5&aftb=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=771&dpuuid=CAESEEcvBZ3zAjhkn1fpJQP0fDE&google_cver=1","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/png/site2/20180222/f44d305ea0d81bf8a98639.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/webapp/index/img/default.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://bongacams.com/validate-password?username=&value=","request_type":"html"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/?r=1-null_user","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/sharpgrotesk/SharpGroteskDBBook20-vflytuLBR.woff2","request_type":"font"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/transform/310/w710h400/20180415/cTVh-fzcyxmu8953876.jpg/w710h400z1l50t154b.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/c03fd5535e161c3d061f05.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afp.alicdn.com/afp-creative/creative/u113716014/bf8c8920677cc2acc01e2124e4e64090.jpg","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://api.branch.io/v1/open","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://universal.iperceptions.com/wrapper.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://s.yimg.com/wi/ytc.js","request_type":"script"}
+{"origin":"http://www.google.pl/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.cnn.com/css/2.75.8/pages/page.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41DF6mj397L.css,31-8Mn1M1oL.css,31ZYydvXTIL.css,11tkAOwE6OL.css,21xItms32EL.css,11ISqSj9gHL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,21QwDiO8ycL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11ZLLOcO8BL.css,01ATX4LEFqL.css,21CNSKZ67ML.css,11rhPo030XL.css,11G8UP3P7ML.css,51oAYplAOyL.css,21LCBYGBqCL.css,21lDMA2J74L.css,31m2Sw3bVfL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21f0r7D13IL.css,61lDBjn6HPL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,01QRe-mUhyL.css,31LBzl8T3vL.css,21mCSoVjI4L.css,11cAYJlTEgL.css,018mGORJ7tL.css,11fvu+DzMxL.css,11iDQvZvByL.css,01lh9w-GYYL.css,11Mso4bvY-L.css,01LCsoCesOL.css,01NEM4SRd9L.css,21pnh6VHUzL.css,01YXqSisf3L.css_.css?AUIClients/DetailPageMobileWebMetaAsset","request_type":"css"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/scripts/boot.worldwide.3.narrow.js","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzNDAmdGw9MTI5NjAw&u=94AC3827-BDDB-436B-A363-D775FCA8DB42&piggybackCookie=","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://xhamster.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100291235&apid=beans_12292&impid=02ae7c35b3c1133a5_0_0&at=1&mkey=02ae7c35b3c1133a5_0_0&latcy=5187&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=4618.640625&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3Di9475oq4nET%2Bl9E%2BJ4GhIZj8LiFzDgmk8s%2BtyXgc41SknYGC5%2FZRIotIjzGsRlw4QL218iGG2UqSUs8fIKNqTS99yj1u%2BMpQ6uRbe6Jk4zrU8f0WLYYJIRwHd%2FA5S%2FEbbpqGXyJ9QflSddImhU6QCaegiXW60FyFji7%2FSlA5M1uoPv%2BcaSwAxGH345IzhK2YgaJ%2BBMI7jNN5tc08W49bgqmTG3manDWztUMur50OG%2Fgeja3t16pNv45SYhgW7DuvqNUOTGQN%2F%2F%2FDdUSQElWyiuWOynjBu8ZpRh%2B%2BUpEjzgkKiB6%2F7B0lMvaw2N%2BdZoWS4qjLa14abdy7m07GZn5f9RdcfEvDShWalrI%2Fd%2FSmeYrMMn88lWEmRBVBN9h869qWyeO4Dcflnz7zxdEfdwK47xaeCL2KnD1Wrl4exiM9pRuVQbTh%2BA0Y46wBlUcIvk2KGEbtvKWoFwuqWCtntuQkwEUDqSBZuyPlN9Ts31GAqhgRbz3Ggr0DRMC5%2BPBZxSkMMDuuF5DWLGSTDMT1o4HZvJmMYZ8P4GXjtxDLZcKJZjzl8UY2gFNZXLhG%2FK%2F%2BsIzo%09tt2%3D1523791943123%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=7735893201484&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791943475","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/bframe?hl=en&v=v1523554879111&k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo&cb=e30hxdnf29pr","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://pagead2.googlesyndication.com/pagead/js/r20180411/r20170110/osd.js","request_type":"script"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://r.dmp.sina.cn/cm/waplist?sinaglobal=__149.20.63.13_1523791820_0.19234800&host=sina.cn&callback=_sinaads_cbs_rhnhr6","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://sb.scorecardresearch.com/p?c1=2&c2=20632726&cv=2.0&cj=1&c7=https://www.reddit.com/&c4=https://www.reddit.com/","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://revee.outbrain.com/page/view","request_type":"other"}
+{"origin":"http://www.tmall.com/","request_url":"https://pass.tmall.com/add?cookie2=1ba32d15d29c84f24b13237f9958ab43&t=71c2b3e94299583b7e75a8f932e08868&_tb_token_=ee3371b3be6e3&tmsc=1523791823620000&opi=10.103.184.133&pacc=06RIiXUDvLIFbpnJITdPag==&target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.tmall.tac.gateway.execute%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.11%26appKey%3D12574478%26t%3D1523791819640%26sign%3D8ab28eb896b2507753d64da9f48840a2%26AntiCreep%3Dtrue%26api%3Dmtop.tmall.tac.gateway.execute%26v%3D1.0%26ttid%3Dh5ttid%26type%3Djsonp%26dataType%3Djsonp%26timeout%3D2000%26callback%3Dmtopjsonp1%26data%3D%257B%2522msCodes%2522%253A%25222017080800%2522%252C%2522params%2522%253A%2522%257B%255C%2522isH5%255C%2522%253A%255C%2522true%255C%2522%252C%255C%2522h5ttid%255C%2522%253A%255C%2522TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%255C%2522%252C%255C%2522pageCode%255C%2522%253A%255C%2522SELECT_FRONT_PAGE%255C%2522%257D%2522%257D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://bat.bing.com/action/0?ti=5526986&Ver=2&mid=0baa9a85-c971-a94d-a925-89543ea12e41&evt=pageLoad&sid=91b64526-1&lt=8366&pi=0&lg=en-US&sw=360&sh=512&sc=24&tl=CNN%20-%20Breaking%20News,%20Latest%20News%20and%20Videos&kw=cnn%20news,%20daily%20news,%20breaking%20news,%20news%20today,%20current%20events&p=https%3A%2F%2Fwww.cnn.com%2F&r=&msclkid=N&rn=559952","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=yhoo&partner_uid=E0","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/x/px/Qt12fUeHFEtNm7jp5V1XZkEAAAFiyRJ_2wMAAAGVAZopomI/nii/%7B%22ni%22:true%7D","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/x/px/QrOBnc41VABof6yRFOKklT8AAAFiyRUBqQMAAAGbAQEw8GE/nii/%7B%22ni%22:true%7D","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=spotx.com&id=a768cebe-40a0-11e8-81e4-1a79d3e61a01","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://pixel.wp.com/b.gif?subd=wordpress.com&host=wordpress.com&blog=1&v=wpcom&user_id=0&tz=0&rand=0.7459602826022038","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://tdameritrade.demdex.net/firstevent?d_event=imp&d_src=38454&d_site=%esid!&d_creative=%ecid!&d_adgroup=%eaid!&d_placement=%epid!&d_campaign=%ebuy!&d_adsrc=48123&d_bust=%n","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/day-r-android.png:l","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static4.dditscdn.com/mbl/frontend_backbone/static/livejasmin/image/logo-cb42b.png","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/flags/1/images/us/32.png","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/6190d7db-effd-429a-972a-c8adf56a925a_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/default/266/w640h426/20180415/9A6P-fytnfyp5340155.jpg/w200h134f1t10l50q90c55.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/31b0dc245620d322a95ad5e4f0ac79b6_erotic_285x160.jpg?cno=bf81","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s720x220_jfs/t19573/117/1614627888/102825/134b22bf/5ad0563eN7f0ff0db.png!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-af-0.0.337/af-eu-tracking/af-eu-tracking-min.js","request_type":"script"}
+{"origin":"http://www.onclkds.com/","request_url":"http://www.onclkds.com/","request_type":"html"}
+{"origin":"http://www.google.fr/","request_url":"https://www.google.fr/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-2647689032095179&output=html&h=280&slotname=6596214357&adk=1374981622&adf=3407270571&w=336&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&ea=0&flash=0&wgl=1&dt=1523792015892&bpp=45&bdt=488&fdt=50&idt=63&shv=r20180411&cbv=r20170110&saldr=aa&correlator=4374426233436&frm=8&ga_vid=707816148.1523792016&ga_sid=1523792016&ga_hid=1913487757&ga_fc=0&pv=2&iag=60&icsg=2&nhd=3&dssz=3&mdo=0&mso=0&u_tz=-420&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=0&ady=0&biw=-12245933&bih=-12245933&isw=336&ish=280&ifk=4279473675&scr_x=-12245933&scr_y=-12245933&eid=21061122%2C20040069&oid=3&rx=0&eae=2&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C336%2C280&vis=1&rsz=%7C%7CceE%7C&abl=NS&ppjl=u&pfx=0&fu=8208&bc=5&osw_key=3474304009&ifi=1&dtd=89","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://h5api.m.tmall.com/h5/mtop.tmall.tac.gateway.execute/1.0/?tbpm=1&https=on&jsv=2.4.11&appKey=12574478&t=1523791819640&sign=8ab28eb896b2507753d64da9f48840a2&AntiCreep=true&api=mtop.tmall.tac.gateway.execute&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp1&data=%7B%22msCodes%22%3A%222017080800%22%2C%22params%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/drt/s?v=r20120211","request_type":"html"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditmedia.com/gtm/jail?id=GTM-W7RKT4","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938113_2029174901022&itemspaceid=12273&adps=6400320&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938113","request_type":"script"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www-cdn.whatsapp.net/img/v4/icon-iphone.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/autocomplete-list/lang/autocomplete-list_en.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/312aj6HKNXL.js?AUIClients/INRetargetingAsset","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=ADB&partner_url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=86070857378125119120981354726841823876","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=558f8732-6e07-4ff6-bc5d-d07d21a96a01&ttd_puid=b60eac03-40a0-11e8-b967-024257f42601%2Chttps%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3Db60eac03-40a0-11e8-b967-024257f42601","request_type":"other"}
+{"origin":"http://www.sohu.com/","request_url":"https://adv-sv-stat.focus.cn/adv/producer/sendLog?type=2&ad_type=0&demander_id=-1&plan_id=-1&order_id=-1&idea_id=-1&estate_id=-1&city_id=-1&city_name=&area_code=-1&ad_pos_id=-1&resource_id=-1&bid_hash=&domain=m.sohu.com&source_agent=4&referer_url=&user_yyid=&user_ecoid=-1","request_type":"other"}
+{"origin":"http://www.youtube.com/","request_url":"https://fonts.gstatic.com/s/roboto/v18/KFOmCnqEu92Fr1Mu4mxPKTU1Kg.ttf","request_type":"font"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/assets/github-96ebb1551fc5dba84c6d2a0fa7b1cfcf.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/font_paper_atlas_grotesk-vflEbKJso.css","request_type":"css"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/searchbar-m/4.0.20/index.css","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=spotx.com&id=debd7e9d-40a0-11e8-9a4e-1e286a820301","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=84&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A84%7D&logFlag=uaction_1523791857874&t=1523791941877","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-20947729-1&cid=603572290.1523791991&jid=2122569356&gjid=401697157&_gid=1362978636.1523791991&_u=IGBAgEAB~&z=184678812","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.amazon.com/uedata/nvp/unsticky/144-4203505-1964949/NoPageType/ntpoffrw?at&v=0.200436.0&id=XZ4D3PPDB36HTEGXD7ZH&m=1&sc=adblk_no&pc=11048&at=11049&t=1523791921593&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile-unrec&tid=XZ4D3PPDB36HTEGXD7ZH&aftb=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=86070857378125119120981354726841823876&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d86070857378125119120981354726841823876&mm_bnc&mm_bct","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=411&dpuuid=WtM34wAACGMfPfyQ","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=6835&dpuuid=UP71fde697-40a0-11e8-99dc-022d4faf2c18","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://m.jd.com/images/index/seckill-220-new.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/pes-2017-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/travis-ci.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://tpc.googlesyndication.com/simgad/9166515314481223382","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/jQrLB0S1fjOjqnJ145d0OBbOHHIR9nce1lnjzGL2YCvDK8ocxIZOM6wR3GNJLw=w256","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/icons/core.png","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://eclick.baidu.com/fp.htm?br=2&fp=FFCD3806CE347E480226781625EEA0EF&fp2=0F90C49B17C2F2D7BA4D9BF9075C4BC8&ci=&bi=&im=0&wf=0&ct=2137&bp=&m=&t=0&ft=&_=1523791945119","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Dota%202-429x572.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s220x220_jfs/t3664/213/2212841326/143271/e8b78b47/58453027N6e97b8be.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/4695354fb8cfd0f028eeaaa760528e78_erotic_285x160.jpg?cno=772","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_180%2Cw_320%2Cc_fill%2Cg_faces:auto%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/36926699f9b1f27431b6ea8d0c7a4c94.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img17/movies-tv/Oct/280x280_Quadcard_1._CB514398927_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/964caeca-2de3-447c-a55a-9587d8e00671/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/mac/image_small.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/logo_catalog/wordmark--dropbox_m1-vfldArOOy.svg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/watch-history.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-story_cover_atomic_sm/td-applet-viewer-templates-story_cover_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/lib/react-with-addons-15.4.2.min.js","request_type":"script"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://amplify.outbrain.com/cp/obtp.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=880546608&t=pageview&_s=1&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEDAAEAB~&jid=407822979&gjid=1321911993&cid=970841907.1523791982&tid=UA-71552437-1&_gid=1459932104.1523791982&_r=1&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=1379469448","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://8166291.fls.doubleclick.net/activityi;src=8166291;type=dpbxg0;cat=dpbx_0;ord=4439324672617;gtm=G46;~oref=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://ing-district.clicktale.net/ctn_v2/wr/?1699375031091421&100&10&1&1&0&104&subsid=233200&msgsize=10","request_type":"text"}
+{"origin":"http://www.pixnet.net/","request_url":"https://agent.aralego.com/idSync/?redirect=https%3A%2F%2Frec.scupio.com%2Frecweb%2Fuxid.aspx%3Fid%3DSspCookieUserId","request_type":"text"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log/ux_analytics","request_type":"text"}
+{"origin":"http://www.pixnet.net/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=falcon.pixanalytics.com","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://apis.google.com/js/client:plusone.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://m.facebook.com/a/bz","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52772340&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791992182&fs=2&pvid=b51343cc614cc2e00169604d557f71e9&cg=d505bd55a6a613d44694db25571600d7","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://ak1s.abmr.net/is/pixel.mathtag.com?U=/event/img&V=3-pLQbM10fVKF1K2lsVwFtEozPbYPGaQxdi140CYO%2fqGe9fLp6TYIWog%3d%3d&I=D77E4971F3F64FB&D=mathtag.com&01AD=1&mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=&mm_bnc&mm_bct","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/c/splash-e72750192f.css","request_type":"css"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/css/csdn_feed_m.css?1521791741","request_type":"css"}
+{"origin":"http://www.office.com/","request_url":"https://wusofficehome.msocdn.com/s/5d57038d/Areas/Home/Content/js/build/bundles/unauth.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/scooter/scooter-scoped-vflhQ6850.css","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=NoDmCXuapEsb&ex=pulsepoint.com&ev=&pid=557477","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=903&dpuuid=558f8732-6e07-4ff6-bc5d-d07d21a96a01","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.google.com/ads/user-lists/956747825/?userId=uhco9tXJQEKHOlrv_6JpJQ&guid=ON&script=0&cdct=2&is_vtc=1&random=2236186236","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t5668/159/160398199/14046/acfe1fa3/591d9424N068a7ad0.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12781&impid=&at=1&mkey=&latcy=2344&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=4495914382572&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1523791940467","request_type":"html"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=MB94veV&sid=yLIOFNP835fT4D41H3-W","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://tags.bluekai.com/site/24667?ret=html&phint=pageName%3Despn%3Afrontpage&phint=channel%3Despn%3Afrontpage&phint=eVar34%3D&phint=events%3Devent3&phint=prop1%3Despn&phint=swid%3D0A8AF6A3-114D-4E90-CE93-928476B93005&phint=prop4%3Dindex&phint=prop9%3D&phint=prop23%3D&phint=prop25%3D&phint=prop26%3Dno%2Bleague&phint=prop30%3Dpremium-no&phint=prop32%3D&phint=prop45%3D&phint=__bk_t%3DESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&phint=__bk_k%3DESPN%2C%20sports%20scores%2C%20sports%20news%2C%20football%20scores%2C%20cricket%20scores%2C%20rugby%20scores%2C%20f1%20scores%2C%20golf%20scores%2C%20tennis%20scores%2C%20MLB%20scores%2C%20NFL%20scores%2C%20NBA%20scores%2C%20NHL%20scores%2C%20College%20Football%20scores%2C%20College%20Basketball%20scores%2C%20sports%20videos%2C%20sports%20information%2C%20Fantasy%20sports%2C%20Fantasy%20games%2C%20Fantasy%20football%2C%20Fantasy%20baseball&phint=__bk_l%3Dhttp%3A%2F%2Fwww.espn.com%2F&limit=10&bknms=ver=2.0,ua=14b68fe3244daf632785cd9404e86d56,t=1523792056680,m=4b4e4ecaab1f1c93ab1f1c93ab1f1c93,k=1,lang=07ef608d8a7e9677f0b83775f0b83775,sr=512x360x24,tzo=420,hss=true,hls=true,idb=true,addb=undefined,odb=function,cpu=4b4e4ecaab1f1c93ab1f1c93ab1f1c93,platform=1c17637dbf2f8edebf2f8edebf2f8ede,notrack=,plugins=4b4e4ecaab1f1c93ab1f1c93ab1f1c93&r=65412475","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"https://lmjy9nsjglodu0uynqhzq7wsc1o591523792035.nuid.imrworldwide.com/","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5582000/5582119/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/08/BC254E.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/EinkBundle-Mobile_billboard-a-de-1242x450._SX1242_CB529985201_.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180413092744-kerry-babies-tease-02-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/018/35c/33c/big_lq/50b1e629509695f47cf54c4719a79ee7.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5400000/5400589/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1MzfaLpXXXXaXXXXXXXXXXXXX-345-306.jpg_q50.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51g4qr8fBNL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/website/logo/monogram/pp_rv_mg.svg","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/sc/h/5esw1kd3ei3m9esz22djaftd2,2olredkbfbozb6a01qnofxodb","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://pbs.twimg.com/twitter-assets/twitter_shared_public/prod/hashflags/config-2018-04-15.json","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/wwe.png&w=100&h=100&transparent=true","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/21SX%2BXnDsHL.css?AUIClients/RetailSearchAutocompleteAssets","request_type":"css"}
+{"origin":"http://www.twitter.com/","request_url":"https://api.twitter.com/1.1/jot/client_event.json","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://rp.gwallet.com/r1/cm/p50","request_type":"other"}
+{"origin":"http://www.tumblr.com/","request_url":"https://sb.scorecardresearch.com/beacon.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/prom_ev.gif?posId=10080101&itemId=6003&SUV=null&_time_=15237919383363576843225683","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://refer.wordpress.com/wp-content/themes/refer-wordpress/assets/js/referrals.min.js?v=20171117","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.facebook.com/fr/r.php?p=558293300959460&e=KoauPan-R6uDjUaB1jdliw&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dfbca%26id%3DKoauPan-R6uDjUaB1jdliw&s=1523792027&h=c3NSZkFIcENMbWZSd3NyWXJwe1kiNar6D5_inOeD6ohQmudU","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://6355556.fls.doubleclick.net/activityi;type=wordp0;cat=wpvisit;src=6355556;u5=zDW8PEy7OW5KBlV2LVBtGlDi;u6=%2F;u7=TOuWFMuZ7M7UmAdtZtDjgCTLYV5yYpup;ord=TOuWFMuZ7M7UmAdtZtDjgCTLYV5yYpup","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/id?d_visid_ver=2.3.0&d_fieldgroup=MC&d_rtbd=json&d_ver=2&d_orgid=EA76ADE95776D2EC7F000101%40AdobeOrg&d_nsid=0&ts=1523791840559","request_type":"script"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/UserRegisterTrackActionResource/update/","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-xy/anim-xy-min.js","request_type":"script"}
+{"origin":"http://www.so.com/","request_url":"https://s.ssl.qhres.com/callback/204d017b0ebe9777/_204d017b0ebe9777/novaCarousel.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-73daaf80d024e2a615e29ad3979a782f673f74a3._V2_.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-be7afd80869374e8f9fd0c31859f748aaefbe2fd._V2_.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61D3Cj7SaVL.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,513EDHaa7SL.js,11sT42sZnQL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61x-Yxr2raL.js,318CMPRminL.js,11dYToHZZ0L.js,21TDqwIsfQL.js,01qkmZhGmAL.js,012YXvM7lUL.js_.js?AUIClients/AmazonUI","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://cloudfront-labs.amazonaws.com/x.png","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://t.myvisualiq.net/sync?prid=123&ao=0&red=https%3A%2F%2Fwww.facebook.com%2Ftr%3Fid%3D1939652716271841%26ev%3DPageView%26cd%5Border_id%5D%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://pixel.tapad.com/idsync/ex/receive/check?partner_id=2682&partner_device_id=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"other"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/localnav/3.0/styles/ac-localnav.built.css","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/css/one-feed-refresh.css","request_type":"css"}
+{"origin":"http://www.youth.cn/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&time=1524189914902&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fm.youth.cn%2F&random_number=12039801813&sess_cookie=8ba3a1a3162e0cc6715e67bf020&sess_cookie_flag=1&user_cookie=8ba3a1a3162e0cc6715e67bf020&user_cookie_flag=1&dynamic=true&domain=youth.cn&account=r+FMm1a4KM+2uW&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://c.bing.com/c.gif?Red3=DataXMS_pd&IXID=E0","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p5.qhmsg.com/t019a6abf63f83db386.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/icons/blog.png","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/transit80.png","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/b894360d-b385-4e01-b4ad-bfb163ff8bd7_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/rkEAAOSw43haTAta/$_57.JPG","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/co_create/mobile/dropbox_digital_mobile_01@2x-vflD5Yy9V.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/3e/87/eb/3e87ebf8c57c11de79a9a767262d64f8/3e87ebf8c57c11de79a9a767262d64f8.19.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p2.qhimg.com/t012320e7677a2a8613.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/4188lji0e7L._SCLZZZZZZZ__AC_.jpg","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://conductor.clicktale.net/monitor?t=chunk&p=147&2=2927199622326975&v=1.4.86","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-yapnativead/td-applet-viewer-templates-yapnativead-min.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://bw.scupio.com/adpinline/adcall.aspx?imp2=H4sIABqp01oA_z1RTWsTURTNG5s4nQrVASE7H1lICun7mC8nrYvWgA22gYFGBDf6MvNinn2ZGTIzWLvqUooLKYjoqqAb_QeC6L64UnHRQi2CULpTXFTowmFKu7hwuJdz7uEcbWNM3f3x6euLDzuKXiPUck0_4EGPEYtwl9KmYbiOS2yfEZeZjlVVaprXIgZtJFz268_fHgtjepCmcTKDcZ9JPwpRLFZZyOTjVPgJ8qMhZgHmwx4PMHWpMVPJ7yFP5_7K9lVv_G5Vff9P03VP-CYhhk3u3W7dzMKQy_ufj77_Pt4_OFQflmKwdvn0yxCdCKB88Dp4CjfAhdZgFA15wxtEId8E49q5MH1UU7LkFShtgco7cF5TklgHxhmiBXrACzShKXGqlwv2NngDOtGakJJhGxFYXxJhtjoL58NgFIkAOoggOgs7URrBBVi3puCNTMgAd7xbhoWo2Zx28t18HEt-h_cWRYpt8xoyHVhfbHc7Sw0oxQqHC9xfiabgiW1su7moSYwmcmmu3BOSw2XWZyNxSva6y908PWJRE1FKLNv4AlStkvhZLKIdUC4q2Qcv9_Ah0DQ18_tFhH_AFRXoF9vX93a35g4ubdYH5W31dVD99utj0TgER-Dn5Loy9kSZfKZM6KX_9eoB0Q8CAAA&callid=01483cdedba040e81192286805ca08a364&br2=%7B%22bi%22%3A%5B%5D%2C%22br%22%3A%5B%7B%22winner%22%3A%22sc%22%2C%22adid%22%3A179385%2C%22price%22%3A0%7D%5D%7D","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://analytics.twitter.com/i/adsct?p_user_id=L6N62llA&p_id=10623","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/autocomplete-list/assets/skins/sam/autocomplete-list.css","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/61dthWUjS5L._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,11B0Us3dmsL.css,21pknbpyIxL.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,31B945bG3dL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21s7MLn4blL.css,11X2-nh0PYL.css,01h2e2BEitL.css,114wDplwccL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31VU7Pt5U6L.css,01b7OI3r44L.css,11mmd1QliNL.css,01cbS3UK11L.css,21pKFuuDucL.css,01EjbsDjo-L.css_.css?AUIClients/AmazonUI","request_type":"css"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/home.logged-out/page-domain-only/js/bundle.js?v=1520593818","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/toolbar/js/m_iconfont.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spsvcsp.i-mobile.co.jp/ajax/ad_spot.ashx?pid=6107&asid=185725&asn=1&ver=0.2.1&dpr=3","request_type":"text"}
+{"origin":"http://www.jd.com/","request_url":"http://mapi.m.jd.com/cart/cart.json?sid=6cc3e501805e57c0186275faea9b7443&t=1523791999419","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://dpm.demdex.net/id/rd?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_cb=s_c_il%5B0%5D._setMarketingCloudFields","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://x.bidswitch.net/sync?ssp=yieldmo","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://token.rubiconproject.com/token?pid=2974&pt=n&a=1","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.facebook.com/tr/?id=823166884443641&ev=Microdata&dl=https%3A%2F%2Fwordpress.com%2F&rl=&if=false&ts=1523791841782&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22article%3Apublisher%22%3A%22https%3A%2F%2Fwww.facebook.com%2FWordPresscom%22%2C%22og%3Atype%22%3A%22website%22%2C%22og%3Atitle%22%3A%22WordPress.com%3A%20Create%20a%20free%20website%20or%20blog%22%2C%22og%3Adescription%22%3A%22Create%20a%20free%20website%20or%20easily%20build%20a%20blog%20on%20WordPress.com.%20Dozens%20of%20free%2C%20customizable%2C%20mobile-ready%20designs%20and%20themes.%20Free%20hosting%20and%20support.%22%2C%22og%3Aurl%22%3A%22https%3A%2F%2Fwordpress.com%2F%22%2C%22og%3Asite_name%22%3A%22WordPress.com%22%2C%22og%3Aimage%22%3A%22https%3A%2F%2Fs1.wp.com%2Fhome.logged-out%2Fimages%2Fwpcom-withjetpack.jpg%22%7D&cd[Meta]=%7B%22title%22%3A%22WordPress.com%3A%20Create%20a%20free%20website%20or%20blog%22%2C%22meta%3Adescription%22%3A%22Create%20a%20free%20website%20or%20easily%20build%20a%20blog%20on%20WordPress.com.%20Dozens%20of%20free%2C%20customizable%2C%20mobile-ready%20designs%20and%20themes.%20Free%20hosting%20and%20support.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=28&it=1523791840811","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://adservice.google.com/ddm/fls/p/src=1295336;type=adobe994;cat=aamuuid;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=;~oref=https://adobe.demdex.net/dest5.html%3Fd_nsid%3D0","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://ybx.yahoo.co.jp/clear.gif?bkey=loginpromo&mtype=pop&status=normal&action=view&src=www&spaceid=2080377422&ts=1523791949869","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_1%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D30027%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/tubemate-youtube-downloader-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/traductor-de-google-android.png:l","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/select2.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/equality3806384/albumset/16224593/zoomcrop/75x75.jpg?v=1523340641","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p5.qhmsg.com/t015c4a525a2379d9f6.png","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://em.baidu.com/pixel?media_sign=a47c60c72bd194de16bfd3d65a193714&media_site=2b754e1aec5785e2c1d894d225ea394825783f84526c2c00c2907787c06bc8f1","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=yieldmo&ttd_tpi=1&ttd_puid=g9e51602ae03bce4bdfa","request_type":"html"}
+{"origin":"http://www.yahoo.com/","request_url":"http://www.yahoo.com/","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Heroes%20of%20the%20Storm-429x572.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201605/19/77030221/original/(m=eafTGgaaaa)(mh=YurWEE0kMduT2lzZ)12.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33050992","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201803/15/158212652/original/(m=eafTGgaaaa)(mh=UKZDLK8-qlfH_ekC)4.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=2052027540,2177633059&fm=173&app=25&f=JPEG?w=218&h=146&s=32013666065066751333686D0300F07A","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d30758a2f1c3a50503a.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/80/09/25/8009259483f9a22fffbfbbddcb789ed0/8009259483f9a22fffbfbbddcb789ed0.4.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/02/02/dc/0202dcb1b777c8ff3ce8b84ecf917ead/0202dcb1b777c8ff3ce8b84ecf917ead.2.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20130828ksxdh.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_ESTqIq1mND1juJUYR9II5Q&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/514JesWg6VL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17000/0/0/315/1523791935.dop006.sj3.t%2C1523791935.cds016.sj3.shn%2C1523791936.dop006.sj3.t%2C1523791936.cds034.sj3.c/0","request_type":"text"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/default/browser/favicon_32.ico","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/see.svg","request_type":"image"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/navigationdrawer/settings_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://secure-assets.rubiconproject.com/utils/xapi/multi-sync.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/gp/gw/ajax/dataStore.html/262-9616072-1847409?ie=UTF8&hmac=C2F5173EF240C11D48236AE3BABEA62062B5D192&opf_redir=1&relatedRequestId=Q3AKTQX4Z8AX1W7T64V5","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vtablet/hammer.min.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-home-unread.min-vfl3h_kZ9.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpmm.alicdn.com/g/mm/afp-cdn/JS/r.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://theta.sogoucdn.com/wap/js/anticheat-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/escape-html.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/sdk/template/js/6.handlebars.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB198AeHFXXXXX2apXX760XFXXXy.png","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-55c98a093133640017000a51.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NBA_POP_POSTGAME_REV1/dm_180414_NBA_POP_POSTGAME_REV1.jpg","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://accounts.google.com/ServiceLogin?service=blogger&hl=en_US&passive=true&go=true&continue=https://www.blogger.com?rinli%3D1","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100285255&apid=beans_12419&impid=08b6db32ab9a21f55_0_0&at=1&mkey=08b6db32ab9a21f55_0_0&latcy=2942&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=2692.046875&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DEQgXqPyXCr2HgdhRwJINBvp4mBxMRPAM%2FCoUVy9Hk0rENLMFixHh%2FdRWZFugj2xm8snvcd5ySF1iuzlBIQD2Z21EJdORv%2BeCnTlxTCu26ryCVSk1RcGWkmUD%2FOGbv0HfO%2Bib5hL8%2FJl4bBHu2yrbva7gQ1j%2B4bojZ0KpxkowXgd26JbSzLnEptOOuEvQwmdmc4oYZsS1ubJSPN%2FMBHyruyMtsxC4BxO%2BPxv%2FvN0kB8ohbZvLn1scuFFxDMK62BVP9RKXNH2bFlK1dyOtKe%2F%2F2zJevgNTT%2FRZyL7KsEOJHANc6ll%2BBBfYcNO5jQub%2BOayupz%2F0WoqZDhnzqCRpJdZfOFX%2BcwYYucGQBHbG6PFblQwqxtaZPueXCMCd3A0UueEbyUS8njVsBvAinctx5tQUSXtwIK44WKoY6K5yg9qbXickOXc%2FnW6ck3Q%2FhlAS6EzURWacFTO8XbTubNrIL2PHJYowtoj%2BCqwdbrSLNFWQtpbMtJPPGbUKwvK786VRuLPQqqBtoXaoOPsAyyyDb1X%2Fc6Odm5kPWf9O11Axb8uYHeT52FmsLAabwqh8zowguWlQAni%2F7yEGTKaNg2wld7GF7t0zCHXjdgk5xzTNDH%2FY6U%3D%09tt2%3D1523791940734%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=7861074818648&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791941098","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTI2NjgmdGw9NDMyMDA%3D%26piggybackCookie%3D__EFGSURFER__.__EFGCK__","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://aax.amazon-adsystem.com/e/dtb/bid?src=3159&u=https%3A%2F%2Fwww.cnn.com%2F&pid=5400474871011523791861740&cb=1568435224811523791861759&ws=360x512&v=6.8.1&t=750&slots=%5B%7B%22id%22%3A%22videoSlotName1%22%2C%22mt%22%3A%22v%22%7D%5D","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2","request_type":"font"}
+{"origin":"http://www.amazon.in/","request_url":"https://stags.bluekai.com/site/36841?dt=0&r=1612984397&sig=266897515&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmih1xvl5HuFzEzhvgXwBlWkmnvTonDUnlAda0QjeWxo0q7s3LSrtVZ3O3f3O3jhe+8hTKsKQvjj3APxvsA7BnDf1H1i9Rp9W1JcNA=","request_type":"other"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/nav-category/4.2.0/index.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=app_download_banner_android&cat=&value=&t=1523791859635","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=12&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A12%7D&logFlag=uaction_1523791857874&t=1523791869877","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_6%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D29519%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t19654/278/1209266478/16675/af0e963a/5ac20477Nee0db9f4.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/logotip.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_health.png","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p.ssl.qhimg.com/t01681f76d5d875653c.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/img/sections/millions/millions-mobile-markers_2x.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/about/img/ui/icon-arrow-down.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_13713&impid=&at=1&mkey=&latcy=5366&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=9248468959066&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&suv=180415193221Z74L&_time_=1523791943681","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-ec-1440x810.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/product/paper/paper_ui_mobile@2x-vflt1FHUx.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180412225018-kyle-plush-trapped-teen-cincinatti-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/022/0d1/00d/big_lq/f11cd1ff9f08d1ee5faae9fc91a17071.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f11/1269660a4c082160d9c30335d51d8d16_erotic_285x160.jpg?cno=c18","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/5c/05/15/5c051512cb5b02d9a0916f590fd8a931/5c051512cb5b02d9a0916f590fd8a931.30.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/5XhEk60O-nP4eX0GtFYbOGoAusA9G92EGW8DezNFL9g.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/digital/video/merch2016/mobile/GW_Mob_Evergreen_1242x450_FT._SX1242_CB502575189_.jpg","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/home.logged-out/page-domain-only/img/hero-icons.svg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://secure-dcdn.cdn.nimg.jp/enquete/static/js/enquete.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://static.criteo.net/js/ld/publishertag.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://310987714.log.optimizely.com/event?a=310987714&d=310987714&y=false&src=js&s310954789=none&s311043393=true&s311047346=gc&s311052307=direct&s793783561=true&s806111078=none&s806950111=mobile&tsent=1523792026.106&n=http%3A%2F%2Fwww.espn.com%2F&u=oeu1523792025971r0.47098347521900563&wxhr=true&time=1523792026.076&f=8448890495,9262875135,9263073801,8792134866,8483651062&g=&cx2=8461291","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/mwf/_h/v2.75/mwf.app/fonts/mwfmdl2-v2.75.woff2","request_type":"font"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/scope.js","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://wq.jd.com/user_redpoint/QueryUserRedPoint?type=4&sceneid=2&callback=QueryUserRedPoint&v=4387","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-59a4061c64746d5174000477.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NBA_One-Play_Belinelli_3_pointer/dm_180414_NBA_One-Play_Belinelli_3_pointer.jpg","request_type":"image"}
+{"origin":"http://www.stackoverflow.com/","request_url":"http://www.stackoverflow.com/","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://fd.3.cn/cesu/r?pid=657&os=android%206.0.1&apn=unknow&wq_area=null&_=1.774135145112271&s1=1682&s2=3650&s3=3603&s5=3242&ext=360%2C512%093%09","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791948359&yhlClientVer=3.30.2&yhlRnd=FfHkSxtyhJMGVVRkjg0qds93&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.imdb.com/","request_url":"https://odr.mookie1.com/t/v2?tagid=V2_393725&AMAZON_REGION_SPECIFIC_ENDPOINT=s.amazon-adsystem.com&src.visitorID=pBvvj7WxSEu3UBsRQZRCCg","request_type":"text"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=cms-adobecom_us_index_TopOfBody&mboxSession=9bacdabf39b7406b83ce178a57242400&mboxPC=&mboxPage=5ededb5d3e024eab82d38d46617d12fd&mboxVersion=1.2.3&mboxCount=2&mboxTime=1523766796143&mboxHost=www.adobe.com&mboxURL=https%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-420&screenHeight=512&screenWidth=360&colorDepth=24&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=0F715D2B1317710A-3C141A64CA81D397&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id=","request_type":"script"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.live.com/","request_url":"https://cdn.optimizely.com/js/8066781501.js","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production//public/content/query/v1/article/search/tag/pop-culture?pageSize=12","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.googletagmanager.com/gtm.js?id=GTM-MDKJT8","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://token.rubiconproject.com/token?pid=27384&puid=L6N7iig7","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.fps.clientlibs/beagle/fe/resources/css/aceui-reimagine.min.fp-bf26f4c2e490cc3124e6c0a7fb460ac9.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=75bd0709-b9f8-c141-15fd-e8af093a5c07","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Free%20Live%20Sex%20Cams%20-%20Live%20Sex%20Chat%20and%20XXX%20Live%20Porn%20Shows&time=1523791943345&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fbongacams.com%2F&random_number=17634742147&sess_cookie=62eb4351162c913d6af1025d16d&sess_cookie_flag=1&user_cookie=62eb4351162c913d6af1025d16d&user_cookie_flag=1&dynamic=true&domain=bongacams.com&account=X2xYi1a8Dy00aY&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=19360&dpuuid=86070857378125119120981354726841823876","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/wish-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/f-droid-android.png:l","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"http://www.yahoo.co.jp/","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/06/E30088.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/603905a0-88e6-425e-9830-d73f3fe0e0cf_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/87/70/bf/8770bfaf0b717e5c8aaa9f307e299569/8770bfaf0b717e5c8aaa9f307e299569.17.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://production.mtm-cdn.com/filmer/archives/408/1961/794.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://a.thumbs.redditmedia.com/fuB_hc0k0ju4Dag-KRX0Pobxk8-fYSx77YmUZmBbGR4.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31MOwKIzA0L._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/e4b13ae0-b7dd-455d-89ad-3296524ded39/scale-to-width-down/100","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/oYgAAOSwu4haoZg0/s-l225.webp","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/favicon-vflUeLeeY.ico","request_type":"image"}
+{"origin":"http://www.google.com.ua/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/js/side-nav.min.js?v=e8869abe59f37ca1f0847c8fa8d65222","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://d31qbv1cthcecs.cloudfront.net/atrk.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-misc.min-vfluf2J52.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-vv_topbar/td-applet-viewer-templates-vv_topbar-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-yapad-model/td-yapad-model-min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nfl.png&w=288&h=288&transparent=true","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=7LOhZDOrTi2dZfi89QUpvw&twitter_redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dtwca%26id%3D7LOhZDOrTi2dZfi89QUpvw%26","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://rp.gwallet.com/r1/cm/p50","request_type":"other"}
+{"origin":"http://www.diply.com/","request_url":"https://sb.scorecardresearch.com/c2/17462746/cs.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_4&relatedID=&news=0_0&SUV=null&_time_=15237919513345040620205662","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/js/personalized-one-feed.min.js","request_type":"script"}
+{"origin":"http://www.google.com.pk/","request_url":"http://www.google.com.pk/","request_type":"html"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/gen_204?atyp=csi&ei=JjjTWrziKqGW0gLfrIuQDA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.554,dcl.506,iml.554,ol.2834,prt.372,xjs.1713,xjsee.1713,xjses.1529,xjsls.402,wsrt.2160,cst.705,dnst.0,rqst.804,rspt.414,sslt.379,rqstt.1698,unt.2096,cstt.990,dit.2666&zx=1523791913834","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100269248&apid=beans_12274&impid=0f0dbcc288104b396_0_0&at=1&mkey=0f0dbcc288104b396_0_0&latcy=3917&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=1701.671875&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DOyygn03WYDL%2BVv%2F3mNEQdqFmyQMB%2Fruy3%2F1xRO6RNFfGs9qthLHF70DQ8pec15VHqZovbVXrzzco7XYsOegVBjcDCze1BpeCimHmb2LvXsKGB9oaN3%2FU8uLXYHGVdGcROKCRJeS81hJEXPOJIIKfhh6l1THTruIiodwOjJDvGuqB2OztFDF12oTtnMx5oRDrYEuFktpJBq8%2FvNUYK51Vvh8fiveh5womueMDFo3uJUuniRvire2hLbtfQwvXwBDP9Z%2FRds5Il%2Bg9bnkITnNoCyOMzKMhQXJH1qSAQiuwY4VAq7voRegM6gkSuQ0mY4sBtX69iAJOAoKwatrJU1mhZj37lZNqHevo3wzFLEd5LlLrIAADmwPsL1MEZW35%2B8ppstU0qP7L1JzywfJ6%2FL3U3LzQgusRb1%2Fsi8eLgIaFbrbSHH0owgFPgRl7nBYWVzwMeYWcaxLPA3SXVgmHcQwr1wzpMrErZO%2FDTJdBOcuFKgTp0QpGOBIkUUAe%2BzBMWP9MzlXIVzma9N%2BfvWLL344x%2Fy1L3x0k8U3KXfkA3ICrOJYNAdBtiFsQ3GQQW%2BC9vfhNbChkAbyKFIKoZGM6C50xrQ%3D%3D%09tt2%3D1523791941847%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=2927770983255&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942195","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938250_4571976178678&itemspaceid=12282&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938250&plateid=1001000000,1003000000","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938242_2830613342153&itemspaceid=13819&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938242&plateid=1001700000,1001500000","request_type":"script"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyMoZDDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oEP8NJFdreLOb-MuaK1oeaBXDDz4Q","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/array-invoke/array-invoke-min.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C41A079WE8qL.js,118Wk-h2B-L.js_.js?AUIClients/GWMWebAssets","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770103&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792005929&fs=2&pvid=a80c1120fbcd064fdc543f89308287c1&cg=ac6ec01a659365cebc5d0b1b239c312e","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://pixel.mathtag.com/event/img?mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=&mm_bnc&mm_bct","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://dpm.demdex.net/ibs:dpid=477&dpuuid=0a86896aa120602416161f5fd48d117aadd02b8924497fd6eb1e7b45967c248bb0da87c991749652&redir=https%3A%2F%2Fidsync.rlcdn.com%2F362248.gif%3Fpartner_uid%3D%24%7BDD_UUID%7D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fwww.facebook.com%2Ffr%2Fb.php%3Fp%3D1531105787105294%26e%3D%24%7BTM_USER_ID%7D%26t%3D2592000%26o%3D0","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fwww.facebook.com%2Ffr%2Fb.php%3Fp%3D1531105787105294%26e%3D%24%7BTM_USER_ID%7D%26t%3D2592000%26o%3D0","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=79908&dpuuid=WtM362f4QZWkMUP1ajJKZodR","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/youtube-mp3-download-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/whatsapp-messenger-android.png:xl","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/wzcq1234/albumset/4848483/zoomcrop/75x75.jpg?v=1508078353","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/qqrice0416/albumset/16228730/zoomcrop/75x75.jpg?v=1523785511","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/wuxianguaziershouche.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"http://www.mail.ru/","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"http://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://h5api.m.tmall.com/h5/mtop.user.getusersimple/1.0/?jsv=2.4.11&appKey=12574478&t=1523791821652&sign=892d1785a3e46dd3882630f5b49ebb17&api=mtop.user.getUserSimple&v=1.0&H5Request=true&jsonpIncPrefix=smb_xc&timeout=2000&type=jsonp&dataType=jsonp&callback=mtopjsonpsmb_xc2&data=%7B%7D","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBBc4AMP6lQ.woff2","request_type":"font"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/transform/310/w710h400/20180415/gFGX-fytnfyp5080862.jpg/w710h400z1l50t1925.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/01/7d/22/017d22f4dacfb8d532ec86da62809345/017d22f4dacfb8d532ec86da62809345.24.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d305ea8c01c3a591c19.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=3265157990,4222544966&fm=173&app=25&f=JPEG?w=218&h=146&s=49D014C74A7183D610A62CBF0300C01A","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTczODMyMjQ5Ml5BMl5BanBnXkFtZTgwODgzMjA4MTI@._CR11,10,1458,1092_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/fkgAAOSwCcZaTAxj/$_57.JPG","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51WWPA21koL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61-xbfN4v6L._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/UK-digital-music/2018/MarketingCampaigns/032318_MC_EltonJohn/032318_MC_EltonJohnProject__GW_M_1242x450_MU._SX414_CB499558132_.jpg","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflUiilPi/desktopplayer.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.wikia-services.com/__track/special/trackingevent?a=69286&beacon=NyiV-67qg0&c=1452001&c_loc=0&cb=1523791988433&client_ip=208.70.31.93&dev=false&dev_cat=mobile&event_ts=1523791988&f=Home&ga_action=69286&ga_category=card&ga_label=view.item-0&lc=en&nonInteraction=true&pg_type=home&pv_number=1&pv_number_global=1&pv_unique_id=af377f25-1ffc-4914-9834-c80ec4217531&r=direct&r_type=direct&s=fandom_mobile&session=Q4ulawcgCl&session_id=5d21d0a7-b14a-4f7f-ac4b-8ba9846d26f7&site=web&t=event&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&url=http%3A%2F%2Fwww.wikia.com%2Ffandom","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/gizmo/js/src/components/site.min.js?v=lgMZgnYB0G7zB-SRhzLa3rhEsObVFrrm2GkJFg3PbhI","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-controllers-core.min-vfl0G_AUz.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://c.amazon-adsystem.com/aax2/apstag.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/asset/js/main/index.min.js?c370df7fa30ee3042456963db74f4700","request_type":"script"}
+{"origin":"http://www.google.ru/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://cmnt.sina.cn/aj/v2/counts?ids=gn:comos-fzfkmth4078676:0,gn:comos-fzcyxmu9449362:0,297_376_0&_=1523791828761&_callback=Zepto1523791825220","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://m.imdb.com/","request_type":"html"}
+{"origin":"http://www.twitter.com/","request_url":"https://api.twitter.com/1.1/jot/client_event.json","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://amplify.outbrain.com/cp/obtp.js","request_type":"script"}
+{"origin":"http://www.google.co.uk/","request_url":"https://adservice.google.co.uk/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V3RNMzR3QUFDR01mUGZ5UQ&url=/1/gr%3furl=https%253A%252F%252Fus-u.openx.net%252Fw%252F1.0%252Fsd%253Fid%253D537072980%2526val%253D__EFGSURFER__.__EFGCK__","request_type":"html"}
+{"origin":"http://www.live.com/","request_url":"https://outlook.live.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/tc?tcreq4log=1&r=1523791827494&logid=1811881676&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=10&cst=1&ref=index_iphone&logInfo=show_baiduapp_ad&logFrom=callbaidu","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/fcmdynet.js?&cid=8CUNL3XVM&cpcd=NaEyhZu73BMxXJoVzER-IQ%3D%3D&crid=903352736&size=300x250&cc=US&sc=CA&wsip=2886781043&https=1&vif=1&requrl=https%3A%2F%2Fwww.msn.com%2F&vi=1523791837453272108&lw=1&ugd=3&chnm3=startPage&re=1&dma=807&msa=2&rtbs=1&nb=1","request_type":"script"}
+{"origin":"http://www.txxx.com/","request_url":"https://mc.yandex.ru/watch/23578849/1?wmode=7&page-url=https%3A%2F%2Fm.txxx.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-420%3Ai%3A20180415043312%3Aet%3A1523791993%3Aen%3Autf-8%3Av%3A1072%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A1396006951435%3Arqn%3A1%3Arn%3A1045535901%3Ahid%3A19071466%3Ads%3A0%2C0%2C632%2C319%2C3862%2C0%2C0%2C4900%2C328%2C%2C%2C%2C8782%3Afp%3A5928%3Awn%3A34150%3Ahl%3A3%3Arqnl%3A1%3Ast%3A1523791993%3Au%3A1523791993707055678%3At%3APorn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://b.scorecardresearch.com/b?c1=2&c2=3000005&ns__t=1523792055712&ns_c=UTF-8&cv=3.1m&c8=ESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&c7=http%3A%2F%2Fwww.espn.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.livejasmin.com/","request_url":"http://jaws.dditscdn.com/socket.io/?EIO=3&transport=websocket","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/ZMAwryCI?redir=https%3A%2F%2Fdsum-sec.casalemedia.com%2Frum%3Fcm_dsp_id%3D88%26external_user_id%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.savefrom.net/","request_url":"https://themes.googleusercontent.com/static/fonts/opensans/v6/RjgO7rYTmqiVp7vzi-Q5UT8E0i7KZn-EPnyo3HZu7kw.woff","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-51278971-3&cid=205197444.1523791993&jid=884883245&_gid=350041298.1523791993&gjid=210711659&_v=j66&z=1664534790","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d1315113.gif?rnd=167330934&ts=1523791836","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20180111_mobileGMW_728X90.gif","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://ad.doubleclick.net/ddm/trackimp/N426203.2426714VISUALIQ/B11035907.147164125;dc_trk_aid=318650907;dc_trk_cid=79651416;sz=1x1;u=%7CVIQ_0-8dbf6c7e-1b78-4842-8ee1-2d91dbde8de8%7Chttps%3A%2F%2Fwww.paypal.com%2Fus%2Fhome;ord=1523791848365","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://statics.itc.cn/mobile/css/images/loading-50508229.gif","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.google.com/ads/user-lists/1064110564/?userId=T8END0GPSW-I-45Xox-rSQ&guid=ON&script=0&cdct=2&is_vtc=1&random=1834992622","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/dv-station-android.png:l","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/mobile/bongacams_logo3_header.png","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/img/listing-click-pattern.png","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s220x220_jfs/t15820/255/2337971650/598924/2ce96dd9/5aa0bd2aN8f1220af.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=8134546","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmrbkhd.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f10/0570cfd344d5a708b4eb515452cce0c1_erotic_285x160.jpg?cno=679","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/arrow-bottom.svg","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://nexus.ensighten.com/paypal/prod/serverComponent.php?r=18332487.068312496&ensJson=true&ClientID=1620&PageID=https%3A%2F%2Fwww.paypal.com%2Fus%2Fhome%3Ftms_country%3Dus%26ensJson%3Dtrue","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v-a299f42da18/v3/js/i18n/front/english.json","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-applet-0.0.210/ape-applet-lang-strings_en-us/ape-applet-lang-strings_en-us-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/ds/ult/rapidjp-1.0.2.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://fonts.googleapis.com/css?family=Noto+Sans:400,400i,700,700i&subset=cyrillic,cyrillic-ext,devanagari,greek,greek-ext,latin-ext,vietnamese","request_type":"css"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/1a6b23b513b148e3fd049ff7ad0495f1.js?conditionId0=422975","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://images.sohu.com/bill/s2016/jscript/lib/sjs/matrix/ad/tf.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=adobe_dmp&google_cm","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.facebook.com/fr/r.php?p=558293300959460&e=Z2VZffBGTkq5k_VXFnQLdg&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dfbca%26id%3DZ2VZffBGTkq5k_VXFnQLdg&s=1523791925&h=S0IyczVmc1JkUldVTFNwYzyny4s_dmX2YXm_qaXIq_qpa3ej","request_type":"html"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/gen_204?s=webaft&atyp=csi&ei=GjjTWsbuEOGC0wKDm7uACA&rt=wsrt.2107,aft.370,prt.252","request_type":"html"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/gen_204?s=webaft&atyp=csi&ei=CjjTWqbWH8rT0gKEqqpA&rt=wsrt.2185,aft.415,prt.383","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/en-us/mscomhp/onerf/MeSilentPassport?SilentAuth=1","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://tsyndicate.com/iframes2/beae3ac3790c4b7893f0189651c238ea.html?keywords=Watch,and,download,all,Porn,Videos,xHamster,for,Free,including,Browse,sex,photos,date,girls,fuck,have,fun,Live,Sex,Chat,only,xHamster,Free,Porn,Videos,Sex,Tube,Movies,xHamster&param1=0&param2=0&adb=0&w=1080&h=1536","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ads.yahoo.com/cms/v1?nwid=10001117525&eid=WtM34wAACGMfPfyQ&sigv=1&esig=1~8068d344bc8d024cdb57824548f7ecba3c8cba7e","request_type":"text"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/v3/pr?exlist=mp_aone-fe_sx_kr_bsw_bk_ox_index_g-fe_aold_an_rb_im-fe_fbca_aolv_twca_y_rlsa_adb&fv=1.0&ex-pl-fbca=-AYFQvTfQS66Rccu-6kpkQ&ex-pl-twca=TuAeGoH2Tk-ooTaFluPLUw&a=cm&ep=hwyfmSf-wyPawZxHQV29hjtZQXc5kyEGO6sfKrR7GjK-mG6dMVXieYzkJbrAZgt-kqqoHPJSlSGgS9fycD0vUt2bvrR7GbP2UY17Sy-WGgb9TLRvhIqYuXWtaD4adE1Zs4BwiFhFPmz_4M2z4uDP7Hc5EIgA63qCfwS19k0Y537_aXKvOZFxChdNQ2iZOWzZ9WtZMDb5AcUYAdvmDY6SAg","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://idsync.rlcdn.com/382399.gif?partner_uid=39041E2B94ED6EF00CB315F995BE6F73","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yj/r/4z8Q2T6BpKW.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://sb.scorecardresearch.com/b2?c1=2&c2=3000001&rn=1523791836830&c7=https%3A%2F%2Fwww.msn.com%2F&c8=MSN+%7C+Outlook%2C+Office%2C+Skype%2C+Bing%2C+Breaking+News%2C+and+Latest+Videos&c9=","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"http://www.microsoft.com/","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://sync.ipredictive.com/d/sync/cookie/generic?https://aax-eu.amazon-adsystem.com/s/ecm3?id=${ADELPHIC_CUID}&ex=adelphic","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://i.w55c.net/ping_match.gif?st=Krux&rurl=https://beacon.krxd.net/usermatch.gif?partner=dataxu&uid=_wfivefivec_","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://m.youtube.com/yts/cssbin/mobile-nirvana-phone-mangled-vflb3Fuec.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=102&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A102%7D&logFlag=uaction_1523791857874&t=1523791959876","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.200436.0%26id%3D49NGBMVT1ABRN6GGR916%26m%3D1%26sc%3Dadblk_no%26pc%3D13161%26at%3D13161%26t%3D1523792000006%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D49NGBMVT1ABRN6GGR916%26aftb%3D1:13161","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=76&redir=https%3A%2F%2Fads.yieldmo.com%2Fv000%2Fsync%3Fmm_user_id%3D%5BMM_UUID%5D","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://dt.adsafeprotected.com/dt?anId=928108&asId=aa7f89d4-6c96-e26f-d7d0-9342e39910a2&tv={c:9OXV9v,pingTime:-2,time:5993,type:a,sca:{dfp:{df:4,sz:100.100,dom:div},ha1:{res1:1,ps:1,ts:1523791892950,psfr:1}},env:{sf:0,pom:1},rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:1,fif:1,gm:1,slTimes:{i:0,o:5998,n:0,pp:0,pm:0},slEvents:[{sl:o,t:5441,wc:0.0.360.512,ac:0.0.0.0,am:i,cc:0.0.0.0,piv:0,obst:0,th:0,reas:l,cmps:1,bkn:{piv:[724~0],as:[724~0.0]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:jload,dtt:0,fm:qPhNt7y+11|12|13|14|1511|1512|151311|151312|151313|151314|151315|151316|151317|151318|151319|15131a|15131b|15131c|15131d|15131e|15131f|15131g|15131h|15131i|15131j|15131k|15131l|1514|16|17|18.928108|181|182|183|19*.928108|191|1a|1b1|1b21|1b31|1b4|1c|1d|1e1|1e2|1f|1g,idMap:19*,slid:[google_ads_iframe_/8663477/CNN/homepage/landing/super-ad-zone_0,google_ads_iframe_/8663477/CNN/homepage/landing/super-ad-zone_0__container__,ad_bnr_btf_01,homepage-magellan-zone-2],sinceFw:535,readyFired:true}&br=c","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif?rid=e86f55f780704d568af4af783e3cb6c4&cts=1523791839035&idx=4&clid=39041E2B94ED6EF00CB315F995BE6F73&di=340&mkt=en-us&pn=startpage&su=https%253A%252F%252Fwww.msn.com%252F&pid=startpage&cv.product=prime_mobile&flightid=mmxios1cf&activityId=e86f55f780704d568af4af783e3cb6c4&cvs=Browser&subcvs=homepage&pg.n=startpage&pg.t=hp&pg.p=prime_mobile&evt=adimpr_update&dst=6639&den=6723&id=banner1_homepag_0&pg=MMSNUSEN12&w=320&h=50&status=success&sdk=aol&fen=9082","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-reading.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/xingzuo20171026-56.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/wangyi20171024-56.png","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.weibo.com/","request_url":"https://weibo.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=879ae321-40a0-11e8-a40f-0242033f0d7d%252C","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/5205000/5205829/220x165/4.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$newsquiz/ic/84227801/31c1a571.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=32929579","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201804/10/161486532/original/(m=eafTGgaaaa)(mh=JpxbGMMz0d7mA8EK)6.jpg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1XB2p?ver=ec3d&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=335&y=11&s=1401&d=787&aim=true","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0406/dm_180406_nfl_dallas_ms_price/dm_180406_nfl_dallas_ms_price.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_0,y_0,w_493,h_328/os/news/7c89451bba584b5e795df7285edabc71.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.yieldmo.com/img/crtv/2018/04/1918292139302716419/braving-the-wilderness_120.webp","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://m.so.com/index.php?c=home&a=data&types=Hotwords&fmt=jsonp&callback=jsonp3","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages.adobe.com/etc/beagle/public/globalnav/adobe-config/index.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/listing/tool/stream/rappie_stream-1.8.0.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://b92.yahoo.co.jp/js/s_retargeting.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61dthWUjS5L._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,11B0Us3dmsL.css,21pknbpyIxL.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,31B945bG3dL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21s7MLn4blL.css,11X2-nh0PYL.css,01h2e2BEitL.css,114wDplwccL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31VU7Pt5U6L.css,01b7OI3r44L.css,11mmd1QliNL.css,01cbS3UK11L.css,21pKFuuDucL.css,01EjbsDjo-L.css_.css?AUIClients/AmazonUI","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://rp.gwallet.com/r1/cm/p50?check_uid_cookie","request_type":"other"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/scripts/boot.worldwide.2.narrow.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://h5api.m.tmall.com/h5/mtop.tmall.tac.gateway.execute/1.0/?jsv=2.4.11&appKey=12574478&t=1523791819640&sign=8ab28eb896b2507753d64da9f48840a2&AntiCreep=true&api=mtop.tmall.tac.gateway.execute&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp1&data=%7B%22msCodes%22%3A%222017080800%22%2C%22params%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D","request_type":"html"}
+{"origin":"http://www.google.de/","request_url":"https://www.google.de/gen_204?atyp=csi&ei=CTjTWt_vBumQ0wLAv4jgBQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.417,dcl.396,iml.417,ol.2917,prt.230,xjs.1591,xjsee.1588,xjses.1369,xjsls.237,wsrt.2168,cst.696,dnst.0,rqst.839,rspt.448,sslt.371,rqstt.1694,unt.2094,cstt.995,dit.2564&zx=1523791884339","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log_js_sw_data","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://idsync.rlcdn.com/420246.gif?partner_uid=WtM35B__DJPpGsQgT1fYqPHA","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://choices.truste.com/ca?pid=spark01&aid=audible01&cid=20961954_92161433_218069769&js=st0","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://dup.baidustatic.com/js/os.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://tag.clrstm.com/sync?dmp=adobe","request_type":"other"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://sync.im-apps.net/imid/redirect?cid=1000285&tid=aapid","request_type":"other"}
+{"origin":"http://www.twitter.com/","request_url":"https://www.twitter.com/","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://usermatch.krxd.net/um/v2?partner=amzn","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://pixel.tapad.com/idsync/ex/receive/check?partner_id=ADB&partner_url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=91191954147729940174299115411397659455","request_type":"other"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/css/2014/index/index_7_1_0.css?v=jd201802175619","request_type":"css"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/gizmo/scss/src/components/home.min.css?v=UNQv5z10_6fJU7yWDVorr196eMv7dLx3XoT4qM8UkH0","request_type":"css"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_7%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D30022%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://wgo.mmstat.com/msearch.3.3?cache=3ccd8b5&gmkey=searchbar-placeholder&gokey=dim%3Dmallfp..m%26q%3D&cna=&spm-cnt=a223j.8443192.0.0.550f3dbeLF7YWD&logtype=2","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/jfs/t18583/69/717127328/4407/5e47882b/5aa10ceaN649eec12.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/97/8D23B8.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/images/20170601header_menu.png","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://gw.alicdn.com/tfs/TB1yqhOQpXXXXcwaXXXXXXXXXXX-60-64.png","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-01a49470266a51f632dab1aef2fc09112d280c1e._V2_.png","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://acdn.adnxs.com/ib/static/usersync/v4/async_usersync.html","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/4cdc7156-efc2-49a3-8bea-036a2a27f37c_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1TeBD?ver=df90&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=786&y=139&s=1334&d=750&aim=true","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/pic/skypelogo.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/3694000/3694231/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-na.ssl-images-amazon.com/images/I/416-IxTunjL._AC_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s124x124_jfs/t18184/284/245723/39588/47c2cb6b/5a56fd19N80f5a210.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://smetrics.cnn.com/b/ss/cnn-adbp-domestic/1/H.26.1/s12549212069593?AQB=1&ndh=1&t=15%2F3%2F2018%204%3A31%3A4%200%20420&fid=4BEA7D18C905084D-3799DBF4B8681903&ce=UTF-8&ns=cnn&pageName=cnn%3Ain%3A%2F&g=https%3A%2F%2Fwww.cnn.com%2F&cc=USD&ch=cnn%20homepage&server=cnn.com&events=event26&c5=nvs&v5=D%3Dc5&c8=new%3A1&v8=D%3Dc8&c9=nvs&v9=D%3Dc9&c13=section&v13=D%3Dc13&v15=0853&c17=anonymous&v17=D%3Dc17&v22=0&c26=www.cnn.com%2F&v26=D%3DpageName&v27=D%3Dch&c28=cnn%20homepage%3Anvs&v28=D%3Dc28&v29=cnn.com&c30=cnn%20domestic&v30=D%3Dc30&c32=adbp%3Aindex&v32=D%3Dc32&c33=adbp%3Anone&v33=D%3Dc33&c35=cnn.24.1-0-0.20180329%3A0&v35=D%3Dc35&c37=smartphone&v37=D%3Dc37&c46=1523791858448543148946430&v46=D%3Dc46&c56=portrait&v56=D%3Dc56&c57=no%20mvpd%20set&v57=D%3Dc57&c59=no%20mvpd%20set&v59=D%3Dc59&c64=cnn%20news&v64=D%3Dc64&c65=nvs&c75=nvs&v75=D%3Dc75&h1=news%7Ccnn%7Ccnn%20domestic%7Ccnn.com%7Ccnn%20homepage%7Ccnn%20homepage%3Anvs&l1=D%3Dc65&l2=&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/assets/fave/svg/live.svg","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.redditstatic.com/mweb2x/ProductionClient.893ab64c2165d80f910d.js","request_type":"script"}
+{"origin":"http://www.taobao.com/","request_url":"https://g.alicdn.com/mtb/??fingerprint2/0.0.3/fingerprint2.min.js","request_type":"script"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://secure.quantserve.com/quant.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://sm.bdimg.com/static/wiseindex/js/plugin/baiduappAd_f7257e5.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/feature.min.js?v=150727","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/a1de3e3a01556d8ae2c39f1636a60691.js?conditionId0=472867","request_type":"script"}
+{"origin":"http://www.alipay.com/","request_url":"https://a.alipayobjects.com/amui/zepto/1.1.3/zepto.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://googleads.g.doubleclick.net/pagead/drt/s?v=r20120211","request_type":"html"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/gen_204?atyp=csi&ei=zjfTWo-aD4mg8AOcoa_wCQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.368,dcl.351,iml.368,ol.2691,prt.207,xjs.1549,xjsee.1548,xjses.1332,xjsls.213,wsrt.2140,cst.672,dnst.0,rqst.766,rspt.393,sslt.367,rqstt.1655,unt.2055,cstt.983,dit.2491&zx=1523791825270","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938176_8193710216228&itemspaceid=12423&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938176&cnid=228338076,228300352,228267489,228273682,228325157,228322774","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spsvcsp.i-mobile.co.jp/ajax/ad_spot.ashx?pid=6107&asid=155353&asn=1&ver=0.2.1&dpr=3","request_type":"text"}
+{"origin":"http://www.uptodown.com/","request_url":"http://pagead2.googlesyndication.com/pagead/osd.js","request_type":"script"}
+{"origin":"http://www.blogspot.com/","request_url":"https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://experiment.appadhoc.com/get_flags_async","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production//public/content/query/v1/article/search/tag/humor?pageSize=12","request_type":"script"}
+{"origin":"http://www.twitch.tv/","request_url":"https://api.branch.io/v1/event","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/01KEEhMJ-KL.js?AUIClients/DetailPageAlohaAssets","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/music-racer-android.png:l","request_type":"other"}
+{"origin":"http://www.yahoo.com/","request_url":"https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1523791950140&yhlClientVer=3.42.4&yhlRnd=gbv3qOMH6Xh5szCH&yhlCompressed=0","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://cm.everesttech.net/cm/dd?d_uuid=91191954147729940174299115411397659455","request_type":"other"}
+{"origin":"http://www.mail.ru/","request_url":"https://p.rfihub.com/cm?in=1&pub=224&getuid=https%3A//simage2.pubmatic.com/AdServer/Pug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTI3MzkmdGw9MTI5NjAw%26piggybackCookie%3D%24UID","request_type":"other"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/fd/ls/l?IG=2E674091B80D41D497ED8B2E88AE58C9&CID=15398167FE80640C2D1F8AB5FFD365B8&TYPE=Event.ClientInst&DATA=%5B%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Facebook%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Twitter%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Skype%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Email%22%2C%22TS%22%3A1523791833444%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%228b417c99-d930-414e-a863-72c547d91ccc%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22GetUrl%22%2C%22TS%22%3A1523791833445%7D%2C%7B%22T%22%3A%22CI.Load%22%2C%22FID%22%3A%22HP%22%2C%22Name%22%3A%22HpmobAjaxLoad%22%2C%22TS%22%3A1523791833447%7D%5D","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://rtd-tm.everesttech.net/migrate_et3/","request_type":"other"}
+{"origin":"http://www.csdn.net/","request_url":"https://www.csdn.net/images/svgs/svg-symbols.css?1516016762","request_type":"css"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/css-min/1F6C6p/m.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/maestro_layout-vflwIfhrd.css","request_type":"css"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=bidswitch.com&id=4685dd320c4de48720dc6c88c4f78c2a","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=60&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A60%7D&logFlag=uaction_1523791857874&t=1523791917876","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=index&id=E4EPM4H4q1pwUnY0JxBuNTcxcJQ4ZgIC","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1957&dpuuid=398FA6D04E55659D3C94AD024F0B64DD","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/i/logo-446a3d251c.flat.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/aldiko-book-reader-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/dong1104/albumset/8500119/zoomcrop/75x75.jpg?v=1523698407","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/feiji083002.png","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/8UY6aGXssMtwEhVT0HxD2Q/009/340/991/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/rn9NcFOQ0z0/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLB-Ld-vNFhrzQ7-PAnNrUwiVM_AGQ","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/570c6bcb-8fa0-4c53-aafc-142a77b42bc8_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1M1fg?ver=ce66&q=90&m=6&h=276&w=494&b=%23FFFFFFFF&l=f&o=t&aim=true","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/e8/7c/21/e87c21b5fa9cf4082c66e3a54b260334/e87c21b5fa9cf4082c66e3a54b260334.11.jpg","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/feed/20180411/3ee7f34a38b42b9f84acfa5031442263.jpg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/mobi/2017/image/section-title-dujia.svg","request_type":"image"}
+{"origin":"http://www.google.fr/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://as-sec.casalemedia.com/cygnus?v=7&cb=1523791888914&s=185860&r=%7B%22id%22%3A1523791887%2C%22imp%22%3A%5B%7B%22id%22%3A1%2C%22banner%22%3A%7B%22w%22%3A720%2C%22h%22%3A480%2C%22topframe%22%3A1%7D%2C%22pmp%22%3A%7B%22deals%22%3A%5B%7B%22id%22%3A%2252620162%22%7D%5D%7D%7D%5D%2C%22site%22%3A%7B%22page%22%3A%22https%3A%2F%2Fwww.cnn.com%2F%3Fdeployment%3Dagilityzone%26device%3Dmobile%22%2C%22ref%22%3A%22%22%2C%22mobile%22%3A1%7D%7D","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://cdnssl.clicktale.net/www/ChangeMonitor-latest.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-slideshow_inline_sm/td-applet-viewer-templates-slideshow_inline_sm-min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/mtop/4.1.4/index.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/21SX%2BXnDsHL.css?AUIClients/RetailSearchAutocompleteAssets","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-580da78c64746d4cc8007eca.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-58d4d7ed64746d431d00ab11.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://eus.rubiconproject.com/usync.html?geo=na&co=us&s=ms1","request_type":"html"}
+{"origin":"http://www.google.com.ua/","request_url":"http://www.google.com.ua/","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://1295336.fls.doubleclick.net/activityi;src=1295336;type=idsync;cat=uuidm0;u1=NotSignedIn;u2=91191954147729940174299115411397659455;u3=91347194757900030554314852707948543921;u4=;u5=;u6=adobe.com;u7=%%dc_rdid%%;u8=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=3254237940278.7236","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log/ux_analytics","request_type":"text"}
+{"origin":"http://www.pixnet.net/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_window_focus_non_hydra.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ad.doubleclick.net/ddm/trackimpj/N3941.2005704YIELDMO/B20912526.217082534;dc_trk_aid=416280703;dc_trk_cid=67442974;kw=764344014241209959-1916679378487477386;ord=4709060416213419146;dc_lat=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=","request_type":"script"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA?xjs=s1","request_type":"script"}
+{"origin":"http://www.google.ca/","request_url":"https://www.google.ca/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb1.qujishu.com/avnekderkycx.js","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"http://www.linkedin.com/","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://stags.bluekai.com/site/26357?id=L6N62llA&redir=https://beacon.krxd.net/usermatch.gif?_kuid%3DL6N62llA%26partner%3Dbluekai%26bk_uuid%3D%24_BK_UUID","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WtM34wAACGMfPfyQ&img=1","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=ttd&partner_uid=aa0b5f17-a2c2-4d29-8653-094d8ddd8796","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/assets/page/SiteWide/SiteWide.css?f490b224bf874288433778c6054ae55a","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://aax-fe.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEOQr980FmpF1jeq80FyQbwA&google_cver=1","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:358-6685975-3653550:QVRKZSEBR7BT5RF15TNH$uedata=s:%2Fuedata%2Funsticky%2F358-6685975-3653550%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQVRKZSEBR7BT5RF15TNH%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D9304%26pc0%3D9304%26ld0%3D9304%26t0%3D1523791974992%26csmtags%3Daui%3Asw%3Aunregister%3Asupported%7Caui%3Asw%3Aunregister%3Aunsupported%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQVRKZSEBR7BT5RF15TNH%26aftb%3D1:9304","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://d.agkn.com/pixel/7421/?che=[FT_Random]&col=91234,9271,3092000,[FT_CONFID],50126,[%FT_IMPRESSIONID%],[%FT_GUID%]&puid=[%FT_GUID%]","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://ib.adnxs.com/getuid?https://aax-eu.amazon-adsystem.com/s/ecm3?id=$UID&ex=appnexus.com&","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1064110624/?userId=Yotka6hnTlOGvGgrxT09Cg&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://vdms-ssl.cedexis-test.com/img/16999/r20.gif?rnd=1-1-13960-0-0-16999-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_Movies/ic/c8fd6b5d/bd5c0afb.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/0B/DE5313.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p5.qhmsg.com/t0139a3cf9218887d3d.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/cxb_taobao.PNG","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/favicon.ico","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/news/transform/310/w710h400/20180415/oh-0-fytnfyp5003923.jpg/w710h400z1l50t14fa.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=32960581","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20140306wenmingzjg.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180403/f44d305ea48e1c2d010101.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/c5/cb/a0/c5cba0593e7052e0cf5e6c89563a0240/c5cba0593e7052e0cf5e6c89563a0240.9.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_180%2Cw_320%2Cc_fill%2Cg_faces:auto%2Ce_sharpen/http%3A//assets.eatingwell.com/sites/default/files/imagecache/standard/almonds_310_0.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMTYyODg0NDU1OV5BMl5BanBnXkFtZTgwNjcxMzU0MjI@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BNDU1MDI2OTUyNV5BMl5BanBnXkFtZTcwNTA1OTY1OQ@@._V1_SY345_CR13,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BMjA5NTk3NzE5OV5BMl5BanBnXkFtZTgwODAyODIwNTM@._CR127,22,1789,1341_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/vjav.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-vv_banner_atomic_sm/td-applet-viewer-templates-vv_banner_atomic_sm-min.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"https://hm.baidu.com/hm.js?12423ecbc0e2ca965d84259063d35238","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://cdn.tsyndicate.com/sdk/v1/bi2.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/mtb-windvane/4.0.3/index.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/mobile/website/img/espn_app_72@2x.png&w=240&h=240&transparent=true","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/cdo/rum/id?1523791896696","request_type":"other"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_5&relatedID=&news=0_0&SUV=null&_time_=15237919543342922656595425","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/js/collections/common-1818413004._CB499603761_.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://r.nexac.com/e/getdata.xgi?dt=br&pkey=quky68qukyi81&ru=https://beacon.krxd.net/data.gif?_kuid%3DL6N62llA%26_kdpid%3D4e3f8627-26fa-484d-bd95-a1f8f09d95a6%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAU5fm3dSuY9dJCdoTinHgyiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/316nxKpnxGL._RC%7C51faQ1uINoL.js_.js?AUIClients/SharedShoppingCartMobileAsset","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C41PsXsu4WrL.js,118Wk-h2B-L.js_.js?AUIClients/GWMWebAssets","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://m.thepiratebay.org/stylesheets/skeleton-min.css","request_type":"css"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?p_user_id=-yalcI9yS-6iePfINjDv7Q&ex=twca&id=-yalcI9yS-6iePfINjDv7Q","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=70&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A70%7D&logFlag=uaction_1523791857874&t=1523791927876","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://ib.adnxs.com/getuid?https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D358%26dpuuid%3D%24UID","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/last-survival-war-apocalypse-android.png:l","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=rp&google_hm=SkcwUUMyUEQtMTQtODJBTA==","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/icon_img.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/xizhim333/albumset/15079763/zoomcrop/75x75.jpg?v=1523785491","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/eitox8uppers/albumset/1930115/zoomcrop/75x75.jpg?v=1523785676","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/nav/right.png?1372079637","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://images.sohu.com/bill/s2017/materials/jd/0921/3272.html?clkm=%2F%2Fi.go.sohu.com%2Fcount%2Fc%3Fappid%3Dwapnews%26aid%3D100269248%26apid%3Dbeans_12274%26impid%3D0f0dbcc288104b396_0_0%26at%3D1%26mkey%3D0f0dbcc288104b396_0_0%26latcy%3D3917%26freq%3D0%26turn%3D1%26pgid%3Dsohu_index%26ax%3D12.953125%26ay%3D1701.671875%26cx%3D%26cy%3D%26ed%3D%26bucket%3D%26supplyid%3D4%26ext%3De%253DOyygn03WYDL%252BVv%252F3mNEQdqFmyQMB%252Fruy3%252F1xRO6RNFfGs9qthLHF70DQ8pec15VHqZovbVXrzzco7XYsOegVBjcDCze1BpeCimHmb2LvXsKGB9oaN3%252FU8uLXYHGVdGcROKCRJeS81hJEXPOJIIKfhh6l1THTruIiodwOjJDvGuqB2OztFDF12oTtnMx5oRDrYEuFktpJBq8%252FvNUYK51Vvh8fiveh5womueMDFo3uJUuniRvire2hLbtfQwvXwBDP9Z%252FRds5Il%252Bg9bnkITnNoCyOMzKMhQXJH1qSAQiuwY4VAq7voRegM6gkSuQ0mY4sBtX69iAJOAoKwatrJU1mhZj37lZNqHevo3wzFLEd5LlLrIAADmwPsL1MEZW35%252B8ppstU0qP7L1JzywfJ6%252FL3U3LzQgusRb1%252Fsi8eLgIaFbrbSHH0owgFPgRl7nBYWVzwMeYWcaxLPA3SXVgmHcQwr1wzpMrErZO%252FDTJdBOcuFKgTp0QpGOBIkUUAe%252BzBMWP9MzlXIVzma9N%252BfvWLL344x%252Fy1L3x0k8U3KXfkA3ICrOJYNAdBtiFsQ3GQQW%252BC9vfhNbChkAbyKFIKoZGM6C50xrQ%253D%253D%2509tt2%253D1523791941847%2509turn%253D1%2509geoid1%253D1410000000%2509geoid2%253D0%2509source%253Dshjtsybxpsyq%26rsln%3D360*512%26sf%3D0%26r%3D2927770983255%26uloc%3D%26newschn%3D1000000000%26subchannelid%3D%26ch_trans%3D%26jsv%3D%26ipos%3D1%26shbd_monitor_ext%3Dc%26c%3D%26e%3D%26pagerefer%3D%26suv%3D180415193221Z74L%26source%3D0%26_time_%3D1523791942196","request_type":"html"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://www.thepiratebay.org/","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mscom.demdex.net/dest5.html?d_nsid=0","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s2.pimg.tw/album/topman99/element/329267402_1523283654-3826437513/zoomcrop/90x65.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_BRlCMxM_Q3QQxkj9hS0QhQ&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/public/common/toolbar/images/100x100.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ia.media-imdb.com/images/M/MV5BNjMxNTMxNDMxNl5BMl5BanBnXkFtZTgwNTk3NDUyNTM@._V1_SX233_CR0,0,233,345_AL_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/514JesWg6VL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/91-lXBqc19L._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/BsQAAOSwT7Va0Rat/s-l225.webp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/footer_bg.png","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://feed.baidu.com/feed/api/tab/gettabinfo?pd=wise&sid=122436_100808_122154_114746_100097_120171_122489_118895_118870_118847_118830_118805_120550_107315_122862_117330_117433_122789_121142_122857_122886_123139_122496_114975_116407_122669_110085_122303&ssid=0&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&qid=1811881676&ms=1&cb=indJsonp&current_data=%22%22&_=1523791817276&cb=jsonp2","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/hotmovs.svg","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://securepubads.g.doubleclick.net/gpt/pubads_impl_194.js?v=195","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/bundle.LoggedOutHomeV2.a57dd2c46109bb7f.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-viewer-model/td-viewer-model-min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://entitlement.auth.adobe.com/entitlement/js/AccessEnabler.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/i/teamlogos/soccer/500/187.png&w=288&h=288","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/8323b1c0da95554f5fc75952b0430b32.js?conditionId0=472867","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/js/espn-defer-mobile.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/nomod/flexible_cbe608e.js","request_type":"script"}
+{"origin":"http://www.google.co.jp/","request_url":"https://adservice.google.co.jp/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938223_4579862638755&itemspaceid=12275&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938223&plateid=1001500000,1001800000","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://an.facebook.com/v2/placementbid.json?sdk=5.5.web&placementids[]=123410111540958_187803348434967&adformats[]=native&pageurl=https%3A%2F%2Fwww.msn.com%2F","request_type":"script"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/js/556f83bf/photos.module.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.unid.go.com/js/unid.min.js","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-js-9a10b8f6/js/js/bootstrap.js,common%7Cbootstrap.js/2/4QgC0ogxgag84Egcgp0E0v4yghgB0s0S02gDgggjgd0Bgwgt4Igig5gm4L4K1x/bk/true/none","request_type":"script"}
+{"origin":"http://www.360.cn/","request_url":"http://s8.qhmsg.com/!a04eed30/monitor131227.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://cdn.registerdisney.go.com/v2/outer/DisneyID.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"http://www.thepiratebay.org/","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fib.adnxs.com%252Fpxj%253Faction%253Dsetuid(%2527__EFGSURFER__.__EFGCK__%2527)%2526bidder%253D51%2526seg%253D2634060der%253D51%2526seg%253D2634060&google_gid=CAESEPd4Jzcj87qgNvzrB164ELA&google_cver=1","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner_id=rfuel&partner_user_id=1182546749638174950","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/prompt/4.0.2/css/loading.css","request_type":"css"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=16&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A16%7D&logFlag=uaction_1523791857874&t=1523791873876","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://pcookie.csbew.com/app.gif?&cna=fSZaEwxwcnECAdBGH1277Lo6","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=3&redir=https%3A%2F%2Fimage4.pubmatic.com%2FAdServer%2FSPug%3FpartnerID%3D27%26partnerUID%3D%5BMM_UUID%5D","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/index_xm.gif","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBKbHiE.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/yuanzun_2018323.png","request_type":"image"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.google.es/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20130828szjy.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_GjRFukgy7c1Sr6-RBjhs1g&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4151.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4155.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/amazonlaunchpad/de/Gateway/2018_02/iolandac_2018-02-05T15-59_0ebc52_1099615_de_launchpad_gw_quadcard_feb18_420x420_7._CB487250273_.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_yellow.svg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/os/mit/media/p/common/images/favicon_new-7483e38.svg","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://aorta.clickagy.com/pixel.gif?ch=124&cm=86070857378125119120981354726841823876&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D79908%26dpuuid%3D%7Bvisitor_id%7D","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/premium/launch-banner.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://mem.gfx.ms/me/MeControl/9.18088.0/en-US/meBoot.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/linked-buffer.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets","request_type":"css"}
+{"origin":"http://www.baidu.com/","request_url":"http://na0.bdstatic.com/static/cover/static/shoubaiWapAds/nativeAds_7366254.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/pkg/page/index/index.tpl_aio_baae7e4.js","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=13&checkda=1&ct=1523791831&rver=7.0.6730.0&wp=lbi&wreply=https%3a%2f%2fwww.msn.com%2fen-us%2fhomepage%2fsecure%2fsilentpassport%3fsecure%3dtrue&lc=1033&id=1184&mkt=en-us","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938208_4192652154822&itemspaceid=12278&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938208&plateid=1000800000,1001900000","request_type":"script"}
+{"origin":"http://www.jd.com/","request_url":"http://m.jd.com/index/recommend.action?_format_=json&page=1","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/languages/strings/en_US.js?1343","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/assets/experiment/playerjs/js/main.min.js?v=7&_=1523791941892","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yS/r/sCJjNfImXMR.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.espn.com/core/format/modules/head/i18n?edition-host=espn.com&lang=en&region=us&site=espn&site-type=full&type=ext&build=0.391.46.4&edition-view=espn-en-us&edition=espn-en-us","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://us-u.openx.net/w/1.0/sd?id=537148856&val=WtM4gQAABibm4O17","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fpixel.everesttech.net%252F1x1%253F&google_gid=CAESEPd4Jzcj87qgNvzrB164ELA&google_cver=1","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=8981&nid=2307&put=ecf97925-4f99-4dc2-9bf7-6775e63a3ba0&expires=30&next=https%3A%2F%2Fmatch.adsrvr.org%2Ftrack%2Fcmf%2Frubicon","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.amazon.in/","request_url":"https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://fonts.gstatic.com/s/roboto/v18/KFOlCnqEu92Fr1MmEU9fBBc9AMP6lQ.ttf","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/nn/lib/metro/g/myy/advance_base_rc4_0.0.68.css","request_type":"css"}
+{"origin":"http://www.wikia.com/","request_url":"https://loadm.exelator.com/load?_kdpid=e4942ff0-4070-4896-a7ef-e6a5a30ce9f9&buid=L6N7iig7&p=204&g=270&j=0","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a67349c00005ad338814cf070f2d9fb&pid=mm_113716014_12970037_52768244&cid=258981&mid=244850&oid=376&productType=1&qytInfoMTime=1523728962&cb=130301573","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WtM4gQAABibm4O17&C=1","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://tags.bluekai.com/site/2981?id=&google_gid=CAESEPMH7cxqolXTF3iOyv-nzbc&google_cver=1","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://rover.ebay.com/roversync/?site=0&stg=1&mpt=1523791923836","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/iptv-android.png:l","request_type":"image"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p3.qhimg.com/t01aba831f3e831c0e7.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/Jg2dXKZlPdWuKYHBdBbDS25UARWidDaJkQ0anjMmWns.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/Vk4AAOSwACRaxRTz/s-l500.webp","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t019c4a1e971c450c93.webp?size=500x257","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/like.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://pagead2.googlesyndication.com/bg/YRKqPoIt_ONlxH2tUGnouQ_G4hFZfGHYM-YHumdPwHE.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-header/td-applet-viewer-templates-header-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/security/pf/pcore-1.0.1.min.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51chvDI28JL._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/","request_type":"html"}
+{"origin":"http://www.espn.com/","request_url":"http://a2.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_NCF_OHIO_STATE_MEYER_SOT/dm_180414_NCF_OHIO_STATE_MEYER_SOT.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.google.com.tr/","request_url":"https://www.google.com.tr/gen_204?s=webaft&atyp=csi&ei=GTjTWtyLFcXe0wLprqPwBA&rt=wsrt.2142,aft.384,prt.241","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://simage4.pubmatic.com/AdServer/SPug?partnerID=156736","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns1.gigya.com/js/gigya.services.socialize.plugins.reactions.min.js?lang=en&version=latest","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768234&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791999800&fs=3&pvid=d7971891669a867aad69c9fd5e23f480&cg=a695bba4e9d1cc34d82bfe4598d8f297","request_type":"script"}
+{"origin":"http://www.uptodown.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=www.uptodown.com","request_type":"script"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.linkedin.com/fizzy/admin?1523791896705","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D","request_type":"other"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/normalize.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.cnn.com/","request_url":"https://sb.scorecardresearch.com/r2?c2=6035748&d.c=gif&d.o=cnn-adbp-domestic&d.x=180293245&d.t=page&d.u=https%3A%2F%2Fwww.cnn.com%2F","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-23892695-1&cid=885864085.1523791857&jid=1339518023&_gid=1294404763.1523791857&gjid=481498379&_v=j66&z=1331474201","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsuxA6TKmcLcE9uKWzkH5N3DWMRDuVQxa4gfySvHeUykFnrkpjJMdVUE75e3A6KlA-WlWl8NsQr4OTFWLCkgZ-4&sig=Cg0ArKJSzB308yzUaM6IEAE&id=osdim&ti=1&adk=1002300037&tt=11092&bs=360,512&mtos=1182,1182,1182,1182,1182&tos=1182,0,0,0,0&p=114,20,164,340&mcvt=1182&rs=3&ht=0&tfs=9908&tls=11090&mc=1&lte=1&bas=0&bac=0&avms=geo&bos=360,512&ps=360,8320&ss=360,512&pt=-1&deb=1-0-2-16-21--1-11-19&tvt=8460&op=1&r=v&uc=8&tgt=DIV&cl=1&lop=1&tslp=606&cec=1&clc=1&cac=0&cd=320x54&v=r20180411","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=191940&nid=3778&put=WtM4BQAAAGWhsjF0","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.facebook.com/fr/b.php?p=1531105787105294&e=WtM34wAACGMfPfyQ&t=2592000&o=0","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=2340&dpuuid=73f6f712-40a0-11e8-9d26-2b16715804f7","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/batch/sprites/social-24/8ce93608061b39e441a79f519dd1a3ab.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/aldiko-book-reader-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/park15/albumset/16903182/zoomcrop/75x75.jpg?v=1403516218","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/i/teamlogos/nfl/500/dal.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/icons/scalable.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1sbfQk1GSBuNjSspb763iipXa1.png_q70.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/gno/sprites/sky_webnav_V1_sprite_2x._CB515271921_.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791946943_4451391546583&itemspaceid=13413&adps=30000001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&suv=180415193221Z74L&appid=wapnews&_time_=1523791946943","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://cdn.at.atwola.com/_media/uac/msn.html","request_type":"html"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/6IDiefzOIVg-TylK8P5FhA/009/330/102/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180413145051-kfile-ximena-barreto-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/4462000/4462157/220x165/7.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_5,y_5,w_730,h_487/os/news/744acc11485e354a6dffd709651b36be.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/images/favicon/favicon-16x16.png?v=1","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://a950cd219fa61389e8248ff8941022738.profile.atl51.cloudfront.net/test.png","request_type":"image"}
+{"origin":"http://www.stackoverflow.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-user-notification-0.1.js","request_type":"script"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/recaptcha__vi.js","request_type":"script"}
+{"origin":"http://www.twitter.com/","request_url":"https://abs-0.twimg.com/responsive-web/web/ltr/loader.AppModules.4995b016a71e028c.js","request_type":"script"}
+{"origin":"http://www.qq.com/","request_url":"https://mat1.gtimg.com/www/https/pingjs20161020.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-starred.min-vfln2FSqr.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://libs.pixfs.net/localScrollFix/localScrollFix.min.js?v=e8869abe59f37ca1f0847c8fa8d65222","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/common.js?a1e6006aa2ff53ecfa47f237af6a755a","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://t.co/i/adsct?txn_id=l4umf&p_id=Twitter","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/kor.png&h=60&w=60","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-css-9a10b8f6/css/css/pages%7Chome%7Cconcord.less/2/0H0W080P0e0R0O0_0X0Q0V/none/true/none","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=%2Fphoto%2F2018%2F0414%2Fr356695_1296x729_16%2D9.jpg&w=320&h=180&scale=crop&cquality=40&location=center","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=openx&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.facebook.com/fr/r.php?p=558293300959460&e=yv2UNYixS52k7Ba5Hrdpyw&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dfbca%26id%3Dyv2UNYixS52k7Ba5Hrdpyw&s=1523792001&h=T0xOVTVFUWYrbVNvZS9BVcbMOolk3qo5H4Bd_0keaSzR4Z20","request_type":"html"}
+{"origin":"http://www.live.com/","request_url":"https://outlook.live.com/owa/prefetch.aspx","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938233_8652547780288&itemspaceid=13818&adps=30000002&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938233&plateid=1001900000,1001700000","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://www.baidu.com/?action=static&ms=1&version=css_page_2@0,css_callapp@0,css_weather@0,css_icon@0,css_plus@0,css_edit@0,css_modal@0,css_widget_sug@0,css_skin@0,js_esl@0,js_zepto@0,js_event@0,js_fastclick@0,js_utils@0,js_smartymonkey@0,js_index@0,js_banner_ctrl@0,js_inputlog@0,js_bdnow@0,js_nctips@0,js_widget_textinput@0,js_widget_sug@0,js_mp@0,js_hash_lib@0,js_skinRenderIndex@0,js_skinIphone@0,js_prefetch@0,js_sug@0,js_iscroll@0,js_superframe@0,js_init@0,js_geolocation@0,js_login@0,js_tab@0,js_md5@0,js_url@0,js_lswrite@0,js_modal@0,js_thirdparty@0,js_m_monitor@0,js_superstart@0,js_baiduloc@0,js_callbaiduapp_android@0&callback=B.getCode&r=468&sid=122436_100808_122154_114746_100097_120171_122489_118895_118870_118847_118830_118805_120550_107315_122862_117330_117433_122789_121142_122857_122886_123139_122496_114975_116407_122669_110085_122303","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1067250390/?random=1523791839044&cv=9&fst=1523791839044&num=1&guid=ON&resp=GooglemKTybQhCsO&eid=376635470&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=0&url=https%3A%2F%2Fwordpress.com%2F&tiba=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&async=1&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://invocation.combotag.com/placement_invocation?id=65349","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ml314.com/utsync.ashx?pub=748&adv=&et=0&eid=&ct=js&pi=&fp=&clid=&ps=&cl=&mlt=&data=&&cp=https%3A%2F%2Fcdn.krxd.net%2Fpartnerjs%2Fxdi%2Fproxy.3d2100fd7107262ecb55ce6847f01fa5.html%23!kxcid%3DITb_4eqO%26kxt%3Dhttps%253A%252F%252Fwww.cnn.com%26kxcl%3Dcdn%26kxp%3D&pv=1523791884986_j6svqxlh6&bl=en-us&cb=4036304&return=%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dmadisonlogic%26partner_uid%3D%5BPersonID%5D&ht=&d=&dc=&si=1523791884986_j6svqxlh6&cid=&s=360x512&rp=https%3A%2F%2Fwww.cnn.com%2F","request_type":"script"}
+{"origin":"http://www.360.cn/","request_url":"http://s3.qhmsg.com/static/92642666da227923/carousel.1.0.4.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://connect.facebook.net/signals/config/1559459634097838?v=2.8.12&r=stable","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01ozf6ortdL.js?AUIClients/DetailPageAlohaAssets","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://re.csdn.net/csdnbi","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel-a.sitescout.com/dmp/pixelSync?nid=1","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dp2.33across.com/ps/?pid=897&random=515648114","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://token.rubiconproject.com/token?pid=2179&pt=n","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://px.ads.linkedin.com/collect/?time=1523791867534&pid=4373&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&fmt=js&s=1&cookiesTest=true","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://fls-eu.amazon.in/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=a999e432-40a0-11e8-b967-95a25c8f73fa&ex=adelphic","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v3/img/skins/xnxx/xnxx-inline-loader.gif","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_news_scroll-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://tags.bluekai.com/site/2981?id=&google_gid=CAESENw6F0A8tlL6bVZ7Bb6Ed20&google_cver=1","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.google.com/ads/conversion/981179826/?random=642328750&cv=9&fst=*&num=1&label=40zWCLqP1XUQsrvu0wM&bg=ffffff&hl=en&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=2&url=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26session%3Dn%252Fa%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Df1fdc59c-9452-4167-a583-cc8ede9a2929&ref=https://adtech.nflximg.net/adtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522f1fdc59c-9452-4167-a583-cc8ede9a2929%2522%257D&fmt=3&ctc_id=CAIVAgAAAB0CAAAA&ct_cookie_present=false&cdct=2&is_vtc=1&ocp_id=HjjTWoG_OYSkigOvzoHACw&random=3764641554&resp=GooglemKTybQhCsO","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/user-lists/1000051215/?random=1523791866937&cv=9&fst=1523790000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=2643173663&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/color-neighbors-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/aaaavikey/albumset/15079760/zoomcrop/75x75.jpg?v=1523786367","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/hero-bifurcated-icons.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/tianqiwuxian1111.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://www.savefrom.net/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/safeframe/1-0-23/html/container.html","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/League%20of%20Legends-429x572.jpg","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://i.ytimg.com/vi/NgLVxhNEbn4/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLBC1USGsLVrXaWeOWM62Q7qmeFtBA","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/2ncAAOSwNkJaTAxj/$_57.JPG","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius2.bongacams.com/live/01d/056/359/big_lq/97a9080fea58f1ff991b87f8e9d5f8dd.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afp.alicdn.com/afp-creative/creative/u113716014/465b11e883f45e8a41cd035da41a7084.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/514JesWg6VL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/network/porn555.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://0914.global.ssl.fastly.net/ad2/script/x.js?cb=1523791865025","request_type":"script"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/bundles/base/Consumer.js/42b70c664565.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ssl.cdn.turner.com//ads/cnn/cnn_homepage.json","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v3/js/skins/min/require.static.js","request_type":"script"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/images/ds/ult/jp/useraction-1.0.3.js","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/static/fonts/roboto/roboto-regular.woff","request_type":"font"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/js/espn-analytics.js","request_type":"script"}
+{"origin":"http://www.google.de/","request_url":"http://www.google.de/","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://6355556.fls.doubleclick.net/activityi;type=wordp0;cat=wppv;src=6355556;u5=zDW8PEy7OW5KBlV2LVBtGlDi;u6=%2F;u7=TOuWFMuZ7M7UmAdtZtDjgCTLYV5yYpup;ord=2991209809826.525","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://www.pinterest.com/resource/ContextLogResource/create/","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770091&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792004409&fs=2&pvid=a5a22014e1af117ffb99390c46a26eef&cg=afc1254985e793d9efc92f30cc3fef22","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://c.go-mpulse.net/boomerang/config.js?key=9SLYA-PCQKP-CU56T-D2UD9-N4WJG&d=www.microsoft.com&t=5079306&v=1.405.1475087321&if=&sl=0&si=4hjpcyvjjm7-NaN&plugins=ConfigOverride,PageParams,AutoXHR,SPA,Angular,Backbone,Ember,History,RT,CrossDomain,BW,NavigationTiming,ResourceTiming,Memory,CACHE_RELOAD,Errors,TPAnalytics,LOGN","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://d.agkn.com/pixel/8198/?che=1523792004&sk=164801102661000507459&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164801102661000507459&ex=neustar.biz","request_type":"other"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/css/index/icon_c04c63d.css","request_type":"css"}
+{"origin":"http://www.wikia.com/","request_url":"https://static.wikia.nocookie.net/qube-assets/f2/2961/news-and-stories.css?v=109b113e36f1dd3de996f15be39a047fa178b3a4","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://loadm.exelator.com/load/?p=204&g=1270&j=0&BUID=39041E2B94ED6EF00CB315F995BE6F73","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://imp.optaim.com/201803/90cd1cc4e492010a17e53379a0913b0c.php?a=0&adpid=beans_12292&impid=02ae7c35b3c1133a5_0_0&_time_=1523791943475","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://top-fwz1.mail.ru/counter?js=13;id=2104775;u=https%3A//mail.ru/;st=1523791840769;title=Mail.Ru;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=8444bcd29777bf8d;ver=60;lvid=1523791844609%3A1523791844612%3A1%3Ae5d8a31e801c4e17a79c5b7f63693070;_=0.9288797762443417","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/vi/incognito.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/ik3pxLhNpdCMLyi3o_mpkMaGASASLMjSQJ_v7TutUuIiD-qtLkXEiRYlPzGhoQ=w256","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/images/20170601Rectangle_3.png","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/cv/ae/news/Purple-News.png","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/gno/sprites/sky_webnav_V1_sprite_1x._CB515271921_.png","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://www.wordpress.com/","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/b3ef1c0a-2b6b-4130-aeb3-b46091ebd1a2_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33035992","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0412/dm_180412_WNBA_DRAFT_RECAP/dm_180412_WNBA_DRAFT_RECAP.jpg","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTMzMDk0MzU1NV5BMl5BanBnXkFtZTYwMTg0NTg3._CR100,357,386,289_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_52,y_17,w_912,h_608/os/news/b64e4f6d7f49bee1a4318572672931f1.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61nrWDGVoOL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.onclkds.com/","request_url":"http://www.onclkds.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/wordmarks/wordmark_black.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-button-cheeseburger-vflBv7pSe.svg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/rtbspub?&prid=7PRFT79UO&cid=8CUNL3XVM&crid=903352736&size=300x250&rp=1.2&vi=1523791837453272108&ugd=3&requrl=https%3A%2F%2Fwww.msn.com%2F&useAppData=0&hlt=1&tr=0.1587048845192376","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://www.googletagservices.com/dcm/dcmads.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://use.typekit.com/af/ef4671/000000000000000000017706/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n9&v=3","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-lasso-footer.min-vfl3p6P7q.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41DF6mj397L.css,31lbgEQUW6L.css,31o-8LAxirL.css,11tkAOwE6OL.css,21yQivNbm7L.css,11ISqSj9gHL.css,018pZJ+Ms7L.css,21LL5kV+OzL.css,21mvSipn7pL.css,01FhhDKMwIL.css,01iAFIIjomL.css,21QwDiO8ycL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11rOGHgDuHL.css,01oETTPm7xL.css,21CNSKZ67ML.css,11rhPo030XL.css,11G8UP3P7ML.css,51oAYplAOyL.css,21LCBYGBqCL.css,21lDMA2J74L.css,31oRAb0fZWL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,11UDdszadlL.css,21f0r7D13IL.css,61lDBjn6HPL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,01QRe-mUhyL.css,31LBzl8T3vL.css,21DFs8eEV-L.css,110QeNMe7yL.css,01YdhMxma0L.css,01urH7Slt6L.css,11cAYJlTEgL.css,01zKZ9sec9L.css,018mGORJ7tL.css,11fvu+DzMxL.css,11iDQvZvByL.css,01lh9w-GYYL.css,01S-aGXaDFL.css,11Mso4bvY-L.css,01dDkofRjeL.css,21hDhA73OmL.css,01LCsoCesOL.css,01NEM4SRd9L.css,01BU7o1DHkL.css,21pnh6VHUzL.css,01YXqSisf3L.css_.css?AUIClients/DetailPageMobileWebMetaAsset","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://tredir.espn.com/capmon/GetDE?set=j&param=country&param=countryisocode&param=state&param=metro&param=metrocode&param=postcode&param=offset&param=dst&param=countrycode&param=connection","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://hubt.pornhub.com/js/ht.js?site_id=3","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://secure.quantserve.com/aquant.js?a=p-3Ma3jHaQMB_bS","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a2.espncdn.com/combiner/i?img=/photo/2018/0412/r355616_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j46&a=660400026&t=pageview&_s=1&dl=https%3A%2F%2Fwww.paypal.com%2Fus%2Fhome&ul=en-us&de=UTF-8&dt=Send%20Money%2C%20Pay%20Online%20or%20Set%20Up%20a%20Merchant%20Account%20-%20PayPal&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=SGCACEABJ~&jid=1227979929&cid=31773146.1523791847&tid=UA-53389718-12&_r=1&cd1=31773146.1523791847&cd2=&cd3=false&cd4=%2Fus%2Fhome&cd5=us&cd6=en_US&cd7=&cd8=&cd9=&cd10=&cd19=&cd20=&cd22=mobile%3Amktg%3Apersonal%3A%3Ahome&cd25=&cg3=false&cg1=mpp&cg2=3&z=1872806","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://sshowads.pubmatic.com/AdServer/AdServerServlet?pubId=156736&siteId=269857&adId=1318691&kadwidth=320&kadheight=50&SAVersion=2&js=1&kdntuid=1&pageURL=https%3A%2F%2Fad.mail.ru%2Fadi%2F100590%3Frnd%3D107581893&inIframe=1&kadpageurl=https%3A%2F%2Fmail.ru&operId=3&sec=1&kltstamp=2018-4-15%204%3A30%3A53&timezone=-7&screenResolution=360x512&ranreq=0.9334147702138578&pmUniAdId=0&adVisibility=0&adPosition=-1x-1","request_type":"html"}
+{"origin":"http://www.facebook.com/","request_url":"https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537072980%26val%3D__EFGSURFER__.__EFGCK__","request_type":"html"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.google.com.br/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.adsafeprotected.com/rfw/st/143441/22764869/skeleton.js?adsafe_url=https%3A%2F%2Fwww.cnn.com%2F&adsafe_type=abcedfq&adsafe_jsinfo=,id:1cd9a402-3805-7f68-3cd0-7d66358c863f,c:9OXR3k,sl:outOfView,em:true,fr:true,mn:app04sje,pt:1-5-15,wc:0.0.360.512,ac:0.7403.336.72,am:by,cc:4.359.352.72,piv:0,obst:0,th:0,reas:l,cmps:1,br:c,fv:0,bv:na,dm:na,abv:na,an:n,fm:qPhNqxI+11|12|13|14|151|16|17|18|19|1a|1b1|1b2|1b3|1b4*.143441-22764869|1c|1d|1e|1f,idMap:1b4*,pl:,rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:1,fif:0,gm:0,uf:0,tt:rjss,et:153,oid:81df2541-40a0-11e8-bfe6-40167e34c5be,v:17.4.90,sp:0,ct:3640,dtm:i,gtpl:0,wr:360.512,sr:360.512,ov:0","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9201373478&_s=s&_id=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.co.uk&slot=navFooter&a2=0101264bea73f7f0a15d445ceba12c12b857d9ceb1efa65d37a4620a87e44f56c1ef&old_oo=0&cb=1523791855593","request_type":"other"}
+{"origin":"http://www.netflix.com/","request_url":"http://www.netflix.com/","request_type":"other"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.krxd.net/usermatch.gif?partner=survata&partner_uid=132845f5-8fb2-71b2-d8e6-bc193e3cf87a","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:262-9616072-1847409:Q3AKTQX4Z8AX1W7T64V5$uedata=s:%2Fuedata%2Funsticky%2F262-9616072-1847409%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3DQ3AKTQX4Z8AX1W7T64V5%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D13236%26cf0%3D13258%26pc0%3D13258%26ld0%3D13258%26t0%3D1523791869127%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DQ3AKTQX4Z8AX1W7T64V5%26aftb%3D1:13259","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:258-8151141-7687141:49NGBMVT1ABRN6GGR916$uedata=s:%2Fuedata%2Funsticky%2F258-8151141-7687141%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.200436.0%26id%3D49NGBMVT1ABRN6GGR916%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D13154%26pc0%3D13159%26ld0%3D13159%26t0%3D1523792000004%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D49NGBMVT1ABRN6GGR916%26aftb%3D1:13159","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://dpm.demdex.net/ibs:dpid=81304&dpuuid=g9e51602ae03bce4bdfa","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=1084201993&t=pageview&_s=1&dl=http%3A%2F%2Fcoccoc.com%2F&ul=en-us&de=UTF-8&dt=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IGBAgAAB~&jid=1172235258&gjid=1611549489&cid=1265310549.1523791856&tid=UA-35860610-14&_gid=1916280616.1523791856&z=69795872","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/shareit-connect-and-transfer-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/stories/developers/ariya.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/madminton2011/albumset/16223219/zoomcrop/75x75.jpg?v=1523211718","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/default/bonga_thumb.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p5.qhmsg.com/t017796b49e636afdd7.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"https://static.popads.net/img/bg/rounded/main/bg.png","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.google.co.in/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"http://www.taobao.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.yieldmo.com/partner.min.html?mps=0","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/04/15/1523775620_20180415-00000023-asahi-000-view-x104-y104.jpg","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://otf.msn.com/c.gif","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://m.so.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/gp/gw/ajax/dataStore.html/258-8151141-7687141?ie=UTF8&hmac=AE3752E2A39869F5B3F770EFBC36D1704E4E4A9A&opf_redir=1&relatedRequestId=49NGBMVT1ABRN6GGR916","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://www.amazon.in/gp/gw/ajax/dataStore.html/260-2953656-0613235?ie=UTF8&hmac=91EEF8EF197E83F91D3619CDA51B6722A9D0688C&opf_redir=1&relatedRequestId=3P95XKNQTYVQ066DW1Q8","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://libs.pixfs.net/jquery.templates/beta1/jquery.tmpl.min.js","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-bce1c4976aa/v3/js/jquery.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.fps.clientlibs/beagle/fe/resources/js/aceui-reimagine.min.fp-f7469725784f8beef23540866c4bd0c6.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/zepto/4.0.9/touch.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://s.secure.espncdn.com/stitcher/artwork/collections/media/6da363ae-4a4b-48f4-805e-98f00ae65f67/16x9.png?showBadge=true&package=ESPN_PLUS?showBadge=true&package=ESPN_PLUS","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=pavVoOCiQGy08CEOlgWPZQ&twitter_redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dtwca%26id%3DpavVoOCiQGy08CEOlgWPZQ%26","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.chartbeat.com/js/chartbeat_mab.js","request_type":"script"}
+{"origin":"http://www.bongacams.com/","request_url":"https://bongacams.com/tools/track.php?mo=portrait","request_type":"html"}
+{"origin":"http://www.google.co.in/","request_url":"https://adservice.google.co.in/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.google.es/","request_url":"https://www.google.es/gen_204?s=webaft&atyp=csi&ei=EjjTWr-7F4Ws8APa7aPACQ&rt=wsrt.2199,aft.378,prt.215","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"http://www.xnxx.com/","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"http://www.wikia.com/","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_js_controller.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/client/ext/m_qs_click_protection.js","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.google.com.hk/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb1.qujishu.com/bvzdlc.js","request_type":"script"}
+{"origin":"http://www.bongacams.com/","request_url":"https://rum-static.pingdom.net/prum.min.js","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://static.ads-twitter.com/uwt.js","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo0OC4zMTIJOTUzYTdhMDgtNWEzNS00YTdiLTkyZjEtZjc1NDc0MDEwOTYwCTMyNTAyNDUJMzExNzM2Mwk1OTE4NDAzMzAxX1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc4MwkzNTMxOTg3CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQkwZTczNGQ5NS01MzA5LTM3MzMtYTgxNC03ZmE4YTA4MTU2YjMJMzAwMDAJMC4wMDE2NjY2NjY3CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjAzMTc6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwMjowLjB8dXNlcl9nZW5kZXI6NTAxOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTMJMzAwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=86ff799ad09e37ab&p=DnNNlVMJNzOoFH%2BooIFWszQIuq%2B%2FVhM7l9FrXA%3D%3D","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/usermatch.gif?google_gid=&google_gid=CAESELNHBHB7h6f1Lri-d-4iYIk&google_cver=1","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/components/rebrand_navigation-vflvfWcqH.css","request_type":"css"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=91191954147729940174299115411397659455&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d91191954147729940174299115411397659455&mm_bnc&mm_bct","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=992&dpuuid=1enkd06utfhwf","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://www.google-analytics.com/collect?v=1&_v=j66&a=880546608&t=event&ni=0&_s=2&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=ns-fandom-app-smart-banner&ea=impression&el=view&_u=YEDAAEAB~&jid=&gjid=&cid=970841907.1523791982&tid=UA-71552437-1&_gid=1459932104.1523791982&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&cd11=US&z=2101791865","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/v/home/dq/images/logos/product_red_logo_small_2x.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://code.jquery.com/mobile/1.2.0/images/icons-36-white.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/yyc0408/albumset/16228655/zoomcrop/75x75.jpg?v=1523716655","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/logo-menu.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=yieldmo&ttd_tpi=1&ttd_puid=g9e51602ae03bce4bdfa","request_type":"html"}
+{"origin":"http://www.onclkds.com/","request_url":"http://fonts.gstatic.com/s/ptsans/v9/jizaRExUiTo99u79D0KExcOPIDU.woff2","request_type":"font"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/4domqStuhOzuc0bQ_2BIKQ/009/342/170/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/0674dfe5-fc76-4073-9f45-80062939cb1b_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180413203722-jeffery-zeigler-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/fd3dec6e-fbe9-4d43-9d20-fcb69e1bf532/scale-to-width-down/800","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/webstatic/icon/favicon.ico","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ad2.nend.net/feed.php?media=1182&site=5271&spot=208015&type=1&oriented=1&target=_top&cb=44433924649396130","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn3.optimizely.com/js/geo2.js","request_type":"script"}
+{"origin":"http://www.baidu.com/","request_url":"http://m.baidu.com/se/static/js/service/index_polymer_7a2eb26.js","request_type":"script"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/imdb/js/collections/mobile/responsive-3721259438._CB497239437_.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/photo/2018/0402/r350715_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/media/motion/2018/0414/dm_180414_Enhanced_Donovan_Mitchell_historically_great/dm_180414_Enhanced_Donovan_Mitchell_historically_great.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://m.yahoo.co.jp/","request_type":"html"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://idsync.rlcdn.com/397286.gif?partner_uid=g9e51602ae03bce4bdfa","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1","request_type":"html"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMt5DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGe_EJBPiaZ3OQDl1cLsLN2xzE5Ug?xjs=s1","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://pb1.qujishu.com/vrdicaeb8x.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"http://www.apple.com/","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://servedby.flashtalking.com/imp/8/91234;3093000;201;redirect;YieldMo;CRDCU000000XXXXXXXXXXXYIELDMOXXXXXXXXXXXCOUSAHWXENWWWXOAYLSLEVENH5CRLinks/?cachebuster=4714041425447159699&url=https://dishdigital.sp1.convertro.com/view/vt/v1/dishdigital/15/cvo.gif?cvosrc=display.yieldmo.crdcut&cvo_cid=91234&cvo_creative=yieldmolifestyle&cvo_pid=SLGD_ACQ_MTAGAXX_COUSA_YM_NA_WTCP_CRDCU_000000XXX_XXXX_XXXX_YMxLIFESTYLEx_XXXXX_COUSA_HWXEN_WWWXOA_YLSL_EV_EN_H5_CRLinks","request_type":"other"}
+{"origin":"http://www.wordpress.com/","request_url":"https://s1.wp.com/home.logged-out/page-domain-only/css/styles.css?v=1513794015","request_type":"css"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/listings.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"https://www.facebook.com/tr?ev=BlueKaiAudience&id=350737188667353&cd[bkcampaignid]=270103","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-44184928-2&cid=541858476.1523791959&jid=1581826687&gjid=1297575630&_gid=47841196.1523791959&_u=6GDAgEADQ~&z=695749511","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A2016%2C%22netDns%22%3A300%2C%22netTcp%22%3A455%2C%22srv%22%3A598%2C%22dom%22%3A18126%2C%22loadEvent%22%3A80000%7D&et=87&ja=0&ln=en-us&lo=0&rnd=900359793&si=969516094b342230ceaf065c844d82f3&v=1.2.30&lv=1","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://servedby.flashtalking.com/spot/8/10943;85008;8362/?spotName=Variables_Tag&ftXRef=&U1=91347194757900030554314852707948543921&U2=&U3=&U4=adobe.com&U5=&U6=&cachebuster=27481.63080445276&ft_trackID=37575927C0CEDF","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://apiservices.krxd.net/stats?q=controltagv2.views%3A1%7Cc%2Ccontroltagv2.views.alpha%3A1%7Cc%2Ccontroltagv2.views.alpha.Chrome%3A1%7Cc%2Ccontroltagv2.tags_delivered%3A18%7Cc%2Ccontroltagv2.tags_delivered.alpha%3A18%7Cc%2Ccontroltagv2.tags_delivered.alpha.Chrome%3A18%7Cc%2Ccontroltagv2.proxy_start%3A11702%7Cms%2Ccontroltagv2.nav_start%3A1523791973836%7Cms%2Ccontroltagv2.start%3A11684%7Cms%2Ccontroltagv2.set_kuid%3A11742%7Cms%2Ccontroltagv2.proxy_ready%3A14492%7Cms%2Ccontroltagv2.dom_ready%3A14603%7Cms%2Ccontroltagv2.tags_first%3A14609%7Cms%2Ccontroltagv2.dom_load%3A14661%7Cms&format=gif","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://servedby.flashtalking.com/track/85008;8362;403;37575927C0CEDF/?ft_data=d9:f55a5f4c03e14f21b9cf809f6cffcf9e&cachebuster=246177.07028579284","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/stuntcar3-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/8-ball-pool-android.png:l","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/wzyqk/qdj/201804/W020180418573433796079.png","request_type":"image"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/resources/images/0/sprite1.narrow.x2.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/hiamber0/albumset/7391240/zoomcrop/75x75.jpg?v=1523609867","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/3b719e6e122565e45cfc06eeee89af0f.PNG","request_type":"image"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://nicolive.cdn.nimg.jp/live/simg/img/a447/1339329.5640d1.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/fc919dd4-a9e9-4b87-82dc-443fbf953f21_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Counter-Strike:%20Global%20Offensive-429x572.jpg","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB1bcsuauGSBuNjSspbq6AiipXaA.jpg_220x220q90.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/cf2ef83b-34a1-4987-bc6b-8f5d6f8fcfda_desktop.png?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=32904103","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/f44d307589141c3a683d02.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180412124136-cnn-total-recall-quiz-041318-large-tease.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afp.alicdn.com/afp-creative/creative/u113716014/c69c5e537c724c173551c90cbdd45416.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41BMyAk8duL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/0I0AAOSwTPRavRhk/s-l500.webp","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://d9.flashtalking.com/lgc","request_type":"text"}
+{"origin":"http://www.live.com/","request_url":"https://logx.optimizely.com/log/event","request_type":"text"}
+{"origin":"http://www.adobe.com/","request_url":"https://use.typekit.com/af/6e034a/000000000000000000017702/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=i4&v=3","request_type":"font"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-swipe_progress_dots/td-applet-viewer-templates-swipe_progress_dots-min.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-soccer.png&h=240&w=240&scale=crop&cquality=40","request_type":"image"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.xnxx.com/","request_url":"https://www.xnxx.com/in.php?referer=","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6865528665029394&output=html&h=280&slotname=7131202640&adk=3899251677&adf=42664218&w=336&lmt=1523792014&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&flash=0&wgl=1&dt=1523792013488&bpp=44&bdt=11381&fdt=1069&idt=1080&shv=r20180411&cbv=r20170110&saldr=aa&prev_fmts=336x280%2C336x280&correlator=5842617019658&frm=20&ga_vid=151777037.1523792004&ga_sid=1523792014&ga_hid=963839304&ga_fc=0&pv=1&iag=3&icsg=2&nhd=1&dssz=3&mdo=0&mso=0&u_tz=-420&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=12&ady=2111&biw=360&bih=512&abxe=1&scr_x=0&scr_y=1&eid=21061122%2C20040069&oid=3&rx=0&eae=0&fc=656&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C360%2C512&vis=1&rsz=%7C%7CeEbr%7C&abl=CS&ppjl=f&pfx=0&fu=8208&bc=5&osw_key=4279392610&ifi=3&xpc=JVqNezhmtP&p=https%3A//m.pixnet.net&dtd=1095","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns.us1.gigya.com/gs/webSdk/Api.aspx?apiKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&version=latest","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://m.leju.com/?callback=jsonp_0540699252445348&timestamp=1523791845317&ctl=langshou&site=api&act=sl&nopic=0&page=0","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/api/OxBannerService/getAdvertisements.jsonp?zone=614&category=&pageurl=http%3A%2F%2Fsp.nicovideo.jp%2F&pagevariant=&callback=ads_callback_1&_=1523791955790","request_type":"script"}
+{"origin":"http://www.savefrom.net/","request_url":"https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/2.75.8/js/cnn-analytics.min.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://sb.scorecardresearch.com/b?c1=8&c2=11473066&c3=2370896352948000006&ns__t=1523792027852&ns_c=UTF-8&ns_if=1&cv=3.1m&c8=&c7=https%3A%2F%2Fimg.scupio.com%2Fhtml%2Fad.html%3Fv%3D1.2.14&c9=","request_type":"other"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/eboxapps/css/6c/cc2ec0351f5c0129add6ad34bf8f33a6a2374a.css","request_type":"css"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/nn/lib/metro/g/theme/viewer_sm_0.0.5.css","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=adobe.com&id=50374719972319092543287407355026526680","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=36&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A36%7D&logFlag=uaction_1523791857874&t=1523791893876","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=22&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A22%7D&logFlag=uaction_1523791857874&t=1523791879876","request_type":"image"}
+{"origin":"http://www.youtube.com/","request_url":"https://ad.doubleclick.net/ddm/trackimp/N3671.YouTube/B20898414.216859501;dc_trk_aid=417338505;dc_trk_cid=99743133;ord=1987069749;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://audible.demdex.net/event?d_event=imp&d_src=214509&d_site=2311301&d_creative=92161433&d_placement=218069769&d_campaign=20961954&d_bust=1468081195","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/color-neighbors-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/turn-right-android.png:l","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://www.xvideos.com/favicon-16x16.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/MPmddYcgxwTm3Iy-Q_vWIyBEbdR_ugBlhQjpIg2eQPC4c1LFn-j7A3-nFawqrA=w256","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/nanfangyouqiaomu_18323.png","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/y_/r/mFt2Gbxw9rO.png","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/2017/GW/SubNav/Final/01._CB499114221_.png","request_type":"image"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://ae01.alicdn.com/kf/HTB11f6YjY1YBuNjSszh763UsFXa3.png","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-01a49470266a51f632dab1aef2fc09112d280c1e._V2_.png","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://navdmp.com/req?adID=86070857378125119120981354726841823876","request_type":"html"}
+{"origin":"http://www.taobao.com/","request_url":"https://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/4651000/4651729/220x165/2.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$homepagequiz/ic/0bea548b/d305a9ed.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://tn.smilevideo.jp/smile?i=33051262","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/03/cb/a1/03cba13ce9e6a703a216f94ea43fda2d/03cba13ce9e6a703a216f94ea43fda2d.29.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/ed/17/f5/ed17f5fc966105611eec0b98f5426dc7/ed17f5fc966105611eec0b98f5426dc7.21.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://a.thumbs.redditmedia.com/u7GHzN0A5do2c-E_5fHQvHf6XkkpYPgO9IFd3kgZL04.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/rz/l/favicon.ico","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-list-0.1.js","request_type":"script"}
+{"origin":"http://www.bongacams.com/","request_url":"https://www.gstatic.com/recaptcha/api2/v1523554879111/recaptcha__en.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://web.vortex.data.microsoft.com/collect/v1","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://cdnssl.clicktale.net/www/WR-latest.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-coreui.min-vfl5cpin5.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/mlb/500/scoreboard/chc.png&h=312&w=312","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/common/commonH_B/js/monitoringTool.min.js?v=jd201802175619","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/pagead/gen_204?id=sodar&v=24&t=2&bgai=BKlBkAjjTWpCRBs_wkwO64IuICwAAAAA4AeAEAg&bg=!R0SlRFxEJ9onNf_7FuMCAAABclIAAAmQmQGHNUs7Qwp1JoGsRnaIpEi93Dcat16M1i11TDpkhB_jrP4OgWChCK7uhbZwKsfr_XUyfW0P7R44Kr7hzoCB-t5gph42cQiJwzTVNP28asykuHEJ5HEa3Sg7BWFbnGOdmHAj3c8m2o55_8-jlJycSmI3SMaVMqpl4D2g_aosCkQtDd2qFIHsEIZilJPNskT0hZ52RcHy5CR8AmuT3-y_epB_9ZUj_t87IRkLWPSl-ew9qwuJzEXxNQf4uWivy2e7a4wpbI97GyY6gtEzD0gC15GUYutcqcFkJ2_P__bqatqRL_261joBq5hC8ueN_nqQUhxFqL9sA5TdjfLOjqxQdEpM5ra7oHT6oyCYMa0hto1NnkNXOXL_dzr8hWtf_v0n4P9tuhIl40P7EAz-zlb1fBI1gXeS3mnUY6GpGVs9eFNaVkArHae9dcfIHxF6D-UVIV1rWQlxct_TBSnQX9aKdVtT6c2sZyRi8USH-j3kDpfbTt-0tybr5QO2160qk2NNtgA46iCqiJCYsg","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100297724&apid=beans_13819&impid=0d2bdf54327be366e_0_0&at=1&mkey=0d2bdf54327be366e_0_0&latcy=4495&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=3212.796875&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3D5qBdtKaNqQu%2B1StuvWhg1bTiufW09KkoCe3PelKPHd3vc1aPmvmogP9p58TjFbR7NQAUUDrWHWy0UpZJGyKsQ2fp8dUrchbq27QY7mFf8MSuM9MrG7lkqWPTTMPKFh6qxN7d5Sx7h7sQzHZ9kwDo7HF1I4opfjwqPKDGmlTr55MIj5GgUrUSCbS1ffDp%2FW3vRpKc%2F67yHrE8T7JO6gKXiYoAbF%2BdbUA5Orl5lyNuzWRnZRgUt5oRw9pIl5Au3L9YwToVunSkN%2BvVGq7qAeGEn%2BD5otH3UT4fTkfcf9OImYOt69HhakNMGlK1urjjFDV%2Bv54ylGVP7A8t3mTQfl%2Fl%2FOmXSWcwX52yRA7owMfDd4VeYhhKVbvs0hlIUw3C86KCfcxaguk8n1251jQ4btnbWOIG2JENVvFmsIDet4gXDFx7iqDmFEg8KQCD%2BO3vuExW7WYEVudcHFle%2F%2Fa0%2BGQTVWHsiXvB8DTN8Wv%2FffU%2BwCRyGle%2BB8%2Blz8MAUlk1Xt9s2xLoFptXVvJP3Lr4dMXB7wsWQS%2FdubIR1NZI40YV1wuzDYy%2BKl2ImmVdqYNUb1ZD%09tt2%3D1523791942456%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=5243363099138&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942747","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938185_8482904568112&itemspaceid=12425&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938185&cnid=228343489,228346690,228318835,228345535,228323224,228336823","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"http://sr.symcd.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBR0JBRnBp%2F14Jg%2FXj4aa6BlKlQVdQQUAVmr5906C1mmZGPWzyAHV9WR52oCEAI1kyIO4cO7gCOaDqCOX%2BSiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.google.com.pk/","request_url":"https://www.google.com.pk/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/recaptcha_challenge-vflrcf67y.css","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/px.gif?ch=1&rn=1","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://sb.scorecardresearch.com/p2?c1=2&c2=13765216&c3=&c4=https%3A%2F%2Fm.vk.com%2F&c5=&c9=https%3A%2F%2Fm.vk.com%2F&c15=&cv=2.0&cj=1&rn=74200331","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.adsafeprotected.com/mon?anId=928108&campId=1x2&pubId=38386957&chanId=52063237&placementId=4640152498&pubCreative=138230533951&pubOrder=237199237&cb=185240709&custom=bnr_atf_01&custom2=&custom3=&adsafe_par&impId=&adsafe_url=https%3A%2F%2Fwww.cnn.com%2F&adsafe_type=abcedfq&adsafe_jsinfo=,id:3e804f8a-8ce8-5c2f-4eaf-599092bc7429,c:9OXUUW,sl:outOfView,em:true,fr:true,mn:app25sje,pt:1-5-15,wc:0.0.360.512,ac:0.0.0.0,am:i,cc:0.0.0.0,piv:0,obst:0,th:0,reas:l,cmps:1,br:c,fv:0,bv:na,dm:na,abv:na,an:n,fm:qPhNtcp+11|12|13|14|1511|1512|151311|151312|151313|151314|151315|151316|151317|151318|151319|15131a|15131b|15131c|15131d|15131e|15131f|15131g|15131h|15131i|15131j|15131k|15131l|1514|16|17|18*.928108|181|191|1a|1b1|1b21|1b31|1b4|1c|1d|1e1|1e2|1f|1g,idMap:18*,pl:,rt:1,cb:0,th:0,es:0,sa:1,sc:1,ha:1,fif:1,gm:1,uf:0,tt:jload,et:4799,oid:891798ed-40a0-11e8-a7ce-00259086ca10,v:17.4.90,sp:1,ct:12395,dtm:i,gtpl:0,wr:360.512,sr:360.512,mst:4612,ov:0","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://smetrics.cnn.com/b/ss/cnn-adbp-domestic/1/H.26.1/s15371146183716?AQB=1&ndh=1&t=15%2F3%2F2018%204%3A31%3A38%200%20420&fid=4BEA7D18C905084D-3799DBF4B8681903&ce=UTF-8&ns=cnn&pageName=cnn%3Ain%3A%2F&g=https%3A%2F%2Fwww.cnn.com%2F&cc=USD&ch=cnn%20homepage&server=cnn.com&events=event29&c5=nvs&v5=D%3Dc5&c8=new%3A1&v8=D%3Dc8&c9=nvs&v9=D%3Dc9&c13=section&v13=D%3Dc13&c17=anonymous&v17=D%3Dc17&v22=0&c26=www.cnn.com%2F&v26=D%3DpageName&v27=D%3Dch&c28=cnn%20homepage%3Anvs&v28=D%3Dc28&v29=cnn.com&c30=cnn%20domestic&v30=D%3Dc30&c32=adbp%3Aindex&v32=D%3Dc32&c33=adbp%3Anone&v33=D%3Dc33&c35=cnn.24.1-0-0.20180329%3A0&v35=D%3Dc35&v36=L6N62llA&c37=smartphone&v37=D%3Dc37&c44=6d78b411-8e49-4487-b09e-f10ac0f8f8ed%3Bfalse&v44=D%3Dc44&c46=1523791858448543148946430&v46=D%3Dc46&c47=5ad337f701115d0a3c732e5b38006d32&v47=D%3Dc47&c56=portrait&v56=D%3Dc56&c57=no%20mvpd%20set&v57=D%3Dc57&c59=no%20mvpd%20set&v59=D%3Dc59&c64=cnn%20news&v64=D%3Dc64&c65=nvs&c73=2d699bfd851d2aaf-600001710000d60d&v73=D%3Dc73&c75=nvs&v75=D%3Dc75&h1=news%7Ccnn%7Ccnn%20domestic%7Ccnn.com%7Ccnn%20homepage%7Ccnn%20homepage%3Anvs&l1=D%3Dc65&l2=&pe=lnk_o&pev2=sourcepoint&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://tags.bluekai.com/site/2981?id=&google_gid=CAESEG3Dxv6TOCUdN4zUeUzcwIc&google_cver=1","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=30064&dpuuid=2pqm7XDJyuFo7kDB6GUzLGJy_H_i9MGbrOcMcYoLG7C0","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-fb.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/microsoft-powerpoint-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/wonmiao/albumset/16224401/zoomcrop/75x75.jpg?v=1523527572","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/canonical_car.png","request_type":"image"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/Overwatch-429x572.jpg","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/sports/transform/310/w710h400/20180415/ioAh-fytnfyp5169769.jpg/w710h400z1l50t1db0.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/ent/310/w710h400/20180415/FjbI-fzcyxmv0025008.jpg/w710h400z1l50t16c0.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=3773293211,3909347333&fm=173&app=25&f=JPEG?w=218&h=146&s=F3A49D40D278478EB6108890030040AB","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/digital/video/placement/Gateway/Evergreen/Mobile/DE_EvergreenHero_X-Site_Superhero_1242x450_SFT_v2._SX414_CB486792589_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/31uzIgVilQL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://rpt.cedexis.com/f1/_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17000/1/0/315/1523791935.dop006.sj3.t%2C1523791935.cds016.sj3.shn%2C1523791936.dop006.sj3.t%2C1523791936.cds034.sj3.c/0","request_type":"text"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/react/index/components/rebrand_footer_plane.min-vflu0Ptb7.js","request_type":"script"}
+{"origin":"http://www.office.com/","request_url":"https://mem.gfx.ms/me/MeControl/9.18088.0/en-US/meCore.min.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spad.i-mobile.co.jp/script/adcore_sp_inline-0.2.js?20110201","request_type":"script"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/native/impress?52379=Y2FsbGJhY2s9c2F4X2pzb25wQ2FsbGJhY2tfMSZhZHVuaXRfaWQ9UERQUzAwMDAwMDA1Nzc3OCZwYWdlX3VybD1odHRwcyUzQSUyRiUyRnNpbmEuY24lMkYlM0Zmcm9tJTNEd2ViJnRpbWVzdGFtcD0xNTIzNzkxODI1MjM3JnJvdGF0ZV9jb3VudD03NjAmYW09JTdCJTIyZHMlMjIlM0ElMjIzNjAqNTEyJTIyJTJDJTIyb3YlMjIlM0ElMjJhbmRyb2lkJTIyJTdEJm5ldD1udWxs","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://cdn.tsyndicate.com/sdk/v1/b.b.js","request_type":"script"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://a3.espncdn.com/combiner/i?img=/photo/2018/0408/r353722_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://adservice.google.com/ddm/fls/i/src=4954221;type=gl-nmh;cat=dcmgl0;u1=US;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=2789806431025.7275;_dc_1=1;~oref=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Df1fdc59c-9452-4167-a583-cc8ede9a2929","request_type":"html"}
+{"origin":"http://www.blogspot.com/","request_url":"https://www.blogger.com/","request_type":"html"}
+{"origin":"http://www.google.com.tr/","request_url":"http://www.google.com.tr/","request_type":"html"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.google.com.au/gen_204?atyp=i&ct=ppm&cad=&lids=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi&ids=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc&am=gEXyM95DDkHGRjEhGYy_AAo4ERA&k=xjs.qs.en_US.OeOVYA94wZw.O&ei=DjjTWvfeGYaB8AOat73oBA&zx=1523791888293","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://yj.p.adnxs.com/seg?add=4511230&external_uid=93625819-cbf4-4733-ba3b-11ac4270c753&t=2&redir=https%3A%2F%2Fyj.p.adnxs.com%2Fmapuid%3Fmember%3D3663%26user%3D93625819-cbf4-4733-ba3b-11ac4270c753","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://cookiex.ngd.yahoo.com/v2/cexposer/SIG=11lum9jej/*https%3A//www.tumblr.com/yahoo_cookie_receiver.html","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log/ux_analytics","request_type":"text"}
+{"origin":"http://www.amazon.in/","request_url":"http://www.amazon.in/","request_type":"html"}
+{"origin":"http://www.google.co.jp/","request_url":"https://www.google.co.jp/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=RMhBfe/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi,sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFSijRVXB7Xh2Mqo9vXGhftK9ZAxA","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdns.gigya.com/js/gigya.js?apiKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC","request_type":"script"}
+{"origin":"http://www.wordpress.com/","request_url":"https://snap.licdn.com/li.lms-analytics/insight.min.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770856&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523791989674&fs=4&pvid=ade72ed46af0ccae0f4d6bcdda1fb86a&cg=af19bece926e5ddbd1f75656de795de9","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://pub.pxl.ace.advertising.com/cfcm.ashx?providerId=1008&extMatch=1&rcode=1","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://fls-eu.amazon.de/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/index/components/rebrand_creation-vflJIWsBR.css","request_type":"css"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/css/font_sharp_grotesk-vfl1d5hYC.css","request_type":"css"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/redesign/0.391.46/css/page.css","request_type":"css"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=aolvideo.com&id=e5edde57b967b80987ca4b2c38724aa4bf38f15e","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=28&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A28%7D&logFlag=uaction_1523791857874&t=1523791885876","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=58d57c97-9f20-818f-ba5b-1328f195c2a4","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://trc.taboola.com/msn-msn-home/log/3/available?ri=0adbeca5d888c6b0de6e6302179561ed&sd=v2_a839064e4dc128f89e336e1585d06e96_39041E2B94ED6EF00CB315F995BE6F73_1523791842_1523791842_CIi3jgYQy9c-GMWRycisLCABKAUw4QE&ui=39041E2B94ED6EF00CB315F995BE6F73&pi=/&wi=6400712663452445953&pt=home&vi=1523791841477&li=rbox-h2m&utm=16%2C1005%2C1223%2C1981&mgo=1&df=1&tim=04%3A30%3A42.849&id=677&llvl=1&cv=301-1-RELEASE&fil=%5B%7B%22tii%22%3A%22%7E%7EV1%7E%7E2941817511074997885%7E%7Ey8vGgWplPeomoWV4Zs8XWWxRL4hnm9sfUfn_pkHOa2USO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT5YZVzyM3_sqdzWJ-OVLWMZMRcC1HUqLKGzVuQ0uTpxX3kjgZ-VSqH9qM20zEbbygaowzPcwqce1nMGnTHPSM2yI-SxCVCqgvz6_dfQm-Jd117LfaJSyi-7Q75WaWtbzndxU938uwE_FZuuE6QkcKnKe9ai2ANFMgxbNzFLyjdKe%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22photo%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E197665741990824324%7E%7EkQyDJopeIQb-UkkrdqSjTi1qeMS8Yj8EHGkpOWe5qnMgADLX0sCLI84lvxeYoNVBXtEiVLHvk6BFwXvQihx-5qElbYrjiyMVGBi3i_wpDzEpuYbO4mp4jIt_6yTY2U15pD3waL8acz03BZ55sL8vKoaSrV13DrUfn2g2GGwP38xunB4XuVe0-mCDYb6GLhdaOE8lX5ohuqaktbVOqRtTMbfpCBIcwxhGdYAYhZm5wPbxm3vsLv4PHg0RURsDiXHF%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E-6404010561096418818%7E%7EMTh0BIIciOa-iLKZFNtWX05b1-NDFii4FGqU8azmnXESO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT52s0By_DdF9FMP0graI91BMRcC1HUqLKGzVuQ0uTpxX3kjgZ-VSqH9qM20zEbbygaowzPcwqce1nMGnTHPSM2wblMaVGSSuXJjTVn8gJaL0Y9jCwuaWWPF5TECMkxtQk1vFq5znoocy2C7MaM6KK7me9ai2ANFMgxbNzFLyjdKe%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%5D&","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/evernote-android.png:l","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/somewhere-android.png:l","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=mediamath&google_hm=xD1a0zFJSACod7fYAp6xiQ","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/favicons.png?v=3","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/wapchezhijia_1219.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.gstatic.com/recaptcha/api2/info_black.png","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201312/28/21358441/original/(m=eafTGgaaaa)(mh=EMd2xjgssi8zFh5y)12.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/wzyqk/qdj/201804/W020180413525570031307.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201804/04/160837202/original/(m=eafTGgaaaa)(mh=LSmtu1D6dHdup_kW)2.jpg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/media/motion/2018/0412/dm_180412_WNBA_Draft_first_pick/dm_180412_WNBA_Draft_first_pick.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/4545000/4545027/220x165/2.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://a.thumbs.redditmedia.com/eUG_GiXeo03hMO3I6c-HR9UTMx3at3q4_qR02gsqYE8.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/61q9-pQXAWL._AC_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s720x352_jfs/t18553/216/1490015765/114927/5e96d7bc/5acc94a8N70fa383b.jpg!cr_1125x549_0_72!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/n1/s124x124_jfs/t3244/32/3963048280/146422/406f27e2/57fd9dc3Na880c8cb.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/W7oAAOSwB1Jaz2ZA/s-l225.webp","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t015ac2f5c43c598bc1.webp?size=500x253","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/tpl2/vr-badge.svg","request_type":"image"}
+{"origin":"http://www.twitter.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://tags.bluekai.com/site/56802?ret=js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://mab.chartbeat.com/mab_strategy/headline_testing/get_strategy/?host=cnn.com&domain=cnn.com&path=%2F","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/digitalassets/c/paypal-ui/fonts/PayPalSansBig-Light.woff2","request_type":"font"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-mcl-icons.min-vfl0diaA6.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/ape-pipe-0.0.65/af-pipe/af-pipe-min.js","request_type":"script"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2751/td-applet-viewer-templates-lightbox_lead_mega/td-applet-viewer-templates-lightbox_lead_mega-min.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://cdn1d-static-shared.phncdn.com/mg_utils-1.0.0.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-36f20cfcd79/v3/js/skins/min/default.footer.static.js","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/font/roboto-medium-webfont-1f990.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/ads/cnn/singles/cnn_homepage_rb.js","request_type":"script"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/57c0f912006fed6af5e8ad35652688fa.js?conditionId0=422975","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ssl.cdn.turner.com/ads/adfuel/modules/keypress.js","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/swiper_4bb3bcc.js","request_type":"script"}
+{"origin":"http://www.alipay.com/","request_url":"https://a.alipayobjects.com/g/animajs/mtracker/3.1.0/seed.js","request_type":"script"}
+{"origin":"http://www.instagram.com/","request_url":"https://www.instagram.com/static/images/ico/favicon.ico/dfa85bb1fd63.ico","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.unid.go.com/inner/?v=4.0.43","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/pagead/gen_204?id=sodar&v=24&t=2&bgai=BTgEFATjTWtCzO83WkgPUxoKQBAAAAAA4AeAEAg&bg=!h4SlhJxEteuvCpij4wUCAAABpFIAAALQmQGHFR4kP7bMSYFWNBSlcJhPf51heCo0BTaeRUZxsAyFqvHMQ9YCB4-Jdt60fRDvcZZEU1RyDW4LP68-HxuKg-IOFMYo8YID6C15vvzx9Cl3VGdQvkb1HzfEWpj2T7zZkd_8un6ZeencNUU88qiscHE1flKfs4dN3djD-S1s3TMc_Hyj1kyRCohogiBEaMhfwvIr3VCg1SYQVtkFZ1xEGbpvGMi0R_uFPjgRwV9BvN4Uy4PDTh_5mdCCf2bYFBQA0D80TC2p_eNdeDG85ZXjEw5pzI283KKaCWg4UL2MZpDYPlkBxZUbqXQenY9YU5yBT263EMTjsF4IaSYhrRYI5tC9AnrgVNdLBgrarDLdgp75TL-dTw7waeFkRbBSUqyCBRwL4CSIje6_71SQx8cZsDvgm4E63VP-JUhd4TkBDU4t1NoD9g9apj5y3W6dDnruJtsOyKp3inUwhJ2L1vFG0hPl4Ca24SamJrYTh5uV5e-woOZegln6GrxbNbMvi9Y4afTRGaZUv7zU_g","request_type":"html"}
+{"origin":"http://www.youth.cn/","request_url":"http://cm.g.doubleclick.net/pixel?google_nid=baidu&google_cm","request_type":"html"}
+{"origin":"http://www.tmall.com/","request_url":"https://h5api.m.tmall.com/h5/mtop.taobao.baichuan.smb.get/1.0/?jsv=2.4.3&appKey=12574478&t=1523791823659&sign=970aa63436f78b76c8fd5b5ce054e379&api=mtop.taobao.baichuan.smb.get&v=1.0&type=originaljson&dataType=jsonp&timeout=10000","request_type":"html"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.google.co.uk/gen_204?atyp=csi&ei=CjjTWqbWH8rT0gKEqqpA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.415,dcl.532,iml.415,ol.3025,prt.383,xjs.1940,xjsee.1940,xjses.1581,xjsls.408,wsrt.2185,cst.703,dnst.0,rqst.846,rspt.452,sslt.375,rqstt.1710,unt.2125,cstt.1001,dit.2717&zx=1523791885861","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=&apid=beans_12423&impid=&at=1&mkey=&latcy=3070&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=9582837115812&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&source=0&_time_=1523791941246","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938128_5738343206446&itemspaceid=12416&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938128&cnid=228342282,228341275,228321989,228324585,228318314,228330771","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938272_6731044119691&itemspaceid=12290&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938272&plateid=1003000000,1004300000","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/alternate_wtl","request_type":"text"}
+{"origin":"http://www.google.ca/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/xjs/_/js/k=xjs.qs.en_US.OeOVYA94wZw.O/m=sb_wiz,aa,abd,async,dvl,foot,ipv6,mu,sonic,d3l,udlg,rQSi2,iP7ptb,if1iFc,yQ43ff,ws9Tlc,uz938c,xpltpb,Fkg7bd,vWNDde,kopZwe,czrJpf,QfiAub,wI7Sfc,HcFEGb,L1AAkb,xPR7tc,y8zIvc,opNw3,Uox2uf,dtPt4d,CiVnBc/am=gEXyMoZDDkHGRjEhGYy_AAo4ERA/exm=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHU8HEAkCh-aMUsm8MIvLVSTjLj3A?xjs=s1","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://at.atwola.com/bind?ckey1=ATTACID;cvalue1=kvtid=UP3f8e855a-40a0-11e8-aa25-06b4b18950f6;cbase64enc1=1;ckey2=APID;cvalue2=UP3f8e855a-40a0-11e8-aa25-06b4b18950f6;apidSync=1;expiresDays=366","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://adobe-sync.dotomi.com/adobe/match?dtm_test=7d4e17a3acc08ff&nuid=86070857378125119120981354726841823876&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=openx.com&id=89558f3d-d4a7-ceda-1ca9-281d71b739be","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://s.amazon-adsystem.com/ecm3?id=+RrouGEbbdTIAxJc2M7Y9MWWwYjZzChgQG1x/JmYjWc=&ex=rubiconproject.com&status=ok","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=openx.com&id=f82c8cc5-f532-ce94-1318-c4991d3c90ed","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-53389718-12&cid=31773146.1523791847&jid=1227979929&_v=j46&z=1872806","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/icons/icon_spacer-vflN3BYt2.gif","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://p.skimresources.com/?provider_id=39041E2B94ED6EF00CB315F995BE6F73&skim_mapping=true","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.facebook.com/fr/b.php?p=1531105787105294&e=WtM4gQAABibm4O17&t=2592000&o=0","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/ads/user-lists/971301452/?random=1523791866950&cv=9&fst=1523790000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&gtm=G46&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=1334750719&resp=GooglemKTybQhCsO&rmt_tld=0&ipr=y","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://limg.imgsmail.ru/touchsplash/v/i/sign-aquarius@x2-a9cadddc43.png","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/xxl/201804/W020180420347978306245.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/5R8IjxFf2Aatn2ivlRCWDWkRI04nNgpap0dUyMzVAeiWlvsDAIxHZIu-t3NpHg4=w192","request_type":"image"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yN/r/Y8VrvG-1crh.png","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_4,y_16,w_800,h_533/os/news/35ce4d2e6feb6ba0529eee111d4e3354.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://tr.outbrain.com/pixel?marketerId=00f0f5287433c2851cc0cb917c7ff0465e&obApiVersion=1.0.4&name=PAGE_VIEW&dl=https%3A%2F%2Fwordpress.com%2F&bust=0670437474071371","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s220x220_jfs/t13519/289/570849623/290501/37fcc600/5a0e9a16N55e43e87.jpg!q70.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/8c/72/19/8c7219990af31f231551947aa047f4f1/8c7219990af31f231551947aa047f4f1.18.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s9.pimg.tw/album/cschan10583/element/708031859_1523626252-84600944/zoomcrop/90x65.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/e5/eb/c0/e5ebc0219a25ac395028b53e0c183f73/e5ebc0219a25ac395028b53e0c183f73.8.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/gmrbweixinkhd.jpg","request_type":"image"}
+{"origin":"http://www.reddit.com/","request_url":"https://b.thumbs.redditmedia.com/CP9hzIJ4W3A18ggi6tesw8NKJL2pQd-HBW7HtFswaiA.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/Digital_Video/GW_HERO/GW_MobileBillboard_GhostInTheShell_1242x450_NonPrime._SX414_CB486961678_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/subscribe_save/gw/mobile/1049516_gw_mobilebillboard_02_1242x450._SX414_CB507792628_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/71mi0QkRETL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/51g4qr8fBNL._AC_SY600_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/02/digital/video/merch2016/mobile/GW_Mob_Evergreen_1242x450_FT._SX414_CB502575189_.jpg","request_type":"image"}
+{"origin":"http://www.google.com.au/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/promo-banner.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/static/fonts/roboto/roboto-medium.woff","request_type":"font"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/01ekIXTj5kL._RC%7C01j62IBqyaL.css,41wvsvL+sxL.css,31-8Mn1M1oL.css,31ZYydvXTIL.css,11tkAOwE6OL.css,21xItms32EL.css,11q7D6YoQCL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,01kwuiPOKIL.css,41SYzOsGaLL.css,017SKMFW8lL.css,21QwDiO8ycL.css,01IHzhAZ28L.css,31no24Dqj1L.css,01wBE2Z+USL.css,11ZLLOcO8BL.css,01D-B-OeNDL.css,21CNSKZ67ML.css,11rhPo030XL.css,11G8UP3P7ML.css,51oAYplAOyL.css,21LCBYGBqCL.css,21lDMA2J74L.css,31ka0STwoDL.css,21thLxrpr2L.css,11P7nJr8UuL.css,012dCODns-L.css,11oH9gtOgDL.css,21ZKosCj0iL.css,313bzSzzhRL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21Df5N8kF4L.css,61lDBjn6HPL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,01QRe-mUhyL.css,31LBzl8T3vL.css,21DFs8eEV-L.css,11cAYJlTEgL.css,018mGORJ7tL.css,11fvu+DzMxL.css,11iDQvZvByL.css,01lh9w-GYYL.css,11Mso4bvY-L.css,01LCsoCesOL.css,11Y-grr95dL.css,010kw0xkZfL.css,21pnh6VHUzL.css,11qL99m7IWL.css,01839NKfnVL.css,01YXqSisf3L.css_.css?AUIClients/DetailPageMobileWebMetaAsset","request_type":"css"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://www.amazon.co.uk/gp/gw/ajax/card.html/262-9616072-1847409?ie=UTF8&opf_redir=1&rshVal=1523791862828","request_type":"html"}
+{"origin":"http://www.yahoo.com/","request_url":"https://www.yahoo.com/","request_type":"html"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/gen_204?atyp=csi&ei=HzjTWsvkNuGX0gKXxZi4Bw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.373,dcl.332,iml.373,ol.2682,prt.214,xjs.1544,xjsee.1542,xjses.1320,xjsls.224,wsrt.2130,cst.674,dnst.0,rqst.769,rspt.386,sslt.366,rqstt.1639,unt.2032,cstt.965,dit.2461&zx=1523791906916","request_type":"html"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/iu3?d=imdb.com&a1=&a2=0101984209483bd8c7c1016806edc8a14899e1e6726d95448da1cea28358af825a8a&cb=332843615559&pId=&r=1&rP=https%3A%2F%2Fm.imdb.com%2F&encoding=server","request_type":"html"}
+{"origin":"http://www.amazon.in/","request_url":"https://usermatch.krxd.net/um/v2?partner=amzn","request_type":"other"}
+{"origin":"http://www.amazon.in/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/id?d_visid_ver=2.5.0&d_fieldgroup=MC&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=9E1005A551ED61CA0A490D45%40AdobeOrg&d_nsid=0&ts=1523791992949","request_type":"other"}
+{"origin":"http://www.diply.com/","request_url":"http://diply.com/gizmo/scss/src/components/main.min.css?v=l5aQa8Bjs0thUwPg1e4IpfRqO6RnfI-XDYgp1LP997c","request_type":"css"}
+{"origin":"http://www.msn.com/","request_url":"https://ping.chartbeat.net/ping?h=en-us.msn.com&p=%2Fen-us&u=B3yH7RDGDi2CDqetp4&d=msn.com&g=42635&g0=homepage&n=1&f=00001&c=0&x=0&m=0&y=7350&o=360&w=512&j=45&R=1&W=0&I=0&E=0&e=0&r=&b=6235&t=D5EUUvBPXgiBDcV24cCFYn3IBA4X1d&V=103&i=MSN%20%7C%20Outlook%2C%20Office%2C%20Skype%2C%20Bing%2C%20Breaking%20News%2C%20and%20Latest%20Videos&tz=420&_cdname=westus&sn=1&sv=Cb8I53TfdwSBCtfTICZtkOWDIf3Vo&sd=1&im=06032ff0&_","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=xIHHyNB2xlik&ex=pulsepoint.com&ev=&pid=557477","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a671d6100015ad3387e3b6a70c073d3&pid=mm_113716014_12970037_52768233&cid=264978&mid=2582&oid=151&productType=1&qytInfoMTime=1523728959&cb=501551015","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/shadow_x.gif","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://benchmark.1e100cdn.net/r20.gif?rnd=0-1-13960-0-0-32430-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://www.google.com/ads/user-lists/1063929773/?userId=SBrLLYJkShGT4YAgqXAH6A&guid=ON&script=0&cdct=2&is_vtc=1&random=687886736","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/instagram-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/nasa-logo.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/27/7ACC79.png","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/img/after-video-download/popup-close.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/aso092201/albumset/15919701/zoomcrop/75x75.jpg?v=1523785696","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/images/code_gmrbfrwb_s.png","request_type":"image"}
+{"origin":"http://www.alipay.com/","request_url":"https://m.alipay.com/?from=pc","request_type":"html"}
+{"origin":"http://www.weibo.com/","request_url":"https://passport.weibo.cn/favicon.ico","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"http://m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201711/30/143425182/thumbs_5/(m=eafTGgaaaa)(mh=HVpMaN3KSeZyb4g7)14.jpg","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://img.revcontent.com/?url=https://revcontent-p0.s3.amazonaws.com/content/images/15204082911045909745.jpg&static=true&pos=face&h=315&w=420&static=true&fmt=jpeg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/81l6zbSjSzL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=834980672190&photoType=4","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t0122f29f53719a2d31.webp?size=640x905","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://rtax.criteo.com/delivery/rta/rta.js?netId=4606&cookieName=crtg_rta&rnd=40064439507&varName=crtg_content","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://i2-ioqzhtqexjvyudqpsczwuydfwxmlbh.init.cedexis-radar.net/i2/1/13960/j1/20/74/1523791929/providers.json?imagesok=1&n=1&p=1&r=1&t=0","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/sc/2e/1b13ea.woff2","request_type":"font"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/footer.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/premium/premium-modals.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-core.min-vflGry986.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/yR/l/0,cross/nWgMAYdcako.css","request_type":"css"}
+{"origin":"http://www.jd.com/","request_url":"http://wl.jd.com/unify.min.js","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ir.ebaystatic.com/rs/c/inception-3375a9.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://m.media-amazon.com/images/G/01/csm/showads.v2.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100282154&apid=beans_13784&impid=0ccdae08017e50a7f_0_0&at=1&mkey=0ccdae08017e50a7f_0_0&latcy=3800&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=6824.890625&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DkJbwAkGnJIlpmQ4r%2F0bctqRUT5E69XL%2Bd2jzP3rOcSUeTgddgCaGnt2imVsZif4U4CgT%2BlCwKe8l7f34zstZQwEPF9DzfvIItoXmym%2B3ur3zyndfbSx0bHsXrAfZeTNKTBh5%2FfsbCyMZsC%2BdKUmhsmJen%2BiqJoeZX7vX%2BRuWk7prmFPfegMoQ65mOHqXEPoNqLmh6616HNX1iqXB8Ww%2FE0koNcXHYjE0YBjNpaYwi0tHtqxD%2BKoN4YhFfc8wGTZqAeA0pUlhMkPwEoIou2OOvKxgLx2DSbRy20A%2BdqxbuvQeCBFPzhSJMZ6%2Ftdl5TkR3lTwLhnR4lZxHE7oWjic6rXslGIaOHYSRB8CQRvxX0mvNGHPg1TdRrCA6g8b3CSWoOWMhF1Yh34DH%2BL4nUtNUxViauwEZVcWpD1eNhcWdZ2%2Bo7crApmvQsiQ5LxnsaZ7k2Pm%2FxrlHdjnvRtBbeftVYg5pN64MV%2FGyOg%2BdO9%2B9eQNMsp%2FazeG8vbfRXRNIgTRe6aRDVn0BoHd70Jpl7j6Y9DlzznNa3hx2ncdYPtDfLXd%2BHRyBZAoS2PMkwP2wRYM%2BeXvVSi2jJlmSSCPoNVC7ggv91PO3joVVFl26I%2B1En4o%3D%09tt2%3D1523791940800%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=3686403715693&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791941980","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://simage4.pubmatic.com/AdServer/SPug?partnerID=156011","request_type":"text"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/hao123_api/page/getRootData?vit=h123&from=3w123","request_type":"script"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.googleadservices.com/pagead/conversion.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9212291508&puid=g9e51602ae03bce4bdfa","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://fls-eu.amazon.co.uk/1/batch/1/OE/","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://www.facebook.com/tr/?id=1944925959056690&ev=Microdata&dl=https%3A%2F%2Fwww.adobe.com%2F&rl=&if=false&ts=1523792017790&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22Adobe%3A%20Creative%2C%20marketing%20and%20document%20management%20solutions%22%2C%22meta%3Adescription%22%3A%22Adobe%20is%20changing%20the%20world%20through%20digital%20experiences.%20We%20help%20our%20customers%20create%2C%20deliver%20and%20optimize%20content%20and%20applications.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.12&r=stable&ec=1&o=30&it=1523792015787","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsv3XSuci98EX9wC0CecGDTnm7EvV3BCjfjVkbXKkq7XuLQ0lQncECpqc1pWd-vqSIrj8oBESoA7L_jebXLWS8bFpN8N3is3sLU&sig=Cg0ArKJSzOp0wZlxYTNqEAE&id=osdim&ti=1&adk=1002300037&tt=11092&bs=360,512&mtos=1182,1182,1182,1182,1182&tos=1182,0,0,0,0&p=114,20,164,340&mcvt=1182&rs=3&ht=0&tfs=9908&tls=11090&mc=1&lte=1&bas=0&bac=0&avms=geo&bos=360,512&ps=360,8320&ss=360,512&pt=-1&deb=1-0-2-16-21--1-11-19&tvt=8460&op=1&r=v&uc=8&tgt=DIV&cl=1&lop=1&tslp=606&cec=1&clc=1&cac=0&cd=320x54&v=r20180411","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d20915561.gif?sz=3&rnd=784703839&ts=1523791836&sz=3","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/p?s=2080377422&t=VJBf8jeZeDeuhbUyjg0qdt7u,0.6818521277596461&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-7%04A_sid%03lHDp6MRWIjCVA6cqjg0qdpah%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031523791949%04viewtime%03%2Bsearch%3A5~1523791948.370%2Bstream%3A6%231523791945.603%2Bstream%3A6~1523791948.370%2Bstream%3A7%231523791945.603%2Bstream%3A7~1523791948.370%2Bstream%3A8%231523791945.603%2Bstream%3A8~1523791948.370%2Bstream%3A9%231523791945.603%2Bstream%3A9~1523791948.370%2BheaderBody%3A5%231523791948.383%2BheaderBody%3A6%231523791948.383%04_E%03l_viewtime","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/hp-wus/sc/9b/e151e5.gif","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"https://certify.alexametrics.com/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Diply&time=1523791963405&time_zone_offset=420&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fdiply.com%2F&random_number=16531591799&sess_cookie=863c94c5162c91425093f000a16&sess_cookie_flag=1&user_cookie=863c94c5162c91425093f000a16&user_cookie_flag=1&dynamic=true&domain=diply.com&account=PA4wi1asyr00gj&jsv=20130128&user_lang=en-US","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://ads.yieldmo.com/v000/sync?userid=ad268718-6d81-467d-ac23-c26c6cc49e0e&pn_id=b","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://www.xnxx.com/favicon-16x16.png","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://www.xvideos.com/favicon-32x32.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/img/3C/86664F.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/tps/TB1RN0HMFXXXXXNXpXXXXXXXXXX-183-129.png?imgtag=avatar","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=b60eac03-40a0-11e8-b967-024257f42601%252Chttps%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253Db60eac03-40a0-11e8-b967-024257f42601","request_type":"html"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://k.sinaimg.cn/n/ent/310/w710h400/20180415/017k-fzcyxmu9944480.jpg/w710h400z1l50t1f60.jpg?by=comos","request_type":"image"}
+{"origin":"http://www.msn.com/","request_url":"https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAvSWSQ.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=543&y=316","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius3.bongacams.com/live/037/02c/1e7/big_lq/73d35a629f532ad24fcda27cab231e9a.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f18/8a490b52373c5df2c279a6ac108aa7f5_erotic_285x160.jpg?cno=3a57","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://643108e7617ef.cdn.sohucs.com/bd66c44ceaac467781ab47e6f580d90a.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s3.yimg.com/lo/api/res/1.2/qrKjr.Kco1QjBIXhZY72cw--/YXBwaWQ9eW15O3c9NjA-/https://ct.yimg.com/cy/4597/27531755179_dfca42_192sq.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/61N6V2GDTAL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/images/g/My8AAOSwNq5Zi0xC/s-l225.webp","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1K9tEQVXXXXauaXXXXXXXXXXX-1035-500.png_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/71aae27c-ad3b-4e04-8d82-463fe510d833/scale-to-width-down/366","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/icons/upload.svg","request_type":"image"}
+{"origin":"http://www.google.co.uk/","request_url":"https://www.gstatic.com/navigationdrawer/home_icon.svg","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://310987714.log.optimizely.com/event?a=310987714&d=310987714&y=false&src=js&s310954789=none&s311043393=true&s311047346=gc&s311052307=direct&s793783561=true&s806111078=none&s806950111=mobile&tsent=1523792030.783&n=http%3A%2F%2Fwww.espn.com%2F&u=oeu1523792025971r0.47098347521900563&wxhr=true&time=1523792030.783&f=8448890495,9262875135,9263073801,8792134866,8483651062&g=&cx2=2307eec2","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mtb/lib-smb-wake/0.0.42/wake.js","request_type":"script"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/scripts/ac-globalnav.built.js","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spad.i-mobile.co.jp/script/adssp.js?20110215","request_type":"script"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.google.co.uk/","request_url":"http://www.google.co.uk/","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/iu3?d=amazon.com&slot=navFooter&a2=01010f1290735014d1dc37263c3c759ba6a5871252372bcd23221999ce60d83c6b3c&old_oo=0&cb=1523791910363&dcc=t","request_type":"html"}
+{"origin":"http://www.tumblr.com/","request_url":"https://sb.scorecardresearch.com/b?c1=2&c2=15742520&ns__t=1523791926927&ns_c=UTF-8&cv=3.1m&c8=Sign%20up%20%7C%20Tumblr&c7=https%3A%2F%2Fwww.tumblr.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://m.fg8dgt.com/ul_cb/sync?ssp=bidswitch&bidswitch_ssp_id=pubmatic","request_type":"other"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com%26","request_type":"other"}
+{"origin":"http://www.popads.net/","request_url":"https://www.popads.net/css/scambar.css?1516108355","request_type":"css"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/10101.files/css/2012_index.css?v=2015050109","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=aolvideo.com&id=3c8e39bb8c5b815eba308bf8c95253dd640d2291","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?ex=aolvideo.com&id=4cb0c6ab226a494b19d50bbe3a6991c9b07cc878","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?gmkey=EXP&spm-cnt=a2g0n.home-amp.0.0.amp&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_5%26exp_type%3Dresource_share%26exp_condition%3Dscm%3D1007.15875.97775.0%26scm_id%3D1007.15875.97775.0%26scm-url%3D1007.15875.97775.0%26pvid%3Dfd1c32f2-5e27-41ee-b6c8-5160cd465647%26exp_product%3D29937%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26st_page_id%3D8054amp-JbK9PxBGc80upnWkV7mIgQ1523791931973","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://www.amazon.de/uedata/unsticky/258-8151141-7687141/NoPageType/ntpoffrw?at&v=0.200436.0&id=49NGBMVT1ABRN6GGR916&m=1&sc=adblk_no&pc=13161&at=13161&t=1523792000006&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=49NGBMVT1ABRN6GGR916&aftb=1","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://rec.scupio.com/recweb/uxid.aspx?id=dff75162-3702-4518-b1cb-76335dbae505","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1486958744&t=pageview&_s=1&dl=https%3A%2F%2Fen.savefrom.net%2F&ul=en-us&de=UTF-8&dt=Free%20Online%20YouTube%20Downloader%3A%20Download%20YouTube%20Videos%2C%20Facebook%20and%20many%20others!&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=qGDAAAABC~&jid=1511637063&gjid=1685032153&cid=2145003528.1523791946&tid=UA-7055055-24&_gid=496215688.1523791946&_r=1&cd1=2145003528.1523791946&z=1915837740","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/assets/img/top/noimage_newsblomaga.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fcmatch.youtube.com/pixel?google_gm=AMnCDorYR6VMHu4X6-zhU5FkifJYJSRG9ozbU34cqPeTLXGmzoMZztgnwqYeD9Z6AZIPeMwSFsF7HSSTVQl7-s0VVYCUUjQ3_A","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://a.tribalfusion.com/z/i.match?p=b13&u=91191954147729940174299115411397659455&redirect=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid=22054&dpuuid=$TF_USER_ID_ENC$","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://match.adsrvr.org/track/cmb/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=35117910-40a1-11e8-a553-0242acc1cc07%252Chttps%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253D35117910-40a1-11e8-a553-0242acc1cc07","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/c1/79/53/c179530d4ed6d5b3f17cbc1e5d0ab226/c179530d4ed6d5b3f17cbc1e5d0ab226.11.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s4.pimg.tw/album/mmasm312/element/237374804_1523785353-899518828/zoomcrop/90x65.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://f10.baidu.com/it/u=3972265311,4249389268&fm=76","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/sQN6vwYTttKnnQBmRZGM4A--~B/Zmk9c3RyaW07aD00MzI7cHlvZmY9MDtxPTgwO3c9NzY4O3NtPTE7YXBwaWQ9eXRhY2h5b24-/https://media.zenfs.com/creatr-images/GLB/2018-04-14/2aa17db0-4009-11e8-922e-2f0b195abbc4_image-1717","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/61oosK63kOL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/A1tSbR5LGZL._AC_SY200_.jpg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://inews.gtimg.com/newsapp_ls/0/3274859134_294195/0?tp=webp","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://inews.gtimg.com/newsapp_ls/0/3273652995_640330/0?tp=webp","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/f039d319-7d0c-4f23-bbf3-904a0b73ca65/scale-to-height-down/100","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://pages.ebay.com/favicon.ico","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/watch/image_small.svg","request_type":"image"}
+{"origin":"http://www.google.co.in/","request_url":"https://www.gstatic.com/navigationdrawer/save_icon.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.criteo.net/js/ld/publishertag.js","request_type":"script"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://cdn.ampproject.org/v0/amp-animation-0.1.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/external/jquery_bundle/jquery_bundle.min-vflsXQkTZ.js","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_6&relatedID=&news=0_0&SUV=null&_time_=15237919573345353198922191","request_type":"script"}
+{"origin":"http://www.google.com.au/","request_url":"https://adservice.google.com.au/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.wikia.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_cm&google_nid=krux_digital&google_hm=TDZON2lpZzc%3D","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://pagead2.googlesyndication.com/pagead/s/cookie_push.html","request_type":"html"}
+{"origin":"http://www.bongacams.com/","request_url":"https://bongacams.com/","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100297535&apid=beans_13818&impid=0bc78c59c10fe0452_0_0&at=1&mkey=0bc78c59c10fe0452_0_0&latcy=4297&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=2452.734375&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DxswmM8FLjvrg7m7zYu8yrInfiMNQFba3CwMFQ5J%2B5muvqQU7EpBllNh95CKo8s6PtRFYMNY%2BOwzsr%2B8xxbp4D0gYkfl%2FweZFy0OgHpJ%2B3Pi1IQ%2Bo0q5jdW5oTtz7BBN%2FVJqWZX817j5jNzcwKcMtcbW9nxUPMYsgTlIRjB6xNZVkLTv7I5LHY9kMs96mK1h51p%2BCwn8N6u9NTxx3F2Alv2ylwnd1e1R06W4Myy3zAUlizbQUcONwVdzzvCTSx9rFrWgCbjX5NzMxGKT2qzm%2B9ypGufjB8pO9mddLmMPdcSXueBoSC2B9onEkNB2rodwAstxXFa51uy4oDG8vMOoBECXHBLxD%2FdHkJANWPU0JX0kuJs%2BfjrqlmEUyqHddQLXjgKKe5LXEurR%2F4jJFT%2FRrKQeg35PE4McZcFGs%2FqWpxd7u8xCnWQo%2BHRJso%2F%2FJI1JFn0o%2FEhoiLfm2b%2FHWuduHannG7SowB3O5qQyJXmskLE5WhuIqbDKxjuGZTjledLCfSIL6a692dBc%2FJydkkuGrSB%2FqStiWIx6bgTk1%2BJ3WTtkdIqQXBEtusGb5w9L2LtWi%09tt2%3D1523791942202%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=2778223835634&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&suv=180415193221Z74L&source=0&_time_=1523791942557","request_type":"html"}
+{"origin":"http://www.coccoc.com/","request_url":"https://www.google.com/recaptcha/api2/bframe?hl=vi&v=v1523554879111&k=6LeTvAoUAAAAADj3Cr1Onbp4OIH1gzywMUJaefT0&cb=xttha1kuyf1o","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://idsync.rlcdn.com/420486.gif?partner_uid=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://ssum-sec.casalemedia.com/usermatchredir?s=183716&cb=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dcasale%26partner_uid%3D__UID__","request_type":"html"}
+{"origin":"http://www.yahoo.com/","request_url":"https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-scroll/anim-scroll-min.js","request_type":"script"}
+{"origin":"http://www.tumblr.com/","request_url":"https://assets.tumblr.com/client/prod/app/vendor.build.js?_v=60e6027b39a60ba199412a4ea15e69c0","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://img.scupio.com/js/config/13940.js?v=1.9.22","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/css/vmobile/main.css?cache=2018041212","request_type":"css"}
+{"origin":"http://www.savefrom.net/","request_url":"https://static.inter1ads.com/templates/inapp/Custom/_gen-square-teasers-feed-new-layouts/css/style.css?v=1523281953437","request_type":"css"}
+{"origin":"http://www.amazon.in/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=bidswitch.com&id=0376a6bc912c8594da43e6fa08b75e03","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=ZGVlNDAyNGUtYTlhOS0zNDg1LTg4ZjgtNDA4MWE1ZGNlZjgzCTQ1CVBEUFMwMDAwMDAwNTgxMTgJNTAJMzUzMTk4NwkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://secure.espncdn.com/ad/blank.gif","request_type":"image"}
+{"origin":"http://www.netflix.com/","request_url":"https://www.google.com/ads/user-lists/991179584/?value=0&guid=ON&script=0&cdct=2&is_vtc=1&random=2285762456","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEyWDIxMA==/z/iH0AAOSwwzhZSpE7/$_57.PNG","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e/img/3.0/weather/weatherIcon_35.png","request_type":"image"}
+{"origin":"http://www.blogspot.com/","request_url":"https://lh3.googleusercontent.com/Br6226SyPnl0JKRaetNVksBPrakJrD3MeF_ltH6fydJ9SOpNrja5yLU2m3dAGw=w384","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.google.co.id/images/nav_logo242.png","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"http://h5.m.taobao.com/?sprefer=sypc00","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://a.tribalfusion.com/i.match?p=b13&u=91191954147729940174299115411397659455&redirect=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid=22054&dpuuid=$TF_USER_ID_ENC$","request_type":"html"}
+{"origin":"http://www.amazon.de/","request_url":"https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID","request_type":"html"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-egc.xvideos-cdn.com/videos/thumbs169ll/57/b9/26/57b9267a1dea0fa84575bd9fce926650/57b9267a1dea0fa84575bd9fce926650.20.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180415/f44d305ea1ac1c3cff3420.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://news.youth.cn/images/huiselogo_pic.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180415020123-ben-stiller-robert-de-niro-snl-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1b/bcc17f5dc7c0b3d51e5b4047328c4e7b_erotic_285x160.jpg?cno=85f","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/o_KOER0e.K_npRrBxFrdOw--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/video/video.abcnewsplus.com/798f3bde0b9ab6b1a21e72550351e899","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/pantry/AwarenessCampaigns17/2018/ganeg_2018-03-15T11-00_8bd114_1102919_DE--Amazon-Pantry-Spring_Selection_2018_1242x450._SX414_CB499147738_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41bQWuQrFXL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://sdk.appadhoc.com/ab.plus.js","request_type":"script"}
+{"origin":"http://www.youth.cn/","request_url":"http://push.zhanzhang.baidu.com/push.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-prompt.min-vflUnNVkA.js","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://static-hw.xvideos.com/v3/js/libs/jquery.min.js","request_type":"script"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.gstatic.com/og/_/ss/k=og.mob.-1rk0m4d4igny5.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTtM68hAEZE60MbYC5rX7odvcC06qA","request_type":"css"}
+{"origin":"http://www.blogspot.com/","request_url":"https://fonts.googleapis.com/css?family=Roboto+Slab:400,700,300|Roboto:400,500,700,300,900&subset=latin,greek,greek-ext,vietnamese,cyrillic-ext,latin-ext,cyrillic","request_type":"css"}
+{"origin":"http://www.mail.ru/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTExMTMmdGw9NDMyMDA=&piggybackCookie=p_DqAaGm6AC_9LgA9qOjBPHy61S_obxX9qXieb1S","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://bongacams.com/validate-username?value=","request_type":"html"}
+{"origin":"http://www.google.de/","request_url":"https://adservice.google.de/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.netflix.com/","request_url":"https://adservice.google.com/ddm/fls/i/src=4968236;type=naanz-nm;cat=dcmna0;u1=US;ord=8829946326844.074;_dc_1=1;~oref=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Df1fdc59c-9452-4167-a583-cc8ede9a2929","request_type":"html"}
+{"origin":"http://www.google.pl/","request_url":"https://www.google.pl/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=datalogix_dmp&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6&google_hm=2018041511333959567445911358","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.facebook.com/connect/ping?client_id=80401312489&domain=www.cnn.com&origin=2&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FFdM1l_dpErI.js%3Fversion%3D42%23cb%3Df3220b8a3bb6328%26domain%3Dwww.cnn.com%26origin%3Dhttps%253A%252F%252Fwww.cnn.com%252Ff1c71c6dd61bc4c%26relation%3Dparent&response_type=token%2Csigned_request%2Ccode&sdk=joey","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://www.google-analytics.com/r/collect?v=1&_v=j66&a=599700673&t=event&_s=1&dl=https%3A%2F%2Fm.txxx.com%2F&ul=en-us&de=UTF-8&dt=Porn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=&ea=&_u=aGDAAAAj~&jid=884883245&gjid=210711659&cid=205197444.1523791993&tid=UA-51278971-3&_gid=350041298.1523791993&_r=1&gtm=G46MDKJT8&z=1664534790","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://i.go.sohu.com/count/v?appid=wapnews&aid=100240376&apid=beans_12417&impid=0a5649c94beb659a2_0_0&at=1&mkey=0a5649c94beb659a2_0_0&latcy=2500&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=3092.109375&cx=&cy=&ed=&bucket=&supplyid=4&ext=e%3DRK9vKEBy6q2ymoAS2yZ8NgFLoISM8SkXcNIWK%2BtzRaWmW%2FIrh6lDq%2BE5pCBwa5KqOX5elCQkEgix3Kl5xyIajVagkozbEsrXd6rx4%2BJcmiMWfsFMze%2BrZxOS9DjJsPyVitOZHUZnaXBFLHenZwbvFHNK5sLZKZQo%2B2I91WV5t8zreXq03shu5k4dZ2ZCUbvP9%2BvzdyUGbYaBL9j8fXS9TV8xiwcbugC2XNvHWmyeNoKZIrKhE%2Fs1snIfIp3snPXiZRVH0h6uevcyhrljS4Z2hpbJro8A6gXef8MZSI4OInvHu1HH1q9YyFp%2B5FIEizzIbFn%2BuU4jFeo36pvpOAqUU0WpPk9iUsQhD4B3KIRORZv%2BU7n%2FcG56lgWvIUYXNyiwB82PfgwkGMMfy6J0Mv%2B8dStHn%2BRC2pVBekGin3B2IvpBlk%2FBq7m47oczHaztolRiPgaQpJNN2NyBbmmBwXwXFmETaa82L7ZYoVMqsbj2gNcwDiJs9HTVZ7LKnSQgKzyHRgdCJzelLPeN12xaOV1iFeFsbSnVpKMRxAJtdEk%2FKF%2BSfXrBPCz93XQ0BW%2Bi8errYcQgrV70%2F7hx3SbO78Oo1pCQFdbZM1nu4HcSBplp5xY%3D%09tt2%3D1523791940362%09turn%3D1%09geoid1%3D1410000000%09geoid2%3D0%09source%3Dshjtsybxpsyq&rsln=360*512&sf=0&r=2096572412879&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=c&c=&e=&pagerefer=&source=0&_time_=1523791940651","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://pp.d2-apps.net/v1/redirect?p_id=yahoo&url=https%3A%2F%2Fyjtag.yahoo.co.jp%2Fcs%3ftp%3dGvIpabp%26btt%3d0","request_type":"html"}
+{"origin":"http://www.instagram.com/","request_url":"https://staticxx.facebook.com/connect/xd_arbiter/r/FdM1l_dpErI.js?version=42","request_type":"script"}
+{"origin":"http://www.mail.ru/","request_url":"https://id.rlcdn.com/463496.gif?queue=dmp&credir=https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAw&piggybackCookie=","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://mobpushup.com/notice.php?p=1617677&interstitial=1&_=1523791941896","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://static.ads-twitter.com/uwt.js","request_type":"script"}
+{"origin":"http://www.facebook.com/","request_url":"https://static.xx.fbcdn.net/rsrc.php/v3/y9/r/tMugClB-U1v.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://aa.agkn.com/adscores/g.pixel?sid=9201373478&_s=s&_id=D34DC539-63A7-4F27-8DFD-50E0EE1E218A","request_type":"other"}
+{"origin":"http://www.pixnet.net/","request_url":"https://bidder.criteo.com/cdb?ptv=48&profileId=184&cb=42722499929","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://d.company-target.com/pixel?type=js&id=1421361512&page=https%3A%2F%2Fwww.adobe.com%2F","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key=265040302661004446320","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://90.media.tumblr.com/cedexis/r20.gif?rnd=1-1-13960-1-13960-30623-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/961332156/?value=1.00&currency_code=USD&label=ovrQCMHWrWAQvIezygM&guid=ON&script=0","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d1102768.gif?rnd=943749373&ts=1523791836","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/2.75.8/assets/video_buffer_square_blk.gif","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/facebook-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/integrators/codeship.png","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/images/icons/mobile_new_2x.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/angel710518/albumset/3087814/zoomcrop/75x75.jpg?v=1436529422","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/icon/weath/sunny_218a53c.png","request_type":"image"}
+{"origin":"http://www.alipay.com/","request_url":"https://zos.alipayobjects.com/rmsportal/eFatlrQCyUQVBoalzBPS.png","request_type":"image"}
+{"origin":"http://www.popads.net/","request_url":"http://www.popads.net/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://assets.bounceexchange.com/assets/bounce/local_storage_frame7.min.html","request_type":"html"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/3337000/3337688/220x165/8.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$geographyquiz/ic/905a59b7/146ad29b.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/8a0d321c-4bb5-4a16-8798-0ac699c62f3c_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/44/91/c6/4491c63257937175af1f51e0b4ad3b34/4491c63257937175af1f51e0b4ad3b34.24.jpg","request_type":"image"}
+{"origin":"http://www.xvideos.com/","request_url":"https://img-hw.xvideos-cdn.com/videos/thumbs169ll/f0/91/3f/f0913f6498029d2c8293358a258b6ffd/f0913f6498029d2c8293358a258b6ffd.7.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/034/259/342/big_lq/376f713bebd2c646ec5bd4dd5eb6f39c.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/3468000/3468946/220x165/9.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_358,h_239/os/news/4d5f3fce69da002eee4846f5de3cf530.jpg","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://conductor.clicktale.net/monitor?t=init&p=162&2=8342295539382868&v=1.4.86","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://logx.optimizely.com/v1/events","request_type":"text"}
+{"origin":"http://www.cnn.com/","request_url":"https://beacon.krxd.net/optout_check?callback=Krux.ns._default.kxjsonp_optOutCheck","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/www-static/js/vmobile/premium/slider.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://sp.res.nimg.jp/js/ads/middle_banner.js?20170223","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://fex.bdstatic.com/hunter/alog/dp.csp.min.js?v=140804","request_type":"script"}
+{"origin":"http://www.csdn.net/","request_url":"https://csdnimg.cn/asdf/tracking-1.0.1.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://m.media-amazon.com/images/G/01/csm/showads.v2.js","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=adobe_dmp&google_cm","request_type":"html"}
+{"origin":"http://www.amazon.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm=&ex=doubleclick.net&google_tc=","request_type":"html"}
+{"origin":"http://www.google.com.tw/","request_url":"https://www.google.com.tw/?gws_rd=ssl","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://adservice.google.com/adsid/integrator.js?domain=www.cnn.com","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://sync.crwdcntrl.net/map/c=8545/tp=CKGY/tpid=WtM35B__DJPpGsQgT1fYqPHA/?https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D120%26cm%3D%24%7Bprofile_id%7D","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?ex=spotx.com&id=cf1ec73e-40a0-11e8-9605-1fdd5b850201","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/spn16_1@2x.gif","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://sb.scorecardresearch.com/p2?c1=2&c2=7241469&c5=1197228339&c7=https%3A%2F%2Fwww.yahoo.com%2F&ns__t=1523791945716&ns_c=UTF-8","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-20543617-6&cid=151777037.1523792004&jid=1321578915&_gid=373776111.1523792004&gjid=2122442467&_v=j66&z=90343270","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://90.media.tumblr.com/cedexis/r20.gif?rnd=0-1-13960-1-13960-30623-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.aliexpress.com/","request_url":"https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-17640202-1&cid=amp-50XQcMshov1NQ7I2bYC0LQ&jid=0.9569944429846904&_v=a1&z=0.25131427119327143","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=NjY5OTBmMjQtODcwNi0zMGYyLTk3ZjMtNTc1YzBmZTQ2ODQzCTQ1CVBEUFMwMDAwMDAwNTc3ODEJNTAJMzU0NTMyNQkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p3.qhmsg.com/d/inn/2edf2228/aqrj/Box_60.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/wb.PNG","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/BwEAAOSwVlVaTA3D/$_57.JPG","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://spcdnsp.i-mobile.co.jp/ad_creative.ashx?advid=4656735&eid=15","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"https://oimageb4.ydstatic.com/image?id=-4578851359833136444&product=adpublish&w=640&h=384&sc=0&rm=2&gsb=0&gsbd=60","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/3678000/3678502/220x165/4.jpg","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/uu/api/res/1.2/GrvnfYQ25CL4EvlLp7Wtug--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/homerun/people_218/95d52d1679d11febde31d083fafbfb69","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/kindle/merch/2018/TPR/EchoDotAprilTPR/VX-1697-TPR_ED_GW-Hero-Mobile-1242x450-2X._SX1242_CB498397567_.jpg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://vignette.wikia.nocookie.net/bfe67144-04c5-4e57-9619-3fb5b56440b1/scale-to-width-down/700","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/beta-straight.svg","request_type":"image"}
+{"origin":"http://www.wikia.com/","request_url":"https://beacon.wikia-services.com/__track/view?a=&beacon=NyiV-67qg0&c=1452001&cb=1523791979504&dev=false&dev_cat=mobile&event_ts=1523791979&f=Home&ga_action=&ga_category=pageview&ga_label=&lc=en&pg_type=home&pv_number=1&pv_number_global=1&pv_unique_id=af377f25-1ffc-4914-9834-c80ec4217531&r=direct&r_type=direct&s=fandom_mobile&session=Q4ulawcgCl&session_id=5d21d0a7-b14a-4f7f-ac4b-8ba9846d26f7&site=web&t=pageview&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180406.130428&url=http%3A%2F%2Fwww.wikia.com%2Ffandom","request_type":"script"}
+{"origin":"http://www.xnxx.com/","request_url":"https://rpc-php.trafficfactory.biz/json/headermobile-hometopfooter-1xfootermobile-footerhome-1///xvideos////content.json?v=0.7532590660004319","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpmm.alicdn.com/g/mm/afp-cdn/JS/e.js","request_type":"script"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=HYc9c1dpSLWqgzShMqE45A&twitter_redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dtwca%26id%3DHYc9c1dpSLWqgzShMqE45A%26","request_type":"html"}
+{"origin":"http://www.jd.com/","request_url":"http://st.360buyimg.com/m/js/2014/module/plugIn/downloadAppPlugIn_imk2.js?v=20180323","request_type":"script"}
+{"origin":"http://www.popads.net/","request_url":"https://www.popads.net/favicon.ico","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://www.google.com.mx/gen_204?s=webaft&atyp=csi&ei=ATjTWoTsCJGF8AO8wIjADg&rt=wsrt.2153,aft.431,prt.234","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/bframe?hl=en&v=v1523554879111&k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo&cb=yjuqzyrjzt6","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.dropbox.com/log/ux_analytics","request_type":"text"}
+{"origin":"http://www.adobe.com/","request_url":"https://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=adobe-global-mbox&mboxSession=9bacdabf39b7406b83ce178a57242400&mboxPC=9bacdabf39b7406b83ce178a57242400.28_31&mboxPage=5ededb5d3e024eab82d38d46617d12fd&mboxVersion=1.2.3&mboxCount=4&mboxTime=1523766812719&mboxHost=www.adobe.com&mboxURL=https%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-420&screenHeight=512&screenWidth=360&colorDepth=24&mboxMCGVID=91347194757900030554314852707948543921&mboxAAMB=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&mboxMCAVID=2D699C4005031F55-600011820000562A&mboxMCGLH=9&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=52ED17672A35D87F-5AEFE73070D3C67A&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id=","request_type":"script"}
+{"origin":"http://www.ebay.com/","request_url":"https://ocsrest.ebay.com/ocsrsapp/o2/inflow/inflowcomponent?callback=Inflow.cb&fromGH=true&input=%7B%22pageId%22%3A2380057%2C%22gbhEnabled%22%3Afalse%7D","request_type":"script"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/rms/Framework/cj,nj/2db0047b/8df804ba.js?bu=rms+answers+BoxModel+config.instant%2cempty%2ccore%2ccore%24viewport%2ccore%24layout%2ccore%24metrics%2cmodules%24mutation%2cmodules%24error%2cmodules%24network%2cmodules%24cursor%2cmodules%24keyboard%2cempty%2cmodules%24bot","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://match.basebanner.com/match?https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMxNjAmdGw9MTI5NjAw&piggybackCookie=uid:$UID&excid=23&cijs=0","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://pixel.quantserve.com/pixel/p-5aWVS_roA1dVM.gif?idmatch=0","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://token.rubiconproject.com/token?pid=27384&puid=L6N62llA","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://tdameritrade.demdex.net/event?d_event=imp&d_src=38454&d_site=%esid!&d_creative=%ecid!&d_adgroup=%eaid!&d_placement=%epid!&d_campaign=%ebuy!&d_adsrc=48123&d_bust=%n","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://stags.bluekai.com/site/26358?dt=0&r=1017462832&sig=3186293012&bkca=KJpnEncN141p1XgJzPxguAlJnnnBvYAovnquN62vEDpmp2wnn3o/6z+nn5WFnDT+0A6LuzfxuX21LTdwnLN1DEPtQVkVBE/guYy30DL+9QGZ8juZji5Z9LVuLrBn/xoPMDpi7qpMx612Ux9ZPuzV","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo1MC4xMzgJMjZhNTBkNTgtYmZlZi00NzIyLTlmZWUtZDdhOTdlYjUzNjQ5CTMyNTAyNDUJMzExNzM2Mwk1OTE4NDAzMzAxX1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1OTk0OQkzNTMxOTg3CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQk2Njk5MGYyNC04NzA2LTMwZjItOTdmMy01NzVjMGZlNDY4NDMJMzAwMDAJMC4wMDE2NjY2NjY3CTE0OS4yMC42My4xMwlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJMAl0cnVlCU5BVElWRQlXQVAJLQkwCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAlXQVBfRkVFRAktCW5vcm1hbHx1dmZtLXJ0CS0JdXNlcl90YWc6MjAzMTc6MC4wfHdhcF9vczo3MDE6MC4wfHVzZXJfYWdlOjYwMjowLjB8dXNlcl9nZW5kZXI6NTAxOjAuMHx2X3pvbmU6Nzc3MjgwOjAuMHxuZXRfd2lmaToxMTAyOjAuMHxjcm93ZHM6fF9jcm93ZHM6CTMJMzAwMDAJMjAwMDA=&userid=__149.20.63.13_1523791820_0.19234800&auth=731f570c1642ee09&p=ZpkPJIcGMPKX81dcD%2BRoQ5qmM%2BCipe3nQ3XMlw%3D%3D","request_type":"other"}
+{"origin":"http://www.coccoc.com/","request_url":"https://mc.yandex.ru/watch/24497819?wmode=7&page-url=http%3A%2F%2Fcoccoc.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-420%3Ai%3A20180415043108%3Aet%3A1523791868%3Aen%3Autf-8%3Av%3A1072%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A1225906347662%3Arqn%3A1%3Arn%3A1031824494%3Ahid%3A1047608455%3Ads%3A342%2C473%2C499%2C46%2C2698%2C0%2C0%2C2228%2C52%2C17431%2C17433%2C7%2C4944%3Afp%3A4342%3Awn%3A12636%3Ahl%3A3%3Arqnl%3A1%3Ast%3A1523791868%3Au%3A1523791868847094136%3At%3ATr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t","request_type":"other"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WtM4gQAABibm4O17&img=1","request_type":"other"}
+{"origin":"http://www.cnn.com/","request_url":"https://magnetic.t.domdex.com/sync/pubmatic?next=https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTI5NDImdGw9NTI1NjAw&piggybackCookie=$UID","request_type":"image"}
+{"origin":"http://www.imdb.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=RX-66a22ba6-4518-42d0-a311-6ff2831bc9b0&ex=rhythmone.com","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://level3ssl.optimicdn.com/img/13070/r20.gif?rnd=0-1-13960-0-0-33636-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.vk.com/","request_url":"https://counter.yadro.ru/hit?q;uhttps%3A%2F%2Fm.vk.com%2F;rhttps%3A%2F%2Fm.vk.com%2F;74200331","request_type":"image"}
+{"origin":"http://www.tumblr.com/","request_url":"https://deazs14tb5j7o.cloudfront.net/img/29/r20.gif?rnd=1-1-13960-0-0-29-2621943475-_CgJqMRAUGEoiBQgBEIhtKLPdnuIJMM-AXTi68MzWBUDK-un9BEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuc2pjLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ads.trafficjunky.net/tj_pixel?id=001&data=%7B%22ad_ip%22%3A%22149.20.63.13%22%2C%22ad_user_agent%22%3A%22Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180413.110452%22%2C%22ad_uuid%22%3A%227308f41d-51ee-4315-9ad6-e6cd8d94fda7%22%2C%22ad_imp_id%22%3A%227_1523791909292676001_30567_7980%22%2C%22ad_request_zone_id%22%3A1686541%2C%22ad_final_zone_id%22%3A1686541%2C%22ad_campaign_id%22%3A1001849561%2C%22ad_id%22%3A1273866001%2C%22ad_aclid%22%3A%22JTjTWgAAAAANvBkA2QK3OxGn7Ut-AAAADbwZAAAAAAD_____AAAAAA%3D%3D%22%2C%22ad_isp%22%3A%22Internet%20Systems%20Consortium%2C%20Inc.%22%2C%22ad_country%22%3A%22us%22%2C%22ad_region%22%3A%22ca%22%2C%22ad_city%22%3A%22redwood%20city%22%2C%22ad_carrier%22%3A%22wifi%22%7D","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/microsoft-excel-preview-android.png:l","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://m.ok.ru/mres/img/social/44/fb_login@2x.png","request_type":"image"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/webstatic/icon/pp196.png","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB14EMrQFXXXXX.XXXXXXXXXXXX-1500-320.png?getAvatar.png=_720x720Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/ditu083002.png","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/images/branding/product/1x/gsa_android_144dp.png","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://match.adsrvr.org/track/cmf/generic?ttd_pid=pubmatic&ttd_tpi=1","request_type":"html"}
+{"origin":"http://www.wordpress.com/","request_url":"https://match.adsrvr.org/track/cmf/rubicon","request_type":"html"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/3a7c23ea-cdfd-4f11-947d-a946118c2ca5_desktop.jpg?impolicy=mobile&imwidth=399","request_type":"image"}
+{"origin":"http://www.yahoo.com/","request_url":"https://s.yimg.com/wv/images/alphatar_100x100_B_jl_2.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"https://production.mtm-cdn.com/filmer/archives/1159/8780/21.jpg","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/digital/video/placement/Gateway/Evergreen/Mobile/DE_EvergreenHero_X-Site_Superhero_1242x450_SFT_v2._SX1242_CB486792589_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s134x134_jfs/t15820/255/2337971650/598924/2ce96dd9/5aa0bd2aN8f1220af.jpg!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=865327869836&photoType=4","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/tfs/TB1doyvQFXXXXa2XpXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.savefrom.net/","request_url":"https://en.savefrom.net/favicon.ico","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.google-analytics.com/analytics.js","request_type":"script"}
+{"origin":"http://www.bongacams.com/","request_url":"https://d31qbv1cthcecs.cloudfront.net/atrk.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://tpc.googlesyndication.com/sodar/V6zvOIoD.js","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/register/view.min-vflJuLILj.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://wwwimages2.adobe.com/etc.clientlibs/beagle/fe/thirdparty-new.min.fp-84b08f1708a198e570f3b5fa819bec5d.js","request_type":"script"}
+{"origin":"http://www.twitch.tv/","request_url":"https://m.twitch.tv/static/javascript/bundle-index.0013ea90d3c02b253e6f.js","request_type":"script"}
+{"origin":"http://www.amazon.de/","request_url":"https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=-yalcI9yS-6iePfINjDv7Q&twitter_redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dtwca%26id%3D-yalcI9yS-6iePfINjDv7Q%26","request_type":"html"}
+{"origin":"http://www.baidu.com/","request_url":"http://www.baidu.com/?action=exception&sid=122436_100808_122154_114746_100097_120171_122489_118895_118870_118847_118830_118805_120550_107315_122862_117330_117433_122789_121142_122857_122886_123139_122496_114975_116407_122669_110085_122303&ssid=0&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&qid=1811881676&errno=2&strategy=emptycookiebaiduid&_=1523791817101","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypalobjects.com/tagmgmt/codefiles/8d6c38cba2c6ba608641dd96b5028c3d.js?conditionId0=381750","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/es6-promise.auto_23fef72.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://ad.doubleclick.net/ddm/ad/N461601.2005704YIELDMO/B20743590.215238486;sz=1x1;kw=764344014241209959-1902252717768542290;ord=4730661999536277586;dc_lat=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=","request_type":"html"}
+{"origin":"http://www.paypal.com/","request_url":"https://www.paypal.com/us/home","request_type":"html"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.googletagmanager.com/gtm.js?id=GTM-W7RKT4&l=googleTagManager","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://sb.scorecardresearch.com/b?c1=7&c2=13739933&c3=20121515121&ns__t=1523791840790&ns_c=UTF-8&cv=3.1m&c8=MSN%20%7C%20Outlook%2C%20Office%2C%20Skype%2C%20Bing%2C%20Breaking%20News%2C%20and%20Latest%20Videos&c7=https%3A%2F%2Fwww.msn.com%2F&c9=","request_type":"other"}
+{"origin":"http://www.msn.com/","request_url":"https://pixel.advertising.com/ups/254/occ","request_type":"other"}
+{"origin":"http://www.amazon.de/","request_url":"https://aax-eu.amazon-adsystem.com/s/ecm3?id=fYGtVxcexqhy&ex=pulsepoint.com&&ev=&pid=557477","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afptrack.alimama.com/opt?bid=0a671d5f00015ad3387df52870831a80&pid=mm_113716014_12970037_52768242&cid=143140&mid=74920&oid=149&productType=1&qytInfoMTime=1523728959&cb=7581993","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-62256447-1&cid=489400867.1523791896&jid=1324324500&_v=j39&z=1618093907","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://top-fwz1.mail.ru/tracker?js=13;id=2104775;u=https%3A//mail.ru/;st=1523791840769;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=8444bcd29777bf8d;ver=60;nt=0/0/1523791832347/////5292/2672/2672/2672/4214/3168/4215/5273/5410/5325/9210/9210/9210/28142/28142/;detect=0;lvid=1523791844609%3A1523791860490%3A3%3Ae5d8a31e801c4e17a79c5b7f63693070;_=0.423852364368005;e=RT/load;et=1523791860490","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mainpagemobile/style/images/topic-spotlight-flip-right.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/albertayu773/albumset/15005821/zoomcrop/75x75.jpg?v=1443208961","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/static/img/jingdong20171024-56.png","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID","request_type":"html"}
+{"origin":"http://www.msn.com/","request_url":"https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/191d82ef19f7f0cb1b491cc0cdf88061.jpg","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://thumb-v-cl2.xhcdn.com/a/kKvDG39fBnGszUBscHAbug/009/342/103/320x240.3.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://ad.gmw.cn/index_banner/20160919_hr365_260x90.jpg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/5619000/5619757/220x165/1.jpg","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/ganlan4152.jpg","request_type":"image"}
+{"origin":"http://www.taobao.com/","request_url":"https://gw.alicdn.com/imgextra/i4/173/TB286lTbrArBKNjSZFLXXc_dVXa_!!173-0-lubanu.jpg_q50.jpg","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/images/checkmark-vfl56VRyi.svg","request_type":"image"}
+{"origin":"http://www.linkedin.com/","request_url":"https://static.licdn.com/scds/concat/common/js?h=7ndrn0f9fw0hum7uoqcjcnzne-95d8d303rtd0n9wj4dcjbnh2c","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://fandom.wikia.com/f2/api/get-client-ip","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://api.mixpanel.com/track/?data=eyJldmVudCI6ICJtcF9wYWdlX3ZpZXciLCJwcm9wZXJ0aWVzIjogeyIkb3MiOiAiQW5kcm9pZCIsIiRicm93c2VyIjogIkNocm9tZSIsIiRkZXZpY2UiOiAiQW5kcm9pZCIsIiRjdXJyZW50X3VybCI6ICJodHRwOi8vd3d3LmVzcG4uY29tLyIsIiRicm93c2VyX3ZlcnNpb24iOiA1OCwiJHNjcmVlbl9oZWlnaHQiOiA1MTIsIiRzY3JlZW5fd2lkdGgiOiAzNjAsIm1wX2xpYiI6ICJ3ZWIiLCIkbGliX3ZlcnNpb24iOiAiMi4yMC4wIiwiZGlzdGluY3RfaWQiOiAiMTYyYzkxNTU4MTFlMjctMDhiNmM5MDEzMjdlYTctODY2NjQ3Zi0yZDAwMC0xNjJjOTE1NTgxMjE5NSIsIiRpbml0aWFsX3JlZmVycmVyIjogIiRkaXJlY3QiLCIkaW5pdGlhbF9yZWZlcnJpbmdfZG9tYWluIjogIiRkaXJlY3QiLCJtcF9wYWdlIjogImh0dHA6Ly93d3cuZXNwbi5jb20vIiwibXBfYnJvd3NlciI6ICJDaHJvbWUiLCJtcF9wbGF0Zm9ybSI6ICJBbmRyb2lkIiwidG9rZW4iOiAiNmIzNDdjMzlmMGY1NzA2N2EzNmFjYzZhYTYwMGEwOTQifX0%3D&ip=1&_=1523792042026","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mem.gfx.ms/meversion?partner=MSHomePage&market=en-us","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/zepto/4.0.9/zepto.js","request_type":"script"}
+{"origin":"http://www.wikia.com/","request_url":"http://static.parsely.com/code/ptrack-v1.0.3-engagedtime-slots-video.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=%2Fphoto%2F2018%2F0414%2Fr356648_1296x729_16%2D9.jpg&w=320&h=180&scale=crop&cquality=40&location=center","request_type":"image"}
+{"origin":"http://www.google.com.br/","request_url":"http://www.google.com.br/","request_type":"html"}
+{"origin":"http://www.cnn.com/","request_url":"https://id.rlcdn.com/463496.gif?queue=dmp&credir=https://simage2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAw&piggybackCookie=","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://aax.amazon-adsystem.com/e/dtb/bid?src=3159&u=https%3A%2F%2Fwww.cnn.com%2F&pid=5400474871011523791861740&cb=7428719915151523791866271&ws=360x512&v=6.8.1&t=750&slots=%5B%7B%22sd%22%3A%22ad_rect_atf_01%22%2C%22s%22%3A%5B%22300x250%22%5D%7D%2C%7B%22sd%22%3A%22ad_rect_btf_02%22%2C%22s%22%3A%5B%22300x250%22%5D%7D%2C%7B%22sd%22%3A%22ad_rect_btf_03%22%2C%22s%22%3A%5B%22300x250%22%5D%7D%5D","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"https://googleads.g.doubleclick.net/pagead/viewthroughconversion/971301452/?random=1523791867108&cv=9&fst=1523791867108&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&resp=GooglemKTybQhCsO&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-420&u_java=false&u_nplug=0&u_nmime=0&sendb=1&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&rfmt=3&fmt=4","request_type":"script"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/og/_/js/k=og.mob.en_US.k50d9vxbstI.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTskXeeXd7SWvpNwE2dYOLzdHV82WA","request_type":"script"}
+{"origin":"http://www.hao123.com/","request_url":"https://as1.m.hao123.com/bvzdlc.js","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2","request_type":"font"}
+{"origin":"http://www.diply.com/","request_url":"https://connect.facebook.net/en_US/sdk.js","request_type":"script"}
+{"origin":"http://www.gmw.cn/","request_url":"http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768244&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1523792000832&fs=3&pvid=a1004bd6c326ed77293756d90ef5d8a0&cg=af337a7725468314f9b634ba2e666b5d","request_type":"script"}
+{"origin":"http://www.livejasmin.com/","request_url":"http://jaws.dditscdn.com/socket.io/?EIO=3&transport=websocket&sid=yLIOFNP835fT4D41H3-W","request_type":"other"}
+{"origin":"http://www.jd.com/","request_url":"https://im-x.jd.com/dsp/np?log=kKWpPGny+Mglmy4fCUUYoP8sFAUXX9bSQZ6Of+red0l9wh1sPWqkJRBTDFn6L7+yBoFqrtLMqmhng/FhF+Bl/4M1fhtvBeuByBgBrpPTrMn0/aydYvr81yVQOkqLk2ol+QHfI1c8ous1SK52ytZL+zDKVhPO8Ri0DGc33bk+r8A5XNk42ZbCA+T+tNQLI0F8yBW3RJz4Lf2ScMUOK6yxxKAPm8/4xig6vhz9JN/98J+ePTRffl3NYF2VWNCtpUqN6d/hIyiNzUhOUqU+e10OMfimLhZH9JWPaZvarK7OQXDmFITPmcDTKmZIr2D+j8VP&v=404&_=1523792011409","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://dt.adsafeprotected.com/dt?advEntityId=143441&asId=1cd9a402-3805-7f68-3cd0-7d66358c863f&tv={c:9OXR9r,pingTime:-2,time:523,type:a,sca:{dfp:{df:0}},env:{sf:0,pom:1},rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:1,fif:0,gm:0,slTimes:{i:0,o:523,n:0,pp:0,pm:0},slEvents:[{sl:o,t:135,wc:0.0.360.512,ac:0.7403.336.72,am:by,cc:4.359.352.72,piv:0,obst:0,th:0,reas:l,cmps:1,bkn:{piv:[484~0],as:[484~336.72]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:rjss,dtt:0,fm:qPhNqxI+11|12|13|14|151|16|17|18|19|1a|1b1|1b2|1b3|1b4*.143441-22764869|1c|1d|1e|1f,idMap:1b4*,slid:[ym_764344014241209959.0],sinceFw:347,readyFired:true}&br=c","request_type":"image"}
+{"origin":"http://www.wordpress.com/","request_url":"https://secure.leadback.advertising.com/adcedge/lb?site=695501&betr=sslbet_1501625044=ssprlb_1501625044[720]","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"http://m.jd.com/images/index/load/slider-min.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/tubemate-3-android.png:l","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/shao1019/albumset/7410782/zoomcrop/75x75.jpg?v=1523785980","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/demona/albumset/14608664/zoomcrop/75x75.jpg?v=1367249137","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=everest&google_hm=V3RNNGt3QUFBQU9MNngwYQ&google_push=AHNF13LZcnuEnYiXLFPiWRM5QR2HEQhrPeBiJ_Et7lS9MtH6","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/static/html5-index/falls/img/addtohome_d10e3b1.png","request_type":"image"}
+{"origin":"http://www.google.com.hk/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.csdn.net/","request_url":"http://www.csdn.net/","request_type":"html"}
+{"origin":"http://www.hao123.com/","request_url":"https://m.hao123.com/","request_type":"html"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/32/9b/7b/329b7bb735879a9a35478aecef0c797b/329b7bb735879a9a35478aecef0c797b.2.jpg","request_type":"image"}
+{"origin":"http://www.gmw.cn/","request_url":"http://img.gmw.cn/images/attachement/jpg/site2/20180413/94c69122e4b71c3a4e6716.jpg","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s6.pimg.tw/album/fafa168/element/237339026_1523627925-1178508249/zoomcrop/90x65.jpg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/150611164327-cnnmoneyeggs-large-169.jpg","request_type":"image"}
+{"origin":"http://www.baidu.com/","request_url":"https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2095786667,3948127858&fm=173&app=25&f=JPEG?w=218&h=146&s=A18962B10C8664C21008056F03007072","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://txxx-tn1.yurivideo.com/contents/videos_screenshots/4632000/4632229/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_yKuJXEA4Y3y9BpnKMkGTAA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/th?id=OPN.RTNews_DJt81Hce7EJ9GWwXQHKGJg&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://www.google.com/recaptcha/api2/payload?c=03AJIzXZ7NbaYK69XY1XhHyq9lv_37qwu0yPlQ3f7nd_EQiz-wi2D_DyPxcTO_NrMTwLGvVNF1QIVQT930PyZX5-2YZz4qgl4FwzLKkzlpFYv8Y_1RFi60MatdYzc8pCLsdW6x9pkQoOL1rZJ51C5nG8Q11hct4bCbbd3FnpwmsVErzDzDlMXl5gAepqte2-ejUHy95saHTG-i6wXl6u-CvUUbC97zGpr5tK82oBAr99ccGI9_qhU_c8_E3Md9ExWHBxs7IfIRUZKoN67IpyUV-34iNAYWl5xMkIpCAGUcG7XMceuBrWdqTFJcX2mDtkTLdJtEq-j2tYt5U3BgE_CSJcEy2ksrjW3BMfXYNPzPUbRRNZ5XDwpXybpdn94U5o82doS8NuajwFpHSLE33_D5nXp8aAm8OPxKwpKJiDRzAEBKFUF1Iangiy2tLyc88DBrnZ8-aanjgCt0Vykbsx0fjNhz350iDWDyRK-pbFFmWLKAgJhVjDTALhfrKSgU7yd6Llagl-M1U863F2rZgpuS341zCYW0HPn0ERpJQMQH-WHEa-PwQ4hYbRr3Z5AEFn66TTUW61HD0RnoKLfRgnkSLPJkoKWzsx3sxoyErzy8oIjrWbjjfDuRP2QbqHQMqQw79I4bs3RhmfEpzIy8y_WInnbLj-JlToVdQCo9w1n1deVYq8stZPJ4YYl1m8pFs903SVQ4r59NIjKzPVgZkFrBiqUjmkPTK1prLRXwKuaBqOAOXMadPEBe0q3bWSTd6p4e_OgAcf8hKehRL-NOeRN1YnTbC_MWnYJ1LTaPlMHOhGvJxduCgaPL_OjDPeHwQrTfhB2K6bDDbrikLOWfPDDGfpFjQhDEcAkqCm7tkIgo8ix6JRkh-s4jIY05B9b8dPAIXV9c6LL0pa0k8SeN9qLHlgdpMHeBi0VcGxR0OAWk_VSUKGEpUacJvxdEKREtFwXmTu3N5Q324P-q4mAhjb0Y0CuO4l8AzIl1dYCddjkqV0-eGlyCXIwiOCYLOP7lHhXI1qiWOI6ujhb0LrRYUeWVeIIRT1XTr5Cs198w6684Seko5qLG5bUyYA_t73mIVIstxCeEM4ZzVFgLUvO-ybWNrJRa-LCbOvVYv06KYkkLRvX8L0DmzZjvCoAzIXVmxjCOafmzPaLG2tktCgQsoNUtcuXCDDyAGCMLuShNFX-KguLHdViWp4FkHRSf59k3ezszdfK-FuabsP1n94txb83E4lhTgqadzBvBTYE-C_Z_uqdfFyWkBU49LV-OVLCCnqSLRx1qjYre8hsB-GXX64mX8PA1MvJiOjoFfghOaOh7vcfGJd5AquDTat_mEAizJef-5CPZc040kr9PF_ds-t6WhEnf-G7vsmTgBfWBUl2D08VWC4-1efts2pEjOA6gi27Nm8U6_5IygvXXqRuWKZ2dEEY1iZGrNwvw0IFLQyFYeyPhf3ZZ3ZySxT3KkvHNvOxIkMYQtQ3xC0ooiAAzOfgfMdEh6_ek9bLCBR58ZMScYdaY1XRJ8FCAeWeQ99-h993dJruEMWlJM9cQJqshDbpJzGpQ2-ahka27llctPOcQCzuDx0H2cKmiiDI-pwyNU9W9C9iAqdlujWx54mxtlYQqIONytnWOospVJ_Vi7MuStqmEtT8D6lnWwGe_wxX_4W2EPaOpDP7GgxZcxMPutgKC9uJH3NCJRJ2j7cQw88kzWdNb200jAnwCxtxxE2L9cl4ipK60Uw6ZXatYpIBQvW8dPmQV7AIbJtsBBPIBAd8atjX_Z74r-YUF6ebfjX8WOQQbGyTkFePHPnaETZy0XklIVxigp1crdljyrOC3KZzuq9PphQYWILEXMry1Z2Wt-5IS0nT-LBQ44L7LgZD2PwYDehsFAgpPm7PDKZVURXVkkGoebNilZbJI3kRmph26oATbojY3meUSVHo9kGgxhkibbnuqZh6TXIrJ0Tn6BC0mpfjS27W3GgOi94M-P6w3-XKX9C3t0e6YzyjeJJyMHQXD8ezxpx50Gzk07FR-mJrxhRem3Cimqh6lSS0GPm_cwL7iIQ9V15lktgf4mkAAjbs_z6f9Z2ody3IJxp-jrZvNQLtbjfWDE_i59f_BkyiVT7Kjyt5mVLfl2YEVxxfWuntyBJ-Pp97Ev3bZvLpdLH25Hl99q_8d_7gHyLsZoFTfzaNTNUo0mwIxXPwtpS8A6i6CKi-gad4jgHQ7i7kB4vZUn4eu5D7FR8NL0jw&k=6LdnLyIUAAAAAOiGPtddh-g3KiJRoDGGPD-6dqXo","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/41Wo77ejldL._AC_SY80_.jpg","request_type":"image"}
+{"origin":"http://www.jd.com/","request_url":"https://m.360buyimg.com/mobilecms/s720x352_jfs/t18733/183/1623991221/147112/2d6c7314/5ad03b7fN5e43020a.jpg!cr_1125x549_0_72!q70.jpg.dpg.webp","request_type":"image"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/images/svg/hd.svg","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://fastlane.rubiconproject.com/a/api/fastlane.json?account_id=11078&rp_floor=0.01&rf=https%3A%2F%2Fwww.cnn.com%2F&p_screen_res=360x512&x_source.tid=ceffcb6d-e438-47aa-9b2a-b6cca793c897&tk_flint=plain&size_id=15&p_pos=btf&tg_fl.eid=ad_rect_btf_02&tg_fl.uname=%2F8664377%2FCNN%2Fhomepage&kw=CNN%2Fhomepage%2Crp.fastlane&tg_i.site=CNN&tg_i.section=homepage&tg_i.subsection=landing&tg_i.cap_topics=&tg_i.ssl=1&tg_i.pos=rect_btf_02&tg_fl.pr_acctid=11078&rp_secure=1&rand=0.033955121149267464","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://unagi-fe.amazon.com/1/events/com.amazon.csm.nexusclient.prod","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/onerfstatics/marketingsites-wcus-prod/_h/9ae23327/mscom.statics/externalscripts/mscomhp/audiencemanager.js","request_type":"script"}
+{"origin":"http://www.xhamster.com/","request_url":"https://static-cl.xhcdn.com/xh-mobile/js/54348c04.common.js","request_type":"script"}
+{"origin":"http://www.pornhub.com/","request_url":"https://cdn1d-static-shared.phncdn.com/vortex-simple-1.0.0.js?cache=2018041212","request_type":"script"}
+{"origin":"http://www.xvideos.com/","request_url":"https://static-hw.xvideos.com/v-afc155966ab/v3/js/skins/min/default.header.static.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/tpe.png&h=60&w=60","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/mod_2b1d325.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a4.espncdn.com/combiner/i?img=/photo/2018/0315/r341675_1296x1296_1-1.jpg&w=208&h=208&scale=crop&location=center&cquality=40","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://geo.moatads.com/n.js?e=35&ue=0&uu=0&qm=420&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2BweM!%2CxnyAk_D2fQ%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=BmCCkSBBBBBBbBBBBq6YYNCu3NB8Qwk0Bv34mCeCC4g6miE2wif6W0lBg1SfTBBBBBBeUIBCyBMBBvBUtBWx6jHdBBfXe8kBPB2kc3MMpFBTaBBBBBBBBBBBtsWaBBBHCZ5iWeWSBM31KJPlglCCFMWFpcxaBCNBZnuBBOFeBCBBblBwxBHryaIGoXjTr93nNa0B3BBJBBzBPBBBlDDVCDCCDCDDDDDC0GuBeEES8DDBqBCKqeMFB&iv=5&gz=0&hh=0&hn=0&qt=0&i=TURNERDFP1&hp=1&zMoatTEAM=Value%20Not%20Defined&zMoatSOC=Value%20Not%20Defined&zMoatHT=2&zMoatPS=bnr_atf_01&zMoatPG=Value%20Not%20Defined&zMoatWD=1&zMoatAPP=Value%20Not%20Defined&zMoatST=Site%20Not%20Defined&zMoatBUZ=Value%20Not%20Defined&zMoatISAPP=Value%20Not%20Defined&zMoatPLATFORM=mobileWeb&zMoatRetail=true&zMoatPSB=bnr_atf_01&zMoatOrigSlicer1=%2F8663477%2FCNN%2Fhomepage&zMoatOrigSlicer2=52063237&cm=16&kq=3&hq=0&hs=0&hu=0&hr=0&ht=1&bq=0&f=0&tw=hOJYITEA2B&j=&o=3&t=1523791879792&de=167419061556&m=0&ar=cf7e882-clean&q=6&cb=1&cu=1523791879792&ll=3&lm=0&ln=1&r=0&em=0&en=0&d=38386957%3A237199237%3A4640152498%3A138230533951&cadf=-&gptMoat_pg=-&gptMoat_appname=-&gptMoat_pos=bnr_atf_01&gptMoat_mivr=-&za=-&zb=-&zc=-&zd=-&ze=-&zf=-&qs=1&zGSRC=1&gu=https%3A%2F%2Fwww.cnn.com%2F&bo=%2F8663477%2FCNN%2Fhomepage&bp=52063237&bd=bnr_atf_01&zMoatAltSL=zMoatAdUnit1%3AzMoatAdUnit2%3AzMoatPS&dfp=0%2C4&la=52063237&gw=turnerdfpcwrefresh475219962180&fd=1&ac=1&it=500&fs=142625&na=1474555811&cs=0&callback=MoatSuperV26.gna716887","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=clickagy&google_sc&google_cm&google_hm=V3RNMzVCX19ESlBwR3NRZ1QxZllxUEhB","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://image6.pubmatic.com/AdServer/PugMaster?rnd=2276659&p=156736&s=269857&a=1318691&ptask=ALL&np=0&fp=0&mpc=0&spug=1&coppa=0&sec=1&kdntuid=1","request_type":"html"}
+{"origin":"http://www.google.com.ar/","request_url":"https://www.google.com.ar/gen_204?s=webaft&atyp=csi&ei=HzjTWsvkNuGX0gKXxZi4Bw&rt=wsrt.2130,aft.373,prt.214","request_type":"html"}
+{"origin":"http://www.pinterest.com/","request_url":"https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.pa4EfGZJtyM.O/m=rpc,shindig_random/rt=j/sv=1/d=1/ed=1/am=AQE/rs=AGLTcCNvuMxw8LpLrCWFeoIaET1OMP8dSQ/cb=gapi.loaded_0","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://cdn.optimizely.com/js/310987714.js","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://connect.facebook.net/en_US/fbevents.js","request_type":"script"}
+{"origin":"http://www.vk.com/","request_url":"https://m.vk.com/js/s_c.js?722","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://c1.adform.net/serving/cookie/match?party=14&cid=D34DC539-63A7-4F27-8DFD-50E0EE1E218A","request_type":"other"}
+{"origin":"http://www.yahoo.com/","request_url":"https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1523791946596&yhlClientVer=3.42.4&yhlRnd=VsYXT12CoJBfJLNj&yhlCompressed=0","request_type":"other"}
+{"origin":"http://www.imdb.com/","request_url":"https://video-http.media-imdb.com/MV5BNGQyYzYyNmYtNTA2MC00NmRkLWIwZDktNjc4ZjA1Y2YxMGI3XkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1523878331&Signature=FWox8O8guCL1RgVCkbOmgoEzPzs2ZLM8LUbGNj1qTAcoFjImTBnQAWhw-orwdQ9IL9285Xm~drvX4NaTvGwUdwie4bwefwIsPNQl-56NY-SfvXq3WzZfGhFQic5wKbtI46WkKnwVTqssGAAL4M0r4vMtze3SAS6q7AQfw7fF97w_&Key-Pair-Id=APKAILW5I44IHKUN2DYA","request_type":"video"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDo1MC4xMzgJNmY2YWM2ODUtYzExNy00NDBiLTljOGQtZDQ3NmQ2NzM1OTcxCTMyNTQ5OTcJMzExOTgyMAk1OTE4Mjg4Mzc0X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1OTk1MAkzNTQwNzM2CXh4bAkxCS0JV0FQCS0JMQk4MDIyM2JhN2FlMDJlYTJhODdmZGE0Y2E2NzJlYTIxNQk2Njk5MGYyNC04NzA2LTMwZjItOTdmMy01NzVjMGZlNDY4NDMJMzczOTgJMC4wMDEyNQkxNDkuMjAuNjMuMTMJX18xNDkuMjAuNjMuMTNfMTUyMzc5MTgyMF8wLjE5MjM0ODAwCTAJdHJ1ZQlOQVRJVkUJV0FQCS0JMAlfXzE0OS4yMC42My4xM18xNTIzNzkxODIwXzAuMTkyMzQ4MDAJV0FQX0ZFRUQJLQlub3JtYWx8dXZmbS1ydAktCXVzZXJfdGFnOjIwNzM2OjAuMHx3YXBfb3M6NzAxOjAuMHx1c2VyX2FnZTo2MDI6MC4wfHVzZXJfZ2VuZGVyOjUwMTowLjB8dl96b25lOjc3NzI4MDowLjB8bmV0X3dpZmk6MTEwMjowLjB8Y3Jvd2RzOnxfY3Jvd2RzOgk0CTQwMDAwCTIwMDAw&userid=__149.20.63.13_1523791820_0.19234800&auth=b2d144e2d173d643&p=ZpkPJIcGMPKX81dcD%2BRoQ5qmM%2BCipe3nQ3XMlw%3D%3D","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://s.amazon-adsystem.com/ecm3?id=RX-08740e04-0b5b-4c9e-b858-dbf5726876b9&ex=rhythmone.com","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=3&redir=https%3A%2F%2Fsimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTM2MiZ0bD00MzIwMA%3D%3D%26piggybackCookie%3Duid%3A%5BMM_UUID%5D","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=86070857378125119120981354726841823876&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d86070857378125119120981354726841823876","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.rubiconproject.com/tap.php?cookie_redirect=1&v=7941&nid=2243&put=WtM34wAACGMfPfyQ&expires=90","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://mc.yandex.ru/watch/23578849/1?page-url=https%3A%2F%2Fm.txxx.com%2F&charset=utf-8&force-urlencoded=1&browser-info=ti%3A1%3Adp%3A1%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Az%3A-420%3Ai%3A20180415043313%3Aet%3A1523791993%3Aen%3Autf-8%3Av%3A1072%3Ac%3A1%3Ala%3Aen-us%3Aar%3A1%3Apa%3A1%3Als%3A1396006951435%3Arqn%3A2%3Arn%3A1045895234%3Ahid%3A19071466%3Ads%3A%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%3Arqnl%3A1%3Ast%3A1523791994%3Au%3A1523791993707055678","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=21&dpuuid=164761502661000506101","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/waze-android.png:l","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/ico-movie.png","request_type":"image"}
+{"origin":"http://www.uptodown.com/","request_url":"https://img.utdstc.com/icons/musixmatch-lyrics-player-android.png:l","request_type":"image"}
+{"origin":"http://www.github.com/","request_url":"https://assets-cdn.github.com/images/modules/site/logos/walmart-logo.png","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/image/loader-f2c81.png","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pimg.tw/album2/kiki598/albumset/16338119/zoomcrop/75x75.jpg?v=1478443759","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://assets.bounceexchange.com/assets/uploads/clients/1682/ads/e0dd2acd3574679864cd76965aa5dce2.png","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/images/mobile-logo.png","request_type":"image"}
+{"origin":"http://www.google.com.mx/","request_url":"https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png","request_type":"image"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/paper-atlasgrotesk/AtlasGrotesk-Bold-Web-vfl39K48X.woff2","request_type":"font"}
+{"origin":"http://www.txxx.com/","request_url":"https://11268780.pix-cdn.org/contents/videos_screenshots/3510000/3510949/220x165/3.jpg","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://ci.phncdn.com/videos/201802/24/155830362/thumbs_25/(m=eafTGgaaaa)(mh=uHyisjyae2GVBn7S)3.jpg","request_type":"image"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://img.cdn.nimg.jp/s/niconews/articles/images/3435260/c73907ab9e1c989142e032f4b0516d508631adb1e941456bd811e49e83497f14c9ddd92f96296da38feffba8e13dd5a2c4669b0199e8d83c76fc63995ac8d06c/110x110l_FFFFFFFF?key=56ee0491e18249949c0939fb9aae66e99929a769032ca8a4883df139735ae083","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnnnext/dam/assets/180321154513-starbucks-igualdad-salarial-vo-portafolio-00000005-small-tease.jpg","request_type":"image"}
+{"origin":"http://www.bing.com/","request_url":"https://www.bing.com/az/hprichbg/rb/PaintedForest_EN-US5613568462_480x640.jpg","request_type":"image"}
+{"origin":"http://www.youth.cn/","request_url":"http://m.youth.cn/qwtx/lbt/201804/W020180420294944536785.jpg","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"https://p5.ssl.qhimg.com/t0182c18bafd2389586.jpg","request_type":"image"}
+{"origin":"http://www.sohu.com/","request_url":"https://643108e7617ef.cdn.sohucs.com/f78623d11fca425f83ec59046707ee54.jpg","request_type":"image"}
+{"origin":"http://www.qq.com/","request_url":"https://inews.gtimg.com/newsapp_ls/0/3273470421_294195/0?tp=webp","request_type":"image"}
+{"origin":"http://www.apple.com/","request_url":"https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/tv/image_small.svg","request_type":"image"}
+{"origin":"http://www.pinterest.com/","request_url":"https://s.pinimg.com/mobile/js/entryChunk-mobile-6432f5bf6ba5f63a4718.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-nascar.png&h=120&w=120&cquality=40","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://www.microsoft.com/mwf/css/MWF_20180410_9005042/west-european/default/alert/autosuggest/cards/contentplacement/contentplacementitem/glyph/heading/hero/heroitem/hyperlinkgroup/image/list/mediagallery/pagebehaviors/singleslidecarousel/skiptomain/social?apiVersion=1.0","request_type":"css"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31LiSGwXxjL.css_.css?AUIClients/SharedShoppingCartMobileAsset","request_type":"css"}
+{"origin":"http://www.popads.net/","request_url":"https://www.popads.net/login_box.html","request_type":"html"}
+{"origin":"http://www.adobe.com/","request_url":"https://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-595522bf64746d0bd4004510.js","request_type":"script"}
+{"origin":"http://www.pixnet.net/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bw_cookie&google_cm&google_ula=3918219&google_hm=&layout=js","request_type":"html"}
+{"origin":"http://www.mail.ru/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=pubmatic&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fcmatch.google.com/pixel?google_gm=AMnCDophMBgwnebV5L2A8Y4SjOPNrQt2TuaYeI3zraD2oZAhmmB8iyR4EM7D-SNBs6WhaBHOBFo7pdB6IBlYHcLZZnXcJiiK1EAV-8qjZdgkoqF0CwQ68Ec","request_type":"html"}
+{"origin":"http://www.pixnet.net/","request_url":"https://fcmatch.google.com/pixel?google_gm=AMnCDorYR6VMHu4X6-zhU5FkifJYJSRG9ozbU34cqPeTLXGmzoMZztgnwqYeD9Z6AZIPeMwSFsF7HSSTVQl7-s0VVYCUUjQ3_A","request_type":"html"}
+{"origin":"http://www.microsoft.com/","request_url":"https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA=&piggybackCookie=WtM34wAACGMfPfyQ","request_type":"html"}
+{"origin":"http://www.whatsapp.com/","request_url":"https://www.whatsapp.com/","request_type":"html"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791948286&yhlClientVer=3.30.2&yhlRnd=P0MuJmSmxCSeAzRBjg0qds72&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.espn.com/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/activeview/osd_listener.js","request_type":"script"}
+{"origin":"http://www.google.it/","request_url":"https://www.google.it/xjs/_/js/k=xjs.qs.en_US.GQVczEEvPnE.O/m=sx,bct,cdos,elog,hsm,jsa,qim,r,d,csi/am=gEXyM95DDkHGRjEhGYy_AAo4ERA/rt=j/d=1/t=zcms/rs=ACT90oF_H_1oNpCgKdy7CQHyn7N8ww-4ag","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://fragment.tmall.com/mit/get_home_data?wh_callback=true","request_type":"script"}
+{"origin":"http://www.diply.com/","request_url":"https://data.diply.com/production/public/content/query/v1/article/search/tag/delicious?pageSize=3","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://www.i.cdn.cnn.com/.a/bundles/fave.71d7513eb0fa253d9602.bundle.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/bundles/fave/vendor-5e756f17/vendor","request_type":"script"}
+{"origin":"http://www.msn.com/","request_url":"https://sb.scorecardresearch.com/b?c1=2&c2=3000001&rn=1523791836830&c7=https%3A%2F%2Fwww.msn.com%2F&c8=MSN+%7C+Outlook%2C+Office%2C+Skype%2C+Bing%2C+Breaking+News%2C+and+Latest+Videos&c9=","request_type":"other"}
+{"origin":"http://www.microsoft.com/","request_url":"https://pixel.rubiconproject.com/tap.php?v=7941&nid=2243&put=WtM34wAACGMfPfyQ&expires=90","request_type":"other"}
+{"origin":"http://www.amazon.com/","request_url":"https://d.agkn.com/pixel/8198/?che=1523791925&sk=163911502661000498832&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=163911502661000498832&ex=neustar.biz","request_type":"other"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixern.sina.cn/dsp/view?m=MjAxOC0wNC0xNSAxOTozMDoyNy41NDIJNmI0ZjFiNjUtOTRmNi00MzgwLWFmMDAtOTA4MmI3Y2NhYzlhCTMyMzUxNzMJMzExMDEyNwk1OTE4Mjg4Mzc0X1BJTlBBSS1DUEMJUERQUzAwMDAwMDA1Nzc3OQkzNTAwMDcxCXh4bAkxCS0JV0FQCS0JMQk2MGIxMzYwOWVkNjI4NjNjMDE0YzhiNDM4MWVlNTY4ZglkZWU0MDI0ZS1hOWE5LTM0ODUtODhmOC00MDgxYTVkY2VmODMJNDc2ODMJMC4wMDEJMTQ5LjIwLjYzLjEzCV9fMTQ5LjIwLjYzLjEzXzE1MjM3OTE4MjBfMC4xOTIzNDgwMAkwCXRydWUJTkFUSVZFCVdBUAktCTAJX18xNDkuMjAuNjMuMTNfMTUyMzc5MTgyMF8wLjE5MjM0ODAwCVdBUF9GRUVECS0Jbm9ybWFsfHV2Zm0tcnQJLQl1c2VyX3RhZzoyMTE2NzowLjB8d2FwX29zOjcwMTowLjB8dXNlcl9hZ2U6NjAyOjAuMHx1c2VyX2dlbmRlcjo1MDE6MC4wfHZfem9uZTo3NzcyODA6MC4wfG5ldF93aWZpOjExMDI6MC4wfGNyb3dkczp8X2Nyb3dkczoJNAk1MDAwMAkyMDAwMA==&userid=__149.20.63.13_1523791820_0.19234800&auth=685c4a99b7aa787e&p=3uQCTqmpNIWI%2BECBpdzvg40Ov91U84Nht3m1IQ%3D%3D","request_type":"other"}
+{"origin":"http://www.live.com/","request_url":"https://r4.res.office365.com/owa/prem/16.2250.9.2535828/resources/images/0/sprite1.narrow.css","request_type":"css"}
+{"origin":"http://www.imdb.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/vap/video/airy2/prod/2.0.1459.0/css/gemini._TTW_.css","request_type":"css"}
+{"origin":"http://www.mail.ru/","request_url":"https://sync.adaptv.advertising.com/sync?type=gif&key=pubmatic-55&uid=94AC3827-BDDB-436B-A363-D775FCA8DB42","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d902146.gif?rnd=155220149&ts=1523791836","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://beacon.sina.com.cn/b.gif?https%3A//sina.cn/%3Ffrom%3Dweb|*|t=cardViewExp,s=cardViewExp,h=,ct=1523791845942,aid=exp_life-0||*|1654439800560.783.1523791824016|*|__149.20.63.13_1523791820_0.19234800|*||*|2957|*||*|","request_type":"image"}
+{"origin":"http://www.sina.com.cn/","request_url":"https://mixer.sina.cn/view?type=2&t=MjVhMmM4MDctMzIzOC0zM2M0LTkxYWQtNzlmMmQ2ZTdiYjhkCTQ1CVBEUFMwMDAwMDAwNTc3NzgJNTAJMzU1Nzc5MwkxCVJUQgktCQk%3D","request_type":"image"}
+{"origin":"http://www.coccoc.com/","request_url":"http://coccoc.com/themes/mobile/browser/img/vi/shopping-2.png","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://i.bimbolive.com/images/mobile/spiner-transparent-white.png","request_type":"image"}
+{"origin":"http://www.google.com/","request_url":"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_160x56dp.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"http://www.hao123.com/","request_type":"html"}
+{"origin":"http://www.dropbox.com/","request_url":"https://cfl.dropboxstatic.com/static/fonts/sharpgrotesk/SharpGroteskDBMedium20-vfloPliP8.woff2","request_type":"font"}
+{"origin":"http://www.cnn.com/","request_url":"https://amplifypixel.outbrain.com/pixel?mid=006eb1f8dded486e0974a6b4a7b9805f5f&dl=https%3A%2F%2Fwww.cnn.com%2F&bust=07193842477300758","request_type":"image"}
+{"origin":"http://www.ebay.com/","request_url":"https://i.ebayimg.com/00/s/MjEwWDIxMA==/z/gDYAAOSwAC1aTA3D/$_57.JPG","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://r.mradx.net/pictures/05/498583.jpg","request_type":"image"}
+{"origin":"http://www.diply.com/","request_url":"http://img.diply.com/article-images/a/0f54f8ce-855c-4975-9668-db1b6822d493_desktop.png?impolicy=desktop&imwidth=753","request_type":"image"}
+{"origin":"http://www.amazon.de/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/EinkBundle-Mobile_billboard-a-de-1242x450._SX414_CB529985201_.jpg","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/1f/c7/2f/1fc72fd95779993a22c46c65a6dd9a49/1fc72fd95779993a22c46c65a6dd9a49.19.jpg","request_type":"image"}
+{"origin":"http://www.bongacams.com/","request_url":"https://ius1.bongacams.com/live/023/3ba/1b4/big_lq/4c5f652e85f9d467300958dc10774ae8.jpg","request_type":"image"}
+{"origin":"http://www.livejasmin.com/","request_url":"https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f19/9a2ff39f1e21fd8abfe7f4f390b5f9df_erotic_445x250.jpg?cno=c82e","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71XnZiOnQML._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.ok.ru/","request_url":"https://i.mycdn.me/getImage?photoId=864732416050&photoType=4","request_type":"image"}
+{"origin":"http://www.tmall.com/","request_url":"https://img.alicdn.com/bao/uploaded/bao/upload/TB1vrwGNFXXXXbPXVXXwu0bFXXX.png_320x5000Q50s50.jpg_.webp","request_type":"image"}
+{"origin":"http://www.google.it/","request_url":"https://www.gstatic.com/navigationdrawer/feedback_icon.svg","request_type":"image"}
+{"origin":"http://www.espn.com/","request_url":"https://www.googletagservices.com/dcm/impl_v41.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"https://api.mixpanel.com/decide/?verbose=1&version=1&lib=web&token=6b347c39f0f57067a36acc6aa600a094&ip=1&_=1523792042012","request_type":"script"}
+{"origin":"http://www.microsoft.com/","request_url":"https://mem.gfx.ms/me/MeControl/9.18088.0/en-US/meCore.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/secdev/entry/index.js?t=211637","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=a9ap&google_cm&ex=doubleclick.net","request_type":"html"}
+{"origin":"http://www.sohu.com/","request_url":"https://s.go.sohu.com/cdAOd/?callback=jsonp_1523791938228_1946366413210&itemspaceid=12281&adps=160001&apt=4&turn=1&pgid=20d54ae4-a2c8-1a05-3c79-e3aac2d3d0d6&newschn=1000000000&subchannelid=&appid=wapnews&_time_=1523791938228&plateid=1001900000,1001700000","request_type":"script"}
+{"origin":"http://www.dropbox.com/","request_url":"http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D","request_type":"other"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1523791948350&yhlClientVer=3.30.2&yhlRnd=d1j5511TL45Dzk1Ljg0qds8u&yhlCompressed=0","request_type":"text"}
+{"origin":"http://www.pixnet.net/","request_url":"https://tpc.googlesyndication.com/pagead/js/r20180411/r20110914/activeview/osd_listener.js","request_type":"script"}
+{"origin":"http://www.cnn.com/","request_url":"https://registry.api.cnn.io/bundles/fave/latest-2.x/js","request_type":"script"}
+{"origin":"http://www.thepiratebay.org/","request_url":"https://platform.twitter.com/js/button.4e380b7372da43f94df254b09037e839.js","request_type":"script"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/I/31%2BnhCK5QGL.js?AUIClients/DetailPageAlohaAssets","request_type":"script"}
+{"origin":"http://www.amazon.co.jp/","request_url":"https://images-fe.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C41PsXsu4WrL.js,118Wk-h2B-L.js_.js?AUIClients/GWMWebAssets","request_type":"script"}
+{"origin":"http://www.adobe.com/","request_url":"https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D","request_type":"other"}
+{"origin":"http://www.so.com/","request_url":"https://s.360.cn/mso/disp.gif?pro=m_so&pid=home_next&u=https%3A%2F%2Fm.so.com%2F&guid=34870781.245367792129314460.1523791856399.254&srcg=default_srcg&src=default_src&mod=uaction&type=home&stay=78&value=%7B%22type%22%3A%22home%22%2C%22time%22%3A78%7D&logFlag=uaction_1523791857874&t=1523791935876","request_type":"image"}
+{"origin":"http://www.mail.ru/","request_url":"https://rs.mail.ru/d27103601.gif?sz=23&rnd=108902987&ts=1523791836&sz=23","request_type":"image"}
+{"origin":"http://www.pornhub.com/","request_url":"https://hw-cdn.contentabc.com/ads/dat_305x99_768192/768192_d377b6b263b30d4d9eff4f1c1c06f4fc.gif","request_type":"image"}
+{"origin":"http://www.microsoft.com/","request_url":"https://dpm.demdex.net/ibs:dpid=58051&dpuuid=d3427dff-e86a-4268-a13d-dbd731c5921d","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=22052&dpuuid=5978151418383291182","request_type":"image"}
+{"origin":"http://www.adobe.com/","request_url":"https://dpm.demdex.net/ibs:dpid=1175&dpuuid=6PlV6O6gCOnwrQTo5aoc77ygUujw-1Pj7P0rMVMK","request_type":"image"}
+{"origin":"http://www.xnxx.com/","request_url":"https://www.xnxx.com/favicon-32x32.png","request_type":"image"}
+{"origin":"http://www.cnn.com/","request_url":"https://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_entertainment.png","request_type":"image"}
+{"origin":"http://www.360.cn/","request_url":"http://p3.qhmsg.com/t01c0561be4b31c1466.png","request_type":"image"}
+{"origin":"http://www.yahoo.co.jp/","request_url":"https://s.yimg.jp/c/icon/s/bsc/2.0/shopping80.png","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"http://www.hao123.com/wise_test.php","request_type":"html"}
+{"origin":"http://www.twitch.tv/","request_url":"https://static-cdn.jtvnw.net/ttv-boxart/IRL-429x572.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/G/31/img18/Watches/April/WRS/GW_blackjack_billboard_1242x450-WomenWatches._SX1242_CB497220605_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/71cSa-wuJxL._AC_SY240_.jpg","request_type":"image"}
+{"origin":"http://www.amazon.com/","request_url":"https://images-na.ssl-images-amazon.com/images/G/01/xba/GIFT3._CB503125777_.jpg","request_type":"image"}
+{"origin":"http://www.so.com/","request_url":"https://p0.ssl.qhimgs4.com/dmsmty/212_160_/t013ace2912a280d12c.webp?size=640x905","request_type":"image"}
+{"origin":"http://www.pixnet.net/","request_url":"https://s.pixfs.net/mobile/images/icons/btn-close.svg","request_type":"image"}
+{"origin":"http://www.google.de/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.google.co.id/","request_url":"https://www.gstatic.com/navigationdrawer/help_icon.svg","request_type":"image"}
+{"origin":"http://www.txxx.com/","request_url":"https://m.txxx.com/assets/mobile/js/modernizr-custom-2.8.3.min.js","request_type":"script"}
+{"origin":"http://www.tmall.com/","request_url":"https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/menu.xtpl.js","request_type":"script"}
+{"origin":"http://www.espn.com/","request_url":"http://a1.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/eng.png&h=60&w=60","request_type":"image"}
+{"origin":"http://www.hao123.com/","request_url":"https://hdj.baidu.com/dianj/?u=default&ie=1&tm=512&cm=512&md=1&at=3&v=naked&cs=&pk=&act=LP&w=&prod=hao123_wise&h=&os=android&appid=f9b6199b&adstrade=&n=40&q=f9b6199b_cpr&sn=B381A494A3AABDC7B0A4AE7F9EACB927&callback=callback_json_1","request_type":"script"}
+{"origin":"http://www.sohu.com/","request_url":"https://pv.sohu.com/suv/?t?=1523791937936654_360_512?r?=?url?=https%3A%2F%2Fm.sohu.com%2F%3Fpvid%3D000115_3w_index%26jump%3Dfront?SUV?=","request_type":"script"}
+{"origin":"http://www.google.com.mx/","request_url":"https://adservice.google.com.mx/adsid/google/ui","request_type":"html"}
+{"origin":"http://www.amazon.co.uk/","request_url":"https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc","request_type":"html"}
+{"origin":"http://www.google.ru/","request_url":"https://www.google.ru/gen_204?atyp=csi&ei=-DfTWri-EumB0wK74IagAg&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&imeb=0&imeo=0&mem=ujhs.11,tjhs.16,jhsl.2190&rt=aft.437,dcl.440,iml.437,ol.2709,prt.253,xjs.1601,xjsee.1601,xjses.1418,xjsls.278,wsrt.2175,cst.699,dnst.0,rqst.844,rspt.453,sslt.373,rqstt.1692,unt.2092,cstt.992,dit.2615&zx=1523791867329","request_type":"html"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.reddit.com/","request_type":"html"}
+{"origin":"http://www.nicovideo.jp/","request_url":"http://ads.nicovideo.jp/api/OxBannerService/logImpression?bannerid=35106&zoneid=461&_=1523791961267","request_type":"text"}
+{"origin":"http://www.msn.com/","request_url":"https://contextual.media.net/kbb.php?cme=KkKUG6JLaWptcd7ygVoZgW_gowIx32vSl5tlbUoHIlTwG_Hajq4qm8TPaunw8hu-gs5H0j_cu9dNg1SpNWSXZk_dUMBskfm2DCZac_fs9rdNqOZacpYzAHiUO_JWt2C2%7C%7CNDHRnZ9Gz3KXlI-i9OnZqQ%3D%3D%7C5gDUJdTGiJzedmq9hanWYg%3D%3D%7CfTACDBAb70YAH7VJEs6iY7FiuYJwPXfy%7CN7fu2vKt8_s%3D%7CYdjFvixrVaHKWoanJxQ7pIbs71hugNrT_9Dy98sN7BVysk146vCoY0D8h8dpPPEv%7CsRBSg3CPSiQ%3D%7C&srp=ypQJNGNB4UQ6DlVQ7Bw1-z5SPb1QMbUwivcE4Sk0S2ZfA87jX7LL1ZDTJ09Aip7a&klp=_9rucIc7-IE6Oa3AYgZDE1ZeZoRWeChb56v-6IPMKYoExR4wMQCnp8lpIW_pmKbx-LYXZLsvrB4Rs8W4woVwz_UhqboNoxbSgsM3mbaNhbt14yZZ2e26ub6W3KcT_Sg47HU5uQxvC_OH5hrwiQEvquVnZqJ0C7tNad-ER39uvXiiHitHFVOylJkde3Z8pdUSXnunHaQqOVjuymLo0TVi2-Pesk9i0gkEZlw2lEaxEcITKMbN2c22Z4Of56ym443k&cb=resultPageUtil.kwdRandmzn[%271523791837719580622%27]","request_type":"script"}
+{"origin":"http://www.reddit.com/","request_url":"https://www.reddit.com/hot.json?redditWebClient=mweb2x&raw_json=1&withAds=true&feature=link_preview&sr_detail=true&app=2x-client-production","request_type":"script"}
+{"origin":"http://www.amazon.in/","request_url":"https://images-eu.ssl-images-amazon.com/images/I/518e5yqTyZL.js?AUIClients/RetailSearchAutocompleteAssets","request_type":"script"} \ No newline at end of file
diff --git a/chromium/components/subresource_filter/core/common/perftests/data/httparchive_request_corpus.csv b/chromium/components/subresource_filter/core/common/perftests/data/httparchive_request_corpus.csv
deleted file mode 100644
index 0fa1b9d1917..00000000000
--- a/chromium/components/subresource_filter/core/common/perftests/data/httparchive_request_corpus.csv
+++ /dev/null
@@ -1,6845 +0,0 @@
-http://www.youtube.com/ https://www.youtube.com/ html
-http://www.youtube.com/ https://m.youtube.com/ html
-http://www.youtube.com/ https://m.youtube.com/yts/cssbin/mobile-nirvana-phone-mangled-vfllYxyuY.css css
-http://www.youtube.com/ https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflgsDWx2/core.js script
-http://www.youtube.com/ https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflgsDWx2/noncore.js script
-http://www.baidu.com/ http://www.baidu.com/ html
-http://www.youtube.com/ https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflgsDWx2/logged_out_users.js script
-http://www.baidu.com/ https://m.baidu.com/?from=844b&vit=fps html
-http://www.youtube.com/ https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflgsDWx2/watch.js script
-http://www.baidu.com/ https://m.baidu.com/static/index/plus/plus_logo.png image
-http://www.wikipedia.org/ https://www.wikipedia.org/ html
-http://www.baidu.com/ https://m.baidu.com/static/index/plus/public/icon_police.png image
-http://www.youtube.com/ https://fonts.gstatic.com/s/roboto/v18/QHD8zigcbDB8aPfIoaupKOvvDin1pK8aKteLpeZ5c0A.ttf font
-http://www.wikipedia.org/ https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikipedia-logo-v2@2x.png image
-http://www.baidu.com/ https://hpd.baidu.com/v.gif?tid=365&funcSta=whiteScreenEx&sourceSta=wiseindex&actionSta=start&logid=1817903589&ssid=0&ct=1&cst=9&logFrom=mid_news&logInfo=stability image
-http://www.wikipedia.org/ https://www.wikipedia.org/portal/wikipedia.org/assets/img/sprite-6e35f464.svg image
-http://www.youtube.com/ https://fonts.gstatic.com/s/roboto/v18/RxZJdnzeo3R5zSexge8UUSZ2oysoEQEeKwjgmXLRnTc.ttf font
-http://www.baidu.com/ https://hpd.baidu.com/v.gif?tid=13&ct=1&cst=1&logFrom=index&logInfo=index&ssid=0&from=844b&pu=sz%40320_1001%2Cta%40iphone_2_6.0_3_537&qid=1817903589&sid=120388_110317_114552_117039_104885_121253_120215_118884_118861_118838_118836_118804_107315_121254_121534_121215_117332_121861_117428_120608_121560_121044_121423_120943_121042_121363_120482_121618_121107_120851_121603_120035_116409_121361_110085_121375&logid=1817903589&ref=index_iphone&r=l1516015819450 image
-http://www.wikipedia.org/ https://www.wikipedia.org/portal/wikipedia.org/assets/js/index-47f5f07682.js script
-http://www.youtube.com/ https://accounts.google.com/ServiceLogin?hl=en&service=youtube&uilel=3&passive=true&continue=https%3A%2F%2Fm.youtube.com%2Fsignin%3Fnext%3Dhttps%253A%252F%252Fm.youtube.com%252Fsignin_passive%253Foriginal_url%253Dhttps%25253A%25252F%25252Fm.youtube.com%25252F%26action_handle_signin%3Dtrue%26feature%3Dmobile_passive%26hl%3Den%26noapp%3D1%26app%3Dm&ltmpl=mobile other
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/iconfont/iconfont_04b353e.woff font
-http://www.wikipedia.org/ https://www.wikipedia.org/portal/wikipedia.org/assets/js/gt-ie9-011f8dbfa9.js script
-http://www.youtube.com/ https://m.youtube.com/feed?ajax=1&layout=mobile&tsp=1&utcoffset=-480 text
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/ns_diff_color_v3_991d8b3.png image
-http://www.wikipedia.org/ https://www.wikipedia.org/portal/wikipedia.org/assets/img/Wikinews-logo_sister@2x.png image
-http://www.youtube.com/ https://m.youtube.com/yts/imgbin/mobile-inverted_phone-set-vhigh-vflX17Zn4.png image
-http://www.baidu.com/ https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=677347038,1655274655&fm=173&s=69C23A666626011759A96C920100C091&w=218&h=146&img.JPEG image
-http://www.wikipedia.org/ https://www.wikipedia.org/static/favicon/wikipedia.ico image
-http://www.youtube.com/ https://m.youtube.com/gen_204?action=screen_dimensions&dimension=512x360&isTablet=0&isBigTablet=0 html
-http://www.baidu.com/ https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=42343404,591908257&fm=173&s=D1A8B955E6307F940E3CC1C70300E0A3&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://www.facebook.com/ html
-http://www.youtube.com/ https://www.gstatic.com/feedback/js/help/prod/service/lazy.min.js script
-http://www.baidu.com/ https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=121945147,3695672295&fm=173&s=07940E64CE264B2E4C0AE5CA0300E09A&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr html
-http://www.youtube.com/ https://m.youtube.com/yts/cssbin/mobile-html5-player-mweb-2x-mangled-vflcIeF5V.css css
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3iuD54/yQ/l/en_US/uCXzZQ_RB5I.js script
-http://www.baidu.com/ https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=3453257726,1285179350&fm=173&s=8D8BA3557AAA073AD139E00D0300F047&w=218&h=146&img.JPEG image
-http://www.youtube.com/ https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflgsDWx2/pubsub.js script
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/yV/l/0,cross/W-02DUeBWlW.css css
-http://www.youtube.com/ https://m.youtube.com/yts/jsbin/mobile-blazer-nirvana-phone-vflgsDWx2/desktopplayer.js script
-http://www.baidu.com/ https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2875601611,1145535095&fm=173&s=1D955C904903034B0495BC85030070C0&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/yq/l/0,cross/8H3935MX1ye.css css
-http://www.youtube.com/ https://m.youtube.com/yts/favicon-vfl8qSV2F.ico image
-http://www.baidu.com/ https://ss0.bdstatic.com/9bA1vGfa2gU2pMbfm9GUKT-w/timg?searchbox_feed&size=f660_370&quality=80&wh_rate=0&imgtype=0&ref=http%3A%2F%2Fwww.baidu.com&sec=0&di=45ccbb3ed9486506e18e2128b95ee8a4&src=http%3A%2F%2Fboscdn.bpc.baidu.com%2Fv1%2Fmediaspot%2F2c4eeef564fedad9bebd390d0a733f10.jpeg image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/yu/l/0,cross/U3gVo4J-zBa.css css
-http://www.youtube.com/ https://googleads.g.doubleclick.net/pagead/id script
-http://www.baidu.com/ https://ss0.baidu.com/6ONWsjip0QIZ8tyhnq/it/u=4266091290,3430474053&fm=173&s=729634C10C1B0A57401FE19F0300B0C3&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/y8/r/fBjA8_IwJif.png image
-http://www.youtube.com/ https://www.google.com/pagead/lvz?pg=feed&evtid=ADGABQpXQLPlcU1RT0r58wjhoRpUYv87_kCYqpelB1YJo1ZIO8aL-zTCxuUyPpn-8UXWOAHDvrs_VXyzQDXAwkoi-4DvQX3BYw&req_ts=1516015817&sigh=AIqYTPiEqBkaF3t4xrrPM-ULl6mqA87nYg image
-http://www.baidu.com/ https://m.baidu.com/?action=static&ms=1&version=css_page_2@0,css_callapp@0,css_weather@0,css_icon@0,css_plus@0,css_edit@0,css_modal@0,css_widget_sug@0,css_skin@0,js_esl@0,js_zepto@0,js_event@0,js_fastclick@0,js_utils@0,js_smartymonkey@0,js_index@0,js_banner_ctrl@0,js_inputlog@0,js_bdnow@0,js_nctips@0,js_widget_textinput@0,js_widget_sug@0,js_mp@0,js_hash_lib@0,js_skinRenderIndex@0,js_skinIphone@0,js_prefetch@0,js_sug@0,js_iscroll@0,js_superframe@0,js_init@0,js_geolocation@0,js_login@0,js_tab@0,js_md5@0,js_url@0,js_lswrite@0,js_modal@0,js_thirdparty@0,js_m_monitor@0,js_superstart@0,js_baiduloc@0,js_callbaiduapp_android@0&callback=B.getCode&r=558&sid=120388_110317_114552_117039_104885_121253_120215_118884_118861_118838_118836_118804_107315_121254_121534_121215_117332_121861_117428_120608_121560_121044_121423_120943_121042_121363_120482_121618_121107_120851_121603_120035_116409_121361_110085_121375 script
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/y7/r/Y2MjxbM6lz1.png image
-http://www.youtube.com/ https://yt3.ggpht.com/--sVrVezsAIo/AAAAAAAAAAI/AAAAAAAAAAA/XzCXxvGiWs0/s68-c-k-no-mo-rj-c0xffffff/photo.jpg image
-http://www.baidu.com/ https://ss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=255931969,685089572&fm=173&s=4FA68744260B1B514CA4F81D030070C0&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/yN/r/Y8VrvG-1crh.png image
-http://www.youtube.com/ https://yt3.ggpht.com/-dDZUkj9sY4g/AAAAAAAAAAI/AAAAAAAAAAA/oy6dm2Uy8dc/s68-c-k-no-mo-rj-c0xffffff/photo.jpg image
-http://www.baidu.com/ https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=2181539963,180491322&fm=173&s=BDD24D819853B9C2168C50810300E082&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://facebook.com/security/hsts-pixel.gif?c=3.2 image
-http://www.youtube.com/ https://yt3.ggpht.com/-KX9kUq2mCFc/AAAAAAAAAAI/AAAAAAAAAAA/PGvxMGahIDg/s68-c-k-no-mo-rj-c0xffffff/photo.jpg image
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/newtab/img/fetch_ing_8_0.png image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3i9Cc4/y7/l/en_US/Y4QrWpwBQcp.js script
-http://www.youtube.com/ https://yt3.ggpht.com/-x-pKW1yb6y8/AAAAAAAAAAI/AAAAAAAAAAA/jPbMU4ZW0sA/s68-c-k-no-mo-rj-c0xffffff/photo.jpg image
-http://www.baidu.com/ https://ss0.bdstatic.com/9bA1vGfa2gU2pMbfm9GUKT-w/timg?searchbox_feed&size=f660_370&quality=80&wh_rate=0&imgtype=0&ref=http%3A%2F%2Fwww.baidu.com&sec=0&di=23b58f894ba2c9f6cf2e276c4c14974f&src=http%3A%2F%2Fpic.rmb.bdstatic.com%2Fbbbfddec2bdd78545a76a90951710826.png image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3idIr4/yB/l/en_US/W4N2GCXXqJM.js script
-http://www.youtube.com/ https://yt3.ggpht.com/-l3M-PF3Tvg0/AAAAAAAAAAI/AAAAAAAAAAA/vFUsylcbewc/s68-c-k-no-mo-rj-c0xffffff/photo.jpg image
-http://www.baidu.com/ https://m.baidu.com/se/static/img/iphone/logo.png image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/yv/r/r5OOMr3H5k1.js script
-http://www.youtube.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjssezP2c-13r5LkZC2SIUCrj_RQ4J3XjO9DZzZt2iMb31q3lPtWDFjvofur_KuTk6uEHiiTdS_1cr1tyIVGmTJTgUF9SP3K-NFog22XdnFb8Ot7rBmCzh65-LAeQ4OrRcEWoC7nC2b296iMdMb-gEtUR3RrIW1dfV2R-O3Dv6-gbvlCIZImtPoCL-GKN_NKd0RQix2cTgsfvtdDEG5crBeoXf4USVw&sig=Cg0ArKJSzHCxmmzcO2tWEAE&urlfix=1&adurl= html
-http://www.baidu.com/ https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=1409134235,2826944481&fm=173&s=1C70C80356733B84660829B70300C083&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://fbcdn.net/security/hsts-pixel.gif?c=2 image
-http://www.youtube.com/ https://ad.doubleclick.net/ddm/ad/N6595.127733.YOUTUBE/B6395408.212606383;sz=1x1;ord=130269364;dc_lat=;dc_rdid=;tag_for_child_directed_treatment= html
-http://www.baidu.com/ https://ss2.baidu.com/6ONYsjip0QIZ8tyhnq/it/u=1827088178,3533159054&fm=173&s=18848B554C1277C84C34815F03009073&w=218&h=146&img.JPEG image
-http://www.facebook.com/ https://staticxx.facebook.com/common/referer_frame.php html
-http://www.youtube.com/ https://i.ytimg.com/vi/APp4PIZ-4YA/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLC4BapriF2tORmotJ8PO0cT9Wzfbg image
-http://www.baidu.com/ https://m.baidu.com/se/static/img/iphone/tab_loading__bg_logo.png image
-http://www.facebook.com/ https://m.facebook.com/sem_campaigns/sem_pixel_test/?google_pixel_category=4&google_pixel_src=https%3A%2F%2Fgoogleads.g.doubleclick.net%2Fpagead%2Fviewthroughconversion%2F995153884%2F%3Fvalue%3D1.00%26currency_code%3DUSD%26label%3DctneCPPWkWAQ3K_D2gM%26guid%3DON%26script%3D0&encoded_one=AQTmJh7oHcy6ZcMp2bugDmImJN6i73Ex6wiwIAHRLZirI6TxwUiXLhQqkTovLdYawCnes8G6YAwLIfnNZWhMkwsw&encoded_two=AQRt2-dYH-y6mcS9ryytGoOsPy1F8BZNEkGph3UKdvxE-sk3PYBzHJ-lo0zzUfh5i7Wi_wKoHzeHM5DKjT_d4M5b html
-http://www.youtube.com/ https://i.ytimg.com/vi/AcMmLmvOYTo/sddefault.jpg image
-http://www.baidu.com/ https://m.baidu.com/static/search/clear.png image
-http://www.facebook.com/ https://fbsbx.com/security/hsts-pixel.gif image
-http://www.youtube.com/ https://i.ytimg.com/vi/AiyZ92_JZxA/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLAA6rkEZsu_EX4MJj19v227HhB6Zg image
-http://www.baidu.com/ https://m.baidu.com/se/static/js/dep/ralltiir.min_1a3d103.js script
-http://www.facebook.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/995153884/?value=1.00&currency_code=USD&label=ctneCPPWkWAQ3K_D2gM&guid=ON&script=0 image
-http://www.youtube.com/ https://i.ytimg.com/vi/Ko-Obw6Ee7I/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLCbi2kNTKEhQJcNZg2pGEccvtQAFQ image
-http://www.baidu.com/ https://m.baidu.com/his?callback=jsonp1&type=3&pic=1&lid=1817903589&ishome=1&net=&islogin=0&hissid=120388,110317,114552,117039,104885,121253,120215,118884,118861,118838,118836,118804,107315,121254,121534,121215,117332,121861,117428,120608,121560,121044,121423,120943,121042,121363,120482,121618,121107,120851,121603,120035,116409,121361,110085,121375&_=1516015823202 script
-http://www.facebook.com/ https://www.google.com/ads/user-lists/995153884/?value=1.00&currency_code=USD&label=ctneCPPWkWAQ3K_D2gM&guid=ON&script=0&cdct=2&is_vtc=1&random=491008095 image
-http://www.youtube.com/ https://i.ytimg.com/vi/CH9yvMGeHfo/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLAAp32YDIS9datd3YI3owiV3UwU1Q image
-http://www.facebook.com/ https://static.xx.fbcdn.net/rsrc.php/v3/ya/r/O2aKM2iSbOw.png image
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/js/package/newsActivity_f6d3b0f.js script
-http://www.youtube.com/ https://i.ytimg.com/vi/Y73jjPOiePc/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLDaU7wB1KrtBh5OcYwbRQRXvFts_w image
-http://www.baidu.com/ https://m.baidu.com/se/static/js/service/index_seloader_release.js?v=25266930 script
-http://www.youtube.com/ https://i.ytimg.com/vi/FI_fCBRicyY/hq720.jpg?sqp=-oaymwEhCK4FEIIDSFryq4qpAxMIARUAAAAAGAElAADIQj0AgKJD&rs=AOn4CLBJt2s9hjIdEi3pTXmbpd8Eo_o8xQ image
-http://www.baidu.com/ https://m.baidu.com/tc?tcreq4log=1&r=1516015823109&logid=1817903589&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=10&cst=1&ref=index_iphone&logFrom=index text
-http://www.youtube.com/ https://m.youtube.com/csi_204?v=2&s=youtube_mobile&action=home&e=23705739,23708904,23708906,23708910,23710476,23713711,23713888,23715611,23718333,23719526,23719816,9422596,9431754,9449243,9460172,9474595,9484237,9484344,9485000&yt_sts=dhs&yt_vis=1&rc=&p=h2&t=tcp&yt_pt=html5&yt_nt=wifi&yt_lt=cold&rt=asr.5720,ol.5799,rsf_mbcj.2732,rse_mbcj.3483,rsf_mbc.2717,rse_mbc.3045,rsf_mblouj.2742,rse_mblouj.3774,rsf_mbnj.2741,rse_mbnj.4028,rsf_mbpc.5397,rse_mbpc.5931,rsf_mbwj.2741,rse_mbwj.4046,aft.5799,nreqs.2257,nress.2607,nrese.2621,srt.2607 html
-http://www.baidu.com/ https://m.baidu.com/se/static/js/service/index_polymer_fbd2fce.js script
-http://www.youtube.com/ https://s0.2mdn.net/viewad/2992003/geico_1x1.jpg image
-http://www.baidu.com/ https://m.baidu.com/se/static/js/dep/atom.min_373895d.js script
-http://www.youtube.com/ https://m.youtube.com/youtubei/v1/log_event?alt=json&key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8 script
-http://www.baidu.com/ https://feed.baidu.com/feed/api/tab/gettabinfo?pd=wise&sid=120388_110317_114552_117039_104885_121253_120215_118884_118861_118838_118836_118804_107315_121254_121534_121215_117332_121861_117428_120608_121560_121044_121423_120943_121042_121363_120482_121618_121107_120851_121603_120035_116409_121361_110085_121375&ssid=0&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&qid=1817903589&ms=1&cb=indJsonp&current_data=%22%22&_=1516015823249&cb=jsonp2 html
-http://www.baidu.com/ http://127.0.0.1:59468/?data=fCMxIzsjMi8xLzUjLSMyIzsjdDZnRDlRaUZEMWtQW3lJbnhbZ0s1V2JJTjpYbjl6Vkh7NnhNY0dpbHc1aFdac3BVM2xTRUtndVJwS1tYUkt3dUNmWFhyem1UU3pHRGdmc1ZMe1BVS25RYllXaFpucVViZmRjQklDNW5lNkd6Y29nW1hKRHM4RFNmQjA1TzpOWngjLSMzIzsjOTU1Y305NTVjIy0jNCM7MjYyNzEyNjkzNjE5Nn4%3D other
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/itemrep/bottomBanner/index_ffa4760.js script
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/itemrep/channelMgr/index_c70dc69.js script
-http://www.baidu.com/ https://m.baidu.com/static/ecom/js/wise/home/nativeAds_68eb76d.js script
-http://www.baidu.com/ https://s.bdstatic.com/common/openjs/openBox.js?_v=2018-01-15-3 script
-http://www.baidu.com/ https://m.baidu.com/static/index/plus/public/tab_news.png image
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/js/package/superframe_545f0a9.js script
-http://www.baidu.com/ https://s.bdstatic.com/common/openjs/bdbanner.js?bd-reform-version=2018011503 script
-http://www.baidu.com/ https://hpd.baidu.com/v.gif?logid=1817903589&ssid=0&sid=120388_110317_114552_117039_104885_121253_120215_118884_118861_118838_118836_118804_107315_121254_121534_121215_117332_121861_117428_120608_121560_121044_121423_120943_121042_121363_120482_121618_121107_120851_121603_120035_116409_121361_110085_121375&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=1&cst=1&logFrom=mid_news&logInfo=a2_l*&logExtra=%7B%22st%22%3A%22news%22%2C%22rid%22%3A%229802602849811423014%22%2C%22isBaijiahao%22%3A1%2C%22extra%22%3A%22%7B%5C%22mark%5C%22%3A0%2C%5C%22mark_rec%5C%22%3A0%2C%5C%22rec_src%5C%22%3A%5B5%5D%2C%5C%22top%5C%22%3A1%2C%5C%22dispatch_time%5C%22%3A1516015818%2C%5C%22msrcid%5C%22%3A80001%2C%5C%22mthid%5C%22%3A%5C%221567805706555546%5C%22%2C%5C%22mrtype%5C%22%3A%5C%22text%5C%22%7D%22%2C%22title%22%3A%22%5Cu5168%5Cu9762%5Cu4ece%5Cu4e25%5Cu6cbb%5Cu515a%5Cuff0c%5Cu4e60%5Cu8fd1%5Cu5e73%5Cu63d0%5Cu51fa%5Cu54ea%5Cu4e9b%5Cu8981%5Cu6c42%5Cuff1f%22%2C%22picNum%22%3A0%2C%22stype%22%3A0%2C%22itemType%22%3A%22newsTitle%22%2C%22pos%22%3A1%7D%2C%7B%22st%22%3A%22answer%22%2C%22rid%22%3A%2210534384611603806863%22%2C%22extra%22%3A%22%7B%5C%22ac%5C%22%3A0%2C%5C%22category%5C%22%3A-1%2C%5C%22channel_id%5C%22%3A1%2C%5C%22city%5C%22%3A%5C%22%5C%22%2C%5C%22cs%5C%22%3A%5C%223545573268%20981851826%5C%22%2C%5C%22district%5C%22%3A%5C%22%5C%22%2C%5C%22event_hot%5C%22%3A0%2C%5C%22gbdt_score%5C%22%3A0.15321686377859%2C%5C%22gr_merge_score%5C%22%3A0%2C%5C%22gr_pred_score%5C%22%3A0%2C%5C%22high_level_flag%5C%22%3A0%2C%5C%22important_news%5C%22%3A0%2C%5C%22intervene_level%5C%22%3A0%2C%5C%22is_tab_recommend%5C%22%3A0%2C%5C%22low_quality_sensin_ctr%5C%22%3A-1%2C%5C%22manual_edit%5C%22%3A1%2C%5C%22mark%5C%22%3A1%2C%5C%22mark_rec%5C%22%3A1%2C%5C%22mthid%5C%22%3A%5C%22-1%5C%22%2C%5C%22new_cat%5C%22%3A%5C%22%5C%5Cu56fd%5C%5Cu5185%5C%22%2C%5C%22new_sub_cat%5C%22%3A%5C%22%5C%5Cu7efc%5C%5Cu5408%5C%22%2C%5C%22odus%5C%22%3A0%2C%5C%22offline_rank_score%5C%22%3A434.0346841%2C%5C%22predictor_result%5C%22%3A%5C%22CAEZAACOF4HwwEA%3D%5C%22%2C%5C%22province%5C%22%3A%5C%22%5C%22%2C%5C%22public_time%5C%22%3A0%2C%5C%22q_ratio%5C%22%3A1.1378951774007%2C%5C%22r_att_src%5C%22%3A1000%2C%5C%22rec_src%5C%22%3A%5B34%5D%2C%5C%22rec_tabs%5C%22%3A%5C%22%5C%22%2C%5C%22recall_type%5C%22%3A1%2C%5C%22rela_score%5C%22%3A0%2C%5C%22score%5C%22%3A9868.9745813581%2C%5C%22srccat%5C%22%3A0%2C%5C%22srcid%5C%22%3A81280%2C%5C%22tag%5C%22%3A0%2C%5C%22tj_timeliness%5C%22%3A604800%2C%5C%22type%5C%22%3A1%2C%5C%22ua%5C%22%3A%5C%220_0_android_6.0_0%5C%22%2C%5C%22user_active%5C%22%3A-1%2C%5C%22user_hotnews_level%5C%22%3A3%2C%5C%22user_profile%5C%22%3A0%2C%5C%22ut%5C%22%3A%5C%220_6.0_0_0%5C%22%2C%5C%22vertical_type%5C%22%3A0%2C%5C%22dispatch_time%5C%22%3A1516015818%2C%5C%22msrcid%5C%22%3A81280%7D%22%2C%22title%22%3A%22%5Cu201c%5Cu6851%5Cu5409%5Cu201d%5Cu8f6e%5Cu5168%5Cu8239%5Cu7206%5Cu71c3%5Cu540e%5Cu6c89%5Cu6ca1%5Cuff0c%5Cu8fd9%5Cu573a%5Cu4e8b%5Cu6545%5Cu7684%5Cu4e8b%5Cu6001%5Cu4f1a%5Cu5982%5Cu4f55%5Cu53d1%5Cu5c55%5Cuff1f%22%2C%22picNum%22%3A3%2C%22stype%22%3A1%2C%22flow%22%3A12%2C%22itemType%22%3A%22newsThree%22%2C%22pos%22%3A2%7D&r=l1516015825883 image
-http://www.baidu.com/ https://m.baidu.com/?action=getadsdata&sourceChannel=&pagetype=1&sid=120388_110317_114552_117039_104885_121253_120215_118884_118861_118838_118836_118804_107315_121254_121534_121215_117332_121861_117428_120608_121560_121044_121423_120943_121042_121363_120482_121618_121107_120851_121603_120035_116409_121361_110085_121375&from=wise_index_banner&_=1516015826167&callback=jsonp3 html
-http://www.google.com/ http://www.google.com/ html
-http://www.baidu.com/ https://hm.baidu.com/hm.gif?si=c42dc7b5fa22eba9c22b2ca4d8829372&et=0&v=pixel-1.0&u=https%3A%2F%2Fm.baidu.com%2Fexp%2Ffailed%3Fv%3D1.0.4&rnd=1655930606 image
-http://www.baidu.com/ https://hm.baidu.com/hm.js?12423ecbc0e2ca965d84259063d35238 script
-http://www.google.com/ https://www.google.com/?gws_rd=ssl html
-http://www.baidu.com/ https://m.baidu.com/static/search/baiduapp_icon.png image
-http://www.google.com/ https://www.google.com/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.baidu.com/ https://m.baidu.com/static/index/phonebox.png image
-http://www.google.com/ https://www.google.com/images/nav_logo242_hr.webp image
-http://www.baidu.com/ https://ext.baidu.com/rest/id-mapping/cuid?callback=_box_jsonp848 script
-http://www.google.com/ https://www.google.com/gen_204?s=webaft&atyp=csi&ei=wpBcWoqpJ9KcjwPL5oOIDg&rt=wsrt.1783,aft.150,prt.150 html
-http://www.baidu.com/ https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=1229626250&si=12423ecbc0e2ca965d84259063d35238&v=1.2.27&lv=1&ct=!!&tt=%E7%99%BE%E5%BA%A6%E4%B8%80%E4%B8%8B&sn=60208 image
-http://www.google.com/ https://www.google.com/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.baidu.com/ https://wapsite.baidu.com/static/tj.gif?_=1516015826755&cuid=-&pid=516381015705994&page=sepcial_nbpz_wise&pos=disp_float&status=100002&tnfrom=22872_0&platform=android&browser=6 image
-http://www.google.com/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/js/plugin/safariicon_6bd009a.js script
-http://www.google.com/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.baidu.com/ https://m.baidu.com/tc?tcreq4log=1&r=1516015829377&logid=1817903589&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=10&cst=2&ref=index_iphone&logFrom=callbaidu&logInfo=%7B%22value%22%3A%22try%22%7D text
-http://www.google.com/ https://www.google.com/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.baidu.com/ https://m.baidu.com/tcbox?service=bdbox&action=pblog&ctv=2&cen=uid_ua_ut&data=%7B%22appid%22%3A%221%22%2C%22dataid%22%3A%222%22%2C%22actiontype%22%3A%221%22%2C%22actionid%22%3A%222%22%2C%22actiondata%22%3A%7B%22ref%22%3A%22%22%2C%22gmv%22%3A%22%22%2C%22source%22%3A%22844b%22%2C%22boxVersion%22%3A0%2C%22boxPlatform%22%3A%22android%22%2C%22evtName%22%3A%22openBox%22%2C%22evtType%22%3A%221020684i%22%2C%22evtTag%22%3A%7B%22source%22%3A%221020684i%22%2C%22from%22%3A%22openbox%22%2C%22page%22%3A%22chrome%22%2C%22type%22%3A%22%22%2C%22value%22%3A%22%22%2C%22channel%22%3A%22%22%2C%22extlog%22%3A%22%22%2C%22baiduId%22%3A%22BDA1F3466C6DB68472F64829531016B4%3AFG%3D1%22%2C%22app_now%22%3A%22chrome_1516015829392_2594510548%22%2C%22yyb_pkg%22%3A%22com.baidu.searchbox%22%2C%22idmData%22%3A%7B%22firstOpen%22%3A%22lite%22%2C%22secondOpen%22%3A%22main%22%2C%22status%22%3A%220%22%2C%22timeout%22%3A1516102228348%7D%2C%22matrix%22%3A%22lite%22%7D%7D%2C%22cateid%22%3A14%7D&_rnd=1521077821 html
-http://www.google.com/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.baidu.com/ https://gss0.bdstatic.com/5bd1bjqh_Q23odCf/static/wiseindex/img/favicon64.ico image
-http://www.google.com/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.baidu.com/ https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A3546%2C%22netDns%22%3A1583%2C%22netTcp%22%3A621%2C%22srv%22%3A786%2C%22dom%22%3A4031%2C%22loadEvent%22%3A15258%7D&et=87&ja=0&ln=en-us&lo=0&rnd=710871627&si=12423ecbc0e2ca965d84259063d35238&v=1.2.27&lv=1 image
-http://www.google.com/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.baidu.com/ https://m.baidu.com/tc?tcreq4log=1&r=1516015831496&logid=1817903589&from=844b&pu=sz%2540320_1001%252Cta%2540iphone_2_6.0_3_537&ct=10&cst=2&ref=index_iphone&logFrom=callbaidu&logInfo=%7B%22value%22%3A%22fail%22%7D text
-http://www.google.com/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.com/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.google.com/ https://www.google.com/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.com/ https://www.google.com/images/nav_logo242.png image
-http://www.google.com/ https://www.google.com/gen_204?atyp=csi&ei=wpBcWoqpJ9KcjwPL5oOIDg&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.614,dcl.318,iml.614,ol.2408,prt.148,xjs.1544,xjsee.1543,xjses.1172,xjsls.170,wsrt.1783,cst.635,dnst.0,rqst.737,rspt.373,sslt.337,rqstt.1283,unt.645,cstt.645,dit.2102&zx=1516015813406 html
-http://www.google.com/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.com/ https://www.google.com/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.com/ https://adservice.google.com/adsid/google/ui html
-http://www.google.co.in/ http://www.google.co.in/ html
-http://www.google.co.in/ https://www.google.co.in/?gws_rd=ssl html
-http://www.google.co.in/ https://www.google.co.in/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.co.in/ https://www.google.co.in/images/nav_logo242_hr.webp image
-http://www.google.co.in/ https://www.google.co.in/gen_204?s=webaft&atyp=csi&ei=DJFcWraDHNTSjwOkuYT4Dw&rt=wsrt.2090,aft.253,prt.253 html
-http://www.google.co.in/ https://www.google.co.in/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.co.in/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.co.in/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.co.in/ https://www.google.co.in/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.co.in/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.co.in/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.co.in/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.google.co.in/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.co.in/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.co.in/ https://www.google.co.in/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.co.in/ https://www.google.co.in/images/nav_logo242.png image
-http://www.google.co.in/ https://www.google.co.in/gen_204?atyp=csi&ei=DJFcWraDHNTSjwOkuYT4Dw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.591,dcl.383,iml.591,ol.2281,prt.253,xjs.1469,xjsee.1468,xjses.1128,xjsls.293,wsrt.2091,cst.652,dnst.0,rqst.736,rspt.372,sslt.353,rqstt.1593,unt.937,cstt.937,dit.2472&zx=1516015887087 html
-http://www.google.co.in/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.co.in/ https://www.google.co.in/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.co.in/ https://adservice.google.co.in/adsid/google/ui html
-http://www.qq.com/ http://www.qq.com/ html
-http://www.qq.com/ http://mat1.gtimg.com/www/qq_index/css/qq_e52f4f3f.css css
-http://www.qq.com/ http://mat1.gtimg.com/www/css/qq2012/hot_word_sogou.css css
-http://www.qq.com/ http://xw.qq.com/index.htm html
-http://www.qq.com/ http://pingjs.qq.com/ping.js script
-http://www.qq.com/ https://xw.qq.com/index.htm html
-http://www.qq.com/ https://xw.qq.com/service-worker.js script
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/elevator_icons_v0.svg image
-http://www.qq.com/ https://mat1.gtimg.com/pingjs/ext2020/xw-next/_next/b6695a827aadb914d53b81a2eee713cc/app.js script
-http://www.qq.com/ https://mat1.gtimg.com/pingjs/ext2020/xw-next/_next/53cae6c6-4105-430d-9cff-c988d6cf6fee/page/_error/index.js script
-http://www.qq.com/ https://mat1.gtimg.com/pingjs/ext2020/xw-next/_next/53cae6c6-4105-430d-9cff-c988d6cf6fee/page/index.js script
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/siteheader-skin-default.svg image
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/logo-text-white.svg image
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/image-placeholder-logo.svg image
-http://www.qq.com/ https://mat1.gtimg.com/libs/workbox-sw/2.1.2/workbox-sw.prod.v2.1.2.js script
-http://www.qq.com/ https://www.googletagmanager.com/gtag/js?id=UA-110817881-1 script
-http://www.qq.com/ https://pingjs.qq.com/h5/stats.js script
-http://www.qq.com/ https://pingjs.qq.com/tcss.ping.https.js script
-http://www.qq.com/ https://mat1.gtimg.com/libs/t/finalboss-lite/0.1.7/finalboss-lite.min.js script
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/weather/00.svg image
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/location_black.svg image
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/arrow-right-fff.svg image
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/section-title-24hours.svg image
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/section-title-dujia.svg image
-http://www.qq.com/ https://img1.gtimg.com/rcdimg/20180110/09/30442229.png image
-http://www.qq.com/ https://xw.qq.com/offline.html?_workbox-precaching=11dd7d40996e6d25e0706b6840e678d8 html
-http://www.qq.com/ https://inews.gtimg.com/newsapp_ls/0/2708426098_294195/0 image
-http://www.qq.com/ https://inews.gtimg.com/newsapp_ls/0/2708467266_294195/0 image
-http://www.qq.com/ https://inews.gtimg.com/newsapp_ls/0/2708778478_294195/0 image
-http://www.qq.com/ https://inews.gtimg.com/newsapp_ls/0/2704970628_640330/0 image
-http://www.qq.com/ https://fw.qq.com/ipwhere?callback=jsonp_5021338300446 html
-http://www.qq.com/ https://www.google-analytics.com/analytics.js script
-http://www.qq.com/ https://pingtas.qq.com/webview/pingd?dm=xw.qq.com&pvi=983121516015908666&si=s35921516015908667&url=/index.htm&arg=&ty=1&rdm=www.qq.com&rurl=/&rarg=&adt=&r2=500092411&scr=360x512&scl=24-bit&lg=en-us&tz=8&ext=version=2.0.6&random=1516015908674 html
-http://www.qq.com/ https://btrace.qq.com/kvcollect?BossId=4787&Pwd=1286385847&expo=pv&page=yaowen&channel=yaowen&qq=&source=http%3A%2F%2Fwww.qq.com%2F&pac_uid=&openid=&xw_uid=db5f2a06a&webview=&network=&_dc=94200763 image
-http://www.qq.com/ https://pingfore.qq.com/pingd?dm=www.xw.qq.com&url=/index.htm&rdm=www.qq.com&rurl=/&rarg=-&pvid=8629687888&scr=360x512&scl=24-bit&lang=en-us&java=0&pf=Linux%20x86_64&tz=8&flash=-&ct=-&vs=tcsso.3.1.5&ext=nw%3D1%3Btm%3D37%3Bch%3D2&hurlcn=ad%3Dxw.qq.com&rand=33159&reserved1=-1&tt= other
-http://www.qq.com/ https://wis.qq.com/weather/common?weather_type=observe%7Cforecast_24h%7Cair%7Calarm&source=xw&province=%E5%8C%97%E4%BA%AC%E5%B8%82&city=%E5%8C%97%E4%BA%AC%E5%B8%82&callback=__jp0 script
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/weather/02.svg image
-http://www.qq.com/ https://pingtas.qq.com/webview/pingd?dm=xw.qq.com&pvi=983121516015908666&si=s35921516015908667&url=/index.htm&arg=&ty=0&r2=500421382&scr=360x512&scl=24-bit&lg=en-us&tz=8&random=1516015912007&r3=2526&ext=pfm=0_1168_583_571_719;version=2.0.6 html
-http://www.qq.com/ https://mat1.gtimg.com/www/mobi/2017/image/logo/v0/192.png image
-http://www.reddit.com/ https://www.reddit.com/ html
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/ProductionClient.e1b8f2c7b422c91e68bf4a5cbcfb22c9.css css
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/ProductionClient.557a4ee590a2a26f14aa.js script
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/img/listing-click-pattern.png image
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/img/tutorial-app.png image
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/fonts/rfont.9ef40b74e68730d0c78852e43e4e5a7f.woff font
-http://www.reddit.com/ https://www.reddit.com/hot.json?redditWebClient=mweb2x&raw_json=1&feature=link_preview&sr_detail=true&app=2x-client-production script
-http://www.reddit.com/ https://app.link/_r?sdk=web2.27.0&branch_key=key_live_hoc05HaCXaME10UMwyj3filpqzfu2Ue6&callback=branch_callback__0 script
-http://www.reddit.com/ https://www.reddit.com/api/request_promo.json?app=2x-client-production script
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/GtwaouQ6LNZz9OXJY9eSMEDl1MJwijXbj0xakw2YnEA.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/vkH1wNXl4WrLB5WaWJQfKB2mBeaJAVZtiuXaXW-PR6U.jpg image
-http://www.reddit.com/ https://thumbs.gfycat.com/ElaborateLavishHuia-mobile.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/X8LXFP-317lCHvg-F_sYiZpar2_8bWF68jMWSVOTtxs.jpg image
-http://www.reddit.com/ https://thumbs.gfycat.com/hiddenscornfulfirefly-mobile.jpg xml
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/Uqo2zbHEdmsMM8CJvTJzqroqcYY7UZ_bmYM_VLbMCok.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/J_KVhxgUXJjvXi0i7qL8NYPL22_EFYNmZR1et4Sadls.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/Gxer7wW_xaVuNF1zvFUPAdFKGz8c40BPFSvvwT6EGpQ.jpg image
-http://www.reddit.com/ https://a.thumbs.redditmedia.com/5KFb2L00QWSz3JtFHMTbPFegz5o4iTrty1-ZhNCxKM8.jpg image
-http://www.reddit.com/ https://a.thumbs.redditmedia.com/KYv0KKcnVSQFutJ25YdaAsd3-rFp5KFes1hv7QjowN8.jpg image
-http://www.reddit.com/ https://i.redditmedia.com/Q_PA7KQLRh30QojGcMhHoBde1ny4A1ZG_88trsu6SAQ.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=216&s=ffd15bfb62caae65aded7fe58779eea0 image
-http://www.reddit.com/ https://a.thumbs.redditmedia.com/vF_aWrHVBde0my4uE_GTyHFLFR0z0VJPSMmdUNuBcn4.jpg image
-http://www.reddit.com/ https://i.redditmedia.com/8HBNZvcnU6SowzG7Lc9pY6fhXHfsY33nl_NLaU3AUuE.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=00336ab305e4c1531c8d4c9090488b5b image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/6qkc-G-Isd2jnyeec3P0QQxvwPJ8Wwc29RKi6950XsE.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/voTZ0wMFHLo6ZbEHQGz1lcXmshsaKS-UR1XnZwSi1eI.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/MTXustUR_XaJ8JK-FbK7I4rc-RBSQFcnhQYFzucifaU.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/m89ahWdUpLHQlVAeamShYSDT1DamVcqed-kb12Scbfo.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/_rzCSUKqbDJo_VzmMhsVi7kxoWrIxAeD60ob5SKebGs.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/O0ZMXRuekpPKu7ikr47MxsDRzNL815PyrG76ewvNtpg.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/MFVWG3X1LheWTAY25wDkHeAgFoPfVoVTuv7BwMJwQAw.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/CBQioz81679uZcO6sA4qj9MY-awOOQHy7HY4kxI9dgw.jpg image
-http://www.reddit.com/ https://i.redditmedia.com/r6-5ASy1KkyT7e0oUxyrDTzCT5jdp1nsZNNMv6gZVY4.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=c5e315dd8bdc5b726c408fb264296fdd image
-http://www.reddit.com/ https://api.branch.io/v1/open script
-http://www.reddit.com/ https://i.redditmedia.com/L7NXim8rhgFJG-FwVtl3umXkiXI1I2VbTBMz9TKvbzA.jpg?fit=crop&crop=faces%2Centropy&arh=2&w=108&s=dff47a017f67d88ddaba5b1c47baaaac image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/dxZIIGqLnsO30sPADp6KxKQdvJNX0YJOh63w6x-Ncow.jpg image
-http://www.reddit.com/ https://b.thumbs.redditmedia.com/W0qzgbUCRzQgwCyyu2Dboo9LH6VyYepbOtKrKpmSLjI.jpg image
-http://www.reddit.com/ https://events.redditmedia.com/v1?key=Mweb2&mac=51609e553da4cf8b61c76a7996b3858a4993e3e4a9def7e5fea4930ed5c8ce8d other
-http://www.reddit.com/ https://events.redditmedia.com/v1?key=Mweb2&mac=fc7d4a00c32c33f6183b8d1d4163aae2094c37c547de995b99209a23d0993e1d other
-http://www.reddit.com/ https://api.branch.io/v1/event script
-http://www.reddit.com/ https://www.redditmedia.com/gtm/jail?id=GTM-W7RKT4 html
-http://www.reddit.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.reddit.com/ https://c.amazon-adsystem.com/aax2/apstag.js script
-http://www.reddit.com/ https://www.redditstatic.com/gtm-jail.jTMwZME_TT8.js script
-http://www.reddit.com/ https://www.redditmedia.com/gtm?id=GTM-W7RKT4&cb=null html
-http://www.reddit.com/ https://www.redditstatic.com/gtm.aX_QHhLRPyo.js script
-http://www.reddit.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.reddit.com/ https://adservice.google.com/adsid/integrator.js?domain=www.reddit.com script
-http://www.reddit.com/ https://www.googletagmanager.com/gtm.js?id=GTM-W7RKT4&l=googleTagManager script
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/favicon/64x64.png image
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/favicon/128x128.png image
-http://www.reddit.com/ https://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.reddit.com/ https://www.redditstatic.com/mweb2x/favicon/192x192.png image
-http://www.reddit.com/ https://www.google-analytics.com/analytics.js script
-http://www.reddit.com/ https://sb.scorecardresearch.com/p?c1=2&c2=20632726&cv=2.0&cj=1&c7=https://www.reddit.com/&c4=https://www.reddit.com/ other
-http://www.reddit.com/ https://sb.scorecardresearch.com/p2?c1=2&c2=20632726&cv=2.0&cj=1&c7=https://www.reddit.com/&c4=https://www.reddit.com/ image
-http://www.reddit.com/ https://secure.quantserve.com/aquant.js?a=p-xLEyC0FLYFXAH script
-http://www.reddit.com/ https://rules.quantcount.com/rules-p-xLEyC0FLYFXAH.js script
-http://www.reddit.com/ https://pixel.quantserve.com/pixel;r=687870873;a=p-xLEyC0FLYFXAH;labels=;rf=0;fpan=1;fpa=P0-141100854-1516015976985;ns=1;ce=1;cm=;je=0;sr=360x512x24;enc=n;dst=1;et=1516015976984;tzo=480;ref=;url=https%3A%2F%2Fwww.redditmedia.com%2Fgtm%3Fid%3DGTM-W7RKT4%26cb%3Dnull;ogl= image
-http://www.taobao.com/ http://www.taobao.com/ html
-http://www.taobao.com/ http://m.taobao.com/?sprefer=sypc00 html
-http://www.taobao.com/ https://m.taobao.com/?sprefer=sypc00 html
-http://www.taobao.com/ http://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.taobao.com/ https://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.yahoo.com/ http://www.yahoo.com/ html
-http://www.taobao.com/ https://g.alicdn.com/??zebra-solution/homeintl/1.0.77/index.css,mui/popbox/4.1.0/index.css,mui/zebra-oversea-toolbars/4.0.22/index.css,mui/zebra-oversea-toolbars/4.0.22/svelte.css,mui/zebra-oversea-banner/4.0.16/index.css,mui/zebra-oversea-navigation/4.0.21/index.css,mui/zebra-oversea-supermarket/4.0.12/index.css,mui/zebra-oversea-fliggy/4.0.2/index.css,mui/zebra-oversea-category/4.0.13/index.css,mui/zebra-oversea-header/4.0.2/index.css,mui/zebra-oversea-hotmarket/4.0.5/index.css,mui/zebra-oversea-goodshop/4.0.3/index.css,mui/zebra-oversea-toutiao/4.0.3/index.css,mui/zebra-oversea-yaotong-banner/4.0.3/index.css,mui/slider-m/4.0.9/index.css,mui/zebra-oversea-guess/4.0.29/index.css css
-http://www.yahoo.com/ https://www.yahoo.com/ html
-http://www.taobao.com/ https://g.alicdn.com/??mui/zebra-oversea-toutiao/4.0.3/index.js,mui/zebra-oversea-yaotong-banner/4.0.3/index.js,mui/zebra-oversea-banner/4.0.16/index.xtpl.js,mui/zebra-oversea-subbanner/4.0.0/index.xtpl.js,mui/zebra-oversea-navigation/4.0.21/index.xtpl.js,mui/zebra-oversea-supermarket/4.0.12/index.xtpl.js,mui/zebra-oversea-fliggy/4.0.2/index.xtpl.js,mui/zebra-oversea-category/4.0.13/index.xtpl.js,mui/zebra-oversea-header/4.0.2/index.xtpl.js,mui/zebra-oversea-hotmarket/4.0.5/index.xtpl.js,mui/zebra-oversea-goodshop/4.0.3/index.xtpl.js,mui/zebra-oversea-toutiao/4.0.3/index.xtpl.js,mui/zebra-oversea-yaotong-banner/4.0.3/index.xtpl.js,zebra-pages/oversea-62197/1.0.98/m/index.js,mui/zebra-oversea-monitor/4.0.24/index.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/nn/lib/metro/g/theme/viewer_sm_0.0.2.css css
-http://www.taobao.com/ https://g.alicdn.com/??mui/feloader/4.1.16/feloader-min.js,zebra-solution/homeintl/1.0.77/config.js,mui/babel-polyfill/6.2.6/index.js,mui/bat/4.0.39/index.js,mui/tes/4.2.18/index.js,mui/fetch/4.1.12/fetch.js,mui/fetch/4.1.12/tool.js,mui/fetch/4.1.12/jsonp.js,mui/zepto/4.0.9/zepto.js,mui/mtb-windvane/4.0.3/index.js,mui/mtop/4.1.7/index.js,mui/hybrid/4.2.24/index.js,mui/cookie/4.1.0/index.js,mui/country-location/4.1.3/index.js,mui/oversea-region/4.0.12/index.js,mui/custom-event/4.0.3/index.js,mui/zepto/4.0.9/event.js,mui/popbox/4.1.0/index.js,zebra-solution/homeintl/1.0.77/utils.js,zebra-solution/homeintl/1.0.77/index.js,zebra-pages/oversea-62197/1.0.98/m/js/utils.js,mui/cookie-pass/4.0.2/index.js,mui/zepto/4.0.9/touch.js,mui/login/4.1.20/util.js,mui/login/4.1.20/index.js,mui/lazyload/4.1.7/index.js,mui/crossimage/4.1.30/index.js,mui/zebra-oversea-toolbars/4.0.22/index.js,mui/kissy-polyfill/4.0.16/index.js,mui/xtemplate/4.0.11/runtime/escape-html.js,mui/xtemplate/4.0.11/runtime/util.js,mui/xtemplate/4.0.11/runtime/scope.js,mui/xtemplate/4.0.11/runtime/commands.js,mui/xtemplate/4.0.11/runtime/linked-buffer.js,mui/xtemplate/4.0.11/runtime.js,mui/zebra-oversea-guess/4.0.29/item.xtpl.js,mui/scroll/4.0.2/index.js,mui/location/4.1.0/get-user-location-by-ip.js,mui/zebra-oversea-guess/4.0.29/index.js,mui/url-search-params/4.0.1/index.js,mui/flipsnap/4.0.1/index.js,mui/slider-m/4.0.9/index.js,mui/zebra-oversea-banner/4.0.16/index.js,mui/zebra-oversea-navigation/4.0.21/index.js,mui/zebra-oversea-supermarket/4.0.12/index.js,mui/zebra-oversea-fliggy/4.0.2/index.js,mui/zebra-oversea-category/4.0.13/index.js,mui/zebra-oversea-header/4.0.2/index.js,mui/zebra-oversea-hotmarket/4.0.5/index.js,mui/zebra-oversea-goodshop/4.0.3/index.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/nn/lib/metro/g/myy/advance_base_rc4_0.0.65.css css
-http://www.taobao.com/ https://g.alicdn.com/alilog/mlog/aplus_wap.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/nn/lib/metro/g/myy/font_rc4_0.0.67.css css
-http://www.taobao.com/ https://tbip.alicdn.com/api/getipinfo?callback=jsonp0 html
-http://www.yahoo.com/ https://mbp.yimg.com/sy/nn/lib/metro/g/myy/advance_sm_0.0.43.css css
-http://www.taobao.com/ https://g.alicdn.com/alilog/??s/7.7.0/plugin/aplus_client.js,aplus_cplugin/0.2.11/toolkit.js,aplus_cplugin/0.2.11/monitor.js,s/7.7.0/aplus_wap.js,aplus_cplugin/0.2.11/aol.js,s/7.7.0/plugin/aplus_spmact.js?v=20180109204426 script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/fp/atomic-sm-css.33ab7001.css css
-http://www.taobao.com/ https://h5api-intl.m.taobao.com/h5/mtop.taobao.wireless.home.load/1.0/?jsv=2.4.8&appKey=12574478&t=1516015940233&sign=0415020e13370f4ad58ba73d796b6b24&api=mtop.taobao.wireless.home.load&v=1.0&type=jsonp&dataType=jsonp&callback=mtopjsonp1&data=%7B%22longitude%22%3A%220%22%2C%22latitude%22%3A%220%22%2C%22containerId%22%3A%22intl%22%2C%22edition%22%3A%22%7B%5C%22cityId%5C%22%3A%5C%22undefined%5C%22%2C%5C%22countryId%5C%22%3A%5C%22US%5C%22%2C%5C%22actualLanguageCode%5C%22%3A%5C%22zh-CN%5C%22%7D%22%7D script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/stencil/3.2.1/styles-ltr.css css
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/yc/css/bundle.c60a6d54.css css
-http://www.taobao.com/ https://ocservice.taobao.com/cookieController/processUserCookie?site=US_zh-CN_USD_840&callback=jsonp_40288979 script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/nn/lib/metro/g/myy/polyvore_0.0.3.css css
-http://www.yahoo.com/ https://mbp.yimg.com/sy/rq/darla/3-1-1/js/g-r-min.js script
-http://www.yahoo.com/ https://geo.yahoo.com/b?s=1197228339&t=1164787394&_I=0s8hrq9d5p499&_AO=0&_NOL=0&_R=&_P=_pl%0317%04_ts%031516015913%04_ms%03726%04etrg%03backgroundPost%04navtype%03validation%04outcm%03backgroundPost%04usergenf%030%04_w%03slw1011.fp.gq1.yahoo.com%252F%04test%03900 image
-http://www.taobao.com/ https://suggest.taobao.com/sug?area=sug_hot&wireless=2&code=utf-8&sid=null&nick=&callback=jsonp_4030258 html
-http://www.yahoo.com/ https://s.yimg.com/wm/modern/images/default_user_profile_pic_64.png image
-http://www.taobao.com/ https://img.alicdn.com/tfs/TB1AQzDQFXXXXbgXpXXXXXXXXXX-64-64.ico image
-http://www.taobao.com/ https://g.alicdn.com/secdev/sufei_data/3.0.9/index.js script
-http://www.yahoo.com/ https://s.yimg.com/cv/ae/notifications/push-promo-icon.png image
-http://www.taobao.com/ https://h5api-intl.m.taobao.com/h5/mtop.taobao.wireless.home.load/1.0/?jsv=2.4.8&appKey=12574478&t=1516015942158&sign=aa611b09a879b4e7f2ab545b527cde63&api=mtop.taobao.wireless.home.load&v=1.0&type=jsonp&dataType=jsonp&callback=mtopjsonp2&data=%7B%22longitude%22%3A%220%22%2C%22latitude%22%3A%220%22%2C%22containerId%22%3A%22intl%22%2C%22edition%22%3A%22%7B%5C%22cityId%5C%22%3A%5C%22undefined%5C%22%2C%5C%22countryId%5C%22%3A%5C%22US%5C%22%2C%5C%22actualLanguageCode%5C%22%3A%5C%22zh-CN%5C%22%7D%22%7D script
-http://www.taobao.com/ https://login.taobao.com/jump?target=https://www.tmall.com html
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/Kj6zCVEsvjH4SNiJi4NC3g--~B/Zmk9c3RyaW07aD00MzI7cHlvZmY9MDtxPTgwO3c9NzY4O3NtPTE7YXBwaWQ9eXRhY2h5b24-/https://media.zenfs.com/creatr-images/GLB/2018-01-15/1c591520-f98b-11e7-9614-d3fd5842a437_jamie-lee-curtis-ap-ntk.jpg.cf.jpg image
-http://www.taobao.com/ https://img.alicdn.com/tps/TB1BZYGPVXXXXcZXXXXXXXXXXXX-30-54.png_30x30Q90s50.jpg_.webp image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/mit/td/td-applet-stream-atomic-2.0.1025/r-min.js script
-http://www.taobao.com/ https://img.alicdn.com/tps/TB1JdLDPVXXXXX6XpXXXXXXXXXX-750-70.png_1080x1800Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/mit/td/td-applet-mobile-header-1.0.170/r-min.js script
-http://www.amazon.com/ https://www.amazon.com/ html
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i3/29/TB28awheqLN8KJjSZFmXXcQ6XXa_!!29-0-luban.jpg_1080x1800Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/mit/td/aperollup-min-4e40f372_smartphone.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/21EugTBba7L.css?AUIClients/RetailSearchAutocompleteAssets css
-http://www.taobao.com/ https://img.alicdn.com/tps/TB1Y3HqPVXXXXaCXFXXXXXXXXXX-200-200.png_130x130Q90s50.jpg_.webp image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/yui/yui-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/51qmkBF36fL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,01d8Fs5iBdL.css,21ZwnZnTQ7L.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,318hCTMRXQL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21g9AOmZB5L.css,11X2-nh0PYL.css,01h2e2BEitL.css,11AYjYP-YzL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31k72ulyOYL.css,01kPgnKe7wL.css,01MGoIPodIL.css,01Alnvtt1zL.css,01BBs40O5ZL.css_.css?AUIClients/AmazonUI css
-http://www.taobao.com/ https://img.alicdn.com/tps/TB1QKLFPVXXXXcRXXXXXXXXXXXX-200-200.png_130x130Q90s50.jpg_.webp image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/51jo%2BAP3U9L._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset css
-http://www.yahoo.com/ https://mbp.yimg.com/sy/ss/rapid-3.42.4.js script
-http://www.taobao.com/ https://img.alicdn.com/tps/TB1Md6KPVXXXXamXXXXXXXXXXXX-200-200.png_130x130Q90s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/wv/images/alphatar_100x100_Y_jl.jpg image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/41MjpWujmTL.css?AUIClients/GWMWebAssets css
-http://www.taobao.com/ https://img.alicdn.com/tps/TB1F3e3PVXXXXctaXXXXXXXXXXX-200-200.png_130x130Q90s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/JUmiq1UC.z0N7utv4mYO8w--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/homerun/people_218/a96f32ec3d317fef61b8582f49858ce6 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/airstream/mobile-upnav/C/mobile_upnav_C_latest_1x._CB492140733_.jpg image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/TB2QrNwmsnI8KJjSspeXXcwIpXa_!!170-0-luban.jpg_284x284Q50s50.jpg_.webp image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/gno/sprites/sky_webnav_V1_sprite_1x._CB515697137_.png image
-http://www.yahoo.com/ https://s.yimg.com/cv/ae/default/170721/wide-trans-16-9.gif image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i4/163/TB2cUFOc50TMKJjSZFNXXa_1FXa_!!163-0-yamato.jpg_284x284Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/wv/images/alphatar_100x100_P_jd_6-16.jpg image
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DD8CDZ20FD8M1403SAHVK%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile:1000 image
-http://www.twitter.com/ http://www.twitter.com/ other
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i3/8/TB24j_0cW8lpuFjy0FpXXaGrpXa_!!8-0-yamato.jpg_284x284Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/wv/images/alphatar_100x100_R_jd_6-16.jpg image
-http://www.amazon.com/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-a3d92a134e6afaec4974bceac0812b73d0b635c1._V2_.png image
-http://www.twitter.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i3/75/TB23RCQXOfmJKJjy0FcXXbmeFXa_!!75-0-yamato.jpg_284x284Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/Pws_8olwgvARrsz.udyC1A--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/homerun/the_huffington_post_584/d9826222ceb78067cf8a2de7e32d86e0 image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/TB2ngFemtfJ8KJjy0FeXXXKEXXa_!!138-0-luban.jpg_240x5000Q50s50.jpg_.webp image
-http://www.twitter.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAd2td3Kg6S5ylmPXXcfnkaiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.yahoo.com/ https://s.yimg.com/wv/images/alphatar_100x100_W_ad.jpg image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/184/TB25k3CngMPMeJjy1XdXXasrXXa_!!184-0-yamato.jpg_240x5000Q50s50.jpg_.webp image
-http://www.twitter.com/ https://www.twitter.com/ other
-http://www.amazon.com/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2 font
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i4/7/TB2.MMGlMvD8KJjSsplXXaIEFXa_!!7-0-yamato.jpg_240x5000Q50s50.jpg_.webp image
-http://www.twitter.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAs%2FtxexOGVLEkvH5vEO0wGiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61-dJ29Zw5L.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,51nK0kUyg2L.js,11Mdh5CVmhL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61IUvg6RIjL.js,31y9nF9Z1BL.js,11SW3HEKjtL.js,01qkmZhGmAL.js,01eORIy6e6L.js_.js?AUIClients/AmazonUI script
-http://www.yahoo.com/ https://s.yimg.com/wv/images/alphatar_100x100_N_jd_6-16.jpg image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/112/TB24GbnaRP8F1JjSspaXXb4ypXa_!!112-0-yamato.jpg_240x5000Q50s50.jpg_.webp image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C414ftrYGv0L.js,11P4Lu1aIqL.js_.js?AUIClients/GWMWebAssets script
-http://www.twitter.com/ https://mobile.twitter.com/ html
-http://www.taobao.com/ https://img.alicdn.com/tfs/TB1uj.qi5qAXuNjy1XdXXaYcVXa-96-96.png_100x150Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/wv/images/alphatar_100x100_PR_ad.jpg image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets script
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/2/TB1JyQHe0fJ8KJjy0FeSutKEXXa.jpg_180x180Q50s50.jpg_.webp image
-http://www.twitter.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/Do7MPgkn4IJiajLxu1EQgg--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en/homerun/feed_manager_auto_publish_494/da3445948895ef86c4dc3023f0e9c93d image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/41XJlIDdUUL._RC%7C01vojWHr8gL.js,31qKd4DgPkL.js_.js?AUIClients/NavMobileMetaAsset script
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/runtime.d391ff8c609c8d6f.js script
-http://www.taobao.com/ https://img.alicdn.com/i3/175850305234831774/TB1IfqKNVXXXXXNaXXXXXXXXXXX_!!0-tejia.jpg_180x180Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/RyO69kfwilI2YGMJsbDHXQ--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-GB/homerun/newsweek_europe_news_328/ef6b6e02ce59296e30268166218de7c3 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/510wwe1qMUL.js?AUIClients/RetailSearchAutocompleteAssets script
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/vendor.789a86e33892ac88.js script
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/2/TB1k9g8RXXXXXaoaXXXYXGcGpXX_M2.SS2_180x180Q50s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/xopyLwPq5n2Y5DpfiW4r5g--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/homerun/the_huffington_post_584/6d22dcd32e8705766e4ee40c7c10abc5 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/11QXqf0G81L.js?AUIClients/RetailWebsiteOverlayAUIAssets script
-http://www.taobao.com/ https://img.alicdn.com/bao/uploaded/i1/669922406/TB28YGBsbxmpuFjSZJiXXXauVXa_!!669922406.jpg_180x180Q50s50.jpg_.webp image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/i18n/en.ddcda8e44e0ae492.js script
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/17DRuCE7IRxBqQQk6ocHWw--~B/Zmk9c3RyaW07aD00ODA7cHlvZmY9MDtxPTgwO3c9NzUwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en/homerun/feed_manager_auto_publish_494/a6b2328bc2d2d1b7bbb10f7780f438f7 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/airstream/mobile-upnav/C/mobile_upnav_C_latest_2x._CB492140722_.jpg image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/2/TB1Z1YkOpXXXXXyXVXXSutbFXXX.jpg_180x180Q50s50.jpg_.webp image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/main.7ba263fd84331110.js script
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/w8JVPJHqIcJvhW5pACC.bw--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en/homerun/feed_manager_auto_publish_494/6c6dd1e0947047dd6e042a2c7a8faee4 image
-http://www.amazon.com/ https://www.amazon.com/uedata/nvp/unsticky/146-2560051-6146567/NoPageType/ntpoffrw?ld&v=0.1284.0&id=D8CDZ20FD8M1403SAHVK&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=D8CDZ20FD8M1403SAHVK&ue=25&bb=1376&ns=1382&cf=1559&be=1670&af=1729&ne=1874&pc=3611&tc=-1565&na_=-1565&ul_=-1516015825230&_ul=-1516015825230&rd_=-1516015825230&_rd=-1516015825230&fe_=-1516&lk_=-1516&_lk=-1263&co_=-1263&_co=-632&sc_=-961&rq_=-629&rs_=-121&_rs=298&dl_=-111&di_=1713&de_=1713&_de=1714&_dc=3611&ld_=3611&_ld=-1516015825230&ntd=-1&ty=0&rc=0&hob=21&hoe=26&ld=3615&t=1516015828845&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:16-6-4-4-3-0-0&csmtags=aui|aui:aui_build_date:3.17.20-2017-12-07|gwImgNoCached|fls-na|pageEncoding:UTF-8|gwmNoCardHistory&viz=visible:25&pty=gateway-phone-web&spty=smartphone-card&pti=mobile-unrec&tid=D8CDZ20FD8M1403SAHVK&aftb=1 image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/2/TB2eNLpoVXXXXXyXFXXXXXXXXXX_!!2329766006.jpg_180x180Q50s50.jpg_.webp image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/shared.73386a971a4ac48e.js script
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D78%26cf0%3D1353%26pc0%3D1354%26ld0%3D1354%26t0%3D1516015826584%26sc1%3Dlg%26af1%3D1558%26pc1%3D1559%26ld1%3D1559%26t1%3D1516015826789%26sc2%3DcsmCELLSframework%26bb2%3D1645%26pc2%3D1651%26ld2%3D1651%26t2%3D1516015826881%26sc3%3DcsmCELLSpdm%26bb3%3D1656%26pc3%3D1659%26ld3%3D1659%26t3%3D1516015826889%26sc4%3DcsmCELLSvpm%26bb4%3D1659%26pc4%3D1659%26ld4%3D1659%26t4%3D1516015826889%26sc5%3DcsmCELLSfem%26bb5%3D1664%26pc5%3D1665%26ld5%3D1665%26t5%3D1516015826895%26sc6%3Dpc%26af6%3D1732%26cf6%3D1732%26pc6%3D1732%26ld6%3D1732%26t6%3D1516015826962%26sc7%3Dinteractivity%26cf7%3D2853%26pc7%3D2853%26ld7%3D2853%26t7%3D1516015828083%26ctb%3D1:3638 image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/tPeVWxfYOMpw8xwuhZVV9g--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en/homerun/feed_manager_auto_publish_494/a5420e28c19f5956a1ace4b46d2f5369 image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/PH32LyNSatqOu2AlHCQSMA--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en/homerun/feed_manager_auto_publish_494/773064a42e40459e6548c8c916e5f867 image
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/2/TB1kcBxbEAKL1JjSZFkSuu8cFXa.jpg_180x180Q50s50.jpg_.webp image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/loader.notificationsData.21dd8686ef19f730.js script
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/2/TB2CnAdsXXXXXa2XXXXXXXXXXXX_!!88020338-0-goldwindow.jpg_180x180Q50s50.jpg_.webp image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/loader.SearchBox.5cee055e2c271da0.js script
-http://www.amazon.com/ https://m.media-amazon.com/images/G/01/csm/showads.v2.js script
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/BtaRQPeyUVc71WM5MZVHtw--~B/Zmk9c3RyaW07aD0yMDA7cHlvZmY9MDtxPTgwO3c9MjAwO3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en/homerun/feed_manager_auto_publish_494/fd73e73e6af16fc1b2150933a8a9db80 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js script
-http://www.taobao.com/ https://log.mmstat.com/eg.js script
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/bundle.LoggedOutHome.b2882f61bdc1cd24.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/ape/m/81f43c2/t.gif image
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D3657%26pc0%3D3657%26ld0%3D3657%26t0%3D1516015828887%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:3657 image
-http://www.taobao.com/ https://wgo.mmstat.com/codetrack.1.1?cache=5386a45&gmkey=EXP&gokey=msg%3Dbat%257C%257C%257C%257C%257C0%257C0%257C1%26hash%3D-1139410274%26spm%3Da2141.8294651%26client%3Dh5%26token%3D1TTrrc5r6evF4mxp2x7D%26proxy%3D&cna=&spm-cnt=a2141.8294651.0.0.618cf714qPtytF&logtype=2 image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/loader.AppModules.03ce850967407859.js script
-http://www.yahoo.com/ https://s.yimg.com/xf/btrl/lightning-player-0.3.1-min.js script
-http://www.amazon.com/ https://www.amazon.com/favicon.ico image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/bundle.NetworkInstrument.95da7a634e6b2637.js script
-http://www.taobao.com/ https://log.mmstat.com/m.gif?logtype=1&title=%u6DD8%u5B9D%u7F51%20%u7F8E%u56FD%u7AD9&pre=&cache=8e041db&scr=360x512&spm-cnt=a2141.8294651.0.0.618cf714qPtytF&category=&uidaplus=&&aplus&udpid=&&asid=AQAAAABAkVxa1OwjIwAAAAD/yJQMOdMXOQ==&sidx=fKJuVZrR0qr+gxzF8Qn7tgD4a1k+VkkE3rVDabnkUqW4GWrGOYHEdwdnskeBPUyzVS/RYcIgRkHmqjRFfyvcr0D+jknMCSHUivYaqIIf7O198+3/ou6e0FhELuD75HABMSdfacD7O8NN/mhTN5SQLdZ6lWaTuw9V+JnH51oL4X0=&p=1&o=android6.01&b=chrome58&s=360x512&w=webkit&ism=android&lver=7.7.0&jsver=aplus_wap&tag=0&stag=-2&lstag=-1 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/kindle/merch/2017/SMP/JanuaryEvergreenGateway/1242x450_U_v1._SX1242_CB489998393_.jpg image
-http://www.twitter.com/ https://api.twitter.com/1.1/account/verify_credentials.json?skip_status=1 script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/mit/td/td-applet-breakingnews-atomic-0.0.57/r-min.js script
-http://www.taobao.com/ http://www.taobao.com/ html
-http://www.taobao.com/ http://m.taobao.com/?sprefer=sypc00 other
-http://www.twitter.com/ https://api.twitter.com/1.1/jot/client_event.json script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/yaft/yaft-0.3.11.min.js script
-http://www.taobao.com/ https://h5api-intl.m.taobao.com/h5/mtop.taobao.wireless.guess.get/1.0/?jsv=2.4.8&appKey=12574478&t=1516015943507&sign=ae1580a43c5aa48d063239ea37cf5f7c&api=mtop.taobao.wireless.guess.get&v=1.0&type=jsonp&dataType=jsonp&callback=mtopjsonp3&data=%7B%22fromLocation%22%3A%20%22unknown%22%2C%22platformVersion%22%3A%2214%22%2C%22channel%22%3A%22hTaoHomePage%22%2C%22longitude%22%3A%220%22%2C%22latitude%22%3A%220%22%2C%22pageTotal%22%3A%204%2C%22pageNum%22%3A%200%2C%22edition%22%3A%22%7B%5C%22cityId%5C%22%3A%5C%22undefined%5C%22%2C%5C%22countryId%5C%22%3A%5C%22US%5C%22%2C%5C%22actualLanguageCode%5C%22%3A%5C%22zh-CN%5C%22%7D%22%7D script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/yaft/yaft-plugin-aftnoad-0.1.5.min.js script
-http://www.taobao.com/ https://m.taobao.com/?sprefer=sypc00 html
-http://www.taobao.com/ https://pass.tmall.com/add?t=a3baf3b7caef969bb9d347f5a7dada20&cookie2=1a0580b3dbd84acdbf956f80bf0cfece&_tb_token_=ee795e4ee8e8f&hng=US%7Czh-CN%7CUSD%7C840&tmsc=1516015943667000&opi=10.103.184.33&pacc=7Vqr3qfmwPV8iVpnzaolIQ==&target=https%3A%2F%2Fwww.tmall.com other
-http://www.twitter.com/ https://api.twitter.com/1.1/jot/client_event.json script
-http://www.yahoo.com/ https://d2g8lys5ezlyfo.cloudfront.net/Pix-1x1.gif?mode=mp&sp_id=0&xtra=0513f1cc-32aa-4c97-8faf-1c69a4f38cf1&method=11&time=2 image
-http://www.taobao.com/ http://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/41P%2BYvE0rjL._AC_SY400_.jpg image
-http://www.twitter.com/ https://abs-0.twimg.com/responsive-web/web/ltr/icon-default.882fa4ccf6539401.png image
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D4041%26cf0%3D4064%26pc0%3D4064%26ld0%3D4064%26t0%3D1516015829294%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:4065 image
-http://www.taobao.com/ https://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.taobao.com/ https://www.tmall.com/ html
-http://www.yahoo.com/ https://mbp.yimg.com/sy/lq/lib/3pm/cs_0.2.js script
-http://www.amazon.com/ https://www.amazon.com/uedata/nvp/unsticky/146-2560051-6146567/NoPageType/ntpoffrw?at&v=0.1284.0&id=D8CDZ20FD8M1403SAHVK&m=1&sc=adblk_no&pc=4129&at=4129&t=1516015829359&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile-unrec&tid=D8CDZ20FD8M1403SAHVK&aftb=1 image
-http://www.twitter.com/ https://www.google-analytics.com/analytics.js script
-http://www.taobao.com/ https://pcookie.taobao.com/app.gif?&cna=SH/jEsj35i8CAZUUPw0humlN image
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26m%3D1%26sc%3Dadblk_no%26pc%3D4129%26at%3D4129%26t%3D1516015829359%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:4129 image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-af-0.0.336/media-agof-tracking/media-agof-tracking-min.js script
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i2/112394247/TB2uGe9eBLN8KJjSZPhXXc.spXa-112394247.jpg_1080x1800Q50s50.jpg_.webp image
-http://www.twitter.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&aip=1&a=471844455&t=pageview&_s=1&dl=https%3A%2F%2Fmobile.twitter.com%2F&dp=%2Fanon%2Ffront%2F&ul=en-us&de=UTF-8&dt=Twitter.%20It%27s%20what%27s%20happening.&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAUAB~&jid=606820435&gjid=1683403961&cid=312109092.1516015836&tid=UA-30775-67&_gid=53992482.1516015836&_r=1&z=1393587373 image
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D4163%26pc0%3D4170%26ld0%3D4170%26t0%3D1516015829400%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:4170 image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-af-0.0.336/af-eu-tracking/af-eu-tracking-min.js script
-http://www.taobao.com/ https://img.alicdn.com/imgextra/i1/3017497142/TB2CXjKmdbJ8KJjy1zjXXaqapXa_!!3017497142.jpg_1080x1800Q50s50.jpg_.webp image
-http://www.amazon.com/ https://www.amazon.com/gp/gw/ajax/dataStore.html/146-2560051-6146567?ie=UTF8&hmac=BA8EA1C330D102FDF031FB4C3946A92C0CE2EFB6&opf_redir=1&relatedRequestId=D8CDZ20FD8M1403SAHVK script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/stencil-3.2.1/stencil-imageloader/stencil-imageloader-min.js script
-http://www.taobao.com/ https://wgo.mmstat.com/codetrack.1.1?cache=2ff5fa5&gmkey=EXP&gokey=msg%3Djserror%257Cbat%257C%257C%257CScript%2520error.%255E%255E0%255E0%255E%257C7888%257C1%257C1%26hash%3D1174183457%26spm%3Da2141.8294651%26client%3Dh5%26token%3D1TTrrc5r6evF4mxp2x7D%26proxy%3D&cna=SH%2FjEsj35i8CAZUUPw0humlN&spm-cnt=a2141.8294651.0.0.618cf714qPtytF&logtype=2 image
-http://www.taobao.com/ http://www.taobao.com/ html
-http://www.amazon.com/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2 font
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/dust-helpers-0.0.154/intl-messageformat/intl-messageformat-min.js script
-http://www.taobao.com/ http://m.taobao.com/?sprefer=sypc00 other
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/gno/sprites/sky_webnav_V1_sprite_2x._CB515696737_.png image
-http://www.taobao.com/ https://m.taobao.com/?sprefer=sypc00 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/dust-helpers-0.0.154/dust-helper-intl/dust-helper-intl-min.js script
-http://www.amazon.com/ https://www.amazon.com/gp/overlay/display.html html
-http://www.taobao.com/ http://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/dust-helpers-0.0.154/intl-helper/intl-helper-min.js script
-http://www.taobao.com/ https://img.alicdn.com/tfs/TB11yx5mwvD8KJjy0FlXXagBFXa-1125-350.jpg_1080x1800Q50s50.jpg_.webp image
-http://www.amazon.com/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2 font
-http://www.yahoo.com/ https://mbp.yimg.com/sy//nn/lib/metro/g/myy/myy_viewer_atomic_0.0.2.js script
-http://www.taobao.com/ https://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.amazon.com/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2 font
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/node-scroll-info/node-scroll-info-min.js script
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26ctb%3D1%26sc0%3Ddata-store-1%26bb0%3D4253%26cf0%3D4834%26pc0%3D4834%26ld0%3D4834%26t0%3D1516015830064%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:4834 image
-http://www.yahoo.com/ https://mbp.yimg.com/sy//nn/lib/metro/g/myy/video_manager_0.0.172.js script
-http://www.amazon.com/ https://www.amazon.com/gp/gw/ajax/card.html/146-2560051-6146567?ie=UTF8&opf_redir=1&rshVal=1516015830149 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-applet-0.0.210/ape-applet-templates-reload/ape-applet-templates-reload-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/US-hq/2018/img/Furniture_Private_Label/XCM_1095314_Manual_1242x450_1095314_us_furniture_private_label_rivet_v1_gw_mbb_1242x450_jpg_Gateway._SX414_CB488743460_.jpg image
-http://www.yahoo.com/ https://d2g8lys5ezlyfo.cloudfront.net/Pix-1x1.gif?mode=mp&sp_id=0&xtra=0513f1cc-32aa-4c97-8faf-1c69a4f38cf1&method=12&time=4380 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/41FQCldSn2L._SCLZZZZZZZ__AC_.jpg image
-http://www.yahoo.com/ https://sb.scorecardresearch.com/p?c1=2&c2=7241469&c5=1197228339&c7=https%3A%2F%2Fwww.yahoo.com%2F&ns__t=1516015921039&ns_c=UTF-8 other
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/51fg6wHgdaL._SCLZZZZZZZ__AC_.jpg image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/widget-base/assets/skins/sam/widget-base.css css
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/41N+045AcRL._SCLZZZZZZZ__AC_.jpg image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/autocomplete-list/assets/skins/sam/autocomplete-list.css css
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OE/ other
-http://www.yahoo.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1516015923074&yhlClientVer=3.42.4&yhlRnd=YoSuIZLWxT87xHDK&yhlCompressed=0 other
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/US-hq/2018/img/Furniture_Private_Label/XCM_1095314_Manual_1242x450_1095314_us_furniture_private_label_rivet_v1_gw_mbb_1242x450_jpg_Gateway._SX1242_CB488743460_.jpg image
-http://www.yahoo.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1516015923098&yhlClientVer=3.42.4&yhlRnd=4csBV4m92Sif7Nyi&yhlCompressed=0 other
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/317Qb9WY18L._RC%7C51LXHcJtjWL.js_.js?AUIClients/SharedShoppingCartMobileAsset script
-http://www.yahoo.com/ https://sb.scorecardresearch.com/p2?c1=2&c2=7241469&c5=1197228339&c7=https%3A%2F%2Fwww.yahoo.com%2F&ns__t=1516015921039&ns_c=UTF-8 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31sOpTNvD0L.css_.css?AUIClients/SharedShoppingCartMobileAsset css
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/autocomplete-list/lang/autocomplete-list_en.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/51qeNhhxS9L._AC_SY80_.jpg image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/widget-base/widget-base-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/41w1jyAbWTL._SCLZZZZZZZ__AC_.jpg image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/autocomplete-list/autocomplete-list-min.js script
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26ctb%3D1%26sc0%3Dgwm%26cf0%3D1558%26af0%3D5445%26pc0%3D5446%26ld0%3D5446%26t0%3D1516015830676%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:5446 image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/color-base/color-base-min.js script
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OP/ATVPDKIKX0DER:146-2560051-6146567:D8CDZ20FD8M1403SAHVK$uedata=s:%2Fuedata%2Fnvp%2Funsticky%2F146-2560051-6146567%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DD8CDZ20FD8M1403SAHVK%26ctb%3D1%26sc0%3Dcard-load-1%26bb0%3D4919%26cf0%3D5378%26pc0%3D5440%26ld0%3D5440%26t0%3D1516015830670%26csmtags%3Daui%7Caui%3Aajax%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile-unrec%26tid%3DD8CDZ20FD8M1403SAHVK%26aftb%3D1:5440 image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-base/anim-base-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/iu3?d=amazon.com&slot=navFooter&a2=01017ec8e21ef9874fb8b7c5557696b04b1c4b199b8bd90ee8927b9a178d9d724181&old_oo=0&cb=1516015824992 other
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-color/anim-color-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/412v-AA4thL._AC_SY80_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-applet-0.0.210/ape-applet-lang-strings_en-us/ape-applet-lang-strings_en-us-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/xba/CategoryCard_US_Electronics_Nov_2017._UX350_SX350_CB513029584_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-pipe-0.0.65/comet/comet-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/xba/Womens_2_pt5._CB490307620_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-pipe-0.0.65/af-comet/af-comet-min.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-pipe-0.0.65/af-pipe/af-pipe-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/xba/Gifts_pt5._CB491716672_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/ape-af-0.0.336/af-history/af-history-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/xba/Men-5._CB490778658_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-vertical-video-util/td-applet-viewer-vertical-video-util-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/iu3?d=amazon.com&slot=navFooter&a2=01017ec8e21ef9874fb8b7c5557696b04b1c4b199b8bd90ee8927b9a178d9d724181&old_oo=0&cb=1516015824992&dcc=t html
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/xba/Watches_2_pt5._CB490307943_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-viewer-model/td-viewer-model-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/kindle/merch/2017/E-reader/Dec/VX-1301-TPR_KP_GW-Hero-Mobile-1242x450-2X._SX414_CB492656923_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-ads-model/td-ads-model-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/91X6BQHte1L._AC_SY80_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-relatedvideo-model/td-relatedvideo-model-min.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-tilesad-model/td-tilesad-model-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/91TPmmUT5UL._AC_SY80_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-viewer-ads/td-viewer-ads-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/91mSHaL6oEL._AC_SY80_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-viewer-slideshow/td-viewer-slideshow-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/31HTGEouXpL.js?AUIClients/DetailPageAlohaAssets script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-yapad-model/td-yapad-model-min.js script
-http://www.amazon.com/ https://unagi-na.amazon.com/1/events/com.amazon.csm.nexusclient.prod script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-viewer-mainview/td-viewer-mainview-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/v3/pr?exlist=pp_sx_ns_rx_kr_g_bsw_bk_ox_index_aold_an_rb_br_fbca_aolv_twca_y_pm_adelphic_rlsa_adb_tbl&fv=1.0&ex-pl-fbca=u3DaIt0bQ6mobZu_JqSFqA&ex-pl-twca=Woa8_4FqTxiQ_jiifBsWYQ&a=cm&ep=LjFg6mFEAYlJJNpLmgMTmnXwgzlvfpqZPRHUVjD8yUI7hKowRL2Mh7joscXKVsZAlnpJmQRKiHv-REoMs2a3HLLvyJUZWFKHfLCb5BxNKT8 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-video-manager-util/td-video-manager-util-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/01%2B4CxAE%2BiL.css?AUIClients/DetailPageAlohaAssets css
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-mag_slideshow/td-applet-viewer-templates-mag_slideshow-min.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-content_body_mega/td-applet-viewer-templates-content_body_mega-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/11chYsfG59L._RC%7C411E-IzoCiL.js,31cePTj3CrL.js,11NxOa490XL.js,31E+jMbvKeL.js,21ydeSYKyxL.js,31hd9A67kaL.js,51wmFWz9R9L.js,51Hi2VfLU+L.js,21yUMfZsKLL.js,31Uv36U8jvL.js,016DBHJkIYL.js,31jTkOse2dL.js,51jBpR55mHL.js,81ewiHI9QoL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,11QIUl6VLbL.js,21jBAndZe0L.js,51YzCqyJFIL.js,0111g0cQvbL.js,01nKqcvaCIL.js,01X117Z9PgL.js,51XB-Z2U6zL.js,01X5C8pWB1L.js,518wG9hJ8NL.js,11exTzl96yL.js,21+S39dBotL.js,31egXBuM55L.js,01RHiyjONOL.js,31I-BifbuzL.js,210S22NrxIL.js,41gWwCA3yQL.js,314ZAgS3sJL.js,11U-t4vkrhL.js,21dd1rjDvsL.js,01q0JZaOPlL.js,11E9uGq9IjL.js,31ze7I-RWjL.js,21q3UdjiveL.js,21HlHGr1+aL.js,0193uyIciNL.js,51NhK1niNZL.js,71Tfqvb+QML.js,01FlgNba65L.js,01-Sz0ff1pL.js,01UujNMpLSL.js,41Eexuqvf6L.js,21e16+5SkdL.js,11NHZnHlFmL.js,21CbPMxfA+L.js,015J4NGaO3L.js,11B4fwZPeqL.js,21-q-ofQTaL.js,01lQqh9VSML.js,01jqyAujTwL.js,01KcbtwkAOL.js,01-XJ1YSEXL.js,113LFYzRWdL.js,01NAT+3p7KL.js,111vgqp2a0L.js,51GfggKdyCL.js,01MZJG6lH8L.js,01VtYReatCL.js,21LWJ90NCIL.js,01CyECqkeYL.js,01RQtSMdG+L.js,21JwQBfgBXL.js,41GhTGxzilL.js,01HkRA6GGsL.js,01l3c7okxRL.js,01-Eu4U-17L.js,01qwoVEkKlL.js,011HXD1ky3L.js,011X+p22ALL.js,01k57x9vvBL.js,01RNXZDiBuL.js,01ZF+ovNflL.js,31MsfX4iIYL.js,01S8y9NkxoL.js,01Qrw-EXW5L.js,119v9AP9VIL.js,01WMAHenIIL.js,51-wBjbbYrL.js,01DbXKJJh7L.js_.js?AUIClients/DetailPageMobileWebMetaAsset script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-modal_aside_mega/td-applet-viewer-templates-modal_aside_mega-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/51qeNhhxS9L._AC_SY240_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-share_btns_mega/td-applet-viewer-templates-share_btns_mega-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/01ekIXTj5kL._RC%7C01j62IBqyaL.css,41CNXGW6T4L.css,318TvQQkpyL.css,31tH-GJ-doL.css,01YiKvi4CgL.css,21hZfe6sDdL.css,11q7D6YoQCL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,21qOYA5+VOL.css,21QwDiO8ycL.css,01IHzhAZ28L.css,31no24Dqj1L.css,01wBE2Z+USL.css,11xlykx3aFL.css,01D-B-OeNDL.css,21CNSKZ67ML.css,11rhPo030XL.css,11zgKVdkIJL.css,51oAYplAOyL.css,21hLnMMJrfL.css,21lDMA2J74L.css,21A-3ofYwnL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,11oH9gtOgDL.css,21ZKosCj0iL.css,313bzSzzhRL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21Df5N8kF4L.css,61ypmw1UTGL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,016xTzXJLfL.css,31LBzl8T3vL.css,21cgaWigpnL.css,11cAYJlTEgL.css,018mGORJ7tL.css,11fvu+DzMxL.css,11ho+83HCzL.css,01ticFfm7pL.css,01lh9w-GYYL.css,31ZqywtmC7L.css,11Mso4bvY-L.css,01LCsoCesOL.css,01ifu3nZXpL.css,21Yyo4tu6ZL.css_.css?AUIClients/DetailPageMobileWebMetaAsset css
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-header/td-applet-viewer-templates-header-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/01Juwat-A-L.js?AUIClients/AutomotiveEUMobileAssets script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-share_btns_lead_mega/td-applet-viewer-templates-share_btns_lead_mega-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/412v-AA4thL._AC_SY240_.jpg image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-thumbnail_items/td-applet-viewer-templates-thumbnail_items-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/01f4WNlzROL.css?AUIClients/AutomotiveMobileAssets css
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-lightbox_lead_mega/td-applet-viewer-templates-lightbox_lead_mega-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/81MDTSEXQgL.js?AUIClients/GoldboxUDPAssets script
-http://www.amazon.com/ https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm&ex=doubleclick.net html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-debug/td-applet-viewer-templates-debug-min.js script
-http://www.amazon.com/ https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-slideshow_inline_sm/td-applet-viewer-templates-slideshow_inline_sm-min.js script
-http://www.amazon.com/ https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-carousel/td-applet-viewer-templates-carousel-min.js script
-http://www.amazon.com/ https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm=&ex=doubleclick.net&google_tc= html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-fallback/td-applet-viewer-templates-fallback-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=d5sZQkpK0ekd&ex=pulsepoint.com&ev=&pid=557477 image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-footer/td-applet-viewer-templates-footer-min.js script
-http://www.amazon.com/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__ html
-http://www.amazon.com/ https://aa.agkn.com/adscores/g.pixel?sid=9212284268 other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-modal_lrecs_mega/td-applet-viewer-templates-modal_lrecs_mega-min.js script
-http://www.amazon.com/ https://usermatch.krxd.net/um/v2?partner=amzn other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-header_atomic_sm/td-applet-viewer-templates-header_atomic_sm-min.js script
-http://www.amazon.com/ https://sync.1rx.io/usersync2/rmpssp?sub=amazon&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%5BRX_UUID%5D%26ex%3Drhythmone.com html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-ads_story/td-applet-viewer-templates-ads_story-min.js script
-http://www.amazon.com/ https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-content_body/td-applet-viewer-templates-content_body-min.js script
-http://www.amazon.com/ https://x.bidswitch.net/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-header_ads/td-applet-viewer-templates-header_ads-min.js script
-http://www.amazon.com/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-video/td-applet-viewer-templates-video-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=doubleclick.net&google_gid=CAESEMvmwRGFTgY-FuJYfOnFeF8&google_cver=1 image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-swipe_progress_dots/td-applet-viewer-templates-swipe_progress_dots-min.js script
-http://www.amazon.com/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-story_cover_atomic_sm/td-applet-viewer-templates-story_cover_atomic_sm-min.js script
-http://www.amazon.com/ https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D image
-http://www.amazon.com/ https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-slideshow_atomic_sm/td-applet-viewer-templates-slideshow_atomic_sm-min.js script
-http://www.amazon.com/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=adfc626e-f9e7-11e7-b119-1142d8060001 other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-drawer_feedback/td-applet-viewer-templates-drawer_feedback-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=index&id=Ew6n6oH4q1pwUlUo1NhuNTcmdCM4ZgAC image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-ad_fdb_thank_you/td-applet-viewer-templates-ad_fdb_thank_you-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=a507dd82-446c-c927-3666-82bd55ef557e image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-vv_topbar/td-applet-viewer-templates-vv_topbar-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=bidswitch.com&id=3d0da677c70e873ec3388130370567f1 image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-carousel_atomic_sm/td-applet-viewer-templates-carousel_atomic_sm-min.js script
-http://www.amazon.com/ https://stags.bluekai.com/site/36841?dt=0&r=1941615532&sig=2032588566&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmiRglWl1u3dep5hJEi0rvuNa028whzGcC3z3bh3gaqjG33LRr3ADZXAl5XSvQ7AsZVVQWDuLGoEzNmp9xoOQeP0hFr other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-lightbox_atomic_sm/td-applet-viewer-templates-lightbox_atomic_sm-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=spotx.com&id=adfcac28-f9e7-11e7-b119-1142d8060001 image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-app_install_sm/td-applet-viewer-templates-app_install_sm-min.js script
-http://www.amazon.com/ https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1 other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-story/td-applet-viewer-templates-story-min.js script
-http://www.amazon.com/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc html
-http://www.amazon.com/ https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1&verify=true other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-reblog/td-applet-viewer-templates-reblog-min.js script
-http://www.amazon.com/ https://d.agkn.com/pixel/8198/?che=1516015834&sk=164751302571000793076&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164751302571000793076&ex=neustar.biz other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-yapnativead/td-applet-viewer-templates-yapnativead-min.js script
-http://www.amazon.com/ https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-taptooltip/td-applet-viewer-templates-taptooltip-min.js script
-http://www.amazon.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=470486297 html
-http://www.tmall.com/ http://www.tmall.com/ html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-video_atomic_sm/td-applet-viewer-templates-video_atomic_sm-min.js script
-http://www.amazon.com/ https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn image
-http://www.tmall.com/ https://www.tmall.com/ html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-story_atomic_sm/td-applet-viewer-templates-story_atomic_sm-min.js script
-http://www.amazon.com/ https://tags.bluekai.com/site/2981?id=&google_gid=CAESENEup1o0PDTUnH4j68dHyxM&google_cver=1 image
-http://www.tmall.com/ https://g.alicdn.com/mui/global/1.2.35/file/favicon.ico image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-cards_atomic_sm/td-applet-viewer-templates-cards_atomic_sm-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=51233cb24d6e114f8180e0df3c1fa0c340a13ef5&ex=aoldisplay.com image
-http://www.tmall.com/ https://g.alicdn.com/alilog/mlog/aplus_v2.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-main_atomic_sm/td-applet-viewer-templates-main_atomic_sm-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=164751302571000793076&ex=neustar.biz image
-http://www.tmall.com/ https://g.alicdn.com/??mui/feloader/4.0.17/feloader-min.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-vv_ad_cta/td-applet-viewer-templates-vv_ad_cta-min.js script
-http://www.amazon.com/ https://match.adsrvr.org/track/cmb/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=470486297 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-lightbox_mega/td-applet-viewer-templates-lightbox_mega-min.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-vv_banner_atomic_sm/td-applet-viewer-templates-vv_banner_atomic_sm-min.js script
-http://www.amazon.com/ https://token.rubiconproject.com/token?pid=2179&pt=n other
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-story_cover/td-applet-viewer-templates-story_cover-min.js script
-http://www.amazon.com/ https://sync.1rx.io/usersync/tradedesk/7352bc8e-c355-4c1b-8cd7-6ff3893b1f50 html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-content_body_atomic_sm/td-applet-viewer-templates-content_body_atomic_sm-min.js script
-http://www.tmall.com/ https://g.alicdn.com/hybrid/api/4.0.16/hybrid.min.js script
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-lightbox/td-applet-viewer-templates-lightbox-min.js script
-http://www.amazon.com/ https://www.facebook.com/fr/r.php?p=558293300959460&e=u3DaIt0bQ6mobZu_JqSFqA&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dfbca%26id%3Du3DaIt0bQ6mobZu_JqSFqA&s=1516015832&h=V2RndGVrRmRCMDdEcS9GdOnjRwhhrXI9KiIIhFvFomDdujTo html
-http://www.tmall.com/ https://img.alicdn.com/tps/TB1WIQfJFXXXXbqXFXXXXXXXXXX-88-88.png image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-main/td-applet-viewer-templates-main-min.js script
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1woHWSFXXXXcPaXXXXXXXXXXX-1000-441.jpg_720x720Q90s50.jpg_.webp image
-http://www.amazon.com/ https://geo-um.btrll.com/v1/map_pixel/partner/64.png image
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1HWNORFXXXXciaXXXXXXXXXXX-800-140.png image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-slideshow/td-applet-viewer-templates-slideshow-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id image
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1yqhOQpXXXXcwaXXXXXXXXXXX-60-64.png image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-vv_ad/td-applet-viewer-templates-vv_ad-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=RX-aaf0909d-52e3-496a-ab60-b8664226e78a&ex=rhythmone.com image
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1uDEXSFXXXXbkXVXXXXXXXXXX-1000-242.jpg_720x720Q90s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-cards/td-applet-viewer-templates-cards-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=fbca&id=u3DaIt0bQ6mobZu_JqSFqA image
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1cePtSFXXXXcWXFXXXXXXXXXX-1000-277.jpg_720x720Q90s50.jpg_.webp image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-relatedvideos/td-applet-viewer-templates-relatedvideos-min.js script
-http://www.amazon.com/ https://geo-um.btrll.com/v1/map_pixel/partner/64.png?set_aps=1&BR_APS=3WlyQ3AYQubgBxwXgIQ& image
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1FEsePXXXXXcqXXXXXXXXXXXX-80-80.gif image
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-videocluster/td-applet-viewer-templates-videocluster-min.js script
-http://www.amazon.com/ https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D text
-http://www.tmall.com/ https://h5api.m.tmall.com/h5/mtop.tmall.tac.gateway.execute/1.0/?jsv=2.4.2&appKey=12574478&t=1516015831431&sign=ba2dda3547f688866462e02c223ff920&AntiCreep=true&api=mtop.tmall.tac.gateway.execute&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp1&data=%7B%22msCodes%22%3A%222017080800%22%2C%22params%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D html
-http://www.yahoo.com/ https://s.yimg.com/os/mit/td/td-applet-viewer-0.1.2715/td-applet-viewer-templates-share_btns/td-applet-viewer-templates-share_btns-min.js script
-http://www.amazon.com/ https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=Woa8_4FqTxiQ_jiifBsWYQ&twitter_redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dtwca%26id%3DWoa8_4FqTxiQ_jiifBsWYQ%26 html
-http://www.tmall.com/ https://g.alicdn.com/mui/fetch/4.1.12/jsonp.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-xy/anim-xy-min.js script
-http://www.amazon.com/ https://ads.yahoo.com/cms/v1?esig=1~b9bada6fffbf45c1ffda7783879fb5715486894a&nwid=10000922750&sigv=1 text
-http://www.tmall.com/ https://g.alicdn.com/mui/fetch/4.1.12/fetch.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-node-plugin/anim-node-plugin-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=3WlyQ3AYQubgBxwXgIQ&ex=brightroll.com&n=1516015837& image
-http://www.tmall.com/ https://g.alicdn.com/mui/fetch/4.1.12/tool.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-easing/anim-easing-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/31%2BfpQuoLFL.js?AUIClients/AutomotiveMobileAssets script
-http://www.tmall.com/ https://g.alicdn.com/mui/babel-polyfill/6.2.6/index.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-curve/anim-curve-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=aolvideo.com&id=41e786533511f2743c7ab41a3600319bfa49c365 image
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/index.css css
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/promise/promise-min.js script
-http://www.amazon.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1063929773/?userId=tFlubMzmShWV2zhqBT1jrw&guid=ON&script=0 image
-http://www.tmall.com/ https://g.alicdn.com/mui/app-download-popup/4.0.12/index.css css
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/anim-scroll/anim-scroll-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?p_user_id=Woa8_4FqTxiQ_jiifBsWYQ&ex=twca&id=Woa8_4FqTxiQ_jiifBsWYQ image
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/index.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=rightmedia.com&xid=E0 image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/array-invoke/array-invoke-min.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/mods/util.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/xba/CategoryCard_US_Electronics_Nov_2017._CB513029584_.jpg image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/arraylist/arraylist-min.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/mods/env.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/G/01/kindle/merch/2017/E-reader/Dec/VX-1301-TPR_KP_GW-Hero-Mobile-1242x450-2X._SX1242_CB492656923_.jpg image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/io-form/io-form-min.js script
-http://www.amazon.com/ https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID html
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/mods/action.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/io-upload-iframe/io-upload-iframe-min.js script
-http://www.amazon.com/ https://sync.ipredictive.com/d/sync/cookie/generic?https://s.amazon-adsystem.com/ecm3?id=${ADELPHIC_CUID}&ex=adelphic other
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/mods/callApp.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/io-queue/io-queue-min.js script
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OE/ other
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/mods/download.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/async-queue/async-queue-min.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=7D2B4E0B-880B-458C-8E0C-E6DBA8209BFF&ex=pubmatic.com image
-http://www.tmall.com/ https://g.alicdn.com/mui/smart-jump/4.1.21/mods/loadConfig.js script
-http://www.yahoo.com/ https://mbp.yimg.com/sy/zz/combo?yui:/3.18.0/jsonp-url/jsonp-url-min.js script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/91X6BQHte1L._AC_SY240_.jpg image
-http://www.tmall.com/ https://g.alicdn.com/mui/zepto/4.0.9/touch.js script
-http://www.yahoo.com/ https://www.yahoo.com/_td_api/beacon/perf?os=android&rid=0s8hrq9d5p499&bucket=900&device=smartphone&site=fp&navT=0&navS=1516015911913&fetS=948&dluS=949&dluE=949&conS=949&conE=1596&reqS=1600&resS=2197&resE=4848&domL=2204&domI=8760&domS=8854&domE=9014&domC=15637&lodS=15639&lodE=-1516015911913&secS=1258&code=pageload&time=-1516015911913&src=af-beacon&_rdn=927564 image
-http://www.amazon.com/ https://trc.taboola.com/sg/amazon-a9-network/1/rtb other
-http://www.tmall.com/ https://g.alicdn.com/mui/zepto/4.0.9/zepto.js script
-http://www.yahoo.com/ https://geo.yahoo.com/p?s=1197228339&t=gmZhX5kqq8fDMWih,0.008269547858214432&_I=&_AO=0&_NOL=0&_R=&_P=3.42.4%05_pl%031%04A_v%033.42.4%04test%03900%04_bt%03rapid%04A_pr%03https%04A_tzoff%030%04A_sid%03TzBbGY34z3QQlplM%04_w%03www.yahoo.com%2F%04_rid%030s8hrq9d5p499%04mrkt%03us%04pt%03home%04ver%03ss%04uh_vw%030%04colo%03slw1011.fp.gq1.yahoo.com%04navtype%03server%04nob%031%04A_pfb%03601%04A_pbp%032651%04A_psr%033248%04A_pol%0315639%04A_pdi%038760%04A_pdl%030%04A_psh%03338%04A_psc%03647%04A_pfe%0310791%04etrg%03backgroundPost%04outcm%03performance%04usergenf%030%04etag%03performance%04_E%03pageperf%04_ts%031516015927%04_ms%03593%04A_sr%03360x512%04A_vr%03360x512%04A_do%030 image
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?id=82c01f9f-f9e7-11e7-992a-77162e1e688c&ex=adelphic image
-http://www.tmall.com/ https://g.alicdn.com/mui/zepto/4.0.9/event.js script
-http://www.yahoo.com/ https://www.yahoo.com/_td_api/resource/notificationHistory;count=4;imageTag=img%3A40x40%7C2%7C80;lastUpdate=1516015927 script
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/91mSHaL6oEL._AC_SY240_.jpg image
-http://www.tmall.com/ https://g.alicdn.com/mui/crossimage/4.1.25/index.js script
-http://www.yahoo.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1516015927912&yhlClientVer=3.42.4&yhlRnd=z78hsvJaXmn16bLS&yhlCompressed=0 other
-http://www.amazon.com/ https://dpm.demdex.net/ibs:dpid=139200&dpuuid=BhfRrNo5QW2Bu-rPJQpTJA&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D other
-http://www.tmall.com/ https://g.alicdn.com/mui/tengine-detector/4.0.0/index.js script
-http://www.yahoo.com/ https://www.yahoo.com/p.gif?beaconType=saready&timeFromNavigationStart=15908&timeFromDomLoading=13704&bucket=900 image
-http://www.amazon.com/ https://images-na.ssl-images-amazon.com/images/I/91TPmmUT5UL._AC_SY240_.jpg image
-http://www.tmall.com/ https://g.alicdn.com/mui/app-download-popup/4.0.12/env.js script
-http://www.yahoo.com/ https://www.yahoo.com/lib/metro/g/myy/rapidworker_1_2_0.0.5.js script
-http://www.amazon.com/ https://www.google.com/ads/user-lists/1063929773/?userId=tFlubMzmShWV2zhqBT1jrw&guid=ON&script=0&cdct=2&is_vtc=1&random=4235390339 image
-http://www.tmall.com/ https://g.alicdn.com/mui/app-download-popup/4.0.12/util.js script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=taboola.com&id=f7a8913a-1509-4532-a6f1-4b9c0871d64a-tuct156165e image
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/FKgasr3tDUK6H4wvWZ3leg--~B/Zmk9c3RyaW07aD00MzI7cHlvZmY9MDtxPTgwO3c9NzY4O3NtPTE7YXBwaWQ9eXRhY2h5b24-/https://media.zenfs.com/creatr-images/GLB/2018-01-15/3e6354f0-f995-11e7-ac44-6f84d116c845_image-8612 image
-http://www.tmall.com/ https://g.alicdn.com/mui/app-download-popup/4.0.12/index.js script
-http://www.amazon.com/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=BhfRrNo5QW2Bu-rPJQpTJA&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D image
-http://www.yahoo.com/ https://www.yahoo.com/_td_api/resource/contentList;ad_meta=true;category=;commentsEnabled=true;curveball=%7B%22sectionId%22%3A5417125%2C%22positionThreshold%22%3A100%2C%22enabled%22%3Atrue%2C%22genericViewability%22%3Afalse%2C%22count%22%3A5%2C%22lowerBound%22%3A2%2C%22fromContentAPI%22%3A0%2C%22fromCurveballAPI%22%3A1%2C%22enableBeaconListenerOnly%22%3Afalse%2C%22enableVisibilityRect%22%3Afalse%2C%22adChoicesUrl%22%3A%22https%3A%2F%2Finfo.yahoo.com%2Fprivacy%2Fus%2Fyahoo%2Frelevantads.html%22%2C%22host%22%3A%22www.yahoo.com%22%2C%22bucketId%22%3A%22900%22%7D;enable_vertical_video=true;lazyLoad=true;linkYlk=sec%3Agiraffe_viewer%3Bitc%3A0%2Celm%3Acontext_link%3B;offnetDeeplink=true;related_content_enabled=true;uuids=f9672bd8-4e71-35cb-84c1-b69be35c395e%2C5c745dce-961e-3233-8eca-bd37b7017dfc%2C4a7543d2-7daf-31da-9297-a6a92bdb48e8%2C328ee7c7-e319-3182-805b-1d0501c006fd%2Ce61ca6ee-3a3a-3b91-a26c-e5bd030fdd40%2Cb16b376b-3d3b-30ad-ab04-42282a239972%2C479e1b59-bbc4-336b-9fc1-1f19a09937ef%2Cb9ebc732-6bcb-35e4-bd82-cfa3893d10f1%2C82b7ddea-8ab8-3e33-9e78-374e5f4eaaed%2Cc989060a-41b1-317f-8e0d-7dcaaa9af556%2C316d9253-55d4-39fc-864e-80ff3a6d9108%2C73926325-9fb2-3dcf-98d5-d94711e355cd%2Ce9bc99e2-abf1-3747-9656-69041a29870e%2Cbaac751f-e7ea-3414-8ddb-87b30b6ca362%2C571e6da5-6668-3b0d-ba93-faf4ce8bad7f;vertical_video_ar=03x04?_appletType=viewer&_p=p1&authed=0&browserName=CH&browserVersion=58&bucket=900&cookieCapCount=2&crumb=&default_appletinit=now&default_page=p1&device=smartphone&enable_dd=&guid=&lang=en-US&locdrop_crumb=&mcCrumb=&messageCookieName=pmc&osName=Android&osVersion=6.0.1&region=US&rid=0s8hrq9d5p499&site=fp&ssl=1&ucsCrumb=&woeid=12797130 script
-http://www.amazon.com/ https://s.amazon-adsystem.com/ecm3?ex=adobe.com&id=71861573841976223923392367502500695704 image
-http://www.yahoo.com/ https://mbp.yimg.com/sy/os/mit/media/p/common/images/favicon_new-7483e38.svg image
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OE/ other
-http://www.yahoo.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1516015928233&yhlClientVer=3.42.4&yhlRnd=l5NMwI3rYUAKAP2E&yhlCompressed=0 other
-http://www.amazon.com/ https://fls-na.amazon.com/1/batch/1/OE/ other
-http://www.tmall.com/ https://g.alicdn.com/mui/datalazyload/4.0.21/index.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/nav-category/4.2.0/index.css css
-http://www.tmall.com/ https://g.alicdn.com/mui/prompt/4.0.2/css/loading.css css
-http://www.yahoo.com/ https://s.yimg.com/cv/ae/news/Purple-News.png image
-http://www.tmall.com/ https://g.alicdn.com/mui/nav-category/4.2.0/index.js script
-http://www.yahoo.com/ https://www.yahoo.com/_td_api/beacon/error?os=android&rid=0s8hrq9d5p499&bucket=900&device=smartphone&site=fp&code=&message=Uncaught%20ReferenceError%3A%20Notification%20is%20not%20defined&url=https%3A%2F%2Fwww.yahoo.com%2F&line=1502&file=&src=rt&_rdn=928345 image
-http://www.tmall.com/ https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/container.xtpl.js script
-http://www.yahoo.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1516015928721&yhlClientVer=3.42.4&yhlRnd=BmdmZCUjEhqZ0H3L&yhlCompressed=3 other
-http://www.yahoo.com/ https://mbp.yimg.com/sy/rz/l/favicon.ico image
-http://www.tmall.com/ https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/list.xtpl.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/menu.xtpl.js script
-http://www.yahoo.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197228339&yhlCT=2&yhlBTMS=1516015929552&yhlClientVer=3.42.4&yhlRnd=pWDPb0qGRcSkEgpp&yhlCompressed=0 other
-http://www.tmall.com/ https://g.alicdn.com/mui/nav-category/4.2.0/xtpl/nav.xtpl.js script
-http://www.yahoo.com/ https://yep.video.yahoo.com/js/3/videoplayer-min.js?r=nextgen-mobile&ypv=prod script
-http://www.tmall.com/ https://g.alicdn.com/mui/hybrid/4.2.18/index.js script
-http://www.yahoo.com/ https://s.yimg.com/rx/builds/0a171ecbb4/yvp-video-player.css css
-http://www.tmall.com/ https://g.alicdn.com/mui/custom-event/4.0.3/index.js script
-http://www.yahoo.com/ https://s.yimg.com/rx/builds/7.86.650.1513621494/assets/streamsense.min.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/mtop/4.1.4/index.js script
-http://www.yahoo.com/ https://video-api.yql.yahoo.com/v1/video/sapi/streams/95d43e5e-4822-3115-92f5-22954996f8ec?protocol=http&format=mp4&srid=510426770&rt=html&devtype=smartphone&offnetwork=false&region=&site=&expb=900&expn=giraffe&lang=&width=1&height=1&resize=true&ps=qlbe36fp&autoplay=false&image_sizes=&excludePS=true&acctid&synd=&pspid=1197228339&plidl=&topic&pver=7.86.650.1513621494&try=1&failover_count=0&firstVideo=95d43e5e-4822-3115-92f5-22954996f8ec&hlspre=true script
-http://www.tmall.com/ https://g.alicdn.com/mui/mtb-windvane/4.0.3/index.js script
-http://www.yahoo.com/ https://bats.video.yahoo.com/p?t=0.022473101591421685&_V=V&s=1197228339&V_sec=pb&evt=v_request&ccode=&sec=&cpos=&type=vod%20short&ss=vod&prefetch=false&host=www.yahoo.com&vid=95d43e5e-4822-3115-92f5-22954996f8ec&pstaid=95d43e5e-4822-3115-92f5-22954996f8ec&prt=none&cprt=none&lms_id=&vs=qlbe36fp&psz=nullxnull&ccap=0&ccav=0&cdn=uncalculated&st=none&sp=none&bit=0&pls=705129809&vlng=none&site=none&lang=&intl=none&lbl=none&synd=&pver=7.86.650.1513621494&pl_type=none&pl_uuid=&pl_intr=&expn=giraffe&expt=&expb=900&loc=onProp&auto=false&cont=1&replay=0&bckt=Retry_AfterLiveEventEnded_Bucket&snd=m&test=900%2C3.RTgzNDU0MgdSZXRyeV9BZnRlckxpdmVFdmVudEVuZGVkX0J1Y2tldAZfQ0hHAzAEX3ZlcgM0LjguMQ--&pt=content&pd=&pct=&pstcat=&ver=&pstaid_p=&pkgt=&subsec=&_w=https%3A%2F%2Fwww.yahoo.com%2F&vsid=&_R=&pltype=nextgen-mobile&cached_vs=&man=&class=&smpl=6&env=p&am=&rcmode=none&fav=0&focus=1&view=0%25&expm=na&deos=0&deom=1&_rid= text
-http://www.yahoo.com/ https://s.yimg.com/uu/api/res/1.2/0wX7rJO51Mv902PouYDymw--~B/aD05NjA7dz03MjA7c209MTthcHBpZD15dGFjaHlvbg--/https://slick-prod.s3-us-west-2.amazonaws.com/slick_thumb/giraffe-113428-1515980784493.jpg image
-http://www.tmall.com/ https://g.alicdn.com/mui/xtemplate/4.0.11/runtime.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/escape-html.js script
-http://www.yahoo.com/ https://bats.video.yahoo.com/p?t=0.09443856038928256&_V=V&s=1197228339&V_sec=pb&evt=v_api&ccode=&sec=&cpos=&type=vod%20short&ss=vod&source=player&url=%2F%2Fvideo-api.yql.yahoo.com%2Fv1%2Fvideo%2Fsapi%2Fstreams%2F95d43e5e-4822-3115-92f5-22954996f8ec%3Fprotocol%3Dhttp%26format%3Dmp4%26srid%3D510426770%26rt%3Dhtml%26devtype%3Dsmartphone%26offnetwork%3Dfalse%26region%3D%26site%3D%26expb%3D900%26expn%3Dgiraffe%26lang%3D%26width%3D1%26height%3D1%26resize%3Dtrue%26ps%3Dqlbe36fp%26autoplay%3Dfalse%26image_sizes%3D%26excludePS%3Dtrue%26acctid%26synd%3D%26pspid%3D1197228339%26plidl%3D%26topic%26pver%3D7.86.650.1513621494%26try%3D1%26failover_count%3D0%26firstVideo%3D95d43e5e-4822-3115-92f5-22954996f8ec%26hlspre%3Dtrue%26try%3D1&latency=487&http_code=200&resp_len=2228&instrument=%7B%22colo%22%3A%22gq1%2B%22%2C%22ue%22%3A%22true%22%2C%22statuses%22%3A%5B%22100%22%5D%2C%22messages%22%3A%5B%22ready%22%5D%2C%22vpaTrace%22%3A%5B%22dc-mobile_web~ms-vbr~p-default~s-default~css-static~csl-pq~csb-pq~rr-vod_traffic_all~rl-ar2%22%5D%7D&perf_info=na&perf_stack=na&vid=95d43e5e-4822-3115-92f5-22954996f8ec&pstaid=95d43e5e-4822-3115-92f5-22954996f8ec&prt=none&cprt=html&lms_id=a0770000007byQaAAI&vs=qlbe36fp&psz=1x1&ccap=0&ccav=0&cdn=atlas&st=mp4&sp=https&bit=0&pls=705129809&vlng=44&site=none&lang=&intl=none&lbl=none&synd=&pver=7.86.650.1513621494&pl_type=none&pl_uuid=&pl_intr=&expn=giraffe&expt=&expb=900&loc=onProp&auto=false&cont=1&replay=0&bckt=Retry_AfterLiveEventEnded_Bucket&snd=m&test=900%2C3.RTgzNDU0MgdSZXRyeV9BZnRlckxpdmVFdmVudEVuZGVkX0J1Y2tldAZfQ0hHAzAEX3ZlcgM0LjguMQ--&pt=content&pd=&pct=&pstcat=&ver=&pstaid_p=&pkgt=&subsec=&_w=https%3A%2F%2Fwww.yahoo.com%2F&vsid=1197228339&_R=&pltype=nextgen-mobile&cached_vs=&man=&class=&smpl=6&env=p&am=&rcmode=VBR&fav=0&focus=1&view=NaN%25&expm=na&deos=0&deom=1&_rid= text
-http://www.tmall.com/ https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/util.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/scope.js script
-http://www.yahoo.com/ https://geo.yahoo.com/p?s=1197228339&t=M9kt02Pgdjx0NGAt,0.8553399003517466&_I=&_AO=0&_NOL=0&_R=&_P=3.42.4%05_pl%031%04A_v%033.42.4%04test%03900%04_bt%03rapid%04A_pr%03https%04A_tzoff%030%04A_sid%03TzBbGY34z3QQlplM%04_w%03www.yahoo.com%2F%04_rid%030s8hrq9d5p499%04mrkt%03us%04pt%03home%04ver%03ss%04uh_vw%030%04colo%03slw1011.fp.gq1.yahoo.com%04navtype%03server%04nob%031%04offst_st%030%04A_cmi%03%7B%22AFT%22%3A7378%2C%22AFT1%22%3A7378%2C%22STR%22%3A6347.999811172485%2C%22VIC%22%3A7500%2C%22PLT%22%3A15639%2C%22DOMC%22%3A641%2C%22HTTPC%22%3A151%2C%22CP%22%3A99.8046875%2C%22NCP%22%3A100%2C%22AFTNOAD%22%3A7378%7D%04A_utm%03%7B%22COSTLY_RESOURCE%22%3A7457%2C%22X_FB1%22%3A10%2C%22X_FBN%22%3A22%2C%22DARLA_RSTART%22%3A6974%2C%22DARLA_REND%22%3A7032%2C%22darlaJsLoaded%22%3A6729%2C%22strmInteractive%20STOP%22%3A11358%2C%22header_aptNew%20START%22%3A15742%2C%22header_aptNew%20STOP%22%3A15973%2C%22breakingnews_aptNew%20START%22%3A16025%2C%22breakingnews_aptNew%20STOP%22%3A16030%2C%22streamv2_aptNew%20START%22%3A16038%2C%22streamv2_aptNew%20STOP%22%3A16147%2C%22viewer_aptNew%20START%22%3A16186%2C%22viewer_aptNew%20STOP%22%3A16240%2C%22header_aptNew%20DUR%22%3A231%2C%22breakingnews_aptNew%20DUR%22%3A5%2C%22streamv2_aptNew%20DUR%22%3A109%2C%22viewer_aptNew%20DUR%22%3A54%7D%04etrg%03backgroundPost%04outcm%03performance%04usergenf%030%04etag%03performance%04_E%03pageperf%04_ts%031516015933%04_ms%03590%04A_sr%03360x512%04A_vr%03360x512%04A_do%030 image
-http://www.tmall.com/ https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/linked-buffer.js script
-http://www.yahoo.com/ https://daarack01.vpg.cdn.yimg.com/yahoosports/9/9/redirect_0XpwpP6QPV97c7x0H3ZBNnDyD5xUkqLH72miqwJV-u4FGx2_mbm5MdoZVoMrYyG8kA6ScV_vpKI-~A3_30_0.mp4?a=yahoosports&b=5910&flags=marker_cslpq+marker_csbpq+marker_dist2000_3000km+marker_ar2+am_allow&ib=sapi&m=video%2fmp4&mr=0&ns=c+i+ci+cii+flags&vid=95d43e5e-4822-3115-92f5-22954996f8ec&x=1516665599&s=48e60f70c12b30f3b0654992a1d11060 video
-http://www.tmall.com/ https://g.alicdn.com/mui/xtemplate/4.0.11/runtime/commands.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/index.css css
-http://www.yahoo.com/ https://daarack01.vpg.cdn.yimg.com/yahoosports/9/9/redirect_0XpwpP6QPV97c7x0H3ZBNnDyD5xUkqLH72miqwJV-u4FGx2_mbm5MdoZVoMrYyG8kA6ScV_vpKI-~A3_30_0.mp4?a=yahoosports&b=5910&flags=marker_cslpq+marker_csbpq+marker_dist2000_3000km+marker_ar2+am_allow&ib=sapi&m=video%2fmp4&mr=0&ns=c+i+ci+cii+flags&vid=95d43e5e-4822-3115-92f5-22954996f8ec&x=1516665599&s=48e60f70c12b30f3b0654992a1d11060 video
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/index.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/lib/index.js script
-http://www.yahoo.com/ https://daarack01.vpg.cdn.yimg.com/yahoosports/9/9/redirect_0XpwpP6QPV97c7x0H3ZBNnDyD5xUkqLH72miqwJV-u4FGx2_mbm5MdoZVoMrYyG8kA6ScV_vpKI-~A3_30_0.mp4?a=yahoosports&b=5910&flags=marker_cslpq+marker_csbpq+marker_dist2000_3000km+marker_ar2+am_allow&ib=sapi&m=video%2fmp4&mr=0&ns=c+i+ci+cii+flags&vid=95d43e5e-4822-3115-92f5-22954996f8ec&x=1516665599&s=48e60f70c12b30f3b0654992a1d11060 video
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/template.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/template/list.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/lib/atp.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/template/banner.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/zepto/4.0.9/form.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/hotquery.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/native.js script
-http://www.tmall.com/ https://g.alicdn.com/mui/searchbar-m/4.0.20/plugin/custom-hotquery.js script
-http://www.tmall.com/ https://h5api.m.tmall.com/h5/mtop.tmall.wireless.minsk.tmallxbrand/1.0/?jsv=2.4.2&appKey=12574478&t=1516015833440&sign=7f86da07215d50d646927b60bdc50127&AntiCreep=true&api=mtop.tmall.wireless.minsk.tmallxbrand&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp2&data=%7B%22pageCode%22%3A%22SELECT_FRONT_PAGE%22%2C%22parmaMap%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D html
-http://www.tmall.com/ https://g.alicdn.com/alilog/??s/7.7.0/plugin/aplus_client.js,aplus_cplugin/0.2.11/toolkit.js,aplus_cplugin/0.2.11/monitor.js,s/7.7.0/aplus_std.js,aplus_cplugin/0.2.11/aol.js,s/7.7.0/plugin/aplus_spmact.js?v=20180109204418 script
-http://www.tmall.com/ https://fragment.tmall.com/mit/get_home_data?wh_callback=true script
-http://www.tmall.com/ https://login.taobao.com/jump?target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.tmall.wireless.minsk.tmallxbrand%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.2%26appKey%3D12574478%26t%3D1516015833440%26sign%3D7f86da07215d50d646927b60bdc50127%26AntiCreep%3Dtrue%26api%3Dmtop.tmall.wireless.minsk.tmallxbrand%26v%3D1.0%26ttid%3Dh5ttid%26type%3Djsonp%26dataType%3Djsonp%26timeout%3D2000%26callback%3Dmtopjsonp2%26data%3D%257B%2522pageCode%2522%253A%2522SELECT_FRONT_PAGE%2522%252C%2522parmaMap%2522%253A%2522%257B%255C%2522isH5%255C%2522%253A%255C%2522true%255C%2522%252C%255C%2522h5ttid%255C%2522%253A%255C%2522TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%255C%2522%252C%255C%2522pageCode%255C%2522%253A%255C%2522SELECT_FRONT_PAGE%255C%2522%257D%2522%257D html
-http://www.tmall.com/ https://login.taobao.com/jump?target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.tmall.tac.gateway.execute%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.2%26appKey%3D12574478%26t%3D1516015831431%26sign%3Dba2dda3547f688866462e02c223ff920%26AntiCreep%3Dtrue%26api%3Dmtop.tmall.tac.gateway.execute%26v%3D1.0%26ttid%3Dh5ttid%26type%3Djsonp%26dataType%3Djsonp%26timeout%3D2000%26callback%3Dmtopjsonp1%26data%3D%257B%2522msCodes%2522%253A%25222017080800%2522%252C%2522params%2522%253A%2522%257B%255C%2522isH5%255C%2522%253A%255C%2522true%255C%2522%252C%255C%2522h5ttid%255C%2522%253A%255C%2522TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%255C%2522%252C%255C%2522pageCode%255C%2522%253A%255C%2522SELECT_FRONT_PAGE%255C%2522%257D%2522%257D html
-http://www.tmall.com/ https://g.alicdn.com/alilog/oneplus/entry.js?t=210557 script
-http://www.tmall.com/ https://g.alicdn.com/secdev/entry/index.js?t=210557 script
-http://www.tmall.com/ https://tmm.m.taobao.com/member/user_login_info.mobile?callback=jsonp_34005426 script
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB14EMrQFXXXXX.XXXXXXXXXXXX-1500-320.png?getAvatar.png=_720x720Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1xVp9QVXXXXa5XFXXXXXXXXXX-1035-500.png_720x720Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1K9tEQVXXXXauaXXXXXXXXXXX-1035-500.png_720x720Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1uUKJQFXXXXb4XXXXXXXXXXXX-1500-76.png_720x720Q90s50.jpg_.webp image
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB13SW3QFXXXXawaXXXXXXXXXXX-108-105.png image
-http://www.tmall.com/ https://www.tmall.com/ html
-http://www.tmall.com/ https://gw.alicdn.com/tfs/TB1KruLQFXXXXX.XpXXXXXXXXXX-60-57.png image
-http://www.tmall.com/ https://ald.taobao.com/recommend.htm?appId=201512292&callback=jsonp_34755834 script
-http://www.tmall.com/ https://suggest.taobao.com/sug?area=tmall-hq&code=utf-8&src=mallfp..m&callback=jsonp_34799228 html
-http://www.tmall.com/ https://suggest.taobao.com/sug?area=tmall-hq&code=utf-8&src=mallfp..m&callback=jsonp_34808386 html
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1Fq0QQFXXXXbOaXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1iiXZQFXXXXbeaXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1c2yCQFXXXXa7XXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1EoCAQFXXXXcWXXXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/tfs/TB1doyvQFXXXXa2XpXXXXXXXXXX-160-160.png_100x150Q90s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/bao/uploaded/bao/upload/TB1vrwGNFXXXXbPXVXXwu0bFXXX.png_320x5000Q50s50.jpg_.webp image
-http://www.tmall.com/ https://img.alicdn.com/bao/uploaded/bao/upload/TB1wfrdOpXXXXaEaVXXwu0bFXXX.png_320x5000Q50s50.jpg_.webp image
-http://www.tmall.com/ https://wgo.mmstat.com/alihybrid.hybrid.call?cache=1f35c29&gmkey=EXP&gokey=api%3Dnetwork_getType%26platform%3Dweb_Android&cna=&spm-cnt=a223j.8443192.0.0.19143741hGIM4v&logtype=2 image
-http://www.tmall.com/ https://log.mmstat.com/eg.js script
-http://www.tmall.com/ https://pass.tmall.com/add?cookie2=120CAA53A0C5D5EDF86CB41AA81D9668&t=459EF2F0AF2799E16FA538E089C49963&_tb_token_=7017571898e9f&tmsc=1516015834931000&opi=10.103.184.135&pacc=FpL-3fCtNyQ0pxv6I6w7Mg==&target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.tmall.tac.gateway.execute%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.2%26appKey%3D12574478%26t%3D1516015831431%26sign%3Dba2dda3547f688866462e02c223ff920%26AntiCreep%3Dtrue%26api%3Dmtop.tmall.tac.gateway.execute%26v%3D1.0%26ttid%3Dh5ttid%26type%3Djsonp%26dataType%3Djsonp%26timeout%3D2000%26callback%3Dmtopjsonp1%26data%3D%257B%2522msCodes%2522%253A%25222017080800%2522%252C%2522params%2522%253A%2522%257B%255C%2522isH5%255C%2522%253A%255C%2522true%255C%2522%252C%255C%2522h5ttid%255C%2522%253A%255C%2522TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%255C%2522%252C%255C%2522pageCode%255C%2522%253A%255C%2522SELECT_FRONT_PAGE%255C%2522%257D%2522%257D other
-http://www.tmall.com/ https://pass.tmall.com/add?cookie2=1B43D2B9293A89E669E102B052E0BF45&t=F65181F8817CB1DF1BBF454E2CAE8CDE&_tb_token_=e4504e737eb0b&tmsc=1516015834933000&opi=10.103.184.135&pacc=Q0nysPHS6SxBQ2KUVrWnhg==&target=https%3A%2F%2Fh5api.m.tmall.com%2Fh5%2Fmtop.tmall.wireless.minsk.tmallxbrand%2F1.0%2F%3Ftbpm%3D1%26https%3Don%26jsv%3D2.4.2%26appKey%3D12574478%26t%3D1516015833440%26sign%3D7f86da07215d50d646927b60bdc50127%26AntiCreep%3Dtrue%26api%3Dmtop.tmall.wireless.minsk.tmallxbrand%26v%3D1.0%26ttid%3Dh5ttid%26type%3Djsonp%26dataType%3Djsonp%26timeout%3D2000%26callback%3Dmtopjsonp2%26data%3D%257B%2522pageCode%2522%253A%2522SELECT_FRONT_PAGE%2522%252C%2522parmaMap%2522%253A%2522%257B%255C%2522isH5%255C%2522%253A%255C%2522true%255C%2522%252C%255C%2522h5ttid%255C%2522%253A%255C%2522TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%255C%2522%252C%255C%2522pageCode%255C%2522%253A%255C%2522SELECT_FRONT_PAGE%255C%2522%257D%2522%257D other
-http://www.tmall.com/ https://g.alicdn.com/secdev/sufei_data/3.2.6/index.js script
-http://www.tmall.com/ https://wgo.mmstat.com/msearch.3.3?cache=ea981e0&gmkey=searchbar-placeholder&gokey=dim%3Dmallfp..m%26q%3D&cna=&spm-cnt=a223j.8443192.0.0.19143741hGIM4v&logtype=2 image
-http://www.tmall.com/ https://gm.mmstat.com/tmallacti.1003.1219.1?mmstat=download_homepage&t=1516015836956 image
-http://www.tmall.com/ https://wgo.mmstat.com//tmwap.1.auto?apuri=sb_appjump&mmstat=download_homepage&ui=default&r=1516015836962 image
-http://www.tmall.com/ https://img.alicdn.com/tps/TB19f3WKVXXXXcUXpXXXXXXXXXX-613-667.png_1080x1800Q50s50.jpg_.webp image
-http://www.tmall.com/ https://gw.alicdn.com/tps/TB1t4cwKVXXXXbjXXXXXXXXXXXX-64-64.png image
-http://www.tmall.com/ https://gw.alicdn.com/tps/TB1QUD8KVXXXXXeXVXXXXXXXXXX-29-32.png image
-http://www.tmall.com/ https://h5api.m.tmall.com/h5/mtop.tmall.tac.gateway.execute/1.0/?tbpm=1&https=on&jsv=2.4.2&appKey=12574478&t=1516015831431&sign=ba2dda3547f688866462e02c223ff920&AntiCreep=true&api=mtop.tmall.tac.gateway.execute&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp1&data=%7B%22msCodes%22%3A%222017080800%22%2C%22params%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D html
-http://www.tmall.com/ https://h5api.m.tmall.com/h5/mtop.tmall.wireless.minsk.tmallxbrand/1.0/?tbpm=1&https=on&jsv=2.4.2&appKey=12574478&t=1516015833440&sign=7f86da07215d50d646927b60bdc50127&AntiCreep=true&api=mtop.tmall.wireless.minsk.tmallxbrand&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp2&data=%7B%22pageCode%22%3A%22SELECT_FRONT_PAGE%22%2C%22parmaMap%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D html
-http://www.tmall.com/ https://img.alicdn.com/tps/TB1rqyaOVXXXXboXVXXXXXXXXXX-654-760.png_1080x1800Q50s50.jpg_.webp image
-http://www.tmall.com/ https://log.mmstat.com/m.gif?logtype=1&title=%u5929%u732BTMALL&pre=&cache=3f7d804&scr=360x512&cna=3H7jEiIKjVICAZUUPw0LnVYY&spm-cnt=a223j.8443192.0.0.19143741hGIM4v&category=&pre=&req_url=http%3a%2f%2fwww%2etmall%2ecom%2f&aplus&udpid=&asid=AQAAAADVkFxa05S5OwAAAABJzLWUScIAOA==&sidx=QDyN3MXcm2aoS4kktemC21WRTi3yWnSvZDpktWiVy9zYYA5b+bNhUJ+i5jul0y7VLTRHq8kqeLneUHZ9Tjf7jpREj2FUbjw3nz6WfLWipdSg0X8w3eCN2D8v3TU4xvRpgtrgx0/0RT6V6J3sHJpyMhMk137nawz8oea2hamGEhY=&ckx=|&p=1&o=android6.01&b=chrome58&s=360x512&w=webkit&ism=android&lver=7.7.0&jsver=aplus_std&mansndlog=1&urlokey=%2Fmain&tag=0&stag=2&lstag=0 image
-http://www.tmall.com/ http://www.taobao.com/ html
-http://www.tmall.com/ https://h5api.m.tmall.com/h5/mtop.tmall.tac.gateway.execute/1.0/?https=on&https=on&jsv=2.4.2&appKey=12574478&t=1516015831431&sign=ba2dda3547f688866462e02c223ff920&AntiCreep=true&api=mtop.tmall.tac.gateway.execute&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp1&data=%7B%22msCodes%22%3A%222017080800%22%2C%22params%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D script
-http://www.tmall.com/ https://h5api.m.tmall.com/h5/mtop.tmall.wireless.minsk.tmallxbrand/1.0/?https=on&https=on&jsv=2.4.2&appKey=12574478&t=1516015833440&sign=7f86da07215d50d646927b60bdc50127&AntiCreep=true&api=mtop.tmall.wireless.minsk.tmallxbrand&v=1.0&ttid=h5ttid&type=jsonp&dataType=jsonp&timeout=2000&callback=mtopjsonp2&data=%7B%22pageCode%22%3A%22SELECT_FRONT_PAGE%22%2C%22parmaMap%22%3A%22%7B%5C%22isH5%5C%22%3A%5C%22true%5C%22%2C%5C%22h5ttid%5C%22%3A%5C%22TMALL-H5-1.0.0-SELECT_FRONT_PAGE-0%5C%22%2C%5C%22pageCode%5C%22%3A%5C%22SELECT_FRONT_PAGE%5C%22%7D%22%7D script
-http://www.tmall.com/ https://wgo.mmstat.com/tmwap.1.7?apuri=sb_andriod_click_fail&mmstat=download_homepage&ui=default&r=1516015837776 image
-http://www.tmall.com/ http://www.taobao.com/ html
-http://www.tmall.com/ https://log.mmstat.com/eg.js script
-http://www.live.com/ http://www.live.com/ other
-http://www.tmall.com/ http://m.taobao.com/?sprefer=sypc00 html
-http://www.tmall.com/ http://m.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://outlook.live.com/owa/ html
-http://www.tmall.com/ https://m.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://cdn.optimizely.com/js/8066781501.js script
-http://www.live.com/ https://az725175.vo.msecnd.net/scripts/jsll-4.js script
-http://www.live.com/ https://r1.res.office365.com/owalanding/v1.16/landing.js script
-http://www.live.com/ https://r1.res.office365.com/owalanding/v1.16/images/landing-outlookappicon.png image
-http://www.tmall.com/ https://m.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://r1.res.office365.com/owalanding/v1.16/images/landing-playstore.png image
-http://www.live.com/ https://outlook.live.com/owa/prefetch.aspx html
-http://www.tmall.com/ http://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.tmall.com/ http://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://a3698060313.cdn.optimizely.com/client_storage/a3698060313.html html
-http://www.tmall.com/ https://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://web.vortex.data.microsoft.com/collect/v1/t.js?ver=%272.1%27&name=%27Ms.Webi.PageView%27&time=%272018-01-15T11%3A30%3A32.991Z%27&os=%27Android%27&appId=%27JS%3AOutlookCom%27&-ver=%271.0%27&-impressionGuid=%27d28ce16a-894f-4d91-a606-2ba521dd3215%27&-pageName=%27Home%27&-uri=%27https%3A%2F%2Foutlook.live.com%2Fowa%2F%27&-resHeight=512&-resWidth=360&-pageTags=%27%7B%22metaTags%22%3A%7B%7D%7D%27&-behavior=0&*baseType=%27Ms.Content.PageView%27&*cookieEnabled=true&*isJs=true&*title=%27Outlook.com%20-%20Microsoft%20free%20personal%20email%27&*isLoggedIn=false&*flashInstalled=false&ext-javascript-ver=%271.1%27&ext-javascript-libVer=%274.2.3%27&ext-javascript-domain=%27outlook.live.com%27&ext-javascript-userConsent=false&$mscomCookies=false script
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/styles/fonts/segoeui-regular.woff font
-http://www.tmall.com/ https://m.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.0.narrow.js script
-http://www.live.com/ https://logx.optimizely.com/log/event text
-http://www.tmall.com/ http://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.tmall.com/ https://m.intl.taobao.com/?sprefer=sypc00 html
-http://www.live.com/ https://web.vortex.data.microsoft.com/collect/v1?$mscomCookies=false&ext-javascript-msfpc=%27GUID%3D1c43e851df4b48e0bef4826167245d46%26HASH%3D1c43%26LV%3D201801%26V%3D4%26LU%3D1516015834776%27 script
-http://www.live.com/ https://outlook.live.com/favicon.ico image
-http://www.live.com/ https://outlook.live.com/owa/favicon.ico image
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.1.narrow.js script
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.2.narrow.js script
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.3.narrow.js script
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.png image
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.x2.png image
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.css css
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.x2.css css
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/styles/0/boot.worldwide.narrow.css css
-http://www.live.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/styles/fonts/office365icons.woff font
-http://www.instagram.com/ http://www.instagram.com/ text
-http://www.instagram.com/ https://www.instagram.com/ html
-http://www.instagram.com/ https://www.instagram.com/static/bundles/LandingPage.js/14ed40b34f19.js script
-http://www.instagram.com/ https://www.instagram.com/static/bundles/Vendor.js/c79ab33255d8.js script
-http://www.instagram.com/ https://www.instagram.com/static/bundles/en_US.js/e717774ba7e9.js script
-http://www.instagram.com/ https://www.instagram.com/static/bundles/ConsumerCommons.js/53454d5cef0f.js script
-http://www.instagram.com/ https://www.instagram.com/static/bundles/Consumer.js/3a795ab885e3.js script
-http://www.instagram.com/ https://www.instagram.com/static/images/appstore-install-badges/badge_android_english-en.png/f06b908907d5.png image
-http://www.instagram.com/ https://www.instagram.com/static/bundles/sprite_core_2x.png/9e7638226e17.png image
-http://www.instagram.com/ https://connect.facebook.net/en_US/fbevents.js script
-http://www.instagram.com/ https://connect.facebook.net/en_US/sdk.js script
-http://www.instagram.com/ https://connect.facebook.net/signals/config/1425767024389221?v=2.8.6&r=stable script
-http://www.instagram.com/ https://www.facebook.com/impression.php/f32f2ead482aa28/?api_key=124024574287414&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D image
-http://www.instagram.com/ https://www.facebook.com/tr/?id=1425767024389221&ev=PageView&dl=https%3A%2F%2Fwww.instagram.com%2F&rl=&if=false&ts=1516015901491&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=28&ttf=6601.39&tts=6212.610000000001&ttse=6597.130000000001&it=1516015901104 image
-http://www.instagram.com/ https://www.facebook.com/tr/?id=1425767024389221&ev=Microdata&dl=https%3A%2F%2Fwww.instagram.com%2F&rl=&if=false&ts=1516015902003&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Asite_name%22%3A%22Instagram%22%2C%22og%3Atitle%22%3A%22Instagram%22%2C%22og%3Aimage%22%3A%22%2Fstatic%2Fimages%2Fico%2Ffavicon-200.png%2Fa0d593d4e9d5.png%22%2C%22og%3Aurl%22%3A%22https%3A%2F%2Finstagram.com%2F%22%7D&cd[Meta]=%7B%22title%22%3A%22Instagram%22%2C%22meta%3Adescription%22%3A%22Create%20an%20account%20or%20log%20in%20to%20Instagram%20-%20A%20simple%2C%20fun%20%26%20creative%20way%20to%20capture%2C%20edit%20%26%20share%20photos%2C%20videos%20%26%20messages%20with%20friends%20%26%20family.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=28&ttf=7115.755000000001&tts=6212.610000000001&ttse=6609.43 image
-http://www.instagram.com/ https://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.instagram.com/ https://www.facebook.com/connect/ping?client_id=124024574287414&domain=www.instagram.com&origin=2&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FlY4eZXm_YWu.js%3Fversion%3D42%23cb%3Df2f2a43e17fefe4%26domain%3Dwww.instagram.com%26origin%3Dhttps%253A%252F%252Fwww.instagram.com%252Ff33d9400305da7c%26relation%3Dparent&response_type=token%2Csigned_request%2Ccode&sdk=joey html
-http://www.instagram.com/ https://www.instagram.com/static/images/ico/favicon-192.png/b407fa101800.png image
-http://www.instagram.com/ https://www.instagram.com/static/images/ico/favicon.ico/dfa85bb1fd63.ico image
-http://www.instagram.com/ https://graph.instagram.com/logging_client_events script
-http://www.google.co.jp/ http://www.google.co.jp/ html
-http://www.google.co.jp/ https://www.google.co.jp/?gws_rd=ssl html
-http://www.google.co.jp/ https://www.google.co.jp/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.co.jp/ https://www.google.co.jp/images/nav_logo242_hr.webp image
-http://www.google.co.jp/ https://www.google.co.jp/gen_204?s=webaft&atyp=csi&ei=zpBcWpztLcq-jwPnl4OgDA&rt=wsrt.2059,aft.146,prt.146 html
-http://www.google.co.jp/ https://www.google.co.jp/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.co.jp/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.co.jp/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.co.jp/ https://www.google.co.jp/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.co.jp/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.co.jp/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.360.cn/ http://www.360.cn/ html
-http://www.360.cn/ https://www.360.cn/ html
-http://www.360.cn/ https://p4.ssl.qhimg.com/t01a334284ab2c07df4.png image
-http://www.google.co.jp/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.360.cn/ http://m.360.com/ html
-http://www.360.cn/ http://m.360.cn/ html
-http://www.google.co.jp/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.360.cn/ https://s.ssl.qhmsg.com/static/0e4b4f909dd26431/jquery,qw.core.js script
-http://www.google.co.jp/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.360.cn/ https://p3.ssl.qhimg.com/t015eebd58e3c9362f7.png image
-http://www.google.co.jp/ https://www.google.co.jp/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.360.cn/ http://s8.qhmsg.com/!a04eed30/monitor131227.js script
-http://www.google.co.jp/ https://www.google.co.jp/images/nav_logo242.png image
-http://www.360.cn/ http://s1.qhmsg.com/static/c8b7de8c67377042/widget.1.0.2.js script
-http://www.google.co.jp/ https://www.google.co.jp/gen_204?atyp=csi&ei=zpBcWpztLcq-jwPnl4OgDA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.600,dcl.278,iml.600,ol.2580,prt.145,xjs.1685,xjsee.1684,xjses.1197,xjsls.161,wsrt.2059,cst.637,dnst.0,rqst.708,rspt.347,sslt.337,rqstt.1582,unt.943,cstt.944,dit.2337&zx=1516015825664 html
-http://www.360.cn/ http://s0.qhmsg.com/static/24fee17ef5eeefee/zepto_touch_fx.112.js script
-http://www.360.cn/ http://s3.qhmsg.com/static/92642666da227923/carousel.1.0.4.js script
-http://www.360.cn/ https://p1.ssl.qhimg.com/t0112454b2ad89460e8.png image
-http://www.360.cn/ http://p.ssl.qhimg.com/t01610f98dd079cf948.jpg image
-http://www.360.cn/ http://p2.qhmsg.com/t01ecc3b6b24e7bdbd8.png image
-http://www.360.cn/ http://p1.qhmsg.com/t01dd057241efdad2ad.png image
-http://www.google.co.jp/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.360.cn/ http://p2.qhmsg.com/t01e2a809acc329ae82.png image
-http://www.google.co.jp/ https://www.google.co.jp/images/branding/product/1x/gsa_android_144dp.png image
-http://www.360.cn/ http://p7.qhmsg.com/d/inn/2edf2228/aqrj/weishi_60.png image
-http://www.google.co.jp/ https://adservice.google.co.jp/adsid/google/ui html
-http://www.360.cn/ http://p7.qhmsg.com/t0192c6a682125e6cc9.png image
-http://www.360.cn/ http://p0.qhmsg.com/t01f222be1309c2fd7f.png image
-http://www.360.cn/ http://p9.qhmsg.com/t010fa93a99715aad32.png image
-http://www.360.cn/ http://p9.qhmsg.com/t01ac094f0e7138f4c1.png image
-http://www.360.cn/ http://p2.qhmsg.com/t01946e38139012bf1a.png image
-http://www.360.cn/ http://p9.qhmsg.com/t01dc430e8c4fbc2aee.png image
-http://www.360.cn/ http://p0.qhmsg.com/t01a1539e3423346062.png image
-http://www.360.cn/ http://p5.qhmsg.com/t019a6abf63f83db386.png image
-http://www.360.cn/ http://p5.qhmsg.com/t015c4a525a2379d9f6.png image
-http://www.360.cn/ http://p5.qhmsg.com/t017796b49e636afdd7.png image
-http://www.360.cn/ http://p15.qhmsg.com/t01c5bfd5968d038a63.png image
-http://www.360.cn/ http://p4.qhmsg.com/t01d7427e1f6239b1b1.png image
-http://www.360.cn/ http://p4.qhmsg.com/t01e4c126e44c6e0e47.png image
-http://www.360.cn/ http://p4.qhmsg.com/t01f9b7903b471806d0.png image
-http://www.360.cn/ http://p3.qhmsg.com/d/inn/2edf2228/aqrj/Box_60.png image
-http://www.360.cn/ https://p.ssl.qhmsg.com/t0108746fb9d4417925.png image
-http://www.360.cn/ http://p4.qhmsg.com/t0189741dcf6c159d34.png image
-http://www.360.cn/ http://p6.qhmsg.com/t01a03df1ddec4c9046.png image
-http://www.360.cn/ http://p3.qhmsg.com/t01c0561be4b31c1466.png image
-http://www.360.cn/ http://p9.qhimg.com/t01bccedbc0d45dd194.png image
-http://www.360.cn/ https://p2.ssl.qhimg.com/t01c4239d3c1e617adf.png image
-http://www.360.cn/ https://p5.ssl.qhimg.com/t0182c18bafd2389586.jpg image
-http://www.360.cn/ http://p2.qhimg.com/t01dfc013c7b3c21ac3.png image
-http://www.360.cn/ http://p2.qhimg.com/t012320e7677a2a8613.jpg image
-http://www.360.cn/ http://p9.qhimg.com/t01926a306f89be23f3.jpg image
-http://www.360.cn/ http://p3.qhimg.com/t01aba831f3e831c0e7.jpg image
-http://www.360.cn/ http://p3.qhimg.com/t01fb225170c5a262ee.jpg image
-http://www.360.cn/ http://p3.qhmsg.com/t01abe6ce0386485d19.png image
-http://www.360.cn/ http://p0.qhmsg.com/t01f025a32b676961bb.jpg image
-http://www.360.cn/ http://p6.qhmsg.com/t01f8ae6ea3d7f727ff.png image
-http://www.360.cn/ http://p5.qhmsg.com/t0139a3cf9218887d3d.png image
-http://www.360.cn/ http://p8.qhmsg.com/t0105139de64586cf40.png image
-http://www.360.cn/ http://haostat.qihoo.com/haopv.gif?b=chrome&a=1&u=http%3A%2F%2Fm.360.com%2Findex.html&id=59677681.3104270938398971000.1516015983656.348&c=1&r=&t=1516015983700 image
-http://www.360.cn/ http://haostat.qihoo.com/haouv.gif?b=chrome&a=1&u=http%3A%2F%2Fm.360.com%2Findex.html&id=59677681.1307132661243331600.1516015983660.477&c=1&r=&t=1516015983700 image
-http://www.360.cn/ http://www.360.cn/favicon.ico image
-http://www.sohu.com/ http://www.sohu.com/ html
-http://www.sohu.com/ https://m.sohu.com/?pvid=000115_3w_index&jump=front html
-http://www.sohu.com/ https://statics.itc.cn/mobile/css/main-b1ae680282.css css
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/mobile/sohu-logo-d.png image
-http://www.sohu.com/ https://statics.itc.cn/mobile/js/lib-d117b294bc.js script
-http://www.sohu.com/ https://statics.itc.cn/mobile/js/main-756c257517.js script
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_899,h_600/os/news/cc67b1141f5ccfaab80d44551f54b210.jpg image
-http://www.sohu.com/ https://js.sohu.com/pv.js?_t=20171214 script
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_899,h_600/os/news/15b4a5a37316ca0bc31c603ef22d7a6.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_982,h_654/os/news/c1259a2968e87870fb0b5aed11c2f08e.jpg image
-http://www.sohu.com/ https://statics.itc.cn/mobile/css/images/loading-50508229.gif image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_12,y_0,w_429,h_286/os/news/d57508c1483fb4520a0bcc5df9f30ced.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_35,w_880,h_586/os/news/c46e39fd72563245f3a3a2f6b4f46b2a.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_639,h_426/os/news/c899fc828c0c8041f95d7bf68ca490aa.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/c_cut,x_0,y_0,w_899,h_600/os/news/59660c11cd066d244cbef16627aef7ee.jpg image
-http://www.sohu.com/ https://statics.itc.cn/mobile/css/images/sicon-f812a5cc.woff font
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_fill,w_640,h_320,g_faces/os/news/4cddaf0e18ad071dc6c8eace2d9003d7.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_0,y_13,w_673,h_449/os/news/cc190686a89f3466b2ce542a6cef6222.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_48,y_24,w_308,h_205/os/news/5255798995305b34ffe1c43cf2956087.jpg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/74b2b1ff0d244e88886b720bc0bd7ef7.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/0ee0a762e2114c6cbd2dc461f1314b27.jpeg image
-http://www.sohu.com/ https://39d0825d09f05.cdn.sohucs.com/sdk/passport-4.0.2.js script
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_87,y_15,w_868,h_579/os/news/2881b32c107a8dc539877167d3803f31.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_128,y_14,w_481,h_320/os/news/f890b04ea91ef55051a4af873a31fbf7.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_26,y_15,w_559,h_372/os/news/7fb55b0eb33c05b401c44cf29d2934dd.jpg image
-http://www.sohu.com/ https://29e5534ea20a8.cdn.sohucs.com/q_70,c_zoom,w_375/c_cut,x_0,y_32,w_504,h_336/os/news/1e53842b9c6af6c260937ebebd43319f.jpg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/86d36a9f40a5405cb4a797bf1697e602.gif image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/1561836e1ea94df8a7a0abf6d59f19a9.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/14d003919c00404eb266f80dbf4bbc04.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/947920449b2646b69a0f6a8c421c54a2.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/a472bfdadbdd41368e636ba4cc71963e.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/4e88d42f510d461c8925f2dae63b84db.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/1fd708b95dd048ff8a989d6292a0f3c6.jpeg image
-http://www.sohu.com/ https://5b0988e595225.cdn.sohucs.com/q_70,c_fill,w_320,h_240,g_faces/images/20180115/a5943f25990a4d6fbe40f92771b3febe.jpg image
-http://www.sohu.com/ https://api.k.sohu.com/IdConverter/servlet/IdConverter?mpId=undefined&reqType=mpId html
-http://www.sohu.com/ https://pv.sohu.com/suv/?t?=1516016047163899_360_512?r?=?url?=https%3A%2F%2Fm.sohu.com%2F%3Fpvid%3D000115_3w_index%26jump%3Dfront?SUV?= script
-http://www.sohu.com/ https://statics.itc.cn/mobile/ucenter/images/ic_home_photo_gray.png image
-http://www.sohu.com/ https://pv.sohu.com/prom_ev.gif?posId=undefined&itemId=undefined&SUV=null&_time_=15160160541930233736205615 script
-http://www.sohu.com/ https://pv.sohu.com/prom_ev.gif?posId=10080101&itemId=4740&SUV=null&_time_=15160160541930199861562609 script
-http://www.sohu.com/ https://pv.sohu.com/prom_ev.gif?posId=10080201&itemId=4788&SUV=null&_time_=15160160541932523692553574 script
-http://www.sohu.com/ https://v2.sohu.com/public-api/frag/bussiness_touch_index?callback=jQuery32107006455308167654_1516016047029&_=1516016047030 script
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054069_4276869632754&itemspaceid=12273&adps=6400320&apt=4&turn=4&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054069 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054095_7936026958454&itemspaceid=12417&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054095 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054076_9533972584629&itemspaceid=12781&adps=6400320&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054076 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054081_4634169150803&itemspaceid=12416&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054081 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054086_9741901833476&itemspaceid=15690&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054086 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054091_9397293999815&itemspaceid=13702&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054091 html
-http://www.sohu.com/ https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_1,m-index_top_news_1,m-index_top_news_2,m-index_top_news_3,m-index_tv_tg_1,m-index_tv_tg_2,m-index_top_pic_1&relatedID=&news=0_0,216692496_157267,216823078_260616,216823229_115376,0_0,0_0,0_0&SUV=null&_time_=15160160551909100158645545 script
-http://www.sohu.com/ https://www.qchannel03.cn/m2.js?w=sohunews script
-http://www.sohu.com/ https://hotword.sogoucdn.com/hot_word.json?callback=_getjson&_=1516016047028 script
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054101_3065338380062&itemspaceid=12418&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054100 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054108_9710875867587&itemspaceid=12421&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054108 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054106_9432400916048&itemspaceid=12420&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054106 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054103_8707894241530&itemspaceid=12419&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054103 html
-http://www.sohu.com/ https://adv-sv-stat.focus.cn/adv/producer/sendLog?type=2&ad_type=0&demander_id=-1&plan_id=-1&order_id=-1&idea_id=-1&estate_id=-1&city_id=-1&city_name=&area_code=-1&ad_pos_id=-1&resource_id=-1&bid_hash=&domain=m.sohu.com&source_agent=4&referer_url=&user_yyid=&user_ecoid=-1 other
-http://www.sohu.com/ https://wuliao.epro.sogou.com/ask/?callback=jsonp_1516016054172_0343461246751&id=563067&_time_=1516016054171 html
-http://www.sohu.com/ https://txt.go.sohu.com/ip/soip?_=1516016047031 script
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054112_7940105223043&itemspaceid=13784&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054112 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054113_2436637075017&itemspaceid=12423&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054113 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054116_9661025339567&itemspaceid=12424&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054116 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054118_6741447384359&itemspaceid=12425&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054118 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054121_7058535805244&itemspaceid=12426&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054121 html
-http://www.sohu.com/ https://wuliao.epro.sogou.com/wapxml?id=563067&hd=75&m=&if=16&ex=1&tmp_cdif=0&sohuurl=https%3A%2F%2Fm.sohu.com%2F%3Fpvid%3D000115_3w_index%26jump%3Dfront&refer=&ti=%E6%89%8B%E6%9C%BA%E6%90%9C%E7%8B%90%E7%BD%91&ua=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&rnd=6318f5fcfc776613&z=f3809d409d3e71ea&ssi0=1796&bs=360,512 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054123_6276207541612&itemspaceid=12428&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054123 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_12781&impid=&at=1&mkey=&latcy=1673&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=5988070684294&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016055752 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054126_8035311548299&itemspaceid=12278&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054126 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4255921&apid=beans_12273&impid=fa52845998f99ba92ba2a4f5e1e7ab7b00&at=1&mkey=20q1K0VC50000003jya10hR9T&latcy=1703&freq=0&turn=4&pgid=sohu_index&ax=360&ay=141.09375&cx=&cy=&ed=58A87D34BB63AA9A898F28B2B940EC6B09F69308CD19D5ED2B0DD008242095CC7BFDF3023158A6ADDFC9813AE1B3433FB828C29AA9C405215201101A5E151030CD1550305F33ADA244475BB9C728AE99&bucket=priority_n&supplyid=4&ext=6&rsln=360*512&sf=0&r=1552602198500&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D4%09hours%3D%09indexnode%3Dsearctest%09priority%3D300%09mediaid%3D2%09markettag%3D%09bidid%3D436ca0fcb90a4c31ab3d2e8ce91d7cff%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D18014424723881984%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=6C4C39981E6EE7F481F89796BDD2988FB828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&pagerefer=&_time_=1516016055835 html
-http://www.sohu.com/ https://images.sohu.com/bill/r2018/0108/ChAKr1pS1QCAT2msAAC_omDrj_8290.jpg image
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054128_2916209535265&itemspaceid=12274&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054128 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054131_6828448552535&itemspaceid=12279&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054131 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054139_1291959492275&itemspaceid=12275&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054139 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4222465&apid=beans_15690&impid=ac2d6f5aca32bd7bfb408dd3f7cae4e000&at=1&mkey=20xiH0Vkg0000003hPX50hIsh&latcy=1791&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=981.828125&cx=&cy=&ed=9E84B76ADA7B33729C7B0F18BFDCCD8251911AA0EA3A95F3E0E43BFED52021B396C104062947C40087C5A79EFD015773A7B9225040D7533994D813CFAB116DDAADCA4BFAC5E5B6F0B31F16372A982C401C6AD2B6ACFCF101010899D9FF06469357583A3D361AC78541DD77B7CEF0392DDE273725CA6DEB290213C29F5632B2DF033A27BF1B39FFB47C8BC67CB128538D62620074A7C4E97176E583CF8947ECC6144BF2A74D1C07547D96B5A6D759C572B828C29AA9C405215201101A5E151030382999D0D69FFC52EBCB5F2E36219729&bucket=252_self_rank_14_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=8929816321089&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D137%2E602%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=986BA562778DAB2AAA8CEFA1297737A7A084792514DAAD778523733F5DB77ABC9C2A89DD5367DAEC36DCE2610918433E&e=BB14FE33D7289201C515B0E16C237446B828C29AA9C405215201101A5E151030F064DECA2CEE35A7B45B0207C6A06BD3&pagerefer=&_time_=1516016055889 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054141_9879294012248&itemspaceid=12281&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054141 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4287461&apid=beans_13702&impid=96bb67d9acb1290be7d70e796fb923c600&at=1&mkey=20yBC0VWK0000003la450hZmB&latcy=1805&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=1566.984375&cx=&cy=&ed=F5B0D5DDE556E31EF511F020D7706FA42A40611793B265865C40E4E9167C7411DE027399C215D4EC0162C917025D2130DC360875082505721FDC46810FBC85D415BEA3BF9DC8B4B13AC689E9A27D275B18E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_12_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=9503128240635&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14287461%09rankscore%3D82%2E4357%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=64C45BBC5E76F29591753CF6F440281A224C383744FBFEA3006498994B637AAF45CB6A7EA50998DECE0F809DD23483B3&e=F5B0D5DDE556E31EF511F020D7706FA4B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016055901 html
-http://www.sohu.com/ http://pmptrack-sohu.gentags.net/sohu/win?&bidid=436ca0fcb90a4c31ab3d2e8ce91d7cff&win=FB35093CB575B01E832A3CA1D8C09AB13559DE5D36B5D1672EF7E8B31F63CB5B&display=bidid=436ca0fcb90a4c31ab3d2e8ce91d7cff__impid=0__pid=12273__bcc_id=708__crt_id=11420__mtid=43476__uid=1801151934117VED__uidt=cookie_ori__dealid=221469!790138__region=1000000000__city=1392000000__fq=260__vusr=10000074__dmp=0__ta=0__aud=1801151934117ved_5__pl=3__check=-1391424936&_time_=1516016055836 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054142_7505566064173&itemspaceid=13818&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054142 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054145_0398426314316&itemspaceid=12280&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054144 html
-http://www.sohu.com/ https://images.sohu.com/bill/s2017/materials/jd/0921/3272.html?clkm=%2F%2Fi.go.sohu.com%2Fcount%2Fc%3Faid%3D4256004%26apid%3Dbeans_12274%26impid%3D8d0fd3553bb02955cb6f1401f62501df00%26at%3D1%26mkey%3D20qAw0VC60000003jy530hRbe%26latcy%3D3680%26freq%3D0%26turn%3D1%26pgid%3Dsohu_index%26ax%3D12.953125%26ay%3D1701.140625%26cx%3D%26cy%3D%26ed%3DA3BBAA21FA7672B001FC98D56D431061BF8E0C2C8201154416EDB8FD424354D9E9DB80F9AEC3520D458893CD806A3583B828C29AA9C405215201101A5E151030D94DA61E803B6ADC8793B70972585198%26bucket%3Dpriority_n%26supplyid%3D4%26ext%3D0%26rsln%3D360*512%26sf%3D0%26r%3D8229464062878%26uloc%3D935651042131968%26newschn%3D1000000000%26subchannelid%3D%26ch_trans%3D%26jsv%3D%26ipos%3D1%26shbd_monitor_ext%3Dturn%253D1%2509hours%253D%2509indexnode%253Dsearctest%2509priority%253D250%2509mediaid%253D2%2509markettag%253D%2509bidid%253D%2509uid%253D1801151934117VED%2509form%253D%2509sperotag%253Dv1%252E3%252E36%2509acc%255Findustry%253D25051272930197500%2509tgid%253D%2509arloc%253D%2509newsid%253D%2509newstag%253D%2509adtype%253D%2509lsc%253D%2509ssc%253D%2509freqid%253D%2509rankscore%253D0%2509ctrfilter%253D%2509servip%253D10%252E11%252E152%252E57%26c%3D333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B%26e%3D2E9E25B7287B504564C10A6ABF841CAAB828C29AA9C405215201101A5E151030203015AF69119DD3E2115F46B857AE24%26pagerefer%3D%26_time_%3D1516016057851 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054146_2348252459763&itemspaceid=13819&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054146 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054148_0355600888195&itemspaceid=12288&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054148 html
-http://www.sohu.com/ https://www.qchannel03.cn/1.gif?domain=m.sohu.com&account=sohunews&channel=&point=&platform=android&ts=1516016056054&dur=0 image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=3634864&apid=beans_12417&impid=493d7933902b2b9a0d4547e3b62a93c600&at=1&mkey=20wKz0Qef0000002KgX50ffAQ&latcy=2240&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=3103.5&cx=&cy=&ed=8DA5582DB74188573FC27DA51C712DBB2999AA5A685946667CC26B2BAD96913A6EB860CDC45C3ABED245E7153E9A5330290CCE3E885C6637A3B91CE797221FDA9DAE464A7A3ADF1B343A3D1F903B390218E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_12_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=9287704595887&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D64%2E2974%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=521EDE72E79E6C17ED843951423B73FC9E5E617BF6413E0FDD7F172A6744BBDB45CB6A7EA50998DECE0F809DD23483B3&e=8DA5582DB74188573FC27DA51C712DBBB828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016056341 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054150_7810763092055&itemspaceid=12282&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054150 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4269743&apid=beans_12418&impid=a88e726c4e9ff233dec13d35891fd86800&at=1&mkey=20y960VL30000003kdX50hUKP&latcy=2408&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=1985.859375&cx=&cy=&ed=650C42E7A4DED1684A2E58BF91B7A78D98D810933491F260809D2968A62B737280981999DD8F82BA8BB73CE96B979BD194BD4F11CA629C21D69EDC91254EA774550344DFB559125324CF657830BFCCFA18E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_43_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4607671649993&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14269743%09rankscore%3D67%2E316%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=10D8ACB60C7A50A7AD266053467C8A26D938B9BEAA5D9492985ABB82EA33529945CB6A7EA50998DECE0F809DD23483B3&e=650C42E7A4DED1684A2E58BF91B7A78DB828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016056519 html
-http://www.sohu.com/ https://imp.optaim.com/201712/7a0aeccb157b3eb6a8168ce6ba09dd0e.php?a=0&adpid=beans_12273&impid=fa52845998f99ba92ba2a4f5e1e7ab7b00&_time_=1516016055836 image
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054152_8067333770407&itemspaceid=12291&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054152 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054154_7550587424596&itemspaceid=13820&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054154 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054156_7078042894353&itemspaceid=13821&adps=30000002&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054156 html
-http://www.sohu.com/ https://images.sohu.com/bill/s2016/jscript/lib/sjs/matrix/ad/tf.js script
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054158_4070171768746&itemspaceid=12290&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054158 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4198747&apid=beans_12420&impid=aa5b5e8a4d0b40705d93fbea3d7203de00&at=1&mkey=20yMA0V9e0000003guz50hChJ&latcy=2439&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=4484.703125&cx=&cy=&ed=8A9129EBE1D6D9BE9AF72D4BFFE797B6CCE34BC498A353DAA166C0516017DF9BD41BEF8BCF14445F6CD7D7589989AD5D30296BDF2F2246932DA889BA13E0310DBA40CE876D38063A0BE60CBD41541C645C03A24499681DD6043CFEA70BB01C30DC9C4B3E01538C7DBF41096E06AB4EEB9AB40D387D9711FF52EE8F3AAA3AC6BAAAB3A8DF89CCC7C8ED4000E9D14C81F7EBA8D3986E483E4E6DBB2D4B53E89E0ACC719B2A424F6256C36308F95E8B95E3B828C29AA9C405215201101A5E15103051E70C6579FE1344DBBC8B21A2FC9C04&bucket=252_self_rank_62_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4029896098710&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14198747%09rankscore%3D84%2E833%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=8FB04BB824954C764FE647C25838DE2F2BD075079B546FE9981B6F8809611C9845CB6A7EA50998DECE0F809DD23483B3&e=8A9129EBE1D6D9BE9AF72D4BFFE797B6B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016056549 html
-http://www.sohu.com/ https://theta.sogoucdn.com/wap/js/anticheat-min.js script
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4220133&apid=beans_12421&impid=32d264a792374c736770de8daa2ec36200&at=1&mkey=20ylF0ViJ0000003hHv50hHQF&latcy=2461&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=6009.296875&cx=&cy=&ed=1F4E1CEF999C9345D63B47D5291412A717EFCC92C984099F569A36BF2852634537F8D0DE0F2BCF1E51B1AC8627582EEB0C64CD89B2CA88711F98EF4667BBE67190ABF6FCFF4AC6D1E402B3FA8E6D81355C03A24499681DD6043CFEA70BB01C30DC9C4B3E01538C7DBF41096E06AB4EEB9AB40D387D9711FF52EE8F3AAA3AC6BAAAB3A8DF89CCC7C8ED4000E9D14C81F7EBA8D3986E483E4E6DBB2D4B53E89E0ACC719B2A424F6256C36308F95E8B95E3B828C29AA9C405215201101A5E15103051E70C6579FE1344DBBC8B21A2FC9C04&bucket=252_self_rank_93_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=1423949760394&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D54%2E7692%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=28768CCD6E6A072FD9322F05E5FB19A08416B8F303A289590E26A8A27379AD9845CB6A7EA50998DECE0F809DD23483B3&e=1F4E1CEF999C9345D63B47D5291412A7B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016056573 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054162_9329191084551&itemspaceid=12292&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054162 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054164_2401418922062&itemspaceid=12293&adps=160001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054164 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=2615235&apid=beans_12419&impid=6310f7f035d8730c35c37d5aed4d3b0000&at=1&mkey=20u950J4X00000021GM50aYld&latcy=2628&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=2613.71875&cx=&cy=&ed=9AF87B6D82BC7A7F182918239BDFD7C525427539D323DF7578AF70A6E33D7D7C73C96FE51A0F0188A205F96B28FE4E3226FA35604ABE5C35472213F9A0E1DCE97653D0B9DAC5DFDD8ECEF853D35B221318E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_96_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=0972345358466&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D41%2E6585%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=48ED4E8601D737E0376477541F14B9B5EFF593AF8A78342C5FB0754F5C346C5645CB6A7EA50998DECE0F809DD23483B3&e=9AF87B6D82BC7A7F182918239BDFD7C5B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016056739 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054167_6369115912775&itemspaceid=13455&adps=6400120&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054167 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054169_9488023151479&itemspaceid=13713&adps=6400320&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054169 html
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016054324_5628213164311&itemspaceid=15697&adps=4800640&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016054324 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4301141&apid=beans_12416&impid=ca5a5deb3488414f94a9e1ca6bdb8d0200&at=1&mkey=20yZh0W4O0000003lTD50i2Vf&latcy=2867&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=731.046875&cx=&cy=&ed=27A47BE547A7634C4182AC11C373F1D80F81F03125DEC9EDEB175567E3F0041293BA3D7168B2F50BCF0B3BE7AB236EC4E40AFFBF2509186BE7961D2F5E8F7D1DC7F10B94AAF5550856FD284DAEB716FC1C6AD2B6ACFCF101010899D9FF06469357583A3D361AC78541DD77B7CEF0392DDE273725CA6DEB290213C29F5632B2DF033A27BF1B39FFB47C8BC67CB128538D62620074A7C4E97176E583CF8947ECC6144BF2A74D1C07547D96B5A6D759C572B828C29AA9C405215201101A5E151030382999D0D69FFC52EBCB5F2E36219729&bucket=252_self_rank_92_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=2332139916029&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D119%2E288%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=196A18AF68AD6966AE4DEC3B5C8A1249A391498B04C2FA8039A403B7C6AA319F9C2A89DD5367DAEC36DCE2610918433E&e=27A47BE547A7634C4182AC11C373F1D8B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016056952 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4307950&apid=beans_13784&impid=4a71fa0b51b760de26008e421c5beae800&at=1&mkey=20yih0W9r0000003meZ50i4H4&latcy=2892&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=6752.359375&cx=&cy=&ed=5FFB62DDF29D6BDF30774D7A79C76E1E81226C97F01E624DD62D19B8F86A32D3D5DF55550EE73ED383A8122213FAA1B8C0B0351DADD83263DAAD2E2F6228B3C94CF7E444E87500FC3F670B7ED279A3325C03A24499681DD6043CFEA70BB01C30DC9C4B3E01538C7DBF41096E06AB4EEB9AB40D387D9711FF52EE8F3AAA3AC6BAAAB3A8DF89CCC7C8ED4000E9D14C81F7EBA8D3986E483E4E6DBB2D4B53E89E0ACC719B2A424F6256C36308F95E8B95E3B828C29AA9C405215201101A5E15103051E70C6579FE1344DBBC8B21A2FC9C04&bucket=252_self_rank_24_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=5842409421420&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D32%2E3441%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=3AC3D7B7F9297891737AD6B7A6B132414970E6F505C57729CC7B58685EC7D77745CB6A7EA50998DECE0F809DD23483B3&e=F263DEF26CD241ADF57CACCBE0FA1CE3B828C29AA9C405215201101A5E1510300F40438B9EB21B59CBC67C1A9F1BDBC2&pagerefer=&_time_=1516016057006 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=3600776&apid=beans_12423&impid=3fb6501f01bf6a40329ed83fb10e139500&at=1&mkey=20tns0PU20000002Imj50f6J2&latcy=3036&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=5214.15625&cx=&cy=&ed=930344891DF74BA3DA7EFAC38985326AFD4F18F7FCBC88BD07B90F15B6DB62A5F98805C26CD58799CA765A78EB96C34ABD9AE4C3A54A8352789923286EA56E502B3B2B0064D5478D95E67FCB1340621818E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_3_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4945386528205&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D27%2E544%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=6BC2A11B0C4FC1D504D607D7DECB3248E27C931359FD67822256814E773696BB45CB6A7EA50998DECE0F809DD23483B3&e=930344891DF74BA3DA7EFAC38985326AB828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016057156 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4288225&apid=beans_12424&impid=f11a3752cf431de1d56c173777a2c52f00&at=1&mkey=20yX20VX30000003le250hZyV&latcy=3059&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=3940.34375&cx=&cy=&ed=59CC6742A49A72AC83AD9961473B5BFF1591F882A7779BE370AC087F98251C6CDE2747FFC37B94CA112E81D32C7D96DBEC8AA8DA40948DD5D5BC443C1051ABC1866881B2B865349D567A4CB9A36C50455C03A24499681DD6043CFEA70BB01C30DC9C4B3E01538C7DBF41096E06AB4EEB9AB40D387D9711FF52EE8F3AAA3AC6BAAAB3A8DF89CCC7C8ED4000E9D14C81F7EBA8D3986E483E4E6DBB2D4B53E89E0ACC719B2A424F6256C36308F95E8B95E3B828C29AA9C405215201101A5E15103051E70C6579FE1344DBBC8B21A2FC9C04&bucket=252_self_rank_20_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=0503666482293&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D32%2E2487%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=30386DB1394070CA458AB66D28A81586CCF5472493E00EB42C8DDFE0726BEFCE45CB6A7EA50998DECE0F809DD23483B3&e=59CC6742A49A72AC83AD9961473B5BFFB828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016057182 html
-http://www.sohu.com/ https://theta.sogoucdn.com/wap/images/sg_logo.png image
-http://www.sohu.com/ https://imp.optaim.com/201712/9144061f289277cffc2998771b46460b.php?a=0&adpid=beans_12292&impid=84ffe27386c1ab1d91b45910b562b27200&_time_=1516016059581 image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4299062&apid=beans_12426&impid=4d020640a6e2eb44bffb89064968ac2d00&at=1&mkey=20y9N0W350000003lN850i2nI&latcy=3258&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=5771.21875&cx=&cy=&ed=049DDE12731878A6416C2455B4203FB8B29EFA8C91D0195039D748F0207AED9A64ADEB793D8920321248FBF4A0A53473&bucket=random_noctr_32_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=7944096112741&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=38D15895D7BCFCF83575AB39CF5FD96DB828C29AA9C405215201101A5E15103025D911FC7E18B952EC3F04E70CEDA425&pagerefer=&_time_=1516016057383 html
-http://www.sohu.com/ https://imp.optaim.com/201712/bbecd8ce10bd20a2ab11aa2e161d8947.php?a=0&adpid=beans_12274&impid=8d0fd3553bb02955cb6f1401f62501df00&_time_=1516016057851 image
-http://www.sohu.com/ https://images.sohu.com/saf/a2018/0109/ChAKr1pUeZKAY5FSAAAyBUGG9oE606216x151.jpg image
-http://www.sohu.com/ https://images.sohu.com/saf/a2018/0112/ChAKr1pYRh6ABAGfAAArMxLMVfk084216x151.jpg image
-http://www.sohu.com/ https://static-alias-1.360buyimg.com/jzt/tpl/sspPicH5.html?ad_ids=3272:5&adflag=0&clkmn=&expose= html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=3956186&apid=beans_12428&impid=2010136f547b432582aa14de02ec63ce00&at=1&mkey=20v3u0Tgq000000349E50gBbs&latcy=3459&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=10347.84375&cx=&cy=&ed=E191A8906D596AD1CA397A0978B325A1B713310A993D182AD169494ADECABF040AF5AAF1EAAC0D54A1A1D61AFD52A6061C1B866F6C8F6D696353A80F68FF13B05AC4EADE5E5594C19C60C84C0AC4762A18E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_34_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4622831129964&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D25%2E8443%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=17321915FC5F374B5C1332BB8C353453A2448135C10277B0AB10A2AAE0A8828145CB6A7EA50998DECE0F809DD23483B3&e=E191A8906D596AD1CA397A0978B325A1B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016057598 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4256004&apid=beans_12274&impid=8d0fd3553bb02955cb6f1401f62501df00&at=1&mkey=20qAw0VC60000003jy530hRbe&latcy=3680&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=1701.140625&cx=&cy=&ed=A3BBAA21FA7672B001FC98D56D431061BF8E0C2C8201154416EDB8FD424354D9E9DB80F9AEC3520D458893CD806A3583B828C29AA9C405215201101A5E151030D94DA61E803B6ADC8793B70972585198&bucket=priority_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=8229464062878&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D250%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D25051272930197500%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=2E9E25B7287B504564C10A6ABF841CAAB828C29AA9C405215201101A5E151030203015AF69119DD3E2115F46B857AE24&pagerefer=&_time_=1516016057850 html
-http://www.sohu.com/ https://imp.optaim.com/201712/ce8674ad1ecfba3e8a1fe864e766586d.php?a=0&adpid=beans_15697&impid=6209d80361077802993dc13129eab9b100&_time_=1516016059943 image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4305918&apid=beans_12279&impid=a614a70b9b9034c88c29a07d762e11af00&at=1&mkey=20v8Q0OEJ0000003m7z50i4ai&latcy=3750&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=3719.03125&cx=&cy=&ed=8581D0B2A6B6966CD92A9EECECD1F3238581D0B2A6B6966CD92A9EECECD1F323911B8785AEB6773C9910CD8662115D4193F7BC5027A494306EF2011719D113F5A3D05C552C37E656FA0FF88A6297A31F8D8300994F8A83E4243A3E5B4A0DC2C08B41E4E3A82FBDDD99C31EAD687FD8E5EE5C73448B5B4523920DC26B1C3A76536AF784A652B8A45455C90126CC24087DB3A8E0DE49849A7003816845F04CBBDF000C560D792CA4049B2840AEFE33EFB0B828C29AA9C405215201101A5E1510302868B4697164800A85B4E9621A6AEB26&bucket=252_self_rank_5_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=1890115213568&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D10%2E0877%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=56041E7938B34C6F8F9DA7819FEC5D02AAC6A1D5B3070EE4B41CA2E4DF4C0BC245CB6A7EA50998DECE0F809DD23483B3&e=E72F2F0B869CA274A95FCCD4447D6071B828C29AA9C405215201101A5E1510300F40438B9EB21B59CBC67C1A9F1BDBC2&pagerefer=&_time_=1516016057895 html
-http://www.sohu.com/ https://adv-sv-show.focus.cn/be_fox_say3?cityCode=UM&adposId=50&callback=jQuery32107006455308167654_1516016047029&_=1516016047032 script
-http://www.sohu.com/ https://images.sohu.com/saf/a2017/1229/ChAKr1pF9ziAYKR7AAA6YR-NKfk611216x151.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=3596748&apid=beans_12425&impid=ccb8e5d32d20fd7a9224248c5770066100&at=1&mkey=20wrE0Pfp0000002I7A50f5G4&latcy=3841&freq=0&turn=1&pgid=sohu_index&ax=12.46875&ay=9715.125&cx=&cy=&ed=9E5F2C3E8E68851A32C38D6636687949E6F0BC1CAB61058B613080B65C82D7A66379493B6C6790D3809CFCDAB7638C002749454F09998589B390B56AB07426C9876DDF6CB5A5E5B3B679465D36F73F5318E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_83_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=9125399234116&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22%2C23%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D14%2E6317%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=33F7F8057562502FAFF9A3B924D1BD03359D99DEDD2454796706731DA618D90E45CB6A7EA50998DECE0F809DD23483B3&e=9E5F2C3E8E68851A32C38D6636687949B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016057962 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4284091&apid=beans_12275&impid=195bcee2e8515c2b61035e2e27df4f8600&at=1&mkey=20yF30VU20000003kYd10hYuf&latcy=3865&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=3762.09375&cx=&cy=&ed=F43A59D3ACF110AE782E482BE9B4A0BD0D8713355A6BD9CCC30B9249A280B11DCA8EF8F04FD9DE97C3A07527AAF6531EED0C5734D1017B238EA8883A659D643E1F9601EDF9D9DAACC152810EBB99CED91C6AD2B6ACFCF101010899D9FF06469357583A3D361AC78541DD77B7CEF0392DDE273725CA6DEB290213C29F5632B2DF033A27BF1B39FFB47C8BC67CB128538D62620074A7C4E97176E583CF8947ECC6144BF2A74D1C07547D96B5A6D759C572B828C29AA9C405215201101A5E151030382999D0D69FFC52EBCB5F2E36219729&bucket=252_self_rank_7_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=7542057025634&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14284091%09rankscore%3D151%2E208%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=C221607E135A2A339FE63A16D2895880CDDE0C10FA7EEC4DE58F257D79846CBB9C2A89DD5367DAEC36DCE2610918433E&e=F43A59D3ACF110AE782E482BE9B4A0BDB828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016058012 html
-http://www.sohu.com/ https://images.sohu.com/saf/a2018/0115/ChAKr1pcdnSAd98wAAA5Klgz4JU158640x100.jpg image
-http://www.sina.com.cn/ http://www.sina.com.cn/ html
-http://www.sina.com.cn/ http://www.sina.com.cn/css/79/index2016/v0510/index.css css
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4067140&apid=beans_12281&impid=67ee1c13ea824c9344d0c0d93224405300&at=1&mkey=20uQF0UcJ0000003amu50h432&latcy=4100&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=2434.203125&cx=&cy=&ed=884EF5B1017C57B64D96EBED0B0ADD12B5D8BE5434E0978A9069E8B2CFF7252B2BF3405302F97C4540012CEC84C8D3647BA6A1AB97DE109FCAAA06B3D3399D5C914D996897D6A193C07F079A49BC06E45C03A24499681DD6043CFEA70BB01C30DC9C4B3E01538C7DBF41096E06AB4EEB9AB40D387D9711FF52EE8F3AAA3AC6BAAAB3A8DF89CCC7C8ED4000E9D14C81F7EBA8D3986E483E4E6DBB2D4B53E89E0ACC719B2A424F6256C36308F95E8B95E3B828C29AA9C405215201101A5E15103051E70C6579FE1344DBBC8B21A2FC9C04&bucket=252_self_rank_61_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4596077075451&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14067140%09rankscore%3D8%2E7121%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=5B07D0EB4500C7EA1D41C8901262B132EFFC80A3F471B10C0E5A8A7FD5F6505E45CB6A7EA50998DECE0F809DD23483B3&e=E66C08290B1477C7C07B71DB6931A309B828C29AA9C405215201101A5E1510300F40438B9EB21B59CBC67C1A9F1BDBC2&pagerefer=&_time_=1516016058246 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/ent/js/lib/jquery-1.7.2.js script
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016059818_3045065609496&itemspaceid=13730&adps=30000001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016059818 html
-http://www.sina.com.cn/ http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js script
-http://www.sohu.com/ https://statics.itc.cn/mobile/css/images/index-win-close-d68ddac0.png image
-http://www.sina.com.cn/ http://news.sina.com.cn/js/pctianyi/sima.js script
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4298303&apid=beans_13818&impid=ca6dec3e1ca8ab7659ea7e5aecfe024500&at=1&mkey=20wxF0W3B0000003lL610i2bt&latcy=4286&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=2477.265625&cx=&cy=&ed=2BF529264F06B37DAC039334E93555A1B29EFA8C91D0195039D748F0207AED9A64ADEB793D8920321248FBF4A0A53473&bucket=random_noctr_32_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=8270892873415&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=23EC458D04D3E5E741AF220FA0E7575DB828C29AA9C405215201101A5E15103025D911FC7E18B952EC3F04E70CEDA425&pagerefer=&_time_=1516016058438 html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_12280&impid=&at=1&mkey=&latcy=4357&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=2392569700287&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016058501 html
-http://www.sina.com.cn/ http://d3.sina.com.cn/litong/zhitou/sinaads/demo/wanglt/sinaIndexAD/edu_ad_change.js script
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_12278&impid=&at=1&mkey=&latcy=4461&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=9514609615062&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016058587 html
-http://www.sina.com.cn/ http://www.sina.com.cn/js/79/2013/0717/fix.js script
-http://www.sina.com.cn/ http://d3.sina.com.cn/d1images/sinaads_entry/sinaads_entry_index.js script
-http://www.sina.com.cn/ http://d3.sina.com.cn/litong/zhitou/sinaads/release/sinaads.js script
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/transform/w120h164/20180112/3XIw-fyqnicm1462973.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/default/1e20c22f/20161223/titlejbicon.png image
-http://www.sina.com.cn/ http://d3.sina.com.cn/litong/zhitou/sinaads/demo/wanglt/sinaIndexAD/sinaAD_slide01.js script
-http://www.sina.com.cn/ http://n.sinaimg.cn/default/1e20c22f/20170314/WangShangYouHaiXinXiJuBaoZhuanQu.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/www/index/12377app.png image
-http://www.sina.com.cn/ http://n.sinaimg.cn/index/mid_article/images/ask.png image
-http://www.sohu.com/ https://img04.sogoucdn.com/app/a/200630/f16edf71a2760024d436491592f70872 image
-http://www.sina.com.cn/ http://n.sinaimg.cn/video/transform/w105h90/20180115/bjrr-fyqrewi3278930.png image
-http://www.sina.com.cn/ http://i.sso.sina.com.cn/js/user_panel_homepage.js script
-http://www.sina.com.cn/ http://i.sso.sina.com.cn/js/ssologin.js script
-http://www.sina.com.cn/ http://i.sso.sina.com.cn/js/outlogin_layer.js script
-http://www.sina.com.cn/ http://auto.sina.com.cn/sinaauto/2016/sinahome/chooseCars.js script
-http://www.sina.com.cn/ http://i0.sinaimg.cn/home/main/index2013/0403/icon.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_12288&impid=&at=1&mkey=&latcy=4494&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=6202620785689&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016058642 html
-http://www.sina.com.cn/ http://i0.sinaimg.cn/home/main/index2013/0719/bg2.png image
-http://www.sina.com.cn/ http://i0.sinaimg.cn/home/2014/1030/hxjzg103.jpg image
-http://www.sina.com.cn/ http://i0.sinaimg.cn/cha/images/c.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/transform/w105h70/20180115/JTde-fyqrewi1549143.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/www/index/play_icon_normal.png image
-http://www.sina.com.cn/ http://n.sinaimg.cn/sports/w105h90/20180114/N9OE-fyqrewi0847321.jpg image
-http://www.sina.com.cn/ http://i2.sinaimg.cn/dy/deco/2013/0321/bg1px.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4292082&apid=beans_12282&impid=4931c9f1b9a73fe990c31b23aa07821000&at=1&mkey=20yWN0VQj0000003ltx10i0z8&latcy=4736&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=5331.171875&cx=&cy=&ed=83A4AA4F9C6088720F8441FB36010152DFF5ED61DD0D811AD5E25CA0DAE61BA013AC63538225B399536751057F787F460F658841606BC37291C2CB107B7480C51C2C9021807CE3A34570E22952689B005C03A24499681DD6043CFEA70BB01C30DC9C4B3E01538C7DBF41096E06AB4EEB9AB40D387D9711FF52EE8F3AAA3AC6BAAAB3A8DF89CCC7C8ED4000E9D14C81F7EBA8D3986E483E4E6DBB2D4B53E89E0ACC719B2A424F6256C36308F95E8B95E3B828C29AA9C405215201101A5E15103051E70C6579FE1344DBBC8B21A2FC9C04&bucket=252_self_rank_61_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=6657592933947&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D19%2C20%2C21%2C22%2C23%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D28%2E0103%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=E46C91C34738B7DEC90F4923CF0A65A26EF015E9CAD74D26FBC48E1B1892B36B9C2A89DD5367DAEC36DCE2610918433E&e=83A4AA4F9C6088720F8441FB36010152B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016058900 html
-http://www.sina.com.cn/ http://i2.sinaimg.cn/dy/deco/2013/0329/logo/LOGO_2x.png image
-http://www.sohu.com/ https://images.sohu.com/saf/a2018/0112/ChAKr1pYVBOAFE41AACZ-042Nws898480x640.jpg image
-http://www.sina.com.cn/ http://i3.sinaimg.cn/qc/autoimages/autoVersion2014/auto_bg_01.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4256765&apid=beans_13819&impid=5427ddaba4986561deaad5a0ee2326dc00&at=1&mkey=20yTL0VCs0000003jC910hRnv&latcy=4892&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=3219.328125&cx=&cy=&ed=E3DC1CF3F5F6B8A8EF5350B62DEA952777F52024F0A42618A0571E7F440C0E27EDD23389775D905234CF0A7D6EF4D3C32A74D49D8845D85B3A6C79447EE090972C92894188A380C80A24C12DEDEC33C618E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_49_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=2701370053216&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D28%2E5145%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=70C0238AF46FF2DD30FBA7DA0EB3B0FACE28BA370E75315B9416F798951E15DB45CB6A7EA50998DECE0F809DD23483B3&e=E3DC1CF3F5F6B8A8EF5350B62DEA9527B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016059046 html
-http://www.sina.com.cn/ http://i3.sinaimg.cn/dy/stencil/sysimages/sysimg/loading_01.gif image
-http://www.sina.com.cn/ http://i2.sinaimg.cn/home/2014/1030/jb5.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4287462&apid=beans_12291&impid=9c83cc2886dc35293a2db1ed702ea2ef00&at=1&mkey=20yBC0VWK0000003la450hZmC&latcy=5051&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=7199.375&cx=&cy=&ed=CA1D8E6B895058CBB6F6509BFFFEF082F9A1EB4BE248A89468774FE772E8D3F696ED6659D6E337C2FA9D32C65B0A0E6B393FC53857A5B9FE8695921E4DF269418872A10A488C7625C614DAC0152AB95618E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_54_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4080531017521&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14287462%09rankscore%3D30%2E7833%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=98D36412DECCA6ED63EEDCEF663AA5900980E6137B2D8B31F520959BB9ED74DE45CB6A7EA50998DECE0F809DD23483B3&e=CA1D8E6B895058CBB6F6509BFFFEF082B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016059214 html
-http://www.sina.com.cn/ http://i3.sinaimg.cn/home/main/index2013/0509/bkjb.png image
-http://www.sohu.com/ https://m1.go.sohu.com/z1/M00/10/D3/ChAKr1pXMfqAHGvDAACO60nHQCs448.jpg image
-http://www.sina.com.cn/ http://beacon.sina.com.cn/ckctl.html html
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_13820&impid=&at=1&mkey=&latcy=5080&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=8148281499170&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016059235 html
-http://www.sina.com.cn/ http://beacon.sina.com.cn/data.html?1516016079233 html
-http://www.sohu.com/ https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_2,m-index_top_pic_3&relatedID=&news=0_0,0_0&SUV=null&_time_=15160160611938527368672473 script
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/transform/w105h70/20180115/wqEz-fyqrewi1552671.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4308433&apid=beans_13821&impid=417ccf2604045501c9f5188a5630ab2300&at=1&mkey=20rAy0SD40000003mhm10i4OR&latcy=5083&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=7847.640625&cx=&cy=&ed=A21010265405ECF5028FE4FD82F552B4406D145D7CE9FEC83B0116F9FF8E354742012CAEE329F7E7ED584621817FECDF42988567247F01118C455C674C4D9323F249FC6E200416AD638213D15450F83F18E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_25_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=8682553634055&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dbannersingle%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D24%2E7537%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=BBC3679D8440CBA806EA984E0C9A2C932F7121DCAC4F3412334FA801C66EA93C45CB6A7EA50998DECE0F809DD23483B3&e=A21010265405ECF5028FE4FD82F552B4B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016059243 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/tech/transform/w116h80/20180112/ECEZ-fyqnick9636087.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4222465&apid=beans_12290&impid=4cadacd8d57db62515bca09973dc465c00&at=1&mkey=20xiH0Vkg0000003hPX50hIsh&latcy=5170&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=6121.84375&cx=&cy=&ed=8AE8066EE42EEF6BB841D2A00280B86B235D0C428B1CD5BF0C8E79DBB67FACA2A3C955469F22738DC1867227475855B08CBAA5BE55E3620CC922BF1D76ED4276496C221A330D3DDCAFAD1B4881E4A42B18E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_62_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=4796575107237&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D22%2E0925%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=99308F95E81826ABA832A079E12D5A7EC55A55F391BAE26C925A8AB91BF21FD345CB6A7EA50998DECE0F809DD23483B3&e=8AE8066EE42EEF6BB841D2A00280B86BB828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016059347 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/20161214/WCVU-fxypunk6627147.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4289233&apid=beans_12292&impid=84ffe27386c1ab1d91b45910b562b27200&at=1&mkey=20usc0V9y0000003lif50hZPb&latcy=5390&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=4692.03125&cx=&cy=&ed=DD38BFD89FE9E1E8C0351C0A63066DDACC6F9954A6A32D9A82047B36D7C72022F2FD094D24DE7A1DB6BD93745C60F1B5B828C29AA9C405215201101A5E151030BFFE428B7965730D472F63D751E7AE7E&bucket=priority_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=6674302143667&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D150%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=02366D12C91C400DF0C2AD4B320ABE2EB828C29AA9C405215201101A5E151030D7B7F6CDD1CD768FE85F51EE0475E175&pagerefer=&_time_=1516016059581 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/transform/w105h90/20180115/sF3k-fyqrewi3639295.jpg image
-http://www.sina.com.cn/ http://www.sinaimg.cn/home/main/blk/d.gif image
-http://www.sina.com.cn/ http://www.sinaimg.cn/home/2018/0115/U996P30DT20180115131055.png image
-http://www.sina.com.cn/ http://www.sinaimg.cn/home/2018/0115/U996P30DT20180115100411.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_13455&impid=&at=1&mkey=&latcy=5641&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=8442021086938&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016059809 html
-http://www.sina.com.cn/ http://www.sinaimg.cn/home/2018/0115/U996P30DT20180115100556.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_13713&impid=&at=1&mkey=&latcy=5646&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=4920000524594&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016059821 html
-http://www.sina.com.cn/ http://www.sinaimg.cn/home/2018/0115/U996P30DT20180115105048.png image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4269743&apid=beans_12293&impid=5ba533188da95ee8a87727892f20b16200&at=1&mkey=20y960VL30000003kdX50hUKP&latcy=5676&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=6742.375&cx=&cy=&ed=A37DBEFF6E411A417BF9F1C2EDE68D106B7C2F2704CC180F473AB2AF37FE50789C0DE41742EF4B63066EC8861CC496CDB23C5318104643843C59FCC30C5DB96482A8746EE57711A1ED09C854AA5C0BB518E33E26567518B5B5FA8E28D105DC11EF5FB2CC6F0DF1886168D17523FF22E5D0D79877A5625F12D686BC74B34D780380CAB1F0FDEF81B696F6EB2AB732118FC64CE80C408CD378183F3708F39C0E76278AC87FCBC832B9FC5DA86A5F47C4BCB828C29AA9C405215201101A5E1510306A20938629610C7732C3316F4D928F25&bucket=252_self_rank_49_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=8013379712232&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%09indexnode%3Dsearctest%09priority%3D70%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3D%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DHS14269743%09rankscore%3D32%2E5421%09ctrfilter%3D0%09servip%3D10%2E11%2E152%2E57&c=CFF8B63D39E12A5C82D47565922DB862921650D08645052611E758E5BDFF0E6B45CB6A7EA50998DECE0F809DD23483B3&e=A37DBEFF6E411A417BF9F1C2EDE68D10B828C29AA9C405215201101A5E151030312A27F73A7FAED0E78BB20A58E20B9B&pagerefer=&_time_=1516016059844 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/ent/transform/20171105/m7tm-fynmzrs7231921.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/sports/transform/w105h90/20180113/DrVd-fyqrewh5010225.jpg image
-http://www.sohu.com/ http://v.admaster.com.cn/i/a101201,b2219543,c2137,i0,m202,8a2,8b2,h?_time_=1516016059943 image
-http://www.sina.com.cn/ http://n.sinaimg.cn/ent/transform/w105h70/20180115/KvPv-fyqrewi1437271.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4299646&apid=beans_15697&impid=6209d80361077802993dc13129eab9b100&at=1&mkey=20q570VDM0000003lNz10i2x8&latcy=5576&freq=0&turn=1&pgid=sohu_index&ax=0&ay=11945.5&cx=&cy=&ed=B81C14777F2478CCF29048D123378450347F58173F7F3D7C1D106E1390FC8CBA0D3FFA972B22999DEB8E59F56331A9CAB828C29AA9C405215201101A5E151030EF4B6321788BFC3D17FB438E1260D3A6&bucket=priority_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=9433311338489&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D150%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D18014424723881984%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DAE259%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=BED1D1552D62F19E76D913CD603D7D6BB828C29AA9C405215201101A5E15103042C09A323E9B3404571C7B89845E0F57&pagerefer=&_time_=1516016059943 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/tech/transform/w105h70/20180112/_ety-fyqnick8700935.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/av?aid=4299646&apid=beans_15697&impid=6209d80361077802993dc13129eab9b100&at=1&mkey=20q570VDM0000003lNz10i2x8&latcy=5576&freq=0&turn=1&pgid=sohu_index&ax=0&ay=11945.5&cx=&cy=&ed=B81C14777F2478CCF29048D123378450347F58173F7F3D7C1D106E1390FC8CBA0D3FFA972B22999DEB8E59F56331A9CAB828C29AA9C405215201101A5E151030EF4B6321788BFC3D17FB438E1260D3A6&bucket=priority_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=9433311338489&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D150%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D18014424723881984%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3DAE259%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=BED1D1552D62F19E76D913CD603D7D6BB828C29AA9C405215201101A5E15103042C09A323E9B3404571C7B89845E0F57&pagerefer=&_time_=1516016059944 html
-http://www.sina.com.cn/ http://www.sina.com.cn/api/hotword.json script
-http://www.sohu.com/ https://s.go.sohu.com/cmxOd/?callback=jsonp_1516016061400_7246088375650&itemspaceid=13413&adps=30000001&apt=4&turn=1&pgid=880c859a-277b-b9f5-5e15-c3523353cd45&newschn=1000000000&subchannelid=&_time_=1516016061400 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/sports/transform/w105h70/20180115/jHhh-fyqrewi1346119.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=&apid=beans_13730&impid=&at=1&mkey=&latcy=1574&freq=&turn=1&pgid=sohu_index&ax=&ay=&cx=&cy=&ed=&bucket=&supplyid=4&ext=&rsln=360*512&sf=0&r=9849023078834&uloc=&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=&c=&e=&pagerefer=&_time_=1516016061401 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/sports/transform/w105h70/20180114/rNuR-fyqrewi0916292.jpg image
-http://www.sohu.com/ https://t3.focus-img.cn/sh340x226sh/esf/2018-01-11/1dd98d4ffb334e3694238474ef10f26a.png image
-http://www.sina.com.cn/ http://d2.sina.com.cn/litong/zhitou/sinaads/release/ad_logo_update_IAB.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w210h140/20180114/mU5P-fyqrewh9163275.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w210h140/20180114/MzDr-fyqrewh9158664.jpg image
-http://www.sohu.com/ https://x.jd.com/mkt/pcwap?ad_ids=3272:5&adflag=0&clkmn=&expose=&ref=https%3A%2F%2Fimages.sohu.com%2Fbill%2Fs2017%2Fmaterials%2Fjd%2F0921%2F3272.html%3Fclkm%3D%252F%252Fi.go.sohu.com%252Fcount%252Fc%253Faid%253D4256004%2526apid%253Dbeans_12274%2526impid%253D8d0fd3553bb02955cb6f1401f62501df00%2526at%253D1%2526mkey%253D20qAw0VC60000003jy530hRbe%2526latcy%253D3680%2526freq%253D0%2526turn%253D1%2526pgid%253Dsohu_index%2526ax%253D12.953125%2526ay%253D1701.140625%2526cx%253D%2526cy%253D%2526ed%253DA3BBAA21FA7672B001FC98D56D431061BF8E0C2C8201154416EDB8FD424354D9E9DB80F9AEC3520D458893CD806A3583B828C29AA9C405215201101A5E151030D94DA61E803B6ADC8793B70972585198%2526bucket%253Dpriority_n%2526supplyid%253D4%2526ext%253D0%2526rsln%253D360*512%2526sf%253D0%2526r%253D8229464062878%2526uloc%253D935651042131968%2526newschn%253D1000000000%2526subchannelid%253D%2526ch_trans%253D%2526jsv%253D%2526ipos%253D1%2526shbd_monitor_ext%253Dturn%25253D1%252509hours%25253D%252509indexnode%25253Dsearctest%252509priority%25253D250%252509mediaid%25253D2%252509markettag%25253D%252509bidid%25253D%252509uid%25253D1801151934117VED%252509form%25253D%252509sperotag%25253Dv1%25252E3%25252E36%252509acc%25255Findustry%25253D25051272930197500%252509tgid%25253D%252509arloc%25253D%252509newsid%25253D%252509newstag%25253D%252509adtype%25253D%252509lsc%25253D%252509ssc%25253D%252509freqid%25253D%252509rankscore%25253D0%252509ctrfilter%25253D%252509servip%25253D10%25252E11%25252E152%25252E57%2526c%253D333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B%2526e%253D2E9E25B7287B504564C10A6ABF841CAAB828C29AA9C405215201101A5E151030203015AF69119DD3E2115F46B857AE24%2526pagerefer%253D%2526_time_%253D1516016057851&callback=dsp_1516016060247&r=1516016060248 script
-http://www.sina.com.cn/ http://image.sinajs.cn/newchart/small/t/sh000001.gif image
-http://www.sohu.com/ https://t2.focus-img.cn/sh340x226sh/xf/zxc/de2349c90891a9317789de780796b68c.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/kandian/transform/20170620/_PTI-fyhfxph4388828.jpg image
-http://www.sohu.com/ https://static-alias-1.360buyimg.com/jzt/libs/behavior/v2/behavior.js script
-http://www.sina.com.cn/ http://n.sinaimg.cn/fashion/w105h70/20180115/tMvP-fyqrewi1415111.jpg image
-http://www.sohu.com/ https://img1.360buyimg.com/pop/jfs/t17371/88/32367666/21690/5b6f0286/5a58702fN5dee8478.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/transform/w105h70/20180115/PgID-fyqrewi1689078.jpg image
-http://www.sina.com.cn/ http://i14.esfimg.com/imp/583a560c1dc0029f4561370b0eff5182_os8128de.jpg image
-http://www.sohu.com/ https://images.sohu.com/saf/a2018/0112/ChAKr1pYqAaAVbs7AACPE36zMk0137640x320.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/sports/w105h70/20180113/ASLH-fyqrewh6165937.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/v?aid=4303976&apid=beans_13413&impid=bd4f7ffbc7d24bb57060885d2104e94100&at=1&mkey=20q780VDx0000003m3510i3EY&latcy=2128&freq=0&turn=1&pgid=sohu_index&ax=12.953125&ay=1701.140625&cx=&cy=&ed=19ADBC8FFFAC4640B5D8E76F42C890E4CC6F9954A6A32D9A82047B36D7C72022CA7A492529703D7848F55E019FADA6E6B828C29AA9C405215201101A5E151030BFFE428B7965730D472F63D751E7AE7E&bucket=priority_n&supplyid=4&ext=0&rsln=360*512&sf=0&r=5882499949215&uloc=844424930131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D1%09hours%3D%09indexnode%3Dsearctest%09priority%3D150%09mediaid%3D2%09markettag%3D%09bidid%3D%09uid%3D1801151934117VED%09form%3Dinfo%5Fvideo%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=097C1E052B33E92D805B6522774FE960B828C29AA9C405215201101A5E151030D7B7F6CDD1CD768FE85F51EE0475E175&pagerefer=&_time_=1516016063574 html
-http://www.sina.com.cn/ http://src.leju.com/imp/imp/deal/91/48/0/5ad1b0664afba444f0991c5c284_p24_mk24.jpg image
-http://www.sohu.com/ https://i.go.sohu.com/count/av?aid=4255921&apid=beans_12273&impid=fa52845998f99ba92ba2a4f5e1e7ab7b00&at=1&mkey=20q1K0VC50000003jya10hR9T&latcy=1703&freq=0&turn=4&pgid=sohu_index&ax=360&ay=141.09375&cx=&cy=&ed=58A87D34BB63AA9A898F28B2B940EC6B09F69308CD19D5ED2B0DD008242095CC7BFDF3023158A6ADDFC9813AE1B3433FB828C29AA9C405215201101A5E151030CD1550305F33ADA244475BB9C728AE99&bucket=priority_n&supplyid=4&ext=6&rsln=360*512&sf=0&r=1552602198500&uloc=935651042131968&newschn=1000000000&subchannelid=&ch_trans=&jsv=&ipos=1&shbd_monitor_ext=turn%3D4%09hours%3D%09indexnode%3Dsearctest%09priority%3D300%09mediaid%3D2%09markettag%3D%09bidid%3D436ca0fcb90a4c31ab3d2e8ce91d7cff%09uid%3D1801151934117VED%09form%3Dpicturetxt%09sperotag%3Dv1%2E3%2E36%09acc%5Findustry%3D18014424723881984%09tgid%3D%09arloc%3D%09newsid%3D%09newstag%3D%09adtype%3D%09lsc%3D%09ssc%3D%09freqid%3D%09rankscore%3D0%09ctrfilter%3D%09servip%3D10%2E11%2E152%2E57&c=333329FE5F4E5BFFE6BD50893DB6CE07B828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&e=6C4C39981E6EE7F481F89796BDD2988FB828C29AA9C405215201101A5E151030221237EE833F473E002579CA5502E82B&pagerefer=&_time_=1516016063575 html
-http://www.sina.com.cn/ http://src.leju.com/imp/imp/deal/bb/9c/4/07ea2cee841fc8ee7eddf7f98e6_p24_mk24.jpg image
-http://www.sohu.com/ https://imp.optaim.com/201712/e037349f30e16afe7c317bece287c153.php?a=0&adpid=beans_13413&impid=bd4f7ffbc7d24bb57060885d2104e94100&_time_=1516016063574 image
-http://www.sina.com.cn/ http://n.sinaimg.cn/ent/transform/w105h70/20180115/dFQI-fyqrewi1331615.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w171h94/20171213/ypK7-fypsqiz3459652.jpg image
-http://www.sohu.com/ https://static-alias-1.360buyimg.com/jzt/temp/conermark/ad_jd.png image
-http://www.sina.com.cn/ http://n.sinaimg.cn/kandian/transform/w210h140/20180108/Nd8c-fyqincv2235483.jpg image
-http://www.sohu.com/ https://statics.itc.cn/mobile/css/images/index-win-bar-close-118a18b4.png image
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/20171117/I9eb-fynwnwt7164124.jpg image
-http://www.sohu.com/ http://data.vod.itc.cn/?prod=rtb&new=/79/63/Ea9Y8ZvckpOhYAovY8Q8zk.mp4 other
-http://www.sina.com.cn/ http://i1.sinaimg.cn/unipro/pub/suda_m_v630.js script
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w171h94/20171213/eqfH-fypsqiz3458392.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w171h94/20171213/dAo5-fypsqiz3457888.jpg image
-http://www.sina.com.cn/ http://beacon.sina.com.cn/h.js script
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w171h94/20171213/lA9C-fypsqiz3457195.jpg image
-http://www.sohu.com/ http://104.254.66.29/sohu/v1/TmXBTmsmTCaF0av79ROL4iYz45lYtiOO05w7cWNytHrChWoIymcAwm8ioF2OfYx.mp4?k=nVhN0w&p=XZhuOp3AjfK&r=TmI20LscWOoCNLfcWG1OvmXAyBj&q=OpCAhW7IWh1Soh24WYoGgT1cWhbXlGvs5GNOlG6OvmbcWJeOfGNXRhbSqD2sWGvSqF2sY&cip=149.20.63.13 video
-http://www.sina.com.cn/ http://n.sinaimg.cn/auto/transform/w171h94/20171213/C_J4-fypsqiz3456319.jpg image
-http://www.sohu.com/ https://im-x.jd.com/dsp/np?log=RHFEEbeCNbUp-QmIo7A41hpzOSBRTl5AwS2cWINfZ5h4x_qp2HAw4a4PXsrnfD0X_NVfagn2T4ajHd4FuJ0a69geNj25aJFSeV5ePJrwWMmPKcEqstE_KYLdhuldoVguEKVLBvS3pfbWL98GkKr8JPhVWHeSctTH42CImOT6egDLnrfGLbUM5jfzbjt307O6ORZAZSgVVHlkW-wAcktXuyoO7I3-xeoc9iikBR68AIAoH1vqAH9T3g1uI_WUFLQdMg34pd43pJhfJuhLAF4lDBy4BI3v6SFzD6KPxOuOWo17_COg8E-S17IyKA2kfcJ4bSPI7UZawzqbPpxComNm-l_te2dcj7ffl5KcfAjdrrsXfg1J9n3CFZr3vhtnDjWurPxsn6OlGCX25_WzCZ41xP9Ci73zYq4s6GzP6ZKLxB93HKsAEh5YA-8T1mmmXf3711sFKwSdkuReMP8uumqR45GkStBWJ3uYvp2xBjFVCZM~&v=404&seq=1&n=pcwap image
-http://www.sina.com.cn/ http://n.sinaimg.cn/games/w105h70/20180115/0kTB-fyqrewi2188481.jpg image
-http://www.sohu.com/ https://sohutv.m.cn.miaozhen.com/x/k=2067486&p=7CSZE&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&tr=__REQUESTID__&mo=3&m0=&m0a=__DUID__&m1=__ANDROIDID1__&m1a=&m2=&m4=__AAID__&m5=&m6=__MAC1__&m6a=&o=?_time_=1516016063574 html
-http://www.sina.com.cn/ http://n.sinaimg.cn/games/w105h70/20180115/Y90g-fyqrewi2191166.jpg image
-http://www.sohu.com/ https://t.go.sohu.com/cm.gif?ver=1&mid=10041&type=active&getuid=0&ext= image
-http://www.sina.com.cn/ http://adm.leju.com/get_abp_list/PG_514AC419D66F33?callback=lejuDataCallback script
-http://www.sohu.com/ http://cc.xtgreat.com/sohu.gif?suid=1801151934117VED&ver=1 image
-http://www.google.ru/ http://www.google.ru/ html
-http://www.sina.com.cn/ http://www.sina.com.cn/js/wwwindex/79/v2/sina_product_tabs.js script
-http://www.sohu.com/ https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_5&relatedID=&news=0_0&SUV=null&_time_=15160160701904666770310499 script
-http://www.sina.com.cn/ http://i1.sinaimg.cn/dy/main/icon/photoNewsLeft2.gif image
-http://www.sohu.com/ http://xtrader.cm.admaster.com.cn/?type=1&tid=3251&uid=523be04y2k40&redir=https%3A%2F%2Fcc.xtgreat.com%2Fadmaster.gif%3Frd%3Dxtrader html
-http://www.google.ru/ https://www.google.ru/?gws_rd=ssl html
-http://www.sina.com.cn/ http://i1.sinaimg.cn/dy/deco/2013/0313/videoNewsLeft.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/w65h65/20171211/st5r-fypnsip6399046.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/index/js/shms2.js script
-http://www.sina.com.cn/ http://beacon.sina.com.cn/a.gif?V=2.1.16&CI=sz:360x512|dp:24|ac:Mozilla|an:Netscape|cpu:undefined|pf:Linux%20x86_64|jv:1.3|ct:unkown|lg:en-US|tz:8|fv:undefined|ja:0&PI=pid:30-9999-0-131-1|st:0|et:4|ref:|hp:unkown|PGLS:PGLS000022|ZT:|MT:|keys:|dom:1128|ifr:2&UI=vid:undefined|sid:8090613509712.044.1516016080910|lv::1:1:1|un:|uo:|ae:|lu:|si:|rs:0|dm:1|su:&MT=vjuids:&EX=ex1:2017_old|ex2:&gUid_1516016080919 image
-http://www.sina.com.cn/ http://i3.sinaimg.cn/dy/deco/2013/0305/d.gif image
-http://www.google.ru/ https://www.google.ru/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.sina.com.cn/ http://d4.sina.com.cn/litong/zhitou/sinaads/release/sinaads.js script
-http://www.google.ru/ https://www.google.ru/images/nav_logo242_hr.webp image
-http://www.sina.com.cn/ http://i3.sinaimg.cn/home/main/index2013/0904/history_arr.png image
-http://www.sina.com.cn/ http://i1.sinaimg.cn/dy/deco/2013/0316/liveNewsLeft.gif image
-http://www.google.ru/ https://www.google.ru/gen_204?s=webaft&atyp=csi&ei=HJFcWtDgIczKjwPp7L-IAg&rt=wsrt.2043,aft.215,prt.215 html
-http://www.sina.com.cn/ http://d5.sina.com.cn/litong/zhitou/sinaads/demo/jiliang/toutiaobao/toutiaobao.js script
-http://www.sina.com.cn/ http://i1.sinaimg.cn/dy/deco/2013/0316/arr.png image
-http://www.google.ru/ https://www.google.ru/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPJfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oHFKBcvcVQykztV52RGYNzZHVtuLg script
-http://www.sohu.com/ https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_6&relatedID=&news=0_0&SUV=null&_time_=15160160731904950156511239 script
-http://www.sina.com.cn/ http://n.sinaimg.cn/games/55d1b789/20160617/foxue_register.png image
-http://www.google.ru/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.sohu.com/ https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_7&relatedID=&news=0_0&SUV=null&_time_=15160160761909427644156914 script
-http://www.sina.com.cn/ http://i2.sinaimg.cn/dy/main/index15/02/slide_btn.png image
-http://www.google.ru/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.ru/ https://www.google.ru/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPJfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHFKBcvcVQykztV52RGYNzZHVtuLg?xjs=s1 script
-http://www.sohu.com/ https://cc.xtgreat.com/admaster.gif?rd=xtrader&uid=sfee717e68f20a9e8bf image
-http://www.google.ru/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.sohu.com/ https://pv.sohu.com/content_ev.gif?location=m-index_top_pic_8&relatedID=&news=0_0&SUV=null&_time_=15160160791906506586906406 script
-http://www.sina.com.cn/ http://i3.sinaimg.cn/dy/main/index15/02/slide_icon.png image
-http://www.google.ru/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.sohu.com/ https://cm.l.qq.com/?dspid=110066&gettuid=1&ext=1&dspuid=523be04y2k40 html
-http://www.google.ru/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.sina.com.cn/ http://news.sina.com.cn/js/694/2012/0830/realtime.js?ver=1.5.1 script
-http://www.sohu.com/ https://cc.xtgreat.com/tencent.gif?tuid=AQEB6wT-mdKyim4a0fVlw-jjjpubFQyZdBLa&ver=1&ext=1 image
-http://www.sohu.com/ https://mp.sohu.com/favicon.ico image
-http://www.sina.com.cn/ http://www.sinaimg.cn/qc/js/brandList.min.js script
-http://www.vk.com/ http://www.vk.com/ html
-http://www.google.ru/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.sina.com.cn/ http://finance.sina.com.cn/basejs/suggestServer.js script
-http://www.vk.com/ http://vk.com/ html
-http://www.google.ru/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.sina.com.cn/ http://hq.sinajs.cn/list=hf_GC,hf_CL,USDCNY script
-http://www.vk.com/ http://m.vk.com/ html
-http://www.google.ru/ https://www.google.ru/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPJfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHFKBcvcVQykztV52RGYNzZHVtuLg script
-http://www.vk.com/ https://m.vk.com/ html
-http://www.google.ru/ https://www.google.ru/images/nav_logo242.png image
-http://www.vk.com/ https://m.vk.com/css/s_cf.css?653 css
-http://www.google.ru/ https://www.google.ru/gen_204?atyp=csi&ei=HJFcWtDgIczKjwPp7L-IAg&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.634,dcl.361,iml.634,ol.2334,prt.215,xjs.1499,xjsee.1498,xjses.1208,xjsls.233,wsrt.2043,cst.623,dnst.0,rqst.779,rspt.429,sslt.325,rqstt.1553,unt.927,cstt.929,dit.2402&zx=1516015903233 html
-http://www.google.ru/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.sina.com.cn/ http://hq.sinajs.cn/list=s_sh000001,s_sh000011 script
-http://www.vk.com/ https://m.vk.com/css/s_yzg.css?196 css
-http://www.google.ru/ https://www.google.ru/images/branding/product/1x/gsa_android_144dp.png image
-http://www.sina.com.cn/ http://d8.sina.com.cn/litong/zhitou/sinaads/test/e-recommendation/release/sinaere.js script
-http://www.vk.com/ https://m.vk.com/ html
-http://www.google.ru/ https://adservice.google.ru/adsid/google/ui html
-http://www.sina.com.cn/ http://d1.sina.com.cn/litong/zhitou/sinaads/src/spec/sinaads_ck.js script
-http://www.vk.com/ https://m.vk.com/css/s_cfmxwr.css?855 css
-http://www.sina.com.cn/ http://ip.house.sina.com.cn/sina_sanshou_2010.php html
-http://www.sina.com.cn/ http://d1.sina.com.cn/xingyue1/liuxingyue/ali2/mm_15890324_2192376_13096223.js?uuid=__UUID__ script
-http://www.vk.com/ https://m.vk.com/css/s_zgt.css?211 css
-http://www.sina.com.cn/ https://i.sso.sina.com.cn/js/qrcode_login.js script
-http://www.vk.com/ https://m.vk.com/js/s_c.js?635 script
-http://www.vk.com/ https://counter.yadro.ru/hit?uhttps%3A%2F%2Fm.vk.com%2F;rhttps%3A%2F%2Fm.vk.com%2F;62039139 html
-http://www.vk.com/ https://counter.yadro.ru/hit?q;uhttps%3A%2F%2Fm.vk.com%2F;rhttps%3A%2F%2Fm.vk.com%2F;62039139 image
-http://www.sina.com.cn/ https://i.sso.sina.com.cn/images/login/pre_loading.gif image
-http://www.vk.com/ https://sb.scorecardresearch.com/p?c1=2&c2=13765216&c3=&c4=https%3A%2F%2Fm.vk.com%2F&c5=&c9=https%3A%2F%2Fm.vk.com%2F&c15=&cv=2.0&cj=1&rn=62039139 other
-http://www.sina.com.cn/ https://i.sso.sina.com.cn/images/login/td.png image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=75RtB&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.vk.com/ https://sb.scorecardresearch.com/p2?c1=2&c2=13765216&c3=&c4=https%3A%2F%2Fm.vk.com%2F&c5=&c9=https%3A%2F%2Fm.vk.com%2F&c15=&cv=2.0&cj=1&rn=62039139 image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=73xv2&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.vk.com/ https://top-fwz1.mail.ru/counter?id=2579437;pid=0;r=https%3A%2F%2Fm.vk.com%2F other
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=72Jax&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.vk.com/ https://top-fwz1.mail.ru/counter2?id=2579437;pid=0;r=https%3A%2F%2Fm.vk.com%2F image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=71dZr&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.vk.com/ https://m.vk.com/images/mobile/logo/logo_2x.png image
-http://www.vk.com/ https://m.vk.com/images/mobile/fb_icon_2x.png?1 image
-http://www.vk.com/ https://m.vk.com/images/icons/favicons/fav_logo_2x.ico?7 image
-http://www.sina.com.cn/ https://i.sso.sina.com.cn/images/login/weibo_how_ot.png image
-http://www.sina.com.cn/ http://d6.sina.com.cn/litong/zhitou/sinaads/src/spec/sinaads_ck.html html
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=71dZt&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=71kSU&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://n.sinaimg.cn/default/1e20c22f/20160919/home.recommender.2014.min1.js script
-http://www.sina.com.cn/ http://news.sina.com.cn/iframe/87/store.html?handle=___CrossDomainStorage___.onReady&domain=sina.com.cn html
-http://www.sina.com.cn/ http://news.sina.com.cn/iframe/87/store.html?handle=___SinaadsCrossDomainStorage___.onReady&domain=sina.com.cn html
-http://www.sina.com.cn/ http://www.sina.com.cn/js/index/96/b_search.js script
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=71dZq&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=71dZo&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=71dZm&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=74dHq&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://cre.mix.sina.com.cn/api/v3/get?cre=sinapc&mod=picg&statics=1&merge=3&type=1&length=20&cateid=t_s&fields=url,stitle,title,thumb&callback=homePicGuessLoaded__&rnd=1516016083448 script
-http://www.sina.com.cn/ http://open.weather.sina.com.cn/api/weather/sinaForecast?length=1&air=1&city=&callback=homeWeatherRenderFunNew__ script
-http://www.sina.com.cn/ http://g.cn.miaozhen.com/x/k=2022917&p=72JaP&dx=__IPDX__&rt=2&ns=__IP__&ni=__IESID__&v=__LOC__&xa=__ADPLATFORM__&o= image
-http://www.sina.com.cn/ http://s.weibo.com/ajax/jsonp/suggestion?ver=1&Refer=sina_sug&_t=0.6985239388701263&_cb=fun_501408081082942154& html
-http://www.sina.com.cn/ http://finance.sina.com.cn/tougu/goldenstock/goldenstock.js script
-http://www.sina.com.cn/ http://finance.sina.com.cn/tougu/profitStar/newprofitStar.js script
-http://www.sina.com.cn/ http://n.sinaimg.cn/baby/20170926/XsYL-fymesii5801903.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/astro/w198h132/20180112/-j-P-fyqnicm0853539.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/tech/w240h176/20180115/uHiy-fyqrewi2066432.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/astro/w198h132/20180112/WCRJ-fyqnicm0851909.gif image
-http://www.sina.com.cn/ http://n.sinaimg.cn/astro/w198h132/20180112/vGew-fyqnicm0849893.gif image
-http://www.sina.com.cn/ http://i1.sinaimg.cn/dy/weather/main/index14/007/icons_32_yl/w_07_25_01.png image
-http://www.sina.com.cn/ http://finance.sina.com.cn/licaishi/recommend/sinaIdxRcmdPlanner.js script
-http://www.sina.com.cn/ https://passport.weibo.com/visitor/visitor?from=iframe html
-http://www.sina.com.cn/ https://passport.weibo.com/js/visitor/mini_original.js?v=20161116 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=2495FC81338A&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_vnhf68 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=lejuguding&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_huiujm script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000045825&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_ie9pze script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000045976&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_htowor script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000016827&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_veriu5 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000045982&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_jz15xl script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000045983&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_8or15c script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000025256&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_pba03g script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000046010&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_8xop1i script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058040&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_j6tm9q script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000043762&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_bfujfo script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058041&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_hny3l0 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058042&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_899zox script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000005494&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_s2w5py script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=xinceshe0726&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_3rtx8p script
-http://www.sina.com.cn/ https://passport.weibo.com/visitor/genvisitor script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058043&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_w30p script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058184&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_kq05e6 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058185&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_fub2e6 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000046020&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_odunf2 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000046021&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_qg4zgd script
-http://www.google.de/ http://www.google.de/ html
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058044&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_h5azkf script
-http://www.google.de/ https://www.google.de/?gws_rd=ssl html
-http://www.google.de/ https://www.google.de/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000056034&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_98nzie script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=lszuoce50090&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_1wxjya script
-http://www.google.de/ https://www.google.de/images/nav_logo242_hr.webp image
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=lsyouce50090&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_xywzif script
-http://www.google.de/ https://www.google.de/gen_204?s=webaft&atyp=csi&ei=HJFcWungIZWWjQOIu7TwDw&rt=wsrt.2068,aft.152,prt.152 html
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058046&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_9470zq script
-http://www.google.de/ https://www.google.de/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfIAR0IiA/rt=j/d=1/t=zcms/rs=ACT90oHBqL8B7cjIL7x8gRAbcUPj8H6Slg script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000016990&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_9js2yw script
-http://www.google.de/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=2EF482AADE63&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_b6w3zh script
-http://www.google.de/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000000001&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_mmvgcm script
-http://www.google.de/ https://www.google.de/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfIAR0IiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHBqL8B7cjIL7x8gRAbcUPj8H6Slg?xjs=s1 script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000059618&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_rzways script
-http://www.google.de/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000006450&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_986eoq script
-http://www.google.de/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000054315&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_tu8t29 script
-http://www.google.de/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000051826&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_gnkkin script
-http://www.google.de/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.it/ http://www.google.it/ html
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000052408,PDPS000000057463&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_hkufxd script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=texingxibao&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_rpddmo script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000057532&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_fj06yt script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=7C691C8CED38&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_xi3q2a script
-http://www.sina.com.cn/ https://sax.sina.com.cn/newimpress?rotate_count=68&TIMESTAMP=jcg4u0z3&referral=http%3A%2F%2Fwww.sina.com.cn%2F&adunitid=PDPS000000058017&am=%7Bds%3A360x512%2Cfv%3A0%2Cov%3ALinux%20x86_64%7D&callback=_sinaads_cbs_9c9pa8 script
-http://www.google.it/ https://www.google.it/?gws_rd=ssl html
-http://www.google.de/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.sina.com.cn/ http://cre.mix.sina.com.cn/api/v3/get?rfunc=107&cre=ad_business&mod=g&merge=3&statics=1&cateid=carshopping&multi_func=2&length=3&callback=ere_callbackuossnu script
-http://www.weibo.com/ http://www.weibo.com/ html
-http://www.google.it/ https://www.google.it/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.sina.com.cn/ http://www.sina.com.cn/api/headline.js script
-http://www.weibo.com/ https://weibo.com/ html
-http://www.google.it/ https://www.google.it/images/nav_logo242_hr.webp image
-http://www.sina.com.cn/ http://woocall.sina.com.cn/lib/IO.WebPush4.js script
-http://www.google.it/ https://www.google.it/gen_204?s=webaft&atyp=csi&ei=MpFcWteeJtLqjwPe3baQBw&rt=wsrt.2050,aft.151,prt.151 html
-http://www.sina.com.cn/ http://cre.mix.sina.com.cn/api/v3/get?cateid=sina_all&fields=url,title,stitle,tags,type,thumb&length=48&cre=sinapc&mod=g&statics=1&merge=3&rnd=1516016085548_14461275&callback=cb_1516016085548_25417899& script
-http://www.google.it/ https://www.google.it/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfIAR0IiA/rt=j/d=1/t=zcms/rs=ACT90oHBqL8B7cjIL7x8gRAbcUPj8H6Slg script
-http://www.sina.com.cn/ http://sax.sina.com.cn/view?type=nonstd&t=REowMDAxMDc1OQ%3D%3D image
-http://www.google.it/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.sina.com.cn/ http://d2.sina.com.cn/litong/zhitou/sinaads/test/e-recommendation/tpl/eretpl_3_1000_100.html?1516016104940 html
-http://www.weibo.com/ http://m.weibo.cn/?&jumpfrom=weibocom html
-http://www.google.it/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.sina.com.cn/ http://r.dmp.sina.com.cn/cm/list?sinaglobal=149.20.63.13_1516016083.34567&host=www.sina.com.cn&callback=_sinaads_cbs_z194e6 script
-http://www.weibo.com/ https://m.weibo.cn/?&jumpfrom=weibocom html
-http://www.sina.com.cn/ https://phs.tanx.com/ex?i=mm_15890324_2192376_13096223&_t=1516016084745 script
-http://www.google.it/ https://www.google.it/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfIAR0IiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHBqL8B7cjIL7x8gRAbcUPj8H6Slg?xjs=s1 script
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/ent/transform/w600h400/20180115/n5lc-fyqrewi2977656.png&size=198_132 image
-http://www.weibo.com/ https://passport.weibo.cn/signin/welcome?entry=mweibo&r=http%3A%2F%2Fm.weibo.cn%2F%3F%26jumpfrom%3Dweibocom html
-http://www.google.it/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.de/ https://www.google.de/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfIAR0IiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHBqL8B7cjIL7x8gRAbcUPj8H6Slg script
-http://www.jd.com/ http://www.jd.com/ other
-http://www.google.it/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.de/ https://www.google.de/images/nav_logo242.png image
-http://www.jd.com/ https://global.jd.com/ html
-http://www.google.it/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.jd.com/ https://misc.360buyimg.com/??jdf/1.0.0/unit/ui-base/5.0.0/ui-base.css,jdf/1.0.0/unit/shortcut/5.0.0/shortcut.css,jdf/1.0.0/unit/global-header/5.0.0/global-header.css,jdf/1.0.0/unit/myjd/5.0.0/myjd.css,jdf/1.0.0/unit/nav/5.0.0/nav.css,jdf/1.0.0/unit/shoppingcart/5.0.0/shoppingcart.css,jdf/1.0.0/unit/global-footer/5.0.0/global-footer.css,jdf/1.0.0/unit/service/5.0.0/service.css,channel/lib/1.2.0/css/channel-base.css css
-http://www.google.de/ https://www.google.de/gen_204?atyp=csi&ei=HJFcWungIZWWjQOIu7TwDw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.614,dcl.332,iml.614,ol.2167,prt.152,xjs.1369,xjsee.1369,xjses.1128,xjsls.160,wsrt.2068,cst.635,dnst.0,rqst.743,rspt.370,sslt.337,rqstt.1579,unt.940,cstt.942,dit.2400&zx=1516015903052 html
-http://www.jd.com/ https://misc.360buyimg.com/??jdf/1.0.0/unit/base/5.0.0/base.js,jdf/lib/jquery-1.6.4.js,channel/lib/1.2.0/js/channel-base.js script
-http://www.google.de/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.de/ https://www.google.de/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.it/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.it/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.it/ https://www.google.it/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfIAR0IiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHBqL8B7cjIL7x8gRAbcUPj8H6Slg script
-http://www.google.it/ https://www.google.it/images/nav_logo242.png image
-http://www.jd.com/ https://misc.360buyimg.com/channel/??/global-sales2017/1.0.0/widget/nav/nav.css,global-sales2017/1.0.0/widget/firstscreen/firstscreen.css,global-sales2017/1.0.0/widget/miaosha/miaosha.css,global-sales2017/1.0.0/widget/week/week.css,global-sales2017/1.0.0/widget/special/special.css,global-sales2017/1.0.0/widget/product/product.css,global-sales2017/1.0.0/widget/widget-ad/widget-ad.css,global-sales2017/1.0.0/widget/domestic/domestic.css,global-sales2017/1.0.0/widget/store/store.css,global-sales2017/1.0.0/widget/more/more.css,global-sales2017/1.0.0/widget/widget-elevator/widget-elevator.css css
-http://www.google.it/ https://www.google.it/gen_204?atyp=csi&ei=MpFcWteeJtLqjwPe3baQBw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.608,dcl.379,iml.608,ol.2453,prt.151,xjs.1564,xjsee.1564,xjses.1180,xjsls.164,wsrt.2050,cst.638,dnst.0,rqst.761,rspt.392,sslt.337,rqstt.1579,unt.938,cstt.939,dit.2429&zx=1516015925398 html
-http://www.weibo.com/ https://passport.weibo.cn/css/weibo/signin/login.css?id=201406091907 css
-http://www.google.de/ https://adservice.google.de/adsid/google/ui html
-http://www.jd.com/ https://misc.360buyimg.com/channel/??/global-sales2017/1.0.0/widget/more/more.js,global-sales2017/1.0.0/widget/widget-elevator/widget-elevator.js script
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/sc/w550h298/20180113/yxWo-fyqrewh8129906.jpg&size=198_132 image
-http://www.weibo.com/ https://passport.weibo.cn/images/weibo/signin/index-pic_2x.png image
-http://www.google.it/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.jd.com/ https://misc.360buyimg.com/mall/lib/hotwords.js?position=h-2062 script
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/mil/8_img/upload/e1815041/w690h319/20180113/n4ZK-fyqrewh7357466.jpg&size=198_132 image
-http://www.google.it/ https://www.google.it/images/branding/product/1x/gsa_android_144dp.png image
-http://www.weibo.com/ https://passport.weibo.cn/images/weibo/signin/icon_2x.png image
-http://www.jd.com/ https://misc.360buyimg.com/jdf/1.0.0/unit/global-header/5.0.0/i/jdlogo-201708-@2x.png image
-http://www.google.it/ https://adservice.google.it/adsid/google/ui html
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/edu/11_img/upload/1370767d/w550h363/20180115/LVZ4-fyqrewi2392924.jpg&size=198_132 image
-http://www.jd.com/ https://misc.360buyimg.com/channel/lib/1.2.0/css/i/lazyload.gif image
-http://www.weibo.com/ https://passport.weibo.cn/favicon.ico image
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/news/transform/w600h400/20180114/ZMNb-fyqrewh8501500.jpg&size=198_132 image
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/widget-elevator/i/kefulogo.png image
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/ent/transform/w600h400/20180115/Lx1w-fyqrewi3489267.jpg&size=198_132 image
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/mil/8_img/upload/641784af/w640h609/20180112/ppu8-fyqnicm1339173.jpg&size=198_132 image
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/widget-elevator/i/arrowtop.png image
-http://www.jd.com/ https://misc.360buyimg.com/jdf/2.0.0/ui/ui/1.0.0/ui.js script
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/ent/transform/w600h400/20180114/2Llq-fyqrewh9663081.jpg&size=198_132 image
-http://www.jd.com/ https://misc.360buyimg.com/jdf/1.0.0/unit/global-footer/5.0.0/i/ico_footer.png image
-http://www.jd.com/ https://misc.360buyimg.com/jdf/1.0.0/unit/service/5.0.0/i/ico_service.png image
-http://www.jd.com/ https://misc.360buyimg.com/jdf/1.0.0/??ui/dialog/1.0.0/dialog.js,unit/cookie/1.0.0/cookie.js script
-http://www.jd.com/ https://misc.360buyimg.com/jdf/1.0.0/unit/ui-base/5.0.0/font/iconfont.woff font
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/ent/transform/w600h400/20180114/E4qB-fyqrewh9113825.jpg&size=198_132 image
-http://www.jd.com/ https://wl.jd.com/wl.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/js/main.js script
-http://www.jd.com/ https://misc.360buyimg.com/jdf/2.0.0/ui/??fixable/1.0.0/fixable.js,elevator/1.0.0/elevator.js script
-http://www.jd.com/ https://misc.360buyimg.com/jdf/2.0.0/ui/gotop/1.0.0/gotop.js script
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/ent/transform/w600h400/20180115/qIeV-fyqrewi1413656.jpg&size=198_132 image
-http://www.jd.com/ https://misc.360buyimg.com/??jdf/1.0.0/unit/globalInit/5.0.0/globalInit.js,jdf/1.0.0/unit/category/2.0.0/category.js,jdf/1.0.0/unit/trimPath/1.0.0/trimPath.js,jdf/1.0.0/unit/login/1.0.0/login.js,jdf/2.0.0/ui/lazyload/1.0.0/lazyload.js,channel/lib/1.2.0/js/webp.js script
-http://www.jd.com/ https://misc.360buyimg.com/jdf/1.0.0/??ui/switchable/1.0.0/switchable.js,ui/dropdown/1.0.0/dropdown.js,ui/lazyload/1.0.0/lazyload.js,ui/areamini/1.0.0/areamini.js,unit/getjsonp/1.0.0/getjsonp.js,unit/event/1.0.0/event.js,unit/hotkey/1.0.0/hotkey.js,unit/globalReco/1.0.0/globalReco.js,unit/search/1.0.0/search.js,unit/setUserInfo/5.0.0/setUserInfo.js,unit/localStorage/1.0.0/localStorage.js,unit/myjd/2.0.0/myjd.js,unit/shortcut/5.0.0/shortcut.js,unit/shoppingcart/5.0.0/shoppingcart.js,unit/category/5.0.0/category.js,unit/log/1.0.0/log.js script
-http://www.jd.com/ https://static.360buyimg.com/webstatic/getprice/1.0.0/js/price.min.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/nav/nav.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/firstscreen/firstscreen.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/miaosha/miaosha.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/week/week.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/nav/i/icon-menu.png image
-http://www.jd.com/ https://misc.360buyimg.com/jdf/2.0.0/ui/tab/1.0.0/tab.js script
-http://www.jd.com/ https://misc.360buyimg.com/jdf/2.0.0/ui/slider/1.0.0/slider.js script
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/miaosha/i/miaoshabg.png image
-http://www.jd.com/ https://misc.360buyimg.com/channel/global-sales2017/1.0.0/widget/firstscreen/i/icon-arrow.png image
-http://www.jd.com/ https://img14.360buyimg.com/cms/jfs/t13123/131/2057935683/36201/1007659c/5a3237fdNba35350a.png!q90.webp image
-http://www.jd.com/ https://img14.360buyimg.com/cms/jfs/t12736/211/2280523294/30798/83308c99/5a542a98Nda58fefd.jpg!q95.webp image
-http://www.jd.com/ https://img14.360buyimg.com/cms/jfs/t14992/208/1671749876/33851/d44aa9c3/5a5422a6Na214a662.jpg!q95.webp image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t16561/365/31697181/8463/bf243d5/5a275794Na685811c.jpg!q95.webp image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t13408/318/1709389880/7844/680eb600/5a2757baN163f2c30.jpg!q95.webp image
-http://www.jd.com/ https://img12.360buyimg.com/cms/jfs/t15100/360/220728747/23460/25f71852/5a275859Nf5e6ce00.jpg!q95.webp image
-http://www.jd.com/ https://img14.360buyimg.com/cms/jfs/t12550/352/1721608361/3982/f40205af/5a2758d5N8321fdb0.png!q95.webp image
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/default/20150527/um-A-cczmvup2382703.jpg&size=135_90 image
-http://www.jd.com/ https://img12.360buyimg.com/cms/jfs/t13342/208/1739110692/13639/11c94f/5a2758e7N834b8b95.jpg!q95.webp image
-http://www.sina.com.cn/ http://d6.sina.com.cn/litong/zhitou/sinaads/demo/jiliang/toutiaobao/simulate/toutiaobaoMedia.js script
-http://www.sina.com.cn/ http://open.weather.sina.com.cn/api/weather/warn_pic/?city=&callback=homeWeatherWarnFun__ script
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t12775/83/1751514055/15890/e67a131d/5a275888Na997fe58.jpg!q95.webp image
-http://www.sina.com.cn/ http://beacon.sina.com.cn/e.gif?UATrack||149.20.63.13_1516016083.34567||149.20.63.13_1516016083.34570||||index_new_guess||c_timeout||||||||&gUid_1516016090579 image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t16339/297/28906778/12705/cc070e44/5a2758c4N7cb84dae.jpg!q95.webp image
-http://www.sina.com.cn/ http://d2.sina.com.cn/litong/zhitou/adJs/store.html?handle=___SinaadsMonBoxCrossDomainStorage___.onReady&domain=sina.com.cn html
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t13261/24/1762566571/25044/3699fd0a/5a275b48Nfb603360.jpg!q95.webp image
-http://www.sina.com.cn/ http://top.news.sina.com.cn/ws/GetTopDataList.php?top_type=day&top_cat=www_www_all_suda_12_suda&top_time=20180115&top_show_num=48&top_order=ASC&format=json&__app_key=ls&callback=cb_1516016090579_97545633&dpc=1 script
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t15025/121/226575484/22312/7b08d132/5a275b3aN995f6d1a.jpg!q95.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000045825&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094094&_sinaads_sio_log_2v1byr image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t14590/259/227221807/21790/98d16948/5a275b52N09ac7a93.jpg!q95.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=2495FC81338A&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_kcuxtu image
-http://www.jd.com/ https://img12.360buyimg.com/cms/jfs/t12958/337/1699718825/22451/c47460c0/5a27ad73N31aead45.png!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%202495FC81338A&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094089&_sinaads_sio_log_sdb06p image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000045825&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_l8enlz image
-http://www.jd.com/ https://img12.360buyimg.com/uba/jfs/t13453/253/1151162982/2161/3b6c8077/5a1c0811N3adfe566.jpg image
-http://www.sina.com.cn/ http://z8.sinaimg.cn/auto/resize?img=http://www.sinaimg.cn/IT/mobile/models/idx/2016/1031/U1734P2T136D21133F3244DT20161031120029.jpg&size=135_90 image
-http://www.jd.com/ https://img14.360buyimg.com/cms/jfs/t14050/130/1734895506/10889/4028494c/5a27ad25Ncad72aa4.png!q90.webp image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t15802/58/108069058/9633/736f8c2d/5a27ad3cN86ed0591.png!q90.webp image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t12820/260/1763001798/5200/af5259b1/5a27ad56Nbeb538a2.png!q90.webp image
-http://www.jd.com/ https://cds.3.cn/get_jimdb_key/get?key=hotword&argv=h-2062&callback=jQuery6791943&_=1516015955663 html
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t14767/300/1621878162/24044/70ad69e1/5a542b11Nd6046d7f.jpg!q95.webp image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t12613/13/2497370083/28888/88dde7cc/5a542b45N47776305.jpg!q95.webp image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t13090/253/1738993732/21484/a31a41fd/5a275871Nc1cc3ec4.jpg!q95.webp image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t12316/259/1714405354/17628/c123d0d5/5a275ba1N4d64fef1.jpg!q95.webp image
-http://www.sina.com.cn/ https://passport.weibo.com/visitor/visitor?a=incarnate&t=X7Gs3ctvZz3P%2FoPwQZnXuv7na3XhwNB7IIFvmWeKTu8%3D&w=2&c=095&gc=&cb=cross_domain&from=iframe&_rand=0.6886126482178869 script
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t14041/217/1754687608/64484/e2ad5df2/5a27b288N8503d562.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20lejuguding&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094101&_sinaads_sio_log_f24qe image
-http://www.jd.com/ https://mercury.jd.com/log.gif?t=www.100000&m=UA-J2011-1&pin=-&uid=1516015955627735810748&sid=1516015955627735810748|1&v=je%3D0%24sc%3D24-bit%24sr%3D360x512%24ul%3Den-us%24cs%3DGBK%24dt%3D%E4%BA%AC%E4%B8%9C%E5%85%A8%E7%90%83%E5%94%AE%20%E2%80%93%20%E4%BA%AC%E4%B8%9C%E7%9B%B4%E9%82%AE%E6%B8%AF%E6%BE%B3%E5%8F%B0%EF%BC%88%E9%A6%99%E6%B8%AF%EF%BC%8C%E6%BE%B3%E9%97%A8%EF%BC%8C%E5%8F%B0%E6%B9%BE%EF%BC%89%E3%80%81%E4%BA%AC%E4%B8%9C%E7%9B%B4%E9%82%AE%E6%B5%B7%E5%A4%96%EF%BC%8C%E5%8C%85%E6%8B%AC%E7%BE%8E%E5%9B%BD%EF%BC%8C%E6%BE%B3%E5%A4%A7%E5%88%A9%E4%BA%9A%EF%BC%8C%E5%8A%A0%E6%8B%BF%E5%A4%A7%EF%BC%8C%E6%97%A5%E6%9C%AC%E7%AD%89%E5%9C%B0%E5%8C%BA%24hn%3Dglobal.jd.com%24fl%3D-%24os%3Dlinux%24br%3Dchrome%24bv%3D58.0.3029.81%24wb%3D1516015956%24xb%3D1516015956%24yb%3D1516015956%24zb%3D1%24cb%3D1%24usc%3Ddirect%24ucp%3D-%24umd%3Dnone%24uct%3D-%24lt%3D0%24ct%3D1516015955614%24tad%3D-%24pinid%3D-%24jdv%3D122270672%7Cdirect%7C-%7Cnone%7C-%7C1516015955631%24dataver%3D0.1&ref=&rm=1516015955634 image
-http://www.sina.com.cn/ https://current.sina.com.cn/theone/IO.WebPush4.localConn.html html
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t15130/17/1709425861/138156/b3b176d8/5a556f17N44e50ca2.png!q90.webp image
-http://www.sina.com.cn/ http://d3.sina.com.cn/litong/zhitou/sinaads/demo/jiliang/toutiaobao/close.jpg image
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/w300h78/20180115/f_JI-fyqrewi1620748.jpg image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t15820/59/524253560/42886/9c299470/5a334356Nbb85892f.jpg!q90.webp image
-http://www.sina.com.cn/ http://n.sinaimg.cn/news/w300h133/20180115/5u_X-fyqrewi1620356.jpg image
-http://www.sina.com.cn/ http://z9.sinaimg.cn/auto/resize?img=http://www.sinaimg.cn/qc/photo_auto/photo/37/09/57633709/57633709_950.jpg&size=135_90 image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t14812/86/205470349/12598/6f213916/5a2671bbN08e317d5.jpg!q95.webp image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t14455/274/1630491447/29133/f8fc45d0/5a542ad3Nc49d5cbd.jpg!q95.webp image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t16141/331/1514518725/43493/e009fb20/5a542bc5Nfc98bb21.jpg!q95.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=lejuguding&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_ixdbkw image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t16387/137/6952677/34368/d11f701f/5a27b707Nd8165883.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000045976&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_m9w03i image
-http://www.jd.com/ https://img14.360buyimg.com/cms/jfs/t12493/246/1722368252/27726/c831fb75/5a27ba96N9bace328.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000045976&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094104&_sinaads_sio_log_n8npya image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t12298/168/2013822221/43880/12432a35/5a2e4632N645c3eaf.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000016827&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094107&_sinaads_sio_log_natwej image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t15400/147/245517277/49229/b5176d34/5a27b66aN6843204c.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000016827&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_a6eenx image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t13162/330/1920643922/18047/d0822233/5a2e0014N1768b8a3.png!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000045982&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094110&_sinaads_sio_log_4k5dh8 image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t14116/276/1742029010/45394/679bd8b7/5a27b6e2N9c7ac6d7.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000045982&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_aqtoy2 image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t15496/17/117495241/36610/85320987/5a27b9f3N8dc74beb.jpg!q90.webp image
-http://www.jd.com/ https://passport.jd.com/new/helloService.ashx?callback=jQuery7365551&_=1516015956895 script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000045983&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_cbk8st image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000045983&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094113&_sinaads_sio_log_2kdjaa image
-http://www.jd.com/ https://passport.jd.com/loginservice.aspx?callback=jQuery7721464&method=Login&_=1516015957007 script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000025256&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094117&_sinaads_sio_log_3lmw9b image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t16276/113/1160282940/10418/bf4a3461/5a4f1676Nad7d89bd.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000025256&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_l0a3fb image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t16438/287/97391912/41556/a37c82a3/5a27bff8N2d4f209e.jpg!q90.webp image
-http://www.sina.com.cn/ http://slog.sina.com.cn/b.gif?type=recmd_ad_exposure&ad_url=http%3A%2F%2Fdata.auto.sina.com.cn%2F2328%3Fsid%3Db99cf2f6e98c4dc899da801924ec6858%26cre%3Dad_business%26mod%3Dg%26loc%3D2%26r%3D0%26doct%3D1%26rfunc%3D12%26tj%3Dnone&ad_pos=P_H_H_3&host_url=http%3A%2F%2Fwww.sina.com.cn%2F&sinaglobal=149.20.63.13_1516016083.34567&time=1516016104939&features=cbrand%3D6XPn%26cseries%3D7GRf%26ctype%3D2%26cprice%3D3%26country%3D0&_ere_sio_log_q1graq image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t16396/299/1108821580/19164/30006788/5a4f1695N70d1ffc7.jpg!q90.webp image
-http://www.sina.com.cn/ http://slog.sina.com.cn/b.gif?type=recmd_ad_exposure&ad_url=http%3A%2F%2Ffashion.sina.com.cn%2Fcosmetics%2Fproduct%2F25637%3Fsid%3D8649bbc828fc436e843816e6c9831437%26cre%3Dad_business%26mod%3Dg%26loc%3D1%26r%3D0%26doct%3D0%26rfunc%3D12%26tj%3Dnone&ad_pos=P_H_H_3&host_url=http%3A%2F%2Fwww.sina.com.cn%2F&sinaglobal=149.20.63.13_1516016083.34567&time=1516016104937&features=mbrand%3D7p8D%26mtype1%3DRFu%26mtype2%3DLQ9%26mprice%3D270&_ere_sio_log_gidswl image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t14590/313/247277313/69923/90f57ffc/5a27baeaN1069a86f.jpg!q90.webp image
-http://www.sina.com.cn/ http://slog.sina.com.cn/b.gif?type=recmd_ad_exposure&ad_url=http%3A%2F%2Ftech.sina.com.cn%2Fmobile%2Fmodels%2F21133.html%3Fsid%3Dc2d725aa3e7347258d7ca69bc7d0c53f%26cre%3Dad_business%26mod%3Dg%26loc%3D3%26r%3D0%26doct%3D2%26rfunc%3D12%26tj%3Dnone&ad_pos=P_H_H_3&host_url=http%3A%2F%2Fwww.sina.com.cn%2F&sinaglobal=149.20.63.13_1516016083.34567&time=1516016104939&features=product%3D2%26manufactor%3DFv7%26price%3D2%26pub_time%3D201610%26os%3DMAo&_ere_sio_log_rcplrx image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t15322/257/1433468070/13396/6ac8d87/5a4f16adN372f5ddf.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000046010&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_bqx5ow image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t15856/246/76568538/30214/6de02fe8/5a27bb4cN144fc8b0.png!q90.webp image
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t15466/112/248934730/123807/c1570cc3/5a27b950N53c46b47.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000046010&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094120&_sinaads_sio_log_z8eb9g image
-http://www.jd.com/ https://img12.360buyimg.com/cms/jfs/t14893/222/1451422782/13469/d37ea0c6/5a4f16cdNdc677502.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058040&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094127&_sinaads_sio_log_e13epb image
-http://www.jd.com/ https://img11.360buyimg.com/cms/jfs/t17752/56/5503270/174006/19e919c8/5a573348N8678205b.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058040&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_cjpiod image
-http://www.jd.com/ https://api.m.jd.com/client.action?functionId=queryMatProdsForGrps&body={%22ids%22:%2201634355%22,%22currentStageFlag%22:%22Y%22,%22sourceCode%22:%22global%22,%22pageId%22:%223894%22}&screen=1081*1921&client=wh5&clientVersion=1.0.0&sid=994d51c8310a73bf7fd138a961cbc616&uuid=1516015955627735810748&callback=jQuery6964983&_=1516015957908 text
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000043762&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094132&_sinaads_sio_log_d6tua4 image
-http://www.jd.com/ https://www.jd.com/favicon.ico image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000043762&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_14r6i2 image
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/sinacn/w640h360/20180113/970f-fyqrewh7593134.png&face=0&size=198_132 image
-http://www.sina.com.cn/ http://z0.sinaimg.cn/auto/resize?img=http://n.sinaimg.cn/sinacn/w480h320/20180113/395b-fyqrewh7374428.png&face=0&size=198_132 image
-http://www.jd.com/ https://payrisk.jd.com/js/td.js script
-http://www.sina.com.cn/ http://beacon.sina.com.cn/e.gif?UATrack||149.20.63.13_1516016083.34567||149.20.63.13_1516016083.34570||||index_new_guess||c_pageview||||||||&gUid_1516016106021 image
-http://www.jd.com/ https://d.jd.com/lab/get?callback=lab script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058041&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_kiz0zf image
-http://www.jd.com/ https://gia.jd.com/y.html?v=0.9410716268823542&o=global.jd.com/ html
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058041&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094137&_sinaads_sio_log_by4sdh image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058042&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094140&_sinaads_sio_log_9qrly1 image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058042&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_gqyke4 image
-http://www.sina.com.cn/ http://www.sinaimg.cn/unipro/pub/suda_s_v851c.js script
-http://www.jd.com/ https://img13.360buyimg.com/cms/jfs/t16192/268/1469567541/212236/33833665/5a541e40N0fc7d23c.jpg!q90.webp image
-http://www.jd.com/ https://gia.jd.com/fcf.html?a=7TJI7TceW0Pu7Tce7TZ37Tce7Tce7T7L7TcezlP47Tce7TZ37Tce7Tce7T7L7TceWIAewGAB6SAewdwPwHcPw4wPwH7QWIAewGAB6SAewQixZHFQwL%3CEZHWDZB2eZBcxFHwkiQFHZ0FGwQ6kwlcE7Tce7T7L7TceJGAewGAB6SAewHcuZID*vH%3CPwHcPw4wPwH7X7Tce7TZ37TceFlxXiQNsvQp4vQZXzSAeRGAewGAe6eAewd6PwHcPwj%3CPwH736AolAAR7g%3CsBf4wkAPJNS4JTSPFiZAkOSBf7gPiBfN4BwPN0AAaBTjk0RN7LAAPKTjx%3CR4ikTTWjwj8eRjAt6PPZgHF3SAZTTjbySSAewGAtR2/ html
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000005494&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_pj5uwo image
-http://www.jd.com/ https://img10.360buyimg.com/cms/jfs/t15994/288/1531751493/163084/15c90bec/5a547f65Ne4317b55.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000005494&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094144&_sinaads_sio_log_y5zqke image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20xinceshe0726&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094149&_sinaads_sio_log_azgwhh image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=xinceshe0726&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_ofx0mf image
-http://www.jd.com/ https://img12.360buyimg.com/cms/jfs/t15850/108/1598916881/300349/f4cbf95d/5a586ffaN6dcb47ba.jpg!q90.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058043&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094155&_sinaads_sio_log_41bc1s image
-http://www.sina.com.cn/ http://newspush.sinajs.cn/wskt?list=live_NEWSPUSH other
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058043&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_2qc0wr image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058184&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_g1tsus image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058184&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094159&_sinaads_sio_log_4i0y79 image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058185&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094161&_sinaads_sio_log_ozubfi image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058185&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_eah7w7 image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000046020&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094165&_sinaads_sio_log_xjkhj1 image
-http://www.sina.com.cn/ http://cm.dmp.360.cn/sina?tuid=149.20.63.13_1516016083.34567 html
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000046020&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_6hq6hl image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000046021&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094169&_sinaads_sio_log_2yu0bq image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000046021&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_6nlgt0 image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058044&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094172&_sinaads_sio_log_epiefk image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058044&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_3hveau image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000056034&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094176&_sinaads_sio_log_24ssj1 image
-http://www.sina.com.cn/ http://r.dmp.sina.com.cn/cm/write?cid=1018&platform=pc&sid=f1089f45dc353d2642d3990b90b33e59 text
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000056034&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_g49jly image
-http://www.sina.com.cn/ http://cm.api.baifendian.com/Mapping.do?bfd_nid=sina&bfd_client_uid=149.20.63.13_1516016083.34567 html
-http://www.sina.com.cn/ http://sina.cm.cn.miaozhen.com/x.gif?v=sina_cm&tuid=149.20.63.13_1516016083.34567&o=http%3A%2F%2Fr.dmp.sina.com.cn%2Fcm%2Fwrite%3Fcid%3D1002%26platform%3Dpc%26sid%3D__M-MZID__ image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20lszuoce50090&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094178&_sinaads_sio_log_ntw56q image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=lszuoce50090&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_4f6gcr image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20lsyouce50090&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094193&_sinaads_sio_log_cm1ftd image
-http://www.sina.com.cn/ http://cms.gtags.net/c?v=51&sinadmp_id=149.20.63.13_1516016083.34567&o=http%3A%2F%2Fr.dmp.sina.com.cn%2Fcm%2Fwrite%3Fcid%3D1004%26platform%3Dpc%26sid%3D__M-MZID__ other
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=lsyouce50090&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_5ns9ub image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058046&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094199&_sinaads_sio_log_9r30xs image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058046&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_665tkg image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000016990&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_l67vny image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000016990&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094203&_sinaads_sio_log_ua7wkq image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%202EF482AADE63&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094207&_sinaads_sio_log_aft0vo image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=2EF482AADE63&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_nnbr2h image
-http://www.google.fr/ http://www.google.fr/ html
-http://www.google.fr/ https://www.google.fr/?gws_rd=ssl html
-http://www.google.com.mx/ http://www.google.com.mx/ html
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000000001&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094210&_sinaads_sio_log_pkrzr2 image
-http://www.google.fr/ https://www.google.fr/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.com.mx/ https://www.google.com.mx/?gws_rd=ssl html
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000000001&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_umqrv4 image
-http://www.google.com.mx/ https://www.google.com.mx/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.fr/ https://www.google.fr/images/nav_logo242_hr.webp image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000059618&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094214&_sinaads_sio_log_dwb0ap image
-http://www.google.com.mx/ https://www.google.com.mx/images/nav_logo242_hr.webp image
-http://www.google.fr/ https://www.google.fr/gen_204?s=webaft&atyp=csi&ei=DZFcWsilEYbUjwObv4awCQ&rt=wsrt.2101,aft.208,prt.208 html
-http://www.google.com.mx/ https://www.google.com.mx/gen_204?s=webaft&atyp=csi&ei=LpFcWruuIoekjwPp8LiwCA&rt=wsrt.2086,aft.148,prt.148 html
-http://www.google.fr/ https://www.google.fr/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/rt=j/d=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.google.fr/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.com.mx/ https://www.google.com.mx/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000059618&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_z2vp1n image
-http://www.google.com.mx/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.fr/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.sina.com.cn/ http://cmpp.gentags.net/sina?tuid=149.20.63.13_1516016083.34567&o=http%3A%2F%2Fr.dmp.sina.com.cn%2Fcm%2Fwrite%3Fcid%3D1005%26platform%3Dpc%26sid%3D__M-MZID__ html
-http://www.google.com.mx/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.fr/ https://www.google.fr/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw?xjs=s1 script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000006450&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094217&_sinaads_sio_log_fobs8 image
-http://www.google.com.mx/ https://www.google.com.mx/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.fr/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.fr/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.fr/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.google.com.mx/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.fr/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.fr/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.fr/ https://www.google.fr/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.google.fr/ https://www.google.fr/images/nav_logo242.png image
-http://www.google.com.mx/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.fr/ https://www.google.fr/gen_204?atyp=csi&ei=DZFcWsilEYbUjwObv4awCQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.572,dcl.357,iml.572,ol.2425,prt.208,xjs.1580,xjsee.1580,xjses.1187,xjsls.241,wsrt.2101,cst.643,dnst.0,rqst.735,rspt.370,sslt.345,rqstt.1587,unt.941,cstt.943,dit.2458&zx=1516015888094 html
-http://www.sina.com.cn/ http://r.dmp.sina.com.cn/cm/write?cid=1002&platform=pc&sid=L23be0QDY8E7 text
-http://www.google.fr/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.fr/ https://www.google.fr/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.fr/ https://adservice.google.fr/adsid/google/ui html
-http://www.google.com.mx/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000006450&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_tbxd1b image
-http://www.linkedin.com/ http://www.linkedin.com/ other
-http://www.google.com.mx/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000054315&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094221&_sinaads_sio_log_ci6py2 image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000054315&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_f58huu image
-http://www.google.com.mx/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.sina.com.cn/ https://atanx.alicdn.com/t/tanxssp.js?_v=12 script
-http://www.google.com.mx/ https://www.google.com.mx/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000051826&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094224&_sinaads_sio_log_dbgrti image
-http://www.google.com.mx/ https://www.google.com.mx/images/nav_logo242.png image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000051826&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_cky26u image
-http://www.google.com.mx/ https://www.google.com.mx/gen_204?atyp=csi&ei=LpFcWruuIoekjwPp8LiwCA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.569,dcl.303,iml.569,ol.2141,prt.147,xjs.1364,xjsee.1364,xjses.1113,xjsls.157,wsrt.2086,cst.642,dnst.0,rqst.725,rspt.346,sslt.343,rqstt.1585,unt.940,cstt.941,dit.2390&zx=1516015921055 html
-http://www.google.com.mx/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.linkedin.com/ https://www.linkedin.com/ html
-http://www.google.com.mx/ https://www.google.com.mx/images/branding/product/1x/gsa_android_144dp.png image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000052408%2CPDPS000000057463&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094227&_sinaads_sio_log_55ppoz image
-http://www.sina.com.cn/ http://beacon.sina.com.cn/mrt.gif?{%22_pk%22:%22179823%22,%22_src%22:%22web%22,%22_rk%22:%221516016109155_0.2681530106848822%22,%22_v%22:%221.0%22,%22_cp%22:{%22os%22:%22pc%22,%22ua%22:%22mozilla/5.0%20(linux;%20android%206.0.1;%20moto%20g%20(4)%20build/mpj24.139-64)%20applewebkit/537.36%20(khtml,%20like%20gecko)%20chrome/58.0.3029.81%20mobile%20safari/537.36%20ptst/180111.190127%22,%22device_id%22:%22%22,%22uid%22:%22unknown%22,%22accesstype%22:%22%22},%22_ep%22:[{%22attribute%22:{%22exp%22:%22visual%22,%22cre%22:%22tianyi%22,%22mod%22:%22pchomettb%22,%22subp%22:%22%22},%22channel%22:%22pc_www%22,%22ek%22:%22toutiaobao%22,%22ref%22:%22%22,%22et%22:%22custom%22,%22src%22:%22http%3A%2F%2Fwww.sina.com.cn%2F%22,%22method%22:%22toutiaobao%22,%22timestamp%22:1516016109156}]} image
-http://www.google.com.mx/ https://adservice.google.com.mx/adsid/google/ui html
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/concat/common/js?h=e2lgukqldpqool72t8g7tysag-3nuvxgwg15rbghxm1gpzfbya2-1nm61x5u7981e88m10hpaekkm-mv3v66b8q0h1hvgvd3yfjv5f-14k913qahq3mh0ac0lh0twk9v script
-http://www.linkedin.com/ https://static-exp2.licdn.com/sc/h/8z5xqy266agx6fxeb5g3gpxy3,dixanwizs7x2n36hdxfx30jwi css
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000052408,PDPS000000057463&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_ohawm9 image
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/concat/common/js?h=7ndrn0f9fw0hum7uoqcjcnzne-95d8d303rtd0n9wj4dcjbnh2c script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20texingxibao&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094230&_sinaads_sio_log_wdz2n0 image
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/concat/common/js?h=a06jpss2hf43xwxobn0gl598m-44hhbxag3hinac547ym9vby09-5jratctnqzzuc1057yivxswgf-9zz2lhu3eq1epk7sq1t8cdb5s-eound1d1xhqm86h7g2p57b94l-edgsl2z4e4gk56cy2m5kbpp1q-acgipb6zomeaovod456pb7yjs-bctwwqj7p01tcj2smshz2bboe-88ec8b078z4fzj5q3z4qowg63-bftaa82sjwcbrohoe28skni7b-58m2n4boqb1vxfd6hgd34auwd-8ycvggo1571xgrdka3utvcyml-cfabcg4u1cj0em4yissh5mfxu script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=texingxibao&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_mtap3i image
-http://www.linkedin.com/ https://static-exp2.licdn.com/sc/h/dtaxdur7yo56xnnlcwq74mt07,bp2iganh4dmi9rrb9j1b720nw script
-http://www.sina.com.cn/ http://r.dmp.sina.com.cn/cm/write?cid=1005&platform=pc&sid=0D3F14950606B95A5C91F4 text
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/concat/common/js?h=69w33ou4umkyupw2uqgn7za7w script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000057532&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094233&_sinaads_sio_log_x82eha image
-http://www.linkedin.com/ https://www.linkedin.com/li/track text
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000057532&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_ynie0d image
-http://www.linkedin.com/ https://platform.linkedin.com/js/analytics.js script
-http://www.sina.com.cn/ http://r.dmp.sina.com.cn/cm/write?cid=1004&platform=pc&sid=2rgV5C_s07-iNerI1lG92r-ELYjt3v1j text
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/concat/common/js?h=ebbt2vixcc5qz0otts5io08xv script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%207C691C8CED38&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094236&_sinaads_sio_log_73zz6s image
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/concat/common/js?h=ed29nkjpsa16bhrjq4na16owq-1mucgfycc664m7vmhpjgqse65-1l5rurej3h44qodo5rn0cdvyn-8om6v2ckrxsbnwf40t9ta8a7e-8jlhg6lqacthgadello7fgxzm-28w7d5j2k2jtil9ncckolke4m-9jzlwicvu376y9q4vjq77y5ks-1m0whdrwis44c1hoa9mrwhlt4-1uvutm1mpyov7rqhtcf8fksby-aac54ic1fmca5xz1yvc5t9nfe-1hn40w0bomeivihj9lopp4hp2-c0121povror81d0xao0yez4gy script
-http://www.sina.com.cn/ http://beacon.sina.com.cn/e.gif?UATrack||149.20.63.13_1516016083.34567||149.20.63.13_1516016083.34570||||index_new_guess||c_hotlist_pageview||||||||&gUid_1516016109778 image
-http://www.linkedin.com/ https://static-exp2.licdn.com/sc/h/8qpm7msyfvdhz89ns9j8pl4n7,crfx0bwvjglv0fh0uev62x5zr script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=7C691C8CED38&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_7qt1xa image
-http://www.linkedin.com/ https://platform.linkedin.com/js/px.js?ch=1 script
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=sinaads_error&msg=sinaads%3Arequest%20timeout%2C%20via%20PDPS000000058017&ref=http%3A%2F%2Fwww.sina.com.cn%2F&ja=0&ck=1&ds=360x512&ua=5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&pf=Linux%20x86_64&ts=1516016094240&_sinaads_sio_log_dgsee1 image
-http://www.linkedin.com/ https://static-exp2.licdn.com/scds/common/u/images/logos/favicons/v1/favicon.ico image
-http://www.sina.com.cn/ http://d00.sina.com.cn/a.gif?type=tp_pc_timeout&pos=PDPS000000058017&ref=http%3A%2F%2Fwww.sina.com.cn%2F&_sinaads_sio_log_gcc306 image
-http://www.linkedin.com/ https://www.linkedin.com/lite/platformtelemetry other
-http://www.sina.com.cn/ https://atanx.alicdn.com/t/acookie/acbeacon4.js script
-http://www.sina.com.cn/ http://beacon.sina.com.cn/a.gif?V=2.1.16&CI=sz:360x512|dp:24|ac:Mozilla|an:Netscape|cpu:undefined|pf:Linux%20x86_64|jv:1.3|ct:unkown|lg:en-US|tz:8|fv:undefined|ja:0&PI=pid:0-9999-0-0-1|st:0|et:1|ref:http%3A//www.sina.com.cn/|hp:unkown|PGLS:|ZT:|MT:|keys:|dom:36|ifr:0&UI=vid:149.20.63.13_1516016083.34567|sid:149.20.63.13_1516016083.34570|lv:1516016080911:2:2:2|un:|uo:|ae:|lu:|si:|rs:0|dm:0|su:&MT=vjuids:&EX=ex1:indexTL|ex2:&gUid_1516016112799 image
-http://www.linkedin.com/ https://www.linkedin.com/fizzy/admin?1516015851113 html
-http://www.sina.com.cn/ https://opehs.tanx.com/ex?i=mm_15890324_2192376_13096223&cb=jsonp_callback_54738&callback=&userid=&o=&f=&n=&r=&cg=c454a31b1d692df0280590fb5e18917d&pvid=a59f6857227e8fa00de99e6172233e3f&u=http%3A%2F%2Fwww.sina.com.cn%2F&psl=0&fp=1.FZBB5uDvOtEe6hzxUD2SuouMrsxyYp3C4x3NL43NXM~-h1h1JqOQCU.UTF-8.g2mitbRpmYrhlA.Q.1nx84sh script
-http://www.linkedin.com/ https://platform.linkedin.com/js/px.js?ch=2 script
-http://www.sina.com.cn/ http://ask.ivideo.sina.com.cn/v_play_ipad.php?vid=146192456 other
-http://www.linkedin.com/ https://static-exp2.licdn.com/sc/h/5ndxqp5qfiw8dfhnuwft3nunh image
-http://www.sina.com.cn/ https://phs.tanx.com/acbeacon4.html html
-http://www.linkedin.com/ https://static-exp2.licdn.com/sc/h/3ubxfas73i6u9fn5k8w6hdxq4 image
-http://www.sina.com.cn/ http://atanx.alicdn.com/t/img/TB1tWvVJFXXXXc_aXXXXXXXXXXX-40-26.png image
-http://www.sina.com.cn/ http://atanx.alicdn.com/t/img/TB1upAiJXXXXXa5aXXXXXXXXXXX-116-30.png image
-http://www.linkedin.com/ https://www.google-analytics.com/r/collect?v=1&_v=j39&a=111182121&t=pageview&_s=1&dl=https%3A%2F%2Fwww.linkedin.com%2Funo-reg-guest-home-mobile&dr=&dp=uno-reg-guest-home-mobile&ul=en-us&de=UTF-8&dt=LinkedIn&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=SEAAAAABM~&jid=594894655&cid=203587286.1516015851&tid=UA-62256447-1&_r=1&z=385060744 html
-http://www.linkedin.com/ https://static-exp2.licdn.com/cdo/rum/id?1516015851108 other
-http://www.linkedin.com/ https://media-exp2.licdn.com/cdo/rum/id?1516015851103 other
-http://www.sina.com.cn/ http://img.alicdn.com/tfs/TB1HaIwMVXXXXb.XFXXXXXXXXXX-1-26.png image
-http://www.linkedin.com/ https://www.linkedin.com/lite/rum-track?csrfToken=ajax%3A7131189071273100441 script
-http://www.google.com.br/ http://www.google.com.br/ html
-http://www.linkedin.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-62256447-1&cid=203587286.1516015851&jid=594894655&_v=j39&z=385060744 html
-http://www.google.com.br/ https://www.google.com.br/?gws_rd=ssl html
-http://www.linkedin.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-62256447-1&cid=203587286.1516015851&jid=594894655&_v=j39&z=385060744 image
-http://www.sina.com.cn/ http://a1.alicdn.com/creation/html/2016/09/19/creation-65122v604gy9XJqq-5273753.html html
-http://www.google.com.br/ https://www.google.com.br/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.com.br/ https://www.google.com.br/images/nav_logo242_hr.webp image
-http://www.google.com.br/ https://www.google.com.br/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.com.br/ https://www.google.com.br/gen_204?s=webaft&atyp=csi&ei=3pBcWsa-OIOEjwPVjafoDQ&rt=wsrt.1969,aft.211,prt.211 html
-http://www.google.com.br/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.sina.com.cn/ http://atanx.alicdn.com/t/tanxclick.js script
-http://www.google.com.br/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.com.br/ https://www.google.com.br/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.sina.com.cn/ http://edge.ivideo.sina.com.cn/146192456.mp4?KID=sina,viask&Expires=1516118400&ssig=8HAW2v9XZJ video
-http://www.google.com.br/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.sina.com.cn/ https://df.tanx.com/spf3?e=T1Q33QSRdNWxnIc0XVIGw9QGqUUx3yjKzVeRs8H0rP_f8mtg5BXsUhPOOIdHALCyqLsYUtTEOaA3I4VITzVh60DFh9xFuGWVaEF45QKY8qRRipMrBDNxs4ufAy14VMT6Cv-5bhgAq7RxZu2H-UhP9osDEEDjDdmT&k=161&i=mm_15890324_2192376_13096223 image
-http://www.google.com.br/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.sina.com.cn/ http://m.simba.taobao.com/?name=itemdsp&o=j&st_type=5_8&tanxdspv=https%3A%2F%2Frdstat.tanx.com%2Ftrd%3Ff%3D%26k%3Da09e279ad7f7a12a%26p%3Dmm_15890324_2192376_13096223%26pvid%3D0a67267d00005a5c91f5344400327ec2%26s%3D360x242%26d%3D59420271%26t%3D1516016117&pid=mm_15890324_2192376_13096223&tp=3&tsid=0a67267d00005a5c91f5344400327ec2&u=http%3A%2F%2Fwww.sina.com.cn%2F&r=&layouttid=40952&count=9&p4p=jsonp0jcg4urwa html
-http://www.google.com.br/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.sina.com.cn/ https://log.mmstat.com/t.gif image
-http://www.google.com.br/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.sina.com.cn/ http://gma.alicdn.com/bao/uploaded/i8/TB1w4Lea7v85uJjSZFPYXIh4pXa_315x315.jpg image
-http://www.google.com.br/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.sina.com.cn/ http://gma.alicdn.com/bao/uploaded/i4/117608284/TB2tX1jj0fJ8KJjy0FeXXXKEXXa_!!0-saturn_solar.jpg_315x315.jpg image
-http://www.sina.com.cn/ http://gma.alicdn.com/bao/uploaded/i3/32664870/TB2_QecdlfM8KJjSZPiXXXdspXa_!!0-saturn_solar.jpg_315x315.jpg image
-http://www.sina.com.cn/ https://pcookie.tanx.com/app.gif?&cna=+H/jEovVUj8CAZUUPw1TjNKQ image
-http://www.google.com.br/ https://www.google.com.br/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.sina.com.cn/ http://www.sina.com.cn/favicon.ico image
-http://www.sina.com.cn/ http://gtms04.alicdn.com/tps/i4/TB1dO74JFXXXXbPXFXXpwSwJFXX-3-3.png image
-http://www.google.com.br/ https://www.google.com.br/images/nav_logo242.png image
-http://www.sina.com.cn/ http://interest.mix.sina.com.cn/api/customize/get_click?homeId=10001&_t=0.48035219839319865&callback=fun_700572923689359572& script
-http://www.google.com.br/ https://www.google.com.br/gen_204?atyp=csi&ei=3pBcWsa-OIOEjwPVjafoDQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.670,dcl.382,iml.670,ol.2087,prt.211,xjs.1367,xjsee.1366,xjses.1186,xjsls.199,wsrt.1969,cst.622,dnst.0,rqst.755,rspt.408,sslt.322,rqstt.1544,unt.921,cstt.922,dit.2349&zx=1516015841285 html
-http://www.google.com.br/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.com.br/ https://www.google.com.br/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.com.br/ https://adservice.google.com.br/adsid/google/ui html
-http://www.yandex.ru/ http://www.yandex.ru/ other
-http://www.yandex.ru/ https://www.yandex.ru/ html
-http://www.yandex.ru/ https://yastatic.net/jquery/2.1.4/jquery.min.js script
-http://www.yandex.ru/ https://yastatic.net/www/_/f/G/prtpfcPuKCOnEmAgSXcAoImWo.js script
-http://www.yandex.ru/ https://yastatic.net/www/_/i/W/HwjHLBtzDBrPeh3dxEyFpfSbo.js script
-http://www.yandex.ru/ https://yastatic.net/www/_/e/S/-nxtWWJ1LfBWLfd096swuFjH4.svg image
-http://www.netflix.com/ http://www.netflix.com/ other
-http://www.yandex.ru/ https://yastatic.net/www/_/S/m/OoQ5UV2O78_VId8qbYCP0LrvI.svg image
-http://www.yandex.ru/ https://www.yandex.ru/search/suggest-history?format=json script
-http://www.netflix.com/ https://www.netflix.com/ html
-http://www.yandex.ru/ https://yastatic.net/www/_/w/3/NMs8GVrUhnZ_rfJGK5NAC2FQo.css css
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2/freeform/WebsiteDetect?source=wwwhead&fetchType=css&modalView=nmLanding text
-http://www.yandex.ru/ https://www.yandex.ru/portal/home-touch/service-worker.js script
-http://www.yandex.ru/ https://www.yandex.ru/portal/log/json/?type=morda-topnews html
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2/freeform/WebsiteDetect?source=wwwhead&fetchType=js&modalView=nmLanding text
-http://www.yandex.ru/ https://mc.yandex.ru/metrika/watch.js script
-http://www.yandex.ru/ https://yandex.ru/clck/counter image
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2/freeform/WebsiteScreen?source=wwwhead&fetchType=js&winw=360&winh=512&screenw=980&screenh=1394&ratio=3 text
-http://www.yandex.ru/ https://zen.yandex.ru/api/v3/mobile-morda/teasers?country_code=ru script
-http://www.netflix.com/ https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-css-27a7d20c/css/css/pages%7Chome%7Cconcord.less/2/0I0_0h0e0Q0O120-0P0Y/none/true/none css
-http://www.yandex.ru/ https://mc.yandex.ru/watch/23474449?wmode=7&page-url=https%3A%2F%2Fwww.yandex.ru%2F&charset=utf-8&ut=noindex&exp=qA205T_ANuqp_npzfYfGZQ&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Ai%3A20180115113057%3Aet%3A1516015858%3Aen%3Autf-8%3Av%3A932%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A881410072369%3Arqn%3A1%3Arn%3A288643946%3Ahid%3A523917819%3Ads%3A0%2C946%2C615%2C936%2C1451%2C0%2C0%2C981%2C25%2C%2C%2C%2C6368%3Afp%3A3418%3Arqnl%3A1%3Ast%3A1516015858%3Au%3A1516015858146933186%3At%3A%D0%AF%D0%BD%D0%B4%D0%B5%D0%BA%D1%81 other
-http://www.netflix.com/ https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-js-27a7d20c/js/js/bootstrap.js,common%7Cbootstrap.js/2/4ygi03gefTfR4lg40k0i4ffYgh070y02f_fW0ggdga4qfZfOg14t4s1e/bk/true/none script
-http://www.netflix.com/ https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-js-27a7d20c/js/js/signup%7Chome%7Clite%7Cclient.js/2/4ygi03gefTfR4lg40k0i4ffYgh070y02f_fW0ggdga4qfZfOg14t4s1e/l/true/none script
-http://www.yandex.ru/ https://www.yandex.ru/portal/set/any/?sk=yd5a3ceee505a8e86362cba0365f58598&empty=1&szm=3_00:360x512:360x512 html
-http://www.yandex.ru/ https://mc.yandex.ru/metrika/advert.gif image
-http://www.netflix.com/ https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-js-27a7d20c/js/js/signup%7Csimplicity%7CsimpleSignupClient.js/2/4ygi03gefTfR4lg40k0i4ffYgh070y02f_fW0ggdga4qfZfOg14t4s1e/l/true/none script
-http://www.yandex.ru/ https://mc.yandex.ru/watch/23474449/1?wmode=7&page-url=https%3A%2F%2Fwww.yandex.ru%2F&charset=utf-8&ut=noindex&exp=qA205T_ANuqp_npzfYfGZQ&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Ai%3A20180115113057%3Aet%3A1516015858%3Aen%3Autf-8%3Av%3A932%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A881410072369%3Arqn%3A1%3Arn%3A288643946%3Ahid%3A523917819%3Ads%3A0%2C946%2C615%2C936%2C1451%2C0%2C0%2C981%2C25%2C%2C%2C%2C6368%3Afp%3A3418%3Arqnl%3A1%3Ast%3A1516015858%3Au%3A1516015858146933186%3At%3A%D0%AF%D0%BD%D0%B4%D0%B5%D0%BA%D1%81 script
-http://www.netflix.com/ https://assets.nflxext.com/ffe/siteui/vlv3/20b38e8a-bb42-419c-97e7-55063f4dc4ea/3449d932-8f67-4c5b-aa79-c5de4a7fdee8/US-en-20180108-popsignuptwoweeks-perspective_alpha_website_small.jpg image
-http://www.yandex.ru/ https://yandex.ru/clck/counter image
-http://www.yandex.ru/ https://yandex.ru/clck/counter image
-http://www.netflix.com/ https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_cancelanytime_withdevice.jpg image
-http://www.yandex.ru/ https://awaps.yandex.net/99/c1/tzVGQsWZ9Xe7noxwTANSC7tnKr35jC3678BqUhnOEWOz-E+e-ABRT9TDMH8VZ_tXMrJuEHUjC0+uMTCFhjRszJX6ocfCyVCyUo1tAKgMEwKUCBVSoqDbhMhVEu7_tscYbABAmhdLeYYWsCt4ZHwJG+KcD6nOQyELHzY9eYAo4VQV49kRTcY+1hEg+_tOCnTo6bM3alOPan5ZfXHKAQNZKlO00sxNcimEzFM8B8UVsbFQwFc+Zb2uWN8_tELnrmZgJ2NIKywSRCOWcuRj2viK9mkiovWIJlX67IBSsPm8IftBkhGDOAodv_f2BsyxjWxzN-ZRqWEu4EKSbX3RAwxONdQ0AuDsrBYIwAA_A_.gif image
-http://www.netflix.com/ https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_TV_UI.jpg image
-http://www.yandex.ru/ https://avatars.mds.yandex.net/get-zen_doc/118017/rss_9122441715438513317/smart_crop_516x290 image
-http://www.netflix.com/ https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_mobile_tablet_UI_2.jpg image
-http://www.yandex.ru/ https://avatars.mds.yandex.net/get-zen_doc/108399/db_-6649040632175834052/smart_crop_516x290 image
-http://www.netflix.com/ https://assets.nflxext.com/ffe/siteui/acquisition/home/thisIsNetflix/modules/small/asset_website_UI.jpg image
-http://www.netflix.com/ https://assets.nflxext.com/ffe/siteui/fonts/nf-icon-v1-88.woff font
-http://www.yandex.ru/ https://yastatic.net/zen-logos/files/domain-logos/adme.ru-white.png?md5=fea0eccfeafcfc96329ab4ac78894221 image
-http://www.yandex.ru/ https://yastatic.net/zen-logos/files/domain-logos/russian7.ru-white.png?md5=9ced9294b421cfe883708022a89ec7d9 image
-http://www.yandex.ru/ https://yastatic.net/iconostasis/_/8lFaTHLDzmsEZz-5XaQg9iTWZGE.png image
-http://www.netflix.com/ https://codex.nflxext.com/%5E2.0.0/truthBundle/webui/0.0.1-shakti-css-27a7d20c/css/css/pages%7Csignup%7Csimplicity%7Csimplicity.less/2/0I0_0h0e0Q0O120-0P0Y/none/true/none css
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2/freeform/DebugEvent?source=www&action=cssSimplicityPrefetch&statusCode=200&startTime=1516015856114&endTime=1516015857423 text
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2 text
-http://www.yandex.ru/ https://yandex.ru/search/touchcache.js script
-http://www.yandex.ru/ https://yandex.ru/clck/click/dtype=stred/pid=1/cid=72202/reqid=1516015851.85081.22878.18799/path=690.1033/vars=143=28.15.1785,287=102567,695=1833,1036=1455,1037=0,1038=946,1039=615,1040=936,1041=402,1042=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127,1051=6284,1402=167,1676=464,1961=0,1964=0,1965=0,2095=3177,2290=652,2700=1774,2793=3418,2794=3418,2796=9106,1040.318=3952,1041.660=3418,1041.906=1963,1041.318=3418,2796.2797=s-3116-3174.u-3548-3655.s-6104-6414.s-6442-6516.s-8523-8591.s-9051-9105,1402.318=3183,2290.318=3668,695.318=4849,2095.318=6193,2095.2136=173,2700.318=4790,2700.2136=9/slots=58904,0,42/* image
-http://www.google.com.hk/ http://www.google.com.hk/ html
-http://www.google.com.hk/ https://www.google.com.hk/?gws_rd=ssl html
-http://www.google.com.hk/ https://www.google.com.hk/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.com.hk/ https://www.google.com.hk/images/nav_logo242_hr.webp image
-http://www.google.com.hk/ https://www.google.com.hk/gen_204?s=webaft&atyp=csi&ei=6ZBcWt25GpG8jwPYiqPQCQ&rt=wsrt.2030,aft.227,prt.227 html
-http://www.netflix.com/ https://assets.nflxext.com/us/ffe/siteui/common/icons/nficon2016.ico image
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2 text
-http://www.google.com.hk/ https://www.google.com.hk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.com.hk/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.com.hk/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.com.hk/ https://www.google.com.hk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.com.hk/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.google.com.hk/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.com.hk/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.com.hk/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.com.hk/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.com.hk/ https://www.google.com.hk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.com.hk/ https://www.google.com.hk/images/nav_logo242.png image
-http://www.google.com.hk/ https://www.google.com.hk/gen_204?atyp=csi&ei=6ZBcWt25GpG8jwPYiqPQCQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.657,dcl.379,iml.657,ol.2366,prt.227,xjs.1549,xjsee.1549,xjses.1237,xjsls.240,wsrt.2030,cst.629,dnst.0,rqst.772,rspt.425,sslt.331,rqstt.1553,unt.922,cstt.924,dit.2409&zx=1516015852122 html
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2/freeform/WebsiteTTI?source=www&timeToInteractive=3112&firstByte=1274&wire=321&domReady=3112&docLoad=6520&shakti=931&previousPage=1003&navigateTTI=4433 text
-http://www.google.com.hk/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.com.hk/ https://www.google.com.hk/images/branding/product/1x/gsa_android_144dp.png image
-http://www.netflix.com/ https://www.netflix.com/ichnaea/cl2/freeform/DebugEvent?source=www&action=jsSimplicityPrefetch&statusCode=200&startTime=1516015856110&endTime=1516015859717 text
-http://www.google.com.hk/ https://adservice.google.com.hk/adsid/google/ui html
-http://www.netflix.com/ https://ethn.io/mob/41183.js?guid=D2P4DMBBR5BUVPT6ONQTDLN6FI script
-http://www.netflix.com/ https://adtech.nflximg.net/adtech_iframe_target_03.html?data=%7B%22is_member%22%3A%22anonymous%22%2C%22membership_status%22%3A%22NON_REGISTERED_MEMBER%22%2C%22session%22%3A%22n%2Fa%22%2C%22country%22%3A%22US%22%2C%22referrer%22%3A%22nmLanding%22%2C%22source%22%3A%22%22%2C%22fbaId%22%3A%22c8bdae26-b243-4e10-9fea-91fd2d3d87d9%22%7D html
-http://www.netflix.com/ https://www.netflix.com/ichnaea/log text
-http://www.netflix.com/ https://s.thebrighttag.com/tag?site=voKfK9l&mode=iframe&is_member=anonymous&membership_status=NON_REGISTERED_MEMBER&session=n%2Fa&country=US&referrer=netflix.com%2Fbt%2FnmLanding&source=&fbaId=c8bdae26-b243-4e10-9fea-91fd2d3d87d9 html
-http://www.google.co.uk/ http://www.google.co.uk/ html
-http://www.google.co.uk/ https://www.google.co.uk/?gws_rd=ssl html
-http://www.google.co.uk/ https://www.google.co.uk/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.co.uk/ https://www.google.co.uk/images/nav_logo242_hr.webp image
-http://www.google.co.uk/ https://www.google.co.uk/gen_204?s=webaft&atyp=csi&ei=IpFcWvCTC9DCjwPUqomIBA&rt=wsrt.2034,aft.174,prt.174 html
-http://www.google.co.uk/ https://www.google.co.uk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.co.uk/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.co.uk/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.co.uk/ https://www.google.co.uk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.co.uk/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.netflix.com/ https://s.btstatic.com/tag.js script
-http://www.google.co.uk/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.netflix.com/ https://www.netflix.com/ichnaea/log text
-http://www.google.co.uk/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.netflix.com/ https://s.thebrighttag.com/tag?site=voKfK9l&H=-2cvf10o&referrer=netflix.com%2Fbt%2FnmLanding&docReferrer=https%3A%2F%2Fadtech.nflximg.net%2Fadtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522c8bdae26-b243-4e10-9fea-91fd2d3d87d9%2522%257D&mode=v2&cf=1968499%2C2766978%2C2812541&_cb_bt_data(%27gclid%27)=&btpdb.voKfK9l.dGZjLjU5OTM5MjA=VVNFUg&btpdb.voKfK9l.dGZjLjI3ODY5NTI=VVNFUg script
-http://www.google.co.uk/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.co.uk/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.co.uk/ https://www.google.co.uk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.netflix.com/ https://www.googleadservices.com/pagead/conversion.js script
-http://www.google.co.uk/ https://www.google.co.uk/images/nav_logo242.png image
-http://www.netflix.com/ https://4954221.fls.doubleclick.net/activityi;src=4954221;type=gl-cs;cat=dcmgl0;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=4903371628340.179 html
-http://www.google.co.uk/ https://www.google.co.uk/gen_204?atyp=csi&ei=IpFcWvCTC9DCjwPUqomIBA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.647,dcl.323,iml.647,ol.2437,prt.174,xjs.1417,xjsee.1417,xjses.1178,xjsls.182,wsrt.2034,cst.636,dnst.0,rqst.734,rspt.368,sslt.336,rqstt.1578,unt.942,cstt.942,dit.2358&zx=1516015908924 html
-http://www.netflix.com/ https://4954221.fls.doubleclick.net/activityi;src=4954221;type=gl-nmh;cat=dcmgl0;u1=US;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=2497355217470.6626 html
-http://www.google.co.uk/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.netflix.com/ https://cm.g.doubleclick.net/pixel?google_nid=netflix_dmp&referrer=netflix.com/bt/nmLanding&google_cm html
-http://www.google.co.uk/ https://www.google.co.uk/images/branding/product/1x/gsa_android_144dp.png image
-http://www.netflix.com/ https://www.facebook.com/tr?id=829253787145710&ev=NM_landing&cd[value]=9.99&cd[currency]=USD text
-http://www.google.co.uk/ https://adservice.google.co.uk/adsid/google/ui html
-http://www.netflix.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/983869946/?value=0&guid=ON&script=0 image
-http://www.netflix.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/991179584/?value=0&guid=ON&script=0 image
-http://www.netflix.com/ https://www.facebook.com/tr?id=829253787145710&ev=NMLanding&cd[value]=9.99&cd[currency]=USD image
-http://www.netflix.com/ https://4968236.fls.doubleclick.net/activityi;src=4968236;type=naanz-nm;cat=dcmna0;u1=US;ord=5686108697362.591 html
-http://www.netflix.com/ https://www.googleadservices.com/pagead/conversion/981179826/?random=1516015865411&cv=8&fst=1516015865411&num=1&label=40zWCLqP1XUQsrvu0wM&bg=ffffff&hl=en&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fs.thebrighttag.com%2Ftag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26session%3Dn%252Fa%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Dc8bdae26-b243-4e10-9fea-91fd2d3d87d9&ref=https%3A%2F%2Fadtech.nflximg.net%2Fadtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522c8bdae26-b243-4e10-9fea-91fd2d3d87d9%2522%257D&rfmt=3&fmt=4 script
-http://www.netflix.com/ https://cm.g.doubleclick.net/pixel?google_nid=netflix_dmp&referrer=netflix.com/bt/nmLanding&google_cm=&google_tc= html
-http://www.netflix.com/ https://www.facebook.com/tr?cd[currency]=USD&cd[value]=9.99&ev=NM_landing&id=829253787145710&redirect=0 image
-http://www.netflix.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/981179826/?random=610563922&cv=8&fst=*&num=1&label=40zWCLqP1XUQsrvu0wM&bg=ffffff&hl=en&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26session%3Dn%252Fa%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Dc8bdae26-b243-4e10-9fea-91fd2d3d87d9&ref=https://adtech.nflximg.net/adtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522c8bdae26-b243-4e10-9fea-91fd2d3d87d9%2522%257D&fmt=3&ctc_id=CAIVAgAAAB0CAAAA&ct_cookie_present=false&ocp_id=-ZBcWpSxJ4bQkwOt47jwDA image
-http://www.netflix.com/ https://www.google.com/ads/user-lists/983869946/?value=0&guid=ON&script=0&cdct=2&is_vtc=1&random=3008282913 image
-http://www.netflix.com/ https://www.google.com/ads/user-lists/991179584/?value=0&guid=ON&script=0&cdct=2&is_vtc=1&random=1852610199 image
-http://www.netflix.com/ https://www.google.com/ads/conversion/981179826/?random=610563922&cv=8&fst=*&num=1&label=40zWCLqP1XUQsrvu0wM&bg=ffffff&hl=en&guid=ON&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26session%3Dn%252Fa%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Dc8bdae26-b243-4e10-9fea-91fd2d3d87d9&ref=https://adtech.nflximg.net/adtech_iframe_target_03.html%3Fdata%3D%257B%2522is_member%2522%253A%2522anonymous%2522%252C%2522membership_status%2522%253A%2522NON_REGISTERED_MEMBER%2522%252C%2522session%2522%253A%2522n%252Fa%2522%252C%2522country%2522%253A%2522US%2522%252C%2522referrer%2522%253A%2522nmLanding%2522%252C%2522source%2522%253A%2522%2522%252C%2522fbaId%2522%253A%2522c8bdae26-b243-4e10-9fea-91fd2d3d87d9%2522%257D&fmt=3&ctc_id=CAIVAgAAAB0CAAAA&ct_cookie_present=false&cdct=2&is_vtc=1&ocp_id=-ZBcWpSxJ4bQkwOt47jwDA&random=1573368872 image
-http://www.netflix.com/ https://adservice.google.com/ddm/fls/i/src=4954221;type=gl-nmh;cat=dcmgl0;u1=US;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=2497355217470.6626;_dc_1=1;~oref=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Dc8bdae26-b243-4e10-9fea-91fd2d3d87d9 html
-http://www.netflix.com/ https://adservice.google.com/ddm/fls/i/src=4954221;type=gl-cs;cat=dcmgl0;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=4903371628340.179;_dc_1=1;~oref=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Dc8bdae26-b243-4e10-9fea-91fd2d3d87d9 html
-http://www.netflix.com/ https://adservice.google.com/ddm/fls/i/src=4968236;type=naanz-nm;cat=dcmna0;u1=US;ord=5686108697362.591;_dc_1=1;~oref=https://s.thebrighttag.com/tag%3Fsite%3DvoKfK9l%26mode%3Diframe%26is_member%3Danonymous%26membership_status%3DNON_REGISTERED_MEMBER%26country%3DUS%26referrer%3Dnetflix.com%252Fbt%252FnmLanding%26source%3D%26fbaId%3Dc8bdae26-b243-4e10-9fea-91fd2d3d87d9 html
-http://www.netflix.com/ https://ichnaea.netflix.com/log/image/doubleclick/cm?referrer=netflix.com/bt/nmLanding&google_gid=CAESEA6yp9cofzqzG2L0SbLKA3s&google_cver=1 image
-http://www.google.es/ http://www.google.es/ html
-http://www.google.es/ https://www.google.es/?gws_rd=ssl html
-http://www.google.es/ https://www.google.es/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.es/ https://www.google.es/images/nav_logo242_hr.webp image
-http://www.google.es/ https://www.google.es/gen_204?s=webaft&atyp=csi&ei=G5FcWp3nGpTCjwOdx6j4DA&rt=wsrt.2089,aft.166,prt.166 html
-http://www.google.es/ https://www.google.es/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.es/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.google.es/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.google.es/ https://www.google.es/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.es/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.es/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.es/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.google.es/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.es/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.es/ https://www.google.es/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.es/ https://www.google.es/images/nav_logo242.png image
-http://www.google.es/ https://www.google.es/gen_204?atyp=csi&ei=G5FcWp3nGpTCjwOdx6j4DA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.572,dcl.274,iml.572,ol.2211,prt.165,xjs.1391,xjsee.1391,xjses.1079,xjsls.187,wsrt.2089,cst.644,dnst.0,rqst.714,rspt.346,sslt.345,rqstt.1587,unt.940,cstt.940,dit.2364&zx=1516015902004 html
-http://www.google.es/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.google.es/ https://www.google.es/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.es/ https://adservice.google.es/adsid/google/ui html
-http://www.alipay.com/ http://www.alipay.com/ html
-http://www.alipay.com/ https://www.alipay.com/ html
-http://www.alipay.com/ https://m.alipay.com/?from=pc html
-http://www.alipay.com/ https://ds.alipay.com/?from=pc html
-http://www.alipay.com/ https://a.alipayobjects.com/g/animajs/mtracker/3.1.0/seed.js script
-http://www.alipay.com/ https://a.alipayobjects.com/amui/zepto/1.1.3/zepto.js script
-http://www.alipay.com/ https://gw.alipayobjects.com/os/s/prod/i/index-bd57f.css css
-http://www.alipay.com/ https://gw.alipayobjects.com/os/??s/prod/i/common-47226.js,s/prod/i/index-3bf35.js script
-http://www.alipay.com/ https://gw.alipayobjects.com/os/rmsportal/WpGrtMXlamAjMGBnDmvF.js script
-http://www.alipay.com/ https://zos.alipayobjects.com/rmsportal/eFatlrQCyUQVBoalzBPS.png image
-http://www.alipay.com/ https://log.mmstat.com/5.gif?url=https://kcart.alipay.com/web/1.do? image
-http://www.alipay.com/ https://kcart.alipay.com/s.gif?data=eyJ3aW5fdmFyIjpbIm9ub3JpZW50YXRpb25jaGFuZ2UiXSwicmVmZXJyZXIiOiIiLCJvcmlfaW5mbyI6eyJhbHBoYSI6eyJhdmciOjAsImRldiI6MH0sImJldGEiOnsiYXZnIjowLCJkZXYiOjB9LCJnYW1tYSI6eyJhdmciOjAsImRldiI6MH0sIm51bSI6MX19 image
-http://www.alipay.com/ https://kcart.alipay.com/web/1.do?&cna=gH/jErzWglwCAZUUPw0EuMK+ image
-http://www.alipay.com/ https://ds.alipay.com/favicon.ico image
-http://www.xvideos.com/ http://www.xvideos.com/ html
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-7963e0cccd9/v3/js/skins/min/default.header.static.js script
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-8437aa666c6/v3/css/default/main.css css
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-aae497bb6e5/v3/js/skins/min/default.footer.static.js script
-http://www.xvideos.com/ http://static-hw.xvideos.com/v3/js/libs/jquery.min.js script
-http://www.xvideos.com/ http://static-hw.xvideos.com/img/lightbox/lightbox-blank.gif image
-http://www.xvideos.com/ http://static-hw.xvideos.com/v3/js/skins/min/require.static.js script
-http://www.xvideos.com/ http://static-hw.xvideos.com/v3/img/skins/default/xvideos.com.svg image
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-1937087c8d6/v3/js/i18n/front/english.json script
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-8437aa666c6/v3/img/flags/flat/flags-32.png image
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-00000000019/v3/img/skins/default/xv-icons-sprite.svg image
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-8437aa666c6/v3/img/flags/flat/flags-16.png image
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-00000000012/v3/fonts/skins/default/iconfont/iconfont.woff2?p4y3fi font
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/bf/e9/c6/bfe9c67dcecca701844b3ae262910fff/bfe9c67dcecca701844b3ae262910fff.20.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/c0/da/7a/c0da7a53ae5d8d74a534e29b0dffd836/c0da7a53ae5d8d74a534e29b0dffd836.18.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/06/c8/4d/06c84dca1ace9e484d759e7c1b26b15b/06c84dca1ace9e484d759e7c1b26b15b.7.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/b0/79/2c/b0792caa87e2964c96de592ad0f39f51/b0792caa87e2964c96de592ad0f39f51.23.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/32/c9/88/32c98837ce4d90b5150e44f9fe9844e7/32c98837ce4d90b5150e44f9fe9844e7.4.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/5b/99/18/5b9918c0a8a6947e7aba2d00a456e57a/5b9918c0a8a6947e7aba2d00a456e57a.1.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/96/dc/a9/96dca91c3666803136e6fe4898d13cbb/96dca91c3666803136e6fe4898d13cbb.5.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/bf/81/c6/bf81c6de4d70c9e4dd258152a9b0ac48/bf81c6de4d70c9e4dd258152a9b0ac48.9.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/bc/98/84/bc9884c0222ee64e3fadd5cfcd5357f1/bc9884c0222ee64e3fadd5cfcd5357f1.6.jpg image
-http://www.pornhub.com/ http://www.pornhub.com/ html
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/75/19/db/7519db0951cdf23dcfa85d618d65f41d/7519db0951cdf23dcfa85d618d65f41d.7.jpg image
-http://www.pornhub.com/ https://www.pornhub.com/ html
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/normalize.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/fc/03/b9/fc03b9ec3b451d5a7a88c54e67892d15/fc03b9ec3b451d5a7a88c54e67892d15.5.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/widgets-premium_promo_banner.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/fa/f3/53/faf353a2d5fbccae857a8e3cb204ad82/faf353a2d5fbccae857a8e3cb204ad82.27.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/7c/dd/a6/7cdda63bfc6e382d47e606c944ea829c/7cdda63bfc6e382d47e606c944ea829c.6.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/premium/launch-banner.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/98/b6/85/98b6854b591ce8652f57246aaa46e9eb/98b6854b591ce8652f57246aaa46e9eb.13.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/modals_commons.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/d9/e4/71/d9e471dfb46d592ea523aaf73789d0c8/d9e471dfb46d592ea523aaf73789d0c8.7.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/main.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-l3.xvideos.com/videos/thumbs169ll/d9/28/30/d9283013160e94b03cd7e1db106a6bd9/d9283013160e94b03cd7e1db106a6bd9.2.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/listings.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/40/c9/ef/40c9efa3961bf1ce8bf5c2ad095f8702/40c9efa3961bf1ce8bf5c2ad095f8702.9.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/13/83/06/1383062c42e1396f361ecb39379e185d/1383062c42e1396f361ecb39379e185d.15.jpg image
-http://www.pornhub.com/ https://cdn1d-static-shared.phncdn.com/vortex-simple-1.0.0.js?cache=2018010401 script
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/7a/77/fe/7a77febc2a29f83d4e2213c05c8d7e1c/7a77febc2a29f83d4e2213c05c8d7e1c.8.jpg image
-http://www.pornhub.com/ https://cdn1d-static-shared.phncdn.com/mg_utils-1.0.0.js?cache=2018010401 script
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/13/fc/b7/13fcb7247b9a065abea08ff33d30084e/13fcb7247b9a065abea08ff33d30084e.5.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/css/vmobile/premium/premium-modals.css?cache=2018010401 css
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/5d/d8/f8/5dd8f82c959e2254aed4ea4a43b85f6a/5dd8f82c959e2254aed4ea4a43b85f6a.28.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/utils.js?cache=2018010401 script
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/f1/97/75/f197759a8145188ff17fc2a6b35a0bf2/f197759a8145188ff17fc2a6b35a0bf2.14.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/mg_modal-1.0.0.js?cache=2018010401 script
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/ff/31/d4/ff31d436f8db20dcf9ca79208f9e30ee/ff31d436f8db20dcf9ca79208f9e30ee.15.jpg image
-http://www.xvideos.com/ http://img-l3.xvideos.com/videos/thumbs169ll/00/2c/fc/002cfc446ecc0b06c680f505b0c9c97c/002cfc446ecc0b06c680f505b0c9c97c.13.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/lib/ph-functions.js?cache=2018010401 script
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/8e/da/58/8eda58d5097e9097c43369de43e91f03/8eda58d5097e9097c43369de43e91f03.13.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/html5-canvas.js?cache=2018010401 script
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/bd/43/dd/bd43dd3566e4379590742c762748f33f/bd43dd3566e4379590742c762748f33f.24.jpg image
-http://www.pornhub.com/ https://fonts.googleapis.com/css?family=Open+Sans:300,400&subset=latin,latin-ext css
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/eb/10/4a/eb104a96d489333923770c368953b0ee/eb104a96d489333923770c368953b0ee.8.jpg image
-http://www.pornhub.com/ https://fonts.googleapis.com/css?family=Open+Sans:300,400,700&subset=latin,latin-ext css
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/e8/d8/d1/e8d8d1fd9e6805d409b5fb77f3c49296/e8d8d1fd9e6805d409b5fb77f3c49296.8.jpg image
-http://www.pornhub.com/ https://media.trafficjunky.net/delivery/js/abp/js1.js script
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/2f/e5/ae/2fe5ae8928576c4d189b32a54d2340e5/2fe5ae8928576c4d189b32a54d2340e5.23.jpg image
-http://www.xvideos.com/ http://img-l3.xvideos.com/videos/thumbs169ll/d1/73/2f/d1732f9e6ecf0631184faa35aa16f80e/d1732f9e6ecf0631184faa35aa16f80e.26.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/pics/logos/2972.png?cache=2018010401 image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/83/29/4a/83294adc85c5be51ab5f87cd0d1aa018/83294adc85c5be51ab5f87cd0d1aa018.22.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/96/37/7a/96377a735891fb3c1cae308b370d4397/96377a735891fb3c1cae308b370d4397.11.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201105/15/3087866/original/(m=eafTGgaaaa)(mh=eGOpECfEO_mPBY7N)12.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/f8/35/b6/f835b6061460b3f19637174a6970bbfb/f835b6061460b3f19637174a6970bbfb.3.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/2a/45/94/2a4594572da7afb72f2c9bfe9e403b14/2a4594572da7afb72f2c9bfe9e403b14.30.jpg image
-http://www.yahoo.co.jp/ http://www.yahoo.co.jp/ html
-http://www.xvideos.com/ http://images-llnw.xvideos-cdn.com/videos/thumbs169ll/3d/da/2c/3dda2c737ff6657342aec14c101033d1/3dda2c737ff6657342aec14c101033d1.10.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201207/03/5226235/original/(m=eafTGgaaaa)(mh=EYH7tKE06NdycZ7p)14.jpg image
-http://www.yahoo.co.jp/ https://www.yahoo.co.jp/ html
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/cf/85/ac/cf85ac89ac686d461c943c28f6744a69/cf85ac89ac686d461c943c28f6744a69.14.jpg image
-http://www.yahoo.co.jp/ https://m.yahoo.co.jp/ html
-http://www.xvideos.com/ http://images-llnw.xvideos-cdn.com/videos/thumbs169ll/f1/40/e6/f140e6a3fb5e2ee879571f63c48c2fa1/f140e6a3fb5e2ee879571f63c48c2fa1.5.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/mtop/5.3.4/styles/top.css css
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/33/36/90/3336906e2e4fd13fc019da01591afb3a/3336906e2e4fd13fc019da01591afb3a.30.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/02/fc/24/02fc24494e4fc8dfed2b336dbfb68bfb/02fc24494e4fc8dfed2b336dbfb68bfb.26.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/login/sp/js/login_promo/1.1.8/login_promo-min.js script
-http://www.xvideos.com/ http://img-l3.xvideos.com/videos/thumbs169ll/1b/e0/c2/1be0c27c12d55fd3464693e6c0cdddb1/1be0c27c12d55fd3464693e6c0cdddb1.14.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201703/08/108941442/original/(m=eafTGgaaaa)(mh=zU0jdG6bwAODDKTF)16.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/ds/ult/rapidjp-1.0.2.js script
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/07/f6/aa/07f6aa0a909c9df46c10c1607aa3c8a0/07f6aa0a909c9df46c10c1607aa3c8a0.7.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201412/29/36678021/original/(m=eafTGgaaaa)(mh=OABbnWJ5N11EZSMB)5.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/listing/tool/stream/rappie_stream-1.8.0.js script
-http://www.xvideos.com/ http://img-l3.xvideos.com/videos/thumbs169ll/30/7f/1c/307f1c483d2cdc479b5cadf7191cf9a9/307f1c483d2cdc479b5cadf7191cf9a9.5.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201708/18/129054271/original/(m=eafTGgaaaa)(mh=tykcLGHDVN3QUnHS)14.jpg image
-http://www.xvideos.com/ http://images-llnw.xvideos-cdn.com/videos/thumbs169ll/84/ec/e2/84ece2d061ba30858a041a87d77d32c0/84ece2d061ba30858a041a87d77d32c0.4.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/listing/tool/yads/yads-stream-lib.js?3 script
-http://www.pornhub.com/ https://cdn1d-static-shared.phncdn.com/jquery-2.0.3.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/listing/tool/yads/yads-stream-conf-top_smp.js?3 script
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/b6/94/d0/b694d0a1419ae916f448a3c68ef7c78f/b694d0a1419ae916f448a3c68ef7c78f.11.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/approach/jslib/deeplink-1.4.3.js script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/vmobile/sprite-flag-icons.png?cache=2018010401 image
-http://www.yahoo.co.jp/ https://yads.c.yimg.jp/js/yads-async.js script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/vmobile/sprite-ui.png?cache=2018010401 image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/transit80.png image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201711/20/141920112/original/(m=eafTGgaaaa)(mh=FciUSDquIDgTMnN-)10.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/mail80.png image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201712/03/143834662/original/(m=eafTGgaaaa)(mh=ZqzNNaHkgG5kGDPh)1.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/shopping80.png image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201708/30/130646651/original/(m=eafTGgaaaa)(mh=x3UrE37VGnjQt04L)0.jpg image
-http://www.xvideos.com/ http://img-hw.xvideos-cdn.com/videos/thumbs169ll/41/71/8d/41718d42298c8e017ce66d47722218fe/41718d42298c8e017ce66d47722218fe.24.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/weather80.png image
-http://www.pornhub.com/ https://bi.phncdn.com/videos/201712/12/145141492/original/(m=eafTGgaaaa)(mh=a3ZHL_U-TcRD23jR)6.jpg image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/df/25/9c/df259c8d427d05d7e9a4943066567b21/df259c8d427d05d7e9a4943066567b21.30.jpg image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/sports80.png image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/blank.gif image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/fortune80.png image
-http://www.xvideos.com/ http://img-egc.xvideos-cdn.com/videos/thumbs169ll/3b/da/90/3bda903aa5ce152425e5c222400d96fc/3bda903aa5ce152425e5c222400d96fc.7.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/vmobile/sprite-mobile_menu.png?cache=2018010401 image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/finance80.png image
-http://www.xvideos.com/ http://img-l3.xvideos.com/videos/thumbs169ll/10/bc/a6/10bca6ae7c667481419a68ba484dd3f2/10bca6ae7c667481419a68ba484dd3f2.3.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/sprite-pornhub-nf.png?cache=2018010401 image
-http://www.yahoo.co.jp/ https://s.yimg.jp/c/icon/s/bsc/2.0/gyao80.png image
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-feff45997a2/v3/js/skins/min/default.js script
-http://www.pornhub.com/ https://cdn1d-static-shared.phncdn.com/jquery/jquery.cookie-1.3.js?cache=2018010401 script
-http://www.xvideos.com/ http://static-hw.xvideos.com/v3/img/skins/default/xv-inline-loader.gif image
-http://www.yahoo.co.jp/ https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/01/15/1516012338_20180115-00002166-tokaiv-000-thumb-x104-y104.jpg image
-http://www.xvideos.com/ http://www.xvideos.com/favicon-32x32.png image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/head.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/01/15/1516012081_20180115-00000060-zdn_n-000-view-x104-y104.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vtablet/hammer.min.js?cache=2018010401 script
-http://www.xvideos.com/ http://static-hw.xvideos.com/v-feff45997a2/v3/js/jquery.js script
-http://www.yahoo.co.jp/ https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/01/15/1516001803_20180115-00000070-sph-000-view-x104-y104.jpg image
-http://www.pornhub.com/ https://ci.phncdn.com/videos/201801/06/148841162/original/(m=eafTGgaaaa)(mh=waK7nThhAkZsuisi)16.jpg image
-http://www.pornhub.com/ https://ci.phncdn.com/videos/201801/10/149402052/thumbs_20/(m=eafTGgaaaa)(mh=li_A9zAASGs9CkRm)15.jpg image
-http://www.xvideos.com/ http://www.xvideos.com/favicon-16x16.png image
-http://www.yahoo.co.jp/ https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/01/15/1516013486_20180115-00000025-jij-000-view-x104-y104.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/autocomplete-search.js?cache=2018010401 script
-http://www.xvideos.com/ http://rpc-php.trafficfactory.biz/json/footermobile-1///xvideos///content.json?v=0.16249166166598972 script
-http://www.yahoo.co.jp/ https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/2018/01/15/1516012039_20180115-00000043-jnn-000-thumb-x104-y104.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/phub.js?cache=2018010401 script
-http://www.xvideos.com/ http://media.trafficfactory.biz//banners/b1/f5/76/8149df4c6d6d8e7202a1038b38ca1156.gif image
-http://www.yahoo.co.jp/ https://giwiz-tpc.c.yimg.jp/q/iwiz-tpc/images/tpc/eternal/2017/11/7/1510038180_1439792390_1439792376_aflo_twia027472-x104-y104.jpg image
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/popunder-build.js?cache=2018010401 script
-http://www.pornhub.com/ https://www.google-analytics.com/analytics.js script
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/mtop/5.3.4/scripts/Main.bundle.js script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/application.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/mtop/5.3.4/fonts/icon.woff font
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/footer.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/listing/tool/yads/impl/yads-stream-lib.js?2018011501 script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/premium/premium-modals.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015990429&yhlClientVer=3.30.2&yhlRnd=aNRcU360auyxzqKKjcg4s0pp&yhlCompressed=0 text
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/premium/slider.js?cache=2018010401 script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/flipbook.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015990518&yhlClientVer=3.30.2&yhlRnd=OvVsWseetdL16eKZjcg4s0s5&yhlCompressed=0 text
-http://www.pornhub.com/ https://cdn1-smallimg.phncdn.com/n172nWs1UEcnquuObA5x52osw51230gH/rta-1.gif image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/listing/tool/yads/impl/yads-stream-conf-top_smp.js?2018011501 script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=EXxthZe0eYbtUrPpjcg4s2l9,0.22116003312289778&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04_ts%031516015992%04sec%034%04_E%03depicTime image
-http://www.pornhub.com/ https://ads.trafficjunky.net/ads_batch?format=json&clientType=mobile&data=%5B%7B%22spots%22%3A%5B%7B%22zone%22%3A981%2C%22site%22%3A23%7D%5D%7D%5D&cache=1516015861&channel%5Bsite%5D=pornhub script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015993160&yhlClientVer=3.30.2&yhlRnd=LF8DGAQZqKJabhTGjcg4s2tk&yhlCompressed=0 text
-http://www.pornhub.com/ https://ads.trafficjunky.net/ads_batch?format=json&clientType=mobile&data=%5B%7B%22spots%22%3A%5B%7B%22zone%22%3A985%2C%22site%22%3A23%7D%5D%7D%5D&cache=1516015861&channel%5Bsite%5D=pornhub script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015993174&yhlClientVer=3.30.2&yhlRnd=dg2gMHMWoSQBh9ocjcg4s2ty&yhlCompressed=0 text
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/premium/launch-banner.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015993180&yhlClientVer=3.30.2&yhlRnd=H7s7P4ZxOTrTeKJJjcg4s2u4&yhlCompressed=0 text
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/front-index.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015993208&yhlClientVer=3.30.2&yhlRnd=Re9A9sQ7G4yinUpKjcg4s2uw&yhlCompressed=0 text
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015993238&yhlClientVer=3.30.2&yhlRnd=Hpq0knyV1GNF5L3ijcg4s2vq&yhlCompressed=0 text
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/js/vmobile/promo-banner.js?cache=2018010401 script
-http://www.yahoo.co.jp/ https://s.yjtag.jp/tag.js script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/vmobile/main-sprite.png?cache=2018010401 image
-http://www.pornhub.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=288273758&t=pageview&_s=1&dl=https%3A%2F%2Fwww.pornhub.com%2F&ul=en-us&de=UTF-8&dt=Free%20Porn%20Videos%20%26%20Sex%20Movies%20-%20Porno%2C%20XXX%2C%20Porn%20Tube%20%7C%20Pornhub&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IGBAiAABB~&jid=349364025&gjid=1127884921&cid=952100290.1516015869&tid=UA-2623535-1&_gid=525464642.1516015869&z=2073549876 image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516015993257&yhlClientVer=3.30.2&yhlRnd=UD3DRK12YBCD8q50jcg4s2w9&yhlCompressed=0 text
-http://www.pornhub.com/ https://ads.trafficjunky.net/tj_pixel?id=001&data=%7B%22ad_ip%22%3A%22149.20.63.13%22%2C%22ad_user_agent%22%3A%22Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127%22%2C%22ad_uuid%22%3A%2290ddd6ac-7954-4f8f-bc31-0ce7ab5a16d7%22%2C%22ad_imp_id%22%3A%226_1516015868926872741_16783_5148%22%2C%22ad_request_zone_id%22%3A985%2C%22ad_final_zone_id%22%3A985%2C%22ad_campaign_id%22%3A1001724171%2C%22ad_id%22%3A1265919321%2C%22ad_aclid%22%3A%22_JBcWgAAAADZAwAACxm1O1lldEt6HAAA2QMAAAAAAAD_____AAAAAA%3D%3D%22%2C%22ad_isp%22%3A%22Internet%20Systems%20Consortium%2C%20Inc.%22%2C%22ad_country%22%3A%22us%22%2C%22ad_region%22%3A%22ca%22%2C%22ad_city%22%3A%22redwood%20city%22%2C%22ad_carrier%22%3A%22wifi%22%7D image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/login/sp/js/login_promo/1.0.3/login_promo_param-min.js?t=421115 script
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/approach/jslib/clear.gif?method=init&callback=mobiledeeplinkingcallback1516015993281 image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/login/sp/js/login_promo/1.0.5/login_promo_core-min.js?t=421115 script
-http://www.pornhub.com/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-2623535-1&cid=952100290.1516015869&jid=349364025&gjid=1127884921&_gid=525464642.1516015869&_u=IGBAiAABB~&z=1654002788 image
-http://www.yahoo.co.jp/ https://quriosity.yahoo.co.jp/v1/recommend/list?output=jsonp&cassette=stm_top&cat=sports&crumb=-100&start=1&results=20&lvt=0&crop=on&imgx=192&imgy=192&imgx2=718&imgy2=298&movie_imgx=296&movie_imgy=168&movie_imgx2=608&movie_imgy2=342&lgcode=&extra=on&vtestid=&callback=reqwest_1516015992699 script
-http://www.pornhub.com/ https://hw-cdn.trafficjunky.net/uploaded_content/creative/101/382/312/1/1013823121.gif image
-http://www.yahoo.co.jp/ https://quriosity.yahoo.co.jp/v1/recommend/list?output=jsonp&cassette=stm_top&cat=all&crumb=-100&start=1&results=20&lvt=0&crop=on&imgx=192&imgy=192&imgx2=718&imgy2=298&movie_imgx=296&movie_imgy=168&movie_imgx2=608&movie_imgy2=342&lgcode=&extra=off&vtestid=&autoplay=off&autoplayTotal=0&digest=on&digestResults=6&callback=reqwest_1516015992699 script
-http://www.pornhub.com/ https://hw-cdn.contentabc.com/ads/bb_300x250_739915/uploadMVideo.mpg video
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/login/sp/js/login_promo/1.0.4/login_promo_dom-min.js?d=201512 script
-http://www.pornhub.com/ https://hw-cdn.contentabc.com/ads/bb_300x250_739915/uploadMLogo.png image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/security/pf/pcore-1.0.1.min.js script
-http://www.pornhub.com/ https://bi.phncdn.com/www-static/images/touch-icon-iphone.png?cache=2018010401 image
-http://www.yahoo.co.jp/ https://s.yimg.jp/images/ksk/promo/top_peron/170816_02.png image
-http://www.pornhub.com/ https://hubt.pornhub.com/js/ht.js?site_id=3 script
-http://www.yahoo.co.jp/ https://yjtag.yahoo.co.jp/tag?site=GKNjDO2&H=2ve9sua script
-http://www.yahoo.co.jp/ https://ybx.yahoo.co.jp/clear.gif?bkey=loginpromo&mtype=pop&status=normal&action=view&src=www&spaceid=2080377422&ts=1516015994678 image
-http://www.pornhub.com/ https://hubt.pornhub.com/htcheck.html?site_id=3 html
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=P6duGwMKOemCduIpjcg4s4jp,0.11422388944326145&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031516015995%04scrnpos%03%231516015990.393%400%3A0~0%04_E%03scrnpos image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=GicZjHxQ8iaGhpFgjcg4s4ju,0.2152763427442963&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031516015995%04viewtime%03%2BheaderBody%3A1%231516015991.440%2BheaderBody%3A1~1516015993.441%2BheaderBody%3A2%231516015991.440%2BheaderBody%3A2~1516015993.441%2BheaderBody%3A3%231516015991.440%2BheaderBody%3A3~1516015993.441%2BheaderBody%3A4%231516015991.440%2BheaderBody%3A4~1516015993.441%2BLifetool%3A1%231516015991.440%2BLifetool%3A2%231516015991.440%04_E%03l_viewtime image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=GDM55z0TZbluPQMvjcg4s4jw,0.49868895824505244&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031516015995%04viewtime%03%2BLifetool%3A3%231516015991.440%2BLifetool%3A4%231516015991.440%2BLifetool%3A5%231516015991.440%2BLifetool%3A6%231516015991.440%2BLifetool%3A7%231516015991.440%2BLifetool%3A7~1516015993.441%2BLifetool%3A8%231516015991.440%2BLifetool%3A9%231516015991.440%2BLifetool%3A10%231516015991.440%2BLifetool%3A10~1516015993.441%2Bsearch%3A5%231516015991.440%04_E%03l_viewtime image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=GvBDyeEPIiK10W4xjcg4s4k0,0.9013187879904265&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031516015995%04viewtime%03%2BheaderBody%3A7%231516015993.452%2BheaderBody%3A8%231516015993.452%2BLifetool%3A11%231516015993.452%2BLifetool%3A12%231516015993.452%2BsideMenu%3A1%231516015993.452%2Bsearch%3A9%231516015993.452%2Bstream%3A111%231516015993.452%2Bstream%3A112%231516015993.452%2Bstream%3A113%231516015993.452%2Bstream%3A114%231516015993.452%2Bstream%3A115%231516015993.452%04_E%03l_viewtime image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=XnR2KbjgwwWpotk8jcg4s4k9,0.10182463413649123&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031516015995%04viewtime%03%2Bstream%3A116%231516015993.452%2Bstream%3A117%231516015993.452%2Bstream%3A118%231516015993.452%2Bstream%3A119%231516015993.452%04_E%03l_viewtime image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/p?s=2080377422&t=0QO3njNWXyCzPUBTjcg4s4jx,0.5334287585755801&_I=&_AO=0&_NOL=0&_R=&_P=3.30.2%05_pl%031%04A_v%033.30.2%04A_jpv%031.0.2%04_bt%03rapid%04A_pr%03https%04A_tzoff%03-8%04A_sid%03KLUjUYlhmNCDIqwrjcg4s0nx%04_w%03m.yahoo.co.jp%2F%04service%03toppage%04pagetype%03top%04vtgrpid%03portal%04device%03smartphone%04opttype%03smartphone%04os%03android%04status%03logout%04apptype%03web%04vtestid%03false%04rcpid%03tp_fynw%04wt%03off%04ft%03off%04fs%030%04v_pkjp%032%04dpr%033%04_do%030%04_sr%03360x512%04dspsize%03360x512%04k_thm%03%04w2a%03mbt%04conttype%03%04sw_aid%030%04_rpv%031.8.0%04tl_ct%030%04vst_flg%030%04lvd_ct%030%04w_freq%031%04w_login%030%04rclvt%030%04autoplay%03on%04pb%03off%04kb%03off%04_ts%031516015995%04viewtime%03%2Bsearch%3A5~1516015993.441%2Bstream%3A6%231516015991.440%2Bstream%3A6~1516015993.441%2Bstream%3A7%231516015991.440%2Bstream%3A7~1516015993.441%2Bstream%3A8%231516015991.440%2Bstream%3A8~1516015993.441%2Bstream%3A9%231516015991.440%2Bstream%3A9~1516015993.441%2BheaderBody%3A5%231516015993.452%2BheaderBody%3A6%231516015993.452%04_E%03l_viewtime image
-http://www.yahoo.co.jp/ https://m.yahoo.co.jp/favicon.ico image
-http://www.yahoo.co.jp/ https://b95.yahoo.co.jp/s?s=bt&csurl=https%3A%2F%2Fyjtag.yahoo.co.jp%2Fcs&tp=8FzrfRY&btt=0 html
-http://www.yahoo.co.jp/ https://yjtag.yahoo.co.jp/cs?btt=0&tp=8FzrfRY&uid=1EjaPLB7z0LEUSKo7gWLnBJs&uid2=&uid3=&uid4=&uid5= image
-http://www.yahoo.co.jp/ https://yj.p.adnxs.com/seg?add=4511230&t=2&redir=https%3A%2F%2Fyj.p.adnxs.com%2Fmapuid%3Fmember%3D3663%26user%3D html
-http://www.yahoo.co.jp/ https://pp.d2-apps.net/v1/redirect?p_id=yahoo&url=https%3A%2F%2Fyjtag.yahoo.co.jp%2Fcs%3ftp%3dGvIpabp%26btt%3d0 html
-http://www.yahoo.co.jp/ https://yj.p.adnxs.com/mapuid?member=3663&user= image
-http://www.yahoo.co.jp/ https://aw.dw.impact-ad.jp/c/u/?oid=207d81ffda0cc019&rdr=https%3A%2F%2Fyjtag.yahoo.co.jp%2Fcs%3Fbtt%3D0%26tp%3DkhADDtf%26uid%3D{AONEID} other
-http://www.yahoo.co.jp/ https://yjtag.yahoo.co.jp/cs?tp=GvIpabp&btt=0&uid=8ef2883dcb554d9257fa428094320db5 image
-http://www.yahoo.co.jp/ https://aw.dw.impact-ad.jp/c/ur/?oid=207d81ffda0cc019&rdr=https%3A%2F%2Fyjtag.yahoo.co.jp%2Fcs%3Fbtt%3D0%26tp%3DkhADDtf%26uid%3D{AONEID} other
-http://www.yahoo.co.jp/ https://yjtag.yahoo.co.jp/cs?btt=0&tp=khADDtf&uid=e160f13e-4616-43ca-9914-adf7f593e4b6 image
-http://www.yahoo.co.jp/ https://logql.yahoo.co.jp/v1/public/yql?yhlVer=2&yhlClient=rapid&yhlS=2080377422&yhlCT=2&yhlBTMS=1516016003063&yhlClientVer=3.30.2&yhlRnd=MSC2q3ERBrgSK9eAjcg4sagn&yhlCompressed=0 text
-http://www.ebay.com/ http://www.ebay.com/ other
-http://www.ebay.com/ https://m.ebay.com/?_mwBanner=1 html
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/klqr5wcxay4vplv0dqofevlawe5.css css
-http://www.ebay.com/ https://ir.ebaystatic.com/pictures/aw/pics/mobile/rwap/LView_placeholder.png image
-http://www.ebay.com/ https://i.ebayimg.com/00/s/NjYxWDE1MDA=/z/hucAAOSw5cNYPMZ-/$_62.JPG?set_id=8800005007 image
-http://www.ebay.com/ https://i.ebayimg.com/00/s/MTIwMFgxMjAw/z/w6QAAOSwKQ9aTUcJ/$_62.JPG?set_id=8800005007 image
-http://www.ebay.com/ https://i.ebayimg.com/00/s/MTAwMFg4ODc=/z/~ZIAAOSwpDdU8nzJ/$_62.JPG?set_id=880000500F image
-http://www.ebay.com/ https://i.ebayimg.com/00/s/MTYwMFgxNjAw/z/xZwAAOSwvTBZsxCc/$_62.JPG?set_id=880000500F image
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/35n5oaub1m5tdeg1jnz1xkrswmn.js script
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/41mvwryey24rjl04u0hopdeexy5.js script
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/u3mjvbupvy4y5jin3tmjts2liqd.js script
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/zmjs51wzhq35xmgdx25vcqgiaqn.js script
-http://www.ebay.com/ https://i.ebayimg.com/00/s/NTAwWDUwMA==/z/Px4AAOSw-ddZcoNW/$_62.JPG?set_id=8800005007 image
-http://www.ebay.com/ https://ir.ebaystatic.com/pictures/aw/mobile/mobileWeb/popular_categories/spr/us-w188x178-q50-v1.jpg image
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/bjsll44fvq5gzelpqzuhsn1mx22.png image
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/mhunzsi4yi3fvpe5seocmathp2l.png image
-http://www.ebay.com/ https://rover.ebay.com/roversync/?site=0&stg=1&mpt=1516015984852 image
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/ey02vizpqa4gpkf3jafc2nnv4en.png image
-http://www.ebay.com/ https://rover.ebay.com/roverimp/0/0/9?imp=2046301&trknvp=cp%3D2056088%26ghi%3D96&1516015988411 image
-http://www.ebay.com/ https://ir.ebaystatic.com/rs/v/odwzr2qysi3fpkvoqj35al3w2uk.ico image
-http://www.ebay.com/ https://www.ebay.com/rec/plmt/100582?callback=jQuery17032249508178313935_1516015987791&si=0&fmt=json&enc=UTF-8&guid=f9981a181600a86000e7c1e7fed09639&cguid=f9981a181600a86000e7c1e7fed09639&_=1516015989084 script
-http://www.ebay.com/ https://srv.main.ebayrtm.com/rtm?RtmCmd&a=json&g=f9981a181600a86000e7c1e7fed09639&uf=0&c=1H4sIAAAAAAAAADWMQWuDMBiG7%2F6KD3axY8bvS6JGSw5dC462gUItu%2Bxiq%2BtCUyNSYezXLzvs%2Brzv8zwZP8C2HYAyQFkJUaGE2jQJFhUicCQVjUIV%2Br7enDbX63M0khKaY5ajCpMUXFN4CNIkS8aR5YKR%2BCOojf%2BxzrVpxhDivR3m7yWshm7ytoOcIaMlGP%2FwUEMsF%2FA6W9el5rDlMhTKJA9sNY6uf%2B%2FPO%2FtIM1EwkUO8e2vM%2FgWcvfVQ95ebX8D6a%2FL3Ps1UiArkJVMUymfreji2n%2B1k%2F%2BVDc2xSUkhEjEokXkQjF1InFF1sp4l%2FzIhI0S%2BnwrVaFwEAAA%3D%3D&ord=1516015984890&p=20309:20050:20051:20052:20053:20054&e=USC:1&z=-1&bw=360&bh=512&enc=UTF-8&v=6&rnc=1&cg=f9982f431600ab14ac534fb7cfbb445d&_vrdm=1516015989142&cb=raptor.rtm.RtmManager.storeResponse other
-http://www.ebay.com/ https://secureinclude.ebaystatic.com/js/v/us/pulsar.js script
-http://www.ebay.com/ https://gha.ebay.com/nproxy/notification/v1/bullseye script
-http://www.ebay.com/ https://ocsrest.ebay.com/ocsrsapp/o2/inflow/inflowcomponent?callback=Inflow.cb&fromGH=true&input=%7B%22pageId%22%3A2056088%2C%22gbhEnabled%22%3Afalse%7D script
-http://www.ebay.com/ https://srv.main.ebayrtm.com/rtm?RtmCmd&a=json&g=f9981a181600a86000e7c1e7fed09639&uf=0&c=1H4sIAAAAAAAAADWMQWuDMBiG7%2F6KD3axY8bvS6JGSw5dC462gUItu%2Bxiq%2BtCUyNSYezXLzvs%2Brzv8zwZP8C2HYAyQFkJUaGE2jQJFhUicCQVjUIV%2Br7enDbX63M0khKaY5ajCpMUXFN4CNIkS8aR5YKR%2BCOojf%2BxzrVpxhDivR3m7yWshm7ytoOcIaMlGP%2FwUEMsF%2FA6W9el5rDlMhTKJA9sNY6uf%2B%2FPO%2FtIM1EwkUO8e2vM%2FgWcvfVQ95ebX8D6a%2FL3Ps1UiArkJVMUymfreji2n%2B1k%2F%2BVDc2xSUkhEjEokXkQjF1InFF1sp4l%2FzIhI0S%2BnwrVaFwEAAA%3D%3D&ord=1516015984890&p=20309:20050:20051:20052:20053:20054&e=USC:1&z=-1&bw=360&bh=512&enc=UTF-8&v=6&rnc=1&cg=f9982f431600ab14ac534fb7cfbb445d&_vrdm=1516015989142&cb=raptor.rtm.RtmManager.storeResponse&r=yes script
-http://www.ebay.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.ebay.com/ https://ir.ebaystatic.com/rtm/0/RTMS/Image/5938_100118_NFL-Football-SuperBowlPlayoffs-COUPON_mWeb_Standard_564x362.jpg image
-http://www.ebay.com/ https://srv.main.ebayrtm.com/rtm?RtmIt&ite=1&m=726487&pg=2056088&y=3FwEhNghfJGVQVyRpB1YsPQlQLFABAysHAAMrDlQCLFUHVSVWUlt6TQheLh4FVS1KAVZ94gBSfecEVSjuU1F%2F6lMEKKQEAg%3D%3D&uf=0&ord=1516015984890&ts=1516015991021 image
-http://www.ebay.com/ https://ir.ebaystatic.com/rtm/0/RTMS/Image/5815_010118_NYNY_HUB_TOPPmWebED_RW1_MWEB.jpg image
-http://www.ebay.com/ https://srv.main.ebayrtm.com/rtm?RtmIt&ite=1&m=726447&pg=2056088&y=3FwEhNghfJGVQVyRpB1YsPQlQLFABAysHAAMrDlQCLFUHVSVWUlt6TQheLh4FVS1KAVZ94gBSfecEVSjuU1F%2F6lMEKKQEAg%3D%3D&uf=0&ord=1516015984890&ts=1516015991021 image
-http://www.ebay.com/ https://adservice.google.com/adsid/integrator.js?domain=m.ebay.com script
-http://www.ebay.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.ebay.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=1322679750956949&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fif&adsid=NT&eid=21060361%2C21061149&sc=1&sfv=1-0-14&iu=%2F6245%2Febay.ebayus.homepage.cchp%2Fmweb&sz=300x250%7C320x50%7C320x100%7C336x280&fsf=1&scp=ap%3DScandal%26cat%3D%26cg%3Df9981a181600a86000e7c1e7fed09639%26us%3D13%26ot%3D1%26pr%3D20%26xp%3D20%26np%3D20%26u%3D88b795adc72141ada04da82cf6d4cd46%26et%3D%26ipp%3D0%26iccr%3D0&cookie_enabled=1&abxe=1&lmt=1516015993&dt=1516015993968&frm=20&biw=360&bih=512&oid=3&adx=30&ady=690&adk=3476036193&gut=v2&ifi=1&u_tz=-480&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=https%3A%2F%2Fm.ebay.com%2F%3F_mwBanner%3D1&dssz=11&icsg=0&std=0&vrg=172&vis=1&scr_x=0&scr_y=0&ga_vid=1268903468.1516015994&ga_sid=1516015994&ga_hid=1484070516 script
-http://www.ebay.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_172.js script
-http://www.ebay.com/ https://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.ebay.com/ https://tpc.googlesyndication.com/safeframe/1-0-14/js/ext.js script
-http://www.ebay.com/ https://ir.ebaystatic.com/cr/v/c1/jd-1239sec.js script
-http://www.ebay.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener.js script
-http://www.ebay.com/ https://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.ebay.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjssaFBLR-w19M-VjtqQuMs55pvQJISAScLEypemKj_r3oqic7W62RIpMN8xkKQ4QvnZyxeSuzSoWcvcGUclqvyXQXYtgkl7-UiQl8EYr5SV0sbmgR7QECLx0WDZJM9wTRCE4PEPWSd-LwSPNw5hCIz1hP06rvWXONLZ8pAEnMY2sRY2uKgqnWSserRNAxS9ohWUMGjuWhGChDQL0AebLciebSjpXzQvM-szZoilam9R8TrleRS1n-QRcUVwvIVUg0K5AS_QrbQ&sig=Cg0ArKJSzPLyZu1lK7f7EAE&urlfix=1&adurl= html
-http://www.ebay.com/ https://adserver-us.adtech.advertising.com/pubapi/3.0/10588.1/4277428/0/170/ADTECH;v=2;cmd=bid;cors=yes;kvrefd=ebay.com;alias=mHP_300;misc=690509368714393100;callback=cbalaol script
-http://www.ebay.com/ https://showads.pubmatic.com/AdServer/AdServerServlet?operId=102&pubId=31445&siteId=140985&adId=657330&kadwidth=300&kadheight=250&inIframe=1&sec=1&pageURL=https%3A%2F%2Fm.ebay.com%2F&rs=2&dctr=cat%3D&kltstamp=2018-1-15%203%3A33%3A15&screenResolution=360x512&timezone=-8&pmZoneId=&awt=1&ranreq=0.10444193387418599 script
-http://www.ebay.com/ https://as-sec.casalemedia.com/cygnus?v=7&fn=cbali&s=172191&r=%7B%22id%22%3A690509368714393100%2C%22site%22%3A%7B%22page%22%3A%22https%3A%2F%2Fm.ebay.com%2F%22%2C%22ref%22%3A%22%22%7D%2C%22imp%22%3A%5B%7B%22id%22%3A%221%22%2C%20%22banner%22%3A%7B%22w%22%3A300%2C%22h%22%3A250%2C%22topframe%22%3A1%7D%2C%22ext%22%3A%20%7B%22sid%22%3A%22172191%22%2C%22custom%22%3A%22f9981a181600a86000e7c1e7fed09639||88b795adc72141ada04da82cf6d4cd46%22%2C%22kv%22%3A%22cat:%22%2C%22siteID%22%3A172191%7D%7D%5D%7D script
-http://www.ebay.com/ https://secure.adnxs.com/jpt?callback=cbalan&callback_uid=690509368714393100&psa=0&id=9763980&referrer=https%3A%2F%2Fm.ebay.com%2F html
-http://www.ebay.com/ https://ebayus-d.openx.net/w/1.0/arj?tg=_blank&ju=https%3A%2F%2Fm.ebay.com%2F&jr=https%3A%2F%2Fm.ebay.com%2F&c.cat=&c.cg=&auid=538324657&ch=UTF-8&res=360x512x24&tz=480&aus=300x250&callback=cbalo&be=1&bc=hb_ebayus&cb=690509368714393100 other
-http://www.ebay.com/ https://fastlane.rubiconproject.com/a/api/fastlane.jsonp?enc=url&account_id=11440&site_id=66724&zone_id=314888&size_id=15&rp_callback=rp_onAdResponseLoaded&rp_secure=1&tk_user_key=f9981a181600a86000e7c1e7fed09639||88b795adc72141ada04da82cf6d4cd46&tg_i.usde=13&tg_i.umde=&tg_i.categories=&p_pos=btf&p_screen_res=360x512&rand=0.3414144022363288&rf=https%3A%2F%2Fm.ebay.com script
-http://www.ebay.com/ https://ebayus-d.openx.net/w/1.0/arj?cc=1&tg=_blank&ju=https%3A%2F%2Fm.ebay.com%2F&jr=https%3A%2F%2Fm.ebay.com%2F&c.cat=&c.cg=&auid=538324657&ch=UTF-8&res=360x512x24&tz=480&aus=300x250&callback=cbalo&be=1&bc=hb_ebayus&cb=690509368714393100 script
-http://www.google.ca/ http://www.google.ca/ html
-http://www.google.ca/ https://www.google.ca/?gws_rd=ssl html
-http://www.google.ca/ https://www.google.ca/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.ca/ https://www.google.ca/images/nav_logo242_hr.webp image
-http://www.apple.com/ http://www.apple.com/ other
-http://www.google.ca/ https://www.google.ca/gen_204?s=webaft&atyp=csi&ei=NZFcWuG3PM2ojwP5-6mICw&rt=wsrt.2082,aft.137,prt.137 html
-http://www.apple.com/ http://s2.symcb.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBS56bKHAoUD%2BOyl%2B0LhPg9JxyQm4gQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMCEH7hSm9v7%2FLTfz%2BtZU062rSiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.google.ca/ https://www.google.ca/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.ca/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.apple.com/ https://www.apple.com/ html
-http://www.google.ca/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/styles/ac-globalnav.built.css css
-http://www.apple.com/ https://www.apple.com/ac/localnav/3.0/styles/ac-localnav.built.css css
-http://www.google.ca/ https://www.google.ca/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.google.ca/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalfooter/3/en_US/styles/ac-globalfooter.built.css css
-http://www.google.ca/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.apple.com/ https://www.apple.com/ac/localeswitcher/1/styles/localeswitcher.built.css css
-http://www.apple.com/ https://www.apple.com/wss/fonts?families=SF+Pro,v1|SF+Pro+Icons,v1 css
-http://www.google.ca/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.apple.com/ https://www.apple.com/ac/ac-films/5.1.0/styles/modal.css css
-http://www.google.ca/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.ca/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.ca/ https://www.google.ca/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/scripts/ac-globalnav.built.js script
-http://www.google.ca/ https://www.google.ca/images/nav_logo242.png image
-http://www.apple.com/ https://www.apple.com/metrics/ac-analytics/2.2/scripts/ac-analytics.js script
-http://www.apple.com/ https://www.apple.com/ac/globalfooter/3/en_US/scripts/ac-globalfooter.built.js script
-http://www.google.ca/ https://www.google.ca/gen_204?atyp=csi&ei=NZFcWuG3PM2ojwP5-6mICw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.594,dcl.285,iml.594,ol.2419,prt.137,xjs.1634,xjsee.1634,xjses.1389,xjsls.147,wsrt.2082,cst.639,dnst.0,rqst.715,rspt.343,sslt.339,rqstt.1580,unt.940,cstt.940,dit.2367&zx=1516015928759 html
-http://www.apple.com/ https://www.apple.com/ac/localeswitcher/1/scripts/localeswitcher.built.js script
-http://www.google.ca/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.apple.com/ https://www.apple.com/ac/ac-films/5.1.0/scripts/autofilms.built.js script
-http://www.google.ca/ https://www.google.ca/images/branding/product/1x/gsa_android_144dp.png image
-http://www.apple.com/ https://images.apple.com/v/home/dn/built/scripts/head.built.js script
-http://www.google.ca/ https://adservice.google.ca/adsid/google/ui html
-http://www.apple.com/ https://images.apple.com/v/home/dn/built/styles/main.built.css css
-http://www.apple.com/ https://images.apple.com/v/home/dn/built/scripts/main.built.js script
-http://www.apple.com/ https://www.apple.com/wss/fonts/SF-Pro-Text/v1/sf-pro-text_regular.woff2 font
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/apple/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/bag/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/mac/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/ipad/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/iphone/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/support/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/search/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/watch/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/tv/image_small.svg image
-http://www.apple.com/ https://www.apple.com/ac/globalnav/3/en_US/images/globalnav/links/music/image_small.svg image
-http://www.apple.com/ https://www.apple.com/us/shop/bag/status?apikey=SFX9YPYY9PPXCU9KH script
-http://www.apple.com/ https://images.apple.com/ac/flags/1/images/us/32.png image
-http://www.apple.com/ https://www.apple.com/wss/fonts/SF-Pro-Display/v1/sf-pro-display_semibold.woff2 font
-http://www.apple.com/ https://www.apple.com/favicon.ico image
-http://www.apple.com/ https://images.apple.com/v/home/dn/images/heroes/mlk-takeover/mlk_small_2x.jpg image
-http://www.apple.com/ http://sr.symcd.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBR0JBRnBp%2F14Jg%2FXj4aa6BlKlQVdQQUAVmr5906C1mmZGPWzyAHV9WR52oCEAI1kyIO4cO7gCOaDqCOX%2BSiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.apple.com/ https://securemetrics.apple.com/b/ss/appleglobal,applehome,applestoreww,applestoreus/1/JS-1.8.0/s15601716398657?AQB=1&ndh=1&pf=1&t=15%2F0%2F2018%203%3A32%3A30%201%20480&fid=61D73B36DE20246C-3A906587541D4A46&ce=UTF-8&pageName=apple%20-%20index%2Ftab%20%28us%29&g=https%3A%2F%2Fwww.apple.com%2F&cc=USD&ch=www.us.homepage&server=new%20approach%20ac-analytics&h1=www.us.homepage&v3=aos%3A%20us&c4=D%3Dg&v4=D%3DpageName&c5=linux%20x86_64%202x&c9=android%206.0.1&v14=en-us&c19=aos%3A%20us%3A%20apple%20-%20index%2Ftab%20%28us%29&c20=aos%3A%20us&c25=direct%20entry&c48=1&c49=D%3Ds_vi&c50=homepage%3D1&v54=https%3A%2F%2Fwww.apple.com%2F&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 text
-http://www.apple.com/ https://securemetrics.apple.com/b/ss/appleglobal,applehome,applestoreww,applestoreus/1/JS-1.8.0/s15601716398657?AQB=1&pccr=true&vidn=2D2E48A8852E2B89-40002CD5E04E21F6&&ndh=1&pf=1&t=15%2F0%2F2018%203%3A32%3A30%201%20480&fid=61D73B36DE20246C-3A906587541D4A46&ce=UTF-8&pageName=apple%20-%20index%2Ftab%20%28us%29&g=https%3A%2F%2Fwww.apple.com%2F&cc=USD&ch=www.us.homepage&server=new%20approach%20ac-analytics&h1=www.us.homepage&v3=aos%3A%20us&c4=D%3Dg&v4=D%3DpageName&c5=linux%20x86_64%202x&c9=android%206.0.1&v14=en-us&c19=aos%3A%20us%3A%20apple%20-%20index%2Ftab%20%28us%29&c20=aos%3A%20us&c25=direct%20entry&c48=1&c49=D%3Ds_vi&c50=homepage%3D1&v54=https%3A%2F%2Fwww.apple.com%2F&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 image
-http://www.apple.com/ https://securemetrics.apple.com/b/ss/appleglobal,applehome,applestoreww,applestoreus/1/JS-1.8.0/s13013169423422?AQB=1&ndh=1&pf=1&t=15%2F0%2F2018%203%3A32%3A30%201%20480&fid=61D73B36DE20246C-3A906587541D4A46&ce=UTF-8&pageName=apple%20-%20index%2Ftab%20%28us%29&g=https%3A%2F%2Fwww.apple.com%2F&cc=USD&h1=www.us.homepage&v4=D%3DpageName&v14=en-us&c34=apple%20-%20index%2Ftab%20-%20hero-mlk-takeover%20-%20section%20engaged%20.1&c35=0.00&v54=https%3A%2F%2Fwww.apple.com%2F&pe=lnk_o&pev2=apple%20-%20index%2Ftab%20-%20hero-mlk-takeover%20-%20section%20engaged%20.1&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 image
-http://www.twitch.tv/ http://www.twitch.tv/ other
-http://www.twitch.tv/ https://www.twitch.tv/ other
-http://www.twitch.tv/ https://m.twitch.tv/?desktop-redirect=true html
-http://www.twitch.tv/ https://m.twitch.tv/static/javascript/bundle-index.e7fd7b8041c4d84ad16a.js script
-http://www.twitch.tv/ https://polyfill.twitchsvc.net/v2/polyfill.min.js?unknown=polyfill&features=fetch%2CSet%2CMap%2CObject.assign%2CURL%2CUserTiming%2CString.prototype.startsWith%2CArray.prototype.includes%2CString.prototype.includes%2CIntl.~locale.en&flags=gated script
-http://www.twitch.tv/ https://player.twitch.tv/js/embed/v1.js script
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/PLAYERUNKNOWN%27S%20BATTLEGROUNDS-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/League%20of%20Legends-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/IRL-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Hearthstone-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Fortnite-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Dota%202-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Dragon%20Ball%20FighterZ-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Overwatch-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Counter-Strike:%20Global%20Offensive-272x380.jpg image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/World%20of%20Warcraft-272x380.jpg image
-http://www.bing.com/ http://www.bing.com/ html
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Tabletop%20Simulator-272x380.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20serp%20Homepage$bgLogoBingTeal/ic/23b397af/f2e8bbe3.png image
-http://www.twitch.tv/ https://static-cdn.jtvnw.net/ttv-boxart/Escape%20From%20Tarkov-272x380.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$MobileHeaderSprite2x/ic/e445f98b/0759ba51.png image
-http://www.bing.com/ http://www.bing.com/fd/ls/l?IG=53AA41CF48644E0294F53CCD1CD6CA0C&CID=1E1EFC61D9EE6CC73031F719D8B16D13&Type=Event.CPT&DATA={%22pp%22:{%22S%22:%22L%22,%22FC%22:-1,%22BC%22:-1,%22SE%22:-1,%22TC%22:-1,%22H%22:-1,%22BP%22:403,%22CT%22:408,%22IL%22:2},%22ad%22:[-1,-1,360,512,360,512,1],%22net%22:%22undefined%22}&P=SERP&DA=CO4&MN=SERP other
-http://www.bing.com/ http://www.bing.com/fd/ls/lsp.aspx other
-http://www.twitch.tv/ https://video-edge-f41b3e.sjc01.hls.ttvnw.net/v1/playlist/Cho1qx1J7_aDIoML4BY9J2Fp7vlqgVxLfGYEig93PR2B8eJ4PoRHOTNi6xNN_gAo7ZQOyIO_UE17_ewa8mNj_9XfE3Znknn97vF2jcYuqR5dbVJP5U4HOGfbv3YcR3vh_zZ3F7UCAZ1jvdTLHHTdDfzwJd1ejCZ23Ajr8mKP8YbMtVdsMfmTmZtM8K95OnB5i8zHA2d76PHxoil-YMaPlzVzhFQ4Fl76uYevz4uNVagLmHpUjgFlmy4eHONQJm56O0ypHTlgKotErOKkKHy2hckvK4m3O4Uzi2o8o7U96a-CjAe0ivNF6Z-0xIGlsr97u3NOUsOvnQQs5QhFfnzl6KaaDDh6N-8x3FqvzoGjAaiEOd-WuPgbr-yskzSuiW-VeLwYyK7SqalymDO8qgPAK5PNf_vw05Mg9yBp0ru70K0HO6JZfTNV4OH8HKXuupZWNgOzgBoUHGwVW_muG6FBIGpzF.m3u8 other
-http://www.bing.com/ http://www.bing.com/fd/s/a/hp/bing.svg image
-http://www.bing.com/ http://www.bing.com/apple-touch-icon-144x144.png image
-http://www.bing.com/ http://www.bing.com/rms/BingCore.Bundle/cj,nj/aaf9fcac/3d93b506.js?bu=rms+answers+Shared+BingCore%24ClientInstV2%24DuplicateXlsDefaultConfig%2cBingCore%24ClientInstV2%24SharedLocalStorageConfigDefault%2cBingCore%24shared%2cBingCore%24env.override%2cEmpty%2cBingCore%24event.custom.fix%2cBingCore%24event.native%2cBingCore%24onHTML%2cBingCore%24dom%2cBingCore%24cookies%2cBingCore%24rmsajax%2cBingCore%24ClientInstV2%24LogUploadCapFeatureDisabled%2cBingCore%24ClientInstV2%24ClientInstConfigSeparateOfflineQueue%2cBingCore%24clientinst%2cBingCore%24replay%2cBingCore%24Animation%2cBingCore%24fadeAnimation%2cBingCore%24framework script
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Shared%20BingCore$Animation/cj,nj/c9ce19fd/92e3c570.js script
-http://www.twitch.tv/ https://api.twitch.tv/gql script
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Shared%20BingCore$fadeAnimation/cj,nj/8c497c38/f92a50a7.js script
-http://www.bing.com/ http://www.bing.com/rms/Framework/cj,nj/2db0047b/8df804ba.js?bu=rms+answers+BoxModel+config.instant%2cempty%2ccore%2ccore%24viewport%2ccore%24layout%2ccore%24metrics%2cmodules%24mutation%2cmodules%24error%2cmodules%24network%2cmodules%24cursor%2cmodules%24keyboard%2cempty%2cmodules%24bot script
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Identity%20Mobile$HamburgerMenu/cj,nj/47eedaa8/1bff6059.js script
-http://www.bing.com/ http://www.bing.com/notifications/render?bnptrigger=%7B%22PartnerId%22%3A%22HomePage%22%2C%22IID%22%3A%22SERP.2000%22%2C%22Attributes%22%3A%7B%22RawRequestURL%22%3A%22%2F%22%7D%7D&IG=53AA41CF48644E0294F53CCD1CD6CA0C&IID=SERP.2000 html
-http://www.bing.com/ http://www.bing.com/sa/simg/bing_p_rr_teal_min.ico image
-http://www.twitch.tv/ https://video-edge-f41b3e.sjc01.hls.ttvnw.net/v1/playlist/Cho1qx1J7_aDIoML4BY9J2Fp7vlqgVxLfGYEig93PR2B8eJ4PoRHOTNi6xNN_gAo7ZQOyIO_UE17_ewa8mNj_9XfE3Znknn97vF2jcYuqR5dbVJP5U4HOGfbv3YcR3vh_zZ3F7UCAZ1jvdTLHHTdDfzwJd1ejCZ23Ajr8mKP8YbMtVdsMfmTmZtM8K95OnB5i8zHA2d76PHxoil-YMaPlzVzhFQ4Fl76uYevz4uNVagLmHpUjgFlmy4eHONQJm56O0ypHTlgKotErOKkKHy2hckvK4m3O4Uzi2o8o7U96a-CjAe0ivNF6Z-0xIGlsr97u3NOUsOvnQQs5QhFfnzl6KaaDDh6N-8x3FqvzoGjAaiEOd-WuPgbr-yskzSuiW-VeLwYyK7SqalymDO8qgPAK5PNf_vw05Mg9yBp0ru70K0HO6JZfTNV4OH8HKXuupZWNgOzgBoUHGwVW_muG6FBIGpzF.m3u8 other
-http://www.twitch.tv/ https://twitch.tv/favicon.ico image
-http://www.bing.com/ http://www.bing.com/rms/AutoSug/cj,nj/0f23ffac/ff58bedf.js?bu=rms+answers+AutoSuggest+Service%2cWeb%24Utils%2cWeb%24EventRegisterer%2cWeb%24EventRegistration%2cEmpty%2cEmpty%2cEmpty%2cWeb%24WebCore%2cWeb%24DataProvider%2cEmpty%2cWeb%24Canvas%2cEmpty%2cWeb%24Layout%2cWeb%24SearchForm%2cEmpty%2cEmpty%2cWeb%24PrefixThrottling%2cEmpty%2cEmpty%2cWeb%24DeleteHistorySuggestionHandler%2cWeb%24Init script
-http://www.twitch.tv/ https://www.twitch.tv/favicon.ico image
-http://www.bing.com/ http://www.bing.com/ImageResolution.aspx?w=360&h=512&hash=fc0dfbe49849ab3d5099f60bcb228d44 html
-http://www.bing.com/ http://www.bing.com/fd/ls/lsp.aspx other
-http://www.bing.com/ http://www.bing.com/az/hprichbg/rb/MLKMemorial_EN-US8458096334_480x640.jpg image
-http://www.bing.com/ http://www.bing.com/hpmob?IG=53AA41CF48644E0294F53CCD1CD6CA0C&IID=SERP.5000 html
-http://www.bing.com/ http://www.bing.com/rms/MobileSiteBase/cc,nc/8d0342e9/e3492d89.css?bu=rms+serp+Mobile%24mobileSite_c%2cMobile%24mobilesiteandroidhigh css
-http://www.bing.com/ http://www.bing.com/fd/ls/lsp.aspx other
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20MultimediaFavorites%20Core$MMFaves/cj,nj/56b755ce/802fbfb7.js script
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20ImageFavorites/cj,nj/99fc20e9/f936b02d.js script
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Identity%20Mobile$MobileSnrWindowsLiveConnectBootstrap/cj,nj/da504a49/f805f359.js script
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_g-f2khEhZ-YqNUn9qL32xA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_pJkZWT0qkRpxTmMNC89p7w&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$OpalUpsellMicb/ic/1e2a04ea/89ab204a.png image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_NeHXvI6EjjrMrSXelR8YOQ&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/favorites/cfx html
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_5d-z_zO3qrEwfM8auXfH-w&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_f53zfjMBuOj40wfF0NbGaQ&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_EJu01ot8EWDZ-uO4PIDxZg&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_jgxg0miF7uFGu9U3eYnSog&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_D97aG0v3mduzIwuOUjstXA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_SMJ8Hh-SgA2k6olB0cT27Q&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_FmZAUTIjJ8vi3tXNWOPqDA&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://a4.bing.com/fd/ls/l?IG=53AA41CF48644E0294F53CCD1CD6CA0C&CID=1E1EFC61D9EE6CC73031F719D8B16D13&TYPE=Event.ClientInst&DATA=%5B%7B%22T%22%3A%22CI.Init%22%2C%22FID%22%3A%22CI%22%2C%22Name%22%3A%22Base%22%2C%22TS%22%3A1516015963981%7D%2C%7B%22T%22%3A%22CI.Show%22%2C%22FID%22%3A%22HpPortrait%22%2C%22Name%22%3A%22null%22%2C%22TS%22%3A1516015963982%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22WhatsApp%22%2C%22TS%22%3A1516015965807%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Facebook%22%2C%22TS%22%3A1516015965807%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Skype%22%2C%22TS%22%3A1516015965807%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22WhatsApp%22%2C%22TS%22%3A1516015965807%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Sms%22%2C%22TS%22%3A1516015965807%7D%5D other
-http://www.bing.com/ http://a4.bing.com/fd/ls/l?IG=53AA41CF48644E0294F53CCD1CD6CA0C&CID=1E1EFC61D9EE6CC73031F719D8B16D13&TYPE=Event.ClientInst&DATA=%5B%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Facebook%22%2C%22TS%22%3A1516015965807%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Twitter%22%2C%22TS%22%3A1516015965808%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Skype%22%2C%22TS%22%3A1516015965808%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22Email%22%2C%22TS%22%3A1516015965808%7D%2C%7B%22shareKey%22%3A%22%22%2C%22guid%22%3A%22dc9249a7-0fb7-4fb3-9c02-70bc75393dd9%22%2C%22stage%22%3A%22Visible%22%2C%22message%22%3A%22Social%20share%20is%20visible.%22%2C%22T%22%3A%22CI.SocialShare%22%2C%22FID%22%3A%22null%22%2C%22Name%22%3A%22GetUrl%22%2C%22TS%22%3A1516015965808%7D%2C%7B%22T%22%3A%22CI.Load%22%2C%22FID%22%3A%22HP%22%2C%22Name%22%3A%22HpmobAjaxLoad%22%2C%22TS%22%3A1516015965813%7D%5D other
-http://www.bing.com/ http://www.bing.com/fd/ls/lsp.aspx other
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_pIgWFqd6hdpysBmWS4soZQ&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/th?id=OPN.RTNews_fD5OGbf4OsldJP9Nx2kKQw&w=400&h=200&c=7&rs=2&qlt=80&cdv=1&pid=PopNow image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_Images/ic/ee308001/bff07120.png image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_Videos/ic/495b665f/14f67787.png image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_News/ic/d61dcdf7/e7066e3c.png image
-http://www.bing.com/ https://www.bing.com/images/favorites/manage?action=getStatus&sid=08FCBE42FB426AD93CF0B53AFA1D6B71 html
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$NearByCard$mscopes_Movies/ic/c8fd6b5d/bd5c0afb.png image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$sudoku/ic/0fc4e494/b41889c1.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$slidingtiles/ic/b44fce8e/f5f36af7.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$jigsaw/ic/da97cf8c/7988cc1c.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$2048/ic/3e32adef/2889f0f1.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$geographyquiz/ic/905a59b7/146ad29b.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$celebrityquiz/ic/86deb1b6/5ccac8d2.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$newsquiz/ic/84227801/31c1a571.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$rewardsquiz/ic/62e26c9c/4d15d5bc.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$crossword/ic/78b41b92/d4671a5c.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$homepagequiz/ic/0bea548b/d305a9ed.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Homepage%20Mobile$BingFun$TouchQuery$rubix/ic/da45e62f/201dd8a2.jpg image
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20Multimedia%20Favorites$FavoritesLog/cj,nj/aa1d9405/bf201099.js script
-http://www.bing.com/ http://www.bing.com/rms/rms%20answers%20MultimediaFavorites%20Manage$FavProperties/cj,nj/4077ab63/3489ceef.js script
-http://www.bing.com/ https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=11&ct=1516015965&rver=6.0.5286.0&wp=MBI&wreply=https:%2F%2fwww.bing.com%2Fsecure%2FPassport.aspx%3Fpopup%3D1&lc=1033&id=264960&checkda=1 html
-http://www.bing.com/ https://www.bing.com/secure/Passport.aspx?popup=1 html
-http://www.bing.com/ http://www.bing.com/Passport.aspx?popup=1 html
-http://www.office.com/ http://www.office.com/ other
-http://www.office.com/ https://www.office.com/ html
-http://www.office.com/ https://statics-uhf-wus.akamaized.net/west-european/shell/_scrf/css/themes=default.device=uplevel_web_pc/21-ecd6ef/6a-459940/9d-005998/14-a4dc48/e0-030d39/4b-120352/5a-621a2e?ver=2.0 css
-http://www.msn.com/ http://www.msn.com/ html
-http://www.msn.com/ https://www.msn.com/ html
-http://www.office.com/ https://wusofficehome.msocdn.com/s/d57a027c/Areas/Home/Content/js/build/bundles/unauth-vendor.js script
-http://www.office.com/ https://wusofficehome.msocdn.com/s/0af0171d/Areas/Home/Content/js/build/bundles/unauth.css css
-http://www.office.com/ https://wusofficehome.msocdn.com/s/45aa9c62/Areas/Home/Content/js/build/bundles/sharedfontstyles.css css
-http://www.office.com/ https://wusofficehome.msocdn.com/s/61c31bdf/Areas/Home/Content/js/build/bundles/unauth.js script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/en-us/homepage/_sc/css/f5956224-cf998423/direction=ltr.locales=en-us.themes=start.dpi=resolution1x/1f-382780-c946678f/86-6e06b2-d6318459/60-9a7c98-68ddb2ab/e7-b2ca17-961c2d27/cb-69cc24-46b61bfc/35-f90e47-2347cfa6/33-c0a7d2-f9d7be4e/e7-ae426e-dbc6220a/c9-17e318-5e17ba71/20-f12f3b-725d65b7/6a-9b3e3d-3c427d05/6a-71e029-5960eecb/56-a35c1c-813a2baa/93-53aad2-7394809d/78-bb3d98-a4b3038c/11-e6f5f3-9ea6310d/73-6747ff-c48ec8f9/a0-b1a857-4b5f58d3?ver=2.0.6583.10059&fdhead=muidflt56cf,muidflt298cf,muidflt315cf&csopd=20180110002809&csopdb=20180105223439 css
-http://www.office.com/ https://wusofficehome.msocdn.com/s/53ce9072/Areas/Home/Content/js/build/bundles/sharedscripts.js script
-http://www.msn.com/ https://s.aolcdn.com/ads/adswrappermsni.js script
-http://www.office.com/ https://statics-uhf-wus.akamaized.net/shell/_scrf/js/themes=default/a9-7a153c/75-5a6f00/2d-ec94e0/8a-743b47/ad-6e0df3/c0-ce5530/60-8edf46/f0-b41b18/d6-85d258/60-83556e/e5-8544d9/bf-391770/c9-7479f7/34-f17a8e/3b-c900a6/3f-cf48da/c2-fbaa77/55-ebcaeb/cd-c177a3/39-97641b/c2-55b6fb/c6-dff7f7/af-eb98d9/1f-f0db2b/7c-5650f2/c4-f116b7/8c-25ae9a/de-a04f90/26-493871/fc-fc1204/da-a2b29b?ver=2.0&iife=1 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuGOXI.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=2448&y=811 image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/sc/9b/e151e5.gif image
-http://www.office.com/ https://wusofficehome.msocdn.com/s/bd34d329/images/hero-still-image-mobile.jpg image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBiwNf.img?m=6&o=true&u=true&n=true&w=30&h=30 image
-http://www.office.com/ https://wusofficehome.msocdn.com/s/4fc774a3/images/google-play-badge.png image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/_h/975a7d20/webcore/externalscripts/jquery/jquery-2.1.1.min.js script
-http://www.office.com/ https://assets.onestore.ms/cdnfiles/external/uhf/long/9a49a7e9d8e881327e81b9eb43dabc01de70a9bb/images/microsoft-gray.png image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/en-us/homepage/_sc/js/f5956224-51e0d79d/direction=ltr.locales=en-us.themes=start.dpi=resolution1x/e3-dc80e8-b0156a25/dd-8b2942-814f2f4f/cf-bbda30-5599dabd/cc-ca9775-e76dbcc3/c6-facbe2-68ddb2ab/78-b1295e-cae48929/48-ec51b5-d1f8fb43/1e-4ceb3d-f9c98504/6c-3bdaf0-e5780970/f1-8dbec1-69add1ed/5b-f47379-68ddb2ab?ver=2.0.6583.10059&fdhead=muidflt56cf,muidflt298cf,muidflt315cf&csopd=20180110002809&csopdb=20180105223439 script
-http://www.office.com/ https://assets.onestore.ms/cdnfiles/external/mwf/long/v1/v1.30.0/fonts/MWFMDL2.woff font
-http://www.office.com/ https://mem.gfx.ms/meversion?partner=office&market=en-us script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/sc/b7/da0571.woff2 font
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/_h/57566d09/webcore/fonts/SegoeUI/WestEuropean/Segoe-UI.woff2 font
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA42Hq5.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuFVeD.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=271&y=154 image
-http://www.office.com/ https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/Bold/latest.woff2 font
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA38A54.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.office.com/ https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.woff2 font
-http://www.office.com/ https://mem.gfx.ms/me/MeControl/9.1.17346.1/en-US/meBoot.min.js script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuHv0U.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=657&y=97 image
-http://www.office.com/ https://web.vortex.data.microsoft.com/collect/v1/t.js?ver=%272.1%27&name=%27Ms.Webi.PageView%27&time=%272018-01-15T11%3A31%3A21.763Z%27&os=%27Android%27&appId=%27JS%3Awww.office.com-unauth%27&*baseType=%27Ms.Content.PageView%27&-ver=%271.0%27&-impressionGuid=%27bda3f4b4-45c1-453f-aec7-b9422b6fbd1a%27&-pageName=%27UnauthOhp%27&-uri=%27https%3A%2F%2Fwww.office.com%2F%27&-pageTags=%27%7B%22metaTags%22%3A%7B%22ver%22%3A%225%22%2C%22ms.lang%22%3A%22en%22%2C%22ms.loc%22%3A%22US%22%2C%22ms.ocpub.assetid%22%3A%22UnauthOhp%22%2C%22ms.env%22%3A%22prod%22%2C%22ms.sitever%22%3A%225%22%2C%22ms.flightid%22%3A%22firstruneduupdatedcf%7Cfirstruniwcf%7Cairforceone1%22%7D%7D%27&-behavior=0&-resHeight=512&-resWidth=360&-market=%27en-US%27&*cookieEnabled=true&*flashInstalled=false&*isJs=true&*title=%27Office%20365%20Login%20%7C%20Microsoft%20Office%27&*isLoggedIn=false&ext-javascript-ver=%271.1%27&ext-javascript-libVer=%274.1.0%27&ext-javascript-domain=%27www.office.com%27&ext-user-localId=%27t%3A300BB15CEA9560DD06B4BA24EB0261C8%27 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA9UODq.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.office.com/ https://browser.pipe.aria.microsoft.com/Collector/3.0/?qsp=true&content-type=application%2Fbond-compact-binary&client-id=NO_AUTH&sdk-version=ACT-Web-JS-2.8.1&x-apikey=ea6758984c4b43529f9929667d8d3198-c52d4a8b-47fe-4fdf-99b8-5f897ff4e33b-7365 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/hp-wus/sc/2b/a5ea21.ico image
-http://www.office.com/ https://mem.gfx.ms/me/MeControl/9.1.17346.1/en-US/meCore.min.js script
-http://www.office.com/ https://web.vortex.data.microsoft.com/collect/v1 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuI5z3.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=408&y=275 image
-http://www.office.com/ https://wusofficehome.msocdn.com/s/7047452e/Images/favicon_metro.ico image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuGlBx.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=1570&y=854 image
-http://www.office.com/ https://web.vortex.data.microsoft.com/collect/v1 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAfZ6og.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.office.com/ https://c1.microsoft.com/c.gif?DI=4050&did=1&t= image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuFUTO.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f image
-http://www.office.com/ https://c.bing.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=6FAEBBFC8CAF4A2098862DE30AF8DA00&RedC=c1.microsoft.com&MXFR=1EEE82BD06F06D8127A389C502F06BC3 image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBlfFAC.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.office.com/ https://c1.microsoft.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=6FAEBBFC8CAF4A2098862DE30AF8DA00&MUID=1C1C9F943F546548142694EC3B546332 image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBCAaUE.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuHhUh.img?h=75&w=100&m=6&q=60&u=t&o=t&l=f&x=2256&y=1256 image
-http://www.msn.com/ https://otf.msn.com/c.gif?evt=impr&js=1&rid=b0cfac6e7f1145728509bfc5729d4f39&cts=1516015878197&idx=1&clid=0A923B01671A654A21333079664564F2&rf=&cu=https%3A%2F%2Fwww.msn.com%2F&scr=360x512&bh=512&bw=360&dv.Title1=MSN.com+-+Hotmail%2C+Outlook%2C+Skype%2C+Bing%2C+Latest+News%2C+Photos+%26+Videos&viewType=size1column&di=340&mkt=en-us&pn=startpage&su=https%253A%252F%252Fwww.msn.com%252F&pid=startpage&cv.product=prime_mobile&flightid=muidflt56cf%2Cmuidflt298cf%2Cmuidflt315cf&activityId=b0cfac6e7f1145728509bfc5729d4f39&cvs=Browser&subcvs=homepage&pg.n=startpage&pg.t=hp&pg.p=prime_mobile&st.dpt=&st.sdpt=&cv.partner=&cv.publcat=&cv.author=&cv.entityId=&cv.entitySrc=&cv.parentId=&provid=&ar=0&d.dgk=tmx.mobile.webkit.android&d.imd=1&tmpl=EAggMo%3A0%3Binfopane%3A0%3Bcat%3A0%3BIP%3ACb%3BRV%3ACb%3BEP%3A0%3BCI%3A0&isStaticPage=False&pgIdx=&pgTot=&pp=False&pb=%7B%7D image
-http://www.msn.com/ https://pixel.advertising.com/ups/254/occ other
-http://www.msn.com/ https://cms.analytics.yahoo.com/cms?partner_id=MSFT html
-http://www.msn.com/ https://pixel.advertising.com/ups/254/occ?verify=true other
-http://www.msn.com/ https://contextual.media.net/dmedianet.js?geo=en-us&property=homepage&device=mobile&https=1 script
-http://www.msn.com/ https://g.bing.com/uac/request?size=320x50;noperf=1;adclntid=1002;alias=MMSNUSEN12;kvmsft_providerid=7hd66fc;kvmsft_rid=b0cfac6e7f1145728509bfc5729d4f39;kvmsft_ext_inv_cd=us;kvmsft_muid=0a923b01671a654a21333079664564f2;kvmsft_pagetype=homepage;kvpg=%2Fmsn;kvugc=0;kvmn=MMSNUSEN12;kvgrp=15875715;kvismob=1;extmirroring=0;kvtile=1;target=_blank;aduho=-480;grp=15875715 other
-http://www.msn.com/ https://c.bing.com/c.gif?Red3=MSNLI_pd&rid=b0cfac6e-7f11-4572-8509-bfc5729d4f39&lng=en-us&dgk=tmx.mobile.webkit.android&imd=1&pn=startpage&rf=&tp=https%3A%2F%2Fwww.msn.com%2F image
-http://www.msn.com/ https://c.bing.com/c.gif?Red3=DataXMS_pd&IXID=E0 image
-http://www.msn.com/ https://sb.scorecardresearch.com/b?c1=2&c2=3000001&rn=1516015878195&c7=https%3A%2F%2Fwww.msn.com%2F&c8=MSN.com+-+Hotmail%2C+Outlook%2C+Skype%2C+Bing%2C+Latest+News%2C+Photos+%26+Videos&c9= other
-http://www.msn.com/ https://a248.e.akamai.net/chartbeat.download.akamai.com/102508/js/chartbeat.js script
-http://www.msn.com/ https://at.atwola.com/addyn/3.0/5113.1/221794/0/-1/size=320x50;noperf=1;adclntid=1002;alias=MMSNUSEN12;kvmsft_providerid=7hd66fc;kvmsft_rid=b0cfac6e7f1145728509bfc5729d4f39;kvmsft_ext_inv_cd=us;kvmsft_muid=0a923b01671a654a21333079664564f2;kvmsft_pagetype=homepage;kvpg=%2Fmsn;kvugc=0;kvmn=MMSNUSEN12;kvgrp=15875715;kvismob=1;extmirroring=0;kvtile=1;target=_blank;aduho=-480;grp=15875715 other
-http://www.msn.com/ https://at.atwola.com/bind?ckey1=ATTACID;cvalue1=kvtid=UP9aaf9813-f9e7-11e7-a7e1-02b98bd66ab6;cbase64enc1=1;ckey2=APID;cvalue2=UP9aaf9813-f9e7-11e7-a7e1-02b98bd66ab6;apidSync=1;expiresDays=366 other
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.msn.com/ https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=13&checkda=1&ct=1516015873&rver=6.7.6643.0&wp=lbi&wreply=https%3a%2f%2fwww.msn.com%2fen-us%2fhomepage%2fsecure%2fsilentpassport%3fsecure%3dtrue&lc=1033&id=1184&mkt=en-us html
-http://www.msn.com/ https://c.msn.com/c.gif?udc=true&rid=b0cfac6e7f1145728509bfc5729d4f39&rnd=636516126739172190&rf=&tp=https%253A%252F%252Fwww.msn.com%252F&di=340&lng=en-us&cv.product=prime_mobile&pn=startpage&activityId=b0cfac6e7f1145728509bfc5729d4f39&d.dgk=tmx.mobile.webkit.android&d.imd=1&st.dpt=&st.sdpt=&subcvs=homepage&pg.n=startpage image
-http://www.msn.com/ https://www.bizographics.com/collect/?fmt=gif&pid=7850 other
-http://www.msn.com/ https://sb.scorecardresearch.com/b2?c1=2&c2=3000001&rn=1516015878195&c7=https%3A%2F%2Fwww.msn.com%2F&c8=MSN.com+-+Hotmail%2C+Outlook%2C+Skype%2C+Bing%2C+Latest+News%2C+Photos+%26+Videos&c9= other
-http://www.msn.com/ https://cdn.taboola.com/libtrc/msn-home-network/loader.js script
-http://www.msn.com/ https://contextual.media.net/rtbspub?&prid=7PRFT79UO&cid=8CUNL3XVM&crid=903352736&size=300x250&rp=2.5&vi=1516015879536653757&ugd=3&requrl=https%3A%2F%2Fwww.msn.com%2F&useAppData=0&hlt=1&tr=0.8053354917224145 script
-http://www.msn.com/ https://ib.adnxs.com/async_usersync_file html
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.msn.com/ https://www.msn.com/en-us/homepage/secure/silentpassport?secure=true&lc=1033 html
-http://www.msn.com/ https://c.bing.com/c.gif?udc=true&rid=b0cfac6e7f1145728509bfc5729d4f39&rnd=636516126739172190&rf=&tp=https%253A%252F%252Fwww.msn.com%252F&di=340&lng=en-us&cv.product=prime_mobile&pn=startpage&activityId=b0cfac6e7f1145728509bfc5729d4f39&d.dgk=tmx.mobile.webkit.android&d.imd=1&st.dpt=&st.sdpt=&subcvs=homepage&pg.n=startpage&ctsa=mr&CtsSyncId=F1EAD194011C40F3B41F21E7FC0F59C3&RedC=c.msn.com&MXFR=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://contextual.media.net/fcmdynet.js?&cid=8CUNL3XVM&cpcd=NaEyhZu73BMxXJoVzER-IQ%3D%3D&crid=903352736&size=300x250&cc=US&sc=CA&https=1&vif=1&requrl=https%3A%2F%2Fwww.msn.com%2F&vi=1516015879536653757&lw=1&ugd=3&chnm3=startPage&re=1&dma=807&msa=2&rtbs=1&nb=1 script
-http://www.msn.com/ https://contextual.media.net/px.gif?ch=1&rn=1 image
-http://www.msn.com/ https://g.bing.com/uac/response?size=320x50;noperf=1;adclntid=1002;alias=MMSNUSEN12;kvmsft_providerid=7hd66fc;kvmsft_rid=b0cfac6e7f1145728509bfc5729d4f39;kvmsft_ext_inv_cd=us;kvmsft_muid=0a923b01671a654a21333079664564f2;kvmsft_pagetype=homepage;kvpg=%2Fmsn;kvugc=0;kvmn=MMSNUSEN12;kvgrp=15875715;kvismob=1;extmirroring=0;kvtile=1;target=_blank;aduho=-480;grp=15875715 other
-http://www.msn.com/ https://c.msn.com/c.gif?udc=true&rid=b0cfac6e7f1145728509bfc5729d4f39&rnd=636516126739172190&rf=&tp=https%253A%252F%252Fwww.msn.com%252F&di=340&lng=en-us&cv.product=prime_mobile&pn=startpage&activityId=b0cfac6e7f1145728509bfc5729d4f39&d.dgk=tmx.mobile.webkit.android&d.imd=1&st.dpt=&st.sdpt=&subcvs=homepage&pg.n=startpage&ctsa=mr&CtsSyncId=F1EAD194011C40F3B41F21E7FC0F59C3&MUID=3CDAE09C536D653B3E41EBE4576D6622 image
-http://www.msn.com/ https://contextual.media.net/kbb.php?cme=KkKUG6JLaWptcd7ygVoZgW_gowIx32vSl5tlbUoHIlTwG_Hajq4qm8TPaunw8hu-gs5H0j_cu9dNg1SpNWSXZk_dUMBskfm26tBhbg8dZUZVZ7w2Pa9YygRYhZthVtj3%7C%7CNDHRnZ9Gz3KXlI-i9OnZqQ%3D%3D%7C5gDUJdTGiJzedmq9hanWYg%3D%3D%7CfTACDBAb70YAH7VJEs6iY7FiuYJwPXfy%7CN7fu2vKt8_s%3D%7CYdjFvixrVaHKWoanJxQ7pIbs71hugNrT_zzfTnjrTk2DZtMcbrd3gqo-5BoyMDWX%7CsRBSg3CPSiQ%3D%7C&srp=ypQJNGNB4UQ6DlVQ7Bw1-yJ_PHenCDJ5hiwjLtoBusHrPnHEjjW3DqLgt_hUNjPQ&klp=_9rucIc7-IFVjfDerCW7u4SeKTYbt5rFvjoC_E_SRB5jW8NR70bTa3nl387FuMSK_WOncvVtd4zR3bIyq-YXN-ARPAM0CHUZmLM0OPUSPdOrafyoFwyQJJJiuoUYp9f5BBXScD_NSwk5gpZNARS0h66oRqWo99q5Zqr8EWcedfjoFrTG9G6D8xi2O3iFAFQNyg1BAT82eOzUBMksPcprKddgKiPjMPQl73w24vXoEjYkspuzfeNOPIClHjCuln-U&cb=resultPageUtil.kwdRandmzn[%271516015879536653757%27] script
-http://www.msn.com/ https://contextual.media.net/__media__/js/util/nrr.js?v=67 script
-http://www.msn.com/ https://cdn.at.atwola.com/_media/uac/msn.html html
-http://www.msn.com/ https://contextual.media.net/mediamain.html?&cid=8CUNL3XVM&cpcd=NaEyhZu73BMxXJoVzER-IQ%3D%3D&crid=903352736&pid=8PO383B67&size=300x250&cpnet=yVb1sHm-0KKoFeunLBVJxQIq7tQvdLolbpWYR-zZN9c%3D&cme=KkKUG6JLaWptcd7ygVoZgW_gowIx32vSl5tlbUoHIlTwG_Hajq4qm8TPaunw8hu-gs5H0j_cu9dNg1SpNWSXZk_dUMBskfm26tBhbg8dZUZVZ7w2Pa9YygRYhZthVtj3%7C%7CNDHRnZ9Gz3KXlI-i9OnZqQ%3D%3D%7C5gDUJdTGiJzedmq9hanWYg%3D%3D%7CfTACDBAb70YAH7VJEs6iY7FiuYJwPXfy%7CN7fu2vKt8_s%3D%7CYdjFvixrVaHKWoanJxQ7pIbs71hugNrT_zzfTnjrTk2DZtMcbrd3gqo-5BoyMDWX%7CsRBSg3CPSiQ%3D%7C&https=1&cc=US&bf=0&staticIframe=1&vif=1&vi=1516015879536653757&lw=1&ugd=3&ib=0&nb=1 script
-http://www.msn.com/ https://otf.msn.com/c.gif?rid=b0cfac6e7f1145728509bfc5729d4f39&cts=1516015880769&idx=4&clid=0A923B01671A654A21333079664564F2&di=340&mkt=en-us&pn=startpage&su=https%253A%252F%252Fwww.msn.com%252F&pid=startpage&cv.product=prime_mobile&flightid=muidflt56cf%2Cmuidflt298cf%2Cmuidflt315cf&activityId=b0cfac6e7f1145728509bfc5729d4f39&cvs=Browser&subcvs=homepage&pg.n=startpage&pg.t=hp&pg.p=prime_mobile&evt=adimpr_update&dst=5802&den=5899&id=banner1_homepag_0&pg=MMSNUSEN12&w=320&h=50&status=success&sdk=aol&fen=8737 image
-http://www.msn.com/ https://an.facebook.com/v2/placementbid.json?sdk=5.5.web&placementids[]=123410111540958_149188285629807&adformats[]=300x250&pageurl=https%3A%2F%2Fwww.msn.com%2F script
-http://www.msn.com/ https://cdn.taboola.com/libtrc/impl.thin.290-5-RELEASE.js script
-http://www.msn.com/ https://sb.scorecardresearch.com/beacon.js script
-http://www.msn.com/ https://c.bing.com/c.gif?aol_uid=noapid&uac_muid=0a923b01671a654a21333079664564f2&cd=us&pg=/msn&Red3=MSAOL_pd image
-http://www.msn.com/ https://s.mnet-ad.net/px.gif?ch=2&rn=1 image
-http://www.msn.com/ https://sb.scorecardresearch.com/b?c1=7&c2=13739933&c3=20121515121&ns__t=1516015881278&ns_c=UTF-8&cv=3.1m&c8=MSN.com%20-%20Hotmail%2C%20Outlook%2C%20Skype%2C%20Bing%2C%20Latest%20News%2C%20Photos%20%26%20Videos&c7=https%3A%2F%2Fwww.msn.com%2F&c9= other
-http://www.msn.com/ https://us-west-2.dc.ads.linkedin.com/collect/?pid=7850&fmt=gif&ck= other
-http://www.msn.com/ https://pixel.advertising.com/ups/136/sync?uid=%2C3CDAE09C536D653B3E41EBE4576D6622&_origin=1 other
-http://www.msn.com/ https://ping.chartbeat.net/ping?h=en-us.msn.com&p=%2Fen-us&u=BGgwMrB-CKXMDeiM6d&d=msn.com&g=42635&g0=homepage&n=1&f=00001&c=0&x=0&m=0&y=7271&o=360&w=512&j=45&R=1&W=0&I=0&E=0&e=0&r=&b=5644&t=CV6CUdDU3mfniBPz3CkI_UfCmbiFO&V=97&i=MSN.com%20-%20Hotmail%2C%20Outlook%2C%20Skype%2C%20Bing%2C%20Latest%20News%2C%20Photos%20%26%20Videos&tz=480&_cdname=westus&sn=1&EE=0&sv=tllMlDhbu1XqdMfVoKXEr2wGSO&_ image
-http://www.msn.com/ https://trc.taboola.com/msn-msn-home/trc/3/json?tim=03%3A31%3A21.881&data=%7B%22id%22%3A236%2C%22ii%22%3A%22_homepage_%22%2C%22it%22%3A%22home%22%2C%22sd%22%3Anull%2C%22ui%22%3Anull%2C%22uifp%22%3Anull%2C%22vi%22%3A1516015881871%2C%22cv%22%3A%22290-5-RELEASE%22%2C%22uiv%22%3A%22default%22%2C%22u%22%3A%22https%3A%2F%2Fwww.msn.com%2F%22%2C%22did%22%3A%220A923B01671A654A21333079664564F2%22%2C%22extpvid%22%3A%22b0cfac6e7f1145728509bfc5729d4f39%22%2C%22bv%22%3A%220%22%2C%22nsid%22%3A%22msn-home-network%22%2C%22r%22%3A%5B%7B%22li%22%3A%22rbox-h2m%22%2C%22s%22%3A4%2C%22uim%22%3A%22thumbnails-2x1%3Apub%3Dmsn-home-network%3Aabp%3D0%22%2C%22uip%22%3A%22Mid%20Infopane%20Thumbnails%20-%20Mobile%22%2C%22orig_uip%22%3A%22Mid%20Infopane%20Thumbnails%22%7D%2C%7B%22li%22%3A%22rbox-h2m%22%2C%22s%22%3A4%2C%22uim%22%3A%22thumbnails-2x1%3Apub%3Dmsn-home-network%3Aabp%3D0%22%2C%22uip%22%3A%22Mid%20Infopane%20Thumbnails%202nd%20-%20Mobile%22%2C%22orig_uip%22%3A%22Mid%20Infopane%20Thumbnails%202nd%22%7D%5D%2C%22cb%22%3A%22TRC.callbacks.recommendations_1%22%2C%22lt%22%3A%22normal%22%7D script
-http://www.msn.com/ https://secure.adnxs.com/getuid?https%3A%2F%2Fwww.linkedin.com%2Fcsp%2Fdtag%3Fp%3D9%26_x%3D%252526opid%25253D7850%252526fmt%25253Dgif%252526ck%25253D%2525263pc%25253Dtrue%252526an_user_id%25253D%24UID image
-http://www.msn.com/ https://ib.adnxs.com/getuid?https://trc.taboola.com/sg/appnexus-network/1/rtb-h/?taboola_hm=$UID image
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuGOW7.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=1360&y=778 image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BB6Dp75.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuGXN2.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=773&y=493 image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BB1uPMT.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.msn.com/ https://pixel.tapad.com/idsync/ex/receive?partner_id=2227&partner_device_id=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://cm.g.doubleclick.net/pixel?google_nid=taboola_dbm&google_cm&google_sc html
-http://www.msn.com/ https://pixel.tapad.com/idsync/ex/receive/check?partner_id=2227&partner_device_id=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://idsync.rlcdn.com/382399.gif?partner_uid=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://su.addthis.com/red/usync?pid=11204&puid=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://cm.g.doubleclick.net/pixel?google_nid=taboola_dbm&google_cm=&google_sc=&google_tc= html
-http://www.msn.com/ https://global.ib-ibi.com/image.sbxx?go=307361&pid=607&xid=0A923B01671A654A21333079664564F2 html
-http://www.msn.com/ https://ml314.com/utsync.ashx?eid=50077&et=0&fp=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://p.adsymptotic.com/d/px/?_pid=15138&_psign=e953c926b5a61d23218ec152eda756db&_puuid=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=054f32o&ttd_tpi=1 html
-http://www.msn.com/ https://idsync.rlcdn.com/382399.gif?partner_uid=0A923B01671A654A21333079664564F2&redirect=1 image
-http://www.msn.com/ https://www.storygize.net/ccm/4b560cdd-91f9-422b-adb7-e9dff26bc3ad?u=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://trc.taboola.com/sg/google-network/1/rtb-h/?taboola_hm=CAESEOTBqyWOMGkKVQKo3-2gEg0&google_cver=1 other
-http://www.msn.com/ https://soda.startappservice.com/soda/1.0/sendEvent?partnerId=162905987&internalUserId=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252C html
-http://www.msn.com/ https://p.adsymptotic.com/d/px/?_pid=15138&_psign=e953c926b5a61d23218ec152eda756db&_puuid=0A923B01671A654A21333079664564F2&_expected_cookie=f86fcd45f1fe5390281216d53810b74b image
-http://www.msn.com/ https://match.adsrvr.org/track/cmb/generic?ttd_pid=054f32o&ttd_tpi=1 html
-http://www.msn.com/ https://trc.taboola.com/sg/storygize-network/1/rtb-h?taboola_hm=41e728ea-c2f1-40cd-8bfe-ed7618843387 other
-http://www.msn.com/ https://match.adsrvr.org/track/cmb/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252C html
-http://www.msn.com/ https://trc.taboola.com/sg/thetradedesk-network/1/rtb-h/?taboola_hm=66ddc1a0-333d-4961-bae2-b1cab76f055c other
-http://www.msn.com/ https://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=8a8541a4-973c-4648-ba54-eb9614bb0e0a&ttd_puid=%2C image
-http://www.msn.com/ https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_180%2Cw_320%2Cc_fill%2Cg_faces:auto%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/bdb9cfcd32977c4617de7896cec75de6.jpg image
-http://www.msn.com/ https://tags.bluekai.com/site/35702?id=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/cfa68fe2de4f00bb01b274b4c425197a.png image
-http://www.msn.com/ https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/https%3A//content-creative.s3.amazonaws.com/7a32001f-92da-4ab0-a933-bd13c57c1c86.png image
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=145&cm=0A923B01671A654A21333079664564F2 script
-http://www.msn.com/ https://ib.mookie1.com/image.sbxx?go=307361&pid=607&xid=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_180%2Cw_320%2Cc_fill%2Cg_faces:auto%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/dc87158dcba83f4680db642229522176.jpg image
-http://www.msn.com/ https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/aa163b12e09ce7e1eb0d88bd03574a9a.jpg image
-http://www.msn.com/ https://dpm.demdex.net/ibs:dpid=477&dpuuid=81fa7bf172da735ac43d35ca433b3feb7373b187bc42179330191d6b06fa1db5b0da87c991749652&redir=https%3A%2F%2Fidsync.rlcdn.com%2F362248.gif%3Fpartner_uid%3D%24%7BDD_UUID%7D other
-http://www.msn.com/ https://aa.agkn.com/adscores/g.pixel?sid=9212237748&puid=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://images.taboola.com/taboola/image/fetch/f_jpg%2Cq_auto%2Ch_167%2Cw_312%2Cc_fill%2Cg_faces%2Ce_sharpen/http%3A//cdn.taboola.com/libtrc/static/thumbnails/2cf1285c436509c2122e5ee9040ef6b8.jpg image
-http://www.msn.com/ https://trc.taboola.com/msn-msn-home/log/3/available?ri=97ee1d75fb36b3415434ac98fcf1568c&sd=v2_6ea838e6b01a803c368bb3c0bce55280_0A923B01671A654A21333079664564F2_1516015883_1516015883_CIi3jgYQy9c-GI-d2syPLCABKAUw4QE&ui=0A923B01671A654A21333079664564F2&pi=/&wi=1914632520524480793&pt=home&vi=1516015881871&li=rbox-h2m&utm=16%2C873%2C991%2C2555&mgo=1&df=1&tim=03%3A31%3A23.893&id=3044&llvl=1&cv=290-5-RELEASE&fil=%5B%7B%22tii%22%3A%22%7E%7EV1%7E%7E-4876977387296268586%7E%7E2NzWbo6UkHOgpEAOsBqrbjdZ1qF2FOomqPUNO8g6q-wSO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT5dYIwm9x5LE1ZLaf5R3jrmsEbsEDg0md9z_0nbm-g8kTWwldecz1pH8KNZnBMsbNfnP_o9GtEjIB9cWY9joDL4pr43AfzWL_nA_cXmQwbOHEq-sZYY4El1TymFEcX4lFQ3cRbO5PunaC7zzRTf6GpU%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E3796694735490080540%7E%7ERJ0FLYzTZE0DLBMWM6inPhAGvpxTZevb5BJBBfahRE0SO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT6v3u32iWirHrqPEmiXknc-sEbsEDg0md9z_0nbm-g8kTWwldecz1pH8KNZnBMsbNX5nRgDryzUeGAoziSO8IiO3bj8kyqopi6drm28hYQPMJFc85Ur12wiBkZ_uArmCkSgKfKBKTDV4GuL_cqsUU7mppiNe8sxzhaMvePZzFf7A%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E6311808433225450765%7E%7E83uCMu2tbfZPLDr8ykwOL_a3MrgITTZeEfhW3S3Dc8sSO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgTxrtRA_RAKuL_kvJlVjzXiGsEbsEDg0md9z_0nbm-g8kTWwldecz1pH8KNZnBMsbNX5nRgDryzUeGAoziSO8IiMZZ3mBBlnETgE-4zslt_7_hLljQEaoD7uLZl0dundlS87wlfSjlpnURVcGyHh6R14%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%5D& image
-http://www.msn.com/ https://pxl.connexity.net/c/cse?a=R&A=22c&D=569a&V=9&I0k=ptnrid&I0v=0A923B01671A654A21333079664564F2 image
-http://www.msn.com/ https://match.taboola.com/sg/thetradedesk-network/1/rtb-h?taboola_hm=66ddc1a0-333d-4961-bae2-b1cab76f055c&tbid=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://dpm.demdex.net/ibs:dpid=79908&dpuuid=WlyRDqG4ziWB8XnR-setyEdM&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D124%26cm%3D%24%7BDD_UUID%7D other
-http://www.msn.com/ https://trc.taboola.com/msn-msn-home/log/3/available?ri=1f43f18d4e1f9f937268509150ec8671&sd=v2_6ea838e6b01a803c368bb3c0bce55280_0A923B01671A654A21333079664564F2_1516015883_1516015883_CIi3jgYQy9c-GI-d2syPLCABKAUw4QE&ui=0A923B01671A654A21333079664564F2&pi=/&wi=1914632520524480793&pt=home&vi=1516015881871&li=rbox-h2m&utm=16%2C873%2C991%2C2555&mgo=1&df=1&tim=03%3A31%3A23.935&id=2416&llvl=1&cv=290-5-RELEASE&fil=%5B%7B%22tii%22%3A%22%7E%7EV1%7E%7E-1939417431871489613%7E%7EHoN_7dHDyCXmd5G9Jo_wSYna0PZMt1ajX1iwg1YZ8rUSO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT5YZVzyM3_sqdzWJ-OVLWMbFBLoq_t_WCuEfzE6ubgc2DJNEJA6SnPpJaFlWdZ6cddz-p3yK2zd-zPGQG6wnRHskubBbs4TEeP_qZa1u1SU91p5Jb0iMqQI775aG0vbdlcOqCsqPQZK5lJUrnbGYbYHni5eMMdH6lHLRwY1fgSQk%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E-5228514076735715683%7E%7EVnzUt2XiSuq6fs7y8V2uRLZ0mQKy1yju8TS0cQK6BzASO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT3o9nDi2F-pM-ay-zUH_zIrFBLoq_t_WCuEfzE6ubgc2DJNEJA6SnPpJaFlWdZ6cddz-p3yK2zd-zPGQG6wnRHtuggi41b0xW02DcTU_o_lZ9yTUkn0WNi1bWuBEYMRrXzJ96sAW4dnGH-aE4_GP4Sc%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%2C%7B%22tii%22%3A%22%7E%7EV1%7E%7E-5434507228818133925%7E%7EN0TC_umecNz3mNygASYjGzsDws0Oc2f0sjDeFbpBD5YSO_fFkG-bpaW2-qyqBDD6A2oNFt1ukOTCFTq8EPPgT52s0By_DdF9FMP0graI91DFBLoq_t_WCuEfzE6ubgc2DJNEJA6SnPpJaFlWdZ6cde6ZTB00ZZEFfIv-tpO_dksJoa7Np4kj4Lazt5M7AO7SF5Ti0mau-jyamfeh682jfw%22%2C%22tipt%22%3A%22SP%22%2C%22tit%22%3A%22text%22%2C%22tids%22%3A%22a%22%7D%5D& image
-http://www.msn.com/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=477&dpuuid=81fa7bf172da735ac43d35ca433b3feb7373b187bc42179330191d6b06fa1db5b0da87c991749652&redir=https%3A%2F%2Fidsync.rlcdn.com%2F362248.gif%3Fpartner_uid%3D%24%7BDD_UUID%7D image
-http://www.msn.com/ https://i.liadm.com/s/32441?bidder_id=88068&bidder_uuid=0A923B01671A654A21333079664564F2 other
-http://www.msn.com/ https://trc.taboola.com/msn-msn-home/log/2/debug?tim=03%3A31%3A24.189&type=warn&msg=blocked%3A0-0-1-unknown&id=3172&cv=290-5-RELEASE image
-http://www.msn.com/ https://trc.taboola.com/msn-msn-home/log/2/debug?tim=03%3A31%3A24.200&type=warn&msg=blocked%3A0-0-1-unknown&id=4008&cv=290-5-RELEASE image
-http://www.msn.com/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=79908&dpuuid=WlyRDqG4ziWB8XnR-setyEdM&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D124%26cm%3D%24%7BDD_UUID%7D image
-http://www.msn.com/ https://idsync.rlcdn.com/362248.gif?partner_uid=14759159721759410453622461067553768789 image
-http://www.wordpress.com/ http://www.wordpress.com/ other
-http://www.msn.com/ https://stags.bluekai.com/site/35703?dt=0&r=656037163&sig=2926120731&bkca=KJpnEnWNznx617R01expBlx61pPhBe/6BMRt1nz61p1hBEBh1y/9ANWcpy== image
-http://www.msn.com/ https://i.liadm.com/s/32441?bidder_id=88068&bidder_uuid=0A923B01671A654A21333079664564F2&_li_chk=true&previous_uuid=dbd3220744be4f77b5b3f0f7999fb243 image
-http://www.wordpress.com/ https://www.wordpress.com/ html
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=124&cm=33891585410148793333228022679055760720 script
-http://www.wordpress.com/ http://ocsp.godaddy.com/MGIwYDA%2BMDwwOjAJBgUrDgMCGgUABBQdI2%2BOBkuXH93foRUj4a7lAr4rGwQUOpqFBxBnKLbv9r0FQW4gwZTaD94CAQeiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.msn.com/ https://stags.bluekai.com/site/51557?id=WlyRDqG4ziWB8XnR-setyEdM&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D122%26cm%3D$_BK_UUID&BKUUID=$_BK_UUID&limit=1 other
-http://www.wordpress.com/ https://wordpress.com/ html
-http://www.msn.com/ https://stags.bluekai.com/site/51558?dt=0&r=810616707&sig=3710488361&bkca=KJpnEnWBpbA1zik6Bb7vecK0i1Qn6iNmnSk6E4aPv6oB0u00puQovuCVBUjDBU/eGLEXGoJWFKuzpmELhwHvFKEXUvOQxVjaSG8KKZSS3gaqzGS3LRrCAjs3APk0noYoWrdAcHXSbrZi8rxBGZyH9MZjrjAk+GR9mLQo6x== other
-http://www.wordpress.com/ https://wordpress.com/home.logged-out/page-domain-only/img/placeholder.gif image
-http://www.msn.com/ https://d.agkn.com/pixel/8463/?che=1516015887&sk=164811302571000792565&puid=0A923B01671A654A21333079664564F2&l0=https://trc.taboola.com/sg/neustar/1/cm?taboola_hm=164811302571000792565 other
-http://www.wordpress.com/ https://wordpress.com/wp-content/themes/h4/landing/marketing/js/affiliate-referrals.js script
-http://www.wordpress.com/ https://fonts.googleapis.com/css?family=Noto+Serif:400,400i,700,700i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese css
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.wordpress.com/ https://fonts.googleapis.com/css?family=Noto+Sans:400,400i,700,700i&subset=cyrillic,cyrillic-ext,devanagari,greek,greek-ext,latin-ext,vietnamese css
-http://www.wordpress.com/ https://s1.wp.com/i/noticons/noticons.css?v=20150727 css
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuHpqO.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=1584&y=1376 image
-http://www.wordpress.com/ https://s1.wp.com/home.logged-out/page-domain-only/css/styles.css?v=1513794015 css
-http://www.wordpress.com/ https://s1.wp.com/home.logged-out/page-domain-only/js/bundle.js?v=1512489702 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BB4kwAp.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.wordpress.com/ https://fonts.gstatic.com/s/notoserif/v6/lJAvZoKA5NttpPc9yc6lPWaVI6zN22yiurzcBKxPjFE.woff2 font
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=122&cm=N2RjJ3Sl99ONVahS script
-http://www.wordpress.com/ https://fonts.gstatic.com/s/notosans/v7/LeFlHvsZjXu2c3ZRgBq9nJBw1xU1rKptJj_0jans920.woff2 font
-http://www.msn.com/ https://trc.taboola.com/sg/neustar/1/cm?taboola_hm=164811302571000792565 other
-http://www.msn.com/ https://bcp.crwdcntrl.net/5/c=8545/tp=CKGY/tpid=WlyRDqG4ziWB8XnR-setyEdM/pv=y?https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D120%26cm%3D%24%7Bprofile_id%7D other
-http://www.wordpress.com/ https://s1.wp.com/home.logged-out/page-domain-only/img/hero-icons.svg image
-http://www.msn.com/ https://bcp.crwdcntrl.net/5/ct=y/c=8545/tp=CKGY/tpid=WlyRDqG4ziWB8XnR-setyEdM/pv=y?https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D120%26cm%3D%24%7Bprofile_id%7D other
-http://www.wordpress.com/ https://fonts.gstatic.com/s/notosans/v7/PIbvSEyHEdL91QLOQRnZ1xampu5_7CjHW5spxoeN3Vs.woff2 font
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=120&cm=b9a669a740a35cc28845757da7f055f8 script
-http://www.wordpress.com/ https://s1.wp.com/home.logged-out/page-domain-only/img/domain-first-background-2x.jpg image
-http://www.msn.com/ https://idsync.rlcdn.com/420246.gif?partner_uid=WlyRDqG4ziWB8XnR-setyEdM image
-http://www.wordpress.com/ https://fonts.gstatic.com/s/notoserif/v6/eCpfeMZI7q4jLksXVRWPQwzyDMXhdD8sAj6OAJTFsBI.woff2 font
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=114&cm=b726b4284b4580b2777ebfa2c328733c7bfdfca7d572a0d488173bc9854ff4f625abae5358c0e7bc script
-http://www.wordpress.com/ https://fonts.gstatic.com/s/notosans/v7/9Z3uUWMRR7crzm1TjRicDv79_ZuUxCigM2DespTnFaw.woff2 font
-http://www.msn.com/ https://sync.1rx.io/usersync/clickagy/WlyRDqG4ziWB8XnR-setyEdM?dspret=1&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D139%26cm%3D%5BRX_UUID%5D html
-http://www.wordpress.com/ https://www.googleadservices.com/pagead/conversion_async.js script
-http://www.msn.com/ https://sync.1rx.io/usersync/clickagy/WlyRDqG4ziWB8XnR-setyEdM?zcc=1&dspret=1&redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D139%26cm%3D%5BRX_UUID%5D&cb=1516015893644 html
-http://www.wordpress.com/ https://www.google-analytics.com/analytics.js script
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.wordpress.com/ https://static.criteo.net/js/ld/ld.js script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBHt66O.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f image
-http://www.wordpress.com/ https://secure.leadback.advertising.com/adcedge/lb?site=695501&betr=sslbet_1472760417=[+]ssprlb_1472760417[720]|sslbet_1472760452=[+]ssprlb_1472760452[8760] image
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAkgetg.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.wordpress.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=363021256&t=pageview&_s=1&dl=https%3A%2F%2Fwordpress.com%2F&ul=en-us&de=UTF-8&dt=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAEAB~&jid=1618430661&gjid=2089051925&cid=321891169.1516016093&tid=UA-10673494-4&_gid=752555317.1516016093&_r=1&z=2051294449 html
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=139&cm=RX-6e106867-eddb-4fdd-8c36-95a0e899d639 script
-http://www.wordpress.com/ https://snap.licdn.com/li.lms-analytics/insight.min.js script
-http://www.wordpress.com/ https://static.ads-twitter.com/uwt.js script
-http://www.msn.com/ https://trc.taboola.com/msn-msn-home/log/3/visible image
-http://www.wordpress.com/ https://connect.facebook.net/en_US/fbevents.js script
-http://www.msn.com/ https://aa.agkn.com/adscores/g.pixel?sid=9212289188&_puid=WlyRDqG4ziWB8XnR-setyEdM&_redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D128%26cm%3D other
-http://www.wordpress.com/ https://bat.bing.com/bat.js script
-http://www.msn.com/ https://d.agkn.com/pixel/8543/?che=1516015895&sk=164811302571000792565&puid=WlyRDqG4ziWB8XnR-setyEdM&l1=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D128%26cm%3D164811302571000792565 other
-http://www.wordpress.com/ https://secure.quantserve.com/aquant.js?a=p-3Ma3jHaQMB_bS script
-http://www.wordpress.com/ https://mc.yandex.ru/metrika/watch.js script
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=128&cm=164811302571000792565 script
-http://www.wordpress.com/ https://refer.wordpress.com/wp-content/themes/refer-wordpress/assets/js/referrals.min.js?v=20171117 script
-http://www.msn.com/ https://pixel-a.sitescout.com/connectors/clickagy/usersync?redir=https%3A%2F%2Faorta.clickagy.com%2Fpixel.gif%3Fch%3D5%26cm%3D{userId} other
-http://www.msn.com/ https://aorta.clickagy.com/pixel.gif?ch=5&cm=6ba89adc-0162-4a85-bca6-8875ae04c205 script
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.wordpress.com/ https://www.clickcease.com/monitor/stat.js script
-http://www.wordpress.com/ https://bat.bing.com/action/0?ti=4074038&Ver=2&mid=56c0dae2-14de-ce68-8689-be3ed8320418&evt=pageLoad&sid=559c7a33-1&lt=7337&pi=0&lg=en-US&sw=360&sh=512&sc=24&tl=WordPress.com:%20Create%20a%20free%20website%20or%20blog&p=https%3A%2F%2Fwordpress.com%2F&r=&msclkid=N&rn=518816 other
-http://www.wordpress.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-10673494-4&cid=321891169.1516016093&jid=1618430661&_gid=752555317.1516016093&gjid=2089051925&_v=j66&z=2051294449 html
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuGE3C.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=1879&y=1535 image
-http://www.wordpress.com/ https://d.turn.com/r/dd/id/L21rdC84MTYvY2lkLzE3NDc0MzIzNDkvdC8w/kv/Pagename=wordpress.com/ script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AA2oHEB.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.wordpress.com/ https://amplify.outbrain.com/cp/obtp.js script
-http://www.msn.com/ https://us-u.openx.net/w/1.0/sd?id=537073026&val=WlyRDqG4ziWB8XnR-setyEdM&r=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fcm%3Fid%3D19b05a3b-50b2-33ac-c6e0-9f21c5fbd143%26r%3Dhttps%253A%252F%252Faorta.clickagy.com%252Fpixel.gif%253Fch%253D4%2526cm%253D other
-http://www.wordpress.com/ https://connect.facebook.net/signals/config/823166884443641?v=2.8.6&r=stable script
-http://www.msn.com/ https://otf.msn.com/c.gif image
-http://www.wordpress.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1067250390/?random=1516016092906&cv=8&fst=1516016092906&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=https%3A%2F%2Fwordpress.com%2F&tiba=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&async=1&rfmt=3&fmt=4 script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/AAuELh1.img?h=180&w=320&m=6&q=60&u=t&o=t&l=f&x=535&y=454 image
-http://www.wordpress.com/ https://mc.yandex.ru/watch/45268389?wmode=7&page-url=https%3A%2F%2Fwordpress.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-480%3Ai%3A20180115033455%3Aet%3A1516016095%3Aen%3Autf-8%3Av%3A932%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A528651412611%3Arqn%3A1%3Arn%3A321181721%3Ahid%3A9708075%3Ads%3A301%2C1612%2C316%2C288%2C1255%2C0%2C0%2C3791%2C50%2C%2C%2C%2C7287%3Afp%3A6068%3Arqnl%3A1%3Ast%3A1516016095%3Au%3A1516016095515935479%3At%3AWordPress.com%3A%20Create%20a%20free%20website%20or%20blog other
-http://www.wordpress.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-10673494-4&cid=321891169.1516016093&jid=1618430661&_v=j66&z=2051294449 image
-http://www.wordpress.com/ https://www.google.com/ads/user-lists/1067250390/?random=1516016092906&cv=8&fst=1516014000000&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=https%3A%2F%2Fwordpress.com%2F&tiba=WordPress.com%3A%20Create%20a%20free%20website%20or%20blog&async=1&fmt=3&cdct=2&is_vtc=1&random=220877547&rmt_tld=0&ipr=y image
-http://www.wordpress.com/ https://sslwidget.criteo.com/event?a=31321&v=4.5.4&p0=e%3Dexd%26site_type%3Dm&p1=e%3Dvh&p2=e%3Ddis&adce=1&lwid=b53ef162-ef44-4930-9cb3-80f53333f84b script
-http://www.msn.com/ https://static-global-s-msn-com.akamaized.net/img-resizer/tenant/amp/entityid/BBAq9.img?h=16&w=16&m=6&q=60&u=t&o=t&l=f&f=png image
-http://www.wordpress.com/ https://tr.outbrain.com/pixel?marketerId=00f0f5287433c2851cc0cb917c7ff0465e&obApiVersion=1.0.4&name=PAGE_VIEW&dl=https%3A%2F%2Fwordpress.com%2F&bust=09037808239000258 image
-http://www.wordpress.com/ https://mc.yandex.ru/metrika/advert.gif image
-http://www.wordpress.com/ https://mc.yandex.ru/watch/45268389/1?wmode=7&page-url=https%3A%2F%2Fwordpress.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-480%3Ai%3A20180115033455%3Aet%3A1516016095%3Aen%3Autf-8%3Av%3A932%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A528651412611%3Arqn%3A1%3Arn%3A321181721%3Ahid%3A9708075%3Ads%3A301%2C1612%2C316%2C288%2C1255%2C0%2C0%2C3791%2C50%2C%2C%2C%2C7287%3Afp%3A6068%3Arqnl%3A1%3Ast%3A1516016095%3Au%3A1516016095515935479%3At%3AWordPress.com%3A%20Create%20a%20free%20website%20or%20blog script
-http://www.wordpress.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.wordpress.com/ https://www.facebook.com/tr/?id=823166884443641&ev=PageView&dl=https%3A%2F%2Fwordpress.com%2F&rl=&if=false&ts=1516016094857&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=28&ttf=7995.715000000002&tts=7607.810000000001&ttse=7988.110000000001&it=1516016094484 image
-http://www.wordpress.com/ https://www.facebook.com/tr/?id=823166884443641&ev=Microdata&dl=https%3A%2F%2Fwordpress.com%2F&rl=&if=false&ts=1516016095362&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22article%3Apublisher%22%3A%22https%3A%2F%2Fwww.facebook.com%2FWordPresscom%22%2C%22og%3Atype%22%3A%22website%22%2C%22og%3Atitle%22%3A%22WordPress.com%3A%20Create%20a%20free%20website%20or%20blog%22%2C%22og%3Adescription%22%3A%22Create%20a%20free%20website%20or%20easily%20build%20a%20blog%20on%20WordPress.com.%20Hundreds%20of%20free%2C%20customizable%2C%20mobile-ready%20designs%20and%20themes.%20Free%20hosting%20and%20support.%22%2C%22og%3Aurl%22%3A%22https%3A%2F%2Fwordpress.com%2F%22%2C%22og%3Asite_name%22%3A%22WordPress.com%22%2C%22og%3Aimage%22%3A%22https%3A%2F%2Fs1.wp.com%2Fhome.logged-out%2Fimages%2Fwpcom-withjetpack.jpg%22%7D&cd[Meta]=%7B%22title%22%3A%22WordPress.com%3A%20Create%20a%20free%20website%20or%20blog%22%2C%22meta%3Adescription%22%3A%22Create%20a%20free%20website%20or%20easily%20build%20a%20blog%20on%20WordPress.com.%20Hundreds%20of%20free%2C%20customizable%2C%20mobile-ready%20designs%20and%20themes.%20Free%20hosting%20and%20support.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=28&ttf=8502.11&tts=7607.810000000001&ttse=8000.6950000000015 image
-http://www.wordpress.com/ https://pixel.quantserve.com/pixel;r=2130355569;labels=_fp.event.Homepage;rf=3;a=p-3Ma3jHaQMB_bS;url=https%3A%2F%2Fwordpress.com%2F;fpan=1;fpa=P0-447761145-1516016094560;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1516016094558;tzo=480;ogl=type.website%2Ctitle.WordPress%252Ecom%3A%20Create%20a%20free%20website%20or%20blog%2Cdescription.Create%20a%20free%20website%20or%20easily%20build%20a%20blog%20on%20WordPress%252Ecom%252E%20Hundreds%20of%20free%252C%2Curl.https%3A%2F%2Fwordpress%252Ecom%2F%2Csite_name.WordPress%252Ecom%2Cimage.https%3A%2F%2Fs1%252Ewp%252Ecom%2Fhome%252Elogged-out%2Fimages%2Fwpcom-withjetpack%252Ejpg image
-http://www.wordpress.com/ https://code.clickcease.com/api/fetch html
-http://www.wordpress.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.wordpress.com/ https://amplifypixel.outbrain.com/pixel?mid=00f0f5287433c2851cc0cb917c7ff0465e&dl=https%3A%2F%2Fwordpress.com%2F&bust=09037808239000258 image
-http://www.wordpress.com/ https://t.co/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvzbs&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0 image
-http://www.wordpress.com/ https://static.criteo.net/js/ld/gbc.js script
-http://www.wordpress.com/ https://www.clickcease.com/monitor/stat-nr.js script
-http://www.wordpress.com/ https://abc.gbc.criteo.net/ping?callback=cb88073 other
-http://www.wordpress.com/ https://monitor.clickcease.com/monitor/api/stats other
-http://www.wordpress.com/ https://acb.gbc.criteo.net/ping?callback=cb59880 other
-http://www.aliexpress.com/ http://www.aliexpress.com/ html
-http://www.wordpress.com/ https://bac.gbc.criteo.net/ping?callback=cb69851 other
-http://www.aliexpress.com/ http://m.aliexpress.com/?tracelog=wwwhome2mobilesitehome html
-http://www.aliexpress.com/ https://m.aliexpress.com/?tracelog=wwwhome2mobilesitehome html
-http://www.aliexpress.com/ https://m.aliexpress.com/ajaxapi/home/ajaxHome.do script
-http://www.wordpress.com/ https://bca.gbc.criteo.net/ping?callback=cb72307 other
-http://www.wordpress.com/ https://cab.gbc.criteo.net/ping?callback=cb59041 other
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/home/index.a9b8db3d.js script
-http://www.wordpress.com/ https://mc.yandex.ru/watch/45268389?page-url=https%3A%2F%2Fwordpress.com%2F&charset=utf-8&force-urlencoded=1&browser-info=ti%3A1%3As%3A360x512x24%3Ask%3A3%3Aadb%3A2%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-480%3Ai%3A20180115033510%3Aet%3A1516016110%3Aen%3Autf-8%3Av%3A932%3Ac%3A1%3Ala%3Aen-us%3Aar%3A1%3Anb%3A1%3Acl%3A985%3Als%3A528651412611%3Arqn%3A2%3Arn%3A402723573%3Ahid%3A9708075%3Ads%3A%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%3Arqnl%3A1%3Ast%3A1516016110%3Au%3A1516016095515935479 image
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/header/??lazy.cd2cf0f4.css css
-http://www.wordpress.com/ https://cba.gbc.criteo.net/ping?callback=cb89401 other
-http://www.aliexpress.com/ https://i.alicdn.com/??aefe-mobile-global/static/core.c1cd1fd8.css,ae-mobile/home/index.c8d1f1d4.css css
-http://www.wordpress.com/ https://gum.criteo.com/pong?stats=T24VyHQ9yztq53y6iCrzdqv22oq79y&uid=502a6e55-de3f-4027-a7be-bd3f1b4e4be2 image
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/static/assets/iconfontmd.6eb7d08b.ttf font
-http://www.wordpress.com/ https://csm.va.us.criteo.net/gev?entry=c~BearcatGbcScript.Init~1&entry=c~BearcatGbcScript.SubDomainSuccess.abc~1&entry=h~BearcatGbcScript.ScriptOnLoad~1533&entry=c~BearcatGbcScript.SubDomainSuccess.acb~1&entry=h~BearcatGbcScript.ScriptOnLoad~1806&entry=c~BearcatGbcScript.SubDomainSuccess.bac~1&entry=h~BearcatGbcScript.ScriptOnLoad~1529&entry=c~BearcatGbcScript.SubDomainSuccess.bca~1&entry=h~BearcatGbcScript.ScriptOnLoad~2125&entry=c~BearcatGbcScript.SubDomainSuccess.cab~1&entry=h~BearcatGbcScript.ScriptOnLoad~1524&entry=c~BearcatGbcScript.SubDomainSuccess.cba~1&entry=c~BearcatGbcScript.IdSuccess~1 image
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/core/package.b2cdd300.js script
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/??polyfill/index.e8e4f485.js,pwa/lib/vue.runtime.4f0cf9dd.js,pwa/lib/vuex.0f6361b4.js,atom/atom.5bd49519.js,standalone/hawe.661d7ae4.js,pwa/lib/seed.4e540154.js script
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/static/??sufei.f271b55b.js script
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/standalone/??venus.e2980efc.js script
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/timing/??page-timing.16013dc3.js script
-http://www.wordpress.com/ https://s1.wp.com/home.logged-out/page-domain-only/img/blog-scene-2x.jpg image
-http://www.wordpress.com/ https://s1.wp.com/home.logged-out/page-domain-only/img/website-scene-2x.jpg image
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/static/js/header.baa6e056.js script
-http://www.wordpress.com/ https://stats.wp.com/w.js?56 script
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1ngdlRVXXXXc.XXXX760XFXXXM.png image
-http://www.wordpress.com/ https://pixel.wp.com/b.gif?subd=wordpress.com&host=wordpress.com&blog=1&v=wpcom&user_id=0&tz=0&rand=0.2170574577593578 image
-http://www.aliexpress.com/ https://assets.alicdn.com/g/alilog/??aplus_plugin_aefront/index.js,mlog/aplus_v2.js script
-http://www.aliexpress.com/ https://ae01.alicdn.com/wimg/monitor/start-render.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB18RmXPXXXXXcBXFXX760XFXXXu.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1Pi5iPXXXXXbdXpXX760XFXXXL.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB10ryjPXXXXXbYXpXX760XFXXXc.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1EjNeXm_I8KJjy0Fo761FnVXac.png image
-http://www.wordpress.com/ https://pixel.wp.com/g.gif?x_stats-initial-visibility=visible&v=wpcom-no-pv&rand=0.5097977383665988 image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB10eZQQpXXXXXRXVXX760XFXXXO.png image
-http://www.wordpress.com/ https://pixel.wp.com/t.gif?lp_name=logged-out-homepage&lp_variation=&do_not_track=0&locale=en&platform=Android&utm_source=&utm_campaign=&affiliate=&_en=wpcom_homepage_view&_ui=tzY7Mvw6b1HNyAEFwgrmMplZ&_ut=anon&_ts=1516016113429&_tz=8&_lg=en-US&_pf=Linux%20x86_64&_ht=512&_wd=360&_sx=0&_sy=0&_dl=https%3A%2F%2Fwordpress.com%2F&_dr=&_rt=1516016113431&_=_ image
-http://www.wordpress.com/ https://analytics.twitter.com/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvzbs&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0&tpx_cb=twttr.conversion.loadPixels&cache_bust=0.12699450830275683 script
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1jzdGOVXXXXaWXpXXq6xXFXXXy.jpg image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1Z0FjRVXXXXXCXXXX760XFXXXi.png image
-http://www.wordpress.com/ https://px.ads.linkedin.com/collect/?time=1516016112600&pid=36622&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&fmt=js&s=1 other
-http://www.wordpress.com/ https://dc.ads.linkedin.com/collect/?time=1516016112600&pid=36622&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&fmt=js&s=1 other
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1gcFYelbM8KJjSZFFq6yynpXay.jpg_350x350.jpg image
-http://www.wordpress.com/ https://dis.us.criteo.com/dis/dis.aspx?p=31321&cb=71750216840&ref=&sc_r=360x512&sc_d=24&site_type=m html
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB12KbIlL6H8KJjy0Fjq6yXepXaD.jpg_350x350.jpg image
-http://www.wordpress.com/ https://px.ads.linkedin.com/collect/?time=1516016112600&pid=36622&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&fmt=js&s=1&cookiesTest=true other
-http://www.wordpress.com/ https://6355556.fls.doubleclick.net/activityi;type=wordp0;cat=wpvisit;src=6355556;u5=tzY7Mvw6b1HNyAEFwgrmMplZ;u6=%2F;u7=eBsUanmvx4WZBI0IJieDaeozojFTOV8z;ord=eBsUanmvx4WZBI0IJieDaeozojFTOV8z html
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1E0zeMVXXXXcAaXXX760XFXXXY.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1KLEHdlUSMeJjy1zdq6yR3FXaU.jpg_350x350.jpg image
-http://www.wordpress.com/ https://6355556.fls.doubleclick.net/activityi;type=wordp0;cat=wppv;src=6355556;u5=tzY7Mvw6b1HNyAEFwgrmMplZ;u6=%2F;u7=eBsUanmvx4WZBI0IJieDaeozojFTOV8z;ord=373498104602.78076 html
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1ckPsewjN8KJjSZFk761boXXai.png image
-http://www.aliexpress.com/ https://assets.alicdn.com/g/alilog/??s/7.7.0/plugin/aplus_client.js,aplus_cplugin/0.2.11/toolkit.js,aplus_cplugin/0.2.11/monitor.js,s/7.7.0/aplus_std.js,aplus_cplugin/0.2.11/aol.js,s/7.7.0/plugin/aplus_spmact.js,aplus_plugin_ae/0.0.8/index.js?v=20180109204418 script
-http://www.aliexpress.com/ https://assets.alicdn.com/g/secdev/entry/index.js?t=210557 script
-http://www.aliexpress.com/ https://assets.alicdn.com/g/secdev/sufei_data/3.2.4/index.js script
-http://www.wordpress.com/ https://secure.leadback.advertising.com/adcedge/lb?site=695501&betr=sslbet_1501625044=ssprlb_1501625044[720] image
-http://www.wordpress.com/ https://secure.leadback.advertising.com/adcedge/lb?site=695501&betr=sslbet_1487351074=[+]ssprlb_1487351074[720]|sslbet_1487351090=[+]ssprlb_1487351090[8760] image
-http://www.aliexpress.com/ https://gj.mmstat.com/eg.js script
-http://www.wordpress.com/ https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25 html
-http://www.aliexpress.com/ https://cmap.alibaba.com/landing_ae.gif?cna=- image
-http://www.wordpress.com/ https://secure.adnxs.com/getuid?https://px.ads.linkedin.com/collect/?time=1516016112600&pid=36622&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&ref=&fmt=js&s=1&cookiesTest=true&anId=%24UID image
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-lego/standalone/lego-dialog/??lego-dialog.b3090918.js script
-http://www.wordpress.com/ https://www.bizographics.com/collect/?pid=36622&ref=&s=1&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&fmt=js&time=1516016112600 other
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/common/ms-man/xman.875154aa.js script
-http://www.wordpress.com/ https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25&C=1 html
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/footer/index.e5c29312.js script
-http://www.wordpress.com/ https://8017305.fls.doubleclick.net/activityi;src=8017305;type=invmedia;cat=obyv3klj;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=9215899996529.854 html
-http://www.aliexpress.com/ https://m.aliexpress.com/shopcart/ajaxapi/count.do script
-http://www.wordpress.com/ https://sp.analytics.yahoo.com/spp.pl?a=10000&.yp=10023913 image
-http://www.wordpress.com/ https://sp.analytics.yahoo.com/spp.pl?a=10000&.yp=10023913&ec=AllPages image
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/header/lazy.dff9b078.js script
-http://www.aliexpress.com/ https://m.aliexpress.com/ajaxapi/log4js.do?log=user,downloadapp,autocall, script
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/home/qp.96e883aa.js script
-http://www.wordpress.com/ https://ds.reson8.com/insights.gif?rand=165885612&t=0&pixt=resonate&advkey=0010M00001RV2QuQAL&opptykey=MASW0517A&evkey=163211&evtype=custom image
-http://www.aliexpress.com/ https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?cache=de3023f&gmkey=&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_1%26exp_type%3Dresource_share%26exp_condition%3D%26exp_product%3D18459%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26Page_size%3D%26Page_no%3D%26refer%3D%26st_page_id%3D95143f0d0b82ddfa5a5c9169160f9980f98ae23fb4%26ali_apache_track%3D-&cna=b3%2FjEj5nVQQCAZUUPw3NItBz&spm-cnt=a2g0n.home.0.0.1463a1fbT4BGiV&logtype=2 image
-http://www.wordpress.com/ https://insight.adsrvr.org/tags/l8hfnf9/4gktlyq/iframe html
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1Ucq8mcnI8KJjSspe763wIpXal.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1Y3U3d2jM8KJjSZFNq6zQjFXa4.jpg image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1fCKsmCfD8KJjSszh762IJFXaA.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1JOXkdIic_eJjSZFn760VwVXa2.png image
-http://www.wordpress.com/ https://getrockerbox.com/assets/xyz.js script
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1kkQkljnD8KJjSspb762bEXXab.png image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB13ku0l46I8KJjy0Fg760XzVXa2.png image
-http://www.aliexpress.com/ https://assets.alicdn.com/g/alilog/oneplus/entry.js?t=210557 script
-http://www.aliexpress.com/ https://gj.mmstat.com/g.gif?logtype=1&title=AliExpress%20Mobile%20-%20Global%20Online%20Shopping%20for%20Apparel%2C%20Phones%2C%20Computers%2C%20Electronics%2C%20Fashion%20and%20more&pre=&cache=31edec6&scr=360x512&cna=b3/jEj5nVQQCAZUUPw3NItBz&spm-cnt=a2g0n.home.0.0.1463a1fbT4BGiV&uidaplus=&aplus=&ali_beacon_id=-&ali_apache_id=10.182.248.34.1516015975605.180091.0&ali_apache_track=-&ali_apache_tracktmp=-&dmtrack_c=%7Bali_resin_trace%3Dws_ab_test%3Dhttps%7Caep_usuc_f%3Dsite%253Dglo%2526aep_cet%253Dmobile%2526b_locale%253Den_US%7Caeu_cid%3D-%7D&pageid=95143f0d0b82ddfa5a5c9169160f9980f98ae23fb4&hn=wsmobi011130221250.us.ot7&asid=AQAAAABpkVxa5AyJIAAAAABVCYBytkr67w%3D%3D&sidx=lRQ%2FDWmRXFoAAAAAQeYckCxpwyK9%2FPUM&ckx=maliexpresscom%7C&dmtrack_b=%7Bifm%3D0%7Clogin%3D0%7D&p=1&o=android6.01&b=chrome58&s=360x512&w=webkit&ism=android&lver=7.7.0&jsver=aplus_std&tag=0&stag=2&lstag=0 image
-http://www.aliexpress.com/ https://m.aliexpress.com/img/favicon-96x96.png image
-http://www.aliexpress.com/ https://m.aliexpress.com/sw.js script
-http://www.wordpress.com/ https://getrockerbox.com/pixel.gif?pageReferrer=https%3A%2F%2Fwordpress.com%2F&action=view&source=wordpress&an_seg=7920770&type=imp image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1H9Kmbzb.heNjSZFA763hKXXaI.png image
-http://www.wordpress.com/ https://us-west-2.dc.ads.linkedin.com/collect/?pid=36622&ref=&s=1&url=https%3A%2F%2Fwordpress.com%2F&pageUrl=https%3A%2F%2Fwordpress.com%2F&fmt=js&time=1516016112600&ck= other
-http://www.aliexpress.com/ https://m.aliexpress.com/ajaxapi/getDialog.do script
-http://www.wordpress.com/ https://secure.adnxs.com/getuid?%2fseg%3fadd%3d7920770%26redir%3dhttps%253a%252f%252fgetrockerbox.com%252fpixel.gif%253fadnxs_uid%253d$UID%2526pageReferrer%253dhttps%25253A%25252F%25252Fwordpress.com%25252F%2526action%253dview%2526source%253dwordpress%2526an_seg%253d7920770%2526type%253dimp image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1C5G1ldfJ8KJjy0Fe760KEXXa5.png image
-http://www.wordpress.com/ https://dis.criteo.com/rex/match.aspx?c=25&uid=WlyR89HM4SIAABhwS-UAAABp%261070 image
-http://www.aliexpress.com/ https://m.aliexpress.com/img/favicon.ico image
-http://www.wordpress.com/ https://secure.adnxs.com/getuid?https%3A%2F%2Fwww.linkedin.com%2Fcsp%2Fdtag%3Fp%3D9%26_x%3D%252526opid%25253D36622%252526fmt%25253Djs%252526ref%25253D%252526ck%25253D%252526url%25253Dhttps%2525253A%2525252F%2525252Fwordpress.com%2525252F%252526s%25253D1%252526pageUrl%25253Dhttps%2525253A%2525252F%2525252Fwordpress.com%2525252F%252526time%25253D1516016112600%2525263pc%25253Dtrue%252526an_user_id%25253D%24UID image
-http://www.aliexpress.com/ https://login.aliexpress.com/xman/xman_config_new.htm?_=1516015984546 html
-http://www.wordpress.com/ https://d1eoo1tco6rr5e.cloudfront.net/l8hfnf9/4gktlyq/iframe html
-http://www.aliexpress.com/ https://gj.mmstat.com/ae.pc_click.statweb_ae_click?cache=fc767b9&gmkey=&gokey=ae_project_id%3D180113%26ae_page_type%3Dpoplayer-newuser-1121%26ae_page_area%3D%26ae_button_type%3D%26ae_object_type%3Dpoplayer-newuser-1121%26ae_object_value%3Dhttps%25253A%25252F%25252Fm.aliexpress.com%25252F%25253Ftracelog%25253Dwwwhome2mobilesitehome%26ae_ismember%3Dfalse%26ae_user_id%3D10.182.248.34.1516015975605.180091.0%26ae_click_behavior%3D%26st_page_id%3D95143f0d0b82ddfa5a5c9169160f9980f98ae23fb4%26ali_apache_track%3D-&cna=b3%2FjEj5nVQQCAZUUPw3NItBz&spm-cnt=a2g0n.home.0.0.1463a1fbT4BGiV&logtype=2 image
-http://www.aliexpress.com/ https://ae01.alicdn.com/tps/i2/TB12r_XHVXXXXacXFXXd4xm0VXX-640-640.png image
-http://www.wordpress.com/ https://insight.adsrvr.org/track/conv/?adv=l8hfnf9&ct=0:4gktlyq&fmt=3 other
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/??polyfill/index.e8e4f485.js,pwa/lib/vue.runtime.4f0cf9dd.js,pwa/lib/vuex.0f6361b4.js,atom/atom.3bdfa010.js,standalone/hawe.661d7ae4.js,pwa/lib/seed.4e540154.js script
-http://www.wordpress.com/ https://sync.adap.tv/sync?type=gif&key=thetradedesk&uid=c1cb8271-eb8c-4ecb-b5bf-5f2fc2087f12 text
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/node_modules/@alife/zeta-iconfont/iconfontmd.6eb7d08b.ttf font
-http://www.wordpress.com/ https://sync.adaptv.advertising.com/sync?type=gif&key=thetradedesk&uid=c1cb8271-eb8c-4ecb-b5bf-5f2fc2087f12 image
-http://www.aliexpress.com/ https://i.alicdn.com/ae-mobile/common/iconfont/iconfont.b573ce3e.ttf font
-http://www.wordpress.com/ https://s1.wp.com/i/favicon.ico?v=1447321881 image
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1Q6aMmb_I8KJjy1Xaq6zsxpXaH.jpg image
-http://www.aliexpress.com/ https://perf.mmstat.com/p.gif image
-http://www.aliexpress.com/ https://perf.mmstat.com/p.gif?memberSeq=&isNewUser=true&pageId=95143f0d0b82ddfa5a5c9169160f9980f98ae23fb4&site=m&pageType=m_home&ns=1516015974773&ules=0&ulee=0&rs=0&re=0&fs=1516015976662&dls=1516015976663&dle=1516015976663&cs=1516015976663&ce=1516015977601&scs=1516015976966&resqs=1516015977602&resps=1516015977934&respe=1516015977940&dl=1516015977942&di=1516015980657&dcles=1516015980668&dclee=1516015980668&domc=1516015983442&les=1516015983442&lee=1516015983525&srt=1516015979681&fst=0 image
-http://www.aliexpress.com/ https://connect.facebook.net/en_US/fbevents.js script
-http://www.aliexpress.com/ https://www.google-analytics.com/analytics.js script
-http://www.aliexpress.com/ https://aeu.alicdn.com/ctl/ctl.js script
-http://www.aliexpress.com/ https://m.aliexpress.com/s/item/32696115470.html html
-http://www.aliexpress.com/ https://m.aliexpress.com/store/2299004 html
-http://www.aliexpress.com/ https://m.aliexpress.com/statuspages/net_error.htm html
-http://www.aliexpress.com/ https://aeis.alicdn.com/vip/login/0.5.18/havanalogin/js/mini-login-embedder-min.js script
-http://www.aliexpress.com/ https://www.google-analytics.com/plugins/ua/ec.js script
-http://www.aliexpress.com/ https://connect.facebook.net/signals/config/1650958108523345?v=2.8.6&r=stable script
-http://www.aliexpress.com/ https://aeu.alicdn.com/js/cj/99.js script
-http://www.aliexpress.com/ https://aeis.alicdn.com/security/umscript/3.3.22/um.js script
-http://www.aliexpress.com/ https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?cache=54dce0f&gmkey=&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_2%26exp_type%3Dresource_share%26exp_condition%3D%26exp_product%3D18261%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26Page_size%3D%26Page_no%3D%26refer%3D%26st_page_id%3D95143f0d0b82ddfa5a5c9169160f9980f98ae23fb4%26ali_apache_track%3D-&cna=b3%2FjEj5nVQQCAZUUPw3NItBz&spm-cnt=a2g0n.home.0.0.1463a1fbT4BGiV&logtype=2 image
-http://www.aliexpress.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1075534031&t=pageview&_s=1&dl=https%3A%2F%2Fm.aliexpress.com%2F%3Ftracelog%3Dwwwhome2mobilesitehome&ul=en-us&de=UTF-8&dt=AliExpress%20Mobile%20-%20Global%20Online%20Shopping%20for%20Apparel%2C%20Phones%2C%20Computers%2C%20Electronics%2C%20Fashion%20and%20more&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aGBAAEIJ~&jid=303004362&gjid=1504084804&cid=1951305887.1516015988&tid=UA-17640202-1&_gid=1823576798.1516015988&_r=1&z=410177355 html
-http://www.aliexpress.com/ https://ae01.alicdn.com/wimg/buyer/single/loading-16x16.gif image
-http://www.aliexpress.com/ https://www.facebook.com/tr/?id=1650958108523345&ev=PageView&dl=https%3A%2F%2Fm.aliexpress.com%2F%3Ftracelog%3Dwwwhome2mobilesitehome&rl=&if=false&ts=1516015988752&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=28&ttf=12089.300000000001&tts=11404.175000000001&ttse=12085.075&it=1516015988090 image
-http://www.aliexpress.com/ https://www.facebook.com/tr/?id=1650958108523345&ev=Microdata&dl=https%3A%2F%2Fm.aliexpress.com%2F%3Ftracelog%3Dwwwhome2mobilesitehome&rl=&if=false&ts=1516015990259&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22AliExpress%20Mobile%20-%20Global%20Online%20Shopping%20for%20Apparel%2C%20Phones%2C%20Computers%2C%20Electronics%2C%20Fashion%20and%20more%22%2C%22meta%3Adescription%22%3A%22Mobile%20Online%20Shopping%20for%20Apparel%2C%20Phones%2C%20Computers%2C%20Electronics%2C%20Fashion%20and%20more%20from%20China%3B%20Shopping%20on%20AliExpress%20from%20mobile%20site%2C%20the%20world%27s%20online%20marketplace!%22%2C%22meta%3Akeywords%22%3A%22AliExpress%2C%20Online%20shopping%2C%20Online%20Marketing%2C%20Automotive%2C%20Phones%2C%20Accessories%2C%20Computers%2C%20Electronics%2C%20Fashion%2C%20Beauty%2C%20Health%2C%20Apparel%2C%20Garden%2C%20Toys%20%2C%20Sports%2C%20Weddings%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=28&ttf=13596.875000000002&tts=11404.175000000001&ttse=12093.650000000001 image
-http://www.aliexpress.com/ https://passport.aliexpress.com/mini_login.htm?lang=en_us&appName=aebuyer&appEntrance=default&styleType=auto&bizParams=&notLoadSsoView=false&notKeepLogin=true&isMobile=true&rnd=0.7027453305266174 html
-http://www.aliexpress.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-17640202-1&cid=1951305887.1516015988&jid=303004362&_gid=1823576798.1516015988&gjid=1504084804&_v=j66&z=410177355 html
-http://www.aliexpress.com/ https://aeis.alicdn.com/vip/havana-login/0.3.0/css/mini-login-form-min.css css
-http://www.aliexpress.com/ https://i.alicdn.com/aefe-mobile-global/css/login/havana.4366ca0b.css css
-http://www.aliexpress.com/ https://aeis.alicdn.com/vip/havana-login/0.3.0/js/mini-login-min.js script
-http://www.aliexpress.com/ https://aeu.alicdn.com/js/uab.js script
-http://www.aliexpress.com/ https://ynuf.alipay.com/uid script
-http://www.aliexpress.com/ https://ae01.alicdn.com/kf/HTB1f9W9jwLD8KJjSsze761GRpXaV.png_.webp image
-http://www.aliexpress.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-17640202-1&cid=1951305887.1516015988&jid=303004362&_v=j66&z=410177355 image
-http://www.aliexpress.com/ https://aeis.alicdn.com/sd/pointman/js/pt2.js?_=421115 script
-http://www.aliexpress.com/ https://us.ynuf.alipay.com/service/um.json script
-http://www.aliexpress.com/ https://us.ynuf.alipay.com//service/clear.png?xt=80ce86399d70d5ca8df0007efef2e9008bd7f556&xa=090D1F110F18782C2C26020C0207 image
-http://www.aliexpress.com/ https://aeu.alicdn.com/js/cj/106.js script
-http://www.aliexpress.com/ https://aeis.alicdn.com/security/umscript/3.3.24/um.js script
-http://www.aliexpress.com/ https://gj.mmstat.com/ae.pc_ctr.statweb_ae_ctr?cache=74fe8b9&gmkey=&gokey=project_id%3D180135%26exp_page%3Dmsite_home%26exp_page_area%3Dhome_banner_3%26exp_type%3Dresource_share%26exp_condition%3D%26exp_product%3D17252%26exp_attribute%3Dpromotion%26exp_result_cnt%3D10%26Page_size%3D%26Page_no%3D%26refer%3D%26st_page_id%3D95143f0d0b82ddfa5a5c9169160f9980f98ae23fb4%26ali_apache_track%3D-&cna=b3%2FjEj5nVQQCAZUUPw3NItBz&spm-cnt=a2g0n.home.0.0.1463a1fbT4BGiV&logtype=2 image
-http://www.aliexpress.com/ https://us.ynuf.alipay.com/service/um.json script
-http://www.ok.ru/ http://www.ok.ru/ other
-http://www.ok.ru/ https://www.ok.ru/ other
-http://www.ok.ru/ http://m.ok.ru/ other
-http://www.ok.ru/ https://m.ok.ru/ html
-http://www.ok.ru/ https://m.ok.ru/mres/batch/css/6a772b0b/mob-android-p.css css
-http://www.ok.ru/ https://m.ok.ru/mres/batch/css/6a772b0b/mobile-sm.css css
-http://www.ok.ru/ https://m.ok.ru/mres/batch/js/head/b7253079/head.js script
-http://www.ok.ru/ https://m.ok.ru/mres/img/t.gif image
-http://www.stackoverflow.com/ http://www.stackoverflow.com/ html
-http://www.ok.ru/ https://m.ok.ru/mres/img/t/prm.png image
-http://www.stackoverflow.com/ http://stackoverflow.com/ other
-http://www.ok.ru/ https://m.ok.ru/mres/batch/sprites/social-24/5123af535080e661fcf0ebc4bb077b2d@2x.png image
-http://www.stackoverflow.com/ https://stackoverflow.com/ html
-http://www.ok.ru/ https://m.ok.ru/mres/batch/sprites/social-24/8ce93608061b39e441a79f519dd1a3ab.png image
-http://www.stackoverflow.com/ https://cdn.sstatic.net/Js/mobile.en.js?v=8e20e188854d script
-http://www.ok.ru/ https://m.ok.ru/mres/img/arDown@2x.png image
-http://www.stackoverflow.com/ https://cdn.sstatic.net/Sites/stackoverflow/mobile.css?v=f667592a31e6 css
-http://www.ok.ru/ https://m.ok.ru/mres/batch/sprites/toolbar-set/83b18f0a8ee581427f77ef40fc876b5c@2x.png image
-http://www.ok.ru/ https://m.ok.ru/mres/batch/js/common/2b6fb198/common.js script
-http://www.stackoverflow.com/ https://cdn.sstatic.net/Js/stub.en.js?v=10cafd98c67a script
-http://www.stackoverflow.com/ https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js script
-http://www.ok.ru/ https://i.mycdn.me/image?id=862248647432&t=17&plc=MOBILE&tkn=*1iCRQVJ8pC2CA1fwCAS-lAn4L9I image
-http://www.stackoverflow.com/ https://cdn.sstatic.net/Js/full-anon.en.js?v=448b407c0535 script
-http://www.ok.ru/ https://pimg.mycdn.me/getImage?url=http%3A%2F%2Fi.mycdn.me%2Fimage%3Fid%3D863074239286%26plc%3DUNKNOWN%26tkn%3D*8xiFo6T8XQ7JxrTvN-ZMYZctJno%26fn%3Dtopic_link_1080&type=TOPIC_LINK_WIDE_548&signatureToken=r6FTxgBA4C5PO9xKFXmyeA image
-http://www.ok.ru/ https://i.mycdn.me/image?id=812080819580&t=17&plc=MOBILE&tkn=*HDur_wRlocpS-eNSaptybmthouw image
-http://www.stackoverflow.com/ https://cdn.sstatic.net/img/share-sprite-new.png?v=e1b8bd67bc12 image
-http://www.ok.ru/ https://i.mycdn.me/image?id=837654277931&t=17&plc=MOBILE&tkn=*r4fSV14A64nKCTTiFVnToNh4hGQ image
-http://www.stackoverflow.com/ https://www.google-analytics.com/analytics.js script
-http://www.ok.ru/ https://i.mycdn.me/image?id=865662581940&t=17&plc=MOBILE&tkn=*2ffNEf9aOkivSawKk7uyT1sEejE image
-http://www.stackoverflow.com/ https://sb.scorecardresearch.com/beacon.js script
-http://www.ok.ru/ https://i.mycdn.me/image?id=864642618760&t=17&plc=MOBILE&tkn=*cyXVs57DCbO2sA_3Jw9G6n5OQ5E image
-http://www.stackoverflow.com/ https://secure.quantserve.com/quant.js script
-http://www.ok.ru/ https://i.mycdn.me/image?id=854383094841&t=17&plc=MOBILE&tkn=*nJJp1hjUwgAvKk-FzlXYtOgT5OQ image
-http://www.stackoverflow.com/ https://sb.scorecardresearch.com/b?c1=2&c2=17440561&ns__t=1516015976252&ns_c=UTF-8&cv=3.1m&c8=Stack%20Overflow%20-%20Where%20Developers%20Learn%2C%20Share%2C%20%26%20Build%20Careers&c7=https%3A%2F%2Fstackoverflow.com%2F&c9= other
-http://www.ok.ru/ https://r3.mail.ru/k?ok_id=&t=obLD1AAAAAAIAAAA&src=mobile&bci=3001570074972073303 image
-http://www.stackoverflow.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1580508328&t=pageview&_s=1&dl=https%3A%2F%2Fstackoverflow.com%2F&ul=en-us&de=UTF-8&dt=Stack%20Overflow%20-%20Where%20Developers%20Learn%2C%20Share%2C%20%26%20Build%20Careers&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAEAB~&jid=304341499&gjid=807627770&cid=913482864.1516015977&tid=UA-5620270-1&_gid=1114931026.1516015977&_r=1&cd3=Home%2FIndex&z=1645195887 image
-http://www.ok.ru/ https://m.ok.ru/mres/img/tb/loader@2x.png image
-http://www.stackoverflow.com/ https://sb.scorecardresearch.com/b2?c1=2&c2=17440561&ns__t=1516015976252&ns_c=UTF-8&cv=3.1m&c8=Stack%20Overflow%20-%20Where%20Developers%20Learn%2C%20Share%2C%20%26%20Build%20Careers&c7=https%3A%2F%2Fstackoverflow.com%2F&c9= other
-http://www.stackoverflow.com/ https://rules.quantcount.com/rules-p-c1rF4kxgLUzNc.js script
-http://www.ok.ru/ https://m.ok.ru/mres/img/spn16_1@2x.gif image
-http://www.stackoverflow.com/ https://pixel.quantserve.com/pixel;r=1606284662;rf=0;a=p-c1rF4kxgLUzNc;url=https%3A%2F%2Fstackoverflow.com%2F;fpan=1;fpa=P0-885347824-1516015977832;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1516015977831;tzo=480;ogl= image
-http://www.stackoverflow.com/ https://cdn.sstatic.net/Sites/stackoverflow/img/favicon.ico?v=4f32ecc8f43d image
-http://www.ok.ru/ https://counter.yadro.ru/hit?uhttp://m.odnoklassniki.ru/ html
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=863035154510&photoType=4 image
-http://www.ok.ru/ https://m.ok.ru/mres/img/avatar_ellip.svg image
-http://www.ok.ru/ https://m.ok.ru/mres/batch/sprites/main/9173f83330392cb5a73175b543135abe@2x.png image
-http://www.ok.ru/ https://i.mycdn.me/image?id=864626673742&t=11&plc=MOBILE&tkn=*qg1j9RgSK5BiGjsUFvjBAPll1dA image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=863423308198&photoType=4 image
-http://www.ok.ru/ https://i.mycdn.me/image?id=863651224486&t=8&plc=MOBILE&tkn=*ybI2hwmuF91vLzKDiuPU6sap1kY image
-http://www.ok.ru/ https://counter.yadro.ru/hit?q;uhttp://m.odnoklassniki.ru/ image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=862378278920&photoType=4 image
-http://www.ok.ru/ https://m.ok.ru/mres/img/outlink_gray.png image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=863952351542&photoType=4 image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=855990655413&photoType=4 image
-http://www.ok.ru/ https://i.mycdn.me/image?id=852073420673&t=9&plc=MOBILE&tkn=*Ev8wCjemMxGrAHI9mHKnz_vJAcg image
-http://www.ok.ru/ https://m.ok.ru/mres/img/spn16_1.gif image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=856513411586&photoType=4 image
-http://www.ok.ru/ https://m.ok.ru/mres/batch/js/1b2892ab/googleSignIn.js script
-http://www.ok.ru/ https://m.ok.ru/mres/batch/js/3cce494d/photos.module.js script
-http://www.ok.ru/ https://m.ok.ru/mres/batch/css/6a772b0b/photo-layer.css css
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=861056159535&photoType=4 image
-http://www.ok.ru/ https://m.ok.ru/mres/default/js/streamsense.5.2.0.160629.min.js script
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=861056159535&photoType=42 image
-http://www.ok.ru/ https://i.mycdn.me/image?id=863988685867&t=11&plc=MOBILE&tkn=*cBJrV6N9Tvm5RrqFoMdVNxffDTg image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=833978819072&photoType=4 image
-http://www.ok.ru/ https://m.ok.ru/mres/batch/js/34da7904/vipModule.js script
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=860744548769&photoType=4 image
-http://www.ok.ru/ https://i.mycdn.me/image?id=864055379470&t=11&plc=MOBILE&tkn=*L37CZCP1s-nsqpUTQ_FK6WnvvFA image
-http://www.ok.ru/ https://i.mycdn.me/getImage?photoId=852604886841&photoType=4 image
-http://www.ok.ru/ https://m.ok.ru/mres/batch/sprites/photolayer/25d1029b279154e2dc2306b725641915@2x.png image
-http://www.ok.ru/ https://m.ok.ru/mres/img/browser-theme/oklogo.png image
-http://www.ok.ru/ https://m.ok.ru/favicon.ico?2 image
-http://www.microsoft.com/ http://www.microsoft.com/ other
-http://www.microsoft.com/ http://www.microsoft.com/en-us/ other
-http://www.microsoft.com/ https://www.microsoft.com/en-us/ html
-http://www.microsoft.com/ https://assets.onestore.ms/cdnfiles/external/mwf/long/v1/v1.30.0/fonts/MWFMDL2.woff font
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/west-european/mscomhp/_scrf/css/themes=default.device=uplevel_web_mobile_webkit_android/29-ff74b0/93-3c2920/f9-46ac91/e6-5ff770/a0-b0aa00/eb-efa998/e4-d7de28/15-5b186e/9a-4117df/22-72808a/13-de3a8e/6a-f5fdda/ba-f52065/b5-9f8a9c/94-cfe3f0/2f-31d721/f7-44be89/2c-9a9e76/76-8a8350/a7-ef91d3?ver=2.0 css
-http://www.microsoft.com/ https://mem.gfx.ms/meversion?partner=MSHomePage&market=en-us script
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/_h/9be151e5/coreui.statics/images/1x1clear.gif image
-http://www.microsoft.com/ https://assets.onestore.ms/cdnfiles/external/uhf/long/9a49a7e9d8e881327e81b9eb43dabc01de70a9bb/images/microsoft-gray.png image
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Iuxr?ver=652c&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=1231&y=345&s=889&d=500&aim=true image
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RWhA6n?ver=de4e&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=941&y=264&s=1179&d=663&aim=true image
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/_h/975a7d20/coreui.statics/externalscripts/jquery/jquery-2.1.1.min.js script
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/_h/2532198d/coreui.statics/images/social/facebook.svg image
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/_h/6f40299c/coreui.statics/images/social/twitter.svg image
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/_h/413bd4a8/coreui.statics/images/social/linkedin.svg image
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/mscomhp/_scrf/js/themes=default/43-eaac0c/69-03404c?ver=2.0 script
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/mscomhp/_scrf/js/themes=default/8e-ae77e0/3e-659366/62-2cc6de/7e-38b58d/50-547028/16-c8713b/7a-dd482c/73-dd5609/c8-7a1e9a/6b-facf10/5e-be0905/ad-d468a6/24-a2fd02/59-dee9e9/41-061a7b/a5-db4aa4/61-1328d0/3e-9d5838/cd-7e3f18/b9-81b1eb/2f-fce65e/e5-653d7a/b4-c945fa/a2-63a25c/b4-96deff/f3-5a897a/b6-e452c0/a6-76353a/f1-3caa62/9b-a08600/85-6be521/52-82a4e3/fa-dd7d60/3f-e4e2be/56-cadc5a/d2-1fbdac/9c-49f12d/55-e943e8/77-cb8df7/7a-a31597/99-3c1ec0/f0-6d25a5/25-13a0a8/da-42be1e/11-0a0ec9/39-bd67c3/bc-96bc8d/38-88cc41/72-7925e8/a8-761789/d9-4d8603/bb-16b805/32-dadf92/e1-776ecd/e2-2b1722/6b-befa41/90-7bb172/11-991255/1e-cd19b3/db-a17376/ef-8ca4e0?ver=2.0 script
-http://www.microsoft.com/ https://cdn.optimizely.com/public/3698060313/s/home.js script
-http://www.microsoft.com/ https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/normal/latest.woff2 font
-http://www.microsoft.com/ https://c.s-microsoft.com/static/fonts/segoe-ui/west-european/Bold/latest.woff2 font
-http://www.microsoft.com/ https://web.vortex.data.microsoft.com/collect/v1/t.js?ver=%272.1%27&name=%27Ms.Webi.PageView%27&time=%272018-01-15T11%3A34%3A26.952Z%27&os=%27Android%27&appId=%27JS%3AMicrosoftHP%27&cV=%27C1%2Bza5SJFUi2vJk6.3%27&-ver=%271.0%27&-impressionGuid=%272d5df7dd-8bf1-485b-ab2a-3ed141255954%27&-pageName=%27Homepage%27&-uri=%27https%3A%2F%2Fwww.microsoft.com%2Fen-us%2F%27&-market=%27en-us%27&-pageType=%27HomePage%27&-resHeight=512&-resWidth=360&-pageTags=%27%7B%22browserGroup%22%3A%22uplevel.web.mobile.webkit.android%22%2C%22isTentedPage%22%3Afalse%2C%22tasId%22%3A%22727b9981-7e28-48ce-ac30-510b0230b9ac%22%2C%22pageVersion%22%3A%220.1%22%2C%22isCachedPage%22%3Afalse%2C%22enabledFeatures%22%3A%22uhf_retailstore2%3A1%2CUhfPb%3A1%2CUhfUsePh%3A1%2CUseModuleTitleFromResolutionDocument%3A1%2CEnableLocaleDetection%3A1%2Cdisable_edge_crossorigin_attribute_script%3A1%2CUhfSwp%3A1%2Cenable_sasslib_minification_runtime%3A1%2Ccore_use_css_from_sp%3A1%2Ccore_cookiecompliance_enabled%3A1%2CMwfCss_1_22_4%3A1%2CDisableRobotsCacheSetting%3A1%2Ccore_akamai_im_enabled%3A1%2Ccoreui_hero_image_resize_90%3A1%2Cuhf_as_iris%3A1%2Ccore_statics_afs%3A1%2Ccore_use_coreui_mwf%3A1%2Ccoreui_makeimagebackgroundtransparent%3A1%2Ccore_render_assetid_primary%3A1%2CSetPicassoTimeOutTo10%3A1%2Cf_audiencemanager_disabled%3A1%2Ccore_BypassJWTValidation%3A1%2Ccore_revert_require_change%3A1%2CMSADisableForceSignin%3A1%2Cuse_assets_onestore_for_mwf_fonts%3A1%2Ccore_disableAADAtBeginRequest%3A1%2CDisableToSkipMarketdetectionforUknownRoutes%3A1%2Cf_video_uselegacyservice%3A1%2Csr_disable_cc%3A1%2CDisablePicassoCaching%3A1%22%2C%22isOneRf%22%3Atrue%2C%22isCorpNet%22%3Afalse%2C%22dataVersion%22%3A%221%2F12%2F2018%2012%3A07%3A01%20PM%20%2B00%3A00%22%2C%22serviceName%22%3A%22marketingsites-wcus-prod%22%2C%22metaTags%22%3A%7B%7D%2C%22scripts%22%3A%22Optimizely%2CClickTale%2CAudienceManager%22%7D%27&-behavior=0&*baseType=%27Ms.Content.PageView%27&*cookieEnabled=true&*isJs=true&*title=%27Microsoft%20-%20Official%20Home%20Page%27&*isLoggedIn=false&*serverImpressionGuid=%27727b9981-7e28-48ce-ac30-510b0230b9ac%27&ext-app-env=%27onerf_prod%27&ext-app-expId=%27EX%3Amuidflt294cf%2CEX%3Amuidflt295cf%2CEX%3Axboxcontentondesktop%2CEX%3Aopenxbl%27&ext-javascript-ver=%271.1%27&ext-javascript-libVer=%274.2.4%27&ext-javascript-domain=%27www.microsoft.com%27&ext-javascript-userConsent=false&ext-user-localId=%27t%3A3D9C59B09A4967113A9252C89B176624%27&$mscomCookies=true script
-http://www.microsoft.com/ https://web.vortex.data.microsoft.com/collect/v1?$mscomCookies=true&ext-javascript-msfpc=%27GUID%3De35327e3b1de4fbaa19cde313cb7bb65%26HASH%3De353%26LV%3D201801%26V%3D4%26LU%3D1516016067118%27 script
-http://www.microsoft.com/ https://mem.gfx.ms/me/MeControl/9.1.17346.1/en-US/meBoot.min.js script
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RW6XQs?ver=6b7f&q=90&m=6&h=276&w=494&b=%23FFFFFFFF&l=f&o=t&aim=true image
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RWfbJT?ver=8259&q=90&m=6&h=276&w=494&b=%23FFFFFFFF&l=f&o=t&aim=true image
-http://www.microsoft.com/ https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE1xHWh other
-http://www.microsoft.com/ https://a3698060313.cdn.optimizely.com/client_storage/a3698060313.html html
-http://www.microsoft.com/ https://logx.optimizely.com/log/event text
-http://www.microsoft.com/ https://logx.optimizely.com/log/decision text
-http://www.microsoft.com/ https://www.microsoft.com/en-us/mscomhp/onerf/MeSilentPassport html
-http://www.microsoft.com/ https://mem.gfx.ms/me/MeControl/9.1.17346.1/en-US/meCore.min.js script
-http://www.microsoft.com/ https://web.vortex.data.microsoft.com/collect/v1?$mscomCookies=true&ext-javascript-msfpc=%27GUID%3De35327e3b1de4fbaa19cde313cb7bb65%26HASH%3De353%26LV%3D201801%26V%3D4%26LU%3D1516016067118%27 script
-http://www.microsoft.com/ https://statics-marketingsites-wcus-ms-com.akamaized.net/_h/9ae23327/mscom.statics/externalscripts/mscomhp/audiencemanager.js script
-http://www.microsoft.com/ https://www.microsoft.com/store/buy/cartcount html
-http://www.microsoft.com/ https://c.go-mpulse.net/boomerang/9SLYA-PCQKP-CU56T-D2UD9-N4WJG script
-http://www.microsoft.com/ https://web.vortex.data.microsoft.com/collect/v1 script
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RWbZ9R?ver=ab37&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=579&y=179&s=1541&d=866&aim=true image
-http://www.microsoft.com/ https://cdnssl.clicktale.net/www32/ptc/755cc4ab-c4bf-46d8-a608-d3c5d66fabac.js script
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1JuWf?ver=36a1&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=931&y=254&s=1189&d=668&aim=true image
-http://www.microsoft.com/ https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1IClv?ver=54f3&q=90&m=8&h=303&w=539&b=%23FFFFFFFF&l=f&x=101&y=49&s=1716&d=964&aim=true image
-http://www.microsoft.com/ https://c1.microsoft.com/c.gif?DI=4050&did=1&t= image
-http://www.microsoft.com/ https://cdnssl.clicktale.net/www/tc/crossdomainInclCEC.html html
-http://www.microsoft.com/ https://c.go-mpulse.net/boomerang/config.js?key=9SLYA-PCQKP-CU56T-D2UD9-N4WJG&d=www.microsoft.com&t=5053387&v=1.405.1475087321&if=&sl=0&si=ha112gdcxsb-NaN&plugins=ConfigOverride,PageParams,AutoXHR,SPA,Angular,Backbone,Ember,History,RT,CrossDomain,BW,NavigationTiming,ResourceTiming,Memory,CACHE_RELOAD,Errors,TPAnalytics,LOGN script
-http://www.microsoft.com/ https://dpm.demdex.net/id?d_visid_ver=2.3.0&d_fieldgroup=MC&d_rtbd=json&d_ver=2&d_orgid=EA76ADE95776D2EC7F000101%40AdobeOrg&d_nsid=0&ts=1516016070990 script
-http://www.microsoft.com/ https://login.live.com/login.srf?wa=wsignin1.0&rpsnv=13&checkda=1&rver=6.7.6643.0&wp=MBI_SSL&wreply=https%3a%2f%2fwww.microsoft.com%2fen-us%2fmscomhp%2fonerf%2fMeSilentPassport%3fSilentAuth%3d1&lc=1033&id=74335 html
-http://www.microsoft.com/ https://login.live.com/me.srf?wa=wsignin1.0&wreply=https%3A%2F%2Fwww.microsoft.com&uaid=40cd8610-048b-43e1-5765-de382a2c7823&partnerId=mshomepage html
-http://www.microsoft.com/ https://cdnssl.clicktale.net/www32/pcc/755cc4ab-c4bf-46d8-a608-d3c5d66fabac.js?DeploymentConfigName=Release_20171214&Version=1 script
-http://www.microsoft.com/ https://mscom.demdex.net/dest5.html?d_nsid=0 html
-http://www.microsoft.com/ https://cdnssl.clicktale.net/www/WR-latest.js script
-http://www.microsoft.com/ https://cdnssl.clicktale.net/www/tc/monitor-latest.js script
-http://www.microsoft.com/ https://dpm.demdex.net/id?d_visid_ver=2.3.0&d_fieldgroup=AAM&d_rtbd=json&d_ver=2&d_orgid=EA76ADE95776D2EC7F000101%40AdobeOrg&d_nsid=0&d_mid=61898491864739142243808492865263618691&d_blob=6G1ynYcLPuiQxYZrsz_pkqfLG9yMXBpb2zX5dvJdYQJzPXImdj0y&d_cid_ic=MSFPC%01e35327e3b1de4fbaa19cde313cb7bb65%012&d_cid_ic=MC1%01e35327e3b1de4fbaa19cde313cb7bb65%012&ts=1516016072655 script
-http://www.microsoft.com/ https://mscom.demdex.net/event?_ts=1516016071104 script
-http://www.microsoft.com/ https://www.microsoft.com/en-us/mscomhp/onerf/MeSilentPassport?SilentAuth=1 html
-http://www.microsoft.com/ https://cdnssl.clicktale.net/www/ChangeMonitor-latest.js script
-http://www.microsoft.com/ https://c.bing.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=74BCC402E5B44A05A9938305D6E42D65&RedC=c1.microsoft.com&MXFR=3D9C59B09A4967113A9252C89B176624 image
-http://www.microsoft.com/ https://c1.microsoft.com/c.gif?DI=4050&did=1&t=&ctsa=mr&CtsSyncId=74BCC402E5B44A05A9938305D6E42D65&MUID=3D9C59B09A4967113A9252C89B176624 image
-http://www.microsoft.com/ https://cm.everesttech.net/cm/dd?d_uuid=61437516830311235833782533879557399436 other
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=411&dpuuid=WlyRygAAA0YIL3Hb image
-http://www.microsoft.com/ https://ing-district.clicktale.net/ctn_v2/auth/?pid=1001&as=1&m=1&740295596&subsid=233396&msgsize=10 script
-http://www.microsoft.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/968413686/?value=0&guid=ON&script=0&data=aam=4933391 image
-http://www.microsoft.com/ https://auth.gfx.ms/16.000.27621.00/MeControl.js script
-http://www.microsoft.com/ https://su.addthis.com/red/usync?pid=16&puid=61437516830311235833782533879557399436&url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D420%26dpuuid%3D%7B%7Buid%7D%7D text
-http://www.microsoft.com/ https://conductor.clicktale.net/monitor?t=init&p=162&2=6351801598271513&v=1.4.11 text
-http://www.hao123.com/ http://www.hao123.com/ html
-http://www.microsoft.com/ https://conductor.clicktale.net/monitor?t=preinit&p=162&2=6351801598271513&v=1.4.11&7=https%3A%2F%2Fwww.microsoft.com%2Fen-us%2F&3=7688328177623393&4=6065671695959868&5=0 text
-http://www.hao123.com/ http://www.hao123.com/wise_test.php html
-http://www.microsoft.com/ https://aa.agkn.com/adscores/g.pixel?sid=9211132908&aam=61437516830311235833782533879557399436 other
-http://www.hao123.com/ http://m.hao123.com/?vit=h123&from=3w123 html
-http://www.hao123.com/ https://m.hao123.com/?vit=h123&from=3w123 html
-http://www.microsoft.com/ https://ib.adnxs.com/getuid?https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D358%26dpuuid%3D%24UID image
-http://www.microsoft.com/ https://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=61437516830311235833782533879557399436&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d61437516830311235833782533879557399436 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/css/index/icon_c04c63d.css css
-http://www.microsoft.com/ https://pixel.tapad.com/idsync/ex/receive?partner_id=ADB&partner_url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=61437516830311235833782533879557399436 other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/pkg/page/index/index.tpl_aio_8a43bb3.css css
-http://www.microsoft.com/ https://idsync.rlcdn.com/365868.gif?partner_uid=61437516830311235833782533879557399436 image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=420&dpuuid=5a5c91cac3a3cb26 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/nomod/flexible_cbe608e.js script
-http://www.microsoft.com/ https://d.turn.com/r/dd/id/L2NzaWQvMS9jaWQvMjM2NTYzMjkvdC8y/url/https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D470%26dpuuid%3D%24!%7BTURN_UUID%7D other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/mod_2b1d325.js script
-http://www.microsoft.com/ https://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=61437516830311235833782533879557399436&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d61437516830311235833782533879557399436&mm_bnc&mm_bct image
-http://www.microsoft.com/ https://pixel.tapad.com/idsync/ex/receive/check?partner_id=ADB&partner_url=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=61437516830311235833782533879557399436 other
-http://www.hao123.com/ https://m.hao123.com/static/img/logo/logo-2.0.png image
-http://www.microsoft.com/ https://www.google.com/ads/user-lists/968413686/?value=0&guid=ON&script=0&data=aam=4933391&cdct=2&is_vtc=1&random=915516451 image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=21&dpuuid=163911502571000811370 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/zepto_7eb941e.js script
-http://www.microsoft.com/ https://idsync.rlcdn.com/365868.gif?partner_uid=61437516830311235833782533879557399436&redirect=1 image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=470&dpuuid=4145161476680044720 image
-http://www.microsoft.com/ https://c.s-microsoft.com/favicon.ico?v2 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/vue_fbd12c9.js script
-http://www.microsoft.com/ https://a.collective-media.net/datapair?net=ab&id=61437516830311235833782533879557399436&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D1177%26dpuuid%3D%7B%24uid%7D other
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=269&dpuuid=e6e65a5c-8bc6-4c00-90bf-eecc01b64382&ddsuuid=61437516830311235833782533879557399436 image
-http://www.hao123.com/ https://m.hao123.com/static/img/logo-menu.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=477&dpuuid=c6c43f14545178b0e003bf6c1f55749f6b6979961e1581664bfbb585fed7f2a8b0da87c991749652 image
-http://www.microsoft.com/ https://dp2.33across.com/ps/?pid=897&random=1356542846 other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/index/taboo_7decb35.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/kuaidi083002.png image
-http://www.onclkds.com/ http://www.onclkds.com/ html
-http://www.microsoft.com/ https://c.bing.com/c.gif?uid=61437516830311235833782533879557399436&Red3=MSAdobe_pd image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/icon/weath/cloudy_a0964f3.png image
-http://www.onclkds.com/ http://www.onclkds.com/style/style.css css
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=adobe_dmp&google_cm html
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/static/img/newzx/3b719e6e122565e45cfc06eeee89af0f.PNG image
-http://www.onclkds.com/ http://fonts.googleapis.com/css?family=PT+Sans&subset=latin,cyrillic-ext css
-http://www.microsoft.com/ https://rtd.tubemogul.com/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/iscroll-lite5_59fbd1e.js script
-http://www.onclkds.com/ http://www.googleadservices.com/pagead/conversion.js script
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=601&dpuuid=72249761963008&random=1516016076 image
-http://www.onclkds.com/ https://www.google.com/recaptcha/api.js script
-http://www.hao123.com/ https://m.hao123.com/static/img/xingzuo20171026-56.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/feiji083002.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=1957&dpuuid=3D9C59B09A4967113A9252C89B176624 image
-http://www.onclkds.com/ http://www.onclkds.com/images/main.png image
-http://www.hao123.com/ https://m.hao123.com/static/webapp/index/img/default.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=771&dpuuid=CAESEEgdQ-inkSDV5FTnEl_QTbQ&google_cver=1 image
-http://www.onclkds.com/ http://fonts.gstatic.com/s/ptsans/v9/CWlc_g68BGYDSGdpJvpktgLUuEpTyoUstqEm5AMlJo4.woff2 font
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/lib/swiper_4bb3bcc.js script
-http://www.microsoft.com/ https://navdmp.com/req?adID=61437516830311235833782533879557399436 html
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/pkg/page/index/index.tpl_aio_ee35128.js script
-http://www.onclkds.com/ https://www.gstatic.com/recaptcha/api2/v1514934548259/recaptcha__en.js script
-http://www.microsoft.com/ https://analytics.twitter.com/i/adsct?p_user_id=61437516830311235833782533879557399436&p_id=38594 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/icon/search_985e3e7.png image
-http://www.onclkds.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/995032169/?random=1516015919997&cv=8&fst=1516015919997&num=1&label=_iK6CP-_7xcQ6fi72gM&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&rfmt=3&fmt=4 script
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/index/erjiicon/dushu_0b2a37e.png image
-http://www.onclkds.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/983473429/?random=1516015920022&cv=8&fst=1516015919997&num=2&label=0_cMCPultwYQlbr61AM&guid=ON&eid=376635470%2C659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&rfmt=3&fmt=4 script
-http://www.microsoft.com/ https://rtd-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D other
-http://www.hao123.com/ https://as1.m.hao123.com/bwofcvxcvzdec.js script
-http://www.microsoft.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252Chttps%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253D185c98e1-f9e8-11e7-97eb-0242dbfbd28c html
-http://www.onclkds.com/ https://www.google.com/ads/user-lists/983473429/?random=1516015920022&cv=8&fst=1516014000000&num=2&label=0_cMCPultwYQlbr61AM&guid=ON&eid=376635470%2C659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&fmt=3&cdct=2&is_vtc=1&random=3745259780&rmt_tld=0&ipr=y image
-http://www.hao123.com/ https://m.hao123.com/static/img/ditu083002.png image
-http://www.microsoft.com/ https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537072980%26val%3D__EFGSURFER__.__EFGCK__ html
-http://www.hao123.com/ https://m.hao123.com/static/img/tianqi20171026-56.png image
-http://www.onclkds.com/ https://www.google.com/ads/user-lists/995032169/?random=1516015919997&cv=8&fst=1516014000000&num=1&label=_iK6CP-_7xcQ6fi72gM&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=http%3A%2F%2Fwww.onclkds.com%2F&fmt=3&cdct=2&is_vtc=1&random=2236444407&rmt_tld=0&ipr=y image
-http://www.hao123.com/ https://hm.baidu.com/hm.js?48c57cebc84275afcff127cd20c37e4b script
-http://www.microsoft.com/ https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fpixel.everesttech.net%2F1x1%3F html
-http://www.onclkds.com/ http://www.onclkds.com/favicon.ico image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=782&dpuuid=WlyRygAAA0YIL3Hb image
-http://www.hao123.com/ https://m.hao123.com/static/img/huangli083002.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/weizhang083002.png image
-http://www.microsoft.com/ https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fib.adnxs.com%2Fpxj%3Faction%3Dsetuid(%27__EFGSURFER__.__EFGCK__%27)%26bidder%3D51%26seg%3D2634060der%3D51%26seg%3D2634060 html
-http://www.hao123.com/ https://hao123.baidu.com/static/mapping/bd.php?type=gif image
-http://www.microsoft.com/ https://match.adsrvr.org/track/cmb/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252Chttps%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253D185c98e1-f9e8-11e7-97eb-0242dbfbd28c html
-http://www.microsoft.com/ https://idpix.media6degrees.com/orbserv/hbpix?pixId=16873&pcv=70&ptid=66&tpuv=01&tpu=61437516830311235833782533879557399436 other
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/alog.min.js?v=-17547-17547 script
-http://www.hao123.com/ https://m.hao123.com/static/img/yingxun20171026-56.png image
-http://www.microsoft.com/ https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fexpires%3D30%26nid%3D2181%26put%3D__EFGSURFER__.__EFGCK__%26v%3D11782 html
-http://www.hao123.com/ https://m.hao123.com/static/img/huochepiao083002.png image
-http://www.microsoft.com/ https://cdn.navdmp.com/req?adID=61437516830311235833782533879557399436 script
-http://www.microsoft.com/ https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTI2NjgmdGw9NDMyMDA%3D%26piggybackCookie%3D__EFGSURFER__.__EFGCK__ html
-http://www.hao123.com/ https://m.hao123.com/static/img/jiudian083002.png image
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V2x5UnlnQUFBMFlJTDNIYg&url=/1/gr%3furl=https%253A%252F%252Fpixel.everesttech.net%252F1x1%253F html
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V2x5UnlnQUFBMFlJTDNIYg&url=/1/gr%3furl=https%253A%252F%252Fus-u.openx.net%252Fw%252F1.0%252Fsd%253Fid%253D537072980%2526val%253D__EFGSURFER__.__EFGCK__ html
-http://www.hao123.com/ https://m.hao123.com/static/img/jieming20171026-56.png image
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V2x5UnlnQUFBMFlJTDNIYg&url=/1/gr%3furl=https%253A%252F%252Fib.adnxs.com%252Fpxj%253Faction%253Dsetuid(%2527__EFGSURFER__.__EFGCK__%2527)%2526bidder%253D51%2526seg%253D2634060der%253D51%2526seg%253D2634060 html
-http://www.hao123.com/ https://as1.m.hao123.com/oimqag.js script
-http://www.microsoft.com/ https://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=d33a72a3-7ea5-4b82-a778-9f93fb01a6ba&ttd_puid=%2Chttps%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D185c98e1-f9e8-11e7-97eb-0242dbfbd28c other
-http://www.hao123.com/ https://m.hao123.com/static/p.gif image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=992&dpuuid=1s05whesn6nex image
-http://www.hao123.com/ https://wap.hao123.com/image/wise-vue/index/erji-novel.png image
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V2x5UnlnQUFBMFlJTDNIYg&url=/1/gr%3furl=https%253A%252F%252Fpixel.rubiconproject.com%252Ftap.php%253Fexpires%253D30%2526nid%253D2181%2526put%253D__EFGSURFER__.__EFGCK__%2526v%253D11782 html
-http://www.hao123.com/ https://wap.hao123.com/image/wise-vue/index/erji-funny.png image
-http://www.microsoft.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=aam html
-http://www.hao123.com/ https://m.hao123.com/ html
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V2x5UnlnQUFBMFlJTDNIYg&url=/1/gr%3furl=https%253A%252F%252Fimage2.pubmatic.com%252FAdServer%252FPug%253Fvcode%253Dbz0yJnR5cGU9MSZjb2RlPTI2NjgmdGw9NDMyMDA%253D%2526piggybackCookie%253D__EFGSURFER__.__EFGCK__ html
-http://www.hao123.com/ https://m.hao123.com/hao123_api/page/getRootData?vit=h123&from=3w123 script
-http://www.microsoft.com/ https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fpixel.everesttech.net%252F1x1%253F&google_gid=CAESEEX06cykgc7_lugHcwl5uSE&google_cver=1 other
-http://www.hao123.com/ https://m.hao123.com/static/img/fenghuang20171024-56.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=540&dpuuid=185c98e1-f9e8-11e7-97eb-0242dbfbd28c image
-http://www.hao123.com/ https://m.hao123.com/static/img/tengxun20171024-56.png image
-http://www.microsoft.com/ https://rtd.tubemogul.com/migrate_et3/ other
-http://www.hao123.com/ https://m.hao123.com/static/img/souhu20171024-56.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=903&dpuuid=d33a72a3-7ea5-4b82-a778-9f93fb01a6ba image
-http://www.hao123.com/ https://m.hao123.com/static/img/wangyi20171024-56.png image
-http://www.microsoft.com/ https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fus-u.openx.net%252Fw%252F1.0%252Fsd%253Fid%253D537072980%2526val%253D__EFGSURFER__.__EFGCK__&google_gid=CAESEEX06cykgc7_lugHcwl5uSE&google_cver=1 other
-http://www.hao123.com/ https://m.hao123.com/static/img/suning_20170907.png image
-http://www.microsoft.com/ https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fib.adnxs.com%252Fpxj%253Faction%253Dsetuid(%2527__EFGSURFER__.__EFGCK__%2527)%2526bidder%253D51%2526seg%253D2634060der%253D51%2526seg%253D2634060&google_gid=CAESEEX06cykgc7_lugHcwl5uSE&google_cver=1 other
-http://www.hao123.com/ https://m.hao123.com/static/img/wapchezhijia_1219.png image
-http://www.microsoft.com/ https://pixel.everesttech.net/1x1 image
-http://www.microsoft.com/ https://rtd-tm.everesttech.net/migrate_et3/ other
-http://www.hao123.com/ https://m.hao123.com/static/img/xiecheng20171121wx.png image
-http://www.microsoft.com/ https://rp.gwallet.com/r1/cm/p50 other
-http://www.microsoft.com/ https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fpixel.rubiconproject.com%252Ftap.php%253Fexpires%253D30%2526nid%253D2181%2526put%253D__EFGSURFER__.__EFGCK__%2526v%253D11782&google_gid=CAESEEX06cykgc7_lugHcwl5uSE&google_cver=1 other
-http://www.hao123.com/ https://m.hao123.com/static/img/wb.PNG image
-http://www.microsoft.com/ https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fimage2.pubmatic.com%252FAdServer%252FPug%253Fvcode%253Dbz0yJnR5cGU9MSZjb2RlPTI2NjgmdGw9NDMyMDA%253D%2526piggybackCookie%253D__EFGSURFER__.__EFGCK__&google_gid=CAESEEX06cykgc7_lugHcwl5uSE&google_cver=1 other
-http://www.hao123.com/ https://m.hao123.com/static/img/jingdong20171024-56.png image
-http://www.hao123.com/ https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=466656377&si=48c57cebc84275afcff127cd20c37e4b&v=1.2.27&lv=1&ct=!!&tt=hao123%E5%AF%BC%E8%88%AA-%E4%B8%8A%E7%BD%91%E4%BB%8E%E8%BF%99%E9%87%8C%E5%BC%80%E5%A7%8B&sn=60271 image
-http://www.microsoft.com/ https://pixel.everesttech.net/1/gr?url=https%3A%2F%2Fdsum-sec.casalemedia.com%2Frum%3Fcm_dsp_id%3D71%26external_user_id%3D__EFGSURFER__.__EFGCK__ html
-http://www.hao123.com/ https://hdj.baidu.com/dianj/?u=default&ie=1&tm=512&cm=512&md=1&at=3&v=naked&cs=&pk=&act=LP&w=&prod=hao123_wise&h=&os=android&appid=f9b6199b&adstrade=&n=40&q=f9b6199b_cpr&sn=B381A494A3AABDC7B0A4AE7F9EACB927&callback=callback_json_1 script
-http://www.microsoft.com/ https://rp.gwallet.com/r1/cm/p50?check_uid_cookie other
-http://www.hao123.com/ https://m.hao123.com/static/img/cxb_taobao.PNG image
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=everest&google_cm&google_sc&ev_rs=1&google_hm=V2x5UnlnQUFBMFlJTDNIYg&url=/1/gr%3furl=https%253A%252F%252Fdsum-sec.casalemedia.com%252Frum%253Fcm_dsp_id%253D71%2526external_user_id%253D__EFGSURFER__.__EFGCK__ html
-http://www.hao123.com/ https://m.hao123.com/static/img/tm.PNG image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=1127&dpuuid=AB-k5dDCuZ7VGdKjq2ZyfpPWw&redir=http%3A%2F%2Frs.gwallet.com%2Fr1%2Fucm%3Fid%3D%24%7BDD_UUID%7D%26r1s%3D8mz96wq8hcqippnyq6isqr79d8qxyafjadragwacpcokxoays3mo other
-http://www.hao123.com/ https://m.hao123.com/static/img/chuangxinbanyiche.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/cx_remenyouxi.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/juhuasuan1222icon.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/renrencheicon_9.18.png image
-http://www.hao123.com/ https://m.hao123.com/static/img/youxinicon_20170913.png image
-http://www.microsoft.com/ https://cm.everesttech.net/cm/ax?cookieid=&ev_rs=1&url=/1/gr%3Furl=https%253A%252F%252Fdsum-sec.casalemedia.com%252Frum%253Fcm_dsp_id%253D71%2526external_user_id%253D__EFGSURFER__.__EFGCK__&google_gid=CAESEEX06cykgc7_lugHcwl5uSE&google_cver=1 other
-http://www.hao123.com/ https://m.hao123.com/static/img/wuxianguaziershouche.png image
-http://www.microsoft.com/ https://p.rfihub.com/cm?in=1&pub=7085 other
-http://www.hao123.com/ https://www.hao123.com/images/track.gif?hjf=hao123wise&type=KTN&code=0&tn=&src= image
-http://www.microsoft.com/ https://pixel.advertising.com/ups/28/sync?uid=61437516830311235833782533879557399436&_origin=1&redir=true other
-http://www.hao123.com/ https://gss2.bdstatic.com/5eZ1dDebRNRTm2_p8IuM_a/img/1L/Aw/2F/mk/ch/o/blank.gif image
-http://www.hao123.com/ https://m.hao123.com/static/img/dongfangcaifu0106.png image
-http://www.microsoft.com/ https://pixel.quantserve.com/pixel/p-vj4AYjBqd6VJ2.gif?idmatch=0 image
-http://www.hao123.com/ https://m.hao123.com/static/img/wangzhidaquan.gif image
-http://www.hao123.com/ https://m.hao123.com/static/img/youxi20170914icon.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=1121&dpuuid=697565378232506189 image
-http://www.microsoft.com/ https://pixel.advertising.com/ups/28/sync?uid=61437516830311235833782533879557399436&_origin=1&redir=true&verify=true other
-http://www.hao123.com/ https://m.hao123.com/static/img/cx_shipin.png image
-http://www.microsoft.com/ https://fei.pro-market.net/engine?site=141472;size=1x1;mimetype=img;csync=di;du=67 image
-http://www.microsoft.com/ https://cms.analytics.yahoo.com/cms?partner_id=ADOBE html
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=1175&dpuuid=3Gng-tA5tv_EarT72G74qNxt4vrEauOgizH9FyLo image
-http://www.microsoft.com/ https://ml314.com/utsync.ashx?eid=50112&et=0&return=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D22052%26dpuuid%3D[PersonID] image
-http://www.microsoft.com/ https://adobe-sync.dotomi.com/adobe/match?nuid=61437516830311235833782533879557399436&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D other
-http://www.hao123.com/ https://m.hao123.com/static/img/cx_youliao.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=6835&dpuuid=UP12805ab6-f9e8-11e7-95e8-067c24bf1fe4 image
-http://www.hao123.com/ https://m.hao123.com/static/img/cx_gaoxiao.png image
-http://www.microsoft.com/ https://ps.eyeota.net/match?bid=6j5b2cv&uid=61437516830311235833782533879557399436&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30064%26dpuuid%3D%7BUUID_6j5b2cv%7D other
-http://www.hao123.com/ https://m.hao123.com/static/img/tianqiwuxian1111.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=575&dpuuid=8179959167547359466 image
-http://www.hao123.com/ https://m.hao123.com/static/browse.gif?pos=page_view&page=index_cxv2&level=1&ver=android&t=1516015892394 image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=30646?dpuuid=E0 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/static/html5-index/falls/img/addtohome_d10e3b1.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=22052&dpuuid=5978151396634796739 image
-http://www.hao123.com/ https://cpro.baidustatic.com/cpro/ui/pr.js script
-http://www.microsoft.com/ https://ps.eyeota.net/match/bounce/?bid=6j5b2cv&uid=61437516830311235833782533879557399436&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30064%26dpuuid%3D%7BUUID_6j5b2cv%7D image
-http://www.hao123.com/ https://www.hao123.com/api/searchrecom?c=6F6A80C14D81E51F12C23108F0320EDF&type=wise&dataType=rs&pageid=index_cxv2&cue=1&qnum=15&sid=10001&u_query=&_=1516015893680&callback=jsonp1 html
-http://www.microsoft.com/ https://rs.gwallet.com/r1/ucm?id=61437516830311235833782533879557399436&r1s=8mz96wq8hcqippnyq6isqr79d8qxyafjadragwacpcokxoays3mo image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/static/img/newzx/8.31qwerty46.jpg image
-http://www.microsoft.com/ https://adobe-sync.dotomi.com/adobe/match?dtm_test=e6adb7c16e508fd&nuid=61437516830311235833782533879557399436&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eR1cXSg2QdV5wybn9fN2DJv/assets/wise-vue/img/icon/weath_bg/cloudy_7474b6e.jpg image
-http://www.microsoft.com/ https://cm.everesttech.net/cm/yh other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115DAI24.jpg image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=30064&dpuuid=2JIm4hjkYmCIulHr4MPakSDvx6zlDG3QMlGkybxwl6Ug image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai17.jpg image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai26.jpg image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=19360&dpuuid=61437516830311235833782533879557399436 image
-http://www.hao123.com/ https://m.hao123.com/static/img/yingxin20171228.png image
-http://www.hao123.com/ https://pos.baidu.com/s?hei=76&wid=360&di=u3106706&ltu=https%3A%2F%2Fm.hao123.com%2F%3Fvit%3Dh123%26from%3D3w123&dri=0&ccd=24&ps=792x0&chi=3&dai=1&pcs=360x512&dc=2&exps=114032&col=en-US&tlm=1516015892&dtm=HTML_POST&prot=2&drs=3&tcn=1516015892&par=360x512&cmi=0&cja=false&dis=0&cce=true&cdo=0&cfv=0&cpl=0&tpr=1516015892441&psr=360x512&cec=UTF-8&ari=2&ti=hao123%E5%AF%BC%E8%88%AA-%E4%B8%8A%E7%BD%91%E4%BB%8E%E8%BF%99%E9%87%8C%E5%BC%80%E5%A7%8B&ant=0&pis=-1x-1&pss=360x792 other
-http://www.microsoft.com/ https://ds.reson8.com/adb-ext.gif?puid=61437516830311235833782533879557399436 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai01.jpg image
-http://www.microsoft.com/ https://mm.markandmini.com/Pixel/8tthgyykyv image
-http://www.hao123.com/ https://m.hao123.com/r/image/2017-12-13/988691ad3db1c4b8a628384fb31eae11.png image
-http://www.microsoft.com/ https://ads.scorecardresearch.com/p?c1=9&c2=6034944&c3=2&cs_xi=61437516830311235833782533879557399436&rn=1516016072452&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D73426%26dpuuid%3D61437516830311235833782533879557399436 other
-http://www.hao123.com/ https://m.hao123.com/static/img/yangyabang1226.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=57282&dpuuid=D290285E2C95CF23A753E31A07DD9AC0 image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai20.jpg image
-http://www.microsoft.com/ https://bttrack.com/dmp/adobe/user?dd_uuid=61437516830311235833782533879557399436 html
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai19.jpg image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai06.jpg image
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai03.jpg image
-http://www.microsoft.com/ https://ads.scorecardresearch.com/p2?c1=9&c2=6034944&c3=2&cs_xi=61437516830311235833782533879557399436&rn=1516016072452&r=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D73426%26dpuuid%3D61437516830311235833782533879557399436 other
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/180115dai02.jpg image
-http://www.hao123.com/ https://gss0.bdstatic.com/5eN1cXSg2QdV5wybn9fN2DJv/static/img/newzx/7.3qwerty42.jpg image
-http://www.hao123.com/ https://m.hao123.com/hao123_api/osc/tasks?uri=%2F script
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/5w3jqr4k?redir=https%3A%2F%2Fcm.g.doubleclick.net%2Fpixel%3Fgoogle_nid%3Dg8f47s39e399f3fe%26google_push%26google_sc%26google_hm%3D%24%7BTM_USER_ID_BASE64ENC_URLENC%7D other
-http://www.hao123.com/ https://graph.baidu.com/mms/graph/static/resource/sdk/mobile.js script
-http://www.mail.ru/ http://www.mail.ru/ html
-http://www.hao123.com/ https://m.hao123.com/hao123_api/osc/report script
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D7941%26nid%3D2243%26put%3D%24%7BUSER_ID%7D%26expires%3D90 other
-http://www.mail.ru/ http://mail.ru/ html
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=49276&dpuuid=8be56530-59cd-46fa-9268-04a7cb4f0d19 image
-http://www.mail.ru/ https://mail.ru/ html
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/j/common-96c24a5c6e.js script
-http://www.microsoft.com/ https://aorta.clickagy.com/pixel.gif?ch=124&cm=61437516830311235833782533879557399436&redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D79908%26dpuuid%3D%7Bvisitor_id%7D script
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/c/splash-e56d572076.css css
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=782&dpuuid=WlyRygAAA0YIL3Hb image
-http://www.hao123.com/ https://as2.m.hao123.com/rdxpgyked?tqu=a.&iup=Z.W&pu=QZXW.aW.&xfg=DPPLO5Zd5Yi5YiI53D6KXYZ538KI5Yi5ZiREP5ZgDXYZ5Y.BNKI5ZgZSXYZ&mdu=Y&be=WTW&fbd=X-X.WX-bcY__X&qjbe=XX_WZ_&bmd=Z.WT-XY&pmu=X&pfy=kwpo3srvw&pdu=W&bue=4XT4X&po=Y&oqo=xwi4b&boe=Z.WT-XY&pue=W&mzf=X&bdaf=Y&bee=Z.WTXWWY&p1=yg7z html
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/j/s-5de2177f83.js script
-http://www.hao123.com/ https://as2.m.hao123.com/ozall/jk?c=d25pZD00ZTcwMDZkODU5NjM1ZmRjAHM9NGU3MDA2ZDg1OTYzNWZkYwB0PTE1MTYwMTU4OTYAc2U9MQBidT00AHByaWNlPVdseVJHQUFMS1VsN2pFcGdXNUlBOGwwc0VBY1JGUVRkQlBfaF9BAGNoYXJnZV9wcmljZT0yOABzaGFyaW5nX3ByaWNlPTI4MDAwAHdpbl9kc3A9NABjaG1kPTEAYmRpZD02RjZBODBDMTREODFFNTFGMTJDMjMxMDhGMDMyMEVERgBjcHJvaWQ9AHdkPTAAdHU9dTMxMDY3MDYAcG9zPTAAYmNobWQ9MAB2PTEAaT04YjZhYzQ1OA image
-http://www.microsoft.com/ https://abp.mxptint.net/sn.ashx html
-http://www.mail.ru/ https://mail.ru/cache script
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=73426&dpuuid=61437516830311235833782533879557399436 image
-http://www.hao123.com/ https://cpro.baidustatic.com/sync.htm?cproid=6F6A80C14D81E51F12C23108F0320EDF%3AFG%3D1 html
-http://www.youth.cn/ http://www.youth.cn/ other
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/i/logo-446a3d251c.flat.png image
-http://www.microsoft.com/ https://sync.ipredictive.com/d/sync/cookie/generic?https://dpm.demdex.net/ibs:dpid=2340&dpuuid=${ADELPHIC_CUID} other
-http://www.hao123.com/ https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_ads_2x.png image
-http://www.mail.ru/ https://r.mradx.net/pictures/BC/AE3D4B.jpg image
-http://www.youth.cn/ http://m.youth.cn/ html
-http://www.hao123.com/ https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_hand_2x.png image
-http://www.microsoft.com/ https://cm.g.doubleclick.net/pixel?google_nid=g8f47s39e399f3fe&google_push&google_sc&google_hm=V2x5UnlnQUFBMFlJTDNIYg== image
-http://www.mail.ru/ https://r.mradx.net/pictures/15/320432.jpg image
-http://www.youth.cn/ http://m.youth.cn/images/20170601mobile_common.css css
-http://www.hao123.com/ https://f10.baidu.com/it/u=351251565,3289309497&fm=76 image
-http://www.mail.ru/ https://r.mradx.net/pictures/5F/C2AC03.jpg image
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/ZMAwryCI?redir=https%3A%2F%2Fdsum-sec.casalemedia.com%2Frum%3Fcm_dsp_id%3D88%26external_user_id%3D%24%7BTM_USER_ID%7D other
-http://www.youth.cn/ http://m.youth.cn/images/20170601mobile_index.css css
-http://www.hao123.com/ https://gss3.bdstatic.com/5foUcz3n1MgCo2Kml5_Y_D3/graph/static/resource/sdk/v1.11.0/mms.js script
-http://www.mail.ru/ https://r.mradx.net/img/3C/86664F.png image
-http://www.youth.cn/ http://m.youth.cn/images/swiper.min.css css
-http://www.mail.ru/ https://r.mradx.net/pictures/17/72F4EB.jpg image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=79908&dpuuid=WlyR0mdQk-ytwplUjYOXZa30 image
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/dp.mobile.min.js?v=-17547-17547 script
-http://www.mail.ru/ https://r.mradx.net/pictures/8C/876483.jpg image
-http://www.microsoft.com/ https://dptr.areyouahuman.com/ping/adobe/%5BPARTNER_USER_ID%5D?rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D58051%26dpuuid%3D%25%25AYAH_UID%25%25 text
-http://www.youth.cn/ http://www.youth.cn/images/jquery-index-1.9.1.js script
-http://www.hao123.com/ https://m.hao123.com/favicon.ico image
-http://www.mail.ru/ https://www.tns-counter.ru/V13a****mail_ru/ru/CP1251/tmsec=mail_main-mobile/ image
-http://www.youth.cn/ http://m.youth.cn/images/20170524zepto.js script
-http://www.microsoft.com/ https://ads.yahoo.com/cms/v1?nwid=10001117525&eid=WlyRygAAA0YIL3Hb&sigv=1&esig=1~99d1a091460eef591992a43a6510269e2c79f3ad text
-http://www.hao123.com/ https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A5136%2C%22netDns%22%3A0%2C%22netTcp%22%3A1009%2C%22srv%22%3A934%2C%22dom%22%3A7519%2C%22loadEvent%22%3A20422%7D&et=87&ja=0&ln=en-us&lo=0&rnd=1049684123&si=48c57cebc84275afcff127cd20c37e4b&v=1.2.27&lv=1 image
-http://www.youth.cn/ http://m.youth.cn/images/20170601mobile_common.js script
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/UH6TUt9n?redir=https%3A%2F%2Fib.adnxs.com%2Fsetuid%3Fentity%3D158%26code%3D%24%7BTM_USER_ID%7D other
-http://www.youth.cn/ http://m.youth.cn/images/swiper_index.js script
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/speed.min.js?v=170721 script
-http://www.youth.cn/ http://m.youth.cn/images/swiper.min.js script
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=75557&dpuuid=R1B342_9E7DF78F_68E8C31&redir=https://abp.mxptint.net/sn.ashx?ak=1 image
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/monkey.mobile.min.js script
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/element.min.js?v=160118 script
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/ny75r2x0?redir=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537148856%26val%3D%24%7BTM_USER_ID%7D other
-http://www.youth.cn/ http://m.youth.cn/images/20170606data_read.js?timestamp script
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/b9pj45k4?redir=https%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D other
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/feature.min.js?v=150727 script
-http://www.mail.ru/ https://r3.mail.ru/k?81e4121baf7286eca0b199916eff4bfd image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=2340&dpuuid=141440d7-f9e8-11e7-83b1-f1c9153fe8a6 image
-http://www.hao123.com/ https://fex.bdstatic.com/hunter/alog/dp.csp.min.js?v=140804 script
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/h0r58thg?redir=https%3A%2F%2Fsync.search.spotxchange.com%2Fpartner%3Fadv_id%3D6409%26uid%3D%24%7BUSER_ID%7D%26img%3D1 other
-http://www.mail.ru/ https://counter.yadro.ru/hit;mail-splash/touch?r;uhttp%3A%2F%2Fm.mail.ru%2f; html
-http://www.youth.cn/ http://m.youth.cn/images/20170606data_get.js script
-http://www.microsoft.com/ https://ib.adnxs.com/setuid?entity=158&code=WlyRygAAA0YIL3Hb html
-http://www.mail.ru/ https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/01.svg image
-http://www.youth.cn/ http://m.youth.cn/qwtx/lbt/201801/W020180112424789493081.jpg image
-http://www.mail.ru/ https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/21.svg image
-http://www.hao123.com/ https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/pms/img/st.gif?ts=9fg&sid=jcg4pvp5t1f&ht=3&fs=577&drt=1981&lt=11076&product_id=9&page_id=9_3252&browser=20&wtt=5220&dns=0&ct=1009&st=1948&tt=4355&dct=16296&olt=16300&_screen=360*512%7C360*512 image
-http://www.microsoft.com/ https://dptr.areyouahuman.com/dptr?dpn=adobe&dpi=%5BPARTNER_USER_ID%5D&aoc=8dcd7710-3487-4f02-ab2b-81ec45d2e49c&rurl=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D58051%26dpuuid%3D8dcd7710-3487-4f02-ab2b-81ec45d2e49c text
-http://www.mail.ru/ https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/05.svg image
-http://www.microsoft.com/ https://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fwww.facebook.com%2Ffr%2Fb.php%3Fp%3D1531105787105294%26e%3D%24%7BTM_USER_ID%7D%26t%3D2592000%26o%3D0 other
-http://www.mail.ru/ https://img.imgsmail.ru/r/weather_new/icons/svg50_outline/57.svg image
-http://www.hao123.com/ https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/pms/img/st.gif?ts=8zr&t=pageview&sid=jcg4pvp5t1f&ver=5&pid=241&px=360*512&page=9_3252&p=9&dv=6&cmd=open&ps=360%2C1002 image
-http://www.mail.ru/ https://ad.mail.ru/adi/100590?rnd=407341088 html
-http://www.youth.cn/ http://m.youth.cn/qwtx/lbt/201801/W020180115314617983742.jpg image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=58051&dpuuid=8dcd7710-3487-4f02-ab2b-81ec45d2e49c image
-http://www.hao123.com/ https://gsp0.baidu.com/5aAHeD3nKhI2p27j8IqW0jdnxx1xbK/tb/pms/img/st.gif?ts=anl&t=feature&sid=jcg4pvp5t1f&dv=4&page=9_3252&p=9&bdrs=y&bxsd=y&opat=y&txsd=y&anim=y&trsi=y&trfm=y&flex=y&3dtr=y&shpe=y&fltr=y&cavs=y&dgdp=y&locs=y&wctem=y&wcsdd=y&wccse=y&wchti=y&wsql=y&natm=y&ustm=y&arra=y&prms=n&xhr2=y&wbgl=y&geol=y&svg=y&work=y&wbsk=y&vido=y&audo=y&hsty=y&file=y&psmg=y&wknf=n&rqaf=y&json=y&flsc=n&i18n=y&cors=y&prog=y&metr=y&becn=y&mcrd=n&esrc=y&WebP-lossy=y&WebP-lossless=y&WebP-alpha=y&WebP-animation=y image
-http://www.mail.ru/ https://ad.mail.ru/adq/?q=3334&q=152408&q=163851&callback=__jsonp_0&_=1516602619440 script
-http://www.youth.cn/ http://m.youth.cn/qwtx/lbt/201801/W020180115315079586015.png image
-http://www.mail.ru/ https://rs.mail.ru/d1102768.gif?rnd=137566674&ts=1516015880 image
-http://www.microsoft.com/ https://pixel.rubiconproject.com/tap.php?v=7941&nid=2243&put=WlyRygAAA0YIL3Hb&expires=90 other
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201710/W020171117635514372684.png image
-http://www.mail.ru/ https://rs.mail.ru/d368066.gif image
-http://www.microsoft.com/ https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WlyRygAAA0YIL3Hb html
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115287687583877.jpg image
-http://www.mail.ru/ https://rs.mail.ru/d902146.gif?rnd=119935562&ts=1516015880 image
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115595457582859.jpg image
-http://www.microsoft.com/ https://cookiex.ngd.yahoo.com/ack?xid=E0&eid=WlyRygAAA0YIL3Hb text
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115289106577376.jpg image
-http://www.mail.ru/ https://rs.mail.ru/d26490428.gif?rnd=407341088&ts=1516015880 image
-http://www.microsoft.com/ https://trc.taboola.com/sg/adobe/1/cm other
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115289712574487.jpg image
-http://www.mail.ru/ https://www.tns-counter.ru/V13b****mail_ru/ru/CP1251/tmsec=mail_main-mobile/ image
-http://www.youth.cn/ http://hm.baidu.com/h.js?969516094b342230ceaf065c844d82f3 script
-http://www.mail.ru/ https://r.mradx.net/pictures/FD/B8CD98.jpg image
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115288398964234.jpg image
-http://www.microsoft.com/ https://pixel.rubiconproject.com/tap.php?cookie_redirect=1&v=7941&nid=2243&put=WlyRygAAA0YIL3Hb&expires=90 image
-http://www.mail.ru/ https://r.mradx.net/pictures/4E/1FE679.jpg image
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115595986684278.jpg image
-http://www.youth.cn/ http://m.youth.cn/qwtx/xxl/201801/W020180115305128369793.jpg image
-http://www.microsoft.com/ https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WlyRygAAA0YIL3Hb&C=1 image
-http://www.mail.ru/ https://r.mradx.net/pictures/DA/329D8E.jpg image
-http://www.youth.cn/ http://news.youth.cn/wzyqk/qdj/201801/W020180108577447318079.jpg image
-http://www.microsoft.com/ https://us-u.openx.net/w/1.0/sd?id=537148856&val=WlyRygAAA0YIL3Hb other
-http://www.mail.ru/ https://counter.yadro.ru/hit;mail-splash/touch?q;r;uhttp%3A%2F%2Fm.mail.ru%2f; image
-http://www.youth.cn/ http://news.youth.cn/wzyqk/qdj/201801/W020180107540632408394.jpg image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=147592?dpuuid=b3e6d2d4-da78-4ae9-9fd2-bff648259f1c-tuct1561753 image
-http://www.mail.ru/ https://r.mradx.net/pictures/18/AE600F.jpg image
-http://www.microsoft.com/ https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA=&piggybackCookie=WlyRygAAA0YIL3Hb html
-http://www.youth.cn/ http://pb1.qujishu.com/vrdicaeb8x.js script
-http://www.mail.ru/ https://rs.mail.ru/d905013.gif?sz=12&rnd=517351913&ts=1516015880&sz=12 image
-http://www.youth.cn/ http://pb1.qujishu.com/avnekderkycx.js script
-http://www.mail.ru/ https://rs.mail.ru/d1315113.gif?rnd=179802138&ts=1516015880 image
-http://www.microsoft.com/ https://mid.rkdms.com/bct?pid=8bc436aa-e0fc-4baa-9c9a-06fbeca87826&puid=61437516830311235833782533879557399436&_ct=img other
-http://www.microsoft.com/ https://www.facebook.com/fr/b.php?p=1531105787105294&e=WlyRygAAA0YIL3Hb&t=2592000&o=0 image
-http://www.youth.cn/ http://news.youth.cn/images/20170601header_menu.png image
-http://www.mail.ru/ https://r.mradx.net/pictures/64/B5A24B.png image
-http://www.microsoft.com/ https://us-u.openx.net/w/1.0/sd?cc=1&id=537148856&val=WlyRygAAA0YIL3Hb image
-http://www.youth.cn/ http://news.youth.cn/images/20170601header_logo.png image
-http://www.mail.ru/ https://r.mradx.net/pictures/6E/D719C5.png image
-http://www.microsoft.com/ https://dpm.demdex.net/ibs:dpid=129099&dpuuid=b47433d4e4c159545eba472fc398fc3f image
-http://www.mail.ru/ https://rs.mail.ru/d1315113.gif?rnd=179802138&ts=1516015880&sz=12 image
-http://www.youth.cn/ http://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=1838334634&si=969516094b342230ceaf065c844d82f3&v=1.2.27&lv=1&ct=!!&tt=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&sn=60275 image
-http://www.mail.ru/ https://r.mradx.net/pictures/B1/0BFD9D.jpg image
-http://www.youth.cn/ http://cl5.webterren.com/webdig.js?z=36 script
-http://www.mail.ru/ https://rs.mail.ru/d28061150.gif?sz=24&rnd=181953086&ts=1516015880&sz=24 image
-http://www.youth.cn/ http://push.zhanzhang.baidu.com/push.js script
-http://www.microsoft.com/ https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WlyRygAAA0YIL3Hb&img=1 other
-http://www.mail.ru/ https://r.mradx.net/img/25/667F80.png image
-http://www.youth.cn/ http://news.youth.cn/images/huidi_pic_banner.jpg image
-http://www.mail.ru/ https://ad.mail.ru/adi/78733?rnd=136657296 html
-http://www.microsoft.com/ https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WlyRygAAA0YIL3Hb&img=1&__user_check__=1&sync_id=40432349-f9e8-11e7-986f-1c210a700001 image
-http://www.youth.cn/ http://news.youth.cn/images/20170601Rectangle_3.png image
-http://www.mail.ru/ https://r.mradx.net/img/54/87A7DF.png image
-http://www.youth.cn/ http://news.youth.cn/images/huiselogo_pic.jpg image
-http://www.mail.ru/ https://rs.mail.ru/pixel/CioI9Zr1C4gBB-ABARCA_v_RAx0PkVxasAHNnD24AcgBoAOfAcICBIU_5FU.gif image
-http://www.youth.cn/ http://pb1.qujishu.com/oimqag.js script
-http://www.mail.ru/ https://rs.mail.ru/d22199634.gif?sz=1&rnd=231636504&ts=1516015880&sz=1 image
-http://www.mail.ru/ https://rs.mail.ru/d27103601.gif?sz=23&rnd=178580626&ts=1516015880&sz=23 image
-http://www.youth.cn/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.mail.ru/ https://rs.mail.ru/d20915561.gif?sz=3&rnd=130652212&ts=1516015880&sz=3 image
-http://www.youth.cn/ http://cl3.webterren.com/1.gif?z=36&a=160f996cffb&b=%u4E2D%u56FD%u9752%u5E74%u7F51&B=UTF-8&c=http%3A//m.youth.cn/%3F_wdxid%3D000000000000000000000000000000000000000000%26_wdc%3D%26_wdt%3D000%26&d=&e=0&f=0&H=m.youth.cn&E=0&r=67e1a447cb34060a&s=0&t=0&u=1&i=en-US&j=0&k=360x512&l=24&m=&n=&o=-8 image
-http://www.mail.ru/ https://rs.mail.ru/d22199766.gif?sz=3&rnd=126733178&ts=1516015880&sz=3 image
-http://www.youth.cn/ http://api.share.baidu.com/s.gif?l=http://m.youth.cn/ image
-http://www.mail.ru/ https://r.mradx.net/img/AB/01FF8B.png image
-http://www.youth.cn/ http://cloudfront-labs.amazonaws.com/x.png image
-http://www.mail.ru/ https://r.mradx.net/img/76/BB0313.png image
-http://www.youth.cn/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&time=1516015899945&time_zone_offset=480&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fm.youth.cn%2F&random_number=14442343860&sess_cookie=732067e5160f996d520dbf30980&sess_cookie_flag=1&user_cookie=732067e5160f996d520dbf30980&user_cookie_flag=1&dynamic=true&domain=youth.cn&account=r+FMm1a4KM+2uW&jsv=20130128&user_lang=en-US image
-http://www.mail.ru/ https://r.mradx.net/img/84/B16060.png image
-http://www.youth.cn/ http://pos.baidu.com/s?hei=110&wid=360&di=u3018881&ltu=http%3A%2F%2Fm.youth.cn%2F&dc=3&dai=2&tpr=1516015900246&cdo=0&ari=2&ti=%E4%B8%AD%E5%9B%BD%E9%9D%92%E5%B9%B4%E7%BD%91&ccd=24&tlm=1516015900&cce=true&chi=3&ps=1246x349&dtm=HTML_POST&par=360x512&pss=360x1531&cmi=0&psr=360x512&pcs=360x512&tcn=1516015900&cec=UTF-8&ant=0&col=en-US&cfv=0&pis=-1x-1&dri=0&cja=false&drs=3&cpl=0&exps=114042&dis=0 html
-http://www.mail.ru/ https://r.mradx.net/img/D0/B01E40.png image
-http://www.youth.cn/ http://cpro.baidustatic.com/cpro/ui/pr.js script
-http://www.mail.ru/ https://r.mradx.net/img/F1/3F5B6D.png image
-http://www.youth.cn/ http://a64f09dfcde057043f79d589be2b02d57.profile.ewr52-c1.cloudfront.net/test.png image
-http://www.mail.ru/ https://rs.mail.ru/d8352871.gif?sz=7&rnd=577628489&ts=1516015880&sz=7 image
-http://www.mail.ru/ https://rs.mail.ru/d23696722.gif?sz=5&rnd=212871017&ts=1516015880&sz=5 image
-http://www.youth.cn/ http://cpro.baidustatic.com/cpro/expire/time2.js script
-http://www.mail.ru/ https://rs.mail.ru/d25374323.gif?sz=27&rnd=166083366&ts=1516015880&sz=27 image
-http://www.youth.cn/ http://pb2.qujishu.com/msnfbt?byc=yxx&qcx=03x&xc=r0yz6y1z&fno=eqqmZ07ZzCZzCjZXvlrqeZX.kZzC&jcm=YyuYy&xlc=x&jwm=03xu2yz&jmm=03xuy32x&xng=EQJIXMLPQ&njl=y2y3xy26xxz13&uhn=y&wyw=RQCY5&jm=5y0uyx&yrjm=yy1x11&xw=0&xuc=y&jul=03xu2yz&ulc=z&xcm=x&x3=arkzg html
-http://www.mail.ru/ https://r.mradx.net/img/99/BFA5E6.png image
-http://www.youth.cn/ http://cpro.baidustatic.com/sync.htm?cproid=2D08E50875A3FC67E6BFB09F872A4CA7%3AFG%3D1 html
-http://www.mail.ru/ https://rs.mail.ru/d12907924.gif?sz=21&rnd=290721440&ts=1516015880&sz=21 image
-http://www.youth.cn/ http://f11.baidu.com/it/u=2651868076,2367709629&fm=76 image
-http://www.mail.ru/ https://rs.mail.ru/d9974532.gif?sz=19&rnd=160061496&ts=1516015880&sz=19 image
-http://www.youth.cn/ http://f10.baidu.com/it/u=352123071,777914931&fm=76 image
-http://www.mail.ru/ https://r.mradx.net/img/EE/BFE3CC.png image
-http://www.mail.ru/ https://r.mradx.net/img/5C/2569F0.png image
-http://www.youth.cn/ http://f12.baidu.com/it/u=3921218333,4163213554&fm=76 image
-http://www.mail.ru/ https://r.mradx.net/img/51/338513.png image
-http://www.youth.cn/ http://wn.pos.baidu.com/adx.php?c=d25pZD1mY2UzMTE0OWNiN2FjMGI4AHM9ZmNlMzExNDljYjdhYzBiOAB0PTE1MTYwMTU5MDEAc2U9MQBidT00AHByaWNlPVdseVJIUUFKME81N2pFcGdXNUlBOHNoTUUxX0NNQTQ4S2VRRUZRAGNoYXJnZV9wcmljZT02NTUAc2hhcmluZ19wcmljZT02NTUwMDAAd2luX2RzcD00AGNobWQ9MQBiZGlkPTJEMDhFNTA4NzVBM0ZDNjdFNkJGQjA5Rjg3MkE0Q0E3AGNwcm9pZD0Ad2Q9MAB0dT11MzAxODg4MQBwb3M9MABiY2htZD0wAHY9MQBpPTc0M2I3Y2E1 image
-http://www.mail.ru/ https://rs.mail.ru/d24906761.gif?sz=25&rnd=141824048&ts=1516015880&sz=25 image
-http://www.youth.cn/ http://t10.baidu.com/it/u=3518155788,1835107690&fm=76 image
-http://www.mail.ru/ https://static.criteo.net/js/ld/publishertag.js script
-http://www.youth.cn/ http://pos.baidu.com/sync_pos.htm?cproid=2D08E50875A3FC67E6BFB09F872A4CA7%3AFG%3D1 html
-http://www.youth.cn/ http://pb2.qujishu.com/haq/e?c=d25pZD02Zjk3ZTgyY2Q0ZmQ1ZjY4AHM9NmY5N2U4MmNkNGZkNWY2OAB0PTE1MTYwMTU5MDIAc2U9MQBidT00AHByaWNlPVdseVJIZ0FPWEI5N2pFcGdXNUlBOHZ6Z1Q3clFNbDJxRDVhZTdRAGNoYXJnZV9wcmljZT05OTgAc2hhcmluZ19wcmljZT05OTgwMDAAd2luX2RzcD00AGNobWQ9MQBiZGlkPQBjcHJvaWQ9AHdkPTAAdHU9dTMxMjkxNDIAcG9zPTAAYmNobWQ9MAB2PTEAaT03ODA5NzM1Zg image
-http://www.mail.ru/ https://rs.mail.ru/un?uniq=WggBALi2dAABOAcB&euniq=WwgBAHsTAAAJCAAB&rnd=130225335 image
-http://www.youth.cn/ http://cm.g.doubleclick.net/pixel?google_nid=baidu&google_cm html
-http://www.youth.cn/ http://t11.baidu.com/it/u=3562189981,746326259&fm=76 image
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/i/sign-aries@x2-23c44a1538.png image
-http://www.youth.cn/ http://cm.baidu.com/pixel?media_sign=a47c60c72bd194de16bfd3d65a193714&media_site=2b754e1aec5785e2c1d894d225ea394825783f84526c2c00c2907787c06bc8f1 html
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/i/sign-taurus@x2-97d78f62bd.png image
-http://www.youth.cn/ http://cm.g.doubleclick.net/pixel?google_nid=baidu&google_cm=&google_tc= html
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/i/sign-gemini@x2-adad807fae.png image
-http://www.youth.cn/ https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_ads_2x.png image
-http://www.mail.ru/ https://rs.mail.ru/d1290389.gif?&rnd=253191271 image
-http://www.youth.cn/ http://pb2.qujishu.com/m.html?mediaid=82c71f967a611a77a122cea66819b3f9734756f3f83da85f763fe6985c9c0fdef6e5da69b74ec74e3d2692ada0e835a6&cookie_version=2&timestamp=1516015904&ext_data= html
-http://www.mail.ru/ https://rs.mail.ru/pixel/Ci0I9Zr1C4gBB8ABCsgBARCA_v_RAx0PkVxasAHNnD24AcgBoAOfAcICBIU_5FU.gif image
-http://www.youth.cn/ https://cpro.baidustatic.com/cpro/ui/noexpire/img/newBDlogo/wap_hand_2x.png image
-http://www.mail.ru/ https://touchsplash.radar.imgsmail.ru/update?t=page&v=3911&i=all%3A3911%2Chead%3A3060%2Cserver%3A11%2CSplashjs%3A3049%2CJSLoad%3A3011%2CJSInit%3A36%2Cheadline%3A0%2Cportal-menu%3A1%2Csocial%3A147%2Csearch%3A19%2Cweather%3A130%2Cnews%3A83%2Cbanner-bottom%3A62%2Ccurrency%3A40%2Choro%3A86%2Ctv%3A2%2Cafisha%3A75%2Csport%3A72%2Cgames%3A3%2Capps-bottom%3A52%2Ccatalogue%3A2%2Cfooter%3A0%2Ccache_clearCache%3A1%2Cconnect%3A1460%2CdomainLookup0%3A0%2Crequest%3A998%2Cresponse%3A368&p=touchsplash&rnd=0.8547618078804813&ver=touch&l=0&em=false%40null&a=0&xy=0 image
-http://www.youth.cn/ http://cm.pos.baidu.com/gpixel?google_gid=CAESEEUTXr-go9P2LWFRH2Khago&google_cver=1 image
-http://www.youth.cn/ http://m.youth.cn/favicon.ico image
-http://www.mail.ru/ https://touchsplash.radar.imgsmail.ru/update?t=nav&v=1&i=all%3A1%2Cnavigate%3A1&p=touchsplash&rnd=0.33915413833734687 image
-http://www.mail.ru/ https://cas.criteo.com/delivery/ajs.php?ptv=40&zoneid=647910&cb=81963900761&nodis=1&charset=UTF-8&dc=2&loc=https%3A%2F%2Fmail.ru%2F script
-http://www.mail.ru/ https://cas.criteo.com/delivery/ajs.php?ptv=40&zoneid=773528&cb=69235050718&nodis=1&charset=UTF-8&dc=2&loc=https%3A%2F%2Fmail.ru%2F script
-http://www.youth.cn/ http://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A4192%2C%22netDns%22%3A1045%2C%22netTcp%22%3A545%2C%22srv%22%3A608%2C%22dom%22%3A9731%2C%22loadEvent%22%3A19267%7D&et=87&ja=0&ln=en-us&lo=0&rnd=1882321434&si=969516094b342230ceaf065c844d82f3&v=1.2.27&lv=1 image
-http://www.mail.ru/ https://top-fwz1.mail.ru/js/code.js script
-http://www.mail.ru/ https://top-fwz1.mail.ru/counter?js=13;id=2104775;u=https%3A//mail.ru/;st=1516015884528;title=Mail.Ru;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=2c89259078faf22e;ver=60;_=0.5893088541403109 image
-http://www.mail.ru/ https://top-fwz1.mail.ru/counter?js=13;id=110605;u=https%3A//mail.ru/touch;st=1516015884529;title=Mail.Ru;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=2c89259078faf22e;ver=60;_=0.739297036466702 image
-http://www.mail.ru/ https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25 html
-http://www.mail.ru/ https://securepubads.g.doubleclick.net/static/glade.js script
-http://www.mail.ru/ https://cat.sv.us.criteo.com/delivery/lg.php?cppv=1&cpp=ylLbkXxEMTZnM28wV3V6SEZRZXFCejJUaEtFK2FQcFlNeStXak53RGMzNU9nS0dPREdBM3piaU1xQzVvOFlJYWNNWmU2NHZESEI3R0d5MXE3VWdaemg1c01McE1maFpteDRlSDNSNVlZMm9ZbkFuYVpXbEM4VFVaQUpieSthdXVtaWVTSzVkQ0NScU9SejdYZVBmVHNiU09PeUtJSUFkZUxXU2lXbExmTUI5eG9TSW1qTDZWaCtXSEF2UnU1UDNDSkNrN0lKQVBoVjA3ZTEyNm1VWWI0a1E2QjNJKzRhVmN5MHlxTU43L09RcnVvWm5wR0NIdE93V2MzcXpmazlBNFlPYzUxfA%3D%3D image
-http://www.mail.ru/ https://cat.sv.us.criteo.com/delivery/lg.php?cppv=1&cpp=vsXhUnxodXBTYTRHWmlQZkoxeGl2SlEyVWNMRkVORHordm8vdnE3KzlBRjlONHFXNEhWeGRtaGtqVWVnMGF3MFJJSzkyZ1ZYdS9xWG5YNFd3ckwwN1F4MmU0V0FqeUVVcUFBQUtsS2VmbmE3YngvOFdoR1hZSDNEVkt4VjlQRnlSZm9uSnlDbHJkZS9ZeCtsR3FOd3RzTmdxSUxZWGxETmJ0dE0vM2lNbGkzMmdOVGk0WVZLeG5jR3hET3VGTlZvT2hTT21sT083b1F2L1E3MUo3SndyWUkvUmh5M1NIRkFDZDRBMEd6bTR3d3crUDFsbXRCTXRjS1JhaGN5L0RuZE1mZ0YyfA%3D%3D image
-http://www.mail.ru/ https://ads.nexage.com/js/admax/admax_api_https.js script
-http://www.mail.ru/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&glade_req=1&glv=26&dt=1516015893226&output=html&iu=%2F205338224%2FMail.ru_mobile_320x50&sz=320x50&sfv=1-0-10&correlator=377077484116926&adk=3471309403&biw=-12245933&bih=-12245933&adx=0&ady=0&oid=3&u_sd=3&ifi=1&click=%25%25CLICK_URL_UNESC%25%25&nhd=1&url=https%3A%2F%2Fmail.ru&top=mail.ru&loc=https%3A%2F%2Fad.mail.ru%2Fadi%2F78733%3Frnd%3D136657296 html
-http://www.mail.ru/ https://securepubads.g.doubleclick.net/static/glade/extra_26.js script
-http://www.mail.ru/ https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25&C=1 html
-http://www.mail.ru/ https://ssum-sec.casalemedia.com/usermatchredir?s=183697&cb=https%3a%2f%2fdis.criteo.com%2frex%2fmatch.aspx%3fc%3d25%26uid%3d%25%25USER_ID%25%25&C=1 html
-http://www.mail.ru/ https://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.mail.ru/ https://tpc.googlesyndication.com/safeframe/1-0-10/js/ext.js script
-http://www.mail.ru/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener.js script
-http://www.mail.ru/ https://scdmed01.advertising.aol.com/admax/adServe.do?cTag=ad702859&dcn=8a809417015757d84d69d8bdd1bc001d&pos=mailru_320x50&req(url)=https%3A//ad.mail.ru/adi/100590%3Frnd%3D407341088&secure=1&grp=&ua=Mozilla/5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build/MPJ24.139-64%29%20AppleWebKit/537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180111.190127&of=js&sd=1 script
-http://www.mail.ru/ https://dis.criteo.com/rex/match.aspx?c=25&uid=WlyRFdHM4YUAACS6FfQAAABY%26060 image
-http://www.mail.ru/ https://dis.criteo.com/rex/match.aspx?c=25&uid=WlyRFdHM4YUAACS6FfMAAABY%26053 image
-http://www.mail.ru/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsuOd6xJcB4BPRP4CiioRqsJq2R6W9VYWfnklmwTlhXbHUmwL_vA_-G9JshWMJWLPJT6DELxuLzmhdlXU-QsxhgT_NnmpCymoNPTXv9O2Bk8g-ZG-bFHJ3d-UZ-_SFYY730GBDzD-2IAA4fx-8s0QcNfyDeOOHvVksOqAiaDlcL-wubXuXLLFEcteoMSAt4uG-PEeyt4tXUEFDGtYmD-Epv004V0sQA2lKrZrsyk4h-3NBofwooYvAkNbFFxicoy&sig=Cg0ArKJSzNZBM6aHw2pdEAE&urlfix=1&adurl= html
-http://www.mail.ru/ https://scdmed01.advertising.aol.com/admax/adServe.do?cTag=ad532538&dcn=8a809417015757d84d69d8bdd1bc001d&pos=mailru_320x50&req(url)=https%3A//securepubads.g.doubleclick.net/gampad/ads%3Fgdfp_req%3D1%26glade_req%3D1%26glv%3D26%26dt%3D1516015893226%26output%3Dhtml%26iu%3D%252F205338224%252FMail.ru_mobile_320x50%26sz%3D320x50%26sfv%3D1-0-10%26correlator%3D377077484116926%26adk%3D3471309403%26biw%3D-12245933%26bih%3D-12245933%26adx%3D0%26ady%3D0%26oid%3D3%26u_sd%3D3%26ifi%3D1%26click%3D%2525%2525CLICK_URL_UNESC%2525%2525%26nhd%3D1%26url%3Dhttps%253A%252F%252Fmail.ru%26top%3Dmail.ru%26loc%3Dhttps%253A%252F%252Fad.mail.ru%252Fadi%252F78733%253Frnd%253D136657296&secure=1&grp=&ua=Mozilla/5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build/MPJ24.139-64%29%20AppleWebKit/537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180111.190127&of=js&sd=1 script
-http://www.mail.ru/ https://top-fwz1.mail.ru/tracker?js=13;id=2104775;u=https%3A//mail.ru/;st=1516015884528;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=2c89259078faf22e;ver=60;nt=0/0/1516015875889/////2920/2920/2920/2920/4380/3401/4381/5379/5747/5386/9480/9480/9480/19955/19956/;detect=0;_=0.20092987453684463;e=RT/load;et=1516015895845 image
-http://www.mail.ru/ https://top-fwz1.mail.ru/tracker?js=13;id=110605;u=https%3A//mail.ru/touch;st=1516015884529;s=360*512;vp=360*512;touch=1;hds=3;flash=;sid=2c89259078faf22e;ver=60;nt=0/0/1516015875889/////2920/2920/2920/2920/4380/3401/4381/5379/5747/5386/9480/9480/9480/19955/19956/;detect=0;_=0.6095690828582547;e=RT/load;et=1516015895845 image
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/i/android-touch-icon-192x192-3329a9ff53.png image
-http://www.mail.ru/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsvyt-bOoS8Is_z4Y4AlbuAtpd8LBfbZZxLNaR3HLSSzLvul1JpB_3C--xfK7gnPtCh2h9NLpyI7SNvd05eJWid-qnGN49-tzZ4&sig=Cg0ArKJSzFZncmLkQphSEAE&id=osdim&ti=1&adk=3471309403&nio=1&tt=1037&bs=-12245933,-12245933&mtos=1030,1030,1030,1030,1030&tos=1030,0,0,0,0&p=0,0,50,320&inapp=0&mcvt=1030&rs=10&ht=0&tfs=664&tls=1581&mc=1&lte=-1&bas=0&bac=0&if=1&bos=360,512&ps=-12245933,-12245933&ss=360,512&pt=545&deb=1-1-1-11-12-23&tvt=1181&is=320,50&op=1&iframe_loc=https%3A%2F%2Fad.mail.ru%2Fadi%2F78733%3Frnd%3D136657296&avms=nio&r=v&uc=11&tgt=BODY&cl=1&cec=4&clc=0&cac=0320x50&v=r20180108 image
-http://www.mail.ru/ https://limg.imgsmail.ru/touchsplash/v/i/favicon-e5142de215.ico image
-http://www.csdn.net/ http://www.csdn.net/ html
-http://www.csdn.net/ https://www.csdn.net/ html
-http://www.csdn.net/ https://www.csdn.net/js/tingyun-rum.js?1511847956 script
-http://www.csdn.net/ https://www.csdn.net/css/csdn_feed.css?1515735954 css
-http://www.csdn.net/ https://www.csdn.net/js/modernizr.js?1506677690 script
-http://www.csdn.net/ https://csdnimg.cn/public/common/libs/jquery/jquery-1.9.1.min.js script
-http://www.csdn.net/ https://csdnimg.cn/pubfooter/js/tracking-1.0.2.js script
-http://www.csdn.net/ https://csdnimg.cn/rabbit/exposure-click/main_flume.js?v1.15.35 script
-http://www.csdn.net/ https://csdnimg.cn/public/common/toolbar/js/content_toolbar.js script
-http://www.csdn.net/ https://csdnimg.cn/public/common/toolbar/content_toolbar_css/content_toolbar.css css
-http://www.csdn.net/ https://csdnimg.cn/public/common/libs/bootstrap/css/bootstrap.min.css css
-http://www.csdn.net/ https://csdnimg.cn/public/static/css/avatar.css css
-http://www.csdn.net/ https://csdnimg.cn/public/common/libs/bootstrap/js/bootstrap.min.js script
-http://www.csdn.net/ https://csdnimg.cn/asdf/async-1.0.1.js script
-http://www.csdn.net/ https://csdnimg.cn/asdf/tracking-1.0.1.js script
-http://www.csdn.net/ https://www.csdn.net/js/csdn_feed.min.js?1515567610 script
-http://www.csdn.net/ https://www.csdn.net/images/feedLoading.gif image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180112/1c6c787ecef99072a061ac12583803ef.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180115/10e668bb468e7f9d28d9f371c1bd7591.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180115/1316046c5bb091f2b7974f7436cde24a.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180115/d134f95e7310492124b67371c26ef5f9.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180112/8a2806a1a9070af5e5ec42d38ef097ec.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180114/19607708fc1999da088a12e944042e8d.png image
-http://www.csdn.net/ https://csdnimg.cn/cdn/content-toolbar/iconfont.js?_=1516016114373 script
-http://www.csdn.net/ https://csdnimg.cn/public/common/toolbar/images/100x100.jpg image
-http://www.csdn.net/ https://www.csdn.net/images/mod_viewpoint.png image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180110/135511e014abd853045a4e2878acc285.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20171212/9de43ae334f6a830147e06f147e39474.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20171212/f20bc5bb44435820f009185ed5b9d1b6.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180111/58d889a2fb523da16a4c75ad5d921f8c.jpg image
-http://www.csdn.net/ https://csdnimg.cn/feed/20180103/ea5e1cc853f8f1a9c9707e5430526d41.jpg image
-http://www.csdn.net/ https://www.csdn.net/images/ali.png image
-http://www.google.com.tw/ http://www.google.com.tw/ html
-http://www.csdn.net/ https://csdnimg.cn/cdn/content-toolbar/iconfont.ttf?t=1509003158575 font
-http://www.google.com.tw/ https://www.google.com.tw/?gws_rd=ssl html
-http://www.csdn.net/ https://sdk.appadhoc.com/ab.plus.js script
-http://www.google.com.tw/ https://www.google.com.tw/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.csdn.net/ https://avatar.csdn.net/5/A/A/1_tkkzc3e6s4ou4.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/images/nav_logo242_hr.webp image
-http://www.csdn.net/ https://avatar.csdn.net/B/2/7/1_qq_32259579.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/gen_204?s=webaft&atyp=csi&ei=SJFcWoqMMpXqjwOSvZjQBw&rt=wsrt.2086,aft.166,prt.166 html
-http://www.csdn.net/ https://avatar.csdn.net/3/9/7/1_j01g58uc80251.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPJfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oHFKBcvcVQykztV52RGYNzZHVtuLg script
-http://www.google.com.tw/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.csdn.net/ https://avatar.csdn.net/E/1/2/1_uw63zqpkxwlrl1.jpg image
-http://www.google.com.tw/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.csdn.net/ https://avatar.csdn.net/B/5/4/1_dzz2sein13yv.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPJfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHFKBcvcVQykztV52RGYNzZHVtuLg?xjs=s1 script
-http://www.csdn.net/ https://avatar.csdn.net/B/6/6/1_b644rofp20z37485o35m.jpg image
-http://www.google.com.tw/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.csdn.net/ https://avatar.csdn.net/7/F/5/1_m7720eiosi6oa9.jpg image
-http://www.google.com.tw/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.com.tw/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.csdn.net/ https://avatar.csdn.net/E/8/6/1_sfm06sqvw55dft1.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/E/4/9/1_p5deyt322jacs.jpg image
-http://www.google.com.tw/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.csdn.net/ https://avatar.csdn.net/2/0/A/1_weixin_39967349.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/7/E/D/1_px01ih8.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/2/F/9/1_t4i2b10x4c22nf6a.jpg image
-http://www.google.com.tw/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.csdn.net/ https://avatar.csdn.net/0/1/2/1_wgl3k77y9fr1k61t1as.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/F/0/C/1_qq_34531925.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPJfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oHFKBcvcVQykztV52RGYNzZHVtuLg script
-http://www.google.com.tw/ https://www.google.com.tw/images/nav_logo242.png image
-http://www.csdn.net/ https://avatar.csdn.net/7/6/6/1_imbrl71u7pt5x29rleu7.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/gen_204?atyp=csi&ei=SJFcWoqMMpXqjwOSvZjQBw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.602,dcl.314,iml.602,ol.2663,prt.166,xjs.1827,xjsee.1826,xjses.1232,xjsls.190,wsrt.2086,cst.639,dnst.0,rqst.739,rspt.371,sslt.340,rqstt.1593,unt.951,cstt.953,dit.2399&zx=1516015947818 html
-http://www.csdn.net/ https://avatar.csdn.net/8/B/4/1_h273979586.jpg image
-http://www.google.com.tw/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.csdn.net/ https://avatar.csdn.net/B/8/4/1_y0w1as5eg37urfds.jpg image
-http://www.google.com.tw/ https://www.google.com.tw/images/branding/product/1x/gsa_android_144dp.png image
-http://www.csdn.net/ https://avatar.csdn.net/7/5/9/1_hd243608836.jpg image
-http://www.google.com.tw/ https://adservice.google.com.tw/adsid/google/ui html
-http://www.csdn.net/ https://avatar.csdn.net/4/E/E/1_mynameishuangshuai.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/6/9/A/1_u011012932.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/2/E/3/1_u011240877.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/C/A/C/1_sunhuaqiang1.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/B/A/8/1_baihuaxiu123.jpg image
-http://www.csdn.net/ https://www.csdn.net/images/icon_close_big.png image
-http://www.csdn.net/ https://img-ads.csdn.net/2016/201608021757063065.png image
-http://www.csdn.net/ https://www.csdn.net/images/viewpoint_bg.png image
-http://www.csdn.net/ https://www.csdn.net/api/articles?type=more&category=home&shown_offset=1516016110972277 script
-http://www.csdn.net/ https://avatar.csdn.net/A/5/F/1_oschina2017.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/B/8/5/1_h176nhx7.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/E/D/3/1_moy37rqw1jarn33bgzk.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/E/3/D/1_z1xpiydj9sn.jpg image
-http://www.csdn.net/ https://avatar.csdn.net/1/0/A/1_u8i7s7k5bv.jpg image
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016118799 other
-http://www.csdn.net/ https://hm.baidu.com/hm.js?6bcd52f51e9b3dce32bec4a3997715ac script
-http://www.csdn.net/ https://ads.csdn.net/get_ads.php?ip=null&zones=240%7C241%7C259%7C260%7C261%7C262%7C131%7C132%7C133%7C134%7C135%7C136%7C242&iframe=false%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse&prefix=revive-0-&loc=https%3A%2F%2Fwww.csdn.net%2F script
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801121816572489.jpg image
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801081533074541.gif image
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801121405222048.jpg image
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801111110209700.jpg image
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801111849093035.gif image
-http://www.csdn.net/ https://img-ads.csdn.net/2017/201712291135454696.jpg image
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801051707294372.png image
-http://www.csdn.net/ https://img-ads.csdn.net/2018/201801121404349623.jpg image
-http://www.microsoftonline.com/ http://www.microsoftonline.com/ html
-http://www.microsoftonline.com/ http://login.microsoftonline.com/ other
-http://www.csdn.net/ https://img-ads.csdn.net/2017/201712141947357700.jpg image
-http://www.microsoftonline.com/ https://login.microsoftonline.com/ html
-http://www.csdn.net/ https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&et=0&ja=0&ln=en-us&lo=0&rnd=333342248&si=6bcd52f51e9b3dce32bec4a3997715ac&v=1.2.27&lv=1&ct=!!&tt=CSDN-%E4%B8%93%E4%B8%9AIT%E6%8A%80%E6%9C%AF%E7%A4%BE%E5%8C%BA&sn=60503 image
-http://www.microsoftonline.com/ https://www.office.com/login html
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.microsoftonline.com/ https://login.microsoftonline.com/common/oauth2/authorize?client_id=4345a7b9-9a63-4910-a426-35363201d503&response_mode=form_post&response_type=code+id_token&scope=openid+profile&state=OpenIdConnect.AuthenticationProperties%3dr048Z8rOOW-YvhlRR9FV18C24ft0-HeqVC8qfjKQfxocXkoue8V_KtZgrdGt07wQrSwcpUiWDAV0VfQj_gKpSYOa6AFv3e8J0_lEScnxkiGSdRuXUb6gy6Y4kHgUtKq4&nonce=636516127825248666.OGYzZGFmZmYtNDgzZS00Yzg5LWI1YzMtNDkxYjU2NmI1NGVlNGI4MGJjY2MtYWU0OC00MzUzLWFjNmEtNGE3N2E5ZmJhZDQ2&redirect_uri=https%3a%2f%2fwww.office.com%2f&ui_locales=en-US&mkt=en-US html
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/cdnbundles/convergedloginpaginatedstrings-en.min.js script
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/cdnbundles/convergedlogin_pcore.min.js script
-http://www.csdn.net/ https://experiment.appadhoc.com/get_flags_async other
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/cdnbundles/converged.login.min.css css
-http://www.microsoftonline.com/ https://www.office.com/prefetch/prefetch html
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/microsoft_logo.svg?x=ee5c8d9fb6248c938fd0dc19370e90bd image
-http://www.csdn.net/ https://experiment.appadhoc.com/get_flags_async script
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/marching_ants_white.gif?x=166de53471265253ab3a456defe6da23 image
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/marching_ants.gif?x=b540a8e518037192e32c4fe58bf2dbab image
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/ellipsis_white.svg?x=5ac590ee72bfe06a7cecfd75b588ad73 image
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016122802 text
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/close.svg?x=40eb39126300b56bf66c20ee75b54093 image
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/ellipsis_grey.svg?x=2b5d393db04a5e6e1f739cb266e65b4c image
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/b29e92f2/Areas/Home/Content/js/build/bundles/staticscripts.js script
-http://www.csdn.net/ https://goutong.baidu.com/site/279/6bcd52f51e9b3dce32bec4a3997715ac/b.js?siteId=6583558 script
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/fab5fe9a/Areas/Home/Content/images/document-sprite.png image
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016124799 text
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/bfbeed03/Areas/Home/Content/js/build/bundles/staticstyles.css css
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/398b5c2a/Areas/Home/Content/images/zero-docs-sprite.png image
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/f5628679/Areas/Home/Content/js/build/bundles/polyfills-bundle.js script
-http://www.tumblr.com/ https://www.tumblr.com/ html
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/c896b368/Areas/Home/Content/js/build/bundles/vendor-bundle.js script
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016126799 text
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.microsoftonline.com/ https://outlook.office365.com/owa/prefetch.aspx html
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/7c18fcc8/Areas/Home/Content/js/build/bundles/react-bundle.js script
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/f378d58f/Areas/Home/Content/js/build/bundles/app-bundle.js script
-http://www.microsoftonline.com/ https://wusofficehome.msocdn.com/s/53ce9072/Areas/Home/Content/js/build/bundles/sharedscripts.js script
-http://www.microsoftonline.com/ https://appsforoffice.microsoft.com/fabric/fonts/SegoeUI-WestEuropean/SegoeUI-Regular.woff font
-http://www.microsoftonline.com/ https://appsforoffice.microsoft.com/fabric/fonts/SegoeUI-WestEuropean/SegoeUI-Semibold.woff font
-http://www.csdn.net/ https://re.csdn.net/csdnbi other
-http://www.tumblr.com/ https://assets.tumblr.com/client/prod/app/header.build.js?_v=aded03b2a77c60c40ea5b452a1f98cee script
-http://www.microsoftonline.com/ https://appsforoffice.microsoft.com/fabric/fonts/SegoeUI-WestEuropean/SegoeUI-Semilight.woff font
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016128799 text
-http://www.tumblr.com/ https://assets.tumblr.com/client/prod/app/global.build.css?_v=998892d57b1e4d7bc5cb07bd09be2deb css
-http://www.microsoftonline.com/ https://appsforoffice.microsoft.com/fabric/fonts/SegoeUI-WestEuropean/SegoeUI-Light.woff font
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016130801 text
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016132799 text
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.0.narrow.js script
-http://www.tumblr.com/ https://assets.tumblr.com/assets/styles/global.css?_v=44249ce7b09db0c22d4afcd313904d10 css
-http://www.csdn.net/ https://pv.csdn.net/csdnbi other
-http://www.microsoftonline.com/ https://secure.aadcdn.microsoftonline-p.com/ests/2.1.7114.7/content/images/favicon_a.ico image
-http://www.csdn.net/ https://beacon.tingyun.com/xhr1?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&__r=1516016134799 text
-http://www.tumblr.com/ https://assets.tumblr.com/assets/scripts/vendor/yahoo/rapid/rapidworker-1.2.js?_v=70c488012831cd8276d74fd06a89ce09 script
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.1.narrow.js script
-http://www.csdn.net/ https://ads.csdn.net/get_ads.php?ip=null&zones=261%7C262%7C263%7C264%7C135%7C242&iframe=false%7Cfalse%7Cfalse%7Cfalse%7Cfalse%7Cfalse&prefix=revive-0-&loc=https%3A%2F%2Fwww.csdn.net%2F script
-http://www.tumblr.com/ https://assets.tumblr.com/assets/scripts/vendor/yahoo/rapid/rapid-3.42.2.js?_v=5459b85e970537e82d0ae9fd51b0aa0e script
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.2.narrow.js script
-http://www.csdn.net/ https://beacon.tingyun.com/pf?pvid=7078513c-de65-41c3-91f0-07ed2dda7625&ref=https%3A%2F%2Fwww.csdn.net%2F&referrer=&key=5raC_g4Hadc&v=1.7.4&av=1.7.4&did=78d3340a-48fc-46ab-b0af-b33c1aa06f34&sid=db69fdae-8bc7-460b-971b-3b663211ead9&f=1415&qs=2566&rs=4061&re=4069&os=8988&oe=9175&oi=8988&oc=37282&ls=37282&le=37301&tus=0&tue=0&cs=1415&ce=2566&fp=6892&sl=1982&je=0&id=6ig1WV1dfhs%23gIMN6oMlwr0&a=795&q=0&tid=1e656d4cfc9c45f&n=WebAction%2FCI%2Findex%252Findex&sh=512&sw=360&dr=8988&fs=37280&trflag=1111&__r=1516016145349 text
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/scripts/boot.worldwide.3.narrow.js script
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.png image
-http://www.csdn.net/ https://csdnimg.cn/public/favicon.ico image
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.x2.png image
-http://www.tumblr.com/ https://assets.tumblr.com/assets/scripts/tumblr/utils/exceptions.js?_v=6480337ee2259189f7dc54042bdc671a script
-http://www.csdn.net/ https://hm.baidu.com/hm.gif?cc=0&ck=1&cl=24-bit&ds=360x512&vl=512&ep=%7B%22netAll%22%3A2566%2C%22netDns%22%3A0%2C%22netTcp%22%3A1151%2C%22srv%22%3A1495%2C%22dom%22%3A7573%2C%22loadEvent%22%3A37301%7D&et=87&ja=0&ln=en-us&lo=0&rnd=1954220644&si=6bcd52f51e9b3dce32bec4a3997715ac&v=1.2.27&lv=1 image
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.css css
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/images/0/sprite1.narrow.x2.css css
-http://www.tumblr.com/ https://assets.tumblr.com/languages/strings/en_US.js?1343 script
-http://www.microsoftonline.com/ https://r4.res.office365.com/owa/prem/16.2091.8.2465767/resources/styles/0/boot.worldwide.narrow.css css
-http://www.tumblr.com/ https://assets.tumblr.com/client/prod/app/context/loginandregister/index.build.css?_v=dac7806aaab0b38b7131a9fb96b28b61 css
-http://www.tumblr.com/ https://assets.tumblr.com/assets/styles/password_strength_meter.css?_v=78c1926d168e565836a2d002cde53866 css
-http://www.tumblr.com/ https://assets.tumblr.com/assets/styles/form_classic_onboarding.css?_v=af9d7b0321a63c680edb4c931fb7351a css
-http://www.tumblr.com/ https://assets.tumblr.com/client/prod/app/vendor.build.js?_v=fd43a60f1f93524a37520afd0ed98260 script
-http://www.tumblr.com/ https://assets.tumblr.com/client/prod/app/global.build.js?_v=ec8ebf2020542e15518de3b6716e9997 script
-http://www.tumblr.com/ https://assets.tumblr.com/assets/scripts/dashboard.js?_v=07df242f35575490930e1700de860569 script
-http://www.tumblr.com/ https://assets.tumblr.com/assets/scripts/registration/registration.js?_v=430ba7bf599b11210d684305ee30bf52 script
-http://www.tumblr.com/ https://assets.tumblr.com/client/prod/app/context/loginandregister/index.build.js?_v=bc17ffb32113834d5d4b05f19243f9d4 script
-http://www.tumblr.com/ https://assets.tumblr.com/delivery/cdn.json script
-http://www.tumblr.com/ https://assets.tumblr.com/images/logo/logo_large@2x.png?v=5ff69a6c9b2fbdb20feac5fbcfa89317 image
-http://www.tumblr.com/ https://ssl.google-analytics.com/ga.js script
-http://www.tumblr.com/ https://cookiex.ngd.yahoo.com/v2/cexposer/SIG=11lum9jej/*https%3A//www.tumblr.com/yahoo_cookie_receiver.html html
-http://www.tumblr.com/ https://sb.scorecardresearch.com/beacon.js script
-http://www.tumblr.com/ https://udc.yahoo.com/v2/public/yql?yhlVer=2&yhlClient=rapid&yhlS=1197719247&yhlCT=2&yhlBTMS=1516016013793&yhlClientVer=3.42.2&yhlRnd=5gkq0FSQjWenF7wl&yhlCompressed=0 other
-http://www.tumblr.com/ https://px.srvcs.tumblr.com/impixu?T=1516016009&J=eyJ0eXBlIjoidXJsIiwidXJsIjoiaHR0cDpcL1wvd3d3LnR1bWJsci5jb21cLyIsInJlcXR5cGUiOjAsInJvdXRlIjoiXC8ifQ==&U=CHLNCIPDEG&K=183a6f6e1800b85094424b23a8fcbd9055a4e020151ed2a4f3ff4787616e23c7&R= image
-http://www.tumblr.com/ https://www.tumblr.com/yahoo_cookie_receiver.html?SIG=112kkc248;x-cookie=SnxreGungfAbgNErnyOPBBXVR html
-http://www.tumblr.com/ https://sb.scorecardresearch.com/b?c1=2&c2=15742520&ns__t=1516016015290&ns_c=UTF-8&cv=3.1m&c8=Sign%20up%20%7C%20Tumblr&c7=https%3A%2F%2Fwww.tumblr.com%2F&c9= other
-http://www.tumblr.com/ https://www.google-analytics.com/analytics.js script
-http://www.tumblr.com/ https://sb.scorecardresearch.com/b2?c1=2&c2=15742520&ns__t=1516016015290&ns_c=UTF-8&cv=3.1m&c8=Sign%20up%20%7C%20Tumblr&c7=https%3A%2F%2Fwww.tumblr.com%2F&c9= other
-http://www.tumblr.com/ https://assets.tumblr.com/images/logo/hover-animations/1@2x.png image
-http://www.tumblr.com/ https://www.tumblr.com/services/cslog other
-http://www.tumblr.com/ https://assets.tumblr.com/assets/scripts/vendor/cedexis/1-13960-radar10.min.js?_v=1c33ba57efaa7c45a6d00094f876fe73 script
-http://www.tumblr.com/ https://assets.tumblr.com/images/favicons/favicon.ico?_v=b45846535fb3e72144f09ddd9ad69b4b image
-http://www.tumblr.com/ https://i2-fabnptuxvwifvjmpwgnbnghqxgnogf.init.cedexis-radar.net/i2/1/13960/j1/20/63/1516016019/providers.json?imagesok=1&n=1&p=1&r=1&t=0 script
-http://www.imdb.com/ http://www.imdb.com/ html
-http://www.tumblr.com/ https://hwcdnssl.cedexis-test.com/img/r20.gif?rnd=1-1-13960-0-0-17000-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.tumblr.com/ https://rpt.cedexis.com/n1/0/1516016008492/0/0/0/0/1516016008611/1516016008612/1516016008795/1516016008795/1516016009450/1516016009116/1516016009450/1516016009872/1516016010118/1516016009972/1516016016810/1516016016810/1516016016960/1516016017110/1516016017110/1516016017116/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/1516016013710 text
-http://www.imdb.com/ http://m.imdb.com/ html
-http://www.tumblr.com/ https://hwcdnssl.cedexis-test.com/img/17000/iuni2.html?rnd=-1-1-13960-0-0-17000-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ html
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/css/collections/mobile/responsive-624213912._CB490322105_.css css
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17000/1/0/306/1516016023.dop008.sj2.t%2C1516016023.cds025.sj2.shn%2C1516016023.dop008.sj2.t%2C1516016024.cds028.sj2.c/0 text
-http://www.tumblr.com/ https://hwcdnssl.cedexis-test.com/img/r20.gif?rnd=0-1-13960-0-0-17000-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/css/collections/mobile/upsell-ad-988557879._CB528806217_.css css
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17000/0/0/302/1516016023.dop008.sj2.t%2C1516016023.cds025.sj2.shn%2C1516016023.dop008.sj2.t%2C1516016024.cds028.sj2.c/0 text
-http://www.imdb.com/ https://ia.media-imdb.com/images/G/01/imdbads/js/collections/ads-mobileweb-437121522._CB492615038_.js script
-http://www.tumblr.com/ https://media-akam.licdn.com/cdo/cdxs/r20.gif?rnd=1-1-13960-0-0-16482-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/16482/1/0/303/0/0 text
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/js/collections/common-2411119445._CB514893747_.js script
-http://www.tumblr.com/ https://media-akam.licdn.com/cdo/cdxs/r20.gif?rnd=0-1-13960-0-0-16482-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/js/collections/mobile/responsive-1178668506._CB489364867_.js script
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/16482/0/0/303/0/0 text
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/js/collections/mobile/upsell-ad-70887417._CB514893702_.js script
-http://www.tumblr.com/ https://benchmark.1e100cdn.net/r20.gif?rnd=1-1-13960-0-0-32430-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://ia.media-imdb.com/images/G/01/imdbads/js/beacon-1792157672._CB514933407_.js script
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/32430/1/0/301/0/0 text
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/images/mobile/imdb-logo-responsive@2-868559777._CB514893749_.png image
-http://www.tumblr.com/ https://benchmark.1e100cdn.net/r20.gif?rnd=0-1-13960-0-0-32430-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/images/mobile/mobile_sprite-3966822794._V_.png image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/32430/0/0/302/0/0 text
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/images/mobile/AppUpsell/IMDbLogo-842911133._CB514892002_.png image
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/html/zergnet-2269547135._CB493880631_.html?widgetId=50277 html
-http://www.tumblr.com/ https://s.pinimg.com/_/_/r20.gif?rnd=1-1-13960-0-0-34022-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/images/mobile/mobile_sprite_x2-27452193._V_.png image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/34022/1/0/1244/0/0 text
-http://www.imdb.com/ http://z-ecx.images-amazon.com/images/G/01/csminstrumentation/ue-full-11e51f253e8ad9d145f4ed644b40f692._V1_.js script
-http://www.tumblr.com/ https://s.pinimg.com/_/_/r20.gif?rnd=0-1-13960-0-0-34022-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BNTg2NTQyODM0Ml5BMl5BanBnXkFtZTgwNTQwMjY1NDM@._CR189,3,1842,1380_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/34022/0/0/313/0/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjM5Mzc0ODU5N15BMl5BanBnXkFtZTgwOTMwMjY1NDM@._CR257,37,1032,773_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.tumblr.com/ https://limelight-ssl.cedexis-test.com/img/17003/r20.gif?rnd=1-1-13960-0-0-17003-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTY2ODU2OTM1M15BMl5BanBnXkFtZTgwNDY1NDc5OTE@._CR985,0,1348,1999_UX402_UY596._SX233_CR0,0,233,345_AL_.jpg image
-http://www.tumblr.com/ https://limelight-ssl.cedexis-test.com/node2/17003min.html?rnd=1-13960-0-0-17003-bztcixsa-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ html
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/play-button._CB318667375_.png image
-http://www.tumblr.com/ https://limelight-ssl.cedexis-test.com/img/17003/r20.gif?rnd=bptrecivmbtfzjzihrsbdbyzaylzlaaq image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/play-button-hover._CB318667374_.png image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17003/1/0/336/lon/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BOTU3NjczMTEzNV5BMl5BanBnXkFtZTgwNjk5MzcwMTI@._CR148,205,714,1058_UX402_UY596._SX233_CR0,0,233,345_AL_.jpg image
-http://www.tumblr.com/ https://limelight-ssl.cedexis-test.com/img/17003/r20.gif?rnd=0-1-13960-0-0-17003-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTg1MTY2MjYzNV5BMl5BanBnXkFtZTgwMTc4NTMwNDI@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTc4MjIwOTg5MF5BMl5BanBnXkFtZTgwNDEwNDgyNDM@._CR167,13,1753,1313_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/17003/0/0/336/lon/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjMyMTY2MzYxN15BMl5BanBnXkFtZTgwMTEwNDgyNDM@._CR213,115,1458,1092_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.tumblr.com/ https://deazs14tb5j7o.cloudfront.net/img/29/r20.gif?rnd=1-1-13960-0-0-29-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjM3NzAxNzA1Ml5BMl5BanBnXkFtZTgwMzA1MjIzNDM@._CR41,19,1137,852_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.tumblr.com/ https://deazs14tb5j7o.cloudfront.net/img/29/iuni2.html?rnd=-1-1-13960-0-0-29-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ html
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTY4NTA4MDYxOF5BMl5BanBnXkFtZTgwMjUxMTYxMjI@._CR65,71,642,481_BR9_CT6_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjMyNzcwODE2MV5BMl5BanBnXkFtZTgwNTAwNDI2MTI@._CR156,18,1249,1249_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.tumblr.com/ https://deazs14tb5j7o.cloudfront.net/img/29/r20.gif?rnd=0-1-13960-0-0-29-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://www.zergnet.com/zerg.js?id=50277 script
-http://www.imdb.com/ https://aax-us-east.amazon-adsystem.com/x/getad?pk=%5B%22p%3Dtop%22%2C%22p%3Dt%22%2C%22c%3D1%22%2C%22pi%3Dhomepage%22%5D&src=401&c=100&sz=320x50&ec=0&u=http%3A%2F%2Fm.imdb.com%2F&slot=TOP_AD&site=m.imdb.com&pt=homepage&jscb=aax_render_ad_top_ad&rnd=685832687953 script
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/29/1/0/303/x-amz-cf-id%3ANtzG3BhmAKkrUa0D_MdVcKN0HVfm2ktyuIw4nAGokN3QXJwoTqHHAw%3D%3D%40via%3A1.1%20dc553909528b8b63475c922dc07d8ba6.cloudfront.net%20(CloudFront)/0 text
-http://www.imdb.com/ http://m.imdb.com/_json/video/vi1727117337,ls053181649,vi1123596313,vi2046343193,vi2381625369,ls025849840,vi3941840921?tracking_tag=&pageId=&pageType=home&subpageType=main script
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/29/0/0/302/x-amz-cf-id%3ANtzG3BhmAKkrUa0D_MdVcKN0HVfm2ktyuIw4nAGokN3QXJwoTqHHAw%3D%3D%40via%3A1.1%20dc553909528b8b63475c922dc07d8ba6.cloudfront.net%20(CloudFront)/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/vap/video/airy2/prod/2.0.1459.0/css/gemini._TTW_.css css
-http://www.tumblr.com/ https://img-cedexis.mncdn.com/img/33756/r20.gif?rnd=1-1-13960-0-0-33756-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://m.imdb.com/tr/ script
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/33756/1/0/315/0/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTc1MDA4NjI4Nl5BMl5BanBnXkFtZTcwMzc1Mzg3OA@@._CR840,96,847,847_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.tumblr.com/ https://img-cedexis.mncdn.com/img/33756/r20.gif?rnd=0-1-13960-0-0-33756-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTY0OTI3NzkxOV5BMl5BanBnXkFtZTcwMTQ1MDUwOA@@._CR227,25,587,587_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/33756/0/0/315/0/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTkyNDQ1MDc5OV5BMl5BanBnXkFtZTgwOTcyNzI2MzI@._V1_SY150_CR0,0,101,150_AL_.jpg image
-http://www.tumblr.com/ https://92.media.tumblr.com/cedexis/r17.gif?rnd=1-1-13960-0-0-20363-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTU0OTMxMTA4N15BMl5BanBnXkFtZTgwODQ0MzY1NDM@._CR240,140,936,936_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/20363/1/0/324/0/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTE0MDk5OTA5MDleQTJeQWpwZ15BbWU4MDMwMDU2NTQz._CR747,322,813,813_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.tumblr.com/ https://92.media.tumblr.com/cedexis/r17.gif?rnd=0-1-13960-0-0-20363-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ http://www.zergnet.com/output.js?id=50277&time=1516015891467&callback=json6826330 script
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/0/0/20363/0/0/324/0/0 text
-http://www.imdb.com/ https://s.media-imdb.com/twilight/?PageType=homepage&Geo=US&tw_ord=f967a13a0e915bef4a62a3701bbd07c1c7bd0e35&timestamp=2018-01-15T11%3A31%3A26GMT&Client=chrome&Site=mobile&Operation.1=page_load&OperationTiming.1=1019&ord=6975889141937783 image
-http://www.tumblr.com/ https://90.media.tumblr.com/cedexis/r20.gif?rnd=1-1-13960-1-13960-30623-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjAxMjA0MTk0NV5BMl5BanBnXkFtZTgwOTE1MzY1NDM@._CR152,93,998,998_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BOTg4M2JkNTMtZmM0NC00NDQ3LWFmNGEtMDIwNDhhMjllMDkxXkEyXkFqcGdeQXVyNDQ3NjYwNg@@._V1_SY345_CR26,0,233,345_AL_.jpg image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/1/13960/30623/1/0/324/0/0 text
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTkzNTgxNDkwNV5BMl5BanBnXkFtZTgwMzY3NzE3MTI@._V1_SY345_CR0,0,233,345_AL_.jpg image
-http://www.tumblr.com/ https://90.media.tumblr.com/cedexis/r20.gif?rnd=0-1-13960-1-13960-30623-3296103783-_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTcwMTg0MDUzOF5BMl5BanBnXkFtZTgwNTA5OTI5NTE@._V1_SY345_CR23,0,233,345_AL_.jpg image
-http://www.tumblr.com/ https://rpt.cedexis.com/f1/_CgJqMRAUGD8iBQgBEIhtKOea2qMMMPDDXDiTo_LSBUDK-sGKBEoUCAEQ3wEYwXYgh4CAwAQoroCAoARQlan8AVoUCAEQ3wEYgAogioCAwAQohYCAoARgAWoaYnV0dG9uLXdvcmtlcjEuaWFkLmh2LnByb2SCARQIARDfARiACiCKgIDABCiFgICgBIgBlan8aQ/1/13960/30623/0/0/324/0/0 text
-http://www.imdb.com/ http://b.scorecardresearch.com/b?c1=2&c2=6034961&rn=0.11760959879787691&c7=http%3A%2F%2Fm.imdb.com%2F&c3=&c4=http%3A%2F%2Fm.imdb.com%2F&c5=&c6=&c10=&c15=&c16=&c8=IMDb%20-%20Movies%2C%20TV%20and%20Celebrities%20-%20IMDb&c9=&cv=1.7 other
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BZDM1YTgxNTEtZGVmYS00OGYyLTg3MTktYzA0ZTJlNDM2MTQzXkEyXkFqcGdeQXVyNzg3NjUyMTM@._CR645,69,1012,758_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BZDNmZDUwYWQtYmUyMi00OTgyLTk3MGItY2QyMTkyNzcxMjEwXkEyXkFqcGdeQXVyNDIwMDMwMjQ@._CR565,9,2233,1673_UX614_UY460._SX350_CR0,0,350,262_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BNTQwMDg0OTQwN15BMl5BanBnXkFtZTgwNDg4NTgxNDM@._CR231,65,973,973_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DMobileAppUpsellWidget%26bb0%3D155%26pc0%3D2785%26ld0%3D159%26t0%3D1516015888655%26csmtags%3D%7C%7C:2790 image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BNjRhNDY2ZmMtYmI5Ni00NzlkLTgzZWUtZTQ0ZTFjMGIxMTI2L2ltYWdlL2ltYWdlXkEyXkFqcGdeQXVyNDQxNjcxNQ@@._CR540,18,750,750_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BYjMyZjZmZjItZjYwMC00MzQzLWJjYmUtMjI4ZDAyZDNjYjE3XkEyXkFqcGdeQXVyMzY0NTA5NDU@._CR282,1,715,715_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ http://b.scorecardresearch.com/b2?c1=2&c2=6034961&rn=0.11760959879787691&c7=http%3A%2F%2Fm.imdb.com%2F&c3=&c4=http%3A%2F%2Fm.imdb.com%2F&c5=&c6=&c10=&c15=&c16=&c8=IMDb%20-%20Movies%2C%20TV%20and%20Celebrities%20-%20IMDb&c9=&cv=1.7 other
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BZTI0MjllMGMtOGYxMi00MTczLWJiMzMtNTA2ZmYxMDE5NmRiXkEyXkFqcGdeQXVyNjkwNzEwMzU@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/external-button._CB304896345_.png image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/IMDb/icon/external-button-hover._CB304896345_.png image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjIzNTYyOTkyOV5BMl5BanBnXkFtZTgwNzk5NzYzNDM@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTYzMDE2MzI4MF5BMl5BanBnXkFtZTgwNTkxODgxOTE@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DHeroWidget%26bb0%3D159%26pc0%3D2791%26ld0%3D204%26t0%3D1516015888700%26csmtags%3D%7C%7C:2791 image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjMyNDkzMzI1OF5BMl5BanBnXkFtZTgwODcxODg5MjI@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ http://img5.zergnet.com/2344166_300.jpg image
-http://www.imdb.com/ http://img1.zergnet.com/2398808_300.jpg image
-http://www.imdb.com/ http://img2.zergnet.com/2070753_300.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BYWVhZjZkYTItOGIwYS00NmRkLWJlYjctMWM0ZjFmMDU4ZjEzXkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BNDFmZjgyMTEtYTk5MC00NmY0LWJhZjktOWY2MzI5YjkzODNlXkEyXkFqcGdeQXVyMDA4NzMyOA@@._V1_SX233_CR0,0,233,345_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTUzMDUwOTU2N15BMl5BanBnXkFtZTgwODQ4NzU1NDM@._CR125,140,1092,1092_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMTg0OTMyNTcwM15BMl5BanBnXkFtZTgwMDAzNTQ5MjI@._CR442,43,1019,1019_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BZWY0NTk4NGMtZDY1ZC00YmEwLTllYmYtNGU2NTZhYzE0ZWE1XkEyXkFqcGdeQXVyNDU4Njg2MzM@._CR725,691,434,434_UX402_UY402._SY233_SX233_AL_.jpg image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D205%26pc0%3D2791%26ld0%3D205%26t0%3D1516015888701%26csmtags%3D%7C%7C:2791 image
-http://www.imdb.com/ http://img4.zergnet.com/2269095_300.jpg image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/vap/video/airy2/prod/2.0.1459.0/js/airy.ads._TTW_.js script
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D206%26pc0%3D2791%26ld0%3D247%26t0%3D1516015888743%26csmtags%3D%7C%7C:2791 image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D247%26pc0%3D2791%26ld0%3D262%26t0%3D1516015888758%26csmtags%3D%7C%7C:2792 image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/M/MV5BMjUxMDQwNjcyNl5BMl5BanBnXkFtZTgwNzcwMzc0MTI@._V1_UY274_CR0%2C0%2C184%2C274_AL_.jpg image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D262%26pc0%3D2797%26ld0%3D272%26t0%3D1516015888768%26csmtags%3D%7C%7C:2797 image
-http://www.imdb.com/ https://ia.media-imdb.com/images/G/01/imdb/images/mobile/mobile_sprite_x2-27452193._V_.png image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D272%26pc0%3D2797%26ld0%3D276%26t0%3D1516015888772%26csmtags%3D%7C%7C:2797 image
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/vap/video/airy2/prod/2.0.1459.0/skins/gemini._TTW_.js script
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNewsDeskWidget%26bb0%3D276%26pc0%3D2797%26ld0%3D306%26t0%3D1516015888802%26csmtags%3D%7C%7C:2797 image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D307%26pc0%3D2797%26ld0%3D308%26t0%3D1516015888804%26csmtags%3D%7C%7C:2798 image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DBornTodayWidget%26bb0%3D308%26pc0%3D2798%26ld0%3D309%26t0%3D1516015888805%26csmtags%3D%7C%7C:2798 image
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D309%26pc0%3D2798%26ld0%3D311%26t0%3D1516015888807%26csmtags%3D%7C%7C:2798 image
-http://www.imdb.com/ http://ia.media-imdb.com/images/G/01/imdb/images/mobile/android-mobile-196x196-1358942022._CB514891826_.png image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D314%26pc0%3D2798%26ld0%3D358%26t0%3D1516015888854%26csmtags%3D%7C%7C:2798 image
-http://www.pinterest.com/ https://www.pinterest.com/ html
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D358%26pc0%3D2798%26ld0%3D370%26t0%3D1516015888866%26csmtags%3D%7C%7C:2798 image
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/entryChunk-webpack-7baa9c4465a08ade1afb.js script
-http://www.imdb.com/ https://images-na.ssl-images-amazon.com/images/G/01/imdbads/custom/test/index/js/show_ads.js script
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-locale-en_US-mobile-a3fb8dae789dcc945317.js script
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/vendor-mweb-04a902b54856bcb72e93.js script
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DPollWidget%26bb0%3D370%26pc0%3D2798%26ld0%3D372%26t0%3D1516015888868%26csmtags%3D%7C%7C:2798 image
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DNinjaWidget%26bb0%3D372%26pc0%3D2798%26ld0%3D402%26t0%3D1516015888898%26csmtags%3D%7C%7C:2798 image
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/entryChunk-mobile-7ee77c37347117e9d59c.js script
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3DZergnetWidget%26bb0%3D403%26pc0%3D2798%26ld0%3D436%26t0%3D1516015888932%26csmtags%3D%7C%7C:2798 image
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-SignupPage-4daa8d5178f77cc8fa8a.js script
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26ctb%3D1%26sc0%3Dimdb_comscore_request%26pc0%3D4398%26ld0%3D4398%26t0%3D1516015892894%26csmtags%3D%7C%7C:4400 image
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-UnauthPageWrapper-218fb4c3fc8bbf805f9e.js script
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.imdb.com/ https://s.amazon-adsystem.com/iu3?d=imdb.com&a1=&a2=010112dd9f07cf43337cc242f81bc04f3ece1ac2c4e02fcec7f40a5bf2546834604e&cb=685832687953&pId=&r=1&rP=http%3A%2F%2Fm.imdb.com%2F&encoding=server html
-http://www.imdb.com/ http://fls-na.amazon.com/1/batch/1/OP/A1EVAM02EL8SFB:147-0209080-3317070:1BE2A95TT4NYVKKJNT6R:m.imdb.com$uedata=s:%2Fuedata%2F147-0209080-3317070%2F%3Fld%26v%3Da02%26id%3D1BE2A95TT4NYVKKJNT6R%26m%3D1%26sc%3D1BE2A95TT4NYVKKJNT6R%26ue%3D1%26bb%3D18%26cf%3D204%26af%3D205%26be%3D2474%26pc%3D9823%26tc%3D-3936%26na_%3D-3936%26fe_%3D-2866%26lk_%3D-2865%26_lk%3D-2545%26co_%3D-2545%26_co%3D-2173%26rq_%3D-2173%26rs_%3D-1664%26_rs%3D-1642%26dl_%3D-1659%26di_%3D2531%26de_%3D2532%26_de%3D2614%26_dc%3D9818%26ld_%3D9820%26ty%3D0%26rc%3D0%26ld%3D9824%26t%3D1516015898320%26ctb%3D1%26csmtags%3D%7C%7Cnonredirect:9824 image
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-167-a09c412ad4dc9e5d044f.js script
-http://www.imdb.com/ https://s.amazon-adsystem.com/v3/pr?exlist=pp_ns_rx_fban_bsw_bk_dm_aold_simplifi_c1x_br_aolv_centro_adelphic_adb_sovrn_sx_brt_kr_g_ox_index_an_rb_rbd_ppt_y_pm_tbl_3lift&fv=1.0&a=cm&ep=8m4Tw8rdPYQLRM0bb5qeTWoluC9epqDcvegP0PD3BdnEEZ3LUab5bXHqtXer-qja html
-http://www.imdb.com/ https://t.brand-server.com/match_a9?r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24UID%26ex%3Dcentro other
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-LoginPage-b6ebc91e484296675ab2.js script
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-CloseupPage-8f7f29cb4da8656feac8.js script
-http://www.imdb.com/ https://sync.c1exchange.com/sync/user?cb=CACHE_BUSTER&pid=a914869&url=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dc1x.com%26id%3D%24C1XUID other
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-ExplorePage-d1a4364f03d8d5616c20.js script
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.pinterest.com/ https://s.pinimg.com/webapp/js/pjs-EmailSignupPage-ad5eeee81f60788f48cd.js script
-http://www.pinterest.com/ https://apis.google.com/js/client:plusone.js script
-http://www.pinterest.com/ https://connect.facebook.net/en_US/sdk.js script
-http://www.imdb.com/ https://www.facebook.com/audiencenetwork/idsync?partner=1881141382166183&callback=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dfb.com%26id%3D%7BBUYERUID%7D html
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.oDs8HZEv41Y.O/m=client,plusone/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg/cb=gapi.loaded_0 script
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.oDs8HZEv41Y.O/m=signin_annotation/exm=client,plusone/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg/cb=gapi.loaded_1 script
-http://www.imdb.com/ https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com other
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.oDs8HZEv41Y.O/m=auth/exm=client,plusone,signin_annotation/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg/cb=gapi.loaded_2 script
-http://www.pinterest.com/ https://apis.google.com/_/widget/render/signin?usegapi=1&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login%20email&clientid=694505692171-31closf3bcmlt59aeulg2j81ej68j6hk.apps.googleusercontent.com&apppackagename=com.pinterest&redirecturi=postmessage&accesstype=offline&cookiepolicy=single_host_origin&origin=https%3A%2F%2Fwww.pinterest.com&url=https%3A%2F%2Fwww.pinterest.com%2F&gsrc=3p&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en_US.oDs8HZEv41Y.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg html
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.oDs8HZEv41Y.O/m=signin/exm=auth,client,plusone,signin_annotation/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg/cb=gapi.loaded_3 script
-http://www.pinterest.com/ https://www.facebook.com/impression.php/f1aea4b5294249/?api_key=274266067164&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D image
-http://www.imdb.com/ https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1 other
-http://www.pinterest.com/ https://www.facebook.com/impression.php/f26d823a7d32724/?api_key=274266067164&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D image
-http://www.imdb.com/ https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com other
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.oDs8HZEv41Y.O/m=googleapis_client,gapi_iframes_style_common,gapi_iframes_iframer/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg/cb=gapi.loaded_0 script
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=fb.com&id=V4_GGIBw96z1flmCcIHFpM82LRok4UnU82R-S6YzG81IbjSX81VKjEGS1FdizDAr88eGL_oWaJY2yTT2Sr85y0z7x3nXZB_yklRkY8zYfzmknSSo1VOdd6oWiL7_CUNTNS8r4gEjBgsAQhiSmMkqmSHESnczdhgQSEkOlGlKe3bQA78-bg1xJnv6ufxUuEd15B3Bt0A image
-http://www.imdb.com/ https://secure-assets.rubiconproject.com/utils/xapi/multi-sync.js script
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=Frh8WVCUNsvV&ex=pulsepoint.com&ev=&pid=557477 image
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.connect.en_US.48Y_cGEOhcg.O/m=c5t/rt=j/sv=1/d=1/ed=1/rs=AGLTcCMfel0-VA_VzKAcixYwiXX2F7lW7g/cb=gapi.loaded_1 script
-http://www.imdb.com/ https://um.simpli.fi/match_redirect?sifi_redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dsimplifi%26id%3D%24UID html
-http://www.imdb.com/ https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1&verify=true other
-http://www.pinterest.com/ https://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.pinterest.com/ https://www.gstatic.com/images/branding/googleg/2x/googleg_standard_color_18dp.png image
-http://www.imdb.com/ https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=districtm image
-http://www.pinterest.com/ https://accounts.google.com/o/oauth2/postmessageRelay?parent=https%3A%2F%2Fwww.pinterest.com&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en_US.oDs8HZEv41Y.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg html
-http://www.pinterest.com/ https://apis.google.com/js/rpc:shindig_random.js?onload=init script
-http://www.imdb.com/ https://x.bidswitch.net/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.pinterest.com/ https://www.pinterest.com/resource/UserRegisterTrackActionResource/update/ script
-http://www.pinterest.com/ https://ssl.gstatic.com/accounts/o/1765587600-postmessagerelay.js script
-http://www.pinterest.com/ https://apis.google.com/_/scs/apps-static/_/js/k=oz.gapi.en_US.oDs8HZEv41Y.O/m=rpc,shindig_random/rt=j/sv=1/d=1/ed=1/am=AQ/rs=AGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg/cb=gapi.loaded_0 script
-http://www.imdb.com/ https://aa.agkn.com/adscores/g.pixel?sid=9212284268 other
-http://www.imdb.com/ https://sync.1rx.io/usersync2/rmpssp?sub=amazon&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%5BRX_UUID%5D%26ex%3Drhythmone.com html
-http://www.imdb.com/ https://geo-um.btrll.com/v1/map_pixel/partner/64.png image
-http://www.imdb.com/ https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D text
-http://www.pinterest.com/ https://www.facebook.com/connect/ping?client_id=274266067164&domain=www.pinterest.com&origin=2&redirect_uri=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FlY4eZXm_YWu.js%3Fversion%3D42%23cb%3Df34fe63a31c9644%26domain%3Dwww.pinterest.com%26origin%3Dhttps%253A%252F%252Fwww.pinterest.com%252Ff25da53d9106ca4%26relation%3Dparent&response_type=token%2Csigned_request%2Ccode&sdk=joey html
-http://www.imdb.com/ https://bh.contextweb.com/visitormatch?p=547259,530912,534301,548607,530739,561117&rurl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3DPulsepoint other
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=6c19540d223d3e47a097c74d02b856e437a4a4e5&ex=aoldisplay.com image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=simplifi&id=385A17C61F915C5AF308432202390B6D image
-http://www.pinterest.com/ https://www.facebook.com/v2.7/plugins/login_button.php?app_id=274266067164&auto_logout_link=false&button_type=continue_with&channel=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FlY4eZXm_YWu.js%3Fversion%3D42%23cb%3Df34ba52740536e4%26domain%3Dwww.pinterest.com%26origin%3Dhttps%253A%252F%252Fwww.pinterest.com%252Ff25da53d9106ca4%26relation%3Dparent.parent&container_width=328&locale=en_US&max_rows=1&scope=public_profile%2Cemail%2Cuser_likes%2Cuser_about_me%2Cuser_birthday%2Cuser_friends&sdk=joey&show_faces=false&size=large&use_continue_as=true&width=100%25 html
-http://www.imdb.com/ https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.pinterest.com/ https://www.facebook.com/rsrc.php/v3iG-04/ye/l/en_US/krSljfz11F_.js script
-http://www.imdb.com/ https://ap.lijit.com/beacon/amazon?url=https://s.amazon-adsystem.com/ecm3?id=$UID&ex=sovrn.com html
-http://www.pinterest.com/ https://accounts.google.com/o/oauth2/auth?client_id=694505692171-31closf3bcmlt59aeulg2j81ej68j6hk.apps.googleusercontent.com&response_type=code%20token%20id_token%20gsession&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login%20email&access_type=offline&after_redirect=keep_open&cookie_policy=single_host_origin&prompt=none&include_granted_scopes=true&proxy=oauth2relay849947492&redirect_uri=postmessage&origin=https%3A%2F%2Fwww.pinterest.com&gsiwebsdk=1&state=466449584%7C0.2970575536&authuser=0&e=3100077&jsh=m%3B%2F_%2Fscs%2Fapps-static%2F_%2Fjs%2Fk%3Doz.gapi.en_US.oDs8HZEv41Y.O%2Fm%3D__features__%2Fam%3DAQ%2Frt%3Dj%2Fd%3D1%2Frs%3DAGLTcCMKmOFsLt6gC9SaO3LTS1N0lTOVsg html
-http://www.imdb.com/ https://geo-um.btrll.com/v1/map_pixel/partner/64.png?set_aps=1&BR_APS=3WlyRIBf5DiIBvmoIcg& image
-http://www.pinterest.com/ https://www.facebook.com/rsrc.php/v3/yC/r/aMltqKRlCHD.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=aolvideo.com&id=809bdcc94fe8bb057d3743aa9483dac5409288b0 image
-http://www.pinterest.com/ https://ssl.gstatic.com/accounts/o/2142924139-postmessage.js script
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=bidswitch.com&id=175a1cbcf461b893c01ddfb85db8e029 image
-http://www.pinterest.com/ https://www.facebook.com/v2.7/plugins/login_button.php?app_id=274266067164&auto_logout_link=false&button_type=continue_with&channel=https%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FlY4eZXm_YWu.js%3Fversion%3D42%23cb%3Df3072fe6e3d80dc%26domain%3Dwww.pinterest.com%26origin%3Dhttps%253A%252F%252Fwww.pinterest.com%252Ff25da53d9106ca4%26relation%3Dparent.parent&container_width=0&locale=en_US&max_rows=1&scope=public_profile%2Cemail%2Cuser_likes%2Cuser_about_me%2Cuser_birthday%2Cuser_friends&sdk=joey&show_faces=false&size=large&use_continue_as=true&width=100%25 html
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=3WlyRIBf5DiIBvmoIcg&ex=brightroll.com&n=1516015904& image
-http://www.pinterest.com/ https://s.pinimg.com/webapp/style/images/favicon-9f8f9adf.png image
-http://www.imdb.com/ https://stags.bluekai.com/site/36841?dt=0&r=1415357735&sig=2032588566&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmiRglWl1u3dep5hJEi0rvuNa028whzGcC3z3bh3gaqjG33LRr3ADZXAl5XSvQ7AsZVVQWDuLGoEzNmp9xoOQeP0hFr other
-http://www.imdb.com/ https://tap-secure.rubiconproject.com/partner/scripts/rubicon/emily.html?rtb_ext=1&geo=na&co=us html
-http://www.pinterest.com/ https://www.pinterest.com/resource/ContextLogResource/create/ script
-http://www.imdb.com/ https://dpm.demdex.net/ibs:dpid=139200&dpuuid=Gu3woMw7S9SxtJhdL84guQ&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D other
-http://www.pinterest.com/ https://www.pinterest.com/resource/UserRegisterTrackActionResource/update/ script
-http://www.imdb.com/ https://sync.ipredictive.com/d/sync/cookie/generic?https://s.amazon-adsystem.com/ecm3?id=${ADELPHIC_CUID}&ex=adelphic other
-http://www.imdb.com/ https://cookie.brealtime.com/getuid?https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbrealtime.com%26id%3D%24UID other
-http://www.imdb.com/ https://d.agkn.com/pixel/8198/?che=1516015904&sk=164801102571000793831&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164801102571000793831&ex=neustar.biz other
-http://www.imdb.com/ https://eb2.3lift.com/getuid?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3D3lift.com%26id%3D%24UID other
-http://www.imdb.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=1255654063 html
-http://www.imdb.com/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=Gu3woMw7S9SxtJhdL84guQ&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=aade0cc7-f9e7-11e7-949e-c1799620084b&ex=adelphic image
-http://www.imdb.com/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID other
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=164801102571000793831&ex=neustar.biz image
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm&ex=doubleclick.net html
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc html
-http://www.imdb.com/ https://match.adsrvr.org/track/cmb/generic?ttd_pid=adconductor&ttd_tpi=1&rndcb=1255654063 html
-http://www.imdb.com/ https://eb2.3lift.com/getuid?ld=1&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3D3lift.com%26id%3D%24UID other
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=adobe.com&id=22099476997039232021784972381553010122 image
-http://www.imdb.com/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=e1100614-f9e7-11e7-8af3-1976204a0001 other
-http://www.imdb.com/ https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com image
-http://www.imdb.com/ https://sync.1rx.io/usersync/tradedesk/e9cec63b-bde6-4ebf-ad26-0e8b7f3d01b3 html
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=a9&google_cm=&ex=doubleclick.net&google_tc= html
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm=&google_sc=&google_tc= html
-http://www.github.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.imdb.com/ https://usermatch.krxd.net/um/v2?partner=amzn other
-http://www.github.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAv9tAkK17XmQMMLFslSmieiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=3lift.com&id=14848554405730175767 image
-http://www.github.com/ https://www.github.com/ other
-http://www.imdb.com/ https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.github.com/ https://github.com/ html
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=spotx.com&id=e1105aae-f9e7-11e7-8af3-1976204a0001 image
-http://www.github.com/ https://assets-cdn.github.com/assets/frameworks-700c269c41d75b60698a62d9306dae4a0f840bec4718545615f752400f1fd908.css css
-http://www.github.com/ https://assets-cdn.github.com/assets/github-c7fa3a7e0dba4dcf7a3fa38cfcddd70a30e01fd27aee0b455615e7967047b47c.css css
-http://www.imdb.com/ https://tags.bluekai.com/site/2981?id=&google_gid=CAESEJRG9jIvTQ_uXFB9b6dgMP4&google_cver=1 image
-http://www.github.com/ https://assets-cdn.github.com/assets/frameworks-2dac127ae89b81b6aa4fb6eb9d15c2bdb43fa4a19d81c17e3d8318d924f6226e.js script
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=doubleclick.net&google_gid=CAESENc_JU799G9yDWsqjFD14Rw&google_cver=1 image
-http://www.github.com/ https://assets-cdn.github.com/assets/site-e2f78def14631b7fd769bf918598cd7d437e67a706a2676aa466634d28ffaabd.css css
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=RX-66fe7712-3a3d-4852-90ef-5dde0e9cbcb0&ex=rhythmone.com image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/home-illo-team-chaos.svg image
-http://www.imdb.com/ https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D image
-http://www.imdb.com/ https://secure.adnxs.com/getuid?https%3A%2F%2Fe1.emxdgt.com%2Fa9-sync%3Fapnxid%3D%24UID image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/home-illo-team-code.svg image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/home-illo-team.svg image
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=contextweb&google_cm&google_sc html
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/heroes/simple-codelines.svg image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=e58ff858-0b78-c69a-2ccd-e39c82bae451 image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/home-illo-team-tools.svg image
-http://www.imdb.com/ https://match.adsrvr.org/track/cmf/contextweb html
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/home-illo-business.png image
-http://www.imdb.com/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__ html
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/slackhq.png image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/zenhubio.png image
-http://www.imdb.com/ https://bh.contextweb.com/bh/rtset?do=add&pid=547259&ev=CAESEJVjK5UfZfAIpwaIsGUPivk&google_cver=1 image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/travis-ci.png image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/atom.png image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/circleci.png image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/codeship.png image
-http://www.imdb.com/ https://bh.contextweb.com/bh/rtset?do=add&pid=534301&ev=e9cec63b-bde6-4ebf-ad26-0e8b7f3d01b3 image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/integrators/codeclimate.png image
-http://www.imdb.com/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1 html
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/developers/ariya.png image
-http://www.imdb.com/ https://ads.yahoo.com/cms/v1?esig=1~b9bada6fffbf45c1ffda7783879fb5715486894a&nwid=10000922750&sigv=1 text
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/developers/freakboy3742.png image
-http://www.imdb.com/ https://token.rubiconproject.com/token?pid=2179&pt=n other
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/customers/mailchimp.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=Frh8WVCUNsvV&ex=Pulsepoint image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/developers/kris-nova.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=index&id=Ew6mE4H4q1pwUlR1rI1uNTd5ccs4ZgIC image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/developers/yyx990803.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=rightmedia.com&xid=E0 image
-http://www.imdb.com/ https://trc.taboola.com/sg/amazon-a9-network/1/rtb other
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/customers/mapbox.png image
-http://www.imdb.com/ https://token.rubiconproject.com/khaos image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/stories/developers/jessfraz.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/airbnb-logo.png image
-http://www.imdb.com/ https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/sap-logo.png image
-http://www.imdb.com/ https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID html
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/ibm-logo.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?ex=taboola.com&id=aa4a56fa-c807-4b82-8104-c80aba321b57-tuct15616a4 image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/google-logo.png image
-http://www.imdb.com/ https://openx2-match.dotomi.com/pulsepoint/match other
-http://www.imdb.com/ https://token.rubiconproject.com/token?pid=2974&pt=n&a=1 other
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/paypal-logo.png image
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=AEA21A9E-656D-4C49-BA60-7209E9D17403&ex=pubmatic.com image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/bloomberg-logo.png image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/spotify-logo.png image
-http://www.imdb.com/ https://match.adsrvr.org/track/cmf/rubicon html
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/swift-logo.png image
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=rubicon&google_cm&google_sc html
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/facebook-logo.png image
-http://www.imdb.com/ https://magnetic.t.domdex.com/sync/contextweb image
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/node-logo.png image
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/nasa-logo.png image
-http://www.imdb.com/ https://openx2-match.dotomi.com/pulsepoint/match?dtm_test=22e6c2bd96da0943 other
-http://www.github.com/ https://assets-cdn.github.com/images/modules/site/logos/walmart-logo.png image
-http://www.imdb.com/ https://bh.contextweb.com/bh/rtset?do=add&pid=530912&ev=AAADSl0NYj1ptgYphc-4AAAAAAA image
-http://www.github.com/ https://assets-cdn.github.com/assets/github-592bdcc9916cebab402ce09d893f4335b9f78a02dc206798816c3ed48a69183c.js script
-http://www.imdb.com/ https://sync-tm.everesttech.net/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D191940%26nid%3D3778%26put%3D%24%7BUSER_ID%7D other
-http://www.github.com/ https://assets-cdn.github.com/static/fonts/roboto/roboto-light.woff font
-http://www.github.com/ https://assets-cdn.github.com/static/fonts/roboto/roboto-regular.woff font
-http://www.imdb.com/ https://usync.aws.rubiconproject.com/yahoo-brx html
-http://www.github.com/ https://assets-cdn.github.com/static/fonts/roboto/roboto-medium.woff font
-http://www.imdb.com/ https://usync.aws.rubiconproject.com/google html
-http://www.github.com/ https://www.google-analytics.com/r/collect image
-http://www.imdb.com/ https://sync.mathtag.com/sync/img?mt_exid=9&redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D4222%26nid%3D1512%26put%3D%5BMM_UUID%5D image
-http://www.github.com/ https://collector.githubapp.com/github/page_view?dimensions[page]=https%3A%2F%2Fgithub.com%2F&dimensions[title]=The%20world%27s%20leading%20software%20development%20platform%20%C2%B7%20GitHub&dimensions[referrer]=&dimensions[user_agent]=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&dimensions[screen_resolution]=360x512&dimensions[pixel_ratio]=3&dimensions[browser_resolution]=360x512&dimensions[tz_seconds]=-28800&dimensions[timestamp]=1516015985861&dimensions[request_id]=C85E%3A1EA70%3A7C80E8%3AE8F7D7%3A5A5C9164&dimensions[region_edge]=sea&dimensions[region_render]=iad&&measures[performance_timing]=1-3504-2859--7015-7011-7010-3961-2859-2559-2559---0---3508-4275-3954-3177--&&&dimensions[cid]=380660052.1516015986 image
-http://www.imdb.com/ https://sync-tm.everesttech.net/ct/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D191940%26nid%3D3778%26put%3D%24%7BUSER_ID%7D&_test=WlyRJQAAAJC1Vw_5 other
-http://www.github.com/ https://assets-cdn.github.com/favicon.ico image
-http://www.imdb.com/ https://ad.turn.com/r/cs?pid=6 other
-http://www.github.com/ https://api.github.com/_private/browser/stats other
-http://www.imdb.com/ https://ads.yahoo.com/cms/v1?nwid=10000010181&eid=JCG4Q95P-1G-BHYP&sigv=1&esig=2~2153ebc8666249c88a61d65facd77bf80ee815d0 text
-http://www.imdb.com/ https://cm.g.doubleclick.net/pixel?google_nid=rp&google_hm=SkNHNFE5NVAtMUctQkhZUA== image
-http://www.github.com/ https://api.github.com/_private/browser/stats script
-http://www.imdb.com/ https://pixel.rubiconproject.com/tap.php?v=8981&nid=2307&put=e9cec63b-bde6-4ebf-ad26-0e8b7f3d01b3&expires=30 image
-http://www.imdb.com/ https://pixel.rubiconproject.com/tap.php?v=7751&nid=2249&expires=30&put=CAESEHleTZgj2tEiO3qejdA6Jks&google_cver=1 image
-http://www.imdb.com/ https://sync.mathtag.com/sync/img?mt_exid=9&redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D4222%26nid%3D1512%26put%3D%5BMM_UUID%5D&mm_bnc&mm_bct image
-http://www.imdb.com/ https://pixel.rubiconproject.com/tap.php?v=191940&nid=3778&put=WlyRJQAAAJC1Vw_5&_test=WlyRJQAAAJC1Vw_5 image
-http://www.imdb.com/ https://pixel.rubiconproject.com/tap.php?v=4212&nid=1185&put=4166707092298378147&expires=60 image
-http://www.imdb.com/ https://pixel.rubiconproject.com/tap.php?v=4222&nid=1512&put=414c5a5c-8cf1-4e00-8b1c-f49a6dca2ff4 image
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.imdb.com/ https://pixel-us-east.rubiconproject.com/exchange/sync.php?p=a9us other
-http://www.imdb.com/ https://s.amazon-adsystem.com/ecm3?id=JCG4Q95P-1G-BHYP&ex=d-rubiconproject.com&status=ok image
-http://www.imdb.com/ https://cookiex.ngd.yahoo.com/ack?xid=E0&eid=JCG4Q95P-1G-BHYP text
-http://www.imdb.com/ https://video-http.media-imdb.com/MV5BMDYwZjI2MzctZThmMi00YjlkLWI5ZmQtYmI4NjhkZTIyODZmXkExMV5BbXA0XkFpbWRiLWV0cy10cmFuc2NvZGU@.mp4?Expires=1516102291&Signature=qX3Lc~oZ9cV7h7XC19b1xVgRAlDr1oNzsErYJHmTYou5kAeEWZqJtLDGmId53vnhiGdAvuGOcPl8W1m-4WVWaQPYHALRc0Q9ekroCFEXEcDsHMJMUpD7rapjpIpcm-SNIyQVxzk0t2wiFv1qaljzuAqDcW8~xVsGsxQSrmH4p3g_&Key-Pair-Id=APKAILW5I44IHKUN2DYA video
-http://www.livejasmin.com/ http://www.livejasmin.com/ html
-http://www.livejasmin.com/ http://m.livejasmin.com/en/list/ html
-http://www.livejasmin.com/ https://m.livejasmin.com/en/list/ html
-http://www.livejasmin.com/ https://static2.dditscdn.com/mbl/frontend_backbone/static/_common/js/ga/advertisement.js script
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/css/mobile-c931e.css css
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/css/armageddon-client-c93c7.css css
-http://www.livejasmin.com/ https://static3.dditscdn.com/mbl/frontend_backbone/static/_common/member-client/script/armageddon-client.min-30fd9.js script
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/livejasmin/image/logo-cb42b.png image
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/image/loader-white-8f1dc.png image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1e/e1bbc0706085b7d922432615ffaa21d0_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1f/f0c3ad95c7a749840af0ffbbf500bafa_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1c/c29aceb4c661d31c3228c057f1865b9a_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/34c323ab324f88ecaa7291e4160ca3ae_erotic_445x250.jpg?cno=180103 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d78ee4522249258fc6c1a674f88dc72b_erotic_285x160.jpg?cno=5ab5 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f19/90539fa325fd55aad79a97a26157ee7d_erotic_445x250.jpg?cno=94f0 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f10/07526bcfbc289b82f5368b25a0950bab_erotic_285x160.jpg?cno=5cb8 image
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f15/589f718d6cea3a9102896ba1c3db9795_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f16/62a2d990b4c0567cadebff8280267103_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f11/16d1fd72678b1a134a3d39d5a7005d59_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1e/eda2b072eff30bdd9232a00907e4f10e_erotic_445x250.jpg?cno=1 image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/ html
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1b/b48d0ce7a90293ced265581037985dff_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/51dx94okAPL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,01d8Fs5iBdL.css,21mKUwWDJaL.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,3103g95VTCL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21g9AOmZB5L.css,11X2-nh0PYL.css,01h2e2BEitL.css,11AYjYP-YzL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31k72ulyOYL.css,01kPgnKe7wL.css,01MGoIPodIL.css,01Alnvtt1zL.css,01BBs40O5ZL.css_.css?AUIClients/AmazonUI css
-http://www.livejasmin.com/ https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f17/7dd658877b584d9e9f0b460262ea4e6e_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/21EugTBba7L.css?AUIClients/RetailSearchAutocompleteAssets css
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/51jo%2BAP3U9L._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset css
-http://www.livejasmin.com/ https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f18/826e4cf213285a1b594d0a5b442fafca_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41MjpWujmTL.css?AUIClients/GWMWebAssets css
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/gno/sprites/sky_webnav_V1_sprite_1x._CB515272527_.png image
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DPB9BX5S23Y13T0JFMFJF%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile:1000 image
-http://www.amazon.co.jp/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-a3d92a134e6afaec4974bceac0812b73d0b635c1._V2_.png image
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/font/JSMobile-ee302.woff font
-http://www.amazon.co.jp/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2 font
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61-dJ29Zw5L.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,51nK0kUyg2L.js,11Mdh5CVmhL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61IUvg6RIjL.js,31y9nF9Z1BL.js,11SW3HEKjtL.js,01qkmZhGmAL.js,01eORIy6e6L.js_.js?AUIClients/AmazonUI script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C414ftrYGv0L.js,11P4Lu1aIqL.js_.js?AUIClients/GWMWebAssets script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets script
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/fonts/roboto-light-webfont-c0839.woff2 font
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41XJlIDdUUL._RC%7C01vojWHr8gL.js,31qKd4DgPkL.js_.js?AUIClients/NavMobileMetaAsset script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/510wwe1qMUL.js?AUIClients/RetailSearchAutocompleteAssets script
-http://www.amazon.co.jp/ https://www.amazon.co.jp/uedata/unsticky/357-5003699-3264848/NoPageType/ntpoffrw?ld&v=0.1284.0&id=PB9BX5S23Y13T0JFMFJF&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=PB9BX5S23Y13T0JFMFJF&ue=27&bb=1699&ns=1710&cf=1979&be=2109&af=2151&ne=2271&pc=3978&tc=-1517&na_=-1517&ul_=-1516016006202&_ul=-1516016006202&rd_=-1516016006202&_rd=-1516016006202&fe_=-1395&lk_=-1395&_lk=-1213&co_=-1213&_co=-568&sc_=-904&rq_=-568&rs_=-90&_rs=220&dl_=-81&di_=2134&de_=2134&_de=2134&_dc=3978&ld_=3978&_ld=-1516016006202&ntd=-1&ty=0&rc=0&hob=24&hoe=28&ld=3989&t=1516016010191&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:13-5-4-2-3-0-0&csmtags=aui|aui:aui_build_date:3.17.20-2017-12-07|gwImgNoCached|fls-fe|pageEncoding:UTF-8|gwmNoCardHistory&viz=visible:27&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=PB9BX5S23Y13T0JFMFJF&aftb=1 image
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/font/roboto-medium-webfont-1f990.woff2 font
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D265%26cf0%3D1674%26pc0%3D1674%26ld0%3D1677%26t0%3D1516016007879%26sc1%3Dlg%26af1%3D1979%26pc1%3D1979%26ld1%3D1979%26t1%3D1516016008181%26sc2%3DcsmCELLSframework%26bb2%3D2090%26pc2%3D2092%26ld2%3D2092%26t2%3D1516016008294%26sc3%3DcsmCELLSpdm%26bb3%3D2092%26pc3%3D2101%26ld3%3D2101%26t3%3D1516016008303%26sc4%3DcsmCELLSvpm%26bb4%3D2101%26pc4%3D2104%26ld4%3D2104%26t4%3D1516016008306%26sc5%3DcsmCELLSfem%26bb5%3D2106%26pc5%3D2107%26ld5%3D2107%26t5%3D1516016008309%26sc6%3Dinteractivity%26cf6%3D3603%26pc6%3D3603%26ld6%3D3603%26t6%3D1516016009805%26ctb%3D1:3995 image
-http://www.livejasmin.com/ https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f10/03f9bc7b589cead9173133315401725f_erotic_285x160.jpg?cno=6387 image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f16/64631003af0f4202e85e7350704fe8ad_erotic_285x160.jpg?cno=fc8b image
-http://www.amazon.co.jp/ https://m.media-amazon.com/images/G/01/csm/showads.v2.js script
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D4026%26pc0%3D4026%26ld0%3D4026%26t0%3D1516016010228%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:4026 image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f19/91bbf3855760bdd7ccac842ff70a78cf_erotic_285x160.jpg?cno=37fe image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/kindle/merch/2018/1111/Tablet/GW/GW_mobile_firehd8_noprice_1242x450._SX1242_CB489874135_.jpg image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f15/5645d8ff84888b2ac5bb86db232e9e03_erotic_285x160.jpg?cno=1 image
-http://www.livejasmin.com/ https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d7ba8af0d674479f6cf57b46c274993a_erotic_285x160.jpg?cno=9325 image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/favicon.ico image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/gp/gw/ajax/dataStore.html/357-5003699-3264848?ie=UTF8&hmac=7B0EB98183F5E558126E7AFB0EB63E94E7B428C6&opf_redir=1&relatedRequestId=PB9BX5S23Y13T0JFMFJF script
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D4328%26cf0%3D4366%26pc0%3D4366%26ld0%3D4366%26t0%3D1516016010568%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:4366 image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/4d77e97f07f4905974faf1d7be7deacc_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2 font
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/gno/sprites/sky_webnav_V1_sprite_2x._CB515272527_.png image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/uedata/unsticky/357-5003699-3264848/NoPageType/ntpoffrw?at&v=0.1284.0&id=PB9BX5S23Y13T0JFMFJF&m=1&sc=adblk_no&pc=4504&at=4505&t=1516016010707&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=PB9BX5S23Y13T0JFMFJF&aftb=1 image
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26m%3D1%26sc%3Dadblk_no%26pc%3D4504%26at%3D4505%26t%3D1516016010707%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:4505 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1b/b194da4ff62b051cd0e20763f933fd30_erotic_445x250.jpg?cno=1 image
-http://www.amazon.co.jp/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2 font
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1e/e49c634b26747609646030e38d01381c_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js script
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1b/b6909313932292e82ea277626b857e3f_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2 font
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Ddata-store-1%26bb0%3D4261%26cf0%3D4854%26pc0%3D4854%26ld0%3D4854%26t0%3D1516016011056%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:4854 image
-http://www.livejasmin.com/ https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1c/cc609ef80791b38d5de6db254fd94e59_erotic_445x250.jpg?cno=1 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d246cfdb48f00dbae7c0c19bc4e49ec2_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/gp/gw/ajax/card.html/357-5003699-3264848?ie=UTF8&opf_redir=1&rshVal=1516016011101 html
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/467ac6da14df64accf4294461c560644_erotic_285x160.jpg?cno=cdda image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2016/x-site/amzoncoupon/coupon_store_blackjack_billboard_870x510._SX290_CB526536578_.png image
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/328d97710a045548adcff8054de75598_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2016/x-site/amzoncoupon/coupon_store_blackjack_billboard_870x510._SX870_CB526536578_.png image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f11/1df046ca72febc9fbb5dab3e54388d25_erotic_285x160.jpg?cno=1 image
-http://www.google.com.tr/ http://www.google.com.tr/ html
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D5120%26pc0%3D5126%26ld0%3D5126%26t0%3D1516016011328%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:5126 image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f19/93c0946d11f3a5d4de75060186d9f2ab_erotic_285x160.jpg?cno=6d86 image
-http://www.google.com.tr/ https://www.google.com.tr/?gws_rd=ssl html
-http://www.amazon.co.jp/ https://www.amazon.co.jp/gp/aw/mobile-ads/ajax/js?10 script
-http://www.google.com.tr/ https://www.google.com.tr/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f14/423674937bd066e35448064f1e820c2c_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/gp/gw/ajax/card.html/357-5003699-3264848?ie=UTF8&opf_redir=1&rshVal=1516016011567 html
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1b/b6b2f9b567ee4f89c6c1b35e6dfa5105_erotic_285x160.jpg?cno=1 image
-http://www.google.com.tr/ https://www.google.com.tr/images/nav_logo242_hr.webp image
-http://www.livejasmin.com/ https://img0.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1c/c12b9d402daa5a569d11722fc16ccedf_erotic_445x250.jpg?cno=1 image
-http://www.google.com.tr/ https://www.google.com.tr/gen_204?s=webaft&atyp=csi&ei=G5FcWpX9DsHIjwOi2IOgDQ&rt=wsrt.2046,aft.195,prt.195 html
-http://www.livejasmin.com/ https://img1.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1f/f0911d10660e0d0d5985c44fe68c6272_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41dK%2BB0KG-L._AC_SY80_.jpg image
-http://www.google.com.tr/ https://www.google.com.tr/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/rt=j/d=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/31YZ0weG21L._AC_SY80_.jpg image
-http://www.google.com.tr/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f1d/d66eb328fd5c6643449413bec0cd3602_erotic_285x160.jpg?cno=1 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41MnK1buauL._AC_SY80_.jpg image
-http://www.google.com.tr/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.livejasmin.com/ https://img3.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f12/2d2fbcd654fdb8de71bd2f67ab7d020d_erotic_285x160.jpg?cno=1 image
-http://www.google.com.tr/ https://www.google.com.tr/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw?xjs=s1 script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/fashion/04_shoes/12Dec/W/1086973_shoes_categorycard_sale_1050x1050_1._UX350_SX350_CB492650124_.jpg image
-http://www.livejasmin.com/ https://img2.dditscdn.com/ff268cab8d9fbae1ed7506f97496274f13/3afeac3e9c0537e69fe6d9dd23778069_erotic_285x160.jpg?cno=1 image
-http://www.google.com.tr/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Dgwm%26cf0%3D1979%26af0%3D5378%26pc0%3D5378%26ld0%3D5378%26t0%3D1516016011580%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:5378 image
-http://www.livejasmin.com/ https://static3.dditscdn.com/mbl/frontend_backbone/static/_common/script/mobile.browser-7900e.js script
-http://www.google.com.tr/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Dcard-load-1%26bb0%3D4899%26cf0%3D5303%26pc0%3D5360%26ld0%3D5360%26t0%3D1516016011562%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:5361 image
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/image/loader-5998b.png image
-http://www.google.com.tr/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.livejasmin.com/ https://www.google-analytics.com/analytics.js script
-http://www.google.com.tr/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.amazon.co.jp/ https://www.amazon.co.jp/gp/aw/mobile-ads/ajax html
-http://www.livejasmin.com/ https://www.googletagmanager.com/gtm.js?id=GTM-MJ29FD7 script
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Dmobileadsajaxfired%3Agrid-9%26pc0%3D5702%26ld0%3D5702%26t0%3D1516016011904%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:5702 image
-http://www.google.com.tr/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/n2a/gw/1079807_timesale_gw_mb_billboard_1242x450._SX414_CB512386221_.png image
-http://www.livejasmin.com/ https://www.google-analytics.com/gtm/js?id=GTM-K2Q3RJP&cid=634227590.1516015897 script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/415TzjIb8WL._AC_SY80_.jpg image
-http://www.google.com.tr/ https://www.google.com.tr/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.livejasmin.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=308789851&t=pageview&_s=1&dl=https%3A%2F%2Fm.livejasmin.com%2Fen%2Flist%2F&dp=%2Fen%2Flist%2F&ul=en-us&de=UTF-8&dt=livejasmin.com%20%7C%20The%20World%60s%20%231%20Most%20Visited%20Video%20Chat%20Community&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aGDAgUADQ~&jid=1268580364&gjid=871765836&cid=634227590.1516015897&uid=0&tid=UA-45543902-8&_gid=282263688.1516015897&gtm=G1cMJ29FD7&cd1=false&cd2=0&cd3=guest&cd4=HTML5&cd5=true&cd6=&cd7=m.livejasmin.com&cd10=dW5kZWZpbmVk&cd37=https&cd40=true&cd41=category&cd11=634227590.1516015897&z=1453375012 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41OgRXocjFL._AC_SY80_.jpg image
-http://www.google.com.tr/ https://www.google.com.tr/images/nav_logo242.png image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/418iluQfbyL._AC_SY80_.jpg image
-http://www.livejasmin.com/ https://m.livejasmin.com/en/window/get-over-eighteen-window text
-http://www.amazon.co.jp/ https://aax-fe.amazon-adsystem.com/s/iu3?d=amazon.co.jp&slot=navFooter&a2=010150d58bff320dbdbc9926119b167f54cf3afd2787d88f0351e0467426ef46380d&old_oo=0&cb=1516016006021 other
-http://www.google.com.tr/ https://www.google.com.tr/gen_204?atyp=csi&ei=G5FcWpX9DsHIjwOi2IOgDQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.603,dcl.365,iml.603,ol.2264,prt.195,xjs.1444,xjsee.1444,xjses.1163,xjsls.210,wsrt.2046,cst.620,dnst.0,rqst.758,rspt.400,sslt.321,rqstt.1550,unt.930,cstt.930,dit.2412&zx=1516015901858 html
-http://www.livejasmin.com/ https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=1516015898439-0 other
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41dK%2BB0KG-L._AC_SY240_.jpg image
-http://www.google.com.tr/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Dcard-load-2%26bb0%3D5365%26cf0%3D5779%26pc0%3D5840%26ld0%3D5840%26t0%3D1516016012042%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:5840 image
-http://www.livejasmin.com/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.google.com.tr/ https://www.google.com.tr/images/branding/product/1x/gsa_android_144dp.png image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/31YZ0weG21L._AC_SY240_.jpg image
-http://www.livejasmin.com/ https://bat.bing.com/bat.js script
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OP/A1VC38T7YXB528:357-5003699-3264848:PB9BX5S23Y13T0JFMFJF$uedata=s:%2Fuedata%2Funsticky%2F357-5003699-3264848%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DPB9BX5S23Y13T0JFMFJF%26ctb%3D1%26sc0%3Dmobileadsajaxnocontent%3Agrid-9%26pc0%3D6076%26ld0%3D6076%26t0%3D1516016012278%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DPB9BX5S23Y13T0JFMFJF%26aftb%3D1:6076 image
-http://www.google.com.tr/ https://adservice.google.com.tr/adsid/google/ui html
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OE/ other
-http://www.livejasmin.com/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-45543902-8&cid=634227590.1516015897&jid=1268580364&gjid=871765836&_gid=282263688.1516015897&_u=aGDAgUADQ~&z=993339497 html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31JZUXRQoEL.css_.css?AUIClients/SharedShoppingCartMobileAsset css
-http://www.livejasmin.com/ https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=1516015900052-2&sid=Hsd83N3ACXPd7_n9O_SY other
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/317Qb9WY18L._RC%7C51V43Ve3tjL.js_.js?AUIClients/SharedShoppingCartMobileAsset script
-http://www.livejasmin.com/ https://static4.dditscdn.com/mbl/frontend_backbone/static/_common/fonts/roboto-regular-webfont-71f67.woff2 font
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/01G0dXhANDL.js?AUIClients/DetailPageAlohaAssets script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets css
-http://www.livejasmin.com/ https://bat.bing.com/action/0?ti=5624388&Ver=2&mid=2a5758f4-85a9-a9c6-d0b9-d487b747d30e&evt=pageLoad&sid=4c89ecc7-1&lt=9902&pi=0&lg=en-US&sw=360&sh=512&sc=24&tl=livejasmin.com%20|%20The%20World`s%20 other
-http://www.livejasmin.com/ https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=1516015900376-3&sid=Hsd83N3ACXPd7_n9O_SY other
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/11chYsfG59L._RC%7C411E-IzoCiL.js,31cePTj3CrL.js,11NxOa490XL.js,31E+jMbvKeL.js,21ydeSYKyxL.js,31hd9A67kaL.js,51wmFWz9R9L.js,51Hi2VfLU+L.js,21yUMfZsKLL.js,31Ime9qWaBL.js,016DBHJkIYL.js,21ng+A1rTWL.js,41mcGVaoxHL.js,71XpcjNHo8L.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,11eu-Mk7IDL.js,21AuBaN+lVL.js,51YzCqyJFIL.js,0111g0cQvbL.js,01nKqcvaCIL.js,01X117Z9PgL.js,41dV+QF7fUL.js,01X5C8pWB1L.js,518wG9hJ8NL.js,31egXBuM55L.js,01RHiyjONOL.js,31I-BifbuzL.js,210S22NrxIL.js,412fOjq25KL.js,314ZAgS3sJL.js,11U-t4vkrhL.js,21XRsSHl9HL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,51rCZ2WOe0L.js,71OuhyN2DxL.js,01BZK417f8L.js,319kjuuQkzL.js,01UujNMpLSL.js,41Eexuqvf6L.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,015J4NGaO3L.js,11B4fwZPeqL.js,21-q-ofQTaL.js,01lQqh9VSML.js,01jqyAujTwL.js,01KcbtwkAOL.js,01-XJ1YSEXL.js,01gaQLz1HjL.js,01NAT+3p7KL.js,111vgqp2a0L.js,51yQ7wSC4tL.js,01MZJG6lH8L.js,01VtYReatCL.js,21LWJ90NCIL.js,01CyECqkeYL.js,01RQtSMdG+L.js,21JwQBfgBXL.js,01l3c7okxRL.js,01qwoVEkKlL.js,31HureBIyaL.js,011X+p22ALL.js,01k57x9vvBL.js,01RNXZDiBuL.js,01ZF+ovNflL.js,31MsfX4iIYL.js,01S8y9NkxoL.js,01XzM3S0ZtL.js,01JGca-NkDL.js,01WMAHenIIL.js,51tlWANRbLL.js_.js?AUIClients/DetailPageMobileWebMetaAsset script
-http://www.livejasmin.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-45543902-8&cid=634227590.1516015897&jid=1268580364&_v=j66&z=993339497 image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/subscribe_save/gw/mobile/1049516_gw_mobilebillboard_02_1242x450._SX414_CB507792628_.jpg image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/other/1079133_clealance_store_gw_mobilebillboard_1242x450._SX414_CB494454373_.png image
-http://www.livejasmin.com/ http://jaws.dditscdn.com/socket.io/?EIO=3&transport=websocket&sid=Hsd83N3ACXPd7_n9O_SY other
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/31efvGROBqL._AC_SY200_.jpg image
-http://www.livejasmin.com/ https://jaws.dditscdn.com/socket.io/?EIO=3&transport=polling&t=1516015900042-1&sid=Hsd83N3ACXPd7_n9O_SY html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/n2a/gw/1079807_n2a_gw_mb_billboard_1242x450._SX414_CB512386221_.png image
-http://www.livejasmin.com/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=livejasmin.com%20%7C%20The%20World%60s%20%231%20Most%20Visited%20Video%20Chat%20Community&time=1516015900147&time_zone_offset=480&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fm.livejasmin.com%2Fen%2Flist%2F&random_number=8433442851&sess_cookie=9283a43e160f996d5f3e6d9b91b&sess_cookie_flag=1&user_cookie=9283a43e160f996d5f3e6d9b91b&user_cookie_flag=1&dynamic=true&domain=livejasmin.com&account=z5aJm1akGFL1uG&jsv=20130128&user_lang=en-US image
-http://www.google.com.au/ http://www.google.com.au/ html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41MnK1buauL._AC_SY240_.jpg image
-http://www.livejasmin.com/ https://static2.dditscdn.com/mbl/frontend_backbone/static/livejasmin/image/favicon-838c4.ico image
-http://www.google.com.au/ https://www.google.com.au/?gws_rd=ssl html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/fashion/04_shoes/12Dec/W/1086973_shoes_categorycard_sale_1050x1050_1._CB492650124_.jpg image
-http://www.livejasmin.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=308789851&t=timing&_s=2&dl=https%3A%2F%2Fm.livejasmin.com%2Fen%2Flist%2F&dp=%2Fen%2Flist%2F&ul=en-us&de=UTF-8&dt=livejasmin.com%20%7C%20The%20World%60s%20%231%20Most%20Visited%20Video%20Chat%20Community&sd=24-bit&sr=360x512&vp=360x512&je=0&plt=17733&pdt=14&dns=0&rrt=1903&srt=415&tcp=943&dit=9902&clt=9902&_u=6GDAgUADQ~&jid=&gjid=&cid=634227590.1516015897&uid=0&tid=UA-45543902-8&_gid=282263688.1516015897&gtm=G1cMJ29FD7&cd1=false&cd2=0&cd3=guest&cd4=HTML5&cd5=true&cd6=&cd7=m.livejasmin.com&cd10=dW5kZWZpbmVk&cd37=https&cd40=true&cd41=category&cd11=634227590.1516015897&z=40233873 image
-http://www.google.com.au/ https://www.google.com.au/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41CNXGW6T4L.css,318TvQQkpyL.css,31tH-GJ-doL.css,11tkAOwE6OL.css,21xItms32EL.css,11ISqSj9gHL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,21QwDiO8ycL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11xlykx3aFL.css,01ATX4LEFqL.css,21CNSKZ67ML.css,51oAYplAOyL.css,21hLnMMJrfL.css,21lDMA2J74L.css,215tV0Xf4NL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21f0r7D13IL.css,61ypmw1UTGL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,016xTzXJLfL.css,31LBzl8T3vL.css,213-16KOboL.css,018mGORJ7tL.css,11fvu+DzMxL.css,11ho+83HCzL.css,01ticFfm7pL.css,01lh9w-GYYL.css,11Mso4bvY-L.css,01LCsoCesOL.css,01ifu3nZXpL.css,21Yyo4tu6ZL.css_.css?AUIClients/DetailPageMobileWebMetaAsset css
-http://www.google.com.au/ https://www.google.com.au/images/nav_logo242_hr.webp image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/81MDTSEXQgL.js?AUIClients/GoldboxUDPAssets script
-http://www.amazon.co.jp/ https://unagi-fe.amazon.com/1/events/com.amazon.csm.nexusclient.prod script
-http://www.google.com.au/ https://www.google.com.au/gen_204?s=webaft&atyp=csi&ei=P5FcWu3vHpSYjwO5j4noCA&rt=wsrt.2036,aft.187,prt.187 html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/n2a/gw/1079807_timesale_gw_mb_billboard_1242x450._SX1242_CB512386221_.png image
-http://www.google.com.au/ https://www.google.com.au/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/41OgRXocjFL._AC_SY240_.jpg image
-http://www.google.com.au/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/iu3?d=amazon.co.jp&slot=navFooter&a2=010150d58bff320dbdbc9926119b167f54cf3afd2787d88f0351e0467426ef46380d&old_oo=0&cb=1516016006021&dcc=t html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/415TzjIb8WL._AC_SY240_.jpg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/v3/pr?exlist=aone-fe_sx_kr_bsw_bk_ox_index_g-fe_aold_an_rb_br_im-fe_fbca_aolv_twca_y_adb&fv=1.0&ex-pl-fbca=jiVvt-PvSWWgv0gyALy5QQ&ex-pl-twca=2DTqtdEdSUq4vVx3A_pdQg&a=cm&ep=zzydW3miBeH7RFgauE5WgRHaXj1_7qRTqbCvbQ2IlQbtS-wLd3doYC2l1NkX4Iex html
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/418iluQfbyL._AC_SY240_.jpg image
-http://www.amazon.co.jp/ https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com other
-http://www.amazon.co.jp/ https://cm.g.doubleclick.net/pixel?google_nid=a9ap&google_cm&ex=doubleclick.net html
-http://www.google.com.au/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.amazon.co.jp/ https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1 other
-http://www.google.com.au/ https://www.google.com.au/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.amazon.co.jp/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__ html
-http://www.google.com.au/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.amazon.co.jp/ https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.google.com.au/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.com.au/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.amazon.co.jp/ https://usermatch.krxd.net/um/v2?partner=amzn other
-http://www.amazon.co.jp/ https://ib.adnxs.com/getuid?https://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com image
-http://www.google.com.au/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.amazon.co.jp/ https://x.bidswitch.net/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.google.com.au/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.amazon.co.jp/ https://aw.dw.impact-ad.jp/c/u/?oid=207d81ffda0cc019&rdr=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%7BAONEID%7D%26ex%3Daudienceone.com other
-http://www.google.com.au/ https://www.google.com.au/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.amazon.co.jp/ https://cm.g.doubleclick.net/pixel?google_nid=a9ap&google_cm=&ex=doubleclick.net&google_tc= html
-http://www.google.com.au/ https://www.google.com.au/images/nav_logo242.png image
-http://www.amazon.co.jp/ https://pixel.advertising.com/ups/56466/sync?redir=true&_origin=1&verify=true other
-http://www.google.com.au/ https://www.google.com.au/gen_204?atyp=csi&ei=P5FcWu3vHpSYjwO5j4noCA&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.617,dcl.379,iml.617,ol.2295,prt.187,xjs.1487,xjsee.1487,xjses.1188,xjsls.212,wsrt.2036,cst.626,dnst.0,rqst.757,rspt.407,sslt.327,rqstt.1553,unt.926,cstt.927,dit.2415&zx=1516015938138 html
-http://www.amazon.co.jp/ https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D image
-http://www.google.com.au/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.amazon.co.jp/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1 html
-http://www.google.com.au/ https://www.google.com.au/images/branding/product/1x/gsa_android_144dp.png image
-http://www.amazon.co.jp/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID other
-http://www.google.com.au/ https://adservice.google.com.au/adsid/google/ui html
-http://www.amazon.co.jp/ https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.xhamster.com/ http://www.xhamster.com/ html
-http://www.amazon.co.jp/ https://aax-fe.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEOIMAWG-P2IjnDWOF4qvBws&google_cver=1 image
-http://www.xhamster.com/ https://xhamster.com/ html
-http://www.amazon.co.jp/ https://aw.dw.impact-ad.jp/c/ur/?oid=207d81ffda0cc019&rdr=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3D%7BAONEID%7D%26ex%3Daudienceone.com other
-http://www.xhamster.com/ https://m.xhamster.com/ html
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/js/mobile/bundle-index-video.min.js script
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id16/js/mobile/pop.min.js script
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?id=58fdbcbdd38ae610eb9748d132e03bf6c80cebbc&ex=aoldisplay.com image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id3/js/mobile/xpops.js script
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/css/mobile_bundles/pageIndex.css css
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=openx.com&id=0637a1d9-3575-c696-02c0-6d2d238b8952 image
-http://www.amazon.co.jp/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://s.amazon-adsystem.com/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=0a8b4076-f9e8-11e7-8b63-1976204a0001 other
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/js/mobile/common.min.js script
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=index&id=Ew6moYH4q7ZwUgsePSRuNTc6cOU4ZgAC image
-http://www.amazon.co.jp/ https://stags.bluekai.com/site/36841?dt=0&r=152187039&sig=2032588566&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmiRglWl1u3dep5hJEi0rvuNa028whzGcC3z3bh3gaqjG33LRr3ADZXAl5XSvQ7AsZVVQWDuLGoEzNmp9xoOQeP0hFr other
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=bidswitch.com&id=c79474929cf414a07b3cac1751daa21a image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com//images/mobile/svg/menu.svg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?id=21a12e84-e3fc-40a0-88e1-07e613cfb19e&ex=audienceone.com image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=spotx.com&id=0a8b960d-f9e8-11e7-8b63-1976204a0001 image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com//images/mobile/svg/searchNew.svg image
-http://www.amazon.co.jp/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc html
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/images/logo/logo_mobile2.svg image
-http://www.amazon.co.jp/ https://token.rubiconproject.com/token?pid=2179&pt=n other
-http://www.amazon.co.jp/ https://tags.bluekai.com/site/2981?id=&google_gid=CAESEEYZxBzEHpcQdQFsW12Dikw&google_cver=1 image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/images/mobile/transparent.gif image
-http://www.amazon.co.jp/ https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/bg.png image
-http://www.amazon.co.jp/ https://www.facebook.com/fr/r.php?p=558293300959460&e=jiVvt-PvSWWgv0gyALy5QQ&r=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dfbca%26id%3DjiVvt-PvSWWgv0gyALy5QQ&s=1516016015&h=L2JRNkU2aWtsTk1pTXAxV8mrqYBSPvPHlh4eDaDMJMgdS7Vk html
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/videos.svg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/categories.svg image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/subscribe_save/gw/mobile/1049516_gw_mobilebillboard_02_1242x450._SX1242_CB507792628_.jpg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/top-rated.svg image
-http://www.amazon.co.jp/ https://sync.im-apps.net/imid/redirect?cid=1000285&tid=aapid other
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/liveCam.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/star.svg image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/other/1079133_clealance_store_gw_mobilebillboard_1242x450._SX1242_CB494454373_.png image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/photos.svg image
-http://www.amazon.co.jp/ https://geo-um.btrll.com/v1/map_pixel/partner/64.png image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/vr.svg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=fbca&id=jiVvt-PvSWWgv0gyALy5QQ image
-http://www.amazon.co.jp/ https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=2DTqtdEdSUq4vVx3A_pdQg&twitter_redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dtwca%26id%3D2DTqtdEdSUq4vVx3A_pdQg%26 html
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/storiesNew.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/uploadVideoNew.svg image
-http://www.amazon.co.jp/ https://ads.yahoo.com/cms/v1?esig=1~b9bada6fffbf45c1ffda7783879fb5715486894a&nwid=10000922750&sigv=1 text
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/langsRetina.png image
-http://www.amazon.co.jp/ https://aax-fe.amazon-adsystem.com/s/ecm3?ex=intimatemerger.com&id=ea02HNu_S-2T7m7CMP47zA image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/arrowRightWhite.svg image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/I/31efvGROBqL._AC_SY600_.jpg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/beta-straight.svg image
-http://www.amazon.co.jp/ https://images-fe.ssl-images-amazon.com/images/G/09/2017/x-site/n2a/gw/1079807_n2a_gw_mb_billboard_1242x450._SX1242_CB512386221_.png image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/close2.svg image
-http://www.amazon.co.jp/ https://geo-um.btrll.com/v1/map_pixel/partner/64.png?set_aps=1&BR_APS=3WlyRkz8OB4gBkw1Mng& image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/microphone.svg image
-http://www.amazon.co.jp/ https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D text
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/hd.svg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?p_user_id=2DTqtdEdSUq4vVx3A_pdQg&ex=twca&id=2DTqtdEdSUq4vVx3A_pdQg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/gear.svg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=rightmedia.com&xid=E0 image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/607/320/5_8848607.jpg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?id=3WlyRkz8OB4gBkw1Mng&ex=brightroll.com&n=1516016019& image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/354/320/3_8851354.jpg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=aolvideo.com&id=0bb05566398441d30dc2bc17592ef59efabb16b0 image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/178/320/1_8851178.jpg image
-http://www.amazon.co.jp/ https://dpm.demdex.net/ibs:dpid=139200&dpuuid=6y9d4FqhRnKc06bpaJPO6w&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D other
-http://www.amazon.co.jp/ https://fls-fe.amazon.co.jp/1/batch/1/OE/ other
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/004/320/8_8849004.jpg image
-http://www.amazon.co.jp/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=6y9d4FqhRnKc06bpaJPO6w&redir=https%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/519/320/3_8848519.jpg image
-http://www.amazon.co.jp/ https://s.amazon-adsystem.com/ecm3?ex=adobe.com&id=11614747856848349493313219342568464492 image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/334/320/10_8853334.jpg image
-http://www.xhamster.com/ https://cdn.trafficstars.com/sdk/v1/bi2.js script
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/footer_bg.png image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/straight.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/trans.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/gays.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/tpl2/vr-badge.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/arrowRightLittle.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/left.svg image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/id109/images/mobile/svg/right.svg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/157/320/3_8850157.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/323/320/4_8843323.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/449/320/10_8848449.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/578/320/6_8833578.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/370/320/3_8422370.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/336/320/1515759480_8844336.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/098/320/9_8826098.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/196/320/1515758281_8844196.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/940/320/1515767822_8844940.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/526/320/7_8843526.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/416/320/1_8848416.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/337/320/1_8848337.jpg image
-http://www.xhamster.com/ https://static.hotjar.com/c/hotjar-29643.js?sv=6 script
-http://www.xhamster.com/ https://www.google-analytics.com/analytics.js script
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/305/320/1_8848305.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/242/320/5_8851242.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/744/320/1515881941_8852744.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/729/320/1_8850729.jpg image
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/740/320/1_8269740.jpg image
-http://www.xhamster.com/ https://collector.xhamster.com/?log=stats&ref=&_=1516016007875 other
-http://www.xhamster.com/ https://thumb-v-ec.xhcdn.com/t/586/320/4_8557586.jpg image
-http://www.xhamster.com/ https://tsyndicate.com/iframes2/088e288d72b1404ea62653e5192fec73.html?keywords=Watch,and,download,all,Porn,Videos,xHamster,for,Free,including,Browse,sex,photos,date,girls,fuck,have,fun,Live,Sex,Chat,only,xHamster,Free,Porn,Videos,Sex,Tube,Movies,xHamster&param1=0&param2={last}&adb=0&w=1080&h=1536 html
-http://www.xhamster.com/ https://tsyndicate.com/iframes2/beae3ac3790c4b7893f0189651c238ea.html?keywords=Watch,and,download,all,Porn,Videos,xHamster,for,Free,including,Browse,sex,photos,date,girls,fuck,have,fun,Live,Sex,Chat,only,xHamster,Free,Porn,Videos,Sex,Tube,Movies,xHamster&param1=0&param2=0&adb=0&w=1080&h=1536 html
-http://www.xhamster.com/ https://script.hotjar.com/modules-14db5ab5e0c940b032d5b5500ffa4f5d.js script
-http://www.xhamster.com/ https://vars.hotjar.com/rcj-99d43ead6bdf30da8ed5ffcb4f17100c.html html
-http://www.xhamster.com/ https://cdn.tsyndicate.com/sdk/v1/b.b.js script
-http://www.xhamster.com/ https://cdn.tsyndicate.com/images/7/d/46a4ece0bd11e79664002590c57f96.gif image
-http://www.xhamster.com/ https://ads2.contentabc.com/ads?spot_id=1591069/ html
-http://www.xhamster.com/ https://us-pxl.trafficstars.com/api/v1/p/p.js?r=1&s=65cd9d96268f56eab735c92fd1f318db77011a2848d4591c0a0b8c206723f0ee1516016011&p=e0SEGUNHhI4YLAbWGXNQRA0xOMTYmEEGRosZY8rEaEGjDA0ZLXDIsNjCjI0wI2HUMJPDog0RCsOQMXNQxg2Fc-AY1IGDhkIxbtwcpJFDxowbOEXUkcPmYI0cOHDYUFpHhkM0dOjA0fHiBR05BNe4IBOGTpk5Y8K4cZHGjZk3L17igBHDaIsbYWTU6DgGxowWYsyMERP4BtUYN2LgUIxjzA-1beCESXPGTY-kSWVwqQMDhgwbY-SUMZvGTpkeRY8m5ewZ9Jw0Z3vMgNH6sw06c-iEOdNjJpkcN8jEKNOirpkbHXPAKO4zBt8xFcXEMFN9JYyaCsdIPpj5hgyZZOwcjDFjr0w4cA7SVginjpiDNhTSaUO-RgwbdfPHSCgCjpyGdIDBBc88Syqn_w4asEDP-JOBBhpuqIFBCn8SYbTxBCSwQP5qqEEhOexQD6EPRShjDDjq0xCGA5eqIw2H7iMDKhnEIKOjiDiiYaIxAgPuIhpQwiGxMm6iIYwaYhJhDrQcskGMG2Yw4zm-WmKxIzLEoKEFl7JsIQwayJBBI-FwqAGHMJQcI0ARqphCSTbYLMIJJdMYUYQYinJBhgEpcqE8JetIUwcRmnhDjzTYYCOMF2ogEAQUmHCrDjx2ACEIN8iQ4400yADBBgL_tNRQOt4A4QhIaUgBBCFeZIOMF5qAQokH_5whhxZsUPXS9Ngo44oyxFgitkaRcmEGGyBdAgkqmmCCBRDYSGONMk49cY03Vh0CjU3bKKNRHEKlTYYcXBgSBEPFSLTaKcIwIww50ij2hmOThYKKKah4YbG6-PtzuRhuUpKMMjLsT9M3bFLojTmImmG-Mxz6LbjhijsuuaKYE4mG51qILkvqrJswOxHucCgGGOhSEo2Ta0BWyTlCdGjT3UqVQ8nRaiI0q63m6OqFNlzAA40w2tCtDDlcGOONNl4YeChCgx666KOTXrq-9mJwCAYl4biK0D0W1a0PNc06aIsPZYihC4XIYNNNEfpQICA=&d=414&priv=false&w=t script
-http://www.xhamster.com/ https://hw-cdn.contentabc.com/delivery/mobile_video_v2/adtool_mobile_video_player.min.css css
-http://www.xhamster.com/ https://hw-cdn.contentabc.com/ads/bz_300x250_714598/uploadMLogo.png image
-http://www.xhamster.com/ https://hw-cdn.contentabc.com/delivery/mobile_video_v2/adtool_mobile_video_player.min.js script
-http://www.whatsapp.com/ https://www.whatsapp.com/ html
-http://www.xhamster.com/ https://us-pxl.trafficstars.com/api/v1/p/p.js?r=1&s=d5ef9478ce17840a2b901ee640793e1f2f9c150093a998556c1ec9e7635de4be1516016011&p=e0SEGUNHhI4YLAbWGXNw4IwbZWSImSGmRRkzY8K0oFHjBo0WOWyQwdHihpgbZmjcsCEjTIwwNEQoDEPGzMGEIubAMagDRw2FYty4wSmSBgyFdWI4REOHDpw5Ol68qDlHhosxb9zQKbM1jJgxWN-0oUpmzo-db-h8SUOmR4waOWLAsJHjxUwRY9rAOUhDhgygA8nYOVjDBk04fHXMQCoCTh0xBw-LoNMGZ40YNmBk3pwTjpyGOmC4gFE65045B0eXZp0Z7owarGWznqFQThnCokm3DizHjmK4CsuMgWNZd846ddI4JKNxzA0cZmq0wAFxBkczZGC0EFNGjMUYMmjkyCH-xo0xZXDgnVNmjkMYZMTIMCOGTJkWMcjUMMMxMxnqzIghhxbCmEEG74zCIYbM8BojNBGqmAIvNiAswgm80lBMhBjGc0GG0WyYwYUYZsCrjjAcauINPdJgg40wXqiBNBBQYCINN-rAYwcQgnCDDDneaAsEG0gjkccV6XgDhCNqpCEFEIRQjg0yXmgCCiXEI3EGAm14ssfE2CjjCu-WSIMOGSFyYQYbalwCCSqaYIIFENhIY40ymBxujTegHAKNINsoQ0YcjGRMhhxcWBCEFcVwMc8pwjAjDDnSSPOGNduEgoopqHghBhw6i4HEHDaT4Qa87sstJyDfOEgGhd54TwcaaqPsDIc6isG7lwisNQwbOAqjBhmogwkkHMTAzAbvapihjBhQVegOh-YKFS80qnXWBvZ8cyhIOsJQMjXbMGLKKaikeqENF_BAI4w25uBKDrHISpUoHURg11145S2D3qwsUwiOpfKFAS84ZIDPQXEP2gIoGWLoQqHmHJJQhD4UCAg=&d=3661&priv=false&w=t script
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/js/v4/jquery-1.12.2.min.js script
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/images/favicon/favicon-32x32.png?v=1 image
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/images/favicon/favicon-16x16.png?v=1 image
-http://www.xhamster.com/ https://hw-cdn.contentabc.com/ads/bz_300x250_714598/uploadMVideo.mpg video
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/css/v4/style.build.css?v=bfe2fe6 css
-http://www.xhamster.com/ https://static-ec-2.xhcdn.com/images/favicon/favicon.ico?v=1 image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/icon-wp.svg image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/icon-desktop.svg image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/icon-iphone.svg image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/badge-google-play-en.svg image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/icon-android.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/security_localized.html?v=bfe2fe6&l=en html
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/whatsapp-logo.svg?v=bfe2fe6 image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/home-phone-mobile.png?v=bfe2fe6 image
-http://www.whatsapp.com/ https://www-cdn.whatsapp.net/img/v4/feature-3.png?v=bfe2fe6 image
-http://www.whatsapp.com/ https://www.google-analytics.com/analytics.js script
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/edge_includes/edge.6.0.0.min.js script
-http://www.whatsapp.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=951171283&t=pageview&_s=1&dl=https%3A%2F%2Fwww.whatsapp.com%2F&ul=en-us&de=UTF-8&dt=WhatsApp&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAAAB~&jid=477254841&gjid=973581928&cid=634774999.1516015911&tid=UA-8707243-1&_gid=1554786104.1516015911&_r=1&z=2125919216 image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/security_edge.js script
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/stylesheet.css css
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted11.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted10.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted3.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted8.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted9.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted7.svg image
-http://www.whatsapp.com/ https://www.whatsapp.com/img/v4/animation/security/images/Pasted5.svg image
-http://www.whatsapp.com/ https://whatsapp.com/favicon.png image
-http://www.google.pl/ http://www.google.pl/ html
-http://www.google.pl/ https://www.google.pl/?gws_rd=ssl html
-http://www.blogspot.com/ http://www.blogspot.com/ html
-http://www.google.pl/ https://www.google.pl/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.blogspot.com/ https://www.blogger.com/ html
-http://www.google.pl/ https://www.google.pl/images/nav_logo242_hr.webp image
-http://www.blogspot.com/ https://accounts.google.com/ServiceLogin?service=blogger&hl=en&passive=true&go=true&continue=https://www.blogger.com?rinli%3D1 html
-http://www.google.pl/ https://www.google.pl/gen_204?s=webaft&atyp=csi&ei=Q5FcWujHFZTAjAOGlI2wAQ&rt=wsrt.2033,aft.235,prt.235 html
-http://www.blogspot.com/ https://www.blogger.com/?rinli=1 html
-http://www.google.pl/ https://www.google.pl/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.blogspot.com/ https://www.blogger.com/about/?r=1-null_user html
-http://www.blogspot.com/ https://www.blogger.com/about/css/styles.min.css?v=1476060772 css
-http://www.google.pl/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.blogspot.com/ https://www.blogger.com/about/js/main.min.js?v=1476060773 script
-http://www.google.pl/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.blogspot.com/ https://fonts.googleapis.com/css?family=Roboto+Slab:400,700,300|Roboto:400,500,700,300,900&subset=latin,greek,greek-ext,vietnamese,cyrillic-ext,latin-ext,cyrillic css
-http://www.google.pl/ https://www.google.pl/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.blogspot.com/ https://ajax.googleapis.com/ajax/libs/webfont/1.5.10/webfont.js script
-http://www.google.pl/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.blogspot.com/ https://www.blogger.com/about/img/sections/millions/millions-mobile-markers_2x.png image
-http://www.blogspot.com/ https://www.blogger.com/about/img/ui/icon-arrow-down.png image
-http://www.google.pl/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.pl/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.blogspot.com/ https://fonts.gstatic.com/s/roboto/v18/RxZJdnzeo3R5zSexge8UUZBw1xU1rKptJj_0jans920.woff2 font
-http://www.google.pl/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.blogspot.com/ https://fonts.gstatic.com/s/roboto/v18/Hgo13k-tfSpn0qi1SFdUfZBw1xU1rKptJj_0jans920.woff2 font
-http://www.blogspot.com/ https://lh3.googleusercontent.com/26eaRZ7AqYQFf7Zt3gBgwxiigJEz-1K4mcrIOb0bA4YjFbDnLQvMVt5VSQ7-=w384 image
-http://www.google.pl/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/ik3pxLhNpdCMLyi3o_mpkMaGASASLMjSQJ_v7TutUuIiD-qtLkXEiRYlPzGhoQ=w256 image
-http://www.google.pl/ https://www.google.pl/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.blogspot.com/ https://lh3.googleusercontent.com/gz9btiN62BwKFzOWZO-DmTZDlraq172rVXTZ_TQwRDy8hT-VrzOVVfMp1nzupJY=w384 image
-http://www.google.pl/ https://www.google.pl/images/nav_logo242.png image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/jQrLB0S1fjOjqnJ145d0OBbOHHIR9nce1lnjzGL2YCvDK8ocxIZOM6wR3GNJLw=w256 image
-http://www.google.pl/ https://www.google.pl/gen_204?atyp=csi&ei=Q5FcWujHFZTAjAOGlI2wAQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.618,dcl.418,iml.618,ol.2300,prt.235,xjs.1477,xjsee.1477,xjses.1191,xjsls.269,wsrt.2033,cst.626,dnst.0,rqst.762,rspt.412,sslt.327,rqstt.1550,unt.923,cstt.923,dit.2451&zx=1516015941996 html
-http://www.blogspot.com/ https://lh3.googleusercontent.com/Y1IHnQ0sM4cWJzRXAPAUA81jkwPmNDEq4nqhjUZN_oYhsyO-_UsuWx20Oy16acE=w192 image
-http://www.google.pl/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.blogspot.com/ https://lh3.googleusercontent.com/WrBvOY07H7-s7HBXAjxwftmhbRC9E6U0jFl-84rniR1UIJVDY4V9El19hkEWtA=w512 image
-http://www.google.pl/ https://www.google.pl/images/branding/product/1x/gsa_android_144dp.png image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/6GftHp2q8zrjTzGG0Xz0zQZYGRh0YuUPyxNwVQLiaLjZboXhWs_TOfTzvxI9DLc=w256 image
-http://www.google.pl/ https://adservice.google.pl/adsid/google/ui html
-http://www.blogspot.com/ https://lh3.googleusercontent.com/9LvBDozBm5r8Ys3F3cYH2eFwwQJMo-uDsL-c3dqtmAYfTmF7hiHCNcRHmMZw=w256 image
-http://www.blogspot.com/ https://www.google-analytics.com/analytics.js script
-http://www.blogspot.com/ https://lh3.googleusercontent.com/Br6226SyPnl0JKRaetNVksBPrakJrD3MeF_ltH6fydJ9SOpNrja5yLU2m3dAGw=w384 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/qxx_R2lwF9JfNbtMoMyK2x73XezkYruSM6CVrLVpLqZ8CCxiWOdbIn8aR9kjsw=w384 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/V02lmzeK6QFkTNAFssnGgriS6KjgNLl2evPSXHtLdEHiyihTPaVVdpzERZKaiA=w256 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/AwLUKnfIxjqCkWZw7vI3a2g7tqRUZ4Ne-b3KBTX8MikfBILxzL8nZrckfO_G=w512 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/qfL8w8HhVvq0PI9rsXZbjBc9gDZtNbE8km3C7-2jMje6Fq0WGWV7x2SNiqpK=w768 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/Sp4ZzNq2eI5tylQz9NrBND3-VDG7XcKBr0PXMtqZFjvNywZSXRsOKmeCTxQ8lH4=w256 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/lTnzFEVNkSc8tN6TzpIOYtfs0_u9FK3d3xiJUmOm9Ca1nsHS9sKLnzAocQ5kOg=w192 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/MPmddYcgxwTm3Iy-Q_vWIyBEbdR_ugBlhQjpIg2eQPC4c1LFn-j7A3-nFawqrA=w256 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/q9EDVvchfjgVyxzRhh2AGq_JF9UaRP5NiP_-oMSwaiKfkZfmDSlk6f5kI5jo_g=w768 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/bUmhI8lzLM1TfnsTsBw6SDwD_SdJq6--zDXelMF90N-4WqWr_dCmIfJfmaJS=w256 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/bkZfwpDRL1PEZ8W8gZFb4C2j-m2b6OafU7pe4KIfxhkyFsZXNAFRTAQ-zPyWFA=w512 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/5R8IjxFf2Aatn2ivlRCWDWkRI04nNgpap0dUyMzVAeiWlvsDAIxHZIu-t3NpHg4=w192 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/_i6FMmMDzrDTVkyCIJwbkZJulXtfrddhjL7-NZNeKg05kI_TgkL8K_zfBGd9Kmo=w192 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/XLIzvEbVuqXvYxUK0lfilYg612zc4qFnhLWASre2oS1HYZkKrPuMG54By3CJ1A=w256 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/W0R6Lf3Id13mEqJu9di9w-or4BARQoZLIEpesrMvKGwc6kBw2sfygoy2vWzkcA=w512 image
-http://www.google.com.ar/ http://www.google.com.ar/ html
-http://www.google.com.ar/ https://www.google.com.ar/?gws_rd=ssl html
-http://www.google.com.ar/ https://www.google.com.ar/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.google.com.ar/ https://www.google.com.ar/images/nav_logo242_hr.webp image
-http://www.google.com.ar/ https://www.google.com.ar/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.blogspot.com/ https://lh3.googleusercontent.com/pfOxQQNkn-S8TN9jPb-jAEtOF-caZWj-yZQDzp4GPFx2N8pGCdHv_7kajYOr8Q=w768 image
-http://www.google.com.ar/ https://www.google.com.ar/gen_204?s=webaft&atyp=csi&ei=K5FcWrXDN42WjQP8gJv4Bw&rt=wsrt.2047,aft.187,prt.187 html
-http://www.blogspot.com/ https://lh3.googleusercontent.com/pu8DIkXffB3UIO_V_EUiraLkZ38Ha4IO9itLklE6OVRf81lFnSCt9ynF9e-4tg=w768 image
-http://www.google.com.ar/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.blogspot.com/ https://lh3.googleusercontent.com/tg02yAOuyOZJZcU5NDvZa1_J_1Ngk9P-CsLd8NWkLaMHVZXY-fPAKW6s1bkp8MI=w768 image
-http://www.google.com.ar/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/EVaQo9gv2ko6xNWFWPFO8DKv-3RqK8J4g0yDcI0P3-hmf-uLSsYOMvRGqicF=w384 image
-http://www.google.com.ar/ https://www.google.com.ar/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.blogspot.com/ https://lh3.googleusercontent.com/lpnI6G9VekY80fLOIqhM09I-jDZJOPg32OHvPq3aLnmSAoKf_5Dt6chjBPvGug=w768 image
-http://www.google.com.ar/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.google.com.ar/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/F13JvZjM5cCjOttGTn7eJiqCW21EohcHoqhhoKzwvuJAY8QN0t9uOlgRE_PCug=w512 image
-http://www.google.com.ar/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/9bifoOJ8M_y35VWf_46xDZ8duvOfNHeHcQbNhss6sx7_-cUKG7zWSaYH4lfS=d image
-http://www.google.com.ar/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.com.ar/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/vJpXUm7SIjPhi4C1k_XRNxbJgUXQd2xiOQvOA_F1zyE8zD5HodQT6OEkUos-=w128 image
-http://www.google.com.ar/ https://www.google.com.ar/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.google.com.ar/ https://www.google.com.ar/images/nav_logo242.png image
-http://www.google.com.ar/ https://www.google.com.ar/gen_204?atyp=csi&ei=K5FcWrXDN42WjQP8gJv4Bw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.612,dcl.348,iml.612,ol.2227,prt.182,xjs.1442,xjsee.1442,xjses.1121,xjsls.175,wsrt.2047,cst.626,dnst.0,rqst.758,rspt.403,sslt.326,rqstt.1568,unt.940,cstt.940,dit.2396&zx=1516015918474 html
-http://www.blogspot.com/ https://lh3.googleusercontent.com/h0_380xSF1bvqkrxX4gIfgUAYvhzVC2a9BcenHEeq786W-kSCb-_sVpvI1Zc=w512 image
-http://www.google.com.ar/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.blogspot.com/ https://lh3.googleusercontent.com/9cbUVdUGgINO5xuTvk_SxU2eiZPu1PtRFMi3JhSMvYO7AOQnPBVpALNJnb8P=w1024 image
-http://www.google.com.ar/ https://www.google.com.ar/images/branding/product/1x/gsa_android_144dp.png image
-http://www.google.com.ar/ https://adservice.google.com.ar/adsid/google/ui html
-http://www.blogspot.com/ https://lh3.googleusercontent.com/5vjrG5sh3rxYqrSoYF-KYIVVRb3aq7Hz_WNbYy480yNV-IdDDuN4-moWedYS-s0=w384 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/Nygft4j6luNxOMjZm4cONKyAqpva8Gn1YfDEQGB0Qhx3sN8cT_vPGm4tF1bjuvQ=w384 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/Ez2JNPaTvHBmThI-ACqiyu5UesCLVrPSCUYsV5e5hSsz1xr3W5rQZy4jaI-mAMQ=w512 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/hJBD51rYjUbo1v-5HRbsZYl8Op971aX1JwwB4GFFeqdxhriI3JSW1VnB50JtqA=w128 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/g15zvfM9ccRqjI8oFWNH4tdgvMF-BQEEpXwSEDRJnyvaJTTx7bI2XJ1bVWh9Vz8=w512 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/LvXV_ldpiygyiAI5R-Nqw8_zdNvmvLEH9jGIie7dycK-TtJO_SdUgmgxAdGtdjM=w128 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/G8OwqoI4B9v3T6npbcEpcDeAoSN3fpkFcKPkb5e0hzdm5HewaG3PaSGmTUyblnQ=w48 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/ytR9Qe3qeOc6qWzwP8N50Jew_RkP68A3gaH77GwUE4EA0fHhg5E6u0mihK6Tntc=w512 image
-http://www.blogspot.com/ https://lh3.googleusercontent.com/GF-5w3cTsh0HnBwp1DLBaMCAwrPCwojFUPyOkvvk47RyFqVsxT6qKkdWnbz4=w512 image
-http://www.blogspot.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&aip=1&a=2050133649&t=pageview&_s=1&dl=https%3A%2F%2Fwww.blogger.com%2Fabout%2F%3Fr%3D1-null_user&ul=en-us&de=UTF-8&dt=Blogger.com%20-%20Create%20a%20unique%20and%20beautiful%20blog.%20It%E2%80%99s%20easy%20and%20free.&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAAAB~&jid=171214063&gjid=1227249530&cid=837639291.1516015994&tid=UA-18003-38&_gid=2031970172.1516015994&_r=1&z=713035488 image
-http://www.blogspot.com/ https://www.blogger.com/about/favicon/favicon-32x32.png image
-http://www.blogspot.com/ https://www.blogger.com/about/favicon/favicon-16x16.png image
-http://www.blogspot.com/ https://www.blogger.com/about/favicon/favicon-96x96.png image
-http://www.blogspot.com/ https://www.blogger.com/about/favicon/android-chrome-192x192.png image
-http://www.blogspot.com/ https://www.blogger.com/about/favicon/favicon.ico image
-http://www.popads.net/ http://www.popads.net/ html
-http://www.popads.net/ https://www.popads.net/app/webroot/ html
-http://www.popads.net/ https://www.popads.net/js/did_challenge.js script
-http://www.popads.net/ https://static.popads.net/css/front_set.css?1391017485 css
-http://www.popads.net/ https://static.popads.net/js/jquery.js?1376733482 script
-http://www.popads.net/ https://static.popads.net/js/various.js?1454527955 script
-http://www.popads.net/ https://static.popads.net/img/logo.png?1372079638 image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/nav/left.png?1372079637 image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/nav/right.png?1372079637 image
-http://www.popads.net/ https://static.popads.net/img/bg/input/members/left.png?1372079638 image
-http://www.popads.net/ https://static.popads.net/js/trustguard.js?1443008335 script
-http://www.popads.net/ https://static.popads.net/img/bg/input/members/right.png?1372079638 image
-http://www.popads.net/ https://static.popads.net/img/btns/sign_in.png image
-http://www.popads.net/ https://static.popads.net/img/btns/sign_up.png?1372079637 image
-http://www.popads.net/ https://static.popads.net/img/icons/rss.png?1372079637 image
-http://www.popads.net/ https://static.popads.net/img/bg/container.gif image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/main/bg.png image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/main/bottom.png image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/main/home.png image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/members/top.png image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/members/bottom.png image
-http://www.popads.net/ https://static.popads.net/img/bg/rounded/members/bg.png image
-http://www.popads.net/ https://static.popads.net/img/bg/input/members/bg.png image
-http://www.popads.net/ https://www.popads.net/login_box.html html
-http://www.popads.net/ https://static.popads.net/img/bg/dotted.png image
-http://www.popads.net/ https://static.popads.net/img/icons/core.png image
-http://www.popads.net/ https://static.popads.net/img/icons/scalable.png image
-http://www.popads.net/ https://static.popads.net/img/icons/on_time.png image
-http://www.popads.net/ https://static.popads.net/img/icons/financial.png image
-http://www.popads.net/ https://static.popads.net/img/icons/blog.png image
-http://www.popads.net/ https://ssl.google-analytics.com/ga.js script
-http://www.popads.net/ https://popads-trustguard.cdn77-ssl.net/privacy-5270-mini.gif image
-http://www.popads.net/ https://popads-trustguard.cdn77-ssl.net/security-5270-mini.gif image
-http://www.popads.net/ https://popads-trustguard.cdn77-ssl.net/business-5270-mini.gif image
-http://www.popads.net/ https://popads-trustguard.cdn77-ssl.net/certified-5270-mini.gif image
-http://www.popads.net/ https://ssl.google-analytics.com/r/__utm.gif?utmwv=5.7.1&utms=1&utmn=1103373638&utmhn=www.popads.net&utmcs=UTF-8&utmsr=360x512&utmvp=980x1393&utmsc=24-bit&utmul=en-us&utmje=0&utmfl=-&utmdt=PopAds%20-%20Home&utmhid=1847460226&utmr=-&utmp=%2Fapp%2Fwebroot%2F&utmht=1516015954736&utmac=UA-19696955-1&utmcc=__utma%3D89311364.1461024986.1516015955.1516015955.1516015955.1%3B%2B__utmz%3D89311364.1516015955.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmjid=478194203&utmredir=1&utmu=qBAAAAAAAAAAAAAAAAAAAAAE~ image
-http://www.popads.net/ https://www.popads.net/favicon.ico image
-http://www.coccoc.com/ http://www.coccoc.com/ html
-http://www.coccoc.com/ http://coccoc.com/ html
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/min/browser-min.css?1515753016 css
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/gb_flag_36.png image
-http://www.coccoc.com/ http://www.youtube.com/embed/wqYg3dtV2eU?autoplay=0 other
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/min/browser-min.js?1515752983 script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/js/jquery.cycle2.min.js script
-http://www.coccoc.com/ http://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.facebook.com%2FCocCocTrinhDuyet&width=1020&height=60&colorscheme=light&layout=standard&action=like&show_faces=true&send=false other
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/fonts/Regular/OpenSans-Regular.woff2 font
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/min/browser.png?511d118fb1a50392970e3b6595634d9f image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/bg.jpg image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/f4.png image
-http://www.coccoc.com/ https://www.google.com/recaptcha/api.js?hl=vi script
-http://www.coccoc.com/ http://www.google-analytics.com/analytics.js script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/f2.png image
-http://www.coccoc.com/ http://topbar.coccoc.com/topbar-widget-vi.min.js script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/f3.png image
-http://www.coccoc.com/ https://www.googletagmanager.com/gtm.js?id=GTM-KKML7SR script
-http://www.coccoc.com/ https://www.youtube.com/embed/wqYg3dtV2eU?autoplay=0 html
-http://www.coccoc.com/ https://www.facebook.com/plugins/like.php?href=https%3A%2F%2Fwww.facebook.com%2FCocCocTrinhDuyet&width=1020&height=60&colorscheme=light&layout=standard&action=like&show_faces=true&send=false html
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/f5.png image
-http://www.coccoc.com/ https://www.facebook.com/images/spacer.gif?4018266035952909 image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/f1.png image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/b5.png image
-http://www.coccoc.com/ https://www.gstatic.com/recaptcha/api2/v1514934548259/recaptcha__vi.js script
-http://www.coccoc.com/ https://www.youtube.com/yts/cssbin/www-player-sprite-mode-vflPv9SdE.css css
-http://www.coccoc.com/ http://bat.bing.com/bat.js script
-http://www.coccoc.com/ https://www.youtube.com/yts/jsbin/www-embed-player-vflZ4LyNi/www-embed-player.js script
-http://www.coccoc.com/ https://www.youtube.com/yts/jsbin/player-vflLCGcm0/en_US/base.js script
-http://www.coccoc.com/ http://d-cache.microadinc.com/js/blade_track_gl.js script
-http://www.coccoc.com/ https://www.facebook.com/rsrc.php/v3ijLc4/yX/l/en_US/wCJ2hAdlhFn.js script
-http://www.coccoc.com/ https://www.facebook.com/rsrc.php/v3/yn/r/lH1ibRl5GKq.png image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/google_play_button.png image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/coccoc-feature.png image
-http://www.coccoc.com/ http://www.youtube.com/embed/wqYg3dtV2eU?autoplay=0&enablejsapi=1&origin=http%3A%2F%2Fcoccoc.com other
-http://www.coccoc.com/ https://www.youtube.com/iframe_api script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/b2.png image
-http://www.coccoc.com/ https://www.youtube.com/embed/wqYg3dtV2eU?autoplay=0&enablejsapi=1&origin=http%3A%2F%2Fcoccoc.com html
-http://www.coccoc.com/ http://bat.bing.com/action/0?ti=5102317&Ver=2&mid=2903fc04-8586-30d2-72b0-24a480248118&evt=pageLoad&sid=8f936fe8-1&lt=5586&pi=0&lg=en-US&sw=360&sh=512&sc=24&tl=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c,%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&p=http%3A%2F%2Fcoccoc.com%2F&r=&msclkid=N&rn=416632 other
-http://www.coccoc.com/ https://www.google-analytics.com/analytics.js script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/b4.png image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/b1.png image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/b3.png image
-http://www.coccoc.com/ http://www.googleadservices.com/pagead/conversion_async.js script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/vi/appstore_button.png image
-http://www.coccoc.com/ http://d-track.send.microadinc.com/bl_track_with_gcm.cgi?co_account_id=12827&group=&country_id=5&ver=2.1.0&referrer=&cbt=b3b4ead0c32be00160f99962dc script
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/img/overlay.png image
-http://www.coccoc.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=1867958681&t=pageview&_s=1&dl=http%3A%2F%2Fcoccoc.com%2F&ul=en-us&de=UTF-8&dt=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&sd=24-bit&sr=360x512&vp=980x1393&je=0&_u=IGBAgAAB~&jid=130462828&gjid=1258008024&cid=1994434474.1516016069&tid=UA-35860610-14&_gid=400275928.1516016069&z=1934904944 image
-http://www.coccoc.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1867958681&t=pageview&_s=1&dl=http%3A%2F%2Fcoccoc.com%2F&ul=en-us&de=UTF-8&dt=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&sd=24-bit&sr=360x512&vp=980x1393&je=0&_u=YGDAAAAB~&jid=452693953&gjid=1225884583&cid=1994434474.1516016069&tid=UA-35860610-27&_gid=400275928.1516016069&_r=1&gtm=G1cKKML7SR&z=1448139736 image
-http://www.coccoc.com/ https://connect.facebook.net/en_US/fbevents.js script
-http://www.coccoc.com/ https://www.google.com/recaptcha/api2/anchor?k=6LeTvAoUAAAAADj3Cr1Onbp4OIH1gzywMUJaefT0&co=aHR0cDovL2NvY2NvYy5jb206ODA.&hl=vi&v=v1514934548259&size=normal&cb=oyd1zpxjdufo html
-http://www.coccoc.com/ https://connect.facebook.net/signals/config/1477013712607702?v=2.8.6&r=stable script
-http://www.coccoc.com/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-35860610-14&cid=1994434474.1516016069&jid=130462828&gjid=1258008024&_gid=400275928.1516016069&_u=IGBAgAAB~&z=1176331525 html
-http://www.coccoc.com/ https://www.gstatic.com/recaptcha/api2/v1514934548259/styles__ltr.css css
-http://www.coccoc.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/824756923/?random=1516016069262&cv=8&fst=1516016069262&num=1&guid=ON&eid=376635471%2C659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=0&u_java=false&u_nplug=0&u_nmime=0&gtm=G1c&frm=0&url=http%3A%2F%2Fcoccoc.com%2F&tiba=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&async=1&rfmt=3&fmt=4 script
-http://www.coccoc.com/ https://bid.g.doubleclick.net/xbbe/pixel?d=KAE html
-http://www.coccoc.com/ https://www.youtube.com/yts/jsbin/player-vflLCGcm0/en_US/base.js script
-http://www.coccoc.com/ https://www.facebook.com/tr/?id=1477013712607702&ev=PageView&dl=http%3A%2F%2Fcoccoc.com%2F&rl=&if=false&ts=1516016071106&sw=360&sh=512&v=2.8.6&r=stable&a=tmgoogletagmanager&ec=0&o=28&ttf=8450.615000000002&tts=7313.050000000001&ttse=8449.260000000002&it=1516016069982 image
-http://www.coccoc.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-35860610-14&cid=1994434474.1516016069&jid=130462828&_v=j66&z=1176331525 image
-http://www.coccoc.com/ https://www.google.com/ads/user-lists/824756923/?random=1516016069262&cv=8&fst=1516014000000&num=1&guid=ON&eid=376635471%2C659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=0&u_java=false&u_nplug=0&u_nmime=0&frm=0&url=http%3A%2F%2Fcoccoc.com%2F&tiba=Tr%C3%ACnh%20duy%E1%BB%87t%20C%E1%BB%91c%20C%E1%BB%91c%2C%20l%C6%B0%E1%BB%9Bt%20web%20theo%20phong%20c%C3%A1ch%20Vi%E1%BB%87t&async=1&fmt=3&cdct=2&is_vtc=1&random=2558056159&rmt_tld=0&ipr=y image
-http://www.coccoc.com/ https://www.facebook.com/tr/ image
-http://www.coccoc.com/ https://www.gstatic.com/recaptcha/api2/logo_48.png image
-http://www.coccoc.com/ https://www.google.com/js/bg/nrON4czd_PmR5XtF7ajsDry8QZzUGdPzmMl9lS-uJTA.js script
-http://www.coccoc.com/ https://www.google.com/recaptcha/api2/webworker.js?hl=vi&v=v1514934548259 script
-http://www.coccoc.com/ https://s.ytimg.com/yts/jsbin/www-widgetapi-vflkvQ6Kw/www-widgetapi.js script
-http://www.coccoc.com/ https://www.google.com/recaptcha/api2/bframe?hl=vi&v=v1514934548259&k=6LeTvAoUAAAAADj3Cr1Onbp4OIH1gzywMUJaefT0 html
-http://www.coccoc.com/ https://googleads.g.doubleclick.net/pagead/id script
-http://www.coccoc.com/ https://www.google.com/js/bg/D5ndehjDpHsBntzgzOcX9rhxH6SG2GNwap9741D1MPg.js script
-http://www.coccoc.com/ https://s.ytimg.com/yts/imgbin/player-cougar-vflUodsN5.png image
-http://www.coccoc.com/ https://i.ytimg.com/vi/wqYg3dtV2eU/hqdefault.jpg image
-http://www.coccoc.com/ https://static.doubleclick.net/instream/ad_status.js script
-http://www.coccoc.com/ https://fonts.gstatic.com/s/roboto/v18/QHD8zigcbDB8aPfIoaupKOvvDin1pK8aKteLpeZ5c0A.ttf font
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/favicon_32.ico image
-http://www.coccoc.com/ http://coccoc.com/themes/default/browser/favicon.ico image
-http://www.amazon.de/ https://www.amazon.de/ html
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51jo%2BAP3U9L._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset css
-http://www.wikia.com/ http://www.wikia.com/ html
-http://www.wikia.com/ http://www.wikia.com/fandom html
-http://www.wikia.com/ https://fonts.googleapis.com/css?family=Rubik:300,300i,400,400i,500,500i,700,700i,900,900i&subset=cyrillic,hebrew,latin-ext css
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/41MjpWujmTL.css?AUIClients/GWMWebAssets css
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/common.css?v=44a83b36a3c1c4885806fc5a37794457d427659b css
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/21EugTBba7L.css?AUIClients/RetailSearchAutocompleteAssets css
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/news-and-stories.css?v=44a83b36a3c1c4885806fc5a37794457d427659b css
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51jSEENgQYL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,01d8Fs5iBdL.css,21ZwnZnTQ7L.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,318hCTMRXQL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21g9AOmZB5L.css,11X2-nh0PYL.css,01h2e2BEitL.css,11AYjYP-YzL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31k72ulyOYL.css,01kPgnKe7wL.css,01MGoIPodIL.css,01Alnvtt1zL.css,01BBs40O5ZL.css_.css?AUIClients/AmazonUI css
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/common.en.js?v=44a83b36a3c1c4885806fc5a37794457d427659b script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/gno/sprites/sky_webnav_V1_sprite_1x._CB515271921_.png image
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/news-and-stories.en.js?v=44a83b36a3c1c4885806fc5a37794457d427659b script
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DFW5S02T97H4K4YK5CGQM%26pty%3DYourOrders%26spty%3DAPPrefetchIframe%26pti%3D:1000 image
-http://www.wikia.com/ https://fonts.gstatic.com/s/rubik/v7/IUSlgBbgyuDQpy87mBOAc3YhjbSpvc47ee6xR_80Hnw.woff2 font
-http://www.wikia.com/ https://fonts.gstatic.com/s/rubik/v7/0hS39AKxpJlEXQF3mVPgrnYhjbSpvc47ee6xR_80Hnw.woff2 font
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61-dJ29Zw5L.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,51nK0kUyg2L.js,11Mdh5CVmhL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61IUvg6RIjL.js,31y9nF9Z1BL.js,11SW3HEKjtL.js,01qkmZhGmAL.js,01eORIy6e6L.js_.js?AUIClients/AmazonUI script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C414ftrYGv0L.js,11P4Lu1aIqL.js_.js?AUIClients/GWMWebAssets script
-http://www.wikia.com/ https://fonts.gstatic.com/s/rubik/v7/p_PvaTv0YzIEJlEVv30xK6CWcynf_cDxXwCLxiixG1c.woff2 font
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets script
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/4893cd3f-15be-43da-a1c9-58f0d5672dcc/scale-to-width-down/1600 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/41XJlIDdUUL._RC%7C01vojWHr8gL.js,31qKd4DgPkL.js_.js?AUIClients/NavMobileMetaAsset script
-http://www.paypal.com/ http://s2.symcb.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBS56bKHAoUD%2BOyl%2B0LhPg9JxyQm4gQUf9Nlp8Ld7LvwMAnzQzn6Aq8zMTMCEH7hSm9v7%2FLTfz%2BtZU062rSiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/510wwe1qMUL.js?AUIClients/RetailSearchAutocompleteAssets script
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/bfc2ce12-b7a1-4415-a251-784a599a7b79/scale-to-width-down/1600 image
-http://www.paypal.com/ https://www.paypal.com/ html
-http://www.amazon.de/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2 font
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/81e6bae5-f46a-49ec-87aa-8ec8073af2ff/scale-to-width-down/1600 image
-http://www.paypal.com/ https://www.paypal.com/us/home html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/ba164b0a-08f0-4f91-8422-35c9d497e07d/scale-to-width-down/1600 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/55427feb-e235-495b-8ee9-6a2bbb68243e/scale-to-width-down/1024 image
-http://www.paypal.com/ https://www.paypal.com/us/signin?country.x=US&locale.x=en_US html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/b186ce14-f2a2-43dc-ade6-47c5544e4455/scale-to-width-down/1024 image
-http://www.paypal.com/ http://sr.symcd.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBR0JBRnBp%2F14Jg%2FXj4aa6BlKlQVdQQUAVmr5906C1mmZGPWzyAHV9WR52oCECxqpDaJyq%2F%2BD0ZiblxvnRKiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.paypal.com/ https://www.paypalobjects.com/eboxapps/css/fe/b9ec3da50d4d5afb899e7a86dceddefa2d44e6.css css
-http://www.wikia.com/ http://d1z2jf7jlzjs58.cloudfront.net/p.js script
-http://www.paypal.com/ https://www.paypalobjects.com/eboxapps/css/8f/c3db75ade712988cd9d0a4815ecbf08983f24d.css css
-http://www.wikia.com/ http://edge.quantserve.com/quant.js script
-http://www.amazon.de/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-a3d92a134e6afaec4974bceac0812b73d0b635c1._V2_.png image
-http://www.paypal.com/ https://www.paypalobjects.com/eboxapps/css/ea/d9b98c63fddb35c7d8a62471ac32e6cceda820.css css
-http://www.wikia.com/ https://www.google-analytics.com/analytics.js script
-http://www.amazon.de/ https://www.amazon.de/uedata/unsticky/259-1459190-6685068/NoPageType/ntpoffrw?ld&v=0.1284.0&id=FW5S02T97H4K4YK5CGQM&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=FW5S02T97H4K4YK5CGQM&ue=20&bb=1504&ns=1522&cf=1674&be=1709&af=1724&ne=1841&pc=3389&tc=-1773&na_=-1773&ul_=-1516015920544&_ul=-1516015920544&rd_=-1516015920544&_rd=-1516015920544&fe_=-1703&lk_=-1703&_lk=-1346&co_=-1346&_co=-703&sc_=-1043&rq_=-696&rs_=-95&_rs=213&dl_=-88&di_=1717&de_=1717&_de=1718&_dc=3389&ld_=3389&_ld=-1516015920544&ntd=0&ty=0&rc=0&hob=14&hoe=20&ld=3390&t=1516015923934&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:13-5-4-2-3-0-0&csmtags=aui|aui:aui_build_date:3.17.20-2017-12-07|gwImgNoCached|fls-eu|pageEncoding:UTF-8|gwmNoCardHistory&viz=visible:20&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=FW5S02T97H4K4YK5CGQM&aftb=1 image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/logo/monogram/pp_bb_mg.png image
-http://www.wikia.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D138%26cf0%3D1485%26pc0%3D1486%26ld0%3D1486%26t0%3D1516015922030%26sc1%3Dlg%26af1%3D1674%26pc1%3D1674%26ld1%3D1674%26t1%3D1516015922218%26sc2%3DcsmCELLSframework%26bb2%3D1701%26pc2%3D1701%26ld2%3D1701%26t2%3D1516015922245%26sc3%3DcsmCELLSpdm%26bb3%3D1701%26pc3%3D1705%26ld3%3D1705%26t3%3D1516015922249%26sc4%3DcsmCELLSvpm%26bb4%3D1706%26pc4%3D1706%26ld4%3D1706%26t4%3D1516015922250%26sc5%3DcsmCELLSfem%26bb5%3D1707%26pc5%3D1707%26ld5%3D1707%26t5%3D1516015922251%26sc6%3Dinteractivity%26cf6%3D2770%26pc6%3D2770%26ld6%3D2770%26t6%3D1516015923314%26ctb%3D1:3398 image
-http://www.wikia.com/ http://s3.amazonaws.com/ki.js/52510/bgJ.js script
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/icon-psnl-creditcards.png image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/icon-psnl-shopsecure.png image
-http://www.amazon.de/ https://m.media-amazon.com/images/G/01/csm/showads.v2.js script
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/icon_biz_1-opt.png image
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D3437%26pc0%3D3437%26ld0%3D3437%26t0%3D1516015923981%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:3437 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/b74e5214-43b2-4af5-8616-dba487b00673/scale-to-width-down/1600 image
-http://www.amazon.de/ https://www.amazon.de/favicon.ico image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/icon-psnl-payanyfi.png image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/cbf77c0a-871f-4839-b7ea-130a01ad8461/scale-to-width-down/1600 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/2018/campaigns/Jan_Promo/r-promo-gw-d-1242x450-de2._SX1242_CB488917619_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/cc5d1465-5c50-49f0-9b4d-ba5370b92b09/scale-to-width-down/1600 image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/icon_biz_2-opt.png image
-http://www.wikia.com/ http://cdn.krxd.net/controltag?confid=KPSUiAKl script
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/icon_biz_3-opt.png image
-http://www.wikia.com/ http://b.scorecardresearch.com/beacon.js script
-http://www.paypal.com/ https://www.paypalobjects.com/eboxapps/js/f4/8ae60df0703b551783167040b5e9e02ef11003.js script
-http://www.wikia.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=2082358518&t=pageview&_s=1&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aEDAAEABE~&jid=252610434&gjid=517597162&cid=1165755339.1516016149&tid=UA-71552437-1&_gid=602335839.1516016149&_r=1&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=174176428 html
-http://www.paypal.com/ https://www.paypalobjects.com/pa/js/min/pa.js script
-http://www.wikia.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=2082358518&t=pageview&_s=1&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aEDAAEABE~&jid=2043135157&gjid=1516829703&cid=1165755339.1516016149&tid=UA-32129070-1&_gid=602335839.1516016149&_r=1&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=1375854082 html
-http://www.paypal.com/ https://www.paypalobjects.com/eboxapps/js/c5/6ffd85c1ffabc778be43f8aacae806c880afb7.js script
-http://www.wikia.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=2082358518&t=pageview&_s=1&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aEDAAEABE~&jid=375893851&gjid=734092258&cid=1165755339.1516016149&tid=UA-32132943-1&_gid=602335839.1516016149&_r=1&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=1990012870 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/bs.js script
-http://www.amazon.de/ https://www.amazon.de/gp/gw/ajax/dataStore.html/259-1459190-6685068?ie=UTF8&hmac=D632FEC6B2E9FA2FA046F061FDE07A552C9148D2&opf_redir=1&relatedRequestId=FW5S02T97H4K4YK5CGQM script
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/images/fandom-app-icon.png image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/logo/monogram/pp_rv_mg.svg image
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D3667%26cf0%3D3675%26pc0%3D3675%26ld0%3D3675%26t0%3D1516015924219%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:3675 image
-http://www.wikia.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=2082358518&t=event&ni=1&_s=2&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=card&ea=59065&el=view.item-0&_u=aEDAAEABE~&jid=&gjid=&cid=1165755339.1516016149&tid=UA-71552437-1&_gid=602335839.1516016149&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&cd8=0&z=710311220 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/gno/sprites/sky_webnav_V1_sprite_2x._CB515271921_.png image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/bifurcated-personal-mobile.jpg image
-http://www.wikia.com/ http://rules.quantcount.com/rules-p-8bG6eLqkH6Avk.js script
-http://www.amazon.de/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2 font
-http://www.wikia.com/ http://fandom.wikia.com/f2/api/get-client-ip script
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/na/us/home/bifurcated-business-mobile.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/791f79bd-e6f1-46ae-9cb8-a8844fd8a93c/scale-to-width-down/1600 image
-http://www.amazon.de/ https://www.amazon.de/uedata/unsticky/259-1459190-6685068/NoPageType/ntpoffrw?at&v=0.1284.0&id=FW5S02T97H4K4YK5CGQM&m=1&sc=adblk_no&pc=3782&at=3783&t=1516015924327&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=FW5S02T97H4K4YK5CGQM&aftb=1 image
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/global/shared/global/country-worldwide/sprite_countries_flag4.png image
-http://www.wikia.com/ http://fandom.wikia.com/f2/api/public/interrupt/trending-topics html
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26m%3D1%26sc%3Dadblk_no%26pc%3D3782%26at%3D3783%26t%3D1516015924327%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:3783 image
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansSmall-Bold.woff font
-http://www.wikia.com/ http://fandom.wikia.com/f2/api/public/interrupt/trending-videos html
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansBig-Light.woff font
-http://www.amazon.de/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2 font
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansSmall-Medium.woff font
-http://www.wikia.com/ http://fandom.wikia.com/f2/api/get-client-ip script
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansBig-Medium.woff font
-http://www.amazon.de/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js script
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansSmall-Light.woff font
-http://www.wikia.com/ http://b.scorecardresearch.com/b?c1=2&c2=6177433&comscorekw=movies&ns__t=1516016149231&ns_c=UTF-8&cv=3.1m&c8=FANDOM&c7=http%3A%2F%2Fwww.wikia.com%2Ffandom&c9= other
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansSmall-Regular.woff font
-http://www.wikia.com/ https://fonts.gstatic.com/s/rubik/v7/tRvJQnSw4lmceQIbdzOKGHYhjbSpvc47ee6xR_80Hnw.woff2 font
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/mktg/2014design/font/PP-Sans/PayPalSansBig-Regular.woff font
-http://www.wikia.com/ http://srv-2018-01-15-11.config.parsely.com/config/fandom.wikia.com script
-http://www.amazon.de/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-c1600921ba590f11b924a6928fdc699bedab0a0c._V2_.js script
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/global/icons/steps-control-left.svg image
-http://www.wikia.com/ https://adservice.google.com/adsid/integrator.js?domain=www.wikia.com script
-http://www.amazon.de/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2 font
-http://www.paypal.com/ https://www.paypalobjects.com/digitalassets/c/website/marketing/global/icons/steps-control-right.svg image
-http://www.wikia.com/ https://fonts.gstatic.com/s/rubik/v7/q1zR17dXuC8hEk69Lb7Bo3YhjbSpvc47ee6xR_80Hnw.woff2 font
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3Ddata-store-1%26bb0%3D3611%26cf0%3D4337%26pc0%3D4337%26ld0%3D4338%26t0%3D1516015924882%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:4338 image
-http://www.paypal.com/ https://www.paypalobjects.com/gajs/analytics.js script
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/view?a=&beacon=EbVBeFSAGG&c=1452001&cb=1516016148829&dev=false&dev_cat=mobile&event_ts=1516016148&f=Home&ga_action=&ga_category=pageview&ga_label=&lc=en&pg_type=home&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&t=pageview&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom script
-http://www.paypal.com/ https://nexus.ensighten.com/paypal/prod/serverComponent.php?r=9758040.41338079&ensJson=true&ClientID=1620&PageID=https%3A%2F%2Fwww.paypal.com%2Fus%2Fhome%3Ftms_country%3Dus%26ensJson%3Dtrue script
-http://www.amazon.de/ https://www.amazon.de/gp/gw/ajax/card.html/259-1459190-6685068?ie=UTF8&opf_redir=1&rshVal=1516015924961 html
-http://www.wikia.com/ http://b.scorecardresearch.com/b2?c1=2&c2=6177433&comscorekw=movies&ns__t=1516016149231&ns_c=UTF-8&cv=3.1m&c8=FANDOM&c7=http%3A%2F%2Fwww.wikia.com%2Ffandom&c9= other
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/8db46309e6349886335823942737f697.js?conditionId0=378623 script
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/trackingevent?a=59065&beacon=EbVBeFSAGG&c=1452001&c_loc=0&cb=1516016150815&dev=false&dev_cat=mobile&event_ts=1516016150&f=Home&ga_action=59065&ga_category=card&ga_label=view.item-0&lc=en&nonInteraction=true&pg_type=home&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&t=event&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/digital/video/placement/Gateway/Evergreen/Mobile/DE_EvergreenHero_X-Site_Superhero_1242x450_SFT_v2._SX414_CB492367753_.jpg image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/5d1f60932d2de7874f1413e7f0a60ccb.js?conditionId0=474093 script
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/248aabf4443966cb0328876d5797f914.js?conditionId0=380088 script
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D4502%26pc0%3D4507%26ld0%3D4507%26t0%3D1516015925051%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:4507 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/34991b7ef71f70aea175b18646183b7c.js?conditionId0=380088 script
-http://www.wikia.com/ http://cdn.krxd.net/ctjs/controltag.js.a44b3dbbe01052e7f96183d0a266743c script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/digital/video/placement/Gateway/Evergreen/Mobile/DE_EvergreenHero_X-Site_Superhero_1242x450_SFT_v2._SX1242_CB492367753_.jpg image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/f424d2932e2b5ebf7a30cd6b997cdcf5.js?conditionId0=380088 script
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/8c024cb0043360c0a183ef86569e5a97.js?conditionId0=422975 script
-http://www.amazon.de/ https://www.amazon.de/gp/gw/ajax/card.html/259-1459190-6685068?ie=UTF8&opf_redir=1&rshVal=1516015925568 html
-http://www.wikia.com/ https://cdn.optimizely.com/js/4228485597.js script
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/bcb41607f75ea330dedec9a4085353b5.js?conditionId0=422975 script
-http://www.wikia.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-71552437-1&cid=1165755339.1516016149&jid=252610434&_gid=602335839.1516016149&gjid=517597162&_v=j66&z=174176428 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/57c0f912006fed6af5e8ad35652688fa.js?conditionId0=422975 script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/de-certifiedrefurbished/redesign/de_certified_refurbished_renewed_gw_mobile_cat_card_1050x1050._UX350_SX350_CB493248861_.jpg image
-http://www.wikia.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-32129070-1&cid=1165755339.1516016149&jid=2043135157&_gid=602335839.1516016149&gjid=1516829703&_v=j66&z=1375854082 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/dbaad2f82257933cdc110875fd4862a1.js?conditionId0=422975 script
-http://www.amazon.de/ https://images-na.ssl-images-amazon.com/images/G/03/acs/amazon-designer/2017/12/13/DURM-28B9FB96CFBA93S5._AC_.jpeg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/293fb63d-c6a3-4550-a668-b3db2d58fb3e/scale-to-height-down/500 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/dd6797289466fcafceda54ba0fd683a6.js?conditionId0=422975 script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/61bnu7GGniL._AC_SY80_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/ae76f925-63a4-4c22-9907-642a535dfd3f/scale-to-height-down/500 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/01f999dbe8972e3f86979480467b4c57.js?conditionId0=379384 script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/41SvLvaDS%2BL._AC_SY80_.jpg image
-http://www.wikia.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/4fd3d4fd7e2dae28394a57c820abfc8a.js?conditionId0=379384 script
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/73482803-d145-47d6-8088-645c4132808a/scale-to-height-down/500 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/56f6fcc6ec0c8a2f6630a4b681d5ad60.js?conditionId0=597156 script
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3Dgwm%26cf0%3D1674%26af0%3D5032%26pc0%3D5032%26ld0%3D5032%26t0%3D1516015925576%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:5032 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/513abb93-116e-453f-96a7-b04fb1057d25/scale-to-height-down/500 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/8d6c38cba2c6ba608641dd96b5028c3d.js?conditionId0=381750 script
-http://www.wikia.com/ http://pixel.quantserve.com/pixel;r=1037438137;labels=Fandom.Article.FANDOM;rf=0;a=p-8bG6eLqkH6Avk;url=http%3A%2F%2Fwww.wikia.com%2Ffandom;fpan=1;fpa=P0-718150469-1516016149819;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=0;et=1516016149819;tzo=0;ogl=locale.en_US%2Ctype.feed%2Ctitle.FANDOM%2Cdescription.The%20entertainment%20site%20where%20fans%20come%20first%252E%20Your%20daily%20source%20for%20all%20things%20T%2Curl.http%3A%2F%2Ffandom%252Ewikia%252Ecom%2Csite_name.FANDOM%2Cimage.https%3A%2F%2Fvignette%252Ewikia%252Enocookie%252Enet%2F48c4c991-2051-4ced-81ba-a3a69062cd19%2Fthumbna%2Cimage%3Awidth.1280%2Cimage%3Aheight.720 image
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/29a5567ef4e201afc0084cf6bf0cf984.js?conditionId0=472867 script
-http://www.wikia.com/ http://cdn.krxd.net/partnerjs/xdi/proxy.3d2100fd7107262ecb55ce6847f01fa5.html html
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/4fd3d4fd7e2dae28394a57c820abfc8a.js?conditionId0=472867 script
-http://www.wikia.com/ http://fandom.wikia.com/f2/api/public/interrupt/trending-topics html
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/802b93f0fe41b41869a2e449e704709d.js?conditionId0=378623 script
-http://www.paypal.com/ https://www.paypalobjects.com/tagmgmt/codefiles/80663e54bf66b08ca5868db9f521c713.js?conditionId0=472867 script
-http://www.wikia.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=2898949716824355&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fifs&adsid=NT&json_a=1&eid=21060361%2C21061149&sc=0&sfv=1-0-14&iu_parts=5441%2Cwka.fandom%2C_home%2CHOME_TOP_LEADERBOARD%2CHOME_TOP_BOXAD&enc_prev_ius=%2F0%2F1%2F2%2F3%2C%2F0%2F1%2F2%2F4&prev_iu_szs=320x50%7C320x480%7C2x2%2C300x250&prev_scp=loc%3Dtop%26uap%3Dnone%26wsi%3Ddlh1%26src%3Dns%26pos%3DTOP_LEADERBOARD%7Cloc%3Dmiddle%26uap%3Dnone%26wsi%3Ddmh1%26src%3Dns%26pos%3DTOP_BOXAD&eri=1&cust_params=host%3Dwww.wikia.com%26kuid%3D%26lang%3Den%26outstream%3Dnone%26post_id%3D-1%26skin%3Dfandom_mobile%26vertical%3Dhome%26wsi%3Ddxh1&cookie_enabled=1&abxe=1&lmt=1516016155&dt=1516016155728&frm=20&biw=360&bih=512&oid=3&adxs=0%2C0&adys=0%2C0&adks=3854150723%2C3769845389&gut=v2&ifi=1&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&dssz=31&icsg=8320&std=0&vrg=172&vis=1&scr_x=0&scr_y=0&ga_vid=1165755339.1516016149&ga_sid=1516016156&ga_hid=2082358518 script
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3Dcard-load-1%26bb0%3D4417%26cf0%3D4964%26pc0%3D5022%26ld0%3D5022%26t0%3D1516015925566%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:5022 image
-http://www.paypal.com/ https://t.myvisualiq.net/sync?prid=Test&ao=0&red=https%3A%2F%2Fad.doubleclick.net%2Fddm%2Ftrackimp%2FN426203.2426714VISUALIQ%2FB11035907.147164125%3Bdc_trk_aid%3D318650907%3Bdc_trk_cid%3D79651416%3Bsz%3D1x1%3Bu%3Dwww.paypal.com%252Fus%252Fhome%7CVIQ_%24%7BUUID%7D%7C;ord=1516016054967 other
-http://www.wikia.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_172.js script
-http://www.paypal.com/ https://t.myvisualiq.net/sync?prid=123&ao=0&red=https%3A%2F%2Fwww.facebook.com%2Ftr%3Fid%3D1939652716271841%26ev%3DPageView%26cd%5Border_id%5D%3D%24%7BUUID%7D other
-http://www.google.com.ua/ http://www.google.com.ua/ html
-http://www.wikia.com/ http://static.parsely.com/code/ptrack-v0.9.2-engaged-time-slots-video.js script
-http://www.google.com.ua/ https://www.google.com.ua/?gws_rd=ssl html
-http://www.amazon.de/ https://www.amazon.de/uedata/unsticky/259-1459190-6685068/NoPageType/ntpoffrw?at&v=0.1284.0&id=FW5S02T97H4K4YK5CGQM&ctb=1&m=1&sc=FW5S02T97H4K4YK5CGQM&pc=5099&at=5099&t=1516015925643&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=FW5S02T97H4K4YK5CGQM&aftb=1 image
-http://www.paypal.com/ https://secure.adnxs.com/mapuid?member=1961&user=f99915b61600a1e1c58827affffd89c9 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/ce975e9b-1844-4e67-b57d-b019ac9112d3/scale-to-height-down/500 image
-http://www.google.com.ua/ https://www.google.com.ua/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.paypal.com/ https://www.facebook.com/tr?id=1674696026155243&ev=ViewContent&noscript=1&cd[MerchantID]=&cd[MerchantTPV]=&cd[MerchantTransaction]=&cd[FPTICookie]=&cd[P2PTransaction]=&cd[P2PTPV]= image
-http://www.wikia.com/ http://cdn.krxd.net/controltag/KPSUiAKl.js script
-http://www.google.com.ua/ https://www.google.com.ua/images/nav_logo242_hr.webp image
-http://www.paypal.com/ https://t.myvisualiq.net/ul_cb/sync?prid=123&ao=0&red=https%3A%2F%2Fwww.facebook.com%2Ftr%3Fid%3D1939652716271841%26ev%3DPageView%26cd%5Border_id%5D%3D%24%7BUUID%7D other
-http://www.google.com.ua/ https://www.google.com.ua/gen_204?s=webaft&atyp=csi&ei=MJFcWsOePMi6jwPQz6z4AQ&rt=wsrt.2180,aft.163,prt.163 html
-http://www.wikia.com/ http://fandom.wikia.com/f2/api/public/interrupt/trending-videos html
-http://www.paypal.com/ https://www.google-analytics.com/r/collect?v=1&_v=j46&a=558947894&t=pageview&_s=1&dl=https%3A%2F%2Fwww.paypal.com%2Fus%2Fhome&ul=en-us&de=UTF-8&dt=Send%20Money%2C%20Pay%20Online%20or%20Set%20Up%20a%20Merchant%20Account%20-%20PayPal&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=SGCACEABJ~&jid=1604150299&cid=1802354007.1516016054&tid=UA-53389718-12&_r=1&cd1=1802354007.1516016054&cd2=&cd3=false&cd4=%2Fus%2Fhome&cd5=us&cd6=en_US&cd7=&cd8=&cd9=&cd10=&cg3=false&cg1=mpp&cg2=3&z=295191411 image
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26m%3D1%26sc%3DFW5S02T97H4K4YK5CGQM%26pc%3D5099%26at%3D5099%26t%3D1516015925643%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:5099 image
-http://www.paypal.com/ https://www.facebook.com/tr?id=1939652716271841&ev=PageView&cd[order_id]=385b306d-ab98-41e8-834a-5bd43ffba5ff image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/20e60989-1714-46d6-87ba-b00b67116944/scale-to-height-down/500 image
-http://www.google.com.ua/ https://www.google.com.ua/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/rt=j/d=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51F%2BW-4dMOL._AC_SY80_.jpg image
-http://www.paypal.com/ https://ad.doubleclick.net/ddm/trackimp/N426203.2426714VISUALIQ/B11035907.147164125;dc_trk_aid=318650907;dc_trk_cid=79651416;sz=1x1;u=www.paypal.com%2Fus%2Fhome%7CVIQ_0-b3dfc2e3-4261-40bf-b75e-fcbb41d75bc3%7C;ord=1516016054967 image
-http://www.wikia.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=2082358518&t=event&ni=1&_s=3&dl=http%3A%2F%2Ffandom.wikia.com%2F&dh=wikia.com&ul=en-us&de=UTF-8&dt=FANDOM&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=optimizely&ea=0&el=optimizely.loaded&_u=aEDAAEABE~&jid=&gjid=&cid=1165755339.1516016149&tid=UA-71552437-1&_gid=602335839.1516016149&cd1=home&cd2=&cd3=&cd4=&cd5=&cd6=&cd7=&z=468582253 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/41ARiFtPimL._AC_SY200_.jpg image
-http://www.google.com.ua/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.wikia.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjss1UuOv-7cRZqC9lmmWC9bB1gzXYXJw7WE6Okmwd-2HqegkZYobv9q5eimdT1BTe9VEa1jF3uFen2-rSi6kwsDmaH2Gpkz5iRUyS0QJjXvA4h0XYDjjWaJz6SN6OFrvppQboBxQ0prBeUNC9ZO9WOKIbvHhqJjGWDUysOwAxE_YTXpti6yvGKTbEBot_ZG20IuWoVYEFMK4_v7vM4a6Ex8zRM3-LKqCsPfJLgqFkysQR9F079pA8-v4tLOjdZuk3Q0vqu0jzYeGaEfVCVEvDIc&sig=Cg0ArKJSzEON-QQ-UWAkEAE&urlfix=1&adurl= html
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/AustinBundle-Mobile_billboard-a-de-1242x450._SX414_CB507116531_.jpg image
-http://www.google.com.ua/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/icon/pp196.png image
-http://www.wikia.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjst4d1MVmDcxZarPjJm_YuNsMRZyHS0wpPLGMdydJ1z_9vcipHemiwi7HrHJch2WVc64G6j8-1MCjJuQwOki7587_JDBfo1M6wm6f-MZHq-jwDq69hhh8EI3_beLANfXRtO02AFAOkJHlZGh9kc4tvskXTQTnJXo65FRilP6D9Q5K1ReywIG5L_FGp-XURF2dGp3JBv-mClyNJ096rUysFu1ZTx9f_bLtSxRqZkNFnHl8NTOGsgeKMNbWTwkZm8GJVC6209boQqpLDbVzBY&sig=Cg0ArKJSzESvZ7-qQWFOEAE&urlfix=1&adurl= html
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51BOlFkokpL._AC_SY80_.jpg image
-http://www.paypal.com/ https://ad.doubleclick.net/ddm/activity/src=6386697;type=mppmz0;cat=pphom0;u1=;u2=;u3=;u4=;u5=;u6=mobile:mktg:personal::home:::;u7=www.paypal.com/us/home%20;u8=;u9=;u10=us;u11=;u12=;u13=;u14=;u15=;u16=;u17=;u18=;u19=;u20=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=1 image
-http://www.wikia.com/ http://beacon.krxd.net/cookie2json?callback=Krux.ns._default.kxjsonp_3pevents script
-http://www.google.com.ua/ https://www.google.com.ua/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ?xjs=s1 script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51PNBCEcjbL._AC_SY80_.jpg image
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengadinfo?a=&ad_status=forced_success&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016157538&country=US&creative_id=138221838949&creative_size=2x2&dev=false&dev_cat=mobile&event_ts=1516016157&f=Home&kv_abi=&kv_ah=&kv_esrb=&kv_lang=en&kv_pos=TOP_LEADERBOARD&kv_ref=&kv_rv=&kv_s0=&kv_s0v=&kv_s1=&kv_s2=&kv_skin=fandom_mobile&kv_top=&kv_wsi=dlh1&lc=en&page_width=360&pg_type=home&product_lineitem_id=4538836048&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&slot_size=2x2&t=event&time_bucket=11&timestamp=1516016157535&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&viewport_height=512 script
-http://www.paypal.com/ https://www.google-analytics.com/collect?v=1&_v=j46&a=558947894&t=pageview&_s=1&dl=https%3A%2F%2Fwww.paypal.com%2Fus%2Fhome&ul=en-us&de=UTF-8&dt=Send%20Money%2C%20Pay%20Online%20or%20Set%20Up%20a%20Merchant%20Account%20-%20PayPal&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=SGCAiEABB~&jid=286579006&cid=1802354007.1516016054&uid=&tid=UA-53389718-2&cd1=%20UTC0&cd2=Mon%20Jan%2015%202018%2011%3A34%3A18%20GMT%2B0000%20(UTC)&cd3=1802354007.1516016054&z=75704342 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.de&slot=navFooter&a2=0101d67c14188b8ece9853f63d7ec12798641006c6e67d8458a06909f00cadbd277c&old_oo=0&cb=1516015920267 other
-http://www.google.com.ua/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.paypal.com/ https://t.paypal.com/ts?v=1.1.8&t=1516016057871&g=0&e=im&pgrp=mobile%3Amktg%3Apersonal%3A%3Ahome&page=mobile%3Amktg%3Apersonal%3A%3Ahome%3A%3A%3A&tmpl=home.dust&pgst=Unknown&lgin=out&calc=b04211ea273a&rsta=en_US&pgtf=Nodejs&s=ci&ccpg=us&csci=90857486c0554faabc4e4b87cb902e5c&comp=mppnodeweb&tsrce=mppnodeweb&xe=3396&xt=8105&pgld=Unknown&bzsr=main&bchn=mktg&pgsf=personal&shir=mobile_mktg_personal_&pros=3&lgcook=0&gacook=1802354007.1516016054&akdc=phx-origin-www-1.paypal.com&pt=Send%20Money%2C%20Pay%20Online%20or%20Set%20Up%20a%20Merchant%20Account%20-%20PayPal&cd=24&sw=360&sh=512&dw=1080&dh=1536&bw=360&bh=512&ce=1&t1=3&t1c=0&t1d=0&t1s=0&t2=796&t3=363&t4d=9233&t4=9233&t4e=0&tt=12514&view=%7B%22t10%22%3A2473%2C%22t11%22%3A12514%2C%22t14%22%3A1516016045339%7D&teal=NEDdO6ROG8bS6VTp7f%252BaNBCnB0eZpkwzRr4XadTbPoykMclKGB4u%252BTJXU%252FPHGuvXrLg4ikknxvg_160f99917a2&res=%7B%22css%22%3A%7B%22t9%22%3A2581.3%2C%22t12%22%3A2578.1%2C%22t13%22%3A0%2C%22cnt%22%3A4%7D%2C%22scr%22%3A%7B%22t9%22%3A6392.7%2C%22t12%22%3A3595.5%2C%22t13%22%3A0%2C%22cnt%22%3A23%7D%2C%22img%22%3A%7B%22t9%22%3A9091.6%2C%22t12%22%3A3601.7%2C%22t13%22%3A0%2C%22cnt%22%3A12%7D%2C%22othr%22%3A%7B%22t9%22%3Anull%2C%22t12%22%3A0%2C%22t13%22%3A0%2C%22cnt%22%3A2%7D%2C%22xhr%22%3A%5B%7B%22nm%22%3A%22nexus.ensighten.com%2F...%2FserverComponent.php%22%2C%22t4%22%3A7875.6%2C%22t5%22%3A8191%2C%22t6%22%3A8823.7%2C%22t7%22%3A7875.6%2C%22t8%22%3A7875.6%2C%22t9%22%3A1270.6%2C%22ta%22%3A7872.2%2C%22tb%22%3A0%2C%22tc%22%3A0%2C%22td%22%3A8823.8%2C%22te%22%3A9141.5%2C%22tf%22%3A9142.8%2C%22t10%22%3A7872.2%7D%5D%7D image
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengadinfo?a=&ad_status=success&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016157571&country=US&creative_id=138219341489&creative_size=300x250&dev=false&dev_cat=mobile&event_ts=1516016157&f=Home&kv_abi=&kv_ah=&kv_esrb=&kv_lang=en&kv_pos=TOP_BOXAD&kv_ref=&kv_rv=&kv_s0=&kv_s0v=&kv_s1=&kv_s2=&kv_skin=fandom_mobile&kv_top=&kv_wsi=dmh1&lc=en&page_width=360&pg_type=home&product_lineitem_id=4538836048&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&slot_size=300x250&t=event&time_bucket=11&timestamp=1516016157570&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&viewport_height=512 script
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OE/ other
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OP/A1PA6795UKMFR9:259-1459190-6685068:FW5S02T97H4K4YK5CGQM$uedata=s:%2Fuedata%2Funsticky%2F259-1459190-6685068%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DFW5S02T97H4K4YK5CGQM%26ctb%3D1%26sc0%3Dcard-load-2%26bb0%3D5024%26cf0%3D5524%26pc0%3D5536%26ld0%3D5536%26t0%3D1516015926080%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3DFW5S02T97H4K4YK5CGQM%26aftb%3D1:5536 image
-http://www.paypal.com/ https://p1.zemanta.com/p/342/585/ image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/fe73c4ef-49a6-48e7-8269-84608579a5a6/scale-to-height-down/500 image
-http://www.google.com.ua/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51u3OcL22oL._AC_SY80_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/00db2fe0-8711-46d6-8037-3b5783a4c132/scale-to-height-down/500 image
-http://www.paypal.com/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j46&tid=UA-53389718-2&cid=1802354007.1516016054&jid=286579006&_u=SGCAiEABB~&z=369012539 html
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/317Qb9WY18L._RC%7C51UyBFLu-QL.js_.js?AUIClients/SharedShoppingCartMobileAsset script
-http://www.wikia.com/ http://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.paypal.com/ https://altfarm.mediaplex.com/ad/bk/3484-16283-2054-241?HomePageLanding=1&mpuid=;;;;;;;;;;;;;;;mobile:mktg:personal::home;;;;;;;;; other
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31i2+AYmxJL.css_.css?AUIClients/SharedShoppingCartMobileAsset css
-http://www.paypal.com/ https://pixel.mathtag.com/event/img?mt_id=888356&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3= image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/01keU37gh%2BL.js?AUIClients/DetailPageAlohaAssets script
-http://www.google.com.ua/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/2d64ba22-562b-4e3f-9b92-1f5ccbfedd8b/scale-to-height-down/500 image
-http://www.paypal.com/ https://pixel.mathtag.com/event/img?mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3= image
-http://www.google.com.ua/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets css
-http://www.wikia.com/ http://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.paypal.com/ https://pixel.mathtag.com/event/img?mt_id=888358&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3= image
-http://www.wikia.com/ https://tpc.googlesyndication.com/pagead/imgad?id=CICAgKDrkZ-RhQEQARgBMghl8i1Z-XUnig image
-http://www.google.com.ua/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/11chYsfG59L._RC%7C411E-IzoCiL.js,31cePTj3CrL.js,11NxOa490XL.js,31E+jMbvKeL.js,21ydeSYKyxL.js,31hd9A67kaL.js,51wmFWz9R9L.js,51Hi2VfLU+L.js,21yUMfZsKLL.js,31Ime9qWaBL.js,016DBHJkIYL.js,21ng+A1rTWL.js,41mcGVaoxHL.js,81ewiHI9QoL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,01CANZ8BqcL.js,21AuBaN+lVL.js,51YzCqyJFIL.js,0111g0cQvbL.js,01nKqcvaCIL.js,01X117Z9PgL.js,41d1c1srD2L.js,01X5C8pWB1L.js,518wG9hJ8NL.js,31egXBuM55L.js,01RHiyjONOL.js,31I-BifbuzL.js,210S22NrxIL.js,412fOjq25KL.js,314ZAgS3sJL.js,11U-t4vkrhL.js,21q5QmCNgJL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,51rCZ2WOe0L.js,71OuhyN2DxL.js,01BZK417f8L.js,319kjuuQkzL.js,01UujNMpLSL.js,41Eexuqvf6L.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,015J4NGaO3L.js,11B4fwZPeqL.js,21-q-ofQTaL.js,01lQqh9VSML.js,01jqyAujTwL.js,01jW+SjLRsL.js,01-XJ1YSEXL.js,01gaQLz1HjL.js,01NAT+3p7KL.js,111vgqp2a0L.js,51yQ7wSC4tL.js,01MZJG6lH8L.js,01VtYReatCL.js,21LWJ90NCIL.js,01CyECqkeYL.js,01RQtSMdG+L.js,21JwQBfgBXL.js,01l3c7okxRL.js,01-Eu4U-17L.js,01qwoVEkKlL.js,011HXD1ky3L.js,011X+p22ALL.js,01k57x9vvBL.js,01RNXZDiBuL.js,01ZF+ovNflL.js,31MsfX4iIYL.js,01S8y9NkxoL.js,01XzM3S0ZtL.js,01JGca-NkDL.js,01WMAHenIIL.js,51tlWANRbLL.js_.js?AUIClients/DetailPageMobileWebMetaAsset script
-http://www.wikia.com/ https://tpc.googlesyndication.com/pagead/imgad?id=CICAgKDrkdfMFxABGAEyCIjJMpo69oPe image
-http://www.paypal.com/ https://d.liadm.com/segment?s=17031 image
-http://www.google.com.ua/ https://www.google.com.ua/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfYARwIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oGGSL5fleXFIXSt7KNWojHV1KOrqQ script
-http://www.wikia.com/ https://tpc.googlesyndication.com/pagead/imgad?id=CICAgKDrsYadaBABGAEyCEW-yIIeiXjr image
-http://www.paypal.com/ https://ak1s.abmr.net/is/www.paypalobjects.com?U=/webstatic/icon/pp196.png&V=3-kCmnm+PIp7jz3nvgIiuV4cNCawF5HztXaUAn%2fL4tA1y5voZU5CWVTl1xK0v2tcNr&I=C756BA4F83C6CFB&D=paypalobjects.com&01AD=1& other
-http://www.google.com.ua/ https://www.google.com.ua/images/nav_logo242.png image
-http://www.paypal.com/ https://pixel.mathtag.com/event/img?mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=&mm_bnc&mm_bct other
-http://www.wikia.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener_heavy.js script
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/de-certifiedrefurbished/redesign/de_certified_refurbished_renewed_gw_mobile_cat_card_1050x1050._CB493248861_.jpg image
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/icon/pp196.png?01AD=3JdHcDz1EZ079Kxkat0M8jqmGVKkiYyt8zDT3Kw0quQ3FVaqWxAqcuQ&01RI=C756BA4F83C6CFB&01NA=na image
-http://www.google.com.ua/ https://www.google.com.ua/gen_204?atyp=csi&ei=MJFcWsOePMi6jwPQz6z4AQ&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2190&rt=aft.608,dcl.330,iml.608,ol.2418,prt.163,xjs.1568,xjsee.1567,xjses.1208,xjsls.176,wsrt.2180,cst.673,dnst.0,rqst.757,rspt.380,sslt.366,rqstt.1660,unt.984,cstt.984,dit.2510&zx=1516015923766 html
-http://www.wikia.com/ https://z.moatads.com/wikiadfp866051287149/moatad.js script
-http://www.google.com.ua/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.paypal.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-53389718-2&cid=1802354007.1516016054&jid=286579006&_v=j46&z=369012539 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.de&slot=navFooter&a2=0101d67c14188b8ece9853f63d7ec12798641006c6e67d8458a06909f00cadbd277c&old_oo=0&cb=1516015920267&dcc=t html
-http://www.google.com.ua/ https://www.google.com.ua/images/branding/product/1x/gsa_android_144dp.png image
-http://www.paypal.com/ https://ak1s.abmr.net/is/pixel.mathtag.com?U=/event/img&V=3-nIXmNUQ2R5e0i8GGeq6iy+%2fdTuRRO0dsGtlvGcTJvHIMO9bctAVggg%3d%3d&I=A53573197D358DA&D=mathtag.com&01AD=1&mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=&mm_bnc&mm_bct other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/1fa86e21-7afe-4026-9b68-16dbd13bed75/scale-to-height-down/500 image
-http://www.google.com.ua/ https://adservice.google.com.ua/adsid/google/ui html
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/icon/pp32.png image
-http://www.wikia.com/ http://srv-2018-01-15-11.pixel.parsely.com/plogger/?rand=1516016157499&idsite=fandom.wikia.com&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&urlref=&screen=360x512%7C360x512%7C24&data=%7B%22parsely_uuid%22%3A%22b7a93f4f-6423-4b8e-a544-8d2f27412559%22%2C%22parsely_site_uuid%22%3A%22c9a6be7f-a01f-4df2-b541-75913b8f651e%22%7D&sid=1&surl=http%3A%2F%2Fwww.wikia.com%2Ffandom&sref=&sts=1516016157480&slts=0&title=FANDOM&date=Mon+Jan+15+2018+11%3A35%3A57+GMT%2B0000+(UTC)&action=pageview image
-http://www.paypal.com/ https://pixel.mathtag.com/event/img?01AD=3DwfgE_ZJ82VL9wO3AiouPFA1DgoQE0aLxkGYF6PaQNWRvFdnNA-H2w&01RI=A53573197D358DA&01NA=&mt_id=1017593&mt_adid=136505&v1=&v2=&v3=&s1=&s2=&s3=&mm_bnc&mm_bct image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/fc6a44c3-1122-49eb-9719-21116a57d3ef/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/de-certifiedrefurbished/2017/Public-Launch/1076789_de_certified_refurbished_renewed_11-10-2017_GW_MobileBillboard_1242x450._SX414_CB512923933_.jpg image
-http://www.paypal.com/ https://www.paypalobjects.com/webstatic/icon/favicon.ico image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/951c9627-c19e-496a-9726-12d496d33b2f/scale-to-height-down/500 image
-http://www.wikia.com/ https://logx.optimizely.com/log/event text
-http://www.paypal.com/ https://sjc-login.dotomi.com/commonid/match?rurl=https%3A%2F%2Faltfarm.mediaplex.com%2Fad%2Fbk%2F3484-16283-2054-241%3Fmpu_token%3DAAABkXi_EulsgwAFCY46AAAAAAA%26HomePageLanding%3D1%26mpuid%3D%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3Bmobile%3Amktg%3Apersonal%3A%3Ahome%3B%3B%3B%3B%3B%3B%3B%3B%3B&user_token=AAABkXi_EulsgwAFCY46AAAAAAA&tok=I8eX8x89QXQ%3D other
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/EinkBundle-Mobile_billboard-a-de-1242x450._SX414_CB529985201_.jpg image
-http://www.paypal.com/ https://altfarm.mediaplex.com/ad/bk/3484-16283-2054-241?mpu_token=AAABkXi_EulsgwAFCY46AAAAAAA&HomePageLanding=1&mpuid=;;;;;;;;;;;;;;;mobile:mktg:personal::home;;;;;;;;;&status=0 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/36757ae6-0ccd-4dab-884c-a3a32791f5ef/scale-to-height-down/500 image
-http://www.wikia.com/ http://i.w55c.net/ping_match.gif?st=Krux&rurl=http://beacon.krxd.net/usermatch.gif?partner=dataxu&uid=_wfivefivec_ image
-http://www.paypal.com/ https://u3s.mathtag.com/sync/img?adv=136505&uuid=92555a14-a69a-4b00-9e0d-a29f683671b2&mt_id=1017593&passback=https://pixel.mathtag.com/sync/img%3Fsync%3Dauto%26stat%3Dbatch_supply_passback html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/fb29ff9b-15c9-4b90-af27-037be3a3714f/scale-to-height-down/500 image
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?partner=dataxu&uid=vAiFPNar1EB33z5 image
-http://www.paypal.com/ https://pixel.mathtag.com/sync/img?sync=auto&stat=batch_supply_passback image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/DE-digital-music/hawkfire/Family/DE_HF_FamilyPlan_GW_MobileBillboard_870x510_family._SX290_CB523544627_.jpg image
-http://www.wikia.com/ http://p.rfihub.com/cm?in=1&pub=6919 other
-http://www.paypal.com/ https://cm.g.doubleclick.net/pixel?google_nid=mediamath&google_cm&google_hm=klVaFKaaSwCeDaKfaDZxsg html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/df1125a6-95e1-448a-b608-9010774cf1b8/scale-to-height-down/500 image
-http://www.paypal.com/ https://sync.mathtag.com/sync/img?mt_exid=4&mt_ec=64ws&mt_exuid=&google_gid=CAESEAwVGXfmCz99scEIRM0JQIs&google_cver=1 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/AMAZON-FASHION/2018/FASHION/FLIP/01_JANUARY/MERCH/WOMENS_COLD_WEATHER/GATEWAY_MOBILE_CATEGORY_CARD_1050X1050._UX350_SX350_CB490789045_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/b4c29200-ca21-4306-aa0c-c59330c7890d/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/80341e32-3ed0-4039-8a36-48a9d94a461c/scale-to-height-down/500 image
-http://www.paypal.com/ https://cm.g.doubleclick.net/pixel?google_nid=mediamath&google_hm=klVaFKaaSwCeDaKfaDZxsg image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/61bnu7GGniL._AC_SY240_.jpg image
-http://www.wikia.com/ http://token.rubiconproject.com/token?pid=27384&puid=Lu5v_RXY other
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41CNXGW6T4L.css,318TvQQkpyL.css,31tH-GJ-doL.css,11tkAOwE6OL.css,21xItms32EL.css,11ISqSj9gHL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,21qOYA5+VOL.css,11V6-eXxKOL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11xlykx3aFL.css,01CCLEN08lL.css,21CNSKZ67ML.css,51oAYplAOyL.css,21hLnMMJrfL.css,21lDMA2J74L.css,215tV0Xf4NL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21f0r7D13IL.css,61ypmw1UTGL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,016xTzXJLfL.css,31LBzl8T3vL.css,21340cB1gjL.css,01YdhMxma0L.css,018mGORJ7tL.css,11fvu+DzMxL.css,11ho+83HCzL.css,01ticFfm7pL.css,01lh9w-GYYL.css,11Mso4bvY-L.css,01LCsoCesOL.css,01ifu3nZXpL.css,21Yyo4tu6ZL.css_.css?AUIClients/DetailPageMobileWebMetaAsset css
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/9e8c0ce8-1613-472a-a0a0-7b4c30b93111/scale-to-height-down/500 image
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?partner_id=rfuel&partner_user_id=1180294949640452972 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/ef2b178b-3bf8-4a81-98cd-a7aab9d345cd/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/029565b7-c42d-44dd-a791-b5aa0b572fca/scale-to-height-down/500 image
-http://www.wikia.com/ http://match.adsrvr.org/track/cmf/generic?ttd_pid=krux&ttd_tpi=1 html
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/81MDTSEXQgL.js?AUIClients/GoldboxUDPAssets script
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/e60db200-86f6-44ef-a293-7c93235779d5/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/41SvLvaDS%2BL._AC_SY240_.jpg image
-http://www.wikia.com/ http://d.turn.com/r/dd/id/L2NzaWQvMS9jaWQvMjg0OTE3NDgvdC8y/dpuid/Lu5v_RXY image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/v3/pr?exlist=pp_sx_ns_kr_g_bsw_bk_ox_index_aold_an_rb_br_fbca_aolv_twca_y_pm_adelphic_adb&fv=1.0&ex-pl-fbca=B-266SXSQ9SAfNsGv-8p_w&ex-pl-twca=wFi6mfXLQ_eeGvx2Ln4ZCg&a=cm&ep=XzkGUMJx6-0WxALoIqWKPQ4G7S3ZyR412QbeDKPvx-r6ob18JGakmlthfSknMjrE html
-http://www.wikia.com/ http://match.adsrvr.org/track/cmb/generic?ttd_pid=krux&ttd_tpi=1 html
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51F%2BW-4dMOL._AC_SY240_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/11de58d6-975b-411c-8397-367d4272290f/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/4ca33269-814a-406a-8c62-08b83f1f85a9/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/be8214ee-12ba-4be6-851c-775cf233e9e7/scale-to-height-down/500 image
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?partner=ttd&partner_uid=c3a06c68-ba4c-4ce6-a4a7-a6d9f08bb060 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/e8d16680-6eea-4c1f-8514-30d3a8c3d3a1/scale-to-height-down/500 image
-http://www.amazon.de/ https://unagi-eu.amazon.com/1/events/com.amazon.csm.nexusclient.prod script
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/88d19cc6-677e-4141-8781-c656b3ac8ae5/scale-to-height-down/500 image
-http://www.wikia.com/ https://cms.analytics.yahoo.com/cms?partner_id=KRUX html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/3fe95190-64bf-42d9-b339-e0fc835c4033/scale-to-height-down/500 image
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016166611&content_type=%28none%29&country=US&creative_id=0&dev=false&dev_cat=mobile&event_name=init&event_ts=1516016166&f=Home&lc=en&line_item_id=0&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016166595&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/4f5fc140-f102-48f0-9c48-3acee1941e88/scale-to-height-down/500 image
-http://www.wikia.com/ http://ib.adnxs.com/getuid?http://beacon.krxd.net/usermatch.gif?adnxs_uid=$UID image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/498e6668-e5a5-42c8-9adf-d728b7f56ef5/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/41ARiFtPimL._AC_SY600_.jpg image
-http://www.wikia.com/ https://idsync.rlcdn.com/379708.gif?partner_uid=Lu5v_RXY image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/51a896f1-e934-4820-a30a-6e5c4130d5f3/scale-to-height-down/500 image
-http://www.amazon.de/ https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com%26 other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/fd1702aa-9656-409f-8d31-9e4fd3af1a10/scale-to-height-down/500 image
-http://www.amazon.de/ https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm&ex=doubleclick.net& html
-http://www.wikia.com/ https://idsync.rlcdn.com/379708.gif?partner_uid=Lu5v_RXY&redirect=1 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=0u6eMJ63EimE&ex=pulsepoint.com&&ev=&pid=557477 image
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengviewability?a=&beacon=EbVBeFSAGG&c=1452001&cb=1516016167489&creative_id=138221838949&dev=false&dev_cat=mobile&event_ts=1516016167&f=Home&lc=en&line_item_id=4538836048&pg_type=home&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&rv=1&session=4cJ5WHuQIo&site=web&t=event&timestamp=1516016167486&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.amazon.de/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__ html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/d483c9df-2fb6-4095-9b74-a8575a8c007f/scale-to-height-down/500 image
-http://www.amazon.de/ https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com%26 other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/454e5292-031c-47d3-917c-cd7af8baae26/scale-to-height-down/500 image
-http://www.amazon.de/ https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm=&ex=doubleclick.net&google_tc= html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/27b49714-b63e-40fa-8f72-16e8872df374/scale-to-height-down/500 image
-http://www.amazon.de/ https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1 other
-http://www.wikia.com/ http://ssum.casalemedia.com/usermatchredir?s=183716&cb=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dcasale%26partner_uid%3D__UID__ html
-http://www.amazon.de/ https://x.bidswitch.net/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/93487b41-dbb9-4815-892b-ddb1d71b6e2a/scale-to-height-down/500 image
-http://www.wikia.com/ https://beacon.krxd.net/usermatch.gif?partner=yhoo&partner_uid=E0 image
-http://www.amazon.de/ https://aa.agkn.com/adscores/g.pixel?sid=9212284268 other
-http://www.amazon.de/ https://usermatch.krxd.net/um/v2?partner=amzn other
-http://www.amazon.de/ https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.wikia.com/ https://usermatch.krxd.net/um/v2?partner=google other
-http://www.amazon.de/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1 html
-http://www.amazon.de/ https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1&verify=true other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/718e3d8b-0b99-41ab-94a8-3d960311a7b8/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEJYjr4knmY-1oJijr4484QQ&google_cver=1 image
-http://www.wikia.com/ http://ssum.casalemedia.com/usermatchredir?s=183716&cb=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dcasale%26partner_uid%3D__UID__&C=1 html
-http://www.amazon.de/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/3d43eb00-2578-492d-80ca-76bd0992eb0c/scale-to-height-down/500 image
-http://www.amazon.de/ https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.wikia.com/ http://px.surveywall-api.survata.com/k html
-http://www.amazon.de/ https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=4bc8fdaa3028ee8ef3cb40db121c62009fc8db7c&ex=aoldisplay.com image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/da83bc1e-a3ca-4508-990b-b8d39fc4db33/scale-to-height-down/500 image
-http://www.amazon.de/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=ecc12d3e-f9e7-11e7-8007-17d7422e0001 other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/5a9af364-8f1e-4826-bd5a-3e152aa16a65/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=index&id=Ew6mCYH4q1pwUlSgip9uNTdtcMg4ZgIC image
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?partner=casale&partner_uid=WlySKNHM4eIAAF91NwIAAAAx%26442 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=bidswitch.com&id=001ac0d8ade0efe1f9b6605946401c5f image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/f47dd5fb-d181-44eb-bffa-d0aa6ad85a36/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=openx.com&id=a6b850c6-b9c4-cf16-0ca0-0dcdb69c369f image
-http://www.amazon.de/ https://stags.bluekai.com/site/36841?dt=0&r=1263432894&sig=266897515&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmih1xvl5HuFzEzhvgXwBlWkmnvTonDUnlAda0QjeWxo0q7s3LSrtVZ3O3f3O3jhe+8hTKsKQvjj3APxvsA7BnDf1H1i9Rp9W1JcNA= other
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=spotx.com&id=ecc18ac1-f9e7-11e7-8007-17d7422e0001 image
-http://www.amazon.de/ https://ib.adnxs.com/getuid?https://aax-eu.amazon-adsystem.com/s/ecm3?id=$UID&ex=appnexus.com& image
-http://www.wikia.com/ https://usermatch.krxd.net/um/v2?partner=vdna other
-http://www.amazon.de/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc html
-http://www.wikia.com/ http://loadm.exelator.com/load?_kdpid=e4942ff0-4070-4896-a7ef-e6a5a30ce9f9&buid=Lu5v_RXY&p=204&g=270&j=0 image
-http://www.amazon.de/ https://d.agkn.com/pixel/8198/?che=1516015929&sk=164801402571000793532&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164801402571000793532&ex=neustar.biz other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/b1d3dc1e-5ae9-4e36-a267-6cf3864037bf/scale-to-height-down/500 image
-http://www.amazon.de/ https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/6e6f1df3-1dac-4ee0-a14f-f18a89d8aa37/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/3b511b0e-4fe2-4a92-8530-0adf36f2c01a/scale-to-height-down/500 image
-http://www.amazon.de/ https://tags.bluekai.com/site/2981?id=&google_gid=CAESEP-Vp4Jw1UNAQGE3JWCsryo&google_cver=1 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/12e6a0f2-7996-4822-8038-d48ee5e5c920/scale-to-height-down/500 image
-http://www.amazon.de/ https://token.rubiconproject.com/token?pid=2179&pt=n other
-http://www.wikia.com/ http://loadm.exelator.com/load?_kdpid=e4942ff0-4070-4896-a7ef-e6a5a30ce9f9&buid=Lu5v_RXY&p=204&g=270&j=0&xl8blockcheck=1 image
-http://www.amazon.de/ https://www.facebook.com/fr/r.php?p=558293300959460&e=B-266SXSQ9SAfNsGv-8p_w&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dfbca%26id%3DB-266SXSQ9SAfNsGv-8p_w&s=1516015927&h=SUF3Zm1lV1R5UlVFTzNONQc5LOS-aOBossIGEK0qOFtbUMQx html
-http://www.wikia.com/ https://cm.g.doubleclick.net/pixel?google_cm&google_nid=krux_digital&google_hm=THU1dl9SWFk%3D html
-http://www.amazon.de/ https://geo-um.btrll.com/v1/map_pixel/partner/63.png image
-http://www.amazon.de/ https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=wFi6mfXLQ_eeGvx2Ln4ZCg&twitter_redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dtwca%26id%3DwFi6mfXLQ_eeGvx2Ln4ZCg%26 html
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=fbca&id=B-266SXSQ9SAfNsGv-8p_w image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/b84ecbac-18c4-405d-8fec-022dc4414857/scale-to-height-down/500 image
-http://www.amazon.de/ https://geo-um.btrll.com/v1/map_pixel/partner/63.png?set_aps=1&BR_APS=3WlyRO3sNY20BtVPqLw& image
-http://www.wikia.com/ https://px.surveywall-api.survata.com/k image
-http://www.amazon.de/ https://ads.yahoo.com/cms/v1?esig=1~6772d6d12bf5fd5c41ee5ef107d84db09124942a&nwid=10000936839&sigv=1 text
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/ce0e29bb-ca45-4d21-897a-c15d4d1e7cb4/scale-to-height-down/500 image
-http://www.amazon.de/ https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D text
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/4b541488-dc6f-450d-a526-fdb22bc1a4c1/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?p_user_id=wFi6mfXLQ_eeGvx2Ln4ZCg&ex=twca&id=wFi6mfXLQ_eeGvx2Ln4ZCg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/d9dce907-fe50-482a-bdda-25e2497ed350/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=3WlyRO3sNY20BtVPqLw&ex=brightroll.com&n=1516015932& image
-http://www.wikia.com/ https://beacon.krxd.net/usermatch.gif?google_gid=&google_gid=CAESELcS-S70F-g1JMCOQcVk5HY&google_cver=1 image
-http://www.amazon.de/ https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/776d9735-7d91-4ad3-b6cd-4f1a4b497534/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=rightmedia.com&xid=E0 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/AustinBundle-Mobile_billboard-a-de-1242x450._SX1242_CB507116531_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/7c3eba96-ea8d-42e4-b8f3-eab8d4cb398a/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=aolvideo.com&id=507fad746a6da464772a8d6027179a45e1ce96c5 image
-http://www.wikia.com/ https://beacon.krxd.net/usermatch.gif?partner=survata&partner_uid=cb748a72-ed77-708f-8698-0c1a95c3269f image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51PNBCEcjbL._AC_SY240_.jpg image
-http://www.wikia.com/ http://ib.adnxs.com/pxj?bidder=140&seg=381342&action=setuid(%27Lu5v_RXY%27)&bust=1516016160 html
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=4C6F8BA4-3618-4384-A3CA-142387D6E30E&ex=pubmatic.com image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/9d087602-09c1-4cd9-a72e-0ed0fc27e8f8/scale-to-height-down/500 image
-http://www.amazon.de/ https://s.amazon-adsystem.com/ecm3?id=164801402571000793532&ex=neustar.biz image
-http://www.amazon.de/ https://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/1aea2d1a-40b4-404e-a9ca-1732e5ba6166/scale-to-height-down/500 image
-http://www.amazon.de/ https://sync.ipredictive.com/d/sync/cookie/generic?https://aax-eu.amazon-adsystem.com/s/ecm3?id=${ADELPHIC_CUID}&ex=adelphic other
-http://www.wikia.com/ http://load77.exelator.com/pixel.gif image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/a56413d1-c5be-455d-a515-2f05f846e67e/scale-to-height-down/500 image
-http://www.amazon.de/ https://dpm.demdex.net/ibs:dpid=139200&dpuuid=VonSkRBUTU-H-PoMSz_xDg&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D other
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/3d05f2af-6f7c-44c2-9a65-bd2ca7db4282/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51BOlFkokpL._AC_SY240_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/78b2fede-2d71-4979-9e2a-affe1d621846/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/I/51u3OcL22oL._AC_SY240_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/4ba2ab13-838c-4ec1-9c7f-e03b1d41b114/scale-to-height-down/500 image
-http://www.amazon.de/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=VonSkRBUTU-H-PoMSz_xDg&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/b821eb3f-cb69-45dd-8d53-39664e39ac90/scale-to-height-down/500 image
-http://www.wikia.com/ https://e.visualdna.com/conversion?api_key=krux&id=sync&_kdpid=8f95f20d-4acf-43fc-9832-3f5174a166cc&partner_user_id=Lu5v_RXY&bust=1516016169972 other
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=bb25d5fa-f9e7-11e7-b629-497c7b508413&ex=adelphic image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/efdb442c-65f3-48db-8dd3-f22dc9fdb6f4/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/de-certifiedrefurbished/2017/Public-Launch/1076789_de_certified_refurbished_renewed_11-10-2017_GW_MobileBillboard_1242x450._SX1242_CB512923933_.jpg image
-http://www.wikia.com/ http://pixel.mathtag.com/sync/img?redir=http:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dmediamath%26mmuuid%3D%5BMM_UUID%5D image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/kindle/merch/accessories/2017/Promo/EssentialsBundle/EinkBundle-Mobile_billboard-a-de-1242x450._SX1242_CB529985201_.jpg image
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/8e88fe14-2bfa-44e8-abe3-c9e319951c53/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/d3a31dde-1d86-4782-b666-58fc65dfd0dd/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/81c57e8b-ff2f-4650-9f24-f366cc7033ce/scale-to-height-down/500 image
-http://www.amazon.de/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=adobe.com&id=55307014426663492522732456399940699340 image
-http://www.wikia.com/ https://e.visualdna.com/conversion?partner_user_id=Lu5v_RXY&bust=1516016169972&id=sync&_kdpid=8f95f20d-4acf-43fc-9832-3f5174a166cc&api_key=krux&do_not_cookie=1 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/824c05c1-a4f7-4e0d-aecc-e5e66c5f50ff/scale-to-height-down/500 image
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/DE-digital-music/hawkfire/Family/DE_HF_FamilyPlan_GW_MobileBillboard_870x510_family._SX870_CB523544627_.jpg image
-http://www.wikia.com/ http://tags.bluekai.com/site/26357?id=Lu5v_RXY&redir=http://beacon.krxd.net/usermatch.gif?_kuid%3DLu5v_RXY%26partner%3Dbluekai%26bk_uuid%3D%24_BK_UUID other
-http://www.amazon.de/ https://fls-eu.amazon.de/1/batch/1/OE/ other
-http://www.amazon.de/ https://images-eu.ssl-images-amazon.com/images/G/03/AMAZON-FASHION/2018/FASHION/FLIP/01_JANUARY/MERCH/WOMENS_COLD_WEATHER/GATEWAY_MOBILE_CATEGORY_CARD_1050X1050._CB490789045_.jpg image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/513af095-81b8-4686-ac31-b6ef571129f9/scale-to-height-down/500 image
-http://www.wikia.com/ http://pixel.mathtag.com/sync/img?redir=http:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dmediamath%26mmuuid%3D%5BMM_UUID%5D&mm_bnc&mm_bct image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/a7bc6e46-014f-406d-8f09-616074891774/scale-to-height-down/500 image
-http://www.wikia.com/ https://vignette.wikia.nocookie.net/20938242-5d44-4b6c-b556-0d8338b02764/scale-to-height-down/500 image
-http://www.wikia.com/ http://b.scorecardresearch.com/p?c1=9&c2=8188709&cs_xi=Lu5v_RXY&rn=1516016160 image
-http://www.wikia.com/ http://beacon.krxd.net/optout_check?callback=Krux.ns._default.kxjsonp_optOutCheck script
-http://www.google.co.id/ http://www.google.co.id/ html
-http://www.wikia.com/ http://cdn.krxd.net/userdata/get?pub=44c1a380-770f-11df-93f2-0800200c9a66&technographics=1&callback=Krux.ns._default.kxjsonp_userdata script
-http://www.google.co.id/ https://www.google.co.id/?gws_rd=ssl html
-http://www.wikia.com/ http://tags.bluekai.com/site/26358?dt=0&r=1539248098&sig=750066657&bkca=KJpnEncNvED+iyIviaxguAlJnnnBvYAoLBnUE6oBE1fw6XLr3AMH06L+6uX+EilvEuhJp+Onp60pMXXrpDhHBUSObPDN1i+/nYgJu06YYiqkkvjZJtRYhjv0T6LCYkVBEmv5FmBexpN59W/XJ86= other
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=gwjn34gwjnh86&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3Dd7158cb7-a851-4e3c-b7ab-cc9e815b2399%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.google.co.id/ https://www.google.co.id/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?partner=mediamath&mmuuid=0c345a5c-8cb5-4900-bfff-6bf1926b3e00 image
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=iefs40iefsj26&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D8da8b14d-5569-4bec-bcea-722864ee8d06%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.google.co.id/ https://www.google.co.id/images/nav_logo242_hr.webp image
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?_kuid=Lu5v_RXY&partner=bluekai&bk_uuid=ofghmERR99eq2ahS image
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=iyzu39iyzud95&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3Dbef9f122-393d-4c45-8d8d-32d8be7ac433%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=gwjn34gwjnh86&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3Dd7158cb7-a851-4e3c-b7ab-cc9e815b2399%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.wikia.com/ http://ads.yahoo.com/v0/get-user-id?user_id=Lu5v_RXY&provider_id=654689&callback=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif&type=redirect&TTL=1516017060&sigver=0&sig=beee01c49b261108fb3a8ef2a84580592dd4e2de script
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=bckw15bckwu20&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D8bf57916-aac8-4f01-a386-4baf103b3e1f%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.google.co.id/ https://www.google.co.id/gen_204?s=webaft&atyp=csi&ei=IpFcWvicF8PCjwO1t5HQDw&rt=wsrt.2038,aft.202,prt.202 html
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=iefs40iefsj26&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D8da8b14d-5569-4bec-bcea-722864ee8d06%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.google.co.id/ https://www.google.co.id/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/rt=j/d=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=2dd640a6-6ebd-4d4f-af30-af8baa441a0d&dlxid=&dlxdata= image
-http://www.google.co.id/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=iefs40iefsj26&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D536f0daa-aaaa-4d9e-9a25-dde40646786a%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.google.co.id/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=d7158cb7-a851-4e3c-b7ab-cc9e815b2399&dlxid=&dlxdata= image
-http://www.google.co.id/ https://www.google.co.id/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw?xjs=s1 script
-http://www.google.co.id/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=iyzu39iyzud95&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3Dbef9f122-393d-4c45-8d8d-32d8be7ac433%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.google.co.id/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.google.co.id/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.google.co.id/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.co.id/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.google.co.id/ https://www.google.co.id/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.wikia.com/ http://secure-us.imrworldwide.com/cgi-bin/m?ci=ent599834&c1=kxkuid,Lu5v_RXY image
-http://www.google.co.id/ https://www.google.co.id/images/nav_logo242.png image
-http://www.wikia.com/ http://aa.agkn.com/adscores/g.js?sid=9212244187&_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e script
-http://www.google.co.id/ https://www.google.co.id/gen_204?atyp=csi&ei=IpFcWvicF8PCjwO1t5HQDw&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.635,dcl.365,iml.635,ol.2292,prt.201,xjs.1468,xjsee.1468,xjses.1192,xjsls.213,wsrt.2038,cst.630,dnst.0,rqst.780,rspt.427,sslt.332,rqstt.1559,unt.925,cstt.926,dit.2403&zx=1516015909000 html
-http://www.wikia.com/ http://pix.btrll.com/partner/868092.png image
-http://www.google.co.id/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=bckw15bckwu20&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D8bf57916-aac8-4f01-a386-4baf103b3e1f%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.google.co.id/ https://www.google.co.id/images/branding/product/1x/gsa_android_144dp.png image
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=rowp70rowpu60&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D7c6392c9-e878-492c-8b14-bf06e3828ebd%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.google.co.id/ https://adservice.google.co.id/adsid/google/ui html
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=8da8b14d-5569-4bec-bcea-722864ee8d06&dlxid=&dlxdata= image
-http://www.wikia.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=rsxs71rsxsk73&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3Dbb8ae0e2-9cd7-45b2-ad37-7737269627d8%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=iefs40iefsj26&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D536f0daa-aaaa-4d9e-9a25-dde40646786a%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=bef9f122-393d-4c45-8d8d-32d8be7ac433&dlxid=&dlxdata= image
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=8bf57916-aac8-4f01-a386-4baf103b3e1f&dlxid=&dlxdata= image
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=rowp70rowpu60&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3D7c6392c9-e878-492c-8b14-bf06e3828ebd%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.wikia.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=rsxs71rsxsk73&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5v_RXY%26_kdpid%3Dbb8ae0e2-9cd7-45b2-ad37-7737269627d8%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=536f0daa-aaaa-4d9e-9a25-dde40646786a&dlxid=&dlxdata= image
-http://www.wikia.com/ http://imasdk.googleapis.com/js/sdkloader/ima3.js script
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?user_id=Lu5v_RXY&provider_id=654689&expiration=1517225776&TTL=1516016236&sigver=0&sig=12f746a372106b13caa6fe2b7ef834c5e534448d image
-http://www.wikia.com/ http://srv-2018-01-15-11.pixel.parsely.com/plogger/?rand=1516016167994&idsite=fandom.wikia.com&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&urlref=&screen=360x512%7C360x512%7C24&data=%7B%22parsely_uuid%22%3A%22b7a93f4f-6423-4b8e-a544-8d2f27412559%22%2C%22parsely_site_uuid%22%3A%22c9a6be7f-a01f-4df2-b541-75913b8f651e%22%7D&sid=1&surl=http%3A%2F%2Fwww.wikia.com%2Ffandom&sref=&sts=1516016157480&slts=0&date=Mon+Jan+15+2018+11%3A36%3A07+GMT%2B0000+(UTC)&action=heartbeat&inc=5 image
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=7c6392c9-e878-492c-8b14-bf06e3828ebd&dlxid=&dlxdata= image
-http://www.wikia.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjss1s-pQlpN-NOP9IC3njFCBiTFWYOX-JrzUQ_ocbMQv8JKM7Yb3RFXtyelzohu4BgMUwhG6w8lehp1pNllv2mkAjJG2E4mWQyQ&sig=Cg0ArKJSzIDdeGDBFKRxEAE&id=osdim&ti=1&adk=3854150723&tt=6022&bs=360,512&mtos=1052,1052,1052,1052,1052&tos=1052,0,0,0,0&p=0,0,203,360&inapp=0&mcvt=1052&rs=3&ht=0&tfs=4968&tls=6020&mc=1&lte=1&bas=0&bac=0&bos=360,512&ps=360,53899&ss=360,512&pt=-1&deb=1-0-2-18-5--1&tvt=1056&op=1&avms=geo&r=v&uc=4&tgt=BODY&cl=1&cec=13&clc=0&cac=0360x203&v=r20180108 image
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5v_RXY&_kdpid=bb8ae0e2-9cd7-45b2-ad37-7737269627d8&dlxid=&dlxdata= image
-http://www.wikia.com/ http://d.agkn.com/pixel/5500/?age=&gender=&st=&sk=&pd=&cbr=&mip=&dm=&py=&l0=http://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key= other
-http://www.wikia.com/ http://geo-um.btrll.com/v1/map_pixel/partner/48.png image
-http://www.wikia.com/ http://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key= image
-http://www.wikia.com/ http://geo-um.btrll.com/v1/map_pixel/partner/48.png?set_aps=1&BR_APS=3WlySMWUI_F8B1hGhuQ& image
-http://www.wikia.com/ http://beacon.krxd.net/usermatch.gif?partner=brightroll&partner_uid=3WlySMWUI_F8B1hGhuQ&n=1516016177& image
-http://www.wikia.com/ http://imasdk.googleapis.com/js/core/bridge3.188.1_en.html html
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016178562&content_type=%28none%29&country=US&creative_id=0&dev=false&dev_cat=mobile&event_name=ready&event_ts=1516016178&f=Home&lc=en&line_item_id=0&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016178562&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ https://s0.2mdn.net/instream/video/client.js script
-http://www.wikia.com/ http://pagead2.googlesyndication.com/pagead/gen_204?request_type=xfp&lid=6&sdkv=h.3.188.1&e=651800003&id=ima_html5&c=2248496551511603&domain=www.wikia.com html
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/favicons/favicon-32x32.png?v=44a83b36a3c1c4885806fc5a37794457d427659b image
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/favicons/favicon-16x16.png?v=44a83b36a3c1c4885806fc5a37794457d427659b image
-http://www.wikia.com/ https://static.wikia.nocookie.net/qube-assets/f2/2321/favicons/favicon.ico?v=44a83b36a3c1c4885806fc5a37794457d427659b image
-http://www.wikia.com/ http://pagead2.googlesyndication.com/pagead/gen_204?rt=xfp&lid=17&sdkv=h.3.188.1&e=651800003&id=ima_html5&c=2248496551511603&domain=www.wikia.com html
-http://www.wikia.com/ https://js-agent.newrelic.com/nr-1044.min.js script
-http://www.wikia.com/ https://pubads.g.doubleclick.net/gampad/ads?output=xml_vast3&env=vp&gdfp_req=1&unviewed_position_start=1&sz=640x480&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&description_url=http%3A%2F%2Fwww.wikia.com%2Ffandom&correlator=4465271554386790&iu=%2F5441%2Fwka.fandom%2F_fandom%2F%2Fhome%2Fns%2FTOP_LEADERBOARD&cust_params=host%3Dwww.wikia.com%26ksg%3D%26lang%3Den%26outstream%3Dnone%26post_id%3D-1%26skin%3Dfandom_mobile%26vertical%3Dhome%26wsi%3Ddlh1%26loc%3Dtop%26uap%3D4538836048%26src%3Dns%26pos%3DTOP_LEADERBOARD%26passback%3Dabcd&eid=651800003&sdkv=h.3.188.1&sdki=3c0d&scor=2477749413621081&adk=2751079464&u_so=l&osd=2&frm=0&sdr=1&is_amp=0&ged=ve4_td37_tt1_pd37_la37000_er0.0.0.0_vi0.0.512.360_vp0_eb16491 xml
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016181360&content_type=%28none%29&country=US&creative_id=0&dev=false&dev_cat=mobile&event_name=play_triggered&event_ts=1516016181&f=Home&lc=en&line_item_id=0&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016181355&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016181450&content_type=video%2Fmp4&country=US&creative_id=138219370518&dev=false&dev_cat=mobile&event_name=loaded&event_ts=1516016181&f=Home&lc=en&line_item_id=4538837971&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016181448&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ http://pagead2.googlesyndication.com/pagead/gen_204?feature=titleBarDiv&lid=58&sdkv=h.3.188.1&e=651800003&id=ima_html5&c=2248496551511603&domain=www.wikia.com html
-http://www.wikia.com/ http://pagead2.googlesyndication.com/pagead/gen_204?feature=learnMoreButtonDiv&lid=58&sdkv=h.3.188.1&e=651800003&id=ima_html5&c=2248496551511603&domain=www.wikia.com html
-http://www.wikia.com/ https://pubads.g.doubleclick.net/pagead/conversion/?ai=BbqG1NZJcWrOoCNDziQPOs5rABO2tnpRFAAAAEAEgnOnGIDgAWJbwkPSCBGDJBrIBDXd3dy53aWtpYS5jb226AQs2NDB4NDgwX3htbMgBBdoBG2h0dHA6Ly93d3cud2lraWEuY29tL2ZhbmRvbcACAuACAOoCMS81NDQxL3drYS5mYW5kb20vX2ZhbmRvbS8vaG9tZS9ucy9UT1BfTEVBREVSQk9BUkT4AvzRHoADAZADpAOYA6QDqAMB4AQB0gUGENPXpPQQkAYBoAYj2AYC2AcB4AcP0ggHCIBhEAEYAQ&sigh=VGwiRQHOiZQ&label=admute&ad_mt=0&acvw=sv%3D644%26cb%3Dj%26e%3D10%26nas%3D1%26sdk%3Dh%26p%3D0,0,0,0%26tos%3D0,0,0,0,0%26mtos%3D0,0,0,0,0%26mcvt%3D0%26ps%3D-12245933,-12245933%26scs%3D360,512%26bs%3D-12245933,-12245933%26pt%26vht%3D0%26mut%3D0%26ft%3D0%26at%3D0%26as%3D0%26vpt%3D0%26gmm%3D4%26efpf%3D2%26nmt%3D0%26tcm%3D0%26bt%3D0%26pst%3D-1%26dur%3D-1%26vmtime%3D0%26is%3D0%26cs%3D4096%26c%3D0%26mc%3D-1%26nc%3D-1%26mv%3D-1%26nv%3D-1%26lte%3D-2%26ces%26femt%3D2038%26femvt%3D0%26emc%3D1%26emuc%3D0%26emb%3D0,0,0,0,0%26avms%3Dexc%26qi%3D31202911%26psm%3D0%26psv%3D0%26psfv%3D0%26psa%3D0%26pngs%3D9,14,15&gv=atos%3D0,0,0,0,0%26amtos%3D0,0,0,0,0%26avt%3D0%26ss%3D0%26t%3D1516016181539&sdkv=h.3.188.1 image
-http://www.wikia.com/ https://csi.gstatic.com/csi?v=2&s=ima&puid=1~jcg4w2ot&c=1285096634257&e=509445014%2C667080008&sdkv=h.3.188.1&slotId=1081237668&gqid=NZJcWo70B8fviQOW44P4Bg&qqid=CPOWza_w2dgCFdB5YgodzpkGSA&met.4=ar.uj~vl.264 image
-http://www.wikia.com/ https://bam.nr-data.net/1/60e97494a4?a=43882980&sa=1&v=1044.a6554e7&t=Unnamed%20Transaction&rst=38102&ref=http://www.wikia.com/fandom&be=3679&fe=36793&dc=5478&af=err,xhr,stn,ins&perf=%7B%22timing%22:%7B%22of%22:1516016143040,%22n%22:0,%22r%22:87,%22re%22:921,%22f%22:921,%22dn%22:921,%22dne%22:921,%22c%22:921,%22ce%22:921,%22rq%22:923,%22rp%22:1230,%22rpe%22:1704,%22dl%22:1233,%22di%22:4621,%22ds%22:5475,%22de%22:5478,%22dc%22:36770,%22l%22:36792,%22le%22:36812%7D,%22navigation%22:%7B%22rc%22:1%7D%7D&jsonp=NREUM.setToken script
-http://www.wikia.com/ https://redirector.gvt1.com/videoplayback/id/83a6281754e710e8/itag/18/source/gfp_video_ads/requiressl/yes/acao/yes/mime/video%2Fmp4/ip/0.0.0.0/ipbits/0/expire/1516037781/sparams/ip,ipbits,expire,id,itag,source,requiressl,acao,mime/signature/9BD2CCE40A3AEAEA61A652C29A674B8622B5ADF2.A72C47DD12C397B361CDCF82932836BB053A0AD9/key/ck2/file/file.mp4 video
-http://www.wikia.com/ https://r1---sn-nx57ynee.gvt1.com/videoplayback/id/83a6281754e710e8/itag/18/source/gfp_video_ads/requiressl/yes/acao/yes/mime/video%2Fmp4/ip/0.0.0.0/ipbits/0/expire/1516037781/sparams/acao,expire,id,ip,ipbits,itag,mime,mip,mm,mn,ms,mv,pl,requiressl,source/signature/8274E9DBEF8E0E76BAF493A06CA15E65838E7A2E.788D47A359138942F65540B3E9C469380BDB9382/key/cms1/cms_redirect/yes/mip/35.203.176.73/mm/28/mn/sn-nx57ynee/ms/nvh/mt/1516015714/mv/u/pl/20/file/file.mp4 video
-http://www.wikia.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsuDkapG6xFKIGKZgc_cmfE0TeM4bzjQDpcJBuK2djEeDb45BVA5_0yuhMygD7gwsKJxM7STBJeiBCZtLOlGmb5OedN7F3x1LigUbxaq9zhW-a3KIfB1Ud8uAwUbnGTgrd4nyjfVj90WDbg7gvqMcxENQyPfacVtwGbdYqWv9x-Yt74iauaFQA7yzUDGK1g3erkj5mMNa0QN8Db7b5Q-wKpKRU2Z82oReBv3M3oFNphqQh0S05k3Kkj8B8SYD9PKL8SfJHBZnxr6_Tg3Rg6sDE0zu80QwQT4VA&sig=Cg0ArKJSzBTfUS3wespBEAE&sdkv=h.3.188.1&adurl= html
-http://www.wikia.com/ https://pubads.g.doubleclick.net/pagead/conversion/?ai=BbqG1NZJcWrOoCNDziQPOs5rABO2tnpRFAAAAEAEgnOnGIDgAWJbwkPSCBGDJBrIBDXd3dy53aWtpYS5jb226AQs2NDB4NDgwX3htbMgBBdoBG2h0dHA6Ly93d3cud2lraWEuY29tL2ZhbmRvbcACAuACAOoCMS81NDQxL3drYS5mYW5kb20vX2ZhbmRvbS8vaG9tZS9ucy9UT1BfTEVBREVSQk9BUkT4AvzRHoADAZADpAOYA6QDqAMB4AQB0gUGENPXpPQQkAYBoAYj2AYC2AcB4AcP0ggHCIBhEAEYAQ&sigh=VGwiRQHOiZQ&label=admute&ad_mt=0&acvw=sv%3D644%26cb%3Dj%26e%3D10%26nas%3D1%26sdk%3Dh%26p%3D0,0,0,0%26tos%3D0,0,0,0,0%26mtos%3D0,0,0,0,0%26mcvt%3D0%26ps%3D360,53899%26scs%3D360,512%26bs%3D360,512%26pt%3D0%26vht%3D0%26mut%3D0%26a%3D0%26ft%3D0%26at%3D0%26as%3D0%26vpt%3D24%26gmm%3D4%26efpf%3D2%26nmt%3D0%26tcm%3D0%26bt%3D24%26pst%3D-1%26dur%3D43119%26vmtime%3D0%26is%3D146%26cs%3D4242%26c%3D0%26mc%3D0%26nc%3D0%26mv%3D0%26nv%3D0%26lte%3D-1%26ces%26femt%3D2038%26femvt%3D0%26emc%3D18%26emuc%3D0%26emb%3D0,0,0,0,0%26avms%3Dexc%26qi%3D31202911%26psm%3D1%26psv%3D0%26psfv%3D0%26psa%3D0%26pngs%3D9,14,15s&gv=atos%3D0,0,0,0,0%26amtos%3D0,0,0,0,0%26avt%3D0%26ss%3D0%26t%3D1516016181539&sdkv=h.3.188.1 image
-http://www.wikia.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjstqh7CzAl9l85xYcqn4R4e_KxhLDhoiCHu4WchrHMnM9UrRg6RbY2pp_-UqYGCqziNRK9I5l-kypHL6rbmCc8gMqU8g3P3FQ_E&sig=Cg0ArKJSzA2UN2bXCq0KEAE&id=lidarv&acvw=sv%3D644%26cb%3Dj%26e%3D15%26nas%3D1%26sdk%3Dh%26p%3D0,0,0,0%26tos%3D0,0,0,0,0%26mtos%3D0,0,0,0,0%26mcvt%3D0%26ps%3D360,53899%26scs%3D360,512%26bs%3D360,512%26pt%26vht%3D0%26mut%3D0%26a%3D0%26ft%3D0%26at%3D0%26as%3D0%26vpt%3D0%26gmm%3D4%26efpf%3D2%26nmt%3D0%26tcm%3D0%26bt%3D0%26pst%3D-1%26dur%3D43119%26vmtime%3D0%26is%3D128%26cs%3D4224%26c%3D0%26mc%3D0%26nc%3D0%26mv%3D0%26nv%3D0%26lte%3D-1%26ces%26femt%3D2038%26femvt%3D0%26emc%3D18%26emuc%3D0%26emb%3D0,0,0,0,0%26avms%3Dexc%26qi%3D31202911%26psm%3D1%26psv%3D0%26psfv%3D0%26psa%3D0%26pngs%3D9,14,15&avm=1 image
-http://www.wikia.com/ http://pagead2.googlesyndication.com/pagead/gen_204?feature=learnMoreButtonDiv&lid=58&sdkv=h.3.188.1&e=651800003&id=ima_html5&c=2248496551511603&domain=www.wikia.com html
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016185118&content_type=video%2Fmp4&country=US&creative_id=138219370518&dev=false&dev_cat=mobile&event_name=ad_can_play&event_ts=1516016185&f=Home&lc=en&line_item_id=4538837971&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016185093&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016185151&content_type=video%2Fmp4&country=US&creative_id=138219370518&dev=false&dev_cat=mobile&event_name=impression&event_ts=1516016185&f=Home&lc=en&line_item_id=4538837971&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016185151&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016185178&content_type=video%2Fmp4&country=US&creative_id=138219370518&dev=false&dev_cat=mobile&event_name=started&event_ts=1516016185&f=Home&lc=en&line_item_id=4538837971&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016185176&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.wikia.com/ https://video-ad-stats.googlesyndication.com/video/client_events?event=2&web_property=ca-pub-2586812665208127&cpn=I-nZiknOUjIOwn45&break_type=1&slot_pos=0&ad_id=4538837971&ad_sys=GDFP&ad_len=43000&p_w=0&p_h=0&mt=0&rwt=1516016180652,1516016181317&wt=1516016185047&sdkv=h.3.188.1&vol=0&content_v=0&conn=0&format=1_2_0 other
-http://www.wikia.com/ https://pubads.g.doubleclick.net/pagead/conversion/?ai=BbqG1NZJcWrOoCNDziQPOs5rABO2tnpRFAAAAEAEgnOnGIDgAWJbwkPSCBGDJBrIBDXd3dy53aWtpYS5jb226AQs2NDB4NDgwX3htbMgBBdoBG2h0dHA6Ly93d3cud2lraWEuY29tL2ZhbmRvbcACAuACAOoCMS81NDQxL3drYS5mYW5kb20vX2ZhbmRvbS8vaG9tZS9ucy9UT1BfTEVBREVSQk9BUkT4AvzRHoADAZADpAOYA6QDqAMB4AQB0gUGENPXpPQQkAYBoAYj2AYC2AcB4AcP0ggHCIBhEAEYAQ&sigh=VGwiRQHOiZQ&label=viewable_impression&acvw=sv%3D644%26cb%3Dj%26e%3D9%26nas%3D1%26sdk%3Dh%26p%3D0,0,203,360%26tos%3D2080,0,0,0,0%26mtos%3D2080,2080,2080,2080,2080%26mcvt%3D2080%26ps%3D360,53899%26scs%3D360,512%26bs%3D360,512%26pt%3D0%26vht%3D0%26mut%3D0%26a%3D0%26ft%3D0%26dft%3D0%26at%3D0%26dat%3D0%26as%3D0%26vpt%3D2332%26gmm%3D4%26efpf%3D2%26nmt%3D0%26tcm%3D0%26bt%3D370%26pst%3D785%26dur%3D43119%26vmtime%3D1981%26dtos%3D2080%26dtoss%3D1%26dvs%3D2080%26dfvs%3D2080%26dvpt%3D2332%26is%3D403%26ic%3D16781715%26cs%3D16781715%26c%3D1%26mc%3D1%26nc%3D0%26mv%3D0%26nv%3D0%26lte%3D-1%26ces%26femt%3D2038%26femvt%3D0%26emc%3D28%26emuc%3D0%26emb%3D10,0,0,0,0%26avms%3Dexc%26qi%3D31202911%26psm%3D3%26psv%3D2%26psfv%3D2%26psa%3D0%26pngs%3D9,14,15s&gv=atos%3D0,0,0,0,0%26amtos%3D0,0,0,0,0%26avt%3D0%26davs%3D0%26dafvs%3D0%26dav%3D0%26ss%3D0.39%26t%3D1516016181539&ad_mt=1982&sdkv=h.3.188.1 image
-http://www.wikia.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjstqh7CzAl9l85xYcqn4R4e_KxhLDhoiCHu4WchrHMnM9UrRg6RbY2pp_-UqYGCqziNRK9I5l-kypHL6rbmCc8gMqU8g3P3FQ_E&sig=Cg0ArKJSzA2UN2bXCq0KEAE&id=lidarv&acvw=sv%3D644%26cb%3Dj%26e%3D9%26nas%3D1%26sdk%3Dh%26p%3D0,0,203,360%26tos%3D2080,0,0,0,0%26mtos%3D2080,2080,2080,2080,2080%26mcvt%3D2080%26ps%3D360,53899%26scs%3D360,512%26bs%3D360,512%26pt%3D0%26vht%3D0%26mut%3D0%26a%3D0%26ft%3D0%26dft%3D0%26at%3D0%26dat%3D0%26as%3D0%26vpt%3D2332%26gmm%3D4%26efpf%3D2%26nmt%3D0%26tcm%3D0%26bt%3D370%26pst%3D785%26dur%3D43119%26vmtime%3D1981%26dtos%3D2080%26dtoss%3D1%26dvs%3D2080%26dfvs%3D2080%26dvpt%3D2332%26is%3D403%26ic%3D16781715%26cs%3D16781715%26c%3D1%26mc%3D1%26nc%3D0%26mv%3D0%26nv%3D0%26lte%3D-1%26ces%26femt%3D2038%26femvt%3D0%26emc%3D28%26emuc%3D0%26emb%3D10,0,0,0,0%26avms%3Dexc%26qi%3D31202911%26psm%3D3%26psv%3D2%26psfv%3D2%26psa%3D0%26pngs%3D9,14,15s image
-http://www.wikia.com/ https://beacon.wikia-services.com/__track/special/adengplayerinfo?a=&ad_error_code=0&ad_product=abcd&beacon=EbVBeFSAGG&browser=Android%20Chrome%2058&c=1452001&cb=1516016187406&content_type=video%2Fmp4&country=US&creative_id=138219370518&dev=false&dev_cat=mobile&event_name=viewable_impression&event_ts=1516016187&f=Home&lc=en&line_item_id=4538837971&pg_type=home&player=porvata&position=TOP_LEADERBOARD&pv_number=1&pv_unique_id=16732db3-a022-4641-a494-d3cbf6e711d9&r=direct&r_type=direct&session=4cJ5WHuQIo&site=web&skin=fandom_mobile&t=event&timestamp=1516016187406&ua=Mozilla%2F5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build%2FMPJ24.139-64%29%20AppleWebKit%2F537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&url=http%3A%2F%2Fwww.wikia.com%2Ffandom&wsi=dlh1 script
-http://www.espn.com/ http://www.espn.com/ html
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/css/shell-mobile.css css
-http://www.espn.com/ http://cdn.espn.com/core/format/modules/head/i18n?edition-host=espn.com&lang=en&region=us&site=espn&site-type=full&type=ext&build=0.382.4.1&edition-view=espn-en-us&edition=espn-en-us script
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/css/page.css css
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/css/one-feed-v1.css css
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/js/espn-critical-mobile.js script
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/node_modules/espn-lazysizes/lazysizes.js script
-http://www.espn.com/ http://a.espncdn.com/test/fancyLogo2.svg image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/redesign/assets/img/logos/logo-espnw-26x30.png&h=32&w=32 image
-http://www.espn.com/ http://a1.espncdn.com/fonts/1.0.46/ESPNIcons/ESPNIcons.woff2 font
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=%2Fmedia%2Fmotion%2F2018%2F0114%2Fdm_180114_NFL_Vikings_walk%2Doff_TD_ENHANCED%2Fdm_180114_NFL_Vikings_walk%2Doff_TD_ENHANCED.jpg&w=750&h=422&scale=crop&cquality=40&location=origin image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/espn/networks_shows/500/undefeated_bk.png&h=32&w=32 image
-http://www.espn.com/ http://a.espncdn.com/redesign/assets/img/logos/logo-espn-82x20@2x.png image
-http://www.espn.com/ http://a.espncdn.com/redesign/assets/img/icons/icon-play-arrow.png image
-http://www.espn.com/ http://cdn.optimizely.com/js/310987714.js script
-http://www.espn.com/ http://c.amazon-adsystem.com/aax2/apstag.js script
-http://www.espn.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/js/espn-analytics.js script
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=%2Fphoto%2F2018%2F0114%2Fr314553_1296x864_3%2D2.jpg&w=360&h=240&scale=crop&cquality=40&location=center image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=%2Fphoto%2F2018%2F0114%2Fr314486_1296x864_3%2D2.jpg&w=360&h=240&scale=crop&cquality=40&location=center image
-http://www.espn.com/ http://dpm.demdex.net/id?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_cb=s_c_il%5B0%5D._setMarketingCloudFields other
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nfl.png&w=100&h=100&transparent=true image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=%2Fmedia%2Fmotion%2F2018%2F0114%2Fdm_180114_nfl_saints_marcus_williams_int%2Fdm_180114_nfl_saints_marcus_williams_int.jpg&w=768&h=432&scale=crop&cquality=40&location=origin image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=%2Fmedia%2Fmotion%2F2018%2F0114%2Fdm_180114_nfl_vikings_diggs_ltt%2Fdm_180114_nfl_vikings_diggs_ltt.jpg&w=768&h=432&scale=crop&cquality=40&location=origin image
-http://www.espn.com/ http://a2.espncdn.com/combiner/i?img=%2Fmedia%2Fmotion%2F2018%2F0114%2Fdm_180114_NFL_One%2DPlay_Vikings_Diggs_TD_catch%2Fdm_180114_NFL_One%2DPlay_Vikings_Diggs_TD_catch.jpg&w=768&h=432&scale=crop&cquality=40&location=origin image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=%2Fmedia%2Fmotion%2F2018%2F0115%2Fdm_180115_NFL_Highlight_Diggs_Catch_against_history%2Fdm_180115_NFL_Highlight_Diggs_Catch_against_history.jpg&w=768&h=432&scale=crop&cquality=40&location=origin image
-http://www.espn.com/ http://tredir.espn.com/capmon/GetDE?set=j&param=country&param=countryisocode&param=state&param=metro&param=metrocode&param=postcode&param=offset&param=dst&param=countrycode&param=connection script
-http://www.espn.com/ http://dpm.demdex.net/id/rd?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_cb=s_c_il%5B0%5D._setMarketingCloudFields script
-http://www.espn.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.espn.com/ https://adservice.google.com/adsid/integrator.js?domain=www.espn.com script
-http://www.espn.com/ http://w88.espn.com/id?d_visid_ver=1.5.6&callback=s_c_il%5B0%5D._setAnalyticsFields&mcorgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&mid=58381219692831642431544101446809648234 script
-http://www.espn.com/ https://310987714.log.optimizely.com/event?a=310987714&d=310987714&y=false&src=js&x8483651062=8486311072&s310954789=none&s311043393=true&s311047346=gc&s311052307=direct&s793783561=true&s806111078=none&s806950111=mobile&tsent=1516016025.102&n=http%3A%2F%2Fwww.espn.com%2F&u=oeu1516016024988r0.16674945697640053&wxhr=true&time=1516016025.101&f=8448890495,9262875135,9263073801,8792134866,8483651062&g=8483651062&cx2=9dc2fd9 script
-http://www.espn.com/ http://dpm.demdex.net/id?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_mid=58381219692831642431544101446809648234&d_blob=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&d_cid_ic=AVID%012D2E48CD0503765A-6000118C600A44E0&d_cb=s_c_il%5B0%5D._setAudienceManagerFields script
-http://www.espn.com/ https://logx.optimizely.com/log/event text
-http://www.espn.com/ http://a.espncdn.com/ad/doubleclick/ads.js script
-http://www.espn.com/ http://a.espncdn.com/js/omniture/tracking.js script
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/js/espn-defer-mobile.js script
-http://www.espn.com/ http://a.espncdn.com/redesign/0.382.4/js/espn-defer-low.js script
-http://www.espn.com/ http://a.espncdn.com/favicon.ico image
-http://www.espn.com/ http://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.espn.com/ http://www.espn.com/core/l?a=false&t=false text
-http://www.espn.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=1434687075273294&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fifs&adsid=NT&json_a=1&eid=21061445%2C21060362%2C21061149&sc=0&sfv=1-0-14&iu_parts=6444%2Cespn.com%2Cfrontpage%2Cindex&enc_prev_ius=%2F0%2F1%2F2%2F3%2C%2F0%2F1%2F2%2F3&prev_iu_szs=1x2%2C1x1&ists=1&prev_scp=pos%3Dexclusions%7CslotId%3Dad-slot-overlay-257539%26pos%3Doutofpage&eri=1&cust_params=ed%3Dus%26sp%3Despn%26pgtyp%3Despnfrontpage%26swid%3D6867945A-20A1-4547-C5EE-736FB233194C%26mnr%3Df%26prof%3Ds&cookie_enabled=1&abxe=1&lmt=1516016027&dt=1516016027858&frm=20&biw=360&bih=512&oid=3&adxs=0%2C0&adys=0%2C0&adks=1164329267%2C4097250353&gut=v2&ifi=1&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.espn.com%2F&dssz=31&icsg=32800&std=0&vrg=172&vis=1&ga_vid=265192708.1516016028&ga_sid=1516016028&ga_hid=2071740595 script
-http://www.espn.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_172.js script
-http://www.espn.com/ https://sds.livesegmentservice.com/segments?prop=GM87FR&swid=6867945A-20A1-4547-C5EE-736FB233194C script
-http://www.espn.com/ http://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.espn.com/ http://log.espn.com/log?srvc=sz&a=100&silent=1&goto=https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsuCxQEj1YfJdSSLlW7BALkYb3aXDkQfRZOePRzxAdcqv286tOlUnjPggoCpswrptJKybHFGqzDR1UG5ED5gibbnsJZXJhdFEOQ3JkD_LaQgO-4vJl83fvFlbL6T3MlfldGoRzzxuSnkIBfKB5n4hMl23cOLfgxh8lin2oncP07UVuarUxEXgN_KpyeysDrsoam2MXpW-EH4ejjfB1ymvG6EYfAedxc1IDifHAYoOYKwLqoZoG6B3q0r_2nZncaHJZI&sig=Cg0ArKJSzFZDGWv7CDrfEAE&urlfix=1&adurl=http://a.espncdn.com/ad/blank.gif text
-http://www.espn.com/ https://secure.espncdn.com/ad/doubleclick/hanfordCap.js script
-http://www.espn.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsuCxQEj1YfJdSSLlW7BALkYb3aXDkQfRZOePRzxAdcqv286tOlUnjPggoCpswrptJKybHFGqzDR1UG5ED5gibbnsJZXJhdFEOQ3JkD_LaQgO-4vJl83fvFlbL6T3MlfldGoRzzxuSnkIBfKB5n4hMl23cOLfgxh8lin2oncP07UVuarUxEXgN_KpyeysDrsoam2MXpW-EH4ejjfB1ymvG6EYfAedxc1IDifHAYoOYKwLqoZoG6B3q0r_2nZncaHJZI&sig=Cg0ArKJSzFZDGWv7CDrfEAE&urlfix=1&adurl=http://a.espncdn.com/ad/blank.gif html
-http://www.espn.com/ https://cdn.registerdisney.go.com/v2/outer/DisneyID.js script
-http://www.espn.com/ http://site.api.espn.com/apis/site/v2/sports/basketball/mens-college-basketball/scoreboard/conferences?groups=50&lang=en&region=us&contentorigin=espn&tz=America%2FNew_York script
-http://www.espn.com/ http://site.api.espn.com/apis/site/v2/sports/basketball/womens-college-basketball/scoreboard/conferences?groups=50&lang=en&region=us&contentorigin=espn&tz=America%2FNew_York script
-http://www.espn.com/ http://cdn.espn.com/core/api/v0/nav/index?&device=mobile&country=us&lang=en&region=us&site=espn&edition-host=espn.com&one-site=true&site-type=full script
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/usa.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/chn.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/swi.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/hun.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/rom.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/den.png&h=60&w=60 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/scoreboard/no.png&h=312&w=312 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/scoreboard/min.png&h=312&w=312 image
-http://www.espn.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=1859360482725425&output=json_html&callback=googletag.impl.pubads.callbackProxy2&impl=fifs&adsid=NT&json_a=1&eid=21061445%2C21060362%2C21061149&sc=0&sfv=1-0-14&iu_parts=6444%2Cespn.com%2Cfrontpage%2Cindex&enc_prev_ius=%2F0%2F1%2F2%2F3%2C%2F0%2F1%2F2%2F3&prev_iu_szs=1x2%2C320x50&rcs=1%2C0&prev_scp=pos%3Dexclusions%7Cpos%3Dtop&eri=1&cust_params=ed%3Dus%26sp%3Despn%26pgtyp%3Despnfrontpage%26swid%3D6867945A-20A1-4547-C5EE-736FB233194C%26mnr%3Df%26prof%3Ds&cookie=ID%3Dba5366fc7f4812cd%3AT%3D1516016028%3AS%3DALNI_MaQq4MLdkaVKxjwTS-Jtufrmp1i_Q&cookie_enabled=1&abxe=1&lmt=1516016031&dt=1516016031878&frm=20&biw=360&bih=512&oid=3&adxs=0%2C20&adys=0%2C114&adks=1164329267%2C491800423&gut=v2&ifi=4&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.espn.com%2F&dssz=35&icsg=704675872&std=0&vrg=172&vis=1&ga_vid=265192708.1516016028&ga_sid=1516016028&ga_hid=2071740595 script
-http://www.espn.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsuCxQEj1YfJdSSLlW7BALkYb3aXDkQfRZOePRzxAdcqv286tOlUnjPggoCpswrptJKybHFGqzDR1UG5ED5gibbnsJZXJhdFEOQ3JkD_LaQgO-4vJl83fvFlbL6T3MlfldGoRzzxuSnkIBfKB5n4hMl23cOLfgxh8lin2oncP07UVuarUxEXgN_KpyeysDrsoam2MXpW-EH4ejjfB1ymvG6EYfAedxc1IDifHAYoOYKwLqoZoG6B3q0r_2nZncaHJZI&sig=Cg0ArKJSzFZDGWv7CDrfEAE&urlfix=1&adurl=https://secure.espncdn.com/ad/blank.gif html
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/aus.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/bul.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/aut.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/jpn.png&h=60&w=60 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/scoreboard/jax.png&h=312&w=312 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nfl/500/scoreboard/pit.png&h=312&w=312 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/spa.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/dom.png&h=60&w=60 image
-http://www.espn.com/ http://a.espncdn.com/ad/blank.gif image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/countries/500/bra.png&h=60&w=60 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nba/500/scoreboard/no.png&h=312&w=312 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/nba/500/scoreboard/ny.png&h=312&w=312 image
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/soccer/500/364.png&h=312&w=312 image
-http://www.espn.com/ https://secure.espncdn.com/ad/blank.gif image
-http://www.espn.com/ https://platform.twitter.com/widgets.js script
-http://www.espn.com/ http://a1.espncdn.com/combiner/i?img=/i/teamlogos/soccer/500/382.png&h=312&w=312 image
-http://www.espn.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjsvXmCYXBTXIZdR108RRRGodqt-Ma9ZyiwMB9kVw-ZR_D-sabTDDahmN7WHKIETTw6Uj-fGnSg1keNpS-bseE_wuJ5g2YryBXs7P481MAAofd3ci-6hCXCl0hYfjH-UuCJTwXNd8uvi_qgzWvpzz73tr9l-fbLvx2x_GUoxotl4YCtNEklNJaVtyQ4eDTb05CD45ZB2LvMisomBDkz5IRfYOkz29jaV9OkzSlt2CEBKwwEHpRseZEPx6GZRrQGtdEsr1w6GqZ2nX&sig=Cg0ArKJSzFsBVcim15uDEAE&urlfix=1&adurl= html
-http://www.espn.com/ https://secure.espncdn.com/ad/doubleclick/blank.gif image
-http://www.espn.com/ http://static.chartbeat.com/js/chartbeat_video.js script
-http://www.espn.com/ https://cdn.registerdisney.go.com/v2/ESPN-ESPNCOM-PROD/en-US?include=config,l10n,js,html&scheme=http&postMessageOrigin=http%3A%2F%2Fwww.espn.com%2F&cookieDomain=www.espn.com&config=PROD&logLevel=INFO&topHost=www.espn.com&cssOverride=https%3A%2F%2Fsecure.espncdn.com%2Fcombiner%2Fc%3Fcss%3Ddisneyid%2Fcore.css&responderPage=https%3A%2F%2Fwww.espn.com%2Flogin%2Fresponder%2Findex.html&buildId=160c87eee28 html
-http://www.espn.com/ http://cdn-gl.imrworldwide.com/novms/js/2/ggcmb510.js script
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nfl.png?w=110&h=110&transparent=true&h=240&w=240 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nba.png?w=110&h=110&transparent=true&h=240&w=240 image
-http://www.espn.com/ http://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js script
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-soccer.png&h=240&w=240&scale=crop&cquality=40 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/mlb.png?w=110&h=110&transparent=true&h=240&w=240 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/redesign/assets/img/icons/ESPN-icon-football-college.png&h=240&w=240&scale=crop&cquality=40 image
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/teamlogos/leagues/500/nhl.png?w=110&h=110&transparent=true&h=240&w=240 image
-http://www.espn.com/ http://aglobal.go.com/stat/cto-espn.js script
-http://www.espn.com/ https://tpc.googlesyndication.com/pagead/imgad?id=CICAgKDr6dq-rQEQARgBMghka4JuXreZig image
-http://www.espn.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener.js script
-http://www.espn.com/ https://platform.twitter.com/widgets/widget_iframe.9c00c8ca14a8618c4db8e2c43139b138.html?origin=http%3A%2F%2Fwww.espn.com html
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/mobile/website/img/espn_app_72@2x.png&w=240&h=240&transparent=true image
-http://www.espn.com/ http://cdn-gl.imrworldwide.com/novms/js/2/configs/glcfg510.js script
-http://www.espn.com/ http://a.espncdn.com/combiner/i?img=/i/mobile/website/img/flm-onehouse-apptile-180.png&w=240&h=240&transparent=true image
-http://www.espn.com/ https://z.moatads.com/espndfp832188684382/moatad.js script
-http://www.espn.com/ https://pixel.adsafeprotected.com/rjss/st/132147/21327473/skeleton.js script
-http://www.espn.com/ https://api.b2c.com/api/init-286421vngpqvy336hdu.js script
-http://www.espn.com/ https://sb.voicefive.com/c2/26060552/rs.js script
-http://www.espn.com/ http://cdn-gl.imrworldwide.com/conf/P07264C85-15CD-4A80-8E56-B5BFA6D93296.js script
-http://www.espn.com/ https://ad.doubleclick.net/ddm/trackimp/N137202.153321ESPN/B20606709.212225207;dc_trk_aid=411056983;dc_trk_cid=94282474;ord=361808391;dc_lat=;dc_rdid=;tag_for_child_directed_treatment= image
-http://www.espn.com/ https://www.espn.com/login/responder/index.html?clientId=ESPN-ESPNCOM-PROD&scheme=http&postMessageOrigin=http%3A%2F%2Fwww.espn.com%2F&cookieDomain=www.espn.com&config=PROD&logLevel=INFO&topHost=www.espn.com&langPref=en-US&cssOverride=https%3A%2F%2Fsecure.espncdn.com%2Fcombiner%2Fc%3Fcss%3Ddisneyid%2Fcore.css&responderPage=https%3A%2F%2Fwww.espn.com%2Flogin%2Fresponder%2Findex.html&buildId=160c87eee28 html
-http://www.espn.com/ http://cdn-gl.imrworldwide.com/novms/js/2/nlsSDK600.bundle.min.js script
-http://www.espn.com/ http://api.mixpanel.com/decide/?verbose=1&version=1&lib=web&token=6b347c39f0f57067a36acc6aa600a094&ip=1&_=1516016034658 script
-http://www.espn.com/ http://api.mixpanel.com/track/?data=eyJldmVudCI6ICJtcF9wYWdlX3ZpZXciLCJwcm9wZXJ0aWVzIjogeyIkb3MiOiAiQW5kcm9pZCIsIiRicm93c2VyIjogIkNocm9tZSIsIiRkZXZpY2UiOiAiQW5kcm9pZCIsIiRjdXJyZW50X3VybCI6ICJodHRwOi8vd3d3LmVzcG4uY29tLyIsIiRicm93c2VyX3ZlcnNpb24iOiA1OCwiJHNjcmVlbl9oZWlnaHQiOiA1MTIsIiRzY3JlZW5fd2lkdGgiOiAzNjAsIm1wX2xpYiI6ICJ3ZWIiLCIkbGliX3ZlcnNpb24iOiAiMi4xNC4wIiwiZGlzdGluY3RfaWQiOiAiMTYwZjk5OGUzNWEzOC0wYzAyYzA1NTM2MDc4Ni1mNjM2MTdiLTJkMDAwLTE2MGY5OThlMzViYmFhIiwiJGluaXRpYWxfcmVmZXJyZXIiOiAiJGRpcmVjdCIsIiRpbml0aWFsX3JlZmVycmluZ19kb21haW4iOiAiJGRpcmVjdCIsIm1wX3BhZ2UiOiAiaHR0cDovL3d3dy5lc3BuLmNvbS8iLCJtcF9icm93c2VyIjogIkNocm9tZSIsIm1wX3BsYXRmb3JtIjogIkFuZHJvaWQiLCJ0b2tlbiI6ICI2YjM0N2MzOWYwZjU3MDY3YTM2YWNjNmFhNjAwYTA5NCJ9fQ%3D%3D&ip=1&_=1516016034678 script
-http://www.espn.com/ http://pespn.chartbeat.net/ping?h=espn.com&p=%2F&u=DQIzj0mbykqCt6FBR&d=espn.com&g=22222&g0=frontpage&g1=index&n=1&f=00001&c=0&x=1&m=1&y=7626&o=360&w=512&j=45&R=1&W=0&I=0&E=0&e=0&r=&b=6841&t=NLb4eC3vUWeHJuBbCBKCk0DxFQAT&V=97&i=ESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&tz=0&sn=1&EE=0&sv=e3kLXCUXTGyC4fjiDM5Vb2Dqu5Ny&_ image
-http://www.espn.com/ https://secure.insightexpressai.com/adServer/adServerESI.aspx?script=false&bannerID=2259269&rnd=361808391&redir=https://secure.insightexpressai.com/adserver/1pixel.gif image
-http://www.txxx.com/ http://www.txxx.com/ other
-http://www.espn.com/ https://syndication.twitter.com/i/jot html
-http://www.espn.com/ https://syndication.twitter.com/settings script
-http://www.txxx.com/ https://www.txxx.com/ html
-http://www.txxx.com/ https://m.txxx.com/ html
-http://www.espn.com/ https://cdn.registerdisney.go.com/v2/responder/responder.js script
-http://www.txxx.com/ https://m.txxx.com/assets/vendor.9cc746a581d5ee1a5eb6.min.js script
-http://www.espn.com/ https://platform.twitter.com/jot.html html
-http://www.espn.com/ http://cdn.unid.go.com/js/unid.min.js script
-http://www.espn.com/ http://cdn-gl.imrworldwide.com/novms/html/ls.html html
-http://www.espn.com/ https://pixel.adsafeprotected.com/rfw/st/132147/21327473/skeleton.js?adsafe_url=http%3A%2F%2Fwww.espn.com%2F&adsafe_type=abedfq&adsafe_jsinfo=,id:6194f49c-b147-85e0-fcf5-3cbfd908b545,c:1mG41i,sl:inView,em:true,fr:true,mn:app27sje,pt:1-5-15,wc:0.0.360.512,ac:20.113.320.50,am:i,cc:0.0.320.68,piv:100,obst:0,th:0,reas:,cmps:1,br:c,fv:0,bv:na,dm:na,abv:na,an:n,fm:qGNyNkj+11|12|13*.132147-21327473|14|15|16|17|181,idMap:13*,pl:,rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:0,fif:0,gm:0,uf:0,tt:rjss,et:100,oid:f7f85d38-f9e7-11e7-9957-54a0508693cd,v:17.4.57,sp:0,ct:5583,dtm:i,gtpl:0,wr:360.512,sr:360.512,mf:2000372605,ov:0 script
-http://www.txxx.com/ https://m.txxx.com/assets/mobile/js/sub_id.js?v=0704 script
-http://www.espn.com/ https://cdn.registerdisney.go.com/v2/inner/tealium/utag.js script
-http://www.txxx.com/ https://m.txxx.com/assets/mobile/css/mobile.min.css?v=9cc746a581d5ee1a5eb6 css
-http://www.txxx.com/ https://ashot.txxx.com/txxx_pass/vanload4.js script
-http://www.txxx.com/ https://m.txxx.com/assets/mobile/js/modernizr-custom-2.8.3.min.js script
-http://www.txxx.com/ https://www.txxx.com/js/advertising.js?v=botrj script
-http://www.espn.com/ https://sc.iasds01.com/dtc?ias_callback=__IntegralAS_6194f49cb14785e0fcf53cbfd908b545_6459&advEntityId=132147&asid=6194f49c-b147-85e0-fcf5-3cbfd908b545 other
-http://www.txxx.com/ https://m.txxx.com/assets/mobile/js/jquery-2.1.4.min.js script
-http://www.txxx.com/ https://m.txxx.com/images/mobile-logo.png image
-http://www.espn.com/ http://secure-dcr.imrworldwide.com/cgi-bin/gn?prd=session&c9=devid,&c13=asid,P07264C85-15CD-4A80-8E56-B5BFA6D93296&sessionId=FX63giFKjLtO3Ylu0GCEuC2ExKq2e1516016037&C16=sdkv,bj.6.0.0&retry=0 image
-http://www.txxx.com/ https://m.txxx.com/assets/mobile/js/main.min.js?v=20170309 script
-http://www.espn.com/ https://dt.adsafeprotected.com/dt?advEntityId=132147&asId=6194f49c-b147-85e0-fcf5-3cbfd908b545&tv={c:1mG435,pingTime:-2,time:208,type:a,env:{sf:0,pom:1},rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:0,fif:0,gm:0,slTimes:{i:208,o:0,n:0,pp:0,pm:0},slEvents:[{sl:i,t:93,wc:0.0.360.512,ac:20.113.320.50,am:i,cc:0.0.320.68,piv:100,obst:0,th:0,reas:,cmps:1,bkn:{piv:[175~100],as:[175~320.50]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:rjss,dtt:0,fm:qGNyNkj+11|12|13*.132147-21327473|14|15|16|17|181,idMap:13*,slid:[google_ads_iframe_/6444/espn.com/frontpage/index_2,google_ads_iframe_/6444/espn.com/frontpage/index_2__container__,ad-slot-banner-561127,pane-main,global-viewport],sinceFw:91,readyFired:true}&br=c image
-http://www.espn.com/ http://cdn.unid.go.com/inner/?v=3.3.100 html
-http://www.txxx.com/ https://m.txxx.com/assets/mobile/fonts/fontawesome-webfont.woff2?v=4.3.0 font
-http://www.espn.com/ https://dt.adsafeprotected.com/dt?advEntityId=132147&asId=6194f49c-b147-85e0-fcf5-3cbfd908b545&tv={c:1mG4uv,pingTime:1,time:1908,type:p,rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:0,fif:0,gm:0,slTimes:{i:1908,o:0,n:0,pp:0,pm:0},slEvents:[{sl:i,t:93,wc:0.0.360.512,ac:NaN.NaN.320.50,am:i,cc:0.0.320.68,piv:100,obst:0,th:0,reas:,cmps:1,bkn:{piv:[1874~100],as:[1874~320.50]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:rjss,dtt:0,fm:qGNyNkj+11|12|13*.132147-21327473|14|15|16|17|181,idMap:13*}&br=c image
-http://www.espn.com/ https://cdn.registerdisney.go.com/v2/inner/tealium/utag.34.js?utv=ut4.44.201801111843 script
-http://www.txxx.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.txxx.com/ https://www.googletagmanager.com/gtm.js?id=GTM-MDKJT8 script
-http://www.espn.com/ https://cdn.registerdisney.go.com/v2/inner/tealium/utag.49.js?utv=ut4.44.201801022331 script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1795000/1795414/220x165/1.jpg image
-http://www.espn.com/ https://sc.iasds01.com/dtc?ias_callback=__IntegralAS_6194f49cb14785e0fcf53cbfd908b545_6459&advEntityId=132147&asid=6194f49c-b147-85e0-fcf5-3cbfd908b545&second_pass=1 other
-http://www.espn.com/ http://b.scorecardresearch.com/rs/mobile/vce_st.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4489000/4489521/220x165/4.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4731000/4731181/220x165/4.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/2256000/2256261/220x165/6.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/133000/133189/220x165/1.jpg image
-http://www.espn.com/ http://b.scorecardresearch.com/p?ns__t=1516016039205&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&c1=3&c3=2202845420&c4=138222175459&c5=4516735323_104318097&c6=&c10=1&c11=104318097&c12=&c13=&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_sv=5.1710.02&ns_ce_mod=vce_st&ns_ad_event=load&c8=&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F other
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/318000/318712/220x165/1.jpg image
-http://www.espn.com/ http://a.scorecardresearch.com/rpc.flow?uid=uid1516016039205&ns_mod_ns=mvce&ns__p=1516016039205&ns__t=1516016039205&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&c1=3&c3=2202845420&c4=138222175459&c5=4516735323_104318097&c6=&c10=1&c11=104318097&c12=&c13=&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_sv=5.1710.02&ns_ce_mod=vce_st&ns_ad_event=load&c8=&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/2913000/2913426/220x165/1.jpg image
-http://www.espn.com/ https://www.facebook.com/brandlift.php?sessionId=FX63giFKjLtO3Ylu0GCEuC2ExKq2e1516016037&media_type=dcr&advertiser_id=NA image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1869000/1869859/220x165/1.jpg image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=17&i=ESPN1&hp=1&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&kq=3&hq=0&hs=0&hu=0&hr=0&ht=1&bq=0&f=0&tw=null&j=&o=3&t=1516016038712&de=868233146273&m=0&ar=ce9a715-clean&q=2&cb=1&cu=1516016038712&ll=3&lm=0&ln=1&r=0&em=0&en=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&qs=1&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&bo=104318097&bd=104335617&dfp=0%2C1&la=104335617&gw=espndfp832188684382&fd=1&ac=1&it=500&fs=135109&na=698518238&cs=0 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/304000/304421/220x165/1.jpg image
-http://www.espn.com/ http://b.scorecardresearch.com/p2?ns__t=1516016039205&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&c1=3&c3=2202845420&c4=138222175459&c5=4516735323_104318097&c6=&c10=1&c11=104318097&c12=&c13=&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_sv=5.1710.02&ns_ce_mod=vce_st&ns_ad_event=load&c8=&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1729000/1729492/220x165/1.jpg image
-http://www.espn.com/ http://b.scorecardresearch.com/beacon.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1835000/1835167/220x165/1.jpg image
-http://www.espn.com/ https://310987714.log.optimizely.com/event?a=310987714&d=310987714&y=false&src=js&x8483651062=8486311072&s310954789=none&s311043393=true&s311047346=gc&s311052307=direct&s793783561=true&s806111078=none&s806950111=mobile&tsent=1516016040.387&n=http%3A%2F%2Fwww.espn.com%2F&u=oeu1516016040389r0.8262098286459276&wxhr=true&time=1516016040.387&f=8448890495,9262875135,9263073801,8792134866,8483651062&g=8483651062&cx2=dae8b107 script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1336000/1336535/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4866000/4866189/220x165/9.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/126000/126015/220x165/1.jpg image
-http://www.espn.com/ http://w88.espn.com/b/ss/wdgespcom,wdgespge/1/JS-1.6.1/s17888151802875?AQB=1&ndh=1&pf=1&t=15%2F0%2F2018%2011%3A34%3A0%201%200&mid=58381219692831642431544101446809648234&aid=2D2E48CD0503765A-6000118C600A44E0&aamlh=9&ce=ISO-8859-1&ns=espn&cdp=2&pageName=espn%3Afrontpage&g=http%3A%2F%2Fwww.espn.com%2F&cc=USD&ch=espn%3Afrontpage&server=www.espn.com&events=event3&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&c1=espn&h1=espn%3Afrontpage&c2=D%3DSWID&l3=1-22098839e01%2C1-22100624e02%2C1-21748450e03%2C1-22099626e04%2C1-22101203e05%2C1-22100229e06%2C1-22096580e07%2C1-22098581e08%2C1-22101253e09%2C1-22100406e10&c4=index&c5=espn%3Afrontpage&c6=New&v7=unknown%3Aunknown%3Aanonymous%3Aanonymous%3Apremium-no&v9=en_us&c11=anonymous%3Apremium-no&v11=index%3Aespn%3Afrontpage&v12=en-us&v13=espn%3Afrontpage&c16=en-us&c17=en_us&c21=unknown&v21=no%2Bleague&c22=unknown&v23=unknown&c24=First%20Visit&c26=no%2Bleague&c29=anonymous&c30=premium-no&c38=Portrait&v38=Portrait&v46=false%7Cfalse&c58=isIndex%3Dtrue&v70=favorites%3Ano%7Cfantasy%3Ano%7Cleague%20mgr%3Ano%7Calerts%3Ano%7Cautostart%3Ano&v73=cbHeadlineTest&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 image
-http://www.txxx.com/ https://adservice.google.com/adsid/integrator.js?domain=m.txxx.com script
-http://www.espn.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsuUXsRJelNnYZZiJNiqFaDaYtvOZUL2AM3xk7y9TQX3oT2IboQUoF3LD8KIubULRrjepfvR9zfVAtpJU8bIHw0l8oEOBRqT1zk&sig=Cg0ArKJSzKW2fFpKUuMdEAE&id=osdim&ti=1&adk=491800423&tt=7204&bs=360,512&mtos=6734,6734,6734,6734,6734&tos=6734,0,0,0,0&p=114,20,164,340&inapp=0&mcvt=6734&rs=3&ht=0&tfs=503&tls=7237&mc=1&lte=1&bas=0&bac=0&bos=360,512&ps=360,7621&ss=360,512&pt=34&deb=1-1-2-37-38-100&tvt=7111&op=1&avms=geo&r=v&uc=1&tgt=BODY&cl=1&cec=13&clc=2&cac=0320x68&v=r20180108 image
-http://www.txxx.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_173.js script
-http://www.espn.com/ http://b.scorecardresearch.com/p?ns__t=1516016040571&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&ns__p=1516016039205&c1=3&c3=_e0_2202845420&c4=138222175459&c5=4516735323_104318097&c6=&c10=1&c11=104318097&c12=&c13=&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_sv=5.1710.02&ns_ce_mod=vce_st&ns_ad_event=boot&ns_ad_boot=1354&ns_ad_fpv=0&c8=&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F image
-http://www.txxx.com/ https://syndication.exosrv.com/splash.php?idzone=2060545&type=12&capping=2&sub=undefined html
-http://www.espn.com/ http://api.mixpanel.com/track/?data=eyJldmVudCI6ICJQYWdlIFZpZXciLCJwcm9wZXJ0aWVzIjogeyIkb3MiOiAiQW5kcm9pZCIsIiRicm93c2VyIjogIkNocm9tZSIsIiRkZXZpY2UiOiAiQW5kcm9pZCIsIiRjdXJyZW50X3VybCI6ICJodHRwOi8vd3d3LmVzcG4uY29tLyIsIiRicm93c2VyX3ZlcnNpb24iOiA1OCwiJHNjcmVlbl9oZWlnaHQiOiA1MTIsIiRzY3JlZW5fd2lkdGgiOiAzNjAsIm1wX2xpYiI6ICJ3ZWIiLCIkbGliX3ZlcnNpb24iOiAiMi4xNC4wIiwiZGlzdGluY3RfaWQiOiAiMTYwZjk5OGUzNWEzOC0wYzAyYzA1NTM2MDc4Ni1mNjM2MTdiLTJkMDAwLTE2MGY5OThlMzViYmFhIiwiJGluaXRpYWxfcmVmZXJyZXIiOiAiJGRpcmVjdCIsIiRpbml0aWFsX3JlZmVycmluZ19kb21haW4iOiAiJGRpcmVjdCIsIkVkaXRpb24gTmFtZSI6ICJFbmdsaXNoIC8gVW5pdGVkIFN0YXRlcyIsIlNwb3J0L0xlYWd1ZSI6ICJIb21lIFBhZ2UiLCJVUkwiOiAiaHR0cDovL3d3dy5lc3BuLmNvbS8iLCJDb250ZW50IFNwb3J0L0xlYWd1ZToiOiAiZnJvbnRwYWdlIiwiUGFnZSBUeXBlIjogIkhvbWUgUGFnZSIsIlVzZXIgRGV2aWNlIExvY2FsIFRpbWUiOiAiMTE6MzQ6MDAiLCJTY3JvbGwgRGVwdGgiOiAxLCJ0b2tlbiI6ICI2YjM0N2MzOWYwZjU3MDY3YTM2YWNjNmFhNjAwYTA5NCIsIiRkdXJhdGlvbiI6IDUuOTQsIiRfX2MiOiAwfX0%3D&ip=1&_=1516016040630 script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/815000/815050/220x165/3.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3334000/3334879/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/421000/421402/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1326000/1326797/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/2332000/2332930/220x165/1.jpg image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=0&q=0&hp=1&kq=3&lo=0&qs=1&ak=https%3A%2F%2Ftpc.googlesyndication.com%2Fpagead%2Fimgad%3Fid%3DCICAgKDr6dq-rQEQARgBMghka4JuXreZig&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=0&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=455&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=0&ag=70&an=0&gf=70&gg=0&ez=1&aj=1&pg=100&pf=0&ib=0&cc=0&bw=70&bx=0&dj=1&aa=0&ad=0&cn=0&gk=0&gl=0&im=0&in=0&em=0&en=0&st=1&su=1&of=1&oz=1&bu=139&cd=0&ah=139&am=0&rf=0&re=0&wb=1&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=651921966&cs=0 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4491000/4491495/220x165/10.jpg image
-http://www.espn.com/ http://unid.go.com/v3/hit other
-http://www.txxx.com/ https://www.google-analytics.com/analytics.js script
-http://www.txxx.com/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.espn.com/ http://b.scorecardresearch.com/b?c1=2&c2=3000005&ns__t=1516016040785&ns_c=UTF-8&cv=3.1m&c8=ESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&c7=http%3A%2F%2Fwww.espn.com%2F&c9= other
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/2454000/2454506/220x165/1.jpg image
-http://www.espn.com/ https://fx63gifkjlto3ylu0gceuc2exkq2e1516016037.nuid.imrworldwide.com/ html
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=37&q=0&hp=1&kq=3&lo=0&qs=1&ak=-&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=1&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=1221&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=1077&an=70&gi=1&gf=1077&gg=70&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=1077&bx=70&ci=1077&jz=908&dj=1&aa=0&ad=349&cn=0&gk=349&gl=0&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=908&cd=139&ah=908&am=139&rf=0&re=0&wb=1&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=1146738332&cs=0 image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=5&q=0&hp=1&kq=3&lo=0&qs=1&ak=-&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=2&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=1223&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=1077&an=1077&gi=1&gf=1077&gg=1077&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=1077&bx=1077&ci=1077&jz=908&dj=1&aa=0&ad=349&cn=349&gk=349&gl=349&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=908&cd=908&ah=908&am=908&rf=0&re=0&wb=1&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=8156004&cs=0 image
-http://www.espn.com/ https://tags.bkrtx.com/js/bk-coretag.js script
-http://www.espn.com/ http://b.scorecardresearch.com/p?ns__t=1516016041656&ns__c=UTF-8&ns_ad_brt=352&ns_ad_conn=true%7Cundefined&uid=img138222175459&c1=3&c3=_e0_2202845420&c4=138222175459&c5=4516735323_104318097&c10=1&c11=104318097&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_mod=vce_st&ns__p=1516016039205&ax_cid=26060552&ns_ad_bld=28&ns_ad_event=late&ns_ad_id=img138222175459&ns_ad_sz=320x50&ns_ad_po=0x0&ns_ad_vsd=360x512&ns_ad_sd=360x512&ns_ad_ia=0&ns_ad_vad=320x50&ns_ad_vap=20x113&ns_ad_vvd=360x512&ns_ad_vvp=0x0&ns_ad_vi=100&ns_type=hidden&ns_ad_pid=1516016040561&ax_mid=8585791516040561&ns_ad_vw=320x50&ns_ad_sc=0x0&ns_ad_sv=5.1712.21&ns_ad_tn=IMG&ns_ad_db=Chrome%2F58.0.3029|0|Linux%20x86_64|0|3|0|en-US|0|0|0|Google%20Inc.|0x0|0x1|-2|-1|50|-1|0|-1|100000000000101000000&ns_ad_ec=1&ns_ad_ple=0,1098,0,0,0,0&ns_ad_src=https%3A%2F%2Ftpc.googlesyndication.com%2Fpagead%2Fimgad%3Fid%3DCICAgKDr6dq-rQEQARgBMghka4JuXreZig&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F&c8= image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=37&q=1&hp=1&kq=3&lo=0&qs=1&ak=-&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=3&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=1231&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=1077&an=1077&gi=1&gf=1077&gg=1077&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=1077&bx=1077&ci=1077&jz=908&dj=1&aa=0&ad=349&cn=349&gk=349&gl=349&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=908&cd=908&ah=908&am=908&rf=0&re=0&wb=1&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=755552614&cs=0 image
-http://www.txxx.com/ https://syndication.exosrv.com/ads-priv.php?i=0 html
-http://www.espn.com/ https://tags.tiqcdn.com/utag/tiqapp/utag.v.js?a=disney/disneyid/201801111843&cb=1516016040757 script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/294000/294574/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/168000/168655/220x165/1.jpg image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=5&q=1&hp=1&kq=3&lo=0&qs=1&ak=-&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=4&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=1940&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=1805&an=1077&gi=1&gf=1805&gg=1077&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=1805&bx=1077&ci=1077&jz=908&dj=1&aa=1&ad=1077&cn=349&gn=1&gk=1077&gl=349&co=1077&cp=1412&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=1412&cd=908&ah=1412&am=908&rf=0&re=0&wb=1&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=2130561440&cs=0 image
-http://www.espn.com/ https://dpm.demdex.net/id?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_cb=s_c_il%5B3%5D._setMarketingCloudFields script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4489000/4489015/220x165/1.jpg image
-http://www.espn.com/ http://b.scorecardresearch.com/p?ns__t=1516016042605&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&c1=3&c3=_e1_2202845420&c4=138222175459&c5=4516735323_104318097&c10=1&c11=104318097&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_mod=vce_st&ns__p=1516016039205&ax_cid=26060552&ns_ad_bld=28&ax_bl=0&ax_blt=1497&ns_ad_id=img138222175459&ns_ad_sz=320x50&ns_ad_po=0x0&ns_ad_vsd=360x512&ns_ad_sd=360x512&ns_ad_ia=0&ns_ad_vad=320x50&ns_ad_vap=20x113&ns_ad_vvd=360x512&ns_ad_vvp=0x0&ns_ad_vi=100&ns_ad_event=qp1&ns_type=hidden&ns_ad_pid=1516016040561&ax_mid=8585791516040561&ns_ad_vw=320x50&ns_ad_sc=0x0&ns_ad_sv=5.1712.21&ns_ad_tn=IMG&ns_ad_db=Chrome%2F58.0.3029|0|Linux%20x86_64|0|3|0|en-US|0|0|0|Google%20Inc.|0x0|0x1|-2|-1|50|-1|0|-1|100000000000101000000&ns_ad_ec=2&ax_vt=949&ns_ad_avt=949&ns_ad_ple=0,2047,0,0,0,949&ns_ad_src=https%3A%2F%2Ftpc.googlesyndication.com%2Fpagead%2Fimgad%3Fid%3DCICAgKDr6dq-rQEQARgBMghka4JuXreZig&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F&c8= image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4333000/4333625/220x165/4.jpg image
-http://www.txxx.com/ https://mc.yandex.ru/metrika/watch.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3358000/3358765/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1970000/1970581/220x165/1.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1904000/1904506/220x165/1.jpg image
-http://www.espn.com/ https://sw88.go.com/b/ss/wdgdilb/1/H.27.4/s16981301599523?AQB=1&ndh=1&t=15%2F0%2F2018%2011%3A34%3A1%201%200&fid=0A4BD9458041C746-13DA30E282747193&ns=disneyid&g=https%3A%2F%2Fcdn.registerdisney.go.com%2Fv2%2FESPN-ESPNCOM-PROD%2Fen-US%3Finclude%3Dconfig%2Cl10n%2Cjs%2Chtml%26scheme%3Dhttp%26postMessageOrigin%3Dhttp%253A%252F%252Fwww.espn.com%252F%26cookieDomain%3Dwww.espn.com%26config%3DPROD%26logLevel%3DINFO%26topHost%3Dwww.espn.com%26cssOverride%3Dhttps%253A%252F%252Fsecure.e&r=http%3A%2F%2Fwww.espn.com%2F&c.&pageview=true&pagename=ready&clientid=ESPN-ESPNCOM-PROD&authenticationstate=not%20authenticated&language=en&didpage=true&swid=6867945A-20A1-4547-C5EE-736FB233194C&unidvalue=3651bc3e-cef1-4759-a14c-b830d9d67f40&unidreason=new&.c&cc=USD&s=360x512&c=24&j=1.6&v=N&k=Y&-g=spncdn.com%252Fcombiner%252Fc%253Fcss%253Ddisneyid%252Fcore.css%26responderPage%3Dhttps%253A%252F%252Fwww.espn.com%252Flogin%252Fresponder%252Findex.html%26buildId%3D160c87eee28&AQE=1 text
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1835000/1835716/220x165/1.jpg image
-http://www.nicovideo.jp/ http://www.nicovideo.jp/ html
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4916000/4916845/220x165/1.jpg image
-http://www.nicovideo.jp/ http://sp.nicovideo.jp/ html
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1461000/1461449/220x165/1.jpg image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/assets/page/Top/Top.css css
-http://www.espn.com/ https://dpm.demdex.net/id?d_visid_ver=1.5.6&d_rtbd=json&d_ver=2&d_orgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&d_nsid=0&d_mid=91467311488249752511208089112671232186&d_cb=s_c_il%5B3%5D._setAudienceManagerFields script
-http://www.txxx.com/ https://www.google-analytics.com/plugins/ua/linkid.js script
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/assets/page/SiteWide/SiteWide.css?f6d5b0627b3184cc9b42e6277c9f2abe css
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1461000/1461353/220x165/1.jpg image
-http://www.espn.com/ https://tags.bluekai.com/site/24667?ret=html&phint=pageName%3Despn%3Afrontpage&phint=channel%3Despn%3Afrontpage&phint=eVar34%3D&phint=events%3Devent3&phint=prop1%3Despn&phint=swid%3D6867945A-20A1-4547-C5EE-736FB233194C&phint=prop4%3Dindex&phint=prop9%3D&phint=prop23%3D&phint=prop25%3D&phint=prop26%3Dno%2Bleague&phint=prop30%3Dpremium-no&phint=prop32%3D&phint=prop45%3D&phint=__bk_t%3DESPN%3A%20The%20Worldwide%20Leader%20in%20Sports&phint=__bk_k%3DESPN.co.uk%2C%20sports%20scores%2C%20sports%20news%2C%20football%20scores%2C%20cricket%20scores%2C%20rugby%20scores%2C%20f1%20scores%2C%20golf%20scores%2C%20tennis%20scores%2C%20MLB%20scores%2C%20NFL%20scores%2C%20NBA%20scores%2C%20NHL%20scores%2C%20College%20Football%20scores%2C%20College%20Basketball%20scores%2C%20sports%20videos%2C%20sports%20information%2C%20Fantasy%20sports%2C%20Fantasy%20games%2C%20Fantasy%20football%2C%20Fantasy%20baseball&phint=__bk_l%3Dhttp%3A%2F%2Fwww.espn.com%2F&limit=10&bknms=ver=2.0,ua=14b68fe3244daf632785cd9404e86d56,t=1516016041995,m=4b4e4ecaab1f1c93ab1f1c93ab1f1c93,k=1,lang=07ef608d8a7e9677f0b83775f0b83775,sr=512x360x24,tzo=0,hss=true,hls=true,idb=true,addb=undefined,odb=function,cpu=4b4e4ecaab1f1c93ab1f1c93ab1f1c93,platform=1c17637dbf2f8edebf2f8edebf2f8ede,notrack=,plugins=4b4e4ecaab1f1c93ab1f1c93ab1f1c93&r=44872141 other
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/polyfill.min.js?v6.23.0 script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1461000/1461351/220x165/8.jpg image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/assets/common/normalize.css?ba65b1d2869363dc014f45ef38b34229 css
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/jquery-1.9.1.min.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3508000/3508306/220x165/4.jpg image
-http://www.espn.com/ https://sw88.go.com/b/ss/wdgdilb/1/H.27.4/s16981301599523?AQB=1&pccr=true&vidn=2D2E48D5850362B4-4000119CC000DD6D&&ndh=1&t=15%2F0%2F2018%2011%3A34%3A1%201%200&fid=0A4BD9458041C746-13DA30E282747193&ns=disneyid&g=https%3A%2F%2Fcdn.registerdisney.go.com%2Fv2%2FESPN-ESPNCOM-PROD%2Fen-US%3Finclude%3Dconfig%2Cl10n%2Cjs%2Chtml%26scheme%3Dhttp%26postMessageOrigin%3Dhttp%253A%252F%252Fwww.espn.com%252F%26cookieDomain%3Dwww.espn.com%26config%3DPROD%26logLevel%3DINFO%26topHost%3Dwww.espn.com%26cssOverride%3Dhttps%253A%252F%252Fsecure.e&r=http%3A%2F%2Fwww.espn.com%2F&c.&pageview=true&pagename=ready&clientid=ESPN-ESPNCOM-PROD&authenticationstate=not%20authenticated&language=en&didpage=true&swid=6867945A-20A1-4547-C5EE-736FB233194C&unidvalue=3651bc3e-cef1-4759-a14c-b830d9d67f40&unidreason=new&.c&cc=USD&s=360x512&c=24&j=1.6&v=N&k=Y&-g=spncdn.com%252Fcombiner%252Fc%253Fcss%253Ddisneyid%252Fcore.css%26responderPage%3Dhttps%253A%252F%252Fwww.espn.com%252Flogin%252Fresponder%252Findex.html%26buildId%3D160c87eee28&AQE=1 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4648000/4648091/220x165/7.jpg image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/nicoapi.js?747e620179aac500bd33d22d030d1bac script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/5004000/5004531/220x165/6.jpg image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/assets/js/adsSimple-1.3.0.min.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3557000/3557830/220x165/5.jpg image
-http://www.nicovideo.jp/ https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css css
-http://www.espn.com/ https://dt.adsafeprotected.com/dt?advEntityId=132147&asId=6194f49c-b147-85e0-fcf5-3cbfd908b545&tv={c:1mG5l5,pingTime:5,time:5168,type:p,rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:0,fif:0,gm:0,slTimes:{i:5168,o:0,n:0,pp:0,pm:0},slEvents:[{sl:i,t:93,wc:0.0.360.512,ac:NaN.NaN.320.50,am:i,cc:0.0.320.68,piv:100,obst:0,th:0,reas:,cmps:1,bkn:{piv:[5134~100],as:[5134~320.50]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:rjss,dtt:768,fm:qGNyNkj+11|12|13*.132147-21327473|14|15|16|17|181,idMap:13*}&br=c image
-http://www.txxx.com/ https://st.tubecup.org/?t_sid=co7xf61xmlibhjdyd0bf7l&t=1516016064978&refa=m.txxx.com html
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/common.js?a1e6006aa2ff53ecfa47f237af6a755a script
-http://www.espn.com/ https://sw88.espn.com/id?d_visid_ver=1.5.6&callback=s_c_il%5B3%5D._setAnalyticsFields&mcorgid=EE0201AC512D2BE80A490D4C%40AdobeOrg&mid=91467311488249752511208089112671232186 script
-http://www.txxx.com/ https://ads.exosrv.com/close.png image
-http://www.espn.com/ https://sw88.espn.com/b/ss/wdgespcom,wdgespge/1/JS-1.6.1/s12108858461971?AQB=1&ndh=1&pf=1&t=15%2F0%2F2018%2011%3A34%3A2%201%200&mid=91467311488249752511208089112671232186&aamlh=9&ce=UTF-8&ns=espn&cdp=2&g=https%3A%2F%2Fcdn.registerdisney.go.com%2Fv2%2FESPN-ESPNCOM-PROD%2Fen-US%3Finclude%3Dconfig%2Cl10n%2Cjs%2Chtml%26scheme%3Dhttp%26postMessageOrigin%3Dhttp%253A%252F%252Fwww.espn.com%252F%26cookieDomain%3Dwww.espn.com%26config%3DPROD%26logLevel%3DINFO%26topHost%3Dwww.espn.com%26cssOverride%3Dhttps%253A%252F%252Fsecure.e&r=http%3A%2F%2Fwww.espn.com%2F&c.&pageview=true&pagename=ready&clientid=ESPN-ESPNCOM-PROD&authenticationstate=not%20authenticated&language=en&didpage=true&swid=6867945A-20A1-4547-C5EE-736FB233194C&.c&cc=USD&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&s=360x512&c=24&j=1.6&v=N&k=Y&bh=598&-g=spncdn.com%252Fcombiner%252Fc%253Fcss%253Ddisneyid%252Fcore.css%26responderPage%3Dhttps%253A%252F%252Fwww.espn.com%252Flogin%252Fresponder%252Findex.html%26buildId%3D160c87eee28&AQE=1 image
-http://www.txxx.com/ https://static.exosrv.com/library/330850/7a021e0c90bd5d2f66244b5142b9ba632be3d268.gif image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=9&q=0&hp=1&kq=3&lo=0&qs=1&ak=-&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=5&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=5246&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=5110&an=1805&gi=1&gf=5110&gg=1805&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=5110&bx=1805&ci=1077&jz=908&dj=1&aa=1&ad=4382&cn=1077&gn=1&gk=4382&gl=1077&co=1077&cp=1412&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=4979&cd=1412&ah=4979&am=1412&rf=0&re=0&wb=2&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=1983683224&cs=0 image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/jquery.showMenu.js?20170420 script
-http://www.txxx.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1338250843&t=pageview&_s=1&dl=https%3A%2F%2Fm.txxx.com%2F&ul=en-us&de=UTF-8&dt=Porn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aGBAAAAj~&jid=1883137769&gjid=639798447&cid=702883325.1516016066&tid=UA-43982756-1&_gid=1153959672.1516016066&_r=1&gtm=G1cMDKJT8&z=865997063 image
-http://www.espn.com/ https://stags.bluekai.com/site/24668?dt=0&r=1343128137&sig=2553478142&bkca=KJhNAXsmZp9xCoIsl/QY5onBQDB/Qlo/G6oq+z4/A9WLpOMjp+J2ITblqWmXVykjXldpKt0wLxsU+S8UibsPbnJOBc9VwDELY2QO/fSFMDq7XKuGVGW/bFXsIYA1T8HdN0I9p73de2MfxARw0PHAx7SDP0vqoXNth24fmal+A8iFIERIg/dcK1LtHjT0krpTRPqWg0EhYg27qc54lzrDOUG5b9NoNasSvheBeVRo+3nDRvYU+p8swzIAM6UTgmMkD7RUHdgTdwN1nRguNRXVSw0kMqgu1UNX97WaxTaWsoTcqj05pIIZIz+vnt25kOf/j52zw3i69H+9CcaY+5SraWGapLg/3Q1UDcBg0+K9NDA9s3l39ek9kmaZFol0QJ0nD6M04DiICobePQGSlb4iXfwzeqZy5vCwnwXSX6/5N0sDVsFEY0zNdL6D9otygpww/tlGUU0926TdXkJRXchIGdfH+1TBql2Wx5XTMAFd9mivK8/nJUFoLZuNveFLqjRLE1q86pjBKw/cxk/rZy== html
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/lib/react-dom-15.4.2.min.js script
-http://www.txxx.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1338250843&t=event&_s=1&dl=https%3A%2F%2Fm.txxx.com%2F&ul=en-us&de=UTF-8&dt=Porn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=&ea=&_u=aGDAAAAj~&jid=2013218688&gjid=1887847620&cid=702883325.1516016066&tid=UA-51278971-3&_gid=1153959672.1516016066&_r=1&gtm=G1cMDKJT8&z=464730238 html
-http://www.espn.com/ https://api.adsymptotic.com/d/px?_pid=10479&_psign=1e962a13c2bbb17776ade0119024edb3&_redirect=https%3A%2F%2Ftags.bluekai.com%2Fsite%2F20931%3Fid%3D%24%7BUUID%7D other
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/lib/react-with-addons-15.4.2.min.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1469000/1469715/220x165/1.jpg image
-http://www.espn.com/ https://api.adsymptotic.com/d/px?_pid=10479&_psign=1e962a13c2bbb17776ade0119024edb3&_redirect=https%3A%2F%2Ftags.bluekai.com%2Fsite%2F20931%3Fid%3D%24%7BUUID%7D&_expected_cookie=18d2394e55cedb3c6f42af4f20d95f78 other
-http://www.txxx.com/ https://mc.yandex.ru/watch/23578849?wmode=7&page-url=https%3A%2F%2Fm.txxx.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-480%3Ai%3A20180115033426%3Aet%3A1516016067%3Aen%3Autf-8%3Av%3A938%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A880838125753%3Arqn%3A1%3Arn%3A267943705%3Ahid%3A750845310%3Ads%3A0%2C0%2C472%2C302%2C2039%2C0%2C0%2C4413%2C118%2C%2C%2C%2C7847%3Afp%3A5486%3Awn%3A3421%3Ahl%3A3%3Arqnl%3A1%3Ast%3A1516016067%3Au%3A1516016067149798111%3At%3APorn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube other
-http://www.espn.com/ https://tags.bluekai.com/site/20931?id=18d2394e55cedb3c6f42af4f20d95f78 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3593000/3593296/220x165/9.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/5009000/5009079/220x165/3.jpg image
-http://www.espn.com/ http://b.scorecardresearch.com/p?ns__t=1516016046612&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&c1=3&c3=_e5_2202845420&c4=138222175459&c5=4516735323_104318097&c10=1&c11=104318097&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_mod=vce_st&ns__p=1516016039205&ax_cid=26060552&ns_ad_bld=28&ax_bl=0&ax_blt=1497&ns_ad_id=img138222175459&ns_ad_sz=320x50&ns_ad_po=0x0&ns_ad_vsd=360x512&ns_ad_sd=360x512&ns_ad_ia=0&ns_ad_vad=320x50&ns_ad_vap=20x113&ns_ad_vvd=360x512&ns_ad_vvp=0x0&ns_ad_vi=100&ns_ad_event=qp5&ns_type=hidden&ns_ad_pid=1516016040561&ax_mid=8585791516040561&ns_ad_vw=320x50&ns_ad_sc=0x0&ns_ad_sv=5.1712.21&ns_ad_tn=IMG&ns_ad_db=Chrome%2F58.0.3029|0|Linux%20x86_64|0|3|0|en-US|0|0|0|Google%20Inc.|0x0|0x1|-2|-1|50|-1|0|-1|100000000000101000000&ns_ad_ec=3&ax_vt=4008&ns_ad_avt=4957&ns_ad_ple=0,6055,0,0,0,4008&ns_ad_src=https%3A%2F%2Ftpc.googlesyndication.com%2Fpagead%2Fimgad%3Fid%3DCICAgKDr6dq-rQEQARgBMghka4JuXreZig&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F&c8= image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/ads/middle_banner.js?20170223 script
-http://www.txxx.com/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Porn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube&time=1516016065344&time_zone_offset=480&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fm.txxx.com%2F&random_number=4749912858&sess_cookie=29c40ccc160f9995b3f54a9bfa9&sess_cookie_flag=1&user_cookie=29c40ccc160f9995b3f54a9bfa9&user_cookie_flag=1&dynamic=true&domain=txxx.com&account=wQ4ei1acVE00WL&jsv=20130128&user_lang=en-US image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=9&q=1&hp=1&kq=3&lo=0&qs=1&ak=-&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=6&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=10246&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=10110&an=5110&gi=1&gf=10110&gg=5110&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=10110&bx=5110&ci=1077&jz=908&dj=1&aa=1&ad=9382&cn=4382&gn=1&gk=9382&gl=4382&co=1077&cp=1412&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=9979&cd=4979&ah=9979&am=4979&rf=0&re=0&wb=2&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&na=477880791&cs=0 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4576000/4576057/220x165/12.jpg image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/js/lib/mustache.min.js script
-http://www.espn.com/ http://b.scorecardresearch.com/p?ns__t=1516016051631&ns__c=UTF-8&ns_ad_conn=true%7Cundefined&c1=3&c3=_e0_2202845420&c4=138222175459&c5=4516735323_104318097&c10=1&c11=104318097&c16=dfp&c2=26060552&ax_iframe=1&ns_ce_mod=vce_st&ns__p=1516016039205&ax_cid=26060552&ns_ad_bld=28&ax_bl=0&ax_blt=1497&ns_ad_id=img138222175459&ns_ad_sz=320x50&ns_ad_po=0x0&ns_ad_vsd=360x512&ns_ad_sd=360x512&ns_ad_ia=0&ns_ad_vad=320x50&ns_ad_vap=20x113&ns_ad_vvd=360x512&ns_ad_vvp=0x0&ns_ad_vi=100&ns_ad_event=qp10&ns_type=hidden&ns_ad_pid=1516016040561&ax_mid=8585791516040561&ns_ad_vw=320x50&ns_ad_sc=0x0&ns_ad_sv=5.1712.21&ns_ad_tn=IMG&ns_ad_db=Chrome%2F58.0.3029|0|Linux%20x86_64|0|3|0|en-US|0|0|0|Google%20Inc.|0x0|0x1|-2|-1|50|-1|0|-1|100000000000101000000&ns_ad_ec=4&ax_vt=5013&ns_ad_avt=9970&ns_ad_ple=0,11068,0,0,0,5013&ns_ad_src=https%3A%2F%2Ftpc.googlesyndication.com%2Fpagead%2Fimgad%3Fid%3DCICAgKDr6dq-rQEQARgBMghka4JuXreZig&c7=http%3A%2F%2Fwww.espn.com%2F&c9=http%3A%2F%2Fwww.espn.com%2F&c8= image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/asset/js/main/index.min.js?2d5411b24568550e98a860dd800249ff script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3564000/3564637/220x165/4.jpg image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/api/OxBannerService/getAdvertisements.jsonp?zone=614&category=&pageurl=http%3A%2F%2Fsp.nicovideo.jp%2F&pagevariant=&callback=ads_callback_1&_=1516015994750 script
-http://www.espn.com/ https://dt.adsafeprotected.com/dt?advEntityId=132147&asId=6194f49c-b147-85e0-fcf5-3cbfd908b545&tv={c:1mG7Wp,pingTime:15,time:15170,type:p,rt:1,cb:0,th:0,es:0,sa:1,sc:0,ha:0,fif:0,gm:0,slTimes:{i:15170,o:0,n:0,pp:0,pm:0},slEvents:[{sl:i,t:93,wc:0.0.360.512,ac:NaN.NaN.320.50,am:i,cc:0.0.320.68,piv:100,obst:0,th:0,reas:,cmps:1,bkn:{piv:[15136~100],as:[15136~320.50]}}],slEventCount:1,em:true,fr:true,uf:0,e:,tt:rjss,dtt:983,fm:qGNyNkj+11|12|13*.132147-21327473|14|15|16|17|181,idMap:13*}&br=c image
-http://www.espn.com/ https://px.moatads.com/pixel.gif?e=25&q=2&hp=1&kq=3&lo=0&qs=1&ak=https%3A%2F%2Ftpc.googlesyndication.com%2Fpagead%2Fimgad%3Fid%3DCICAgKDr6dq-rQEQARgBMghka4JuXreZig&i=ESPN1&ue=0&uu=0&qm=0&qn=(%2BIb%7Cj8o%3FJ(jkkeL07ta_*JRM!6t9B%2CN%3Ey)%2ChXbvU37_*NhSfBghz%5Dj103ett*apQ%3C%3C%2C%5Bo%7BG4%25w%5ETmeja8OvhXldXwo%7BaxcpZ%22%5BNcR%3E)%7C(v.C%248Rp!EnWio8bYLaXBjA%3AmQ)%3CF!tAbjrzJ%3BgoVYGVxc%40lQQV%23tc3%2Fh%7C%3FVKV%3BW5.NO)Wx%3D(a%24%3D!L2U%5EKm_lefSR8o23%3B(8.aS%3B4oD%7D%60%3Fjc!L258%5EB%5BQJt8%2Bwe7RRznyKmhMJ2N%5B.%22%24b_o%3FtVD%5D%5BpN%7CQF%40Sy7%7BA&qp=10000&qq=000001100000&qr=0&is=UBO6KCBhaK82yV0UVCCC7In3s2Tg9CCBCuEqOVFTaClBBCCCo3BkBB7BHgxyBB6I2BBBkt9PP9cB5kiUCBBBsCNBBeBOsBB4yTfsCmdyIWmvnorBCCZOByBCxb3IePDlXoDGF3nNS7BBBBBBCSYDBBD7BBICDDDCDDCdB0hCtxLBE7GIDBBBBB&iv=3&gz=0&hh=0&hn=0&qt=0&bq=0&g=7&hq=0&hs=0&hu=0&hr=0&ht=1&h=50&w=320&fy=0&gp=0&zGSRC=1&gu=http%3A%2F%2Fwww.espn.com%2F&zMoatPS=top&zMoatST=Site%20Not%20Defined&zMoatSW=6867945A-20A1-4547-C5EE-736FB233194C&zMoatSZ=320x50&zMoatOrigSlicer1=104318097&zMoatOrigSlicer2=104335617&f=0&j=&o=3&t=1516016038712&de=868233146273&cu=1516016038712&m=15246&ar=ce9a715-clean&cb=1&ll=3&lm=0&ln=1&r=0&dl=0&dm=3000&dn=0&gh=1&tw=null&td=1&qa=360&qb=512&qi=360&qj=512&qf=360&qe=512&qh=360&qg=512&lk=1&lb=7626&le=1&gm=1&io=1&ct=undefined&as=1&ag=15110&an=10110&gi=1&gf=15110&gg=10110&ez=1&ck=1077&kw=908&aj=1&pg=100&pf=100&ib=0&cc=1&bw=15110&bx=10110&ci=1077&jz=908&dj=1&aa=1&ad=14382&cn=9382&gn=1&gk=14382&gl=9382&co=1077&cp=1412&cq=1&im=1&in=1&nb=1&em=0&en=0&st=1&su=1&of=1&oz=1&bu=14979&cd=9979&ah=14979&am=9979&rf=0&re=0&wb=2&cl=0&at=0&d=4487136156%3A2202845420%3A4516735323%3A138222175459&bo=104318097&bd=104335617&gw=espndfp832188684382&dfp=0%2C1&la=104335617&ab=1&ac=1&fd=1&kt=strict&it=500&fz=1&oq=1&ot=ff&fs=135109&zid=CICAgKDr6dq-rQEQARgBMghka4JuXreZig&na=688543307&cs=0 image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/img/uploader/pickupselection/180115_1_d.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3613000/3613771/220x165/12.jpg image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/img/uploader/pickupselection/20180115_sp_inu.jpg image
-http://www.txxx.com/ https://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/img/uploader/pickupselection/20180115_sp_game.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4517000/4517825/220x165/1.jpg image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/asset/js/main/common/site_wide.min.js?ec384768d650fbc0f30d50cbc8ae80a5 script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3682000/3682696/220x165/6.jpg image
-http://www.nicovideo.jp/ http://notification.nicovideo.jp/res/notify.js script
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/1499000/1499447/220x165/1.jpg image
-http://www.txxx.com/ https://mc.yandex.ru/watch/23578849/1?wmode=7&page-url=https%3A%2F%2Fm.txxx.com%2F&charset=utf-8&browser-info=ti%3A10%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Aw%3A360x512%3Az%3A-480%3Ai%3A20180115033426%3Aet%3A1516016067%3Aen%3Autf-8%3Av%3A938%3Ac%3A1%3Ala%3Aen-us%3Apv%3A1%3Als%3A880838125753%3Arqn%3A1%3Arn%3A267943705%3Ahid%3A750845310%3Ads%3A0%2C0%2C472%2C302%2C2039%2C0%2C0%2C4413%2C118%2C%2C%2C%2C7847%3Afp%3A5486%3Awn%3A3421%3Ahl%3A3%3Arqnl%3A1%3Ast%3A1516016067%3Au%3A1516016067149798111%3At%3APorn%20tube%2C%20free%20sex%20videos%2C%20XXX%20tube%20-%20Txxx.com%20-%20XXX%20Tube script
-http://www.nicovideo.jp/ http://embed.enquete.nicovideo.jp/static/js/enquete.js script
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32557503 image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/assets/img/top/noimage_newsblomaga.png image
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32578878 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3625000/3625270/220x165/5.jpg image
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32488250 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4744000/4744665/220x165/8.jpg image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/bannertext?bannerid=37964&zoneid=614& html
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3690000/3690361/220x165/2.jpg image
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32576520 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3434000/3434689/220x165/5.jpg image
-http://www.nicovideo.jp/ https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2?v=4.7.0 font
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32570320 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3641000/3641563/220x165/9.jpg image
-http://www.nicovideo.jp/ http://nicolive.cdn.nimg.jp/live/simg/img/a431/1290921.7654ab.jpg image
-http://www.nicovideo.jp/ http://nicolive.cdn.nimg.jp/live/simg/img/a447/1340743.f67d8e.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4826000/4826387/220x165/1.jpg image
-http://www.txxx.com/ https://mc.yandex.ru/metrika/advert.gif image
-http://www.nicovideo.jp/ http://nicolive.cdn.nimg.jp/live/simg/img/a450/1349706.67bd84.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3527000/3527065/220x165/2.jpg image
-http://www.nicovideo.jp/ http://nicolive.cdn.nimg.jp/live/simg/img/a450/1347947.1694ae.jpg image
-http://www.txxx.com/ https://mc.yandex.ru/watch/23578849?page-url=https%3A%2F%2Fm.txxx.com%2F&charset=utf-8&force-urlencoded=1&browser-info=ti%3A1%3As%3A360x512x24%3Ask%3A3%3Afpr%3A216613626101%3Acn%3A1%3Az%3A-480%3Ai%3A20180115033427%3Aet%3A1516016067%3Aen%3Autf-8%3Av%3A938%3Ac%3A1%3Ala%3Aen-us%3Aar%3A1%3Apa%3A1%3Als%3A880838125753%3Arqn%3A2%3Arn%3A263679862%3Ahid%3A750845310%3Ads%3A%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%2C%3Arqnl%3A1%3Ast%3A1516016069%3Au%3A1516016067149798111 image
-http://www.nicovideo.jp/ http://sp.nicovideo.jp/api/recommended_video html
-http://www.nicovideo.jp/ http://spad.i-mobile.co.jp/script/adssp.js?20110215 script
-http://www.nicovideo.jp/ http://img.cdn.nimg.jp/s/niconews/articles/images/3215650/a624c43a121dc9f7553cd61cc989a97c2ad425ad09935c521051a900c1b12b6938ad96d0cd4005d02361ce6e93ab73b0b91a7730c0a5f7d6caeaca2187da7c44/110x110s_FFFFFFFF?key=e8c39dce59199ca54e364caa5f27a59db5b4b44d3455d910df3856f766c602a4 image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4738000/4738889/220x165/8.jpg image
-http://www.nicovideo.jp/ http://img.cdn.nimg.jp/s/niconews/articles/images/3214795/70262883eb4b43c7bbeb4d14f50d30746f718d82cf248e66911a0e36c895eb7cb8748ef1c76dfff36377e17174d7dd96196a831536571ca7ddcab293effc1b0d/110x110s_FFFFFFFF?key=3428631cff4e8d446095634b08bc8c1ea1f1d12e31685522de2854011d0154ee image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4581000/4581197/220x165/7.jpg image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4940000/4940451/220x165/3.jpg image
-http://www.nicovideo.jp/ http://img.cdn.nimg.jp/s/niconews/articles/images/3214299/2fc3400c11d4673b099cccdececf90f3ae3c7c5f232187dd046782ad8f8d849c21d197c54016030b9a9f0556c2371bfa55939eab68c090fb5e7ee51f34729e4a/110x110s_FFFFFFFF?key=68d59d25c23f57095be0b001d24fbafdb2ae729d0a0abd5b6123b6fef0a3661c image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/4940000/4940433/220x165/3.jpg image
-http://www.nicovideo.jp/ http://img.cdn.nimg.jp/s/niconews/articles/images/3214375/18acaea788ebdf54e446ea9e6e805a4e1cf953b1abc8bb7d7266612ca37de05573f52d21918424fd975d6844e076c8187b035c7eaf518f3fe4cf3822462a8da4/110x110l_FFFFFFFF?key=7df1deacb6eca07ac05a7f8c373428b621ce64e22e14983187050c197c13327b image
-http://www.txxx.com/ https://11268780.pix-cdn.org/contents/videos_screenshots/3610000/3610000/220x165/6.jpg image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/api/OxBannerService/getAdvertisements.jsonp?zone=613&category=&pageurl=http%3A%2F%2Fsp.nicovideo.jp%2F&pagevariant=&callback=ads_callback_0&_=1516015994550 script
-http://www.txxx.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-51278971-3&cid=702883325.1516016066&jid=2013218688&_gid=1153959672.1516016066&gjid=1887847620&_v=j66&z=464730238 image
-http://www.nicovideo.jp/ http://articleimage.nicoblomaga.jp/thumb/307/2018/3/6/104836.jpg image
-http://www.txxx.com/ https://m.txxx.com/images/newicons/favicon-32x32.png image
-http://www.nicovideo.jp/ http://articleimage.nicoblomaga.jp/thumb/164/2018/5/2/70752.jpg image
-http://www.txxx.com/ https://m.txxx.com/images/newicons/favicon-16x16.png image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/img/common/logo_jasrac.png image
-http://www.nicovideo.jp/ http://swch.nimg.jp/img/system/article_thumbnail/ch2584365/1402316 other
-http://www.txxx.com/ https://m.txxx.com/images/newicons/favicon-96x96.png image
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32422622 image
-http://www.txxx.com/ https://m.txxx.com/images/newicons/android-chrome-192x192.png image
-http://www.nicovideo.jp/ http://ssp-bidder.i-mobile.co.jp/script/sspcore_spot.js?20130501 script
-http://www.txxx.com/ https://m.txxx.com/images/newicons/favicon-194x194.png image
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32521928 image
-http://www.nicovideo.jp/ https://www.googletagmanager.com/gtm.js?id=GTM-KXT7G5G&l=NicoGoogleTagManagerDataLayer script
-http://www.nicovideo.jp/ https://secure-dcdn.cdn.nimg.jp/comch/channel-icon/128x128/ch933.jpg?1464065929 image
-http://www.nicovideo.jp/ https://secure-dcdn.cdn.nimg.jp/comch/channel-icon/128x128/ch2628072.jpg?1480911025 image
-http://www.nicovideo.jp/ https://secure-dcdn.cdn.nimg.jp/comch/channel-icon/128x128/ch222.jpg?1499706952 image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/bannertext?bannerid=52375&zoneid=613& html
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/api/OxBannerService/logImpression?bannerid=37964&zoneid=614&_=1516015995211 text
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32539948 image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/api/OxBannerService/getAdvertisements.jsonp?zone=461&category=&pageurl=http%3A%2F%2Fsp.nicovideo.jp%2F&pagevariant=&callback=ads_callback_2&_=1516015996045 script
-http://www.nicovideo.jp/ http://tn.smilevideo.jp/smile?i=32523732 image
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/api/OxBannerService/logImpression?bannerid=52375&zoneid=613&_=1516015997594 text
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/bannertext?bannerid=35106&zoneid=461& html
-http://www.nicovideo.jp/ http://ssp-bidapi-n2.i-mobile.co.jp/jsonp/ssp_spot.ashx?pid=6107&asid=185725&asn=1&spec=1&dpr=3&sf=0&pos=0&imcallback=_imcallback_185725_1&cashid=1516015997976 script
-http://www.nicovideo.jp/ http://ads.nicovideo.jp/api/OxBannerService/logImpression?bannerid=35106&zoneid=461&_=1516015998482 text
-http://www.nicovideo.jp/ http://spad.i-mobile.co.jp/script/adssp.js?20110215 script
-http://www.nicovideo.jp/ http://spad.i-mobile.co.jp/script/adcore_sp_inline-0.2.js?20110201 script
-http://www.nicovideo.jp/ http://js1.nend.net/js/nendAdLoader.js script
-http://www.nicovideo.jp/ http://ssp-bidder.i-mobile.co.jp/script/sspcore_spot.js?20130501 script
-http://www.nicovideo.jp/ http://js.ptengine.jp/pta.js script
-http://www.nicovideo.jp/ http://js.ptengine.jp/pts.js script
-http://www.nicovideo.jp/ http://ssp-bidapi-n2.i-mobile.co.jp/jsonp/ssp_spot.ashx?pid=6107&asid=155353&asn=1&spec=1&dpr=3&sf=0&pos=0&imcallback=_imcallback_155353_1&cashid=1516015999628 script
-http://www.nicovideo.jp/ https://www.google-analytics.com/analytics.js script
-http://www.nicovideo.jp/ http://js.ptengine.jp/22c266ff.js script
-http://www.nicovideo.jp/ http://xid.i-mobile.co.jp/RestoreXidToMediaStorage.html html
-http://www.nicovideo.jp/ http://spad.i-mobile.co.jp/script/adcore_sp_inline-0.2.js?20110201 script
-http://www.nicovideo.jp/ http://spsvcsp.i-mobile.co.jp/ajax/ad_spot.ashx?pid=6107&asid=185725&asn=1&ver=0.2.1&dpr=3 text
-http://www.nicovideo.jp/ http://ad2.nend.net/feed.php?media=1182&site=5271&spot=208015&type=1&oriented=1&target=_top&cb=57211625497082540 script
-http://www.nicovideo.jp/ https://www.google-analytics.com/plugins/ua/linkid.js script
-http://www.nicovideo.jp/ http://spsvcsp.i-mobile.co.jp/ajax/ad_spot.ashx?pid=6107&asid=155353&asn=1&ver=0.2.1&dpr=3 text
-http://www.nicovideo.jp/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1413456097&t=screenview&_s=1&cd=sp.nicovideo.jp&dl=http%3A%2F%2Fsp.nicovideo.jp%2F&ul=en-us&de=UTF-8&dt=niconico&sd=24-bit&sr=360x512&vp=360x512&je=0&an=%E3%83%8B%E3%82%B3%E3%83%8B%E3%82%B3%E5%8B%95%E7%94%BB%EF%BC%88Spweb%EF%BC%89&av=1.0.0&aid=nicovideo_spweb&_u=aGDAAEIh~&jid=1603943134&gjid=564381002&cid=1627414842.1516016000&tid=UA-88451119-7&_gid=1696552225.1516016000&_r=1&cd1=%2F&cd25=not_login&cd49=&cd52=http%3A%2F%2Fsp.nicovideo.jp%2F&cd55=&cd58=sp.nicovideo.jp&cd61=null&cd70=sp.nicovideo.jp&cd73=%2F&z=1145416957 html
-http://www.nicovideo.jp/ https://cs.nex8.net/precs/nend other
-http://www.nicovideo.jp/ http://spcdnsp.i-mobile.co.jp/ad_creative.ashx?advid=4354854&eid=14 image
-http://www.nicovideo.jp/ http://spcdnsp.i-mobile.co.jp/ad_creative.ashx?advid=4438030&eid=4 image
-http://www.nicovideo.jp/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-88451119-7&cid=1627414842.1516016000&jid=1603943134&_gid=1696552225.1516016000&gjid=564381002&_v=j66&z=1145416957 image
-http://www.nicovideo.jp/ https://cs.nend.net/cs.php?nex_uid=d024ea7a-79a5-42f6-9533-98f306ca42d9 html
-http://www.nicovideo.jp/ http://collect.ptengine.jp/pn?id=22c266ff.6437nJ04eAHZOEwBxyTggA.9WJV6Qn--uF2bGV3ALSlVg.HjLpAqhfGJZk9xp5--gs5A.GqqJKRkMIETUpWRzoSQbGw&stat=1.0.512.512.4079.0&ref=&p=http%3A%2F%2Fsp.nicovideo.jp&tl=niconico&ptif=1.360.512.24.GMT-8.linux%20x86_64.en-us.utf-8&v=v1.36.0&ts=1516016002845 html
-http://www.nicovideo.jp/ https://cs.nex8.net/cs/nend?uid=0888f431405adbdc05db9d740232e44e image
-http://www.nicovideo.jp/ http://sp.res.nimg.jp/img/favicon.ico image
-http://www.xnxx.com/ http://www.xnxx.com/ html
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-be52aaa478e/v3/css/xnxx/front.css css
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-e510aaa8d1d/v3/js/skins/min/xnxx.header.static.js script
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-0bc3e845fbd/v3/js/skins/min/xnxx.footer.static.js script
-http://www.xnxx.com/ http://static-hw.xvideos.com/v3/js/libs/jquery.min.js script
-http://www.xnxx.com/ http://static-hw.xvideos.com/v3/js/skins/min/require.static.js script
-http://www.xnxx.com/ http://static-hw.xvideos.com/v3/img/skins/xnxx/logo-xnxx.png image
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-1937087c8d6/v3/js/i18n/front/english.json script
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-00000000004/v3/img/skins/xnxx/icons-sprite.svg image
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-be52aaa478e/v3/img/flags/flat/flags-32.png image
-http://www.xnxx.com/ http://static-hw.xvideos.com/img/lightbox/lightbox-blank.gif image
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-be52aaa478e/v3/img/skins/xnxx/top-stripe.png image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/dd/bb/dd/ddbbddaa8248e6d73ce028d1523a549a/ddbbddaa8248e6d73ce028d1523a549a.7.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/72/55/3c/72553c083c6eddab2abbf0197dc0554e/72553c083c6eddab2abbf0197dc0554e.11.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/5a/18/be/5a18beb8a66aaff14b341118567201da/5a18beb8a66aaff14b341118567201da.15.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/19/5b/fb/195bfbe6378e86f22de303c7bd4467b6/195bfbe6378e86f22de303c7bd4467b6.10.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/c3/7e/78/c37e7857438d10570865fb05330801d4/c37e7857438d10570865fb05330801d4.11.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/93/26/8a/93268a9cbd52c9e4e687afde96e61e02/93268a9cbd52c9e4e687afde96e61e02.28.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/59/70/ce/5970ceda6df9e64f2da92b865c783c03/5970ceda6df9e64f2da92b865c783c03.1.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/15/77/3d/15773dffa914f11f1e58c05f8db29eb3/15773dffa914f11f1e58c05f8db29eb3.3.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/52/b0/d0/52b0d034ff3a83b03194c4bccd856655/52b0d034ff3a83b03194c4bccd856655.26.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/50/a9/d4/50a9d44799ecbe9aa11f5bcc812fcdba/50a9d44799ecbe9aa11f5bcc812fcdba.15.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/18/8e/0c/188e0c5a90e8b37f361dcd0d09d30ee3/188e0c5a90e8b37f361dcd0d09d30ee3.12.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/41/82/f0/4182f0ec0b118042c8502817729fa1dd/4182f0ec0b118042c8502817729fa1dd.12.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/e0/36/f8/e036f8c64df75129722fba757e22a143/e036f8c64df75129722fba757e22a143.26.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/af/81/a8/af81a80c8357e5b96944deae55cecee9/af81a80c8357e5b96944deae55cecee9.13.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/b1/b6/2c/b1b62c9a548964ab9cbe3e97dac45405/b1b62c9a548964ab9cbe3e97dac45405.1.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/c3/6a/05/c36a0580cb390e420c5de63fb973c9ff/c36a0580cb390e420c5de63fb973c9ff.30.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/65/9a/3e/659a3eb330207ae075a10ab88e0adc72/659a3eb330207ae075a10ab88e0adc72.15.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/3a/b2/e2/3ab2e268dd7aa1f63dc79ad310d88db7/3ab2e268dd7aa1f63dc79ad310d88db7.4.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/da/72/81/da7281bcaf9de069ad3ea718912812b0/da7281bcaf9de069ad3ea718912812b0.12.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/7f/d8/8e/7fd88e2537ec4c6e12f2d89262d2d21b/7fd88e2537ec4c6e12f2d89262d2d21b.24.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/cc/a8/00/cca800cb3a486d917d1567e360c62895/cca800cb3a486d917d1567e360c62895.1.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/50/7a/4b/507a4b4aaf3ab05ae16bc641774d2540/507a4b4aaf3ab05ae16bc641774d2540.12.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/6e/b7/13/6eb7138b7fa6bc030adbd138cf653d43/6eb7138b7fa6bc030adbd138cf653d43.29.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/40/4d/f9/404df94a93a20a392f9d95ab4cfd4d57/404df94a93a20a392f9d95ab4cfd4d57.14.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/6b/7d/8c/6b7d8c07c19ba9980af0a1d8635f91c3/6b7d8c07c19ba9980af0a1d8635f91c3.9.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/bf/07/df/bf07df20d718cb27ef04da534058d8b6/bf07df20d718cb27ef04da534058d8b6.22.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/d3/73/fe/d373fe2de5ae5e911f88bc49fa7fe866/d373fe2de5ae5e911f88bc49fa7fe866.20.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/2c/8e/09/2c8e09c9bf7c0edc494ddf3cb3874689/2c8e09c9bf7c0edc494ddf3cb3874689.7.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/40/d2/23/40d223245858786dc2f619b32c3160d3/40d223245858786dc2f619b32c3160d3.14.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/20/90/95/209095228bf17e838c7e1155816dfa7d/209095228bf17e838c7e1155816dfa7d.3.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/47/22/e9/4722e9ae4a2c437b30d1ef4995711015/4722e9ae4a2c437b30d1ef4995711015.3.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/33/d6/65/33d66522d8ee5f6f8f567a8e924c45af/33d66522d8ee5f6f8f567a8e924c45af.12.jpg image
-http://www.xnxx.com/ http://images-llnw.xnxx-cdn.com/videos/thumbs169xnxxll/02/cc/6a/02cc6a5d503d1fce177bb1ff154dbc9f/02cc6a5d503d1fce177bb1ff154dbc9f.26.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/85/72/b9/8572b9990fb316da58c86f6f03c37201/8572b9990fb316da58c86f6f03c37201.11.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/ef/df/73/efdf737809441371f95ae8028d3d1d55/efdf737809441371f95ae8028d3d1d55.5.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/13/9d/76/139d76091d1d24687309d9b385a89b6a/139d76091d1d24687309d9b385a89b6a.29.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/7b/16/36/7b16366ab51bfcd11146dbefb50d2749/7b16366ab51bfcd11146dbefb50d2749.2.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/83/9d/62/839d62dd57b3f65210a1c415250c0c7b/839d62dd57b3f65210a1c415250c0c7b.9.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/c9/8d/9c/c98d9c94de12089d4888d5f9627ed22f/c98d9c94de12089d4888d5f9627ed22f.30.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/58/a3/74/58a3749e6402454ad52208eb7c662904/58a3749e6402454ad52208eb7c662904.9.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/63/97/de/6397defbc636e7d8961a8053abba126a/6397defbc636e7d8961a8053abba126a.29.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/1f/cd/d6/1fcdd64e8fe613650667aeb9e343c696/1fcdd64e8fe613650667aeb9e343c696.27.jpg image
-http://www.xnxx.com/ http://img-egc.xnxx-cdn.com/videos/thumbs169xnxxll/18/cc/93/18cc93c33c9a0646366b68985272d707/18cc93c33c9a0646366b68985272d707.1.jpg image
-http://www.xnxx.com/ http://images-llnw.xnxx-cdn.com/videos/thumbs169xnxxll/39/25/f4/3925f4677c15556d0baabad36f9958ea/3925f4677c15556d0baabad36f9958ea.16.jpg image
-http://www.xnxx.com/ http://img-l3.xvideos.com/videos/thumbs169xnxxll/16/2e/02/162e0251a52bc71d617d18c284277351/162e0251a52bc71d617d18c284277351.20.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/6e/c9/02/6ec9025ddcaf2fa919cb6b0193bc2a57/6ec9025ddcaf2fa919cb6b0193bc2a57.20.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/50/93/4f/50934f98cd753c0059f9aebf047422e7/50934f98cd753c0059f9aebf047422e7.3.jpg image
-http://www.xnxx.com/ http://img-hw.xnxx-cdn.com/videos/thumbs169xnxxll/2b/b3/13/2bb313edde4f16e6a25ad1ff5e651732/2bb313edde4f16e6a25ad1ff5e651732.12.jpg image
-http://www.xnxx.com/ http://www.xnxx.com/in.php?referer= html
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-7726f46fee1/v3/js/skins/min/xnxx.js script
-http://www.xnxx.com/ http://static-hw.xvideos.com/v3/img/skins/xnxx/xnxx-inline-loader.gif image
-http://www.xnxx.com/ http://static-hw.xvideos.com/v-7726f46fee1/v3/js/jquery.js script
-http://www.xnxx.com/ http://www.xnxx.com/favicon-32x32.png image
-http://www.xnxx.com/ http://rpc-php.trafficfactory.biz/json/footermobile-hometopfooter-1xfootermobile-footerhome-1///xvideos///content.json?v=0.07186369596491726 script
-http://www.xnxx.com/ http://www.xnxx.com/favicon-16x16.png image
-http://www.xnxx.com/ http://media.trafficfactory.biz//banners/d3/ae/45/23bd1778e32ac23e2072725c8feb2fde.gif image
-http://www.xnxx.com/ http://media.trafficfactory.biz//banners/b1/f5/76/8149df4c6d6d8e7202a1038b38ca1156.gif image
-http://www.amazon.in/ http://www.amazon.in/ html
-http://www.amazon.in/ https://www.amazon.in/ html
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41MjpWujmTL.css?AUIClients/GWMWebAssets css
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/gno/sprites/sky_webnav_V1_sprite_1x._CB489388130_.png image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:258-3052532-8836428:A1PXVCAS6W0VFW9H1VPG$uedata=s:%2Fuedata%2Funsticky%2F258-3052532-8836428%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3DA1PXVCAS6W0VFW9H1VPG%26pty%3DError%26spty%3DPageNotFound%26pti%3D:1000 image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51jo%2BAP3U9L._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset css
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/312aj6HKNXL.js?AUIClients/INRetargetingAsset script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61-dJ29Zw5L.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,51nK0kUyg2L.js,11Mdh5CVmhL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61IUvg6RIjL.js,31y9nF9Z1BL.js,11SW3HEKjtL.js,01qkmZhGmAL.js,01eORIy6e6L.js_.js?AUIClients/AmazonUI script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C415yFUsUARL.js,11P4Lu1aIqL.js_.js?AUIClients/GWMWebAssets script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets script
-http://www.amazon.in/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-a3d92a134e6afaec4974bceac0812b73d0b635c1._V2_.png image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41XJlIDdUUL._RC%7C01vojWHr8gL.js,31qKd4DgPkL.js_.js?AUIClients/NavMobileMetaAsset script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/510wwe1qMUL.js?AUIClients/RetailSearchAutocompleteAssets script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41Z%2Buac%2BsbL.js?AUIClients/QTipsMobileWebAssets script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41MARIMx46L._AC_SY200_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/418bKeWQoLL._AC_SY200_.jpg image
-http://www.amazon.in/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2 font
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51jLQluqieL._AC_SY200_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41Fii%2BJs3iL._AC_SY200_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41MARIMx46L._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/418bKeWQoLL._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51jLQluqieL._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41RluvmrWTL._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41Fii%2BJs3iL._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41OhlHGAyuL._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51dO%2B9RvvlL._AC_SY80_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41iBdPtqUkL._AC_SY80_.jpg image
-http://www.gmw.cn/ http://www.gmw.cn/ html
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41gX6UYI6hL._AC_SY80_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/css/2012_index.css css
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51a53pEvOdL._AC_SY80_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/js/jquery.js script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/419nj33gGlL._AC_SY80_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/js/gmw_index.js script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51MIkN4kypL._AC_SY80_.jpg image
-http://www.gmw.cn/ http://afpmm.alicdn.com/g/mm/afp-cdn/JS/k.js script
-http://www.amazon.in/ https://www.amazon.in/gp/aw/qtips/configs.html script
-http://www.gmw.cn/ http://img.gmw.cn/2010/2011search.gif image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41gA0e7UMvL._AC_SY80_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/3720.files/images/logo.gif image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img17/Watches/Dec/EOSS/GW/1092815_EOSS_watches_1242x450_BB_1a._SX414_CB489815253_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/pic/gmmlogo.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/Mobile/BrowseCard/294x570_Mobile-v2._CB274297397_SX98_SY190_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/plugins/superslide/js/jquery.SuperSlide.2.1.1.js script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/Mobile/BrowseCard/294X570_Fashion-v4._CB271274073_SX98_SY190_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/headerBg.gif image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/Mobile/BrowseCard/294x570_HnK-v2._CB274297397_SX98_SY190_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/pic/skypelogo.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/app/sweeps/Spin-wheel/Revised-2/1242X450_2._SX1242_CB490130519_.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img18/X-site/Sunrise18/TeaserGW/GW_Mob-hero_1242x550_Jan-Art-teaser_2._SX1242_CB489356582_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/pic/weizhanlogo_GMWindex.png image
-http://www.amazon.in/ https://www.amazon.in/gp/aw/mshop/qtips.html?page=gateway&url=https%3A%2F%2Fwww.amazon.in%2F&trafficType=DIRECT script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea48e1bc652fb31.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/gif/site2/20180115/f44d305ea14a1bc69ac707.gif image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/HVA/NCtrust/ingress/nc_trust_mob_1._SX1242_CB294950052_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20171223/f44d305ea12e1ba85d970a.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41MARIMx46L._AC_SY600_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20170727/f44d307589141ae3d98618.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/418bKeWQoLL._AC_SY600_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmpic.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51jLQluqieL._AC_SY600_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea0ab1bc641c126.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41Fii%2BJs3iL._AC_SY600_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea0ab1bc643db29.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41MARIMx46L._AC_SY240_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20160816index_260x50.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/418bKeWQoLL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20130828whsz.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51jLQluqieL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20130828szjy.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41Fii%2BJs3iL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20131115zhang.gif image
-http://www.amazon.in/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/984527532/?value=1&label=r_58CJXm0gIQw9iz3gM&guid=ON&script=0&data=ecomm_pagetype%3DMsite_Gateway%3BCURRENT_TIME%3D2018-01-15T11%3A34%3A00.009Z%3BSignedIn%3DN image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20130828ksxdh.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41RluvmrWTL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20160816wljbAPP.jpg image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OE/ other
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41OhlHGAyuL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea0ab1bc642e627.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51dO%2B9RvvlL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea0ab1bc654b73d.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41iBdPtqUkL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea0ab1bc6433828.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41gX6UYI6hL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180109/f44d30758a831bbe5a3601.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51a53pEvOdL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52772341&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016034143&fs=0&pvid=adb7f0496832fa6c102f44fdf78a44dc&cg=a4e6ba21006dfdcff570eff6d012febc script
-http://www.amazon.in/ https://www.google.com/ads/user-lists/984527532/?value=1&label=r_58CJXm0gIQw9iz3gM&guid=ON&script=0&data=ecomm_pagetype%3DMsite_Gateway%3BCURRENT_TIME%3D2018-01-15T11%3A34%3A00.009Z%3BSignedIn%3DN&cdct=2&is_vtc=1&random=863625803 image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/419nj33gGlL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/png/site2/20180115/f44d30758a3a1bc69f5e02.png image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51MIkN4kypL._AC_SY240_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/2010/zhuyeshexiangji.gif image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20140306wenmingzjg.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/41gA0e7UMvL._AC_SY160_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20170306jtjkez.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img17/Watches/Dec/EOSS/GW/1092815_EOSS_watches_1242x450_BB_1a._SX1242_CB489815253_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20151222_150x47.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/Mobile/BrowseCard/294x570_Mobile-v2._CB274297397_SX294_SY570_.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20151222_150x50.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/Mobile/BrowseCard/294X570_Fashion-v4._CB271274073_SX294_SY570_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/index_banner/20170309wsyhxxjbzq_260x90.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/img16/Xsite/Mobile/BrowseCard/294x570_HnK-v2._CB274297397_SX294_SY570_.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d307589931bc602cf01.jpg image
-http://www.amazon.in/ https://www.amazon.in/uedata/unsticky/258-3052532-8836428/NoPageType/ntpoffrw?ld&v=0.1284.0&id=A1PXVCAS6W0VFW9H1VPG&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=A1PXVCAS6W0VFW9H1VPG&ue=13&bb=1508&ns=1518&cf=1632&be=1709&af=1729&ne=1868&pc=9213&tc=-2731&na_=-2731&ul_=-1516016034384&_ul=-1516016034384&rd_=-1516016034384&_rd=-1516016034384&fe_=-1290&lk_=-1289&_lk=-1289&co_=-1289&_co=-662&sc_=-989&rq_=-660&rs_=-75&_rs=540&dl_=-65&di_=1718&de_=1718&_de=1718&_dc=9213&ld_=9213&_ld=-1516016034384&ntd=0&ty=0&rc=0&hob=6&hoe=13&ld=9215&t=1516016043599&ctb=1&rt=cf:1-0-1-0-1-0-0_af:1-0-1-0-1-0-0_ld:62-7-2-48-5-0-1&csmtags=aui|aui:aui_build_date:3.17.20-2017-12-07|gwImgNoCached|fls-eu|pageEncoding:UTF-8|gwmNoCardHistory|aui:ajax&viz=visible:13&pty=gateway-phone-web&spty=smartphone-card-unrec&pti=mobile&tid=A1PXVCAS6W0VFW9H1VPG&aftb=1 image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea6dd1bc64c835b.jpg image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:258-3052532-8836428:A1PXVCAS6W0VFW9H1VPG$uedata=s:%2Fuedata%2Funsticky%2F258-3052532-8836428%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DA1PXVCAS6W0VFW9H1VPG%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D240%26cf0%3D1492%26pc0%3D1494%26ld0%3D1494%26t0%3D1516016035878%26sc1%3Dlg%26af1%3D1632%26pc1%3D1632%26ld1%3D1632%26t1%3D1516016036016%26sc2%3DcsmCELLSframework%26bb2%3D1700%26pc2%3D1700%26ld2%3D1700%26t2%3D1516016036084%26sc3%3DcsmCELLSpdm%26bb3%3D1700%26pc3%3D1705%26ld3%3D1705%26t3%3D1516016036089%26sc4%3DcsmCELLSvpm%26bb4%3D1705%26pc4%3D1705%26ld4%3D1705%26t4%3D1516016036089%26sc5%3DcsmCELLSfem%26bb5%3D1706%26pc5%3D1706%26ld5%3D1706%26t5%3D1516016036090%26sc6%3Dinteractivity%26cf6%3D2680%26pc6%3D2680%26ld6%3D2680%26t6%3D1516016037064%26ctb%3D1:9226 image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea4b61bc6489e33.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180108/f44d305ea48e1bbcf35a4e.jpg image
-http://www.amazon.in/ https://m.media-amazon.com/images/G/01/csm/showads.v2.js script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20171201/f44d307589141b8b31d618.jpg image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:258-3052532-8836428:A1PXVCAS6W0VFW9H1VPG$uedata=s:%2Fuedata%2Funsticky%2F258-3052532-8836428%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DA1PXVCAS6W0VFW9H1VPG%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D9243%26pc0%3D9243%26ld0%3D9243%26t0%3D1516016043627%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card-unrec%26pti%3Dmobile%26tid%3DA1PXVCAS6W0VFW9H1VPG%26aftb%3D1:9243 image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/chinaso.png image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:258-3052532-8836428:A1PXVCAS6W0VFW9H1VPG$uedata=s:%2Fuedata%2Funsticky%2F258-3052532-8836428%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DA1PXVCAS6W0VFW9H1VPG%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D9271%26cf0%3D9280%26pc0%3D9280%26ld0%3D9280%26t0%3D1516016043664%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card-unrec%26pti%3Dmobile%26tid%3DA1PXVCAS6W0VFW9H1VPG%26aftb%3D1:9280 image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/20121123sp.jpg image
-http://www.amazon.in/ https://www.amazon.in/favicon.ico image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/G/31/gno/sprites/sky_webnav_V1_sprite_2x._CB489388157_.png image
-http://www.gmw.cn/ http://img.gmw.cn/pic/index_hotnews_next.png image
-http://www.thepiratebay.org/ http://www.thepiratebay.org/ other
-http://www.amazon.in/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2 font
-http://www.thepiratebay.org/ https://www.thepiratebay.org/ html
-http://www.amazon.in/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2 font
-http://www.gmw.cn/ http://ad.gmw.cn/html/indexbanner_728_1_20171228.html html
-http://www.thepiratebay.org/ http://m.thepiratebay.org/ html
-http://www.amazon.in/ https://www.amazon.in/uedata/unsticky/258-3052532-8836428/NoPageType/ntpoffrw?at&v=0.1284.0&id=A1PXVCAS6W0VFW9H1VPG&m=1&sc=adblk_no&pc=9602&at=9602&t=1516016043986&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card-unrec&pti=mobile&tid=A1PXVCAS6W0VFW9H1VPG&aftb=1 image
-http://www.gmw.cn/ http://img.gmw.cn/pic/index_hotnews_prev.png image
-http://www.thepiratebay.org/ http://m.thepiratebay.org/stylesheets/layout-min.css css
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/shadow_x.gif image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:258-3052532-8836428:A1PXVCAS6W0VFW9H1VPG$uedata=s:%2Fuedata%2Funsticky%2F258-3052532-8836428%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3DA1PXVCAS6W0VFW9H1VPG%26m%3D1%26sc%3Dadblk_no%26pc%3D9602%26at%3D9602%26t%3D1516016043986%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card-unrec%26pti%3Dmobile%26tid%3DA1PXVCAS6W0VFW9H1VPG%26aftb%3D1:9603 image
-http://www.thepiratebay.org/ http://m.thepiratebay.org/stylesheets/base-min.css css
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmwply.gif image
-http://www.thepiratebay.org/ http://m.thepiratebay.org/stylesheets/skeleton-min.css css
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/hot1.gif image
-http://www.thepiratebay.org/ http://m.thepiratebay.org/stylesheets/tpb-min.css css
-http://www.amazon.in/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js script
-http://www.thepiratebay.org/ http://m.thepiratebay.org/js/script-min.js script
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/2012indexBg.gif image
-http://www.thepiratebay.org/ http://traffic.trafficposse.com/in/tpb-dialog-js.php script
-http://www.amazon.in/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2 font
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmy.jpg image
-http://www.thepiratebay.org/ http://m.thepiratebay.org/images/tpb.jpg image
-http://www.gmw.cn/ http://www.google-analytics.com/analytics.js script
-http://www.thepiratebay.org/ http://m.thepiratebay.org/images/kopimi.png image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/barName.gif image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OP/A21TJRUUN4KGV:258-3052532-8836428:A1PXVCAS6W0VFW9H1VPG$uedata=s:%2Fuedata%2Funsticky%2F258-3052532-8836428%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3DA1PXVCAS6W0VFW9H1VPG%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D10180%26pc0%3D10184%26ld0%3D10184%26t0%3D1516016044568%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card-unrec%26pti%3Dmobile%26tid%3DA1PXVCAS6W0VFW9H1VPG%26aftb%3D1:10184 image
-http://www.thepiratebay.org/ http://www.google-analytics.com/analytics.js script
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/shadow_y.gif image
-http://www.thepiratebay.org/ http://www.facebook.com/plugins/like.php?locale=en_US&href=http%3A%2F%2Fm.thepiratebay.se%2F&width=109&layout=button_count&action=like&show_faces=false&share=false&height=26 other
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea4821bc6526401.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/51jSEENgQYL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,01d8Fs5iBdL.css,21ZwnZnTQ7L.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,318hCTMRXQL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21g9AOmZB5L.css,11X2-nh0PYL.css,01h2e2BEitL.css,11AYjYP-YzL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31k72ulyOYL.css,01kPgnKe7wL.css,01MGoIPodIL.css,01Alnvtt1zL.css,01BBs40O5ZL.css_.css?AUIClients/AmazonUI css
-http://www.thepiratebay.org/ http://platform.twitter.com/widgets.js script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d30758a691bc6513d2e.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/31L-%2BMYhz%2BL._RC%7C31sa8-QczxL.css_.css?AUIClients/SharedShoppingCartMobileAsset css
-http://www.thepiratebay.org/ https://www.google-analytics.com/analytics.js script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180108/94c69122e4b71bbd7d4701.jpg image
-http://www.thepiratebay.org/ https://www.facebook.com/plugins/like.php?locale=en_US&href=http%3A%2F%2Fm.thepiratebay.se%2F&width=109&layout=button_count&action=like&show_faces=false&share=false&height=26 html
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/01iHNN%2BjGYL.css?AUIClients/QTipsMobileWebAssets css
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/94c69122e4131bc647f353.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/317Qb9WY18L._RC%7C51V43Ve3tjL.js_.js?AUIClients/SharedShoppingCartMobileAsset script
-http://www.thepiratebay.org/ https://www.facebook.com/rsrc.php/v3ijLc4/yX/l/en_US/wCJ2hAdlhFn.js script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/11chYsfG59L._RC%7C411E-IzoCiL.js,31cePTj3CrL.js,11NxOa490XL.js,31E+jMbvKeL.js,21ydeSYKyxL.js,31hd9A67kaL.js,51I687QY3CL.js,51Hi2VfLU+L.js,210slSxOYRL.js,31Ime9qWaBL.js,016DBHJkIYL.js,21ng+A1rTWL.js,41mcGVaoxHL.js,013JfcJrqrL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,41jvJSDExWL.js,11QIUl6VLbL.js,21AuBaN+lVL.js,51YzCqyJFIL.js,018maJmAE6L.js,01nKqcvaCIL.js,01X117Z9PgL.js,41ZS0DwSp8L.js,01wYyhYnnFL.js,518wG9hJ8NL.js,31egXBuM55L.js,01RHiyjONOL.js,31I-BifbuzL.js,210S22NrxIL.js,412fOjq25KL.js,314ZAgS3sJL.js,11U-t4vkrhL.js,21XRsSHl9HL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,51rCZ2WOe0L.js,71OuhyN2DxL.js,01BZK417f8L.js,319kjuuQkzL.js,01UujNMpLSL.js,41kgH1IIwSL.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,11-RA7FC-HL.js,11B4fwZPeqL.js,21-q-ofQTaL.js,01lQqh9VSML.js,01jqyAujTwL.js,01jW+SjLRsL.js,01ajh3SwkiL.js,01gaQLz1HjL.js,01NAT+3p7KL.js,111vgqp2a0L.js,51yQ7wSC4tL.js,01MZJG6lH8L.js,01VtYReatCL.js,21LWJ90NCIL.js,41Z+uac+sbL.js,01RQtSMdG+L.js,21JwQBfgBXL.js,31GRwNq+Z4L.js,01-Eu4U-17L.js,01qwoVEkKlL.js,011HXD1ky3L.js,21vSk+MGX1L.js,01IfU37ic3L.js,21hu9h-eycL.js,01ZF+ovNflL.js,31MsfX4iIYL.js,01S8y9NkxoL.js,01XzM3S0ZtL.js,01JGca-NkDL.js,01whO-slYAL.js,51tlWANRbLL.js_.js?AUIClients/DetailPageMobileWebMetaAsset script
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20171201_banner19_728.jpg image
-http://www.thepiratebay.org/ http://www.google-analytics.com/r/collect?v=1&_v=j66&a=458324319&t=pageview&_s=1&dl=http%3A%2F%2Fm.thepiratebay.org%2F&ul=en-us&de=UTF-8&dt=Download%20music%2C%20movies%2C%20games%2C%20software!%20The%20Pirate%20Bay%20-%20The%20galaxy%27s%20most%20resilient%20BitTorrent%20site&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAEAB~&jid=237503869&gjid=1066939692&cid=1358549389.1516016009&tid=UA-50103908-5&_gid=1266237608.1516016009&_r=1&z=1805018225 other
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets css
-http://www.thepiratebay.org/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=458324319&t=pageview&_s=1&dl=http%3A%2F%2Fm.thepiratebay.org%2F&ul=en-us&de=UTF-8&dt=Download%20music%2C%20movies%2C%20games%2C%20software!%20The%20Pirate%20Bay%20-%20The%20galaxy%27s%20most%20resilient%20BitTorrent%20site&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAEAB~&jid=237503869&gjid=1066939692&cid=1358549389.1516016009&tid=UA-50103908-5&_gid=1266237608.1516016009&_r=1&z=1805018225 image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20170720_zggcsy728x90.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/21RnT33X0YL.js?AUIClients/AutomotiveEUMobileAssets script
-http://www.thepiratebay.org/ https://www.facebook.com/rsrc.php/v3/yn/r/lH1ibRl5GKq.png image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180112/f44d307589311bc2be9316.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/010NMV%2Bm-jL.css?AUIClients/AutomotiveEUMobileAssets css
-http://www.thepiratebay.org/ https://platform.twitter.com/widgets/widget_iframe.9c00c8ca14a8618c4db8e2c43139b138.html?origin=http%3A%2F%2Fm.thepiratebay.org html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d3075897a1bc6422a29.jpg image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OE/ other
-http://www.thepiratebay.org/ https://platform.twitter.com/js/button.415474f2e22cee7df272249c34e8f0b1.js script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d30758a2f1bc651ca47.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41CNXGW6T4L.css,31+nspS61oL.css,31507pWpoGL.css,11tkAOwE6OL.css,21yQivNbm7L.css,11ISqSj9gHL.css,018pZJ+Ms7L.css,21LL5kV+OzL.css,219Fnsqi9WL.css,01FhhDKMwIL.css,01iAFIIjomL.css,21QwDiO8ycL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11D3rk4ez6L.css,01oETTPm7xL.css,21CNSKZ67ML.css,51oAYplAOyL.css,11JQZul2XRL.css,21lDMA2J74L.css,215tV0Xf4NL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,11UDdszadlL.css,21f0r7D13IL.css,61ypmw1UTGL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,016xTzXJLfL.css,31LBzl8T3vL.css,21cgaWigpnL.css,110QeNMe7yL.css,01YdhMxma0L.css,01urH7Slt6L.css,01zKZ9sec9L.css,018mGORJ7tL.css,11fvu+DzMxL.css,11ho+83HCzL.css,01ticFfm7pL.css,01iHNN+jGYL.css,01lh9w-GYYL.css,11Mso4bvY-L.css,01dDkofRjeL.css,21ihqRLi1VL.css,01LCsoCesOL.css,01ifu3nZXpL.css,21Yyo4tu6ZL.css_.css?AUIClients/DetailPageMobileWebMetaAsset css
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d30758a2f1bc654b848.jpg image
-http://www.thepiratebay.org/ https://platform.twitter.com/widgets/tweet_button.9c00c8ca14a8618c4db8e2c43139b138.en.html html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20170918/408d5cef628d1b29753e01.jpg image
-http://www.thepiratebay.org/ http://m.thepiratebay.org/images/favicon.ico image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d3075891c1bc642e800.jpg image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.in&slot=navFooter&a2=010132f504a7c4ba047f7886e27044026a6ac37b17391c91348084d82adfb8d4ee84&old_oo=0&cb=1516016034168 other
-http://www.thepiratebay.org/ https://syndication.twitter.com/i/jot html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/bc305bae436f1bc65c9653.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/311WURTXdbL.css?AUIClients/IDPMobileAssets css
-http://www.thepiratebay.org/ https://syndication.twitter.com/settings script
-http://www.gmw.cn/ http://cl.webterren.com/webdig.js?z=7 script
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/01keU37gh%2BL.js?AUIClients/DetailPageAlohaAssets script
-http://www.thepiratebay.org/ https://platform.twitter.com/jot.html html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d30758a761bc654441b.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/615AfPD8y4L.js?AUIClients/IDPMobileAssets script
-http://www.thepiratebay.org/ http://traffic.trafficposse.com/www/delivery/lg.php?bannerid=1961&campaignid=825&zoneid=303&loc=http%3A%2F%2Ftraffic.trafficposse.com%2Fin%2Ftpb-dialog-js.php&referer=http%3A%2F%2Fm.thepiratebay.org%2F&cb=302aa53c17 image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea4881bc693b925.jpg image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.in&slot=navFooter&a2=010132f504a7c4ba047f7886e27044026a6ac37b17391c91348084d82adfb8d4ee84&old_oo=0&cb=1516016034168&dcc=t html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/f44d305ea4881bc6499806.jpg image
-http://www.amazon.in/ https://images-eu.ssl-images-amazon.com/images/I/81MDTSEXQgL.js?AUIClients/GoldboxUDPAssets script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/b8ac6f4096f91bc64f6c01.jpg image
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/c03fd5535fbd1bc64d3035.jpg image
-http://www.gmw.cn/ https://www.google-analytics.com/analytics.js script
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/v3/pr?exlist=pp_sx_ns_kr_g_bsw_bk_ox_index_aold_an_rb_br_fbca_aolv_twca_y_pm_adelphic_adb&fv=1.0&ex-pl-fbca=W_voKBNLQlOFmQMQ5sDqFw&ex-pl-twca=Ezk7R3jwRoWUHGYgvyFOJA&a=cm&ep=olR0XsDwCdxYrMJ_ZfSoH8A1a-8BpQjzjra8y1hmFBQ8DUPQqC0VCixYnfkqy0eV html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/c03fd5535fbd1bc64d7436.jpg image
-http://www.amazon.in/ https://unagi-eu.amazon.com/1/events/com.amazon.csm.nexusclient.prod script
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/c03fd5535fbd1bc64dc337.jpg image
-http://www.amazon.in/ https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com%26 other
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/c03fd5535fbd1bc64dfe38.jpg image
-http://www.amazon.in/ https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm&ex=doubleclick.net& html
-http://www.gmw.cn/ http://img.gmw.cn/images/attachement/jpg/site2/20180115/c03fd5535fbd1bc64e4339.jpg image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=5k1ykCCfv8jm&ex=pulsepoint.com&&ev=&pid=557477 image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/yun_70x70.png image
-http://www.amazon.in/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__ html
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEP8-AeYqWlP8yQMDVDZmx0s&google_cver=1 image
-http://www.amazon.in/ https://aa.agkn.com/adscores/g.pixel?sid=9212284268 other
-http://www.amazon.in/ https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1 other
-http://www.amazon.in/ https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com%26 other
-http://www.amazon.in/ https://x.bidswitch.net/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.amazon.in/ https://usermatch.krxd.net/um/v2?partner=amzn other
-http://www.amazon.in/ https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.amazon.in/ https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1&verify=true other
-http://www.amazon.in/ https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.amazon.in/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1 html
-http://www.amazon.in/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID other
-http://www.amazon.in/ https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/cnnic.jpg image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=da13bd4c9418820b939fc976dae611358af2f602&ex=aoldisplay.com image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770682&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016037613&fs=4&pvid=a47cd946dc0b7c1d84f41781ffe69305&cg=ae6f2c01581899923620988655775736 script
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=index&id=Ew6mgIH4q1pwUlQctY1uNTcEcc04ZgAC image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/index_xm.gif image
-http://www.amazon.in/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=0a163510-f9e8-11e7-913f-180430d50001 other
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/close_icon.png image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=bidswitch.com&id=8dcc2a36c384c2a5f2bfb2a645173e81 image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmrbkhd.jpg image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=openx.com&id=c7cc8edb-9742-c253-2a34-16fb4e352cfc image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmrbfarenweibo.jpg image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=spotx.com&id=0a1690b9-f9e8-11e7-913f-180430d50001 image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmrbweixinkhd.jpg image
-http://www.amazon.in/ https://stags.bluekai.com/site/36841?dt=0&r=352673724&sig=266897515&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmih1xvl5HuFzEzhvgXwBlWkmnvTonDUnlAda0QjeWxo0q7s3LSrtVZ3O3f3O3jhe+8hTKsKQvjj3APxvsA7BnDf1H1i9Rp9W1JcNA= other
-http://www.gmw.cn/ http://www.google-analytics.com/collect?v=1&_v=j66&a=755701621&t=pageview&_s=1&dl=http%3A%2F%2Fwww.gmw.cn%2F&ul=en-us&de=UTF-8&dt=%E5%85%89%E6%98%8E%E7%BD%91_%E6%96%B0%E9%97%BB%E8%A7%86%E9%87%8E%E3%80%81%E6%96%87%E5%8C%96%E8%A7%86%E8%A7%92%E3%80%81%E6%80%9D%E6%83%B3%E6%B7%B1%E5%BA%A6%E3%80%81%E7%90%86%E8%AE%BA%E9%AB%98%E5%BA%A6&sd=24-bit&sr=360x512&vp=980x1393&je=0&_u=IGBAgEAB~&jid=585113534&gjid=437797801&cid=1308950974.1516016038&tid=UA-20947729-1&_gid=794116482.1516016038&z=1011757120 other
-http://www.amazon.in/ https://ib.adnxs.com/getuid?https://aax-eu.amazon-adsystem.com/s/ecm3?id=$UID&ex=appnexus.com& image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/ewm_gmym.gif image
-http://www.gmw.cn/ https://www.google-analytics.com/collect?v=1&_v=j66&a=755701621&t=pageview&_s=1&dl=http%3A%2F%2Fwww.gmw.cn%2F&ul=en-us&de=UTF-8&dt=%E5%85%89%E6%98%8E%E7%BD%91_%E6%96%B0%E9%97%BB%E8%A7%86%E9%87%8E%E3%80%81%E6%96%87%E5%8C%96%E8%A7%86%E8%A7%92%E3%80%81%E6%80%9D%E6%83%B3%E6%B7%B1%E5%BA%A6%E3%80%81%E7%90%86%E8%AE%BA%E9%AB%98%E5%BA%A6&sd=24-bit&sr=360x512&vp=980x1393&je=0&_u=IGBAgEAB~&jid=585113534&gjid=437797801&cid=1308950974.1516016038&tid=UA-20947729-1&_gid=794116482.1516016038&z=1011757120 image
-http://www.amazon.in/ https://d.agkn.com/pixel/8198/?che=1516016048&sk=164131202571000810148&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164131202571000810148&ex=neustar.biz other
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmrbapp_index_logo.jpg image
-http://www.amazon.in/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc html
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/code_gmrbfrwb_s.png image
-http://www.amazon.in/ https://token.rubiconproject.com/token?pid=2179&pt=n other
-http://www.amazon.in/ https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/code_gmrbwx_s.png image
-http://www.amazon.in/ https://tags.bluekai.com/site/2981?id=&google_gid=CAESEKPlq3u_xW-ayO6fCGxJa1w&google_cver=1 image
-http://www.amazon.in/ https://www.facebook.com/fr/r.php?p=558293300959460&e=W_voKBNLQlOFmQMQ5sDqFw&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dfbca%26id%3DW_voKBNLQlOFmQMQ5sDqFw&s=1516016047&h=M0NWR1RBZklDbTFoaWFvcJm57Sd5Z6RFnO-ENerXAvyLl_jg html
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmrb_wb_logo.png image
-http://www.amazon.in/ https://geo-um.btrll.com/v1/map_pixel/partner/63.png image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/gmrb_wx_logo.png image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=fbca&id=W_voKBNLQlOFmQMQ5sDqFw image
-http://www.gmw.cn/ http://img.gmw.cn/images/10101.files/images/11.png image
-http://www.amazon.in/ https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=Ezk7R3jwRoWUHGYgvyFOJA&twitter_redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dtwca%26id%3DEzk7R3jwRoWUHGYgvyFOJA%26 html
-http://www.gmw.cn/ http://cl3.webterren.com/1.gif?z=7&a=160f998eec4&b=%u5149%u660E%u7F51_%u65B0%u95FB%u89C6%u91CE%u3001%u6587%u5316%u89C6%u89D2%u3001%u601D%u60F3%u6DF1%u5EA6%u3001%u7406%u8BBA%u9AD8%u5EA6&B=UTF-8&c=http%3A//www.gmw.cn/%3F_wdxid%3D000000000000000000000000000000000000000000%26_wdc%3D0%26_wdt%3D012%26&d=&e=10&f=093594bcb512a9d5&H=www.gmw.cn&E=0&r=722d87df2c605da1&s=0&t=0&u=1&i=en-US&j=0&k=360x512&l=24&m=&n=&o=0 image
-http://www.amazon.in/ https://ads.yahoo.com/cms/v1?esig=1~6772d6d12bf5fd5c41ee5ef107d84db09124942a&nwid=10000936839&sigv=1 text
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770856&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016038140&fs=4&pvid=fe94da41c175f2e927c696f3af41b114&cg=a03dce713c3b0ada4bfabace75ad8a32 script
-http://www.amazon.in/ https://geo-um.btrll.com/v1/map_pixel/partner/63.png?set_aps=1&BR_APS=3WlyRsxJq8S8BSbvnBQ& image
-http://www.amazon.in/ https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D text
-http://www.gmw.cn/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-20947729-1&cid=1308950974.1516016038&jid=585113534&gjid=437797801&_gid=794116482.1516016038&_u=IGBAgEAB~&z=2068756218 image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?p_user_id=Ezk7R3jwRoWUHGYgvyFOJA&ex=twca&id=Ezk7R3jwRoWUHGYgvyFOJA image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768072&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016039163&fs=0&pvid=aea8efbd0962e70445099602d25e4288&cg=a37665cd46011afec73aa204845f1d0c script
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=rightmedia.com&xid=E0 image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=3WlyRsxJq8S8BSbvnBQ&ex=brightroll.com&n=1516016051& image
-http://www.gmw.cn/ http://afpmm.alicdn.com/g/mm/afp-cdn/JS/r.js script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768073&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016039801&fs=0&pvid=da9b9797155cffcb4538ee2e84185ba1&cg=a469284aa9165bca75aaada4ed93ea51 script
-http://www.amazon.in/ https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID html
-http://www.gmw.cn/ http://s.csbew.com/acookie.html html
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=aolvideo.com&id=b28196831127ab518f4f6ebfa80220fd0114e5f9 image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=FBE4BF43-2A16-482A-8E2A-E8358F1B3CF5&ex=pubmatic.com image
-http://www.gmw.cn/ http://afpssp.alimama.com/acookie.html html
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bfbf7c900005a5c91a7312e1dcdf6d4&pid=mm_113716014_12970037_52768072&cid=264583&mid=249945&oid=15131&productType=1&qytInfoMTime=1515957314&e=i35esrXQv0xfumWCnJqSgX3zsnWZJgka4Rj78hzCAm26zQ%2BS3PY%2FujLgt9k6XupY&k=65&cb=380346805 image
-http://www.amazon.in/ https://s.amazon-adsystem.com/ecm3?id=164131202571000810148&ex=neustar.biz image
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bfbf7c900005a5c91a7312e1dcdf6d4&pid=mm_113716014_12970037_52768072&cid=264583&mid=249945&oid=15131&productType=1&qytInfoMTime=1515957314&cb=270185964 image
-http://www.amazon.in/ https://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id image
-http://www.amazon.in/ https://sync.ipredictive.com/d/sync/cookie/generic?https://aax-eu.amazon-adsystem.com/s/ecm3?id=${ADELPHIC_CUID}&ex=adelphic other
-http://www.gmw.cn/ http://afp.alicdn.com/afp-creative/creative/u113716014/79924a241df6bff5536780213e1ecc94.jpg image
-http://www.amazon.in/ https://dpm.demdex.net/ibs:dpid=139200&dpuuid=9NRGxQlgSmKaenuvj9oWxA&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D other
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52772340&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016040990&fs=2&pvid=aaa9cb50af99f960d4c55fdb1b662077&cg=cda9d298cf720f27ae00c3cb4a40c39b script
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=025edeab-f9e8-11e7-992a-77162e1e688c&ex=adelphic image
-http://www.gmw.cn/ http://log.mmstat.com/w.gif?logtype=1&pre=http%3A%2F%2Fwww.gmw.cn%2F&cache=f6a8421&scr=360x512&cna=&isbeta=7& image
-http://www.amazon.in/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=9NRGxQlgSmKaenuvj9oWxA&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D image
-http://www.amazon.in/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=adobe.com&id=25820571867104089870353858325539476733 image
-http://www.gmw.cn/ http://log.mmstat.com/w.gif?logtype=1&pre=http%3A%2F%2Fwww.gmw.cn%2F&cache=29a9500&scr=360x512&cna=&isbeta=7& image
-http://www.amazon.in/ https://fls-eu.amazon.in/1/batch/1/OE/ other
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770055&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016041496&fs=1&pvid=a4ba71274ef7760eb8a8248da97b5340&cg=a0583a06033be947f70e488b4a381edb script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770080&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016042508&fs=1&pvid=a31ed30ac67aa0b677d9ea82936a8a2a&cg=ac7b82e9a13dbd68d11901cd6d9dd672 script
-http://www.gmw.cn/ http://cl3.webterren.com/3.gif?z=7&a=160f998eec4&c=http%3A//www.gmw.cn/&d=1428&k=S&H=www.gmw.cn&r=722d87df2c605da1 image
-http://www.gmw.cn/ http://pcookie.alimama.com/app.gif?&cna=qn/jEm3O13ICASO5z3/DEhVY image
-http://www.gmw.cn/ http://pcookie.csbew.com/app.gif?&cna=qn/jEtcmshECASO5z3/OYDmO image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768238&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016043039&fs=1&pvid=d0ba664213b1b372d0f77fdea21a5fd4&cg=a29d341ae503f736e2af3796540e4b12 script
-http://www.gmw.cn/ http://afpmm.alicdn.com/g/mm/afp-cdn/JS/e.js script
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20171226_wxzlsjh_728x90.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20171226_hongchuan_728x90.jpg image
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bfbf7cd00005a5c91ab787d1de579a6&pid=mm_113716014_12970037_52768238&cid=263183&mid=87911&oid=446&productType=1&qytInfoMTime=1515957311&e=HjWY1J6pSgpfumWCnJqSgZ%2BRS3Opw2aAxENf1%2Fyp9i4r%2BFSkc1WTmFKRvbrjBixd&k=65&cb=62713025 image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768241&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016045350&fs=1&pvid=a88d4861a83932887ece1bdaa33acc2e&cg=a2b8155d89a59a0529abb1d09d8f42ae script
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bfbf7cd00005a5c91ab787d1de579a6&pid=mm_113716014_12970037_52768238&cid=263183&mid=87911&oid=446&productType=1&qytInfoMTime=1515957311&cb=83015174 image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20160919_hr365_260x90.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20160809jkbj260.jpg image
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bb48d9a00005a5c91ad05d81dc261d7&pid=mm_113716014_12970037_52768241&cid=217738&mid=54295&oid=149&productType=1&qytInfoMTime=1515957310&e=K1d5I0dPqGTL3IkfTk3f2svSYwpc2nFfsmnn8vdfkWxRxx54e83bFJ2VtEHN2lFI&k=65&cb=222987305 image
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bb48d9a00005a5c91ad05d81dc261d7&pid=mm_113716014_12970037_52768241&cid=217738&mid=54295&oid=149&productType=1&qytInfoMTime=1515957310&cb=774479902 image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768230&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016045925&fs=2&pvid=fa3beb3864afc2d313949ad8cd45e894&cg=a95b4c7fe250cf6ae5e786806cd71998 script
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20171229_30qiang_728x90.jpg image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20171229_feiyi_728x90.jpg image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768242&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016046973&fs=2&pvid=aafcb98375ab560dd3857d83599cef95&cg=d4bc3c33a1416e122609e8b704554c9e script
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bb48dab00005a5c91ae6ff81dbec41a&pid=mm_113716014_12970037_52768230&cid=263940&mid=229046&oid=32786&productType=1&qytInfoMTime=1515957313&e=YOLefAi89vfL3IkfTk3f2s59wjJaD8F8RtrH19wHLL6azrjo1ldoWlc11l8Nffko&k=65&cb=428874350 image
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bb48dab00005a5c91ae6ff81dbec41a&pid=mm_113716014_12970037_52768230&cid=263940&mid=229046&oid=32786&productType=1&qytInfoMTime=1515957313&cb=768848487 image
-http://www.gmw.cn/ http://afp.alicdn.com/afp-creative/creative/u113716014/465b11e883f45e8a41cd035da41a7084.jpg image
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bb48d9b00005a5c91af78461de37e63&pid=mm_113716014_12970037_52768242&cid=143140&mid=74920&oid=149&productType=1&qytInfoMTime=1515957311&e=Qpdr14cdu9DL3IkfTk3f2q%2BYC8tIZVqzkHSdaSlylzuDELdanIZY3i713c7jp2SZ&k=65&cb=356733566 image
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bb48d9b00005a5c91af78461de37e63&pid=mm_113716014_12970037_52768242&cid=143140&mid=74920&oid=149&productType=1&qytInfoMTime=1515957311&cb=863109667 image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768233&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016047489&fs=2&pvid=a03bcd4d8518ae100e39b1288e366917&cg=aef4c0a2746a00adf1c70a16bf8462fd script
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20180111_mobileGMW_728X90.gif image
-http://www.gmw.cn/ http://ad.gmw.cn/index_banner/20171228_yatx_728x90_3.jpg image
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bb48dab00005a5c91b070061dd48d0e&pid=mm_113716014_12970037_52768233&cid=264978&mid=2582&oid=151&productType=1&qytInfoMTime=1515957310&e=TOfKnyVVPwXL3IkfTk3f2s59wjJaD8F8kb3P6nRT%2Bek3BOBTCI92ehcwdQjwnjfG&k=65&cb=572630520 image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768243&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016048544&fs=2&pvid=ec31c8f774708d4840c6dff97d84fef3&cg=ac46af2bf50fbbdafcd178e61a539798 script
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bb48dab00005a5c91b070061dd48d0e&pid=mm_113716014_12970037_52768233&cid=264978&mid=2582&oid=151&productType=1&qytInfoMTime=1515957310&cb=990631052 image
-http://www.gmw.cn/ http://afp.alicdn.com/afp-creative/creative/u113716014/92766f4e6e57bf7f4c75e3db723820be.jpg image
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bb48dab00005a5c91b0700d1de45d2c&pid=mm_113716014_12970037_52768243&cid=92223&mid=70785&oid=149&productType=1&qytInfoMTime=1515957311&e=zEHtzzlwDoLL3IkfTk3f2s59wjJaD8F8kb3P6nRT%2BemeSCmqjJdj4PX5SowN9KYs&k=65&cb=21835248 image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768234&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016049097&fs=3&pvid=bf5190c155753045fce50a644c0ce737&cg=a8d59c86224c687646103347ce8c11d2 script
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bb48dab00005a5c91b0700d1de45d2c&pid=mm_113716014_12970037_52768243&cid=92223&mid=70785&oid=149&productType=1&qytInfoMTime=1515957311&cb=444246579 image
-http://www.gmw.cn/ http://afp.alicdn.com/afp-creative/creative/u113716014/c69c5e537c724c173551c90cbdd45416.jpg image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768244&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016050108&fs=3&pvid=dcc50bcbac57da87115e364f29cfa9b4&cg=a29e54597ee7d11bb8cdf32ae8358745 script
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bfbf7ca00005a5c91b1757b1dc4c7bc&pid=mm_113716014_12970037_52768234&cid=258980&mid=3276&oid=376&productType=1&qytInfoMTime=1515957310&e=zAbU7bAg2q1fumWCnJqSgbGwtOlaLtnGbRk2eGCf6Suug8f%2BvxB7%2BVNuWSiSwYSx&k=65&cb=268951415 image
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bfbf7ca00005a5c91b1757b1dc4c7bc&pid=mm_113716014_12970037_52768234&cid=258980&mid=3276&oid=376&productType=1&qytInfoMTime=1515957310&cb=483810164 image
-http://www.gmw.cn/ http://afp.alicdn.com/afp-creative/creative/u113716014/bf8c8920677cc2acc01e2124e4e64090.jpg image
-http://www.gmw.cn/ http://afptrack.alimama.com/imp?bid=0bfbf7c900005a5c91b231361dc1deed&pid=mm_113716014_12970037_52768244&cid=258981&mid=244850&oid=376&productType=1&qytInfoMTime=1515957314&e=cA9vlRORo6lfumWCnJqSgX3zsnWZJgkarB01g15bUuQgh8MQRTIas30L0jZiRUla&k=65&cb=845246052 image
-http://www.gmw.cn/ http://afptrack.alimama.com/opt?bid=0bfbf7c900005a5c91b231361dc1deed&pid=mm_113716014_12970037_52768244&cid=258981&mid=244850&oid=376&productType=1&qytInfoMTime=1515957314&cb=908490644 image
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52772343&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016050795&fs=1&pvid=ec4e840bbc8fb0ffc1680152ff29e894&cg=ab260bfff622a4ead47ba302f6f1a10a script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52768132&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016051809&fs=4&pvid=a862ed84335fe8489a19618ec8d6c9ec&cg=a56b1debdbf4e38faea76e213b6411cf script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52766747&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016052335&fs=4&pvid=adcd8b653fbdac9687b303f93541c6eb&cg=a20c6284b734fbecda6fc3e91085fef7 script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770090&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016053352&fs=2&pvid=a8f171cac96cd2d7bfb5b1455e02e26d&cg=a4768b0bb722335f8acbb74bf26447f7 script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770091&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016054138&fs=2&pvid=f12ce4fb2036329b90a3f4f10de8a64d&cg=a7e7ee0b809cfbb9903b859c5e3b43fd script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770104&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016055169&fs=2&pvid=ac1d6cfa402b6c856f26aa79adf43486&cg=afd60a0a406cd369c3862c28df72ab24 script
-http://www.gmw.cn/ http://afpeng.alimama.com/ex?a=mm_113716014_12970037_52770103&sp=1&cb=_acM.r&u=http%3A%2F%2Fwww.gmw.cn%2F&ds=360x512&_=1516016055687&fs=2&pvid=b06432e7ca9e65df5806d6292d5bd6b9&cg=a0554165dac64f5f4160b6abe264a2f6 script
-http://www.gmw.cn/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.gmw.cn/ http://cloudfront-labs.amazonaws.com/x.png image
-http://www.gmw.cn/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=1428&frame_width=1004&iframe=0&title=%E5%85%89%E6%98%8E%E7%BD%91_%E6%96%B0%E9%97%BB%E8%A7%86%E9%87%8E%E3%80%81%E6%96%87%E5%8C%96%E8%A7%86%E8%A7%92%E3%80%81%E6%80%9D%E6%83%B3%E6%B7%B1%E5%BA%A6%E3%80%81%E7%90%86%E8%AE%BA%E9%AB%98%E5%BA%A6&time=1516016058091&time_zone_offset=0&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fwww.gmw.cn%2F&random_number=20369178809&sess_cookie=c54ad2dd160f9993ee945a85282&sess_cookie_flag=1&user_cookie=c54ad2dd160f9993ee945a85282&user_cookie_flag=1&dynamic=true&domain=gmw.cn&account=4+gli1aUCm00OA&jsv=20130128&user_lang=en-US image
-http://www.gmw.cn/ http://a1e267cd0ae82bb09892b88c69c0203e3.profile.sea-m.cloudfront.net/test.png image
-http://www.gmw.cn/ http://www.gmw.cn/favicon.ico image
-http://www.pixnet.net/ http://www.pixnet.net/ html
-http://www.pixnet.net/ https://www.pixnet.net/ html
-http://www.pixnet.net/ http://m.pixnet.net/ html
-http://www.pixnet.net/ https://m.pixnet.net/ html
-http://www.pixnet.net/ https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js script
-http://www.pixnet.net/ https://code.jquery.com/mobile/1.2.0/jquery.mobile-1.2.0.min.js script
-http://www.pixnet.net/ https://s.pixfs.net/js/pixnet/checklogin.min.js?v=311947bc2e1f121d8b4cf9b0ac9058a5 script
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/mobile-PIXNET-logo@2x.png image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/btn-menubar@2x.png image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/scroll-bar-mask@2x.png image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/loading-icon.gif image
-http://www.pixnet.net/ https://s.pixfs.net/mobile/images/icons/btn-close.svg image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/topic-spotlight-flip-left.png image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/topic-spotlight-flip-right.png image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/topic-spotlight-h2.png image
-http://www.pixnet.net/ https://libs.pixfs.net/localScrollFix/localScrollFix.min.js?v=311947bc2e1f121d8b4cf9b0ac9058a5 script
-http://www.pixnet.net/ https://s.pixanalytics.com/js/c.js script
-http://www.pixnet.net/ https://front.pixfs.net/js/fingerprint.min.js script
-http://www.pixnet.net/ https://imageproxy.pimg.tw/zoomcrop?url=http%3A%2F%2Fpics.ctitv.com%2Fwpimg%2F2017%2F06%2Ft020001.jpg&width=90&height=65 image
-http://www.pixnet.net/ https://s9.pimg.tw/album/pink03049/element/125457989_1511672796-113082123/zoomcrop/90x65.png image
-http://www.pixnet.net/ https://s.pimg.tw/album/goris/element/327706850_1515816968-883988179/zoomcrop/90x65.jpg image
-http://www.pixnet.net/ https://s9.pimg.tw/album/acelin0513/element/129551519_1515733779-2836627837/zoomcrop/590x393.jpg image
-http://www.pixnet.net/ https://s6.pimg.tw/album/pixstyleme/element/129578396_1515753490-2633896618/zoomcrop/590x393.jpg image
-http://www.pixnet.net/ https://s.pimg.tw/album/yehman/element/111582170_499d77b141e69/zoomcrop/90x65.jpg image
-http://www.pixnet.net/ https://imageproxy.pimg.tw/zoomcrop?url=http%3A%2F%2Fimg.chinatimes.com%2Fnewsphoto%2F2018-01-12%2F360%2F20180112001514.jpg&width=90&height=65 image
-http://www.pixnet.net/ https://imageproxy.pimg.tw/zoomcrop?url=http%3A%2F%2Fstatic.news.sina.com.tw%2Farticle%2Fimages%2Fnews-15157701013229.jpg&width=90&height=65 image
-http://www.pixnet.net/ https://s4.pimg.tw/avatar/pl38zachanq/0/0/resize/65x0.png?v=1492949382 image
-http://www.pixnet.net/ https://s4.pimg.tw/album/cpucpucpu/element/317836754_1515946293-2150285636/zoomcrop/90x65.jpg image
-http://www.pixnet.net/ https://s1.pimg.tw/album/misspixnet/element/317737301_1515406427-1439378434/zoomcrop/590x393.jpg image
-http://www.pixnet.net/ https://imageproxy.pimg.tw/zoomcrop?url=https%3A%2F%2Ffarm5.staticflickr.com%2F4600%2F39373144561_277f361a99_b.jpg&width=90&height=65 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/gps1111gps/albumset/14993095/zoomcrop/75x75.jpg?v=1515204312 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/lovelycstyle/albumset/5954324/zoomcrop/75x75.jpg?v=1515964325 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/pro770906520/albumset/6870581/zoomcrop/75x75.jpg?v=1515567829 image
-http://www.pixnet.net/ https://s.pixanalytics.com/js/pi.min.js script
-http://www.pixnet.net/ https://s7.pimg.tw/album/yai8/element/317771687_1515590760-2273795313/zoomcrop/90x65.jpg image
-http://www.pixnet.net/ https://s5.pimg.tw/album/ianchiu1107/element/702576905_1515923382-3305839865/zoomcrop/90x65.jpg image
-http://www.pixnet.net/ https://s.pimg.tw/album2/okasos/albumset/2285315/zoomcrop/75x75.jpg?v=1514246578 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/steven0717/albumset/1043177/zoomcrop/75x75.jpg?v=1297692028 image
-http://www.pixnet.net/ https://s3.pimg.tw/avatar/yhb4dheathemy/0/0/resize/65x0.png?v=1490960984 image
-http://www.pixnet.net/ https://api.pixnet.cc/api/checklogin.php?js=1&unique=325207405&timestamp=1516015937&type=3 script
-http://www.pixnet.net/ https://s.pimg.tw/album2/karate362/albumset/11268462/zoomcrop/75x75.jpg?v=1394116710 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/kristin0126/albumset/5949245/zoomcrop/75x75.jpg?v=1515047789 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/pink03049/albumset/2715863/zoomcrop/75x75.jpg?v=1515441685 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/park15/albumset/16873632/zoomcrop/75x75.jpg?v=1394680960 image
-http://www.pixnet.net/ https://libs.pixfs.net/jquery.templates/beta1/jquery.tmpl.min.js script
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/js/all.min.js?v=311947bc2e1f121d8b4cf9b0ac9058a5 script
-http://www.pixnet.net/ https://s.pimg.tw/album2/dong1104/albumset/8500119/zoomcrop/75x75.jpg?v=1515844319 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/ruthpp0520/albumset/18403242/zoomcrop/75x75.jpg?v=1516013716 image
-http://www.pixnet.net/ https://s.pixfs.net/js/pixlogger.min.js?v=311947bc2e1f121d8b4cf9b0ac9058a5 script
-http://www.pixnet.net/ https://s.pimg.tw/album2/hwaiyow/albumset/11385927/zoomcrop/75x75.jpg?v=1514167221 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/tdckw/albumset/3633246/zoomcrop/75x75.jpg?v=1490592260 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/a0905535666/albumset/6948299/zoomcrop/75x75.jpg?v=1515992936 image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/js/side-nav.min.js?v=311947bc2e1f121d8b4cf9b0ac9058a5 script
-http://www.pixnet.net/ https://s.pimg.tw/album2/aguiter/albumset/1064278/zoomcrop/75x75.jpg?v=1512963687 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/barry870618/albumset/16724170/zoomcrop/75x75.jpg?v=1501554636 image
-http://www.pixnet.net/ https://code.jquery.com/mobile/1.2.0/images/ajax-loader.gif image
-http://www.pixnet.net/ https://s.pimg.tw/album2/ryanyang0725/albumset/3777615/zoomcrop/75x75.jpg?v=1496039535 image
-http://www.pixnet.net/ https://front.pixfs.net/css/mobile/styles/images/sprite.png image
-http://www.pixnet.net/ https://code.jquery.com/mobile/1.2.0/images/icons-36-white.png image
-http://www.pixnet.net/ https://s.pimg.tw/album2/wo82208/albumset/18265844/zoomcrop/75x75.jpg?v=1516001520 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/sweet9023001/albumset/16147277/zoomcrop/75x75.jpg?v=1515951804 image
-http://www.pixnet.net/ https://m.pixnet.net/friends/unreadcount script
-http://www.pixnet.net/ https://s.pimg.tw/album2/angel710518/albumset/3087814/zoomcrop/75x75.jpg?v=1436529422 image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/next_s.png image
-http://www.pixnet.net/ https://s.pimg.tw/album2/lovecala/albumset/5450403/zoomcrop/75x75.jpg?v=1515987712 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/six7778/albumset/13393150/zoomcrop/75x75.jpg?v=1415067759 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/lkkhuang0617/albumset/11507295/zoomcrop/75x75.jpg?v=1433467703 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/ellis070/albumset/5955275/zoomcrop/75x75.jpg?v=1516013764 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/irenelin0917/albumset/16148108/zoomcrop/75x75.jpg?v=1516013667 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/sbbzxf60344373/albumset/6955250/zoomcrop/75x75.jpg?v=1516013551 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/sherryko/albumset/16148105/zoomcrop/75x75.jpg?v=1516013611 image
-http://www.pixnet.net/ https://www.google-analytics.com/analytics.js script
-http://www.pixnet.net/ https://s.pimg.tw/album2/hsuan1203/albumset/5955272/zoomcrop/75x75.jpg?v=1516013566 image
-http://www.pixnet.net/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.pixnet.net/ https://s.pimg.tw/album2/greenfish0814/albumset/6568383/zoomcrop/75x75.jpg?v=1516013392 image
-http://www.pixnet.net/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1586326957&t=pageview&_s=1&dl=https%3A%2F%2Fm.pixnet.net%2F&ul=en-us&de=UTF-8&dt=%E7%97%9E%E5%AE%A2%E9%82%A6%20PIXNET&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=IEBAAEAB~&jid=1821863402&gjid=1948967589&cid=881821058.1516015943&tid=UA-20543617-6&_gid=2057946279.1516015943&_r=1&z=1677468459 html
-http://www.pixnet.net/ https://s.pimg.tw/album2/fanfancat/albumset/5954705/zoomcrop/75x75.jpg?v=1516013324 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/monet763/albumset/14518153/zoomcrop/75x75.jpg?v=1516013261 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/doctorofpest/albumset/6910334/zoomcrop/75x75.jpg?v=1516013206 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/tyan945/albumset/9002310/zoomcrop/75x75.jpg?v=1516013191 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/uvmekc09640308/albumset/6955235/zoomcrop/75x75.jpg?v=1516013203 image
-http://www.google.com.pk/ http://www.google.com.pk/ html
-http://www.google.com.pk/ https://www.google.com.pk/?gws_rd=ssl html
-http://www.google.com.pk/ https://www.google.com.pk/logos/doodles/2018/martin-luther-king-jr-day-2018-5351803502723072-l.png image
-http://www.pixnet.net/ https://s.pimg.tw/album2/bearbaby16888/albumset/16137212/zoomcrop/75x75.jpg?v=1516013142 image
-http://www.pixnet.net/ https://pixanalytics.com/pa.gif?t=mainpage_index_new&ver=1.0&random=0.8981492046475679&document.referrer=&document.URL=https://m.pixnet.net/?&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https://m.pixnet.net/?&window.pageXOffset=0&window.pageYOffset=0&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla/5.0%20(Linux;%20Android%206.0.1;%20Moto%20G%20(4)%20Build/MPJ24.139-64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180111.190127&window.devicePixelRatio=3&_pix.login_name=c343c5fb1929984f27c6ac9df742da54&_pix.owner=undefined&_pix.visitor=&_pix.openid=undefined image
-http://www.google.com.pk/ https://www.google.com.pk/images/nav_logo242_hr.webp image
-http://www.pixnet.net/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-20543617-6&cid=881821058.1516015943&jid=1821863402&_gid=2057946279.1516015943&gjid=1948967589&_v=j66&z=1677468459 image
-http://www.google.com.pk/ https://www.google.com.pk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/rt=j/d=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.google.com.pk/ https://www.google.com.pk/gen_204?s=webaft&atyp=csi&ei=MpFcWu2SIcfTjAO6uKLoAg&rt=wsrt.2074,aft.193,prt.193 html
-http://www.pixnet.net/ https://pixanalytics.com/pa.gif?t=mainpage_index_mobile&ver=1.0&random=0.4737961118192613&document.referrer=&document.URL=https://m.pixnet.net/?&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https://m.pixnet.net/?&window.pageXOffset=0&window.pageYOffset=0&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla/5.0%20(Linux;%20Android%206.0.1;%20Moto%20G%20(4)%20Build/MPJ24.139-64)%20AppleWebKit/537.36%20(KHTML,%20like%20Gecko)%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180111.190127&window.devicePixelRatio=3&_pix.login_name=c343c5fb1929984f27c6ac9df742da54&_pix.owner=undefined&_pix.visitor=&_pix.openid=undefined image
-http://www.google.com.pk/ https://www.gstatic.com/og/_/js/k=og.mob.en_US.SG2gwmaNizE.O/rt=j/m=md/exm=mih,mab,meb/d=1/ed=1/rs=AA2YrTv_Md1uUNCaPBOGnQR-KHYIMECr6g script
-http://www.pixnet.net/ https://s.pimg.tw/album2/qianying5566/albumset/4893300/zoomcrop/75x75.jpg?v=1516013175 image
-http://www.google.com.pk/ https://ssl.gstatic.com/gb/images/qi2_00ed8ca1.png image
-http://www.pixnet.net/ https://s.pimg.tw/album2/yong20150803/albumset/1302817/zoomcrop/75x75.jpg?v=1516013050 image
-http://www.pixnet.net/ https://pixanalytics.com/pi.gif?t=pv&r=0.7099823790546349&document.referrer=&document.URL=https%3A%2F%2Fm.pixnet.net%2F%3F&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https%3A%2F%2Fm.pixnet.net%2F%3F&window.pageXOffset=0&window.pageYOffset=0&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&window.devicePixelRatio=3&venue=pixnet-mainpage-mobile&visitor_id=&utm_source=&utm_medium=&utm_term=&utm_content=&utm_campaign= image
-http://www.google.com.pk/ https://www.google.com.pk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw?xjs=s1 script
-http://www.pixnet.net/ https://s.pimg.tw/album2/sharlalee/albumset/4720767/zoomcrop/75x75.jpg?v=1516012988 image
-http://www.google.com.pk/ https://www.gstatic.com/navigationdrawer/home_icon.svg image
-http://www.pixnet.net/ https://s.pixfs.net/mainpagemobile/style/images/top.png image
-http://www.google.com.pk/ https://www.gstatic.com/navigationdrawer/save_icon.svg image
-http://www.pixnet.net/ https://pixanalytics.com/pi.gif?t=et&r=0.2726881419965663&document.referrer=&document.URL=https%3A%2F%2Fm.pixnet.net%2F%3F&screen.availHeight=512&screen.availLeft=0&screen.availTop=0&screen.availWidth=360&screen.colorDepth=24&screen.height=512&screen.pixelDepth=24&screen.width=360&window.closed=false&window.height=undefined&window.innerHeight=512&window.innerWidth=360&window.length=0&window.location=https%3A%2F%2Fm.pixnet.net%2F%3F&window.pageXOffset=0&window.pageYOffset=0&window.outerHeight=512&window.outerWidth=360&window.screenX=0&window.screenY=0&window.width=undefined&navigator.userAgent=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&window.devicePixelRatio=3&venue=pixnet-mainpage-mobile&visitor_id=&utm_source=&utm_medium=&utm_term=&utm_content=&utm_campaign=&e_category=fingerprinting_test&e_action=%2352350&e_label=284c0301560b5d0d8ac7dfd10967d13281f044e88350e5505dc78faf4b49d8ee image
-http://www.google.com.pk/ https://www.gstatic.com/navigationdrawer/settings_icon.svg image
-http://www.pixnet.net/ https://s.pimg.tw/album2/rosyhuang/albumset/18767243/zoomcrop/75x75.jpg?v=1516012912 image
-http://www.google.com.pk/ https://www.gstatic.com/navigationdrawer/help_icon.svg image
-http://www.google.com.pk/ https://www.gstatic.com/navigationdrawer/feedback_icon.svg image
-http://www.pixnet.net/ https://s.pimg.tw/album2/orfucm35272665/albumset/6955211/zoomcrop/75x75.jpg?v=1516012862 image
-http://www.google.com.pk/ https://www.google.com.pk/xjs/_/js/k=xjs.qs.en_US._sUSDHU4MYA.O/m=RMhBfe/am=AIvkGSf4kAPIHMWEZPBfAARyIiA/exm=sx,sb_mob,bct,cdos,elog,hsm,jsa,mbsf,qim,r,d,csi,d3l,udlg,aa,abd,async,dvl,foot,ipv6,mu,sonic,rQSi2/rt=j/d=1/ed=1/t=zcms/rs=ACT90oFoFDkDF1hTK_cawC1iJmjYyff7Qw script
-http://www.pixnet.net/ https://s.pimg.tw/album2/mina0922/albumset/1548520/zoomcrop/75x75.jpg?v=1516012764 image
-http://www.google.com.pk/ https://www.google.com.pk/images/nav_logo242.png image
-http://www.google.com.pk/ https://www.google.com.pk/gen_204?atyp=csi&ei=MpFcWu2SIcfTjAO6uKLoAg&s=mobilewebhp&imc=1&imn=1&imp=1&adh=&conn=onchange&ima=1&ime=0&mem=ujhs.10,tjhs.13,jhsl.2060&rt=aft.644,dcl.376,iml.644,ol.2300,prt.193,xjs.1476,xjsee.1476,xjses.1211,xjsls.182,wsrt.2074,cst.634,dnst.0,rqst.754,rspt.412,sslt.336,rqstt.1598,unt.960,cstt.962,dit.2451&zx=1516015925174 html
-http://www.pixnet.net/ https://s.pimg.tw/album2/wenchi35/albumset/6955028/zoomcrop/75x75.jpg?v=1516012758 image
-http://www.google.com.pk/ https://www.gstatic.com/og/_/ss/k=og.mob.-e27yel58dgy6.L.W.O/m=md/excm=mih,mab,meb/d=1/ed=1/rs=AA2YrTvCmCpKbqMviNBZMPUbBgZzy2Q1CA css
-http://www.pixnet.net/ https://s.pimg.tw/album2/lala0621/albumset/6954983/zoomcrop/75x75.jpg?v=1516012756 image
-http://www.google.com.pk/ https://www.google.com.pk/images/branding/product/1x/gsa_android_144dp.png image
-http://www.pixnet.net/ https://s.pimg.tw/album2/yyc0408/albumset/16146920/zoomcrop/75x75.jpg?v=1516012254 image
-http://www.google.com.pk/ https://adservice.google.com.pk/adsid/google/ui html
-http://www.pixnet.net/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=%E7%97%9E%E5%AE%A2%E9%82%A6%20PIXNET&time=1516015943029&time_zone_offset=480&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fm.pixnet.net%2F&random_number=5657015038&sess_cookie=865829b1160f9977d73075eccef&sess_cookie_flag=1&user_cookie=865829b1160f9977d73075eccef&user_cookie_flag=1&dynamic=true&domain=pixnet.net&account=H00Mh1aIE700wg&jsv=20130128&user_lang=en-US image
-http://www.pixnet.net/ https://s.pimg.tw/album2/hylm/albumset/5954459/zoomcrop/75x75.jpg?v=1515834422 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/kueiyuanm/albumset/16144982/zoomcrop/75x75.jpg?v=1515726756 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/csddm/albumset/5953256/zoomcrop/75x75.jpg?v=1515491240 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/smallseed/albumset/16144832/zoomcrop/75x75.jpg?v=1515712031 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/mmvis13/albumset/6914906/zoomcrop/75x75.jpg?v=1515734351 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/stese011/albumset/16146533/zoomcrop/75x75.jpg?v=1515908133 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/panda5412/albumset/16146506/zoomcrop/75x75.jpg?v=1515904287 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/qqdeer2016/albumset/6953504/zoomcrop/75x75.jpg?v=1515992988 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/ctkid123/albumset/6929711/zoomcrop/75x75.jpg?v=1515683080 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/cycchntc15/albumset/16146362/zoomcrop/75x75.jpg?v=1515867524 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/fiona3313/albumset/16146002/zoomcrop/75x75.jpg?v=1515830660 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/johnpam11/albumset/18264758/zoomcrop/75x75.jpg?v=1515565473 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/zoesunrise/albumset/16143812/zoomcrop/75x75.jpg?v=1515693805 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/b97140000/albumset/6950837/zoomcrop/75x75.jpg?v=1515945879 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/ts77go2/albumset/6951638/zoomcrop/75x75.jpg?v=1515960515 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/walipower/albumset/16147280/zoomcrop/75x75.jpg?v=1515950948 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/abby30028/albumset/16146869/zoomcrop/75x75.jpg?v=1516010276 image
-http://www.pixnet.net/ https://s.pimg.tw/album2/mingsioumissu/albumset/16146494/zoomcrop/75x75.jpg?v=1515904284 image
-http://www.pixnet.net/ https://falcon.pixanalytics.com/ad/js?fields[]=ad-1150,1150&fields[]=ad-1152,1152&fields[]=ad-1153,1153&_=1516015941992 script
-http://www.pixnet.net/ https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js script
-http://www.pixnet.net/ https://rtax.criteo.com/delivery/rta/rta.js?netId=4606&cookieName=crtg_rta&rnd=81826075840&varName=crtg_content script
-http://www.pixnet.net/ https://rtax.criteo.com/delivery/rta/rta.js?netId=4606&cookieName=crtg_rta&rnd=63411888670&varName=crtg_content script
-http://www.pixnet.net/ https://rtax.criteo.com/delivery/rta/rta.js?netId=4606&cookieName=crtg_rta&rnd=74436030986&varName=crtg_content script
-http://www.pixnet.net/ https://pagead2.googlesyndication.com/pub-config/r20160913/ca-pub-6865528665029394.js script
-http://www.pixnet.net/ https://pagead2.googlesyndication.com/pagead/js/r20180108/r20170110/show_ads_impl.js script
-http://www.pixnet.net/ https://adservice.google.com/adsid/integrator.js?domain=m.pixnet.net script
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/html/r20180108/r20170110/zrt_lookup.html html
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6865528665029394&output=html&h=280&slotname=4177786880&adk=3456403227&adf=646570834&w=336&lmt=1516015950&loeid=38893312%2C368226210&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&flash=0&wgl=1&dt=1516015949926&bpp=62&bdt=12235&fdt=93&idt=861&shv=r20180108&cbv=r20170110&saldr=aa&correlator=8005403857031&frm=20&ga_vid=881821058.1516015943&ga_sid=1516015951&ga_hid=1586326957&ga_fc=0&pv=2&iag=3&icsg=2&nhd=1&dssz=2&mdo=0&mso=0&u_tz=-480&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=12&ady=410&biw=360&bih=512&abxe=1&scr_x=0&scr_y=1&eid=21061122%2C38893302%2C191880502%2C368226200%2C389613000%2C21061011&oid=3&rx=0&eae=0&fc=664&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C360%2C512&vis=1&rsz=%7C%7CeE%7C&abl=CS&ppjl=f&pfx=0&fu=16&bc=1&osw_key=1763479670&ifi=1&xpc=t8nS2yyNdI&p=https%3A//m.pixnet.net&dtd=994 html
-http://www.pixnet.net/ https://pagead2.googlesyndication.com/pagead/js/r20180108/r20170110/osd.js script
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6865528665029394&output=html&h=280&slotname=5654494760&adk=4108093734&adf=2231601519&w=336&lmt=1516015951&loeid=38893312%2C368226210&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&flash=0&wgl=1&dt=1516015950025&bpp=66&bdt=12334&fdt=1039&idt=1182&shv=r20180108&cbv=r20170110&saldr=aa&prev_fmts=336x280&correlator=8005403857031&frm=20&ga_vid=881821058.1516015943&ga_sid=1516015951&ga_hid=1586326957&ga_fc=0&pv=1&iag=3&icsg=2&nhd=1&dssz=2&mdo=0&mso=0&u_tz=-480&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=12&ady=1196&biw=360&bih=512&abxe=1&scr_x=0&scr_y=1&eid=21061122%2C38893302%2C191880502%2C368226200%2C389613000%2C21061011&oid=3&rx=0&eae=0&fc=664&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C360%2C512&vis=1&rsz=%7C%7CoeEbr%7C&abl=CS&ppjl=f&pfx=0&fu=16&bc=1&osw_key=2111767646&ifi=2&xpc=1htArqSBSw&p=https%3A//m.pixnet.net&dtd=1287 html
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/ads?client=ca-pub-6865528665029394&output=html&h=280&slotname=7131202640&adk=3899251677&adf=42664218&w=336&lmt=1516015951&loeid=38893312%2C368226210&format=336x280&url=https%3A%2F%2Fm.pixnet.net%2F&flash=0&wgl=1&dt=1516015950092&bpp=63&bdt=12402&fdt=1388&idt=1399&shv=r20180108&cbv=r20170110&saldr=aa&prev_fmts=336x280%2C336x280&correlator=8005403857031&frm=20&ga_vid=881821058.1516015943&ga_sid=1516015951&ga_hid=1586326957&ga_fc=0&pv=1&iag=3&icsg=2&nhd=1&dssz=2&mdo=0&mso=0&u_tz=-480&u_his=3&u_java=0&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_nplug=0&u_nmime=0&adx=12&ady=2111&biw=360&bih=512&abxe=1&scr_x=0&scr_y=1&eid=21061122%2C38893302%2C191880502%2C368226200%2C389613000%2C21061011&oid=3&rx=0&eae=0&fc=664&brdim=0%2C0%2C0%2C0%2C360%2C0%2C360%2C512%2C360%2C512&vis=1&rsz=%7C%7CeEbr%7C&abl=CS&ppjl=f&pfx=0&fu=16&bc=1&osw_key=4279392610&ifi=3&xpc=01u3VjkqXk&p=https%3A//m.pixnet.net&dtd=1442 html
-http://www.pixnet.net/ https://falcon.pixanalytics.com/ad/embed/1812 html
-http://www.pixnet.net/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/abg.js script
-http://www.pixnet.net/ https://tpc.googlesyndication.com/daca_images/simgad/15623355035671725132 image
-http://www.pixnet.net/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_js_controller.js script
-http://www.pixnet.net/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_window_focus_non_hydra.js script
-http://www.pixnet.net/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener_heavy.js script
-http://www.pixnet.net/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_qs_click_protection.js script
-http://www.pixnet.net/ https://www.google.com/ads/measurement/l?ebcid=ALh7CaRZly8nr5mcY_ofXsHUch9qXUSBkMYXbjUs0M48yjVyFyvhQtYdJ8VPtPfDaFWZvtt1LW-8FnFlbPZ-tWhZEhRY5Tq90g html
-http://www.pixnet.net/ https://fonts.googleapis.com/css?family=Slabo+27px:400&lang=zh-TW css
-http://www.pixnet.net/ https://static.criteo.net/js/ld/publishertag.js script
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/drt/s?v=r20120211 html
-http://www.pixnet.net/ https://pagead2.googlesyndication.com/pagead/s/cookie_push.html html
-http://www.pixnet.net/ https://tpc.googlesyndication.com/pagead/images/transparent.png image
-http://www.pixnet.net/ https://fonts.gstatic.com/s/slabo27px/v4/PuwvqkdbcqU-fCZ9Ed-b7QzyDMXhdD8sAj6OAJTFsBI.woff2 font
-http://www.pixnet.net/ https://www.google.com/pagead/drt/ui html
-http://www.pixnet.net/ https://www.google.com/pagead/drt/ui html
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/drt/si html
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/gen_204?v=3&s=pagead&action=loadimgad&it=bdt.12235,req.994,bpp.62,fb.1577,e2e.5431,fs.1037,reqs.1051,ress.1577,rese.1705&srt=544&e=370204017&id=csi_pagead&gqid=T5FcWpjFCMiQigPMzb24CA&qqid=CNuo-MHv2dgCFdh4YgodAjcF5Q&rt=ol.3854 html
-http://www.pixnet.net/ https://pagead2.googlesyndication.com/bg/CODLVxOWPkvhNbYnVJaNBoOJoU-AurND_bpkm-q7bJU.js script
-http://www.pixnet.net/ https://cm.g.doubleclick.net/pixel/attr?d=AHNF13KyYxhvHev7zuJNtRmyZyjGxhuNX_nD html
-http://www.pixnet.net/ https://adx.adnxs.com/getuid?https%3A%2F%2Fcm.g.doubleclick.net%2Fpixel%3Fgoogle_nid%3Dappnexus1%26google_hm%3D%24%7BBASE64_UID_ENC%7D%26google_push=&google_gid=CAESELo9LzSS_rDRvSjfJTXZTtM&google_cver=1&google_push=AHNF13KsQ8eBIH8sAY8W_1YZTl3NL-NEprGwU2pzapwkog image
-http://www.pixnet.net/ https://bidder.criteo.com/cdb?ptv=40&profileId=184&cb=10691319853 other
-http://www.pixnet.net/ https://googleads.g.doubleclick.net/pagead/gen_204?v=3&s=pagead&action=load,async,iframe3&it=bdt.12402,req.1442,bpp.63,fb.2038,e2e.6017,fs.1482,reqs.1485,ress.2038,rese.2069&srt=557&e=370204017&id=csi_pagead&gqid=T5FcWuSrLc-tiAOamqCQAw&qqid=CO3sncLv2dgCFcuPYgodsjoL1Q&rt=lb.2320,ol.3979 html
-http://www.pixnet.net/ https://m.pixnet.net/favicon.ico image
-http://www.pixnet.net/ https://img.scupio.com/js/ad.js script
-http://www.pixnet.net/ https://img.scupio.com/js/config/13940.js?v=1.17 script
-http://www.pixnet.net/ https://img.scupio.com/html/ad.html?v=1.12.6 html
-http://www.pixnet.net/ https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js script
-http://www.pixnet.net/ https://bidder.criteo.com/cdb?ptv=40&profileId=184&cb=75278711825 other
-http://www.pixnet.net/ https://bw.scupio.com/adpinline/adcall.aspx?cb=0.9707847012081605&cid1=13940 script
-http://www.pixnet.net/ https://img.scupio.com/ad//adpic/9134/187950/20180105102425.jpg image
-http://www.pixnet.net/ https://img.scupio.com/ad//adpic/8865/156307/20151029104349.jpg image
-http://www.pixnet.net/ https://img.scupio.com/ad/images/RBlogo-sh2.png image
-http://www.pixnet.net/ https://bw.scupio.com/adpinline/adcall.aspx?imp2=H4sIANoBXVoA_0VST2jTYBTvF03NUrVbZDK8-NmDdFubfF_S_OkGYldhw61SaHGwS02Tr21cmoQmxW6nHVU8iCKCJxEvCnpV0KMiDE8i-AcP_hlM5sEhBRU8mGVUHzz48Xvv_fjx3mM39jIbj-68-P7uLcWlECaarORVwyBqI09UjOuaWFc0JBs6aqiapI5RKbZcRJKW8YndSN-498cSs60g8PwpQWjotuE6vGf1dEe3VwLL8HnDbQu6KZB2nZgC1rA4FQ_rDglO9u254-WRpUXm4dMEN1o4hdVapSiiWlEPSNPtrGQ7uSN0DisqOvZl-1PyQ__1iYnDxVYtompYQxjLWJPFsG-CQTzaCXkHqVhEqrZ0iLn-fIg7EAmfcWe6ZpME57YfPPn57dKbLeZ8zAOrowPnbX7XFB-msAauwMtgf7HVcdskU265DrkGhtg9TnAhRXX9WyB2G8Tvg30s5XscEP8hHKEmiVCCpbyAo6PpdXAXlNxVy7Z1QeYRTC9YTrc3DQuO2XEtEyo84vE0LLmBC2dhOjcOZ7qWbQql8mkxx2Mpn1VCruB5Nlkk9XkrEGRJ5SUFpufnqqWFDLStZQJnibHsjsNd24KshaISEvO8hkPlumUTWNEbescaDJerlaoQrRHzOI-wqL4CLBv3ja5nucP0e0BHh_4InvUnt8DB_xVEa_QPcJQB3PDXszdfbv7eHHk82aLXkz11bPBLEPwCn5NrFLhIJa9SCS72F38rP5dpAgAA&callid=01e85697cce7f9e711b82b6805ca0f7837&br2=%7B%22bi%22%3A%5B%5D%2C%22br%22%3A%5B%7B%22winner%22%3A%22sc%22%2C%22adid%22%3A187950%2C%22price%22%3A0.00016802013892726401%7D%2C%7B%22winner%22%3A%22sc%22%2C%22adid%22%3A156307%2C%22price%22%3A0%7D%5D%7D script
-http://www.pixnet.net/ https://sb.scorecardresearch.com/beacon.js script
-http://www.pixnet.net/ https://cm.g.doubleclick.net/pixel?google_nid=bw_cookie&google_cm&google_ula=3918219&google_hm=&layout=js html
-http://www.pixnet.net/ https://sb.scorecardresearch.com/b?c1=8&c2=11473066&c3=2370896352948000006&ns__t=1516015963749&ns_c=UTF-8&ns_if=1&cv=3.1m&c8=&c7=https%3A%2F%2Fimg.scupio.com%2Fhtml%2Fad.html%3Fv%3D1.12.6&c9= other
-http://www.pixnet.net/ https://www.facebook.com/tr/?id=1588263144793165&ev=ViewContent&dl=https%3A%2F%2Fimg.scupio.com%2Fhtml%2Fad.html%3Fv%3D1.12.6&rl=&if=true&ts=1516015963610&cd[SBST]=6&cd[PuID]=pixnet image
-http://www.pixnet.net/ https://sb.scorecardresearch.com/b2?c1=8&c2=11473066&c3=2370896352948000006&ns__t=1516015963749&ns_c=UTF-8&ns_if=1&cv=3.1m&c8=&c7=https%3A%2F%2Fimg.scupio.com%2Fhtml%2Fad.html%3Fv%3D1.12.6&c9= other
-http://www.pixnet.net/ https://agent.aralego.com/idSync/?redirect=https%3A%2F%2Frec.scupio.com%2Frecweb%2Fuxid.aspx%3Fid%3DSspCookieUserId text
-http://www.pixnet.net/ https://rec.scupio.com/recweb/ggid.aspx?layout=js&google_gid=CAESEOsEg2vNxevNvhtUbZp3gf0&google_cver=1&google_ula=3918219,0 script
-http://www.pixnet.net/ https://rec.scupio.com/recweb/uxid.aspx?id=315451f4-b786-42af-836c-d34d70fd52f3 image
-http://www.pixnet.net/ https://img.scupio.com/html/ls.html html
-http://www.uptodown.com/ http://www.uptodown.com/ html
-http://www.uptodown.com/ https://stc.utdstc.com/css/home.es.243.css css
-http://www.uptodown.com/ https://stc.utdstc.com/js/es.v10.243.js script
-http://www.uptodown.com/ https://stc.utdstc.com/img/imagelogo.png image
-http://www.uptodown.com/ https://stc.utdstc.com/img/logo_home.png image
-http://www.uptodown.com/ https://stc.utdstc.com/img/logo_new.png image
-http://www.uptodown.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.uptodown.com/ https://img.utdstc.com/screen/13/dc-unchained-001.jpg:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/animedlr-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/code39-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/wartide-heroes-of-atlantis-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/realm-grinder-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/unison-league-android.png:l image
-http://www.uptodown.com/ https://stc.utdstc.com/fonts/roboto-300.woff font
-http://www.uptodown.com/ https://stc.utdstc.com/fonts/uptodown.woff font
-http://www.uptodown.com/ https://stc.utdstc.com/img/flagsx2.png image
-http://www.uptodown.com/ https://stc.utdstc.com/img/flags.png image
-http://www.uptodown.com/ http://www.google-analytics.com/analytics.js script
-http://www.uptodown.com/ https://stc.utdstc.com/fonts/roboto-400.woff font
-http://www.uptodown.com/ https://stc.utdstc.com/fonts/roboto-100.woff font
-http://www.uptodown.com/ https://img.utdstc.com/icons/defaultand.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/dragons-feel-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/hammerman-getting-over-it-android.png:l image
-http://www.uptodown.com/ https://stc.utdstc.com/fonts/roboto-900.woff font
-http://www.uptodown.com/ https://img.utdstc.com/icons/tdmm-necropolis-td-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/kick-the-prince-princess-rush-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/warrior-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/letterboxd-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/velociraptor-map-speed-limit-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/marcacom-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/imc-calculadora-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/microsoft-kaizala-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/snaptube-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/tubemate-youtube-downloader-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/whatsapp-messenger-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/videoder-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/quickshortcutmaker-android.png:l image
-http://www.uptodown.com/ https://www.google-analytics.com/analytics.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/facebook-messenger-android.png:l image
-http://www.bongacams.com/ http://www.bongacams.com/ html
-http://www.uptodown.com/ https://img.utdstc.com/icons/facebook-android.png:l image
-http://www.bongacams.com/ http://bongacams.com/ html
-http://www.uptodown.com/ https://img.utdstc.com/icons/tubemate-3-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/uptodown-android-android.png:l image
-http://www.bongacams.com/ https://bongacams.com/ html
-http://www.uptodown.com/ https://img.utdstc.com/icons/kingroot-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/i18n-min/1515569177/en.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/google-play-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/css-min/1EB2zc/m.css css
-http://www.uptodown.com/ https://img.utdstc.com/icons/peggo-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/facebook-lite-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/js-min/1EAYZ2/ml.js script
-http://www.uptodown.com/ http://en.uptodown.com/ html
-http://www.uptodown.com/ https://img.utdstc.com/icons/you-tv-player-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/mobile/bongacams_logo3_header.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/playview-android.png:l other
-http://www.uptodown.com/ https://img.utdstc.com/icons/instagram-android.png:l image
-http://www.bongacams.com/ https://www.google.com/recaptcha/api.js?onload=recaptchaInit&render=explicit&hl=en script
-http://www.uptodown.com/ https://img.utdstc.com/icons/minecraft-pocket-edition-android.png:l other
-http://www.adobe.com/ http://www.adobe.com/ html
-http://www.bongacams.com/ https://ius.bongacams.com/images/default/bonga_thumb.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/test-dpc-android.png:l other
-http://www.bongacams.com/ https://ius.bongacams.com/images/mobile/ajax-loader.gif image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/satelliteLib-46e65db5bb0c375f8f64619be31cc9b29acf4867.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/whatsapp-messenger-android.png:xl image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/010/0d3/292/big_lq/8930f47e844f7b1aefe79918199d8d17.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/adobe.min.fp-05a76ee0744b9a0bab6197a0316cac4a.css css
-http://www.uptodown.com/ https://img.utdstc.com/icons/snapchat-android.png:l image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/012/083/0f0/big_lq/be4cbe3a2b718bbecbc0b9f05c18d45f.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/ace/source/css/aceui-reimagine.min.css.fps.fp-38d8d1db42e5da3684fec12a71ce83a8.css css
-http://www.uptodown.com/ https://stc.utdstc.com/css/home.en.243.css css
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/thirdparty-new.min.fp-cd8a8def0fb33d30bdacf53e8be9b003.css css
-http://www.bongacams.com/ https://ius1.bongacams.com/live/022/336/006/big_lq/90642f67d5bd0b538d539bf2b223899b.jpg image
-http://www.uptodown.com/ https://stc.utdstc.com/js/en.v10.243.js script
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/customized.min.fp-56a432134cf26319a9e9b649a8ff8b1a.css css
-http://www.bongacams.com/ https://ius3.bongacams.com/live/025/1b6/1cd/big_lq/9a2d3a90f403ff171b50f37821e1a067.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/block-strike-android.png:l image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/adobe-head.min.fp-fa2a81e1fbb52967f1a8de7146c5ddaf.js script
-http://www.bongacams.com/ https://ius3.bongacams.com/live/025/399/066/big_lq/4bfd01fc18f98248fb1e5f484ce4fee8.jpg image
-http://www.uptodown.com/ https://adservice.google.com/adsid/integrator.js?domain=en.uptodown.com script
-http://www.bongacams.com/ https://ius.bongacams.com/images/flag_pack_retina_min.png image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/ace/source/js/aceui-reimagine.min.js.fps.fp-953676be8e7c0183ec3380958d15c2be.js script
-http://www.bongacams.com/ https://ius2.bongacams.com/live/025/196/12f/big_lq/77fa4c8228b4ef43ca489228add4e522.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/mupen64plus-fz-edition-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/028/265/1ec/big_lq/a2ede8f1b7b6c6a01f130032423072bf.jpg image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/mbox-contents-f3808f72f280c66c15bd81363d6f55f0659a684d.js script
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.bongacams.com/ https://ius2.bongacams.com/live/00f/1bc/050/big_lq/9a2d3a90f403ff171b50f37821e1a067.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/growtopia-android.png:l image
-http://www.adobe.com/ http://dpm.demdex.net/id?d_visid_ver=2.5.0&d_fieldgroup=MC&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=9E1005A551ED61CA0A490D45%40AdobeOrg&d_nsid=0&ts=1516016127584 other
-http://www.bongacams.com/ https://ius2.bongacams.com/live/00e/0b3/318/big_lq/6a9db5545f508f664dff121bc15ce8d1.jpg image
-http://www.uptodown.com/ http://www.google-analytics.com/analytics.js script
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-ec-1440x810.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/rondo-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/008/27d/28b/big_lq/7f141a7892082e5386a8e1ad7908d9df.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-dc-1440x810.jpg image
-http://www.bongacams.com/ https://bongacams.com/load-promo-m/b4728/nn/us_en/0/1/0/2176/straight html
-http://www.uptodown.com/ https://img.utdstc.com/icons/databot-android.png:l image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-lr-1440x810.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-bg-cc-4pod-tablet-1440x1120.jpg image
-http://www.bongacams.com/ https://bongacams.com/tools/track.php?mo=portrait html
-http://www.uptodown.com/ http://www.google-analytics.com/collect?v=1&_v=j66&aip=1&a=209249549&t=pageview&_s=1&dl=http%3A%2F%2Fen.uptodown.com%2F&dr=http%3A%2F%2Fwww.uptodown.com%2F&ul=en-us&de=UTF-8&dt=App%20Downloads%20for%20Android%20-%20Download%2C%20Discover%2C%20Share%20on%20Uptodown&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=QACAAEAB~&jid=&gjid=&cid=296644604.1516016042&tid=UA-313498-1&_gid=499508305.1516016042&z=1587799968 other
-http://www.bongacams.com/ https://ius2.bongacams.com/live/018/0ed/0b6/big_lq/a65383e87005a0fd14b326bbcf908f76.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/thirdparty-new.min.fp-798b320b07f772b3a8acbc7ba36028e5.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/free-audiobooks-android.png:l image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/clientlibs/beagle/adobe.min.fp-3d5045495b28dbf1316470315c652c28.js script
-http://www.bongacams.com/ https://ius1.bongacams.com/live/005/174/03b/big_lq/47b12b0df0aef7ab1ac1942a97ec4e55.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/vidmate-android.png:l image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/023/092/3bd/big_lq/315d1dfaf0aa2ce315fcfa390b52ebf4.jpg image
-http://www.adobe.com/ http://dpm.demdex.net/id/rd?d_visid_ver=2.5.0&d_fieldgroup=MC&d_rtbd=json&d_ver=2&d_verify=1&d_orgid=9E1005A551ED61CA0A490D45%40AdobeOrg&d_nsid=0&ts=1516016127584 script
-http://www.bongacams.com/ https://ius3.bongacams.com/live/01e/3c1/23d/big_lq/4bfd01fc18f98248fb1e5f484ce4fee8.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/smart-audiobook-player-android.png:l image
-http://www.adobe.com/ http://use.typekit.com/glm4yoq.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/instagram-android.png:l image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/019/09e/076/big_lq/6da3c09ad900d7eadfc4259b3034a796.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-bg-ec-4pod-shoe-desktop-1440x1120.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/9apps-android.png:l image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/034/26d/28c/big_lq/7d0ecad155f61428dc21b47682c4694d.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-small-pod-cc-1440x810.jpg image
-http://www.adobe.com/ https://wwwimages.adobe.com/etc/beagle/public/globalnav/adobe-config/index.js script
-http://www.uptodown.com/ https://www.google-analytics.com/collect?v=1&_v=j66&aip=1&a=209249549&t=pageview&_s=1&dl=http%3A%2F%2Fen.uptodown.com%2F&dr=http%3A%2F%2Fwww.uptodown.com%2F&ul=en-us&de=UTF-8&dt=App%20Downloads%20for%20Android%20-%20Download%2C%20Discover%2C%20Share%20on%20Uptodown&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=QACAAEAB~&jid=&gjid=&cid=296644604.1516016042&tid=UA-313498-1&_gid=499508305.1516016042&z=1587799968 image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/014/011/094/big_lq/b3786ee789e6672c997991667a99995d.jpg image
-http://www.adobe.com/ https://api.demandbase.com/api/v2/ip.json?key=e4086fa3ea9d74ac2aae2719a0e5285dc7075d7b&rnd=6369&callback=Request_5592254 script
-http://www.uptodown.com/ https://img.utdstc.com/icons/snapchat-android.png:l image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/029/2f4/385/big_lq/d72b16f800412effdc778a1669a4b589.jpg image
-http://www.adobe.com/ https://geo2.adobe.com/json/?callback=ajpRsp& script
-http://www.bongacams.com/ https://ius1.bongacams.com/live/018/25b/115/big_lq/deb50986f7156bd167ec93af4f849ddf.jpg image
-http://www.adobe.com/ http://www.adobe.com/index.loggedin.json script
-http://www.uptodown.com/ https://img.utdstc.com/icons/show-box-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/01e/039/20f/big_lq/0e49ead0fccde30d9eeb671856692bae.jpg image
-http://www.adobe.com/ http://stats.adobe.com/id?d_visid_ver=2.5.0&d_fieldgroup=A&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&mid=25184214671657016004047640859236241357&ts=1516016128934 script
-http://www.bongacams.com/ https://ius.bongacams.com/images/spacer40.png?t=1516015999377 image
-http://www.uptodown.com/ https://img.utdstc.com/icons/lucky-patcher-android.png:l image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-59e8752e64746d7550001939.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/uc-browser-android.png:l image
-http://www.bongacams.com/ https://bongacams.com/tools/js.php?_=1516015999442 script
-http://www.adobe.com/ http://cm.everesttech.net/cm/dd?d_uuid=25028270030411042384063639909326814019 other
-http://www.uptodown.com/ https://img.utdstc.com/icons/whatsapp-messenger-android.png:xl image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/014/1ad/327/big_lq/564fac96d9f1c2c53a1fabcff5aeb3c9.jpg image
-http://www.adobe.com/ http://dpm.demdex.net/id?d_visid_ver=2.5.0&d_fieldgroup=AAM&d_rtbd=json&d_ver=2&d_orgid=9E1005A551ED61CA0A490D45%40AdobeOrg&d_nsid=0&d_mid=25184214671657016004047640859236241357&d_blob=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&d_cid_ic=AVID%012D2E490105033A8B-60001197E013FE62&ts=1516016131010 script
-http://www.uptodown.com/ https://img.utdstc.com/icons/4liker-android.png:l image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/005/2d8/076/big_lq/81a3ca55c7fe05476e375b77a198c5d7.jpg image
-http://www.adobe.com/ https://use.typekit.com/af/f8a6fc/000000000000000000017701/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n4&v=3 font
-http://www.uptodown.com/ https://img.utdstc.com/icons/google-play-games-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/036/008/213/big_lq/5111622176b442c279b32d825db6d386.jpg image
-http://www.adobe.com/ https://use.typekit.com/af/b4df20/000000000000000000017702/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=i4&v=3 font
-http://www.uptodown.com/ https://img.utdstc.com/icons/dj-liker-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/02c/265/1e4/big_lq/5ffd2ed7cf612268d6671e73a6a6d553.jpg image
-http://www.adobe.com/ https://use.typekit.com/af/64fe6a/000000000000000000017703/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n7&v=3 font
-http://www.uptodown.com/ https://img.utdstc.com/icons/messenger-lite-android.png:l image
-http://www.adobe.com/ https://use.typekit.com/af/e2707c/0000000000000000000176ff/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n3&v=3 font
-http://www.uptodown.com/ https://img.utdstc.com/icons/clash-of-clans-android.png:xl image
-http://www.adobe.com/ https://use.typekit.com/af/240659/000000000000000000017706/27/l?primer=fff1a989570eb474b8c22c57cc7199e63bfc7e911b750165d0199218f0b7e7cc&fvd=n9&v=3 font
-http://www.uptodown.com/ https://img.utdstc.com/icons/clash-royale-android.png:l image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/beagle/public/globalnav/adobe-globalnav/latest/adobe-globalnav.min.css css
-http://www.uptodown.com/ https://img.utdstc.com/icons/subway-surfers-android.png:l image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=411&dpuuid=WlySAwAABOoNJqAC image
-http://www.uptodown.com/ https://img.utdstc.com/icons/8-ball-pool-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/happy-chick-android.png:l image
-http://www.adobe.com/ https://static.adobelogin.com/imslib/imslib.min.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/dream-league-android.png:l image
-http://www.adobe.com/ http://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=adobe-global-mbox&mboxSession=4644e6a4ae4242e588d78b70f753b657&mboxPC=&mboxPage=b4c3672a884649e488dcf9c65af9a874&mboxVersion=1.1.0&mboxCount=1&mboxTime=1515987330261&mboxHost=www.adobe.com&mboxURL=http%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-480&screenHeight=512&screenWidth=360&colorDepth=24&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=0253D39273BFCCDA-42F040E6D21C36DE&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id= script
-http://www.uptodown.com/ https://img.utdstc.com/icons/candy-crush-saga-android.png:l image
-http://www.adobe.com/ http://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=cms-adobecom_us_index_TopOfBody&mboxSession=4644e6a4ae4242e588d78b70f753b657&mboxPC=&mboxPage=b4c3672a884649e488dcf9c65af9a874&mboxVersion=1.1.0&mboxCount=2&mboxTime=1515987330303&mboxHost=www.adobe.com&mboxURL=http%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-480&screenHeight=512&screenWidth=360&colorDepth=24&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=0253D39273BFCCDA-42F040E6D21C36DE&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id= script
-http://www.uptodown.com/ https://img.utdstc.com/icons/temple-run-2-android.png:l image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/010/085/340/big_lq/a7fa3e90699ff9f994ea4f7d9843cf76.jpg image
-http://www.adobe.com/ http://adobe.tt.omtrdc.net/m2/adobe/mbox/json?mbox=cms-adobecom_us_index_BottomOfBody&mboxSession=4644e6a4ae4242e588d78b70f753b657&mboxPC=&mboxPage=b4c3672a884649e488dcf9c65af9a874&mboxVersion=1.1.0&mboxCount=3&mboxTime=1515987332056&mboxHost=www.adobe.com&mboxURL=http%3A%2F%2Fwww.adobe.com%2F&mboxReferrer=&mboxXDomain=enabled&browserHeight=512&browserWidth=360&browserTimeOffset=-480&screenHeight=512&screenWidth=360&colorDepth=24&mboxMCGVID=25184214671657016004047640859236241357&mboxAAMB=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&mboxMCAVID=2D2E490105033A8B-60001197E013FE62&mboxMCGLH=9&vst.trk=stats.adobe.com&vst.trks=sstats.adobe.com&mboxMCSDID=0253D39273BFCCDA-42F040E6D21C36DE&at_property=7519f9ed-8af8-596a-460b-f1c9e3e28c47&aamseg=null&tnt_exclusion_targetCampaigns=null&entity.id= script
-http://www.uptodown.com/ http://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-bg-dc-4pod-work-4u-tablet-1440x1120.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/pes-2017-android.png:l image
-http://www.adobe.com/ https://les.everesttech.net/lastevent/3085 html
-http://www.uptodown.com/ https://img.utdstc.com/icons/mobile-legends-android.png:l image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/036/03d/071/big_lq/90d05108273eeaf243703b015f20ae1e.jpg image
-http://www.adobe.com/ https://adobeid-na1.services.adobe.com/ims/check/v4/token?jslClient=adobedotcom2&jslVersion=eb54245 other
-http://www.uptodown.com/ https://img.utdstc.com/icons/uber-android.png:xl image
-http://www.adobe.com/ http://wwwimages.adobe.com/etc/beagle/public/globalnav/adobe-globalnav/latest/adobe-globalnav.min.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/wowbox-android.png:l image
-http://www.adobe.com/ https://adobeid-na1.services.adobe.com/ims/check/v4/token?jslClient=adobedotcom2&jslVersion=eb54245 script
-http://www.uptodown.com/ https://img.utdstc.com/icons/remote-play-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/020/134/338/big_lq/d8b7b247442bf9ff8f6a5b143f0a725b.jpg image
-http://www.adobe.com/ http://wwwimages.adobe.com/services/globalnav.json/www.adobe.com/en/all.json script
-http://www.bongacams.com/ https://ius3.bongacams.com/live/018/219/126/big_lq/e78a08c3630f6132e9be03c209427770.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/waze-android.png:l image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/017/352/047/big_lq/a5c330c3c94fda92a991c7415accb151.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/olx-android.png:l image
-http://www.adobe.com/ http://stats.adobe.com/b/ss/adbhelpxprod/1/JS-2.5.0-D7QN/s18213751721556?AQB=1&ndh=1&pf=1&t=15%2F0%2F2018%203%3A35%3A40%201%20480&sdid=0253D39273BFCCDA-42F040E6D21C36DE&D=D%3D&mid=25184214671657016004047640859236241357&aid=2D2E490105033A8B-60001197E013FE62&aamlh=9&ce=UTF-8&cdp=2&fpCookieDomainPeriods=2&pageName=adobe.com&g=http%3A%2F%2Fwww.adobe.com%2F&c.&hitType=pageView&.c&ch=adobe.com&server=www.adobe.com&v0=D%3Dv6&events=event61%3D16%2Cevent62&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&c1=Home%20Page%20Template&c3=www.adobe.com&c4=en_us&c5=en_us%3Aadobe.com&v16=D%3Dc12&v18=New&c20=D%3Doid&c21=D%3Dpid&v22=Monday%20-%203%3A30AM&c27=NotSignedIn&v28=www.adobe.com%2F&c29=D%3Dv12&c31=en-us&c32=en-us%3Aadobe.com&v37=D%3Doid&v38=D%3Dpid&c52=unknown&c62=16.17&v65=Chrome%2058&v73=no%20value&v84=D%3Dc27&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&AQE=1 image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/014/3bc/1e3/big_lq/a98d338cc1e13abb83d59db0db6028b1.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/voot-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/mobile/icons-36-black.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/amazon-underground-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/mobile/spiner-transparent-white.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/google-maps-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/spacer40.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/talking-tom-cat-2-free-android.png:l image
-http://www.uptodown.com/ https://img.utdstc.com/icons/google-earth-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/bongacams_logo3_header.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/vidmate-android.png:xl image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/036/110/39a/big_lq/761b274473b8b0f66a173416d8825ee6.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/terrarium-tv-android.png:l image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/01f/04c/3ad/big_lq/edeaa3c3074d8160fbb4798658b7447c.jpg image
-http://www.adobe.com/ http://stats.adobe.com/b/ss/adbadobenonacdcprod/10/JS-2.5.0-D7QN/s17667618650821?AQB=1&ndh=1&pf=1&callback=s_c_il[4].doPostbacks&et=1&t=15%2F0%2F2018%203%3A35%3A40%201%20480&d.&nsid=0&jsonv=1&.d&sdid=0253D39273BFCCDA-42F040E6D21C36DE&D=D%3D&mid=25184214671657016004047640859236241357&aid=2D2E490105033A8B-60001197E013FE62&aamlh=9&ce=UTF-8&cdp=2&fpCookieDomainPeriods=2&pageName=adobe.com&g=http%3A%2F%2Fwww.adobe.com%2F&c.&hitType=pageView&s_dmdbase=%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3ABot%3A%5Bn%2Fa%5D&s_dmdbase_custom=%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D&.c&ch=adobe.com&server=www.adobe.com&v0=D%3Dv6&events=event999%3D12500%2CprodView%2Cevent3%2Cevent19%2Cevent61%3D16%2Cevent62&aamb=RKhpRz8krg2tLO6pguXWp5olkAcUniQYPHaMWWgdJ3xzPWQmdj0y&c1=Home%20Page%20Template&c3=www.adobe.com&c4=en_us&c5=en_us%3Aadobe.com&v16=D%3Dc12&v18=New&c20=D%3Doid&c21=D%3Dpid&v22=Monday%20-%203%3A30AM&c25=D%3Dc27&v28=www.adobe.com%2F&c29=D%3Dv12&c31=en-us&c32=en-us%3Aadobe.com&c34=D%3Daamlh&v37=D%3Doid&c38=2.5.0v%7C7QNv%20-%202018-01-11%2010%3A08%3A48%20UTC%7C6.12v%7C2.5.0v%7Cat.js-1.1.0v&v38=D%3Dpid&v51=%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3ABot%3A%5Bn%2Fa%5D&v52=%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D%3A%5Bn%2Fa%5D&c56=VisitorAPI%20Present&c62=16.22&v65=Chrome%2058&c74=s.c27%3Dp%2Cs.c52%3Dp%2Cs.c59%3Dp%2Cs.v12%3Dp%2Cs.v111%3Dp%2Cs.v210%3Dp&v84=D%3Dc27&v193=25184214671657016004047640859236241357&v250=setTimeout-10000&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&AQE=1 script
-http://www.uptodown.com/ https://img.utdstc.com/icons/mobdro-android.png:l image
-http://www.bongacams.com/ https://ius1.bongacams.com/live/021/32b/377/big_lq/8e56bd7a8a97873df28950c2a0791fed.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/reproductor-mx-android.png:l image
-http://www.bongacams.com/ https://ius3.bongacams.com/live/01c/1fd/1be/big_lq/cb2d4fe6dcc611f8ffbc981f360f90c3.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/microsoft-word-preview-android.png:xl image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/02a/0e3/01b/big_lq/23d538afebe71d7c8180ba855844aed0.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/ogyoutube-android.png:l image
-http://www.bongacams.com/ https://ius2.bongacams.com/live/022/0d7/0f3/big_lq/f02072124c65f66565aa32e16e6d09e2.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/wattpad-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/mobile/hd/tw_button.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/pdf-reader-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/mobile/hd/blog_button.png image
-http://www.uptodown.com/ https://img.utdstc.com/icons/evernote-android.png:l image
-http://www.bongacams.com/ https://www.gstatic.com/recaptcha/api2/v1514934548259/recaptcha__en.js script
-http://www.adobe.com/ http://l.betrad.com/pub/p.gif?pid=86&ocid=414&ii=1&d=1&mb=0&nt=0&r=0.3055396831908319 image
-http://www.bongacams.com/ https://www.google-analytics.com/analytics.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/microsoft-excel-preview-android.png:l image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-534da2e96b8ae7c6840004b9.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/kingsoft-android-office-international-android.png:l image
-http://www.bongacams.com/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-bg-dc-4pod-work-4u-mobile-1440x810.jpg image
-http://www.uptodown.com/ https://img.utdstc.com/icons/english-dictionary-offline-android.png:l image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-bg-ec-4pod-shoe-mobile-1440x810.jpg image
-http://www.bongacams.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=1315702622&t=pageview&_s=1&dl=https%3A%2F%2Fbongacams.com%2F&ul=en-us&de=UTF-8&dt=Free%20Live%20Sex%20Cams%20-%20Live%20Sex%20Chat%20and%20XXX%20Live%20Porn%20Shows&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=YEBAAAABC~&jid=1421554354&gjid=1333700747&cid=282811785.1516016002&tid=UA-10874655-24&_gid=1537544513.1516016002&_r=1&cg1=General&cd1=guest&cd2=&cd3=137&z=1146435789 html
-http://www.uptodown.com/ https://img.utdstc.com/icons/duolingo-android.png:l image
-http://www.adobe.com/ http://wwwimages.adobe.com/content/dam/acom/en/lobby/lobby-bg-cc-4pod-mobile-1440x810.jpg image
-http://www.bongacams.com/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Free%20Live%20Sex%20Cams%20-%20Live%20Sex%20Chat%20and%20XXX%20Live%20Porn%20Shows&time=1516016001700&time_zone_offset=0&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=https%3A%2F%2Fbongacams.com%2F&random_number=2395335327&sess_cookie=49c409f4160f99862a4fcbeee07&sess_cookie_flag=1&user_cookie=49c409f4160f99862a4fcbeee07&user_cookie_flag=1&dynamic=true&domain=bongacams.com&account=X2xYi1a8Dy00aY&jsv=20130128&user_lang=en-US image
-http://www.uptodown.com/ https://img.utdstc.com/icons/photomath-android.png:l image
-http://www.adobe.com/ https://ims-na1.adobelogin.com/favicon.ico?cache_bust=19dc551f944a8 image
-http://www.bongacams.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-10874655-24&cid=282811785.1516016002&jid=1421554354&_gid=1537544513.1516016002&gjid=1333700747&_v=j66&z=1146435789 image
-http://www.uptodown.com/ https://img.utdstc.com/icons/google-calendar-android.png:l image
-http://www.bongacams.com/ https://ius.bongacams.com/images/apple_icons/apple-touch-icon.png image
-http://www.adobe.com/ http://fast.adobe.demdex.net/dest5.html?d_nsid=0 html
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-57d1b3c664746d361f00d3cc.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/uptodown-android-android.png:xl image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-54133e4209c7a707dc0001c5.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/shareit-connect-and-transfer-android.png:l image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-5359ac4ecd812179a60007a7.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/mobogenie-market-android.png:l image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-54d24ba23337620019760100.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/xender-android.png:l image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-55e442fd3961370014000784.js script
-http://www.uptodown.com/ https://img.utdstc.com/icons/uc-browser-mini-for-android-android.png:l image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-5627261764746d716d001396.js script
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=3699395545509921&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fif&adsid=NT&eid=21060362%2C21061149&sc=0&sfv=1-0-14&iu=%2F1060150%2FLeaderboard_noadsense&sz=320x100%7C320x50&eri=1&cookie_enabled=1&abxe=1&lmt=1516016047&dt=1516016047753&frm=20&biw=360&bih=512&oid=3&adx=20&ady=330&adk=1062120734&gut=v2&ifi=1&u_tz=-480&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fen.uptodown.com%2F&ref=http%3A%2F%2Fwww.uptodown.com%2F&dssz=13&icsg=34&std=0&vrg=172&vis=1&scr_x=0&scr_y=0&ga_vid=296644604.1516016042&ga_sid=1516016048&ga_hid=209249549 script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-59a4061c64746d5174000477.js script
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_172.js script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-579b419764746d06c7000ab4.js script
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=2151807307142062&output=json_html&callback=googletag.impl.pubads.callbackProxy2&impl=fif&adsid=NT&eid=21060362%2C21061149&sc=0&sfv=1-0-14&iu=%2F1060150%2Fsticky_noadsense&sz=320x50&eri=1&cookie_enabled=1&abxe=1&lmt=1516016047&dt=1516016047803&frm=20&biw=360&bih=512&oid=3&adx=20&ady=462&adk=2180504997&gut=v2&ifi=2&u_tz=-480&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fen.uptodown.com%2F&ref=http%3A%2F%2Fwww.uptodown.com%2F&dssz=14&icsg=10274&std=0&vrg=172&vis=1&scr_x=0&scr_y=0&ga_vid=296644604.1516016042&ga_sid=1516016048&ga_hid=209249549 script
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjstmxZrWUxnUjYh92WmTrRd_bSMj-c6vXc5G2CH_AjYDn8wzIZQnR4y6SKVhQ4qc0Q5oO9VPp6Sev_C5ASYhDnGOGOAIAcmW-eRy3QnYm4JZtkF2VHfYzOW73HbWjFAS5XuZf3rsXahirY_0RdW-x5-pVP60zIE4WgJtfFZ_AmSNrLi0WSgDbod8lh62BKz7JoDdO9A-g-dsDXb1njAAGZ0amWpFN6l-2I8kJ8aq9E2tcw6hX35xPGzfyv6vnMbeHHMp-WDt56sdSpsBGSt5NXBbihIIcg&sig=Cg0ArKJSzDo2AsTR0ccrEAE&adurl= html
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-5916dd0864746d4ae6001259.js script
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjstwDLp7AA-yJrDHTQslu1fVgG0xRrXsiwNd_nIyKHu7-sEm6OvSSh27Y7Rp5QfbBxuV3-mU2-F6UcQB2v5M3OEQGIoeSq54iLhzxJTnCaZ-TRw31aiWurGJ2zyo9KlFUsPupedsA7KtFLidlN-TYd4HdUIGkrIFVL_B5njPkHMykio7t0OmiTcZrGFY1jsTz0T8Zb1caPNugcf5CRxt6WzGpmhAEGzC7VfVvM8iRkQovxmpPJv2J4QKJWmQsSIJUHXz&sig=Cg0ArKJSzDZm_4GjrfyJEAE&urlfix=1&adurl= html
-http://www.uptodown.com/ http://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-58d4d7ed64746d431d00ab11.js script
-http://www.uptodown.com/ https://tpc.googlesyndication.com/simgad/654511925813679944 image
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-580da78c64746d4cc8007eca.js script
-http://www.uptodown.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_window_focus_non_hydra.js script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-585a5bfc64746d4e3d000cda.js script
-http://www.uptodown.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener.js script
-http://www.adobe.com/ http://universal.iperceptions.com/wrapper.js script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-58bd3c7a64746d400000ab25.js script
-http://www.uptodown.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_qs_click_protection.js script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-55c98a093133640017000a51.js script
-http://www.uptodown.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener_heavy.js script
-http://www.adobe.com/ http://assets.adobedtm.com/659ec8ada5450db95675e43beaaae92399591a11/scripts/satellite-595522bf64746d0bd4004510.js script
-http://www.uptodown.com/ http://static.criteo.net/js/ld/publishertag.js script
-http://www.adobe.com/ http://universal.iperceptions.com/iFrame.html html
-http://www.uptodown.com/ http://tpc.googlesyndication.com/pagead/images/transparent.png image
-http://www.adobe.com/ http://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=25028270030411042384063639909326814019&redir=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d25028270030411042384063639909326814019 image
-http://www.uptodown.com/ https://stc.utdstc.com/favicon.ico image
-http://www.adobe.com/ http://cdnssl.clicktale.net/www20/ptc/544fc825-311a-44c5-86f0-70581a36c216.js script
-http://www.adobe.com/ http://servedby.flashtalking.com/container/10943;81912;8481;iframe/?ft_referrer=http%3A//www.adobe.com/&ns=&ftXRef=[%TRANSACTION_ID%]&ftXValue=[%TRANSACTION_VALUE%]&ftXType=[%TRANSACTION_TYPE%]&ftXName=[%TRANSACTION_NAME%]&ftXNumItems=[%TRANSACTION_QUANTITY%]&ftXCurrency=[%TRANSACTION_CURRENCY%]&U1=&U2=&U3=&U4=&U5=&U6=&u7=&U8=&U9=&U10=&U11=&U12=&U13=&U14=&U15=&U16=&U17&U18=&U19=&U20=&cb=7713435977246.215 html
-http://www.uptodown.com/ http://cas.criteo.com/delivery/ajs.php?ptv=40&zoneid=1109006&cb=28419627976&nodis=1&charset=UTF-8&dc=1&atfr=1&loc=http%3A%2F%2Fen.uptodown.com%2F other
-http://www.uptodown.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsvvCSpcCpzoJIlNWNWidT-WXr7yZSuX4nvamfNtAdOCCVbXrWtJlACnZO74CmujI9FOXvjzWn7wx8E8S_YhMqtLgnqNoifweoc&sig=Cg0ArKJSzBG2VFwQ_MBdEAE&id=osdim&ti=1&adk=1062120734&tt=1506&bs=360,512&mtos=1046,1046,1046,1046,1046&tos=1046,0,0,0,0&p=330,20,430,340&inapp=0&mcvt=1046&rs=3&ht=0&tfs=471&tls=1517&mc=1&lte=1&bas=0&bac=0&bos=360,512&ps=360,7646&ss=360,512&pt=12&deb=1-2-2-13-15-156&tvt=1375&op=1&avms=geo&r=v&uc=9&tgt=DIV&cl=1&cec=5&clc=1&cac=0320x100&v=r20180108 image
-http://www.adobe.com/ http://servedby.flashtalking.com/container/10943;85008;8362;iframe/?spotName=Variables_Tag&ftXRef=&U1=25184214671657016004047640859236241357&U2=&U3=&U4=adobe.com&U5=&U6=&cachebuster=186263.40478416358 html
-http://www.uptodown.com/ http://cas.us.criteo.com/delivery/ajs.php?ptv=40&zoneid=1109006&cb=28419627976&nodis=1&charset=UTF-8&dc=1&atfr=1&loc=http%3A%2F%2Fen.uptodown.com%2F script
-http://www.adobe.com/ http://pixel.tapad.com/idsync/ex/receive?partner_id=ADB&partner_url=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=25028270030411042384063639909326814019 other
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/static/glade.js script
-http://www.adobe.com/ http://idsync.rlcdn.com/365868.gif?partner_uid=25028270030411042384063639909326814019 image
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&glade_req=1&glv=26&dt=1516016052354&output=html&iu=%2F1060150%2Fcriteo_passback_sticky_mobile&sz=320x50&sfv=1-0-10&correlator=17663013502526&adk=2178986565&biw=360&bih=512&adx=20&ady=462&oid=3&u_sd=3&ifi=1&nhd=1&url=http%3A%2F%2Fen.uptodown.com%2F&top=http%3A%2F%2Fen.uptodown.com%2F&ref=http%3A%2F%2Fwww.uptodown.com%2F html
-http://www.adobe.com/ http://sync.mathtag.com/sync/img?mt_exid=10004&mt_exuid=25028270030411042384063639909326814019&redir=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D269%26dpuuid%3D[MM_UUID]%26ddsuuid%3d25028270030411042384063639909326814019&mm_bnc&mm_bct image
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/static/glade/extra_26.js script
-http://www.adobe.com/ https://1295336.fls.doubleclick.net/activityi;src=1295336;type=idsync;cat=uuidm0;u1=NotSignedIn;u2=25028270030411042384063639909326814019;u3=25184214671657016004047640859236241357;u4=;u5=;u6=adobe.com;u7=%%dc_rdid%%;u8=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=7734256182617.27 html
-http://www.uptodown.com/ http://cat.sv.us.criteo.com/delivery/lg.php?cppv=1&cpp=WqjNfnxNY3J5Y1F0SEFHbHBRamJrQmtJV0c2RnJUSmxmTmJpRFNTY25LMG0veVF4WXlGemU5UjZtdFVWWVFKL0JmMnRTKzZyeERSZU5ZY2dTUTlwRm9EZXhrWlRlT0NDV2ZvWXU2RWg2SzRMYU4rdk1vclFFS0hLbHNvN3B0TGJHNVdjRHNOQjl6U3duRlZOYVNSd2t0Ky9wNEtFTVM2VjRsWHpXQ0EzK2YvclV0S1R0QjhBUUNmMXpYdXNKZFhrSlFhQ3ZqMmlIZERQMk5Sb1h1M3MxRk5hWXZsMmdJQnp4TDRnQ2NtNS9kOCtrT0RKeDdlWVZ5cUpzKzFWWmNvYkRyMWpjfA%3D%3D image
-http://www.adobe.com/ https://ad.doubleclick.net/ddm/activity/src=1295336;type=adobe994;cat=aamuuid;u2=25028270030411042384063639909326814019;u3=25184214671657016004047640859236241357;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord= html
-http://www.uptodown.com/ https://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.adobe.com/ http://magnetic.t.domdex.com/37764/pix.gif?t=c&for=Adobe image
-http://www.adobe.com/ http://scripts.demandbase.com/qQQxkRp0.min.js script
-http://www.uptodown.com/ https://tpc.googlesyndication.com/simgad/348304717651967069 image
-http://www.adobe.com/ http://pixel.tapad.com/idsync/ex/receive/check?partner_id=ADB&partner_url=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D%24%7BTA_DEVICE_ID%7D&partner_device_id=25028270030411042384063639909326814019 other
-http://www.uptodown.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjstbUA-9XarsscbjW9Flk2UDgREFu6BJMxGr8Y2tDC_uTkKzls-mELkIktScDMhczrvXvXLanvptz6qWzeq3d6RNeqVSrd-Zuw6kno9KDgSEJ15XVtuaisx_jtwXnUFypSNlYxVhr6rr4leMykoj-TtCPirVIYMtXhBtB7SFZEoqPX7qkK-cEXeg6F46s4e_qaMFDbv3X2MAcENygYCf54TLiN1kMigLVOkZV83Bau96On1nCSyWM-DeznyHfZ8QGwEWXeHb6kVFhzto6lD-0cFEJ3kOJoxYZkfYT2u9&sig=Cg0ArKJSzKxhXspVhAIqEAE&adurl= html
-http://www.adobe.com/ http://idsync.rlcdn.com/365868.gif?partner_uid=25028270030411042384063639909326814019&redirect=1 image
-http://www.uptodown.com/ https://tpc.googlesyndication.com/pagead/images/transparent.png image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=269&dpuuid=2e6b5a14-d62a-4800-9eba-296903a883e6&ddsuuid=25028270030411042384063639909326814019 image
-http://www.uptodown.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjsshj708d_KxPISfmHjUx_SX8x13MSg7g8HYKV753pFZ_9L8T3w3f-eHyfmERBk8wua6V3JjTJwIc6NoI7bbOoSLTNY-dfGAgFY&sig=Cg0ArKJSzEwGsVTgu8qwEAE&id=osdim&ti=1&adk=2180504997&tt=5028&bs=360,512&mtos=1036,1036,1036,1036,1036&tos=1036,0,0,0,0&p=462,20,512,340&inapp=0&mcvt=1036&rs=3&ht=0&tfs=4004&tls=5040&mc=1&lte=1&bas=0&bac=0&bos=360,512&ps=360,7646&ss=360,512&pt=12&deb=1-2-2-28-48-156&tvt=4897&op=1&avms=geo&r=v&uc=27&tgt=BODY&cl=1&cec=10&clc=0&cac=0320x50&v=r20180108 image
-http://www.adobe.com/ http://api.iperceptions.com/InviteTriggers script
-http://www.uptodown.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjstiLTJeZEsIKLD1SOeS8vZ0jmvpw3jU1s0eqGyhi7rXM3976Ou8zmRn0XRqokY32S_VOi8_aPY7g1VGahl8JM-7DsevnS78r98&sig=Cg0ArKJSzGHEjFo1wRTREAE&id=osdim&ti=1&adk=2178986565&tt=1032&bs=360,512&mtos=1030,1030,1030,1030,1030&tos=1030,0,0,0,0&p=462,20,512,340&inapp=0&mcvt=1030&rs=10&ht=0&tfs=190&tls=1220&mc=1&lte=1&bas=0&bac=0&bos=360,512&ps=360,7646&ss=360,512&pt=188&deb=1-1-1-8-11-15&tvt=1030&is=320,50&op=1&iframe_loc=http%3A%2F%2Fen.uptodown.com%2F&avms=geo&r=v&uc=11&tgt=DIV&cl=1&cec=5&clc=1&cac=0320x50&v=r20180108 image
-http://www.adobe.com/ http://magnetic.t.domdex.com/37764/pix.gif?t=c&for=Adobe&cc=1 image
-http://www.adobe.com/ https://connect.facebook.net/en_US/fbevents.js script
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=477&dpuuid=b1566d3a78c60c30366a3c0343f68ac2a879fca1c478e5340d4e0e4ace79cae4b0da87c991749652 image
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fwww.facebook.com%2Ffr%2Fb.php%3Fp%3D1531105787105294%26e%3D%24%7BTM_USER_ID%7D%26t%3D2592000%26o%3D0 other
-http://www.adobe.com/ https://cm.g.doubleclick.net/pixel?google_nid=adobe_dmp&google_cm html
-http://www.adobe.com/ http://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252Chttp%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253D3c48c3a1-f9e8-11e7-a71c-0242e5e63087 html
-http://www.adobe.com/ http://rtd.tubemogul.com/upi/pid/r7ifn0SL?redir=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D other
-http://www.adobe.com/ https://connect.facebook.net/signals/config/1944925959056690?v=2.8.6&r=stable script
-http://www.adobe.com/ http://rp.gwallet.com/r1/cm/p50 other
-http://www.adobe.com/ http://match.adsrvr.org/track/cmb/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252Chttp%253A%252F%252Fdpm.demdex.net%252Fibs%253Adpid%253D540%2526dpuuid%253D3c48c3a1-f9e8-11e7-a71c-0242e5e63087 html
-http://www.adobe.com/ http://p.rfihub.com/cm?in=1&pub=7085 other
-http://www.adobe.com/ https://cm.g.doubleclick.net/pixel?google_nid=adobe_dmp&google_cm=&google_tc= html
-http://www.adobe.com/ https://adservice.google.com/ddm/fls/i/src=1295336;type=idsync;cat=uuidm0;u1=NotSignedIn;u2=25028270030411042384063639909326814019;u3=25184214671657016004047640859236241357;u4=;u5=;u6=adobe.com;u7=%%DC_rdid%%;u8=;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=7734256182617.27;_dc_1=1;~oref=http://www.adobe.com/ html
-http://www.adobe.com/ https://adservice.google.com/ddm/fls/p/src=1295336;type=adobe994;cat=aamuuid;u2=25028270030411042384063639909326814019;u3=25184214671657016004047640859236241357;dc_lat=;dc_rdid=;tag_for_child_directed_treatment=;ord=;~oref=http://fast.adobe.demdex.net/dest5.html%3Fd_nsid%3D0 image
-http://www.adobe.com/ http://pixel.quantserve.com/pixel/p-vj4AYjBqd6VJ2.gif?idmatch=0 image
-http://www.adobe.com/ http://c.bing.com/c.gif?uid=25028270030411042384063639909326814019&Red3=MSAdobe_pd image
-http://www.adobe.com/ https://api.company-target.com/api/v2/ip.json?referrer=&page=http%3A%2F%2Fwww.adobe.com%2F&page_title=Adobe%3A%20Creative%2C%20marketing%20and%20document%20management%20solutions&key=b561357daf8504abd0ca9cc239218ae0 script
-http://www.adobe.com/ https://connect.facebook.net/signals/plugins/iwl.js?v=2.8.6 script
-http://www.adobe.com/ http://rp.gwallet.com/r1/cm/p50?check_uid_cookie other
-http://www.adobe.com/ http://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=cb1584c8-6a07-4b1f-882c-37a162f78d6d&ttd_puid=%2Chttp%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D540%26dpuuid%3D3c48c3a1-f9e8-11e7-a71c-0242e5e63087 other
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=1121&dpuuid=1978557984288739656 image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=1175&dpuuid=fl_GBHIMwlVmD8dXKA3eX3wIywJmDcpWfQmBh4HL image
-http://www.adobe.com/ http://pixel.advertising.com/ups/28/sync?uid=25028270030411042384063639909326814019&_origin=1&redir=true other
-http://www.adobe.com/ https://www.facebook.com/fr/b.php?p=1531105787105294&e=WlySAwAABOoNJqAC&t=2592000&o=0 image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=1957&dpuuid=084579838D916AC01CAC72FB899169D8 image
-http://www.adobe.com/ http://rtd-tm.everesttech.net/upi/pid/r7ifn0SL?redir=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D other
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=1127&dpuuid=AB-gqtP52WqBHW1KVKcbql4sQ&redir=http%3A%2F%2Frs.gwallet.com%2Fr1%2Fucm%3Fid%3D%24%7BDD_UUID%7D%26r1s%3D5qia99xmcuzhwczk588mfr74p5qxyafjadragwacpcokxoays3mo other
-http://www.adobe.com/ http://pixel.advertising.com/ups/28/sync?uid=25028270030411042384063639909326814019&_origin=1&redir=true&verify=true other
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=540&dpuuid=3c48c3a1-f9e8-11e7-a71c-0242e5e63087 image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=6835&dpuuid=UP3a509d57-f9e8-11e7-95e8-067c24bf1fe4 image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=782&dpuuid=WlySAwAABOoNJqAC image
-http://www.adobe.com/ http://adobe-sync.dotomi.com/adobe/match?nuid=25028270030411042384063639909326814019&rurl=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D other
-http://www.adobe.com/ http://a.tribalfusion.com/i.match?p=b13&u=25028270030411042384063639909326814019&redirect=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid=22054&dpuuid=$TF_USER_ID_ENC$ html
-http://www.adobe.com/ https://dpm.demdex.net/ibs:dpid=771&dpuuid=CAESEKRjNwNQ7IyEO8P2po1UD6Y&google_cver=1 image
-http://www.adobe.com/ http://ml314.com/utsync.ashx?eid=50112&et=0&return=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D22052%26dpuuid%3D[PersonID] image
-http://www.adobe.com/ http://adobe-sync.dotomi.com/adobe/match?dtm_test=23b5758f2923206d&nuid=25028270030411042384063639909326814019&rurl=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D19360%26dpuuid%3D other
-http://www.adobe.com/ http://a.tribalfusion.com/z/i.match?p=b13&u=25028270030411042384063639909326814019&redirect=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid=22054&dpuuid=$TF_USER_ID_ENC$ html
-http://www.adobe.com/ http://bttrack.com/dmp/adobe/user?dd_uuid=25028270030411042384063639909326814019 html
-http://www.adobe.com/ http://t.mookie1.com/rsp?dnv=%3CCACHEBUSTER%3E&rurl=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30862%26dpuuid%3D%5BMOOKIE%5D%26redir=http%253A%252F%252Ft.mookie1.com%252Ft%252Fv1%252Fevent%253FmigClientId%253D7413%2526migAction%253Dsync%2526migSource%253Dmig%2526migParam1%253D25028270030411042384063639909326814019 text
-http://www.adobe.com/ http://rs.gwallet.com/r1/ucm?id=25028270030411042384063639909326814019&r1s=5qia99xmcuzhwczk588mfr74p5qxyafjadragwacpcokxoays3mo image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=22052&dpuuid=5978151396634800775 image
-http://www.adobe.com/ https://cdnssl.clicktale.net/www/tc/monitor-latest.js script
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=19360&dpuuid=25028270030411042384063639909326814019 image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=22054 image
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=49276&dpuuid=f5d68e59-3a83-4f48-9197-728023d58e65 image
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D782%26dpuuid%3D%24%7BTM_USER_ID%7D other
-http://www.adobe.com/ http://cdn.clicktale.net/www/WR-latest.js script
-http://www.adobe.com/ http://cdn.clicktale.net/www20/pcc/544fc825-311a-44c5-86f0-70581a36c216.js?DeploymentConfigName=Release_20171206&Version=36 script
-http://www.adobe.com/ http://servedby.flashtalking.com/spot/8/10943;85008;8362/?spotName=Variables_Tag&ftXRef=&U1=25184214671657016004047640859236241357&U2=&U3=&U4=adobe.com&U5=&U6=&cachebuster=186263.40478416358&ft_trackID=36677471DB11A0 image
-http://www.adobe.com/ https://www.facebook.com/tr/?id=1944925959056690&ev=Microdata&dl=http%3A%2F%2Fwww.adobe.com%2F&rl=&if=false&ts=1516016147879&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22Adobe%3A%20Creative%2C%20marketing%20and%20document%20management%20solutions%22%2C%22meta%3Adescription%22%3A%22Adobe%20is%20changing%20the%20world%20through%20digital%20experiences.%20We%20help%20our%20customers%20create%2C%20deliver%20and%20optimize%20content%20and%20applications.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=30&ttf=24431.870000000003&tts=22216.175000000003&ttse=22922.390000000003 image
-http://www.adobe.com/ http://rtd.tubemogul.com/migrate_et3/ other
-http://www.adobe.com/ http://tag.clrstm.com/sync?dmp=adobe other
-http://www.adobe.com/ https://dpm.demdex.net/ibs:dpid=782&dpuuid=WlySAwAABOoNJqAC image
-http://www.adobe.com/ http://rtd-tm.everesttech.net/migrate_et3/ other
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/5w3jqr4k?redir=https%3A%2F%2Fcm.g.doubleclick.net%2Fpixel%3Fgoogle_nid%3Dg8f47s39e399f3fe%26google_push%26google_sc%26google_hm%3D%24%7BTM_USER_ID_BASE64ENC_URLENC%7D other
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/btu4jd3a?redir=https%3A%2F%2Fpixel.rubiconproject.com%2Ftap.php%3Fv%3D7941%26nid%3D2243%26put%3D%24%7BUSER_ID%7D%26expires%3D90 other
-http://www.adobe.com/ http://tag.clrstm.com/ul_cb/sync?dmp=adobe other
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/ZMAwryCI?redir=https%3A%2F%2Fdsum-sec.casalemedia.com%2Frum%3Fcm_dsp_id%3D88%26external_user_id%3D%24%7BTM_USER_ID%7D other
-http://www.adobe.com/ http://tlg.mookie1.com/rsp?dnv=%3CCACHEBUSTER%3E&rurl=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30862%26dpuuid%3D%5BMOOKIE%5D%26redir=http%253A%252F%252Ft.mookie1.com%252Ft%252Fv1%252Fevent%253FmigClientId%253D7413%2526migAction%253Dsync%2526migSource%253Dmig%2526migParam1%253D25028270030411042384063639909326814019 text
-http://www.adobe.com/ https://cm.g.doubleclick.net/pixel?google_nid=g8f47s39e399f3fe&google_push&google_sc&google_hm=V2x5U0F3QUFCT29OSnFBQw== image
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/UH6TUt9n?redir=https%3A%2F%2Fib.adnxs.com%2Fsetuid%3Fentity%3D158%26code%3D%24%7BTM_USER_ID%7D other
-http://www.adobe.com/ http://d.company-target.com/pixel?type=js&id=1421361246&page=http%3A%2F%2Fwww.adobe.com%2F other
-http://www.adobe.com/ http://d.company-target.com/pixel?type=js&id=1421361512&page=http%3A%2F%2Fwww.adobe.com%2F other
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=80119&dpuuid=6441c97e-26f2-4d86-83c0-bba010ac0f6e image
-http://www.adobe.com/ http://tlg.mookie1.com/rsp/cc?dnv=%3CCACHEBUSTER%3E&rurl=http%3A%2F%2Fdpm.demdex.net%2Fibs%3Adpid%3D30862%26dpuuid%3D%5BMOOKIE%5D%26redir=http%253A%252F%252Ft.mookie1.com%252Ft%252Fv1%252Fevent%253FmigClientId%253D7413%2526migAction%253Dsync%2526migSource%253Dmig%2526migParam1%253D25028270030411042384063639909326814019 text
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/ny75r2x0?redir=https%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D537148856%26val%3D%24%7BTM_USER_ID%7D other
-http://www.adobe.com/ http://d.company-target.com/ul_cb/pixel?type=js&id=1421361512&page=http%3A%2F%2Fwww.adobe.com%2F script
-http://www.adobe.com/ http://d.company-target.com/ul_cb/pixel?type=js&id=1421361246&page=http%3A%2F%2Fwww.adobe.com%2F script
-http://www.adobe.com/ http://dpm.demdex.net/ibs:dpid=30862&dpuuid=985306161802316&redir=http%3A%2F%2Ft.mookie1.com%2Ft%2Fv1%2Fevent%3FmigClientId%3D7413%26migAction%3Dsync%26migSource%3Dmig%26migParam1%3D25028270030411042384063639909326814019 other
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/b9pj45k4?redir=https%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA%3D%26piggybackCookie%3D%24%7BUSER_ID%7D other
-http://www.adobe.com/ https://d9.flashtalking.com/d9core script
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/h0r58thg?redir=https%3A%2F%2Fsync.search.spotxchange.com%2Fpartner%3Fadv_id%3D6409%26uid%3D%24%7BUSER_ID%7D%26img%3D1 other
-http://www.adobe.com/ http://t.mookie1.com/t/v1/event?migClientId=7413&migAction=sync&migSource=mig&migParam1=25028270030411042384063639909326814019 text
-http://www.adobe.com/ http://universal.iperceptions.com/core/IpEngine_v75.js script
-http://www.adobe.com/ https://www.facebook.com/tr/?id=1944925959056690&ev=PageView&dl=http%3A%2F%2Fwww.adobe.com%2F&rl=&if=false&ts=1516016146370&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=30&ttf=22923.600000000002&tts=22216.175000000003&ttse=22922.390000000003&it=1516016145678 image
-http://www.adobe.com/ https://ing-district.clicktale.net/ctn_v2/auth/?pid=100&as=1&m=1&2017406308&subsid=233200&msgsize=10 script
-http://www.adobe.com/ https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WlySAwAABOoNJqAC html
-http://www.adobe.com/ https://pixel.rubiconproject.com/tap.php?v=7941&nid=2243&put=WlySAwAABOoNJqAC&expires=90 other
-http://www.adobe.com/ http://cdn.clicktale.net/www/ChangeMonitor-latest.js script
-http://www.adobe.com/ https://d9.flashtalking.com/lgc text
-http://www.adobe.com/ https://ib.adnxs.com/setuid?entity=158&code=WlySAwAABOoNJqAC html
-http://www.adobe.com/ https://dsum-sec.casalemedia.com/rum?cm_dsp_id=88&external_user_id=WlySAwAABOoNJqAC&C=1 image
-http://www.adobe.com/ https://pixel.rubiconproject.com/tap.php?cookie_redirect=1&v=7941&nid=2243&put=WlySAwAABOoNJqAC&expires=90 image
-http://www.adobe.com/ http://cdn.clicktale.net/www/WR108b.js script
-http://www.adobe.com/ http://tlg.mookie1.com/t/v1/event?migClientId=7413&migAction=sync&migSource=mig&migParam1=25028270030411042384063639909326814019 image
-http://www.adobe.com/ https://conductor.clicktale.net/monitor?t=init&p=147&2=2137981942943010&v=1.4.11 text
-http://www.adobe.com/ http://servedby.flashtalking.com/track/85008;8362;403;36677471DB11A0/?ft_data=d9:834d4be11aa947f6b8b80de402b7216c&cachebuster=186995.28979332093 image
-http://www.adobe.com/ https://us-u.openx.net/w/1.0/sd?id=537148856&val=WlySAwAABOoNJqAC other
-http://www.adobe.com/ http://az452423.vo.msecnd.net/ius-76ebdeea04cf3415fce2e5af20c935b7/29293_636512132606190203 script
-http://www.adobe.com/ https://ing-district.clicktale.net/ctn_v2/wr/?1571975166492974&100&10&0&0&0&8&subsid=233200&msgsize=10 text
-http://www.adobe.com/ http://sync-tm.everesttech.net/upi/pid/r7ifn0SL?redir=https%3A%2F%2Fwww.facebook.com%2Ffr%2Fb.php%3Fp%3D1531105787105294%26e%3D%24%7BTM_USER_ID%7D%26t%3D2592000%26o%3D0 other
-http://www.adobe.com/ http://stats.adobe.com/b/ss/adbadobenonacdcprod/10/JS-2.5.0-D7QN/s13417579221129?AQB=1&ndh=1&pf=1&callback=s_c_il[4].doPostbacks&et=1&t=15%2F0%2F2018%203%3A35%3A50%201%20480&d.&nsid=0&jsonv=1&.d&D=D%3D&mid=25184214671657016004047640859236241357&aid=2D2E490105033A8B-60001197E013FE62&aamlh=9&ce=UTF-8&cdp=2&fpCookieDomainPeriods=2&pageName=adobe.com&g=http%3A%2F%2Fwww.adobe.com%2F&v73=1571975166492974.100&pe=lnk_o&pev2=Clicktale%20ID&mcorgid=9E1005A551ED61CA0A490D45%40AdobeOrg&AQE=1 script
-http://www.adobe.com/ https://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZqcz0xJmNvZGU9MjE5MSZ0bD0yNTkyMDA=&piggybackCookie=WlySAwAABOoNJqAC html
-http://www.adobe.com/ https://conductor.clicktale.net/monitor?t=preinit&p=147&2=2137981942943010&v=1.4.11&7=http%3A%2F%2Fwww.adobe.com%2F&3=6713363279352091&4=781559878007939&5=0 text
-http://www.adobe.com/ https://us-u.openx.net/w/1.0/sd?cc=1&id=537148856&val=WlySAwAABOoNJqAC image
-http://www.adobe.com/ https://www.facebook.com/fr/b.php?p=1531105787105294&e=WlySAwAABOoNJqAC&t=2592000&o=0 image
-http://www.adobe.com/ https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WlySAwAABOoNJqAC&img=1 other
-http://www.adobe.com/ https://sync.search.spotxchange.com/partner?adv_id=6409&uid=WlySAwAABOoNJqAC&img=1&__user_check__=1&sync_id=6d354e80-f9e8-11e7-a8b4-1e286a820001 image
-http://www.adobe.com/ https://wwwimages2.adobe.com/favicon.ico image
-http://www.adobe.com/ https://ing-district.clicktale.net/ctn_v2/wr/?1571975166492974&100&10&1&1&0&104&subsid=233200&msgsize=10 text
-http://www.adobe.com/ https://ing-district.clicktale.net/ctn_v2/wr/?1571975166492974&100&10&2&1&1&105&subsid=233200&msgsize=10 text
-http://www.adobe.com/ https://conductor.clicktale.net/monitor?t=chunk&p=147&2=2137981942943010&v=1.4.11 text
-http://www.adobe.com/ https://conductor.clicktale.net/monitor?t=chunk&p=147&2=2137981942943010&v=1.4.11 other
-http://www.savefrom.net/ http://www.savefrom.net/ html
-http://www.savefrom.net/ http://savefrom.net/ html
-http://www.savefrom.net/ http://en.savefrom.net/ html
-http://www.savefrom.net/ http://en.savefrom.net/js/libs/modernizr-2.8.3.min.js script
-http://www.savefrom.net/ http://en.savefrom.net/js/scripts_1.19.js?v=1 script
-http://www.savefrom.net/ http://en.savefrom.net/css/styles.css?v=1.120 css
-http://www.savefrom.net/ http://en.savefrom.net/js/savefrom_6.29.min.js?v=3 script
-http://www.savefrom.net/ http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js script
-http://www.savefrom.net/ http://imasdk.googleapis.com/js/sdkloader/ima3.js script
-http://www.savefrom.net/ http://en.savefrom.net/js/libs/share42_en_2.js?v=2 script
-http://www.savefrom.net/ http://en.savefrom.net/img/ummy_icon_16.png image
-http://www.savefrom.net/ http://en.savefrom.net/img/ummyradio/icon_16.png image
-http://www.savefrom.net/ https://fonts.googleapis.com/css?family=Open+Sans:400,600,700,300&subset=latin,cyrillic css
-http://www.savefrom.net/ http://en.savefrom.net/img/uvc_16.png image
-http://www.savefrom.net/ http://en.savefrom.net/img/logotip.png image
-http://www.savefrom.net/ http://en.savefrom.net/img/vdp_16.png image
-http://www.savefrom.net/ http://en.savefrom.net/img/smart_search/search_icon_32.png image
-http://www.savefrom.net/ http://en.savefrom.net/img/extension/info_new_yt/screenshot_en.png image
-http://www.savefrom.net/ http://www.google-analytics.com/analytics.js script
-http://www.savefrom.net/ http://en.savefrom.net/img/logo_small2.svg?v=1 image
-http://www.savefrom.net/ http://en.savefrom.net/img/menu.svg?v=1 image
-http://www.savefrom.net/ http://en.savefrom.net/img/favicons.png?v=3 image
-http://www.savefrom.net/ http://en.savefrom.net/img/arrows.png?v=3 image
-http://www.savefrom.net/ http://en.savefrom.net/img/after-video-download/popup-close.png image
-http://www.savefrom.net/ http://en.savefrom.net/img/flags.png?v=7 image
-http://www.savefrom.net/ https://fonts.gstatic.com/s/roboto/v18/Hgo13k-tfSpn0qi1SFdUfVtXRa8TVwTICgirnJhmVJw.woff2 font
-http://www.savefrom.net/ http://widget.manychat.com/1350927965011870.js?_=1516016025876 script
-http://www.savefrom.net/ http://en.savefrom.net/img/select2.png image
-http://www.savefrom.net/ https://themes.googleusercontent.com/static/fonts/opensans/v6/RjgO7rYTmqiVp7vzi-Q5UT8E0i7KZn-EPnyo3HZu7kw.woff font
-http://www.savefrom.net/ https://www.google-analytics.com/analytics.js script
-http://www.savefrom.net/ http://manychat.com/104567/assets/js/widget.js?909609617545 script
-http://www.savefrom.net/ https://manychat.com/104567/assets/js/widget.js?909609617545?909609617545 script
-http://www.savefrom.net/ https://fonts.googleapis.com/css?family=Lato:600,500,400,300 css
-http://www.savefrom.net/ https://fonts.gstatic.com/s/lato/v14/MDadn8DQ_3oT6kvnUq_2r_esZW2xOQ-xsNqO47m55DA.woff2 font
-http://www.savefrom.net/ http://connect.facebook.net/en_US/sdk.js script
-http://www.savefrom.net/ http://en.savefrom.net/favicon.ico image
-http://www.savefrom.net/ http://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.savefrom.net/ https://www.facebook.com/v2.6/plugins/send_to_messenger.php?app_id=532160876956612&channel=http%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FlY4eZXm_YWu.js%3Fversion%3D42%23cb%3Df174c05b335ddc%26domain%3Den.savefrom.net%26origin%3Dhttp%253A%252F%252Fen.savefrom.net%252Ff372f14b70a8a%26relation%3Dparent.parent&color=blue&container_width=177&locale=en_US&messenger_app_id=532160876956612&page_id=1350927965011870&ref=optin_959901_e4141564-b075-4ea2-9d9e-2af252487e20_6a3fb8e1-6f8d-3c5f-7f8d-44ace676651d&sdk=joey&size=xlarge html
-http://www.savefrom.net/ https://www.facebook.com/impression.php/f8343c7d230548/?api_key=532160876956612&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D image
-http://www.savefrom.net/ https://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/yv/l/0,cross/eh3WZ2NYPZy.css css
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/yh/l/0,cross/_ADoAUPd4oh.css css
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/yH/l/0,cross/pG7ANTf--oS.css css
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/y3/r/AM1U0a8QIn7.js script
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/y8/r/Q--sdT2937V.js script
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3ijLc4/yX/l/en_US/1G9xj2mCeRx.js script
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v1/yi/r/odA9sNLrE86.jpg image
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/yc/r/OZdF8Sasdxn.png image
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/yX/r/VKhZ02Dagk3.js script
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/yq/r/0plLwnjDTzX.js script
-http://www.savefrom.net/ https://www.facebook.com/rsrc.php/v3/ye/r/3_yIUnFcp3c.js script
-http://www.savefrom.net/ https://manychat.com/widget/log?event=impression&page_id=1350927965011870&widget_id=959901&user_sign=e4141564-b075-4ea2-9d9e-2af252487e20&sign=6a3fb8e1-6f8d-3c5f-7f8d-44ace676651d script
-http://www.amazon.co.uk/ https://www.amazon.co.uk/ html
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/51jo%2BAP3U9L._RC%7C31H9QnSNj3L.css,01+72+wCC9L.css_.css?AUIClients/NavMobileMetaAsset css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/21EugTBba7L.css?AUIClients/RetailSearchAutocompleteAssets css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/51YJM%2BVUcfL._RC%7C01-yf03D4rL.css,01gq5Ie9j3L.css,31stfprY0tL.css,01d8Fs5iBdL.css,21ZwnZnTQ7L.css,11UksSmDw-L.css,11+zKfQDbkL.css,21quTPIGBxL.css,01jkimhv0aL.css,318hCTMRXQL.css,01COiFb05sL.css,01djTkqmZSL.css,11pdOHTh95L.css,21g9AOmZB5L.css,11X2-nh0PYL.css,01h2e2BEitL.css,11AYjYP-YzL.css,11aMMTVEKqL.css,11oyQ9RIYtL.css,01vd5lqeZUL.css,31k72ulyOYL.css,01kPgnKe7wL.css,01MGoIPodIL.css,01Alnvtt1zL.css,01BBs40O5ZL.css_.css?AUIClients/AmazonUI css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41MjpWujmTL.css?AUIClients/GWMWebAssets css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/gno/sprites/sky_webnav_V1_sprite_1x._CB515271932_.png image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fstaticb%26id%3D4MJEQWKDP6PFXD1HSBQM%26pty%3DCheckoutThankYouWebview%26spty%3DAndroidPhone%26pti%3D3201:1000 image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/61ea4y7yPdL._RC%7C11IYhapguOL.js,61-dJ29Zw5L.js,21dmoxZTACL.js,01E8f3KV-NL.js,31fv8bqHLoL.js,31ReKJl2X6L.js,51nK0kUyg2L.js,11Mdh5CVmhL.js,01xMsWWFUQL.js,11KkQiUpBPL.js,113pP0Sfh0L.js,21auxuI+dRL.js,01PoLXBDXWL.js,61IUvg6RIjL.js,31y9nF9Z1BL.js,11SW3HEKjtL.js,01qkmZhGmAL.js,01eORIy6e6L.js_.js?AUIClients/AmazonUI script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/017jgg7jJRL._RC%7C414ftrYGv0L.js,11P4Lu1aIqL.js_.js?AUIClients/GWMWebAssets script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/21hyeuTdJ9L.js?AUIClients/MobileMarketingSmartAppBannerAssets script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41XJlIDdUUL._RC%7C01vojWHr8gL.js,31qKd4DgPkL.js_.js?AUIClients/NavMobileMetaAsset script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/510wwe1qMUL.js?AUIClients/RetailSearchAutocompleteAssets script
-http://www.amazon.co.uk/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-sprite_2x-a3d92a134e6afaec4974bceac0812b73d0b635c1._V2_.png image
-http://www.amazon.co.uk/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rg-cc7ebaa05a2cd3b02c0929ac0475a44ab30b7efa._V2_.woff2 font
-http://www.amazon.co.uk/ https://www.amazon.co.uk/uedata/unsticky/258-0076635-6530229/NoPageType/ntpoffrw?ld&v=0.1284.0&id=4MJEQWKDP6PFXD1HSBQM&bf=dall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-&m=1&sc=4MJEQWKDP6PFXD1HSBQM&ue=28&bb=1635&ns=1646&cf=1809&be=1875&af=1916&ne=2071&pc=3743&tc=-2179&na_=-2179&ul_=-1516016049460&_ul=-1516016049460&rd_=-1516016049460&_rd=-1516016049460&fe_=-2059&lk_=-2059&_lk=-1866&co_=-1866&_co=-1171&sc_=-1535&rq_=-1166&rs_=-102&_rs=387&dl_=-93&di_=1900&de_=1900&_de=1900&_dc=3743&ld_=3743&_ld=-1516016049460&ntd=0&ty=0&rc=0&hob=23&hoe=28&ld=3744&t=1516016053204&ctb=1&rt=cf:4-0-4-0-1-0-0_af:4-0-4-0-1-0-0_ld:13-5-4-2-3-0-0&csmtags=aui|aui:aui_build_date:3.17.20-2017-12-07|gwImgNoCached|fls-eu|pageEncoding:UTF-8|gwmNoCardHistory&viz=visible:28&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=4MJEQWKDP6PFXD1HSBQM&aftb=1 image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26bf%3Ddall_1-dcm_1-xhr_1-qs_1-ael_1-atob_1-pjs_0-njs_0-cjs_0-rhn_0-sel_0-chrm_0-plg_0-no_0-%26sc0%3Dgwm-head-aui-assets%26bb0%3D143%26cf0%3D1613%26pc0%3D1614%26ld0%3D1614%26t0%3D1516016051074%26sc1%3Dlg%26af1%3D1809%26pc1%3D1809%26ld1%3D1809%26t1%3D1516016051269%26sc2%3DcsmCELLSframework%26bb2%3D1859%26pc2%3D1859%26ld2%3D1859%26t2%3D1516016051319%26sc3%3DcsmCELLSpdm%26bb3%3D1859%26pc3%3D1872%26ld3%3D1872%26t3%3D1516016051332%26sc4%3DcsmCELLSvpm%26bb4%3D1872%26pc4%3D1872%26ld4%3D1872%26t4%3D1516016051332%26sc5%3DcsmCELLSfem%26bb5%3D1873%26pc5%3D1873%26ld5%3D1873%26t5%3D1516016051333%26sc6%3Dpc%26af6%3D1921%26cf6%3D1921%26pc6%3D1921%26ld6%3D1921%26t6%3D1516016051381%26sc7%3Dinteractivity%26cf7%3D3018%26pc7%3D3018%26ld7%3D3018%26t7%3D1516016052478%26ctb%3D1:3751 image
-http://www.amazon.co.uk/ https://m.media-amazon.com/images/G/01/csm/showads.v2.js script
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26sc0%3DtempPageLoaded%26cf0%3D3783%26pc0%3D3783%26ld0%3D3783%26t0%3D1516016053243%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:3788 image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/kindle/merch/2017/campaign/1951620/GW/AuCC/holiday/b-xmas-gw-d-1242x450-uk-v1._SX1242_CB493776708_.jpg image
-http://www.amazon.co.uk/ https://www.amazon.co.uk/favicon.ico image
-http://www.amazon.co.uk/ https://www.amazon.co.uk/gp/gw/ajax/dataStore.html/258-0076635-6530229?ie=UTF8&hmac=D3EE05A29A72A4D32CDD9D6502881F85ED3B38FB&opf_redir=1&relatedRequestId=4MJEQWKDP6PFXD1HSBQM script
-http://www.amazon.co.uk/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bd-46b91bda68161c14e554a779643ef4957431987b._V2_.woff2 font
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26sc0%3Diss-init-aw%26bb0%3D4261%26cf0%3D4273%26pc0%3D4273%26ld0%3D4273%26t0%3D1516016053733%26csmtags%3Diss-on-time-aw%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:4273 image
-http://www.amazon.co.uk/ https://www.amazon.co.uk/uedata/unsticky/258-0076635-6530229/NoPageType/ntpoffrw?at&v=0.1284.0&id=4MJEQWKDP6PFXD1HSBQM&m=1&sc=adblk_no&pc=4309&at=4309&t=1516016053769&csmtags=adblk_no&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=4MJEQWKDP6PFXD1HSBQM&aftb=1 image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26m%3D1%26sc%3Dadblk_no%26pc%3D4309%26at%3D4309%26t%3D1516016053769%26csmtags%3Dadblk_no%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:4310 image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/gno/sprites/sky_webnav_V1_sprite_2x._CB515271932_.png image
-http://www.amazon.co.uk/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/ClientSideMetricsAUIJavascript-96ea10f95c9c40ac3d7cc81f2d76b78f0fdf178b._V2_.js script
-http://www.amazon.co.uk/ https://images-na.ssl-images-amazon.com/images/G/01/AUIClients/MojibakeGarbledTextDetectionAssets-c1600921ba590f11b924a6928fdc699bedab0a0c._V2_.js script
-http://www.amazon.co.uk/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_rgit-9cc1bb64eb270135f1adf3a4881c2ee5e7c37be5._V2_.woff2 font
-http://www.amazon.co.uk/ https://m.media-amazon.com/images/G/01/AUIClients/AmazonUIBaseCSS-amazonember_bdit-80ff7aba37dd1ff5a6b90233a19e3a780a96dc2f._V2_.woff2 font
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26sc0%3Due_sushi_v1%26bb0%3D4857%26pc0%3D4867%26ld0%3D4867%26t0%3D1516016054327%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:4867 image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26sc0%3Ddata-store-1%26bb0%3D4122%26cf0%3D4888%26pc0%3D4888%26ld0%3D4888%26t0%3D1516016054348%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:4888 image
-http://www.amazon.co.uk/ https://www.amazon.co.uk/gp/gw/ajax/card.html/258-0076635-6530229?ie=UTF8&opf_redir=1&rshVal=1516016054440 html
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/digital/video/merch2016/mobile/GW_Mob_Evergreen_1242x450_FT._SX414_CB492371743_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/uk-sports/brands/Canterbury/AW16/AW16_RH_Training_Sq_1500px._UX350_SX350_CB527302663_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/digital/video/merch2016/mobile/GW_Mob_Evergreen_1242x450_FT._SX1242_CB492371743_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/uk-sports/brands/Canterbury/AW16/AW16_RH_Training_Sq_1500px._CB527302663_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/317Qb9WY18L._RC%7C51V43Ve3tjL.js_.js?AUIClients/SharedShoppingCartMobileAsset script
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fat%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26m%3D1%26sc%3D4MJEQWKDP6PFXD1HSBQM%26pc%3D5361%26at%3D5361%26t%3D1516016054821%26csmtags%3Di18n_ok%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:5361 image
-http://www.amazon.co.uk/ https://www.amazon.co.uk/uedata/unsticky/258-0076635-6530229/NoPageType/ntpoffrw?at&v=0.1284.0&id=4MJEQWKDP6PFXD1HSBQM&ctb=1&m=1&sc=4MJEQWKDP6PFXD1HSBQM&pc=5361&at=5361&t=1516016054821&csmtags=i18n_ok&pty=gateway-phone-web&spty=smartphone-card&pti=mobile&tid=4MJEQWKDP6PFXD1HSBQM&aftb=1 image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/318xlkYHrhL._RC%7C31JZUXRQoEL.css_.css?AUIClients/SharedShoppingCartMobileAsset css
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.co.uk&slot=navFooter&a2=0101f05ccabf59e55c2ff996cf5739f1b5fb0ce1cbd39d459651a71bf259d48de6cb&old_oo=0&cb=1516016049191 other
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/61PB34aXbtL._AC_SY80_.png image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/61GA3lSuDNL._AC_SY80_.png image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26sc0%3Dcard-load-1%26bb0%3D4980%26cf0%3D5889%26pc0%3D5931%26ld0%3D5931%26t0%3D1516016055391%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:5931 image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OP/A1F83G8C2ARO7P:258-0076635-6530229:4MJEQWKDP6PFXD1HSBQM$uedata=s:%2Fuedata%2Funsticky%2F258-0076635-6530229%2FNoPageType%2Fntpoffrw%3Fld%26v%3D0.1284.0%26id%3D4MJEQWKDP6PFXD1HSBQM%26ctb%3D1%26sc0%3Dgwm%26cf0%3D1809%26af0%3D5937%26pc0%3D5937%26ld0%3D5937%26t0%3D1516016055397%26pty%3Dgateway-phone-web%26spty%3Dsmartphone-card%26pti%3Dmobile%26tid%3D4MJEQWKDP6PFXD1HSBQM%26aftb%3D1:5937 image
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OE/ other
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/71g21uGppQL._AC_SY80_.png image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41CTN-5Kq0L._AC_SY200_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/kindle/merch/accessories/2017/Promo/EssentialsBundle/EanabBundle-Mobile_billboard-a-uk-1242x450._SX414_CB503933201_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/411Nkn1qbnL._AC_SY80_.jpg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41LDHJHtOnL._AC_SY80_.jpg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/iu3?d=amazon.co.uk&slot=navFooter&a2=0101f05ccabf59e55c2ff996cf5739f1b5fb0ce1cbd39d459651a71bf259d48de6cb&old_oo=0&cb=1516016049191&dcc=t html
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41W7w9dfhAL._AC_SY80_.jpg image
-http://www.dropbox.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBTfqhLjKLEJQZPin0KCzkdAQpVYowQUsT7DaQP4v0cB1JgmGggC72NkK8MCEAx5qUSwjBGVIJJhX%2BJrHYOiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/marketing/prime/dex/trafficdrivers/VXD-1095_GWMobileHero_1242x450_copy2._SX414_CB508068870_.jpg image
-http://www.dropbox.com/ https://www.dropbox.com/ html
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/01SHZTts1pL.css?AUIClients/DetailPageAlohaAssets css
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/scooter/scooter-scoped-vflhQ6850.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/01AtjzSY2EL.js?AUIClients/DetailPageAlohaAssets script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/spectrum/index-vflYL_8Rr.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/61PB34aXbtL._AC_SY240_.png image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/sprites/web_sprites-vflv2MHAO.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/11chYsfG59L._RC%7C411E-IzoCiL.js,31cePTj3CrL.js,11NxOa490XL.js,31E+jMbvKeL.js,21ydeSYKyxL.js,31hd9A67kaL.js,51wmFWz9R9L.js,51Hi2VfLU+L.js,21yUMfZsKLL.js,31Ime9qWaBL.js,016DBHJkIYL.js,21ng+A1rTWL.js,41mcGVaoxHL.js,81ewiHI9QoL.js,21hyeuTdJ9L.js,01H0TE47EIL.js,013NxCyC-FL.js,11QIUl6VLbL.js,21AuBaN+lVL.js,51YzCqyJFIL.js,0111g0cQvbL.js,01nKqcvaCIL.js,01X117Z9PgL.js,41kdD43EgvL.js,01X5C8pWB1L.js,518wG9hJ8NL.js,31egXBuM55L.js,01RHiyjONOL.js,31I-BifbuzL.js,210S22NrxIL.js,412fOjq25KL.js,314ZAgS3sJL.js,11U-t4vkrhL.js,21q5QmCNgJL.js,01q0JZaOPlL.js,01lijXu9CYL.js,31ze7I-RWjL.js,21p3ItvcX-L.js,21HlHGr1+aL.js,0193uyIciNL.js,51tR9VCi49L.js,71OuhyN2DxL.js,01BZK417f8L.js,319kjuuQkzL.js,01UujNMpLSL.js,41kgH1IIwSL.js,11ISJZDdTuL.js,11NHZnHlFmL.js,011lR1kB6CL.js,015J4NGaO3L.js,11B4fwZPeqL.js,21-q-ofQTaL.js,01lQqh9VSML.js,01jqyAujTwL.js,01jW+SjLRsL.js,01-XJ1YSEXL.js,01gaQLz1HjL.js,01NAT+3p7KL.js,01VbOIsFDdL.js,51yQ7wSC4tL.js,01MZJG6lH8L.js,01VtYReatCL.js,21LWJ90NCIL.js,01CyECqkeYL.js,01RQtSMdG+L.js,21JwQBfgBXL.js,01l3c7okxRL.js,01-Eu4U-17L.js,01qwoVEkKlL.js,011HXD1ky3L.js,011X+p22ALL.js,01k57x9vvBL.js,01RNXZDiBuL.js,01ZF+ovNflL.js,31MsfX4iIYL.js,01S8y9NkxoL.js,01XzM3S0ZtL.js,01JGca-NkDL.js,01WMAHenIIL.js,51tlWANRbLL.js_.js?AUIClients/DetailPageMobileWebMetaAsset script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/rebrand/elements/homepage_login_register_panel-vflWMqqkO.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/01uwSfX2vxL._RC%7C01j62IBqyaL.css,41CNXGW6T4L.css,318TvQQkpyL.css,31tH-GJ-doL.css,11tkAOwE6OL.css,21xItms32EL.css,11ISqSj9gHL.css,018pZJ+Ms7L.css,21t5UAtA4iL.css,21mvSipn7pL.css,21qOYA5+VOL.css,21QwDiO8ycL.css,01mnEQW78iL.css,31no24Dqj1L.css,01wBE2Z+USL.css,11xlykx3aFL.css,01D-B-OeNDL.css,21CNSKZ67ML.css,51oAYplAOyL.css,21hLnMMJrfL.css,21lDMA2J74L.css,215tV0Xf4NL.css,21thLxrpr2L.css,01swE6xAjEL.css,012dCODns-L.css,01TKZlySggL.css,21ZKosCj0iL.css,21pVn1+KCbL.css,21-9Q-rNd0L.css,01rgQ3jqo7L.css,01XzaDG7OBL.css,21UuKlej9VL.css,61ypmw1UTGL.css,014Z+MbaRaL.css,11hxZgqF80L.css,01QUs5FVXoL.css,016xTzXJLfL.css,31LBzl8T3vL.css,21cgaWigpnL.css,01YdhMxma0L.css,018mGORJ7tL.css,11fvu+DzMxL.css,11ho+83HCzL.css,01ticFfm7pL.css,01lh9w-GYYL.css,11Mso4bvY-L.css,01LCsoCesOL.css,01ifu3nZXpL.css,21Yyo4tu6ZL.css_.css?AUIClients/DetailPageMobileWebMetaAsset css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/21RnT33X0YL.js?AUIClients/AutomotiveEUMobileAssets script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/recaptcha_v2_challenge-vflLfwbvt.css css
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/rebrand/elements/footer-vfltwB7V6.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/61GA3lSuDNL._AC_SY240_.png image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/recaptcha_challenge-vflrcf67y.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/81MDTSEXQgL.js?AUIClients/GoldboxUDPAssets script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/010NMV%2Bm-jL.css?AUIClients/AutomotiveEUMobileAssets css
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/modal-vfls56Rdx.css css
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/v3/pr?exlist=pp_sx_ns_kr_g_bsw_bk_ox_index_aold_an_rb_br_fbca_aolv_twca_y_pm_adelphic_adb&fv=1.0&ex-pl-fbca=30kmw-qIRrici1IxSeAoFQ&ex-pl-twca=m1Q9S4ujTW2GeR8K9ErDDQ&a=cm&ep=G6_155CvqDFVOuZpqr_OFDrGQcrRx4VnlHv0IocdrizugPkTqfU1AmW2OF9OWulN html
-http://www.amazon.co.uk/ https://unagi-eu.amazon.com/1/events/com.amazon.csm.nexusclient.prod script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/login_or_register-vflTH-z_u.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/71g21uGppQL._AC_SY240_.png image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/components/rebrand_navigation-vfltYo44i.css css
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41CTN-5Kq0L._AC_SY600_.jpg image
-http://www.amazon.co.uk/ https://bh.contextweb.com/bh/rtset?pid=557477&ev=&rurl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%25%25VGUID%25%25%26ex%3Dpulsepoint.com%26 other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/components/rebrand_plane-vflGHJ5Ou.css css
-http://www.amazon.co.uk/ https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm&ex=doubleclick.net& html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/components/rebrand_sidekick-vfl4fHbq3.css css
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=jgvaLEC95BLs&ex=pulsepoint.com&&ev=&pid=557477 image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/obsidian/logo-vflM1D8V1.css css
-http://www.amazon.co.uk/ https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1 other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/legacy_packages/components-vflC9ETTX.css css
-http://www.amazon.co.uk/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__ html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/rebrand_page-vfl53TdSc.css css
-http://www.amazon.co.uk/ https://cm.g.doubleclick.net/pixel?google_nid=a9eu&google_cm=&ex=doubleclick.net&google_tc= html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/components/login_form-vfleIcXNF.css css
-http://www.amazon.co.uk/ https://tags.bluekai.com/site/36840?redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3D%24_BK_UUID%26ex%3Dbluekai.com%26 other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/components/react_locale_selector-vflK3A4bZ.css css
-http://www.amazon.co.uk/ https://aa.agkn.com/adscores/g.pixel?sid=9212284268 other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/components/rebrand_hero-vflkvw3uD.css css
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/components/rebrand_media-vfluSiI-a.css css
-http://www.amazon.co.uk/ https://usermatch.krxd.net/um/v2?partner=amzn other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/accessibility-vflMqZNeg.css css
-http://www.amazon.co.uk/ https://x.bidswitch.net/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/components/button-vfl-_t7Pp.css css
-http://www.amazon.co.uk/ https://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/components/exp_cards-vflJsYU3g.css css
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/css/index/components/rebrand_creation-vflKfQ5Ls.css css
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=doubleclick.net&google_gid=CAESEAwNQ7kBbUeYvG9lE7uWaik&google_cver=1 image
-http://www.dropbox.com/ https://fonts.googleapis.com/css?family=Open+Sans:100,200,300,400,600,700&subset=latin,latin-ext css
-http://www.amazon.co.uk/ https://pixel.advertising.com/ups/56613/sync?redir=true&_origin=1&verify=true other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/alameda_bundle/alameda_bundle.min-vflHM5cap.js script
-http://www.amazon.co.uk/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_aqua.svg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/wordmarks/wordmark_white.svg image
-http://www.amazon.co.uk/ https://ssum-sec.casalemedia.com/usermatchredir?s=184155&cb=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dindex%26id%3D__UID__&C=1 html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/co_create/mobile/dropbox_digital_mobile_01@2x-vflD5Yy9V.jpg image
-http://www.amazon.co.uk/ https://x.bidswitch.net/ul_cb/sync_a9/https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dbidswitch.com%26id%3D%24%7BUUID%7D other
-http://www.amazon.co.uk/ https://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dopenx.com%26id%3D image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/co_create/mobile/dropbox_digital_mobile_02@2x-vflHbuTFv.jpg image
-http://www.amazon.co.uk/ https://sync.search.spotxchange.com/partner?adv_id=7922&redir=https://aax-eu.amazon-adsystem.com%2Fs/ecm3?ex%3Dspotx.com%26id%3D%24SPOTX_USER_ID&__user_check__=1&sync_id=40388b7f-f9e8-11e7-b278-119d6fb00001 other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_cherry.svg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=8a1cdfafb15a57486b2dc24524baea1ac47256ed&ex=aoldisplay.com image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/wordmarks/wordmark_black.svg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=index&id=Ew6mioH4q0twUkazUkpuNTdqc3o4ZgIC image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=bidswitch.com&id=05ab7a02c6adcf80d5f346c66e0e1fd7 image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_dark_blue.svg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=openx.com&id=04202552-ce12-c90a-2444-96742567ac64 image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/product/core/core_ui_mobile@2x-vflEs81im.jpg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=spotx.com&id=4038e4a6-f9e8-11e7-b278-119d6fb00001 image
-http://www.amazon.co.uk/ https://stags.bluekai.com/site/36841?dt=0&r=1013389691&sig=266897515&bkca=KJyguAlJnnnBvYAovaRN5kxNzQmih1xvl5HuFzEzhvgXwBlWkmnvTonDUnlAda0QjeWxo0q7s3LSrtVZ3O3f3O3jhe+8hTKsKQvjj3APxvsA7BnDf1H1i9Rp9W1JcNA= other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_yellow.svg image
-http://www.amazon.co.uk/ https://ib.adnxs.com/getuid?https://aax-eu.amazon-adsystem.com/s/ecm3?id=$UID&ex=appnexus.com& image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/product/paper/paper_ui_mobile@2x-vflt1FHUx.jpg image
-http://www.amazon.co.uk/ https://d.agkn.com/pixel/8198/?che=1516016058&sk=164791302571000795747&pd=&l0=https://s.amazon-adsystem.com/ecm3?id=164791302571000795747&ex=neustar.biz other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/logos/glyphs/glyph_blue.svg image
-http://www.amazon.co.uk/ https://cm.g.doubleclick.net/pixel?google_nid=bluekai&google_cm&google_sc html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/icons/icon_spacer-vflN3BYt2.gif image
-http://www.amazon.co.uk/ https://beacon.krxd.net/usermatch.gif?kuid_status=new&partner=amzn image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/security_keys/insert-vflkCfC4_.png image
-http://www.amazon.co.uk/ https://tags.bluekai.com/site/2981?id=&google_gid=CAESECGnGgdt2UxvcAZM9kB9ZNQ&google_cver=1 image
-http://www.amazon.co.uk/ https://token.rubiconproject.com/token?pid=2179&pt=n other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/icons/ajax-loading-small-vfl3Wt7C_.gif image
-http://www.amazon.co.uk/ https://www.facebook.com/fr/r.php?p=558293300959460&e=30kmw-qIRrici1IxSeAoFQ&r=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dfbca%26id%3D30kmw-qIRrici1IxSeAoFQ&s=1516016056&h=bzFyazY5VnFLTnJ6UUgzR-XI2KL9m9z7pvw4eIThg57BpJ5X html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/fonts/sharpgrotesk/SharpGroteskDBBook20-vflytuLBR.woff2 font
-http://www.amazon.co.uk/ https://geo-um.btrll.com/v1/map_pixel/partner/63.png image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-button-cheeseburger-vflBv7pSe.svg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=fbca&id=30kmw-qIRrici1IxSeAoFQ image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/fonts/sharpgrotesk/SharpGroteskDBMedium22-vflPPMtcG.woff2 font
-http://www.amazon.co.uk/ https://analytics.twitter.com/i/adsct?p_id=985&p_user_id=m1Q9S4ujTW2GeR8K9ErDDQ&twitter_redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dtwca%26id%3Dm1Q9S4ujTW2GeR8K9ErDDQ%26 html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/fonts/atlasgrotesk/AtlasGrotesk-Regular-Web-vflg7ta4-.woff font
-http://www.amazon.co.uk/ https://ads.yahoo.com/cms/v1?esig=1~6772d6d12bf5fd5c41ee5ef107d84db09124942a&nwid=10000936839&sigv=1 text
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-arrow-aqua-vflrYQuro.svg image
-http://www.amazon.co.uk/ https://geo-um.btrll.com/v1/map_pixel/partner/63.png?set_aps=1&BR_APS=3WlyRvUjrAisBhxmIzA& image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-button-cheeseburger__black-vflOBpd_i.svg image
-http://www.amazon.co.uk/ https://sync.adaptv.advertising.com/sync?rUrl=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Daolvideo.com%26id%3D%7BBUYER_HASHED_USER_ID%7D text
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/logo_catalog/logotype_m1-vfltuHich.svg image
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/kindle/merch/accessories/2017/Promo/EssentialsBundle/EanabBundle-Mobile_billboard-a-uk-1242x450._SX1242_CB503933201_.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/ob-button-close-vflzGggYo.svg image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?p_user_id=m1Q9S4ujTW2GeR8K9ErDDQ&ex=twca&id=m1Q9S4ujTW2GeR8K9ErDDQ image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/fonts/sharpgrotesk/SharpGroteskDBMedium20-vfloPliP8.woff2 font
-http://www.amazon.co.uk/ https://image5.pubmatic.com/AdServer/usersync/usersync.html?predirect=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID html
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/sprites/web_2x_sprites-vflN8VDFL.png image
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=rightmedia.com&xid=E0 image
-http://www.dropbox.com/ https://dropbox.com/hstsping other
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=3WlyRvUjrAisBhxmIzA&ex=brightroll.com&n=1516016061& image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-timing.min-vflp7n81J.js script
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=aolvideo.com&id=289fb89c59c71d50c4da622358e0913649c6c0a6 image
-http://www.amazon.co.uk/ https://s.amazon-adsystem.com/ecm3?id=164791302571000795747&ex=neustar.biz image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-index-rebrand.min-vflrq56lZ.js script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/411Nkn1qbnL._AC_SY240_.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-coreui.min-vflUlwEut.js script
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=DFADFA6B-40C8-4A67-AC94-8F84ABED7C60&ex=pubmatic.com image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-exception-reporting.min-vflCIA_bM.js script
-http://www.amazon.co.uk/ https://s.amazon-adsystem.com/ecm3?id=&ex=rubiconproject.com&status=no-user-id image
-http://www.amazon.co.uk/ https://sync.ipredictive.com/d/sync/cookie/generic?https://aax-eu.amazon-adsystem.com/s/ecm3?id=${ADELPHIC_CUID}&ex=adelphic other
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41LDHJHtOnL._AC_SY240_.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-telemetry.min-vfl9joyKo.js script
-http://www.amazon.co.uk/ https://dpm.demdex.net/ibs:dpid=139200&dpuuid=fec6N5cmSrKRNq3ffTX_Mg&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-external.min-vflzygzOm.js script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/I/41W7w9dfhAL._AC_SY240_.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/redux-thunk-2.1.0.min-vflyq1AZ7.js script
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?id=076e56ad-f9e8-11e7-bedc-6fde7aefa7ff&ex=adelphic image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-core.min-vflQrPi_I.js script
-http://www.amazon.co.uk/ https://images-eu.ssl-images-amazon.com/images/G/02/marketing/prime/dex/trafficdrivers/VXD-1095_GWMobileHero_1242x450_copy2._SX1242_CB508068870_.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-i18n.min-vflpN5E37.js script
-http://www.amazon.co.uk/ https://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=139200&dpuuid=fec6N5cmSrKRNq3ffTX_Mg&redir=https%3A%2F%2Faax-eu.amazon-adsystem.com%2Fs%2Fecm3%3Fex%3Dadobe.com%26id%3D%24%7BDD_UUID%7D image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-rebrand-core.min-vflwSblBm.js script
-http://www.amazon.co.uk/ https://aax-eu.amazon-adsystem.com/s/ecm3?ex=adobe.com&id=65724109875761167590029409518778335092 image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-xhr-client.min-vfl-TXz3N.js script
-http://www.amazon.co.uk/ https://fls-eu.amazon.co.uk/1/batch/1/OE/ other
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-modules-unneeded-for-home.min-vflWi9pG9.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-react-15.5.4-prod.min-vflVLIAJV.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/langpack/en.json?17545 script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/accessibility/tabbable.min-vfl-JKEFx.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/index_rebrand.min-vflL3RP6g.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-legacy-ab.min-vflY-32Sm.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/react/index/components/rebrand_footer_plane.min-vflPcUdDd.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/react/index/components/rebrand_plane.min-vflDBvPSo.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-coreui-with-i18n.min-vflAAwglQ.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-lasso-footer.min-vflGFunOQ.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/jquery_bundle/jquery_bundle.min-vflVNaNHj.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-prompt.min-vflQfnHVs.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-misc.min-vflpRpd2B.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/hi_res.min-vflf-Wbx9.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-profile_services.min-vflzXB9Mg.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-coreui-forms.min-vfl8x5liQ.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/abuse/recaptcha_helper.min-vflq1NK4f.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/cyfd_init.min-vfl4IyrLD.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/react/paper/paper_log.min-vflcPLJ18.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth/u2f.min-vflwGib47.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/create-react-class-shim.min-vfl82nDw6.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/pixie.min-vflMGHwsI.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/auth_event_logger.min-vflm407ey.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/modules/clean/global_constants.min-vflxItXmN.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/cyfd.min-vflpIHoJf.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/u2f-api.min-vflHi1vKQ.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-payments-common.min-vflPV3utg.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/packaged/pkg-calendar.min-vflk8IFh-.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/product/core/core_ui_desktop@2x-vflLsWztX.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/rebrand/product/paper/paper_ui_desktop@2x-vflj8awd7.jpg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/icons/icon_caps_lock@2x-vflz_EymR.png image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/checkmark-vfl56VRyi.svg image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/index/google-logo-color-vflpJqkMT.svg image
-http://www.dropbox.com/ https://www.dropbox.com/log/ux_analytics text
-http://www.dropbox.com/ https://rebrand.dropboxstatic.com/videos/homepage_paper_ui.mp4 video
-http://www.dropbox.com/ https://rebrand.dropboxstatic.com/videos/homepage_coredb_ui.mp4 video
-http://www.dropbox.com/ https://www.dropbox.com/ajax_register text
-http://www.dropbox.com/ https://marketing.dropbox.com/?referrer= html
-http://www.dropbox.com/ https://www.dropbox.com/ajax_needs_signup_captcha text
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/compiled/js/external/zxcvbn.min-vflXrsFxo.js script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/icons/ajax-loading-small@2x-vflAxdZTP.gif image
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/security_keys/insert@2x-vflTxG2RJ.png image
-http://www.dropbox.com/ https://www.google.com/recaptcha/api.js?onload=recaptchaOnloadCallback&render=explicit script
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/fonts/roboto/Roboto-Medium-webfont-vflGvvuWg.woff2 font
-http://www.dropbox.com/ https://fonts.gstatic.com/s/opensans/v15/cJZKeOuBrn4kERxqtaUH3ZBw1xU1rKptJj_0jans920.woff2 font
-http://www.dropbox.com/ https://www.dropbox.com/log/ux_analytics text
-http://www.dropbox.com/ https://www.gstatic.com/recaptcha/api2/v1514934548259/recaptcha__en.js script
-http://www.dropbox.com/ https://www.googletagmanager.com/gtm.js?id=GTM-K8WT2R script
-http://www.dropbox.com/ https://www.dropbox.com/log/ux_analytics text
-http://www.dropbox.com/ https://www.google-analytics.com/analytics.js script
-http://www.dropbox.com/ https://www.googleadservices.com/pagead/conversion.js script
-http://www.dropbox.com/ https://www.googleadservices.com/pagead/conversion_async.js script
-http://www.dropbox.com/ https://static.ads-twitter.com/uwt.js script
-http://www.dropbox.com/ https://sjs.bizographics.com/insight.min.js script
-http://www.dropbox.com/ https://s.yimg.com/wi/ytc.js script
-http://www.dropbox.com/ https://b92.yahoo.co.jp/js/s_retargeting.js script
-http://www.dropbox.com/ https://8166291.fls.doubleclick.net/activityi;src=8166291;type=dpbxg0;cat=dpbx_0;ord=8305443992824;gtm=G1c;~oref=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D html
-http://www.dropbox.com/ https://www.google-analytics.com/plugins/ua/linkid.js script
-http://www.dropbox.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=1386038344&t=pageview&_s=1&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ul=en-us&de=windows-1252&dt=Dropbox&sd=24-bit&sr=360x512&vp=&je=0&_u=aGBAgUAj~&jid=1709656506&gjid=1877520203&cid=1800070688.1516015936&tid=UA-279179-2&_gid=1519423086.1516015936&gtm=G1cK8WT2R&cd47=en&z=480199579 image
-http://www.dropbox.com/ https://b92.yahoo.co.jp/search/?p=0GPI4UYVBZ&label=&ref=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rref=&pt=&item=&cat=&price=&quantity=&r=1516015936.3925686 script
-http://www.dropbox.com/ https://snap.licdn.com/li.lms-analytics/insight.min.js script
-http://www.dropbox.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/971301452/?random=1516015935683&cv=8&fst=1516015935683&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&rfmt=3&fmt=4 script
-http://www.dropbox.com/ http://ocsp.digicert.com/MHEwbzBNMEswSTAJBgUrDgMCGgUABBRJ9L2KGL92BpjF3kAtaDtxauTmhgQUPdNQpdagre7zSmAKZdMh1Pj41g8CEAxZqYy%2B4LY6VknLzEtXLRiiHjAcMBoGCSsGAQUFBzABBAQNMAsGCSsGAQUFBzABAQ%3D%3D other
-http://www.dropbox.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/960612778/?random=1516015935855&cv=8&fst=1516015935855&num=1&guid=ON&eid=376635470%2C659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&gtm=G1c&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4 script
-http://www.dropbox.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/977748509/?random=1516015935891&cv=8&fst=1516015935891&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&gtm=G1c&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4 script
-http://www.dropbox.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/949424158/?random=1516015935896&cv=8&fst=1516015935896&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&gtm=G1c&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4 script
-http://www.dropbox.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/1000051215/?random=1516015935887&cv=8&fst=1516015935887&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&gtm=G1c&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4 script
-http://www.dropbox.com/ https://googleads.g.doubleclick.net/pagead/viewthroughconversion/971301452/?random=1516015935875&cv=8&fst=1516015935875&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&gtm=G1c&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&rfmt=3&fmt=4 script
-http://www.dropbox.com/ https://sp.analytics.yahoo.com/sp.pl?a=1000543649509&jsonp=YAHOO.ywa.I13N.handleJSONResponse&d=Mon%2C%2015%20Jan%202018%2011%3A32%3A15%20GMT&n=8&b=Dropbox&.yp=25979&f=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&enc=windows-1252&isIframe=1 script
-http://www.dropbox.com/ https://sp.analytics.yahoo.com/sp.pl?a=10000&jsonp=YAHOO.ywa.I13N.handleJSONResponse&d=Mon%2C%2015%20Jan%202018%2011%3A32%3A15%20GMT&n=8&b=Dropbox&.yp=10030786&f=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&enc=windows-1252&isIframe=1 script
-http://www.dropbox.com/ https://analytics.twitter.com/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvx41&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=1&tpx_cb=twttr.conversion.loadPixels&cache_bust=0.6851047772730725 script
-http://www.dropbox.com/ https://www.google.com/ads/user-lists/971301452/?random=1516015935683&cv=8&fst=1516014000000&num=1&label=j-t9CI7XnFkQzMSTzwM&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&fmt=3&cdct=2&is_vtc=1&random=3937876110&rmt_tld=0&ipr=y image
-http://www.dropbox.com/ https://adservice.google.com/ddm/fls/i/src=8166291;type=dpbxg0;cat=dpbx_0;ord=8305443992824;gtm=G1c;_dc_1=1;~oref=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D html
-http://www.dropbox.com/ https://t.co/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nvx41&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=1 image
-http://www.dropbox.com/ https://www.google.com/ads/user-lists/1000051215/?random=1516015935887&cv=8&fst=1516014000000&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=619930254&rmt_tld=0&ipr=y image
-http://www.dropbox.com/ https://www.google.com/ads/user-lists/949424158/?random=1516015935896&cv=8&fst=1516014000000&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=2102526655&rmt_tld=0&ipr=y image
-http://www.dropbox.com/ https://www.google.com/ads/user-lists/960612778/?random=1516015935855&cv=8&fst=1516014000000&num=1&guid=ON&eid=376635470%2C659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=2273660535&rmt_tld=0&ipr=y image
-http://www.dropbox.com/ https://www.google.com/ads/user-lists/971301452/?random=1516015935875&cv=8&fst=1516014000000&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=1028612705&rmt_tld=0&ipr=y image
-http://www.dropbox.com/ https://www.google.com/ads/user-lists/977748509/?random=1516015935891&cv=8&fst=1516014000000&num=1&guid=ON&eid=659238991&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_his=3&u_tz=-480&u_java=false&u_nplug=0&u_nmime=0&frm=2&url=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&tiba=Dropbox&async=1&fmt=3&cdct=2&is_vtc=1&random=3021755119&rmt_tld=0&ipr=y image
-http://www.dropbox.com/ https://connect.facebook.net/en_US/fbevents.js script
-http://www.dropbox.com/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-279179-2&cid=1800070688.1516015936&jid=1709656506&gjid=1877520203&_gid=1519423086.1516015936&_u=aGBAgUAj~&z=1080264338 html
-http://www.dropbox.com/ https://www.google.com/ads/ga-audiences?v=1&aip=1&t=sr&_r=4&tid=UA-279179-2&cid=1800070688.1516015936&jid=1709656506&_v=j66&z=1080264338 image
-http://www.dropbox.com/ https://px.ads.linkedin.com/collect/?time=1516015937537&pid=4373&url=&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&fmt=js&s=1 other
-http://www.dropbox.com/ https://connect.facebook.net/signals/config/1097950916987081?v=2.8.6&r=stable script
-http://www.dropbox.com/ https://dc.ads.linkedin.com/collect/?time=1516015937537&pid=4373&url=&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&fmt=js&s=1 other
-http://www.dropbox.com/ https://px.ads.linkedin.com/collect/?time=1516015937537&pid=4373&url=&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&fmt=js&s=1&cookiesTest=true other
-http://www.dropbox.com/ https://connect.facebook.net/signals/config/1559459634097838?v=2.8.6&r=stable script
-http://www.dropbox.com/ https://www.dropbox.com/log/ux_analytics text
-http://www.dropbox.com/ https://secure.adnxs.com/getuid?https://px.ads.linkedin.com/collect/?time=1516015937537&pid=4373&url=&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&ref=&fmt=js&s=1&cookiesTest=true&anId=%24UID image
-http://www.dropbox.com/ https://connect.facebook.net/signals/plugins/iwl.js?v=2.8.6 script
-http://www.dropbox.com/ https://www.bizographics.com/collect/?pid=4373&ref=&s=1&url=&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&fmt=js&time=1516015937537 other
-http://www.dropbox.com/ https://www.facebook.com/tr/?id=1097950916987081&ev=PageView&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1516015939570&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=28&ttf=10188.380000000001&tts=9377.27&ttse=10186.095000000001&it=1516015938772 image
-http://www.dropbox.com/ https://www.facebook.com/tr/?id=1559459634097838&ev=PageView&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1516015940678&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=30&ttf=11296.295&tts=9377.27&ttse=11296.06&it=1516015938772 image
-http://www.dropbox.com/ https://www.facebook.com/tr/?id=1097950916987081&ev=Microdata&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1516015941075&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22Dropbox%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=28&ttf=11693.375&tts=9377.27&ttse=11296.06 image
-http://www.dropbox.com/ https://us-west-2.dc.ads.linkedin.com/collect/?pid=4373&ref=&s=1&url=&pageUrl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&fmt=js&time=1516015937537&ck= other
-http://www.dropbox.com/ https://www.facebook.com/tr/?id=1559459634097838&ev=Microdata&dl=https%3A%2F%2Fmarketing.dropbox.com%2F%3Freferrer%3D&rl=&if=true&ts=1516015942179&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%7D&cd[Meta]=%7B%22title%22%3A%22Dropbox%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=30&ttf=12797.805000000002&tts=9377.27&ttse=11296.06 image
-http://www.dropbox.com/ https://secure.adnxs.com/getuid?https%3A%2F%2Fwww.linkedin.com%2Fcsp%2Fdtag%3Fp%3D9%26_x%3D%252526opid%25253D4373%252526fmt%25253Djs%252526ref%25253D%252526ck%25253D%252526url%25253D%252526s%25253D1%252526pageUrl%25253Dhttps%2525253A%2525252F%2525252Fmarketing.dropbox.com%2525252F%2525253Freferrer%2525253D%252526time%25253D1516015937537%2525263pc%25253Dtrue%252526an_user_id%25253D%24UID image
-http://www.dropbox.com/ https://www.dropbox.com/alternate_wtl_browser_performance_info text
-http://www.dropbox.com/ https://www.dropbox.com/log_js_sw_data text
-http://www.dropbox.com/ https://cfl.dropboxstatic.com/static/images/favicon-vflUeLeeY.ico image
-http://www.dropbox.com/ https://www.dropbox.com/alternate_wtl text
-http://www.dropbox.com/ https://www.dropbox.com/log/ux_analytics text
-http://www.dropbox.com/ https://www.dropbox.com/log_js_sw_data text
-http://www.diply.com/ http://www.diply.com/ other
-http://www.diply.com/ http://diply.com/ html
-http://www.diply.com/ http://diply.com/v2/scss/src/components/app.min.css?v=yju-zmfPPuk4Mdadr3eYUyayBNQyRTDh_9BG64Rwogw css
-http://www.diply.com/ http://diply.com/v2/js/src/components/analytics.min.js?v=NbdkoZriHcMo2MSOk02Lkof9MISV768q0EXlGASAg7A script
-http://www.diply.com/ http://diply.com/v2/scss/src/components/siteHead.min.css?v=2_80_qkD4fMbtPLnv6mantzoFbclwGCfjXFlF-KhUrs css
-http://www.diply.com/ http://diply.com/v2/scss/src/components/site.min.css?v=-Auqiz78WisCsTzRjQPbAUhlRdHxKdZHdVQsniD9htg css
-http://www.diply.com/ http://diply.com/v2/scss/src/components/home.min.css?v=8DGM3oFMNt3BCl9xo6dWAVT15Q_L3jefO1TpSTiaN_M css
-http://www.diply.com/ http://cdn.diply.com/resources/Fonts/Arimo.woff font
-http://www.diply.com/ http://cdn.diply.com/resources/Fonts/Font-Arimo.min.css css
-http://www.diply.com/ http://cdn.diply.com/resources/dipbid/delta.js?ver=12/31/2017 script
-http://www.diply.com/ http://cdn.diply.com/resources/Fonts/ArimoBold.woff font
-http://www.diply.com/ http://cdn.diply.com/resources/js/jquery-2.2.0.min.js script
-http://www.diply.com/ http://cdn.diply.com/resources/js/js.cookie.min.js script
-http://www.diply.com/ http://cdn.diply.com/resources/js/ads.min.js script
-http://www.diply.com/ https://www.googletagservices.com/tag/js/gpt.js script
-http://www.diply.com/ http://diply.com/v2/js/src/components/feed.min.js?v=wyPvjcGb03KeT51w37j8bRDKPQ_8QDVgqbbbS94MsCY script
-http://www.diply.com/ http://service-auth.diply.com/api/v1/auth/view script
-http://www.diply.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.diply.com/ https://adservice.google.com/adsid/integrator.sync.js?domain=diply.com script
-http://www.diply.com/ http://diply.com/v2/js/src/components/home.min.js?v=LJgc6ZGitRlMFNF5wlQgqE8lngR2Gdkq5mbHh-5J7wY script
-http://www.diply.com/ http://diply.com/v2/img/crafty.jpg image
-http://www.diply.com/ http://diply.com/v2/js/src/components/site.min.js?v=iuQpmBB_trRWEy6PVF6cRvK_wbJbGdE5C-2E8xaqxY8 script
-http://www.diply.com/ http://cdn.diply.com/resources/js/handlebars-4.0.5.min.js script
-http://www.diply.com/ http://cdn.diply.com/resources/js/headroom-0.9.3.min.js script
-http://www.diply.com/ http://cdn.diply.com/resources/dipbid/videoPlayer.js?ver=12/31/2017 script
-http://www.diply.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=2138385982097864&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fif&adsid=NT&eid=21060362%2C21061149&sc=0&sfv=1-0-14&iu=%2F28725707%2FDiplyNet_Home&sz=300x250%7C320x100%7C320x50&cookie_enabled=1&abxe=1&lmt=1516015928&dt=1516015928141&frm=20&biw=360&bih=512&oid=3&adx=16&ady=106&adk=50941798&gut=v2&ifi=1&u_tz=-480&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fdiply.com%2F&dssz=24&icsg=928&std=0&csl=51&vrg=172&vis=1&scr_x=0&scr_y=0&ga_vid=1633812065.1516015928&ga_sid=1516015928&ga_hid=180195975 script
-http://www.diply.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_172.js script
-http://www.diply.com/ https://goviral-engine-bus.servicebus.windows.net/views-in-hub/messages/?timeout=60 other
-http://www.diply.com/ https://goviral-engine-bus.servicebus.windows.net/views-in-hub/messages/?timeout=60 xml
-http://www.diply.com/ http://content.jwplatform.com/libraries/e5z09GtQ.js script
-http://www.diply.com/ https://securepubads.g.doubleclick.net/pcs/view?xai=AKAOjssQWRePrMfwZPPKft0OJ-tKbroTRseh7IZQrBv-nsYAaQcpCg9ypRifeQeN8IU24ppcfECZ0KEE9xQqtR-ULBvtPoyiYVEHrXKd_0fDfdoKSRnHzi0o3ow36niwsXoxMTuAFoz6hIQDSfar7YsZvm8LVwlTsiq1k3BiZFlxyW2QyLpFbYlTGOK_JDPaMFPreuoAQuaKCBEzvNLzP4SXN7cQ5vabtzEhOYek8C0FIXTG02JPvCm_&sig=Cg0ArKJSzH047fJg1k9iEAE&adurl= html
-http://www.diply.com/ http://ds-aksb-a.akamaihd.net/aksb.min.js script
-http://www.diply.com/ http://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.diply.com/ https://www.googletagmanager.com/gtm.js?id=GTM-WD2DK3 script
-http://www.diply.com/ https://www.google-analytics.com/analytics.js script
-http://www.diply.com/ http://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.diply.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener.js script
-http://www.diply.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_qs_click_protection.js script
-http://www.diply.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_window_focus_non_hydra.js script
-http://www.diply.com/ https://tpc.googlesyndication.com/simgad/2892869277396911080 image
-http://www.diply.com/ http://diply.com/v2/img/Flawless-Cover.png image
-http://www.diply.com/ http://diply.com/v2/img/Delicious-Cover.png image
-http://www.diply.com/ http://diply.com/v2/img/Crafty-Cover.png image
-http://www.diply.com/ https://www.google-analytics.com/gtm/js?id=GTM-M6BDP4F&cid=1633812065.1516015928 script
-http://www.diply.com/ http://tpc.googlesyndication.com/pagead/images/transparent.png image
-http://www.diply.com/ http://service-search.diply.com/api/v2/search/publishedarticles/mustread?pageSize=100&next=&locale=en script
-http://www.diply.com/ https://www.google-analytics.com/collect?v=1&_v=j66&a=180195975&t=pageview&_s=1&dl=http%3A%2F%2Fdiply.com%2F&ul=en-us&de=UTF-8&dt=Diply&sd=24-bit&sr=360x512&vp=360x512&je=0&_u=aCjAgEADQ~&jid=445365049&gjid=866764120&cid=1633812065.1516015928&tid=UA-44184928-2&_gid=576429235.1516015930&gtm=G1cWD2DK3&cd2=&cd8=0&cd14=3%3A32%3A10%3A198am&cd15=N%2FA&cd19=1516015930185.g506ru4&cd25=2000&cd27=PALOALTO&cd28=CA&cd36=US&cm1=-1516015922.4&cm2=7.1&cm3=-1516015929.5&cd13=1633812065.1516015928&z=259201723 image
-http://www.diply.com/ https://data.diply.com/production/public/content/query/homepage/v2/slots script
-http://www.diply.com/ http://static.ads-twitter.com/uwt.js script
-http://www.diply.com/ http://connect.facebook.net/en_US/fbevents.js script
-http://www.diply.com/ http://connect.facebook.net/en_US/sdk.js script
-http://www.diply.com/ https://d31qbv1cthcecs.cloudfront.net/atrk.js script
-http://www.diply.com/ https://sb.scorecardresearch.com/b?c1=2&c2=17462746&ns__t=1516015930222&ns_c=UTF-8&c8=Diply&c7=http%3A%2F%2Fdiply.com%2F&c9= other
-http://www.diply.com/ https://secure.quantserve.com/quant.js script
-http://www.diply.com/ https://stats.g.doubleclick.net/r/collect?t=dc&aip=1&_r=3&v=1&_v=j66&tid=UA-44184928-2&cid=1633812065.1516015928&jid=445365049&gjid=866764120&_gid=576429235.1516015930&_u=aCjAgEADQ~&z=169742116 image
-http://www.diply.com/ http://img.diply.com/article-images/a/650e6ec4-6c4a-49f3-a58e-16e5b2094cc4.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/bd4a2e5f-5d43-4deb-ab8b-38b8a8f54c21.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/a5fb7f31-cc07-4d52-9171-1da08e00508b.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/c2abef21-6ada-47c9-b820-72fa90e8c681.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/4ae5233b-c26e-4d63-9a27-c899e6c4c635.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/20ff7f5a-24bd-4367-a05e-761c38025f20.png?impolicy=mobile image
-http://www.diply.com/ http://connect.facebook.net/signals/config/969519813086003?v=2.8.6&r=stable script
-http://www.diply.com/ https://sb.scorecardresearch.com/b2?c1=2&c2=17462746&ns__t=1516015930222&ns_c=UTF-8&c8=Diply&c7=http%3A%2F%2Fdiply.com%2F&c9= other
-http://www.diply.com/ http://img.diply.com/article-images/a/77717232-a054-4438-a3f3-2b54fa3b9613.jpg?impolicy=desktop image
-http://www.diply.com/ http://img.diply.com/article-images/a/7187645e-de30-45b4-8c42-d265ab4b16d1.jpg?impolicy=mobile image
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/jwplayer.controls.js script
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/skins/bekle.css css
-http://www.diply.com/ http://img.diply.com/article-images/a/a6f160ba-567d-4f68-bc7e-6cdb920296b0.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/a8138324-5d42-42ea-92d3-e423d9488bd7.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/6e1d285d-8e18-4970-a32a-dacc8194242d.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/1e7ffca1-548c-4502-a529-3916d72e49d7.jpg?impolicy=mobile image
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/provider.html5.js script
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/jwpsrv.js script
-http://www.diply.com/ http://t.co/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nxeax&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0 image
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/related.js script
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/sharing.js script
-http://www.diply.com/ http://img.diply.com/article-images/a/9632d178-8b2b-4dd4-8604-45f716fd024f.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/eaa2fe2d-a8d9-45c1-a1db-a551f21b05a8.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/04870c00-ee89-47f8-89ef-1a0c362ca542.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/f97a254d-f700-4c45-b8ac-503d8d667524.png?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/5a98acfd-9b74-4679-8164-034c0927cc90.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/49a6d8dd-9bac-446b-8788-492ecdb09c23.png?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/7dee0486-beae-408e-974e-597523a58335.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/28442e6c-e77e-4289-8c18-e00026965adc.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/ae0d8c64-3f19-4bbf-87ff-a630daf6fbc8.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/34c1ecd3-5743-4754-bc36-af0e67b4db1e.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/fde65fc8-ac05-4914-ba0b-0b482db43016.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/70e6b84e-7c79-4d42-9104-1a59add2b9ef.jpg?impolicy=mobile image
-http://www.diply.com/ http://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.diply.com/ http://img.diply.com/article-images/a/82bb382a-d10d-4060-8f49-6297978652da.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/9b54bd45-bc8a-4424-ae38-ceb2a5bb9564.jpg?impolicy=mobile image
-http://www.diply.com/ http://img.diply.com/article-images/a/97b8a46f-68a4-4003-90b1-c0b732d0d206.jpg?impolicy=mobile image
-http://www.diply.com/ https://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.diply.com/ http://rules.quantcount.com/rules-p-z0zMG4nCgXzzj.js script
-http://www.diply.com/ http://cloudfront-labs.amazonaws.com/x.png image
-http://www.diply.com/ https://pagead2.googlesyndication.com/pcs/activeview?xai=AKAOjst6tFEzi3uYdTja7E0eA8jA4fEQL4xr9NQKu7z6-4wHBlEn3OI7zUnUY-cv5XiKKp3wR2AIup82H8hkBcNPJyLa6O2kWn2aJ7Y&sig=Cg0ArKJSzEYsjtpF_JXlEAE&id=osdim&ti=1&adk=50941798&tt=1613&bs=360,512&mtos=1414,1414,1414,1414,1414&tos=1414,0,0,0,0&p=1815,30,2065,330&inapp=0&mcvt=1414&rs=3&ht=0&tfs=198&tls=720&mc=1&lte=1&bas=0&bac=0&bos=360,512&ps=360,6538&ss=360,512&pt=-1&deb=1-0-1-5-4--1&tvt=1420&op=1&avms=geo&r=v&uc=5&tgt=DIV&cl=1&cec=5&clc=1&cac=0300x250&v=r20180108 image
-http://www.diply.com/ http://ssl.p.jwpcdn.com/player/v/7.12.11/provider.cast.js script
-http://www.diply.com/ https://d5nxst8fruw4z.cloudfront.net/atrk.gif?frame_height=512&frame_width=360&iframe=0&title=Diply&time=1516015932049&time_zone_offset=480&screen_params=360x512x24&java_enabled=0&cookie_enabled=1&ref_url=&host_url=http%3A%2F%2Fdiply.com%2F&random_number=20654964217&sess_cookie=3faed541160f99752902de9d3be&sess_cookie_flag=1&user_cookie=3faed541160f99752902de9d3be&user_cookie_flag=1&dynamic=true&domain=diply.com&account=PA4wi1asyr00gj&jsv=20130128&user_lang=en-US image
-http://www.diply.com/ https://www.facebook.com/tr/?id=969519813086003&ev=PageView&dl=http%3A%2F%2Fdiply.com%2F&rl=&if=false&ts=1516015932490&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=28&ttf=9040.635&tts=7798.25&ttse=9035.455000000002&it=1516015931272 image
-http://www.diply.com/ https://www.facebook.com/tr/?id=627392657291988&ev=fb_page_view&dl=http%3A%2F%2Fdiply.com%2F&rl=&if=false&ts=1516015932413&sw=360&sh=512 image
-http://www.diply.com/ https://www.facebook.com/impression.php/f3a3a9e2065e71c/?api_key=627392657291988&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D image
-http://www.diply.com/ https://www.facebook.com/tr/?id=969519813086003&ev=Microdata&dl=http%3A%2F%2Fdiply.com%2F&rl=&if=false&ts=1516015932997&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Aurl%22%3A%22http%3A%2F%2Fdiply.com%2F%22%2C%22og%3Atype%22%3A%22website%22%2C%22og%3Atitle%22%3A%22Diply%22%2C%22og%3Aimage%22%3A%22http%3A%2F%2Fcdn.diply.com%2Fstatic-images%2Fv2%2Fico%2Fapple-touch-icon-210-precomposed.jpg%22%2C%22og%3Aimage%3Awidth%22%3A%221200%22%2C%22og%3Aimage%3Aheight%22%3A%22630%22%2C%22og%3Adescription%22%3A%22Diply%20is%20a%20leading%20social%20entertainment%20publisher%20that%20creates%20captivating%20content%20for%20millennials.%20We%20are%20a%20ComScore%20Top%2010%20Lifestyle%20property%20with%201%20billion%20video%20views%20monthly.%22%2C%22og%3Asite_name%22%3A%22Diply%22%7D&cd[Meta]=%7B%22title%22%3A%22Diply%22%2C%22meta%3Adescription%22%3A%22Diply%20is%20a%20leading%20social%20entertainment%20publisher%20that%20creates%20captivating%20content%20for%20millennials.%20We%20are%20a%20ComScore%20Top%2010%20Lifestyle%20property%20with%201%20billion%20video%20views%20monthly.%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=28&ttf=9546.54&tts=7798.25&ttse=9043.66 image
-http://www.diply.com/ http://pixel.quantserve.com/pixel;r=456941885;labels=Diply;rf=0;a=p-z0zMG4nCgXzzj;url=http%3A%2F%2Fdiply.com%2F;fpan=1;fpa=P0-484533183-1516015935454;ns=0;ce=1;cm=;ref=;je=0;sr=360x512x24;enc=n;dst=1;et=1516015935450;tzo=480;ogl=url.http%3A%2F%2Fdiply%252Ecom%2F%2Ctype.website%2Ctitle.Diply%2Cimage.http%3A%2F%2Fcdn%252Ediply%252Ecom%2Fstatic-images%2Fv2%2Fico%2Fapple-touch-icon-210-precomposed%252Ejpg%2Cimage%3Awidth.1200%2Cimage%3Aheight.630%2Cdescription.Diply%20is%20a%20leading%20social%20entertainment%20publisher%20that%20creates%20captivating%20conte%2Csite_name.Diply image
-http://www.diply.com/ http://a3edd13139e9bc07216c3372c36457b87.profile.mnl50.cloudfront.net/test.png image
-http://www.diply.com/ https://cdns.diply.com/article-images/a/77717232-a054-4438-a3f3-2b54fa3b9613_desktop.jpg image
-http://www.diply.com/ https://cdns.diply.com/article-images/a/7187645e-de30-45b4-8c42-d265ab4b16d1_desktop.jpg image
-http://www.diply.com/ https://www.gstatic.com/cv/js/sender/v1/cast_sender.js?loadCastFramework=1 script
-http://www.diply.com/ https://diply-vh.akamaihd.net/i/delivery/22/b9/22b96ddf-9f75-4a9f-a928-6592b8c8c9cf/11d4002d-82e9-43db-9c58-dd7395ba0f96_,600k_4,200k_1,400k_3,600k_3,1000k_3,1500k_2,800k_4,200k_2,1500k_4,800k_1,1000k_4,2500k_3,2500k_2,400k_1,4000k,.mp4.csmil/master.m3u8 other
-http://www.diply.com/ http://www.gstatic.com/cast/sdk/libs/sender/1.0/cast_framework.js script
-http://www.diply.com/ http://www.gstatic.com/eureka/clank/58/cast_sender.js script
-http://www.diply.com/ http://www.gstatic.com/eureka/clank/cast_sender.js script
-http://www.diply.com/ https://sb.scorecardresearch.com/c2/17462746/cs.js script
-http://www.diply.com/ https://www.google-analytics.com/r/collect?v=1&_v=j66&a=180195975&t=event&ni=1&_s=1&dl=http%3A%2F%2Fdiply.com%2F&ul=en-us&de=UTF-8&dt=Diply&sd=24-bit&sr=360x512&vp=360x512&je=0&ec=Page%20Load%20Performance&ea=%2F&el=15.8&ev=16&_u=6CjAAEADQ~&jid=1571069749&gjid=1064409756&cid=1633812065.1516015928&tid=UA-44184928-2&_gid=576429235.1516015930&_r=1&gtm=G1cWD2DK3&cd2=&cd8=0&cd14=3%3A32%3A18%3A323am&cd15=N%2FA&cd25=2000&cd27=PALOALTO&cd28=CA&cd36=US&cm1=15.8&cm2=7.1&cm3=8.7&cd29=1&cd30=2131223066&cd31=1516015926&cd32=1516015926&cd33=1516015926&z=1286425291 html
-http://www.diply.com/ http://cdn.diply.com/static-images/v2/ico/favicon.ico image
-http://www.diply.com/ https://stats.g.doubleclick.net/r/collect?v=1&aip=1&t=dc&_r=3&tid=UA-44184928-2&cid=1633812065.1516015928&jid=1571069749&_gid=576429235.1516015930&gjid=1064409756&_v=j66&z=1286425291 image
-http://www.diply.com/ http://jwpltx.com/v1/jwplayer6/ping.gif?h=299095840&e=e&tv=2.21.0&n=5482612890276646&aid=akJOBoEXEeenFAY3v_uBow&ed=3&pv=7.12.11&sdk=0&emi=1k0xi1d1ib0n&ph=1&pid=e5z09GtQ&pgi=1t5ga6k13vn4&lid=e17zfe1t7i84&stc=1&prc=1&pli=19zaifg1ap6b&tvs=0&c=-1&fv=&plt=11150&st=1850&plc=8&pd=2&vp=1&ab=0&po=0&s=1&r=1&sn=bekle&cb=1&ga=0&dd=1&rf=http%3A%2F%2Fcontent.jwplatform.com%2Ffeed.json%3Ffeed_id%3DKML436JL%26related_media_id%3DMEDIAID&pbc=0&d=0&pp=html5&ps=4&wd=0&pl=0&vb=0&vi=0&at=1&i=0&vl=90&mt=1&ccp=0&eb=1&pbr=1&pbd=1&mu=https%3A%2F%2Fdiply-vh.akamaihd.net%2Fi%2Fdelivery%2F22%2Fb9%2F22b96ddf-9f75-4a9f-a928-6592b8c8c9cf%2F11d4002d-82e9-43db-9c58-dd7395ba0f96_%2C600k_4%2C200k_1%2C400k_3%2C600k_3%2C1000k_3%2C1500k_2%2C800k_4%2C200k_2%2C1500k_4%2C800k_1%2C1000k_4%2C2500k_3%2C2500k_2%2C400k_1%2C4000k%2C.mp4.csmil%2Fmaster.m3u8&cp=0&pyc=0&pii=0&pss=1&t=Raise%20Your%20Nature%20Game%20With%20This%20Golden%20Concrete%20Plant%20Stand&pu=http%3A%2F%2Fdiply.com%2F&pt=Diply image
-http://www.diply.com/ http://i95143f00-ds-aksb-a.akamaihd.net/2/535267/b?dE=327&cS=327&cE=629&rqS=629&rsS=935&rsE=1238&sS=&dl=943&di=6025&fp=4885&dlS=6076&dlE=6167&dc=14717&leS=14718&leE=14823&to=&ol=0&cr=302&mt=&mb=&b=257&u=http%3A//diply.com/&ua=Mozilla/5.0%20%28Linux%3B%20Android%206.0.1%3B%20Moto%20G%20%284%29%20Build/MPJ24.139-64%29%20AppleWebKit/537.36%20%28KHTML%2C%20like%20Gecko%29%20Chrome/58.0.3029.81%20Mobile%20Safari/537.36%20PTST/180111.190127&pl=Linux%20x86_64&us=&gh=184.50.88.113&t=&rid=177b0eb0&r=20211&akM=ch&akN=ae&vc=13:15&bpcip=95143f00&akTX=1&akTI=177b0eb0&ai=255027&pmgn=&pmgi=&pmp= html
-http://www.diply.com/ https://analytics.twitter.com/i/adsct?p_id=Twitter&p_user_id=0&txn_id=nxeax&events=%5B%5B%22pageview%22%2Cnull%5D%5D&tw_sale_amount=0&tw_order_quantity=0&tw_iframe_status=0&tpx_cb=twttr.conversion.loadPixels&cache_bust=0.07967576399781984 script
-http://www.cnn.com/ http://www.cnn.com/ html
-http://www.cnn.com/ http://www.cnn.com/css/2.58.4/global.css css
-http://www.cnn.com/ http://www.cnn.com/css/2.58.4/pages/page.css css
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/2.58.4/js/cnn-header-second.min.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/cnn-header.bb0d864591f5bdfc609e-first-bundle.js script
-http://www.cnn.com/ http://cdn.optimizely.com/js/131788053.js script
-http://www.cnn.com/ http://cdn.cnn.com/analytics/cnnexpan/jsmd.min.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/2.58.4/js/cnn-footer-lib.min.js script
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_politics.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_money.png image
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/2.58.4/js/cnn-analytics.min.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/2.58.4/js/gigya-sharebar.min.js script
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_entertainment.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_tech.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_style_new.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_travel.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/vr/vr_new_asset.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/menu_bleacher.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_espaniol.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_nav_bottom.png image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_arabic.png image
-http://www.cnn.com/ https://logx.optimizely.com/log/event text
-http://www.cnn.com/ https://logx.optimizely.com/log/decision text
-http://www.cnn.com/ http://native.sharethrough.com/assets/sfp-creative-hub-listener.js script
-http://www.cnn.com/ http://static.chartbeat.com/js/chartbeat_mab.js script
-http://www.cnn.com/ http://ads.rubiconproject.com/header/11078.js script
-http://www.cnn.com/ http://c.amazon-adsystem.com/aax2/apstag.js script
-http://www.cnn.com/ http://static.criteo.net/js/ld/publishertag.js script
-http://www.cnn.com/ http://cdn.krxd.net/controltag?confid=ITb_4eqO script
-http://www.cnn.com/ https://a125375509.cdn.optimizely.com/client_storage/a125375509.html html
-http://www.cnn.com/ http://www.ugdturner.com/xd.sjs script
-http://www.cnn.com/ http://www.googletagservices.com/tag/js/gpt.js script
-http://www.cnn.com/ http://ssl.cdn.turner.com/ads/adfuel/modules/keypress.js script
-http://www.cnn.com/ http://ssl.cdn.turner.com/ads/adfuel/modules/dhtmlxgrid.js script
-http://www.cnn.com/ http://cdn3.optimizely.com/js/geo2.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/usabilla.431efe788e222a8c6b8a.bundle.js script
-http://www.cnn.com/ http://www.cnn.com/data/ocs/section/index3.html:homepage-magellan-zone-1/views/zones/common/zone-manager.izl script
-http://www.cnn.com/ http://www.cnn.com/data/ocs/section/index3.html:homepage-magellan-zone-2/views/zones/common/zone-manager.izl script
-http://www.cnn.com/ https://logx.optimizely.com/log/decision text
-http://www.cnn.com/ https://logx.optimizely.com/log/decision text
-http://www.cnn.com/ https://logx.optimizely.com/log/event text
-http://www.cnn.com/ http://cdn.krxd.net/ctjs/controltag.js.a44b3dbbe01052e7f96183d0a266743c script
-http://www.cnn.com/ http://bat.bing.com/bat.js script
-http://www.cnn.com/ http://static.yieldmo.com/ym.m2.js script
-http://www.cnn.com/ http://amplify.outbrain.com/cp/obtp.js script
-http://www.cnn.com/ http://cdn.cnn.com/ads/cnn/singles/cnn_homepage_rb.js script
-http://www.cnn.com/ http://tag.bounceexchange.com/340/i.js script
-http://www.cnn.com/ http://cdn.livefyre.com/Livefyre.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/one_tap.cca9193cce0d141db9fe.bundle.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/weather.cc2fe338d8278c5852d1.bundle.js script
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/170120113809-25-inauguration-donald-trump-0120-small-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/171206061203-flake-trump-02-small-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/120411111923-mlk-speaking-small-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180115141317-jakarta-stock-exchange-0115-01-small-34.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e1mo/img/4.0/logos/logo_cnn_badge_2up.png image
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/2.58.4/assets/video_buffer_square_blk.gif image
-http://www.cnn.com/ http://www.cnn.com/.a/2.58.4/assets/sprite-chrome.png image
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-regular.woff2 font
-http://www.cnn.com/ https://adservice.google.com/adsid/integrator.js?domain=www.cnn.com script
-http://www.cnn.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_172.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-medium.woff2 font
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-bold.woff2 font
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-light.woff2 font
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/icons/2.3.3/cnn-icons.woff font
-http://www.cnn.com/ http://cdn3.optimizely.com/js/geo2.js?cb=1516016261606 script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/grid_resize.622dd53a3dfd19b9f928.bundle.js script
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-italic.woff2 font
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/fonts/cnn/3.5.0/cnnsans-lightit.woff2 font
-http://www.cnn.com/ http://mab.chartbeat.com/mab_strategy/headline_testing/get_strategy/?host=cnn.com&domain=cnn.com&path=%2F script
-http://www.cnn.com/ http://0914.global.ssl.fastly.net/ad2/script/x.js?cb=1516016261561 script
-http://www.cnn.com/ http://ad.doubleclick.net/ddm/ad/ormq/;ord=1516016261612 image
-http://www.cnn.com/ http://0914.global.ssl.fastly.net/ad2/img/x.gif?cb=1516016261558 image
-http://www.cnn.com/ http://0914.global.ssl.fastly.net/ad2/img/x.gif?cb=1516016261622 image
-http://www.cnn.com/ http://cdn.cnn.com/ads/cnn/cnn_homepage.js script
-http://www.cnn.com/ http://data.cnn.com/jsonp/breaking_news/domestic.json?callback=CNNBreakingNewsCallback script
-http://www.cnn.com/ http://widgets.outbrain.com/outbrain.js script
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/170120113809-25-inauguration-donald-trump-0120-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/171206061203-flake-trump-02-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/120411111923-mlk-speaking-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180115141317-jakarta-stock-exchange-0115-01-large-34.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180114184848-casino-shuttle-boat-fire-nr-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180114064317-turkey-plane-skids-off-runway-newday-00000000-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180114004610-bill-murray-steve-bannon-snl-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180114062118-saturday-night-live-president-oprah-00000000-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180112123927-jld-sons-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180114204216-saints-vikings-nfl-playoffs-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/170808213332-how-hawaii-is-preparing-for-a-nuclear-strike-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/131017090017-09-cory-booker-1017-story-top.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180115182936-north-korea-moranbong-band-160511-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180112011447-santa-barbara-county-fire-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180115114413-zainab-wanted-posted-split-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/130828193955-mlk-memorial-large-169.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/171215164822-trump-12-15-2017-large-tease.jpg image
-http://www.cnn.com/ http://metrics.cnn.com/b/ss/cnn-adbp-domestic/1/H.26.1/s15493195192617?AQB=1&ndh=1&t=15%2F0%2F2018%203%3A37%3A42%201%20480&fid=3BD061AB4C1A7DBC-03CA17704898AFE3&ce=UTF-8&ns=cnn&pageName=cnn%3Ain%3A%2F&g=http%3A%2F%2Fwww.cnn.com%2F&cc=USD&ch=cnn%20homepage&server=cnn.com&events=event26&c5=nvs&v5=D%3Dc5&c8=new%3A1&v8=D%3Dc8&c9=nvs&v9=D%3Dc9&c13=section&v13=D%3Dc13&v15=1403&c17=anonymous&v17=D%3Dc17&c20=0&v20=D%3Dc20&v22=0&c26=www.cnn.com%2F&v26=D%3DpageName&v27=D%3Dch&c28=cnn%20homepage%3Anvs&v28=D%3Dc28&v29=cnn.com&c30=cnn%20domestic&v30=D%3Dc30&c32=adbp%3Aindex&v32=D%3Dc32&c33=adbp%3Anone&v33=D%3Dc33&c35=cnn.17.1-0-0.20171212%3A0&v35=D%3Dc35&c37=smartphone&v37=D%3Dc37&c46=15160162567078112473106116&v46=D%3Dc46&c47=5a5c92820daa9a0a3c732e45390057c3&v47=D%3Dc47&c56=portrait&v56=D%3Dc56&c57=no%20mvpd%20set&v57=D%3Dc57&c59=no%20mvpd%20set&v59=D%3Dc59&c64=cnn%20news&v64=D%3Dc64&c65=nvs&c75=nvs&v75=D%3Dc75&h1=news%7Ccnn%7Ccnn%20domestic%7Ccnn.com%7Ccnn%20homepage%7Ccnn%20homepage%3Anvs&l1=D%3Dc65&l2=&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 text
-http://www.cnn.com/ http://secure-us.imrworldwide.com/cgi-bin/m?ci=us-204044h&cg=0&cc=1&si=http%3A//www.cnn.com/&rp=&ts=compact&rnd=1516016262614 other
-http://www.cnn.com/ http://w.usabilla.com/0649ef72a7be.js?lv=1 script
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/171016152625-file-obama-january-2010-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/150622193058-walmart-file-large-169.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180115160008-weber-testino-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/161121203757-13-dennis-rodman-large-tease.jpg image
-http://www.cnn.com/ http://cdn.cnn.com/cnnnext/dam/assets/180112135116-getty-cloi-lg-thinq-artificial-intelligence-large-tease.jpg image
-http://www.cnn.com/ http://bat.bing.com/action/0?ti=5526986&Ver=2&mid=097280f9-c440-d3d8-5df4-4e5d33cb1810&evt=pageLoad&sid=9ea6599d-1&lt=8139&pi=0&lg=en-US&sw=360&sh=512&sc=24&tl=CNN%20-%20Breaking%20News,%20Latest%20News%20and%20Videos&kw=cnn%20news,%20daily%20news,%20breaking%20news,%20news%20today,%20current%20events&p=http%3A%2F%2Fwww.cnn.com%2F&r=&msclkid=N&rn=224104 other
-http://www.cnn.com/ http://cdn.livefyre.com/libs/Livefyre/v1.1.4/builds/1510877390342/Livefyre.min.js script
-http://www.cnn.com/ http://cdn.krxd.net/partnerjs/xdi/proxy.3d2100fd7107262ecb55ce6847f01fa5.html html
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/video.c6882e31c5a2f929b0e7.bundle.js script
-http://www.cnn.com/ http://tr.outbrain.com/pixel?marketerId=006eb1f8dded486e0974a6b4a7b9805f5f&obApiVersion=1.0.4&name=PAGE_VIEW&dl=http%3A%2F%2Fwww.cnn.com%2F&bust=09406971601461427 image
-http://www.cnn.com/ http://metrics.cnn.com/b/ss/cnn-adbp-domestic/1/H.26.1/s15493195192617?AQB=1&pccr=true&vidn=2D2E4944851D2346-4000190E8000784F&&ndh=1&t=15%2F0%2F2018%203%3A37%3A42%201%20480&fid=3BD061AB4C1A7DBC-03CA17704898AFE3&ce=UTF-8&ns=cnn&pageName=cnn%3Ain%3A%2F&g=http%3A%2F%2Fwww.cnn.com%2F&cc=USD&ch=cnn%20homepage&server=cnn.com&events=event26&c5=nvs&v5=D%3Dc5&c8=new%3A1&v8=D%3Dc8&c9=nvs&v9=D%3Dc9&c13=section&v13=D%3Dc13&v15=1403&c17=anonymous&v17=D%3Dc17&c20=0&v20=D%3Dc20&v22=0&c26=www.cnn.com%2F&v26=D%3DpageName&v27=D%3Dch&c28=cnn%20homepage%3Anvs&v28=D%3Dc28&v29=cnn.com&c30=cnn%20domestic&v30=D%3Dc30&c32=adbp%3Aindex&v32=D%3Dc32&c33=adbp%3Anone&v33=D%3Dc33&c35=cnn.17.1-0-0.20171212%3A0&v35=D%3Dc35&c37=smartphone&v37=D%3Dc37&c46=15160162567078112473106116&v46=D%3Dc46&c47=5a5c92820daa9a0a3c732e45390057c3&v47=D%3Dc47&c56=portrait&v56=D%3Dc56&c57=no%20mvpd%20set&v57=D%3Dc57&c59=no%20mvpd%20set&v59=D%3Dc59&c64=cnn%20news&v64=D%3Dc64&c65=nvs&c75=nvs&v75=D%3Dc75&h1=news%7Ccnn%7Ccnn%20domestic%7Ccnn.com%7Ccnn%20homepage%7Ccnn%20homepage%3Anvs&l1=D%3Dc65&l2=&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 text
-http://www.cnn.com/ http://secure-us.imrworldwide.com/cgi-bin/m?ci=us-204044h&cg=0&cc=1&si=http%3A//www.cnn.com/&rp=&ts=compact&rnd=1516016262614&ja=1 image
-http://www.cnn.com/ http://weather.api.cnn.io/graphql?query=%7BwsiForecast(zip%3A%2294303%22%2Ccelcius%3A%22false%22)%7BcurrentConditions%7Btemperature%2Cdescription%2Cicon%7D%2Clocation%7Bcity%2CstateOrCountry%7D%7D%7D script
-http://www.cnn.com/ http://amplifypixel.outbrain.com/pixel?mid=006eb1f8dded486e0974a6b4a7b9805f5f&dl=http%3A%2F%2Fwww.cnn.com%2F&bust=09406971601461427 image
-http://www.cnn.com/ http://cdn.gigya.com/js/gigya.js?apiKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC script
-http://www.cnn.com/ http://beacon.krxd.net/cookie2json?callback=Krux.ns._default.kxjsonp_3pevents script
-http://www.cnn.com/ http://odb.outbrain.com/utils/get?url=http%3A%2F%2Fwww.cnn.com%2F&settings=true&recs=true&widgetJSId=MB_12&key=NANOWDGT01&idx=0&version=01002070&ref=&apv=false&sig=7gbLPOT0&format=html&rand=77564&winW=360&winH=512&adblck=false script
-http://www.cnn.com/ http://tpc.googlesyndication.com/safeframe/1-0-14/html/container.html html
-http://www.cnn.com/ https://static.yieldmo.com/blank.min.html?orig=http://www.cnn.com html
-http://www.cnn.com/ http://www.cnn.com/css/2.58.4/wp-video.css css
-http://www.cnn.com/ http://www.i.cdn.cnn.com/.a/bundles/fave.bd18dbe934950a0ca691.bundle.js script
-http://www.cnn.com/ http://aax.amazon-adsystem.com/e/dtb/bid?src=3159&u=http%3A%2F%2Fwww.cnn.com%2F&pid=3537167621516016260356&cb=5907439841516016267855&ws=360x512&v=6.1.0&t=2000&slots=%5B%7B%22sd%22%3A%22ad_rect_atf_01%22%2C%22s%22%3A%5B%22300x250%22%5D%7D%2C%7B%22sd%22%3A%22ad_rect_btf_02%22%2C%22s%22%3A%5B%22300x250%22%5D%7D%2C%7B%22sd%22%3A%22ad_rect_btf_03%22%2C%22s%22%3A%5B%22300x250%22%5D%7D%5D script
-http://www.cnn.com/ https://gum.criteo.com/sync?r=2&c=160&j=_ccb script
-http://www.cnn.com/ http://fastlane.rubiconproject.com/a/api/fastlane.json?account_id=11078&size_id=15&p_pos=atf&rp_floor=0.01&rf=http%3A%2F%2Fwww.cnn.com%2F&p_screen_res=360x512&tg_fl.eid=ad_rect_atf_01&tid=bc4e44ef-afab-4048-91b1-82fb037e4aca&tg_fl.uname=%2F8664377%2FCNN%2Fhomepage&tg_fl.pr_acctid=11078&kw=CNN%2Fhomepage%2Crp.fastlane&tk_flint=plain&tg_i.site=CNN&tg_i.section=homepage&tg_i.subsection=landing&tg_i.cap_topics=&tg_i.ssl=0&tg_i.pos=rect_atf_01&rand=0.2188066832002329 script
-http://www.cnn.com/ http://fastlane.rubiconproject.com/a/api/fastlane.json?account_id=11078&size_id=15&p_pos=btf&rp_floor=0.01&rf=http%3A%2F%2Fwww.cnn.com%2F&p_screen_res=360x512&tg_fl.eid=ad_rect_btf_02&tid=bc4e44ef-afab-4048-91b1-82fb037e4aca&tg_fl.uname=%2F8664377%2FCNN%2Fhomepage&tg_fl.pr_acctid=11078&kw=CNN%2Fhomepage%2Crp.fastlane&tk_flint=plain&tg_i.site=CNN&tg_i.section=homepage&tg_i.subsection=landing&tg_i.cap_topics=&tg_i.ssl=0&tg_i.pos=rect_btf_02&rand=0.9865101187961447 script
-http://www.cnn.com/ http://fastlane.rubiconproject.com/a/api/fastlane.json?account_id=11078&size_id=15&p_pos=btf&rp_floor=0.01&rf=http%3A%2F%2Fwww.cnn.com%2F&p_screen_res=360x512&tg_fl.eid=ad_rect_btf_03&tid=bc4e44ef-afab-4048-91b1-82fb037e4aca&tg_fl.uname=%2F8664377%2FCNN%2Fhomepage&tg_fl.pr_acctid=11078&kw=CNN%2Fhomepage%2Crp.fastlane&tk_flint=plain&tg_i.site=CNN&tg_i.section=homepage&tg_i.subsection=landing&tg_i.cap_topics=&tg_i.ssl=0&tg_i.pos=rect_btf_03&rand=0.7028473550393908 script
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e/img/3.0/weather/weatherIcon_33.png image
-http://www.cnn.com/ http://registry.api.cnn.io/bundles/fave/latest/css css
-http://www.cnn.com/ https://assets.bounceexchange.com/assets/bounce/local_storage_frame7.min.html html
-http://www.cnn.com/ http://b.scorecardresearch.com/r?c2=6035748&d.c=gif&d.o=cnn-adbp-domestic&d.x=97302858&d.t=page&d.u=http%3A%2F%2Fwww.cnn.com%2F other
-http://www.cnn.com/ http://widgets.outbrain.com/nanoWidget/01002070/module/swipeLayout.js script
-http://www.cnn.com/ http://odb.outbrain.com/utils/get?url=http%3A%2F%2Fwww.cnn.com&settings=true&recs=true&widgetJSId=TR_1&key=NANOWDGT01&idx=1&version=01002070&ref=&apv=false&sig=7gbLPOT0&format=html&rand=9847&lsd=b6fdcf6b-6e44-4726-90ef-05f0ad55debb&t=MV8wYmIyMTMwMmJlZTUwODcyZTcwMTZkMzAyNDM3MTBhNl8w&winW=360&winH=512&adblck=false script
-http://www.cnn.com/ http://cdn.krxd.net/controltag/ITb_4eqO.js script
-http://www.cnn.com/ http://registry.api.cnn.io/bundles/fave/latest/js script
-http://www.cnn.com/ http://b.scorecardresearch.com/r2?c2=6035748&d.c=gif&d.o=cnn-adbp-domestic&d.x=97302858&d.t=page&d.u=http%3A%2F%2Fwww.cnn.com%2F image
-http://www.cnn.com/ http://rva.outbrain.com/analytics-v1.js script
-http://www.cnn.com/ http://srv.adngin.com/185.js script
-http://www.cnn.com/ http://bidder.criteo.com/cdb?ptv=40&profileId=184&cb=23742890059 other
-http://www.cnn.com/ http://s.amazon-adsystem.com/iu3?cm3ppd=1&d=dtb-pub&csif=t&dl=ox_pm_an other
-http://www.cnn.com/ http://log.outbrain.com/loggerServices/widgetGlobalEvent?eT=6&tm=3616&pid=185&sid=185984&wId=569&wRV=01002070&rId=0bb21302bee50872e7016d30243710a6&idx=0&pvId=0bb21302bee50872e7016d30243710a6&org=0&pad=0&pVis=0&eIdx=&ab=0&wl=0 script
-http://www.cnn.com/ http://log.outbrain.com/loggerServices/widgetGlobalEvent?eT=0&tm=4257&pid=185&sid=185984&wId=117&wRV=01002070&rId=4b431087c0c517177b09ef770eb31d0b&idx=1&pvId=0bb21302bee50872e7016d30243710a6&org=0&pad=0&pVis=0&eIdx=&ab=0&wl=0 script
-http://www.cnn.com/ https://ads.yieldmo.com/v002/t_ads/ads?bust=1516016269469&dh=838417024&ae=0&_s=0&e=0&v=9.3.0&page_url=http%3A%2F%2Fwww.cnn.com%2F&p=764344014241209959&description=View%20the%20latest%20news%20and%20breaking%20news%20today%20for%20U.S.%2C%20world%2C%20weather%2C%20entertainment%2C%20politics%20and%20health%20at%20CNN.com.&title=CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos&dnt=false&ymid=9c9ad278e6fb77a525b6&scrd=3&h=512&w=360&lane=m2&pft=1516016269470&ct=1516016266126 script
-http://www.cnn.com/ https://cdns.us1.gigya.com/gs/webSdk/Api.aspx?apiKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC html
-http://www.cnn.com/ http://cnn.bounceexchange.com/bounce/init1.js?tojQ=function&cts=1516016270129&tzo=480&is_preview=false&website_id=340&resolution=360x512&referrer=&is_google_pla=0&calling_url=http%3A%2F%2Fwww.cnn.com%2F&visit_cookie=%7B%22lp%22%3A%22http%253A%252F%252Fwww.cnn.com%252F%22%2C%22r%22%3A%22%22%7D&cookie=%7B%22v%22%3A%7B%22completed_signup%22%3Afalse%7D%2C%22sid%22%3A1%7D&vars[desktop_ad_visible]=false&vars[mobile_ad_visible]=false&vars[article_page]=false&vars[flagship_domain]=true&vars[video_playing_and_large]=0&vars[video_playing_in_rail]=0&vars[video_playing_and_visible]=0&vars[money_article_page]=false&vars[section_name]=homepage&vars[tos]=true&vars[completed_signup]=false&vars[dfp_exclusion]=not_ready&vars[dfp_rblock]=fallback&vars[video_beacon]=false&vars[video_playing]=false&vars[breaking_news_present]=false&vdef[completed_signup]=false&cookie_too_large=false&bp=0 script
-http://www.cnn.com/ http://widgets.outbrain.com/nanoWidget/externals/obFrame/obFrame.htm html
-http://www.cnn.com/ http://registry.api.cnn.io/assets/fave/fonts/2.0.15/cnn-icons.woff font
-http://www.cnn.com/ https://securepubads.g.doubleclick.net/gampad/ads?gdfp_req=1&correlator=2733922461395066&output=json_html&callback=googletag.impl.pubads.callbackProxy1&impl=fifs&adsid=NT&json_a=1&eid=21060361%2C21061149&tfcd=0&sc=0&sfv=1-0-14&iu_parts=8663477%2CCNN%2Chomepage%2Clanding%2Cpushdown%2Csuper-ad-zone&enc_prev_ius=%2F0%2F1%2F2%2F3%2F4%2C%2F0%2F1%2F2%2C%2F0%2F1%2F2%2F3%2F5%2C%2F0%2F1%2F2%2C%2F0%2F1%2F2&prev_iu_szs=1x1%7C1x2%2C1x2%2C1x2%7C1x1%2C300x252%7C300x250%7C1x2%7C1x1%2C1x2%7C1x1&ists=1&prev_scp=pos%3Dbnr_atf_02%26elemId%3Dad_mod_35731bb1e%7Cpos%3Dbnr_atf_01%26elemId%3Dad_bnr_atf_01%7Cpos%3Dbnr_btf_01%26elemId%3Dad_bnr_btf_01%7Cpos%3Drect_btf_02%26elemId%3Dad_rect_btf_02%26amznbid%3D2%26amzniid%3D%26amznsz%3D0x0%26amznp%3D2%26rpfl_elemid%3Dad_rect_btf_02%26fln_to%3D0%7Cpos%3Doop_float_01%26elemId%3Dad_oop_float_01&eri=1&cust_params=prx_to%3D1%26transId%3D15160162567078112473106116%26guid%3D5a5c92820daa9a0a3c732e45390057c3%26protocol%3Dnon-ssl%26refdom%3Dother&cookie_enabled=1&abxe=1&lmt=1516016271&dt=1516016271894&frm=20&biw=360&bih=512&oid=3&adxs=0%2C0%2C0%2C0%2C0&adys=0%2C0%2C0%2C0%2C0&adks=1113343234%2C884486896%2C3275573252%2C2039529775%2C2831922974&gut=v2&ifi=1&u_tz=-480&u_his=3&u_h=512&u_w=360&u_ah=512&u_aw=360&u_cd=24&u_sd=3&flash=0&url=http%3A%2F%2Fwww.cnn.com%2F&dssz=56&icsg=140742061195264&mso=2147484161&std=0&vrg=172&vis=1&scr_x=0&scr_y=0&ga_vid=637012380.1516016272&ga_sid=1516016272&ga_hid=1547034594 script
-http://www.cnn.com/ https://securepubads.g.doubleclick.net/gpt/pubads_impl_rendering_172.js script
-http://www.cnn.com/ http://s.amazon-adsystem.com/iu3?cm3ppd=1&d=dtb-pub&csif=t&dl=ox_pm_an&dcc=t html
-http://www.cnn.com/ http://revee.outbrain.com/page/view other
-http://www.cnn.com/ http://beacon.krxd.net/optout_check?callback=Krux.ns._default.kxjsonp_optOutCheck script
-http://www.cnn.com/ http://cdn.krxd.net/userdata/get?pub=e9eaedd3-c1da-4334-82f0-d7e3ff883c87&technographics=1&callback=Krux.ns._default.kxjsonp_userdata script
-http://www.cnn.com/ https://static.yieldmo.com/sdk/template/js/10.handlebars.js script
-http://www.cnn.com/ http://b.scorecardresearch.com/beacon.js script
-http://www.cnn.com/ http://pagead2.googlesyndication.com/pagead/osd.js script
-http://www.cnn.com/ http://static.yieldmo.com/icons/af-beta/b2b54826-bc97-40aa-a9a3-0e546888dd58.gif image
-http://www.cnn.com/ http://revee.outbrain.com/page/view other
-http://www.cnn.com/ http://static.yieldmo.com/img/crtv/2017/10/bui/76d149eeec0da752a78f606aae15f683.gif image
-http://www.cnn.com/ http://t.cwkuki.com/cs/ob1j8s other
-http://www.cnn.com/ https://static.yieldmo.com/images/ad-choices.svg image
-http://www.cnn.com/ http://s.amazon-adsystem.com/v3/pr?exlist=ox_pm_an&fv=1.0&a=cm&cm3ppd=1 html
-http://www.cnn.com/ https://ads.yieldmo.com/v000/t_tkr/errlog?x=0&y=0&pvt=1516016270720&stime=1516016273791&etime=1516016273795&p=764344014241209959&pv=1863598647048238408&page_url=http%3A%2F%2Fwww.cnn.com%2F&w=360&h=512&fmtid=10&crid=1839829567281301297%2C1804247575409035869&e=0&lane=m2&wh=I_FOR_VER&location=http%3A%2F%2Fwww.cnn.com%2F&desc=Format%20Version%3A%205.3.0%2C%20Kind%3A%2010&v=9.3.0 script
-http://www.cnn.com/ https://ads.yieldmo.com/v000/t_tkr/ev?type=r&plid=764344014241209959&pvid=1863598647048238408&x=0&y=0&pvt=1516016270720&pft=1516016269470&stime=1516016273929&etime=1516016273930 other
-http://www.cnn.com/ http://servedby.flashtalking.com/imp/8/58116;1705291;201;redirect;YieldMo;SLNGDUSACRDCUTMWDISXXXDIRYIELDMOxxxTUNEINxXXXXXX310x310/?cachebuster=880637357911411505&url=https://dishdigital.sp1.convertro.com/view/vt/v1/dishdigital/15/cvo.gif?cvosrc=Display.Yieldmo.CRDCUT&cvo_cid=58116&cvo_pid=SLNGD_USA_CRDCUT_MW_DIS_XXX_DIR_YIELDMOxxx_TUNEINx_XXXXXX_310x310 other
-http://www.cnn.com/ https://ad.doubleclick.net/ddm/trackimp/N6054.2005704YIELDMO/B11193130.207681961;dc_trk_aid=405867218;dc_trk_cid=81105239;kw=764344014241209959-1804247575409035869;ord=916831759909389917;dc_lat=;dc_rdid=;tag_for_child_directed_treatment= image
-http://www.cnn.com/ http://connect.facebook.net/en_US/fbevents.js script
-http://www.cnn.com/ http://googleads.g.doubleclick.net/pagead/viewthroughconversion/986255830/?value=0&guid=ON&script=0 image
-http://www.cnn.com/ http://googleads.g.doubleclick.net/pagead/viewthroughconversion/925133270/?value=1.00&currency_code=USD&label=IEQNCNXH9GcQ1tORuQM&guid=ON&script=0 image
-http://www.cnn.com/ http://bea4.cnn.com/ad/u?mode=echo&cr=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dfreewheel%26partner_uid%3D%23%7Buser.id%7D other
-http://www.cnn.com/ https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=3da3903768f3e3c5dd7a image
-http://www.cnn.com/ https://ad.atdmt.com/i/img;adv=11022204596223;ec=11022204596285;c.a=11193130;p.a=207681961;a.a=405867218;s.a=4049107;idfa=;idfa_lat=;aaid=;aaid_lat=;cache= image
-http://www.cnn.com/ https://sb.scorecardresearch.com/p?c1=8&c2=18969557&ns_ap_it=b&rn=5bb4a3178065c2107ad8 image
-http://www.cnn.com/ https://z.moatads.com/yieldmodisplay554285300888/moatad.js script
-http://www.cnn.com/ https://s.yieldmo.com/partner.min.html html
-http://www.cnn.com/ http://revee.outbrain.com/page/update other
-http://www.cnn.com/ https://securepubads.g.doubleclick.net/pagead/adview?ai=Ck7RGkJJcWobMC4LbkgO60Z7ABMO9sIdQp4PB9cMFwI23ARABIJrd5B9gyZ7rhoCAoBmgAbvjvJ8DyAEC4AIAqAMByAOZBKoEqwFP0Ft9ljWCXgFdDf1AIExuB1QYPiUMdtjd38yu_8mHHkjk2xfMYTZt-ibVE4AO4L5fyAdKZeW59CrRa_N5U5E5KEWtTkbaeHrVJtMyBr8cgFRPM4W5dGxlo7_vdsW7ndWyLxG0eveSZGjAcIjxXGH8_L8hAjrlrZJHB_mynCm6v55-GBZK_pNNMS8m5pa3gY2dhrBhT4mDRBUXcjUzEdVT0TOeroWaOxvj7GPABIyNtfy1AeAEAYgFnf-ilQOSBQQIBBgBkgUECAUYBKAGAtgGAoAHrZzDYKgHpr4b2AcB8gcEENytLKAI6qGnBLAIAtIIBwiAYRABGAGACgPYEwyCFA0aC3d3dy5jbm4uY29t&sigh=zAY73elZGTE html
-http://www.cnn.com/ http://track.adngin.com/track?env=prod&accountId=1359&siteId=1513&nav=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&location=http%3A%2F%2Fwww.cnn.com%2F&bt=20171228112646017&bws=360x512&ds=360x512&event=pageserved&ts=1516016275157&tzo=480&hod=3&dow=1&device=mobile&os=Android&browser=Chrome&userId=LWFFT0PV&sessionId=PF2T6JFY&viewId=XEOV3EGK other
-http://www.cnn.com/ http://token.rubiconproject.com/token?pid=27384&puid=Lu5wrPPJ other
-http://www.cnn.com/ https://tpc.googlesyndication.com/simgad/14456697088005709719 image
-http://www.cnn.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_qs_click_protection.js script
-http://www.cnn.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/abg.js script
-http://www.cnn.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/activeview/osd_listener_heavy.js script
-http://www.cnn.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_js_controller.js script
-http://www.cnn.com/ https://tpc.googlesyndication.com/pagead/js/r20180108/r20110914/client/ext/m_window_focus_non_hydra.js script
-http://www.cnn.com/ https://ads.yieldmo.com/v000/t_tkr/ev?type=dl&dltime=2389&frmtversion=5.3.0&plid=764344014241209959&pvid=1863598647048238408&x=0&y=0&pvt=1516016270720&pft=1516016269470&stime=1516016276215&etime=1516016276257 other
-http://www.cnn.com/ http://revee.outbrain.com/page/update other
-http://www.cnn.com/ https://sync.outbrain.com/codewise/pixel?user_id=86823aa0-f9e8-11e7-8646-0242ac110003 other
-http://www.cnn.com/ http://www.google.com/ads/user-lists/925133270/?value=1.00&currency_code=USD&label=IEQNCNXH9GcQ1tORuQM&guid=ON&script=0&cdct=2&is_vtc=1&random=2998697083 image
-http://www.cnn.com/ http://www.google.com/ads/user-lists/986255830/?value=0&guid=ON&script=0&cdct=2&is_vtc=1&random=2151969468 image
-http://www.cnn.com/ https://social-login.cnn.com/accounts.webSdkBootstrap?apiKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&pageURL=http%3A%2F%2Fwww.cnn.com%2F&format=jsonp&callback=gigya.callback&context=R485904126 script
-http://www.cnn.com/ https://usermatch.krxd.net/um/v2?partner=google other
-http://www.cnn.com/ http://match.adsrvr.org/track/cmf/generic?ttd_pid=krux&ttd_tpi=1 html
-http://www.cnn.com/ https://dishdigital.sp1.convertro.com/view/vt/v1/dishdigital/15/cvo.gif?cvosrc=Display.Yieldmo.CRDCUT&cvo_cid=58116&cvo_pid=SLNGD_USA_CRDCUT_MW_DIS_XXX_DIR_YIELDMOxxx_TUNEINx_XXXXXX_310x310 image
-http://www.cnn.com/ http://sync-tm.everesttech.net/upi/pid/NC4WTmcy?redir=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner_id%3Dcb276571-e0d9-4438-9fd4-80a1ff034b01%26puid%3D%24%7BTM_USER_ID%7D other
-http://www.cnn.com/ http://sync.search.spotxchange.com/audience_sync/9?redir=http:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dspotxchange%26partner_uid%3D%3Cspotx_audience_id%3E other
-http://www.cnn.com/ http://ib.adnxs.com/getuid?http://beacon.krxd.net/usermatch.gif?adnxs_uid=$UID image
-http://www.cnn.com/ http://p.rfihub.com/cm?in=1&pub=6919 other
-http://www.cnn.com/ http://ib.adnxs.com/getuid?http://s.amazon-adsystem.com/ecm3?id=$UID&ex=appnexus.com image
-http://www.cnn.com/ https://srv.adngin.com/pixel.png image
-http://www.cnn.com/ https://idsync.rlcdn.com/379708.gif?partner_uid=Lu5wrPPJ image
-http://www.cnn.com/ http://match.adsrvr.org/track/cmb/generic?ttd_pid=krux&ttd_tpi=1 html
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner=spotxchange&partner_uid=b4b00ad8-f9e8-11e7-91f3-199f9d040001 image
-http://www.cnn.com/ http://us-u.openx.net/w/1.0/cm?id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&ph=2d1251ae-7f3a-47cf-bd2a-2f288854a0ba&plm=5&r=http%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D other
-http://www.cnn.com/ http://sync-tm.everesttech.net/ct/upi/pid/NC4WTmcy?redir=https%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner_id%3Dcb276571-e0d9-4438-9fd4-80a1ff034b01%26puid%3D%24%7BTM_USER_ID%7D&_test=WlySlQAAAFAnkEsY other
-http://www.cnn.com/ http://ads.pubmatic.com/AdServer/js/user_sync.html?p=156011&s=165626&predirect=http%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fid%3DPM_UID%26ex%3Dpubmatic.com&userIdMacro=PM_UID html
-http://www.cnn.com/ http://tags.bluekai.com/site/26357?id=Lu5wrPPJ&redir=http://beacon.krxd.net/usermatch.gif?_kuid%3DLu5wrPPJ%26partner%3Dbluekai%26bk_uuid%3D%24_BK_UUID other
-http://www.cnn.com/ https://analytics.twitter.com/i/adsct?p_user_id=Lu5wrPPJ&p_id=10623 image
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner_id=rfuel&partner_user_id=1172413650296186928 image
-http://www.cnn.com/ http://dt.scanscout.com/ssframework/uid?UIKX=Lu5wrPPJ&url=http://beacon.krxd.net/usermatch.gif%3Fpartner_id%3Dtremor%26partner_uid%3D%5BUSER_ID%5D image
-http://www.cnn.com/ http://bea4.v.fwmrm.net/ad/u?mode=echo&cr=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dfreewheel%26partner_uid%3D%23%7Buser.id%7D other
-http://www.cnn.com/ https://cm.g.doubleclick.net/pixel?google_cm&google_nid=krux_digital&google_hm=THU1d3JQUEo%3D html
-http://www.cnn.com/ http://ads.undertone.com/u?dp=30&url=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dundertone%26partner_uid%3D text
-http://www.cnn.com/ https://idsync.rlcdn.com/379708.gif?partner_uid=Lu5wrPPJ&redirect=1 image
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner=ttd&partner_uid=6afba69b-e745-41b2-ac3c-e5df77243d55 image
-http://www.cnn.com/ http://us-u.openx.net/w/1.0/cm?cc=1&id=e818ca1e-0c23-caa8-0dd3-096b0ada08b7&ph=2d1251ae-7f3a-47cf-bd2a-2f288854a0ba&plm=5&r=http%3A%2F%2Fs.amazon-adsystem.com%2Fecm3%3Fex%3Dopenx.com%26id%3D html
-http://www.cnn.com/ http://tags.bluekai.com/site/26358?dt=0&r=1098175050&sig=2952250253&bkca=KJpnEncNvED+nyG/Xa/guAlJnnnBvYAoLBnUE6oBE1fw6XLr3AMH06L+6uX+EilvEuhJp+Onp60pMXXrpDhHBUSObPDN1i+/nYgJu06YYiqkkvjZJtRYhjv0T6LCYkVBEmv5FmBexpN59eIyJ81= other
-http://www.cnn.com/ http://usersync.videoamp.com/usersync?partner_id=6902992&redirect=http:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dvidamp%26partner_uid%3D%7Bvamp_user_id%7D other
-http://www.cnn.com/ http://loadm.exelator.com/load?_kdpid=e4942ff0-4070-4896-a7ef-e6a5a30ce9f9&buid=Lu5wrPPJ&p=204&g=270&j=0 image
-http://www.cnn.com/ https://cm.g.doubleclick.net/pixel?google_nid=yieldmo_dbm&google_cm&pn_id=c html
-http://www.cnn.com/ https://cm.g.doubleclick.net/pixel?google_nid=yieldmo&google_hm=OWM5YWQyNzhlNmZiNzdhNTI1YjY= html
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner_id=tremor&partner_uid=9c4983e6cea4594fabfae7165dca2646 image
-http://www.cnn.com/ https://googleads.g.doubleclick.net/pagead/drt/s?v=r20120211 html
-http://www.cnn.com/ https://usermatch.krxd.net/um/v2?partner=vdna other
-http://www.cnn.com/ http://ads.undertone.com/u?dp=30&url=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dundertone%26partner_uid%3D&ct=1 text
-http://www.cnn.com/ http://dpm.demdex.net/ibs:dpid=66757&&dpuuid=Lu5wrPPJ&redir=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dadobe%26partner_uid%3D$%7BDD_UUID%7D other
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?_kuid=Lu5wrPPJ&partner=bluekai&bk_uuid=LfPYvMRR99OM2ahS image
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner=vidamp&partner_uid=89c383ec-f9e8-11e7-8bc9-0242cad9c6ae image
-http://www.cnn.com/ http://loadm.exelator.com/load?_kdpid=e4942ff0-4070-4896-a7ef-e6a5a30ce9f9&buid=Lu5wrPPJ&p=204&g=270&j=0&xl8blockcheck=1 image
-http://www.cnn.com/ https://beacon.krxd.net/usermatch.gif?partner_id=cb276571-e0d9-4438-9fd4-80a1ff034b01&puid=WlySlQAAAFAnkEsY&_test=WlySlQAAAFAnkEsY image
-http://www.cnn.com/ http://ps.eyeota.net/match?bid=i0r4o4v&uid=Lu5wrPPJ other
-http://www.cnn.com/ http://tapestry.tapad.com/tapestry/1?ta_partner_id=1969&ta_redirect=http:%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dtapad%26partner_uid%3D%24%7BIDS%3Akey%7D other
-http://www.cnn.com/ https://ads.yieldmo.com/v000/sync?pn_id=c&google_gid=CAESENme8wto0Md0RhfqOhtUIZw&google_cver=1 image
-http://www.cnn.com/ http://ads.pubmatic.com/AdServer/js/showad.js script
-http://www.cnn.com/ http://dpm.demdex.net/demconf.jpg?et:ibs%7cdata:dpid=66757&&dpuuid=Lu5wrPPJ&redir=http%3A%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dadobe%26partner_uid%3D$%7BDD_UUID%7D image
-http://www.cnn.com/ https://beacon.krxd.net/usermatch.gif?google_gid=&google_gid=CAESEIqbs-0SeQ5WdrJbqPd4Ytg&google_cver=1 image
-http://www.cnn.com/ https://ads.yieldmo.com/exsync image
-http://www.cnn.com/ https://pagead2.googlesyndication.com/pagead/s/cookie_push.html html
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner=undertone&partner_uid=2sqx2sue9g29kak2tfnx6qawo image
-http://www.cnn.com/ http://ps.eyeota.net/match/bounce/?bid=i0r4o4v&uid=Lu5wrPPJ image
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner=tapad&partner_uid=8a3a60a1-f9e8-11e7-ade4-0242ac110003 image
-http://www.cnn.com/ http://beacon.krxd.net/usermatch.gif?partner=adobe&partner_uid=55119354727851796431761212154101747641 image
-http://www.cnn.com/ http://odb.outbrain.com/utils/get?url=http%3A%2F%2Fwww.cnn.com%2F&settings=true&recs=true&widgetJSId=NGN_4&key=NANOWDGT01&idx=101&version=01002070&ref=&apv=false&sig=7gbLPOT0&format=vjapi&rand=78608&lsd=b6fdcf6b-6e44-4726-90ef-05f0ad55debb&t=MV8wYmIyMTMwMmJlZTUwODcyZTcwMTZkMzAyNDM3MTBhNl8w&winW=360&winH=512&adblck=false&extid=NGN_VAR_569_2668 script
-http://www.cnn.com/ http://track.adngin.com/track?env=prod&accountId=1359&siteId=1513&nav=Mozilla%2F5.0%20(Linux%3B%20Android%206.0.1%3B%20Moto%20G%20(4)%20Build%2FMPJ24.139-64)%20AppleWebKit%2F537.36%20(KHTML%2C%20like%20Gecko)%20Chrome%2F58.0.3029.81%20Mobile%20Safari%2F537.36%20PTST%2F180111.190127&location=http%3A%2F%2Fwww.cnn.com%2F&bt=20171228112646017&bws=360x512&ds=360x512&g=183&u=2668&event=adrequested&ts=1516016276054&tzo=480&hod=3&dow=1&device=mobile&os=Android&browser=Chrome&userId=LWFFT0PV&sessionId=PF2T6JFY&viewId=XEOV3EGK other
-http://www.cnn.com/ http://b.scorecardresearch.com/b?c1=7&c2=14320224&c3=185&ns__t=1516016276071&ns_c=windows-1252&ns_if=1&cv=3.1m&c8=&c7=http%3A%2F%2Fwidgets.outbrain.com%2FnanoWidget%2Fexternals%2FobFrame%2FobFrame.htm%23pid%3D185%26dmpenabled%3Dtrue%26filterDMP%3D%26csenabled%3Dtrue%26d%3DrEzJ0Zub7aCKvS5r3v4qUt7MvGLMubbO-oLie9xY-Owce8EFp8iJfEKoQrJjdizt&c9=http%3A%2F%2Fwww.cnn.com%2F other
-http://www.cnn.com/ http://ml314.com/tag.aspx?1502018 script
-http://www.cnn.com/ http://r.nexac.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5wrPPJ%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E html
-http://www.cnn.com/ http://kr.ixiaa.com/C726AB29-0470-440B-B8D2-D552CED3A3DC/a.gif image
-http://www.cnn.com/ https://www.google.com/pagead/drt/ui html
-http://www.cnn.com/ http://connect.facebook.net/signals/config/731697573629176?v=2.8.6&r=stable script
-http://www.cnn.com/ http://registry.api.cnn.io/assets/fave/theoplayer/1.6.110/theoplayer.js script
-http://www.cnn.com/ http://load77.exelator.com/pixel.gif image
-http://www.cnn.com/ http://cdn.gigya.com/js/gigya.services.plugins.base.min.js?services=gigya.services.socialize.plugins.reactions&lang=en script
-http://www.cnn.com/ http://image6.pubmatic.com/AdServer/PugMaster?rnd=7559249&p=156011&s=165626&a=0&ptask=ALL&np=0&fp=0&mpc=0&spug=1&coppa=0&kdntuid=1 html
-http://www.cnn.com/ http://aa.agkn.com/adscores/g.js?sid=9212244187&_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e script
-http://www.cnn.com/ http://cdn.livefyre.com/libs/fyre.conv/v3.0.0/livefyre.min.js script
-http://www.cnn.com/ https://cm.g.doubleclick.net/pixel/attr?d=AHNF13KviMDeh8mt0W8ue_1PqvgSasSfA4UY html
-http://www.cnn.com/ http://connect.facebook.net/en_US/sdk.js script
-http://www.cnn.com/ http://beacon.krxd.net/data.gif?_kdpid=5eddb9ca-88c9-4c34-a9ae-2680df2a7de7&aa=8&ab=2&ac=21&ay=1&az=1&ia=1&ib=0&ic=1&id=1&ie=1&if=0&ig=0&ih=0&ij=1&ik=0&ba=0&bb=1&bc=1&bd=0&be=1&bf=0&bg=0&bh=1&bi=1&bj=1&sba=0&ea1=0&ea2=0&ea3=0&ea4=0&ea5=1&ea6=0&ea7=0&ea8=0&ea9=0&ea10=0&ea11=0&eb1=0&eb2=0&eb3=0&eb4=0&eb5=1&eb6=0&eb7=0&eb8=0&eb9=0&ed1=0&ed2=0&ed3=1&ed4=0&ec=33&ee=9&fa=1&fb=1&fc=1&fd=1&fe=7&da=1&db=0&dc=1&dg=1&dh=0&di=0&dj=0&dk=0&ga=1&gb=0&gc=0&gd=1&ge=0&gf=1&gg=1&gh=0&gi=0&gj=0&ha=0&hb=0&hc=0&hd=0&he=0&hf=0&la=0&lb=0&oa=0&ob=0&oc=0&od=0&ra=0&rb=0&rc=0&rd=0&re=0&rf=0&rg=0&sbb=0&sbc=0&sbi=0&sbj=0&sbk=0&sbl=0&sbm=0&sbn=0&sbo=0&sbp=0&sbq=0&sbr=0&sbd=0&sbe=0&sbf=0&sbg=0&sbh=0&ta=1&tb=0&tc=0&td=0&te=0&tf=0&tg=0&th=0&ti=0&tj=0&tk=0&tl=0&tm=0&tn=0&to=0&tp=1&tq=1&va=0&vb=1&vc=1&vd=0&ve=0&vk=1&vl=0&vm=0&vn=0&vo=0&vp=0&vq=0&wa=0&wb=0&wc=0&wd=0&we=0&wf=0&wg=0&wh=0&wi=0&wj=1&wk=0&wl=1&wm=0&wn=1&wo=1&wp=1&wq=0&wr=0&ws=0&wt=0&sa=0&sb=0&sc=0&sd=0&se=0&sf=0&sg=0&sh=0&si=0&sj=1&sk=0&sl=1&sm=0&sn=1&so=1&hg=0&hh=0&hi=0&hj=0&hk=0&hl=0&hm=0&hn=0&ho=1&hp=0&hq=0&hr=0&hs=0&ht=0&hu=0&hv=1&vf=0&vg=1&vh=1&vi=0&vj=1&vr=0&vs=1&vt=0&vu=0&vv=0&vw=0&io=0 image
-http://www.cnn.com/ https://googleads.g.doubleclick.net/pagead/drt/si html
-http://www.cnn.com/ https://idsync.rlcdn.com/397286.gif?partner_uid=9c9ad278e6fb77a525b6 image
-http://www.cnn.com/ http://match.adsrvr.org/track/cmf/generic?ttd_pid=pubmatic&ttd_tpi=1 html
-http://www.cnn.com/ http://s.amazon-adsystem.com/ecm3?id=3B3ADE1D-8F92-47BE-8C5B-7F45C10678C8&ex=pubmatic.com image
-http://www.cnn.com/ http://aa.agkn.com/adscores/g.pixel?sid=9201373478&_s=&_id=3B3ADE1D-8F92-47BE-8C5B-7F45C10678C8 other
-http://www.cnn.com/ http://dpm.demdex.net/ibs:dpid=19566&dpuuid=3B3ADE1D-8F92-47BE-8C5B-7F45C10678C8 image
-http://www.cnn.com/ https://e.visualdna.com/conversion?api_key=krux&id=sync&_kdpid=8f95f20d-4acf-43fc-9832-3f5174a166cc&partner_user_id=Lu5wrPPJ&bust=1516016280256 other
-http://www.cnn.com/ http://cm.g.doubleclick.net/pixel?google_nid=pubmatic&google_cm&google_sc html
-http://www.cnn.com/ http://r.dlx.addthis.com/e/getdata.xgi?dt=br&pkey=gpwn29rvapq62&ru=http://beacon.krxd.net/data.gif?_kuid%3DLu5wrPPJ%26_kdpid%3D2dd640a6-6ebd-4d4f-af30-af8baa441a0d%26dlxid%3D%3Cna_id%3E%26dlxdata%3D%3Cna_da%3E other
-http://www.cnn.com/ http://geo-um.btrll.com/v1/map_pixel/partner/1895.png image
-http://www.cnn.com/ http://pixel.tapad.com/idsync/ex/receive?partner_id=2682&partner_device_id=3B3ADE1D-8F92-47BE-8C5B-7F45C10678C8 other
-http://www.cnn.com/ http://pubmatic-match.dotomi.com/pubmatic/match?rurl=http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTQ2MSZ0bD0xNTc2ODAw&piggybackCookie= other
-http://www.cnn.com/ http://id.rlcdn.com/463496.gif?queue=dmp&credir=http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAw&piggybackCookie= image
-http://www.cnn.com/ https://social-login.cnn.com/gscounters.sendReport?reports=%5B%7B%22name%22%3A%22loadc%22%2C%22time%22%3A%221516016269672%22%2C%22reportData%22%3A%7B%22sref%22%3A%22%22%7D%7D%5D&APIKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&sdk=js_7.4.40&pageURL=http%3A%2F%2Fwww.cnn.com%2F&format=jsonp&callback=gigya.callback&context=R4101112535 script
-http://www.cnn.com/ http://dis.criteo.com/dis/usersync.aspx?r=3&p=4&cp=pubmaticUS&cu=1&url=http%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTE5MjgmdGw9NDMyMDA%3D%26piggybackCookie%3Duid%3A%40%40CRITEO_USERID%40%40 other
-http://www.cnn.com/ http://d.agkn.com/pixel/5500/?age=&gender=&st=&sk=&pd=&cbr=&mip=&dm=&py=&l0=http://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key= other
-http://www.cnn.com/ http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzNDAmdGw9MTI5NjAw&u=3B3ADE1D-8F92-47BE-8C5B-7F45C10678C8&piggybackCookie=EE0B43D871D7C1E91FC7BF24F7B4FA00F2DC59A8 image
-http://www.cnn.com/ http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTI4NDkmdGw9MTI5NjAw&piggybackCookie=6afba69b-e745-41b2-ac3c-e5df77243d55 image
-http://www.cnn.com/ https://dpm.demdex.net/ibs:dpid=81304&dpuuid=9c9ad278e6fb77a525b6 image
-http://www.cnn.com/ https://ib.adnxs.com/getuid?https://ads.yieldmo.com/v000/sync?userid=$UID&pn_id=an image
-http://www.cnn.com/ http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTIxNzcmdGw9MTI5NjAw&piggybackCookie=CAESEEvqCIz4w1EWMBYG2hCYX-M&google_cver=1 image
-http://www.cnn.com/ http://beacon.krxd.net/data.gif?_kuid=Lu5wrPPJ&_kdpid=2dd640a6-6ebd-4d4f-af30-af8baa441a0d&dlxid=&dlxdata= image
-http://www.cnn.com/ https://e.visualdna.com/conversion?partner_user_id=Lu5wrPPJ&bust=1516016280256&id=sync&_kdpid=8f95f20d-4acf-43fc-9832-3f5174a166cc&api_key=krux&do_not_cookie=1 image
-http://www.cnn.com/ http://geo-um.btrll.com/v1/map_pixel/partner/1895.png?set_aps=1&BR_APS=3WlySmx3W-JIBGOL3Sg& image
-http://www.cnn.com/ https://stags.bluekai.com/site/26980?limit=0&id=9c9ad278e6fb77a525b6 image
-http://www.cnn.com/ http://pixel.tapad.com/idsync/ex/receive/check?partner_id=2682&partner_device_id=3B3ADE1D-8F92-47BE-8C5B-7F45C10678C8 other
-http://www.cnn.com/ http://beacon.krxd.net/data.gif?_kdpid=2111c0af-fc3a-446f-ab07-63aa74fbde8e&_kua_seg=000&_kua_zip=&_kua_age=&_kua_gender=&_k_adadvisor_key= image
-http://www.cnn.com/ http://pubmatic-match.dotomi.com/pubmatic/match?dtm_test=47efc74cacdd0518&piggybackCookie=&rurl=http%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTQ2MSZ0bD0xNTc2ODAw other
-http://www.cnn.com/ https://bttrack.com/pixel/cookiesync?source=6f15a88d-e42c-4017-8276-dff2b21d7926&secure=1 html
-http://www.cnn.com/ http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTMzMzkmdGw9MTI5NjAwXc1193jBGQM320JKQnPE5VHVJ_R1NEL6kIOf9wKzlZxZfWr5g image
-http://www.cnn.com/ http://dis.us.criteo.com/dis/usersync.aspx?r=3&p=4&cp=pubmaticUS&cu=1&url=http%3A%2F%2Fimage2.pubmatic.com%2FAdServer%2FPug%3Fvcode%3Dbz0yJnR5cGU9MSZjb2RlPTE5MjgmdGw9NDMyMDA%3D%26piggybackCookie%3Duid%3A%40%40CRITEO_USERID%40%40 image
-http://www.cnn.com/ http://tpc.googlesyndication.com/pagead/images/transparent.png image
-http://www.cnn.com/ https://sync.mathtag.com/sync/img?mt_exid=76&redir=https%3A%2F%2Fads.yieldmo.com%2Fv000%2Fsync%3Fmm_user_id%3D%5BMM_UUID%5D image
-http://www.cnn.com/ http://s.amazon-adsystem.com/ecm3?ex=openx.com&id=9a3e10fc-d76a-8c01-b709-c095dd2fc75b image
-http://www.cnn.com/ https://match.deepintent.com/usersync?p_id=109 image
-http://www.cnn.com/ https://aa.agkn.com/adscores/g.pixel?sid=9212291508&puid=9c9ad278e6fb77a525b6 other
-http://www.cnn.com/ http://image4.pubmatic.com/AdServer/SPug?partnerID=156020&xid=3WlySmx3W-JIBGOL3Sg& text
-http://www.cnn.com/ http://match.adsrvr.org/track/cmf/generic?ttd_pid=tapad&ttd_tpi=1&ttd_puid=%252C html
-http://www.cnn.com/ https://ads.yieldmo.com/v000/sync?userid=ded0020b-2cb4-45de-ba9c-aec5b3ff1850&pn_id=b image
-http://www.cnn.com/ http://image2.pubmatic.com/AdServer/Pug?vcode=bz0yJnR5cGU9MSZjb2RlPTQ2MSZ0bD0xNTc2ODAwAAABzjkeg7_QDQZ8Q9l5AAAAAAA image
-http://www.cnn.com/ http://match.adsrvr.org/track/cmf/openx?oxid=c2e86c81-cbc0-37fb-7707-4202b51c0cbb html
-http://www.cnn.com/ http://cmap.ox.ace.advertising.com/cfcm.ashx?providerId=1009 image
-http://www.cnn.com/ https://match.adsrvr.org/track/cmf/generic?ttd_pid=yieldmo&ttd_tpi=1&ttd_puid=9c9ad278e6fb77a525b6 html
-http://www.cnn.com/ http://sync.mathtag.com/sync/img?mt_exid=5&redir=http%3A%2F%2Fus-u.openx.net%2Fw%2F1.0%2Fsd%3Fid%3D536872786%26val%3D%5BMM_UUID%5D image
-http://www.cnn.com/ https://b1sync.zemanta.com/usersync/yieldmo/?id=9c9ad278e6fb77a525b6 image
-http://www.cnn.com/ https://x.bidswitch.net/sync?ssp=yieldmo other
-http://www.cnn.com/ http://cm.g.doubleclick.net/pixel?google_nid=openx&google_cm&google_sc html
-http://www.cnn.com/ https://sync.mathtag.com/sync/img?mt_exid=76&redir=https%3A%2F%2Fads.yieldmo.com%2Fv000%2Fsync%3Fmm_user_id%3D%5BMM_UUID%5D&mm_bnc&mm_bct image
-http://www.cnn.com/ http://pixel.tapad.com/idsync/ex/receive?partner_id=1830&partner_device_id=6afba69b-e745-41b2-ac3c-e5df77243d55&ttd_puid=%2C image
-http://www.cnn.com/ http://us-u.openx.net/w/1.0/sd?id=537072971&val=6afba69b-e745-41b2-ac3c-e5df77243d55&ttd_puid=c2e86c81-cbc0-37fb-7707-4202b51c0cbb image
-http://www.cnn.com/ https://ads.yieldmo.com/v000/sync?tdid=6afba69b-e745-41b2-ac3c-e5df77243d55 image
-http://www.cnn.com/ https://x.bidswitch.net/ul_cb/sync?ssp=yieldmo other
-http://www.cnn.com/ https://ads.yieldmo.com/v000/sync?mm_user_id=b9615a5c-8c2e-4c00-b488-8e99109847bf image
-http://www.cnn.com/ http://us-u.openx.net/w/1.0/sd?id=536872786&val=b9615a5c-8c2e-4c00-b488-8e99109847bf image
-http://www.cnn.com/ https://ad.turn.com/r/cs?pid=9 other
-http://www.cnn.com/ http://us-u.openx.net/w/1.0/sd?id=537072991&val=CAESEExEMh8yvqbcP0r0PcL62vc&google_cver=1 image
-http://www.cnn.com/ http://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.cnn.com/ http://cdn.gigya.com/gs/i/shareBar/button/mobile/buttonCenterImgUp.png image
-http://www.cnn.com/ https://d.agkn.com/pixel/8697/?che=1516016284&sk=164120802571000249030&puid=9c9ad278e6fb77a525b6 image
-http://www.cnn.com/ https://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.cnn.com/ https://google2waycm.netmng.com/cm/?google_gid=CAESEDhASdAjRWtFBUQyVzxBn7k&google_cver=1&google_push=AHNF13I1k5UPNUARCEHWvn2nYvUz0LHx0z1yCd2rTPpiSCWlaQ other
-http://www.cnn.com/ https://ml314.com/utsync.ashx?pub=748&adv=&et=0&eid=&ct=js&pi=&fp=&clid=&ps=&cl=&mlt=&data=&&cp=http%3A%2F%2Fcdn.krxd.net%2Fpartnerjs%2Fxdi%2Fproxy.3d2100fd7107262ecb55ce6847f01fa5.html%23!kxcid%3DITb_4eqO%26kxt%3Dhttp%253A%252F%252Fwww.cnn.com%26kxcl%3Dcdn%26kxp%3D&pv=1516016282350_zz4w2hczr&bl=en-us&cb=7308087&return=%2F%2Fbeacon.krxd.net%2Fusermatch.gif%3Fpartner%3Dmadisonlogic%26partner_uid%3D%5BPersonID%5D&ht=&d=&dc=&si=1516016282350_zz4w2hczr&cid=&s=360x512&rp=http%3A%2F%2Fwww.cnn.com%2F script
-http://www.cnn.com/ https://www.facebook.com/tr/?id=731697573629176&ev=PageView&dl=http%3A%2F%2Fwww.cnn.com%2F&rl=&if=false&ts=1516016282474&sw=360&sh=512&v=2.8.6&r=stable&ec=0&o=28&ttf=30544.440000000002&tts=25020.22&ttse=30532.300000000003&it=1516016276988 image
-http://www.cnn.com/ https://www.facebook.com/tr/?id=731697573629176&ev=Microdata&dl=http%3A%2F%2Fwww.cnn.com%2F&rl=&if=false&ts=1516016283426&cd[Schema.org]=%5B%5D&cd[OpenGraph]=%7B%22og%3Apubdate%22%3A%222014-02-19T19%3A15%3A05Z%22%2C%22og%3Aurl%22%3A%22http%3A%2F%2Fwww.cnn.com%22%2C%22og%3Atitle%22%3A%22CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos%22%2C%22og%3Adescription%22%3A%22View%20the%20latest%20news%20and%20breaking%20news%20today%20for%20U.S.%2C%20world%2C%20weather%2C%20entertainment%2C%20politics%20and%20health%20at%20CNN.com.%22%2C%22og%3Asite_name%22%3A%22CNN%22%2C%22og%3Atype%22%3A%22website%22%7D&cd[Meta]=%7B%22title%22%3A%22CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos%22%2C%22meta%3Adescription%22%3A%22View%20the%20latest%20news%20and%20breaking%20news%20today%20for%20U.S.%2C%20world%2C%20weather%2C%20entertainment%2C%20politics%20and%20health%20at%20CNN.com.%22%2C%22meta%3Akeywords%22%3A%22cnn%20news%2C%20daily%20news%2C%20breaking%20news%2C%20news%20today%2C%20current%20events%22%7D&cd[DataLayer]=%5B%5D&sw=360&sh=512&v=2.8.6&o=28&ttf=31496.600000000002&tts=25020.22&ttse=30562.335000000003 image
-http://www.cnn.com/ http://image4.pubmatic.com/AdServer/SPug?partnerID=156011 text
-http://www.cnn.com/ https://www.facebook.com/impression.php/f1420ff9203ae4/?api_key=80401312489&lid=115&payload=%7B%22source%22%3A%22jssdk%22%7D image
-http://www.cnn.com/ http://cdn2.gigya.com/gs/i/shareBar/button/mobile/buttonCenterImgUp.png image
-http://www.cnn.com/ http://cdn2.gigya.com/js/gigya.services.socialize.plugins.simpleshare.min.js script
-http://www.cnn.com/ https://cm.g.doubleclick.net/pixel?google_nid=netmng&google_push=AHNF13I1k5UPNUARCEHWvn2nYvUz0LHx0z1yCd2rTPpiSCWlaQ&google_hm= image
-http://www.cnn.com/ https://d3qdfnco3bamip.cloudfront.net/wjs/v3.0.1510876983/javascripts/livefyre_base.js script
-http://www.cnn.com/ https://social-login.cnn.com/gscounters.sendReport?reports=%5B%7B%22name%22%3A%22load%22%2C%22time%22%3A%221516016282732%22%2C%22source%22%3A%22showShareBarUI%22%2C%22reportData%22%3A%7B%7D%7D%2C%7B%22name%22%3A%22load%22%2C%22time%22%3A%221516016282910%22%2C%22source%22%3A%22showShareBarUI%22%2C%22reportData%22%3A%7B%7D%7D%2C%7B%22name%22%3A%22load%22%2C%22time%22%3A%221516016282934%22%2C%22source%22%3A%22showShareBarUI%22%2C%22reportData%22%3A%7B%7D%7D%5D&APIKey=3_gtUbleJNtrRITgx-1mM_ci7GcIrH8xL9W_VfAbzSa4zpFrRwnpq_eYd8QTRkr7VC&sdk=js_7.4.40&pageURL=http%3A%2F%2Fwww.cnn.com%2F&format=jsonp&callback=gigya.callback&context=R741414015 script
-http://www.cnn.com/ https://a.company-target.com/bidswitch_match?bidswitch_ssp_id=yieldmo&bsw_custom_parameter=1 other
-http://www.cnn.com/ https://us-u.openx.net/w/1.0/sd?id=537073061&val=3035464215136316560 image
-http://www.cnn.com/ https://googleads.g.doubleclick.net/pagead/gen_204?v=3&s=pagead&action=loadimgad&it=fb.1368,e2e.17072,fs.1364,reqs.1367,ress.1368,rese.1593&srt=6&e=370204017&id=csi_pagead&gqid=kJJcWrDBCo3IkwPG0p3oCQ&qqid=CIbUgtvw2dgCFYKtZAoduqgHSA&rt=ol.15704 html
-http://www.cnn.com/ https://a.company-target.com/ul_cb/bidswitch_match?bidswitch_ssp_id=yieldmo&bsw_custom_parameter=1 other
-http://www.cnn.com/ https://z.cdn.turner.com/xslo/aspen/config/theo/cnn/aspenanalytics.json?_=1455 script
-http://www.cnn.com/ http://pmd.cdn.turner.com/cnn/.element/video/assets/blank.mp4 video
-http://www.cnn.com/ https://x.bidswitch.net/sync?dsp_id=7&user_id=1c74eedd-af9d-4be4-a4c6-2ffc5b11ca6b&user_group=3&ssp=yieldmo&bsw_param=1 other
-http://www.cnn.com/ https://z.cdn.turner.com/xslo/cvp/easyxdm/js/easyXDM.ugly.js script
-http://www.cnn.com/ https://ads.yieldmo.com/v000/sync?userid=9afac365-fb56-4fcb-bffc-93f39b21c029&pn_id=bsw image
-http://www.cnn.com/ http://pmd.cdn.turner.com/cnn/.element/video/assets/blank.mp4 video
-http://www.cnn.com/ https://license.theoplayer.com/ other
-http://www.cnn.com/ http://pmd.cdn.turner.com/cnn/.element/video/assets/blank.mp4 video
-http://www.cnn.com/ https://aspen.ngtv.io/static/xdm_iframe.html?xdm_e=http%3A%2F%2Fwww.cnn.com&xdm_c=default9337&xdm_p=1 html
-http://www.cnn.com/ https://cvp1.cdn.turner.com/xslo/cvp/easyxdm/js/easyXDM.ugly.js script
-http://www.cnn.com/ http://pmd.cdn.turner.com/cnn/.element/video/assets/blank.mp4 video
-http://www.cnn.com/ http://static.chartbeat.com/js/chartbeat.js script
-http://www.cnn.com/ https://www.facebook.com/connect/ping?client_id=80401312489&domain=www.cnn.com&origin=2&redirect_uri=http%3A%2F%2Fstaticxx.facebook.com%2Fconnect%2Fxd_arbiter%2Fr%2FlY4eZXm_YWu.js%3Fversion%3D42%23cb%3Df36ac0b44d5b84c%26domain%3Dwww.cnn.com%26origin%3Dhttp%253A%252F%252Fwww.cnn.com%252Ffdc3ccad7a2c5%26relation%3Dparent&response_type=token%2Csigned_request%2Ccode&sdk=joey html
-http://www.cnn.com/ http://staticxx.facebook.com/connect/xd_arbiter/r/lY4eZXm_YWu.js?version=42 script
-http://www.cnn.com/ https://aspen.ngtv.io/api/hello.json script
-http://www.cnn.com/ http://ping.chartbeat.net/ping?h=cnn.com&p=%2F&u=CubA8HBtZVkOCpBni1&d=cnn.com&g=37612&n=1&f=00001&c=0&x=0&m=0&y=9260&o=360&w=512&j=45&R=1&W=0&I=0&E=0&e=0&r=&b=41512&t=p6BcpudngElvaFkab5yUCudiZy&V=97&i=CNN%20-%20Breaking%20News%2C%20Latest%20News%20and%20Videos&tz=480&sn=1&EE=0&sv=qDM6QBYrGs3BHNE5gD4jU2ACwzy0k&_ image
-http://www.cnn.com/ http://www.summerhamster.com/bcn?fe=1516016294155&y=2.0.980&elg=571879868&flg=328&x=zzz.fqq.frp%2F&vqwo=1&deo=0&g0=vg%3A%3Aer%2Cxd%3A%3Aqexd%3A%3Aqsu%7Cvg%3A%3Ask%3A%3Aqsk%3A%3Aqsu%7Clq%3A%3Adm%2Clp%2Clqi%2Cqh%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2F0914.joredo.vvo.idvwob.qhw%2Fdg2%2Flpj%2Fa.jli%3Ffe%3D1516016261558%7Clq%3A%3Adm%2Clqi%2Cqh%2Cvf%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2F0914.joredo.vvo.idvwob.qhw%2Fdg2%2Fvfulsw%2Fa.mv%3Ffe%3D1516016261561%7Clq%3A%3Adm%2Clqi%2Cqh%2Cvf%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2Ffgq3.rswlplchob.frp%2Fmv%2Fjhr2.mv%3Ffe%3D1516016261606%7Cgisl%3A%3Alp%2Clqi%2Cqh%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2Fdg.grxeohfolfn.qhw%2Fggp%2Fdg%2Frupt%2F%3Brug%3D1516016261612%3F%7Cjdg%3A%3Aho%2Ckl%2Cklg%2Clqi%3A%3Aqhk%3A%3Aqsu%3A%3Avho%3D.sodlqDg%7Cjdg%3A%3Akl%2Clp%2Clqi%3A%3Aqoe%3A%3Aqsu%3A%3Axuo%3D%2F%2F0914.joredo.vvo.idvwob.qhw%2Fdg2%2Flpj%2Fa.jli%3Ffe%3D1516016261622%7Cjdg%3A%3Aho%2Ckl%2Cklg%2Clqi%3A%3Aqhk%3A%3Aqsu%3A%3Avho%3D.sodlqDg%7Cddg%2Cjdg%3A%3Aho%2Ckl%2Cklg%2Clqi%3A%3Aqhk%3A%3Aqsu%3A%3Avho%3D.des_re_halvw&hu=0&g2=0%3A%3A0%3A%3A0%3A%3A0%3A%3A0 image
-http://www.cnn.com/ http://mms.cnn.com/aahcmhBbmx7Znpwe2xmcXpGfUQ4LWhqanZ8dXtmcGtEOjk_LWhpd0RtaHN6bC15bG1seXlseUQtcX1EOTU3NUA_Ny1qa2pEfnB1a3Z-NWZ6d2Y1dHpuNWZwdXtseXVoczVqa2o4LW95bG1Eb3t7dyw6SCw5TSw5TX5-fjVqdXU1anZ0LDlNLXssPEkhLDxLRCI= script
-http://www.cnn.com/ http://metrics.cnn.com/b/ss/cnn-adbp-domestic/1/H.26.1/s19966728708393?AQB=1&ndh=1&t=15%2F0%2F2018%203%3A38%3A15%201%20480&fid=3BD061AB4C1A7DBC-03CA17704898AFE3&ce=UTF-8&ns=cnn&pageName=cnn%3Ain%3A%2F&g=http%3A%2F%2Fwww.cnn.com%2F&cc=USD&ch=cnn%20homepage&server=cnn.com&events=event29&c5=nvs&v5=D%3Dc5&c8=new%3A1&v8=D%3Dc8&c9=nvs&v9=D%3Dc9&c13=section&v13=D%3Dc13&c17=anonymous&v17=D%3Dc17&c20=0&v20=D%3Dc20&v22=0&c26=www.cnn.com%2F&v26=D%3DpageName&v27=D%3Dch&c28=cnn%20homepage%3Anvs&v28=D%3Dc28&v29=cnn.com&c30=cnn%20domestic&v30=D%3Dc30&c32=adbp%3Aindex&v32=D%3Dc32&c33=adbp%3Anone&v33=D%3Dc33&c35=cnn.17.1-0-0.20171212%3A0&v35=D%3Dc35&v36=Lu5wrPPJ&c37=smartphone&v37=D%3Dc37&c44=412807cc-201f-45da-848a-26c88edf54f9%3Bfalse&v44=D%3Dc44&c46=15160162567078112473106116&v46=D%3Dc46&c47=5a5c92820daa9a0a3c732e45390057c3&v47=D%3Dc47&c56=portrait&v56=D%3Dc56&c57=no%20mvpd%20set&v57=D%3Dc57&c59=no%20mvpd%20set&v59=D%3Dc59&c64=cnn%20news&v64=D%3Dc64&c65=nvs&c73=2d2e4944851d2346-4000190e8000784f&v73=D%3Dc73&c75=nvs&v75=D%3Dc75&h1=news%7Ccnn%7Ccnn%20domestic%7Ccnn.com%7Ccnn%20homepage%7Ccnn%20homepage%3Anvs&l1=D%3Dc65&l2=&pe=lnk_o&pev2=sourcepoint&s=360x512&c=24&j=1.6&v=N&k=Y&bw=360&bh=512&AQE=1 image
-http://www.cnn.com/ http://cdn.cnn.com/cnn/.e/img/3.0/global/misc/cnn-logo.png image
-http://www.cnn.com/ http://www.cnn.com/favicon.ie9.ico image
-http://www.cnn.com/ https://ml314.com/imsync.ashx?pi=5978151396634809035&data=eyJwaCI6OCwid2giOjAsInRicyI6MCwiZHQiOjE0LCJwaWQiOiIxNTE2MDE2MjgyMzUwX3p6NHcyaGN6ciJ9 html
diff --git a/chromium/components/subresource_filter/core/common/perftests/indexed_ruleset_perftest.cc b/chromium/components/subresource_filter/core/common/perftests/indexed_ruleset_perftest.cc
index bf699508460..de5081ab6be 100644
--- a/chromium/components/subresource_filter/core/common/perftests/indexed_ruleset_perftest.cc
+++ b/chromium/components/subresource_filter/core/common/perftests/indexed_ruleset_perftest.cc
@@ -20,8 +20,8 @@
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
-#include "components/subresource_filter/core/common/tools/filter_tool.h"
-#include "components/subresource_filter/core/common/tools/indexing_tool.h"
+#include "components/subresource_filter/tools/filter_tool.h"
+#include "components/subresource_filter/tools/indexing_tool.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -35,10 +35,13 @@ class IndexedRulesetPerftest : public testing::Test {
void SetUp() override {
base::FilePath dir_path;
- PathService::Get(base::DIR_SOURCE_ROOT, &dir_path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &dir_path);
+
+ // The file contains the subresource URLs of the top-100 Alexa landing
+ // pages.
base::FilePath request_path = dir_path.AppendASCII(
"components/subresource_filter/core/common/perftests/"
- "/data/httparchive_request_corpus.csv");
+ "/data/http_archive_top_100_page_requests");
base::ReadFileToString(request_path, &requests_);
unindexed_path_ = dir_path.AppendASCII(
diff --git a/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc b/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
index 392fdc27e16..96ffa23ad27 100644
--- a/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
+++ b/chromium/components/subresource_filter/core/common/test_ruleset_creator.cc
@@ -13,8 +13,8 @@
#include "base/threading/thread_restrictions.h"
#include "components/subresource_filter/core/common/indexed_ruleset.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
#include "components/url_pattern_index/proto/rules.pb.h"
-#include "components/url_pattern_index/unindexed_ruleset.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
diff --git a/chromium/components/url_pattern_index/unindexed_ruleset.cc b/chromium/components/subresource_filter/core/common/unindexed_ruleset.cc
index d9f4c2df037..5c0d1530476 100644
--- a/chromium/components/url_pattern_index/unindexed_ruleset.cc
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/url_pattern_index/unindexed_ruleset.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
diff --git a/chromium/components/url_pattern_index/unindexed_ruleset.h b/chromium/components/subresource_filter/core/common/unindexed_ruleset.h
index 520f5a1efcc..a0f112c6c7f 100644
--- a/chromium/components/url_pattern_index/unindexed_ruleset.h
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset.h
@@ -19,8 +19,8 @@
// before reading the next one. In practice, this should not be an issue as
// indexing of the ruleset is expected to be performed in an on-line fashion.
-#ifndef COMPONENTS_URL_PATTERN_INDEX_UNINDEXED_RULESET_H_
-#define COMPONENTS_URL_PATTERN_INDEX_UNINDEXED_RULESET_H_
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_UNINDEXED_RULESET_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_UNINDEXED_RULESET_H_
#include "base/macros.h"
#include "components/url_pattern_index/proto/rules.pb.h"
@@ -97,4 +97,4 @@ class UnindexedRulesetWriter {
} // namespace url_pattern_index
-#endif // COMPONENTS_URL_PATTERN_INDEX_UNINDEXED_RULESET_H_
+#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_UNINDEXED_RULESET_H_
diff --git a/chromium/components/url_pattern_index/unindexed_ruleset_unittest.cc b/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
index 318855e013a..ca4a57afdd2 100644
--- a/chromium/components/url_pattern_index/unindexed_ruleset_unittest.cc
+++ b/chromium/components/subresource_filter/core/common/unindexed_ruleset_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/url_pattern_index/unindexed_ruleset.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
#include <memory>
#include <string>
diff --git a/chromium/components/subresource_filter/tools/BUILD.gn b/chromium/components/subresource_filter/tools/BUILD.gn
new file mode 100644
index 00000000000..557e6b29385
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/BUILD.gn
@@ -0,0 +1,121 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/compiled_action.gni")
+
+static_library("tools_lib") {
+ sources = [
+ "filter_tool.cc",
+ "filter_tool.h",
+ "indexing_tool.cc",
+ "indexing_tool.h",
+ ]
+ deps = [
+ "../core/browser",
+ "../core/common",
+ "//base",
+ "//components/url_pattern_index:util",
+ "//url",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "filter_tool_unittest.cc",
+ "indexing_tool_unittest.cc",
+ ]
+
+ deps = [
+ ":tools_lib",
+ "../core/common",
+ "../core/common:test_support",
+ "rule_parser:unit_tests",
+ "ruleset_converter:unit_tests",
+ "//base",
+ "//base/test:test_support",
+ "//components/url_pattern_index:test_support",
+ "//testing/gtest",
+ "//third_party/protobuf:protobuf_lite",
+ "//url",
+ ]
+}
+
+if (!is_ios) {
+ executable("subresource_filter_tool") {
+ # Production code should not depend on this.
+ testonly = true
+ sources = [
+ "filter_tool_main.cc",
+ ]
+ deps = [
+ ":tools_lib",
+ "//base",
+ "//build/config:exe_and_shlib_deps",
+ ]
+ }
+
+ executable("subresource_indexing_tool") {
+ # Production code should not depend on this.
+ testonly = true
+ sources = [
+ "indexing_tool_main.cc",
+ ]
+ deps = [
+ ":tools_lib",
+ "//base",
+ "//build/config:exe_and_shlib_deps",
+ ]
+ }
+
+ executable("ruleset_converter") {
+ sources = [
+ "ruleset_converter/main.cc",
+ ]
+ deps = [
+ "ruleset_converter:support",
+ "//base",
+ "//build/config:exe_and_shlib_deps",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+ }
+
+ group("subresource_filter_tools") {
+ # Production code should not depend on this.
+ testonly = true
+ deps = [
+ ":ruleset_converter",
+ ":subresource_filter_tool",
+ ":subresource_indexing_tool",
+ ]
+ }
+
+ # This action compiles the indexing tool using the host's toolchain, and
+ # generates an indexed ruleset using the existing unindexed ruleset in the
+ # source tree.
+ compiled_action("index_ruleset") {
+ testonly = true
+ tool = ":subresource_indexing_tool"
+
+ outputs = [
+ "$target_gen_dir/GeneratedRulesetData",
+ ]
+
+ inputs = [
+ # Make sure the inputs are system-absolute, as base::File cannot open files with ".." components.
+ rebase_path(
+ "//components/subresource_filter/core/common/perftests/data/UnindexedRules_7.54",
+ "",
+ "/"),
+ ]
+ deps = [
+ ":subresource_indexing_tool",
+ ]
+
+ args = [
+ inputs[0],
+ rebase_path("$target_gen_dir/GeneratedRulesetData", root_build_dir),
+ ]
+ }
+}
diff --git a/chromium/components/subresource_filter/core/common/tools/filter_tool.cc b/chromium/components/subresource_filter/tools/filter_tool.cc
index 9862813fc9e..22641d29cc3 100644
--- a/chromium/components/subresource_filter/core/common/tools/filter_tool.cc
+++ b/chromium/components/subresource_filter/tools/filter_tool.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/subresource_filter/core/common/tools/filter_tool.h"
+#include "components/subresource_filter/tools/filter_tool.h"
#include <istream>
#include <ostream>
@@ -11,7 +11,9 @@
#include <utility>
#include <vector>
-#include "base/strings/string_split.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/values.h"
#include "components/subresource_filter/core/common/activation_level.h"
#include "components/subresource_filter/core/common/activation_state.h"
#include "components/subresource_filter/core/common/document_subresource_filter.h"
@@ -85,6 +87,15 @@ const url_pattern_index::flat::UrlRule* FindMatchingUrlRule(
return filter.FindMatchingUrlRule(request_url, type);
}
+const std::string& ExtractStringFromDictionary(base::Value* dictionary,
+ const std::string& key) {
+ DCHECK(dictionary->is_dict());
+
+ const base::Value* found = dictionary->FindKey(key);
+ CHECK(found);
+ return found->GetString();
+}
+
} // namespace
FilterTool::FilterTool(
@@ -119,7 +130,7 @@ void FilterTool::PrintResult(bool blocked,
base::StringPiece type) {
*output_ << (blocked ? "BLOCKED " : "ALLOWED ");
if (rule) {
- *output_ << url_pattern_index::FlatUrlRuleToString(rule) << " ";
+ *output_ << url_pattern_index::FlatUrlRuleToFilterlistString(rule) << " ";
}
*output_ << document_origin << " " << url << " " << type << std::endl;
}
@@ -152,15 +163,15 @@ void FilterTool::MatchBatchImpl(std::istream* request_stream,
if (line.empty())
continue;
- std::vector<base::StringPiece> strings = base::SplitStringPiece(
- line, " ", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-
- LOG_IF(FATAL, strings.size() != 3u)
- << "Incorrect number of arguments found in batch record";
+ std::unique_ptr<base::Value> dictionary = base::JSONReader::Read(line);
+ CHECK(dictionary);
- base::StringPiece origin = strings[0];
- base::StringPiece request_url = strings[1];
- base::StringPiece request_type = strings[2];
+ const std::string& origin =
+ ExtractStringFromDictionary(dictionary.get(), "origin");
+ const std::string& request_url =
+ ExtractStringFromDictionary(dictionary.get(), "request_url");
+ const std::string& request_type =
+ ExtractStringFromDictionary(dictionary.get(), "request_type");
bool blocked;
const url_pattern_index::flat::UrlRule* rule =
@@ -177,7 +188,8 @@ void FilterTool::MatchBatchImpl(std::istream* request_stream,
for (auto rule_and_count : matched_rules) {
if (rule_and_count.second >= min_match_count) {
- *output_ << url_pattern_index::FlatUrlRuleToString(rule_and_count.first)
+ *output_ << url_pattern_index::FlatUrlRuleToFilterlistString(
+ rule_and_count.first)
.c_str()
<< std::endl;
}
diff --git a/chromium/components/subresource_filter/core/common/tools/filter_tool.h b/chromium/components/subresource_filter/tools/filter_tool.h
index f762df07a43..4eef9032deb 100644
--- a/chromium/components/subresource_filter/core/common/tools/filter_tool.h
+++ b/chromium/components/subresource_filter/tools/filter_tool.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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TOOLS_FILTER_TOOL_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TOOLS_FILTER_TOOL_H_
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_TOOLS_FILTER_TOOL_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_FILTER_TOOL_H_
#include <istream>
#include <ostream>
@@ -79,4 +79,4 @@ class FilterTool {
} // namespace subresource_filter
-#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TOOLS_FILTER_TOOL_H_
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_FILTER_TOOL_H_
diff --git a/chromium/components/subresource_filter/core/common/tools/filter_tool_main.cc b/chromium/components/subresource_filter/tools/filter_tool_main.cc
index 0fa65830b66..b5a93665ae8 100644
--- a/chromium/components/subresource_filter/core/common/tools/filter_tool_main.cc
+++ b/chromium/components/subresource_filter/tools/filter_tool_main.cc
@@ -15,7 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
-#include "components/subresource_filter/core/common/tools/filter_tool.h"
+#include "components/subresource_filter/tools/filter_tool.h"
namespace {
@@ -46,12 +46,16 @@ const char kHelpMsg[] = R"(
For a given request if a whitelist rule matches as well as a blacklist
rule, the whitelist rule is printed but not the blacklist rule.
- * match_batch --input_file=<csv_file_path>
- Like match, except it does the same for each request in a space
- delimited file. The file format is:
- <document_origin> <request_url> <type>
+ * match_batch --input_file=<json_file_path>
+ Like match, except it does the same for each request in a json file.
+ The file format is one json expression per line. An example line
+ follows (note: in the file it wouldn't have a line break like this
+ comment does):
- * match_rules --input_file=<csv_file_path> --min_matches=<optional>
+ {"origin":"http://www.example.com/","request_url":"http://www.exam
+ ple.com/foo.js","request_type":"script"}
+
+ * match_rules --input_file=<json_file_path> --min_matches=<optional>
For each record in the given whitespace delimited file (see
match_batch for input file format), records the matching rule (see
match command above) and prints all of the matched rules at the end.
diff --git a/chromium/components/subresource_filter/core/common/tools/filter_tool_unittest.cc b/chromium/components/subresource_filter/tools/filter_tool_unittest.cc
index fa188810eb0..f210b819276 100644
--- a/chromium/components/subresource_filter/core/common/tools/filter_tool_unittest.cc
+++ b/chromium/components/subresource_filter/tools/filter_tool_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/subresource_filter/core/common/tools/filter_tool.h"
+#include "components/subresource_filter/tools/filter_tool.h"
#include <algorithm>
#include <memory>
@@ -10,6 +10,8 @@
#include <string>
#include <vector>
+#include "base/json/json_writer.h"
+#include "base/values.h"
#include "components/subresource_filter/core/common/memory_mapped_ruleset.h"
#include "components/subresource_filter/core/common/test_ruleset_creator.h"
#include "components/subresource_filter/core/common/test_ruleset_utils.h"
@@ -38,6 +40,19 @@ bool StringsHaveSameLines(const std::string& a, const std::string& b) {
return lines_a == lines_b;
}
+std::string CreateJsonLine(const std::string& origin,
+ const std::string& request_url,
+ const std::string& request_type) {
+ base::DictionaryValue dictionary;
+ dictionary.SetString("origin", origin);
+ dictionary.SetString("request_url", request_url);
+ dictionary.SetString("request_type", request_type);
+
+ std::string output;
+ EXPECT_TRUE(base::JSONWriter::Write(dictionary, &output));
+ return output + "\n";
+}
+
class FilterToolTest : public ::testing::Test {
public:
FilterToolTest() {}
@@ -106,11 +121,13 @@ TEST_F(FilterToolTest, NoMatch) {
TEST_F(FilterToolTest, MatchBatch) {
std::stringstream batch_queries;
- batch_queries
- << "http://example.com http://example.com/disallowed1.png image\n"
- "http://example.com http://example.com/disallowed2.png image\n"
- "http://example.com http://example.com/whitelist/disallowed2.png "
- "image\n";
+ batch_queries << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed1.png", "image")
+ << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed2.png", "image")
+ << CreateJsonLine(
+ "http://example.com",
+ "http://example.com/whitelist/disallowed2.png", "image");
filter_tool_->MatchBatch(&batch_queries);
@@ -127,12 +144,15 @@ TEST_F(FilterToolTest, MatchBatch) {
TEST_F(FilterToolTest, MatchRules) {
std::stringstream batch_queries;
- batch_queries
- << "http://example.com http://example.com/disallowed1.png image\n"
- "http://example.com http://example.com/disallowed1.png image\n"
- "http://example.com http://example.com/disallowed2.png image\n"
- "http://example.com http://example.com/whitelist/disallowed2.png "
- "image\n";
+ batch_queries << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed1.png", "image")
+ << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed1.png", "image")
+ << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed2.png", "image")
+ << CreateJsonLine(
+ "http://example.com",
+ "http://example.com/whitelist/disallowed2.png", "image");
filter_tool_->MatchRules(&batch_queries, 1);
@@ -148,16 +168,21 @@ TEST_F(FilterToolTest, MatchRules) {
TEST_F(FilterToolTest, MatchRulesMinCount) {
std::stringstream batch_queries;
- batch_queries
- << "http://example.com http://example.com/disallowed1.png image\n"
- "http://example.com http://example.com/disallowed1.png image\n"
- "http://example.com http://example.com/disallowed2.png image\n"
- "http://example.com http://example.com/whitelist/disallowed2.png "
- "image\n"
- "http://example.com http://example.com/whitelist/disallowed2.png "
- "image\n"
- "http://example.com http://example.com/whitelist/disallowed2.png "
- "image\n";
+ batch_queries << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed1.png", "image")
+ << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed1.png", "image")
+ << CreateJsonLine("http://example.com",
+ "http://example.com/disallowed2.png", "image")
+ << CreateJsonLine(
+ "http://example.com",
+ "http://example.com/whitelist/disallowed2.png", "image")
+ << CreateJsonLine(
+ "http://example.com",
+ "http://example.com/whitelist/disallowed2.png", "image")
+ << CreateJsonLine(
+ "http://example.com",
+ "http://example.com/whitelist/disallowed2.png", "image");
filter_tool_->MatchRules(&batch_queries, 2);
diff --git a/chromium/components/subresource_filter/core/common/tools/indexing_tool.cc b/chromium/components/subresource_filter/tools/indexing_tool.cc
index 832a5728852..bcffeb2abad 100644
--- a/chromium/components/subresource_filter/core/common/tools/indexing_tool.cc
+++ b/chromium/components/subresource_filter/tools/indexing_tool.cc
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/subresource_filter/core/common/tools/indexing_tool.h"
+#include "components/subresource_filter/tools/indexing_tool.h"
#include <utility>
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/numerics/safe_conversions.h"
+#include "components/subresource_filter/core/browser/copying_file_stream.h"
#include "components/subresource_filter/core/common/indexed_ruleset.h"
-#include "components/url_pattern_index/copying_file_stream.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
#include "components/url_pattern_index/proto/rules.pb.h"
-#include "components/url_pattern_index/unindexed_ruleset.h"
namespace subresource_filter {
diff --git a/chromium/components/subresource_filter/core/common/tools/indexing_tool.h b/chromium/components/subresource_filter/tools/indexing_tool.h
index 3dbade98898..fbb232e646f 100644
--- a/chromium/components/subresource_filter/core/common/tools/indexing_tool.h
+++ b/chromium/components/subresource_filter/tools/indexing_tool.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 COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TOOLS_INDEXING_TOOL_H_
-#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TOOLS_INDEXING_TOOL_H_
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_TOOLS_INDEXING_TOOL_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_INDEXING_TOOL_H_
#include "base/command_line.h"
#include "base/files/file_path.h"
@@ -18,4 +18,4 @@ bool IndexAndWriteRuleset(const base::FilePath& unindexed_path,
} // namespace subresource_filter
-#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_TOOLS_INDEXING_TOOL_H_
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_INDEXING_TOOL_H_
diff --git a/chromium/components/subresource_filter/core/common/tools/indexing_tool_main.cc b/chromium/components/subresource_filter/tools/indexing_tool_main.cc
index 2d335d529c4..8b07dd2d276 100644
--- a/chromium/components/subresource_filter/core/common/tools/indexing_tool_main.cc
+++ b/chromium/components/subresource_filter/tools/indexing_tool_main.cc
@@ -6,7 +6,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
-#include "components/subresource_filter/core/common/tools/indexing_tool.h"
+#include "components/subresource_filter/tools/indexing_tool.h"
const char kHelpMsg[] = R"(
subresource_indexing_tool <unindexed_ruleset_file> <output_file>
diff --git a/chromium/components/subresource_filter/core/common/tools/indexing_tool_unittest.cc b/chromium/components/subresource_filter/tools/indexing_tool_unittest.cc
index 807f4d9446d..86becab1a27 100644
--- a/chromium/components/subresource_filter/core/common/tools/indexing_tool_unittest.cc
+++ b/chromium/components/subresource_filter/tools/indexing_tool_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/subresource_filter/core/common/tools/indexing_tool.h"
+#include "components/subresource_filter/tools/indexing_tool.h"
#include <memory>
#include <string>
diff --git a/chromium/components/subresource_filter/tools/rule_parser/BUILD.gn b/chromium/components/subresource_filter/tools/rule_parser/BUILD.gn
new file mode 100644
index 00000000000..7a2ff522f45
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/BUILD.gn
@@ -0,0 +1,35 @@
+# 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.
+
+source_set("rule_parser") {
+ sources = [
+ "rule.cc",
+ "rule.h",
+ "rule_options.h",
+ "rule_parser.cc",
+ "rule_parser.h",
+ ]
+ public_deps = [
+ "//components/url_pattern_index",
+ ]
+ deps = [
+ "//base",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "rule_parser_unittest.cc",
+ "rule_unittest.cc",
+ ]
+ deps = [
+ ":rule_parser",
+ "//base",
+ "//components/url_pattern_index/proto:url_pattern_index",
+ "//testing/gtest",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+}
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule.cc b/chromium/components/subresource_filter/tools/rule_parser/rule.cc
new file mode 100644
index 00000000000..f3452f5481f
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule.cc
@@ -0,0 +1,351 @@
+// 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 "components/subresource_filter/tools/rule_parser/rule.h"
+
+#include <stddef.h>
+#include <algorithm>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/string_util.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Returns the simplest matching strategy that can be used for the |rule|.
+UrlPatternType GetUrlPatternType(const UrlRule& rule) {
+ const std::string& url_pattern = rule.url_pattern;
+ if (url_pattern.size() >= 2 && url_pattern.front() == '/' &&
+ url_pattern.back() == '/') {
+ return url_pattern_index::proto::URL_PATTERN_TYPE_REGEXP;
+ }
+ if (url_pattern.find('^') != std::string::npos ||
+ rule.anchor_right != url_pattern_index::proto::ANCHOR_TYPE_NONE ||
+ rule.anchor_left != url_pattern_index::proto::ANCHOR_TYPE_NONE) {
+ return url_pattern_index::proto::URL_PATTERN_TYPE_WILDCARDED;
+ }
+ size_t wildcard_pos = url_pattern.find('*');
+
+ if (wildcard_pos == std::string::npos ||
+ wildcard_pos == url_pattern.size() - 1) {
+ return url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ }
+
+ if (wildcard_pos == 0) {
+ size_t next_wildcard = url_pattern.find('*', 1);
+ if (next_wildcard == std::string::npos ||
+ next_wildcard == url_pattern.size() - 1) {
+ return url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ }
+ }
+ return url_pattern_index::proto::URL_PATTERN_TYPE_WILDCARDED;
+}
+
+void DomainListJoin(const google::protobuf::RepeatedPtrField<
+ url_pattern_index::proto::DomainListItem>& domain_list,
+ char separator,
+ std::string* output) {
+ for (const url_pattern_index::proto::DomainListItem& item : domain_list) {
+ if (item.exclude())
+ *output += '~';
+ *output += item.domain();
+ *output += separator;
+ }
+ output->pop_back(); // Remove the last separator.
+}
+
+} // namespace
+
+UrlRule::UrlRule() = default;
+
+UrlRule::UrlRule(const UrlRule&) = default;
+
+UrlRule::~UrlRule() = default;
+
+UrlRule& UrlRule::operator=(const UrlRule&) = default;
+
+bool UrlRule::operator==(const UrlRule& other) const {
+ return is_whitelist == other.is_whitelist &&
+ is_third_party == other.is_third_party &&
+ match_case == other.match_case && type_mask == other.type_mask &&
+ domains == other.domains &&
+ url_pattern_type == other.url_pattern_type &&
+ url_pattern == other.url_pattern;
+}
+
+url_pattern_index::proto::UrlRule UrlRule::ToProtobuf() const {
+ url_pattern_index::proto::UrlRule result;
+
+ result.set_semantics(
+ is_whitelist ? url_pattern_index::proto::RULE_SEMANTICS_WHITELIST
+ : url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST);
+ switch (is_third_party) {
+ case TriState::DONT_CARE:
+ result.set_source_type(url_pattern_index::proto::SOURCE_TYPE_ANY);
+ break;
+ case TriState::YES:
+ result.set_source_type(url_pattern_index::proto::SOURCE_TYPE_THIRD_PARTY);
+ break;
+ case TriState::NO:
+ result.set_source_type(url_pattern_index::proto::SOURCE_TYPE_FIRST_PARTY);
+ break;
+ default:
+ LOG(FATAL);
+ break;
+ }
+
+ if (type_mask & kAllElementTypes)
+ result.set_element_types(type_mask & kAllElementTypes);
+ if (type_mask & kAllActivationTypes) {
+ result.set_activation_types((type_mask & kAllActivationTypes) >>
+ kActivationTypesShift);
+ }
+
+ for (const std::string& domain : domains) {
+ url_pattern_index::proto::DomainListItem* list_item = result.add_domains();
+ if (domain.empty())
+ continue;
+ if (domain[0] == '~') {
+ list_item->set_domain(domain.substr(1));
+ list_item->set_exclude(true);
+ } else {
+ list_item->set_domain(domain);
+ }
+ }
+
+ result.set_url_pattern_type(url_pattern_type);
+ result.set_anchor_left(anchor_left);
+ result.set_anchor_right(anchor_right);
+ if (match_case != result.match_case())
+ result.set_match_case(match_case);
+ if (!url_pattern.empty())
+ result.set_url_pattern(url_pattern);
+
+ return result;
+}
+
+void UrlRule::Canonicalize() {
+ url_pattern_type = GetUrlPatternType(*this);
+ CanonicalizeUrlPattern();
+ CanonicalizeDomainList(&domains);
+}
+
+CssRule::CssRule() = default;
+
+CssRule::CssRule(const CssRule&) = default;
+
+CssRule::~CssRule() = default;
+
+CssRule& CssRule::operator=(const CssRule&) = default;
+
+bool CssRule::operator==(const CssRule& other) const {
+ return is_whitelist == other.is_whitelist && domains == other.domains &&
+ css_selector == other.css_selector;
+}
+
+url_pattern_index::proto::CssRule CssRule::ToProtobuf() const {
+ url_pattern_index::proto::CssRule result;
+
+ result.set_semantics(
+ is_whitelist ? url_pattern_index::proto::RULE_SEMANTICS_WHITELIST
+ : url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST);
+
+ for (const std::string& domain : domains) {
+ url_pattern_index::proto::DomainListItem* list_item = result.add_domains();
+ if (domain.empty())
+ continue;
+ if (domain[0] == '~') {
+ list_item->set_domain(domain.substr(1));
+ list_item->set_exclude(true);
+ } else {
+ list_item->set_domain(domain);
+ }
+ }
+
+ if (!css_selector.empty())
+ result.set_css_selector(css_selector);
+
+ return result;
+}
+
+void CssRule::Canonicalize() {
+ CanonicalizeDomainList(&domains);
+}
+
+void UrlRule::CanonicalizeUrlPattern() {
+ if (url_pattern_type == url_pattern_index::proto::URL_PATTERN_TYPE_REGEXP)
+ return;
+ // TODO(melandory): Canonicalize more, e.g. squeeze '/\*\*+/' sequences
+ // down to one '*'.
+ if (anchor_left != url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN &&
+ !url_pattern.empty() && url_pattern.front() == '*') {
+ url_pattern.erase(0, 1);
+ anchor_left = url_pattern_index::proto::ANCHOR_TYPE_NONE;
+ }
+ if (!url_pattern.empty() && url_pattern.back() == '*') {
+ url_pattern.erase(url_pattern.size() - 1, 1);
+ anchor_right = url_pattern_index::proto::ANCHOR_TYPE_NONE;
+ }
+}
+
+void CanonicalizeDomainList(std::vector<std::string>* domains) {
+ if (!domains->empty()) {
+ std::sort(domains->begin(), domains->end(),
+ [](const std::string& lhs, const std::string& rhs) {
+ return lhs.size() > rhs.size() ||
+ (lhs.size() == rhs.size() && lhs < rhs);
+ });
+ }
+}
+
+std::string ToString(const url_pattern_index::proto::UrlRule& rule) {
+ std::string result;
+
+ switch (rule.semantics()) {
+ case url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST:
+ break;
+ case url_pattern_index::proto::RULE_SEMANTICS_WHITELIST:
+ result += "@@";
+ break;
+ default:
+ LOG(FATAL);
+ }
+
+ switch (rule.anchor_left()) {
+ case url_pattern_index::proto::ANCHOR_TYPE_NONE:
+ break;
+ case url_pattern_index::proto::ANCHOR_TYPE_BOUNDARY:
+ result += '|';
+ break;
+ case url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN:
+ result += "||";
+ break;
+ default:
+ LOG(FATAL);
+ }
+ result += rule.url_pattern();
+ switch (rule.anchor_right()) {
+ case url_pattern_index::proto::ANCHOR_TYPE_NONE:
+ break;
+ case url_pattern_index::proto::ANCHOR_TYPE_BOUNDARY:
+ result += '|';
+ break;
+ default:
+ LOG(FATAL);
+ }
+
+ std::vector<std::string> options;
+
+ if (rule.element_types() != kDefaultElementTypes) {
+ // Try to print as few element types as possible.
+ int balance = 0;
+ for (const auto& element_type : kElementTypes) {
+ if (rule.element_types() & type_mask_for(element_type.type))
+ ++balance;
+ else
+ --balance;
+ }
+ const bool print_positives = (balance <= 0);
+
+ for (const auto& element_type : kElementTypes) {
+ if (element_type.type == url_pattern_index::proto::ELEMENT_TYPE_POPUP)
+ continue;
+
+ const bool is_positive =
+ rule.element_types() & type_mask_for(element_type.type);
+ if (is_positive == print_positives) {
+ if (is_positive)
+ options.push_back(element_type.name);
+ else
+ options.push_back(std::string("~") + element_type.name);
+ }
+ }
+
+ // The POPUP type is excluded by default, therefore should be printed last.
+ if (rule.element_types() &
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_POPUP)) {
+ const auto& popup_type = kElementTypes[11];
+ DCHECK_EQ(url_pattern_index::proto::ELEMENT_TYPE_POPUP, popup_type.type);
+ options.push_back(popup_type.name);
+ }
+ }
+
+ for (const auto& activation_type : kActivationTypes) {
+ if (rule.activation_types() & activation_type.type)
+ options.push_back(activation_type.name);
+ }
+
+ // This workaround produces a text rule which, when parsed back from text,
+ // results in the same URL rule. Otherwise the parsed rule would have
+ // element_types == kDefaultElementTypes instead of 0.
+ if (!rule.element_types() && !rule.activation_types()) {
+ const auto& image_type = kElementTypes[2];
+ DCHECK_EQ(url_pattern_index::proto::ELEMENT_TYPE_IMAGE, image_type.type);
+ options.push_back(image_type.name);
+ options.push_back(std::string("~") + image_type.name);
+ }
+
+ std::string source_type_string;
+ switch (rule.source_type()) {
+ case url_pattern_index::proto::SOURCE_TYPE_ANY:
+ break;
+ case url_pattern_index::proto::SOURCE_TYPE_FIRST_PARTY:
+ source_type_string = "~";
+ FALLTHROUGH;
+ case url_pattern_index::proto::SOURCE_TYPE_THIRD_PARTY:
+ source_type_string += "third-party";
+ options.push_back(std::move(source_type_string));
+ break;
+ default:
+ LOG(FATAL);
+ }
+
+ if (rule.match_case())
+ options.push_back("match-case");
+
+ if (rule.domains_size()) {
+ std::string domains = "domain=";
+ DomainListJoin(rule.domains(), '|', &domains);
+ options.push_back(std::move(domains));
+ }
+
+ if (!options.empty()) {
+ result += '$';
+ result += base::JoinString(options, ",");
+ }
+
+ return result;
+}
+
+std::string ToString(const url_pattern_index::proto::CssRule& rule) {
+ std::string result;
+ if (rule.domains_size())
+ DomainListJoin(rule.domains(), ',', &result);
+
+ switch (rule.semantics()) {
+ case url_pattern_index::proto::RULE_SEMANTICS_BLACKLIST:
+ result += "##";
+ break;
+ case url_pattern_index::proto::RULE_SEMANTICS_WHITELIST:
+ result += "#@#";
+ break;
+ default:
+ LOG(FATAL);
+ }
+
+ return result += rule.css_selector();
+}
+
+std::ostream& operator<<(std::ostream& os, const UrlRule& rule) {
+ return os << "UrlRule(" << ToString(rule.ToProtobuf()) << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const CssRule& rule) {
+ return os << "CssRule(" << ToString(rule.ToProtobuf()) << ")";
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule.h b/chromium/components/subresource_filter/tools/rule_parser/rule.h
new file mode 100644
index 00000000000..fe989bccd03
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule.h
@@ -0,0 +1,136 @@
+// 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.
+//
+// This file contains definitions of data structures needed for representing
+// filtering/hiding rules as parsed from EasyList. See the following links for
+// detailed explanation on available rule types and their syntax:
+// https://adblockplus.org/en/filters
+// https://adblockplus.org/en/filter-cheatsheet
+// For out-of-documentation options see the following:
+// https://adblockplus.org/forum/viewtopic.php?t=9353
+// https://adblockplus.org/development-builds/experimental-pop-up-blocking-support
+// https://adblockplus.org/development-builds/new-filter-options-generichide-and-genericblock
+//
+// TODO(pkalinnikov): Consider removing these classes, leaving only the
+// corresponding protobuf structures.
+
+#ifndef COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_H_
+
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "components/subresource_filter/tools/rule_parser/rule_options.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+
+namespace subresource_filter {
+
+using UrlPatternType = url_pattern_index::proto::UrlPatternType;
+using RuleType = url_pattern_index::proto::RuleType;
+using AnchorType = url_pattern_index::proto::AnchorType;
+
+// Represents the three values in a kind of tri-state logic.
+enum class TriState {
+ DONT_CARE = 0,
+ YES = 1,
+ NO = 2,
+};
+
+// A single URL filtering rule as parsed from EasyList.
+// TODO(pkalinnikov): Add 'sitekey', 'collapse', and 'donottrack' options.
+struct UrlRule {
+ // Constructs a default empty blacklist rule. That means URL pattern is empty,
+ // not case sensitive and not anchored, domain list is empty, and the rule is
+ // associated with all ElementType's (except POPUP), and none of the
+ // ActivationType's.
+ UrlRule();
+
+ UrlRule(const UrlRule&);
+ ~UrlRule();
+ UrlRule& operator=(const UrlRule&);
+
+ bool operator==(const UrlRule& other) const;
+ bool operator!=(const UrlRule& other) const { return !operator==(other); }
+
+ // Returns a protobuf representation of the rule.
+ url_pattern_index::proto::UrlRule ToProtobuf() const;
+
+ // Canonicalizes the rule, i.e. orders the |domains| list properly, determines
+ // |url_pattern_type| based on |url_pattern| together with |anchor_*|'s and
+ // modifies the |url_pattern| accordingly to reduce the amount of redundancy
+ // in the pattern.
+ void Canonicalize();
+
+ // Canonicalizes the rule's |url_pattern|.
+ void CanonicalizeUrlPattern();
+
+ // This is a whitelist rule (aka rule-level exception).
+ bool is_whitelist = false;
+ // An anchor used at the beginning of the URL pattern.
+ AnchorType anchor_left = url_pattern_index::proto::ANCHOR_TYPE_NONE;
+ // The same for the end of the pattern. Never equals to ANCHOR_TYPE_SUBDOMAIN.
+ AnchorType anchor_right = url_pattern_index::proto::ANCHOR_TYPE_NONE;
+ // Restriction to first-party/third-party requests.
+ TriState is_third_party = TriState::DONT_CARE;
+ // Apply the filter only to addresses with matching case.
+ // TODO(pkalinnikov): Implement case insensitivity in matcher.
+ bool match_case = false;
+ // A bitmask that reflects what ElementType's to block/whitelist and what
+ // kinds of ActivationType's to associate this rule with.
+ TypeMask type_mask = kDefaultElementTypes;
+ // The list of domains to be included/excluded from the filter's affected set.
+ // If a particular string in the list starts with '~' then the respective
+ // domain is excluded, otherwise included. The list should be ordered by
+ // |CanonicalizeDomainList|.
+ std::vector<std::string> domains;
+ // The type of the URL pattern's format.
+ UrlPatternType url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ // A URL pattern in either of UrlPatternType's formats, corresponding to
+ // |url_pattern_type|.
+ std::string url_pattern;
+};
+
+// A single CSS element hiding rule as parsed from EasyList.
+struct CssRule {
+ // Constructs a default empty blacklist rule (no domains, empty selector).
+ CssRule();
+
+ CssRule(const CssRule&);
+ ~CssRule();
+ CssRule& operator=(const CssRule&);
+
+ bool operator==(const CssRule& other) const;
+ bool operator!=(const CssRule& other) const { return !operator==(other); }
+
+ // Returns a protobuf representation of the rule.
+ url_pattern_index::proto::CssRule ToProtobuf() const;
+
+ // Canonicalizes the rule, i.e. orders the |domains| list properly.
+ void Canonicalize();
+
+ // This is a whitelist rule (aka rule-level exception).
+ bool is_whitelist = false;
+ // The list of domains, same as UrlRule::domains.
+ std::vector<std::string> domains;
+ // A CSS selector as specified in http://www.w3.org/TR/css3-selectors.
+ std::string css_selector;
+};
+
+// Sorts domain patterns in decreasing order of length (and alphabetically
+// within same-length groups).
+void CanonicalizeDomainList(std::vector<std::string>* domains);
+
+// Converts protobuf |rule| into its canonical EasyList string representation.
+std::string ToString(const url_pattern_index::proto::UrlRule& rule);
+std::string ToString(const url_pattern_index::proto::CssRule& rule);
+
+// For testing.
+std::ostream& operator<<(std::ostream& os, const UrlRule& rule);
+std::ostream& operator<<(std::ostream& os, const CssRule& rule);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_H_
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule_options.h b/chromium/components/subresource_filter/tools/rule_parser/rule_options.h
new file mode 100644
index 00000000000..6e69c6a6130
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule_options.h
@@ -0,0 +1,93 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_OPTIONS_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_OPTIONS_H_
+
+#include <limits>
+
+#include "components/url_pattern_index/proto/rules.pb.h"
+#include "components/url_pattern_index/url_pattern_index.h"
+
+namespace subresource_filter {
+
+// A type used for representing bitmask with ElementType's and ActivationType's.
+using TypeMask = uint32_t;
+
+static constexpr uint32_t kActivationTypesShift = 24;
+static constexpr uint32_t kActivationTypesBits =
+ std::numeric_limits<TypeMask>::digits - kActivationTypesShift;
+
+static_assert(kActivationTypesShift <= std::numeric_limits<TypeMask>::digits,
+ "TypeMask layout is broken");
+static_assert(url_pattern_index::proto::ElementType_MAX <
+ (1 << kActivationTypesShift),
+ "TypeMask layout is broken");
+static_assert(url_pattern_index::proto::ActivationType_MAX <
+ (1 << kActivationTypesBits),
+ "TypeMask layout is broken");
+
+// The functions used to calculate masks for individual types.
+inline constexpr TypeMask type_mask_for(
+ url_pattern_index::proto::ElementType type) {
+ return type;
+}
+inline constexpr TypeMask type_mask_for(
+ url_pattern_index::proto::ActivationType type) {
+ return type << kActivationTypesShift;
+}
+
+static constexpr TypeMask kAllElementTypes =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_ALL);
+static constexpr TypeMask kAllActivationTypes =
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_ALL);
+
+static constexpr TypeMask kDefaultElementTypes =
+ url_pattern_index::kDefaultProtoElementTypesMask;
+
+// A list of items mapping element type options to their names.
+const struct {
+ url_pattern_index::proto::ElementType type;
+ const char* name;
+} kElementTypes[] = {
+ {url_pattern_index::proto::ELEMENT_TYPE_OTHER, "other"},
+ {url_pattern_index::proto::ELEMENT_TYPE_SCRIPT, "script"},
+ {url_pattern_index::proto::ELEMENT_TYPE_IMAGE, "image"},
+ {url_pattern_index::proto::ELEMENT_TYPE_STYLESHEET, "stylesheet"},
+ {url_pattern_index::proto::ELEMENT_TYPE_OBJECT, "object"},
+ {url_pattern_index::proto::ELEMENT_TYPE_XMLHTTPREQUEST, "xmlhttprequest"},
+ {url_pattern_index::proto::ELEMENT_TYPE_OBJECT_SUBREQUEST,
+ "object-subrequest"},
+ {url_pattern_index::proto::ELEMENT_TYPE_SUBDOCUMENT, "subdocument"},
+ {url_pattern_index::proto::ELEMENT_TYPE_PING, "ping"},
+ {url_pattern_index::proto::ELEMENT_TYPE_MEDIA, "media"},
+ {url_pattern_index::proto::ELEMENT_TYPE_FONT, "font"},
+ {url_pattern_index::proto::ELEMENT_TYPE_POPUP, "popup"},
+ {url_pattern_index::proto::ELEMENT_TYPE_WEBSOCKET, "websocket"},
+};
+
+// A mapping from deprecated element type names to active element types.
+const struct {
+ const char* name;
+ url_pattern_index::proto::ElementType maps_to_type;
+} kDeprecatedElementTypes[] = {
+ {"background", url_pattern_index::proto::ELEMENT_TYPE_IMAGE},
+ {"xbl", url_pattern_index::proto::ELEMENT_TYPE_OTHER},
+ {"dtd", url_pattern_index::proto::ELEMENT_TYPE_OTHER},
+};
+
+// A list of items mapping activation type options to their names.
+const struct {
+ url_pattern_index::proto::ActivationType type;
+ const char* name;
+} kActivationTypes[] = {
+ {url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT, "document"},
+ {url_pattern_index::proto::ACTIVATION_TYPE_ELEMHIDE, "elemhide"},
+ {url_pattern_index::proto::ACTIVATION_TYPE_GENERICHIDE, "generichide"},
+ {url_pattern_index::proto::ACTIVATION_TYPE_GENERICBLOCK, "genericblock"},
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_OPTIONS_H_
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule_parser.cc b/chromium/components/subresource_filter/tools/rule_parser/rule_parser.cc
new file mode 100644
index 00000000000..47e9590d170
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule_parser.cc
@@ -0,0 +1,478 @@
+// 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 "components/subresource_filter/tools/rule_parser/rule_parser.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "components/subresource_filter/tools/rule_parser/rule_options.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Encapsulates meta-information of URL rule options identified by keywords.
+class KeywordMap {
+ public:
+ // Types of rule options that can be represented by keywords.
+ enum OptionType {
+ OPTION_UNDEFINED,
+ OPTION_ELEMENT_TYPE,
+ OPTION_ACTIVATION_TYPE,
+ OPTION_THIRD_PARTY,
+ OPTION_DOMAIN,
+ OPTION_SITEKEY,
+ OPTION_MATCH_CASE,
+ OPTION_COLLAPSE,
+ OPTION_DO_NOT_TRACK,
+ };
+
+ enum OptionFlag : int {
+ FLAG_NONE = 0,
+ // The option requires a value, e.g. 'domain=example.org'.
+ FLAG_REQUIRES_VALUE = 1,
+ // The option allows invertion, e.g. 'image' and '~image'.
+ FLAG_IS_TRISTATE = 2,
+ // The option can be used with whitelist rules only.
+ FLAG_IS_WHITELIST_ONLY = 4,
+ // The option is not supposed to be used any more.
+ FLAG_IS_DEPRECATED = 8,
+ // The option is not supported yet.
+ FLAG_IS_NOT_SUPPORTED = 16,
+ };
+
+ // Meta-information about an option represented by a certain keyword.
+ struct OptionDetails {
+ // Creates an option that defines a filter for the specified |element_type|.
+ // In addition to the provided |flags|, FLAG_IS_TRISTATE will always be set
+ // by default.
+ OptionDetails(url_pattern_index::proto::ElementType element_type, int flags)
+ : type(OPTION_ELEMENT_TYPE),
+ flags(FLAG_IS_TRISTATE | flags),
+ element_type(element_type) {}
+
+ // Creates an ActivationType option.
+ explicit OptionDetails(
+ url_pattern_index::proto::ActivationType activation_type)
+ : type(OPTION_ACTIVATION_TYPE),
+ flags(FLAG_IS_WHITELIST_ONLY),
+ activation_type(activation_type) {}
+
+ // Creates a generic option.
+ OptionDetails(OptionType type, int flags) : type(type), flags(flags) {
+ DCHECK_NE(type, OPTION_ELEMENT_TYPE);
+ DCHECK_NE(type, OPTION_ACTIVATION_TYPE);
+ }
+
+ bool requires_value() const { return flags & FLAG_REQUIRES_VALUE; }
+ bool is_tristate() const { return flags & FLAG_IS_TRISTATE; }
+ bool is_whitelist_only() const { return flags & FLAG_IS_WHITELIST_ONLY; }
+ bool is_deprecated() const { return flags & FLAG_IS_DEPRECATED; }
+ bool is_not_supported() const { return flags & FLAG_IS_NOT_SUPPORTED; }
+
+ OptionType type = OPTION_UNDEFINED;
+
+ // Stores various OptionFlag's combined using bitwise OR.
+ int flags = FLAG_NONE;
+
+ // The element type that this option defines a filter for, if any. Set to
+ // ELEMENT_TYPE_UNSPECIFIED for non-ElementType options.
+ url_pattern_index::proto::ElementType element_type =
+ url_pattern_index::proto::ELEMENT_TYPE_UNSPECIFIED;
+
+ // The activation type that this option includes to the rule. Set to
+ // ACTIVATION_TYPE_UNSPECIFIED for non-ActivationType options.
+ url_pattern_index::proto::ActivationType activation_type =
+ url_pattern_index::proto::ACTIVATION_TYPE_UNSPECIFIED;
+ };
+
+ // Initializes the map with default keywords.
+ KeywordMap();
+ ~KeywordMap();
+
+ // Returns detailed information associated with the provided |name| option.
+ // Returns nullptr on unknown options.
+ const OptionDetails* Lookup(base::StringPiece name) const;
+
+ private:
+ // Associates |details| with a specified option |name|.
+ void AddOption(base::StringPiece name, const OptionDetails& details);
+
+ std::map<std::string, OptionDetails> options_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeywordMap);
+};
+
+KeywordMap::KeywordMap() {
+ // ElementType options.
+ for (const auto& element_type : kElementTypes) {
+ OptionDetails details(element_type.type, FLAG_NONE);
+ AddOption(element_type.name, details);
+ }
+ // Deprecated ElementType options.
+ for (const auto& element_type : kDeprecatedElementTypes) {
+ OptionDetails details(element_type.maps_to_type, FLAG_IS_DEPRECATED);
+ AddOption(element_type.name, details);
+ }
+
+ // ActivationType options.
+ for (const auto& activation_type : kActivationTypes) {
+ OptionDetails details(activation_type.type);
+ AddOption(activation_type.name, details);
+ }
+
+ // TODO(pkalinnikov): Consider moving options metadata to a header.
+ struct {
+ const char* name;
+ OptionType type;
+ int flags;
+ } const options[] = {
+ // Tristate options.
+ {"third-party", OPTION_THIRD_PARTY, FLAG_IS_TRISTATE},
+ {"collapse", OPTION_COLLAPSE, FLAG_IS_TRISTATE | FLAG_IS_NOT_SUPPORTED},
+ // Flag options.
+ {"match-case", OPTION_MATCH_CASE, FLAG_NONE},
+ {"donottrack", OPTION_DO_NOT_TRACK, FLAG_IS_NOT_SUPPORTED},
+ // Value options.
+ {"sitekey", OPTION_SITEKEY, FLAG_REQUIRES_VALUE | FLAG_IS_NOT_SUPPORTED},
+ {"domain", OPTION_DOMAIN, FLAG_REQUIRES_VALUE},
+ };
+
+ for (const auto& option : options) {
+ AddOption(option.name, OptionDetails(option.type, option.flags));
+ }
+}
+
+KeywordMap::~KeywordMap() = default;
+
+const KeywordMap::OptionDetails* KeywordMap::Lookup(
+ base::StringPiece name) const {
+ // TODO(pkalinnikov): Avoid std::string allocation.
+ auto iterator = options_.find(std::string(name));
+ return iterator != options_.end() ? &iterator->second : nullptr;
+}
+
+void KeywordMap::AddOption(base::StringPiece name,
+ const OptionDetails& details) {
+ auto inserted = options_.insert(std::make_pair(std::string(name), details));
+ DCHECK(inserted.second);
+}
+
+KeywordMap* GetKeywordsMapSingleton() {
+ // TODO(melandory): Get rid of this singleton.
+ static auto* shared_keywords = new KeywordMap;
+ return shared_keywords;
+}
+
+} // namespace
+
+// RuleParser ------------------------------------------------------------------
+
+RuleParser::ParseError::ParseError() = default;
+RuleParser::ParseError::~ParseError() = default;
+
+RuleParser::RuleParser() = default;
+RuleParser::~RuleParser() = default;
+
+const char* RuleParser::GetParseErrorCodeDescription(
+ ParseError::ErrorCode code) {
+ switch (code) {
+ case ParseError::NONE:
+ return "Ok";
+ case ParseError::EMPTY_RULE:
+ return "The rule is empty";
+ case ParseError::BAD_WHITELIST_SYNTAX:
+ return "Wrong whitelist rule syntax";
+ case ParseError::UNKNOWN_OPTION:
+ return "Unknown URL rule option";
+ case ParseError::NOT_A_TRISTATE_OPTION:
+ return "Unexpected '~', the option is not invertable";
+ case ParseError::DEPRECATED_OPTION:
+ return "The option is deprecated";
+ case ParseError::WHITELIST_ONLY_OPTION:
+ return "The option can be used with whitelist rules only";
+ case ParseError::NO_VALUE_PROVIDED:
+ return "Expected '=', the option requires a value";
+ case ParseError::WRONG_CSS_RULE_DELIM:
+ return "Wrong CSS rule delimiter";
+ case ParseError::EMPTY_CSS_SELECTOR:
+ return "Expected non-empty CSS selector";
+ case ParseError::UNSUPPORTED_FEATURE:
+ return "The feature is not currently supported";
+ default:
+ return "Unknown error";
+ }
+}
+
+// TODO(pkalinnikov): Refactor parsing approach to use a FSM.
+RuleType RuleParser::Parse(base::StringPiece line) {
+ rule_type_ = url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ parse_error_ = ParseError();
+
+ // Strip all leading and trailing whitespaces.
+ base::StringPiece part = line;
+ part = base::TrimWhitespaceASCII(part, base::TRIM_ALL);
+ // Check whether it's a trivial rule.
+ if (part.empty()) {
+ // Note: cannot use part.data() here because it is flaky to rely on *which*
+ // empty StringPiece StripWhitespace will return.
+ SetParseError(ParseError::EMPTY_RULE, line, line.data());
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ }
+
+ // Check whether it's a comment.
+ // TODO(pkalinnikov): Handle special comments (e.g. 'Title', 'Expires' etc.).
+ if (part[0] == '!' || part[0] == '[') {
+ return rule_type_ = url_pattern_index::proto::RULE_TYPE_COMMENT;
+ }
+
+ // Suppose it is a CSS rule if a CSS-selector separator character ('#') is
+ // present, followed by '#' or '@'.
+ size_t css_separator_pos = part.find('#');
+ for (; css_separator_pos != base::StringPiece::npos;
+ css_separator_pos = part.find('#', css_separator_pos + 1)) {
+ if (css_separator_pos + 1 == part.size()) {
+ css_separator_pos = base::StringPiece::npos;
+ break;
+ }
+ const char next_char = part[css_separator_pos + 1];
+ if (next_char == '#' || next_char == '@') // CSS rule starter.
+ break;
+ }
+
+ if (css_separator_pos != base::StringPiece::npos) {
+ return rule_type_ = ParseCssRule(line, part, css_separator_pos);
+ }
+ // Else assume we read a URL filtering rule.
+ return rule_type_ = ParseUrlRule(line, part);
+}
+
+RuleType RuleParser::ParseUrlRule(base::StringPiece origin,
+ base::StringPiece part) {
+ CHECK(!part.empty() && part.data() >= origin.data());
+ url_rule_ = UrlRule();
+
+ // Check whether it's a whitelist rule.
+ if (part[0] == '@') {
+ part.remove_prefix(1);
+ if (part.empty() || part[0] != '@') {
+ SetParseError(ParseError::BAD_WHITELIST_SYNTAX, origin, part.data());
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ }
+ part.remove_prefix(1);
+ url_rule_.is_whitelist = true;
+ }
+
+ size_t options_start = part.rfind('$');
+ // If the URL pattern is a regular expression, |options_start| might be
+ // pointing to a character inside the pattern. This can happen for those rules
+ // which don't have options at all, e.g., "/.*substring$/". All such rules end
+ // with '/', therefore the following code can detect them to work around.
+ if (options_start != base::StringPiece::npos && part.back() == '/')
+ options_start = base::StringPiece::npos;
+
+ if (options_start != base::StringPiece::npos) {
+ const base::StringPiece options = part.substr(options_start + 1);
+ if (!ParseUrlRuleOptions(origin, options))
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ part.remove_suffix(part.size() - options_start);
+ }
+
+ // Check for a left anchor.
+ if (!part.empty() && part[0] == '|') {
+ part.remove_prefix(1);
+ if (!part.empty() && part[0] == '|') {
+ part.remove_prefix(1);
+ url_rule_.anchor_left = url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN;
+ } else {
+ url_rule_.anchor_left = url_pattern_index::proto::ANCHOR_TYPE_BOUNDARY;
+ }
+ }
+
+ // Check for a right anchor.
+ if (!part.empty()) {
+ if (part[part.size() - 1] == '|') {
+ part.remove_suffix(1);
+ url_rule_.anchor_right = url_pattern_index::proto::ANCHOR_TYPE_BOUNDARY;
+ }
+ }
+
+ url_rule_.url_pattern = std::string(part);
+ url_rule_.Canonicalize();
+
+ return url_pattern_index::proto::RULE_TYPE_URL;
+}
+
+bool RuleParser::ParseUrlRuleOptions(base::StringPiece origin,
+ base::StringPiece options) {
+ CHECK_GE(options.data(), origin.data());
+
+ bool has_seen_element_or_activation_type = false;
+ for (base::StringPiece piece : base::SplitStringPiece(
+ options, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+ DCHECK(!piece.empty());
+
+ TriState tri_state = TriState::YES;
+ if (base::StartsWith(piece, "~", base::CompareCase::SENSITIVE)) {
+ piece.remove_prefix(1);
+ tri_state = TriState::NO;
+ }
+
+ size_t option_name_end = piece.find('=');
+ base::StringPiece option_name = piece.substr(0, option_name_end);
+
+ const auto* option_details = GetKeywordsMapSingleton()->Lookup(option_name);
+ if (!option_details) {
+ // TODO(pkalinnikov): Add a flag to RuleParser allowing unknown options.
+ SetParseError(ParseError::UNKNOWN_OPTION, origin, option_name.data());
+ return false;
+ }
+
+ if (tri_state == TriState::NO && !option_details->is_tristate()) {
+ SetParseError(ParseError::NOT_A_TRISTATE_OPTION, origin,
+ option_name.data());
+ return false;
+ }
+
+ if (option_details->requires_value() &&
+ option_name_end == base::StringPiece::npos) {
+ SetParseError(ParseError::NO_VALUE_PROVIDED, origin, option_name.data());
+ return false;
+ }
+
+ if (option_details->is_whitelist_only() && !url_rule_.is_whitelist) {
+ SetParseError(ParseError::WHITELIST_ONLY_OPTION, origin,
+ option_name.data());
+ return false;
+ }
+
+ if (option_details->is_deprecated()) {
+ // TODO(pkalinnikov): Add a flag to RuleParser allowing deprecated
+ // options (and issuing kind of a warning).
+ SetParseError(ParseError::DEPRECATED_OPTION, origin, option_name.data());
+ return false;
+ }
+
+ if (option_details->is_not_supported()) {
+ // TODO(pkalinnikov): Add a flag to RuleParser allowing unsupported
+ // features.
+ SetParseError(ParseError::UNSUPPORTED_FEATURE, origin,
+ option_name.data());
+ return false;
+ }
+
+ switch (option_details->type) {
+ case KeywordMap::OPTION_ELEMENT_TYPE: {
+ // The sign of the first element type option encountered determines
+ // whether the unspecified element types will be included (if the first
+ // option is negated) or excluded (otherwise).
+ if (tri_state == TriState::YES) {
+ // TODO(pkalinnikov): How about not resetting ActivationType options?
+ if (!has_seen_element_or_activation_type)
+ url_rule_.type_mask = 0;
+ url_rule_.type_mask |= type_mask_for(option_details->element_type);
+ } else {
+ DCHECK(tri_state == TriState::NO);
+ url_rule_.type_mask &= ~type_mask_for(option_details->element_type);
+ }
+ has_seen_element_or_activation_type = true;
+ break;
+ }
+ case KeywordMap::OPTION_ACTIVATION_TYPE:
+ if (!has_seen_element_or_activation_type)
+ url_rule_.type_mask = 0;
+ url_rule_.type_mask |= type_mask_for(option_details->activation_type);
+ has_seen_element_or_activation_type = true;
+ break;
+ case KeywordMap::OPTION_THIRD_PARTY:
+ url_rule_.is_third_party = tri_state;
+ break;
+ case KeywordMap::OPTION_MATCH_CASE:
+ url_rule_.match_case = true;
+ break;
+ case KeywordMap::OPTION_DOMAIN:
+ url_rule_.domains =
+ base::SplitString(piece.substr(option_name_end + 1), "|",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ break;
+ default:
+ LOG(FATAL);
+ }
+ }
+
+ return true;
+}
+
+RuleType RuleParser::ParseCssRule(base::StringPiece origin,
+ base::StringPiece part,
+ size_t css_section_start) {
+ CHECK(part.data() >= origin.data());
+ css_rule_ = CssRule();
+
+ // Check for a list of domains.
+ if (css_section_start) {
+ DCHECK(css_section_start != base::StringPiece::npos);
+ auto pieces = base::SplitStringPiece(part.substr(0, css_section_start), ",",
+ base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY);
+ for (base::StringPiece domain : pieces) {
+ DCHECK(!domain.empty());
+ css_rule_.domains.push_back(std::string(domain));
+ }
+ }
+
+ part.remove_prefix(css_section_start + 1);
+ if (part.empty()) {
+ SetParseError(ParseError::WRONG_CSS_RULE_DELIM, origin, part.data());
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ }
+ if (part[0] == '@') {
+ css_rule_.is_whitelist = true;
+ part.remove_prefix(1);
+ }
+ if (part.empty() || part[0] != '#') {
+ SetParseError(ParseError::WRONG_CSS_RULE_DELIM, origin, part.data());
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ }
+ part.remove_prefix(1);
+
+ if (part.empty()) {
+ SetParseError(ParseError::EMPTY_CSS_SELECTOR, origin, part.data());
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ }
+
+ css_rule_.css_selector = std::string(part);
+ css_rule_.Canonicalize();
+ return url_pattern_index::proto::RULE_TYPE_CSS;
+}
+
+void RuleParser::SetParseError(ParseError::ErrorCode code,
+ base::StringPiece origin,
+ const char* error_begin) {
+ DCHECK(code != ParseError::NONE);
+ DCHECK(error_begin >= origin.data());
+
+ parse_error_.error_code = code;
+ parse_error_.line = std::string(origin);
+ parse_error_.error_index = error_begin - origin.data();
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const RuleParser::ParseError& error) {
+ if (error.error_code != RuleParser::ParseError::NONE) {
+ out << "(error:" << error.error_index + 1 << ") "
+ << RuleParser::GetParseErrorCodeDescription(error.error_code) << ":\n"
+ << error.line << '\n'
+ << std::string(error.error_index, ' ') << "^\n";
+ }
+ return out;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule_parser.h b/chromium/components/subresource_filter/tools/rule_parser/rule_parser.h
new file mode 100644
index 00000000000..75c6b673e4f
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule_parser.h
@@ -0,0 +1,133 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_PARSER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_PARSER_H_
+
+#include <stddef.h>
+#include <ostream>
+#include <string>
+
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/tools/rule_parser/rule.h"
+
+namespace subresource_filter {
+
+// A parser of EasyList rules. It is intended to be (re-)used for parsing
+// multiple rules.
+// TODO(pkalinnikov): Support 'sitekey', 'collapse', and 'donottrack' options.
+class RuleParser {
+ public:
+ // Detailed information about a parse error (if any).
+ struct ParseError {
+ // Indicates the type of an error occured during a Parse(...) call.
+ enum ErrorCode {
+ NONE, // Parsing was successful.
+
+ EMPTY_RULE, // The parsed line does not contain any rule.
+ BAD_WHITELIST_SYNTAX, // Used wrong sytnax for a whitelist rule.
+ UNKNOWN_OPTION, // Using of unknown option in a URL rule.
+ NOT_A_TRISTATE_OPTION, // Used negation for a non-tristate option.
+ DEPRECATED_OPTION, // Used a deprecated option.
+ WHITELIST_ONLY_OPTION, // The option applies to whitelist rules only.
+ NO_VALUE_PROVIDED, // A valued option is used without a value.
+
+ WRONG_CSS_RULE_DELIM, // Using of a wrong delimiter in a CSS rule.
+ EMPTY_CSS_SELECTOR, // No CSS selector specified in a CSS rule.
+
+ UNSUPPORTED_FEATURE, // Using not currently supported EasyList feature.
+ };
+
+ // TODO(pkalinnikov): Introduce warnings for, e.g., using an inverted
+ // "document" activation type, using unsupported option, etc. This would let
+ // a client have a best-effort version of the rule. Leave it up to clients
+ // to decide what warnings/errors are critical for them.
+
+ // Constructs a ParseError in a default (no error) state.
+ ParseError();
+ ~ParseError();
+
+ ErrorCode error_code = NONE;
+
+ // A copy of the parsed line. If no error occurred, it is empty.
+ std::string line;
+
+ // Position of the character in the |line| that introduced the error. If
+ // |error_code| != NONE, then 0 <= |error_index| <= line.size(), otherwise
+ // |error_index| == std::string::npos.
+ size_t error_index = std::string::npos;
+ };
+
+ RuleParser();
+ ~RuleParser();
+
+ // Returns a human-readable detailed explanation of a parsing error.
+ static const char* GetParseErrorCodeDescription(ParseError::ErrorCode code);
+
+ // Parses a rule from the |line|. Returns the type of the rule parsed, or
+ // RULE_TYPE_UNSPECIFIED on error. Notes:
+ // - When parsing a URL rule, URL syntax is not verified.
+ // - When parsing a CSS rule, the CSS selector syntax is not verified.
+ RuleType Parse(base::StringPiece line);
+
+ // Returns error diagnostics on the latest parsed line.
+ const ParseError& parse_error() const { return parse_error_; }
+
+ // Gets the last parsed rule type. It is guaranteed to return the same value
+ // as the last Parse(...) invocation, or RULE_TYPE_UNSPECIFIED if no calls
+ // were done.
+ RuleType rule_type() const { return rule_type_; }
+
+ // Gets the last parsed URL filtering rule. The result is undefined if
+ // rule_type() != RULE_TYPE_URL,
+ const UrlRule& url_rule() const { return url_rule_; }
+
+ // Gets the last parsed CSS element hiding rule. The result is undefined if
+ // rule_type() != RULE_TYPE_CSS.
+ const CssRule& css_rule() const { return css_rule_; }
+
+ private:
+ // Parses the |part| and saves parsed URL filtering rule to the |url_rule_|
+ // member. |origin| is used for a proper error reporting. Returns
+ // RULE_TYPE_URL ff the |part| is a well-formed URL rule. Otherwise returns
+ // RULE_TYPE_UNSPECIFIED and sets |parse_error_|.
+ RuleType ParseUrlRule(base::StringPiece origin, base::StringPiece part);
+
+ // Parses the |options| segment of a URL filtering rule and saves the parsed
+ // options to the |url_rule_| member. Returns true if the options were parsed
+ // correctly. Otherwise sets an error in |parse_error_| and returns false.
+ bool ParseUrlRuleOptions(base::StringPiece origin, base::StringPiece options);
+
+ // Parses the |part| and saves parsed CSS rule to the |css_rule_| member.
+ // |css_section_start| denotes a position of '#' in the |part|, used to
+ // separate a CSS selector. Returns true iff the line is a well-formed CSS
+ // rule. Sets |parse_error_| on error.
+ RuleType ParseCssRule(base::StringPiece origin,
+ base::StringPiece part,
+ size_t css_section_start);
+
+ // Sets |parse_error_| to contain specific error, starting at |error_begin|.
+ void SetParseError(ParseError::ErrorCode code,
+ base::StringPiece origin,
+ const char* error_begin);
+
+ ParseError parse_error_;
+ RuleType rule_type_;
+ UrlRule url_rule_;
+ CssRule css_rule_;
+
+ DISALLOW_COPY_AND_ASSIGN(RuleParser);
+};
+
+// Pretty-prints the parsing |error| to |out|, e.g. like this:
+// (error:22) Unknown URL rule option:
+// @@example.org$script,unknown_option
+// ^
+std::ostream& operator<<(std::ostream& out,
+ const RuleParser::ParseError& error);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULE_PARSER_RULE_PARSER_H_
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule_parser_unittest.cc b/chromium/components/subresource_filter/tools/rule_parser/rule_parser_unittest.cc
new file mode 100644
index 00000000000..e5282d76a99
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule_parser_unittest.cc
@@ -0,0 +1,392 @@
+// 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 "components/subresource_filter/tools/rule_parser/rule_parser.h"
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "components/subresource_filter/tools/rule_parser/rule.h"
+#include "components/subresource_filter/tools/rule_parser/rule_options.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+void ParseAndExpectUrlRule(base::StringPiece line,
+ const UrlRule& expected_rule) {
+ UrlRule canonicalized_rule = expected_rule;
+ canonicalized_rule.Canonicalize();
+
+ RuleParser parser;
+ EXPECT_NE(url_pattern_index::proto::RULE_TYPE_UNSPECIFIED,
+ parser.Parse(line));
+ EXPECT_EQ(RuleParser::ParseError::NONE, parser.parse_error().error_code);
+ EXPECT_TRUE(parser.parse_error().line.empty());
+ EXPECT_EQ(std::string::npos, parser.parse_error().error_index);
+
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_URL, parser.rule_type());
+ EXPECT_EQ(canonicalized_rule, parser.url_rule());
+}
+
+void ParseAndExpectCssRule(base::StringPiece line,
+ const CssRule& expected_rule) {
+ CssRule canonicalized_rule = expected_rule;
+ canonicalized_rule.Canonicalize();
+
+ RuleParser parser;
+ EXPECT_NE(url_pattern_index::proto::RULE_TYPE_UNSPECIFIED,
+ parser.Parse(line));
+ EXPECT_EQ(RuleParser::ParseError::NONE, parser.parse_error().error_code);
+ EXPECT_TRUE(parser.parse_error().line.empty());
+ EXPECT_EQ(std::string::npos, parser.parse_error().error_index);
+
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_CSS, parser.rule_type());
+ EXPECT_EQ(canonicalized_rule, parser.css_rule());
+}
+
+} // namespace
+
+TEST(RuleParserTest, ParseComment) {
+ RuleParser parser;
+
+ static const char* kLines[] = {
+ "! this is a comment", " ! this is a comment too", "[ and this",
+ " [ as well as this",
+ };
+
+ for (const char* line : kLines) {
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_COMMENT, parser.Parse(line));
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_COMMENT, parser.rule_type());
+ }
+}
+
+TEST(RuleParserTest, ParseUrlRule) {
+ static const char* kLine = "?param=";
+ UrlRule expected_rule;
+ expected_rule.url_pattern = kLine;
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+
+ ParseAndExpectUrlRule(kLine, expected_rule);
+}
+
+TEST(RuleParserTest, UrlRuleMatchCase) {
+ const struct {
+ const char* line;
+ bool expected_match_case;
+ } kTestCases[] = {
+ {"example.com$image", false}, {"example.com$image,match-case", true},
+ };
+ RuleParser parser;
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << test_case.line);
+ ASSERT_EQ(url_pattern_index::proto::RULE_TYPE_URL,
+ parser.Parse(test_case.line));
+ EXPECT_EQ(test_case.expected_match_case, parser.url_rule().match_case);
+ }
+}
+
+TEST(RuleParserTest, ParseWhitelistUrlRule) {
+ static const char* kLine = "@@?param=";
+ UrlRule expected_rule;
+ expected_rule.is_whitelist = true;
+ expected_rule.url_pattern = kLine + 2;
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+
+ ParseAndExpectUrlRule(kLine, expected_rule);
+}
+
+TEST(RuleParserTest, ParseEmptyOptions) {
+ static const char* kLine = "&param=value$";
+ UrlRule expected_rule;
+ expected_rule.url_pattern.assign(kLine, strlen(kLine) - 1);
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+
+ ParseAndExpectUrlRule(kLine, expected_rule);
+}
+
+TEST(RuleParserTest, ParseSingleTypeOptions) {
+ static const std::string kRulePrefix = "?param=$";
+ for (const auto& type_info : kElementTypes) {
+ UrlRule expected_rule;
+ expected_rule.url_pattern = "?param=";
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ expected_rule.type_mask = type_mask_for(type_info.type);
+
+ ParseAndExpectUrlRule(kRulePrefix + type_info.name, expected_rule);
+ }
+}
+
+TEST(RuleParserTest, ParseSingleInverseTypeOptions) {
+ static const std::string kRulePrefix = "?param=$";
+
+ for (const auto& type_info : kElementTypes) {
+ UrlRule expected_rule;
+ expected_rule.url_pattern = "?param=";
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ expected_rule.type_mask = type_mask_for(type_info.type);
+
+ ParseAndExpectUrlRule(kRulePrefix + type_info.name, expected_rule);
+ }
+}
+
+TEST(RuleParserTest, ParseMultipleTypeOptions) {
+ static const char* kLine = "?param=$script,image,~stylesheet";
+
+ UrlRule expected_rule;
+ expected_rule.url_pattern = "?param=";
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ expected_rule.type_mask =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_SCRIPT) |
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_IMAGE);
+
+ ParseAndExpectUrlRule(kLine, expected_rule);
+}
+
+TEST(RuleParserTest, ParseContradictingTypeOptions) {
+ static const char* kLines[2] = {
+ "?param=$image,~image", "?param=$popup,image,~image",
+ };
+
+ for (size_t i = 0; i < 2; ++i) {
+ UrlRule expected_rule;
+ expected_rule.url_pattern = "?param=";
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ expected_rule.type_mask = 0;
+ if (i == 1) {
+ expected_rule.type_mask |=
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_POPUP);
+ }
+ ParseAndExpectUrlRule(kLines[i], expected_rule);
+ }
+}
+
+TEST(RuleParserTest, ParseUrlRuleOptions) {
+ static const char* kLine =
+ "?param=$popup,match-case,domain=example1.com|example2.org,~third-party";
+
+ UrlRule expected_rule;
+ expected_rule.url_pattern = "?param=";
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ expected_rule.match_case = true;
+ expected_rule.type_mask =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_POPUP);
+ expected_rule.is_third_party = TriState::NO;
+ expected_rule.domains.push_back("example1.com");
+ expected_rule.domains.push_back("example2.org");
+
+ ParseAndExpectUrlRule(kLine, expected_rule);
+}
+
+TEST(RuleParserTest, ParseUrlRuleAnchors) {
+ const std::string kLine = "example.com";
+ static const struct {
+ AnchorType type;
+ const char* literal;
+ } kAnchors[] = {
+ {url_pattern_index::proto::ANCHOR_TYPE_NONE, ""},
+ {url_pattern_index::proto::ANCHOR_TYPE_BOUNDARY, "|"},
+ {url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN, "||"},
+ };
+
+ for (const auto& left_anchor : kAnchors) {
+ UrlRule expected_rule;
+ expected_rule.url_pattern = kLine;
+ expected_rule.anchor_left = left_anchor.type;
+
+ for (const auto& right_anchor : kAnchors) {
+ if (right_anchor.type == url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN)
+ continue;
+ expected_rule.anchor_right = right_anchor.type;
+ std::string line = left_anchor.literal + kLine + right_anchor.literal;
+ if (left_anchor.type != url_pattern_index::proto::ANCHOR_TYPE_NONE ||
+ right_anchor.type != url_pattern_index::proto::ANCHOR_TYPE_NONE) {
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_WILDCARDED;
+ } else {
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING;
+ }
+ ParseAndExpectUrlRule(line, expected_rule);
+ }
+ }
+}
+
+TEST(RuleParserTest, ParseUrlRuleWithBookmark) {
+ static const char* kLine = "@@example.com^*#-$image";
+ UrlRule expected_rule;
+ expected_rule.is_whitelist = true;
+ expected_rule.type_mask =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_IMAGE);
+ expected_rule.url_pattern = "example.com^*#-";
+ expected_rule.url_pattern_type =
+ url_pattern_index::proto::URL_PATTERN_TYPE_WILDCARDED;
+
+ ParseAndExpectUrlRule(kLine, expected_rule);
+}
+
+TEST(RuleParserTest, ParseUrlRuleWithElementAndActivationTypes) {
+ constexpr auto kImage =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_IMAGE);
+ constexpr auto kFont =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_FONT);
+ constexpr auto kScript =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_SCRIPT);
+ constexpr auto kPopup =
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_POPUP);
+ constexpr auto kDocument =
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT);
+ constexpr auto kGenericBlock =
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_GENERICBLOCK);
+
+ const struct {
+ const char* rule;
+ TypeMask expected_type_mask;
+ } kTestCases[] = {
+ {"ex.com", kDefaultElementTypes},
+ {"ex.com$", kDefaultElementTypes},
+ {"ex.com$popup", kPopup},
+ {"ex.com$~popup", kDefaultElementTypes},
+ {"ex.com$image", kImage},
+ {"ex.com$~image", kDefaultElementTypes & ~kImage},
+ {"ex.com$image,font", kImage | kFont},
+ {"ex.com$image,popup", kImage | kPopup},
+ {"ex.com$~font,~script", kDefaultElementTypes & ~kFont & ~kScript},
+ {"ex.com$subdocument,~subdocument", 0},
+ {"@@ex.com$document", kDocument},
+ {"@@ex.com$document,genericblock", kDocument | kGenericBlock},
+ {"@@ex.com$document,image", kDocument | kImage},
+ {"@@ex.com$document,image,popup", kDocument | kImage | kPopup},
+ {"@@ex.com$document,~image", kDocument},
+ {"@@ex.com$~image,document",
+ (kDefaultElementTypes & ~kImage) | kDocument},
+ };
+
+ RuleParser parser;
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << test_case.rule);
+ ASSERT_EQ(url_pattern_index::proto::RULE_TYPE_URL,
+ parser.Parse(test_case.rule));
+ EXPECT_EQ(test_case.expected_type_mask, parser.url_rule().type_mask);
+ }
+}
+
+TEST(RuleParserTest, ParseUrlRuleWithRegexp) {
+ const struct {
+ const char* line;
+ const char* expected_url_pattern;
+ } kTestCases[] = {
+ {"/.*substring.*/", "/.*substring.*/"},
+ {"/.*substring$/", "/.*substring$/"},
+ {"/.*substring.*/$image", "/.*substring.*/"},
+ {"/.*[$#].*/$image", "/.*[$#].*/"},
+ {"/.*$script/$image", "/.*$script/"},
+ {"@@/^.*$/$script,domain=example.com", "/^.*$/"},
+ };
+
+ for (const auto& test : kTestCases) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << test.line);
+
+ RuleParser parser;
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_URL, parser.Parse(test.line));
+ EXPECT_EQ(url_pattern_index::proto::URL_PATTERN_TYPE_REGEXP,
+ parser.url_rule().url_pattern_type);
+ EXPECT_EQ(test.expected_url_pattern, parser.url_rule().url_pattern);
+ }
+}
+
+TEST(RuleParserTest, ParseCssRules) {
+ static const std::string kCssSelector = "div.blocked_class";
+ static const std::string kTestDomain = "example.com";
+ static const std::string kTestSubDomain = "however.example.com";
+
+ CssRule expected_rule;
+ expected_rule.css_selector = kCssSelector;
+
+ ParseAndExpectCssRule("##" + kCssSelector, expected_rule);
+ ParseAndExpectCssRule(" ##" + kCssSelector, expected_rule);
+ ParseAndExpectCssRule(" \t\t##" + kCssSelector, expected_rule);
+
+ expected_rule.domains.push_back(kTestDomain);
+ ParseAndExpectCssRule(kTestDomain + "##" + kCssSelector, expected_rule);
+
+ expected_rule.is_whitelist = true;
+ ParseAndExpectCssRule(kTestDomain + "#@#" + kCssSelector, expected_rule);
+
+ expected_rule.is_whitelist = false;
+ expected_rule.domains.push_back("~" + kTestSubDomain);
+ ParseAndExpectCssRule(
+ kTestDomain + ",~" + kTestSubDomain + "##" + kCssSelector, expected_rule);
+
+ expected_rule.is_whitelist = true;
+ ParseAndExpectCssRule(
+ kTestDomain + ",~" + kTestSubDomain + "#@#" + kCssSelector,
+ expected_rule);
+}
+
+TEST(RuleParserTest, ParseErrors) {
+ RuleParser parser;
+
+ struct {
+ const char* rule;
+ RuleParser::ParseError::ErrorCode expected_code;
+ size_t expected_index;
+ } kRulesAndExpectations[] = {
+ {"", RuleParser::ParseError::EMPTY_RULE, 0},
+ {" ", RuleParser::ParseError::EMPTY_RULE, 0},
+ {" \t ", RuleParser::ParseError::EMPTY_RULE, 0},
+ {"@", RuleParser::ParseError::BAD_WHITELIST_SYNTAX, 1},
+ {"@http://example.com", RuleParser::ParseError::BAD_WHITELIST_SYNTAX, 1},
+ {"?opt=$unknown_option", RuleParser::ParseError::UNKNOWN_OPTION, 6},
+ {"example.com$image,dtd", RuleParser::ParseError::DEPRECATED_OPTION, 18},
+ {"?opt=$elemhide", RuleParser::ParseError::WHITELIST_ONLY_OPTION, 6},
+ {"?opt=$generichide", RuleParser::ParseError::WHITELIST_ONLY_OPTION, 6},
+ {"?opt=$generblock", RuleParser::ParseError::WHITELIST_ONLY_OPTION, 6},
+ {"?opt=$~document", RuleParser::ParseError::WHITELIST_ONLY_OPTION, 7},
+ {"~host$sitekey=1", RuleParser::ParseError::UNSUPPORTED_FEATURE, 6},
+ {"?param=$~match-case", RuleParser::ParseError::NOT_A_TRISTATE_OPTION, 9},
+ {"?param=$domain", RuleParser::ParseError::NO_VALUE_PROVIDED, 8},
+ {"#@!", RuleParser::ParseError::WRONG_CSS_RULE_DELIM, 2},
+ {"#@#", RuleParser::ParseError::EMPTY_CSS_SELECTOR, 3},
+ {"example.com##", RuleParser::ParseError::EMPTY_CSS_SELECTOR, 13},
+ };
+
+ for (const auto& rule_and_expectation : kRulesAndExpectations) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << rule_and_expectation.rule);
+
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_UNSPECIFIED,
+ parser.Parse(rule_and_expectation.rule));
+ EXPECT_NE(RuleParser::ParseError::NONE, parser.parse_error().error_code);
+ EXPECT_EQ(rule_and_expectation.rule, parser.parse_error().line);
+ EXPECT_EQ(rule_and_expectation.expected_index,
+ parser.parse_error().error_index);
+ }
+}
+
+TEST(RuleParserTest, ParseNonEmptyUrlRuleWithEmptyUrlPattern) {
+ const std::string kRules[] = {
+ "|", "||", "|||", "@@", "@@|", "@@||", "@@|||", "$image", "@@|$image",
+ };
+
+ RuleParser parser;
+ for (const std::string& rule : kRules) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << rule);
+
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_URL, parser.Parse(rule));
+ EXPECT_TRUE(parser.url_rule().url_pattern.empty());
+ }
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/rule_parser/rule_unittest.cc b/chromium/components/subresource_filter/tools/rule_parser/rule_unittest.cc
new file mode 100644
index 00000000000..bb7b1e915b3
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/rule_parser/rule_unittest.cc
@@ -0,0 +1,187 @@
+// 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 "components/subresource_filter/tools/rule_parser/rule.h"
+
+#include <stddef.h>
+#include <memory>
+
+#include "components/subresource_filter/tools/rule_parser/rule_options.h"
+#include "components/subresource_filter/tools/rule_parser/rule_parser.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+constexpr auto kScript = url_pattern_index::proto::ELEMENT_TYPE_SCRIPT;
+constexpr auto kImage = url_pattern_index::proto::ELEMENT_TYPE_IMAGE;
+constexpr auto kPopup = url_pattern_index::proto::ELEMENT_TYPE_POPUP;
+constexpr auto kWebsocket = url_pattern_index::proto::ELEMENT_TYPE_WEBSOCKET;
+
+constexpr auto kAnchorNone = url_pattern_index::proto::ANCHOR_TYPE_NONE;
+
+} // namespace
+
+TEST(RuleTest, DefaultUrlRule) {
+ UrlRule rule;
+ EXPECT_TRUE(rule.url_pattern.empty());
+ EXPECT_EQ(url_pattern_index::proto::URL_PATTERN_TYPE_SUBSTRING,
+ rule.url_pattern_type);
+ EXPECT_FALSE(rule.match_case);
+ EXPECT_EQ(kAnchorNone, rule.anchor_left);
+ EXPECT_EQ(kAnchorNone, rule.anchor_right);
+ EXPECT_TRUE(rule.domains.empty());
+
+ EXPECT_TRUE(rule.type_mask &
+ type_mask_for(url_pattern_index::proto::ELEMENT_TYPE_OTHER));
+ EXPECT_TRUE(rule.type_mask & type_mask_for(kScript));
+ EXPECT_TRUE(rule.type_mask & type_mask_for(kImage));
+ EXPECT_FALSE(rule.type_mask & type_mask_for(kPopup));
+ EXPECT_TRUE(rule.type_mask & type_mask_for(kWebsocket));
+
+ EXPECT_FALSE(
+ rule.type_mask &
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT));
+ EXPECT_FALSE(
+ rule.type_mask &
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_ELEMHIDE));
+ EXPECT_FALSE(
+ rule.type_mask &
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_GENERICBLOCK));
+ EXPECT_FALSE(
+ rule.type_mask &
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_GENERICHIDE));
+}
+
+TEST(RuleTest, CanonicalizeUrlPattern) {
+ const struct {
+ const char* rule;
+ const char* expected_url_pattern;
+ AnchorType expected_anchor_left;
+ AnchorType expected_anchor_right;
+ } kTestCases[] = {
+ {"*/text/*", "/text/", kAnchorNone, kAnchorNone},
+ {"*/text", "/text", kAnchorNone, kAnchorNone},
+ {"text/*", "text/", kAnchorNone, kAnchorNone},
+ {"*te*xt*", "te*xt", kAnchorNone, kAnchorNone},
+ {"|*te*xt*", "te*xt", kAnchorNone,
+ url_pattern_index::proto::ANCHOR_TYPE_NONE},
+ {"*te*xt*|", "te*xt", kAnchorNone, kAnchorNone},
+ {"|*te*xt*|", "te*xt", kAnchorNone, kAnchorNone},
+ {"||*te*xt*", "*te*xt", url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN,
+ kAnchorNone},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ SCOPED_TRACE(testing::Message() << "Rule: " << test_case.rule);
+
+ RuleParser parser;
+ ASSERT_EQ(url_pattern_index::proto::RULE_TYPE_URL,
+ parser.Parse(test_case.rule));
+
+ const UrlRule& rule = parser.url_rule();
+ EXPECT_EQ(test_case.expected_url_pattern, rule.url_pattern);
+ EXPECT_EQ(test_case.expected_anchor_left, rule.anchor_left);
+ EXPECT_EQ(test_case.expected_anchor_right, rule.anchor_right);
+ }
+}
+
+TEST(RuleTest, CanonicalizeDomainList) {
+ static const size_t kMaxDomainsCount = 3;
+ static const char* const kTestCases[][kMaxDomainsCount] = {
+ {"a.com", "c.com", "b.com"},
+ {"a.com", "aa.aa.com", "long-example.com"},
+ {"~sub.ex1.com", "ex2.com", "ex1.com"},
+ {"example.com", "b.exmpl.com", "~a.b.example.com"},
+ {"~example.com", "b.example.com", "~a.b.example.com"},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ std::vector<std::string> domains;
+ size_t count = 0;
+ for (; count < kMaxDomainsCount && test_case[count]; ++count)
+ domains.push_back(test_case[count]);
+
+ CanonicalizeDomainList(&domains);
+ EXPECT_EQ(count, domains.size());
+ for (size_t i = 1; i < domains.size(); ++i) {
+ EXPECT_GE(domains[i - 1].size(), domains[i].size());
+ if (domains[i - 1].size() == domains[i].size())
+ EXPECT_LE(domains[i - 1], domains[i]);
+ }
+ }
+}
+
+TEST(RuleTest, UrlRuleToString) {
+ UrlRule rule;
+ rule.url_pattern = "domain*.example.com^";
+ rule.anchor_left = url_pattern_index::proto::ANCHOR_TYPE_SUBDOMAIN;
+ rule.url_pattern_type = url_pattern_index::proto::URL_PATTERN_TYPE_WILDCARDED;
+ rule.is_whitelist = true;
+ rule.is_third_party = TriState::NO;
+ rule.type_mask = kScript | kImage;
+ rule.domains = {"example.com", "~exception.example.com"};
+
+ EXPECT_EQ(
+ "@@||domain*.example.com^$script,image,~third-party,"
+ "domain=example.com|~exception.example.com",
+ ToString(rule.ToProtobuf()));
+
+ rule = UrlRule();
+ rule.url_pattern = "example.com";
+ rule.type_mask =
+ url_pattern_index::proto::ELEMENT_TYPE_ALL & ~kImage & ~kPopup;
+ EXPECT_EQ("example.com$~image", ToString(rule.ToProtobuf()));
+
+ rule.type_mask = url_pattern_index::proto::ELEMENT_TYPE_ALL & ~kPopup;
+ EXPECT_EQ("example.com", ToString(rule.ToProtobuf()));
+
+ rule.type_mask = url_pattern_index::proto::ELEMENT_TYPE_ALL & ~kImage;
+ EXPECT_EQ("example.com$~image,popup", ToString(rule.ToProtobuf()));
+
+ rule.type_mask = url_pattern_index::proto::ELEMENT_TYPE_ALL & ~kWebsocket;
+ EXPECT_EQ("example.com$~websocket,popup", ToString(rule.ToProtobuf()));
+
+ rule.type_mask = kPopup;
+ EXPECT_EQ("example.com$popup", ToString(rule.ToProtobuf()));
+
+ rule.type_mask = kPopup | kImage;
+ EXPECT_EQ("example.com$image,popup", ToString(rule.ToProtobuf()));
+
+ rule.type_mask = kPopup | kWebsocket;
+ EXPECT_EQ("example.com$websocket,popup", ToString(rule.ToProtobuf()));
+
+ rule.type_mask =
+ url_pattern_index::proto::ELEMENT_TYPE_SUBDOCUMENT |
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT);
+ EXPECT_EQ("example.com$subdocument,document", ToString(rule.ToProtobuf()));
+
+ rule.type_mask =
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT);
+ EXPECT_EQ("example.com$document", ToString(rule.ToProtobuf()));
+
+ rule.type_mask =
+ (url_pattern_index::proto::ELEMENT_TYPE_ALL & ~kImage & ~kPopup) |
+ type_mask_for(url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT);
+ EXPECT_EQ("example.com$~image,document", ToString(rule.ToProtobuf()));
+
+ // A workaround for when no type is specified. This is to avoid ambiguity with
+ // the pure "example.com" rule which targets a bunch of default element types.
+ rule.type_mask = 0;
+ EXPECT_EQ("example.com$image,~image", ToString(rule.ToProtobuf()));
+}
+
+TEST(RuleTest, CssRuleToString) {
+ CssRule rule;
+ rule.is_whitelist = true;
+ rule.domains = {"example.com", "~exception.example.com"};
+ rule.css_selector = "#example-id";
+
+ EXPECT_EQ("example.com,~exception.example.com#@##example-id",
+ ToString(rule.ToProtobuf()));
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/BUILD.gn b/chromium/components/subresource_filter/tools/ruleset_converter/BUILD.gn
new file mode 100644
index 00000000000..7ab3f2d412f
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/BUILD.gn
@@ -0,0 +1,42 @@
+# 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.
+
+source_set("support") {
+ sources = [
+ "//third_party/protobuf:protobuf_lite",
+ "rule_stream.cc",
+ "rule_stream.h",
+ "ruleset_converter.cc",
+ "ruleset_converter.h",
+ "ruleset_format.cc",
+ "ruleset_format.h",
+ ]
+ deps = [
+ "../rule_parser",
+ "//base",
+ "//components/subresource_filter/core/common",
+ "//components/url_pattern_index/proto:url_pattern_index",
+ "//third_party/protobuf:protobuf_lite",
+ ]
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "rule_stream_unittest.cc",
+ "ruleset_converter_unittest.cc",
+ "ruleset_test_util.cc",
+ "ruleset_test_util.h",
+ ]
+ deps = [
+ ":support",
+ "../rule_parser",
+ "//base",
+ "//base/test:test_support",
+ "//components/url_pattern_index:test_support",
+ "//components/url_pattern_index/proto:url_pattern_index",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/main.cc b/chromium/components/subresource_filter/tools/ruleset_converter/main.cc
new file mode 100644
index 00000000000..ed5dd4e2a91
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/main.cc
@@ -0,0 +1,117 @@
+// 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 "base/command_line.h"
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_converter.h"
+
+namespace {
+
+const char kSwitchInputFiles[] = "input_files";
+const char kSwitchOutputFile[] = "output_file";
+
+const char kSwitchOutputFileUrl[] = "output_file_url";
+const char kSwitchOutputFileCss[] = "output_file_css";
+
+const char kSwitchInputFormat[] = "input_format";
+const char kSwitchOutputFormat[] = "output_format";
+
+const char kSwitchChromeVersion[] = "chrome_version";
+
+const char kHelpMsg[] = R"(
+ ruleset_converter [--input_format=<format>] --output_format=<format>
+ --input_files=<path1>[:<path2>...]
+ (--output_file=<path> | [--output_file_url=<path>] [--output_file_css=<path>)
+ [--chrome_version=<version>]
+
+ ruleset_converter is a utility for converting subresource_filter rulesets
+ across multiple formats:
+
+ * --input_files: Comma-separated list of input files with rules. The files
+ are processed in the order of declaration
+
+ * --output_file: The file to output the rules. Either this option or at least
+ one of the --output_file_url|--output_file_css should be specified.
+
+ * --output_file_url: The file to output URL rules. If equal to
+ --output_file_css, the results are merged.
+
+ * --output_file_css: The file to output CSS rules. See --output_file and
+ --output_file_url for details.
+
+ * --input_format: The format of the input file(s). One of
+ {filter-list, proto, unindexed-ruleset}
+
+ * --output_format: The format of the output file(s). See --input_format for
+ available formats.
+
+ * --chrome_version: The earliest version of Chrome that the produced ruleset
+ needs to be compatible with. Currently one of 54, 59, or 0
+ (not Chrome-specific). Defaults to the maximum (i.e. 59).
+)";
+
+void PrintHelp() {
+ printf("%s\n\n", kHelpMsg);
+}
+
+} // namespace
+
+int main(int argc, char* argv[]) {
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess();
+
+ if (command_line.GetArgs().size() != 0U) {
+ PrintHelp();
+ return 1;
+ }
+
+ subresource_filter::RulesetConverter converter;
+ if (!converter.SetInputFiles(
+ command_line.GetSwitchValueNative(kSwitchInputFiles))) {
+ PrintHelp();
+ return 1;
+ }
+
+ if (command_line.HasSwitch(kSwitchOutputFile) &&
+ !converter.SetOutputFile(
+ command_line.GetSwitchValuePath(kSwitchOutputFile))) {
+ PrintHelp();
+ return 1;
+ }
+ if (command_line.HasSwitch(kSwitchOutputFileUrl) &&
+ !converter.SetOutputFileUrl(
+ command_line.GetSwitchValuePath(kSwitchOutputFileUrl))) {
+ PrintHelp();
+ return 1;
+ }
+ if (command_line.HasSwitch(kSwitchOutputFileCss) &&
+ !converter.SetOutputFileCss(
+ command_line.GetSwitchValuePath(kSwitchOutputFileCss))) {
+ PrintHelp();
+ return 1;
+ }
+
+ if (command_line.HasSwitch(kSwitchChromeVersion) &&
+ !converter.SetChromeVersion(
+ command_line.GetSwitchValueASCII(kSwitchChromeVersion))) {
+ PrintHelp();
+ return 1;
+ }
+
+ if (command_line.HasSwitch(kSwitchInputFormat) &&
+ !converter.SetInputFormat(
+ command_line.GetSwitchValueASCII(kSwitchInputFormat))) {
+ PrintHelp();
+ return 1;
+ }
+ if (command_line.HasSwitch(kSwitchOutputFormat) &&
+ !converter.SetOutputFormat(
+ command_line.GetSwitchValueASCII(kSwitchOutputFormat))) {
+ PrintHelp();
+ return 1;
+ }
+
+ if (!converter.Convert())
+ return 1;
+ return 0;
+}
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.cc b/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.cc
new file mode 100644
index 00000000000..86214195ed5
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.cc
@@ -0,0 +1,434 @@
+// 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 "components/subresource_filter/tools/ruleset_converter/rule_stream.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "components/subresource_filter/core/common/unindexed_ruleset.h"
+#include "components/subresource_filter/tools/rule_parser/rule.h"
+#include "components/subresource_filter/tools/rule_parser/rule_parser.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream_impl_lite.h"
+
+namespace subresource_filter {
+
+namespace {
+
+std::string ReadStreamToString(std::istream* input) {
+ return std::string(std::istreambuf_iterator<char>(*input), {});
+}
+
+bool IsTrivialParseError(const RuleParser::ParseError& error) {
+ return error.error_code == RuleParser::ParseError::NONE ||
+ error.error_code == RuleParser::ParseError::EMPTY_RULE;
+}
+
+// A helper class used by rule input streams for converting a FilteringRules
+// message into a stream.
+class ProtobufRuleInputStreamImpl {
+ public:
+ explicit ProtobufRuleInputStreamImpl(
+ const url_pattern_index::proto::FilteringRules& rules)
+ : rules_(rules) {}
+
+ url_pattern_index::proto::RuleType FetchNextRule() {
+ if (not_first_rule_)
+ ++rule_index_;
+ not_first_rule_ = true;
+
+ if (is_reading_url_rules_ && rule_index_ >= rules_.url_rules_size()) {
+ is_reading_url_rules_ = false;
+ rule_index_ = 0;
+ }
+ if (!is_reading_url_rules_ && rule_index_ >= rules_.css_rules_size())
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ return is_reading_url_rules_ ? url_pattern_index::proto::RULE_TYPE_URL
+ : url_pattern_index::proto::RULE_TYPE_CSS;
+ }
+
+ const url_pattern_index::proto::UrlRule& GetUrlRule() {
+ CHECK(is_reading_url_rules_ && rule_index_ < rules_.url_rules_size());
+ return rules_.url_rules(rule_index_);
+ }
+
+ const url_pattern_index::proto::CssRule& GetCssRule() {
+ CHECK(!is_reading_url_rules_ && rule_index_ < rules_.css_rules_size());
+ return rules_.css_rules(rule_index_);
+ }
+
+ private:
+ ProtobufRuleInputStreamImpl(const ProtobufRuleInputStreamImpl&) = delete;
+ void operator=(const ProtobufRuleInputStreamImpl&) = delete;
+
+ const url_pattern_index::proto::FilteringRules& rules_;
+ bool not_first_rule_ = false;
+ bool is_reading_url_rules_ = true;
+ int rule_index_ = 0;
+};
+
+// FilterList streams ---------------------------------------------------------
+
+// Reads rules from a text |file| of the FilterList format.
+class FilterListRuleInputStream : public RuleInputStream {
+ public:
+ explicit FilterListRuleInputStream(std::unique_ptr<std::istream> input)
+ : input_(std::move(input)) {}
+
+ url_pattern_index::proto::RuleType FetchNextRule() override {
+ std::string line;
+ while (std::getline(*input_, line)) {
+ auto rule_type = parser_.Parse(line);
+ if (rule_type != url_pattern_index::proto::RULE_TYPE_UNSPECIFIED)
+ return rule_type;
+ if (!IsTrivialParseError(parser_.parse_error())) {
+ std::cerr << parser_.parse_error() << std::endl;
+ }
+ // TODO(pkalinnikov): Export the number of processed/skipped rules.
+ }
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ }
+
+ url_pattern_index::proto::UrlRule GetUrlRule() override {
+ CHECK_EQ(url_pattern_index::proto::RULE_TYPE_URL, parser_.rule_type());
+ return parser_.url_rule().ToProtobuf();
+ }
+
+ url_pattern_index::proto::CssRule GetCssRule() override {
+ CHECK_EQ(url_pattern_index::proto::RULE_TYPE_CSS, parser_.rule_type());
+ return parser_.css_rule().ToProtobuf();
+ }
+
+ private:
+ FilterListRuleInputStream(const FilterListRuleInputStream&) = delete;
+ void operator=(const FilterListRuleInputStream&) = delete;
+
+ RuleParser parser_;
+ std::unique_ptr<std::istream> input_;
+};
+
+// Writes rules to |output| in FilterList format.
+class FilterListRuleOutputStream : public RuleOutputStream {
+ public:
+ explicit FilterListRuleOutputStream(std::unique_ptr<std::ostream> output)
+ : output_(std::move(output)) {}
+
+ bool PutUrlRule(const url_pattern_index::proto::UrlRule& rule) override {
+ std::string line = ToString(rule) + '\n';
+ output_->write(line.data(), line.size());
+ return !output_->bad();
+ }
+
+ bool PutCssRule(const url_pattern_index::proto::CssRule& rule) override {
+ std::string line = ToString(rule) + '\n';
+ output_->write(line.data(), line.size());
+ return !output_->bad();
+ }
+
+ bool Finish() override {
+ output_->flush();
+ return !output_->bad();
+ }
+
+ private:
+ FilterListRuleOutputStream(const FilterListRuleOutputStream&) = delete;
+ void operator=(const FilterListRuleOutputStream&) = delete;
+
+ std::unique_ptr<std::ostream> output_;
+};
+
+// Protobuf streams ------------------------------------------------------------
+
+// Reads rules from a |file| with a serialized FilteredRules message.
+class ProtobufRuleInputStream : public RuleInputStream {
+ public:
+ explicit ProtobufRuleInputStream(std::unique_ptr<std::istream> input) {
+ std::string buffer = ReadStreamToString(input.get());
+ CHECK(rules_.ParseFromString(buffer));
+ impl_.reset(new ProtobufRuleInputStreamImpl(rules_));
+ }
+
+ url_pattern_index::proto::RuleType FetchNextRule() override {
+ return impl_->FetchNextRule();
+ }
+ url_pattern_index::proto::UrlRule GetUrlRule() override {
+ return impl_->GetUrlRule();
+ }
+ url_pattern_index::proto::CssRule GetCssRule() override {
+ return impl_->GetCssRule();
+ }
+
+ private:
+ ProtobufRuleInputStream(const ProtobufRuleInputStream&) = delete;
+ void operator=(const ProtobufRuleInputStream&) = delete;
+
+ url_pattern_index::proto::FilteringRules rules_;
+ std::unique_ptr<ProtobufRuleInputStreamImpl> impl_;
+};
+
+// Writes rules to |output| as a single url_pattern_index::proto::FilteringRules
+// message in binary format.
+class ProtobufRuleOutputStream : public RuleOutputStream {
+ public:
+ explicit ProtobufRuleOutputStream(std::unique_ptr<std::ostream> output)
+ : output_(std::move(output)) {}
+
+ bool PutUrlRule(const url_pattern_index::proto::UrlRule& rule) override {
+ *all_rules_.add_url_rules() = rule;
+ return true;
+ }
+
+ bool PutCssRule(const url_pattern_index::proto::CssRule& rule) override {
+ *all_rules_.add_css_rules() = rule;
+ return true;
+ }
+
+ bool Finish() override {
+ std::string buffer;
+ if (!all_rules_.SerializeToString(&buffer))
+ return false;
+ output_->write(buffer.data(), buffer.size());
+ output_->flush();
+ return !output_->bad();
+ }
+
+ private:
+ ProtobufRuleOutputStream(const ProtobufRuleOutputStream&) = delete;
+ void operator=(const ProtobufRuleOutputStream&) = delete;
+
+ url_pattern_index::proto::FilteringRules all_rules_;
+ std::unique_ptr<std::ostream> output_;
+};
+
+// UnindexedRuleset streams ----------------------------------------------------
+
+// Reads rules stored in |input| in UnindexedRuleset format.
+class UnindexedRulesetRuleInputStream : public RuleInputStream {
+ public:
+ explicit UnindexedRulesetRuleInputStream(
+ std::unique_ptr<std::istream> input) {
+ ruleset_ = ReadStreamToString(input.get());
+ ruleset_input_.reset(new google::protobuf::io::ArrayInputStream(
+ ruleset_.data(), ruleset_.size()));
+ ruleset_reader_.reset(
+ new url_pattern_index::UnindexedRulesetReader(ruleset_input_.get()));
+ }
+
+ url_pattern_index::proto::RuleType FetchNextRule() override {
+ if (!impl_ && !ReadNextChunk())
+ return url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ url_pattern_index::proto::RuleType rule_type = impl_->FetchNextRule();
+ while (rule_type == url_pattern_index::proto::RULE_TYPE_UNSPECIFIED &&
+ ReadNextChunk()) {
+ rule_type = impl_->FetchNextRule();
+ }
+ return rule_type;
+ }
+
+ url_pattern_index::proto::UrlRule GetUrlRule() override {
+ return impl_->GetUrlRule();
+ }
+ url_pattern_index::proto::CssRule GetCssRule() override {
+ return impl_->GetCssRule();
+ }
+
+ private:
+ UnindexedRulesetRuleInputStream(const UnindexedRulesetRuleInputStream&) =
+ delete;
+ void operator=(const UnindexedRulesetRuleInputStream&) = delete;
+
+ bool ReadNextChunk() {
+ if (ruleset_reader_->ReadNextChunk(&rules_chunk_)) {
+ impl_.reset(new ProtobufRuleInputStreamImpl(rules_chunk_));
+ return true;
+ }
+ impl_.reset();
+ return false;
+ }
+
+ std::string ruleset_;
+ std::unique_ptr<google::protobuf::io::ArrayInputStream> ruleset_input_;
+ std::unique_ptr<url_pattern_index::UnindexedRulesetReader> ruleset_reader_;
+
+ url_pattern_index::proto::FilteringRules rules_chunk_;
+ std::unique_ptr<ProtobufRuleInputStreamImpl> impl_;
+};
+
+// Writes the rules to |output| in UnindexedRuleset format. Discards CSS rules.
+class UnindexedRulesetRuleOutputStream : public RuleOutputStream {
+ public:
+ explicit UnindexedRulesetRuleOutputStream(
+ std::unique_ptr<std::ostream> output)
+ : ruleset_output_(&ruleset_),
+ ruleset_writer_(&ruleset_output_),
+ output_(std::move(output)) {}
+
+ bool PutUrlRule(const url_pattern_index::proto::UrlRule& rule) override {
+ return ruleset_writer_.AddUrlRule(rule);
+ }
+
+ bool PutCssRule(const url_pattern_index::proto::CssRule& rule) override {
+ return true;
+ }
+
+ bool Finish() override {
+ if (!ruleset_writer_.Finish())
+ return false;
+ output_->write(ruleset_.data(), ruleset_.size());
+ output_->flush();
+ return !output_->bad();
+ }
+
+ private:
+ UnindexedRulesetRuleOutputStream(const UnindexedRulesetRuleOutputStream&) =
+ delete;
+ void operator=(const UnindexedRulesetRuleOutputStream&) = delete;
+
+ std::string ruleset_;
+ google::protobuf::io::StringOutputStream ruleset_output_;
+ url_pattern_index::UnindexedRulesetWriter ruleset_writer_;
+ std::unique_ptr<std::ostream> output_;
+};
+
+} // namespace
+
+// static
+std::unique_ptr<RuleInputStream> RuleInputStream::Create(
+ std::unique_ptr<std::istream> input,
+ RulesetFormat format) {
+ CHECK(input);
+ CHECK(!input->bad());
+ std::unique_ptr<RuleInputStream> result;
+ switch (format) {
+ case RulesetFormat::kFilterList:
+ result = std::make_unique<FilterListRuleInputStream>(std::move(input));
+ break;
+ case RulesetFormat::kProto:
+ result = std::make_unique<ProtobufRuleInputStream>(std::move(input));
+ break;
+ case RulesetFormat::kUnindexedRuleset:
+ result =
+ std::make_unique<UnindexedRulesetRuleInputStream>(std::move(input));
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+// static
+std::unique_ptr<RuleOutputStream> RuleOutputStream::Create(
+ std::unique_ptr<std::ostream> output,
+ RulesetFormat format) {
+ CHECK(output);
+ CHECK(!output->bad());
+ std::unique_ptr<RuleOutputStream> result;
+ switch (format) {
+ case RulesetFormat::kFilterList:
+ result = std::make_unique<FilterListRuleOutputStream>(std::move(output));
+ break;
+ case RulesetFormat::kProto:
+ result = std::make_unique<ProtobufRuleOutputStream>(std::move(output));
+ break;
+ case RulesetFormat::kUnindexedRuleset:
+ result =
+ std::make_unique<UnindexedRulesetRuleOutputStream>(std::move(output));
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+// TransferRules helpers and implementation. -----------------------------------
+
+namespace {
+
+// Up to M58 subresource_filter supported only these types.
+constexpr int kChrome54To58ElementTypes = 2047;
+
+static_assert(kChrome54To58ElementTypes &
+ url_pattern_index::proto::ELEMENT_TYPE_OTHER,
+ "Wrong M54 element types.");
+static_assert(kChrome54To58ElementTypes &
+ url_pattern_index::proto::ELEMENT_TYPE_FONT,
+ "Wrong M54 element types.");
+static_assert(!(kChrome54To58ElementTypes &
+ url_pattern_index::proto::ELEMENT_TYPE_WEBSOCKET),
+ "Wrong M54 element types.");
+static_assert(!(kChrome54To58ElementTypes &
+ url_pattern_index::proto::ELEMENT_TYPE_POPUP),
+ "Wrong M54 element types.");
+
+} // namespace
+
+bool TransferRules(RuleInputStream* input,
+ RuleOutputStream* url_rules_output,
+ RuleOutputStream* css_rules_output,
+ int chrome_version) {
+ while (true) {
+ auto rule_type = input->FetchNextRule();
+ if (rule_type == url_pattern_index::proto::RULE_TYPE_UNSPECIFIED)
+ break;
+ switch (rule_type) {
+ case url_pattern_index::proto::RULE_TYPE_URL: {
+ if (!url_rules_output)
+ break;
+ url_pattern_index::proto::UrlRule url_rule = input->GetUrlRule();
+ if (!DeleteUrlRuleOrAmend(&url_rule, chrome_version))
+ url_rules_output->PutUrlRule(url_rule);
+ break;
+ }
+ case url_pattern_index::proto::RULE_TYPE_CSS:
+ if (css_rules_output)
+ css_rules_output->PutCssRule(input->GetCssRule());
+ break;
+ case url_pattern_index::proto::RULE_TYPE_COMMENT:
+ // Ignore comments.
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool DeleteUrlRuleOrAmend(url_pattern_index::proto::UrlRule* rule,
+ int lowest_chrome_version) {
+ if (!lowest_chrome_version)
+ return false;
+
+ CHECK(rule->has_element_types() || rule->element_types() == 0);
+
+ // REGEXP rules are not supported in Chrome's subresource_filter.
+ if (rule->url_pattern_type() ==
+ url_pattern_index::proto::URL_PATTERN_TYPE_REGEXP)
+ return true;
+
+ // POPUP type is deprecated because popup blocking is activated by default
+ // in Chrome.
+ rule->set_element_types(rule->element_types() &
+ ~url_pattern_index::proto::ELEMENT_TYPE_POPUP);
+
+ // Only the following activation types are supported in Chrome.
+ rule->set_activation_types(
+ rule->activation_types() &
+ (url_pattern_index::proto::ACTIVATION_TYPE_DOCUMENT |
+ url_pattern_index::proto::ACTIVATION_TYPE_GENERICBLOCK));
+ if (!rule->activation_types())
+ rule->clear_activation_types();
+
+ // Chrome 54-58 ignores rules with unknown element types (like websocket).
+ if (lowest_chrome_version == 54) {
+ // Remove unknown types to prevent the |rule| from being ignored.
+ rule->set_element_types(rule->element_types() & kChrome54To58ElementTypes);
+ }
+ if (!rule->element_types())
+ rule->clear_element_types();
+
+ // The rule should have at least 1 type bit, otherwise it targets nothing.
+ return !rule->element_types() && !rule->activation_types();
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.h b/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.h
new file mode 100644
index 00000000000..bab58711e02
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream.h
@@ -0,0 +1,98 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULE_STREAM_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULE_STREAM_H_
+
+#include <istream>
+#include <memory>
+#include <ostream>
+#include <string>
+
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_format.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+
+namespace subresource_filter {
+
+class RuleInputStream;
+class RuleOutputStream;
+
+// Interface to read the rules one by one.
+class RuleInputStream {
+ public:
+ virtual ~RuleInputStream() = default;
+
+ // Fetches the next rule and returns its type. Returns RULE_TYPE_UNSPECIFIED
+ // if end of the stream is reached or an I/O error occurred.
+ // TODO(pkalinnikov): Distinguish between errors and end-of-stream.
+ virtual url_pattern_index::proto::RuleType FetchNextRule() = 0;
+
+ // Returns the latest fetched UrlRule. If the last FetchNextRule() returned
+ // not url_pattern_index::proto::RULE_TYPE_URL, the resulting value is
+ // undefined. This method is idempotent and optional to call.
+ virtual url_pattern_index::proto::UrlRule GetUrlRule() = 0;
+
+ // Same as above, but for CSS rules.
+ virtual url_pattern_index::proto::CssRule GetCssRule() = 0;
+
+ // Factory method to produce a RuleInputStream reading rules from |input| in
+ // the specified |format|. If the |format| is not supported, then returns
+ // nullptr.
+ static std::unique_ptr<RuleInputStream> Create(
+ std::unique_ptr<std::istream> input,
+ RulesetFormat format);
+};
+
+// Interface to output rules one by one.
+class RuleOutputStream {
+ public:
+ virtual ~RuleOutputStream() = default;
+
+ // The following methods are used to write rules into the stream. Return false
+ // iff an error occurred.
+ virtual bool PutUrlRule(const url_pattern_index::proto::UrlRule& rule) = 0;
+ virtual bool PutCssRule(const url_pattern_index::proto::CssRule& rule) = 0;
+
+ // Finalizes the serialization. Returns false on error.
+ virtual bool Finish() = 0;
+
+ // Factory method to produce a RuleOutputStream writing to the |output| in the
+ // specified |format|. If the |format| is not supported, then returns nullptr.
+ static std::unique_ptr<RuleOutputStream> Create(
+ std::unique_ptr<std::ostream> output,
+ RulesetFormat format);
+};
+
+// Reads rules from the |input| stream, puts URL rules to |url_rules_output|,
+// and CSS rules to |css_rules_output|. Returns false iff an error occurred
+// either in the input or one of the output streams.
+//
+// If one of the output streams is nullptr, the corresponding rules are
+// discarded. The same instance can be passed in for both output streams, but in
+// this case the original order of rules may be not preserved. However, it is
+// guaranteed that for a certain type of rules (e.g., URL) the relative order of
+// such rules is preserved.
+//
+// If |chrome_version| is non-zero, some rules and element type options will be
+// filtered out so that the output ruleset can be consumed by Chrome clients as
+// early as the specified |chrome_version|. A value of 0 indicates that the
+// ruleset should remain intact.
+bool TransferRules(RuleInputStream* input,
+ RuleOutputStream* url_rules_output,
+ RuleOutputStream* css_rules_output,
+ int chrome_version = 0);
+
+// This function is used by TransferRules to amend a stream of UrlRules
+// according to the given |lowest_chrome_version| which uses the produced
+// ruleset. Exposed here only for testing purposes.
+//
+// Returns false if the |rule| should be deleted altogether, otherwise returns
+// true and amends the |rule| if necessary for the given
+// |lowest_chrome_version|.
+bool DeleteUrlRuleOrAmend(url_pattern_index::proto::UrlRule* rule,
+ int lowest_chrome_version);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULE_STREAM_H_
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream_unittest.cc b/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream_unittest.cc
new file mode 100644
index 00000000000..66c8c430751
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/rule_stream_unittest.cc
@@ -0,0 +1,415 @@
+// 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 "components/subresource_filter/tools/ruleset_converter/rule_stream.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "components/subresource_filter/tools/rule_parser/rule_parser.h"
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+namespace {
+
+// Returns a small number of predefined rules in text format.
+std::vector<std::string> GetSomeRules() {
+ return std::vector<std::string>{
+ "example.com",
+ "||ex.com$image",
+ "|http://example.com/?key=value$~third-party,domain=ex.com",
+ "&key1=value1&key2=value2|$script,image,font",
+ "domain1.com,domain1.com###id",
+ "@@whitelisted.com$document,domain=example.com|~sub.example.com",
+ "###absolute_evil_id",
+ "@@whitelisted.com$match-case,document,domain=another.example.com",
+ "domain.com,~sub.domain.com,sub.sub.domain.com#@#id",
+ "#@#absolute_good_id",
+ "host$websocket",
+ };
+}
+
+// Returns some rules which Chrome doesn't support fully or partially, mixed
+// with a couple of supported rules, or otherwise weird ones.
+std::vector<std::string> GetSomeChromeUnfriendlyRules() {
+ return std::vector<std::string>{
+ "/a[0-9].com/$image",
+ "a.com$image,popup"
+ "a.com$popup",
+ "a.com$~image",
+ "a.com$~popup",
+ "a.com$~image,~popup",
+ "@@a.com$subdocument,document",
+ "@@a.com$document,generichide",
+ "@@a.com$document",
+ "@@a.com$genericblock",
+ "@@a.com$elemhide",
+ "@@a.com$generichide",
+ "@@a.com$elemhide,generichide",
+ "@@a.com$image,elemhide,generichide",
+ "a.com$image,~image",
+ };
+}
+
+// Generates and returns many rules in text format.
+std::vector<std::string> GetManyRules() {
+ constexpr size_t kNumberOfUrlRules = 10123;
+ constexpr size_t kNumberOfCssRules = 5321;
+
+ std::vector<std::string> text_rules;
+
+ for (size_t i = 0; i != kNumberOfUrlRules; ++i) {
+ std::string text_rule;
+ if (!(i & 3))
+ text_rule += "@@";
+ if (i & 1)
+ text_rule += "sub.";
+ text_rule += "example" + base::IntToString(i) + ".com";
+ text_rule += '$';
+ text_rule += (i & 7) ? "script" : "image";
+ if (i & 1)
+ text_rule += ",domain=example.com|~but_not.example.com";
+ text_rules.push_back(text_rule);
+ }
+
+ for (size_t i = 0; i != kNumberOfCssRules; ++i) {
+ std::string text_rule = "domain.com";
+ if (i & 1)
+ text_rule += ",~but_not.domain.com";
+ text_rule += (i & 3) ? "##" : "#@#";
+ text_rule += "#id" + base::IntToString(i);
+ text_rules.push_back(text_rule);
+ }
+
+ return text_rules;
+}
+
+// Reads the provided |ruleset_file| skipping every second rule (independently
+// for URL and CSS rules), and EXPECTs that it contains exactly all the rules
+// from |expected_contents| in the same order.
+void ReadHalfRulesOfTestRulesetAndExpectContents(
+ const ScopedTempRulesetFile& ruleset_file,
+ const TestRulesetContents& expected_contents) {
+ std::unique_ptr<RuleInputStream> input = ruleset_file.OpenForInput();
+
+ TestRulesetContents contents;
+
+ bool take_url_rule = true;
+ bool take_css_rule = true;
+ url_pattern_index::proto::RuleType rule_type =
+ url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ while ((rule_type = input->FetchNextRule()) !=
+ url_pattern_index::proto::RULE_TYPE_UNSPECIFIED) {
+ if (rule_type == url_pattern_index::proto::RULE_TYPE_URL) {
+ if (take_url_rule)
+ contents.url_rules.push_back(input->GetUrlRule());
+ take_url_rule = !take_url_rule;
+ } else {
+ ASSERT_EQ(url_pattern_index::proto::RULE_TYPE_CSS, rule_type);
+ if (take_css_rule)
+ contents.css_rules.push_back(input->GetCssRule());
+ take_css_rule = !take_css_rule;
+ }
+ }
+
+ EXPECT_EQ(contents, expected_contents);
+}
+
+} // namespace
+
+TEST(RuleStreamTest, WriteAndReadRuleset) {
+ for (int small_or_big = 0; small_or_big < 2; ++small_or_big) {
+ TestRulesetContents contents;
+ if (small_or_big)
+ contents.AppendRules(GetManyRules());
+ else
+ contents.AppendRules(GetSomeRules());
+
+ TestRulesetContents only_url_rules;
+ only_url_rules.url_rules = contents.url_rules;
+
+ for (auto format : {RulesetFormat::kFilterList, RulesetFormat::kProto,
+ RulesetFormat::kUnindexedRuleset}) {
+ ScopedTempRulesetFile ruleset_file(format);
+ ruleset_file.WriteRuleset(contents);
+ // Note: kUnindexedRuleset discards CSS rules, test it differently.
+ EXPECT_EQ(ruleset_file.ReadContents(),
+ format == RulesetFormat::kUnindexedRuleset ? only_url_rules
+ : contents);
+ }
+ }
+}
+
+TEST(RuleStreamTest, WriteAndReadHalfRuleset) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetManyRules());
+
+ TestRulesetContents half_contents;
+ for (size_t i = 0, size = contents.url_rules.size(); i < size; i += 2)
+ half_contents.url_rules.push_back(contents.url_rules[i]);
+ for (size_t i = 0, size = contents.css_rules.size(); i < size; i += 2)
+ half_contents.css_rules.push_back(contents.css_rules[i]);
+
+ TestRulesetContents half_url_rules;
+ half_url_rules.url_rules = half_contents.url_rules;
+
+ for (auto format : {RulesetFormat::kFilterList, RulesetFormat::kProto,
+ RulesetFormat::kUnindexedRuleset}) {
+ ScopedTempRulesetFile ruleset_file(format);
+ ruleset_file.WriteRuleset(contents);
+ // Note: kUnindexedRuleset discards CSS rules, test it differently.
+ ReadHalfRulesOfTestRulesetAndExpectContents(
+ ruleset_file, format == RulesetFormat::kUnindexedRuleset
+ ? half_url_rules
+ : half_contents);
+ }
+}
+
+TEST(RuleStreamTest, TransferAllRulesToSameStream) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetManyRules());
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset(RulesetFormat::kFilterList);
+ source_ruleset.WriteRuleset(contents);
+
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ std::unique_ptr<RuleOutputStream> output = target_ruleset.OpenForOutput();
+ TransferRules(input.get(), output.get(), output.get());
+ EXPECT_TRUE(output->Finish());
+ input.reset();
+ output.reset();
+
+ EXPECT_EQ(target_ruleset.ReadContents(), contents);
+}
+
+TEST(RuleStreamTest, TransferUrlRulesToOneStream) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetManyRules());
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset(RulesetFormat::kFilterList);
+ source_ruleset.WriteRuleset(contents);
+
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ std::unique_ptr<RuleOutputStream> output = target_ruleset.OpenForOutput();
+ TransferRules(input.get(), output.get(), nullptr);
+ EXPECT_TRUE(output->Finish());
+ input.reset();
+ output.reset();
+
+ contents.css_rules.clear();
+ EXPECT_EQ(target_ruleset.ReadContents(), contents);
+}
+
+TEST(RuleStreamTest, TransferCssRulesToOneStream) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetManyRules());
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset(RulesetFormat::kFilterList);
+ source_ruleset.WriteRuleset(contents);
+
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ std::unique_ptr<RuleOutputStream> output = target_ruleset.OpenForOutput();
+ TransferRules(input.get(), nullptr, output.get());
+ EXPECT_TRUE(output->Finish());
+ input.reset();
+ output.reset();
+
+ contents.url_rules.clear();
+ EXPECT_EQ(target_ruleset.ReadContents(), contents);
+}
+
+TEST(RuleStreamTest, TransferAllRulesToDifferentStreams) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetManyRules());
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset_url(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset_css(RulesetFormat::kFilterList);
+ source_ruleset.WriteRuleset(contents);
+
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ std::unique_ptr<RuleOutputStream> output_url =
+ target_ruleset_url.OpenForOutput();
+ std::unique_ptr<RuleOutputStream> output_css =
+ target_ruleset_css.OpenForOutput();
+ TransferRules(input.get(), output_url.get(), output_css.get());
+ EXPECT_TRUE(output_url->Finish());
+ EXPECT_TRUE(output_css->Finish());
+ input.reset();
+ output_url.reset();
+ output_css.reset();
+
+ TestRulesetContents only_url_rules;
+ only_url_rules.url_rules = contents.url_rules;
+ EXPECT_EQ(target_ruleset_url.ReadContents(), only_url_rules);
+
+ contents.url_rules.clear();
+ EXPECT_EQ(target_ruleset_css.ReadContents(), contents);
+}
+
+TEST(RuleStreamTest, TransferRulesAndDiscardRegexpRules) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetManyRules());
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset(RulesetFormat::kFilterList);
+ source_ruleset.WriteRuleset(contents);
+
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ std::unique_ptr<RuleOutputStream> output = target_ruleset.OpenForOutput();
+ TransferRules(input.get(), output.get(), nullptr, 54 /* chrome_version */);
+ EXPECT_TRUE(output->Finish());
+ input.reset();
+ output.reset();
+
+ contents.url_rules.erase(
+ std::remove_if(contents.url_rules.begin(), contents.url_rules.end(),
+ [](const url_pattern_index::proto::UrlRule& rule) {
+ return rule.url_pattern_type() ==
+ url_pattern_index::proto::URL_PATTERN_TYPE_REGEXP;
+ }),
+ contents.url_rules.end());
+ contents.css_rules.clear();
+ EXPECT_EQ(target_ruleset.ReadContents(), contents);
+}
+
+TEST(RuleStreamTest, TransferRulesChromeVersion) {
+ TestRulesetContents contents;
+ contents.AppendRules(GetSomeChromeUnfriendlyRules());
+ contents.AppendRules(GetManyRules());
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ source_ruleset.WriteRuleset(contents);
+
+ for (int chrome_version : {0, 54, 59}) {
+ TestRulesetContents expected_contents;
+ for (url_pattern_index::proto::UrlRule url_rule : contents.url_rules) {
+ if (DeleteUrlRuleOrAmend(&url_rule, chrome_version))
+ continue;
+ expected_contents.url_rules.push_back(url_rule);
+ }
+
+ ScopedTempRulesetFile target_ruleset(RulesetFormat::kFilterList);
+ std::unique_ptr<RuleOutputStream> output = target_ruleset.OpenForOutput();
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ TransferRules(input.get(), output.get(), nullptr, chrome_version);
+ EXPECT_TRUE(output->Finish());
+ input.reset();
+ output.reset();
+
+ EXPECT_EQ(target_ruleset.ReadContents(), expected_contents);
+ }
+}
+
+TEST(RuleStreamTest, TransferRulesFromFilterListWithUnsupportedOptions) {
+ std::vector<std::string> text_rules = GetSomeRules();
+ const size_t number_of_correct_rules = text_rules.size();
+
+ // Insert several rules with non-critical parse errors.
+ text_rules.insert(text_rules.begin(), "host1$donottrack");
+ text_rules.push_back("");
+ text_rules.insert(text_rules.begin() + text_rules.size() / 2,
+ "host3$collapse");
+
+ ScopedTempRulesetFile source_ruleset(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile target_ruleset(RulesetFormat::kFilterList);
+
+ // Output all the rules to the |source_ruleset| file.
+ std::string joined_rules = base::JoinString(text_rules, "\n");
+ base::WriteFile(source_ruleset.ruleset_path(), joined_rules.data(),
+ joined_rules.size());
+
+ // Filter out the rules with parse errors, and save the rest to |contents|.
+ TestRulesetContents contents;
+ contents.AppendRules(text_rules, true /* allow_errors */);
+
+ // Make sure all the rules with no errors were transferred.
+ {
+ std::unique_ptr<RuleInputStream> input = source_ruleset.OpenForInput();
+ std::unique_ptr<RuleOutputStream> output = target_ruleset.OpenForOutput();
+ TransferRules(input.get(), output.get(), output.get());
+ EXPECT_TRUE(output->Finish());
+ }
+
+ EXPECT_EQ(number_of_correct_rules,
+ contents.url_rules.size() + contents.css_rules.size());
+ EXPECT_EQ(target_ruleset.ReadContents(), contents);
+}
+
+TEST(RuleStreamTest, DeleteUrlRuleOrAmend) {
+ const struct TestCase {
+ const char* rule;
+ const char* chrome_54_rule;
+ const char* chrome_59_rule;
+ } kTestCases[] = {
+ {"/a[0-9].com/$image", nullptr, nullptr},
+ {"a.com$image,popup", "a.com$image,~popup", "#54"},
+ {"a.com$popup", nullptr, nullptr},
+ {"a.com$~image", "a.com$~image,~popup,~websocket", "#0"},
+ {"a.com$~popup", "a.com$~popup,~websocket", "a.com"},
+ {"a.com$~image,~popup", "a.com$~image,~popup,~websocket", "#0"},
+ {"@@a.com$subdocument,document", "#0", "#0"},
+ {"@@a.com$document,generichide", "@@a.com$document", "#54"},
+ {"@@a.com$document", "#0", "#0"},
+ {"@@a.com$genericblock", "#0", "#0"},
+ {"@@a.com$elemhide", nullptr, nullptr},
+ {"@@a.com$generichide", nullptr, nullptr},
+ {"@@a.com$elemhide,generichide", nullptr, nullptr},
+ {"@@a.com$image,elemhide,generichide", "@@a.com$image", "#54"},
+ {"a.com$image,~image", nullptr, nullptr},
+ };
+
+ auto get_target_rule = [](const TestCase& test, std::string target_rule) {
+ RuleParser parser;
+ if (target_rule == "#0")
+ target_rule = test.rule;
+ else if (target_rule == "#54")
+ target_rule = test.chrome_54_rule;
+ EXPECT_EQ(url_pattern_index::proto::RULE_TYPE_URL,
+ parser.Parse(target_rule));
+ return parser.url_rule().ToProtobuf();
+ };
+
+ RuleParser parser;
+ for (const auto& test : kTestCases) {
+ SCOPED_TRACE(test.rule);
+ ASSERT_EQ(url_pattern_index::proto::RULE_TYPE_URL, parser.Parse(test.rule));
+ const url_pattern_index::proto::UrlRule current_rule =
+ parser.url_rule().ToProtobuf();
+
+ url_pattern_index::proto::UrlRule modified_rule = current_rule;
+ EXPECT_FALSE(DeleteUrlRuleOrAmend(&modified_rule, 0));
+ EXPECT_TRUE(AreUrlRulesEqual(modified_rule, current_rule));
+
+ modified_rule = current_rule;
+ EXPECT_EQ(!test.chrome_54_rule, DeleteUrlRuleOrAmend(&modified_rule, 54));
+ if (test.chrome_54_rule) {
+ EXPECT_TRUE(AreUrlRulesEqual(modified_rule,
+ get_target_rule(test, test.chrome_54_rule)));
+ }
+
+ modified_rule = current_rule;
+ EXPECT_EQ(!test.chrome_59_rule, DeleteUrlRuleOrAmend(&modified_rule, 59));
+ if (test.chrome_59_rule) {
+ EXPECT_TRUE(AreUrlRulesEqual(modified_rule,
+ get_target_rule(test, test.chrome_59_rule)));
+ }
+ }
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc
new file mode 100644
index 00000000000..a10ba914e01
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.cc
@@ -0,0 +1,176 @@
+// 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 "components/subresource_filter/tools/ruleset_converter/ruleset_converter.h"
+
+#include <fstream>
+#include <iostream>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/subresource_filter/tools/ruleset_converter/rule_stream.h"
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_format.h"
+
+namespace subresource_filter {
+
+RulesetConverter::RulesetConverter() = default;
+RulesetConverter::~RulesetConverter() = default;
+
+bool RulesetConverter::Convert() {
+ if (inputs_.empty()) {
+ std::fprintf(stderr, "No input files specified\n");
+ return false;
+ }
+
+ std::unique_ptr<RuleOutputStream> primary_output;
+ std::unique_ptr<RuleOutputStream> secondary_output;
+ subresource_filter::RuleOutputStream* css_rules_output = nullptr;
+
+ auto make_output = [](const base::FilePath& path, RulesetFormat format) {
+ return RuleOutputStream::Create(
+ std::make_unique<std::ofstream>(path.AsUTF8Unsafe(),
+ std::ios::binary | std::ios::out),
+ format);
+ };
+
+ if (!output_file_.empty()) {
+ primary_output = make_output(output_file_, output_format_);
+ css_rules_output = primary_output.get();
+ } else {
+ if (!output_url_.empty()) {
+ primary_output = make_output(output_url_, output_format_);
+ }
+ if (output_css_ == output_url_) {
+ css_rules_output = primary_output.get();
+ } else if (!output_css_.empty()) {
+ secondary_output = make_output(output_css_, output_format_);
+ css_rules_output = secondary_output.get();
+ }
+ }
+
+ if (!primary_output && !secondary_output) {
+ std::fprintf(stderr,
+ "Must specify an output_file, or one of "
+ "output_file_url|output_file_css\n");
+ return false;
+ }
+
+ // Iterate through input files and stream them to the outputs.
+ for (const auto& path : inputs_) {
+ auto input_stream = subresource_filter::RuleInputStream::Create(
+ std::make_unique<std::ifstream>(path.AsUTF8Unsafe(),
+ std::ios::binary | std::ios::in),
+ input_format_);
+ CHECK(input_stream);
+ CHECK(TransferRules(input_stream.get(), primary_output.get(),
+ css_rules_output, chrome_version_));
+ }
+
+ if (primary_output)
+ CHECK(primary_output->Finish());
+ if (secondary_output)
+ CHECK(secondary_output->Finish());
+ return true;
+}
+
+bool RulesetConverter::SetInputFiles(
+ const base::CommandLine::StringType& comma_separated_paths) {
+#if defined(OS_WIN)
+ base::string16 separator16 = base::ASCIIToUTF16(",");
+ base::StringPiece16 separator(separator16);
+#else
+ base::StringPiece separator(",");
+#endif
+ for (const auto& piece : base::SplitStringPiece(
+ comma_separated_paths, separator, base::TRIM_WHITESPACE,
+ base::SPLIT_WANT_NONEMPTY)) {
+ base::FilePath path(piece);
+
+ if (!base::PathExists(path)) {
+ std::fprintf(stderr, "Path not found: %s\n", path.AsUTF8Unsafe().c_str());
+ return false;
+ }
+
+ inputs_.push_back(path);
+ }
+
+ if (inputs_.empty()) {
+ std::fprintf(stderr, "Received no input files\n");
+ return false;
+ }
+ return true;
+}
+
+bool RulesetConverter::SetChromeVersion(const std::string& version) {
+ int parsed_version = 0;
+ if (!base::StringToInt(version, &parsed_version)) {
+ std::fprintf(stderr,
+ "chrome_version could not be parsed into an integer.\n");
+ return false;
+ }
+ if (parsed_version != 0 && parsed_version != 54 && parsed_version != 59) {
+ std::fprintf(stderr, "chrome_version should be in {0, 54, 59}.\n");
+ return false;
+ }
+ chrome_version_ = parsed_version;
+ return true;
+}
+
+bool RulesetConverter::SetOutputFile(const base::FilePath& path) {
+ if (!base::DirectoryExists(path.DirName())) {
+ std::printf("Directory does not exist: %s\n",
+ path.DirName().AsUTF8Unsafe().c_str());
+ return false;
+ }
+ output_file_ = path;
+ return true;
+}
+
+bool RulesetConverter::SetOutputFileUrl(const base::FilePath& path) {
+ if (!base::DirectoryExists(path.DirName())) {
+ std::printf("Directory does not exist: %s\n",
+ path.DirName().AsUTF8Unsafe().c_str());
+ return false;
+ }
+ output_url_ = path;
+ return true;
+}
+
+bool RulesetConverter::SetOutputFileCss(const base::FilePath& path) {
+ if (!base::DirectoryExists(path.DirName())) {
+ std::printf("Directory does not exist: %s\n",
+ path.DirName().AsUTF8Unsafe().c_str());
+ return false;
+ }
+ output_css_ = path;
+ return true;
+}
+
+bool RulesetConverter::SetInputFormat(const std::string& format) {
+ RulesetFormat ruleset_format = ParseFlag(format);
+ if (ruleset_format == subresource_filter::RulesetFormat::kUndefined) {
+ std::fprintf(stderr, "Input format is not defined.\n");
+ return false;
+ }
+ input_format_ = ruleset_format;
+ return true;
+}
+
+bool RulesetConverter::SetOutputFormat(const std::string& format) {
+ RulesetFormat ruleset_format = ParseFlag(format);
+ if (ruleset_format == subresource_filter::RulesetFormat::kUndefined) {
+ std::fprintf(stderr, "Output format is not defined.\n");
+ return false;
+ }
+ output_format_ = ruleset_format;
+ return true;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.h b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.h
new file mode 100644
index 00000000000..1e4c39cdf23
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter.h
@@ -0,0 +1,73 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_CONVERTER_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_CONVERTER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "components/subresource_filter/tools/ruleset_converter/rule_stream.h"
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_format.h"
+
+namespace subresource_filter {
+
+// The RulesetConverter converts subresource_filter rulesets across multiple
+// formats.
+// This class is a thin abstraction to enable testing of the |ruleset_converter|
+// command line tool. See comments in main.cc for more information.
+class RulesetConverter {
+ public:
+ RulesetConverter();
+ ~RulesetConverter();
+
+ // Converts rulesets based on Set* configurations.
+ bool Convert();
+
+ // Returns false if the input files are invalid or cannot be found.
+ // Corresponds to --input_files parameter.
+ bool SetInputFiles(
+ const base::CommandLine::StringType& comma_separated_paths);
+
+ // These methods will return false if the directory does not exist.
+ //
+ // Corresponds to --output_file parameter.
+ bool SetOutputFile(const base::FilePath& path);
+
+ // Corresponds to --output_file_url parameter.
+ bool SetOutputFileUrl(const base::FilePath& path);
+
+ // Corresponds to --output_file_css parameter.
+ bool SetOutputFileCss(const base::FilePath& path);
+
+ // Corresponds to --chrome_version.
+ bool SetChromeVersion(const std::string& version);
+
+ // Corresponds to --input_format / --output_format.
+ bool SetInputFormat(const std::string& format);
+ bool SetOutputFormat(const std::string& format);
+
+ private:
+ std::vector<base::FilePath> inputs_;
+
+ base::FilePath output_file_;
+ base::FilePath output_url_;
+ base::FilePath output_css_;
+
+ RulesetFormat input_format_ = RulesetFormat::kFilterList;
+ RulesetFormat output_format_ = RulesetFormat::kUnindexedRuleset;
+
+ // Increase this if rule_stream gets more custom logic for versions > 59.
+ int chrome_version_ = 59;
+
+ DISALLOW_COPY_AND_ASSIGN(RulesetConverter);
+};
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_CONVERTER_H_
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc
new file mode 100644
index 00000000000..76aed3c0bd5
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_converter_unittest.cc
@@ -0,0 +1,310 @@
+// 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 "components/subresource_filter/tools/ruleset_converter/ruleset_converter.h"
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+// Returns a small number of predefined rules in text format.
+std::vector<std::string> GetSomeRules() {
+ return std::vector<std::string>{
+ "example.com",
+ "||ex.com$image",
+ "|http://example.com/?key=value$~third-party,domain=ex.com",
+ "&key1=value1&key2=value2|$script,image,font",
+ "domain1.com,domain1.com###id",
+ "@@whitelisted.com$document,domain=example.com|~sub.example.com",
+ "###absolute_evil_id",
+ "@@whitelisted.com$match-case,document,domain=another.example.com",
+ "domain.com,~sub.domain.com,sub.sub.domain.com#@#id",
+ "#@#absolute_good_id",
+ "host$websocket",
+ };
+}
+
+base::CommandLine::StringType AsciiToNativeString(std::string ascii) {
+#if defined(OS_WIN)
+ return base::ASCIIToUTF16(ascii);
+#else
+ return ascii;
+#endif
+}
+
+class RulesetConverterTest : public testing::Test {
+ public:
+ RulesetConverterTest() { test_content_.AppendRules(GetSomeRules()); }
+ TestRulesetContents test_content_;
+};
+
+TEST_F(RulesetConverterTest, InputNotFound_Fails) {
+ RulesetConverter converter;
+ EXPECT_FALSE(converter.SetInputFiles(AsciiToNativeString("/not-a-file")));
+}
+
+TEST_F(RulesetConverterTest, NoInputFiles_Fails) {
+ RulesetConverter converter;
+ EXPECT_FALSE(converter.SetInputFiles(AsciiToNativeString("")));
+}
+
+TEST_F(RulesetConverterTest, OutputDirNotFound_Fails) {
+ RulesetConverter converter;
+ base::FilePath path(FILE_PATH_LITERAL("/not-a-dir/output"));
+ EXPECT_FALSE(converter.SetOutputFile(path));
+}
+
+TEST_F(RulesetConverterTest, BadInputFormat_Fails) {
+ RulesetConverter converter;
+ EXPECT_FALSE(converter.SetInputFormat("badformat"));
+}
+
+TEST_F(RulesetConverterTest, BadOutputFormat_Fails) {
+ RulesetConverter converter;
+ EXPECT_FALSE(converter.SetOutputFormat("badformat"));
+}
+
+TEST_F(RulesetConverterTest, BadChromeVersions_Fail) {
+ RulesetConverter converter;
+ EXPECT_FALSE(converter.SetChromeVersion("not-a-number"));
+ EXPECT_FALSE(converter.SetChromeVersion("1"));
+ EXPECT_FALSE(converter.SetChromeVersion("60"));
+}
+
+TEST_F(RulesetConverterTest, NoInput_Fails) {
+ RulesetConverter converter;
+ base::FilePath path(FILE_PATH_LITERAL("/output"));
+ EXPECT_TRUE(converter.SetOutputFile(path));
+ EXPECT_FALSE(converter.Convert());
+}
+
+TEST_F(RulesetConverterTest, NoOutput_Fails) {
+ RulesetConverter converter;
+ ScopedTempRulesetFile ruleset_file(RulesetFormat::kFilterList);
+ ruleset_file.WriteRuleset(test_content_);
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(ruleset_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_FALSE(converter.Convert());
+}
+
+TEST_F(RulesetConverterTest, InputAndOneOutput_Succeeds) {
+ RulesetConverter converter;
+ ScopedTempRulesetFile input_file(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_file(RulesetFormat::kUnindexedRuleset);
+
+ input_file.WriteRuleset(test_content_);
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFile(output_file.ruleset_path()));
+ EXPECT_TRUE(converter.Convert());
+}
+
+TEST_F(RulesetConverterTest, MultipleInputs) {
+ RulesetConverter converter;
+ ScopedTempRulesetFile input_1(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile input_2(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile input_3(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_file(RulesetFormat::kFilterList);
+
+ input_1.WriteRuleset(test_content_);
+
+ TestRulesetContents content_2;
+ content_2.AppendRules({"foo.com", "eggs*waffles.org"});
+ input_2.WriteRuleset(content_2);
+
+ TestRulesetContents content_3;
+ content_3.AppendRules({"@@bar.net/some/path"});
+ input_3.WriteRuleset(content_3);
+
+ std::string joined = base::JoinString({input_1.ruleset_path().AsUTF8Unsafe(),
+ input_2.ruleset_path().AsUTF8Unsafe(),
+ input_3.ruleset_path().AsUTF8Unsafe()},
+ ",");
+ EXPECT_TRUE(converter.SetInputFiles(AsciiToNativeString(joined)));
+ EXPECT_TRUE(converter.SetOutputFile(output_file.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.Convert());
+
+ TestRulesetContents expected_output = test_content_;
+ expected_output.AppendParsedRules(content_2);
+ expected_output.AppendParsedRules(content_3);
+ EXPECT_EQ(expected_output, output_file.ReadContents());
+}
+
+TEST_F(RulesetConverterTest, MultipleOutputs) {
+ RulesetConverter converter;
+ ScopedTempRulesetFile input_file(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_url(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_css(RulesetFormat::kFilterList);
+
+ input_file.WriteRuleset(test_content_);
+
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFileUrl(output_url.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFileCss(output_url.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.Convert());
+
+ TestRulesetContents expected_url_output;
+ expected_url_output.url_rules = test_content_.url_rules;
+ TestRulesetContents expected_css_output;
+ expected_url_output.css_rules = test_content_.css_rules;
+
+ EXPECT_EQ(expected_url_output, output_url.ReadContents());
+ EXPECT_EQ(expected_css_output, output_css.ReadContents());
+}
+
+TEST_F(RulesetConverterTest, UrlOutput) {
+ RulesetConverter converter;
+ ScopedTempRulesetFile input_file(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_url(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_css(RulesetFormat::kFilterList);
+
+ input_file.WriteRuleset(test_content_);
+
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFileUrl(output_url.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.Convert());
+
+ TestRulesetContents expected_url_output;
+ expected_url_output.url_rules = test_content_.url_rules;
+
+ // Expect no CSS output.
+ TestRulesetContents expected_css_output;
+
+ EXPECT_EQ(expected_url_output, output_url.ReadContents());
+ EXPECT_EQ(expected_css_output, output_css.ReadContents());
+}
+
+TEST_F(RulesetConverterTest, CssOutput) {
+ RulesetConverter converter;
+ ScopedTempRulesetFile input_file(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_url(RulesetFormat::kFilterList);
+ ScopedTempRulesetFile output_css(RulesetFormat::kFilterList);
+
+ input_file.WriteRuleset(test_content_);
+
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFileCss(output_css.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.Convert());
+
+ // Expect no URL output.
+ TestRulesetContents expected_url_output;
+
+ TestRulesetContents expected_css_output;
+ expected_css_output.css_rules = test_content_.css_rules;
+
+ EXPECT_EQ(expected_url_output, output_url.ReadContents());
+ EXPECT_EQ(expected_css_output, output_css.ReadContents());
+}
+
+TEST_F(RulesetConverterTest, ChromeVersions) {
+ ScopedTempRulesetFile input_file(RulesetFormat::kFilterList);
+
+ std::vector<std::string> kUnfriendlyRules{
+ // No Chrome version supports regexes.
+ "/a[0-9].com/$image",
+
+ // No Chrome version supports badly defined rules.
+ "a.com$image,~image",
+
+ // No Chrome version supports popups.
+ "a.com$popup",
+
+ // Only genericblock/document activations are supported.
+ "@@a.com$generichide", "@@a.com$elemhide",
+
+ // Chrome 59+ supports websocket.
+ "host.com$websocket",
+ };
+ TestRulesetContents unfriendly_contents;
+ unfriendly_contents.AppendRules(kUnfriendlyRules);
+ input_file.WriteRuleset(unfriendly_contents);
+ {
+ RulesetConverter converter;
+ ScopedTempRulesetFile output_file(RulesetFormat::kFilterList);
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFile(output_file.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.SetChromeVersion("0"));
+ EXPECT_TRUE(converter.Convert());
+ EXPECT_EQ(unfriendly_contents, output_file.ReadContents());
+ }
+ {
+ RulesetConverter converter;
+ ScopedTempRulesetFile output_file(RulesetFormat::kFilterList);
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFile(output_file.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.SetChromeVersion("54"));
+ EXPECT_TRUE(converter.Convert());
+ EXPECT_EQ(0u, output_file.ReadContents().url_rules.size());
+ }
+ {
+ RulesetConverter converter;
+ ScopedTempRulesetFile output_file(RulesetFormat::kFilterList);
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFile(output_file.ruleset_path()));
+ EXPECT_TRUE(converter.SetOutputFormat("filter-list"));
+ EXPECT_TRUE(converter.SetChromeVersion("59"));
+ EXPECT_TRUE(converter.Convert());
+
+ TestRulesetContents expected_contents;
+ expected_contents.AppendRules({"host.com$websocket"});
+ EXPECT_EQ(expected_contents, output_file.ReadContents());
+ }
+}
+
+TEST_F(RulesetConverterTest, FormatConversions) {
+ std::vector<std::string> kSupportedFormats = {"filter-list",
+ "unindexed-ruleset", "proto"};
+ for (const auto& input_format : kSupportedFormats) {
+ for (const auto& output_format : kSupportedFormats) {
+ SCOPED_TRACE(testing::Message() << "input: " << input_format
+ << " output: " << output_format);
+ RulesetConverter converter;
+ ScopedTempRulesetFile input_file(ParseFlag(input_format));
+ input_file.WriteRuleset(test_content_);
+
+ ScopedTempRulesetFile output_file(ParseFlag(output_format));
+ EXPECT_TRUE(converter.SetInputFiles(
+ AsciiToNativeString(input_file.ruleset_path().AsUTF8Unsafe())));
+ EXPECT_TRUE(converter.SetOutputFile(output_file.ruleset_path()));
+ EXPECT_TRUE(converter.SetInputFormat(input_format));
+ EXPECT_TRUE(converter.SetOutputFormat(output_format));
+ EXPECT_TRUE(converter.Convert());
+
+ TestRulesetContents input_contents = input_file.ReadContents();
+ TestRulesetContents output_contents = output_file.ReadContents();
+ TestRulesetContents expected_output;
+
+ // Unindexed format strips CSS rules.
+ if (output_format == "unindexed-ruleset" &&
+ input_format != output_format) {
+ expected_output.url_rules = input_contents.url_rules;
+ } else {
+ expected_output = input_contents;
+ }
+ EXPECT_EQ(expected_output, output_contents);
+ }
+ }
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.cc b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.cc
new file mode 100644
index 00000000000..0b09335a988
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.cc
@@ -0,0 +1,21 @@
+// 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 "components/subresource_filter/tools/ruleset_converter/ruleset_format.h"
+
+#include "base/strings/string_number_conversions.h"
+
+namespace subresource_filter {
+
+RulesetFormat ParseFlag(const std::string& text) {
+ if (text == "filter-list")
+ return RulesetFormat::kFilterList;
+ if (text == "proto")
+ return RulesetFormat::kProto;
+ if (text == "unindexed-ruleset")
+ return RulesetFormat::kUnindexedRuleset;
+ return RulesetFormat::kUndefined;
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.h b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.h
new file mode 100644
index 00000000000..55889d000b7
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_format.h
@@ -0,0 +1,32 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_FORMAT_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_FORMAT_H_
+
+#include <string>
+
+namespace subresource_filter {
+
+// Enumerates supported ruleset serialization formats.
+enum class RulesetFormat {
+ // The format is not defined.
+ kUndefined,
+ // Text representation of FilterList rules. See
+ // //components/subresource_filter/tools/rule_parser
+ // for details.
+ kFilterList,
+ // A serialized url_pattern_index::proto::FilteringRules message.
+ kProto,
+ // UnindexedRuleset format. See
+ // //components/subresource_filter/core/common/unindexed_ruleset.* for
+ // details.
+ kUnindexedRuleset,
+};
+
+RulesetFormat ParseFlag(const std::string& text);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_FORMAT_H_
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.cc b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.cc
new file mode 100644
index 00000000000..ae22b1284e8
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.cc
@@ -0,0 +1,143 @@
+// 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 "components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h"
+
+#include <fstream>
+#include <ios>
+#include <istream>
+
+#include "base/files/file_util.h"
+#include "components/subresource_filter/tools/rule_parser/rule_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace subresource_filter {
+
+TestRulesetContents::TestRulesetContents() = default;
+TestRulesetContents::~TestRulesetContents() = default;
+
+TestRulesetContents::TestRulesetContents(const TestRulesetContents& other)
+ : url_rules(other.url_rules), css_rules(other.css_rules) {}
+
+void TestRulesetContents::AppendRules(
+ const std::vector<std::string>& text_rules,
+ bool allow_errors) {
+ RuleParser parser;
+ for (const std::string& text_rule : text_rules) {
+ url_pattern_index::proto::RuleType rule_type = parser.Parse(text_rule);
+ switch (rule_type) {
+ case url_pattern_index::proto::RULE_TYPE_URL:
+ url_rules.push_back(parser.url_rule().ToProtobuf());
+ break;
+ case url_pattern_index::proto::RULE_TYPE_CSS:
+ css_rules.push_back(parser.css_rule().ToProtobuf());
+ break;
+ case url_pattern_index::proto::RULE_TYPE_UNSPECIFIED:
+ ASSERT_TRUE(allow_errors);
+ break;
+ default:
+ ASSERT_TRUE(false);
+ }
+ }
+}
+
+void TestRulesetContents::AppendParsedRules(const TestRulesetContents& other) {
+ url_rules.insert(url_rules.end(), other.url_rules.begin(),
+ other.url_rules.end());
+ css_rules.insert(css_rules.end(), other.css_rules.begin(),
+ other.css_rules.end());
+}
+
+bool TestRulesetContents::operator==(const TestRulesetContents& other) const {
+ if (url_rules.size() != other.url_rules.size() ||
+ css_rules.size() != other.css_rules.size()) {
+ return false;
+ }
+ for (size_t i = 0; i < url_rules.size(); ++i) {
+ if (!AreUrlRulesEqual(url_rules[i], other.url_rules[i]))
+ return false;
+ }
+ for (size_t i = 0; i < css_rules.size(); ++i) {
+ if (!AreCssRulesEqual(css_rules[i], other.css_rules[i]))
+ return false;
+ }
+ return true;
+}
+
+std::ostream& operator<<(std::ostream& out,
+ const TestRulesetContents& contents) {
+ for (const auto& rule : contents.url_rules) {
+ out << ToString(rule) << "\n";
+ }
+ for (const auto& rule : contents.css_rules) {
+ out << ToString(rule) << "\n";
+ }
+ return out;
+}
+
+ScopedTempRulesetFile::ScopedTempRulesetFile(RulesetFormat format)
+ : format_(format) {
+ // Cannot ASSERT due to returning in constructor.
+ CHECK(scoped_dir_.CreateUniqueTempDir());
+ CHECK(base::CreateTemporaryFileInDir(scoped_dir_.GetPath(), &ruleset_path_));
+}
+
+ScopedTempRulesetFile::~ScopedTempRulesetFile() = default;
+
+std::unique_ptr<RuleOutputStream> ScopedTempRulesetFile::OpenForOutput() const {
+ return RuleOutputStream::Create(
+ std::make_unique<std::ofstream>(ruleset_path().MaybeAsASCII(),
+ std::ios::binary | std::ios::out),
+ format());
+}
+
+// Opens the |ruleset_file| with already existing ruleset and returns the
+// corresponding input stream, or nullptr if it failed to be created.
+std::unique_ptr<RuleInputStream> ScopedTempRulesetFile::OpenForInput() const {
+ return RuleInputStream::Create(
+ std::make_unique<std::ifstream>(ruleset_path().MaybeAsASCII(),
+ std::ios::binary | std::ios::in),
+ format());
+}
+
+void ScopedTempRulesetFile::WriteRuleset(
+ const TestRulesetContents& contents) const {
+ std::unique_ptr<RuleOutputStream> output = OpenForOutput();
+ ASSERT_NE(nullptr, output);
+
+ for (const auto& rule : contents.url_rules)
+ EXPECT_TRUE(output->PutUrlRule(rule));
+ for (const auto& rule : contents.css_rules)
+ EXPECT_TRUE(output->PutCssRule(rule));
+ EXPECT_TRUE(output->Finish());
+}
+
+TestRulesetContents ScopedTempRulesetFile::ReadContents() const {
+ std::unique_ptr<RuleInputStream> input = OpenForInput();
+ TestRulesetContents contents;
+ url_pattern_index::proto::RuleType rule_type =
+ url_pattern_index::proto::RULE_TYPE_UNSPECIFIED;
+ while ((rule_type = input->FetchNextRule()) !=
+ url_pattern_index::proto::RULE_TYPE_UNSPECIFIED) {
+ if (rule_type == url_pattern_index::proto::RULE_TYPE_URL) {
+ contents.url_rules.push_back(input->GetUrlRule());
+ } else {
+ CHECK_EQ(url_pattern_index::proto::RULE_TYPE_CSS, rule_type);
+ contents.css_rules.push_back(input->GetCssRule());
+ }
+ }
+ return contents;
+}
+
+bool AreUrlRulesEqual(const url_pattern_index::proto::UrlRule& first,
+ const url_pattern_index::proto::UrlRule& second) {
+ return first.SerializeAsString() == second.SerializeAsString();
+}
+
+bool AreCssRulesEqual(const url_pattern_index::proto::CssRule& first,
+ const url_pattern_index::proto::CssRule& second) {
+ return first.SerializeAsString() == second.SerializeAsString();
+}
+
+} // namespace subresource_filter
diff --git a/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h
new file mode 100644
index 00000000000..c2525be54b9
--- /dev/null
+++ b/chromium/components/subresource_filter/tools/ruleset_converter/ruleset_test_util.h
@@ -0,0 +1,83 @@
+// 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 COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_TEST_UTIL_H_
+#define COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_TEST_UTIL_H_
+
+#include <memory>
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "components/subresource_filter/tools/ruleset_converter/rule_stream.h"
+#include "components/subresource_filter/tools/ruleset_converter/ruleset_format.h"
+#include "components/url_pattern_index/proto/rules.pb.h"
+
+namespace subresource_filter {
+
+// Stores lists of the rules that a test ruleset consists of.
+struct TestRulesetContents {
+ TestRulesetContents();
+ TestRulesetContents(const TestRulesetContents& other);
+ ~TestRulesetContents();
+
+ std::vector<url_pattern_index::proto::UrlRule> url_rules;
+ std::vector<url_pattern_index::proto::CssRule> css_rules;
+
+ // Parses |text_rules| and appends them to the |ruleset|.
+ void AppendRules(const std::vector<std::string>& text_rules,
+ bool allow_errors = false);
+
+ // Extends this TestRulesetContents rules with rules from |other|.
+ void AppendParsedRules(const TestRulesetContents& other);
+
+ bool operator==(const TestRulesetContents& other) const;
+};
+std::ostream& operator<<(std::ostream& out,
+ const TestRulesetContents& contents);
+
+// Stores identification information about a temporary File with a ruleset.
+// Deletes the file automatically on destruction.
+class ScopedTempRulesetFile {
+ public:
+ // Creates a temporary file of the specified |format|.
+ explicit ScopedTempRulesetFile(RulesetFormat format);
+ ~ScopedTempRulesetFile();
+
+ // Opens the |ruleset_file| and creates an empty rule output stream to this
+ // file. Returns the stream or nullptr if it failed to be created.
+ std::unique_ptr<RuleOutputStream> OpenForOutput() const;
+
+ // Opens the |ruleset_file| and returns the corresponding input stream, or
+ // nullptr if it failed to be created.
+ std::unique_ptr<RuleInputStream> OpenForInput() const;
+
+ // Opens the |ruleset_file|, and writes the test ruleset |contents| to it in
+ // the corresponding format.
+ void WriteRuleset(const TestRulesetContents& contents) const;
+
+ TestRulesetContents ReadContents() const;
+
+ const base::FilePath& ruleset_path() const { return ruleset_path_; }
+ RulesetFormat format() const { return format_; }
+
+ private:
+ base::ScopedTempDir scoped_dir_;
+ base::FilePath ruleset_path_;
+ const RulesetFormat format_; // The format of the |file|.
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedTempRulesetFile);
+};
+
+bool AreUrlRulesEqual(const url_pattern_index::proto::UrlRule& first,
+ const url_pattern_index::proto::UrlRule& second);
+
+bool AreCssRulesEqual(const url_pattern_index::proto::CssRule& first,
+ const url_pattern_index::proto::CssRule& second);
+
+} // namespace subresource_filter
+
+#endif // COMPONENTS_SUBRESOURCE_FILTER_TOOLS_RULESET_CONVERTER_RULESET_TEST_UTIL_H_
diff --git a/chromium/components/suggestions/image_manager.cc b/chromium/components/suggestions/image_manager.cc
index 9e63123b469..d8f1007e371 100644
--- a/chromium/components/suggestions/image_manager.cc
+++ b/chromium/components/suggestions/image_manager.cc
@@ -175,7 +175,7 @@ void ImageManager::OnCacheImageDecoded(const GURL& url,
const GURL& image_url,
const ImageCallback& callback,
std::unique_ptr<SkBitmap> bitmap) {
- if (bitmap.get()) {
+ if (bitmap) {
callback.Run(url, gfx::Image::CreateFrom1xBitmap(*bitmap));
} else {
image_fetcher_->FetchImage(
@@ -200,7 +200,7 @@ void ImageManager::ServeFromCacheOrNetwork(const GURL& url,
ImageCallback callback) {
scoped_refptr<base::RefCountedMemory> encoded_data =
GetEncodedImageFromCache(url);
- if (encoded_data.get()) {
+ if (encoded_data) {
base::PostTaskAndReplyWithResult(
background_task_runner_.get(), FROM_HERE,
base::Bind(&DecodeImage, encoded_data),
diff --git a/chromium/components/suggestions/suggestions_service_impl.cc b/chromium/components/suggestions/suggestions_service_impl.cc
index d999bfb5ef4..e55b28d8ff3 100644
--- a/chromium/components/suggestions/suggestions_service_impl.cc
+++ b/chromium/components/suggestions/suggestions_service_impl.cc
@@ -198,7 +198,7 @@ bool SuggestionsServiceImpl::BlacklistURL(const GURL& candidate_url) {
// Blacklist uploads are scheduled on any request completion, so only schedule
// an upload if there is no ongoing request.
- if (!pending_request_.get())
+ if (!pending_request_)
ScheduleBlacklistUpload();
return true;
@@ -238,7 +238,7 @@ base::TimeDelta SuggestionsServiceImpl::BlacklistDelayForTesting() const {
}
bool SuggestionsServiceImpl::HasPendingRequestForTesting() const {
- return !!pending_request_.get();
+ return !!pending_request_;
}
// static
@@ -370,7 +370,7 @@ void SuggestionsServiceImpl::IssueRequestIfNoneOngoing(const GURL& url) {
// request happens to be ongoing.
// TODO(treib): Queue such requests and send them after the current one
// completes.
- if (pending_request_.get())
+ if (pending_request_)
return;
// If there is an ongoing token request, also wait for that.
if (token_fetcher_)
@@ -554,6 +554,8 @@ void SuggestionsServiceImpl::PopulateExtraData(
void SuggestionsServiceImpl::Shutdown() {
// Cancel pending request.
pending_request_.reset(nullptr);
+
+ sync_service_observer_.RemoveAll();
}
void SuggestionsServiceImpl::ScheduleBlacklistUpload() {
diff --git a/chromium/components/suggestions/suggestions_service_impl_unittest.cc b/chromium/components/suggestions/suggestions_service_impl_unittest.cc
index e99c5d92858..2c906e3285a 100644
--- a/chromium/components/suggestions/suggestions_service_impl_unittest.cc
+++ b/chromium/components/suggestions/suggestions_service_impl_unittest.cc
@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
+#include <vector>
#include "base/bind.h"
#include "base/macros.h"
@@ -83,7 +84,7 @@ SuggestionsProfile CreateSuggestionsProfile() {
class MockSyncService : public syncer::FakeSyncService {
public:
MockSyncService() {}
- virtual ~MockSyncService() {}
+ ~MockSyncService() override {}
MOCK_CONST_METHOD0(CanSyncStart, bool());
MOCK_CONST_METHOD0(IsSyncActive, bool());
MOCK_CONST_METHOD0(ConfigurationDone, bool());
@@ -115,7 +116,7 @@ class TestSuggestionsStore : public suggestions::SuggestionsStore {
class MockImageManager : public suggestions::ImageManager {
public:
MockImageManager() {}
- virtual ~MockImageManager() {}
+ ~MockImageManager() override {}
MOCK_METHOD1(Initialize, void(const SuggestionsProfile&));
MOCK_METHOD2(GetImageForURL,
void(const GURL&,
@@ -182,7 +183,10 @@ class SuggestionsServiceTest : public testing::Test {
2, 7, false, 0, base::Time::Now(), base::Time::Now(),
std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
std::vector<int>(syncer::MODEL_TYPE_COUNT, 0),
- sync_pb::SyncEnums::UNKNOWN_ORIGIN)));
+ sync_pb::SyncEnums::UNKNOWN_ORIGIN,
+ /*short_poll_interval=*/base::TimeDelta::FromMinutes(30),
+ /*long_poll_interval=*/base::TimeDelta::FromMinutes(180),
+ /*has_remaining_local_changes=*/false)));
// These objects are owned by the SuggestionsService, but we keep the
// pointers around for testing.
test_suggestions_store_ = new TestSuggestionsStore();
@@ -436,7 +440,7 @@ TEST_F(SuggestionsServiceTest, FetchSuggestionsDataNoAccessToken) {
suggestions_service()->FetchSuggestionsData();
- identity_test_env()->WaitForAccessTokenRequestAndRespondWithError(
+ identity_test_env()->WaitForAccessTokenRequestIfNecessaryAndRespondWithError(
GoogleServiceAuthError(
GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
diff --git a/chromium/components/supervised_user_error_page_strings_grdp/OWNERS b/chromium/components/supervised_user_error_page_strings_grdp/OWNERS
new file mode 100644
index 00000000000..0ba46ac8d26
--- /dev/null
+++ b/chromium/components/supervised_user_error_page_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/supervised_user_error_page/OWNERS
diff --git a/chromium/components/supervised_user_error_page_strings_grdp/README.md b/chromium/components/supervised_user_error_page_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/supervised_user_error_page_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/sync/BUILD.gn b/chromium/components/sync/BUILD.gn
index 1a49fc1f87e..a799b4cd861 100644
--- a/chromium/components/sync/BUILD.gn
+++ b/chromium/components/sync/BUILD.gn
@@ -141,8 +141,6 @@ jumbo_static_library("sync") {
"driver/sync_error_controller.h",
"driver/sync_service.cc",
"driver/sync_service.h",
- "driver/sync_service_base.cc",
- "driver/sync_service_base.h",
"driver/sync_service_crypto.cc",
"driver/sync_service_crypto.h",
"driver/sync_service_observer.cc",
@@ -151,6 +149,8 @@ jumbo_static_library("sync") {
"driver/sync_service_utils.h",
"driver/sync_stopped_reporter.cc",
"driver/sync_stopped_reporter.h",
+ "driver/sync_token_status.cc",
+ "driver/sync_token_status.h",
"driver/sync_type_preference_provider.h",
"driver/sync_util.cc",
"driver/sync_util.h",
@@ -214,12 +214,16 @@ jumbo_static_library("sync") {
"engine/sync_auth_provider.h",
"engine/sync_backend_registrar.cc",
"engine/sync_backend_registrar.h",
+ "engine/sync_credentials.cc",
+ "engine/sync_credentials.h",
"engine/sync_encryption_handler.cc",
"engine/sync_encryption_handler.h",
"engine/sync_engine.cc",
"engine/sync_engine.h",
"engine/sync_engine_host.cc",
"engine/sync_engine_host.h",
+ "engine/sync_engine_switches.cc",
+ "engine/sync_engine_switches.h",
"engine/sync_manager.cc",
"engine/sync_manager.h",
"engine/sync_manager_factory.cc",
@@ -395,8 +399,6 @@ jumbo_static_library("sync") {
"model/model_error.h",
"model/model_type_change_processor.cc",
"model/model_type_change_processor.h",
- "model/model_type_debug_info.cc",
- "model/model_type_debug_info.h",
"model/model_type_store.cc",
"model/model_type_store.h",
"model/model_type_sync_bridge.cc",
@@ -487,8 +489,6 @@ jumbo_static_library("sync") {
"syncable/scoped_kernel_lock.h",
"syncable/scoped_parent_child_index_updater.cc",
"syncable/scoped_parent_child_index_updater.h",
- "syncable/sync_db_util.cc",
- "syncable/sync_db_util.h",
"syncable/syncable_base_transaction.cc",
"syncable/syncable_base_transaction.h",
"syncable/syncable_base_write_transaction.cc",
@@ -714,6 +714,8 @@ static_library("test_support_model") {
"model/data_type_error_handler_mock.h",
"model/fake_model_type_change_processor.cc",
"model/fake_model_type_change_processor.h",
+ "model/fake_model_type_controller_delegate.cc",
+ "model/fake_model_type_controller_delegate.h",
"model/fake_model_type_sync_bridge.cc",
"model/fake_model_type_sync_bridge.h",
"model/fake_sync_change_processor.cc",
diff --git a/chromium/components/sync/protocol/protocol_sources.gni b/chromium/components/sync/protocol/protocol_sources.gni
index 3212373de8f..bf4501877bf 100644
--- a/chromium/components/sync/protocol/protocol_sources.gni
+++ b/chromium/components/sync/protocol/protocol_sources.gni
@@ -27,13 +27,14 @@ sync_protocol_sources = [
"//components/sync/protocol/history_delete_directive_specifics.proto",
"//components/sync/protocol/history_status.proto",
"//components/sync/protocol/loopback_server.proto",
- "//components/sync/protocol/nigori_specifics.proto",
"//components/sync/protocol/managed_user_setting_specifics.proto",
"//components/sync/protocol/managed_user_shared_setting_specifics.proto",
"//components/sync/protocol/managed_user_specifics.proto",
"//components/sync/protocol/managed_user_whitelist_specifics.proto",
"//components/sync/protocol/model_type_state.proto",
"//components/sync/protocol/model_type_store_schema_descriptor.proto",
+ "//components/sync/protocol/mountain_share_specifics.proto",
+ "//components/sync/protocol/nigori_specifics.proto",
"//components/sync/protocol/password_specifics.proto",
"//components/sync/protocol/preference_specifics.proto",
"//components/sync/protocol/printer_specifics.proto",
@@ -49,6 +50,8 @@ sync_protocol_sources = [
"//components/sync/protocol/theme_specifics.proto",
"//components/sync/protocol/typed_url_specifics.proto",
"//components/sync/protocol/unique_position.proto",
+ "//components/sync/protocol/user_consent_specifics.proto",
+ "//components/sync/protocol/user_consent_types.proto",
"//components/sync/protocol/user_event_specifics.proto",
"//components/sync/protocol/wifi_credential_specifics.proto",
]
diff --git a/chromium/components/sync_bookmarks/BUILD.gn b/chromium/components/sync_bookmarks/BUILD.gn
index 09110f92ce3..eecc87f7ce1 100644
--- a/chromium/components/sync_bookmarks/BUILD.gn
+++ b/chromium/components/sync_bookmarks/BUILD.gn
@@ -16,6 +16,8 @@ static_library("sync_bookmarks") {
"bookmark_model_type_controller.h",
"bookmark_model_type_processor.cc",
"bookmark_model_type_processor.h",
+ "synced_bookmark_tracker.cc",
+ "synced_bookmark_tracker.h",
]
deps = [
@@ -36,6 +38,7 @@ source_set("unit_tests") {
"bookmark_data_type_controller_unittest.cc",
"bookmark_model_type_controller_unittest.cc",
"bookmark_model_type_processor_unittest.cc",
+ "synced_bookmark_tracker_unittest.cc",
]
deps = [
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc b/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc
index ccc49f88cf2..678334e0eb3 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_controller.cc
@@ -68,12 +68,15 @@ void BookmarkModelTypeController::RegisterWithBackend(
base::Callback<void(bool)> set_downloaded,
syncer::ModelTypeConfigurer* configurer) {
DCHECK(CalledOnValidThread());
+ if (activated_)
+ return;
DCHECK(configurer);
std::unique_ptr<syncer::ActivationContext> activation_context =
PrepareActivationContext();
set_downloaded.Run(activation_context->model_type_state.initial_sync_done());
configurer->ActivateNonBlockingDataType(type(),
std::move(activation_context));
+ activated_ = true;
}
void BookmarkModelTypeController::StartAssociating(
@@ -92,13 +95,17 @@ void BookmarkModelTypeController::StartAssociating(
void BookmarkModelTypeController::ActivateDataType(
syncer::ModelTypeConfigurer* configurer) {
DCHECK(CalledOnValidThread());
- NOTIMPLEMENTED();
+ DCHECK(configurer);
+ DCHECK_EQ(RUNNING, state_);
}
void BookmarkModelTypeController::DeactivateDataType(
syncer::ModelTypeConfigurer* configurer) {
DCHECK(CalledOnValidThread());
- NOTIMPLEMENTED();
+ if (activated_) {
+ configurer->DeactivateNonBlockingDataType(type());
+ activated_ = false;
+ }
}
void BookmarkModelTypeController::Stop() {
@@ -158,7 +165,8 @@ BookmarkModelTypeController::PrepareActivationContext() {
directory->InitialSyncEndedForType(type()));
// TODO(pavely): Populate model_type_state.type_context.
- model_type_processor_ = std::make_unique<BookmarkModelTypeProcessor>();
+ model_type_processor_ =
+ std::make_unique<BookmarkModelTypeProcessor>(sync_client_);
activation_context->type_processor =
std::make_unique<syncer::ModelTypeProcessorProxy>(
model_type_processor_->GetWeakPtr(),
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_controller.h b/chromium/components/sync_bookmarks/bookmark_model_type_controller.h
index daf3b1a130c..42451be5466 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_controller.h
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_controller.h
@@ -61,6 +61,12 @@ class BookmarkModelTypeController : public syncer::DataTypeController {
// BookmarkModel/HistoryService.
std::unique_ptr<BookmarkModelTypeProcessor> model_type_processor_;
+ // This is a hack to prevent reconfigurations from crashing, because USS
+ // activation is not idempotent. RegisterWithBackend only needs to actually do
+ // something the first time after the type is enabled.
+ // TODO(crbug.com/647505): Remove this once the DTM handles things better.
+ bool activated_ = false;
+
DISALLOW_COPY_AND_ASSIGN(BookmarkModelTypeController);
};
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
index ccac311794b..d65bec249b0 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.cc
@@ -7,13 +7,128 @@
#include <utility>
#include "base/callback.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_model.h"
#include "components/sync/base/model_type.h"
+#include "components/sync/driver/sync_client.h"
#include "components/sync/engine/commit_queue.h"
+#include "components/undo/bookmark_undo_utils.h"
namespace sync_bookmarks {
-BookmarkModelTypeProcessor::BookmarkModelTypeProcessor()
- : weak_ptr_factory_(this) {}
+namespace {
+
+// The sync protocol identifies top-level entities by means of well-known tags,
+// (aka server defined tags) which should not be confused with titles or client
+// tags that aren't supported by bookmarks (at the time of writing). Each tag
+// corresponds to a singleton instance of a particular top-level node in a
+// user's share; the tags are consistent across users. The tags allow us to
+// locate the specific folders whose contents we care about synchronizing,
+// without having to do a lookup by name or path. The tags should not be made
+// user-visible. For example, the tag "bookmark_bar" represents the permanent
+// node for bookmarks bar in Chrome. The tag "other_bookmarks" represents the
+// permanent folder Other Bookmarks in Chrome.
+//
+// It is the responsibility of something upstream (at time of writing, the sync
+// server) to create these tagged nodes when initializing sync for the first
+// time for a user. Thus, once the backend finishes initializing, the
+// ProfileSyncService can rely on the presence of tagged nodes.
+const char kBookmarkBarTag[] = "bookmark_bar";
+const char kMobileBookmarksTag[] = "synced_bookmarks";
+const char kOtherBookmarksTag[] = "other_bookmarks";
+
+// Id is created by concatenating the specifics field number and the server tag
+// similar to LookbackServerEntity::CreateId() that uses
+// GetSpecificsFieldNumberFromModelType() to compute the field number.
+static const char kBookmarksRootId[] = "32904_google_chrome_bookmarks";
+
+// |sync_entity| must contain a bookmark specifics.
+// Metainfo entries must have unique keys.
+bookmarks::BookmarkNode::MetaInfoMap GetBookmarkMetaInfo(
+ const syncer::EntityData& sync_entity) {
+ const sync_pb::BookmarkSpecifics& specifics =
+ sync_entity.specifics.bookmark();
+ bookmarks::BookmarkNode::MetaInfoMap meta_info_map;
+ for (const sync_pb::MetaInfo& meta_info : specifics.meta_info()) {
+ meta_info_map[meta_info.key()] = meta_info.value();
+ }
+ DCHECK_EQ(static_cast<size_t>(specifics.meta_info_size()),
+ meta_info_map.size());
+ return meta_info_map;
+}
+
+// Creates a bookmark node under the given parent node from the given sync node.
+// Returns the newly created node. |sync_entity| must contain a bookmark
+// specifics with Metainfo entries having unique keys.
+const bookmarks::BookmarkNode* CreateBookmarkNode(
+ const syncer::EntityData& sync_entity,
+ const bookmarks::BookmarkNode* parent,
+ bookmarks::BookmarkModel* model,
+ syncer::SyncClient* sync_client,
+ int index) {
+ DCHECK(parent);
+ DCHECK(model);
+ DCHECK(sync_client);
+
+ const sync_pb::BookmarkSpecifics& specifics =
+ sync_entity.specifics.bookmark();
+ bookmarks::BookmarkNode::MetaInfoMap metainfo =
+ GetBookmarkMetaInfo(sync_entity);
+ if (sync_entity.is_folder) {
+ return model->AddFolderWithMetaInfo(
+ parent, index, base::UTF8ToUTF16(specifics.title()), &metainfo);
+ }
+ // 'creation_time_us' was added in M24. Assume a time of 0 means now.
+ const int64_t create_time_us = specifics.creation_time_us();
+ base::Time create_time =
+ (create_time_us == 0)
+ ? base::Time::Now()
+ : base::Time::FromDeltaSinceWindowsEpoch(
+ // Use FromDeltaSinceWindowsEpoch because create_time_us has
+ // always used the Windows epoch.
+ base::TimeDelta::FromMicroseconds(create_time_us));
+ return model->AddURLWithCreationTimeAndMetaInfo(
+ parent, index, base::UTF8ToUTF16(specifics.title()),
+ GURL(specifics.url()), create_time, &metainfo);
+ // TODO(crbug.com/516866): Add the favicon related code.
+}
+
+class ScopedRemoteUpdateBookmarks {
+ public:
+ // |bookmark_model| must not be null and must outlive this object.
+ explicit ScopedRemoteUpdateBookmarks(syncer::SyncClient* const sync_client)
+ : sync_client_(sync_client),
+ suspend_undo_(sync_client->GetBookmarkUndoServiceIfExists()) {
+ // Notify UI intensive observers of BookmarkModel that we are about to make
+ // potentially significant changes to it, so the updates may be batched. For
+ // example, on Mac, the bookmarks bar displays animations when bookmark
+ // items are added or deleted.
+ sync_client_->GetBookmarkModel()->BeginExtensiveChanges();
+ }
+
+ ~ScopedRemoteUpdateBookmarks() {
+ // Notify UI intensive observers of BookmarkModel that all updates have been
+ // applied, and that they may now be consumed. This prevents issues like the
+ // one described in https://crbug.com/281562, where old and new items on the
+ // bookmarks bar would overlap.
+ sync_client_->GetBookmarkModel()->EndExtensiveChanges();
+ }
+
+ private:
+ syncer::SyncClient* const sync_client_;
+
+ // Changes made to the bookmark model due to sync should not be undoable.
+ ScopedSuspendBookmarkUndo suspend_undo_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedRemoteUpdateBookmarks);
+};
+} // namespace
+
+BookmarkModelTypeProcessor::BookmarkModelTypeProcessor(
+ syncer::SyncClient* sync_client)
+ : sync_client_(sync_client),
+ bookmark_model_(sync_client->GetBookmarkModel()),
+ weak_ptr_factory_(this) {}
BookmarkModelTypeProcessor::~BookmarkModelTypeProcessor() = default;
@@ -49,7 +164,228 @@ void BookmarkModelTypeProcessor::OnUpdateReceived(
const sync_pb::ModelTypeState& model_type_state,
const syncer::UpdateResponseDataList& updates) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- NOTIMPLEMENTED();
+
+ ScopedRemoteUpdateBookmarks update_bookmarks(sync_client_);
+
+ for (const syncer::UpdateResponseData* update : ReorderUpdates(updates)) {
+ const syncer::EntityData& update_data = update->entity.value();
+ // TODO(crbug.com/516866): Check |update_data| for sanity.
+ // 1. Has bookmark specifics or no specifics in case of delete.
+ // 2. All meta info entries in the specifics have unique keys.
+ const SyncedBookmarkTracker::Entity* tracked_entity =
+ bookmark_tracker_.GetEntityForSyncId(update_data.id);
+ if (update_data.is_deleted()) {
+ ProcessRemoteDelete(update_data, tracked_entity);
+ continue;
+ }
+ if (!tracked_entity) {
+ ProcessRemoteCreate(update_data);
+ continue;
+ }
+ // Ignore changes to the permanent nodes (e.g. bookmarks bar). We only care
+ // about their children.
+ if (bookmark_model_->is_permanent_node(tracked_entity->bookmark_node())) {
+ continue;
+ }
+ ProcessRemoteUpdate(update_data, tracked_entity);
+ }
+}
+
+// static
+std::vector<const syncer::UpdateResponseData*>
+BookmarkModelTypeProcessor::ReorderUpdatesForTest(
+ const syncer::UpdateResponseDataList& updates) {
+ return ReorderUpdates(updates);
+}
+
+const SyncedBookmarkTracker* BookmarkModelTypeProcessor::GetTrackerForTest()
+ const {
+ return &bookmark_tracker_;
+}
+
+// static
+std::vector<const syncer::UpdateResponseData*>
+BookmarkModelTypeProcessor::ReorderUpdates(
+ const syncer::UpdateResponseDataList& updates) {
+ // TODO(crbug.com/516866): This is a very simple (hacky) reordering algorithm
+ // that assumes no folders exist except the top level permanent ones. This
+ // should be fixed before enabling USS for bookmarks.
+ std::vector<const syncer::UpdateResponseData*> ordered_updates;
+ for (const syncer::UpdateResponseData& update : updates) {
+ const syncer::EntityData& update_data = update.entity.value();
+ if (update_data.parent_id == "0") {
+ continue;
+ }
+ if (update_data.parent_id == kBookmarksRootId) {
+ ordered_updates.push_back(&update);
+ }
+ }
+ for (const syncer::UpdateResponseData& update : updates) {
+ const syncer::EntityData& update_data = update.entity.value();
+ // Deletions should come last.
+ if (update_data.is_deleted()) {
+ continue;
+ }
+ if (update_data.parent_id != "0" &&
+ update_data.parent_id != kBookmarksRootId) {
+ ordered_updates.push_back(&update);
+ }
+ }
+ // Now add deletions.
+ for (const syncer::UpdateResponseData& update : updates) {
+ const syncer::EntityData& update_data = update.entity.value();
+ if (!update_data.is_deleted()) {
+ continue;
+ }
+ if (update_data.parent_id != "0" &&
+ update_data.parent_id != kBookmarksRootId) {
+ ordered_updates.push_back(&update);
+ }
+ }
+ return ordered_updates;
+}
+
+void BookmarkModelTypeProcessor::ProcessRemoteCreate(
+ const syncer::EntityData& update_data) {
+ // Because the Synced Bookmarks node can be created server side, it's possible
+ // it'll arrive at the client as an update. In that case it won't have been
+ // associated at startup, the GetChromeNodeFromSyncId call above will return
+ // null, and we won't detect it as a permanent node, resulting in us trying to
+ // create it here (which will fail). Therefore, we add special logic here just
+ // to detect the Synced Bookmarks folder.
+ if (update_data.parent_id == kBookmarksRootId) {
+ // Associate permanent folders.
+ AssociatePermanentFolder(update_data);
+ return;
+ }
+
+ const bookmarks::BookmarkNode* parent_node = GetParentNode(update_data);
+ if (!parent_node) {
+ // If we cannot find the parent, we can do nothing.
+ DLOG(ERROR) << "Could not find parent of node being added."
+ << " Node title: " << update_data.specifics.bookmark().title()
+ << ", parent id = " << update_data.parent_id;
+ return;
+ }
+ // TODO(crbug.com/516866): This code appends the code to the very end of the
+ // list of the children by assigning the index to the
+ // parent_node->child_count(). It should instead compute the exact using the
+ // unique position information of the new node as well as the siblings.
+ const bookmarks::BookmarkNode* bookmark_node =
+ CreateBookmarkNode(update_data, parent_node, bookmark_model_,
+ sync_client_, parent_node->child_count());
+ if (!bookmark_node) {
+ // We ignore bookmarks we can't add.
+ DLOG(ERROR) << "Failed to create bookmark node with title "
+ << update_data.specifics.bookmark().title() << " and url "
+ << update_data.specifics.bookmark().url();
+ return;
+ }
+ bookmark_tracker_.Associate(update_data.id, bookmark_node);
+ // TODO(crbug.com/516866): Update metadata (e.g. server version,
+ // specifics_hash).
+}
+
+void BookmarkModelTypeProcessor::ProcessRemoteUpdate(
+ const syncer::EntityData& update_data,
+ const SyncedBookmarkTracker::Entity* tracked_entity) {
+ // Can only update existing nodes.
+ DCHECK(tracked_entity);
+ DCHECK_EQ(tracked_entity,
+ bookmark_tracker_.GetEntityForSyncId(update_data.id));
+ // Must no be a deletion
+ DCHECK(!update_data.is_deleted());
+ if (tracked_entity->IsUnsynced()) {
+ // TODO(crbug.com/516866): Handle conflict resolution.
+ return;
+ }
+ if (tracked_entity->MatchesData(update_data)) {
+ // TODO(crbug.com/516866): Update metadata (e.g. server version,
+ // specifics_hash).
+ return;
+ }
+ const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
+ if (update_data.is_folder != node->is_folder()) {
+ DLOG(ERROR) << "Could not update node. Remote node is a "
+ << (update_data.is_folder ? "folder" : "bookmark")
+ << " while local node is a "
+ << (node->is_folder() ? "folder" : "bookmark");
+ return;
+ }
+ const sync_pb::BookmarkSpecifics& specifics =
+ update_data.specifics.bookmark();
+ if (!update_data.is_folder) {
+ bookmark_model_->SetURL(node, GURL(specifics.url()));
+ }
+
+ bookmark_model_->SetTitle(node, base::UTF8ToUTF16(specifics.title()));
+ // TODO(crbug.com/516866): Add the favicon related code.
+ bookmark_model_->SetNodeMetaInfoMap(node, GetBookmarkMetaInfo(update_data));
+ // TODO(crbug.com/516866): Update metadata (e.g. server version,
+ // specifics_hash).
+ // TODO(crbug.com/516866): Handle reparenting.
+ // TODO(crbug.com/516866): Handle the case of moving the bookmark to a new
+ // position under the same parent (i.e. change in the unique position)
+}
+
+void BookmarkModelTypeProcessor::ProcessRemoteDelete(
+ const syncer::EntityData& update_data,
+ const SyncedBookmarkTracker::Entity* tracked_entity) {
+ DCHECK(update_data.is_deleted());
+
+ DCHECK_EQ(tracked_entity,
+ bookmark_tracker_.GetEntityForSyncId(update_data.id));
+
+ // Handle corner cases first.
+ if (tracked_entity == nullptr) {
+ // Local entity doesn't exist and update is tombstone.
+ DLOG(WARNING) << "Received remote delete for a non-existing item.";
+ return;
+ }
+
+ const bookmarks::BookmarkNode* node = tracked_entity->bookmark_node();
+ // Ignore changes to the permanent top-level nodes. We only care about
+ // their children.
+ if (bookmark_model_->is_permanent_node(node)) {
+ return;
+ }
+ // TODO(crbug.com/516866): Allow deletions of non-empty direcoties if makes
+ // sense, and recursively delete children.
+ if (node->child_count() > 0) {
+ DLOG(WARNING) << "Trying to delete a non-empty folder.";
+ return;
+ }
+
+ bookmark_model_->Remove(node);
+ bookmark_tracker_.Disassociate(update_data.id);
+}
+
+const bookmarks::BookmarkNode* BookmarkModelTypeProcessor::GetParentNode(
+ const syncer::EntityData& update_data) const {
+ const SyncedBookmarkTracker::Entity* parent_entity =
+ bookmark_tracker_.GetEntityForSyncId(update_data.parent_id);
+ if (!parent_entity) {
+ return nullptr;
+ }
+ return parent_entity->bookmark_node();
+}
+
+void BookmarkModelTypeProcessor::AssociatePermanentFolder(
+ const syncer::EntityData& update_data) {
+ DCHECK_EQ(update_data.parent_id, kBookmarksRootId);
+
+ const bookmarks::BookmarkNode* permanent_node = nullptr;
+ if (update_data.server_defined_unique_tag == kBookmarkBarTag) {
+ permanent_node = bookmark_model_->bookmark_bar_node();
+ } else if (update_data.server_defined_unique_tag == kOtherBookmarksTag) {
+ permanent_node = bookmark_model_->other_node();
+ } else if (update_data.server_defined_unique_tag == kMobileBookmarksTag) {
+ permanent_node = bookmark_model_->mobile_node();
+ }
+
+ if (permanent_node != nullptr) {
+ bookmark_tracker_.Associate(update_data.id, permanent_node);
+ }
}
base::WeakPtr<syncer::ModelTypeProcessor>
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor.h b/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
index 3a32a958a29..892c64ef9da 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor.h
@@ -6,17 +6,28 @@
#define COMPONENTS_SYNC_BOOKMARKS_BOOKMARK_MODEL_TYPE_PROCESSOR_H_
#include <memory>
+#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "components/sync/engine/model_type_processor.h"
+#include "components/sync_bookmarks/synced_bookmark_tracker.h"
+
+namespace syncer {
+class SyncClient;
+}
+
+namespace bookmarks {
+class BookmarkModel;
+}
namespace sync_bookmarks {
class BookmarkModelTypeProcessor : public syncer::ModelTypeProcessor {
public:
- BookmarkModelTypeProcessor();
+ // |sync_client| must not be nullptr and must outlive this object.
+ explicit BookmarkModelTypeProcessor(syncer::SyncClient* sync_client);
~BookmarkModelTypeProcessor() override;
// ModelTypeProcessor implementation.
@@ -30,13 +41,74 @@ class BookmarkModelTypeProcessor : public syncer::ModelTypeProcessor {
void OnUpdateReceived(const sync_pb::ModelTypeState& type_state,
const syncer::UpdateResponseDataList& updates) override;
+ // Public for testing.
+ static std::vector<const syncer::UpdateResponseData*> ReorderUpdatesForTest(
+ const syncer::UpdateResponseDataList& updates);
+
+ const SyncedBookmarkTracker* GetTrackerForTest() const;
+
base::WeakPtr<syncer::ModelTypeProcessor> GetWeakPtr();
private:
SEQUENCE_CHECKER(sequence_checker_);
+ // Reorders incoming updates such that parent creation is before child
+ // creation and child deletion is before parent deletion, and deletions should
+ // come last. The returned pointers point to the elements in the original
+ // |updates|.
+ static std::vector<const syncer::UpdateResponseData*> ReorderUpdates(
+ const syncer::UpdateResponseDataList& updates);
+
+ // Given a remote update entity, it returns the parent bookmark node of the
+ // corresponding node. It returns null if the parent node cannot be found.
+ const bookmarks::BookmarkNode* GetParentNode(
+ const syncer::EntityData& update_data) const;
+
+ // Processes a remote creation of a bookmark node.
+ // 1. For permanent folders, they are only registered in |bookmark_tracker_|.
+ // 2. If the nodes parent cannot be found, the remote creation update is
+ // ignored.
+ // 3. Otherwise, a new node is created in the local bookmark model and
+ // registered in |bookmark_tracker_|.
+ void ProcessRemoteCreate(const syncer::EntityData& update_data);
+
+ // Processes a remote update of a bookmark node. |update_data| must not be a
+ // deletion, and the server_id must be already tracked, otherwise, it is a
+ // creation that gets handeled in ProcessRemoteCreate(). |tracked_entity| is
+ // the tracked entity for that server_id. It is passed as a dependency instead
+ // of performing a lookup inside ProcessRemoteUpdate() to avoid wasting CPU
+ // cycles for doing another lookup (this code runs on the UI thread).
+ void ProcessRemoteUpdate(const syncer::EntityData& update_data,
+ const SyncedBookmarkTracker::Entity* tracked_entity);
+
+ // Process a remote delete of a bookmark node. |update_data| must not be a
+ // deletion. |tracked_entity| is the tracked entity for that server_id. It is
+ // passed as a dependency instead of performing a lookup inside
+ // ProcessRemoteDelete() to avoid wasting CPU cycles for doing another lookup
+ // (this code runs on the UI thread).
+ void ProcessRemoteDelete(const syncer::EntityData& update_data,
+ const SyncedBookmarkTracker::Entity* tracked_entity);
+
+ // Associates the permanent bookmark folders with the corresponding server
+ // side ids and registers the association in |bookmark_tracker_|.
+ // |update_data| must contain server_defined_unique_tag that is used to
+ // determine the corresponding permanent node. All permanent nodes are assumed
+ // to be directly children nodes of |kBookmarksRootId|. This method is used in
+ // the initial sync cycle only.
+ void AssociatePermanentFolder(const syncer::EntityData& update_data);
+
+ syncer::SyncClient* const sync_client_;
+
+ // The bookmark model we are processing local changes from and forwarding
+ // remote changes to.
+ bookmarks::BookmarkModel* const bookmark_model_;
+
std::unique_ptr<syncer::CommitQueue> worker_;
+ // Keeps the mapping between server ids and bookmarks nodes. It also caches
+ // the metadata upon a local change until the commit configration is received.
+ SyncedBookmarkTracker bookmark_tracker_;
+
base::WeakPtrFactory<BookmarkModelTypeProcessor> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(BookmarkModelTypeProcessor);
diff --git a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
index b3d40e3581d..ff2d3b32715 100644
--- a/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
+++ b/chromium/components/sync_bookmarks/bookmark_model_type_processor_unittest.cc
@@ -4,16 +4,302 @@
#include "components/sync_bookmarks/bookmark_model_type_processor.h"
+#include <string>
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/sync/driver/fake_sync_client.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using base::ASCIIToUTF16;
+using testing::Eq;
+using testing::NotNull;
+
namespace sync_bookmarks {
namespace {
-class BookmarkModelTypeProcessorTest : public testing::Test {};
+// The parent tag for children of the root entity. Entities with this parent are
+// referred to as top level enities.
+const char kRootParentTag[] = "0";
+const char kBookmarkBarTag[] = "bookmark_bar";
+const char kBookmarksRootId[] = "32904_google_chrome_bookmarks";
+
+struct BookmarkInfo {
+ std::string server_id;
+ std::string title;
+ std::string url; // empty for folders.
+ std::string parent_id;
+ std::string server_tag;
+};
+
+syncer::UpdateResponseData CreateUpdateData(const BookmarkInfo& bookmark_info) {
+ syncer::EntityData data;
+ data.id = bookmark_info.server_id;
+ data.parent_id = bookmark_info.parent_id;
+ data.server_defined_unique_tag = bookmark_info.server_tag;
+
+ sync_pb::BookmarkSpecifics* bookmark_specifics =
+ data.specifics.mutable_bookmark();
+ bookmark_specifics->set_title(bookmark_info.title);
+ if (bookmark_info.url.empty()) {
+ data.is_folder = true;
+ } else {
+ bookmark_specifics->set_url(bookmark_info.url);
+ }
+
+ syncer::UpdateResponseData response_data;
+ response_data.entity = data.PassToPtr();
+ // Similar to what's done in the loopback_server.
+ response_data.response_version = 0;
+ return response_data;
+}
+
+void AssertState(const BookmarkModelTypeProcessor* processor,
+ const std::vector<BookmarkInfo>& bookmarks) {
+ const SyncedBookmarkTracker* tracker = processor->GetTrackerForTest();
+
+ // Make sure the tracker contains all bookmarks in |bookmarks| + the
+ // bookmark bar node.
+ ASSERT_THAT(tracker->TrackedEntitiesCountForTest(), Eq(bookmarks.size() + 1));
+
+ for (BookmarkInfo bookmark : bookmarks) {
+ const SyncedBookmarkTracker::Entity* entity =
+ tracker->GetEntityForSyncId(bookmark.server_id);
+ ASSERT_THAT(entity, NotNull());
+ const bookmarks::BookmarkNode* node = entity->bookmark_node();
+ ASSERT_THAT(node->GetTitle(), Eq(ASCIIToUTF16(bookmark.title)));
+ ASSERT_THAT(node->url(), Eq(GURL(bookmark.url)));
+ const SyncedBookmarkTracker::Entity* parent_entity =
+ tracker->GetEntityForSyncId(bookmark.parent_id);
+ ASSERT_THAT(node->parent(), parent_entity->bookmark_node());
+ }
+}
+
+// TODO(crbug.com/516866): Replace with a simpler implementation (e.g. by
+// simulating loading from metadata) instead of receiving remote updates.
+// Inititalizes the processor with the bookmarks in |bookmarks|.
+void InitWithSyncedBookmarks(const std::vector<BookmarkInfo>& bookmarks,
+ BookmarkModelTypeProcessor* processor) {
+ syncer::UpdateResponseDataList updates;
+ // Add update for the permanent folder "Bookmarks bar".
+ updates.push_back(
+ CreateUpdateData({"bookmark_bar", std::string(), std::string(),
+ kBookmarksRootId, kBookmarkBarTag}));
+ for (BookmarkInfo bookmark : bookmarks) {
+ updates.push_back(CreateUpdateData(bookmark));
+ }
+ processor->OnUpdateReceived(sync_pb::ModelTypeState(), updates);
+ AssertState(processor, bookmarks);
+}
+
+syncer::UpdateResponseData CreateTombstone(const std::string& server_id) {
+ // EntityData is considered to represent a deletion if its
+ // specifics hasn't been set.
+ syncer::EntityData data;
+ data.id = server_id;
+
+ syncer::UpdateResponseData response_data;
+ response_data.entity = data.PassToPtr();
+ return response_data;
+}
+
+syncer::UpdateResponseData CreateBookmarkRootUpdateData() {
+ return CreateUpdateData({syncer::ModelTypeToRootTag(syncer::BOOKMARKS),
+ std::string(), std::string(), kRootParentTag,
+ syncer::ModelTypeToRootTag(syncer::BOOKMARKS)});
+}
+
+class TestSyncClient : public syncer::FakeSyncClient {
+ public:
+ explicit TestSyncClient(bookmarks::BookmarkModel* bookmark_model)
+ : bookmark_model_(bookmark_model) {}
+
+ bookmarks::BookmarkModel* GetBookmarkModel() override {
+ return bookmark_model_;
+ }
+
+ private:
+ bookmarks::BookmarkModel* bookmark_model_;
+};
+
+class BookmarkModelTypeProcessorTest : public testing::Test {
+ public:
+ BookmarkModelTypeProcessorTest()
+ : bookmark_model_(bookmarks::TestBookmarkClient::CreateModel()),
+ sync_client_(bookmark_model_.get()) {}
+
+ TestSyncClient* sync_client() { return &sync_client_; }
+ bookmarks::BookmarkModel* bookmark_model() { return bookmark_model_.get(); }
+
+ private:
+ std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
+ TestSyncClient sync_client_;
+};
+
+TEST_F(BookmarkModelTypeProcessorTest, ReorderUpdatesShouldIgnoreRootNodes) {
+ syncer::UpdateResponseDataList updates;
+ updates.push_back(CreateBookmarkRootUpdateData());
+ std::vector<const syncer::UpdateResponseData*> ordered_updates =
+ BookmarkModelTypeProcessor::ReorderUpdatesForTest(updates);
+ // Root node update should be filtered out.
+ EXPECT_THAT(ordered_updates.size(), Eq(0U));
+}
+
+// TODO(crbug.com/516866): This should change to cover the general case of
+// parents before children for non-deletions, and another test should be added
+// for children before parents for deletions.
+TEST_F(BookmarkModelTypeProcessorTest,
+ ReorderUpdatesShouldPlacePermanentNodesFirstForNonDeletions) {
+ const std::string kNode1Id = "node1";
+ const std::string kNode2Id = "node2";
+ syncer::UpdateResponseDataList updates;
+ updates.push_back(CreateUpdateData(
+ {kNode1Id, std::string(), std::string(), kNode2Id, std::string()}));
+ updates.push_back(CreateUpdateData({kNode2Id, std::string(), std::string(),
+ kBookmarksRootId, kBookmarkBarTag}));
+ std::vector<const syncer::UpdateResponseData*> ordered_updates =
+ BookmarkModelTypeProcessor::ReorderUpdatesForTest(updates);
+
+ // No update should be dropped.
+ ASSERT_THAT(ordered_updates.size(), Eq(2U));
+
+ // Updates should be ordered such that parent node update comes first.
+ EXPECT_THAT(ordered_updates[0]->entity.value().id, Eq(kNode2Id));
+ EXPECT_THAT(ordered_updates[1]->entity.value().id, Eq(kNode1Id));
+}
+
+TEST_F(BookmarkModelTypeProcessorTest, ShouldUpdateModelAfterRemoteCreation) {
+ BookmarkModelTypeProcessor processor(sync_client());
+
+ syncer::UpdateResponseDataList updates;
+ // Add update for the permanent folder "Bookmarks bar".
+ updates.push_back(
+ CreateUpdateData({"bookmark_bar", std::string(), std::string(),
+ kBookmarksRootId, kBookmarkBarTag}));
+
+ // Add update for another node under the bookmarks bar.
+ const std::string kNodeId = "node_id";
+ const std::string kTitle = "title";
+ const std::string kUrl = "http://www.url.com";
+ updates.push_back(CreateUpdateData({kNodeId, kTitle, kUrl, kBookmarkBarTag,
+ /*server_tag=*/std::string()}));
+
+ const bookmarks::BookmarkNode* bookmarkbar =
+ bookmark_model()->bookmark_bar_node();
+ EXPECT_TRUE(bookmarkbar->empty());
+
+ processor.OnUpdateReceived(sync_pb::ModelTypeState(), updates);
+
+ ASSERT_THAT(bookmarkbar->GetChild(0), NotNull());
+ EXPECT_THAT(bookmarkbar->GetChild(0)->GetTitle(), Eq(ASCIIToUTF16(kTitle)));
+ EXPECT_THAT(bookmarkbar->GetChild(0)->url(), Eq(GURL(kUrl)));
+}
+
+TEST_F(BookmarkModelTypeProcessorTest, ShouldUpdateModelAfterRemoteUpdate) {
+ BookmarkModelTypeProcessor processor(sync_client());
+
+ const std::string kNodeId = "node_id";
+ const std::string kTitle = "title";
+ const std::string kUrl = "http://www.url.com";
+
+ std::vector<BookmarkInfo> bookmarks = {
+ {kNodeId, kTitle, kUrl, kBookmarkBarTag, /*server_tag=*/std::string()}};
+
+ InitWithSyncedBookmarks(bookmarks, &processor);
+
+ // Make sure original bookmark exists.
+ const bookmarks::BookmarkNode* bookmark_bar =
+ bookmark_model()->bookmark_bar_node();
+ const bookmarks::BookmarkNode* bookmark_node = bookmark_bar->GetChild(0);
+ ASSERT_THAT(bookmark_node, NotNull());
+ ASSERT_THAT(bookmark_node->GetTitle(), Eq(ASCIIToUTF16(kTitle)));
+ ASSERT_THAT(bookmark_node->url(), Eq(GURL(kUrl)));
+
+ // Process an update for the same bookmark.
+ const std::string kNewTitle = "new-title";
+ const std::string kNewUrl = "http://www.new-url.com";
+ syncer::UpdateResponseDataList updates;
+ updates.push_back(
+ CreateUpdateData({kNodeId, kNewTitle, kNewUrl, kBookmarkBarTag,
+ /*server_tag=*/std::string()}));
+ processor.OnUpdateReceived(sync_pb::ModelTypeState(), updates);
+
+ // Check if the bookmark has been updated properly.
+ EXPECT_THAT(bookmark_bar->GetChild(0), Eq(bookmark_node));
+ EXPECT_THAT(bookmark_node->GetTitle(), Eq(ASCIIToUTF16(kNewTitle)));
+ EXPECT_THAT(bookmark_node->url(), Eq(GURL(kNewUrl)));
+}
+
+TEST_F(BookmarkModelTypeProcessorTest, ShouldUpdateModelAfterRemoteDelete) {
+ BookmarkModelTypeProcessor processor(sync_client());
+ // Build this structure
+ // bookmark_bar
+ // |- folder1
+ // |- title1
+ // |- title2
+ // |- folder2
+ // |- title3
+
+ // Then send delete updates in this order
+ // folder1 -> title2 -> title1
+ // to exercise the code of creating a |foster_parent|.
+
+ const std::string kTitle1 = "title1";
+ const std::string kTitle1Id = "title1Id";
+ const std::string kTitle2 = "title2";
+ const std::string kTitle2Id = "title2Id";
+ const std::string kTitle3 = "title3";
+ const std::string kTitle3Id = "title3Id";
+ const std::string kFolder1 = "folder1";
+ const std::string kFolder1Id = "folder1Id";
+ const std::string kFolder2 = "folder2";
+ const std::string kFolder2Id = "folder2Id";
+ const std::string kUrl = "http://www.url.com";
+
+ std::vector<BookmarkInfo> bookmarks = {
+ {kFolder1Id, kFolder1, /*url=*/std::string(), kBookmarkBarTag,
+ /*server_tag=*/std::string()},
+ {kTitle1Id, kTitle1, kUrl, kFolder1Id, /*server_tag=*/std::string()},
+ {kTitle2Id, kTitle2, kUrl, kFolder1Id, /*server_tag=*/std::string()},
+ {kFolder2Id, kFolder2, /*url=*/std::string(), kBookmarkBarTag,
+ /*server_tag=*/std::string()},
+ {kTitle3Id, kTitle3, kUrl, kFolder2Id, /*server_tag=*/std::string()},
+ };
+
+ InitWithSyncedBookmarks(bookmarks, &processor);
+
+ const bookmarks::BookmarkNode* bookmarkbar =
+ bookmark_model()->bookmark_bar_node();
+
+ ASSERT_THAT(bookmarkbar->child_count(), Eq(2));
+ ASSERT_THAT(bookmarkbar->GetChild(0)->GetTitle(), Eq(ASCIIToUTF16(kFolder1)));
+ ASSERT_THAT(bookmarkbar->GetChild(0)->child_count(), Eq(2));
+ ASSERT_THAT(bookmarkbar->GetChild(1)->GetTitle(), Eq(ASCIIToUTF16(kFolder2)));
+ ASSERT_THAT(bookmarkbar->GetChild(1)->child_count(), Eq(1));
+ ASSERT_THAT(bookmarkbar->GetChild(1)->GetChild(0)->GetTitle(),
+ Eq(ASCIIToUTF16(kTitle3)));
+
+ // Process delete updates
+ syncer::UpdateResponseDataList updates;
+ updates.push_back(CreateTombstone(kTitle2Id));
+ updates.push_back(CreateTombstone(kTitle1Id));
+ updates.push_back(CreateTombstone(kFolder1Id));
+
+ const sync_pb::ModelTypeState model_type_state;
+ processor.OnUpdateReceived(model_type_state, updates);
-TEST_F(BookmarkModelTypeProcessorTest, CreateInstance) {
- BookmarkModelTypeProcessor processor;
+ // The structure should be
+ // bookmark_bar
+ // |- folder2
+ // |- title3
+ EXPECT_THAT(bookmarkbar->child_count(), Eq(1));
+ EXPECT_THAT(bookmarkbar->GetChild(0)->GetTitle(), Eq(ASCIIToUTF16(kFolder2)));
+ EXPECT_THAT(bookmarkbar->GetChild(0)->child_count(), Eq(1));
+ EXPECT_THAT(bookmarkbar->GetChild(0)->GetChild(0)->GetTitle(),
+ Eq(ASCIIToUTF16(kTitle3)));
}
} // namespace
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc b/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
new file mode 100644
index 00000000000..175b16dc944
--- /dev/null
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker.cc
@@ -0,0 +1,55 @@
+// 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 "components/sync_bookmarks/synced_bookmark_tracker.h"
+
+#include <utility>
+
+#include "components/sync/model/entity_data.h"
+
+namespace sync_bookmarks {
+
+SyncedBookmarkTracker::Entity::Entity(
+ const bookmarks::BookmarkNode* bookmark_node)
+ : bookmark_node_(bookmark_node) {
+ DCHECK(bookmark_node);
+}
+
+SyncedBookmarkTracker::Entity::~Entity() = default;
+
+bool SyncedBookmarkTracker::Entity::MatchesData(
+ const syncer::EntityData& data) const {
+ // TODO(crbug.com/516866): Implement properly.
+ return false;
+}
+
+bool SyncedBookmarkTracker::Entity::IsUnsynced() const {
+ // TODO(crbug.com/516866): Implement properly.
+ return false;
+}
+
+SyncedBookmarkTracker::SyncedBookmarkTracker() = default;
+SyncedBookmarkTracker::~SyncedBookmarkTracker() = default;
+
+const SyncedBookmarkTracker::Entity* SyncedBookmarkTracker::GetEntityForSyncId(
+ const std::string& sync_id) const {
+ auto it = sync_id_to_entities_map_.find(sync_id);
+ return it != sync_id_to_entities_map_.end() ? it->second.get() : nullptr;
+}
+
+void SyncedBookmarkTracker::Associate(
+ const std::string& sync_id,
+ const bookmarks::BookmarkNode* bookmark_node) {
+ sync_id_to_entities_map_[sync_id] = std::make_unique<Entity>(bookmark_node);
+}
+
+void SyncedBookmarkTracker::Disassociate(const std::string& sync_id) {
+ sync_id_to_entities_map_.erase(sync_id);
+}
+
+std::size_t SyncedBookmarkTracker::TrackedEntitiesCountForTest() const {
+ return sync_id_to_entities_map_.size();
+}
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker.h b/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
new file mode 100644
index 00000000000..84e5850ff3c
--- /dev/null
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker.h
@@ -0,0 +1,85 @@
+// 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 COMPONENTS_SYNC_BOOKMARKS_SYNCED_BOOKMARK_TRACKER_H_
+#define COMPONENTS_SYNC_BOOKMARKS_SYNCED_BOOKMARK_TRACKER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "components/sync/protocol/entity_metadata.pb.h"
+
+namespace bookmarks {
+class BookmarkNode;
+}
+
+namespace syncer {
+struct EntityData;
+}
+
+namespace sync_bookmarks {
+
+// This class is responsible for keeping the mapping between bookmarks node in
+// the local model and the server-side corresponding sync entities. It manages
+// the metadata for its entity and caches entity data upon a local change until
+// commit confirmation is received.
+class SyncedBookmarkTracker {
+ public:
+ class Entity {
+ public:
+ // |bookmark_node| must not be null and must outlive this object.
+ explicit Entity(const bookmarks::BookmarkNode* bookmark_node);
+ ~Entity();
+
+ // Returns true if this data is out of sync with the server.
+ // A commit may or may not be in progress at this time.
+ bool IsUnsynced() const;
+
+ // Check whether |data| matches the stored specifics hash.
+ bool MatchesData(const syncer::EntityData& data) const;
+
+ // It never returns null.
+ const bookmarks::BookmarkNode* bookmark_node() const {
+ return bookmark_node_;
+ }
+
+ private:
+ const bookmarks::BookmarkNode* const bookmark_node_;
+
+ DISALLOW_COPY_AND_ASSIGN(Entity);
+ };
+
+ SyncedBookmarkTracker();
+ ~SyncedBookmarkTracker();
+
+ // Returns null if not entity is found.
+ const Entity* GetEntityForSyncId(const std::string& sync_id) const;
+
+ // Associates a server id with the corresponding local bookmark node in
+ // |sync_id_to_entities_map_|.
+ void Associate(const std::string& sync_id,
+ const bookmarks::BookmarkNode* bookmark_node);
+
+ // Removes the association that corresponds to |sync_id| from
+ // |sync_id_to_entities_map_|.
+ void Disassociate(const std::string& sync_id);
+
+ // Returns number of tracked entities. Used only in test.
+ std::size_t TrackedEntitiesCountForTest() const;
+
+ private:
+ // A map of sync server ids to sync entities. This should contain entries and
+ // metadata for almost everything. However, since local data are loaded only
+ // when needed (e.g. before a commit cycle), the entities may not always
+ // contain model type data/specifics.
+ std::map<std::string, std::unique_ptr<Entity>> sync_id_to_entities_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncedBookmarkTracker);
+};
+
+} // namespace sync_bookmarks
+
+#endif // COMPONENTS_SYNC_BOOKMARKS_SYNCED_BOOKMARK_TRACKER_H_
diff --git a/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc b/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
new file mode 100644
index 00000000000..877eeaf2193
--- /dev/null
+++ b/chromium/components/sync_bookmarks/synced_bookmark_tracker_unittest.cc
@@ -0,0 +1,45 @@
+// 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 "components/sync_bookmarks/synced_bookmark_tracker.h"
+
+#include "components/bookmarks/browser/bookmark_node.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Eq;
+using testing::IsNull;
+using testing::NotNull;
+
+namespace sync_bookmarks {
+
+namespace {
+
+TEST(SyncedBookmarkTrackerTest, ShouldGetAssociatedNodes) {
+ SyncedBookmarkTracker tracker;
+ const std::string kSyncId = "SYNC_ID";
+ const int64_t kId = 1;
+ bookmarks::BookmarkNode node(kId, GURL());
+ tracker.Associate(kSyncId, &node);
+ const SyncedBookmarkTracker::Entity* entity =
+ tracker.GetEntityForSyncId(kSyncId);
+ ASSERT_THAT(entity, NotNull());
+ EXPECT_THAT(entity->bookmark_node(), Eq(&node));
+ EXPECT_THAT(tracker.GetEntityForSyncId("unknown id"), IsNull());
+}
+
+TEST(SyncedBookmarkTrackerTest, ShouldReturnNullForDisassociatedNodes) {
+ SyncedBookmarkTracker tracker;
+ const std::string kSyncId = "SYNC_ID";
+ const int64_t kId = 1;
+ bookmarks::BookmarkNode node(kId, GURL());
+ tracker.Associate(kSyncId, &node);
+ ASSERT_THAT(tracker.GetEntityForSyncId(kSyncId), NotNull());
+ tracker.Disassociate(kSyncId);
+ EXPECT_THAT(tracker.GetEntityForSyncId(kSyncId), IsNull());
+}
+
+} // namespace
+
+} // namespace sync_bookmarks
diff --git a/chromium/components/sync_preferences/BUILD.gn b/chromium/components/sync_preferences/BUILD.gn
index a3ae9d2535d..49ca9514a71 100644
--- a/chromium/components/sync_preferences/BUILD.gn
+++ b/chromium/components/sync_preferences/BUILD.gn
@@ -63,6 +63,7 @@ source_set("unit_tests") {
":test_support",
"//components/pref_registry",
"//components/prefs",
+ "//components/prefs:test_support",
"//components/sync",
"//components/sync:test_support_model",
"//testing/gtest",
diff --git a/chromium/components/sync_preferences/pref_model_associator.cc b/chromium/components/sync_preferences/pref_model_associator.cc
index 401d614defd..2aeff8dbbe1 100644
--- a/chromium/components/sync_preferences/pref_model_associator.cc
+++ b/chromium/components/sync_preferences/pref_model_associator.cc
@@ -375,7 +375,7 @@ syncer::SyncError PrefModelAssociator::ProcessSyncChanges(
// Windows client, the Windows client does not support
// kConfirmToQuitEnabled. Ignore updates from these preferences.
std::string pref_name = pref_specifics.name();
- if (!IsPrefRegistered(pref_name.c_str()))
+ if (!IsPrefRegistered(pref_name))
continue;
if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
@@ -406,6 +406,7 @@ syncer::SyncError PrefModelAssociator::ProcessSyncChanges(
return syncer::SyncError();
}
+// static
base::Value* PrefModelAssociator::ReadPreferenceSpecifics(
const sync_pb::PreferenceSpecifics& preference) {
base::JSONReader reader;
@@ -425,10 +426,10 @@ bool PrefModelAssociator::IsPrefSynced(const std::string& name) const {
void PrefModelAssociator::AddSyncedPrefObserver(const std::string& name,
SyncedPrefObserver* observer) {
- std::unique_ptr<SyncedPrefObserverList>& observers =
+ std::unique_ptr<base::ObserverList<SyncedPrefObserver>>& observers =
synced_pref_observers_[name];
if (!observers)
- observers = std::make_unique<SyncedPrefObserverList>();
+ observers = std::make_unique<base::ObserverList<SyncedPrefObserver>>();
observers->AddObserver(observer);
}
@@ -439,18 +440,7 @@ void PrefModelAssociator::RemoveSyncedPrefObserver(
auto observer_iter = synced_pref_observers_.find(name);
if (observer_iter == synced_pref_observers_.end())
return;
- SyncedPrefObserverList* observers = observer_iter->second.get();
- observers->RemoveObserver(observer);
-}
-
-void PrefModelAssociator::SetPrefModelAssociatorClientForTesting(
- const PrefModelAssociatorClient* client) {
- DCHECK(!client_);
- client_ = client;
-}
-
-std::set<std::string> PrefModelAssociator::registered_preferences() const {
- return registered_preferences_;
+ observer_iter->second->RemoveObserver(observer);
}
void PrefModelAssociator::RegisterPref(const char* name) {
@@ -458,7 +448,7 @@ void PrefModelAssociator::RegisterPref(const char* name) {
registered_preferences_.insert(name);
}
-bool PrefModelAssociator::IsPrefRegistered(const char* name) {
+bool PrefModelAssociator::IsPrefRegistered(const std::string& name) const {
return registered_preferences_.count(name) > 0;
}
@@ -475,7 +465,7 @@ void PrefModelAssociator::ProcessPrefChange(const std::string& name) {
if (!preference)
return;
- if (!IsPrefRegistered(name.c_str()))
+ if (!IsPrefRegistered(name))
return; // We are not syncing this preference.
syncer::SyncChangeList changes;
@@ -522,8 +512,7 @@ void PrefModelAssociator::NotifySyncedPrefObservers(const std::string& path,
auto observer_iter = synced_pref_observers_.find(path);
if (observer_iter == synced_pref_observers_.end())
return;
- SyncedPrefObserverList* observers = observer_iter->second.get();
- for (auto& observer : *observers)
+ for (auto& observer : *observer_iter->second)
observer.OnSyncedPrefChanged(path, from_sync);
}
diff --git a/chromium/components/sync_preferences/pref_model_associator.h b/chromium/components/sync_preferences/pref_model_associator.h
index 8832be194e7..d47a36b4a64 100644
--- a/chromium/components/sync_preferences/pref_model_associator.h
+++ b/chromium/components/sync_preferences/pref_model_associator.h
@@ -61,10 +61,6 @@ class PrefModelAssociator : public syncer::SyncableService {
std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) override;
void StopSyncing(syncer::ModelType type) override;
- // Returns the list of preference names that are registered as syncable, and
- // hence should be monitored for changes.
- std::set<std::string> registered_preferences() const;
-
// Register a preference with the specified name for syncing. We do not care
// about the type at registration time, but when changes arrive from the
// syncer, we check if they can be applied and if not drop them.
@@ -72,9 +68,6 @@ class PrefModelAssociator : public syncer::SyncableService {
// begins).
virtual void RegisterPref(const char* name);
- // Returns true if the specified preference is registered for syncing.
- virtual bool IsPrefRegistered(const char* name);
-
// Process a local preference change. This can trigger new SyncChanges being
// sent to the syncer.
virtual void ProcessPrefChange(const std::string& name);
@@ -95,15 +88,13 @@ class PrefModelAssociator : public syncer::SyncableService {
bool CreatePrefSyncData(const std::string& name,
const base::Value& value,
syncer::SyncData* sync_data) const;
-
- // Extract preference value from sync specifics.
- base::Value* ReadPreferenceSpecifics(
- const sync_pb::PreferenceSpecifics& specifics);
-
// Returns true if the pref under the given name is pulled down from sync.
// Note this does not refer to SYNCABLE_PREF.
bool IsPrefSynced(const std::string& name) const;
+ // Returns true if the specified preference is registered for syncing.
+ bool IsPrefRegistered(const std::string& name) const;
+
// Adds a SyncedPrefObserver to watch for changes to a specific pref.
void AddSyncedPrefObserver(const std::string& name,
SyncedPrefObserver* observer);
@@ -115,19 +106,13 @@ class PrefModelAssociator : public syncer::SyncableService {
// Returns the PrefModelAssociatorClient for this object.
const PrefModelAssociatorClient* client() const { return client_; }
- // Set the PrefModelAssociatorClient to use for that object during tests.
- void SetPrefModelAssociatorClientForTesting(
- const PrefModelAssociatorClient* client);
-
// Register callback method which will get called at the end of
// PrefModelAssociator::MergeDataAndStartSyncing().
void RegisterMergeDataFinishedCallback(const base::Closure& callback);
- protected:
+ private:
friend class PrefServiceSyncableTest;
- typedef std::map<std::string, syncer::SyncData> SyncDataMap;
-
// Create an association for a given preference. If |sync_pref| is valid,
// signifying that sync has data for this preference, we reconcile their data
// with ours and append a new UPDATE SyncChange to |sync_changes|. If
@@ -143,9 +128,14 @@ class PrefModelAssociator : public syncer::SyncableService {
static std::unique_ptr<base::Value> MergeListValues(
const base::Value& from_value,
const base::Value& to_value);
+
static base::Value MergeDictionaryValues(const base::Value& from_value,
const base::Value& to_value);
+ // Extract preference value from sync specifics.
+ static base::Value* ReadPreferenceSpecifics(
+ const sync_pb::PreferenceSpecifics& specifics);
+
// Do we have an active association between the preferences and sync models?
// Set when start syncing, reset in StopSyncing. While this is not set, we
// ignore any local preference changes (when we start syncing we will look
@@ -184,17 +174,14 @@ class PrefModelAssociator : public syncer::SyncableService {
// PRIORITY_PREFERENCES.
syncer::ModelType type_;
- private:
+ void NotifySyncedPrefObservers(const std::string& path, bool from_sync) const;
+
// Map prefs to lists of observers. Observers will receive notification when
// a pref changes, including the detail of whether or not the change came
// from sync.
- using SyncedPrefObserverList = base::ObserverList<SyncedPrefObserver>;
- using SyncedPrefObserverMap =
- base::hash_map<std::string, std::unique_ptr<SyncedPrefObserverList>>;
-
- void NotifySyncedPrefObservers(const std::string& path, bool from_sync) const;
-
- SyncedPrefObserverMap synced_pref_observers_;
+ base::hash_map<std::string,
+ std::unique_ptr<base::ObserverList<SyncedPrefObserver>>>
+ synced_pref_observers_;
const PrefModelAssociatorClient* client_; // Weak.
std::vector<base::Closure> callback_list_;
diff --git a/chromium/components/sync_preferences/pref_service_syncable.cc b/chromium/components/sync_preferences/pref_service_syncable.cc
index 96e192dbf69..478d278aa3e 100644
--- a/chromium/components/sync_preferences/pref_service_syncable.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable.cc
@@ -174,15 +174,6 @@ void PrefServiceSyncable::RegisterMergeDataFinishedCallback(
pref_sync_associator_.RegisterMergeDataFinishedCallback(callback);
}
-// Set the PrefModelAssociatorClient to use for that object during tests.
-void PrefServiceSyncable::SetPrefModelAssociatorClientForTesting(
- const PrefModelAssociatorClient* pref_model_associator_client) {
- pref_sync_associator_.SetPrefModelAssociatorClientForTesting(
- pref_model_associator_client);
- priority_pref_sync_associator_.SetPrefModelAssociatorClientForTesting(
- pref_model_associator_client);
-}
-
void PrefServiceSyncable::AddRegisteredSyncablePreference(
const std::string& path,
uint32_t flags) {
diff --git a/chromium/components/sync_preferences/pref_service_syncable.h b/chromium/components/sync_preferences/pref_service_syncable.h
index f425965a986..656b10e8201 100644
--- a/chromium/components/sync_preferences/pref_service_syncable.h
+++ b/chromium/components/sync_preferences/pref_service_syncable.h
@@ -40,7 +40,7 @@ class PrefServiceSyncable : public PrefService {
std::unique_ptr<PrefValueStore> pref_value_store,
scoped_refptr<PersistentPrefStore> user_prefs,
scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry,
- const PrefModelAssociatorClient* pref_model_associato_client,
+ const PrefModelAssociatorClient* pref_model_associator_client,
base::RepeatingCallback<void(PersistentPrefStore::PrefReadError)>
read_error_callback,
bool async);
@@ -91,11 +91,6 @@ class PrefServiceSyncable : public PrefService {
void RemoveSyncedPrefObserver(const std::string& name,
SyncedPrefObserver* observer);
- protected:
- // Set the PrefModelAssociatorClient to use for that object during tests.
- void SetPrefModelAssociatorClientForTesting(
- const PrefModelAssociatorClient* pref_model_associator_client);
-
private:
friend class PrefModelAssociator;
diff --git a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
index d79abb4c914..1129b294554 100644
--- a/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
+++ b/chromium/components/sync_preferences/pref_service_syncable_unittest.cc
@@ -13,10 +13,11 @@
#include "base/json/json_writer.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_notifier_impl.h"
#include "components/prefs/scoped_user_pref_update.h"
+#include "components/prefs/testing_pref_store.h"
#include "components/sync/model/sync_change.h"
#include "components/sync/model/sync_data.h"
#include "components/sync/model/sync_error_factory_mock.h"
@@ -30,6 +31,7 @@
using syncer::SyncChange;
using syncer::SyncData;
+using testing::NotNull;
namespace sync_preferences {
@@ -40,6 +42,7 @@ const char kExampleUrl1[] = "http://example.com/1";
const char kExampleUrl2[] = "http://example.com/2";
const char kStringPrefName[] = "string_pref_name";
const char kListPrefName[] = "list_pref_name";
+const char kDictPrefName[] = "dict_pref_name";
const char kUnsyncedPreferenceName[] = "nonsense_pref_name";
const char kUnsyncedPreferenceDefaultValue[] = "default";
const char kDefaultCharsetPrefName[] = "default_charset";
@@ -50,25 +53,6 @@ void Increment(int* num) {
(*num)++;
}
-class TestPrefModelAssociatorClient : public PrefModelAssociatorClient {
- public:
- TestPrefModelAssociatorClient() {}
- ~TestPrefModelAssociatorClient() override {}
-
- // PrefModelAssociatorClient implementation.
- bool IsMergeableListPreference(const std::string& pref_name) const override {
- return pref_name == kListPrefName;
- }
-
- bool IsMergeableDictionaryPreference(
- const std::string& pref_name) const override {
- return false;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestPrefModelAssociatorClient);
-};
-
class TestSyncProcessorStub : public syncer::SyncChangeProcessor {
public:
explicit TestSyncProcessorStub(syncer::SyncChangeList* output)
@@ -101,11 +85,9 @@ class PrefServiceSyncableTest : public testing::Test {
public:
PrefServiceSyncableTest()
: pref_sync_service_(nullptr),
- test_processor_(nullptr),
next_pref_remote_sync_node_id_(0) {}
void SetUp() override {
- prefs_.SetPrefModelAssociatorClientForTesting(&client_);
prefs_.registry()->RegisterStringPref(kUnsyncedPreferenceName,
kUnsyncedPreferenceDefaultValue);
prefs_.registry()->RegisterStringPref(
@@ -117,7 +99,7 @@ class PrefServiceSyncableTest : public testing::Test {
kDefaultCharsetPrefName, kDefaultCharsetValue,
user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
- pref_sync_service_ = reinterpret_cast<PrefModelAssociator*>(
+ pref_sync_service_ = static_cast<PrefModelAssociator*>(
prefs_.GetSyncableService(syncer::PREFERENCES));
ASSERT_TRUE(pref_sync_service_);
}
@@ -155,9 +137,9 @@ class PrefServiceSyncableTest : public testing::Test {
void InitWithSyncDataTakeOutput(const syncer::SyncDataList& initial_data,
syncer::SyncChangeList* output) {
- test_processor_ = new TestSyncProcessorStub(output);
syncer::SyncMergeResult r = pref_sync_service_->MergeDataAndStartSyncing(
- syncer::PREFERENCES, initial_data, base::WrapUnique(test_processor_),
+ syncer::PREFERENCES, initial_data,
+ std::make_unique<TestSyncProcessorStub>(output),
std::make_unique<syncer::SyncErrorFactoryMock>());
EXPECT_FALSE(r.error().IsSet());
}
@@ -185,22 +167,20 @@ class PrefServiceSyncableTest : public testing::Test {
}
bool IsSynced(const std::string& pref_name) {
- return pref_sync_service_->registered_preferences().count(pref_name) > 0;
+ return pref_sync_service_->IsPrefSynced(pref_name);
}
- bool HasSyncData(const std::string& pref_name) {
- return pref_sync_service_->IsPrefSynced(pref_name);
+ bool IsRegistered(const std::string& pref_name) {
+ return pref_sync_service_->IsPrefRegistered(pref_name.c_str());
}
PrefService* GetPrefs() { return &prefs_; }
TestingPrefServiceSyncable* GetTestingPrefService() { return &prefs_; }
protected:
- TestPrefModelAssociatorClient client_;
TestingPrefServiceSyncable prefs_;
PrefModelAssociator* pref_sync_service_;
- TestSyncProcessorStub* test_processor_;
int next_pref_remote_sync_node_id_;
};
@@ -229,7 +209,7 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationDoNotSyncDefaults) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
- EXPECT_TRUE(IsSynced(kStringPrefName));
+ EXPECT_TRUE(IsRegistered(kStringPrefName));
EXPECT_TRUE(pref->IsDefaultValue());
EXPECT_FALSE(FindValue(kStringPrefName, out).get());
}
@@ -259,7 +239,6 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationCloudHasData) {
ListPrefUpdate update(GetPrefs(), kListPrefName);
base::ListValue* url_list = update.Get();
url_list->AppendString(kExampleUrl0);
- url_list->AppendString(kExampleUrl1);
}
syncer::SyncDataList in;
@@ -267,7 +246,6 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationCloudHasData) {
AddToRemoteDataList(kStringPrefName, base::Value(kExampleUrl1), &in);
base::ListValue urls_to_restore;
urls_to_restore.AppendString(kExampleUrl1);
- urls_to_restore.AppendString(kExampleUrl2);
AddToRemoteDataList(kListPrefName, urls_to_restore, &in);
AddToRemoteDataList(kDefaultCharsetPrefName,
base::Value(kNonDefaultCharsetValue), &in);
@@ -278,15 +256,259 @@ TEST_F(PrefServiceSyncableTest, ModelAssociationCloudHasData) {
EXPECT_EQ(kExampleUrl1, prefs_.GetString(kStringPrefName));
+ // No associator client is registered, so lists and dictionaries should not
+ // get merged (remote write wins).
+ auto expected_urls = std::make_unique<base::ListValue>();
+ expected_urls->AppendString(kExampleUrl1);
+ EXPECT_FALSE(FindValue(kListPrefName, out));
+ EXPECT_TRUE(GetPreferenceValue(kListPrefName).Equals(expected_urls.get()));
+ EXPECT_EQ(kNonDefaultCharsetValue, prefs_.GetString(kDefaultCharsetPrefName));
+}
+
+class TestPrefModelAssociatorClient : public PrefModelAssociatorClient {
+ public:
+ TestPrefModelAssociatorClient() {}
+ ~TestPrefModelAssociatorClient() override {}
+
+ // PrefModelAssociatorClient implementation.
+ bool IsMergeableListPreference(const std::string& pref_name) const override {
+ return pref_name == kListPrefName;
+ }
+
+ bool IsMergeableDictionaryPreference(
+ const std::string& pref_name) const override {
+ return true;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestPrefModelAssociatorClient);
+};
+
+class PrefServiceSyncableMergeTest : public testing::Test {
+ public:
+ PrefServiceSyncableMergeTest()
+ : pref_registry_(
+ base::MakeRefCounted<user_prefs::PrefRegistrySyncable>()),
+ pref_notifier_(new PrefNotifierImpl),
+ managed_prefs_(base::MakeRefCounted<TestingPrefStore>()),
+ user_prefs_(base::MakeRefCounted<TestingPrefStore>()),
+ prefs_(
+ std::unique_ptr<PrefNotifierImpl>(pref_notifier_),
+ std::make_unique<PrefValueStore>(managed_prefs_.get(),
+ new TestingPrefStore,
+ new TestingPrefStore,
+ new TestingPrefStore,
+ user_prefs_.get(),
+ new TestingPrefStore,
+ pref_registry_->defaults().get(),
+ pref_notifier_),
+ user_prefs_,
+ pref_registry_,
+ &client_,
+ base::BindRepeating(&PrefServiceSyncableMergeTest::HandleReadError),
+ /*async=*/false),
+ pref_sync_service_(nullptr),
+ next_pref_remote_sync_node_id_(0) {}
+
+ void SetUp() override {
+ pref_registry_->RegisterStringPref(kUnsyncedPreferenceName,
+ kUnsyncedPreferenceDefaultValue);
+ pref_registry_->RegisterStringPref(
+ kStringPrefName, std::string(),
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ pref_registry_->RegisterListPref(
+ kListPrefName, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ pref_registry_->RegisterDictionaryPref(
+ kDictPrefName, user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+ pref_registry_->RegisterStringPref(
+ kDefaultCharsetPrefName, kDefaultCharsetValue,
+ user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+
+ // Downcast to PrefModelAssociator so that tests can access its' specific
+ // behavior. This is a smell. The roles between PrefServiceSyncable and
+ // PrefModelAssociator are not clearly separated (and this test should only
+ // test against the SyncableService interface).
+ pref_sync_service_ = // static_cast<PrefModelAssociator*>(
+ prefs_.GetSyncableService(syncer::PREFERENCES); //);
+ ASSERT_THAT(pref_sync_service_, NotNull());
+ }
+
+ /// Empty stub for prefs_ error handling.
+ static void HandleReadError(PersistentPrefStore::PrefReadError error) {}
+
+ syncer::SyncChange MakeRemoteChange(int64_t id,
+ const std::string& name,
+ const base::Value& value,
+ SyncChange::SyncChangeType type) {
+ std::string serialized;
+ JSONStringValueSerializer json(&serialized);
+ CHECK(json.Serialize(value));
+ sync_pb::EntitySpecifics entity;
+ sync_pb::PreferenceSpecifics* pref_one = entity.mutable_preference();
+ pref_one->set_name(name);
+ pref_one->set_value(serialized);
+ return syncer::SyncChange(
+ FROM_HERE, type,
+ syncer::SyncData::CreateRemoteData(id, entity, base::Time()));
+ }
+
+ void AddToRemoteDataList(const std::string& name,
+ const base::Value& value,
+ syncer::SyncDataList* out) {
+ std::string serialized;
+ JSONStringValueSerializer json(&serialized);
+ ASSERT_TRUE(json.Serialize(value));
+ sync_pb::EntitySpecifics one;
+ sync_pb::PreferenceSpecifics* pref_one = one.mutable_preference();
+ pref_one->set_name(name);
+ pref_one->set_value(serialized);
+ out->push_back(SyncData::CreateRemoteData(++next_pref_remote_sync_node_id_,
+ one, base::Time()));
+ }
+
+ void InitWithSyncDataTakeOutput(const syncer::SyncDataList& initial_data,
+ syncer::SyncChangeList* output) {
+ syncer::SyncMergeResult r = pref_sync_service_->MergeDataAndStartSyncing(
+ syncer::PREFERENCES, initial_data,
+ std::make_unique<TestSyncProcessorStub>(output),
+ std::make_unique<syncer::SyncErrorFactoryMock>());
+ EXPECT_FALSE(r.error().IsSet());
+ }
+
+ const base::Value& GetPreferenceValue(const std::string& name) {
+ const PrefService::Preference* preference =
+ prefs_.FindPreference(name.c_str());
+ return *preference->GetValue();
+ }
+
+ std::unique_ptr<base::Value> FindValue(const std::string& name,
+ const syncer::SyncChangeList& list) {
+ syncer::SyncChangeList::const_iterator it = list.begin();
+ for (; it != list.end(); ++it) {
+ if (syncer::SyncDataLocal(it->sync_data()).GetTag() == name) {
+ return base::JSONReader::Read(
+ it->sync_data().GetSpecifics().preference().value());
+ }
+ }
+ return nullptr;
+ }
+
+ protected:
+ scoped_refptr<user_prefs::PrefRegistrySyncable> pref_registry_;
+ // Owned by prefs_;
+ PrefNotifierImpl* pref_notifier_;
+ scoped_refptr<TestingPrefStore> managed_prefs_;
+ scoped_refptr<TestingPrefStore> user_prefs_;
+ TestPrefModelAssociatorClient client_;
+ PrefServiceSyncable prefs_;
+ syncer::SyncableService* pref_sync_service_;
+ int next_pref_remote_sync_node_id_;
+};
+
+TEST_F(PrefServiceSyncableMergeTest, ShouldMergeSelectedListValues) {
+ {
+ ListPrefUpdate update(&prefs_, kListPrefName);
+ base::ListValue* url_list = update.Get();
+ url_list->AppendString(kExampleUrl0);
+ url_list->AppendString(kExampleUrl1);
+ }
+
+ base::ListValue urls_to_restore;
+ urls_to_restore.AppendString(kExampleUrl1);
+ urls_to_restore.AppendString(kExampleUrl2);
+ syncer::SyncDataList in;
+ AddToRemoteDataList(kListPrefName, urls_to_restore, &in);
+
+ syncer::SyncChangeList out;
+ InitWithSyncDataTakeOutput(in, &out);
+
std::unique_ptr<base::ListValue> expected_urls(new base::ListValue);
expected_urls->AppendString(kExampleUrl1);
expected_urls->AppendString(kExampleUrl2);
expected_urls->AppendString(kExampleUrl0);
std::unique_ptr<base::Value> value(FindValue(kListPrefName, out));
ASSERT_TRUE(value.get());
- EXPECT_TRUE(value->Equals(expected_urls.get()));
+ EXPECT_TRUE(value->Equals(expected_urls.get())) << *value;
EXPECT_TRUE(GetPreferenceValue(kListPrefName).Equals(expected_urls.get()));
- EXPECT_EQ(kNonDefaultCharsetValue, prefs_.GetString(kDefaultCharsetPrefName));
+}
+
+// List preferences have special handling at association time due to our ability
+// to merge the local and sync value. Make sure the merge logic doesn't merge
+// managed preferences.
+TEST_F(PrefServiceSyncableMergeTest, ManagedListPreferences) {
+ // Make the list of urls to restore on startup managed.
+ base::ListValue managed_value;
+ managed_value.AppendString(kExampleUrl0);
+ managed_value.AppendString(kExampleUrl1);
+ managed_prefs_->SetValue(kListPrefName, managed_value.CreateDeepCopy(),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+ // Set a cloud version.
+ syncer::SyncDataList in;
+ base::ListValue urls_to_restore;
+ urls_to_restore.AppendString(kExampleUrl1);
+ urls_to_restore.AppendString(kExampleUrl2);
+ AddToRemoteDataList(kListPrefName, urls_to_restore, &in);
+
+ // Start sync and verify the synced value didn't get merged.
+ {
+ syncer::SyncChangeList out;
+ InitWithSyncDataTakeOutput(in, &out);
+ EXPECT_FALSE(FindValue(kListPrefName, out).get());
+ }
+
+ // Changing the user's urls to restore on startup pref should not sync
+ // anything.
+ {
+ syncer::SyncChangeList out;
+ base::ListValue user_value;
+ user_value.AppendString("http://chromium.org");
+ prefs_.Set(kListPrefName, user_value);
+ EXPECT_FALSE(FindValue(kListPrefName, out).get());
+ }
+
+ // An incoming sync transaction should change the user value, not the managed
+ // value.
+ base::ListValue sync_value;
+ sync_value.AppendString("http://crbug.com");
+ syncer::SyncChangeList list;
+ list.push_back(MakeRemoteChange(1, kListPrefName, sync_value,
+ SyncChange::ACTION_UPDATE));
+ pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
+
+ const base::Value* managed_prefs_result;
+ ASSERT_TRUE(managed_prefs_->GetValue(kListPrefName, &managed_prefs_result));
+ EXPECT_TRUE(managed_value.Equals(managed_prefs_result));
+ // Get should return the managed value, too.
+ EXPECT_TRUE(managed_value.Equals(prefs_.Get(kListPrefName)));
+ // Verify the user pref value has the change.
+ EXPECT_TRUE(sync_value.Equals(prefs_.GetUserPrefValue(kListPrefName)));
+}
+
+TEST_F(PrefServiceSyncableMergeTest, ShouldMergeSelectedDictionaryValues) {
+ {
+ DictionaryPrefUpdate update(&prefs_, kDictPrefName);
+ base::DictionaryValue* dict_value = update.Get();
+ dict_value->Set("my_key1", std::make_unique<base::Value>("my_value1"));
+ dict_value->Set("my_key3", std::make_unique<base::Value>("my_value3"));
+ }
+
+ base::DictionaryValue remote_update;
+ remote_update.Set("my_key2", std::make_unique<base::Value>("my_value2"));
+ syncer::SyncDataList in;
+ AddToRemoteDataList(kDictPrefName, remote_update, &in);
+
+ syncer::SyncChangeList out;
+ InitWithSyncDataTakeOutput(in, &out);
+
+ base::DictionaryValue expected_dict;
+ expected_dict.Set("my_key1", std::make_unique<base::Value>("my_value1"));
+ expected_dict.Set("my_key2", std::make_unique<base::Value>("my_value2"));
+ expected_dict.Set("my_key3", std::make_unique<base::Value>("my_value3"));
+ std::unique_ptr<base::Value> value(FindValue(kDictPrefName, out));
+ ASSERT_TRUE(value.get());
+ EXPECT_TRUE(value->Equals(&expected_dict));
+ EXPECT_TRUE(GetPreferenceValue(kDictPrefName).Equals(&expected_dict));
}
TEST_F(PrefServiceSyncableTest, FailModelAssociation) {
@@ -354,8 +576,7 @@ TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeActionAdd) {
const base::Value& actual = GetPreferenceValue(kStringPrefName);
EXPECT_TRUE(expected.Equals(&actual));
- EXPECT_EQ(
- 1U, pref_sync_service_->registered_preferences().count(kStringPrefName));
+ EXPECT_TRUE(pref_sync_service_->IsPrefSynced(kStringPrefName));
}
TEST_F(PrefServiceSyncableTest, UpdatedSyncNodeUnknownPreference) {
@@ -395,49 +616,6 @@ TEST_F(PrefServiceSyncableTest, ManagedPreferences) {
EXPECT_TRUE(sync_value.Equals(prefs_.GetUserPref(kStringPrefName)));
}
-// List preferences have special handling at association time due to our ability
-// to merge the local and sync value. Make sure the merge logic doesn't merge
-// managed preferences.
-TEST_F(PrefServiceSyncableTest, ManagedListPreferences) {
- // Make the list of urls to restore on startup managed.
- base::ListValue managed_value;
- managed_value.AppendString(kExampleUrl0);
- managed_value.AppendString(kExampleUrl1);
- prefs_.SetManagedPref(kListPrefName, managed_value.CreateDeepCopy());
-
- // Set a cloud version.
- syncer::SyncDataList in;
- syncer::SyncChangeList out;
- base::ListValue urls_to_restore;
- urls_to_restore.AppendString(kExampleUrl1);
- urls_to_restore.AppendString(kExampleUrl2);
- AddToRemoteDataList(kListPrefName, urls_to_restore, &in);
-
- // Start sync and verify the synced value didn't get merged.
- InitWithSyncDataTakeOutput(in, &out);
- EXPECT_FALSE(FindValue(kListPrefName, out).get());
- out.clear();
-
- // Changing the user's urls to restore on startup pref should not sync
- // anything.
- base::ListValue user_value;
- user_value.AppendString("http://chromium.org");
- prefs_.SetUserPref(kListPrefName, user_value.CreateDeepCopy());
- EXPECT_FALSE(FindValue(kListPrefName, out).get());
-
- // An incoming sync transaction should change the user value, not the managed
- // value.
- base::ListValue sync_value;
- sync_value.AppendString("http://crbug.com");
- syncer::SyncChangeList list;
- list.push_back(MakeRemoteChange(1, kListPrefName, sync_value,
- SyncChange::ACTION_UPDATE));
- pref_sync_service_->ProcessSyncChanges(FROM_HERE, list);
-
- EXPECT_TRUE(managed_value.Equals(prefs_.GetManagedPref(kListPrefName)));
- EXPECT_TRUE(sync_value.Equals(prefs_.GetUserPref(kListPrefName)));
-}
-
TEST_F(PrefServiceSyncableTest, DynamicManagedPreferences) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
@@ -501,7 +679,7 @@ TEST_F(PrefServiceSyncableTest, DynamicManagedDefaultPreferences) {
syncer::SyncChangeList out;
InitWithSyncDataTakeOutput(syncer::SyncDataList(), &out);
- EXPECT_TRUE(IsSynced(kStringPrefName));
+ EXPECT_TRUE(IsRegistered(kStringPrefName));
EXPECT_TRUE(pref->IsDefaultValue());
EXPECT_FALSE(FindValue(kStringPrefName, out).get());
out.clear();
diff --git a/chromium/components/sync_preferences/testing_pref_service_syncable.cc b/chromium/components/sync_preferences/testing_pref_service_syncable.cc
index 92fa102683d..e42f5020b72 100644
--- a/chromium/components/sync_preferences/testing_pref_service_syncable.cc
+++ b/chromium/components/sync_preferences/testing_pref_service_syncable.cc
@@ -4,6 +4,8 @@
#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include <memory>
+
#include "base/bind.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_notifier_impl.h"
@@ -31,7 +33,7 @@ TestingPrefServiceBase<sync_preferences::PrefServiceSyncable,
pref_notifier),
user_prefs,
pref_registry,
- nullptr, // pref_model_associator_client
+ /*pref_model_associator_client=*/nullptr,
base::Bind(&TestingPrefServiceBase<
PrefServiceSyncable,
user_prefs::PrefRegistrySyncable>::HandleReadError),
diff --git a/chromium/components/sync_preferences/testing_pref_service_syncable.h b/chromium/components/sync_preferences/testing_pref_service_syncable.h
index cf83573fcdf..ee59cc1dfad 100644
--- a/chromium/components/sync_preferences/testing_pref_service_syncable.h
+++ b/chromium/components/sync_preferences/testing_pref_service_syncable.h
@@ -16,6 +16,18 @@ class PrefRegistrySyncable;
namespace sync_preferences {
// Test version of PrefServiceSyncable.
+// This class hierarchy has a flaw: TestingPrefServiceBase is inheriting from
+// the first template parameter (PrefServiceSyncable in this case). This means,
+// all of the supported parameter types must support the same constructor
+// signatures -- which they don't. Hence, it's not possible to properly inject
+// a PrefModelAssociatorClient.
+// TODO(tschumann) The whole purpose of TestingPrefServiceBase is questionable
+// and I'd be in favor of removing it completely:
+// -- it hides the dependency injetion of the different stores
+// -- just to later offer ways to manipulate speficic stores.
+// -- if tests just dependency injects the individual stores directly, they
+// already have full control and won't need that indirection at all.
+// See PrefServiceSyncableMergeTest as an example of a cleaner way.
class TestingPrefServiceSyncable
: public TestingPrefServiceBase<PrefServiceSyncable,
user_prefs::PrefRegistrySyncable> {
@@ -34,8 +46,6 @@ class TestingPrefServiceSyncable
// a PrefRegistry via its constructor (or via e.g. PrefServiceFactory).
user_prefs::PrefRegistrySyncable* registry();
- using PrefServiceSyncable::SetPrefModelAssociatorClientForTesting;
-
private:
DISALLOW_COPY_AND_ASSIGN(TestingPrefServiceSyncable);
};
diff --git a/chromium/components/sync_sessions/BUILD.gn b/chromium/components/sync_sessions/BUILD.gn
index e66739c899e..099cce20c8e 100644
--- a/chromium/components/sync_sessions/BUILD.gn
+++ b/chromium/components/sync_sessions/BUILD.gn
@@ -4,6 +4,8 @@
static_library("sync_sessions") {
sources = [
+ "abstract_sessions_sync_manager.cc",
+ "abstract_sessions_sync_manager.h",
"favicon_cache.cc",
"favicon_cache.h",
"local_session_event_handler_impl.cc",
@@ -17,6 +19,10 @@ static_library("sync_sessions") {
"open_tabs_ui_delegate_impl.h",
"session_data_type_controller.cc",
"session_data_type_controller.h",
+ "session_store.cc",
+ "session_store.h",
+ "session_sync_bridge.cc",
+ "session_sync_bridge.h",
"sessions_global_id_mapper.cc",
"sessions_global_id_mapper.h",
"sessions_sync_manager.cc",
@@ -90,6 +96,8 @@ source_set("unit_tests") {
"lost_navigations_recorder_unittest.cc",
"open_tabs_ui_delegate_impl_unittest.cc",
"session_data_type_controller_unittest.cc",
+ "session_store_unittest.cc",
+ "session_sync_bridge_unittest.cc",
"sessions_global_id_mapper_unittest.cc",
"sessions_sync_manager_unittest.cc",
"synced_session_tracker_unittest.cc",
diff --git a/chromium/components/sync_sessions/abstract_sessions_sync_manager.cc b/chromium/components/sync_sessions/abstract_sessions_sync_manager.cc
new file mode 100644
index 00000000000..a022ccc6b49
--- /dev/null
+++ b/chromium/components/sync_sessions/abstract_sessions_sync_manager.cc
@@ -0,0 +1,13 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/sync_sessions/abstract_sessions_sync_manager.h"
+
+namespace sync_sessions {
+
+AbstractSessionsSyncManager::AbstractSessionsSyncManager() = default;
+
+AbstractSessionsSyncManager::~AbstractSessionsSyncManager() = default;
+
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/abstract_sessions_sync_manager.h b/chromium/components/sync_sessions/abstract_sessions_sync_manager.h
new file mode 100644
index 00000000000..b13743af166
--- /dev/null
+++ b/chromium/components/sync_sessions/abstract_sessions_sync_manager.h
@@ -0,0 +1,43 @@
+// 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 COMPONENTS_SYNC_SESSIONS_ABSTRACT_SESSIONS_SYNC_MANAGER_H_
+#define COMPONENTS_SYNC_SESSIONS_ABSTRACT_SESSIONS_SYNC_MANAGER_H_
+
+#include "base/macros.h"
+
+namespace syncer {
+class ModelTypeSyncBridge;
+class SyncableService;
+} // namespace syncer
+
+namespace sync_sessions {
+
+class FaviconCache;
+class OpenTabsUIDelegate;
+class SessionsGlobalIdMapper;
+
+// TODO(crbug.com/681921): Remove this interface once the migration to USS
+// is completed and the old code removed.
+class AbstractSessionsSyncManager {
+ public:
+ AbstractSessionsSyncManager();
+ virtual ~AbstractSessionsSyncManager();
+
+ virtual void ScheduleGarbageCollection() = 0;
+ virtual FaviconCache* GetFaviconCache() = 0;
+ virtual SessionsGlobalIdMapper* GetGlobalIdMapper() = 0;
+ virtual OpenTabsUIDelegate* GetOpenTabsUIDelegate() = 0;
+ virtual void OnSessionRestoreComplete() = 0;
+ // Exactly one of the two below returns nullptr.
+ virtual syncer::SyncableService* GetSyncableService() = 0;
+ virtual syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AbstractSessionsSyncManager);
+};
+
+} // namespace sync_sessions
+
+#endif // COMPONENTS_SYNC_SESSIONS_ABSTRACT_SESSIONS_SYNC_MANAGER_H_
diff --git a/chromium/components/sync_sessions/favicon_cache.cc b/chromium/components/sync_sessions/favicon_cache.cc
index d451d6bdac0..446b061a23b 100644
--- a/chromium/components/sync_sessions/favicon_cache.cc
+++ b/chromium/components/sync_sessions/favicon_cache.cc
@@ -987,16 +987,13 @@ void FaviconCache::DropPartialFavicon(FaviconMap::iterator favicon_iter,
}
void FaviconCache::OnURLsDeleted(history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
+ const history::DeletionInfo& deletion_info) {
// We only care about actual user (or sync) deletions.
- if (expired)
+ if (deletion_info.is_from_expiration())
return;
- if (!all_history) {
- DeleteSyncedFavicons(favicon_urls);
+ if (!deletion_info.IsAllHistory()) {
+ DeleteSyncedFavicons(deletion_info.favicon_urls());
return;
}
diff --git a/chromium/components/sync_sessions/favicon_cache.h b/chromium/components/sync_sessions/favicon_cache.h
index 9ed3dc294bf..378b15d54b8 100644
--- a/chromium/components/sync_sessions/favicon_cache.h
+++ b/chromium/components/sync_sessions/favicon_cache.h
@@ -201,10 +201,7 @@ class FaviconCache : public syncer::SyncableService,
// history::HistoryServiceObserver:
void OnURLsDeleted(history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const history::DeletionInfo& deletion_info) override;
favicon::FaviconService* favicon_service_;
diff --git a/chromium/components/sync_sessions/favicon_cache_unittest.cc b/chromium/components/sync_sessions/favicon_cache_unittest.cc
index 1ed52756b5a..247888d5821 100644
--- a/chromium/components/sync_sessions/favicon_cache_unittest.cc
+++ b/chromium/components/sync_sessions/favicon_cache_unittest.cc
@@ -1355,8 +1355,7 @@ TEST_F(SyncFaviconCacheTest, HistoryFullClear) {
EXPECT_TRUE(changes.empty());
EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
- cache()->OnURLsDeleted(nullptr, true, false, history::URLRows(),
- std::set<GURL>());
+ cache()->OnURLsDeleted(nullptr, history::DeletionInfo::ForAllHistory());
EXPECT_EQ(0U, GetFaviconCount());
changes = processor()->GetAndResetChangeList();
ASSERT_EQ(changes.size(), static_cast<size_t>(kFaviconBatchSize)*2);
@@ -1405,8 +1404,9 @@ TEST_F(SyncFaviconCacheTest, HistorySubsetClear) {
EXPECT_TRUE(changes.empty());
EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize), GetFaviconCount());
- cache()->OnURLsDeleted(nullptr, false, false, history::URLRows(),
- favicon_urls_to_delete);
+ cache()->OnURLsDeleted(
+ nullptr, history::DeletionInfo::ForUrls(history::URLRows(),
+ favicon_urls_to_delete));
EXPECT_EQ(static_cast<size_t>(kFaviconBatchSize)/2, GetFaviconCount());
changes = processor()->GetAndResetChangeList();
ASSERT_EQ(changes.size(), static_cast<size_t>(kFaviconBatchSize));
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl.cc b/chromium/components/sync_sessions/local_session_event_handler_impl.cc
index 0f823e13377..aec1b2533a2 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl.cc
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl.cc
@@ -41,28 +41,27 @@ bool IsWindowSyncable(const SyncedWindowDelegate& window_delegate) {
// we have no tabbed window, we may also have sync data with conflicting sync
// ids, but to keep this logic simple and less error prone, we do not attempt
// to do anything clever.
-std::map<int, size_t> DetectDuplicateSyncIds(
+//
+// Returns tabs grouped by sync id (tab_node_id).
+std::map<int, std::vector<SyncedTabDelegate*>> GroupTabsBySyncId(
const SyncedWindowDelegatesGetter::SyncedWindowDelegateMap& windows) {
- std::map<int, size_t> sync_id_count;
+ std::map<int, std::vector<SyncedTabDelegate*>> tabs_per_sync_id;
int duplicate_count = 0;
for (auto& window_iter_pair : windows) {
const SyncedWindowDelegate* window_delegate = window_iter_pair.second;
- if (IsWindowSyncable(*window_delegate)) {
- for (int j = 0; j < window_delegate->GetTabCount(); ++j) {
- SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j);
- if (synced_tab &&
- synced_tab->GetSyncId() != TabNodePool::kInvalidTabNodeID) {
- auto iter = sync_id_count.find(synced_tab->GetSyncId());
- if (iter == sync_id_count.end()) {
- sync_id_count.insert(iter,
- std::make_pair(synced_tab->GetSyncId(), 1));
- } else {
- // If an id is used more than twice, this count will be a bit odd,
- // but for our purposes, it will be sufficient.
- duplicate_count++;
- iter->second++;
- }
- }
+ for (int j = 0; j < window_delegate->GetTabCount(); ++j) {
+ SyncedTabDelegate* synced_tab = window_delegate->GetTabAt(j);
+ if (!synced_tab ||
+ synced_tab->GetSyncId() == TabNodePool::kInvalidTabNodeID) {
+ continue;
+ }
+ std::vector<SyncedTabDelegate*>* synced_tabs =
+ &tabs_per_sync_id[synced_tab->GetSyncId()];
+ synced_tabs->push_back(synced_tab);
+ if (synced_tabs->size() > 1) {
+ // If an id is used more than twice, this count will be a bit odd,
+ // but for our purposes, it will be sufficient.
+ duplicate_count++;
}
}
}
@@ -70,8 +69,38 @@ std::map<int, size_t> DetectDuplicateSyncIds(
if (duplicate_count > 0) {
UMA_HISTOGRAM_COUNTS_100("Sync.SesssionsDuplicateSyncId", duplicate_count);
}
+ return tabs_per_sync_id;
+}
- return sync_id_count;
+// Function to resolve a conflict when multiple tabs reported by the delegate
+// contain a shared sync ID (tab_node_id). |initially_associated_tab_id| can be
+// invalid if |tab_node_id| is currently not associated in the tracker.
+const SyncedTabDelegate* ResolveConflictingSyncId(
+ int tab_node_id,
+ SessionID initially_associated_tab_id,
+ const std::vector<SyncedTabDelegate*>& synced_tabs) {
+ DCHECK_GT(synced_tabs.size(), 1U);
+ // If among the conflicting tabs, there's one which matches what sync knows
+ // about, we should prefer that. This should be rare but is possible for
+ // example if a Custom tab was being synced without a tabbed window, and
+ // suddenly the tabbed window shows up with conflicting sync IDs.
+ for (const SyncedTabDelegate* synced_tab : synced_tabs) {
+ if (synced_tab->GetSessionId() == initially_associated_tab_id) {
+ return synced_tab;
+ }
+ }
+ // In doubt, prefer non-placeholder tabs, because we cannot do anything about
+ // placeholder tabs that the tracker doesn't know about (because the delegate
+ // does not provide enough information to start tracking it).
+ for (const SyncedTabDelegate* synced_tab : synced_tabs) {
+ if (!synced_tab->IsPlaceholderTab()) {
+ // If multiple non-placeholder tabs have the same sync ID, choose among
+ // them arbitrarily.
+ return synced_tab;
+ }
+ }
+ // We have multiple conflicting placeholder tabs, so choose arbitrarily.
+ return synced_tabs.front();
}
} // namespace
@@ -98,6 +127,7 @@ LocalSessionEventHandlerImpl::LocalSessionEventHandlerImpl(
current_session_tag_ = session_tracker_->GetLocalSessionTag();
DCHECK(!current_session_tag_.empty());
+ AssociateExistingSyncIds();
AssociateWindows(RELOAD_TABS, ScanForTabbedWindow(), initial_batch);
}
@@ -109,6 +139,36 @@ LocalSessionEventHandlerImpl::GetTabSpecificsFromDelegateForTest(
return GetTabSpecificsFromDelegate(tab_delegate);
}
+void LocalSessionEventHandlerImpl::AssociateExistingSyncIds() {
+ const SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows =
+ sessions_client_->GetSyncedWindowDelegatesGetter()
+ ->GetSyncedWindowDelegates();
+
+ const std::map<int, std::vector<SyncedTabDelegate*>> tabs_per_sync_id =
+ GroupTabsBySyncId(windows);
+
+ for (const auto& sync_id_and_tabs : tabs_per_sync_id) {
+ const int tab_node_id = sync_id_and_tabs.first;
+ const std::vector<SyncedTabDelegate*>& tabs = sync_id_and_tabs.second;
+
+ const SessionID initially_associated_tab_id =
+ session_tracker_->LookupTabIdFromTabNodeId(current_session_tag_,
+ tab_node_id);
+ const SyncedTabDelegate* selected_tab =
+ tabs.size() == 1 ? tabs.front()
+ : ResolveConflictingSyncId(
+ tab_node_id, initially_associated_tab_id, tabs);
+ // Execute the result of the conflict resolution.
+ session_tracker_->ReassociateLocalTab(tab_node_id,
+ selected_tab->GetSessionId());
+ for (SyncedTabDelegate* synced_tab : tabs) {
+ if (synced_tab != selected_tab) {
+ synced_tab->SetSyncId(TabNodePool::kInvalidTabNodeID);
+ }
+ }
+ }
+}
+
void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
bool has_tabbed_window,
WriteBatch* batch) {
@@ -133,7 +193,7 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
// session; the current tabbed windows are now the source of truth.
session_tracker_->ResetSessionTracking(current_session_tag_);
current_session->modified_time = base::Time::Now();
- } else {
+ } else if (option == RELOAD_TABS) {
DVLOG(1) << "Found no tabbed windows. Reloading "
<< current_session->windows.size()
<< " windows from previous session.";
@@ -149,12 +209,15 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
// through and update them to the new SessionIds.
for (auto& win_iter : current_session->windows) {
for (auto& tab : win_iter.second->wrapped_window.tabs) {
- int sync_id = TabNodePool::kInvalidTabNodeID;
- if (!session_tracker_->GetTabNodeFromLocalTabId(tab->tab_id,
- &sync_id) ||
- sync_id == TabNodePool::kInvalidTabNodeID) {
+ int sync_id = session_tracker_->LookupTabNodeFromTabId(
+ current_session_tag_, tab->tab_id);
+ // In rare cases, the local model could contain a tab that doesn't
+ // have a sync ID, if the restored header referenced a tab ID but the
+ // tab entity didn't exist (e.g. was unsyncable).
+ if (sync_id == TabNodePool::kInvalidTabNodeID) {
continue;
}
+
DVLOG(1) << "Rewriting tab node " << sync_id << " with tab id "
<< tab->tab_id.id();
AppendChangeForExistingTab(sync_id, *tab, batch);
@@ -162,7 +225,6 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
}
}
- const std::map<int, size_t> sync_id_count = DetectDuplicateSyncIds(windows);
for (auto& window_iter_pair : windows) {
const SyncedWindowDelegate* window_delegate = window_iter_pair.second;
if (option == RELOAD_TABS) {
@@ -194,20 +256,6 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
continue;
}
- if (synced_tab->GetSyncId() != TabNodePool::kInvalidTabNodeID) {
- auto duplicate_iter = sync_id_count.find(synced_tab->GetSyncId());
- DCHECK(duplicate_iter != sync_id_count.end());
- if (duplicate_iter->second > 1) {
- // Strip the id before processing it. This is going to mean it'll be
- // treated the same as a new tab. If it's also a placeholder, we'll
- // have no data about it, sync it cannot be synced until it is
- // loaded. It is too difficult to try to guess which of the multiple
- // tabs using the same id actually corresponds to the existing sync
- // data.
- synced_tab->SetSyncId(TabNodePool::kInvalidTabNodeID);
- }
- }
-
// Placeholder tabs are those without WebContents, either because they
// were never loaded into memory or they were evicted from memory
// (typically only on Android devices). They only have a tab id,
@@ -278,7 +326,7 @@ void LocalSessionEventHandlerImpl::AssociateWindows(ReloadTabsOption option,
auto specifics = std::make_unique<sync_pb::SessionSpecifics>();
specifics->set_session_tag(current_session_tag_);
current_session->ToSessionHeaderProto().Swap(specifics->mutable_header());
- batch->Update(std::move(specifics));
+ batch->Put(std::move(specifics));
}
void LocalSessionEventHandlerImpl::AssociateTab(
@@ -305,17 +353,17 @@ void LocalSessionEventHandlerImpl::AssociateTab(
DVLOG(1) << "Syncing tab " << tab_id.id() << " from window "
<< tab_delegate->GetWindowId().id();
- int tab_node_id = TabNodePool::kInvalidTabNodeID;
- bool existing_tab_node = true;
- if (session_tracker_->IsLocalTabNodeAssociated(tab_delegate->GetSyncId())) {
- tab_node_id = tab_delegate->GetSyncId();
- session_tracker_->ReassociateLocalTab(tab_node_id, tab_id);
+ int tab_node_id =
+ session_tracker_->LookupTabNodeFromTabId(current_session_tag_, tab_id);
+
+ if (tab_node_id != TabNodePool::kInvalidTabNodeID) {
+ DCHECK(tab_delegate->GetSyncId() == TabNodePool::kInvalidTabNodeID ||
+ tab_delegate->GetSyncId() == tab_node_id);
} else if (has_tabbed_window) {
- existing_tab_node =
- session_tracker_->GetTabNodeFromLocalTabId(tab_id, &tab_node_id);
- CHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id)
+ // Allocate a new (or reused) sync node for this tab.
+ tab_node_id = session_tracker_->AssociateLocalTabWithFreeTabNode(tab_id);
+ DCHECK_NE(TabNodePool::kInvalidTabNodeID, tab_node_id)
<< "https://crbug.com/639009";
- tab_delegate->SetSyncId(tab_node_id);
} else {
// Only allowed to allocate sync ids when we have native data, which is only
// true when we have a tabbed window. Without a sync id we cannot sync this
@@ -326,6 +374,8 @@ void LocalSessionEventHandlerImpl::AssociateTab(
return;
}
+ tab_delegate->SetSyncId(tab_node_id);
+
// Get the previously synced url.
sessions::SessionTab* session_tab =
session_tracker_->GetTab(current_session_tag_, tab_id);
@@ -349,11 +399,7 @@ void LocalSessionEventHandlerImpl::AssociateTab(
DCHECK(!session_tab->timestamp.is_null());
// Write to the sync model itself.
- if (existing_tab_node) {
- batch->Update(std::move(specifics));
- } else {
- batch->Add(std::move(specifics));
- }
+ batch->Put(std::move(specifics));
int current_index = tab_delegate->GetCurrentEntryIndex();
const GURL new_url = tab_delegate->GetVirtualURLAtIndex(current_index);
@@ -422,6 +468,7 @@ void LocalSessionEventHandlerImpl::OnLocalTabModified(
bool found_tabbed_window = ScanForTabbedWindow();
std::unique_ptr<WriteBatch> batch = delegate_->CreateLocalSessionWriteBatch();
+ AssociateExistingSyncIds();
AssociateTab(modified_tab, found_tabbed_window, batch.get());
// Note, we always associate windows because it's possible a tab became
// "interesting" by going to a valid URL, in which case it needs to be added
@@ -446,27 +493,23 @@ void LocalSessionEventHandlerImpl::AssociateRestoredPlaceholderTab(
SessionID new_tab_id,
SessionID new_window_id,
WriteBatch* batch) {
- DCHECK_NE(tab_delegate.GetSyncId(), TabNodePool::kInvalidTabNodeID);
-
- // It's possible the placeholder tab is associated with a tab node that's
- // since been deleted. If that's the case, there's no way to reassociate it,
- // so just return now without adding the tab to the session tracker.
- if (!session_tracker_->IsLocalTabNodeAssociated(tab_delegate.GetSyncId())) {
- DVLOG(1) << "Restored placeholder tab's node " << tab_delegate.GetSyncId()
- << " deleted.";
- return;
- }
-
- // Update tracker with the new association (and inform it of the tab node
- // in the process).
- session_tracker_->ReassociateLocalTab(tab_delegate.GetSyncId(), new_tab_id);
+ int tab_node_id = tab_delegate.GetSyncId();
+ DCHECK_NE(tab_node_id, TabNodePool::kInvalidTabNodeID);
+ DCHECK_EQ(new_tab_id, session_tracker_->LookupTabIdFromTabNodeId(
+ current_session_tag_, tab_node_id));
// Update the window id on the SessionTab itself.
sessions::SessionTab* local_tab =
session_tracker_->GetTab(current_session_tag_, new_tab_id);
local_tab->window_id = new_window_id;
- AppendChangeForExistingTab(tab_delegate.GetSyncId(), *local_tab, batch);
+ // Filter out placeholder tabs that have been associated but don't have known
+ // sync data.
+ if (local_tab->navigations.empty()) {
+ return;
+ }
+
+ AppendChangeForExistingTab(tab_node_id, *local_tab, batch);
}
void LocalSessionEventHandlerImpl::AppendChangeForExistingTab(
@@ -479,7 +522,7 @@ void LocalSessionEventHandlerImpl::AppendChangeForExistingTab(
tab.ToSyncData().Swap(specifics->mutable_tab());
specifics->set_session_tag(current_session_tag_);
specifics->set_tab_node_id(sync_id);
- batch->Update(std::move(specifics));
+ batch->Put(std::move(specifics));
}
sync_pb::SessionTab LocalSessionEventHandlerImpl::GetTabSpecificsFromDelegate(
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl.h b/chromium/components/sync_sessions/local_session_event_handler_impl.h
index 25519634681..071b593b266 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl.h
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl.h
@@ -37,9 +37,7 @@ class LocalSessionEventHandlerImpl : public LocalSessionEventHandler {
WriteBatch();
virtual ~WriteBatch();
virtual void Delete(int tab_node_id) = 0;
- virtual void Add(std::unique_ptr<sync_pb::SessionSpecifics> specifics) = 0;
- virtual void Update(
- std::unique_ptr<sync_pb::SessionSpecifics> specifics) = 0;
+ virtual void Put(std::unique_ptr<sync_pb::SessionSpecifics> specifics) = 0;
virtual void Commit() = 0;
private:
@@ -81,6 +79,16 @@ class LocalSessionEventHandlerImpl : public LocalSessionEventHandler {
private:
enum ReloadTabsOption { RELOAD_TABS, DONT_RELOAD_TABS };
+
+ // Updates |session_tracker_| with tab_id<->tab_node_id association that the
+ // delegate already knows about, while resolving conflicts if the delegate
+ // reports conflicting sync IDs. This makes sure duplicate tab_node_id-s are
+ // not assigned. On return, the following conditions are met:
+ // 1. Delegate contains no duplicate sync IDs (tab_node_id).
+ // 2. Delegate contains no sync-ID <-> tab_id association that the tracker
+ // doesn't know about (but not the opposite).
+ void AssociateExistingSyncIds();
+
void AssociateWindows(ReloadTabsOption option,
bool has_tabbed_window,
WriteBatch* batch);
diff --git a/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc b/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
index ec0db039949..38da108a3ae 100644
--- a/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
+++ b/chromium/components/sync_sessions/local_session_event_handler_impl_unittest.cc
@@ -47,9 +47,6 @@ const base::Time kTime0 = base::Time::FromInternalValue(100);
const base::Time kTime1 = base::Time::FromInternalValue(110);
const base::Time kTime2 = base::Time::FromInternalValue(120);
const base::Time kTime3 = base::Time::FromInternalValue(130);
-const base::Time kTime4 = base::Time::FromInternalValue(140);
-const base::Time kTime5 = base::Time::FromInternalValue(150);
-const base::Time kTime6 = base::Time::FromInternalValue(190);
const int kWindowId1 = 1000001;
const int kWindowId2 = 1000002;
@@ -63,19 +60,8 @@ class MockWriteBatch : public LocalSessionEventHandlerImpl::WriteBatch {
MockWriteBatch() {}
~MockWriteBatch() override {}
- void Add(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
- DoAdd(specifics.get());
- }
-
- void Update(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
- DoUpdate(specifics.get());
- }
-
MOCK_METHOD1(Delete, void(int tab_node_id));
- // TODO(crbug.com/729950): Use unique_ptr here direclty once move-only
- // arguments are supported in gMock.
- MOCK_METHOD1(DoAdd, void(sync_pb::SessionSpecifics* specifics));
- MOCK_METHOD1(DoUpdate, void(sync_pb::SessionSpecifics* specifics));
+ MOCK_METHOD1(Put, void(std::unique_ptr<sync_pb::SessionSpecifics> specifics));
MOCK_METHOD0(Commit, void());
};
@@ -294,10 +280,9 @@ TEST_F(LocalSessionEventHandlerImplTest, AssociateWindowsAndTabsIfEmpty) {
EXPECT_CALL(mock_delegate_, OnFaviconVisited(_, _)).Times(0);
StrictMock<MockWriteBatch> mock_batch;
- EXPECT_CALL(
- mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, /*window_ids=*/IsEmpty(),
- /*tabs_ids=*/IsEmpty()))));
+ EXPECT_CALL(mock_batch,
+ Put(Pointee(MatchesHeader(kSessionTag, /*window_ids=*/IsEmpty(),
+ /*tabs_ids=*/IsEmpty()))));
InitHandler(&mock_batch);
}
@@ -320,21 +305,20 @@ TEST_F(LocalSessionEventHandlerImplTest, AssociateWindowsAndTabs) {
EXPECT_CALL(mock_delegate_, OnFaviconVisited(GURL(kBaz1), _));
StrictMock<MockWriteBatch> mock_batch;
- EXPECT_CALL(
- mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, {kWindowId1, kWindowId2},
- {kTabId1, kTabId2, kTabId3}))));
EXPECT_CALL(mock_batch,
- DoAdd(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1,
- /*tab_node_id=*/_,
- /*urls=*/{kFoo1}))));
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1, kWindowId2},
+ {kTabId1, kTabId2, kTabId3}))));
+ EXPECT_CALL(mock_batch,
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1,
+ /*tab_node_id=*/_,
+ /*urls=*/{kFoo1}))));
EXPECT_CALL(mock_batch,
- DoAdd(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId2,
- /*tab_node_id=*/_, /*urls=*/{kBar1}))));
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId2,
+ /*tab_node_id=*/_, /*urls=*/{kBar1}))));
EXPECT_CALL(
mock_batch,
- DoAdd(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId3,
- /*tab_node_id=*/_, /*urls=*/{kBar2, kBaz1}))));
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId3,
+ /*tab_node_id=*/_, /*urls=*/{kBar2, kBaz1}))));
InitHandler(&mock_batch);
}
@@ -389,15 +373,16 @@ TEST_F(LocalSessionEventHandlerImplTest, AssociateCustomTab) {
StrictMock<MockWriteBatch> mock_batch;
testing::InSequence seq;
EXPECT_CALL(mock_batch,
- DoUpdate(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1,
- kRegularTabNodeId, /*urls=*/{}))));
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1,
+ kRegularTabNodeId, /*urls=*/{}))));
+ // Overriden by the Put() below, so we don't care about the args.
EXPECT_CALL(mock_batch,
- DoUpdate(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId2,
- kCustomTabNodeId, /*urls=*/{}))));
- EXPECT_CALL(mock_batch, DoUpdate(Pointee(MatchesTab(kSessionTag, kWindowId3,
- kTabId3, kCustomTabNodeId,
- /*urls=*/{kFoo1}))));
- EXPECT_CALL(mock_batch, DoUpdate(Pointee(MatchesHeader(
+ Put(Pointee(MatchesTab(kSessionTag, _, _, kCustomTabNodeId,
+ /*urls=*/_))));
+ EXPECT_CALL(mock_batch, Put(Pointee(MatchesTab(kSessionTag, kWindowId3,
+ kTabId3, kCustomTabNodeId,
+ /*urls=*/{kFoo1}))));
+ EXPECT_CALL(mock_batch, Put(Pointee(MatchesHeader(
kSessionTag, {kWindowId1, kWindowId2, kWindowId3},
{kTabId1, kTabId3}))));
InitHandler(&mock_batch);
@@ -409,6 +394,27 @@ TEST_F(LocalSessionEventHandlerImplTest, AssociateCustomTab) {
{kWindowId3, std::vector<int>{kTabId3}}}));
}
+// Tests that calling initial association during construction handles the case
+// where only a subset of tabs (and not the first) have a sync ID.
+TEST_F(LocalSessionEventHandlerImplTest, AssociateTabsWhenOnlySomeHaveNodeIds) {
+ const int kTabNodeId = 0;
+
+ AddWindow(kWindowId1);
+ AddTab(kWindowId1, kFoo1, kTabId1);
+ AddTab(kWindowId1, kBar1, kTabId2)->SetSyncId(kTabNodeId);
+
+ StrictMock<MockWriteBatch> mock_batch;
+ EXPECT_CALL(mock_batch, Put(Pointee(MatchesHeader(_, _, _))));
+ EXPECT_CALL(mock_batch,
+ Put(Pointee(MatchesTab(_, _, kTabId1, /*tab_node_id=*/1,
+ /*urls=*/_))));
+ EXPECT_CALL(mock_batch,
+ Put(Pointee(MatchesTab(_, _, kTabId2,
+ /*tab_node_id=*/kTabNodeId, /*urls=*/_))));
+
+ InitHandler(&mock_batch);
+}
+
TEST_F(LocalSessionEventHandlerImplTest, PropagateNewNavigation) {
AddWindow(kWindowId1);
TestSyncedTabDelegate* tab = AddTab(kWindowId1, kFoo1, kTabId1);
@@ -420,11 +426,11 @@ TEST_F(LocalSessionEventHandlerImplTest, PropagateNewNavigation) {
// OK because sync will avoid updating an entity with identical content.
EXPECT_CALL(
*update_mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, {kWindowId1}, {kTabId1}))));
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1}, {kTabId1}))));
EXPECT_CALL(*update_mock_batch,
- DoUpdate(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1,
- /*tab_node_id=*/_,
- /*urls=*/{kFoo1, kBar1}))));
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1,
+ /*tab_node_id=*/_,
+ /*urls=*/{kFoo1, kBar1}))));
EXPECT_CALL(*update_mock_batch, Commit());
EXPECT_CALL(mock_delegate_, CreateLocalSessionWriteBatch())
@@ -446,16 +452,16 @@ TEST_F(LocalSessionEventHandlerImplTest, PropagateNewTab) {
auto tab_create_mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
EXPECT_CALL(
*tab_create_mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, {kWindowId1}, {kTabId1}))));
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1}, {kTabId1}))));
EXPECT_CALL(*tab_create_mock_batch, Commit());
auto navigation_mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
EXPECT_CALL(*navigation_mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, {kWindowId1},
- {kTabId1, kTabId2}))));
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1},
+ {kTabId1, kTabId2}))));
EXPECT_CALL(*navigation_mock_batch,
- DoAdd(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId2,
- /*tab_node_id=*/_, /*urls=*/{kBar1}))));
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId2,
+ /*tab_node_id=*/_, /*urls=*/{kBar1}))));
EXPECT_CALL(*navigation_mock_batch, Commit());
EXPECT_CALL(mock_delegate_, CreateLocalSessionWriteBatch())
@@ -478,18 +484,17 @@ TEST_F(LocalSessionEventHandlerImplTest, PropagateNewWindow) {
// the window is not syncable and is hence skipped.
auto tab_create_mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
EXPECT_CALL(*tab_create_mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, {kWindowId1},
- {kTabId1, kTabId2}))));
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1},
+ {kTabId1, kTabId2}))));
EXPECT_CALL(*tab_create_mock_batch, Commit());
auto navigation_mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
- EXPECT_CALL(
- *navigation_mock_batch,
- DoUpdate(Pointee(MatchesHeader(kSessionTag, {kWindowId1, kWindowId2},
- {kTabId1, kTabId2, kTabId3}))));
EXPECT_CALL(*navigation_mock_batch,
- DoAdd(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId3,
- /*tab_node_id=*/_, /*urls=*/{kBaz1}))));
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1, kWindowId2},
+ {kTabId1, kTabId2, kTabId3}))));
+ EXPECT_CALL(*navigation_mock_batch,
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId2, kTabId3,
+ /*tab_node_id=*/_, /*urls=*/{kBaz1}))));
EXPECT_CALL(*navigation_mock_batch, Commit());
EXPECT_CALL(mock_delegate_, CreateLocalSessionWriteBatch())
@@ -500,5 +505,70 @@ TEST_F(LocalSessionEventHandlerImplTest, PropagateNewWindow) {
AddTab(kWindowId2, kBaz1, kTabId3);
}
+TEST_F(LocalSessionEventHandlerImplTest,
+ PropagateNewNavigationWithoutTabbedWindows) {
+ const int kTabNodeId1 = 0;
+ const int kTabNodeId2 = 1;
+
+ // The tracker is initially restored from persisted state, containing two
+ // custom tabs.
+ sync_pb::SessionSpecifics custom_tab1;
+ custom_tab1.set_session_tag(kSessionTag);
+ custom_tab1.set_tab_node_id(kTabNodeId1);
+ custom_tab1.mutable_tab()->set_window_id(kWindowId1);
+ custom_tab1.mutable_tab()->set_tab_id(kTabId1);
+ session_tracker_.ReassociateLocalTab(kTabNodeId1,
+ SessionID::FromSerializedValue(kTabId1));
+ UpdateTrackerWithSpecifics(custom_tab1, base::Time::Now(), &session_tracker_);
+
+ sync_pb::SessionSpecifics custom_tab2;
+ custom_tab2.set_session_tag(kSessionTag);
+ custom_tab2.set_tab_node_id(kTabNodeId2);
+ custom_tab2.mutable_tab()->set_window_id(kWindowId2);
+ custom_tab2.mutable_tab()->set_tab_id(kTabId2);
+ session_tracker_.ReassociateLocalTab(kTabNodeId2,
+ SessionID::FromSerializedValue(kTabId2));
+ UpdateTrackerWithSpecifics(custom_tab2, base::Time::Now(), &session_tracker_);
+
+ sync_pb::SessionSpecifics header;
+ header.set_session_tag(kSessionTag);
+ header.mutable_header()->add_window()->set_window_id(kWindowId1);
+ header.mutable_header()->mutable_window(0)->add_tab(kTabId1);
+ header.mutable_header()->add_window()->set_window_id(kWindowId2);
+ header.mutable_header()->mutable_window(1)->add_tab(kTabId2);
+ UpdateTrackerWithSpecifics(header, base::Time::Now(), &session_tracker_);
+
+ ASSERT_THAT(session_tracker_.LookupSession(kSessionTag),
+ MatchesSyncedSession(kSessionTag,
+ {{kWindowId1, std::vector<int>{kTabId1}},
+ {kWindowId2, std::vector<int>{kTabId2}}}));
+
+ AddWindow(kWindowId1, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
+ TestSyncedTabDelegate* tab1 = AddTab(kWindowId1, kFoo1, kTabId1);
+ tab1->SetSyncId(kTabNodeId1);
+
+ AddWindow(kWindowId2, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
+ AddTab(kWindowId2, kBar1, kTabId2)->SetSyncId(kTabNodeId2);
+
+ InitHandler();
+
+ auto update_mock_batch = std::make_unique<StrictMock<MockWriteBatch>>();
+ // Note that the header is reported again, although it hasn't changed. This is
+ // OK because sync will avoid updating an entity with identical content.
+ EXPECT_CALL(*update_mock_batch,
+ Put(Pointee(MatchesHeader(kSessionTag, {kWindowId1, kWindowId2},
+ {kTabId1, kTabId2}))));
+ EXPECT_CALL(
+ *update_mock_batch,
+ Put(Pointee(MatchesTab(kSessionTag, kWindowId1, kTabId1, kTabNodeId1,
+ /*urls=*/{kFoo1, kBaz1}))));
+ EXPECT_CALL(*update_mock_batch, Commit());
+
+ EXPECT_CALL(mock_delegate_, CreateLocalSessionWriteBatch())
+ .WillOnce(Return(ByMove(std::move(update_mock_batch))));
+
+ tab1->Navigate(kBaz1);
+}
+
} // namespace
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_store.cc b/chromium/components/sync_sessions/session_store.cc
new file mode 100644
index 00000000000..f08a600075c
--- /dev/null
+++ b/chromium/components/sync_sessions/session_store.cc
@@ -0,0 +1,617 @@
+// 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 "components/sync_sessions/session_store.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/pickle.h"
+#include "base/strings/stringprintf.h"
+#include "components/sync/base/sync_prefs.h"
+#include "components/sync/base/time.h"
+#include "components/sync/device_info/device_info.h"
+#include "components/sync/device_info/device_info_util.h"
+#include "components/sync/model/entity_change.h"
+#include "components/sync/model/metadata_batch.h"
+#include "components/sync/model/mutable_data_batch.h"
+#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync_sessions/sync_sessions_client.h"
+
+namespace sync_sessions {
+namespace {
+
+using sync_pb::SessionSpecifics;
+using syncer::MetadataChangeList;
+using syncer::ModelTypeStore;
+
+std::string TabNodeIdToClientTag(const std::string& session_tag,
+ int tab_node_id) {
+ CHECK_GT(tab_node_id, TabNodePool::kInvalidTabNodeID);
+ return base::StringPrintf("%s %d", session_tag.c_str(), tab_node_id);
+}
+
+std::string EncodeStorageKey(const std::string& session_tag, int tab_node_id) {
+ base::Pickle pickle;
+ pickle.WriteString(session_tag);
+ pickle.WriteInt(tab_node_id);
+ return std::string(static_cast<const char*>(pickle.data()), pickle.size());
+}
+
+bool DecodeStorageKey(const std::string& storage_key,
+ std::string* session_tag,
+ int* tab_node_id) {
+ base::Pickle pickle(storage_key.c_str(), storage_key.size());
+ base::PickleIterator iter(pickle);
+ if (!iter.ReadString(session_tag)) {
+ return false;
+ }
+ if (!iter.ReadInt(tab_node_id)) {
+ return false;
+ }
+ return true;
+}
+
+std::unique_ptr<syncer::EntityData> MoveToEntityData(
+ const std::string& client_name,
+ SessionSpecifics* specifics) {
+ auto entity_data = std::make_unique<syncer::EntityData>();
+ entity_data->non_unique_name = client_name;
+ if (specifics->has_header()) {
+ entity_data->non_unique_name += " (header)";
+ } else if (specifics->has_tab()) {
+ entity_data->non_unique_name +=
+ base::StringPrintf(" (tab node %d)", specifics->tab_node_id());
+ }
+ entity_data->specifics.mutable_session()->Swap(specifics);
+ return entity_data;
+}
+
+std::string GetSessionTagWithPrefs(const std::string& cache_guid,
+ syncer::SessionSyncPrefs* sync_prefs) {
+ const std::string persisted_guid = sync_prefs->GetSyncSessionsGUID();
+ if (!persisted_guid.empty()) {
+ DVLOG(1) << "Restoring persisted session sync guid: " << persisted_guid;
+ return persisted_guid;
+ }
+
+ const std::string new_guid =
+ base::StringPrintf("session_sync%s", cache_guid.c_str());
+ DVLOG(1) << "Creating session sync guid: " << new_guid;
+ sync_prefs->SetSyncSessionsGUID(new_guid);
+ return new_guid;
+}
+
+void OnLocalDeviceInfoAvailable(
+ syncer::SessionSyncPrefs* sync_prefs,
+ const syncer::LocalDeviceInfoProvider* provider,
+ const base::RepeatingCallback<void(const SessionStore::SessionInfo&)>&
+ callback) {
+ const syncer::DeviceInfo* device_info = provider->GetLocalDeviceInfo();
+ const std::string cache_guid = provider->GetLocalSyncCacheGUID();
+ DCHECK(device_info);
+ DCHECK(!cache_guid.empty());
+
+ SessionStore::SessionInfo session_info;
+ session_info.client_name = device_info->client_name();
+ session_info.device_type = device_info->device_type();
+ session_info.session_tag = GetSessionTagWithPrefs(cache_guid, sync_prefs);
+ callback.Run(session_info);
+}
+
+// Listens to local device information and triggers the provided callback
+// when the object is constructed (once DeviceInfo is available). Caller is
+// responsible for storing the returned subscription as a mechanism to cancel
+// the creation request (the subscription must not outlive |provider|).
+std::unique_ptr<syncer::LocalDeviceInfoProvider::Subscription>
+SubscribeToSessionInfo(
+ syncer::SessionSyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* provider,
+ const base::RepeatingCallback<void(const SessionStore::SessionInfo&)>&
+ callback) {
+ if (provider->GetLocalDeviceInfo()) {
+ OnLocalDeviceInfoAvailable(sync_prefs, provider, callback);
+ return nullptr;
+ }
+
+ return provider->RegisterOnInitializedCallback(base::BindRepeating(
+ &OnLocalDeviceInfoAvailable, base::Unretained(sync_prefs),
+ base::Unretained(provider), callback));
+}
+
+void ForwardError(syncer::OnceModelErrorHandler error_handler,
+ const base::Optional<syncer::ModelError>& error) {
+ if (error) {
+ std::move(error_handler).Run(*error);
+ }
+}
+
+class FactoryImpl : public base::SupportsWeakPtr<FactoryImpl> {
+ public:
+ // Raw pointers must not be null and must outlive this object.
+ FactoryImpl(SyncSessionsClient* sessions_client,
+ syncer::SessionSyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* local_device_info_provider,
+ const syncer::RepeatingModelTypeStoreFactory& store_factory,
+ const SessionStore::RestoredForeignTabCallback&
+ restored_foreign_tab_callback)
+ : sessions_client_(sessions_client),
+ store_factory_(store_factory),
+ restored_foreign_tab_callback_(restored_foreign_tab_callback) {
+ DCHECK(sessions_client);
+ DCHECK(sync_prefs);
+ DCHECK(local_device_info_provider);
+ DCHECK(store_factory_);
+ local_device_info_subscription_ = SubscribeToSessionInfo(
+ sync_prefs, local_device_info_provider,
+ base::BindRepeating(&FactoryImpl::OnSessionInfoAvailable,
+ base::Unretained(this)));
+ }
+
+ ~FactoryImpl() {}
+
+ void Create(SessionStore::FactoryCompletionCallback callback) {
+ if (!session_info_.has_value()) {
+ DVLOG(1) << "Deferring creation of store until session info is available";
+ deferred_creations_.push_back(std::move(callback));
+ return;
+ }
+
+ CreateImpl(std::move(callback));
+ }
+
+ private:
+ void OnSessionInfoAvailable(const SessionStore::SessionInfo& session_info) {
+ local_device_info_subscription_.reset();
+ session_info_ = session_info;
+
+ std::vector<SessionStore::FactoryCompletionCallback> deferred_creations;
+ std::swap(deferred_creations, deferred_creations_);
+ for (SessionStore::FactoryCompletionCallback& callback :
+ deferred_creations) {
+ CreateImpl(std::move(callback));
+ }
+ }
+
+ void CreateImpl(SessionStore::FactoryCompletionCallback callback) {
+ DCHECK(session_info_.has_value());
+ DCHECK(deferred_creations_.empty());
+ DVLOG(1) << "Initiating creation of session store";
+ store_factory_.Run(
+ syncer::SESSIONS,
+ base::BindOnce(&FactoryImpl::OnStoreCreated, base::AsWeakPtr(this),
+ std::move(callback)));
+ }
+
+ void OnStoreCreated(SessionStore::FactoryCompletionCallback callback,
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<ModelTypeStore> store) {
+ if (error) {
+ std::move(callback).Run(error, /*store=*/nullptr,
+ /*metadata_batch=*/nullptr);
+ return;
+ }
+
+ DCHECK(store);
+ ModelTypeStore* store_copy = store.get();
+ store_copy->ReadAllData(
+ base::BindOnce(&FactoryImpl::OnReadAllData, base::AsWeakPtr(this),
+ std::move(callback), std::move(store)));
+ }
+
+ void OnReadAllData(SessionStore::FactoryCompletionCallback callback,
+ std::unique_ptr<ModelTypeStore> store,
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<ModelTypeStore::RecordList> record_list) {
+ if (error) {
+ std::move(callback).Run(error, /*store=*/nullptr,
+ /*metadata_batch=*/nullptr);
+ return;
+ }
+
+ store->ReadAllMetadata(base::BindOnce(
+ &FactoryImpl::OnReadAllMetadata, base::AsWeakPtr(this),
+ std::move(callback), std::move(store), std::move(record_list)));
+ }
+
+ void OnReadAllMetadata(
+ SessionStore::FactoryCompletionCallback callback,
+ std::unique_ptr<ModelTypeStore> store,
+ std::unique_ptr<ModelTypeStore::RecordList> record_list,
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
+ if (error) {
+ std::move(callback).Run(error, /*store=*/nullptr,
+ /*metadata_batch=*/nullptr);
+ return;
+ }
+
+ std::map<std::string, sync_pb::SessionSpecifics> initial_data;
+ for (ModelTypeStore::Record& record : *record_list) {
+ const std::string& storage_key = record.id;
+ SessionSpecifics specifics;
+ if (storage_key.empty() ||
+ !specifics.ParseFromString(std::move(record.value))) {
+ DVLOG(1) << "Ignoring corrupt database entry with key: " << storage_key;
+ continue;
+ }
+ initial_data[storage_key].Swap(&specifics);
+ }
+
+ auto session_store = std::make_unique<SessionStore>(
+ sessions_client_, *session_info_, std::move(store),
+ std::move(initial_data), metadata_batch->GetAllMetadata(),
+ restored_foreign_tab_callback_);
+
+ std::move(callback).Run(/*error=*/base::nullopt, std::move(session_store),
+ std::move(metadata_batch));
+ }
+
+ SyncSessionsClient* const sessions_client_;
+ const syncer::RepeatingModelTypeStoreFactory store_factory_;
+ const SessionStore::RestoredForeignTabCallback restored_foreign_tab_callback_;
+ base::Optional<SessionStore::SessionInfo> session_info_;
+ std::vector<SessionStore::FactoryCompletionCallback> deferred_creations_;
+ std::unique_ptr<syncer::LocalDeviceInfoProvider::Subscription>
+ local_device_info_subscription_;
+};
+
+} // namespace
+
+// static
+SessionStore::Factory SessionStore::CreateFactory(
+ SyncSessionsClient* sessions_client,
+ syncer::SessionSyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* local_device_info_provider,
+ const syncer::RepeatingModelTypeStoreFactory& store_factory,
+ const RestoredForeignTabCallback& restored_foreign_tab_callback) {
+ auto factory = std::make_unique<FactoryImpl>(
+ sessions_client, sync_prefs, local_device_info_provider, store_factory,
+ restored_foreign_tab_callback);
+ return base::BindRepeating(&FactoryImpl::Create, std::move(factory));
+}
+
+SessionStore::WriteBatch::WriteBatch(
+ std::unique_ptr<ModelTypeStore::WriteBatch> batch,
+ CommitCallback commit_cb,
+ syncer::OnceModelErrorHandler error_handler,
+ SyncedSessionTracker* session_tracker)
+ : batch_(std::move(batch)),
+ commit_cb_(std::move(commit_cb)),
+ error_handler_(std::move(error_handler)),
+ session_tracker_(session_tracker) {
+ DCHECK(batch_);
+ DCHECK(commit_cb_);
+ DCHECK(error_handler_);
+ DCHECK(session_tracker_);
+}
+
+SessionStore::WriteBatch::~WriteBatch() {
+ DCHECK(!batch_) << "Destructed without prior commit";
+}
+
+std::string SessionStore::WriteBatch::PutAndUpdateTracker(
+ const sync_pb::SessionSpecifics& specifics,
+ base::Time modification_time) {
+ UpdateTrackerWithSpecifics(specifics, modification_time, session_tracker_);
+ return PutWithoutUpdatingTracker(specifics);
+}
+
+void SessionStore::WriteBatch::DeleteForeignEntityAndUpdateTracker(
+ const std::string& storage_key) {
+ std::string session_tag;
+ int tab_node_id;
+ bool success = DecodeStorageKey(storage_key, &session_tag, &tab_node_id);
+ DCHECK(success);
+ DCHECK_NE(session_tag, session_tracker_->GetLocalSessionTag());
+
+ if (tab_node_id == TabNodePool::kInvalidTabNodeID) {
+ // Removal of a foreign header entity.
+ // TODO(mastiz): This cascades with the removal of tabs too. Should we
+ // reflect this as batch_->DeleteData()? The old code didn't, presumably
+ // because we expect the rest of the removals to follow.
+ session_tracker_->DeleteForeignSession(session_tag);
+ } else {
+ // Removal of a foreign tab entity.
+ session_tracker_->DeleteForeignTab(session_tag, tab_node_id);
+ }
+
+ batch_->DeleteData(storage_key);
+}
+
+std::string SessionStore::WriteBatch::PutWithoutUpdatingTracker(
+ const sync_pb::SessionSpecifics& specifics) {
+ DCHECK(AreValidSpecifics(specifics));
+
+ const std::string storage_key = GetStorageKey(specifics);
+ batch_->WriteData(storage_key, specifics.SerializeAsString());
+ return storage_key;
+}
+
+std::string SessionStore::WriteBatch::DeleteLocalTabWithoutUpdatingTracker(
+ int tab_node_id) {
+ std::string storage_key =
+ EncodeStorageKey(session_tracker_->GetLocalSessionTag(), tab_node_id);
+ batch_->DeleteData(storage_key);
+ return storage_key;
+}
+
+MetadataChangeList* SessionStore::WriteBatch::GetMetadataChangeList() {
+ return batch_->GetMetadataChangeList();
+}
+
+// static
+void SessionStore::WriteBatch::Commit(std::unique_ptr<WriteBatch> batch) {
+ DCHECK(batch);
+ std::move(batch->commit_cb_)
+ .Run(std::move(batch->batch_),
+ base::BindOnce(&ForwardError, std::move(batch->error_handler_)));
+}
+
+// static
+bool SessionStore::AreValidSpecifics(const SessionSpecifics& specifics) {
+ if (specifics.session_tag().empty()) {
+ return false;
+ }
+ if (specifics.has_tab()) {
+ return specifics.tab_node_id() >= 0 && specifics.tab().tab_id() > 0;
+ }
+ if (specifics.has_header()) {
+ // Verify that tab IDs appear only once within a header. Intended to prevent
+ // http://crbug.com/360822.
+ std::set<int> session_tab_ids;
+ for (const sync_pb::SessionWindow& window : specifics.header().window()) {
+ for (int tab_id : window.tab()) {
+ bool success = session_tab_ids.insert(tab_id).second;
+ if (!success) {
+ return false;
+ }
+ }
+ }
+ return !specifics.has_tab() &&
+ specifics.tab_node_id() == TabNodePool::kInvalidTabNodeID;
+ }
+ return false;
+}
+
+// static
+std::string SessionStore::GetClientTag(const SessionSpecifics& specifics) {
+ DCHECK(AreValidSpecifics(specifics));
+
+ if (specifics.has_header()) {
+ return specifics.session_tag();
+ }
+
+ DCHECK(specifics.has_tab());
+ return TabNodeIdToClientTag(specifics.session_tag(), specifics.tab_node_id());
+}
+
+// static
+std::string SessionStore::GetStorageKey(const SessionSpecifics& specifics) {
+ DCHECK(AreValidSpecifics(specifics));
+ return EncodeStorageKey(specifics.session_tag(), specifics.tab_node_id());
+}
+
+// static
+std::string SessionStore::GetHeaderStorageKey(const std::string& session_tag) {
+ return EncodeStorageKey(session_tag, TabNodePool::kInvalidTabNodeID);
+}
+
+// static
+std::string SessionStore::GetTabStorageKey(const std::string& session_tag,
+ int tab_node_id) {
+ DCHECK_GE(tab_node_id, 0);
+ return EncodeStorageKey(session_tag, tab_node_id);
+}
+
+bool SessionStore::StorageKeyMatchesLocalSession(
+ const std::string& storage_key) const {
+ std::string session_tag;
+ int tab_node_id;
+ bool success = DecodeStorageKey(storage_key, &session_tag, &tab_node_id);
+ DCHECK(success);
+ return session_tag == local_session_info_.session_tag;
+}
+
+// static
+std::string SessionStore::GetTabClientTagForTest(const std::string& session_tag,
+ int tab_node_id) {
+ return TabNodeIdToClientTag(session_tag, tab_node_id);
+}
+
+SessionStore::SessionStore(
+ SyncSessionsClient* sessions_client,
+ const SessionInfo& local_session_info,
+ std::unique_ptr<ModelTypeStore> store,
+ std::map<std::string, sync_pb::SessionSpecifics> initial_data,
+ const syncer::EntityMetadataMap& initial_metadata,
+ const RestoredForeignTabCallback& restored_foreign_tab_callback)
+ : store_(std::move(store)),
+ local_session_info_(local_session_info),
+ session_tracker_(sessions_client),
+ weak_ptr_factory_(this) {
+ DCHECK(store_);
+
+ DVLOG(1) << "Constructed session store with " << initial_data.size()
+ << " restored entities and " << initial_metadata.size()
+ << " metadata entries.";
+
+ session_tracker_.InitLocalSession(local_session_info.session_tag,
+ local_session_info.client_name,
+ local_session_info.device_type);
+
+ // Map of all rewritten local ids. Because ids are reset on each restart,
+ // and id generation happens outside of Sync, all ids from a previous local
+ // session must be rewritten in order to be valid (i.e not collide with
+ // newly assigned IDs). Otherwise, SyncedSessionTracker could mix up IDs.
+ // Key: previous session id. Value: new session id.
+ std::map<SessionID::id_type, SessionID> session_id_map;
+
+ bool found_local_header = false;
+
+ for (auto& storage_key_and_specifics : initial_data) {
+ const std::string& storage_key = storage_key_and_specifics.first;
+ SessionSpecifics& specifics = storage_key_and_specifics.second;
+
+ // The store should not contain invalid data, but as a precaution we filter
+ // out anyway in case the persisted data is corrupted.
+ if (!AreValidSpecifics(specifics)) {
+ continue;
+ }
+
+ // Metadata should be available if data is available. If not, it means
+ // the local store is corrupt, because we delete all data and metadata
+ // at the same time (e.g. sync is disabled).
+ syncer::EntityMetadataMap::const_iterator metadata_it =
+ initial_metadata.find(storage_key);
+ if (metadata_it == initial_metadata.end()) {
+ continue;
+ }
+
+ const base::Time mtime =
+ syncer::ProtoTimeToTime(metadata_it->second.modification_time());
+
+ if (specifics.session_tag() != local_session_info.session_tag) {
+ UpdateTrackerWithSpecifics(specifics, mtime, &session_tracker_);
+
+ // Notify listeners. In practice, this has the goal to load the URLs and
+ // visit times into the in-memory favicon cache.
+ if (specifics.has_tab()) {
+ restored_foreign_tab_callback.Run(specifics.tab(), mtime);
+ }
+ } else if (specifics.has_header()) {
+ // This is previously stored local header information. Restoring the local
+ // is actually needed on Android only where we might not have a complete
+ // view of local window/tabs.
+
+ // Two local headers cannot coexist because they would use the very same
+ // storage key in ModelTypeStore/LevelDB.
+ DCHECK(!found_local_header);
+ found_local_header = true;
+
+ // Go through and generate new tab and window ids as necessary, updating
+ // the specifics in place.
+ for (auto& window : *specifics.mutable_header()->mutable_window()) {
+ session_id_map.emplace(window.window_id(), SessionID::NewUnique());
+ window.set_window_id(session_id_map.at(window.window_id()).id());
+
+ for (int& tab_id : *window.mutable_tab()) {
+ if (session_id_map.count(tab_id) == 0) {
+ session_id_map.emplace(tab_id, SessionID::NewUnique());
+ }
+ tab_id = session_id_map.at(tab_id).id();
+ // Note: the tab id of the SessionTab will be updated when the tab
+ // node itself is processed.
+ }
+ }
+
+ UpdateTrackerWithSpecifics(specifics, mtime, &session_tracker_);
+
+ DVLOG(1) << "Loaded local header and rewrote " << session_id_map.size()
+ << " ids.";
+ } else {
+ DCHECK(specifics.has_tab());
+
+ // This is a valid old tab node, add it to the tracker and associate
+ // it (using the new tab id).
+ DVLOG(1) << "Associating local tab " << specifics.tab().tab_id()
+ << " with node " << specifics.tab_node_id();
+
+ // Now file the tab under the new tab id.
+ SessionID new_tab_id = SessionID::InvalidValue();
+ auto iter = session_id_map.find(specifics.tab().tab_id());
+ if (iter != session_id_map.end()) {
+ new_tab_id = iter->second;
+ } else {
+ new_tab_id = SessionID::NewUnique();
+ session_id_map.emplace(specifics.tab().tab_id(), new_tab_id);
+ }
+ DVLOG(1) << "Remapping tab " << specifics.tab().tab_id() << " to "
+ << new_tab_id;
+
+ specifics.mutable_tab()->set_tab_id(new_tab_id.id());
+ session_tracker_.ReassociateLocalTab(specifics.tab_node_id(), new_tab_id);
+ UpdateTrackerWithSpecifics(specifics, mtime, &session_tracker_);
+ }
+ }
+
+ // Cleanup all foreign sessions, since orphaned tabs may have been added after
+ // the header.
+ for (const SyncedSession* session :
+ session_tracker_.LookupAllForeignSessions(SyncedSessionTracker::RAW)) {
+ session_tracker_.CleanupSession(session->session_tag);
+ }
+}
+
+SessionStore::~SessionStore() {}
+
+std::unique_ptr<syncer::DataBatch> SessionStore::GetSessionDataForKeys(
+ const std::vector<std::string>& storage_keys) const {
+ // Decode |storage_keys| into a map that can be fed to
+ // SerializePartialTrackerToSpecifics().
+ std::map<std::string, std::set<int>> session_tag_to_node_ids;
+ for (const std::string& storage_key : storage_keys) {
+ std::string session_tag;
+ int tab_node_id;
+ bool success = DecodeStorageKey(storage_key, &session_tag, &tab_node_id);
+ DCHECK(success);
+ session_tag_to_node_ids[session_tag].insert(tab_node_id);
+ }
+ // Run the actual serialization into a data batch.
+ auto batch = std::make_unique<syncer::MutableDataBatch>();
+ SerializePartialTrackerToSpecifics(
+ session_tracker_, session_tag_to_node_ids,
+ base::BindRepeating(
+ [](syncer::MutableDataBatch* batch, const std::string& session_name,
+ sync_pb::SessionSpecifics* specifics) {
+ DCHECK(AreValidSpecifics(*specifics));
+ // Local variable used to avoid assuming argument evaluation order.
+ const std::string storage_key = GetStorageKey(*specifics);
+ batch->Put(storage_key, MoveToEntityData(session_name, specifics));
+ },
+ batch.get()));
+ return batch;
+}
+
+std::unique_ptr<syncer::DataBatch> SessionStore::GetAllSessionData() const {
+ auto batch = std::make_unique<syncer::MutableDataBatch>();
+ SerializeTrackerToSpecifics(
+ session_tracker_,
+ base::BindRepeating(
+ [](syncer::MutableDataBatch* batch, const std::string& session_name,
+ sync_pb::SessionSpecifics* specifics) {
+ DCHECK(AreValidSpecifics(*specifics));
+ // Local variable used to avoid assuming argument evaluation order.
+ const std::string storage_key = GetStorageKey(*specifics);
+ batch->Put(storage_key, MoveToEntityData(session_name, specifics));
+ },
+ batch.get()));
+ return batch;
+}
+
+std::unique_ptr<SessionStore::WriteBatch> SessionStore::CreateWriteBatch(
+ syncer::OnceModelErrorHandler error_handler) {
+ // The store is guaranteed to outlive WriteBatch instances (as per API
+ // requirement).
+ return std::make_unique<WriteBatch>(
+ store_->CreateWriteBatch(),
+ base::BindOnce(&ModelTypeStore::CommitWriteBatch,
+ base::Unretained(store_.get())),
+ std::move(error_handler), &session_tracker_);
+}
+
+void SessionStore::DeleteAllDataAndMetadata() {
+ session_tracker_.Clear();
+ return store_->DeleteAllDataAndMetadata(base::DoNothing());
+}
+
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_store.h b/chromium/components/sync_sessions/session_store.h
new file mode 100644
index 00000000000..cbd3f63b9ff
--- /dev/null
+++ b/chromium/components/sync_sessions/session_store.h
@@ -0,0 +1,173 @@
+// 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 COMPONENTS_SYNC_SESSIONS_SESSION_STORE_H_
+#define COMPONENTS_SYNC_SESSIONS_SESSION_STORE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/model/data_batch.h"
+#include "components/sync/model/model_error.h"
+#include "components/sync/model/model_type_store.h"
+#include "components/sync_sessions/synced_session_tracker.h"
+
+namespace syncer {
+class SessionSyncPrefs;
+} // namespace syncer
+
+namespace sync_sessions {
+
+// Class responsible for maintaining an in-memory representation of sync
+// sessions (by owning a SyncedSessionTracker) with the capability to persist
+// state to disk and restore (data and metadata). The API enforces a valid and
+// consistent state of the model, e.g. by making sure there is at most one sync
+// entity per client tag.
+class SessionStore {
+ public:
+ struct SessionInfo {
+ std::string session_tag;
+ std::string client_name;
+ sync_pb::SyncEnums::DeviceType device_type = sync_pb::SyncEnums::TYPE_UNSET;
+ };
+
+ // Creation factory. The instantiation process is quite complex because it
+ // loads state from disk in addition to other asynchronous dependencies like
+ // LocalDeviceInfoProvider.
+ using FactoryCompletionCallback = base::OnceCallback<void(
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<SessionStore> store,
+ std::unique_ptr<syncer::MetadataBatch> metadata_batch)>;
+ using Factory =
+ base::RepeatingCallback<void(FactoryCompletionCallback callback)>;
+ // Mimics signature of FaviconCache::UpdateMappingsFromForeignTab().
+ using RestoredForeignTabCallback =
+ base::RepeatingCallback<void(const sync_pb::SessionTab&, base::Time)>;
+
+ // Creates a factory object that is capable of constructing instances of type
+ // |SessionStore| and handling the involved IO. All pointer arguments must not
+ // be null and must outlive the factory as well as the instantiated stores.
+ static Factory CreateFactory(
+ SyncSessionsClient* sessions_client,
+ syncer::SessionSyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* local_device_info_provider,
+ const syncer::RepeatingModelTypeStoreFactory& store_factory,
+ const RestoredForeignTabCallback& restored_foreign_tab_callback);
+
+ // Verifies whether a proto is malformed (e.g. required fields are missing).
+ static bool AreValidSpecifics(const sync_pb::SessionSpecifics& specifics);
+ // |specifics| must be valid, see AreValidSpecifics().
+ static std::string GetClientTag(const sync_pb::SessionSpecifics& specifics);
+ // |specifics| must be valid, see AreValidSpecifics().
+ static std::string GetStorageKey(const sync_pb::SessionSpecifics& specifics);
+ static std::string GetHeaderStorageKey(const std::string& session_tag);
+ static std::string GetTabStorageKey(const std::string& session_tag,
+ int tab_node_id);
+ // Verifies if |storage_key| corresponds to an entity in the local session,
+ // identified by the session tag.
+ bool StorageKeyMatchesLocalSession(const std::string& storage_key) const;
+
+ // Various equivalents for testing.
+ static std::string GetTabClientTagForTest(const std::string& session_tag,
+ int tab_node_id);
+
+ // Similar to ModelTypeStore::WriteBatch but enforces a consistent state. In
+ // the current implementation, some functions do *NOT* update the tracker, so
+ // callers are responsible for doing so.
+ // TODO(crbug.com/681921): Enforce consistency between in-memory and persisted
+ // data by always updating the tracker.
+ class WriteBatch {
+ public:
+ // Callback that mimics the signature of ModelTypeStore::CommitWriteBatch().
+ using CommitCallback = base::OnceCallback<void(
+ std::unique_ptr<syncer::ModelTypeStore::WriteBatch>,
+ syncer::ModelTypeStore::CallbackWithResult)>;
+
+ // Raw pointers must not be nullptr and must outlive this object.
+ WriteBatch(std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch,
+ CommitCallback commit_cb,
+ syncer::OnceModelErrorHandler error_handler,
+ SyncedSessionTracker* session_tracker);
+ ~WriteBatch();
+
+ // Most mutations below return a storage key.
+ std::string PutAndUpdateTracker(const sync_pb::SessionSpecifics& specifics,
+ base::Time modification_time);
+ void DeleteForeignEntityAndUpdateTracker(const std::string& storage_key);
+ // The functions below do not update SyncedSessionTracker and hence it is
+ // the caller's responsibility to do so *before* calling these functions.
+ std::string PutWithoutUpdatingTracker(
+ const sync_pb::SessionSpecifics& specifics);
+ std::string DeleteLocalTabWithoutUpdatingTracker(int tab_node_id);
+
+ syncer::MetadataChangeList* GetMetadataChangeList();
+
+ static void Commit(std::unique_ptr<WriteBatch> batch);
+
+ private:
+ std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch_;
+ CommitCallback commit_cb_;
+ syncer::OnceModelErrorHandler error_handler_;
+ SyncedSessionTracker* const session_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(WriteBatch);
+ };
+
+ // Construction once all data and metadata has been loaded from disk. Use
+ // the factory above to take care of the IO. |sessions_client| must not be
+ // null and must outlive this object.
+ SessionStore(SyncSessionsClient* sessions_client,
+ const SessionInfo& local_session_info,
+ std::unique_ptr<syncer::ModelTypeStore> store,
+ std::map<std::string, sync_pb::SessionSpecifics> initial_data,
+ const syncer::EntityMetadataMap& initial_metadata,
+ const RestoredForeignTabCallback& restored_foreign_tab_callback);
+ ~SessionStore();
+
+ const SessionInfo& local_session_info() const { return local_session_info_; }
+
+ // Converts the in-memory model (SyncedSessionTracker) of sessions to sync
+ // protos.
+ std::unique_ptr<syncer::DataBatch> GetSessionDataForKeys(
+ const std::vector<std::string>& storage_keys) const;
+
+ // Returns all known session entities, local and foreign, generated from the
+ // in-memory model (SyncedSessionTracker).
+ std::unique_ptr<syncer::DataBatch> GetAllSessionData() const;
+
+ // Write API. WriteBatch instances must not outlive this store and must be
+ // committed prior to destruction. Besides, more than one uncommitted
+ // instance must not exist at any time.
+ std::unique_ptr<WriteBatch> CreateWriteBatch(
+ syncer::OnceModelErrorHandler error_handler);
+ void DeleteAllDataAndMetadata();
+
+ // TODO(crbug.com/681921): Avoid exposing a mutable tracker, because that
+ // bypasses the consistency-enforcing API.
+ SyncedSessionTracker* mutable_tracker() { return &session_tracker_; }
+ const SyncedSessionTracker* tracker() const { return &session_tracker_; }
+
+ private:
+ // In charge of actually persisting changes to disk.
+ std::unique_ptr<syncer::ModelTypeStore> store_;
+
+ const SessionInfo local_session_info_;
+
+ SyncedSessionTracker session_tracker_;
+
+ base::WeakPtrFactory<SessionStore> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionStore);
+};
+
+} // namespace sync_sessions
+
+#endif // COMPONENTS_SYNC_SESSIONS_SESSION_STORE_H_
diff --git a/chromium/components/sync_sessions/session_store_unittest.cc b/chromium/components/sync_sessions/session_store_unittest.cc
new file mode 100644
index 00000000000..fa0f7984ad9
--- /dev/null
+++ b/chromium/components/sync_sessions/session_store_unittest.cc
@@ -0,0 +1,635 @@
+// 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 "components/sync_sessions/session_store.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/mock_callback.h"
+#include "components/sync/base/hash_util.h"
+#include "components/sync/base/sync_prefs.h"
+#include "components/sync/device_info/local_device_info_provider_mock.h"
+#include "components/sync/model/model_type_store_test_util.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+#include "components/sync/test/test_matchers.h"
+#include "components/sync_sessions/mock_sync_sessions_client.h"
+#include "components/sync_sessions/test_matchers.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sync_sessions {
+namespace {
+
+using sync_pb::SessionSpecifics;
+using syncer::DataBatch;
+using syncer::EntityData;
+using syncer::EntityMetadataMap;
+using syncer::HasEncryptionKeyName;
+using syncer::IsEmptyMetadataBatch;
+using syncer::MetadataBatch;
+using syncer::MetadataBatchContains;
+using syncer::ModelTypeStore;
+using syncer::NoModelError;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::IsEmpty;
+using testing::IsNull;
+using testing::Matcher;
+using testing::NiceMock;
+using testing::NotNull;
+using testing::Pair;
+using testing::Return;
+using testing::UnorderedElementsAre;
+using testing::_;
+
+const char kCacheGuid[] = "SomeCacheGuid";
+const char kClientName[] = "Some Client Name";
+
+class MockSessionSyncPrefs : public syncer::SessionSyncPrefs {
+ public:
+ MockSessionSyncPrefs() = default;
+ ~MockSessionSyncPrefs() override = default;
+
+ MOCK_CONST_METHOD0(GetSyncSessionsGUID, std::string());
+ MOCK_METHOD1(SetSyncSessionsGUID, void(const std::string& guid));
+};
+
+// A mock callback that a) can be used as mock to verify call expectations and
+// b) conveniently exposes the last instantiated session store.
+class MockFactoryCompletionCallback {
+ public:
+ MOCK_METHOD3(Run,
+ void(const base::Optional<syncer::ModelError>& error,
+ SessionStore* store,
+ MetadataBatch* metadata_batch));
+
+ SessionStore::FactoryCompletionCallback Get() {
+ return base::BindOnce(
+ [](MockFactoryCompletionCallback* callback,
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<SessionStore> store,
+ std::unique_ptr<MetadataBatch> metadata_batch) {
+ // Store a copy of the pointer for GetResult().
+ callback->store_ = std::move(store);
+ // Call mock method.
+ callback->Run(error, callback->store_.get(), metadata_batch.get());
+ callback->loop_.Quit();
+ },
+ base::Unretained(this));
+ }
+
+ // Waits until the callback gets triggered.
+ void Wait() { loop_.Run(); }
+
+ SessionStore* GetResult() { return store_.get(); }
+
+ std::unique_ptr<SessionStore> StealResult() { return std::move(store_); }
+
+ private:
+ base::RunLoop loop_;
+ std::unique_ptr<SessionStore> store_;
+};
+
+MATCHER_P(EntityDataHasSpecifics, session_specifics_matcher, "") {
+ return session_specifics_matcher.MatchAndExplain(arg.specifics.session(),
+ result_listener);
+}
+
+std::map<std::string, EntityData> BatchToEntityDataMap(
+ std::unique_ptr<DataBatch> batch) {
+ std::map<std::string, EntityData> storage_key_to_data;
+ while (batch && batch->HasNext()) {
+ auto batch_entry = batch->Next();
+ const std::string& storage_key = batch_entry.first;
+ std::unique_ptr<EntityData> entity_data = std::move(batch_entry.second);
+ EXPECT_THAT(entity_data, NotNull());
+ if (entity_data) {
+ storage_key_to_data.emplace(storage_key, std::move(*entity_data));
+ }
+ }
+ return storage_key_to_data;
+}
+
+std::unique_ptr<MetadataBatch> ReadAllPersistedMetadataFrom(
+ ModelTypeStore* store) {
+ std::unique_ptr<MetadataBatch> batch;
+ base::RunLoop loop;
+ store->ReadAllMetadata(base::BindOnce(
+ [](std::unique_ptr<MetadataBatch>* output_batch, base::RunLoop* loop,
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<MetadataBatch> input_batch) {
+ EXPECT_FALSE(error) << error->ToString();
+ EXPECT_THAT(input_batch, NotNull());
+ *output_batch = std::move(input_batch);
+ loop->Quit();
+ },
+ &batch, &loop));
+ loop.Run();
+ return batch;
+}
+
+std::map<std::string, SessionSpecifics> ReadAllPersistedDataFrom(
+ ModelTypeStore* store) {
+ std::unique_ptr<ModelTypeStore::RecordList> records;
+ base::RunLoop loop;
+ store->ReadAllData(base::BindOnce(
+ [](std::unique_ptr<ModelTypeStore::RecordList>* output_records,
+ base::RunLoop* loop, const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<ModelTypeStore::RecordList> input_records) {
+ EXPECT_FALSE(error) << error->ToString();
+ EXPECT_THAT(input_records, NotNull());
+ *output_records = std::move(input_records);
+ loop->Quit();
+ },
+ &records, &loop));
+ loop.Run();
+ std::map<std::string, SessionSpecifics> result;
+ if (records) {
+ for (const ModelTypeStore::Record& record : *records) {
+ SessionSpecifics specifics;
+ EXPECT_TRUE(specifics.ParseFromString(record.value));
+ result.emplace(record.id, specifics);
+ }
+ }
+ return result;
+}
+
+class SessionStoreFactoryTest : public ::testing::Test {
+ protected:
+ SessionStoreFactoryTest()
+ : underlying_store_(
+ syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest(
+ syncer::SESSIONS)),
+ factory_(SessionStore::CreateFactory(
+ &mock_sync_sessions_client_,
+ &mock_sync_prefs_,
+ &mock_device_info_provider_,
+ syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(
+ underlying_store_.get()),
+ mock_restored_foreign_tab_callback_.Get())) {}
+
+ ~SessionStoreFactoryTest() override {}
+
+ void InitializeDeviceInfoProvider() {
+ mock_device_info_provider_.Initialize(std::make_unique<syncer::DeviceInfo>(
+ kCacheGuid, kClientName, "Chromium 10k", "Chrome 10k",
+ sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id"));
+ }
+
+ base::MessageLoop message_loop_;
+ testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
+ testing::NiceMock<MockSessionSyncPrefs> mock_sync_prefs_;
+ syncer::LocalDeviceInfoProviderMock mock_device_info_provider_;
+ testing::NiceMock<
+ base::MockCallback<SessionStore::RestoredForeignTabCallback>>
+ mock_restored_foreign_tab_callback_;
+
+ std::unique_ptr<ModelTypeStore> underlying_store_;
+ SessionStore::Factory factory_;
+};
+
+TEST_F(SessionStoreFactoryTest, ShouldWaitForDeviceInfo) {
+ MockFactoryCompletionCallback completion;
+ EXPECT_CALL(completion, Run(_, _, _)).Times(0);
+ factory_.Run(completion.Get());
+ EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(),
+ MetadataBatchContains(_, IsEmpty())));
+ EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID());
+ EXPECT_CALL(mock_sync_prefs_,
+ SetSyncSessionsGUID(std::string("session_sync") + kCacheGuid));
+ InitializeDeviceInfoProvider();
+ completion.Wait();
+ ASSERT_THAT(completion.GetResult(), NotNull());
+ EXPECT_THAT(completion.GetResult()->local_session_info().client_name,
+ Eq(kClientName));
+ // Second deviceinfo should be ignored.
+ EXPECT_CALL(completion, Run(_, _, _)).Times(0);
+ EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID()).Times(0);
+ EXPECT_CALL(mock_sync_prefs_, SetSyncSessionsGUID(_)).Times(0);
+ InitializeDeviceInfoProvider();
+}
+
+TEST_F(SessionStoreFactoryTest,
+ ShouldCreateStoreIfDeviceInfoInitiallyAvailable) {
+ EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID());
+ EXPECT_CALL(mock_sync_prefs_,
+ SetSyncSessionsGUID(std::string("session_sync") + kCacheGuid));
+ InitializeDeviceInfoProvider();
+
+ MockFactoryCompletionCallback completion;
+ EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(),
+ MetadataBatchContains(_, IsEmpty())));
+ factory_.Run(completion.Get());
+ completion.Wait();
+ ASSERT_THAT(completion.GetResult(), NotNull());
+ EXPECT_THAT(completion.GetResult()->local_session_info().client_name,
+ Eq(kClientName));
+ // Second deviceinfo should be ignored.
+ EXPECT_CALL(completion, Run(_, _, _)).Times(0);
+ EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID()).Times(0);
+ EXPECT_CALL(mock_sync_prefs_, SetSyncSessionsGUID(_)).Times(0);
+ InitializeDeviceInfoProvider();
+}
+
+TEST_F(SessionStoreFactoryTest, ShouldReadSessionsGuidFromPrefs) {
+ const std::string kCachedGuid = "cachedguid1";
+ EXPECT_CALL(mock_sync_prefs_, SetSyncSessionsGUID(_)).Times(0);
+ EXPECT_CALL(mock_sync_prefs_, GetSyncSessionsGUID())
+ .WillOnce(Return(kCachedGuid));
+
+ InitializeDeviceInfoProvider();
+
+ NiceMock<MockFactoryCompletionCallback> completion;
+ factory_.Run(completion.Get());
+ completion.Wait();
+ ASSERT_THAT(completion.GetResult(), NotNull());
+ EXPECT_THAT(completion.GetResult()->local_session_info().session_tag,
+ Eq(kCachedGuid));
+}
+
+// Test fixture that creates an initial session store.
+class SessionStoreTest : public SessionStoreFactoryTest {
+ protected:
+ const std::string kLocalSessionTag = "localsessiontag";
+
+ SessionStoreTest() {
+ ON_CALL(mock_sync_prefs_, GetSyncSessionsGUID())
+ .WillByDefault(Return(kLocalSessionTag));
+
+ session_store_ = CreateSessionStore();
+ }
+
+ std::unique_ptr<SessionStore> CreateSessionStore() {
+ NiceMock<MockFactoryCompletionCallback> completion;
+ InitializeDeviceInfoProvider();
+ factory_.Run(completion.Get());
+ completion.Wait();
+ EXPECT_THAT(completion.GetResult(), NotNull());
+ return completion.StealResult();
+ }
+
+ SessionStore* session_store() { return session_store_.get(); }
+
+ private:
+ std::unique_ptr<SessionStore> session_store_;
+};
+
+TEST_F(SessionStoreTest, ShouldCreateLocalSession) {
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+
+ EXPECT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()),
+ ElementsAre(Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, /*window_ids=*/{},
+ /*tab_ids=*/{})))));
+ // Verify that GetSessionDataForKeys() returns the header entity.
+ EXPECT_THAT(BatchToEntityDataMap(
+ session_store()->GetSessionDataForKeys({header_storage_key})),
+ ElementsAre(Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, /*window_ids=*/{},
+ /*tab_ids=*/{})))));
+
+ // Verify the underlying storage does NOT contain the data.
+ EXPECT_THAT(ReadAllPersistedDataFrom(underlying_store_.get()), IsEmpty());
+
+ // Verify the underlying storage does NOT contain metadata.
+ EXPECT_THAT(ReadAllPersistedMetadataFrom(underlying_store_.get()),
+ IsEmptyMetadataBatch());
+}
+
+TEST_F(SessionStoreTest, ShouldWriteAndRestoreMetadata) {
+ const std::string kStorageKey1 = "TestStorageKey1";
+ const std::string kServerId1 = "TestServerId1";
+ const std::string kEncryptionKeyName1 = "TestEncryptionKey1";
+
+ // Populate with metadata.
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing());
+ ASSERT_THAT(batch, NotNull());
+
+ sync_pb::EntityMetadata metadata1;
+ metadata1.set_server_id(kServerId1);
+ batch->GetMetadataChangeList()->UpdateMetadata(kStorageKey1, metadata1);
+
+ sync_pb::ModelTypeState model_type_state;
+ model_type_state.set_encryption_key_name(kEncryptionKeyName1);
+ batch->GetMetadataChangeList()->UpdateModelTypeState(model_type_state);
+
+ SessionStore::WriteBatch::Commit(std::move(batch));
+
+ // Verify the underlying storage contains the metadata.
+ EXPECT_THAT(ReadAllPersistedMetadataFrom(underlying_store_.get()),
+ MetadataBatchContains(HasEncryptionKeyName(kEncryptionKeyName1),
+ ElementsAre(Pair(kStorageKey1, _))));
+
+ // Create second session store.
+ NiceMock<MockFactoryCompletionCallback> completion;
+ EXPECT_CALL(completion, Run(NoModelError(), /*store=*/NotNull(),
+ MetadataBatchContains(
+ HasEncryptionKeyName(kEncryptionKeyName1),
+ ElementsAre(Pair(kStorageKey1, _)))));
+ factory_.Run(completion.Get());
+ completion.Wait();
+ EXPECT_THAT(completion.GetResult(), NotNull());
+ EXPECT_NE(session_store(), completion.GetResult());
+}
+
+TEST_F(SessionStoreTest, ShouldUpdateTrackerWithForeignData) {
+ const std::string kForeignSessionTag = "SomeForeignTag";
+ const int kWindowId = 5;
+ const int kTabId1 = 7;
+ const int kTabId2 = 8;
+ const int kTabNodeId1 = 2;
+ const int kTabNodeId2 = 3;
+
+ EXPECT_CALL(mock_restored_foreign_tab_callback_, Run(_, _)).Times(0);
+
+ ASSERT_THAT(session_store()->tracker()->LookupAllForeignSessions(
+ SyncedSessionTracker::RAW),
+ IsEmpty());
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+ const std::string tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId1);
+ const std::string tab_storage_key2 =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId2);
+ ASSERT_THAT(BatchToEntityDataMap(session_store()->GetSessionDataForKeys(
+ {header_storage_key, tab_storage_key1, tab_storage_key2})),
+ IsEmpty());
+
+ // Populate with data.
+ SessionSpecifics header;
+ header.set_session_tag(kForeignSessionTag);
+ header.mutable_header()->add_window()->set_window_id(kWindowId);
+ header.mutable_header()->mutable_window(0)->add_tab(kTabId1);
+ header.mutable_header()->mutable_window(0)->add_tab(kTabId2);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(header));
+
+ SessionSpecifics tab1;
+ tab1.set_session_tag(kForeignSessionTag);
+ tab1.set_tab_node_id(kTabNodeId1);
+ tab1.mutable_tab()->set_window_id(kWindowId);
+ tab1.mutable_tab()->set_tab_id(kTabId1);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(tab1));
+
+ SessionSpecifics tab2;
+ tab2.set_session_tag(kForeignSessionTag);
+ tab2.set_tab_node_id(kTabNodeId2);
+ tab2.mutable_tab()->set_window_id(kWindowId);
+ tab2.mutable_tab()->set_tab_id(kTabId2);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(tab2));
+
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing());
+ ASSERT_THAT(batch, NotNull());
+ batch->PutAndUpdateTracker(header, base::Time::Now());
+ batch->PutAndUpdateTracker(tab1, base::Time::Now());
+ batch->PutAndUpdateTracker(tab2, base::Time::Now());
+ SessionStore::WriteBatch::Commit(std::move(batch));
+
+ EXPECT_THAT(session_store()->tracker()->LookupAllForeignSessions(
+ SyncedSessionTracker::RAW),
+ ElementsAre(MatchesSyncedSession(
+ kForeignSessionTag, {{kWindowId, {kTabId1, kTabId2}}})));
+ EXPECT_THAT(
+ BatchToEntityDataMap(session_store()->GetSessionDataForKeys(
+ {header_storage_key, tab_storage_key1, tab_storage_key2})),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kForeignSessionTag, {kWindowId}, {kTabId1, kTabId2}))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(kForeignSessionTag, kWindowId,
+ kTabId1, kTabNodeId1,
+ /*urls=*/_))),
+ Pair(tab_storage_key2,
+ EntityDataHasSpecifics(MatchesTab(kForeignSessionTag, kWindowId,
+ kTabId2, kTabNodeId2,
+ /*urls=*/_)))));
+}
+
+TEST_F(SessionStoreTest, ShouldWriteAndRestoreForeignData) {
+ const std::string kForeignSessionTag = "SomeForeignTag";
+ const int kWindowId = 5;
+ const int kTabId1 = 7;
+ const int kTabNodeId1 = 2;
+
+ EXPECT_CALL(mock_restored_foreign_tab_callback_, Run(_, _)).Times(0);
+
+ const std::string local_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+
+ ASSERT_THAT(session_store()->tracker()->LookupAllForeignSessions(
+ SyncedSessionTracker::RAW),
+ IsEmpty());
+ // Local session is automatically created.
+ ASSERT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()),
+ ElementsAre(Pair(local_header_storage_key, _)));
+ ASSERT_THAT(ReadAllPersistedDataFrom(underlying_store_.get()), IsEmpty());
+
+ // Populate with data.
+ SessionSpecifics header;
+ header.set_session_tag(kForeignSessionTag);
+ header.mutable_header()->add_window()->set_window_id(kWindowId);
+ header.mutable_header()->mutable_window(0)->add_tab(kTabId1);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(header));
+
+ SessionSpecifics tab1;
+ tab1.set_session_tag(kForeignSessionTag);
+ tab1.set_tab_node_id(kTabNodeId1);
+ tab1.mutable_tab()->set_window_id(kWindowId);
+ tab1.mutable_tab()->set_tab_id(kTabId1);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(tab1));
+
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing());
+ ASSERT_THAT(batch, NotNull());
+ batch->PutAndUpdateTracker(header, base::Time::Now());
+ batch->PutAndUpdateTracker(tab1, base::Time::Now());
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+ const std::string tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId1);
+
+ sync_pb::EntityMetadata header_metadata;
+ header_metadata.set_server_id("someserverid1");
+ batch->GetMetadataChangeList()->UpdateMetadata(header_storage_key,
+ header_metadata);
+
+ sync_pb::EntityMetadata tab1_metadata;
+ tab1_metadata.set_server_id("someserverid2");
+ batch->GetMetadataChangeList()->UpdateMetadata(tab_storage_key1,
+ tab1_metadata);
+
+ SessionStore::WriteBatch::Commit(std::move(batch));
+
+ // Verify the underlying storage contains the data.
+ ASSERT_THAT(
+ ReadAllPersistedDataFrom(underlying_store_.get()),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ MatchesHeader(kForeignSessionTag, {kWindowId}, {kTabId1})),
+ Pair(tab_storage_key1,
+ MatchesTab(kForeignSessionTag, kWindowId, kTabId1, kTabNodeId1,
+ /*urls=*/_))));
+
+ // Verify tracker exposes the foreign tabs.
+ ASSERT_THAT(
+ session_store()->tracker()->LookupAllForeignSessions(
+ SyncedSessionTracker::RAW),
+ ElementsAre(MatchesSyncedSession(
+ kForeignSessionTag, {{kWindowId, std::vector<int>{kTabId1}}})));
+
+ // Creation of a second session store should trigger a callback for the
+ // restored tab.
+ EXPECT_CALL(mock_restored_foreign_tab_callback_,
+ Run(testing::Property(&sync_pb::SessionTab::tab_id, kTabId1), _));
+
+ // Create second session store to verify that the persisted state is restored,
+ // by mimicing a Chrome restart and using |underlying_store_| (in-memory) as a
+ // replacement for on-disk persistence.
+ std::unique_ptr<SessionStore> restored_store = CreateSessionStore();
+ ASSERT_THAT(restored_store, NotNull());
+ ASSERT_NE(session_store(), restored_store.get());
+
+ // Verify tracker was restored.
+ EXPECT_THAT(
+ restored_store->tracker()->LookupAllForeignSessions(
+ SyncedSessionTracker::RAW),
+ ElementsAre(MatchesSyncedSession(
+ kForeignSessionTag, {{kWindowId, std::vector<int>{kTabId1}}})));
+
+ EXPECT_THAT(BatchToEntityDataMap(restored_store->GetAllSessionData()),
+ UnorderedElementsAre(
+ Pair(local_header_storage_key, _),
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kForeignSessionTag, {kWindowId}, {kTabId1}))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kForeignSessionTag, kWindowId, kTabId1, kTabNodeId1,
+ /*urls=*/_)))));
+
+ EXPECT_THAT(BatchToEntityDataMap(session_store()->GetSessionDataForKeys(
+ {header_storage_key, tab_storage_key1})),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kForeignSessionTag, {kWindowId}, {kTabId1}))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kForeignSessionTag, kWindowId, kTabId1, kTabNodeId1,
+ /*urls=*/_)))));
+}
+
+TEST_F(SessionStoreTest, ShouldReturnForeignUnmappedTabs) {
+ const std::string kForeignSessionTag = "SomeForeignTag";
+ const int kWindowId = 5;
+ const int kTabId1 = 7;
+ const int kTabNodeId1 = 2;
+
+ const std::string local_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string foreign_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+ const std::string foreign_tab_storage_key =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId1);
+
+ // Local header entity is present initially.
+ ASSERT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()),
+ ElementsAre(Pair(local_header_storage_key, _)));
+
+ SessionSpecifics tab1;
+ tab1.set_session_tag(kForeignSessionTag);
+ tab1.set_tab_node_id(kTabNodeId1);
+ tab1.mutable_tab()->set_window_id(kWindowId);
+ tab1.mutable_tab()->set_tab_id(kTabId1);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(tab1));
+
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing());
+ ASSERT_THAT(batch, NotNull());
+ batch->PutAndUpdateTracker(tab1, base::Time::Now());
+ SessionStore::WriteBatch::Commit(std::move(batch));
+
+ EXPECT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()),
+ UnorderedElementsAre(
+ Pair(local_header_storage_key, _),
+ Pair(foreign_header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kForeignSessionTag,
+ /*window_ids=*/{},
+ /*tab_ids=*/{}))),
+ Pair(foreign_tab_storage_key,
+ EntityDataHasSpecifics(MatchesTab(
+ kForeignSessionTag, kWindowId, kTabId1, kTabNodeId1,
+ /*urls=*/_)))));
+}
+
+TEST_F(SessionStoreTest, ShouldIgnoreForeignOrphanTabs) {
+ const std::string kForeignSessionTag = "SomeForeignTag";
+ const int kWindowId = 5;
+ const int kTabId = 7;
+ // Both tab nodes point to the same tab ID, so the second one should prevail.
+ const int kTabNodeId1 = 2;
+ const int kTabNodeId2 = 3;
+
+ const std::string local_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string foreign_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+ const std::string foreign_tab_storage_key2 =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kTabNodeId2);
+
+ // Local header entity is present initially.
+ ASSERT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()),
+ ElementsAre(Pair(local_header_storage_key, _)));
+
+ SessionSpecifics tab1;
+ tab1.set_session_tag(kForeignSessionTag);
+ tab1.set_tab_node_id(kTabNodeId1);
+ tab1.mutable_tab()->set_window_id(kWindowId);
+ tab1.mutable_tab()->set_tab_id(kTabId);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(tab1));
+
+ SessionSpecifics tab2;
+ tab2.set_session_tag(kForeignSessionTag);
+ tab2.set_tab_node_id(kTabNodeId2);
+ tab2.mutable_tab()->set_window_id(kWindowId);
+ tab2.mutable_tab()->set_tab_id(kTabId);
+ ASSERT_TRUE(SessionStore::AreValidSpecifics(tab2));
+
+ // Store the two foreign tabs, in order.
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ session_store()->CreateWriteBatch(/*error_handler=*/base::DoNothing());
+ ASSERT_THAT(batch, NotNull());
+ batch->PutAndUpdateTracker(tab1, base::Time::Now());
+ batch->PutAndUpdateTracker(tab2, base::Time::Now());
+ SessionStore::WriteBatch::Commit(std::move(batch));
+
+ // The first foreign tab should have been overwritten by the second one,
+ // because they shared a tab ID.
+ EXPECT_THAT(BatchToEntityDataMap(session_store()->GetAllSessionData()),
+ UnorderedElementsAre(
+ Pair(local_header_storage_key, _),
+ Pair(foreign_header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kForeignSessionTag,
+ /*window_ids=*/{},
+ /*tab_ids=*/{}))),
+ Pair(foreign_tab_storage_key2,
+ EntityDataHasSpecifics(MatchesTab(
+ kForeignSessionTag, kWindowId, kTabId, kTabNodeId2,
+ /*urls=*/_)))));
+}
+
+} // namespace
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_sync_bridge.cc b/chromium/components/sync_sessions/session_sync_bridge.cc
new file mode 100644
index 00000000000..62ebe3c1458
--- /dev/null
+++ b/chromium/components/sync_sessions/session_sync_bridge.cc
@@ -0,0 +1,517 @@
+// 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 "components/sync_sessions/session_sync_bridge.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/location.h"
+#include "base/time/time.h"
+#include "components/sync/base/hash_util.h"
+#include "components/sync/base/time.h"
+#include "components/sync/model/entity_change.h"
+#include "components/sync/model/metadata_batch.h"
+#include "components/sync/model/mutable_data_batch.h"
+#include "components/sync/model_impl/in_memory_metadata_change_list.h"
+#include "components/sync/protocol/model_type_state.pb.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync_sessions/sync_sessions_client.h"
+#include "components/sync_sessions/synced_window_delegate.h"
+#include "components/sync_sessions/synced_window_delegates_getter.h"
+
+namespace sync_sessions {
+namespace {
+
+using sync_pb::SessionSpecifics;
+using syncer::MetadataChangeList;
+using syncer::ModelTypeStore;
+using syncer::ModelTypeSyncBridge;
+
+// Maximum number of favicons to sync.
+const int kMaxSyncFavicons = 200;
+
+// Default time without activity after which a session is considered stale and
+// becomes a candidate for garbage collection.
+const base::TimeDelta kStaleSessionThreshold = base::TimeDelta::FromDays(14);
+
+std::unique_ptr<syncer::EntityData> MoveToEntityData(
+ const std::string& client_name,
+ SessionSpecifics* specifics) {
+ auto entity_data = std::make_unique<syncer::EntityData>();
+ entity_data->non_unique_name = client_name;
+ entity_data->specifics.mutable_session()->Swap(specifics);
+ return entity_data;
+}
+
+class LocalSessionWriteBatch : public LocalSessionEventHandlerImpl::WriteBatch {
+ public:
+ LocalSessionWriteBatch(const SessionStore::SessionInfo& session_info,
+ std::unique_ptr<SessionStore::WriteBatch> batch,
+ syncer::ModelTypeChangeProcessor* processor)
+ : session_info_(session_info),
+ batch_(std::move(batch)),
+ processor_(processor) {
+ DCHECK(batch_);
+ DCHECK(processor_);
+ DCHECK(processor_->IsTrackingMetadata());
+ }
+
+ ~LocalSessionWriteBatch() override {}
+
+ // WriteBatch implementation.
+ void Delete(int tab_node_id) override {
+ const std::string storage_key =
+ batch_->DeleteLocalTabWithoutUpdatingTracker(tab_node_id);
+ processor_->Delete(storage_key, batch_->GetMetadataChangeList());
+ }
+
+ void Put(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
+ DCHECK(SessionStore::AreValidSpecifics(*specifics));
+ const std::string storage_key =
+ batch_->PutWithoutUpdatingTracker(*specifics);
+
+ processor_->Put(
+ storage_key,
+ MoveToEntityData(session_info_.client_name, specifics.get()),
+ batch_->GetMetadataChangeList());
+ }
+
+ void Commit() override {
+ DCHECK(batch_) << "Cannot commit twice";
+ SessionStore::WriteBatch::Commit(std::move(batch_));
+ }
+
+ private:
+ const SessionStore::SessionInfo session_info_;
+ std::unique_ptr<SessionStore::WriteBatch> batch_;
+ syncer::ModelTypeChangeProcessor* const processor_;
+};
+
+bool IsSessionRestoreInProgress(SyncSessionsClient* sessions_client) {
+ DCHECK(sessions_client);
+ SyncedWindowDelegatesGetter* synced_window_getter =
+ sessions_client->GetSyncedWindowDelegatesGetter();
+ SyncedWindowDelegatesGetter::SyncedWindowDelegateMap windows =
+ synced_window_getter->GetSyncedWindowDelegates();
+ for (const auto& window_iter_pair : windows) {
+ if (window_iter_pair.second->IsSessionRestoreInProgress()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace
+
+SessionSyncBridge::SessionSyncBridge(
+ SyncSessionsClient* sessions_client,
+ syncer::SessionSyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* local_device_info_provider,
+ const syncer::RepeatingModelTypeStoreFactory& store_factory,
+ const base::RepeatingClosure& foreign_sessions_updated_callback,
+ std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor)
+ : ModelTypeSyncBridge(std::move(change_processor)),
+ sessions_client_(sessions_client),
+ local_session_event_router_(
+ sessions_client->GetLocalSessionEventRouter()),
+ foreign_sessions_updated_callback_(foreign_sessions_updated_callback),
+ favicon_cache_(sessions_client->GetFaviconService(),
+ sessions_client->GetHistoryService(),
+ kMaxSyncFavicons),
+ session_store_factory_(SessionStore::CreateFactory(
+ sessions_client,
+ sync_prefs,
+ local_device_info_provider,
+ store_factory,
+ base::BindRepeating(&FaviconCache::UpdateMappingsFromForeignTab,
+ base::Unretained(&favicon_cache_)))),
+ is_session_restore_in_progress_(
+ IsSessionRestoreInProgress(sessions_client)) {
+ DCHECK(sessions_client_);
+ DCHECK(local_session_event_router_);
+ DCHECK(foreign_sessions_updated_callback_);
+}
+
+SessionSyncBridge::~SessionSyncBridge() {
+ if (syncing_) {
+ local_session_event_router_->Stop();
+ }
+}
+
+void SessionSyncBridge::ScheduleGarbageCollection() {
+ if (!syncing_) {
+ return;
+ }
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&SessionSyncBridge::DoGarbageCollection,
+ base::AsWeakPtr(this)));
+}
+
+FaviconCache* SessionSyncBridge::GetFaviconCache() {
+ return &favicon_cache_;
+}
+
+SessionsGlobalIdMapper* SessionSyncBridge::GetGlobalIdMapper() {
+ return &global_id_mapper_;
+}
+
+OpenTabsUIDelegate* SessionSyncBridge::GetOpenTabsUIDelegate() {
+ if (!syncing_) {
+ return nullptr;
+ }
+ return syncing_->open_tabs_ui_delegate.get();
+}
+
+void SessionSyncBridge::OnSessionRestoreComplete() {
+ is_session_restore_in_progress_ = false;
+
+ if (syncing_) {
+ StartLocalSessionEventHandler();
+ }
+}
+
+syncer::SyncableService* SessionSyncBridge::GetSyncableService() {
+ return nullptr;
+}
+
+syncer::ModelTypeSyncBridge* SessionSyncBridge::GetModelTypeSyncBridge() {
+ return this;
+}
+
+std::unique_ptr<MetadataChangeList>
+SessionSyncBridge::CreateMetadataChangeList() {
+ return std::make_unique<syncer::InMemoryMetadataChangeList>();
+}
+
+base::Optional<syncer::ModelError> SessionSyncBridge::MergeSyncData(
+ std::unique_ptr<MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_data) {
+ DCHECK(syncing_);
+ DCHECK(change_processor()->IsTrackingMetadata());
+
+ if (!is_session_restore_in_progress_) {
+ StartLocalSessionEventHandler();
+ }
+
+ return ApplySyncChanges(std::move(metadata_change_list),
+ std::move(entity_data));
+}
+
+void SessionSyncBridge::StartLocalSessionEventHandler() {
+ // We should be ready to propagate local state to sync.
+ DCHECK(syncing_);
+ DCHECK(!syncing_->local_session_event_handler);
+ DCHECK(change_processor()->IsTrackingMetadata());
+ DCHECK(!is_session_restore_in_progress_);
+
+ // TODO(crbug.com/681921): Remove injecting |local_session_write_batch| and
+ // let the impl create one via the delegate once the directory-based
+ // implementation is removed.
+ std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
+ local_session_write_batch = CreateLocalSessionWriteBatch();
+ syncing_->local_session_event_handler =
+ std::make_unique<LocalSessionEventHandlerImpl>(
+ /*delegate=*/this, sessions_client_,
+ syncing_->store->mutable_tracker(), local_session_write_batch.get());
+
+ local_session_write_batch->Commit();
+
+ // Start processing local changes, which will be propagated to the store as
+ // well as the processor.
+ local_session_event_router_->StartRoutingTo(
+ syncing_->local_session_event_handler.get());
+}
+
+base::Optional<syncer::ModelError> SessionSyncBridge::ApplySyncChanges(
+ std::unique_ptr<MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_changes) {
+ DCHECK(change_processor()->IsTrackingMetadata());
+ DCHECK(syncing_);
+
+ // Merging sessions is simple: remote entities are expected to be foreign
+ // sessions (identified by the session tag) and hence must simply be
+ // stored (server wins, including undeletion). For local sessions, remote
+ // information is ignored (local wins).
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ CreateSessionStoreWriteBatch();
+ for (const syncer::EntityChange& change : entity_changes) {
+ switch (change.type()) {
+ case syncer::EntityChange::ACTION_DELETE:
+ // Deletions are all or nothing (since we only ever delete entire
+ // sessions). Therefore we don't care if it's a tab node or meta node,
+ // and just ensure we've disassociated.
+ if (syncing_->store->StorageKeyMatchesLocalSession(
+ change.storage_key())) {
+ // Another client has attempted to delete our local data (possibly by
+ // error or a clock is inaccurate). Just ignore the deletion for now.
+ DLOG(WARNING) << "Local session data deleted. Ignoring until next "
+ << "local navigation event.";
+ syncing_->local_data_out_of_sync = true;
+ } else {
+ batch->DeleteForeignEntityAndUpdateTracker(change.storage_key());
+ }
+ break;
+ case syncer::EntityChange::ACTION_ADD:
+ case syncer::EntityChange::ACTION_UPDATE: {
+ const SessionSpecifics& specifics = change.data().specifics.session();
+
+ if (syncing_->store->StorageKeyMatchesLocalSession(
+ change.storage_key())) {
+ // We should only ever receive a change to our own machine's session
+ // info if encryption was turned on. In that case, the data is still
+ // the same, so we can ignore.
+ DLOG(WARNING) << "Dropping modification to local session.";
+ syncing_->local_data_out_of_sync = true;
+ continue;
+ }
+
+ if (!SessionStore::AreValidSpecifics(specifics) ||
+ change.data().client_tag_hash !=
+ GenerateSyncableHash(syncer::SESSIONS,
+ SessionStore::GetClientTag(specifics))) {
+ continue;
+ }
+
+ batch->PutAndUpdateTracker(specifics, change.data().modification_time);
+ // If a favicon or favicon urls are present, load the URLs and visit
+ // times into the in-memory favicon cache.
+ if (specifics.has_tab()) {
+ favicon_cache_.UpdateMappingsFromForeignTab(
+ specifics.tab(), change.data().modification_time);
+ }
+ break;
+ }
+ }
+ }
+
+ static_cast<syncer::InMemoryMetadataChangeList*>(metadata_change_list.get())
+ ->TransferChangesTo(batch->GetMetadataChangeList());
+ SessionStore::WriteBatch::Commit(std::move(batch));
+
+ // This might overtrigger because we don't check if the batch is empty, but
+ // observers should handle these events well so we don't bother detecting.
+ foreign_sessions_updated_callback_.Run();
+ return base::nullopt;
+}
+
+void SessionSyncBridge::GetData(StorageKeyList storage_keys,
+ DataCallback callback) {
+ DCHECK(syncing_);
+ std::move(callback).Run(syncing_->store->GetSessionDataForKeys(storage_keys));
+}
+
+void SessionSyncBridge::GetAllData(DataCallback callback) {
+ DCHECK(syncing_);
+ std::move(callback).Run(syncing_->store->GetAllSessionData());
+}
+
+std::string SessionSyncBridge::GetClientTag(
+ const syncer::EntityData& entity_data) {
+ return SessionStore::GetClientTag(entity_data.specifics.session());
+}
+
+std::string SessionSyncBridge::GetStorageKey(
+ const syncer::EntityData& entity_data) {
+ if (!SessionStore::AreValidSpecifics(entity_data.specifics.session())) {
+ return std::string();
+ }
+ return SessionStore::GetStorageKey(entity_data.specifics.session());
+}
+
+ModelTypeSyncBridge::DisableSyncResponse
+SessionSyncBridge::ApplyDisableSyncChanges(
+ std::unique_ptr<MetadataChangeList> delete_metadata_change_list) {
+ local_session_event_router_->Stop();
+ if (syncing_) {
+ syncing_->store->DeleteAllDataAndMetadata();
+ }
+ syncing_.reset();
+ return DisableSyncResponse::kModelNoLongerReadyToSync;
+}
+
+std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
+SessionSyncBridge::CreateLocalSessionWriteBatch() {
+ DCHECK(syncing_);
+
+ // If a remote client mangled with our local session (typically deleted
+ // entities due to garbage collection), we resubmit all local entities at this
+ // point (i.e. local changes observed).
+ if (syncing_->local_data_out_of_sync) {
+ syncing_->local_data_out_of_sync = false;
+ // We use PostTask() to avoid interferring with the ongoing handling of
+ // local changes that triggered this function.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&SessionSyncBridge::ResubmitLocalSession,
+ base::AsWeakPtr(this)));
+ }
+
+ return std::make_unique<LocalSessionWriteBatch>(
+ syncing_->store->local_session_info(), CreateSessionStoreWriteBatch(),
+ change_processor());
+}
+
+void SessionSyncBridge::TrackLocalNavigationId(base::Time timestamp,
+ int unique_id) {
+ global_id_mapper_.TrackNavigationId(timestamp, unique_id);
+}
+
+void SessionSyncBridge::OnPageFaviconUpdated(const GURL& page_url) {
+ favicon_cache_.OnPageFaviconUpdated(page_url, base::Time::Now());
+}
+
+void SessionSyncBridge::OnFaviconVisited(const GURL& page_url,
+ const GURL& favicon_url) {
+ favicon_cache_.OnFaviconVisited(page_url, favicon_url);
+}
+
+void SessionSyncBridge::OnSyncStarting() {
+ DCHECK(!syncing_);
+
+ session_store_factory_.Run(base::BindOnce(
+ &SessionSyncBridge::OnStoreInitialized, base::AsWeakPtr(this)));
+}
+
+void SessionSyncBridge::OnStoreInitialized(
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<SessionStore> store,
+ std::unique_ptr<syncer::MetadataBatch> metadata_batch) {
+ DCHECK(!syncing_);
+
+ if (error) {
+ change_processor()->ReportError(*error);
+ return;
+ }
+
+ DCHECK(store);
+ DCHECK(metadata_batch);
+
+ syncing_.emplace();
+ syncing_->store = std::move(store);
+ syncing_->open_tabs_ui_delegate = std::make_unique<OpenTabsUIDelegateImpl>(
+ sessions_client_, syncing_->store->tracker(), &favicon_cache_,
+ base::BindRepeating(&SessionSyncBridge::DeleteForeignSessionFromUI,
+ base::Unretained(this)));
+
+ change_processor()->ModelReadyToSync(std::move(metadata_batch));
+
+ // If initial sync was already done, MergeSyncData() will never be called so
+ // we need to start syncing local changes.
+ if (change_processor()->IsTrackingMetadata() &&
+ !is_session_restore_in_progress_) {
+ StartLocalSessionEventHandler();
+ }
+}
+
+void SessionSyncBridge::DeleteForeignSessionFromUI(const std::string& tag) {
+ if (!syncing_) {
+ return;
+ }
+
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ CreateSessionStoreWriteBatch();
+ DeleteForeignSessionWithBatch(tag, batch.get());
+ SessionStore::WriteBatch::Commit(std::move(batch));
+}
+
+void SessionSyncBridge::DoGarbageCollection() {
+ if (!syncing_) {
+ return;
+ }
+
+ std::unique_ptr<SessionStore::WriteBatch> batch =
+ CreateSessionStoreWriteBatch();
+
+ // Iterate through all the sessions and delete any with age older than
+ // |kStaleSessionThreshold|.
+ for (const auto* session :
+ syncing_->store->tracker()->LookupAllForeignSessions(
+ SyncedSessionTracker::RAW)) {
+ const base::TimeDelta session_age =
+ base::Time::Now() - session->modified_time;
+ if (session_age > kStaleSessionThreshold) {
+ const std::string session_tag = session->session_tag;
+ DVLOG(1) << "Found stale session " << session_tag << " with age "
+ << session_age.InDays() << " days, deleting.";
+ DeleteForeignSessionWithBatch(session_tag, batch.get());
+ }
+ }
+
+ SessionStore::WriteBatch::Commit(std::move(batch));
+}
+
+void SessionSyncBridge::DeleteForeignSessionWithBatch(
+ const std::string& session_tag,
+ SessionStore::WriteBatch* batch) {
+ DCHECK(syncing_);
+ DCHECK(change_processor()->IsTrackingMetadata());
+
+ if (session_tag == syncing_->store->local_session_info().session_tag) {
+ DLOG(ERROR) << "Attempting to delete local session. This is not currently "
+ << "supported.";
+ return;
+ }
+
+ // Delete tabs.
+ for (int tab_node_id :
+ syncing_->store->tracker()->LookupTabNodeIds(session_tag)) {
+ const std::string tab_storage_key =
+ SessionStore::GetTabStorageKey(session_tag, tab_node_id);
+ batch->DeleteForeignEntityAndUpdateTracker(tab_storage_key);
+ change_processor()->Delete(tab_storage_key, batch->GetMetadataChangeList());
+ }
+
+ // Delete header.
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(session_tag);
+ batch->DeleteForeignEntityAndUpdateTracker(header_storage_key);
+ change_processor()->Delete(header_storage_key,
+ batch->GetMetadataChangeList());
+
+ foreign_sessions_updated_callback_.Run();
+}
+
+std::unique_ptr<SessionStore::WriteBatch>
+SessionSyncBridge::CreateSessionStoreWriteBatch() {
+ DCHECK(syncing_);
+
+ return syncing_->store->CreateWriteBatch(
+ base::BindOnce(&SessionSyncBridge::ReportError, base::AsWeakPtr(this)));
+}
+
+void SessionSyncBridge::ResubmitLocalSession() {
+ if (!syncing_) {
+ return;
+ }
+
+ std::unique_ptr<SessionStore::WriteBatch> write_batch =
+ CreateSessionStoreWriteBatch();
+ std::unique_ptr<syncer::DataBatch> read_batch =
+ syncing_->store->GetAllSessionData();
+ while (read_batch->HasNext()) {
+ syncer::KeyAndData key_and_data = read_batch->Next();
+ if (syncing_->store->StorageKeyMatchesLocalSession(key_and_data.first)) {
+ change_processor()->Put(key_and_data.first,
+ std::move(key_and_data.second),
+ write_batch->GetMetadataChangeList());
+ }
+ }
+
+ SessionStore::WriteBatch::Commit(std::move(write_batch));
+}
+
+void SessionSyncBridge::ReportError(const syncer::ModelError& error) {
+ change_processor()->ReportError(error);
+}
+
+SessionSyncBridge::SyncingState::SyncingState() {}
+
+SessionSyncBridge::SyncingState::~SyncingState() {}
+
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/session_sync_bridge.h b/chromium/components/sync_sessions/session_sync_bridge.h
new file mode 100644
index 00000000000..c18a2dcd6b7
--- /dev/null
+++ b/chromium/components/sync_sessions/session_sync_bridge.h
@@ -0,0 +1,137 @@
+// 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 COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_BRIDGE_H_
+#define COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_BRIDGE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "components/sync/device_info/local_device_info_provider.h"
+#include "components/sync/model/model_error.h"
+#include "components/sync/model/model_type_store.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+#include "components/sync_sessions/abstract_sessions_sync_manager.h"
+#include "components/sync_sessions/favicon_cache.h"
+#include "components/sync_sessions/local_session_event_handler_impl.h"
+#include "components/sync_sessions/open_tabs_ui_delegate_impl.h"
+#include "components/sync_sessions/session_store.h"
+#include "components/sync_sessions/sessions_global_id_mapper.h"
+
+namespace sync_sessions {
+
+class LocalSessionEventRouter;
+class SyncSessionsClient;
+
+// Sync bridge implementation for SESSIONS model type. Takes care of propagating
+// local sessions to other clients as well as providing a representation of
+// foreign sessions.
+//
+// This is achieved by implementing the interface ModelTypeSyncBridge, which
+// ClientTagBasedModelTypeProcessor will use to interact, ultimately, with the
+// sync server. See
+// https://chromium.googlesource.com/chromium/src/+/lkcr/docs/sync/model_api.md#Implementing-ModelTypeSyncBridge
+// for details.
+class SessionSyncBridge : public AbstractSessionsSyncManager,
+ public syncer::ModelTypeSyncBridge,
+ public LocalSessionEventHandlerImpl::Delegate {
+ public:
+ // Raw pointers must not be null and their pointees must outlive this object.
+ SessionSyncBridge(
+ SyncSessionsClient* sessions_client,
+ syncer::SessionSyncPrefs* sync_prefs,
+ syncer::LocalDeviceInfoProvider* local_device_info_provider,
+ const syncer::RepeatingModelTypeStoreFactory& store_factory,
+ const base::RepeatingClosure& foreign_sessions_updated_callback,
+ std::unique_ptr<syncer::ModelTypeChangeProcessor> change_processor);
+ ~SessionSyncBridge() override;
+
+ // AbstractSessionsSyncManager implementation.
+ void ScheduleGarbageCollection() override;
+ FaviconCache* GetFaviconCache() override;
+ SessionsGlobalIdMapper* GetGlobalIdMapper() override;
+ OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
+ void OnSessionRestoreComplete() override;
+ syncer::SyncableService* GetSyncableService() override;
+ syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override;
+
+ // ModelTypeSyncBridge implementation.
+ void OnSyncStarting() override;
+ std::unique_ptr<syncer::MetadataChangeList> CreateMetadataChangeList()
+ override;
+ base::Optional<syncer::ModelError> MergeSyncData(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_data) override;
+ base::Optional<syncer::ModelError> ApplySyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> metadata_change_list,
+ syncer::EntityChangeList entity_changes) override;
+ void GetData(StorageKeyList storage_keys, DataCallback callback) override;
+ void GetAllData(DataCallback callback) override;
+ std::string GetClientTag(const syncer::EntityData& entity_data) override;
+ std::string GetStorageKey(const syncer::EntityData& entity_data) override;
+ DisableSyncResponse ApplyDisableSyncChanges(
+ std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list)
+ override;
+
+ // LocalSessionEventHandlerImpl::Delegate implementation.
+ std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
+ CreateLocalSessionWriteBatch() override;
+ void TrackLocalNavigationId(base::Time timestamp, int unique_id) override;
+ void OnPageFaviconUpdated(const GURL& page_url) override;
+ void OnFaviconVisited(const GURL& page_url, const GURL& favicon_url) override;
+
+ private:
+ void OnStoreInitialized(
+ const base::Optional<syncer::ModelError>& error,
+ std::unique_ptr<SessionStore> store,
+ std::unique_ptr<syncer::MetadataBatch> metadata_batch);
+ void StartLocalSessionEventHandler();
+ void DeleteForeignSessionFromUI(const std::string& tag);
+ void DoGarbageCollection();
+ std::unique_ptr<SessionStore::WriteBatch> CreateSessionStoreWriteBatch();
+ void DeleteForeignSessionWithBatch(const std::string& session_tag,
+ SessionStore::WriteBatch* batch);
+ void ResubmitLocalSession();
+ void ReportError(const syncer::ModelError& error);
+
+ SyncSessionsClient* const sessions_client_;
+ LocalSessionEventRouter* const local_session_event_router_;
+ const base::RepeatingClosure foreign_sessions_updated_callback_;
+
+ FaviconCache favicon_cache_;
+ SessionsGlobalIdMapper global_id_mapper_;
+ SessionStore::Factory session_store_factory_;
+ bool is_session_restore_in_progress_;
+
+ // All data dependent on sync being starting or started.
+ struct SyncingState {
+ SyncingState();
+ ~SyncingState();
+
+ std::unique_ptr<SessionStore> store;
+ std::unique_ptr<OpenTabsUIDelegateImpl> open_tabs_ui_delegate;
+ std::unique_ptr<LocalSessionEventHandlerImpl> local_session_event_handler;
+
+ // Tracks whether our local representation of which sync nodes map to what
+ // tabs (belonging to the current local session) is inconsistent. This can
+ // happen if a foreign client deems our session as "stale" and decides to
+ // delete it. Rather than respond by bullishly re-creating our nodes
+ // immediately, which could lead to ping-pong sequences, we give the benefit
+ // of the doubt and hold off until another local navigation occurs, which
+ // proves that we are still relevant.
+ bool local_data_out_of_sync = false;
+ };
+
+ base::Optional<SyncingState> syncing_;
+
+ DISALLOW_COPY_AND_ASSIGN(SessionSyncBridge);
+};
+
+} // namespace sync_sessions
+
+#endif // COMPONENTS_SYNC_SESSIONS_SESSION_SYNC_BRIDGE_H_
diff --git a/chromium/components/sync_sessions/session_sync_bridge_unittest.cc b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
new file mode 100644
index 00000000000..25902c79227
--- /dev/null
+++ b/chromium/components/sync_sessions/session_sync_bridge_unittest.cc
@@ -0,0 +1,1429 @@
+// 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 "components/sync_sessions/session_sync_bridge.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "base/bind_helpers.h"
+#include "base/json/json_writer.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/mock_callback.h"
+#include "components/sync/base/hash_util.h"
+#include "components/sync/base/sync_prefs.h"
+#include "components/sync/device_info/local_device_info_provider_mock.h"
+#include "components/sync/model/data_batch.h"
+#include "components/sync/model/metadata_batch.h"
+#include "components/sync/model/metadata_change_list.h"
+#include "components/sync/model/mock_model_type_change_processor.h"
+#include "components/sync/model/model_type_store_test_util.h"
+#include "components/sync/model/model_type_sync_bridge.h"
+#include "components/sync/model/sync_metadata_store.h"
+#include "components/sync/model_impl/client_tag_based_model_type_processor.h"
+#include "components/sync/protocol/proto_value_conversions.h"
+#include "components/sync/protocol/sync.pb.h"
+#include "components/sync/test/test_matchers.h"
+#include "components/sync_sessions/favicon_cache.h"
+#include "components/sync_sessions/mock_sync_sessions_client.h"
+#include "components/sync_sessions/tab_node_pool.h"
+#include "components/sync_sessions/test_matchers.h"
+#include "components/sync_sessions/test_synced_window_delegates_getter.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace sync_sessions {
+namespace {
+
+using sync_pb::EntityMetadata;
+using sync_pb::SessionSpecifics;
+using syncer::DataBatch;
+using syncer::EntityChangeList;
+using syncer::EntityData;
+using syncer::IsEmptyMetadataBatch;
+using syncer::MetadataBatch;
+using syncer::MetadataChangeList;
+using syncer::MockModelTypeChangeProcessor;
+using testing::_;
+using testing::Contains;
+using testing::ElementsAre;
+using testing::Eq;
+using testing::InSequence;
+using testing::IsEmpty;
+using testing::IsNull;
+using testing::Matcher;
+using testing::Not;
+using testing::NotNull;
+using testing::Pair;
+using testing::Pointee;
+using testing::Return;
+using testing::SaveArg;
+using testing::SizeIs;
+using testing::UnorderedElementsAre;
+using testing::WithArg;
+
+const char kLocalSessionTag[] = "sessiontag1";
+
+class MockSessionSyncPrefs : public syncer::SessionSyncPrefs {
+ public:
+ MockSessionSyncPrefs() = default;
+ ~MockSessionSyncPrefs() override = default;
+
+ MOCK_CONST_METHOD0(GetSyncSessionsGUID, std::string());
+ MOCK_METHOD1(SetSyncSessionsGUID, void(const std::string& guid));
+};
+
+MATCHER_P(EntityDataHasSpecifics, session_specifics_matcher, "") {
+ return session_specifics_matcher.MatchAndExplain(arg->specifics.session(),
+ result_listener);
+}
+
+syncer::EntityDataPtr SpecificsToEntity(
+ const sync_pb::SessionSpecifics& specifics,
+ base::Time mtime = base::Time::Now()) {
+ syncer::EntityData data;
+ data.client_tag_hash = syncer::GenerateSyncableHash(
+ syncer::SESSIONS, SessionStore::GetClientTag(specifics));
+ *data.specifics.mutable_session() = specifics;
+ data.modification_time = mtime;
+ return data.PassToPtr();
+}
+
+syncer::UpdateResponseData SpecificsToUpdateResponse(
+ const sync_pb::SessionSpecifics& specifics,
+ base::Time mtime = base::Time::Now()) {
+ syncer::UpdateResponseData data;
+ data.entity = SpecificsToEntity(specifics, mtime);
+ return data;
+}
+
+std::map<std::string, std::unique_ptr<EntityData>> BatchToEntityDataMap(
+ std::unique_ptr<DataBatch> batch) {
+ std::map<std::string, std::unique_ptr<EntityData>> storage_key_to_data;
+ while (batch && batch->HasNext()) {
+ storage_key_to_data.insert(batch->Next());
+ }
+ return storage_key_to_data;
+}
+
+syncer::UpdateResponseData CreateTombstone(const std::string& client_tag) {
+ EntityData tombstone;
+ tombstone.client_tag_hash =
+ syncer::GenerateSyncableHash(syncer::SESSIONS, client_tag);
+
+ syncer::UpdateResponseData data;
+ data.entity = tombstone.PassToPtr();
+ data.response_version = 2;
+ return data;
+}
+
+syncer::CommitResponseData CreateSuccessResponse(
+ const std::string& client_tag) {
+ syncer::CommitResponseData response;
+ response.client_tag_hash =
+ syncer::GenerateSyncableHash(syncer::SESSIONS, client_tag);
+ response.sequence_number = 1;
+ return response;
+}
+
+sync_pb::SessionSpecifics CreateHeaderSpecificsWithOneTab(
+ const std::string& session_tag,
+ int window_id,
+ int tab_id) {
+ sync_pb::SessionSpecifics specifics;
+ specifics.set_session_tag(session_tag);
+ specifics.mutable_header()->set_client_name("Some client name");
+ specifics.mutable_header()->set_device_type(
+ sync_pb::SyncEnums_DeviceType_TYPE_LINUX);
+ sync_pb::SessionWindow* window = specifics.mutable_header()->add_window();
+ window->set_browser_type(sync_pb::SessionWindow_BrowserType_TYPE_TABBED);
+ window->set_window_id(window_id);
+ window->add_tab(tab_id);
+ return specifics;
+}
+
+sync_pb::SessionSpecifics CreateTabSpecifics(const std::string& session_tag,
+ int window_id,
+ int tab_id,
+ int tab_node_id,
+ const std::string& url) {
+ sync_pb::SessionSpecifics specifics;
+ specifics.set_session_tag(session_tag);
+ specifics.set_tab_node_id(tab_node_id);
+ specifics.mutable_tab()->add_navigation()->set_virtual_url(url);
+ specifics.mutable_tab()->set_window_id(window_id);
+ specifics.mutable_tab()->set_tab_id(tab_id);
+ return specifics;
+}
+
+class SessionSyncBridgeTest : public ::testing::Test {
+ protected:
+ SessionSyncBridgeTest()
+ : store_(syncer::ModelTypeStoreTestUtil::CreateInMemoryStoreForTest(
+ syncer::SESSIONS)),
+ favicon_cache_(/*favicon_service=*/nullptr,
+ /*history_service=*/nullptr,
+ /*max_sync_favicon_limit=*/0) {
+ ON_CALL(mock_sync_sessions_client_, GetSyncedWindowDelegatesGetter())
+ .WillByDefault(Return(&window_getter_));
+ ON_CALL(mock_sync_sessions_client_, GetLocalSessionEventRouter())
+ .WillByDefault(Return(window_getter_.router()));
+ ON_CALL(mock_sync_prefs_, GetSyncSessionsGUID())
+ .WillByDefault(Return(kLocalSessionTag));
+
+ // Even if we use NiceMock, let's be strict about errors and let tests
+ // explicitly list them.
+ EXPECT_CALL(mock_processor_, ReportError(_)).Times(0);
+ }
+
+ ~SessionSyncBridgeTest() override {}
+
+ void InitializeBridge() {
+ real_processor_ =
+ std::make_unique<syncer::ClientTagBasedModelTypeProcessor>(
+ syncer::SESSIONS, /*dump_stack=*/base::DoNothing(),
+ /*commit_only=*/false);
+ mock_processor_.DelegateCallsByDefaultTo(real_processor_.get());
+ // Instantiate the bridge.
+ bridge_ = std::make_unique<SessionSyncBridge>(
+ &mock_sync_sessions_client_, &mock_sync_prefs_,
+ &mock_device_info_provider_,
+ /*store_factory=*/
+ syncer::ModelTypeStoreTestUtil::FactoryForForwardingStore(store_.get()),
+ mock_foreign_sessions_updated_callback_.Get(),
+ mock_processor_.CreateForwardingProcessor());
+ }
+
+ void ShutdownBridge() {
+ bridge_.reset();
+ // The mock is still delegating to |real_processor_|, so we reset it too.
+ ASSERT_TRUE(testing::Mock::VerifyAndClear(&mock_processor_));
+ real_processor_.reset();
+ }
+
+ void StartSyncing(const std::vector<SessionSpecifics>& remote_data = {}) {
+ // DeviceInfo is provided when sync is being enabled, which should lead to
+ // ModelReadyToSync().
+ mock_device_info_provider_.Initialize(std::make_unique<syncer::DeviceInfo>(
+ "cache_guid", "Wayne Gretzky's Hacking Box", "Chromium 10k",
+ "Chrome 10k", sync_pb::SyncEnums_DeviceType_TYPE_LINUX, "device_id"));
+
+ base::RunLoop loop;
+ real_processor_->OnSyncStarting(
+ /*error_handler=*/base::DoNothing(),
+ base::BindLambdaForTesting(
+ [&loop](std::unique_ptr<syncer::ActivationContext>) {
+ loop.Quit();
+ }));
+ loop.Run();
+
+ sync_pb::ModelTypeState state;
+ state.set_initial_sync_done(true);
+ syncer::UpdateResponseDataList initial_updates;
+ for (const SessionSpecifics& specifics : remote_data) {
+ initial_updates.push_back(SpecificsToUpdateResponse(specifics));
+ }
+ real_processor_->OnUpdateReceived(state, initial_updates);
+ }
+
+ std::map<std::string, std::unique_ptr<EntityData>> GetAllData() {
+ base::RunLoop loop;
+ std::unique_ptr<DataBatch> batch;
+ bridge_->GetAllData(base::BindLambdaForTesting(
+ [&loop, &batch](std::unique_ptr<DataBatch> input_batch) {
+ batch = std::move(input_batch);
+ loop.Quit();
+ }));
+ loop.Run();
+ EXPECT_NE(nullptr, batch);
+ return BatchToEntityDataMap(std::move(batch));
+ }
+
+ std::map<std::string, std::unique_ptr<EntityData>> GetData(
+ const std::vector<std::string>& storage_keys) {
+ base::RunLoop loop;
+ std::unique_ptr<DataBatch> batch;
+ bridge_->GetData(
+ storage_keys,
+ base::BindLambdaForTesting(
+ [&loop, &batch](std::unique_ptr<DataBatch> input_batch) {
+ batch = std::move(input_batch);
+ loop.Quit();
+ }));
+ loop.Run();
+ EXPECT_NE(nullptr, batch);
+ return BatchToEntityDataMap(std::move(batch));
+ }
+
+ std::unique_ptr<EntityData> GetData(const std::string& storage_key) {
+ std::map<std::string, std::unique_ptr<EntityData>> entity_data_map =
+ GetData(std::vector<std::string>{storage_key});
+ EXPECT_LE(entity_data_map.size(), 1U);
+ if (entity_data_map.empty()) {
+ return nullptr;
+ }
+ EXPECT_EQ(storage_key, entity_data_map.begin()->first);
+ return std::move(entity_data_map.begin()->second);
+ }
+
+ void ResetWindows() { window_getter_.ResetWindows(); }
+
+ TestSyncedWindowDelegate* AddWindow(
+ int window_id,
+ sync_pb::SessionWindow_BrowserType type =
+ sync_pb::SessionWindow_BrowserType_TYPE_TABBED) {
+ return window_getter_.AddWindow(type,
+ SessionID::FromSerializedValue(window_id));
+ }
+
+ TestSyncedTabDelegate* AddTab(int window_id,
+ const std::string& url,
+ int tab_id = SessionID::NewUnique().id()) {
+ TestSyncedTabDelegate* tab =
+ window_getter_.AddTab(SessionID::FromSerializedValue(window_id),
+ SessionID::FromSerializedValue(tab_id));
+ tab->Navigate(url, base::Time::Now());
+ return tab;
+ }
+
+ SessionSyncBridge* bridge() { return bridge_.get(); }
+
+ syncer::MockModelTypeChangeProcessor& mock_processor() {
+ return mock_processor_;
+ }
+
+ syncer::ClientTagBasedModelTypeProcessor* real_processor() {
+ return real_processor_.get();
+ }
+
+ base::MockCallback<base::RepeatingClosure>&
+ mock_foreign_sessions_updated_callback() {
+ return mock_foreign_sessions_updated_callback_;
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ const std::unique_ptr<syncer::ModelTypeStore> store_;
+
+ // Dependencies.
+ testing::NiceMock<MockSyncSessionsClient> mock_sync_sessions_client_;
+ testing::NiceMock<MockSessionSyncPrefs> mock_sync_prefs_;
+ syncer::LocalDeviceInfoProviderMock mock_device_info_provider_;
+ testing::NiceMock<MockModelTypeChangeProcessor> mock_processor_;
+ testing::NiceMock<base::MockCallback<base::RepeatingClosure>>
+ mock_foreign_sessions_updated_callback_;
+ TestSyncedWindowDelegatesGetter window_getter_;
+ FaviconCache favicon_cache_;
+
+ std::unique_ptr<SessionSyncBridge> bridge_;
+ std::unique_ptr<syncer::ClientTagBasedModelTypeProcessor> real_processor_;
+};
+
+TEST_F(SessionSyncBridgeTest, ShouldCallModelReadyToSyncWhenSyncEnabled) {
+ EXPECT_CALL(mock_processor(), ModelReadyToSync(_)).Times(0);
+ InitializeBridge();
+ EXPECT_CALL(mock_processor(), ModelReadyToSync(IsEmptyMetadataBatch()));
+ StartSyncing();
+}
+
+// Test that handling of local events (i.e. propagating the local state to
+// sync) does not start while a session restore is in progress.
+TEST_F(SessionSyncBridgeTest, ShouldDeferLocalEventDueToSessionRestore) {
+ const int kWindowId = 1000001;
+ const int kTabId1 = 1000002;
+ const int kTabId2 = 1000003;
+
+ // No notifications expected until OnSessionRestoreComplete().
+ EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+
+ AddWindow(kWindowId)->SetIsSessionRestoreInProgress(true);
+ // Initial tab should be ignored (not exposed to processor) while session
+ // restore is in progress.
+ AddTab(kWindowId, "http://foo.com/", kTabId1);
+
+ InitializeBridge();
+ StartSyncing();
+ EXPECT_THAT(GetAllData(),
+ ElementsAre(Pair(
+ _, EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag,
+ /*window_ids=*/{},
+ /*tab_ids=*/{})))));
+
+ // Create the actual tab, which should be ignored because session restore
+ // is in progress.
+ AddTab(kWindowId, "http://bar.com/", kTabId2);
+ EXPECT_THAT(GetAllData(), SizeIs(1));
+
+ // OnSessionRestoreComplete() should issue three Put() calls, one updating the
+ // header and one for each of the two added tabs.
+ EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(3);
+ bridge()->OnSessionRestoreComplete();
+ EXPECT_THAT(GetAllData(), SizeIs(3));
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldCreateHeaderByDefault) {
+ InitializeBridge();
+
+ EXPECT_CALL(mock_processor(), ModelReadyToSync(IsEmptyMetadataBatch()));
+ StartSyncing();
+
+ EXPECT_THAT(GetAllData(), SizeIs(1));
+}
+
+// Tests that local windows and tabs that exist at the time the bridge is
+// started (e.g. after a Chrome restart) are properly exposed via the bridge's
+// GetData() and GetAllData() methods, as well as notified via Put().
+TEST_F(SessionSyncBridgeTest, ShouldExposeInitialLocalTabsToProcessor) {
+ const int kWindowId = 1000001;
+ const int kTabId1 = 1000002;
+ const int kTabId2 = 1000003;
+
+ AddWindow(kWindowId);
+ AddTab(kWindowId, "http://foo.com/", kTabId1);
+ AddTab(kWindowId, "http://bar.com/", kTabId2);
+
+ InitializeBridge();
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, 0);
+ const std::string tab_storage_key2 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, 1);
+
+ EXPECT_CALL(mock_processor(),
+ Put(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1, kTabId2})),
+ _));
+ EXPECT_CALL(mock_processor(),
+ Put(tab_storage_key1,
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId1,
+ /*tab_node_id=*/_, {"http://foo.com/"})),
+ _));
+ EXPECT_CALL(mock_processor(),
+ Put(tab_storage_key2,
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId2,
+ /*tab_node_id=*/_, {"http://bar.com/"})),
+ _));
+
+ StartSyncing();
+
+ EXPECT_THAT(GetData(header_storage_key),
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1, kTabId2})));
+ EXPECT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1, kTabId2}))),
+ Pair(tab_storage_key1, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabId1,
+ /*tab_node_id=*/_, {"http://foo.com/"}))),
+ Pair(tab_storage_key2,
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId2,
+ /*tab_node_id=*/_, {"http://bar.com/"})))));
+}
+
+// Tests that the creation of a new tab while sync is enabled is propagated to:
+// 1) The processor, via Put().
+// 2) The in-memory representation exposed via GetData().
+// 3) The persisted store, exposed via GetAllData().
+TEST_F(SessionSyncBridgeTest, ShouldReportLocalTabCreation) {
+ const int kWindowId = 1000001;
+ const int kTabId1 = 1000002;
+ const int kTabId2 = 1000003;
+
+ AddWindow(kWindowId);
+ AddTab(kWindowId, "http://foo.com/", kTabId1);
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(GetAllData(), SizeIs(2));
+ EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0);
+
+ // Expectations for the processor.
+ std::string header_storage_key;
+ std::string tab_storage_key;
+ // Tab creation triggers an update event due to the tab parented notification,
+ // so the event handler issues two commits as well (one for tab creation, one
+ // for tab update). During the first update, however, the tab is not syncable
+ // and is hence skipped.
+ testing::Expectation put_transient_header = EXPECT_CALL(
+ mock_processor(), Put(_,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1})),
+ _));
+ EXPECT_CALL(mock_processor(),
+ Put(_,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1, kTabId2})),
+ _))
+ .After(put_transient_header)
+ .WillOnce(WithArg<0>(SaveArg<0>(&header_storage_key)));
+ EXPECT_CALL(mock_processor(),
+ Put(_,
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId2,
+ /*tab_node_id=*/_, {"http://bar.com/"})),
+ _))
+ .WillOnce(WithArg<0>(SaveArg<0>(&tab_storage_key)));
+
+ // Create the actual tab, now that we're syncing.
+ AddTab(kWindowId, "http://bar.com/", kTabId2);
+
+ ASSERT_THAT(header_storage_key,
+ Eq(SessionStore::GetHeaderStorageKey(kLocalSessionTag)));
+ ASSERT_THAT(tab_storage_key, Not(IsEmpty()));
+
+ // Verify the bridge's state exposed via the getters.
+ EXPECT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1, kTabId2}))),
+ Pair(_, EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId1,
+ /*tab_node_id=*/_, {"http://foo.com/"}))),
+ Pair(tab_storage_key, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabId2,
+ /*tab_node_id=*/_, {"http://bar.com/"})))));
+ EXPECT_THAT(GetData(header_storage_key),
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId1, kTabId2})));
+ EXPECT_THAT(GetData(tab_storage_key),
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId2,
+ /*tab_node_id=*/_, {"http://bar.com/"})));
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldUpdateIdsDuringRestore) {
+ const int kWindowId = 1000001;
+ const int kTabIdBeforeRestore1 = 1000002;
+ const int kTabIdBeforeRestore2 = 1000003;
+ const int kTabIdAfterRestore1 = 1000004;
+ const int kTabIdAfterRestore2 = 1000005;
+ // Zero is the first assigned tab node ID.
+ const int kTabNodeId1 = 0;
+ const int kTabNodeId2 = 1;
+
+ AddWindow(kWindowId);
+ TestSyncedTabDelegate* tab1 =
+ AddTab(kWindowId, "http://foo.com/", kTabIdBeforeRestore1);
+ TestSyncedTabDelegate* tab2 =
+ AddTab(kWindowId, "http://bar.com/", kTabIdBeforeRestore2);
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, kTabNodeId1);
+ const std::string tab_storage_key2 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, kTabNodeId2);
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(tab1->GetSyncId(), Eq(kTabNodeId1));
+ ASSERT_THAT(tab2->GetSyncId(), Eq(kTabNodeId2));
+
+ ASSERT_THAT(GetData(header_storage_key),
+ EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, {kWindowId},
+ {kTabIdBeforeRestore1, kTabIdBeforeRestore2})));
+ ASSERT_THAT(GetData(tab_storage_key1),
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabIdBeforeRestore1,
+ kTabNodeId1, {"http://foo.com/"})));
+ ASSERT_THAT(GetData(tab_storage_key2),
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabIdBeforeRestore2,
+ kTabNodeId2, {"http://bar.com/"})));
+
+ ShutdownBridge();
+
+ // Override tabs with placeholder tab delegates.
+ PlaceholderTabDelegate placeholder_tab1(
+ SessionID::FromSerializedValue(kTabIdAfterRestore1), tab1->GetSyncId());
+ PlaceholderTabDelegate placeholder_tab2(
+ SessionID::FromSerializedValue(kTabIdAfterRestore2), tab2->GetSyncId());
+ ResetWindows();
+ TestSyncedWindowDelegate* window = AddWindow(kWindowId);
+ window->OverrideTabAt(0, &placeholder_tab1);
+ window->OverrideTabAt(1, &placeholder_tab2);
+
+ // When the bridge gets restarted, we expected tab IDs being updated, but the
+ // rest of the information such as navigation URLs should be reused.
+ EXPECT_CALL(mock_processor(),
+ Put(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId},
+ {kTabIdAfterRestore1, kTabIdAfterRestore2})),
+ _));
+ EXPECT_CALL(mock_processor(),
+ Put(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabIdAfterRestore1,
+ kTabNodeId1, {"http://foo.com/"})),
+ _));
+ EXPECT_CALL(mock_processor(),
+ Put(tab_storage_key2,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabIdAfterRestore2,
+ kTabNodeId2, {"http://bar.com/"})),
+ _));
+
+ // Start the bridge again.
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(placeholder_tab1.GetSyncId(), Eq(kTabNodeId1));
+ EXPECT_THAT(placeholder_tab2.GetSyncId(), Eq(kTabNodeId2));
+
+ EXPECT_THAT(GetData(header_storage_key),
+ EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, {kWindowId},
+ {kTabIdAfterRestore1, kTabIdAfterRestore2})));
+ EXPECT_THAT(GetData(tab_storage_key1),
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabIdAfterRestore1,
+ kTabNodeId1, {"http://foo.com/"})));
+ EXPECT_THAT(GetData(tab_storage_key2),
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabIdAfterRestore2,
+ kTabNodeId2, {"http://bar.com/"})));
+
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId},
+ {kTabIdAfterRestore1, kTabIdAfterRestore2}))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabIdAfterRestore1,
+ kTabNodeId1, {"http://foo.com/"}))),
+ Pair(tab_storage_key2,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabIdAfterRestore2,
+ kTabNodeId2, {"http://bar.com/"})))));
+}
+
+TEST_F(SessionSyncBridgeTest,
+ ShouldIgnoreUnsyncablePlaceholderTabDuringRestore) {
+ const int kWindowId = 1000001;
+ const int kTabIdBeforeRestore1 = 1000002;
+ const int kTabIdBeforeRestore2 = 1000003;
+ const int kTabIdAfterRestore1 = 1000004;
+ const int kTabIdAfterRestore2 = 1000005;
+ // Zero is the first assigned tab node ID.
+ const int kTabNodeId1 = 0;
+
+ AddWindow(kWindowId);
+ TestSyncedTabDelegate* tab1 =
+ AddTab(kWindowId, "http://foo.com/", kTabIdBeforeRestore1);
+ // Tab 2 is unsyncable because of the URL scheme.
+ TestSyncedTabDelegate* tab2 =
+ AddTab(kWindowId, "about:blank", kTabIdBeforeRestore2);
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, kTabNodeId1);
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(tab1->GetSyncId(), Eq(kTabNodeId1));
+ ASSERT_THAT(tab2->GetSyncId(), Eq(TabNodePool::kInvalidTabNodeID));
+
+ ASSERT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId},
+ {kTabIdBeforeRestore1}))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabIdBeforeRestore1,
+ kTabNodeId1, {"http://foo.com/"})))));
+
+ ShutdownBridge();
+
+ // Override tabs with placeholder tab delegates.
+ PlaceholderTabDelegate placeholder_tab1(
+ SessionID::FromSerializedValue(kTabIdAfterRestore1), tab1->GetSyncId());
+ PlaceholderTabDelegate placeholder_tab2(
+ SessionID::FromSerializedValue(kTabIdAfterRestore2), tab2->GetSyncId());
+ ResetWindows();
+ TestSyncedWindowDelegate* window = AddWindow(kWindowId);
+ window->OverrideTabAt(0, &placeholder_tab1);
+ window->OverrideTabAt(1, &placeholder_tab2);
+
+ // Start the bridge again.
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(placeholder_tab1.GetSyncId(), Eq(kTabNodeId1));
+ EXPECT_THAT(placeholder_tab2.GetSyncId(), Eq(TabNodePool::kInvalidTabNodeID));
+
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId},
+ {kTabIdAfterRestore1}))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId, kTabIdAfterRestore1,
+ kTabNodeId1, {"http://foo.com/"})))));
+}
+
+// Ensure that tabbed windows from a previous session are preserved if no
+// windows are present on startup.
+TEST_F(SessionSyncBridgeTest, ShouldRestoreTabbedDataIfNoWindowsDuringStartup) {
+ const int kWindowId = 1000001;
+ const int kTabNodeId = 0;
+
+ AddWindow(kWindowId);
+ TestSyncedTabDelegate* tab = AddTab(kWindowId, "http://foo.com/");
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string tab_storage_key =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, kTabNodeId);
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(tab_storage_key,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, _, _, kTabNodeId, {"http://foo.com/"})))));
+
+ ShutdownBridge();
+
+ // Start the bridge with no local windows/tabs.
+ ResetWindows();
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(tab_storage_key,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, _, _, kTabNodeId, {"http://foo.com/"})))));
+
+ // Now actually resurrect the native data, which will end up having different
+ // native ids, but the tab has the same sync id as before.
+ EXPECT_CALL(
+ mock_processor(),
+ Put(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _)), _));
+ EXPECT_CALL(mock_processor(),
+ Put(tab_storage_key,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, /*window_id=*/_, /*tab_id=*/_,
+ kTabNodeId, {"http://foo.com/", "http://bar.com/"})),
+ _));
+ AddWindow(kWindowId)->OverrideTabAt(0, tab);
+ tab->Navigate("http://bar.com/");
+}
+
+// Ensure that tabbed windows from a previous session are preserved if only
+// a custom tab is present at startup.
+TEST_F(SessionSyncBridgeTest, ShouldPreserveTabbedDataIfCustomTabOnlyFound) {
+ const int kWindowId1 = 1000001;
+ const int kWindowId2 = 1000002;
+
+ AddWindow(kWindowId1);
+ AddTab(kWindowId1, "http://foo.com/");
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, _, _,
+ /*tab_node_id=*/0, {"http://foo.com/"})))));
+
+ ShutdownBridge();
+
+ // Start the bridge with only a custom tab open.
+ ResetWindows();
+ AddWindow(kWindowId2, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
+ AddTab(kWindowId2, "http://bar.com/");
+ InitializeBridge();
+ StartSyncing();
+
+ // The previous session should be preserved. The transient window cannot be
+ // synced because we do not have enough local data to ensure that we wouldn't
+ // vend the same sync ID if our persistent storage didn't match upon the last
+ // shutdown.
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, _, _,
+ /*tab_node_id=*/0, {"http://foo.com/"})))));
+}
+
+// Ensure that tabbed windows from a previous session are preserved and combined
+// with a custom tab that was newly found during startup.
+TEST_F(SessionSyncBridgeTest, ShouldPreserveTabbedDataIfNewCustomTabAlsoFound) {
+ const int kWindowId1 = 1000001;
+ const int kWindowId2 = 1000002;
+ const int kTabId1 = 1000003;
+ const int kTabId2 = 1000004;
+
+ AddWindow(kWindowId1);
+ AddTab(kWindowId1, "http://foo.com/", kTabId1);
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId1}, {kTabId1}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId1, kTabId1,
+ /*tab_node_id=*/0, {"http://foo.com/"})))));
+
+ ShutdownBridge();
+
+ // Start the bridge with an additional local custom tab.
+ AddWindow(kWindowId2, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
+ AddTab(kWindowId2, "http://bar.com/", kTabId2);
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId1, kWindowId2},
+ {kTabId1, kTabId2}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId1, kTabId1,
+ /*tab_node_id=*/0, {"http://foo.com/"}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId2, kTabId2,
+ /*tab_node_id=*/1, {"http://bar.com/"})))));
+}
+
+// Ensure that, in a scenario without prior sync data, encountering a custom
+// tab only ( no tabbed window) does not vend new sync IDs.
+TEST_F(SessionSyncBridgeTest, ShouldIgnoreIfCustomTabOnlyOnStartup) {
+ const int kWindowId = 1000001;
+
+ AddWindow(kWindowId, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
+ AddTab(kWindowId, "http://foo.com/");
+
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, _, _)))));
+}
+
+// Ensure that all tabs are exposed in a scenario where only a custom tab
+// (without tabbed windows) was present during startup, and later tabbed windows
+// appear (browser started).
+TEST_F(SessionSyncBridgeTest, ShouldExposeTabbedWindowAfterCustomTabOnly) {
+ const int kWindowId1 = 1000001;
+ const int kWindowId2 = 1000002;
+ const int kTabId1 = 1000003;
+ const int kTabId2 = 1000004;
+
+ AddWindow(kWindowId1, sync_pb::SessionWindow_BrowserType_TYPE_CUSTOM_TAB);
+ TestSyncedTabDelegate* custom_tab =
+ AddTab(kWindowId1, "http://foo.com/", kTabId1);
+
+ InitializeBridge();
+ StartSyncing();
+
+ ASSERT_THAT(GetAllData(),
+ UnorderedElementsAre(Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, _, _)))));
+
+ // Load the actual tabbed window, now that we're syncing.
+ AddWindow(kWindowId2);
+ AddTab(kWindowId2, "http://bar.com/", kTabId2);
+
+ // The local change should be created and tracked correctly. This doesn't
+ // actually start syncing the custom tab yet, because the tab itself isn't
+ // associated yet.
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId2}, {kTabId2}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId2, kTabId2,
+ /*tab_node_id=*/0, {"http://bar.com/"})))));
+
+ // Now trigger OnLocalTabModified() for the custom tab again, it should sync.
+ custom_tab->Navigate("http://baz.com/");
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId1, kWindowId2},
+ {kTabId1, kTabId2}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId2, kTabId2,
+ /*tab_node_id=*/0, {"http://bar.com/"}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId1, kTabId1,
+ /*tab_node_id=*/1,
+ {"http://foo.com/", "http://baz.com/"})))));
+}
+
+// Ensure that newly assigned tab node IDs do not conflict with IDs provided
+// by the delegate, for IDs the tracker might not know about. This is possible
+// for example if an Android client gets killed after Android's tab restore
+// has flushed the sync ID to disk, but before the sync database has been
+// written.
+TEST_F(SessionSyncBridgeTest, ShouldHonorUnknownSyncIdsFromDelegate) {
+ const int kWindowId = 1000001;
+ const int kTabNodeId = 0;
+
+ // In a previous run of a browser, we associated sync ID 0 to the second tab
+ // below, which the Android tab restore database succeeded to flush to disk.
+ // The sync_sessions counterpart (SessionStore) however didn't, because writes
+ // are not atomic.
+ AddWindow(kWindowId);
+ AddTab(kWindowId, "http://foo.com/");
+ AddTab(kWindowId, "http://bar.com/")->SetSyncId(kTabNodeId);
+
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(_,
+ EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(_,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, _, _, kTabNodeId, {"http://bar.com/"}))),
+ Pair(_, EntityDataHasSpecifics(MatchesTab(kLocalSessionTag, _, _,
+ /*tab_node_id=*/1,
+ {"http://foo.com/"})))));
+}
+
+// Ensure that unsyncable tabs are ignored even if the delegate reports a sync
+// ID (because the tab used to be syncable).
+TEST_F(SessionSyncBridgeTest,
+ ShouldHonorUnknownSyncIdsFromDelegateWithUnsyncableTab) {
+ const int kWindowId = 1000001;
+ const int kTabId = 1000002;
+ const int kTabNodeId = 0;
+
+ AddWindow(kWindowId);
+ AddTab(kWindowId, "about:blank", kTabId)->SetSyncId(kTabNodeId);
+
+ InitializeBridge();
+
+ EXPECT_CALL(mock_processor(),
+ Put(_,
+ EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, {kWindowId}, {kTabId})),
+ _));
+
+ StartSyncing();
+
+ // As a regression test for crbug.com/846480, we verify that restarting the
+ // bridge without tabbed windows doesn't crash or issue more calls to Put().
+ // This is only problematic because, in the current implementation and as
+ // reflected in the assertion below, the unsyncable tab is still stored in
+ // the local model.
+ ASSERT_THAT(GetAllData(),
+ UnorderedElementsAre(
+ Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, {kWindowId}, {kTabId}))),
+ Pair(_, EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, kWindowId, kTabId,
+ kTabNodeId, /*urls=*/{})))));
+
+ ShutdownBridge();
+ ResetWindows();
+ InitializeBridge();
+ StartSyncing();
+ EXPECT_THAT(
+ GetAllData(),
+ ElementsAre(Pair(_, EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, /*window_ids=*/SizeIs(1),
+ /*tab_ids=*/SizeIs(1))))));
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldDisableSyncAndReenable) {
+ const int kWindowId = 1000001;
+ const int kTabId = 1000002;
+
+ AddWindow(kWindowId);
+ AddTab(kWindowId, "http://foo.com/", kTabId);
+
+ InitializeBridge();
+ StartSyncing();
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ ASSERT_THAT(GetData(header_storage_key),
+ EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, {kWindowId}, {kTabId})));
+ ASSERT_THAT(GetAllData(), Not(IsEmpty()));
+
+ EXPECT_CALL(mock_processor(), ModelReadyToSync(_)).Times(0);
+ real_processor()->DisableSync();
+
+ EXPECT_CALL(mock_processor(), ModelReadyToSync(IsEmptyMetadataBatch()));
+ StartSyncing();
+ ASSERT_THAT(GetData(header_storage_key),
+ EntityDataHasSpecifics(
+ MatchesHeader(kLocalSessionTag, {kWindowId}, {kTabId})));
+}
+
+// Starting sync with no local data should just store the foreign entities in
+// the store and expose them via OpenTabsUIDelegate.
+TEST_F(SessionSyncBridgeTest, ShouldMergeForeignSession) {
+ const std::string kForeignSessionTag = "foreignsessiontag";
+ const int kForeignWindowId = 2000001;
+ const int kForeignTabId = 2000002;
+ const int kForeignTabNodeId = 2003;
+
+ EXPECT_CALL(mock_processor(), UpdateStorageKey(_, _, _)).Times(0);
+ EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+ InitializeBridge();
+
+ const sync_pb::SessionSpecifics foreign_header =
+ CreateHeaderSpecificsWithOneTab(kForeignSessionTag, kForeignWindowId,
+ kForeignTabId);
+ const sync_pb::SessionSpecifics foreign_tab =
+ CreateTabSpecifics(kForeignSessionTag, kForeignWindowId, kForeignTabId,
+ kForeignTabNodeId, "http://baz.com/");
+
+ EXPECT_CALL(
+ mock_processor(),
+ Put(_, EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _)), _));
+ EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+
+ StartSyncing({foreign_header, foreign_tab});
+
+ std::vector<const SyncedSession*> foreign_sessions;
+ EXPECT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+ EXPECT_THAT(foreign_sessions,
+ ElementsAre(MatchesSyncedSession(
+ kForeignSessionTag,
+ {{kForeignWindowId, std::vector<int>{kForeignTabId}}})));
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldNotExposeForeignHeaderWithoutTabs) {
+ const std::string kForeignSessionTag = "foreignsessiontag";
+ const int kForeignWindowId = 2000001;
+ const int kForeignTabId = 2000002;
+
+ EXPECT_CALL(mock_processor(), UpdateStorageKey(_, _, _)).Times(0);
+ EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+ InitializeBridge();
+
+ const sync_pb::SessionSpecifics foreign_header =
+ CreateHeaderSpecificsWithOneTab(kForeignSessionTag, kForeignWindowId,
+ kForeignTabId);
+ const std::string foreign_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+
+ EXPECT_CALL(
+ mock_processor(),
+ Put(_, EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _)), _));
+
+ StartSyncing({foreign_header});
+ ASSERT_THAT(GetData(foreign_header_storage_key), NotNull());
+
+ std::vector<const SyncedSession*> foreign_sessions;
+ EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+
+ // Restart bridge to verify the state doesn't change.
+ ShutdownBridge();
+ InitializeBridge();
+ StartSyncing();
+ ASSERT_THAT(GetData(foreign_header_storage_key), NotNull());
+
+ EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+}
+
+// Regression test for crbug.com/837517: Ensure that the bridge doesn't crash
+// and closed foreign tabs (|kForeignTabId2| in the test) are not exposed after
+// restarting the browser.
+TEST_F(SessionSyncBridgeTest, ShouldNotExposeClosedTabsAfterRestart) {
+ const std::string kForeignSessionTag = "foreignsessiontag";
+ const int kForeignWindowId = 2000001;
+ const int kForeignTabId1 = 2000002;
+ const int kForeignTabId2 = 2000003;
+ const int kForeignTabNodeId1 = 2004;
+ const int kForeignTabNodeId2 = 2005;
+
+ // The header only lists a single tab |kForeignTabId1|, which becomes a mapped
+ // tab.
+ const sync_pb::SessionSpecifics foreign_header =
+ CreateHeaderSpecificsWithOneTab(kForeignSessionTag, kForeignWindowId,
+ kForeignTabId1);
+ const sync_pb::SessionSpecifics foreign_tab1 =
+ CreateTabSpecifics(kForeignSessionTag, kForeignWindowId, kForeignTabId1,
+ kForeignTabNodeId1, "http://foo.com/");
+ // |kForeignTabId2| is not present in the header, leading to an unmapped tab.
+ const sync_pb::SessionSpecifics foreign_tab2 =
+ CreateTabSpecifics(kForeignSessionTag, kForeignWindowId, kForeignTabId2,
+ kForeignTabNodeId2, "http://bar.com/");
+
+ InitializeBridge();
+ StartSyncing({foreign_header, foreign_tab1, foreign_tab2});
+
+ const std::string local_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string foreign_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+ const std::string foreign_tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kForeignTabNodeId1);
+ const std::string foreign_tab_storage_key2 =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kForeignTabNodeId2);
+
+ ASSERT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(local_header_storage_key, _),
+ Pair(foreign_header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kForeignSessionTag, {kForeignWindowId}, {kForeignTabId1}))),
+ Pair(foreign_tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kForeignSessionTag, kForeignWindowId, kForeignTabId1,
+ kForeignTabNodeId1, {"http://foo.com/"}))),
+ Pair(foreign_tab_storage_key2,
+ EntityDataHasSpecifics(MatchesTab(
+ kForeignSessionTag, kForeignWindowId, kForeignTabId2,
+ kForeignTabNodeId2, {"http://bar.com/"})))));
+
+ // Mimic a browser restart, which should restore the very same state (and not
+ // crash!).
+ ShutdownBridge();
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_THAT(GetAllData(),
+ UnorderedElementsAre(Pair(local_header_storage_key, _),
+ Pair(foreign_header_storage_key, _),
+ Pair(foreign_tab_storage_key1, _),
+ Pair(foreign_tab_storage_key2, _)));
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldHandleRemoteDeletion) {
+ const std::string kForeignSessionTag = "foreignsessiontag";
+ const int kForeignWindowId = 2000001;
+ const int kForeignTabId = 2000002;
+ const int kForeignTabNodeId = 2003;
+
+ InitializeBridge();
+
+ const sync_pb::SessionSpecifics foreign_header =
+ CreateHeaderSpecificsWithOneTab(kForeignSessionTag, kForeignWindowId,
+ kForeignTabId);
+ const sync_pb::SessionSpecifics foreign_tab =
+ CreateTabSpecifics(kForeignSessionTag, kForeignWindowId, kForeignTabId,
+ kForeignTabNodeId, "http://baz.com/");
+ StartSyncing({foreign_header, foreign_tab});
+
+ const sessions::SessionTab* foreign_session_tab = nullptr;
+ ASSERT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetForeignTab(
+ kForeignSessionTag, SessionID::FromSerializedValue(kForeignTabId),
+ &foreign_session_tab));
+ ASSERT_THAT(foreign_session_tab, NotNull());
+ std::vector<const SyncedSession*> foreign_sessions;
+ ASSERT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+ ASSERT_THAT(foreign_sessions,
+ ElementsAre(MatchesSyncedSession(
+ kForeignSessionTag,
+ {{kForeignWindowId, std::vector<int>{kForeignTabId}}})));
+ ASSERT_TRUE(real_processor()->IsTrackingMetadata());
+
+ // Mimic receiving a remote deletion of the foreign session.
+ sync_pb::ModelTypeState state;
+ state.set_initial_sync_done(true);
+
+ EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+ real_processor()->OnUpdateReceived(
+ state, {CreateTombstone(SessionStore::GetClientTag(foreign_header))});
+
+ foreign_session_tab = nullptr;
+ EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetForeignTab(
+ kForeignSessionTag, SessionID::FromSerializedValue(kForeignTabId),
+ &foreign_session_tab));
+
+ EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldIgnoreRemoteDeletionOfLocalTab) {
+ const int kWindowId1 = 1000001;
+ const int kTabId1 = 1000002;
+ const int kTabNodeId1 = 0;
+
+ AddWindow(kWindowId1);
+ AddTab(kWindowId1, "http://foo.com/", kTabId1);
+
+ InitializeBridge();
+ StartSyncing();
+
+ const std::string header_storage_key =
+ SessionStore::GetHeaderStorageKey(kLocalSessionTag);
+ const std::string tab_storage_key1 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, kTabNodeId1);
+ const std::string tab_client_tag1 =
+ SessionStore::GetTabClientTagForTest(kLocalSessionTag, kTabNodeId1);
+
+ ASSERT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(tab_storage_key1, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId1, kTabId1,
+ kTabNodeId1, {"http://foo.com/"})))));
+ ASSERT_TRUE(real_processor()->IsTrackingMetadata());
+ ASSERT_TRUE(real_processor()->HasLocalChangesForTest());
+
+ // Mimic receiving a commit ack for both the tab and the header entity,
+ // because otherwise it will be treated as conflict, and then local wins.
+ sync_pb::ModelTypeState state;
+ state.set_initial_sync_done(true);
+ real_processor()->OnCommitCompleted(
+ state, {CreateSuccessResponse(tab_client_tag1),
+ CreateSuccessResponse(kLocalSessionTag)});
+ ASSERT_FALSE(real_processor()->HasLocalChangesForTest());
+
+ // Mimic receiving a remote deletion of both entities.
+ EXPECT_CALL(mock_processor(), Put(_, _, _)).Times(0);
+ real_processor()->OnUpdateReceived(state, {CreateTombstone(kLocalSessionTag),
+ CreateTombstone(tab_client_tag1)});
+
+ // State should remain unchanged (deletions ignored).
+ EXPECT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(kLocalSessionTag, _, _))),
+ Pair(tab_storage_key1, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId1, kTabId1,
+ kTabNodeId1, {"http://foo.com/"})))));
+
+ // Creating a new tab locally should trigger Put() calls for *all* entities
+ // (because the local data was out of sync).
+ const int kWindowId2 = 2000001;
+ const int kTabId2 = 2000002;
+ const int kTabNodeId2 = 1;
+
+ const std::string tab_storage_key2 =
+ SessionStore::GetTabStorageKey(kLocalSessionTag, kTabNodeId2);
+
+ // Window creation already triggers a header update, which will be overriden
+ // later below.
+ testing::Expectation put_transient_header =
+ EXPECT_CALL(mock_processor(), Put(header_storage_key, _, _));
+ AddWindow(kWindowId2);
+
+ // In the current implementation, some of the updates are reported to the
+ // processor twice, but that's OK because the processor can detect it.
+ EXPECT_CALL(mock_processor(),
+ Put(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, ElementsAre(kWindowId1, kWindowId2),
+ ElementsAre(kTabId1, kTabId2))),
+ _))
+ .Times(2)
+ .After(put_transient_header);
+ EXPECT_CALL(mock_processor(), Put(tab_storage_key1,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId1, kTabId1,
+ kTabNodeId1, {"http://foo.com/"})),
+ _));
+ EXPECT_CALL(mock_processor(), Put(tab_storage_key2,
+ EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId2, kTabId2,
+ kTabNodeId2, {"http://bar.com/"})),
+ _))
+ .Times(2);
+
+ AddTab(kWindowId2, "http://bar.com/", kTabId2);
+
+ EXPECT_THAT(
+ GetAllData(),
+ UnorderedElementsAre(
+ Pair(header_storage_key,
+ EntityDataHasSpecifics(MatchesHeader(
+ kLocalSessionTag, ElementsAre(kWindowId1, kWindowId2),
+ ElementsAre(kTabId1, kTabId2)))),
+ Pair(tab_storage_key1,
+ EntityDataHasSpecifics(
+ MatchesTab(kLocalSessionTag, /*window_id=*/_, /*tab_id=*/_,
+ kTabNodeId1, {"http://foo.com/"}))),
+ Pair(tab_storage_key2, EntityDataHasSpecifics(MatchesTab(
+ kLocalSessionTag, kWindowId2, kTabId2,
+ kTabNodeId2, {"http://bar.com/"})))));
+
+ // Run until idle because PostTask() is used to invoke ResubmitLocalSession().
+ base::RunLoop().RunUntilIdle();
+}
+
+// Verifies that a foreign session can be deleted by the user from the history
+// UI (via OpenTabsUIDelegate).
+TEST_F(SessionSyncBridgeTest, ShouldDeleteForeignSessionFromUI) {
+ const std::string kForeignSessionTag = "foreignsessiontag";
+ const int kForeignWindowId = 2000001;
+ const int kForeignTabId = 2000002;
+ const int kForeignTabNodeId = 2003;
+
+ InitializeBridge();
+
+ const sync_pb::SessionSpecifics foreign_header =
+ CreateHeaderSpecificsWithOneTab(kForeignSessionTag, kForeignWindowId,
+ kForeignTabId);
+ const sync_pb::SessionSpecifics foreign_tab =
+ CreateTabSpecifics(kForeignSessionTag, kForeignWindowId, kForeignTabId,
+ kForeignTabNodeId, "http://baz.com/");
+ StartSyncing({foreign_header, foreign_tab});
+
+ const std::string foreign_header_storage_key =
+ SessionStore::GetHeaderStorageKey(kForeignSessionTag);
+ const std::string foreign_tab_storage_key =
+ SessionStore::GetTabStorageKey(kForeignSessionTag, kForeignTabNodeId);
+
+ // Test fixture expects the two foreign entities in the model as well as the
+ // underlying store.
+ ASSERT_THAT(GetData(foreign_header_storage_key), NotNull());
+ ASSERT_THAT(GetData(foreign_tab_storage_key), NotNull());
+
+ const sessions::SessionTab* foreign_session_tab = nullptr;
+ ASSERT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetForeignTab(
+ kForeignSessionTag, SessionID::FromSerializedValue(kForeignTabId),
+ &foreign_session_tab));
+ ASSERT_THAT(foreign_session_tab, NotNull());
+ std::vector<const SyncedSession*> foreign_sessions;
+ ASSERT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+ ASSERT_THAT(foreign_sessions,
+ ElementsAre(MatchesSyncedSession(
+ kForeignSessionTag,
+ {{kForeignWindowId, std::vector<int>{kForeignTabId}}})));
+ ASSERT_TRUE(real_processor()->IsTrackingMetadata());
+
+ // Mimic the user requesting a session deletion from the UI.
+ EXPECT_CALL(mock_processor(), Delete(foreign_header_storage_key, _));
+ EXPECT_CALL(mock_processor(), Delete(foreign_tab_storage_key, _));
+ EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+ bridge()->GetOpenTabsUIDelegate()->DeleteForeignSession(kForeignSessionTag);
+
+ // Verify what gets exposed to the UI.
+ foreign_session_tab = nullptr;
+ EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetForeignTab(
+ kForeignSessionTag, SessionID::FromSerializedValue(kForeignTabId),
+ &foreign_session_tab));
+ EXPECT_FALSE(bridge()->GetOpenTabsUIDelegate()->GetAllForeignSessions(
+ &foreign_sessions));
+
+ // Verify store.
+ EXPECT_THAT(GetData(foreign_header_storage_key), IsNull());
+ EXPECT_THAT(GetData(foreign_tab_storage_key), IsNull());
+}
+
+// Verifies that attempts to delete the local session from the UI are ignored,
+// although the UI sholdn't really be offering that option.
+TEST_F(SessionSyncBridgeTest, ShouldIgnoreLocalSessionDeletionFromUI) {
+ InitializeBridge();
+ StartSyncing();
+
+ EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run()).Times(0);
+ EXPECT_CALL(mock_processor(), Delete(_, _)).Times(0);
+
+ bridge()->GetOpenTabsUIDelegate()->DeleteForeignSession(kLocalSessionTag);
+
+ const SyncedSession* session = nullptr;
+ EXPECT_TRUE(bridge()->GetOpenTabsUIDelegate()->GetLocalSession(&session));
+ EXPECT_THAT(session, NotNull());
+ EXPECT_THAT(GetData(SessionStore::GetHeaderStorageKey(kLocalSessionTag)),
+ NotNull());
+}
+
+TEST_F(SessionSyncBridgeTest, ShouldDoGarbageCollection) {
+ // We construct two identical sessions, one modified recently, one modified
+ // more than |kStaleSessionThreshold| ago (14 days ago).
+ const base::Time stale_mtime =
+ base::Time::Now() - base::TimeDelta::FromDays(15);
+ const base::Time recent_mtime =
+ base::Time::Now() - base::TimeDelta::FromDays(13);
+ const std::string kStaleSessionTag = "stalesessiontag";
+ const std::string kRecentSessionTag = "recentsessiontag";
+ const int kWindowId = 2000001;
+ const int kTabId = 2000002;
+ const int kTabNodeId = 2003;
+
+ InitializeBridge();
+ StartSyncing();
+
+ // Construct a remote update.
+ sync_pb::ModelTypeState state;
+ state.set_initial_sync_done(true);
+ syncer::UpdateResponseDataList updates;
+ // Two entities belong to a recent session.
+ updates.push_back(SpecificsToUpdateResponse(
+ CreateHeaderSpecificsWithOneTab(kStaleSessionTag, kWindowId, kTabId),
+ stale_mtime));
+ updates.push_back(SpecificsToUpdateResponse(
+ CreateTabSpecifics(kStaleSessionTag, kWindowId, kTabId, kTabNodeId,
+ "http://baz.com/"),
+ stale_mtime));
+ updates.push_back(SpecificsToUpdateResponse(
+ CreateHeaderSpecificsWithOneTab(kRecentSessionTag, kWindowId, kTabId),
+ recent_mtime));
+ updates.push_back(SpecificsToUpdateResponse(
+ CreateTabSpecifics(kRecentSessionTag, kWindowId, kTabId, kTabNodeId,
+ "http://baz.com/"),
+ recent_mtime));
+ real_processor()->OnUpdateReceived(state, updates);
+
+ // During garbage collection, we expect |kStaleSessionTag| to be deleted.
+ EXPECT_CALL(mock_processor(),
+ Delete(SessionStore::GetHeaderStorageKey(kStaleSessionTag), _));
+ EXPECT_CALL(
+ mock_processor(),
+ Delete(SessionStore::GetTabStorageKey(kStaleSessionTag, kTabNodeId), _));
+ EXPECT_CALL(mock_foreign_sessions_updated_callback(), Run());
+
+ bridge()->ScheduleGarbageCollection();
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace
+} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.cc b/chromium/components/sync_sessions/sessions_sync_manager.cc
index dacbe0d493f..e3c428a0adb 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager.cc
@@ -86,13 +86,30 @@ class SyncChangeListWriteBatch
SyncChangeListWriteBatch(
const std::string& machine_tag,
const std::string& session_name,
+ const std::set<int>& known_tab_node_ids,
base::OnceCallback<void(const syncer::SyncChangeList&)> commit_cb)
: machine_tag_(machine_tag),
session_name_(session_name),
+ known_tab_node_ids_(known_tab_node_ids),
commit_cb_(std::move(commit_cb)) {}
syncer::SyncChangeList* sync_change_list() { return &changes_; }
+ void AddKnownTabNodeIds(const std::set<int>& known_tab_node_ids) {
+ known_tab_node_ids_.insert(known_tab_node_ids.begin(),
+ known_tab_node_ids.end());
+ }
+
+ void PutWithType(std::unique_ptr<sync_pb::SessionSpecifics> specifics,
+ SyncChange::SyncChangeType change_type) {
+ sync_pb::EntitySpecifics entity_specifics;
+ specifics->Swap(entity_specifics.mutable_session());
+ changes_.push_back(SyncChange(
+ FROM_HERE, change_type,
+ SyncData::CreateLocalData(TagFromSpecifics(entity_specifics.session()),
+ session_name_, entity_specifics)));
+ }
+
// WriteBatch implementation.
void Delete(int tab_node_id) override {
changes_.push_back(syncer::SyncChange(
@@ -101,24 +118,13 @@ class SyncChangeListWriteBatch
syncer::SESSIONS)));
}
- void Add(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
- sync_pb::EntitySpecifics entity_specifics;
- specifics->Swap(entity_specifics.mutable_session());
- changes_.push_back(
- syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD,
- syncer::SyncData::CreateLocalData(
- TagFromSpecifics(entity_specifics.session()),
- session_name_, entity_specifics)));
- }
+ void Put(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
+ bool new_entity =
+ specifics->tab_node_id() != TabNodePool::kInvalidTabNodeID &&
+ known_tab_node_ids_.insert(specifics->tab_node_id()).second;
- void Update(std::unique_ptr<sync_pb::SessionSpecifics> specifics) override {
- sync_pb::EntitySpecifics entity_specifics;
- specifics->Swap(entity_specifics.mutable_session());
- changes_.push_back(
- syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_UPDATE,
- syncer::SyncData::CreateLocalData(
- TagFromSpecifics(entity_specifics.session()),
- session_name_, entity_specifics)));
+ PutWithType(std::move(specifics), new_entity ? SyncChange::ACTION_ADD
+ : SyncChange::ACTION_UPDATE);
}
void Commit() override { std::move(commit_cb_).Run(changes_); }
@@ -126,6 +132,7 @@ class SyncChangeListWriteBatch
private:
const std::string machine_tag_;
const std::string session_name_;
+ std::set<int> known_tab_node_ids_;
base::OnceCallback<void(const syncer::SyncChangeList&)> commit_cb_;
syncer::SyncChangeList changes_;
};
@@ -136,7 +143,7 @@ class SyncChangeListWriteBatch
// lifetime of SessionSyncManager.
SessionsSyncManager::SessionsSyncManager(
sync_sessions::SyncSessionsClient* sessions_client,
- syncer::SyncPrefs* sync_prefs,
+ syncer::SessionSyncPrefs* sync_prefs,
LocalDeviceInfoProvider* local_device,
const base::RepeatingClosure& sessions_updated_callback)
: sessions_client_(sessions_client),
@@ -166,6 +173,25 @@ static std::string BuildMachineTag(const std::string& cache_guid) {
return machine_tag;
}
+void SessionsSyncManager::ScheduleGarbageCollection() {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&SessionsSyncManager::DoGarbageCollection,
+ base::AsWeakPtr(this)));
+}
+
+void SessionsSyncManager::OnSessionRestoreComplete() {
+ // Do nothing. The very same event is plumbed manually to
+ // SessionDataTypeController by ProfileSyncComponentsFactoryImpl.
+}
+
+syncer::SyncableService* SessionsSyncManager::GetSyncableService() {
+ return this;
+}
+
+syncer::ModelTypeSyncBridge* SessionsSyncManager::GetModelTypeSyncBridge() {
+ return nullptr;
+}
+
syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
syncer::ModelType type,
const syncer::SyncDataList& initial_sync_data,
@@ -213,6 +239,7 @@ syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
// SyncChangeListWriteBatch. Ideally InitFromSyncModel() could use the
// WriteBatch API as well.
SyncChangeListWriteBatch batch(current_machine_tag(), current_session_name_,
+ /*known_tab_node_ids=*/{},
/*commit_cb=*/base::DoNothing());
// First, we iterate over sync data to update our session_tracker_.
@@ -223,9 +250,12 @@ syncer::SyncMergeResult SessionsSyncManager::MergeDataAndStartSyncing(
sync_pb::SessionHeader* header_s = specifics->mutable_header();
header_s->set_client_name(current_session_name_);
header_s->set_device_type(local_device_info->device_type());
- batch.Add(std::move(specifics));
+ batch.PutWithType(std::move(specifics), SyncChange::ACTION_ADD);
}
+ batch.AddKnownTabNodeIds(
+ session_tracker_.LookupTabNodeIds(current_machine_tag()));
+
#if defined(OS_ANDROID)
std::string sync_machine_tag(
BuildMachineTag(local_device_->GetLocalSyncCacheGUID()));
@@ -588,6 +618,8 @@ std::unique_ptr<LocalSessionEventHandlerImpl::WriteBatch>
SessionsSyncManager::CreateLocalSessionWriteBatch() {
return std::make_unique<SyncChangeListWriteBatch>(
current_machine_tag(), current_session_name_,
+ /*known_tab_node_ids=*/
+ session_tracker_.LookupTabNodeIds(current_machine_tag()),
/*commit_cb=*/
base::BindOnce(&SessionsSyncManager::ProcessLocalSessionSyncChanges,
base::AsWeakPtr(this)));
diff --git a/chromium/components/sync_sessions/sessions_sync_manager.h b/chromium/components/sync_sessions/sessions_sync_manager.h
index 0a0c41e74f2..106104f978a 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager.h
+++ b/chromium/components/sync_sessions/sessions_sync_manager.h
@@ -24,6 +24,7 @@
#include "components/sync/base/sync_prefs.h"
#include "components/sync/device_info/device_info.h"
#include "components/sync/model/syncable_service.h"
+#include "components/sync_sessions/abstract_sessions_sync_manager.h"
#include "components/sync_sessions/favicon_cache.h"
#include "components/sync_sessions/local_session_event_handler_impl.h"
#include "components/sync_sessions/lost_navigations_recorder.h"
@@ -35,7 +36,6 @@
namespace syncer {
class LocalDeviceInfoProvider;
class SyncErrorFactory;
-class SyncPrefs;
} // namespace syncer
namespace sync_pb {
@@ -51,15 +51,25 @@ namespace sync_sessions {
// Contains all logic for associating the Chrome sessions model and
// the sync sessions model.
-class SessionsSyncManager : public syncer::SyncableService,
+class SessionsSyncManager : public AbstractSessionsSyncManager,
+ public syncer::SyncableService,
public LocalSessionEventHandlerImpl::Delegate {
public:
SessionsSyncManager(SyncSessionsClient* sessions_client,
- syncer::SyncPrefs* sync_prefs,
+ syncer::SessionSyncPrefs* sync_prefs,
syncer::LocalDeviceInfoProvider* local_device,
const base::RepeatingClosure& sessions_updated_callback);
~SessionsSyncManager() override;
+ // AbstractSessionsSyncManager implementation.
+ void ScheduleGarbageCollection() override;
+ FaviconCache* GetFaviconCache() override;
+ SessionsGlobalIdMapper* GetGlobalIdMapper() override;
+ OpenTabsUIDelegate* GetOpenTabsUIDelegate() override;
+ void OnSessionRestoreComplete() override;
+ syncer::SyncableService* GetSyncableService() override;
+ syncer::ModelTypeSyncBridge* GetModelTypeSyncBridge() override;
+
// syncer::SyncableService implementation.
syncer::SyncMergeResult MergeDataAndStartSyncing(
syncer::ModelType type,
@@ -79,8 +89,6 @@ class SessionsSyncManager : public syncer::SyncableService,
void OnPageFaviconUpdated(const GURL& page_url) override;
void OnFaviconVisited(const GURL& page_url, const GURL& favicon_url) override;
- FaviconCache* GetFaviconCache();
-
// Returns the tag used to uniquely identify this machine's session in the
// sync model.
const std::string& current_machine_tag() const {
@@ -97,10 +105,6 @@ class SessionsSyncManager : public syncer::SyncableService,
// sessions data downloaded (sync cycles complete).
void DoGarbageCollection();
- SessionsGlobalIdMapper* GetGlobalIdMapper();
-
- OpenTabsUIDelegate* GetOpenTabsUIDelegate();
-
private:
friend class extensions::ExtensionSessionsTest;
friend class SessionsSyncManagerTest;
@@ -187,7 +191,7 @@ class SessionsSyncManager : public syncer::SyncableService,
// proves that we are still relevant.
bool local_tab_pool_out_of_sync_;
- syncer::SyncPrefs* sync_prefs_;
+ syncer::SessionSyncPrefs* sync_prefs_;
std::unique_ptr<syncer::SyncErrorFactory> error_handler_;
std::unique_ptr<syncer::SyncChangeProcessor> sync_processor_;
diff --git a/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc b/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
index 20f0ea28147..4c788a67550 100644
--- a/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
+++ b/chromium/components/sync_sessions/sessions_sync_manager_unittest.cc
@@ -214,10 +214,6 @@ class SessionsSyncManagerTest : public testing::Test {
return local_device_->GetLocalDeviceInfo();
}
- TabNodePool* GetTabPool() {
- return &manager()->session_tracker_.local_tab_pool_;
- }
-
SessionsSyncManager* manager() { return manager_.get(); }
SessionSyncTestHelper* helper() { return &helper_; }
LocalDeviceInfoProviderMock* local_device() { return local_device_.get(); }
@@ -569,7 +565,7 @@ TEST_F(SessionsSyncManagerTest, ConflictingSyncIdsWithPlaceholder) {
InitWithSyncDataTakeOutput(ConvertToRemote(in), &out);
ASSERT_TRUE(ChangeTypeMatches(
- out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
+ out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE}));
VerifyLocalTabChange(out[0], 1, kBar1);
VerifyLocalHeaderChange(out[1], 1, 1);
}
@@ -602,8 +598,8 @@ TEST_F(SessionsSyncManagerTest, ConflictingSyncIdsBothReal) {
VerifyLocalTabChange(out[2], 1, kBar1);
VerifyLocalHeaderChange(out[3], 1, 2);
- // The sync ids should have been fixed.
- EXPECT_NE(dupe_sync_id,
+ // The sync ids should have been fixed for exactly one of the two tabs.
+ EXPECT_EQ(dupe_sync_id,
out[1].sync_data().GetSpecifics().session().tab_node_id());
EXPECT_NE(dupe_sync_id,
out[2].sync_data().GetSpecifics().session().tab_node_id());
@@ -1016,11 +1012,13 @@ TEST_F(SessionsSyncManagerTest, ProcessRemoteDeleteOfLocalSession) {
VerifyLocalHeaderChange(out[3], 1, 1);
// Verify TabLinks.
- EXPECT_EQ(1U, GetTabPool()->Capacity());
- EXPECT_TRUE(GetTabPool()->Empty());
int tab_node_id = out[2].sync_data().GetSpecifics().session().tab_node_id();
int tab_id = out[2].sync_data().GetSpecifics().session().tab().tab_id();
- EXPECT_EQ(tab_id, GetTabPool()->GetTabIdFromTabNodeId(tab_node_id).id());
+ EXPECT_EQ(tab_id, manager()
+ ->session_tracker_
+ .LookupTabIdFromTabNodeId(
+ manager()->current_machine_tag(), tab_node_id)
+ .id());
}
// Test that receiving a session delete from sync removes the session
@@ -2053,10 +2051,9 @@ TEST_F(SessionsSyncManagerTest, PlaceholderConflictAcrossWindows) {
// The two tabs have the same sync id, which is not allowed. They will have
// their ids stripped and re-generated. But the placeholder cannot survive
- // this and will not show up in results. Because we have potentially new sync
- // ids, the essentially re-created tab will be an ADD.
+ // this and will not show up in results.
ASSERT_TRUE(ChangeTypeMatches(
- out, {SyncChange::ACTION_ADD, SyncChange::ACTION_UPDATE}));
+ out, {SyncChange::ACTION_UPDATE, SyncChange::ACTION_UPDATE}));
VerifyLocalHeaderChange(out[1], 1, 1);
VerifyLocalTabChange(out[0], 1, kFoo1);
EXPECT_EQ(tab1->GetSessionId().id(),
diff --git a/chromium/components/sync_sessions/synced_session_tracker.cc b/chromium/components/sync_sessions/synced_session_tracker.cc
index 3b003a75d52..ad682bf59e0 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker.cc
@@ -153,17 +153,14 @@ const std::string& SyncedSessionTracker::GetLocalSessionTag() const {
return local_session_tag_;
}
+std::vector<const SyncedSession*> SyncedSessionTracker::LookupAllSessions(
+ SessionLookup lookup) const {
+ return LookupSessions(lookup, /*exclude_local_session=*/false);
+}
+
std::vector<const SyncedSession*>
SyncedSessionTracker::LookupAllForeignSessions(SessionLookup lookup) const {
- std::vector<const SyncedSession*> sessions;
- for (const auto& session_pair : session_map_) {
- const SyncedSession& foreign_session = session_pair.second.synced_session;
- if (session_pair.first != local_session_tag_ &&
- (lookup == RAW || IsPresentable(sessions_client_, foreign_session))) {
- sessions.push_back(&foreign_session);
- }
- }
- return sessions;
+ return LookupSessions(lookup, /*exclude_local_session=*/true);
}
bool SyncedSessionTracker::LookupSessionWindows(
@@ -202,7 +199,19 @@ const sessions::SessionTab* SyncedSessionTracker::LookupSessionTab(
std::set<int> SyncedSessionTracker::LookupTabNodeIds(
const std::string& session_tag) const {
const TrackedSession* session = LookupTrackedSession(session_tag);
- return session ? session->tab_node_ids : std::set<int>();
+ return session ? session->tab_node_pool.GetAllTabNodeIds() : std::set<int>();
+}
+
+std::vector<const sessions::SessionTab*>
+SyncedSessionTracker::LookupUnmappedTabs(const std::string& session_tag) const {
+ const TrackedSession* session = LookupTrackedSession(session_tag);
+ std::vector<const sessions::SessionTab*> unmapped_tabs;
+ if (session) {
+ for (const auto& unmapped_tab_entry : session->unmapped_tabs) {
+ unmapped_tabs.push_back(unmapped_tab_entry.second.get());
+ }
+ }
+ return unmapped_tabs;
}
const SyncedSession* SyncedSessionTracker::LookupLocalSession() const {
@@ -264,7 +273,7 @@ void SyncedSessionTracker::DeleteForeignTab(const std::string& session_tag,
DCHECK_NE(local_session_tag_, session_tag);
TrackedSession* session = LookupTrackedSession(session_tag);
if (session)
- session->tab_node_ids.erase(tab_node_id);
+ session->tab_node_pool.DeleteTabNode(tab_node_id);
}
const SyncedSessionTracker::TrackedSession*
@@ -295,6 +304,23 @@ SyncedSessionTracker::TrackedSession* SyncedSessionTracker::GetTrackedSession(
return session;
}
+std::vector<const SyncedSession*> SyncedSessionTracker::LookupSessions(
+ SessionLookup lookup,
+ bool exclude_local_session) const {
+ std::vector<const SyncedSession*> sessions;
+ for (const auto& session_pair : session_map_) {
+ const SyncedSession& session = session_pair.second.synced_session;
+ if (lookup == PRESENTABLE && !IsPresentable(sessions_client_, session)) {
+ continue;
+ }
+ if (exclude_local_session && session_pair.first == local_session_tag_) {
+ continue;
+ }
+ sessions.push_back(&session);
+ }
+ return sessions;
+}
+
void SyncedSessionTracker::CleanupSessionImpl(const std::string& session_tag) {
TrackedSession* session = LookupTrackedSession(session_tag);
if (!session)
@@ -411,9 +437,15 @@ void SyncedSessionTracker::PutTabInWindow(const std::string& session_tag,
}
void SyncedSessionTracker::OnTabNodeSeen(const std::string& session_tag,
- int tab_node_id) {
- if (tab_node_id != TabNodePool::kInvalidTabNodeID) {
- GetTrackedSession(session_tag)->tab_node_ids.insert(tab_node_id);
+ int tab_node_id,
+ SessionID tab_id) {
+ // TODO(mastiz): Revisit if the exception for |local_session_tag_| can be
+ // avoided and treat all sessions equally, which ideally involves merging this
+ // function with ReassociateLocalTab().
+ if (session_tag != local_session_tag_ &&
+ tab_node_id != TabNodePool::kInvalidTabNodeID) {
+ GetTrackedSession(session_tag)
+ ->tab_node_pool.ReassociateTabNode(tab_node_id, tab_id);
}
}
@@ -463,35 +495,38 @@ void SyncedSessionTracker::CleanupLocalTabs(std::set<int>* deleted_node_ids) {
DCHECK(!local_session_tag_.empty());
TrackedSession* session = GetTrackedSession(local_session_tag_);
for (const auto& tab_pair : session->unmapped_tabs)
- local_tab_pool_.FreeTab(tab_pair.first);
+ session->tab_node_pool.FreeTab(tab_pair.first);
CleanupSessionImpl(local_session_tag_);
- local_tab_pool_.CleanupTabNodes(deleted_node_ids);
- for (int tab_node_id : *deleted_node_ids) {
- session->tab_node_ids.erase(tab_node_id);
- }
+ session->tab_node_pool.CleanupTabNodes(deleted_node_ids);
+}
+
+int SyncedSessionTracker::LookupTabNodeFromTabId(const std::string& session_tag,
+ SessionID tab_id) const {
+ const TrackedSession* session = LookupTrackedSession(session_tag);
+ DCHECK(session);
+ return session->tab_node_pool.GetTabNodeIdFromTabId(tab_id);
}
-bool SyncedSessionTracker::GetTabNodeFromLocalTabId(SessionID tab_id,
- int* tab_node_id) {
+SessionID SyncedSessionTracker::LookupTabIdFromTabNodeId(
+ const std::string& session_tag,
+ int tab_node_id) const {
+ const TrackedSession* session = LookupTrackedSession(session_tag);
+ DCHECK(session);
+ return session->tab_node_pool.GetTabIdFromTabNodeId(tab_node_id);
+}
+
+int SyncedSessionTracker::AssociateLocalTabWithFreeTabNode(SessionID tab_id) {
DCHECK(!local_session_tag_.empty());
+ TrackedSession* session = GetTrackedSession(local_session_tag_);
+
// Ensure a placeholder SessionTab is in place, if not already. Although we
// don't need a SessionTab to fulfill this request, this forces the creation
// of one if it doesn't already exist. This helps to make sure we're tracking
- // this |tab_id| if |local_tab_pool_| is, and everyone's data structures are
- // kept in sync and as consistent as possible.
+ // this |tab_id| if TabNodePool is, and everyone's data structures are kept in
+ // sync and as consistent as possible.
GetTab(local_session_tag_, tab_id); // Ignore result.
- bool reused_existing_tab =
- local_tab_pool_.GetTabNodeForTab(tab_id, tab_node_id);
- DCHECK_NE(TabNodePool::kInvalidTabNodeID, *tab_node_id);
- GetTrackedSession(local_session_tag_)->tab_node_ids.insert(*tab_node_id);
- return reused_existing_tab;
-}
-
-bool SyncedSessionTracker::IsLocalTabNodeAssociated(int tab_node_id) {
- if (tab_node_id == TabNodePool::kInvalidTabNodeID)
- return false;
- return local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id).is_valid();
+ return session->tab_node_pool.AssociateWithFreeTabNode(tab_id);
}
void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
@@ -503,12 +538,13 @@ void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
TrackedSession* session = LookupTrackedSession(local_session_tag_);
DCHECK(session);
- SessionID old_tab_id = local_tab_pool_.GetTabIdFromTabNodeId(tab_node_id);
+ SessionID old_tab_id =
+ session->tab_node_pool.GetTabIdFromTabNodeId(tab_node_id);
if (new_tab_id == old_tab_id) {
return;
}
- local_tab_pool_.ReassociateTabNode(tab_node_id, new_tab_id);
+ session->tab_node_pool.ReassociateTabNode(tab_node_id, new_tab_id);
sessions::SessionTab* tab_ptr = nullptr;
@@ -577,12 +613,10 @@ void SyncedSessionTracker::ReassociateLocalTab(int tab_node_id,
// Add the tab back into the tab map with the new id.
session->synced_tab_map[new_tab_id] = tab_ptr;
- session->tab_node_ids.insert(tab_node_id);
}
void SyncedSessionTracker::Clear() {
session_map_.clear();
- local_tab_pool_.Clear();
local_session_tag_.clear();
}
@@ -652,7 +686,7 @@ void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics,
// is currently kInvalidTabNodeID.
//
// In both cases, we can safely throw it into the set of node ids.
- tracker->OnTabNodeSeen(session_tag, specifics.tab_node_id());
+ tracker->OnTabNodeSeen(session_tag, specifics.tab_node_id(), tab_id);
sessions::SessionTab* tab = tracker->GetTab(session_tag, tab_id);
if (!tab->timestamp.is_null() && tab->timestamp > modification_time) {
DVLOG(1) << "Ignoring " << session_tag << "'s session tab " << tab_id
@@ -673,4 +707,90 @@ void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics,
}
}
+void SerializeTrackerToSpecifics(
+ const SyncedSessionTracker& tracker,
+ const base::RepeatingCallback<void(const std::string& session_name,
+ sync_pb::SessionSpecifics* specifics)>&
+ output_cb) {
+ std::map<std::string, std::set<int>> session_tag_to_node_ids;
+ for (const SyncedSession* session :
+ tracker.LookupAllSessions(SyncedSessionTracker::RAW)) {
+ // Request all tabs.
+ session_tag_to_node_ids[session->session_tag] =
+ tracker.LookupTabNodeIds(session->session_tag);
+ // Request the header too.
+ session_tag_to_node_ids[session->session_tag].insert(
+ TabNodePool::kInvalidTabNodeID);
+ }
+ SerializePartialTrackerToSpecifics(tracker, session_tag_to_node_ids,
+ output_cb);
+}
+
+void SerializePartialTrackerToSpecifics(
+ const SyncedSessionTracker& tracker,
+ const std::map<std::string, std::set<int>>& session_tag_to_node_ids,
+ const base::RepeatingCallback<void(const std::string& session_name,
+ sync_pb::SessionSpecifics* specifics)>&
+ output_cb) {
+ for (const auto& session_entry : session_tag_to_node_ids) {
+ const std::string& session_tag = session_entry.first;
+ const SyncedSession* session = tracker.LookupSession(session_tag);
+ if (!session) {
+ // Unknown session.
+ continue;
+ }
+
+ const std::set<int> known_tab_node_ids =
+ tracker.LookupTabNodeIds(session_tag);
+
+ for (int tab_node_id : session_entry.second) {
+ // Header entity.
+ if (tab_node_id == TabNodePool::kInvalidTabNodeID) {
+ sync_pb::SessionSpecifics header_pb;
+ header_pb.set_session_tag(session_tag);
+ session->ToSessionHeaderProto().Swap(header_pb.mutable_header());
+ output_cb.Run(session->session_name, &header_pb);
+ continue;
+ }
+
+ // Check if |tab_node_id| is known by the tracker.
+ if (known_tab_node_ids.count(tab_node_id) == 0) {
+ continue;
+ }
+
+ // Tab entities.
+ const SessionID tab_id =
+ tracker.LookupTabIdFromTabNodeId(session_tag, tab_node_id);
+ if (!tab_id.is_valid()) {
+ // This can be the case for tabs that were unmapped because we received
+ // a new foreign tab with the same tab ID (the last one wins), so we
+ // don't remember the tab ID for the original |tab_node_id|. Instead of
+ // returning partially populated SessionSpecifics (without tab ID), we
+ // simply drop them, because older clients don't handle well such
+ // invalid specifics.
+ continue;
+ }
+
+ const sessions::SessionTab* tab =
+ tracker.LookupSessionTab(session_tag, tab_id);
+ if (tab) {
+ // Associated/mapped tab node.
+ sync_pb::SessionSpecifics tab_pb;
+ tab_pb.set_session_tag(session_tag);
+ tab_pb.set_tab_node_id(tab_node_id);
+ tab->ToSyncData().Swap(tab_pb.mutable_tab());
+ output_cb.Run(session->session_name, &tab_pb);
+ continue;
+ }
+
+ // Create entities for unmapped tabs nodes.
+ sync_pb::SessionSpecifics tab_pb;
+ tab_pb.set_tab_node_id(tab_node_id);
+ tab_pb.set_session_tag(session_tag);
+ tab_pb.mutable_tab()->set_tab_id(tab_id.id());
+ output_cb.Run(session->session_name, &tab_pb);
+ }
+ }
+}
+
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/synced_session_tracker.h b/chromium/components/sync_sessions/synced_session_tracker.h
index 8b823bd5500..24dac10ad45 100644
--- a/chromium/components/sync_sessions/synced_session_tracker.h
+++ b/chromium/components/sync_sessions/synced_session_tracker.h
@@ -46,6 +46,12 @@ class SyncedSessionTracker {
// **** Synced session/tab query methods. ****
+ // Returns vector with all sessions we're tracking. SyncedSession ownership
+ // remains within the SyncedSessionTracker. Lookup parameter is used to decide
+ // which tabs should be included.
+ std::vector<const SyncedSession*> LookupAllSessions(
+ SessionLookup lookup) const;
+
// Returns all foreign sessions we're tracking (skips the local session
// object). SyncedSession ownership remains within the SyncedSessionTracker.
// Lookup parameter is used to decide which foreign tabs should be include.
@@ -56,6 +62,10 @@ class SyncedSessionTracker {
// session having tag |session_tag|.
std::set<int> LookupTabNodeIds(const std::string& session_tag) const;
+ // Returns tabs that are unmapped for session with tag |session_tag|.
+ std::vector<const sessions::SessionTab*> LookupUnmappedTabs(
+ const std::string& session_tag) const;
+
// Attempts to look up the session windows associatd with the session given
// by |session_tag|. Ownership of SessionWindows stays within the
// SyncedSessionTracker.
@@ -126,7 +136,9 @@ class SyncedSessionTracker {
// tag is passed. The tab pool is only updated with new tab nodes when they're
// associated with a tab id (see ReassociateLocalTabNode or
// GetTabNodeFromLocalTabId).
- void OnTabNodeSeen(const std::string& session_tag, int tab_node_id);
+ void OnTabNodeSeen(const std::string& session_tag,
+ int tab_node_id,
+ SessionID tab_id);
// Returns a pointer to the SessionTab object associated with
// |tab_id| for the session specified with |session_tag|.
@@ -167,14 +179,19 @@ class SyncedSessionTracker {
// free tab nodes to be deleted.
void CleanupLocalTabs(std::set<int>* deleted_node_ids);
- // Fills |tab_node_id| with a tab node for |tab_id|. Returns true if an
- // existing tab node was found, false if there was none and one had to be
- // created.
- bool GetTabNodeFromLocalTabId(SessionID tab_id, int* tab_node_id);
+ // Returns the tab node ID for |tab_id| if an existing tab node was found, or
+ // kInvalidTabNodeID otherwise.
+ int LookupTabNodeFromTabId(const std::string& session_tag,
+ SessionID tab_id) const;
- // Returns whether |tab_node_id| refers to a valid tab node that is associated
- // with a tab.
- bool IsLocalTabNodeAssociated(int tab_node_id);
+ // Returns the tab ID associated to |tab_node_id| or SessionID::InvalidValue()
+ // if not associated.
+ SessionID LookupTabIdFromTabNodeId(const std::string& session_tag,
+ int tab_node_id) const;
+
+ // Returns a valid tab node for |tab_id|. Will reuse an existing tab node if
+ // possible, and otherwise create a new one.
+ int AssociateLocalTabWithFreeTabNode(SessionID tab_id);
// Reassociates the tab denoted by |tab_node_id| with a new tab id, preserving
// any previous SessionTab object the node was associated with. This is useful
@@ -210,7 +227,6 @@ class SyncedSessionTracker {
bool IsTabUnmappedForTesting(SessionID tab_id);
private:
- friend class SessionsSyncManagerTest;
friend class SyncedSessionTrackerTest;
struct TrackedSession {
@@ -236,15 +252,9 @@ class SyncedSessionTracker {
std::map<SessionID, std::unique_ptr<sessions::SessionTab>> unmapped_tabs;
std::map<SessionID, std::unique_ptr<SyncedSessionWindow>> unmapped_windows;
- // A tab node id is part of the identifier for the sync tab objects. Tab
- // node ids are not used for interacting with the model/browser tabs.
- // However, when when we want to delete a foreign session, we use these
- // values to inform sync which tabs to delete. We are extracting these tab
- // node ids from individual session (tab, not header) specifics, but store
- // them here during runtime. We do this because tab node ids may be reused
- // for different tabs, and tracking which tab id is currently associated
- // with each tab node id is both difficult and unnecessary.
- std::set<int> tab_node_ids;
+ // Mappings between tab node IDs and tab IDs. For the local session, it also
+ // knows about available sync nodes associated with this session.
+ TabNodePool tab_node_pool;
};
// LookupTrackedSession() returns null if the session tag is unknown.
@@ -254,6 +264,10 @@ class SyncedSessionTracker {
// Creates tracked session if it wasn't known previously. Never returns null.
TrackedSession* GetTrackedSession(const std::string& session_tag);
+ std::vector<const SyncedSession*> LookupSessions(
+ SessionLookup lookup,
+ bool exclude_local_session) const;
+
// Implementation of CleanupForeignSession/CleanupLocalTabs.
void CleanupSessionImpl(const std::string& session_tag);
@@ -267,9 +281,6 @@ class SyncedSessionTracker {
// sessions.
std::string local_session_tag_;
- // Pool of used/available sync nodes associated with local tabs.
- TabNodePool local_tab_pool_;
-
DISALLOW_COPY_AND_ASSIGN(SyncedSessionTracker);
};
@@ -279,6 +290,25 @@ void UpdateTrackerWithSpecifics(const sync_pb::SessionSpecifics& specifics,
base::Time modification_time,
SyncedSessionTracker* tracker);
+// Generates all sync entities represented by the tracker. Instead of returning
+// protos by value, |output_cb| is run for each serialized entity.
+void SerializeTrackerToSpecifics(
+ const SyncedSessionTracker& tracker,
+ const base::RepeatingCallback<void(const std::string& session_name,
+ sync_pb::SessionSpecifics* specifics)>&
+ output_cb);
+
+// Same as above but generates a subset of sync entities represented by the
+// tracker, as selected by |session_tag_to_node_ids|. Unknown session tags or
+// node IDs will be ignored. kInvalidTabNodeID can be used to request header
+// entities.
+void SerializePartialTrackerToSpecifics(
+ const SyncedSessionTracker& tracker,
+ const std::map<std::string, std::set<int>>& session_tag_to_node_ids,
+ const base::RepeatingCallback<void(const std::string& session_name,
+ sync_pb::SessionSpecifics* specifics)>&
+ output_cb);
+
} // namespace sync_sessions
#endif // COMPONENTS_SYNC_SESSIONS_SYNCED_SESSION_TRACKER_H_
diff --git a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
index e1f496b1712..e6a7aeb7f0e 100644
--- a/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
+++ b/chromium/components/sync_sessions/synced_session_tracker_unittest.cc
@@ -7,6 +7,7 @@
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/test/mock_callback.h"
#include "components/sessions/core/serialized_navigation_entry_test_helper.h"
#include "components/sync_sessions/mock_sync_sessions_client.h"
#include "components/sync_sessions/synced_tab_delegate.h"
@@ -19,7 +20,10 @@ using testing::AssertionSuccess;
using testing::ElementsAre;
using testing::IsEmpty;
using testing::IsNull;
+using testing::Ne;
using testing::NotNull;
+using testing::Pointee;
+using testing::_;
namespace sync_sessions {
@@ -36,6 +40,8 @@ const char kTitle[] = "title";
const int kTabNode1 = 1;
const int kTabNode2 = 2;
const int kTabNode3 = 3;
+const int kTabNode4 = 4;
+const int kTabNode5 = 5;
const SessionID kWindow1 = SessionID::FromSerializedValue(1);
const SessionID kWindow2 = SessionID::FromSerializedValue(2);
const SessionID kWindow3 = SessionID::FromSerializedValue(3);
@@ -59,7 +65,18 @@ class SyncedSessionTrackerTest : public testing::Test {
~SyncedSessionTrackerTest() override {}
SyncedSessionTracker* GetTracker() { return &tracker_; }
- TabNodePool* GetTabNodePool() { return &tracker_.local_tab_pool_; }
+ TabNodePool* GetLocalTabNodePool() {
+ return &tracker_.LookupTrackedSession(tracker_.local_session_tag_)
+ ->tab_node_pool;
+ }
+
+ // Returns whether |tab_node_id| refers to a valid tab node that is associated
+ // with a tab.
+ bool IsLocalTabNodeAssociated(int tab_node_id) const {
+ return tracker_
+ .LookupTabIdFromTabNodeId(tracker_.local_session_tag_, tab_node_id)
+ .is_valid();
+ }
// Verify that each tab within a session is allocated one SessionTab object,
// and that that tab object is owned either by the Session itself or the
@@ -168,6 +185,44 @@ TEST_F(SyncedSessionTrackerTest, PutTabInWindow) {
// Should clean up memory on its own.
}
+TEST_F(SyncedSessionTrackerTest, LookupAllSessions) {
+ EXPECT_THAT(
+ GetTracker()->LookupAllSessions(SyncedSessionTracker::PRESENTABLE),
+ IsEmpty());
+
+ GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
+ GetTracker()->PutWindowInSession(kTag, kWindow1);
+ GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
+
+ EXPECT_THAT(GetTracker()->LookupAllSessions(SyncedSessionTracker::RAW),
+ ElementsAre(HasSessionTag(kTag)));
+ EXPECT_THAT(
+ GetTracker()->LookupAllSessions(SyncedSessionTracker::PRESENTABLE),
+ IsEmpty());
+
+ sessions::SessionTab* tab = GetTracker()->GetTab(kTag, kTab1);
+ ASSERT_TRUE(tab);
+ tab->navigations.push_back(
+ sessions::SerializedNavigationEntryTestHelper::CreateNavigation(kValidUrl,
+ kTitle));
+ EXPECT_THAT(
+ GetTracker()->LookupAllSessions(SyncedSessionTracker::PRESENTABLE),
+ ElementsAre(HasSessionTag(kTag)));
+
+ GetTracker()->GetSession(kTag2);
+ GetTracker()->PutWindowInSession(kTag2, kWindow1);
+ GetTracker()->PutTabInWindow(kTag2, kWindow1, kTab2);
+
+ sessions::SessionTab* tab2 = GetTracker()->GetTab(kTag2, kTab2);
+ ASSERT_TRUE(tab2);
+ tab2->navigations.push_back(
+ sessions::SerializedNavigationEntryTestHelper::CreateNavigation(kValidUrl,
+ kTitle));
+ EXPECT_THAT(
+ GetTracker()->LookupAllSessions(SyncedSessionTracker::PRESENTABLE),
+ ElementsAre(HasSessionTag(kTag), HasSessionTag(kTag2)));
+}
+
TEST_F(SyncedSessionTrackerTest, LookupAllForeignSessions) {
const char kInvalidUrl[] = "invalid.url";
ON_CALL(*GetSyncSessionsClient(), ShouldSyncURL(GURL(kInvalidUrl)))
@@ -311,8 +366,8 @@ TEST_F(SyncedSessionTrackerTest, ManyGetTabs) {
}
TEST_F(SyncedSessionTrackerTest, LookupTabNodeIds) {
- GetTracker()->OnTabNodeSeen(kTag, 1);
- GetTracker()->OnTabNodeSeen(kTag, 2);
+ GetTracker()->OnTabNodeSeen(kTag, 1, kTab1);
+ GetTracker()->OnTabNodeSeen(kTag, 2, kTab2);
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag), ElementsAre(1, 2));
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag2), IsEmpty());
@@ -320,11 +375,11 @@ TEST_F(SyncedSessionTrackerTest, LookupTabNodeIds) {
GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag), ElementsAre(1, 2));
- GetTracker()->OnTabNodeSeen(kTag, 3);
+ GetTracker()->OnTabNodeSeen(kTag, 3, kTab3);
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag), ElementsAre(1, 2, 3));
- GetTracker()->OnTabNodeSeen(kTag2, 21);
- GetTracker()->OnTabNodeSeen(kTag2, 22);
+ GetTracker()->OnTabNodeSeen(kTag2, 21, kTab4);
+ GetTracker()->OnTabNodeSeen(kTag2, 22, kTab5);
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag2), ElementsAre(21, 22));
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag), ElementsAre(1, 2, 3));
@@ -339,14 +394,28 @@ TEST_F(SyncedSessionTrackerTest, LookupTabNodeIds) {
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag), IsEmpty());
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag2), ElementsAre(21, 22));
- GetTracker()->OnTabNodeSeen(kTag2, 21);
- GetTracker()->OnTabNodeSeen(kTag2, 23);
+ GetTracker()->OnTabNodeSeen(kTag2, 21, kTab6);
+ GetTracker()->OnTabNodeSeen(kTag2, 23, kTab7);
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag2), ElementsAre(21, 22, 23));
EXPECT_FALSE(GetTracker()->DeleteForeignSession(kTag2));
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag2), IsEmpty());
}
+TEST_F(SyncedSessionTrackerTest, LookupUnmappedTabs) {
+ EXPECT_THAT(GetTracker()->LookupUnmappedTabs(kTag), IsEmpty());
+
+ sessions::SessionTab* tab = GetTracker()->GetTab(kTag, kTab1);
+ ASSERT_THAT(tab, NotNull());
+
+ EXPECT_THAT(GetTracker()->LookupUnmappedTabs(kTag), ElementsAre(tab));
+ EXPECT_THAT(GetTracker()->LookupUnmappedTabs(kTag2), IsEmpty());
+
+ GetTracker()->PutWindowInSession(kTag, kWindow1);
+ GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
+ EXPECT_THAT(GetTracker()->LookupUnmappedTabs(kTag), IsEmpty());
+}
+
TEST_F(SyncedSessionTrackerTest, SessionTracking) {
ASSERT_TRUE(GetTracker()->Empty());
@@ -413,8 +482,8 @@ TEST_F(SyncedSessionTrackerTest, DeleteForeignTab) {
int tab_node_id_2 = 2;
std::set<int> result;
- GetTracker()->OnTabNodeSeen(kTag, tab_node_id_1);
- GetTracker()->OnTabNodeSeen(kTag, tab_node_id_2);
+ GetTracker()->OnTabNodeSeen(kTag, tab_node_id_1, kTab1);
+ GetTracker()->OnTabNodeSeen(kTag, tab_node_id_2, kTab2);
EXPECT_THAT(GetTracker()->LookupTabNodeIds(kTag),
ElementsAre(tab_node_id_1, tab_node_id_2));
@@ -429,59 +498,58 @@ TEST_F(SyncedSessionTrackerTest, DeleteForeignTab) {
TEST_F(SyncedSessionTrackerTest, CleanupLocalTabs) {
std::set<int> free_node_ids;
- int tab_node_id = TabNodePool::kInvalidTabNodeID;
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
// Start with two restored tab nodes.
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
GetTracker()->ReassociateLocalTab(kTabNode2, kTab2);
- EXPECT_TRUE(GetTabNodePool()->Empty());
- EXPECT_FALSE(GetTabNodePool()->Full());
- EXPECT_EQ(2U, GetTabNodePool()->Capacity());
+ EXPECT_TRUE(GetLocalTabNodePool()->Empty());
+ EXPECT_FALSE(GetLocalTabNodePool()->Full());
+ EXPECT_EQ(2U, GetLocalTabNodePool()->Capacity());
// Associate with no tabs. The tab pool should now be full.
GetTracker()->ResetSessionTracking(kTag);
GetTracker()->CleanupLocalTabs(&free_node_ids);
EXPECT_TRUE(free_node_ids.empty());
- EXPECT_TRUE(GetTabNodePool()->Full());
+ EXPECT_TRUE(GetLocalTabNodePool()->Full());
// Associate with only 1 tab open. A tab node should be reused.
GetTracker()->ResetSessionTracking(kTag);
GetTracker()->PutWindowInSession(kTag, kWindow1);
GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
- EXPECT_TRUE(GetTracker()->GetTabNodeFromLocalTabId(kTab1, &tab_node_id));
+ EXPECT_EQ(kTabNode1, GetTracker()->AssociateLocalTabWithFreeTabNode(kTab1));
GetTracker()->CleanupLocalTabs(&free_node_ids);
EXPECT_TRUE(free_node_ids.empty());
// TabNodePool should have one free tab node and one used.
- EXPECT_EQ(2U, GetTabNodePool()->Capacity());
- EXPECT_FALSE(GetTabNodePool()->Empty());
- EXPECT_FALSE(GetTabNodePool()->Full());
+ EXPECT_EQ(2U, GetLocalTabNodePool()->Capacity());
+ EXPECT_FALSE(GetLocalTabNodePool()->Empty());
+ EXPECT_FALSE(GetLocalTabNodePool()->Full());
// Simulate a tab opening, which should use the last free tab node.
- EXPECT_TRUE(GetTracker()->GetTabNodeFromLocalTabId(kTab2, &tab_node_id));
- EXPECT_TRUE(GetTabNodePool()->Empty());
+ EXPECT_EQ(kTabNode2, GetTracker()->AssociateLocalTabWithFreeTabNode(kTab2));
+ EXPECT_EQ(kTabNode2, GetTracker()->LookupTabNodeFromTabId(kTag, kTab2));
+ EXPECT_TRUE(GetLocalTabNodePool()->Empty());
// Simulate another tab opening, which should create a new associated tab
// node.
- EXPECT_FALSE(GetTracker()->GetTabNodeFromLocalTabId(kTab3, &tab_node_id));
- EXPECT_EQ(kTabNode3, tab_node_id);
- EXPECT_EQ(3U, GetTabNodePool()->Capacity());
- EXPECT_TRUE(GetTabNodePool()->Empty());
+ EXPECT_EQ(kTabNode3, GetTracker()->AssociateLocalTabWithFreeTabNode(kTab3));
+ EXPECT_EQ(kTabNode3, GetTracker()->LookupTabNodeFromTabId(kTag, kTab3));
+ EXPECT_EQ(3U, GetLocalTabNodePool()->Capacity());
+ EXPECT_TRUE(GetLocalTabNodePool()->Empty());
- // Fetching the same tab should return the same tab node id.
- EXPECT_TRUE(GetTracker()->GetTabNodeFromLocalTabId(kTab3, &tab_node_id));
- EXPECT_EQ(kTabNode3, tab_node_id);
- EXPECT_TRUE(GetTabNodePool()->Empty());
+ // Previous tabs should still be associated.
+ EXPECT_EQ(kTabNode1, GetTracker()->LookupTabNodeFromTabId(kTag, kTab1));
+ EXPECT_EQ(kTabNode2, GetTracker()->LookupTabNodeFromTabId(kTag, kTab2));
// Associate with no tabs. All tabs should be freed again, and the pool
// should now be full.
GetTracker()->ResetSessionTracking(kTag);
GetTracker()->CleanupLocalTabs(&free_node_ids);
EXPECT_TRUE(free_node_ids.empty());
- EXPECT_TRUE(GetTabNodePool()->Full());
- EXPECT_FALSE(GetTabNodePool()->Empty());
+ EXPECT_TRUE(GetLocalTabNodePool()->Full());
+ EXPECT_FALSE(GetLocalTabNodePool()->Empty());
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -490,10 +558,10 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) {
// First create the tab normally.
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Map it to a window with the same tab id as it was created with.
@@ -512,7 +580,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) {
// Then reassociate with a new tab id.
GetTracker()->ReassociateLocalTab(kTabNode1, kTab2);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab2));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
@@ -532,7 +600,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMapped) {
session->windows.at(kWindow1)->wrapped_window.tabs[0].get());
ASSERT_EQ(GetTracker()->LookupTabNodeIds(kTag).size(),
GetTracker()->LookupTabNodeIds(kTag).count(kTabNode1));
- ASSERT_EQ(1U, GetTabNodePool()->Capacity());
+ ASSERT_EQ(1U, GetLocalTabNodePool()->Capacity());
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -541,10 +609,10 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMappedTwice) {
// First create the tab normally.
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Map it to a window with the same tab id as it was created with.
@@ -564,7 +632,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMappedTwice) {
// Then reassociate with a new tab id.
GetTracker()->ReassociateLocalTab(kTabNode1, kTab2);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab2));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
@@ -590,13 +658,13 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabMappedTwice) {
session->windows.at(kWindow1)->wrapped_window.tabs[1].get());
EXPECT_EQ(GetTracker()->LookupTabNodeIds(kTag).size(),
GetTracker()->LookupTabNodeIds(kTag).count(kTabNode1));
- EXPECT_EQ(1U, GetTabNodePool()->Capacity());
+ EXPECT_EQ(1U, GetLocalTabNodePool()->Capacity());
// Attempting to access the original tab will create a new SessionTab object.
EXPECT_NE(GetTracker()->GetTab(kTag, kTab1),
GetTracker()->GetTab(kTag, kTab2));
- int tab_node_id = -1;
- EXPECT_FALSE(GetTracker()->GetTabNodeFromLocalTabId(kTab1, &tab_node_id));
+ EXPECT_EQ(TabNodePool::kInvalidTabNodeID,
+ GetTracker()->LookupTabNodeFromTabId(kTag, kTab1));
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -605,17 +673,17 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabUnmapped) {
// First create the old tab in an unmapped state.
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Map it to a window, but reassociated with a new tab id.
GetTracker()->ResetSessionTracking(kTag);
GetTracker()->ReassociateLocalTab(kTabNode1, kTab2);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab2));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
GetTracker()->PutWindowInSession(kTag, kWindow1);
@@ -632,7 +700,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabUnmapped) {
session->windows.at(kWindow1)->wrapped_window.tabs[0].get());
ASSERT_EQ(GetTracker()->LookupTabNodeIds(kTag).size(),
GetTracker()->LookupTabNodeIds(kTag).count(kTabNode1));
- ASSERT_EQ(1U, GetTabNodePool()->Capacity());
+ ASSERT_EQ(1U, GetLocalTabNodePool()->Capacity());
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -641,16 +709,16 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabOldUnmappedNewMapped) {
// First create the old tab in an unmapped state.
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Map an unseen tab to a window, then reassociate the existing tab to the
// mapped tab id.
GetTracker()->ResetSessionTracking(kTag);
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->PutWindowInSession(kTag, kWindow1);
GetTracker()->PutTabInWindow(kTag, kWindow1, kTab2);
GetTracker()->CleanupLocalTabs(&free_node_ids);
@@ -670,7 +738,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabOldUnmappedNewMapped) {
session->windows.at(kWindow1)->wrapped_window.tabs[0].get());
ASSERT_EQ(GetTracker()->LookupTabNodeIds(kTag).size(),
GetTracker()->LookupTabNodeIds(kTag).count(kTabNode1));
- ASSERT_EQ(1U, GetTabNodePool()->Capacity());
+ ASSERT_EQ(1U, GetLocalTabNodePool()->Capacity());
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -679,10 +747,10 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabSameTabId) {
// First create the tab normally.
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Map it to a window.
@@ -701,7 +769,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabSameTabId) {
// Reassociate, using the same tab id.
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Reset tracking, and put the tab id back into the same window.
@@ -720,7 +788,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabSameTabId) {
session->windows.at(kWindow1)->wrapped_window.tabs[0].get());
ASSERT_EQ(GetTracker()->LookupTabNodeIds(kTag).size(),
GetTracker()->LookupTabNodeIds(kTag).count(kTabNode1));
- ASSERT_EQ(1U, GetTabNodePool()->Capacity());
+ ASSERT_EQ(1U, GetLocalTabNodePool()->Capacity());
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -729,10 +797,10 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabOldMappedNewUnmapped) {
// First create an unmapped tab.
GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode1));
GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab1));
// Now, map the first one, deleting the second one.
@@ -751,14 +819,14 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabOldMappedNewUnmapped) {
// Create a second unmapped tab.
GetTracker()->ReassociateLocalTab(kTabNode2, kTab2);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode2));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode2));
EXPECT_TRUE(GetTracker()->IsTabUnmappedForTesting(kTab2));
// Reassociate the second tab with node of the first tab.
GetTracker()->ReassociateLocalTab(kTabNode1, kTab2);
ASSERT_TRUE(VerifyTabIntegrity(kTag));
- EXPECT_TRUE(GetTracker()->IsLocalTabNodeAssociated(kTabNode1));
- EXPECT_FALSE(GetTracker()->IsLocalTabNodeAssociated(kTabNode2));
+ EXPECT_TRUE(IsLocalTabNodeAssociated(kTabNode1));
+ EXPECT_FALSE(IsLocalTabNodeAssociated(kTabNode2));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab1));
EXPECT_FALSE(GetTracker()->IsTabUnmappedForTesting(kTab2));
@@ -775,7 +843,7 @@ TEST_F(SyncedSessionTrackerTest, ReassociateTabOldMappedNewUnmapped) {
// GetSession as well as the GetTab.
ASSERT_EQ(GetTracker()->GetTab(kTag, kTab2),
session->windows.at(kWindow1)->wrapped_window.tabs[0].get());
- ASSERT_EQ(2U, GetTabNodePool()->Capacity());
+ ASSERT_EQ(2U, GetLocalTabNodePool()->Capacity());
ASSERT_TRUE(VerifyTabIntegrity(kTag));
}
@@ -925,4 +993,92 @@ TEST_F(SyncedSessionTrackerTest, UpdateTrackerWithTwoTabsSameId) {
EXPECT_EQ(true, tracked_tab->pinned);
}
+TEST_F(SyncedSessionTrackerTest, SerializeTrackerToSpecifics) {
+ GetTracker()->InitLocalSession(kTag, kSessionName, kDeviceType);
+ GetTracker()->PutWindowInSession(kTag, kWindow1);
+ GetTracker()->GetSession(kTag)->windows[kWindow1]->window_type =
+ sync_pb::SessionWindow_BrowserType_TYPE_TABBED;
+ GetTracker()->PutTabInWindow(kTag, kWindow1, kTab1);
+ GetTracker()->PutTabInWindow(kTag, kWindow1, kTab2);
+ // Unmapped tab.
+ GetTracker()->GetTab(kTag, kTab3);
+ // |kTabNode4| will be unassociated, because |kTab1| is associated twice.
+ GetTracker()->ReassociateLocalTab(kTabNode4, kTab1);
+ GetTracker()->ReassociateLocalTab(kTabNode1, kTab1);
+ // Regular associations.
+ GetTracker()->ReassociateLocalTab(kTabNode2, kTab2);
+ GetTracker()->ReassociateLocalTab(kTabNode3, kTab3);
+
+ base::MockCallback<base::RepeatingCallback<void(
+ const std::string& session_name, sync_pb::SessionSpecifics* specifics)>>
+ callback;
+ EXPECT_CALL(callback, Run(kSessionName,
+ Pointee(MatchesHeader(kTag, {kWindow1.id()},
+ {kTab1.id(), kTab2.id()}))));
+ EXPECT_CALL(callback, Run(kSessionName,
+ Pointee(MatchesTab(kTag, kWindow1.id(), kTab1.id(),
+ kTabNode1, /*urls=*/_))));
+ EXPECT_CALL(callback, Run(kSessionName,
+ Pointee(MatchesTab(kTag, kWindow1.id(), kTab2.id(),
+ kTabNode2, /*urls=*/_))));
+ EXPECT_CALL(
+ callback,
+ Run(kSessionName, Pointee(MatchesTab(kTag, Ne(kWindow1.id()), kTab3.id(),
+ kTabNode3, /*urls=*/_))));
+
+ SerializeTrackerToSpecifics(*GetTracker(), callback.Get());
+ EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&callback));
+
+ // Serialize the header only.
+ EXPECT_CALL(callback, Run(kSessionName,
+ Pointee(MatchesHeader(kTag, {kWindow1.id()},
+ {kTab1.id(), kTab2.id()}))));
+ SerializePartialTrackerToSpecifics(*GetTracker(),
+ {{kTag, {TabNodePool::kInvalidTabNodeID}}},
+ callback.Get());
+ EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&callback));
+
+ // Serialize a known and associated tab.
+ EXPECT_CALL(callback, Run(kSessionName,
+ Pointee(MatchesTab(kTag, kWindow1.id(), kTab1.id(),
+ kTabNode1, /*urls=*/_))));
+ SerializePartialTrackerToSpecifics(*GetTracker(), {{kTag, {kTabNode1}}},
+ callback.Get());
+ EXPECT_TRUE(testing::Mock::VerifyAndClearExpectations(&callback));
+
+ // Attempt to serialize unknown entities.
+ EXPECT_CALL(callback, Run(_, _)).Times(0);
+ SerializePartialTrackerToSpecifics(*GetTracker(), {{kTag, {kTabNode5}}},
+ callback.Get());
+ SerializePartialTrackerToSpecifics(
+ *GetTracker(), {{kTag2, {TabNodePool::kInvalidTabNodeID, kTabNode1}}},
+ callback.Get());
+}
+
+TEST_F(SyncedSessionTrackerTest, SerializeTrackerToSpecificsWithEmptyHeader) {
+ sync_pb::SessionSpecifics tab;
+ tab.set_session_tag(kTag);
+ tab.set_tab_node_id(kTabNode1);
+ tab.mutable_tab()->set_window_id(kWindow1.id());
+ tab.mutable_tab()->set_tab_id(kTab1.id());
+ UpdateTrackerWithSpecifics(tab, base::Time::Now(), GetTracker());
+
+ sync_pb::SessionSpecifics header;
+ header.set_session_tag(kTag);
+ header.mutable_header()->set_client_name(kSessionName);
+ UpdateTrackerWithSpecifics(header, base::Time::Now(), GetTracker());
+
+ base::MockCallback<base::RepeatingCallback<void(
+ const std::string& session_name, sync_pb::SessionSpecifics* specifics)>>
+ callback;
+ EXPECT_CALL(callback,
+ Run(kSessionName, Pointee(MatchesHeader(kTag, /*window_ids=*/{},
+ /*tab_ids=*/{}))));
+ EXPECT_CALL(
+ callback,
+ Run(kSessionName, Pointee(MatchesTab(kTag, /*window_id=*/0, kTab1.id(),
+ kTabNode1, /*urls=*/_))));
+ SerializeTrackerToSpecifics(*GetTracker(), callback.Get());
+}
+
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/tab_node_pool.cc b/chromium/components/sync_sessions/tab_node_pool.cc
index 0810b1136ec..c638fc62d3c 100644
--- a/chromium/components/sync_sessions/tab_node_pool.cc
+++ b/chromium/components/sync_sessions/tab_node_pool.cc
@@ -50,25 +50,12 @@ void TabNodePool::AssociateTabNode(int tab_node_id, SessionID tab_id) {
tabid_nodeid_map_[tab_id] = tab_node_id;
}
-bool TabNodePool::GetTabNodeForTab(SessionID tab_id, int* tab_node_id) {
- if (tabid_nodeid_map_.find(tab_id) != tabid_nodeid_map_.end()) {
- *tab_node_id = tabid_nodeid_map_[tab_id];
- return true;
- }
-
- if (free_nodes_pool_.empty()) {
- // Tab pool has no free nodes, allocate new one.
- *tab_node_id = ++max_used_tab_node_id_;
- AddTabNode(*tab_node_id);
-
- AssociateTabNode(*tab_node_id, tab_id);
- return false;
- } else {
- // Return the next free node.
- *tab_node_id = *free_nodes_pool_.begin();
- AssociateTabNode(*tab_node_id, tab_id);
- return true;
+int TabNodePool::GetTabNodeIdFromTabId(SessionID tab_id) const {
+ TabIDToTabNodeIDMap::const_iterator it = tabid_nodeid_map_.find(tab_id);
+ if (it != tabid_nodeid_map_.end()) {
+ return it->second;
}
+ return kInvalidTabNodeID;
}
void TabNodePool::FreeTab(SessionID tab_id) {
@@ -85,6 +72,23 @@ void TabNodePool::FreeTab(SessionID tab_id) {
free_nodes_pool_.insert(tab_node_id);
}
+int TabNodePool::AssociateWithFreeTabNode(SessionID tab_id) {
+ DCHECK_EQ(0U, tabid_nodeid_map_.count(tab_id));
+
+ int tab_node_id;
+ if (free_nodes_pool_.empty()) {
+ // Tab pool has no free nodes, allocate new one.
+ tab_node_id = ++max_used_tab_node_id_;
+ AddTabNode(tab_node_id);
+ } else {
+ // Return the next free node.
+ tab_node_id = *free_nodes_pool_.begin();
+ }
+
+ AssociateTabNode(tab_node_id, tab_id);
+ return tab_node_id;
+}
+
void TabNodePool::ReassociateTabNode(int tab_node_id, SessionID tab_id) {
DCHECK_GT(tab_node_id, kInvalidTabNodeID);
DCHECK(tab_id.is_valid());
@@ -136,6 +140,21 @@ void TabNodePool::CleanupTabNodes(std::set<int>* deleted_node_ids) {
}
}
+void TabNodePool::DeleteTabNode(int tab_node_id) {
+ TabNodeIDToTabIDMap::iterator it = nodeid_tabid_map_.find(tab_node_id);
+ if (it == nodeid_tabid_map_.end()) {
+ free_nodes_pool_.erase(tab_node_id);
+ return;
+ }
+
+ DCHECK_EQ(0U, free_nodes_pool_.count(tab_node_id));
+
+ SessionID tab_id = it->second;
+ DVLOG(1) << "Deleting node " << tab_node_id << " with tab ID " << tab_id;
+ tabid_nodeid_map_.erase(tab_id);
+ nodeid_tabid_map_.erase(it);
+}
+
// Clear tab pool.
void TabNodePool::Clear() {
free_nodes_pool_.clear();
@@ -156,4 +175,12 @@ bool TabNodePool::Full() {
return nodeid_tabid_map_.empty();
}
+std::set<int> TabNodePool::GetAllTabNodeIds() const {
+ std::set<int> tab_node_ids = free_nodes_pool_;
+ for (const auto& entry : nodeid_tabid_map_) {
+ tab_node_ids.insert(entry.first);
+ }
+ return tab_node_ids;
+}
+
} // namespace sync_sessions
diff --git a/chromium/components/sync_sessions/tab_node_pool.h b/chromium/components/sync_sessions/tab_node_pool.h
index 424e5a117ae..e36c84e8935 100644
--- a/chromium/components/sync_sessions/tab_node_pool.h
+++ b/chromium/components/sync_sessions/tab_node_pool.h
@@ -42,19 +42,19 @@ class TabNodePool {
static const int kInvalidTabNodeID;
- // Fills |tab_node_id| with a tab node associated with |tab_id|.
- // If tab_id is already associated with a tab_node_id, reuses the existing
- // association. Otherwise attempts to get the next free tab node and
- // associate it with |tab_id|. If none are available, will create a new tab
- // node.
- // Returns true if a pre-existing tab node could be reused, false if a new one
- // had to be created.
- bool GetTabNodeForTab(SessionID tab_id, int* tab_node_id);
+ // Returns the tab node associated with |tab_id| or kInvalidTabNodeID if
+ // no association existed.
+ int GetTabNodeIdFromTabId(SessionID tab_id) const;
// Returns the tab_id for |tab_node_id| if it is associated else returns an
// invalid ID.
SessionID GetTabIdFromTabNodeId(int tab_node_id) const;
+ // Gets the next free tab node (or creates a new one if needed) and associates
+ // it to |tab_id|. Returns the tab node ID associated to |tab_id|. |tab_id|
+ // must not be previously associated.
+ int AssociateWithFreeTabNode(SessionID tab_id);
+
// Reassociates |tab_node_id| with |tab_id|. If |tab_node_id| is not already
// known, it is added to the tab node pool before being associated.
void ReassociateTabNode(int tab_node_id, SessionID tab_id);
@@ -68,6 +68,11 @@ class TabNodePool {
// does not grow too large.
void CleanupTabNodes(std::set<int>* deleted_node_ids);
+ // Deletes all known mappings for |tab_node_id|. As opposed to FreeTab(), it
+ // does NOT free the node for later reuse. This is used for foreign sessions
+ // when remote deletions are received.
+ void DeleteTabNode(int tab_node_id);
+
// Clear tab pool.
void Clear();
@@ -81,6 +86,9 @@ class TabNodePool {
// Return full status (no tab nodes are in use).
bool Full();
+ // Returns tab node IDs for all known (used or free) tab nodes.
+ std::set<int> GetAllTabNodeIds() const;
+
private:
friend class SyncTabNodePoolTest;
using TabNodeIDToTabIDMap = std::map<int, SessionID>;
diff --git a/chromium/components/sync_sessions/tab_node_pool_unittest.cc b/chromium/components/sync_sessions/tab_node_pool_unittest.cc
index 6150cb538b1..48743313df1 100644
--- a/chromium/components/sync_sessions/tab_node_pool_unittest.cc
+++ b/chromium/components/sync_sessions/tab_node_pool_unittest.cc
@@ -6,6 +6,7 @@
#include <vector>
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sync_sessions {
@@ -16,19 +17,19 @@ class SyncTabNodePoolTest : public testing::Test {
int GetMaxUsedTabNodeId() const { return pool_.max_used_tab_node_id_; }
- void AddFreeTabNodes(size_t size, const int node_ids[]);
+ void AddFreeTabNodes(const std::vector<int>& node_ids) {
+ for (int node_id : node_ids) {
+ pool_.free_nodes_pool_.insert(node_id);
+ }
+ }
TabNodePool pool_;
};
-void SyncTabNodePoolTest::AddFreeTabNodes(size_t size, const int node_ids[]) {
- for (size_t i = 0; i < size; ++i) {
- pool_.free_nodes_pool_.insert(node_ids[i]);
- }
-}
-
namespace {
+using testing::UnorderedElementsAre;
+
const int kTabNodeId1 = 10;
const int kTabNodeId2 = 5;
const int kTabNodeId3 = 1000;
@@ -57,9 +58,11 @@ TEST_F(SyncTabNodePoolTest, TabNodeIdIncreases) {
pool_.CleanupTabNodes(&deleted_node_ids);
EXPECT_TRUE(deleted_node_ids.empty());
for (int i = 0; i < 3; ++i) {
- int tab_node_id = -1;
- EXPECT_TRUE(pool_.GetTabNodeForTab(SessionID::FromSerializedValue(i + 1),
- &tab_node_id));
+ const SessionID tab_id = SessionID::FromSerializedValue(i + 1);
+ ASSERT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(tab_id));
+ EXPECT_NE(TabNodePool::kInvalidTabNodeID,
+ pool_.AssociateWithFreeTabNode(tab_id));
EXPECT_EQ(kTabNodeId3, GetMaxUsedTabNodeId());
}
pool_.CleanupTabNodes(&deleted_node_ids);
@@ -135,19 +138,19 @@ TEST_F(SyncTabNodePoolTest, ReassociateThenFree) {
pool_.CleanupTabNodes(&deleted_node_ids);
EXPECT_TRUE(deleted_node_ids.empty());
EXPECT_TRUE(pool_.Full());
- std::set<int> free_sync_ids;
+
+ // Reassociate tab nodes.
+ std::vector<int> sync_ids;
for (int i = 1; i <= 3; ++i) {
- int tab_node_id = -1;
- EXPECT_TRUE(pool_.GetTabNodeForTab(SessionID::FromSerializedValue(i),
- &tab_node_id));
- free_sync_ids.insert(tab_node_id);
+ const SessionID tab_id = SessionID::FromSerializedValue(i);
+ EXPECT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(tab_id));
+ sync_ids.push_back(pool_.AssociateWithFreeTabNode(tab_id));
}
EXPECT_TRUE(pool_.Empty());
- EXPECT_EQ(3u, free_sync_ids.size());
- EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId1));
- EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId2));
- EXPECT_EQ(1u, free_sync_ids.count(kTabNodeId3));
+ EXPECT_THAT(sync_ids,
+ UnorderedElementsAre(kTabNodeId1, kTabNodeId2, kTabNodeId3));
}
TEST_F(SyncTabNodePoolTest, Init) {
@@ -156,25 +159,34 @@ TEST_F(SyncTabNodePoolTest, Init) {
}
TEST_F(SyncTabNodePoolTest, AddGet) {
- int free_nodes[] = {5, 10};
- AddFreeTabNodes(2, free_nodes);
+ AddFreeTabNodes({5, 10});
EXPECT_EQ(2U, pool_.Capacity());
- int tab_node_id = -1;
- EXPECT_TRUE(pool_.GetTabNodeForTab(kTabId1, &tab_node_id));
- EXPECT_EQ(5, tab_node_id);
+ ASSERT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(kTabId1));
+ EXPECT_EQ(5, pool_.AssociateWithFreeTabNode(kTabId1));
EXPECT_FALSE(pool_.Empty());
EXPECT_FALSE(pool_.Full());
EXPECT_EQ(2U, pool_.Capacity());
+ ASSERT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(kTabId2));
// 5 is now used, should return 10.
- EXPECT_TRUE(pool_.GetTabNodeForTab(kTabId2, &tab_node_id));
- EXPECT_EQ(10, tab_node_id);
+ EXPECT_EQ(10, pool_.AssociateWithFreeTabNode(kTabId2));
}
-TEST_F(SyncTabNodePoolTest, GetTabNodeForTabCreate) {
- int tab_node_id = -1;
- EXPECT_FALSE(pool_.GetTabNodeForTab(kTabId1, &tab_node_id));
- EXPECT_EQ(0, tab_node_id);
+TEST_F(SyncTabNodePoolTest, AssociateWithFreeTabNode) {
+ ASSERT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(kTabId1));
+ ASSERT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(kTabId2));
+ EXPECT_EQ(0, pool_.AssociateWithFreeTabNode(kTabId1));
+ EXPECT_EQ(0, pool_.GetTabNodeIdFromTabId(kTabId1));
+ ASSERT_EQ(TabNodePool::kInvalidTabNodeID,
+ pool_.GetTabNodeIdFromTabId(kTabId2));
+ EXPECT_EQ(1, pool_.AssociateWithFreeTabNode(kTabId2));
+ EXPECT_EQ(1, pool_.GetTabNodeIdFromTabId(kTabId2));
+ pool_.FreeTab(kTabId1);
+ EXPECT_EQ(0, pool_.AssociateWithFreeTabNode(kTabId3));
}
TEST_F(SyncTabNodePoolTest, TabPoolFreeNodeLimits) {
@@ -185,10 +197,8 @@ TEST_F(SyncTabNodePoolTest, TabPoolFreeNodeLimits) {
// kFreeNodesLowWatermark.
std::vector<int> used_sync_ids;
for (size_t i = 1; i <= TabNodePool::kFreeNodesHighWatermark + 1; ++i) {
- int sync_id = -1;
- EXPECT_FALSE(
- pool_.GetTabNodeForTab(SessionID::FromSerializedValue(i), &sync_id));
- used_sync_ids.push_back(sync_id);
+ used_sync_ids.push_back(
+ pool_.AssociateWithFreeTabNode(SessionID::FromSerializedValue(i)));
}
// Free all except one node.
diff --git a/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc b/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc
index 7a37060818c..3cc6e3dba52 100644
--- a/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc
+++ b/chromium/components/sync_sessions/test_synced_window_delegates_getter.cc
@@ -253,7 +253,9 @@ SessionID PlaceholderTabDelegate::GetSourceTabID() const {
TestSyncedWindowDelegate::TestSyncedWindowDelegate(
SessionID window_id,
sync_pb::SessionWindow_BrowserType type)
- : window_id_(window_id), window_type_(type) {}
+ : window_id_(window_id),
+ window_type_(type),
+ is_session_restore_in_progress_(false) {}
TestSyncedWindowDelegate::~TestSyncedWindowDelegate() = default;
@@ -262,6 +264,10 @@ void TestSyncedWindowDelegate::OverrideTabAt(int index,
tab_delegates_[index] = delegate;
}
+void TestSyncedWindowDelegate::SetIsSessionRestoreInProgress(bool value) {
+ is_session_restore_in_progress_ = value;
+}
+
bool TestSyncedWindowDelegate::HasWindow() const {
return true;
}
@@ -309,7 +315,7 @@ SessionID TestSyncedWindowDelegate::GetTabIdAt(int index) const {
}
bool TestSyncedWindowDelegate::IsSessionRestoreInProgress() const {
- return false;
+ return is_session_restore_in_progress_;
}
bool TestSyncedWindowDelegate::ShouldSync() const {
diff --git a/chromium/components/sync_sessions/test_synced_window_delegates_getter.h b/chromium/components/sync_sessions/test_synced_window_delegates_getter.h
index adbbd78383f..868d26b268a 100644
--- a/chromium/components/sync_sessions/test_synced_window_delegates_getter.h
+++ b/chromium/components/sync_sessions/test_synced_window_delegates_getter.h
@@ -128,6 +128,8 @@ class TestSyncedWindowDelegate : public SyncedWindowDelegate {
// |delegate| must not be nullptr and must outlive this object.
void OverrideTabAt(int index, SyncedTabDelegate* delegate);
+ void SetIsSessionRestoreInProgress(bool value);
+
// SyncedWindowDelegate overrides.
bool HasWindow() const override;
SessionID GetSessionId() const override;
@@ -149,6 +151,7 @@ class TestSyncedWindowDelegate : public SyncedWindowDelegate {
std::map<int, SyncedTabDelegate*> tab_delegates_;
std::map<int, SyncedTabDelegate*> tab_overrides_;
std::map<int, SessionID> tab_id_overrides_;
+ bool is_session_restore_in_progress_;
DISALLOW_COPY_AND_ASSIGN(TestSyncedWindowDelegate);
};
diff --git a/chromium/components/sync_ui_strings_grdp/OWNERS b/chromium/components/sync_ui_strings_grdp/OWNERS
new file mode 100644
index 00000000000..261ab189a66
--- /dev/null
+++ b/chromium/components/sync_ui_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/sync/OWNERS
diff --git a/chromium/components/sync_ui_strings_grdp/README.md b/chromium/components/sync_ui_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/sync_ui_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/task_scheduler_util/common/BUILD.gn b/chromium/components/task_scheduler_util/BUILD.gn
index ee178bf8a3b..a7c02de131c 100644
--- a/chromium/components/task_scheduler_util/common/BUILD.gn
+++ b/chromium/components/task_scheduler_util/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-static_library("common") {
+static_library("task_scheduler_util") {
sources = [
"variations_util.cc",
"variations_util.h",
@@ -19,7 +19,7 @@ source_set("unit_tests") {
"variations_util_unittest.cc",
]
deps = [
- ":common",
+ ":task_scheduler_util",
"//base",
"//components/variations:test_support",
"//testing/gtest",
diff --git a/chromium/components/task_scheduler_util/common/DEPS b/chromium/components/task_scheduler_util/DEPS
index be216e98a5e..be216e98a5e 100644
--- a/chromium/components/task_scheduler_util/common/DEPS
+++ b/chromium/components/task_scheduler_util/DEPS
diff --git a/chromium/components/task_scheduler_util/common/variations_util.cc b/chromium/components/task_scheduler_util/variations_util.cc
index 21e86db6434..5c2aa320564 100644
--- a/chromium/components/task_scheduler_util/common/variations_util.cc
+++ b/chromium/components/task_scheduler_util/variations_util.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/task_scheduler_util/common/variations_util.h"
+#include "components/task_scheduler_util/variations_util.h"
#include <map>
#include <string>
diff --git a/chromium/components/task_scheduler_util/common/variations_util.h b/chromium/components/task_scheduler_util/variations_util.h
index 991f23cd931..901ef19dcbf 100644
--- a/chromium/components/task_scheduler_util/common/variations_util.h
+++ b/chromium/components/task_scheduler_util/variations_util.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 COMPONENTS_TASK_SCHEDULER_UTIL_COMMON_VARIATIONS_UTIL_H_
-#define COMPONENTS_TASK_SCHEDULER_UTIL_COMMON_VARIATIONS_UTIL_H_
+#ifndef COMPONENTS_TASK_SCHEDULER_UTIL_VARIATIONS_UTIL_H_
+#define COMPONENTS_TASK_SCHEDULER_UTIL_VARIATIONS_UTIL_H_
#include <memory>
@@ -33,4 +33,4 @@ GetTaskSchedulerInitParamsForRenderer();
} // namespace task_scheduler_util
-#endif // COMPONENTS_TASK_SCHEDULER_UTIL_COMMON_VARIATIONS_UTIL_H_
+#endif // COMPONENTS_TASK_SCHEDULER_UTIL_VARIATIONS_UTIL_H_
diff --git a/chromium/components/task_scheduler_util/common/variations_util_unittest.cc b/chromium/components/task_scheduler_util/variations_util_unittest.cc
index 57b50a4ddc6..65b69f63657 100644
--- a/chromium/components/task_scheduler_util/common/variations_util_unittest.cc
+++ b/chromium/components/task_scheduler_util/variations_util_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/task_scheduler_util/common/variations_util.h"
+#include "components/task_scheduler_util/variations_util.h"
#include <map>
#include <string>
diff --git a/chromium/components/test/BUILD.gn b/chromium/components/test/BUILD.gn
index 737c1a07ade..247a3f78f0c 100644
--- a/chromium/components/test/BUILD.gn
+++ b/chromium/components/test/BUILD.gn
@@ -52,7 +52,7 @@ source_set("run_all_unittests") {
":test_support",
]
- if (enable_basic_printing || enable_print_preview) {
+ if (enable_basic_printing) {
defines = [ "HAS_SERVICE_IN_UNIT_TEST" ]
deps += [
":components_unittests_catalog_source",
@@ -61,13 +61,11 @@ source_set("run_all_unittests") {
}
}
-if (enable_basic_printing || enable_print_preview) {
+if (enable_basic_printing) {
# There is only one service in catalog, which depends on printing feature.
# When more services are added, the condition can be moved inside of catalog.
catalog("components_unittests_catalog") {
- embedded_services = [
- "//components/printing/service:pdf_compositor_service_unittest_manifest",
- ]
+ embedded_services = [ "//components/services/pdf_compositor:pdf_compositor_service_unittest_manifest" ]
}
catalog_cpp_source("components_unittests_catalog_source") {
diff --git a/chromium/components/timers/alarm_timer_unittest.cc b/chromium/components/timers/alarm_timer_unittest.cc
index 1a10edb5c0c..ec822374550 100644
--- a/chromium/components/timers/alarm_timer_unittest.cc
+++ b/chromium/components/timers/alarm_timer_unittest.cc
@@ -21,8 +21,7 @@
#include "testing/gtest/include/gtest/gtest.h"
// Most of these tests have been lifted right out of timer_unittest.cc with only
-// cosmetic changes (like replacing calls to MessageLoop::current()->Run() with
-// a RunLoop). We want the AlarmTimer to be a drop-in replacement for the
+// cosmetic changes. We want the AlarmTimer to be a drop-in replacement for the
// regular Timer so it should pass the same tests as the Timer class.
namespace timers {
namespace {
@@ -44,7 +43,7 @@ class OneShotAlarmTimerTester {
*did_run_ = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
bool* did_run_;
@@ -72,7 +71,7 @@ class OneShotSelfDeletingAlarmTimerTester {
timer_.reset();
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
bool* did_run_;
@@ -101,7 +100,7 @@ class RepeatingAlarmTimerTester {
timer_->Stop();
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
}
@@ -371,13 +370,13 @@ void ClearAllCallbackHappened() {
void SetCallbackHappened1() {
g_callback_happened1 = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
void SetCallbackHappened2() {
g_callback_happened2 = true;
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+ FROM_HERE, base::RunLoop::QuitCurrentWhenIdleClosureDeprecated());
}
TEST(AlarmTimerTest, ContinuationStopStart) {
diff --git a/chromium/components/toolbar/BUILD.gn b/chromium/components/toolbar/BUILD.gn
index 3e6affddd9b..339de1690e1 100644
--- a/chromium/components/toolbar/BUILD.gn
+++ b/chromium/components/toolbar/BUILD.gn
@@ -20,14 +20,10 @@ aggregate_vector_icons("toolbar_vector_icons") {
"http.icon",
"https_invalid.icon",
"https_valid.icon",
- "http_20.icon",
- "https_invalid_20.icon",
- "https_valid_20.icon",
"https_valid_in_chip.icon",
"offline_pin.icon",
"open_in_new.icon",
"product.icon",
- "product_20.icon",
"star_active.icon",
"star.icon",
]
@@ -48,6 +44,7 @@ static_library("toolbar") {
"toolbar_field_trial.cc",
"toolbar_field_trial.h",
"toolbar_model.h",
+ "toolbar_model_delegate.cc",
"toolbar_model_delegate.h",
"toolbar_model_impl.cc",
"toolbar_model_impl.h",
@@ -99,3 +96,17 @@ static_library("test_support") {
deps += [ "//ui/views" ]
}
}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "toolbar_model_impl_unittest.cc",
+ ]
+
+ deps = [
+ ":toolbar",
+ "//base",
+ "//testing/gtest",
+ "//url",
+ ]
+}
diff --git a/chromium/components/toolbar/toolbar_model_delegate.cc b/chromium/components/toolbar/toolbar_model_delegate.cc
new file mode 100644
index 00000000000..68b53364493
--- /dev/null
+++ b/chromium/components/toolbar/toolbar_model_delegate.cc
@@ -0,0 +1,31 @@
+// 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 "components/toolbar/toolbar_model_delegate.h"
+
+bool ToolbarModelDelegate::ShouldDisplayURL() const {
+ return true;
+}
+
+ToolbarModelDelegate::SecurityLevel ToolbarModelDelegate::GetSecurityLevel()
+ const {
+ return SecurityLevel::NONE;
+}
+
+scoped_refptr<net::X509Certificate> ToolbarModelDelegate::GetCertificate()
+ const {
+ return nullptr;
+}
+
+bool ToolbarModelDelegate::FailsMalwareCheck() const {
+ return false;
+}
+
+const gfx::VectorIcon* ToolbarModelDelegate::GetVectorIconOverride() const {
+ return nullptr;
+}
+
+bool ToolbarModelDelegate::IsOfflinePage() const {
+ return false;
+}
diff --git a/chromium/components/toolbar/toolbar_model_delegate.h b/chromium/components/toolbar/toolbar_model_delegate.h
index f0f4f171b13..3cd724bf2f3 100644
--- a/chromium/components/toolbar/toolbar_model_delegate.h
+++ b/chromium/components/toolbar/toolbar_model_delegate.h
@@ -38,27 +38,27 @@ class ToolbarModelDelegate {
// Returns whether the URL for the current navigation entry should be
// in the location bar.
- virtual bool ShouldDisplayURL() const = 0;
+ virtual bool ShouldDisplayURL() const;
// Returns the underlying security level of the page without regard to any
// user edits that may be in progress.
- virtual SecurityLevel GetSecurityLevel() const = 0;
+ virtual SecurityLevel GetSecurityLevel() const;
// Returns the certificate for the current navigation entry.
- virtual scoped_refptr<net::X509Certificate> GetCertificate() const = 0;
+ virtual scoped_refptr<net::X509Certificate> GetCertificate() const;
// Returns true if the current page fails the malware check.
- virtual bool FailsMalwareCheck() const = 0;
+ virtual bool FailsMalwareCheck() const;
// Returns the id of the icon to show to the left of the address, or nullptr
// if the icon should be selected by the caller. This is useful for
// associating particular URLs with particular schemes without importing
// knowledge of those schemes into this component.
- virtual const gfx::VectorIcon* GetVectorIconOverride() const = 0;
+ virtual const gfx::VectorIcon* GetVectorIconOverride() const;
// Returns whether the page is an offline page, sourced from a cache of
// previously-downloaded content.
- virtual bool IsOfflinePage() const = 0;
+ virtual bool IsOfflinePage() const;
protected:
virtual ~ToolbarModelDelegate() {}
diff --git a/chromium/components/toolbar/toolbar_model_impl.cc b/chromium/components/toolbar/toolbar_model_impl.cc
index cdb80da4200..689f02345fd 100644
--- a/chromium/components/toolbar/toolbar_model_impl.cc
+++ b/chromium/components/toolbar/toolbar_model_impl.cc
@@ -16,13 +16,10 @@
#include "components/toolbar/buildflags.h"
#include "components/toolbar/toolbar_field_trial.h"
#include "components/toolbar/toolbar_model_delegate.h"
-#include "components/url_formatter/elide_url.h"
-#include "components/url_formatter/url_formatter.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/x509_certificate.h"
#include "net/ssl/ssl_connection_status_flags.h"
#include "ui/base/l10n/l10n_util.h"
-#include "ui/base/material_design/material_design_controller.h"
#include "ui/gfx/text_elider.h"
#include "ui/gfx/vector_icon_types.h"
@@ -42,15 +39,31 @@ ToolbarModelImpl::~ToolbarModelImpl() {
// ToolbarModelImpl Implementation.
base::string16 ToolbarModelImpl::GetFormattedFullURL() const {
+ return GetFormattedURL(url_formatter::kFormatUrlOmitDefaults);
+}
+
+base::string16 ToolbarModelImpl::GetURLForDisplay() const {
+ url_formatter::FormatUrlTypes format_types =
+#if defined(OS_IOS)
+ url_formatter::kFormatUrlTrimAfterHost |
+#endif
+ url_formatter::kFormatUrlOmitDefaults |
+ url_formatter::kFormatUrlOmitHTTPS |
+ url_formatter::kFormatUrlOmitTrivialSubdomains;
+ return GetFormattedURL(format_types);
+}
+
+base::string16 ToolbarModelImpl::GetFormattedURL(
+ url_formatter::FormatUrlTypes format_types) const {
GURL url(GetURL());
// Note that we can't unescape spaces here, because if the user copies this
// and pastes it into another program, that program may think the URL ends at
// the space.
const base::string16 formatted_text =
delegate_->FormattedStringWithEquivalentMeaning(
- url, url_formatter::FormatUrl(
- url, url_formatter::kFormatUrlOmitDefaults,
- net::UnescapeRule::NORMAL, nullptr, nullptr, nullptr));
+ url,
+ url_formatter::FormatUrl(url, format_types, net::UnescapeRule::NORMAL,
+ nullptr, nullptr, nullptr));
// Truncating the URL breaks editing and then pressing enter, but hopefully
// people won't try to do much with such enormous URLs anyway. If this becomes
@@ -61,19 +74,6 @@ base::string16 ToolbarModelImpl::GetFormattedFullURL() const {
gfx::CHARACTER_BREAK);
}
-base::string16 ToolbarModelImpl::GetURLForDisplay() const {
- url_formatter::FormatUrlTypes format_types =
- url_formatter::kFormatUrlOmitDefaults |
- url_formatter::kFormatUrlOmitHTTPS |
- url_formatter::kFormatUrlOmitTrivialSubdomains;
- base::string16 result = url_formatter::FormatUrl(GetURL(), format_types,
- net::UnescapeRule::NORMAL,
- nullptr, nullptr, nullptr);
-
- return gfx::TruncateString(result, max_url_display_chars_,
- gfx::CHARACTER_BREAK);
-}
-
GURL ToolbarModelImpl::GetURL() const {
GURL url;
return delegate_->GetURL(&url) ? url : GURL(url::kAboutBlankURL);
@@ -89,9 +89,6 @@ security_state::SecurityLevel ToolbarModelImpl::GetSecurityLevel(
const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
#if (!defined(OS_ANDROID) || BUILDFLAG(ENABLE_VR)) && !defined(OS_IOS)
- const bool is_touch_ui =
- ui::MaterialDesignController::IsTouchOptimizedUiEnabled();
-
auto* const icon_override = delegate_->GetVectorIconOverride();
if (icon_override)
return *icon_override;
@@ -102,16 +99,14 @@ const gfx::VectorIcon& ToolbarModelImpl::GetVectorIcon() const {
switch (GetSecurityLevel(false)) {
case security_state::NONE:
case security_state::HTTP_SHOW_WARNING:
- return is_touch_ui ? toolbar::kHttp20Icon : toolbar::kHttpIcon;
+ return toolbar::kHttpIcon;
case security_state::EV_SECURE:
case security_state::SECURE:
- return is_touch_ui ? toolbar::kHttpsValid20Icon
- : toolbar::kHttpsValidIcon;
+ return toolbar::kHttpsValidIcon;
case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
return vector_icons::kBusinessIcon;
case security_state::DANGEROUS:
- return is_touch_ui ? toolbar::kHttpsInvalid20Icon
- : toolbar::kHttpsInvalidIcon;
+ return toolbar::kHttpsInvalidIcon;
case security_state::SECURITY_LEVEL_COUNT:
NOTREACHED();
return toolbar::kHttpIcon;
diff --git a/chromium/components/toolbar/toolbar_model_impl.h b/chromium/components/toolbar/toolbar_model_impl.h
index 2e2a74407af..bfa873c923a 100644
--- a/chromium/components/toolbar/toolbar_model_impl.h
+++ b/chromium/components/toolbar/toolbar_model_impl.h
@@ -13,6 +13,7 @@
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/toolbar/toolbar_model.h"
+#include "components/url_formatter/url_formatter.h"
#include "url/gurl.h"
class ToolbarModelDelegate;
@@ -26,7 +27,6 @@ class ToolbarModelImpl : public ToolbarModel {
size_t max_url_display_chars);
~ToolbarModelImpl() override;
- private:
// ToolbarModel:
base::string16 GetFormattedFullURL() const override;
base::string16 GetURLForDisplay() const override;
@@ -39,6 +39,10 @@ class ToolbarModelImpl : public ToolbarModel {
bool ShouldDisplayURL() const override;
bool IsOfflinePage() const override;
+ private:
+ base::string16 GetFormattedURL(
+ url_formatter::FormatUrlTypes format_types) const;
+
ToolbarModelDelegate* delegate_;
const size_t max_url_display_chars_;
diff --git a/chromium/components/toolbar/toolbar_model_impl_unittest.cc b/chromium/components/toolbar/toolbar_model_impl_unittest.cc
new file mode 100644
index 00000000000..4fe89059c02
--- /dev/null
+++ b/chromium/components/toolbar/toolbar_model_impl_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/toolbar/toolbar_model_impl.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "components/toolbar/toolbar_model_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+class FakeToolbarModelDelegate : public ToolbarModelDelegate {
+ public:
+ void SetURL(const GURL& url) { url_ = url; }
+
+ // ToolbarModelDelegate:
+ base::string16 FormattedStringWithEquivalentMeaning(
+ const GURL& url,
+ const base::string16& formatted_url) const override {
+ return formatted_url + base::ASCIIToUTF16("/TestSuffix");
+ }
+
+ bool GetURL(GURL* url) const override {
+ *url = url_;
+ return true;
+ }
+
+ private:
+ GURL url_;
+};
+
+TEST(ToolbarModelImplTest,
+ DisplayUrlAppliesFormattedStringWithEquivalentMeaning) {
+ FakeToolbarModelDelegate delegate;
+ auto model = std::make_unique<ToolbarModelImpl>(&delegate, 1024);
+
+ delegate.SetURL(GURL("http://www.google.com/"));
+
+ // Verify that both the full formatted URL and the display URL add the test
+ // suffix.
+ EXPECT_EQ(base::ASCIIToUTF16("www.google.com/TestSuffix"),
+ model->GetFormattedFullURL());
+ EXPECT_EQ(base::ASCIIToUTF16("google.com/TestSuffix"),
+ model->GetURLForDisplay());
+}
+
+} // namespace
diff --git a/chromium/components/toolbar/vector_icons/http.icon b/chromium/components/toolbar/vector_icons/http.icon
index 387a87457d9..affa42cae2d 100644
--- a/chromium/components/toolbar/vector_icons/http.icon
+++ b/chromium/components/toolbar/vector_icons/http.icon
@@ -25,6 +25,32 @@ LINE_TO, 15, 10,
LINE_TO, 15, 13,
CLOSE
+CANVAS_DIMENSIONS, 20,
+MOVE_TO, 10, 2,
+R_CUBIC_TO, -4.42f, 0, -8, 3.58f, -8, 8,
+R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
+R_CUBIC_TO, 4.42f, 0, 8, -3.58f, 8, -8,
+R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
+CLOSE,
+R_MOVE_TO, -6, 8,
+R_CUBIC_TO, 0, -3.31f, 2.69f, -6, 6, -6,
+R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
+R_CUBIC_TO, 0, 3.31f, -2.69f, 6, -6, 6,
+R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
+CLOSE,
+R_MOVE_TO, 7, 4,
+V_LINE_TO, 9,
+H_LINE_TO, 9,
+R_V_LINE_TO, 5,
+R_H_LINE_TO, 2,
+CLOSE,
+MOVE_TO, 9, 8,
+R_H_LINE_TO, 2,
+V_LINE_TO, 6,
+H_LINE_TO, 9,
+R_V_LINE_TO, 2,
+CLOSE
+
CANVAS_DIMENSIONS, 16,
MOVE_TO, 8, 1,
CUBIC_TO, 4.14f, 1, 1, 4.14f, 1, 8,
diff --git a/chromium/components/toolbar/vector_icons/http_20.icon b/chromium/components/toolbar/vector_icons/http_20.icon
deleted file mode 100644
index 20abc44a3b9..00000000000
--- a/chromium/components/toolbar/vector_icons/http_20.icon
+++ /dev/null
@@ -1,32 +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.
-
-// TODO(crbug.com/647286): This is a duplicate of the existing kHttpIcon, just
-// sized to 20x20dips for use in Chrome's touch mode.
-// Delete this when vector icons can support multiple icon sizes.
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 10, 2,
-R_CUBIC_TO, -4.42f, 0, -8, 3.58f, -8, 8,
-R_CUBIC_TO, 0, 4.42f, 3.58f, 8, 8, 8,
-R_CUBIC_TO, 4.42f, 0, 8, -3.58f, 8, -8,
-R_CUBIC_TO, 0, -4.42f, -3.58f, -8, -8, -8,
-CLOSE,
-R_MOVE_TO, -6, 8,
-R_CUBIC_TO, 0, -3.31f, 2.69f, -6, 6, -6,
-R_CUBIC_TO, 3.31f, 0, 6, 2.69f, 6, 6,
-R_CUBIC_TO, 0, 3.31f, -2.69f, 6, -6, 6,
-R_CUBIC_TO, -3.31f, 0, -6, -2.69f, -6, -6,
-CLOSE,
-R_MOVE_TO, 7, 4,
-V_LINE_TO, 9,
-H_LINE_TO, 9,
-R_V_LINE_TO, 5,
-R_H_LINE_TO, 2,
-CLOSE,
-MOVE_TO, 9, 8,
-R_H_LINE_TO, 2,
-V_LINE_TO, 6,
-H_LINE_TO, 9,
-R_V_LINE_TO, 2,
-CLOSE
diff --git a/chromium/components/toolbar/vector_icons/https_invalid_20.icon b/chromium/components/toolbar/vector_icons/https_invalid_20.icon
deleted file mode 100644
index 3e96bb92e03..00000000000
--- a/chromium/components/toolbar/vector_icons/https_invalid_20.icon
+++ /dev/null
@@ -1,25 +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.
-
-// TODO(crbug.com/647286): This is a duplicate of the existing
-// kHttpsInvalidIcon, just sized to 20x20dips for use in Chrome's touch mode.
-// Delete this when vector icons can support multiple icon sizes.
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 1, 18,
-R_H_LINE_TO, 18,
-LINE_TO, 10, 2,
-LINE_TO, 1, 18,
-CLOSE,
-R_MOVE_TO, 10, -2,
-H_LINE_TO, 9,
-R_V_LINE_TO, -2,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 2,
-CLOSE,
-R_MOVE_TO, -2, -3,
-V_LINE_TO, 8,
-R_H_LINE_TO, 2,
-R_V_LINE_TO, 5,
-H_LINE_TO, 9,
-CLOSE
diff --git a/chromium/components/toolbar/vector_icons/https_valid_20.icon b/chromium/components/toolbar/vector_icons/https_valid_20.icon
deleted file mode 100644
index 61c61bca77e..00000000000
--- a/chromium/components/toolbar/vector_icons/https_valid_20.icon
+++ /dev/null
@@ -1,29 +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.
-
-// TODO(crbug.com/647286): This is a duplicate of the existing kHttpsValidIcon,
-// just sized to 20x20dips for use in Chrome's touch mode. Delete this when
-// vector icons can support multiple icon sizes.
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 13, 7,
-V_LINE_TO, 6,
-R_CUBIC_TO, 0, -1.66f, -1.34f, -3, -3, -3,
-CUBIC_TO_SHORTHAND, 7, 4.34f, 7, 6,
-R_V_LINE_TO, 1,
-R_H_LINE_TO, -0.5f,
-CUBIC_TO, 5.33f, 7, 5, 7.79f, 5, 8.5f,
-R_V_LINE_TO, 6,
-R_CUBIC_TO, 0, 0.83f, 0.67f, 1.5f, 1.5f, 1.5f,
-R_H_LINE_TO, 7,
-R_CUBIC_TO, 0.83f, 0, 1.5f, -0.67f, 1.5f, -1.5f,
-R_V_LINE_TO, -6,
-R_CUBIC_TO, 0, -0.83f, -0.67f, -1.5f, -1.5f, -1.5f,
-H_LINE_TO, 13,
-CLOSE,
-R_MOVE_TO, -5, 0,
-R_V_LINE_TO, -1,
-R_ARC_TO, 2, 2, 0, 0, 1, 4, 0,
-R_V_LINE_TO, 1,
-H_LINE_TO, 8,
-CLOSE
diff --git a/chromium/components/toolbar/vector_icons/product_20.icon b/chromium/components/toolbar/vector_icons/product_20.icon
deleted file mode 100644
index 89c0c2ecd3a..00000000000
--- a/chromium/components/toolbar/vector_icons/product_20.icon
+++ /dev/null
@@ -1,36 +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.
-
-// TODO(crbug.com/647286): This is a duplicate of the existing kProductIcon,
-// just sized to 20x20dips for use in Chrome's touch mode. Delete this when
-// vector icons can support multiple icon sizes.
-CANVAS_DIMENSIONS, 20,
-MOVE_TO, 10, 6.4f,
-R_H_LINE_TO, 7.12f,
-CUBIC_TO, 15.84f, 3.76f, 13.12f, 2, 10, 2,
-CUBIC_TO, 7.52f, 2, 5.28f, 3.12f, 3.84f, 4.88f,
-R_LINE_TO, 2.64f, 4.56f,
-CUBIC_TO, 6.72f, 7.76f, 8.24f, 6.4f, 10, 6.4f,
-CLOSE,
-R_MOVE_TO, 0, 7.2f,
-R_CUBIC_TO, -1.36f, 0, -2.48f, -0.72f, -3.12f, -1.84f,
-LINE_TO, 3.28f, 5.6f,
-CUBIC_TO, 2.48f, 6.88f, 2, 8.4f, 2, 10,
-R_CUBIC_TO, 0, 4, 2.88f, 7.28f, 6.72f, 7.92f,
-R_LINE_TO, 2.64f, -4.56f,
-R_CUBIC_TO, -0.48f, 0.16f, -0.88f, 0.24f, -1.36f, 0.24f,
-CLOSE,
-R_MOVE_TO, 3.6f, -3.6f,
-R_CUBIC_TO, 0, -1.12f, -0.56f, -2.16f, -1.36f, -2.8f,
-R_H_LINE_TO, 5.28f,
-R_CUBIC_TO, 0.32f, 0.88f, 0.48f, 1.84f, 0.48f, 2.8f,
-R_CUBIC_TO, 0, 4.4f, -3.6f, 8, -8, 8,
-R_H_LINE_TO, -0.48f,
-R_LINE_TO, 3.6f, -6.24f,
-R_CUBIC_TO, 0.32f, -0.48f, 0.48f, -1.12f, 0.48f, -1.76f,
-CLOSE,
-MOVE_TO, 10, 12.8f,
-R_ARC_TO, 2.8f, 2.8f, 0, 1, 1, 0, -5.6f,
-R_ARC_TO, 2.8f, 2.8f, 0, 0, 1, 0, 5.6f,
-CLOSE
diff --git a/chromium/components/tracing/BUILD.gn b/chromium/components/tracing/BUILD.gn
index af5de3a8b0b..2fedf988579 100644
--- a/chromium/components/tracing/BUILD.gn
+++ b/chromium/components/tracing/BUILD.gn
@@ -25,10 +25,10 @@ component("tracing") {
component("startup_tracing") {
sources = [
- "common/trace_config_file.cc",
- "common/trace_config_file.h",
"common/trace_startup.cc",
"common/trace_startup.h",
+ "common/trace_startup_config.cc",
+ "common/trace_startup_config.h",
"common/trace_to_console.cc",
"common/trace_to_console.h",
"common/tracing_switches.cc",
@@ -60,7 +60,7 @@ source_set("unit_tests") {
]
if (!is_android) {
- sources += [ "common/trace_config_file_unittest.cc" ]
+ sources += [ "common/trace_startup_config_unittest.cc" ]
deps += [ ":startup_tracing" ]
}
}
@@ -80,12 +80,9 @@ test("tracing_perftests") {
"//testing/perf",
]
- data = [
+ data_deps = [
# Needed for isolate script to execute.
- "//testing/scripts/common.py",
- "//testing/xvfb.py",
- "//testing/scripts/run_gtest_perf_test.py",
- "//tools/perf/generate_legacy_perf_dashboard_json.py",
+ "//testing:run_perf_test",
]
if (is_android) {
diff --git a/chromium/components/tracing/common/trace_startup.cc b/chromium/components/tracing/common/trace_startup.cc
index 54b6aedd9d6..8bcc6d0bf8c 100644
--- a/chromium/components/tracing/common/trace_startup.cc
+++ b/chromium/components/tracing/common/trace_startup.cc
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_log.h"
-#include "components/tracing/common/trace_config_file.h"
+#include "components/tracing/common/trace_startup_config.h"
#include "components/tracing/common/trace_to_console.h"
#include "components/tracing/common/tracing_switches.h"
@@ -22,33 +22,22 @@ void EnableStartupTracingIfNeeded() {
// https://crbug.com/764357
base::trace_event::TraceLog::GetInstance();
- // Enables heap profiling if "--enable-heap-profiling" flag is passed.
- base::trace_event::MemoryDumpManager::GetInstance()
- ->EnableHeapProfilingIfNeeded();
-
- if (command_line.HasSwitch(switches::kTraceStartup)) {
- base::trace_event::TraceConfig trace_config(
- command_line.GetSwitchValueASCII(switches::kTraceStartup),
- command_line.GetSwitchValueASCII(switches::kTraceStartupRecordMode));
+ if (TraceStartupConfig::GetInstance()->IsEnabled()) {
+ const base::trace_event::TraceConfig& trace_config =
+ TraceStartupConfig::GetInstance()->GetTraceConfig();
+ uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
+ if (!trace_config.event_filters().empty())
+ modes |= base::trace_event::TraceLog::FILTERING_MODE;
+ // This checks kTraceConfigFile switch.
base::trace_event::TraceLog::GetInstance()->SetEnabled(
- trace_config, base::trace_event::TraceLog::RECORDING_MODE);
+ TraceStartupConfig::GetInstance()->GetTraceConfig(), modes);
} else if (command_line.HasSwitch(switches::kTraceToConsole)) {
- base::trace_event::TraceConfig trace_config =
- tracing::GetConfigForTraceToConsole();
+ base::trace_event::TraceConfig trace_config = GetConfigForTraceToConsole();
LOG(ERROR) << "Start " << switches::kTraceToConsole
<< " with CategoryFilter '"
<< trace_config.ToCategoryFilterString() << "'.";
base::trace_event::TraceLog::GetInstance()->SetEnabled(
trace_config, base::trace_event::TraceLog::RECORDING_MODE);
- } else if (tracing::TraceConfigFile::GetInstance()->IsEnabled()) {
- const base::trace_event::TraceConfig& trace_config =
- tracing::TraceConfigFile::GetInstance()->GetTraceConfig();
- uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
- if (!trace_config.event_filters().empty())
- modes |= base::trace_event::TraceLog::FILTERING_MODE;
- // This checks kTraceConfigFile switch.
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- tracing::TraceConfigFile::GetInstance()->GetTraceConfig(), modes);
}
}
diff --git a/chromium/components/tracing/common/trace_config_file.cc b/chromium/components/tracing/common/trace_startup_config.cc
index ff0745cfd5d..7a60710012c 100644
--- a/chromium/components/tracing/common/trace_config_file.cc
+++ b/chromium/components/tracing/common/trace_startup_config.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/tracing/common/trace_config_file.h"
+#include "components/tracing/common/trace_startup_config.h"
#include <stddef.h>
@@ -14,6 +14,7 @@
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
+#include "base/strings/string_number_conversions.h"
#include "base/values.h"
#include "build/build_config.h"
#include "components/tracing/common/tracing_switches.h"
@@ -33,9 +34,6 @@ const base::FilePath::CharType kAndroidTraceConfigFile[] =
FILE_PATH_LITERAL("/data/local/chrome-trace-config.json");
#endif
-const base::FilePath::CharType kDefaultResultFile[] =
- FILE_PATH_LITERAL("chrometrace.log");
-
// String parameters that can be used to parse the trace config file content.
const char kTraceConfigParam[] = "trace_config";
const char kStartupDurationParam[] = "startup_duration";
@@ -43,28 +41,47 @@ const char kResultFileParam[] = "result_file";
} // namespace
-TraceConfigFile* TraceConfigFile::GetInstance() {
- return base::Singleton<TraceConfigFile,
- base::DefaultSingletonTraits<TraceConfigFile>>::get();
+TraceStartupConfig* TraceStartupConfig::GetInstance() {
+ return base::Singleton<TraceStartupConfig, base::DefaultSingletonTraits<
+ TraceStartupConfig>>::get();
}
-TraceConfigFile::TraceConfigFile()
+TraceStartupConfig::TraceStartupConfig()
: is_enabled_(false),
trace_config_(base::trace_event::TraceConfig()),
startup_duration_(0),
- result_file_(kDefaultResultFile) {
+ result_file_() {
+ auto* command_line = base::CommandLine::ForCurrentProcess();
+
+ if (command_line->HasSwitch(switches::kTraceStartup)) {
+ std::string startup_duration_str =
+ command_line->GetSwitchValueASCII(switches::kTraceStartupDuration);
+ startup_duration_ = 5;
+ if (!startup_duration_str.empty() &&
+ !base::StringToInt(startup_duration_str, &startup_duration_)) {
+ DLOG(WARNING) << "Could not parse --" << switches::kTraceStartupDuration
+ << "=" << startup_duration_str << " defaulting to 5 (secs)";
+ startup_duration_ = 5;
+ }
+
+ trace_config_ = base::trace_event::TraceConfig(
+ command_line->GetSwitchValueASCII(switches::kTraceStartup),
+ command_line->GetSwitchValueASCII(switches::kTraceStartupRecordMode));
+
+ result_file_ =
+ command_line->GetSwitchValuePath(switches::kTraceStartupFile);
+
+ is_enabled_ = true;
+ return;
+ }
+
#if defined(OS_ANDROID)
base::FilePath trace_config_file(kAndroidTraceConfigFile);
#else
- const base::CommandLine& command_line =
- *base::CommandLine::ForCurrentProcess();
- if (!command_line.HasSwitch(switches::kTraceConfigFile) ||
- command_line.HasSwitch(switches::kTraceStartup) ||
- command_line.HasSwitch(switches::kTraceShutdown)) {
+ if (!command_line->HasSwitch(switches::kTraceConfigFile))
return;
- }
base::FilePath trace_config_file =
- command_line.GetSwitchValuePath(switches::kTraceConfigFile);
+ command_line->GetSwitchValuePath(switches::kTraceConfigFile);
#endif
if (trace_config_file.empty()) {
@@ -93,9 +110,10 @@ TraceConfigFile::TraceConfigFile()
DLOG(WARNING) << "Cannot parse the trace config file correctly.";
}
-TraceConfigFile::~TraceConfigFile() {}
+TraceStartupConfig::~TraceStartupConfig() = default;
-bool TraceConfigFile::ParseTraceConfigFileContent(const std::string& content) {
+bool TraceStartupConfig::ParseTraceConfigFileContent(
+ const std::string& content) {
std::unique_ptr<base::Value> value(base::JSONReader::Read(content));
if (!value || !value->is_dict())
return false;
@@ -122,26 +140,30 @@ bool TraceConfigFile::ParseTraceConfigFileContent(const std::string& content) {
return true;
}
-bool TraceConfigFile::IsEnabled() const {
+bool TraceStartupConfig::IsEnabled() const {
return is_enabled_;
}
-void TraceConfigFile::SetDisabled() {
+void TraceStartupConfig::SetDisabled() {
is_enabled_ = false;
}
-base::trace_event::TraceConfig TraceConfigFile::GetTraceConfig() const {
+bool TraceStartupConfig::IsTracingStartupForDuration() const {
+ return is_enabled_ && startup_duration_ > 0;
+}
+
+base::trace_event::TraceConfig TraceStartupConfig::GetTraceConfig() const {
DCHECK(IsEnabled());
return trace_config_;
}
-int TraceConfigFile::GetStartupDuration() const {
+int TraceStartupConfig::GetStartupDuration() const {
DCHECK(IsEnabled());
return startup_duration_;
}
#if !defined(OS_ANDROID)
-base::FilePath TraceConfigFile::GetResultFile() const {
+base::FilePath TraceStartupConfig::GetResultFile() const {
DCHECK(IsEnabled());
return result_file_;
}
diff --git a/chromium/components/tracing/common/trace_config_file.h b/chromium/components/tracing/common/trace_startup_config.h
index 145adc25d93..a5acfdc368c 100644
--- a/chromium/components/tracing/common/trace_config_file.h
+++ b/chromium/components/tracing/common/trace_startup_config.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 COMPONENTS_TRACING_COMMON_TRACE_CONFIG_FILE_H_
-#define COMPONENTS_TRACING_COMMON_TRACE_CONFIG_FILE_H_
+#ifndef COMPONENTS_TRACING_COMMON_TRACE_STARTUP_CONFIG_H_
+#define COMPONENTS_TRACING_COMMON_TRACE_STARTUP_CONFIG_H_
#include "base/files/file_path.h"
#include "base/macros.h"
@@ -18,9 +18,10 @@ struct DefaultSingletonTraits;
namespace tracing {
-// TraceConfigFile is a singleton that contains the configurations of tracing.
-// One can create a trace config file and use it to configure startup and/or
-// shutdown tracing.
+// TraceStartupConfig is a singleton that contains the configurations of startup
+// tracing. One can use --trace-startup flag or, for more complicated
+// configurations, create a trace config file and use it to configure startup
+// tracing.
//
// The trace config file should be JSON formated. One example is:
// {
@@ -54,10 +55,10 @@ namespace tracing {
//
// The trace config file can be specified by the --trace-config-file flag on
// most platforms except on Android, e.g., --trace-config-file=path/to/file/.
-// This flag should not be used with --trace-startup or --trace-shutdown. If
-// those two flags are used, --trace-config-file flag will be ignored. If the
-// --trace-config-file flag is used without the file path, Chrome will do
-// startup tracing with 5 seconds' startup duration.
+// This flag should not be used with --trace-startup; otherwise,
+// --trace-config-file flag will be ignored. If the --trace-config-file flag is
+// used without the file path, Chrome will do startup tracing with 5 seconds'
+// duration.
//
// On Android, Chrome does not read the --trace-config-file flag, because not
// all Chrome based browsers read customized flag, e.g., Android WebView. Chrome
@@ -65,23 +66,31 @@ namespace tracing {
// /data/local/chrome-trace-config.json
// If this file exists, Chrome will start tracing according to the configuration
// specified in the file, otherwise, Chrome will not start tracing.
+//
// In order for Chrome to read this file on Android M+, SE Linux mode must be
-// set to 0. Run "adb shell setenforce 0".
-// Note that on Android, the output path is ignored, and the result is emitted
-// to a location generated by TracingControllerAndroid::GenerateTracingFilePath.
-class TRACING_EXPORT TraceConfigFile {
+// set to 0. Run "adb shell setenforce 0". Note that on Android, the output path
+// is ignored, and the result is emitted to a location generated by
+// TracingControllerAndroid::GenerateTracingFilePath.
+class TRACING_EXPORT TraceStartupConfig {
public:
- static TraceConfigFile* GetInstance();
+ static TraceStartupConfig* GetInstance();
- // IsEnabled() returns true if a valid trace config file is specified and
- // either we are passed the trace duration, if it is positive, or startup
- // tracing is stopped by other means, e.g. via DevTools protocol.
+ // IsEnabled() returns true if
+ // - valid trace config file or trace startup flags are specified,
+ // - the specified startup duration is zero or we are not passed the positive
+ // startup duration, and
+ // - startup tracing is not stopped by other means, e.g. via DevTools
+ // protocol.
bool IsEnabled() const;
// SetDisabled() is used by the tracing controller to indicate that startup
// tracing is finished.
void SetDisabled();
+ // Returns true while startup tracing is not finished, if startup duration is
+ // positive.
+ bool IsTracingStartupForDuration() const;
+
base::trace_event::TraceConfig GetTraceConfig() const;
int GetStartupDuration() const;
#if !defined(OS_ANDROID)
@@ -91,9 +100,9 @@ class TRACING_EXPORT TraceConfigFile {
private:
// This allows constructor and destructor to be private and usable only
// by the Singleton class.
- friend struct base::DefaultSingletonTraits<TraceConfigFile>;
- TraceConfigFile();
- ~TraceConfigFile();
+ friend struct base::DefaultSingletonTraits<TraceStartupConfig>;
+ TraceStartupConfig();
+ ~TraceStartupConfig();
bool ParseTraceConfigFileContent(const std::string& content);
@@ -102,9 +111,9 @@ class TRACING_EXPORT TraceConfigFile {
int startup_duration_;
base::FilePath result_file_;
- DISALLOW_COPY_AND_ASSIGN(TraceConfigFile);
+ DISALLOW_COPY_AND_ASSIGN(TraceStartupConfig);
};
} // namespace tracing
-#endif // COMPONENTS_TRACING_COMMON_TRACE_CONFIG_FILE_H_
+#endif // COMPONENTS_TRACING_COMMON_TRACE_STARTUP_CONFIG_H_
diff --git a/chromium/components/tracing/common/trace_config_file_unittest.cc b/chromium/components/tracing/common/trace_startup_config_unittest.cc
index 471d676212c..0b9caf32adc 100644
--- a/chromium/components/tracing/common/trace_config_file_unittest.cc
+++ b/chromium/components/tracing/common/trace_startup_config_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/tracing/common/trace_config_file.h"
+#include "components/tracing/common/trace_startup_config.h"
#include "base/at_exit.h"
#include "base/command_line.h"
@@ -51,53 +51,40 @@ std::string GetTraceConfigFileContent(std::string trace_config,
} // namespace
-TEST(TraceConfigFileTest, TraceStartupEnabled) {
+TEST(TraceStartupConfigTest, TraceStartupEnabled) {
base::ShadowingAtExitManager sem;
base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kTraceStartup);
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kTraceConfigFile);
-
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
-}
-
-TEST(TraceConfigFileTest, TraceShutdownEnabled) {
- base::ShadowingAtExitManager sem;
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kTraceShutdown);
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kTraceConfigFile);
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled());
}
-TEST(TraceConfigFileTest, TraceConfigFileNotEnabled) {
+TEST(TraceStartupConfigTest, TraceStartupConfigNotEnabled) {
base::ShadowingAtExitManager sem;
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled());
}
-TEST(TraceConfigFileTest, TraceConfigFileEnabledWithoutPath) {
+TEST(TraceStartupConfigTest, TraceStartupConfigEnabledWithoutPath) {
base::ShadowingAtExitManager sem;
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kTraceConfigFile);
- ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled());
EXPECT_EQ(base::trace_event::TraceConfig().ToString(),
- TraceConfigFile::GetInstance()->GetTraceConfig().ToString());
- EXPECT_EQ(5, TraceConfigFile::GetInstance()->GetStartupDuration());
- EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")),
- TraceConfigFile::GetInstance()->GetResultFile());
+ TraceStartupConfig::GetInstance()->GetTraceConfig().ToString());
+ EXPECT_EQ(5, TraceStartupConfig::GetInstance()->GetStartupDuration());
+ EXPECT_TRUE(TraceStartupConfig::GetInstance()->GetResultFile().empty());
}
-TEST(TraceConfigFileTest, TraceConfigFileEnabledWithInvalidPath) {
+TEST(TraceStartupConfigTest, TraceStartupConfigEnabledWithInvalidPath) {
base::ShadowingAtExitManager sem;
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile,
base::FilePath(FILE_PATH_LITERAL("invalid-trace-config-file-path")));
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled());
}
-TEST(TraceConfigFileTest, ValidContent) {
+TEST(TraceStartupConfigTest, ValidContent) {
base::ShadowingAtExitManager sem;
std::string content =
GetTraceConfigFileContent(kTraceConfig, "10", "trace_result_file.log");
@@ -112,16 +99,16 @@ TEST(TraceConfigFileTest, ValidContent) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled());
EXPECT_STREQ(
kTraceConfig,
- TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str());
- EXPECT_EQ(10, TraceConfigFile::GetInstance()->GetStartupDuration());
+ TraceStartupConfig::GetInstance()->GetTraceConfig().ToString().c_str());
+ EXPECT_EQ(10, TraceStartupConfig::GetInstance()->GetStartupDuration());
EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("trace_result_file.log")),
- TraceConfigFile::GetInstance()->GetResultFile());
+ TraceStartupConfig::GetInstance()->GetResultFile());
}
-TEST(TraceConfigFileTest, ValidContentWithOnlyTraceConfig) {
+TEST(TraceStartupConfigTest, ValidContentWithOnlyTraceConfig) {
base::ShadowingAtExitManager sem;
std::string content = GetTraceConfigFileContent(kTraceConfig, "", "");
@@ -135,16 +122,15 @@ TEST(TraceConfigFileTest, ValidContentWithOnlyTraceConfig) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled());
EXPECT_STREQ(
kTraceConfig,
- TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str());
- EXPECT_EQ(0, TraceConfigFile::GetInstance()->GetStartupDuration());
- EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")),
- TraceConfigFile::GetInstance()->GetResultFile());
+ TraceStartupConfig::GetInstance()->GetTraceConfig().ToString().c_str());
+ EXPECT_EQ(0, TraceStartupConfig::GetInstance()->GetStartupDuration());
+ EXPECT_TRUE(TraceStartupConfig::GetInstance()->GetResultFile().empty());
}
-TEST(TraceConfigFileTest, ContentWithAbsoluteResultFilePath) {
+TEST(TraceStartupConfigTest, ContentWithAbsoluteResultFilePath) {
base::ShadowingAtExitManager sem;
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
@@ -171,11 +157,12 @@ TEST(TraceConfigFileTest, ContentWithAbsoluteResultFilePath) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
- EXPECT_EQ(result_file_path, TraceConfigFile::GetInstance()->GetResultFile());
+ ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled());
+ EXPECT_EQ(result_file_path,
+ TraceStartupConfig::GetInstance()->GetResultFile());
}
-TEST(TraceConfigFileTest, ContentWithNegtiveDuration) {
+TEST(TraceStartupConfigTest, ContentWithNegtiveDuration) {
base::ShadowingAtExitManager sem;
std::string content = GetTraceConfigFileContent(kTraceConfig, "-1", "");
@@ -189,16 +176,15 @@ TEST(TraceConfigFileTest, ContentWithNegtiveDuration) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ ASSERT_TRUE(TraceStartupConfig::GetInstance()->IsEnabled());
EXPECT_STREQ(
kTraceConfig,
- TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str());
- EXPECT_EQ(0, TraceConfigFile::GetInstance()->GetStartupDuration());
- EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")),
- TraceConfigFile::GetInstance()->GetResultFile());
+ TraceStartupConfig::GetInstance()->GetTraceConfig().ToString().c_str());
+ EXPECT_EQ(0, TraceStartupConfig::GetInstance()->GetStartupDuration());
+ EXPECT_TRUE(TraceStartupConfig::GetInstance()->GetResultFile().empty());
}
-TEST(TraceConfigFileTest, ContentWithoutTraceConfig) {
+TEST(TraceStartupConfigTest, ContentWithoutTraceConfig) {
base::ShadowingAtExitManager sem;
std::string content =
GetTraceConfigFileContent("", "10", "trace_result_file.log");
@@ -213,10 +199,10 @@ TEST(TraceConfigFileTest, ContentWithoutTraceConfig) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled());
}
-TEST(TraceConfigFileTest, InvalidContent) {
+TEST(TraceStartupConfigTest, InvalidContent) {
base::ShadowingAtExitManager sem;
std::string content = "invalid trace config file content";
@@ -230,10 +216,10 @@ TEST(TraceConfigFileTest, InvalidContent) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled());
}
-TEST(TraceConfigFileTest, EmptyContent) {
+TEST(TraceStartupConfigTest, EmptyContent) {
base::ShadowingAtExitManager sem;
base::FilePath trace_config_file;
base::ScopedTempDir temp_dir;
@@ -243,7 +229,7 @@ TEST(TraceConfigFileTest, EmptyContent) {
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
switches::kTraceConfigFile, trace_config_file);
- EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_FALSE(TraceStartupConfig::GetInstance()->IsEnabled());
}
} // namespace tracing
diff --git a/chromium/components/tracing/docs/heap_profiler_internals.md b/chromium/components/tracing/docs/heap_profiler_internals.md
deleted file mode 100644
index a54e7f30710..00000000000
--- a/chromium/components/tracing/docs/heap_profiler_internals.md
+++ /dev/null
@@ -1,2 +0,0 @@
-This document has moved to [//docs/memory-infra/heap_profiler_internals.md](/docs/memory-infra/heap_profiler_internals.md).
-
diff --git a/chromium/components/translate/content/common/BUILD.gn b/chromium/components/translate/content/common/BUILD.gn
index 0487c534829..a5b6a6787e8 100644
--- a/chromium/components/translate/content/common/BUILD.gn
+++ b/chromium/components/translate/content/common/BUILD.gn
@@ -10,7 +10,6 @@ mojom("common") {
]
public_deps = [
- "//mojo/common:common_custom_types",
"//mojo/public/mojom/base",
"//url/mojom:url_mojom_gurl",
]
diff --git a/chromium/components/translate/core/browser/BUILD.gn b/chromium/components/translate/core/browser/BUILD.gn
index d4a3cbe9b9c..54310351781 100644
--- a/chromium/components/translate/core/browser/BUILD.gn
+++ b/chromium/components/translate/core/browser/BUILD.gn
@@ -112,6 +112,7 @@ source_set("unit_tests") {
"//components/assist_ranker/proto",
"//components/infobars/core",
"//components/language/core/browser",
+ "//components/language/core/common:common",
"//components/pref_registry:pref_registry",
"//components/prefs",
"//components/prefs:test_support",
diff --git a/chromium/components/translate_strings_grdp/OWNERS b/chromium/components/translate_strings_grdp/OWNERS
new file mode 100644
index 00000000000..bb5c3afcabc
--- /dev/null
+++ b/chromium/components/translate_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/translate/OWNERS
diff --git a/chromium/components/translate_strings_grdp/README.md b/chromium/components/translate_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/translate_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/typemaps.gni b/chromium/components/typemaps.gni
index f53c80315b8..780ef767707 100644
--- a/chromium/components/typemaps.gni
+++ b/chromium/components/typemaps.gni
@@ -3,14 +3,13 @@
# found in the LICENSE file.
typemaps = [
+ "//components/account_id/interfaces/account_id.typemap",
"//components/autofill/content/common/autofill_types.typemap",
"//components/chrome_cleaner/public/typemaps/chrome_prompt.typemap",
"//components/content_settings/core/common/content_settings.typemap",
- "//components/services/leveldb/leveldb.typemap",
"//components/nacl/common/nacl.typemap",
"//components/password_manager/content/common/credential_manager.typemap",
- "//components/password_manager/public/interfaces/sync_password_data.typemap",
- "//components/signin/public/interfaces/account_id.typemap",
+ "//components/services/leveldb/leveldb.typemap",
"//components/spellcheck/common/spellcheck.typemap",
"//components/translate/content/common/translate.typemap",
]
diff --git a/chromium/components/ui_devtools/BUILD.gn b/chromium/components/ui_devtools/BUILD.gn
index beda6487380..4a8e106d037 100644
--- a/chromium/components/ui_devtools/BUILD.gn
+++ b/chromium/components/ui_devtools/BUILD.gn
@@ -19,7 +19,7 @@ _protocol_generated = [
action("protocol_compatibility") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
- script = "$_inspector_protocol/CheckProtocolCompatibility.py"
+ script = "$_inspector_protocol/check_protocol_compatibility.py"
inputs = [
"protocol.json",
]
@@ -89,7 +89,11 @@ component("ui_devtools") {
":protocol_generated_sources",
"//base",
"//net",
- "//net:http_server",
"//ui/gfx",
]
+
+ public_deps = [
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
+ ]
}
diff --git a/chromium/components/ui_devtools/DEPS b/chromium/components/ui_devtools/DEPS
index d733034f081..cb9c722cda5 100644
--- a/chromium/components/ui_devtools/DEPS
+++ b/chromium/components/ui_devtools/DEPS
@@ -1,6 +1,8 @@
include_rules = [
"+base",
"+net",
+ "+services/network/public/cpp",
+ "+services/network/public/mojom",
"+third_party/blink/renderer/platform/inspector_protocol",
"+ui/gfx",
]
diff --git a/chromium/components/ui_devtools/devtools_server.cc b/chromium/components/ui_devtools/devtools_server.cc
index dab9d68bd0f..294e430197e 100644
--- a/chromium/components/ui_devtools/devtools_server.cc
+++ b/chromium/components/ui_devtools/devtools_server.cc
@@ -13,13 +13,11 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "net/base/net_errors.h"
#include "net/log/net_log.h"
-#include "net/server/http_server_request_info.h"
-#include "net/socket/server_socket.h"
-#include "net/socket/tcp_server_socket.h"
+#include "services/network/public/cpp/server/http_server_request_info.h"
+#include "services/network/public/mojom/tcp_socket.mojom.h"
namespace ui_devtools {
@@ -69,44 +67,28 @@ constexpr net::NetworkTrafficAnnotationTag kUIDevtoolsServer =
UiDevToolsServer* UiDevToolsServer::devtools_server_ = nullptr;
-UiDevToolsServer::UiDevToolsServer(
- scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
- const char* enable_devtools_flag,
- int default_port)
- : io_thread_task_runner_(io_thread_task_runner),
- port_(GetUiDevToolsPort(enable_devtools_flag, default_port)) {
+UiDevToolsServer::UiDevToolsServer(const char* enable_devtools_flag,
+ int default_port)
+ : port_(GetUiDevToolsPort(enable_devtools_flag, default_port)),
+ weak_ptr_factory_(this) {
DCHECK(!devtools_server_);
- main_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
devtools_server_ = this;
- if (io_thread_task_runner_)
- return;
- // If io_thread_task_runner not passed in, create an I/O thread
- thread_.reset(new base::Thread("UiDevToolsServerThread"));
- base::Thread::Options options;
- options.message_loop_type = base::MessageLoop::TYPE_IO;
- CHECK(thread_->StartWithOptions(options));
- io_thread_task_runner_ = thread_->task_runner();
}
UiDevToolsServer::~UiDevToolsServer() {
- if (io_thread_task_runner_)
- io_thread_task_runner_->DeleteSoon(FROM_HERE, server_.release());
- if (thread_ && thread_->IsRunning())
- thread_->Stop();
devtools_server_ = nullptr;
}
// static
std::unique_ptr<UiDevToolsServer> UiDevToolsServer::Create(
- scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
+ network::mojom::NetworkContext* network_context,
const char* enable_devtools_flag,
int default_port) {
std::unique_ptr<UiDevToolsServer> server;
if (IsDevToolsEnabled(enable_devtools_flag) && !devtools_server_) {
// TODO(mhashmi): Change port if more than one inspectable clients
- server.reset(new UiDevToolsServer(io_thread_task_runner,
- enable_devtools_flag, default_port));
- server->Start("0.0.0.0");
+ server.reset(new UiDevToolsServer(enable_devtools_flag, default_port));
+ server->Start(network_context, "0.0.0.0");
}
return server;
}
@@ -129,32 +111,45 @@ UiDevToolsServer::GetClientNamesAndUrls() {
}
void UiDevToolsServer::AttachClient(std::unique_ptr<UiDevToolsClient> client) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
clients_.push_back(std::move(client));
}
void UiDevToolsServer::SendOverWebSocket(int connection_id,
const String& message) {
- io_thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&net::HttpServer::SendOverWebSocket,
- base::Unretained(server_.get()), connection_id,
- message, kUIDevtoolsServer));
-}
-
-void UiDevToolsServer::Start(const std::string& address_string) {
- io_thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&UiDevToolsServer::StartServer,
- base::Unretained(this), address_string));
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
+ server_->SendOverWebSocket(connection_id, message, kUIDevtoolsServer);
}
-void UiDevToolsServer::StartServer(const std::string& address_string) {
+void UiDevToolsServer::Start(network::mojom::NetworkContext* network_context,
+ const std::string& address_string) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
DCHECK(!server_);
- std::unique_ptr<net::ServerSocket> socket(
- new net::TCPServerSocket(nullptr, net::NetLogSource()));
- constexpr int kBacklog = 1;
- if (socket->ListenWithAddressAndPort(address_string, port_, kBacklog) !=
- net::OK)
+
+ network::mojom::TCPServerSocketPtr server_socket;
+ net::IPAddress address;
+
+ if (!address.AssignFromIPLiteral(address_string))
return;
- server_ = std::make_unique<net::HttpServer>(std::move(socket), this);
+
+ constexpr int kBacklog = 1;
+ network_context->CreateTCPServerSocket(
+ net::IPEndPoint(address, port_), kBacklog,
+ net::MutableNetworkTrafficAnnotationTag(kUIDevtoolsServer),
+ mojo::MakeRequest(&server_socket),
+ base::BindOnce(&UiDevToolsServer::MakeServer,
+ weak_ptr_factory_.GetWeakPtr(), std::move(server_socket)));
+}
+
+void UiDevToolsServer::MakeServer(
+ network::mojom::TCPServerSocketPtr server_socket,
+ int result,
+ const base::Optional<net::IPEndPoint>& local_addr) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
+ if (result == net::OK) {
+ server_ = std::make_unique<network::server::HttpServer>(
+ std::move(server_socket), this);
+ }
}
// HttpServer::Delegate Implementation
@@ -162,14 +157,16 @@ void UiDevToolsServer::OnConnect(int connection_id) {
NOTIMPLEMENTED();
}
-void UiDevToolsServer::OnHttpRequest(int connection_id,
- const net::HttpServerRequestInfo& info) {
+void UiDevToolsServer::OnHttpRequest(
+ int connection_id,
+ const network::server::HttpServerRequestInfo& info) {
NOTIMPLEMENTED();
}
void UiDevToolsServer::OnWebSocketRequest(
int connection_id,
- const net::HttpServerRequestInfo& info) {
+ const network::server::HttpServerRequestInfo& info) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
size_t target_id = 0;
if (info.path.empty() ||
!base::StringToSizeT(info.path.substr(1), &target_id) ||
@@ -182,32 +179,25 @@ void UiDevToolsServer::OnWebSocketRequest(
return;
client->set_connection_id(connection_id);
connections_[connection_id] = client;
- io_thread_task_runner_->PostTask(
- FROM_HERE, base::Bind(&net::HttpServer::AcceptWebSocket,
- base::Unretained(server_.get()), connection_id,
- info, kUIDevtoolsServer));
+ server_->AcceptWebSocket(connection_id, info, kUIDevtoolsServer);
}
void UiDevToolsServer::OnWebSocketMessage(int connection_id,
const std::string& data) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
ConnectionsMap::iterator it = connections_.find(connection_id);
DCHECK(it != connections_.end());
UiDevToolsClient* client = it->second;
- DCHECK(client);
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&UiDevToolsClient::Dispatch, base::Unretained(client), data));
+ client->Dispatch(data);
}
void UiDevToolsServer::OnClose(int connection_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(devtools_server_sequence_);
ConnectionsMap::iterator it = connections_.find(connection_id);
if (it == connections_.end())
return;
UiDevToolsClient* client = it->second;
- DCHECK(client);
- main_thread_task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&UiDevToolsClient::Disconnect, base::Unretained(client)));
+ client->Disconnect();
connections_.erase(it);
}
diff --git a/chromium/components/ui_devtools/devtools_server.h b/chromium/components/ui_devtools/devtools_server.h
index 14c3a155d3a..572ed3e6312 100644
--- a/chromium/components/ui_devtools/devtools_server.h
+++ b/chromium/components/ui_devtools/devtools_server.h
@@ -8,6 +8,7 @@
#include <vector>
#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "components/ui_devtools/DOM.h"
@@ -16,11 +17,12 @@
#include "components/ui_devtools/devtools_client.h"
#include "components/ui_devtools/devtools_export.h"
#include "components/ui_devtools/string_util.h"
-#include "net/server/http_server.h"
+#include "services/network/public/cpp/server/http_server.h"
namespace ui_devtools {
-class UI_DEVTOOLS_EXPORT UiDevToolsServer : public net::HttpServer::Delegate {
+class UI_DEVTOOLS_EXPORT UiDevToolsServer
+ : public network::server::HttpServer::Delegate {
public:
~UiDevToolsServer() override;
@@ -28,7 +30,7 @@ class UI_DEVTOOLS_EXPORT UiDevToolsServer : public net::HttpServer::Delegate {
// server instance has already been created. Server doesn't know anything
// about the caller, so both UI and Viz pass their corresponding params.
static std::unique_ptr<UiDevToolsServer> Create(
- scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
+ network::mojom::NetworkContext* network_context,
const char* enable_devtools_flag,
int default_port);
@@ -42,20 +44,22 @@ class UI_DEVTOOLS_EXPORT UiDevToolsServer : public net::HttpServer::Delegate {
int port() const { return port_; }
private:
- explicit UiDevToolsServer(
- scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
- const char* enable_devtools_flag,
- int default_port);
+ UiDevToolsServer(const char* enable_devtools_flag, int default_port);
- void Start(const std::string& address_string);
- void StartServer(const std::string& address_string);
+ void Start(network::mojom::NetworkContext* network_context,
+ const std::string& address_string);
+ void MakeServer(network::mojom::TCPServerSocketPtr server_socket,
+ int result,
+ const base::Optional<net::IPEndPoint>& local_addr);
// HttpServer::Delegate
void OnConnect(int connection_id) override;
- void OnHttpRequest(int connection_id,
- const net::HttpServerRequestInfo& info) override;
- void OnWebSocketRequest(int connection_id,
- const net::HttpServerRequestInfo& info) override;
+ void OnHttpRequest(
+ int connection_id,
+ const network::server::HttpServerRequestInfo& info) override;
+ void OnWebSocketRequest(
+ int connection_id,
+ const network::server::HttpServerRequestInfo& info) override;
void OnWebSocketMessage(int connection_id, const std::string& data) override;
void OnClose(int connection_id) override;
@@ -64,10 +68,7 @@ class UI_DEVTOOLS_EXPORT UiDevToolsServer : public net::HttpServer::Delegate {
ClientsList clients_;
ConnectionsMap connections_;
- std::unique_ptr<base::Thread> thread_;
- std::unique_ptr<net::HttpServer> server_;
- scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner_;
- scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
+ std::unique_ptr<network::server::HttpServer> server_;
// The port the devtools server listens on
const int port_;
@@ -75,6 +76,9 @@ class UI_DEVTOOLS_EXPORT UiDevToolsServer : public net::HttpServer::Delegate {
// The server (owned by ash for now)
static UiDevToolsServer* devtools_server_;
+ SEQUENCE_CHECKER(devtools_server_sequence_);
+ base::WeakPtrFactory<UiDevToolsServer> weak_ptr_factory_;
+
DISALLOW_COPY_AND_ASSIGN(UiDevToolsServer);
};
diff --git a/chromium/components/ui_devtools/ui_element.cc b/chromium/components/ui_devtools/ui_element.cc
index 9981a9120c7..617e611a9d2 100644
--- a/chromium/components/ui_devtools/ui_element.cc
+++ b/chromium/components/ui_devtools/ui_element.cc
@@ -32,6 +32,8 @@ std::string UIElement::GetTypeName() const {
return "Widget";
case UIElementType::VIEW:
return "View";
+ case UIElementType::FRAMESINK:
+ return "FrameSink";
}
NOTREACHED();
return std::string();
diff --git a/chromium/components/ui_devtools/ui_element.h b/chromium/components/ui_devtools/ui_element.h
index 9e2216ef4a6..4798c8b4f34 100644
--- a/chromium/components/ui_devtools/ui_element.h
+++ b/chromium/components/ui_devtools/ui_element.h
@@ -23,7 +23,7 @@ class Array;
}
// UIElement type.
-enum UIElementType { WINDOW, WIDGET, VIEW, ROOT };
+enum UIElementType { WINDOW, WIDGET, VIEW, ROOT, FRAMESINK };
class UI_DEVTOOLS_EXPORT UIElement {
public:
diff --git a/chromium/components/ui_devtools/viz_views/BUILD.gn b/chromium/components/ui_devtools/viz_views/BUILD.gn
new file mode 100644
index 00000000000..804301f947a
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/BUILD.gn
@@ -0,0 +1,21 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//components/viz/viz.gni")
+
+source_set("viz_views") {
+ sources = [
+ "dom_agent_viz.cc",
+ "dom_agent_viz.h",
+ "frame_sink_element.cc",
+ "frame_sink_element.h",
+ "overlay_agent_viz.cc",
+ "overlay_agent_viz.h",
+ ]
+
+ deps = [
+ "//components/ui_devtools",
+ "//components/viz/service",
+ ]
+}
diff --git a/chromium/components/ui_devtools/viz_views/DEPS b/chromium/components/ui_devtools/viz_views/DEPS
new file mode 100644
index 00000000000..09a70199c2e
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/viz/common",
+ "+components/viz/service",
+]
diff --git a/chromium/components/ui_devtools/viz_views/dom_agent_viz.cc b/chromium/components/ui_devtools/viz_views/dom_agent_viz.cc
new file mode 100644
index 00000000000..e325daa827f
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/dom_agent_viz.cc
@@ -0,0 +1,148 @@
+// 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 "components/ui_devtools/viz_views/dom_agent_viz.h"
+
+#include "components/ui_devtools/root_element.h"
+#include "components/ui_devtools/ui_element.h"
+#include "components/ui_devtools/viz_views/frame_sink_element.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+
+namespace ui_devtools {
+
+using namespace ui_devtools::protocol;
+
+DOMAgentViz::DOMAgentViz(viz::FrameSinkManagerImpl* frame_sink_manager)
+ : frame_sink_manager_(frame_sink_manager) {}
+
+DOMAgentViz::~DOMAgentViz() {
+ Clear();
+}
+
+std::unique_ptr<DOM::Node> DOMAgentViz::BuildTreeForFrameSink(
+ UIElement* frame_sink_element,
+ const viz::FrameSinkId& frame_sink_id) {
+ frame_sink_elements_.emplace(frame_sink_id, frame_sink_element);
+ std::unique_ptr<Array<DOM::Node>> children = Array<DOM::Node>::create();
+
+ // Once the FrameSinkElement is created it calls this function to build its
+ // subtree. So we iterate through |frame_sink_element|'s children and
+ // recursively build the subtree for them.
+ for (auto& child : frame_sink_manager_->GetChildrenByParent(frame_sink_id)) {
+ bool is_registered = registered_frame_sink_ids_.find(child) !=
+ registered_frame_sink_ids_.end();
+ bool is_client_connected = client_connected_frame_sinks_.find(child) !=
+ client_connected_frame_sinks_.end();
+
+ UIElement* f_s_element = new FrameSinkElement(
+ child, frame_sink_manager_, this, frame_sink_element, false /*is_root*/,
+ is_registered, is_client_connected);
+
+ children->addItem(BuildTreeForFrameSink(f_s_element, child));
+ frame_sink_element->AddChild(f_s_element);
+ }
+ std::unique_ptr<DOM::Node> node =
+ BuildNode("FrameSink", frame_sink_element->GetAttributes(),
+ std::move(children), frame_sink_element->node_id());
+ return node;
+}
+
+protocol::Response DOMAgentViz::enable() {
+ InitFrameSinkSets();
+ return protocol::Response::OK();
+}
+
+protocol::Response DOMAgentViz::disable() {
+ Clear();
+ return DOMAgent::disable();
+}
+
+std::vector<UIElement*> DOMAgentViz::CreateChildrenForRoot() {
+ std::vector<UIElement*> children;
+
+ // Step 1. Add created RootFrameSinks and detached FrameSinks.
+ for (auto& frame_sink_id : client_connected_frame_sinks_) {
+ const viz::CompositorFrameSinkSupport* support =
+ frame_sink_manager_->GetFrameSinkForId(frame_sink_id);
+ // Do nothing if it's a non-detached non-root FrameSink.
+ if (support && !support->is_root() &&
+ attached_frame_sinks_.find(frame_sink_id) !=
+ attached_frame_sinks_.end())
+ continue;
+
+ bool is_registered = registered_frame_sink_ids_.find(frame_sink_id) !=
+ registered_frame_sink_ids_.end();
+ bool is_root = support && support->is_root();
+
+ UIElement* frame_sink_element = new FrameSinkElement(
+ frame_sink_id, frame_sink_manager_, this, element_root(), is_root,
+ is_registered, true /*is_client_connected*/);
+ children.push_back(frame_sink_element);
+ }
+
+ // Step 2. Add registered but not created FrameSinks. If a FrameSinkId was
+ // registered but not created we don't really know whether it's a root or not.
+ // And we don't know any information about the hierarchy. Therefore we process
+ // FrameSinks that are in the correct state first and only after that we
+ // process registered but not created FrameSinks. We consider them unembedded
+ // as well.
+ for (auto& frame_sink_id : registered_frame_sink_ids_) {
+ if (client_connected_frame_sinks_.find(frame_sink_id) !=
+ client_connected_frame_sinks_.end())
+ continue;
+
+ UIElement* frame_sink_element = new FrameSinkElement(
+ frame_sink_id, frame_sink_manager_, this, element_root(),
+ false /*is_root*/, true /*is_registered*/,
+ false /*is_client_connected*/);
+
+ children.push_back(frame_sink_element);
+ }
+
+ return children;
+}
+
+std::unique_ptr<DOM::Node> DOMAgentViz::BuildTreeForUIElement(
+ UIElement* ui_element) {
+ if (ui_element->type() == UIElementType::FRAMESINK) {
+ return BuildTreeForFrameSink(ui_element,
+ FrameSinkElement::From(ui_element));
+ }
+ return nullptr;
+}
+
+void DOMAgentViz::Clear() {
+ attached_frame_sinks_.clear();
+ client_connected_frame_sinks_.clear();
+ frame_sink_elements_.clear();
+ registered_frame_sink_ids_.clear();
+}
+
+void DOMAgentViz::InitFrameSinkSets() {
+ for (auto& entry : frame_sink_manager_->GetRegisteredFrameSinkIds())
+ registered_frame_sink_ids_.insert(entry);
+ for (auto& entry : frame_sink_manager_->GetCreatedFrameSinkIds())
+ client_connected_frame_sinks_.insert(entry);
+
+ // Init the |attached_frame_sinks_| set. All RootFrameSinks and accessible
+ // from roots are attached. All the others are detached.
+ for (auto& frame_sink_id : client_connected_frame_sinks_) {
+ const viz::CompositorFrameSinkSupport* support =
+ frame_sink_manager_->GetFrameSinkForId(frame_sink_id);
+ // Start only from roots.
+ if (!support || !support->is_root())
+ continue;
+
+ SetAttachedFrameSink(frame_sink_id);
+ }
+}
+
+void DOMAgentViz::SetAttachedFrameSink(const viz::FrameSinkId& frame_sink_id) {
+ attached_frame_sinks_.insert(frame_sink_id);
+ for (auto& child : frame_sink_manager_->GetChildrenByParent(frame_sink_id))
+ SetAttachedFrameSink(child);
+}
+
+} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/viz_views/dom_agent_viz.h b/chromium/components/ui_devtools/viz_views/dom_agent_viz.h
new file mode 100644
index 00000000000..66bead1baa8
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/dom_agent_viz.h
@@ -0,0 +1,71 @@
+// 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 COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_DOM_AGENT_VIZ_H_
+#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_DOM_AGENT_VIZ_H_
+
+#include "base/containers/flat_map.h"
+#include "base/containers/flat_set.h"
+#include "components/ui_devtools/DOM.h"
+#include "components/ui_devtools/dom_agent.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+
+namespace viz {
+class FrameSinkManagerImpl;
+}
+
+namespace ui_devtools {
+
+class DOMAgentViz : public DOMAgent {
+ public:
+ explicit DOMAgentViz(viz::FrameSinkManagerImpl* frame_sink_manager);
+ ~DOMAgentViz() override;
+
+ private:
+ std::unique_ptr<protocol::DOM::Node> BuildTreeForFrameSink(
+ UIElement* frame_sink_element,
+ const viz::FrameSinkId& frame_sink_id);
+
+ // DOM::Backend:
+ protocol::Response enable() override;
+ protocol::Response disable() override;
+
+ // DOMAgent:
+ std::vector<UIElement*> CreateChildrenForRoot() override;
+ std::unique_ptr<protocol::DOM::Node> BuildTreeForUIElement(
+ UIElement* ui_element) override;
+
+ // Every time the frontend disconnects we don't destroy DOMAgent so once we
+ // establish the connection again we need to clear the FrameSinkId sets
+ // because they may carry obsolete data. Then we initialize these with alive
+ // FrameSinkIds. Clears the sets of FrameSinkIds that correspond to created
+ // FrameSinks, registered FrameSinkIds and those that have corresponding
+ // FrameSinkElements created.
+ void Clear();
+ // Initializes the sets of FrameSinkIds that correspond to registered
+ // FrameSinkIds and created FrameSinks.
+ void InitFrameSinkSets();
+
+ // Mark a FrameSink that has |frame_sink_id| and all its subtree as attached.
+ void SetAttachedFrameSink(const viz::FrameSinkId& frame_sink_id);
+
+ // These sets are used to create and update the DOM tree.
+ base::flat_set<viz::FrameSinkId> registered_frame_sink_ids_;
+ base::flat_set<viz::FrameSinkId> client_connected_frame_sinks_;
+
+ // This is used to track created FrameSinkElements and will be used for
+ // updates in a FrameSink tree.
+ base::flat_map<viz::FrameSinkId, UIElement*> frame_sink_elements_;
+
+ // This is used to denote attached FrameSinks.
+ base::flat_set<viz::FrameSinkId> attached_frame_sinks_;
+
+ viz::FrameSinkManagerImpl* frame_sink_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(DOMAgentViz);
+};
+
+} // namespace ui_devtools
+
+#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_DOM_AGENT_VIZ_H_
diff --git a/chromium/components/ui_devtools/viz_views/frame_sink_element.cc b/chromium/components/ui_devtools/viz_views/frame_sink_element.cc
new file mode 100644
index 00000000000..8298c13324c
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/frame_sink_element.cc
@@ -0,0 +1,111 @@
+// 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 "components/ui_devtools/viz_views/frame_sink_element.h"
+
+#include "components/ui_devtools/Protocol.h"
+#include "components/ui_devtools/ui_element_delegate.h"
+#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
+#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
+#include "components/viz/service/surfaces/surface.h"
+#include "components/viz/service/surfaces/surface_manager.h"
+
+namespace ui_devtools {
+
+FrameSinkElement::FrameSinkElement(
+ const viz::FrameSinkId& frame_sink_id,
+ viz::FrameSinkManagerImpl* frame_sink_manager,
+ UIElementDelegate* ui_element_delegate,
+ UIElement* parent,
+ bool is_root,
+ bool is_registered,
+ bool is_client_connected)
+ : UIElement(UIElementType::FRAMESINK, ui_element_delegate, parent),
+ frame_sink_id_(frame_sink_id),
+ frame_sink_manager_(frame_sink_manager),
+ is_root_(is_root),
+ is_registered_(is_registered),
+ is_client_connected_(is_client_connected) {}
+
+FrameSinkElement::~FrameSinkElement() {}
+
+std::vector<std::pair<std::string, std::string>>
+FrameSinkElement::GetCustomProperties() const {
+ std::vector<std::pair<std::string, std::string>> v;
+
+ // Hierarchical information about the FrameSink.
+ v.push_back(std::make_pair("Is root", is_root_ ? "true" : "false"));
+ v.push_back(
+ std::make_pair("Is registered", is_registered_ ? "true" : "false"));
+ v.push_back(std::make_pair("Is connected by client",
+ is_client_connected_ ? "true" : "false"));
+
+ // LastUsedBeingFrameArgs information.
+ const viz::CompositorFrameSinkSupport* support =
+ frame_sink_manager_->GetFrameSinkForId(frame_sink_id_);
+ if (support) {
+ const viz::BeginFrameArgs args =
+ static_cast<const viz::BeginFrameObserver*>(support)
+ ->LastUsedBeginFrameArgs();
+ v.push_back(std::make_pair("SourceId", std::to_string(args.source_id)));
+ v.push_back(
+ std::make_pair("SequenceNumber", std::to_string(args.sequence_number)));
+ v.push_back(std::make_pair(
+ "FrameType",
+ std::string(viz::BeginFrameArgs::TypeToString(args.type))));
+ }
+ return v;
+}
+
+void FrameSinkElement::GetBounds(gfx::Rect* bounds) const {
+ const viz::CompositorFrameSinkSupport* support =
+ frame_sink_manager_->GetFrameSinkForId(frame_sink_id_);
+ if (!support) {
+ *bounds = gfx::Rect();
+ return;
+ }
+
+ // Get just size of last activated surface that corresponds to this frame
+ // sink.
+ viz::Surface* srfc = frame_sink_manager_->surface_manager()->GetSurfaceForId(
+ support->last_activated_surface_id());
+ if (srfc)
+ *bounds = gfx::Rect(srfc->size_in_pixels());
+ else
+ *bounds = gfx::Rect();
+}
+
+void FrameSinkElement::SetBounds(const gfx::Rect& bounds) {}
+
+void FrameSinkElement::GetVisible(bool* visible) const {
+ // Currently not real data.
+ *visible = true;
+}
+
+void FrameSinkElement::SetVisible(bool visible) {}
+
+std::unique_ptr<protocol::Array<std::string>> FrameSinkElement::GetAttributes()
+ const {
+ auto attributes = protocol::Array<std::string>::create();
+ attributes->addItem("FrameSinkId");
+ attributes->addItem(frame_sink_id_.ToString());
+ attributes->addItem("Title");
+ attributes->addItem(
+ frame_sink_manager_->surface_manager()->GetFrameSinkDebugLabel(
+ frame_sink_id_));
+ return attributes;
+}
+
+std::pair<gfx::NativeWindow, gfx::Rect>
+FrameSinkElement::GetNodeWindowAndBounds() const {
+ return {};
+}
+
+// static
+const viz::FrameSinkId& FrameSinkElement::From(const UIElement* element) {
+ DCHECK_EQ(UIElementType::FRAMESINK, element->type());
+ return static_cast<const FrameSinkElement*>(element)->frame_sink_id_;
+}
+
+} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/viz_views/frame_sink_element.h b/chromium/components/ui_devtools/viz_views/frame_sink_element.h
new file mode 100644
index 00000000000..b0cfc9a12a6
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/frame_sink_element.h
@@ -0,0 +1,61 @@
+// 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 COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_FRAME_SINK_ELEMENT_H_
+#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_FRAME_SINK_ELEMENT_H_
+
+#include "base/macros.h"
+#include "components/ui_devtools/ui_element.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+
+namespace viz {
+class FrameSinkManagerImpl;
+}
+
+namespace ui_devtools {
+
+class FrameSinkElement : public UIElement {
+ public:
+ FrameSinkElement(const viz::FrameSinkId& frame_sink_id,
+ viz::FrameSinkManagerImpl* frame_sink_manager,
+ UIElementDelegate* ui_element_delegate,
+ UIElement* parent,
+ bool is_root,
+ bool is_registered,
+ bool is_client_connected);
+ ~FrameSinkElement() override;
+
+ // UIElement:
+ std::vector<std::pair<std::string, std::string>> GetCustomProperties()
+ const override;
+ void GetBounds(gfx::Rect* bounds) const override;
+ void SetBounds(const gfx::Rect& bounds) override;
+ void GetVisible(bool* visible) const override;
+ void SetVisible(bool visible) override;
+ std::unique_ptr<protocol::Array<std::string>> GetAttributes() const override;
+ std::pair<gfx::NativeWindow, gfx::Rect> GetNodeWindowAndBounds()
+ const override;
+
+ static const viz::FrameSinkId& From(const UIElement* element);
+
+ private:
+ const viz::FrameSinkId frame_sink_id_;
+ viz::FrameSinkManagerImpl* frame_sink_manager_;
+
+ // Properties of the FrameSink. If element is a RootFrameSink then it has
+ // |is_root_| = true. If element is not a root than it has |is_root_| = false.
+ // If an element is a sibling of a RootFrameSink but has property |is_root_| =
+ // false then it is considered detached. If the FrameSink was registered then
+ // corresponding element's |is_registered_| = true. If a FrameSink was created
+ // then |is_client_connected_| = true.
+ bool is_root_;
+ bool is_registered_;
+ bool is_client_connected_;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameSinkElement);
+};
+
+} // namespace ui_devtools
+
+#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_FRAME_SINK_ELEMENT_H_
diff --git a/chromium/components/ui_devtools/viz_views/overlay_agent_viz.cc b/chromium/components/ui_devtools/viz_views/overlay_agent_viz.cc
new file mode 100644
index 00000000000..058db6cf9fd
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/overlay_agent_viz.cc
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/ui_devtools/viz_views/overlay_agent_viz.h"
+
+namespace ui_devtools {
+
+OverlayAgentViz::OverlayAgentViz(DOMAgentViz* dom_agent)
+ : OverlayAgent(dom_agent) {}
+
+OverlayAgentViz::~OverlayAgentViz() {}
+
+protocol::Response OverlayAgentViz::setInspectMode(
+ const String& in_mode,
+ protocol::Maybe<protocol::Overlay::HighlightConfig> in_highlightConfig) {
+ return protocol::Response::OK();
+}
+
+protocol::Response OverlayAgentViz::highlightNode(
+ std::unique_ptr<protocol::Overlay::HighlightConfig> highlight_config,
+ protocol::Maybe<int> node_id) {
+ return protocol::Response::OK();
+}
+
+protocol::Response OverlayAgentViz::hideHighlight() {
+ return protocol::Response::OK();
+}
+
+} // namespace ui_devtools
diff --git a/chromium/components/ui_devtools/viz_views/overlay_agent_viz.h b/chromium/components/ui_devtools/viz_views/overlay_agent_viz.h
new file mode 100644
index 00000000000..ef4dcdccc79
--- /dev/null
+++ b/chromium/components/ui_devtools/viz_views/overlay_agent_viz.h
@@ -0,0 +1,35 @@
+// 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 COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_OVERLAY_AGENT_VIZ_H_
+#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_OVERLAY_AGENT_VIZ_H_
+
+#include "components/ui_devtools/Overlay.h"
+#include "components/ui_devtools/overlay_agent.h"
+#include "components/ui_devtools/viz_views/dom_agent_viz.h"
+
+namespace ui_devtools {
+
+class OverlayAgentViz : public OverlayAgent {
+ public:
+ explicit OverlayAgentViz(DOMAgentViz* dom_agent);
+ ~OverlayAgentViz() override;
+
+ // Overlay::Backend:
+ protocol::Response setInspectMode(
+ const String& in_mode,
+ protocol::Maybe<protocol::Overlay::HighlightConfig> in_highlightConfig)
+ override;
+ protocol::Response highlightNode(
+ std::unique_ptr<protocol::Overlay::HighlightConfig> highlight_config,
+ protocol::Maybe<int> node_id) override;
+ protocol::Response hideHighlight() override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(OverlayAgentViz);
+};
+
+} // namespace ui_devtools
+
+#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_OVERLAY_AGENT_VIZ_H_
diff --git a/chromium/components/ukm/BUILD.gn b/chromium/components/ukm/BUILD.gn
index 2367f2eb497..2f7e20991cf 100644
--- a/chromium/components/ukm/BUILD.gn
+++ b/chromium/components/ukm/BUILD.gn
@@ -27,6 +27,7 @@ static_library("ukm") {
public_deps = [
"//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//services/metrics/public/mojom",
"//third_party/metrics_proto",
]
@@ -92,6 +93,7 @@ source_set("unit_tests") {
"//components/metrics",
"//components/metrics:test_support",
"//components/prefs:test_support",
+ "//components/sync",
"//components/sync:test_support_driver",
"//components/variations",
"//net:test_support",
@@ -107,7 +109,7 @@ test("ukm_unittests") {
deps = [
":unit_tests",
"//base",
- "//base/test:run_all_unittests",
"//base/test:test_support",
+ "//components/test:run_all_unittests",
]
}
diff --git a/chromium/components/ukm/content/BUILD.gn b/chromium/components/ukm/content/BUILD.gn
index 8708c14296a..203c75cd0d6 100644
--- a/chromium/components/ukm/content/BUILD.gn
+++ b/chromium/components/ukm/content/BUILD.gn
@@ -11,6 +11,7 @@ static_library("content") {
"//base",
"//content/public/browser",
"//services/metrics/public/cpp:metrics_cpp",
+ "//services/metrics/public/cpp:ukm_builders",
"//services/metrics/public/mojom",
"//url",
]
diff --git a/chromium/components/ukm/content/DEPS b/chromium/components/ukm/content/DEPS
index e8d9654d8b6..a92b1c9805e 100644
--- a/chromium/components/ukm/content/DEPS
+++ b/chromium/components/ukm/content/DEPS
@@ -3,4 +3,5 @@ include_rules = [
"+content/public/common",
"+content/public/test",
"+content/shell",
+ "+third_party/blink/public/platform/ukm.mojom.h",
]
diff --git a/chromium/components/ukm/content/source_url_recorder.cc b/chromium/components/ukm/content/source_url_recorder.cc
index bfc762f6cfe..3ca862510f4 100644
--- a/chromium/components/ukm/content/source_url_recorder.cc
+++ b/chromium/components/ukm/content/source_url_recorder.cc
@@ -10,10 +10,13 @@
#include "base/macros.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_binding_set.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
-#include "services/metrics/public/cpp/ukm_recorder.h"
+#include "services/metrics/public/cpp/delegating_ukm_recorder.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "third_party/blink/public/platform/ukm.mojom.h"
#include "url/gurl.h"
namespace ukm {
@@ -25,7 +28,8 @@ namespace internal {
// SourceUrlRecorderWebContentsObserver records both the final URL for a
// navigation, and, if the navigation was redirected, the initial URL as well.
class SourceUrlRecorderWebContentsObserver
- : public content::WebContentsObserver,
+ : public blink::mojom::UkmSourceIdFrameHost,
+ public content::WebContentsObserver,
public content::WebContentsUserData<
SourceUrlRecorderWebContentsObserver> {
public:
@@ -41,18 +45,32 @@ class SourceUrlRecorderWebContentsObserver
ukm::SourceId GetLastCommittedSourceId() const;
+ // blink::mojom::UkmSourceIdFrameHost
+ void SetDocumentSourceId(int64_t source_id) override;
+
private:
explicit SourceUrlRecorderWebContentsObserver(
content::WebContents* web_contents);
friend class content::WebContentsUserData<
SourceUrlRecorderWebContentsObserver>;
+ // Record any pending DocumentCreated events to UKM.
+ void MaybeFlushPendingEvents();
+
void MaybeRecordUrl(content::NavigationHandle* navigation_handle,
const GURL& initial_url);
+ // Recieves document source IDs from the renderer.
+ content::WebContentsFrameBindingSet<blink::mojom::UkmSourceIdFrameHost>
+ bindings_;
+
// Map from navigation ID to the initial URL for that navigation.
base::flat_map<int64_t, GURL> pending_navigations_;
+ // Holds pending DocumentCreated events.
+ using PendingEvent = std::pair<int64_t, bool>;
+ std::vector<PendingEvent> pending_document_created_events_;
+
int64_t last_committed_source_id_;
DISALLOW_COPY_AND_ASSIGN(SourceUrlRecorderWebContentsObserver);
@@ -61,6 +79,7 @@ class SourceUrlRecorderWebContentsObserver
SourceUrlRecorderWebContentsObserver::SourceUrlRecorderWebContentsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
+ bindings_(web_contents, this),
last_committed_source_id_(ukm::kInvalidSourceId) {}
void SourceUrlRecorderWebContentsObserver::DidStartNavigation(
@@ -81,6 +100,9 @@ void SourceUrlRecorderWebContentsObserver::DidStartNavigation(
// in a download.
pending_navigations_.insert(std::make_pair(
navigation_handle->GetNavigationId(), navigation_handle->GetURL()));
+
+ // Clear any unassociated pending events.
+ pending_document_created_events_.clear();
}
void SourceUrlRecorderWebContentsObserver::DidFinishNavigation(
@@ -105,6 +127,8 @@ void SourceUrlRecorderWebContentsObserver::DidFinishNavigation(
return;
MaybeRecordUrl(navigation_handle, initial_url);
+
+ MaybeFlushPendingEvents();
}
ukm::SourceId SourceUrlRecorderWebContentsObserver::GetLastCommittedSourceId()
@@ -112,23 +136,50 @@ ukm::SourceId SourceUrlRecorderWebContentsObserver::GetLastCommittedSourceId()
return last_committed_source_id_;
}
+void SourceUrlRecorderWebContentsObserver::SetDocumentSourceId(
+ int64_t source_id) {
+ pending_document_created_events_.emplace_back(
+ source_id, !bindings_.GetCurrentTargetFrame()->GetParent());
+ MaybeFlushPendingEvents();
+}
+
+void SourceUrlRecorderWebContentsObserver::MaybeFlushPendingEvents() {
+ if (!last_committed_source_id_)
+ return;
+
+ ukm::DelegatingUkmRecorder* ukm_recorder = ukm::DelegatingUkmRecorder::Get();
+ if (!ukm_recorder)
+ return;
+
+ while (!pending_document_created_events_.empty()) {
+ auto record = pending_document_created_events_.back();
+
+ ukm::builders::DocumentCreated(record.first)
+ .SetNavigationSourceId(last_committed_source_id_)
+ .SetIsMainFrame(record.second)
+ .Record(ukm_recorder);
+
+ pending_document_created_events_.pop_back();
+ }
+}
+
void SourceUrlRecorderWebContentsObserver::MaybeRecordUrl(
content::NavigationHandle* navigation_handle,
const GURL& initial_url) {
DCHECK(navigation_handle->IsInMainFrame());
DCHECK(!navigation_handle->IsSameDocument());
- ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
+ ukm::DelegatingUkmRecorder* ukm_recorder = ukm::DelegatingUkmRecorder::Get();
if (!ukm_recorder)
return;
const ukm::SourceId source_id = ukm::ConvertToSourceId(
navigation_handle->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID);
- ukm_recorder->UpdateSourceURL(source_id, initial_url);
+ ukm_recorder->UpdateNavigationURL(source_id, initial_url);
const GURL& final_url = navigation_handle->GetURL();
if (final_url != initial_url)
- ukm_recorder->UpdateSourceURL(source_id, final_url);
+ ukm_recorder->UpdateNavigationURL(source_id, final_url);
}
// static
diff --git a/chromium/components/ukm/content/source_url_recorder_browsertest.cc b/chromium/components/ukm/content/source_url_recorder_browsertest.cc
index bb37e781e78..6022a8b5384 100644
--- a/chromium/components/ukm/content/source_url_recorder_browsertest.cc
+++ b/chromium/components/ukm/content/source_url_recorder_browsertest.cc
@@ -16,6 +16,7 @@
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_browser_context.h"
#include "content/shell/browser/shell_download_manager_delegate.h"
+#include "services/metrics/public/cpp/ukm_builders.h"
class SourceUrlRecorderWebContentsObserverBrowserTest
: public content::ContentBrowserTest {
@@ -48,6 +49,10 @@ class SourceUrlRecorderWebContentsObserverBrowserTest
return src ? src->url() : GURL();
}
+ const ukm::TestAutoSetUkmRecorder& test_ukm_recorder() const {
+ return *test_ukm_recorder_;
+ }
+
private:
base::test::ScopedFeatureList scoped_feature_list_;
std::unique_ptr<ukm::TestAutoSetUkmRecorder> test_ukm_recorder_;
@@ -78,6 +83,8 @@ class SourceUrlRecorderWebContentsObserverDownloadBrowserTest
};
IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest, Basic) {
+ using Entry = ukm::builders::DocumentCreated;
+
GURL url = embedded_test_server()->GetURL("/title1.html");
content::NavigationHandleObserver observer(shell()->web_contents(), url);
content::NavigateToURL(shell(), url);
@@ -89,10 +96,21 @@ IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest, Basic) {
EXPECT_TRUE(source->initial_url().is_empty());
EXPECT_EQ(url, GetAssociatedURLForWebContentsDocument());
+
+ // Check we have created a DocumentCreated event.
+ auto ukm_entries = test_ukm_recorder().GetEntriesByName(Entry::kEntryName);
+ EXPECT_EQ(1u, ukm_entries.size());
+ EXPECT_EQ(source->id(), *test_ukm_recorder().GetEntryMetric(
+ ukm_entries[0], Entry::kNavigationSourceIdName));
+ EXPECT_EQ(1, *test_ukm_recorder().GetEntryMetric(ukm_entries[0],
+ Entry::kIsMainFrameName));
+ EXPECT_NE(source->id(), ukm_entries[0]->source_id);
}
IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest,
IgnoreUrlInSubframe) {
+ using Entry = ukm::builders::DocumentCreated;
+
GURL main_url = embedded_test_server()->GetURL("/page_with_iframe.html");
GURL subframe_url = embedded_test_server()->GetURL("/title1.html");
@@ -114,6 +132,21 @@ IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverBrowserTest,
GetSourceForNavigationId(subframe_observer.navigation_id()));
EXPECT_EQ(main_url, GetAssociatedURLForWebContentsDocument());
+
+ // Check we have created a DocumentCreated event for both frames.
+ auto ukm_entries = test_ukm_recorder().GetEntriesByName(Entry::kEntryName);
+ EXPECT_EQ(2u, ukm_entries.size());
+ EXPECT_EQ(source->id(), *test_ukm_recorder().GetEntryMetric(
+ ukm_entries[0], Entry::kNavigationSourceIdName));
+ EXPECT_EQ(0, *test_ukm_recorder().GetEntryMetric(ukm_entries[0],
+ Entry::kIsMainFrameName));
+ EXPECT_EQ(source->id(), *test_ukm_recorder().GetEntryMetric(
+ ukm_entries[1], Entry::kNavigationSourceIdName));
+ EXPECT_EQ(1, *test_ukm_recorder().GetEntryMetric(ukm_entries[1],
+ Entry::kIsMainFrameName));
+ EXPECT_NE(ukm_entries[0]->source_id, ukm_entries[1]->source_id);
+ EXPECT_NE(source->id(), ukm_entries[0]->source_id);
+ EXPECT_NE(source->id(), ukm_entries[1]->source_id);
}
IN_PROC_BROWSER_TEST_F(SourceUrlRecorderWebContentsObserverDownloadBrowserTest,
diff --git a/chromium/components/ukm/debug/ukm_debug_data_extractor.cc b/chromium/components/ukm/debug/ukm_debug_data_extractor.cc
index 5377eeeec9c..0e471c3eb3e 100644
--- a/chromium/components/ukm/debug/ukm_debug_data_extractor.cc
+++ b/chromium/components/ukm/debug/ukm_debug_data_extractor.cc
@@ -22,10 +22,11 @@ struct SourceData {
std::vector<mojom::UkmEntry*> entries;
};
-std::string GetName(ukm::builders::DecodeMap& decode_map, uint64_t hash) {
- if (decode_map.count(hash))
- return decode_map[hash];
- return base::StringPrintf("Unknown %" PRIu64, hash);
+std::string GetName(const ukm::builders::EntryDecoder& decoder, uint64_t hash) {
+ const auto it = decoder.metric_map.find(hash);
+ if (it == decoder.metric_map.end())
+ return base::StringPrintf("Unknown %" PRIu64, hash);
+ return it->second;
}
} // namespace
@@ -59,7 +60,7 @@ std::string UkmDebugDataExtractor::GetHTMLData(UkmService* ukm_service) {
output.append(
base::StringPrintf("<p>SessionId:%d</p>", ukm_service->session_id_));
- auto decode_map = ::ukm::builders::CreateDecodeMap();
+ const auto& decode_map = ukm_service->decode_map_;
std::map<SourceId, SourceData> source_data;
for (const auto& kv : ukm_service->sources_) {
source_data[kv.first].source = kv.second.get();
@@ -79,13 +80,17 @@ std::string UkmDebugDataExtractor::GetHTMLData(UkmService* ukm_service) {
output.append(base::StringPrintf("<h3>Id:%" PRId64 "</h3>", kv.first));
}
for (auto* entry : kv.second.entries) {
- output.append(
- base::StringPrintf("<h4>Entry:%s</h4>",
- GetName(decode_map, entry->event_hash).c_str()));
+ const auto it = decode_map.find(entry->event_hash);
+ if (it == decode_map.end()) {
+ output.append(base::StringPrintf(
+ "<h4>Entry: Unknown %" PRIu64 "</h4>", entry->event_hash));
+ continue;
+ }
+ output.append(base::StringPrintf("<h4>Entry:%s</h4>", it->second.name));
for (const auto& metric : entry->metrics) {
output.append(base::StringPrintf(
"<h5>Metric:%s Value:%" PRId64 "</h5>",
- GetName(decode_map, metric->metric_hash).c_str(), metric->value));
+ GetName(it->second, metric.first).c_str(), metric.second));
}
}
}
diff --git a/chromium/components/ukm/observers/history_delete_observer.cc b/chromium/components/ukm/observers/history_delete_observer.cc
index 00b6f983a2e..da42600ebc5 100644
--- a/chromium/components/ukm/observers/history_delete_observer.cc
+++ b/chromium/components/ukm/observers/history_delete_observer.cc
@@ -21,11 +21,8 @@ void HistoryDeleteObserver::ObserveServiceForDeletions(
void HistoryDeleteObserver::OnURLsDeleted(
history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) {
- if (!expired)
+ const history::DeletionInfo& deletion_info) {
+ if (!deletion_info.is_from_expiration())
OnHistoryDeleted();
}
diff --git a/chromium/components/ukm/observers/history_delete_observer.h b/chromium/components/ukm/observers/history_delete_observer.h
index eb39e50a772..ea48bfc0902 100644
--- a/chromium/components/ukm/observers/history_delete_observer.h
+++ b/chromium/components/ukm/observers/history_delete_observer.h
@@ -24,10 +24,7 @@ class HistoryDeleteObserver : public history::HistoryServiceObserver {
// history::HistoryServiceObserver
void OnURLsDeleted(history::HistoryService* history_service,
- bool all_history,
- bool expired,
- const history::URLRows& deleted_rows,
- const std::set<GURL>& favicon_urls) override;
+ const history::DeletionInfo& deletion_info) override;
void HistoryServiceBeingDeleted(
history::HistoryService* history_service) override;
diff --git a/chromium/components/ukm/observers/sync_disable_observer.cc b/chromium/components/ukm/observers/sync_disable_observer.cc
index 68218595147..f6d72866cfd 100644
--- a/chromium/components/ukm/observers/sync_disable_observer.cc
+++ b/chromium/components/ukm/observers/sync_disable_observer.cc
@@ -7,6 +7,7 @@
#include "base/feature_list.h"
#include "base/metrics/histogram_macros.h"
#include "base/stl_util.h"
+#include "components/sync/driver/sync_token_status.h"
#include "components/sync/engine/connection_status.h"
namespace ukm {
@@ -52,8 +53,7 @@ SyncDisableObserver::~SyncDisableObserver() {}
// static
SyncDisableObserver::SyncState SyncDisableObserver::GetSyncState(
syncer::SyncService* sync_service) {
- syncer::SyncService::SyncTokenStatus status =
- sync_service->GetSyncTokenStatus();
+ syncer::SyncTokenStatus status = sync_service->GetSyncTokenStatus();
SyncState state;
state.history_enabled = sync_service->GetPreferredDataTypes().Has(
syncer::HISTORY_DELETE_DIRECTIVES);
@@ -75,9 +75,9 @@ void SyncDisableObserver::ObserveServiceForSyncDisables(
}
void SyncDisableObserver::UpdateAllProfileEnabled(bool must_purge) {
- bool all_enabled = CheckHistorySyncOnAllProfiles();
+ bool all_enabled = CheckSyncStateOnAllProfiles();
bool all_extensions_enabled =
- all_enabled && CheckExtensionSyncOnAllProfiles();
+ all_enabled && CheckSyncStateForExtensionsOnAllProfiles();
// Any change in sync settings needs to call OnSyncPrefsChanged so that the
// new settings take effect.
if (must_purge || (all_enabled != all_histories_enabled_) ||
@@ -88,7 +88,7 @@ void SyncDisableObserver::UpdateAllProfileEnabled(bool must_purge) {
}
}
-bool SyncDisableObserver::CheckHistorySyncOnAllProfiles() {
+bool SyncDisableObserver::CheckSyncStateOnAllProfiles() {
if (previous_states_.empty())
return false;
for (const auto& kv : previous_states_) {
@@ -112,7 +112,7 @@ bool SyncDisableObserver::CheckHistorySyncOnAllProfiles() {
return true;
}
-bool SyncDisableObserver::CheckExtensionSyncOnAllProfiles() {
+bool SyncDisableObserver::CheckSyncStateForExtensionsOnAllProfiles() {
if (previous_states_.empty())
return false;
for (const auto& kv : previous_states_) {
@@ -148,11 +148,11 @@ void SyncDisableObserver::OnSyncShutdown(syncer::SyncService* sync) {
UpdateAllProfileEnabled(false);
}
-bool SyncDisableObserver::IsHistorySyncEnabledOnAllProfiles() {
+bool SyncDisableObserver::SyncStateAllowsUkm() {
return all_histories_enabled_;
}
-bool SyncDisableObserver::IsExtensionSyncEnabledOnAllProfiles() {
+bool SyncDisableObserver::SyncStateAllowsExtensionUkm() {
return all_extensions_enabled_;
}
diff --git a/chromium/components/ukm/observers/sync_disable_observer.h b/chromium/components/ukm/observers/sync_disable_observer.h
index abb698a9c3f..2de46181f0f 100644
--- a/chromium/components/ukm/observers/sync_disable_observer.h
+++ b/chromium/components/ukm/observers/sync_disable_observer.h
@@ -25,11 +25,15 @@ class SyncDisableObserver : public syncer::SyncServiceObserver {
// Starts observing a service for sync disables.
void ObserveServiceForSyncDisables(syncer::SyncService* sync_service);
- // Returns if history sync is enabled on all active profiles.
- virtual bool IsHistorySyncEnabledOnAllProfiles();
+ // Returns true iff sync is in a state that allows UKM to be enabled.
+ // This means that for all profiles, sync is initialized, connected, has the
+ // HISTORY_DELETE_DIRECTIVES data type enabled, and does not have a secondary
+ // passphrase enabled.
+ virtual bool SyncStateAllowsUkm();
- // Returns if history sync is enabled on all active profiles.
- virtual bool IsExtensionSyncEnabledOnAllProfiles();
+ // Returns true iff sync is in a state that allows UKM to capture extensions.
+ // This means that all profiles have EXTENSIONS data type enabled for syncing.
+ virtual bool SyncStateAllowsExtensionUkm();
protected:
// Called after state changes and some profile has sync disabled.
@@ -45,13 +49,13 @@ class SyncDisableObserver : public syncer::SyncServiceObserver {
// Recomputes all_profiles_enabled_ state from previous_states_;
void UpdateAllProfileEnabled(bool must_purge);
- // Returns true iff all profile histories are enabled in previous_states_.
+ // Returns true iff all sync states in previous_states_ allow UKM.
// If there are no profiles being observed, this returns false.
- bool CheckHistorySyncOnAllProfiles();
+ bool CheckSyncStateOnAllProfiles();
- // Returns true iff all profile extensions are enabled in previous_states_.
+ // Returns true iff all sync states in previous_states_ allow extension UKM.
// If there are no profiles being observed, this returns false.
- bool CheckExtensionSyncOnAllProfiles();
+ bool CheckSyncStateForExtensionsOnAllProfiles();
// Tracks observed history services, for cleanup.
ScopedObserver<syncer::SyncService, syncer::SyncServiceObserver>
diff --git a/chromium/components/ukm/observers/sync_disable_observer_unittest.cc b/chromium/components/ukm/observers/sync_disable_observer_unittest.cc
index d8021d94c9a..f75fd2dff38 100644
--- a/chromium/components/ukm/observers/sync_disable_observer_unittest.cc
+++ b/chromium/components/ukm/observers/sync_disable_observer_unittest.cc
@@ -6,6 +6,8 @@
#include "base/observer_list.h"
#include "components/sync/driver/fake_sync_service.h"
+#include "components/sync/driver/sync_token_status.h"
+#include "components/sync/engine/connection_status.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace ukm {
@@ -56,8 +58,8 @@ class MockSyncService : public syncer::FakeSyncService {
syncer::ModelTypeSet GetPreferredDataTypes() const override {
return preferred_data_types_;
}
- SyncTokenStatus GetSyncTokenStatus() const override {
- SyncTokenStatus status;
+ syncer::SyncTokenStatus GetSyncTokenStatus() const override {
+ syncer::SyncTokenStatus status;
status.connection_status = connection_status_;
return status;
}
@@ -113,7 +115,7 @@ class SyncDisableObserverTest : public testing::Test {
TEST_F(SyncDisableObserverTest, NoProfiles) {
TestSyncDisableObserver observer;
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -123,7 +125,7 @@ TEST_F(SyncDisableObserverTest, OneEnabled) {
MockSyncService sync;
sync.SetStatus(false, true);
observer.ObserveServiceForSyncDisables(&sync);
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -133,7 +135,7 @@ TEST_F(SyncDisableObserverTest, Passphrase) {
MockSyncService sync;
sync.SetStatus(true, true);
observer.ObserveServiceForSyncDisables(&sync);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -143,7 +145,7 @@ TEST_F(SyncDisableObserverTest, HistoryDisabled) {
MockSyncService sync;
sync.SetStatus(false, false);
observer.ObserveServiceForSyncDisables(&sync);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -153,11 +155,11 @@ TEST_F(SyncDisableObserverTest, AuthError) {
MockSyncService sync;
sync.SetStatus(false, true);
observer.ObserveServiceForSyncDisables(&sync);
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
sync.SetConnectionStatus(syncer::CONNECTION_AUTH_ERROR);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
sync.SetConnectionStatus(syncer::CONNECTION_OK);
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
}
TEST_F(SyncDisableObserverTest, MixedProfiles1) {
@@ -168,7 +170,7 @@ TEST_F(SyncDisableObserverTest, MixedProfiles1) {
MockSyncService sync2;
sync2.SetStatus(false, true);
observer.ObserveServiceForSyncDisables(&sync2);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -182,11 +184,11 @@ TEST_F(SyncDisableObserverTest, MixedProfiles2) {
MockSyncService sync2;
sync2.SetStatus(false, false);
observer.ObserveServiceForSyncDisables(&sync2);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
sync2.Shutdown();
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -200,7 +202,7 @@ TEST_F(SyncDisableObserverTest, TwoEnabled) {
MockSyncService sync2;
sync2.SetStatus(false, true);
observer.ObserveServiceForSyncDisables(&sync2);
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -209,15 +211,15 @@ TEST_F(SyncDisableObserverTest, OneAddRemove) {
TestSyncDisableObserver observer;
MockSyncService sync;
observer.ObserveServiceForSyncDisables(&sync);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
sync.SetStatus(false, true);
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
sync.Shutdown();
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
@@ -227,15 +229,15 @@ TEST_F(SyncDisableObserverTest, PurgeOnDisable) {
MockSyncService sync;
sync.SetStatus(false, true);
observer.ObserveServiceForSyncDisables(&sync);
- EXPECT_TRUE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_TRUE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
sync.SetStatus(false, false);
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_TRUE(observer.ResetNotified());
EXPECT_TRUE(observer.ResetPurged());
sync.Shutdown();
- EXPECT_FALSE(observer.IsHistorySyncEnabledOnAllProfiles());
+ EXPECT_FALSE(observer.SyncStateAllowsUkm());
EXPECT_FALSE(observer.ResetNotified());
EXPECT_FALSE(observer.ResetPurged());
}
diff --git a/chromium/components/ukm/test_ukm_recorder.cc b/chromium/components/ukm/test_ukm_recorder.cc
index 75b3e6be1e9..cdf89c49fcf 100644
--- a/chromium/components/ukm/test_ukm_recorder.cc
+++ b/chromium/components/ukm/test_ukm_recorder.cc
@@ -29,7 +29,7 @@ void MergeEntry(const mojom::UkmEntry* in, mojom::UkmEntry* out) {
out->source_id = in->source_id;
}
for (const auto& metric : in->metrics) {
- out->metrics.emplace_back(metric->Clone());
+ out->metrics.emplace(metric);
}
}
@@ -37,6 +37,7 @@ void MergeEntry(const mojom::UkmEntry* in, mojom::UkmEntry* out) {
TestUkmRecorder::TestUkmRecorder() {
EnableRecording(/*extensions=*/true);
+ StoreWhitelistedEntries();
}
TestUkmRecorder::~TestUkmRecorder() {
@@ -112,10 +113,9 @@ bool TestUkmRecorder::EntryHasMetric(const mojom::UkmEntry* entry,
const int64_t* TestUkmRecorder::GetEntryMetric(const mojom::UkmEntry* entry,
base::StringPiece metric_name) {
uint64_t hash = base::HashMetricName(metric_name);
- for (const auto& metric : entry->metrics) {
- if (metric->metric_hash == hash)
- return &metric->value;
- }
+ const auto it = entry->metrics.find(hash);
+ if (it != entry->metrics.end())
+ return &it->second;
return nullptr;
}
diff --git a/chromium/components/ukm/ukm_recorder_impl.cc b/chromium/components/ukm/ukm_recorder_impl.cc
index 4da7241ad2f..f2b0b007300 100644
--- a/chromium/components/ukm/ukm_recorder_impl.cc
+++ b/chromium/components/ukm/ukm_recorder_impl.cc
@@ -18,6 +18,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "components/ukm/ukm_source.h"
+#include "services/metrics/public/cpp/ukm_decode.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/metrics_proto/ukm/entry.pb.h"
#include "third_party/metrics_proto/ukm/report.pb.h"
@@ -96,6 +97,7 @@ enum class DroppedDataReason {
EXTENSION_URLS_DISABLED = 6,
EXTENSION_NOT_SYNCED = 7,
NOT_MATCHED = 8,
+ EMPTY_URL = 9,
NUM_DROPPED_DATA_REASONS
};
@@ -119,8 +121,8 @@ void StoreEntryProto(const mojom::UkmEntry& in, Entry* out) {
out->set_event_hash(in.event_hash);
for (const auto& metric : in.metrics) {
Entry::Metric* proto_metric = out->add_metrics();
- proto_metric->set_metric_hash(metric->metric_hash);
- proto_metric->set_value(metric->value);
+ proto_metric->set_metric_hash(metric.first);
+ proto_metric->set_value(metric.second);
}
}
@@ -149,6 +151,19 @@ void AppendWhitelistedUrls(
}
}
+bool HasUnknownMetrics(const ukm::builders::DecodeMap& decode_map,
+ const mojom::UkmEntry& entry) {
+ const auto it = decode_map.find(entry.event_hash);
+ if (it == decode_map.end())
+ return true;
+ const auto& metric_map = it->second.metric_map;
+ for (const auto& metric : entry.metrics) {
+ if (metric_map.count(metric.first) == 0)
+ return true;
+ }
+ return false;
+}
+
} // namespace
UkmRecorderImpl::UkmRecorderImpl() : recording_enabled_(false) {}
@@ -236,6 +251,8 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
event_aggregate.dropped_due_to_limits);
proto_aggregate->set_dropped_due_to_sampling(
event_aggregate.dropped_due_to_sampling);
+ proto_aggregate->set_dropped_due_to_whitelist(
+ event_aggregate.dropped_due_to_whitelist);
for (const auto& metric_and_aggregate : event_aggregate.metrics) {
const MetricAggregate& aggregate = metric_and_aggregate.second;
Aggregate::Metric* proto_metric = proto_aggregate->add_metrics();
@@ -255,6 +272,11 @@ void UkmRecorderImpl::StoreRecordingsInReport(Report* report) {
proto_metric->set_dropped_due_to_sampling(
aggregate.dropped_due_to_sampling);
}
+ if (aggregate.dropped_due_to_whitelist !=
+ event_aggregate.dropped_due_to_whitelist) {
+ proto_metric->set_dropped_due_to_whitelist(
+ aggregate.dropped_due_to_whitelist);
+ }
}
}
@@ -328,6 +350,11 @@ void UkmRecorderImpl::UpdateSourceURL(SourceId source_id,
return;
}
+ if (unsanitized_url.is_empty()) {
+ RecordDroppedSource(DroppedDataReason::EMPTY_URL);
+ return;
+ }
+
source_counts_.observed++;
if (GetSourceIdType(source_id) == SourceIdType::NAVIGATION_ID)
source_counts_.navigation_sources++;
@@ -336,6 +363,8 @@ void UkmRecorderImpl::UpdateSourceURL(SourceId source_id,
if (!HasSupportedScheme(url)) {
RecordDroppedSource(DroppedDataReason::UNSUPPORTED_URL_SCHEME);
+ DVLOG(2) << "Dropped Unsupported UKM URL:" << source_id << ":"
+ << url.spec();
return;
}
@@ -371,30 +400,35 @@ void UkmRecorderImpl::UpdateSourceURL(SourceId source_id,
void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!HasUnknownMetrics(decode_map_, *entry));
+
if (!recording_enabled_) {
RecordDroppedEntry(DroppedDataReason::RECORDING_DISABLED);
return;
}
+ EventAggregate& event_aggregate = event_aggregations_[entry->event_hash];
+ event_aggregate.total_count++;
+ for (const auto& metric : entry->metrics) {
+ MetricAggregate& aggregate = event_aggregate.metrics[metric.first];
+ double value = metric.second;
+ aggregate.total_count++;
+ aggregate.value_sum += value;
+ aggregate.value_square_sum += value * value;
+ }
+
if (ShouldRestrictToWhitelistedEntries() &&
!base::ContainsKey(whitelisted_entry_hashes_, entry->event_hash)) {
RecordDroppedEntry(DroppedDataReason::NOT_WHITELISTED);
+ event_aggregate.dropped_due_to_whitelist++;
+ for (auto& metric : entry->metrics)
+ event_aggregate.metrics[metric.first].dropped_due_to_whitelist++;
return;
}
if (default_sampling_rate_ == 0)
LoadExperimentSamplingInfo();
- EventAggregate& event_aggregate = event_aggregations_[entry->event_hash];
- event_aggregate.total_count++;
- for (const auto& metric : entry->metrics) {
- MetricAggregate& aggregate = event_aggregate.metrics[metric->metric_hash];
- double value = metric->value;
- aggregate.total_count++;
- aggregate.value_sum += value;
- aggregate.value_square_sum += value * value;
- }
-
auto found = event_sampling_rates_.find(entry->event_hash);
int sampling_rate = (found != event_sampling_rates_.end())
? found->second
@@ -404,7 +438,7 @@ void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) {
RecordDroppedEntry(DroppedDataReason::SAMPLED_OUT);
event_aggregate.dropped_due_to_sampling++;
for (auto& metric : entry->metrics)
- event_aggregate.metrics[metric->metric_hash].dropped_due_to_sampling++;
+ event_aggregate.metrics[metric.first].dropped_due_to_sampling++;
return;
}
@@ -412,7 +446,7 @@ void UkmRecorderImpl::AddEntry(mojom::UkmEntryPtr entry) {
RecordDroppedEntry(DroppedDataReason::MAX_HIT);
event_aggregate.dropped_due_to_limits++;
for (auto& metric : entry->metrics)
- event_aggregate.metrics[metric->metric_hash].dropped_due_to_limits++;
+ event_aggregate.metrics[metric.first].dropped_due_to_limits++;
return;
}
@@ -461,6 +495,7 @@ void UkmRecorderImpl::StoreWhitelistedEntries() {
base::SPLIT_WANT_NONEMPTY);
for (const auto& entry_string : entries)
whitelisted_entry_hashes_.insert(base::HashMetricName(entry_string));
+ decode_map_ = ::ukm::builders::CreateDecodeMap();
}
} // namespace ukm
diff --git a/chromium/components/ukm/ukm_recorder_impl.h b/chromium/components/ukm/ukm_recorder_impl.h
index ada90890a86..aa832dc7e88 100644
--- a/chromium/components/ukm/ukm_recorder_impl.h
+++ b/chromium/components/ukm/ukm_recorder_impl.h
@@ -16,6 +16,7 @@
#include "base/containers/flat_map.h"
#include "base/sequence_checker.h"
#include "base/strings/string_piece.h"
+#include "services/metrics/public/cpp/ukm_decode.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
#include "services/metrics/public/mojom/ukm_interface.mojom.h"
@@ -86,6 +87,7 @@ class UkmRecorderImpl : public UkmRecorder {
double value_square_sum = 0.0;
uint64_t dropped_due_to_limits = 0;
uint64_t dropped_due_to_sampling = 0;
+ uint64_t dropped_due_to_whitelist = 0;
};
struct EventAggregate {
@@ -96,6 +98,7 @@ class UkmRecorderImpl : public UkmRecorder {
uint64_t total_count = 0;
uint64_t dropped_due_to_limits = 0;
uint64_t dropped_due_to_sampling = 0;
+ uint64_t dropped_due_to_whitelist = 0;
};
using MetricAggregateMap = std::map<uint64_t, MetricAggregate>;
@@ -124,6 +127,9 @@ class UkmRecorderImpl : public UkmRecorder {
// events for that source yet.
std::unordered_set<std::string> carryover_urls_whitelist_;
+ // Map from hashes to entry and metric names.
+ ukm::builders::DecodeMap decode_map_;
+
// Whitelisted Entry hashes, only the ones in this set will be recorded.
std::set<uint64_t> whitelisted_entry_hashes_;
diff --git a/chromium/components/ukm/ukm_service.h b/chromium/components/ukm/ukm_service.h
index 0beed52614f..a7e8f3b2820 100644
--- a/chromium/components/ukm/ukm_service.h
+++ b/chromium/components/ukm/ukm_service.h
@@ -85,14 +85,6 @@ class UkmService : public UkmRecorderImpl {
friend ::metrics::UkmEGTestHelper;
friend ::ukm::debug::UkmDebugDataExtractor;
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, AddEntryWithEmptyMetrics);
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, EntryBuilderAndSerialization);
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest,
- LogsUploadedOnlyWhenHavingSourcesOrEntries);
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, MetricsProviderTest);
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, PersistAndPurge);
- FRIEND_TEST_ALL_PREFIXES(UkmServiceTest, WhitelistEntryTest);
-
// Starts metrics client initialization.
void StartInitTask();
diff --git a/chromium/components/ukm/ukm_service_unittest.cc b/chromium/components/ukm/ukm_service_unittest.cc
index 1acb64a1304..2a836533679 100644
--- a/chromium/components/ukm/ukm_service_unittest.cc
+++ b/chromium/components/ukm/ukm_service_unittest.cc
@@ -36,6 +36,20 @@
namespace ukm {
+// Some arbitrary events used in tests.
+using TestEvent1 = ukm::builders::PageLoad;
+const char* kTestEvent1Metric1 =
+ TestEvent1::kPaintTiming_NavigationToFirstContentfulPaintName;
+const char* kTestEvent1Metric2 = TestEvent1::kNet_CacheBytesName;
+using TestEvent2 = ukm::builders::Memory_Experimental;
+const char* kTestEvent2Metric1 = TestEvent2::kArrayBufferName;
+const char* kTestEvent2Metric2 = TestEvent2::kBlinkGCName;
+using TestEvent3 = ukm::builders::Previews;
+
+std::string Entry1And2Whitelist() {
+ return std::string(TestEvent1::kEntryName) + ',' + TestEvent2::kEntryName;
+}
+
// A small shim exposing UkmRecorder methods to tests.
class TestRecordingHelper {
public:
@@ -45,11 +59,6 @@ class TestRecordingHelper {
recorder_->UpdateSourceURL(source_id, url);
}
- std::unique_ptr<UkmEntryBuilder> GetEntryBuilder(SourceId source_id,
- const char* event_name) {
- return recorder_->GetEntryBuilder(source_id, event_name);
- }
-
private:
UkmRecorder* recorder_;
@@ -187,7 +196,7 @@ TEST_F(UkmServiceTest, EnableDisableSchedule) {
TEST_F(UkmServiceTest, PersistAndPurge) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "PageLoad"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
UkmService service(&prefs_, &client_,
true /* restrict_to_whitelisted_entries */);
@@ -204,11 +213,7 @@ TEST_F(UkmServiceTest, PersistAndPurge) {
task_runner_->RunPendingTasks();
EXPECT_TRUE(client_.uploader()->is_uploading());
// Flushes the generated log to disk and generates a new entry.
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- recorder.GetEntryBuilder(id, "PageLoad");
- builder->AddMetric("FirstContentfulPaint", 300);
- }
+ TestEvent1(id).Record(&service);
service.Flush();
EXPECT_EQ(GetPersistedLogCount(), 2);
service.Purge();
@@ -243,79 +248,10 @@ TEST_F(UkmServiceTest, SourceSerialization) {
EXPECT_FALSE(proto_source.has_initial_url());
}
-TEST_F(UkmServiceTest, EntryBuilderAndSerialization) {
- base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
- ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "foo,bar"}});
-
- UkmService service(&prefs_, &client_,
- true /* restrict_to_whitelisted_entries */);
- TestRecordingHelper recorder(&service);
- EXPECT_EQ(0, GetPersistedLogCount());
- service.Initialize();
- task_runner_->RunUntilIdle();
- service.EnableRecording(/*extensions=*/false);
- service.EnableReporting();
-
- ukm::SourceId id = GetWhitelistedSourceId(0);
- recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
- {
- std::unique_ptr<UkmEntryBuilder> foo_builder =
- service.GetEntryBuilder(id, "foo");
- foo_builder->AddMetric("foo_start", 0);
- foo_builder->AddMetric("foo_end", 10);
-
- std::unique_ptr<UkmEntryBuilder> bar_builder =
- service.GetEntryBuilder(id, "bar");
- bar_builder->AddMetric("bar_start", 5);
- bar_builder->AddMetric("bar_end", 15);
- }
-
- service.Flush();
- EXPECT_EQ(1, GetPersistedLogCount());
-
- Report proto_report = GetPersistedReport();
-
- ASSERT_EQ(1, proto_report.sources_size());
- const Source& proto_source = proto_report.sources(0);
- EXPECT_EQ(GURL("https://google.com/foobar").spec(), proto_source.url());
- EXPECT_EQ(id, proto_source.id());
-
- ASSERT_EQ(2, proto_report.entries_size());
-
- // Bar entry is the 0th entry here because bar_builder is destructed before
- // foo_builder: the reverse order as they are constructed. To have the same
- // ordering as the builders are constructed, one can achieve that by putting
- // builders in separate scopes.
- const Entry& proto_entry_bar = proto_report.entries(0);
- EXPECT_EQ(id, proto_entry_bar.source_id());
- EXPECT_EQ(base::HashMetricName("bar"), proto_entry_bar.event_hash());
- ASSERT_EQ(2, proto_entry_bar.metrics_size());
- const Entry::Metric proto_entry_bar_start = proto_entry_bar.metrics(0);
- EXPECT_EQ(base::HashMetricName("bar_start"),
- proto_entry_bar_start.metric_hash());
- EXPECT_EQ(5, proto_entry_bar_start.value());
- const Entry::Metric proto_entry_bar_end = proto_entry_bar.metrics(1);
- EXPECT_EQ(base::HashMetricName("bar_end"), proto_entry_bar_end.metric_hash());
- EXPECT_EQ(15, proto_entry_bar_end.value());
-
- const Entry& proto_entry_foo = proto_report.entries(1);
- EXPECT_EQ(id, proto_entry_foo.source_id());
- EXPECT_EQ(base::HashMetricName("foo"), proto_entry_foo.event_hash());
- ASSERT_EQ(2, proto_entry_foo.metrics_size());
- const Entry::Metric proto_entry_foo_start = proto_entry_foo.metrics(0);
- EXPECT_EQ(base::HashMetricName("foo_start"),
- proto_entry_foo_start.metric_hash());
- EXPECT_EQ(0, proto_entry_foo_start.value());
- const Entry::Metric proto_entry_foo_end = proto_entry_foo.metrics(1);
- EXPECT_EQ(base::HashMetricName("foo_end"), proto_entry_foo_end.metric_hash());
- EXPECT_EQ(10, proto_entry_foo_end.value());
-}
-
TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "PageLoad"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
UkmService service(&prefs_, &client_,
true /* restrict_to_whitelisted_entries */);
@@ -329,7 +265,7 @@ TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) {
ukm::SourceId id = GetWhitelistedSourceId(0);
recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
- { ::ukm::builders::PageLoad(id).Record(&service); }
+ TestEvent1(id).Record(&service);
service.Flush();
ASSERT_EQ(1, GetPersistedLogCount());
Report proto_report = GetPersistedReport();
@@ -339,7 +275,7 @@ TEST_F(UkmServiceTest, AddEntryWithEmptyMetrics) {
TEST_F(UkmServiceTest, MetricsProviderTest) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "PageLoad"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
UkmService service(&prefs_, &client_,
true /* restrict_to_whitelisted_entries */);
@@ -360,11 +296,7 @@ TEST_F(UkmServiceTest, MetricsProviderTest) {
ukm::SourceId id = GetWhitelistedSourceId(0);
recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
- {
- ::ukm::builders::PageLoad(id)
- .SetPaintTiming_NavigationToFirstContentfulPaint(300)
- .Record(&service);
- }
+ TestEvent1(id).Record(&service);
service.Flush();
EXPECT_EQ(GetPersistedLogCount(), 1);
@@ -421,7 +353,7 @@ TEST_F(UkmServiceTest, LogsUploadedOnlyWhenHavingSourcesOrEntries) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
// Testing two whitelisted Entries.
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "PageLoad"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
UkmService service(&prefs_, &client_,
true /* restrict_to_whitelisted_entries */);
@@ -444,21 +376,13 @@ TEST_F(UkmServiceTest, LogsUploadedOnlyWhenHavingSourcesOrEntries) {
service.Flush();
EXPECT_EQ(GetPersistedLogCount(), 1);
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- service.GetEntryBuilder(id, "PageLoad");
- builder->AddMetric("FirstPaint", 300);
- }
+ TestEvent1(id).Record(&service);
// Includes an Entry, so will persist.
service.Flush();
EXPECT_EQ(GetPersistedLogCount(), 2);
recorder.UpdateSourceURL(id, GURL("https://google.com/foobar"));
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- service.GetEntryBuilder(id, "PageLoad");
- builder->AddMetric("FirstContentfulPaint", 300);
- }
+ TestEvent1(id).Record(&service);
// Includes a Source and an Entry, so will persist.
service.Flush();
EXPECT_EQ(GetPersistedLogCount(), 3);
@@ -524,7 +448,7 @@ TEST_F(UkmServiceTest, RestrictToWhitelistedSourceIds) {
base::FeatureList::OVERRIDE_ENABLE_FEATURE,
{{"RestrictToWhitelistedSourceIds",
restrict_to_whitelisted_source_ids ? "true" : "false"},
- {"WhitelistEntries", "FakeEntry"}});
+ {"WhitelistEntries", Entry1And2Whitelist()}});
ClearPrefs();
UkmService service(&prefs_, &client_,
@@ -538,12 +462,12 @@ TEST_F(UkmServiceTest, RestrictToWhitelistedSourceIds) {
ukm::SourceId id1 = GetWhitelistedSourceId(0);
recorder.UpdateSourceURL(id1, kURL);
- recorder.GetEntryBuilder(id1, "FakeEntry");
+ TestEvent1(id1).Record(&service);
// Create a non-navigation-based sourceid, which should not be whitelisted.
ukm::SourceId id2 = GetNonWhitelistedSourceId(1);
recorder.UpdateSourceURL(id2, kURL);
- recorder.GetEntryBuilder(id2, "FakeEntry");
+ TestEvent1(id2).Record(&service);
service.Flush();
ASSERT_EQ(GetPersistedLogCount(), 1);
@@ -648,7 +572,7 @@ TEST_F(UkmServiceTest, WhitelistEntryTest) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
// Testing two whitelisted Entries.
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "EntryA,EntryB"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
ClearPrefs();
UkmService service(&prefs_, &client_,
@@ -663,22 +587,10 @@ TEST_F(UkmServiceTest, WhitelistEntryTest) {
auto id = GetWhitelistedSourceId(0);
recorder.UpdateSourceURL(id, GURL("https://google.com/foobar1"));
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- service.GetEntryBuilder(id, "EntryA");
- builder->AddMetric("MetricA", 300);
- }
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- service.GetEntryBuilder(id, "EntryB");
- builder->AddMetric("MetricB", 400);
- }
+ TestEvent1(id).Record(&service);
+ TestEvent2(id).Record(&service);
// Note that this third entry is not in the whitelist.
- {
- std::unique_ptr<UkmEntryBuilder> builder =
- service.GetEntryBuilder(id, "EntryC");
- builder->AddMetric("MetricC", 500);
- }
+ TestEvent3(id).Record(&service);
service.Flush();
EXPECT_EQ(1, GetPersistedLogCount());
@@ -690,11 +602,13 @@ TEST_F(UkmServiceTest, WhitelistEntryTest) {
const Entry& proto_entry_a = proto_report.entries(0);
EXPECT_EQ(id, proto_entry_a.source_id());
- EXPECT_EQ(base::HashMetricName("EntryA"), proto_entry_a.event_hash());
+ EXPECT_EQ(base::HashMetricName(TestEvent1::kEntryName),
+ proto_entry_a.event_hash());
const Entry& proto_entry_b = proto_report.entries(1);
EXPECT_EQ(id, proto_entry_b.source_id());
- EXPECT_EQ(base::HashMetricName("EntryB"), proto_entry_b.event_hash());
+ EXPECT_EQ(base::HashMetricName(TestEvent2::kEntryName),
+ proto_entry_b.event_hash());
}
TEST_F(UkmServiceTest, SourceURLLength) {
@@ -710,7 +624,8 @@ TEST_F(UkmServiceTest, SourceURLLength) {
auto id = GetWhitelistedSourceId(0);
// This URL is too long to be recorded fully.
- const std::string long_string = "https://" + std::string(10000, 'a');
+ const std::string long_string =
+ "https://example.com/" + std::string(10000, 'a');
recorder.UpdateSourceURL(id, GURL(long_string));
service.Flush();
@@ -730,7 +645,7 @@ TEST_F(UkmServiceTest, UnreferencedNonWhitelistedSources) {
ScopedUkmFeatureParams params(
base::FeatureList::OVERRIDE_ENABLE_FEATURE,
{{"MaxKeptSources", "3"},
- {"WhitelistEntries", "EntryA,EntryB"},
+ {"WhitelistEntries", Entry1And2Whitelist()},
{"RestrictToWhitelistedSourceIds",
restrict_to_whitelisted_source_ids ? "true" : "false"}});
@@ -765,10 +680,10 @@ TEST_F(UkmServiceTest, UnreferencedNonWhitelistedSources) {
}
// Add whitelisted entries for 0, 2 and non-whitelisted entries for 2, 3.
- recorder.GetEntryBuilder(ids[0], "EntryA")->AddMetric("Metric", 500);
- recorder.GetEntryBuilder(ids[2], "EntryB")->AddMetric("Metric", 500);
- recorder.GetEntryBuilder(ids[2], "EntryC")->AddMetric("Metric", 500);
- recorder.GetEntryBuilder(ids[3], "EntryC")->AddMetric("Metric", 500);
+ TestEvent1(ids[0]).Record(&service);
+ TestEvent2(ids[2]).Record(&service);
+ TestEvent3(ids[2]).Record(&service);
+ TestEvent3(ids[3]).Record(&service);
service.Flush();
EXPECT_EQ(1, GetPersistedLogCount());
@@ -802,10 +717,10 @@ TEST_F(UkmServiceTest, UnreferencedNonWhitelistedSources) {
// - Source 0 should not be re-transmitted since it was sent before.
// - Source 1 should not be transmitted due to MaxKeptSources param.
// - Sources 3 and 4 should be transmitted since they were not sent before.
- recorder.GetEntryBuilder(ids[4], "EntryA")->AddMetric("Metric", 500);
- recorder.GetEntryBuilder(ids[3], "EntryA")->AddMetric("Metric", 500);
- recorder.GetEntryBuilder(ids[1], "EntryA")->AddMetric("Metric", 500);
- recorder.GetEntryBuilder(ids[0], "EntryA")->AddMetric("Metric", 500);
+ TestEvent1(ids[4]).Record(&service);
+ TestEvent1(ids[3]).Record(&service);
+ TestEvent1(ids[1]).Record(&service);
+ TestEvent1(ids[0]).Record(&service);
service.Flush();
EXPECT_EQ(2, GetPersistedLogCount());
@@ -850,7 +765,7 @@ TEST_F(UkmServiceTest, NonWhitelistedUrls) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "FakeEntry"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
for (const auto& test : test_cases) {
ClearPrefs();
@@ -871,7 +786,7 @@ TEST_F(UkmServiceTest, NonWhitelistedUrls) {
// Record non whitelisted ID with a entry.
ukm::SourceId nonwhitelist_id = GetNonWhitelistedSourceId(100);
recorder.UpdateSourceURL(nonwhitelist_id, test.url);
- recorder.GetEntryBuilder(nonwhitelist_id, "FakeEntry");
+ TestEvent1(nonwhitelist_id).Record(&service);
service.Flush();
ASSERT_EQ(1, GetPersistedLogCount());
@@ -936,7 +851,7 @@ TEST_F(UkmServiceTest, NonWhitelistedCarryoverUrls) {
base::FieldTrialList field_trial_list(nullptr /* entropy_provider */);
ScopedUkmFeatureParams params(base::FeatureList::OVERRIDE_ENABLE_FEATURE,
- {{"WhitelistEntries", "FakeEntry"}});
+ {{"WhitelistEntries", Entry1And2Whitelist()}});
for (const auto& test : test_cases) {
ClearPrefs();
@@ -979,8 +894,8 @@ TEST_F(UkmServiceTest, NonWhitelistedCarryoverUrls) {
// Record the Source2 and events for Source1 and Source2.
ukm::SourceId nonwhitelist_id2 = GetNonWhitelistedSourceId(101);
recorder.UpdateSourceURL(nonwhitelist_id2, test.source2_url);
- recorder.GetEntryBuilder(nonwhitelist_id1, "FakeEntry");
- recorder.GetEntryBuilder(nonwhitelist_id2, "FakeEntry");
+ TestEvent1(nonwhitelist_id1).Record(&service);
+ TestEvent1(nonwhitelist_id2).Record(&service);
service.Flush();
ASSERT_EQ(2, GetPersistedLogCount());
@@ -1049,7 +964,7 @@ TEST_F(UkmServiceTest, SupportedSchemes) {
for (const auto& test : test_cases) {
auto source_id = GetWhitelistedSourceId(id_counter++);
recorder.UpdateSourceURL(source_id, GURL(test.url));
- recorder.GetEntryBuilder(source_id, "FakeEntry");
+ TestEvent1(source_id).Record(&service);
if (test.expected_kept)
++expected_kept_count;
}
@@ -1105,7 +1020,7 @@ TEST_F(UkmServiceTest, SupportedSchemesNoExtensions) {
for (const auto& test : test_cases) {
auto source_id = GetWhitelistedSourceId(id_counter++);
recorder.UpdateSourceURL(source_id, GURL(test.url));
- recorder.GetEntryBuilder(source_id, "FakeEntry");
+ TestEvent1(source_id).Record(&service);
if (test.expected_kept)
++expected_kept_count;
}
diff --git a/chromium/components/undo_strings_grdp/OWNERS b/chromium/components/undo_strings_grdp/OWNERS
new file mode 100644
index 00000000000..3c4cda0c561
--- /dev/null
+++ b/chromium/components/undo_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/undo/OWNERS
diff --git a/chromium/components/undo_strings_grdp/README.md b/chromium/components/undo_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/undo_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/update_client/BUILD.gn b/chromium/components/update_client/BUILD.gn
index 7d394a0fbcd..a105b0414ae 100644
--- a/chromium/components/update_client/BUILD.gn
+++ b/chromium/components/update_client/BUILD.gn
@@ -12,6 +12,8 @@ static_library("update_client") {
"activity_data_service.h",
"background_downloader_win.cc",
"background_downloader_win.h",
+ "command_line_config_policy.cc",
+ "command_line_config_policy.h",
"component.cc",
"component.h",
"component_patcher.cc",
diff --git a/chromium/components/update_client/action_runner.cc b/chromium/components/update_client/action_runner.cc
index c91388ac6e7..8cfb13c448a 100644
--- a/chromium/components/update_client/action_runner.cc
+++ b/chromium/components/update_client/action_runner.cc
@@ -44,7 +44,7 @@ void ActionRunner::Run(Callback run_complete) {
void ActionRunner::Unpack(
std::unique_ptr<service_manager::Connector> connector) {
- const auto& installer = component_.crx_component().installer;
+ const auto& installer = component_.crx_component()->installer;
base::FilePath file_path;
installer->GetInstalledFile(component_.action_run(), &file_path);
diff --git a/chromium/components/update_client/background_downloader_win.cc b/chromium/components/update_client/background_downloader_win.cc
index a83f9b94884..fb8c9ed1591 100644
--- a/chromium/components/update_client/background_downloader_win.cc
+++ b/chromium/components/update_client/background_downloader_win.cc
@@ -719,9 +719,11 @@ HRESULT BackgroundDownloader::QueueBitsJob(const GURL& url,
HRESULT BackgroundDownloader::CreateOrOpenJob(const GURL& url,
ComPtr<IBackgroundCopyJob>* job) {
std::vector<ComPtr<IBackgroundCopyJob>> jobs;
- HRESULT hr =
- FindBitsJobIf(std::bind2nd(std::ptr_fun(JobFileUrlEqualPredicate), url),
- bits_manager_, &jobs);
+ HRESULT hr = FindBitsJobIf(
+ [&url](ComPtr<IBackgroundCopyJob> job) {
+ return JobFileUrlEqualPredicate(job, url);
+ },
+ bits_manager_, &jobs);
if (SUCCEEDED(hr) && !jobs.empty()) {
*job = jobs.front();
return S_FALSE;
@@ -899,9 +901,11 @@ void BackgroundDownloader::CleanupStaleJobs() {
last_sweep = current_time;
std::vector<ComPtr<IBackgroundCopyJob>> jobs;
- FindBitsJobIf(std::bind2nd(std::ptr_fun(JobCreationOlderThanDaysPredicate),
- kPurgeStaleJobsAfterDays),
- bits_manager_, &jobs);
+ FindBitsJobIf(
+ [](ComPtr<IBackgroundCopyJob> job) {
+ return JobCreationOlderThanDaysPredicate(job, kPurgeStaleJobsAfterDays);
+ },
+ bits_manager_, &jobs);
for (const auto& job : jobs)
CleanupJob(job);
diff --git a/chromium/components/update_client/command_line_config_policy.cc b/chromium/components/update_client/command_line_config_policy.cc
new file mode 100644
index 00000000000..a6456019b22
--- /dev/null
+++ b/chromium/components/update_client/command_line_config_policy.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/update_client/command_line_config_policy.h"
+
+#include "build/build_config.h"
+#include "url/gurl.h"
+
+namespace update_client {
+
+bool CommandLineConfigPolicy::BackgroundDownloadsEnabled() const {
+#if defined(OS_WIN)
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool CommandLineConfigPolicy::DeltaUpdatesEnabled() const {
+ return true;
+}
+
+bool CommandLineConfigPolicy::FastUpdate() const {
+ return false;
+}
+
+bool CommandLineConfigPolicy::PingsEnabled() const {
+ return true;
+}
+
+bool CommandLineConfigPolicy::TestRequest() const {
+ return false;
+}
+
+GURL CommandLineConfigPolicy::UrlSourceOverride() const {
+ return GURL();
+}
+
+} // namespace update_client
diff --git a/chromium/components/update_client/command_line_config_policy.h b/chromium/components/update_client/command_line_config_policy.h
new file mode 100644
index 00000000000..d515c994180
--- /dev/null
+++ b/chromium/components/update_client/command_line_config_policy.h
@@ -0,0 +1,40 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_UPDATE_CLIENT_COMMAND_LINE_CONFIG_POLICY_H_
+#define COMPONENTS_UPDATE_CLIENT_COMMAND_LINE_CONFIG_POLICY_H_
+
+class GURL;
+
+namespace update_client {
+
+// This class provides additional settings from command line switches to the
+// main configurator.
+class CommandLineConfigPolicy {
+ public:
+ // If true, background downloads are enabled.
+ virtual bool BackgroundDownloadsEnabled() const;
+
+ // If true, differential updates are enabled.
+ virtual bool DeltaUpdatesEnabled() const;
+
+ // If true, speed up the initial update checking.
+ virtual bool FastUpdate() const;
+
+ // If true, pings are enabled. Pings are the requests sent to the update
+ // server that report the success or failure of installs or update attempts.
+ virtual bool PingsEnabled() const;
+
+ // If true, add "testrequest" attribute to update check requests.
+ virtual bool TestRequest() const;
+
+ // The override URL for updates. Can be empty.
+ virtual GURL UrlSourceOverride() const;
+
+ virtual ~CommandLineConfigPolicy() {}
+};
+
+} // namespace update_client
+
+#endif // COMPONENTS_UPDATE_CLIENT_COMMAND_LINE_CONFIG_POLICY_H_
diff --git a/chromium/components/update_client/component.cc b/chromium/components/update_client/component.cc
index cbed9b77538..6c8ce2c8bcb 100644
--- a/chromium/components/update_client/component.cc
+++ b/chromium/components/update_client/component.cc
@@ -27,12 +27,12 @@
// The state machine representing how a CRX component changes during an update.
//
-// +------------------------> kNew <---------------------+--------+
-// | | | |
-// | V | |
-// | kChecking | |
-// | | | |
-// | error V no no | |
+// +------------------------- kNew
+// | |
+// | V
+// | kChecking
+// | |
+// V error V no no
// kUpdateError <------------- [update?] -> [action?] -> kUpToDate kUpdated
// ^ | | ^ ^
// | yes | | yes | |
@@ -62,7 +62,7 @@ namespace update_client {
namespace {
using InstallOnBlockingTaskRunnerCompleteCallback = base::OnceCallback<
- void(int error_category, int error_code, int extra_code1)>;
+ void(ErrorCategory error_category, int error_code, int extra_code1)>;
void InstallComplete(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
@@ -78,11 +78,9 @@ void InstallComplete(
const CrxInstaller::Result& result) {
base::DeleteFile(unpack_path, true);
const ErrorCategory error_category =
- result.error ? ErrorCategory::kInstallError
- : ErrorCategory::kErrorNone;
+ result.error ? ErrorCategory::kInstall : ErrorCategory::kNone;
main_task_runner->PostTask(
- FROM_HERE, base::BindOnce(std::move(callback),
- static_cast<int>(error_category),
+ FROM_HERE, base::BindOnce(std::move(callback), error_category,
static_cast<int>(result.error),
result.extended_error));
},
@@ -109,8 +107,7 @@ void InstallOnBlockingTaskRunner(
const CrxInstaller::Result result(InstallError::FINGERPRINT_WRITE_FAILED);
main_task_runner->PostTask(
FROM_HERE,
- base::BindOnce(std::move(callback),
- static_cast<int>(ErrorCategory::kInstallError),
+ base::BindOnce(std::move(callback), ErrorCategory::kInstall,
static_cast<int>(result.error), result.extended_error));
return;
}
@@ -133,8 +130,7 @@ void UnpackCompleteOnBlockingTaskRunner(
if (result.error != UnpackerError::kNone) {
main_task_runner->PostTask(
FROM_HERE,
- base::BindOnce(std::move(callback),
- static_cast<int>(ErrorCategory::kUnpackError),
+ base::BindOnce(std::move(callback), ErrorCategory::kUnpack,
static_cast<int>(result.error), result.extended_error));
return;
}
@@ -212,10 +208,14 @@ CrxUpdateItem Component::GetCrxUpdateItem() const {
CrxUpdateItem crx_update_item;
crx_update_item.state = state_->state();
crx_update_item.id = id_;
- crx_update_item.component = crx_component_;
+ if (crx_component_)
+ crx_update_item.component = *crx_component_;
crx_update_item.last_check = last_check_;
crx_update_item.next_version = next_version_;
crx_update_item.next_fp = next_fp_;
+ crx_update_item.error_category = error_category_;
+ crx_update_item.error_code = error_code_;
+ crx_update_item.extra_code1 = extra_code1_;
return crx_update_item;
}
@@ -256,6 +256,9 @@ void Component::Uninstall(const base::Version& version, int reason) {
DCHECK_EQ(ComponentState::kNew, state());
+ crx_component_ = std::make_unique<CrxComponent>();
+ crx_component_->version = version;
+
previous_version_ = version;
next_version_ = base::Version("0");
extra_code1_ = reason;
@@ -274,7 +277,8 @@ void Component::UpdateCheckComplete() {
bool Component::CanDoBackgroundDownload() const {
// Foreground component updates are always downloaded in foreground.
- return !is_foreground() && crx_component_.allows_background_download &&
+ return !is_foreground() &&
+ (crx_component() && crx_component()->allows_background_download) &&
update_context_.config->EnabledBackgroundDownloader();
}
@@ -340,8 +344,13 @@ void Component::StateNew::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
-
- TransitionState(std::make_unique<StateChecking>(&component));
+ if (component.crx_component()) {
+ TransitionState(std::make_unique<StateChecking>(&component));
+ } else {
+ component.error_code_ = static_cast<int>(Error::CRX_NOT_FOUND);
+ component.error_category_ = ErrorCategory::kService;
+ TransitionState(std::make_unique<StateUpdateError>(&component));
+ }
}
Component::StateChecking::StateChecking(Component* component)
@@ -361,6 +370,7 @@ void Component::StateChecking::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
+ DCHECK(component.crx_component());
component.last_check_ = base::TimeTicks::Now();
component.update_check_complete_ = base::BindOnce(
@@ -372,7 +382,7 @@ void Component::StateChecking::DoHandle() {
void Component::StateChecking::UpdateCheckComplete() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
- if (!component.update_check_error_) {
+ if (!component.error_code_) {
if (component.status_ == "ok") {
TransitionState(std::make_unique<StateCanUpdate>(&component));
return;
@@ -421,13 +431,15 @@ void Component::StateCanUpdate::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
+ DCHECK(component.crx_component());
component.is_update_available_ = true;
component.NotifyObservers(Events::COMPONENT_UPDATE_FOUND);
- if (component.crx_component_.supports_group_policy_enable_component_updates &&
+ if (component.crx_component()
+ ->supports_group_policy_enable_component_updates &&
!component.update_context_.enabled_component_updates) {
- component.error_category_ = static_cast<int>(ErrorCategory::kServiceError);
+ component.error_category_ = ErrorCategory::kService;
component.error_code_ = static_cast<int>(ServiceError::UPDATE_DISABLED);
component.extra_code1_ = 0;
TransitionState(std::make_unique<StateUpdateError>(&component));
@@ -462,6 +474,7 @@ void Component::StateUpToDate::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
+ DCHECK(component.crx_component());
component.NotifyObservers(Events::COMPONENT_NOT_UPDATED);
EndState();
@@ -480,6 +493,8 @@ void Component::StateDownloadingDiff::DoHandle() {
const auto& component = Component::State::component();
const auto& update_context = component.update_context_;
+ DCHECK(component.crx_component());
+
crx_downloader_ = update_context.crx_downloader_factory(
component.CanDoBackgroundDownload(),
update_context.config->RequestContext());
@@ -522,8 +537,7 @@ void Component::StateDownloadingDiff::DownloadComplete(
if (download_result.error) {
DCHECK(download_result.response.empty());
- component.diff_error_category_ =
- static_cast<int>(ErrorCategory::kNetworkError);
+ component.diff_error_category_ = ErrorCategory::kDownload;
component.diff_error_code_ = download_result.error;
TransitionState(std::make_unique<StateDownloading>(&component));
@@ -548,6 +562,8 @@ void Component::StateDownloading::DoHandle() {
const auto& component = Component::State::component();
const auto& update_context = component.update_context_;
+ DCHECK(component.crx_component());
+
crx_downloader_ = update_context.crx_downloader_factory(
component.CanDoBackgroundDownload(),
update_context.config->RequestContext());
@@ -590,7 +606,7 @@ void Component::StateDownloading::DownloadComplete(
if (download_result.error) {
DCHECK(download_result.response.empty());
- component.error_category_ = static_cast<int>(ErrorCategory::kNetworkError);
+ component.error_category_ = ErrorCategory::kDownload;
component.error_code_ = download_result.error;
TransitionState(std::make_unique<StateUpdateError>(&component));
@@ -615,6 +631,8 @@ void Component::StateUpdatingDiff::DoHandle() {
const auto& component = Component::State::component();
const auto& update_context = component.update_context_;
+ DCHECK(component.crx_component());
+
component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
// Create a fresh connector that can be used on the other task runner.
@@ -627,14 +645,14 @@ void Component::StateUpdatingDiff::DoHandle() {
base::BindOnce(
&update_client::StartInstallOnBlockingTaskRunner,
base::ThreadTaskRunnerHandle::Get(),
- component.crx_component_.pk_hash, component.crx_path_,
- component.next_fp_, component.crx_component_.installer,
+ component.crx_component()->pk_hash, component.crx_path_,
+ component.next_fp_, component.crx_component()->installer,
std::move(connector),
base::BindOnce(&Component::StateUpdatingDiff::InstallComplete,
base::Unretained(this))));
}
-void Component::StateUpdatingDiff::InstallComplete(int error_category,
+void Component::StateUpdatingDiff::InstallComplete(ErrorCategory error_category,
int error_code,
int extra_code1) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -650,13 +668,11 @@ void Component::StateUpdatingDiff::InstallComplete(int error_category,
return;
}
- DCHECK_EQ(static_cast<int>(ErrorCategory::kErrorNone),
- component.diff_error_category_);
+ DCHECK_EQ(ErrorCategory::kNone, component.diff_error_category_);
DCHECK_EQ(0, component.diff_error_code_);
DCHECK_EQ(0, component.diff_extra_code1_);
- DCHECK_EQ(static_cast<int>(ErrorCategory::kErrorNone),
- component.error_category_);
+ DCHECK_EQ(ErrorCategory::kNone, component.error_category_);
DCHECK_EQ(0, component.error_code_);
DCHECK_EQ(0, component.extra_code1_);
@@ -679,6 +695,8 @@ void Component::StateUpdating::DoHandle() {
const auto& component = Component::State::component();
const auto& update_context = component.update_context_;
+ DCHECK(component.crx_component());
+
component.NotifyObservers(Events::COMPONENT_UPDATE_READY);
// Create a fresh connector that can be used on the other task runner.
@@ -690,14 +708,14 @@ void Component::StateUpdating::DoHandle() {
base::BindOnce(
&update_client::StartInstallOnBlockingTaskRunner,
base::ThreadTaskRunnerHandle::Get(),
- component.crx_component_.pk_hash, component.crx_path_,
- component.next_fp_, component.crx_component_.installer,
+ component.crx_component()->pk_hash, component.crx_path_,
+ component.next_fp_, component.crx_component()->installer,
std::move(connector),
base::BindOnce(&Component::StateUpdating::InstallComplete,
base::Unretained(this))));
}
-void Component::StateUpdating::InstallComplete(int error_category,
+void Component::StateUpdating::InstallComplete(ErrorCategory error_category,
int error_code,
int extra_code1) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -713,8 +731,7 @@ void Component::StateUpdating::InstallComplete(int error_category,
return;
}
- DCHECK_EQ(static_cast<int>(ErrorCategory::kErrorNone),
- component.error_category_);
+ DCHECK_EQ(ErrorCategory::kNone, component.error_category_);
DCHECK_EQ(0, component.error_code_);
DCHECK_EQ(0, component.extra_code1_);
@@ -737,8 +754,10 @@ void Component::StateUpdated::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
- component.crx_component_.version = component.next_version_;
- component.crx_component_.fingerprint = component.next_fp_;
+ DCHECK(component.crx_component());
+
+ component.crx_component_->version = component.next_version_;
+ component.crx_component_->fingerprint = component.next_fp_;
component.AppendEvent(BuildUpdateCompleteEventElement(component));
@@ -759,6 +778,8 @@ void Component::StateUninstalled::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
auto& component = State::component();
+ DCHECK(component.crx_component());
+
component.AppendEvent(BuildUninstalledEventElement(component));
EndState();
@@ -775,6 +796,8 @@ void Component::StateRun::DoHandle() {
DCHECK(thread_checker_.CalledOnValidThread());
const auto& component = State::component();
+ DCHECK(component.crx_component());
+
action_runner_ = std::make_unique<ActionRunner>(component);
action_runner_->Run(
base::BindOnce(&StateRun::ActionRunComplete, base::Unretained(this)));
diff --git a/chromium/components/update_client/component.h b/chromium/components/update_client/component.h
index ff52638f4fb..749e3009bba 100644
--- a/chromium/components/update_client/component.h
+++ b/chromium/components/update_client/component.h
@@ -72,9 +72,9 @@ class Component {
std::string id() const { return id_; }
- const CrxComponent& crx_component() const { return crx_component_; }
- void set_crx_component(const CrxComponent& crx_component) {
- crx_component_ = crx_component;
+ const CrxComponent* crx_component() const { return crx_component_.get(); }
+ void set_crx_component(std::unique_ptr<CrxComponent> crx_component) {
+ crx_component_ = std::move(crx_component);
}
const base::Version& previous_version() const { return previous_version_; }
@@ -92,9 +92,10 @@ class Component {
std::string next_fp() const { return next_fp_; }
void set_next_fp(const std::string& next_fp) { next_fp_ = next_fp; }
- int update_check_error() const { return update_check_error_; }
void set_update_check_error(int update_check_error) {
- update_check_error_ = update_check_error;
+ error_category_ = ErrorCategory::kUpdateCheck;
+ error_code_ = update_check_error;
+ extra_code1_ = 0;
}
bool is_foreground() const;
@@ -105,10 +106,10 @@ class Component {
bool diff_update_failed() const { return !!diff_error_code_; }
- int error_category() const { return error_category_; }
+ ErrorCategory error_category() const { return error_category_; }
int error_code() const { return error_code_; }
int extra_code1() const { return extra_code1_; }
- int diff_error_category() const { return diff_error_category_; }
+ ErrorCategory diff_error_category() const { return diff_error_category_; }
int diff_error_code() const { return diff_error_code_; }
int diff_extra_code1() const { return diff_extra_code1_; }
@@ -292,7 +293,9 @@ class Component {
// State overrides.
void DoHandle() override;
- void InstallComplete(int error_category, int error_code, int extra_code1);
+ void InstallComplete(ErrorCategory error_category,
+ int error_code,
+ int extra_code1);
DISALLOW_COPY_AND_ASSIGN(StateUpdatingDiff);
};
@@ -306,7 +309,9 @@ class Component {
// State overrides.
void DoHandle() override;
- void InstallComplete(int error_category, int error_code, int extra_code1);
+ void InstallComplete(ErrorCategory error_category,
+ int error_code,
+ int extra_code1);
DISALLOW_COPY_AND_ASSIGN(StateUpdating);
};
@@ -369,7 +374,7 @@ class Component {
base::ThreadChecker thread_checker_;
const std::string id_;
- CrxComponent crx_component_;
+ std::unique_ptr<CrxComponent> crx_component_;
// The status of the updatecheck response.
std::string status_;
@@ -412,10 +417,10 @@ class Component {
// the |extra_code1| usually contains a system error, but it can contain
// any extended information that is relevant to either the category or the
// error itself.
- int error_category_ = 0;
+ ErrorCategory error_category_ = ErrorCategory::kNone;
int error_code_ = 0;
int extra_code1_ = 0;
- int diff_error_category_ = 0;
+ ErrorCategory diff_error_category_ = ErrorCategory::kNone;
int diff_error_code_ = 0;
int diff_extra_code1_ = 0;
diff --git a/chromium/components/update_client/component_patcher_unittest.cc b/chromium/components/update_client/component_patcher_unittest.cc
index 2ec97786982..1a530d8bda0 100644
--- a/chromium/components/update_client/component_patcher_unittest.cc
+++ b/chromium/components/update_client/component_patcher_unittest.cc
@@ -51,7 +51,7 @@ void TestCallback::Set(update_client::UnpackerError error, int extra_code) {
base::FilePath test_file(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/update_client/component_unpacker_unittest.cc b/chromium/components/update_client/component_unpacker_unittest.cc
index 221ba8df603..910bb4d99b8 100644
--- a/chromium/components/update_client/component_unpacker_unittest.cc
+++ b/chromium/components/update_client/component_unpacker_unittest.cc
@@ -15,6 +15,7 @@
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/single_thread_task_runner.h"
#include "base/task_scheduler/post_task.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -53,7 +54,7 @@ void TestCallback::Set(update_client::UnpackerError error, int extra_code) {
base::FilePath test_file(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/update_client/crx_downloader_unittest.cc b/chromium/components/update_client/crx_downloader_unittest.cc
index 7dec8b1e898..cb5c80842f9 100644
--- a/chromium/components/update_client/crx_downloader_unittest.cc
+++ b/chromium/components/update_client/crx_downloader_unittest.cc
@@ -11,7 +11,6 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
@@ -40,7 +39,7 @@ const char hash_jebg[] =
base::FilePath MakeTestFilePath(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components/test/data/update_client")
.AppendASCII(file);
}
diff --git a/chromium/components/update_client/crx_update_item.h b/chromium/components/update_client/crx_update_item.h
index 2882a8421c9..9fd73988a7e 100644
--- a/chromium/components/update_client/crx_update_item.h
+++ b/chromium/components/update_client/crx_update_item.h
@@ -15,6 +15,7 @@
#include "base/version.h"
#include "components/update_client/crx_downloader.h"
#include "components/update_client/update_client.h"
+#include "components/update_client/update_client_errors.h"
namespace update_client {
@@ -33,6 +34,10 @@ struct CrxUpdateItem {
base::Version next_version;
std::string next_fp;
+
+ ErrorCategory error_category = ErrorCategory::kNone;
+ int error_code = 0;
+ int extra_code1 = 0;
};
} // namespace update_client
diff --git a/chromium/components/update_client/ping_manager.cc b/chromium/components/update_client/ping_manager.cc
index 7ec516eb402..f9b885b4eae 100644
--- a/chromium/components/update_client/ping_manager.cc
+++ b/chromium/components/update_client/ping_manager.cc
@@ -70,8 +70,10 @@ void PingSender::SendPing(const Component& component, Callback callback) {
return;
}
+ DCHECK(component.crx_component());
+
auto urls(config_->PingUrl());
- if (component.crx_component().requires_network_encryption)
+ if (component.crx_component()->requires_network_encryption)
RemoveUnsecureUrls(&urls);
if (urls.empty()) {
diff --git a/chromium/components/update_client/ping_manager_unittest.cc b/chromium/components/update_client/ping_manager_unittest.cc
index 7f945bc8fc6..32cd92ba9dd 100644
--- a/chromium/components/update_client/ping_manager_unittest.cc
+++ b/chromium/components/update_client/ping_manager_unittest.cc
@@ -11,7 +11,6 @@
#include "base/bind.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -114,7 +113,7 @@ TEST_F(PingManagerTest, SendPing) {
{
Component component(*update_context, "abc");
-
+ component.crx_component_ = std::make_unique<CrxComponent>();
component.state_ = std::make_unique<Component::StateUpdated>(&component);
component.previous_version_ = base::Version("1.0");
component.next_version_ = base::Version("2.0");
@@ -147,6 +146,7 @@ TEST_F(PingManagerTest, SendPing) {
{
// Test eventresult="0" is sent for failed updates.
Component component(*update_context, "abc");
+ component.crx_component_ = std::make_unique<CrxComponent>();
component.state_ =
std::make_unique<Component::StateUpdateError>(&component);
component.previous_version_ = base::Version("1.0");
@@ -170,16 +170,17 @@ TEST_F(PingManagerTest, SendPing) {
{
// Test the error values and the fingerprints.
Component component(*update_context, "abc");
+ component.crx_component_ = std::make_unique<CrxComponent>();
component.state_ =
std::make_unique<Component::StateUpdateError>(&component);
component.previous_version_ = base::Version("1.0");
component.next_version_ = base::Version("2.0");
component.previous_fp_ = "prev fp";
component.next_fp_ = "next fp";
- component.error_category_ = 1;
+ component.error_category_ = ErrorCategory::kDownload;
component.error_code_ = 2;
component.extra_code1_ = -1;
- component.diff_error_category_ = 10;
+ component.diff_error_category_ = ErrorCategory::kService;
component.diff_error_code_ = 20;
component.diff_extra_code1_ = -10;
component.crx_diffurls_.push_back(GURL("http://host/path"));
@@ -195,7 +196,7 @@ TEST_F(PingManagerTest, SendPing) {
"<app appid=\"abc\">"
"<event eventtype=\"3\" eventresult=\"0\" errorcat=\"1\" "
"errorcode=\"2\" extracode1=\"-1\" diffresult=\"0\" "
- "differrorcat=\"10\" "
+ "differrorcat=\"4\" "
"differrorcode=\"20\" diffextracode1=\"-10\" "
"previousfp=\"prev fp\" nextfp=\"next fp\" "
"previousversion=\"1.0\" nextversion=\"2.0\"/></app>"))
@@ -206,6 +207,7 @@ TEST_F(PingManagerTest, SendPing) {
{
// Test an invalid |next_version| is not serialized.
Component component(*update_context, "abc");
+ component.crx_component_ = std::make_unique<CrxComponent>();
component.state_ =
std::make_unique<Component::StateUpdateError>(&component);
component.previous_version_ = base::Version("1.0");
@@ -229,6 +231,7 @@ TEST_F(PingManagerTest, SendPing) {
// Test a valid |previouversion| and |next_version| = base::Version("0")
// are serialized correctly under <event...> for uninstall.
Component component(*update_context, "abc");
+ component.crx_component_ = std::make_unique<CrxComponent>();
component.Uninstall(base::Version("1.2.3.4"), 0);
component.AppendEvent(BuildUninstalledEventElement(component));
@@ -249,6 +252,7 @@ TEST_F(PingManagerTest, SendPing) {
{
// Test the download metrics.
Component component(*update_context, "abc");
+ component.crx_component_ = std::make_unique<CrxComponent>();
component.state_ = std::make_unique<Component::StateUpdated>(&component);
component.previous_version_ = base::Version("1.0");
component.next_version_ = base::Version("2.0");
@@ -306,9 +310,10 @@ TEST_F(PingManagerTest, RequiresEncryption) {
const auto update_context = MakeMockUpdateContext();
Component component(*update_context, "abc");
+ component.crx_component_ = std::make_unique<CrxComponent>();
// The default value for |requires_network_encryption| is true.
- EXPECT_TRUE(component.crx_component_.requires_network_encryption);
+ EXPECT_TRUE(component.crx_component_->requires_network_encryption);
component.state_ = std::make_unique<Component::StateUpdated>(&component);
component.previous_version_ = base::Version("1.0");
diff --git a/chromium/components/update_client/protocol_builder.cc b/chromium/components/update_client/protocol_builder.cc
index 46794ffcd47..e708c46706a 100644
--- a/chromium/components/update_client/protocol_builder.cc
+++ b/chromium/components/update_client/protocol_builder.cc
@@ -141,8 +141,9 @@ std::string BuildUpdateCompleteEventElement(const Component& component) {
std::string event("<event eventtype=\"3\"");
const int event_result = component.state() == ComponentState::kUpdated;
StringAppendF(&event, " eventresult=\"%d\"", event_result);
- if (component.error_category())
- StringAppendF(&event, " errorcat=\"%d\"", component.error_category());
+ if (component.error_category() != ErrorCategory::kNone)
+ StringAppendF(&event, " errorcat=\"%d\"",
+ static_cast<int>(component.error_category()));
if (component.error_code())
StringAppendF(&event, " errorcode=\"%d\"", component.error_code());
if (component.extra_code1())
@@ -150,9 +151,9 @@ std::string BuildUpdateCompleteEventElement(const Component& component) {
if (HasDiffUpdate(component))
StringAppendF(&event, " diffresult=\"%d\"",
!component.diff_update_failed());
- if (component.diff_error_category()) {
+ if (component.diff_error_category() != ErrorCategory::kNone) {
StringAppendF(&event, " differrorcat=\"%d\"",
- component.diff_error_category());
+ static_cast<int>(component.diff_error_category()));
}
if (component.diff_error_code())
StringAppendF(&event, " differrorcode=\"%d\"", component.diff_error_code());
@@ -232,11 +233,11 @@ std::string BuildProtocolRequest(
// Chrome version and platform information.
base::StringAppendF(&request,
- "version=\"%s-%s\" prodversion=\"%s\" "
+ "updater=\"%s\" updaterversion=\"%s\" prodversion=\"%s\" "
"lang=\"%s\" updaterchannel=\"%s\" prodchannel=\"%s\" "
"os=\"%s\" arch=\"%s\" nacl_arch=\"%s\"",
- prod_id.c_str(), // "version" is prefixed by prod_id.
- browser_version.c_str(),
+ prod_id.c_str(), // "updater"
+ browser_version.c_str(), // "updaterversion"
browser_version.c_str(), // "prodversion"
lang.c_str(), // "lang"
channel.c_str(), // "updaterchannel"
@@ -334,22 +335,27 @@ std::string BuildUpdateCheckRequest(
for (const auto& id : ids_checked) {
DCHECK_EQ(1u, components.count(id));
const auto& component = *components.at(id);
- const auto& crx_component = component.crx_component();
const auto& component_id = component.id();
+ const auto* crx_component = component.crx_component();
+
+ DCHECK(crx_component);
const update_client::InstallerAttributes installer_attributes(
- SanitizeInstallerAttributes(crx_component.installer_attributes));
+ SanitizeInstallerAttributes(crx_component->installer_attributes));
std::string app("<app ");
base::StringAppendF(&app, "appid=\"%s\" version=\"%s\"",
component_id.c_str(),
- crx_component.version.GetString().c_str());
+ crx_component->version.GetString().c_str());
if (!brand.empty())
base::StringAppendF(&app, " brand=\"%s\"", brand.c_str());
- if (!crx_component.install_source.empty())
+ if (!crx_component->install_source.empty())
base::StringAppendF(&app, " installsource=\"%s\"",
- crx_component.install_source.c_str());
+ crx_component->install_source.c_str());
else if (component.is_foreground())
base::StringAppendF(&app, " installsource=\"ondemand\"");
+ if (!crx_component->install_location.empty())
+ base::StringAppendF(&app, " installedby=\"%s\"",
+ crx_component->install_location.c_str());
for (const auto& attr : installer_attributes) {
base::StringAppendF(&app, " %s=\"%s\"", attr.first.c_str(),
attr.second.c_str());
@@ -357,7 +363,7 @@ std::string BuildUpdateCheckRequest(
const auto& cohort = metadata->GetCohort(component_id);
const auto& cohort_name = metadata->GetCohortName(component_id);
const auto& cohort_hint = metadata->GetCohortHint(component_id);
- const auto& disabled_reasons = crx_component.disabled_reasons;
+ const auto& disabled_reasons = crx_component->disabled_reasons;
if (!cohort.empty())
base::StringAppendF(&app, " cohort=\"%s\"", cohort.c_str());
if (!cohort_name.empty())
@@ -371,7 +377,7 @@ std::string BuildUpdateCheckRequest(
base::StringAppendF(&app, "<disabled reason=\"%d\"/>", disabled_reason);
base::StringAppendF(&app, "<updatecheck");
- if (crx_component.supports_group_policy_enable_component_updates &&
+ if (crx_component->supports_group_policy_enable_component_updates &&
!enabled_component_updates) {
base::StringAppendF(&app, " updatedisabled=\"true\"");
}
@@ -399,12 +405,12 @@ std::string BuildUpdateCheckRequest(
base::StringAppendF(&app, " ping_freshness=\"%s\"/>",
metadata->GetPingFreshness(component_id).c_str());
- if (!crx_component.fingerprint.empty()) {
+ if (!crx_component->fingerprint.empty()) {
base::StringAppendF(&app,
"<packages>"
"<package fp=\"%s\"/>"
"</packages>",
- crx_component.fingerprint.c_str());
+ crx_component->fingerprint.c_str());
}
base::StringAppendF(&app, "</app>");
app_elements.append(app);
diff --git a/chromium/components/update_client/protocol_builder_unittest.cc b/chromium/components/update_client/protocol_builder_unittest.cc
index 74700482259..f748ced1951 100644
--- a/chromium/components/update_client/protocol_builder_unittest.cc
+++ b/chromium/components/update_client/protocol_builder_unittest.cc
@@ -28,7 +28,8 @@ TEST(BuildProtocolRequest, SessionIdProdIdVersion) {
string::npos,
request.find(" sessionid=\"{15160585-8ADE-4D3C-839B-1281A6035D1F}\" "));
EXPECT_NE(string::npos,
- request.find(" version=\"some_prod_id-1.0\" prodversion=\"1.0\" "));
+ request.find(" updater=\"some_prod_id\" updaterversion=\"1.0\" "
+ "prodversion=\"1.0\" "));
}
TEST(BuildProtocolRequest, DownloadPreference) {
diff --git a/chromium/components/update_client/request_sender_unittest.cc b/chromium/components/update_client/request_sender_unittest.cc
index ecebd945d05..f480cac3a66 100644
--- a/chromium/components/update_client/request_sender_unittest.cc
+++ b/chromium/components/update_client/request_sender_unittest.cc
@@ -31,7 +31,7 @@ const char kUrlPath2[] = "path2";
// TODO(sorin): refactor as a utility function for unit tests.
base::FilePath test_file(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
diff --git a/chromium/components/update_client/update_checker.cc b/chromium/components/update_client/update_checker.cc
index d63f0eb12da..1fb0479865e 100644
--- a/chromium/components/update_client/update_checker.cc
+++ b/chromium/components/update_client/update_checker.cc
@@ -41,7 +41,8 @@ namespace {
bool IsEncryptionRequired(const IdToComponentPtrMap& components) {
for (const auto& item : components) {
const auto& component = item.second;
- if (component->crx_component().requires_network_encryption)
+ if (component->crx_component() &&
+ component->crx_component()->requires_network_encryption)
return true;
}
return false;
diff --git a/chromium/components/update_client/update_checker_unittest.cc b/chromium/components/update_client/update_checker_unittest.cc
index 8dc0c61ebde..a3249b985c3 100644
--- a/chromium/components/update_client/update_checker_unittest.cc
+++ b/chromium/components/update_client/update_checker_unittest.cc
@@ -28,6 +28,7 @@
#include "components/update_client/update_engine.h"
#include "components/update_client/url_request_post_interceptor.h"
#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -39,7 +40,7 @@ namespace {
base::FilePath test_file(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
@@ -104,7 +105,7 @@ void ActivityDataServiceTest::SetDaysSinceLastRollCall(const std::string& id,
} // namespace
class UpdateCheckerTest : public testing::Test,
- public ::testing::WithParamInterface<bool> {
+ public testing::WithParamInterface<bool> {
public:
UpdateCheckerTest();
~UpdateCheckerTest() override;
@@ -145,7 +146,7 @@ class UpdateCheckerTest : public testing::Test,
DISALLOW_COPY_AND_ASSIGN(UpdateCheckerTest);
};
-INSTANTIATE_TEST_CASE_P(IsForeground, UpdateCheckerTest, ::testing::Bool());
+INSTANTIATE_TEST_CASE_P(IsForeground, UpdateCheckerTest, testing::Bool());
UpdateCheckerTest::UpdateCheckerTest()
: scoped_task_environment_(
@@ -211,16 +212,17 @@ scoped_refptr<UpdateContext> UpdateCheckerTest::MakeMockUpdateContext() const {
}
std::unique_ptr<Component> UpdateCheckerTest::MakeComponent() const {
- CrxComponent crx_component;
- crx_component.name = "test_jebg";
- crx_component.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx_component.installer = nullptr;
- crx_component.version = base::Version("0.9");
- crx_component.fingerprint = "fp1";
+ std::unique_ptr<CrxComponent> crx_component =
+ std::make_unique<CrxComponent>();
+ crx_component->name = "test_jebg";
+ crx_component->pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
+ crx_component->installer = nullptr;
+ crx_component->version = base::Version("0.9");
+ crx_component->fingerprint = "fp1";
auto component = std::make_unique<Component>(*update_context_, kUpdateItemId);
component->state_ = std::make_unique<Component::StateNew>(component.get());
- component->crx_component_ = crx_component;
+ component->crx_component_ = std::move(crx_component);
return component;
}
@@ -238,11 +240,11 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
components[kUpdateItemId] = MakeComponent();
auto& component = components[kUpdateItemId];
- component->crx_component_.installer_attributes["ap"] = "some_ap";
+ component->crx_component_->installer_attributes["ap"] = "some_ap";
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -253,30 +255,29 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
<< post_interceptor_->GetRequestsAsString();
// Sanity check the request.
- const auto request = post_interceptor_->GetRequestBody(0);
- EXPECT_NE(string::npos,
- request.find("request protocol=\"3.1\" extra=\"params\""));
+ const auto& request = post_interceptor_->GetRequestBody(0);
+ EXPECT_THAT(request,
+ testing::HasSubstr(R"(request protocol="3.1" extra="params")"));
// The request must not contain any "dlpref" in the default case.
- EXPECT_EQ(string::npos, request.find(" dlpref=\""));
- EXPECT_NE(string::npos,
- request.find(std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" "
- "brand=\"TEST\"" +
- (GetParam() ? " installsource=\"ondemand\"" : "") +
- " ap=\"some_ap\" enabled=\"1\">"
- "<updatecheck/><ping r=\"-2\" "));
- EXPECT_NE(string::npos,
- request.find("<packages><package fp=\"fp1\"/></packages></app>"));
-
- EXPECT_NE(string::npos, request.find("<hw physmemory="));
-
- // Tests that the progid is injected correctly from the configurator.
- EXPECT_NE(
- string::npos,
- request.find(" version=\"fake_prodid-30.0\" prodversion=\"30.0\" "));
+ EXPECT_THAT(request, testing::Not(testing::HasSubstr(R"( dlpref=")")));
+ EXPECT_THAT(request,
+ testing::HasSubstr(
+ std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" brand="TEST")" +
+ (GetParam() ? R"( installsource="ondemand")" : "") +
+ R"( ap="some_ap" enabled="1"><updatecheck/><ping r="-2" )"));
+ EXPECT_THAT(
+ request,
+ testing::HasSubstr(R"(<packages><package fp="fp1"/></packages></app>)"));
+ EXPECT_THAT(request, testing::HasSubstr("<hw physmemory="));
+
+ // Tests that the product id is injected correctly from the configurator.
+ EXPECT_THAT(request, testing::HasSubstr(
+ R"( updater="fake_prodid" updaterversion="30.0")"
+ R"( prodversion="30.0" )"));
// Tests that there is a sessionid attribute.
- EXPECT_NE(string::npos, request.find(" sessionid="));
+ EXPECT_THAT(request, testing::HasSubstr(" sessionid="));
// Sanity check the arguments of the callback after parsing.
EXPECT_EQ(0, error_);
@@ -290,11 +291,11 @@ TEST_P(UpdateCheckerTest, UpdateCheckSuccess) {
EXPECT_STREQ("this", component->action_run_.c_str());
#if (OS_WIN)
- EXPECT_NE(string::npos, request.find(" domainjoined="));
+ EXPECT_THAT(request, testing::HasSubstr(" domainjoined="));
#if defined(GOOGLE_CHROME_BUILD)
// Check the Omaha updater state data in the request.
- EXPECT_NE(string::npos, request.find("<updater "));
- EXPECT_NE(string::npos, request.find(" name=\"Omaha\" "));
+ EXPECT_THAT(request, testing::HasSubstr("<updater "));
+ EXPECT_THAT(request, testing::HasSubstr(R"( name="Omaha" )"));
#endif // GOOGLE_CHROME_BUILD
#endif // OS_WINDOWS
@@ -323,23 +324,23 @@ TEST_F(UpdateCheckerTest, UpdateCheckInvalidAp) {
// Make "ap" too long.
auto& component = components[kUpdateItemId];
- component->crx_component_.installer_attributes["ap"] = std::string(257, 'a');
+ component->crx_component_->installer_attributes["ap"] = std::string(257, 'a');
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
const auto request = post_interceptor_->GetRequestBody(0);
- EXPECT_NE(string::npos,
- request.find(std::string("app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" brand=\"TEST\" enabled=\"1\">"
- "<updatecheck/><ping r=\"-2\" "));
- EXPECT_NE(string::npos,
- request.find("<packages><package fp=\"fp1\"/></packages></app>"));
+ EXPECT_THAT(request, testing::HasSubstr(
+ std::string(R"(app appid=")") + kUpdateItemId +
+ R"(" version="0.9" brand="TEST" enabled="1">)" +
+ R"(<updatecheck/><ping r="-2" )"));
+ EXPECT_THAT(
+ request,
+ testing::HasSubstr(R"(<packages><package fp="fp1"/></packages></app>)"));
}
TEST_F(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
@@ -354,20 +355,21 @@ TEST_F(UpdateCheckerTest, UpdateCheckSuccessNoBrand) {
components[kUpdateItemId] = MakeComponent();
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
const auto request = post_interceptor_->GetRequestBody(0);
- EXPECT_NE(string::npos,
- request.find(std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" enabled=\"1\">"
- "<updatecheck/><ping r=\"-2\" "));
- EXPECT_NE(string::npos,
- request.find("<packages><package fp=\"fp1\"/></packages></app>"));
+ EXPECT_THAT(
+ request,
+ testing::HasSubstr(
+ std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" enabled="1"><updatecheck/><ping r="-2" )"));
+ EXPECT_THAT(
+ request,
+ testing::HasSubstr(R"(<packages><package fp="fp1"/></packages></app>)"));
}
// Simulates a 403 server response error.
@@ -383,8 +385,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckError) {
auto& component = components[kUpdateItemId];
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -411,8 +412,8 @@ TEST_F(UpdateCheckerTest, UpdateCheckDownloadPreference) {
components[kUpdateItemId] = MakeComponent();
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
@@ -420,7 +421,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckDownloadPreference) {
// The request must contain dlpref="cacheable".
const auto request = post_interceptor_->GetRequestBody(0);
- EXPECT_NE(string::npos, request.find(" dlpref=\"cacheable\""));
+ EXPECT_THAT(request, testing::HasSubstr(R"( dlpref="cacheable")"));
}
// This test is checking that an update check signed with CUP fails, since there
@@ -440,8 +441,7 @@ TEST_F(UpdateCheckerTest, UpdateCheckCupError) {
const auto& component = components[kUpdateItemId];
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
@@ -453,14 +453,14 @@ TEST_F(UpdateCheckerTest, UpdateCheckCupError) {
<< post_interceptor_->GetRequestsAsString();
// Sanity check the request.
- const auto request = post_interceptor_->GetRequestBody(0);
- EXPECT_NE(string::npos,
- request.find(std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" "
- "brand=\"TEST\" enabled=\"1\">"
- "<updatecheck/><ping r=\"-2\" "));
- EXPECT_NE(string::npos,
- request.find("<packages><package fp=\"fp1\"/></packages></app>"));
+ const auto& request = post_interceptor_->GetRequestBody(0);
+ EXPECT_THAT(request, testing::HasSubstr(
+ std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" brand="TEST" enabled="1">)" +
+ R"(<updatecheck/><ping r="-2" )"));
+ EXPECT_THAT(
+ request,
+ testing::HasSubstr(R"(<packages><package fp="fp1"/></packages></app>)"));
// Expect an error since the response is not trusted.
EXPECT_EQ(-10000, error_);
@@ -478,11 +478,10 @@ TEST_F(UpdateCheckerTest, UpdateCheckRequiresEncryptionError) {
components[kUpdateItemId] = MakeComponent();
auto& component = components[kUpdateItemId];
- component->crx_component_.requires_network_encryption = true;
+ component->crx_component_->requires_network_encryption = true;
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -509,16 +508,16 @@ TEST_F(UpdateCheckerTest, UpdateCheckLastRollCall) {
// Do two update-checks.
activity_data_service_->SetDaysSinceLastRollCall(kUpdateItemId, 5);
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -527,10 +526,10 @@ TEST_F(UpdateCheckerTest, UpdateCheckLastRollCall) {
<< post_interceptor_->GetRequestsAsString();
ASSERT_EQ(2, post_interceptor_->GetCount())
<< post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(0).find(
- "<ping r=\"5\" ping_freshness="));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
- "<ping rd=\"3383\" ping_freshness="));
+ EXPECT_THAT(post_interceptor_->GetRequestBody(0),
+ testing::HasSubstr(R"(<ping r="5" ping_freshness=)"));
+ EXPECT_THAT(post_interceptor_->GetRequestBody(1),
+ testing::HasSubstr(R"(<ping rd="3383" ping_freshness=)"));
}
TEST_F(UpdateCheckerTest, UpdateCheckLastActive) {
@@ -552,8 +551,8 @@ TEST_F(UpdateCheckerTest, UpdateCheckLastActive) {
activity_data_service_->SetActiveBit(kUpdateItemId, true);
activity_data_service_->SetDaysSinceLastActive(kUpdateItemId, 10);
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -564,8 +563,8 @@ TEST_F(UpdateCheckerTest, UpdateCheckLastActive) {
activity_data_service_->SetActiveBit(kUpdateItemId, true);
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -575,8 +574,8 @@ TEST_F(UpdateCheckerTest, UpdateCheckLastActive) {
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "extra=\"params\"", true,
+ update_context_->session_id, {kUpdateItemId}, components,
+ "extra=\"params\"", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -587,12 +586,13 @@ TEST_F(UpdateCheckerTest, UpdateCheckLastActive) {
<< post_interceptor_->GetRequestsAsString();
ASSERT_EQ(3, post_interceptor_->GetCount())
<< post_interceptor_->GetRequestsAsString();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(0).find(
- "<ping a=\"10\" r=\"-2\" ping_freshness="));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
- "<ping ad=\"3383\" rd=\"3383\" ping_freshness="));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
- "<ping rd=\"3383\" ping_freshness="));
+ EXPECT_THAT(post_interceptor_->GetRequestBody(0),
+ testing::HasSubstr(R"(<ping a="10" r="-2" ping_freshness=)"));
+ EXPECT_THAT(
+ post_interceptor_->GetRequestBody(1),
+ testing::HasSubstr(R"(<ping ad="3383" rd="3383" ping_freshness=)"));
+ EXPECT_THAT(post_interceptor_->GetRequestBody(2),
+ testing::HasSubstr(R"(<ping rd="3383" ping_freshness=)"));
}
TEST_F(UpdateCheckerTest, UpdateCheckInstallSource) {
@@ -602,64 +602,65 @@ TEST_F(UpdateCheckerTest, UpdateCheckInstallSource) {
components[kUpdateItemId] = MakeComponent();
auto& component = components[kUpdateItemId];
- auto& crx_component = const_cast<CrxComponent&>(component->crx_component());
+ auto* crx_component = const_cast<CrxComponent*>(component->crx_component());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_EQ(string::npos,
- post_interceptor_->GetRequestBody(0).find("installsource="));
+ EXPECT_THAT(post_interceptor_->GetRequestBody(0),
+ testing::Not(testing::HasSubstr("installsource=")));
update_context_->is_foreground = true;
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
- "installsource=\"ondemand\""));
+ const auto& body1 = post_interceptor_->GetRequestBody(1);
+ EXPECT_THAT(body1, testing::HasSubstr(R"(installsource="ondemand")"));
+ EXPECT_THAT(body1, testing::Not(testing::HasSubstr(R"(installedby=)")));
update_context_->is_foreground = false;
- crx_component.install_source = "webstore";
+ crx_component->install_source = "webstore";
+ crx_component->install_location = "external";
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
- "installsource=\"webstore\""));
+ const auto& body2 = post_interceptor_->GetRequestBody(2);
+ EXPECT_THAT(body2, testing::HasSubstr(R"(installsource="webstore")"));
+ EXPECT_THAT(body2, testing::HasSubstr(R"(installedby="external")"));
update_context_->is_foreground = true;
- crx_component.install_source = "sideload";
+ crx_component->install_source = "sideload";
+ crx_component->install_location = "policy";
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(3).find(
- "installsource=\"sideload\""));
+ const auto& body3 = post_interceptor_->GetRequestBody(3);
+ EXPECT_THAT(body3, testing::HasSubstr(R"(installsource="sideload")"));
+ EXPECT_THAT(body3, testing::HasSubstr(R"(installedby="policy")"));
}
TEST_F(UpdateCheckerTest, ComponentDisabled) {
@@ -669,110 +670,99 @@ TEST_F(UpdateCheckerTest, ComponentDisabled) {
components[kUpdateItemId] = MakeComponent();
auto& component = components[kUpdateItemId];
- auto& crx_component = const_cast<CrxComponent&>(component->crx_component());
+ auto* crx_component = const_cast<CrxComponent*>(component->crx_component());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequestBody(0).find("enabled=\"1\""));
- EXPECT_EQ(string::npos,
- post_interceptor_->GetRequestBody(0).find("<disabled"));
- crx_component.disabled_reasons = std::vector<int>();
+ const auto& body0 = post_interceptor_->GetRequestBody(0);
+ EXPECT_THAT(body0, testing::HasSubstr(R"(enabled="1")"));
+ EXPECT_THAT(body0, testing::Not(testing::HasSubstr("<disabled")));
+
+ crx_component->disabled_reasons = {};
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequestBody(1).find("enabled=\"1\""));
- EXPECT_EQ(string::npos,
- post_interceptor_->GetRequestBody(1).find("<disabled"));
- crx_component.disabled_reasons = std::vector<int>({0});
+ const auto& body1 = post_interceptor_->GetRequestBody(1);
+ EXPECT_THAT(body1, testing::HasSubstr(R"(enabled="1")"));
+ EXPECT_THAT(body1, testing::Not(testing::HasSubstr("<disabled")));
+
+ crx_component->disabled_reasons = {0};
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequestBody(2).find("enabled=\"0\""));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
- "<disabled reason=\"0\"/>"));
- crx_component.disabled_reasons = std::vector<int>({1});
+ const auto& body2 = post_interceptor_->GetRequestBody(2);
+ EXPECT_THAT(body2, testing::HasSubstr(R"(enabled="0")"));
+ EXPECT_THAT(body2, testing::HasSubstr(R"(<disabled reason="0")"));
+
+ crx_component->disabled_reasons = {1};
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequestBody(3).find("enabled=\"0\""));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(3).find(
- "<disabled reason=\"1\"/>"));
- crx_component.disabled_reasons = std::vector<int>({4, 8, 16});
+ const auto& body3 = post_interceptor_->GetRequestBody(3);
+ EXPECT_THAT(body3, testing::HasSubstr(R"(enabled="0")"));
+ EXPECT_THAT(body3, testing::HasSubstr(R"(<disabled reason="1")"));
+
+ crx_component->disabled_reasons = {4, 8, 16};
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequestBody(4).find("enabled=\"0\""));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(4).find(
- "<disabled reason=\"4\"/>"));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(4).find(
- "<disabled reason=\"8\"/>"));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(4).find(
- "<disabled reason=\"16\"/>"));
-
- crx_component.disabled_reasons = std::vector<int>({0, 4, 8, 16});
+
+ const auto& body4 = post_interceptor_->GetRequestBody(4);
+ EXPECT_THAT(body4, testing::HasSubstr(R"(enabled="0")"));
+ EXPECT_THAT(body4, testing::HasSubstr(R"(<disabled reason="4")"));
+ EXPECT_THAT(body4, testing::HasSubstr(R"(<disabled reason="8")"));
+ EXPECT_THAT(body4, testing::HasSubstr(R"(<disabled reason="16")"));
+
+ crx_component->disabled_reasons = {0, 4, 8, 16};
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos,
- post_interceptor_->GetRequestBody(5).find("enabled=\"0\""));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
- "<disabled reason=\"0\"/>"));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
- "<disabled reason=\"4\"/>"));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
- "<disabled reason=\"8\"/>"));
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(5).find(
- "<disabled reason=\"16\"/>"));
+
+ const auto& body5 = post_interceptor_->GetRequestBody(5);
+ EXPECT_THAT(body5, testing::HasSubstr(R"(enabled="0")"));
+ EXPECT_THAT(body5, testing::HasSubstr(R"(<disabled reason="0")"));
+ EXPECT_THAT(body5, testing::HasSubstr(R"(<disabled reason="4")"));
+ EXPECT_THAT(body5, testing::HasSubstr(R"(<disabled reason="8")"));
+ EXPECT_THAT(body5, testing::HasSubstr(R"(<disabled reason="16")"));
}
TEST_F(UpdateCheckerTest, UpdateCheckUpdateDisabled) {
@@ -789,85 +779,82 @@ TEST_F(UpdateCheckerTest, UpdateCheckUpdateDisabled) {
// * the component updates are disabled.
// Expects the group policy to be ignored and the update check to not
// include the "updatedisabled" attribute.
- EXPECT_FALSE(
- component->crx_component_.supports_group_policy_enable_component_updates);
+ EXPECT_FALSE(component->crx_component_
+ ->supports_group_policy_enable_component_updates);
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(0).find(
- std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" enabled=\"1\">"
- "<updatecheck/>"));
+ EXPECT_THAT(
+ post_interceptor_->GetRequestBody(0),
+ testing::HasSubstr(std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" enabled="1"><updatecheck/>)"));
// Tests the scenario where:
// * the component supports group policies.
// * the component updates are disabled.
// Expects the update check to include the "updatedisabled" attribute.
- component->crx_component_.supports_group_policy_enable_component_updates =
+ component->crx_component_->supports_group_policy_enable_component_updates =
true;
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", false,
+ update_context_->session_id, {kUpdateItemId}, components, "", false,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(1).find(
- std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" enabled=\"1\">"
- "<updatecheck updatedisabled=\"true\"/>"));
+ EXPECT_THAT(
+ post_interceptor_->GetRequestBody(1),
+ testing::HasSubstr(std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" enabled="1">)" +
+ R"(<updatecheck updatedisabled="true"/>)"));
// Tests the scenario where:
// * the component does not support group policies.
// * the component updates are enabled.
// Expects the update check to not include the "updatedisabled" attribute.
- component->crx_component_.supports_group_policy_enable_component_updates =
+ component->crx_component_->supports_group_policy_enable_component_updates =
false;
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(2).find(
- std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" enabled=\"1\">"
- "<updatecheck/>"));
+ EXPECT_THAT(
+ post_interceptor_->GetRequestBody(2),
+ testing::HasSubstr(std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" enabled="1"><updatecheck/>)"));
// Tests the scenario where:
// * the component supports group policies.
// * the component updates are enabled.
// Expects the update check to not include the "updatedisabled" attribute.
- component->crx_component_.supports_group_policy_enable_component_updates =
+ component->crx_component_->supports_group_policy_enable_component_updates =
true;
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
EXPECT_TRUE(post_interceptor_->ExpectRequest(
std::make_unique<PartialMatch>("updatecheck"),
test_file("updatecheck_reply_1.xml")));
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- EXPECT_NE(string::npos, post_interceptor_->GetRequestBody(3).find(
- std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" enabled=\"1\">"
- "<updatecheck/>"));
+ EXPECT_THAT(
+ post_interceptor_->GetRequestBody(3),
+ testing::HasSubstr(std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" enabled="1"><updatecheck/>)"));
}
TEST_F(UpdateCheckerTest, NoUpdateActionRun) {
@@ -883,8 +870,7 @@ TEST_F(UpdateCheckerTest, NoUpdateActionRun) {
auto& component = components[kUpdateItemId];
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
@@ -915,19 +901,19 @@ TEST_F(UpdateCheckerTest, UpdatePauseResume) {
components[kUpdateItemId] = MakeComponent();
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
RunThreads();
- const auto request = post_interceptor_->GetRequestBody(0);
- EXPECT_NE(string::npos,
- request.find(std::string("<app appid=\"") + kUpdateItemId +
- "\" version=\"0.9\" brand=\"TEST\" enabled=\"1\">"
- "<updatecheck/><ping r=\"-2\" "));
- EXPECT_NE(string::npos,
- request.find("<packages><package fp=\"fp1\"/></packages></app>"));
+ const auto& request = post_interceptor_->GetRequestBody(0);
+ EXPECT_THAT(request, testing::HasSubstr(
+ std::string(R"(<app appid=")") + kUpdateItemId +
+ R"(" version="0.9" brand="TEST" enabled="1">)" +
+ R"(<updatecheck/><ping r="-2" )"));
+ EXPECT_THAT(
+ request,
+ testing::HasSubstr(R"(<packages><package fp="fp1"/></packages></app>)"));
}
// Tests that an update checker object and its underlying URLFetcher can
@@ -949,8 +935,7 @@ TEST_F(UpdateCheckerTest, UpdateResetUpdateChecker) {
update_checker_ = UpdateChecker::Create(config_, metadata_.get());
update_checker_->CheckForUpdates(
- update_context_->session_id, std::vector<std::string>{kUpdateItemId},
- components, "", true,
+ update_context_->session_id, {kUpdateItemId}, components, "", true,
base::BindOnce(&UpdateCheckerTest::UpdateCheckComplete,
base::Unretained(this)));
runloop.Run();
diff --git a/chromium/components/update_client/update_client.h b/chromium/components/update_client/update_client.h
index af0df043f0b..d8d546a16a2 100644
--- a/chromium/components/update_client/update_client.h
+++ b/chromium/components/update_client/update_client.h
@@ -258,6 +258,11 @@ struct CrxComponent {
// For extension, this information is set from the update service, which
// gets the install source from the update URL.
std::string install_source;
+
+ // Information about where the component/extension was loaded from.
+ // For extensions, this information is inferred from the extension
+ // registry.
+ std::string install_location;
};
// Called when a non-blocking call of UpdateClient completes.
@@ -270,8 +275,8 @@ using Callback = base::OnceCallback<void(Error error)>;
class UpdateClient : public base::RefCounted<UpdateClient> {
public:
using CrxDataCallback =
- base::OnceCallback<void(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components)>;
+ base::OnceCallback<std::vector<std::unique_ptr<CrxComponent>>(
+ const std::vector<std::string>& ids)>;
// Defines an interface to observe the UpdateClient. It provides
// notifications when state changes occur for the service itself or for the
diff --git a/chromium/components/update_client/update_client_errors.h b/chromium/components/update_client/update_client_errors.h
index 814f08a1d77..129d7aa9763 100644
--- a/chromium/components/update_client/update_client_errors.h
+++ b/chromium/components/update_client/update_client_errors.h
@@ -17,16 +17,18 @@ enum class Error {
RETRY_LATER = 3,
SERVICE_ERROR = 4,
UPDATE_CHECK_ERROR = 5,
+ CRX_NOT_FOUND = 6,
};
// These errors are sent in pings. Add new values only to the bottom of
// the enums below; the order must be kept stable.
enum class ErrorCategory {
- kErrorNone = 0,
- kNetworkError,
- kUnpackError,
- kInstallError,
- kServiceError, // Runtime errors which occur in the service itself.
+ kNone = 0,
+ kDownload,
+ kUnpack,
+ kInstall,
+ kService, // Runtime errors which occur in the service itself.
+ kUpdateCheck,
};
// These errors are returned with the |kNetworkError| error category. This
@@ -43,7 +45,7 @@ enum class CrxDownloaderError {
GENERIC_ERROR = -1
};
-// These errors are returned with the |kUnpackError| error category and
+// These errors are returned with the |kUnpack| error category and
// indicate unpacker or patcher error.
enum class UnpackerError {
kNone = 0,
@@ -66,7 +68,7 @@ enum class UnpackerError {
// kFingerprintWriteFailed = 17, // Deprecated. Don't use.
};
-// These errors are returned with the |kServiceError| error category and
+// These errors are returned with the |kService| error category and
// are returned by the component installers.
enum class InstallError {
NONE = 0,
@@ -83,7 +85,7 @@ enum class InstallError {
CUSTOM_ERROR_BASE = 100, // Specific installer errors go above this value.
};
-// These errors are returned with the |kInstallError| error category and
+// These errors are returned with the |kInstall| error category and
// indicate critical or configuration errors in the update service.
enum class ServiceError {
NONE = 0,
diff --git a/chromium/components/update_client/update_client_unittest.cc b/chromium/components/update_client/update_client_unittest.cc
index 4b9c0b1fdde..581cbf9e9b9 100644
--- a/chromium/components/update_client/update_client_unittest.cc
+++ b/chromium/components/update_client/update_client_unittest.cc
@@ -13,6 +13,7 @@
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
+#include "base/stl_util.h"
#include "base/task_scheduler/post_task.h"
#include "base/task_scheduler/task_traits.h"
#include "base/test/scoped_path_override.h"
@@ -93,10 +94,10 @@ class MockPingManagerImpl : public PingManager {
std::string id;
base::Version previous_version;
base::Version next_version;
- int error_category = 0;
+ ErrorCategory error_category = ErrorCategory::kNone;
int error_code = 0;
int extra_code1 = 0;
- int diff_error_category = 0;
+ ErrorCategory diff_error_category = ErrorCategory::kNone;
int diff_error_code = 0;
bool diff_update_failed = false;
};
@@ -200,7 +201,7 @@ void UpdateClientTest::RunThreads() {
base::FilePath UpdateClientTest::TestFilePath(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components")
.AppendASCII("test")
.AppendASCII("data")
@@ -213,14 +214,16 @@ base::FilePath UpdateClientTest::TestFilePath(const char* file) {
TEST_F(UpdateClientTest, OneCrxNoUpdate) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.9");
- crx.installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx);
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.9");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -319,22 +322,24 @@ TEST_F(UpdateClientTest, OneCrxNoUpdate) {
TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx1;
- crx1.name = "test_jebg";
- crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = base::Version("0.9");
- crx1.installer = base::MakeRefCounted<TestInstaller>();
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
+ crx1->name = "test_jebg";
+ crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx1->version = base::Version("0.9");
+ crx1->installer = base::MakeRefCounted<TestInstaller>();
- CrxComponent crx2;
- crx2.name = "test_abag";
- crx2.pk_hash.assign(abag_hash, abag_hash + arraysize(abag_hash));
- crx2.version = base::Version("2.2");
- crx2.installer = base::MakeRefCounted<TestInstaller>();
+ std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
+ crx2->name = "test_abag";
+ crx2->pk_hash.assign(abag_hash, abag_hash + base::size(abag_hash));
+ crx2->version = base::Version("2.2");
+ crx2->installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx1);
- components->push_back(crx2);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx1));
+ component.push_back(std::move(crx2));
+ return component;
}
};
@@ -482,7 +487,7 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(0, ping_data[0].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(0, ping_data[0].error_code);
}
};
@@ -528,26 +533,26 @@ TEST_F(UpdateClientTest, TwoCrxUpdateNoUpdate) {
update_client->RemoveObserver(&observer);
}
-// Tests the update check for two CRXs scenario. Both CRXs have updates.
-TEST_F(UpdateClientTest, TwoCrxUpdate) {
+// Tests the update check for two CRXs scenario when the second CRX does not
+// provide a CrxComponent instance. In this case, the update is handled as
+// if only one component were provided as an argument to the |Update| call
+// with the exception that the second component still fires an event such as
+// |COMPONENT_UPDATE_ERROR|.
+TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentData) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx1;
- crx1.name = "test_jebg";
- crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = base::Version("0.9");
- crx1.installer = base::MakeRefCounted<TestInstaller>();
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.9");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
- CrxComponent crx2;
- crx2.name = "test_ihfo";
- crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx2.version = base::Version("0.8");
- crx2.installer = base::MakeRefCounted<TestInstaller>();
-
- components->push_back(crx1);
- components->push_back(crx2);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ component.push_back(std::move(nullptr));
+ return component;
}
};
@@ -592,25 +597,11 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
</manifest>
</updatecheck>
</app>
- <app appid='ihfokbkgjpifnbbojhneepfflplebdkc'>
- <updatecheck status='ok'>
- <urls>
- <url codebase='http://localhost/download/'/>
- </urls>
- <manifest version='1.0' prodversionmin='11.0.1.0'>
- <packages>
- <package name='ihfokbkgjpifnbbojhneepfflplebdkc_1.crx'
- hash_sha256='813c59747e139a608b3b5fc49633affc6db574373f
- 309f156ea6d27229c0b3f9'/>
- </packages>
- </manifest>
- </updatecheck>
- </app>
</response>
*/
EXPECT_FALSE(session_id.empty());
EXPECT_TRUE(enabled_component_updates);
- EXPECT_EQ(2u, ids_to_check.size());
+ EXPECT_EQ(1u, ids_to_check.size());
{
const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
@@ -636,30 +627,6 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
EXPECT_FALSE(component->is_foreground());
}
- {
- const std::string id = "ihfokbkgjpifnbbojhneepfflplebdkc";
- EXPECT_EQ(id, ids_to_check[1]);
- EXPECT_EQ(1u, components.count(id));
-
- ProtocolParser::Result::Manifest::Package package;
- package.name = "ihfokbkgjpifnbbojhneepfflplebdkc_1.crx";
- package.hash_sha256 =
- "813c59747e139a608b3b5fc49633affc6db574373f309f156ea6d27229c0b3f9";
-
- ProtocolParser::Result result;
- result.extension_id = id;
- result.status = "ok";
- result.crx_urls.push_back(GURL("http://localhost/download/"));
- result.manifest.version = "1.0";
- result.manifest.browser_min_version = "11.0.1.0";
- result.manifest.packages.push_back(package);
-
- auto& component = components.at(id);
- component->SetParseResult(result);
-
- EXPECT_FALSE(component->is_foreground());
- }
-
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(update_check_callback), 0, 0));
}
@@ -695,22 +662,6 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
result.response = path;
result.downloaded_bytes = 1843;
result.total_bytes = 1843;
- } else if (url.path() ==
- "/download/ihfokbkgjpifnbbojhneepfflplebdkc_1.crx") {
- download_metrics.url = url;
- download_metrics.downloader = DownloadMetrics::kNone;
- download_metrics.error = 0;
- download_metrics.downloaded_bytes = 53638;
- download_metrics.total_bytes = 53638;
- download_metrics.download_time_ms = 2000;
-
- EXPECT_TRUE(MakeTestFile(
- TestFilePath("ihfokbkgjpifnbbojhneepfflplebdkc_1.crx"), &path));
-
- result.error = 0;
- result.response = path;
- result.downloaded_bytes = 53638;
- result.total_bytes = 53638;
} else {
NOTREACHED();
}
@@ -734,17 +685,12 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
protected:
~MockPingManager() override {
const auto ping_data = MockPingManagerImpl::ping_data();
- EXPECT_EQ(2u, ping_data.size());
+ EXPECT_EQ(1u, ping_data.size());
EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(0, ping_data[0].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(0, ping_data[0].error_code);
- EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
- EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
- EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
- EXPECT_EQ(0, ping_data[1].error_category);
- EXPECT_EQ(0, ping_data[1].error_code);
}
};
@@ -770,19 +716,104 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
}
{
InSequence seq;
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_CHECKING_FOR_UPDATES,
- "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_FOUND,
- "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_WAIT,
- "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_DOWNLOADING,
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
"ihfokbkgjpifnbbojhneepfflplebdkc"))
- .Times(AtLeast(1));
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_READY,
- "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
- EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATED,
- "ihfokbkgjpifnbbojhneepfflplebdkc")).Times(1);
+ .Times(1);
+ }
+
+ update_client->AddObserver(&observer);
+
+ const std::vector<std::string> ids = {"jebgalgnebhfojomionfpkfelancnnkf",
+ "ihfokbkgjpifnbbojhneepfflplebdkc"};
+ update_client->Update(
+ ids, base::BindOnce(&DataCallbackMock::Callback), false,
+ base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
+// Tests the update check for two CRXs scenario when no CrxComponent data is
+// provided for either component. In this case, no update check occurs, and
+// |COMPONENT_UPDATE_ERROR| event fires for both components.
+TEST_F(UpdateClientTest, TwoCrxUpdateNoCrxComponentDataAtAll) {
+ class DataCallbackMock {
+ public:
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(nullptr));
+ component.push_back(std::move(nullptr));
+ return component;
+ }
+ };
+
+ class CompletionCallbackMock {
+ public:
+ static void Callback(base::OnceClosure quit_closure, Error error) {
+ EXPECT_EQ(Error::NONE, error);
+ std::move(quit_closure).Run();
+ }
+ };
+
+ class MockUpdateChecker : public UpdateChecker {
+ public:
+ static std::unique_ptr<UpdateChecker> Create(
+ scoped_refptr<Configurator> config,
+ PersistedData* metadata) {
+ return std::make_unique<MockUpdateChecker>();
+ }
+
+ void CheckForUpdates(const std::string& session_id,
+ const std::vector<std::string>& ids_to_check,
+ const IdToComponentPtrMap& components,
+ const std::string& additional_attributes,
+ bool enabled_component_updates,
+ UpdateCheckCallback update_check_callback) override {
+ NOTREACHED();
+ }
+ };
+
+ class MockCrxDownloader : public CrxDownloader {
+ public:
+ static std::unique_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ scoped_refptr<net::URLRequestContextGetter> context_getter) {
+ return std::make_unique<MockCrxDownloader>();
+ }
+
+ MockCrxDownloader() : CrxDownloader(nullptr) {}
+
+ private:
+ void DoStartDownload(const GURL& url) override { NOTREACHED(); }
+ };
+
+ class MockPingManager : public MockPingManagerImpl {
+ public:
+ explicit MockPingManager(scoped_refptr<Configurator> config)
+ : MockPingManagerImpl(config) {}
+
+ protected:
+ ~MockPingManager() override {
+ EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
+ }
+ };
+
+ scoped_refptr<UpdateClient> update_client =
+ base::MakeRefCounted<UpdateClientImpl>(
+ config(), base::MakeRefCounted<MockPingManager>(config()),
+ &MockUpdateChecker::Create, &MockCrxDownloader::Create);
+
+ MockObserver observer;
+ {
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
+ "jebgalgnebhfojomionfpkfelancnnkf"))
+ .Times(1);
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
+ "ihfokbkgjpifnbbojhneepfflplebdkc"))
+ .Times(1);
}
update_client->AddObserver(&observer);
@@ -804,22 +835,24 @@ TEST_F(UpdateClientTest, TwoCrxUpdate) {
TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx1;
- crx1.name = "test_jebg";
- crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = base::Version("0.9");
- crx1.installer = base::MakeRefCounted<TestInstaller>();
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
+ crx1->name = "test_jebg";
+ crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx1->version = base::Version("0.9");
+ crx1->installer = base::MakeRefCounted<TestInstaller>();
- CrxComponent crx2;
- crx2.name = "test_ihfo";
- crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx2.version = base::Version("0.8");
- crx2.installer = base::MakeRefCounted<TestInstaller>();
+ std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
+ crx2->name = "test_ihfo";
+ crx2->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
+ crx2->version = base::Version("0.8");
+ crx2->installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx1);
- components->push_back(crx2);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx1));
+ component.push_back(std::move(crx2));
+ return component;
}
};
@@ -1004,12 +1037,12 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(1, ping_data[0].error_category);
+ EXPECT_EQ(1, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(-118, ping_data[0].error_code);
EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
- EXPECT_EQ(0, ping_data[1].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
EXPECT_EQ(0, ping_data[1].error_code);
}
};
@@ -1031,7 +1064,15 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
.Times(AtLeast(1));
EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
"jebgalgnebhfojomionfpkfelancnnkf"))
- .Times(1);
+ .Times(1)
+ .WillOnce(Invoke([&update_client](Events event, const std::string& id) {
+ CrxUpdateItem item;
+ update_client->GetCrxUpdateState(id, &item);
+ EXPECT_EQ(ComponentState::kUpdateError, item.state);
+ EXPECT_EQ(1, static_cast<int>(item.error_category));
+ EXPECT_EQ(-118, item.error_code);
+ EXPECT_EQ(0, item.extra_code1);
+ }));
}
{
InSequence seq;
@@ -1068,8 +1109,8 @@ TEST_F(UpdateClientTest, TwoCrxUpdateDownloadTimeout) {
TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
static int num_calls = 0;
// Must use the same stateful installer object.
@@ -1078,19 +1119,21 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
++num_calls;
- CrxComponent crx;
- crx.name = "test_ihfo";
- crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx.installer = installer;
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_ihfo";
+ crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
+ crx->installer = installer;
if (num_calls == 1) {
- crx.version = base::Version("0.8");
+ crx->version = base::Version("0.8");
} else if (num_calls == 2) {
- crx.version = base::Version("1.0");
+ crx->version = base::Version("1.0");
} else {
NOTREACHED();
}
- components->push_back(crx);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -1295,15 +1338,15 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdate) {
EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(0, ping_data[0].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(0, ping_data[0].error_code);
EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
EXPECT_FALSE(ping_data[1].diff_update_failed);
- EXPECT_EQ(0, ping_data[1].diff_error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[1].diff_error_category));
EXPECT_EQ(0, ping_data[1].diff_error_code);
- EXPECT_EQ(0, ping_data[1].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
EXPECT_EQ(0, ping_data[1].error_code);
}
};
@@ -1381,7 +1424,7 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
void Install(const base::FilePath& unpack_path,
const std::string& public_key,
- Callback callback) {
+ Callback callback) override {
DoInstall(unpack_path, std::move(callback));
unpack_path_ = unpack_path;
@@ -1408,8 +1451,8 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
scoped_refptr<MockInstaller> installer =
base::MakeRefCounted<MockInstaller>();
@@ -1418,12 +1461,15 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
EXPECT_CALL(*installer, GetInstalledFile(_, _)).Times(0);
EXPECT_CALL(*installer, Uninstall()).Times(0);
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.9");
- crx.installer = installer;
- components->push_back(crx);
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.9");
+ crx->installer = installer;
+
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -1550,8 +1596,8 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(3, ping_data[0].error_category); // kInstallError.
- EXPECT_EQ(9, ping_data[0].error_code); // kInstallerError.
+ EXPECT_EQ(3, static_cast<int>(ping_data[0].error_category)); // kInstall.
+ EXPECT_EQ(9, ping_data[0].error_code); // kInstallerError.
}
};
@@ -1593,8 +1639,8 @@ TEST_F(UpdateClientTest, OneCrxInstallError) {
TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
static int num_calls = 0;
// Must use the same stateful installer object.
@@ -1603,19 +1649,21 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
++num_calls;
- CrxComponent crx;
- crx.name = "test_ihfo";
- crx.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx.installer = installer;
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_ihfo";
+ crx->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
+ crx->installer = installer;
if (num_calls == 1) {
- crx.version = base::Version("0.8");
+ crx->version = base::Version("0.8");
} else if (num_calls == 2) {
- crx.version = base::Version("1.0");
+ crx->version = base::Version("1.0");
} else {
NOTREACHED();
}
- components->push_back(crx);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -1834,15 +1882,15 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[0].id);
EXPECT_EQ(base::Version("0.8"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(0, ping_data[0].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(0, ping_data[0].error_code);
EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
EXPECT_EQ(base::Version("1.0"), ping_data[1].previous_version);
EXPECT_EQ(base::Version("2.0"), ping_data[1].next_version);
- EXPECT_EQ(0, ping_data[1].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
EXPECT_EQ(0, ping_data[1].error_code);
EXPECT_TRUE(ping_data[1].diff_update_failed);
- EXPECT_EQ(1, ping_data[1].diff_error_category); // kNetworkError.
+ EXPECT_EQ(1, static_cast<int>(ping_data[1].diff_error_category));
EXPECT_EQ(-1, ping_data[1].diff_error_code);
}
};
@@ -1911,14 +1959,16 @@ TEST_F(UpdateClientTest, OneCrxDiffUpdateFailsFullUpdateSucceeds) {
TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.9");
- crx.installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx);
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.9");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -2028,15 +2078,17 @@ TEST_F(UpdateClientTest, OneCrxNoUpdateQueuedCall) {
TEST_F(UpdateClientTest, OneCrxInstall) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.0");
- crx.installer = base::MakeRefCounted<TestInstaller>();
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.0");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -2172,7 +2224,7 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
EXPECT_EQ(base::Version("0.0"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(0, ping_data[0].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(0, ping_data[0].error_code);
}
};
@@ -2208,19 +2260,107 @@ TEST_F(UpdateClientTest, OneCrxInstall) {
update_client->RemoveObserver(&observer);
}
+// Tests the install of one CRX when no component data is provided. This
+// results in an install error.
+TEST_F(UpdateClientTest, OneCrxInstallNoCrxComponentData) {
+ class DataCallbackMock {
+ public:
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(nullptr);
+ return component;
+ }
+ };
+
+ class CompletionCallbackMock {
+ public:
+ static void Callback(base::OnceClosure quit_closure, Error error) {
+ EXPECT_EQ(Error::NONE, error);
+ std::move(quit_closure).Run();
+ }
+ };
+
+ class MockUpdateChecker : public UpdateChecker {
+ public:
+ static std::unique_ptr<UpdateChecker> Create(
+ scoped_refptr<Configurator> config,
+ PersistedData* metadata) {
+ return std::make_unique<MockUpdateChecker>();
+ }
+
+ void CheckForUpdates(const std::string& session_id,
+ const std::vector<std::string>& ids_to_check,
+ const IdToComponentPtrMap& components,
+ const std::string& additional_attributes,
+ bool enabled_component_updates,
+ UpdateCheckCallback update_check_callback) override {
+ NOTREACHED();
+ }
+ };
+
+ class MockCrxDownloader : public CrxDownloader {
+ public:
+ static std::unique_ptr<CrxDownloader> Create(
+ bool is_background_download,
+ scoped_refptr<net::URLRequestContextGetter> context_getter) {
+ return std::make_unique<MockCrxDownloader>();
+ }
+
+ MockCrxDownloader() : CrxDownloader(nullptr) {}
+
+ private:
+ void DoStartDownload(const GURL& url) override { NOTREACHED(); }
+ };
+
+ class MockPingManager : public MockPingManagerImpl {
+ public:
+ explicit MockPingManager(scoped_refptr<Configurator> config)
+ : MockPingManagerImpl(config) {}
+
+ protected:
+ ~MockPingManager() override {
+ EXPECT_EQ(0u, MockPingManagerImpl::ping_data().size());
+ }
+ };
+
+ scoped_refptr<UpdateClient> update_client =
+ base::MakeRefCounted<UpdateClientImpl>(
+ config(), base::MakeRefCounted<MockPingManager>(config()),
+ &MockUpdateChecker::Create, &MockCrxDownloader::Create);
+
+ MockObserver observer;
+ InSequence seq;
+ EXPECT_CALL(observer, OnEvent(Events::COMPONENT_UPDATE_ERROR,
+ "jebgalgnebhfojomionfpkfelancnnkf"))
+ .Times(1);
+
+ update_client->AddObserver(&observer);
+
+ update_client->Install(
+ std::string("jebgalgnebhfojomionfpkfelancnnkf"),
+ base::BindOnce(&DataCallbackMock::Callback),
+ base::BindOnce(&CompletionCallbackMock::Callback, quit_closure()));
+
+ RunThreads();
+
+ update_client->RemoveObserver(&observer);
+}
+
// Tests that overlapping installs of the same CRX result in an error.
TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.0");
- crx.installer = base::MakeRefCounted<TestInstaller>();
-
- components->push_back(crx);
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.0");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -2337,8 +2477,10 @@ TEST_F(UpdateClientTest, ConcurrentInstallSameCRX) {
TEST_F(UpdateClientTest, EmptyIdList) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {}
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ return {};
+ }
};
class CompletionCallbackMock {
@@ -2474,14 +2616,16 @@ TEST_F(UpdateClientTest, SendUninstallPing) {
TEST_F(UpdateClientTest, RetryAfter) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.9");
- crx.installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx);
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.9");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -2666,23 +2810,25 @@ TEST_F(UpdateClientTest, RetryAfter) {
TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx1;
- crx1.name = "test_jebg";
- crx1.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx1.version = base::Version("0.9");
- crx1.installer = base::MakeRefCounted<TestInstaller>();
- crx1.supports_group_policy_enable_component_updates = true;
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx1 = std::make_unique<CrxComponent>();
+ crx1->name = "test_jebg";
+ crx1->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx1->version = base::Version("0.9");
+ crx1->installer = base::MakeRefCounted<TestInstaller>();
+ crx1->supports_group_policy_enable_component_updates = true;
- CrxComponent crx2;
- crx2.name = "test_ihfo";
- crx2.pk_hash.assign(ihfo_hash, ihfo_hash + arraysize(ihfo_hash));
- crx2.version = base::Version("0.8");
- crx2.installer = base::MakeRefCounted<TestInstaller>();
+ std::unique_ptr<CrxComponent> crx2 = std::make_unique<CrxComponent>();
+ crx2->name = "test_ihfo";
+ crx2->pk_hash.assign(ihfo_hash, ihfo_hash + base::size(ihfo_hash));
+ crx2->version = base::Version("0.8");
+ crx2->installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx1);
- components->push_back(crx2);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx1));
+ component.push_back(std::move(crx2));
+ return component;
}
};
@@ -2858,12 +3004,12 @@ TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
EXPECT_EQ("jebgalgnebhfojomionfpkfelancnnkf", ping_data[0].id);
EXPECT_EQ(base::Version("0.9"), ping_data[0].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[0].next_version);
- EXPECT_EQ(4, ping_data[0].error_category);
+ EXPECT_EQ(4, static_cast<int>(ping_data[0].error_category));
EXPECT_EQ(2, ping_data[0].error_code);
EXPECT_EQ("ihfokbkgjpifnbbojhneepfflplebdkc", ping_data[1].id);
EXPECT_EQ(base::Version("0.8"), ping_data[1].previous_version);
EXPECT_EQ(base::Version("1.0"), ping_data[1].next_version);
- EXPECT_EQ(0, ping_data[1].error_category);
+ EXPECT_EQ(0, static_cast<int>(ping_data[1].error_category));
EXPECT_EQ(0, ping_data[1].error_code);
}
};
@@ -2924,14 +3070,16 @@ TEST_F(UpdateClientTest, TwoCrxUpdateOneUpdateDisabled) {
TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
class DataCallbackMock {
public:
- static void Callback(const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_jebg";
- crx.pk_hash.assign(jebg_hash, jebg_hash + arraysize(jebg_hash));
- crx.version = base::Version("0.9");
- crx.installer = base::MakeRefCounted<TestInstaller>();
- components->push_back(crx);
+ static std::vector<std::unique_ptr<CrxComponent>> Callback(
+ const std::vector<std::string>& ids) {
+ std::unique_ptr<CrxComponent> crx = std::make_unique<CrxComponent>();
+ crx->name = "test_jebg";
+ crx->pk_hash.assign(jebg_hash, jebg_hash + base::size(jebg_hash));
+ crx->version = base::Version("0.9");
+ crx->installer = base::MakeRefCounted<TestInstaller>();
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}
};
@@ -2963,9 +3111,11 @@ TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
const std::string id = "jebgalgnebhfojomionfpkfelancnnkf";
EXPECT_EQ(id, ids_to_check.front());
EXPECT_EQ(1u, components.count(id));
-
+ constexpr int update_check_error = -1;
+ components.at(id)->set_update_check_error(update_check_error);
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(std::move(update_check_callback), -1, 0));
+ FROM_HERE, base::BindOnce(std::move(update_check_callback),
+ update_check_error, 0));
}
};
@@ -3009,6 +3159,9 @@ TEST_F(UpdateClientTest, OneCrxUpdateCheckFails) {
CrxUpdateItem item;
update_client->GetCrxUpdateState(id, &item);
EXPECT_EQ(ComponentState::kUpdateError, item.state);
+ EXPECT_EQ(5, static_cast<int>(item.error_category));
+ EXPECT_EQ(-1, item.error_code);
+ EXPECT_EQ(0, item.extra_code1);
}));
update_client->AddObserver(&observer);
@@ -3170,14 +3323,15 @@ TEST_F(UpdateClientTest, ActionRun_Install) {
// The action is a program which returns 1877345072 as a hardcoded value.
update_client->Install(
std::string("gjpmebpgbhcamgdgjcmnjfhggjpgcimm"),
- base::BindOnce([](const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_niea";
- crx.pk_hash.assign(gjpm_hash, gjpm_hash + arraysize(gjpm_hash));
- crx.version = base::Version("0.0");
- crx.installer = base::MakeRefCounted<VersionedTestInstaller>();
- components->push_back(crx);
+ base::BindOnce([](const std::vector<std::string>& ids) {
+ auto crx = std::make_unique<CrxComponent>();
+ crx->name = "test_niea";
+ crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
+ crx->version = base::Version("0.0");
+ crx->installer = base::MakeRefCounted<VersionedTestInstaller>();
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
}),
base::BindOnce(
[](base::OnceClosure quit_closure, Error error) {
@@ -3278,7 +3432,7 @@ TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
base::OnceClosure quit_closure = runloop.QuitClosure();
auto config = base::MakeRefCounted<TestConfigurator>();
- scoped_refptr<ComponentUnpacker> component_unpacker = new ComponentUnpacker(
+ auto component_unpacker = base::MakeRefCounted<ComponentUnpacker>(
std::vector<uint8_t>(std::begin(gjpm_hash), std::end(gjpm_hash)),
TestFilePath("runaction_test_win.crx3"), nullptr,
config->CreateServiceManagerConnector());
@@ -3317,15 +3471,16 @@ TEST_F(UpdateClientTest, ActionRun_NoUpdate) {
ids,
base::BindOnce(
[](const base::FilePath& unpack_path,
- const std::vector<std::string>& ids,
- std::vector<CrxComponent>* components) {
- CrxComponent crx;
- crx.name = "test_niea";
- crx.pk_hash.assign(gjpm_hash, gjpm_hash + arraysize(gjpm_hash));
- crx.version = base::Version("1.0");
- crx.installer =
+ const std::vector<std::string>& ids) {
+ auto crx = std::make_unique<CrxComponent>();
+ crx->name = "test_niea";
+ crx->pk_hash.assign(gjpm_hash, gjpm_hash + base::size(gjpm_hash));
+ crx->version = base::Version("1.0");
+ crx->installer =
base::MakeRefCounted<ReadOnlyTestInstaller>(unpack_path);
- components->push_back(crx);
+ std::vector<std::unique_ptr<CrxComponent>> component;
+ component.push_back(std::move(crx));
+ return component;
},
unpack_path),
false,
diff --git a/chromium/components/update_client/update_engine.cc b/chromium/components/update_client/update_engine.cc
index 1f33635b12b..351cb3893c2 100644
--- a/chromium/components/update_client/update_engine.cc
+++ b/chromium/components/update_client/update_engine.cc
@@ -97,31 +97,44 @@ void UpdateEngine::Update(bool is_foreground,
// Calls out to get the corresponding CrxComponent data for the CRXs in this
// update context.
- DCHECK_EQ(ids.size(), update_context->ids.size());
- DCHECK_EQ(update_context->ids.size(), update_context->components.size());
- std::vector<CrxComponent> crx_components;
- std::move(update_context->crx_data_callback)
- .Run(update_context->ids, &crx_components);
+ std::vector<std::unique_ptr<CrxComponent>> crx_components =
+ std::move(update_context->crx_data_callback).Run(update_context->ids);
DCHECK_EQ(update_context->ids.size(), crx_components.size());
for (size_t i = 0; i != update_context->ids.size(); ++i) {
const auto& id = update_context->ids[i];
- const auto& crx_component = crx_components[i];
- DCHECK_EQ(id, GetCrxComponentID(crx_component));
- DCHECK_EQ(1u, update_context->components.count(id));
- DCHECK(update_context->components.at(id));
+ DCHECK(update_context->components[id]->state() == ComponentState::kNew);
+
+ auto& crx_component = crx_components[i];
+ if (crx_component) {
+ // This component can be checked for updates.
+ DCHECK_EQ(id, GetCrxComponentID(*crx_component));
+ auto& component = update_context->components[id];
+ component->set_crx_component(std::move(crx_component));
+ component->set_previous_version(component->crx_component()->version);
+ component->set_previous_fp(component->crx_component()->fingerprint);
+ update_context->components_to_check_for_updates.push_back(id);
+ } else {
+ // |CrxDataCallback| did not return a CrxComponent instance for this
+ // component, which most likely, has been uninstalled. This component
+ // is going to be transitioned to an error state when the its |Handle|
+ // method is called later on by the engine.
+ update_context->component_queue.push(id);
+ }
+ }
- auto& component = *update_context->components.at(id);
- component.set_crx_component(crx_component);
- component.set_previous_version(crx_component.version);
- component.set_previous_fp(crx_component.fingerprint);
+ if (update_context->components_to_check_for_updates.empty()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&UpdateEngine::HandleComponent,
+ base::Unretained(this), update_context));
+ return;
+ }
- // Handle |kNew| state. This will transition the components to |kChecking|.
- component.Handle(
+ for (const auto& id : update_context->components_to_check_for_updates)
+ update_context->components[id]->Handle(
base::BindOnce(&UpdateEngine::ComponentCheckingForUpdatesStart,
base::Unretained(this), update_context, id));
- }
}
void UpdateEngine::ComponentCheckingForUpdatesStart(
@@ -141,7 +154,7 @@ void UpdateEngine::ComponentCheckingForUpdatesStart(
++update_context->num_components_ready_to_check;
if (update_context->num_components_ready_to_check <
- update_context->ids.size()) {
+ update_context->components_to_check_for_updates.size()) {
return;
}
@@ -158,7 +171,8 @@ void UpdateEngine::DoUpdateCheck(scoped_refptr<UpdateContext> update_context) {
update_checker_factory_(config_, metadata_.get());
update_context->update_checker->CheckForUpdates(
- update_context->session_id, update_context->ids,
+ update_context->session_id,
+ update_context->components_to_check_for_updates,
update_context->components, config_->ExtraRequestParams(),
update_context->enabled_component_updates,
base::BindOnce(&UpdateEngine::UpdateCheckDone, base::Unretained(this),
@@ -188,7 +202,7 @@ void UpdateEngine::UpdateCheckDone(scoped_refptr<UpdateContext> update_context,
update_context->update_check_error = error;
- for (const auto& id : update_context->ids) {
+ for (const auto& id : update_context->components_to_check_for_updates) {
DCHECK_EQ(1u, update_context->components.count(id));
DCHECK(update_context->components.at(id));
@@ -203,7 +217,8 @@ void UpdateEngine::ComponentCheckingForUpdatesComplete(
DCHECK(update_context);
++update_context->num_components_checked;
- if (update_context->num_components_checked < update_context->ids.size()) {
+ if (update_context->num_components_checked <
+ update_context->components_to_check_for_updates.size()) {
return;
}
@@ -217,7 +232,7 @@ void UpdateEngine::UpdateCheckComplete(
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(update_context);
- for (const auto& id : update_context->ids)
+ for (const auto& id : update_context->components_to_check_for_updates)
update_context->component_queue.push(id);
base::ThreadTaskRunnerHandle::Get()->PostTask(
@@ -314,7 +329,7 @@ bool UpdateEngine::GetUpdateState(const std::string& id,
for (const auto& context : update_contexts_) {
const auto& components = context.second->components;
const auto it = components.find(id);
- if (it != components.end()) {
+ if (it != components.end() && it->second->crx_component()) {
*update_item = it->second->GetCrxUpdateItem();
return true;
}
diff --git a/chromium/components/update_client/update_engine.h b/chromium/components/update_client/update_engine.h
index 3bc8f383721..2cfe9da0465 100644
--- a/chromium/components/update_client/update_engine.h
+++ b/chromium/components/update_client/update_engine.h
@@ -157,10 +157,20 @@ struct UpdateContext : public base::RefCounted<UpdateContext> {
// The time in seconds to wait until doing further update checks.
int retry_after_sec = 0;
+ // Contains the ids of the components to check for updates. It is possible
+ // for a component to be uninstalled after it has been added in this context
+ // but before an update check is made. When this happens, the component won't
+ // have a CrxComponent instance, therefore, it can't be included in an
+ // update check.
+ std::vector<std::string> components_to_check_for_updates;
+
+ // The error reported by the update checker.
int update_check_error = 0;
+
size_t num_components_ready_to_check = 0;
size_t num_components_checked = 0;
+ // Contains the ids of the components that the state machine must handle.
base::queue<std::string> component_queue;
// The time to wait before handling the update for a component.
diff --git a/chromium/components/update_client/url_fetcher_downloader.cc b/chromium/components/update_client/url_fetcher_downloader.cc
index 7db726b4bd9..d181daa0202 100644
--- a/chromium/components/update_client/url_fetcher_downloader.cc
+++ b/chromium/components/update_client/url_fetcher_downloader.cc
@@ -142,6 +142,7 @@ void UrlFetcherDownloader::StartURLFetch(const GURL& url) {
net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DISABLE_CACHE);
url_fetcher_->SetAutomaticallyRetryOn5xx(false);
+ url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
url_fetcher_->SaveResponseToFileAtPath(
response, base::CreateSequencedTaskRunnerWithTraits(kTaskTraits));
data_use_measurement::DataUseUserData::AttachToFetcher(
diff --git a/chromium/components/update_client/url_request_post_interceptor.cc b/chromium/components/update_client/url_request_post_interceptor.cc
index 2bf72e1c05b..b177f533287 100644
--- a/chromium/components/update_client/url_request_post_interceptor.cc
+++ b/chromium/components/update_client/url_request_post_interceptor.cc
@@ -10,6 +10,7 @@
#include "base/files/file_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "components/update_client/test_configurator.h"
#include "net/base/upload_bytes_element_reader.h"
diff --git a/chromium/components/update_client/utils.cc b/chromium/components/update_client/utils.cc
index 19b93a09688..1213c1f5b57 100644
--- a/chromium/components/update_client/utils.cc
+++ b/chromium/components/update_client/utils.cc
@@ -86,6 +86,7 @@ std::unique_ptr<net::URLFetcher> SendProtocolRequest(
net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DISABLE_CACHE);
url_fetcher->SetAutomaticallyRetryOn5xx(false);
+ url_fetcher->SetAutomaticallyRetryOnNetworkChanges(3);
for (const auto& header : protocol_request_extra_headers)
url_fetcher->AddExtraRequestHeader(base::StringPrintf(
"%s: %s", header.first.c_str(), header.second.c_str()));
diff --git a/chromium/components/update_client/utils.h b/chromium/components/update_client/utils.h
index 54eb873a774..e2840f9dcbb 100644
--- a/chromium/components/update_client/utils.h
+++ b/chromium/components/update_client/utils.h
@@ -97,6 +97,18 @@ CrxInstaller::Result InstallFunctionWrapper(
std::unique_ptr<base::DictionaryValue> ReadManifest(
const base::FilePath& unpack_path);
+// Converts a custom, specific installer error (and optionally extended error)
+// to an installer result.
+template <typename T>
+CrxInstaller::Result ToInstallerResult(const T& error, int extended_error = 0) {
+ static_assert(std::is_enum<T>::value,
+ "Use an enum class to define custom installer errors");
+ return CrxInstaller::Result(
+ static_cast<int>(update_client::InstallError::CUSTOM_ERROR_BASE) +
+ static_cast<int>(error),
+ extended_error);
+}
+
} // namespace update_client
#endif // COMPONENTS_UPDATE_CLIENT_UTILS_H_
diff --git a/chromium/components/update_client/utils_unittest.cc b/chromium/components/update_client/utils_unittest.cc
index 77ea7ae3b51..e2670e9ba9d 100644
--- a/chromium/components/update_client/utils_unittest.cc
+++ b/chromium/components/update_client/utils_unittest.cc
@@ -15,7 +15,7 @@ namespace {
base::FilePath MakeTestFilePath(const char* file) {
base::FilePath path;
- PathService::Get(base::DIR_SOURCE_ROOT, &path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &path);
return path.AppendASCII("components/test/data/update_client")
.AppendASCII(file);
}
@@ -160,4 +160,32 @@ TEST(UpdateClientUtils, RemoveUnsecureUrls) {
EXPECT_EQ(0u, urls.size());
}
+TEST(UpdateClientUtils, ToInstallerResult) {
+ enum EnumA {
+ ENTRY0 = 10,
+ ENTRY1 = 20,
+ };
+
+ enum class EnumB {
+ ENTRY0 = 0,
+ ENTRY1,
+ };
+
+ const auto result1 = ToInstallerResult(EnumA::ENTRY0);
+ EXPECT_EQ(110, result1.error);
+ EXPECT_EQ(0, result1.extended_error);
+
+ const auto result2 = ToInstallerResult(ENTRY1, 10000);
+ EXPECT_EQ(120, result2.error);
+ EXPECT_EQ(10000, result2.extended_error);
+
+ const auto result3 = ToInstallerResult(EnumB::ENTRY0);
+ EXPECT_EQ(100, result3.error);
+ EXPECT_EQ(0, result3.extended_error);
+
+ const auto result4 = ToInstallerResult(EnumB::ENTRY1, 20000);
+ EXPECT_EQ(101, result4.error);
+ EXPECT_EQ(20000, result4.extended_error);
+}
+
} // namespace update_client
diff --git a/chromium/components/url_formatter/idn_spoof_checker.cc b/chromium/components/url_formatter/idn_spoof_checker.cc
index 97b11719004..a41e7350391 100644
--- a/chromium/components/url_formatter/idn_spoof_checker.cc
+++ b/chromium/components/url_formatter/idn_spoof_checker.cc
@@ -155,15 +155,20 @@ IDNSpoofChecker::IDNSpoofChecker() {
UTRANS_FORWARD, parse_error, status));
// Supplement the Unicode confusable list by the following mapping.
+ // - {U+00E6 (æ), U+04D5 (ӕ)} => "ae"
// - {U+00FE (þ), U+03FC (ϼ), U+048F (ҏ)} => p
// - {U+0127 (ħ), U+043D (н), U+045B (ћ), U+04A3 (ң), U+04A5 (ҥ),
// U+04C8 (ӈ), U+04CA (ӊ), U+050B (ԋ), U+0527 (ԧ), U+0529 (ԩ)} => h
// - {U+0138 (ĸ), U+03BA (κ), U+043A (к), U+049B (қ), U+049D (ҝ),
// U+049F (ҟ), U+04A1(ҡ), U+04C4 (ӄ), U+051F (ԟ)} => k
- // - {U+014B (ŋ), U+043F (п)} => n
+ // - {U+014B (ŋ), U+043F (п), U+0525 (ԥ)} => n
+ // - U+0153 (œ) => "ce"
+ // TODO: see https://crbug.com/843352 for further work on
+ // U+0525 and U+0153.
// - {U+0167 (ŧ), U+0442 (т), U+04AD (ҭ), U+050F (ԏ)} => t
// - {U+0185 (ƅ), U+044C (ь), U+048D (ҍ), U+0432 (в)} => b
- // - {U+03C9 (ω), U+0448 (ш), U+0449 (щ), U+0E1F (ฟ)} => w
+ // - {U+03C9 (ω), U+0448 (ш), U+0449 (щ), U+0E1E (พ),
+ // U+0E1F (ฟ), U+0E9E (ພ), U+0E9F (ຟ)} => w
// - {U+043C (м), U+04CE (ӎ)} => m
// - {U+0454 (є), U+04BD (ҽ), U+04BF (ҿ), U+1054 (ၔ)} => e
// - U+0491 (ґ) => r
@@ -173,18 +178,20 @@ IDNSpoofChecker::IDNSpoofChecker() {
// - U+03C7 (χ), U+04B3 (ҳ), U+04FD (ӽ), U+04FF (ӿ) => x
// - U+0503 (ԃ) => d
// - {U+050D (ԍ), U+100c (ဌ)} => g
- // - {U+0D1F (ട), U+0E23 (ร)} => s
+ // - {U+0D1F (ട), U+0E23 (ร), U+0EA3 (ຣ), U+0EAE (ຮ)} => s
// - U+1042 (၂) => j
- // - {U+0437 (з), U+04E1 (ӡ)} => 3
+ // - {U+0437 (з), U+0499 (ҙ), U+04E1 (ӡ), U+10D5 (ვ), U+1012 (ဒ)} => 3
+ // - {U+0E1A (บ), U+0E9A (ບ)} => u
extra_confusable_mapper_.reset(icu::Transliterator::createFromRules(
UNICODE_STRING_SIMPLE("ExtraConf"),
- icu::UnicodeString::fromUTF8("[þϼҏ] > p; [ħнћңҥӈӊԋԧԩ] > h;"
- "[ĸκкқҝҟҡӄԟ] > k; [ŋп] > n; [ŧтҭԏ] > t;"
- "[ƅьҍв] > b; [ωшщฟ] > w; [мӎ] > m;"
- "[єҽҿၔ] > e; ґ > r; [ғӻ] > f; [ҫင] > c;"
- "ұ > y; [χҳӽӿ] > x;"
- "ԃ > d; [ԍဌ] > g; [ടร] > s; ၂ > j;"
- "[зӡ] > 3"),
+ icu::UnicodeString::fromUTF8(
+ "[æӕ] > ae; [þϼҏ] > p; [ħнћңҥӈӊԋԧԩ] > h;"
+ "[ĸκкқҝҟҡӄԟ] > k; [ŋпԥ] > n; œ > ce;"
+ "[ŧтҭԏ] > t; [ƅьҍв] > b; [ωшщพฟພຟ] > w;"
+ "[мӎ] > m; [єҽҿၔ] > e; ґ > r; [ғӻ] > f;"
+ "[ҫင] > c; ұ > y; [χҳӽӿ] > x;"
+ "ԃ > d; [ԍဌ] > g; [ടรຣຮ] > s; ၂ > j;"
+ "[зҙӡვဒ] > 3; [บບ] > u"),
UTRANS_FORWARD, parse_error, status));
DCHECK(U_SUCCESS(status))
<< "Spoofchecker initalization failed due to an error: "
@@ -274,8 +281,6 @@ bool IDNSpoofChecker::SafeToDisplayAsUnicode(base::StringPiece16 label,
// - Disallow three Hiragana letters (U+307[8-A]) or Katakana letters
// (U+30D[8-A]) that look exactly like each other when they're used in a
// label otherwise entirely in Katakna or Hiragana.
- // - Disallow U+0585 (Armenian Small Letter Oh) and U+0581 (Armenian Small
- // Letter Co) to be next to Latin.
// - Disallow combining diacritical mark (U+0300-U+0339) after a non-LGC
// character. Other combining diacritical marks are not in the allowed
// character set.
diff --git a/chromium/components/url_formatter/top_domains/test_domains.list b/chromium/components/url_formatter/top_domains/test_domains.list
index 0f0be0e2e23..0a654469a28 100644
--- a/chromium/components/url_formatter/top_domains/test_domains.list
+++ b/chromium/components/url_formatter/top_domains/test_domains.list
@@ -17,4 +17,8 @@ ld.com
1gd.com
cegjo.com
wsws.com
+wsu.com
+wsou.com
1234567890.com
+aece.com
+aen.com
diff --git a/chromium/components/url_formatter/top_domains/test_skeletons.gperf b/chromium/components/url_formatter/top_domains/test_skeletons.gperf
index 0646188e9fe..f59caf6dd41 100644
--- a/chromium/components/url_formatter/top_domains/test_skeletons.gperf
+++ b/chromium/components/url_formatter/top_domains/test_skeletons.gperf
@@ -27,5 +27,9 @@ ld.corn, 1
lgd.corn, 1
cegjo.corn, 1
wsws.corn, 1
+wsu.corn, 1
+wsou.corn, 1
l23456789O.corn, 1
+aece.corn, 1
+aen.corn, 1
%%
diff --git a/chromium/components/url_formatter/url_fixer.cc b/chromium/components/url_formatter/url_fixer.cc
index 47c04997ac0..26be3c86492 100644
--- a/chromium/components/url_formatter/url_fixer.cc
+++ b/chromium/components/url_formatter/url_fixer.cc
@@ -22,7 +22,7 @@
#include "url/url_file.h"
#include "url/url_util.h"
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
#include "base/path_service.h"
#endif
@@ -101,8 +101,10 @@ void PrepareStringForFileOps(const base::FilePath& text,
#if defined(OS_WIN)
base::TrimWhitespace(text.value(), base::TRIM_ALL, output);
replace(output->begin(), output->end(), '/', '\\');
-#else
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
TrimWhitespaceUTF8(text.value(), base::TRIM_ALL, output);
+#else
+#error Unsupported platform
#endif
}
@@ -122,7 +124,7 @@ bool ValidPathForFile(const base::FilePath::StringType& text,
return true;
}
-#if defined(OS_POSIX)
+#if defined(OS_POSIX) || defined(OS_FUCHSIA)
// Given a path that starts with ~, return a path that starts with an
// expanded-out /user/foobar directory.
std::string FixupHomedir(const std::string& text) {
@@ -133,7 +135,7 @@ std::string FixupHomedir(const std::string& text) {
if (home_directory_override)
file_path = base::FilePath(home_directory_override);
else
- PathService::Get(base::DIR_HOME, &file_path);
+ base::PathService::Get(base::DIR_HOME, &file_path);
// We'll probably break elsewhere if $HOME is undefined, but check here
// just in case.
@@ -176,7 +178,7 @@ std::string FixupPath(const std::string& text) {
// Fixup Windows-style drive letters, where "C:" gets rewritten to "C|".
if (filename.length() > 1 && filename[1] == '|')
filename[1] = ':';
-#elif defined(OS_POSIX)
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
base::FilePath input_path(text);
PrepareStringForFileOps(input_path, &filename);
if (filename.length() > 0 && filename[0] == '~')
@@ -402,20 +404,20 @@ std::string SegmentURLInternal(std::string* text, url::Parsed* parts) {
if (trimmed.empty())
return std::string(); // Nothing to segment.
+ std::string scheme;
#if defined(OS_WIN)
int trimmed_length = static_cast<int>(trimmed.length());
if (url::DoesBeginWindowsDriveSpec(trimmed.data(), 0, trimmed_length) ||
url::DoesBeginUNCPath(trimmed.data(), 0, trimmed_length, true))
- return url::kFileScheme;
-#elif defined(OS_POSIX)
+ scheme = url::kFileScheme;
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
if (base::FilePath::IsSeparator(trimmed.data()[0]) ||
trimmed.data()[0] == '~')
- return url::kFileScheme;
+ scheme = url::kFileScheme;
#endif
// Otherwise, we need to look at things carefully.
- std::string scheme;
- if (!GetValidScheme(*text, &parts->scheme, &scheme)) {
+ if (scheme.empty() && !GetValidScheme(*text, &parts->scheme, &scheme)) {
// Try again if there is a ';' in the text. If changing it to a ':' results
// in a standard scheme, "about", "chrome" or "file" scheme being found,
// continue processing with the modified text.
@@ -442,24 +444,26 @@ std::string SegmentURLInternal(std::string* text, url::Parsed* parts) {
// Proceed with about and chrome schemes, but not file or nonstandard schemes.
if ((scheme != url::kAboutScheme) && (scheme != kChromeUIScheme) &&
- ((scheme == url::kFileScheme) ||
- !url::IsStandard(
- scheme.c_str(),
- url::Component(0, static_cast<int>(scheme.length()))))) {
+ !url::IsStandard(scheme.c_str(),
+ url::Component(0, static_cast<int>(scheme.length())))) {
+ return scheme;
+ }
+
+ int text_length = static_cast<int>(text->length());
+ if (scheme == url::kFileScheme) {
+ url::ParseFileURL(text->data(), text_length, parts);
return scheme;
}
if (scheme == url::kFileSystemScheme) {
// Have the GURL parser do the heavy lifting for us.
- url::ParseFileSystemURL(text->data(), static_cast<int>(text->length()),
- parts);
+ url::ParseFileSystemURL(text->data(), text_length, parts);
return scheme;
}
if (parts->scheme.is_valid()) {
// Have the GURL parser do the heavy lifting for us.
- url::ParseStandardURL(text->data(), static_cast<int>(text->length()),
- parts);
+ url::ParseStandardURL(text->data(), text_length, parts);
return scheme;
}
@@ -623,7 +627,7 @@ GURL FixupRelativeFile(const base::FilePath& base_dir,
base::WideToUTF8(trimmed),
net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS));
-#elif defined(OS_POSIX)
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
std::string unescaped = net::UnescapeURLComponent(
trimmed,
net::UnescapeRule::SPACES | net::UnescapeRule::PATH_SEPARATORS |
@@ -650,7 +654,7 @@ GURL FixupRelativeFile(const base::FilePath& base_dir,
// Fall back on regular fixup for this input.
#if defined(OS_WIN)
std::string text_utf8 = base::WideToUTF8(text.value());
-#elif defined(OS_POSIX)
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
std::string text_utf8 = text.value();
#endif
return FixupURL(text_utf8, std::string());
diff --git a/chromium/components/url_formatter/url_fixer_unittest.cc b/chromium/components/url_formatter/url_fixer_unittest.cc
index e946f2395a9..5415d19f31b 100644
--- a/chromium/components/url_formatter/url_fixer_unittest.cc
+++ b/chromium/components/url_formatter/url_fixer_unittest.cc
@@ -192,6 +192,52 @@ static const SegmentCase segment_cases[] = {
url::Component(), // query
url::Component(), // ref
},
+ {
+ "file://host/path/file#ref", "file", url::Component(0, 4), // scheme
+ url::Component(), // username
+ url::Component(), // password
+ url::Component(7, 4), // host
+ url::Component(), // port
+ url::Component(11, 10), // path
+ url::Component(), // query
+ url::Component(22, 3), // ref
+ },
+ {
+ "file:///notahost/path/file#ref", "file",
+ url::Component(0, 4), // scheme
+ url::Component(), // username
+ url::Component(), // password
+ url::Component(), // host
+ url::Component(), // port
+ url::Component(7, 19), // path
+ url::Component(), // query
+ url::Component(27, 3), // ref
+ },
+#if defined(OS_WIN)
+ {
+ "c:/notahost/path/file#ref", "file",
+ url::Component(), // scheme
+ url::Component(), // username
+ url::Component(), // password
+ url::Component(), // host
+ url::Component(), // port
+ url::Component(0, 21), // path
+ url::Component(), // query
+ url::Component(22, 3), // ref
+ },
+#elif defined(OS_POSIX)
+ {
+ "~/notahost/path/file#ref", "file",
+ url::Component(), // scheme
+ url::Component(), // username
+ url::Component(), // password
+ url::Component(), // host
+ url::Component(), // port
+ url::Component(0, 20), // path
+ url::Component(), // query
+ url::Component(21, 3), // ref
+ },
+#endif
};
typedef testing::Test URLFixerTest;
diff --git a/chromium/components/url_formatter/url_formatter.cc b/chromium/components/url_formatter/url_formatter.cc
index 42f438eb067..37ff5e6962a 100644
--- a/chromium/components/url_formatter/url_formatter.cc
+++ b/chromium/components/url_formatter/url_formatter.cc
@@ -70,6 +70,11 @@ class HostComponentTransform : public AppendComponentTransform {
component_text,
net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+ // If there is no domain and registry, we may be looking at an intranet
+ // or otherwise non-standard host. Leave those alone.
+ if (domain_and_registry.empty())
+ return IDNToUnicodeWithAdjustments(component_text, adjustments);
+
base::OffsetAdjuster::Adjustments trivial_subdomains_adjustments;
base::StringTokenizer tokenizer(
component_text.begin(),
@@ -408,6 +413,7 @@ const FormatUrlType kFormatUrlOmitTrailingSlashOnBareHostname = 1 << 2;
const FormatUrlType kFormatUrlOmitHTTPS = 1 << 3;
const FormatUrlType kFormatUrlExperimentalElideAfterHost = 1 << 4;
const FormatUrlType kFormatUrlOmitTrivialSubdomains = 1 << 5;
+const FormatUrlType kFormatUrlTrimAfterHost = 1 << 6;
const FormatUrlType kFormatUrlOmitDefaults =
kFormatUrlOmitUsernamePassword | kFormatUrlOmitHTTP |
@@ -484,7 +490,8 @@ base::string16 FormatUrlWithAdjustments(
new_parsed->scheme = parsed.scheme;
// Username & password.
- if ((format_types & kFormatUrlOmitUsernamePassword) != 0) {
+ if (((format_types & kFormatUrlOmitUsernamePassword) != 0) ||
+ ((format_types & kFormatUrlTrimAfterHost) != 0)) {
// Remove the username and password fields. We don't want to display those
// to the user since they can be used for attacks,
// e.g. "http://google.com:search@evil.ru/"
@@ -543,37 +550,44 @@ base::string16 FormatUrlWithAdjustments(
}
// Path & query. Both get the same general unescape & convert treatment.
- if ((format_types & kFormatUrlOmitTrailingSlashOnBareHostname) &&
- CanStripTrailingSlash(url)) {
+ if ((format_types & kFormatUrlTrimAfterHost) ||
+ ((format_types & kFormatUrlExperimentalElideAfterHost) &&
+ url.IsStandard() && !url.SchemeIsFile() && !url.SchemeIsFileSystem())) {
+ // Only elide when the eliding is required and when the host is followed by
+ // more than just one forward slash.
+ bool should_elide = (format_types & kFormatUrlExperimentalElideAfterHost) &&
+ ((parsed.path.len > 1) || parsed.query.is_valid() ||
+ parsed.ref.is_valid());
+
+ // Either remove the path completely, or, if eliding, keep the first slash.
+ const size_t new_path_len = should_elide ? 1 : 0;
+
+ size_t trimmed_length = parsed.path.len - new_path_len;
+ // Remove query and the '?' delimeter.
+ if (parsed.query.is_valid())
+ trimmed_length += parsed.query.len + 1;
+
+ // Remove ref and the '#" delimiter.
+ if (parsed.ref.is_valid())
+ trimmed_length += parsed.ref.len + 1;
+
+ if (should_elide) {
+ // Replace everything after the host with a forward slash and ellipsis.
+ url_string.push_back('/');
+ constexpr base::char16 kEllipsisUTF16[] = {0x2026, 0};
+ url_string.append(kEllipsisUTF16);
+ }
+
+ adjustments->push_back(base::OffsetAdjuster::Adjustment(
+ parsed.path.begin + new_path_len, trimmed_length, new_path_len));
+
+ } else if ((format_types & kFormatUrlOmitTrailingSlashOnBareHostname) &&
+ CanStripTrailingSlash(url)) {
// Omit the path, which is a single trailing slash. There's no query or ref.
if (parsed.path.len > 0) {
adjustments->push_back(base::OffsetAdjuster::Adjustment(
parsed.path.begin, parsed.path.len, 0));
}
- } else if ((format_types & kFormatUrlExperimentalElideAfterHost) &&
- url.IsStandard() && !url.SchemeIsFile() &&
- !url.SchemeIsFileSystem()) {
- // Replace everything after the host with a forward slash and ellipsis.
- url_string.push_back('/');
- constexpr base::char16 kEllipsisUTF16[] = {0x2026, 0};
- url_string.append(kEllipsisUTF16);
-
- // Compute the length of everything we're replacing. For the path, we are
- // removing everything but the first slash.
- size_t old_length = parsed.path.len - 1;
-
- // We're also removing any query, plus the delimiting '?'.
- if (parsed.query.is_valid())
- old_length += parsed.query.len + 1;
-
- // We're also removing any ref, plus the delimiting '#'.
- if (parsed.ref.is_valid())
- old_length += parsed.ref.len + 1;
-
- // We're replacing all of these with a single character (an ellipsis). The
- // adjustment begins after the forward slash at the beginning of the path.
- adjustments->push_back(
- base::OffsetAdjuster::Adjustment(parsed.path.begin + 1, old_length, 1));
} else {
// Append the formatted path, query, and ref.
AppendFormattedComponent(spec, parsed.path,
diff --git a/chromium/components/url_formatter/url_formatter.h b/chromium/components/url_formatter/url_formatter.h
index 338d5aeb29c..ce68c7169bf 100644
--- a/chromium/components/url_formatter/url_formatter.h
+++ b/chromium/components/url_formatter/url_formatter.h
@@ -62,6 +62,10 @@ extern const FormatUrlType kFormatUrlExperimentalElideAfterHost;
// kFormatUrlOmitDefaults.
extern const FormatUrlType kFormatUrlOmitTrivialSubdomains;
+// Omits everything after the host: the path, query, ref, username and password
+// are all omitted.
+extern const FormatUrlType kFormatUrlTrimAfterHost;
+
// Convenience for omitting all unecessary types. Does not include HTTPS scheme
// removal, or experimental flags.
extern const FormatUrlType kFormatUrlOmitDefaults;
diff --git a/chromium/components/url_formatter/url_formatter_android.cc b/chromium/components/url_formatter/url_formatter_android.cc
index 4faa790d775..0558d5a84af 100644
--- a/chromium/components/url_formatter/url_formatter_android.cc
+++ b/chromium/components/url_formatter/url_formatter_android.cc
@@ -40,26 +40,40 @@ static ScopedJavaLocalRef<jstring> JNI_UrlFormatter_FixupUrl(
: ScopedJavaLocalRef<jstring>();
}
-static ScopedJavaLocalRef<jstring> JNI_UrlFormatter_FormatUrlForDisplay(
+static ScopedJavaLocalRef<jstring>
+JNI_UrlFormatter_FormatUrlForDisplayOmitScheme(
JNIEnv* env,
const JavaParamRef<jclass>& clazz,
const JavaParamRef<jstring>& url) {
return base::android::ConvertUTF16ToJavaString(
env, url_formatter::FormatUrl(
- JNI_UrlFormatter_ConvertJavaStringToGURL(env, url)));
+ JNI_UrlFormatter_ConvertJavaStringToGURL(env, url),
+ url_formatter::kFormatUrlOmitDefaults |
+ url_formatter::kFormatUrlOmitHTTPS,
+ net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
}
static ScopedJavaLocalRef<jstring>
-JNI_UrlFormatter_FormatUrlForDisplayOmitScheme(
+JNI_UrlFormatter_FormatUrlForDisplayOmitHTTPScheme(
JNIEnv* env,
const JavaParamRef<jclass>& clazz,
const JavaParamRef<jstring>& url) {
return base::android::ConvertUTF16ToJavaString(
env, url_formatter::FormatUrl(
JNI_UrlFormatter_ConvertJavaStringToGURL(env, url),
- url_formatter::kFormatUrlOmitDefaults |
- url_formatter::kFormatUrlOmitHTTPS,
- net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
+ url_formatter::kFormatUrlOmitDefaults, net::UnescapeRule::SPACES,
+ nullptr, nullptr, nullptr));
+}
+
+static ScopedJavaLocalRef<jstring> JNI_UrlFormatter_FormatUrlForCopy(
+ JNIEnv* env,
+ const JavaParamRef<jclass>& clazz,
+ const JavaParamRef<jstring>& url) {
+ return base::android::ConvertUTF16ToJavaString(
+ env, url_formatter::FormatUrl(
+ JNI_UrlFormatter_ConvertJavaStringToGURL(env, url),
+ url_formatter::kFormatUrlOmitNothing, net::UnescapeRule::NORMAL,
+ nullptr, nullptr, nullptr));
}
static ScopedJavaLocalRef<jstring> JNI_UrlFormatter_FormatUrlForSecurityDisplay(
diff --git a/chromium/components/url_formatter/url_formatter_unittest.cc b/chromium/components/url_formatter/url_formatter_unittest.cc
index d182e5a4259..aa68fc99553 100644
--- a/chromium/components/url_formatter/url_formatter_unittest.cc
+++ b/chromium/components/url_formatter/url_formatter_unittest.cc
@@ -449,7 +449,10 @@ const IDNTestCase idn_cases[] = {
// phĸtb.com
{"xn--phtb-m0a.com", L"ph\x0138tb.com", false},
// phkŧb.com
- {"xn--phkb-d7a.com", L"phk\x0167" L"b.com", false},
+ {"xn--phkb-d7a.com",
+ L"phk\x0167"
+ L"b.com",
+ false},
// phktƅ.com
{"xn--phkt-ocb.com", L"phkt\x0185.com", false},
// ҏнкть.com
@@ -522,30 +525,100 @@ const IDNTestCase idn_cases[] = {
{"xn--s5a8h3a.com", L"\x04cf\x050d\x0503.com", false},
// ꓲ2345б7890.com
- {"xn--23457890-e7g93622b.com", L"\xa4f2" L"2345\x0431" L"7890.com", false},
+ {"xn--23457890-e7g93622b.com",
+ L"\xa4f2"
+ L"2345\x0431"
+ L"7890.com",
+ false},
// 1ᒿ345б7890.com
- {"xn--13457890-e7g0943b.com", L"1\x14bf" L"345\x0431" L"7890.com", false},
+ {"xn--13457890-e7g0943b.com",
+ L"1\x14bf"
+ L"345\x0431"
+ L"7890.com",
+ false},
// 12з4567890.com
- {"xn--124567890-10h.com", L"12\x0437" L"4567890.com", false},
+ {"xn--124567890-10h.com",
+ L"12\x0437"
+ L"4567890.com",
+ false},
+ // 12ҙ4567890.com
+ {"xn--124567890-1ti.com",
+ L"12\x0499"
+ L"4567890.com",
+ false},
// 12ӡ4567890.com
- {"xn--124567890-mfj.com", L"12\x04e1" L"4567890.com", false},
+ {"xn--124567890-mfj.com",
+ L"12\x04e1"
+ L"4567890.com",
+ false},
+ // 12ვ4567890.com
+ {"xn--124567890-we8a.com",
+ L"12\x10D5"
+ L"4567890.com",
+ false},
+ // 12ဒ4567890.com
+ {"xn--124567890-6s6a.com",
+ L"12\x1012"
+ L"4567890.com",
+ false},
// 123Ꮞ567890.com
- {"xn--123567890-dm4b.com", L"123\x13ce" L"567890.com", false},
+ {"xn--123567890-dm4b.com",
+ L"123\x13ce"
+ L"567890.com",
+ false},
// 12345б7890.com
- {"xn--123457890-fzh.com", L"12345\x0431" L"7890.com", false},
+ {"xn--123457890-fzh.com",
+ L"12345\x0431"
+ L"7890.com",
+ false},
// 1234567ȣ90.com
- {"xn--123456790-6od.com", L"1234567\x0223" L"90.com", false},
+ {"xn--123456790-6od.com",
+ L"1234567\x0223"
+ L"90.com",
+ false},
// 12345678୨0.com
- {"xn--123456780-71w.com", L"12345678\x0b68" L"0.com", false},
+ {"xn--123456780-71w.com",
+ L"12345678\x0b68"
+ L"0.com",
+ false},
// 123456789ꓳ.com
{"xn--123456789-tx75a.com", L"123456789\xa4f3.com", false},
+ // aeœ.com
+ {"xn--ae-fsa.com", L"ae\x0153.com", false},
+ // æce.com
+ {"xn--ce-0ia.com",
+ L"\x00e6"
+ L"ce.com",
+ false},
+ // æœ.com
+ {"xn--6ca2t.com", L"\x00e6\x0153.com", false},
+ // ӕԥ.com
+ {"xn--y5a4n.com", L"\x04d5\x0525.com", false},
+
// ငၔဌ၂ဝ.com (entirely made of Myanmar characters)
- {"xn--ridq5c9hnd.com", L"\x1004\x1054\x100c" L"\x1042\x101d.com", false},
+ {"xn--ridq5c9hnd.com",
+ L"\x1004\x1054\x100c"
+ L"\x1042\x101d.com",
+ false},
// ฟรฟร.com (made of two Thai characters. similar to wsws.com in
// some fonts)
{"xn--w3calb.com", L"\x0e1f\x0e23\x0e1f\x0e23.com", false},
+ // พรบ.com
+ {"xn--r3chp.com", L"\x0e1e\x0e23\x0e1a.com", false},
+ // ฟรบ.com
+ {"xn--r3cjm.com", L"\x0e1f\x0e23\x0e1a.com", false},
+
+ // Lao characters that look like w, s, o, and u.
+ // ພຣບ.com
+ {"xn--f7chp.com", L"\x0e9e\x0ea3\x0e9a.com", false},
+ // ຟຣບ.com
+ {"xn--f7cjm.com", L"\x0e9f\x0ea3\x0e9a.com", false},
+ // ຟຮບ.com
+ {"xn--f7cj9b.com", L"\x0e9f\x0eae\x0e9a.com", false},
+ // ຟຮ໐ບ.com
+ {"xn--f7cj9b5h.com", L"\x0e9f\x0eae" L"\x0ed0\x0e9a.com", false},
// At one point the skeleton of 'w' was 'vv', ensure that
// that it's treated as 'w'.
@@ -1188,6 +1261,53 @@ TEST(UrlFormatterTest, FormatUrl) {
{"omit trivial subdomains but leave registry and domain alone - co.uk",
"http://m.co.uk/", kFormatUrlOmitTrivialSubdomains,
net::UnescapeRule::NORMAL, L"http://m.co.uk/", 7},
+
+ {"omit trivial subdomains but leave intranet hostnames alone",
+ "http://router/", kFormatUrlOmitTrivialSubdomains,
+ net::UnescapeRule::NORMAL, L"http://router/", 7},
+ {"omit trivial subdomains but leave alone if host itself is a registry",
+ "http://co.uk/", kFormatUrlOmitTrivialSubdomains,
+ net::UnescapeRule::NORMAL, L"http://co.uk/", 7},
+
+ // -------- trim after host --------
+ {"omit the trailing slash when ommitting the path", "http://google.com/",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit the simple file path when ommitting the path",
+ "http://google.com/foo",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit the file and folder path when ommitting the path",
+ "http://google.com/ab/cd",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with query only",
+ "http://google.com/?foo=bar",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with ref only", "http://google.com/#foobar",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with path and query only",
+ "http://google.com/foo?a=b",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with path and ref only",
+ "http://google.com/foo#c",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with query and ref only",
+ "http://google.com/?a=b#c",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with path, query and ref",
+ "http://google.com/foo?a=b#c",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
+ {"omit everything after host with repeated delimiters (sanity check)",
+ "http://google.com////???####",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, L"google.com", 0},
};
for (size_t i = 0; i < arraysize(tests); ++i) {
@@ -1564,6 +1684,28 @@ TEST(UrlFormatterTest, FormatUrlWithOffsets) {
kFormatUrlOmitDefaults | kFormatUrlExperimentalElideAfterHost,
net::UnescapeRule::NORMAL, elide_after_host_offsets);
+ const size_t trim_after_host_offsets[] = {
+ 0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, 1, 2, 3, 4,
+ 5, 6, 7, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 9};
+ CheckAdjustedOffsets("http://foo.com/abcdefg",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, trim_after_host_offsets);
+ CheckAdjustedOffsets("http://foo.com/abc/def",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, trim_after_host_offsets);
+ CheckAdjustedOffsets("http://foo.com/abc?a=b",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, trim_after_host_offsets);
+ CheckAdjustedOffsets("http://foo.com/abc#def",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, trim_after_host_offsets);
+ CheckAdjustedOffsets("http://foo.com/a?a=b#f",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, trim_after_host_offsets);
+ CheckAdjustedOffsets("http://foo.com//??###",
+ kFormatUrlOmitDefaults | kFormatUrlTrimAfterHost,
+ net::UnescapeRule::NORMAL, trim_after_host_offsets);
+
const size_t omit_https_offsets[] = {
0, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, kNpos, 0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
diff --git a/chromium/components/url_pattern_index/BUILD.gn b/chromium/components/url_pattern_index/BUILD.gn
index 50ae1131a6d..14f90fd0e8b 100644
--- a/chromium/components/url_pattern_index/BUILD.gn
+++ b/chromium/components/url_pattern_index/BUILD.gn
@@ -5,15 +5,11 @@
static_library("url_pattern_index") {
sources = [
"closed_hash_map.h",
- "copying_file_stream.cc",
- "copying_file_stream.h",
"fuzzy_pattern_matching.cc",
"fuzzy_pattern_matching.h",
"ngram_extractor.h",
"string_splitter.h",
"uint64_hasher.h",
- "unindexed_ruleset.cc",
- "unindexed_ruleset.h",
"url_pattern.cc",
"url_pattern.h",
"url_pattern_index.cc",
@@ -66,7 +62,6 @@ source_set("unit_tests") {
"fuzzy_pattern_matching_unittest.cc",
"ngram_extractor_unittest.cc",
"string_splitter_unittest.cc",
- "unindexed_ruleset_unittest.cc",
"url_pattern_index_unittest.cc",
"url_pattern_unittest.cc",
"url_rule_util_unittest.cc",
diff --git a/chromium/components/url_pattern_index/flat/url_pattern_index.fbs b/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
index f6085503eb2..32a6a2a9866 100644
--- a/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
+++ b/chromium/components/url_pattern_index/flat/url_pattern_index.fbs
@@ -37,7 +37,6 @@ enum ActivationType : ubyte (bit_flags) {
}
// The types of subresource requests that a URL rule should be applied to.
-// Corresponds to url_pattern_index::proto::ElementType.
enum ElementType : ushort (bit_flags) {
OTHER,
SCRIPT,
@@ -53,6 +52,8 @@ enum ElementType : ushort (bit_flags) {
MEDIA,
FONT,
WEBSOCKET,
+ CSP_REPORT,
+ MAIN_FRAME,
// Note: Update the default value for |element_types| field in UrlRule, on
// adding/removing values from this enum.
}
@@ -63,9 +64,11 @@ table UrlRule {
// Rule matching options, a bitmask consisting of OptionFlags.
options : ubyte;
- // A bitmask of ElementType. Equals ElementType_ANY by default for
- // compactness.
- element_types : ushort = 4095;
+ // A bitmask of ElementType. Equals ElementType_ANY & ~ElementType_MAIN_FRAME
+ // by default for compactness. We expect most rules to not use
+ // ElementType_MAIN_FRAME. Keep this in sync with
+ // url_pattern_index::kDefaultFlatElementTypesMask.
+ element_types : ushort = 8191;
// A bitmask of ActivationType. Disables all activation types by default.
activation_types : ubyte = 0;
diff --git a/chromium/components/url_pattern_index/url_pattern_index.cc b/chromium/components/url_pattern_index/url_pattern_index.cc
index cc591ab924d..a09240a7d4e 100644
--- a/chromium/components/url_pattern_index/url_pattern_index.cc
+++ b/chromium/components/url_pattern_index/url_pattern_index.cc
@@ -252,6 +252,17 @@ class UrlRuleFlatBufferConverter {
static_assert(flat::ElementType_ANY <= std::numeric_limits<uint16_t>::max(),
"Element types can not be stored in uint16_t.");
+ // Handle the default case. Note this means we end up adding
+ // flat::ElementType_CSP_REPORT as an element type when there is no
+ // corresponding proto::ElementType for it. However this should not matter
+ // in practice since subresource_filter does not do matching on CSP reports
+ // currently. If subresource_filter started to do so, add support for CSP
+ // reports in proto::ElementType.
+ if (rule_.element_types() == kDefaultProtoElementTypesMask) {
+ element_types_ = kDefaultFlatElementTypesMask;
+ return true;
+ }
+
const ElementTypeMap& element_type_map = GetElementTypeMap();
// Ensure all proto::ElementType(s) are mapped in |element_type_map|.
DCHECK_EQ(proto::ELEMENT_TYPE_ALL, GetKeysMask(element_type_map));
diff --git a/chromium/components/url_pattern_index/url_pattern_index.h b/chromium/components/url_pattern_index/url_pattern_index.h
index 142a2865de4..4eb3d02aedf 100644
--- a/chromium/components/url_pattern_index/url_pattern_index.h
+++ b/chromium/components/url_pattern_index/url_pattern_index.h
@@ -40,6 +40,14 @@ using UrlPatternIndexOffset = flatbuffers::Offset<flat::UrlPatternIndex>;
constexpr size_t kNGramSize = 5;
static_assert(kNGramSize <= sizeof(NGram), "NGram type is too narrow.");
+// The default element types mask as specified by the flatbuffer schema.
+constexpr uint16_t kDefaultFlatElementTypesMask =
+ flat::ElementType_ANY & ~flat::ElementType_MAIN_FRAME;
+
+// The default element types mask used by a proto::UrlRule.
+constexpr uint32_t kDefaultProtoElementTypesMask =
+ proto::ELEMENT_TYPE_ALL & ~proto::ELEMENT_TYPE_POPUP;
+
// Serializes the |rule| to the FlatBuffer |builder|, and returns an offset to
// it in the resulting buffer. Returns null offset iff the |rule| could not be
// serialized because of unsupported options or it is otherwise invalid.
diff --git a/chromium/components/url_pattern_index/url_pattern_index_unittest.cc b/chromium/components/url_pattern_index/url_pattern_index_unittest.cc
index b773c06c0ab..f256c0ded73 100644
--- a/chromium/components/url_pattern_index/url_pattern_index_unittest.cc
+++ b/chromium/components/url_pattern_index/url_pattern_index_unittest.cc
@@ -12,6 +12,7 @@
#include <vector>
#include "base/macros.h"
+#include "base/rand_util.h"
#include "base/strings/string_piece.h"
#include "components/url_pattern_index/url_pattern.h"
#include "components/url_pattern_index/url_rule_test_support.h"
@@ -748,7 +749,7 @@ TEST_F(UrlPatternIndexTest, FindMatchHighestPriority) {
// Create a shuffled vector of priorities from 1 to |i|.
std::vector<uint32_t> priorities(i);
std::iota(priorities.begin(), priorities.end(), 1);
- std::random_shuffle(priorities.begin(), priorities.end());
+ base::RandomShuffle(priorities.begin(), priorities.end());
for (size_t j = 0; j < i; j++) {
AddSimpleUrlRule(pattern, id, priorities[j]);
diff --git a/chromium/components/url_pattern_index/url_rule_util.cc b/chromium/components/url_pattern_index/url_rule_util.cc
index 5dbf3490638..289ec8c8b20 100644
--- a/chromium/components/url_pattern_index/url_rule_util.cc
+++ b/chromium/components/url_pattern_index/url_rule_util.cc
@@ -76,9 +76,14 @@ std::string TypeOptionsToString(
out += options_printer->PrintOption("genericblock");
}
- uint16_t types = flat_rule->element_types();
-
- if (types == url_pattern_index::flat::ElementType_ANY)
+ // Filterlists do not support the "main_frame" and "csp_report" element types.
+ // Hence we ignore them here.
+ constexpr uint16_t kSupportedElementTypes =
+ url_pattern_index::flat::ElementType_ANY &
+ ~url_pattern_index::flat::ElementType_MAIN_FRAME &
+ ~url_pattern_index::flat::ElementType_CSP_REPORT;
+ uint16_t types = flat_rule->element_types() & kSupportedElementTypes;
+ if (types == kSupportedElementTypes)
return out;
if (types & url_pattern_index::flat::ElementType_OTHER)
@@ -144,7 +149,7 @@ std::string DomainOptionsToString(
} // namespace
-std::string FlatUrlRuleToString(const flat::UrlRule* flat_rule) {
+std::string FlatUrlRuleToFilterlistString(const flat::UrlRule* flat_rule) {
std::string out;
if (flat_rule->options() & url_pattern_index::flat::OptionFlag_IS_WHITELIST)
diff --git a/chromium/components/url_pattern_index/url_rule_util.h b/chromium/components/url_pattern_index/url_rule_util.h
index a91c3306b57..5e0ff91e8e1 100644
--- a/chromium/components/url_pattern_index/url_rule_util.h
+++ b/chromium/components/url_pattern_index/url_rule_util.h
@@ -14,7 +14,7 @@ struct UrlRule;
}
// Prints a UrlRule in string form.
-std::string FlatUrlRuleToString(const flat::UrlRule* flat_rule);
+std::string FlatUrlRuleToFilterlistString(const flat::UrlRule* flat_rule);
} // namespace url_pattern_index
diff --git a/chromium/components/url_pattern_index/url_rule_util_unittest.cc b/chromium/components/url_pattern_index/url_rule_util_unittest.cc
index ee6c1bae9a8..312e63d1a1e 100644
--- a/chromium/components/url_pattern_index/url_rule_util_unittest.cc
+++ b/chromium/components/url_pattern_index/url_rule_util_unittest.cc
@@ -5,10 +5,12 @@
#include "components/url_pattern_index/url_rule_util.h"
#include <cmath>
+#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
+#include "components/url_pattern_index/flat/url_pattern_index_generated.h"
#include "components/url_pattern_index/url_pattern.h"
#include "components/url_pattern_index/url_pattern_index.h"
#include "components/url_pattern_index/url_rule_test_support.h"
@@ -56,6 +58,18 @@ class UrlRuleUtilTest : public ::testing::Test {
return flatbuffers::GetTemporaryPointer(flat_builder_, offset);
}
+ const flat::UrlRule* MakeFlatRule(const std::string& pattern,
+ uint16_t flat_element_types_mask) {
+ auto pattern_offset = flat_builder_.CreateString(pattern);
+
+ flat::UrlRuleBuilder rule_builder(flat_builder_);
+ rule_builder.add_url_pattern(pattern_offset);
+ rule_builder.add_element_types(flat_element_types_mask);
+ auto offset = rule_builder.Finish();
+
+ return flatbuffers::GetTemporaryPointer(flat_builder_, offset);
+ }
+
flatbuffers::FlatBufferBuilder flat_builder_;
private:
@@ -66,14 +80,14 @@ TEST_F(UrlRuleUtilTest, Blacklist) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, Whitelist) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_WHITELIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("@@example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("@@example.com/", FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, LeftAnchor) {
@@ -82,21 +96,21 @@ TEST_F(UrlRuleUtilTest, LeftAnchor) {
UrlPattern("example.com/", proto::ANCHOR_TYPE_NONE,
proto::ANCHOR_TYPE_NONE),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
UrlPattern("example.com/", proto::ANCHOR_TYPE_BOUNDARY,
proto::ANCHOR_TYPE_NONE),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("|example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("|example.com/", FlatUrlRuleToFilterlistString(flat_rule));
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
UrlPattern("example.com/", proto::ANCHOR_TYPE_SUBDOMAIN,
proto::ANCHOR_TYPE_NONE),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("||example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("||example.com/", FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, RightAnchor) {
@@ -105,14 +119,14 @@ TEST_F(UrlRuleUtilTest, RightAnchor) {
UrlPattern("example.com", proto::ANCHOR_TYPE_NONE,
proto::ANCHOR_TYPE_NONE),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com", FlatUrlRuleToFilterlistString(flat_rule));
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST,
UrlPattern("example.com", proto::ANCHOR_TYPE_NONE,
proto::ANCHOR_TYPE_BOUNDARY),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com|", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com|", FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, BothSidesAnchored) {
@@ -121,20 +135,20 @@ TEST_F(UrlRuleUtilTest, BothSidesAnchored) {
UrlPattern("example.com", proto::ANCHOR_TYPE_SUBDOMAIN,
proto::ANCHOR_TYPE_BOUNDARY),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("||example.com|", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("||example.com|", FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, NonRegex) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("/foo/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("/foo/*", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("/foo/*", FlatUrlRuleToFilterlistString(flat_rule));
// Show that whitelist rules work too.
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_WHITELIST, UrlPattern("/foo/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("@@/foo/*", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("@@/foo/*", FlatUrlRuleToFilterlistString(flat_rule));
// TODO(jkarlin): If regex support is added to UrlRule, verify that regex
// rules don't get the '*' appended.
@@ -144,19 +158,22 @@ TEST_F(UrlRuleUtilTest, Party) {
const flat::UrlRule* flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_THIRD_PARTY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/$third-party", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/$third-party",
+ FlatUrlRuleToFilterlistString(flat_rule));
flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_FIRST_PARTY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/$~third-party", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/$~third-party",
+ FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, MultipleOptions) {
const flat::UrlRule* flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_THIRD_PARTY, proto::ELEMENT_TYPE_SCRIPT, {}));
- EXPECT_EQ("example.com/$third-party,script", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/$third-party,script",
+ FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, ElementType) {
@@ -164,13 +181,13 @@ TEST_F(UrlRuleUtilTest, ElementType) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_SCRIPT, {}));
- EXPECT_EQ("example.com/$script", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/$script", FlatUrlRuleToFilterlistString(flat_rule));
// Test blocking every type.
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
// Block everything except other. This test will need to be updated as
// proto::ElementType is changed.
@@ -183,7 +200,7 @@ TEST_F(UrlRuleUtilTest, ElementType) {
"$script,image,stylesheet,object,xmlhttprequest,object-subrequest,"
"subdocument,ping,media,font,websocket";
- EXPECT_EQ(expected, FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ(expected, FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, ActivationType) {
@@ -191,7 +208,7 @@ TEST_F(UrlRuleUtilTest, ActivationType) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
// Test with a document activation type.
auto proto_rule =
@@ -199,14 +216,14 @@ TEST_F(UrlRuleUtilTest, ActivationType) {
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {});
proto_rule.set_activation_types(proto::ACTIVATION_TYPE_DOCUMENT);
flat_rule = MakeFlatRule(proto_rule);
- EXPECT_EQ("example.com/$document", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/$document", FlatUrlRuleToFilterlistString(flat_rule));
// Test with Document & Generic block types.
proto_rule.set_activation_types(proto::ACTIVATION_TYPE_DOCUMENT |
proto::ACTIVATION_TYPE_GENERICBLOCK);
flat_rule = MakeFlatRule(proto_rule);
EXPECT_EQ("example.com/$document,genericblock",
- FlatUrlRuleToString(flat_rule));
+ FlatUrlRuleToFilterlistString(flat_rule));
}
TEST_F(UrlRuleUtilTest, DomainList) {
@@ -214,7 +231,7 @@ TEST_F(UrlRuleUtilTest, DomainList) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
- EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
+ EXPECT_EQ("example.com/", FlatUrlRuleToFilterlistString(flat_rule));
// Test with domains set.
flat_rule = MakeFlatRule(
@@ -222,7 +239,18 @@ TEST_F(UrlRuleUtilTest, DomainList) {
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL,
{"foo.example.com", "~bar.example.com"}));
EXPECT_EQ("example.com/$domain=foo.example.com|~bar.example.com",
- FlatUrlRuleToString(flat_rule));
+ FlatUrlRuleToFilterlistString(flat_rule));
+}
+
+// Ensures that MAIN_FRAME and CSP_REPORT types are ignored since Filterlist
+// does not support these.
+TEST_F(UrlRuleUtilTest, IgnoredTypes) {
+ const flat::UrlRule* flat_rule =
+ MakeFlatRule("example.com/", flat::ElementType_MAIN_FRAME |
+ flat::ElementType_CSP_REPORT |
+ flat::ElementType_SCRIPT);
+
+ EXPECT_EQ("example.com/$script", FlatUrlRuleToFilterlistString(flat_rule));
}
} // namespace
diff --git a/chromium/components/user_manager/BUILD.gn b/chromium/components/user_manager/BUILD.gn
index 4b8e1b6255a..07b80449655 100644
--- a/chromium/components/user_manager/BUILD.gn
+++ b/chromium/components/user_manager/BUILD.gn
@@ -16,7 +16,7 @@ component("user_manager") {
deps = [
"//base",
- "//components/signin/core/account_id",
+ "//components/account_id",
"//google_apis",
"//skia",
"//ui/gfx",
@@ -58,7 +58,7 @@ if (is_chromeos) {
":user_manager",
"//base",
"//chromeos:chromeos",
- "//components/signin/core/account_id",
+ "//components/account_id",
"//skia",
"//ui/base",
]
@@ -71,7 +71,7 @@ if (is_chromeos) {
]
deps = [
":user_manager",
- "//components/signin/core/account_id",
+ "//components/account_id",
"//skia",
"//testing/gtest",
"//ui/gfx",
diff --git a/chromium/components/user_manager/DEPS b/chromium/components/user_manager/DEPS
index e64e44f5510..b04f915c370 100644
--- a/chromium/components/user_manager/DEPS
+++ b/chromium/components/user_manager/DEPS
@@ -1,7 +1,7 @@
include_rules = [
"+chromeos/chromeos_switches.h",
+"+components/account_id/account_id.h",
"+components/prefs",
-"+components/signin/core/account_id/account_id.h",
"+google_apis/gaia/gaia_auth_util.h",
"+third_party/skia/include",
"+ui/gfx/codec",
diff --git a/chromium/components/user_manager/fake_user_manager.h b/chromium/components/user_manager/fake_user_manager.h
index f3554992c17..48b4e494d53 100644
--- a/chromium/components/user_manager/fake_user_manager.h
+++ b/chromium/components/user_manager/fake_user_manager.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/macros.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager_base.h"
diff --git a/chromium/components/user_manager/known_user.cc b/chromium/components/user_manager/known_user.cc
index b218adb2d77..d3d54d262e1 100644
--- a/chromium/components/user_manager/known_user.cc
+++ b/chromium/components/user_manager/known_user.cc
@@ -64,6 +64,10 @@ const char kMinimalMigrationAttempted[] = "minimal_migration_attempted";
// Key of the boolean flag telling if user session requires policy.
const char kProfileRequiresPolicy[] = "profile_requires_policy";
+// Key of the boolean flag telling if user is ephemeral and should be removed
+// from the local state on logout.
+const char kIsEphemeral[] = "is_ephemeral";
+
PrefService* GetLocalState() {
if (!UserManager::IsInitialized())
return nullptr;
@@ -138,9 +142,11 @@ bool FindPrefs(const AccountId& account_id,
return false;
// UserManager is usually NULL in unit tests.
- if (UserManager::IsInitialized() &&
- UserManager::Get()->IsUserNonCryptohomeDataEphemeral(account_id))
+ if (account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY &&
+ UserManager::IsInitialized() &&
+ UserManager::Get()->IsUserNonCryptohomeDataEphemeral(account_id)) {
return false;
+ }
const base::ListValue* known_users = local_state->GetList(kKnownUsers);
for (size_t i = 0; i < known_users->GetSize(); ++i) {
@@ -165,9 +171,11 @@ void UpdatePrefs(const AccountId& account_id,
return;
// UserManager is usually NULL in unit tests.
- if (UserManager::IsInitialized() &&
- UserManager::Get()->IsUserNonCryptohomeDataEphemeral(account_id))
+ if (account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY &&
+ UserManager::IsInitialized() &&
+ UserManager::Get()->IsUserNonCryptohomeDataEphemeral(account_id)) {
return;
+ }
ListPrefUpdate update(local_state, kKnownUsers);
for (size_t i = 0; i < update->GetSize(); ++i) {
@@ -397,6 +405,24 @@ void SetGaiaIdMigrationStatusDone(const AccountId& account_id,
true);
}
+void SaveKnownUser(const AccountId& account_id) {
+ const bool is_ephemeral =
+ UserManager::IsInitialized() &&
+ UserManager::Get()->IsUserNonCryptohomeDataEphemeral(account_id);
+ if (is_ephemeral &&
+ account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY) {
+ return;
+ }
+ UpdateId(account_id);
+ GetLocalState()->CommitPendingWrite();
+}
+
+void SetIsEphemeralUser(const AccountId& account_id, bool is_ephemeral) {
+ if (account_id.GetAccountType() != AccountType::ACTIVE_DIRECTORY)
+ return;
+ SetBooleanPref(account_id, kIsEphemeral, is_ephemeral);
+}
+
void UpdateGaiaID(const AccountId& account_id, const std::string& gaia_id) {
SetStringPref(account_id, kGAIAIdKey, gaia_id);
SetStringPref(account_id, kAccountTypeKey,
@@ -544,6 +570,31 @@ void RemovePrefs(const AccountId& account_id) {
}
}
+void CleanEphemeralUsers() {
+ PrefService* local_state = GetLocalState();
+
+ // Local State may not be initialized in tests.
+ if (!local_state)
+ return;
+
+ ListPrefUpdate update(local_state, kKnownUsers);
+ auto& list_storage = update->GetList();
+ for (auto it = list_storage.begin(); it < list_storage.end();) {
+ bool remove = false;
+ base::DictionaryValue* element = nullptr;
+ if (update->GetDictionary(std::distance(list_storage.begin(), it),
+ &element)) {
+ base::Value* is_ephemeral = element->FindKey(kIsEphemeral);
+ if (is_ephemeral && is_ephemeral->GetBool())
+ remove = true;
+ }
+ if (remove)
+ it = list_storage.erase(it);
+ else
+ it++;
+ }
+}
+
// Exported so tests can call this from other components.
void RemoveSetProfileEverInitializedPrefForTesting(
const AccountId& account_id) {
diff --git a/chromium/components/user_manager/known_user.h b/chromium/components/user_manager/known_user.h
index 38fed5ee1c9..0e8a53f9f93 100644
--- a/chromium/components/user_manager/known_user.h
+++ b/chromium/components/user_manager/known_user.h
@@ -87,6 +87,15 @@ void USER_MANAGER_EXPORT
SetGaiaIdMigrationStatusDone(const AccountId& account_id,
const std::string& subsystem);
+// Marks if user is ephemeral and should be removed on log out.
+void SetIsEphemeralUser(const AccountId& account_id, bool is_ephemeral);
+
+// Saves |account_id| into known users. Tries to commit the change on disk. Use
+// only if account_id is not yet in the known user list. Important if Chrome
+// crashes shortly after starting a session. Cryptohome should be able to find
+// known account_id on Chrome restart.
+void USER_MANAGER_EXPORT SaveKnownUser(const AccountId& account_id);
+
// Updates |gaia_id| for user with |account_id|.
// TODO(alemate): Update this once AccountId contains GAIA ID
// (crbug.com/548926).
@@ -181,6 +190,9 @@ WasUserHomeMinimalMigrationAttempted(const AccountId& account_id);
// Not exported as code should not be calling this outside this component
void RemovePrefs(const AccountId& account_id);
+// Removes all ephemeral users.
+void CleanEphemeralUsers();
+
// Clears kProfileEverInitialized for a user.
void USER_MANAGER_EXPORT
RemoveSetProfileEverInitializedPrefForTesting(const AccountId& account_id);
diff --git a/chromium/components/user_manager/user.cc b/chromium/components/user_manager/user.cc
index 4448702eae0..90530ae1d70 100644
--- a/chromium/components/user_manager/user.cc
+++ b/chromium/components/user_manager/user.cc
@@ -13,7 +13,7 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/user_manager.h"
#include "google_apis/gaia/gaia_auth_util.h"
@@ -202,6 +202,10 @@ bool User::IsSupervised() const {
type == USER_TYPE_CHILD;
}
+bool User::IsChild() const {
+ return GetType() == USER_TYPE_CHILD;
+}
+
std::string User::GetAccountName(bool use_display_email) const {
if (use_display_email && !display_email_.empty())
return GetUserName(display_email_);
diff --git a/chromium/components/user_manager/user.h b/chromium/components/user_manager/user.h
index 074691bd0d4..10cafc73cd2 100644
--- a/chromium/components/user_manager/user.h
+++ b/chromium/components/user_manager/user.h
@@ -13,7 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/strings/string16.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/user_image/user_image.h"
#include "components/user_manager/user_info.h"
#include "components/user_manager/user_manager_export.h"
@@ -100,6 +100,9 @@ class USER_MANAGER_EXPORT User : public UserInfo {
// Returns true if user is supervised.
virtual bool IsSupervised() const;
+ // Returns true if user is child.
+ virtual bool IsChild() const;
+
// True if user image can be synced.
virtual bool CanSyncImage() const;
diff --git a/chromium/components/user_manager/user_info_impl.cc b/chromium/components/user_manager/user_info_impl.cc
index 7cadadf5485..ab1ac117c0b 100644
--- a/chromium/components/user_manager/user_info_impl.cc
+++ b/chromium/components/user_manager/user_info_impl.cc
@@ -6,7 +6,7 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/user_names.h"
namespace user_manager {
diff --git a/chromium/components/user_manager/user_info_impl.h b/chromium/components/user_manager/user_info_impl.h
index 7c0d84048e3..283d10ea6ec 100644
--- a/chromium/components/user_manager/user_info_impl.h
+++ b/chromium/components/user_manager/user_info_impl.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/strings/string16.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/user_info.h"
#include "components/user_manager/user_manager_export.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/chromium/components/user_manager/user_manager.cc b/chromium/components/user_manager/user_manager.cc
index 374eeea1ba3..e02109fef62 100644
--- a/chromium/components/user_manager/user_manager.cc
+++ b/chromium/components/user_manager/user_manager.cc
@@ -5,7 +5,7 @@
#include "components/user_manager/user_manager.h"
#include "base/logging.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
namespace user_manager {
@@ -23,8 +23,6 @@ void UserManager::Observer::OnUserProfileImageUpdated(
const User& user,
const gfx::ImageSkia& profile_image) {}
-void UserManager::Observer::OnChildStatusChanged(const User& user) {}
-
void UserManager::Observer::OnUsersSignInConstraintsChanged() {}
void UserManager::UserSessionStateObserver::ActiveUserChanged(
diff --git a/chromium/components/user_manager/user_manager.h b/chromium/components/user_manager/user_manager.h
index 4d68eea050d..cf398fad8ff 100644
--- a/chromium/components/user_manager/user_manager.h
+++ b/chromium/components/user_manager/user_manager.h
@@ -48,9 +48,6 @@ class USER_MANAGER_EXPORT UserManager {
virtual void OnUserProfileImageUpdated(const User& user,
const gfx::ImageSkia& profile_image);
- // Called when the child status of the given user has changed.
- virtual void OnChildStatusChanged(const User& user);
-
// Called when any of the device cros settings which are responsible for
// user sign in are changed.
virtual void OnUsersSignInConstraintsChanged();
diff --git a/chromium/components/user_manager/user_manager_base.cc b/chromium/components/user_manager/user_manager_base.cc
index d5072b3bc30..5d4088d4235 100644
--- a/chromium/components/user_manager/user_manager_base.cc
+++ b/chromium/components/user_manager/user_manager_base.cc
@@ -934,6 +934,7 @@ void UserManagerBase::RegularUserLoggedIn(const AccountId& account_id,
}
AddUserRecord(active_user_);
+ known_user::SetIsEphemeralUser(active_user_->GetAccountId(), false);
// Make sure that new data is persisted to Local State.
GetLocalState()->CommitPendingWrite();
@@ -946,6 +947,7 @@ void UserManagerBase::RegularUserLoggedInAsEphemeral(
SetIsCurrentUserNew(true);
is_current_user_ephemeral_regular_user_ = true;
active_user_ = User::CreateRegularUser(account_id, user_type);
+ known_user::SetIsEphemeralUser(active_user_->GetAccountId(), true);
}
void UserManagerBase::NotifyOnLogin() {
@@ -1075,6 +1077,8 @@ void UserManagerBase::ResetProfileEverInitialized(const AccountId& account_id) {
void UserManagerBase::Initialize() {
UserManager::Initialize();
+ if (!HasBrowserRestarted())
+ known_user::CleanEphemeralUsers();
CallUpdateLoginState();
}
diff --git a/chromium/components/user_manager/user_manager_base.h b/chromium/components/user_manager/user_manager_base.h
index 006af52d3a7..cf9950520a8 100644
--- a/chromium/components/user_manager/user_manager_base.h
+++ b/chromium/components/user_manager/user_manager_base.h
@@ -16,7 +16,7 @@
#include "base/observer_list.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_manager_export.h"
diff --git a/chromium/components/user_manager/user_names.cc b/chromium/components/user_manager/user_names.cc
index 5342a5e8b2c..88ce147e27b 100644
--- a/chromium/components/user_manager/user_names.cc
+++ b/chromium/components/user_manager/user_names.cc
@@ -5,7 +5,7 @@
#include "base/macros.h"
#include "base/memory/singleton.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "google_apis/gaia/gaia_auth_util.h"
class AccountId;
@@ -27,6 +27,7 @@ class FixedAccountManager {
}
const AccountId& stub_account_id() const { return stub_account_id_; }
+ const AccountId& stub_ad_account_id() const { return stub_ad_account_id_; }
const AccountId& signin_account_id() const { return signin_account_id_; }
const AccountId& guest_account_id() const { return guest_account_id_; }
const AccountId& demo_account_id() const { return demo_account_id_; }
@@ -39,6 +40,9 @@ class FixedAccountManager {
const AccountId stub_account_id_ =
AccountId::FromUserEmailGaiaId(user_manager::kStubUserEmail,
user_manager::kStubUserId);
+ const AccountId stub_ad_account_id_ =
+ AccountId::AdFromUserEmailObjGuid(user_manager::kStubAdUserEmail,
+ user_manager::kStubAdUserObjGuid);
const AccountId signin_account_id_ = AccountId::FromUserEmail(kSignInUser);
const AccountId guest_account_id_ =
AccountId::FromUserEmail(user_manager::kGuestUserName);
@@ -54,6 +58,9 @@ namespace user_manager {
const char kStubUserEmail[] = "stub-user@example.com";
const char kStubUserId[] = "1234567890123456789012";
+const char kStubAdUserEmail[] = "stub-ad-user@example.com";
+const char kStubAdUserObjGuid[] = "{11111111-1111-1111-1111-111111111111}";
+
// Should match cros constant in platform/libchromeos/chromeos/cryptohome.h
const char kGuestUserName[] = "$guest";
@@ -70,6 +77,11 @@ const AccountId& StubAccountId() {
return FixedAccountManager::GetInstance()->stub_account_id();
}
+// Note: StubAdAccountId is used for ChromeOS tests only.
+const AccountId& StubAdAccountId() {
+ return FixedAccountManager::GetInstance()->stub_ad_account_id();
+}
+
const AccountId& SignInAccountId() {
return FixedAccountManager::GetInstance()->signin_account_id();
}
diff --git a/chromium/components/user_manager/user_names.h b/chromium/components/user_manager/user_names.h
index 895b144c92d..afc37a1c91f 100644
--- a/chromium/components/user_manager/user_names.h
+++ b/chromium/components/user_manager/user_names.h
@@ -13,12 +13,18 @@ class AccountId;
namespace user_manager {
-// Stub user name. For tests and CrOS on Linux dev build only.
+// Stub Gaia user name. For tests and CrOS on Linux dev build only.
USER_MANAGER_EXPORT extern const char kStubUserEmail[];
-// Stub user id. For tests and CrOS on Linux dev build only.
+// Stub Gaia user id. For tests and CrOS on Linux dev build only.
USER_MANAGER_EXPORT extern const char kStubUserId[];
+// Stub Active Directory user name. For tests only.
+USER_MANAGER_EXPORT extern const char kStubAdUserEmail[];
+
+// Stub Active Directory user object GUID. For tests only.
+USER_MANAGER_EXPORT extern const char kStubAdUserObjGuid[];
+
// Magic e-mail addresses are bad. They exist here because some code already
// depends on them and it is hard to figure out what. Any user types added in
// the future should be identified by a new |UserType|, not a new magic e-mail
@@ -34,8 +40,12 @@ USER_MANAGER_EXPORT extern const char kSupervisedUserDomain[];
// @ symbol.
USER_MANAGER_EXPORT std::string CanonicalizeUserID(const std::string& user_id);
+// Stub account id for a Gaia user.
USER_MANAGER_EXPORT const AccountId& StubAccountId();
+// Stub account id for an Active Directory user.
+USER_MANAGER_EXPORT const AccountId& StubAdAccountId();
+
// AccountId for the login screen. It identifies ephemeral profile that is used
// to display WebUI during OOBE and SignIn.
USER_MANAGER_EXPORT const AccountId& SignInAccountId();
diff --git a/chromium/components/user_manager/user_unittest.cc b/chromium/components/user_manager/user_unittest.cc
index b0188726f2b..f5ff2037c41 100644
--- a/chromium/components/user_manager/user_unittest.cc
+++ b/chromium/components/user_manager/user_unittest.cc
@@ -4,7 +4,7 @@
#include "components/user_manager/user.h"
-#include "components/signin/core/account_id/account_id.h"
+#include "components/account_id/account_id.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace user_manager {
diff --git a/chromium/components/variations/BUILD.gn b/chromium/components/variations/BUILD.gn
index f74e77ebfa3..5b535dd278d 100644
--- a/chromium/components/variations/BUILD.gn
+++ b/chromium/components/variations/BUILD.gn
@@ -38,6 +38,8 @@ static_library("variations") {
"proto/permuted_entropy_cache.proto",
"proto/study.proto",
"proto/variations_seed.proto",
+ "seed_response.cc",
+ "seed_response.h",
"study_filtering.cc",
"study_filtering.h",
"synthetic_trial_registry.cc",
diff --git a/chromium/components/variations/android/variations_seed_bridge.cc b/chromium/components/variations/android/variations_seed_bridge.cc
index d9a6ca7a59c..5356248e1b8 100644
--- a/chromium/components/variations/android/variations_seed_bridge.cc
+++ b/chromium/components/variations/android/variations_seed_bridge.cc
@@ -43,11 +43,7 @@ ScopedJavaLocalRef<jbyteArray> JNI_VariationsSeedBridge_StringToJavaByteArray(
namespace variations {
namespace android {
-void GetVariationsFirstRunSeed(std::string* seed_data,
- std::string* seed_signature,
- std::string* seed_country,
- std::string* response_date,
- bool* is_gzip_compressed) {
+std::unique_ptr<variations::SeedResponse> GetVariationsFirstRunSeed() {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jbyteArray> j_seed_data =
Java_VariationsSeedBridge_getVariationsFirstRunSeedData(env);
@@ -59,12 +55,15 @@ void GetVariationsFirstRunSeed(std::string* seed_data,
Java_VariationsSeedBridge_getVariationsFirstRunSeedDate(env);
jboolean j_is_gzip_compressed =
Java_VariationsSeedBridge_getVariationsFirstRunSeedIsGzipCompressed(env);
- *seed_data =
+
+ auto seed = std::make_unique<variations::SeedResponse>();
+ seed->data =
JNI_VariationsSeedBridge_JavaByteArrayToString(env, j_seed_data.obj());
- *seed_signature = ConvertJavaStringToUTF8(j_seed_signature);
- *seed_country = ConvertJavaStringToUTF8(j_seed_country);
- *response_date = ConvertJavaStringToUTF8(j_response_date);
- *is_gzip_compressed = static_cast<bool>(j_is_gzip_compressed);
+ seed->signature = ConvertJavaStringToUTF8(j_seed_signature);
+ seed->country = ConvertJavaStringToUTF8(j_seed_country);
+ seed->date = ConvertJavaStringToUTF8(j_response_date);
+ seed->is_gzip_compressed = static_cast<bool>(j_is_gzip_compressed);
+ return seed;
}
void ClearJavaFirstRunPrefs() {
diff --git a/chromium/components/variations/android/variations_seed_bridge.h b/chromium/components/variations/android/variations_seed_bridge.h
index c83f6f39e67..633fe35aa3e 100644
--- a/chromium/components/variations/android/variations_seed_bridge.h
+++ b/chromium/components/variations/android/variations_seed_bridge.h
@@ -8,15 +8,13 @@
#include <jni.h>
#include <string>
+#include "components/variations/seed_response.h"
+
namespace variations {
namespace android {
// Return the first run seed data pulled from the Java side of application.
-void GetVariationsFirstRunSeed(std::string* seed_data,
- std::string* seed_signature,
- std::string* seed_country,
- std::string* response_date,
- bool* is_gzip_compressed);
+std::unique_ptr<variations::SeedResponse> GetVariationsFirstRunSeed();
// Clears first run seed preferences stored on the Java side of Chrome for
// Android.
diff --git a/chromium/components/variations/field_trial_config/field_trial_util.cc b/chromium/components/variations/field_trial_config/field_trial_util.cc
index 4ee5fa5586f..4ee47dc1579 100644
--- a/chromium/components/variations/field_trial_config/field_trial_util.cc
+++ b/chromium/components/variations/field_trial_config/field_trial_util.cc
@@ -21,12 +21,6 @@
namespace variations {
namespace {
-std::string UnescapeValue(const std::string& value) {
- return net::UnescapeURLComponent(
- value, net::UnescapeRule::PATH_SEPARATORS |
- net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
-}
-
void AssociateParamsFromExperiment(
const std::string& study_name,
const FieldTrialTestingExperiment& experiment,
@@ -83,10 +77,30 @@ const FieldTrialTestingExperiment& ChooseExperiment(
} // namespace
+std::string UnescapeValue(const std::string& value) {
+ return net::UnescapeURLComponent(
+ value, net::UnescapeRule::PATH_SEPARATORS |
+ net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS);
+}
+
std::string EscapeValue(const std::string& value) {
// This needs to be the inverse of UnescapeValue in the anonymous namespace
// above.
- return net::EscapeQueryParamValue(value, true /* use_plus */);
+ std::string net_escaped_str =
+ net::EscapeQueryParamValue(value, true /* use_plus */);
+
+ // net doesn't escape '.' and '*' but UnescapeValue() covers those cases.
+ std::string escaped_str;
+ escaped_str.reserve(net_escaped_str.length());
+ for (const char ch : net_escaped_str) {
+ if (ch == '.')
+ escaped_str.append("%2E");
+ else if (ch == '*')
+ escaped_str.append("%2A");
+ else
+ escaped_str.push_back(ch);
+ }
+ return escaped_str;
}
bool AssociateParamsFromString(const std::string& varations_string) {
diff --git a/chromium/components/variations/field_trial_config/field_trial_util.h b/chromium/components/variations/field_trial_config/field_trial_util.h
index 8bb44eded02..053a0490bec 100644
--- a/chromium/components/variations/field_trial_config/field_trial_util.h
+++ b/chromium/components/variations/field_trial_config/field_trial_util.h
@@ -15,6 +15,9 @@ namespace variations {
struct FieldTrialTestingConfig;
+// Unescapes special characters from the given string.
+std::string UnescapeValue(const std::string& value);
+
// Escapes the trial name, or parameter name, or parameter value in a way that
// makes it usable within variations::switches::kForceFieldTrialParams.
std::string EscapeValue(const std::string& value);
diff --git a/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc b/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc
index 00fc288f672..c27a7c760e1 100644
--- a/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc
+++ b/chromium/components/variations/field_trial_config/field_trial_util_unittest.cc
@@ -177,4 +177,15 @@ TEST_F(FieldTrialUtilTest, AssociateForcingFlagsFromFieldTrialConfig) {
EXPECT_EQ("ForcedGroup3", base::FieldTrialList::FindFullName("TestTrial3"));
}
+TEST_F(FieldTrialUtilTest, TestEscapeValue) {
+ std::string str = "trail.:/,*";
+ std::string escaped_str = EscapeValue(str);
+ EXPECT_EQ(escaped_str.find('.'), std::string::npos);
+ EXPECT_EQ(escaped_str.find(':'), std::string::npos);
+ EXPECT_EQ(escaped_str.find('/'), std::string::npos);
+ EXPECT_EQ(escaped_str.find(','), std::string::npos);
+ EXPECT_EQ(escaped_str.find('*'), std::string::npos);
+
+ EXPECT_EQ(str, UnescapeValue(escaped_str));
+}
} // namespace variations
diff --git a/chromium/components/variations/seed_response.cc b/chromium/components/variations/seed_response.cc
new file mode 100644
index 00000000000..7e9e170fade
--- /dev/null
+++ b/chromium/components/variations/seed_response.cc
@@ -0,0 +1,12 @@
+// 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 "components/variations/seed_response.h"
+
+namespace variations {
+
+SeedResponse::SeedResponse() = default;
+SeedResponse::~SeedResponse() = default;
+
+} // namespace variations
diff --git a/chromium/components/variations/seed_response.h b/chromium/components/variations/seed_response.h
new file mode 100644
index 00000000000..0de272bbf8f
--- /dev/null
+++ b/chromium/components/variations/seed_response.h
@@ -0,0 +1,27 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VARIATIONS_SEED_RESPONSE_H_
+#define COMPONENTS_VARIATIONS_SEED_RESPONSE_H_
+
+#include <string>
+
+namespace variations {
+
+// Represents data received when downloading the seed: "data" is the response
+// body while the other fields come from headers.
+struct SeedResponse {
+ SeedResponse();
+ ~SeedResponse();
+
+ std::string data; // "data" is binary, for which protobuf uses strings.
+ std::string signature;
+ std::string country;
+ std::string date;
+ bool is_gzip_compressed = false;
+};
+
+} // namespace variations
+
+#endif // COMPONENTS_VARIATIONS_SEED_RESPONSE_H_
diff --git a/chromium/components/variations/service/variations_field_trial_creator.cc b/chromium/components/variations/service/variations_field_trial_creator.cc
index 65acdfc4c2f..966d21d16b1 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator.cc
@@ -157,9 +157,19 @@ VariationsFieldTrialCreator::VariationsFieldTrialCreator(
PrefService* local_state,
VariationsServiceClient* client,
const UIStringOverrider& ui_string_overrider)
+ : VariationsFieldTrialCreator(local_state,
+ client,
+ ui_string_overrider,
+ nullptr) {}
+
+VariationsFieldTrialCreator::VariationsFieldTrialCreator(
+ PrefService* local_state,
+ VariationsServiceClient* client,
+ const UIStringOverrider& ui_string_overrider,
+ std::unique_ptr<SeedResponse> initial_seed)
: client_(client),
ui_string_overrider_(ui_string_overrider),
- seed_store_(local_state),
+ seed_store_(local_state, std::move(initial_seed)),
create_trials_from_seed_called_(false),
has_platform_override_(false),
platform_override_(Study::PLATFORM_WINDOWS) {}
diff --git a/chromium/components/variations/service/variations_field_trial_creator.h b/chromium/components/variations/service/variations_field_trial_creator.h
index 7043454b937..ae9cc954104 100644
--- a/chromium/components/variations/service/variations_field_trial_creator.h
+++ b/chromium/components/variations/service/variations_field_trial_creator.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/metrics/field_trial.h"
#include "components/variations/client_filterable_state.h"
+#include "components/variations/seed_response.h"
#include "components/variations/service/ui_string_overrider.h"
#include "components/variations/variations_seed_store.h"
@@ -31,6 +32,12 @@ class VariationsFieldTrialCreator {
VariationsFieldTrialCreator(PrefService* local_state,
VariationsServiceClient* client,
const UIStringOverrider& ui_string_overrider);
+ // |initial_seed| may be null. If not null, then it will be stored in the
+ // contained seed store.
+ VariationsFieldTrialCreator(PrefService* local_state,
+ VariationsServiceClient* client,
+ const UIStringOverrider& ui_string_overrider,
+ std::unique_ptr<SeedResponse> initial_seed);
virtual ~VariationsFieldTrialCreator();
// Returns what variations will consider to be the latest country. Returns
diff --git a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
index b61078e0ebb..46f2c3e9127 100644
--- a/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
+++ b/chromium/components/variations/service/variations_field_trial_creator_unittest.cc
@@ -6,6 +6,7 @@
#include <stddef.h>
#include <memory>
+#include <utility>
#include "base/feature_list.h"
#include "base/macros.h"
@@ -25,6 +26,7 @@
#if defined(OS_ANDROID)
#include "components/variations/android/variations_seed_bridge.h"
+#include "components/variations/seed_response.h"
#endif // OS_ANDROID
using testing::_;
@@ -185,7 +187,7 @@ class TestVariationsServiceClient : public VariationsServiceClient {
class TestVariationsSeedStore : public VariationsSeedStore {
public:
- TestVariationsSeedStore(PrefService* local_state)
+ explicit TestVariationsSeedStore(PrefService* local_state)
: VariationsSeedStore(local_state), local_state_(local_state) {}
~TestVariationsSeedStore() override = default;
@@ -453,15 +455,12 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_LoadsCountryOnFirstRun) {
// Simulate having received a seed in Java during First Run.
const base::Time one_day_ago =
base::Time::Now() - base::TimeDelta::FromDays(1);
- const std::string test_seed_data =
- SerializeSeed(CreateTestSeedWithCountryFilter());
- const std::string test_seed_signature = kTestSeedSignature;
- const std::string test_seed_country = kTestSeedCountry;
- const std::string test_response_date = ToUTCString(one_day_ago);
- const bool test_is_gzip_compressed = false;
- android::SetJavaFirstRunPrefsForTesting(test_seed_data, test_seed_signature,
- test_seed_country, test_response_date,
- test_is_gzip_compressed);
+ auto initial_seed = std::make_unique<SeedResponse>();
+ initial_seed->data = SerializeSeed(CreateTestSeedWithCountryFilter());
+ initial_seed->signature = kTestSeedSignature;
+ initial_seed->country = kTestSeedCountry;
+ initial_seed->date = ToUTCString(one_day_ago);
+ initial_seed->is_gzip_compressed = false;
TestVariationsServiceClient variations_service_client;
TestPlatformFieldTrials platform_field_trials;
@@ -472,11 +471,12 @@ TEST_F(FieldTrialCreatorTest, SetupFieldTrials_LoadsCountryOnFirstRun) {
// Note: Unlike other tests, this test does not mock out the seed store, since
// the interaction between these two classes is what's being tested.
VariationsFieldTrialCreator field_trial_creator(
- &prefs_, &variations_service_client, UIStringOverrider());
+ &prefs_, &variations_service_client, UIStringOverrider(),
+ std::move(initial_seed));
// Check that field trials are created from the seed. The test seed contains a
- // single study with an experiment targeting 100% of users in India. Since the
- // First Run prefs included the country code for India, this study should be
+ // single study with an experiment targeting 100% of users in India. Since
+ // |initial_seed| included the country code for India, this study should be
// active.
EXPECT_TRUE(field_trial_creator.SetupFieldTrials(
"", "", "", std::set<std::string>(), std::vector<std::string>(), nullptr,
diff --git a/chromium/components/variations/service/variations_service.cc b/chromium/components/variations/service/variations_service.cc
index 21ce2b832c7..2c298489fee 100644
--- a/chromium/components/variations/service/variations_service.cc
+++ b/chromium/components/variations/service/variations_service.cc
@@ -37,6 +37,7 @@
#include "components/prefs/pref_service.h"
#include "components/variations/pref_names.h"
#include "components/variations/proto/variations_seed.pb.h"
+#include "components/variations/seed_response.h"
#include "components/variations/variations_seed_processor.h"
#include "components/variations/variations_seed_simulator.h"
#include "components/variations/variations_switches.h"
@@ -55,6 +56,10 @@
#include "ui/base/device_form_factor.h"
#include "url/gurl.h"
+#if defined(OS_ANDROID)
+#include "components/variations/android/variations_seed_bridge.h"
+#endif // OS_ANDROID
+
namespace variations {
namespace {
@@ -232,6 +237,17 @@ bool IsFetchingEnabled() {
return true;
}
+std::unique_ptr<SeedResponse> MaybeImportFirstRunSeed(
+ PrefService* local_state) {
+#if defined(OS_ANDROID)
+ if (!local_state->HasPrefPath(prefs::kVariationsSeedSignature)) {
+ DVLOG(1) << "Importing first run seed from Java preferences.";
+ return android::GetVariationsFirstRunSeed();
+ }
+#endif
+ return nullptr;
+}
+
} // namespace
VariationsService::VariationsService(
@@ -250,7 +266,10 @@ VariationsService::VariationsService(
request_count_(0),
safe_seed_manager_(state_manager->clean_exit_beacon()->exited_cleanly(),
local_state),
- field_trial_creator_(local_state, client_.get(), ui_string_overrider),
+ field_trial_creator_(local_state,
+ client_.get(),
+ ui_string_overrider,
+ MaybeImportFirstRunSeed(local_state)),
weak_ptr_factory_(this) {
DCHECK(client_.get());
DCHECK(resource_request_allowed_notifier_.get());
@@ -437,6 +456,10 @@ bool VariationsService::StoreSeed(const std::string& seed_data,
RecordSuccessfulFetch();
+ // Now, do simulation to determine if there are any kill-switches that were
+ // activated by this seed. To do this, first get the Chrome version to do a
+ // simulation with, which must be done on a background thread, and then do the
+ // actual simulation on the UI thread.
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
client_->GetVersionForSimulationCallback(),
diff --git a/chromium/components/variations/variations_seed_processor_unittest.cc b/chromium/components/variations/variations_seed_processor_unittest.cc
index 376b3a1e1af..4c6d395e4b1 100644
--- a/chromium/components/variations/variations_seed_processor_unittest.cc
+++ b/chromium/components/variations/variations_seed_processor_unittest.cc
@@ -936,6 +936,7 @@ TEST_F(VariationsSeedProcessorTest, ExpiredStudy_NoDefaultGroup) {
auto* exp1 = AddExperiment("A", 1, &study);
exp1->mutable_feature_association()->add_enable_feature(kFeature.name);
+ EXPECT_FALSE(study.has_default_experiment_name());
EXPECT_TRUE(CreateTrialFromStudy(study));
EXPECT_EQ("VariationsDefaultExperiment",
base::FieldTrialList::FindFullName("Study1"));
diff --git a/chromium/components/variations/variations_seed_simulator.cc b/chromium/components/variations/variations_seed_simulator.cc
index 721564438fb..f711c8d1552 100644
--- a/chromium/components/variations/variations_seed_simulator.cc
+++ b/chromium/components/variations/variations_seed_simulator.cc
@@ -209,6 +209,9 @@ VariationsSeedSimulator::PermanentStudyGroupChanged(
const std::string simulated_group =
SimulateGroupAssignment(entropy_provider, processed_study);
+
+ // Note: The current (i.e. old) group is checked for the type since that group
+ // is the one that should be annotated with the type when killing it.
const Study_Experiment* experiment = FindExperiment(study, selected_group);
if (simulated_group != selected_group) {
if (experiment)
@@ -216,10 +219,12 @@ VariationsSeedSimulator::PermanentStudyGroupChanged(
return CHANGED;
}
- // Current group exists in the study - check whether its params changed.
- DCHECK(experiment);
- if (!VariationParamsAreEqual(study, *experiment))
+ // If the group is unchanged, check whether its params may have changed.
+ if (experiment && !VariationParamsAreEqual(study, *experiment))
return ConvertExperimentTypeToChangeType(experiment->type());
+
+ // Since the group name has not changed and params are either equal or the
+ // experiment was not found (and thus there are none), return NO_CHANGE.
return NO_CHANGE;
}
diff --git a/chromium/components/variations/variations_seed_simulator_unittest.cc b/chromium/components/variations/variations_seed_simulator_unittest.cc
index 3b7838a5318..8a6089070aa 100644
--- a/chromium/components/variations/variations_seed_simulator_unittest.cc
+++ b/chromium/components/variations/variations_seed_simulator_unittest.cc
@@ -19,6 +19,12 @@
namespace variations {
namespace {
+
+// Converts |time| to Study proto format.
+int64_t TimeToProtoTime(const base::Time& time) {
+ return (time - base::Time::UnixEpoch()).InSeconds();
+}
+
// Creates and activates a single-group field trial with name |trial_name| and
// group |group_name| and variations |params| (if not null).
void CreateTrial(const std::string& trial_name,
@@ -156,6 +162,9 @@ TEST_F(VariationsSeedSimulatorTest, PermanentGroupChange) {
// Changing "C" group type should not affect the type of change. (Since the
// type is evaluated for the "old" group.)
+ //
+ // Note: The current (i.e. old) group is checked for the type since that group
+ // is the one that should be annotated with the type when killing it.
experiment->set_type(Study_Experiment_Type_NORMAL);
EXPECT_EQ("1 0 0", SimulateStudyDifferences(&study));
experiment->set_type(Study_Experiment_Type_IGNORE_CHANGE);
@@ -379,4 +388,28 @@ TEST_F(VariationsSeedSimulatorTest, ParamsAdded) {
EXPECT_EQ("0 0 1", SimulateStudyDifferences(&study));
}
+// Tests that simulating an expired trial without a default group doesn't crash.
+// This is very much an edge case which should generally not be encountered due
+// to server-side, but we should ensure that it still doesn't cause a client
+// side crash.
+TEST_F(VariationsSeedSimulatorTest, NoDefaultGroup) {
+ static struct base::Feature kFeature {
+ "FeatureName", base::FEATURE_ENABLED_BY_DEFAULT
+ };
+ CreateTrial("Study1", "VariationsDefaultExperiment", nullptr);
+
+ Study study;
+ study.set_consistency(Study::PERMANENT);
+ study.set_name("Study1");
+ const base::Time year_ago =
+ base::Time::Now() - base::TimeDelta::FromDays(365);
+ study.set_expiry_date(TimeToProtoTime(year_ago));
+ auto* exp1 = AddExperiment("A", 1, &study);
+ study.clear_default_experiment_name();
+ exp1->mutable_feature_association()->add_enable_feature(kFeature.name);
+
+ EXPECT_FALSE(study.has_default_experiment_name());
+ EXPECT_EQ("0 0 0", SimulateStudyDifferencesExpired(&study));
+}
+
} // namespace variations
diff --git a/chromium/components/variations/variations_seed_store.cc b/chromium/components/variations/variations_seed_store.cc
index 6c5aea0c7e0..b8ce4a0d78a 100644
--- a/chromium/components/variations/variations_seed_store.cc
+++ b/chromium/components/variations/variations_seed_store.cc
@@ -5,6 +5,7 @@
#include "components/variations/variations_seed_store.h"
#include <stdint.h>
+#include <utility>
#include "base/base64.h"
#include "base/macros.h"
@@ -23,6 +24,7 @@
#if defined(OS_ANDROID)
#include "components/variations/android/variations_seed_bridge.h"
+#include "components/variations/metrics.h"
#endif // OS_ANDROID
namespace variations {
@@ -62,14 +64,12 @@ VerifySignatureResult VerifySeedSignature(
crypto::SignatureVerifier verifier;
if (!verifier.VerifyInit(crypto::SignatureVerifier::ECDSA_SHA256,
- reinterpret_cast<const uint8_t*>(signature.data()),
- signature.size(), kPublicKey,
- arraysize(kPublicKey))) {
+ base::as_bytes(base::make_span(signature)),
+ kPublicKey)) {
return VerifySignatureResult::INVALID_SIGNATURE;
}
- verifier.VerifyUpdate(reinterpret_cast<const uint8_t*>(seed_bytes.data()),
- seed_bytes.size());
+ verifier.VerifyUpdate(base::as_bytes(base::make_span(seed_bytes)));
if (!verifier.VerifyFinal())
return VerifySignatureResult::INVALID_SEED;
@@ -111,14 +111,15 @@ UpdateSeedDateResult GetSeedDateChangeState(
} // namespace
VariationsSeedStore::VariationsSeedStore(PrefService* local_state)
+ : VariationsSeedStore(local_state, nullptr) {}
+
+VariationsSeedStore::VariationsSeedStore(
+ PrefService* local_state,
+ std::unique_ptr<SeedResponse> initial_seed)
: local_state_(local_state) {
#if defined(OS_ANDROID)
- // If there is a first run seed to import, do so as soon as possible. This is
- // especially important because some clients query the seed store prefs
- // directly rather than accessing them via the seed store API:
- // https://crbug.com/829527
- if (!local_state_->HasPrefPath(prefs::kVariationsSeedSignature))
- ImportFirstRunJavaSeed();
+ if (initial_seed)
+ ImportInitialSeed(std::move(initial_seed));
#endif // OS_ANDROID
}
@@ -420,33 +421,25 @@ void VariationsSeedStore::ClearPrefs(SeedType seed_type) {
}
#if defined(OS_ANDROID)
-void VariationsSeedStore::ImportFirstRunJavaSeed() {
- DVLOG(1) << "Importing first run seed from Java preferences.";
-
- std::string seed_data;
- std::string seed_signature;
- std::string seed_country;
- std::string response_date;
- bool is_gzip_compressed;
-
- android::GetVariationsFirstRunSeed(&seed_data, &seed_signature, &seed_country,
- &response_date, &is_gzip_compressed);
- if (seed_data.empty()) {
+void VariationsSeedStore::ImportInitialSeed(
+ std::unique_ptr<SeedResponse> initial_seed) {
+ if (initial_seed->data.empty()) {
RecordFirstRunSeedImportResult(
FirstRunSeedImportResult::FAIL_NO_FIRST_RUN_SEED);
return;
}
- base::Time current_date;
- if (!base::Time::FromUTCString(response_date.c_str(), &current_date)) {
+ base::Time date;
+ if (!base::Time::FromUTCString(initial_seed->date.c_str(), &date)) {
RecordFirstRunSeedImportResult(
FirstRunSeedImportResult::FAIL_INVALID_RESPONSE_DATE);
- LOG(WARNING) << "Invalid response date: " << response_date;
+ LOG(WARNING) << "Invalid response date: " << date;
return;
}
- if (!StoreSeedData(seed_data, seed_signature, seed_country, current_date,
- false, is_gzip_compressed, false, nullptr)) {
+ if (!StoreSeedData(initial_seed->data, initial_seed->signature,
+ initial_seed->country, date, false,
+ initial_seed->is_gzip_compressed, false, nullptr)) {
RecordFirstRunSeedImportResult(FirstRunSeedImportResult::FAIL_STORE_FAILED);
LOG(WARNING) << "First run variations seed is invalid.";
return;
diff --git a/chromium/components/variations/variations_seed_store.h b/chromium/components/variations/variations_seed_store.h
index 56bd21da90e..088716bd178 100644
--- a/chromium/components/variations/variations_seed_store.h
+++ b/chromium/components/variations/variations_seed_store.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VARIATIONS_VARIATIONS_SEED_STORE_H_
#define COMPONENTS_VARIATIONS_VARIATIONS_SEED_STORE_H_
+#include <memory>
#include <string>
#include "base/compiler_specific.h"
@@ -13,6 +14,7 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/variations/metrics.h"
+#include "components/variations/seed_response.h"
class PrefService;
class PrefRegistrySimple;
@@ -27,6 +29,11 @@ class VariationsSeed;
class VariationsSeedStore {
public:
explicit VariationsSeedStore(PrefService* local_state);
+ // |initial_seed| may be null. If not null, then it will be stored in this
+ // seed store. This is used by Android Chrome to supply the first run seed,
+ // and by Android WebView to supply the seed on every run.
+ VariationsSeedStore(PrefService* local_state,
+ std::unique_ptr<SeedResponse> initial_seed);
virtual ~VariationsSeedStore();
// Loads the variations seed data from local state into |seed|, as well as the
@@ -135,9 +142,12 @@ class VariationsSeedStore {
void ClearPrefs(SeedType seed_type);
#if defined(OS_ANDROID)
- // Imports the variations seed data from Java side during the first
- // Chrome for Android run.
- void ImportFirstRunJavaSeed();
+ // Imports the variations seed from the Java side. Logs UMA on failure.
+ // Android Chrome uses this on first run; WebView uses this on every startup.
+ // In Chrome's case, it's important to set the first run seed as soon as
+ // possible, because some clients query the seed store prefs directly rather
+ // than accessing them via the seed store API: https://crbug.com/829527
+ void ImportInitialSeed(std::unique_ptr<SeedResponse> initial_seed);
#endif // OS_ANDROID
// Loads the variations seed data from local state into |seed|, as well as the
diff --git a/chromium/components/variations/variations_seed_store_unittest.cc b/chromium/components/variations/variations_seed_store_unittest.cc
index 8173ec6650d..b16e04d8a07 100644
--- a/chromium/components/variations/variations_seed_store_unittest.cc
+++ b/chromium/components/variations/variations_seed_store_unittest.cc
@@ -1194,27 +1194,20 @@ TEST(VariationsSeedStoreTest, ImportFirstRunJavaSeed) {
test_seed_country, test_response_date,
test_is_gzip_compressed);
- std::string seed_data;
- std::string seed_signature;
- std::string seed_country;
- std::string response_date;
- bool is_gzip_compressed;
- android::GetVariationsFirstRunSeed(&seed_data, &seed_signature, &seed_country,
- &response_date, &is_gzip_compressed);
- EXPECT_EQ(test_seed_data, seed_data);
- EXPECT_EQ(test_seed_signature, seed_signature);
- EXPECT_EQ(test_seed_country, seed_country);
- EXPECT_EQ(test_response_date, response_date);
- EXPECT_EQ(test_is_gzip_compressed, is_gzip_compressed);
+ auto seed = android::GetVariationsFirstRunSeed();
+ EXPECT_EQ(test_seed_data, seed->data);
+ EXPECT_EQ(test_seed_signature, seed->signature);
+ EXPECT_EQ(test_seed_country, seed->country);
+ EXPECT_EQ(test_response_date, seed->date);
+ EXPECT_EQ(test_is_gzip_compressed, seed->is_gzip_compressed);
android::ClearJavaFirstRunPrefs();
- android::GetVariationsFirstRunSeed(&seed_data, &seed_signature, &seed_country,
- &response_date, &is_gzip_compressed);
- EXPECT_EQ("", seed_data);
- EXPECT_EQ("", seed_signature);
- EXPECT_EQ("", seed_country);
- EXPECT_EQ("", response_date);
- EXPECT_FALSE(is_gzip_compressed);
+ seed = android::GetVariationsFirstRunSeed();
+ EXPECT_EQ("", seed->data);
+ EXPECT_EQ("", seed->signature);
+ EXPECT_EQ("", seed->country);
+ EXPECT_EQ("", seed->date);
+ EXPECT_FALSE(seed->is_gzip_compressed);
}
#endif // OS_ANDROID
diff --git a/chromium/components/vector_icons/BUILD.gn b/chromium/components/vector_icons/BUILD.gn
index 030a9c5d5ce..3653ec14ba9 100644
--- a/chromium/components/vector_icons/BUILD.gn
+++ b/chromium/components/vector_icons/BUILD.gn
@@ -14,7 +14,7 @@ aggregate_vector_icons("components_vector_icons") {
"business.icon",
"check_circle.icon",
"close.icon",
- "close_16.icon",
+ "close_rounded.icon",
"edit.icon",
"folder.icon",
"folder_managed.icon",
diff --git a/chromium/components/vector_icons/README.md b/chromium/components/vector_icons/README.md
index 2fc3b3d5bae..bf51d91b6c7 100644
--- a/chromium/components/vector_icons/README.md
+++ b/chromium/components/vector_icons/README.md
@@ -4,19 +4,19 @@
Chrome can draw vectorized images using Skia. Vector images have the advantages of looking better at different scale factors or sizes, can be easily colorized at runtime, and reduce the chrome binary size.
-Chrome uses .icon files to describe vector icons. This is a bespoke file format which is actually a C++ array definition. At build time, the .icon files are composed into a .cc file which is compiled into the binary.
+Chrome uses `.icon` files to describe vector icons. This is a bespoke file format which is actually a C++ array definition. At build time, the `.icon` files are composed into a .cc file which is compiled into the binary.
-Vector icons can be found in various vector_icons subdirectories throughout the code base. Use `components/vector_icons/` for generic icons shared among many directories and components, or more specific directories such as `ui/views/vector_icons` or `ash/resources/vector_icons` for less widely used icons.
+Vector icons can be found in various `vector_icons` subdirectories throughout the code base. Use `components/vector_icons/` for generic icons shared among many directories and components, or more specific directories such as `ui/views/vector_icons` or `ash/resources/vector_icons` for less widely used icons.
-Some of the icons have **.1x.icon** variants which are used when the device scale factor is 100%. For any other scale factor, the **.icon** variant will be used. The 1x variants are generally only necessary for very small icons which may look fuzzy if shrunk from a larger icon.
+Some of the `.icon` files have multiple variants of the same icon (contained within the same file). See [Why do we need multiples sizes of vector icons](#why-do-we-need-multiple-sizes-of-vector-icons).
## Converting an SVG to .icon format
-[This tool](http://evanstade.github.io/skiafy/) generates .icon file output from SVGs. (If you want to contribute improvements, [here's the project](https://github.com/evanstade/skiafy).)
+[This tool](http://evanstade.github.io/skiafy/) generates `.icon` file output from SVGs. (If you want to contribute improvements, [here's the project](https://github.com/evanstade/skiafy).)
-It handles only a small subset of SVG (paths, circles, etc.) and it's finicky about what it expects as the format, but with a minor amount of manual intervention beforehand, it mostly spits out usable .icon output. It will often work better if you run the SVG through SVGO first, which is a separate project (an SVG minifier). [Jake Archibald's SVGOMG](https://jakearchibald.github.io/svgomg/) is a web interface to SVGO. If any manual adjustments need to be made to the output, the [SVG Path spec](https://www.w3.org/TR/SVG/paths.html) is a helpful reference; compare with the relevant [Chromium drawing commands](https://cs.chromium.org/chromium/src/ui/gfx/vector_icon_types.h?rcl=b9bf332694f083c6767416b69d0f8539d1c44707&l=22).
+It handles only a small subset of SVG (paths, circles, etc.) and it's finicky about what it expects as the format, but with a minor amount of manual intervention beforehand, it mostly spits out usable `.icon` output. It will often work better if you run the SVG through SVGO first, which is a separate project (an SVG minifier). [Jake Archibald's SVGOMG](https://jakearchibald.github.io/svgomg/) is a web interface to SVGO. If any manual adjustments need to be made to the output, the [SVG Path spec](https://www.w3.org/TR/SVG/paths.html) is a helpful reference; compare with the relevant [Chromium drawing commands](https://cs.chromium.org/chromium/src/ui/gfx/vector_icon_types.h?rcl=b9bf332694f083c6767416b69d0f8539d1c44707&l=22).
-Some SVGs are already pretty minimal, like the ones at [the Material Design Icon repository](https://material.io/icons/) so they don't require much if any adjustment, but some SVG editing tools like Sketch leave a lot of random cruft so SVGOMG helps a lot. Take the output and insert into a .icon file.
+Some SVGs are already pretty minimal, like the ones at [the Material Design Icon repository](https://material.io/icons/) so they don't require much if any adjustment, but some SVG editing tools like Sketch leave a lot of random cruft so SVGOMG helps a lot. Take the output and insert into a `.icon` file.
### Troubleshooting icon generation
@@ -24,11 +24,25 @@ Some SVGs are already pretty minimal, like the ones at [the Material Design Icon
## Using .icon files
-Once you have created an .icon file, place it in an appropriate vector_icon subdirectory and add the filename to the corresponding BUILD.gn. A constant is automatically generated so that the icon can be referenced at runtime. The icon file foo_bar.icon is mapped to the constant name of kFooBarIcon ('k' + camel-cased filename + 'Icon') and a sample call site to create this icon looks something like:
+### Adding new icons
+
+Once you have created an `.icon` file, place it in an appropriate `vector_icon` subdirectory and add the filename to the corresponding `BUILD.gn`. A constant is automatically generated so that the icon can be referenced at runtime. The icon file `foo_bar.icon` is mapped to the constant name of `kFooBarIcon` ('k' + camel-cased filename + 'Icon'), which you can use to reference that icon in code. The icon's name should match its identifier on [the MD icons site](https://material.io/icons/) if that's where it came from. For example, `ic_accessibility` would become `accessibility.icon`.
+
+### Icons with multiple definitions
+
+To add multiple icon definitions to a single `.icon` file, place the definitions generated by Skiafy in descending order of size. Each definition after the first must start with a `CANVAS_DIMENSIONS` directive.
+
+Your icon may not need multiple definitions. Don't add different sizes that are exact copies of one another with a scaling multiplier applied.
+
+### In code
+
+A sample call site to create an icon for the `foo_bar.icon` file looks something like:
gfx::CreateVectorIcon(kFooBarIcon, 32, color_utils::DeriveDefaultIconColor(text_color));
-If the size argument is unspecified, the size will be taken from the .icon file (or the .1x.icon if more than one exists). The icon's name should match its identifier on [the MD icons site](https://material.io/icons/) if that's where it came from. For example, `ic_accessibility` would become `accessibility.icon`.
+If the size argument is unspecified, the size will be taken from the smallest icon size in the `.icon` file.
+
+`CreateVectorIcon()` will use the icon definition that best matches the final pixel size required, which is the product of DIP and the device scale factor (DSF). For example, for a DIP size of 32 and DSF of 100%, a rep with `CANVAS_DIMENSIONS, 32,` would be used, whereas a configuration with DSF of 150% would prefer a rep with `CANVAS_DIMENSIONS, 48`.
## FAQ
@@ -46,7 +60,14 @@ You can also build and run the `views_examples_exe` (or `views_examples_with_con
Yes. You can hard-code colors for specific path elements by adding a `PATH_COLOR_ARGB` command to the appropriate place within the .icon file. Any path elements which are not given a hard-coded color in this manner will use the color provided to `CreateVectorIcon()` at runtime.
-
### When introducing a new icon, should I use a PNG or a vector icon?
Use a vector icon, unless the icon is extremely complex (e.g., a product logo). Also see above, "Where can I use vector icons?"
+
+### I see mentions of '.1x.icon' files on the bug tracker. What are those?
+
+A deprecated format where different icon representations were spread across different files.
+
+### Why do we need multiple sizes of **vector** icons?
+
+Even though these icons are vector, sometimes they may still be blurry or fuzzy drawn at different sizes. This is due to the icon not being aligned to the pixel grid and is more obvious at small sizes. In these cases, it is better to design an additional icon specifically for that size. For larger icons, the line stroke width used is often thicker (e.g. 2px for 100%, 3px for 200%), or they may include more detail omitted from smaller ones.
diff --git a/chromium/components/vector_icons/aggregate_vector_icons.py b/chromium/components/vector_icons/aggregate_vector_icons.py
index 112cf7bb749..cc7f0c6de1d 100644
--- a/chromium/components/vector_icons/aggregate_vector_icons.py
+++ b/chromium/components/vector_icons/aggregate_vector_icons.py
@@ -28,21 +28,29 @@ def CamelCase(name, suffix):
return "k" + "".join(words) + suffix
-def GetPathName(name, append_1x=False):
- return CamelCase(name, "Path1x" if append_1x else "Path")
+def GetPathName(name, size=None):
+ return CamelCase(name, "{}Path".format(size) if size != None else "Path")
-def GetRepName(name, append_1x=False):
- return CamelCase(name, "Rep1x" if append_1x else "Rep")
+def GetRepListName(name):
+ return CamelCase(name, "RepList")
def GetIconName(name):
return CamelCase(name, "Icon")
+def AddIconToDictionary(icon_file, new_icon, icon_size, icon_index):
+ if icon_size in icon_index:
+ Error("Duplicate icon of size {} found in {}.".format(icon_size, icon_file))
+ icon_index[icon_size] = "\n".join(new_icon)
+ return icon_index
+
+
def ExtractIconReps(icon_file_name):
- """Reads the contents of the given icon file and returns a list of vector
- commands for different icon representations stored in that file.
+ """Reads the contents of the given icon file and returns a dictionary of icon
+ sizes to vector commands for different icon representations stored in that
+ file.
Args:
icon_file_name: The file path of the icon file to read.
@@ -50,9 +58,10 @@ def ExtractIconReps(icon_file_name):
with open(icon_file_name, "r") as icon_file:
icon_file_contents = icon_file.readlines()
+ current_icon_size = REFERENCE_SIZE_DIP
icon_sizes = []
current_icon_representation = []
- icon_representation_list = []
+ icon_representations = {}
for line in icon_file_contents:
# Strip comments and empty lines.
line = line.partition(CPP_COMMENT_DELIMITER)[0].strip()
@@ -63,28 +72,34 @@ def ExtractIconReps(icon_file_name):
if line.startswith(CANVAS_DIMENSIONS):
sizes = re.findall(r"\d+", line)
if len(sizes) != 1:
- Error("Malformed {} line found in {} - it should only specify one size."
+ Error("Malformed {} line in {} - it should specify exactly one size."
.format(CANVAS_DIMENSIONS, icon_file_name))
icon_sizes.append(int(sizes[0]))
# All icons except the first / default icon must start with
# "CANVAS_DIMENSIONS", so rely on it here as a icon delimiter.
if current_icon_representation:
- icon_representation_list.append("\n".join(current_icon_representation))
+ icon_representations = AddIconToDictionary(
+ icon_file_name, current_icon_representation, current_icon_size,
+ icon_representations)
current_icon_representation = []
+ current_icon_size = icon_sizes[-1]
+
current_icon_representation.append(line)
if current_icon_representation:
- icon_representation_list.append("\n".join(current_icon_representation))
+ icon_representations = AddIconToDictionary(
+ icon_file_name, current_icon_representation, current_icon_size,
+ icon_representations)
- if not icon_representation_list:
+ if not icon_representations:
Error("Didn't find any icons in {}.".format(icon_file_name))
- if len(icon_representation_list) != len(icon_sizes):
+ if len(icon_representations) != len(icon_sizes):
icon_sizes.insert(0, REFERENCE_SIZE_DIP)
if sorted(icon_sizes, reverse=True) != icon_sizes:
Error("The icons in {} should be sorted in descending order of size."
.format(icon_file_name))
- return icon_representation_list
+ return icon_representations
def AggregateVectorIcons(working_directory, file_list, output_cc, output_h):
@@ -157,34 +172,24 @@ def AggregateVectorIcons(working_directory, file_list, output_cc, output_h):
(icon_name, extension) = os.path.splitext(
os.path.basename(path_map[icon]))
- # Store the vector-drawing commands for foo_bar.icon in the temporary
- # variable kFooBarPath.
- icon_representation_list = ExtractIconReps(path_map[icon])
- (vector_commands, vector_commands_1x) = None, None
- if len(icon_representation_list) >= 1:
- vector_commands = icon_representation_list[0]
- if len(icon_representation_list) >= 2:
- vector_commands_1x = icon_representation_list[1]
- if len(icon_representation_list) >= 3:
- print "Warning: " + path_map[icon] + " has more than two icon", \
- "representations. Support for this is still a WIP - see", \
- "crbug.com/647286. For now, only the first two will be used."
- output_cc.write("VECTOR_ICON_REP_TEMPLATE({}, {}, {})\n".format(
- GetPathName(icon_name), GetRepName(icon_name), vector_commands))
-
- # Store the vector-drawing commands for foo_bar.icon's 1x version in the
- # temporary variable kFooBarPath1x, if it exists.
- if vector_commands_1x:
- output_cc.write("VECTOR_ICON_REP_TEMPLATE({}, {}, {})\n".format(
- GetPathName(icon_name, True), GetRepName(icon_name, True),
- vector_commands_1x))
- output_cc.write("VECTOR_ICON_TEMPLATE2({}, {}, {})\n".format(
- GetIconName(icon_name), GetRepName(icon_name),
- GetRepName(icon_name, True)))
- else:
- # Define the value of kFooBarIcon.
- output_cc.write("VECTOR_ICON_TEMPLATE({}, {})\n".format(
- GetIconName(icon_name), GetRepName(icon_name)))
+ icon_representations = ExtractIconReps(path_map[icon])
+ icon_representation_strings = []
+ for i, size in enumerate(sorted(icon_representations, reverse=True)):
+ vector_commands = icon_representations[size]
+ icon_path_name = GetPathName(icon_name, size if i != 0 else None)
+ # Store the vector-drawing commands for foo_bar.icon in the temporary
+ # variable kFooBarPath.
+ output_cc.write("VECTOR_ICON_REP_TEMPLATE({}, {})\n".format(
+ icon_path_name, vector_commands))
+ icon_representation_strings.append(
+ "{{{0}, arraysize({0})}}".format(icon_path_name))
+
+ # Another temporary variable kFooBarRepList is used to create all the
+ # VectorIconReps inline, with a pointer to it in the final VectorIcon.
+ output_cc.write("VECTOR_ICON_TEMPLATE_CC({}, {}, {})\n".format(
+ GetRepListName(icon_name), GetIconName(icon_name),
+ ", ".join(icon_representation_strings)))
+
output_cc.close()
diff --git a/chromium/components/vector_icons/cc_macros.h b/chromium/components/vector_icons/cc_macros.h
index eba40a59e1c..e51c4d4486d 100644
--- a/chromium/components/vector_icons/cc_macros.h
+++ b/chromium/components/vector_icons/cc_macros.h
@@ -15,19 +15,14 @@
#define VECTOR_ICON_ID_PREFIX ""
#endif
-#define VECTOR_ICON_REP_TEMPLATE(path_name, rep_name, ...) \
- static constexpr gfx::PathElement path_name[] = {__VA_ARGS__}; \
- constexpr gfx::VectorIconRep rep_name = {path_name, arraysize(path_name)};
+#define VECTOR_ICON_REP_TEMPLATE(path_name, ...) \
+ static constexpr gfx::PathElement path_name[] = {__VA_ARGS__};
-// The VectorIcon will be called kMyIcon, and the identifier for the icon might
-// be "my_namespace::kMyIconId".
-#define VECTOR_ICON_TEMPLATE(icon_name, rep_name) \
- const char icon_name##Id[] = VECTOR_ICON_ID_PREFIX #icon_name; \
- const gfx::VectorIcon icon_name = {&rep_name, nullptr, icon_name##Id};
-
-#define VECTOR_ICON_TEMPLATE2(icon_name, rep_name, rep_name_1x) \
- const char icon_name##Id[] = VECTOR_ICON_ID_PREFIX #icon_name; \
- const gfx::VectorIcon icon_name = {&rep_name, &rep_name_1x, icon_name##Id};
+#define VECTOR_ICON_TEMPLATE_CC(rep_list_name, icon_name, ...) \
+ constexpr char icon_name##Id[] = VECTOR_ICON_ID_PREFIX #icon_name; \
+ static constexpr gfx::VectorIconRep rep_list_name[] = {__VA_ARGS__}; \
+ const gfx::VectorIcon icon_name = {rep_list_name, arraysize(rep_list_name), \
+ icon_name##Id};
#else // !COMPONENTS_VECTOR_ICONS_CC_MACROS_H_
#error This file should only be included once.
diff --git a/chromium/components/vector_icons/close_16.icon b/chromium/components/vector_icons/close_rounded.icon
index e97aa9c61f9..e97aa9c61f9 100644
--- a/chromium/components/vector_icons/close_16.icon
+++ b/chromium/components/vector_icons/close_rounded.icon
diff --git a/chromium/components/version_ui_strings_grdp/OWNERS b/chromium/components/version_ui_strings_grdp/OWNERS
new file mode 100644
index 00000000000..21929621d70
--- /dev/null
+++ b/chromium/components/version_ui_strings_grdp/OWNERS
@@ -0,0 +1 @@
+file://components/version_ui/OWNERS
diff --git a/chromium/components/version_ui_strings_grdp/README.md b/chromium/components/version_ui_strings_grdp/README.md
new file mode 100644
index 00000000000..119d8b9bff7
--- /dev/null
+++ b/chromium/components/version_ui_strings_grdp/README.md
@@ -0,0 +1,5 @@
+This directory of image SHA-1 hashes is used to improve translations of UI
+strings through context images for translators.
+
+See also: [Chrome Translation Screenshots - Instructions & FAQ
+](https://docs.google.com/document/d/1nwYWDny20icMSpLUuV_LgrlbWKrYpbXOERUIZNH636o/edit#heading=h.2t7lc4cxo2au)
diff --git a/chromium/components/visitedlink/browser/visitedlink_master.cc b/chromium/components/visitedlink/browser/visitedlink_master.cc
index 8290597fb3c..c7fbbc0d5e3 100644
--- a/chromium/components/visitedlink/browser/visitedlink_master.cc
+++ b/chromium/components/visitedlink/browser/visitedlink_master.cc
@@ -18,7 +18,6 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
@@ -869,7 +868,7 @@ bool VisitedLinkMaster::CreateApartURLTable(
// Create the shared memory object.
*memory = base::ReadOnlySharedMemoryRegion::Create(alloc_size);
- if (!memory->region.IsValid() || !memory->mapping.IsValid())
+ if (!memory->IsValid())
return false;
memset(memory->mapping.memory(), 0, alloc_size);
diff --git a/chromium/components/viz/OWNERS b/chromium/components/viz/OWNERS
index e0c775099b6..de51ef0cffa 100644
--- a/chromium/components/viz/OWNERS
+++ b/chromium/components/viz/OWNERS
@@ -16,6 +16,11 @@ weiliangc@chromium.org
# CopyOutputRequests/Results
miu@chromium.org
+# renderers (GL/Skia/Software)
+weiliangc@chromium.org
+rjkroege@chromium.org
+ccameron@chromium.org
+
# display_embedder / ozone
reveman@chromium.org
rjkroege@chromium.org
diff --git a/chromium/components/viz/PRESUBMIT.py b/chromium/components/viz/PRESUBMIT.py
index c18ec999493..705241b0248 100644
--- a/chromium/components/viz/PRESUBMIT.py
+++ b/chromium/components/viz/PRESUBMIT.py
@@ -19,9 +19,10 @@ def PostUploadHook(cl, change, output_api):
"""git cl upload will call this hook after the issue is created/modified.
This hook modifies the CL description in order to run extra GPU
- tests (in particular, on Android) in addition to the regular CQ try
- bots. These tests don't yet run by default on
- android_n5x_swarming_rel, but viz changes need to run them.
+ tests (in particular, the WebGL 2.0 conformance tests) in addition
+ to the regular CQ try bots. This test suite is too large to run
+ against all Chromium commits, but should be run against changes
+ likely to affect these tests.
When adding/removing tests here, ensure that both gpu/PRESUBMIT.py and
ui/gl/PRESUBMIT.py are updated.
@@ -29,6 +30,9 @@ def PostUploadHook(cl, change, output_api):
return output_api.EnsureCQIncludeTrybotsAreAdded(
cl,
[
+ 'luci.chromium.try:linux_optional_gpu_tests_rel',
+ 'luci.chromium.try:mac_optional_gpu_tests_rel',
+ 'luci.chromium.try:win_optional_gpu_tests_rel',
'luci.chromium.try:android_optional_gpu_tests_rel',
],
'Automatically added optional GPU tests to run on CQ.')
diff --git a/chromium/components/viz/client/BUILD.gn b/chromium/components/viz/client/BUILD.gn
index f1ff32ed9d8..4bbeeb832aa 100644
--- a/chromium/components/viz/client/BUILD.gn
+++ b/chromium/components/viz/client/BUILD.gn
@@ -8,8 +8,6 @@ viz_component("client") {
sources = [
"client_layer_tree_frame_sink.cc",
"client_layer_tree_frame_sink.h",
- "client_shared_bitmap_manager.cc",
- "client_shared_bitmap_manager.h",
"frame_eviction_manager.cc",
"frame_eviction_manager.h",
"frame_evictor.cc",
@@ -17,8 +15,6 @@ viz_component("client") {
"hit_test_data_provider.h",
"hit_test_data_provider_draw_quad.cc",
"hit_test_data_provider_draw_quad.h",
- "hit_test_data_provider_surface_layer.cc",
- "hit_test_data_provider_surface_layer.h",
"local_surface_id_provider.cc",
"local_surface_id_provider.h",
]
@@ -39,7 +35,6 @@ viz_source_set("unit_tests") {
sources = [
"client_layer_tree_frame_sink_unittest.cc",
"hit_test_data_provider_draw_quad_unittest.cc",
- "hit_test_data_provider_surface_layer_unittest.cc",
]
deps = [
diff --git a/chromium/components/viz/client/DEPS b/chromium/components/viz/client/DEPS
index 2fa7a11d9d7..db90fed94b9 100644
--- a/chromium/components/viz/client/DEPS
+++ b/chromium/components/viz/client/DEPS
@@ -2,7 +2,6 @@
include_rules = [
"+cc",
- "-cc/blink",
"-cc/test",
"-components/viz/common/features.h",
"-components/viz/common/switches.h",
diff --git a/chromium/components/viz/client/client_layer_tree_frame_sink.cc b/chromium/components/viz/client/client_layer_tree_frame_sink.cc
index 58c487fce70..c779823dc64 100644
--- a/chromium/components/viz/client/client_layer_tree_frame_sink.cc
+++ b/chromium/components/viz/client/client_layer_tree_frame_sink.cc
@@ -10,11 +10,10 @@
#include "base/trace_event/trace_event.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
#include "components/viz/client/hit_test_data_provider.h"
-#include "components/viz/client/hit_test_data_provider_surface_layer.h"
#include "components/viz/client/local_surface_id_provider.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/quads/compositor_frame.h"
-#include "components/viz/common/resources/shared_bitmap_manager.h"
namespace viz {
@@ -42,8 +41,7 @@ ClientLayerTreeFrameSink::ClientLayerTreeFrameSink(
: cc::LayerTreeFrameSink(std::move(context_provider),
std::move(worker_context_provider),
std::move(params->compositor_task_runner),
- params->gpu_memory_buffer_manager,
- params->shared_bitmap_manager),
+ params->gpu_memory_buffer_manager),
hit_test_data_provider_(std::move(params->hit_test_data_provider)),
local_surface_id_provider_(std::move(params->local_surface_id_provider)),
synthetic_begin_frame_source_(
@@ -109,12 +107,6 @@ void ClientLayerTreeFrameSink::DetachFromClient() {
cc::LayerTreeFrameSink::DetachFromClient();
}
-void ClientLayerTreeFrameSink::UpdateHitTestData(
- const cc::LayerTreeHostImpl* host_impl) {
- if (hit_test_data_provider_)
- hit_test_data_provider_->UpdateLayerTreeHostImpl(host_impl);
-}
-
void ClientLayerTreeFrameSink::SetLocalSurfaceId(
const LocalSurfaceId& local_surface_id) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
@@ -133,6 +125,15 @@ void ClientLayerTreeFrameSink::SubmitCompositorFrame(CompositorFrame frame) {
if (!enable_surface_synchronization_) {
local_surface_id_ =
local_surface_id_provider_->GetLocalSurfaceIdForFrame(frame);
+ } else {
+ if (local_surface_id_ == last_submitted_local_surface_id_) {
+ CHECK_EQ(last_submitted_device_scale_factor_,
+ frame.device_scale_factor());
+ CHECK_EQ(last_submitted_size_in_pixels_.height(),
+ frame.size_in_pixels().height());
+ CHECK_EQ(last_submitted_size_in_pixels_.width(),
+ frame.size_in_pixels().width());
+ }
}
TRACE_EVENT_FLOW_BEGIN0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
@@ -141,9 +142,15 @@ void ClientLayerTreeFrameSink::SubmitCompositorFrame(CompositorFrame frame) {
TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
&tracing_enabled);
- mojom::HitTestRegionListPtr hit_test_region_list;
+ base::Optional<HitTestRegionList> hit_test_region_list;
if (hit_test_data_provider_)
hit_test_region_list = hit_test_data_provider_->GetHitTestData(frame);
+ else
+ hit_test_region_list = client_->BuildHitTestData();
+
+ last_submitted_local_surface_id_ = local_surface_id_;
+ last_submitted_device_scale_factor_ = frame.device_scale_factor();
+ last_submitted_size_in_pixels_ = frame.size_in_pixels();
compositor_frame_sink_ptr_->SubmitCompositorFrame(
local_surface_id_, std::move(frame), std::move(hit_test_region_list),
diff --git a/chromium/components/viz/client/client_layer_tree_frame_sink.h b/chromium/components/viz/client/client_layer_tree_frame_sink.h
index 06101ea850f..33f06266fc6 100644
--- a/chromium/components/viz/client/client_layer_tree_frame_sink.h
+++ b/chromium/components/viz/client/client_layer_tree_frame_sink.h
@@ -11,6 +11,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "components/viz/client/viz_client_export.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
@@ -24,7 +25,6 @@ namespace viz {
class HitTestDataProvider;
class LocalSurfaceIdProvider;
-class SharedBitmapManager;
class VIZ_CLIENT_EXPORT ClientLayerTreeFrameSink
: public cc::LayerTreeFrameSink,
@@ -52,7 +52,6 @@ class VIZ_CLIENT_EXPORT ClientLayerTreeFrameSink
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager = nullptr;
- SharedBitmapManager* shared_bitmap_manager = nullptr;
std::unique_ptr<SyntheticBeginFrameSource> synthetic_begin_frame_source;
std::unique_ptr<HitTestDataProvider> hit_test_data_provider;
std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider;
@@ -77,7 +76,6 @@ class VIZ_CLIENT_EXPORT ClientLayerTreeFrameSink
// cc::LayerTreeFrameSink implementation.
bool BindToClient(cc::LayerTreeFrameSinkClient* client) override;
void DetachFromClient() override;
- void UpdateHitTestData(const cc::LayerTreeHostImpl* host_impl) override;
void SetLocalSurfaceId(const LocalSurfaceId& local_surface_id) override;
void SubmitCompositorFrame(CompositorFrame frame) override;
void DidNotProduceFrame(const BeginFrameAck& ack) override;
@@ -128,6 +126,10 @@ class VIZ_CLIENT_EXPORT ClientLayerTreeFrameSink
const bool enable_surface_synchronization_;
const bool wants_animate_only_begin_frames_;
+ LocalSurfaceId last_submitted_local_surface_id_;
+ float last_submitted_device_scale_factor_ = 1.f;
+ gfx::Size last_submitted_size_in_pixels_;
+
base::WeakPtrFactory<ClientLayerTreeFrameSink> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(ClientLayerTreeFrameSink);
diff --git a/chromium/components/viz/client/client_shared_bitmap_manager.cc b/chromium/components/viz/client/client_shared_bitmap_manager.cc
deleted file mode 100644
index 4438d890bfc..00000000000
--- a/chromium/components/viz/client/client_shared_bitmap_manager.cc
+++ /dev/null
@@ -1,138 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/client/client_shared_bitmap_manager.h"
-
-#include <stddef.h>
-
-#include <utility>
-
-#include "base/debug/alias.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-#include "components/viz/common/resources/bitmap_allocation.h"
-#include "components/viz/common/resources/resource_format_utils.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace viz {
-
-namespace {
-
-class ClientSharedBitmap : public SharedBitmap {
- public:
- ClientSharedBitmap(
- scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
- shared_bitmap_allocation_notifier,
- base::SharedMemory* shared_memory,
- const SharedBitmapId& id,
- uint32_t sequence_number)
- : SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()),
- id,
- sequence_number),
- shared_bitmap_allocation_notifier_(
- std::move(shared_bitmap_allocation_notifier)),
- tracing_id_(shared_memory->mapped_id()) {}
-
- ClientSharedBitmap(
- scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
- shared_bitmap_allocation_notifier,
- std::unique_ptr<base::SharedMemory> shared_memory_holder,
- const SharedBitmapId& id,
- uint32_t sequence_number)
- : ClientSharedBitmap(std::move(shared_bitmap_allocation_notifier),
- shared_memory_holder.get(),
- id,
- sequence_number) {
- shared_memory_holder_ = std::move(shared_memory_holder);
- }
-
- ~ClientSharedBitmap() override {
- (*shared_bitmap_allocation_notifier_)->DidDeleteSharedBitmap(id());
- }
-
- // SharedBitmap implementation.
- base::UnguessableToken GetCrossProcessGUID() const override {
- return tracing_id_;
- }
-
- private:
- scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
- shared_bitmap_allocation_notifier_;
- std::unique_ptr<base::SharedMemory> shared_memory_holder_;
- base::UnguessableToken tracing_id_;
-};
-
-} // namespace
-
-ClientSharedBitmapManager::ClientSharedBitmapManager(
- scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
- shared_bitmap_allocation_notifier)
- : shared_bitmap_allocation_notifier_(
- std::move(shared_bitmap_allocation_notifier)) {}
-
-ClientSharedBitmapManager::~ClientSharedBitmapManager() = default;
-
-std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::AllocateSharedBitmap(
- const gfx::Size& size,
- ResourceFormat format) {
- DCHECK(IsBitmapFormatSupported(format));
- TRACE_EVENT2("renderer", "ClientSharedBitmapManager::AllocateSharedBitmap",
- "width", size.width(), "height", size.height());
- SharedBitmapId id = SharedBitmap::GenerateId();
- std::unique_ptr<base::SharedMemory> memory =
- bitmap_allocation::AllocateMappedBitmap(size, format);
- uint32_t sequence_number = NotifyAllocatedSharedBitmap(memory.get(), id);
- return std::make_unique<ClientSharedBitmap>(
- shared_bitmap_allocation_notifier_, std::move(memory), id,
- sequence_number);
-}
-
-std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::GetSharedBitmapFromId(
- const gfx::Size&,
- ResourceFormat,
- const SharedBitmapId&) {
- NOTREACHED();
- return nullptr;
-}
-
-bool ClientSharedBitmapManager::ChildAllocatedSharedBitmap(
- mojo::ScopedSharedBufferHandle buffer,
- const SharedBitmapId& id) {
- // Display compositor only.
- NOTREACHED();
- return false;
-}
-
-void ClientSharedBitmapManager::ChildDeletedSharedBitmap(
- const SharedBitmapId& id) {
- // Display compositor only.
- NOTREACHED();
-}
-
-std::unique_ptr<SharedBitmap>
-ClientSharedBitmapManager::GetBitmapForSharedMemory(base::SharedMemory* mem) {
- SharedBitmapId id = SharedBitmap::GenerateId();
- uint32_t sequence_number = NotifyAllocatedSharedBitmap(mem, id);
- return std::make_unique<ClientSharedBitmap>(
- shared_bitmap_allocation_notifier_, mem, id, sequence_number);
-}
-
-// Notifies the browser process that a shared bitmap with the given ID was
-// allocated. Caller keeps ownership of |memory|.
-uint32_t ClientSharedBitmapManager::NotifyAllocatedSharedBitmap(
- base::SharedMemory* memory,
- const SharedBitmapId& id) {
- mojo::ScopedSharedBufferHandle buffer_handle =
- bitmap_allocation::DuplicateAndCloseMappedBitmap(memory, gfx::Size(),
- RGBA_8888);
- {
- base::AutoLock lock(lock_);
- (*shared_bitmap_allocation_notifier_)
- ->DidAllocateSharedBitmap(std::move(buffer_handle), id);
- return ++last_sequence_number_;
- }
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/client/client_shared_bitmap_manager.h b/chromium/components/viz/client/client_shared_bitmap_manager.h
deleted file mode 100644
index 0c5d731a8b0..00000000000
--- a/chromium/components/viz/client/client_shared_bitmap_manager.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_CLIENT_CLIENT_SHARED_BITMAP_MANAGER_H_
-#define COMPONENTS_VIZ_CLIENT_CLIENT_SHARED_BITMAP_MANAGER_H_
-
-#include <stdint.h>
-
-#include <memory>
-
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/synchronization/lock.h"
-#include "components/viz/client/viz_client_export.h"
-#include "components/viz/common/resources/shared_bitmap_manager.h"
-#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
-#include "services/viz/public/interfaces/compositing/shared_bitmap_allocation_notifier.mojom.h"
-
-namespace viz {
-
-// A SharedBitmapManager implementation for use outside of the display
-// compositor's process. This implementation supports SharedBitmaps that
-// can be transported over process boundaries to the display compositor.
-class VIZ_CLIENT_EXPORT ClientSharedBitmapManager : public SharedBitmapManager {
- public:
- explicit ClientSharedBitmapManager(
- scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
- shared_bitmap_allocation_notifier);
- ~ClientSharedBitmapManager() override;
-
- // SharedBitmapManager implementation.
- std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
- const gfx::Size&,
- ResourceFormat format) override;
- std::unique_ptr<SharedBitmap> GetSharedBitmapFromId(
- const gfx::Size&,
- ResourceFormat,
- const SharedBitmapId&) override;
- bool ChildAllocatedSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
- const SharedBitmapId& id) override;
- void ChildDeletedSharedBitmap(const SharedBitmapId& id) override;
-
- std::unique_ptr<SharedBitmap> GetBitmapForSharedMemory(
- base::SharedMemory* mem);
-
- private:
- uint32_t NotifyAllocatedSharedBitmap(base::SharedMemory* memory,
- const SharedBitmapId& id);
-
- scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
- shared_bitmap_allocation_notifier_;
-
- base::Lock lock_;
-
- // Each SharedBitmap allocated by this class is assigned a unique sequence
- // number that is incremental.
- uint32_t last_sequence_number_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(ClientSharedBitmapManager);
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_CLIENT_CLIENT_SHARED_BITMAP_MANAGER_H_
diff --git a/chromium/components/viz/client/hit_test_data_provider.h b/chromium/components/viz/client/hit_test_data_provider.h
index 8afb7cc15d6..4afce3e68b7 100644
--- a/chromium/components/viz/client/hit_test_data_provider.h
+++ b/chromium/components/viz/client/hit_test_data_provider.h
@@ -5,19 +5,13 @@
#ifndef COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_H_
#define COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_H_
-#include <memory>
-#include <vector>
-
#include "base/macros.h"
+#include "base/optional.h"
#include "components/viz/client/viz_client_export.h"
#include "components/viz/common/quads/compositor_frame.h"
-#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
-
-namespace cc {
-class LayerTreeHostImpl;
-}
namespace viz {
+struct HitTestRegionList;
class VIZ_CLIENT_EXPORT HitTestDataProvider {
public:
@@ -26,13 +20,9 @@ class VIZ_CLIENT_EXPORT HitTestDataProvider {
// Returns an array of hit-test regions. May return nullptr to disable
// hit-testing.
- virtual mojom::HitTestRegionListPtr GetHitTestData(
+ virtual base::Optional<HitTestRegionList> GetHitTestData(
const CompositorFrame& compositor_frame) const = 0;
- // Exclusively called by HitTestDataProviderSurfaceLayer.
- virtual void UpdateLayerTreeHostImpl(const cc::LayerTreeHostImpl* host_impl) {
- }
-
private:
DISALLOW_COPY_AND_ASSIGN(HitTestDataProvider);
};
diff --git a/chromium/components/viz/client/hit_test_data_provider_draw_quad.cc b/chromium/components/viz/client/hit_test_data_provider_draw_quad.cc
index 7131e17cef6..a9352520ddf 100644
--- a/chromium/components/viz/client/hit_test_data_provider_draw_quad.cc
+++ b/chromium/components/viz/client/hit_test_data_provider_draw_quad.cc
@@ -4,6 +4,7 @@
#include "components/viz/client/hit_test_data_provider_draw_quad.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/quads/surface_draw_quad.h"
namespace viz {
@@ -14,12 +15,13 @@ HitTestDataProviderDrawQuad::HitTestDataProviderDrawQuad(
HitTestDataProviderDrawQuad::~HitTestDataProviderDrawQuad() = default;
-mojom::HitTestRegionListPtr HitTestDataProviderDrawQuad::GetHitTestData(
+// Derives HitTestRegions from information in the |compositor_frame|.
+base::Optional<HitTestRegionList> HitTestDataProviderDrawQuad::GetHitTestData(
const CompositorFrame& compositor_frame) const {
- // Derive hit test regions from information in the CompositorFrame.
- auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->flags =
- mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine;
+ base::Optional<HitTestRegionList> hit_test_region_list(base::in_place);
+ hit_test_region_list->flags = HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine;
hit_test_region_list->bounds.set_size(compositor_frame.size_in_pixels());
for (const auto& render_pass : compositor_frame.render_pass_list) {
@@ -53,17 +55,18 @@ mojom::HitTestRegionListPtr HitTestDataProviderDrawQuad::GetHitTestData(
continue;
}
- auto hit_test_region = mojom::HitTestRegion::New();
- hit_test_region->frame_sink_id =
+ hit_test_region_list->regions.emplace_back();
+ HitTestRegion& hit_test_region = hit_test_region_list->regions.back();
+ hit_test_region.frame_sink_id =
surface_quad->primary_surface_id.frame_sink_id();
- hit_test_region->flags = mojom::kHitTestMouse | mojom::kHitTestTouch |
- mojom::kHitTestChildSurface;
+ hit_test_region.flags = HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestChildSurface;
if (should_ask_for_child_region_)
- hit_test_region->flags |= mojom::kHitTestAsk;
- hit_test_region->rect = surface_quad->rect;
- hit_test_region->transform =
+ hit_test_region.flags |= HitTestRegionFlags::kHitTestAsk;
+ hit_test_region.rect = surface_quad->rect;
+ hit_test_region.transform =
target_to_quad_transform * transform_from_root_target;
- hit_test_region_list->regions.push_back(std::move(hit_test_region));
}
}
}
diff --git a/chromium/components/viz/client/hit_test_data_provider_draw_quad.h b/chromium/components/viz/client/hit_test_data_provider_draw_quad.h
index f3195d1eb7a..66ecdd776b6 100644
--- a/chromium/components/viz/client/hit_test_data_provider_draw_quad.h
+++ b/chromium/components/viz/client/hit_test_data_provider_draw_quad.h
@@ -17,7 +17,7 @@ class VIZ_CLIENT_EXPORT HitTestDataProviderDrawQuad
explicit HitTestDataProviderDrawQuad(bool should_ask_for_child_region);
~HitTestDataProviderDrawQuad() override;
- mojom::HitTestRegionListPtr GetHitTestData(
+ base::Optional<HitTestRegionList> GetHitTestData(
const CompositorFrame& compositor_frame) const override;
private:
diff --git a/chromium/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc b/chromium/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
index 449ab27ff81..2e27702b44d 100644
--- a/chromium/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
+++ b/chromium/components/viz/client/hit_test_data_provider_draw_quad_unittest.cc
@@ -69,10 +69,12 @@ TEST(HitTestDataProviderDrawQuad, HitTestDataRenderer) {
// Ensure that a CompositorFrame without a child surface sets kHitTestMine.
CompositorFrame compositor_frame =
CompositorFrameBuilder().AddRenderPass(kFrameRect, kFrameRect).Build();
- mojom::HitTestRegionListPtr hit_test_region_list =
+ base::Optional<HitTestRegionList> hit_test_region_list =
hit_test_data_provider->GetHitTestData(compositor_frame);
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine,
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine,
hit_test_region_list->flags);
EXPECT_EQ(kFrameRect, hit_test_region_list->bounds);
EXPECT_FALSE(hit_test_region_list->regions.size());
@@ -94,23 +96,27 @@ TEST(HitTestDataProviderDrawQuad, HitTestDataRenderer) {
hit_test_region_list =
hit_test_data_provider->GetHitTestData(compositor_frame);
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine,
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine,
hit_test_region_list->flags);
EXPECT_EQ(kFrameRect, hit_test_region_list->bounds);
EXPECT_EQ(1u, hit_test_region_list->regions.size());
EXPECT_EQ(child_surface_id.frame_sink_id(),
- hit_test_region_list->regions[0]->frame_sink_id);
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch |
- mojom::kHitTestChildSurface | mojom::kHitTestAsk,
- hit_test_region_list->regions[0]->flags);
- EXPECT_EQ(child_rect, hit_test_region_list->regions[0]->rect);
+ hit_test_region_list->regions[0].frame_sink_id);
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestAsk,
+ hit_test_region_list->regions[0].flags);
+ EXPECT_EQ(child_rect, hit_test_region_list->regions[0].rect);
gfx::Transform render_pass_transform_inverse;
EXPECT_TRUE(render_pass_transform.GetInverse(&render_pass_transform_inverse));
gfx::Transform shared_state_transform_inverse;
EXPECT_TRUE(
shared_state_transform.GetInverse(&shared_state_transform_inverse));
EXPECT_EQ(shared_state_transform_inverse * render_pass_transform_inverse,
- hit_test_region_list->regions[0]->transform);
+ hit_test_region_list->regions[0].transform);
}
// Test to ensure that we skip regions with non-invertible transforms and with
@@ -167,14 +173,14 @@ TEST(HitTestDataProviderDrawQuad, HitTestDataSkipQuads) {
auto compositor_frame =
CompositorFrameBuilder().SetRenderPassList(std::move(pass_list)).Build();
- mojom::HitTestRegionListPtr hit_test_region_list =
+ base::Optional<HitTestRegionList> hit_test_region_list =
hit_test_data_provider->GetHitTestData(compositor_frame);
// Only pass3 should have a hit-test region that corresponds to
// child_surface_id3.
EXPECT_EQ(1u, hit_test_region_list->regions.size());
EXPECT_EQ(child_surface_id3.frame_sink_id(),
- hit_test_region_list->regions[0]->frame_sink_id);
+ hit_test_region_list->regions[0].frame_sink_id);
}
// Test to ensure that browser shouldn't set kHitTestAsk flag for the renderers
@@ -194,28 +200,31 @@ TEST(HitTestDataProviderDrawQuad, HitTestDataBrowser) {
render_to_browser_transform);
CompositorFrame compositor_frame =
CompositorFrameBuilder().AddRenderPass(std::move(pass)).Build();
- mojom::HitTestRegionListPtr hit_test_region_list =
+ base::Optional<HitTestRegionList> hit_test_region_list =
hit_test_data_provider->GetHitTestData(compositor_frame);
// Browser should be able to receive both mouse and touch events. It embeds
// one renderer, which should also have mouse and touch flags; the renderer
// should have child surface flag because it is being embeded, but not ask
// flag because we shouldn't do asyn targeting for the entire renderer.
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine,
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine,
hit_test_region_list->flags);
EXPECT_EQ(frame_rect, hit_test_region_list->bounds);
EXPECT_EQ(1u, hit_test_region_list->regions.size());
EXPECT_EQ(child_surface_id.frame_sink_id(),
- hit_test_region_list->regions[0]->frame_sink_id);
- EXPECT_EQ(
- mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestChildSurface,
- hit_test_region_list->regions[0]->flags);
- EXPECT_EQ(child_rect, hit_test_region_list->regions[0]->rect);
+ hit_test_region_list->regions[0].frame_sink_id);
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestChildSurface,
+ hit_test_region_list->regions[0].flags);
+ EXPECT_EQ(child_rect, hit_test_region_list->regions[0].rect);
gfx::Transform browser_to_render_transform;
EXPECT_TRUE(
render_to_browser_transform.GetInverse(&browser_to_render_transform));
EXPECT_EQ(browser_to_render_transform,
- hit_test_region_list->regions[0]->transform);
+ hit_test_region_list->regions[0].transform);
}
} // namespace viz
diff --git a/chromium/components/viz/client/hit_test_data_provider_surface_layer.cc b/chromium/components/viz/client/hit_test_data_provider_surface_layer.cc
deleted file mode 100644
index acea52c5245..00000000000
--- a/chromium/components/viz/client/hit_test_data_provider_surface_layer.cc
+++ /dev/null
@@ -1,116 +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 "hit_test_data_provider_surface_layer.h"
-
-#include "base/containers/adapters.h"
-#include "cc/layers/surface_layer_impl.h"
-#include "cc/trees/layer_tree_host_impl.h"
-#include "cc/trees/layer_tree_impl.h"
-
-namespace {
-
-uint32_t GetFlagsForSurfaceLayer(const cc::SurfaceLayerImpl* layer) {
- uint32_t flags = viz::mojom::kHitTestMouse | viz::mojom::kHitTestTouch;
- const auto& surface_id = layer->primary_surface_id();
- if (layer->is_clipped()) {
- flags |= viz::mojom::kHitTestAsk;
- }
- if (surface_id.local_surface_id().is_valid()) {
- flags |= viz::mojom::kHitTestChildSurface;
- } else {
- flags |= viz::mojom::kHitTestMine;
- }
- return flags;
-}
-
-viz::mojom::HitTestRegionPtr CreateHitTestRegion(
- const cc::LayerImpl* layer,
- uint32_t flags,
- const gfx::Rect& rect,
- const viz::SurfaceId& surface_id,
- float device_scale_factor) {
- auto hit_test_region = viz::mojom::HitTestRegion::New();
- hit_test_region->frame_sink_id = surface_id.frame_sink_id();
- hit_test_region->flags = flags;
-
- hit_test_region->rect = rect;
- // The transform of hit test region maps a point from parent hit test region
- // to the local space. This is the inverse of screen space transform. Because
- // hit test query wants the point in target to be in Pixel space, we
- // counterscale the transform here. Note that the rect is scaled by dsf, so
- // the point and the rect are still in the same space.
- gfx::Transform surface_to_root_transform = layer->ScreenSpaceTransform();
- surface_to_root_transform.Scale(SK_MScalar1 / device_scale_factor,
- SK_MScalar1 / device_scale_factor);
- // TODO(sunxd): Avoid losing precision by not using inverse if possible.
- if (!surface_to_root_transform.GetInverse(&(hit_test_region->transform)))
- hit_test_region->transform = gfx::Transform();
- return hit_test_region;
-}
-
-} // namespace
-
-namespace viz {
-
-// TODO(sunxd): Remove the compositor_frame parameter in base class when surface
-// layer hit testing is enabled.
-mojom::HitTestRegionListPtr HitTestDataProviderSurfaceLayer::GetHitTestData(
- const CompositorFrame& compositor_frame) const {
- DCHECK(host_impl_);
- float device_scale_factor = host_impl_->active_tree()->device_scale_factor();
- auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->flags =
- mojom::kHitTestMine | mojom::kHitTestMouse | mojom::kHitTestTouch;
- hit_test_region_list->bounds = host_impl_->DeviceViewport();
- hit_test_region_list->transform = host_impl_->DrawTransform();
-
- cc::Region overlapping_region;
- for (const auto* layer : base::Reversed(*host_impl_->active_tree())) {
- if (!layer->should_hit_test())
- continue;
-
- if (layer->is_surface_layer()) {
- const auto* surface_layer =
- static_cast<const cc::SurfaceLayerImpl*>(layer);
-
- if (!surface_layer->hit_testable()) {
- overlapping_region.Union(cc::MathUtil::MapEnclosingClippedRect(
- layer->ScreenSpaceTransform(), gfx::Rect(surface_layer->bounds())));
- continue;
- }
-
- gfx::Rect content_rect(
- gfx::ScaleToEnclosingRect(gfx::Rect(surface_layer->bounds()),
- device_scale_factor, device_scale_factor));
-
- gfx::Rect layer_screen_space_rect = cc::MathUtil::MapEnclosingClippedRect(
- surface_layer->ScreenSpaceTransform(),
- gfx::Rect(surface_layer->bounds()));
- if (overlapping_region.Contains(layer_screen_space_rect))
- continue;
-
- auto flag = GetFlagsForSurfaceLayer(surface_layer);
- if (overlapping_region.Intersects(layer_screen_space_rect))
- flag |= mojom::kHitTestAsk;
- auto surface_id = surface_layer->primary_surface_id();
- hit_test_region_list->regions.push_back(CreateHitTestRegion(
- layer, flag, content_rect, surface_id, device_scale_factor));
- continue;
- }
- // TODO(sunxd): Submit all overlapping layer bounds as hit test regions to
- // viz.
- overlapping_region.Union(cc::MathUtil::MapEnclosingClippedRect(
- layer->ScreenSpaceTransform(), gfx::Rect(layer->bounds())));
- }
-
- return hit_test_region_list;
-}
-
-void HitTestDataProviderSurfaceLayer::UpdateLayerTreeHostImpl(
- const cc::LayerTreeHostImpl* host_impl) {
- host_impl_ = host_impl;
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/client/hit_test_data_provider_surface_layer.h b/chromium/components/viz/client/hit_test_data_provider_surface_layer.h
deleted file mode 100644
index 50480404ff2..00000000000
--- a/chromium/components/viz/client/hit_test_data_provider_surface_layer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_SURFACE_LAYER_H_
-#define COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_SURFACE_LAYER_H_
-
-#include "base/macros.h"
-#include "components/viz/client/hit_test_data_provider.h"
-#include "components/viz/client/viz_client_export.h"
-
-namespace cc {
-
-class LayerTreeHostImpl;
-}
-
-namespace viz {
-
-// HitTestDataProviderSurfaceLayer is used to extract hit test data from
-// cc::LayerTreeHostImpl when submitting CompositorFrame.
-class VIZ_CLIENT_EXPORT HitTestDataProviderSurfaceLayer
- : public HitTestDataProvider {
- public:
- HitTestDataProviderSurfaceLayer() = default;
-
- mojom::HitTestRegionListPtr GetHitTestData(
- const CompositorFrame& compositor_frame) const override;
-
- void UpdateLayerTreeHostImpl(const cc::LayerTreeHostImpl* host_impl) override;
-
- private:
- const cc::LayerTreeHostImpl* host_impl_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(HitTestDataProviderSurfaceLayer);
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_CLIENT_HIT_TEST_DATA_PROVIDER_SURFACE_LAYER_H_
diff --git a/chromium/components/viz/client/hit_test_data_provider_surface_layer_unittest.cc b/chromium/components/viz/client/hit_test_data_provider_surface_layer_unittest.cc
deleted file mode 100644
index c92968d9d88..00000000000
--- a/chromium/components/viz/client/hit_test_data_provider_surface_layer_unittest.cc
+++ /dev/null
@@ -1,153 +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 "components/viz/client/hit_test_data_provider_surface_layer.h"
-
-#include <memory>
-
-#include "base/bind.h"
-#include "base/memory/scoped_refptr.h"
-#include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread.h"
-#include "cc/layers/surface_layer_impl.h"
-#include "cc/test/fake_impl_task_runner_provider.h"
-#include "cc/test/fake_layer_tree_frame_sink_client.h"
-#include "cc/test/fake_layer_tree_host_impl.h"
-#include "cc/test/test_task_graph_runner.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "components/viz/client/local_surface_id_provider.h"
-#include "components/viz/common/quads/surface_draw_quad.h"
-#include "components/viz/test/compositor_frame_helpers.h"
-#include "components/viz/test/test_gpu_memory_buffer_manager.h"
-#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace viz {
-
-// Test to ensure that hit test data is created correctly from CompositorFrame
-// and the underlying layer tree.
-TEST(HitTestDataProviderSurfaceLayerTest, HitTestDataRenderer) {
- cc::FakeImplTaskRunnerProvider task_runner_provider;
- cc::TestTaskGraphRunner task_graph_runner;
- cc::FakeLayerTreeHostImpl host_impl(&task_runner_provider,
- &task_graph_runner);
-
-#if DCHECK_IS_ON()
- task_runner_provider.SetCurrentThreadIsImplThread(true);
-#endif
-
- std::unique_ptr<HitTestDataProvider> hit_test_data_provider =
- std::make_unique<HitTestDataProviderSurfaceLayer>();
-
- // Setup surface layers in LayerTreeHostImpl.
-
- host_impl.CreatePendingTree();
- host_impl.ActivateSyncTree();
-
- // The structure of the layer tree:
- // +-Root (1024x768)
- // +---intermediate_layer (200, 300), 200x200
- // +-----surface_child1 (50, 50), 100x100, Rotate(45)
- // +---surface_child2 (450, 300), 100x100
- // +---overlapping_layer (500, 350), 200x200
- std::unique_ptr<cc::LayerImpl> intermediate_layer =
- cc::LayerImpl::Create(host_impl.active_tree(), 2);
- std::unique_ptr<cc::SurfaceLayerImpl> surface_child1 =
- cc::SurfaceLayerImpl::Create(host_impl.active_tree(), 3);
- std::unique_ptr<cc::SurfaceLayerImpl> surface_child2 =
- cc::SurfaceLayerImpl::Create(host_impl.active_tree(), 4);
- std::unique_ptr<cc::LayerImpl> overlapping_layer =
- cc::LayerImpl::Create(host_impl.active_tree(), 5);
-
- host_impl.SetViewportSize(gfx::Size(1024, 768));
-
- intermediate_layer->SetPosition(gfx::PointF(200, 300));
- intermediate_layer->SetBounds(gfx::Size(200, 200));
-
- surface_child1->SetPosition(gfx::PointF(50, 50));
- surface_child1->SetBounds(gfx::Size(100, 100));
- gfx::Transform rotate;
- rotate.Rotate(45);
- surface_child1->test_properties()->transform = rotate;
- surface_child1->SetDrawsContent(true);
- surface_child1->SetHitTestable(true);
-
- surface_child2->SetPosition(gfx::PointF(450, 300));
- surface_child2->SetBounds(gfx::Size(100, 100));
- surface_child2->SetDrawsContent(true);
- surface_child2->SetHitTestable(true);
-
- overlapping_layer->SetPosition(gfx::PointF(500, 350));
- overlapping_layer->SetBounds(gfx::Size(200, 200));
- overlapping_layer->SetDrawsContent(true);
-
- LocalSurfaceId child_local_surface_id(2, base::UnguessableToken::Create());
- FrameSinkId frame_sink_id(2, 0);
- SurfaceId child_surface_id(frame_sink_id, child_local_surface_id);
- surface_child1->SetPrimarySurfaceId(child_surface_id, base::nullopt);
- surface_child2->SetPrimarySurfaceId(child_surface_id, base::nullopt);
-
- std::unique_ptr<cc::LayerImpl> root =
- cc::LayerImpl::Create(host_impl.active_tree(), 1);
- host_impl.active_tree()->SetRootLayerForTesting(std::move(root));
- intermediate_layer->test_properties()->AddChild(std::move(surface_child1));
- host_impl.active_tree()
- ->root_layer_for_testing()
- ->test_properties()
- ->AddChild(std::move(intermediate_layer));
- host_impl.active_tree()
- ->root_layer_for_testing()
- ->test_properties()
- ->AddChild(std::move(surface_child2));
- host_impl.active_tree()
- ->root_layer_for_testing()
- ->test_properties()
- ->AddChild(std::move(overlapping_layer));
-
- host_impl.active_tree()->BuildPropertyTreesForTesting();
-
- hit_test_data_provider->UpdateLayerTreeHostImpl(&host_impl);
- constexpr gfx::Rect kFrameRect(0, 0, 1024, 768);
-
- CompositorFrame compositor_frame =
- CompositorFrameBuilder().AddRenderPass(kFrameRect, kFrameRect).Build();
- mojom::HitTestRegionListPtr hit_test_region_list =
- hit_test_data_provider->GetHitTestData(compositor_frame);
-
- // Since surface_child2 draws in front of surface_child1, it should also be in
- // the front of the hit test region list.
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine,
- hit_test_region_list->flags);
- EXPECT_EQ(kFrameRect, hit_test_region_list->bounds);
- EXPECT_EQ(2u, hit_test_region_list->regions.size());
-
- EXPECT_EQ(child_surface_id.frame_sink_id(),
- hit_test_region_list->regions[1]->frame_sink_id);
- EXPECT_EQ(
- mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestChildSurface,
- hit_test_region_list->regions[1]->flags);
- gfx::Transform child1_transform;
- child1_transform.Rotate(-45);
- child1_transform.Translate(-250, -350);
- EXPECT_TRUE(child1_transform.ApproximatelyEqual(
- hit_test_region_list->regions[1]->transform));
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- hit_test_region_list->regions[1]->rect.ToString());
-
- EXPECT_EQ(child_surface_id.frame_sink_id(),
- hit_test_region_list->regions[0]->frame_sink_id);
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch |
- mojom::kHitTestChildSurface | mojom::kHitTestAsk,
- hit_test_region_list->regions[0]->flags);
- gfx::Transform child2_transform;
- child2_transform.Translate(-450, -300);
- EXPECT_TRUE(child2_transform.ApproximatelyEqual(
- hit_test_region_list->regions[0]->transform));
- EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
- hit_test_region_list->regions[0]->rect.ToString());
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/client/local_surface_id_provider.cc b/chromium/components/viz/client/local_surface_id_provider.cc
index 80405f3069c..e84ce919114 100644
--- a/chromium/components/viz/client/local_surface_id_provider.cc
+++ b/chromium/components/viz/client/local_surface_id_provider.cc
@@ -16,9 +16,7 @@ DefaultLocalSurfaceIdProvider::DefaultLocalSurfaceIdProvider() = default;
const LocalSurfaceId& DefaultLocalSurfaceIdProvider::GetLocalSurfaceIdForFrame(
const CompositorFrame& frame) {
- if (!parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId()
- .is_valid() ||
- surface_size_ != frame.size_in_pixels() ||
+ if (frame.size_in_pixels() != surface_size_ ||
frame.device_scale_factor() != device_scale_factor_) {
parent_local_surface_id_allocator_.GenerateId();
}
diff --git a/chromium/components/viz/common/BUILD.gn b/chromium/components/viz/common/BUILD.gn
index ea9eed0ab96..34f30ddb03a 100644
--- a/chromium/components/viz/common/BUILD.gn
+++ b/chromium/components/viz/common/BUILD.gn
@@ -62,16 +62,13 @@ viz_component("common") {
"gpu/context_lost_observer.h",
"gpu/context_provider.cc",
"gpu/context_provider.h",
- "gpu/in_process_context_provider.cc",
- "gpu/in_process_context_provider.h",
"gpu/raster_context_provider.cc",
"gpu/raster_context_provider.h",
"gpu/texture_allocation.cc",
"gpu/texture_allocation.h",
- "gpu/vulkan_context_provider.h",
- "gpu/vulkan_in_process_context_provider.cc",
- "gpu/vulkan_in_process_context_provider.h",
"hit_test/aggregated_hit_test_region.h",
+ "hit_test/hit_test_region_list.cc",
+ "hit_test/hit_test_region_list.h",
"quads/compositor_frame.cc",
"quads/compositor_frame.h",
"quads/compositor_frame_metadata.cc",
@@ -121,10 +118,12 @@ viz_component("common") {
"resources/resource_settings.cc",
"resources/resource_settings.h",
"resources/resource_sizes.h",
- "resources/resource_texture_hint.h",
"resources/resource_type.h",
+ "resources/return_callback.h",
"resources/returned_resource.h",
"resources/shared_bitmap_manager.h",
+ "resources/shared_bitmap_reporter.cc",
+ "resources/shared_bitmap_reporter.h",
"resources/single_release_callback.cc",
"resources/single_release_callback.h",
"resources/transferable_resource.cc",
@@ -165,9 +164,6 @@ viz_component("common") {
"//gpu/command_buffer/client:gles2_interface",
"//gpu/command_buffer/client:raster",
"//gpu/command_buffer/client:raster_interface",
- "//gpu/command_buffer/service",
- "//gpu/ipc:gl_in_process_context",
- "//gpu/skia_bindings:skia_bindings",
"//gpu/vulkan:buildflags",
"//mojo/public/cpp/bindings",
"//skia",
@@ -181,8 +177,22 @@ viz_component("common") {
]
if (enable_vulkan) {
+ sources += [
+ "gpu/vulkan_context_provider.h",
+ "gpu/vulkan_in_process_context_provider.cc",
+ "gpu/vulkan_in_process_context_provider.h",
+ ]
configs = [ "//third_party/vulkan:vulkan_config" ]
- deps += [ "//gpu/vulkan" ]
+ deps += [ "//gpu/vulkan/init" ]
+ }
+
+ if (is_win) {
+ sources += [
+ "display/use_layered_window.cc",
+ "display/use_layered_window.h",
+ ]
+
+ deps += [ "//ui/base" ]
}
public_deps = [
@@ -204,6 +214,7 @@ viz_source_set("unit_tests") {
"quads/draw_quad_unittest.cc",
"quads/render_pass_unittest.cc",
"resources/platform_color_unittest.cc",
+ "resources/resource_sizes_unittest.cc",
"surfaces/child_local_surface_id_allocator_unittest.cc",
"surfaces/local_surface_id_unittest.cc",
"surfaces/parent_local_surface_id_allocator_unittest.cc",
diff --git a/chromium/components/viz/common/display/renderer_settings.h b/chromium/components/viz/common/display/renderer_settings.h
index db0b1d75f1d..740cb2ab71c 100644
--- a/chromium/components/viz/common/display/renderer_settings.h
+++ b/chromium/components/viz/common/display/renderer_settings.h
@@ -33,6 +33,7 @@ class VIZ_COMMON_EXPORT RendererSettings {
bool allow_overlays = true;
bool dont_round_texture_sizes_for_pixel_tests = false;
int highp_threshold_min = 0;
+ bool auto_resize_output_surface = true;
int slow_down_compositing_scale_factor = 1;
diff --git a/chromium/components/viz/common/display/use_layered_window.cc b/chromium/components/viz/common/display/use_layered_window.cc
new file mode 100644
index 00000000000..8df5d69ba22
--- /dev/null
+++ b/chromium/components/viz/common/display/use_layered_window.cc
@@ -0,0 +1,20 @@
+// 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 "components/viz/common/display/use_layered_window.h"
+
+#include "ui/base/win/internal_constants.h"
+
+namespace viz {
+
+bool NeedsToUseLayerWindow(HWND hwnd) {
+ // TODO(kylechar): Revisit if we can not use layered windows on Windows 8 and
+ // higher. With DWM enabled HWNDs seem to support an alpha channel natively.
+ // However, when touch highlight or pointer trails are enabled Windows ends up
+ // blending the highlight/trail with old content for non-layered HWNDs. See
+ // https://crbug.com/843974 for more details.
+ return GetProp(hwnd, ui::kWindowTranslucent);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/common/display/use_layered_window.h b/chromium/components/viz/common/display/use_layered_window.h
new file mode 100644
index 00000000000..2db19f310df
--- /dev/null
+++ b/chromium/components/viz/common/display/use_layered_window.h
@@ -0,0 +1,20 @@
+// 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 COMPONENTS_VIZ_COMMON_DISPLAY_USE_LAYERED_WINDOW_H_
+#define COMPONENTS_VIZ_COMMON_DISPLAY_USE_LAYERED_WINDOW_H_
+
+#include <windows.h>
+
+#include "components/viz/common/viz_common_export.h"
+
+namespace viz {
+
+// Checks if an HWND needs to support transparency and should use a layered
+// window.
+VIZ_COMMON_EXPORT bool NeedsToUseLayerWindow(HWND hwnd);
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_DISPLAY_USE_LAYERED_WINDOW_H_
diff --git a/chromium/components/viz/common/features.cc b/chromium/components/viz/common/features.cc
index 0355086f325..745c26bb950 100644
--- a/chromium/components/viz/common/features.cc
+++ b/chromium/components/viz/common/features.cc
@@ -40,6 +40,14 @@ const base::Feature kEnableVizHitTestDrawQuad{
const base::Feature kEnableVizHitTestSurfaceLayer{
"VizHitTestSurfaceLayer", base::FEATURE_DISABLED_BY_DEFAULT};
+// Use the SkiaRenderer.
+const base::Feature kUseSkiaDeferredDisplayList{
+ "UseSkiaDeferredDisplayList", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Use the Skia deferred display list.
+const base::Feature kUseSkiaRenderer{"UseSkiaRenderer",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
bool IsSurfaceSynchronizationEnabled() {
auto* command_line = base::CommandLine::ForCurrentProcess();
return base::FeatureList::IsEnabled(kEnableSurfaceSynchronization) ||
@@ -75,4 +83,14 @@ bool IsDrawOcclusionEnabled() {
return base::FeatureList::IsEnabled(kEnableDrawOcclusion);
}
+bool IsUsingSkiaRenderer() {
+ return base::FeatureList::IsEnabled(kUseSkiaRenderer);
+}
+
+bool IsUsingSkiaDeferredDisplayList() {
+ return IsUsingSkiaRenderer() &&
+ base::FeatureList::IsEnabled(kUseSkiaDeferredDisplayList) &&
+ base::FeatureList::IsEnabled(kVizDisplayCompositor);
+}
+
} // namespace features
diff --git a/chromium/components/viz/common/features.h b/chromium/components/viz/common/features.h
index b7eaf7f385d..f5f21df0018 100644
--- a/chromium/components/viz/common/features.h
+++ b/chromium/components/viz/common/features.h
@@ -16,6 +16,8 @@ VIZ_COMMON_EXPORT extern const base::Feature kEnableSurfaceSynchronization;
VIZ_COMMON_EXPORT extern const base::Feature kEnableInvariantsViolationLogging;
VIZ_COMMON_EXPORT extern const base::Feature kEnableVizHitTestDrawQuad;
VIZ_COMMON_EXPORT extern const base::Feature kEnableVizHitTestSurfaceLayer;
+VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaDeferredDisplayList;
+VIZ_COMMON_EXPORT extern const base::Feature kUseSkiaRenderer;
VIZ_COMMON_EXPORT extern const base::Feature kVizDisplayCompositor;
VIZ_COMMON_EXPORT bool IsDrawOcclusionEnabled();
@@ -24,6 +26,8 @@ VIZ_COMMON_EXPORT bool IsSurfaceInvariantsViolationLoggingEnabled();
VIZ_COMMON_EXPORT bool IsVizHitTestingDrawQuadEnabled();
VIZ_COMMON_EXPORT bool IsVizHitTestingEnabled();
VIZ_COMMON_EXPORT bool IsVizHitTestingSurfaceLayerEnabled();
+VIZ_COMMON_EXPORT bool IsUsingSkiaDeferredDisplayList();
+VIZ_COMMON_EXPORT bool IsUsingSkiaRenderer();
} // namespace features
diff --git a/chromium/components/viz/common/frame_sinks/copy_output_request.cc b/chromium/components/viz/common/frame_sinks/copy_output_request.cc
index 43fa33bcbde..56164fa32ea 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_request.cc
+++ b/chromium/components/viz/common/frame_sinks/copy_output_request.cc
@@ -64,14 +64,6 @@ bool CopyOutputRequest::SendsResultsInCurrentSequence() const {
result_task_runner_->RunsTasksInCurrentSequence();
}
-void CopyOutputRequest::SetMailbox(const gpu::Mailbox& mailbox,
- const gpu::SyncToken& sync_token) {
- DCHECK_EQ(result_format_, ResultFormat::RGBA_TEXTURE);
- DCHECK(!mailbox.IsZero());
- mailbox_ = mailbox;
- sync_token_ = sync_token;
-}
-
// static
std::unique_ptr<CopyOutputRequest> CopyOutputRequest::CreateStubForTesting() {
return std::make_unique<CopyOutputRequest>(
diff --git a/chromium/components/viz/common/frame_sinks/copy_output_request.h b/chromium/components/viz/common/frame_sinks/copy_output_request.h
index 4c57ab26846..d38cfde73ad 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_request.h
+++ b/chromium/components/viz/common/frame_sinks/copy_output_request.h
@@ -107,17 +107,6 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
bool has_result_selection() const { return result_selection_.has_value(); }
const gfx::Rect& result_selection() const { return *result_selection_; }
- // Legacy support for providing textures up-front, to copy results into.
- // TODO(miu): Remove these methods after tab capture is moved to VIZ.
- // http://crbug.com/754872
- // The texture bound to the mailbox is expected to have a GL_TEXTURE_2D
- // target.
- void SetMailbox(const gpu::Mailbox& mailbox,
- const gpu::SyncToken& sync_token);
- bool has_mailbox() const { return mailbox_.has_value(); }
- const gpu::Mailbox& mailbox() const { return *mailbox_; }
- const gpu::SyncToken& sync_token() const { return *sync_token_; }
-
// Sends the result from executing this request. Called by the internal
// implementation, usually a DirectRenderer.
void SendResult(std::unique_ptr<CopyOutputResult> result);
@@ -144,8 +133,6 @@ class VIZ_COMMON_EXPORT CopyOutputRequest {
base::Optional<base::UnguessableToken> source_;
base::Optional<gfx::Rect> area_;
base::Optional<gfx::Rect> result_selection_;
- base::Optional<gpu::Mailbox> mailbox_;
- base::Optional<gpu::SyncToken> sync_token_;
DISALLOW_COPY_AND_ASSIGN(CopyOutputRequest);
};
diff --git a/chromium/components/viz/common/frame_sinks/copy_output_result.cc b/chromium/components/viz/common/frame_sinks/copy_output_result.cc
index 0e71b82219a..0354e37a22c 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_result.cc
+++ b/chromium/components/viz/common/frame_sinks/copy_output_result.cc
@@ -77,6 +77,16 @@ bool CopyOutputResult::ReadI420Planes(uint8_t* y_out,
return false;
}
+bool CopyOutputResult::ReadRGBAPlane(uint8_t* dest, int stride) const {
+ const SkBitmap& bitmap = AsSkBitmap();
+ if (!bitmap.readyToDraw())
+ return false;
+ SkImageInfo image_info = SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
+ kPremul_SkAlphaType);
+ bitmap.readPixels(image_info, dest, stride, 0, 0);
+ return true;
+}
+
CopyOutputSkBitmapResult::CopyOutputSkBitmapResult(const gfx::Rect& rect,
const SkBitmap& bitmap)
: CopyOutputSkBitmapResult(Format::RGBA_BITMAP, rect, bitmap) {}
diff --git a/chromium/components/viz/common/frame_sinks/copy_output_result.h b/chromium/components/viz/common/frame_sinks/copy_output_result.h
index 5e6318c6f3c..2ae0b84452e 100644
--- a/chromium/components/viz/common/frame_sinks/copy_output_result.h
+++ b/chromium/components/viz/common/frame_sinks/copy_output_result.h
@@ -104,6 +104,11 @@ class VIZ_COMMON_EXPORT CopyOutputResult {
uint8_t* v_out,
int v_out_stride) const;
+ // Copies the result of an RGBA_BITMAP into |dest|. The result is in N32Premul
+ // form. Returns true if successful, or false if: 1) the result is empty, or
+ // 2) the result format is not RGBA_BITMAP and conversion is not implemented.
+ virtual bool ReadRGBAPlane(uint8_t* dest, int stride) const;
+
protected:
// Accessor for subclasses to initialize the cached SkBitmap.
SkBitmap* cached_bitmap() const { return &cached_bitmap_; }
diff --git a/chromium/components/viz/common/gl_helper.cc b/chromium/components/viz/common/gl_helper.cc
index efc29c8504e..414d65fe305 100644
--- a/chromium/components/viz/common/gl_helper.cc
+++ b/chromium/components/viz/common/gl_helper.cc
@@ -15,7 +15,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
diff --git a/chromium/components/viz/common/gl_helper_benchmark.cc b/chromium/components/viz/common/gl_helper_benchmark.cc
index 3cbaf0470a3..3cf84a90e38 100644
--- a/chromium/components/viz/common/gl_helper_benchmark.cc
+++ b/chromium/components/viz/common/gl_helper_benchmark.cc
@@ -10,14 +10,14 @@
#include <stddef.h>
#include <stdio.h>
-#include <cmath>
-#include <string>
-#include <vector>
-
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
+#include <cmath>
+#include <string>
+#include <vector>
+
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
@@ -72,7 +72,6 @@ class GLHelperBenchmark : public testing::Test {
nullptr, /* surface */
true, /* offscreen */
gpu::kNullSurfaceHandle, /* window */
- nullptr, /* share_context */
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
nullptr, /* image_factory */
diff --git a/chromium/components/viz/common/gl_helper_scaling.cc b/chromium/components/viz/common/gl_helper_scaling.cc
index 72d81dd3301..acd0203a382 100644
--- a/chromium/components/viz/common/gl_helper_scaling.cc
+++ b/chromium/components/viz/common/gl_helper_scaling.cc
@@ -16,7 +16,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/components/viz/common/gl_helper_unittest.cc b/chromium/components/viz/common/gl_helper_unittest.cc
index f6252192ddb..8a07533d34a 100644
--- a/chromium/components/viz/common/gl_helper_unittest.cc
+++ b/chromium/components/viz/common/gl_helper_unittest.cc
@@ -6,15 +6,18 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
-#include <cmath>
-#include <string>
-#include <tuple>
-#include <vector>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <GLES2/gl2extchromium.h>
+#include <algorithm>
+#include <cmath>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
@@ -67,7 +70,6 @@ class GLHelperTest : public testing::Test {
nullptr, /* surface */
true, /* offscreen */
gpu::kNullSurfaceHandle, /* window */
- nullptr, /* share_context */
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
nullptr, /* image_factory */
diff --git a/chromium/components/viz/common/gpu/DEPS b/chromium/components/viz/common/gpu/DEPS
index 1d4410875ae..f310bed2876 100644
--- a/chromium/components/viz/common/gpu/DEPS
+++ b/chromium/components/viz/common/gpu/DEPS
@@ -4,12 +4,8 @@ include_rules = [
"+cc/output",
"+cc/resources",
"+gpu/command_buffer",
- "+gpu/config/gpu_feature_info.h",
"+gpu/GLES2/gl2extchromium.h",
- "+gpu/ipc",
- "+gpu/skia_bindings",
"+gpu/vulkan",
"+third_party/khronos/GLES2/gl2.h",
- "+third_party/khronos/GLES2/gl2ext.h",
"+third_party/skia/include/gpu",
]
diff --git a/chromium/components/viz/common/gpu/vulkan_context_provider.h b/chromium/components/viz/common/gpu/vulkan_context_provider.h
index ff09c31b745..a4c11f8aad8 100644
--- a/chromium/components/viz/common/gpu/vulkan_context_provider.h
+++ b/chromium/components/viz/common/gpu/vulkan_context_provider.h
@@ -12,6 +12,7 @@ class GrContext;
namespace gpu {
class VulkanDeviceQueue;
+class VulkanImplementation;
}
namespace viz {
@@ -20,6 +21,7 @@ namespace viz {
class VIZ_COMMON_EXPORT VulkanContextProvider
: public base::RefCountedThreadSafe<VulkanContextProvider> {
public:
+ virtual gpu::VulkanImplementation* GetVulkanImplementation() = 0;
virtual gpu::VulkanDeviceQueue* GetDeviceQueue() = 0;
virtual GrContext* GetGrContext() = 0;
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
index 4e023d4e929..8528ee8af9b 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.cc
@@ -4,33 +4,24 @@
#include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
#include "gpu/vulkan/buildflags.h"
-
-#if BUILDFLAG(ENABLE_VULKAN)
+#include "gpu/vulkan/init/vulkan_factory.h"
#include "gpu/vulkan/vulkan_device_queue.h"
#include "gpu/vulkan/vulkan_implementation.h"
#include "third_party/skia/include/gpu/GrContext.h"
#include "third_party/skia/include/gpu/vk/GrVkInterface.h"
-#endif // BUILDFLAG(ENABLE_VULKAN)
namespace viz {
scoped_refptr<VulkanInProcessContextProvider>
-VulkanInProcessContextProvider::Create() {
-#if BUILDFLAG(ENABLE_VULKAN)
- if (!gpu::VulkanSupported())
- return nullptr;
-
+VulkanInProcessContextProvider::Create(
+ gpu::VulkanImplementation* vulkan_implementation) {
scoped_refptr<VulkanInProcessContextProvider> context_provider(
- new VulkanInProcessContextProvider);
+ new VulkanInProcessContextProvider(vulkan_implementation));
if (!context_provider->Initialize())
return nullptr;
return context_provider;
-#else
- return nullptr;
-#endif
}
-#if BUILDFLAG(ENABLE_VULKAN)
GrVkInterface::GetProc make_unified_getter(
const GrVkInterface::GetInstanceProc& iproc,
const GrVkInterface::GetDeviceProc& dproc) {
@@ -42,17 +33,15 @@ GrVkInterface::GetProc make_unified_getter(
return iproc(instance, proc_name);
};
}
-#endif
bool VulkanInProcessContextProvider::Initialize() {
-#if BUILDFLAG(ENABLE_VULKAN)
DCHECK(!device_queue_);
- std::unique_ptr<gpu::VulkanDeviceQueue> device_queue(
- new gpu::VulkanDeviceQueue);
- if (!device_queue->Initialize(
+ std::unique_ptr<gpu::VulkanDeviceQueue> device_queue =
+ gpu::CreateVulkanDeviceQueue(
+ vulkan_implementation_,
gpu::VulkanDeviceQueue::GRAPHICS_QUEUE_FLAG |
- gpu::VulkanDeviceQueue::PRESENTATION_SUPPORT_QUEUE_FLAG)) {
- device_queue->Destroy();
+ gpu::VulkanDeviceQueue::PRESENTATION_SUPPORT_QUEUE_FLAG);
+ if (!device_queue) {
return false;
}
@@ -82,13 +71,9 @@ bool VulkanInProcessContextProvider::Initialize() {
backend_context_.reset(backend_context);
gr_context_ = GrContext::MakeVulkan(backend_context_);
return true;
-#else
- return false;
-#endif
}
void VulkanInProcessContextProvider::Destroy() {
-#if BUILDFLAG(ENABLE_VULKAN)
if (gr_context_)
gr_context_.reset();
@@ -97,26 +82,24 @@ void VulkanInProcessContextProvider::Destroy() {
device_queue_.reset();
backend_context_.reset();
}
-#endif
}
GrContext* VulkanInProcessContextProvider::GetGrContext() {
-#if BUILDFLAG(ENABLE_VULKAN)
return gr_context_.get();
-#else
- return nullptr;
-#endif
+}
+
+gpu::VulkanImplementation*
+VulkanInProcessContextProvider::GetVulkanImplementation() {
+ return vulkan_implementation_;
}
gpu::VulkanDeviceQueue* VulkanInProcessContextProvider::GetDeviceQueue() {
-#if BUILDFLAG(ENABLE_VULKAN)
return device_queue_.get();
-#else
- return nullptr;
-#endif
}
-VulkanInProcessContextProvider::VulkanInProcessContextProvider() {}
+VulkanInProcessContextProvider::VulkanInProcessContextProvider(
+ gpu::VulkanImplementation* vulkan_implementation)
+ : vulkan_implementation_(vulkan_implementation) {}
VulkanInProcessContextProvider::~VulkanInProcessContextProvider() {
Destroy();
diff --git a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
index 2015aa0b449..6a79746f332 100644
--- a/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
+++ b/chromium/components/viz/common/gpu/vulkan_in_process_context_provider.h
@@ -15,6 +15,7 @@
#endif
namespace gpu {
+class VulkanImplementation;
class VulkanDeviceQueue;
}
@@ -23,22 +24,26 @@ namespace viz {
class VIZ_COMMON_EXPORT VulkanInProcessContextProvider
: public VulkanContextProvider {
public:
- static scoped_refptr<VulkanInProcessContextProvider> Create();
+ static scoped_refptr<VulkanInProcessContextProvider> Create(
+ gpu::VulkanImplementation* vulkan_implementation);
bool Initialize();
void Destroy();
GrContext* GetGrContext() override;
// VulkanContextProvider implementation
+ gpu::VulkanImplementation* GetVulkanImplementation() override;
gpu::VulkanDeviceQueue* GetDeviceQueue() override;
protected:
- VulkanInProcessContextProvider();
+ explicit VulkanInProcessContextProvider(
+ gpu::VulkanImplementation* vulkan_implementation);
~VulkanInProcessContextProvider() override;
private:
#if BUILDFLAG(ENABLE_VULKAN)
sk_sp<GrContext> gr_context_;
+ gpu::VulkanImplementation* vulkan_implementation_;
std::unique_ptr<gpu::VulkanDeviceQueue> device_queue_;
sk_sp<GrVkBackendContext> backend_context_;
#endif
diff --git a/chromium/components/viz/common/hit_test/DEPS b/chromium/components/viz/common/hit_test/DEPS
new file mode 100644
index 00000000000..16764a92a85
--- /dev/null
+++ b/chromium/components/viz/common/hit_test/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+mojo/public/cpp/bindings",
+]
diff --git a/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h b/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
index 9fb48ff47b5..42476fe1fcd 100644
--- a/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
+++ b/chromium/components/viz/common/hit_test/aggregated_hit_test_region.h
@@ -7,12 +7,17 @@
#include <stdint.h>
-#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"
namespace viz {
+namespace mojom {
+class AggregatedHitTestRegionDataView;
+}
+
// A AggregatedHitTestRegion element with child_count of kEndOfList indicates
// the last element and end of the list.
constexpr int32_t kEndOfList = -1;
@@ -24,10 +29,12 @@ constexpr int32_t kEndOfList = -1;
// write the hit_test data, and the viz host can read without
// process hops.
struct AggregatedHitTestRegion {
- AggregatedHitTestRegion(FrameSinkId frame_sink_id,
+ AggregatedHitTestRegion() = default;
+
+ AggregatedHitTestRegion(const FrameSinkId& frame_sink_id,
uint32_t flags,
- gfx::Rect rect,
- gfx::Transform transform,
+ const gfx::Rect& rect,
+ const gfx::Transform& transform,
int32_t child_count)
: frame_sink_id(frame_sink_id),
flags(flags),
@@ -39,9 +46,8 @@ struct AggregatedHitTestRegion {
// are routed to this surface.
FrameSinkId frame_sink_id;
- // Flags to indicate the type of region as defined for
- // mojom::HitTestRegion
- uint32_t flags;
+ // HitTestRegionFlags to indicate the type of region.
+ uint32_t flags = 0;
// The rectangle that defines the region in parent region's coordinate space.
gfx::Rect rect;
@@ -49,7 +55,7 @@ struct AggregatedHitTestRegion {
// The number of children including their children below this entry.
// If this element is not matched then child_count elements can be skipped
// to move to the next entry.
- int32_t child_count;
+ int32_t child_count = 0;
// gfx::Transform is backed by SkMatrix44. SkMatrix44 has a mutable attribute
// which can be changed even during a const function call (e.g.
@@ -68,6 +74,9 @@ struct AggregatedHitTestRegion {
}
private:
+ friend struct mojo::StructTraits<mojom::AggregatedHitTestRegionDataView,
+ AggregatedHitTestRegion>;
+
// The transform applied to the rect in parent region's coordinate space.
gfx::Transform transform_;
};
diff --git a/chromium/components/viz/common/hit_test/hit_test_region_list.cc b/chromium/components/viz/common/hit_test/hit_test_region_list.cc
new file mode 100644
index 00000000000..62887c1b925
--- /dev/null
+++ b/chromium/components/viz/common/hit_test/hit_test_region_list.cc
@@ -0,0 +1,15 @@
+// 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 "components/viz/common/hit_test/hit_test_region_list.h"
+
+namespace viz {
+
+HitTestRegionList::HitTestRegionList() = default;
+HitTestRegionList::~HitTestRegionList() = default;
+
+HitTestRegionList::HitTestRegionList(HitTestRegionList&&) = default;
+HitTestRegionList& HitTestRegionList::operator=(HitTestRegionList&&) = default;
+
+} // namespace viz
diff --git a/chromium/components/viz/common/hit_test/hit_test_region_list.h b/chromium/components/viz/common/hit_test/hit_test_region_list.h
new file mode 100644
index 00000000000..64d33806fde
--- /dev/null
+++ b/chromium/components/viz/common/hit_test/hit_test_region_list.h
@@ -0,0 +1,76 @@
+// 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 COMPONENTS_VIZ_COMMON_HIT_TEST_HIT_TEST_REGION_LIST_H_
+#define COMPONENTS_VIZ_COMMON_HIT_TEST_HIT_TEST_REGION_LIST_H_
+
+#include <vector>
+
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/common/viz_common_export.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/transform.h"
+
+namespace viz {
+
+struct HitTestRegionFlags {
+ // Region maps to this surface (me).
+ enum : uint32_t { kHitTestMine = 0x01 };
+ // Region ignored for hit testing (transparent backgrounds & hover:none).
+ enum : uint32_t { kHitTestIgnore = 0x02 };
+ // Region maps to child surface (OOPIF).
+ enum : uint32_t { kHitTestChildSurface = 0x04 };
+ // Irregular boundary - send HitTestRequest to resolve.
+ enum : uint32_t { kHitTestAsk = 0x08 };
+
+ // TODO(varkha): Add other kHitTest* flags as necessary for other event
+ // sources such as mouse-wheel, stylus or perhaps even mouse-move.
+
+ // Hit-testing for mouse events.
+ enum : uint32_t { kHitTestMouse = 0x10 };
+ // Hit-testing for touch events.
+ enum : uint32_t { kHitTestTouch = 0x20 };
+};
+
+struct HitTestRegion {
+ // HitTestRegionFlags to indicate the type of HitTestRegion.
+ uint32_t flags = 0;
+
+ // FrameSinkId of this region.
+ FrameSinkId frame_sink_id;
+
+ // The rect of the region in the coordinate space of the embedder.
+ gfx::Rect rect;
+
+ // The transform of the region. The transform applied to the rect
+ // defines the space occupied by this region in the coordinate space of
+ // the embedder.
+ gfx::Transform transform;
+};
+
+struct VIZ_COMMON_EXPORT HitTestRegionList {
+ HitTestRegionList();
+ ~HitTestRegionList();
+
+ HitTestRegionList(HitTestRegionList&&);
+ HitTestRegionList& operator=(HitTestRegionList&&);
+
+ // HitTestRegionFlags indicate how to handle events that match no sub-regions.
+ // kHitTestMine routes un-matched events to this surface (opaque).
+ // kHitTestIgnore keeps previous match in the parent (transparent).
+ uint32_t flags = 0;
+
+ // The bounds of the surface.
+ gfx::Rect bounds;
+
+ // The transform applied to all regions in this surface.
+ gfx::Transform transform;
+
+ // The list of sub-regions in front to back order.
+ std::vector<HitTestRegion> regions;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_HIT_TEST_HIT_TEST_REGION_LIST_H_
diff --git a/chromium/components/viz/common/quads/draw_quad_unittest.cc b/chromium/components/viz/common/quads/draw_quad_unittest.cc
index c225a7cac25..34be8a3f6c0 100644
--- a/chromium/components/viz/common/quads/draw_quad_unittest.cc
+++ b/chromium/components/viz/common/quads/draw_quad_unittest.cc
@@ -396,6 +396,7 @@ TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
float resource_multiplier = 2.001f;
uint32_t bits_per_channel = 5;
bool require_overlay = true;
+ bool is_protected_video = true;
gfx::ColorSpace video_color_space = gfx::ColorSpace::CreateJpeg();
CREATE_SHARED_STATE();
@@ -419,12 +420,13 @@ TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
EXPECT_EQ(resource_multiplier, copy_quad->resource_multiplier);
EXPECT_EQ(bits_per_channel, copy_quad->bits_per_channel);
EXPECT_FALSE(copy_quad->require_overlay);
+ EXPECT_FALSE(copy_quad->is_protected_video);
CREATE_QUAD_ALL(YUVVideoDrawQuad, ya_tex_coord_rect, uv_tex_coord_rect,
ya_tex_size, uv_tex_size, y_plane_resource_id,
u_plane_resource_id, v_plane_resource_id, a_plane_resource_id,
video_color_space, resource_offset, resource_multiplier,
- bits_per_channel, require_overlay);
+ bits_per_channel, require_overlay, is_protected_video);
EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
EXPECT_EQ(uv_tex_coord_rect, copy_quad->uv_tex_coord_rect);
@@ -438,6 +440,7 @@ TEST(DrawQuadTest, CopyYUVVideoDrawQuad) {
EXPECT_EQ(resource_multiplier, copy_quad->resource_multiplier);
EXPECT_EQ(bits_per_channel, copy_quad->bits_per_channel);
EXPECT_EQ(require_overlay, copy_quad->require_overlay);
+ EXPECT_EQ(is_protected_video, copy_quad->is_protected_video);
}
TEST(DrawQuadTest, CopyPictureDrawQuad) {
diff --git a/chromium/components/viz/common/quads/yuv_video_draw_quad.cc b/chromium/components/viz/common/quads/yuv_video_draw_quad.cc
index fb7e5fc9e84..91254b359a9 100644
--- a/chromium/components/viz/common/quads/yuv_video_draw_quad.cc
+++ b/chromium/components/viz/common/quads/yuv_video_draw_quad.cc
@@ -66,7 +66,8 @@ void YUVVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
float offset,
float multiplier,
uint32_t bits_per_channel,
- bool require_overlay) {
+ bool require_overlay,
+ bool is_protected_video) {
DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
visible_rect, needs_blending);
this->ya_tex_coord_rect = ya_tex_coord_rect;
@@ -83,6 +84,7 @@ void YUVVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
this->resource_multiplier = multiplier;
this->bits_per_channel = bits_per_channel;
this->require_overlay = require_overlay;
+ this->is_protected_video = is_protected_video;
}
const YUVVideoDrawQuad* YUVVideoDrawQuad::MaterialCast(const DrawQuad* quad) {
@@ -105,6 +107,7 @@ void YUVVideoDrawQuad::ExtendValue(
value->SetInteger("a_plane_resource_id",
resources.ids[kAPlaneResourceIdIndex]);
value->SetBoolean("require_overlay", require_overlay);
+ value->SetBoolean("is_protected_video", is_protected_video);
}
} // namespace viz
diff --git a/chromium/components/viz/common/quads/yuv_video_draw_quad.h b/chromium/components/viz/common/quads/yuv_video_draw_quad.h
index dba0551f641..82ff32ca747 100644
--- a/chromium/components/viz/common/quads/yuv_video_draw_quad.h
+++ b/chromium/components/viz/common/quads/yuv_video_draw_quad.h
@@ -70,7 +70,8 @@ class VIZ_COMMON_EXPORT YUVVideoDrawQuad : public DrawQuad {
float offset,
float multiplier,
uint32_t bits_per_channel,
- bool require_overlay);
+ bool require_overlay,
+ bool is_protected_video);
gfx::RectF ya_tex_coord_rect;
gfx::RectF uv_tex_coord_rect;
@@ -82,6 +83,7 @@ class VIZ_COMMON_EXPORT YUVVideoDrawQuad : public DrawQuad {
// TODO(hubbe): Move to ResourceProvider::ScopedSamplerGL.
gfx::ColorSpace video_color_space;
bool require_overlay = false;
+ bool is_protected_video = false;
static const YUVVideoDrawQuad* MaterialCast(const DrawQuad*);
diff --git a/chromium/components/viz/common/resources/platform_color.h b/chromium/components/viz/common/resources/platform_color.h
index 5a6caba510d..6bf22ad88b4 100644
--- a/chromium/components/viz/common/resources/platform_color.h
+++ b/chromium/components/viz/common/resources/platform_color.h
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "components/viz/common/resources/resource_format.h"
+#include "gpu/command_buffer/common/capabilities.h"
#include "third_party/skia/include/core/SkTypes.h"
namespace viz {
@@ -20,11 +21,13 @@ class PlatformColor {
return SK_B32_SHIFT ? SOURCE_FORMAT_RGBA8 : SOURCE_FORMAT_BGRA8;
}
- // Returns the most efficient texture format for this platform.
- static ResourceFormat BestTextureFormat() {
+ // Returns the most efficient supported format for textures that will be
+ // software-generated and uploaded via TexImage2D et al.
+ static ResourceFormat BestSupportedTextureFormat(
+ const gpu::Capabilities& caps) {
switch (Format()) {
case SOURCE_FORMAT_BGRA8:
- return BGRA_8888;
+ return (caps.texture_format_bgra8888) ? BGRA_8888 : RGBA_8888;
case SOURCE_FORMAT_RGBA8:
return RGBA_8888;
}
@@ -32,11 +35,13 @@ class PlatformColor {
return RGBA_8888;
}
- // Returns the most efficient supported texture format for this platform.
- static ResourceFormat BestSupportedTextureFormat(bool supports_bgra8888) {
+ // Returns the most efficient supported format for textures that will be
+ // rastered in the gpu (bound as a framebuffer and drawn to).
+ static ResourceFormat BestSupportedRenderBufferFormat(
+ const gpu::Capabilities& caps) {
switch (Format()) {
case SOURCE_FORMAT_BGRA8:
- return (supports_bgra8888) ? BGRA_8888 : RGBA_8888;
+ return (caps.render_buffer_format_bgra8888) ? BGRA_8888 : RGBA_8888;
case SOURCE_FORMAT_RGBA8:
return RGBA_8888;
}
@@ -44,25 +49,27 @@ class PlatformColor {
return RGBA_8888;
}
- // Return true if the given 32bpp resource format has the same component order
- // as the platform color data format.
+ // Return true if the given resource format has the same component order
+ // as the platform color data format. Only supports formats that the
+ // compositor can use for software raster.
static bool SameComponentOrder(ResourceFormat format) {
switch (format) {
case RGBA_8888:
return Format() == SOURCE_FORMAT_RGBA8;
case BGRA_8888:
return Format() == SOURCE_FORMAT_BGRA8;
+ case RGBA_4444:
+ return true;
+
case ALPHA_8:
case LUMINANCE_8:
case RGB_565:
- case RGBA_4444:
case ETC1:
case RED_8:
case LUMINANCE_F16:
case RGBA_F16:
case R16_EXT:
- NOTREACHED();
- return false;
+ break;
}
NOTREACHED();
diff --git a/chromium/components/viz/common/resources/resource.cc b/chromium/components/viz/common/resources/resource.cc
index 42d3ae2ef7e..2597163d010 100644
--- a/chromium/components/viz/common/resources/resource.cc
+++ b/chromium/components/viz/common/resources/resource.cc
@@ -6,22 +6,16 @@
#include "build/build_config.h"
#include "components/viz/common/quads/shared_bitmap.h"
-#include "ui/gfx/gpu_memory_buffer.h"
namespace viz {
namespace internal {
Resource::Resource(const gfx::Size& size,
- Origin origin,
- ResourceTextureHint hint,
ResourceType type,
ResourceFormat format,
const gfx::ColorSpace& color_space)
- : locked_for_write(false),
- locked_for_external_use(false),
- lost(false),
+ : locked_for_external_use(false),
marked_for_deletion(false),
- allocated(false),
read_lock_fences_enabled(false),
has_shared_bitmap_id(false),
is_overlay_candidate(false),
@@ -30,8 +24,6 @@ Resource::Resource(const gfx::Size& size,
wants_promotion_hint(false),
#endif
size(size),
- origin(origin),
- hint(hint),
type(type),
format(format),
color_space(color_space) {
@@ -44,7 +36,6 @@ Resource& Resource::operator=(Resource&& other) = default;
void Resource::SetSharedBitmap(SharedBitmap* bitmap) {
DCHECK(bitmap);
DCHECK(bitmap->pixels());
- allocated = true;
shared_bitmap = bitmap;
pixels = bitmap->pixels();
has_shared_bitmap_id = true;
@@ -76,13 +67,5 @@ bool Resource::ShouldWaitSyncToken() const {
return synchronization_state_ == NEEDS_WAIT;
}
-void Resource::SetGenerateMipmap() {
- DCHECK(is_gpu_resource_type());
- DCHECK_EQ(target, static_cast<GLenum>(GL_TEXTURE_2D));
- DCHECK(hint & ResourceTextureHint::kMipmap);
- DCHECK(!gpu_memory_buffer);
- mipmap_state = GENERATE;
-}
-
} // namespace internal
} // namespace viz
diff --git a/chromium/components/viz/common/resources/resource.h b/chromium/components/viz/common/resources/resource.h
index 82bef3a0c62..5fc1841b6aa 100644
--- a/chromium/components/viz/common/resources/resource.h
+++ b/chromium/components/viz/common/resources/resource.h
@@ -13,7 +13,6 @@
#include "components/viz/common/resources/resource_fence.h"
#include "components/viz/common/resources/resource_format.h"
#include "components/viz/common/resources/resource_id.h"
-#include "components/viz/common/resources/resource_texture_hint.h"
#include "components/viz/common/resources/resource_type.h"
#include "components/viz/common/viz_common_export.h"
#include "gpu/command_buffer/common/mailbox.h"
@@ -36,7 +35,6 @@ namespace internal {
// for client and service libraries and should not be used directly from
// external client code.
struct VIZ_COMMON_EXPORT Resource {
- enum Origin { INTERNAL, DELEGATED };
enum SynchronizationState {
// The LOCALLY_USED state is the state each resource defaults to when
// constructed or modified or read. This state indicates that the
@@ -66,11 +64,8 @@ struct VIZ_COMMON_EXPORT Resource {
// external resource for others to wait on.
SYNCHRONIZED,
};
- enum MipmapState { INVALID, GENERATE, VALID };
Resource(const gfx::Size& size,
- Origin origin,
- ResourceTextureHint hint,
ResourceType type,
ResourceFormat format,
const gfx::ColorSpace& color_space);
@@ -103,21 +98,12 @@ struct VIZ_COMMON_EXPORT Resource {
// SyncToken waited on in order to be synchronized for use.
bool ShouldWaitSyncToken() const;
int8_t* GetSyncTokenData();
- void SetGenerateMipmap();
// Bitfield flags. ======
- // When true, the resource is currently being written to. Used to prevent
- // misuse while the resource is being modified.
- bool locked_for_write : 1;
// When true, the resource is currently being used externally.
bool locked_for_external_use : 1;
- // When true the resource can not be used and must only be deleted. This is
- // passed along to the |release_callback|.
- bool lost : 1;
// When the resource should be deleted until it is actually reaped.
bool marked_for_deletion : 1;
- // When false, the resource backing hasn't been allocated yet.
- bool allocated : 1;
// Tracks if a gpu fence needs to be used for reading a GpuMemoryBuffer-
// backed or texture-backed resource.
bool read_lock_fences_enabled : 1;
@@ -159,7 +145,6 @@ struct VIZ_COMMON_EXPORT Resource {
// of the resource.
int lock_for_read_count = 0;
int imported_count = 0;
- int exported_count = 0;
// A fence used for accessing a GpuMemoryBuffer-backed or texture-backed
// resource for reading, that ensures any writing done to the resource has
// been completed. This is implemented and used to implement transferring
@@ -168,10 +153,6 @@ struct VIZ_COMMON_EXPORT Resource {
scoped_refptr<ResourceFence> read_lock_fence;
// Size of the resource in pixels.
gfx::Size size;
- // Where the resource was originally allocated. Either internally by the
- // ResourceProvider instance, or in a client and given to the ResourceProvider
- // via IPC.
- Origin origin = INTERNAL;
// The texture target for GpuMemoryBuffer- and texture-backed resources.
GLenum target = GL_TEXTURE_2D;
// The min/mag filter of the resource when it was given to/created by the
@@ -184,16 +165,8 @@ struct VIZ_COMMON_EXPORT Resource {
GLenum filter = GL_LINEAR;
// The current min filter for GpuMemoryBuffer- and texture-backed resources.
GLenum min_filter = GL_LINEAR;
- // The GL image id for GpuMemoryBuffer-backed resources.
- GLuint image_id = 0;
- // A hint for texture-backed resources about how the resource will be used,
- // that dictates how it should be allocated/used.
- ResourceTextureHint hint = ResourceTextureHint::kDefault;
// The type of backing for the resource (such as gpu vs software).
ResourceType type = ResourceType::kBitmap;
- // GpuMemoryBuffer resource allocation needs to know how the resource will
- // be used.
- gfx::BufferUsage usage = gfx::BufferUsage::GPU_READ_CPU_READ_WRITE;
// This is the the actual format of the underlying GpuMemoryBuffer, if any,
// and might not correspond to ResourceFormat. This format is needed to
// allocate the GpuMemoryBuffer and scanout the buffer as a hardware overlay.
@@ -212,13 +185,9 @@ struct VIZ_COMMON_EXPORT Resource {
SharedBitmap* shared_bitmap = nullptr;
// Ownership of |shared_bitmap| for when it is created internally.
std::unique_ptr<SharedBitmap> owned_shared_bitmap;
- // The GpuMemoryBuffer ownership for GpuMemoryBuffer-backed resources.
- std::unique_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer;
// The color space for all resource types, to control how the resource should
// be drawn to output device.
gfx::ColorSpace color_space;
- // Used to track generating mipmaps for texture-backed resources.
- MipmapState mipmap_state = INVALID;
private:
// Tracks if a sync token needs to be waited on before using the resource.
diff --git a/chromium/components/viz/common/resources/resource_format_utils.cc b/chromium/components/viz/common/resources/resource_format_utils.cc
index a7c072f5215..dcf5d8d7667 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.cc
+++ b/chromium/components/viz/common/resources/resource_format_utils.cc
@@ -12,7 +12,15 @@
namespace viz {
-SkColorType ResourceFormatToClosestSkColorType(ResourceFormat format) {
+SkColorType ResourceFormatToClosestSkColorType(bool gpu_compositing,
+ ResourceFormat format) {
+ if (!gpu_compositing) {
+ // In software compositing we lazily use RGBA_8888 throughout the system,
+ // but actual pixel encodings are the native skia bit ordering, which can be
+ // RGBA or BGRA.
+ return kN32_SkColorType;
+ }
+
// Use kN32_SkColorType if there is no corresponding SkColorType.
switch (format) {
case RGBA_4444:
@@ -171,26 +179,6 @@ bool IsResourceFormatCompressed(ResourceFormat format) {
return format == ETC1;
}
-bool DoesResourceFormatSupportAlpha(ResourceFormat format) {
- switch (format) {
- case RGBA_4444:
- case RGBA_8888:
- case BGRA_8888:
- case ALPHA_8:
- case RGBA_F16:
- return true;
- case LUMINANCE_8:
- case RGB_565:
- case ETC1:
- case RED_8:
- case LUMINANCE_F16:
- case R16_EXT:
- return false;
- }
- NOTREACHED();
- return false;
-}
-
unsigned int TextureStorageFormat(ResourceFormat format) {
switch (format) {
case RGBA_8888:
diff --git a/chromium/components/viz/common/resources/resource_format_utils.h b/chromium/components/viz/common/resources/resource_format_utils.h
index 5d6b4101c40..27957f65517 100644
--- a/chromium/components/viz/common/resources/resource_format_utils.h
+++ b/chromium/components/viz/common/resources/resource_format_utils.h
@@ -14,7 +14,7 @@
namespace viz {
VIZ_RESOURCE_FORMAT_EXPORT SkColorType
-ResourceFormatToClosestSkColorType(ResourceFormat format);
+ResourceFormatToClosestSkColorType(bool gpu_compositing, ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT int BitsPerPixel(ResourceFormat format);
// The following functions use unsigned int instead of GLenum, since including
@@ -35,8 +35,6 @@ VIZ_RESOURCE_FORMAT_EXPORT gfx::BufferFormat BufferFormat(
ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT bool IsResourceFormatCompressed(
ResourceFormat format);
-VIZ_RESOURCE_FORMAT_EXPORT bool DoesResourceFormatSupportAlpha(
- ResourceFormat format);
VIZ_RESOURCE_FORMAT_EXPORT unsigned int TextureStorageFormat(
ResourceFormat format);
diff --git a/chromium/components/viz/common/resources/resource_settings.h b/chromium/components/viz/common/resources/resource_settings.h
index 434f9605c5a..ed2e5b0418a 100644
--- a/chromium/components/viz/common/resources/resource_settings.h
+++ b/chromium/components/viz/common/resources/resource_settings.h
@@ -21,8 +21,7 @@ class VIZ_COMMON_EXPORT ResourceSettings {
~ResourceSettings();
bool use_gpu_memory_buffer_resources = false;
- bool high_bit_for_testing = false;
- // TODO(riju): Remove after r16 is used without the flag. crbug.com/759456
+ // TODO(crbug.com/759456): Remove after r16 is used without the flag.
bool use_r16_texture = false;
};
diff --git a/chromium/components/viz/common/resources/resource_sizes_unittest.cc b/chromium/components/viz/common/resources/resource_sizes_unittest.cc
new file mode 100644
index 00000000000..06fe461faee
--- /dev/null
+++ b/chromium/components/viz/common/resources/resource_sizes_unittest.cc
@@ -0,0 +1,170 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "base/logging.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+struct TestFormat {
+ ResourceFormat format;
+ size_t expected_bytes;
+ size_t expected_bytes_aligned;
+};
+
+// Modify this constant as per TestFormat variables defined in following tests.
+const int kTestFormats = 4;
+
+class ResourceUtilTest : public testing::Test {
+ public:
+ void TestVerifyWidthInBytes(int width, const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ EXPECT_TRUE(ResourceSizes::VerifyWidthInBytes<size_t>(
+ width, test_formats[i].format));
+ }
+ }
+
+ void TestCheckedWidthInBytes(int width, const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceSizes::CheckedWidthInBytes<size_t>(
+ width, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedWidthInBytes(int width, const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceSizes::UncheckedWidthInBytes<size_t>(
+ width, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedWidthInBytesAligned(int width,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceSizes::UncheckedWidthInBytesAligned<size_t>(
+ width, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
+ }
+ }
+
+ void TestVerifySizeInBytes(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ EXPECT_TRUE(ResourceSizes::VerifySizeInBytes<size_t>(
+ size, test_formats[i].format));
+ }
+ }
+
+ void TestCheckedSizeInBytes(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceSizes::CheckedSizeInBytes<size_t>(
+ size, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedSizeInBytes(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceSizes::UncheckedSizeInBytes<size_t>(
+ size, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes);
+ }
+ }
+
+ void TestUncheckedSizeInBytesAligned(const gfx::Size& size,
+ const TestFormat* test_formats) {
+ for (int i = 0; i < kTestFormats; ++i) {
+ size_t bytes = ResourceSizes::UncheckedSizeInBytesAligned<size_t>(
+ size, test_formats[i].format);
+ EXPECT_EQ(bytes, test_formats[i].expected_bytes_aligned);
+ }
+ }
+};
+
+TEST_F(ResourceUtilTest, WidthInBytes) {
+ // Check bytes for even width.
+ int width = 10;
+ TestFormat test_formats[] = {
+ {RGBA_8888, 40, 40}, // for 32 bits
+ {RGBA_4444, 20, 20}, // for 16 bits
+ {ALPHA_8, 10, 12}, // for 8 bits
+ {ETC1, 5, 8} // for 4 bits
+ };
+
+ TestVerifyWidthInBytes(width, test_formats);
+ TestCheckedWidthInBytes(width, test_formats);
+ TestUncheckedWidthInBytes(width, test_formats);
+ TestUncheckedWidthInBytesAligned(width, test_formats);
+
+ // Check bytes for odd width.
+ int width_odd = 11;
+ TestFormat test_formats_odd[] = {
+ {RGBA_8888, 44, 44}, // for 32 bits
+ {RGBA_4444, 22, 24}, // for 16 bits
+ {ALPHA_8, 11, 12}, // for 8 bits
+ {ETC1, 6, 8} // for 4 bits
+ };
+
+ TestVerifyWidthInBytes(width_odd, test_formats_odd);
+ TestCheckedWidthInBytes(width_odd, test_formats_odd);
+ TestUncheckedWidthInBytes(width_odd, test_formats_odd);
+ TestUncheckedWidthInBytesAligned(width_odd, test_formats_odd);
+}
+
+TEST_F(ResourceUtilTest, SizeInBytes) {
+ // Check bytes for even size.
+ gfx::Size size(10, 10);
+ TestFormat test_formats[] = {
+ {RGBA_8888, 400, 400}, // for 32 bits
+ {RGBA_4444, 200, 200}, // for 16 bits
+ {ALPHA_8, 100, 120}, // for 8 bits
+ {ETC1, 50, 80} // for 4 bits
+ };
+
+ TestVerifySizeInBytes(size, test_formats);
+ TestCheckedSizeInBytes(size, test_formats);
+ TestUncheckedSizeInBytes(size, test_formats);
+ TestUncheckedSizeInBytesAligned(size, test_formats);
+
+ // Check bytes for odd size.
+ gfx::Size size_odd(11, 11);
+ TestFormat test_formats_odd[] = {
+ {RGBA_8888, 484, 484}, // for 32 bits
+ {RGBA_4444, 242, 264}, // for 16 bits
+ {ALPHA_8, 121, 132}, // for 8 bits
+ {ETC1, 66, 88} // for 4 bits
+ };
+
+ TestVerifySizeInBytes(size_odd, test_formats_odd);
+ TestCheckedSizeInBytes(size_odd, test_formats_odd);
+ TestUncheckedSizeInBytes(size_odd, test_formats_odd);
+ TestUncheckedSizeInBytesAligned(size_odd, test_formats_odd);
+}
+
+TEST_F(ResourceUtilTest, WidthInBytesOverflow) {
+ int width = 10;
+ // 10 * 16 = 160 bits, overflows in char, but fits in unsigned char.
+ EXPECT_FALSE(
+ ResourceSizes::VerifyWidthInBytes<signed char>(width, RGBA_4444));
+ EXPECT_TRUE(
+ ResourceSizes::VerifyWidthInBytes<unsigned char>(width, RGBA_4444));
+}
+
+TEST_F(ResourceUtilTest, SizeInBytesOverflow) {
+ gfx::Size size(10, 10);
+ // 10 * 16 * 10 = 1600 bits, overflows in char, but fits in int.
+ EXPECT_FALSE(ResourceSizes::VerifySizeInBytes<signed char>(size, RGBA_4444));
+ EXPECT_TRUE(ResourceSizes::VerifySizeInBytes<int>(size, RGBA_4444));
+}
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/common/resources/resource_texture_hint.h b/chromium/components/viz/common/resources/resource_texture_hint.h
deleted file mode 100644
index 40a63222ac0..00000000000
--- a/chromium/components/viz/common/resources/resource_texture_hint.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_TEXTURE_HINT_H_
-#define COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_TEXTURE_HINT_H_
-
-namespace viz {
-
-// A hint for how a resource will be used that is created for sharing
-// with the viz compositing service.
-struct ResourceTextureHint {
- enum {
- kDefault = 0,
- kMipmap = 1 << 0,
- kFramebuffer = 1 << 1,
- kOverlay = 1 << 2,
- };
-
- ResourceTextureHint() : value_(kDefault) {}
-
- // Acts like an enum (via the char type).
- ResourceTextureHint(char i) : value_(i) {} // NOLINT
- operator char() const { return value_; }
-
- ResourceTextureHint& operator|=(const ResourceTextureHint& o) {
- value_ |= o.value_;
- return *this;
- }
-
- private:
- char value_;
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RESOURCE_TEXTURE_HINT_H_
diff --git a/chromium/components/viz/common/resources/resource_type.h b/chromium/components/viz/common/resources/resource_type.h
index fcb339dc8d0..a9f8ae35ec2 100644
--- a/chromium/components/viz/common/resources/resource_type.h
+++ b/chromium/components/viz/common/resources/resource_type.h
@@ -9,7 +9,6 @@ namespace viz {
// Types of resources that can be sent to the viz compositing service.
enum class ResourceType {
- kGpuMemoryBuffer,
kTexture,
kBitmap,
};
diff --git a/chromium/components/viz/common/resources/return_callback.h b/chromium/components/viz/common/resources/return_callback.h
new file mode 100644
index 00000000000..c0ae0a1235d
--- /dev/null
+++ b/chromium/components/viz/common/resources/return_callback.h
@@ -0,0 +1,18 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_COMMON_RESOURCES_RETURN_CALLBACK_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_RETURN_CALLBACK_H_
+
+#include "base/callback.h"
+#include "components/viz/common/resources/returned_resource.h"
+
+namespace viz {
+
+using ReturnCallback =
+ base::RepeatingCallback<void(const std::vector<ReturnedResource>&)>;
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_RETURN_CALLBACK_H_
diff --git a/chromium/components/viz/common/resources/shared_bitmap_manager.h b/chromium/components/viz/common/resources/shared_bitmap_manager.h
index 1975daa3f85..0aefd3533dc 100644
--- a/chromium/components/viz/common/resources/shared_bitmap_manager.h
+++ b/chromium/components/viz/common/resources/shared_bitmap_manager.h
@@ -19,19 +19,6 @@ class SharedBitmapManager {
SharedBitmapManager() {}
virtual ~SharedBitmapManager() {}
- // Allocate a shared bitmap that can be given to the display compositor.
- virtual std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
- const gfx::Size&,
- ResourceFormat) = 0;
-
- // The following methods are only used by the display compositor, but are on
- // the base interface in order to allow tests (or prod) to implement the
- // display and client implementations with the same type, in lieu of having
- // the ServerSharedBitmapManager and ClientSharedBitmapManager be separate
- // interfaces instead of this single one.
- // TODO(crbug.com/730660): Intent is to remove the ClientSharedBitmapManager
- // over time, and make SharedBitmapManager a display-compositor-only concept.
-
// Used in the display compositor to find the bitmap associated with an id.
virtual std::unique_ptr<SharedBitmap> GetSharedBitmapFromId(
const gfx::Size&,
diff --git a/chromium/components/password_manager/public/interfaces/sync_password_data.mojom b/chromium/components/viz/common/resources/shared_bitmap_reporter.cc
index d96090e3b34..fcd80364869 100644
--- a/chromium/components/password_manager/public/interfaces/sync_password_data.mojom
+++ b/chromium/components/viz/common/resources/shared_bitmap_reporter.cc
@@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-module password_manager.mojom;
-
-// Mirror of SyncPasswordData in Mojo.
-struct SyncPasswordData {
- uint32 length;
- string salt;
- uint64 hash;
- bool force_update;
-};
+#include "components/viz/common/resources/shared_bitmap_reporter.h"
+
+namespace viz {
+
+SharedBitmapReporter::~SharedBitmapReporter() = default;
+
+} // namespace viz
diff --git a/chromium/components/viz/common/resources/shared_bitmap_reporter.h b/chromium/components/viz/common/resources/shared_bitmap_reporter.h
new file mode 100644
index 00000000000..2494a2f004b
--- /dev/null
+++ b/chromium/components/viz/common/resources/shared_bitmap_reporter.h
@@ -0,0 +1,34 @@
+// 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 COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_BITMAP_REPORTER_H_
+#define COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_BITMAP_REPORTER_H_
+
+#include "components/viz/common/quads/shared_bitmap.h"
+#include "components/viz/common/viz_common_export.h"
+#include "mojo/public/cpp/system/buffer.h"
+
+namespace viz {
+
+// Used by clients to notify the display compositor about SharedMemory allocated
+// for shared bitmaps.
+// TODO(kylechar): This should be //components/viz/client but because of deps
+// issues that isn't possible. Fix and move there.
+class VIZ_COMMON_EXPORT SharedBitmapReporter {
+ public:
+ // Associates a SharedBitmapId with a shared buffer handle.
+ virtual void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ const SharedBitmapId& id) = 0;
+
+ // Disassociates a SharedBitmapId previously passed to
+ // DidAllocateSharedBitmap.
+ virtual void DidDeleteSharedBitmap(const SharedBitmapId& id) = 0;
+
+ protected:
+ virtual ~SharedBitmapReporter();
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_COMMON_RESOURCES_SHARED_BITMAP_REPORTER_H_
diff --git a/chromium/components/viz/common/resources/transferable_resource.h b/chromium/components/viz/common/resources/transferable_resource.h
index 36abdba6a36..fafb1770c86 100644
--- a/chromium/components/viz/common/resources/transferable_resource.h
+++ b/chromium/components/viz/common/resources/transferable_resource.h
@@ -35,13 +35,11 @@ struct VIZ_COMMON_EXPORT TransferableResource {
const std::vector<TransferableResource>& input);
static TransferableResource MakeSoftware(const SharedBitmapId& id,
- uint32_t sequence_number,
const gfx::Size& size,
ResourceFormat format) {
TransferableResource r;
r.is_software = true;
r.mailbox_holder.mailbox = id;
- r.shared_bitmap_sequence_number = sequence_number;
r.size = size;
r.format = format;
return r;
@@ -113,10 +111,6 @@ struct VIZ_COMMON_EXPORT TransferableResource {
// The color space of the pixels in the resource.
gfx::ColorSpace color_space;
- // Sequence number for the shared bitmap in software resources, used for
- // synchronization to not display the bitmap before it is ready.
- uint32_t shared_bitmap_sequence_number = 0;
-
// A gpu resource may be possible to use directly in an overlay if this is
// true.
bool is_overlay_candidate = false;
@@ -150,7 +144,6 @@ struct VIZ_COMMON_EXPORT TransferableResource {
mailbox_holder.sync_token == o.mailbox_holder.sync_token &&
mailbox_holder.texture_target == o.mailbox_holder.texture_target &&
color_space == o.color_space &&
- shared_bitmap_sequence_number == o.shared_bitmap_sequence_number &&
is_overlay_candidate == o.is_overlay_candidate &&
filter == o.filter &&
#if defined(OS_ANDROID)
diff --git a/chromium/components/viz/common/skia_helper.cc b/chromium/components/viz/common/skia_helper.cc
index 151f5523aba..65d12b59bce 100644
--- a/chromium/components/viz/common/skia_helper.cc
+++ b/chromium/components/viz/common/skia_helper.cc
@@ -4,6 +4,7 @@
#include "components/viz/common/skia_helper.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
#include "ui/gfx/skia_util.h"
namespace viz {
@@ -47,7 +48,7 @@ sk_sp<SkImage> SkiaHelper::ApplyImageFilter(sk_sp<SkImage> src_image,
// Force a flush of the Skia pipeline before we switch back to the compositor
// context.
- image->getTextureHandle(true);
+ image->getBackendTexture(true);
CHECK(image->isTextureBacked());
return image;
}
diff --git a/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.cc b/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.cc
index ba19b7a7450..f39a5479fa9 100644
--- a/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.cc
+++ b/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.cc
@@ -15,20 +15,17 @@ ChildLocalSurfaceIdAllocator::ChildLocalSurfaceIdAllocator()
kInitialChildSequenceNumber,
base::UnguessableToken()) {}
-const LocalSurfaceId& ChildLocalSurfaceIdAllocator::UpdateFromParent(
+bool ChildLocalSurfaceIdAllocator::UpdateFromParent(
const LocalSurfaceId& parent_allocated_local_surface_id) {
- DCHECK_GE(parent_allocated_local_surface_id.parent_sequence_number(),
- current_local_surface_id_.parent_sequence_number());
- if (!current_local_surface_id_.embed_token().is_empty()) {
- DCHECK_EQ(parent_allocated_local_surface_id.embed_token(),
- current_local_surface_id_.embed_token());
+ if (parent_allocated_local_surface_id.parent_sequence_number() >
+ current_local_surface_id_.parent_sequence_number()) {
+ current_local_surface_id_.parent_sequence_number_ =
+ parent_allocated_local_surface_id.parent_sequence_number_;
+ current_local_surface_id_.embed_token_ =
+ parent_allocated_local_surface_id.embed_token_;
+ return true;
}
-
- current_local_surface_id_.parent_sequence_number_ =
- parent_allocated_local_surface_id.parent_sequence_number_;
- current_local_surface_id_.embed_token_ =
- parent_allocated_local_surface_id.embed_token_;
- return current_local_surface_id_;
+ return false;
}
const LocalSurfaceId& ChildLocalSurfaceIdAllocator::GenerateId() {
diff --git a/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.h b/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.h
index bc1317acf7a..2ca71d699c8 100644
--- a/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.h
+++ b/chromium/components/viz/common/surfaces/child_local_surface_id_allocator.h
@@ -30,8 +30,9 @@ class VIZ_COMMON_EXPORT ChildLocalSurfaceIdAllocator {
// When a parent-allocated LocalSurfaceId arrives in the child, the child
// needs to update its understanding of the last generated message so the
- // messages can continue to monotonically increase.
- const LocalSurfaceId& UpdateFromParent(
+ // messages can continue to monotonically increase. Returns whether the
+ // current LocalSurfaceId has been updated.
+ bool UpdateFromParent(
const LocalSurfaceId& parent_allocated_local_surface_id);
const LocalSurfaceId& GenerateId();
diff --git a/chromium/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc b/chromium/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc
index abddd5dd3a1..99dd27aea58 100644
--- a/chromium/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc
+++ b/chromium/components/viz/common/surfaces/child_local_surface_id_allocator_unittest.cc
@@ -91,9 +91,9 @@ TEST(ChildLocalSurfaceIdAllocatorTest,
EXPECT_NE(preupdate_local_surface_id.embed_token(),
parent_allocated_local_surface_id.embed_token());
- const LocalSurfaceId& returned_local_surface_id =
- parent_updated_child_allocator.UpdateFromParent(
- parent_allocated_local_surface_id);
+ bool changed = parent_updated_child_allocator.UpdateFromParent(
+ parent_allocated_local_surface_id);
+ EXPECT_TRUE(changed);
const LocalSurfaceId& postupdate_local_surface_id =
parent_updated_child_allocator.GetCurrentLocalSurfaceId();
@@ -103,8 +103,6 @@ TEST(ChildLocalSurfaceIdAllocatorTest,
parent_allocated_local_surface_id.child_sequence_number());
EXPECT_EQ(postupdate_local_surface_id.embed_token(),
parent_allocated_local_surface_id.embed_token());
- EXPECT_EQ(returned_local_surface_id,
- parent_updated_child_allocator.GetCurrentLocalSurfaceId());
}
// GenerateId() on a child allocator should monotonically increment the child
diff --git a/chromium/components/viz/common/surfaces/local_surface_id.h b/chromium/components/viz/common/surfaces/local_surface_id.h
index 133eaa322e1..5a84bb1965c 100644
--- a/chromium/components/viz/common/surfaces/local_surface_id.h
+++ b/chromium/components/viz/common/surfaces/local_surface_id.h
@@ -26,6 +26,7 @@ class ChildLocalSurfaceIdAllocator;
constexpr uint32_t kInvalidParentSequenceNumber = 0;
constexpr uint32_t kInvalidChildSequenceNumber = 0;
+constexpr uint32_t kInitialParentSequenceNumber = 1;
constexpr uint32_t kInitialChildSequenceNumber = 1;
// This struct is the part of SurfaceId that can be modified by the client.
diff --git a/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.cc b/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
index 4e732bed709..42586557b4c 100644
--- a/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
+++ b/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.cc
@@ -13,19 +13,20 @@ base::LazyInstance<LocalSurfaceId>::Leaky g_invalid_local_surface_id =
LAZY_INSTANCE_INITIALIZER;
ParentLocalSurfaceIdAllocator::ParentLocalSurfaceIdAllocator()
- : current_local_surface_id_(kInvalidParentSequenceNumber,
+ : current_local_surface_id_(kInitialParentSequenceNumber,
kInitialChildSequenceNumber,
base::UnguessableToken::Create()) {}
-const LocalSurfaceId& ParentLocalSurfaceIdAllocator::UpdateFromChild(
+bool ParentLocalSurfaceIdAllocator::UpdateFromChild(
const LocalSurfaceId& child_allocated_local_surface_id) {
- DCHECK_GE(child_allocated_local_surface_id.child_sequence_number(),
- current_local_surface_id_.child_sequence_number());
-
- current_local_surface_id_.child_sequence_number_ =
- child_allocated_local_surface_id.child_sequence_number_;
- is_invalid_ = false;
- return current_local_surface_id_;
+ if (child_allocated_local_surface_id.child_sequence_number() >
+ current_local_surface_id_.child_sequence_number()) {
+ current_local_surface_id_.child_sequence_number_ =
+ child_allocated_local_surface_id.child_sequence_number_;
+ is_invalid_ = false;
+ return true;
+ }
+ return false;
}
void ParentLocalSurfaceIdAllocator::Reset(
diff --git a/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.h b/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.h
index d90e38f9624..2dab7b67756 100644
--- a/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.h
+++ b/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator.h
@@ -30,9 +30,9 @@ class VIZ_COMMON_EXPORT ParentLocalSurfaceIdAllocator {
// When a child-allocated LocalSurfaceId arrives in the parent, the parent
// needs to update its understanding of the last generated message so the
- // messages can continue to monotonically increase.
- const LocalSurfaceId& UpdateFromChild(
- const LocalSurfaceId& child_allocated_local_surface_id);
+ // messages can continue to monotonically increase. Returns whether the
+ // current LocalSurfaceId has been updated.
+ bool UpdateFromChild(const LocalSurfaceId& child_allocated_local_surface_id);
// Resets this allocator with the provided |local_surface_id| as a seed.
void Reset(const LocalSurfaceId& local_surface_id);
diff --git a/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc b/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
index d64834a509a..77837ea2758 100644
--- a/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
+++ b/chromium/components/viz/common/surfaces/parent_local_surface_id_allocator_unittest.cc
@@ -18,28 +18,29 @@
namespace viz {
namespace {
-::testing::AssertionResult ParentSequenceNumberIsNotSet(
+::testing::AssertionResult ParentSequenceNumberIsSet(
const LocalSurfaceId& local_surface_id);
::testing::AssertionResult ChildSequenceNumberIsSet(
const LocalSurfaceId& local_surface_id);
::testing::AssertionResult NonceIsEmpty(const LocalSurfaceId& local_surface_id);
-LocalSurfaceId GetFakeChildAllocatedLocalSurfaceId();
+LocalSurfaceId GetFakeChildAllocatedLocalSurfaceId(
+ const ParentLocalSurfaceIdAllocator& parent_allocator);
ParentLocalSurfaceIdAllocator GetChildUpdatedAllocator();
} // namespace
// The default constructor should generate a embed_token and initialize the
-// sequence number of the last known LocalSurfaceId to an invalid state.
+// last known LocalSurfaceId.
// Allocation should not be suppressed.
TEST(ParentLocalSurfaceIdAllocatorTest,
- DefaultConstructorShouldNotSetLocalSurfaceIdComponents) {
+ DefaultConstructorShouldInitializeLocalSurfaceIdAndNotBeSuppressed) {
ParentLocalSurfaceIdAllocator default_constructed_parent_allocator;
const LocalSurfaceId& default_local_surface_id =
default_constructed_parent_allocator.GetCurrentLocalSurfaceId();
- EXPECT_FALSE(default_local_surface_id.is_valid());
- EXPECT_TRUE(ParentSequenceNumberIsNotSet(default_local_surface_id));
+ EXPECT_TRUE(default_local_surface_id.is_valid());
+ EXPECT_TRUE(ParentSequenceNumberIsSet(default_local_surface_id));
EXPECT_TRUE(ChildSequenceNumberIsSet(default_local_surface_id));
EXPECT_FALSE(NonceIsEmpty(default_local_surface_id));
EXPECT_FALSE(default_constructed_parent_allocator.is_allocation_suppressed());
@@ -86,30 +87,28 @@ TEST(ParentLocalSurfaceIdAllocatorTest,
UpdateFromChildOnlyUpdatesExpectedLocalSurfaceIdComponents) {
ParentLocalSurfaceIdAllocator child_updated_parent_allocator;
LocalSurfaceId preupdate_local_surface_id =
- child_updated_parent_allocator.GetCurrentLocalSurfaceId();
+ child_updated_parent_allocator.GenerateId();
LocalSurfaceId child_allocated_local_surface_id =
- GetFakeChildAllocatedLocalSurfaceId();
- EXPECT_NE(preupdate_local_surface_id.parent_sequence_number(),
+ GetFakeChildAllocatedLocalSurfaceId(child_updated_parent_allocator);
+ EXPECT_EQ(preupdate_local_surface_id.parent_sequence_number(),
child_allocated_local_surface_id.parent_sequence_number());
EXPECT_NE(preupdate_local_surface_id.child_sequence_number(),
child_allocated_local_surface_id.child_sequence_number());
- EXPECT_NE(preupdate_local_surface_id.embed_token(),
+ EXPECT_EQ(preupdate_local_surface_id.embed_token(),
child_allocated_local_surface_id.embed_token());
- const LocalSurfaceId& returned_local_surface_id =
- child_updated_parent_allocator.UpdateFromChild(
- child_allocated_local_surface_id);
+ bool changed = child_updated_parent_allocator.UpdateFromChild(
+ child_allocated_local_surface_id);
+ EXPECT_TRUE(changed);
const LocalSurfaceId& postupdate_local_surface_id =
child_updated_parent_allocator.GetCurrentLocalSurfaceId();
- EXPECT_NE(postupdate_local_surface_id.parent_sequence_number(),
+ EXPECT_EQ(postupdate_local_surface_id.parent_sequence_number(),
child_allocated_local_surface_id.parent_sequence_number());
EXPECT_EQ(postupdate_local_surface_id.child_sequence_number(),
child_allocated_local_surface_id.child_sequence_number());
- EXPECT_NE(postupdate_local_surface_id.embed_token(),
+ EXPECT_EQ(postupdate_local_surface_id.embed_token(),
child_allocated_local_surface_id.embed_token());
- EXPECT_EQ(returned_local_surface_id,
- child_updated_parent_allocator.GetCurrentLocalSurfaceId());
EXPECT_FALSE(child_updated_parent_allocator.is_allocation_suppressed());
}
@@ -145,13 +144,13 @@ TEST(ParentLocalSurfaceIdAllocatorTest, ResetUpdatesComponents) {
LocalSurfaceId default_local_surface_id =
default_constructed_parent_allocator.GetCurrentLocalSurfaceId();
- EXPECT_FALSE(default_local_surface_id.is_valid());
- EXPECT_TRUE(ParentSequenceNumberIsNotSet(default_local_surface_id));
+ EXPECT_TRUE(default_local_surface_id.is_valid());
+ EXPECT_TRUE(ParentSequenceNumberIsSet(default_local_surface_id));
EXPECT_TRUE(ChildSequenceNumberIsSet(default_local_surface_id));
EXPECT_FALSE(NonceIsEmpty(default_local_surface_id));
LocalSurfaceId new_local_surface_id(
- 1u, 1u, base::UnguessableToken::Deserialize(0, 1u));
+ 2u, 2u, base::UnguessableToken::Deserialize(0, 1u));
default_constructed_parent_allocator.Reset(new_local_surface_id);
EXPECT_EQ(new_local_surface_id,
@@ -169,12 +168,12 @@ TEST(ParentLocalSurfaceIdAllocatorTest, ResetUpdatesComponents) {
namespace {
-::testing::AssertionResult ParentSequenceNumberIsNotSet(
+::testing::AssertionResult ParentSequenceNumberIsSet(
const LocalSurfaceId& local_surface_id) {
- if (local_surface_id.parent_sequence_number() == kInvalidParentSequenceNumber)
+ if (local_surface_id.parent_sequence_number() != kInvalidParentSequenceNumber)
return ::testing::AssertionSuccess();
- return ::testing::AssertionFailure() << "parent_sequence_number() is set";
+ return ::testing::AssertionFailure() << "parent_sequence_number() is not set";
}
::testing::AssertionResult ChildSequenceNumberIsSet(
@@ -193,19 +192,20 @@ namespace {
return ::testing::AssertionFailure() << "embed_token() is not empty";
}
-LocalSurfaceId GetFakeChildAllocatedLocalSurfaceId() {
- constexpr uint32_t kParentSequenceNumber = 1;
- constexpr uint32_t kChildSequenceNumber = 3;
- const base::UnguessableToken embed_token = base::UnguessableToken::Create();
+LocalSurfaceId GetFakeChildAllocatedLocalSurfaceId(
+ const ParentLocalSurfaceIdAllocator& parent_allocator) {
+ const LocalSurfaceId& current_local_surface_id =
+ parent_allocator.GetCurrentLocalSurfaceId();
- return LocalSurfaceId(kParentSequenceNumber, kChildSequenceNumber,
- embed_token);
+ return LocalSurfaceId(current_local_surface_id.parent_sequence_number(),
+ current_local_surface_id.child_sequence_number() + 1,
+ current_local_surface_id.embed_token());
}
ParentLocalSurfaceIdAllocator GetChildUpdatedAllocator() {
ParentLocalSurfaceIdAllocator child_updated_parent_allocator;
LocalSurfaceId child_allocated_local_surface_id =
- GetFakeChildAllocatedLocalSurfaceId();
+ GetFakeChildAllocatedLocalSurfaceId(child_updated_parent_allocator);
child_updated_parent_allocator.UpdateFromChild(
child_allocated_local_surface_id);
return child_updated_parent_allocator;
diff --git a/chromium/components/viz/common/switches.cc b/chromium/components/viz/common/switches.cc
index d600f462d4d..30d95509c71 100644
--- a/chromium/components/viz/common/switches.cc
+++ b/chromium/components/viz/common/switches.cc
@@ -33,6 +33,10 @@ const char kRunAllCompositorStagesBeforeDraw[] =
// hit-test data coming from surface layer.
const char kUseVizHitTestSurfaceLayer[] = "use-viz-hit-test-surface-layer";
+// Disables begin frame limiting in both cc scheduler and display scheduler.
+// Also implies --disable-gpu-vsync (see //ui/gl/gl_switches.h).
+const char kDisableFrameRateLimit[] = "disable-frame-rate-limit";
+
base::Optional<uint32_t> GetDeadlineToSynchronizeSurfaces() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw)) {
diff --git a/chromium/components/viz/common/switches.h b/chromium/components/viz/common/switches.h
index 78648fa333e..1cd65ca103c 100644
--- a/chromium/components/viz/common/switches.h
+++ b/chromium/components/viz/common/switches.h
@@ -19,6 +19,7 @@ VIZ_COMMON_EXPORT extern const char kEnableSurfaceSynchronization[];
VIZ_COMMON_EXPORT extern const char kEnableVizDevTools[];
VIZ_COMMON_EXPORT extern const char kRunAllCompositorStagesBeforeDraw[];
VIZ_COMMON_EXPORT extern const char kUseVizHitTestSurfaceLayer[];
+VIZ_COMMON_EXPORT extern const char kDisableFrameRateLimit[];
VIZ_COMMON_EXPORT base::Optional<uint32_t> GetDeadlineToSynchronizeSurfaces();
diff --git a/chromium/components/viz/common/yuv_readback_unittest.cc b/chromium/components/viz/common/yuv_readback_unittest.cc
index d3f38fd6067..a758f3cb9f8 100644
--- a/chromium/components/viz/common/yuv_readback_unittest.cc
+++ b/chromium/components/viz/common/yuv_readback_unittest.cc
@@ -49,7 +49,6 @@ class YUVReadbackTest : public testing::Test {
nullptr, /* surface */
true, /* offscreen */
gpu::kNullSurfaceHandle, /* window */
- nullptr, /* share_context */
attributes, gpu::SharedMemoryLimits(),
nullptr, /* gpu_memory_buffer_manager */
nullptr, /* image_factory */
diff --git a/chromium/components/viz/host/BUILD.gn b/chromium/components/viz/host/BUILD.gn
index d52ccabf939..e82fa99cdba 100644
--- a/chromium/components/viz/host/BUILD.gn
+++ b/chromium/components/viz/host/BUILD.gn
@@ -9,6 +9,8 @@ viz_component("host") {
defines = [ "VIZ_HOST_IMPLEMENTATION" ]
sources = [
+ "client_frame_sink_video_capturer.cc",
+ "client_frame_sink_video_capturer.h",
"hit_test/hit_test_query.cc",
"hit_test/hit_test_query.h",
"host_frame_sink_client.h",
@@ -21,6 +23,13 @@ viz_component("host") {
"viz_host_export.h",
]
+ if (is_win) {
+ sources += [
+ "layered_window_updater_impl.cc",
+ "layered_window_updater_impl.h",
+ ]
+ }
+
deps = [
"//base",
"//components/viz/common",
diff --git a/chromium/components/viz/host/DEPS b/chromium/components/viz/host/DEPS
index 6d13397fbd6..83389e05a38 100644
--- a/chromium/components/viz/host/DEPS
+++ b/chromium/components/viz/host/DEPS
@@ -1,9 +1,9 @@
# Please consult components/viz/README.md about allowable dependencies.
include_rules = [
- "+cc/ipc",
"+components/viz/common/features.h",
"-components/viz/common/switches.h",
+ "+media/base/video_types.h",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
"+gpu/ipc/client",
@@ -13,6 +13,8 @@ include_rules = [
"+services/viz/privileged/interfaces",
"+services/viz/public/interfaces",
"+services/viz/public/interfaces/hit_test",
+ "+skia",
+ "+third_party/skia",
]
specific_include_rules = {
diff --git a/chromium/components/viz/host/client_frame_sink_video_capturer.cc b/chromium/components/viz/host/client_frame_sink_video_capturer.cc
new file mode 100644
index 00000000000..331fa0755ba
--- /dev/null
+++ b/chromium/components/viz/host/client_frame_sink_video_capturer.cc
@@ -0,0 +1,161 @@
+// 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 "components/viz/host/client_frame_sink_video_capturer.h"
+
+namespace viz {
+
+namespace {
+
+// How long to wait before attempting to re-establish a lost connection.
+constexpr base::TimeDelta kReEstablishConnectionDelay =
+ base::TimeDelta::FromMilliseconds(100);
+
+} // namespace
+
+ClientFrameSinkVideoCapturer::ClientFrameSinkVideoCapturer(
+ EstablishConnectionCallback callback)
+ : establish_connection_callback_(callback),
+ consumer_binding_(this),
+ weak_factory_(this) {
+ EstablishConnection();
+}
+
+ClientFrameSinkVideoCapturer::~ClientFrameSinkVideoCapturer() = default;
+
+void ClientFrameSinkVideoCapturer::SetFormat(media::VideoPixelFormat format,
+ media::ColorSpace color_space) {
+ format_.emplace(format, color_space);
+ capturer_->SetFormat(format, color_space);
+}
+
+void ClientFrameSinkVideoCapturer::SetMinCapturePeriod(
+ base::TimeDelta min_capture_period) {
+ min_capture_period_ = min_capture_period;
+ capturer_->SetMinCapturePeriod(min_capture_period);
+}
+
+void ClientFrameSinkVideoCapturer::SetMinSizeChangePeriod(
+ base::TimeDelta min_period) {
+ min_size_change_period_ = min_period;
+ capturer_->SetMinSizeChangePeriod(min_period);
+}
+
+void ClientFrameSinkVideoCapturer::SetResolutionConstraints(
+ const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ bool use_fixed_aspect_ratio) {
+ resolution_constraints_.emplace(min_size, max_size, use_fixed_aspect_ratio);
+ capturer_->SetResolutionConstraints(min_size, max_size,
+ use_fixed_aspect_ratio);
+}
+
+void ClientFrameSinkVideoCapturer::SetAutoThrottlingEnabled(bool enabled) {
+ auto_throttling_enabled_ = enabled;
+ capturer_->SetAutoThrottlingEnabled(enabled);
+}
+
+void ClientFrameSinkVideoCapturer::ChangeTarget(
+ const FrameSinkId& frame_sink_id) {
+ target_ = frame_sink_id;
+ capturer_->ChangeTarget(frame_sink_id);
+}
+
+void ClientFrameSinkVideoCapturer::Start(
+ mojom::FrameSinkVideoConsumer* consumer) {
+ DCHECK(consumer);
+ is_started_ = true;
+ consumer_ = consumer;
+ StartInternal();
+}
+
+void ClientFrameSinkVideoCapturer::Stop() {
+ is_started_ = false;
+ capturer_->Stop();
+}
+
+void ClientFrameSinkVideoCapturer::StopAndResetConsumer() {
+ Stop();
+ consumer_ = nullptr;
+ consumer_binding_.Close();
+}
+
+void ClientFrameSinkVideoCapturer::RequestRefreshFrame() {
+ capturer_->RequestRefreshFrame();
+}
+
+ClientFrameSinkVideoCapturer::Format::Format(
+ media::VideoPixelFormat pixel_format,
+ media::ColorSpace color_space)
+ : pixel_format(pixel_format), color_space(color_space) {}
+
+ClientFrameSinkVideoCapturer::ResolutionConstraints::ResolutionConstraints(
+ const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ bool use_fixed_aspect_ratio)
+ : min_size(min_size),
+ max_size(max_size),
+ use_fixed_aspect_ratio(use_fixed_aspect_ratio) {}
+
+void ClientFrameSinkVideoCapturer::OnFrameCaptured(
+ mojo::ScopedSharedBufferHandle buffer,
+ uint32_t buffer_size,
+ media::mojom::VideoFrameInfoPtr info,
+ const gfx::Rect& update_rect,
+ const gfx::Rect& content_rect,
+ mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) {
+ consumer_->OnFrameCaptured(std::move(buffer), buffer_size, std::move(info),
+ update_rect, content_rect, std::move(callbacks));
+}
+
+void ClientFrameSinkVideoCapturer::OnTargetLost(
+ const FrameSinkId& frame_sink_id) {
+ consumer_->OnTargetLost(frame_sink_id);
+}
+
+void ClientFrameSinkVideoCapturer::OnStopped() {
+ consumer_->OnStopped();
+}
+
+void ClientFrameSinkVideoCapturer::EstablishConnection() {
+ establish_connection_callback_.Run(mojo::MakeRequest(&capturer_));
+ capturer_.set_connection_error_handler(
+ base::BindOnce(&ClientFrameSinkVideoCapturer::OnConnectionError,
+ base::Unretained(this)));
+ if (format_)
+ capturer_->SetFormat(format_->pixel_format, format_->color_space);
+ if (min_capture_period_)
+ capturer_->SetMinCapturePeriod(*min_capture_period_);
+ if (min_size_change_period_)
+ capturer_->SetMinSizeChangePeriod(*min_size_change_period_);
+ if (resolution_constraints_) {
+ capturer_->SetResolutionConstraints(
+ resolution_constraints_->min_size, resolution_constraints_->max_size,
+ resolution_constraints_->use_fixed_aspect_ratio);
+ }
+ if (auto_throttling_enabled_)
+ capturer_->SetAutoThrottlingEnabled(*auto_throttling_enabled_);
+ if (target_)
+ capturer_->ChangeTarget(*target_);
+ if (is_started_)
+ StartInternal();
+}
+
+void ClientFrameSinkVideoCapturer::OnConnectionError() {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&ClientFrameSinkVideoCapturer::EstablishConnection,
+ weak_factory_.GetWeakPtr()),
+ kReEstablishConnectionDelay);
+}
+
+void ClientFrameSinkVideoCapturer::StartInternal() {
+ if (consumer_binding_)
+ consumer_binding_.Close();
+ mojom::FrameSinkVideoConsumerPtr consumer;
+ consumer_binding_.Bind(mojo::MakeRequest(&consumer));
+ capturer_->Start(std::move(consumer));
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/host/client_frame_sink_video_capturer.h b/chromium/components/viz/host/client_frame_sink_video_capturer.h
new file mode 100644
index 00000000000..dd6c5fb4f18
--- /dev/null
+++ b/chromium/components/viz/host/client_frame_sink_video_capturer.h
@@ -0,0 +1,115 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_HOST_CLIENT_FRAME_SINK_VIDEO_CAPTURER_H_
+#define COMPONENTS_VIZ_HOST_CLIENT_FRAME_SINK_VIDEO_CAPTURER_H_
+
+#include "base/callback.h"
+#include "base/time/time.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/host/viz_host_export.h"
+#include "media/base/video_types.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace viz {
+
+// Client library for using FrameSinkVideoCapturer. Clients should use this
+// class instead of talking directly to FrameSinkVideoCapturer in order to
+// survive Viz crashes.
+// TODO(samans): Move this class and all its dependencies to the client
+// directory.
+class VIZ_HOST_EXPORT ClientFrameSinkVideoCapturer
+ : private mojom::FrameSinkVideoConsumer {
+ public:
+ using EstablishConnectionCallback =
+ base::RepeatingCallback<void(mojom::FrameSinkVideoCapturerRequest)>;
+
+ explicit ClientFrameSinkVideoCapturer(EstablishConnectionCallback callback);
+ ~ClientFrameSinkVideoCapturer() override;
+
+ // See FrameSinkVideoCapturer for documentation.
+ void SetFormat(media::VideoPixelFormat format, media::ColorSpace color_space);
+ void SetMinCapturePeriod(base::TimeDelta min_capture_period);
+ void SetMinSizeChangePeriod(base::TimeDelta min_period);
+ void SetResolutionConstraints(const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ bool use_fixed_aspect_ratio);
+ void SetAutoThrottlingEnabled(bool enabled);
+ void ChangeTarget(const FrameSinkId& frame_sink_id);
+ void Stop();
+ void RequestRefreshFrame();
+
+ // Similar to FrameSinkVideoCapturer::Start, but takes in a pointer directly
+ // to the FrameSinkVideoConsumer implemenation class (as opposed to a
+ // mojo::InterfacePtr or a proxy object).
+ void Start(mojom::FrameSinkVideoConsumer* consumer);
+
+ // Similar to Stop() but also resets the consumer immediately so no further
+ // messages (even OnStopped()) will be delivered to the consumer.
+ void StopAndResetConsumer();
+
+ private:
+ struct Format {
+ Format(media::VideoPixelFormat pixel_format, media::ColorSpace color_space);
+
+ media::VideoPixelFormat pixel_format;
+ media::ColorSpace color_space;
+ };
+
+ struct ResolutionConstraints {
+ ResolutionConstraints(const gfx::Size& min_size,
+ const gfx::Size& max_size,
+ bool use_fixed_aspect_ratio);
+
+ gfx::Size min_size;
+ gfx::Size max_size;
+ bool use_fixed_aspect_ratio;
+ };
+
+ // mojom::FrameSinkVideoConsumer implementation.
+ void OnFrameCaptured(
+ mojo::ScopedSharedBufferHandle buffer,
+ uint32_t buffer_size,
+ media::mojom::VideoFrameInfoPtr info,
+ const gfx::Rect& update_rect,
+ const gfx::Rect& content_rect,
+ mojom::FrameSinkVideoConsumerFrameCallbacksPtr callbacks) final;
+ void OnTargetLost(const FrameSinkId& frame_sink_id) final;
+ void OnStopped() final;
+
+ // Establishes connection to FrameSinkVideoCapturer and sends the existing
+ // configuration.
+ void EstablishConnection();
+
+ // Called when the message pipe is gone. Will call EstablishConnection after
+ // some delay.
+ void OnConnectionError();
+
+ void StartInternal();
+
+ // The following variables keep the latest arguments provided to their
+ // corresponding method in mojom::FrameSinkVideoCapturer. The arguments are
+ // saved so we can resend them if viz crashes and a new FrameSinkVideoCapturer
+ // has to be created.
+ base::Optional<Format> format_;
+ base::Optional<base::TimeDelta> min_capture_period_;
+ base::Optional<base::TimeDelta> min_size_change_period_;
+ base::Optional<ResolutionConstraints> resolution_constraints_;
+ base::Optional<bool> auto_throttling_enabled_;
+ base::Optional<FrameSinkId> target_;
+ bool is_started_ = false;
+
+ mojom::FrameSinkVideoConsumer* consumer_ = nullptr;
+ EstablishConnectionCallback establish_connection_callback_;
+ mojom::FrameSinkVideoCapturerPtr capturer_;
+ mojo::Binding<mojom::FrameSinkVideoConsumer> consumer_binding_;
+
+ base::WeakPtrFactory<ClientFrameSinkVideoCapturer> weak_factory_;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_HOST_CLIENT_FRAME_SINK_VIDEO_CAPTURER_H_
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.cc b/chromium/components/viz/host/hit_test/hit_test_query.cc
index efeb4c42cc9..15d9f2c741c 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query.cc
+++ b/chromium/components/viz/host/hit_test/hit_test_query.cc
@@ -5,16 +5,27 @@
#include "components/viz/host/hit_test/hit_test_query.h"
#include "base/metrics/histogram_macros.h"
-#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace viz {
namespace {
// If we want to add new source type here, consider switching to use
// ui::EventPointerType instead of EventSource.
-bool ShouldUseTouchBounds(EventSource event_source) {
- return event_source == EventSource::TOUCH;
+bool RegionMatchEventSource(EventSource event_source, uint32_t flags) {
+ if (event_source == EventSource::TOUCH)
+ return (flags & HitTestRegionFlags::kHitTestTouch) != 0u;
+ if (event_source == EventSource::MOUSE)
+ return (flags & HitTestRegionFlags::kHitTestMouse) != 0u;
+ return (flags & (HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch)) != 0u;
+}
+
+bool CheckChildCount(int32_t child_count, uint32_t child_count_max) {
+ return (child_count >= 0) &&
+ (static_cast<uint32_t>(child_count) < child_count_max);
}
} // namespace
@@ -25,39 +36,10 @@ HitTestQuery::HitTestQuery(base::RepeatingClosure bad_message_gpu_callback)
HitTestQuery::~HitTestQuery() = default;
void HitTestQuery::OnAggregatedHitTestRegionListUpdated(
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) {
- if (!active_handle.is_valid() || !idle_handle.is_valid()) {
- ReceivedBadMessageFromGpuProcess();
- return;
- }
- handle_buffer_sizes_[0] = active_handle_size;
- handle_buffers_[0] = active_handle->Map(handle_buffer_sizes_[0] *
- sizeof(AggregatedHitTestRegion));
- handle_buffer_sizes_[1] = idle_handle_size;
- handle_buffers_[1] = idle_handle->Map(handle_buffer_sizes_[1] *
- sizeof(AggregatedHitTestRegion));
- if (!handle_buffers_[0] || !handle_buffers_[1]) {
- handle_buffer_sizes_[0] = handle_buffer_sizes_[1] = 0;
- handle_buffers_[0] = {};
- handle_buffers_[1] = {};
- ReceivedBadMessageFromGpuProcess();
- return;
- }
- SwitchActiveAggregatedHitTestRegionList(0);
-}
-
-void HitTestQuery::SwitchActiveAggregatedHitTestRegionList(
- uint8_t active_handle_index) {
- if (active_handle_index != 0u && active_handle_index != 1u) {
- ReceivedBadMessageFromGpuProcess();
- return;
- }
- active_hit_test_list_ = static_cast<AggregatedHitTestRegion*>(
- handle_buffers_[active_handle_index].get());
- active_hit_test_list_size_ = handle_buffer_sizes_[active_handle_index];
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) {
+ hit_test_data_.clear();
+ hit_test_data_ = hit_test_data;
+ hit_test_data_size_ = hit_test_data.size();
}
Target HitTestQuery::FindTargetForLocation(
@@ -66,11 +48,10 @@ Target HitTestQuery::FindTargetForLocation(
SCOPED_UMA_HISTOGRAM_TIMER("Event.VizHitTest.TargetTime");
Target target;
- if (!active_hit_test_list_size_)
+ if (!hit_test_data_size_)
return target;
- FindTargetInRegionForLocation(event_source, location_in_root,
- active_hit_test_list_, &target);
+ FindTargetInRegionForLocation(event_source, location_in_root, 0, &target);
return target;
}
@@ -81,66 +62,75 @@ bool HitTestQuery::TransformLocationForTarget(
gfx::PointF* transformed_location) const {
SCOPED_UMA_HISTOGRAM_TIMER("Event.VizHitTest.TransformTime");
- if (!active_hit_test_list_size_)
+ if (!hit_test_data_size_)
return false;
if (target_ancestors.size() == 0u ||
target_ancestors[target_ancestors.size() - 1] !=
- active_hit_test_list_->frame_sink_id) {
+ hit_test_data_[0].frame_sink_id) {
return false;
}
// TODO(riajiang): Cache the matrix product such that the transform can be
// done immediately. crbug/758062.
*transformed_location = location_in_root;
- return TransformLocationForTargetRecursively(
- event_source, target_ancestors, target_ancestors.size() - 1,
- active_hit_test_list_, transformed_location);
+ return TransformLocationForTargetRecursively(event_source, target_ancestors,
+ target_ancestors.size() - 1, 0,
+ transformed_location);
+}
+
+bool HitTestQuery::GetTransformToTarget(const FrameSinkId& target,
+ gfx::Transform* transform) const {
+ if (!hit_test_data_size_)
+ return false;
+
+ return GetTransformToTargetRecursively(target, 0, transform);
}
bool HitTestQuery::FindTargetInRegionForLocation(
EventSource event_source,
const gfx::PointF& location_in_parent,
- AggregatedHitTestRegion* region,
+ uint32_t region_index,
Target* target) const {
gfx::PointF location_transformed(location_in_parent);
- region->transform().TransformPoint(&location_transformed);
- if (!gfx::RectF(region->rect).Contains(location_transformed))
+ hit_test_data_[region_index].transform().TransformPoint(
+ &location_transformed);
+ if (!gfx::RectF(hit_test_data_[region_index].rect)
+ .Contains(location_transformed)) {
return false;
+ }
- if (region->child_count < 0 ||
- region->child_count >
- (active_hit_test_list_ + active_hit_test_list_size_ - region - 1)) {
+ const int32_t region_child_count = hit_test_data_[region_index].child_count;
+ if (!CheckChildCount(region_child_count, hit_test_data_size_ - region_index))
return false;
- }
- AggregatedHitTestRegion* child_region = region + 1;
- AggregatedHitTestRegion* child_region_end =
- child_region + region->child_count;
+
+ uint32_t child_region = region_index + 1;
+ uint32_t child_region_end = child_region + region_child_count;
gfx::PointF location_in_target =
- location_transformed - region->rect.OffsetFromOrigin();
+ location_transformed -
+ hit_test_data_[region_index].rect.OffsetFromOrigin();
while (child_region < child_region_end) {
if (FindTargetInRegionForLocation(event_source, location_in_target,
child_region, target)) {
return true;
}
- if (child_region->child_count < 0 ||
- child_region->child_count >= region->child_count) {
+ const int32_t child_region_child_count =
+ hit_test_data_[child_region].child_count;
+ if (!CheckChildCount(child_region_child_count, region_child_count))
return false;
- }
- child_region = child_region + child_region->child_count + 1;
+
+ child_region = child_region + child_region_child_count + 1;
}
- bool match_touch_or_mouse_region =
- ShouldUseTouchBounds(event_source)
- ? (region->flags & mojom::kHitTestTouch) != 0u
- : (region->flags & mojom::kHitTestMouse) != 0u;
- if (!match_touch_or_mouse_region)
+ const uint32_t flags = hit_test_data_[region_index].flags;
+ if (!RegionMatchEventSource(event_source, flags))
return false;
- if (region->flags & (mojom::kHitTestMine | mojom::kHitTestAsk)) {
- target->frame_sink_id = region->frame_sink_id;
+ if (flags &
+ (HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestAsk)) {
+ target->frame_sink_id = hit_test_data_[region_index].frame_sink_id;
target->location_in_target = location_in_target;
- target->flags = region->flags;
+ target->flags = flags;
return true;
}
return false;
@@ -150,42 +140,81 @@ bool HitTestQuery::TransformLocationForTargetRecursively(
EventSource event_source,
const std::vector<FrameSinkId>& target_ancestors,
size_t target_ancestor,
- AggregatedHitTestRegion* region,
+ uint32_t region_index,
gfx::PointF* location_in_target) const {
- bool match_touch_or_mouse_region =
- ShouldUseTouchBounds(event_source)
- ? (region->flags & mojom::kHitTestTouch) != 0u
- : (region->flags & mojom::kHitTestMouse) != 0u;
- if ((region->flags & mojom::kHitTestChildSurface) == 0u &&
- !match_touch_or_mouse_region) {
+ const uint32_t flags = hit_test_data_[region_index].flags;
+ if ((flags & HitTestRegionFlags::kHitTestChildSurface) == 0u &&
+ !RegionMatchEventSource(event_source, flags)) {
return false;
}
- region->transform().TransformPoint(location_in_target);
- location_in_target->Offset(-region->rect.x(), -region->rect.y());
+ hit_test_data_[region_index].transform().TransformPoint(location_in_target);
+ location_in_target->Offset(-hit_test_data_[region_index].rect.x(),
+ -hit_test_data_[region_index].rect.y());
if (!target_ancestor)
return true;
- if (region->child_count < 0 ||
- region->child_count >
- (active_hit_test_list_ + active_hit_test_list_size_ - region - 1)) {
+ const int32_t region_child_count = hit_test_data_[region_index].child_count;
+ if (!CheckChildCount(region_child_count, hit_test_data_size_ - region_index))
return false;
- }
- AggregatedHitTestRegion* child_region = region + 1;
- AggregatedHitTestRegion* child_region_end =
- child_region + region->child_count;
+
+ uint32_t child_region = region_index + 1;
+ uint32_t child_region_end = child_region + region_child_count;
while (child_region < child_region_end) {
- if (child_region->frame_sink_id == target_ancestors[target_ancestor - 1]) {
+ if (hit_test_data_[child_region].frame_sink_id ==
+ target_ancestors[target_ancestor - 1]) {
return TransformLocationForTargetRecursively(
event_source, target_ancestors, target_ancestor - 1, child_region,
location_in_target);
}
- if (child_region->child_count < 0 ||
- child_region->child_count >= region->child_count) {
+ const int32_t child_region_child_count =
+ hit_test_data_[child_region].child_count;
+ if (!CheckChildCount(child_region_child_count, region_child_count))
return false;
+
+ child_region = child_region + child_region_child_count + 1;
+ }
+
+ return false;
+}
+
+bool HitTestQuery::GetTransformToTargetRecursively(
+ const FrameSinkId& target,
+ uint32_t region_index,
+ gfx::Transform* transform) const {
+ // TODO(riajiang): Cache the matrix product such that the transform can be
+ // found immediately.
+ if (hit_test_data_[region_index].frame_sink_id == target) {
+ *transform = hit_test_data_[region_index].transform();
+ transform->Translate(-hit_test_data_[region_index].rect.x(),
+ -hit_test_data_[region_index].rect.y());
+ return true;
+ }
+
+ const int32_t region_child_count = hit_test_data_[region_index].child_count;
+ if (!CheckChildCount(region_child_count, hit_test_data_size_ - region_index))
+ return false;
+
+ uint32_t child_region = region_index + 1;
+ uint32_t child_region_end = child_region + region_child_count;
+ while (child_region < child_region_end) {
+ gfx::Transform transform_to_child;
+ if (GetTransformToTargetRecursively(target, child_region,
+ &transform_to_child)) {
+ gfx::Transform region_transform(hit_test_data_[region_index].transform());
+ region_transform.Translate(-hit_test_data_[region_index].rect.x(),
+ -hit_test_data_[region_index].rect.y());
+ *transform = transform_to_child * region_transform;
+ return true;
}
- child_region = child_region + child_region->child_count + 1;
+
+ const int32_t child_region_child_count =
+ hit_test_data_[child_region].child_count;
+ if (!CheckChildCount(child_region_child_count, region_child_count))
+ return false;
+
+ child_region = child_region + child_region_child_count + 1;
}
return false;
diff --git a/chromium/components/viz/host/hit_test/hit_test_query.h b/chromium/components/viz/host/hit_test/hit_test_query.h
index 3c82875c40e..a722182a0a3 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query.h
+++ b/chromium/components/viz/host/hit_test/hit_test_query.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
#include "components/viz/host/viz_host_export.h"
-#include "mojo/public/cpp/system/buffer.h"
#include "ui/gfx/geometry/point_f.h"
namespace viz {
@@ -28,6 +27,7 @@ struct Target {
enum class EventSource {
MOUSE,
TOUCH,
+ ANY,
};
// Finds the target for a given location based on the AggregatedHitTestRegion
@@ -41,20 +41,10 @@ class VIZ_HOST_EXPORT HitTestQuery {
// TODO(riajiang): Need to validate the data received.
// http://crbug.com/746470
- // HitTestAggregator should only send new active_handle and idle_handle when
- // they are initialized or replaced with OnAggregatedHitTestRegionListUpdated.
- // Both handles must be valid. HitTestQuery would store and update these two
- // handles received.
- // HitTestAggregator would tell HitTestQuery to update its active hit test
- // list based on |active_handle_index| with
- // SwitchActiveAggregatedHitTestRegionList if HitTestAggregator only swapped
- // handles.
+ // HitTestAggregator has sent the most recent |hit_test_data| for targeting/
+ // transforming requests.
void OnAggregatedHitTestRegionListUpdated(
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size);
- void SwitchActiveAggregatedHitTestRegionList(uint8_t active_handle_index);
+ const std::vector<AggregatedHitTestRegion>& hit_test_data);
// Finds Target for |location_in_root|, including the FrameSinkId of the
// target, updated location in the coordinate system of the target and
@@ -94,32 +84,41 @@ class VIZ_HOST_EXPORT HitTestQuery {
const gfx::PointF& location_in_root,
gfx::PointF* transformed_location) const;
+ // Gets the transform from root to |target| in physical pixels. Returns true
+ // and stores the result into |transform| if successful, returns false
+ // otherwise. This is potentially a little more expensive than
+ // TransformLocationForTarget(). So if the path from root to target is known,
+ // then that is the preferred API.
+ bool GetTransformToTarget(const FrameSinkId& target,
+ gfx::Transform* transform) const;
+
private:
- // Helper function to find |target| for |location_in_parent| in the |region|,
- // returns true if a target is found and false otherwise. |location_in_parent|
- // is in the coordinate space of |region|'s parent.
+ // Helper function to find |target| for |location_in_parent| in the
+ // |region_index|, returns true if a target is found and false otherwise.
+ // |location_in_parent| is in the coordinate space of |region_index|'s parent.
bool FindTargetInRegionForLocation(EventSource event_source,
const gfx::PointF& location_in_parent,
- AggregatedHitTestRegion* region,
+ uint32_t region_index,
Target* target) const;
- // Transform |location_in_target| to be in |region|'s coordinate space.
- // |location_in_target| is in the coordinate space of |region|'s parent at the
- // beginning.
+ // Transform |location_in_target| to be in |region_index|'s coordinate space.
+ // |location_in_target| is in the coordinate space of |region_index|'s parent
+ // at the beginning.
bool TransformLocationForTargetRecursively(
EventSource event_source,
const std::vector<FrameSinkId>& target_ancestors,
size_t target_ancestor,
- AggregatedHitTestRegion* region,
+ uint32_t region_index,
gfx::PointF* location_in_target) const;
- void ReceivedBadMessageFromGpuProcess() const;
+ bool GetTransformToTargetRecursively(const FrameSinkId& target,
+ uint32_t region_index,
+ gfx::Transform* transform) const;
- uint32_t handle_buffer_sizes_[2];
- mojo::ScopedSharedBufferMapping handle_buffers_[2];
+ void ReceivedBadMessageFromGpuProcess() const;
- AggregatedHitTestRegion* active_hit_test_list_ = nullptr;
- uint32_t active_hit_test_list_size_ = 0;
+ std::vector<AggregatedHitTestRegion> hit_test_data_;
+ uint32_t hit_test_data_size_ = 0;
// Log bad message and shut down Viz process when it is compromised.
base::RepeatingClosure bad_message_gpu_callback_;
diff --git a/chromium/components/viz/host/hit_test/hit_test_query_fuzzer.cc b/chromium/components/viz/host/hit_test/hit_test_query_fuzzer.cc
index 5bdfde0e68f..0f247e095da 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query_fuzzer.cc
+++ b/chromium/components/viz/host/hit_test/hit_test_query_fuzzer.cc
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/test/fuzzed_data_provider.h"
#include "components/viz/host/hit_test/hit_test_query.h"
-#include "mojo/edk/embedder/embedder.h"
namespace {
@@ -45,22 +44,9 @@ void AddHitTestRegion(base::FuzzedDataProvider* fuzz,
AddHitTestRegion(fuzz, regions, frame_sink_ids, depth + 1);
}
-class Environment {
- public:
- Environment() {
- // Initialize environment so that we can create the mojo shared memory
- // handles.
- base::CommandLine::Init(0, nullptr);
- mojo::edk::Init();
- }
-};
-
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) {
- // Initialize the environment only once.
- static Environment environment;
-
// If there isn't enough memory to have a single AggregatedHitTestRegion, then
// skip.
if (num_bytes < sizeof(viz::AggregatedHitTestRegion))
@@ -72,22 +58,9 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) {
base::FuzzedDataProvider fuzz(data, num_bytes);
AddHitTestRegion(&fuzz, &regions, &frame_sink_ids);
- // Put the regions into shared memory.
- size_t regions_in_bytes =
- regions.size() * sizeof(viz::AggregatedHitTestRegion);
- auto shared_buffer = mojo::SharedBufferHandle::Create(regions_in_bytes);
- auto buffer = shared_buffer->Map(regions_in_bytes);
- memcpy(buffer.get(), regions.data(), regions_in_bytes);
- buffer = nullptr;
- auto backup_buffer = mojo::SharedBufferHandle::Create(regions_in_bytes);
-
- // Create the HitTestQuery and inject the shared memory into it.
+ // Create the HitTestQuery and send hit-test data.
viz::HitTestQuery query;
- query.OnAggregatedHitTestRegionListUpdated(
- shared_buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
- regions.size(),
- backup_buffer->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
- regions.size());
+ query.OnAggregatedHitTestRegionListUpdated(regions);
for (float x = 0; x < 1000.; x += 10) {
for (float y = 0; y < 1000.; y += 10) {
diff --git a/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc b/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc
index df8a25f1762..3b56f36e25b 100644
--- a/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc
+++ b/chromium/components/viz/host/hit_test/hit_test_query_unittest.cc
@@ -6,7 +6,7 @@
#include <cstdint>
-#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
@@ -17,32 +17,17 @@ class HitTestQueryTest : public testing::Test {
HitTestQueryTest() = default;
~HitTestQueryTest() override = default;
+ void SendHitTestData() {
+ hit_test_query_.OnAggregatedHitTestRegionListUpdated(active_data_);
+ }
+
protected:
HitTestQuery& hit_test_query() { return hit_test_query_; }
- AggregatedHitTestRegion* aggregated_hit_test_region() {
- return static_cast<AggregatedHitTestRegion*>(active_buffer_.get());
- }
- private:
- // testing::Test:
- void SetUp() override {
- uint32_t handle_size = 100;
- size_t num_bytes = handle_size * sizeof(AggregatedHitTestRegion);
- mojo::ScopedSharedBufferHandle active_handle =
- mojo::SharedBufferHandle::Create(num_bytes);
- mojo::ScopedSharedBufferHandle idle_handle =
- mojo::SharedBufferHandle::Create(num_bytes);
- active_buffer_ = active_handle->Map(num_bytes);
- hit_test_query_.OnAggregatedHitTestRegionListUpdated(
- active_handle->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
- handle_size,
- idle_handle->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
- handle_size);
- }
- void TearDown() override {}
+ std::vector<AggregatedHitTestRegion> active_data_;
+ private:
HitTestQuery hit_test_query_;
- mojo::ScopedSharedBufferMapping active_buffer_;
DISALLOW_COPY_AND_ASSIGN(HitTestQueryTest);
};
@@ -59,11 +44,11 @@ TEST_F(HitTestQueryTest, OneSurface) {
FrameSinkId e_id = FrameSinkId(1, 1);
gfx::Rect e_bounds = gfx::Rect(0, 0, 600, 600);
gfx::Transform transform_e_to_e;
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds, transform_e_to_e, 0); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds, transform_e_to_e, 0)); // e
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -74,7 +59,8 @@ TEST_F(HitTestQueryTest, OneSurface) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
// point2 is on the bounds of e so no target found.
Target target2 =
@@ -88,7 +74,8 @@ TEST_F(HitTestQueryTest, OneSurface) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, e_id);
EXPECT_EQ(target3.location_in_target, point3);
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
}
// One embedder with two children.
@@ -110,17 +97,19 @@ TEST_F(HitTestQueryTest, OneEmbedderTwoChildren) {
gfx::Transform transform_e_to_e, transform_e_to_c1, transform_e_to_c2;
transform_e_to_c1.Translate(-100, -100);
transform_e_to_c2.Translate(-300, -300);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 2); // e
- aggregated_hit_test_region_list[1] =
- AggregatedHitTestRegion(c1_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c1_bounds_in_e, transform_e_to_c1, 0); // c1
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(c2_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c2_bounds_in_e, transform_e_to_c2, 0); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 2)); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ c1_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c1_bounds_in_e, transform_e_to_c1, 0)); // c1
+ active_data_.push_back(AggregatedHitTestRegion(
+ c2_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c2_bounds_in_e, transform_e_to_c2, 0)); // c2
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(99, 200);
@@ -132,19 +121,22 @@ TEST_F(HitTestQueryTest, OneEmbedderTwoChildren) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, c1_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(50, 50));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, c2_id);
EXPECT_EQ(target3.location_in_target, gfx::PointF(100, 100));
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point4);
@@ -163,14 +155,15 @@ TEST_F(HitTestQueryTest, OneEmbedderRotatedChild) {
transform_e_to_c.Translate(-100, -100);
transform_e_to_c.Skew(2, 3);
transform_e_to_c.Scale(.5f, .7f);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 1); // e
- aggregated_hit_test_region_list[1] =
- AggregatedHitTestRegion(c_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c_bounds_in_e, transform_e_to_c, 0); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 1)); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ c_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c_bounds_in_e, transform_e_to_c, 0)); // c
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(150, 120); // Point(-22.07, -12.07) after transform.
@@ -180,14 +173,16 @@ TEST_F(HitTestQueryTest, OneEmbedderRotatedChild) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, c_id);
EXPECT_NEAR(target2.location_in_target.x(), 185, .5);
EXPECT_NEAR(target2.location_in_target.y(), 194, .5);
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
}
// One embedder with a clipped child with a tab and transparent background.
@@ -214,20 +209,24 @@ TEST_F(HitTestQueryTest, ClippedChildWithTabAndTransparentBackground) {
transform_c_to_b;
transform_e_to_c.Translate(-200, -100);
transform_c_to_b.Translate(0, -100);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 3); // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
- transform_e_to_c, 2); // c
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c, transform_c_to_a, 0); // a
- aggregated_hit_test_region_list[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c, transform_c_to_b, 0); // b
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 3)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, 2)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -239,25 +238,29 @@ TEST_F(HitTestQueryTest, ClippedChildWithTabAndTransparentBackground) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, a_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(2, 2));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, e_id);
EXPECT_EQ(target3.location_in_target, point3);
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point4);
EXPECT_EQ(target4.frame_sink_id, b_id);
EXPECT_EQ(target4.location_in_target, gfx::PointF(2, 2));
- EXPECT_EQ(target4.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target4.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
}
// One embedder with a clipped child with a tab and transparent background, and
@@ -289,23 +292,28 @@ TEST_F(HitTestQueryTest, ClippedChildWithChildUnderneath) {
transform_e_to_c.Translate(-200, -100);
transform_c_to_b.Translate(0, -100);
transform_e_to_d.Translate(-400, -50);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 4); // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
- transform_e_to_c, 2); // c
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c, transform_c_to_a, 0); // a
- aggregated_hit_test_region_list[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c, transform_c_to_b, 0); // b
- aggregated_hit_test_region_list[4] =
- AggregatedHitTestRegion(d_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- d_bounds_in_e, transform_e_to_d, 0); // d
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 4)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, 2)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ active_data_.push_back(AggregatedHitTestRegion(
+ d_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ d_bounds_in_e, transform_e_to_d, 0)); // d
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -317,25 +325,29 @@ TEST_F(HitTestQueryTest, ClippedChildWithChildUnderneath) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, a_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(2, 2));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, d_id);
EXPECT_EQ(target3.location_in_target, gfx::PointF(50, 100));
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point4);
EXPECT_EQ(target4.frame_sink_id, b_id);
EXPECT_EQ(target4.location_in_target, gfx::PointF(2, 2));
- EXPECT_EQ(target4.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target4.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
}
// Tests transforming location to be in target's coordinate system given the
@@ -355,23 +367,28 @@ TEST_F(HitTestQueryTest, ClippedChildWithChildUnderneathTransform) {
transform_c_to_b, transform_e_to_d;
transform_e_to_c.Translate(-200, -100);
transform_e_to_d.Translate(-400, -50);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 4); // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
- transform_e_to_c, 2); // c
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c, transform_c_to_a, 0); // a
- aggregated_hit_test_region_list[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c, transform_c_to_b, 0); // b
- aggregated_hit_test_region_list[4] =
- AggregatedHitTestRegion(d_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- d_bounds_in_e, transform_e_to_d, 0); // d
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 4)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, 2)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ active_data_.push_back(AggregatedHitTestRegion(
+ d_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ d_bounds_in_e, transform_e_to_d, 0)); // d
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -438,29 +455,37 @@ TEST_F(HitTestQueryTest, ClippedChildrenWithTabAndTransparentBackground) {
transform_c1_to_b.Translate(0, -100);
transform_e_to_c2.Translate(-200, -700);
transform_c2_to_h.Translate(0, -100);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 6); // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
- c1_bounds_in_e, transform_e_to_c1, 2); // c1
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c1, transform_c1_to_a, 0); // a
- aggregated_hit_test_region_list[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c1, transform_c1_to_b, 0); // b
- aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
- c2_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
- c2_bounds_in_e, transform_e_to_c2, 2); // c2
- aggregated_hit_test_region_list[5] =
- AggregatedHitTestRegion(g_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- g_bounds_in_c2, transform_c2_to_g, 0); // g
- aggregated_hit_test_region_list[6] =
- AggregatedHitTestRegion(h_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- h_bounds_in_c2, transform_c2_to_h, 0); // h
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 6)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c1_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 2)); // c1
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c1, transform_c1_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c1, transform_c1_to_b, 0)); // b
+ active_data_.push_back(
+ AggregatedHitTestRegion(c2_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c2_bounds_in_e, transform_e_to_c2, 2)); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ g_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ g_bounds_in_c2, transform_c2_to_g, 0)); // g
+ active_data_.push_back(AggregatedHitTestRegion(
+ h_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ h_bounds_in_c2, transform_c2_to_h, 0)); // h
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -475,43 +500,50 @@ TEST_F(HitTestQueryTest, ClippedChildrenWithTabAndTransparentBackground) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, a_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(2, 2));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, e_id);
EXPECT_EQ(target3.location_in_target, point3);
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point4);
EXPECT_EQ(target4.frame_sink_id, b_id);
EXPECT_EQ(target4.location_in_target, gfx::PointF(2, 2));
- EXPECT_EQ(target4.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target4.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target5 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point5);
EXPECT_EQ(target5.frame_sink_id, g_id);
EXPECT_EQ(target5.location_in_target, gfx::PointF(50, 50));
- EXPECT_EQ(target5.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target5.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target6 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point6);
EXPECT_EQ(target6.frame_sink_id, e_id);
EXPECT_EQ(target6.location_in_target, point6);
- EXPECT_EQ(target6.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target6.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target7 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point7);
EXPECT_EQ(target7.frame_sink_id, h_id);
EXPECT_EQ(target7.location_in_target, gfx::PointF(150, 300));
- EXPECT_EQ(target7.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target7.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
}
// Tests transforming location to be in target's coordinate system given the
@@ -540,29 +572,37 @@ TEST_F(HitTestQueryTest,
transform_c1_to_b.Translate(0, -100);
transform_e_to_c2.Translate(-200, -700);
transform_c2_to_h.Translate(0, -100);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 6); // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
- c1_bounds_in_e, transform_e_to_c1, 2); // c1
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c1, transform_c1_to_a, 0); // a
- aggregated_hit_test_region_list[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c1, transform_c1_to_b, 0); // b
- aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
- c2_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
- c2_bounds_in_e, transform_e_to_c2, 2); // c2
- aggregated_hit_test_region_list[5] =
- AggregatedHitTestRegion(g_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- g_bounds_in_c2, transform_c2_to_g, 0); // g
- aggregated_hit_test_region_list[6] =
- AggregatedHitTestRegion(h_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- h_bounds_in_c2, transform_c2_to_h, 0); // h
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 6)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c1_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 2)); // c1
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c1, transform_c1_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c1, transform_c1_to_b, 0)); // b
+ active_data_.push_back(
+ AggregatedHitTestRegion(c2_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c2_bounds_in_e, transform_e_to_c2, 2)); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ g_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ g_bounds_in_c2, transform_c2_to_g, 0)); // g
+ active_data_.push_back(AggregatedHitTestRegion(
+ h_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ h_bounds_in_c2, transform_c2_to_h, 0)); // h
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -636,26 +676,32 @@ TEST_F(HitTestQueryTest, MultipleLayerChild) {
transform_a_to_b.Translate(-50, -30);
transform_b_to_g.Translate(-150, -200);
transform_e_to_c2.Translate(-400, -50);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 5), // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
- c1_bounds_in_e, transform_e_to_c1, 3); // c1
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c1, transform_c1_to_a, 2); // a
- aggregated_hit_test_region_list[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_a, transform_a_to_b, 1); // b
- aggregated_hit_test_region_list[4] =
- AggregatedHitTestRegion(g_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- g_bounds_in_b, transform_b_to_g, 0); // g
- aggregated_hit_test_region_list[5] =
- AggregatedHitTestRegion(c2_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c2_bounds_in_e, transform_e_to_c2, 0); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 5)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c1_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 3)); // c1
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c1, transform_c1_to_a, 2)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_a, transform_a_to_b, 1)); // b
+ active_data_.push_back(AggregatedHitTestRegion(
+ g_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ g_bounds_in_b, transform_b_to_g, 0)); // g
+ active_data_.push_back(AggregatedHitTestRegion(
+ c2_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c2_bounds_in_e, transform_e_to_c2, 0)); // c2
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -667,25 +713,29 @@ TEST_F(HitTestQueryTest, MultipleLayerChild) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, g_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(0, 20));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, b_id);
EXPECT_EQ(target3.location_in_target, gfx::PointF(400, 220));
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point4);
EXPECT_EQ(target4.frame_sink_id, c2_id);
EXPECT_EQ(target4.location_in_target, gfx::PointF(500, 300));
- EXPECT_EQ(target4.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target4.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
}
// Multiple layers deep of transparent children.
@@ -722,26 +772,35 @@ TEST_F(HitTestQueryTest, MultipleLayerTransparentChild) {
transform_a_to_b.Translate(-50, -30);
transform_b_to_g.Translate(-150, -200);
transform_e_to_c2.Translate(-400, -50);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 5); // e
- aggregated_hit_test_region_list[1] = AggregatedHitTestRegion(
- c1_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore,
- c1_bounds_in_e, transform_e_to_c1, 3); // c1
- aggregated_hit_test_region_list[2] = AggregatedHitTestRegion(
- a_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, a_bounds_in_c1,
- transform_c1_to_a, 2); // a
- aggregated_hit_test_region_list[3] = AggregatedHitTestRegion(
- b_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, b_bounds_in_a,
- transform_a_to_b, 1); // b
- aggregated_hit_test_region_list[4] = AggregatedHitTestRegion(
- g_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, g_bounds_in_b,
- transform_b_to_g, 0); // g
- aggregated_hit_test_region_list[5] =
- AggregatedHitTestRegion(c2_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c2_bounds_in_e, transform_e_to_c2, 0); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 5)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c1_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c1_bounds_in_e, transform_e_to_c1, 3)); // c1
+ active_data_.push_back(
+ AggregatedHitTestRegion(a_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ a_bounds_in_c1, transform_c1_to_a, 2)); // a
+ active_data_.push_back(
+ AggregatedHitTestRegion(b_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ b_bounds_in_a, transform_a_to_b, 1)); // b
+ active_data_.push_back(
+ AggregatedHitTestRegion(g_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ g_bounds_in_b, transform_b_to_g, 0)); // g
+ active_data_.push_back(AggregatedHitTestRegion(
+ c2_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c2_bounds_in_e, transform_e_to_c2, 0)); // c2
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -787,20 +846,24 @@ TEST_F(HitTestQueryTest, InvalidAggregatedHitTestRegionData) {
transform_c_to_b;
transform_e_to_c.Translate(-200, -100);
transform_c_to_b.Translate(0, -100);
- AggregatedHitTestRegion* aggregated_hit_test_region_list_min =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list_min[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 3); // e
- aggregated_hit_test_region_list_min[1] = AggregatedHitTestRegion(
- c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
- transform_e_to_c, INT32_MIN); // c
- aggregated_hit_test_region_list_min[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c, transform_c_to_a, 0); // a
- aggregated_hit_test_region_list_min[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c, transform_c_to_b, 0); // b
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 3)); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, INT32_MIN)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -820,20 +883,25 @@ TEST_F(HitTestQueryTest, InvalidAggregatedHitTestRegionData) {
EXPECT_EQ(target2.location_in_target, gfx::PointF());
EXPECT_FALSE(target2.flags);
- AggregatedHitTestRegion* aggregated_hit_test_region_list_max =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list_max[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, INT32_MAX); // e
- aggregated_hit_test_region_list_max[1] = AggregatedHitTestRegion(
- c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
- transform_e_to_c, 2); // c
- aggregated_hit_test_region_list_max[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c, transform_c_to_a, 0); // a
- aggregated_hit_test_region_list_max[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c, transform_c_to_b, 0); // b
+ active_data_.clear();
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, INT32_MAX)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, 2)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ SendHitTestData();
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
@@ -841,20 +909,25 @@ TEST_F(HitTestQueryTest, InvalidAggregatedHitTestRegionData) {
EXPECT_EQ(target3.location_in_target, gfx::PointF());
EXPECT_FALSE(target3.flags);
- AggregatedHitTestRegion* aggregated_hit_test_region_list_bigger =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list_bigger[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 3); // e
- aggregated_hit_test_region_list_bigger[1] = AggregatedHitTestRegion(
- c_id, mojom::kHitTestChildSurface | mojom::kHitTestIgnore, c_bounds_in_e,
- transform_e_to_c, 3); // c
- aggregated_hit_test_region_list_bigger[2] =
- AggregatedHitTestRegion(a_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- a_bounds_in_c, transform_c_to_a, 0); // a
- aggregated_hit_test_region_list_bigger[3] =
- AggregatedHitTestRegion(b_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- b_bounds_in_c, transform_c_to_b, 0); // b
+ active_data_.clear();
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 3)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, 3)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ SendHitTestData();
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
@@ -874,17 +947,20 @@ TEST_F(HitTestQueryTest, MouseTouchFlags) {
gfx::Transform transform_e_to_e, transform_e_to_c1, transform_e_to_c2;
transform_e_to_c1.Translate(-100, -100);
transform_e_to_c2.Translate(-75, -75);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] = AggregatedHitTestRegion(
- e_id, mojom::kHitTestMine | mojom::kHitTestMouse | mojom::kHitTestTouch,
- e_bounds_in_e, transform_e_to_e, 2); // e
- aggregated_hit_test_region_list[1] =
- AggregatedHitTestRegion(c1_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c1_bounds_in_e, transform_e_to_c1, 0); // c1
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(c2_id, mojom::kHitTestMine | mojom::kHitTestTouch,
- c2_bounds_in_e, transform_e_to_c2, 0); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch,
+ e_bounds_in_e, transform_e_to_e, 2)); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ c1_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c1_bounds_in_e, transform_e_to_c1, 0)); // c1
+ active_data_.push_back(AggregatedHitTestRegion(
+ c2_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestTouch,
+ c2_bounds_in_e, transform_e_to_c2, 0)); // c2
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(80, 80);
@@ -894,37 +970,40 @@ TEST_F(HitTestQueryTest, MouseTouchFlags) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags,
- mojom::kHitTestMine | mojom::kHitTestMouse | mojom::kHitTestTouch);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::TOUCH, point1);
EXPECT_EQ(target2.frame_sink_id, c2_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(5, 5));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestTouch);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestTouch);
Target target3 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target3.frame_sink_id, c1_id);
EXPECT_EQ(target3.location_in_target, gfx::PointF(50, 50));
- EXPECT_EQ(target3.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target4 =
hit_test_query().FindTargetForLocation(EventSource::TOUCH, point2);
EXPECT_EQ(target4.frame_sink_id, c2_id);
EXPECT_EQ(target4.location_in_target, gfx::PointF(75, 75));
- EXPECT_EQ(target4.flags, mojom::kHitTestMine | mojom::kHitTestTouch);
+ EXPECT_EQ(target4.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestTouch);
}
TEST_F(HitTestQueryTest, RootHitTestAskFlag) {
FrameSinkId e_id = FrameSinkId(1, 1);
gfx::Rect e_bounds = gfx::Rect(0, 0, 600, 600);
gfx::Transform transform_e_to_e;
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestAsk | mojom::kHitTestMouse,
- e_bounds, transform_e_to_e, 0); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id, HitTestRegionFlags::kHitTestAsk | HitTestRegionFlags::kHitTestMouse,
+ e_bounds, transform_e_to_e, 0)); // e
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(1, 1);
@@ -935,7 +1014,8 @@ TEST_F(HitTestQueryTest, RootHitTestAskFlag) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestAsk | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestAsk |
+ HitTestRegionFlags::kHitTestMouse);
// point2 is on the bounds of e so no target found.
Target target2 =
@@ -964,17 +1044,19 @@ TEST_F(HitTestQueryTest, ChildHitTestAskFlag) {
gfx::Transform transform_e_to_e, transform_e_to_c1, transform_e_to_c2;
transform_e_to_c1.Translate(-100, -100);
transform_e_to_c2.Translate(-300, -300);
- AggregatedHitTestRegion* aggregated_hit_test_region_list =
- aggregated_hit_test_region();
- aggregated_hit_test_region_list[0] =
- AggregatedHitTestRegion(e_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- e_bounds_in_e, transform_e_to_e, 2); // e
- aggregated_hit_test_region_list[1] =
- AggregatedHitTestRegion(c1_id, mojom::kHitTestMine | mojom::kHitTestMouse,
- c1_bounds_in_e, transform_e_to_c1, 0); // c1
- aggregated_hit_test_region_list[2] =
- AggregatedHitTestRegion(c2_id, mojom::kHitTestAsk | mojom::kHitTestMouse,
- c2_bounds_in_e, transform_e_to_c2, 0); // c2
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 2)); // e
+ active_data_.push_back(AggregatedHitTestRegion(
+ c1_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ c1_bounds_in_e, transform_e_to_c1, 0)); // c1
+ active_data_.push_back(AggregatedHitTestRegion(
+ c2_id,
+ HitTestRegionFlags::kHitTestAsk | HitTestRegionFlags::kHitTestMouse,
+ c2_bounds_in_e, transform_e_to_c2, 0)); // c2
+ SendHitTestData();
// All points are in e's coordinate system when we reach this case.
gfx::PointF point1(99, 200);
@@ -985,13 +1067,15 @@ TEST_F(HitTestQueryTest, ChildHitTestAskFlag) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point1);
EXPECT_EQ(target1.frame_sink_id, e_id);
EXPECT_EQ(target1.location_in_target, point1);
- EXPECT_EQ(target1.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target1.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
Target target2 =
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point2);
EXPECT_EQ(target2.frame_sink_id, c1_id);
EXPECT_EQ(target2.location_in_target, gfx::PointF(50, 50));
- EXPECT_EQ(target2.flags, mojom::kHitTestMine | mojom::kHitTestMouse);
+ EXPECT_EQ(target2.flags, HitTestRegionFlags::kHitTestMine |
+ HitTestRegionFlags::kHitTestMouse);
// point3 is inside c2 but we have to ask clients for targeting. Event
// shouldn't go back to e.
@@ -999,7 +1083,82 @@ TEST_F(HitTestQueryTest, ChildHitTestAskFlag) {
hit_test_query().FindTargetForLocation(EventSource::MOUSE, point3);
EXPECT_EQ(target3.frame_sink_id, c2_id);
EXPECT_EQ(target3.location_in_target, gfx::PointF(100, 100));
- EXPECT_EQ(target3.flags, mojom::kHitTestAsk | mojom::kHitTestMouse);
+ EXPECT_EQ(target3.flags, HitTestRegionFlags::kHitTestAsk |
+ HitTestRegionFlags::kHitTestMouse);
+}
+
+// Tests getting the transform from root to a given target.
+TEST_F(HitTestQueryTest, GetTransformToTarget) {
+ FrameSinkId e_id = FrameSinkId(1, 1);
+ FrameSinkId c_id = FrameSinkId(2, 2);
+ FrameSinkId a_id = FrameSinkId(3, 3);
+ FrameSinkId b_id = FrameSinkId(4, 4);
+ FrameSinkId d_id = FrameSinkId(5, 5);
+ gfx::Rect e_bounds_in_e = gfx::Rect(0, 0, 600, 600);
+ gfx::Rect c_bounds_in_e = gfx::Rect(0, 50, 800, 800);
+ gfx::Rect a_bounds_in_c = gfx::Rect(0, 0, 200, 100);
+ gfx::Rect b_bounds_in_c = gfx::Rect(0, 100, 800, 600);
+ gfx::Rect d_bounds_in_e = gfx::Rect(0, 0, 800, 800);
+ gfx::Transform transform_e_to_e, transform_e_to_c, transform_c_to_a,
+ transform_c_to_b, transform_e_to_d;
+ transform_e_to_c.Translate(-200, -100);
+ transform_e_to_d.Translate(-400, -50);
+ transform_c_to_b.Skew(2, 3);
+ transform_c_to_b.Scale(.5f, .7f);
+ active_data_.push_back(AggregatedHitTestRegion(
+ e_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ e_bounds_in_e, transform_e_to_e, 4)); // e
+ active_data_.push_back(
+ AggregatedHitTestRegion(c_id,
+ HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ c_bounds_in_e, transform_e_to_c, 2)); // c
+ active_data_.push_back(AggregatedHitTestRegion(
+ a_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ a_bounds_in_c, transform_c_to_a, 0)); // a
+ active_data_.push_back(AggregatedHitTestRegion(
+ b_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ b_bounds_in_c, transform_c_to_b, 0)); // b
+ active_data_.push_back(AggregatedHitTestRegion(
+ d_id,
+ HitTestRegionFlags::kHitTestMine | HitTestRegionFlags::kHitTestMouse,
+ d_bounds_in_e, transform_e_to_d, 0)); // d
+ SendHitTestData();
+
+ // Check that we can get the correct transform to all regions.
+ gfx::Transform transform_to_e;
+ EXPECT_TRUE(hit_test_query().GetTransformToTarget(e_id, &transform_to_e));
+ EXPECT_EQ(transform_to_e, gfx::Transform());
+
+ gfx::Transform transform_to_c;
+ gfx::Transform expected_transform_to_c;
+ expected_transform_to_c.Translate(-200, -150);
+ EXPECT_TRUE(hit_test_query().GetTransformToTarget(c_id, &transform_to_c));
+ EXPECT_EQ(transform_to_c, expected_transform_to_c);
+
+ gfx::Transform transform_to_a;
+ gfx::Transform expected_transform_to_a;
+ expected_transform_to_a.Translate(-200, -150);
+ EXPECT_TRUE(hit_test_query().GetTransformToTarget(a_id, &transform_to_a));
+ EXPECT_EQ(transform_to_a, expected_transform_to_a);
+
+ gfx::Transform transform_to_b;
+ gfx::Transform expected_transform_to_b;
+ expected_transform_to_b.Translate(-200, -150);
+ expected_transform_to_b.Translate(0, -100);
+ expected_transform_to_b.ConcatTransform(transform_c_to_b);
+ EXPECT_TRUE(hit_test_query().GetTransformToTarget(b_id, &transform_to_b));
+ // Use ToString so that we can compare float.
+ EXPECT_EQ(transform_to_b.ToString(), expected_transform_to_b.ToString());
+
+ gfx::Transform transform_to_d;
+ gfx::Transform expected_transform_to_d;
+ expected_transform_to_d.Translate(-400, -50);
+ EXPECT_TRUE(hit_test_query().GetTransformToTarget(d_id, &transform_to_d));
+ EXPECT_EQ(transform_to_d, expected_transform_to_d);
}
} // namespace test
diff --git a/chromium/components/viz/host/host_frame_sink_manager.cc b/chromium/components/viz/host/host_frame_sink_manager.cc
index 747231a42b8..5910a73f6da 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager.cc
@@ -7,6 +7,7 @@
#include <utility>
#include "base/sequenced_task_runner.h"
+#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "components/viz/common/surfaces/surface_info.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
@@ -136,7 +137,7 @@ void HostFrameSinkManager::CreateRootCompositorFrameSink(
// the old CompositorFrameSink first.
if (data.has_created_compositor_frame_sink) {
frame_sink_manager_->DestroyCompositorFrameSink(frame_sink_id,
- base::OnceClosure());
+ base::DoNothing());
}
data.is_root = true;
@@ -159,7 +160,7 @@ void HostFrameSinkManager::CreateCompositorFrameSink(
// the old CompositorFrameSink first.
if (data.has_created_compositor_frame_sink) {
frame_sink_manager_->DestroyCompositorFrameSink(frame_sink_id,
- base::OnceClosure());
+ base::DoNothing());
}
data.is_root = false;
@@ -181,9 +182,16 @@ void HostFrameSinkManager::OnFrameTokenChanged(const FrameSinkId& frame_sink_id,
data.client->OnFrameTokenChanged(frame_token);
}
-void HostFrameSinkManager::RegisterFrameSinkHierarchy(
+bool HostFrameSinkManager::RegisterFrameSinkHierarchy(
const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id) {
+ auto iter = frame_sink_data_map_.find(parent_frame_sink_id);
+ // |parent_frame_sink_id| isn't registered so it can't embed anything.
+ if (iter == frame_sink_data_map_.end() ||
+ !iter->second.IsFrameSinkRegistered()) {
+ return false;
+ }
+
// Register and store the parent.
frame_sink_manager_->RegisterFrameSinkHierarchy(parent_frame_sink_id,
child_frame_sink_id);
@@ -193,10 +201,11 @@ void HostFrameSinkManager::RegisterFrameSinkHierarchy(
DCHECK(!base::ContainsValue(child_data.parents, parent_frame_sink_id));
child_data.parents.push_back(parent_frame_sink_id);
- FrameSinkData& parent_data = frame_sink_data_map_[parent_frame_sink_id];
- DCHECK(parent_data.IsFrameSinkRegistered());
+ FrameSinkData& parent_data = iter->second;
DCHECK(!base::ContainsValue(parent_data.children, child_frame_sink_id));
parent_data.children.push_back(child_frame_sink_id);
+
+ return true;
}
void HostFrameSinkManager::UnregisterFrameSinkHierarchy(
@@ -249,6 +258,16 @@ void HostFrameSinkManager::CreateVideoCapturer(
frame_sink_manager_->CreateVideoCapturer(std::move(request));
}
+std::unique_ptr<ClientFrameSinkVideoCapturer>
+HostFrameSinkManager::CreateVideoCapturer() {
+ return std::make_unique<ClientFrameSinkVideoCapturer>(base::BindRepeating(
+ [](base::WeakPtr<HostFrameSinkManager> self,
+ mojom::FrameSinkVideoCapturerRequest request) {
+ self->CreateVideoCapturer(std::move(request));
+ },
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
void HostFrameSinkManager::EvictSurfaces(
const std::vector<SurfaceId>& surface_ids) {
frame_sink_manager_->EvictSurfaces(surface_ids);
@@ -405,30 +424,14 @@ void HostFrameSinkManager::OnFirstSurfaceActivation(
void HostFrameSinkManager::OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) {
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) {
auto iter = display_hit_test_query_.find(frame_sink_id);
// The corresponding HitTestQuery has already been deleted, so drop the
// in-flight hit-test data.
if (iter == display_hit_test_query_.end())
return;
- iter->second->OnAggregatedHitTestRegionListUpdated(
- std::move(active_handle), active_handle_size, std::move(idle_handle),
- idle_handle_size);
-}
-
-void HostFrameSinkManager::SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) {
- auto iter = display_hit_test_query_.find(frame_sink_id);
- // The corresponding HitTestQuery has already been deleted, so drop the
- // in-flight hit-test data.
- if (iter == display_hit_test_query_.end())
- return;
- iter->second->SwitchActiveAggregatedHitTestRegionList(active_handle_index);
+ iter->second->OnAggregatedHitTestRegionListUpdated(hit_test_data);
}
HostFrameSinkManager::FrameSinkData::FrameSinkData() = default;
diff --git a/chromium/components/viz/host/host_frame_sink_manager.h b/chromium/components/viz/host/host_frame_sink_manager.h
index 31233ea804a..afe8caa1810 100644
--- a/chromium/components/viz/host/host_frame_sink_manager.h
+++ b/chromium/components/viz/host/host_frame_sink_manager.h
@@ -17,6 +17,7 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "components/viz/host/client_frame_sink_video_capturer.h"
#include "components/viz/host/hit_test/hit_test_query.h"
#include "components/viz/host/host_frame_sink_client.h"
#include "components/viz/host/viz_host_export.h"
@@ -114,9 +115,15 @@ class VIZ_HOST_EXPORT HostFrameSinkManager
mojom::CompositorFrameSinkRequest request,
mojom::CompositorFrameSinkClientPtr client);
- // Registers frame sink hierarchy. Both parent and child FrameSinkIds must be
- // registered before calling. A frame sink can have multiple parents.
- void RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
+ // Registers FrameSink hierarchy. It's expected that the parent will embed
+ // the child. If |parent_frame_sink_id| is registered then it will be added as
+ // a parent of |child_frame_sink_id| and the function will return true. If
+ // |parent_frame_sink_id| is not registered then the function will return
+ // false.
+ //
+ // |child_frame_sink_id| must be registered before calling. A frame sink
+ // can have multiple parents.
+ bool RegisterFrameSinkHierarchy(const FrameSinkId& parent_frame_sink_id,
const FrameSinkId& child_frame_sink_id);
// Unregisters FrameSink hierarchy. Client must have registered frame sink
@@ -134,9 +141,15 @@ class VIZ_HOST_EXPORT HostFrameSinkManager
// Asks viz to send updates regarding video activity to |observer|.
void AddVideoDetectorObserver(mojom::VideoDetectorObserverPtr observer);
- // Creates a FrameSinkVideoCapturer instance.
+ // Creates a FrameSinkVideoCapturer instance in viz.
void CreateVideoCapturer(mojom::FrameSinkVideoCapturerRequest request);
+ // Creates a FrameSinkVideoCapturer instance in viz and returns a
+ // ClientFrameSinkVideoCapturer that's connected to it. Clients should prefer
+ // this version because ClientFrameSinkVideoCapturer is resilient to viz
+ // crashes.
+ std::unique_ptr<ClientFrameSinkVideoCapturer> CreateVideoCapturer();
+
// Marks the given SurfaceIds for destruction.
void EvictSurfaces(const std::vector<SurfaceId>& surface_ids);
@@ -228,13 +241,7 @@ class VIZ_HOST_EXPORT HostFrameSinkManager
void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
void OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_sizes) override;
- void SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) override;
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) override;
// This will point to |frame_sink_manager_ptr_| if using Mojo or
// |frame_sink_manager_impl_| if directly connected. Use this to make function
diff --git a/chromium/components/viz/host/host_frame_sink_manager_unittest.cc b/chromium/components/viz/host/host_frame_sink_manager_unittest.cc
index 77d8a4d16d7..0e0bc1f62af 100644
--- a/chromium/components/viz/host/host_frame_sink_manager_unittest.cc
+++ b/chromium/components/viz/host/host_frame_sink_manager_unittest.cc
@@ -625,8 +625,8 @@ TEST_F(HostFrameSinkManagerRemoteTest, DeletedHitTestQuery) {
run_loop.Run();
}
- GetFrameSinkManagerClient()->SwitchActiveAggregatedHitTestRegionList(
- kFrameSinkParent1, 0);
+ GetFrameSinkManagerClient()->OnAggregatedHitTestRegionListUpdated(
+ kFrameSinkParent1, {});
// Continue to send hit-test data to HitTestQuery associated with
// kFrameSinkChild1.
@@ -634,8 +634,8 @@ TEST_F(HostFrameSinkManagerRemoteTest, DeletedHitTestQuery) {
// Invalidating kFrameSinkChild1 would delete the corresponding HitTestQuery,
// so further msgs to that HitTestQuery should be dropped.
EXPECT_FALSE(DisplayHitTestQueryExists(kFrameSinkParent1));
- GetFrameSinkManagerClient()->SwitchActiveAggregatedHitTestRegionList(
- kFrameSinkParent1, 1);
+ GetFrameSinkManagerClient()->OnAggregatedHitTestRegionListUpdated(
+ kFrameSinkParent1, {});
}
// Verify that HostFrameSinkManager assigns temporary references when connected
diff --git a/chromium/components/viz/host/layered_window_updater_impl.cc b/chromium/components/viz/host/layered_window_updater_impl.cc
new file mode 100644
index 00000000000..d3a49ed8be8
--- /dev/null
+++ b/chromium/components/viz/host/layered_window_updater_impl.cc
@@ -0,0 +1,79 @@
+// 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 "components/viz/host/layered_window_updater_impl.h"
+
+#include "base/memory/shared_memory.h"
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "skia/ext/platform_canvas.h"
+#include "skia/ext/skia_utils_win.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+
+namespace viz {
+
+LayeredWindowUpdaterImpl::LayeredWindowUpdaterImpl(
+ HWND hwnd,
+ mojom::LayeredWindowUpdaterRequest request)
+ : hwnd_(hwnd), binding_(this, std::move(request)) {}
+
+LayeredWindowUpdaterImpl::~LayeredWindowUpdaterImpl() = default;
+
+void LayeredWindowUpdaterImpl::OnAllocatedSharedMemory(
+ const gfx::Size& pixel_size,
+ mojo::ScopedSharedBufferHandle scoped_buffer_handle) {
+ canvas_.reset();
+
+ // Make sure |pixel_size| is sane.
+ size_t expected_bytes;
+ bool size_result = ResourceSizes::MaybeSizeInBytes(
+ pixel_size, ResourceFormat::RGBA_8888, &expected_bytes);
+ if (!size_result)
+ return;
+
+ base::SharedMemoryHandle shm_handle;
+ MojoResult unwrap_result = mojo::UnwrapSharedMemoryHandle(
+ std::move(scoped_buffer_handle), &shm_handle, nullptr, nullptr);
+ if (unwrap_result != MOJO_RESULT_OK)
+ return;
+
+ // The SkCanvas maps shared memory on creation and unmaps on destruction.
+ canvas_ = skia::CreatePlatformCanvasWithSharedSection(
+ pixel_size.width(), pixel_size.height(), true, shm_handle.GetHandle(),
+ skia::RETURN_NULL_ON_FAILURE);
+
+ shm_handle.Close();
+}
+
+void LayeredWindowUpdaterImpl::Draw(DrawCallback draw_callback) {
+ TRACE_EVENT0("viz", "LayeredWindowUpdaterImpl::Draw");
+
+ if (!canvas_) {
+ std::move(draw_callback).Run();
+ return;
+ }
+
+ // Set WS_EX_LAYERED extended window style if not already set.
+ DWORD style = GetWindowLong(hwnd_, GWL_EXSTYLE);
+ DCHECK(!(style & WS_EX_COMPOSITED));
+ if (!(style & WS_EX_LAYERED))
+ SetWindowLong(hwnd_, GWL_EXSTYLE, style | WS_EX_LAYERED);
+
+ // Draw to the HWND. If |canvas_| size doesn't match HWND size then it will be
+ // clipped or guttered accordingly.
+ RECT wr;
+ GetWindowRect(hwnd_, &wr);
+ SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
+ POINT position = {wr.left, wr.top};
+ POINT zero = {0, 0};
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
+ HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get());
+ UpdateLayeredWindow(hwnd_, nullptr, &position, &size, dib_dc, &zero,
+ RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
+
+ std::move(draw_callback).Run();
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/host/layered_window_updater_impl.h b/chromium/components/viz/host/layered_window_updater_impl.h
new file mode 100644
index 00000000000..93c52d2b928
--- /dev/null
+++ b/chromium/components/viz/host/layered_window_updater_impl.h
@@ -0,0 +1,48 @@
+// 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 COMPONENTS_VIZ_HOST_LAYERED_WINDOW_UPDATER_IMPL_H_
+#define COMPONENTS_VIZ_HOST_LAYERED_WINDOW_UPDATER_IMPL_H_
+
+#include <windows.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "components/viz/host/viz_host_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h"
+#include "ui/gfx/geometry/size.h"
+
+class SkCanvas;
+
+namespace viz {
+
+// Makes layered window drawing syscalls. Updates a layered window from shared
+// memory backing buffer that was drawn into by the GPU process. This is
+// required as UpdateLayeredWindow() syscall is blocked by the GPU sandbox.
+class VIZ_HOST_EXPORT LayeredWindowUpdaterImpl
+ : public mojom::LayeredWindowUpdater {
+ public:
+ LayeredWindowUpdaterImpl(HWND hwnd,
+ mojom::LayeredWindowUpdaterRequest request);
+ ~LayeredWindowUpdaterImpl() override;
+
+ // mojom::LayeredWindowUpdater implementation.
+ void OnAllocatedSharedMemory(
+ const gfx::Size& pixel_size,
+ mojo::ScopedSharedBufferHandle scoped_buffer_handle) override;
+ void Draw(DrawCallback draw_callback) override;
+
+ private:
+ const HWND hwnd_;
+ mojo::Binding<mojom::LayeredWindowUpdater> binding_;
+ std::unique_ptr<SkCanvas> canvas_;
+
+ DISALLOW_COPY_AND_ASSIGN(LayeredWindowUpdaterImpl);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_HOST_LAYERED_WINDOW_UPDATER_IMPL_H_
diff --git a/chromium/components/viz/host/renderer_settings_creation.cc b/chromium/components/viz/host/renderer_settings_creation.cc
index 0a147eedb66..eca60205352 100644
--- a/chromium/components/viz/host/renderer_settings_creation.cc
+++ b/chromium/components/viz/host/renderer_settings_creation.cc
@@ -49,6 +49,7 @@ RendererSettings CreateRendererSettings() {
renderer_settings.finish_rendering_on_resize = true;
#elif defined(OS_MACOSX)
renderer_settings.release_overlay_resources_after_gpu_query = true;
+ renderer_settings.auto_resize_output_surface = false;
#endif
renderer_settings.tint_gl_composited_content =
command_line->HasSwitch(switches::kTintGlCompositedContent);
@@ -57,10 +58,9 @@ RendererSettings CreateRendererSettings() {
renderer_settings.enable_draw_occlusion = features::IsDrawOcclusionEnabled();
renderer_settings.allow_antialiasing =
!command_line->HasSwitch(switches::kDisableCompositedAntialiasing);
- renderer_settings.use_skia_renderer =
- command_line->HasSwitch(switches::kUseSkiaRenderer);
+ renderer_settings.use_skia_renderer = features::IsUsingSkiaRenderer();
renderer_settings.use_skia_deferred_display_list =
- command_line->HasSwitch(switches::kUseSkiaDeferredDisplayList);
+ features::IsUsingSkiaDeferredDisplayList();
#if defined(OS_MACOSX)
renderer_settings.allow_overlays =
ui::RemoteLayerAPISupported() &&
diff --git a/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc b/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
index b2a5007f6fd..9d3479bd508 100644
--- a/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
+++ b/chromium/components/viz/host/server_gpu_memory_buffer_manager_unittest.cc
@@ -106,7 +106,8 @@ class TestGpuService : public mojom::GpuService {
void RequestCompleteGpuInfo(
RequestCompleteGpuInfoCallback callback) override {}
- void GetGpuSupportedRuntimeVersion() override {}
+ void GetGpuSupportedRuntimeVersion(
+ GetGpuSupportedRuntimeVersionCallback callback) override {}
void RequestHDRStatus(RequestHDRStatusCallback callback) override {}
@@ -122,8 +123,12 @@ class TestGpuService : public mojom::GpuService {
void DestroyAllChannels() override {}
+ void OnBackgroundCleanup() override {}
+
void OnBackgrounded() override {}
+ void OnForegrounded() override {}
+
void Crash() override {}
void Hang() override {}
diff --git a/chromium/components/viz/service/BUILD.gn b/chromium/components/viz/service/BUILD.gn
index 154fb88b827..cfec9fbec12 100644
--- a/chromium/components/viz/service/BUILD.gn
+++ b/chromium/components/viz/service/BUILD.gn
@@ -27,6 +27,8 @@ viz_component("service") {
"display/display.cc",
"display/display.h",
"display/display_client.h",
+ "display/display_resource_provider.cc",
+ "display/display_resource_provider.h",
"display/display_scheduler.cc",
"display/display_scheduler.h",
"display/draw_polygon.cc",
@@ -48,6 +50,8 @@ viz_component("service") {
"display/output_surface_client.h",
"display/output_surface_frame.cc",
"display/output_surface_frame.h",
+ "display/overlay_candidate.cc",
+ "display/overlay_candidate.h",
"display/overlay_candidate_validator.h",
"display/overlay_processor.cc",
"display/overlay_processor.h",
@@ -69,6 +73,8 @@ viz_component("service") {
"display/scoped_render_pass_texture.h",
"display/shader.cc",
"display/shader.h",
+ "display/skia_output_surface.cc",
+ "display/skia_output_surface.h",
"display/skia_renderer.cc",
"display/skia_renderer.h",
"display/software_output_device.cc",
@@ -101,10 +107,14 @@ viz_component("service") {
"display_embedder/in_process_gpu_memory_buffer_manager.h",
"display_embedder/server_shared_bitmap_manager.cc",
"display_embedder/server_shared_bitmap_manager.h",
- "display_embedder/shared_bitmap_allocation_notifier_impl.cc",
- "display_embedder/shared_bitmap_allocation_notifier_impl.h",
+ "display_embedder/skia_output_surface_impl.cc",
+ "display_embedder/skia_output_surface_impl.h",
+ "display_embedder/skia_output_surface_impl_on_gpu.cc",
+ "display_embedder/skia_output_surface_impl_on_gpu.h",
"display_embedder/software_output_surface.cc",
"display_embedder/software_output_surface.h",
+ "display_embedder/viz_process_context_provider.cc",
+ "display_embedder/viz_process_context_provider.h",
"frame_sinks/compositor_frame_sink_impl.cc",
"frame_sinks/compositor_frame_sink_impl.h",
"frame_sinks/compositor_frame_sink_support.cc",
@@ -168,12 +178,16 @@ viz_component("service") {
"//cc/paint",
"//components/crash/core/common:crash_key",
"//components/viz/common",
+ "//gpu/command_buffer/client:gles2_implementation",
+ "//gpu/command_buffer/client:raster",
+ "//gpu/command_buffer/service:gles2",
"//gpu/ipc:gl_in_process_context",
# Note that dependency on //gpu/ipc/client is for GpuMemoryBufferImpl. This
# dependency should not be in public_deps.
"//gpu/ipc/client",
"//gpu/ipc/service",
+ "//gpu/skia_bindings:skia_bindings",
"//gpu/vulkan:buildflags",
"//media",
"//media/capture:capture_lib",
@@ -249,6 +263,8 @@ viz_component("service") {
"display_embedder/compositor_overlay_candidate_validator_win.h",
"display_embedder/gl_output_surface_win.cc",
"display_embedder/gl_output_surface_win.h",
+ "display_embedder/output_device_backing.cc",
+ "display_embedder/output_device_backing.h",
"display_embedder/software_output_device_win.cc",
"display_embedder/software_output_device_win.h",
]
@@ -264,6 +280,7 @@ viz_source_set("unit_tests") {
sources = [
"display/bsp_tree_unittest.cc",
"display/copy_output_scaling_pixeltest.cc",
+ "display/display_resource_provider_unittest.cc",
"display/display_scheduler_unittest.cc",
"display/display_unittest.cc",
"display/draw_polygon_unittest.cc",
@@ -343,6 +360,10 @@ viz_source_set("unit_tests") {
sources += [ "display_embedder/software_output_device_mac_unittest.mm" ]
libs = [ "IOSurface.framework" ]
}
+
+ if (is_win) {
+ sources += [ "display_embedder/output_device_backing_unittest.cc" ]
+ }
}
viz_source_set("perf_tests") {
diff --git a/chromium/components/viz/service/display/DEPS b/chromium/components/viz/service/display/DEPS
index 314ebb3a28c..3560a35a10b 100644
--- a/chromium/components/viz/service/display/DEPS
+++ b/chromium/components/viz/service/display/DEPS
@@ -19,6 +19,7 @@ include_rules = [
"+ui/latency",
"+ui/gl/ca_renderer_layer_params.h",
"+ui/gl/dc_renderer_layer_params.h",
+ "+ui/gl/trace_util.h",
]
specific_include_rules = {
diff --git a/chromium/components/viz/service/display/bsp_tree_perftest.cc b/chromium/components/viz/service/display/bsp_tree_perftest.cc
index 76ea2e10eff..93df78fa388 100644
--- a/chromium/components/viz/service/display/bsp_tree_perftest.cc
+++ b/chromium/components/viz/service/display/bsp_tree_perftest.cc
@@ -59,7 +59,7 @@ class BspTreePerfTest : public cc::LayerTreeTest {
void ReadTestFile(const std::string& name) {
base::FilePath test_data_dir;
- ASSERT_TRUE(PathService::Get(Paths::DIR_TEST_DATA, &test_data_dir));
+ ASSERT_TRUE(base::PathService::Get(Paths::DIR_TEST_DATA, &test_data_dir));
base::FilePath json_file = test_data_dir.AppendASCII(name + ".json");
ASSERT_TRUE(base::ReadFileToString(json_file, &json_));
}
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.cc b/chromium/components/viz/service/display/ca_layer_overlay.cc
index eb6c8aa9982..284ccf3a565 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.cc
+++ b/chromium/components/viz/service/display/ca_layer_overlay.cc
@@ -7,12 +7,12 @@
#include <algorithm>
#include "base/metrics/histogram_macros.h"
-#include "cc/resources/display_resource_provider.h"
#include "components/viz/common/quads/render_pass_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/stream_video_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
namespace viz {
@@ -75,7 +75,7 @@ bool FilterOperationSupported(const cc::FilterOperation& operation) {
}
CALayerResult FromRenderPassQuad(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const RenderPassDrawQuad* quad,
const base::flat_map<RenderPassId, cc::FilterOperations*>&
render_pass_filters,
@@ -104,10 +104,9 @@ CALayerResult FromRenderPassQuad(
return CA_LAYER_SUCCESS;
}
-CALayerResult FromStreamVideoQuad(
- cc::DisplayResourceProvider* resource_provider,
- const StreamVideoDrawQuad* quad,
- CALayerOverlay* ca_layer_overlay) {
+CALayerResult FromStreamVideoQuad(DisplayResourceProvider* resource_provider,
+ const StreamVideoDrawQuad* quad,
+ CALayerOverlay* ca_layer_overlay) {
unsigned resource_id = quad->resource_id();
if (!resource_provider->IsOverlayCandidate(resource_id))
return CA_LAYER_FAILED_STREAM_VIDEO_NOT_CANDIDATE;
@@ -132,7 +131,7 @@ CALayerResult FromSolidColorDrawQuad(const SolidColorDrawQuad* quad,
return CA_LAYER_SUCCESS;
}
-CALayerResult FromTextureQuad(cc::DisplayResourceProvider* resource_provider,
+CALayerResult FromTextureQuad(DisplayResourceProvider* resource_provider,
const TextureDrawQuad* quad,
CALayerOverlay* ca_layer_overlay) {
unsigned resource_id = quad->resource_id();
@@ -160,7 +159,7 @@ CALayerResult FromTextureQuad(cc::DisplayResourceProvider* resource_provider,
return CA_LAYER_SUCCESS;
}
-CALayerResult FromTileQuad(cc::DisplayResourceProvider* resource_provider,
+CALayerResult FromTileQuad(DisplayResourceProvider* resource_provider,
const TileDrawQuad* quad,
CALayerOverlay* ca_layer_overlay) {
unsigned resource_id = quad->resource_id();
@@ -177,7 +176,7 @@ CALayerResult FromTileQuad(cc::DisplayResourceProvider* resource_provider,
class CALayerOverlayProcessor {
public:
CALayerResult FromDrawQuad(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const DrawQuad* quad,
const base::flat_map<RenderPassId, cc::FilterOperations*>&
@@ -277,7 +276,7 @@ CALayerOverlay::CALayerOverlay(const CALayerOverlay& other) = default;
CALayerOverlay::~CALayerOverlay() {}
bool ProcessForCALayerOverlays(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const QuadList& quad_list,
const base::flat_map<RenderPassId, cc::FilterOperations*>&
diff --git a/chromium/components/viz/service/display/ca_layer_overlay.h b/chromium/components/viz/service/display/ca_layer_overlay.h
index 248fbeeebd3..ac52d0eb783 100644
--- a/chromium/components/viz/service/display/ca_layer_overlay.h
+++ b/chromium/components/viz/service/display/ca_layer_overlay.h
@@ -14,11 +14,8 @@
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gl/ca_renderer_layer_params.h"
-namespace cc {
-class DisplayResourceProvider;
-}
-
namespace viz {
+class DisplayResourceProvider;
class DrawQuad;
class RenderPassDrawQuad;
@@ -77,7 +74,7 @@ typedef std::vector<CALayerOverlay> CALayerOverlayList;
// Returns true if all quads in the root render pass have been replaced by
// CALayerOverlays.
bool ProcessForCALayerOverlays(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
const QuadList& quad_list,
const base::flat_map<RenderPassId, cc::FilterOperations*>&
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.cc b/chromium/components/viz/service/display/dc_layer_overlay.cc
index 592eb099581..288b1703c71 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.cc
+++ b/chromium/components/viz/service/display/dc_layer_overlay.cc
@@ -6,10 +6,10 @@
#include "base/metrics/histogram_macros.h"
#include "cc/base/math_util.h"
-#include "cc/resources/display_resource_provider.h"
#include "components/viz/common/quads/render_pass_draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/yuv_video_draw_quad.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gl/gl_switches.h"
@@ -19,18 +19,19 @@ namespace viz {
namespace {
DCLayerOverlayProcessor::DCLayerResult FromYUVQuad(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const YUVVideoDrawQuad* quad,
- DCLayerOverlay* ca_layer_overlay) {
+ DCLayerOverlay* dc_layer_overlay) {
for (const auto& resource : quad->resources) {
if (!resource_provider->IsOverlayCandidate(resource))
return DCLayerOverlayProcessor::DC_LAYER_FAILED_TEXTURE_NOT_CANDIDATE;
}
- ca_layer_overlay->resources = quad->resources;
- ca_layer_overlay->contents_rect = quad->ya_tex_coord_rect;
- ca_layer_overlay->filter = GL_LINEAR;
- ca_layer_overlay->color_space = quad->video_color_space;
- ca_layer_overlay->require_overlay = quad->require_overlay;
+ dc_layer_overlay->resources = quad->resources;
+ dc_layer_overlay->contents_rect = quad->ya_tex_coord_rect;
+ dc_layer_overlay->filter = GL_LINEAR;
+ dc_layer_overlay->color_space = quad->video_color_space;
+ dc_layer_overlay->require_overlay = quad->require_overlay;
+ dc_layer_overlay->is_protected_video = quad->is_protected_video;
return DCLayerOverlayProcessor::DC_LAYER_SUCCESS;
}
@@ -90,11 +91,11 @@ DCLayerOverlayProcessor::DCLayerOverlayProcessor() = default;
DCLayerOverlayProcessor::~DCLayerOverlayProcessor() = default;
DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
QuadList::ConstIterator quad_list_begin,
QuadList::ConstIterator quad,
- DCLayerOverlay* ca_layer_overlay) {
+ DCLayerOverlay* dc_layer_overlay) {
if (quad->shared_quad_state->blend_mode != SkBlendMode::kSrcOver)
return DC_LAYER_FAILED_QUAD_BLEND_MODE;
@@ -103,7 +104,7 @@ DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad(
case DrawQuad::YUV_VIDEO_CONTENT:
result =
FromYUVQuad(resource_provider, YUVVideoDrawQuad::MaterialCast(*quad),
- ca_layer_overlay);
+ dc_layer_overlay);
break;
default:
return DC_LAYER_FAILED_UNSUPPORTED_QUAD;
@@ -123,19 +124,19 @@ DCLayerOverlayProcessor::DCLayerResult DCLayerOverlayProcessor::FromDrawQuad(
overlay_shared_state->transform =
quad->shared_quad_state->quad_to_target_transform.matrix();
- ca_layer_overlay->shared_state = overlay_shared_state;
- ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
+ dc_layer_overlay->shared_state = overlay_shared_state;
+ dc_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
return result;
}
void DCLayerOverlayProcessor::Process(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
RenderPassList* render_passes,
gfx::Rect* overlay_damage_rect,
gfx::Rect* damage_rect,
- DCLayerOverlayList* ca_layer_overlays) {
+ DCLayerOverlayList* dc_layer_overlays) {
DCHECK(pass_info_.empty());
processed_overlay_in_frame_ = false;
if (base::FeatureList::IsEnabled(
@@ -145,12 +146,12 @@ void DCLayerOverlayProcessor::Process(
ProcessRenderPass(resource_provider, display_rect, pass.get(), is_root,
overlay_damage_rect,
is_root ? damage_rect : &pass->damage_rect,
- ca_layer_overlays);
+ dc_layer_overlays);
}
} else {
ProcessRenderPass(resource_provider, display_rect,
render_passes->back().get(), true, overlay_damage_rect,
- damage_rect, ca_layer_overlays);
+ damage_rect, dc_layer_overlays);
}
pass_info_.clear();
}
@@ -218,13 +219,13 @@ QuadList::Iterator DCLayerOverlayProcessor::ProcessRenderPassDrawQuad(
}
void DCLayerOverlayProcessor::ProcessRenderPass(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
RenderPass* render_pass,
bool is_root,
gfx::Rect* overlay_damage_rect,
gfx::Rect* damage_rect,
- DCLayerOverlayList* ca_layer_overlays) {
+ DCLayerOverlayList* dc_layer_overlays) {
gfx::Rect this_frame_underlay_rect;
QuadList* quad_list = &render_pass->quad_list;
@@ -286,7 +287,7 @@ void DCLayerOverlayProcessor::ProcessRenderPass(
overlay_damage_rect->Union(rect_in_root);
RecordDCLayerResult(DC_LAYER_SUCCESS);
- ca_layer_overlays->push_back(dc_layer);
+ dc_layer_overlays->push_back(dc_layer);
if (!base::FeatureList::IsEnabled(
features::kDirectCompositionNonrootOverlays)) {
// Only allow one overlay for now.
diff --git a/chromium/components/viz/service/display/dc_layer_overlay.h b/chromium/components/viz/service/display/dc_layer_overlay.h
index 280b8dfe2ff..34d118dccd0 100644
--- a/chromium/components/viz/service/display/dc_layer_overlay.h
+++ b/chromium/components/viz/service/display/dc_layer_overlay.h
@@ -14,11 +14,8 @@
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gl/dc_renderer_layer_params.h"
-namespace cc {
-class DisplayResourceProvider;
-}
-
namespace viz {
+class DisplayResourceProvider;
class VIZ_SERVICE_EXPORT DCLayerOverlaySharedState
: public base::RefCounted<DCLayerOverlaySharedState> {
@@ -71,6 +68,7 @@ class VIZ_SERVICE_EXPORT DCLayerOverlay {
gfx::ColorSpace color_space;
bool require_overlay = false;
+ bool is_protected_video = false;
};
typedef std::vector<DCLayerOverlay> DCLayerOverlayList;
@@ -96,7 +94,7 @@ class DCLayerOverlayProcessor {
DCLayerOverlayProcessor();
~DCLayerOverlayProcessor();
- void Process(cc::DisplayResourceProvider* resource_provider,
+ void Process(DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
RenderPassList* render_passes,
gfx::Rect* overlay_damage_rect,
@@ -108,7 +106,7 @@ class DCLayerOverlayProcessor {
}
private:
- DCLayerResult FromDrawQuad(cc::DisplayResourceProvider* resource_provider,
+ DCLayerResult FromDrawQuad(DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
QuadList::ConstIterator quad_list_begin,
QuadList::ConstIterator quad,
@@ -117,7 +115,7 @@ class DCLayerOverlayProcessor {
QuadList::Iterator ProcessRenderPassDrawQuad(RenderPass* render_pass,
gfx::Rect* damage_rect,
QuadList::Iterator it);
- void ProcessRenderPass(cc::DisplayResourceProvider* resource_provider,
+ void ProcessRenderPass(DisplayResourceProvider* resource_provider,
const gfx::RectF& display_rect,
RenderPass* render_pass,
bool is_root,
diff --git a/chromium/components/viz/service/display/direct_renderer.cc b/chromium/components/viz/service/display/direct_renderer.cc
index 4e6823d2780..2e79ba0f068 100644
--- a/chromium/components/viz/service/display/direct_renderer.cc
+++ b/chromium/components/viz/service/display/direct_renderer.cc
@@ -80,7 +80,7 @@ DirectRenderer::DrawingFrame::~DrawingFrame() = default;
DirectRenderer::DirectRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
+ DisplayResourceProvider* resource_provider)
: settings_(settings),
output_surface_(output_surface),
resource_provider_(resource_provider),
@@ -273,7 +273,7 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
// Create the overlay candidate for the output surface, and mark it as
// always handled.
if (output_surface_->IsDisplayedAsOverlayPlane()) {
- cc::OverlayCandidate output_surface_plane;
+ OverlayCandidate output_surface_plane;
output_surface_plane.display_rect =
gfx::RectF(device_viewport_size.width(), device_viewport_size.height());
output_surface_plane.resource_size_in_pixels = device_viewport_size;
@@ -328,8 +328,23 @@ void DirectRenderer::DrawFrame(RenderPassList* render_passes_in_draw_order,
if (!skip_drawing_root_render_pass && !use_partial_swap_)
current_frame()->root_damage_rect = gfx::Rect(device_viewport_size);
- if (!skip_drawing_root_render_pass)
+ if (!skip_drawing_root_render_pass) {
DrawRenderPassAndExecuteCopyRequests(root_render_pass);
+ // Use a fence to synchronize display of the surface overlay. Note that
+ // gpu_fence_id may have the special value 0 ("no fence") if fences are not
+ // supported. In that case synchronization will happen through other means
+ // on the service side.
+ // TODO(crbug.com/840805): We currently only use fences for root render
+ // passes but we may also need to use fences for non-root passes in some
+ // cases (e.g. WebGL canvas).
+ auto gpu_fence_id = output_surface_->UpdateGpuFence();
+ for (auto& overlay : current_frame()->overlay_list) {
+ if (overlay.use_output_surface_for_resource) {
+ overlay.gpu_fence_id = gpu_fence_id;
+ break;
+ }
+ }
+ }
FinishDrawingFrame();
render_passes_in_draw_order->clear();
diff --git a/chromium/components/viz/service/display/direct_renderer.h b/chromium/components/viz/service/display/direct_renderer.h
index 63be93b71c4..5cf6c6840aa 100644
--- a/chromium/components/viz/service/display/direct_renderer.h
+++ b/chromium/components/viz/service/display/direct_renderer.h
@@ -12,10 +12,10 @@
#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
#include "base/macros.h"
-#include "cc/resources/display_resource_provider.h"
#include "components/viz/common/quads/tile_draw_quad.h"
#include "components/viz/service/display/ca_layer_overlay.h"
#include "components/viz/service/display/dc_layer_overlay.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_processor.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/texture_in_use_response.h"
@@ -25,7 +25,6 @@
namespace cc {
class FilterOperations;
-class OutputSurface;
} // namespace cc
namespace gfx {
@@ -35,6 +34,7 @@ class ColorSpace;
namespace viz {
class BspWalkActionDrawPolygon;
class DrawPolygon;
+class OutputSurface;
class RendererSettings;
class RenderPass;
@@ -46,7 +46,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
public:
DirectRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider);
+ DisplayResourceProvider* resource_provider);
virtual ~DirectRenderer();
void Initialize();
@@ -61,7 +61,8 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
const gfx::Size& device_viewport_size);
// Public interface implemented by subclasses.
- virtual void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) = 0;
+ virtual void SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) = 0;
virtual void SwapBuffersComplete() {}
virtual void DidReceiveTextureInUseResponses(
const gpu::TextureInUseResponses& responses) {}
@@ -82,7 +83,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
gfx::Transform projection_matrix;
gfx::Transform window_matrix;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
CALayerOverlayList ca_layer_overlay_list;
DCLayerOverlayList dc_layer_overlay_list;
};
@@ -201,7 +202,7 @@ class VIZ_SERVICE_EXPORT DirectRenderer {
const RendererSettings* const settings_;
OutputSurface* const output_surface_;
- cc::DisplayResourceProvider* const resource_provider_;
+ DisplayResourceProvider* const resource_provider_;
// This can be replaced by test implementations.
std::unique_ptr<OverlayProcessor> overlay_processor_;
diff --git a/chromium/components/viz/service/display/display.cc b/chromium/components/viz/service/display/display.cc
index ef3b32de61b..178708effd2 100644
--- a/chromium/components/viz/service/display/display.cc
+++ b/chromium/components/viz/service/display/display.cc
@@ -24,6 +24,7 @@
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/display/skia_output_surface.h"
#include "components/viz/service/display/skia_renderer.h"
#include "components/viz/service/display/software_renderer.h"
#include "components/viz/service/display/surface_aggregator.h"
@@ -44,10 +45,12 @@ Display::Display(
const FrameSinkId& frame_sink_id,
std::unique_ptr<OutputSurface> output_surface,
std::unique_ptr<DisplayScheduler> scheduler,
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> current_task_runner,
+ SkiaOutputSurface* skia_output_surface)
: bitmap_manager_(bitmap_manager),
settings_(settings),
frame_sink_id_(frame_sink_id),
+ skia_output_surface_(skia_output_surface),
output_surface_(std::move(output_surface)),
scheduler_(std::move(scheduler)),
current_task_runner_(std::move(current_task_runner)) {
@@ -58,17 +61,11 @@ Display::Display(
}
Display::~Display() {
- for (auto& callbacks : previous_presented_callbacks_) {
- for (auto& callback : callbacks)
+ for (auto& callback_list : pending_presented_callbacks_) {
+ for (auto& callback : callback_list)
std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0);
}
- for (auto& callback : active_presented_callbacks_)
- std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0);
-
- for (auto& callback : presented_callbacks_)
- std::move(callback).Run(base::TimeTicks(), base::TimeDelta(), 0);
-
// Only do this if Initialize() happened.
if (client_) {
if (auto* context = output_surface_->context_provider())
@@ -95,6 +92,9 @@ void Display::Initialize(DisplayClient* client,
surface_manager_->AddObserver(scheduler_.get());
output_surface_->BindToClient(this);
+ if (output_surface_->software_device())
+ output_surface_->software_device()->BindToClient(this);
+
InitializeRenderer();
// This depends on assumptions that Display::Initialize will happen on the
@@ -205,7 +205,7 @@ void Display::SetOutputIsSecure(bool secure) {
}
void Display::InitializeRenderer() {
- resource_provider_ = std::make_unique<cc::DisplayResourceProvider>(
+ resource_provider_ = std::make_unique<DisplayResourceProvider>(
output_surface_->context_provider(), bitmap_manager_);
if (output_surface_->context_provider()) {
@@ -214,15 +214,15 @@ void Display::InitializeRenderer() {
&settings_, output_surface_.get(), resource_provider_.get(),
current_task_runner_);
} else {
+ DCHECK(output_surface_);
renderer_ = std::make_unique<SkiaRenderer>(
- &settings_, output_surface_.get(), resource_provider_.get());
+ &settings_, output_surface_.get(), resource_provider_.get(),
+ skia_output_surface_);
}
- } else if (output_surface_->vulkan_context_provider()) {
#if BUILDFLAG(ENABLE_VULKAN)
+ } else if (output_surface_->vulkan_context_provider()) {
renderer_ = std::make_unique<SkiaRenderer>(
&settings_, output_surface_.get(), resource_provider_.get());
-#else
- NOTREACHED();
#endif
} else {
auto renderer = std::make_unique<SoftwareRenderer>(
@@ -307,7 +307,8 @@ bool Display::DrawAndSwap() {
gfx::Size surface_size;
bool have_damage = false;
auto& last_render_pass = *frame.render_pass_list.back();
- if (last_render_pass.output_rect.size() != current_surface_size_ &&
+ if (settings_.auto_resize_output_surface &&
+ last_render_pass.output_rect.size() != current_surface_size_ &&
last_render_pass.damage_rect == last_render_pass.output_rect &&
!current_surface_size_.IsEmpty()) {
// Resize the output rect to the current surface size so that we won't
@@ -323,15 +324,6 @@ bool Display::DrawAndSwap() {
TRACE_EVENT_INSTANT0("viz", "Size mismatch.", TRACE_EVENT_SCOPE_THREAD);
bool should_draw = have_copy_requests || (have_damage && size_matches);
-
- // If the surface is suspended then the resources to be used by the draw are
- // likely destroyed.
- if (output_surface_->SurfaceIsSuspendForRecycle()) {
- TRACE_EVENT_INSTANT0("viz", "Surface is suspended for recycle.",
- TRACE_EVENT_SCOPE_THREAD);
- should_draw = false;
- }
-
client_->DisplayWillDrawAndSwap(should_draw, frame.render_pass_list);
if (should_draw) {
@@ -375,24 +367,28 @@ bool Display::DrawAndSwap() {
if (scheduler_) {
frame.metadata.latency_info.emplace_back(ui::SourceEventType::FRAME);
frame.metadata.latency_info.back().AddLatencyNumberWithTimestamp(
- ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT, 0, 0,
+ ui::LATENCY_BEGIN_FRAME_DISPLAY_COMPOSITOR_COMPONENT, 0,
scheduler_->current_frame_time(), 1);
}
- DLOG_IF(WARNING, !presented_callbacks_.empty())
- << "DidReceiveSwapBuffersAck() is not called for the last SwapBuffers!";
+ std::vector<Surface::PresentedCallback> callbacks;
for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
Surface::PresentedCallback callback;
- if (surface && surface->TakePresentedCallback(&callback))
- presented_callbacks_.push_back(std::move(callback));
+ if (surface && surface->TakePresentedCallback(&callback)) {
+ callbacks.emplace_back(std::move(callback));
+ }
}
+ bool need_presentation_feedback = !callbacks.empty();
+ if (need_presentation_feedback)
+ pending_presented_callbacks_.emplace_back(std::move(callbacks));
ui::LatencyInfo::TraceIntermediateFlowEvents(frame.metadata.latency_info,
"Display::DrawAndSwap");
cc::benchmark_instrumentation::IssueDisplayRenderingStatsEvent();
- renderer_->SwapBuffers(std::move(frame.metadata.latency_info));
+ renderer_->SwapBuffers(std::move(frame.metadata.latency_info),
+ need_presentation_feedback);
if (scheduler_)
scheduler_->DidSwapBuffers();
} else {
@@ -413,13 +409,11 @@ bool Display::DrawAndSwap() {
base::TimeTicks now = base::TimeTicks::Now();
while (!frame.metadata.latency_info.empty()) {
auto& latency = frame.metadata.latency_info.back();
- if (latency.FindLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT,
- nullptr)) {
+ if (latency.Snapshots().size()) {
stored_latency_info_.push_back(std::move(latency));
} else {
latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT, 0, 0, now,
- 1);
+ ui::INPUT_EVENT_LATENCY_TERMINATED_NO_SWAP_COMPONENT, 0, now, 1);
}
frame.metadata.latency_info.pop_back();
}
@@ -441,17 +435,7 @@ bool Display::DrawAndSwap() {
return true;
}
-void Display::DidReceiveSwapBuffersAck(uint64_t swap_id) {
- // TODO(penghuang): Remove it when we can get accurate presentation time from
- // GPU for every SwapBuffers. https://crbug.com/776877
- if (!active_presented_callbacks_.empty() ||
- !previous_presented_callbacks_.empty()) {
- DLOG(WARNING) << "VSync for last SwapBuffers is not received!";
- previous_presented_callbacks_.push_back(
- std::move(active_presented_callbacks_));
- }
- active_presented_callbacks_ = std::move(presented_callbacks_);
-
+void Display::DidReceiveSwapBuffersAck() {
if (scheduler_)
scheduler_->DidReceiveSwapBuffersAck();
if (renderer_)
@@ -471,25 +455,28 @@ void Display::DidReceiveCALayerParams(
}
void Display::DidReceivePresentationFeedback(
- uint64_t swap_id,
const gfx::PresentationFeedback& feedback) {
- // TODO(penghuang): Remove it when we can get accurate presentation time from
- // GPU for every SwapBuffers. https://crbug.com/776877
- base::TimeTicks previous_timebase =
- feedback.timestamp -
- feedback.interval * previous_presented_callbacks_.size();
- for (auto& callbacks : previous_presented_callbacks_) {
- for (auto& callback : callbacks)
- std::move(callback).Run(previous_timebase, feedback.interval, 0);
- previous_timebase += feedback.interval;
- }
- previous_presented_callbacks_.clear();
-
- for (auto& callback : active_presented_callbacks_) {
+ DCHECK(!pending_presented_callbacks_.empty());
+ auto& callbacks = pending_presented_callbacks_.front();
+ for (auto& callback : callbacks) {
std::move(callback).Run(feedback.timestamp, feedback.interval,
feedback.flags);
}
- active_presented_callbacks_.clear();
+ pending_presented_callbacks_.pop_front();
+}
+
+void Display::DidFinishLatencyInfo(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+ std::vector<ui::LatencyInfo> latency_info_with_snapshot_component;
+ for (const auto& latency : latency_info) {
+ if (latency.Snapshots().size())
+ latency_info_with_snapshot_component.push_back(latency);
+ }
+
+ if (!latency_info_with_snapshot_component.empty()) {
+ client_->DidSwapAfterSnapshotRequestReceived(
+ latency_info_with_snapshot_component);
+ }
}
void Display::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
@@ -561,6 +548,12 @@ LocalSurfaceId Display::GetSurfaceAtAggregation(
return it->second;
}
+void Display::SoftwareDeviceUpdatedCALayerParams(
+ const gfx::CALayerParams& ca_layer_params) {
+ if (client_)
+ client_->DisplayDidReceiveCALayerParams(ca_layer_params);
+}
+
void Display::ForceImmediateDrawAndSwapIfPossible() {
if (scheduler_)
scheduler_->ForceImmediateSwapIfPossible();
diff --git a/chromium/components/viz/service/display/display.h b/chromium/components/viz/service/display/display.h
index 7759c67aa47..51312be163e 100644
--- a/chromium/components/viz/service/display/display.h
+++ b/chromium/components/viz/service/display/display.h
@@ -8,16 +8,19 @@
#include <memory>
#include <vector>
+#include "base/containers/circular_deque.h"
#include "base/macros.h"
#include "base/observer_list.h"
-#include "cc/resources/display_resource_provider.h"
+#include "base/single_thread_task_runner.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/gpu/context_lost_observer.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/display/output_surface_client.h"
+#include "components/viz/service/display/software_output_device_client.h"
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/surfaces/latest_local_surface_id_lookup_delegate.h"
#include "components/viz/service/surfaces/surface_manager.h"
@@ -26,11 +29,6 @@
#include "ui/gfx/color_space.h"
#include "ui/latency/latency_info.h"
-namespace cc {
-class DisplayResourceProvider;
-class RendererSettings;
-} // namespace cc
-
namespace gfx {
class Size;
}
@@ -38,8 +36,11 @@ class Size;
namespace viz {
class DirectRenderer;
class DisplayClient;
+class DisplayResourceProvider;
class OutputSurface;
+class RendererSettings;
class SharedBitmapManager;
+class SkiaOutputSurface;
class SoftwareRenderer;
class VIZ_SERVICE_EXPORT DisplayObserver {
@@ -55,18 +56,22 @@ class VIZ_SERVICE_EXPORT DisplayObserver {
class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
public OutputSurfaceClient,
public ContextLostObserver,
- public LatestLocalSurfaceIdLookupDelegate {
+ public LatestLocalSurfaceIdLookupDelegate,
+ public SoftwareOutputDeviceClient {
public:
// The |begin_frame_source| and |scheduler| may be null (together). In that
// case, DrawAndSwap must be called externally when needed.
// The |current_task_runner| may be null if the Display is on a thread without
// a MessageLoop.
+ // TODO(penghuang): Remove skia_output_surface when all DirectRenderer
+ // subclasses are replaced by SkiaRenderer.
Display(SharedBitmapManager* bitmap_manager,
const RendererSettings& settings,
const FrameSinkId& frame_sink_id,
std::unique_ptr<OutputSurface> output_surface,
std::unique_ptr<DisplayScheduler> scheduler,
- scoped_refptr<base::SingleThreadTaskRunner> current_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> current_task_runner,
+ SkiaOutputSurface* skia_output_surface = nullptr);
~Display() override;
@@ -101,19 +106,24 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
// OutputSurfaceClient implementation.
void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
- void DidReceiveSwapBuffersAck(uint64_t swap_id) override;
+ void DidReceiveSwapBuffersAck() override;
void DidReceiveTextureInUseResponses(
const gpu::TextureInUseResponses& responses) override;
void DidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) override;
void DidReceivePresentationFeedback(
- uint64_t swap_id,
const gfx::PresentationFeedback& feedback) override;
+ void DidFinishLatencyInfo(
+ const std::vector<ui::LatencyInfo>& latency_info) override;
// LatestLocalSurfaceIdLookupDelegate implementation.
LocalSurfaceId GetSurfaceAtAggregation(
const FrameSinkId& frame_sink_id) const override;
+ // SoftwareOutputDeviceClient implementation
+ void SoftwareDeviceUpdatedCALayerParams(
+ const gfx::CALayerParams& ca_layer_params) override;
+
bool has_scheduler() const { return !!scheduler_; }
DirectRenderer* renderer_for_testing() const { return renderer_.get(); }
@@ -144,9 +154,10 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
bool swapped_since_resize_ = false;
bool output_is_secure_ = false;
+ SkiaOutputSurface* skia_output_surface_;
std::unique_ptr<OutputSurface> output_surface_;
std::unique_ptr<DisplayScheduler> scheduler_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<SurfaceAggregator> aggregator_;
// This may be null if the Display is on a thread without a MessageLoop.
scoped_refptr<base::SingleThreadTaskRunner> current_task_runner_;
@@ -154,12 +165,8 @@ class VIZ_SERVICE_EXPORT Display : public DisplaySchedulerClient,
SoftwareRenderer* software_renderer_ = nullptr;
std::vector<ui::LatencyInfo> stored_latency_info_;
- using PresentedCallbacks = std::vector<Surface::PresentedCallback>;
- PresentedCallbacks presented_callbacks_;
- PresentedCallbacks active_presented_callbacks_;
- // TODO(penghuang): Remove it when we can get accurate presentation time from
- // GPU for every SwapBuffers. https://crbug.com/776877
- std::vector<PresentedCallbacks> previous_presented_callbacks_;
+ base::circular_deque<std::vector<Surface::PresentedCallback>>
+ pending_presented_callbacks_;
private:
DISALLOW_COPY_AND_ASSIGN(Display);
diff --git a/chromium/components/viz/service/display/display_client.h b/chromium/components/viz/service/display/display_client.h
index 286aa158ff3..9734040a581 100644
--- a/chromium/components/viz/service/display/display_client.h
+++ b/chromium/components/viz/service/display/display_client.h
@@ -11,6 +11,10 @@ namespace gfx {
struct CALayerParams;
} // namespace gfx
+namespace ui {
+class LatencyInfo;
+} // namespace ui
+
namespace viz {
class DisplayClient {
@@ -22,6 +26,11 @@ class DisplayClient {
virtual void DisplayDidDrawAndSwap() = 0;
virtual void DisplayDidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) = 0;
+
+ // Notifies that a swap has occured after some latency info with snapshot
+ // component reached the display.
+ virtual void DidSwapAfterSnapshotRequestReceived(
+ const std::vector<ui::LatencyInfo>& latency_info) = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/display/display_resource_provider.cc b/chromium/components/viz/service/display/display_resource_provider.cc
new file mode 100644
index 00000000000..2b78a9662b5
--- /dev/null
+++ b/chromium/components/viz/service/display/display_resource_provider.cc
@@ -0,0 +1,972 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/display/display_resource_provider.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/trace_event.h"
+#include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/resource_sizes.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
+#include "gpu/command_buffer/client/context_support.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/skia/include/gpu/GrBackendSurface.h"
+#include "ui/gl/trace_util.h"
+
+using gpu::gles2::GLES2Interface;
+
+namespace viz {
+
+namespace {
+
+// Generates process-unique IDs to use for tracing resources.
+base::AtomicSequenceNumber g_next_display_resource_provider_tracing_id;
+
+} // namespace
+
+static GLint GetActiveTextureUnit(GLES2Interface* gl) {
+ GLint active_unit = 0;
+ gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit);
+ return active_unit;
+}
+
+class ScopedSetActiveTexture {
+ public:
+ ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit)
+ : gl_(gl), unit_(unit) {
+ DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
+
+ if (unit_ != GL_TEXTURE0)
+ gl_->ActiveTexture(unit_);
+ }
+
+ ~ScopedSetActiveTexture() {
+ // Active unit being GL_TEXTURE0 is effectively the ground state.
+ if (unit_ != GL_TEXTURE0)
+ gl_->ActiveTexture(GL_TEXTURE0);
+ }
+
+ private:
+ GLES2Interface* gl_;
+ GLenum unit_;
+};
+
+DisplayResourceProvider::DisplayResourceProvider(
+ ContextProvider* compositor_context_provider,
+ SharedBitmapManager* shared_bitmap_manager)
+ : compositor_context_provider_(compositor_context_provider),
+ shared_bitmap_manager_(shared_bitmap_manager),
+ tracing_id_(g_next_display_resource_provider_tracing_id.GetNext()) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
+ // Don't register a dump provider in these cases.
+ // TODO(crbug.com/517156): Get this working in Android Webview.
+ if (base::ThreadTaskRunnerHandle::IsSet()) {
+ base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+ this, "cc::ResourceProvider", base::ThreadTaskRunnerHandle::Get());
+ }
+}
+
+DisplayResourceProvider::~DisplayResourceProvider() {
+ while (!children_.empty())
+ DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
+
+ GLES2Interface* gl = ContextGL();
+ if (gl)
+ gl->Finish();
+
+ while (!resources_.empty())
+ DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
+
+ if (compositor_context_provider_) {
+ // Check that all GL resources has been deleted.
+ for (const auto& pair : resources_)
+ DCHECK(!pair.second.is_gpu_resource_type());
+ }
+
+ base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+ this);
+}
+
+bool DisplayResourceProvider::OnMemoryDump(
+ const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ for (const auto& resource_entry : resources_) {
+ const auto& resource = resource_entry.second;
+
+ bool backing_memory_allocated = false;
+ switch (resource.type) {
+ case ResourceType::kTexture:
+ backing_memory_allocated = !!resource.gl_id;
+ break;
+ case ResourceType::kBitmap:
+ backing_memory_allocated = !!resource.shared_bitmap;
+ break;
+ }
+
+ if (!backing_memory_allocated) {
+ // Don't log unallocated resources - they have no backing memory.
+ continue;
+ }
+
+ // ResourceIds are not process-unique, so log with the ResourceProvider's
+ // unique id.
+ std::string dump_name =
+ base::StringPrintf("cc/resource_memory/provider_%d/resource_%d",
+ tracing_id_, resource_entry.first);
+ base::trace_event::MemoryAllocatorDump* dump =
+ pmd->CreateAllocatorDump(dump_name);
+
+ // Texture resources may not come with a size, in which case don't report
+ // one.
+ if (!resource.size.IsEmpty()) {
+ uint64_t total_bytes = ResourceSizes::UncheckedSizeInBytesAligned<size_t>(
+ resource.size, resource.format);
+ dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ static_cast<uint64_t>(total_bytes));
+ }
+
+ // Resources may be shared across processes and require a shared GUID to
+ // prevent double counting the memory.
+ base::trace_event::MemoryAllocatorDumpGuid guid;
+ base::UnguessableToken shared_memory_guid;
+ switch (resource.type) {
+ case ResourceType::kTexture:
+ DCHECK(resource.gl_id);
+ guid = gl::GetGLTextureClientGUIDForTracing(
+ compositor_context_provider_->ContextSupport()
+ ->ShareGroupTracingGUID(),
+ resource.gl_id);
+ break;
+ case ResourceType::kBitmap:
+ // If the resource comes from out of process, it will have this id,
+ // which we prefer. Otherwise, we fall back to the SharedBitmapGUID
+ // which can be generated for in-process bitmaps.
+ shared_memory_guid = resource.shared_bitmap->GetCrossProcessGUID();
+ if (shared_memory_guid.is_empty())
+ guid = GetSharedBitmapGUIDForTracing(resource.shared_bitmap_id);
+ break;
+ }
+
+ DCHECK(!shared_memory_guid.is_empty() || !guid.empty());
+
+ // The client that owns the resource will use a higher importance (2), and
+ // the GPU service will use a lower one (0).
+ const int importance = 1;
+ if (!shared_memory_guid.is_empty()) {
+ pmd->CreateSharedMemoryOwnershipEdge(dump->guid(), shared_memory_guid,
+ importance);
+ } else {
+ pmd->CreateSharedGlobalAllocatorDump(guid);
+ pmd->AddOwnershipEdge(dump->guid(), guid, importance);
+ }
+ }
+
+ return true;
+}
+
+#if defined(OS_ANDROID)
+void DisplayResourceProvider::SendPromotionHints(
+ const OverlayCandidateList::PromotionHintInfoMap& promotion_hints) {
+ GLES2Interface* gl = ContextGL();
+ if (!gl)
+ return;
+
+ for (const auto& id : wants_promotion_hints_set_) {
+ auto it = resources_.find(id);
+ if (it == resources_.end())
+ continue;
+
+ if (it->second.marked_for_deletion)
+ continue;
+
+ const internal::Resource* resource = LockForRead(id);
+ // TODO(ericrk): We should never fail LockForRead, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ if (!resource)
+ return;
+
+ DCHECK(resource->wants_promotion_hint);
+
+ // Insist that this is backed by a GPU texture.
+ if (resource->is_gpu_resource_type()) {
+ DCHECK(resource->gl_id);
+ auto iter = promotion_hints.find(id);
+ bool promotable = iter != promotion_hints.end();
+ gl->OverlayPromotionHintCHROMIUM(resource->gl_id, promotable,
+ promotable ? iter->second.x() : 0,
+ promotable ? iter->second.y() : 0,
+ promotable ? iter->second.width() : 0,
+ promotable ? iter->second.height() : 0);
+ }
+ UnlockForRead(id);
+ }
+}
+
+bool DisplayResourceProvider::IsBackedBySurfaceTexture(ResourceId id) {
+ internal::Resource* resource = GetResource(id);
+ return resource->is_backed_by_surface_texture;
+}
+
+bool DisplayResourceProvider::WantsPromotionHintForTesting(ResourceId id) {
+ return wants_promotion_hints_set_.count(id) > 0;
+}
+
+size_t DisplayResourceProvider::CountPromotionHintRequestsForTesting() {
+ return wants_promotion_hints_set_.size();
+}
+#endif
+
+bool DisplayResourceProvider::IsOverlayCandidate(ResourceId id) {
+ internal::Resource* resource = TryGetResource(id);
+ // TODO(ericrk): We should never fail TryGetResource, but we appear to
+ // be doing so on Android in rare cases. Handle this gracefully until a
+ // better solution can be found. https://crbug.com/811858
+ return resource && resource->is_overlay_candidate;
+}
+
+ResourceType DisplayResourceProvider::GetResourceType(ResourceId id) {
+ return GetResource(id)->type;
+}
+
+GLenum DisplayResourceProvider::GetResourceTextureTarget(ResourceId id) {
+ return GetResource(id)->target;
+}
+
+gfx::BufferFormat DisplayResourceProvider::GetBufferFormat(ResourceId id) {
+ internal::Resource* resource = GetResource(id);
+ return resource->buffer_format;
+}
+
+void DisplayResourceProvider::WaitSyncToken(ResourceId id) {
+ internal::Resource* resource = TryGetResource(id);
+ // TODO(ericrk): We should never fail TryGetResource, but we appear to
+ // be doing so on Android in rare cases. Handle this gracefully until a
+ // better solution can be found. https://crbug.com/811858
+ if (!resource)
+ return;
+ WaitSyncTokenInternal(resource);
+#if defined(OS_ANDROID)
+ // Now that the resource is synced, we may send it a promotion hint. We could
+ // sync all |wants_promotion_hint| resources elsewhere, and send 'no' to all
+ // resources that weren't used. However, there's no real advantage.
+ if (resource->wants_promotion_hint)
+ wants_promotion_hints_set_.insert(id);
+#endif // OS_ANDROID
+}
+
+int DisplayResourceProvider::CreateChild(
+ const ReturnCallback& return_callback) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ Child child_info;
+ child_info.return_callback = return_callback;
+
+ int child = next_child_++;
+ children_[child] = child_info;
+ return child;
+}
+
+void DisplayResourceProvider::SetChildNeedsSyncTokens(int child_id,
+ bool needs) {
+ auto it = children_.find(child_id);
+ DCHECK(it != children_.end());
+ it->second.needs_sync_tokens = needs;
+}
+
+void DisplayResourceProvider::DestroyChild(int child_id) {
+ auto it = children_.find(child_id);
+ DCHECK(it != children_.end());
+ DestroyChildInternal(it, NORMAL);
+}
+
+void DisplayResourceProvider::ReceiveFromChild(
+ int child,
+ const std::vector<TransferableResource>& resources) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ GLES2Interface* gl = ContextGL();
+ Child& child_info = children_.find(child)->second;
+ DCHECK(!child_info.marked_for_deletion);
+ for (std::vector<TransferableResource>::const_iterator it = resources.begin();
+ it != resources.end(); ++it) {
+ auto resource_in_map_it = child_info.child_to_parent_map.find(it->id);
+ if (resource_in_map_it != child_info.child_to_parent_map.end()) {
+ internal::Resource* resource = GetResource(resource_in_map_it->second);
+ resource->marked_for_deletion = false;
+ resource->imported_count++;
+ continue;
+ }
+
+ if ((!it->is_software && !gl) ||
+ (it->is_software && !shared_bitmap_manager_)) {
+ TRACE_EVENT0(
+ "cc", "DisplayResourceProvider::ReceiveFromChild dropping invalid");
+ std::vector<ReturnedResource> to_return;
+ to_return.push_back(it->ToReturnedResource());
+ child_info.return_callback.Run(to_return);
+ continue;
+ }
+
+ ResourceId local_id = next_id_++;
+ internal::Resource* resource = nullptr;
+ if (it->is_software) {
+ DCHECK(IsBitmapFormatSupported(it->format));
+ resource = InsertResource(
+ local_id, internal::Resource(it->size, ResourceType::kBitmap,
+ it->format, it->color_space));
+ resource->has_shared_bitmap_id = true;
+ resource->shared_bitmap_id = it->mailbox_holder.mailbox;
+ } else {
+ resource = InsertResource(
+ local_id, internal::Resource(it->size, ResourceType::kTexture,
+ it->format, it->color_space));
+ resource->target = it->mailbox_holder.texture_target;
+ resource->filter = it->filter;
+ resource->original_filter = it->filter;
+ resource->min_filter = it->filter;
+ resource->buffer_format = it->buffer_format;
+ resource->mailbox = it->mailbox_holder.mailbox;
+ resource->UpdateSyncToken(it->mailbox_holder.sync_token);
+ resource->read_lock_fences_enabled = it->read_lock_fences_enabled;
+ resource->is_overlay_candidate = it->is_overlay_candidate;
+#if defined(OS_ANDROID)
+ resource->is_backed_by_surface_texture = it->is_backed_by_surface_texture;
+ resource->wants_promotion_hint = it->wants_promotion_hint;
+#endif
+ }
+ resource->child_id = child;
+ resource->imported_count = 1;
+ resource->id_in_child = it->id;
+ child_info.child_to_parent_map[it->id] = local_id;
+ }
+}
+
+void DisplayResourceProvider::DeclareUsedResourcesFromChild(
+ int child,
+ const ResourceIdSet& resources_from_child) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ auto child_it = children_.find(child);
+ DCHECK(child_it != children_.end());
+ Child& child_info = child_it->second;
+ DCHECK(!child_info.marked_for_deletion);
+
+ std::vector<ResourceId> unused;
+ for (auto it = child_info.child_to_parent_map.begin();
+ it != child_info.child_to_parent_map.end(); ++it) {
+ ResourceId local_id = it->second;
+ bool resource_is_in_use = resources_from_child.count(it->first) > 0;
+ if (!resource_is_in_use)
+ unused.push_back(local_id);
+ }
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
+}
+
+const std::unordered_map<ResourceId, ResourceId>&
+DisplayResourceProvider::GetChildToParentMap(int child) const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ ChildMap::const_iterator it = children_.find(child);
+ DCHECK(it != children_.end());
+ DCHECK(!it->second.marked_for_deletion);
+ return it->second.child_to_parent_map;
+}
+
+bool DisplayResourceProvider::InUse(ResourceId id) {
+ internal::Resource* resource = GetResource(id);
+ return resource->lock_for_read_count > 0 || resource->locked_for_external_use;
+}
+
+internal::Resource* DisplayResourceProvider::InsertResource(
+ ResourceId id,
+ internal::Resource resource) {
+ auto result =
+ resources_.insert(ResourceMap::value_type(id, std::move(resource)));
+ DCHECK(result.second);
+ return &result.first->second;
+}
+
+internal::Resource* DisplayResourceProvider::GetResource(ResourceId id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(id);
+ auto it = resources_.find(id);
+ DCHECK(it != resources_.end());
+ return &it->second;
+}
+
+internal::Resource* DisplayResourceProvider::TryGetResource(ResourceId id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (!id)
+ return nullptr;
+ auto it = resources_.find(id);
+ if (it == resources_.end())
+ return nullptr;
+ return &it->second;
+}
+
+void DisplayResourceProvider::PopulateSkBitmapWithResource(
+ SkBitmap* sk_bitmap,
+ const internal::Resource* resource) {
+ DCHECK(IsBitmapFormatSupported(resource->format));
+ SkImageInfo info = SkImageInfo::MakeN32Premul(resource->size.width(),
+ resource->size.height());
+ bool pixels_installed =
+ sk_bitmap->installPixels(info, resource->pixels, info.minRowBytes());
+ DCHECK(pixels_installed);
+}
+
+void DisplayResourceProvider::DeleteResourceInternal(ResourceMap::iterator it,
+ DeleteStyle style) {
+ TRACE_EVENT0("cc", "DosplayResourceProvider::DeleteResourceInternal");
+ internal::Resource* resource = &it->second;
+
+ if (resource->gl_id) {
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ gl->DeleteTextures(1, &resource->gl_id);
+ resource->gl_id = 0;
+ }
+
+ if (resource->owned_shared_bitmap) {
+ DCHECK_EQ(ResourceType::kBitmap, resource->type);
+ resource->shared_bitmap = nullptr;
+ resource->pixels = nullptr;
+ resource->owned_shared_bitmap = nullptr;
+ }
+
+ resources_.erase(it);
+}
+
+void DisplayResourceProvider::WaitSyncTokenInternal(
+ internal::Resource* resource) {
+ DCHECK(resource);
+ if (!resource->ShouldWaitSyncToken())
+ return;
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ // In the case of context lost, this sync token may be empty (see comment in
+ // the UpdateSyncToken() function). The WaitSyncTokenCHROMIUM() function
+ // handles empty sync tokens properly so just wait anyways and update the
+ // state the synchronized.
+ gl->WaitSyncTokenCHROMIUM(resource->sync_token().GetConstData());
+ resource->SetSynchronized();
+}
+
+GLES2Interface* DisplayResourceProvider::ContextGL() const {
+ ContextProvider* context_provider = compositor_context_provider_;
+ return context_provider ? context_provider->ContextGL() : nullptr;
+}
+
+const internal::Resource* DisplayResourceProvider::LockForRead(ResourceId id) {
+ // TODO(ericrk): We should never fail TryGetResource, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ internal::Resource* resource = TryGetResource(id);
+ if (!resource)
+ return nullptr;
+
+ // Mailbox sync_tokens must be processed by a call to WaitSyncToken() prior to
+ // calling LockForRead().
+ DCHECK_NE(internal::Resource::NEEDS_WAIT, resource->synchronization_state());
+
+ if (resource->is_gpu_resource_type() && !resource->gl_id) {
+ DCHECK(!resource->mailbox.IsZero());
+
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ resource->gl_id =
+ gl->CreateAndConsumeTextureCHROMIUM(resource->mailbox.name);
+ resource->SetLocallyUsed();
+ }
+
+ if (!resource->pixels && resource->has_shared_bitmap_id &&
+ shared_bitmap_manager_) {
+ std::unique_ptr<SharedBitmap> bitmap =
+ shared_bitmap_manager_->GetSharedBitmapFromId(
+ resource->size, resource->format, resource->shared_bitmap_id);
+ if (bitmap) {
+ resource->SetSharedBitmap(bitmap.get());
+ resource->owned_shared_bitmap = std::move(bitmap);
+ }
+ }
+
+ resource->lock_for_read_count++;
+ if (resource->read_lock_fences_enabled) {
+ if (current_read_lock_fence_.get())
+ current_read_lock_fence_->Set();
+ resource->read_lock_fence = current_read_lock_fence_;
+ }
+
+ return resource;
+}
+
+void DisplayResourceProvider::UnlockForRead(ResourceId id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto it = resources_.find(id);
+ // TODO(ericrk): We should never fail to find id, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ if (it == resources_.end())
+ return;
+
+ internal::Resource* resource = &it->second;
+ DCHECK_GT(resource->lock_for_read_count, 0);
+ resource->lock_for_read_count--;
+ TryReleaseResource(it);
+}
+
+ResourceMetadata DisplayResourceProvider::LockForExternalUse(ResourceId id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto it = resources_.find(id);
+ DCHECK(it != resources_.end());
+
+ internal::Resource* resource = &it->second;
+ ResourceMetadata metadata;
+ // Make sure there is no outstanding LockForExternalUse without calling
+ // UnlockForExternalUse.
+ DCHECK(!resource->locked_for_external_use);
+ // TODO(penghuang): support software resource.
+ DCHECK(resource->is_gpu_resource_type());
+
+ metadata.mailbox = resource->mailbox;
+ metadata.backend_format = GrBackendFormat::MakeGL(
+ TextureStorageFormat(resource->format), resource->target);
+ metadata.size = resource->size;
+ metadata.mip_mapped = GrMipMapped::kNo;
+ metadata.origin = kTopLeft_GrSurfaceOrigin;
+ metadata.color_type =
+ ResourceFormatToClosestSkColorType(!IsSoftware(), resource->format);
+ metadata.alpha_type = kPremul_SkAlphaType;
+ metadata.color_space = nullptr;
+ metadata.sync_token = resource->sync_token();
+
+ resource->locked_for_external_use = true;
+ return metadata;
+}
+
+void DisplayResourceProvider::UnlockForExternalUse(
+ ResourceId id,
+ const gpu::SyncToken& sync_token) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto it = resources_.find(id);
+ DCHECK(it != resources_.end());
+ DCHECK(sync_token.verified_flush());
+
+ internal::Resource* resource = &it->second;
+ DCHECK(resource->locked_for_external_use);
+ // TODO(penghuang): support software resource.
+ DCHECK(resource->is_gpu_resource_type());
+
+ // Update the resource sync token to |sync_token|. When the next frame is
+ // being composited, the DeclareUsedResourcesFromChild() will be called with
+ // resources belong to every child for the next frame. If the resource is not
+ // used by the next frame, the resource will be returned to a child which
+ // owns it with the |sync_token|. The child is responsible for issuing a
+ // WaitSyncToken GL command with the |sync_token| before reusing it.
+ resource->UpdateSyncToken(sync_token);
+ resource->locked_for_external_use = false;
+
+ TryReleaseResource(it);
+}
+
+void DisplayResourceProvider::TryReleaseResource(ResourceMap::iterator it) {
+ ResourceId id = it->first;
+ internal::Resource* resource = &it->second;
+ if (resource->marked_for_deletion && !resource->lock_for_read_count &&
+ !resource->locked_for_external_use) {
+ if (!resource->child_id) {
+// The resource belongs to this instance, so it can be destroyed.
+// TODO(danakj): Is this dead code?
+#if defined(OS_ANDROID)
+ DeletePromotionHint(it, NORMAL);
+#endif
+ DeleteResourceInternal(it, NORMAL);
+ } else {
+ if (batch_return_resources_) {
+ batched_returning_resources_[resource->child_id].push_back(id);
+ } else {
+ auto child_it = children_.find(resource->child_id);
+ std::vector<ResourceId> unused;
+ unused.push_back(id);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
+ }
+ }
+ }
+}
+
+GLenum DisplayResourceProvider::BindForSampling(ResourceId resource_id,
+ GLenum unit,
+ GLenum filter) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ GLES2Interface* gl = ContextGL();
+ auto it = resources_.find(resource_id);
+ // TODO(ericrk): We should never fail to find resource_id, but we appear to
+ // be doing so on Android in rare cases. Handle this gracefully until a
+ // better solution can be found. https://crbug.com/811858
+ if (it == resources_.end())
+ return GL_TEXTURE_2D;
+
+ internal::Resource* resource = &it->second;
+ DCHECK(resource->lock_for_read_count);
+
+ ScopedSetActiveTexture scoped_active_tex(gl, unit);
+ GLenum target = resource->target;
+ gl->BindTexture(target, resource->gl_id);
+ GLenum min_filter = filter;
+ if (min_filter != resource->min_filter) {
+ gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filter);
+ resource->min_filter = min_filter;
+ }
+ if (filter != resource->filter) {
+ gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
+ resource->filter = filter;
+ }
+
+ return target;
+}
+
+bool DisplayResourceProvider::ReadLockFenceHasPassed(
+ const internal::Resource* resource) {
+ return !resource->read_lock_fence || resource->read_lock_fence->HasPassed();
+}
+
+#if defined(OS_ANDROID)
+void DisplayResourceProvider::DeletePromotionHint(ResourceMap::iterator it,
+ DeleteStyle style) {
+ internal::Resource* resource = &it->second;
+ // If this resource was interested in promotion hints, then remove it from
+ // the set of resources that we'll notify.
+ if (resource->wants_promotion_hint)
+ wants_promotion_hints_set_.erase(it->first);
+}
+#endif
+
+void DisplayResourceProvider::DeleteAndReturnUnusedResourcesToChild(
+ ChildMap::iterator child_it,
+ DeleteStyle style,
+ const std::vector<ResourceId>& unused) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(child_it != children_.end());
+ Child* child_info = &child_it->second;
+
+ if (unused.empty() && !child_info->marked_for_deletion)
+ return;
+
+ std::vector<ReturnedResource> to_return;
+ to_return.reserve(unused.size());
+ std::vector<ReturnedResource*> need_synchronization_resources;
+ std::vector<GLbyte*> unverified_sync_tokens;
+ std::vector<size_t> to_return_indices_unverified;
+
+ GLES2Interface* gl = ContextGL();
+
+ for (ResourceId local_id : unused) {
+ auto it = resources_.find(local_id);
+ CHECK(it != resources_.end());
+ internal::Resource& resource = it->second;
+
+ ResourceId child_id = resource.id_in_child;
+ DCHECK(child_info->child_to_parent_map.count(child_id));
+
+ bool is_lost = (resource.is_gpu_resource_type() && lost_context_provider_);
+ if (resource.lock_for_read_count > 0 || resource.locked_for_external_use) {
+ if (style != FOR_SHUTDOWN) {
+ // Defer this resource deletion.
+ resource.marked_for_deletion = true;
+ continue;
+ }
+ // We can't postpone the deletion, so we'll have to lose it.
+ is_lost = true;
+ } else if (!ReadLockFenceHasPassed(&resource)) {
+ // TODO(dcastagna): see if it's possible to use this logic for
+ // the branch above too, where the resource is locked or still exported.
+ if (style != FOR_SHUTDOWN && !child_info->marked_for_deletion) {
+ // Defer this resource deletion.
+ resource.marked_for_deletion = true;
+ continue;
+ }
+ // We can't postpone the deletion, so we'll have to lose it.
+ is_lost = true;
+ }
+
+ if (resource.is_gpu_resource_type() &&
+ resource.filter != resource.original_filter) {
+ DCHECK(resource.target);
+ DCHECK(resource.gl_id);
+ DCHECK(gl);
+ gl->BindTexture(resource.target, resource.gl_id);
+ gl->TexParameteri(resource.target, GL_TEXTURE_MIN_FILTER,
+ resource.original_filter);
+ gl->TexParameteri(resource.target, GL_TEXTURE_MAG_FILTER,
+ resource.original_filter);
+ resource.SetLocallyUsed();
+ }
+
+ ReturnedResource returned;
+ returned.id = child_id;
+ returned.sync_token = resource.sync_token();
+ returned.count = resource.imported_count;
+ returned.lost = is_lost;
+ to_return.push_back(returned);
+
+ if (resource.is_gpu_resource_type() && child_info->needs_sync_tokens) {
+ if (resource.needs_sync_token()) {
+ need_synchronization_resources.push_back(&to_return.back());
+ } else if (returned.sync_token.HasData() &&
+ !returned.sync_token.verified_flush()) {
+ // Before returning any sync tokens, they must be verified. Store an
+ // index into |to_return| instead of a pointer as vectors may realloc
+ // and move their data.
+ to_return_indices_unverified.push_back(to_return.size() - 1);
+ }
+ }
+
+ child_info->child_to_parent_map.erase(child_id);
+ resource.imported_count = 0;
+#if defined(OS_ANDROID)
+ DeletePromotionHint(it, style);
+#endif
+ DeleteResourceInternal(it, style);
+ }
+
+ for (size_t i : to_return_indices_unverified)
+ unverified_sync_tokens.push_back(to_return[i].sync_token.GetData());
+
+ gpu::SyncToken new_sync_token;
+ if (!need_synchronization_resources.empty()) {
+ DCHECK(child_info->needs_sync_tokens);
+ DCHECK(gl);
+ gl->GenUnverifiedSyncTokenCHROMIUM(new_sync_token.GetData());
+ unverified_sync_tokens.push_back(new_sync_token.GetData());
+ }
+
+ if (!unverified_sync_tokens.empty()) {
+ DCHECK(child_info->needs_sync_tokens);
+ DCHECK(gl);
+ gl->VerifySyncTokensCHROMIUM(unverified_sync_tokens.data(),
+ unverified_sync_tokens.size());
+ }
+
+ // Set sync token after verification.
+ for (ReturnedResource* returned : need_synchronization_resources)
+ returned->sync_token = new_sync_token;
+
+ if (!to_return.empty())
+ child_info->return_callback.Run(to_return);
+
+ if (child_info->marked_for_deletion &&
+ child_info->child_to_parent_map.empty()) {
+ children_.erase(child_it);
+ }
+}
+
+void DisplayResourceProvider::DestroyChildInternal(ChildMap::iterator it,
+ DeleteStyle style) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ Child& child = it->second;
+ DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
+
+ std::vector<ResourceId> resources_for_child;
+
+ for (auto child_it = child.child_to_parent_map.begin();
+ child_it != child.child_to_parent_map.end(); ++child_it) {
+ ResourceId id = child_it->second;
+ resources_for_child.push_back(id);
+ }
+
+ child.marked_for_deletion = true;
+
+ DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child);
+}
+
+void DisplayResourceProvider::SetBatchReturnResources(bool batch) {
+ DCHECK_NE(batch_return_resources_, batch);
+ batch_return_resources_ = batch;
+ if (!batch) {
+ for (const auto& resources : batched_returning_resources_) {
+ auto child_it = children_.find(resources.first);
+ DCHECK(child_it != children_.end());
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, resources.second);
+ }
+ batched_returning_resources_.clear();
+ }
+}
+
+DisplayResourceProvider::ScopedReadLockGL::ScopedReadLockGL(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id)
+ : resource_provider_(resource_provider), resource_id_(resource_id) {
+ const internal::Resource* resource =
+ resource_provider->LockForRead(resource_id);
+ // TODO(ericrk): We should never fail LockForRead, but we appear to be
+ // doing so on Android in rare cases. Handle this gracefully until a better
+ // solution can be found. https://crbug.com/811858
+ if (!resource)
+ return;
+
+ texture_id_ = resource->gl_id;
+ target_ = resource->target;
+ size_ = resource->size;
+ color_space_ = resource->color_space;
+}
+
+DisplayResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() {
+ resource_provider_->UnlockForRead(resource_id_);
+}
+
+DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id,
+ GLenum filter)
+ : resource_lock_(resource_provider, resource_id),
+ unit_(GL_TEXTURE0),
+ target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {}
+
+DisplayResourceProvider::ScopedSamplerGL::ScopedSamplerGL(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id,
+ GLenum unit,
+ GLenum filter)
+ : resource_lock_(resource_provider, resource_id),
+ unit_(unit),
+ target_(resource_provider->BindForSampling(resource_id, unit_, filter)) {}
+
+DisplayResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() = default;
+
+DisplayResourceProvider::ScopedReadLockSkImage::ScopedReadLockSkImage(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id)
+ : resource_provider_(resource_provider), resource_id_(resource_id) {
+ const internal::Resource* resource =
+ resource_provider->LockForRead(resource_id);
+ DCHECK(resource);
+ if (resource_provider_->resource_sk_image_.find(resource_id) !=
+ resource_provider_->resource_sk_image_.end()) {
+ // Use cached sk_image.
+ sk_image_ =
+ resource_provider_->resource_sk_image_.find(resource_id)->second;
+ } else if (resource->gl_id) {
+ GrGLTextureInfo texture_info;
+ texture_info.fID = resource->gl_id;
+ texture_info.fTarget = resource->target;
+ texture_info.fFormat = TextureStorageFormat(resource->format);
+ GrBackendTexture backend_texture(resource->size.width(),
+ resource->size.height(), GrMipMapped::kNo,
+ texture_info);
+ sk_image_ = SkImage::MakeFromTexture(
+ resource_provider->compositor_context_provider_->GrContext(),
+ backend_texture, kTopLeft_GrSurfaceOrigin,
+ ResourceFormatToClosestSkColorType(!resource_provider->IsSoftware(),
+ resource->format),
+ kPremul_SkAlphaType, nullptr);
+ } else if (resource->pixels) {
+ SkBitmap sk_bitmap;
+ resource_provider->PopulateSkBitmapWithResource(&sk_bitmap, resource);
+ sk_bitmap.setImmutable();
+ sk_image_ = SkImage::MakeFromBitmap(sk_bitmap);
+ } else {
+ // During render process shutdown, ~RenderMessageFilter which calls
+ // ~HostSharedBitmapClient (which deletes shared bitmaps from child)
+ // can race with OnBeginFrameDeadline which draws a frame.
+ // In these cases, shared bitmaps (and this read lock) won't be valid.
+ // Renderers need to silently handle locks failing until this race
+ // is fixed. DCHECK that this is the only case where there are no pixels.
+ DCHECK(!resource->shared_bitmap_id.IsZero());
+ }
+}
+
+DisplayResourceProvider::ScopedReadLockSkImage::~ScopedReadLockSkImage() {
+ resource_provider_->UnlockForRead(resource_id_);
+}
+
+DisplayResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware(
+ DisplayResourceProvider* resource_provider,
+ ResourceId resource_id)
+ : resource_provider_(resource_provider), resource_id_(resource_id) {
+ const internal::Resource* resource =
+ resource_provider->LockForRead(resource_id);
+ DCHECK(resource);
+ resource_provider->PopulateSkBitmapWithResource(&sk_bitmap_, resource);
+}
+
+DisplayResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() {
+ resource_provider_->UnlockForRead(resource_id_);
+}
+
+DisplayResourceProvider::LockSetForExternalUse::LockSetForExternalUse(
+ DisplayResourceProvider* resource_provider)
+ : resource_provider_(resource_provider) {}
+
+DisplayResourceProvider::LockSetForExternalUse::~LockSetForExternalUse() {
+ DCHECK(resources_.empty());
+}
+
+ResourceMetadata DisplayResourceProvider::LockSetForExternalUse::LockResource(
+ ResourceId id) {
+ DCHECK(std::find(resources_.begin(), resources_.end(), id) ==
+ resources_.end());
+ resources_.push_back(id);
+ return resource_provider_->LockForExternalUse(id);
+}
+
+void DisplayResourceProvider::LockSetForExternalUse::UnlockResources(
+ const gpu::SyncToken& sync_token) {
+ for (const auto& id : resources_)
+ resource_provider_->UnlockForExternalUse(id, sync_token);
+ resources_.clear();
+}
+
+DisplayResourceProvider::SynchronousFence::SynchronousFence(
+ gpu::gles2::GLES2Interface* gl)
+ : gl_(gl), has_synchronized_(true) {}
+
+DisplayResourceProvider::SynchronousFence::~SynchronousFence() = default;
+
+void DisplayResourceProvider::SynchronousFence::Set() {
+ has_synchronized_ = false;
+}
+
+bool DisplayResourceProvider::SynchronousFence::HasPassed() {
+ if (!has_synchronized_) {
+ has_synchronized_ = true;
+ Synchronize();
+ }
+ return true;
+}
+
+void DisplayResourceProvider::SynchronousFence::Wait() {
+ HasPassed();
+}
+
+void DisplayResourceProvider::SynchronousFence::Synchronize() {
+ TRACE_EVENT0("cc", "DisplayResourceProvider::SynchronousFence::Synchronize");
+ gl_->Finish();
+}
+
+DisplayResourceProvider::ScopedBatchReturnResources::ScopedBatchReturnResources(
+ DisplayResourceProvider* resource_provider)
+ : resource_provider_(resource_provider) {
+ resource_provider_->SetBatchReturnResources(true);
+}
+
+DisplayResourceProvider::ScopedBatchReturnResources::
+ ~ScopedBatchReturnResources() {
+ resource_provider_->SetBatchReturnResources(false);
+}
+
+DisplayResourceProvider::Child::Child() = default;
+DisplayResourceProvider::Child::Child(const Child& other) = default;
+DisplayResourceProvider::Child::~Child() = default;
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/display_resource_provider.h b/chromium/components/viz/service/display/display_resource_provider.h
new file mode 100644
index 00000000000..d81e561bee8
--- /dev/null
+++ b/chromium/components/viz/service/display/display_resource_provider.h
@@ -0,0 +1,397 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_
+
+#include <stddef.h>
+#include <map>
+#include <unordered_map>
+#include <vector>
+
+#include "base/containers/flat_map.h"
+#include "base/containers/small_map.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
+#include "components/viz/common/resources/resource.h"
+#include "components/viz/common/resources/resource_fence.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/resources/resource_metadata.h"
+#include "components/viz/common/resources/return_callback.h"
+#include "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/service/display/overlay_candidate.h"
+#include "components/viz/service/viz_service_export.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+
+namespace gfx {
+class ColorSpace;
+class Size;
+} // namespace gfx
+
+namespace gpu {
+namespace gles2 {
+class GLES2Interface;
+}
+} // namespace gpu
+
+namespace viz {
+class ContextProvider;
+class SharedBitmapManager;
+
+// This class provides abstractions for receiving and using resources from other
+// modules/threads/processes. It abstracts away GL textures vs GpuMemoryBuffers
+// vs software bitmaps behind a single ResourceId so that code in common can
+// hold onto ResourceIds, as long as the code using them knows the correct type.
+// It accepts as input TransferableResources which it holds internally, tracks
+// state on, and exposes as a ResourceId.
+//
+// The resource's underlying type is accessed through locks that help to
+// scope and safeguard correct usage with DCHECKs.
+//
+// This class is not thread-safe and can only be called from the thread it was
+// created on.
+class VIZ_SERVICE_EXPORT DisplayResourceProvider
+ : public base::trace_event::MemoryDumpProvider {
+ public:
+ DisplayResourceProvider(ContextProvider* compositor_context_provider,
+ SharedBitmapManager* shared_bitmap_manager);
+ ~DisplayResourceProvider() override;
+
+ bool IsSoftware() const { return !compositor_context_provider_; }
+ void DidLoseContextProvider() { lost_context_provider_ = true; }
+ size_t num_resources() const { return resources_.size(); }
+
+ // base::trace_event::MemoryDumpProvider implementation.
+ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+ base::trace_event::ProcessMemoryDump* pmd) override;
+
+#if defined(OS_ANDROID)
+ // Send an overlay promotion hint to all resources that requested it via
+ // |wants_promotion_hints_set_|. |promotable_hints| contains all the
+ // resources that should be told that they're promotable. Others will be told
+ // that they're not promotable right now.
+ void SendPromotionHints(
+ const OverlayCandidateList::PromotionHintInfoMap& promotion_hints);
+
+ // Indicates if this resource is backed by an Android SurfaceTexture, and thus
+ // can't really be promoted to an overlay.
+ bool IsBackedBySurfaceTexture(ResourceId id);
+
+ // Indicates if this resource wants to receive promotion hints.
+ bool WantsPromotionHintForTesting(ResourceId id);
+
+ // Return the number of resources that request promotion hints.
+ size_t CountPromotionHintRequestsForTesting();
+#endif
+
+ ResourceType GetResourceType(ResourceId id);
+ GLenum GetResourceTextureTarget(ResourceId id);
+ // Return the format of the underlying buffer that can be used for scanout.
+ gfx::BufferFormat GetBufferFormat(ResourceId id);
+ // Indicates if this resource may be used for a hardware overlay plane.
+ bool IsOverlayCandidate(ResourceId id);
+
+ void WaitSyncToken(ResourceId id);
+
+ // Checks whether a resource is in use.
+ bool InUse(ResourceId id);
+
+ // The following lock classes are part of the DisplayResourceProvider API and
+ // are needed to read the resource contents. The user must ensure that they
+ // only use GL locks on GL resources, etc, and this is enforced by assertions.
+ class VIZ_SERVICE_EXPORT ScopedReadLockGL {
+ public:
+ ScopedReadLockGL(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id);
+ ~ScopedReadLockGL();
+
+ GLuint texture_id() const { return texture_id_; }
+ GLenum target() const { return target_; }
+ const gfx::Size& size() const { return size_; }
+ const gfx::ColorSpace& color_space() const { return color_space_; }
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ const ResourceId resource_id_;
+
+ GLuint texture_id_ = 0;
+ GLenum target_ = GL_TEXTURE_2D;
+ gfx::Size size_;
+ gfx::ColorSpace color_space_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedReadLockGL);
+ };
+
+ class VIZ_SERVICE_EXPORT ScopedSamplerGL {
+ public:
+ ScopedSamplerGL(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id,
+ GLenum filter);
+ ScopedSamplerGL(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id,
+ GLenum unit,
+ GLenum filter);
+ ~ScopedSamplerGL();
+
+ GLuint texture_id() const { return resource_lock_.texture_id(); }
+ GLenum target() const { return target_; }
+ const gfx::ColorSpace& color_space() const {
+ return resource_lock_.color_space();
+ }
+
+ private:
+ const ScopedReadLockGL resource_lock_;
+ const GLenum unit_;
+ const GLenum target_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSamplerGL);
+ };
+
+ class VIZ_SERVICE_EXPORT ScopedReadLockSkImage {
+ public:
+ ScopedReadLockSkImage(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id);
+ ~ScopedReadLockSkImage();
+
+ const SkImage* sk_image() const { return sk_image_.get(); }
+
+ bool valid() const { return !!sk_image_; }
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ const ResourceId resource_id_;
+ sk_sp<SkImage> sk_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSkImage);
+ };
+
+ class VIZ_SERVICE_EXPORT ScopedReadLockSoftware {
+ public:
+ ScopedReadLockSoftware(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id);
+ ~ScopedReadLockSoftware();
+
+ const SkBitmap* sk_bitmap() const {
+ DCHECK(valid());
+ return &sk_bitmap_;
+ }
+
+ bool valid() const { return !!sk_bitmap_.getPixels(); }
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ const ResourceId resource_id_;
+ SkBitmap sk_bitmap_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedReadLockSoftware);
+ };
+
+ // Maintains set of lock for external use.
+ class VIZ_SERVICE_EXPORT LockSetForExternalUse {
+ public:
+ explicit LockSetForExternalUse(DisplayResourceProvider* resource_provider);
+ ~LockSetForExternalUse();
+
+ // Lock a resource for external use.
+ ResourceMetadata LockResource(ResourceId resource_id);
+
+ // Unlock all locked resources with a |sync_token|.
+ // See UnlockForExternalUse for the detail. All resources must be unlocked
+ // before destroying this class.
+ void UnlockResources(const gpu::SyncToken& sync_token);
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+ std::vector<ResourceId> resources_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockSetForExternalUse);
+ };
+
+ // All resources that are returned to children while an instance of this
+ // class exists will be stored and returned when the instance is destroyed.
+ class VIZ_SERVICE_EXPORT ScopedBatchReturnResources {
+ public:
+ explicit ScopedBatchReturnResources(
+ DisplayResourceProvider* resource_provider);
+ ~ScopedBatchReturnResources();
+
+ private:
+ DisplayResourceProvider* const resource_provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedBatchReturnResources);
+ };
+
+ class VIZ_SERVICE_EXPORT SynchronousFence : public ResourceFence {
+ public:
+ explicit SynchronousFence(gpu::gles2::GLES2Interface* gl);
+
+ // ResourceFence implementation.
+ void Set() override;
+ bool HasPassed() override;
+ void Wait() override;
+
+ // Returns true if fence has been set but not yet synchornized.
+ bool has_synchronized() const { return has_synchronized_; }
+
+ private:
+ ~SynchronousFence() override;
+
+ void Synchronize();
+
+ gpu::gles2::GLES2Interface* gl_;
+ bool has_synchronized_;
+
+ DISALLOW_COPY_AND_ASSIGN(SynchronousFence);
+ };
+
+ // Sets the current read fence. If a resource is locked for read
+ // and has read fences enabled, the resource will not allow writes
+ // until this fence has passed.
+ void SetReadLockFence(ResourceFence* fence) {
+ current_read_lock_fence_ = fence;
+ }
+
+ // Creates accounting for a child. Returns a child ID.
+ int CreateChild(const ReturnCallback& return_callback);
+
+ // Destroys accounting for the child, deleting all accounted resources.
+ void DestroyChild(int child);
+
+ // Sets whether resources need sync points set on them when returned to this
+ // child. Defaults to true.
+ void SetChildNeedsSyncTokens(int child, bool needs_sync_tokens);
+
+ // Gets the child->parent resource ID map.
+ const std::unordered_map<ResourceId, ResourceId>& GetChildToParentMap(
+ int child) const;
+
+ // Receives resources from a child, moving them from mailboxes. ResourceIds
+ // passed are in the child namespace, and will be translated to the parent
+ // namespace, added to the child->parent map.
+ // This adds the resources to the working set in the ResourceProvider without
+ // declaring which resources are in use. Use DeclareUsedResourcesFromChild
+ // after calling this method to do that. All calls to ReceiveFromChild should
+ // be followed by a DeclareUsedResourcesFromChild.
+ // NOTE: if the sync_token is set on any TransferableResource, this will
+ // wait on it.
+ void ReceiveFromChild(
+ int child,
+ const std::vector<TransferableResource>& transferable_resources);
+
+ // Once a set of resources have been received, they may or may not be used.
+ // This declares what set of resources are currently in use from the child,
+ // releasing any other resources back to the child.
+ void DeclareUsedResourcesFromChild(int child,
+ const ResourceIdSet& resources_from_child);
+
+ private:
+ struct Child {
+ Child();
+ Child(const Child& other);
+ ~Child();
+
+ std::unordered_map<ResourceId, ResourceId> child_to_parent_map;
+ ReturnCallback return_callback;
+ bool marked_for_deletion = false;
+ bool needs_sync_tokens = true;
+ };
+
+ enum DeleteStyle {
+ NORMAL,
+ FOR_SHUTDOWN,
+ };
+
+ using ChildMap = std::unordered_map<int, Child>;
+ using ResourceMap = std::unordered_map<ResourceId, internal::Resource>;
+
+ internal::Resource* InsertResource(ResourceId id,
+ internal::Resource resource);
+ internal::Resource* GetResource(ResourceId id);
+
+ // TODO(ericrk): TryGetResource is part of a temporary workaround for cases
+ // where resources which should be available are missing. This version may
+ // return nullptr if a resource is not found. https://crbug.com/811858
+ internal::Resource* TryGetResource(ResourceId id);
+
+ void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap,
+ const internal::Resource* resource);
+
+ void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style);
+
+ void WaitSyncTokenInternal(internal::Resource* resource);
+
+ // Returns null if we do not have a ContextProvider.
+ gpu::gles2::GLES2Interface* ContextGL() const;
+
+ const internal::Resource* LockForRead(ResourceId id);
+ void UnlockForRead(ResourceId id);
+
+ // Lock a resource for external use.
+ ResourceMetadata LockForExternalUse(ResourceId id);
+
+ // Unlock a resource which locked by LockForExternalUse.
+ // The |sync_token| should be waited on before reusing the resouce's backing
+ // to ensure that any external use of it is completed. This |sync_token|
+ // should have been verified.
+ void UnlockForExternalUse(ResourceId id, const gpu::SyncToken& sync_token);
+
+ void TryReleaseResource(ResourceMap::iterator it);
+ // Binds the given GL resource to a texture target for sampling using the
+ // specified filter for both minification and magnification. Returns the
+ // texture target used. The resource must be locked for reading.
+ GLenum BindForSampling(ResourceId resource_id, GLenum unit, GLenum filter);
+ bool ReadLockFenceHasPassed(const internal::Resource* resource);
+#if defined(OS_ANDROID)
+ void DeletePromotionHint(ResourceMap::iterator it, DeleteStyle style);
+#endif
+
+ void DeleteAndReturnUnusedResourcesToChild(
+ ChildMap::iterator child_it,
+ DeleteStyle style,
+ const std::vector<ResourceId>& unused);
+ void DestroyChildInternal(ChildMap::iterator it, DeleteStyle style);
+
+ void SetBatchReturnResources(bool aggregate);
+
+ THREAD_CHECKER(thread_checker_);
+ ContextProvider* const compositor_context_provider_;
+ SharedBitmapManager* const shared_bitmap_manager_;
+
+ ResourceMap resources_;
+ ChildMap children_;
+ base::flat_map<ResourceId, sk_sp<SkImage>> resource_sk_image_;
+ // Maps from a child id to the set of resources to be returned to it.
+ base::small_map<std::map<int, std::vector<ResourceId>>>
+ batched_returning_resources_;
+ scoped_refptr<ResourceFence> current_read_lock_fence_;
+ // Keep track of whether deleted resources should be batched up or returned
+ // immediately.
+ bool batch_return_resources_ = false;
+ // Set to true when the ContextProvider becomes lost, to inform that resources
+ // modified by this class are now in an indeterminate state.
+ bool lost_context_provider_ = false;
+ // The ResourceIds in DisplayResourceProvider start from 2 to avoid
+ // conflicts with id from LayerTreeResourceProvider.
+ ResourceId next_id_ = 2;
+ // Used as child id when creating a child.
+ int next_child_ = 1;
+ // A process-unique ID used for disambiguating memory dumps from different
+ // resource providers.
+ int tracing_id_;
+
+#if defined(OS_ANDROID)
+ // Set of ResourceIds that would like to be notified about promotion hints.
+ ResourceIdSet wants_promotion_hints_set_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayResourceProvider);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_DISPLAY_RESOURCE_PROVIDER_H_
diff --git a/chromium/components/viz/service/display/display_resource_provider_unittest.cc b/chromium/components/viz/service/display/display_resource_provider_unittest.cc
new file mode 100644
index 00000000000..af4d091a81a
--- /dev/null
+++ b/chromium/components/viz/service/display/display_resource_provider_unittest.cc
@@ -0,0 +1,1389 @@
+// 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 "components/viz/service/display/display_resource_provider.h"
+#include "cc/resources/layer_tree_resource_provider.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "build/build_config.h"
+#include "cc/test/render_pass_test_utils.h"
+#include "cc/test/resource_provider_test_utils.h"
+#include "components/viz/common/quads/shared_bitmap.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/returned_resource.h"
+#include "components/viz/common/resources/shared_bitmap_manager.h"
+#include "components/viz/common/resources/single_release_callback.h"
+#include "components/viz/test/test_context_provider.h"
+#include "components/viz/test/test_gpu_memory_buffer_manager.h"
+#include "components/viz/test/test_shared_bitmap_manager.h"
+#include "components/viz/test/test_texture.h"
+#include "components/viz/test/test_web_graphics_context_3d.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+using testing::_;
+using testing::Return;
+using testing::SaveArg;
+
+namespace viz {
+namespace {
+
+class MockReleaseCallback {
+ public:
+ MOCK_METHOD2(Released, void(const gpu::SyncToken& token, bool lost));
+};
+
+MATCHER_P(MatchesSyncToken, sync_token, "") {
+ gpu::SyncToken other;
+ memcpy(&other, arg, sizeof(other));
+ return other == sync_token;
+}
+
+static void CollectResources(std::vector<ReturnedResource>* array,
+ const std::vector<ReturnedResource>& returned) {
+ array->insert(array->end(), returned.begin(), returned.end());
+}
+
+static SharedBitmapId CreateAndFillSharedBitmap(SharedBitmapManager* manager,
+ const gfx::Size& size,
+ ResourceFormat format,
+ uint32_t value) {
+ SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId();
+
+ std::unique_ptr<base::SharedMemory> shm =
+ bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888);
+ manager->ChildAllocatedSharedBitmap(
+ bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size,
+ RGBA_8888),
+ shared_bitmap_id);
+
+ std::fill_n(static_cast<uint32_t*>(shm->memory()), size.GetArea(), value);
+ return shared_bitmap_id;
+}
+
+// Shared data between multiple ResourceProviderContext. This contains mailbox
+// contents as well as information about sync points.
+class ContextSharedData {
+ public:
+ static std::unique_ptr<ContextSharedData> Create() {
+ return base::WrapUnique(new ContextSharedData());
+ }
+
+ uint32_t InsertFenceSync() { return next_fence_sync_++; }
+
+ void GenMailbox(GLbyte* mailbox) {
+ memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM);
+ memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_));
+ ++next_mailbox_;
+ }
+
+ void ProduceTexture(const GLbyte* mailbox_name,
+ const gpu::SyncToken& sync_token,
+ scoped_refptr<TestTexture> texture) {
+ uint32_t sync_point = static_cast<uint32_t>(sync_token.release_count());
+
+ unsigned mailbox = 0;
+ memcpy(&mailbox, mailbox_name, sizeof(mailbox));
+ ASSERT_TRUE(mailbox && mailbox < next_mailbox_);
+ textures_[mailbox] = texture;
+ ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point);
+ sync_point_for_mailbox_[mailbox] = sync_point;
+ }
+
+ scoped_refptr<TestTexture> ConsumeTexture(const GLbyte* mailbox_name,
+ const gpu::SyncToken& sync_token) {
+ unsigned mailbox = 0;
+ memcpy(&mailbox, mailbox_name, sizeof(mailbox));
+ DCHECK(mailbox && mailbox < next_mailbox_);
+
+ // If the latest sync point the context has waited on is before the sync
+ // point for when the mailbox was set, pretend we never saw that
+ // ProduceTexture.
+ if (sync_point_for_mailbox_[mailbox] > sync_token.release_count()) {
+ NOTREACHED();
+ return scoped_refptr<TestTexture>();
+ }
+ return textures_[mailbox];
+ }
+
+ private:
+ ContextSharedData() : next_fence_sync_(1), next_mailbox_(1) {}
+
+ uint64_t next_fence_sync_;
+ unsigned next_mailbox_;
+ using TextureMap = std::unordered_map<unsigned, scoped_refptr<TestTexture>>;
+ TextureMap textures_;
+ std::unordered_map<unsigned, uint32_t> sync_point_for_mailbox_;
+};
+
+class ResourceProviderContext : public TestWebGraphicsContext3D {
+ public:
+ static std::unique_ptr<ResourceProviderContext> Create(
+ ContextSharedData* shared_data) {
+ return base::WrapUnique(new ResourceProviderContext(shared_data));
+ }
+
+ void genSyncToken(GLbyte* sync_token) override {
+ uint64_t fence_sync = shared_data_->InsertFenceSync();
+ gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x123),
+ fence_sync);
+ sync_token_data.SetVerifyFlush();
+ // Commit the ProduceTextureDirectCHROMIUM calls at this point, so that
+ // they're associated with the sync point.
+ for (const std::unique_ptr<PendingProduceTexture>& pending_texture :
+ pending_produce_textures_) {
+ shared_data_->ProduceTexture(pending_texture->mailbox, sync_token_data,
+ pending_texture->texture);
+ }
+ pending_produce_textures_.clear();
+ memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
+ }
+
+ void waitSyncToken(const GLbyte* sync_token) override {
+ gpu::SyncToken sync_token_data;
+ if (sync_token)
+ memcpy(&sync_token_data, sync_token, sizeof(sync_token_data));
+
+ if (sync_token_data.release_count() >
+ last_waited_sync_token_.release_count()) {
+ last_waited_sync_token_ = sync_token_data;
+ }
+ }
+
+ const gpu::SyncToken& last_waited_sync_token() const {
+ return last_waited_sync_token_;
+ }
+
+ void texStorage2DEXT(GLenum target,
+ GLint levels,
+ GLuint internalformat,
+ GLint width,
+ GLint height) override {
+ CheckTextureIsBound(target);
+ ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+ ASSERT_EQ(1, levels);
+ GLenum format = GL_RGBA;
+ switch (internalformat) {
+ case GL_RGBA8_OES:
+ break;
+ case GL_BGRA8_EXT:
+ format = GL_BGRA_EXT;
+ break;
+ default:
+ NOTREACHED();
+ }
+ AllocateTexture(gfx::Size(width, height), format);
+ }
+
+ void texImage2D(GLenum target,
+ GLint level,
+ GLenum internalformat,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ const void* pixels) override {
+ CheckTextureIsBound(target);
+ ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+ ASSERT_FALSE(level);
+ ASSERT_EQ(internalformat, format);
+ ASSERT_FALSE(border);
+ ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ AllocateTexture(gfx::Size(width, height), format);
+ if (pixels)
+ SetPixels(0, 0, width, height, pixels);
+ }
+
+ void texSubImage2D(GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void* pixels) override {
+ CheckTextureIsBound(target);
+ ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
+ ASSERT_FALSE(level);
+ ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
+ {
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format);
+ }
+ ASSERT_TRUE(pixels);
+ SetPixels(xoffset, yoffset, width, height, pixels);
+ }
+
+ void genMailboxCHROMIUM(GLbyte* mailbox) override {
+ return shared_data_->GenMailbox(mailbox);
+ }
+
+ void produceTextureDirectCHROMIUM(GLuint texture,
+ const GLbyte* mailbox) override {
+ // Delay moving the texture into the mailbox until the next
+ // sync token, so that it is not visible to other contexts that
+ // haven't waited on that sync point.
+ std::unique_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
+ memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ pending->texture = UnboundTexture(texture);
+ pending_produce_textures_.push_back(std::move(pending));
+ }
+
+ GLuint createAndConsumeTextureCHROMIUM(const GLbyte* mailbox) override {
+ GLuint texture_id = createTexture();
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ scoped_refptr<TestTexture> texture =
+ shared_data_->ConsumeTexture(mailbox, last_waited_sync_token_);
+ namespace_->textures.Replace(texture_id, texture);
+ return texture_id;
+ }
+
+ void GetPixels(const gfx::Size& size,
+ ResourceFormat format,
+ uint8_t* pixels) {
+ CheckTextureIsBound(GL_TEXTURE_2D);
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
+ ASSERT_EQ(texture->size, size);
+ ASSERT_EQ(texture->format, format);
+ memcpy(pixels, texture->data.get(), TextureSizeBytes(size, format));
+ }
+
+ protected:
+ explicit ResourceProviderContext(ContextSharedData* shared_data)
+ : shared_data_(shared_data) {}
+
+ private:
+ void AllocateTexture(const gfx::Size& size, GLenum format) {
+ CheckTextureIsBound(GL_TEXTURE_2D);
+ ResourceFormat texture_format = RGBA_8888;
+ switch (format) {
+ case GL_RGBA:
+ texture_format = RGBA_8888;
+ break;
+ case GL_BGRA_EXT:
+ texture_format = BGRA_8888;
+ break;
+ }
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format);
+ }
+
+ void SetPixels(int xoffset,
+ int yoffset,
+ int width,
+ int height,
+ const void* pixels) {
+ CheckTextureIsBound(GL_TEXTURE_2D);
+ base::AutoLock lock_for_texture_access(namespace_->lock);
+ scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
+ ASSERT_TRUE(texture->data.get());
+ ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width());
+ ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height());
+ ASSERT_TRUE(pixels);
+ size_t in_pitch = TextureSizeBytes(gfx::Size(width, 1), texture->format);
+ size_t out_pitch =
+ TextureSizeBytes(gfx::Size(texture->size.width(), 1), texture->format);
+ uint8_t* dest = texture->data.get() + yoffset * out_pitch +
+ TextureSizeBytes(gfx::Size(xoffset, 1), texture->format);
+ const uint8_t* src = static_cast<const uint8_t*>(pixels);
+ for (int i = 0; i < height; ++i) {
+ memcpy(dest, src, in_pitch);
+ dest += out_pitch;
+ src += in_pitch;
+ }
+ }
+
+ struct PendingProduceTexture {
+ GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
+ scoped_refptr<TestTexture> texture;
+ };
+ ContextSharedData* shared_data_;
+ gpu::SyncToken last_waited_sync_token_;
+ std::vector<std::unique_ptr<PendingProduceTexture>> pending_produce_textures_;
+};
+
+class DisplayResourceProviderTest : public testing::TestWithParam<bool> {
+ public:
+ explicit DisplayResourceProviderTest(bool child_needs_sync_token)
+ : use_gpu_(GetParam()),
+ child_needs_sync_token_(child_needs_sync_token),
+ shared_data_(ContextSharedData::Create()) {
+ if (use_gpu_) {
+ auto context3d(ResourceProviderContext::Create(shared_data_.get()));
+ context3d_ = context3d.get();
+ context_provider_ = TestContextProvider::Create(std::move(context3d));
+ context_provider_->UnboundTestContext3d()
+ ->set_support_texture_format_bgra8888(true);
+ context_provider_->BindToCurrentThread();
+
+ auto child_context_owned =
+ ResourceProviderContext::Create(shared_data_.get());
+ child_context_ = child_context_owned.get();
+ child_context_provider_ =
+ TestContextProvider::Create(std::move(child_context_owned));
+ child_context_provider_->UnboundTestContext3d()
+ ->set_support_texture_format_bgra8888(true);
+ child_context_provider_->BindToCurrentThread();
+ gpu_memory_buffer_manager_ =
+ std::make_unique<TestGpuMemoryBufferManager>();
+ } else {
+ shared_bitmap_manager_ = std::make_unique<TestSharedBitmapManager>();
+ }
+
+ resource_provider_ = std::make_unique<DisplayResourceProvider>(
+ context_provider_.get(), shared_bitmap_manager_.get());
+
+ MakeChildResourceProvider();
+ }
+
+ DisplayResourceProviderTest() : DisplayResourceProviderTest(true) {}
+
+ bool use_gpu() const { return use_gpu_; }
+
+ void MakeChildResourceProvider() {
+ child_resource_provider_ = std::make_unique<cc::LayerTreeResourceProvider>(
+ child_context_provider_.get(), child_needs_sync_token_);
+ }
+
+ static ReturnCallback GetReturnCallback(
+ std::vector<ReturnedResource>* array) {
+ return base::BindRepeating(&CollectResources, array);
+ }
+
+ static void SetResourceFilter(DisplayResourceProvider* resource_provider,
+ ResourceId id,
+ GLenum filter) {
+ DisplayResourceProvider::ScopedSamplerGL sampler(resource_provider, id,
+ GL_TEXTURE_2D, filter);
+ }
+
+ ResourceProviderContext* context() { return context3d_; }
+
+ TransferableResource CreateResource(ResourceFormat format) {
+ if (use_gpu()) {
+ unsigned texture = child_context_->createTexture();
+ gpu::Mailbox gpu_mailbox;
+ child_context_->genMailboxCHROMIUM(gpu_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(texture, gpu_mailbox.name);
+ gpu::SyncToken sync_token;
+ child_context_->genSyncToken(sync_token.GetData());
+ EXPECT_TRUE(sync_token.HasData());
+
+ TransferableResource gl_resource = TransferableResource::MakeGL(
+ gpu_mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token);
+ gl_resource.format = format;
+ return gl_resource;
+ } else {
+ gfx::Size size(64, 64);
+ SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap(
+ shared_bitmap_manager_.get(), size, format, 0);
+
+ return TransferableResource::MakeSoftware(shared_bitmap_id, size, format);
+ }
+ }
+
+ ResourceId MakeGpuResourceAndSendToDisplay(
+ char c,
+ GLuint filter,
+ GLuint target,
+ const gpu::SyncToken& sync_token,
+ DisplayResourceProvider* resource_provider) {
+ ReturnCallback return_callback = base::DoNothing();
+
+ int child = resource_provider->CreateChild(return_callback);
+
+ gpu::Mailbox gpu_mailbox;
+ gpu_mailbox.name[0] = c;
+ gpu_mailbox.name[1] = 0;
+ auto resource = TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR, target,
+ sync_token);
+ resource.id = 11;
+ resource_provider->ReceiveFromChild(child, {resource});
+ auto& map = resource_provider->GetChildToParentMap(child);
+ return map.find(resource.id)->second;
+ }
+
+ protected:
+ const bool use_gpu_;
+ const bool child_needs_sync_token_;
+ const std::unique_ptr<ContextSharedData> shared_data_;
+ ResourceProviderContext* context3d_ = nullptr;
+ ResourceProviderContext* child_context_ = nullptr;
+ scoped_refptr<TestContextProvider> context_provider_;
+ scoped_refptr<TestContextProvider> child_context_provider_;
+ std::unique_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_;
+ std::unique_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
+};
+
+INSTANTIATE_TEST_CASE_P(DisplayResourceProviderTests,
+ DisplayResourceProviderTest,
+ ::testing::Values(false, true));
+
+TEST_P(DisplayResourceProviderTest, LockForExternalUse) {
+ // TODO(penghuang): consider supporting SW mode.
+ if (!use_gpu())
+ return;
+
+ gpu::SyncToken sync_token1(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x123),
+ 0x42);
+ auto mailbox = gpu::Mailbox::Generate();
+ TransferableResource gl_resource = TransferableResource::MakeGL(
+ mailbox, GL_LINEAR, GL_TEXTURE_2D, sync_token1);
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ gl_resource, SingleReleaseCallback::Create(base::DoNothing()));
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer some resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent({id1}, &list,
+ child_context_provider_.get());
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ unsigned parent_id = resource_map[list.front().id];
+
+ DisplayResourceProvider::LockSetForExternalUse lock_set(
+ resource_provider_.get());
+
+ ResourceMetadata metadata = lock_set.LockResource(parent_id);
+ ASSERT_EQ(metadata.mailbox, mailbox);
+ ASSERT_TRUE(metadata.sync_token.HasData());
+
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ // The resource should not be returned due to the external use lock.
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ gpu::SyncToken sync_token2(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x234),
+ 0x456);
+ sync_token2.SetVerifyFlush();
+ lock_set.UnlockResources(sync_token2);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ // The resource should be returned after the lock is released.
+ EXPECT_EQ(1u, returned_to_child.size());
+ EXPECT_EQ(sync_token2, returned_to_child[0].sync_token);
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ child_resource_provider_->RemoveImportedResource(id1);
+}
+
+TEST_P(DisplayResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
+ if (!use_gpu())
+ return;
+
+ MockReleaseCallback release;
+ TransferableResource tran = CreateResource(RGBA_8888);
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ tran, SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+ {
+ // Transfer some resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent(
+ {id1}, &list, child_context_provider_.get());
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+ ResourceId mapped_resource_id = resource_map[list[0].id];
+ resource_provider_->WaitSyncToken(mapped_resource_id);
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ mapped_resource_id);
+
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ ResourceIdSet());
+ EXPECT_EQ(0u, returned_to_child.size());
+ }
+
+ EXPECT_EQ(1u, returned_to_child.size());
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+
+ // No need to wait for the sync token here -- it will be returned to the
+ // client on delete.
+ {
+ EXPECT_CALL(release, Released(_, _));
+ child_resource_provider_->RemoveImportedResource(id1);
+ }
+
+ resource_provider_->DestroyChild(child_id);
+}
+
+class TestFence : public ResourceFence {
+ public:
+ TestFence() = default;
+
+ // ResourceFence implementation.
+ void Set() override {}
+ bool HasPassed() override { return passed; }
+ void Wait() override {}
+
+ bool passed = false;
+
+ private:
+ ~TestFence() override = default;
+};
+
+TEST_P(DisplayResourceProviderTest, ReadLockFenceStopsReturnToChildOrDelete) {
+ if (!use_gpu())
+ return;
+
+ MockReleaseCallback release;
+ TransferableResource tran1 = CreateResource(RGBA_8888);
+ tran1.read_lock_fences_enabled = true;
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ tran1, SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer some resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent({id1}, &list,
+ child_context_provider_.get());
+ ASSERT_EQ(1u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_TRUE(list[0].read_lock_fences_enabled);
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ scoped_refptr<TestFence> fence(new TestFence);
+ resource_provider_->SetReadLockFence(fence.get());
+ {
+ unsigned parent_id = resource_map[list.front().id];
+ resource_provider_->WaitSyncToken(parent_id);
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ parent_id);
+ }
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(0u, returned_to_child.size());
+ fence->passed = true;
+
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(1u, returned_to_child.size());
+
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ EXPECT_CALL(release, Released(_, _));
+ child_resource_provider_->RemoveImportedResource(id1);
+}
+
+TEST_P(DisplayResourceProviderTest, ReadLockFenceDestroyChild) {
+ if (!use_gpu())
+ return;
+
+ MockReleaseCallback release;
+
+ TransferableResource tran1 = CreateResource(RGBA_8888);
+ tran1.read_lock_fences_enabled = true;
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ tran1, SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+
+ TransferableResource tran2 = CreateResource(RGBA_8888);
+ tran2.read_lock_fences_enabled = false;
+ ResourceId id2 = child_resource_provider_->ImportResource(
+ tran2, SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent({id1, id2}, &list,
+ child_context_provider_.get());
+ ASSERT_EQ(2u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ scoped_refptr<TestFence> fence(new TestFence);
+ resource_provider_->SetReadLockFence(fence.get());
+ {
+ for (size_t i = 0; i < list.size(); i++) {
+ unsigned parent_id = resource_map[list[i].id];
+ resource_provider_->WaitSyncToken(parent_id);
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ parent_id);
+ }
+ }
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ EXPECT_EQ(2u, resource_provider_->num_resources());
+
+ resource_provider_->DestroyChild(child_id);
+
+ EXPECT_EQ(0u, resource_provider_->num_resources());
+ EXPECT_EQ(2u, returned_to_child.size());
+
+ // id1 should be lost and id2 should not.
+ EXPECT_EQ(returned_to_child[0].lost, returned_to_child[0].id == id1);
+ EXPECT_EQ(returned_to_child[1].lost, returned_to_child[1].id == id1);
+
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ EXPECT_CALL(release, Released(_, _)).Times(2);
+ child_resource_provider_->RemoveImportedResource(id1);
+ child_resource_provider_->RemoveImportedResource(id2);
+}
+
+TEST_P(DisplayResourceProviderTest, ReadLockFenceContextLost) {
+ if (!use_gpu())
+ return;
+
+ TransferableResource tran1 = CreateResource(RGBA_8888);
+ tran1.read_lock_fences_enabled = true;
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ tran1, SingleReleaseCallback::Create(base::DoNothing()));
+
+ TransferableResource tran2 = CreateResource(RGBA_8888);
+ tran2.read_lock_fences_enabled = false;
+ ResourceId id2 = child_resource_provider_->ImportResource(
+ tran2, SingleReleaseCallback::Create(base::DoNothing()));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent({id1, id2}, &list,
+ child_context_provider_.get());
+ ASSERT_EQ(2u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ scoped_refptr<TestFence> fence(new TestFence);
+ resource_provider_->SetReadLockFence(fence.get());
+ {
+ for (size_t i = 0; i < list.size(); i++) {
+ unsigned parent_id = resource_map[list[i].id];
+ resource_provider_->WaitSyncToken(parent_id);
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ parent_id);
+ }
+ }
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ EXPECT_EQ(2u, resource_provider_->num_resources());
+ resource_provider_->DidLoseContextProvider();
+ resource_provider_ = nullptr;
+
+ EXPECT_EQ(2u, returned_to_child.size());
+
+ EXPECT_TRUE(returned_to_child[0].lost);
+ EXPECT_TRUE(returned_to_child[1].lost);
+}
+
+TEST_P(DisplayResourceProviderTest, ReturnResourcesWithoutSyncToken) {
+ if (!use_gpu())
+ return;
+
+ bool need_sync_tokens = false;
+ auto no_token_resource_provider =
+ std::make_unique<cc::LayerTreeResourceProvider>(
+ child_context_provider_.get(), need_sync_tokens);
+
+ GLuint external_texture_id = child_context_->createExternalTexture();
+
+ // A sync point is specified directly and should be used.
+ gpu::Mailbox external_mailbox;
+ child_context_->genMailboxCHROMIUM(external_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(external_texture_id,
+ external_mailbox.name);
+ gpu::SyncToken external_sync_token;
+ child_context_->genSyncToken(external_sync_token.GetData());
+ EXPECT_TRUE(external_sync_token.HasData());
+ ResourceId id = no_token_resource_provider->ImportResource(
+ TransferableResource::MakeGL(external_mailbox, GL_LINEAR,
+ GL_TEXTURE_EXTERNAL_OES,
+ external_sync_token),
+ SingleReleaseCallback::Create(base::DoNothing()));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+ resource_provider_->SetChildNeedsSyncTokens(child_id, false);
+ {
+ // Transfer some resources to the parent.
+ std::vector<TransferableResource> list;
+ no_token_resource_provider->PrepareSendToParent(
+ {id}, &list, child_context_provider_.get());
+ ASSERT_EQ(1u, list.size());
+ // A given sync point should be passed through.
+ EXPECT_EQ(external_sync_token, list[0].mailbox_holder.sync_token);
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ resource_ids_to_receive);
+ }
+
+ {
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ // Transfer resources back from the parent to the child. Set no resources as
+ // being in use.
+ ResourceIdSet no_resources;
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
+
+ ASSERT_EQ(1u, returned_to_child.size());
+ std::map<ResourceId, gpu::SyncToken> returned_sync_tokens;
+ for (const auto& returned : returned_to_child)
+ returned_sync_tokens[returned.id] = returned.sync_token;
+
+ // Original sync point given should be returned.
+ ASSERT_TRUE(returned_sync_tokens.find(id) != returned_sync_tokens.end());
+ EXPECT_EQ(external_sync_token, returned_sync_tokens[id]);
+ EXPECT_FALSE(returned_to_child[0].lost);
+ no_token_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+ returned_to_child.clear();
+ }
+
+ resource_provider_->DestroyChild(child_id);
+}
+
+// Test that ScopedBatchReturnResources batching works.
+TEST_P(DisplayResourceProviderTest, ScopedBatchReturnResourcesPreventsReturn) {
+ if (!use_gpu())
+ return;
+
+ MockReleaseCallback release;
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer some resources to the parent.
+ std::vector<ResourceId> resource_ids_to_transfer;
+ ResourceId ids[2];
+ for (size_t i = 0; i < base::size(ids); i++) {
+ TransferableResource tran = CreateResource(RGBA_8888);
+ ids[i] = child_resource_provider_->ImportResource(
+ tran, SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+ resource_ids_to_transfer.push_back(ids[i]);
+ }
+
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list,
+ child_context_provider_.get());
+ ASSERT_EQ(2u, list.size());
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(ids[0]));
+ EXPECT_TRUE(child_resource_provider_->InUseByConsumer(ids[1]));
+
+ resource_provider_->ReceiveFromChild(child_id, list);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+
+ std::vector<std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>>
+ read_locks;
+ for (auto& resource_id : list) {
+ unsigned int mapped_resource_id = resource_map[resource_id.id];
+ resource_provider_->WaitSyncToken(mapped_resource_id);
+ read_locks.push_back(
+ std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
+ resource_provider_.get(), mapped_resource_id));
+ }
+
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ std::unique_ptr<DisplayResourceProvider::ScopedBatchReturnResources>
+ returner =
+ std::make_unique<DisplayResourceProvider::ScopedBatchReturnResources>(
+ resource_provider_.get());
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ read_locks.clear();
+ EXPECT_EQ(0u, returned_to_child.size());
+
+ returner.reset();
+ EXPECT_EQ(2u, returned_to_child.size());
+ // All resources in a batch should share a sync token.
+ EXPECT_EQ(returned_to_child[0].sync_token, returned_to_child[1].sync_token);
+
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+ EXPECT_CALL(release, Released(_, _)).Times(2);
+ child_resource_provider_->RemoveImportedResource(ids[0]);
+ child_resource_provider_->RemoveImportedResource(ids[1]);
+}
+
+TEST_P(DisplayResourceProviderTest, LostMailboxInParent) {
+ gpu::Mailbox gpu_mailbox;
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
+ auto tran = TransferableResource::MakeGL(gpu_mailbox, GL_LINEAR,
+ GL_TEXTURE_2D, sync_token);
+ tran.id = 11;
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id = resource_provider_->CreateChild(
+ base::BindRepeating(&CollectResources, &returned_to_child));
+
+ // Receive a resource then lose the gpu context.
+ resource_provider_->ReceiveFromChild(child_id, {tran});
+ resource_provider_->DidLoseContextProvider();
+
+ // Transfer resources back from the parent to the child.
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, {});
+ ASSERT_EQ(1u, returned_to_child.size());
+
+ // Losing an output surface only loses hardware resources.
+ EXPECT_EQ(returned_to_child[0].lost, use_gpu());
+}
+
+TEST_P(DisplayResourceProviderTest, ReadSoftwareResources) {
+ if (use_gpu())
+ return;
+
+ gfx::Size size(64, 64);
+ ResourceFormat format = RGBA_8888;
+ const uint32_t kBadBeef = 0xbadbeef;
+ SharedBitmapId shared_bitmap_id = CreateAndFillSharedBitmap(
+ shared_bitmap_manager_.get(), size, format, kBadBeef);
+
+ auto resource =
+ TransferableResource::MakeSoftware(shared_bitmap_id, size, format);
+
+ MockReleaseCallback release;
+ ResourceId resource_id = child_resource_provider_->ImportResource(
+ resource,
+ SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+ EXPECT_NE(0u, resource_id);
+
+ // Transfer resources to the parent.
+ std::vector<TransferableResource> send_to_parent;
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id = resource_provider_->CreateChild(
+ base::BindRepeating(&CollectResources, &returned_to_child));
+ child_resource_provider_->PrepareSendToParent({resource_id}, &send_to_parent,
+ child_context_provider_.get());
+ resource_provider_->ReceiveFromChild(child_id, send_to_parent);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+ ResourceId mapped_resource_id = resource_map[resource_id];
+
+ {
+ DisplayResourceProvider::ScopedReadLockSoftware lock(
+ resource_provider_.get(), mapped_resource_id);
+ const SkBitmap* sk_bitmap = lock.sk_bitmap();
+ EXPECT_EQ(sk_bitmap->width(), size.width());
+ EXPECT_EQ(sk_bitmap->height(), size.height());
+ EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef);
+ }
+
+ EXPECT_EQ(0u, returned_to_child.size());
+ // Transfer resources back from the parent to the child. Set no resources as
+ // being in use.
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(1u, returned_to_child.size());
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+
+ EXPECT_CALL(release, Released(_, false));
+ child_resource_provider_->RemoveImportedResource(resource_id);
+}
+
+class TextureStateTrackingContext : public TestWebGraphicsContext3D {
+ public:
+ MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture));
+ MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
+ MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
+ MOCK_METHOD2(produceTextureDirectCHROMIUM,
+ void(GLuint texture, const GLbyte* mailbox));
+ MOCK_METHOD1(createAndConsumeTextureCHROMIUM,
+ unsigned(const GLbyte* mailbox));
+
+ // Force all textures to be consecutive numbers starting at "1",
+ // so we easily can test for them.
+ GLuint NextTextureId() override {
+ base::AutoLock lock(namespace_->lock);
+ return namespace_->next_texture_id++;
+ }
+
+ void RetireTextureId(GLuint) override {}
+
+ void genSyncToken(GLbyte* sync_token) override {
+ gpu::SyncToken sync_token_data(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x123),
+ next_fence_sync_++);
+ sync_token_data.SetVerifyFlush();
+ memcpy(sync_token, &sync_token_data, sizeof(sync_token_data));
+ }
+
+ GLuint64 GetNextFenceSync() const { return next_fence_sync_; }
+
+ GLuint64 next_fence_sync_ = 1;
+};
+
+class ResourceProviderTestImportedResourceGLFilters {
+ public:
+ static void RunTest(TestSharedBitmapManager* shared_bitmap_manager,
+ bool mailbox_nearest_neighbor,
+ GLenum sampler_filter) {
+ auto context_owned(std::make_unique<TextureStateTrackingContext>());
+ TextureStateTrackingContext* context = context_owned.get();
+ auto context_provider =
+ TestContextProvider::Create(std::move(context_owned));
+ context_provider->BindToCurrentThread();
+
+ auto resource_provider = std::make_unique<DisplayResourceProvider>(
+ context_provider.get(), shared_bitmap_manager);
+
+ auto child_context_owned = std::make_unique<TextureStateTrackingContext>();
+ TextureStateTrackingContext* child_context = child_context_owned.get();
+ auto child_context_provider =
+ TestContextProvider::Create(std::move(child_context_owned));
+ child_context_provider->BindToCurrentThread();
+
+ auto child_resource_provider =
+ std::make_unique<cc::LayerTreeResourceProvider>(
+ child_context_provider.get(),
+ /*delegated_sync_points_required=*/true);
+
+ unsigned texture_id = 1;
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x12),
+ 0x34);
+ const GLuint64 current_fence_sync = child_context->GetNextFenceSync();
+
+ EXPECT_CALL(*child_context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*child_context, waitSyncToken(_)).Times(0);
+ EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*child_context, createAndConsumeTextureCHROMIUM(_)).Times(0);
+
+ gpu::Mailbox gpu_mailbox;
+ memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
+ GLuint filter = mailbox_nearest_neighbor ? GL_NEAREST : GL_LINEAR;
+ auto resource = TransferableResource::MakeGL(gpu_mailbox, filter,
+ GL_TEXTURE_2D, sync_token);
+
+ MockReleaseCallback release;
+ ResourceId resource_id = child_resource_provider->ImportResource(
+ resource,
+ SingleReleaseCallback::Create(base::BindOnce(
+ &MockReleaseCallback::Released, base::Unretained(&release))));
+ EXPECT_NE(0u, resource_id);
+ EXPECT_EQ(current_fence_sync, child_context->GetNextFenceSync());
+
+ testing::Mock::VerifyAndClearExpectations(child_context);
+
+ // Transfer resources to the parent.
+ std::vector<TransferableResource> send_to_parent;
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id = resource_provider->CreateChild(
+ base::BindRepeating(&CollectResources, &returned_to_child));
+ child_resource_provider->PrepareSendToParent({resource_id}, &send_to_parent,
+ child_context_provider.get());
+ resource_provider->ReceiveFromChild(child_id, send_to_parent);
+
+ // In DisplayResourceProvider's namespace, use the mapped resource id.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider->GetChildToParentMap(child_id);
+ ResourceId mapped_resource_id = resource_map[resource_id];
+ {
+ // The verified flush flag will be set by
+ // cc::LayerTreeResourceProvider::PrepareSendToParent. Before checking if
+ // the gpu::SyncToken matches, set this flag first.
+ sync_token.SetVerifyFlush();
+
+ // Mailbox sync point WaitSyncToken before using the texture.
+ EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token)));
+ resource_provider->WaitSyncToken(mapped_resource_id);
+ testing::Mock::VerifyAndClearExpectations(context);
+
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_))
+ .WillOnce(Return(texture_id));
+ EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
+
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+
+ // The sampler will reset these if |mailbox_nearest_neighbor| does not
+ // match |sampler_filter|.
+ if (mailbox_nearest_neighbor != (sampler_filter == GL_NEAREST)) {
+ EXPECT_CALL(*context,
+ texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ sampler_filter));
+ EXPECT_CALL(*context,
+ texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ sampler_filter));
+ }
+
+ DisplayResourceProvider::ScopedSamplerGL lock(
+ resource_provider.get(), mapped_resource_id, sampler_filter);
+ testing::Mock::VerifyAndClearExpectations(context);
+ EXPECT_EQ(current_fence_sync, context->GetNextFenceSync());
+
+ // When done with it, a sync point should be inserted, but no produce is
+ // necessary.
+ EXPECT_CALL(*child_context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+
+ EXPECT_CALL(*child_context, waitSyncToken(_)).Times(0);
+ EXPECT_CALL(*child_context, createAndConsumeTextureCHROMIUM(_)).Times(0);
+ }
+
+ EXPECT_EQ(0u, returned_to_child.size());
+ // Transfer resources back from the parent to the child. Set no resources as
+ // being in use.
+ resource_provider->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(1u, returned_to_child.size());
+ child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+
+ gpu::SyncToken released_sync_token;
+ {
+ EXPECT_CALL(release, Released(_, false))
+ .WillOnce(SaveArg<0>(&released_sync_token));
+ child_resource_provider->RemoveImportedResource(resource_id);
+ }
+ EXPECT_TRUE(released_sync_token.HasData());
+ }
+};
+
+TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_LinearToLinear) {
+ // Mailboxing is only supported for GL textures.
+ if (!use_gpu())
+ return;
+
+ ResourceProviderTestImportedResourceGLFilters::RunTest(
+ shared_bitmap_manager_.get(), false, GL_LINEAR);
+}
+
+TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_NearestToNearest) {
+ // Mailboxing is only supported for GL textures.
+ if (!use_gpu())
+ return;
+
+ ResourceProviderTestImportedResourceGLFilters::RunTest(
+ shared_bitmap_manager_.get(), true, GL_NEAREST);
+}
+
+TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_NearestToLinear) {
+ // Mailboxing is only supported for GL textures.
+ if (!use_gpu())
+ return;
+
+ ResourceProviderTestImportedResourceGLFilters::RunTest(
+ shared_bitmap_manager_.get(), true, GL_LINEAR);
+}
+
+TEST_P(DisplayResourceProviderTest, ReceiveGLTexture2D_LinearToNearest) {
+ // Mailboxing is only supported for GL textures.
+ if (!use_gpu())
+ return;
+
+ ResourceProviderTestImportedResourceGLFilters::RunTest(
+ shared_bitmap_manager_.get(), false, GL_NEAREST);
+}
+
+TEST_P(DisplayResourceProviderTest, ReceiveGLTextureExternalOES) {
+ // Mailboxing is only supported for GL textures.
+ if (!use_gpu())
+ return;
+
+ auto context_owned(std::make_unique<TextureStateTrackingContext>());
+ TextureStateTrackingContext* context = context_owned.get();
+ auto context_provider = TestContextProvider::Create(std::move(context_owned));
+ context_provider->BindToCurrentThread();
+
+ auto resource_provider = std::make_unique<DisplayResourceProvider>(
+ context_provider.get(), shared_bitmap_manager_.get());
+
+ auto child_context_owned = std::make_unique<TextureStateTrackingContext>();
+ TextureStateTrackingContext* child_context = child_context_owned.get();
+ auto child_context_provider =
+ TestContextProvider::Create(std::move(child_context_owned));
+ child_context_provider->BindToCurrentThread();
+
+ auto child_resource_provider =
+ std::make_unique<cc::LayerTreeResourceProvider>(
+ child_context_provider.get(),
+ /*delegated_sync_points_required=*/true);
+
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
+ const GLuint64 current_fence_sync = child_context->GetNextFenceSync();
+
+ EXPECT_CALL(*child_context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*child_context, waitSyncToken(_)).Times(0);
+ EXPECT_CALL(*child_context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*child_context, createAndConsumeTextureCHROMIUM(_)).Times(0);
+
+ gpu::Mailbox gpu_mailbox;
+ memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
+ std::unique_ptr<SingleReleaseCallback> callback =
+ SingleReleaseCallback::Create(base::DoNothing());
+
+ auto resource = TransferableResource::MakeGL(
+ gpu_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, sync_token);
+
+ ResourceId resource_id =
+ child_resource_provider->ImportResource(resource, std::move(callback));
+ EXPECT_NE(0u, resource_id);
+ EXPECT_EQ(current_fence_sync, child_context->GetNextFenceSync());
+
+ testing::Mock::VerifyAndClearExpectations(child_context);
+
+ // Transfer resources to the parent.
+ std::vector<TransferableResource> send_to_parent;
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id = resource_provider->CreateChild(
+ base::BindRepeating(&CollectResources, &returned_to_child));
+ child_resource_provider->PrepareSendToParent({resource_id}, &send_to_parent,
+ child_context_provider_.get());
+ resource_provider->ReceiveFromChild(child_id, send_to_parent);
+
+ // Before create DrawQuad in DisplayResourceProvider's namespace, get the
+ // mapped resource id first.
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider->GetChildToParentMap(child_id);
+ ResourceId mapped_resource_id = resource_map[resource_id];
+ {
+ // The verified flush flag will be set by
+ // cc::LayerTreeResourceProvider::PrepareSendToParent. Before checking if
+ // the gpu::SyncToken matches, set this flag first.
+ sync_token.SetVerifyFlush();
+
+ // Mailbox sync point WaitSyncToken before using the texture.
+ EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token)));
+ resource_provider->WaitSyncToken(mapped_resource_id);
+ testing::Mock::VerifyAndClearExpectations(context);
+
+ unsigned texture_id = 1;
+
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_))
+ .WillOnce(Return(texture_id));
+
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider.get(),
+ mapped_resource_id);
+ testing::Mock::VerifyAndClearExpectations(context);
+
+ // When done with it, a sync point should be inserted, but no produce is
+ // necessary.
+ EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+
+ EXPECT_CALL(*context, waitSyncToken(_)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_)).Times(0);
+ testing::Mock::VerifyAndClearExpectations(context);
+ }
+ EXPECT_EQ(0u, returned_to_child.size());
+ // Transfer resources back from the parent to the child. Set no resources as
+ // being in use.
+ resource_provider->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(1u, returned_to_child.size());
+ child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
+
+ child_resource_provider->RemoveImportedResource(resource_id);
+}
+
+TEST_P(DisplayResourceProviderTest, WaitSyncTokenIfNeeded) {
+ // Mailboxing is only supported for GL textures.
+ if (!use_gpu())
+ return;
+
+ auto context_owned = std::make_unique<TextureStateTrackingContext>();
+ TextureStateTrackingContext* context = context_owned.get();
+ auto context_provider = TestContextProvider::Create(std::move(context_owned));
+ context_provider->BindToCurrentThread();
+
+ auto resource_provider = std::make_unique<DisplayResourceProvider>(
+ context_provider.get(), shared_bitmap_manager_.get());
+
+ const GLuint64 current_fence_sync = context->GetNextFenceSync();
+
+ EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
+ EXPECT_CALL(*context, waitSyncToken(_)).Times(0);
+ EXPECT_CALL(*context, produceTextureDirectCHROMIUM(_, _)).Times(0);
+ EXPECT_CALL(*context, createAndConsumeTextureCHROMIUM(_)).Times(0);
+
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
+ gpu::CommandBufferId::FromUnsafeValue(0x12), 0x34);
+ ResourceId id_with_sync = MakeGpuResourceAndSendToDisplay(
+ 'a', GL_LINEAR, GL_TEXTURE_2D, sync_token, resource_provider.get());
+ ResourceId id_without_sync = MakeGpuResourceAndSendToDisplay(
+ 'a', GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(), resource_provider.get());
+
+ EXPECT_EQ(current_fence_sync, context->GetNextFenceSync());
+
+ // First call to WaitSyncToken should call WaitSyncToken, but only if a
+ // SyncToken was present.
+ {
+ EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))).Times(1);
+ resource_provider->WaitSyncToken(id_with_sync);
+ EXPECT_CALL(*context, waitSyncToken(_)).Times(0);
+ resource_provider->WaitSyncToken(id_without_sync);
+ }
+
+ {
+ // Subsequent calls to WaitSyncToken shouldn't call WaitSyncToken.
+ EXPECT_CALL(*context, waitSyncToken(_)).Times(0);
+ resource_provider->WaitSyncToken(id_with_sync);
+ resource_provider->WaitSyncToken(id_without_sync);
+ }
+}
+
+#if defined(OS_ANDROID)
+TEST_P(DisplayResourceProviderTest, OverlayPromotionHint) {
+ if (!use_gpu())
+ return;
+
+ GLuint external_texture_id = child_context_->createExternalTexture();
+
+ gpu::Mailbox external_mailbox;
+ child_context_->genMailboxCHROMIUM(external_mailbox.name);
+ child_context_->produceTextureDirectCHROMIUM(external_texture_id,
+ external_mailbox.name);
+ gpu::SyncToken external_sync_token;
+ child_context_->genSyncToken(external_sync_token.GetData());
+ EXPECT_TRUE(external_sync_token.HasData());
+
+ TransferableResource id1_transfer = TransferableResource::MakeGLOverlay(
+ external_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, external_sync_token,
+ gfx::Size(1, 1), true);
+ id1_transfer.wants_promotion_hint = true;
+ id1_transfer.is_backed_by_surface_texture = true;
+ ResourceId id1 = child_resource_provider_->ImportResource(
+ id1_transfer, SingleReleaseCallback::Create(base::DoNothing()));
+
+ TransferableResource id2_transfer = TransferableResource::MakeGLOverlay(
+ external_mailbox, GL_LINEAR, GL_TEXTURE_EXTERNAL_OES, external_sync_token,
+ gfx::Size(1, 1), true);
+ id2_transfer.wants_promotion_hint = false;
+ id2_transfer.is_backed_by_surface_texture = false;
+ ResourceId id2 = child_resource_provider_->ImportResource(
+ id2_transfer, SingleReleaseCallback::Create(base::DoNothing()));
+
+ std::vector<ReturnedResource> returned_to_child;
+ int child_id =
+ resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
+
+ // Transfer some resources to the parent.
+ std::vector<TransferableResource> list;
+ child_resource_provider_->PrepareSendToParent({id1, id2}, &list,
+ child_context_provider_.get());
+ ASSERT_EQ(2u, list.size());
+ resource_provider_->ReceiveFromChild(child_id, list);
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ resource_provider_->GetChildToParentMap(child_id);
+ ResourceId mapped_id1 = resource_map[list[0].id];
+ ResourceId mapped_id2 = resource_map[list[1].id];
+
+ // The promotion hints should not be recorded until after we wait. This is
+ // because we can't notify them until they're synchronized, and we choose to
+ // ignore unwaited resources rather than send them a "no" hint. If they end
+ // up in the request set before we wait, then the attempt to notify them wil;
+ // DCHECK when we try to lock them for reading in SendPromotionHints.
+ EXPECT_EQ(0u, resource_provider_->CountPromotionHintRequestsForTesting());
+ {
+ resource_provider_->WaitSyncToken(mapped_id1);
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ mapped_id1);
+ }
+ EXPECT_EQ(1u, resource_provider_->CountPromotionHintRequestsForTesting());
+
+ EXPECT_EQ(list[0].mailbox_holder.sync_token,
+ context3d_->last_waited_sync_token());
+ ResourceIdSet resource_ids_to_receive;
+ resource_ids_to_receive.insert(id1);
+ resource_ids_to_receive.insert(id2);
+ resource_provider_->DeclareUsedResourcesFromChild(child_id,
+ resource_ids_to_receive);
+
+ EXPECT_EQ(2u, resource_provider_->num_resources());
+
+ EXPECT_NE(0u, mapped_id1);
+ EXPECT_NE(0u, mapped_id2);
+
+ // Make sure that the request for a promotion hint was noticed.
+ EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id1));
+ EXPECT_TRUE(resource_provider_->IsBackedBySurfaceTexture(mapped_id1));
+ EXPECT_TRUE(resource_provider_->WantsPromotionHintForTesting(mapped_id1));
+
+ EXPECT_TRUE(resource_provider_->IsOverlayCandidate(mapped_id2));
+ EXPECT_FALSE(resource_provider_->IsBackedBySurfaceTexture(mapped_id2));
+ EXPECT_FALSE(resource_provider_->WantsPromotionHintForTesting(mapped_id2));
+
+ // ResourceProvider maintains a set of promotion hint requests that should be
+ // cleared when resources are deleted.
+ resource_provider_->DeclareUsedResourcesFromChild(child_id, ResourceIdSet());
+ EXPECT_EQ(2u, returned_to_child.size());
+ child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
+
+ EXPECT_EQ(0u, resource_provider_->CountPromotionHintRequestsForTesting());
+
+ resource_provider_->DestroyChild(child_id);
+}
+#endif
+
+} // namespace
+} // namespace viz
diff --git a/chromium/components/viz/service/display/display_unittest.cc b/chromium/components/viz/service/display/display_unittest.cc
index fa0e2f93a52..696bdb03231 100644
--- a/chromium/components/viz/service/display/display_unittest.cc
+++ b/chromium/components/viz/service/display/display_unittest.cc
@@ -30,8 +30,8 @@
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/mock_compositor_frame_sink_client.h"
+#include "components/viz/test/test_gles2_interface.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -107,21 +107,40 @@ class DisplayTest : public testing::Test {
~DisplayTest() override {}
- void SetUpDisplay(const RendererSettings& settings,
- std::unique_ptr<TestWebGraphicsContext3D> context) {
- begin_frame_source_.reset(new StubBeginFrameSource);
+ void SetUpSoftwareDisplay(const RendererSettings& settings) {
+ std::unique_ptr<FakeOutputSurface> output_surface;
+ auto device = std::make_unique<TestSoftwareOutputDevice>();
+ software_output_device_ = device.get();
+ output_surface = FakeOutputSurface::CreateSoftware(std::move(device));
+ output_surface_ = output_surface.get();
+ CreateDisplaySchedulerAndDisplay(settings, kArbitraryFrameSinkId,
+ std::move(output_surface));
+ }
+
+ void SetUpGpuDisplay(const RendererSettings& settings,
+ std::unique_ptr<TestGLES2Interface> context = nullptr) {
std::unique_ptr<FakeOutputSurface> output_surface;
+ scoped_refptr<TestContextProvider> provider;
if (context) {
- auto provider = TestContextProvider::Create(std::move(context));
- provider->BindToCurrentThread();
- output_surface = FakeOutputSurface::Create3d(std::move(provider));
+ provider = TestContextProvider::Create(std::move(context));
+
} else {
- auto device = std::make_unique<TestSoftwareOutputDevice>();
- software_output_device_ = device.get();
- output_surface = FakeOutputSurface::CreateSoftware(std::move(device));
+ provider = TestContextProvider::Create();
}
+ provider->BindToCurrentThread();
+ output_surface = FakeOutputSurface::Create3d(std::move(provider));
output_surface_ = output_surface.get();
+
+ CreateDisplaySchedulerAndDisplay(settings, kArbitraryFrameSinkId,
+ std::move(output_surface));
+ }
+
+ void CreateDisplaySchedulerAndDisplay(
+ const RendererSettings& settings,
+ const FrameSinkId& frame_sink_id,
+ std::unique_ptr<OutputSurface> output_surface) {
+ begin_frame_source_.reset(new StubBeginFrameSource);
auto scheduler = std::make_unique<TestDisplayScheduler>(
begin_frame_source_.get(), task_runner_.get());
scheduler_ = scheduler.get();
@@ -187,6 +206,8 @@ class StubDisplayClient : public DisplayClient {
void DisplayDidDrawAndSwap() override {}
void DisplayDidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) override{};
+ void DidSwapAfterSnapshotRequestReceived(
+ const std::vector<ui::LatencyInfo>& latency_info) override {}
};
void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
@@ -198,7 +219,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
RendererSettings settings;
settings.partial_swap_enabled = true;
settings.finish_rendering_on_resize = true;
- SetUpDisplay(settings, nullptr);
+ SetUpSoftwareDisplay(settings);
gfx::ColorSpace color_space_1 = gfx::ColorSpace::CreateXYZD50();
gfx::ColorSpace color_space_2 = gfx::ColorSpace::CreateSCRGBLinear();
@@ -462,7 +483,7 @@ TEST_F(DisplayTest, DisplayDamaged) {
void DisplayTest::LatencyInfoCapTest(bool over_capacity) {
RendererSettings settings;
settings.finish_rendering_on_resize = true;
- SetUpDisplay(settings, nullptr);
+ SetUpSoftwareDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -530,9 +551,9 @@ TEST_F(DisplayTest, OverLatencyInfoCap) {
LatencyInfoCapTest(true);
}
-class MockedContext : public TestWebGraphicsContext3D {
+class MockedGLES2Interface : public TestGLES2Interface {
public:
- MOCK_METHOD0(shallowFinishCHROMIUM, void());
+ MOCK_METHOD0(ShallowFinishCHROMIUM, void());
};
TEST_F(DisplayTest, Finish) {
@@ -543,11 +564,11 @@ TEST_F(DisplayTest, Finish) {
settings.partial_swap_enabled = true;
settings.finish_rendering_on_resize = true;
- auto context = std::make_unique<MockedContext>();
- MockedContext* context_ptr = context.get();
- EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
+ auto gl = std::make_unique<MockedGLES2Interface>();
+ MockedGLES2Interface* gl_ptr = gl.get();
+ EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()).Times(0);
- SetUpDisplay(settings, std::move(context));
+ SetUpGpuDisplay(settings, std::move(gl));
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -570,19 +591,19 @@ TEST_F(DisplayTest, Finish) {
display_->DrawAndSwap();
// First resize and draw shouldn't finish.
- testing::Mock::VerifyAndClearExpectations(context_ptr);
+ testing::Mock::VerifyAndClearExpectations(gl_ptr);
- EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM());
+ EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM());
display_->Resize(gfx::Size(150, 150));
- testing::Mock::VerifyAndClearExpectations(context_ptr);
+ testing::Mock::VerifyAndClearExpectations(gl_ptr);
// Another resize without a swap doesn't need to finish.
- EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
+ EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()).Times(0);
display_->SetLocalSurfaceId(local_surface_id2, 1.f);
display_->Resize(gfx::Size(200, 200));
- testing::Mock::VerifyAndClearExpectations(context_ptr);
+ testing::Mock::VerifyAndClearExpectations(gl_ptr);
- EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
+ EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM()).Times(0);
{
RenderPassList pass_list;
auto pass = RenderPass::Create();
@@ -596,11 +617,11 @@ TEST_F(DisplayTest, Finish) {
display_->DrawAndSwap();
- testing::Mock::VerifyAndClearExpectations(context_ptr);
+ testing::Mock::VerifyAndClearExpectations(gl_ptr);
- EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM());
+ EXPECT_CALL(*gl_ptr, ShallowFinishCHROMIUM());
display_->Resize(gfx::Size(250, 250));
- testing::Mock::VerifyAndClearExpectations(context_ptr);
+ testing::Mock::VerifyAndClearExpectations(gl_ptr);
TearDownDisplay();
}
@@ -617,7 +638,7 @@ class CountLossDisplayClient : public StubDisplayClient {
};
TEST_F(DisplayTest, ContextLossInformsClient) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
CountLossDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -639,7 +660,7 @@ TEST_F(DisplayTest, CompositorFrameDamagesCorrectDisplay) {
LocalSurfaceId local_surface_id(id_allocator_.GenerateId());
// Set up first display.
- SetUpDisplay(settings, nullptr);
+ SetUpSoftwareDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
display_->SetLocalSurfaceId(local_surface_id, 1.f);
@@ -690,7 +711,7 @@ TEST_F(DisplayTest, CompositorFrameDamagesCorrectDisplay) {
// Check if draw occlusion does not remove any DrawQuads when no quad is being
// covered completely.
TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -911,7 +932,7 @@ TEST_F(DisplayTest, DrawOcclusionWithNonCoveringDrawQuad) {
TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1042,7 +1063,7 @@ TEST_F(DisplayTest, CompositorFrameWithOverlapDrawQuad) {
// skip_rect size, such that DrawQuads that are smaller than the |skip_rect|
// are drawn on the screen regardless is shown or not.
TEST_F(DisplayTest, DrawOcclusionWithSkipRect) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1166,7 +1187,7 @@ TEST_F(DisplayTest, DrawOcclusionWithSkipRect) {
// skip_rect size, such that DrawQuads that are smaller than the |skip_rect|
// cannot occlude other quads behind it.
TEST_F(DisplayTest, OcclusionIgnoringSkipRect) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1228,7 +1249,7 @@ TEST_F(DisplayTest, OcclusionIgnoringSkipRect) {
TEST_F(DisplayTest, CompositorFrameWithTransformer) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1499,7 +1520,7 @@ TEST_F(DisplayTest, CompositorFrameWithTransformer) {
// Check if draw occlusion works with transform at epsilon scale.
TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1611,7 +1632,7 @@ TEST_F(DisplayTest, CompositorFrameWithEpsilonScaleTransform) {
// Check if draw occlusion works with transform at negative scale.
TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1736,7 +1757,7 @@ TEST_F(DisplayTest, CompositorFrameWithNegativeScaleTransform) {
TEST_F(DisplayTest, CompositorFrameWithRotation) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1865,7 +1886,7 @@ TEST_F(DisplayTest, CompositorFrameWithRotation) {
TEST_F(DisplayTest, CompositorFrameWithPerspective) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -1941,7 +1962,7 @@ TEST_F(DisplayTest, CompositorFrameWithPerspective) {
TEST_F(DisplayTest, CompositorFrameWithOpacityChange) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2008,7 +2029,7 @@ TEST_F(DisplayTest, CompositorFrameWithOpacityChange) {
TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2076,7 +2097,7 @@ TEST_F(DisplayTest, CompositorFrameWithOpaquenessChange) {
TEST_F(DisplayTest, CompositorFrameZTranslate) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2131,7 +2152,7 @@ TEST_F(DisplayTest, CompositorFrameZTranslate) {
TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2252,7 +2273,7 @@ TEST_F(DisplayTest, CompositorFrameWithTranslateTransformer) {
TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2380,7 +2401,7 @@ TEST_F(DisplayTest, CompositorFrameWithCombinedSharedQuadState) {
TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2454,7 +2475,7 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleRenderPass) {
}
TEST_F(DisplayTest, CompositorFrameWithCoveredRenderPass) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2524,7 +2545,7 @@ TEST_F(DisplayTest, CompositorFrameWithCoveredRenderPass) {
TEST_F(DisplayTest, CompositorFrameWithClip) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2641,7 +2662,7 @@ TEST_F(DisplayTest, CompositorFrameWithClip) {
TEST_F(DisplayTest, CompositorFrameWithCopyRequest) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2689,7 +2710,7 @@ TEST_F(DisplayTest, CompositorFrameWithCopyRequest) {
TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -2869,7 +2890,7 @@ TEST_F(DisplayTest, CompositorFrameWithRenderPass) {
TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -3046,7 +3067,7 @@ TEST_F(DisplayTest, CompositorFrameWithMultipleDrawQuadInSharedQuadState) {
TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) {
RendererSettings settings;
settings.kMinimumDrawOcclusionSize.set_width(0);
- SetUpDisplay(settings, TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -3149,7 +3170,7 @@ TEST_F(DisplayTest, CompositorFrameWithNonInvertibleTransform) {
// Check if draw occlusion works with very large DrawQuad. crbug.com/824528.
TEST_F(DisplayTest, DrawOcclusionWithLargeDrawQuad) {
- SetUpDisplay(RendererSettings(), TestWebGraphicsContext3D::Create());
+ SetUpGpuDisplay(RendererSettings());
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
@@ -3194,7 +3215,7 @@ TEST_F(DisplayTest, CompositorFrameWithPresentationToken) {
const LocalSurfaceId local_surface_id(id_allocator_.GenerateId());
// Set up first display.
- SetUpDisplay(settings, nullptr);
+ SetUpSoftwareDisplay(settings);
StubDisplayClient client;
display_->Initialize(&client, manager_.surface_manager());
display_->SetLocalSurfaceId(local_surface_id, 1.f);
diff --git a/chromium/components/viz/service/display/gl_renderer.cc b/chromium/components/viz/service/display/gl_renderer.cc
index 0393c487f08..afda183f41e 100644
--- a/chromium/components/viz/service/display/gl_renderer.cc
+++ b/chromium/components/viz/service/display/gl_renderer.cc
@@ -58,7 +58,6 @@
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/gpu_memory_allocation.h"
#include "media/base/media_switches.h"
-#include "skia/ext/texture_handle.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkColorFilter.h"
@@ -222,10 +221,8 @@ struct GLRenderer::DrawRenderPassDrawQuadParams {
bool use_aa = false;
- // Some filters affect pixels outside the original contents bounds. This
- // requires translation of the source when texturing, as well as a change in
- // the bounds of the destination.
- gfx::Point src_offset;
+ // Some filters affect pixels outside the original contents bounds, in which
+ // case ApplyImageFilter will modify this rect.
gfx::RectF dst_rect;
// A Skia image that should be sampled from instead of the original
@@ -233,25 +230,11 @@ struct GLRenderer::DrawRenderPassDrawQuadParams {
sk_sp<SkImage> filter_image;
// The original contents, bound for sampling.
- std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL>
+ std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL>
bypass_quad_resource_lock;
// A mask to be applied when drawing the RPDQ.
- std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL>
- mask_resource_lock;
-
- // Original background texture.
- uint32_t background_texture = 0;
-
- // Backdrop bounding box.
- gfx::Rect background_rect;
-
- // Filtered background texture.
- sk_sp<SkImage> background_image;
- GLuint background_image_id = 0;
-
- // Whether the original background texture is needed for the mask.
- bool mask_for_background = false;
+ std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> mask_resource_lock;
// Whether a color matrix needs to be applied by the shaders when drawing
// the RPDQ.
@@ -266,6 +249,17 @@ struct GLRenderer::DrawRenderPassDrawQuadParams {
// The color space of the texture bound for sampling (from filter_image or
// bypass_quad_resource_lock, depending on the path taken).
gfx::ColorSpace contents_and_bypass_color_space;
+
+ // Background filters block.
+ // Original background texture.
+ uint32_t background_texture = 0;
+ // Backdrop bounding box.
+ gfx::Rect background_rect;
+ // Filtered background texture.
+ sk_sp<SkImage> background_image;
+ GLuint background_image_id = 0;
+ // Whether the original background texture is needed for the mask.
+ bool mask_for_background = false;
};
class GLRenderer::ScopedUseGrContext {
@@ -307,7 +301,7 @@ class GLRenderer::ScopedUseGrContext {
GLRenderer::GLRenderer(
const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)
: DirectRenderer(settings, output_surface, resource_provider),
shared_geometry_quad_(QuadVertexRect()),
@@ -452,8 +446,7 @@ void GLRenderer::BeginDrawingFrame() {
read_lock_fence = sync_queries_.StartNewFrame();
} else {
read_lock_fence =
- base::MakeRefCounted<cc::DisplayResourceProvider::SynchronousFence>(
- gl_);
+ base::MakeRefCounted<DisplayResourceProvider::SynchronousFence>(gl_);
}
resource_provider_->SetReadLockFence(read_lock_fence.get());
@@ -1028,6 +1021,21 @@ bool GLRenderer::InitializeRPDQParameters(
return true;
}
+// Get a GL texture id from an SkImage. An optional origin pointer can be
+// passed in which will be filled out with the origin for the texture
+// backing the SkImage.
+static GLuint GetGLTextureIDFromSkImage(const SkImage* image,
+ GrSurfaceOrigin* origin = nullptr) {
+ GrBackendTexture backend_texture = image->getBackendTexture(true, origin);
+ if (!backend_texture.isValid()) {
+ return 0;
+ }
+ GrGLTextureInfo info;
+ bool result = backend_texture.getGLTextureInfo(&info);
+ DCHECK(result);
+ return info.fID;
+}
+
void GLRenderer::UpdateRPDQShadersForBlending(
DrawRenderPassDrawQuadParams* params) {
const RenderPassDrawQuad* quad = params->quad;
@@ -1067,10 +1075,8 @@ void GLRenderer::UpdateRPDQShadersForBlending(
params->background_rect, unclipped_rect);
if (params->background_image) {
params->background_image_id =
- skia::GrBackendObjectToGrGLTextureInfo(
- params->background_image->getTextureHandle(true))
- ->fID;
- DCHECK(params->background_image_id);
+ GetGLTextureIDFromSkImage(params->background_image.get());
+ DCHECK(params->background_image_id || IsContextLost());
}
}
}
@@ -1169,7 +1175,7 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters(
src_image, src_rect, params->dst_rect, quad->filters_scale,
std::move(filter), &offset, &subset, quad->filters_origin);
} else {
- cc::DisplayResourceProvider::ScopedReadLockGL
+ DisplayResourceProvider::ScopedReadLockGL
prefilter_bypass_quad_texture_lock(
resource_provider_, params->bypass_quad_texture.resource_id);
params->contents_and_bypass_color_space =
@@ -1189,8 +1195,7 @@ bool GLRenderer::UpdateRPDQWithSkiaFilters(
params->dst_rect =
gfx::RectF(src_rect.x() + offset.fX, src_rect.y() + offset.fY,
subset.width(), subset.height());
- params->src_offset.SetPoint(subset.x(), subset.y());
- gfx::RectF tex_rect = gfx::RectF(gfx::PointF(params->src_offset),
+ gfx::RectF tex_rect = gfx::RectF(gfx::PointF(subset.x(), subset.y()),
params->dst_rect.size());
params->tex_coord_rect = tex_rect;
}
@@ -1203,7 +1208,7 @@ void GLRenderer::UpdateRPDQTexturesForSampling(
DrawRenderPassDrawQuadParams* params) {
if (params->quad->mask_resource_id()) {
params->mask_resource_lock.reset(
- new cc::DisplayResourceProvider::ScopedSamplerGL(
+ new DisplayResourceProvider::ScopedSamplerGL(
resource_provider_, params->quad->mask_resource_id(), GL_TEXTURE1,
GL_LINEAR));
}
@@ -1211,10 +1216,8 @@ void GLRenderer::UpdateRPDQTexturesForSampling(
if (params->filter_image) {
GrSurfaceOrigin origin;
GLuint filter_image_id =
- skia::GrBackendObjectToGrGLTextureInfo(
- params->filter_image->getTextureHandle(true, &origin))
- ->fID;
- DCHECK(filter_image_id);
+ GetGLTextureIDFromSkImage(params->filter_image.get(), &origin);
+ DCHECK(filter_image_id || IsContextLost());
DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
gl_->BindTexture(GL_TEXTURE_2D, filter_image_id);
gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1229,7 +1232,7 @@ void GLRenderer::UpdateRPDQTexturesForSampling(
params->source_needs_flip = params->flip_texture;
} else {
params->bypass_quad_resource_lock =
- std::make_unique<cc::DisplayResourceProvider::ScopedSamplerGL>(
+ std::make_unique<DisplayResourceProvider::ScopedSamplerGL>(
resource_provider_, params->bypass_quad_texture.resource_id,
GL_LINEAR);
DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
@@ -1383,8 +1386,8 @@ void GLRenderer::UpdateRPDQUniforms(DrawRenderPassDrawQuadParams* params) {
gl_->Uniform4f(current_program_->backdrop_rect_location(),
params->background_rect.x(), params->background_rect.y(),
- params->background_rect.width(),
- params->background_rect.height());
+ 1.0f / params->background_rect.width(),
+ 1.0f / params->background_rect.height());
// Either |background_image_id| or |background_texture| will be the
// |backdrop_location| in the shader.
@@ -1862,7 +1865,7 @@ void GLRenderer::DrawContentQuadAA(const ContentDrawQuadBase* quad,
float edge[24];
SetupQuadForClippingAndAntialiasing(device_transform, quad, &aa_quad,
clip_region, &local_quad, edge);
- cc::DisplayResourceProvider::ScopedSamplerGL quad_resource_lock(
+ DisplayResourceProvider::ScopedSamplerGL quad_resource_lock(
resource_provider_, resource_id,
quad->nearest_neighbor ? GL_NEAREST : GL_LINEAR);
SamplerType sampler =
@@ -1932,7 +1935,7 @@ void GLRenderer::DrawContentQuadNoAA(const ContentDrawQuadBase* quad,
? GL_LINEAR
: GL_NEAREST;
- cc::DisplayResourceProvider::ScopedSamplerGL quad_resource_lock(
+ DisplayResourceProvider::ScopedSamplerGL quad_resource_lock(
resource_provider_, resource_id, filter);
SamplerType sampler =
SamplerTypeFromTextureTarget(quad_resource_lock.target());
@@ -2054,40 +2057,48 @@ void GLRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad,
? UV_TEXTURE_MODE_UV
: UV_TEXTURE_MODE_U_V;
- // TODO(ccameron): There are currently three sources of the color space: the
- // resource, quad->color_space, and quad->video_color_space. Remove two of
- // them.
- gfx::ColorSpace src_color_space = quad->video_color_space;
- gfx::ColorSpace dst_color_space =
- current_frame()->current_render_pass->color_space;
- cc::DisplayResourceProvider::ScopedSamplerGL y_plane_lock(
+ DisplayResourceProvider::ScopedSamplerGL y_plane_lock(
resource_provider_, quad->y_plane_resource_id(), GL_TEXTURE1, GL_LINEAR);
- cc::DisplayResourceProvider::ScopedSamplerGL u_plane_lock(
+ DisplayResourceProvider::ScopedSamplerGL u_plane_lock(
resource_provider_, quad->u_plane_resource_id(), GL_TEXTURE2, GL_LINEAR);
DCHECK_EQ(y_plane_lock.target(), u_plane_lock.target());
DCHECK_EQ(y_plane_lock.color_space(), u_plane_lock.color_space());
- // TODO(jbauman): Use base::Optional when available.
- std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> v_plane_lock;
+ // TODO(ccameron): There are currently three sources of the color space: the
+ // resource, quad->color_space, and quad->video_color_space. Remove two of
+ // them.
+ gfx::ColorSpace src_color_space = quad->video_color_space;
// Invalid or unspecified color spaces should be treated as REC709.
if (!src_color_space.IsValid())
src_color_space = gfx::ColorSpace::CreateREC709();
else
DCHECK_EQ(src_color_space, y_plane_lock.color_space());
-
// The source color space should never be RGB.
DCHECK_NE(src_color_space, src_color_space.GetAsFullRangeRGB());
+ gfx::ColorSpace dst_color_space =
+ current_frame()->current_render_pass->color_space;
+ // Force sRGB output on Windows for overlay candidate video quads to match
+ // DirectComposition behavior in case these switch between overlays and
+ // compositing. See https://crbug.com/811118 for details.
+ if (supports_dc_layers_ &&
+ resource_provider_->IsOverlayCandidate(quad->y_plane_resource_id())) {
+ DCHECK(resource_provider_->IsOverlayCandidate(quad->u_plane_resource_id()));
+ dst_color_space = gfx::ColorSpace::CreateSRGB();
+ }
+
+ // TODO(jbauman): Use base::Optional when available.
+ std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> v_plane_lock;
if (uv_texture_mode == UV_TEXTURE_MODE_U_V) {
- v_plane_lock.reset(new cc::DisplayResourceProvider::ScopedSamplerGL(
+ v_plane_lock.reset(new DisplayResourceProvider::ScopedSamplerGL(
resource_provider_, quad->v_plane_resource_id(), GL_TEXTURE3,
GL_LINEAR));
DCHECK_EQ(y_plane_lock.target(), v_plane_lock->target());
DCHECK_EQ(y_plane_lock.color_space(), v_plane_lock->color_space());
}
- std::unique_ptr<cc::DisplayResourceProvider::ScopedSamplerGL> a_plane_lock;
+ std::unique_ptr<DisplayResourceProvider::ScopedSamplerGL> a_plane_lock;
if (alpha_texture_mode == YUV_HAS_ALPHA_TEXTURE) {
- a_plane_lock.reset(new cc::DisplayResourceProvider::ScopedSamplerGL(
+ a_plane_lock.reset(new DisplayResourceProvider::ScopedSamplerGL(
resource_provider_, quad->a_plane_resource_id(), GL_TEXTURE4,
GL_LINEAR));
DCHECK_EQ(y_plane_lock.target(), a_plane_lock->target());
@@ -2210,8 +2221,8 @@ void GLRenderer::DrawStreamVideoQuad(const StreamVideoDrawQuad* quad,
gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
- cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
- quad->resource_id());
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ quad->resource_id());
SetUseProgram(ProgramKey::VideoStream(tex_coord_precision),
lock.color_space(),
@@ -2262,7 +2273,7 @@ void GLRenderer::FlushTextureQuadCache(BoundGeometry flush_binding) {
SetBlendEnabled(draw_cache_.needs_blending);
// Assume the current active textures is 0.
- cc::DisplayResourceProvider::ScopedSamplerGL locked_quad(
+ DisplayResourceProvider::ScopedSamplerGL locked_quad(
resource_provider_, draw_cache_.resource_id,
draw_cache_.nearest_neighbor ? GL_NEAREST : GL_LINEAR);
@@ -2353,8 +2364,8 @@ void GLRenderer::EnqueueTextureQuad(const TextureDrawQuad* quad,
gl_, &highp_threshold_cache_, settings_->highp_threshold_min,
quad->shared_quad_state->visible_quad_layer_rect.bottom_right());
- cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
- quad->resource_id());
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ quad->resource_id());
const SamplerType sampler = SamplerTypeFromTextureTarget(lock.target());
bool need_tex_clamp_rect = !quad->resource_size_in_pixels().IsEmpty() &&
@@ -2659,7 +2670,8 @@ void GLRenderer::DrawQuadGeometryWithAA(const DrawQuad* quad,
CenteredRect(tile_rect));
}
-void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
+void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) {
DCHECK(visible_);
TRACE_EVENT0("viz", "GLRenderer::SwapBuffers");
@@ -2670,6 +2682,7 @@ void GLRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
OutputSurfaceFrame output_frame;
output_frame.latency_info = std::move(latency_info);
output_frame.size = surface_size;
+ output_frame.need_presentation_feedback = need_presentation_feedback;
if (use_swap_with_bounds_) {
output_frame.content_bounds = std::move(swap_content_bounds_);
} else if (use_partial_swap_) {
@@ -2752,7 +2765,7 @@ void GLRenderer::SwapBuffersComplete() {
// that once a swap buffer has completed we can remove the oldest buffers
// from the queue, but only once we've swapped another frame afterward.
if (swapping_overlay_resources_.size() > 1) {
- cc::DisplayResourceProvider::ScopedBatchReturnResources returner(
+ DisplayResourceProvider::ScopedBatchReturnResources returner(
resource_provider_);
swapping_overlay_resources_.pop_front();
}
@@ -2770,7 +2783,7 @@ void GLRenderer::SwapBuffersComplete() {
void GLRenderer::DidReceiveTextureInUseResponses(
const gpu::TextureInUseResponses& responses) {
DCHECK(settings_->release_overlay_resources_after_gpu_query);
- cc::DisplayResourceProvider::ScopedBatchReturnResources returner(
+ DisplayResourceProvider::ScopedBatchReturnResources returner(
resource_provider_);
for (const gpu::TextureInUseResponse& response : responses) {
if (response.in_use)
@@ -3085,7 +3098,7 @@ void GLRenderer::ScheduleCALayers() {
unsigned texture_id = 0;
if (contents_resource_id) {
pending_overlay_resources_.push_back(
- std::make_unique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
resource_provider_, contents_resource_id));
texture_id = pending_overlay_resources_.back()->texture_id();
}
@@ -3137,7 +3150,7 @@ void GLRenderer::ScheduleDCLayers() {
for (const auto& contents_resource_id : dc_layer_overlay.resources) {
if (contents_resource_id) {
pending_overlay_resources_.push_back(
- std::make_unique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
resource_provider_, contents_resource_id));
texture_ids[i] = pending_overlay_resources_.back()->texture_id();
ids_to_send = i + 1;
@@ -3178,7 +3191,7 @@ void GLRenderer::ScheduleDCLayers() {
gl_->ScheduleDCLayerCHROMIUM(ids_to_send, texture_ids, contents_rect,
dc_layer_overlay.background_color,
dc_layer_overlay.edge_aa_mask, bounds_rect,
- filter);
+ filter, dc_layer_overlay.is_protected_video);
}
}
@@ -3186,7 +3199,7 @@ void GLRenderer::ScheduleOverlays() {
if (current_frame()->overlay_list.empty())
return;
- cc::OverlayCandidateList& overlays = current_frame()->overlay_list;
+ OverlayCandidateList& overlays = current_frame()->overlay_list;
for (const auto& overlay_candidate : overlays) {
unsigned texture_id = 0;
if (overlay_candidate.use_output_surface_for_resource) {
@@ -3194,7 +3207,7 @@ void GLRenderer::ScheduleOverlays() {
DCHECK(texture_id || IsContextLost());
} else {
pending_overlay_resources_.push_back(
- std::make_unique<cc::DisplayResourceProvider::ScopedReadLockGL>(
+ std::make_unique<DisplayResourceProvider::ScopedReadLockGL>(
resource_provider_, overlay_candidate.resource_id));
texture_id = pending_overlay_resources_.back()->texture_id();
}
@@ -3202,7 +3215,8 @@ void GLRenderer::ScheduleOverlays() {
context_support_->ScheduleOverlayPlane(
overlay_candidate.plane_z_order, overlay_candidate.transform,
texture_id, ToNearestRect(overlay_candidate.display_rect),
- overlay_candidate.uv_rect, !overlay_candidate.is_opaque);
+ overlay_candidate.uv_rect, !overlay_candidate.is_opaque,
+ overlay_candidate.gpu_fence_id);
}
}
@@ -3614,8 +3628,7 @@ ResourceFormat GLRenderer::BackbufferFormat() const {
DCHECK(caps.color_buffer_half_float_rgba);
return RGBA_F16;
}
- return PlatformColor::BestSupportedTextureFormat(
- caps.texture_format_bgra8888);
+ return PlatformColor::BestSupportedTextureFormat(caps);
}
void GLRenderer::AllocateRenderPassResourceIfNeeded(
diff --git a/chromium/components/viz/service/display/gl_renderer.h b/chromium/components/viz/service/display/gl_renderer.h
index 180052af412..1cd981c9d71 100644
--- a/chromium/components/viz/service/display/gl_renderer.h
+++ b/chromium/components/viz/service/display/gl_renderer.h
@@ -33,12 +33,6 @@ namespace base {
class SingleThreadTaskRunner;
}
-namespace cc {
-class GLRendererShaderTest;
-class OutputSurface;
-class StreamVideoDrawQuad;
-} // namespace cc
-
namespace gpu {
namespace gles2 {
class GLES2Interface;
@@ -48,8 +42,11 @@ class GLES2Interface;
namespace viz {
class DynamicGeometryBinding;
+class GLRendererShaderTest;
+class OutputSurface;
class ScopedRenderPassTexture;
class StaticGeometryBinding;
+class StreamVideoDrawQuad;
class TextureDrawQuad;
// Class that handles drawing of composited render layers using GL.
@@ -59,13 +56,14 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
GLRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
scoped_refptr<base::SingleThreadTaskRunner> current_task_runner);
~GLRenderer() override;
bool use_swap_with_bounds() const { return use_swap_with_bounds_; }
- void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
+ void SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) override;
void SwapBuffersComplete() override;
void DidReceiveTextureInUseResponses(
@@ -154,7 +152,7 @@ class VIZ_SERVICE_EXPORT GLRenderer : public DirectRenderer {
friend class GLRendererTest;
using OverlayResourceLock =
- std::unique_ptr<cc::DisplayResourceProvider::ScopedReadLockGL>;
+ std::unique_ptr<DisplayResourceProvider::ScopedReadLockGL>;
using OverlayResourceLockList = std::vector<OverlayResourceLock>;
// If a RenderPass is used as an overlay, we render the RenderPass with any
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.cc b/chromium/components/viz/service/display/gl_renderer_copier.cc
index 478b2cb9950..f116895077d 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier.cc
+++ b/chromium/components/viz/service/display/gl_renderer_copier.cc
@@ -215,10 +215,10 @@ GLuint GLRendererCopier::RenderResultTexture(
// return it as the result texture. The request must not include scaling nor
// a texture mailbox to use for delivering results. The texture format must
// also be GL_RGBA, as described by CopyOutputResult::Format::RGBA_TEXTURE.
- const int purpose = (!request.is_scaled() && flipped_source &&
- !request.has_mailbox() && internal_format == GL_RGBA)
- ? CacheEntry::kResultTexture
- : CacheEntry::kFramebufferCopyTexture;
+ const int purpose =
+ (!request.is_scaled() && flipped_source && internal_format == GL_RGBA)
+ ? CacheEntry::kResultTexture
+ : CacheEntry::kFramebufferCopyTexture;
TakeCachedObjectsOrCreate(SourceOf(request), purpose, 1, &source_texture);
gl->BindTexture(GL_TEXTURE_2D, source_texture);
gl->CopyTexImage2D(GL_TEXTURE_2D, 0, internal_format, sampling_rect.x(),
@@ -230,21 +230,9 @@ GLuint GLRendererCopier::RenderResultTexture(
sampling_rect.set_origin(gfx::Point());
}
- // Determine the result texture: If the copy request provided a valid one, use
- // it instead of one owned by GLRendererCopier.
GLuint result_texture = 0;
- if (request.has_mailbox()) {
- if (!request.mailbox().IsZero()) {
- if (request.sync_token().HasData())
- gl->WaitSyncTokenCHROMIUM(request.sync_token().GetConstData());
- result_texture =
- gl->CreateAndConsumeTextureCHROMIUM(request.mailbox().name);
- }
- }
- if (result_texture == 0) {
- TakeCachedObjectsOrCreate(SourceOf(request), CacheEntry::kResultTexture, 1,
- &result_texture);
- }
+ TakeCachedObjectsOrCreate(SourceOf(request), CacheEntry::kResultTexture, 1,
+ &result_texture);
gl->BindTexture(GL_TEXTURE_2D, result_texture);
gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, result_rect.width(),
result_rect.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
@@ -266,11 +254,12 @@ GLuint GLRendererCopier::RenderResultTexture(
CacheScalerOrDelete(SourceOf(request), std::move(scaler));
} else {
DCHECK_SIZE_EQ(sampling_rect.size(), result_rect.size());
+ const bool flip_output = !flipped_source;
gl->CopySubTextureCHROMIUM(
source_texture, 0 /* source_level */, GL_TEXTURE_2D, result_texture,
0 /* dest_level */, 0 /* xoffset */, 0 /* yoffset */, sampling_rect.x(),
sampling_rect.y(), sampling_rect.width(), sampling_rect.height(),
- !flipped_source, false, false);
+ flip_output, false, false);
}
// If |source_texture| was a copy, maybe cache it for future requests.
@@ -305,6 +294,80 @@ void GLRendererCopier::StartReadbackFromTexture(
namespace {
+class GLPixelBufferRGBAResult : public CopyOutputResult {
+ public:
+ GLPixelBufferRGBAResult(const gfx::Rect& result_rect,
+ scoped_refptr<ContextProvider> context_provider,
+ GLuint transfer_buffer,
+ GLenum readback_format)
+ : CopyOutputResult(CopyOutputResult::Format::RGBA_BITMAP, result_rect),
+ context_provider_(std::move(context_provider)),
+ transfer_buffer_(transfer_buffer),
+ readback_format_(readback_format) {}
+
+ ~GLPixelBufferRGBAResult() final {
+ if (transfer_buffer_)
+ context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_);
+ }
+
+ bool ReadRGBAPlane(uint8_t* dest, int stride) const final {
+ // No need to read from GPU memory if a cached bitmap already exists.
+ if (rect().IsEmpty() || cached_bitmap()->readyToDraw())
+ return CopyOutputResult::ReadRGBAPlane(dest, stride);
+ auto* const gl = context_provider_->ContextGL();
+ gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
+ const uint8_t* pixels = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
+ GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
+ if (pixels) {
+ const SkColorType src_format = (readback_format_ == GL_BGRA_EXT)
+ ? kBGRA_8888_SkColorType
+ : kRGBA_8888_SkColorType;
+ const int src_bytes_per_row = size().width() * kRGBABytesPerPixel;
+ const SkImageInfo src_row_image_info =
+ SkImageInfo::Make(size().width(), 1, src_format, kPremul_SkAlphaType);
+ const SkImageInfo dest_row_image_info =
+ SkImageInfo::MakeN32Premul(size().width(), 1);
+
+ for (int y = 0; y < size().height(); ++y) {
+ const int flipped_y = (size().height() - y - 1);
+ const uint8_t* const src_row = pixels + flipped_y * src_bytes_per_row;
+ void* const dest_row = dest + y * stride;
+ SkPixmap src_pixmap(src_row_image_info, src_row, src_bytes_per_row);
+ SkPixmap dest_pixmap(dest_row_image_info, dest_row, stride);
+ src_pixmap.readPixels(dest_pixmap);
+ }
+ gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
+ }
+ gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, 0);
+ return !!pixels;
+ }
+
+ const SkBitmap& AsSkBitmap() const final {
+ if (rect().IsEmpty())
+ return *cached_bitmap(); // Return "null" bitmap for empty result.
+
+ if (cached_bitmap()->readyToDraw())
+ return *cached_bitmap();
+
+ SkBitmap result_bitmap;
+ result_bitmap.allocPixels(
+ SkImageInfo::MakeN32Premul(size().width(), size().height()));
+ ReadRGBAPlane(static_cast<uint8_t*>(result_bitmap.getPixels()),
+ result_bitmap.rowBytes());
+ *cached_bitmap() = result_bitmap;
+ // Now that we have a cached bitmap, no need to read from GPU memory
+ // anymore.
+ context_provider_->ContextGL()->DeleteBuffers(1, &transfer_buffer_);
+ transfer_buffer_ = 0;
+ return *cached_bitmap();
+ }
+
+ private:
+ const scoped_refptr<ContextProvider> context_provider_;
+ mutable GLuint transfer_buffer_;
+ GLenum readback_format_;
+};
+
// Manages the execution of one asynchronous framebuffer readback and contains
// all the relevant state needed to complete a copy request. The constructor
// initiates the operation, and then at some later point either: 1) the Finish()
@@ -357,7 +420,8 @@ class ReadPixelsWorkflow {
~ReadPixelsWorkflow() {
auto* const gl = context_provider_->ContextGL();
gl->DeleteQueriesEXT(1, &query_);
- gl->DeleteBuffers(1, &transfer_buffer_);
+ if (transfer_buffer_)
+ gl->DeleteBuffers(1, &transfer_buffer_);
}
GLuint query() const { return query_; }
@@ -365,42 +429,15 @@ class ReadPixelsWorkflow {
// Callback for the asynchronous glReadPixels(). The pixels are read from the
// transfer buffer, and a CopyOutputResult is sent to the requestor.
void Finish() {
- auto* const gl = context_provider_->ContextGL();
-
- gl->BindBuffer(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, transfer_buffer_);
- const uint8_t* pixels = static_cast<uint8_t*>(gl->MapBufferCHROMIUM(
- GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM, GL_READ_ONLY));
- if (!pixels) {
- // CopyOutputRequest will auto-send an empty result when its destructor
- // is run from ~ReadPixelsWorkflow().
- return;
- }
-
- // Create the result bitmap, making sure to flip the image in the Y
- // dimension.
- //
- // TODO(crbug/758057): Plumb-through color space into the output bitmap.
- SkBitmap result_bitmap;
- const int bytes_per_row = result_rect_.width() * kRGBABytesPerPixel;
- result_bitmap.allocPixels(
- SkImageInfo::Make(result_rect_.width(), result_rect_.height(),
- (readback_format_ == GL_BGRA_EXT)
- ? kBGRA_8888_SkColorType
- : kRGBA_8888_SkColorType,
- kPremul_SkAlphaType),
- bytes_per_row);
- for (int y = 0; y < result_rect_.height(); ++y) {
- const int flipped_y = (result_rect_.height() - y - 1);
- const uint8_t* const src_row = pixels + flipped_y * bytes_per_row;
- void* const dest_row = result_bitmap.getAddr(0, y);
- memcpy(dest_row, src_row, bytes_per_row);
+ auto result = std::make_unique<GLPixelBufferRGBAResult>(
+ result_rect_, context_provider_, transfer_buffer_, readback_format_);
+ transfer_buffer_ = 0; // Ownerhip was transferred to the result.
+ if (!copy_request_->SendsResultsInCurrentSequence()) {
+ // Force readback into a SkBitmap now, because after PostTask we don't
+ // have access to |context_provider_|.
+ result->AsSkBitmap();
}
- gl->UnmapBufferCHROMIUM(GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM);
-
- copy_request_->SendResult(std::make_unique<CopyOutputSkBitmapResult>(
- result_rect_, result_bitmap));
-
- // |transfer_buffer_| and |query_| will be deleted soon by the destructor.
+ copy_request_->SendResult(std::move(result));
}
private:
@@ -444,34 +481,18 @@ void GLRendererCopier::SendTextureResult(
// within its own GL context will be using the texture at a point in time
// after the texture has been rendered (via GLRendererCopier's GL context).
gpu::Mailbox mailbox;
- if (request->has_mailbox()) {
- mailbox = request->mailbox();
- } else {
- gl->GenMailboxCHROMIUM(mailbox.name);
- gl->ProduceTextureDirectCHROMIUM(result_texture, mailbox.name);
- }
+ gl->GenMailboxCHROMIUM(mailbox.name);
+ gl->ProduceTextureDirectCHROMIUM(result_texture, mailbox.name);
gpu::SyncToken sync_token;
gl->GenSyncTokenCHROMIUM(sync_token.GetData());
- // Create a |release_callback| appropriate to the situation: If the
- // |result_texture| was provided in the mailbox of the copy request,
- // create a no-op release callback because the requestor owns the texture.
- // Otherwise, create a callback that deletes what was created in this GL
- // context.
- std::unique_ptr<SingleReleaseCallback> release_callback;
- if (request->has_mailbox()) {
- gl->DeleteTextures(1, &result_texture);
- // TODO(crbug/754872): This non-null release callback wart is going away
- // soon, as copy requestors won't need pool/manage textures anymore.
- release_callback = SingleReleaseCallback::Create(base::DoNothing());
- } else {
- // Note: There's no need to try to pool/re-use the result texture from here,
- // since only clients that are trying to re-invent video capture would see
- // any significant performance benefit. Instead, such clients should use the
- // video capture services provided by VIZ.
- release_callback =
- texture_deleter_->GetReleaseCallback(context_provider_, result_texture);
- }
+ // Create a callback that deletes what was created in this GL context.
+ // Note: There's no need to try to pool/re-use the result texture from here,
+ // since only clients that are trying to re-invent video capture would see any
+ // significant performance benefit. Instead, such clients should use the video
+ // capture services provided by VIZ.
+ auto release_callback =
+ texture_deleter_->GetReleaseCallback(context_provider_, result_texture);
request->SendResult(std::make_unique<CopyOutputTextureResult>(
result_rect, mailbox, sync_token, color_space,
@@ -825,9 +846,10 @@ GLRendererCopier::TakeCachedScalerOrCreate(const CopyOutputRequest& for_request,
const GLHelper::ScalerQuality quality = is_downscale_in_both_dimensions
? GLHelper::SCALER_QUALITY_GOOD
: GLHelper::SCALER_QUALITY_BEST;
+ const bool flip_output = !flipped_source;
return helper_.CreateScaler(quality, for_request.scale_from(),
- for_request.scale_to(), flipped_source, false,
- false);
+ for_request.scale_to(), flipped_source,
+ flip_output, false);
}
void GLRendererCopier::CacheScalerOrDelete(
diff --git a/chromium/components/viz/service/display/gl_renderer_copier.h b/chromium/components/viz/service/display/gl_renderer_copier.h
index 7470b09cc91..5f60ffcddb1 100644
--- a/chromium/components/viz/service/display/gl_renderer_copier.h
+++ b/chromium/components/viz/service/display/gl_renderer_copier.h
@@ -183,6 +183,8 @@ class VIZ_SERVICE_EXPORT GLRendererCopier {
const GLuint* names);
// Returns a cached scaler for the given request, or creates one on-demand.
+ // The scaler can be configured for source textures that may or may not be
+ // Y-flipped, but its results will always be Y-flipped.
std::unique_ptr<GLHelper::ScalerInterface> TakeCachedScalerOrCreate(
const CopyOutputRequest& for_request,
bool flipped_source);
diff --git a/chromium/components/viz/service/display/gl_renderer_unittest.cc b/chromium/components/viz/service/display/gl_renderer_unittest.cc
index 241284a5ccc..1913ad59553 100644
--- a/chromium/components/viz/service/display/gl_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/gl_renderer_unittest.cc
@@ -12,11 +12,12 @@
#include <vector>
#include "base/location.h"
+#include "base/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/base/math_util.h"
-#include "cc/resources/resource_provider.h"
+#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/test/fake_impl_task_runner_provider.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface_client.h"
@@ -28,7 +29,9 @@
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "components/viz/test/fake_output_surface.h"
@@ -462,13 +465,13 @@ class FakeRendererGL : public GLRenderer {
public:
FakeRendererGL(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
+ DisplayResourceProvider* resource_provider)
: GLRenderer(settings, output_surface, resource_provider, nullptr) {}
FakeRendererGL(
const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
scoped_refptr<base::SingleThreadTaskRunner> current_task_runner)
: GLRenderer(settings,
output_surface,
@@ -504,13 +507,15 @@ class GLRendererWithDefaultHarnessTest : public GLRendererTest {
renderer_->SetVisible(true);
}
- void SwapBuffers() { renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); }
+ void SwapBuffers() {
+ renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false);
+ }
RendererSettings settings_;
cc::FakeOutputSurfaceClient output_surface_client_;
std::unique_ptr<FakeOutputSurface> output_surface_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<FakeRendererGL> renderer_;
};
@@ -538,7 +543,7 @@ class GLRendererShaderTest : public GLRendererTest {
child_context_provider_->BindToCurrentThread();
child_resource_provider_ =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_context_provider_.get(), shared_bitmap_manager_.get());
+ child_context_provider_.get());
}
void TestRenderPassProgram(TexCoordPrecision precision,
@@ -628,7 +633,7 @@ class GLRendererShaderTest : public GLRendererTest {
cc::FakeOutputSurfaceClient output_surface_client_;
std::unique_ptr<FakeOutputSurface> output_surface_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
scoped_refptr<TestContextProvider> child_context_provider_;
std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_;
std::unique_ptr<FakeRendererGL> renderer_;
@@ -651,38 +656,45 @@ TEST_F(GLRendererWithDefaultHarnessTest, ExternalStencil) {
EXPECT_TRUE(renderer_->stencil_enabled());
}
-class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
+class ForbidSynchronousCallGLES2Interface : public TestGLES2Interface {
public:
- ForbidSynchronousCallContext() {}
+ ForbidSynchronousCallGLES2Interface() = default;
- void getAttachedShaders(GLuint program,
+ void GetAttachedShaders(GLuint program,
GLsizei max_count,
GLsizei* count,
GLuint* shaders) override {
ADD_FAILURE();
}
- GLint getAttribLocation(GLuint program, const GLchar* name) override {
+
+ GLint GetAttribLocation(GLuint program, const GLchar* name) override {
ADD_FAILURE();
return 0;
}
- void getBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
- void getBufferParameteriv(GLenum target,
+
+ void GetBooleanv(GLenum pname, GLboolean* value) override { ADD_FAILURE(); }
+
+ void GetBufferParameteriv(GLenum target,
GLenum pname,
GLint* value) override {
ADD_FAILURE();
}
- GLenum getError() override {
+
+ GLenum GetError() override {
ADD_FAILURE();
return GL_NO_ERROR;
}
- void getFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
- void getFramebufferAttachmentParameteriv(GLenum target,
+
+ void GetFloatv(GLenum pname, GLfloat* value) override { ADD_FAILURE(); }
+
+ void GetFramebufferAttachmentParameteriv(GLenum target,
GLenum attachment,
GLenum pname,
GLint* value) override {
ADD_FAILURE();
}
- void getIntegerv(GLenum pname, GLint* value) override {
+
+ void GetIntegerv(GLenum pname, GLint* value) override {
if (pname == GL_MAX_TEXTURE_SIZE) {
// MAX_TEXTURE_SIZE is cached client side, so it's OK to query.
*value = 1024;
@@ -693,64 +705,66 @@ class ForbidSynchronousCallContext : public TestWebGraphicsContext3D {
// We allow querying the shader compilation and program link status in debug
// mode, but not release.
- void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
-#ifndef NDEBUG
- *value = 1;
-#else
+ void GetProgramiv(GLuint program, GLenum pname, GLint* value) override {
ADD_FAILURE();
-#endif
}
- void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
-#ifndef NDEBUG
- *value = 1;
-#else
+ void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override {
ADD_FAILURE();
-#endif
}
- void getRenderbufferParameteriv(GLenum target,
+ void GetRenderbufferParameteriv(GLenum target,
GLenum pname,
GLint* value) override {
ADD_FAILURE();
}
- void getShaderPrecisionFormat(GLenum shadertype,
+ void GetShaderPrecisionFormat(GLenum shadertype,
GLenum precisiontype,
GLint* range,
GLint* precision) override {
ADD_FAILURE();
}
- void getTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
+
+ void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* value) override {
ADD_FAILURE();
}
- void getTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
+
+ void GetTexParameteriv(GLenum target, GLenum pname, GLint* value) override {
ADD_FAILURE();
}
- void getUniformfv(GLuint program, GLint location, GLfloat* value) override {
+
+ void GetUniformfv(GLuint program, GLint location, GLfloat* value) override {
ADD_FAILURE();
}
- void getUniformiv(GLuint program, GLint location, GLint* value) override {
+
+ void GetUniformiv(GLuint program, GLint location, GLint* value) override {
ADD_FAILURE();
}
- GLint getUniformLocation(GLuint program, const GLchar* name) override {
+
+ GLint GetUniformLocation(GLuint program, const GLchar* name) override {
ADD_FAILURE();
return 0;
}
- void getVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
+
+ void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* value) override {
ADD_FAILURE();
}
- void getVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
+
+ void GetVertexAttribiv(GLuint index, GLenum pname, GLint* value) override {
ADD_FAILURE();
}
- GLsizeiptr getVertexAttribOffset(GLuint index, GLenum pname) override {
+
+ void GetVertexAttribPointerv(GLuint index,
+ GLenum pname,
+ void** pointer) override {
ADD_FAILURE();
- return 0;
}
};
+
TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
- auto context = std::make_unique<ForbidSynchronousCallContext>();
- auto provider = TestContextProvider::Create(std::move(context));
+ auto gl_owned = std::make_unique<ForbidSynchronousCallGLES2Interface>();
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -760,7 +774,7 @@ TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -769,24 +783,26 @@ TEST_F(GLRendererTest, InitializationDoesNotMakeSynchronousCalls) {
resource_provider.get());
}
-class LoseContextOnFirstGetContext : public TestWebGraphicsContext3D {
+class LoseContextOnFirstGetGLES2Interface : public TestGLES2Interface {
public:
- LoseContextOnFirstGetContext() {}
+ LoseContextOnFirstGetGLES2Interface() {}
- void getProgramiv(GLuint program, GLenum pname, GLint* value) override {
- context_lost_ = true;
+ void GetProgramiv(GLuint program, GLenum pname, GLint* value) override {
+ LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB);
*value = 0;
}
- void getShaderiv(GLuint shader, GLenum pname, GLint* value) override {
- context_lost_ = true;
+ void GetShaderiv(GLuint shader, GLenum pname, GLint* value) override {
+ LoseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB);
*value = 0;
}
};
TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
- auto context = std::make_unique<LoseContextOnFirstGetContext>();
- auto provider = TestContextProvider::Create(std::move(context));
+ auto gl_owned = std::make_unique<LoseContextOnFirstGetGLES2Interface>();
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -796,7 +812,7 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -805,22 +821,24 @@ TEST_F(GLRendererTest, InitializationWithQuicklyLostContextDoesNotAssert) {
resource_provider.get());
}
-class ClearCountingContext : public TestWebGraphicsContext3D {
+class ClearCountingGLES2Interface : public TestGLES2Interface {
public:
- ClearCountingContext() { test_capabilities_.discard_framebuffer = true; }
+ ClearCountingGLES2Interface() = default;
- MOCK_METHOD3(discardFramebufferEXT,
+ MOCK_METHOD3(DiscardFramebufferEXT,
void(GLenum target,
GLsizei numAttachments,
const GLenum* attachments));
- MOCK_METHOD1(clear, void(GLbitfield mask));
+ MOCK_METHOD1(Clear, void(GLbitfield mask));
};
TEST_F(GLRendererTest, OpaqueBackground) {
- std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
- ClearCountingContext* context = context_owned.get();
+ auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
+ gl_owned->set_have_discard_framebuffer(true);
- auto provider = TestContextProvider::Create(std::move(context_owned));
+ auto* gl = gl_owned.get();
+
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -830,7 +848,7 @@ TEST_F(GLRendererTest, OpaqueBackground) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -848,23 +866,24 @@ TEST_F(GLRendererTest, OpaqueBackground) {
// On DEBUG builds, render passes with opaque background clear to blue to
// easily see regions that were not drawn on the screen.
- EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+ EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
.With(Args<2, 1>(ElementsAre(GL_COLOR_EXT)))
.Times(1);
#ifdef NDEBUG
- EXPECT_CALL(*context, clear(_)).Times(0);
+ EXPECT_CALL(*gl, Clear(_)).Times(0);
#else
- EXPECT_CALL(*context, clear(_)).Times(1);
+ EXPECT_CALL(*gl, Clear(_)).Times(1);
#endif
DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(context);
+ Mock::VerifyAndClearExpectations(gl);
}
TEST_F(GLRendererTest, TransparentBackground) {
- std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
- ClearCountingContext* context = context_owned.get();
+ auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
+ auto* gl = gl_owned.get();
+ gl_owned->set_have_discard_framebuffer(true);
- auto provider = TestContextProvider::Create(std::move(context_owned));
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -874,7 +893,7 @@ TEST_F(GLRendererTest, TransparentBackground) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -890,18 +909,19 @@ TEST_F(GLRendererTest, TransparentBackground) {
gfx::Transform(), cc::FilterOperations());
root_pass->has_transparent_background = true;
- EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
- EXPECT_CALL(*context, clear(_)).Times(1);
+ EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, 1, _)).Times(1);
+ EXPECT_CALL(*gl, Clear(_)).Times(1);
DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(context);
+ Mock::VerifyAndClearExpectations(gl);
}
TEST_F(GLRendererTest, OffscreenOutputSurface) {
- std::unique_ptr<ClearCountingContext> context_owned(new ClearCountingContext);
- ClearCountingContext* context = context_owned.get();
+ auto gl_owned = std::make_unique<ClearCountingGLES2Interface>();
+ auto* gl = gl_owned.get();
+ gl_owned->set_have_discard_framebuffer(true);
- auto provider = TestContextProvider::Create(std::move(context_owned));
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -911,7 +931,7 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -925,26 +945,25 @@ TEST_F(GLRendererTest, OffscreenOutputSurface) {
cc::AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(viewport_size),
gfx::Transform(), cc::FilterOperations());
- EXPECT_CALL(*context, discardFramebufferEXT(GL_FRAMEBUFFER, _, _))
+ EXPECT_CALL(*gl, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
.With(Args<2, 1>(ElementsAre(GL_COLOR_ATTACHMENT0)))
.Times(1);
- EXPECT_CALL(*context, clear(_)).Times(AnyNumber());
+ EXPECT_CALL(*gl, Clear(_)).Times(AnyNumber());
DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(context);
+ Mock::VerifyAndClearExpectations(gl);
}
-class TextureStateTrackingContext : public TestWebGraphicsContext3D {
+class TextureStateTrackingGLES2Interface : public TestGLES2Interface {
public:
- TextureStateTrackingContext() : active_texture_(GL_INVALID_ENUM) {
- test_capabilities_.egl_image_external = true;
- }
+ TextureStateTrackingGLES2Interface() : active_texture_(GL_INVALID_ENUM) {}
- MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
- MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
- MOCK_METHOD4(drawElements,
- void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+ MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
+ MOCK_METHOD3(TexParameteri, void(GLenum target, GLenum pname, GLint param));
+ MOCK_METHOD4(
+ DrawElements,
+ void(GLenum mode, GLsizei count, GLenum type, const void* indices));
- virtual void activeTexture(GLenum texture) {
+ void ActiveTexture(GLenum texture) override {
EXPECT_NE(texture, active_texture_);
active_texture_ = texture;
}
@@ -956,11 +975,11 @@ class TextureStateTrackingContext : public TestWebGraphicsContext3D {
};
TEST_F(GLRendererTest, ActiveTextureState) {
- std::unique_ptr<TextureStateTrackingContext> context_owned(
- new TextureStateTrackingContext);
- TextureStateTrackingContext* context = context_owned.get();
+ auto gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
+ gl_owned->set_have_extension_egl_image(true);
+ auto* gl = gl_owned.get();
- auto provider = TestContextProvider::Create(std::move(context_owned));
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -970,7 +989,7 @@ TEST_F(GLRendererTest, ActiveTextureState) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -981,32 +1000,31 @@ TEST_F(GLRendererTest, ActiveTextureState) {
renderer.SetVisible(true);
// During initialization we are allowed to set any texture parameters.
- EXPECT_CALL(*context, texParameteri(_, _, _)).Times(AnyNumber());
+ EXPECT_CALL(*gl, TexParameteri(_, _, _)).Times(AnyNumber());
- std::unique_ptr<TextureStateTrackingContext> child_context_owned(
- new TextureStateTrackingContext);
+ auto child_gl_owned = std::make_unique<TextureStateTrackingGLES2Interface>();
auto child_context_provider =
- TestContextProvider::Create(std::move(child_context_owned));
+ TestContextProvider::Create(std::move(child_gl_owned));
child_context_provider->BindToCurrentThread();
auto child_resource_provider =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_context_provider.get(), shared_bitmap_manager.get());
+ child_context_provider.get());
RenderPass* root_pass =
cc::AddRenderPass(&render_passes_in_draw_order_, 1, gfx::Rect(100, 100),
gfx::Transform(), cc::FilterOperations());
gpu::SyncToken mailbox_sync_token;
AddOneOfEveryQuadTypeInDisplayResourceProvider(
- root_pass, resource_provider.get(), child_resource_provider.get(), 0,
- &mailbox_sync_token);
+ root_pass, resource_provider.get(), child_resource_provider.get(),
+ child_context_provider.get(), 0, &mailbox_sync_token);
EXPECT_EQ(12u, resource_provider->num_resources());
renderer.DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
// Set up expected texture filter state transitions that match the quads
// created in AppendOneOfEveryQuadType().
- Mock::VerifyAndClearExpectations(context);
+ Mock::VerifyAndClearExpectations(gl);
{
InSequence sequence;
// The verified flush flag will be set by
@@ -1018,43 +1036,45 @@ TEST_F(GLRendererTest, ActiveTextureState) {
// (with mailbox), resource2, resource3, resource4, resource9, resource10,
// resource11, resource12. resource8 has its own mailbox mailbox_sync_token.
// The rest resources share a common default sync token.
- EXPECT_CALL(*context, waitSyncToken(_)).Times(2);
- EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(mailbox_sync_token)))
+ EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(2);
+ EXPECT_CALL(*gl,
+ WaitSyncTokenCHROMIUM(MatchesSyncToken(mailbox_sync_token)))
.Times(1);
- EXPECT_CALL(*context, waitSyncToken(_)).Times(7);
+ EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(_)).Times(7);
// yuv_quad is drawn with the default linear filter.
- EXPECT_CALL(*context, drawElements(_, _, _, _));
+ EXPECT_CALL(*gl, DrawElements(_, _, _, _));
// tile_quad is drawn with GL_NEAREST because it is not transformed or
// scaled.
- EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
- GL_NEAREST));
- EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
- GL_NEAREST));
+ EXPECT_CALL(
+ *gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+ EXPECT_CALL(
+ *gl, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
// The remaining quads also use GL_LINEAR because nearest neighbor
// filtering is currently only used with tile quads.
- EXPECT_CALL(*context, drawElements(_, _, _, _)).Times(8);
+ EXPECT_CALL(*gl, DrawElements(_, _, _, _)).Times(8);
}
gfx::Size viewport_size(100, 100);
DrawFrame(&renderer, viewport_size);
- Mock::VerifyAndClearExpectations(context);
+ Mock::VerifyAndClearExpectations(gl);
}
-class NoClearRootRenderPassMockContext : public TestWebGraphicsContext3D {
+class NoClearRootRenderPassMockGLES2Interface : public TestGLES2Interface {
public:
- MOCK_METHOD1(clear, void(GLbitfield mask));
- MOCK_METHOD4(drawElements,
- void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+ MOCK_METHOD1(Clear, void(GLbitfield mask));
+ MOCK_METHOD4(
+ DrawElements,
+ void(GLenum mode, GLsizei count, GLenum type, const void* indices));
};
TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
- std::unique_ptr<NoClearRootRenderPassMockContext> mock_context_owned(
- new NoClearRootRenderPassMockContext);
- NoClearRootRenderPassMockContext* mock_context = mock_context_owned.get();
+ auto mock_gl_owned =
+ std::make_unique<NoClearRootRenderPassMockGLES2Interface>();
+ NoClearRootRenderPassMockGLES2Interface* mock_gl = mock_gl_owned.get();
- auto provider = TestContextProvider::Create(std::move(mock_context_owned));
+ auto provider = TestContextProvider::Create(std::move(mock_gl_owned));
provider->BindToCurrentThread();
cc::FakeOutputSurfaceClient output_surface_client;
@@ -1064,7 +1084,7 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -1099,17 +1119,15 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
#endif
// First render pass is not the root one, clearing should happen.
- EXPECT_CALL(*mock_context, clear(clear_bits)).Times(AtLeast(1));
+ EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(AtLeast(1));
Expectation first_render_pass =
- EXPECT_CALL(*mock_context, drawElements(_, _, _, _)).Times(1);
+ EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _)).Times(1);
// The second render pass is the root one, clearing should be prevented.
- EXPECT_CALL(*mock_context, clear(clear_bits))
- .Times(0)
- .After(first_render_pass);
+ EXPECT_CALL(*mock_gl, Clear(clear_bits)).Times(0).After(first_render_pass);
- EXPECT_CALL(*mock_context, drawElements(_, _, _, _))
+ EXPECT_CALL(*mock_gl, DrawElements(_, _, _, _))
.Times(AnyNumber())
.After(first_render_pass);
@@ -1118,7 +1136,7 @@ TEST_F(GLRendererTest, ShouldClearRootRenderPass) {
// In multiple render passes all but the root pass should clear the
// framebuffer.
- Mock::VerifyAndClearExpectations(&mock_context);
+ Mock::VerifyAndClearExpectations(&mock_gl);
}
class ScissorTestOnClearCheckingGLES2Interface : public TestGLES2Interface {
@@ -1154,7 +1172,7 @@ TEST_F(GLRendererTest, ScissorTestWhenClearing) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -1198,11 +1216,6 @@ class DiscardCheckingGLES2Interface : public TestGLES2Interface {
public:
DiscardCheckingGLES2Interface() = default;
- void InitializeTestContext(TestWebGraphicsContext3D* context) override {
- context->set_have_post_sub_buffer(true);
- context->set_have_discard_framebuffer(true);
- }
-
void DiscardFramebufferEXT(GLenum target,
GLsizei numAttachments,
const GLenum* attachments) override {
@@ -1218,6 +1231,9 @@ class DiscardCheckingGLES2Interface : public TestGLES2Interface {
TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
auto gl_owned = std::make_unique<DiscardCheckingGLES2Interface>();
+ gl_owned->set_have_post_sub_buffer(true);
+ gl_owned->set_have_discard_framebuffer(true);
+
auto* gl = gl_owned.get();
auto provider = TestContextProvider::Create(std::move(gl_owned));
@@ -1229,7 +1245,7 @@ TEST_F(GLRendererTest, NoDiscardOnPartialUpdates) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -1429,7 +1445,7 @@ TEST_F(GLRendererTest, NoResourceLeak) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -1457,10 +1473,6 @@ TEST_F(GLRendererTest, NoResourceLeak) {
class DrawElementsGLES2Interface : public TestGLES2Interface {
public:
- void InitializeTestContext(TestWebGraphicsContext3D* context) override {
- context->set_have_post_sub_buffer(true);
- }
-
MOCK_METHOD4(
DrawElements,
void(GLenum mode, GLsizei count, GLenum type, const void* indices));
@@ -1470,6 +1482,7 @@ class GLRendererSkipTest : public GLRendererTest {
protected:
GLRendererSkipTest() {
auto gl_owned = std::make_unique<StrictMock<DrawElementsGLES2Interface>>();
+ gl_owned->set_have_post_sub_buffer(true);
gl_ = gl_owned.get();
auto provider = TestContextProvider::Create(std::move(gl_owned));
@@ -1494,7 +1507,7 @@ class GLRendererSkipTest : public GLRendererTest {
cc::FakeOutputSurfaceClient output_surface_client_;
std::unique_ptr<FakeOutputSurface> output_surface_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<FakeRendererGL> renderer_;
};
@@ -1567,7 +1580,7 @@ TEST_F(GLRendererTest, DrawFramePreservesFramebuffer) {
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager =
std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), shared_bitmap_manager.get());
@@ -1611,15 +1624,16 @@ TEST_F(GLRendererShaderTest, DrawRenderPassQuadShaderPermutations) {
int root_pass_id = 1;
RenderPass* root_pass;
- ResourceId mask = child_resource_provider_->CreateGpuTextureResource(
- gfx::Size(20, 12), ResourceTextureHint::kDefault,
- child_resource_provider_->best_texture_format(), gfx::ColorSpace());
- child_resource_provider_->AllocateForTesting(mask);
+ auto transfer_resource = TransferableResource::MakeGL(
+ gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken());
+ ResourceId mask = child_resource_provider_->ImportResource(
+ transfer_resource, SingleReleaseCallback::Create(base::DoNothing()));
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({mask}, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(),
+ child_context_provider_.get());
ResourceId mapped_mask = resource_map[mask];
SkScalar matrix[20];
@@ -1867,28 +1881,34 @@ TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
TestSolidColorProgramAA();
}
-class OutputSurfaceMockContext : public TestWebGraphicsContext3D {
+class OutputSurfaceMockGLES2Interface : public TestGLES2Interface {
public:
- OutputSurfaceMockContext() { test_capabilities_.post_sub_buffer = true; }
+ OutputSurfaceMockGLES2Interface() = default;
// Specifically override methods even if they are unused (used in conjunction
// with StrictMock). We need to make sure that GLRenderer does not issue
// framebuffer-related GLuint calls directly. Instead these are supposed to go
// through the OutputSurface abstraction.
- MOCK_METHOD2(bindFramebuffer, void(GLenum target, GLuint framebuffer));
- MOCK_METHOD3(reshapeWithScaleFactor,
- void(int width, int height, float scale_factor));
- MOCK_METHOD4(drawElements,
- void(GLenum mode, GLsizei count, GLenum type, GLintptr offset));
+ MOCK_METHOD2(BindFramebuffer, void(GLenum target, GLuint framebuffer));
+ MOCK_METHOD5(ResizeCHROMIUM,
+ void(GLuint width,
+ GLuint height,
+ float device_scale,
+ GLenum color_space,
+ GLboolean has_alpha));
+ MOCK_METHOD4(
+ DrawElements,
+ void(GLenum mode, GLsizei count, GLenum type, const void* indices));
};
class MockOutputSurface : public OutputSurface {
public:
explicit MockOutputSurface(scoped_refptr<ContextProvider> provider)
: OutputSurface(std::move(provider)) {}
- virtual ~MockOutputSurface() {}
+ ~MockOutputSurface() override {}
void BindToClient(OutputSurfaceClient*) override {}
+ unsigned UpdateGpuFence() override { return 0; }
MOCK_METHOD0(EnsureBackbuffer, void());
MOCK_METHOD0(DiscardBackbuffer, void());
@@ -1908,7 +1928,6 @@ class MockOutputSurface : public OutputSurface {
MOCK_CONST_METHOD0(IsDisplayedAsOverlayPlane, bool());
MOCK_CONST_METHOD0(GetOverlayTextureId, unsigned());
MOCK_CONST_METHOD0(GetOverlayBufferFormat, gfx::BufferFormat());
- MOCK_CONST_METHOD0(SurfaceIsSuspendForRecycle, bool());
MOCK_CONST_METHOD0(HasExternalStencilTest, bool());
MOCK_METHOD0(ApplyExternalStencil, void());
};
@@ -1916,9 +1935,10 @@ class MockOutputSurface : public OutputSurface {
class MockOutputSurfaceTest : public GLRendererTest {
protected:
void SetUp() override {
- auto context = std::make_unique<StrictMock<OutputSurfaceMockContext>>();
- context_ = context.get();
- auto provider = TestContextProvider::Create(std::move(context));
+ auto gl = std::make_unique<StrictMock<OutputSurfaceMockGLES2Interface>>();
+ gl->set_have_post_sub_buffer(true);
+ gl_ = gl.get();
+ auto provider = TestContextProvider::Create(std::move(gl));
provider->BindToCurrentThread();
output_surface_ =
std::make_unique<StrictMock<MockOutputSurface>>(std::move(provider));
@@ -1941,7 +1961,9 @@ class MockOutputSurfaceTest : public GLRendererTest {
Mock::VerifyAndClearExpectations(output_surface_.get());
}
- void SwapBuffers() { renderer_->SwapBuffers(std::vector<ui::LatencyInfo>()); }
+ void SwapBuffers() {
+ renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false);
+ }
void DrawFrame(float device_scale_factor,
const gfx::Size& viewport_size,
@@ -1961,7 +1983,7 @@ class MockOutputSurfaceTest : public GLRendererTest {
EXPECT_CALL(*output_surface_, BindFramebuffer()).Times(1);
- EXPECT_CALL(*context_, drawElements(_, _, _, _)).Times(1);
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(1);
renderer_->DecideRenderPassAllocationsForFrame(
render_passes_in_draw_order_);
@@ -1971,10 +1993,10 @@ class MockOutputSurfaceTest : public GLRendererTest {
RendererSettings settings_;
cc::FakeOutputSurfaceClient output_surface_client_;
- OutputSurfaceMockContext* context_ = nullptr;
+ OutputSurfaceMockGLES2Interface* gl_ = nullptr;
std::unique_ptr<StrictMock<MockOutputSurface>> output_surface_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<FakeRendererGL> renderer_;
};
@@ -1999,9 +2021,9 @@ class TestOverlayProcessor : public OverlayProcessor {
MOCK_METHOD5(Attempt,
bool(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidates,
+ OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds));
};
@@ -2019,7 +2041,7 @@ class TestOverlayProcessor : public OverlayProcessor {
// to be traditionally composited. Candidates with |overlay_handled| set to
// true must also have their |display_rect| converted to integer
// coordinates if necessary.
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) {}
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
explicit TestOverlayProcessor(OutputSurface* surface)
@@ -2056,7 +2078,7 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
child_context_provider->BindToCurrentThread();
auto child_resource_provider =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_context_provider.get(), shared_bitmap_manager.get());
+ child_context_provider.get());
auto transfer_resource = TransferableResource::MakeGLOverlay(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
@@ -2071,14 +2093,15 @@ TEST_F(GLRendererTest, DontOverlayWithCopyRequests) {
base::Bind(&CollectResources, &returned_to_child));
// Transfer resource to the parent.
- cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ std::vector<ResourceId> resource_ids_to_transfer;
resource_ids_to_transfer.push_back(resource_id);
std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list);
+ child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list,
+ child_context_provider.get());
parent_resource_provider->ReceiveFromChild(child_id, list);
// In DisplayResourceProvider's namespace, use the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
parent_resource_provider->GetChildToParentMap(child_id);
ResourceId parent_resource_id = resource_map[list[0].id];
@@ -2188,9 +2211,9 @@ class SingleOverlayOnTopProcessor : public OverlayProcessor {
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return false; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
ASSERT_EQ(1U, surfaces->size());
- cc::OverlayCandidate& candidate = surfaces->back();
+ OverlayCandidate& candidate = surfaces->back();
candidate.overlay_handled = true;
}
};
@@ -2206,27 +2229,28 @@ class SingleOverlayOnTopProcessor : public OverlayProcessor {
SingleOverlayValidator validator_;
};
-class WaitSyncTokenCountingContext : public TestWebGraphicsContext3D {
+class WaitSyncTokenCountingGLES2Interface : public TestGLES2Interface {
public:
- MOCK_METHOD1(waitSyncToken, void(const GLbyte* sync_token));
+ MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte* sync_token));
};
class MockOverlayScheduler {
public:
- MOCK_METHOD5(Schedule,
+ MOCK_METHOD7(Schedule,
void(int plane_z_order,
gfx::OverlayTransform plane_transform,
unsigned overlay_texture_id,
const gfx::Rect& display_bounds,
- const gfx::RectF& uv_rect));
+ const gfx::RectF& uv_rect,
+ bool enable_blend,
+ unsigned gpu_fence_id));
};
TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
- std::unique_ptr<WaitSyncTokenCountingContext> context_owned(
- new WaitSyncTokenCountingContext);
- WaitSyncTokenCountingContext* context = context_owned.get();
+ auto gl_owned = std::make_unique<WaitSyncTokenCountingGLES2Interface>();
+ WaitSyncTokenCountingGLES2Interface* gl = gl_owned.get();
- auto provider = TestContextProvider::Create(std::move(context_owned));
+ auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
MockOverlayScheduler overlay_scheduler;
@@ -2248,7 +2272,7 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
child_context_provider->BindToCurrentThread();
auto child_resource_provider =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_context_provider.get(), shared_bitmap_manager.get());
+ child_context_provider.get());
gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO,
gpu::CommandBufferId::FromUnsafeValue(0x123), 29);
@@ -2265,14 +2289,15 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
base::Bind(&CollectResources, &returned_to_child));
// Transfer resource to the parent.
- cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ std::vector<ResourceId> resource_ids_to_transfer;
resource_ids_to_transfer.push_back(resource_id);
std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list);
+ child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list,
+ child_context_provider.get());
parent_resource_provider->ReceiveFromChild(child_id, list);
// In DisplayResourceProvider's namespace, use the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
parent_resource_provider->GetChildToParentMap(child_id);
ResourceId parent_resource_id = resource_map[list[0].id];
@@ -2321,12 +2346,13 @@ TEST_F(GLRendererTest, OverlaySyncTokensAreProcessed) {
// Verify that overlay_quad actually gets turned into an overlay, and even
// though it's not drawn, that its sync point is waited on.
- EXPECT_CALL(*context, waitSyncToken(MatchesSyncToken(sync_token))).Times(1);
+ EXPECT_CALL(*gl, WaitSyncTokenCHROMIUM(MatchesSyncToken(sync_token)))
+ .Times(1);
EXPECT_CALL(
overlay_scheduler,
Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, gfx::Rect(viewport_size),
- BoundingRect(uv_top_left, uv_bottom_right)))
+ BoundingRect(uv_top_left, uv_bottom_right), _, _))
.Times(1);
DrawFrame(&renderer, viewport_size);
@@ -2358,7 +2384,7 @@ TEST_F(GLRendererTest, OutputColorMatrixTest) {
FakeOutputSurface::Create3d(std::move(provider)));
cc::FakeOutputSurfaceClient output_surface_client;
output_surface->BindToClient(&output_surface_client);
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), nullptr);
RendererSettings settings;
@@ -2434,16 +2460,17 @@ class GenerateMipmapMockGLESInterface : public TestGLES2Interface {
TEST_F(GLRendererTest, GenerateMipmap) {
// Initialize the mock GL interface, the output surface and the renderer.
auto gl_owned = std::make_unique<GenerateMipmapMockGLESInterface>();
+ gl_owned->set_support_texture_npot(true);
+
auto* gl = gl_owned.get();
auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
- provider->TestContext3d()->set_support_texture_npot(true);
std::unique_ptr<FakeOutputSurface> output_surface(
FakeOutputSurface::Create3d(std::move(provider)));
cc::FakeOutputSurfaceClient output_surface_client;
output_surface->BindToClient(&output_surface_client);
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), nullptr);
RendererSettings settings;
@@ -2480,28 +2507,21 @@ TEST_F(GLRendererTest, GenerateMipmap) {
class PartialSwapMockGLES2Interface : public TestGLES2Interface {
public:
- explicit PartialSwapMockGLES2Interface(bool support_dc_layers)
- : support_dc_layers_(support_dc_layers) {}
-
- void InitializeTestContext(TestWebGraphicsContext3D* context) override {
- context->set_have_post_sub_buffer(true);
- context->set_enable_dc_layers(support_dc_layers_);
- }
+ PartialSwapMockGLES2Interface() = default;
MOCK_METHOD1(Enable, void(GLenum cap));
MOCK_METHOD1(Disable, void(GLenum cap));
MOCK_METHOD4(Scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
MOCK_METHOD1(SetEnableDCLayersCHROMIUM, void(GLboolean enable));
-
- private:
- bool support_dc_layers_;
};
class GLRendererPartialSwapTest : public GLRendererTest {
protected:
void RunTest(bool partial_swap, bool set_draw_rectangle) {
- auto gl_owned =
- std::make_unique<PartialSwapMockGLES2Interface>(set_draw_rectangle);
+ auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>();
+ gl_owned->set_have_post_sub_buffer(true);
+ gl_owned->set_enable_dc_layers(set_draw_rectangle);
+
auto* gl = gl_owned.get();
auto provider = TestContextProvider::Create(std::move(gl_owned));
@@ -2512,7 +2532,7 @@ class GLRendererPartialSwapTest : public GLRendererTest {
FakeOutputSurface::Create3d(std::move(provider)));
output_surface->BindToClient(&output_surface_client);
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), nullptr);
@@ -2606,7 +2626,7 @@ class DCLayerValidator : public OverlayCandidateValidator {
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return true; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {}
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
// Test that SetEnableDCLayersCHROMIUM is properly called when enabling
@@ -2614,7 +2634,9 @@ class DCLayerValidator : public OverlayCandidateValidator {
TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kDirectCompositionUnderlays);
- auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>(true);
+ auto gl_owned = std::make_unique<PartialSwapMockGLES2Interface>();
+ gl_owned->set_have_post_sub_buffer(true);
+ gl_owned->set_enable_dc_layers(true);
auto* gl = gl_owned.get();
auto provider = TestContextProvider::Create(std::move(gl_owned));
@@ -2633,7 +2655,7 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
child_context_provider->BindToCurrentThread();
auto child_resource_provider =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_context_provider.get(), nullptr);
+ child_context_provider.get());
auto transfer_resource = TransferableResource::MakeGLOverlay(
gpu::Mailbox::Generate(), GL_LINEAR, GL_TEXTURE_2D, gpu::SyncToken(),
@@ -2648,13 +2670,14 @@ TEST_F(GLRendererTest, DCLayerOverlaySwitch) {
base::Bind(&CollectResources, &returned_to_child));
// Transfer resource to the parent.
- cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ std::vector<ResourceId> resource_ids_to_transfer;
resource_ids_to_transfer.push_back(resource_id);
std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list);
+ child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list,
+ child_context_provider.get());
parent_resource_provider->ReceiveFromChild(child_id, list);
// In DisplayResourceProvider's namespace, use the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
parent_resource_provider->GetChildToParentMap(child_id);
ResourceId parent_resource_id = resource_map[list[0].id];
@@ -2740,8 +2763,8 @@ class GLRendererWithMockContextTest : public ::testing::Test {
void SetUp() override {
auto context_support = std::make_unique<MockContextSupport>();
context_support_ptr_ = context_support.get();
- auto context_provider = TestContextProvider::Create(
- TestWebGraphicsContext3D::Create(), std::move(context_support));
+ auto context_provider =
+ TestContextProvider::Create(std::move(context_support));
ASSERT_EQ(context_provider->BindToCurrentThread(),
gpu::ContextResult::kSuccess);
output_surface_ = FakeOutputSurface::Create3d(std::move(context_provider));
@@ -2758,7 +2781,7 @@ class GLRendererWithMockContextTest : public ::testing::Test {
cc::FakeOutputSurfaceClient output_surface_client_;
MockContextSupport* context_support_ptr_;
std::unique_ptr<OutputSurface> output_surface_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<GLRenderer> renderer_;
};
@@ -2773,13 +2796,6 @@ TEST_F(GLRendererWithMockContextTest,
Mock::VerifyAndClearExpectations(context_support_ptr_);
}
-class SwapWithBoundsMockGLES2Interface : public TestGLES2Interface {
- public:
- void InitializeTestContext(TestWebGraphicsContext3D* context) override {
- context->set_have_swap_buffers_with_bounds(true);
- }
-};
-
class ContentBoundsOverlayProcessor : public OverlayProcessor {
public:
class Strategy : public OverlayProcessor::Strategy {
@@ -2789,9 +2805,9 @@ class ContentBoundsOverlayProcessor : public OverlayProcessor {
~Strategy() override = default;
bool Attempt(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidates,
+ OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds) override {
content_bounds->insert(content_bounds->end(), content_bounds_.begin(),
content_bounds_.end());
@@ -2820,7 +2836,8 @@ class ContentBoundsOverlayProcessor : public OverlayProcessor {
class GLRendererSwapWithBoundsTest : public GLRendererTest {
protected:
void RunTest(const std::vector<gfx::Rect>& content_bounds) {
- auto gl_owned = std::make_unique<SwapWithBoundsMockGLES2Interface>();
+ auto gl_owned = std::make_unique<TestGLES2Interface>();
+ gl_owned->set_have_swap_buffers_with_bounds(true);
auto provider = TestContextProvider::Create(std::move(gl_owned));
provider->BindToCurrentThread();
@@ -2830,7 +2847,7 @@ class GLRendererSwapWithBoundsTest : public GLRendererTest {
FakeOutputSurface::Create3d(std::move(provider)));
output_surface->BindToClient(&output_surface_client);
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), nullptr);
@@ -2857,7 +2874,7 @@ class GLRendererSwapWithBoundsTest : public GLRendererTest {
renderer.DecideRenderPassAllocationsForFrame(
render_passes_in_draw_order_);
DrawFrame(&renderer, viewport_size);
- renderer.SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer.SwapBuffers(std::vector<ui::LatencyInfo>(), false);
std::vector<gfx::Rect> expected_content_bounds;
EXPECT_EQ(content_bounds,
@@ -2883,7 +2900,7 @@ class CALayerValidator : public OverlayCandidateValidator {
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
bool AllowCALayerOverlays() override { return true; }
bool AllowDCLayerOverlays() override { return false; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {}
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
class MockCALayerGLES2Interface : public TestGLES2Interface {
@@ -2903,16 +2920,6 @@ class MockCALayerGLES2Interface : public TestGLES2Interface {
GLuint filter));
MOCK_METHOD2(ScheduleCALayerInUseQueryCHROMIUM,
void(GLsizei count, const GLuint* textures));
-
- void InitializeTestContext(TestWebGraphicsContext3D* context) override {
- // Support image storage for GpuMemoryBuffers, needed for
- // CALayers/IOSurfaces backed by textures.
- context->set_support_texture_storage_image(true);
-
- // Allow the renderer to make an empty SwapBuffers - skipping even the
- // root RenderPass.
- context->set_have_commit_overlay_planes(true);
- }
};
class CALayerGLRendererTest : public GLRendererTest {
@@ -2920,6 +2927,13 @@ class CALayerGLRendererTest : public GLRendererTest {
void SetUp() override {
// A mock GLES2Interface that can watch CALayer stuff happen.
auto gles2_interface = std::make_unique<MockCALayerGLES2Interface>();
+ // Support image storage for GpuMemoryBuffers, needed for
+ // CALayers/IOSurfaces backed by textures.
+ gles2_interface->set_support_texture_storage_image(true);
+ // Allow the renderer to make an empty SwapBuffers - skipping even the
+ // root RenderPass.
+ gles2_interface->set_have_commit_overlay_planes(true);
+
gl_ = gles2_interface.get();
auto provider = TestContextProvider::Create(std::move(gles2_interface));
@@ -2967,7 +2981,7 @@ class CALayerGLRendererTest : public GLRendererTest {
MockCALayerGLES2Interface* gl_;
CALayerValidator validator_;
std::unique_ptr<FakeOutputSurface> output_surface_;
- std::unique_ptr<cc::DisplayResourceProvider> display_resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> display_resource_provider_;
std::unique_ptr<RendererSettings> settings_;
std::unique_ptr<FakeRendererGL> renderer_;
};
@@ -3011,7 +3025,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysWithAllQuadsPromoted) {
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// The damage was eliminated when everything was promoted to CALayers.
ASSERT_TRUE(output_surface().last_sent_frame()->sub_buffer_rect);
@@ -3049,7 +3063,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysWithAllQuadsPromoted) {
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
}
TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) {
@@ -3098,7 +3112,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// ScheduleCALayerCHROMIUM happened and used a non-0 texture.
EXPECT_NE(saved_texture_id, 0u);
@@ -3151,7 +3165,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// There are now 2 textures to check if they are free.
EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
@@ -3201,7 +3215,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReusesTextureWithDifferentSizes) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
}
TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) {
@@ -3250,7 +3264,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// ScheduleCALayerCHROMIUM happened and used a non-0 texture.
EXPECT_NE(saved_texture_id, 0u);
@@ -3301,7 +3315,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// There are now 2 textures to check if they are free.
EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
@@ -3349,7 +3363,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysDontReuseTooBigTexture) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
}
TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) {
@@ -3435,7 +3449,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) {
Mock::VerifyAndClearExpectations(&gl());
// SwapBuffers() *does* happen this time.
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// There are 2 textures to check if they are free.
EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(2, _));
@@ -3480,7 +3494,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseAfterNoSwapBuffers) {
}
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
}
TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) {
@@ -3524,7 +3538,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) {
}));
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// ScheduleCALayerCHROMIUM happened and used a non-0 texture.
EXPECT_NE(sent_texture_ids[i], 0u);
@@ -3598,7 +3612,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysReuseManyIfReturnedSlowly) {
}));
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// All sent textures will be checked to verify if they are free yet. There's
// also 1 outstanding texture to check for that wasn't returned yet from the
@@ -3649,7 +3663,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) {
}));
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// ScheduleCALayerCHROMIUM happened and used a non-0 texture.
EXPECT_NE(sent_texture_ids[i], 0u);
@@ -3689,7 +3703,7 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) {
EXPECT_CALL(gl(), ScheduleCALayerCHROMIUM(_, _, _, _, _, _));
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
// There's just 1 outstanding RenderPass texture to query for.
EXPECT_CALL(gl(), ScheduleCALayerInUseQueryCHROMIUM(1, _));
@@ -3735,14 +3749,14 @@ TEST_F(CALayerGLRendererTest, CALayerOverlaysCachedTexturesAreFreed) {
}));
DrawFrame(&renderer(), viewport_size);
Mock::VerifyAndClearExpectations(&gl());
- renderer().SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer().SwapBuffers(std::vector<ui::LatencyInfo>(), false);
}
class FramebufferWatchingGLRenderer : public FakeRendererGL {
public:
FramebufferWatchingGLRenderer(RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
+ DisplayResourceProvider* resource_provider)
: FakeRendererGL(settings, output_surface, resource_provider) {}
void BindFramebufferToOutputSurface() override {
@@ -3780,7 +3794,7 @@ TEST_F(GLRendererTest, UndamagedRenderPassStillDrawnWhenNoPartialSwap) {
auto output_surface = FakeOutputSurface::Create3d(std::move(provider));
output_surface->BindToClient(&output_surface_client);
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
output_surface->context_provider(), nullptr);
diff --git a/chromium/components/viz/service/display/output_surface.cc b/chromium/components/viz/service/display/output_surface.cc
index 87cdf3118b7..f563afc1deb 100644
--- a/chromium/components/viz/service/display/output_surface.cc
+++ b/chromium/components/viz/service/display/output_surface.cc
@@ -16,6 +16,7 @@
#include "gpu/GLES2/gl2extchromium.h"
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/vulkan/buildflags.h"
#include "ui/gfx/swap_result.h"
namespace viz {
@@ -31,72 +32,35 @@ OutputSurface::OutputSurface(
DCHECK(software_device_);
}
+#if BUILDFLAG(ENABLE_VULKAN)
OutputSurface::OutputSurface(
scoped_refptr<VulkanContextProvider> vulkan_context_provider)
: vulkan_context_provider_(std::move(vulkan_context_provider)) {
DCHECK(vulkan_context_provider_);
}
+#endif
OutputSurface::~OutputSurface() = default;
-OutputSurface::LatencyInfoCache::SwapInfo::SwapInfo(
- uint64_t id,
- std::vector<ui::LatencyInfo> info)
- : swap_id(id), latency_info(std::move(info)) {}
-
-OutputSurface::LatencyInfoCache::SwapInfo::SwapInfo(SwapInfo&& src) = default;
-
-OutputSurface::LatencyInfoCache::SwapInfo&
-OutputSurface::LatencyInfoCache::SwapInfo::operator=(SwapInfo&& src) = default;
-
-OutputSurface::LatencyInfoCache::SwapInfo::~SwapInfo() = default;
-
-OutputSurface::LatencyInfoCache::LatencyInfoCache(Client* client)
- : client_(client) {
- DCHECK(client);
-}
-
-OutputSurface::LatencyInfoCache::~LatencyInfoCache() = default;
-
-bool OutputSurface::LatencyInfoCache::WillSwap(
- std::vector<ui::LatencyInfo> latency_info) {
- bool snapshot_requested = false;
- for (const auto& latency : latency_info) {
- if (latency.FindLatency(ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT,
- nullptr)) {
- snapshot_requested = true;
- break;
- }
- }
-
- // Don't grow unbounded in case of error.
- while (swap_infos_.size() >= kCacheCountMax) {
- client_->LatencyInfoCompleted(swap_infos_.front().latency_info);
- swap_infos_.pop_front();
+void OutputSurface::UpdateLatencyInfoOnSwap(
+ const gfx::SwapResponse& response,
+ std::vector<ui::LatencyInfo>* latency_info) {
+ for (auto& latency : *latency_info) {
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, response.swap_start, 1);
+ latency.AddLatencyNumberWithTimestamp(
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0,
+ response.swap_end, 1);
}
- swap_infos_.emplace_back(swap_id_++, std::move(latency_info));
-
- return snapshot_requested;
}
-void OutputSurface::LatencyInfoCache::OnSwapBuffersCompleted(
- const gfx::SwapResponse& response) {
- auto it = std::find_if(
- swap_infos_.begin(), swap_infos_.end(),
- [&](const SwapInfo& si) { return si.swap_id == response.swap_id; });
-
- if (it != swap_infos_.end()) {
- for (auto& latency : it->latency_info) {
- latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, response.swap_start,
- 1);
- latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
- response.swap_end, 1);
- }
- client_->LatencyInfoCompleted(it->latency_info);
- swap_infos_.erase(it);
+bool OutputSurface::LatencyInfoHasSnapshotRequest(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+ for (const auto& latency : latency_info) {
+ if (latency.Snapshots().size())
+ return true;
}
+ return false;
}
} // namespace viz
diff --git a/chromium/components/viz/service/display/output_surface.h b/chromium/components/viz/service/display/output_surface.h
index 26d0e6394c2..9eaef93529a 100644
--- a/chromium/components/viz/service/display/output_surface.h
+++ b/chromium/components/viz/service/display/output_surface.h
@@ -12,17 +12,20 @@
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/gpu/vulkan_context_provider.h"
#include "components/viz/common/resources/returned_resource.h"
#include "components/viz/service/display/overlay_candidate_validator.h"
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "gpu/vulkan/buildflags.h"
-#include "gpu/vulkan/vulkan_surface.h"
#include "ui/gfx/color_space.h"
#include "ui/latency/latency_info.h"
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "gpu/vulkan/vulkan_surface.h"
+#endif
+
namespace gfx {
class ColorSpace;
class Size;
@@ -57,9 +60,11 @@ class VIZ_SERVICE_EXPORT OutputSurface {
explicit OutputSurface(scoped_refptr<ContextProvider> context_provider);
// Constructor for software compositing.
explicit OutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device);
+#if BUILDFLAG(ENABLE_VULKAN)
// Constructor for Vulkan-based compositing.
explicit OutputSurface(
scoped_refptr<VulkanContextProvider> vulkan_context_provider);
+#endif
virtual ~OutputSurface();
@@ -70,9 +75,11 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// In the event of a lost context, the entire output surface should be
// recreated.
ContextProvider* context_provider() const { return context_provider_.get(); }
+#if BUILDFLAG(ENABLE_VULKAN)
VulkanContextProvider* vulkan_context_provider() const {
return vulkan_context_provider_.get();
}
+#endif
SoftwareOutputDevice* software_device() const {
return software_device_.get();
}
@@ -108,9 +115,6 @@ class VIZ_SERVICE_EXPORT OutputSurface {
// Get the format for the main image's overlay.
virtual gfx::BufferFormat GetOverlayBufferFormat() const = 0;
- // If this returns true, then the surface will not attempt to draw.
- virtual bool SurfaceIsSuspendForRecycle() const = 0;
-
virtual void Reshape(const gfx::Size& size,
float device_scale_factor,
const gfx::ColorSpace& color_space,
@@ -134,54 +138,30 @@ class VIZ_SERVICE_EXPORT OutputSurface {
virtual gpu::VulkanSurface* GetVulkanSurface() = 0;
#endif
- // A helper class for implementations of OutputSurface that want to cache
- // LatencyInfos that can be updated when we get the corresponding
- // gfx::SwapResponse.
- class VIZ_SERVICE_EXPORT LatencyInfoCache {
- public:
- class Client {
- public:
- virtual ~Client() = default;
- virtual void LatencyInfoCompleted(
- const std::vector<ui::LatencyInfo>& latency_info) = 0;
- };
-
- explicit LatencyInfoCache(Client* client);
- ~LatencyInfoCache();
-
- // Returns true if there's a snapshot request.
- bool WillSwap(std::vector<ui::LatencyInfo> latency_info);
- void OnSwapBuffersCompleted(const gfx::SwapResponse& response);
-
- private:
- struct SwapInfo {
- SwapInfo(uint64_t id, std::vector<ui::LatencyInfo> info);
- SwapInfo(SwapInfo&& src);
- SwapInfo& operator=(SwapInfo&& src);
- ~SwapInfo();
- uint64_t swap_id;
- std::vector<ui::LatencyInfo> latency_info;
- DISALLOW_COPY_AND_ASSIGN(SwapInfo);
- };
-
- Client* client_ = nullptr;
-
- // Incremented in sync with the ImageTransportSurface's swap_id_.
- uint64_t swap_id_ = 0;
- base::circular_deque<SwapInfo> swap_infos_;
-
- // We only expect a couple swap acks outstanding, but there are cases where
- // we will get timestamps for swaps from several frames ago when using
- // platform extensions like eglGetFrameTimestampsANDROID.
- static constexpr size_t kCacheCountMax = 10;
-
- DISALLOW_COPY_AND_ASSIGN(LatencyInfoCache);
- };
+ // Updates the GpuFence associated with this surface. The id of a newly
+ // created GpuFence is returned, or if an error occurs, or fences are not
+ // supported, the special id of 0 (meaning "no fence") is returned. In all
+ // cases, any previously associated fence is destroyed. The returned fence id
+ // corresponds to the GL id used by the CHROMIUM_gpu_fence GL extension and
+ // can be passed directly to any related extension functions.
+ virtual unsigned UpdateGpuFence() = 0;
+
+ // Returns true if any of the LatencyInfos provided contains a snapshot
+ // request.
+ static bool LatencyInfoHasSnapshotRequest(
+ const std::vector<ui::LatencyInfo>& latency_info);
+
+ // Updates timing info on the provided LatencyInfo when swap completes.
+ static void UpdateLatencyInfoOnSwap(
+ const gfx::SwapResponse& response,
+ std::vector<ui::LatencyInfo>* latency_info);
protected:
struct OutputSurface::Capabilities capabilities_;
scoped_refptr<ContextProvider> context_provider_;
+#if BUILDFLAG(ENABLE_VULKAN)
scoped_refptr<VulkanContextProvider> vulkan_context_provider_;
+#endif
std::unique_ptr<SoftwareOutputDevice> software_device_;
private:
diff --git a/chromium/components/viz/service/display/output_surface_client.h b/chromium/components/viz/service/display/output_surface_client.h
index 58c086544c7..e802952c92d 100644
--- a/chromium/components/viz/service/display/output_surface_client.h
+++ b/chromium/components/viz/service/display/output_surface_client.h
@@ -13,6 +13,7 @@
#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/texture_in_use_response.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/latency/latency_info.h"
namespace gfx {
struct CALayerParams;
@@ -25,7 +26,7 @@ class VIZ_SERVICE_EXPORT OutputSurfaceClient {
public:
// A notification that the swap of the backbuffer to the hardware is complete
// and is now visible to the user.
- virtual void DidReceiveSwapBuffersAck(uint64_t swap_id) = 0;
+ virtual void DidReceiveSwapBuffersAck() = 0;
// For surfaceless/ozone implementations to create damage for the next frame.
virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
@@ -38,12 +39,14 @@ class VIZ_SERVICE_EXPORT OutputSurfaceClient {
virtual void DidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) = 0;
- // A notification that the presentation feedback for a CompositorFrame with
- // given |swap_id|. See |gfx::PresentationFeedback| for detail.
+ // See |gfx::PresentationFeedback| for detail.
virtual void DidReceivePresentationFeedback(
- uint64_t swap_id,
const gfx::PresentationFeedback& feedback) {}
+ // Call after a swap occurs with all LatencyInfo aggregated up to that point.
+ virtual void DidFinishLatencyInfo(
+ const std::vector<ui::LatencyInfo>& latency_info) = 0;
+
protected:
virtual ~OutputSurfaceClient() {}
};
diff --git a/chromium/components/viz/service/display/output_surface_frame.h b/chromium/components/viz/service/display/output_surface_frame.h
index 6a09dfa06da..b3f20cedc66 100644
--- a/chromium/components/viz/service/display/output_surface_frame.h
+++ b/chromium/components/viz/service/display/output_surface_frame.h
@@ -34,6 +34,7 @@ class VIZ_SERVICE_EXPORT OutputSurfaceFrame {
// Optional content area for SwapWithBounds. Rectangles may overlap.
std::vector<gfx::Rect> content_bounds;
std::vector<ui::LatencyInfo> latency_info;
+ bool need_presentation_feedback = false;
private:
DISALLOW_COPY_AND_ASSIGN(OutputSurfaceFrame);
diff --git a/chromium/components/viz/service/display/overlay_candidate.cc b/chromium/components/viz/service/display/overlay_candidate.cc
new file mode 100644
index 00000000000..2cac5568008
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_candidate.cc
@@ -0,0 +1,397 @@
+// 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 "components/viz/service/display/overlay_candidate.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "cc/base/math_util.h"
+#include "components/viz/common/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/stream_video_draw_quad.h"
+#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/service/display/display_resource_provider.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace viz {
+
+namespace {
+// Tolerance for considering axis vector elements to be zero.
+const SkMScalar kEpsilon = std::numeric_limits<float>::epsilon();
+
+const gfx::BufferFormat kOverlayFormats[] = {
+ gfx::BufferFormat::RGBX_8888, gfx::BufferFormat::RGBA_8888,
+ gfx::BufferFormat::BGRX_8888, gfx::BufferFormat::BGRA_8888,
+ gfx::BufferFormat::BGR_565, gfx::BufferFormat::YUV_420_BIPLANAR};
+
+enum Axis { NONE, AXIS_POS_X, AXIS_NEG_X, AXIS_POS_Y, AXIS_NEG_Y };
+
+Axis VectorToAxis(const gfx::Vector3dF& vec) {
+ if (std::abs(vec.z()) > kEpsilon)
+ return NONE;
+ const bool x_zero = (std::abs(vec.x()) <= kEpsilon);
+ const bool y_zero = (std::abs(vec.y()) <= kEpsilon);
+ if (x_zero && !y_zero)
+ return (vec.y() > 0) ? AXIS_POS_Y : AXIS_NEG_Y;
+ else if (y_zero && !x_zero)
+ return (vec.x() > 0) ? AXIS_POS_X : AXIS_NEG_X;
+ else
+ return NONE;
+}
+
+gfx::OverlayTransform GetOverlayTransform(const gfx::Transform& quad_transform,
+ bool y_flipped) {
+ if (!quad_transform.Preserves2dAxisAlignment()) {
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+
+ gfx::Vector3dF x_axis = cc::MathUtil::GetXAxis(quad_transform);
+ gfx::Vector3dF y_axis = cc::MathUtil::GetYAxis(quad_transform);
+ if (y_flipped) {
+ y_axis.Scale(-1);
+ }
+
+ Axis x_to = VectorToAxis(x_axis);
+ Axis y_to = VectorToAxis(y_axis);
+
+ if (x_to == AXIS_POS_X && y_to == AXIS_POS_Y)
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ else if (x_to == AXIS_NEG_X && y_to == AXIS_POS_Y)
+ return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ else if (x_to == AXIS_POS_X && y_to == AXIS_NEG_Y)
+ return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ else if (x_to == AXIS_NEG_Y && y_to == AXIS_POS_X)
+ return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+ else if (x_to == AXIS_NEG_X && y_to == AXIS_NEG_Y)
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ else if (x_to == AXIS_POS_Y && y_to == AXIS_NEG_X)
+ return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ else
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+}
+
+// Apply transform |delta| to |in| and return the resulting transform,
+// or OVERLAY_TRANSFORM_INVALID.
+gfx::OverlayTransform ComposeTransforms(gfx::OverlayTransform delta,
+ gfx::OverlayTransform in) {
+ // There are 8 different possible transforms. We can characterize these
+ // by looking at where the origin moves and the direction the horizontal goes.
+ // (TL=top-left, BR=bottom-right, H=horizontal, V=vertical).
+ // NONE: TL, H
+ // FLIP_VERTICAL: BL, H
+ // FLIP_HORIZONTAL: TR, H
+ // ROTATE_90: TR, V
+ // ROTATE_180: BR, H
+ // ROTATE_270: BL, V
+ // Missing transforms: TL, V & BR, V
+ // Basic combinations:
+ // Flip X & Y -> Rotate 180 (TL,H -> TR,H -> BR,H or TL,H -> BL,H -> BR,H)
+ // Flip X or Y + Rotate 180 -> other flip (eg, TL,H -> TR,H -> BL,H)
+ // Rotate + Rotate simply adds values.
+ // Rotate 90/270 + flip is invalid because we can only have verticals with
+ // the origin in TR or BL.
+ if (delta == gfx::OVERLAY_TRANSFORM_NONE)
+ return in;
+ switch (in) {
+ case gfx::OVERLAY_TRANSFORM_NONE:
+ return delta;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_270;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ switch (delta) {
+ case gfx::OVERLAY_TRANSFORM_ROTATE_90:
+ return gfx::OVERLAY_TRANSFORM_NONE;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_180:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ case gfx::OVERLAY_TRANSFORM_ROTATE_270:
+ return gfx::OVERLAY_TRANSFORM_ROTATE_180;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+ break;
+ default:
+ return gfx::OVERLAY_TRANSFORM_INVALID;
+ }
+}
+
+} // namespace
+
+OverlayCandidate::OverlayCandidate()
+ : transform(gfx::OVERLAY_TRANSFORM_NONE),
+ format(gfx::BufferFormat::RGBA_8888),
+ uv_rect(0.f, 0.f, 1.f, 1.f),
+ is_clipped(false),
+ is_opaque(false),
+ use_output_surface_for_resource(false),
+ resource_id(0),
+#if defined(OS_ANDROID)
+ is_backed_by_surface_texture(false),
+ is_promotable_hint(false),
+#endif
+ plane_z_order(0),
+ is_unoccluded(false),
+ overlay_handled(false),
+ gpu_fence_id(0) {
+}
+
+OverlayCandidate::OverlayCandidate(const OverlayCandidate& other) = default;
+
+OverlayCandidate::~OverlayCandidate() = default;
+
+// static
+bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider,
+ const SkMatrix44& output_color_matrix,
+ const DrawQuad* quad,
+ OverlayCandidate* candidate) {
+ // It is currently not possible to set a color conversion matrix on an HW
+ // overlay plane.
+ // TODO(https://crbug.com/792757): Remove this check once the bug is resolved.
+ if (!output_color_matrix.isIdentity())
+ return false;
+
+ // We don't support an opacity value different than one for an overlay plane.
+ if (quad->shared_quad_state->opacity != 1.f)
+ return false;
+ // We support only kSrc (no blending) and kSrcOver (blending with premul).
+ if (!(quad->shared_quad_state->blend_mode == SkBlendMode::kSrc ||
+ quad->shared_quad_state->blend_mode == SkBlendMode::kSrcOver))
+ return false;
+
+ switch (quad->material) {
+ case DrawQuad::TEXTURE_CONTENT:
+ return FromTextureQuad(resource_provider,
+ TextureDrawQuad::MaterialCast(quad), candidate);
+ case DrawQuad::TILED_CONTENT:
+ return FromTileQuad(resource_provider, TileDrawQuad::MaterialCast(quad),
+ candidate);
+ case DrawQuad::STREAM_VIDEO_CONTENT:
+ return FromStreamVideoQuad(resource_provider,
+ StreamVideoDrawQuad::MaterialCast(quad),
+ candidate);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+// static
+bool OverlayCandidate::IsInvisibleQuad(const DrawQuad* quad) {
+ float opacity = quad->shared_quad_state->opacity;
+ if (opacity < std::numeric_limits<float>::epsilon())
+ return true;
+ if (quad->material == DrawQuad::SOLID_COLOR) {
+ SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
+ float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
+ return quad->ShouldDrawWithBlending() &&
+ alpha < std::numeric_limits<float>::epsilon();
+ }
+ return false;
+}
+
+// static
+bool OverlayCandidate::IsOccluded(const OverlayCandidate& candidate,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end) {
+ // Check that no visible quad overlaps the candidate.
+ for (auto overlap_iter = quad_list_begin; overlap_iter != quad_list_end;
+ ++overlap_iter) {
+ gfx::RectF overlap_rect = cc::MathUtil::MapClippedRect(
+ overlap_iter->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(overlap_iter->rect));
+ if (candidate.display_rect.Intersects(overlap_rect) &&
+ !OverlayCandidate::IsInvisibleQuad(*overlap_iter))
+ return true;
+ }
+ return false;
+}
+
+// static
+bool OverlayCandidate::FromDrawQuadResource(
+ DisplayResourceProvider* resource_provider,
+ const DrawQuad* quad,
+ ResourceId resource_id,
+ bool y_flipped,
+ OverlayCandidate* candidate) {
+ if (!resource_provider->IsOverlayCandidate(resource_id))
+ return false;
+
+ candidate->format = resource_provider->GetBufferFormat(resource_id);
+ if (std::find(std::begin(kOverlayFormats), std::end(kOverlayFormats),
+ candidate->format) == std::end(kOverlayFormats))
+ return false;
+
+ gfx::OverlayTransform overlay_transform = GetOverlayTransform(
+ quad->shared_quad_state->quad_to_target_transform, y_flipped);
+ if (overlay_transform == gfx::OVERLAY_TRANSFORM_INVALID)
+ return false;
+
+ auto& transform = quad->shared_quad_state->quad_to_target_transform;
+ candidate->display_rect = gfx::RectF(quad->rect);
+ transform.TransformRect(&candidate->display_rect);
+
+ candidate->clip_rect = quad->shared_quad_state->clip_rect;
+ candidate->is_clipped = quad->shared_quad_state->is_clipped;
+ candidate->is_opaque = !quad->ShouldDrawWithBlending();
+
+ candidate->resource_id = resource_id;
+ candidate->transform = overlay_transform;
+
+ return true;
+}
+
+// static
+bool OverlayCandidate::FromTextureQuad(
+ DisplayResourceProvider* resource_provider,
+ const TextureDrawQuad* quad,
+ OverlayCandidate* candidate) {
+ if (quad->background_color != SK_ColorTRANSPARENT)
+ return false;
+ if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(),
+ quad->y_flipped, candidate)) {
+ return false;
+ }
+ candidate->resource_size_in_pixels = quad->resource_size_in_pixels();
+ candidate->uv_rect = BoundingRect(quad->uv_top_left, quad->uv_bottom_right);
+ return true;
+}
+
+// static
+bool OverlayCandidate::FromTileQuad(DisplayResourceProvider* resource_provider,
+ const TileDrawQuad* quad,
+ OverlayCandidate* candidate) {
+ if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(), false,
+ candidate)) {
+ return false;
+ }
+ candidate->resource_size_in_pixels = quad->texture_size;
+ candidate->uv_rect = quad->tex_coord_rect;
+ return true;
+}
+
+// static
+bool OverlayCandidate::FromStreamVideoQuad(
+ DisplayResourceProvider* resource_provider,
+ const StreamVideoDrawQuad* quad,
+ OverlayCandidate* candidate) {
+ if (!FromDrawQuadResource(resource_provider, quad, quad->resource_id(), false,
+ candidate)) {
+ return false;
+ }
+ if (!quad->matrix.IsScaleOrTranslation()) {
+ // We cannot handle anything other than scaling & translation for texture
+ // coordinates yet.
+ return false;
+ }
+ candidate->resource_id = quad->resource_id();
+ candidate->resource_size_in_pixels = quad->resource_size_in_pixels();
+#if defined(OS_ANDROID)
+ candidate->is_backed_by_surface_texture =
+ resource_provider->IsBackedBySurfaceTexture(quad->resource_id());
+#endif
+
+ gfx::Point3F uv0 = gfx::Point3F(0, 0, 0);
+ gfx::Point3F uv1 = gfx::Point3F(1, 1, 0);
+ quad->matrix.TransformPoint(&uv0);
+ quad->matrix.TransformPoint(&uv1);
+ gfx::Vector3dF delta = uv1 - uv0;
+ if (delta.x() < 0) {
+ candidate->transform = ComposeTransforms(
+ gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL, candidate->transform);
+ float x0 = uv0.x();
+ uv0.set_x(uv1.x());
+ uv1.set_x(x0);
+ delta.set_x(-delta.x());
+ }
+
+ if (delta.y() < 0) {
+ // In this situation, uv0y < uv1y. Since we overlay inverted, a request
+ // to invert the source texture means we can just output the texture
+ // normally and it will be correct.
+ candidate->uv_rect = gfx::RectF(uv0.x(), uv1.y(), delta.x(), -delta.y());
+ } else {
+ candidate->transform = ComposeTransforms(
+ gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL, candidate->transform);
+ candidate->uv_rect = gfx::RectF(uv0.x(), uv0.y(), delta.x(), delta.y());
+ }
+ return true;
+}
+
+OverlayCandidateList::OverlayCandidateList() = default;
+
+OverlayCandidateList::OverlayCandidateList(const OverlayCandidateList& other) =
+ default;
+
+OverlayCandidateList::OverlayCandidateList(OverlayCandidateList&& other) =
+ default;
+
+OverlayCandidateList::~OverlayCandidateList() = default;
+
+OverlayCandidateList& OverlayCandidateList::operator=(
+ const OverlayCandidateList& other) = default;
+
+OverlayCandidateList& OverlayCandidateList::operator=(
+ OverlayCandidateList&& other) = default;
+
+void OverlayCandidateList::AddPromotionHint(const OverlayCandidate& candidate) {
+ promotion_hint_info_map_[candidate.resource_id] = candidate.display_rect;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_candidate.h b/chromium/components/viz/service/display/overlay_candidate.h
new file mode 100644
index 00000000000..27217c69892
--- /dev/null
+++ b/chromium/components/viz/service/display/overlay_candidate.h
@@ -0,0 +1,144 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_
+
+#include <map>
+#include <vector>
+
+#include "build/build_config.h"
+#include "components/viz/common/quads/render_pass.h"
+#include "components/viz/common/resources/resource_id.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/overlay_transform.h"
+#include "ui/gfx/transform.h"
+
+namespace gfx {
+class Rect;
+}
+
+namespace viz {
+class DisplayResourceProvider;
+class StreamVideoDrawQuad;
+class TextureDrawQuad;
+class TileDrawQuad;
+
+class VIZ_SERVICE_EXPORT OverlayCandidate {
+ public:
+ // Returns true and fills in |candidate| if |draw_quad| is of a known quad
+ // type and contains an overlayable resource.
+ static bool FromDrawQuad(DisplayResourceProvider* resource_provider,
+ const SkMatrix44& output_color_matrix,
+ const DrawQuad* quad,
+ OverlayCandidate* candidate);
+ // Returns true if |quad| will not block quads underneath from becoming
+ // an overlay.
+ static bool IsInvisibleQuad(const DrawQuad* quad);
+
+ // Returns true if any any of the quads in the list given by |quad_list_begin|
+ // and |quad_list_end| are visible and on top of |candidate|.
+ static bool IsOccluded(const OverlayCandidate& candidate,
+ QuadList::ConstIterator quad_list_begin,
+ QuadList::ConstIterator quad_list_end);
+
+ OverlayCandidate();
+ OverlayCandidate(const OverlayCandidate& other);
+ ~OverlayCandidate();
+
+ // Transformation to apply to layer during composition.
+ gfx::OverlayTransform transform;
+ // Format of the buffer to scanout.
+ gfx::BufferFormat format;
+ // Size of the resource, in pixels.
+ gfx::Size resource_size_in_pixels;
+ // Rect on the display to position the overlay to. Implementer must convert
+ // to integer coordinates if setting |overlay_handled| to true.
+ gfx::RectF display_rect;
+ // Crop within the buffer to be placed inside |display_rect|.
+ gfx::RectF uv_rect;
+ // Clip rect in the target content space after composition.
+ gfx::Rect clip_rect;
+ // If the quad is clipped after composition.
+ bool is_clipped;
+ // If the quad doesn't require blending.
+ bool is_opaque;
+ // True if the texture for this overlay should be the same one used by the
+ // output surface's main overlay.
+ bool use_output_surface_for_resource;
+ // Texture resource to present in an overlay.
+ unsigned resource_id;
+
+#if defined(OS_ANDROID)
+ // For candidates from StreamVideoDrawQuads, this records whether the quad is
+ // marked as being backed by a SurfaceTexture or not. If so, it's not really
+ // promotable to an overlay.
+ bool is_backed_by_surface_texture;
+
+ // Filled in by the OverlayCandidateValidator to indicate whether this is a
+ // promotable candidate or not.
+ bool is_promotable_hint;
+#endif
+
+ // Stacking order of the overlay plane relative to the main surface,
+ // which is 0. Signed to allow for "underlays".
+ int plane_z_order;
+ // True if the overlay does not have any visible quads on top of it. Set by
+ // the strategy so the OverlayProcessor can consider subtracting damage caused
+ // by underlay quads.
+ bool is_unoccluded;
+
+ // To be modified by the implementer if this candidate can go into
+ // an overlay.
+ bool overlay_handled;
+
+ // Gpu fence to wait for before overlay is ready for display.
+ unsigned gpu_fence_id;
+
+ private:
+ static bool FromDrawQuadResource(DisplayResourceProvider* resource_provider,
+ const DrawQuad* quad,
+ ResourceId resource_id,
+ bool y_flipped,
+ OverlayCandidate* candidate);
+ static bool FromTextureQuad(DisplayResourceProvider* resource_provider,
+ const TextureDrawQuad* quad,
+ OverlayCandidate* candidate);
+ static bool FromTileQuad(DisplayResourceProvider* resource_provider,
+ const TileDrawQuad* quad,
+ OverlayCandidate* candidate);
+ static bool FromStreamVideoQuad(DisplayResourceProvider* resource_provider,
+ const StreamVideoDrawQuad* quad,
+ OverlayCandidate* candidate);
+};
+
+class VIZ_SERVICE_EXPORT OverlayCandidateList
+ : public std::vector<OverlayCandidate> {
+ public:
+ OverlayCandidateList();
+ OverlayCandidateList(const OverlayCandidateList&);
+ OverlayCandidateList(OverlayCandidateList&&);
+ ~OverlayCandidateList();
+
+ OverlayCandidateList& operator=(const OverlayCandidateList&);
+ OverlayCandidateList& operator=(OverlayCandidateList&&);
+
+ // [id] == candidate's |display_rect| for all promotable resources.
+ using PromotionHintInfoMap = std::map<ResourceId, gfx::RectF>;
+
+ // For android, this provides a set of resources that could be promoted to
+ // overlay, if one backs them with a SurfaceView.
+ PromotionHintInfoMap promotion_hint_info_map_;
+
+ // Helper to insert |candidate| into |promotion_hint_info_|.
+ void AddPromotionHint(const OverlayCandidate& candidate);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_OVERLAY_CANDIDATE_H_
diff --git a/chromium/components/viz/service/display/overlay_candidate_validator.h b/chromium/components/viz/service/display/overlay_candidate_validator.h
index d053dbe8a73..8407cb9a36e 100644
--- a/chromium/components/viz/service/display/overlay_candidate_validator.h
+++ b/chromium/components/viz/service/display/overlay_candidate_validator.h
@@ -7,7 +7,7 @@
#include <vector>
-#include "cc/output/overlay_candidate.h"
+#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/display/overlay_processor.h"
#include "components/viz/service/viz_service_export.h"
@@ -33,7 +33,7 @@ class VIZ_SERVICE_EXPORT OverlayCandidateValidator {
// to be traditionally composited. Candidates with |overlay_handled| set to
// true must also have their |display_rect| converted to integer
// coordinates if necessary.
- virtual void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) = 0;
+ virtual void CheckOverlaySupport(OverlayCandidateList* surfaces) = 0;
virtual ~OverlayCandidateValidator() {}
};
diff --git a/chromium/components/viz/service/display/overlay_processor.cc b/chromium/components/viz/service/display/overlay_processor.cc
index 002e0535d9e..f43a211444a 100644
--- a/chromium/components/viz/service/display/overlay_processor.cc
+++ b/chromium/components/viz/service/display/overlay_processor.cc
@@ -4,16 +4,19 @@
#include "components/viz/service/display/overlay_processor.h"
+#include "base/metrics/histogram_macros.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "cc/resources/display_resource_provider.h"
#include "components/viz/service/display/dc_layer_overlay.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/overlay_strategy_single_on_top.h"
#include "components/viz/service/display/overlay_strategy_underlay.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/transform.h"
+namespace viz {
+
namespace {
#if defined(OS_ANDROID)
@@ -21,9 +24,8 @@ namespace {
// before returning from ProcessForOverlays.
class SendPromotionHintsBeforeReturning {
public:
- SendPromotionHintsBeforeReturning(
- cc::DisplayResourceProvider* resource_provider,
- cc::OverlayCandidateList* candidates)
+ SendPromotionHintsBeforeReturning(DisplayResourceProvider* resource_provider,
+ OverlayCandidateList* candidates)
: resource_provider_(resource_provider), candidates_(candidates) {}
~SendPromotionHintsBeforeReturning() {
resource_provider_->SendPromotionHints(
@@ -31,8 +33,8 @@ class SendPromotionHintsBeforeReturning {
}
private:
- cc::DisplayResourceProvider* resource_provider_;
- cc::OverlayCandidateList* candidates_;
+ DisplayResourceProvider* resource_provider_;
+ OverlayCandidateList* candidates_;
DISALLOW_COPY_AND_ASSIGN(SendPromotionHintsBeforeReturning);
};
@@ -40,7 +42,9 @@ class SendPromotionHintsBeforeReturning {
} // namespace
-namespace viz {
+OverlayProcessor::StrategyType OverlayProcessor::Strategy::GetUMAEnum() const {
+ return StrategyType::kUnknown;
+}
OverlayProcessor::OverlayProcessor(OutputSurface* surface)
: surface_(surface) {}
@@ -62,11 +66,11 @@ gfx::Rect OverlayProcessor::GetAndResetOverlayDamage() {
}
bool OverlayProcessor::ProcessForCALayers(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
const OverlayProcessor::FilterOperationsMap& render_pass_filters,
const OverlayProcessor::FilterOperationsMap& render_pass_background_filters,
- cc::OverlayCandidateList* overlay_candidates,
+ OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect) {
OverlayCandidateValidator* overlay_validator =
@@ -90,11 +94,11 @@ bool OverlayProcessor::ProcessForCALayers(
}
bool OverlayProcessor::ProcessForDCLayers(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPassList* render_passes,
const OverlayProcessor::FilterOperationsMap& render_pass_filters,
const OverlayProcessor::FilterOperationsMap& render_pass_background_filters,
- cc::OverlayCandidateList* overlay_candidates,
+ OverlayCandidateList* overlay_candidates,
DCLayerOverlayList* dc_layer_overlays,
gfx::Rect* damage_rect) {
OverlayCandidateValidator* overlay_validator =
@@ -111,12 +115,12 @@ bool OverlayProcessor::ProcessForDCLayers(
}
void OverlayProcessor::ProcessForOverlays(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPassList* render_passes,
const SkMatrix44& output_color_matrix,
const OverlayProcessor::FilterOperationsMap& render_pass_filters,
const OverlayProcessor::FilterOperationsMap& render_pass_background_filters,
- cc::OverlayCandidateList* candidates,
+ OverlayCandidateList* candidates,
CALayerOverlayList* ca_layer_overlays,
DCLayerOverlayList* dc_layer_overlays,
gfx::Rect* damage_rect,
@@ -158,16 +162,23 @@ void OverlayProcessor::ProcessForOverlays(
}
// Only if that fails, attempt hardware overlay strategies.
+ Strategy* successful_strategy = nullptr;
for (const auto& strategy : strategies_) {
if (!strategy->Attempt(output_color_matrix, resource_provider,
render_passes->back().get(), candidates,
content_bounds)) {
continue;
}
-
+ successful_strategy = strategy.get();
UpdateDamageRect(candidates, previous_frame_underlay_rect, damage_rect);
break;
}
+
+ UMA_HISTOGRAM_ENUMERATION("Viz.DisplayCompositor.OverlayStrategy",
+ successful_strategy
+ ? successful_strategy->GetUMAEnum()
+ : StrategyType::kNoStrategyUsed);
+
TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("viz.debug.overlay_planes"),
"Scheduled overlay planes", candidates->size());
}
@@ -181,12 +192,12 @@ void OverlayProcessor::ProcessForOverlays(
// previous frame. This only handles the common case of a single underlay quad
// for fullscreen video.
void OverlayProcessor::UpdateDamageRect(
- cc::OverlayCandidateList* candidates,
+ OverlayCandidateList* candidates,
const gfx::Rect& previous_frame_underlay_rect,
gfx::Rect* damage_rect) {
gfx::Rect output_surface_overlay_damage_rect;
gfx::Rect this_frame_underlay_rect;
- for (const cc::OverlayCandidate& overlay : *candidates) {
+ for (const OverlayCandidate& overlay : *candidates) {
if (overlay.plane_z_order >= 0) {
const gfx::Rect overlay_display_rect =
ToEnclosedRect(overlay.display_rect);
diff --git a/chromium/components/viz/service/display/overlay_processor.h b/chromium/components/viz/service/display/overlay_processor.h
index 3822f52fed4..a8ee4b71e95 100644
--- a/chromium/components/viz/service/display/overlay_processor.h
+++ b/chromium/components/viz/service/display/overlay_processor.h
@@ -9,10 +9,10 @@
#include "base/containers/flat_map.h"
#include "base/macros.h"
-#include "cc/output/overlay_candidate.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/service/display/ca_layer_overlay.h"
#include "components/viz/service/display/dc_layer_overlay.h"
+#include "components/viz/service/display/overlay_candidate.h"
#include "components/viz/service/viz_service_export.h"
namespace cc {
@@ -24,6 +24,18 @@ class OutputSurface;
class VIZ_SERVICE_EXPORT OverlayProcessor {
public:
+ // Enum used for UMA histogram. These enum values must not be changed or
+ // reused.
+ enum class StrategyType {
+ kUnknown = 0,
+ kNoStrategyUsed = 1,
+ kFullscreen = 2,
+ kSingleOnTop = 3,
+ kUnderlay = 4,
+ kUnderlayCast = 5,
+ kMaxValue = kUnderlayCast,
+ };
+
class VIZ_SERVICE_EXPORT Strategy {
public:
virtual ~Strategy() {}
@@ -32,10 +44,12 @@ class VIZ_SERVICE_EXPORT OverlayProcessor {
// and adds any additional passes necessary to represent overlays to
// |render_passes|.
virtual bool Attempt(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidates,
+ OverlayCandidateList* candidates,
std::vector<gfx::Rect>* content_bounds) = 0;
+
+ virtual StrategyType GetUMAEnum() const;
};
using StrategyList = std::vector<std::unique_ptr<Strategy>>;
@@ -52,12 +66,12 @@ class VIZ_SERVICE_EXPORT OverlayProcessor {
// Attempt to replace quads from the specified root render pass with overlays
// or CALayers. This must be called every frame.
void ProcessForOverlays(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPassList* render_passes,
const SkMatrix44& output_color_matrix,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_background_filters,
- cc::OverlayCandidateList* overlay_candidates,
+ OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
DCLayerOverlayList* dc_layer_overlays,
gfx::Rect* damage_rect,
@@ -71,23 +85,23 @@ class VIZ_SERVICE_EXPORT OverlayProcessor {
private:
bool ProcessForCALayers(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_background_filters,
- cc::OverlayCandidateList* overlay_candidates,
+ OverlayCandidateList* overlay_candidates,
CALayerOverlayList* ca_layer_overlays,
gfx::Rect* damage_rect);
bool ProcessForDCLayers(
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPassList* render_passes,
const FilterOperationsMap& render_pass_filters,
const FilterOperationsMap& render_pass_background_filters,
- cc::OverlayCandidateList* overlay_candidates,
+ OverlayCandidateList* overlay_candidates,
DCLayerOverlayList* dc_layer_overlays,
gfx::Rect* damage_rect);
// Update |damage_rect| by removing damage casued by |candidates|.
- void UpdateDamageRect(cc::OverlayCandidateList* candidates,
+ void UpdateDamageRect(OverlayCandidateList* candidates,
const gfx::Rect& previous_frame_underlay_rect,
gfx::Rect* damage_rect);
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
index d7bd9f61428..aa5e125acca 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.cc
@@ -22,15 +22,15 @@ OverlayStrategyFullscreen::~OverlayStrategyFullscreen() {}
bool OverlayStrategyFullscreen::Attempt(
const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
QuadList* quad_list = &render_pass->quad_list;
// First quad of quad_list is the top most quad.
auto front = quad_list->begin();
while (front != quad_list->end()) {
- if (!cc::OverlayCandidate::IsInvisibleQuad(*front))
+ if (!OverlayCandidate::IsInvisibleQuad(*front))
break;
++front;
}
@@ -42,22 +42,20 @@ bool OverlayStrategyFullscreen::Attempt(
if (quad->ShouldDrawWithBlending())
return false;
- cc::OverlayCandidate candidate;
- if (!cc::OverlayCandidate::FromDrawQuad(
- resource_provider, output_color_matrix, quad, &candidate)) {
+ OverlayCandidate candidate;
+ if (!OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
+ quad, &candidate)) {
return false;
}
if (!candidate.display_rect.origin().IsOrigin() ||
gfx::ToRoundedSize(candidate.display_rect.size()) !=
- render_pass->output_rect.size() ||
- render_pass->output_rect.size() != candidate.resource_size_in_pixels) {
+ render_pass->output_rect.size()) {
return false;
}
candidate.is_opaque = true;
candidate.plane_z_order = 0;
- candidate.overlay_handled = true;
- cc::OverlayCandidateList new_candidate_list;
+ OverlayCandidateList new_candidate_list;
new_candidate_list.push_back(candidate);
capability_checker_->CheckOverlaySupport(&new_candidate_list);
if (!new_candidate_list.front().overlay_handled)
@@ -69,4 +67,8 @@ bool OverlayStrategyFullscreen::Attempt(
return true;
}
+OverlayProcessor::StrategyType OverlayStrategyFullscreen::GetUMAEnum() const {
+ return OverlayProcessor::StrategyType::kFullscreen;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
index 1ce04efa6bb..62bf1232d32 100644
--- a/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
+++ b/chromium/components/viz/service/display/overlay_strategy_fullscreen.h
@@ -23,11 +23,13 @@ class VIZ_SERVICE_EXPORT OverlayStrategyFullscreen
~OverlayStrategyFullscreen() override;
bool Attempt(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
+ OverlayProcessor::StrategyType GetUMAEnum() const override;
+
private:
OverlayCandidateValidator* capability_checker_; // Weak.
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
index 8888d6b4d95..573f48207f9 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.cc
@@ -20,19 +20,19 @@ OverlayStrategySingleOnTop::~OverlayStrategySingleOnTop() {}
bool OverlayStrategySingleOnTop::Attempt(
const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
QuadList* quad_list = &render_pass->quad_list;
// Build a list of candidates with the associated quad.
- cc::OverlayCandidate best_candidate;
+ OverlayCandidate best_candidate;
auto best_quad_it = quad_list->end();
for (auto it = quad_list->begin(); it != quad_list->end(); ++it) {
- cc::OverlayCandidate candidate;
- if (cc::OverlayCandidate::FromDrawQuad(
- resource_provider, output_color_matrix, *it, &candidate) &&
- !cc::OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
+ OverlayCandidate candidate;
+ if (OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
+ *it, &candidate) &&
+ !OverlayCandidate::IsOccluded(candidate, quad_list->cbegin(), it)) {
if (candidate.display_rect.size().GetArea() >
best_candidate.display_rect.size().GetArea()) {
best_candidate = candidate;
@@ -51,18 +51,18 @@ bool OverlayStrategySingleOnTop::Attempt(
bool OverlayStrategySingleOnTop::TryOverlay(
QuadList* quad_list,
- cc::OverlayCandidateList* candidate_list,
- const cc::OverlayCandidate& candidate,
+ OverlayCandidateList* candidate_list,
+ const OverlayCandidate& candidate,
QuadList::Iterator candidate_iterator) {
// Add the overlay.
- cc::OverlayCandidateList new_candidate_list = *candidate_list;
+ OverlayCandidateList new_candidate_list = *candidate_list;
new_candidate_list.push_back(candidate);
new_candidate_list.back().plane_z_order = 1;
// Check for support.
capability_checker_->CheckOverlaySupport(&new_candidate_list);
- const cc::OverlayCandidate& overlay_candidate = new_candidate_list.back();
+ const OverlayCandidate& overlay_candidate = new_candidate_list.back();
// If the candidate can be handled by an overlay, create a pass for it.
if (overlay_candidate.overlay_handled) {
quad_list->EraseAndInvalidateAllPointers(candidate_iterator);
@@ -73,4 +73,8 @@ bool OverlayStrategySingleOnTop::TryOverlay(
return false;
}
+OverlayProcessor::StrategyType OverlayStrategySingleOnTop::GetUMAEnum() const {
+ return OverlayProcessor::StrategyType::kSingleOnTop;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
index 0a50ffa5bd0..9a9c07d4d95 100644
--- a/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
+++ b/chromium/components/viz/service/display/overlay_strategy_single_on_top.h
@@ -21,15 +21,17 @@ class VIZ_SERVICE_EXPORT OverlayStrategySingleOnTop
~OverlayStrategySingleOnTop() override;
bool Attempt(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
+ OverlayProcessor::StrategyType GetUMAEnum() const override;
+
private:
bool TryOverlay(QuadList* quad_list,
- cc::OverlayCandidateList* candidate_list,
- const cc::OverlayCandidate& candidate,
+ OverlayCandidateList* candidate_list,
+ const OverlayCandidate& candidate,
QuadList::Iterator candidate_iterator);
OverlayCandidateValidator* capability_checker_; // Weak.
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.cc b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
index 0460321e86d..846ad14eaba 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.cc
@@ -4,6 +4,7 @@
#include "components/viz/service/display/overlay_strategy_underlay.h"
+#include "build/build_config.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/service/display/overlay_candidate_validator.h"
@@ -11,8 +12,9 @@
namespace viz {
OverlayStrategyUnderlay::OverlayStrategyUnderlay(
- OverlayCandidateValidator* capability_checker)
- : capability_checker_(capability_checker) {
+ OverlayCandidateValidator* capability_checker,
+ OpaqueMode opaque_mode)
+ : capability_checker_(capability_checker), opaque_mode_(opaque_mode) {
DCHECK(capability_checker);
}
@@ -20,22 +22,25 @@ OverlayStrategyUnderlay::~OverlayStrategyUnderlay() {}
bool OverlayStrategyUnderlay::Attempt(
const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
QuadList& quad_list = render_pass->quad_list;
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
- cc::OverlayCandidate candidate;
- if (!cc::OverlayCandidate::FromDrawQuad(
- resource_provider, output_color_matrix, *it, &candidate)) {
+ OverlayCandidate candidate;
+ if (!OverlayCandidate::FromDrawQuad(resource_provider, output_color_matrix,
+ *it, &candidate) ||
+ (opaque_mode_ == OpaqueMode::RequireOpaqueCandidates &&
+ !candidate.is_opaque)) {
continue;
}
// Add the overlay.
- cc::OverlayCandidateList new_candidate_list = *candidate_list;
+ OverlayCandidateList new_candidate_list = *candidate_list;
new_candidate_list.push_back(candidate);
new_candidate_list.back().plane_z_order = -1;
+ new_candidate_list.front().is_opaque = false;
// Check for support.
capability_checker_->CheckOverlaySupport(&new_candidate_list);
@@ -44,7 +49,7 @@ bool OverlayStrategyUnderlay::Attempt(
// need to switch out the video quad with a black transparent one.
if (new_candidate_list.back().overlay_handled) {
new_candidate_list.back().is_unoccluded =
- !cc::OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it);
+ !OverlayCandidate::IsOccluded(candidate, quad_list.cbegin(), it);
quad_list.ReplaceExistingQuadWithOpaqueTransparentSolidColor(it);
candidate_list->swap(new_candidate_list);
@@ -66,4 +71,8 @@ bool OverlayStrategyUnderlay::Attempt(
return false;
}
+OverlayProcessor::StrategyType OverlayStrategyUnderlay::GetUMAEnum() const {
+ return OverlayProcessor::StrategyType::kUnderlay;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay.h b/chromium/components/viz/service/display/overlay_strategy_underlay.h
index 45371779d29..7dce1364b79 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay.h
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay.h
@@ -21,18 +21,32 @@ class OverlayCandidateValidator;
class VIZ_SERVICE_EXPORT OverlayStrategyUnderlay
: public OverlayProcessor::Strategy {
public:
- explicit OverlayStrategyUnderlay(
- OverlayCandidateValidator* capability_checker);
+ enum class OpaqueMode {
+ // Require candidates to be |is_opaque|.
+ RequireOpaqueCandidates,
+
+ // Allow non-|is_opaque| candidates to be promoted.
+ AllowTransparentCandidates,
+ };
+
+ // If |allow_nonopaque_overlays| is true, then we don't require that the
+ // the candidate is_opaque.
+ OverlayStrategyUnderlay(
+ OverlayCandidateValidator* capability_checker,
+ OpaqueMode opaque_mode = OpaqueMode::RequireOpaqueCandidates);
~OverlayStrategyUnderlay() override;
bool Attempt(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
+ OverlayProcessor::StrategyType GetUMAEnum() const override;
+
private:
OverlayCandidateValidator* capability_checker_; // Weak.
+ OpaqueMode opaque_mode_;
DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlay);
};
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
index cc7ba761d87..b585b1c9f2e 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.cc
@@ -26,15 +26,15 @@ OverlayStrategyUnderlayCast::~OverlayStrategyUnderlayCast() {}
bool OverlayStrategyUnderlayCast::Attempt(
const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) {
QuadList& quad_list = render_pass->quad_list;
bool found_underlay = false;
gfx::Rect content_rect;
for (const auto* quad : base::Reversed(quad_list)) {
- if (cc::OverlayCandidate::IsInvisibleQuad(quad))
+ if (OverlayCandidate::IsInvisibleQuad(quad))
continue;
const auto& transform = quad->shared_quad_state->quad_to_target_transform;
@@ -43,8 +43,8 @@ bool OverlayStrategyUnderlayCast::Attempt(
bool is_underlay = false;
if (!found_underlay) {
- cc::OverlayCandidate candidate;
- is_underlay = cc::OverlayCandidate::FromDrawQuad(
+ OverlayCandidate candidate;
+ is_underlay = OverlayCandidate::FromDrawQuad(
resource_provider, output_color_matrix, quad, &candidate);
found_underlay = is_underlay;
}
@@ -63,9 +63,17 @@ bool OverlayStrategyUnderlayCast::Attempt(
}
if (found_underlay) {
+ // If the primary plane shows up in the candidates list make sure it isn't
+ // opaque otherwise the video underlay won't be visible.
+ if (!candidate_list->empty()) {
+ DCHECK_EQ(1u, candidate_list->size());
+ DCHECK(candidate_list->front().use_output_surface_for_resource);
+ candidate_list->front().is_opaque = false;
+ }
+
for (auto it = quad_list.begin(); it != quad_list.end(); ++it) {
- cc::OverlayCandidate candidate;
- if (!cc::OverlayCandidate::FromDrawQuad(
+ OverlayCandidate candidate;
+ if (!OverlayCandidate::FromDrawQuad(
resource_provider, output_color_matrix, *it, &candidate)) {
continue;
}
@@ -89,6 +97,10 @@ bool OverlayStrategyUnderlayCast::Attempt(
return found_underlay;
}
+OverlayProcessor::StrategyType OverlayStrategyUnderlayCast::GetUMAEnum() const {
+ return OverlayProcessor::StrategyType::kUnderlayCast;
+}
+
// static
void OverlayStrategyUnderlayCast::SetOverlayCompositedCallback(
const OverlayCompositedCallback& cb) {
diff --git a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
index 0ea20e6c4f1..ea73e340b5d 100644
--- a/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
+++ b/chromium/components/viz/service/display/overlay_strategy_underlay_cast.h
@@ -24,9 +24,9 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayCast
~OverlayStrategyUnderlayCast() override;
bool Attempt(const SkMatrix44& output_color_matrix,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
RenderPass* render_pass,
- cc::OverlayCandidateList* candidate_list,
+ OverlayCandidateList* candidate_list,
std::vector<gfx::Rect>* content_bounds) override;
// Callback that's made whenever an overlay quad is processed in the
@@ -36,6 +36,8 @@ class VIZ_SERVICE_EXPORT OverlayStrategyUnderlayCast
base::RepeatingCallback<void(const gfx::RectF&, gfx::OverlayTransform)>;
static void SetOverlayCompositedCallback(const OverlayCompositedCallback& cb);
+ OverlayProcessor::StrategyType GetUMAEnum() const override;
+
private:
DISALLOW_COPY_AND_ASSIGN(OverlayStrategyUnderlayCast);
};
diff --git a/chromium/components/viz/service/display/overlay_unittest.cc b/chromium/components/viz/service/display/overlay_unittest.cc
index 5cb75117474..119841fc713 100644
--- a/chromium/components/viz/service/display/overlay_unittest.cc
+++ b/chromium/components/viz/service/display/overlay_unittest.cc
@@ -9,7 +9,6 @@
#include "base/containers/flat_map.h"
#include "base/test/scoped_feature_list.h"
-#include "cc/resources/display_resource_provider.h"
#include "cc/resources/layer_tree_resource_provider.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_resource_provider.h"
@@ -22,6 +21,7 @@
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "components/viz/service/display/ca_layer_overlay.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_client.h"
@@ -72,7 +72,9 @@ class FullscreenOverlayValidator : public OverlayCandidateValidator {
}
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return false; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {}
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
+ surfaces->back().overlay_handled = true;
+ }
};
class SingleOverlayValidator : public OverlayCandidateValidator {
@@ -86,13 +88,13 @@ class SingleOverlayValidator : public OverlayCandidateValidator {
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return false; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {
// We may have 1 or 2 surfaces depending on whether this ran through the
// full renderer and picked up the output surface, or not.
ASSERT_LE(1U, surfaces->size());
ASSERT_GE(2U, surfaces->size());
- cc::OverlayCandidate& candidate = surfaces->back();
+ OverlayCandidate& candidate = surfaces->back();
EXPECT_TRUE(!candidate.use_output_surface_for_resource);
for (const auto& r : expected_rects_) {
const float kAbsoluteError = 0.01f;
@@ -129,7 +131,7 @@ class CALayerValidator : public OverlayCandidateValidator {
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
bool AllowCALayerOverlays() override { return true; }
bool AllowDCLayerOverlays() override { return false; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {}
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
class DCLayerValidator : public OverlayCandidateValidator {
@@ -137,7 +139,7 @@ class DCLayerValidator : public OverlayCandidateValidator {
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {}
bool AllowCALayerOverlays() override { return false; }
bool AllowDCLayerOverlays() override { return true; }
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override {}
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override {}
};
class SingleOnTopOverlayValidator : public SingleOverlayValidator {
@@ -154,6 +156,14 @@ class UnderlayOverlayValidator : public SingleOverlayValidator {
}
};
+class TransparentUnderlayOverlayValidator : public SingleOverlayValidator {
+ public:
+ void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
+ strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(
+ this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
+ }
+};
+
class UnderlayCastOverlayValidator : public SingleOverlayValidator {
public:
void GetStrategies(OverlayProcessor::StrategyList* strategies) override {
@@ -211,7 +221,7 @@ class OverlayOutputSurface : public OutputSurface {
gfx::BufferFormat GetOverlayBufferFormat() const override {
return gfx::BufferFormat::RGBX_8888;
}
- bool SurfaceIsSuspendForRecycle() const override { return false; }
+ unsigned UpdateGpuFence() override { return 0; }
void set_is_displayed_as_overlay_plane(bool value) {
is_displayed_as_overlay_plane_ = value;
@@ -272,8 +282,9 @@ static ResourceId CreateResourceInLayerTree(
}
ResourceId CreateResource(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const gfx::Size& size,
bool is_overlay_candidate) {
ResourceId resource_id = CreateResourceInLayerTree(
@@ -283,14 +294,15 @@ ResourceId CreateResource(
base::BindRepeating([](const std::vector<ReturnedResource>&) {}));
// Transfer resource to the parent.
- cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ std::vector<ResourceId> resource_ids_to_transfer;
resource_ids_to_transfer.push_back(resource_id);
std::vector<TransferableResource> list;
- child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list);
+ child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, &list,
+ child_context_provider);
parent_resource_provider->ReceiveFromChild(child_id, list);
// In DisplayResourceProvider's namespace, use the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
parent_resource_provider->GetChildToParentMap(child_id);
return resource_map[list[0].id];
}
@@ -307,8 +319,9 @@ SolidColorDrawQuad* CreateSolidColorQuadAt(
}
TextureDrawQuad* CreateCandidateQuadAt(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
@@ -319,9 +332,9 @@ TextureDrawQuad* CreateCandidateQuadAt(
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
- ResourceId resource_id =
- CreateResource(parent_resource_provider, child_resource_provider,
- resource_size_in_pixels, is_overlay_candidate);
+ ResourceId resource_id = CreateResource(
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
@@ -334,8 +347,9 @@ TextureDrawQuad* CreateCandidateQuadAt(
}
TextureDrawQuad* CreateTransparentCandidateQuadAt(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
@@ -346,9 +360,9 @@ TextureDrawQuad* CreateTransparentCandidateQuadAt(
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
- ResourceId resource_id =
- CreateResource(parent_resource_provider, child_resource_provider,
- resource_size_in_pixels, is_overlay_candidate);
+ ResourceId resource_id = CreateResource(
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
@@ -361,8 +375,9 @@ TextureDrawQuad* CreateTransparentCandidateQuadAt(
}
StreamVideoDrawQuad* CreateCandidateVideoQuadAt(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect,
@@ -370,9 +385,9 @@ StreamVideoDrawQuad* CreateCandidateVideoQuadAt(
bool needs_blending = false;
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
- ResourceId resource_id =
- CreateResource(parent_resource_provider, child_resource_provider,
- resource_size_in_pixels, is_overlay_candidate);
+ ResourceId resource_id = CreateResource(
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad =
render_pass->CreateAndAppendDrawQuad<StreamVideoDrawQuad>();
@@ -383,29 +398,32 @@ StreamVideoDrawQuad* CreateCandidateVideoQuadAt(
}
TextureDrawQuad* CreateFullscreenCandidateQuad(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass) {
- return CreateCandidateQuadAt(parent_resource_provider,
- child_resource_provider, shared_quad_state,
- render_pass, render_pass->output_rect);
+ return CreateCandidateQuadAt(
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ shared_quad_state, render_pass, render_pass->output_rect);
}
StreamVideoDrawQuad* CreateFullscreenCandidateVideoQuad(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Transform& transform) {
return CreateCandidateVideoQuadAt(
- parent_resource_provider, child_resource_provider, shared_quad_state,
- render_pass, render_pass->output_rect, transform);
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ shared_quad_state, render_pass, render_pass->output_rect, transform);
}
YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad(
- cc::DisplayResourceProvider* parent_resource_provider,
+ DisplayResourceProvider* parent_resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass) {
bool needs_blending = false;
@@ -413,9 +431,9 @@ YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad(
gfx::Rect rect = render_pass->output_rect;
gfx::Size resource_size_in_pixels = rect.size();
bool is_overlay_candidate = true;
- ResourceId resource_id =
- CreateResource(parent_resource_provider, child_resource_provider,
- resource_size_in_pixels, is_overlay_candidate);
+ ResourceId resource_id = CreateResource(
+ parent_resource_provider, child_resource_provider, child_context_provider,
+ resource_size_in_pixels, is_overlay_candidate);
auto* overlay_quad = render_pass->CreateAndAppendDrawQuad<YUVVideoDrawQuad>();
overlay_quad->SetNew(shared_quad_state, rect, rect, needs_blending,
@@ -427,7 +445,7 @@ YUVVideoDrawQuad* CreateFullscreenCandidateYUVVideoQuad(
return overlay_quad;
}
-void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider,
+void CreateOpaqueQuadAt(DisplayResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect) {
@@ -435,7 +453,7 @@ void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider,
color_quad->SetNew(shared_quad_state, rect, rect, SK_ColorBLACK, false);
}
-void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider,
+void CreateOpaqueQuadAt(DisplayResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass,
const gfx::Rect& rect,
@@ -445,7 +463,7 @@ void CreateOpaqueQuadAt(cc::ResourceProvider* resource_provider,
color_quad->SetNew(shared_quad_state, rect, rect, color, false);
}
-void CreateFullscreenOpaqueQuad(cc::ResourceProvider* resource_provider,
+void CreateFullscreenOpaqueQuad(DisplayResourceProvider* resource_provider,
const SharedQuadState* shared_quad_state,
RenderPass* render_pass) {
CreateOpaqueQuadAt(resource_provider, shared_quad_state, render_pass,
@@ -514,7 +532,7 @@ class OverlayTest : public testing::Test {
child_provider_->BindToCurrentThread();
child_resource_provider_ =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_provider_.get(), shared_bitmap_manager_.get());
+ child_provider_.get());
overlay_processor_ =
std::make_unique<OverlayProcessor>(output_surface_.get());
@@ -525,7 +543,7 @@ class OverlayTest : public testing::Test {
std::unique_ptr<OutputSurfaceType> output_surface_;
cc::FakeOutputSurfaceClient client_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
scoped_refptr<TestContextProvider> child_provider_;
std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_;
std::unique_ptr<OverlayProcessor> overlay_processor_;
@@ -536,6 +554,8 @@ class OverlayTest : public testing::Test {
using FullscreenOverlayTest = OverlayTest<FullscreenOverlayValidator>;
using SingleOverlayOnTopTest = OverlayTest<SingleOnTopOverlayValidator>;
using UnderlayTest = OverlayTest<UnderlayOverlayValidator>;
+using TransparentUnderlayTest =
+ OverlayTest<TransparentUnderlayOverlayValidator>;
using UnderlayCastTest = OverlayTest<UnderlayCastOverlayValidator>;
using CALayerOverlayTest = OverlayTest<CALayerValidator>;
@@ -557,7 +577,7 @@ TEST(OverlayTest, OverlaysProcessorHasStrategy) {
output_surface.SetOverlayCandidateValidator(new SingleOverlayValidator);
auto shared_bitmap_manager = std::make_unique<TestSharedBitmapManager>();
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider =
+ std::unique_ptr<DisplayResourceProvider> resource_provider =
cc::FakeResourceProvider::CreateDisplayResourceProvider(
provider.get(), shared_bitmap_manager.get());
@@ -572,7 +592,7 @@ TEST_F(FullscreenOverlayTest, SuccessfulOverlay) {
gfx::Rect output_rect = pass->output_rect;
TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
unsigned original_resource_id = original_quad->resource_id();
// Add something behind it.
@@ -580,7 +600,7 @@ TEST_F(FullscreenOverlayTest, SuccessfulOverlay) {
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -608,14 +628,14 @@ TEST_F(FullscreenOverlayTest, FailOnOutputColorMatrix) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -638,10 +658,11 @@ TEST_F(FullscreenOverlayTest, AlphaFail) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateTransparentCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), pass.get()->output_rect);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ pass.get()->output_rect);
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -659,15 +680,15 @@ TEST_F(FullscreenOverlayTest, AlphaFail) {
EXPECT_EQ(0U, candidate_list.size());
}
-TEST_F(FullscreenOverlayTest, ResourceSizeInPixelsFail) {
+TEST_F(FullscreenOverlayTest, SuccessfulResourceSizeInPixels) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
original_quad->set_resource_size_in_pixels(gfx::Size(64, 64));
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -678,10 +699,10 @@ TEST_F(FullscreenOverlayTest, ResourceSizeInPixelsFail) {
resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
render_pass_filters, render_pass_background_filters, &candidate_list,
nullptr, nullptr, &damage_rect_, &content_bounds_);
- ASSERT_EQ(0U, candidate_list.size());
+ ASSERT_EQ(1U, candidate_list.size());
- // Check that the quad is not gone.
- EXPECT_EQ(1U, main_pass->quad_list.size());
+ // Check that the quad is gone.
+ EXPECT_EQ(0U, main_pass->quad_list.size());
}
TEST_F(FullscreenOverlayTest, OnTopFail) {
@@ -694,10 +715,10 @@ TEST_F(FullscreenOverlayTest, OnTopFail) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -718,12 +739,13 @@ TEST_F(FullscreenOverlayTest, NotCoveringFullscreenFail) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
gfx::Rect inset_rect = pass->output_rect;
inset_rect.Inset(0, 1, 0, 1);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), inset_rect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ inset_rect);
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -752,10 +774,10 @@ TEST_F(FullscreenOverlayTest, RemoveFullscreenQuadFromQuadList) {
shared_state->opacity = 1.f;
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -777,7 +799,7 @@ TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* original_quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
unsigned original_resource_id = original_quad->resource_id();
// Add something behind it.
@@ -787,7 +809,7 @@ TEST_F(SingleOverlayOnTopTest, SuccessfulOverlay) {
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -815,9 +837,10 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
// Add a small quad.
const auto kSmallCandidateRect = gfx::Rect(0, 0, 16, 16);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kSmallCandidateRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kSmallCandidateRect);
output_surface_->GetOverlayCandidateValidator()->AddExpectedRect(
gfx::RectF(kSmallCandidateRect));
@@ -825,7 +848,8 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
const auto kBigCandidateRect = gfx::Rect(20, 20, 32, 32);
TextureDrawQuad* quad_big = CreateCandidateQuadAt(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kBigCandidateRect);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kBigCandidateRect);
output_surface_->GetOverlayCandidateValidator()->AddExpectedRect(
gfx::RectF(kBigCandidateRect));
@@ -836,7 +860,7 @@ TEST_F(SingleOverlayOnTopTest, PrioritizeBiggerOne) {
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -860,7 +884,7 @@ TEST_F(SingleOverlayOnTopTest, DamageRect) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
// Add something behind it.
@@ -870,10 +894,10 @@ TEST_F(SingleOverlayOnTopTest, DamageRect) {
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
// Primary plane.
- cc::OverlayCandidate output_surface_plane;
+ OverlayCandidate output_surface_plane;
output_surface_plane.display_rect = gfx::RectF(kOverlayRect);
output_surface_plane.use_output_surface_for_resource = true;
output_surface_plane.overlay_handled = true;
@@ -903,7 +927,7 @@ TEST_F(SingleOverlayOnTopTest, NoCandidates) {
RenderPassList original_pass_list;
RenderPass::CopyAll(pass_list, &original_pass_list);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
@@ -924,7 +948,7 @@ TEST_F(SingleOverlayOnTopTest, OccludedCandidates) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -932,7 +956,7 @@ TEST_F(SingleOverlayOnTopTest, OccludedCandidates) {
RenderPassList original_pass_list;
RenderPass::CopyAll(pass_list, &original_pass_list);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
overlay_processor_->ProcessForOverlays(
@@ -949,7 +973,7 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
// Add something behind it.
CreateFullscreenOpaqueQuad(resource_provider_.get(),
@@ -958,7 +982,7 @@ TEST_F(SingleOverlayOnTopTest, MultipleRenderPasses) {
pass->shared_quad_state_list.back(), pass.get());
// Check for potential candidates.
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -974,10 +998,10 @@ TEST_F(SingleOverlayOnTopTest, AcceptBlending) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
quad->needs_blending = true;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = quad->rect;
@@ -998,10 +1022,10 @@ TEST_F(SingleOverlayOnTopTest, RejectBackgroundColor) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
TextureDrawQuad* quad = CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
quad->background_color = SK_ColorBLACK;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1017,10 +1041,10 @@ TEST_F(SingleOverlayOnTopTest, RejectBlendMode) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->blend_mode = SkBlendMode::kScreen;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1036,10 +1060,10 @@ TEST_F(SingleOverlayOnTopTest, RejectOpacity) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0.5f;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1055,11 +1079,11 @@ TEST_F(SingleOverlayOnTopTest, RejectNonAxisAlignedTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutXAxis(45.f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1075,11 +1099,11 @@ TEST_F(SingleOverlayOnTopTest, AllowClipped) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = kOverlayClipRect;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1097,11 +1121,11 @@ TEST_F(UnderlayTest, AllowVerticalFlip) {
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f,
-1.0f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1121,12 +1145,12 @@ TEST_F(UnderlayTest, AllowHorizontalFlip) {
rect.Offset(-rect.width(), 0);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(-1.0f,
2.0f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1145,11 +1169,11 @@ TEST_F(SingleOverlayOnTopTest, AllowPositiveScaleTransform) {
rect.set_width(rect.width() / 2);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(2.0f,
1.0f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1166,12 +1190,12 @@ TEST_F(SingleOverlayOnTopTest, AcceptMirrorYTransform) {
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()->quad_to_target_transform.Scale(1.f,
-1.f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1188,12 +1212,12 @@ TEST_F(UnderlayTest, Allow90DegreeRotation) {
rect.Offset(0, -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(90.f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1211,12 +1235,12 @@ TEST_F(UnderlayTest, Allow180DegreeRotation) {
rect.Offset(-rect.width(), -rect.height());
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(180.f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1234,12 +1258,12 @@ TEST_F(UnderlayTest, Allow270DegreeRotation) {
rect.Offset(-rect.width(), 0);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), rect);
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(270.f);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1252,6 +1276,84 @@ TEST_F(UnderlayTest, Allow270DegreeRotation) {
EXPECT_EQ(gfx::OVERLAY_TRANSFORM_ROTATE_270, candidate_list.back().transform);
}
+TEST_F(UnderlayTest, AllowsOpaqueCandidates) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
+ ->needs_blending = false;
+ pass->shared_quad_state_list.front()->opacity = 1.0;
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessor::FilterOperationsMap render_pass_filters;
+ OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+ RenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_background_filters, &candidate_list,
+ nullptr, nullptr, &damage_rect_, &content_bounds_);
+ ASSERT_EQ(1U, candidate_list.size());
+}
+
+TEST_F(UnderlayTest, DisallowsTransparentCandidates) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
+ ->needs_blending = true;
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessor::FilterOperationsMap render_pass_filters;
+ OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+ RenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_background_filters, &candidate_list,
+ nullptr, nullptr, &damage_rect_, &content_bounds_);
+ ASSERT_EQ(0U, candidate_list.size());
+}
+
+TEST_F(TransparentUnderlayTest, AllowsOpaqueCandidates) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
+ ->needs_blending = false;
+ pass->shared_quad_state_list.front()->opacity = 1.0;
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessor::FilterOperationsMap render_pass_filters;
+ OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+ RenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_background_filters, &candidate_list,
+ nullptr, nullptr, &damage_rect_, &content_bounds_);
+ ASSERT_EQ(1U, candidate_list.size());
+}
+
+TEST_F(TransparentUnderlayTest, AllowsTransparentCandidates) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+ CreateFullscreenCandidateQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get())
+ ->needs_blending = true;
+
+ OverlayCandidateList candidate_list;
+ OverlayProcessor::FilterOperationsMap render_pass_filters;
+ OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+ RenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_background_filters, &candidate_list,
+ nullptr, nullptr, &damage_rect_, &content_bounds_);
+ ASSERT_EQ(1U, candidate_list.size());
+}
+
TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
output_surface_->GetOverlayCandidateValidator()->AddExpectedRect(
gfx::RectF(kOverlayBottomRightRect));
@@ -1260,11 +1362,12 @@ TEST_F(SingleOverlayOnTopTest, AllowNotTopIfNotOccluded) {
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1288,10 +1391,10 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentOnTop) {
shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(), shared_state,
- pass.get(), kOverlayBottomRightRect);
+ child_resource_provider_.get(), child_provider_.get(),
+ shared_state, pass.get(), kOverlayBottomRightRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1311,11 +1414,12 @@ TEST_F(SingleOverlayOnTopTest, AllowTransparentColorOnTop) {
CreateSolidColorQuadAt(pass->shared_quad_state_list.back(),
SK_ColorTRANSPARENT, pass.get(),
kOverlayBottomRightRect);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1336,10 +1440,10 @@ TEST_F(SingleOverlayOnTopTest, RejectOpaqueColorOnTop) {
shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(), shared_state,
- pass.get(), kOverlayBottomRightRect);
+ child_resource_provider_.get(), child_provider_.get(),
+ shared_state, pass.get(), kOverlayBottomRightRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1358,10 +1462,10 @@ TEST_F(SingleOverlayOnTopTest, RejectTransparentColorOnTopWithoutBlending) {
kOverlayBottomRightRect)
->needs_blending = false;
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(), shared_state,
- pass.get(), kOverlayBottomRightRect);
+ child_resource_provider_.get(), child_provider_.get(),
+ shared_state, pass.get(), kOverlayBottomRightRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1377,9 +1481,10 @@ TEST_F(SingleOverlayOnTopTest, RejectVideoSwapTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kSwapTransform);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kSwapTransform);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1395,9 +1500,10 @@ TEST_F(UnderlayTest, AllowVideoXMirrorTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kXMirrorTransform);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kXMirrorTransform);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1413,9 +1519,10 @@ TEST_F(UnderlayTest, AllowVideoBothMirrorTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kBothMirrorTransform);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kBothMirrorTransform);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1431,9 +1538,10 @@ TEST_F(UnderlayTest, AllowVideoNormalTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kNormalTransform);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kNormalTransform);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1449,9 +1557,10 @@ TEST_F(SingleOverlayOnTopTest, AllowVideoYMirrorTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kYMirrorTransform);
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get(),
+ kYMirrorTransform);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1470,11 +1579,12 @@ TEST_F(UnderlayTest, OverlayLayerUnderMainLayer) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1499,12 +1609,12 @@ TEST_F(UnderlayTest, AllowOnTop) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->CreateAndAppendSharedQuadState()->opacity = 0.5f;
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1529,11 +1639,11 @@ TEST_F(UnderlayTest, InitialUnderlayDamageNotSubtracted) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1553,7 +1663,7 @@ TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
@@ -1561,7 +1671,7 @@ TEST_F(UnderlayTest, DamageSubtractedForConsecutiveIdenticalUnderlays) {
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1587,13 +1697,14 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonIdenticalConsecutiveUnderlays) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), overlay_rects[i]);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ overlay_rects[i]);
damage_rect_ = overlay_rects[i];
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1618,7 +1729,8 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) {
if (has_fullscreen_candidate[i]) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(),
+ pass.get());
}
damage_rect_ = kOverlayRect;
@@ -1627,7 +1739,7 @@ TEST_F(UnderlayTest, DamageNotSubtractedForNonConsecutiveIdenticalUnderlays) {
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1649,11 +1761,11 @@ TEST_F(UnderlayTest, DamageNotSubtractedWhenQuadsAboveOverlap) {
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
damage_rect_ = kOverlayRect;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1678,13 +1790,13 @@ TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
CreateCandidateQuadAt(resource_provider_.get(),
- child_resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
damage_rect_ = kOverlayBottomRightRect;
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1698,6 +1810,37 @@ TEST_F(UnderlayTest, DamageSubtractedWhenQuadsAboveDontOverlap) {
EXPECT_TRUE(damage_rect_.IsEmpty());
}
+TEST_F(UnderlayTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+ gfx::Rect output_rect = pass->output_rect;
+ CreateOpaqueQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ output_rect, SK_ColorWHITE);
+
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayRect);
+
+ OverlayCandidateList candidate_list;
+ OverlayCandidate candidate;
+ candidate.use_output_surface_for_resource = true;
+ candidate.is_opaque = true;
+ candidate_list.push_back(candidate);
+
+ OverlayProcessor::FilterOperationsMap render_pass_filters;
+ OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+ RenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_background_filters, &candidate_list,
+ nullptr, nullptr, &damage_rect_, &content_bounds_);
+
+ EXPECT_EQ(2U, candidate_list.size());
+ ASSERT_EQ(false, candidate_list[0].is_opaque);
+}
+
TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
@@ -1705,7 +1848,7 @@ TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1719,11 +1862,12 @@ TEST_F(UnderlayCastTest, NoOverlayContentBounds) {
TEST_F(UnderlayCastTest, FullScreenOverlayContentBounds) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1745,9 +1889,10 @@ TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) {
const gfx::Rect kTopRight(128, 0, 128, 128);
std::unique_ptr<RenderPass> pass = CreateRenderPass();
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(), kLeftSide,
SK_ColorBLACK);
@@ -1755,7 +1900,7 @@ TEST_F(UnderlayCastTest, BlackOutsideOverlayContentBounds) {
pass->shared_quad_state_list.back(), pass.get(), kTopRight,
SK_ColorBLACK);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1774,11 +1919,12 @@ TEST_F(UnderlayCastTest, OverlayOccludedContentBounds) {
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayTopLeftRect);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1800,11 +1946,12 @@ TEST_F(UnderlayCastTest, OverlayOccludedUnionContentBounds) {
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
kOverlayBottomRightRect);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayRect);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1829,14 +1976,15 @@ TEST_F(UnderlayCastTest, RoundOverlayContentBounds) {
transform.Translate(0.5f, 0.5f);
std::unique_ptr<RenderPass> pass = CreateRenderPassWithTransform(transform);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), overlay_rect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ overlay_rect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 0, 10, 10), SK_ColorWHITE);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1862,14 +2010,15 @@ TEST_F(UnderlayCastTest, RoundContentBounds) {
transform.Translate(0.5f, 0.5f);
std::unique_ptr<RenderPass> pass = CreateRenderPassWithTransform(transform);
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), overlay_rect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ overlay_rect);
CreateOpaqueQuadAt(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get(),
gfx::Rect(0, 0, 255, 255), SK_ColorWHITE);
- cc::OverlayCandidateList candidate_list;
+ OverlayCandidateList candidate_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1883,10 +2032,41 @@ TEST_F(UnderlayCastTest, RoundContentBounds) {
EXPECT_EQ(kOverlayRect, content_bounds_[0]);
}
-cc::OverlayCandidateList BackbufferOverlayList(
- const RenderPass* root_render_pass) {
- cc::OverlayCandidateList list;
- cc::OverlayCandidate output_surface_plane;
+TEST_F(UnderlayCastTest, PrimaryPlaneOverlayIsTransparentWithUnderlay) {
+ std::unique_ptr<RenderPass> pass = CreateRenderPass();
+ gfx::Rect output_rect = pass->output_rect;
+ CreateOpaqueQuadAt(resource_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ output_rect, SK_ColorWHITE);
+
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayRect);
+
+ OverlayCandidateList candidate_list;
+ OverlayCandidate candidate;
+ candidate.use_output_surface_for_resource = true;
+ candidate.is_opaque = true;
+ candidate_list.push_back(candidate);
+
+ OverlayProcessor::FilterOperationsMap render_pass_filters;
+ OverlayProcessor::FilterOperationsMap render_pass_background_filters;
+ RenderPassList pass_list;
+ pass_list.push_back(std::move(pass));
+ overlay_processor_->ProcessForOverlays(
+ resource_provider_.get(), &pass_list, GetIdentityColorMatrix(),
+ render_pass_filters, render_pass_background_filters, &candidate_list,
+ nullptr, nullptr, &damage_rect_, &content_bounds_);
+
+ ASSERT_EQ(false, candidate_list[0].is_opaque);
+ EXPECT_EQ(1U, content_bounds_.size());
+ EXPECT_EQ(output_rect, content_bounds_[0]);
+}
+
+OverlayCandidateList BackbufferOverlayList(const RenderPass* root_render_pass) {
+ OverlayCandidateList list;
+ OverlayCandidate output_surface_plane;
output_surface_plane.display_rect = gfx::RectF(root_render_pass->output_rect);
output_surface_plane.use_output_surface_for_resource = true;
output_surface_plane.overlay_handled = true;
@@ -1898,13 +2078,13 @@ TEST_F(CALayerOverlayTest, AllowNonAxisAlignedTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
- cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
+ OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1923,12 +2103,12 @@ TEST_F(CALayerOverlayTest, ThreeDTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutXAxis(45.f);
CALayerOverlayList ca_layer_list;
- cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
+ OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1950,13 +2130,13 @@ TEST_F(CALayerOverlayTest, AllowContainingClip) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = kOverlayRect;
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
- cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
+ OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -1975,13 +2155,13 @@ TEST_F(CALayerOverlayTest, NontrivialClip) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->is_clipped = true;
pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(64, 64, 128, 128);
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
- cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
+ OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -2003,12 +2183,12 @@ TEST_F(CALayerOverlayTest, SkipTransparent) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0;
gfx::Rect damage_rect;
CALayerOverlayList ca_layer_list;
- cc::OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
+ OverlayCandidateList overlay_list(BackbufferOverlayList(pass.get()));
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -2043,13 +2223,13 @@ TEST_P(DCLayerOverlayTest, AllowNonAxisAlignedTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -2074,14 +2254,14 @@ TEST_P(DCLayerOverlayTest, AllowRequiredNonAxisAlignedTransform) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
YUVVideoDrawQuad* yuv_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
yuv_quad->require_overlay = true;
pass->shared_quad_state_list.back()
->quad_to_target_transform.RotateAboutZAxis(45.f);
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -2109,11 +2289,11 @@ TEST_P(DCLayerOverlayTest, Occluded) {
gfx::Rect(0, 2, 100, 100), SK_ColorWHITE);
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -2138,11 +2318,11 @@ TEST_P(DCLayerOverlayTest, Occluded) {
gfx::Rect(2, 2, 100, 100), SK_ColorWHITE);
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -2168,11 +2348,11 @@ TEST_P(DCLayerOverlayTest, DamageRect) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -2204,7 +2384,8 @@ TEST_P(DCLayerOverlayTest, MultiplePassDamageRect) {
pass1->id = child_pass_id;
YUVVideoDrawQuad* yuv_quad = CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass1->shared_quad_state_list.back(), pass1.get());
+ child_provider_.get(), pass1->shared_quad_state_list.back(),
+ pass1.get());
yuv_quad->require_overlay = true;
pass1->damage_rect = gfx::Rect();
pass1->transform_to_root_target.Translate(0, 100);
@@ -2226,7 +2407,7 @@ TEST_P(DCLayerOverlayTest, MultiplePassDamageRect) {
gfx::Rect damage_rect;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect();
@@ -2281,15 +2462,15 @@ TEST_P(DCLayerOverlayTest, ClipRect) {
pass->shared_quad_state_list.back()->clip_rect = gfx::Rect(0, 3, 100, 100);
SharedQuadState* shared_state = pass->CreateAndAppendSharedQuadState();
shared_state->opacity = 1.f;
- CreateFullscreenCandidateYUVVideoQuad(resource_provider_.get(),
- child_resource_provider_.get(),
- shared_state, pass.get());
+ CreateFullscreenCandidateYUVVideoQuad(
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_provider_.get(), shared_state, pass.get());
shared_state->is_clipped = true;
// Clipped rect shouldn't be overlapped by clipped opaque quad rect.
shared_state->clip_rect = gfx::Rect(0, 0, 100, 3);
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
RenderPassList pass_list;
@@ -2322,11 +2503,11 @@ TEST_P(DCLayerOverlayTest, TransparentOnTop) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
CreateFullscreenCandidateYUVVideoQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
pass->shared_quad_state_list.back()->opacity = 0.5f;
DCLayerOverlayList dc_layer_list;
- cc::OverlayCandidateList overlay_list;
+ OverlayCandidateList overlay_list;
OverlayProcessor::FilterOperationsMap render_pass_filters;
OverlayProcessor::FilterOperationsMap render_pass_background_filters;
damage_rect_ = gfx::Rect(1, 1, 10, 10);
@@ -2350,7 +2531,7 @@ class OverlayInfoRendererGL : public GLRenderer {
public:
OverlayInfoRendererGL(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
+ DisplayResourceProvider* resource_provider)
: GLRenderer(settings, output_surface, resource_provider, nullptr),
expect_overlays_(false) {}
@@ -2385,12 +2566,14 @@ class OverlayInfoRendererGL : public GLRenderer {
class MockOverlayScheduler {
public:
- MOCK_METHOD5(Schedule,
+ MOCK_METHOD7(Schedule,
void(int plane_z_order,
gfx::OverlayTransform plane_transform,
unsigned overlay_texture_id,
const gfx::Rect& display_bounds,
- const gfx::RectF& uv_rect));
+ const gfx::RectF& uv_rect,
+ bool enable_blend,
+ unsigned gpu_fence_id));
};
class GLRendererWithOverlaysTest : public testing::Test {
@@ -2413,7 +2596,7 @@ class GLRendererWithOverlaysTest : public testing::Test {
child_provider_->BindToCurrentThread();
child_resource_provider_ =
cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- child_provider_.get(), nullptr);
+ child_provider_.get());
}
void Init(bool use_validator) {
@@ -2430,16 +2613,16 @@ class GLRendererWithOverlaysTest : public testing::Test {
renderer_->DrawFrame(pass_list, 1.f, viewport_size);
}
void SwapBuffers() {
- renderer_->SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false);
renderer_->SwapBuffersComplete();
}
void SwapBuffersWithoutComplete() {
- renderer_->SwapBuffers(std::vector<ui::LatencyInfo>());
+ renderer_->SwapBuffers(std::vector<ui::LatencyInfo>(), false);
}
void SwapBuffersComplete() { renderer_->SwapBuffersComplete(); }
void ReturnResourceInUseQuery(ResourceId id) {
- cc::DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
- id);
+ DisplayResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
+ id);
gpu::TextureInUseResponse response;
response.texture = lock.texture_id();
response.in_use = false;
@@ -2451,7 +2634,7 @@ class GLRendererWithOverlaysTest : public testing::Test {
RendererSettings settings_;
cc::FakeOutputSurfaceClient output_surface_client_;
std::unique_ptr<OutputSurfaceType> output_surface_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<OverlayInfoRendererGL> renderer_;
scoped_refptr<TestContextProvider> provider_;
scoped_refptr<TestContextProvider> child_provider_;
@@ -2468,9 +2651,10 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) {
std::unique_ptr<RenderPass> pass = CreateRenderPass();
- CreateCandidateQuadAt(
- resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get(), kOverlayBottomRightRect);
+ CreateCandidateQuadAt(resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get(),
+ pass->shared_quad_state_list.back(), pass.get(),
+ kOverlayBottomRightRect);
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
@@ -2484,11 +2668,12 @@ TEST_F(GLRendererWithOverlaysTest, OverlayQuadNotDrawn) {
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(2);
EXPECT_CALL(scheduler_,
Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _,
- gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1)))
+ gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1), _, _))
.Times(1);
- EXPECT_CALL(scheduler_, Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _,
- kOverlayBottomRightRect,
- BoundingRect(kUVTopLeft, kUVBottomRight)))
+ EXPECT_CALL(
+ scheduler_,
+ Schedule(1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayBottomRightRect,
+ BoundingRect(kUVTopLeft, kUVBottomRight), _, _))
.Times(1);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(1U, output_surface_->bind_framebuffer_count());
@@ -2513,7 +2698,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -2523,11 +2708,11 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadInUnderlay) {
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
EXPECT_CALL(scheduler_,
Schedule(0, gfx::OVERLAY_TRANSFORM_NONE, _,
- gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1)))
+ gfx::Rect(kDisplaySize), gfx::RectF(0, 0, 1, 1), _, _))
.Times(1);
EXPECT_CALL(scheduler_,
Schedule(-1, gfx::OVERLAY_TRANSFORM_NONE, _, kOverlayRect,
- BoundingRect(kUVTopLeft, kUVBottomRight)))
+ BoundingRect(kUVTopLeft, kUVBottomRight), _, _))
.Times(1);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(1U, output_surface_->bind_framebuffer_count());
@@ -2547,7 +2732,7 @@ TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
@@ -2560,7 +2745,7 @@ TEST_F(GLRendererWithOverlaysTest, NoValidatorNoOverlay) {
// Should not see the primary surface's overlay.
output_surface_->set_is_displayed_as_overlay_plane(false);
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(3);
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(1U, output_surface_->bind_framebuffer_count());
SwapBuffers();
@@ -2580,7 +2765,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
@@ -2591,7 +2776,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenPartialSwapEnabled) {
output_surface_->set_is_displayed_as_overlay_plane(true);
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0);
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
SwapBuffers();
@@ -2610,7 +2795,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) {
CreateFullscreenCandidateQuad(
resource_provider_.get(), child_resource_provider_.get(),
- pass->shared_quad_state_list.back(), pass.get());
+ child_provider_.get(), pass->shared_quad_state_list.back(), pass.get());
CreateFullscreenOpaqueQuad(resource_provider_.get(),
pass->shared_quad_state_list.back(), pass.get());
@@ -2622,7 +2807,7 @@ TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawnWhenEmptySwapAllowed) {
output_surface_->set_is_displayed_as_overlay_plane(true);
EXPECT_CALL(*renderer_, DoDrawQuad(_, _)).Times(0);
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
DrawFrame(&pass_list, kDisplaySize);
EXPECT_EQ(0U, output_surface_->bind_framebuffer_count());
SwapBuffers();
@@ -2643,10 +2828,10 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
child_resource_provider_.get(), gfx::Size(32, 32), true);
// Return the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
- SendResourceAndGetChildToParentMap({resource1, resource2, resource3},
- resource_provider_.get(),
- child_resource_provider_.get());
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ SendResourceAndGetChildToParentMap(
+ {resource1, resource2, resource3}, resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get());
ResourceId mapped_resource1 = resource_map[resource1];
ResourceId mapped_resource2 = resource_map[resource2];
@@ -2660,7 +2845,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
frame1.render_passes_in_draw_order = &pass_list;
frame1.overlay_list.resize(2);
frame1.overlay_list.front().use_output_surface_for_resource = true;
- cc::OverlayCandidate& overlay1 = frame1.overlay_list.back();
+ OverlayCandidate& overlay1 = frame1.overlay_list.back();
overlay1.resource_id = mapped_resource1;
overlay1.plane_z_order = 1;
@@ -2668,7 +2853,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
frame2.render_passes_in_draw_order = &pass_list;
frame2.overlay_list.resize(2);
frame2.overlay_list.front().use_output_surface_for_resource = true;
- cc::OverlayCandidate& overlay2 = frame2.overlay_list.back();
+ OverlayCandidate& overlay2 = frame2.overlay_list.back();
overlay2.resource_id = mapped_resource2;
overlay2.plane_z_order = 1;
@@ -2676,11 +2861,11 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
frame3.render_passes_in_draw_order = &pass_list;
frame3.overlay_list.resize(2);
frame3.overlay_list.front().use_output_surface_for_resource = true;
- cc::OverlayCandidate& overlay3 = frame3.overlay_list.back();
+ OverlayCandidate& overlay3 = frame3.overlay_list.back();
overlay3.resource_id = mapped_resource3;
overlay3.plane_z_order = 1;
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2704,7 +2889,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame2);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2720,7 +2905,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
EXPECT_TRUE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame3);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2738,7 +2923,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_TRUE(resource_provider_->InUse(mapped_resource3));
// No overlays, release the resource.
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0);
DirectRenderer::DrawingFrame frame_no_overlays;
frame_no_overlays.render_passes_in_draw_order = &pass_list;
renderer_->set_expect_overlays(false);
@@ -2761,7 +2946,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
// Use the same buffer twice.
renderer_->set_expect_overlays(true);
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2779,7 +2964,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2797,7 +2982,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
EXPECT_FALSE(resource_provider_->InUse(mapped_resource2));
EXPECT_FALSE(resource_provider_->InUse(mapped_resource3));
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(0);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(0);
renderer_->set_expect_overlays(false);
renderer_->SetCurrentFrame(frame_no_overlays);
renderer_->BeginDrawingFrame();
@@ -2832,10 +3017,10 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
child_resource_provider_.get(), gfx::Size(32, 32), true);
// Return the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
- SendResourceAndGetChildToParentMap({resource1, resource2, resource3},
- resource_provider_.get(),
- child_resource_provider_.get());
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ SendResourceAndGetChildToParentMap(
+ {resource1, resource2, resource3}, resource_provider_.get(),
+ child_resource_provider_.get(), child_provider_.get());
ResourceId mapped_resource1 = resource_map[resource1];
ResourceId mapped_resource2 = resource_map[resource2];
ResourceId mapped_resource3 = resource_map[resource3];
@@ -2848,7 +3033,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
frame1.render_passes_in_draw_order = &pass_list;
frame1.overlay_list.resize(2);
frame1.overlay_list.front().use_output_surface_for_resource = true;
- cc::OverlayCandidate& overlay1 = frame1.overlay_list.back();
+ OverlayCandidate& overlay1 = frame1.overlay_list.back();
overlay1.resource_id = mapped_resource1;
overlay1.plane_z_order = 1;
@@ -2856,7 +3041,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
frame2.render_passes_in_draw_order = &pass_list;
frame2.overlay_list.resize(2);
frame2.overlay_list.front().use_output_surface_for_resource = true;
- cc::OverlayCandidate& overlay2 = frame2.overlay_list.back();
+ OverlayCandidate& overlay2 = frame2.overlay_list.back();
overlay2.resource_id = mapped_resource2;
overlay2.plane_z_order = 1;
@@ -2864,12 +3049,12 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
frame3.render_passes_in_draw_order = &pass_list;
frame3.overlay_list.resize(2);
frame3.overlay_list.front().use_output_surface_for_resource = true;
- cc::OverlayCandidate& overlay3 = frame3.overlay_list.back();
+ OverlayCandidate& overlay3 = frame3.overlay_list.back();
overlay3.resource_id = mapped_resource3;
overlay3.plane_z_order = 1;
// First frame, with no swap completion.
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame1);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2879,7 +3064,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
Mock::VerifyAndClearExpectations(&scheduler_);
// Second frame, with no swap completion.
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame2);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2892,7 +3077,7 @@ TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedAfterGpuQuery) {
// Third frame, still with no swap completion (where the resources would
// otherwise have been released).
- EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+ EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _, _, _)).Times(2);
renderer_->SetCurrentFrame(frame3);
renderer_->BeginDrawingFrame();
renderer_->FinishDrawingFrame();
@@ -2958,7 +3143,7 @@ class CALayerOverlayRPDQTest : public CALayerOverlayTest {
OverlayProcessor::FilterOperationsMap render_pass_filters_;
OverlayProcessor::FilterOperationsMap render_pass_background_filters_;
CALayerOverlayList ca_layer_list_;
- cc::OverlayCandidateList overlay_list_;
+ OverlayCandidateList overlay_list_;
};
TEST_F(CALayerOverlayRPDQTest, RenderPassDrawQuadNoFilters) {
diff --git a/chromium/components/viz/service/display/renderer_pixeltest.cc b/chromium/components/viz/service/display/renderer_pixeltest.cc
index f939419f0f2..5a4c00d3e26 100644
--- a/chromium/components/viz/service/display/renderer_pixeltest.cc
+++ b/chromium/components/viz/service/display/renderer_pixeltest.cc
@@ -8,7 +8,6 @@
#include <tuple>
#include "base/memory/aligned_memory.h"
-#include "base/message_loop/message_loop.h"
#include "build/build_config.h"
#include "cc/base/math_util.h"
#include "cc/paint/paint_flags.h"
@@ -21,8 +20,11 @@
#include "cc/test/render_pass_test_utils.h"
#include "cc/test/resource_provider_test_utils.h"
#include "cc/test/test_in_process_context_provider.h"
+#include "components/viz/common/gpu/texture_allocation.h"
#include "components/viz/common/quads/picture_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
+#include "components/viz/common/resources/resource_format_utils.h"
#include "components/viz/service/display/gl_renderer.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -46,6 +48,72 @@ namespace viz {
namespace {
#if !defined(OS_ANDROID)
+std::unique_ptr<base::SharedMemory> AllocateAndRegisterSharedBitmapMemory(
+ const SharedBitmapId& id,
+ const gfx::Size& size,
+ SharedBitmapManager* shared_bitmap_manager) {
+ std::unique_ptr<base::SharedMemory> shm =
+ bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888);
+ shared_bitmap_manager->ChildAllocatedSharedBitmap(
+ bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size,
+ RGBA_8888),
+ id);
+ return shm;
+}
+
+void DeleteTexture(scoped_refptr<ContextProvider> context_provider,
+ GLuint texture,
+ const gpu::SyncToken& sync_token,
+ bool is_lost) {
+ DCHECK(context_provider);
+ gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
+ DCHECK(gl);
+ gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
+ gl->DeleteTextures(1, &texture);
+}
+
+ResourceId CreateGpuResource(scoped_refptr<ContextProvider> context_provider,
+ cc::LayerTreeResourceProvider* resource_provider,
+ const gfx::Size& size,
+ ResourceFormat format,
+ gfx::ColorSpace color_space,
+ const void* pixels = nullptr) {
+ DCHECK(context_provider);
+ gpu::gles2::GLES2Interface* gl = context_provider->ContextGL();
+ DCHECK(gl);
+ const gpu::Capabilities& caps = context_provider->ContextCapabilities();
+ auto allocation = TextureAllocation::MakeTextureId(
+ gl, caps, format,
+ /*use_gpu_memory_buffer_resources=*/false,
+ /*for_framebuffer_attachment=*/false);
+ if (pixels) {
+ TextureAllocation::UploadStorage(gl, caps, format, size, allocation,
+ color_space, pixels);
+ } else {
+ TextureAllocation::AllocateStorage(gl, caps, format, size, allocation,
+ color_space);
+ }
+ gpu::Mailbox mailbox;
+ gl->GenMailboxCHROMIUM(mailbox.name);
+ gl->ProduceTextureDirectCHROMIUM(allocation.texture_id, mailbox.name);
+ gpu::SyncToken sync_token;
+ gl->GenSyncTokenCHROMIUM(sync_token.GetData());
+ TransferableResource gl_resource = TransferableResource::MakeGL(
+ mailbox, GL_LINEAR, allocation.texture_target, sync_token);
+ gl_resource.size = size;
+ gl_resource.format = format;
+ // We didn't allocate a GpuMemoryBuffer, but we want to set buffer_format for
+ // consistency with other callsites.
+ // TODO(piman): See if we can remove TransferableResource::buffer_format
+ // altogether, it looks redundant with format. crbug.com/836488
+ gl_resource.buffer_format = BufferFormat(format);
+ gl_resource.color_space = std::move(color_space);
+ auto release_callback = SingleReleaseCallback::Create(base::BindOnce(
+ &DeleteTexture, std::move(context_provider), allocation.texture_id));
+ return resource_provider->ImportResource(gl_resource,
+ std::move(release_callback));
+}
+
std::unique_ptr<RenderPass> CreateTestRootRenderPass(int id,
const gfx::Rect& rect) {
std::unique_ptr<RenderPass> pass = RenderPass::Create();
@@ -128,8 +196,10 @@ void CreateTestTwoColoredTextureDrawQuad(
SkColor background_color,
bool premultiplied_alpha,
const SharedQuadState* shared_state,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ SharedBitmapManager* shared_bitmap_manager,
+ scoped_refptr<ContextProvider> child_context_provider,
RenderPass* render_pass) {
SkPMColor pixel_color = premultiplied_alpha
? SkPreMultiplyColor(texel_color)
@@ -153,20 +223,28 @@ void CreateTestTwoColoredTextureDrawQuad(
ResourceId resource;
if (gpu_resource) {
- resource = child_resource_provider->CreateGpuTextureResource(
- rect.size(), ResourceTextureHint::kDefault, RGBA_8888,
- gfx::ColorSpace());
+ resource = CreateGpuResource(std::move(child_context_provider),
+ child_resource_provider, rect.size(),
+ RGBA_8888, gfx::ColorSpace(), &pixels.front());
} else {
- resource = child_resource_provider->CreateBitmapResource(
- rect.size(), gfx::ColorSpace(), RGBA_8888);
+ SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId();
+ std::unique_ptr<base::SharedMemory> shm =
+ AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(),
+ shared_bitmap_manager);
+ resource = child_resource_provider->ImportResource(
+ TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(),
+ RGBA_8888),
+ SingleReleaseCallback::Create(base::DoNothing()));
+
+ for (int i = 0; i < rect.size().GetArea(); ++i)
+ static_cast<uint32_t*>(shm->memory())[i] = pixels[i];
}
- child_resource_provider->CopyToResource(
- resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size());
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource}, resource_provider,
- child_resource_provider);
+ child_resource_provider,
+ child_context_provider.get());
ResourceId mapped_resource = resource_map[resource];
bool needs_blending = true;
@@ -190,8 +268,10 @@ void CreateTestTextureDrawQuad(
SkColor background_color,
bool premultiplied_alpha,
const SharedQuadState* shared_state,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ SharedBitmapManager* shared_bitmap_manager,
+ scoped_refptr<ContextProvider> child_context_provider,
RenderPass* render_pass) {
SkPMColor pixel_color = premultiplied_alpha
? SkPreMultiplyColor(texel_color)
@@ -204,20 +284,28 @@ void CreateTestTextureDrawQuad(
ResourceId resource;
if (gpu_resource) {
- resource = child_resource_provider->CreateGpuTextureResource(
- rect.size(), ResourceTextureHint::kDefault, RGBA_8888,
- gfx::ColorSpace());
+ resource = CreateGpuResource(std::move(child_context_provider),
+ child_resource_provider, rect.size(),
+ RGBA_8888, gfx::ColorSpace(), &pixels.front());
} else {
- resource = child_resource_provider->CreateBitmapResource(
- rect.size(), gfx::ColorSpace(), RGBA_8888);
+ SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId();
+ std::unique_ptr<base::SharedMemory> shm =
+ AllocateAndRegisterSharedBitmapMemory(shared_bitmap_id, rect.size(),
+ shared_bitmap_manager);
+ resource = child_resource_provider->ImportResource(
+ TransferableResource::MakeSoftware(shared_bitmap_id, rect.size(),
+ RGBA_8888),
+ SingleReleaseCallback::Create(base::DoNothing()));
+
+ for (int i = 0; i < rect.size().GetArea(); ++i)
+ static_cast<uint32_t*>(shm->memory())[i] = pixels[i];
}
- child_resource_provider->CopyToResource(
- resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size());
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource}, resource_provider,
- child_resource_provider);
+ child_resource_provider,
+ child_context_provider.get());
ResourceId mapped_resource = resource_map[resource];
bool needs_blending = true;
@@ -239,14 +327,17 @@ void CreateTestTextureDrawQuad(
SkColor background_color,
bool premultiplied_alpha,
const SharedQuadState* shared_state,
- cc::DisplayResourceProvider* resource_provider,
+ DisplayResourceProvider* resource_provider,
cc::LayerTreeResourceProvider* child_resource_provider,
+ SharedBitmapManager* shared_bitmap_manager,
+ scoped_refptr<ContextProvider> child_context_provider,
RenderPass* render_pass) {
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
CreateTestTextureDrawQuad(gpu_resource, rect, texel_color, vertex_opacity,
background_color, premultiplied_alpha, shared_state,
resource_provider, child_resource_provider,
- render_pass);
+ shared_bitmap_manager,
+ std::move(child_context_provider), render_pass);
}
void CreateTestYUVVideoDrawQuad_FromVideoFrame(
@@ -258,8 +349,9 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame(
cc::VideoResourceUpdater* video_resource_updater,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider) {
const bool with_alpha = (video_frame->format() == media::PIXEL_FORMAT_I420A);
gfx::ColorSpace video_color_space = video_frame->ColorSpace();
@@ -303,16 +395,17 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame(
resources.release_callbacks[media::VideoFrame::kAPlane])));
}
- cc::ResourceProvider::ResourceIdArray resource_ids_to_transfer;
+ std::vector<ResourceId> resource_ids_to_transfer;
resource_ids_to_transfer.push_back(resource_y);
resource_ids_to_transfer.push_back(resource_u);
resource_ids_to_transfer.push_back(resource_v);
if (with_alpha)
resource_ids_to_transfer.push_back(resource_a);
// Transfer resources to the parent, and get the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap(
- resource_ids_to_transfer, resource_provider, child_resource_provider);
+ resource_ids_to_transfer, resource_provider, child_resource_provider,
+ child_context_provider);
ResourceId mapped_resource_y = resource_map[resource_y];
ResourceId mapped_resource_u = resource_map[resource_u];
@@ -351,7 +444,7 @@ void CreateTestYUVVideoDrawQuad_FromVideoFrame(
}
ResourceFormat yuv_highbit_resource_format =
- child_resource_provider->YuvResourceFormat(bits_per_channel);
+ video_resource_updater->YuvResourceFormat(bits_per_channel);
float multiplier = 1.0;
@@ -375,8 +468,9 @@ void CreateTestY16TextureDrawQuad_FromVideoFrame(
cc::VideoResourceUpdater* video_resource_updater,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider) {
cc::VideoFrameExternalResources resources =
video_resource_updater->CreateExternalResourcesFromVideoFrame(
video_frame);
@@ -390,9 +484,10 @@ void CreateTestY16TextureDrawQuad_FromVideoFrame(
SingleReleaseCallback::Create(std::move(resources.release_callbacks[0])));
// Transfer resources to the parent, and get the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource_y}, resource_provider,
- child_resource_provider);
+ child_resource_provider,
+ child_context_provider);
ResourceId mapped_resource_y = resource_map[resource_y];
auto* quad = render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -458,8 +553,9 @@ void CreateTestYUVVideoDrawQuad_Striped(
cc::VideoResourceUpdater* video_resource_updater,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider) {
scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
format, rect.size(), rect, rect.size(), base::TimeDelta());
@@ -497,7 +593,7 @@ void CreateTestYUVVideoDrawQuad_Striped(
CreateTestYUVVideoDrawQuad_FromVideoFrame(
shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
video_resource_updater, rect, visible_rect, resource_provider,
- child_resource_provider);
+ child_resource_provider, child_context_provider);
}
// Creates a video frame of size background_size filled with yuv_background,
@@ -521,8 +617,9 @@ void CreateTestYUVVideoDrawQuad_TwoColor(
uint8_t v_foreground,
RenderPass* render_pass,
cc::VideoResourceUpdater* video_resource_updater,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider) {
const gfx::Rect rect(background_size);
scoped_refptr<media::VideoFrame> video_frame =
@@ -566,7 +663,7 @@ void CreateTestYUVVideoDrawQuad_TwoColor(
CreateTestYUVVideoDrawQuad_FromVideoFrame(
shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
video_resource_updater, rect, visible_rect, resource_provider,
- child_resource_provider);
+ child_resource_provider, child_context_provider);
}
void CreateTestYUVVideoDrawQuad_Solid(
@@ -582,8 +679,9 @@ void CreateTestYUVVideoDrawQuad_Solid(
cc::VideoResourceUpdater* video_resource_updater,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider) {
scoped_refptr<media::VideoFrame> video_frame = media::VideoFrame::CreateFrame(
format, rect.size(), rect, rect.size(), base::TimeDelta());
video_frame->metadata()->SetInteger(media::VideoFrameMetadata::COLOR_SPACE,
@@ -605,7 +703,7 @@ void CreateTestYUVVideoDrawQuad_Solid(
CreateTestYUVVideoDrawQuad_FromVideoFrame(
shared_state, video_frame, alpha_value, tex_coord_rect, render_pass,
video_resource_updater, rect, visible_rect, resource_provider,
- child_resource_provider);
+ child_resource_provider, child_context_provider);
}
void CreateTestYUVVideoDrawQuad_NV12(
@@ -617,10 +715,12 @@ void CreateTestYUVVideoDrawQuad_NV12(
uint8_t u,
uint8_t v,
RenderPass* render_pass,
+ cc::VideoResourceUpdater* video_resource_updater,
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ scoped_refptr<ContextProvider> child_context_provider) {
gfx::ColorSpace gfx_color_space = gfx::ColorSpace::CreateREC601();
if (video_frame_color_space == media::COLOR_SPACE_JPEG) {
gfx_color_space = gfx::ColorSpace::CreateJpeg();
@@ -631,29 +731,26 @@ void CreateTestYUVVideoDrawQuad_NV12(
const gfx::Size uv_tex_size = media::VideoFrame::PlaneSize(
media::PIXEL_FORMAT_NV12, media::VideoFrame::kUVPlane, rect.size());
- ResourceId resource_y = child_resource_provider->CreateGpuTextureResource(
- rect.size(), ResourceTextureHint::kDefault,
- child_resource_provider->YuvResourceFormat(8), gfx_color_space);
- ResourceId resource_u = child_resource_provider->CreateGpuTextureResource(
- uv_tex_size, ResourceTextureHint::kDefault, RGBA_8888, gfx_color_space);
- ResourceId resource_v = resource_u;
- ResourceId resource_a = 0;
-
std::vector<uint8_t> y_pixels(ya_tex_size.GetArea(), y);
- child_resource_provider->CopyToResource(resource_y, y_pixels.data(),
- ya_tex_size);
+ ResourceId resource_y = CreateGpuResource(
+ child_context_provider, child_resource_provider, ya_tex_size,
+ video_resource_updater->YuvResourceFormat(8), gfx_color_space,
+ y_pixels.data());
// U goes in the R component and V goes in the G component.
uint32_t rgba_pixel = (u << 24) | (v << 16);
std::vector<uint32_t> uv_pixels(uv_tex_size.GetArea(), rgba_pixel);
- child_resource_provider->CopyToResource(
- resource_u, reinterpret_cast<uint8_t*>(uv_pixels.data()), uv_tex_size);
+ ResourceId resource_u = CreateGpuResource(
+ child_context_provider, child_resource_provider, uv_tex_size, RGBA_8888,
+ gfx_color_space, uv_pixels.data());
+ ResourceId resource_v = resource_u;
+ ResourceId resource_a = 0;
// Transfer resources to the parent, and get the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
- SendResourceAndGetChildToParentMap({resource_y, resource_u, resource_v},
- resource_provider,
- child_resource_provider);
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ SendResourceAndGetChildToParentMap(
+ {resource_y, resource_u, resource_v}, resource_provider,
+ child_resource_provider, child_context_provider.get());
ResourceId mapped_resource_y = resource_map[resource_y];
ResourceId mapped_resource_u = resource_map[resource_u];
@@ -686,8 +783,9 @@ void CreateTestY16TextureDrawQuad_TwoColor(
const gfx::Rect& rect,
const gfx::Rect& visible_rect,
const gfx::Rect& foreground_rect,
- cc::DisplayResourceProvider* resource_provider,
- cc::LayerTreeResourceProvider* child_resource_provider) {
+ DisplayResourceProvider* resource_provider,
+ cc::LayerTreeResourceProvider* child_resource_provider,
+ ContextProvider* child_context_provider) {
std::unique_ptr<unsigned char, base::AlignedFreeDeleter> memory(
static_cast<unsigned char*>(
base::AlignedAlloc(rect.size().GetArea() * 2,
@@ -730,7 +828,7 @@ void CreateTestY16TextureDrawQuad_TwoColor(
CreateTestY16TextureDrawQuad_FromVideoFrame(
shared_state, video_frame, tex_coord_rect, render_pass,
video_resource_updater, rect, visible_rect, resource_provider,
- child_resource_provider);
+ child_resource_provider, child_context_provider);
}
using RendererTypes =
@@ -783,6 +881,13 @@ bool FuzzyForSoftwareOnlyPixelComparator<SoftwareRenderer>::Compare(
}
template <>
+bool FuzzyForSoftwareOnlyPixelComparator<SkiaRenderer>::Compare(
+ const SkBitmap& actual_bmp,
+ const SkBitmap& expected_bmp) const {
+ return fuzzy_.Compare(actual_bmp, expected_bmp);
+}
+
+template <>
bool FuzzyForSoftwareOnlyPixelComparator<
cc::SoftwareRendererWithExpandedViewport>::
Compare(const SkBitmap& actual_bmp, const SkBitmap& expected_bmp) const {
@@ -861,13 +966,14 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithoutBackground) {
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- CreateTestTextureDrawQuad(this->use_gpu(),
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(128, 0, 255, 0), // Texel color.
- SK_ColorTRANSPARENT, // Background color.
- true, // Premultiplied alpha.
- shared_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), pass.get());
+ CreateTestTextureDrawQuad(
+ this->use_gpu(), gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(128, 0, 255, 0), // Texel color.
+ SK_ColorTRANSPARENT, // Background color.
+ true, // Premultiplied alpha.
+ shared_state, this->resource_provider_.get(),
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, pass.get());
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
@@ -890,13 +996,14 @@ TYPED_TEST(RendererPixelTest, PremultipliedTextureWithBackground) {
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
texture_quad_state->opacity = 0.8f;
- CreateTestTextureDrawQuad(this->use_gpu(),
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(204, 120, 255, 120), // Texel color.
- SK_ColorGREEN, // Background color.
- true, // Premultiplied alpha.
- texture_quad_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), pass.get());
+ CreateTestTextureDrawQuad(
+ this->use_gpu(), gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(204, 120, 255, 120), // Texel color.
+ SK_ColorGREEN, // Background color.
+ true, // Premultiplied alpha.
+ texture_quad_state, this->resource_provider_.get(),
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, pass.get());
SharedQuadState* color_quad_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
@@ -1022,14 +1129,15 @@ TEST_F(GLRendererPixelTest,
texture_quad_state->opacity = 0.8f;
float vertex_opacity[4] = {1.f, 1.f, 0.f, 0.f};
- CreateTestTextureDrawQuad(this->use_gpu(),
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(204, 120, 255, 120), // Texel color.
- vertex_opacity,
- SK_ColorGREEN, // Background color.
- true, // Premultiplied alpha.
- texture_quad_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), pass.get());
+ CreateTestTextureDrawQuad(
+ this->use_gpu(), gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(204, 120, 255, 120), // Texel color.
+ vertex_opacity,
+ SK_ColorGREEN, // Background color.
+ true, // Premultiplied alpha.
+ texture_quad_state, this->resource_provider_.get(),
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, pass.get());
SharedQuadState* color_quad_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
@@ -1109,12 +1217,6 @@ class IntersectingQuadPixelTest : public RendererPixelTest<TypeParam> {
RenderPassList pass_list_;
};
-// TODO(weiliangc): Move these tests to normal RendererPixelTest as they pass
-// with SkiaRenderer. Failed test list recorded in crbug.com/821176.
-template <typename TypeParam>
-class IntersectingQuadNonSkiaPixelTest
- : public IntersectingQuadPixelTest<TypeParam> {};
-
template <typename TypeParam>
class IntersectingQuadGLPixelTest
: public IntersectingQuadPixelTest<TypeParam> {
@@ -1123,15 +1225,17 @@ class IntersectingQuadGLPixelTest
IntersectingQuadPixelTest<TypeParam>::SetUp();
constexpr bool kUseStreamVideoDrawQuad = false;
constexpr bool kUseGpuMemoryBufferResources = false;
+ constexpr bool kUseR16Texture = false;
+ constexpr int kMaxResourceSize = 10000;
video_resource_updater_ = std::make_unique<cc::VideoResourceUpdater>(
this->child_context_provider_.get(), nullptr,
this->child_resource_provider_.get(), kUseStreamVideoDrawQuad,
- kUseGpuMemoryBufferResources);
+ kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize);
video_resource_updater2_ = std::make_unique<cc::VideoResourceUpdater>(
this->child_context_provider_.get(), nullptr,
this->child_resource_provider_.get(), kUseStreamVideoDrawQuad,
- kUseGpuMemoryBufferResources);
+ kUseGpuMemoryBufferResources, kUseR16Texture, kMaxResourceSize);
}
protected:
@@ -1150,7 +1254,6 @@ using GLRendererTypes =
::testing::Types<GLRenderer, cc::GLRendererWithExpandedViewport>;
TYPED_TEST_CASE(IntersectingQuadPixelTest, RendererTypes);
-TYPED_TEST_CASE(IntersectingQuadNonSkiaPixelTest, NonSkiaRendererTypes);
TYPED_TEST_CASE(IntersectingQuadGLPixelTest, GLRendererTypes);
TYPED_TEST_CASE(IntersectingQuadSoftwareTest, SoftwareRendererTypes);
@@ -1170,6 +1273,11 @@ TYPED_TEST(IntersectingQuadPixelTest, SolidColorQuads) {
FILE_PATH_LITERAL("intersecting_blue_green.png"));
}
+static inline SkColor GetSkiaOrGLColor(const SkColor& color) {
+ return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color),
+ SkColorGetG(color), SkColorGetR(color));
+}
+
template <typename TypeParam>
SkColor GetColor(const SkColor& color) {
return color;
@@ -1177,28 +1285,35 @@ SkColor GetColor(const SkColor& color) {
template <>
SkColor GetColor<GLRenderer>(const SkColor& color) {
- return SkColorSetARGB(SkColorGetA(color), SkColorGetB(color),
- SkColorGetG(color), SkColorGetR(color));
+ return GetSkiaOrGLColor(color);
}
+
+template <>
+SkColor GetColor<SkiaRenderer>(const SkColor& color) {
+ return GetSkiaOrGLColor(color);
+}
+
template <>
SkColor GetColor<cc::GLRendererWithExpandedViewport>(const SkColor& color) {
- return GetColor<GLRenderer>(color);
+ return GetSkiaOrGLColor(color);
}
-TYPED_TEST(IntersectingQuadNonSkiaPixelTest, TexturedQuads) {
+TYPED_TEST(IntersectingQuadPixelTest, TexturedQuads) {
this->SetupQuadStateAndRenderPass();
CreateTestTwoColoredTextureDrawQuad(
this->use_gpu(), this->quad_rect_,
GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)),
GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT,
true, this->front_quad_state_, this->resource_provider_.get(),
- this->child_resource_provider_.get(), this->render_pass_.get());
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, this->render_pass_.get());
CreateTestTwoColoredTextureDrawQuad(
this->use_gpu(), this->quad_rect_,
GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)),
GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT,
true, this->back_quad_state_, this->resource_provider_.get(),
- this->child_resource_provider_.get(), this->render_pass_.get());
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, this->render_pass_.get());
SCOPED_TRACE("IntersectingTexturedQuads");
this->AppendBackgroundAndRunTest(
@@ -1261,7 +1376,7 @@ TYPED_TEST(IntersectingQuadSoftwareTest, PictureQuads) {
FILE_PATH_LITERAL("intersecting_blue_green_squares.png"));
}
-TYPED_TEST(IntersectingQuadNonSkiaPixelTest, RenderPassQuads) {
+TYPED_TEST(IntersectingQuadPixelTest, RenderPassQuads) {
this->SetupQuadStateAndRenderPass();
int child_pass_id1 = 2;
int child_pass_id2 = 3;
@@ -1278,13 +1393,15 @@ TYPED_TEST(IntersectingQuadNonSkiaPixelTest, RenderPassQuads) {
GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)),
GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 255)), SK_ColorTRANSPARENT,
true, child1_quad_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), child_pass1.get());
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, child_pass1.get());
CreateTestTwoColoredTextureDrawQuad(
this->use_gpu(), this->quad_rect_,
GetColor<TypeParam>(SkColorSetARGB(255, 0, 255, 0)),
GetColor<TypeParam>(SkColorSetARGB(255, 0, 0, 0)), SK_ColorTRANSPARENT,
true, child2_quad_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), child_pass2.get());
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, child_pass2.get());
CreateTestRenderPassDrawQuad(this->front_quad_state_, this->quad_rect_,
child_pass_id1, this->render_pass_.get());
@@ -1312,14 +1429,16 @@ TYPED_TEST(IntersectingQuadGLPixelTest, YUVVideoQuads) {
media::COLOR_SPACE_JPEG, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
this->quad_rect_.size(), this->quad_rect_, 0, 128, 128, inner_rect, 29,
255, 107, this->render_pass_.get(), this->video_resource_updater_.get(),
- this->resource_provider_.get(), this->child_resource_provider_.get());
+ this->resource_provider_.get(), this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
CreateTestYUVVideoDrawQuad_TwoColor(
this->back_quad_state_, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG,
false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), this->quad_rect_.size(),
this->quad_rect_, 149, 43, 21, inner_rect, 0, 128, 128,
this->render_pass_.get(), this->video_resource_updater2_.get(),
- this->resource_provider_.get(), this->child_resource_provider_.get());
+ this->resource_provider_.get(), this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
SCOPED_TRACE("IntersectingVideoQuads");
this->AppendBackgroundAndRunTest(
@@ -1339,13 +1458,15 @@ TYPED_TEST(IntersectingQuadGLPixelTest, Y16VideoQuads) {
this->front_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 18, 0,
this->render_pass_.get(), this->video_resource_updater_.get(),
this->quad_rect_, this->quad_rect_, inner_rect,
- this->resource_provider_.get(), this->child_resource_provider_.get());
+ this->resource_provider_.get(), this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
CreateTestY16TextureDrawQuad_TwoColor(
this->back_quad_state_, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 0, 182,
this->render_pass_.get(), this->video_resource_updater2_.get(),
this->quad_rect_, this->quad_rect_, inner_rect,
- this->resource_provider_.get(), this->child_resource_provider_.get());
+ this->resource_provider_.get(), this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
SCOPED_TRACE("IntersectingVideoQuads");
this->AppendBackgroundAndRunTest(
@@ -1363,13 +1484,14 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithoutBackground) {
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- CreateTestTextureDrawQuad(this->use_gpu(),
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(128, 0, 255, 0), // Texel color.
- SK_ColorTRANSPARENT, // Background color.
- false, // Premultiplied alpha.
- shared_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), pass.get());
+ CreateTestTextureDrawQuad(
+ this->use_gpu(), gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(128, 0, 255, 0), // Texel color.
+ SK_ColorTRANSPARENT, // Background color.
+ false, // Premultiplied alpha.
+ shared_state, this->resource_provider_.get(),
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, pass.get());
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
@@ -1393,13 +1515,14 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
texture_quad_state->opacity = 0.8f;
- CreateTestTextureDrawQuad(this->use_gpu(),
- gfx::Rect(this->device_viewport_size_),
- SkColorSetARGB(204, 120, 255, 120), // Texel color.
- SK_ColorGREEN, // Background color.
- false, // Premultiplied alpha.
- texture_quad_state, this->resource_provider_.get(),
- this->child_resource_provider_.get(), pass.get());
+ CreateTestTextureDrawQuad(
+ this->use_gpu(), gfx::Rect(this->device_viewport_size_),
+ SkColorSetARGB(204, 120, 255, 120), // Texel color.
+ SK_ColorGREEN, // Background color.
+ false, // Premultiplied alpha.
+ texture_quad_state, this->resource_provider_.get(),
+ this->child_resource_provider_.get(), this->shared_bitmap_manager_.get(),
+ this->child_context_provider_, pass.get());
SharedQuadState* color_quad_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
@@ -1449,7 +1572,8 @@ class VideoGLRendererPixelTest : public cc::GLRendererPixelTest {
shared_state, format, color_space, false, tex_coord_rect,
background_size, gfx::Rect(background_size), 128, 128, 128, green_rect,
149, 43, 21, pass.get(), video_resource_updater_.get(),
- resource_provider_.get(), child_resource_provider_.get());
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_context_provider_.get());
pass_list->push_back(std::move(pass));
}
@@ -1457,9 +1581,12 @@ class VideoGLRendererPixelTest : public cc::GLRendererPixelTest {
GLRendererPixelTest::SetUp();
constexpr bool kUseStreamVideoDrawQuad = false;
constexpr bool kUseGpuMemoryBufferResources = false;
+ constexpr bool kUseR16Texture = false;
+ constexpr int kMaxResourceSize = 10000;
video_resource_updater_ = std::make_unique<cc::VideoResourceUpdater>(
child_context_provider_.get(), nullptr, child_resource_provider_.get(),
- kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources);
+ kUseStreamVideoDrawQuad, kUseGpuMemoryBufferResources, kUseR16Texture,
+ kMaxResourceSize);
}
std::unique_ptr<cc::VideoResourceUpdater> video_resource_updater_;
@@ -1487,7 +1614,7 @@ TEST_P(VideoGLRendererPixelHiLoTest, SimpleYUVRect) {
shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1515,7 +1642,8 @@ TEST_P(VideoGLRendererPixelHiLoTest, ClippedYUVRect) {
shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
false, IsHighbit(), gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
video_resource_updater_.get(), draw_rect, viewport,
- resource_provider_.get(), child_resource_provider_.get());
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1541,7 +1669,7 @@ TEST_F(VideoGLRendererPixelHiLoTest, OffsetYUVRect) {
shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
false, false, gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1568,7 +1696,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) {
shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_SD_REC601,
false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1597,7 +1725,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) {
shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false,
gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1619,8 +1747,9 @@ TEST_F(VideoGLRendererPixelTest, SimpleNV12JRect) {
// YUV of (149,43,21) should be green (0,255,0) in RGB.
CreateTestYUVVideoDrawQuad_NV12(
shared_state, media::COLOR_SPACE_JPEG, gfx::ColorSpace::CreateJpeg(),
- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(), rect, rect,
- resource_provider_.get(), child_resource_provider_.get());
+ gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
+ video_resource_updater_.get(), rect, rect, resource_provider_.get(),
+ child_resource_provider_.get(), child_context_provider_);
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1668,7 +1797,7 @@ TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) {
shared_state, media::PIXEL_FORMAT_I420, media::COLOR_SPACE_JPEG, false,
gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1694,7 +1823,7 @@ TEST_F(VideoGLRendererPixelHiLoTest, SimpleYUVARect) {
shared_state, media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601,
false, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
@@ -1723,7 +1852,7 @@ TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) {
shared_state, media::PIXEL_FORMAT_I420A, media::COLOR_SPACE_SD_REC601,
true, false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), pass.get(),
video_resource_updater_.get(), rect, rect, resource_provider_.get(),
- child_resource_provider_.get());
+ child_resource_provider_.get(), child_context_provider_.get());
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false);
@@ -1749,7 +1878,8 @@ TEST_F(VideoGLRendererPixelTest, TwoColorY16Rect) {
CreateTestY16TextureDrawQuad_TwoColor(
shared_state, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 68, 123, pass.get(),
video_resource_updater_.get(), rect, rect, upper_rect,
- resource_provider_.get(), child_resource_provider_.get());
+ resource_provider_.get(), child_resource_provider_.get(),
+ child_context_provider_.get());
RenderPassList pass_list;
pass_list.push_back(std::move(pass));
@@ -1760,7 +1890,7 @@ TEST_F(VideoGLRendererPixelTest, TwoColorY16Rect) {
cc::FuzzyPixelOffByOneComparator(true)));
}
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlpha) {
+TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
gfx::Rect viewport_rect(this->device_viewport_size_);
int root_pass_id = 1;
@@ -1838,7 +1968,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlpha) {
FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassSaturateFilter) {
+TYPED_TEST(RendererPixelTest, FastPassSaturateFilter) {
gfx::Rect viewport_rect(this->device_viewport_size_);
int root_pass_id = 1;
@@ -1898,7 +2028,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, FastPassSaturateFilter) {
FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassFilterChain) {
+TYPED_TEST(RendererPixelTest, FastPassFilterChain) {
gfx::Rect viewport_rect(this->device_viewport_size_);
int root_pass_id = 1;
@@ -1960,7 +2090,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, FastPassFilterChain) {
FuzzyForSoftwareOnlyPixelComparator<TypeParam>(false)));
}
-TYPED_TEST(NonSkiaRendererPixelTest, FastPassColorFilterAlphaTranslation) {
+TYPED_TEST(RendererPixelTest, FastPassColorFilterAlphaTranslation) {
gfx::Rect viewport_rect(this->device_viewport_size_);
int root_pass_id = 1;
@@ -2142,7 +2272,7 @@ TYPED_TEST(RendererPixelTest, EnlargedRenderPassTextureWithAntiAliasing) {
// This tests the case where we have a RenderPass with a mask, but the quad
// for the masked surface does not include the full surface texture.
-TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad) {
+TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad) {
gfx::Rect viewport_rect(this->device_viewport_size_);
int root_pass_id = 1;
@@ -2186,23 +2316,20 @@ TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad) {
ResourceId mask_resource_id;
if (this->use_gpu()) {
- mask_resource_id = this->child_resource_provider_->CreateGpuTextureResource(
- mask_rect.size(), ResourceTextureHint::kDefault, RGBA_8888,
- gfx::ColorSpace());
+ mask_resource_id = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels());
} else {
- mask_resource_id = this->child_resource_provider_->CreateBitmapResource(
- mask_rect.size(), gfx::ColorSpace(), RGBA_8888);
+ mask_resource_id =
+ this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
}
- this->child_resource_provider_->CopyToResource(
- mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect.size());
-
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({mask_resource_id},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
// This RenderPassDrawQuad does not include the full |viewport_rect|
@@ -2241,7 +2368,7 @@ TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad) {
// This tests the case where we have a RenderPass with a mask, but the quad
// for the masked surface does not include the full surface texture.
-TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad2) {
+TYPED_TEST(RendererPixelTest, RenderPassAndMaskWithPartialQuad2) {
gfx::Rect viewport_rect(this->device_viewport_size_);
int root_pass_id = 1;
@@ -2285,23 +2412,20 @@ TYPED_TEST(NonSkiaRendererPixelTest, RenderPassAndMaskWithPartialQuad2) {
ResourceId mask_resource_id;
if (this->use_gpu()) {
- mask_resource_id = this->child_resource_provider_->CreateGpuTextureResource(
- mask_rect.size(), ResourceTextureHint::kDefault, RGBA_8888,
- gfx::ColorSpace());
+ mask_resource_id = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels());
} else {
- mask_resource_id = this->child_resource_provider_->CreateBitmapResource(
- mask_rect.size(), gfx::ColorSpace(), RGBA_8888);
+ mask_resource_id =
+ this->AllocateAndFillSoftwareResource(mask_rect.size(), bitmap);
}
- this->child_resource_provider_->CopyToResource(
- mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect.size());
-
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({mask_resource_id},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_mask_resource_id = resource_map[mask_resource_id];
// This RenderPassDrawQuad does not include the full |viewport_rect|
@@ -2440,16 +2564,14 @@ class RendererPixelTestWithBackgroundFilter
gfx::Rect filter_pass_layer_rect_;
};
+// The software renderer does not support background filters yet.
using BackgroundFilterRendererTypes =
- ::testing::Types<GLRenderer, SoftwareRenderer>;
+ ::testing::Types<GLRenderer, SkiaRenderer>;
+
TYPED_TEST_CASE(RendererPixelTestWithBackgroundFilter,
BackgroundFilterRendererTypes);
-using GLRendererPixelTestWithBackgroundFilter =
- RendererPixelTestWithBackgroundFilter<GLRenderer>;
-
-// TODO(skaslev): The software renderer does not support filters yet.
-TEST_F(GLRendererPixelTestWithBackgroundFilter, InvertFilter) {
+TYPED_TEST(RendererPixelTestWithBackgroundFilter, InvertFilter) {
this->background_filters_.Append(
cc::FilterOperation::CreateInvertFilter(1.f));
@@ -2771,21 +2893,19 @@ TEST_F(GLRendererPixelTest, TileDrawQuadForceAntiAliasingOff) {
gfx::Size tile_size(32, 32);
ResourceId resource;
if (this->use_gpu()) {
- resource = this->child_resource_provider_->CreateGpuTextureResource(
- tile_size, ResourceTextureHint::kDefault, RGBA_8888, gfx::ColorSpace());
+ resource = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels());
} else {
- resource = this->child_resource_provider_->CreateBitmapResource(
- tile_size, gfx::ColorSpace(), RGBA_8888);
+ resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap);
}
- this->child_resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
-
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
int id = 1;
@@ -3207,19 +3327,18 @@ TYPED_TEST(NonSkiaRendererPixelTest, TileDrawQuadNearestNeighbor) {
gfx::Size tile_size(2, 2);
ResourceId resource;
if (this->use_gpu()) {
- resource = this->child_resource_provider_->CreateGpuTextureResource(
- tile_size, ResourceTextureHint::kDefault, RGBA_8888, gfx::ColorSpace());
+ resource = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels());
} else {
- resource = this->child_resource_provider_->CreateBitmapResource(
- tile_size, gfx::ColorSpace(), RGBA_8888);
+ resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap);
}
- this->child_resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
int id = 1;
@@ -3262,17 +3381,15 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadNearestNeighbor) {
draw_point_color(&canvas, 1, 1, SK_ColorGREEN);
gfx::Size tile_size(2, 2);
- ResourceId resource = this->child_resource_provider_->CreateBitmapResource(
- tile_size, gfx::ColorSpace(), RGBA_8888);
-
- this->child_resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
+ ResourceId resource =
+ this->AllocateAndFillSoftwareResource(tile_size, bitmap);
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
int id = 1;
@@ -3317,17 +3434,15 @@ TYPED_TEST(SoftwareRendererPixelTest, TextureDrawQuadLinear) {
}
gfx::Size tile_size(2, 2);
- ResourceId resource = this->child_resource_provider_->CreateBitmapResource(
- tile_size, gfx::ColorSpace(), RGBA_8888);
-
- this->child_resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
+ ResourceId resource =
+ this->AllocateAndFillSoftwareResource(tile_size, bitmap);
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
int id = 1;
@@ -3666,20 +3781,16 @@ TEST_F(GLRendererPixelTest, TextureQuadBatching) {
inset_rect.Inset(6, 6, 4, 4);
}
- ResourceId resource =
- this->child_resource_provider_->CreateGpuTextureResource(
- mask_rect.size(), ResourceTextureHint::kDefault, RGBA_8888,
- gfx::ColorSpace());
-
- this->child_resource_provider_->CopyToResource(
- resource, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect.size());
+ ResourceId resource = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ mask_rect.size(), RGBA_8888, gfx::ColorSpace(), bitmap.getPixels());
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
// Arbitrary dividing lengths to divide up the resource into 16 quads.
@@ -3748,19 +3859,18 @@ TEST_F(GLRendererPixelTest, TileQuadClamping) {
ResourceId resource;
if (this->use_gpu()) {
- resource = this->child_resource_provider_->CreateGpuTextureResource(
- tile_size, ResourceTextureHint::kDefault, RGBA_8888, gfx::ColorSpace());
+ resource = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ tile_size, RGBA_8888, gfx::ColorSpace(), bitmap.getPixels());
} else {
- resource = this->child_resource_provider_->CreateBitmapResource(
- tile_size, gfx::ColorSpace(), RGBA_8888);
+ resource = this->AllocateAndFillSoftwareResource(tile_size, bitmap);
}
- this->child_resource_provider_->CopyToResource(
- resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource},
this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
int id = 1;
@@ -3847,7 +3957,7 @@ TEST_F(GLRendererPixelTestWithOverdrawFeedback, TranslucentRectangles) {
cc::ExactPixelComparator(true)));
}
-using ColorSpacePair = std::tuple<gfx::ColorSpace, gfx::ColorSpace>;
+using ColorSpacePair = std::tuple<gfx::ColorSpace, gfx::ColorSpace, bool>;
class ColorTransformPixelTest
: public GLRendererPixelTest,
@@ -3857,7 +3967,7 @@ class ColorTransformPixelTest
// Note that this size of 17 is not random -- it is chosen to match the
// size of LUTs that are created. If we did not match the LUT size exactly,
// then the error for LUT based transforms is much larger.
- device_viewport_size_ = gfx::Size(17, 4);
+ device_viewport_size_ = gfx::Size(17, 5);
src_color_space_ = std::get<0>(GetParam());
dst_color_space_ = std::get<1>(GetParam());
if (!src_color_space_.IsValid()) {
@@ -3868,9 +3978,11 @@ class ColorTransformPixelTest
dst_color_space_ =
gfx::ICCProfileForTestingNoAnalyticTrFn().GetColorSpace();
}
+ premultiplied_alpha_ = std::get<2>(GetParam());
}
gfx::ColorSpace src_color_space_;
gfx::ColorSpace dst_color_space_;
+ bool premultiplied_alpha_ = false;
};
TEST_P(ColorTransformPixelTest, Basic) {
@@ -3883,15 +3995,25 @@ TEST_P(ColorTransformPixelTest, Basic) {
// Row 1: Gradient of green from 0 to 255
// Row 2: Gradient of blue from 0 to 255
// Row 3: Gradient of grey from 0 to 255
+ // Row 4: Gradient of alpha from 0 to 255 with mixed colors.
for (int x = 0; x < rect.width(); ++x) {
- int v = (x * 255) / (rect.width() - 1);
+ int gradient_value = (x * 255) / (rect.width() - 1);
for (int y = 0; y < rect.height(); ++y) {
- for (int c = 0; c < 3; ++c) {
- if (y == c || y == rect.height() - 1) {
- input_colors[c + 4 * (x + rect.width() * y)] = v;
+ uint8_t* pixel = &input_colors[4 * (x + rect.width() * y)];
+ pixel[3] = 255;
+ if (y < 3) {
+ pixel[y] = gradient_value;
+ } else if (y == 3) {
+ pixel[0] = pixel[1] = pixel[2] = gradient_value;
+ } else {
+ if (premultiplied_alpha_) {
+ pixel[x % 3] = gradient_value;
+ pixel[3] = gradient_value;
+ } else {
+ pixel[x % 3] = 0xFF;
+ pixel[3] = gradient_value;
}
}
- input_colors[3 + 4 * (x + rect.width() * y)] = 255;
}
}
@@ -3915,30 +4037,30 @@ TEST_P(ColorTransformPixelTest, Basic) {
color.set_y(std::min(std::max(0.f, color.y()), 1.f));
color.set_z(std::min(std::max(0.f, color.z()), 1.f));
expected_output_colors[i] =
- SkColorSetARGBInline(255, static_cast<size_t>(255.f * color.x() + 0.5f),
- static_cast<size_t>(255.f * color.y() + 0.5f),
- static_cast<size_t>(255.f * color.z() + 0.5f));
+ SkColorSetARGB(255, static_cast<size_t>(255.f * color.x() + 0.5f),
+ static_cast<size_t>(255.f * color.y() + 0.5f),
+ static_cast<size_t>(255.f * color.z() + 0.5f));
}
int id = 1;
std::unique_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
pass->color_space = dst_color_space_;
+ // Append a quad to execute the transform.
{
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- ResourceId resource = child_resource_provider_->CreateGpuTextureResource(
- rect.size(), ResourceTextureHint::kDefault, RGBA_8888,
- src_color_space_);
- this->child_resource_provider_->CopyToResource(
- resource, input_colors.data(), rect.size());
+ ResourceId resource = CreateGpuResource(
+ this->child_context_provider_, this->child_resource_provider_.get(),
+ rect.size(), RGBA_8888, src_color_space_, input_colors.data());
// Return the mapped resource id.
- cc::ResourceProvider::ResourceIdMap resource_map =
- SendResourceAndGetChildToParentMap(
- {resource}, this->resource_provider_.get(),
- this->child_resource_provider_.get());
+ std::unordered_map<ResourceId, ResourceId> resource_map =
+ SendResourceAndGetChildToParentMap({resource},
+ this->resource_provider_.get(),
+ this->child_resource_provider_.get(),
+ this->child_context_provider_.get());
ResourceId mapped_resource = resource_map[resource];
bool needs_blending = true;
@@ -3946,17 +4068,16 @@ TEST_P(ColorTransformPixelTest, Basic) {
const gfx::PointF uv_bottom_right(1.0f, 1.0f);
const bool flipped = false;
const bool nearest_neighbor = false;
- const bool premultiplied_alpha = false;
auto* quad = pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
quad->SetNew(shared_state, rect, rect, needs_blending, mapped_resource,
- premultiplied_alpha, uv_top_left, uv_bottom_right,
+ premultiplied_alpha_, uv_top_left, uv_bottom_right,
SK_ColorBLACK, vertex_opacity, flipped, nearest_neighbor,
false);
auto* color_quad = pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
- color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
+ color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false);
}
RenderPassList pass_list;
@@ -4033,17 +4154,23 @@ gfx::ColorSpace intermediate_color_spaces[] = {
gfx::ColorSpace(PrimaryID::XYZ_D50, TransferID::IEC61966_2_1_HDR),
};
+bool color_space_premul_values[] = {
+ true, false,
+};
+
INSTANTIATE_TEST_CASE_P(
FromColorSpace,
ColorTransformPixelTest,
testing::Combine(testing::ValuesIn(src_color_spaces),
- testing::ValuesIn(intermediate_color_spaces)));
+ testing::ValuesIn(intermediate_color_spaces),
+ testing::ValuesIn(color_space_premul_values)));
INSTANTIATE_TEST_CASE_P(
ToColorSpace,
ColorTransformPixelTest,
testing::Combine(testing::ValuesIn(intermediate_color_spaces),
- testing::ValuesIn(dst_color_spaces)));
+ testing::ValuesIn(dst_color_spaces),
+ testing::ValuesIn(color_space_premul_values)));
#endif // !defined(OS_ANDROID)
diff --git a/chromium/components/viz/service/display/scoped_render_pass_texture.h b/chromium/components/viz/service/display/scoped_render_pass_texture.h
index b3a79e2067d..5700c68745e 100644
--- a/chromium/components/viz/service/display/scoped_render_pass_texture.h
+++ b/chromium/components/viz/service/display/scoped_render_pass_texture.h
@@ -7,7 +7,6 @@
#include "base/macros.h"
#include "components/viz/common/resources/resource_format.h"
-#include "components/viz/common/resources/resource_texture_hint.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/gfx/color_space.h"
diff --git a/chromium/components/viz/service/display/shader.cc b/chromium/components/viz/service/display/shader.cc
index e7a927d140e..62bab35ad8b 100644
--- a/chromium/components/viz/service/display/shader.cc
+++ b/chromium/components/viz/service/display/shader.cc
@@ -11,6 +11,7 @@
#include <vector>
#include "base/logging.h"
+#include "base/strings/char_traits.h"
#include "base/strings/stringprintf.h"
#include "components/viz/service/display/static_geometry_binding.h"
#include "gpu/command_buffer/client/gles2_interface.h"
@@ -18,29 +19,18 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
-constexpr bool ConstexprEqual(const char* a, const char* b, size_t length) {
- for (size_t i = 0; i < length; i++) {
- if (a[i] != b[i])
- return false;
- }
- return true;
-}
-
constexpr base::StringPiece StripLambda(base::StringPiece shader) {
- // Must contain at least "[]() {}" and trailing null (included in size).
- // TODO(jbroman): Simplify this once we're in a post-C++17 world, where
- // starts_with and ends_with can easily be made constexpr.
- DCHECK(shader.size() >= 7); // NOLINT
- DCHECK(ConstexprEqual(shader.data(), "[]() {", 6));
+ // Must contain at least "[]() {}".
+ DCHECK(shader.starts_with("[]() {"));
+ DCHECK(shader.ends_with("}"));
shader.remove_prefix(6);
- DCHECK(shader[shader.size() - 1] == '}'); // NOLINT
shader.remove_suffix(1);
return shader;
}
// Shaders are passed in with lambda syntax, which tricks clang-format into
// handling them correctly. StripLambda removes this.
-#define SHADER0(Src) StripLambda(base::StringPiece(#Src, sizeof(#Src) - 1))
+#define SHADER0(Src) StripLambda(#Src)
#define HDR(x) \
do { \
@@ -535,11 +525,7 @@ void FragmentShader::Init(GLES2Interface* context,
}
void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const {
- if (shader_string->find("ApplyBlendMode") == std::string::npos)
- return;
-
if (!has_blend_mode()) {
- shader_string->insert(0, "#define ApplyBlendMode(X, Y) (X)\n");
return;
}
@@ -549,48 +535,39 @@ void FragmentShader::SetBlendModeFunctions(std::string* shader_string) const {
uniform TexCoordPrecision vec4 backdropRect;
});
- base::StringPiece mixFunction;
+ base::StringPiece function_apply_blend_mode;
if (mask_for_background_) {
- static constexpr base::StringPiece kMixFunctionWithMask = SHADER0([]() {
- vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) {
+ static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
+ vec4 ApplyBlendMode(vec4 src, float mask) {
+ TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+ bgTexCoord *= backdropRect.zw;
vec4 backdrop = texture2D(s_backdropTexture, bgTexCoord);
vec4 original_backdrop =
texture2D(s_originalBackdropTexture, bgTexCoord);
- return mix(original_backdrop, backdrop, mask);
+ vec4 dst = mix(original_backdrop, backdrop, mask);
+ return Blend(src, dst);
}
});
- mixFunction = kMixFunctionWithMask;
+ function_apply_blend_mode = kFunctionApplyBlendMode;
} else {
- static constexpr base::StringPiece kMixFunctionWithoutMask = SHADER0([]() {
- vec4 MixBackdrop(TexCoordPrecision vec2 bgTexCoord, float mask) {
- return texture2D(s_backdropTexture, bgTexCoord);
+ static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
+ vec4 ApplyBlendMode(vec4 src) {
+ TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+ bgTexCoord *= backdropRect.zw;
+ vec4 dst = texture2D(s_backdropTexture, bgTexCoord);
+ return Blend(src, dst);
}
});
- mixFunction = kMixFunctionWithoutMask;
+ function_apply_blend_mode = kFunctionApplyBlendMode;
}
- static constexpr base::StringPiece kFunctionApplyBlendMode = SHADER0([]() {
- vec4 GetBackdropColor(float mask) {
- TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
- bgTexCoord.x /= backdropRect.z;
- bgTexCoord.y /= backdropRect.w;
- return MixBackdrop(bgTexCoord, mask);
- }
-
- vec4 ApplyBlendMode(vec4 src, float mask) {
- vec4 dst = GetBackdropColor(mask);
- return Blend(src, dst);
- }
- });
-
std::string shader;
shader.reserve(shader_string->size() + 1024);
shader += "precision mediump float;";
AppendHelperFunctions(&shader);
AppendBlendFunction(&shader);
kUniforms.AppendToString(&shader);
- mixFunction.AppendToString(&shader);
- kFunctionApplyBlendMode.AppendToString(&shader);
+ function_apply_blend_mode.AppendToString(&shader);
shader += *shader_string;
*shader_string = std::move(shader);
}
@@ -1015,12 +992,6 @@ std::string FragmentShader::GetShaderSource() const {
SRC("float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);");
}
- // Premultiply by alpha.
- if (premultiply_alpha_mode_ == NON_PREMULTIPLIED_ALPHA) {
- SRC("// Premultiply alpha");
- SRC("texColor.rgb *= texColor.a;");
- }
-
// Apply background texture.
if (has_background_color_) {
HDR("uniform vec4 background_color;");
@@ -1087,10 +1058,16 @@ std::string FragmentShader::GetShaderSource() const {
SRC("gl_FragColor = vec4(texColor.rgb, 1.0);");
break;
case FRAG_COLOR_MODE_APPLY_BLEND_MODE:
- if (mask_mode_ != NO_MASK)
- SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);");
- else
- SRC("gl_FragColor = ApplyBlendMode(texColor, 0.0);");
+ if (!has_blend_mode()) {
+ SRC("gl_FragColor = texColor;");
+ } else if (mask_mode_ != NO_MASK) {
+ if (mask_for_background_)
+ SRC("gl_FragColor = ApplyBlendMode(texColor, maskColor.w);");
+ else
+ SRC("gl_FragColor = ApplyBlendMode(texColor);");
+ } else {
+ SRC("gl_FragColor = ApplyBlendMode(texColor);");
+ }
break;
}
source += "}\n";
diff --git a/chromium/components/viz/service/display/shader_unittest.cc b/chromium/components/viz/service/display/shader_unittest.cc
index c05da251fe5..6990cbf14de 100644
--- a/chromium/components/viz/service/display/shader_unittest.cc
+++ b/chromium/components/viz/service/display/shader_unittest.cc
@@ -4,8 +4,8 @@
#include "components/viz/service/display/shader.h"
+#include "components/viz/test/test_context_provider.h"
#include "components/viz/test/test_gles2_interface.h"
-#include "components/viz/test/test_web_graphics_context_3d.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
@@ -13,12 +13,11 @@
namespace viz {
TEST(ShaderTest, HighpThresholds) {
- // The test context always uses a mediump precision of 10 bits which
+ // The test gl always uses a mediump precision of 10 bits which
// corresponds to a native highp threshold of 2^10 = 1024
- std::unique_ptr<TestWebGraphicsContext3D> test_context =
- TestWebGraphicsContext3D::Create();
- TestGLES2Interface test_gl;
- test_gl.set_test_context(test_context.get());
+ scoped_refptr<TestContextProvider> provider = TestContextProvider::Create();
+ provider->BindToCurrentThread();
+ gpu::gles2::GLES2Interface* test_gl = provider->ContextGL();
int threshold_cache = 0;
int threshold_min;
@@ -29,30 +28,30 @@ TEST(ShaderTest, HighpThresholds) {
threshold_min = 0;
EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
closePoint));
EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
smallSize));
EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
farPoint));
EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
bigSize));
threshold_min = 3000;
EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
closePoint));
EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
smallSize));
EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
farPoint));
EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
- TexCoordPrecisionRequired(&test_gl, &threshold_cache, threshold_min,
+ TexCoordPrecisionRequired(test_gl, &threshold_cache, threshold_min,
bigSize));
}
diff --git a/chromium/components/viz/service/display/skia_output_surface.cc b/chromium/components/viz/service/display/skia_output_surface.cc
new file mode 100644
index 00000000000..abc0a6cdc1c
--- /dev/null
+++ b/chromium/components/viz/service/display/skia_output_surface.cc
@@ -0,0 +1,15 @@
+// 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 "components/viz/service/display/skia_output_surface.h"
+
+namespace viz {
+
+SkiaOutputSurface::SkiaOutputSurface(
+ scoped_refptr<ContextProvider> context_provider)
+ : OutputSurface(std::move(context_provider)) {}
+
+SkiaOutputSurface::~SkiaOutputSurface() = default;
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_output_surface.h b/chromium/components/viz/service/display/skia_output_surface.h
new file mode 100644
index 00000000000..a93bfc26d66
--- /dev/null
+++ b/chromium/components/viz/service/display/skia_output_surface.h
@@ -0,0 +1,98 @@
+// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_
+
+#include "components/viz/common/resources/resource_format.h"
+#include "components/viz/service/display/output_surface.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+
+class SkCanvas;
+class SkImage;
+
+namespace viz {
+
+struct ResourceMetadata;
+
+// This class extends the OutputSurface for SkiaRenderer needs. In future, the
+// SkiaRenderer will be the only renderer. When other renderers are removed,
+// we will replace OutputSurface with SkiaOutputSurface, and remove all
+// OutputSurface's methods which are not useful for SkiaRenderer.
+class VIZ_SERVICE_EXPORT SkiaOutputSurface : public OutputSurface {
+ public:
+ explicit SkiaOutputSurface(scoped_refptr<ContextProvider> context_provider);
+ ~SkiaOutputSurface() override;
+
+ // Get a SkCanvas for the current frame. The SkiaRenderer will use this
+ // SkCanvas to draw quads. This class retains the ownership of the SkCanvas,
+ // And this SkCanvas may become invalid, when the frame is swapped out.
+ virtual SkCanvas* GetSkCanvasForCurrentFrame() = 0;
+
+ // Make a promise SkImage from the given |metadata|. The SkiaRenderer can use
+ // the image with SkCanvas returned by |GetSkCanvasForCurrentFrame|, but Skia
+ // will not read the content of the resource until the sync token in the
+ // |metadata| is satisfied. The SwapBuffers should take care of this by
+ // scheduling a GPU task with all resource sync tokens recorded by
+ // MakePromiseSkImage for the current frame.
+ virtual sk_sp<SkImage> MakePromiseSkImage(ResourceMetadata metadata) = 0;
+
+ // Make a promise SkImage from the given |metadata| and the |yuv_color_space|.
+ // For YUV format, three resource metadatas should be provided. metadatas[0]
+ // contains pixels from y panel, metadatas[1] contains pixels from u panel,
+ // metadatas[2] contains pixels from v panel.
+ // For NV12 format, two resource metadatas should be provided. metadatas[0]
+ // contains pixels from y panel, metadatas[1] contains pixels from u and v
+ // panels.
+ virtual sk_sp<SkImage> MakePromiseSkImageFromYUV(
+ std::vector<ResourceMetadata> metadatas,
+ SkYUVColorSpace yuv_color_space) = 0;
+
+ // Swaps the current backbuffer to the screen and return a sync token which
+ // can be waited on in a command buffer to ensure the frame is completed. This
+ // token is released when the GPU ops from drawing the frame have been seen
+ // and processed by the GPU main.
+ // TODO(penghuang): replace OutputSurface::SwapBuffers with this method when
+ // SkiaRenderer and DDL are used everywhere.
+ virtual gpu::SyncToken SkiaSwapBuffers(OutputSurfaceFrame frame) = 0;
+
+ // Begin painting a render pass. This method will create a
+ // SkDeferredDisplayListRecorder and return a SkCanvas of it. The SkiaRenderer
+ // will use this SkCanvas to paint the render pass.
+ // Note: BeginPaintRenderPass cannot be called without finishing the prior
+ // paint render pass.
+ virtual SkCanvas* BeginPaintRenderPass(const RenderPassId& id,
+ const gfx::Size& size,
+ ResourceFormat format,
+ bool mipmap) = 0;
+
+ // Finish painting a render pass. It should be paired with
+ // BeginPaintRenderPass. This method will schedule a GPU task to play the DDL
+ // back on GPU thread on a cached SkSurface. This method returns a sync token
+ // which can be waited on in a command buffer to ensure the paint operation is
+ // completed. This token is released when the GPU ops from painting the render
+ // pass have been seen and processed by the GPU main.
+ virtual gpu::SyncToken FinishPaintRenderPass() = 0;
+
+ // Make a promise SkImage from a render pass id. The render pass has been
+ // painted with BeginPaintRenderPass and FinishPaintRenderPass. The format
+ // and mipmap must match arguments used for BeginPaintRenderPass() to paint
+ // this render pass.
+ virtual sk_sp<SkImage> MakePromiseSkImageFromRenderPass(
+ const RenderPassId& id,
+ const gfx::Size& size,
+ ResourceFormat format,
+ bool mipmap) = 0;
+
+ // Remove cached resources generated by BeginPaintRenderPass and
+ // FinishPaintRenderPass.
+ virtual void RemoveRenderPassResource(std::vector<RenderPassId> ids) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurface);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_OUTPUT_SURFACE_H_
diff --git a/chromium/components/viz/service/display/skia_renderer.cc b/chromium/components/viz/service/display/skia_renderer.cc
index 452b0146409..783fb7f778e 100644
--- a/chromium/components/viz/service/display/skia_renderer.cc
+++ b/chromium/components/viz/service/display/skia_renderer.cc
@@ -17,13 +17,16 @@
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/common/quads/yuv_video_draw_quad.h"
#include "components/viz/common/resources/platform_color.h"
#include "components/viz/common/resources/resource_fence.h"
#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/resource_metadata.h"
#include "components/viz/common/skia_helper.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display/output_surface_frame.h"
#include "components/viz/service/display/renderer_utils.h"
+#include "components/viz/service/display/skia_output_surface.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "skia/ext/opacity_filter_canvas.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -34,32 +37,20 @@
#include "third_party/skia/include/core/SkPath.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/include/effects/SkOverdrawColorFilter.h"
+#include "third_party/skia/include/effects/SkShaderMaskFilter.h"
#include "third_party/skia/include/gpu/GrBackendSurface.h"
-#include "third_party/skia/include/gpu/GrContext.h"
#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/transform.h"
-#if BUILDFLAG(ENABLE_VULKAN)
-#include "components/viz/common/gpu/vulkan_in_process_context_provider.h"
-#include "gpu/vulkan/vulkan_device_queue.h"
-#include "gpu/vulkan/vulkan_implementation.h"
-#include "gpu/vulkan/vulkan_surface.h"
-#include "gpu/vulkan/vulkan_swap_chain.h"
-#include "third_party/skia/include/gpu/GrContext.h"
-#include "third_party/skia/include/gpu/vk/GrVkBackendContext.h"
-#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
-#endif
-
namespace viz {
// Parameters needed to draw a RenderPassDrawQuad.
struct SkiaRenderer::DrawRenderPassDrawQuadParams {
// The "in" parameters that will be used when apply filters.
const cc::FilterOperations* filters = nullptr;
- const cc::FilterOperations* background_filters = nullptr;
- // The "out" parameters that will be returned for future use.
+ // The "out" parameters returned by filters.
// A Skia image that should be sampled from instead of the original
// contents.
sk_sp<SkImage> filter_image;
@@ -68,32 +59,141 @@ struct SkiaRenderer::DrawRenderPassDrawQuadParams {
gfx::RectF tex_coord_rect;
};
+namespace {
+
+bool IsTextureResource(DisplayResourceProvider* resource_provider,
+ ResourceId resource_id) {
+ return resource_provider->GetResourceType(resource_id) ==
+ ResourceType::kTexture;
+}
+
+} // namespace
+
+// Scoped helper class for building SkImage from resource id.
+class SkiaRenderer::ScopedSkImageBuilder {
+ public:
+ ScopedSkImageBuilder(SkiaRenderer* skia_renderer, ResourceId resource_id);
+ ~ScopedSkImageBuilder() = default;
+
+ const SkImage* sk_image() const { return sk_image_; }
+
+ private:
+ std::unique_ptr<DisplayResourceProvider::ScopedReadLockSkImage> lock_;
+ const SkImage* sk_image_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSkImageBuilder);
+};
+
+SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
+ SkiaRenderer* skia_renderer,
+ ResourceId resource_id) {
+ auto* resource_provider = skia_renderer->resource_provider_;
+ if (!skia_renderer->skia_output_surface_ ||
+ skia_renderer->non_root_surface_ ||
+ !IsTextureResource(resource_provider, resource_id)) {
+ // TODO(penghuang): remove this code when DDL is used everywhere.
+ lock_ = std::make_unique<DisplayResourceProvider::ScopedReadLockSkImage>(
+ resource_provider, resource_id);
+ sk_image_ = lock_->sk_image();
+ } else {
+ // Look up the image from promise_images_by resource_id and return the
+ // reference. If the resource_id doesn't exist, this statement will
+ // allocate it and return reference of it, and the reference will be used
+ // to store the new created image later.
+ auto& image = skia_renderer->promise_images_[resource_id];
+ if (!image) {
+ auto metadata =
+ skia_renderer->lock_set_for_external_use_.LockResource(resource_id);
+ DCHECK(!metadata.mailbox.IsZero());
+ image = skia_renderer->skia_output_surface_->MakePromiseSkImage(
+ std::move(metadata));
+ DCHECK(image);
+ }
+ sk_image_ = image.get();
+ }
+}
+
+class SkiaRenderer::ScopedYUVSkImageBuilder {
+ public:
+ ScopedYUVSkImageBuilder(SkiaRenderer* skia_renderer,
+ const YUVVideoDrawQuad* quad) {
+ DCHECK(skia_renderer->skia_output_surface_);
+ DCHECK(IsTextureResource(skia_renderer->resource_provider_,
+ quad->y_plane_resource_id()));
+ DCHECK(IsTextureResource(skia_renderer->resource_provider_,
+ quad->u_plane_resource_id()));
+ DCHECK(IsTextureResource(skia_renderer->resource_provider_,
+ quad->v_plane_resource_id()));
+ DCHECK(quad->a_plane_resource_id() == kInvalidResourceId ||
+ IsTextureResource(skia_renderer->resource_provider_,
+ quad->a_plane_resource_id()));
+
+ YUVIds ids(quad->y_plane_resource_id(), quad->u_plane_resource_id(),
+ quad->v_plane_resource_id(), quad->a_plane_resource_id());
+ auto& image = skia_renderer->yuv_promise_images_[std::move(ids)];
+
+ if (!image) {
+ auto yuv_color_space = kRec601_SkYUVColorSpace;
+ quad->video_color_space.ToSkYUVColorSpace(&yuv_color_space);
+
+ std::vector<ResourceMetadata> metadatas;
+ bool is_yuv = quad->u_plane_resource_id() != quad->v_plane_resource_id();
+ metadatas.reserve(is_yuv ? 3 : 2);
+ auto y_metadata = skia_renderer->lock_set_for_external_use_.LockResource(
+ quad->y_plane_resource_id());
+ metadatas.push_back(std::move(y_metadata));
+ auto u_metadata = skia_renderer->lock_set_for_external_use_.LockResource(
+ quad->u_plane_resource_id());
+ metadatas.push_back(std::move(u_metadata));
+ if (is_yuv) {
+ auto v_metadata =
+ skia_renderer->lock_set_for_external_use_.LockResource(
+ quad->v_plane_resource_id());
+ metadatas.push_back(std::move(v_metadata));
+ }
+
+ if (quad->a_plane_resource_id() != kInvalidResourceId) {
+ // TODO(penghuang): Handle alpha channel when Skia supports YUVA format.
+ NOTIMPLEMENTED();
+ }
+
+ image = skia_renderer->skia_output_surface_->MakePromiseSkImageFromYUV(
+ std::move(metadatas), yuv_color_space);
+ DCHECK(image);
+ }
+ sk_image_ = image.get();
+ }
+
+ ~ScopedYUVSkImageBuilder() = default;
+
+ const SkImage* sk_image() const { return sk_image_; }
+
+ private:
+ std::unique_ptr<DisplayResourceProvider::ScopedReadLockSkImage> lock_;
+ SkImage* sk_image_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedYUVSkImageBuilder);
+};
+
SkiaRenderer::SkiaRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
- : DirectRenderer(settings, output_surface, resource_provider) {
-#if BUILDFLAG(ENABLE_VULKAN)
- use_swap_with_bounds_ = false;
-#else
+ DisplayResourceProvider* resource_provider,
+ SkiaOutputSurface* skia_output_surface)
+ : DirectRenderer(settings, output_surface, resource_provider),
+ skia_output_surface_(skia_output_surface),
+ lock_set_for_external_use_(resource_provider) {
const auto& context_caps =
output_surface_->context_provider()->ContextCapabilities();
use_swap_with_bounds_ = context_caps.swap_buffers_with_bounds;
- if (context_caps.sync_query)
+ if (context_caps.sync_query) {
sync_queries_ = base::Optional<SyncQueryCollection>(
- output_surface->context_provider()->ContextGL());
-#endif
+ output_surface_->context_provider()->ContextGL());
+ }
}
-SkiaRenderer::~SkiaRenderer() {
-#if BUILDFLAG(ENABLE_VULKAN)
- return;
-#endif
-}
+SkiaRenderer::~SkiaRenderer() = default;
bool SkiaRenderer::CanPartialSwap() {
-#if BUILDFLAG(ENABLE_VULKAN)
- return false;
-#endif
if (use_swap_with_bounds_)
return false;
auto* context_provider = output_surface_->context_provider();
@@ -102,29 +202,28 @@ bool SkiaRenderer::CanPartialSwap() {
void SkiaRenderer::BeginDrawingFrame() {
TRACE_EVENT0("viz", "SkiaRenderer::BeginDrawingFrame");
-#if BUILDFLAG(ENABLE_VULKAN)
- return;
-#else
// Copied from GLRenderer.
scoped_refptr<ResourceFence> read_lock_fence;
if (sync_queries_) {
read_lock_fence = sync_queries_->StartNewFrame();
} else {
read_lock_fence =
- base::MakeRefCounted<cc::DisplayResourceProvider::SynchronousFence>(
+ base::MakeRefCounted<DisplayResourceProvider::SynchronousFence>(
output_surface_->context_provider()->ContextGL());
}
resource_provider_->SetReadLockFence(read_lock_fence.get());
- // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the frame,
- // so that drawing can proceed without GL context switching interruptions.
- for (const auto& pass : *current_frame()->render_passes_in_draw_order) {
- for (auto* quad : pass->quad_list) {
- for (ResourceId resource_id : quad->resources)
- resource_provider_->WaitSyncToken(resource_id);
+ if (!skia_output_surface_) {
+ // Insert WaitSyncTokenCHROMIUM on quad resources prior to drawing the
+ // frame, so that drawing can proceed without GL context switching
+ // interruptions.
+ for (const auto& pass : *current_frame()->render_passes_in_draw_order) {
+ for (auto* quad : pass->quad_list) {
+ for (ResourceId resource_id : quad->resources)
+ resource_provider_->WaitSyncToken(resource_id);
+ }
}
}
-#endif
}
void SkiaRenderer::FinishDrawingFrame() {
@@ -154,12 +253,14 @@ void SkiaRenderer::FinishDrawingFrame() {
swap_content_bounds_ = current_frame()->root_content_bounds;
}
-void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
+void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) {
DCHECK(visible_);
TRACE_EVENT0("cc,benchmark", "SkiaRenderer::SwapBuffers");
OutputSurfaceFrame output_frame;
output_frame.latency_info = std::move(latency_info);
output_frame.size = surface_size_for_swap_buffers();
+ output_frame.need_presentation_feedback = need_presentation_feedback;
if (use_swap_with_bounds_) {
output_frame.content_bounds = std::move(swap_content_bounds_);
} else if (use_partial_swap_) {
@@ -168,7 +269,17 @@ void SkiaRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
} else if (swap_buffer_rect_.IsEmpty() && allow_empty_swap_) {
output_frame.sub_buffer_rect = swap_buffer_rect_;
}
- output_surface_->SwapBuffers(std::move(output_frame));
+
+ if (skia_output_surface_) {
+ auto sync_token =
+ skia_output_surface_->SkiaSwapBuffers(std::move(output_frame));
+ promise_images_.clear();
+ yuv_promise_images_.clear();
+ lock_set_for_external_use_.UnlockResources(sync_token);
+ } else {
+ // TODO(penghuang): remove it when SkiaRenderer and SkDDL are always used.
+ output_surface_->SwapBuffers(std::move(output_frame));
+ }
swap_buffer_rect_ = gfx::Rect();
}
@@ -195,36 +306,16 @@ void SkiaRenderer::BindFramebufferToOutputSurface() {
SkSurfaceProps surface_props =
SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
-#if BUILDFLAG(ENABLE_VULKAN)
- gpu::VulkanSurface* vulkan_surface = output_surface_->GetVulkanSurface();
- gpu::VulkanSwapChain* swap_chain = vulkan_surface->GetSwapChain();
- VkImage image = swap_chain->GetCurrentImage(swap_chain->current_image());
-
- GrVkImageInfo info_;
- info_.fImage = image;
- info_.fAlloc = {VK_NULL_HANDLE, 0, 0, 0};
- info_.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- info_.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
- info_.fFormat = VK_FORMAT_B8G8R8A8_UNORM;
- info_.fLevelCount = 1;
-
- GrBackendRenderTarget render_target(
- current_frame()->device_viewport_size.width(),
- current_frame()->device_viewport_size.height(), 0, 0, info_);
-
- GrContext* gr_context =
- output_surface_->vulkan_context_provider()->GetGrContext();
- root_surface_ = SkSurface::MakeFromBackendRenderTarget(
- gr_context, render_target, kTopLeft_GrSurfaceOrigin,
- kBGRA_8888_SkColorType, nullptr, &surface_props);
-#else
// TODO(weiliangc): Set up correct can_use_lcd_text for SkSurfaceProps flags.
// How to setup is in ResourceProvider. (http://crbug.com/644851)
GrContext* gr_context = output_surface_->context_provider()->GrContext();
- if (!root_canvas_ || root_canvas_->getGrContext() != gr_context ||
- gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) !=
- current_frame()->device_viewport_size) {
+ if (skia_output_surface_) {
+ root_canvas_ = skia_output_surface_->GetSkCanvasForCurrentFrame();
+ DCHECK(root_canvas_);
+ } else if (!root_canvas_ || root_canvas_->getGrContext() != gr_context ||
+ gfx::SkISizeToSize(root_canvas_->getBaseLayerSize()) !=
+ current_frame()->device_viewport_size) {
// Either no SkSurface setup yet, or new GrContext, need to create new
// surface.
GrGLFramebufferInfo framebuffer_info;
@@ -237,13 +328,12 @@ void SkiaRenderer::BindFramebufferToOutputSurface() {
root_surface_ = SkSurface::MakeFromBackendRenderTarget(
gr_context, render_target, kBottomLeft_GrSurfaceOrigin,
kRGB_888x_SkColorType, nullptr, &surface_props);
+ root_canvas_ = root_surface_->getCanvas();
}
-#endif
- root_canvas_ = root_surface_->getCanvas();
if (settings_->show_overdraw_feedback) {
- const gfx::Size size(root_surface_->width(), root_surface_->height());
- overdraw_surface_ = root_surface_->makeSurface(
+ const auto& size = current_frame()->device_viewport_size;
+ overdraw_surface_ = root_canvas_->makeSurface(
SkImageInfo::MakeA8(size.width(), size.height()));
nway_canvas_ = std::make_unique<SkNWayCanvas>(size.width(), size.height());
overdraw_canvas_ =
@@ -264,9 +354,16 @@ void SkiaRenderer::BindFramebufferToTexture(const RenderPassId render_pass_id) {
// This function is called after AllocateRenderPassResourceIfNeeded, so there
// should be backing ready.
RenderPassBacking& backing = iter->second;
- non_root_surface_ = backing.render_pass_surface;
- current_canvas_ = non_root_surface_->getCanvas();
- current_surface_ = non_root_surface_.get();
+ if (skia_output_surface_) {
+ non_root_surface_ = nullptr;
+ current_canvas_ = skia_output_surface_->BeginPaintRenderPass(
+ render_pass_id, backing.size, backing.format, backing.mipmap);
+ } else {
+ non_root_surface_ = backing.render_pass_surface;
+ current_surface_ = non_root_surface_.get();
+ current_canvas_ = non_root_surface_->getCanvas();
+ }
+ is_drawing_render_pass_ = true;
}
void SkiaRenderer::SetScissorTestRect(const gfx::Rect& scissor_rect) {
@@ -420,8 +517,15 @@ void SkiaRenderer::DoDrawQuad(const DrawQuad* quad,
// reaching a direct renderer.
NOTREACHED();
break;
- case DrawQuad::INVALID:
case DrawQuad::YUV_VIDEO_CONTENT:
+ if (skia_output_surface_) {
+ DrawYUVVideoQuad(YUVVideoDrawQuad::MaterialCast(quad));
+ } else {
+ DrawUnsupportedQuad(quad);
+ NOTIMPLEMENTED();
+ }
+ break;
+ case DrawQuad::INVALID:
case DrawQuad::STREAM_VIDEO_CONTENT:
DrawUnsupportedQuad(quad);
NOTREACHED();
@@ -509,10 +613,8 @@ void SkiaRenderer::DrawSolidColorQuad(const SolidColorDrawQuad* quad) {
}
void SkiaRenderer::DrawTextureQuad(const TextureDrawQuad* quad) {
- // TODO(skaslev): Add support for non-premultiplied alpha.
- cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
- quad->resource_id());
- const SkImage* image = lock.sk_image();
+ ScopedSkImageBuilder builder(this, quad->resource_id());
+ const SkImage* image = builder.sk_image();
if (!image)
return;
gfx::RectF uv_rect = gfx::ScaleRect(
@@ -551,9 +653,9 @@ void SkiaRenderer::DrawTileQuad(const TileDrawQuad* quad) {
// |resource_provider_| can be NULL in resourceless software draws, which
// should never produce tile quads in the first place.
DCHECK(resource_provider_);
- cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
- quad->resource_id());
- if (!lock.sk_image())
+ ScopedSkImageBuilder builder(this, quad->resource_id());
+ const SkImage* image = builder.sk_image();
+ if (!image)
return;
gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional(
quad->tex_coord_rect, gfx::RectF(quad->rect),
@@ -564,7 +666,27 @@ void SkiaRenderer::DrawTileQuad(const TileDrawQuad* quad) {
SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
current_paint_.setFilterQuality(
quad->nearest_neighbor ? kNone_SkFilterQuality : kLow_SkFilterQuality);
- current_canvas_->drawImageRect(lock.sk_image(), uv_rect,
+ current_canvas_->drawImageRect(image, uv_rect,
+ gfx::RectFToSkRect(visible_quad_vertex_rect),
+ &current_paint_);
+}
+
+void SkiaRenderer::DrawYUVVideoQuad(const YUVVideoDrawQuad* quad) {
+ DCHECK(resource_provider_);
+ ScopedYUVSkImageBuilder builder(this, quad);
+ const SkImage* image = builder.sk_image();
+ if (!image)
+ return;
+ gfx::RectF visible_tex_coord_rect = cc::MathUtil::ScaleRectProportional(
+ quad->ya_tex_coord_rect, gfx::RectF(quad->rect),
+ gfx::RectF(quad->visible_rect));
+ gfx::RectF visible_quad_vertex_rect = cc::MathUtil::ScaleRectProportional(
+ QuadVertexRect(), gfx::RectF(quad->rect), gfx::RectF(quad->visible_rect));
+
+ SkRect uv_rect = gfx::RectFToSkRect(visible_tex_coord_rect);
+ // TODO(penghuang): figure out how to set correct filter quality.
+ current_paint_.setFilterQuality(kLow_SkFilterQuality);
+ current_canvas_->drawImageRect(image, uv_rect,
gfx::RectFToSkRect(visible_quad_vertex_rect),
&current_paint_);
}
@@ -582,10 +704,8 @@ bool SkiaRenderer::CalculateRPDQParams(sk_sp<SkImage> content,
// should be backing ready.
RenderPassBacking& content_texture = iter->second;
DCHECK(!params->filters->IsEmpty());
- gfx::Size size(content_texture.render_pass_surface->width(),
- content_texture.render_pass_surface->height());
auto paint_filter = cc::RenderSurfaceFilters::BuildImageFilter(
- *params->filters, gfx::SizeF(size));
+ *params->filters, gfx::SizeF(content_texture.size));
auto filter = paint_filter ? paint_filter->cached_sk_filter_ : nullptr;
// Apply filters to the content texture.
@@ -641,17 +761,20 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
DCHECK(render_pass_backings_.end() != iter);
// This function is called after AllocateRenderPassResourceIfNeeded, so there
// should be backing ready.
- RenderPassBacking& content_texture = iter->second;
+ RenderPassBacking& backing = iter->second;
// TODO(weiliangc): GL Renderer has optimization that when Render Pass has a
// single quad inside we would draw that directly. We could add similar
// optimization here by using the quad's SkImage.
sk_sp<SkImage> content =
- content_texture.render_pass_surface->makeImageSnapshot();
+ skia_output_surface_
+ ? skia_output_surface_->MakePromiseSkImageFromRenderPass(
+ quad->render_pass_id, backing.size, backing.format,
+ backing.mipmap)
+ : backing.render_pass_surface->makeImageSnapshot();
DrawRenderPassDrawQuadParams params;
params.filters = FiltersForPass(quad->render_pass_id);
- params.background_filters = BackgroundFiltersForPass(quad->render_pass_id);
bool can_draw = CalculateRPDQParams(content, quad, &params);
if (!can_draw)
@@ -670,8 +793,6 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
QuadVertexRect(), gfx::RectF(quad->rect),
gfx::RectF(quad->visible_rect)));
}
- current_canvas_->drawImageRect(content, content_rect, dest_visible_rect,
- &current_paint_);
SkRect dest_rect = gfx::RectFToSkRect(QuadVertexRect());
@@ -680,20 +801,42 @@ void SkiaRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
SkMatrix::kFill_ScaleToFit);
sk_sp<SkShader> shader;
- shader = content->makeShader(SkShader::kClamp_TileMode,
- SkShader::kClamp_TileMode, &content_mat);
+ shader = content->makeShader(&content_mat);
- // TODO(weiliangc): Implement mask. (https://crbug.com/644851)
if (quad->mask_resource_id()) {
- NOTIMPLEMENTED();
+ ScopedSkImageBuilder builder(this, quad->mask_resource_id());
+ const SkImage* image = builder.sk_image();
+ if (!image)
+ return;
+
+ // Scale normalized uv rect into absolute texel coordinates.
+ SkRect mask_rect = gfx::RectFToSkRect(
+ gfx::ScaleRect(quad->mask_uv_rect, quad->mask_texture_size.width(),
+ quad->mask_texture_size.height()));
+
+ SkMatrix mask_mat;
+ mask_mat.setRectToRect(mask_rect, dest_rect, SkMatrix::kFill_ScaleToFit);
+ current_paint_.setMaskFilter(
+ SkShaderMaskFilter::Make((image->makeShader(&mask_mat))));
+ current_paint_.setShader(std::move(shader));
+ current_canvas_->drawRect(dest_visible_rect, current_paint_);
+ return;
}
- // TODO(weiliangc): If we have a background filter shader, render its
- // results first. (https://crbug.com/644851)
- if (ShouldApplyBackgroundFilters(quad, params.background_filters)) {
+ // If we have a background filter shader, render its results first.
+ sk_sp<SkShader> background_filter_shader =
+ GetBackgroundFilterShader(quad, SkShader::kClamp_TileMode);
+ if (background_filter_shader) {
+ SkPaint paint;
+ paint.setShader(std::move(background_filter_shader));
+ paint.setMaskFilter(current_paint_.refMaskFilter());
+ current_canvas_->drawRect(dest_visible_rect, paint);
current_paint_.setShader(std::move(shader));
current_canvas_->drawRect(dest_visible_rect, current_paint_);
+ return;
}
+ current_canvas_->drawImageRect(content, content_rect, dest_visible_rect,
+ &current_paint_);
}
void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad) {
@@ -714,6 +857,12 @@ void SkiaRenderer::CopyDrawnRenderPass(
// TODO(weiliangc): Make copy request work. (crbug.com/644851)
TRACE_EVENT0("viz", "SkiaRenderer::CopyDrawnRenderPass");
+ if (skia_output_surface_) {
+ // TODO(penghuang): Support it with SkDDL.
+ NOTIMPLEMENTED();
+ return;
+ }
+
gfx::Rect copy_rect = current_frame()->current_render_pass->output_rect;
if (request->has_area())
copy_rect.Intersect(request->area());
@@ -752,7 +901,17 @@ void SkiaRenderer::DidChangeVisibility() {
}
void SkiaRenderer::FinishDrawingQuadList() {
- current_canvas_->flush();
+ if (skia_output_surface_) {
+ if (is_drawing_render_pass_) {
+ gpu::SyncToken sync_token = skia_output_surface_->FinishPaintRenderPass();
+ promise_images_.clear();
+ yuv_promise_images_.clear();
+ lock_set_for_external_use_.UnlockResources(sync_token);
+ is_drawing_render_pass_ = false;
+ }
+ } else {
+ current_canvas_->flush();
+ }
}
void SkiaRenderer::GenerateMipmap() {
@@ -773,20 +932,17 @@ bool SkiaRenderer::ShouldApplyBackgroundFilters(
return true;
}
-SkBitmap SkiaRenderer::GetBackdropBitmap(const gfx::Rect& bounding_rect) const {
- SkBitmap bitmap;
- bitmap.allocPixels(SkImageInfo::MakeN32Premul(bounding_rect.width(),
- bounding_rect.height()));
- if (!current_canvas_->readPixels(bitmap, bounding_rect.x(),
- bounding_rect.y()))
- bitmap.reset();
- return bitmap;
+sk_sp<SkImage> SkiaRenderer::GetBackdropImage(
+ const gfx::Rect& bounding_rect) const {
+ return root_surface_->makeImageSnapshot()->makeSubset(
+ gfx::RectToSkIRect(bounding_rect));
}
gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad(
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
- const cc::FilterOperations* background_filters) const {
+ const cc::FilterOperations* background_filters,
+ gfx::Rect* unclipped_rect) const {
DCHECK(ShouldApplyBackgroundFilters(quad, background_filters));
gfx::Rect backdrop_rect = gfx::ToEnclosingRect(cc::MathUtil::MapClippedRect(
contents_device_transform, QuadVertexRect()));
@@ -795,18 +951,105 @@ gfx::Rect SkiaRenderer::GetBackdropBoundingBoxForRenderPassQuad(
matrix.setScale(quad->filters_scale.x(), quad->filters_scale.y());
backdrop_rect = background_filters->MapRectReverse(backdrop_rect, matrix);
+ *unclipped_rect = backdrop_rect;
backdrop_rect.Intersect(MoveFromDrawToWindowSpace(
current_frame()->current_render_pass->output_rect));
return backdrop_rect;
}
+// If non-null, auto_bounds will be filled with the automatically-computed
+// destination bounds. If null, the output will be the same size as the
+// input image.
+sk_sp<SkImage> SkiaRenderer::ApplyBackgroundFilters(
+ SkImageFilter* filter,
+ const RenderPassDrawQuad* quad,
+ sk_sp<SkImage> src_image,
+ const gfx::Rect& rect) const {
+ if (!filter)
+ return nullptr;
+
+ SkMatrix local_matrix;
+ local_matrix.setTranslate(quad->filters_origin.x(), quad->filters_origin.y());
+ local_matrix.postScale(quad->filters_scale.x(), quad->filters_scale.y());
+
+ SkImageInfo image_info =
+ SkImageInfo::Make(rect.width(), rect.height(), src_image->colorType(),
+ src_image->alphaType(), nullptr);
+
+ GrContext* gr_context = output_surface_->context_provider()->GrContext();
+ // TODO(weiliangc): Set up correct can_use_lcd_text for SkSurfaceProps flags.
+ // How to setup is in ResourceProvider. (http://crbug.com/644851)
+ // LegacyFontHost will get LCD text and skia figures out what type to use.
+ SkSurfaceProps surface_props(0, SkSurfaceProps::kLegacyFontHost_InitType);
+ sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(
+ gr_context, SkBudgeted::kNo, image_info, 0, kBottomLeft_GrSurfaceOrigin,
+ &surface_props, false);
+
+ if (!surface) {
+ return nullptr;
+ }
+
+ SkPaint paint;
+ // Treat subnormal float values as zero for performance.
+ cc::ScopedSubnormalFloatDisabler disabler;
+ paint.setImageFilter(filter->makeWithLocalMatrix(local_matrix));
+ surface->getCanvas()->translate(-rect.x(), -rect.y());
+ surface->getCanvas()->drawImage(src_image, rect.x(), rect.y(), &paint);
+
+ return surface->makeImageSnapshot();
+}
+
sk_sp<SkShader> SkiaRenderer::GetBackgroundFilterShader(
const RenderPassDrawQuad* quad,
SkShader::TileMode content_tile_mode) const {
- // TODO(weiliangc): properly implement background filters. (crbug.com/644851)
- NOTIMPLEMENTED();
- return nullptr;
+ const cc::FilterOperations* background_filters =
+ BackgroundFiltersForPass(quad->render_pass_id);
+ if (!ShouldApplyBackgroundFilters(quad, background_filters))
+ return nullptr;
+
+ gfx::Transform quad_rect_matrix;
+ QuadRectTransform(&quad_rect_matrix,
+ quad->shared_quad_state->quad_to_target_transform,
+ gfx::RectF(quad->rect));
+ gfx::Transform contents_device_transform =
+ current_frame()->window_matrix * current_frame()->projection_matrix *
+ quad_rect_matrix;
+ contents_device_transform.FlattenTo2d();
+
+ gfx::Rect unclipped_rect;
+ gfx::Rect backdrop_rect = GetBackdropBoundingBoxForRenderPassQuad(
+ quad, contents_device_transform, background_filters, &unclipped_rect);
+
+ // Figure out the transformations to move it back to pixel space.
+ gfx::Transform contents_device_transform_inverse;
+ if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
+ return nullptr;
+
+ SkMatrix filter_backdrop_transform =
+ contents_device_transform_inverse.matrix();
+ filter_backdrop_transform.preTranslate(backdrop_rect.x(), backdrop_rect.y());
+
+ // Apply the filter to the backdrop.
+ sk_sp<SkImage> backdrop_image = GetBackdropImage(backdrop_rect);
+
+ gfx::Vector2dF clipping_offset =
+ (unclipped_rect.top_right() - backdrop_rect.top_right()) +
+ (backdrop_rect.bottom_left() - unclipped_rect.bottom_left());
+ sk_sp<SkImageFilter> filter =
+ cc::RenderSurfaceFilters::BuildImageFilter(
+ *background_filters,
+ gfx::SizeF(backdrop_image->width(), backdrop_image->height()),
+ clipping_offset)
+ ->cached_sk_filter_;
+ sk_sp<SkImage> filter_backdrop_image =
+ ApplyBackgroundFilters(filter.get(), quad, backdrop_image, backdrop_rect);
+
+ if (!filter_backdrop_image)
+ return nullptr;
+
+ return filter_backdrop_image->makeShader(content_tile_mode, content_tile_mode,
+ &filter_backdrop_transform);
}
void SkiaRenderer::UpdateRenderPassTextures(
@@ -823,10 +1066,8 @@ void SkiaRenderer::UpdateRenderPassTextures(
const RenderPassRequirements& requirements = render_pass_it->second;
const RenderPassBacking& backing = pair.second;
- SkSurface* backing_surface = pair.second.render_pass_surface.get();
- bool size_appropriate =
- backing_surface->width() >= requirements.size.width() &&
- backing_surface->height() >= requirements.size.height();
+ bool size_appropriate = backing.size.width() >= requirements.size.width() &&
+ backing.size.height() >= requirements.size.height();
bool mipmap_appropriate = !requirements.mipmap || backing.mipmap;
if (!size_appropriate || !mipmap_appropriate)
passes_to_delete.push_back(pair.first);
@@ -838,6 +1079,10 @@ void SkiaRenderer::UpdateRenderPassTextures(
auto it = render_pass_backings_.find(passes_to_delete[i]);
render_pass_backings_.erase(it);
}
+
+ if (skia_output_surface_ && !passes_to_delete.empty()) {
+ skia_output_surface_->RemoveRenderPassResource(std::move(passes_to_delete));
+ }
}
void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
@@ -847,32 +1092,30 @@ void SkiaRenderer::AllocateRenderPassResourceIfNeeded(
if (it != render_pass_backings_.end())
return;
-#if BUILDFLAG(ENABLE_VULKAN)
- GrContext* gr_context =
- output_surface_->vulkan_context_provider()->GetGrContext();
// TODO(penghuang): check supported format correctly.
- bool capability_bgra8888 = true;
-#else
- ContextProvider* context_provider = output_surface_->context_provider();
- bool capability_bgra8888 =
- context_provider->ContextCapabilities().texture_format_bgra8888;
- GrContext* gr_context = context_provider->GrContext();
-#endif
+ gpu::Capabilities caps;
+ caps.texture_format_bgra8888 = true;
+ GrContext* gr_context = nullptr;
+ if (!skia_output_surface_) {
+ ContextProvider* context_provider = output_surface_->context_provider();
+ caps.texture_format_bgra8888 =
+ context_provider->ContextCapabilities().texture_format_bgra8888;
+ gr_context = context_provider->GrContext();
+ }
render_pass_backings_.insert(std::pair<RenderPassId, RenderPassBacking>(
render_pass_id,
- RenderPassBacking(gr_context, requirements.size, requirements.mipmap,
- capability_bgra8888,
+ RenderPassBacking(gr_context, caps, requirements.size,
+ requirements.mipmap,
current_frame()->current_render_pass->color_space)));
}
SkiaRenderer::RenderPassBacking::RenderPassBacking(
GrContext* gr_context,
+ const gpu::Capabilities& caps,
const gfx::Size& size,
bool mipmap,
- bool capability_bgra8888,
const gfx::ColorSpace& color_space)
- : mipmap(mipmap), color_space(color_space) {
- ResourceFormat format;
+ : size(size), mipmap(mipmap), color_space(color_space) {
if (color_space.IsHDR()) {
// If a platform does not support half-float renderbuffers then it should
// not should request HDR rendering.
@@ -880,14 +1123,20 @@ SkiaRenderer::RenderPassBacking::RenderPassBacking(
// DCHECK(caps.color_buffer_half_float_rgba);
format = RGBA_F16;
} else {
- format = PlatformColor::BestSupportedTextureFormat(capability_bgra8888);
+ format = PlatformColor::BestSupportedTextureFormat(caps);
}
- SkColorType color_type = ResourceFormatToClosestSkColorType(format);
+
+ // For DDL, we don't need create teh render_pass_surface here, and we will
+ // create the SkSurface by SkiaOutputSurface on Gpu thread.
+ if (!gr_context)
+ return;
constexpr uint32_t flags = 0;
// LegacyFontHost will get LCD text and skia figures out what type to use.
SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
int msaa_sample_count = 0;
+ SkColorType color_type =
+ ResourceFormatToClosestSkColorType(true /* gpu_compositing*/, format);
SkImageInfo image_info = SkImageInfo::Make(
size.width(), size.height(), color_type, kPremul_SkAlphaType, nullptr);
render_pass_surface = SkSurface::MakeRenderTarget(
@@ -899,15 +1148,20 @@ SkiaRenderer::RenderPassBacking::~RenderPassBacking() {}
SkiaRenderer::RenderPassBacking::RenderPassBacking(
SkiaRenderer::RenderPassBacking&& other)
- : mipmap(other.mipmap), color_space(other.color_space) {
+ : size(other.size),
+ mipmap(other.mipmap),
+ color_space(other.color_space),
+ format(other.format) {
render_pass_surface = other.render_pass_surface;
other.render_pass_surface = nullptr;
}
SkiaRenderer::RenderPassBacking& SkiaRenderer::RenderPassBacking::operator=(
SkiaRenderer::RenderPassBacking&& other) {
+ size = other.size;
mipmap = other.mipmap;
color_space = other.color_space;
+ format = other.format;
render_pass_surface = other.render_pass_surface;
other.render_pass_surface = nullptr;
return *this;
@@ -923,8 +1177,7 @@ gfx::Size SkiaRenderer::GetRenderPassBackingPixelSize(
const RenderPassId& render_pass_id) {
auto it = render_pass_backings_.find(render_pass_id);
DCHECK(it != render_pass_backings_.end());
- SkSurface* texture = it->second.render_pass_surface.get();
- return gfx::Size(texture->width(), texture->height());
+ return it->second.size;
}
} // namespace viz
diff --git a/chromium/components/viz/service/display/skia_renderer.h b/chromium/components/viz/service/display/skia_renderer.h
index 08a8a3de61d..63fdef52ea9 100644
--- a/chromium/components/viz/service/display/skia_renderer.h
+++ b/chromium/components/viz/service/display/skia_renderer.h
@@ -5,37 +5,41 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_SKIA_RENDERER_H_
+#include <tuple>
+
#include "base/macros.h"
#include "cc/cc_export.h"
#include "components/viz/service/display/direct_renderer.h"
#include "components/viz/service/display/sync_query_collection.h"
#include "components/viz/service/viz_service_export.h"
-#include "gpu/vulkan/buildflags.h"
#include "ui/latency/latency_info.h"
class SkNWayCanvas;
-namespace cc {
-class OutputSurface;
-class RenderPassDrawQuad;
-} // namespace cc
+namespace gpu {
+struct Capabilities;
+}
namespace viz {
class DebugBorderDrawQuad;
class PictureDrawQuad;
+class SkiaOutputSurface;
class SolidColorDrawQuad;
class TextureDrawQuad;
class TileDrawQuad;
+class YUVVideoDrawQuad;
class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
public:
+ // TODO(penghuang): Remove skia_output_surface when DDL is used everywhere.
SkiaRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider);
-
+ DisplayResourceProvider* resource_provider,
+ SkiaOutputSurface* skia_output_surface = nullptr);
~SkiaRenderer() override;
- void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
+ void SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) override;
void SetDisablePictureQuadImageFiltering(bool disable) {
disable_picture_quad_image_filtering_ = disable;
@@ -73,6 +77,8 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
private:
struct DrawRenderPassDrawQuadParams;
+ class ScopedSkImageBuilder;
+ class ScopedYUVSkImageBuilder;
void ClearCanvas(SkColor color);
void ClearFramebuffer();
@@ -84,6 +90,7 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
void DrawSolidColorQuad(const SolidColorDrawQuad* quad);
void DrawTextureQuad(const TextureDrawQuad* quad);
void DrawTileQuad(const TileDrawQuad* quad);
+ void DrawYUVVideoQuad(const YUVVideoDrawQuad* quad);
void DrawUnsupportedQuad(const DrawQuad* quad);
bool CalculateRPDQParams(sk_sp<SkImage> src_image,
const RenderPassDrawQuad* quad,
@@ -95,8 +102,14 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform,
- const cc::FilterOperations* background_filters) const;
- SkBitmap GetBackdropBitmap(const gfx::Rect& bounding_rect) const;
+ const cc::FilterOperations* background_filters,
+ gfx::Rect* unclipped_rect) const;
+ sk_sp<SkImage> ApplyBackgroundFilters(SkImageFilter* filter,
+ const RenderPassDrawQuad* quad,
+ sk_sp<SkImage> src_image,
+ const gfx::Rect& rect) const;
+
+ sk_sp<SkImage> GetBackdropImage(const gfx::Rect& bounding_rect) const;
sk_sp<SkShader> GetBackgroundFilterShader(
const RenderPassDrawQuad* quad,
SkShader::TileMode content_tile_mode) const;
@@ -104,12 +117,14 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
// A map from RenderPass id to the texture used to draw the RenderPass from.
struct RenderPassBacking {
sk_sp<SkSurface> render_pass_surface;
+ gfx::Size size;
bool mipmap;
gfx::ColorSpace color_space;
+ ResourceFormat format;
RenderPassBacking(GrContext* gr_context,
+ const gpu::Capabilities& caps,
const gfx::Size& size,
bool mipmap,
- bool capability_bgra8888,
const gfx::ColorSpace& color_space);
~RenderPassBacking();
RenderPassBacking(RenderPassBacking&&);
@@ -117,11 +132,13 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
};
base::flat_map<RenderPassId, RenderPassBacking> render_pass_backings_;
+ SkiaOutputSurface* const skia_output_surface_ = nullptr;
bool disable_picture_quad_image_filtering_ = false;
-
bool is_scissor_enabled_ = false;
+
gfx::Rect scissor_rect_;
+ bool is_drawing_render_pass_ = false;
sk_sp<SkSurface> root_surface_;
sk_sp<SkSurface> non_root_surface_;
sk_sp<SkSurface> overdraw_surface_;
@@ -138,6 +155,22 @@ class VIZ_SERVICE_EXPORT SkiaRenderer : public DirectRenderer {
gfx::Rect swap_buffer_rect_;
std::vector<gfx::Rect> swap_content_bounds_;
+ // Lock set for resources that are used for the current frame. All resources
+ // in this set will be unlocked with a sync token when the frame is done in
+ // the compositor thread. And the sync token will be released when the DDL
+ // for the current frame is replayed on the GPU thread.
+ // It is only used with DDL.
+ DisplayResourceProvider::LockSetForExternalUse lock_set_for_external_use_;
+
+ // Promise images created from resources used in the current frame. This map
+ // will be cleared when the frame is done and before all resources in
+ // |lock_set_for_external_use_| are unlocked on the compositor thread.
+ // It is only used with DDL.
+ base::flat_map<ResourceId, sk_sp<SkImage>> promise_images_;
+
+ using YUVIds = std::tuple<ResourceId, ResourceId, ResourceId, ResourceId>;
+ base::flat_map<YUVIds, sk_sp<SkImage>> yuv_promise_images_;
+
DISALLOW_COPY_AND_ASSIGN(SkiaRenderer);
};
diff --git a/chromium/components/viz/service/display/software_output_device.cc b/chromium/components/viz/service/display/software_output_device.cc
index 7f8e8fd8504..6508266d977 100644
--- a/chromium/components/viz/service/display/software_output_device.cc
+++ b/chromium/components/viz/service/display/software_output_device.cc
@@ -5,14 +5,27 @@
#include "components/viz/service/display/software_output_device.h"
#include "base/logging.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/vsync_provider.h"
namespace viz {
-SoftwareOutputDevice::SoftwareOutputDevice() = default;
+SoftwareOutputDevice::SoftwareOutputDevice()
+ : SoftwareOutputDevice(base::SequencedTaskRunnerHandle::Get()) {}
+
+SoftwareOutputDevice::SoftwareOutputDevice(
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : task_runner_(std::move(task_runner)) {}
+
SoftwareOutputDevice::~SoftwareOutputDevice() = default;
+void SoftwareOutputDevice::BindToClient(SoftwareOutputDeviceClient* client) {
+ DCHECK(client);
+ DCHECK(!client_);
+ client_ = client;
+}
+
void SoftwareOutputDevice::Resize(const gfx::Size& viewport_pixel_size,
float scale_factor) {
if (viewport_pixel_size_ == viewport_pixel_size)
@@ -36,4 +49,8 @@ gfx::VSyncProvider* SoftwareOutputDevice::GetVSyncProvider() {
return vsync_provider_.get();
}
+void SoftwareOutputDevice::OnSwapBuffers(base::OnceClosure swap_ack_callback) {
+ task_runner_->PostTask(FROM_HERE, std::move(swap_ack_callback));
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display/software_output_device.h b/chromium/components/viz/service/display/software_output_device.h
index 63e233deb7d..ac80d97157e 100644
--- a/chromium/components/viz/service/display/software_output_device.h
+++ b/chromium/components/viz/service/display/software_output_device.h
@@ -7,7 +7,10 @@
#include <memory>
+#include "base/callback.h"
#include "base/macros.h"
+#include "base/sequenced_task_runner.h"
+#include "components/viz/service/display/software_output_device_client.h"
#include "components/viz/service/viz_service_export.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/gfx/geometry/rect.h"
@@ -18,17 +21,25 @@ class SkCanvas;
namespace gfx {
class VSyncProvider;
-}
+} // namespace gfx
namespace viz {
+class SoftwareOutputDeviceClient;
+
// This is a "tear-off" class providing software drawing support to
// OutputSurface, such as to a platform-provided window framebuffer.
class VIZ_SERVICE_EXPORT SoftwareOutputDevice {
public:
+ // Uses TaskRunner returned from SequencedTaskRunnerHandle::Get().
SoftwareOutputDevice();
+ explicit SoftwareOutputDevice(
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
virtual ~SoftwareOutputDevice();
+ // This may be called only once, and requires a non-nullptr argument.
+ void BindToClient(SoftwareOutputDeviceClient* client);
+
// Discards any pre-existing backing buffers and allocates memory for a
// software device of |size|. This must be called before the
// |SoftwareOutputDevice| can be used in other ways.
@@ -55,7 +66,15 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDevice {
// hardware vsync. Return null if a provider doesn't exist.
virtual gfx::VSyncProvider* GetVSyncProvider();
+ // Called from OutputSurface::SwapBuffers(). The default implementation will
+ // immediately run |swap_ack_callback| via PostTask. If swap isn't synchronous
+ // this can be overriden so that |swap_ack_callback| is run after swap
+ // completes.
+ virtual void OnSwapBuffers(base::OnceClosure swap_ack_callback);
+
protected:
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+ SoftwareOutputDeviceClient* client_ = nullptr;
gfx::Size viewport_pixel_size_;
gfx::Rect damage_rect_;
sk_sp<SkSurface> surface_;
diff --git a/chromium/components/viz/service/display/software_output_device_client.h b/chromium/components/viz/service/display/software_output_device_client.h
new file mode 100644
index 00000000000..695354d2e08
--- /dev/null
+++ b/chromium/components/viz/service/display/software_output_device_client.h
@@ -0,0 +1,26 @@
+// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_
+
+namespace gfx {
+struct CALayerParams;
+} // namespace gfx
+
+namespace viz {
+
+class SoftwareOutputDeviceClient {
+ public:
+ virtual ~SoftwareOutputDeviceClient() {}
+
+ // Specify the CALayer parameters used to display the content drawn by this
+ // device on macOS.
+ virtual void SoftwareDeviceUpdatedCALayerParams(
+ const gfx::CALayerParams& ca_layer_params) = 0;
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_SOFTWARE_OUTPUT_DEVICE_CLIENT_H_
diff --git a/chromium/components/viz/service/display/software_renderer.cc b/chromium/components/viz/service/display/software_renderer.cc
index a107b5be1f9..bc958f621cc 100644
--- a/chromium/components/viz/service/display/software_renderer.cc
+++ b/chromium/components/viz/service/display/software_renderer.cc
@@ -38,10 +38,9 @@
namespace viz {
-SoftwareRenderer::SoftwareRenderer(
- const RendererSettings* settings,
- OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
+SoftwareRenderer::SoftwareRenderer(const RendererSettings* settings,
+ OutputSurface* output_surface,
+ DisplayResourceProvider* resource_provider)
: DirectRenderer(settings, output_surface, resource_provider),
output_device_(output_surface->software_device()) {}
@@ -65,11 +64,13 @@ void SoftwareRenderer::FinishDrawingFrame() {
output_device_->EndPaint();
}
-void SoftwareRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
+void SoftwareRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) {
DCHECK(visible_);
TRACE_EVENT0("viz", "SoftwareRenderer::SwapBuffers");
OutputSurfaceFrame output_frame;
output_frame.latency_info = std::move(latency_info);
+ output_frame.need_presentation_feedback = need_presentation_feedback;
output_surface_->SwapBuffers(std::move(output_frame));
}
@@ -168,16 +169,8 @@ void SoftwareRenderer::PrepareSurfaceForPass(
}
bool SoftwareRenderer::IsSoftwareResource(ResourceId resource_id) const {
- switch (resource_provider_->GetResourceType(resource_id)) {
- case ResourceType::kGpuMemoryBuffer:
- case ResourceType::kTexture:
- return false;
- case ResourceType::kBitmap:
- return true;
- }
-
- LOG(FATAL) << "Invalid resource type.";
- return false;
+ return resource_provider_->GetResourceType(resource_id) ==
+ ResourceType::kBitmap;
}
void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad,
@@ -359,8 +352,8 @@ void SoftwareRenderer::DrawTextureQuad(const TextureDrawQuad* quad) {
}
// TODO(skaslev): Add support for non-premultiplied alpha.
- cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
- quad->resource_id());
+ DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
+ quad->resource_id());
if (!lock.valid())
return;
const SkImage* image = lock.sk_image();
@@ -402,8 +395,8 @@ void SoftwareRenderer::DrawTileQuad(const TileDrawQuad* quad) {
DCHECK(resource_provider_);
DCHECK(IsSoftwareResource(quad->resource_id()));
- cc::DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
- quad->resource_id());
+ DisplayResourceProvider::ScopedReadLockSkImage lock(resource_provider_,
+ quad->resource_id());
if (!lock.valid())
return;
@@ -476,11 +469,10 @@ void SoftwareRenderer::DrawRenderPassQuad(const RenderPassDrawQuad* quad) {
SkShader::kClamp_TileMode, &content_mat);
}
- std::unique_ptr<cc::DisplayResourceProvider::ScopedReadLockSoftware>
- mask_lock;
+ std::unique_ptr<DisplayResourceProvider::ScopedReadLockSoftware> mask_lock;
if (quad->mask_resource_id()) {
mask_lock =
- std::make_unique<cc::DisplayResourceProvider::ScopedReadLockSoftware>(
+ std::make_unique<DisplayResourceProvider::ScopedReadLockSoftware>(
resource_provider_, quad->mask_resource_id());
if (!mask_lock->valid())
diff --git a/chromium/components/viz/service/display/software_renderer.h b/chromium/components/viz/service/display/software_renderer.h
index 3e7d634b077..0b901e7b7ed 100644
--- a/chromium/components/viz/service/display/software_renderer.h
+++ b/chromium/components/viz/service/display/software_renderer.h
@@ -10,13 +10,10 @@
#include "components/viz/service/viz_service_export.h"
#include "ui/latency/latency_info.h"
-namespace cc {
-class OutputSurface;
-class DisplayResourceProvider;
-} // namespace cc
-
namespace viz {
class DebugBorderDrawQuad;
+class DisplayResourceProvider;
+class OutputSurface;
class PictureDrawQuad;
class RenderPassDrawQuad;
class SoftwareOutputDevice;
@@ -28,11 +25,12 @@ class VIZ_SERVICE_EXPORT SoftwareRenderer : public DirectRenderer {
public:
SoftwareRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider);
+ DisplayResourceProvider* resource_provider);
~SoftwareRenderer() override;
- void SwapBuffers(std::vector<ui::LatencyInfo> latency_info) override;
+ void SwapBuffers(std::vector<ui::LatencyInfo> latency_info,
+ bool need_presentation_feedback) override;
void SetDisablePictureQuadImageFiltering(bool disable) {
disable_picture_quad_image_filtering_ = disable;
diff --git a/chromium/components/viz/service/display/software_renderer_unittest.cc b/chromium/components/viz/service/display/software_renderer_unittest.cc
index e14a27766a7..86210a12099 100644
--- a/chromium/components/viz/service/display/software_renderer_unittest.cc
+++ b/chromium/components/viz/service/display/software_renderer_unittest.cc
@@ -7,6 +7,8 @@
#include <stdint.h>
#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/shared_memory.h"
#include "base/run_loop.h"
#include "cc/test/animation_test_common.h"
#include "cc/test/fake_output_surface_client.h"
@@ -20,8 +22,10 @@
#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/quads/render_pass.h"
#include "components/viz/common/quads/render_pass_draw_quad.h"
+#include "components/viz/common/quads/shared_bitmap.h"
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/tile_draw_quad.h"
+#include "components/viz/common/resources/bitmap_allocation.h"
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/test/fake_output_surface.h"
#include "components/viz/test/test_shared_bitmap_manager.h"
@@ -52,11 +56,10 @@ class SoftwareRendererTest : public testing::Test {
renderer_->SetVisible(true);
child_resource_provider_ =
- cc::FakeResourceProvider::CreateLayerTreeResourceProvider(
- nullptr, shared_bitmap_manager_.get());
+ cc::FakeResourceProvider::CreateLayerTreeResourceProvider(nullptr);
}
- cc::DisplayResourceProvider* resource_provider() const {
+ DisplayResourceProvider* resource_provider() const {
return resource_provider_.get();
}
@@ -66,6 +69,26 @@ class SoftwareRendererTest : public testing::Test {
SoftwareRenderer* renderer() const { return renderer_.get(); }
+ ResourceId AllocateAndFillSoftwareResource(const gfx::Size& size,
+ const SkBitmap& source) {
+ std::unique_ptr<base::SharedMemory> shm =
+ bitmap_allocation::AllocateMappedBitmap(size, RGBA_8888);
+ SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
+ source.readPixels(info, shm->memory(), info.minRowBytes(), 0, 0);
+
+ // Registers the SharedBitmapId in the display compositor.
+ SharedBitmapId shared_bitmap_id = SharedBitmap::GenerateId();
+ shared_bitmap_manager_->ChildAllocatedSharedBitmap(
+ bitmap_allocation::DuplicateAndCloseMappedBitmap(shm.get(), size,
+ RGBA_8888),
+ shared_bitmap_id);
+
+ // Makes a resource id that refers to the registered SharedBitmapId.
+ return child_resource_provider_->ImportResource(
+ TransferableResource::MakeSoftware(shared_bitmap_id, size, RGBA_8888),
+ SingleReleaseCallback::Create(base::DoNothing()));
+ }
+
std::unique_ptr<SkBitmap> DrawAndCopyOutput(RenderPassList* list,
float device_scale_factor,
gfx::Size viewport_size) {
@@ -97,7 +120,7 @@ class SoftwareRendererTest : public testing::Test {
cc::FakeOutputSurfaceClient output_surface_client_;
std::unique_ptr<FakeOutputSurface> output_surface_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<cc::LayerTreeResourceProvider> child_resource_provider_;
std::unique_ptr<SoftwareRenderer> renderer_;
};
@@ -156,11 +179,6 @@ TEST_F(SoftwareRendererTest, TileQuad) {
bool needs_blending = false;
InitializeRenderer(std::make_unique<SoftwareOutputDevice>());
- ResourceId resource_yellow = child_resource_provider()->CreateBitmapResource(
- outer_size, gfx::ColorSpace(), RGBA_8888);
- ResourceId resource_cyan = child_resource_provider()->CreateBitmapResource(
- inner_size, gfx::ColorSpace(), RGBA_8888);
-
SkBitmap yellow_tile;
yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height());
yellow_tile.eraseColor(SK_ColorYELLOW);
@@ -169,17 +187,16 @@ TEST_F(SoftwareRendererTest, TileQuad) {
cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height());
cyan_tile.eraseColor(SK_ColorCYAN);
- child_resource_provider()->CopyToResource(
- resource_yellow, static_cast<uint8_t*>(yellow_tile.getPixels()),
- outer_size);
- child_resource_provider()->CopyToResource(
- resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), inner_size);
+ ResourceId resource_yellow =
+ this->AllocateAndFillSoftwareResource(outer_size, yellow_tile);
+ ResourceId resource_cyan =
+ this->AllocateAndFillSoftwareResource(inner_size, cyan_tile);
// Transfer resources to the parent, and get the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource_yellow, resource_cyan},
resource_provider(),
- child_resource_provider());
+ child_resource_provider(), nullptr);
ResourceId mapped_resource_yellow = resource_map[resource_yellow];
ResourceId mapped_resource_cyan = resource_map[resource_cyan];
@@ -228,9 +245,6 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
visible_rect.Inset(1, 2, 3, 4);
InitializeRenderer(std::make_unique<SoftwareOutputDevice>());
- ResourceId resource_cyan = child_resource_provider()->CreateBitmapResource(
- tile_size, gfx::ColorSpace(), RGBA_8888);
-
SkBitmap cyan_tile; // The lowest five rows are yellow.
cyan_tile.allocN32Pixels(tile_size.width(), tile_size.height());
cyan_tile.eraseColor(SK_ColorCYAN);
@@ -238,13 +252,13 @@ TEST_F(SoftwareRendererTest, TileQuadVisibleRect) {
tile_rect.width(), tile_rect.bottom()),
SK_ColorYELLOW);
- child_resource_provider()->CopyToResource(
- resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size);
+ ResourceId resource_cyan =
+ AllocateAndFillSoftwareResource(tile_size, cyan_tile);
// Transfer resources to the parent, and get the resource map.
- cc::ResourceProvider::ResourceIdMap resource_map =
+ std::unordered_map<ResourceId, ResourceId> resource_map =
SendResourceAndGetChildToParentMap({resource_cyan}, resource_provider(),
- child_resource_provider());
+ child_resource_provider(), nullptr);
ResourceId mapped_resource_cyan = resource_map[resource_cyan];
gfx::Rect root_rect(tile_size);
diff --git a/chromium/components/viz/service/display/surface_aggregator.cc b/chromium/components/viz/service/display/surface_aggregator.cc
index 5c41b6d48b8..c021630d66f 100644
--- a/chromium/components/viz/service/display/surface_aggregator.cc
+++ b/chromium/components/viz/service/display/surface_aggregator.cc
@@ -13,10 +13,10 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
+#include "base/numerics/ranges.h"
#include "base/stl_util.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/math_util.h"
-#include "cc/resources/display_resource_provider.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/render_pass_draw_quad.h"
@@ -24,6 +24,7 @@
#include "components/viz/common/quads/solid_color_draw_quad.h"
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/surfaces/surface.h"
#include "components/viz/service/surfaces/surface_client.h"
#include "components/viz/service/surfaces/surface_manager.h"
@@ -34,6 +35,10 @@ namespace {
// Maximum bucket size for the UMA stats.
constexpr int kUmaStatMaxSurfaces = 30;
+// Used for determine when to treat opacity close to 1.f as opaque. The value is
+// chosen to be smaller than 1/255.
+constexpr float kOpacityEpsilon = 0.001f;
+
const char kUmaValidSurface[] =
"Compositing.SurfaceAggregator.SurfaceDrawQuad.ValidSurface";
const char kUmaMissingSurface[] =
@@ -77,7 +82,7 @@ bool CalculateQuadSpaceDamageRect(
} // namespace
SurfaceAggregator::SurfaceAggregator(SurfaceManager* manager,
- cc::DisplayResourceProvider* provider,
+ DisplayResourceProvider* provider,
bool aggregate_only_damaged)
: manager_(manager),
provider_(provider),
@@ -323,14 +328,15 @@ void SurfaceAggregator::EmitSurfaceContent(
referenced_surfaces_.insert(surface_id);
// TODO(vmpstr): provider check is a hack for unittests that don't set up a
// resource provider.
- cc::ResourceProvider::ResourceIdMap empty_map;
+ std::unordered_map<ResourceId, ResourceId> empty_map;
const auto& child_to_parent_map =
provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface))
: empty_map;
gfx::Transform combined_transform = scaled_quad_to_target_transform;
combined_transform.ConcatTransform(target_transform);
- bool merge_pass = source_sqs->opacity == 1.f && copy_requests.empty() &&
- combined_transform.Preserves2dAxisAlignment();
+ bool merge_pass =
+ base::IsApproximatelyEqual(source_sqs->opacity, 1.f, kOpacityEpsilon) &&
+ copy_requests.empty() && combined_transform.Preserves2dAxisAlignment();
const RenderPassList& referenced_passes = render_pass_list;
// TODO(fsamuel): Move this to a separate helper function.
@@ -763,7 +769,7 @@ void SurfaceAggregator::CopyPasses(const CompositorFrame& frame,
// TODO(vmpstr): provider check is a hack for unittests that don't set up a
// resource provider.
- cc::ResourceProvider::ResourceIdMap empty_map;
+ std::unordered_map<ResourceId, ResourceId> empty_map;
const auto& child_to_parent_map =
provider_ ? provider_->GetChildToParentMap(ChildIdForSurface(surface))
: empty_map;
@@ -841,11 +847,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
int parent_pass_id,
bool will_draw,
PrewalkResult* result) {
- // This is for debugging a possible use after free.
- // TODO(jbauman): Remove this once we have enough information.
- // http://crbug.com/560181
- base::WeakPtr<SurfaceAggregator> debug_weak_this = weak_factory_.GetWeakPtr();
-
if (referenced_surfaces_.count(surface->surface_id()))
return gfx::Rect();
@@ -864,18 +865,16 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
surface->RefResources(frame.resource_list);
provider_->ReceiveFromChild(child_id, frame.resource_list);
}
- CHECK(debug_weak_this.get());
std::vector<ResourceId> referenced_resources;
size_t reserve_size = frame.resource_list.size();
referenced_resources.reserve(reserve_size);
bool invalid_frame = false;
- cc::ResourceProvider::ResourceIdMap empty_map;
+ std::unordered_map<ResourceId, ResourceId> empty_map;
const auto& child_to_parent_map =
provider_ ? provider_->GetChildToParentMap(child_id) : empty_map;
- CHECK(debug_weak_this.get());
RenderPassId remapped_pass_id =
RemapPassId(frame.render_pass_list.back()->id, surface->surface_id());
if (in_moved_pixel_surface)
@@ -976,14 +975,12 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
if (invalid_frame)
return gfx::Rect();
- CHECK(debug_weak_this.get());
valid_surfaces_.insert(surface->surface_id());
ResourceIdSet resource_set(std::move(referenced_resources),
base::KEEP_FIRST_OF_DUPES);
if (provider_)
provider_->DeclareUsedResourcesFromChild(child_id, resource_set);
- CHECK(debug_weak_this.get());
gfx::Rect damage_rect;
gfx::Rect full_damage;
@@ -1050,8 +1047,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
surface_info.target_to_surface_transform, surface_damage));
}
- CHECK(debug_weak_this.get());
-
if (!damage_rect.IsEmpty()) {
// The following call can cause one or more copy requests to be added to the
// Surface. Therefore, no code before this point should have assumed
@@ -1066,8 +1061,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
if (will_draw)
surface->OnWillBeDrawn();
- CHECK(debug_weak_this.get());
-
for (const auto& surface_id : frame.metadata.referenced_surfaces) {
if (!contained_surfaces_.count(surface_id)) {
result->undrawn_surfaces.insert(surface_id);
@@ -1077,7 +1070,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
}
}
- CHECK(debug_weak_this.get());
for (const auto& render_pass : frame.render_pass_list) {
if (!render_pass->copy_requests.empty()) {
RenderPassId remapped_pass_id =
@@ -1089,8 +1081,6 @@ gfx::Rect SurfaceAggregator::PrewalkTree(Surface* surface,
}
auto it = referenced_surfaces_.find(surface->surface_id());
- // TODO(jbauman): Remove when https://crbug.com/745684 fixed.
- CHECK(referenced_surfaces_.end() != it);
referenced_surfaces_.erase(it);
if (!damage_rect.IsEmpty() && frame.metadata.may_contain_video)
result->may_contain_video = true;
diff --git a/chromium/components/viz/service/display/surface_aggregator.h b/chromium/components/viz/service/display/surface_aggregator.h
index fc2c379e225..14b4bfe907d 100644
--- a/chromium/components/viz/service/display/surface_aggregator.h
+++ b/chromium/components/viz/service/display/surface_aggregator.h
@@ -19,12 +19,9 @@
#include "components/viz/service/viz_service_export.h"
#include "ui/gfx/color_space.h"
-namespace cc {
-class DisplayResourceProvider;
-} // namespace cc
-
namespace viz {
class CompositorFrame;
+class DisplayResourceProvider;
class Surface;
class SurfaceClient;
class SurfaceDrawQuad;
@@ -36,7 +33,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
using FrameSinkIdMap = base::flat_map<FrameSinkId, LocalSurfaceId>;
SurfaceAggregator(SurfaceManager* manager,
- cc::DisplayResourceProvider* provider,
+ DisplayResourceProvider* provider,
bool aggregate_only_damaged);
~SurfaceAggregator();
@@ -202,7 +199,7 @@ class VIZ_SERVICE_EXPORT SurfaceAggregator {
const std::vector<ReturnedResource>& resources);
SurfaceManager* manager_;
- cc::DisplayResourceProvider* provider_;
+ DisplayResourceProvider* provider_;
// Every Surface has its own RenderPass ID namespace. This structure maps
// each source (SurfaceId, RenderPass id) to a unified ID namespace that's
diff --git a/chromium/components/viz/service/display/surface_aggregator_perftest.cc b/chromium/components/viz/service/display/surface_aggregator_perftest.cc
index 9ae9e880f2f..ca2a7834ed1 100644
--- a/chromium/components/viz/service/display/surface_aggregator_perftest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_perftest.cc
@@ -3,13 +3,13 @@
// found in the LICENSE file.
#include "cc/base/lap_timer.h"
-#include "cc/resources/display_resource_provider.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_resource_provider.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/surface_draw_quad.h"
#include "components/viz/common/quads/texture_draw_quad.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/display/surface_aggregator.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
@@ -150,7 +150,7 @@ class SurfaceAggregatorPerfTest : public testing::Test {
FrameSinkManagerImpl manager_;
scoped_refptr<TestContextProvider> context_provider_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<SurfaceAggregator> aggregator_;
cc::LapTimer timer_;
};
diff --git a/chromium/components/viz/service/display/surface_aggregator_unittest.cc b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
index d25d5115d4a..23db64eab7b 100644
--- a/chromium/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/chromium/components/viz/service/display/surface_aggregator_unittest.cc
@@ -14,7 +14,6 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
-#include "cc/resources/display_resource_provider.h"
#include "cc/test/fake_resource_provider.h"
#include "cc/test/render_pass_test_utils.h"
#include "components/viz/common/frame_sinks/begin_frame_args.h"
@@ -27,6 +26,7 @@
#include "components/viz/common/quads/texture_draw_quad.h"
#include "components/viz/common/resources/shared_bitmap_manager.h"
#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "components/viz/service/display/display_resource_provider.h"
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h"
#include "components/viz/service/surfaces/surface.h"
@@ -378,7 +378,7 @@ class SurfaceAggregatorValidSurfaceTest : public SurfaceAggregatorTest {
void SetUp() override {
SurfaceAggregatorTest::SetUp();
- root_local_surface_id_ = allocator_.GenerateId();
+ root_local_surface_id_ = allocator_.GetCurrentLocalSurfaceId();
root_surface_ = manager_.surface_manager()->GetSurfaceForId(
SurfaceId(support_->frame_sink_id(), root_local_surface_id_));
}
@@ -533,29 +533,44 @@ TEST_F(SurfaceAggregatorValidSurfaceTest, OpacityCopied) {
SubmitCompositorFrame(embedded_support.get(), embedded_passes,
arraysize(embedded_passes), embedded_local_surface_id,
device_scale_factor);
+ SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
+ {
+ Quad quads[] = {Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(),
+ SK_ColorWHITE, gfx::Rect(5, 5), .5f,
+ gfx::Transform(), false)};
+ Pass passes[] = {Pass(quads, arraysize(quads), SurfaceSize())};
- Quad quads[] = {Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(),
- SK_ColorWHITE, gfx::Rect(5, 5), .5f,
- gfx::Transform(), false)};
- Pass passes[] = {Pass(quads, arraysize(quads), SurfaceSize())};
+ SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
+ root_local_surface_id_, device_scale_factor);
- SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
- root_local_surface_id_, device_scale_factor);
+ CompositorFrame aggregated_frame = aggregator_.Aggregate(
+ root_surface_id, GetNextDisplayTimeAndIncrement());
- SurfaceId root_surface_id(support_->frame_sink_id(), root_local_surface_id_);
- CompositorFrame aggregated_frame =
- aggregator_.Aggregate(root_surface_id, GetNextDisplayTimeAndIncrement());
+ auto& render_pass_list = aggregated_frame.render_pass_list;
+ EXPECT_EQ(2u, render_pass_list.size());
- auto& render_pass_list = aggregated_frame.render_pass_list;
- ASSERT_EQ(2u, render_pass_list.size());
- auto& shared_quad_state_list = render_pass_list[0]->shared_quad_state_list;
- ASSERT_EQ(2u, shared_quad_state_list.size());
- EXPECT_EQ(1.f, shared_quad_state_list.ElementAt(0)->opacity);
- EXPECT_EQ(1.f, shared_quad_state_list.ElementAt(1)->opacity);
-
- auto& shared_quad_state_list2 = render_pass_list[1]->shared_quad_state_list;
- ASSERT_EQ(1u, shared_quad_state_list2.size());
- EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity);
+ auto& shared_quad_state_list2 = render_pass_list[1]->shared_quad_state_list;
+ ASSERT_EQ(1u, shared_quad_state_list2.size());
+ EXPECT_EQ(.5f, shared_quad_state_list2.ElementAt(0)->opacity);
+ }
+
+ // For the case where opacity is close to 1.f, we treat it as opaque, and not
+ // use a render surface.
+ {
+ Quad quads[] = {Quad::SurfaceQuad(embedded_surface_id, InvalidSurfaceId(),
+ SK_ColorWHITE, gfx::Rect(5, 5), .9999f,
+ gfx::Transform(), false)};
+ Pass passes[] = {Pass(quads, arraysize(quads), SurfaceSize())};
+
+ SubmitCompositorFrame(support_.get(), passes, arraysize(passes),
+ root_local_surface_id_, device_scale_factor);
+
+ CompositorFrame aggregated_frame = aggregator_.Aggregate(
+ root_surface_id, GetNextDisplayTimeAndIncrement());
+
+ auto& render_pass_list = aggregated_frame.render_pass_list;
+ EXPECT_EQ(1u, render_pass_list.size());
+ }
}
// Test that when surface is rotated and we need the render surface to apply the
@@ -2952,7 +2967,7 @@ class SurfaceAggregatorWithResourcesTest : public testing::Test,
protected:
FrameSinkManagerImpl manager_;
std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
- std::unique_ptr<cc::DisplayResourceProvider> resource_provider_;
+ std::unique_ptr<DisplayResourceProvider> resource_provider_;
std::unique_ptr<SurfaceAggregator> aggregator_;
};
diff --git a/chromium/components/viz/service/display/vulkan_renderer.cc b/chromium/components/viz/service/display/vulkan_renderer.cc
index 87ede657bd4..1ddd1d36e24 100644
--- a/chromium/components/viz/service/display/vulkan_renderer.cc
+++ b/chromium/components/viz/service/display/vulkan_renderer.cc
@@ -19,7 +19,7 @@ void VulkanRenderer::SwapBuffers(std::vector<ui::LatencyInfo> latency_info) {
VulkanRenderer::VulkanRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider)
+ DisplayResourceProvider* resource_provider)
: DirectRenderer(settings, output_surface, resource_provider) {}
void VulkanRenderer::DidChangeVisibility() {
diff --git a/chromium/components/viz/service/display/vulkan_renderer.h b/chromium/components/viz/service/display/vulkan_renderer.h
index ce07ecce7b7..4e7ff89a7ab 100644
--- a/chromium/components/viz/service/display/vulkan_renderer.h
+++ b/chromium/components/viz/service/display/vulkan_renderer.h
@@ -9,17 +9,15 @@
#include "components/viz/service/viz_service_export.h"
#include "ui/latency/latency_info.h"
-namespace cc {
-class OutputSurface;
-} // namespace cc
-
namespace viz {
+class OutputSurface;
+
class VIZ_SERVICE_EXPORT VulkanRenderer : public DirectRenderer {
public:
VulkanRenderer(const RendererSettings* settings,
OutputSurface* output_surface,
- cc::DisplayResourceProvider* resource_provider);
+ DisplayResourceProvider* resource_provider);
~VulkanRenderer() override;
// Implementation of public DirectRenderer functions.
diff --git a/chromium/components/viz/service/display_embedder/DEPS b/chromium/components/viz/service/display_embedder/DEPS
index 5fc1a52037e..38bf218cf88 100644
--- a/chromium/components/viz/service/display_embedder/DEPS
+++ b/chromium/components/viz/service/display_embedder/DEPS
@@ -2,7 +2,6 @@
include_rules = [
"+cc/base",
- "+cc/ipc",
"+cc/output",
"+cc/resources",
"+cc/scheduler",
@@ -10,18 +9,21 @@ include_rules = [
"+components/viz/service/display/output_surface_frame.h",
"+components/viz/service/display/output_surface.h",
"+components/viz/service/display/overlay_candidate_validator.h",
+ "+components/viz/service/display/skia_output_surface.h",
"+components/viz/service/display/software_output_device.h",
+ "+gpu/config/gpu_feature_info.h",
+ "+components/viz/service/gl/gpu_service_impl.h",
"+gpu/GLES2",
"+gpu/command_buffer/client",
"+gpu/command_buffer/common",
"+gpu/command_buffer/service",
- "+gpu/ipc/client",
- "+gpu/ipc/common",
- "+gpu/ipc/in_process_command_buffer.h",
- "+gpu/ipc/service",
+ "+gpu/ipc",
+ "+gpu/skia_bindings",
"+mojo/public/cpp/bindings",
"+mojo/public/cpp/system",
"+skia",
+ "+third_party/khronos/GLES2/gl2.h",
+ "+third_party/khronos/GLES2/gl2ext.h",
"+third_party/skia",
"+ui/accelerated_widget_mac",
"+ui/display",
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc
index a91ebec2695..f0af20b4c82 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.cc
@@ -20,11 +20,19 @@ CompositorOverlayCandidateValidatorAndroid::
void CompositorOverlayCandidateValidatorAndroid::GetStrategies(
OverlayProcessor::StrategyList* strategies) {
- strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(this));
+ // For Android, we do not have the ability to skip an overlay, since the
+ // texture is already in a SurfaceView. Ideally, we would honor a 'force
+ // overlay' flag that FromDrawQuad would also check.
+ // For now, though, just skip the opacity check. We really have no idea if
+ // the underlying overlay is opaque anyway; the candidate is referring to
+ // a dummy resource that has no relation to what the overlay contains.
+ // https://crbug.com/842931 .
+ strategies->push_back(std::make_unique<OverlayStrategyUnderlay>(
+ this, OverlayStrategyUnderlay::OpaqueMode::AllowTransparentCandidates));
}
void CompositorOverlayCandidateValidatorAndroid::CheckOverlaySupport(
- cc::OverlayCandidateList* candidates) {
+ OverlayCandidateList* candidates) {
// There should only be at most a single overlay candidate: the video quad.
// There's no check that the presented candidate is really a video frame for
// a fullscreen video. Instead it's assumed that if a quad is marked as
@@ -32,7 +40,7 @@ void CompositorOverlayCandidateValidatorAndroid::CheckOverlaySupport(
DCHECK_LE(candidates->size(), 1u);
if (!candidates->empty()) {
- cc::OverlayCandidate& candidate = candidates->front();
+ OverlayCandidate& candidate = candidates->front();
// This quad either will be promoted, or would be if it were backed by a
// SurfaceView. Record that it should get a promotion hint.
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h
index df053dce733..2b30937d787 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_android.h
@@ -26,7 +26,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorAndroid
~CompositorOverlayCandidateValidatorAndroid() override;
void GetStrategies(OverlayProcessor::StrategyList* strategies) override;
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override;
bool AllowCALayerOverlays() override;
bool AllowDCLayerOverlays() override;
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc
index 07bc790a298..ebe761bab99 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.cc
@@ -27,7 +27,7 @@ bool CompositorOverlayCandidateValidatorMac::AllowDCLayerOverlays() {
}
void CompositorOverlayCandidateValidatorMac::CheckOverlaySupport(
- cc::OverlayCandidateList* surfaces) {}
+ OverlayCandidateList* surfaces) {}
void CompositorOverlayCandidateValidatorMac::SetSoftwareMirrorMode(
bool enabled) {
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h
index b2a01c46c19..7d6ad9e5b20 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_mac.h
@@ -23,7 +23,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorMac
void GetStrategies(OverlayProcessor::StrategyList* strategies) override;
bool AllowCALayerOverlays() override;
bool AllowDCLayerOverlays() override;
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override;
// CompositorOverlayCandidateValidator implementation.
void SetSoftwareMirrorMode(bool enabled) override;
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
index 88f74d0f352..e0bdbf80fae 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
@@ -29,8 +29,8 @@ std::unique_ptr<OverlayProcessor::Strategy> MakeOverlayStrategy(
} // namespace
// |overlay_candidates| is an object used to answer questions about possible
-// overlays configuarations.
-// |strategies_string| is a comma-separated string containing all the overaly
+// overlays configurations.
+// |strategies_string| is a comma-separated string containing all the overlay
// strategies that should be returned by GetStrategies.
// If |strategies_string| is empty "single-on-top,underlay" will be used as
// default.
@@ -82,7 +82,7 @@ bool CompositorOverlayCandidateValidatorOzone::AllowDCLayerOverlays() {
}
void CompositorOverlayCandidateValidatorOzone::CheckOverlaySupport(
- cc::OverlayCandidateList* surfaces) {
+ OverlayCandidateList* surfaces) {
// SW mirroring copies out of the framebuffer, so we can't remove any
// quads for overlaying, otherwise the output is incorrect.
if (software_mirror_active_) {
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h
index 13fcbc9c039..3c03de00fe8 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h
@@ -31,7 +31,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorOzone
void GetStrategies(OverlayProcessor::StrategyList* strategies) override;
bool AllowCALayerOverlays() override;
bool AllowDCLayerOverlays() override;
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override;
// CompositorOverlayCandidateValidator implementation.
void SetSoftwareMirrorMode(bool enabled) override;
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc
index 44494ef59c5..28663e891fa 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.cc
@@ -18,7 +18,7 @@ void CompositorOverlayCandidateValidatorWin::GetStrategies(
OverlayProcessor::StrategyList* strategies) {}
void CompositorOverlayCandidateValidatorWin::CheckOverlaySupport(
- cc::OverlayCandidateList* candidates) {
+ OverlayCandidateList* candidates) {
NOTIMPLEMENTED();
}
diff --git a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h
index fe25ef93771..2685709a9b6 100644
--- a/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h
+++ b/chromium/components/viz/service/display_embedder/compositor_overlay_candidate_validator_win.h
@@ -20,7 +20,7 @@ class VIZ_SERVICE_EXPORT CompositorOverlayCandidateValidatorWin
~CompositorOverlayCandidateValidatorWin() override;
void GetStrategies(OverlayProcessor::StrategyList* strategies) override;
- void CheckOverlaySupport(cc::OverlayCandidateList* surfaces) override;
+ void CheckOverlaySupport(OverlayCandidateList* surfaces) override;
bool AllowCALayerOverlays() override;
bool AllowDCLayerOverlays() override;
diff --git a/chromium/components/viz/service/display_embedder/display_provider.h b/chromium/components/viz/service/display_embedder/display_provider.h
index eaae5ac0805..12fa6146fef 100644
--- a/chromium/components/viz/service/display_embedder/display_provider.h
+++ b/chromium/components/viz/service/display_embedder/display_provider.h
@@ -8,6 +8,7 @@
#include <memory>
#include "gpu/ipc/common/surface_handle.h"
+#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
namespace viz {
@@ -29,6 +30,7 @@ class DisplayProvider {
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
+ mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) = 0;
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.cc b/chromium/components/viz/service/display_embedder/gl_output_surface.cc
index ef2e3675d25..55fc38aabac 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface.cc
@@ -15,33 +15,34 @@
#include "gpu/command_buffer/client/context_support.h"
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/common/swap_buffers_flags.h"
#include "ui/gl/gl_utils.h"
namespace viz {
GLOutputSurface::GLOutputSurface(
- scoped_refptr<InProcessContextProvider> context_provider,
+ scoped_refptr<VizProcessContextProvider> context_provider,
SyntheticBeginFrameSource* synthetic_begin_frame_source)
: OutputSurface(context_provider),
synthetic_begin_frame_source_(synthetic_begin_frame_source),
- latency_tracker_(true),
- latency_info_cache_(this),
+ use_gpu_fence_(
+ context_provider->ContextCapabilities().chromium_gpu_fence &&
+ context_provider->ContextCapabilities()
+ .use_gpu_fences_for_overlay_planes),
weak_ptr_factory_(this) {
capabilities_.flipped_output_surface =
context_provider->ContextCapabilities().flips_vertically;
capabilities_.supports_stencil =
context_provider->ContextCapabilities().num_stencil_bits > 0;
- context_provider->SetSwapBuffersCompletionCallback(
- base::BindRepeating(&GLOutputSurface::OnGpuSwapBuffersCompleted,
- weak_ptr_factory_.GetWeakPtr()));
context_provider->SetUpdateVSyncParametersCallback(
base::BindRepeating(&GLOutputSurface::OnVSyncParametersUpdated,
weak_ptr_factory_.GetWeakPtr()));
- context_provider->SetPresentationCallback(base::BindRepeating(
- &GLOutputSurface::OnPresentation, weak_ptr_factory_.GetWeakPtr()));
}
-GLOutputSurface::~GLOutputSurface() {}
+GLOutputSurface::~GLOutputSurface() {
+ if (gpu_fence_id_ > 0)
+ context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_);
+}
void GLOutputSurface::BindToClient(OutputSurfaceClient* client) {
DCHECK(client);
@@ -86,21 +87,37 @@ void GLOutputSurface::Reshape(const gfx::Size& size,
void GLOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
DCHECK(context_provider_);
- if (latency_info_cache_.WillSwap(std::move(frame.latency_info)))
+ uint32_t flags = 0;
+ if (synthetic_begin_frame_source_)
+ flags |= gpu::SwapBuffersFlags::kVSyncParams;
+
+ if (LatencyInfoHasSnapshotRequest(frame.latency_info))
context_provider_->ContextSupport()->SetSnapshotRequested();
+ auto swap_callback = base::BindOnce(
+ &GLOutputSurface::OnGpuSwapBuffersCompleted,
+ weak_ptr_factory_.GetWeakPtr(), std::move(frame.latency_info));
+ gpu::ContextSupport::PresentationCallback presentation_callback;
+ if (frame.need_presentation_feedback) {
+ flags |= gpu::SwapBuffersFlags::kPresentationFeedback;
+ presentation_callback = base::BindOnce(&GLOutputSurface::OnPresentation,
+ weak_ptr_factory_.GetWeakPtr());
+ }
+
set_draw_rectangle_for_frame_ = false;
if (frame.sub_buffer_rect) {
context_provider_->ContextSupport()->PartialSwapBuffers(
- *frame.sub_buffer_rect);
+ *frame.sub_buffer_rect, flags, std::move(swap_callback),
+ std::move(presentation_callback));
} else {
- context_provider_->ContextSupport()->Swap();
+ context_provider_->ContextSupport()->Swap(flags, std::move(swap_callback),
+ std::move(presentation_callback));
}
}
uint32_t GLOutputSurface::GetFramebufferCopyTextureFormat() {
// TODO(danakj): What attributes are used for the default framebuffer here?
- // Can it have alpha? InProcessContextProvider doesn't take any
+ // Can it have alpha? VizProcessContextProvider doesn't take any
// attributes.
return GL_RGB;
}
@@ -122,37 +139,28 @@ gfx::BufferFormat GLOutputSurface::GetOverlayBufferFormat() const {
return gfx::BufferFormat::RGBX_8888;
}
-bool GLOutputSurface::SurfaceIsSuspendForRecycle() const {
- return false;
-}
-
bool GLOutputSurface::HasExternalStencilTest() const {
return false;
}
void GLOutputSurface::ApplyExternalStencil() {}
-void GLOutputSurface::DidReceiveSwapBuffersAck(gfx::SwapResult result,
- uint64_t swap_id) {
- client_->DidReceiveSwapBuffersAck(swap_id);
+void GLOutputSurface::DidReceiveSwapBuffersAck(gfx::SwapResult result) {
+ client_->DidReceiveSwapBuffersAck();
}
void GLOutputSurface::OnGpuSwapBuffersCompleted(
+ std::vector<ui::LatencyInfo> latency_info,
const gpu::SwapBuffersCompleteParams& params) {
if (!params.texture_in_use_responses.empty())
client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses);
if (!params.ca_layer_params.is_empty)
client_->DidReceiveCALayerParams(params.ca_layer_params);
- DidReceiveSwapBuffersAck(params.swap_response.result,
- params.swap_response.swap_id);
- latency_info_cache_.OnSwapBuffersCompleted(params.swap_response);
-}
+ DidReceiveSwapBuffersAck(params.swap_response.result);
-void GLOutputSurface::LatencyInfoCompleted(
- const std::vector<ui::LatencyInfo>& latency_info) {
- for (const auto& latency : latency_info) {
- latency_tracker_.OnGpuSwapBuffersCompleted(latency);
- }
+ UpdateLatencyInfoOnSwap(params.swap_response, &latency_info);
+ latency_tracker_.OnGpuSwapBuffersCompleted(latency_info);
+ client_->DidFinishLatencyInfo(latency_info);
}
void GLOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase,
@@ -166,9 +174,8 @@ void GLOutputSurface::OnVSyncParametersUpdated(base::TimeTicks timebase,
}
void GLOutputSurface::OnPresentation(
- uint64_t swap_id,
const gfx::PresentationFeedback& feedback) {
- client_->DidReceivePresentationFeedback(swap_id, feedback);
+ client_->DidReceivePresentationFeedback(feedback);
}
#if BUILDFLAG(ENABLE_VULKAN)
@@ -178,4 +185,16 @@ gpu::VulkanSurface* GLOutputSurface::GetVulkanSurface() {
}
#endif
+unsigned GLOutputSurface::UpdateGpuFence() {
+ if (!use_gpu_fence_)
+ return 0;
+
+ if (gpu_fence_id_ > 0)
+ context_provider()->ContextGL()->DestroyGpuFenceCHROMIUM(gpu_fence_id_);
+
+ gpu_fence_id_ = context_provider()->ContextGL()->CreateGpuFenceCHROMIUM();
+
+ return gpu_fence_id_;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface.h b/chromium/components/viz/service/display_embedder/gl_output_surface.h
index c2e58bb7dca..06f87f581c3 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface.h
@@ -7,8 +7,8 @@
#include <memory>
-#include "components/viz/common/gpu/in_process_context_provider.h"
#include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "ui/latency/latency_tracker.h"
namespace viz {
@@ -17,10 +17,9 @@ class SyntheticBeginFrameSource;
// An OutputSurface implementation that directly draws and
// swaps to an actual GL surface.
-class GLOutputSurface : public OutputSurface,
- public OutputSurface::LatencyInfoCache::Client {
+class GLOutputSurface : public OutputSurface {
public:
- GLOutputSurface(scoped_refptr<InProcessContextProvider> context_provider,
+ GLOutputSurface(scoped_refptr<VizProcessContextProvider> context_provider,
SyntheticBeginFrameSource* synthetic_begin_frame_source);
~GLOutputSurface() override;
@@ -41,31 +40,26 @@ class GLOutputSurface : public OutputSurface,
bool IsDisplayedAsOverlayPlane() const override;
unsigned GetOverlayTextureId() const override;
gfx::BufferFormat GetOverlayBufferFormat() const override;
- bool SurfaceIsSuspendForRecycle() const override;
bool HasExternalStencilTest() const override;
void ApplyExternalStencil() override;
#if BUILDFLAG(ENABLE_VULKAN)
gpu::VulkanSurface* GetVulkanSurface() override;
#endif
-
- // OutputSurface::LatencyInfoCache::Client implementation.
- void LatencyInfoCompleted(
- const std::vector<ui::LatencyInfo>& latency_info) override;
+ unsigned UpdateGpuFence() override;
protected:
OutputSurfaceClient* client() const { return client_; }
// Called when a swap completion is signaled from ImageTransportSurface.
- virtual void DidReceiveSwapBuffersAck(gfx::SwapResult result,
- uint64_t swap_id);
+ virtual void DidReceiveSwapBuffersAck(gfx::SwapResult result);
private:
// Called when a swap completion is signaled from ImageTransportSurface.
- void OnGpuSwapBuffersCompleted(const gpu::SwapBuffersCompleteParams& params);
+ void OnGpuSwapBuffersCompleted(std::vector<ui::LatencyInfo> latency_info,
+ const gpu::SwapBuffersCompleteParams& params);
void OnVSyncParametersUpdated(base::TimeTicks timebase,
base::TimeDelta interval);
- void OnPresentation(uint64_t swap_id,
- const gfx::PresentationFeedback& feedback);
+ void OnPresentation(const gfx::PresentationFeedback& feedback);
OutputSurfaceClient* client_ = nullptr;
SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
@@ -75,7 +69,8 @@ class GLOutputSurface : public OutputSurface,
// True if the draw rectangle has been set at all since the last resize.
bool has_set_draw_rectangle_since_last_resize_ = false;
gfx::Size size_;
- LatencyInfoCache latency_info_cache_;
+ bool use_gpu_fence_;
+ unsigned gpu_fence_id_ = 0;
base::WeakPtrFactory<GLOutputSurface> weak_ptr_factory_;
};
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
index cf02039d4b4..279daf5f4ff 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.cc
@@ -18,7 +18,7 @@
namespace viz {
GLOutputSurfaceBufferQueue::GLOutputSurfaceBufferQueue(
- scoped_refptr<InProcessContextProvider> context_provider,
+ scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
@@ -105,8 +105,7 @@ gfx::BufferFormat GLOutputSurfaceBufferQueue::GetOverlayBufferFormat() const {
}
void GLOutputSurfaceBufferQueue::DidReceiveSwapBuffersAck(
- gfx::SwapResult result,
- uint64_t swap_id) {
+ gfx::SwapResult result) {
bool force_swap = false;
if (result == gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS) {
// Even through the swap failed, this is a fixable error so we can pretend
@@ -117,7 +116,7 @@ void GLOutputSurfaceBufferQueue::DidReceiveSwapBuffersAck(
}
buffer_queue_->PageFlipComplete();
- client()->DidReceiveSwapBuffersAck(swap_id);
+ client()->DidReceiveSwapBuffersAck();
if (force_swap)
client()->SetNeedsRedrawRect(gfx::Rect(swap_size_));
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
index ff22c17ad31..3703297b1c7 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_buffer_queue.h
@@ -10,9 +10,9 @@
#include "base/memory/weak_ptr.h"
#include "components/viz/common/gl_helper.h"
#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/gpu/in_process_context_provider.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/display_embedder/gl_output_surface.h"
+#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/swap_result.h"
@@ -34,7 +34,7 @@ class SyntheticBeginFrameSource;
class GLOutputSurfaceBufferQueue : public GLOutputSurface {
public:
GLOutputSurfaceBufferQueue(
- scoped_refptr<InProcessContextProvider> context_provider,
+ scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
@@ -61,8 +61,7 @@ class GLOutputSurfaceBufferQueue : public GLOutputSurface {
gfx::BufferFormat GetOverlayBufferFormat() const override;
// GLOutputSurface:
- void DidReceiveSwapBuffersAck(gfx::SwapResult result,
- uint64_t swap_id) override;
+ void DidReceiveSwapBuffersAck(gfx::SwapResult result) override;
GLHelper gl_helper_;
std::unique_ptr<BufferQueue> buffer_queue_;
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc
index e1a1c23f4dd..cb0fa658934 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.cc
@@ -9,7 +9,7 @@
namespace viz {
GLOutputSurfaceMac::GLOutputSurfaceMac(
- scoped_refptr<InProcessContextProvider> context_provider,
+ scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h
index f26801f584b..5e2e8b20542 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_mac.h
@@ -12,7 +12,7 @@ namespace viz {
class GLOutputSurfaceMac : public GLOutputSurfaceBufferQueue {
public:
- GLOutputSurfaceMac(scoped_refptr<InProcessContextProvider> context_provider,
+ GLOutputSurfaceMac(scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc
index 50deccee3f7..8c42482ba2c 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.cc
@@ -9,7 +9,7 @@
namespace viz {
GLOutputSurfaceOzone::GLOutputSurfaceOzone(
- scoped_refptr<InProcessContextProvider> context_provider,
+ scoped_refptr<VizProcessContextProvider> context_provider,
gpu::SurfaceHandle surface_handle,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h
index 69544d0a23f..47a7cffb50f 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_ozone.h
@@ -11,12 +11,13 @@ namespace viz {
class GLOutputSurfaceOzone : public GLOutputSurfaceBufferQueue {
public:
- GLOutputSurfaceOzone(scoped_refptr<InProcessContextProvider> context_provider,
- gpu::SurfaceHandle surface_handle,
- SyntheticBeginFrameSource* synthetic_begin_frame_source,
- gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- uint32_t target,
- uint32_t internal_format);
+ GLOutputSurfaceOzone(
+ scoped_refptr<VizProcessContextProvider> context_provider,
+ gpu::SurfaceHandle surface_handle,
+ SyntheticBeginFrameSource* synthetic_begin_frame_source,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ uint32_t target,
+ uint32_t internal_format);
~GLOutputSurfaceOzone() override;
private:
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc b/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc
index da3fde6007a..5e79df4b94e 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_win.cc
@@ -9,7 +9,7 @@
namespace viz {
GLOutputSurfaceWin::GLOutputSurfaceWin(
- scoped_refptr<InProcessContextProvider> context_provider,
+ scoped_refptr<VizProcessContextProvider> context_provider,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
bool use_overlays)
: GLOutputSurface(context_provider, synthetic_begin_frame_source) {
diff --git a/chromium/components/viz/service/display_embedder/gl_output_surface_win.h b/chromium/components/viz/service/display_embedder/gl_output_surface_win.h
index c62a7498b47..e71a7b0bd40 100644
--- a/chromium/components/viz/service/display_embedder/gl_output_surface_win.h
+++ b/chromium/components/viz/service/display_embedder/gl_output_surface_win.h
@@ -16,7 +16,7 @@ class CompositorOverlayCandidateValidatorWin;
class GLOutputSurfaceWin : public GLOutputSurface {
public:
- GLOutputSurfaceWin(scoped_refptr<InProcessContextProvider> context_provider,
+ GLOutputSurfaceWin(scoped_refptr<VizProcessContextProvider> context_provider,
SyntheticBeginFrameSource* synthetic_begin_frame_source,
bool use_overlays);
~GLOutputSurfaceWin() override;
diff --git a/chromium/components/viz/service/display_embedder/gpu_display_provider.cc b/chromium/components/viz/service/display_embedder/gpu_display_provider.cc
index 45b178149bf..3da085bc5df 100644
--- a/chromium/components/viz/service/display_embedder/gpu_display_provider.cc
+++ b/chromium/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -7,18 +7,20 @@
#include <utility>
#include "base/command_line.h"
+#include "base/compiler_specific.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cc/base/switches.h"
#include "components/viz/common/display/renderer_settings.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
-#include "components/viz/common/gpu/in_process_context_provider.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display/display_scheduler.h"
#include "components/viz/service/display_embedder/external_begin_frame_controller_impl.h"
#include "components/viz/service/display_embedder/gl_output_surface.h"
#include "components/viz/service/display_embedder/in_process_gpu_memory_buffer_manager.h"
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
+#include "components/viz/service/display_embedder/skia_output_surface_impl.h"
#include "components/viz/service/display_embedder/software_output_surface.h"
+#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include "gpu/command_buffer/client/shared_memory_limits.h"
#include "gpu/command_buffer/service/image_factory.h"
#include "gpu/ipc/common/surface_handle.h"
@@ -64,11 +66,13 @@ namespace viz {
GpuDisplayProvider::GpuDisplayProvider(
uint32_t restart_id,
+ GpuServiceImpl* gpu_service_impl,
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
gpu::GpuChannelManager* gpu_channel_manager,
bool headless,
bool wait_for_all_pipeline_stages_before_draw)
: restart_id_(restart_id),
+ gpu_service_impl_(gpu_service_impl),
gpu_service_(std::move(gpu_service)),
gpu_channel_manager_delegate_(gpu_channel_manager->delegate()),
gpu_memory_buffer_manager_(
@@ -88,6 +92,7 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
+ mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source) {
@@ -103,21 +108,46 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
display_begin_frame_source = synthetic_begin_frame_source.get();
}
+ // TODO(penghuang): Merge two output surfaces into one when GLRenderer and
+ // software compositor is removed.
std::unique_ptr<OutputSurface> output_surface;
+ SkiaOutputSurface* skia_output_surface = nullptr;
if (!gpu_compositing) {
output_surface = std::make_unique<SoftwareOutputSurface>(
- CreateSoftwareOutputDeviceForPlatform(surface_handle), task_runner_);
+ CreateSoftwareOutputDeviceForPlatform(surface_handle, display_client));
+ } else if (renderer_settings.use_skia_renderer &&
+ renderer_settings.use_skia_deferred_display_list) {
+#if defined(OS_MACOSX) || defined(OS_WIN)
+ // TODO(penghuang): Support DDL for all platforms.
+ NOTIMPLEMENTED();
+ // Workaround compile error: private field 'gpu_service_impl_' is not used.
+ ALLOW_UNUSED_LOCAL(gpu_service_impl_);
+#else
+ // Create an offscreen context_provider for SkiaOutputSurfaceImpl, because
+ // SkiaRenderer still needs it to draw RenderPass into a texture.
+ // TODO(penghuang): Remove this context_provider. https://crbug.com/825901
+ auto context_provider = base::MakeRefCounted<VizProcessContextProvider>(
+ gpu_service_, gpu::kNullSurfaceHandle, gpu_memory_buffer_manager_.get(),
+ image_factory_, gpu_channel_manager_delegate_,
+ gpu::SharedMemoryLimits());
+ auto result = context_provider->BindToCurrentThread();
+ CHECK_EQ(result, gpu::ContextResult::kSuccess);
+ output_surface = std::make_unique<SkiaOutputSurfaceImpl>(
+ gpu_service_impl_, surface_handle, std::move(context_provider),
+ synthetic_begin_frame_source.get());
+ skia_output_surface = static_cast<SkiaOutputSurface*>(output_surface.get());
+#endif
} else {
- scoped_refptr<InProcessContextProvider> context_provider;
+ scoped_refptr<VizProcessContextProvider> context_provider;
// Retry creating and binding |context_provider| on transient failures.
gpu::ContextResult context_result = gpu::ContextResult::kTransientFailure;
while (context_result != gpu::ContextResult::kSuccess) {
- context_provider = base::MakeRefCounted<InProcessContextProvider>(
+ context_provider = base::MakeRefCounted<VizProcessContextProvider>(
gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(),
image_factory_, gpu_channel_manager_delegate_,
- gpu::SharedMemoryLimits(), nullptr /* shared_context */);
+ gpu::SharedMemoryLimits());
context_result = context_provider->BindToCurrentThread();
// TODO(crbug.com/819474): Don't crash here, instead fallback to software
@@ -166,34 +196,22 @@ std::unique_ptr<Display> GpuDisplayProvider::CreateDisplay(
return std::make_unique<Display>(
ServerSharedBitmapManager::current(), renderer_settings, frame_sink_id,
- std::move(output_surface), std::move(scheduler), task_runner_);
+ std::move(output_surface), std::move(scheduler), task_runner_,
+ skia_output_surface);
}
std::unique_ptr<SoftwareOutputDevice>
GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
- gpu::SurfaceHandle surface_handle) {
+ gpu::SurfaceHandle surface_handle,
+ mojom::DisplayClient* display_client) {
if (headless_)
return std::make_unique<SoftwareOutputDevice>();
-#if defined(GPU_SURFACE_HANDLE_IS_ACCELERATED_WINDOW)
- gfx::AcceleratedWidget widget = surface_handle;
-#endif
-
#if defined(OS_WIN)
- if (!output_device_backing_)
- output_device_backing_ = std::make_unique<OutputDeviceBacking>();
- return std::make_unique<SoftwareOutputDeviceWin>(output_device_backing_.get(),
- widget);
+ return CreateSoftwareOutputDeviceWinGpu(
+ surface_handle, &output_device_backing_, display_client);
#elif defined(OS_MACOSX)
- // TODO(crbug.com/730660): What do we do to get something we can draw to? Can
- // we use an IO surface? Can we use CA layers and overlays like we do for gpu
- // compositing? See https://crrev.com/c/792295 to no longer have
- // GpuSurfaceTracker. Part of the SoftwareOutputDeviceMac::EndPaint probably
- // needs to move to the browser process, and we need to set up transport of an
- // IO surface to here?
- NOTIMPLEMENTED();
- (void)widget;
- return nullptr;
+ return std::make_unique<SoftwareOutputDeviceMac>(task_runner_);
#elif defined(OS_ANDROID)
// Android does not do software compositing, so we can't get here.
NOTREACHED();
@@ -202,11 +220,11 @@ GpuDisplayProvider::CreateSoftwareOutputDeviceForPlatform(
ui::SurfaceFactoryOzone* factory =
ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
std::unique_ptr<ui::SurfaceOzoneCanvas> surface_ozone =
- factory->CreateCanvasForWidget(widget);
+ factory->CreateCanvasForWidget(surface_handle);
CHECK(surface_ozone);
return std::make_unique<SoftwareOutputDeviceOzone>(std::move(surface_ozone));
#elif defined(USE_X11)
- return std::make_unique<SoftwareOutputDeviceX11>(widget);
+ return std::make_unique<SoftwareOutputDeviceX11>(surface_handle);
#endif
}
diff --git a/chromium/components/viz/service/display_embedder/gpu_display_provider.h b/chromium/components/viz/service/display_embedder/gpu_display_provider.h
index 0a4c19bbfa8..f714ee18a64 100644
--- a/chromium/components/viz/service/display_embedder/gpu_display_provider.h
+++ b/chromium/components/viz/service/display_embedder/gpu_display_provider.h
@@ -18,6 +18,10 @@
#include "gpu/ipc/common/surface_handle.h"
#include "gpu/ipc/in_process_command_buffer.h"
+#if defined(OS_WIN)
+#include "components/viz/service/display_embedder/output_device_backing.h"
+#endif
+
namespace gpu {
class GpuChannelManager;
class GpuChannelManagerDelegate;
@@ -27,7 +31,7 @@ class ImageFactory;
namespace viz {
class Display;
class ExternalBeginFrameControllerImpl;
-class OutputDeviceBacking;
+class GpuServiceImpl;
class SoftwareOutputDevice;
// In-process implementation of DisplayProvider.
@@ -35,6 +39,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
public:
GpuDisplayProvider(
uint32_t restart_id,
+ GpuServiceImpl* gpu_service_impl,
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
gpu::GpuChannelManager* gpu_channel_manager,
bool headless,
@@ -46,6 +51,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
const FrameSinkId& frame_sink_id,
gpu::SurfaceHandle surface_handle,
bool gpu_compositing,
+ mojom::DisplayClient* display_client,
ExternalBeginFrameControllerImpl* external_begin_frame_controller,
const RendererSettings& renderer_settings,
std::unique_ptr<SyntheticBeginFrameSource>* out_begin_frame_source)
@@ -53,9 +59,11 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
private:
std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceForPlatform(
- gpu::SurfaceHandle surface_handle);
+ gpu::SurfaceHandle surface_handle,
+ mojom::DisplayClient* display_client);
const uint32_t restart_id_;
+ GpuServiceImpl* const gpu_service_impl_;
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
gpu::GpuChannelManagerDelegate* const gpu_channel_manager_delegate_;
std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
@@ -63,7 +71,7 @@ class VIZ_SERVICE_EXPORT GpuDisplayProvider : public DisplayProvider {
#if defined(OS_WIN)
// Used for software compositing output on Windows.
- std::unique_ptr<OutputDeviceBacking> output_device_backing_;
+ OutputDeviceBacking output_device_backing_;
#endif
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/chromium/components/viz/service/display_embedder/output_device_backing.cc b/chromium/components/viz/service/display_embedder/output_device_backing.cc
new file mode 100644
index 00000000000..68e3aca8758
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_device_backing.cc
@@ -0,0 +1,102 @@
+// 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 "components/viz/service/display_embedder/output_device_backing.h"
+
+#include <algorithm>
+
+#include "base/debug/alias.h"
+#include "base/memory/shared_memory.h"
+#include "base/stl_util.h"
+#include "components/viz/common/resources/resource_sizes.h"
+
+namespace viz {
+namespace {
+
+// If a window is larger than this in bytes, don't even try to create a backing
+// bitmap for it.
+constexpr size_t kMaxBitmapSizeBytes = 4 * (16384 * 8192);
+
+// Finds the size in bytes to hold |viewport_size| pixels. If |viewport_size| is
+// a valid size this will return true and |out_bytes| will contain the size in
+// bytes. If |viewport_size| is not a valid size then this will return false.
+bool GetViewportSizeInBytes(const gfx::Size& viewport_size, size_t* out_bytes) {
+ size_t bytes;
+ if (!ResourceSizes::MaybeSizeInBytes(viewport_size, RGBA_8888, &bytes))
+ return false;
+ if (bytes > kMaxBitmapSizeBytes)
+ return false;
+ *out_bytes = bytes;
+ return true;
+}
+
+} // namespace
+
+OutputDeviceBacking::OutputDeviceBacking() = default;
+
+OutputDeviceBacking::~OutputDeviceBacking() {
+ DCHECK(clients_.empty());
+}
+
+void OutputDeviceBacking::ClientResized() {
+ // If the max viewport size doesn't change then nothing here changes.
+ if (GetMaxViewportBytes() == created_shm_bytes_)
+ return;
+
+ // Otherwise we need to allocate a new SharedMemory segment and clients
+ // should re-request it.
+ for (auto* client : clients_)
+ client->ReleaseCanvas();
+
+ shm_.reset();
+ created_shm_bytes_ = 0;
+}
+
+void OutputDeviceBacking::RegisterClient(Client* client) {
+ clients_.push_back(client);
+}
+
+void OutputDeviceBacking::UnregisterClient(Client* client) {
+ DCHECK(base::ContainsValue(clients_, client));
+ base::Erase(clients_, client);
+ ClientResized();
+}
+
+base::SharedMemory* OutputDeviceBacking::GetSharedMemory(
+ const gfx::Size& viewport_size) {
+ // If |viewport_size| is empty or too big don't try to allocate SharedMemory.
+ size_t viewport_bytes;
+ if (!GetViewportSizeInBytes(viewport_size, &viewport_bytes))
+ return nullptr;
+
+ // Allocate a new SharedMemory segment that can fit the largest viewport.
+ if (!shm_) {
+ size_t max_viewport_bytes = GetMaxViewportBytes();
+ DCHECK_LE(viewport_bytes, max_viewport_bytes);
+
+ shm_ = std::make_unique<base::SharedMemory>();
+ base::debug::Alias(&max_viewport_bytes);
+ CHECK(shm_->CreateAnonymous(max_viewport_bytes));
+ created_shm_bytes_ = max_viewport_bytes;
+ } else {
+ // Clients must call Resize() for new |viewport_size|.
+ DCHECK_LE(viewport_bytes, created_shm_bytes_);
+ }
+
+ return shm_.get();
+}
+
+size_t OutputDeviceBacking::GetMaxViewportBytes() {
+ // Minimum byte size is 1 because creating a 0-byte-long SharedMemory fails.
+ size_t max_bytes = 1;
+ for (auto* client : clients_) {
+ size_t current_bytes;
+ if (!GetViewportSizeInBytes(client->GetViewportPixelSize(), &current_bytes))
+ continue;
+ max_bytes = std::max(max_bytes, current_bytes);
+ }
+ return max_bytes;
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/output_device_backing.h b/chromium/components/viz/service/display_embedder/output_device_backing.h
new file mode 100644
index 00000000000..b3a9b1cb81c
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_device_backing.h
@@ -0,0 +1,65 @@
+// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_DEVICE_BACKING_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_DEVICE_BACKING_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/viz/service/viz_service_export.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace viz {
+
+// Allocates and owns a SharedMemory backing for multiple SoftwareOutputDevices.
+// The backing will be big enough to hold the largest size returned by a
+// client's GetViewportPixelSize().
+class VIZ_SERVICE_EXPORT OutputDeviceBacking {
+ public:
+ class Client {
+ public:
+ virtual const gfx::Size& GetViewportPixelSize() const = 0;
+ virtual void ReleaseCanvas() = 0;
+
+ protected:
+ virtual ~Client() = default;
+ };
+
+ OutputDeviceBacking();
+ ~OutputDeviceBacking();
+
+ void RegisterClient(Client* client);
+ void UnregisterClient(Client* client);
+
+ // Called when a client has resized. Clients should call Resize() after being
+ // registered when they have a valid size. Will potential invalidate
+ // SharedMemory and call ReleaseCanvas() on clients.
+ void ClientResized();
+
+ // Requests a SharedMemory segment large enough to fit |viewport_size|. Will
+ // return null if |viewport_size| is too large to safely allocate SharedMemory
+ // for.
+ base::SharedMemory* GetSharedMemory(const gfx::Size& viewport_size);
+
+ // Returns the maximum size in bytes needed for the largest viewport from
+ // registered clients.
+ size_t GetMaxViewportBytes();
+
+ private:
+ std::vector<Client*> clients_;
+ std::unique_ptr<base::SharedMemory> shm_;
+ size_t created_shm_bytes_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(OutputDeviceBacking);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_OUTPUT_DEVICE_BACKING_H_
diff --git a/chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc b/chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc
new file mode 100644
index 00000000000..916573333a6
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/output_device_backing_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/viz/service/display_embedder/output_device_backing.h"
+
+#include <limits>
+#include <memory>
+
+#include "components/viz/common/resources/resource_sizes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace viz {
+namespace {
+
+size_t GetViewportSizeInBytes(const gfx::Size& viewport_size) {
+ size_t bytes = std::numeric_limits<size_t>::max();
+ CHECK(ResourceSizes::MaybeSizeInBytes(viewport_size, RGBA_8888, &bytes));
+ return bytes;
+}
+
+// Test implementation with a set viewport size.
+class TestBackingClient : public OutputDeviceBacking::Client {
+ public:
+ TestBackingClient(OutputDeviceBacking* backing,
+ const gfx::Size& viewport_size)
+ : backing_(backing), viewport_size_(viewport_size) {
+ backing_->RegisterClient(this);
+ backing_->ClientResized();
+ backing_->GetSharedMemory(viewport_size_);
+ }
+ ~TestBackingClient() override { backing_->UnregisterClient(this); }
+
+ const gfx::Size& viewport_size() const { return viewport_size_; }
+ bool release_canvas_called() const { return release_canvas_called_; }
+
+ // OutputDeviceBacking::Client implementation.
+ const gfx::Size& GetViewportPixelSize() const override {
+ return viewport_size_;
+ }
+ void ReleaseCanvas() override { release_canvas_called_ = true; }
+
+ private:
+ OutputDeviceBacking* const backing_;
+ gfx::Size viewport_size_;
+ bool release_canvas_called_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TestBackingClient);
+};
+
+} // namespace
+
+// Verify GetMaxViewportBytes() returns the size in bytes of the largest
+// viewport.
+TEST(OutputDeviceBackingTest, GetMaxViewportBytes) {
+ OutputDeviceBacking backing;
+ TestBackingClient client_a(&backing, gfx::Size(1024, 768));
+ TestBackingClient client_b(&backing, gfx::Size(1920, 1080));
+
+ EXPECT_EQ(GetViewportSizeInBytes(client_b.viewport_size()),
+ backing.GetMaxViewportBytes());
+}
+
+// Verify that unregistering a client works as expected.
+TEST(OutputDeviceBackingTest, UnregisterClient) {
+ OutputDeviceBacking backing;
+ auto client_a =
+ std::make_unique<TestBackingClient>(&backing, gfx::Size(1920, 1080));
+ auto client_b =
+ std::make_unique<TestBackingClient>(&backing, gfx::Size(1080, 1920));
+ auto client_c =
+ std::make_unique<TestBackingClient>(&backing, gfx::Size(1024, 768));
+
+ // Unregister one of the clients with the 1920x1080 viewport size.
+ client_a.reset();
+
+ // After removing |client_a| the max viewport didn't change so ReleaseCanvas()
+ // shouldn't be have been called.
+ EXPECT_FALSE(client_b->release_canvas_called());
+ EXPECT_FALSE(client_c->release_canvas_called());
+
+ // Unregister the second client with 1920x1080 viewport.
+ client_b.reset();
+
+ // After removing |client_b| then max viewport did change so ReleaseCanvas()
+ // should have been called.
+ EXPECT_TRUE(client_c->release_canvas_called());
+
+ EXPECT_EQ(GetViewportSizeInBytes(client_c->viewport_size()),
+ backing.GetMaxViewportBytes());
+}
+
+// Verify that a client with a viewport that is too large doesn't allocate
+// SharedMemory.
+TEST(OutputDeviceBackingTest, ViewportSizeBiggerThanMax) {
+ OutputDeviceBacking backing;
+
+ // The viewport is bigger than |kMaxBitmapSizeBytes| and OutputDeviceBacking
+ // won't try to create SharedMemory for it.
+ TestBackingClient client_a(&backing, gfx::Size(16385, 8193));
+ EXPECT_EQ(nullptr, backing.GetSharedMemory(client_a.viewport_size()));
+
+ // This should cause SharedMemory to get allocated.
+ TestBackingClient client_b(&backing, gfx::Size(1024, 768));
+ EXPECT_NE(nullptr, backing.GetSharedMemory(client_b.viewport_size()));
+
+ // Even though SharedMemory was allocated to fit |client_b|, it will be too
+ // small for |client_a| and GetSharedMemory() should still return null.
+ EXPECT_EQ(nullptr, backing.GetSharedMemory(client_a.viewport_size()));
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
index a9745b91c9c..9d84f91109a 100644
--- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
+++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.cc
@@ -23,10 +23,7 @@ namespace viz {
class BitmapData : public base::RefCountedThreadSafe<BitmapData> {
public:
explicit BitmapData(size_t buffer_size) : buffer_size(buffer_size) {}
- // For shm allocated and shared from a client out-of-process.
std::unique_ptr<base::SharedMemory> memory;
- // For memory allocated by the ServerSharedBitmapManager for in-process.
- std::unique_ptr<uint8_t[]> pixels;
size_t buffer_size;
private:
@@ -39,31 +36,23 @@ namespace {
class ServerSharedBitmap : public SharedBitmap {
public:
- ServerSharedBitmap(uint8_t* pixels,
- scoped_refptr<BitmapData> bitmap_data,
- const SharedBitmapId& id,
- ServerSharedBitmapManager* manager)
- : SharedBitmap(pixels, id, 0 /* sequence_number */),
- bitmap_data_(bitmap_data),
- manager_(manager) {}
+ ServerSharedBitmap(scoped_refptr<BitmapData> bitmap_data,
+ const SharedBitmapId& id)
+ : SharedBitmap(static_cast<uint8_t*>(bitmap_data->memory->memory()),
+ id,
+ 0 /* sequence_number */),
+ bitmap_data_(std::move(bitmap_data)) {}
~ServerSharedBitmap() override {
- if (manager_)
- manager_->FreeSharedMemoryFromMap(id());
}
// SharedBitmap implementation.
base::UnguessableToken GetCrossProcessGUID() const override {
- if (!bitmap_data_->memory) {
- // Locally allocated for in-process use.
- return {};
- }
return bitmap_data_->memory->mapped_id();
}
private:
scoped_refptr<BitmapData> bitmap_data_;
- ServerSharedBitmapManager* manager_;
};
} // namespace
@@ -81,26 +70,6 @@ ServerSharedBitmapManager* ServerSharedBitmapManager::current() {
return g_shared_memory_manager.Pointer();
}
-std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::AllocateSharedBitmap(
- const gfx::Size& size,
- ResourceFormat format) {
- DCHECK(IsBitmapFormatSupported(format));
- base::AutoLock lock(lock_);
- size_t bitmap_size;
- if (!ResourceSizes::MaybeSizeInBytes(size, format, &bitmap_size))
- return nullptr;
-
- scoped_refptr<BitmapData> data(new BitmapData(bitmap_size));
- // Bitmaps allocated in server don't need to be shared to other processes, so
- // allocate them with new instead.
- data->pixels = std::unique_ptr<uint8_t[]>(new uint8_t[bitmap_size]);
-
- SharedBitmapId id = SharedBitmap::GenerateId();
- handle_map_[id] = data;
- return std::make_unique<ServerSharedBitmap>(data->pixels.get(), data, id,
- this);
-}
-
std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId(
const gfx::Size& size,
ResourceFormat format,
@@ -117,16 +86,11 @@ std::unique_ptr<SharedBitmap> ServerSharedBitmapManager::GetSharedBitmapFromId(
bitmap_size > data->buffer_size)
return nullptr;
- if (data->pixels) {
- return std::make_unique<ServerSharedBitmap>(data->pixels.get(), data, id,
- nullptr);
- }
if (!data->memory->memory()) {
return nullptr;
}
- return std::make_unique<ServerSharedBitmap>(
- static_cast<uint8_t*>(data->memory->memory()), data, id, nullptr);
+ return std::make_unique<ServerSharedBitmap>(data, id);
}
bool ServerSharedBitmapManager::ChildAllocatedSharedBitmap(
diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h
index af9be4360b3..57810735850 100644
--- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h
+++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager.h
@@ -36,9 +36,6 @@ class VIZ_SERVICE_EXPORT ServerSharedBitmapManager
static ServerSharedBitmapManager* current();
// SharedBitmapManager implementation.
- std::unique_ptr<SharedBitmap> AllocateSharedBitmap(
- const gfx::Size& size,
- ResourceFormat format) override;
std::unique_ptr<SharedBitmap> GetSharedBitmapFromId(
const gfx::Size& size,
ResourceFormat format,
diff --git a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
index cce61d24a22..b5923739380 100644
--- a/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/server_shared_bitmap_manager_unittest.cc
@@ -5,7 +5,6 @@
#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
#include "components/viz/common/resources/resource_sizes.h"
-#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,12 +35,11 @@ TEST_F(ServerSharedBitmapManagerTest, TestCreate) {
memset(bitmap->memory(), 0xff, size_in_bytes);
SharedBitmapId id = SharedBitmap::GenerateId();
- SharedBitmapAllocationNotifierImpl notifier(manager());
base::SharedMemoryHandle handle = bitmap->handle().Duplicate();
mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
handle, size_in_bytes,
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
- notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
+ manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
std::unique_ptr<SharedBitmap> large_bitmap;
large_bitmap =
@@ -81,7 +79,7 @@ TEST_F(ServerSharedBitmapManagerTest, TestCreate) {
EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
0);
- notifier.DidDeleteSharedBitmap(id);
+ manager()->ChildDeletedSharedBitmap(id);
memset(bitmap->memory(), 0, size_in_bytes);
@@ -91,42 +89,6 @@ TEST_F(ServerSharedBitmapManagerTest, TestCreate) {
shared_bitmap.reset();
}
-TEST_F(ServerSharedBitmapManagerTest, ServiceDestroyed) {
- gfx::Size bitmap_size(1, 1);
- size_t size_in_bytes;
- EXPECT_TRUE(
- ResourceSizes::MaybeSizeInBytes(bitmap_size, RGBA_8888, &size_in_bytes));
- std::unique_ptr<base::SharedMemory> bitmap(new base::SharedMemory());
- bitmap->CreateAndMapAnonymous(size_in_bytes);
- memset(bitmap->memory(), 0xff, size_in_bytes);
- SharedBitmapId id = SharedBitmap::GenerateId();
-
- // This outlives the SharedBitmapAllocationNotifier.
- std::unique_ptr<SharedBitmap> shared_bitmap;
-
- {
- SharedBitmapAllocationNotifierImpl notifier(manager());
- base::SharedMemoryHandle handle = bitmap->handle().Duplicate();
- mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
- handle, size_in_bytes,
- mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
- notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
-
- shared_bitmap =
- manager()->GetSharedBitmapFromId(bitmap_size, RGBA_8888, id);
- ASSERT_TRUE(shared_bitmap.get() != nullptr);
-
- EXPECT_EQ(1u, manager()->AllocatedBitmapCount());
- }
- EXPECT_EQ(0u, manager()->AllocatedBitmapCount());
-
- std::unique_ptr<SharedBitmap> shared_bitmap2;
- shared_bitmap2 = manager()->GetSharedBitmapFromId(bitmap_size, RGBA_8888, id);
- EXPECT_FALSE(!!shared_bitmap2);
- EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
- 0);
-}
-
TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) {
gfx::Size bitmap_size(1, 1);
size_t size_in_bytes;
@@ -137,13 +99,11 @@ TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) {
memset(bitmap->memory(), 0xff, size_in_bytes);
SharedBitmapId id = SharedBitmap::GenerateId();
- SharedBitmapAllocationNotifierImpl notifier(manager());
-
base::SharedMemoryHandle handle = bitmap->handle().Duplicate();
mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
handle, size_in_bytes,
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
- notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
+ manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
std::unique_ptr<base::SharedMemory> bitmap2(new base::SharedMemory());
bitmap2->CreateAndMapAnonymous(size_in_bytes);
@@ -153,14 +113,14 @@ TEST_F(ServerSharedBitmapManagerTest, AddDuplicate) {
buffer_handle = mojo::WrapSharedMemoryHandle(
handle2, size_in_bytes,
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
- notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
+ manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
std::unique_ptr<SharedBitmap> shared_bitmap;
shared_bitmap = manager()->GetSharedBitmapFromId(bitmap_size, RGBA_8888, id);
ASSERT_TRUE(shared_bitmap.get() != nullptr);
EXPECT_EQ(memcmp(shared_bitmap->pixels(), bitmap->memory(), size_in_bytes),
0);
- notifier.DidDeleteSharedBitmap(id);
+ manager()->ChildDeletedSharedBitmap(id);
}
TEST_F(ServerSharedBitmapManagerTest, SharedMemoryHandle) {
@@ -174,21 +134,19 @@ TEST_F(ServerSharedBitmapManagerTest, SharedMemoryHandle) {
base::UnguessableToken shared_memory_guid = bitmap->handle().GetGUID();
EXPECT_FALSE(shared_memory_guid.is_empty());
- SharedBitmapAllocationNotifierImpl notifier(manager());
-
SharedBitmapId id = SharedBitmap::GenerateId();
base::SharedMemoryHandle handle = bitmap->handle().Duplicate();
mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
handle, size_in_bytes,
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
- notifier.ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
+ manager()->ChildAllocatedSharedBitmap(std::move(buffer_handle), id);
std::unique_ptr<SharedBitmap> shared_bitmap;
shared_bitmap =
manager()->GetSharedBitmapFromId(gfx::Size(1, 1), RGBA_8888, id);
EXPECT_EQ(shared_bitmap->GetCrossProcessGUID(), shared_memory_guid);
- notifier.DidDeleteSharedBitmap(id);
+ manager()->ChildDeletedSharedBitmap(id);
}
} // namespace
diff --git a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
deleted file mode 100644
index fa5468d37a3..00000000000
--- a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h"
-
-#include "components/viz/service/display_embedder/server_shared_bitmap_manager.h"
-#include "mojo/public/cpp/system/platform_handle.h"
-
-namespace viz {
-
-SharedBitmapAllocationNotifierImpl::SharedBitmapAllocationNotifierImpl(
- ServerSharedBitmapManager* manager)
- : manager_(manager), binding_(this) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
-}
-
-SharedBitmapAllocationNotifierImpl::~SharedBitmapAllocationNotifierImpl() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- ChildDied();
-}
-
-void SharedBitmapAllocationNotifierImpl::Bind(
- mojom::SharedBitmapAllocationNotifierRequest request) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (binding_.is_bound()) {
- DLOG(ERROR) << "Only one SharedBitmapAllocationNotifierRequest is "
- << "expected from the renderer.";
- return;
- }
- binding_.Bind(std::move(request));
-}
-
-void SharedBitmapAllocationNotifierImpl::DidAllocateSharedBitmap(
- mojo::ScopedSharedBufferHandle buffer,
- const SharedBitmapId& id) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- this->ChildAllocatedSharedBitmap(std::move(buffer), id);
- last_sequence_number_++;
- for (SharedBitmapAllocationObserver& observer : observers_)
- observer.OnSharedBitmapAllocatedByChild(last_sequence_number_);
-}
-
-void SharedBitmapAllocationNotifierImpl::DidDeleteSharedBitmap(
- const SharedBitmapId& id) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- manager_->ChildDeletedSharedBitmap(id);
- owned_bitmaps_.erase(id);
-}
-
-void SharedBitmapAllocationNotifierImpl::ChildAllocatedSharedBitmap(
- mojo::ScopedSharedBufferHandle buffer,
- const SharedBitmapId& id) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (manager_->ChildAllocatedSharedBitmap(std::move(buffer), id))
- owned_bitmaps_.insert(id);
-}
-
-void SharedBitmapAllocationNotifierImpl::ChildDied() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- for (const auto& id : owned_bitmaps_)
- manager_->ChildDeletedSharedBitmap(id);
- owned_bitmaps_.clear();
- binding_.Close();
-}
-
-void SharedBitmapAllocationNotifierImpl::AddObserver(
- SharedBitmapAllocationObserver* observer) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- observers_.AddObserver(observer);
-}
-
-void SharedBitmapAllocationNotifierImpl::RemoveObserver(
- SharedBitmapAllocationObserver* observer) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- observers_.RemoveObserver(observer);
-}
-
-} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h b/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
deleted file mode 100644
index 0b4e32ddaf8..00000000000
--- a/chromium/components/viz/service/display_embedder/shared_bitmap_allocation_notifier_impl.h
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SHARED_BITMAP_ALLOCATION_NOTIFIER_IMPL_H_
-#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SHARED_BITMAP_ALLOCATION_NOTIFIER_IMPL_H_
-
-#include <unordered_set>
-
-#include "base/observer_list.h"
-#include "base/threading/thread_checker.h"
-#include "components/viz/common/quads/shared_bitmap.h"
-#include "components/viz/service/viz_service_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/viz/public/interfaces/compositing/shared_bitmap_allocation_notifier.mojom.h"
-
-namespace viz {
-class ServerSharedBitmapManager;
-
-class SharedBitmapAllocationObserver {
- public:
- virtual void OnSharedBitmapAllocatedByChild(uint32_t sequence_number) = 0;
-};
-
-class VIZ_SERVICE_EXPORT SharedBitmapAllocationNotifierImpl
- : public mojom::SharedBitmapAllocationNotifier {
- public:
- explicit SharedBitmapAllocationNotifierImpl(
- ServerSharedBitmapManager* manager);
-
- ~SharedBitmapAllocationNotifierImpl() override;
-
- void AddObserver(SharedBitmapAllocationObserver* observer);
- void RemoveObserver(SharedBitmapAllocationObserver* observer);
-
- void Bind(mojom::SharedBitmapAllocationNotifierRequest request);
-
- // mojom::SharedBitmapAllocationNotifier overrides:
- void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
- const SharedBitmapId& id) override;
- void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
-
- void ChildAllocatedSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
- const SharedBitmapId& id);
-
- void ChildDied();
-
- uint32_t last_sequence_number() const { return last_sequence_number_; }
-
- private:
- THREAD_CHECKER(thread_checker_);
- ServerSharedBitmapManager* const manager_;
- mojo::Binding<mojom::SharedBitmapAllocationNotifier> binding_;
- std::unordered_set<SharedBitmapId, SharedBitmapIdHash> owned_bitmaps_;
- base::ObserverList<SharedBitmapAllocationObserver> observers_;
- uint32_t last_sequence_number_ = 0;
-
- DISALLOW_COPY_AND_ASSIGN(SharedBitmapAllocationNotifierImpl);
-};
-
-} // namespace viz
-
-#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SHARED_BITMAP_ALLOCATION_NOTIFIER_IMPL_H_
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
new file mode 100644
index 00000000000..ac7b616b261
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -0,0 +1,516 @@
+// 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 "components/viz/service/display_embedder/skia_output_surface_impl.h"
+
+#include "base/callback_helpers.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/viz/common/frame_sinks/begin_frame_source.h"
+#include "components/viz/common/resources/resource_format_utils.h"
+#include "components/viz/common/resources/resource_metadata.h"
+#include "components/viz/service/display/output_surface_client.h"
+#include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"
+#include "components/viz/service/display_embedder/viz_process_context_provider.h"
+#include "components/viz/service/gl/gpu_service_impl.h"
+#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/service/scheduler.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_gl_api_implementation.h"
+
+namespace viz {
+
+namespace {
+
+template <typename... Args>
+void PostAsyncTask(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const base::RepeatingCallback<void(Args...)>& callback,
+ Args... args) {
+ task_runner->PostTask(FROM_HERE, base::BindOnce(callback, args...));
+}
+
+template <typename... Args>
+base::RepeatingCallback<void(Args...)> CreateSafeCallback(
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const base::RepeatingCallback<void(Args...)>& callback) {
+ return base::BindRepeating(&PostAsyncTask<Args...>, task_runner, callback);
+}
+
+} // namespace
+
+// A helper class for fullfilling promise image on the GPU thread.
+template <class FullfillContextType>
+class SkiaOutputSurfaceImpl::PromiseTextureHelper {
+ public:
+ using HelperType = PromiseTextureHelper<FullfillContextType>;
+
+ PromiseTextureHelper(base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu,
+ FullfillContextType context)
+ : impl_on_gpu_(impl_on_gpu), context_(std::move(context)) {}
+ ~PromiseTextureHelper() = default;
+
+ static sk_sp<SkImage> MakePromiseSkImage(
+ SkiaOutputSurfaceImpl* impl,
+ SkDeferredDisplayListRecorder* recorder,
+ const GrBackendFormat& backend_format,
+ gfx::Size size,
+ GrMipMapped mip_mapped,
+ GrSurfaceOrigin origin,
+ SkColorType color_type,
+ SkAlphaType alpha_type,
+ sk_sp<SkColorSpace> color_space,
+ FullfillContextType context) {
+ DCHECK_CALLED_ON_VALID_THREAD(impl->thread_checker_);
+ auto helper = std::make_unique<HelperType>(impl->impl_on_gpu_->weak_ptr(),
+ std::move(context));
+ auto image = recorder->makePromiseTexture(
+ backend_format, size.width(), size.height(), mip_mapped, origin,
+ color_type, alpha_type, color_space, HelperType::Fullfill,
+ HelperType::Release, HelperType::Done, helper.get());
+ if (image) {
+ helper->Init(impl);
+ helper.release();
+ }
+ return image;
+ }
+
+ private:
+ void Init(SkiaOutputSurfaceImpl* impl);
+
+ static void Fullfill(void* texture_context,
+ GrBackendTexture* backend_texture) {
+ DCHECK(texture_context);
+ auto* helper = static_cast<HelperType*>(texture_context);
+ // The fullfill is always called by SkiaOutputSurfaceImplOnGpu::SwapBuffers
+ // or SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass, so impl_on_gpu_
+ // should be always valid.
+ DCHECK(helper->impl_on_gpu_);
+ helper->impl_on_gpu_->FullfillPromiseTexture(helper->context_,
+ backend_texture);
+ }
+
+ static void Release(void* texture_context) { DCHECK(texture_context); }
+
+ static void Done(void* texture_context) {
+ DCHECK(texture_context);
+ std::unique_ptr<HelperType> helper(
+ static_cast<HelperType*>(texture_context));
+ }
+
+ base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_;
+
+ // The data for calling the fullfill methods in SkiaOutputSurfaceImpl.
+ FullfillContextType context_;
+
+ DISALLOW_COPY_AND_ASSIGN(PromiseTextureHelper);
+};
+
+template <class T>
+void SkiaOutputSurfaceImpl::PromiseTextureHelper<T>::Init(
+ SkiaOutputSurfaceImpl* impl) {}
+
+// For YUVResourceMetadata, we need to record the |context_| pointer in
+// |impl->yuv_resource_metadatas_|, because we have to create SkImage from YUV
+// textures before drawing the ddl to a SKSurface.
+// TODO(penghuang): Remove this hack when Skia supports drawing YUV textures
+// directly.
+template <>
+void SkiaOutputSurfaceImpl::PromiseTextureHelper<YUVResourceMetadata>::Init(
+ SkiaOutputSurfaceImpl* impl) {
+ impl->yuv_resource_metadatas_.push_back(&context_);
+}
+
+SkiaOutputSurfaceImpl::SkiaOutputSurfaceImpl(
+ GpuServiceImpl* gpu_service,
+ gpu::SurfaceHandle surface_handle,
+ scoped_refptr<VizProcessContextProvider> context_provider,
+ SyntheticBeginFrameSource* synthetic_begin_frame_source)
+ : SkiaOutputSurface(context_provider),
+ gpu_service_(gpu_service),
+ surface_handle_(surface_handle),
+ synthetic_begin_frame_source_(synthetic_begin_frame_source),
+ weak_ptr_factory_(this) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+SkiaOutputSurfaceImpl::~SkiaOutputSurfaceImpl() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ recorder_ = nullptr;
+ // Use GPU scheduler to release impl_on_gpu_ on the GPU thread, so all
+ // scheduled tasks for the impl_on_gpu_ will be executed, before releasing
+ // it. The GPU thread is the main thread of the viz process. It outlives the
+ // compositor thread. We don't need worry about it for now.
+ auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+ auto callback =
+ base::BindOnce([](std::unique_ptr<SkiaOutputSurfaceImplOnGpu>) {},
+ std::move(impl_on_gpu_));
+ gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+ sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
+}
+
+void SkiaOutputSurfaceImpl::BindToClient(OutputSurfaceClient* client) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(client);
+ DCHECK(!client_);
+
+ client_ = client;
+ weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+ client_thread_task_runner_ = base::ThreadTaskRunnerHandle::Get();
+
+ base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+ auto callback = base::BindOnce(&SkiaOutputSurfaceImpl::InitializeOnGpuThread,
+ base::Unretained(this), &event);
+ gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+ sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
+ event.Wait();
+}
+
+void SkiaOutputSurfaceImpl::EnsureBackbuffer() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+}
+
+void SkiaOutputSurfaceImpl::DiscardBackbuffer() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+}
+
+void SkiaOutputSurfaceImpl::BindFramebuffer() {
+ // TODO(penghuang): remove this method when GLRenderer is removed.
+}
+
+void SkiaOutputSurfaceImpl::SetDrawRectangle(const gfx::Rect& draw_rectangle) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+}
+
+void SkiaOutputSurfaceImpl::Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha,
+ bool use_stencil) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ recorder_ = nullptr;
+ SkSurfaceCharacterization* characterization = nullptr;
+ std::unique_ptr<base::WaitableEvent> event;
+ if (characterization_.isValid()) {
+ characterization_ =
+ characterization_.createResized(size.width(), size.height());
+ } else {
+ characterization = &characterization_;
+ // TODO(penghuang): avoid blocking compositor thread.
+ // We don't have a valid surface characterization, so we have to wait
+ // until reshape is finished on Gpu thread.
+ event = std::make_unique<base::WaitableEvent>(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ }
+
+ auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+ // impl_on_gpu_ is released on the GPU thread by a posted task from
+ // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
+ auto callback = base::BindOnce(&SkiaOutputSurfaceImplOnGpu::Reshape,
+ base::Unretained(impl_on_gpu_.get()), size,
+ device_scale_factor, color_space, has_alpha,
+ use_stencil, characterization, event.get());
+ gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+ sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
+
+ if (event)
+ event->Wait();
+ RecreateRecorder();
+}
+
+void SkiaOutputSurfaceImpl::SwapBuffers(OutputSurfaceFrame frame) {
+ NOTREACHED();
+}
+
+uint32_t SkiaOutputSurfaceImpl::GetFramebufferCopyTextureFormat() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ return GL_RGB;
+}
+
+OverlayCandidateValidator* SkiaOutputSurfaceImpl::GetOverlayCandidateValidator()
+ const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return nullptr;
+}
+
+bool SkiaOutputSurfaceImpl::IsDisplayedAsOverlayPlane() const {
+ return false;
+}
+
+unsigned SkiaOutputSurfaceImpl::GetOverlayTextureId() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return 0;
+}
+
+gfx::BufferFormat SkiaOutputSurfaceImpl::GetOverlayBufferFormat() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return gfx::BufferFormat::RGBX_8888;
+}
+
+bool SkiaOutputSurfaceImpl::HasExternalStencilTest() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ return false;
+}
+
+void SkiaOutputSurfaceImpl::ApplyExternalStencil() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+#if BUILDFLAG(ENABLE_VULKAN)
+gpu::VulkanSurface* SkiaOutputSurfaceImpl::GetVulkanSurface() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ return nullptr;
+}
+#endif
+
+unsigned SkiaOutputSurfaceImpl::UpdateGpuFence() {
+ return 0;
+}
+
+SkCanvas* SkiaOutputSurfaceImpl::GetSkCanvasForCurrentFrame() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(recorder_);
+ DCHECK_EQ(current_render_pass_id_, 0u);
+
+ return recorder_->getCanvas();
+}
+
+sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImage(
+ ResourceMetadata metadata) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(recorder_);
+
+ // Convert internal format from GLES2 to platform GL.
+ const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
+ metadata.backend_format = GrBackendFormat::MakeGL(
+ gl::GetInternalFormat(version_info,
+ *metadata.backend_format.getGLFormat()),
+ *metadata.backend_format.getGLTarget());
+
+ DCHECK(!metadata.mailbox.IsZero());
+ resource_sync_tokens_.push_back(metadata.sync_token);
+
+ return PromiseTextureHelper<ResourceMetadata>::MakePromiseSkImage(
+ this, recorder_.get(), metadata.backend_format, metadata.size,
+ metadata.mip_mapped, metadata.origin, metadata.color_type,
+ metadata.alpha_type, metadata.color_space, std::move(metadata));
+}
+
+sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromYUV(
+ std::vector<ResourceMetadata> metadatas,
+ SkYUVColorSpace yuv_color_space) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(recorder_);
+
+ DCHECK(metadatas.size() == 2 || metadatas.size() == 3);
+
+ // TODO(penghuang): Create SkImage from YUV textures directly when it is
+ // supported by Skia.
+ YUVResourceMetadata yuv_metadata(std::move(metadatas), yuv_color_space);
+
+ // Convert internal format from GLES2 to platform GL.
+ const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
+ auto backend_format = GrBackendFormat::MakeGL(
+ gl::GetInternalFormat(version_info, GL_BGRA8_EXT), GL_TEXTURE_2D);
+
+ return PromiseTextureHelper<YUVResourceMetadata>::MakePromiseSkImage(
+ this, recorder_.get(), backend_format, yuv_metadata.size(),
+ GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType,
+ kPremul_SkAlphaType, nullptr /* color_space */, std::move(yuv_metadata));
+}
+
+gpu::SyncToken SkiaOutputSurfaceImpl::SkiaSwapBuffers(
+ OutputSurfaceFrame frame) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(recorder_);
+
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE,
+ impl_on_gpu_->command_buffer_id(),
+ ++sync_fence_release_);
+ sync_token.SetVerifyFlush();
+
+ auto ddl = recorder_->detach();
+ DCHECK(ddl);
+ RecreateRecorder();
+ auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+ // impl_on_gpu_ is released on the GPU thread by a posted task from
+ // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
+ auto callback = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::SwapBuffers,
+ base::Unretained(impl_on_gpu_.get()), std::move(frame), std::move(ddl),
+ std::move(yuv_resource_metadatas_), sync_fence_release_);
+ gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+ sequence_id, std::move(callback), std::move(resource_sync_tokens_)));
+ return sync_token;
+}
+
+SkCanvas* SkiaOutputSurfaceImpl::BeginPaintRenderPass(
+ const RenderPassId& id,
+ const gfx::Size& surface_size,
+ ResourceFormat format,
+ bool mipmap) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(gpu_service_->gr_context());
+ DCHECK(!current_render_pass_id_);
+ DCHECK(!offscreen_surface_recorder_);
+ DCHECK(resource_sync_tokens_.empty());
+
+ current_render_pass_id_ = id;
+
+ auto gr_context_thread_safe = gpu_service_->gr_context()->threadSafeProxy();
+ constexpr uint32_t flags = 0;
+ // LegacyFontHost will get LCD text and skia figures out what type to use.
+ SkSurfaceProps surface_props(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+ int msaa_sample_count = 0;
+ SkColorType color_type =
+ ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format);
+ SkImageInfo image_info =
+ SkImageInfo::Make(surface_size.width(), surface_size.height(), color_type,
+ kPremul_SkAlphaType, nullptr /* color_space */);
+
+ // TODO(penghuang): Figure out how to choose the right size.
+ constexpr size_t kCacheMaxResourceBytes = 90 * 1024 * 1024;
+ const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
+ unsigned int texture_storage_format = TextureStorageFormat(format);
+ auto backend_format = GrBackendFormat::MakeGL(
+ gl::GetInternalFormat(version_info, texture_storage_format),
+ GL_TEXTURE_2D);
+ auto characterization = gr_context_thread_safe->createCharacterization(
+ kCacheMaxResourceBytes, image_info, backend_format, msaa_sample_count,
+ kTopLeft_GrSurfaceOrigin, surface_props, mipmap);
+ DCHECK(characterization.isValid());
+ offscreen_surface_recorder_ =
+ std::make_unique<SkDeferredDisplayListRecorder>(characterization);
+ return offscreen_surface_recorder_->getCanvas();
+}
+
+gpu::SyncToken SkiaOutputSurfaceImpl::FinishPaintRenderPass() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(gpu_service_->gr_context());
+ DCHECK(current_render_pass_id_);
+ DCHECK(offscreen_surface_recorder_);
+
+ gpu::SyncToken sync_token(gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE,
+ impl_on_gpu_->command_buffer_id(),
+ ++sync_fence_release_);
+ sync_token.SetVerifyFlush();
+
+ auto ddl = offscreen_surface_recorder_->detach();
+ offscreen_surface_recorder_ = nullptr;
+ DCHECK(ddl);
+
+ auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+ // impl_on_gpu_ is released on the GPU thread by a posted task from
+ // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
+ auto callback = base::BindOnce(
+ &SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass,
+ base::Unretained(impl_on_gpu_.get()), current_render_pass_id_,
+ std::move(ddl), std::move(yuv_resource_metadatas_), sync_fence_release_);
+ gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+ sequence_id, std::move(callback), std::move(resource_sync_tokens_)));
+ current_render_pass_id_ = 0;
+ return sync_token;
+}
+
+sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromRenderPass(
+ const RenderPassId& id,
+ const gfx::Size& size,
+ ResourceFormat format,
+ bool mipmap) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(recorder_);
+
+ // Convert internal format from GLES2 to platform GL.
+ const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
+ unsigned int texture_storage_format = TextureStorageFormat(format);
+ auto backend_format = GrBackendFormat::MakeGL(
+ gl::GetInternalFormat(version_info, texture_storage_format),
+ GL_TEXTURE_2D);
+ SkColorType color_type =
+ ResourceFormatToClosestSkColorType(true /*gpu_compositing */, format);
+ return PromiseTextureHelper<RenderPassId>::MakePromiseSkImage(
+ this, recorder_.get(), backend_format, size,
+ mipmap ? GrMipMapped::kYes : GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin,
+ color_type, kPremul_SkAlphaType, nullptr /* color_space */, id);
+}
+
+void SkiaOutputSurfaceImpl::RemoveRenderPassResource(
+ std::vector<RenderPassId> ids) {
+ DCHECK(!ids.empty());
+ auto sequence_id = gpu_service_->skia_output_surface_sequence_id();
+ // impl_on_gpu_ is released on the GPU thread by a posted task from
+ // SkiaOutputSurfaceImpl::dtor. So it is safe to use base::Unretained.
+ auto callback =
+ base::BindOnce(&SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource,
+ base::Unretained(impl_on_gpu_.get()), std::move(ids));
+ gpu_service_->scheduler()->ScheduleTask(gpu::Scheduler::Task(
+ sequence_id, std::move(callback), std::vector<gpu::SyncToken>()));
+}
+
+void SkiaOutputSurfaceImpl::InitializeOnGpuThread(base::WaitableEvent* event) {
+ base::ScopedClosureRunner scoped_runner(
+ base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
+ auto did_swap_buffer_complete_callback = base::BindRepeating(
+ &SkiaOutputSurfaceImpl::DidSwapBuffersComplete, weak_ptr_);
+ auto buffer_presented_callback =
+ base::BindRepeating(&SkiaOutputSurfaceImpl::BufferPresented, weak_ptr_);
+ impl_on_gpu_ = std::make_unique<SkiaOutputSurfaceImplOnGpu>(
+ gpu_service_, surface_handle_,
+ CreateSafeCallback(client_thread_task_runner_,
+ did_swap_buffer_complete_callback),
+ CreateSafeCallback(client_thread_task_runner_,
+ buffer_presented_callback));
+ capabilities_ = impl_on_gpu_->capabilities();
+}
+
+void SkiaOutputSurfaceImpl::RecreateRecorder() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(characterization_.isValid());
+ recorder_ =
+ std::make_unique<SkDeferredDisplayListRecorder>(characterization_);
+ // TODO(penghuang): remove the unnecessary getCanvas() call, when the
+ // recorder crash is fixed in skia.
+ recorder_->getCanvas();
+}
+
+void SkiaOutputSurfaceImpl::DidSwapBuffersComplete(
+ gpu::SwapBuffersCompleteParams params) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(client_);
+
+ if (!params.texture_in_use_responses.empty())
+ client_->DidReceiveTextureInUseResponses(params.texture_in_use_responses);
+ if (!params.ca_layer_params.is_empty)
+ client_->DidReceiveCALayerParams(params.ca_layer_params);
+ client_->DidReceiveSwapBuffersAck();
+}
+
+void SkiaOutputSurfaceImpl::BufferPresented(
+ const gfx::PresentationFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(client_);
+ client_->DidReceivePresentationFeedback(feedback);
+ if (synthetic_begin_frame_source_ &&
+ feedback.flags & gfx::PresentationFeedback::kVSync) {
+ // TODO(brianderson): We should not be receiving 0 intervals.
+ synthetic_begin_frame_source_->OnUpdateVSyncParameters(
+ feedback.timestamp, feedback.interval.is_zero()
+ ? BeginFrameArgs::DefaultInterval()
+ : feedback.interval);
+ }
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
new file mode 100644
index 00000000000..3309aa30433
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -0,0 +1,141 @@
+// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
+
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "components/viz/service/display/skia_output_surface.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/ipc/common/surface_handle.h"
+#include "gpu/ipc/in_process_command_buffer.h"
+#include "third_party/skia/include/core/SkDeferredDisplayListRecorder.h"
+#include "third_party/skia/include/core/SkSurfaceCharacterization.h"
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace viz {
+
+class GpuServiceImpl;
+class VizProcessContextProvider;
+class SkiaOutputSurfaceImplOnGpu;
+class SyntheticBeginFrameSource;
+
+class YUVResourceMetadata;
+
+// The SkiaOutputSurface implementation. It is the output surface for
+// SkiaRenderer. It lives on the compositor thread, but it will post tasks
+// to the GPU thread for initializing. Currently, SkiaOutputSurfaceImpl
+// create a SkiaOutputSurfaceImplOnGpu on the GPU thread. It will be used
+// for creating a SkSurface from the default framebuffer and providing the
+// SkSurfaceCharacterization for the SkSurface. And then SkiaOutputSurfaceImpl
+// will create SkDeferredDisplayListRecorder and SkCanvas for SkiaRenderer to
+// render into. In SwapBuffers, it detaches a SkDeferredDisplayList from the
+// recorder and plays it back on the framebuffer SkSurface on the GPU thread
+// through SkiaOutputSurfaceImpleOnGpu.
+class SkiaOutputSurfaceImpl : public SkiaOutputSurface {
+ public:
+ SkiaOutputSurfaceImpl(
+ GpuServiceImpl* gpu_service,
+ gpu::SurfaceHandle surface_handle,
+ scoped_refptr<VizProcessContextProvider> context_provider,
+ SyntheticBeginFrameSource* synthetic_begin_frame_source);
+ ~SkiaOutputSurfaceImpl() override;
+
+ // OutputSurface implementation:
+ void BindToClient(OutputSurfaceClient* client) override;
+ void EnsureBackbuffer() override;
+ void DiscardBackbuffer() override;
+ void BindFramebuffer() override;
+ void SetDrawRectangle(const gfx::Rect& draw_rectangle) override;
+ void Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha,
+ bool use_stencil) override;
+ void SwapBuffers(OutputSurfaceFrame frame) override;
+ uint32_t GetFramebufferCopyTextureFormat() override;
+ OverlayCandidateValidator* GetOverlayCandidateValidator() const override;
+ bool IsDisplayedAsOverlayPlane() const override;
+ unsigned GetOverlayTextureId() const override;
+ gfx::BufferFormat GetOverlayBufferFormat() const override;
+ bool HasExternalStencilTest() const override;
+ void ApplyExternalStencil() override;
+#if BUILDFLAG(ENABLE_VULKAN)
+ gpu::VulkanSurface* GetVulkanSurface() override;
+#endif
+ unsigned UpdateGpuFence() override;
+
+ // SkiaOutputSurface implementation:
+ SkCanvas* GetSkCanvasForCurrentFrame() override;
+ sk_sp<SkImage> MakePromiseSkImage(ResourceMetadata metadata) override;
+ sk_sp<SkImage> MakePromiseSkImageFromYUV(
+ std::vector<ResourceMetadata> metadatas,
+ SkYUVColorSpace yuv_color_space) override;
+ gpu::SyncToken SkiaSwapBuffers(OutputSurfaceFrame frame) override;
+ SkCanvas* BeginPaintRenderPass(const RenderPassId& id,
+ const gfx::Size& surface_size,
+ ResourceFormat format,
+ bool mipmap) override;
+ gpu::SyncToken FinishPaintRenderPass() override;
+ sk_sp<SkImage> MakePromiseSkImageFromRenderPass(const RenderPassId& id,
+ const gfx::Size& size,
+ ResourceFormat format,
+ bool mipmap) override;
+ void RemoveRenderPassResource(std::vector<RenderPassId> ids) override;
+
+ private:
+ template <class T>
+ class PromiseTextureHelper;
+ void InitializeOnGpuThread(base::WaitableEvent* event);
+ void RecreateRecorder();
+ void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params);
+ void BufferPresented(const gfx::PresentationFeedback& feedback);
+
+ uint64_t sync_fence_release_ = 0;
+ GpuServiceImpl* const gpu_service_;
+ const gpu::SurfaceHandle surface_handle_;
+ SyntheticBeginFrameSource* const synthetic_begin_frame_source_;
+ OutputSurfaceClient* client_ = nullptr;
+
+ SkSurfaceCharacterization characterization_;
+ std::unique_ptr<SkDeferredDisplayListRecorder> recorder_;
+
+ // The current render pass id set by BeginPaintRenderPass.
+ RenderPassId current_render_pass_id_ = 0;
+
+ // The SkDDL recorder created by BeginPaintRenderPass, and
+ // FinishPaintRenderPass will turn it into a SkDDL and play the SkDDL back on
+ // the GPU thread.
+ std::unique_ptr<SkDeferredDisplayListRecorder> offscreen_surface_recorder_;
+
+ // Sync tokens for resources which are used for the current frame.
+ std::vector<gpu::SyncToken> resource_sync_tokens_;
+
+ // YUV resource metadatas for the current frame or the current render pass.
+ // They should be preprocessed for playing recorded frame into a surface.
+ // TODO(penghuang): Remove it when Skia supports drawing YUV textures
+ // directly.
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas_;
+
+ // The task runner for running task on the client (compositor) thread.
+ scoped_refptr<base::SingleThreadTaskRunner> client_thread_task_runner_;
+
+ // |impl_on_gpu| is created and destroyed on the GPU thread.
+ std::unique_ptr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_;
+
+ THREAD_CHECKER(thread_checker_);
+
+ base::WeakPtr<SkiaOutputSurfaceImpl> weak_ptr_;
+ base::WeakPtrFactory<SkiaOutputSurfaceImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurfaceImpl);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_H_
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
new file mode 100644
index 00000000000..eccdf7f1a9b
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -0,0 +1,398 @@
+// 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 "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"
+
+#include "base/atomic_sequence_num.h"
+#include "base/callback_helpers.h"
+#include "base/synchronization/waitable_event.h"
+#include "components/viz/service/display/output_surface_frame.h"
+#include "components/viz/service/gl/gpu_service_impl.h"
+#include "gpu/command_buffer/common/swap_buffers_complete_params.h"
+#include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/scheduler.h"
+#include "gpu/command_buffer/service/sync_point_manager.h"
+#include "gpu/command_buffer/service/texture_base.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/ipc/service/image_transport_surface.h"
+#include "third_party/skia/include/private/SkDeferredDisplayList.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_version_info.h"
+
+namespace viz {
+namespace {
+
+base::AtomicSequenceNumber g_next_command_buffer_id;
+
+} // namespace
+
+YUVResourceMetadata::YUVResourceMetadata(
+ std::vector<ResourceMetadata> metadatas,
+ SkYUVColorSpace yuv_color_space)
+ : metadatas_(std::move(metadatas)), yuv_color_space_(yuv_color_space) {
+ DCHECK(metadatas_.size() == 2 || metadatas_.size() == 3);
+}
+
+YUVResourceMetadata::YUVResourceMetadata(YUVResourceMetadata&& other) = default;
+
+YUVResourceMetadata::~YUVResourceMetadata() = default;
+
+YUVResourceMetadata& YUVResourceMetadata::operator=(
+ YUVResourceMetadata&& other) = default;
+
+SkiaOutputSurfaceImplOnGpu::SkiaOutputSurfaceImplOnGpu(
+ GpuServiceImpl* gpu_service,
+ gpu::SurfaceHandle surface_handle,
+ const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
+ const BufferPresentedCallback& buffer_presented_callback)
+ : command_buffer_id_(gpu::CommandBufferId::FromUnsafeValue(
+ g_next_command_buffer_id.GetNext() + 1)),
+ gpu_service_(gpu_service),
+ surface_handle_(surface_handle),
+ did_swap_buffer_complete_callback_(did_swap_buffer_complete_callback),
+ buffer_presented_callback_(buffer_presented_callback),
+ weak_ptr_factory_(this) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+
+ sync_point_client_state_ =
+ gpu_service_->sync_point_manager()->CreateSyncPointClientState(
+ gpu::CommandBufferNamespace::VIZ_OUTPUT_SURFACE, command_buffer_id_,
+ gpu_service_->skia_output_surface_sequence_id());
+
+ surface_ = gpu::ImageTransportSurface::CreateNativeSurface(
+ weak_ptr_factory_.GetWeakPtr(), surface_handle_, gl::GLSurfaceFormat());
+ DCHECK(surface_);
+
+ if (!gpu_service_->CreateGrContextIfNecessary(surface_.get())) {
+ LOG(FATAL) << "Failed to create GrContext";
+ // TODO(penghuang): handle the failure.
+ }
+
+ DCHECK(gpu_service_->context_for_skia());
+ DCHECK(gpu_service_->gr_context());
+
+ if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
+ LOG(FATAL) << "Failed to make current.";
+ // TODO(penghuang): Handle the failure.
+ }
+
+ capabilities_.flipped_output_surface = surface_->FlipsVertically();
+
+ // Get stencil bits from the default frame buffer.
+ auto* current_gl = gpu_service_->context_for_skia()->GetCurrentGL();
+ const auto* version = current_gl->Version;
+ auto* api = current_gl->Api;
+ GLint stencil_bits = 0;
+ if (version->is_desktop_core_profile) {
+ api->glGetFramebufferAttachmentParameterivEXTFn(
+ GL_FRAMEBUFFER, GL_STENCIL, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE,
+ &stencil_bits);
+ } else {
+ api->glGetIntegervFn(GL_STENCIL_BITS, &stencil_bits);
+ }
+
+ capabilities_.supports_stencil = stencil_bits > 0;
+}
+
+SkiaOutputSurfaceImplOnGpu::~SkiaOutputSurfaceImplOnGpu() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
+
+void SkiaOutputSurfaceImplOnGpu::Reshape(
+ const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha,
+ bool use_stencil,
+ SkSurfaceCharacterization* characterization,
+ base::WaitableEvent* event) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ std::unique_ptr<base::ScopedClosureRunner> scoped_runner;
+ if (event) {
+ scoped_runner = std::make_unique<base::ScopedClosureRunner>(
+ base::BindOnce(&base::WaitableEvent::Signal, base::Unretained(event)));
+ }
+
+ if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
+ LOG(FATAL) << "Failed to make current.";
+ // TODO(penghuang): Handle the failure.
+ }
+ gl::GLSurface::ColorSpace surface_color_space =
+ color_space == gfx::ColorSpace::CreateSCRGBLinear()
+ ? gl::GLSurface::ColorSpace::SCRGB_LINEAR
+ : gl::GLSurface::ColorSpace::UNSPECIFIED;
+ if (!surface_->Resize(size, device_scale_factor, surface_color_space,
+ has_alpha)) {
+ LOG(FATAL) << "Failed to resize.";
+ // TODO(penghuang): Handle the failure.
+ }
+ DCHECK(gpu_service_->context_for_skia()->IsCurrent(surface_.get()));
+ DCHECK(gpu_service_->gr_context());
+
+ SkSurfaceProps surface_props =
+ SkSurfaceProps(0, SkSurfaceProps::kLegacyFontHost_InitType);
+
+ GrGLFramebufferInfo framebuffer_info;
+ framebuffer_info.fFBOID = 0;
+ const auto* version_info = gpu_service_->context_for_skia()->GetVersionInfo();
+ framebuffer_info.fFormat = version_info->is_es ? GL_BGRA8_EXT : GL_RGBA8;
+
+ GrBackendRenderTarget render_target(size.width(), size.height(), 0, 8,
+ framebuffer_info);
+
+ sk_surface_ = SkSurface::MakeFromBackendRenderTarget(
+ gpu_service_->gr_context(), render_target, kBottomLeft_GrSurfaceOrigin,
+ kBGRA_8888_SkColorType, nullptr, &surface_props);
+ DCHECK(sk_surface_);
+
+ if (characterization) {
+ sk_surface_->characterize(characterization);
+ DCHECK(characterization->isValid());
+ }
+}
+
+void SkiaOutputSurfaceImplOnGpu::SwapBuffers(
+ OutputSurfaceFrame frame,
+ std::unique_ptr<SkDeferredDisplayList> ddl,
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas,
+ uint64_t sync_fence_release) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(ddl);
+ DCHECK(sk_surface_);
+
+ if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
+ LOG(FATAL) << "Failed to make current.";
+ // TODO(penghuang): Handle the failure.
+ }
+
+ PreprocessYUVResources(std::move(yuv_resource_metadatas));
+
+ sk_surface_->draw(ddl.get());
+ gpu_service_->gr_context()->flush();
+ OnSwapBuffers();
+ surface_->SwapBuffers(
+ base::BindRepeating([](const gfx::PresentationFeedback&) {}));
+ sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
+}
+
+void SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass(
+ RenderPassId id,
+ std::unique_ptr<SkDeferredDisplayList> ddl,
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas,
+ uint64_t sync_fence_release) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(ddl);
+
+ if (!gpu_service_->context_for_skia()->MakeCurrent(surface_.get())) {
+ LOG(FATAL) << "Failed to make current.";
+ // TODO(penghuang): Handle resize failure.
+ }
+
+ PreprocessYUVResources(std::move(yuv_resource_metadatas));
+
+ auto& surface = offscreen_surfaces_[id];
+ SkSurfaceCharacterization characterization;
+ // TODO(penghuang): Using characterization != ddl->characterization(), when
+ // the SkSurfaceCharacterization::operator!= is implemented in Skia.
+ if (!surface || !surface->characterize(&characterization) ||
+ characterization != ddl->characterization()) {
+ surface = SkSurface::MakeRenderTarget(
+ gpu_service_->gr_context(), ddl->characterization(), SkBudgeted::kNo);
+ DCHECK(surface);
+ }
+ surface->draw(ddl.get());
+ surface->flush();
+ sync_point_client_state_->ReleaseFenceSync(sync_fence_release);
+}
+
+void SkiaOutputSurfaceImplOnGpu::RemoveRenderPassResource(
+ std::vector<RenderPassId> ids) {
+ DCHECK(!ids.empty());
+ for (const auto& id : ids) {
+ auto it = offscreen_surfaces_.find(id);
+ DCHECK(it != offscreen_surfaces_.end());
+ offscreen_surfaces_.erase(it);
+ }
+}
+
+void SkiaOutputSurfaceImplOnGpu::FullfillPromiseTexture(
+ const ResourceMetadata& metadata,
+ GrBackendTexture* backend_texture) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto* mailbox_manager = gpu_service_->mailbox_manager();
+ auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox);
+ if (!texture_base) {
+ DLOG(ERROR) << "Failed to full fill the promise texture.";
+ return;
+ }
+ BindOrCopyTextureIfNecessary(texture_base);
+ GrGLTextureInfo texture_info;
+ texture_info.fTarget = texture_base->target();
+ texture_info.fID = texture_base->service_id();
+ texture_info.fFormat = *metadata.backend_format.getGLFormat();
+ *backend_texture =
+ GrBackendTexture(metadata.size.width(), metadata.size.height(),
+ metadata.mip_mapped, texture_info);
+}
+
+void SkiaOutputSurfaceImplOnGpu::FullfillPromiseTexture(
+ const YUVResourceMetadata& yuv_metadata,
+ GrBackendTexture* backend_texture) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ if (yuv_metadata.image())
+ *backend_texture = yuv_metadata.image()->getBackendTexture(true);
+ DLOG_IF(ERROR, !backend_texture->isValid())
+ << "Failed to full fill the promise texture from yuv resources.";
+}
+
+void SkiaOutputSurfaceImplOnGpu::FullfillPromiseTexture(
+ const RenderPassId id,
+ GrBackendTexture* backend_texture) {
+ auto it = offscreen_surfaces_.find(id);
+ DCHECK(it != offscreen_surfaces_.end());
+ sk_sp<SkSurface>& surface = it->second;
+ *backend_texture =
+ surface->getBackendTexture(SkSurface::kFlushRead_BackendHandleAccess);
+ DLOG_IF(ERROR, !backend_texture->isValid())
+ << "Failed to full fill the promise texture created from RenderPassId:"
+ << id;
+}
+
+#if defined(OS_WIN)
+void SkiaOutputSurfaceImplOnGpu::DidCreateAcceleratedSurfaceChildWindow(
+ gpu::SurfaceHandle parent_window,
+ gpu::SurfaceHandle child_window) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+}
+#endif
+
+void SkiaOutputSurfaceImplOnGpu::DidSwapBuffersComplete(
+ gpu::SwapBuffersCompleteParams params) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ params.swap_response.swap_id = pending_swap_completed_ids_.front();
+ pending_swap_completed_ids_.pop_front();
+ did_swap_buffer_complete_callback_.Run(params);
+}
+
+const gpu::gles2::FeatureInfo* SkiaOutputSurfaceImplOnGpu::GetFeatureInfo()
+ const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+ return nullptr;
+}
+
+const gpu::GpuPreferences& SkiaOutputSurfaceImplOnGpu::GetGpuPreferences()
+ const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+ return gpu_preferences_;
+}
+
+void SkiaOutputSurfaceImplOnGpu::SetSnapshotRequestedCallback(
+ const base::Closure& callback) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+}
+
+void SkiaOutputSurfaceImplOnGpu::BufferPresented(
+ const gfx::PresentationFeedback& feedback) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ buffer_presented_callback_.Run(feedback);
+}
+
+void SkiaOutputSurfaceImplOnGpu::AddFilter(IPC::MessageFilter* message_filter) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+}
+
+int32_t SkiaOutputSurfaceImplOnGpu::GetRouteID() const {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ NOTIMPLEMENTED();
+ return 0;
+}
+
+void SkiaOutputSurfaceImplOnGpu::BindOrCopyTextureIfNecessary(
+ gpu::TextureBase* texture_base) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ if (gpu_service_->gpu_preferences().use_passthrough_cmd_decoder)
+ return;
+ // If a texture created with non-passthrough command buffer and bind with
+ // an image, the Chrome will defer copying the image to the texture until
+ // the texture is used. It is for implementing low latency drawing and
+ // avoiding unnecessary texture copy. So we need check the texture image
+ // state, and bind or copy the image to the texture if necessary.
+ auto* texture = static_cast<gpu::gles2::Texture*>(texture_base);
+ gpu::gles2::Texture::ImageState image_state;
+ auto* image = texture->GetLevelImage(GL_TEXTURE_2D, 0, &image_state);
+ if (image && image_state == gpu::gles2::Texture::UNBOUND) {
+ glBindTexture(texture_base->target(), texture_base->service_id());
+ if (image->BindTexImage(texture_base->target())) {
+ } else {
+ texture->SetLevelImageState(texture_base->target(), 0,
+ gpu::gles2::Texture::COPIED);
+ if (!image->CopyTexImage(texture_base->target()))
+ LOG(ERROR) << "Failed to copy a gl image to texture.";
+ }
+ }
+}
+
+void SkiaOutputSurfaceImplOnGpu::PreprocessYUVResources(
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas) {
+ // Create SkImage for fullfilling YUV promise image, before drawing the ddl.
+ // TODO(penghuang): Remove the extra step when Skia supports drawing YUV
+ // textures directly.
+ auto* mailbox_manager = gpu_service_->mailbox_manager();
+ for (auto* yuv_metadata : yuv_resource_metadatas) {
+ const auto& metadatas = yuv_metadata->metadatas();
+ DCHECK(metadatas.size() == 2 || metadatas.size() == 3);
+ GrBackendTexture backend_textures[3];
+ size_t i = 0;
+ for (const auto& metadata : metadatas) {
+ auto* texture_base = mailbox_manager->ConsumeTexture(metadata.mailbox);
+ if (!texture_base)
+ break;
+ BindOrCopyTextureIfNecessary(texture_base);
+ GrGLTextureInfo texture_info;
+ texture_info.fTarget = texture_base->target();
+ texture_info.fID = texture_base->service_id();
+ texture_info.fFormat = *metadata.backend_format.getGLFormat();
+ backend_textures[i++] =
+ GrBackendTexture(metadata.size.width(), metadata.size.height(),
+ GrMipMapped::kNo, texture_info);
+ }
+
+ if (i != metadatas.size())
+ continue;
+
+ sk_sp<SkImage> image;
+ if (metadatas.size() == 2) {
+ image = SkImage::MakeFromNV12TexturesCopy(
+ gpu_service_->gr_context(), yuv_metadata->yuv_color_space(),
+ backend_textures, kTopLeft_GrSurfaceOrigin,
+ nullptr /* image_color_space */);
+ DCHECK(image);
+ } else {
+ image = SkImage::MakeFromYUVTexturesCopy(
+ gpu_service_->gr_context(), yuv_metadata->yuv_color_space(),
+ backend_textures, kTopLeft_GrSurfaceOrigin,
+ nullptr /* image_color_space */);
+ DCHECK(image);
+ }
+ yuv_metadata->set_image(std::move(image));
+ }
+}
+
+void SkiaOutputSurfaceImplOnGpu::OnSwapBuffers() {
+ uint64_t swap_id = swap_id_++;
+ pending_swap_completed_ids_.push_back(swap_id);
+}
+
+} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
new file mode 100644
index 00000000000..82462b0bf9b
--- /dev/null
+++ b/chromium/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -0,0 +1,173 @@
+// 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 COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_
+
+#include "base/containers/circular_deque.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+#include "build/build_config.h"
+#include "components/viz/common/quads/render_pass.h"
+#include "components/viz/common/resources/resource_metadata.h"
+#include "components/viz/service/display/output_surface.h"
+#include "components/viz/service/display/output_surface_frame.h"
+#include "gpu/command_buffer/common/sync_token.h"
+#include "gpu/ipc/common/surface_handle.h"
+#include "gpu/ipc/in_process_command_buffer.h"
+#include "gpu/ipc/service/image_transport_surface_delegate.h"
+#include "third_party/skia/include/core/SkSurface.h"
+
+class SkDeferredDisplayList;
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace gl {
+class GLSurface;
+}
+
+namespace gpu {
+class SyncPointClientState;
+}
+
+namespace viz {
+
+class GpuServiceImpl;
+
+// Metadata for YUV promise SkImage.
+class YUVResourceMetadata {
+ public:
+ YUVResourceMetadata(std::vector<ResourceMetadata> metadatas,
+ SkYUVColorSpace yuv_color_space);
+ YUVResourceMetadata(YUVResourceMetadata&& other);
+ ~YUVResourceMetadata();
+ YUVResourceMetadata& operator=(YUVResourceMetadata&& other);
+
+ const std::vector<ResourceMetadata>& metadatas() const { return metadatas_; }
+ SkYUVColorSpace yuv_color_space() const { return yuv_color_space_; }
+ const sk_sp<SkImage> image() const { return image_; }
+ void set_image(sk_sp<SkImage> image) { image_ = image; }
+ const gfx::Size size() const { return metadatas_[0].size; }
+
+ private:
+ // Metadatas for YUV planes.
+ std::vector<ResourceMetadata> metadatas_;
+
+ SkYUVColorSpace yuv_color_space_;
+
+ // The image copied from YUV textures, it is for fullfilling the promise
+ // image.
+ // TODO(penghuang): Remove it when Skia supports drawing YUV textures
+ // directly.
+ sk_sp<SkImage> image_;
+
+ DISALLOW_COPY_AND_ASSIGN(YUVResourceMetadata);
+};
+
+// The SkiaOutputSurface implementation running on the GPU thread. This class
+// should be created, used and destroyed on the GPU thread.
+class SkiaOutputSurfaceImplOnGpu : public gpu::ImageTransportSurfaceDelegate {
+ public:
+ using DidSwapBufferCompleteCallback =
+ base::RepeatingCallback<void(gpu::SwapBuffersCompleteParams)>;
+ using BufferPresentedCallback =
+ base::RepeatingCallback<void(const gfx::PresentationFeedback& feedback)>;
+ SkiaOutputSurfaceImplOnGpu(
+ GpuServiceImpl* gpu_service,
+ gpu::SurfaceHandle surface_handle,
+ const DidSwapBufferCompleteCallback& did_swap_buffer_complete_callback,
+ const BufferPresentedCallback& buffer_presented_callback);
+ ~SkiaOutputSurfaceImplOnGpu() override;
+
+ gpu::CommandBufferId command_buffer_id() const { return command_buffer_id_; }
+ const OutputSurface::Capabilities capabilities() const {
+ return capabilities_;
+ }
+ const base::WeakPtr<SkiaOutputSurfaceImplOnGpu>& weak_ptr() const {
+ return weak_ptr_;
+ }
+
+ void Reshape(const gfx::Size& size,
+ float device_scale_factor,
+ const gfx::ColorSpace& color_space,
+ bool has_alpha,
+ bool use_stencil,
+ SkSurfaceCharacterization* characterization,
+ base::WaitableEvent* event);
+ void SwapBuffers(OutputSurfaceFrame frame,
+ std::unique_ptr<SkDeferredDisplayList> ddl,
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas,
+ uint64_t sync_fence_release);
+ void FinishPaintRenderPass(
+ RenderPassId id,
+ std::unique_ptr<SkDeferredDisplayList> ddl,
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas,
+ uint64_t sync_fence_release);
+ void RemoveRenderPassResource(std::vector<RenderPassId> ids);
+
+ // Fullfill callback for promise SkImage created from a resource.
+ void FullfillPromiseTexture(const ResourceMetadata& metadata,
+ GrBackendTexture* backend_texture);
+ // Fullfill callback for promise SkImage created from YUV resources.
+ void FullfillPromiseTexture(const YUVResourceMetadata& metadata,
+ GrBackendTexture* backend_texture);
+ // Fullfill callback for promise SkImage created from a render pass.
+ void FullfillPromiseTexture(const RenderPassId id,
+ GrBackendTexture* backend_texture);
+
+ private:
+// gpu::ImageTransportSurfaceDelegate implementation:
+#if defined(OS_WIN)
+ void DidCreateAcceleratedSurfaceChildWindow(
+ gpu::SurfaceHandle parent_window,
+ gpu::SurfaceHandle child_window) override;
+#endif
+ void DidSwapBuffersComplete(gpu::SwapBuffersCompleteParams params) override;
+ const gpu::gles2::FeatureInfo* GetFeatureInfo() const override;
+ const gpu::GpuPreferences& GetGpuPreferences() const override;
+ void SetSnapshotRequestedCallback(const base::Closure& callback) override;
+ void BufferPresented(const gfx::PresentationFeedback& feedback) override;
+ void AddFilter(IPC::MessageFilter* message_filter) override;
+ int32_t GetRouteID() const override;
+
+ void BindOrCopyTextureIfNecessary(gpu::TextureBase* texture_base);
+ void PreprocessYUVResources(
+ std::vector<YUVResourceMetadata*> yuv_resource_metadatas);
+
+ // Generage the next swap ID and push it to our pending swap ID queues.
+ void OnSwapBuffers();
+
+ const gpu::CommandBufferId command_buffer_id_;
+ GpuServiceImpl* const gpu_service_;
+ const gpu::SurfaceHandle surface_handle_;
+ DidSwapBufferCompleteCallback did_swap_buffer_complete_callback_;
+ BufferPresentedCallback buffer_presented_callback_;
+ scoped_refptr<gpu::SyncPointClientState> sync_point_client_state_;
+ gpu::GpuPreferences gpu_preferences_;
+ scoped_refptr<gl::GLSurface> surface_;
+ sk_sp<SkSurface> sk_surface_;
+ OutputSurface::Capabilities capabilities_;
+
+ // Offscreen surfaces for render passes. It can only be accessed on GPU
+ // thread.
+ base::flat_map<RenderPassId, sk_sp<SkSurface>> offscreen_surfaces_;
+
+ // ID is pushed each time we begin a swap, and popped each time we present or
+ // complete a swap.
+ base::circular_deque<uint64_t> pending_swap_completed_ids_;
+ uint64_t swap_id_ = 0;
+
+ THREAD_CHECKER(thread_checker_);
+
+ base::WeakPtr<SkiaOutputSurfaceImplOnGpu> weak_ptr_;
+ base::WeakPtrFactory<SkiaOutputSurfaceImplOnGpu> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SkiaOutputSurfaceImplOnGpu);
+};
+
+} // namespace viz
+
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SKIA_OUTPUT_SURFACE_IMPL_ON_GPU_H_
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_mac.cc b/chromium/components/viz/service/display_embedder/software_output_device_mac.cc
index b256bf2d60f..b9357082293 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_mac.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_device_mac.cc
@@ -7,7 +7,7 @@
#include "base/mac/foundation_util.h"
#include "base/trace_event/trace_event.h"
#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/accelerated_widget_mac/ca_layer_frame_sink.h"
+#include "ui/gfx/ca_layer_params.h"
#include "ui/gfx/mac/io_surface.h"
#include "ui/gfx/skia_util.h"
@@ -16,8 +16,9 @@ namespace viz {
SoftwareOutputDeviceMac::Buffer::Buffer() = default;
SoftwareOutputDeviceMac::Buffer::~Buffer() = default;
-SoftwareOutputDeviceMac::SoftwareOutputDeviceMac(gfx::AcceleratedWidget widget)
- : widget_(widget) {}
+SoftwareOutputDeviceMac::SoftwareOutputDeviceMac(
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : SoftwareOutputDevice(std::move(task_runner)) {}
SoftwareOutputDeviceMac::~SoftwareOutputDeviceMac() {}
@@ -178,24 +179,14 @@ void SoftwareOutputDeviceMac::EndPaint() {
}
current_paint_canvas_.reset();
- if (widget_ != gfx::kNullAcceleratedWidget) {
+ if (client_) {
gfx::CALayerParams ca_layer_params;
ca_layer_params.is_empty = false;
ca_layer_params.scale_factor = scale_factor_;
ca_layer_params.pixel_size = pixel_size_;
ca_layer_params.io_surface_mach_port.reset(
IOSurfaceCreateMachPort(current_paint_buffer_->io_surface));
- ui::CALayerFrameSink* ca_layer_frame_sink =
- ui::CALayerFrameSink::FromAcceleratedWidget(widget_);
- if (ca_layer_frame_sink) {
- ca_layer_frame_sink->SetSuspended(false);
- ca_layer_frame_sink->UpdateCALayerTree(ca_layer_params);
- base::TimeTicks vsync_timebase;
- base::TimeDelta vsync_interval;
- ca_layer_frame_sink->GetVSyncParameters(&vsync_timebase, &vsync_interval);
- if (!update_vsync_callback_.is_null())
- update_vsync_callback_.Run(vsync_timebase, vsync_interval);
- }
+ client_->SoftwareDeviceUpdatedCALayerParams(ca_layer_params);
}
current_paint_buffer_ = nullptr;
@@ -208,26 +199,7 @@ void SoftwareOutputDeviceMac::DiscardBackbuffer() {
void SoftwareOutputDeviceMac::EnsureBackbuffer() {}
gfx::VSyncProvider* SoftwareOutputDeviceMac::GetVSyncProvider() {
- return this;
-}
-
-void SoftwareOutputDeviceMac::GetVSyncParameters(
- const gfx::VSyncProvider::UpdateVSyncCallback& callback) {
- update_vsync_callback_ = callback;
-}
-
-bool SoftwareOutputDeviceMac::GetVSyncParametersIfAvailable(
- base::TimeTicks* timebase,
- base::TimeDelta* interval) {
- return false;
-}
-
-bool SoftwareOutputDeviceMac::SupportGetVSyncParametersIfAvailable() const {
- return false;
-}
-
-bool SoftwareOutputDeviceMac::IsHWClock() const {
- return false;
+ return nullptr;
}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_mac.h b/chromium/components/viz/service/display_embedder/software_output_device_mac.h
index 4066ac56600..f3867356e3d 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_mac.h
+++ b/chromium/components/viz/service/display_embedder/software_output_device_mac.h
@@ -14,17 +14,15 @@
#include "components/viz/service/viz_service_export.h"
#include "third_party/skia/include/core/SkRefCnt.h"
#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/vsync_provider.h"
class SkCanvas;
namespace viz {
-class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice,
- public gfx::VSyncProvider {
+class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice {
public:
- explicit SoftwareOutputDeviceMac(gfx::AcceleratedWidget widget);
+ explicit SoftwareOutputDeviceMac(
+ scoped_refptr<base::SequencedTaskRunner> task_runner);
~SoftwareOutputDeviceMac() override;
// SoftwareOutputDevice implementation.
@@ -35,14 +33,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice,
void EnsureBackbuffer() override;
gfx::VSyncProvider* GetVSyncProvider() override;
- // gfx::VSyncProvider implementation.
- void GetVSyncParameters(
- const gfx::VSyncProvider::UpdateVSyncCallback& callback) override;
- bool GetVSyncParametersIfAvailable(base::TimeTicks* timebase,
- base::TimeDelta* interval) override;
- bool SupportGetVSyncParametersIfAvailable() const override;
- bool IsHWClock() const override;
-
// Testing methods.
SkRegion LastCopyRegionForTesting() const {
return last_copy_region_for_testing_;
@@ -66,7 +56,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice,
void UpdateAndCopyBufferDamage(Buffer* previous_paint_buffer,
const SkRegion& new_damage_rect);
- gfx::AcceleratedWidget widget_ = gfx::kNullAcceleratedWidget;
gfx::Size pixel_size_;
float scale_factor_ = 1;
@@ -83,8 +72,6 @@ class VIZ_SERVICE_EXPORT SoftwareOutputDeviceMac : public SoftwareOutputDevice,
// valid only between BeginPaint and EndPaint.
std::unique_ptr<SkCanvas> current_paint_canvas_;
- gfx::VSyncProvider::UpdateVSyncCallback update_vsync_callback_;
-
SkRegion last_copy_region_for_testing_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceMac);
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm b/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm
index ed0b8ad3a49..217bf3a2f7f 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm
+++ b/chromium/components/viz/service/display_embedder/software_output_device_mac_unittest.mm
@@ -4,6 +4,7 @@
#include "components/viz/service/display_embedder/software_output_device_mac.h"
+#include "base/threading/sequenced_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/skia_util.h"
@@ -12,8 +13,8 @@ namespace viz {
namespace {
TEST(SoftwareOutputDeviceMacTest, Basics) {
- std::unique_ptr<SoftwareOutputDeviceMac> device(
- new SoftwareOutputDeviceMac(gfx::kNullAcceleratedWidget));
+ auto device = std::make_unique<SoftwareOutputDeviceMac>(
+ base::SequencedTaskRunnerHandle::Get());
gfx::Size pixel_size(512, 512);
float scale_factor = 1;
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc b/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc
index ee5986fdfb6..46cd8125266 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_device_ozone_unittest.cc
@@ -46,7 +46,8 @@ class TestPlatformWindowDelegate : public ui::PlatformWindowDelegate {
float device_pixel_ratio) override {
widget_ = widget;
}
- void OnAcceleratedWidgetDestroyed() override { NOTREACHED(); }
+ void OnAcceleratedWidgetDestroying() override {}
+ void OnAcceleratedWidgetDestroyed() override {}
void OnActivationChanged(bool active) override {}
private:
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_win.cc b/chromium/components/viz/service/display_embedder/software_output_device_win.cc
index 61213e77e24..ba84cac14b3 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_win.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_device_win.cc
@@ -4,109 +4,59 @@
#include "components/viz/service/display_embedder/software_output_device_win.h"
-#include "base/debug/alias.h"
#include "base/memory/shared_memory.h"
+#include "base/threading/thread_checker.h"
+#include "components/viz/common/display/use_layered_window.h"
#include "components/viz/common/resources/resource_sizes.h"
+#include "components/viz/service/display_embedder/output_device_backing.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "services/viz/privileged/interfaces/compositing/layered_window_updater.mojom.h"
#include "skia/ext/platform_canvas.h"
#include "skia/ext/skia_utils_win.h"
-#include "ui/base/win/internal_constants.h"
+#include "third_party/skia/include/core/SkCanvas.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/skia_util.h"
namespace viz {
+namespace {
-// If a window is larger than this in bytes, don't even try to create a
-// backing bitmap for it.
-static const size_t kMaxBitmapSizeBytes = 4 * (16384 * 8192);
+// Shared base class for Windows SoftwareOutputDevice implementations.
+class SoftwareOutputDeviceWinBase : public SoftwareOutputDevice {
+ public:
+ explicit SoftwareOutputDeviceWinBase(HWND hwnd) : hwnd_(hwnd) {}
+ ~SoftwareOutputDeviceWinBase() override {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DCHECK(!in_paint_);
+ }
-OutputDeviceBacking::OutputDeviceBacking() : created_byte_size_(0) {}
+ HWND hwnd() const { return hwnd_; }
-OutputDeviceBacking::~OutputDeviceBacking() {
- DCHECK(devices_.empty());
-}
+ // SoftwareOutputDevice implementation.
+ void Resize(const gfx::Size& viewport_pixel_size,
+ float scale_factor) override;
+ SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
+ void EndPaint() override;
-void OutputDeviceBacking::Resized() {
- size_t new_size = GetMaxByteSize();
- if (new_size == created_byte_size_)
- return;
- for (SoftwareOutputDeviceWin* device : devices_) {
- device->ReleaseContents();
- }
- backing_.reset();
- created_byte_size_ = 0;
-}
-
-void OutputDeviceBacking::RegisterOutputDevice(
- SoftwareOutputDeviceWin* device) {
- devices_.push_back(device);
-}
-
-void OutputDeviceBacking::UnregisterOutputDevice(
- SoftwareOutputDeviceWin* device) {
- auto it = std::find(devices_.begin(), devices_.end(), device);
- DCHECK(it != devices_.end());
- devices_.erase(it);
- Resized();
-}
-
-base::SharedMemory* OutputDeviceBacking::GetSharedMemory(
- const gfx::Size& size) {
- if (backing_)
- return backing_.get();
- size_t expected_byte_size = GetMaxByteSize();
- size_t required_size;
- if (!ResourceSizes::MaybeSizeInBytes(size, RGBA_8888, &required_size))
- return nullptr;
- if (required_size > expected_byte_size)
- return nullptr;
-
- created_byte_size_ = expected_byte_size;
-
- backing_.reset(new base::SharedMemory);
- base::debug::Alias(&expected_byte_size);
- CHECK(backing_->CreateAnonymous(created_byte_size_));
- return backing_.get();
-}
-
-size_t OutputDeviceBacking::GetMaxByteSize() {
- // Minimum byte size is 1 because creating a 0-byte-long SharedMemory fails.
- size_t max_size = 1;
- for (const SoftwareOutputDeviceWin* device : devices_) {
- size_t current_size;
- if (!ResourceSizes::MaybeSizeInBytes(device->viewport_pixel_size(),
- RGBA_8888, &current_size))
- continue;
- if (current_size > kMaxBitmapSizeBytes)
- continue;
- max_size = std::max(max_size, current_size);
- }
- return max_size;
-}
+ // Called from Resize() if |viewport_pixel_size_| has changed.
+ virtual void ResizeDelegated() = 0;
-SoftwareOutputDeviceWin::SoftwareOutputDeviceWin(OutputDeviceBacking* backing,
- gfx::AcceleratedWidget widget)
- : hwnd_(widget),
- is_hwnd_composited_(false),
- backing_(backing),
- in_paint_(false) {
- is_hwnd_composited_ = !!::GetProp(hwnd_, ui::kWindowTranslucent);
- // Layered windows must be completely updated every time, so they can't
- // share contents with other windows.
- if (is_hwnd_composited_)
- backing_ = nullptr;
- if (backing_)
- backing_->RegisterOutputDevice(this);
-}
+ // Called from BeginPaint() and should return an SkCanvas.
+ virtual SkCanvas* BeginPaintDelegated() = 0;
-SoftwareOutputDeviceWin::~SoftwareOutputDeviceWin() {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- DCHECK(!in_paint_);
- if (backing_)
- backing_->UnregisterOutputDevice(this);
-}
+ // Called from EndPaint() if there is damage.
+ virtual void EndPaintDelegated(const gfx::Rect& damage_rect) = 0;
+
+ private:
+ const HWND hwnd_;
+ bool in_paint_ = false;
+
+ THREAD_CHECKER(thread_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinBase);
+};
-void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
- float scale_factor) {
+void SoftwareOutputDeviceWinBase::Resize(const gfx::Size& viewport_pixel_size,
+ float scale_factor) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!in_paint_);
@@ -114,84 +64,301 @@ void SoftwareOutputDeviceWin::Resize(const gfx::Size& viewport_pixel_size,
return;
viewport_pixel_size_ = viewport_pixel_size;
- if (backing_)
- backing_->Resized();
- contents_.reset();
+ ResizeDelegated();
}
-SkCanvas* SoftwareOutputDeviceWin::BeginPaint(const gfx::Rect& damage_rect) {
+SkCanvas* SoftwareOutputDeviceWinBase::BeginPaint(
+ const gfx::Rect& damage_rect) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!in_paint_);
- if (!contents_) {
- HANDLE shared_section = NULL;
- bool can_create_contents = true;
- if (backing_) {
- base::SharedMemory* memory =
- backing_->GetSharedMemory(viewport_pixel_size_);
- if (memory) {
- shared_section = memory->handle().GetHandle();
- } else {
- can_create_contents = false;
- }
- }
- if (can_create_contents) {
- contents_ = skia::CreatePlatformCanvasWithSharedSection(
- viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
- shared_section, skia::CRASH_ON_FAILURE);
- }
- }
damage_rect_ = damage_rect;
in_paint_ = true;
- return contents_.get();
+ return BeginPaintDelegated();
}
-void SoftwareOutputDeviceWin::EndPaint() {
+void SoftwareOutputDeviceWinBase::EndPaint() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(in_paint_);
in_paint_ = false;
- SoftwareOutputDevice::EndPaint();
- if (!contents_)
+ gfx::Rect intersected_damage_rect = damage_rect_;
+ intersected_damage_rect.Intersect(gfx::Rect(viewport_pixel_size_));
+ if (intersected_damage_rect.IsEmpty())
return;
- gfx::Rect rect = damage_rect_;
- rect.Intersect(gfx::Rect(viewport_pixel_size_));
- if (rect.IsEmpty())
+ EndPaintDelegated(intersected_damage_rect);
+}
+
+// SoftwareOutputDevice implementation that draws directly to the provided HWND.
+class SoftwareOutputDeviceWinDirect : public SoftwareOutputDeviceWinBase,
+ public OutputDeviceBacking::Client {
+ public:
+ SoftwareOutputDeviceWinDirect(HWND hwnd, OutputDeviceBacking* backing);
+ ~SoftwareOutputDeviceWinDirect() override;
+
+ // SoftwareOutputDeviceWinBase implementation.
+ void ResizeDelegated() override;
+ SkCanvas* BeginPaintDelegated() override;
+ void EndPaintDelegated(const gfx::Rect& damage_rect) override;
+
+ // OutputDeviceBacking::Client implementation.
+ const gfx::Size& GetViewportPixelSize() const override {
+ return viewport_pixel_size_;
+ }
+ void ReleaseCanvas() override { canvas_.reset(); }
+
+ private:
+ OutputDeviceBacking* const backing_;
+ std::unique_ptr<SkCanvas> canvas_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinDirect);
+};
+
+SoftwareOutputDeviceWinDirect::SoftwareOutputDeviceWinDirect(
+ HWND hwnd,
+ OutputDeviceBacking* backing)
+ : SoftwareOutputDeviceWinBase(hwnd), backing_(backing) {
+ backing_->RegisterClient(this);
+}
+
+SoftwareOutputDeviceWinDirect::~SoftwareOutputDeviceWinDirect() {
+ backing_->UnregisterClient(this);
+}
+
+void SoftwareOutputDeviceWinDirect::ResizeDelegated() {
+ canvas_.reset();
+ backing_->ClientResized();
+}
+
+SkCanvas* SoftwareOutputDeviceWinDirect::BeginPaintDelegated() {
+ if (!canvas_) {
+ // Share pixel backing with other SoftwareOutputDeviceWinDirect instances.
+ // All work happens on the same thread so this is safe.
+ base::SharedMemory* memory =
+ backing_->GetSharedMemory(viewport_pixel_size_);
+ if (memory) {
+ canvas_ = skia::CreatePlatformCanvasWithSharedSection(
+ viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
+ memory->handle().GetHandle(), skia::CRASH_ON_FAILURE);
+ }
+ }
+ return canvas_.get();
+}
+
+void SoftwareOutputDeviceWinDirect::EndPaintDelegated(
+ const gfx::Rect& damage_rect) {
+ if (!canvas_)
return;
- HDC dib_dc = skia::GetNativeDrawingContext(contents_.get());
-
- if (is_hwnd_composited_) {
- RECT wr;
- GetWindowRect(hwnd_, &wr);
- SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
- POINT position = {wr.left, wr.top};
- POINT zero = {0, 0};
- BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
-
- DWORD style = GetWindowLong(hwnd_, GWL_EXSTYLE);
- DCHECK(!(style & WS_EX_COMPOSITED));
- style |= WS_EX_LAYERED;
- SetWindowLong(hwnd_, GWL_EXSTYLE, style);
-
- ::UpdateLayeredWindow(hwnd_, NULL, &position, &size, dib_dc, &zero,
- RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
- } else {
- HDC hdc = ::GetDC(hwnd_);
- RECT src_rect = rect.ToRECT();
- skia::CopyHDC(dib_dc, hdc, rect.x(), rect.y(),
- contents_.get()->imageInfo().isOpaque(), src_rect,
- contents_.get()->getTotalMatrix());
-
- ::ReleaseDC(hwnd_, hdc);
+ HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get());
+ HDC hdc = ::GetDC(hwnd());
+ RECT src_rect = damage_rect.ToRECT();
+ skia::CopyHDC(dib_dc, hdc, damage_rect.x(), damage_rect.y(),
+ canvas_->imageInfo().isOpaque(), src_rect,
+ canvas_->getTotalMatrix());
+
+ ::ReleaseDC(hwnd(), hdc);
+}
+
+// SoftwareOutputDevice implementation that uses layered window API to draw to
+// the provided HWND.
+class SoftwareOutputDeviceWinLayered : public SoftwareOutputDeviceWinBase {
+ public:
+ explicit SoftwareOutputDeviceWinLayered(HWND hwnd)
+ : SoftwareOutputDeviceWinBase(hwnd) {}
+ ~SoftwareOutputDeviceWinLayered() override = default;
+
+ // SoftwareOutputDeviceWinBase implementation.
+ void ResizeDelegated() override;
+ SkCanvas* BeginPaintDelegated() override;
+ void EndPaintDelegated(const gfx::Rect& damage_rect) override;
+
+ private:
+ std::unique_ptr<SkCanvas> canvas_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinLayered);
+};
+
+void SoftwareOutputDeviceWinLayered::ResizeDelegated() {
+ canvas_.reset();
+}
+
+SkCanvas* SoftwareOutputDeviceWinLayered::BeginPaintDelegated() {
+ if (!canvas_) {
+ // Layered windows can't share a pixel backing.
+ canvas_ = skia::CreatePlatformCanvasWithSharedSection(
+ viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
+ nullptr, skia::CRASH_ON_FAILURE);
}
+ return canvas_.get();
}
-void SoftwareOutputDeviceWin::ReleaseContents() {
- DCHECK(!in_paint_);
- contents_.reset();
+void SoftwareOutputDeviceWinLayered::EndPaintDelegated(
+ const gfx::Rect& damage_rect) {
+ if (!canvas_)
+ return;
+
+ // Set WS_EX_LAYERED extended window style if not already set.
+ DWORD style = GetWindowLong(hwnd(), GWL_EXSTYLE);
+ DCHECK(!(style & WS_EX_COMPOSITED));
+ if (!(style & WS_EX_LAYERED))
+ SetWindowLong(hwnd(), GWL_EXSTYLE, style | WS_EX_LAYERED);
+
+ RECT wr;
+ GetWindowRect(hwnd(), &wr);
+ SIZE size = {wr.right - wr.left, wr.bottom - wr.top};
+ POINT position = {wr.left, wr.top};
+ POINT zero = {0, 0};
+ BLENDFUNCTION blend = {AC_SRC_OVER, 0x00, 0xFF, AC_SRC_ALPHA};
+
+ HDC dib_dc = skia::GetNativeDrawingContext(canvas_.get());
+ UpdateLayeredWindow(hwnd(), nullptr, &position, &size, dib_dc, &zero,
+ RGB(0xFF, 0xFF, 0xFF), &blend, ULW_ALPHA);
+}
+
+// SoftwareOutputDevice implementation that uses layered window API to draw
+// indirectly. Since UpdateLayeredWindow() is blocked by the GPU sandbox an
+// implementation of mojom::LayeredWindowUpdater in the browser process handles
+// calling UpdateLayeredWindow. Pixel backing is in SharedMemory so no copying
+// between processes is required.
+class SoftwareOutputDeviceWinProxy : public SoftwareOutputDeviceWinBase {
+ public:
+ SoftwareOutputDeviceWinProxy(
+ HWND hwnd,
+ mojom::LayeredWindowUpdaterPtr layered_window_updater);
+ ~SoftwareOutputDeviceWinProxy() override = default;
+
+ // SoftwareOutputDevice implementation.
+ void OnSwapBuffers(base::OnceClosure swap_ack_callback) override;
+
+ // SoftwareOutputDeviceWinBase implementation.
+ void ResizeDelegated() override;
+ SkCanvas* BeginPaintDelegated() override;
+ void EndPaintDelegated(const gfx::Rect& rect) override;
+
+ private:
+ // Runs |swap_ack_callback_| after draw has happened.
+ void DrawAck();
+
+ mojom::LayeredWindowUpdaterPtr layered_window_updater_;
+
+ std::unique_ptr<SkCanvas> canvas_;
+ bool waiting_on_draw_ack_ = false;
+ base::OnceClosure swap_ack_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWinProxy);
+};
+
+SoftwareOutputDeviceWinProxy::SoftwareOutputDeviceWinProxy(
+ HWND hwnd,
+ mojom::LayeredWindowUpdaterPtr layered_window_updater)
+ : SoftwareOutputDeviceWinBase(hwnd),
+ layered_window_updater_(std::move(layered_window_updater)) {
+ DCHECK(layered_window_updater_.is_bound());
+}
+
+void SoftwareOutputDeviceWinProxy::OnSwapBuffers(
+ base::OnceClosure swap_ack_callback) {
+ DCHECK(swap_ack_callback_.is_null());
+
+ // We aren't waiting on DrawAck() and can immediately run the callback.
+ if (!waiting_on_draw_ack_) {
+ task_runner_->PostTask(FROM_HERE, std::move(swap_ack_callback));
+ return;
+ }
+
+ swap_ack_callback_ = std::move(swap_ack_callback);
+}
+
+void SoftwareOutputDeviceWinProxy::ResizeDelegated() {
+ canvas_.reset();
+
+ size_t required_bytes;
+ if (!ResourceSizes::MaybeSizeInBytes(
+ viewport_pixel_size_, ResourceFormat::RGBA_8888, &required_bytes)) {
+ DLOG(ERROR) << "Invalid viewport size " << viewport_pixel_size_.ToString();
+ return;
+ }
+
+ base::SharedMemory shm;
+ if (!shm.CreateAnonymous(required_bytes)) {
+ DLOG(ERROR) << "Failed to allocate " << required_bytes << " bytes";
+ return;
+ }
+
+ // The SkCanvas maps shared memory on creation and unmaps on destruction.
+ canvas_ = skia::CreatePlatformCanvasWithSharedSection(
+ viewport_pixel_size_.width(), viewport_pixel_size_.height(), true,
+ shm.handle().GetHandle(), skia::CRASH_ON_FAILURE);
+
+ // Transfer handle ownership to the browser process.
+ mojo::ScopedSharedBufferHandle scoped_handle = mojo::WrapSharedMemoryHandle(
+ shm.TakeHandle(), required_bytes,
+ mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
+
+ layered_window_updater_->OnAllocatedSharedMemory(viewport_pixel_size_,
+ std::move(scoped_handle));
+}
+
+SkCanvas* SoftwareOutputDeviceWinProxy::BeginPaintDelegated() {
+ return canvas_.get();
+}
+
+void SoftwareOutputDeviceWinProxy::EndPaintDelegated(
+ const gfx::Rect& damage_rect) {
+ DCHECK(!waiting_on_draw_ack_);
+
+ if (!canvas_)
+ return;
+
+ layered_window_updater_->Draw(base::BindOnce(
+ &SoftwareOutputDeviceWinProxy::DrawAck, base::Unretained(this)));
+ waiting_on_draw_ack_ = true;
+
+ TRACE_EVENT_ASYNC_BEGIN0("viz", "SoftwareOutputDeviceWinProxy::Draw", this);
+}
+
+void SoftwareOutputDeviceWinProxy::DrawAck() {
+ DCHECK(waiting_on_draw_ack_);
+ DCHECK(!swap_ack_callback_.is_null());
+
+ TRACE_EVENT_ASYNC_END0("viz", "SoftwareOutputDeviceWinProxy::Draw", this);
+
+ waiting_on_draw_ack_ = false;
+ std::move(swap_ack_callback_).Run();
+}
+
+} // namespace
+
+std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinBrowser(
+ HWND hwnd,
+ OutputDeviceBacking* backing) {
+ if (NeedsToUseLayerWindow(hwnd))
+ return std::make_unique<SoftwareOutputDeviceWinLayered>(hwnd);
+
+ return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing);
+}
+
+std::unique_ptr<SoftwareOutputDevice> CreateSoftwareOutputDeviceWinGpu(
+ HWND hwnd,
+ OutputDeviceBacking* backing,
+ mojom::DisplayClient* display_client) {
+ if (NeedsToUseLayerWindow(hwnd)) {
+ DCHECK(display_client);
+
+ // Setup mojom::LayeredWindowUpdater implementation in the browser process
+ // to draw to the HWND.
+ mojom::LayeredWindowUpdaterPtr layered_window_updater;
+ display_client->CreateLayeredWindowUpdater(
+ mojo::MakeRequest(&layered_window_updater));
+
+ return std::make_unique<SoftwareOutputDeviceWinProxy>(
+ hwnd, std::move(layered_window_updater));
+ }
+
+ return std::make_unique<SoftwareOutputDeviceWinDirect>(hwnd, backing);
}
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/software_output_device_win.h b/chromium/components/viz/service/display_embedder/software_output_device_win.h
index ad2a049fc77..aa2dd64bb0d 100644
--- a/chromium/components/viz/service/display_embedder/software_output_device_win.h
+++ b/chromium/components/viz/service/display_embedder/software_output_device_win.h
@@ -5,71 +5,29 @@
#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_WIN_H_
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_DEVICE_WIN_H_
-#include <stddef.h>
#include <windows.h>
#include <memory>
-#include <vector>
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
#include "components/viz/service/display/software_output_device.h"
#include "components/viz/service/viz_service_export.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkRefCnt.h"
-#include "ui/gfx/native_widget_types.h"
-
-namespace base {
-class SharedMemory;
-}
+#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
namespace viz {
-class SoftwareOutputDeviceWin;
-
-class VIZ_SERVICE_EXPORT OutputDeviceBacking {
- public:
- OutputDeviceBacking();
- ~OutputDeviceBacking();
-
- void Resized();
- void RegisterOutputDevice(SoftwareOutputDeviceWin* device);
- void UnregisterOutputDevice(SoftwareOutputDeviceWin* device);
- base::SharedMemory* GetSharedMemory(const gfx::Size& size);
-
- private:
- size_t GetMaxByteSize();
-
- std::vector<SoftwareOutputDeviceWin*> devices_;
- std::unique_ptr<base::SharedMemory> backing_;
- size_t created_byte_size_;
-
- DISALLOW_COPY_AND_ASSIGN(OutputDeviceBacking);
-};
-
-class VIZ_SERVICE_EXPORT SoftwareOutputDeviceWin : public SoftwareOutputDevice {
- public:
- SoftwareOutputDeviceWin(OutputDeviceBacking* backing,
- gfx::AcceleratedWidget widget);
- ~SoftwareOutputDeviceWin() override;
-
- void Resize(const gfx::Size& viewport_pixel_size,
- float scale_factor) override;
- SkCanvas* BeginPaint(const gfx::Rect& damage_rect) override;
- void EndPaint() override;
- gfx::Size viewport_pixel_size() const { return viewport_pixel_size_; }
- void ReleaseContents();
+class OutputDeviceBacking;
- private:
- HWND hwnd_;
- std::unique_ptr<SkCanvas> contents_;
- bool is_hwnd_composited_;
- OutputDeviceBacking* backing_;
- bool in_paint_;
- THREAD_CHECKER(thread_checker_);
+// Creates an appropriate SoftwareOutputDevice implementation for the browser
+// process.
+VIZ_SERVICE_EXPORT std::unique_ptr<SoftwareOutputDevice>
+CreateSoftwareOutputDeviceWinBrowser(HWND hwnd, OutputDeviceBacking* backing);
- DISALLOW_COPY_AND_ASSIGN(SoftwareOutputDeviceWin);
-};
+// Creates an appropriate SoftwareOutputDevice implementation for the GPU
+// process.
+VIZ_SERVICE_EXPORT std::unique_ptr<SoftwareOutputDevice>
+CreateSoftwareOutputDeviceWinGpu(HWND hwnd,
+ OutputDeviceBacking* backing,
+ mojom::DisplayClient* display_client);
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.cc b/chromium/components/viz/service/display_embedder/software_output_surface.cc
index 370829010ea..fff590968c5 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.cc
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.cc
@@ -9,7 +9,6 @@
#include "base/bind.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
-#include "base/threading/sequenced_task_runner_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/viz/service/display/output_surface_client.h"
@@ -22,11 +21,8 @@
namespace viz {
SoftwareOutputSurface::SoftwareOutputSurface(
- std::unique_ptr<SoftwareOutputDevice> software_device,
- scoped_refptr<base::SequencedTaskRunner> task_runner)
- : OutputSurface(std::move(software_device)),
- task_runner_(std::move(task_runner)),
- weak_factory_(this) {}
+ std::unique_ptr<SoftwareOutputDevice> software_device)
+ : OutputSurface(std::move(software_device)), weak_factory_(this) {}
SoftwareOutputSurface::~SoftwareOutputSurface() = default;
@@ -66,14 +62,16 @@ void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
base::TimeTicks swap_time = base::TimeTicks::Now();
for (auto& latency : frame.latency_info) {
latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, 0, swap_time, 1);
+ ui::INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT, 0, swap_time, 1);
latency.AddLatencyNumberWithTimestamp(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0,
- swap_time, 1);
+ ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, swap_time,
+ 1);
}
- // TODO(danakj): Send frame.latency_info somewhere like
- // RenderWidgetHostImpl::OnGpuSwapBuffersCompleted. It should go to the
- // ui::LatencyTracker in the viz process.
+
+ DCHECK(stored_latency_info_.empty())
+ << "A second frame is not expected to "
+ << "arrive before the previous latency info is processed.";
+ stored_latency_info_ = std::move(frame.latency_info);
// TODO(danakj): Update vsync params.
// gfx::VSyncProvider* vsync_provider = software_device()->GetVSyncProvider();
@@ -81,10 +79,9 @@ void SoftwareOutputSurface::SwapBuffers(OutputSurfaceFrame frame) {
// vsync_provider->GetVSyncParameters(update_vsync_parameters_callback_);
// Update refresh_interval_ as well.
- ++swap_id_;
- task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&SoftwareOutputSurface::SwapBuffersCallback,
- weak_factory_.GetWeakPtr(), swap_id_));
+ software_device()->OnSwapBuffers(base::BindOnce(
+ &SoftwareOutputSurface::SwapBuffersCallback, weak_factory_.GetWeakPtr(),
+ frame.need_presentation_feedback));
}
bool SoftwareOutputSurface::IsDisplayedAsOverlayPlane() const {
@@ -111,21 +108,22 @@ bool SoftwareOutputSurface::HasExternalStencilTest() const {
void SoftwareOutputSurface::ApplyExternalStencil() {}
-bool SoftwareOutputSurface::SurfaceIsSuspendForRecycle() const {
- return false;
-}
-
uint32_t SoftwareOutputSurface::GetFramebufferCopyTextureFormat() {
// Not used for software surfaces.
NOTREACHED();
return 0;
}
-void SoftwareOutputSurface::SwapBuffersCallback(uint64_t swap_id) {
- client_->DidReceiveSwapBuffersAck(swap_id);
- client_->DidReceivePresentationFeedback(
- swap_id,
- gfx::PresentationFeedback(base::TimeTicks::Now(), refresh_interval_, 0u));
+void SoftwareOutputSurface::SwapBuffersCallback(
+ bool need_presentation_feedback) {
+ latency_tracker_.OnGpuSwapBuffersCompleted(stored_latency_info_);
+ client_->DidFinishLatencyInfo(stored_latency_info_);
+ std::vector<ui::LatencyInfo>().swap(stored_latency_info_);
+ client_->DidReceiveSwapBuffersAck();
+ if (need_presentation_feedback) {
+ client_->DidReceivePresentationFeedback(gfx::PresentationFeedback(
+ base::TimeTicks::Now(), refresh_interval_, 0u));
+ }
}
#if BUILDFLAG(ENABLE_VULKAN)
@@ -135,4 +133,8 @@ gpu::VulkanSurface* SoftwareOutputSurface::GetVulkanSurface() {
}
#endif
+unsigned SoftwareOutputSurface::UpdateGpuFence() {
+ return 0;
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/display_embedder/software_output_surface.h b/chromium/components/viz/service/display_embedder/software_output_surface.h
index 70b20326e25..2c78d933167 100644
--- a/chromium/components/viz/service/display_embedder/software_output_surface.h
+++ b/chromium/components/viz/service/display_embedder/software_output_surface.h
@@ -6,17 +6,18 @@
#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_SOFTWARE_OUTPUT_SURFACE_H_
#include "base/memory/weak_ptr.h"
-#include "base/single_thread_task_runner.h"
#include "components/viz/service/display/output_surface.h"
#include "components/viz/service/viz_service_export.h"
+#include "ui/latency/latency_info.h"
+#include "ui/latency/latency_tracker.h"
namespace viz {
class SoftwareOutputDevice;
class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
public:
- SoftwareOutputSurface(std::unique_ptr<SoftwareOutputDevice> software_device,
- scoped_refptr<base::SequencedTaskRunner> task_runner);
+ explicit SoftwareOutputSurface(
+ std::unique_ptr<SoftwareOutputDevice> software_device);
~SoftwareOutputSurface() override;
// OutputSurface implementation.
@@ -37,19 +38,19 @@ class VIZ_SERVICE_EXPORT SoftwareOutputSurface : public OutputSurface {
gfx::BufferFormat GetOverlayBufferFormat() const override;
bool HasExternalStencilTest() const override;
void ApplyExternalStencil() override;
- bool SurfaceIsSuspendForRecycle() const override;
uint32_t GetFramebufferCopyTextureFormat() override;
#if BUILDFLAG(ENABLE_VULKAN)
gpu::VulkanSurface* GetVulkanSurface() override;
#endif
+ unsigned UpdateGpuFence() override;
private:
- void SwapBuffersCallback(uint64_t swap_id);
+ void SwapBuffersCallback(bool need_presentation_feedback);
OutputSurfaceClient* client_ = nullptr;
- scoped_refptr<base::SequencedTaskRunner> task_runner_;
base::TimeDelta refresh_interval_;
- uint64_t swap_id_ = 0;
+ std::vector<ui::LatencyInfo> stored_latency_info_;
+ ui::LatencyTracker latency_tracker_;
base::WeakPtrFactory<SoftwareOutputSurface> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SoftwareOutputSurface);
diff --git a/chromium/components/viz/common/gpu/in_process_context_provider.cc b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
index 6c740d12afe..e32a6e1864e 100644
--- a/chromium/components/viz/common/gpu/in_process_context_provider.cc
+++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.cc
@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "components/viz/common/gpu/in_process_context_provider.h"
+#include "components/viz/service/display_embedder/viz_process_context_provider.h"
#include <stdint.h>
+#include <utility>
+
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
@@ -47,55 +49,53 @@ gpu::ContextCreationAttribs CreateAttributes() {
} // namespace
-InProcessContextProvider::InProcessContextProvider(
+VizProcessContextProvider::VizProcessContextProvider(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
gpu::SurfaceHandle surface_handle,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- const gpu::SharedMemoryLimits& limits,
- InProcessContextProvider* shared_context)
+ const gpu::SharedMemoryLimits& limits)
: attributes_(CreateAttributes()),
context_(gpu::GLInProcessContext::CreateWithoutInit()),
- context_result_(context_->Initialize(
- std::move(service),
- nullptr,
- (surface_handle == gpu::kNullSurfaceHandle),
- surface_handle,
- (shared_context ? shared_context->context_.get() : nullptr),
- attributes_,
- limits,
- gpu_memory_buffer_manager,
- image_factory,
- gpu_channel_manager_delegate,
- base::ThreadTaskRunnerHandle::Get())),
+ context_result_(
+ context_->Initialize(std::move(service),
+ nullptr,
+ (surface_handle == gpu::kNullSurfaceHandle),
+ surface_handle,
+ attributes_,
+ limits,
+ gpu_memory_buffer_manager,
+ image_factory,
+ gpu_channel_manager_delegate,
+ base::ThreadTaskRunnerHandle::Get())),
cache_controller_(std::make_unique<ContextCacheController>(
context_->GetImplementation(),
base::ThreadTaskRunnerHandle::Get())) {}
-InProcessContextProvider::~InProcessContextProvider() = default;
+VizProcessContextProvider::~VizProcessContextProvider() = default;
-void InProcessContextProvider::AddRef() const {
- base::RefCountedThreadSafe<InProcessContextProvider>::AddRef();
+void VizProcessContextProvider::AddRef() const {
+ base::RefCountedThreadSafe<VizProcessContextProvider>::AddRef();
}
-void InProcessContextProvider::Release() const {
- base::RefCountedThreadSafe<InProcessContextProvider>::Release();
+void VizProcessContextProvider::Release() const {
+ base::RefCountedThreadSafe<VizProcessContextProvider>::Release();
}
-gpu::ContextResult InProcessContextProvider::BindToCurrentThread() {
+gpu::ContextResult VizProcessContextProvider::BindToCurrentThread() {
return context_result_;
}
-gpu::gles2::GLES2Interface* InProcessContextProvider::ContextGL() {
+gpu::gles2::GLES2Interface* VizProcessContextProvider::ContextGL() {
return context_->GetImplementation();
}
-gpu::ContextSupport* InProcessContextProvider::ContextSupport() {
+gpu::ContextSupport* VizProcessContextProvider::ContextSupport() {
return context_->GetImplementation();
}
-class GrContext* InProcessContextProvider::GrContext() {
+class GrContext* VizProcessContextProvider::GrContext() {
if (gr_context_)
return gr_context_->get();
@@ -111,27 +111,29 @@ class GrContext* InProcessContextProvider::GrContext() {
return gr_context_->get();
}
-ContextCacheController* InProcessContextProvider::CacheController() {
+ContextCacheController* VizProcessContextProvider::CacheController() {
return cache_controller_.get();
}
-base::Lock* InProcessContextProvider::GetLock() {
+base::Lock* VizProcessContextProvider::GetLock() {
return &context_lock_;
}
-const gpu::Capabilities& InProcessContextProvider::ContextCapabilities() const {
+const gpu::Capabilities& VizProcessContextProvider::ContextCapabilities()
+ const {
return context_->GetCapabilities();
}
-const gpu::GpuFeatureInfo& InProcessContextProvider::GetGpuFeatureInfo() const {
+const gpu::GpuFeatureInfo& VizProcessContextProvider::GetGpuFeatureInfo()
+ const {
return context_->GetGpuFeatureInfo();
}
-void InProcessContextProvider::AddObserver(ContextLostObserver* obs) {}
+void VizProcessContextProvider::AddObserver(ContextLostObserver* obs) {}
-void InProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {}
+void VizProcessContextProvider::RemoveObserver(ContextLostObserver* obs) {}
-uint32_t InProcessContextProvider::GetCopyTextureInternalFormat() {
+uint32_t VizProcessContextProvider::GetCopyTextureInternalFormat() {
if (attributes_.alpha_size > 0)
return GL_RGBA;
DCHECK_NE(attributes_.red_size, 0);
@@ -140,20 +142,10 @@ uint32_t InProcessContextProvider::GetCopyTextureInternalFormat() {
return GL_RGB;
}
-void InProcessContextProvider::SetSwapBuffersCompletionCallback(
- const gpu::InProcessCommandBuffer::SwapBuffersCompletionCallback&
- callback) {
- context_->SetSwapBuffersCompletionCallback(callback);
-}
-
-void InProcessContextProvider::SetUpdateVSyncParametersCallback(
+void VizProcessContextProvider::SetUpdateVSyncParametersCallback(
const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback&
callback) {
context_->SetUpdateVSyncParametersCallback(callback);
}
-void InProcessContextProvider::SetPresentationCallback(
- const gpu::InProcessCommandBuffer::PresentationCallback& callback) {
- context_->SetPresentationCallback(callback);
-}
} // namespace viz
diff --git a/chromium/components/viz/common/gpu/in_process_context_provider.h b/chromium/components/viz/service/display_embedder/viz_process_context_provider.h
index aa66c1b2d14..a25423e16fe 100644
--- a/chromium/components/viz/common/gpu/in_process_context_provider.h
+++ b/chromium/components/viz/service/display_embedder/viz_process_context_provider.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 COMPONENTS_VIZ_COMMON_GPU_IN_PROCESS_CONTEXT_PROVIDER_H_
-#define COMPONENTS_VIZ_COMMON_GPU_IN_PROCESS_CONTEXT_PROVIDER_H_
+#ifndef COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_
+#define COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_
#include <stdint.h>
@@ -13,7 +13,7 @@
#include "base/synchronization/lock.h"
#include "components/viz/common/gpu/context_cache_controller.h"
#include "components/viz/common/gpu/context_provider.h"
-#include "components/viz/common/viz_common_export.h"
+#include "components/viz/service/viz_service_export.h"
#include "gpu/command_buffer/common/context_creation_attribs.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "ui/gfx/native_widget_types.h"
@@ -34,22 +34,19 @@ class GrContextForGLES2Interface;
namespace viz {
-// A ContextProvider used in the viz process to setup command buffers between
-// the compositor and gpu thread.
-// TODO(kylechar): Rename VizProcessContextProvider and move to
-// components/viz/service.
-class VIZ_COMMON_EXPORT InProcessContextProvider
- : public base::RefCountedThreadSafe<InProcessContextProvider>,
+// A ContextProvider used in the viz process to setup an InProcessCommandBuffer
+// for the display compositor.
+class VIZ_SERVICE_EXPORT VizProcessContextProvider
+ : public base::RefCountedThreadSafe<VizProcessContextProvider>,
public ContextProvider {
public:
- InProcessContextProvider(
+ VizProcessContextProvider(
scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
gpu::SurfaceHandle surface_handle,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
gpu::ImageFactory* image_factory,
gpu::GpuChannelManagerDelegate* gpu_channel_manager_delegate,
- const gpu::SharedMemoryLimits& limits,
- InProcessContextProvider* shared_context);
+ const gpu::SharedMemoryLimits& limits);
// ContextProvider implementation.
void AddRef() const override;
@@ -67,20 +64,13 @@ class VIZ_COMMON_EXPORT InProcessContextProvider
uint32_t GetCopyTextureInternalFormat();
- void SetSwapBuffersCompletionCallback(
- const gpu::InProcessCommandBuffer::SwapBuffersCompletionCallback&
- callback);
-
void SetUpdateVSyncParametersCallback(
const gpu::InProcessCommandBuffer::UpdateVSyncParametersCallback&
callback);
- void SetPresentationCallback(
- const gpu::InProcessCommandBuffer::PresentationCallback& callback);
-
protected:
- friend class base::RefCountedThreadSafe<InProcessContextProvider>;
- ~InProcessContextProvider() override;
+ friend class base::RefCountedThreadSafe<VizProcessContextProvider>;
+ ~VizProcessContextProvider() override;
private:
const gpu::ContextCreationAttribs attributes_;
@@ -94,4 +84,4 @@ class VIZ_COMMON_EXPORT InProcessContextProvider
} // namespace viz
-#endif // COMPONENTS_VIZ_COMMON_GPU_IN_PROCESS_CONTEXT_PROVIDER_H_
+#endif // COMPONENTS_VIZ_SERVICE_DISPLAY_EMBEDDER_VIZ_PROCESS_CONTEXT_PROVIDER_H_
diff --git a/chromium/components/viz/service/frame_sinks/DEPS b/chromium/components/viz/service/frame_sinks/DEPS
index 90500834623..5d7cb869719 100644
--- a/chromium/components/viz/service/frame_sinks/DEPS
+++ b/chromium/components/viz/service/frame_sinks/DEPS
@@ -2,7 +2,6 @@
include_rules = [
"+cc/base",
- "+cc/ipc",
"+cc/scheduler",
"+components/viz/service/display",
"+components/viz/service/display_embedder",
@@ -11,3 +10,9 @@ include_rules = [
"+gpu/ipc/common",
"+mojo/public",
]
+
+specific_include_rules = {
+ ".*unittest\.cc": [
+ "+third_party/khronos/GLES2",
+ ]
+}
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
index 052ac635cd0..b086112b6b0 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -41,10 +41,33 @@ void CompositorFrameSinkImpl::SetWantsAnimateOnlyBeginFrames() {
void CompositorFrameSinkImpl::SubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list,
+ base::Optional<HitTestRegionList> hit_test_region_list,
uint64_t submit_time) {
+ SubmitCompositorFrameInternal(local_surface_id, std::move(frame),
+ std::move(hit_test_region_list), submit_time,
+ SubmitCompositorFrameSyncCallback());
+}
+
+void CompositorFrameSinkImpl::SubmitCompositorFrameSync(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time,
+ SubmitCompositorFrameSyncCallback callback) {
+ SubmitCompositorFrameInternal(local_surface_id, std::move(frame),
+ std::move(hit_test_region_list), submit_time,
+ std::move(callback));
+}
+
+void CompositorFrameSinkImpl::SubmitCompositorFrameInternal(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback callback) {
const auto result = support_->MaybeSubmitCompositorFrame(
- local_surface_id, std::move(frame), std::move(hit_test_region_list));
+ local_surface_id, std::move(frame), std::move(hit_test_region_list),
+ std::move(callback));
if (result == CompositorFrameSinkSupport::ACCEPTED)
return;
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
index a03e101cc88..b05aaea3d51 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
@@ -30,16 +30,30 @@ class CompositorFrameSinkImpl : public mojom::CompositorFrameSink {
// mojom::CompositorFrameSink:
void SetNeedsBeginFrame(bool needs_begin_frame) override;
void SetWantsAnimateOnlyBeginFrames() override;
- void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
- CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list,
- uint64_t submit_time) override;
+ void SubmitCompositorFrame(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time) override;
+ void SubmitCompositorFrameSync(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time,
+ SubmitCompositorFrameSyncCallback callback) override;
void DidNotProduceFrame(const BeginFrameAck& begin_frame_ack) override;
void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
const SharedBitmapId& id) override;
void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
private:
+ void SubmitCompositorFrameInternal(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback);
+
void OnClientConnectionLost();
mojom::CompositorFrameSinkClientPtr compositor_frame_sink_client_;
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index 4d98fd2eaf2..44baa1dae5e 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -44,6 +44,8 @@ CompositorFrameSinkSupport::~CompositorFrameSinkSupport() {
// Unregister |this| as a BeginFrameObserver so that the
// BeginFrameSource does not call into |this| after it's deleted.
+ callback_received_begin_frame_ = true;
+ callback_received_receive_ack_ = true;
SetNeedsBeginFrame(false);
// For display root surfaces the surface is no longer going to be visible.
@@ -207,7 +209,7 @@ void CompositorFrameSinkSupport::EvictLastActivatedSurface() {
}
void CompositorFrameSinkSupport::SetNeedsBeginFrame(bool needs_begin_frame) {
- needs_begin_frame_ = needs_begin_frame;
+ client_needs_begin_frame_ = needs_begin_frame;
UpdateNeedsBeginFramesInternal();
}
@@ -239,10 +241,11 @@ void CompositorFrameSinkSupport::DidNotProduceFrame(const BeginFrameAck& ack) {
void CompositorFrameSinkSupport::SubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list,
+ base::Optional<HitTestRegionList> hit_test_region_list,
uint64_t submit_time) {
const auto result = MaybeSubmitCompositorFrame(
- local_surface_id, std::move(frame), std::move(hit_test_region_list));
+ local_surface_id, std::move(frame), std::move(hit_test_region_list),
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
DCHECK_EQ(result, ACCEPTED);
}
@@ -267,13 +270,24 @@ CompositorFrameSinkSupport::SubmitResult
CompositorFrameSinkSupport::MaybeSubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list) {
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback callback) {
TRACE_EVENT1("viz", "CompositorFrameSinkSupport::MaybeSubmitCompositorFrame",
"FrameSinkId", frame_sink_id_.ToString());
DCHECK(local_surface_id.is_valid());
DCHECK(!frame.render_pass_list.empty());
DCHECK(!frame.size_in_pixels().IsEmpty());
+ CHECK(callback_received_begin_frame_);
+ CHECK(callback_received_receive_ack_);
+
+ compositor_frame_callback_ = std::move(callback);
+ if (compositor_frame_callback_) {
+ callback_received_begin_frame_ = false;
+ callback_received_receive_ack_ = false;
+ UpdateNeedsBeginFramesInternal();
+ }
+
// Ensure no CopyOutputRequests have been submitted if they are banned.
if (!allow_copy_output_requests_ && frame.HasCopyOutputRequests()) {
TRACE_EVENT_INSTANT0("viz", "CopyOutputRequests not allowed",
@@ -296,7 +310,7 @@ CompositorFrameSinkSupport::MaybeSubmitCompositorFrame(
for (ui::LatencyInfo& latency : frame.metadata.latency_info) {
if (latency.latency_components().size() > 0) {
latency.AddLatencyNumber(ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT,
- 0, 0);
+ 0);
}
}
@@ -422,12 +436,31 @@ SurfaceReference CompositorFrameSinkSupport::MakeTopLevelRootReference(
return SurfaceReference(surface_manager_->GetRootSurfaceId(), surface_id);
}
+void CompositorFrameSinkSupport::HandleCallback() {
+ if (!compositor_frame_callback_ || !callback_received_begin_frame_ ||
+ !callback_received_receive_ack_) {
+ return;
+ }
+
+ std::move(compositor_frame_callback_)
+ .Run(std::move(surface_returned_resources_));
+ surface_returned_resources_.clear();
+}
+
void CompositorFrameSinkSupport::DidReceiveCompositorFrameAck() {
DCHECK_GT(ack_pending_count_, 0);
ack_pending_count_--;
if (!client_)
return;
+ // If we have a callback, we only return the resource on onBeginFrame.
+ if (compositor_frame_callback_) {
+ callback_received_receive_ack_ = true;
+ UpdateNeedsBeginFramesInternal();
+ HandleCallback();
+ return;
+ }
+
client_->DidReceiveCompositorFrameAck(surface_returned_resources_);
surface_returned_resources_.clear();
}
@@ -449,11 +482,17 @@ void CompositorFrameSinkSupport::DidPresentCompositorFrame(
}
void CompositorFrameSinkSupport::OnBeginFrame(const BeginFrameArgs& args) {
- UpdateNeedsBeginFramesInternal();
if (last_activated_surface_id_.is_valid())
surface_manager_->SurfaceDamageExpected(last_activated_surface_id_, args);
last_begin_frame_args_ = args;
- if (client_)
+
+ if (compositor_frame_callback_) {
+ callback_received_begin_frame_ = true;
+ UpdateNeedsBeginFramesInternal();
+ HandleCallback();
+ }
+
+ if (client_ && client_needs_begin_frame_)
client_->OnBeginFrame(args);
}
@@ -471,11 +510,17 @@ void CompositorFrameSinkSupport::UpdateNeedsBeginFramesInternal() {
if (!begin_frame_source_)
return;
- if (needs_begin_frame_ == added_frame_observer_)
+ // We require a begin frame if there's a callback pending, or if the client
+ // requested it.
+ bool needs_begin_frame =
+ client_needs_begin_frame_ ||
+ (compositor_frame_callback_ && !callback_received_begin_frame_);
+
+ if (needs_begin_frame == added_frame_observer_)
return;
- added_frame_observer_ = needs_begin_frame_;
- if (needs_begin_frame_)
+ added_frame_observer_ = needs_begin_frame;
+ if (needs_begin_frame)
begin_frame_source_->AddObserver(this);
else
begin_frame_source_->RemoveObserver(this);
@@ -507,6 +552,7 @@ gfx::Size CompositorFrameSinkSupport::GetActiveFrameSize() {
if (last_activated_surface_id_.is_valid()) {
Surface* current_surface =
surface_manager_->GetSurfaceForId(last_activated_surface_id_);
+ DCHECK(current_surface);
if (current_surface->HasActiveFrame()) {
DCHECK(current_surface->GetActiveFrame().size_in_pixels() ==
current_surface->size_in_pixels());
@@ -528,6 +574,16 @@ void CompositorFrameSinkSupport::RequestCopyOfOutput(
}
}
+const CompositorFrameMetadata*
+CompositorFrameSinkSupport::GetLastActivatedFrameMetadata() {
+ if (!last_activated_surface_id_.is_valid())
+ return nullptr;
+ Surface* surface =
+ surface_manager_->GetSurfaceForId(last_activated_surface_id_);
+ DCHECK(surface);
+ return &surface->GetActiveFrame().metadata;
+}
+
HitTestAggregator* CompositorFrameSinkSupport::GetHitTestAggregator() {
DCHECK(is_root_);
return hit_test_aggregator_.get();
@@ -554,11 +610,12 @@ const char* CompositorFrameSinkSupport::GetSubmitResultAsString(
void CompositorFrameSinkSupport::OnAggregatedDamage(
const LocalSurfaceId& local_surface_id,
- const gfx::Size& frame_size_in_pixels,
+ const CompositorFrame& frame,
const gfx::Rect& damage_rect,
base::TimeTicks expected_display_time) const {
DCHECK(!damage_rect.IsEmpty());
+ const gfx::Size& frame_size_in_pixels = frame.size_in_pixels();
if (aggregated_damage_callback_) {
aggregated_damage_callback_.Run(local_surface_id, frame_size_in_pixels,
damage_rect, expected_display_time);
@@ -566,7 +623,7 @@ void CompositorFrameSinkSupport::OnAggregatedDamage(
for (CapturableFrameSink::Client* client : capture_clients_) {
client->OnFrameDamaged(frame_size_in_pixels, damage_rect,
- expected_display_time);
+ expected_display_time, frame.metadata);
}
}
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index 863b4b8b998..8317b21c9e6 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
#include "base/time/time.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/quads/compositor_frame.h"
@@ -110,7 +111,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
void SubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list = nullptr,
+ base::Optional<HitTestRegionList> hit_test_region_list = base::nullopt,
uint64_t submit_time = 0);
// Returns false if the notification was not valid (a duplicate).
bool DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
@@ -130,7 +131,8 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
SubmitResult MaybeSubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list);
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback);
// CapturableFrameSink implementation.
void AttachCaptureClient(CapturableFrameSink::Client* client) override;
@@ -138,6 +140,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
gfx::Size GetActiveFrameSize() override;
void RequestCopyOfOutput(const LocalSurfaceId& local_surface_id,
std::unique_ptr<CopyOutputRequest> request) override;
+ const CompositorFrameMetadata* GetLastActivatedFrameMetadata() override;
HitTestAggregator* GetHitTestAggregator();
@@ -183,10 +186,14 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
Surface* CreateSurface(const SurfaceInfo& surface_info);
void OnAggregatedDamage(const LocalSurfaceId& local_surface_id,
- const gfx::Size& frame_size_in_pixels,
+ const CompositorFrame& frame,
const gfx::Rect& damage_rect,
base::TimeTicks expected_display_time) const;
+ // For the sync API calls, if we are blocking a client callback, runs it once
+ // BeginFrame and FrameAck are done.
+ void HandleCallback();
+
mojom::CompositorFrameSinkClient* const client_;
FrameSinkManagerImpl* const frame_sink_manager_;
@@ -218,7 +225,7 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
BeginFrameArgs last_begin_frame_args_;
// Whether a request for begin frames has been issued.
- bool needs_begin_frame_ = false;
+ bool client_needs_begin_frame_ = false;
// Whether or not a frame observer has been added.
bool added_frame_observer_ = false;
@@ -263,6 +270,11 @@ class VIZ_SERVICE_EXPORT CompositorFrameSinkSupport
std::vector<std::pair<LocalSurfaceId, std::unique_ptr<CopyOutputRequest>>>
copy_output_requests_;
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback
+ compositor_frame_callback_;
+ bool callback_received_begin_frame_ = true;
+ bool callback_received_receive_ack_ = true;
+
base::WeakPtrFactory<CompositorFrameSinkSupport> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkSupport);
diff --git a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index f9d67412f48..9852c9b2f18 100644
--- a/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -5,7 +5,6 @@
#include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
#include "base/macros.h"
-#include "cc/resources/resource_provider.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/quads/compositor_frame.h"
@@ -23,6 +22,7 @@
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/khronos/GLES2/gl2.h"
using testing::UnorderedElementsAre;
using testing::IsEmpty;
@@ -70,13 +70,7 @@ class MockFrameSinkManagerClient : public mojom::FrameSinkManagerClient {
MOCK_METHOD1(OnFirstSurfaceActivation, void(const SurfaceInfo&));
void OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_sizes) override {}
- void SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) override {}
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) override {}
void OnFrameTokenChanged(const FrameSinkId& frame_sink_id,
uint32_t frame_token) override {}
@@ -130,7 +124,8 @@ class CompositorFrameSinkSupportTest : public testing::Test {
auto frame = MakeDefaultCompositorFrame();
frame.render_pass_list.back()->copy_requests.push_back(std::move(request));
const auto result = support_->MaybeSubmitCompositorFrame(
- local_surface_id_, std::move(frame), nullptr);
+ local_surface_id_, std::move(frame), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
switch (result) {
case CompositorFrameSinkSupport::ACCEPTED:
return true;
@@ -540,22 +535,28 @@ TEST_F(CompositorFrameSinkSupportTest, MonotonicallyIncreasingLocalSurfaceIds) {
LocalSurfaceId local_surface_id5(8, 1, kArbitraryToken);
LocalSurfaceId local_surface_id6(9, 3, kArbitraryToken);
auto result = support->MaybeSubmitCompositorFrame(
- local_surface_id1, MakeDefaultCompositorFrame(), nullptr);
+ local_surface_id1, MakeDefaultCompositorFrame(), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result);
result = support->MaybeSubmitCompositorFrame(
- local_surface_id2, MakeDefaultCompositorFrame(), nullptr);
+ local_surface_id2, MakeDefaultCompositorFrame(), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result);
result = support->MaybeSubmitCompositorFrame(
- local_surface_id3, MakeDefaultCompositorFrame(), nullptr);
+ local_surface_id3, MakeDefaultCompositorFrame(), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result);
result = support->MaybeSubmitCompositorFrame(
- local_surface_id4, MakeDefaultCompositorFrame(), nullptr);
+ local_surface_id4, MakeDefaultCompositorFrame(), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result);
result = support->MaybeSubmitCompositorFrame(
- local_surface_id5, MakeDefaultCompositorFrame(), nullptr);
+ local_surface_id5, MakeDefaultCompositorFrame(), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result);
result = support->MaybeSubmitCompositorFrame(
- local_surface_id6, MakeDefaultCompositorFrame(), nullptr);
+ local_surface_id6, MakeDefaultCompositorFrame(), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result);
manager_.InvalidateFrameSinkId(kAnotherArbitraryFrameSinkId);
@@ -775,7 +776,8 @@ TEST_F(CompositorFrameSinkSupportTest, ZeroDeviceScaleFactor) {
.SetDeviceScaleFactor(0.f)
.Build();
const auto result = support_->MaybeSubmitCompositorFrame(
- local_surface_id_, std::move(frame), nullptr);
+ local_surface_id_, std::move(frame), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result);
EXPECT_FALSE(GetSurfaceForId(id));
}
@@ -789,8 +791,9 @@ TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) {
auto frame = CompositorFrameBuilder()
.AddRenderPass(gfx::Rect(5, 5), gfx::Rect())
.Build();
- auto result = support_->MaybeSubmitCompositorFrame(local_surface_id_,
- std::move(frame), nullptr);
+ auto result = support_->MaybeSubmitCompositorFrame(
+ local_surface_id_, std::move(frame), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result);
EXPECT_TRUE(GetSurfaceForId(id));
@@ -799,8 +802,9 @@ TEST_F(CompositorFrameSinkSupportTest, FrameSizeMismatch) {
frame = CompositorFrameBuilder()
.AddRenderPass(gfx::Rect(5, 4), gfx::Rect())
.Build();
- result = support_->MaybeSubmitCompositorFrame(local_surface_id_,
- std::move(frame), nullptr);
+ result = support_->MaybeSubmitCompositorFrame(
+ local_surface_id_, std::move(frame), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result);
}
@@ -815,8 +819,9 @@ TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) {
.AddDefaultRenderPass()
.SetDeviceScaleFactor(0.5f)
.Build();
- auto result = support_->MaybeSubmitCompositorFrame(local_surface_id_,
- std::move(frame), nullptr);
+ auto result = support_->MaybeSubmitCompositorFrame(
+ local_surface_id_, std::move(frame), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::ACCEPTED, result);
EXPECT_TRUE(GetSurfaceForId(id));
@@ -826,8 +831,9 @@ TEST_F(CompositorFrameSinkSupportTest, DeviceScaleFactorMismatch) {
.AddDefaultRenderPass()
.SetDeviceScaleFactor(0.4f)
.Build();
- result = support_->MaybeSubmitCompositorFrame(local_surface_id_,
- std::move(frame), nullptr);
+ result = support_->MaybeSubmitCompositorFrame(
+ local_surface_id_, std::move(frame), base::nullopt,
+ mojom::CompositorFrameSink::SubmitCompositorFrameSyncCallback());
EXPECT_EQ(CompositorFrameSinkSupport::SURFACE_INVARIANTS_VIOLATION, result);
}
diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
index 56be759068b..ed6ac7abfaf 100644
--- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
+++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "cc/trees/layer_tree_frame_sink_client.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/quads/compositor_frame.h"
#include "components/viz/common/quads/draw_quad.h"
#include "components/viz/common/quads/surface_draw_quad.h"
@@ -30,13 +31,11 @@ DirectLayerTreeFrameSink::DirectLayerTreeFrameSink(
scoped_refptr<RasterContextProvider> worker_context_provider,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- SharedBitmapManager* shared_bitmap_manager,
bool use_viz_hit_test)
: LayerTreeFrameSink(std::move(context_provider),
std::move(worker_context_provider),
std::move(compositor_task_runner),
- gpu_memory_buffer_manager,
- shared_bitmap_manager),
+ gpu_memory_buffer_manager),
frame_sink_id_(frame_sink_id),
support_manager_(support_manager),
frame_sink_manager_(frame_sink_manager),
@@ -90,23 +89,79 @@ void DirectLayerTreeFrameSink::DetachFromClient() {
cc::LayerTreeFrameSink::DetachFromClient();
}
+static HitTestRegionList CreateHitTestData(const CompositorFrame& frame) {
+ HitTestRegionList hit_test_region_list;
+ hit_test_region_list.flags = HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine;
+ hit_test_region_list.bounds.set_size(frame.size_in_pixels());
+
+ for (const auto& render_pass : frame.render_pass_list) {
+ // Skip the render_pass if the transform is not invertible (i.e. it will not
+ // be able to receive events).
+ gfx::Transform transform_from_root_target;
+ if (!render_pass->transform_to_root_target.GetInverse(
+ &transform_from_root_target)) {
+ continue;
+ }
+
+ for (const DrawQuad* quad : render_pass->quad_list) {
+ if (quad->material == DrawQuad::SURFACE_CONTENT) {
+ const SurfaceDrawQuad* surface_quad =
+ SurfaceDrawQuad::MaterialCast(quad);
+
+ // Skip the quad if the FrameSinkId between fallback and primary is not
+ // the same, because we don't know which FrameSinkId would be used to
+ // draw this quad.
+ if (surface_quad->fallback_surface_id.has_value() &&
+ surface_quad->fallback_surface_id->frame_sink_id() !=
+ surface_quad->primary_surface_id.frame_sink_id()) {
+ continue;
+ }
+
+ // Skip the quad if the transform is not invertible (i.e. it will not
+ // be able to receive events).
+ gfx::Transform target_to_quad_transform;
+ if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
+ &target_to_quad_transform)) {
+ continue;
+ }
+
+ hit_test_region_list.regions.emplace_back();
+ HitTestRegion* hit_test_region = &hit_test_region_list.regions.back();
+ hit_test_region->frame_sink_id =
+ surface_quad->primary_surface_id.frame_sink_id();
+ hit_test_region->flags = HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestChildSurface;
+ hit_test_region->rect = surface_quad->rect;
+ hit_test_region->transform =
+ target_to_quad_transform * transform_from_root_target;
+ }
+ }
+ }
+ return hit_test_region_list;
+}
+
void DirectLayerTreeFrameSink::SubmitCompositorFrame(CompositorFrame frame) {
DCHECK(frame.metadata.begin_frame_ack.has_damage);
DCHECK_LE(BeginFrameArgs::kStartingFrameNumber,
frame.metadata.begin_frame_ack.sequence_number);
- if (!local_surface_id_.is_valid() ||
- frame.size_in_pixels() != last_swap_frame_size_ ||
+ if (frame.size_in_pixels() != last_swap_frame_size_ ||
frame.device_scale_factor() != device_scale_factor_) {
- local_surface_id_ = parent_local_surface_id_allocator_.GenerateId();
+ parent_local_surface_id_allocator_.GenerateId();
last_swap_frame_size_ = frame.size_in_pixels();
device_scale_factor_ = frame.device_scale_factor();
- display_->SetLocalSurfaceId(local_surface_id_, device_scale_factor_);
+ display_->SetLocalSurfaceId(
+ parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(),
+ device_scale_factor_);
}
- auto hit_test_region_list = CreateHitTestData(frame);
- support_->SubmitCompositorFrame(local_surface_id_, std::move(frame),
- std::move(hit_test_region_list));
+ HitTestRegionList hit_test_region_list = CreateHitTestData(frame);
+ support_->SubmitCompositorFrame(
+ parent_local_surface_id_allocator_.GetCurrentLocalSurfaceId(),
+ std::move(frame), std::move(hit_test_region_list));
}
void DirectLayerTreeFrameSink::DidNotProduceFrame(const BeginFrameAck& ack) {
@@ -153,6 +208,12 @@ void DirectLayerTreeFrameSink::DisplayDidReceiveCALayerParams(
display_client_->OnDisplayReceivedCALayerParams(ca_layer_params);
}
+void DirectLayerTreeFrameSink::DidSwapAfterSnapshotRequestReceived(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+ // TODO(samans): Implement this method once the plumbing for latency info also
+ // works for non-OOP-D.
+}
+
void DirectLayerTreeFrameSink::DidReceiveCompositorFrameAck(
const std::vector<ReturnedResource>& resources) {
// Submitting a CompositorFrame can synchronously draw and dispatch a frame
@@ -204,57 +265,4 @@ void DirectLayerTreeFrameSink::OnContextLost() {
// The display will be listening for OnContextLost(). Do nothing here.
}
-mojom::HitTestRegionListPtr DirectLayerTreeFrameSink::CreateHitTestData(
- const CompositorFrame& frame) const {
- auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->flags =
- mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine;
- hit_test_region_list->bounds.set_size(frame.size_in_pixels());
-
- for (const auto& render_pass : frame.render_pass_list) {
- // Skip the render_pass if the transform is not invertible (i.e. it will not
- // be able to receive events).
- gfx::Transform transform_from_root_target;
- if (!render_pass->transform_to_root_target.GetInverse(
- &transform_from_root_target)) {
- continue;
- }
-
- for (const DrawQuad* quad : render_pass->quad_list) {
- if (quad->material == DrawQuad::SURFACE_CONTENT) {
- const SurfaceDrawQuad* surface_quad =
- SurfaceDrawQuad::MaterialCast(quad);
-
- // Skip the quad if the FrameSinkId between fallback and primary is not
- // the same, because we don't know which FrameSinkId would be used to
- // draw this quad.
- if (surface_quad->fallback_surface_id.has_value() &&
- surface_quad->fallback_surface_id->frame_sink_id() !=
- surface_quad->primary_surface_id.frame_sink_id()) {
- continue;
- }
-
- // Skip the quad if the transform is not invertible (i.e. it will not
- // be able to receive events).
- gfx::Transform target_to_quad_transform;
- if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
- &target_to_quad_transform)) {
- continue;
- }
-
- auto hit_test_region = mojom::HitTestRegion::New();
- hit_test_region->frame_sink_id =
- surface_quad->primary_surface_id.frame_sink_id();
- hit_test_region->flags = mojom::kHitTestMouse | mojom::kHitTestTouch |
- mojom::kHitTestChildSurface;
- hit_test_region->rect = surface_quad->rect;
- hit_test_region->transform =
- target_to_quad_transform * transform_from_root_target;
- hit_test_region_list->regions.push_back(std::move(hit_test_region));
- }
- }
- }
- return hit_test_region_list;
-}
-
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h
index 1bdfcf37560..a37812702df 100644
--- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h
+++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink.h
@@ -6,6 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_DIRECT_LAYER_TREE_FRAME_SINK_H_
#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "cc/trees/layer_tree_frame_sink.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
@@ -16,14 +17,10 @@
#include "services/viz/privileged/interfaces/compositing/display_private.mojom.h"
#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
-namespace cc {
-class LocalSurfaceIdAllocator;
-class FrameSinkManagerImpl;
-} // namespace cc
-
namespace viz {
class CompositorFrameSinkSupportManager;
class Display;
+class FrameSinkManagerImpl;
// This class submits compositor frames to an in-process Display, with the
// client's frame being the root surface of the Display.
@@ -45,7 +42,6 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
scoped_refptr<RasterContextProvider> worker_context_provider,
scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- SharedBitmapManager* shared_bitmap_manager,
bool use_viz_hit_test);
~DirectLayerTreeFrameSink() override;
@@ -65,6 +61,8 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
void DisplayDidDrawAndSwap() override;
void DisplayDidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) override;
+ void DidSwapAfterSnapshotRequestReceived(
+ const std::vector<ui::LatencyInfo>& latency_info) override;
private:
// mojom::CompositorFrameSinkClient implementation:
@@ -86,8 +84,6 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
// ContextLostObserver implementation:
void OnContextLost() override;
- mojom::HitTestRegionListPtr CreateHitTestData(
- const CompositorFrame& frame) const;
void DidReceiveCompositorFrameAckInternal(
const std::vector<ReturnedResource>& resources);
@@ -97,7 +93,6 @@ class VIZ_SERVICE_EXPORT DirectLayerTreeFrameSink
std::unique_ptr<CompositorFrameSinkSupport> support_;
const FrameSinkId frame_sink_id_;
- LocalSurfaceId local_surface_id_;
CompositorFrameSinkSupportManager* const support_manager_;
FrameSinkManagerImpl* frame_sink_manager_;
ParentLocalSurfaceIdAllocator parent_local_surface_id_allocator_;
diff --git a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
index 2ab44fe66c1..26f1c30b484 100644
--- a/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/direct_layer_tree_frame_sink_unittest.cc
@@ -86,7 +86,7 @@ class DirectLayerTreeFrameSinkTest : public testing::Test {
layer_tree_frame_sink_ = std::make_unique<TestDirectLayerTreeFrameSink>(
kArbitraryFrameSinkId, &support_manager_, &frame_sink_manager_,
display_.get(), nullptr /* display_client */, context_provider_,
- nullptr, task_runner_, &gpu_memory_buffer_manager_, &bitmap_manager_,
+ nullptr, task_runner_, &gpu_memory_buffer_manager_,
false /* use_viz_hit_test */);
layer_tree_frame_sink_->BindToClient(&layer_tree_frame_sink_client_);
display_->Resize(display_size_);
@@ -157,21 +157,6 @@ TEST_F(DirectLayerTreeFrameSinkTest, NoDamageDoesNotTriggerSwapBuffers) {
EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
}
-TEST_F(DirectLayerTreeFrameSinkTest, SuspendedDoesNotTriggerSwapBuffers) {
- SwapBuffersWithDamage(display_rect_);
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
- display_output_surface_->set_suspended_for_recycle(true);
- task_runner_->RunUntilIdle();
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
- SwapBuffersWithDamage(display_rect_);
- task_runner_->RunUntilIdle();
- EXPECT_EQ(1u, display_output_surface_->num_sent_frames());
- display_output_surface_->set_suspended_for_recycle(false);
- SwapBuffersWithDamage(display_rect_);
- task_runner_->RunUntilIdle();
- EXPECT_EQ(2u, display_output_surface_->num_sent_frames());
-}
-
// Test that hit_test_region_list are created correctly for the browser.
TEST_F(DirectLayerTreeFrameSinkTest, HitTestRegionList) {
RenderPassList pass_list;
@@ -200,7 +185,9 @@ TEST_F(DirectLayerTreeFrameSinkTest, HitTestRegionList) {
display_.get(), display_->CurrentSurfaceId().frame_sink_id());
EXPECT_TRUE(hit_test_region_list);
EXPECT_EQ(display_rect_, hit_test_region_list->bounds);
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine,
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine,
hit_test_region_list->flags);
EXPECT_FALSE(hit_test_region_list->regions.size());
@@ -276,18 +263,21 @@ TEST_F(DirectLayerTreeFrameSinkTest, HitTestRegionList) {
display_.get(), display_->CurrentSurfaceId().frame_sink_id());
EXPECT_TRUE(hit_test_region_list1);
EXPECT_EQ(display_rect_, hit_test_region_list1->bounds);
- EXPECT_EQ(mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestMine,
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestMine,
hit_test_region_list1->flags);
EXPECT_EQ(1u, hit_test_region_list1->regions.size());
EXPECT_EQ(child_surface_id.frame_sink_id(),
- hit_test_region_list1->regions[0]->frame_sink_id);
- EXPECT_EQ(
- mojom::kHitTestMouse | mojom::kHitTestTouch | mojom::kHitTestChildSurface,
- hit_test_region_list1->regions[0]->flags);
- EXPECT_EQ(gfx::Rect(20, 20), hit_test_region_list1->regions[0]->rect);
+ hit_test_region_list1->regions[0].frame_sink_id);
+ EXPECT_EQ(HitTestRegionFlags::kHitTestMouse |
+ HitTestRegionFlags::kHitTestTouch |
+ HitTestRegionFlags::kHitTestChildSurface,
+ hit_test_region_list1->regions[0].flags);
+ EXPECT_EQ(gfx::Rect(20, 20), hit_test_region_list1->regions[0].rect);
gfx::Transform transform2_inverse;
EXPECT_TRUE(transform2.GetInverse(&transform2_inverse));
- EXPECT_EQ(transform2_inverse, hit_test_region_list1->regions[0]->transform);
+ EXPECT_EQ(transform2_inverse, hit_test_region_list1->regions[0].transform);
}
} // namespace
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index ac084ea4666..bb147945b45 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -144,11 +144,13 @@ void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
std::move(params->external_begin_frame_controller_client)));
}
+ mojom::DisplayClientPtr display_client(std::move(params->display_client));
+
std::unique_ptr<SyntheticBeginFrameSource> begin_frame_source;
auto display = display_provider_->CreateDisplay(
params->frame_sink_id, params->widget, params->gpu_compositing,
- external_begin_frame_controller.get(), params->renderer_settings,
- &begin_frame_source);
+ display_client.get(), external_begin_frame_controller.get(),
+ params->renderer_settings, &begin_frame_source);
// Creating display failed. Drop the CompositorFrameSink message pipes here
// and let host send a new request, potential with a different compositing
@@ -164,8 +166,7 @@ void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
std::move(params->compositor_frame_sink),
mojom::CompositorFrameSinkClientPtr(
std::move(params->compositor_frame_sink_client)),
- std::move(params->display_private),
- mojom::DisplayClientPtr(std::move(params->display_client)));
+ std::move(params->display_private), std::move(display_client));
}
void FrameSinkManagerImpl::CreateCompositorFrameSink(
@@ -352,25 +353,10 @@ void FrameSinkManagerImpl::OnSurfaceDamageExpected(const SurfaceId& surface_id,
void FrameSinkManagerImpl::OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
- if (client_) {
- client_->OnAggregatedHitTestRegionListUpdated(
- frame_sink_id, std::move(active_handle), active_handle_size,
- std::move(idle_handle), idle_handle_size);
- }
-}
-
-void FrameSinkManagerImpl::SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) {
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (client_) {
- client_->SwitchActiveAggregatedHitTestRegionList(frame_sink_id,
- active_handle_index);
+ client_->OnAggregatedHitTestRegionListUpdated(frame_sink_id, hit_test_data);
}
}
@@ -526,7 +512,7 @@ bool FrameSinkManagerImpl::ChildContains(
void FrameSinkManagerImpl::SubmitHitTestRegionList(
const SurfaceId& surface_id,
uint64_t frame_index,
- mojom::HitTestRegionListPtr hit_test_region_list) {
+ base::Optional<HitTestRegionList> hit_test_region_list) {
hit_test_manager_.SubmitHitTestRegionList(surface_id, frame_index,
std::move(hit_test_region_list));
}
diff --git a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index e4821698459..7f2352e9367 100644
--- a/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/chromium/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -16,6 +16,8 @@
#include "base/containers/unique_ptr_adapters.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/optional.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_checker.h"
#include "components/viz/common/constants.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
@@ -112,13 +114,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
// HitTestAggregatorDelegate implementation:
void OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) override;
- void SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) override;
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) override;
// CompositorFrameSinkSupport, hierarchy, and BeginFrameSource can be
// registered and unregistered in any order with respect to each other.
@@ -152,7 +148,7 @@ class VIZ_SERVICE_EXPORT FrameSinkManagerImpl
void SubmitHitTestRegionList(
const SurfaceId& surface_id,
uint64_t frame_index,
- mojom::HitTestRegionListPtr hit_test_region_list);
+ base::Optional<HitTestRegionList> hit_test_region_list);
// Instantiates |video_detector_| for tests where we simulate the passage of
// time.
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index 731741e3bec..654022b75a3 100644
--- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -103,7 +103,7 @@ void RootCompositorFrameSinkImpl::SetWantsAnimateOnlyBeginFrames() {
void RootCompositorFrameSinkImpl::SubmitCompositorFrame(
const LocalSurfaceId& local_surface_id,
CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list,
+ base::Optional<HitTestRegionList> hit_test_region_list,
uint64_t submit_time) {
// Update display when size or local surface id changes.
if (support_->last_activated_local_surface_id() != local_surface_id) {
@@ -112,7 +112,8 @@ void RootCompositorFrameSinkImpl::SubmitCompositorFrame(
}
const auto result = support_->MaybeSubmitCompositorFrame(
- local_surface_id, std::move(frame), std::move(hit_test_region_list));
+ local_surface_id, std::move(frame), std::move(hit_test_region_list),
+ SubmitCompositorFrameSyncCallback());
if (result == CompositorFrameSinkSupport::ACCEPTED)
return;
@@ -125,6 +126,15 @@ void RootCompositorFrameSinkImpl::SubmitCompositorFrame(
OnClientConnectionLost();
}
+void RootCompositorFrameSinkImpl::SubmitCompositorFrameSync(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time,
+ SubmitCompositorFrameSyncCallback callback) {
+ NOTIMPLEMENTED();
+}
+
void RootCompositorFrameSinkImpl::DidNotProduceFrame(
const BeginFrameAck& begin_frame_ack) {
support_->DidNotProduceFrame(begin_frame_ack);
@@ -167,6 +177,11 @@ void RootCompositorFrameSinkImpl::DisplayDidReceiveCALayerParams(
display_client_->OnDisplayReceivedCALayerParams(ca_layer_params);
}
+void RootCompositorFrameSinkImpl::DidSwapAfterSnapshotRequestReceived(
+ const std::vector<ui::LatencyInfo>& latency_info) {
+ display_client_->DidSwapAfterSnapshotRequestReceived(latency_info);
+}
+
void RootCompositorFrameSinkImpl::DisplayDidDrawAndSwap() {}
void RootCompositorFrameSinkImpl::OnClientConnectionLost() {
diff --git a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
index c5f72f85568..35295866214 100644
--- a/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
+++ b/chromium/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -55,14 +55,21 @@ class RootCompositorFrameSinkImpl : public mojom::CompositorFrameSink,
// mojom::CompositorFrameSink:
void SetNeedsBeginFrame(bool needs_begin_frame) override;
void SetWantsAnimateOnlyBeginFrames() override;
- void SubmitCompositorFrame(const LocalSurfaceId& local_surface_id,
- CompositorFrame frame,
- mojom::HitTestRegionListPtr hit_test_region_list,
- uint64_t submit_time) override;
+ void SubmitCompositorFrame(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time) override;
void DidNotProduceFrame(const BeginFrameAck& begin_frame_ack) override;
void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
const SharedBitmapId& id) override;
void DidDeleteSharedBitmap(const SharedBitmapId& id) override;
+ void SubmitCompositorFrameSync(
+ const LocalSurfaceId& local_surface_id,
+ CompositorFrame frame,
+ base::Optional<HitTestRegionList> hit_test_region_list,
+ uint64_t submit_time,
+ SubmitCompositorFrameSyncCallback callback) override;
private:
// DisplayClient:
@@ -72,6 +79,8 @@ class RootCompositorFrameSinkImpl : public mojom::CompositorFrameSink,
void DisplayDidDrawAndSwap() override;
void DisplayDidReceiveCALayerParams(
const gfx::CALayerParams& ca_layer_params) override;
+ void DidSwapAfterSnapshotRequestReceived(
+ const std::vector<ui::LatencyInfo>& latency_info) override;
void OnClientConnectionLost();
diff --git a/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc b/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
index 860743d07bc..8b83cea05dd 100644
--- a/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/surface_synchronization_unittest.cc
@@ -868,16 +868,14 @@ TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) {
const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ ui::DISPLAY_COMPOSITOR_RECEIVED_FRAME_COMPONENT;
const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
// Submit a frame with latency info
ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+ info.AddLatencyNumber(latency_type1, latency_id1);
CompositorFrameBuilder builder;
builder.AddDefaultRenderPass();
@@ -897,7 +895,7 @@ TEST_F(SurfaceSynchronizationTest, LimitLatencyInfo) {
// Submit another frame with some other latency info and a different
// LocalSurfaceId.
ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+ info2.AddLatencyNumber(latency_type2, latency_id2);
builder.AddDefaultRenderPass();
for (int i = 0; i < 60; ++i)
@@ -927,16 +925,14 @@ TEST_F(SurfaceSynchronizationTest,
const SurfaceId parent_id1 = MakeSurfaceId(kParentFrameSink, 1);
const SurfaceId parent_id2 = MakeSurfaceId(kParentFrameSink, 2);
const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT;
const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
// Submit a frame with latency info
ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+ info.AddLatencyNumber(latency_type1, latency_id1);
CompositorFrame frame = CompositorFrameBuilder()
.AddDefaultRenderPass()
@@ -955,7 +951,7 @@ TEST_F(SurfaceSynchronizationTest,
// Submit another frame with some other latency info and a different
// LocalSurfaceId.
ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+ info2.AddLatencyNumber(latency_type2, latency_id2);
CompositorFrame frame2 = CompositorFrameBuilder()
.AddDefaultRenderPass()
@@ -987,7 +983,6 @@ TEST_F(SurfaceSynchronizationTest,
ui::LatencyInfo::LatencyComponent comp1;
EXPECT_TRUE(
aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
EXPECT_TRUE(
aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr));
EXPECT_TRUE(aggregated_latency_info.FindLatency(
@@ -1004,16 +999,14 @@ TEST_F(SurfaceSynchronizationTest,
const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT;
const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
// Submit a frame with no unresolved dependecy.
ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+ info.AddLatencyNumber(latency_type1, latency_id1);
CompositorFrame frame = MakeDefaultCompositorFrame();
frame.metadata.latency_info.push_back(info);
@@ -1023,7 +1016,7 @@ TEST_F(SurfaceSynchronizationTest,
// Submit a frame with unresolved dependencies.
ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+ info2.AddLatencyNumber(latency_type2, latency_id2);
CompositorFrame frame2 = MakeCompositorFrame(
{child_id}, empty_surface_ids(), std::vector<TransferableResource>());
@@ -1065,7 +1058,6 @@ TEST_F(SurfaceSynchronizationTest,
ui::LatencyInfo::LatencyComponent comp1;
EXPECT_TRUE(
aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
EXPECT_TRUE(
aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr));
EXPECT_TRUE(aggregated_latency_info.FindLatency(
@@ -1082,16 +1074,14 @@ TEST_F(SurfaceSynchronizationTest,
const SurfaceId child_id = MakeSurfaceId(kChildFrameSink1, 1);
const ui::LatencyComponentType latency_type1 =
- ui::BROWSER_SNAPSHOT_FRAME_NUMBER_COMPONENT;
+ ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT;
const int64_t latency_id1 = 234;
- const int64_t latency_sequence_number1 = 5645432;
const ui::LatencyComponentType latency_type2 = ui::TAB_SHOW_COMPONENT;
const int64_t latency_id2 = 31434351;
- const int64_t latency_sequence_number2 = 663788;
// Submit a frame with no unresolved dependencies.
ui::LatencyInfo info;
- info.AddLatencyNumber(latency_type1, latency_id1, latency_sequence_number1);
+ info.AddLatencyNumber(latency_type1, latency_id1);
CompositorFrame frame = MakeDefaultCompositorFrame();
frame.metadata.latency_info.push_back(info);
@@ -1108,7 +1098,7 @@ TEST_F(SurfaceSynchronizationTest,
// Submit a frame with a new local surface id and with unresolved
// dependencies.
ui::LatencyInfo info2;
- info2.AddLatencyNumber(latency_type2, latency_id2, latency_sequence_number2);
+ info2.AddLatencyNumber(latency_type2, latency_id2);
CompositorFrame frame2 = MakeCompositorFrame(
{child_id}, empty_surface_ids(), std::vector<TransferableResource>());
@@ -1146,7 +1136,6 @@ TEST_F(SurfaceSynchronizationTest,
ui::LatencyInfo::LatencyComponent comp1;
EXPECT_TRUE(
aggregated_latency_info.FindLatency(latency_type1, latency_id1, &comp1));
- EXPECT_EQ(latency_sequence_number1, comp1.sequence_number);
EXPECT_TRUE(
aggregated_latency_info.FindLatency(latency_type2, latency_id2, nullptr));
EXPECT_TRUE(aggregated_latency_info.FindLatency(
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/OWNERS b/chromium/components/viz/service/frame_sinks/video_capture/OWNERS
index 02bdb39030f..e837b5fcb0d 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/OWNERS
+++ b/chromium/components/viz/service/frame_sinks/video_capture/OWNERS
@@ -1 +1,3 @@
miu@chromium.org
+
+# COMPONENT: Internals>Media>ScreenCapture
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h b/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h
index 908d2756891..ed9e14e507f 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h
@@ -16,6 +16,7 @@ class Rect;
namespace viz {
+class CompositorFrameMetadata;
class CopyOutputRequest;
class LocalSurfaceId;
@@ -35,9 +36,11 @@ class CapturableFrameSink {
// |damage_rect| being the region within that has changed (never empty).
// |expected_display_time| indicates when the content change was expected to
// appear on the Display.
- virtual void OnFrameDamaged(const gfx::Size& frame_size,
- const gfx::Rect& damage_rect,
- base::TimeTicks expected_display_time) = 0;
+ virtual void OnFrameDamaged(
+ const gfx::Size& frame_size,
+ const gfx::Rect& damage_rect,
+ base::TimeTicks expected_display_time,
+ const CompositorFrameMetadata& frame_metadata) = 0;
};
virtual ~CapturableFrameSink() = default;
@@ -59,6 +62,10 @@ class CapturableFrameSink {
virtual void RequestCopyOfOutput(
const LocalSurfaceId& local_surface_id,
std::unique_ptr<CopyOutputRequest> request) = 0;
+
+ // Returns the CompositorFrameMetadata of the last activated CompositorFrame.
+ // Return null if no CompositorFrame has activated yet.
+ virtual const CompositorFrameMetadata* GetLastActivatedFrameMetadata() = 0;
};
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
index c93861ff014..7a8c0af9c0d 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.cc
@@ -311,13 +311,15 @@ void FrameSinkVideoCapturerImpl::RefreshSoon() {
}
MaybeCaptureFrame(VideoCaptureOracle::kRefreshRequest,
- gfx::Rect(oracle_.source_size()), clock_->NowTicks());
+ gfx::Rect(oracle_.source_size()), clock_->NowTicks(),
+ *resolved_target_->GetLastActivatedFrameMetadata());
}
void FrameSinkVideoCapturerImpl::OnFrameDamaged(
const gfx::Size& frame_size,
const gfx::Rect& damage_rect,
- base::TimeTicks expected_display_time) {
+ base::TimeTicks expected_display_time,
+ const CompositorFrameMetadata& frame_metadata) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!frame_size.IsEmpty());
DCHECK(!damage_rect.IsEmpty());
@@ -332,13 +334,14 @@ void FrameSinkVideoCapturerImpl::OnFrameDamaged(
}
MaybeCaptureFrame(VideoCaptureOracle::kCompositorUpdate, damage_rect,
- expected_display_time);
+ expected_display_time, frame_metadata);
}
void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
VideoCaptureOracle::Event event,
const gfx::Rect& damage_rect,
- base::TimeTicks event_time) {
+ base::TimeTicks event_time,
+ const CompositorFrameMetadata& frame_metadata) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(resolved_target_);
@@ -436,6 +439,14 @@ void FrameSinkVideoCapturerImpl::MaybeCaptureFrame(
metadata->SetDouble(VideoFrameMetadata::FRAME_RATE,
1.0 / oracle_.min_capture_period().InSecondsF());
metadata->SetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, event_time);
+ metadata->SetDouble(VideoFrameMetadata::DEVICE_SCALE_FACTOR,
+ frame_metadata.device_scale_factor);
+ metadata->SetDouble(VideoFrameMetadata::PAGE_SCALE_FACTOR,
+ frame_metadata.page_scale_factor);
+ metadata->SetDouble(VideoFrameMetadata::ROOT_SCROLL_OFFSET_X,
+ frame_metadata.root_scroll_offset.x());
+ metadata->SetDouble(VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y,
+ frame_metadata.root_scroll_offset.y());
oracle_.RecordCapture(utilization);
const int64_t frame_number = next_capture_frame_number_++;
@@ -542,18 +553,11 @@ void FrameSinkVideoCapturerImpl::DidCopyFrame(
frame = nullptr;
}
} else {
- // TODO(samans): Avoid doing an extra copy by implementing a method similar
- // to ReadI420Planes() that copies directly from GPU memory into shared
- // memory. https://crbug.com/822264
+ int stride = frame->stride(VideoFrame::kARGBPlane);
DCHECK_EQ(media::PIXEL_FORMAT_ARGB, pixel_format_);
- const SkBitmap& bitmap = result->AsSkBitmap();
- if (bitmap.readyToDraw()) {
- SkImageInfo image_info = SkImageInfo::MakeN32(
- bitmap.width(), bitmap.height(), kPremul_SkAlphaType);
- const int stride = frame->stride(VideoFrame::kARGBPlane);
- uint8_t* const pixels = frame->visible_data(VideoFrame::kARGBPlane) +
- content_rect.y() * stride + content_rect.x() * 4;
- bitmap.readPixels(image_info, pixels, stride, 0, 0);
+ uint8_t* const pixels = frame->visible_data(VideoFrame::kARGBPlane) +
+ content_rect.y() * stride + content_rect.x() * 4;
+ if (result->ReadRGBAPlane(pixels, stride)) {
media::LetterboxVideoFrame(
frame.get(), gfx::Rect(content_rect.origin(),
AdjustSizeForPixelFormat(result->size())));
@@ -643,7 +647,6 @@ void FrameSinkVideoCapturerImpl::MaybeDeliverFrame(
info->timestamp = frame->timestamp();
info->metadata = frame->metadata()->GetInternalValues().Clone();
info->pixel_format = frame->format();
- info->storage_type = media::VideoPixelStorage::CPU;
info->coded_size = frame->coded_size();
info->visible_rect = frame->visible_rect();
const gfx::Rect update_rect = frame->visible_rect();
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
index 8dbfb0525ee..c1c552d4b51 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl.h
@@ -17,6 +17,8 @@
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "base/unguessable_token.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/quads/compositor_frame_metadata.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/service/frame_sinks/video_capture/capturable_frame_sink.h"
#include "components/viz/service/frame_sinks/video_capture/in_flight_frame_delivery.h"
@@ -27,6 +29,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/viz/privileged/interfaces/compositing/frame_sink_video_capture.mojom.h"
#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace gfx {
class Size;
@@ -156,14 +159,16 @@ class VIZ_SERVICE_EXPORT FrameSinkVideoCapturerImpl final
// CapturableFrameSink::Client implementation:
void OnFrameDamaged(const gfx::Size& frame_size,
const gfx::Rect& damage_rect,
- base::TimeTicks target_display_time) final;
+ base::TimeTicks target_display_time,
+ const CompositorFrameMetadata& frame_metadata) final;
// Consults the VideoCaptureOracle to decide whether to capture a frame,
// then ensures prerequisites are met before initiating the capture: that
// there is a consumer present and that the pipeline is not already full.
void MaybeCaptureFrame(media::VideoCaptureOracle::Event event,
const gfx::Rect& damage_rect,
- base::TimeTicks event_time);
+ base::TimeTicks event_time,
+ const CompositorFrameMetadata& frame_metadata);
// Extracts the image data from the copy output |result|, populating the
// |content_rect| region of a [possibly letterboxed] video |frame|.
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
index e5efebcfac0..babe29ca1b1 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/frame_sink_video_capturer_impl_unittest.cc
@@ -39,6 +39,29 @@ using testing::Return;
namespace viz {
namespace {
+// Returns true if |frame|'s device scale factor, page scale factor and root
+// scroll offset are equal to the expected values.
+bool CompareVarsInCompositorFrameMetadata(
+ const VideoFrame& frame,
+ float device_scale_factor,
+ float page_scale_factor,
+ const gfx::Vector2dF& root_scroll_offset) {
+ double dsf, psf, rso_x, rso_y;
+ bool valid = true;
+
+ valid &= frame.metadata()->GetDouble(
+ media::VideoFrameMetadata::DEVICE_SCALE_FACTOR, &dsf);
+ valid &= frame.metadata()->GetDouble(
+ media::VideoFrameMetadata::PAGE_SCALE_FACTOR, &psf);
+ valid &= frame.metadata()->GetDouble(
+ media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_X, &rso_x);
+ valid &= frame.metadata()->GetDouble(
+ media::VideoFrameMetadata::ROOT_SCROLL_OFFSET_Y, &rso_y);
+
+ return valid && dsf == device_scale_factor && psf == page_scale_factor &&
+ gfx::Vector2dF(rso_x, rso_y) == root_scroll_offset;
+}
+
// Dummy frame sink ID.
constexpr FrameSinkId kFrameSinkId = FrameSinkId(1, 1);
@@ -52,6 +75,10 @@ constexpr gfx::Size kSourceSize = gfx::Size(100, 100);
// The size of the VideoFrames produced by the capturer.
constexpr gfx::Size kCaptureSize = gfx::Size(32, 18);
+constexpr float kDefaultDeviceScaleFactor = 1.f;
+constexpr float kDefaultPageScaleFactor = 1.f;
+constexpr gfx::Vector2dF kDefaultRootScrollOffset = gfx::Vector2dF(0, 0);
+
// The location of the letterboxed content within each VideoFrame. All pixels
// outside of this region should be black.
constexpr gfx::Rect kContentRect = gfx::Rect(6, 0, 18, 18);
@@ -182,6 +209,12 @@ class SolidColorI420Result : public CopyOutputResult {
class FakeCapturableFrameSink : public CapturableFrameSink {
public:
+ FakeCapturableFrameSink() {
+ metadata_.root_scroll_offset = kDefaultRootScrollOffset;
+ metadata_.page_scale_factor = kDefaultPageScaleFactor;
+ metadata_.device_scale_factor = kDefaultDeviceScaleFactor;
+ }
+
Client* attached_client() const { return client_; }
void AttachCaptureClient(Client* client) override {
@@ -216,6 +249,14 @@ class FakeCapturableFrameSink : public CapturableFrameSink {
std::move(request), std::move(result)));
}
+ const CompositorFrameMetadata* GetLastActivatedFrameMetadata() override {
+ return &metadata_;
+ }
+
+ void set_metadata(const CompositorFrameMetadata& metadata) {
+ metadata_ = metadata.Clone();
+ }
+
void SetCopyOutputColor(YUVColor color) { color_ = color; }
int num_copy_results() const { return results_.size(); }
@@ -229,6 +270,7 @@ class FakeCapturableFrameSink : public CapturableFrameSink {
private:
CapturableFrameSink::Client* client_ = nullptr;
YUVColor color_ = {0xde, 0xad, 0xbf};
+ CompositorFrameMetadata metadata_;
std::vector<base::OnceClosure> results_;
};
@@ -335,9 +377,20 @@ class FrameSinkVideoCapturerTest : public testing::Test {
task_runner_->FastForwardBy(GetNextVsync() - task_runner_->NowTicks());
}
- void NotifyFrameDamaged() {
+ void NotifyFrameDamaged(
+ float device_scale_factor = kDefaultDeviceScaleFactor,
+ float page_scale_factor = kDefaultPageScaleFactor,
+ gfx::Vector2dF root_scroll_offset = kDefaultRootScrollOffset) {
+ CompositorFrameMetadata metadata;
+
+ metadata.device_scale_factor = device_scale_factor;
+ metadata.page_scale_factor = page_scale_factor;
+ metadata.root_scroll_offset = root_scroll_offset;
+
+ frame_sink_.set_metadata(metadata);
+
capturer_.OnFrameDamaged(kSourceSize, gfx::Rect(kSourceSize),
- GetNextVsync());
+ GetNextVsync(), metadata);
}
void NotifyTargetWentAway() {
@@ -363,7 +416,7 @@ class FrameSinkVideoCapturerTest : public testing::Test {
};
// Tests that the capturer attaches to a frame sink immediately, in the case
-// where the frame sink was already known by the manger.
+// where the frame sink was already known by the manager.
TEST_F(FrameSinkVideoCapturerTest, ResolvesTargetImmediately) {
EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
.WillRepeatedly(Return(&frame_sink_));
@@ -857,4 +910,65 @@ TEST_F(FrameSinkVideoCapturerTest, EventuallySendsARefreshFrame) {
StopCapture();
}
+// Tests that CompositorFrameMetadata variables (|device_scale_factor|,
+// |page_scale_factor| and |root_scroll_offset|) are sent along with each frame,
+// and refreshes cause variables of the cached CompositorFrameMetadata
+// (|last_frame_metadata|) to be used.
+TEST_F(FrameSinkVideoCapturerTest, CompositorFrameMetadataReachesConsumer) {
+ EXPECT_CALL(frame_sink_manager_, FindCapturableFrameSink(kFrameSinkId))
+ .WillRepeatedly(Return(&frame_sink_));
+ capturer_.ChangeTarget(kFrameSinkId);
+
+ MockConsumer consumer;
+ // Initial refresh frame for starting capture, plus later refresh.
+ const int num_refresh_frames = 2;
+ const int num_update_frames = 1;
+ EXPECT_CALL(consumer, OnFrameCapturedMock(_, _, _))
+ .Times(num_refresh_frames + num_update_frames);
+ EXPECT_CALL(consumer, OnTargetLost(_)).Times(0);
+ EXPECT_CALL(consumer, OnStopped()).Times(1);
+ StartCapture(&consumer);
+
+ // With the start, an immediate refresh occurred. Simulate a copy result.
+ // Expect to see the refresh frame delivered to the consumer, along with
+ // default metadata values.
+ int cur_frame_index = 0, expected_frames_count = 1;
+ frame_sink_.SendCopyOutputResult(cur_frame_index);
+ EXPECT_EQ(expected_frames_count, consumer.num_frames_received());
+ EXPECT_TRUE(CompareVarsInCompositorFrameMetadata(
+ *(consumer.TakeFrame(cur_frame_index)), kDefaultDeviceScaleFactor,
+ kDefaultPageScaleFactor, kDefaultRootScrollOffset));
+ consumer.SendDoneNotification(cur_frame_index);
+
+ // The metadata used to signal a frame damage and verify that it reaches the
+ // consumer.
+ const float kNewDeviceScaleFactor = 3.5;
+ const float kNewPageScaleFactor = 1.5;
+ const gfx::Vector2dF kNewRootScrollOffset = gfx::Vector2dF(100, 200);
+
+ // Notify frame damage with new metadata, and expect that the refresh frame
+ // is delivered to the consumer with this new metadata.
+ AdvanceClockToNextVsync();
+ NotifyFrameDamaged(kNewDeviceScaleFactor, kNewPageScaleFactor,
+ kNewRootScrollOffset);
+ frame_sink_.SendCopyOutputResult(++cur_frame_index);
+ EXPECT_EQ(++expected_frames_count, consumer.num_frames_received());
+ EXPECT_TRUE(CompareVarsInCompositorFrameMetadata(
+ *(consumer.TakeFrame(cur_frame_index)), kNewDeviceScaleFactor,
+ kNewPageScaleFactor, kNewRootScrollOffset));
+ consumer.SendDoneNotification(cur_frame_index);
+
+ // Request a refresh frame. Because the refresh request was made just after
+ // the last frame capture, the refresh retry timer should be started.
+ // Expect that the refresh frame is delivered to the consumer with the same
+ // metadata from the previous frame.
+ capturer_.RequestRefreshFrame();
+ AdvanceClockForRefreshTimer();
+ EXPECT_EQ(++expected_frames_count, consumer.num_frames_received());
+ EXPECT_TRUE(CompareVarsInCompositorFrameMetadata(
+ *(consumer.TakeFrame(++cur_frame_index)), kNewDeviceScaleFactor,
+ kNewPageScaleFactor, kNewRootScrollOffset));
+ StopCapture();
+}
+
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
index cb888449836..383a616c7c1 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
+++ b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.cc
@@ -207,10 +207,10 @@ bool InterprocessFramePool::CanLogSharedMemoryFailure() {
}
InterprocessFramePool::PooledBuffer::PooledBuffer() = default;
-InterprocessFramePool::PooledBuffer::PooledBuffer(PooledBuffer&& other) =
- default;
+InterprocessFramePool::PooledBuffer::PooledBuffer(
+ PooledBuffer&& other) noexcept = default;
InterprocessFramePool::PooledBuffer& InterprocessFramePool::PooledBuffer::
-operator=(PooledBuffer&& other) = default;
+operator=(PooledBuffer&& other) noexcept = default;
InterprocessFramePool::PooledBuffer::~PooledBuffer() = default;
} // namespace viz
diff --git a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h
index f75d9214bfe..c1882e16b23 100644
--- a/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h
+++ b/chromium/components/viz/service/frame_sinks/video_capture/interprocess_frame_pool.h
@@ -72,8 +72,8 @@ class VIZ_SERVICE_EXPORT InterprocessFramePool {
mojo::ScopedSharedBufferMapping mapping;
PooledBuffer();
- PooledBuffer(PooledBuffer&&);
- PooledBuffer& operator=(PooledBuffer&&);
+ PooledBuffer(PooledBuffer&&) noexcept;
+ PooledBuffer& operator=(PooledBuffer&&) noexcept;
~PooledBuffer();
};
diff --git a/chromium/components/viz/service/frame_sinks/video_detector.h b/chromium/components/viz/service/frame_sinks/video_detector.h
index 90e240e39cc..c0119ebb240 100644
--- a/chromium/components/viz/service/frame_sinks/video_detector.h
+++ b/chromium/components/viz/service/frame_sinks/video_detector.h
@@ -7,6 +7,7 @@
#include <unordered_map>
+#include "base/sequenced_task_runner.h"
#include "base/time/default_tick_clock.h"
#include "base/timer/timer.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.cc b/chromium/components/viz/service/gl/gpu_service_impl.cc
index 811eda2f35b..9beb6b89684 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl.cc
@@ -17,7 +17,6 @@
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/crash/core/common/crash_key.h"
-#include "components/viz/common/gpu/in_process_context_provider.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
#include "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/scheduler.h"
@@ -115,7 +114,10 @@ GpuServiceImpl::GpuServiceImpl(
std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::GpuFeatureInfo& gpu_feature_info,
- const gpu::GpuPreferences& gpu_preferences)
+ const gpu::GpuPreferences& gpu_preferences,
+ const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
+ const base::Optional<gpu::GpuFeatureInfo>&
+ gpu_feature_info_for_hardware_gpu)
: main_runner_(base::ThreadTaskRunnerHandle::Get()),
io_runner_(std::move(io_runner)),
watchdog_thread_(std::move(watchdog_thread)),
@@ -124,6 +126,8 @@ GpuServiceImpl::GpuServiceImpl(
gpu_preferences_(gpu_preferences),
gpu_info_(gpu_info),
gpu_feature_info_(gpu_feature_info),
+ gpu_info_for_hardware_gpu_(gpu_info_for_hardware_gpu),
+ gpu_feature_info_for_hardware_gpu_(gpu_feature_info_for_hardware_gpu),
bindings_(std::make_unique<mojo::BindingSet<mojom::GpuService>>()),
weak_ptr_factory_(this) {
DCHECK(!io_runner_->BelongsToCurrentThread());
@@ -191,7 +195,9 @@ void GpuServiceImpl::InitializeWithHost(
gpu::SyncPointManager* sync_point_manager,
base::WaitableEvent* shutdown_event) {
DCHECK(main_runner_->BelongsToCurrentThread());
- gpu_host->DidInitialize(gpu_info_, gpu_feature_info_);
+ gpu_host->DidInitialize(gpu_info_, gpu_feature_info_,
+ gpu_info_for_hardware_gpu_,
+ gpu_feature_info_for_hardware_gpu_);
gpu_host_ =
mojom::ThreadSafeGpuHostPtr::Create(gpu_host.PassInterface(), io_runner_);
if (!in_host_process()) {
@@ -436,13 +442,15 @@ void GpuServiceImpl::GetVideoMemoryUsageStats(
}
// Currently, this function only supports the Windows platform.
-void GpuServiceImpl::GetGpuSupportedRuntimeVersion() {
+void GpuServiceImpl::GetGpuSupportedRuntimeVersion(
+ GetGpuSupportedRuntimeVersionCallback callback) {
#if defined(OS_WIN)
if (io_runner_->BelongsToCurrentThread()) {
+ auto wrap_callback = WrapCallback(io_runner_, std::move(callback));
main_runner_->PostTask(
FROM_HERE,
base::BindOnce(&GpuServiceImpl::GetGpuSupportedRuntimeVersion,
- weak_ptr_));
+ weak_ptr_, std::move(wrap_callback)));
return;
}
DCHECK(main_runner_->BelongsToCurrentThread());
@@ -453,6 +461,7 @@ void GpuServiceImpl::GetGpuSupportedRuntimeVersion() {
DCHECK(command_line->HasSwitch("disable-gpu-sandbox") || in_host_process());
gpu::RecordGpuSupportedRuntimeVersionHistograms(&gpu_info_);
+ std::move(callback).Run(gpu_info_);
if (!in_host_process()) {
// The unsandboxed GPU process fulfilled its duty. Rest
// in peace.
@@ -535,9 +544,6 @@ void GpuServiceImpl::UpdateGpuInfoPlatform(
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
DCHECK(command_line->HasSwitch("disable-gpu-sandbox") || in_host_process());
- gpu::GetGpuSupportedD3DVersion(&gpu_info_);
- gpu::GetGpuSupportedVulkanVersion(&gpu_info_);
-
// We can continue on shutdown here because we're not writing any critical
// state in this task.
base::PostTaskAndReplyWithResult(
@@ -714,12 +720,13 @@ void GpuServiceImpl::DestroyAllChannels() {
gpu_channel_manager_->DestroyAllChannels();
}
-void GpuServiceImpl::OnBackgrounded() {
+void GpuServiceImpl::OnBackgroundCleanup() {
// Currently only called on Android.
#if defined(OS_ANDROID)
if (io_runner_->BelongsToCurrentThread()) {
main_runner_->PostTask(
- FROM_HERE, base::BindOnce(&GpuServiceImpl::OnBackgrounded, weak_ptr_));
+ FROM_HERE,
+ base::BindOnce(&GpuServiceImpl::OnBackgroundCleanup, weak_ptr_));
return;
}
DVLOG(1) << "GPU: Performing background cleanup";
@@ -729,6 +736,16 @@ void GpuServiceImpl::OnBackgrounded() {
#endif
}
+void GpuServiceImpl::OnBackgrounded() {
+ if (watchdog_thread_)
+ watchdog_thread_->OnBackgrounded();
+}
+
+void GpuServiceImpl::OnForegrounded() {
+ if (watchdog_thread_)
+ watchdog_thread_->OnForegrounded();
+}
+
void GpuServiceImpl::Crash() {
DCHECK(io_runner_->BelongsToCurrentThread());
DVLOG(1) << "GPU: Simulating GPU crash";
diff --git a/chromium/components/viz/service/gl/gpu_service_impl.h b/chromium/components/viz/service/gl/gpu_service_impl.h
index a29e320f906..15c1bb76964 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl.h
+++ b/chromium/components/viz/service/gl/gpu_service_impl.h
@@ -62,7 +62,10 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
std::unique_ptr<gpu::GpuWatchdogThread> watchdog,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::GpuFeatureInfo& gpu_feature_info,
- const gpu::GpuPreferences& gpu_preferences);
+ const gpu::GpuPreferences& gpu_preferences,
+ const base::Optional<gpu::GPUInfo>& gpu_info_for_hardware_gpu,
+ const base::Optional<gpu::GpuFeatureInfo>&
+ gpu_feature_info_for_hardware_gpu);
~GpuServiceImpl() override;
@@ -184,7 +187,8 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void GetVideoMemoryUsageStats(
GetVideoMemoryUsageStatsCallback callback) override;
void RequestCompleteGpuInfo(RequestCompleteGpuInfoCallback callback) override;
- void GetGpuSupportedRuntimeVersion() override;
+ void GetGpuSupportedRuntimeVersion(
+ GetGpuSupportedRuntimeVersionCallback callback) override;
void RequestHDRStatus(RequestHDRStatusCallback callback) override;
void LoadedShader(const std::string& key, const std::string& data) override;
void DestroyingVideoSurface(int32_t surface_id,
@@ -192,7 +196,9 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
void WakeUpGpu() override;
void GpuSwitched() override;
void DestroyAllChannels() override;
+ void OnBackgroundCleanup() override;
void OnBackgrounded() override;
+ void OnForegrounded() override;
void Crash() override;
void Hang() override;
void ThrowJavaException() override;
@@ -226,6 +232,11 @@ class VIZ_SERVICE_EXPORT GpuServiceImpl : public gpu::GpuChannelManagerDelegate,
// Information about general chrome feature support for the GPU.
gpu::GpuFeatureInfo gpu_feature_info_;
+ // What we would have gotten if we haven't fallen back to SwiftShader or
+ // pure software (in the viz case).
+ base::Optional<gpu::GPUInfo> gpu_info_for_hardware_gpu_;
+ base::Optional<gpu::GpuFeatureInfo> gpu_feature_info_for_hardware_gpu_;
+
scoped_refptr<mojom::ThreadSafeGpuHostPtr> gpu_host_;
std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
std::unique_ptr<media::MediaGpuChannelManager> media_gpu_channel_manager_;
diff --git a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
index c36a072fc58..5120ef5d7f1 100644
--- a/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
+++ b/chromium/components/viz/service/gl/gpu_service_impl_unittest.cc
@@ -8,7 +8,6 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "gpu/config/gpu_info.h"
@@ -51,7 +50,8 @@ class GpuServiceTest : public testing::Test {
ASSERT_TRUE(io_thread_.Start());
gpu_service_ = std::make_unique<GpuServiceImpl>(
gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_.task_runner(),
- gpu::GpuFeatureInfo(), gpu::GpuPreferences());
+ gpu::GpuFeatureInfo(), gpu::GpuPreferences(), gpu::GPUInfo(),
+ gpu::GpuFeatureInfo());
}
void TearDown() override {
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
index 11f6db2762d..d598f2cdb57 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.cc
@@ -5,7 +5,7 @@
#include "components/viz/service/hit_test/hit_test_aggregator.h"
#include "base/metrics/histogram_macros.h"
-#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/service/hit_test/hit_test_aggregator_delegate.h"
#include "third_party/skia/include/core/SkMatrix44.h"
@@ -25,78 +25,34 @@ HitTestAggregator::HitTestAggregator(
initial_region_size_(initial_region_size),
incremental_region_size_(initial_region_size),
max_region_size_(max_region_size),
- weak_ptr_factory_(this) {
- AllocateHitTestRegionArray();
-}
+ weak_ptr_factory_(this) {}
HitTestAggregator::~HitTestAggregator() = default;
void HitTestAggregator::Aggregate(const SurfaceId& display_surface_id) {
DCHECK(referenced_child_regions_.empty());
- AppendRoot(display_surface_id);
- referenced_child_regions_.clear();
- Swap();
-}
-
-void HitTestAggregator::GrowRegionList() {
- ResizeHitTestRegionArray(write_size_ + incremental_region_size_);
-}
-
-void HitTestAggregator::Swap() {
- SwapHandles();
- if (!handle_replaced_) {
- delegate_->SwitchActiveAggregatedHitTestRegionList(root_frame_sink_id_,
- active_handle_index_);
- return;
- }
- delegate_->OnAggregatedHitTestRegionListUpdated(
- root_frame_sink_id_,
- read_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
- read_size_,
- write_handle_->Clone(mojo::SharedBufferHandle::AccessMode::READ_ONLY),
- write_size_);
- active_handle_index_ = 0;
- handle_replaced_ = false;
-}
+ // Reset states.
+ hit_test_data_.clear();
+ hit_test_data_capacity_ = initial_region_size_;
+ hit_test_data_size_ = 0;
+ hit_test_data_.resize(hit_test_data_capacity_);
-void HitTestAggregator::AllocateHitTestRegionArray() {
- ResizeHitTestRegionArray(initial_region_size_);
- SwapHandles();
- ResizeHitTestRegionArray(initial_region_size_);
+ AppendRoot(display_surface_id);
+ referenced_child_regions_.clear();
+ SendHitTestData();
}
-void HitTestAggregator::ResizeHitTestRegionArray(uint32_t size) {
- size_t num_bytes = size * sizeof(AggregatedHitTestRegion);
- write_handle_ = mojo::SharedBufferHandle::Create(num_bytes);
- DCHECK(write_handle_.is_valid());
- auto new_buffer_ = write_handle_->Map(num_bytes);
- DCHECK(new_buffer_);
- handle_replaced_ = true;
-
- AggregatedHitTestRegion* region = (AggregatedHitTestRegion*)new_buffer_.get();
- if (write_size_)
- memcpy(region, write_buffer_.get(), write_size_);
- else
- region[0].child_count = kEndOfList;
-
- write_size_ = size;
- write_buffer_ = std::move(new_buffer_);
-}
-
-void HitTestAggregator::SwapHandles() {
- using std::swap;
-
- swap(read_handle_, write_handle_);
- swap(read_size_, write_size_);
- swap(read_buffer_, write_buffer_);
- active_handle_index_ = !active_handle_index_;
+void HitTestAggregator::SendHitTestData() {
+ hit_test_data_.resize(hit_test_data_size_);
+ delegate_->OnAggregatedHitTestRegionListUpdated(root_frame_sink_id_,
+ hit_test_data_);
}
void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) {
SCOPED_UMA_HISTOGRAM_TIMER("Event.VizHitTest.AggregateTime");
- const mojom::HitTestRegionList* hit_test_region_list =
+ const HitTestRegionList* hit_test_region_list =
hit_test_manager_->GetActiveHitTestRegionList(
local_surface_id_lookup_delegate_, surface_id.frame_sink_id());
if (!hit_test_region_list)
@@ -106,7 +62,7 @@ void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) {
size_t region_index = 1;
for (const auto& region : hit_test_region_list->regions) {
- if (region_index >= write_size_ - 1)
+ if (region_index >= hit_test_data_capacity_ - 1)
break;
region_index = AppendRegion(region_index, region);
}
@@ -117,31 +73,30 @@ void HitTestAggregator::AppendRoot(const SurfaceId& surface_id) {
SetRegionAt(0, surface_id.frame_sink_id(), hit_test_region_list->flags,
hit_test_region_list->bounds, hit_test_region_list->transform,
child_count);
- MarkEndAt(region_index);
}
size_t HitTestAggregator::AppendRegion(size_t region_index,
- const mojom::HitTestRegionPtr& region) {
+ const HitTestRegion& region) {
size_t parent_index = region_index++;
- if (region_index >= write_size_ - 1) {
- if (write_size_ > max_region_size_) {
- MarkEndAt(parent_index);
+ if (region_index >= hit_test_data_capacity_ - 1) {
+ if (hit_test_data_capacity_ > max_region_size_) {
return region_index;
} else {
- GrowRegionList();
+ hit_test_data_capacity_ += incremental_region_size_;
+ hit_test_data_.resize(hit_test_data_capacity_);
}
}
- uint32_t flags = region->flags;
- gfx::Transform transform = region->transform;
+ uint32_t flags = region.flags;
+ gfx::Transform transform = region.transform;
- if (region->flags & mojom::kHitTestChildSurface) {
- if (referenced_child_regions_.count(region->frame_sink_id))
+ if (region.flags & HitTestRegionFlags::kHitTestChildSurface) {
+ if (referenced_child_regions_.count(region.frame_sink_id))
return parent_index;
- const mojom::HitTestRegionList* hit_test_region_list =
+ const HitTestRegionList* hit_test_region_list =
hit_test_manager_->GetActiveHitTestRegionList(
- local_surface_id_lookup_delegate_, region->frame_sink_id);
+ local_surface_id_lookup_delegate_, region.frame_sink_id);
if (!hit_test_region_list) {
// Hit-test data not found with this FrameSinkId. This means that it
// failed to find a surface corresponding to this FrameSinkId at surface
@@ -149,7 +104,7 @@ size_t HitTestAggregator::AppendRegion(size_t region_index,
return parent_index;
}
- referenced_child_regions_.insert(region->frame_sink_id);
+ referenced_child_regions_.insert(region.frame_sink_id);
// Rather than add a node in the tree for this hit_test_region_list
// element we can simplify the tree by merging the flags and transform
@@ -161,14 +116,14 @@ size_t HitTestAggregator::AppendRegion(size_t region_index,
for (const auto& child_region : hit_test_region_list->regions) {
region_index = AppendRegion(region_index, child_region);
- if (region_index >= write_size_ - 1)
+ if (region_index >= hit_test_data_capacity_ - 1)
break;
}
}
DCHECK_GE(region_index - parent_index - 1, 0u);
int32_t child_count = region_index - parent_index - 1;
- SetRegionAt(parent_index, region->frame_sink_id, flags, region->rect,
- transform, child_count);
+ SetRegionAt(parent_index, region.frame_sink_id, flags, region.rect, transform,
+ child_count);
return region_index;
}
@@ -178,21 +133,9 @@ void HitTestAggregator::SetRegionAt(size_t index,
const gfx::Rect& rect,
const gfx::Transform& transform,
int32_t child_count) {
- AggregatedHitTestRegion* regions =
- static_cast<AggregatedHitTestRegion*>(write_buffer_.get());
- AggregatedHitTestRegion* element = &regions[index];
-
- element->frame_sink_id = frame_sink_id;
- element->flags = flags;
- element->rect = rect;
- element->child_count = child_count;
- element->set_transform(transform);
-}
-
-void HitTestAggregator::MarkEndAt(size_t index) {
- AggregatedHitTestRegion* regions =
- static_cast<AggregatedHitTestRegion*>(write_buffer_.get());
- regions[index].child_count = kEndOfList;
+ hit_test_data_[index] = AggregatedHitTestRegion(frame_sink_id, flags, rect,
+ transform, child_count);
+ hit_test_data_size_++;
}
} // namespace viz
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator.h b/chromium/components/viz/service/hit_test/hit_test_aggregator.h
index 4eb67bb5a48..b4999a0ddcf 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator.h
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator.h
@@ -10,19 +10,16 @@
#include "components/viz/service/hit_test/hit_test_manager.h"
#include "components/viz/service/surfaces/surface_observer.h"
#include "components/viz/service/viz_service_export.h"
-#include "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom.h"
namespace viz {
class HitTestAggregatorDelegate;
+struct HitTestRegion;
// HitTestAggregator assembles the list of HitTestRegion objects that define the
// hit test information required for one display. Active HitTestRegionList
-// information is obtained from the HitTestManager. The resulting list is made
-// available in shared memory and used by HitTestQuery to enable efficient hit
-// testing across processes.
-//
-// This is intended to be created in the viz or GPU process. For mus+ash this
-// will be true after the mus process split.
+// information is obtained from the HitTestManager. The resulting list is sent
+// to HitTestQuery for event targeting. This is intended to be created in the
+// viz or GPU process.
class VIZ_SERVICE_EXPORT HitTestAggregator {
public:
// |delegate| owns and outlives HitTestAggregator.
@@ -31,71 +28,38 @@ class VIZ_SERVICE_EXPORT HitTestAggregator {
HitTestAggregatorDelegate* delegate,
LatestLocalSurfaceIdLookupDelegate* local_surface_id_lookup_delegate,
const FrameSinkId& frame_sink_id,
- uint32_t initial_region_size = 1024,
- uint32_t max_region_size = 100 * 1024);
+ uint32_t initial_region_size = 100,
+ uint32_t max_region_size = 100 * 100);
~HitTestAggregator();
// Called after surfaces have been aggregated into the DisplayFrame.
// In this call HitTestRegionList structures received from active surfaces
- // are aggregated into the HitTestRegionList structure in
- // shared memory used for event targetting.
+ // are aggregated into |hit_test_data_|.
void Aggregate(const SurfaceId& display_surface_id);
- // Called at BeginFrame. Swaps buffers in shared memory and tells its
- // delegate.
- void Swap();
-
private:
friend class TestHitTestAggregator;
- // Allocates memory for the AggregatedHitTestRegion array.
- void AllocateHitTestRegionArray();
-
- // Resizes memory for the AggregatedHitTestRegion array. |size| indicates the
- // number of elements.
- void ResizeHitTestRegionArray(uint32_t size);
-
- void GrowRegionList();
- void SwapHandles();
+ void SendHitTestData();
// Appends the root element to the AggregatedHitTestRegion array.
void AppendRoot(const SurfaceId& surface_id);
// Appends a |region| to the HitTestRegionList structure to recursively
- // build the tree. |region_index| indicates the current index of the end of
+ // build the tree. |region_index| indicates the current index of the end of
// the list.
- size_t AppendRegion(size_t region_index,
- const mojom::HitTestRegionPtr& region);
+ size_t AppendRegion(size_t region_index, const HitTestRegion& region);
// Populates the HitTestRegion element at the given element |index|.
- // Access to the HitTestRegion list is localized to this call
- // in order to prevent errors if the array is resized during aggregation.
void SetRegionAt(size_t index,
const FrameSinkId& frame_sink_id,
uint32_t flags,
const gfx::Rect& rect,
const gfx::Transform& transform,
int32_t child_count);
- // Marks the element at the given index as the end of list.
- void MarkEndAt(size_t index);
const HitTestManager* const hit_test_manager_;
- mojo::ScopedSharedBufferHandle read_handle_;
- mojo::ScopedSharedBufferHandle write_handle_;
-
- // The number of elements allocated.
- uint32_t read_size_ = 0;
- uint32_t write_size_ = 0;
-
- mojo::ScopedSharedBufferMapping read_buffer_;
- mojo::ScopedSharedBufferMapping write_buffer_;
-
- bool handle_replaced_ = false;
-
- // Can only be 0 or 1 when we only have two buffers.
- uint8_t active_handle_index_ = 0;
-
HitTestAggregatorDelegate* const delegate_;
LatestLocalSurfaceIdLookupDelegate* const local_surface_id_lookup_delegate_;
@@ -110,6 +74,10 @@ class VIZ_SERVICE_EXPORT HitTestAggregator {
const uint32_t incremental_region_size_;
const uint32_t max_region_size_;
+ uint32_t hit_test_data_capacity_ = 0;
+ uint32_t hit_test_data_size_ = 0;
+ std::vector<AggregatedHitTestRegion> hit_test_data_;
+
// This is the set of FrameSinkIds referenced in the aggregation so far, used
// to detect cycles.
base::flat_set<FrameSinkId> referenced_child_regions_;
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h b/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h
index 51b9b338c79..c6b06cc6992 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator_delegate.h
@@ -5,23 +5,16 @@
#ifndef COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_
#define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_AGGREGATOR_DELEGATE_H_
+#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
+
namespace viz {
// Used by HitTestAggregator to talk to FrameSinkManagerImpl.
class HitTestAggregatorDelegate {
public:
- // Called if any of the buffer that stores the aggregated hit-test data is
- // updated (e.g. destroyed, reallocated etc.). |active_handle| and
- // |idle_handle| both must be valid.
+ // Called to send |hit_test_data| when we receive new data.
virtual void OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) = 0;
-
- virtual void SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) = 0;
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) = 0;
protected:
// The dtor is protected so that HitTestAggregator does not take ownership.
diff --git a/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc b/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
index 08135e64416..d59985209db 100644
--- a/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_aggregator_unittest.cc
@@ -7,6 +7,7 @@
#include <map>
#include <memory>
+#include "components/viz/common/hit_test/hit_test_region_list.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/host/host_frame_sink_manager.h"
@@ -40,34 +41,18 @@ class TestHostFrameSinkManager : public HostFrameSinkManager {
void OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) override {
- DCHECK(active_handle.is_valid() && idle_handle.is_valid());
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) override {
buffer_frame_sink_id_ = frame_sink_id;
- handle_buffers_[0] = active_handle->Map(active_handle_size *
- sizeof(AggregatedHitTestRegion));
- handle_buffers_[1] =
- idle_handle->Map(idle_handle_size * sizeof(AggregatedHitTestRegion));
- SwitchActiveAggregatedHitTestRegionList(buffer_frame_sink_id_, 0);
+ active_list_ = hit_test_data;
}
- void SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) override {
- active_list_ = static_cast<AggregatedHitTestRegion*>(
- handle_buffers_[active_handle_index].get());
- }
-
- AggregatedHitTestRegion* regions() { return active_list_; }
+ const std::vector<AggregatedHitTestRegion>& regions() { return active_list_; }
const FrameSinkId& buffer_frame_sink_id() { return buffer_frame_sink_id_; }
private:
FrameSinkId buffer_frame_sink_id_;
- mojo::ScopedSharedBufferMapping handle_buffers_[2];
- AggregatedHitTestRegion* active_list_;
+ std::vector<AggregatedHitTestRegion> active_list_;
DISALLOW_COPY_AND_ASSIGN(TestHostFrameSinkManager);
};
@@ -83,25 +68,11 @@ class TestFrameSinkManagerImpl : public FrameSinkManagerImpl {
void OnAggregatedHitTestRegionListUpdated(
const FrameSinkId& frame_sink_id,
- mojo::ScopedSharedBufferHandle active_handle,
- uint32_t active_handle_size,
- mojo::ScopedSharedBufferHandle idle_handle,
- uint32_t idle_handle_size) override {
- // Do not check if it's on valid thread for tests.
- if (host_client_) {
- host_client_->OnAggregatedHitTestRegionListUpdated(
- frame_sink_id, std::move(active_handle), active_handle_size,
- std::move(idle_handle), idle_handle_size);
- }
- }
-
- void SwitchActiveAggregatedHitTestRegionList(
- const FrameSinkId& frame_sink_id,
- uint8_t active_handle_index) override {
+ const std::vector<AggregatedHitTestRegion>& hit_test_data) override {
// Do not check if it's on valid thread for tests.
if (host_client_) {
- host_client_->SwitchActiveAggregatedHitTestRegionList(
- frame_sink_id, active_handle_index);
+ host_client_->OnAggregatedHitTestRegionListUpdated(frame_sink_id,
+ hit_test_data);
}
}
@@ -127,28 +98,8 @@ class TestHitTestAggregator final : public HitTestAggregator {
frame_sink_id_(frame_sink_id) {}
~TestHitTestAggregator() = default;
- int GetRegionCount() const {
- AggregatedHitTestRegion* start =
- static_cast<AggregatedHitTestRegion*>(read_buffer_.get());
- AggregatedHitTestRegion* end = start;
- while (end->child_count != kEndOfList)
- end++;
- return end - start;
- }
- int GetHitTestRegionListSize() { return read_size_; }
- void SwapHandles() {
- delegate_->SwitchActiveAggregatedHitTestRegionList(frame_sink_id_,
- active_handle_index_);
- }
-
- void Reset() {
- AggregatedHitTestRegion* regions =
- static_cast<AggregatedHitTestRegion*>(write_buffer_.get());
- regions[0].child_count = kEndOfList;
-
- regions = static_cast<AggregatedHitTestRegion*>(read_buffer_.get());
- regions[0].child_count = kEndOfList;
- }
+ int GetRegionCount() const { return hit_test_data_size_; }
+ int GetHitTestRegionListCapacity() { return hit_test_data_capacity_; }
private:
const FrameSinkId frame_sink_id_;
@@ -187,24 +138,24 @@ class HitTestAggregatorTest : public testing::Test {
SurfaceId surface_id = MakeSurfaceId(client_id);
client_id++;
- auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->flags = mojom::kHitTestMine;
- hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList hit_test_region_list;
+ hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
for (int i = 0; i < 8; i++) {
- auto hit_test_region = mojom::HitTestRegion::New();
- hit_test_region->rect.SetRect(100, 100, 100, 100);
+ HitTestRegion hit_test_region;
+ hit_test_region.rect.SetRect(100, 100, 100, 100);
SurfaceId child_surface_id = MakeSurfaceId(client_id);
- hit_test_region->frame_sink_id = child_surface_id.frame_sink_id();
+ hit_test_region.frame_sink_id = child_surface_id.frame_sink_id();
if (depth > 0) {
- hit_test_region->flags = mojom::kHitTestChildSurface;
+ hit_test_region.flags = HitTestRegionFlags::kHitTestChildSurface;
client_id =
CreateAndSubmitHitTestRegionListWith8Children(client_id, depth - 1);
} else {
- hit_test_region->flags = mojom::kHitTestMine;
+ hit_test_region.flags = HitTestRegionFlags::kHitTestMine;
}
- hit_test_region_list->regions.push_back(std::move(hit_test_region));
+ hit_test_region_list.regions.push_back(std::move(hit_test_region));
}
if (surface_id.frame_sink_id() == kDisplayFrameSink) {
@@ -229,7 +180,7 @@ class HitTestAggregatorTest : public testing::Test {
return hit_test_aggregator_.get();
}
- AggregatedHitTestRegion* host_regions() {
+ const std::vector<AggregatedHitTestRegion>& host_regions() {
return host_frame_sink_manager_->regions();
}
@@ -284,30 +235,26 @@ TEST_F(HitTestAggregatorTest, OneSurface) {
SurfaceId display_surface_id = MakeSurfaceId(kDisplayClientId);
- auto hit_test_region_list = mojom::HitTestRegionList::New();
- hit_test_region_list->flags = mojom::kHitTestMine;
- hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList hit_test_region_list;
+ hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
support()->SubmitCompositorFrame(display_surface_id.local_surface_id(),
MakeDefaultCompositorFrame(),
std::move(hit_test_region_list));
local_surface_id_lookup_delegate()->SetSurfaceIdMap(display_surface_id);
aggregator->Aggregate(display_surface_id);
- aggregator->SwapHandles();
// Expect 1 entry routing all events to the one surface (display root).
EXPECT_EQ(aggregator->GetRegionCount(), 1);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
- AggregatedHitTestRegion* region = nullptr;
-
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, display_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 0);
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, display_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 0);
}
// One opaque embedder with two regions.
@@ -325,22 +272,22 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) {
SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_r1 = mojom::HitTestRegion::New();
- e_hit_test_region_r1->frame_sink_id = e_surface_id.frame_sink_id();
- e_hit_test_region_r1->flags = mojom::kHitTestMine;
- e_hit_test_region_r1->rect.SetRect(100, 100, 200, 400);
+ HitTestRegion e_hit_test_region_r1;
+ e_hit_test_region_r1.frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_r1.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_r1.rect.SetRect(100, 100, 200, 400);
- auto e_hit_test_region_r2 = mojom::HitTestRegion::New();
- e_hit_test_region_r2->frame_sink_id = e_surface_id.frame_sink_id();
- e_hit_test_region_r2->flags = mojom::kHitTestMine;
- e_hit_test_region_r2->rect.SetRect(400, 100, 300, 400);
+ HitTestRegion e_hit_test_region_r2;
+ e_hit_test_region_r2.frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_r2.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_r2.rect.SetRect(400, 100, 300, 400);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_r1));
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_r2));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_r1));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_r2));
support()->SubmitCompositorFrame(e_surface_id.local_surface_id(),
MakeDefaultCompositorFrame(),
@@ -348,30 +295,26 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoRegions) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_EQ(aggregator->GetRegionCount(), 3);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- AggregatedHitTestRegion* region = nullptr;
-
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 2);
-
- region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 400));
- EXPECT_EQ(region->child_count, 0);
- region = &regions[2];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->rect, gfx::Rect(400, 100, 300, 400));
- EXPECT_EQ(region->child_count, 0);
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 2);
+
+ region = host_regions()[1];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 400));
+ EXPECT_EQ(region.child_count, 0);
+
+ region = host_regions()[2];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.rect, gfx::Rect(400, 100, 300, 400));
+ EXPECT_EQ(region.child_count, 0);
}
// One embedder with two children.
@@ -392,26 +335,26 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) {
SurfaceId c1_surface_id = MakeSurfaceId(kDisplayClientId + 1);
SurfaceId c2_surface_id = MakeSurfaceId(kDisplayClientId + 2);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
- e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id();
- e_hit_test_region_c1->rect.SetRect(100, 100, 200, 300);
+ HitTestRegion e_hit_test_region_c1;
+ e_hit_test_region_c1.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c1.frame_sink_id = c1_surface_id.frame_sink_id();
+ e_hit_test_region_c1.rect.SetRect(100, 100, 200, 300);
- auto e_hit_test_region_c2 = mojom::HitTestRegion::New();
- e_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id();
- e_hit_test_region_c2->rect.SetRect(400, 100, 400, 300);
+ HitTestRegion e_hit_test_region_c2;
+ e_hit_test_region_c2.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c2.frame_sink_id = c2_surface_id.frame_sink_id();
+ e_hit_test_region_c2.rect.SetRect(400, 100, 400, 300);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1));
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c2));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c1));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c2));
- auto c1_hit_test_region_list = mojom::HitTestRegionList::New();
+ HitTestRegionList c1_hit_test_region_list;
- auto c2_hit_test_region_list = mojom::HitTestRegionList::New();
+ HitTestRegionList c2_hit_test_region_list;
// Submit in unexpected order.
@@ -435,32 +378,28 @@ TEST_F(HitTestAggregatorTest, OneEmbedderTwoChildren) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(c2_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_EQ(aggregator->GetRegionCount(), 3);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- AggregatedHitTestRegion* region = nullptr;
-
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 2);
-
- region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface);
- EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 300));
- EXPECT_EQ(region->child_count, 0);
-
- region = &regions[2];
- EXPECT_EQ(region->flags, mojom::kHitTestChildSurface);
- EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(400, 100, 400, 300));
- EXPECT_EQ(region->child_count, 0);
+
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 2);
+
+ region = host_regions()[1];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestChildSurface);
+ EXPECT_EQ(region.frame_sink_id, c1_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 300));
+ EXPECT_EQ(region.child_count, 0);
+
+ region = host_regions()[2];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestChildSurface);
+ EXPECT_EQ(region.frame_sink_id, c2_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(400, 100, 400, 300));
+ EXPECT_EQ(region.child_count, 0);
}
// Occluded child frame (OOPIF).
@@ -481,26 +420,26 @@ TEST_F(HitTestAggregatorTest, OccludedChildFrame) {
SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_div = mojom::HitTestRegion::New();
- e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
- e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+ HitTestRegion e_hit_test_region_div;
+ e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div.rect.SetRect(200, 200, 300, 200);
- auto e_hit_test_region_c = mojom::HitTestRegion::New();
- e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
- e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+ HitTestRegion e_hit_test_region_c;
+ e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c.rect.SetRect(100, 100, 200, 500);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c));
- auto c_hit_test_region_list = mojom::HitTestRegionList::New();
- c_hit_test_region_list->flags = mojom::kHitTestMine;
- c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
+ HitTestRegionList c_hit_test_region_list;
+ c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500);
// Submit in unexpected order.
auto support2 = std::make_unique<CompositorFrameSinkSupport>(
@@ -516,32 +455,30 @@ TEST_F(HitTestAggregatorTest, OccludedChildFrame) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_EQ(aggregator->GetRegionCount(), 3);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- AggregatedHitTestRegion* region = nullptr;
-
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 2);
-
- region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200));
- EXPECT_EQ(region->child_count, 0);
-
- region = &regions[2];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500));
- EXPECT_EQ(region->child_count, 0);
+
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 2);
+
+ region = host_regions()[1];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(200, 200, 300, 200));
+ EXPECT_EQ(region.child_count, 0);
+
+ region = host_regions()[2];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, c_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 500));
+ EXPECT_EQ(region.child_count, 0);
}
// Foreground child frame (OOPIF).
@@ -563,26 +500,26 @@ TEST_F(HitTestAggregatorTest, ForegroundChildFrame) {
SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_div = mojom::HitTestRegion::New();
- e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
- e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+ HitTestRegion e_hit_test_region_div;
+ e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div.rect.SetRect(200, 200, 300, 200);
- auto e_hit_test_region_c = mojom::HitTestRegion::New();
- e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
- e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+ HitTestRegion e_hit_test_region_c;
+ e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c.rect.SetRect(100, 100, 200, 500);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div));
- auto c_hit_test_region_list = mojom::HitTestRegionList::New();
- c_hit_test_region_list->flags = mojom::kHitTestMine;
- c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
+ HitTestRegionList c_hit_test_region_list;
+ c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500);
// Submit in unexpected order.
@@ -599,32 +536,30 @@ TEST_F(HitTestAggregatorTest, ForegroundChildFrame) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_EQ(aggregator->GetRegionCount(), 3);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- AggregatedHitTestRegion* region = nullptr;
-
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 2);
-
- region = &regions[1];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 200, 500));
- EXPECT_EQ(region->child_count, 0);
-
- region = &regions[2];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200));
- EXPECT_EQ(region->child_count, 0);
+
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 2);
+
+ region = host_regions()[1];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, c_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 200, 500));
+ EXPECT_EQ(region.child_count, 0);
+
+ region = host_regions()[2];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(200, 200, 300, 200));
+ EXPECT_EQ(region.child_count, 0);
}
// One embedder with a clipped child with a tab and transparent background.
@@ -648,42 +583,42 @@ TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) {
SurfaceId a_surface_id = MakeSurfaceId(kDisplayClientId + 2);
SurfaceId b_surface_id = MakeSurfaceId(kDisplayClientId + 3);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_c = mojom::HitTestRegion::New();
- e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
- e_hit_test_region_c->rect.SetRect(300, 100, 1600, 800);
- e_hit_test_region_c->transform.Translate(200, 100);
+ HitTestRegion e_hit_test_region_c;
+ e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c.rect.SetRect(300, 100, 1600, 800);
+ e_hit_test_region_c.transform.Translate(200, 100);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c));
- auto c_hit_test_region_list = mojom::HitTestRegionList::New();
- c_hit_test_region_list->flags = mojom::kHitTestIgnore;
- c_hit_test_region_list->bounds.SetRect(0, 0, 1600, 800);
+ HitTestRegionList c_hit_test_region_list;
+ c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestIgnore;
+ c_hit_test_region_list.bounds.SetRect(0, 0, 1600, 800);
- auto c_hit_test_region_a = mojom::HitTestRegion::New();
- c_hit_test_region_a->flags = mojom::kHitTestChildSurface;
- c_hit_test_region_a->frame_sink_id = a_surface_id.frame_sink_id();
- c_hit_test_region_a->rect.SetRect(0, 0, 200, 100);
+ HitTestRegion c_hit_test_region_a;
+ c_hit_test_region_a.flags = HitTestRegionFlags::kHitTestChildSurface;
+ c_hit_test_region_a.frame_sink_id = a_surface_id.frame_sink_id();
+ c_hit_test_region_a.rect.SetRect(0, 0, 200, 100);
- auto c_hit_test_region_b = mojom::HitTestRegion::New();
- c_hit_test_region_b->flags = mojom::kHitTestChildSurface;
- c_hit_test_region_b->frame_sink_id = b_surface_id.frame_sink_id();
- c_hit_test_region_b->rect.SetRect(0, 100, 800, 600);
+ HitTestRegion c_hit_test_region_b;
+ c_hit_test_region_b.flags = HitTestRegionFlags::kHitTestChildSurface;
+ c_hit_test_region_b.frame_sink_id = b_surface_id.frame_sink_id();
+ c_hit_test_region_b.rect.SetRect(0, 100, 800, 600);
- c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_a));
- c_hit_test_region_list->regions.push_back(std::move(c_hit_test_region_b));
+ c_hit_test_region_list.regions.push_back(std::move(c_hit_test_region_a));
+ c_hit_test_region_list.regions.push_back(std::move(c_hit_test_region_b));
- auto a_hit_test_region_list = mojom::HitTestRegionList::New();
- a_hit_test_region_list->flags = mojom::kHitTestMine;
- a_hit_test_region_list->bounds.SetRect(0, 0, 200, 100);
+ HitTestRegionList a_hit_test_region_list;
+ a_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ a_hit_test_region_list.bounds.SetRect(0, 0, 200, 100);
- auto b_hit_test_region_list = mojom::HitTestRegionList::New();
- b_hit_test_region_list->flags = mojom::kHitTestMine;
- b_hit_test_region_list->bounds.SetRect(0, 100, 800, 600);
+ HitTestRegionList b_hit_test_region_list;
+ b_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ b_hit_test_region_list.bounds.SetRect(0, 100, 800, 600);
// Submit in unexpected order.
@@ -714,43 +649,45 @@ TEST_F(HitTestAggregatorTest, ClippedChildWithTabAndTransparentBackground) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_EQ(aggregator->GetRegionCount(), 4);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
- AggregatedHitTestRegion* region = nullptr;
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 3);
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 3);
-
- region = &regions[1];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestIgnore, region->flags);
- EXPECT_EQ(region->frame_sink_id, c_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(300, 100, 1600, 800));
- EXPECT_EQ(region->child_count, 2);
+ region = host_regions()[1];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestIgnore,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, c_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(300, 100, 1600, 800));
+ EXPECT_EQ(region.child_count, 2);
gfx::Point point(300, 300);
- gfx::Transform transform(region->transform());
+ gfx::Transform transform(region.transform());
transform.TransformPointReverse(&point);
EXPECT_TRUE(point == gfx::Point(100, 200));
- region = &regions[2];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, a_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 200, 100));
- EXPECT_EQ(region->child_count, 0);
-
- region = &regions[3];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, b_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 100, 800, 600));
- EXPECT_EQ(region->child_count, 0);
+ region = host_regions()[2];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, a_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 200, 100));
+ EXPECT_EQ(region.child_count, 0);
+
+ region = host_regions()[3];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, b_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 100, 800, 600));
+ EXPECT_EQ(region.child_count, 0);
}
// Three children deep.
@@ -775,42 +712,42 @@ TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) {
SurfaceId c2_surface_id = MakeSurfaceId(kDisplayClientId + 2);
SurfaceId c3_surface_id = MakeSurfaceId(kDisplayClientId + 3);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_c1 = mojom::HitTestRegion::New();
- e_hit_test_region_c1->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c1->frame_sink_id = c1_surface_id.frame_sink_id();
- e_hit_test_region_c1->rect.SetRect(100, 100, 700, 700);
+ HitTestRegion e_hit_test_region_c1;
+ e_hit_test_region_c1.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c1.frame_sink_id = c1_surface_id.frame_sink_id();
+ e_hit_test_region_c1.rect.SetRect(100, 100, 700, 700);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c1));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c1));
- auto c1_hit_test_region_list = mojom::HitTestRegionList::New();
- c1_hit_test_region_list->flags = mojom::kHitTestMine;
- c1_hit_test_region_list->bounds.SetRect(0, 0, 600, 600);
+ HitTestRegionList c1_hit_test_region_list;
+ c1_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c1_hit_test_region_list.bounds.SetRect(0, 0, 600, 600);
- auto c1_hit_test_region_c2 = mojom::HitTestRegion::New();
- c1_hit_test_region_c2->flags = mojom::kHitTestChildSurface;
- c1_hit_test_region_c2->frame_sink_id = c2_surface_id.frame_sink_id();
- c1_hit_test_region_c2->rect.SetRect(100, 100, 500, 500);
+ HitTestRegion c1_hit_test_region_c2;
+ c1_hit_test_region_c2.flags = HitTestRegionFlags::kHitTestChildSurface;
+ c1_hit_test_region_c2.frame_sink_id = c2_surface_id.frame_sink_id();
+ c1_hit_test_region_c2.rect.SetRect(100, 100, 500, 500);
- c1_hit_test_region_list->regions.push_back(std::move(c1_hit_test_region_c2));
+ c1_hit_test_region_list.regions.push_back(std::move(c1_hit_test_region_c2));
- auto c2_hit_test_region_list = mojom::HitTestRegionList::New();
- c2_hit_test_region_list->flags = mojom::kHitTestMine;
- c2_hit_test_region_list->bounds.SetRect(0, 0, 400, 400);
+ HitTestRegionList c2_hit_test_region_list;
+ c2_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c2_hit_test_region_list.bounds.SetRect(0, 0, 400, 400);
- auto c2_hit_test_region_c3 = mojom::HitTestRegion::New();
- c2_hit_test_region_c3->flags = mojom::kHitTestChildSurface;
- c2_hit_test_region_c3->frame_sink_id = c3_surface_id.frame_sink_id();
- c2_hit_test_region_c3->rect.SetRect(100, 100, 300, 300);
+ HitTestRegion c2_hit_test_region_c3;
+ c2_hit_test_region_c3.flags = HitTestRegionFlags::kHitTestChildSurface;
+ c2_hit_test_region_c3.frame_sink_id = c3_surface_id.frame_sink_id();
+ c2_hit_test_region_c3.rect.SetRect(100, 100, 300, 300);
- c2_hit_test_region_list->regions.push_back(std::move(c2_hit_test_region_c3));
+ c2_hit_test_region_list.regions.push_back(std::move(c2_hit_test_region_c3));
- auto c3_hit_test_region_list = mojom::HitTestRegionList::New();
- c3_hit_test_region_list->flags = mojom::kHitTestMine;
- c3_hit_test_region_list->bounds.SetRect(0, 0, 200, 200);
+ HitTestRegionList c3_hit_test_region_list;
+ c3_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c3_hit_test_region_list.bounds.SetRect(0, 0, 200, 200);
// Submit in unexpected order.
@@ -841,38 +778,40 @@ TEST_F(HitTestAggregatorTest, ThreeChildrenDeep) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(c2_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_EQ(aggregator->GetRegionCount(), 4);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- AggregatedHitTestRegion* region = nullptr;
-
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 3);
-
- region = &regions[1];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, c1_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 700, 700));
- EXPECT_EQ(region->child_count, 2);
-
- region = &regions[2];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, c2_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 500, 500));
- EXPECT_EQ(region->child_count, 1);
-
- region = &regions[3];
- EXPECT_EQ(mojom::kHitTestChildSurface | mojom::kHitTestMine, region->flags);
- EXPECT_EQ(region->frame_sink_id, c3_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(100, 100, 300, 300));
- EXPECT_EQ(region->child_count, 0);
+
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 3);
+
+ region = host_regions()[1];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, c1_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 700, 700));
+ EXPECT_EQ(region.child_count, 2);
+
+ region = host_regions()[2];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, c2_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 500, 500));
+ EXPECT_EQ(region.child_count, 1);
+
+ region = host_regions()[3];
+ EXPECT_EQ(HitTestRegionFlags::kHitTestChildSurface |
+ HitTestRegionFlags::kHitTestMine,
+ region.flags);
+ EXPECT_EQ(region.frame_sink_id, c3_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(100, 100, 300, 300));
+ EXPECT_EQ(region.child_count, 0);
}
// Missing / late child.
@@ -893,26 +832,26 @@ TEST_F(HitTestAggregatorTest, MissingChildFrame) {
SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_div = mojom::HitTestRegion::New();
- e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
- e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+ HitTestRegion e_hit_test_region_div;
+ e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div.rect.SetRect(200, 200, 300, 200);
- auto e_hit_test_region_c = mojom::HitTestRegion::New();
- e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
- e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+ HitTestRegion e_hit_test_region_c;
+ e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c.rect.SetRect(100, 100, 200, 500);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div));
- auto c_hit_test_region_list = mojom::HitTestRegionList::New();
- c_hit_test_region_list->flags = mojom::kHitTestMine;
- c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
+ HitTestRegionList c_hit_test_region_list;
+ c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500);
// Submit in unexpected order.
@@ -922,27 +861,23 @@ TEST_F(HitTestAggregatorTest, MissingChildFrame) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
// Child c didn't submit any CompositorFrame. Events should go to parent.
EXPECT_EQ(aggregator->GetRegionCount(), 2);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- AggregatedHitTestRegion* region = nullptr;
- region = &regions[0];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(0, 0, 1024, 768));
- EXPECT_EQ(region->child_count, 1);
-
- region = &regions[1];
- EXPECT_EQ(region->flags, mojom::kHitTestMine);
- EXPECT_EQ(region->frame_sink_id, e_surface_id.frame_sink_id());
- EXPECT_EQ(region->rect, gfx::Rect(200, 200, 300, 200));
- EXPECT_EQ(region->child_count, 0);
+ AggregatedHitTestRegion region = host_regions()[0];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(0, 0, 1024, 768));
+ EXPECT_EQ(region.child_count, 1);
+
+ region = host_regions()[1];
+ EXPECT_EQ(region.flags, HitTestRegionFlags::kHitTestMine);
+ EXPECT_EQ(region.frame_sink_id, e_surface_id.frame_sink_id());
+ EXPECT_EQ(region.rect, gfx::Rect(200, 200, 300, 200));
+ EXPECT_EQ(region.child_count, 0);
}
// Exceed limits to ensure that bounds and resize work.
@@ -970,14 +905,13 @@ TEST_F(HitTestAggregatorTest, ExceedLimits) {
TestHitTestAggregator* aggregator = hit_test_aggregator();
EXPECT_EQ(aggregator->GetRegionCount(), 0);
- EXPECT_LT(aggregator->GetHitTestRegionListSize(), 4096);
+ EXPECT_LT(aggregator->GetHitTestRegionListCapacity(), 4096);
SurfaceId display_surface_id = MakeSurfaceId(kDisplayClientId);
CreateAndSubmitHitTestRegionListWith8Children(kDisplayClientId, 3);
aggregator->Aggregate(display_surface_id);
- aggregator->SwapHandles();
// Expect 4680 regions:
// 8 children 4 levels deep 8*8*8*8 is 4096
@@ -985,17 +919,10 @@ TEST_F(HitTestAggregatorTest, ExceedLimits) {
// 1 root + 1
// -----
// 4681.
- EXPECT_GE(aggregator->GetHitTestRegionListSize(), 4681);
+ EXPECT_GE(aggregator->GetHitTestRegionListCapacity(), 4681);
EXPECT_EQ(host_buffer_frame_sink_id(), kDisplayFrameSink);
- AggregatedHitTestRegion* regions = host_regions();
-
- uint32_t count = 0;
- while (regions->child_count != kEndOfList) {
- regions++;
- count++;
- }
- EXPECT_EQ(count, 4681u);
+ EXPECT_EQ(host_regions().size(), 4681u);
}
TEST_F(HitTestAggregatorTest, DiscardedSurfaces) {
@@ -1004,26 +931,26 @@ TEST_F(HitTestAggregatorTest, DiscardedSurfaces) {
SurfaceId e_surface_id = MakeSurfaceId(kDisplayClientId);
SurfaceId c_surface_id = MakeSurfaceId(kDisplayClientId + 1);
- auto e_hit_test_region_list = mojom::HitTestRegionList::New();
- e_hit_test_region_list->flags = mojom::kHitTestMine;
- e_hit_test_region_list->bounds.SetRect(0, 0, 1024, 768);
+ HitTestRegionList e_hit_test_region_list;
+ e_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_list.bounds.SetRect(0, 0, 1024, 768);
- auto e_hit_test_region_div = mojom::HitTestRegion::New();
- e_hit_test_region_div->flags = mojom::kHitTestMine;
- e_hit_test_region_div->frame_sink_id = e_surface_id.frame_sink_id();
- e_hit_test_region_div->rect.SetRect(200, 200, 300, 200);
+ HitTestRegion e_hit_test_region_div;
+ e_hit_test_region_div.flags = HitTestRegionFlags::kHitTestMine;
+ e_hit_test_region_div.frame_sink_id = e_surface_id.frame_sink_id();
+ e_hit_test_region_div.rect.SetRect(200, 200, 300, 200);
- auto e_hit_test_region_c = mojom::HitTestRegion::New();
- e_hit_test_region_c->flags = mojom::kHitTestChildSurface;
- e_hit_test_region_c->frame_sink_id = c_surface_id.frame_sink_id();
- e_hit_test_region_c->rect.SetRect(100, 100, 200, 500);
+ HitTestRegion e_hit_test_region_c;
+ e_hit_test_region_c.flags = HitTestRegionFlags::kHitTestChildSurface;
+ e_hit_test_region_c.frame_sink_id = c_surface_id.frame_sink_id();
+ e_hit_test_region_c.rect.SetRect(100, 100, 200, 500);
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_c));
- e_hit_test_region_list->regions.push_back(std::move(e_hit_test_region_div));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_c));
+ e_hit_test_region_list.regions.push_back(std::move(e_hit_test_region_div));
- auto c_hit_test_region_list = mojom::HitTestRegionList::New();
- c_hit_test_region_list->flags = mojom::kHitTestMine;
- c_hit_test_region_list->bounds.SetRect(0, 0, 200, 500);
+ HitTestRegionList c_hit_test_region_list;
+ c_hit_test_region_list.flags = HitTestRegionFlags::kHitTestMine;
+ c_hit_test_region_list.bounds.SetRect(0, 0, 200, 500);
EXPECT_FALSE(hit_test_manager()->GetActiveHitTestRegionList(
local_surface_id_lookup_delegate(), e_surface_id.frame_sink_id()));
@@ -1045,7 +972,6 @@ TEST_F(HitTestAggregatorTest, DiscardedSurfaces) {
local_surface_id_lookup_delegate()->SetSurfaceIdMap(e_surface_id);
aggregator->Aggregate(e_surface_id);
- aggregator->SwapHandles();
EXPECT_TRUE(hit_test_manager()->GetActiveHitTestRegionList(
local_surface_id_lookup_delegate(), e_surface_id.frame_sink_id()));
diff --git a/chromium/components/viz/service/hit_test/hit_test_manager.cc b/chromium/components/viz/service/hit_test/hit_test_manager.cc
index 886ac9f42c3..4f3e7e1ae9d 100644
--- a/chromium/components/viz/service/hit_test/hit_test_manager.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_manager.cc
@@ -54,17 +54,19 @@ void HitTestManager::OnSurfaceActivated(
void HitTestManager::SubmitHitTestRegionList(
const SurfaceId& surface_id,
const uint64_t frame_index,
- mojom::HitTestRegionListPtr hit_test_region_list) {
- if (!ValidateHitTestRegionList(surface_id, hit_test_region_list))
+ base::Optional<HitTestRegionList> hit_test_region_list) {
+ if (!hit_test_region_list)
+ return;
+ if (!ValidateHitTestRegionList(surface_id, &*hit_test_region_list))
return;
// TODO(gklassen): Runtime validation that hit_test_region_list is valid.
// TODO(gklassen): Inform FrameSink that the hit_test_region_list is invalid.
// TODO(gklassen): FrameSink needs to inform the host of a difficult renderer.
hit_test_region_lists_[surface_id][frame_index] =
- std::move(hit_test_region_list);
+ std::move(*hit_test_region_list);
}
-const mojom::HitTestRegionList* HitTestManager::GetActiveHitTestRegionList(
+const HitTestRegionList* HitTestManager::GetActiveHitTestRegionList(
LatestLocalSurfaceIdLookupDelegate* delegate,
const FrameSinkId& frame_sink_id) const {
if (!delegate)
@@ -89,23 +91,20 @@ const mojom::HitTestRegionList* HitTestManager::GetActiveHitTestRegionList(
if (search2 == frame_index_map.end())
return nullptr;
- return search2->second.get();
+ return &search2->second;
}
bool HitTestManager::ValidateHitTestRegionList(
const SurfaceId& surface_id,
- const mojom::HitTestRegionListPtr& hit_test_region_list) {
- if (!hit_test_region_list)
- return false;
+ HitTestRegionList* hit_test_region_list) {
if (hit_test_region_list->regions.size() > kMaxRegionsPerSurface)
return false;
for (auto& region : hit_test_region_list->regions) {
// TODO(gklassen): Ensure that |region->frame_sink_id| is a child of
// |frame_sink_id|.
- if (region->frame_sink_id.client_id() == 0) {
- region->frame_sink_id =
- FrameSinkId(surface_id.frame_sink_id().client_id(),
- region->frame_sink_id.sink_id());
+ if (region.frame_sink_id.client_id() == 0) {
+ region.frame_sink_id = FrameSinkId(surface_id.frame_sink_id().client_id(),
+ region.frame_sink_id.sink_id());
}
}
return true;
diff --git a/chromium/components/viz/service/hit_test/hit_test_manager.h b/chromium/components/viz/service/hit_test/hit_test_manager.h
index 457f846c1bf..ae4ae6064ad 100644
--- a/chromium/components/viz/service/hit_test/hit_test_manager.h
+++ b/chromium/components/viz/service/hit_test/hit_test_manager.h
@@ -5,6 +5,7 @@
#ifndef COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_MANAGER_H_
#define COMPONENTS_VIZ_SERVICE_HIT_TEST_HIT_TEST_MANAGER_H_
+#include "base/optional.h"
#include "components/viz/common/hit_test/aggregated_hit_test_region.h"
#include "components/viz/common/surfaces/surface_id.h"
#include "components/viz/service/surfaces/surface_manager.h"
@@ -40,22 +41,23 @@ class VIZ_SERVICE_EXPORT HitTestManager : public SurfaceObserver {
void SubmitHitTestRegionList(
const SurfaceId& surface_id,
const uint64_t frame_index,
- mojom::HitTestRegionListPtr hit_test_region_list);
+ base::Optional<HitTestRegionList> hit_test_region_list);
// Returns the HitTestRegionList corresponding to the given
// |frame_sink_id| and the active CompositorFrame matched by frame_index.
- const mojom::HitTestRegionList* GetActiveHitTestRegionList(
+ // The returned pointer is not stable and should not be stored or used after
+ // calling any non-const methods on this class.
+ const HitTestRegionList* GetActiveHitTestRegionList(
LatestLocalSurfaceIdLookupDelegate* delegate,
const FrameSinkId& frame_sink_id) const;
private:
- bool ValidateHitTestRegionList(
- const SurfaceId& surface_id,
- const mojom::HitTestRegionListPtr& hit_test_region_list);
+ bool ValidateHitTestRegionList(const SurfaceId& surface_id,
+ HitTestRegionList* hit_test_region_list);
SurfaceManager* const surface_manager_;
- std::map<SurfaceId, base::flat_map<uint64_t, mojom::HitTestRegionListPtr>>
+ std::map<SurfaceId, base::flat_map<uint64_t, HitTestRegionList>>
hit_test_region_lists_;
DISALLOW_COPY_AND_ASSIGN(HitTestManager);
diff --git a/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc b/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc
index da94df12037..734d626750d 100644
--- a/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc
+++ b/chromium/components/viz/service/hit_test/hit_test_manager_fuzzer.cc
@@ -14,7 +14,6 @@
#include "components/viz/service/hit_test/hit_test_manager.h"
#include "components/viz/test/compositor_frame_helpers.h"
#include "components/viz/test/test_latest_local_surface_id_lookup_delegate.h"
-#include "mojo/edk/embedder/embedder.h"
namespace {
@@ -44,7 +43,7 @@ void SubmitHitTestRegionList(
const uint32_t depth);
void AddHitTestRegion(base::FuzzedDataProvider* fuzz,
- std::vector<viz::mojom::HitTestRegionPtr>* regions,
+ std::vector<viz::HitTestRegion>* regions,
uint32_t child_count,
viz::TestLatestLocalSurfaceIdLookupDelegate* delegate,
viz::FrameSinkManagerImpl* frame_sink_manager,
@@ -54,22 +53,22 @@ void AddHitTestRegion(base::FuzzedDataProvider* fuzz,
return;
// If there's not enough space left for a HitTestRegion, then skip.
- if (fuzz->remaining_bytes() < sizeof(viz::mojom::HitTestRegion))
+ if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegion))
return;
- auto hit_test_region = viz::mojom::HitTestRegion::New();
- hit_test_region->flags = fuzz->ConsumeUint16();
+ viz::HitTestRegion hit_test_region;
+ hit_test_region.flags = fuzz->ConsumeUint16();
if (fuzz->ConsumeBool())
- hit_test_region->flags |= viz::mojom::kHitTestChildSurface;
- hit_test_region->frame_sink_id =
+ hit_test_region.flags |= viz::HitTestRegionFlags::kHitTestChildSurface;
+ hit_test_region.frame_sink_id =
viz::FrameSinkId(fuzz->ConsumeUint8(), fuzz->ConsumeUint8());
- hit_test_region->rect =
+ hit_test_region.rect =
gfx::Rect(fuzz->ConsumeUint8(), fuzz->ConsumeUint8(),
fuzz->ConsumeUint16(), fuzz->ConsumeUint16());
- hit_test_region->transform = GetNextTransform(fuzz);
+ hit_test_region.transform = GetNextTransform(fuzz);
if (fuzz->ConsumeBool() &&
- (hit_test_region->flags & viz::mojom::kHitTestChildSurface)) {
+ (hit_test_region.flags & viz::HitTestRegionFlags::kHitTestChildSurface)) {
// If there's not enough space left for a LocalSurfaceId, then skip.
if (fuzz->remaining_bytes() < sizeof(viz::LocalSurfaceId))
return;
@@ -100,49 +99,40 @@ void SubmitHitTestRegionList(
bool support_is_root,
const uint32_t depth) {
// If there's not enough space left for a HitTestRegionList, then skip.
- if ((fuzz->remaining_bytes() < sizeof(viz::mojom::HitTestRegionList)) ||
+ if (fuzz->remaining_bytes() < sizeof(viz::HitTestRegionList) + sizeof(bool) ||
depth > kMaxDepthAllowed) {
return;
}
- auto hit_test_region_list = viz::mojom::HitTestRegionList::New();
- hit_test_region_list->flags = fuzz->ConsumeUint16();
- if (fuzz->ConsumeBool())
- hit_test_region_list->flags |= viz::mojom::kHitTestChildSurface;
- hit_test_region_list->bounds =
- gfx::Rect(fuzz->ConsumeUint8(), fuzz->ConsumeUint8(),
- fuzz->ConsumeUint16(), fuzz->ConsumeUint16());
- hit_test_region_list->transform = GetNextTransform(fuzz);
-
- uint32_t child_count = fuzz->ConsumeUint16();
- AddHitTestRegion(fuzz, &hit_test_region_list->regions, child_count, delegate,
- frame_sink_manager, surface_id, depth + 1);
+ base::Optional<viz::HitTestRegionList> hit_test_region_list;
+ if (fuzz->ConsumeBool()) {
+ hit_test_region_list.emplace();
+ hit_test_region_list->flags = fuzz->ConsumeUint16();
+ if (fuzz->ConsumeBool())
+ hit_test_region_list->flags |=
+ viz::HitTestRegionFlags::kHitTestChildSurface;
+ hit_test_region_list->bounds =
+ gfx::Rect(fuzz->ConsumeUint8(), fuzz->ConsumeUint8(),
+ fuzz->ConsumeUint16(), fuzz->ConsumeUint16());
+ hit_test_region_list->transform = GetNextTransform(fuzz);
+
+ uint32_t child_count = fuzz->ConsumeUint16();
+ AddHitTestRegion(fuzz, &hit_test_region_list->regions, child_count,
+ delegate, frame_sink_manager, surface_id, depth + 1);
+ }
delegate->SetSurfaceIdMap(surface_id);
viz::CompositorFrameSinkSupport support(
nullptr /* client */, frame_sink_manager, surface_id.frame_sink_id(),
support_is_root, false /* needs_sync_points */);
- support.SubmitCompositorFrame(
- surface_id.local_surface_id(), viz::MakeDefaultCompositorFrame(),
- fuzz->ConsumeBool() ? std::move(hit_test_region_list) : nullptr);
+ support.SubmitCompositorFrame(surface_id.local_surface_id(),
+ viz::MakeDefaultCompositorFrame(),
+ std::move(hit_test_region_list));
}
-class Environment {
- public:
- Environment() {
- // Initialize environment so that we can create the mojo shared memory
- // handles.
- base::CommandLine::Init(0, nullptr);
- mojo::edk::Init();
- }
-};
-
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t num_bytes) {
- // Initialize the environment only once.
- static Environment environment;
-
base::FuzzedDataProvider fuzz(data, num_bytes);
viz::FrameSinkManagerImpl frame_sink_manager;
viz::TestLatestLocalSurfaceIdLookupDelegate delegate;
diff --git a/chromium/components/viz/service/main/viz_main_impl.cc b/chromium/components/viz/service/main/viz_main_impl.cc
index 82cb08d85fc..72b26afce32 100644
--- a/chromium/components/viz/service/main/viz_main_impl.cc
+++ b/chromium/components/viz/service/main/viz_main_impl.cc
@@ -143,7 +143,9 @@ VizMainImpl::VizMainImpl(Delegate* delegate,
gpu_service_ = std::make_unique<GpuServiceImpl>(
gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_task_runner(),
- gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences());
+ gpu_init_->gpu_feature_info(), gpu_init_->gpu_preferences(),
+ gpu_init_->gpu_info_for_hardware_gpu(),
+ gpu_init_->gpu_feature_info_for_hardware_gpu());
}
VizMainImpl::~VizMainImpl() {
@@ -259,11 +261,10 @@ void VizMainImpl::CreateFrameSinkManagerInternal(
DCHECK(gpu_service_);
DCHECK(gpu_thread_task_runner_->BelongsToCurrentThread());
- constexpr bool use_virtualized_gl_context = false;
gpu_command_service_ = base::MakeRefCounted<gpu::GpuInProcessThreadService>(
- use_virtualized_gl_context, gpu_thread_task_runner_,
- gpu_service_->sync_point_manager(), gpu_service_->mailbox_manager(),
- gpu_service_->share_group(), gpu_service_->gpu_feature_info(),
+ gpu_thread_task_runner_, gpu_service_->sync_point_manager(),
+ gpu_service_->mailbox_manager(), gpu_service_->share_group(),
+ gpu_service_->gpu_feature_info(),
gpu_service_->gpu_channel_manager()->gpu_preferences());
compositor_thread_task_runner_->PostTask(
@@ -279,7 +280,7 @@ void VizMainImpl::CreateFrameSinkManagerOnCompositorThread(
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
display_provider_ = std::make_unique<GpuDisplayProvider>(
- params->restart_id, gpu_command_service_,
+ params->restart_id, gpu_service_.get(), gpu_command_service_,
gpu_service_->gpu_channel_manager(),
command_line->HasSwitch(switches::kHeadless),
command_line->HasSwitch(switches::kRunAllCompositorStagesBeforeDraw));
diff --git a/chromium/components/viz/service/main/viz_main_impl.h b/chromium/components/viz/service/main/viz_main_impl.h
index 96b04e47911..fcb3f5680ba 100644
--- a/chromium/components/viz/service/main/viz_main_impl.h
+++ b/chromium/components/viz/service/main/viz_main_impl.h
@@ -6,6 +6,7 @@
#define COMPONENTS_VIZ_SERVICE_MAIN_VIZ_MAIN_IMPL_H_
#include "base/power_monitor/power_monitor.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread.h"
#include "components/discardable_memory/client/client_discardable_shared_memory_manager.h"
#include "gpu/ipc/in_process_command_buffer.h"
diff --git a/chromium/components/viz/service/surfaces/surface.cc b/chromium/components/viz/service/surfaces/surface.cc
index de5eeb930a3..9f8a1bc373e 100644
--- a/chromium/components/viz/service/surfaces/surface.cc
+++ b/chromium/components/viz/service/surfaces/surface.cc
@@ -494,8 +494,7 @@ void Surface::NotifyAggregatedDamage(const gfx::Rect& damage_rect,
return;
active_frame_data_->aggregated_damage_callback.Run(
- surface_id().local_surface_id(),
- active_frame_data_->frame.size_in_pixels(), damage_rect,
+ surface_id().local_surface_id(), active_frame_data_->frame, damage_rect,
expected_display_time);
}
diff --git a/chromium/components/viz/service/surfaces/surface.h b/chromium/components/viz/service/surfaces/surface.h
index 4d9a63a029f..b0331b956e9 100644
--- a/chromium/components/viz/service/surfaces/surface.h
+++ b/chromium/components/viz/service/surfaces/surface.h
@@ -72,7 +72,7 @@ class VIZ_SERVICE_EXPORT Surface final : public SurfaceDeadlineClient {
public:
using AggregatedDamageCallback =
base::RepeatingCallback<void(const LocalSurfaceId& local_surface_id,
- const gfx::Size& frame_size_in_pixels,
+ const CompositorFrame& frame,
const gfx::Rect& damage_rect,
base::TimeTicks expected_display_time)>;
using PresentedCallback =
diff --git a/chromium/components/viz/service/surfaces/surface_client.h b/chromium/components/viz/service/surfaces/surface_client.h
index 7c1fcdd8299..a4d2a6a7a1d 100644
--- a/chromium/components/viz/service/surfaces/surface_client.h
+++ b/chromium/components/viz/service/surfaces/surface_client.h
@@ -10,14 +10,10 @@
#include "base/macros.h"
#include "components/viz/service/viz_service_export.h"
-namespace cc {
-struct ReturnedResource;
-struct TransferableResource;
-} // namespace cc
-
namespace viz {
-
+struct ReturnedResource;
class Surface;
+struct TransferableResource;
class VIZ_SERVICE_EXPORT SurfaceClient {
public:
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
index f60a39b08af..4e86b838144 100644
--- a/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
+++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.cc
@@ -59,7 +59,7 @@ void SurfaceDependencyDeadline::InheritFrom(
}
bool SurfaceDependencyDeadline::operator==(
- const SurfaceDependencyDeadline& other) {
+ const SurfaceDependencyDeadline& other) const {
return begin_frame_source_ == other.begin_frame_source_ &&
deadline_ == other.deadline_;
}
diff --git a/chromium/components/viz/service/surfaces/surface_dependency_deadline.h b/chromium/components/viz/service/surfaces/surface_dependency_deadline.h
index bc5913b7ed3..9c0349dfdd8 100644
--- a/chromium/components/viz/service/surfaces/surface_dependency_deadline.h
+++ b/chromium/components/viz/service/surfaces/surface_dependency_deadline.h
@@ -45,8 +45,8 @@ class VIZ_SERVICE_EXPORT SurfaceDependencyDeadline : public BeginFrameObserver {
// Takes on the same BeginFrameSource and deadline as |other|.
void InheritFrom(const SurfaceDependencyDeadline& other);
- bool operator==(const SurfaceDependencyDeadline& other);
- bool operator!=(const SurfaceDependencyDeadline& other) {
+ bool operator==(const SurfaceDependencyDeadline& other) const;
+ bool operator!=(const SurfaceDependencyDeadline& other) const {
return !(*this == other);
}
diff --git a/chromium/components/viz/service/surfaces/surface_hittest.cc b/chromium/components/viz/service/surfaces/surface_hittest.cc
index 9ba95d40956..14c50d37f84 100644
--- a/chromium/components/viz/service/surfaces/surface_hittest.cc
+++ b/chromium/components/viz/service/surfaces/surface_hittest.cc
@@ -137,13 +137,13 @@ bool SurfaceHittest::GetTargetSurfaceAtPointInternal(
continue;
}
- // If a point hits a Surface after hitting a non-Surface quad, we should
- // defer to the renderer. Some DrawQuads are not valid hit test targets
- // and information needed to distinguish them is not available here.
- if (non_surface_was_hit) {
- *out_query_renderer = true;
+ // For any point that hits a Surface, we should defer to the renderer.
+ // Some DrawQuads are not valid hit test targets and information
+ // needed to distinguish them is not available here.
+ *out_query_renderer = true;
+
+ if (non_surface_was_hit)
return true;
- }
gfx::Transform transform_to_child_space;
if (GetTargetSurfaceAtPointInternal(
diff --git a/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc b/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc
index ed2cf41fd84..e82a5050c29 100644
--- a/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc
+++ b/chromium/components/viz/service/surfaces/surface_hittest_unittest.cc
@@ -121,10 +121,10 @@ TEST_F(SurfaceHittestTest, Hittest_BadCompositorFrameDoesNotCrash) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
{
SurfaceHittest hittest(nullptr, surface_manager());
@@ -145,10 +145,10 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
TestCase tests[] = {
{root_surface_id, gfx::Point(100, 100), root_surface_id,
gfx::Point(100, 100), false},
@@ -165,8 +165,8 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) {
// Add a reference to the child surface on the root surface.
ParentLocalSurfaceIdAllocator child_allocator;
- LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
- SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
+ SurfaceId child_surface_id(kChildFrameSink,
+ child_allocator.GetCurrentLocalSurfaceId());
gfx::Rect child_rect(200, 200);
CreateSurfaceDrawQuad(
root_pass,
@@ -176,10 +176,10 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
// Creates a child surface.
RenderPass* child_pass = nullptr;
@@ -194,19 +194,19 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) {
root_rect, child_solid_quad_rect);
// Submit the frame.
- child_support().SubmitCompositorFrame(child_local_surface_id,
- std::move(child_frame));
+ child_support().SubmitCompositorFrame(
+ child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame));
TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
gfx::Point(10, 10), false},
{root_surface_id, gfx::Point(99, 99), root_surface_id,
- gfx::Point(99, 99), false},
+ gfx::Point(99, 99), true},
{root_surface_id, gfx::Point(100, 100), child_surface_id,
gfx::Point(50, 50), true},
{root_surface_id, gfx::Point(199, 199), child_surface_id,
gfx::Point(149, 149), true},
{root_surface_id, gfx::Point(200, 200), root_surface_id,
- gfx::Point(200, 200), false},
+ gfx::Point(200, 200), true},
{root_surface_id, gfx::Point(290, 290), root_surface_id,
gfx::Point(290, 290), false}};
@@ -219,8 +219,8 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) {
gfx::Transform(1.0f, 0.0f, 0.0f, 75.0f, 0.0f, 1.0f, 0.0f, 75.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f),
root_rect, child_rect, child_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
// Verify that point (100, 100) no longer falls on the child surface.
// Verify that the transform to the child surface's space has also shifted.
@@ -235,7 +235,7 @@ TEST_F(SurfaceHittestTest, Hittest_ChildSurface) {
&transform, &query_renderer));
transform.TransformPoint(&point);
EXPECT_EQ(gfx::Point(100, 100), point);
- EXPECT_EQ(query_renderer, false);
+ EXPECT_EQ(query_renderer, true);
gfx::Point point_in_target_space(100, 100);
gfx::Transform target_transform;
@@ -263,8 +263,8 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) {
// Add a reference to the child surface on the root surface.
ParentLocalSurfaceIdAllocator child_allocator;
- LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
- SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
+ SurfaceId child_surface_id(kChildFrameSink,
+ child_allocator.GetCurrentLocalSurfaceId());
gfx::Rect child_rect(200, 200);
CreateSurfaceDrawQuad(
root_pass,
@@ -274,10 +274,10 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
// Creates a child surface.
RenderPass* child_pass = nullptr;
@@ -292,8 +292,8 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) {
root_rect, child_solid_quad_rect);
// Submit the frame.
- child_support().SubmitCompositorFrame(child_local_surface_id,
- std::move(child_frame));
+ child_support().SubmitCompositorFrame(
+ child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame));
TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
gfx::Point(10, 10), false},
@@ -304,7 +304,7 @@ TEST_F(SurfaceHittestTest, Hittest_OccludedChildSurface) {
{root_surface_id, gfx::Point(199, 199), child_surface_id,
gfx::Point(149, 149), true},
{root_surface_id, gfx::Point(200, 200), root_surface_id,
- gfx::Point(200, 200), false},
+ gfx::Point(200, 200), true},
{root_surface_id, gfx::Point(290, 290), root_surface_id,
gfx::Point(290, 290), false}};
@@ -326,7 +326,8 @@ TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) {
// Add a reference to the child surface on the root surface.
ParentLocalSurfaceIdAllocator child_allocator;
- LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
+ LocalSurfaceId child_local_surface_id =
+ child_allocator.GetCurrentLocalSurfaceId();
SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
gfx::Rect child_rect(200, 200);
CreateSurfaceDrawQuad(
@@ -337,10 +338,10 @@ TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
// Creates a child surface.
RenderPass* child_pass = nullptr;
@@ -355,19 +356,19 @@ TEST_F(SurfaceHittestTest, Hittest_InvalidRenderPassDrawQuad) {
root_rect, child_solid_quad_rect);
// Submit the frame.
- child_support().SubmitCompositorFrame(child_local_surface_id,
- std::move(child_frame));
+ child_support().SubmitCompositorFrame(
+ child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame));
TestCase tests[] = {{root_surface_id, gfx::Point(10, 10), root_surface_id,
gfx::Point(10, 10), false},
{root_surface_id, gfx::Point(99, 99), root_surface_id,
- gfx::Point(99, 99), false},
+ gfx::Point(99, 99), true},
{root_surface_id, gfx::Point(100, 100), child_surface_id,
gfx::Point(50, 50), true},
{root_surface_id, gfx::Point(199, 199), child_surface_id,
gfx::Point(149, 149), true},
{root_surface_id, gfx::Point(200, 200), root_surface_id,
- gfx::Point(200, 200), false},
+ gfx::Point(200, 200), true},
{root_surface_id, gfx::Point(290, 290), root_surface_id,
gfx::Point(290, 290), false}};
@@ -409,10 +410,10 @@ TEST_F(SurfaceHittestTest, Hittest_RenderPassDrawQuad) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
TestCase tests[] = {// These tests just miss the RenderPassDrawQuad.
{root_surface_id, gfx::Point(49, 49), root_surface_id,
@@ -443,8 +444,8 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
// Add a reference to the child surface on the root surface.
ParentLocalSurfaceIdAllocator child_allocator;
- LocalSurfaceId child_local_surface_id = child_allocator.GenerateId();
- SurfaceId child_surface_id(kChildFrameSink, child_local_surface_id);
+ SurfaceId child_surface_id(kChildFrameSink,
+ child_allocator.GetCurrentLocalSurfaceId());
gfx::Rect child_rect(200, 200);
CreateSurfaceDrawQuad(
root_pass,
@@ -454,10 +455,10 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
// Submit the root frame.
ParentLocalSurfaceIdAllocator root_allocator;
- LocalSurfaceId root_local_surface_id = root_allocator.GenerateId();
- SurfaceId root_surface_id(kRootFrameSink, root_local_surface_id);
- root_support().SubmitCompositorFrame(root_local_surface_id,
- std::move(root_frame));
+ SurfaceId root_surface_id(kRootFrameSink,
+ root_allocator.GetCurrentLocalSurfaceId());
+ root_support().SubmitCompositorFrame(
+ root_allocator.GetCurrentLocalSurfaceId(), std::move(root_frame));
// Creates a child surface.
RenderPass* child_pass = nullptr;
@@ -472,8 +473,8 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
root_rect, child_solid_quad_rect);
// Submit the frame.
- child_support().SubmitCompositorFrame(child_local_surface_id,
- std::move(child_frame));
+ child_support().SubmitCompositorFrame(
+ child_allocator.GetCurrentLocalSurfaceId(), std::move(child_frame));
TestCase test_expectations_without_insets[] = {
{root_surface_id, gfx::Point(55, 55), child_surface_id, gfx::Point(5, 5),
@@ -485,9 +486,9 @@ TEST_F(SurfaceHittestTest, Hittest_SingleSurface_WithInsetsDelegate) {
{root_surface_id, gfx::Point(244, 244), child_surface_id,
gfx::Point(194, 194), true},
{root_surface_id, gfx::Point(50, 50), root_surface_id, gfx::Point(50, 50),
- false},
+ true},
{root_surface_id, gfx::Point(249, 249), root_surface_id,
- gfx::Point(249, 249), false},
+ gfx::Point(249, 249), true},
};
TestSurfaceHittestDelegate empty_delegate;
diff --git a/chromium/components/viz/test/BUILD.gn b/chromium/components/viz/test/BUILD.gn
index 95f78b14076..2b21433fffb 100644
--- a/chromium/components/viz/test/BUILD.gn
+++ b/chromium/components/viz/test/BUILD.gn
@@ -77,6 +77,7 @@ viz_static_library("test_support") {
"//testing/gtest",
"//ui/gfx/geometry",
"//ui/gl",
+ "//ui/latency:test_support",
]
}
diff --git a/chromium/components/web_contents_delegate_android/java/DEPS b/chromium/components/web_contents_delegate_android/java/DEPS
index 8ad81c20aa0..f20cebbb3be 100644
--- a/chromium/components/web_contents_delegate_android/java/DEPS
+++ b/chromium/components/web_contents_delegate_android/java/DEPS
@@ -1,7 +1,6 @@
include_rules = [
"-content/public/android/java",
"+content/public/android/java/src/org/chromium/content_public",
- "!content/public/android/java/src/org/chromium/content/browser/ContentVideoViewEmbedder.java",
"+ui/android/java",
]
diff --git a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
index 0d77a101184..33afe2048c5 100644
--- a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
+++ b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.cc
@@ -354,12 +354,14 @@ bool WebContentsDelegateAndroid::ShouldBlockMediaRequest(const GURL& url) {
void WebContentsDelegateAndroid::EnterFullscreenModeForTab(
WebContents* web_contents,
- const GURL& origin) {
+ const GURL& origin,
+ const blink::WebFullscreenOptions& options) {
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(env, obj, true);
+ Java_WebContentsDelegateAndroid_enterFullscreenModeForTab(
+ env, obj, options.prefers_navigation_bar);
}
void WebContentsDelegateAndroid::ExitFullscreenModeForTab(
@@ -368,7 +370,7 @@ void WebContentsDelegateAndroid::ExitFullscreenModeForTab(
ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
if (obj.is_null())
return;
- Java_WebContentsDelegateAndroid_toggleFullscreenModeForTab(env, obj, false);
+ Java_WebContentsDelegateAndroid_exitFullscreenModeForTab(env, obj);
}
bool WebContentsDelegateAndroid::IsFullscreenForTabOrPending(
diff --git a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h
index 81c3ae00a35..91de953e570 100644
--- a/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h
+++ b/chromium/components/web_contents_delegate_android/web_contents_delegate_android.h
@@ -105,8 +105,10 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate {
base::android::ScopedJavaLocalRef<jobject>
GetContentVideoViewEmbedder() override;
bool ShouldBlockMediaRequest(const GURL& url) override;
- void EnterFullscreenModeForTab(content::WebContents* web_contents,
- const GURL& origin) override;
+ void EnterFullscreenModeForTab(
+ content::WebContents* web_contents,
+ const GURL& origin,
+ const blink::WebFullscreenOptions& options) override;
void ExitFullscreenModeForTab(content::WebContents* web_contents) override;
bool IsFullscreenForTabOrPending(
const content::WebContents* web_contents) const override;
diff --git a/chromium/components/web_modal/web_contents_modal_dialog_manager.h b/chromium/components/web_modal/web_contents_modal_dialog_manager.h
index 4636b8c815f..5a646b8ea6a 100644
--- a/chromium/components/web_modal/web_contents_modal_dialog_manager.h
+++ b/chromium/components/web_modal/web_contents_modal_dialog_manager.h
@@ -73,6 +73,9 @@ class WebContentsModalDialogManager
DISALLOW_COPY_AND_ASSIGN(TestApi);
};
+ // Closes all WebContentsModalDialogs.
+ void CloseAllDialogs();
+
private:
explicit WebContentsModalDialogManager(content::WebContents* web_contents);
friend class content::WebContentsUserData<WebContentsModalDialogManager>;
@@ -94,9 +97,6 @@ class WebContentsModalDialogManager
bool IsWebContentsVisible() const;
- // Closes all WebContentsModalDialogs.
- void CloseAllDialogs();
-
// Overridden from content::WebContentsObserver:
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
diff --git a/chromium/components/webcrypto/algorithms/test_helpers.cc b/chromium/components/webcrypto/algorithms/test_helpers.cc
index b3144f0479c..82b151435c3 100644
--- a/chromium/components/webcrypto/algorithms/test_helpers.cc
+++ b/chromium/components/webcrypto/algorithms/test_helpers.cc
@@ -142,7 +142,7 @@ std::vector<uint8_t> MakeJsonVector(const base::DictionaryValue& dict) {
const char* test_file_name,
std::unique_ptr<base::Value>* value) {
base::FilePath test_data_dir;
- if (!PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir))
+ if (!base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir))
return ::testing::AssertionFailure() << "Couldn't retrieve test dir";
base::FilePath file_path = test_data_dir.AppendASCII("components")
diff --git a/chromium/components/webcrypto/webcrypto_impl.h b/chromium/components/webcrypto/webcrypto_impl.h
index 102bab94991..36156aab78a 100644
--- a/chromium/components/webcrypto/webcrypto_impl.h
+++ b/chromium/components/webcrypto/webcrypto_impl.h
@@ -7,6 +7,7 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
#include "third_party/blink/public/platform/web_crypto.h"
#include "third_party/blink/public/platform/web_crypto_algorithm.h"
#include "third_party/blink/public/platform/web_vector.h"
diff --git a/chromium/components/webdata/common/web_database_migration_unittest.cc b/chromium/components/webdata/common/web_database_migration_unittest.cc
index f2d34a47fd3..30cca264e69 100644
--- a/chromium/components/webdata/common/web_database_migration_unittest.cc
+++ b/chromium/components/webdata/common/web_database_migration_unittest.cc
@@ -8,7 +8,6 @@
#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
@@ -96,7 +95,7 @@ class WebDatabaseMigrationTest : public testing::Test {
// Returns true if the file exists and is read successfully, false otherwise.
bool GetWebDatabaseData(const base::FilePath& file, std::string* contents) {
base::FilePath source_path;
- PathService::Get(base::DIR_SOURCE_ROOT, &source_path);
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &source_path);
source_path = source_path.AppendASCII("components");
source_path = source_path.AppendASCII("test");
source_path = source_path.AppendASCII("data");
diff --git a/chromium/components/webdata_services/web_data_service_test_util.h b/chromium/components/webdata_services/web_data_service_test_util.h
index 95f801289c3..3d758b752d1 100644
--- a/chromium/components/webdata_services/web_data_service_test_util.h
+++ b/chromium/components/webdata_services/web_data_service_test_util.h
@@ -6,7 +6,6 @@
#define COMPONENTS_WEBDATA_SERVICES_WEB_DATA_SERVICE_TEST_UTIL_H__
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "components/signin/core/browser/webdata/token_web_data.h"
#include "components/webdata_services/web_data_service_wrapper.h"
diff --git a/chromium/components/webrtc_logging/browser/BUILD.gn b/chromium/components/webrtc_logging/browser/BUILD.gn
index b1f22936dcd..ddc7597532e 100644
--- a/chromium/components/webrtc_logging/browser/BUILD.gn
+++ b/chromium/components/webrtc_logging/browser/BUILD.gn
@@ -2,10 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//media/media_options.gni")
-
-assert(enable_webrtc)
-
source_set("browser") {
sources = [
"log_cleanup.cc",
diff --git a/chromium/components/webrtc_logging/common/BUILD.gn b/chromium/components/webrtc_logging/common/BUILD.gn
index 9df6f3b6e02..34ff3156358 100644
--- a/chromium/components/webrtc_logging/common/BUILD.gn
+++ b/chromium/components/webrtc_logging/common/BUILD.gn
@@ -2,10 +2,6 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//media/media_options.gni")
-
-assert(enable_webrtc)
-
source_set("common") {
sources = [
"partial_circular_buffer.cc",
diff --git a/chromium/components/wifi/fake_wifi_service.cc b/chromium/components/wifi/fake_wifi_service.cc
index e3a46836a0f..2db91c77636 100644
--- a/chromium/components/wifi/fake_wifi_service.cc
+++ b/chromium/components/wifi/fake_wifi_service.cc
@@ -8,7 +8,6 @@
#include <utility>
#include "base/bind.h"
-#include "base/message_loop/message_loop.h"
#include "base/values.h"
#include "components/onc/onc_constants.h"
diff --git a/chromium/components/wifi/network_properties.cc b/chromium/components/wifi/network_properties.cc
index 9d7a23181e3..1e10ff6c2d0 100644
--- a/chromium/components/wifi/network_properties.cc
+++ b/chromium/components/wifi/network_properties.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "components/onc/onc_constants.h"
diff --git a/chromium/components/wifi/wifi_service_mac.mm b/chromium/components/wifi/wifi_service_mac.mm
index c1439e2ee73..cc003b2c456 100644
--- a/chromium/components/wifi/wifi_service_mac.mm
+++ b/chromium/components/wifi/wifi_service_mac.mm
@@ -16,7 +16,6 @@
#include "base/mac/scoped_nsobject.h"
#include "base/mac/sdk_forward_declarations.h"
#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/sys_string_conversions.h"
#include "base/values.h"
diff --git a/chromium/components/wifi/wifi_service_win.cc b/chromium/components/wifi/wifi_service_win.cc
index 85b4e582666..5cf74405771 100644
--- a/chromium/components/wifi/wifi_service_win.cc
+++ b/chromium/components/wifi/wifi_service_win.cc
@@ -21,7 +21,6 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string16.h"
@@ -1000,7 +999,7 @@ void WiFiServiceImpl::SortNetworks(NetworkList* networks) {
DWORD WiFiServiceImpl::LoadWlanLibrary() {
// Use an absolute path to load the DLL to avoid DLL preloading attacks.
base::FilePath path;
- if (!PathService::Get(base::DIR_SYSTEM, &path)) {
+ if (!base::PathService::Get(base::DIR_SYSTEM, &path)) {
LOG(ERROR) << "Unable to get system path.";
return ERROR_NOT_FOUND;
}
diff --git a/chromium/components/wifi/wifi_test.cc b/chromium/components/wifi/wifi_test.cc
index 9440d64d53c..d868c608062 100644
--- a/chromium/components/wifi/wifi_test.cc
+++ b/chromium/components/wifi/wifi_test.cc
@@ -15,6 +15,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -52,7 +53,7 @@ class WiFiTest {
void Finish(Result result) {
DCHECK_NE(RESULT_PENDING, result);
result_ = result;
- if (base::MessageLoop::current())
+ if (base::MessageLoopCurrent::Get())
base::RunLoop::QuitCurrentWhenIdleDeprecated();
}
diff --git a/chromium/components/zucchini/BUILD.gn b/chromium/components/zucchini/BUILD.gn
index 6adbc9e7b47..70831275505 100644
--- a/chromium/components/zucchini/BUILD.gn
+++ b/chromium/components/zucchini/BUILD.gn
@@ -2,10 +2,26 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/buildflag_header.gni")
import("//chrome/process_version_rc_template.gni")
-import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni")
+buildflag_header("buildflags") {
+ header = "buildflags.h"
+
+ # Disable DEX on Windows Official Builds.
+ _enable_dex = !(is_win && is_official_build)
+ _enable_win = true
+
+ # Disable ZTF (Zucchini Text Format) on official builds it is for testing only.
+ _enable_ztf = !is_official_build
+ flags = [
+ "ENABLE_DEX=$_enable_dex",
+ "ENABLE_WIN=$_enable_win",
+ "ENABLE_ZTF=$_enable_ztf",
+ ]
+}
+
static_library("zucchini_lib") {
sources = [
"abs32_utils.cc",
@@ -30,6 +46,8 @@ static_library("zucchini_lib") {
"disassembler_no_op.h",
"disassembler_win32.cc",
"disassembler_win32.h",
+ "disassembler_ztf.cc",
+ "disassembler_ztf.h",
"element_detection.cc",
"element_detection.h",
"encoded_view.cc",
@@ -43,6 +61,8 @@ static_library("zucchini_lib") {
"image_index.cc",
"image_index.h",
"image_utils.h",
+ "imposed_ensemble_matcher.cc",
+ "imposed_ensemble_matcher.h",
"io_utils.cc",
"io_utils.h",
"patch_reader.cc",
@@ -50,6 +70,8 @@ static_library("zucchini_lib") {
"patch_utils.h",
"patch_writer.cc",
"patch_writer.h",
+ "reference_bytes_mixer.cc",
+ "reference_bytes_mixer.h",
"reference_set.cc",
"reference_set.h",
"rel32_finder.cc",
@@ -76,6 +98,7 @@ static_library("zucchini_lib") {
]
deps = [
+ ":buildflags",
"//base",
]
}
@@ -122,31 +145,6 @@ if (is_win) {
}
}
-# To download the corpus for local fuzzing use:
-# gsutil -m rsync \
-# gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_win32_fuzzer \
-# components/zucchini/testdata/disassembler_win32_fuzzer
-fuzzer_test("zucchini_disassembler_win32_fuzzer") {
- sources = [
- "disassembler_win32_fuzzer.cc",
- ]
- deps = [
- ":zucchini_lib",
- "//base",
- ]
-}
-
-fuzzer_test("zucchini_patch_fuzzer") {
- sources = [
- "patch_fuzzer.cc",
- ]
- deps = [
- ":zucchini_lib",
- "//base",
- ]
- seed_corpus = "testdata/patch_fuzzer"
-}
-
test("zucchini_unittests") {
sources = [
"abs32_utils_unittest.cc",
@@ -158,11 +156,13 @@ test("zucchini_unittests") {
"buffer_view_unittest.cc",
"crc32_unittest.cc",
"disassembler_dex_unittest.cc",
+ "disassembler_ztf_unittest.cc",
"element_detection_unittest.cc",
"encoded_view_unittest.cc",
"equivalence_map_unittest.cc",
"image_index_unittest.cc",
"image_utils_unittest.cc",
+ "imposed_ensemble_matcher_unittest.cc",
"io_utils_unittest.cc",
"mapped_file_unittest.cc",
"patch_read_write_unittest.cc",
@@ -208,3 +208,21 @@ test("zucchini_integration_test") {
"//testing/gtest",
]
}
+
+# Group to build and depend on all the Zucchini related fuzzers.
+group("zucchini_fuzzers") {
+ testonly = true
+ deps = [
+ "//components/zucchini/fuzzers:zucchini_disassembler_win32_fuzzer",
+ "//components/zucchini/fuzzers:zucchini_patch_fuzzer",
+ ]
+
+ # Ensure protoc is available.
+ # Disabled on Windows due to crbug/844826.
+ if (current_toolchain == host_toolchain && !is_win) {
+ deps += [
+ "//components/zucchini/fuzzers:zucchini_raw_apply_fuzzer",
+ "//components/zucchini/fuzzers:zucchini_raw_gen_fuzzer",
+ ]
+ }
+}
diff --git a/chromium/components/zucchini/README.md b/chromium/components/zucchini/README.md
index 19f8cd69861..42f3b3e9a52 100644
--- a/chromium/components/zucchini/README.md
+++ b/chromium/components/zucchini/README.md
@@ -209,8 +209,8 @@ PatchElement self contained.
Name | Format | Description
--- | --- | ---
old_offset | uint32 | Starting offset of the element in old file.
-new_offset | uint32 | Starting offset of the element in new file.
old_length | uint32 | Length of the element in old file.
+new_offset | uint32 | Starting offset of the element in new file.
new_length | uint32 | Length of the element in new file.
exe_type | uint32 | Executable type for this unit, see `enum ExecutableType`.
diff --git a/chromium/components/zucchini/disassembler_ztf.cc b/chromium/components/zucchini/disassembler_ztf.cc
new file mode 100644
index 00000000000..9f3c318fa8b
--- /dev/null
+++ b/chromium/components/zucchini/disassembler_ztf.cc
@@ -0,0 +1,647 @@
+// 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 "components/zucchini/disassembler_ztf.h"
+
+#include <algorithm>
+#include <cmath>
+#include <iterator>
+#include <numeric>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/numerics/checked_math.h"
+#include "components/zucchini/algorithm.h"
+#include "components/zucchini/buffer_source.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/io_utils.h"
+
+namespace zucchini {
+
+namespace {
+
+constexpr uint8_t kDelimiter = ',';
+
+constexpr int kHeaderMagicSize = 4;
+constexpr int kFooterMagicSize = 5;
+constexpr int kTotalMagicSize = kHeaderMagicSize + kFooterMagicSize;
+
+// Number of characters that aren't digits in each type of reference.
+constexpr int kNumConstCharInAbs = 3;
+constexpr int kNumConstCharInRel = 5;
+
+/******** ZtfConfig ********/
+
+// For passing around metadata about the type of reference to match.
+// - |digits_per_dim| is the length of the offset in lines/cols of a
+// reference.
+// - |open_char| is an ASCII character representing the opening char.
+// - |close_char| is an ASCII character representing the closing char.
+struct ZtfConfig {
+ uint8_t digits_per_dim;
+ uint8_t open_char;
+ uint8_t close_char;
+
+ constexpr uint8_t abs_width() const {
+ return digits_per_dim * 2 + kNumConstCharInAbs;
+ }
+
+ constexpr uint8_t rel_width() const {
+ return digits_per_dim * 2 + kNumConstCharInRel;
+ }
+
+ uint8_t Width(ztf::LineCol /* lc */) const { return abs_width(); }
+
+ uint8_t Width(ztf::DeltaLineCol /* dlc */) const { return rel_width(); }
+};
+
+// Creates a ZtfConfig for parsing or writing based on the desired |digits| and
+// |pool|.
+template <DisassemblerZtf::ReferencePool pool>
+constexpr ZtfConfig MakeZtfConfig(uint8_t digits) {
+ switch (pool) {
+ case DisassemblerZtf::kAngles:
+ return ZtfConfig{digits, '<', '>'};
+ case DisassemblerZtf::kBraces:
+ return ZtfConfig{digits, '{', '}'};
+ case DisassemblerZtf::kBrackets:
+ return ZtfConfig{digits, '[', ']'};
+ case DisassemblerZtf::kParentheses:
+ break; // Handled below.
+ }
+ return ZtfConfig{digits, '(', ')'};
+}
+
+/******** ZtfParser ********/
+
+// ZtfParser is used to extract (absolute) LineCol and (relative) DeltaLineCol
+// from a ZTF file, and contains various helpers for character, digits, and sign
+// matching.
+class ZtfParser {
+ public:
+ ZtfParser(offset_t hi, ConstBufferView image, ZtfConfig config)
+ : image_(image), hi_(hi), config_(config) {
+ DCHECK_LE(static_cast<size_t>(std::pow(10U, config_.digits_per_dim)),
+ ztf::kMaxDimValue);
+ }
+
+ // Attempts to match an absolute reference at |offset|. If successful then
+ // assigns the result to |abs_lc| and returns true. Otherwise returns false.
+ // An absolute reference takes the form:
+ // <open><digits><delimiter><digits><close>
+ bool MatchAtOffset(offset_t offset, ztf::LineCol* abs_lc) {
+ if (hi_ < config_.abs_width() || offset > hi_ - config_.abs_width())
+ return false;
+ offset_ = offset;
+ return MatchChar(config_.open_char) && MatchDigits(+1, &abs_lc->line) &&
+ MatchChar(kDelimiter) && MatchDigits(+1, &abs_lc->col) &&
+ MatchChar(config_.close_char);
+ }
+
+ // Attempts to match an absolute reference at |offset|. If successful then
+ // assigns the result to |rel_lc| and returns true. Otherwise returns false. A
+ // relative reference takes the form:
+ // <open><sign><digits><delimiter><sign><digits><close>
+ bool MatchAtOffset(offset_t offset, ztf::DeltaLineCol* rel_dlc) {
+ if (hi_ < config_.rel_width() || offset > hi_ - config_.rel_width())
+ return false;
+ offset_ = offset;
+ ztf::dim_t line_sign;
+ ztf::dim_t col_sign;
+ return MatchChar(config_.open_char) && MatchSign(&line_sign) &&
+ MatchDigits(line_sign, &rel_dlc->line) && MatchChar(kDelimiter) &&
+ MatchSign(&col_sign) && MatchDigits(col_sign, &rel_dlc->col) &&
+ MatchChar(config_.close_char);
+ }
+
+ private:
+ // The Match*() functions below can advance |offset_|, and return a bool to
+ // indicate success to allow chaining using &&.
+
+ // Returns true if |character| is at location |offset_| in |image_| and
+ // increments |offset_|.
+ bool MatchChar(uint8_t character) {
+ return character == image_.read<uint8_t>(offset_++);
+ }
+
+ // Looks for '+' or '-' at |offset_|. If found, stores +1 or -1 in |sign| and
+ // returns true. Otherwise returns false.
+ bool MatchSign(ztf::dim_t* sign) {
+ uint8_t val = image_.read<uint8_t>(offset_++);
+ if (val == static_cast<uint8_t>(ztf::SignChar::kMinus)) {
+ *sign = -1;
+ return true;
+ }
+ if (val == static_cast<uint8_t>(ztf::SignChar::kPlus)) {
+ *sign = 1;
+ return true;
+ }
+ return false;
+ }
+
+ // Attempts to extract a number with the number of base 10 digits equal to
+ // |config_.digits_per_dim| from |image_| starting from |offset_|. Returns
+ // true and assigns the integer value to |value| if successful.
+ bool MatchDigits(ztf::dim_t sign, ztf::dim_t* value) {
+ ztf::dim_t output = 0;
+ for (int i = 0; i < config_.digits_per_dim; ++i) {
+ auto digit = image_.read<uint8_t>(offset_++);
+ if (digit >= '0' && digit < '0' + 10)
+ output = output * 10 + digit - '0';
+ else
+ return false;
+ }
+ if (!output && sign < 0) // Disallow "-0", "-00", etc.
+ return false;
+ *value = sign * output;
+ return true;
+ }
+
+ ConstBufferView image_;
+ const offset_t hi_;
+ const ZtfConfig config_;
+ offset_t offset_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(ZtfParser);
+};
+
+/******** ZtfWriter ********/
+
+// ZtfWriter is used to write references to an image. This includes writing
+// the enclosing characters around the reference.
+class ZtfWriter {
+ public:
+ ZtfWriter(MutableBufferView image, ZtfConfig config)
+ : image_(image),
+ config_(config),
+ val_bound_(
+ static_cast<ztf::dim_t>(std::pow(10, config_.digits_per_dim))) {}
+
+ // Write an absolute reference |abs_ref| at |offset|. Note that references
+ // that would overwrite a newline are skipped as this would invalidate all
+ // the other reference line numbers.
+ void Write(offset_t offset, ztf::LineCol abs_ref) {
+ offset_ = offset;
+ if (!SafeToWriteNumber(abs_ref.line) || !SafeToWriteNumber(abs_ref.col) ||
+ !SafeToWriteData(offset_, offset_ + config_.abs_width())) {
+ return;
+ }
+ WriteChar(config_.open_char);
+ WriteNumber(abs_ref.line);
+ WriteChar(kDelimiter);
+ WriteNumber(abs_ref.col);
+ WriteChar(config_.close_char);
+ }
+
+ // Write a relative reference |rel_ref| at |offset|. Note that references
+ // that would overwrite a newline are skipped as this would invalidate all
+ // the other reference line numbers.
+ void Write(offset_t offset, ztf::DeltaLineCol rel_ref) {
+ offset_ = offset;
+ if (!SafeToWriteNumber(rel_ref.line) || !SafeToWriteNumber(rel_ref.col) ||
+ !SafeToWriteData(offset_, offset_ + config_.rel_width())) {
+ return;
+ }
+ WriteChar(config_.open_char);
+ WriteSign(rel_ref.line);
+ WriteNumber(rel_ref.line);
+ WriteChar(kDelimiter);
+ WriteSign(rel_ref.col);
+ WriteNumber(rel_ref.col);
+ WriteChar(config_.close_char);
+ }
+
+ private:
+ // Returns whether it is safe to modify bytes in |[lo, hi)| in |image_| for
+ // Reference correction. Failure cases are:
+ // - Out-of-bound writes.
+ // - Overwriting '\n'. This is a ZTF special case since '\n' dictates file
+ // structure, and Reference correction should never mess with this.
+ bool SafeToWriteData(offset_t lo, offset_t hi) const {
+ DCHECK_LE(lo, hi);
+ // Out of bounds.
+ if (hi > image_.size())
+ return false;
+ for (offset_t i = lo; i < hi; ++i) {
+ if (image_.read<uint8_t>(i) == '\n')
+ return false;
+ }
+ return true;
+ }
+
+ // Checks whether it is safe to write a |val| based on
+ // |config_.digits_per_dim|.
+ bool SafeToWriteNumber(ztf::dim_t val) const {
+ return std::abs(val) < val_bound_;
+ }
+
+ // The Write*() functions each advance |offset_| by a fixed distance. The
+ // caller should ensure there's enough space to write data.
+
+ // Write |character| at |offset_| and increment |offset_|.
+ void WriteChar(uint8_t character) { image_.write(offset_++, character); }
+
+ // Write the sign of |value| at |offset_| and increment |offset_|.
+ void WriteSign(ztf::dim_t value) {
+ image_.write(offset_++,
+ value >= 0 ? ztf::SignChar::kPlus : ztf::SignChar::kMinus);
+ }
+
+ // Writes the absolute value of the number represented by |value| at |offset_|
+ // using zero padding to fill |config_.digits_per_dim|.
+ void WriteNumber(ztf::dim_t value) {
+ size_t size = config_.digits_per_dim + 1;
+ DCHECK_LE(size, kMaxDigitCount + 1);
+ char digits[kMaxDigitCount + 1]; // + 1 for terminator.
+ int len =
+ snprintf(digits, size, "%0*u", config_.digits_per_dim, std::abs(value));
+ DCHECK_EQ(len, config_.digits_per_dim);
+ for (int i = 0; i < len; ++i)
+ image_.write(offset_++, digits[i]);
+ }
+
+ MutableBufferView image_;
+ const ZtfConfig config_;
+ // Bound on numeric values, as limited by |config_.digits_per_dim|.
+ const ztf::dim_t val_bound_;
+ offset_t offset_ = 0;
+ DISALLOW_COPY_AND_ASSIGN(ZtfWriter);
+};
+
+// Specialization of ReferenceReader for reading text references.
+template <typename T>
+class ZtfReferenceReader : public ReferenceReader {
+ public:
+ ZtfReferenceReader(offset_t lo,
+ offset_t hi,
+ ConstBufferView image,
+ const ZtfTranslator& translator,
+ ZtfConfig config)
+ : offset_(lo),
+ hi_(hi),
+ translator_(translator),
+ config_(config),
+ parser_(hi_, image, config_) {
+ DCHECK_LE(hi_, image.size());
+ }
+
+ // Walks |offset_| from |lo| to |hi_| running |parser_|. If any matches are
+ // found they are returned.
+ base::Optional<Reference> GetNext() override {
+ T line_col;
+ for (; offset_ < hi_; ++offset_) {
+ if (!parser_.MatchAtOffset(offset_, &line_col))
+ continue;
+
+ auto target = ConvertToTargetOffset(offset_, line_col);
+ // Ignore targets that point outside the file.
+ if (target == kInvalidOffset)
+ continue;
+ offset_t location = offset_;
+ offset_ += config_.Width(line_col);
+ return Reference{location, target};
+ }
+ return base::nullopt;
+ }
+
+ private:
+ // Converts |lc| (an absolute reference) to an offset using |translator_|.
+ offset_t ConvertToTargetOffset(offset_t /* location */,
+ ztf::LineCol lc) const {
+ return translator_.LineColToOffset(lc);
+ }
+
+ // Converts |dlc| (a relative reference) to an offset using |translator_|.
+ // This requires converting the |dlc| to a ztf::LineCol to find the offset.
+ offset_t ConvertToTargetOffset(offset_t location,
+ ztf::DeltaLineCol dlc) const {
+ auto lc = translator_.OffsetToLineCol(location);
+ if (!lc.has_value())
+ return kInvalidOffset;
+ return translator_.LineColToOffset(lc.value() + dlc);
+ }
+
+ offset_t offset_;
+ const offset_t hi_;
+ const ZtfTranslator& translator_;
+ const ZtfConfig config_;
+ ZtfParser parser_;
+};
+
+// Specialization of ReferenceWriter for writing text references.
+template <typename T>
+class ZtfReferenceWriter : public ReferenceWriter {
+ public:
+ ZtfReferenceWriter(MutableBufferView image,
+ const ZtfTranslator& translator,
+ ZtfConfig config)
+ : translator_(translator), writer_(image, config) {}
+
+ void PutNext(Reference reference) override {
+ T line_col;
+ if (!ConvertToTargetLineCol(reference, &line_col))
+ return;
+
+ writer_.Write(reference.location, line_col);
+ }
+
+ private:
+ // Converts |reference| to an absolute reference to be stored in |out_lc|.
+ // Returns true on success.
+ bool ConvertToTargetLineCol(Reference reference, ztf::LineCol* out_lc) {
+ auto temp_lc = translator_.OffsetToLineCol(reference.target);
+ if (!temp_lc.has_value() || !translator_.IsValid(temp_lc.value()))
+ return false;
+
+ *out_lc = temp_lc.value();
+ return true;
+ }
+
+ // Converts |reference| to a relative reference to be stored in |out_dlc|.
+ // Will return true on success.
+ bool ConvertToTargetLineCol(Reference reference, ztf::DeltaLineCol* out_dlc) {
+ auto location_lc = translator_.OffsetToLineCol(reference.location);
+ if (!location_lc.has_value())
+ return false;
+
+ auto target_lc = translator_.OffsetToLineCol(reference.target);
+ if (!target_lc.has_value())
+ return false;
+
+ *out_dlc = target_lc.value() - location_lc.value();
+ return translator_.IsValid(reference.location, *out_dlc);
+ }
+
+ const ZtfTranslator& translator_;
+ ZtfWriter writer_;
+};
+
+// Reads a text header to check for the magic string "ZTxt" at the start
+// indicating the file should be treated as a Zucchini text file.
+bool ReadZtfHeader(ConstBufferView image) {
+ BufferSource source(image);
+ // Reject empty images and "ZTxtxTZ\n" (missing 't').
+ if (source.size() < kTotalMagicSize)
+ return false;
+ return source.CheckNextBytes({'Z', 'T', 'x', 't'});
+}
+
+} // namespace
+
+/******** ZtfTranslator ********/
+
+ZtfTranslator::ZtfTranslator() {}
+
+ZtfTranslator::~ZtfTranslator() = default;
+
+bool ZtfTranslator::Init(ConstBufferView image) {
+ line_starts_.clear();
+ // Record the starting offset of every line in |image_| into |line_start_|.
+ line_starts_.push_back(0);
+ for (size_t i = 0; i < image.size(); ++i) {
+ if (image.read<uint8_t>(i) == '\n') {
+ // Maximum number of entries is |ztf::kMaxDimValue|, including the end
+ // sentinel.
+ if (line_starts_.size() >= ztf::kMaxDimValue)
+ return false;
+ line_starts_.push_back(i + 1);
+ // Check that the line length is reachable from an absolute reference.
+ if (line_starts_.back() - *std::next(line_starts_.rbegin()) >=
+ ztf::kMaxDimValue) {
+ return false;
+ }
+ }
+ }
+ // Since the last character of ZTF file is always '\n', |line_starts_| will
+ // always contain the file length as the last element, which serves as a
+ // sentinel.
+ CHECK_EQ(image.size(), static_cast<size_t>(line_starts_.back()));
+ return true;
+}
+
+bool ZtfTranslator::IsValid(ztf::LineCol lc) const {
+ DCHECK(!line_starts_.empty());
+ return lc.line >= 1 && lc.col >= 1 &&
+ static_cast<offset_t>(lc.line) <= NumLines() &&
+ static_cast<offset_t>(lc.col) <= LineLength(lc.line);
+}
+
+bool ZtfTranslator::IsValid(offset_t offset, ztf::DeltaLineCol dlc) const {
+ DCHECK(!line_starts_.empty());
+ auto abs_lc = OffsetToLineCol(offset);
+ if (!abs_lc.has_value())
+ return false;
+
+ if (!base::CheckAdd(abs_lc->line, dlc.line).IsValid() ||
+ !base::CheckAdd(abs_lc->col, dlc.col).IsValid()) {
+ return false;
+ }
+ return IsValid(abs_lc.value() + dlc);
+}
+
+offset_t ZtfTranslator::LineColToOffset(ztf::LineCol lc) const {
+ // Guard against out of bounds access to |line_starts_| and ensure the
+ // |lc| falls within the file.
+ DCHECK(!line_starts_.empty());
+ if (!IsValid(lc))
+ return kInvalidOffset;
+
+ offset_t target = line_starts_[lc.line - 1] + lc.col - 1;
+ DCHECK_LT(target, line_starts_.back());
+ return target;
+}
+
+base::Optional<ztf::LineCol> ZtfTranslator::OffsetToLineCol(
+ offset_t offset) const {
+ DCHECK(!line_starts_.empty());
+ // Don't place a target outside the image.
+ if (offset >= line_starts_.back())
+ return base::nullopt;
+ auto it = SearchForRange(offset);
+ ztf::LineCol lc;
+ lc.line = std::distance(line_starts_.cbegin(), it) + 1;
+ lc.col = offset - line_starts_[lc.line - 1] + 1;
+ DCHECK_LE(static_cast<offset_t>(lc.col), LineLength(lc.line));
+ return lc;
+}
+
+std::vector<offset_t>::const_iterator ZtfTranslator::SearchForRange(
+ offset_t offset) const {
+ DCHECK(!line_starts_.empty());
+ auto it =
+ std::upper_bound(line_starts_.cbegin(), line_starts_.cend(), offset);
+ DCHECK(it != line_starts_.cbegin());
+ return --it;
+}
+
+offset_t ZtfTranslator::LineLength(uint16_t line) const {
+ DCHECK_GE(line, 1);
+ DCHECK_LE(line, NumLines());
+ return line_starts_[line] - line_starts_[line - 1];
+}
+
+/******** DisassemblerZtf ********/
+
+// Use 2 even though reference "chaining" isn't present in ZTF as it is the
+// usual case for other Disassemblers and this is meant to mimic that as closely
+// as possible.
+DisassemblerZtf::DisassemblerZtf() : Disassembler(2) {}
+
+DisassemblerZtf::~DisassemblerZtf() = default;
+
+// static.
+bool DisassemblerZtf::QuickDetect(ConstBufferView image) {
+ return ReadZtfHeader(image);
+}
+
+ExecutableType DisassemblerZtf::GetExeType() const {
+ return kExeTypeZtf;
+}
+
+std::string DisassemblerZtf::GetExeTypeString() const {
+ return "Zucchini Text Format";
+}
+
+std::vector<ReferenceGroup> DisassemblerZtf::MakeReferenceGroups() const {
+ return {
+ {{5, TypeTag(kAnglesAbs1), PoolTag(kAngles)},
+ &DisassemblerZtf::MakeReadAbs<1, kAngles>,
+ &DisassemblerZtf::MakeWriteAbs<1, kAngles>},
+ {{7, TypeTag(kAnglesAbs2), PoolTag(kAngles)},
+ &DisassemblerZtf::MakeReadAbs<2, kAngles>,
+ &DisassemblerZtf::MakeWriteAbs<2, kAngles>},
+ {{9, TypeTag(kAnglesAbs3), PoolTag(kAngles)},
+ &DisassemblerZtf::MakeReadAbs<3, kAngles>,
+ &DisassemblerZtf::MakeWriteAbs<3, kAngles>},
+ {{7, TypeTag(kAnglesRel1), PoolTag(kAngles)},
+ &DisassemblerZtf::MakeReadRel<1, kAngles>,
+ &DisassemblerZtf::MakeWriteRel<1, kAngles>},
+ {{9, TypeTag(kAnglesRel2), PoolTag(kAngles)},
+ &DisassemblerZtf::MakeReadRel<2, kAngles>,
+ &DisassemblerZtf::MakeWriteRel<2, kAngles>},
+ {{11, TypeTag(kAnglesRel3), PoolTag(kAngles)},
+ &DisassemblerZtf::MakeReadRel<3, kAngles>,
+ &DisassemblerZtf::MakeWriteRel<3, kAngles>},
+ {{5, TypeTag(kBracesAbs1), PoolTag(kBraces)},
+ &DisassemblerZtf::MakeReadAbs<1, kBraces>,
+ &DisassemblerZtf::MakeWriteAbs<1, kBraces>},
+ {{7, TypeTag(kBracesAbs2), PoolTag(kBraces)},
+ &DisassemblerZtf::MakeReadAbs<2, kBraces>,
+ &DisassemblerZtf::MakeWriteAbs<2, kBraces>},
+ {{9, TypeTag(kBracesAbs3), PoolTag(kBraces)},
+ &DisassemblerZtf::MakeReadAbs<3, kBraces>,
+ &DisassemblerZtf::MakeWriteAbs<3, kBraces>},
+ {{7, TypeTag(kBracesRel1), PoolTag(kBraces)},
+ &DisassemblerZtf::MakeReadRel<1, kBraces>,
+ &DisassemblerZtf::MakeWriteRel<1, kBraces>},
+ {{9, TypeTag(kBracesRel2), PoolTag(kBraces)},
+ &DisassemblerZtf::MakeReadRel<2, kBraces>,
+ &DisassemblerZtf::MakeWriteRel<2, kBraces>},
+ {{11, TypeTag(kBracesRel3), PoolTag(kBraces)},
+ &DisassemblerZtf::MakeReadRel<3, kBraces>,
+ &DisassemblerZtf::MakeWriteRel<3, kBraces>},
+ {{5, TypeTag(kBracketsAbs1), PoolTag(kBrackets)},
+ &DisassemblerZtf::MakeReadAbs<1, kBrackets>,
+ &DisassemblerZtf::MakeWriteAbs<1, kBrackets>},
+ {{7, TypeTag(kBracketsAbs2), PoolTag(kBrackets)},
+ &DisassemblerZtf::MakeReadAbs<2, kBrackets>,
+ &DisassemblerZtf::MakeWriteAbs<2, kBrackets>},
+ {{9, TypeTag(kBracketsAbs3), PoolTag(kBrackets)},
+ &DisassemblerZtf::MakeReadAbs<3, kBrackets>,
+ &DisassemblerZtf::MakeWriteAbs<3, kBrackets>},
+ {{7, TypeTag(kBracketsRel1), PoolTag(kBrackets)},
+ &DisassemblerZtf::MakeReadRel<1, kBrackets>,
+ &DisassemblerZtf::MakeWriteRel<1, kBrackets>},
+ {{9, TypeTag(kBracketsRel2), PoolTag(kBrackets)},
+ &DisassemblerZtf::MakeReadRel<2, kBrackets>,
+ &DisassemblerZtf::MakeWriteRel<2, kBrackets>},
+ {{11, TypeTag(kBracketsRel3), PoolTag(kBrackets)},
+ &DisassemblerZtf::MakeReadRel<3, kBrackets>,
+ &DisassemblerZtf::MakeWriteRel<3, kBrackets>},
+ {{5, TypeTag(kParenthesesAbs1), PoolTag(kParentheses)},
+ &DisassemblerZtf::MakeReadAbs<1, kParentheses>,
+ &DisassemblerZtf::MakeWriteAbs<1, kParentheses>},
+ {{7, TypeTag(kParenthesesAbs2), PoolTag(kParentheses)},
+ &DisassemblerZtf::MakeReadAbs<2, kParentheses>,
+ &DisassemblerZtf::MakeWriteAbs<2, kParentheses>},
+ {{9, TypeTag(kParenthesesAbs3), PoolTag(kParentheses)},
+ &DisassemblerZtf::MakeReadAbs<3, kParentheses>,
+ &DisassemblerZtf::MakeWriteAbs<3, kParentheses>},
+ {{7, TypeTag(kParenthesesRel1), PoolTag(kParentheses)},
+ &DisassemblerZtf::MakeReadRel<1, kParentheses>,
+ &DisassemblerZtf::MakeWriteRel<1, kParentheses>},
+ {{9, TypeTag(kParenthesesRel2), PoolTag(kParentheses)},
+ &DisassemblerZtf::MakeReadRel<2, kParentheses>,
+ &DisassemblerZtf::MakeWriteRel<2, kParentheses>},
+ {{11, TypeTag(kParenthesesRel3), PoolTag(kParentheses)},
+ &DisassemblerZtf::MakeReadRel<3, kParentheses>,
+ &DisassemblerZtf::MakeWriteRel<3, kParentheses>},
+ };
+}
+
+template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
+std::unique_ptr<ReferenceReader> DisassemblerZtf::MakeReadAbs(offset_t lo,
+ offset_t hi) {
+ static_assert(digits >= 1 && digits <= kMaxDigitCount,
+ "|digits| must be in range [1, 3]");
+ return std::make_unique<ZtfReferenceReader<ztf::LineCol>>(
+ lo, hi, image_, translator_, MakeZtfConfig<pool>(digits));
+}
+
+template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
+std::unique_ptr<ReferenceReader> DisassemblerZtf::MakeReadRel(offset_t lo,
+ offset_t hi) {
+ static_assert(digits >= 1 && digits <= kMaxDigitCount,
+ "|digits| must be in range [1, 3]");
+ return std::make_unique<ZtfReferenceReader<ztf::DeltaLineCol>>(
+ lo, hi, image_, translator_, MakeZtfConfig<pool>(digits));
+}
+
+template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
+std::unique_ptr<ReferenceWriter> DisassemblerZtf::MakeWriteAbs(
+ MutableBufferView image) {
+ static_assert(digits >= 1 && digits <= kMaxDigitCount,
+ "|digits| must be in range [1, 3]");
+ return std::make_unique<ZtfReferenceWriter<ztf::LineCol>>(
+ image, translator_, MakeZtfConfig<pool>(digits));
+}
+
+template <uint8_t digits, DisassemblerZtf::ReferencePool pool>
+std::unique_ptr<ReferenceWriter> DisassemblerZtf::MakeWriteRel(
+ MutableBufferView image) {
+ static_assert(digits >= 1 && digits <= kMaxDigitCount,
+ "|digits| must be in range [1, 3]");
+ return std::make_unique<ZtfReferenceWriter<ztf::DeltaLineCol>>(
+ image, translator_, MakeZtfConfig<pool>(digits));
+}
+
+bool DisassemblerZtf::Parse(ConstBufferView image) {
+ image_ = image;
+ if (!ReadZtfHeader(image_))
+ return false;
+
+ CHECK_GE(image_.size(),
+ static_cast<size_t>(kTotalMagicSize)); // Needs header and footer.
+
+ // Find the terminating footer "txTZ\n" that indicates the end of the image.
+ offset_t offset = 0;
+ for (; offset <= image_.size() - kFooterMagicSize; offset++) {
+ if (image_.read<uint8_t>(offset) == 't' &&
+ image_.read<uint8_t>(offset + 1) == 'x' &&
+ image_.read<uint8_t>(offset + 2) == 'T' &&
+ image_.read<uint8_t>(offset + 3) == 'Z' &&
+ image_.read<uint8_t>(offset + 4) == '\n') {
+ break;
+ }
+ }
+
+ // If no footer is found before the end of the image then the parsing failed.
+ if (offset > image_.size() - kFooterMagicSize)
+ return false;
+ image_.shrink(offset + kFooterMagicSize);
+
+ return translator_.Init(image_);
+}
+
+} // namespace zucchini
diff --git a/chromium/components/zucchini/disassembler_ztf.h b/chromium/components/zucchini/disassembler_ztf.h
new file mode 100644
index 00000000000..0719093792d
--- /dev/null
+++ b/chromium/components/zucchini/disassembler_ztf.h
@@ -0,0 +1,201 @@
+// 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 COMPONENTS_ZUCCHINI_DISASSEMBLER_ZTF_H_
+#define COMPONENTS_ZUCCHINI_DISASSEMBLER_ZTF_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/optional.h"
+#include "components/zucchini/disassembler.h"
+#include "components/zucchini/image_utils.h"
+#include "components/zucchini/type_ztf.h"
+
+namespace zucchini {
+
+// Disassembler for text based files. This file format is supported for
+// debugging Zucchini and is not intended for production usage.
+//
+// A valid Zucchini Text Format (ZTF) file is specified as follows:
+//
+// Header:
+// The first four bytes must be - 'Z' 'T' 'x' 't'
+// Footer:
+// The last five bytes must be - 't' 'x' 'T' 'Z' '\n'
+// (note that terminating new line is required).
+// Content:
+// The content can be any sequence of printable ASCII characters and new line
+// (but not carriage return). This excludes the sequence that comprises the
+// Footer.
+// References:
+// A reference is either Absolute or Relative. All references must begin and
+// end with a pair of enclosing characters <open>, <close>. The options are:
+// - Angles: '<' and '>'
+// - Braces: '{' and '}'
+// - Brackets: '[' and ']'
+// - Parentheses: '(' and ')'
+//
+// A reference contains three items:
+// - A line number <line>
+// - A delimiter ',' <delimiter>
+// - A column number <col>
+// <line> and <col> may contain 1-3 digits and both must contain the same
+// number of digits. If a number is too short then it can be left-padded
+// with '0'.
+//
+// For Absolute references, <line> and <col> are 1-based (i.e. positive)
+// index of line and column numbers of a character in the ZTF. This follows
+// standard convention for text editors. Note that "\n" is considered to be
+// part of a preceding line.
+//
+// <open><line><delimiter><col><close>
+//
+// For Relative references, <line> and <col> are integer offsets deltas of the
+// target's (absolute) line and column relative to the line and column of the
+// reference's first byte (i.e. <open>). Relative references have <sign> ('+'
+// or '-') before <line> and <col>. For the special case of "0", "00", etc.,
+// <sign> must be "+".
+//
+// <open><sign><line><delimiter><sign><col><close>
+//
+// If a reference points outside the target either in writing or reading it is
+// considered invalid and ignored. Similarly if it overflows a line. i.e. if a
+// line is 10 characters long and a references targets character 11 of that
+// line it is rejected. Lines are delimited with '\n' which is counted toward
+// the line length.
+//
+// If a reference is to be written that would overwrite a '\n' character it is
+// ignored as this would break all other line values.
+
+enum : size_t { kMaxDigitCount = 3 };
+
+// Helper class for translating among offset_t, ztf::LineCol and
+// ztf::DeltaLineCol.
+class ZtfTranslator {
+ public:
+ ZtfTranslator();
+ ~ZtfTranslator();
+
+ // Initializes |line_starts_| with the contents of |image|.
+ bool Init(ConstBufferView image);
+
+ // Checks if |lc| is a valid location in the file.
+ bool IsValid(ztf::LineCol lc) const;
+
+ // Checks if |dlc| relative to |offset| is a valid location in the file.
+ bool IsValid(offset_t offset, ztf::DeltaLineCol dlc) const;
+
+ // Returns the offset corresponding to |line_col| if it is valid. Otherwise
+ // returns |kInvalidOffset|.
+ offset_t LineColToOffset(ztf::LineCol line_col) const;
+
+ // Returns the ztf::LineCol for an |offset| if it is valid. Otherwise returns
+ // base::nullopt.
+ base::Optional<ztf::LineCol> OffsetToLineCol(offset_t offset) const;
+
+ private:
+ // Returns an iterator to the range containing |offset|. Which is represented
+ // by the starting offset. The next element will contain the upper bound of
+ // the range.
+ std::vector<offset_t>::const_iterator SearchForRange(offset_t offset) const;
+
+ // Returns the length of a 1-indexed line. The caller is expected to check
+ // that the requested line exists.
+ offset_t LineLength(uint16_t line) const;
+
+ offset_t NumLines() const {
+ return static_cast<offset_t>(line_starts_.size() - 1);
+ }
+
+ // |line_starts_| is a sorted list of each line's starting offset, along with
+ // the image size as the sentinel; it looks like {0, ..., image.size}.
+ std::vector<offset_t> line_starts_;
+ DISALLOW_COPY_AND_ASSIGN(ZtfTranslator);
+};
+
+// Disassembler for Zucchini Text Format (ZTF).
+class DisassemblerZtf : public Disassembler {
+ public:
+ // Target Pools
+ enum ReferencePool : uint8_t {
+ kAngles, // <>
+ kBraces, // {}
+ kBrackets, // []
+ kParentheses // ()
+ };
+
+ // Type breakdown. Should contain all permutations of ReferencePool, Abs|Rel
+ // and the possible number of digits (1-3).
+ enum ReferenceType : uint8_t {
+ kAnglesAbs1,
+ kAnglesAbs2,
+ kAnglesAbs3,
+ kAnglesRel1,
+ kAnglesRel2,
+ kAnglesRel3,
+ kBracesAbs1,
+ kBracesAbs2,
+ kBracesAbs3,
+ kBracesRel1,
+ kBracesRel2,
+ kBracesRel3,
+ kBracketsAbs1,
+ kBracketsAbs2,
+ kBracketsAbs3,
+ kBracketsRel1,
+ kBracketsRel2,
+ kBracketsRel3,
+ kParenthesesAbs1,
+ kParenthesesAbs2,
+ kParenthesesAbs3,
+ kParenthesesRel1,
+ kParenthesesRel2,
+ kParenthesesRel3,
+ kNumTypes
+ };
+
+ DisassemblerZtf();
+ ~DisassemblerZtf() override;
+
+ // Applies quick checks to determine if |image| *may* point to the start of a
+ // ZTF file. Returns true on success.
+ static bool QuickDetect(ConstBufferView image);
+
+ // Disassembler:
+ ExecutableType GetExeType() const override;
+ std::string GetExeTypeString() const override;
+ std::vector<ReferenceGroup> MakeReferenceGroups() const override;
+
+ // Reference Readers, templated to allow configurable digit count and pool.
+ template <uint8_t digits, ReferencePool pool>
+ std::unique_ptr<ReferenceReader> MakeReadAbs(offset_t lo, offset_t hi);
+ template <uint8_t digits, ReferencePool pool>
+ std::unique_ptr<ReferenceReader> MakeReadRel(offset_t lo, offset_t hi);
+
+ // Reference Writers, templated to allow configurable digit count and pool.
+ template <uint8_t digits, ReferencePool pool>
+ std::unique_ptr<ReferenceWriter> MakeWriteAbs(MutableBufferView image);
+ template <uint8_t digits, ReferencePool pool>
+ std::unique_ptr<ReferenceWriter> MakeWriteRel(MutableBufferView image);
+
+ private:
+ friend Disassembler;
+
+ // Disassembler:
+ bool Parse(ConstBufferView image) override;
+
+ ZtfTranslator translator_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisassemblerZtf);
+};
+
+} // namespace zucchini
+
+#endif // COMPONENTS_ZUCCHINI_DISASSEMBLER_ZTF_H_
diff --git a/chromium/components/zucchini/disassembler_ztf_unittest.cc b/chromium/components/zucchini/disassembler_ztf_unittest.cc
new file mode 100644
index 00000000000..1e713592777
--- /dev/null
+++ b/chromium/components/zucchini/disassembler_ztf_unittest.cc
@@ -0,0 +1,402 @@
+// 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 "components/zucchini/disassembler_ztf.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/strings/string_piece.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/element_detection.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace zucchini {
+
+namespace {
+
+constexpr char kNormalText[] = R"(ZTxt
+Hello World!
+This is an example of an absolute reference <<1,1>>
+And {-01,+05} is an example of a relative ref
+txTZ
+TRAILING DATA)";
+// -1 to exclude null byte.
+constexpr size_t kNormalTextExtraBytes = base::size("TRAILING DATA") - 1;
+
+constexpr char kOutOfBoundsText[] = R"(ZTxt<1,1>
+Hello World!
+This is an example of an OOB absolute reference <890,605>
+And {-050,+100} is an example of an OOB relative ref.
+but [+00,+10] is valid at least. As is (1,5).
+<1, 6> and { ,1} aren't nor is {4,5]
+{7,6}<1,1><2,3>{+00,+00}{004,100}[+00,+60][+000,-100]<-000,-035>(-00,-00)txTZ
+)";
+
+// Converts a raw string into data.
+std::vector<uint8_t> StrToData(base::StringPiece s) {
+ return std::vector<uint8_t>(s.begin(), s.end());
+}
+
+// Compare if |a.location < b.location| as references have unique locations.
+struct ReferenceCompare {
+ bool operator()(const Reference& a, const Reference& b) const {
+ return a.location < b.location;
+ }
+};
+
+using ReferenceKey =
+ std::pair<DisassemblerZtf::ReferencePool, DisassemblerZtf::ReferenceType>;
+using ReferenceSets =
+ std::map<ReferenceKey, std::set<Reference, ReferenceCompare>>;
+
+// Write references in |refs_to_write| to |image|. Also validate the
+// disassembler parses |image| such that it is of |expected_size|.
+void WriteReferences(MutableBufferView image,
+ size_t expected_size,
+ const ReferenceSets& refs_to_write) {
+ EXPECT_TRUE(DisassemblerZtf::QuickDetect(image));
+ std::unique_ptr<DisassemblerZtf> dis =
+ Disassembler::Make<DisassemblerZtf>(image);
+ EXPECT_TRUE(dis);
+ EXPECT_EQ(expected_size, dis->size());
+ image.shrink(dis->size());
+ auto reference_groups = dis->MakeReferenceGroups();
+ for (const auto& group : reference_groups) {
+ auto writer = group.GetWriter(image, dis.get());
+ ReferenceKey key = {
+ static_cast<DisassemblerZtf::ReferencePool>(group.pool_tag().value()),
+ static_cast<DisassemblerZtf::ReferenceType>(group.type_tag().value())};
+ if (!refs_to_write.count(key))
+ continue;
+ for (const auto& ref : refs_to_write.at(key))
+ writer->PutNext(ref);
+ }
+}
+
+// Read references in |refs_to_read| from |image|. Once found
+// the elements are removed from |refs_to_read|. Also validate the
+// disassembler parses |image| such that it is of |expected_size|.
+void ReadReferences(ConstBufferView image,
+ size_t expected_size,
+ ReferenceSets* refs_to_read) {
+ EXPECT_TRUE(DisassemblerZtf::QuickDetect(image));
+ std::unique_ptr<DisassemblerZtf> dis =
+ Disassembler::Make<DisassemblerZtf>(image);
+ EXPECT_TRUE(dis);
+ EXPECT_EQ(expected_size, dis->size());
+ auto reference_groups = dis->MakeReferenceGroups();
+ for (const auto& group : reference_groups) {
+ auto reader = group.GetReader(dis.get());
+ ReferenceKey key = {
+ static_cast<DisassemblerZtf::ReferencePool>(group.pool_tag().value()),
+ static_cast<DisassemblerZtf::ReferenceType>(group.type_tag().value())};
+ if (!refs_to_read->count(key)) {
+ // No elements of this pool/type pair are expected so assert that none are
+ // found.
+ auto ref = reader->GetNext();
+ EXPECT_FALSE(ref.has_value());
+ continue;
+ }
+ // For each reference remove it from the set if it exists, error if
+ // unexpected references are found.
+ for (auto ref = reader->GetNext(); ref.has_value();
+ ref = reader->GetNext()) {
+ EXPECT_EQ(1UL, refs_to_read->at(key).erase(ref.value()));
+ }
+ EXPECT_EQ(0U, refs_to_read->at(key).size());
+ }
+}
+
+void TestTranslation(const ZtfTranslator& translator,
+ offset_t expected_location,
+ ztf::LineCol lc) {
+ // Check the lc is translated to the expected location.
+ EXPECT_EQ(expected_location, translator.LineColToOffset(lc));
+ auto new_lc = translator.OffsetToLineCol(expected_location);
+ if (expected_location == kInvalidOffset) {
+ EXPECT_FALSE(translator.IsValid(lc));
+ EXPECT_FALSE(new_lc.has_value());
+ } else {
+ EXPECT_TRUE(translator.IsValid(lc));
+ // Check that the reverse is true. |ztf::LineCol{0, 0}| is a sentinel and
+ // should never be valid.
+ EXPECT_EQ(lc.line, new_lc->line);
+ EXPECT_EQ(lc.col, new_lc->col);
+ }
+}
+
+template <typename T>
+size_t CountDistinct(const std::vector<T>& v) {
+ return std::set<T>(v.begin(), v.end()).size();
+}
+
+} // namespace
+
+TEST(ZtfTranslatorTest, Translate) {
+ ztf::dim_t kMaxVal = INT16_MAX;
+ ztf::dim_t kMinVal = INT16_MIN;
+
+ const std::vector<uint8_t> text(StrToData(kOutOfBoundsText));
+ ConstBufferView image(text.data(), text.size());
+ ZtfTranslator translator;
+ EXPECT_TRUE(translator.Init(image));
+
+ // Absolute Translations:
+
+ // Check a bunch of invalid locations.
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{50, 60});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{0, 0});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{1, 0});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{0, 1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{0, 1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{1, -1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{-1, 1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{-1, -1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{1, kMaxVal});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{kMaxVal, 1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{1, kMinVal});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{kMinVal, 1});
+
+ // Check the start of the file.
+ TestTranslation(translator, 0, ztf::LineCol{1, 1});
+ TestTranslation(translator, 1, ztf::LineCol{1, 2});
+
+ // Check the boundary around a newline.
+ TestTranslation(translator, 9, ztf::LineCol{1, 10});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{1, 11});
+ TestTranslation(translator, 10, ztf::LineCol{2, 1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{2, 0});
+
+ // Check the end of the file.
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{8, 1});
+ TestTranslation(translator, kInvalidOffset, ztf::LineCol{7, 79});
+ // Need to subtract to account for the newline.
+ TestTranslation(translator, text.size() - 1, ztf::LineCol{7, 78});
+ TestTranslation(translator, text.size() - 2, ztf::LineCol{7, 77});
+
+ // Delta Validity
+ // - Reminder! 0 -> 1:1
+
+ // Common possible edge cases.
+ EXPECT_TRUE(translator.IsValid(0, ztf::DeltaLineCol{0, 0}));
+ EXPECT_TRUE(translator.IsValid(0, ztf::DeltaLineCol{0, 1}));
+ EXPECT_TRUE(translator.IsValid(0, ztf::DeltaLineCol{1, 0}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{-1, -1}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{-1, 0}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{0, -1}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{0, -1}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{0, kMaxVal}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{kMaxVal, 0}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{0, kMinVal}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{kMinVal, 0}));
+ EXPECT_FALSE(translator.IsValid(233, ztf::DeltaLineCol{0, kMaxVal}));
+ EXPECT_FALSE(translator.IsValid(233, ztf::DeltaLineCol{kMaxVal, 0}));
+ EXPECT_FALSE(translator.IsValid(233, ztf::DeltaLineCol{kMaxVal, kMaxVal}));
+
+ // Newline area.
+ EXPECT_TRUE(translator.IsValid(0, ztf::DeltaLineCol{0, 9}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{0, 10}));
+ EXPECT_FALSE(translator.IsValid(9, ztf::DeltaLineCol{0, 1}));
+ EXPECT_FALSE(translator.IsValid(9, ztf::DeltaLineCol{-1, 0}));
+ EXPECT_FALSE(translator.IsValid(9, ztf::DeltaLineCol{1, -10}));
+ EXPECT_TRUE(translator.IsValid(9, ztf::DeltaLineCol{1, -9}));
+
+ // End of file.
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{7, 78}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{7, 77}));
+ EXPECT_FALSE(translator.IsValid(0, ztf::DeltaLineCol{6, 78}));
+ EXPECT_TRUE(translator.IsValid(0, ztf::DeltaLineCol{6, 77}));
+ EXPECT_FALSE(translator.IsValid(text.size() - 1, ztf::DeltaLineCol{0, 1}));
+ EXPECT_FALSE(translator.IsValid(text.size() - 1, ztf::DeltaLineCol{1, 0}));
+ EXPECT_TRUE(translator.IsValid(text.size() - 2, ztf::DeltaLineCol{0, 1}));
+ EXPECT_FALSE(translator.IsValid(text.size() - 2, ztf::DeltaLineCol{1, 0}));
+}
+
+// Ensures that ReferenceGroups from DisassemblerZtf::MakeReferenceGroups()
+// cover each non-sentinel element in ReferenceType in order, exactly once. Also
+// ensures that the ReferenceType elements are grouped by ReferencePool, and
+// listed in increasing order.
+TEST(DisassemblerZtfTest, ReferenceGroups) {
+ std::vector<uint32_t> pool_list;
+ std::vector<uint32_t> type_list;
+ DisassemblerZtf dis;
+ for (ReferenceGroup group : dis.MakeReferenceGroups()) {
+ pool_list.push_back(static_cast<uint32_t>(group.pool_tag().value()));
+ type_list.push_back(static_cast<uint32_t>(group.type_tag().value()));
+ }
+
+ // Check ReferenceByte coverage.
+ constexpr size_t kNumTypes = DisassemblerZtf::kNumTypes;
+ EXPECT_EQ(kNumTypes, type_list.size());
+ EXPECT_EQ(kNumTypes, CountDistinct(type_list));
+ EXPECT_TRUE(std::is_sorted(type_list.begin(), type_list.end()));
+
+ // Check that ReferenceType elements are grouped by ReferencePool. Note that
+ // repeats can occur, and pools can be skipped.
+ EXPECT_TRUE(std::is_sorted(pool_list.begin(), pool_list.end()));
+}
+
+TEST(DisassemblerZtfTest, BadMagic) {
+ // Test a case where there is no header so a disassembler cannot be created.
+ {
+ const std::vector<uint8_t> text(StrToData("foobarbaz bazbarfoo"));
+ ConstBufferView image(text.data(), text.size());
+ EXPECT_FALSE(DisassemblerZtf::QuickDetect(image));
+ EXPECT_FALSE(Disassembler::Make<DisassemblerZtf>(image));
+ }
+ // Test a case where there is no footer so a disassembler cannot be created.
+ {
+ const std::vector<uint8_t> text(StrToData("ZTxtfoobarbaz bazbarfootxTZ"));
+ ConstBufferView image(text.data(), text.size());
+ EXPECT_TRUE(DisassemblerZtf::QuickDetect(image));
+ EXPECT_FALSE(Disassembler::Make<DisassemblerZtf>(image));
+ }
+ // Test when the header is too short
+ {
+ const std::vector<uint8_t> text(StrToData("ZTxtxTZ\n"));
+ ConstBufferView image(text.data(), text.size());
+ EXPECT_FALSE(DisassemblerZtf::QuickDetect(image));
+ EXPECT_FALSE(Disassembler::Make<DisassemblerZtf>(image));
+ }
+}
+
+TEST(DisassemblerZtfTest, ZtfSizeBound) {
+ {
+ std::vector<uint8_t> text(StrToData("ZTxt"));
+ std::fill_n(std::back_inserter(text), ztf::kMaxDimValue - 2, '\n');
+ text.insert(text.end(), {'t', 'x', 'T', 'Z', '\n'});
+ ConstBufferView image(text.data(), text.size());
+ EXPECT_TRUE(DisassemblerZtf::QuickDetect(image));
+ EXPECT_TRUE(Disassembler::Make<DisassemblerZtf>(image));
+ }
+ {
+ std::vector<uint8_t> text(StrToData("ZTxt"));
+ std::fill_n(std::back_inserter(text), ztf::kMaxDimValue - 1, '\n');
+ text.insert(text.end(), {'t', 'x', 'T', 'Z', '\n'});
+ ConstBufferView image(text.data(), text.size());
+ EXPECT_TRUE(DisassemblerZtf::QuickDetect(image));
+ EXPECT_FALSE(Disassembler::Make<DisassemblerZtf>(image));
+ }
+}
+
+// Try reading from a well formed source.
+TEST(DisassemblerZtfTest, NormalRead) {
+ const std::vector<uint8_t> text(StrToData(kNormalText));
+ ConstBufferView image(text.data(), text.size());
+ ReferenceSets expected_map = {
+ {{DisassemblerZtf::kAngles, DisassemblerZtf::kAnglesAbs1},
+ {Reference({63, 0})}},
+ {{DisassemblerZtf::kBraces, DisassemblerZtf::kBracesRel2},
+ {Reference({74, 27})}},
+ };
+ ReadReferences(image, text.size() - kNormalTextExtraBytes, &expected_map);
+}
+
+// Try writing to a well formed source and ensure that what is read back
+// reflects what was written.
+TEST(DisassemblerZtfTest, NormalWrite) {
+ std::vector<uint8_t> mutable_text(StrToData(kNormalText));
+ MutableBufferView image(mutable_text.data(), mutable_text.size());
+ ReferenceSets change_map = {
+ {{DisassemblerZtf::kParentheses, DisassemblerZtf::kParenthesesAbs1},
+ {Reference({63, 71})}},
+ {{DisassemblerZtf::kBrackets, DisassemblerZtf::kBracketsRel3},
+ {Reference({74, 4})}},
+ };
+ WriteReferences(image, mutable_text.size() - kNormalTextExtraBytes,
+ change_map);
+
+ // As a sanity check see if a disassembler can identify the same references.
+ ConstBufferView const_image(image);
+ ReadReferences(const_image, mutable_text.size() - kNormalTextExtraBytes,
+ &change_map);
+}
+
+// Try reading from a source rife with errors.
+TEST(DisassemblerZtfTest, ReadOutOfBoundsRefs) {
+ const std::vector<uint8_t> text(StrToData(kOutOfBoundsText));
+ ConstBufferView image(text.data(), text.size());
+ ReferenceSets expected_map = {
+ {{DisassemblerZtf::kAngles, DisassemblerZtf::kAnglesAbs1},
+ {Reference({4, 0}), Reference({223, 0}), Reference({228, 12})}},
+ {{DisassemblerZtf::kBrackets, DisassemblerZtf::kBracketsRel2},
+ {Reference({139, 149})}},
+ {{DisassemblerZtf::kBraces, DisassemblerZtf::kBracesAbs1},
+ {Reference({218, 223})}},
+ {{DisassemblerZtf::kBraces, DisassemblerZtf::kBracesRel2},
+ {Reference({233, 233})}},
+ {{DisassemblerZtf::kParentheses, DisassemblerZtf::kParenthesesAbs1},
+ {Reference({174, 4})}},
+ };
+ ReadReferences(image, text.size(), &expected_map);
+}
+
+// Try writing to a source rife with errors (malformed references or ones that
+// reference non-existent locations. Some of the values written are also bad. To
+// validate check if the expected set of references are read back.
+TEST(DisassemblerZtfTest, WriteOutOfBoundsRefs) {
+ // Replace |old_val| (provided for checking) with |new_val| in |set|.
+ auto update_set = [](Reference old_ref, Reference new_ref,
+ std::set<Reference, ReferenceCompare>* set) {
+ auto it = set->find(old_ref);
+ EXPECT_NE(it, set->cend());
+ EXPECT_EQ(*it, old_ref);
+ set->erase(it);
+ set->insert(new_ref);
+ };
+
+ // Replace |old_val| (provided for checking) with |new_val| in the set which
+ // is the value corresponding to |key| in |map|.
+ auto update_map =
+ [update_set](
+ ReferenceKey key, Reference old_ref, Reference new_ref,
+ std::map<ReferenceKey, std::set<Reference, ReferenceCompare>>* map) {
+ auto it = map->find(key);
+ EXPECT_NE(it, map->cend());
+ update_set(old_ref, new_ref, &(it->second));
+ };
+
+ std::vector<uint8_t> mutable_text(StrToData(kOutOfBoundsText));
+ MutableBufferView image(mutable_text.data(), mutable_text.size());
+ ReferenceSets change_map = {
+ {{DisassemblerZtf::kAngles, DisassemblerZtf::kAnglesAbs1},
+ {Reference({223, 15}), Reference({228, 13})}},
+ {{DisassemblerZtf::kAngles, DisassemblerZtf::kAnglesAbs3},
+ {Reference({4, 50})}}, // This should fail to write.
+ {{DisassemblerZtf::kBrackets, DisassemblerZtf::kBracketsRel2},
+ {Reference({139, mutable_text.size()})}}, // This should fail.
+ {{DisassemblerZtf::kParentheses, DisassemblerZtf::kParenthesesAbs1},
+ {Reference({174, 21})}}, // This should fail.
+ {{DisassemblerZtf::kBraces, DisassemblerZtf::kBracesAbs1},
+ {Reference({218, 219})}},
+ {{DisassemblerZtf::kBraces, DisassemblerZtf::kBracesRel2},
+ {Reference({233, 174})}},
+ };
+ WriteReferences(image, mutable_text.size(), change_map);
+
+ // As a sanity check see if a disassembler can identify the same references
+ // (excluding the invalid ones).
+ change_map.erase(change_map.find(
+ {DisassemblerZtf::kAngles, DisassemblerZtf::kAnglesAbs3}));
+ change_map.at({DisassemblerZtf::kAngles, DisassemblerZtf::kAnglesAbs1})
+ .emplace(Reference{4, 0});
+ update_map({DisassemblerZtf::kBrackets, DisassemblerZtf::kBracketsRel2},
+ Reference({139, mutable_text.size()}), Reference({139, 149}),
+ &change_map);
+ update_map({DisassemblerZtf::kParentheses, DisassemblerZtf::kParenthesesAbs1},
+ Reference({174, 21}), Reference({174, 4}), &change_map);
+ ConstBufferView const_image(image);
+ ReadReferences(const_image, mutable_text.size(), &change_map);
+}
+
+} // namespace zucchini
diff --git a/chromium/components/zucchini/element_detection.cc b/chromium/components/zucchini/element_detection.cc
index 2fa3604ae1f..6b31f612f7a 100644
--- a/chromium/components/zucchini/element_detection.cc
+++ b/chromium/components/zucchini/element_detection.cc
@@ -7,17 +7,28 @@
#include <utility>
#include "base/logging.h"
+#include "components/zucchini/buildflags.h"
#include "components/zucchini/disassembler.h"
-#include "components/zucchini/disassembler_dex.h"
#include "components/zucchini/disassembler_no_op.h"
+
+#if BUILDFLAG(ENABLE_DEX)
+#include "components/zucchini/disassembler_dex.h"
+#endif // BUILDFLAG(ENABLE_DEX)
+
+#if BUILDFLAG(ENABLE_WIN)
#include "components/zucchini/disassembler_win32.h"
+#endif // BUILDFLAG(ENABLE_WIN)
+
+#if BUILDFLAG(ENABLE_ZTF)
+#include "components/zucchini/disassembler_ztf.h"
+#endif // BUILDFLAG(ENABLE_ZTF)
namespace zucchini {
namespace {
// Impose a minimal program size to eliminate pathological cases.
-constexpr size_t kMinProgramSize = 16;
+enum : size_t { kMinProgramSize = 16 };
} // namespace
@@ -25,6 +36,7 @@ constexpr size_t kMinProgramSize = 16;
std::unique_ptr<Disassembler> MakeDisassemblerWithoutFallback(
ConstBufferView image) {
+#if BUILDFLAG(ENABLE_WIN)
if (DisassemblerWin32X86::QuickDetect(image)) {
auto disasm = Disassembler::Make<DisassemblerWin32X86>(image);
if (disasm && disasm->size() >= kMinProgramSize)
@@ -36,12 +48,24 @@ std::unique_ptr<Disassembler> MakeDisassemblerWithoutFallback(
if (disasm && disasm->size() >= kMinProgramSize)
return disasm;
}
+#endif // BUILDFLAG(ENABLE_WIN)
+#if BUILDFLAG(ENABLE_DEX)
if (DisassemblerDex::QuickDetect(image)) {
auto disasm = Disassembler::Make<DisassemblerDex>(image);
if (disasm && disasm->size() >= kMinProgramSize)
return disasm;
}
+#endif // BUILDFLAG(ENABLE_DEX)
+
+#if BUILDFLAG(ENABLE_ZTF)
+ if (DisassemblerZtf::QuickDetect(image)) {
+ // This disallows very short examples like "ZTxtxtZ\n" in ensemble patching.
+ auto disasm = Disassembler::Make<DisassemblerZtf>(image);
+ if (disasm && disasm->size() >= kMinProgramSize)
+ return disasm;
+ }
+#endif // BUILDFLAG(ENABLE_ZTF)
return nullptr;
}
@@ -49,15 +73,24 @@ std::unique_ptr<Disassembler> MakeDisassemblerWithoutFallback(
std::unique_ptr<Disassembler> MakeDisassemblerOfType(ConstBufferView image,
ExecutableType exe_type) {
switch (exe_type) {
+#if BUILDFLAG(ENABLE_WIN)
case kExeTypeWin32X86:
return Disassembler::Make<DisassemblerWin32X86>(image);
case kExeTypeWin32X64:
return Disassembler::Make<DisassemblerWin32X64>(image);
+#endif // BUILDFLAG(ENABLE_WIN)
+#if BUILDFLAG(ENABLE_DEX)
case kExeTypeDex:
return Disassembler::Make<DisassemblerDex>(image);
+#endif // BUILDFLAG(ENABLE_DEX)
+#if BUILDFLAG(ENABLE_ZTF)
+ case kExeTypeZtf:
+ return Disassembler::Make<DisassemblerZtf>(image);
+#endif // BUILDFLAG(ENABLE_ZTF)
case kExeTypeNoOp:
return Disassembler::Make<DisassemblerNoOp>(image);
default:
+ // If an architecture is disabled then null is handled gracefully.
return nullptr;
}
}
diff --git a/chromium/components/zucchini/element_detection_unittest.cc b/chromium/components/zucchini/element_detection_unittest.cc
index 2200c0bf1c2..6dbfa3f8b7f 100644
--- a/chromium/components/zucchini/element_detection_unittest.cc
+++ b/chromium/components/zucchini/element_detection_unittest.cc
@@ -11,14 +11,65 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace zucchini {
-
namespace {
+// This test uses a mock archive format where regions are determined by their
+// consecutive byte values rather than parsing real executables.
+//
+// 0 - Padding or raw data (not mapped to an executable).
+// 1 - A Win32x86 executable.
+// 2 - A Win32x64 executable.
+//
+// So an example archive file of;
+// 0 1 1 1 0 1 1 0 0 2 2 2 2
+// contains (in order left to right):
+// - One padding byte
+// - Three byte Win32x86 executable
+// - One padding byte
+// - Two byte Win32x86 executable
+// - Two padding bytes
+// - Four byte Win32x64 executable
-using ElementVector = std::vector<Element>;
+class ElementDetectionTest : public ::testing::Test {
+ protected:
+ using ElementVector = std::vector<Element>;
+ using ExeTypeMap = std::map<uint8_t, ExecutableType>;
-} // namespace
+ ElementDetectionTest()
+ : exe_map_({{1, kExeTypeWin32X86}, {2, kExeTypeWin32X64}}) {}
+
+ ElementVector TestElementFinder(std::vector<uint8_t> buffer) {
+ ConstBufferView image(buffer.data(), buffer.size());
+
+ ElementFinder finder(
+ image,
+ base::BindRepeating(
+ [](ExeTypeMap exe_map, ConstBufferView image,
+ ConstBufferView region) -> base::Optional<Element> {
+ EXPECT_GE(region.begin(), image.begin());
+ EXPECT_LE(region.end(), image.end());
+ EXPECT_GE(region.size(), 0U);
+
+ if (region[0] != 0) {
+ offset_t length = 1;
+ while (length < region.size() && region[length] == region[0])
+ ++length;
+ return Element{{0, length}, exe_map[region[0]]};
+ }
+ return base::nullopt;
+ },
+ exe_map_, image));
+ std::vector<Element> elements;
+ for (auto element = finder.GetNext(); element; element = finder.GetNext()) {
+ elements.push_back(*element);
+ }
+ return elements;
+ }
+
+ // Translation map from mock archive bytes to actual types used in Zucchini.
+ ExeTypeMap exe_map_;
+};
-TEST(ElementDetectionTest, ElementFinderEmpty) {
+TEST_F(ElementDetectionTest, ElementFinderEmpty) {
std::vector<uint8_t> buffer(10, 0);
ElementFinder finder(
ConstBufferView(buffer.data(), buffer.size()),
@@ -28,36 +79,7 @@ TEST(ElementDetectionTest, ElementFinderEmpty) {
EXPECT_EQ(base::nullopt, finder.GetNext());
}
-ElementVector TestElementFinder(std::vector<uint8_t> buffer) {
- ConstBufferView image(buffer.data(), buffer.size());
-
- ElementFinder finder(
- image,
- base::BindRepeating(
- [](ConstBufferView image,
- ConstBufferView region) -> base::Optional<Element> {
- EXPECT_GE(region.begin(), image.begin());
- EXPECT_LE(region.end(), image.end());
- EXPECT_GE(region.size(), 0U);
-
- if (region[0] != 0) {
- offset_t length = 1;
- while (length < region.size() && region[length] == region[0])
- ++length;
- return Element{{0, length},
- static_cast<ExecutableType>(region[0])};
- }
- return base::nullopt;
- },
- image));
- std::vector<Element> elements;
- for (auto element = finder.GetNext(); element; element = finder.GetNext()) {
- elements.push_back(*element);
- }
- return elements;
-}
-
-TEST(ElementDetectionTest, ElementFinder) {
+TEST_F(ElementDetectionTest, ElementFinder) {
EXPECT_EQ(ElementVector(), TestElementFinder({}));
EXPECT_EQ(ElementVector(), TestElementFinder({0, 0}));
EXPECT_EQ(ElementVector({{{0, 2}, kExeTypeWin32X86}}),
@@ -75,4 +97,5 @@ TEST(ElementDetectionTest, ElementFinder) {
TestElementFinder({0, 1, 1, 0, 2, 2, 2}));
}
+} // namespace
} // namespace zucchini
diff --git a/chromium/components/zucchini/equivalence_map_unittest.cc b/chromium/components/zucchini/equivalence_map_unittest.cc
index ce8ffe177fb..9c4166fdff7 100644
--- a/chromium/components/zucchini/equivalence_map_unittest.cc
+++ b/chromium/components/zucchini/equivalence_map_unittest.cc
@@ -251,7 +251,7 @@ TEST(EquivalenceMapTest, PruneEquivalencesAndSortBySource) {
auto PruneEquivalencesAndSortBySourceTest =
[](std::vector<Equivalence>&& equivalences) {
OffsetMapper::PruneEquivalencesAndSortBySource(&equivalences);
- return equivalences;
+ return std::move(equivalences);
};
EXPECT_EQ(std::vector<Equivalence>(),
diff --git a/chromium/components/zucchini/fuzzers/BUILD.gn b/chromium/components/zucchini/fuzzers/BUILD.gn
new file mode 100644
index 00000000000..7afe6db662b
--- /dev/null
+++ b/chromium/components/zucchini/fuzzers/BUILD.gn
@@ -0,0 +1,100 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/protobuf/proto_library.gni")
+
+# To download the corpus for local fuzzing use:
+# gsutil -m rsync \
+# gs://clusterfuzz-corpus/libfuzzer/zucchini_disassembler_win32_fuzzer \
+# components/zucchini/fuzzing/testdata/disassembler_win32_fuzzer
+fuzzer_test("zucchini_disassembler_win32_fuzzer") {
+ sources = [
+ "disassembler_win32_fuzzer.cc",
+ ]
+ deps = [
+ "//base",
+ "//components/zucchini:zucchini_lib",
+ ]
+}
+
+fuzzer_test("zucchini_patch_fuzzer") {
+ sources = [
+ "patch_fuzzer.cc",
+ ]
+ deps = [
+ "//base",
+ "//components/zucchini:zucchini_lib",
+ ]
+ seed_corpus = "testdata/patch_fuzzer"
+}
+
+proto_library("zucchini_file_pair_proto") {
+ sources = [
+ "file_pair.proto",
+ ]
+}
+
+# Ensure protoc is available.
+# Disabled on Windows due to crbug/844826.
+if (current_toolchain == host_toolchain && !is_win) {
+ # Raw Apply Fuzzer:
+ action("zucchini_raw_apply_seed") {
+ script = "generate_fuzzer_data.py"
+
+ args = [
+ "--raw",
+ "old_eventlog_provider.dll", # <old_file>
+ "new_eventlog_provider.dll", # <new_file>
+ "eventlog_provider.patch", # <patch_file> (temporary)
+
+ # <output_dir>
+ rebase_path("$target_gen_dir/testdata/raw_apply_fuzzer", root_build_dir),
+ ]
+
+ # Files depended upon.
+ sources = [
+ "create_seed_file_pair.py",
+ "testdata/new_eventlog_provider.dll",
+ "testdata/old_eventlog_provider.dll",
+ ]
+
+ # Outputs: necessary for validation.
+ outputs = [
+ "$target_gen_dir/testdata/raw_apply_fuzzer/seed_proto.bin",
+ ]
+ deps = [
+ "//components/zucchini:zucchini",
+ "//third_party/protobuf:protoc",
+ ]
+ }
+
+ fuzzer_test("zucchini_raw_apply_fuzzer") {
+ sources = [
+ "raw_gen_fuzzer.cc",
+ ]
+ deps = [
+ ":zucchini_file_pair_proto",
+ "//base",
+ "//components/zucchini:zucchini_lib",
+ "//third_party/libprotobuf-mutator",
+ ]
+ seed_corpus = "$target_gen_dir/testdata/raw_apply_fuzzer"
+ seed_corpus_deps = [ ":zucchini_raw_apply_seed" ]
+ }
+
+ # Raw Gen Fuzzer:
+ fuzzer_test("zucchini_raw_gen_fuzzer") {
+ sources = [
+ "raw_gen_fuzzer.cc",
+ ]
+ deps = [
+ ":zucchini_file_pair_proto",
+ "//base",
+ "//components/zucchini:zucchini_lib",
+ "//third_party/libprotobuf-mutator",
+ ]
+ seed_corpus = "testdata/raw_gen_fuzzer"
+ }
+}
diff --git a/chromium/components/zucchini/fuzzers/create_seed_file_pair.py b/chromium/components/zucchini/fuzzers/create_seed_file_pair.py
new file mode 100755
index 00000000000..a44db7b6a6f
--- /dev/null
+++ b/chromium/components/zucchini/fuzzers/create_seed_file_pair.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# 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.
+
+"""Create binary protobuf encoding for fuzzer seeds.
+
+This script is used to generate binary encoded protobuf seeds for fuzzers
+related to Zucchini-gen and -apply, which take pairs of files are arguments. The
+binary protobuf format is faster to parse so it is the preferred method for
+encoding the seeds. For gen related fuzzers this should only need to be run
+once. For any apply related fuzzers this should be rerun whenever the patch
+format is changed.
+"""
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+
+ABS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__)))
+PROTO_DEFINITION_FILE = 'file_pair.proto'
+OUTPUT_FORMAT = b'old_file: "{}"\nnew_or_patch_file: "{}"'
+
+def parse_args():
+ """Parse commandline args."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument('protoc_path', help='Path to protoc.')
+ parser.add_argument('old_file', help='Old file to generate/apply patch.')
+ parser.add_argument('new_or_patch_file',
+ help='New file to generate or patch to apply.')
+ parser.add_argument('output_file', help='File to write binary protobuf to.')
+ return parser.parse_args()
+
+
+def read_to_proto_escaped_string(filename):
+ """Reads a file and converts it to hex escape sequences."""
+ with open(filename, 'rb') as f:
+ # Note that string_escape escapes all non-ASCII printable characters
+ # excluding ", which needs to be manually escaped.
+ return f.read().encode('string_escape').replace('"', '\\"')
+
+
+def main():
+ args = parse_args()
+ # Create an ASCII string representing a protobuf.
+ content = OUTPUT_FORMAT.format(read_to_proto_escaped_string(args.old_file),
+ read_to_proto_escaped_string(
+ args.new_or_patch_file))
+
+ # Encode the ASCII protobuf as a binary protobuf.
+ ps = subprocess.Popen([args.protoc_path, '--proto_path=%s' % ABS_PATH,
+ '--encode=zucchini.fuzzers.FilePair',
+ os.path.join(ABS_PATH, PROTO_DEFINITION_FILE)],
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+ # Write the string to the subprocess. Single line IO is fine as protoc returns
+ # a string.
+ output = ps.communicate(input=content)
+ ps.wait()
+ if ps.returncode:
+ logging.error('Binary protobuf encoding failed.')
+ return ps.returncode
+
+ # Write stdout of the subprocess for protoc to the |output_file|.
+ with open(args.output_file, 'wb') as f:
+ f.write(output[0])
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chromium/components/zucchini/disassembler_win32_fuzzer.cc b/chromium/components/zucchini/fuzzers/disassembler_win32_fuzzer.cc
index f432dddc960..f432dddc960 100644
--- a/chromium/components/zucchini/disassembler_win32_fuzzer.cc
+++ b/chromium/components/zucchini/fuzzers/disassembler_win32_fuzzer.cc
diff --git a/chromium/components/zucchini/fuzzers/file_pair.proto b/chromium/components/zucchini/fuzzers/file_pair.proto
new file mode 100644
index 00000000000..22163819933
--- /dev/null
+++ b/chromium/components/zucchini/fuzzers/file_pair.proto
@@ -0,0 +1,15 @@
+// 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.
+
+syntax = "proto2";
+
+package zucchini.fuzzers;
+
+// NEXT_TAG = 3
+message FilePair {
+ // File to generate patch from or apply patch to.
+ required bytes old_file = 1;
+ // New file to generate patch or the patch to apply.
+ required bytes new_or_patch_file = 2;
+}
diff --git a/chromium/components/zucchini/fuzzers/generate_fuzzer_data.py b/chromium/components/zucchini/fuzzers/generate_fuzzer_data.py
new file mode 100755
index 00000000000..c182baf2578
--- /dev/null
+++ b/chromium/components/zucchini/fuzzers/generate_fuzzer_data.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# 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.
+
+"""Script for generating new binary protobuf seeds for fuzzers.
+
+Currently supports creating a single seed binary protobuf of the form
+zucchini.fuzzer.FilePair.
+"""
+
+import argparse
+import hashlib
+import logging
+import os
+import platform
+import subprocess
+import sys
+
+ABS_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__)))
+ABS_TESTDATA_PATH = os.path.join(ABS_PATH, 'testdata')
+
+def parse_args():
+ """Parses arguments from command-line."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--raw', help='Whether to use Raw Zucchini.',
+ action='store_true')
+ parser.add_argument('old_file', help='Old file to generate/apply patch.')
+ parser.add_argument('new_file', help='New file to generate patch from.')
+ parser.add_argument('patch_file', help='Patch filename to use.')
+ parser.add_argument('output_dir',
+ help='Directory to write binary protobuf to.')
+ return parser.parse_args()
+
+
+def gen(old_file, new_file, patch_file, output_dir, is_raw, is_win):
+ """Generates a new patch and binary encodes a protobuf pair."""
+ # Create output directory if missing.
+ if not os.path.exists(output_dir):
+ os.makedirs(output_dir)
+
+ # Handle Windows executable names.
+ zucchini = 'zucchini'
+ protoc = 'protoc'
+ if is_win:
+ zucchini += '.exe'
+ protoc += '.exe'
+
+ zuc_cmd = [os.path.abspath(zucchini), '-gen']
+ if is_raw:
+ zuc_cmd.append('-raw')
+ # Generate a new patch.
+ ret = subprocess.call(zuc_cmd + [old_file, new_file, patch_file],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ if ret:
+ logging.error('Patch generation failed for ({}, {})'.format(old_file,
+ new_file))
+ return ret
+ # Binary encode the protobuf pair.
+ ret = subprocess.call([sys.executable,
+ os.path.join(ABS_PATH, 'create_seed_file_pair.py'),
+ os.path.abspath(protoc), old_file, patch_file,
+ os.path.join(output_dir, 'seed_proto.bin')],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ os.remove(patch_file)
+ return ret
+
+
+def main():
+ args = parse_args()
+ return gen(os.path.join(ABS_TESTDATA_PATH, args.old_file),
+ os.path.join(ABS_TESTDATA_PATH, args.new_file),
+ os.path.join(ABS_TESTDATA_PATH, args.patch_file),
+ os.path.abspath(args.output_dir),
+ args.raw,
+ platform.system() == 'Windows')
+
+
+if __name__ == '__main__':
+ sys.exit(main())
+
diff --git a/chromium/components/zucchini/patch_fuzzer.cc b/chromium/components/zucchini/fuzzers/patch_fuzzer.cc
index 2d1c9b7fe45..2d1c9b7fe45 100644
--- a/chromium/components/zucchini/patch_fuzzer.cc
+++ b/chromium/components/zucchini/fuzzers/patch_fuzzer.cc
diff --git a/chromium/components/zucchini/fuzzers/raw_apply_fuzzer.cc b/chromium/components/zucchini/fuzzers/raw_apply_fuzzer.cc
new file mode 100644
index 00000000000..da3230a81f7
--- /dev/null
+++ b/chromium/components/zucchini/fuzzers/raw_apply_fuzzer.cc
@@ -0,0 +1,59 @@
+// 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 <stdint.h>
+#include <stdlib.h>
+
+#include <iostream>
+#include <vector>
+
+#include "base/environment.h"
+#include "base/logging.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/fuzzers/file_pair.pb.h"
+#include "components/zucchini/patch_reader.h"
+#include "components/zucchini/zucchini.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+struct Environment {
+ Environment() {
+ logging::SetMinLogLevel(3); // Disable console spamming.
+ }
+};
+
+Environment* env = new Environment();
+
+DEFINE_BINARY_PROTO_FUZZER(const zucchini::fuzzers::FilePair& file_pair) {
+ // Dump code for debugging.
+ if (base::Environment::Create()->HasVar("LPM_DUMP_NATIVE_INPUT")) {
+ std::cout << "Old File: " << file_pair.old_file() << std::endl
+ << "Patch File: " << file_pair.new_or_patch_file() << std::endl;
+ }
+
+ // Prepare data.
+ zucchini::ConstBufferView old_image(
+ reinterpret_cast<const uint8_t*>(file_pair.old_file().data()),
+ file_pair.old_file().size());
+ zucchini::ConstBufferView patch_file(
+ reinterpret_cast<const uint8_t*>(file_pair.new_or_patch_file().data()),
+ file_pair.new_or_patch_file().size());
+
+ // Generate a patch reader.
+ auto patch_reader = zucchini::EnsemblePatchReader::Create(patch_file);
+ // Abort if the patch can't be read.
+ if (!patch_reader.has_value())
+ return;
+
+ // Create the underlying new file.
+ size_t new_size = patch_reader->header().new_size;
+ // Reject unreasonably large "new" files that fuzzed patch may specify.
+ if (new_size > 64 * 1024)
+ return;
+ std::vector<uint8_t> new_data(new_size);
+ zucchini::MutableBufferView new_image(new_data.data(), new_size);
+
+ // Fuzz target.
+ zucchini::Apply(old_image, *patch_reader, new_image);
+ // No need to check whether output exist, or if so, whether it's valid.
+}
diff --git a/chromium/components/zucchini/fuzzers/raw_gen_fuzzer.cc b/chromium/components/zucchini/fuzzers/raw_gen_fuzzer.cc
new file mode 100644
index 00000000000..176412daf14
--- /dev/null
+++ b/chromium/components/zucchini/fuzzers/raw_gen_fuzzer.cc
@@ -0,0 +1,58 @@
+// 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 <stdint.h>
+
+#include <iostream>
+
+#include "base/environment.h"
+#include "base/logging.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/fuzzers/file_pair.pb.h"
+#include "components/zucchini/patch_writer.h"
+#include "components/zucchini/zucchini_gen.h"
+#include "testing/libfuzzer/proto/lpm_interface.h"
+
+namespace {
+
+constexpr int kMinImageSize = 16;
+constexpr int kMaxImageSize = 1024;
+
+} // namespace
+
+struct Environment {
+ Environment() {
+ logging::SetMinLogLevel(3); // Disable console spamming.
+ }
+};
+
+Environment* env = new Environment();
+
+DEFINE_BINARY_PROTO_FUZZER(const zucchini::fuzzers::FilePair& file_pair) {
+ // Dump code for debugging.
+ if (base::Environment::Create()->HasVar("LPM_DUMP_NATIVE_INPUT")) {
+ std::cout << "Old File: " << file_pair.old_file() << std::endl
+ << "New File: " << file_pair.new_or_patch_file() << std::endl;
+ }
+
+ // Prepare data.
+ zucchini::ConstBufferView old_image(
+ reinterpret_cast<const uint8_t*>(file_pair.old_file().data()),
+ file_pair.old_file().size());
+ zucchini::ConstBufferView new_image(
+ reinterpret_cast<const uint8_t*>(file_pair.new_or_patch_file().data()),
+ file_pair.new_or_patch_file().size());
+
+ // Restrict image sizes to speed up fuzzing.
+ if (old_image.size() < kMinImageSize || old_image.size() > kMaxImageSize ||
+ new_image.size() < kMinImageSize || new_image.size() > kMaxImageSize) {
+ return;
+ }
+
+ // Generate a patch writer.
+ zucchini::EnsemblePatchWriter patch_writer(old_image, new_image);
+
+ // Fuzz Target.
+ zucchini::GenerateRaw(old_image, new_image, &patch_writer);
+}
diff --git a/chromium/components/zucchini/heuristic_ensemble_matcher.cc b/chromium/components/zucchini/heuristic_ensemble_matcher.cc
index aead5dce7b8..1e99d5bf921 100644
--- a/chromium/components/zucchini/heuristic_ensemble_matcher.cc
+++ b/chromium/components/zucchini/heuristic_ensemble_matcher.cc
@@ -68,8 +68,9 @@ bool UnsafeDifference(const Element& old_element, const Element& new_element) {
}
std::ostream& operator<<(std::ostream& stream, const Element& elt) {
- stream << "(" << elt.exe_type << ", " << AsHex<8, size_t>(elt.offset) << " +"
- << AsHex<8, size_t>(elt.size) << ")";
+ stream << "(" << CastExecutableTypeToString(elt.exe_type) << ", "
+ << AsHex<8, size_t>(elt.offset) << " +" << AsHex<8, size_t>(elt.size)
+ << ")";
return stream;
}
diff --git a/chromium/components/zucchini/image_utils.h b/chromium/components/zucchini/image_utils.h
index 3765763f9f9..9aba0a69e99 100644
--- a/chromium/components/zucchini/image_utils.h
+++ b/chromium/components/zucchini/image_utils.h
@@ -8,8 +8,13 @@
#include <stddef.h>
#include <stdint.h>
+#include <string>
+
+#include "base/format_macros.h"
+#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
+#include "base/strings/stringprintf.h"
#include "components/zucchini/buffer_view.h"
#include "components/zucchini/typed_value.h"
@@ -137,20 +142,54 @@ struct EquivalenceCandidate {
double similarity;
};
-// Enumerations for supported executables.
+template <size_t N>
+inline constexpr uint32_t ExeTypeToUint32(const char (&exe_type)[N]) {
+ static_assert(N == 5, "Expected ExeType of length 4 + 1 null byte.");
+ return (exe_type[3] << 24) | (exe_type[2] << 16) | (exe_type[1] << 8) |
+ exe_type[0];
+}
+
+// Enumerations for supported executables. Values in this enum must be distinct.
+// Once present, values should never be altered or removed to ensure backwards
+// compatibility and patch type collision avoidance.
enum ExecutableType : uint32_t {
kExeTypeUnknown = UINT32_MAX,
- kExeTypeNoOp = 0,
- kExeTypeWin32X86 = 1,
- kExeTypeWin32X64 = 2,
- kExeTypeElfX86 = 3,
- kExeTypeElfX64 = 4,
- kExeTypeElfArm32 = 5,
- kExeTypeElfAArch64 = 6,
- kExeTypeDex = 7,
- kNumExeType
+ kExeTypeNoOp = ExeTypeToUint32("NoOp"),
+ kExeTypeWin32X86 = ExeTypeToUint32("Px86"),
+ kExeTypeWin32X64 = ExeTypeToUint32("Px64"),
+ kExeTypeElfX86 = ExeTypeToUint32("Ex86"),
+ kExeTypeElfX64 = ExeTypeToUint32("Ex64"),
+ kExeTypeElfArm32 = ExeTypeToUint32("EA32"),
+ kExeTypeElfAArch64 = ExeTypeToUint32("EA64"),
+ kExeTypeDex = ExeTypeToUint32("DEX "),
+ kExeTypeZtf = ExeTypeToUint32("ZTF "),
};
+constexpr ExecutableType CastToExecutableType(uint32_t possible_exe_type) {
+ switch (static_cast<ExecutableType>(possible_exe_type)) {
+ case kExeTypeNoOp: // Falls through.
+ case kExeTypeWin32X86: // Falls through.
+ case kExeTypeWin32X64: // Falls through.
+ case kExeTypeElfX86: // Falls through.
+ case kExeTypeElfX64: // Falls through.
+ case kExeTypeElfArm32: // Falls through.
+ case kExeTypeElfAArch64: // Falls through.
+ case kExeTypeDex: // Falls through.
+ case kExeTypeZtf: // Falls through.
+ case kExeTypeUnknown:
+ return static_cast<ExecutableType>(possible_exe_type);
+ default:
+ return kExeTypeUnknown;
+ }
+}
+
+inline std::string CastExecutableTypeToString(ExecutableType exe_type) {
+ uint32_t v = static_cast<uint32_t>(exe_type);
+ char result[] = {v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF,
+ (v >> 24) & 0xFF, 0};
+ return result;
+}
+
// A region in an image with associated executable type |exe_type|. If
// |exe_type == kExeTypeNoOp|, then the Element represents a region of raw data.
struct Element : public BufferRegion {
@@ -178,6 +217,15 @@ struct ElementMatch {
bool IsValid() const { return old_element.exe_type == new_element.exe_type; }
ExecutableType exe_type() const { return old_element.exe_type; }
+ // Represents match as "#+#=#+#", where "#" denotes the integers:
+ // [offset in "old", size in "old", offset in "new", size in "new"].
+ // Note that element type is omitted.
+ std::string ToString() const {
+ return base::StringPrintf("%" PRIuS "+%" PRIuS "=%" PRIuS "+%" PRIuS "",
+ old_element.offset, old_element.size,
+ new_element.offset, new_element.size);
+ }
+
Element old_element;
Element new_element;
};
diff --git a/chromium/components/zucchini/image_utils_unittest.cc b/chromium/components/zucchini/image_utils_unittest.cc
index cd71a2f251e..81695e920c8 100644
--- a/chromium/components/zucchini/image_utils_unittest.cc
+++ b/chromium/components/zucchini/image_utils_unittest.cc
@@ -14,4 +14,21 @@ TEST(ImageUtilsTest, Bitness) {
EXPECT_EQ(8U, WidthOf(kBit64));
}
+TEST(ImageUtilsTest, CastExecutableTypeToString) {
+ EXPECT_EQ("NoOp", CastExecutableTypeToString(kExeTypeNoOp));
+ EXPECT_EQ("Px86", CastExecutableTypeToString(kExeTypeWin32X86));
+ EXPECT_EQ("EA64", CastExecutableTypeToString(kExeTypeElfAArch64));
+ EXPECT_EQ("DEX ", CastExecutableTypeToString(kExeTypeDex));
+}
+
+TEST(ImageUtilsTest, ElementMatchToString) {
+ constexpr ExecutableType kAnyType = kExeTypeWin32X86;
+ EXPECT_EQ("1+2=3+4",
+ (ElementMatch{{{1, 2}, kAnyType}, {{3, 4}, kAnyType}}).ToString());
+ EXPECT_EQ(
+ "1000000000+1=0+1000000000",
+ (ElementMatch{{{1000000000, 1}, kAnyType}, {{0, 1000000000}, kAnyType}})
+ .ToString());
+}
+
} // namespace zucchini
diff --git a/chromium/components/zucchini/imposed_ensemble_matcher.cc b/chromium/components/zucchini/imposed_ensemble_matcher.cc
new file mode 100644
index 00000000000..e735bc4e79e
--- /dev/null
+++ b/chromium/components/zucchini/imposed_ensemble_matcher.cc
@@ -0,0 +1,143 @@
+// 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 "components/zucchini/imposed_ensemble_matcher.h"
+
+#include <algorithm>
+#include <sstream>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "components/zucchini/io_utils.h"
+
+namespace zucchini {
+
+/******** ImposedMatchParser ********/
+
+ImposedMatchParser::ImposedMatchParser() = default;
+
+ImposedMatchParser::~ImposedMatchParser() = default;
+
+ImposedMatchParser::Status ImposedMatchParser::Parse(
+ std::string imposed_matches,
+ ConstBufferView old_image,
+ ConstBufferView new_image,
+ ElementDetector&& detector) {
+ CHECK(matches_.empty());
+ CHECK(bad_matches_.empty());
+
+ // Parse |imposed_matches| and check bounds.
+ std::istringstream iss(std::move(imposed_matches));
+ bool first = true;
+ iss.peek(); // Makes empty |iss| realize EOF is reached.
+ while (iss && !iss.eof()) {
+ // Eat delimiter.
+ if (first) {
+ first = false;
+ } else if (!(iss >> EatChar(','))) {
+ return kInvalidDelimiter;
+ }
+ // Extract parameters for one imposed match.
+ offset_t old_offset = 0U;
+ size_t old_size = 0U;
+ offset_t new_offset = 0U;
+ size_t new_size = 0U;
+ if (!(iss >> StrictUInt<offset_t>(old_offset) >> EatChar('+') >>
+ StrictUInt<size_t>(old_size) >> EatChar('=') >>
+ StrictUInt<offset_t>(new_offset) >> EatChar('+') >>
+ StrictUInt<size_t>(new_size))) {
+ return kParseError;
+ }
+ // Check bounds.
+ if (old_size == 0 || new_size == 0 ||
+ !old_image.covers({old_offset, old_size}) ||
+ !new_image.covers({new_offset, new_size})) {
+ return kOutOfBound;
+ }
+ matches_.push_back(
+ {{{old_offset, old_size}, kExeTypeUnknown}, // Assign type later.
+ {{new_offset, new_size}, kExeTypeUnknown}}); // Assign type later.
+ }
+ // Sort matches by "new" file offsets. This helps with overlap checks.
+ std::sort(matches_.begin(), matches_.end(),
+ [](const ElementMatch& match_a, const ElementMatch& match_b) {
+ return match_a.new_element.offset < match_b.new_element.offset;
+ });
+
+ // Check for overlaps in "new" file.
+ if (std::adjacent_find(
+ matches_.begin(), matches_.end(),
+ [](const ElementMatch& match1, const ElementMatch& match2) {
+ return match1.new_element.hi() > match2.new_element.lo();
+ }) != matches_.end()) {
+ return kOverlapInNew;
+ }
+
+ // Compute types and verify consistency. Remove identical matches and matches
+ // where any sub-image has an unknown type.
+ size_t write_idx = 0;
+ for (size_t read_idx = 0; read_idx < matches_.size(); ++read_idx) {
+ ConstBufferView old_sub_image(
+ old_image[matches_[read_idx].old_element.region()]);
+ ConstBufferView new_sub_image(
+ new_image[matches_[read_idx].new_element.region()]);
+ // Remove identical match.
+ if (old_sub_image.equals(new_sub_image)) {
+ ++num_identical_;
+ continue;
+ }
+ // Check executable types of sub-images.
+ base::Optional<Element> old_element = detector.Run(old_sub_image);
+ base::Optional<Element> new_element = detector.Run(new_sub_image);
+ if (!old_element || !new_element) {
+ // Skip unknown types, including those mixed with known types.
+ bad_matches_.push_back(matches_[read_idx]);
+ continue;
+ } else if (old_element->exe_type != new_element->exe_type) {
+ // Error if types are known, but inconsistent.
+ return kTypeMismatch;
+ }
+
+ // Keep match and remove gaps.
+ matches_[read_idx].old_element.exe_type = old_element->exe_type;
+ matches_[read_idx].new_element.exe_type = new_element->exe_type;
+ if (write_idx < read_idx)
+ matches_[write_idx] = matches_[read_idx];
+ ++write_idx;
+ }
+ matches_.resize(write_idx);
+ return kSuccess;
+}
+
+/******** ImposedEnsembleMatcher ********/
+
+ImposedEnsembleMatcher::ImposedEnsembleMatcher(
+ const std::string& imposed_matches)
+ : imposed_matches_(imposed_matches) {}
+
+ImposedEnsembleMatcher::~ImposedEnsembleMatcher() = default;
+
+bool ImposedEnsembleMatcher::RunMatch(ConstBufferView old_image,
+ ConstBufferView new_image) {
+ DCHECK(matches_.empty());
+ LOG(INFO) << "Start matching.";
+ ImposedMatchParser parser;
+ ImposedMatchParser::Status status =
+ parser.Parse(std::move(imposed_matches_), old_image, new_image,
+ base::BindRepeating(DetectElementFromDisassembler));
+ // Print all warnings first.
+ for (const ElementMatch& bad_match : *parser.mutable_bad_matches())
+ LOG(WARNING) << "Skipped match with unknown type: " << bad_match.ToString();
+ if (status != ImposedMatchParser::kSuccess) {
+ LOG(ERROR) << "Imposed match failed with error code " << status << ".";
+ return false;
+ }
+ num_identical_ = parser.num_identical();
+ matches_ = std::move(*parser.mutable_matches());
+ Trim();
+ return true;
+}
+
+} // namespace zucchini
diff --git a/chromium/components/zucchini/imposed_ensemble_matcher.h b/chromium/components/zucchini/imposed_ensemble_matcher.h
new file mode 100644
index 00000000000..4dfc38e1e4e
--- /dev/null
+++ b/chromium/components/zucchini/imposed_ensemble_matcher.h
@@ -0,0 +1,83 @@
+// 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 COMPONENTS_ZUCCHINI_IMPOSED_ENSEMBLE_MATCHER_H_
+#define COMPONENTS_ZUCCHINI_IMPOSED_ENSEMBLE_MATCHER_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/element_detection.h"
+#include "components/zucchini/ensemble_matcher.h"
+
+namespace zucchini {
+
+// A class to parse imposed match format, which is either an empty string (no
+// imposed patch), or a string formatted as:
+// "#+#=#+#,#+#=#+#,..." (e.g., "1+2=3+4", "1+2=3+4,5+6=7+8"),
+// where "#+#=#+#" encodes a match as 4 unsigned integers:
+// [offset in "old", size in "old", offset in "new", size in "new"].
+class ImposedMatchParser {
+ public:
+ enum Status {
+ kSuccess,
+ kInvalidDelimiter,
+ kParseError,
+ kOutOfBound,
+ kOverlapInNew,
+ kTypeMismatch,
+ };
+
+ ImposedMatchParser();
+ ~ImposedMatchParser();
+
+ // Parses |imposed_matches| and writes the results to member variables.
+ // |old_image| and |new_image| are used for validation. Returns a Status value
+ // to signal success or various error modes. |detector| is used to validate
+ // Element types for matched pairs. This should only be called once for each
+ // instance.
+ Status Parse(std::string imposed_matches,
+ ConstBufferView old_image,
+ ConstBufferView new_image,
+ ElementDetector&& detector);
+
+ size_t num_identical() const { return num_identical_; }
+ std::vector<ElementMatch>* mutable_matches() { return &matches_; }
+ std::vector<ElementMatch>* mutable_bad_matches() { return &bad_matches_; }
+
+ private:
+ size_t num_identical_ = 0;
+ std::vector<ElementMatch> matches_;
+ // Stores "forgiven" bad matches, so the caller can impose matches for
+ // unsupported image types (which will simply be ignored). Note that imposing
+ // matches for known but incompatible image types would result in error.
+ std::vector<ElementMatch> bad_matches_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImposedMatchParser);
+};
+
+// An ensemble matcher that parses a format string that describes matches.
+class ImposedEnsembleMatcher : public EnsembleMatcher {
+ public:
+ // |imposed_matches| specifies imposed maches, using a format described below.
+ // Validation is performed in RunMatch().
+ explicit ImposedEnsembleMatcher(const std::string& imposed_matches);
+ ~ImposedEnsembleMatcher() override;
+
+ // EnsembleMatcher:
+ bool RunMatch(ConstBufferView old_image, ConstBufferView new_image) override;
+
+ private:
+ const std::string imposed_matches_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImposedEnsembleMatcher);
+};
+
+} // namespace zucchini
+
+#endif // COMPONENTS_ZUCCHINI_IMPOSED_ENSEMBLE_MATCHER_H_
diff --git a/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc b/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc
new file mode 100644
index 00000000000..97a8898c39a
--- /dev/null
+++ b/chromium/components/zucchini/imposed_ensemble_matcher_unittest.cc
@@ -0,0 +1,214 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "components/zucchini/imposed_ensemble_matcher.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "base/optional.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/disassembler.h"
+#include "components/zucchini/element_detection.h"
+#include "components/zucchini/image_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace zucchini {
+
+namespace {
+
+// This test uses a mock archive format where regions are determined by their
+// consecutive byte values rather than parsing real executables. In fact, since
+// elements are imposed, only the first byte of the element is used to specify
+// executable type of the mock data:
+// - 'W' and 'w' specify kExeTypeWin32X86.
+// - 'E' and 'e' specify kExeTypeElfX86.
+// - Everything else specify kExeTypeUnknown.
+class TestElementDetector {
+ public:
+ TestElementDetector() {}
+
+ base::Optional<Element> Run(ConstBufferView image) const {
+ DCHECK_GT(image.size(), 0U);
+ char first_char = *image.begin();
+ if (first_char == 'W' || first_char == 'w')
+ return Element(image.local_region(), kExeTypeWin32X86);
+ if (first_char == 'E' || first_char == 'e')
+ return Element(image.local_region(), kExeTypeElfX86);
+ return base::nullopt;
+ }
+};
+
+} // namespace
+
+TEST(ImposedMatchParserTest, ImposedMatchParser) {
+ std::vector<uint8_t> old_data;
+ std::vector<uint8_t> new_data;
+ auto populate = [](const std::string& s, std::vector<uint8_t>* data) {
+ for (char ch : s)
+ data->push_back(static_cast<uint8_t>(ch));
+ };
+ // Pos: 11111111
+ // 012345678901234567
+ populate("1WW222EEEE", &old_data);
+ populate("33eee2222222wwww44", &new_data);
+
+ ConstBufferView old_image(&old_data[0], old_data.size());
+ ConstBufferView new_image(&new_data[0], new_data.size());
+
+ TestElementDetector detector;
+
+ // Reusable output values.
+ std::string prev_imposed_matches;
+ ImposedMatchParser::Status status;
+ size_t num_identical;
+ std::vector<ElementMatch> matches;
+ std::vector<ElementMatch> bad_matches;
+
+ auto run_test = [&](const std::string& imposed_matches) -> bool {
+ prev_imposed_matches = imposed_matches;
+ status = ImposedMatchParser::kSuccess;
+ num_identical = 0;
+ matches.clear();
+ bad_matches.clear();
+ ImposedMatchParser parser;
+ status = parser.Parse(imposed_matches, old_image, new_image,
+ base::BindRepeating(&TestElementDetector::Run,
+ base::Unretained(&detector)));
+ num_identical = parser.num_identical();
+ matches = std::move(*parser.mutable_matches());
+ bad_matches = std::move(*parser.mutable_bad_matches());
+ return status == ImposedMatchParser::kSuccess;
+ };
+
+ auto run_check = [&](const ElementMatch& match, ExecutableType exe_type,
+ offset_t old_offset, size_t old_size,
+ offset_t new_offset, size_t new_size) {
+ EXPECT_EQ(exe_type, match.exe_type()) << prev_imposed_matches;
+ EXPECT_EQ(exe_type, match.old_element.exe_type) << prev_imposed_matches;
+ EXPECT_EQ(old_offset, match.old_element.offset) << prev_imposed_matches;
+ EXPECT_EQ(old_size, match.old_element.size) << prev_imposed_matches;
+ EXPECT_EQ(exe_type, match.new_element.exe_type) << prev_imposed_matches;
+ EXPECT_EQ(new_offset, match.new_element.offset) << prev_imposed_matches;
+ EXPECT_EQ(new_size, match.new_element.size) << prev_imposed_matches;
+ };
+
+ // Empty string: Vacuous but valid.
+ EXPECT_TRUE(run_test(""));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(0U, matches.size());
+ EXPECT_EQ(0U, bad_matches.size());
+
+ // Full matches. Different permutations give same result.
+ for (const std::string& imposed_matches :
+ {"1+2=12+4,4+2=5+2,6+4=2+3", "1+2=12+4,6+4=2+3,4+2=5+2",
+ "4+2=5+2,1+2=12+4,6+4=2+3", "4+2=5+2,6+4=2+3,1+2=12+4",
+ "6+4=2+3,1+2=12+4,4+2=5+2", "6+4=2+3,1+2=12+4,4+2=5+2"}) {
+ EXPECT_TRUE(run_test(imposed_matches));
+ EXPECT_EQ(1U, num_identical); // "4+2=5+2"
+ EXPECT_EQ(2U, matches.size());
+ // Results are sorted by "new" offsets.
+ run_check(matches[0], kExeTypeElfX86, 6, 4, 2, 3);
+ run_check(matches[1], kExeTypeWin32X86, 1, 2, 12, 4);
+ EXPECT_EQ(0U, bad_matches.size());
+ }
+
+ // Single subregion match.
+ EXPECT_TRUE(run_test("1+2=12+4"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(1U, matches.size());
+ run_check(matches[0], kExeTypeWin32X86, 1, 2, 12, 4);
+ EXPECT_EQ(0U, bad_matches.size());
+
+ // Single subregion match. We're lax with redundant 0.
+ EXPECT_TRUE(run_test("6+04=02+10"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(1U, matches.size());
+ run_check(matches[0], kExeTypeElfX86, 6, 4, 2, 10);
+ EXPECT_EQ(0U, bad_matches.size());
+
+ // Successive elements, no overlap.
+ EXPECT_TRUE(run_test("1+1=12+1,2+1=13+1"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(2U, matches.size());
+ run_check(matches[0], kExeTypeWin32X86, 1, 1, 12, 1);
+ run_check(matches[1], kExeTypeWin32X86, 2, 1, 13, 1);
+ EXPECT_EQ(0U, bad_matches.size());
+
+ // Overlap in "old" file is okay.
+ EXPECT_TRUE(run_test("1+2=12+2,1+2=14+2"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(2U, matches.size());
+ run_check(matches[0], kExeTypeWin32X86, 1, 2, 12, 2);
+ run_check(matches[1], kExeTypeWin32X86, 1, 2, 14, 2);
+ EXPECT_EQ(0U, bad_matches.size());
+
+ // Entire files: Have unknown type, so are recognized as such, and ignored.
+ EXPECT_TRUE(run_test("0+10=0+18"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(0U, matches.size());
+ EXPECT_EQ(1U, bad_matches.size());
+ run_check(bad_matches[0], kExeTypeUnknown, 0, 10, 0, 18);
+
+ // Forgive matches that mix known type with unknown type.
+ EXPECT_TRUE(run_test("1+2=0+18"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(0U, matches.size());
+ EXPECT_EQ(1U, bad_matches.size());
+ run_check(bad_matches[0], kExeTypeUnknown, 1, 2, 0, 18);
+
+ EXPECT_TRUE(run_test("0+10=12+4"));
+ EXPECT_EQ(0U, num_identical);
+ EXPECT_EQ(0U, matches.size());
+ EXPECT_EQ(1U, bad_matches.size());
+ run_check(bad_matches[0], kExeTypeUnknown, 0, 10, 12, 4);
+
+ // Test invalid delimiter.
+ for (const std::string& imposed_matches :
+ {"1+2=12+4,4+2=5+2x", "1+2=12+4 4+2=5+2", "1+2=12+4,4+2=5+2 ",
+ "1+2=12+4 "}) {
+ EXPECT_FALSE(run_test(imposed_matches));
+ EXPECT_EQ(ImposedMatchParser::kInvalidDelimiter, status);
+ }
+
+ // Test parse errors, including uint32_t overflow.
+ for (const std::string& imposed_matches :
+ {"x1+2=12+4,4+2=5+2,6+4=2+3", "x1+2=12+4,4+2=5+2,6+4=2+3x", ",", " ",
+ "+2=12+4", "1+2+12+4", "1=2+12+4", " 1+2=12+4", "1+2= 12+4", "1", "1+2",
+ "1+2=", "1+2=12", "1+2=12+", "4294967296+2=12+4"}) {
+ EXPECT_FALSE(run_test(imposed_matches));
+ EXPECT_EQ(ImposedMatchParser::kParseError, status);
+ }
+
+ // Test bound errors, include 0-size.
+ for (const std::string& imposed_matches :
+ {"1+10=12+4", "1+2=12+7", "0+11=0+18", "0+12=0+17", "10+1=0+18",
+ "0+10=18+1", "0+0=0+18", "0+10=0+0", "1000000000+1=0+1000000000"}) {
+ EXPECT_FALSE(run_test(imposed_matches));
+ EXPECT_EQ(ImposedMatchParser::kOutOfBound, status);
+ }
+
+ // Test overlap errors. Matches that get ignored are still tested.
+ for (const std::string& imposed_matches :
+ {"1+2=12+4,4+2=5+2,6+4=2+4", "0+10=0+18,1+2=12+4", "6+4=2+10,3+2=5+2"}) {
+ EXPECT_FALSE(run_test(imposed_matches));
+ EXPECT_EQ(ImposedMatchParser::kOverlapInNew, status);
+ }
+
+ // Test type mismatch errors.
+ EXPECT_FALSE(run_test("1+2=2+3"));
+ EXPECT_EQ(ImposedMatchParser::kTypeMismatch, status);
+
+ EXPECT_FALSE(run_test("6+4=12+4"));
+ EXPECT_EQ(ImposedMatchParser::kTypeMismatch, status);
+}
+
+} // namespace zucchini
diff --git a/chromium/components/zucchini/integration_test.cc b/chromium/components/zucchini/integration_test.cc
index b0ec8641eb9..c4c7004d349 100644
--- a/chromium/components/zucchini/integration_test.cc
+++ b/chromium/components/zucchini/integration_test.cc
@@ -22,7 +22,7 @@ namespace zucchini {
base::FilePath MakeTestPath(const std::string& filename) {
base::FilePath path;
- DCHECK(PathService::Get(base::DIR_SOURCE_ROOT, &path));
+ DCHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &path));
return path.AppendASCII("chrome")
.AppendASCII("installer")
.AppendASCII("zucchini")
diff --git a/chromium/components/zucchini/main_utils.cc b/chromium/components/zucchini/main_utils.cc
index 7a283881f99..b6b564280ef 100644
--- a/chromium/components/zucchini/main_utils.cc
+++ b/chromium/components/zucchini/main_utils.cc
@@ -63,13 +63,16 @@ struct Command {
/******** List of Zucchini commands ********/
constexpr Command kCommands[] = {
- {"gen", "-gen <old_file> <new_file> <patch_file> [-raw] [-keep]", 3,
- &MainGen},
+ {"gen",
+ "-gen <old_file> <new_file> <patch_file> [-raw] [-keep]"
+ " [-impose=#+#=#+#,#+#=#+#,...]",
+ 3, &MainGen},
{"apply", "-apply <old_file> <patch_file> <new_file> [-keep]", 3,
&MainApply},
{"read", "-read <exe> [-dump]", 1, &MainRead},
{"detect", "-detect <archive_file> [-dd=format#]", 1, &MainDetect},
- {"match", "-match <old_file> <new_file>", 2, &MainMatch},
+ {"match", "-match <old_file> <new_file> [-impose=#+#=#+#,#+#=#+#,...]", 2,
+ &MainMatch},
{"crc32", "-crc32 <file>", 1, &MainCrc32},
};
diff --git a/chromium/components/zucchini/patch_read_write_unittest.cc b/chromium/components/zucchini/patch_read_write_unittest.cc
index b701df8fbe9..627513c642a 100644
--- a/chromium/components/zucchini/patch_read_write_unittest.cc
+++ b/chromium/components/zucchini/patch_read_write_unittest.cc
@@ -55,6 +55,64 @@ void TestSerialize(const ByteVector& expected, const T& value) {
EXPECT_EQ(expected, buffer);
}
+ByteVector CreatePatchElement() {
+ return {
+ // PatchElementHeader
+ 0x01, 0, 0, 0, // old_offset
+ 0x51, 0, 0, 0, // old_length
+ 0x03, 0, 0, 0, // new_offset
+ 0x13, 0, 0, 0, // new_length
+ 'P', 'x', '8', '6', // exe_type = EXE_TYPE_WIN32_X86
+ // EquivalenceSource
+ 1, 0, 0, 0, // src_skip size
+ 0x10, // src_skip content
+ 1, 0, 0, 0, // dst_skip size
+ 0x00, // dst_skip content
+ 1, 0, 0, 0, // copy_count size
+ 0x12, // copy_count content
+ // ExtraDataSource
+ 1, 0, 0, 0, // extra_data size
+ 0x13, // extra_data content
+ // RawDeltaSource
+ 1, 0, 0, 0, // raw_delta_skip size
+ 0x14, // raw_delta_skip content
+ 1, 0, 0, 0, // raw_delta_diff size
+ 0x15, // raw_delta_diff content
+ // ReferenceDeltaSource
+ 1, 0, 0, 0, // reference_delta size
+ 0x16, // reference_delta content
+ // PatchElementReader
+ 2, 0, 0, 0, // pool count
+ 0, // pool_tag
+ 1, 0, 0, 0, // extra_targets size
+ 0x17, // extra_targets content
+ 2, // pool_tag
+ 1, 0, 0, 0, // extra_targets size
+ 0x18, // extra_targets content
+ };
+}
+
+ByteVector CreateElementMatch() {
+ return {
+ // PatchElementHeader
+ 0x01, 0, 0, 0, // old_offset
+ 0x02, 0, 0, 0, // old_length
+ 0x03, 0, 0, 0, // new_offset
+ 0x04, 0, 0, 0, // new_length
+ 'D', 'E', 'X', ' ', // exe_type = kExeTypeDex
+ };
+}
+
+// Helper to mutate test |data| (e.g., from CreatePatchElement()) at |idx| from
+// |from_val| (as sanity check) to |to_val|.
+void ModifyByte(size_t idx,
+ uint8_t from_val,
+ uint8_t to_val,
+ std::vector<uint8_t>* data) {
+ ASSERT_EQ(from_val, (*data)[idx]);
+ (*data)[idx] = to_val;
+}
+
} // namespace
bool operator==(const ByteVector& a, ConstBufferView b) {
@@ -62,13 +120,7 @@ bool operator==(const ByteVector& a, ConstBufferView b) {
}
TEST(PatchTest, ParseSerializeElementMatch) {
- ByteVector data = {
- 0x01, 0, 0, 0, // old_offset
- 0x03, 0, 0, 0, // new_offset
- 0x02, 0, 0, 0, // old_length
- 0x04, 0, 0, 0, // new_length
- 7, 0, 0, 0, // kExeTypeDex
- };
+ ByteVector data = CreateElementMatch();
BufferSource buffer_source(data.data(), data.size());
ElementMatch element_match = {};
EXPECT_TRUE(patch::ParseElementMatch(&buffer_source, &element_match));
@@ -95,6 +147,38 @@ TEST(PatchTest, ParseElementMatchTooSmall) {
EXPECT_FALSE(patch::ParseElementMatch(&buffer_source, &element_match));
}
+TEST(PatchTest, ParseElementMatchNoLength) {
+ // Set old_length to 0 to trigger an error.
+ {
+ ByteVector data = CreateElementMatch();
+ // old_length := 0.
+ ModifyByte(offsetof(PatchElementHeader, old_length), 0x02, 0x00, &data);
+ BufferSource buffer_source(data.data(), data.size());
+ ElementMatch element_match = {};
+ EXPECT_FALSE(patch::ParseElementMatch(&buffer_source, &element_match));
+ }
+ // Set new_length to 0 to trigger an error.
+ {
+ ByteVector data = CreateElementMatch();
+ // new_length := 0.
+ ModifyByte(offsetof(PatchElementHeader, new_length), 0x04, 0x00, &data);
+ BufferSource buffer_source(data.data(), data.size());
+ ElementMatch element_match = {};
+ EXPECT_FALSE(patch::ParseElementMatch(&buffer_source, &element_match));
+ }
+ // Set both new_length and old_length to 0 to trigger an error.
+ {
+ ByteVector data = CreateElementMatch();
+ // old_length := 0.
+ ModifyByte(offsetof(PatchElementHeader, old_length), 0x02, 0x00, &data);
+ // new_length := 0.
+ ModifyByte(offsetof(PatchElementHeader, new_length), 0x04, 0x00, &data);
+ BufferSource buffer_source(data.data(), data.size());
+ ElementMatch element_match = {};
+ EXPECT_FALSE(patch::ParseElementMatch(&buffer_source, &element_match));
+ }
+}
+
TEST(PatchTest, ParseSerializeElementMatchExeMismatch) {
ByteVector buffer(28);
BufferSink buffer_sink(buffer.data(), buffer.size());
@@ -167,6 +251,7 @@ TEST(PatchTest, SerializeBufferTooSmall) {
TEST(EquivalenceSinkSourceTest, Empty) {
ByteVector data = {
+ // EquivalenceSource
0, 0, 0, 0, // src_skip size
0, 0, 0, 0, // dst_skip size
0, 0, 0, 0, // copy_count size
@@ -182,6 +267,7 @@ TEST(EquivalenceSinkSourceTest, Empty) {
TEST(EquivalenceSourceSinkTest, Normal) {
ByteVector data = {
+ // EquivalenceSource
2, 0, 0, 0, // src_skip size
6, 7, // src_skip content
2, 0, 0, 0, // dst_skip size
@@ -216,6 +302,7 @@ TEST(EquivalenceSourceSinkTest, Normal) {
TEST(ExtraDataSourceSinkTest, Empty) {
ByteVector data = {
+ // ExtraDataSource
0, 0, 0, 0, // extra_data size
};
ExtraDataSource extra_data_source = TestInitialize<ExtraDataSource>(&data);
@@ -228,6 +315,7 @@ TEST(ExtraDataSourceSinkTest, Empty) {
TEST(ExtraDataSourceSinkTest, Normal) {
ByteVector data = {
+ // ExtraDataSource
5, 0, 0, 0, // extra_data size
1, 2, 3, 4, 5, // extra_data content
};
@@ -261,6 +349,7 @@ TEST(ExtraDataSourceSinkTest, Normal) {
TEST(RawDeltaSourceSinkTest, Empty) {
ByteVector data = {
+ // RawDeltaSource
0, 0, 0, 0, // raw_delta_skip size
0, 0, 0, 0, // raw_delta_diff size
};
@@ -274,6 +363,7 @@ TEST(RawDeltaSourceSinkTest, Empty) {
TEST(RawDeltaSinkSourceSinkTest, Normal) {
ByteVector data = {
+ // RawDeltaSource
3, 0, 0, 0, // raw_delta_skip size
1, 3, 0, // raw_delta_skip content
3, 0, 0, 0, // raw_delta_diff size
@@ -310,8 +400,22 @@ TEST(RawDeltaSinkSourceSinkTest, Normal) {
TestSerialize(data, raw_delta_sink);
}
+TEST(RawDeltaSourceSinkTest, InvalidContent) {
+ ByteVector data = {
+ // RawDeltaSource
+ 2, 0, 0, 0, // raw_delta_skip size
+ 1, 3, // raw_delta_skip content
+ 2, 0, 0, 0, // raw_delta_diff size
+ 0, 4, // raw_delta_diff content
+ };
+ RawDeltaSource raw_delta_source = TestInitialize<RawDeltaSource>(&data);
+ EXPECT_FALSE(raw_delta_source.GetNext());
+ EXPECT_FALSE(raw_delta_source.Done());
+}
+
TEST(ReferenceDeltaSourceSinkTest, Empty) {
ByteVector data = {
+ // ReferenceDeltaSource
0, 0, 0, 0, // reference_delta size
};
ReferenceDeltaSource reference_delta_source =
@@ -325,6 +429,7 @@ TEST(ReferenceDeltaSourceSinkTest, Empty) {
TEST(ReferenceDeltaSourceSinkTest, Normal) {
ByteVector data = {
+ // ReferenceDeltaSource
2, 0, 0, 0, // reference_delta size
84, 47, // reference_delta content
};
@@ -353,6 +458,7 @@ TEST(ReferenceDeltaSourceSinkTest, Normal) {
TEST(TargetSourceSinkTest, Empty) {
ByteVector data = {
+ // TargetSource
0, 0, 0, 0, // extra_targets size
};
TargetSource target_source = TestInitialize<TargetSource>(&data);
@@ -365,6 +471,7 @@ TEST(TargetSourceSinkTest, Empty) {
TEST(TargetSourceSinkTest, Normal) {
ByteVector data = {
+ // TargetSource
2, 0, 0, 0, // extra_targets size
3, 1, // extra_targets content
};
@@ -391,39 +498,7 @@ TEST(TargetSourceSinkTest, Normal) {
}
TEST(PatchElementTest, Normal) {
- ByteVector data = {
- 0x01, 0, 0, 0, // old_offset
- 0x03, 0, 0, 0, // new_offset
- 0x02, 0, 0, 0, // old_length
- 0x04, 0, 0, 0, // new_length
- 1, 0, 0, 0, // EXE_TYPE_WIN32_X86
-
- 1, 0, 0, 0, // src_skip size
- 0x10, // src_skip content
- 1, 0, 0, 0, // dst_skip size
- 0x11, // dst_skip content
- 1, 0, 0, 0, // copy_count size
- 0x12, // copy_count content
-
- 1, 0, 0, 0, // extra_data size
- 0x13, // extra_data content
-
- 1, 0, 0, 0, // raw_delta_skip size
- 0x14, // raw_delta_skip content
- 1, 0, 0, 0, // raw_delta_diff size
- 0x15, // raw_delta_diff content
-
- 1, 0, 0, 0, // reference_delta size
- 0x16, // reference_delta content
-
- 2, 0, 0, 0, // pool count
- 0, // pool_tag
- 1, 0, 0, 0, // extra_targets size
- 0x17, // extra_targets content
- 2, // pool_tag
- 1, 0, 0, 0, // extra_targets size
- 0x18, // extra_targets content
- };
+ ByteVector data = CreatePatchElement();
PatchElementReader patch_element_reader =
TestInitialize<PatchElementReader>(&data);
@@ -433,14 +508,14 @@ TEST(PatchElementTest, Normal) {
EXPECT_EQ(kExeTypeWin32X86, element_match.old_element.exe_type);
EXPECT_EQ(kExeTypeWin32X86, element_match.new_element.exe_type);
EXPECT_EQ(0x1U, element_match.old_element.offset);
- EXPECT_EQ(0x2U, element_match.old_element.size);
+ EXPECT_EQ(0x51U, element_match.old_element.size);
EXPECT_EQ(0x3U, element_match.new_element.offset);
- EXPECT_EQ(0x4U, element_match.new_element.size);
+ EXPECT_EQ(0x13U, element_match.new_element.size);
EquivalenceSource equivalence_source =
patch_element_reader.GetEquivalenceSource();
EXPECT_EQ(ByteVector({0x10}), equivalence_source.src_skip());
- EXPECT_EQ(ByteVector({0x11}), equivalence_source.dst_skip());
+ EXPECT_EQ(ByteVector({0x00}), equivalence_source.dst_skip());
EXPECT_EQ(ByteVector({0x12}), equivalence_source.copy_count());
ExtraDataSource extra_data_source = patch_element_reader.GetExtraDataSource();
@@ -467,7 +542,7 @@ TEST(PatchElementTest, Normal) {
PatchElementWriter patch_element_writer(element_match);
patch_element_writer.SetEquivalenceSink(
- EquivalenceSink({0x10}, {0x11}, {0x12}));
+ EquivalenceSink({0x10}, {0x00}, {0x12}));
patch_element_writer.SetExtraDataSink(ExtraDataSink({0x13}));
patch_element_writer.SetRawDeltaSink(RawDeltaSink({0x14}, {0x15}));
patch_element_writer.SetReferenceDeltaSink(ReferenceDeltaSink({0x16}));
@@ -476,29 +551,72 @@ TEST(PatchElementTest, Normal) {
TestSerialize(data, patch_element_writer);
}
+TEST(PatchElementTest, BadEquivalence) {
+ // If the "old" element is too small then the test should fail.
+ {
+ ByteVector data = CreatePatchElement();
+ // old_length := 0x4 (too small).
+ ModifyByte(offsetof(PatchElementHeader, old_length), 0x51, 0x04, &data);
+ TestInvalidInitialize<PatchElementReader>(&data);
+ }
+
+ // If the "new" element is too small then the test should fail.
+ {
+ ByteVector data = CreatePatchElement();
+ // new_length := 0x5 (too small).
+ ModifyByte(offsetof(PatchElementHeader, new_length), 0x13, 0x05, &data);
+ TestInvalidInitialize<PatchElementReader>(&data);
+ }
+}
+
+TEST(PatchElementTest, WrongExtraData) {
+ // Make "new" too large so insufficient extra data exists to cover the image.
+ {
+ ByteVector data = CreatePatchElement();
+ // new_length := 0x14 (too large).
+ ModifyByte(offsetof(PatchElementHeader, new_length), 0x13, 0x14, &data);
+ TestInvalidInitialize<PatchElementReader>(&data);
+ }
+ // Make "new" too small so there is too much extra data.
+ {
+ ByteVector data = CreatePatchElement();
+ // new_length := 0x12 (too small).
+ ModifyByte(offsetof(PatchElementHeader, new_length), 0x13, 0x12, &data);
+ TestInvalidInitialize<PatchElementReader>(&data);
+ }
+}
+
TEST(EnsemblePatchTest, RawPatch) {
ByteVector data = {
+ // PatchHeader
0x5A, 0x75, 0x63, 0x00, // magic
0x10, 0x32, 0x54, 0x76, // old_size
0x00, 0x11, 0x22, 0x33, // old_crc
- 0x98, 0xBA, 0xDC, 0xFE, // new_size
+ 0x01, 0, 0, 0, // new_size
0x44, 0x55, 0x66, 0x77, // new_crc
- 1, 0, 0, 0, // number of element
-
- 0x01, 0, 0, 0, // old_offset
- 0x00, 0, 0, 0, // new_offset
- 0x02, 0, 0, 0, // old_length
- 0x98, 0xBA, 0xDC, 0xFE, // new_length
- 1, 0, 0, 0, // EXE_TYPE_WIN32_X86
- 0, 0, 0, 0, // src_skip size
- 0, 0, 0, 0, // dst_skip size
- 0, 0, 0, 0, // copy_count size
- 0, 0, 0, 0, // extra_data size
- 0, 0, 0, 0, // raw_delta_skip size
- 0, 0, 0, 0, // raw_delta_diff size
- 0, 0, 0, 0, // reference_delta size
- 0, 0, 0, 0, // pool count
+ 1, 0, 0, 0, // number of element
+
+ // PatchElementHeader
+ 0x01, 0, 0, 0, // old_offset
+ 0x02, 0, 0, 0, // old_length
+ 0x00, 0, 0, 0, // new_offset
+ 0x01, 0, 0, 0, // new_length
+ 'P', 'x', '8', '6', // exe_type = EXE_TYPE_WIN32_X86
+ // EquivalenceSource
+ 0, 0, 0, 0, // src_skip size
+ 0, 0, 0, 0, // dst_skip size
+ 0, 0, 0, 0, // copy_count size
+ // ExtraDataSource
+ 0x01, 0, 0, 0, // extra_data size
+ 0x04, // extra_data content
+ // RawDeltaSource
+ 0, 0, 0, 0, // raw_delta_skip size
+ 0, 0, 0, 0, // raw_delta_diff size
+ // ReferenceDeltaSource
+ 0, 0, 0, 0, // reference_delta size
+ // PatchElementReader
+ 0, 0, 0, 0, // pool count
};
EnsemblePatchReader ensemble_patch_reader =
@@ -508,7 +626,7 @@ TEST(EnsemblePatchTest, RawPatch) {
EXPECT_EQ(PatchHeader::kMagic, header.magic);
EXPECT_EQ(0x76543210U, header.old_size);
EXPECT_EQ(0x33221100U, header.old_crc);
- EXPECT_EQ(0xFEDCBA98U, header.new_size);
+ EXPECT_EQ(0x01U, header.new_size);
EXPECT_EQ(0x77665544U, header.new_crc);
const std::vector<PatchElementReader>& elements =
@@ -518,7 +636,7 @@ TEST(EnsemblePatchTest, RawPatch) {
EnsemblePatchWriter ensemble_patch_writer(header);
PatchElementWriter patch_element_writer(elements[0].element_match());
patch_element_writer.SetEquivalenceSink({});
- patch_element_writer.SetExtraDataSink({});
+ patch_element_writer.SetExtraDataSink(ExtraDataSink({0x04}));
patch_element_writer.SetRawDeltaSink({});
patch_element_writer.SetReferenceDeltaSink({});
ensemble_patch_writer.AddElement(std::move(patch_element_writer));
@@ -528,27 +646,35 @@ TEST(EnsemblePatchTest, RawPatch) {
TEST(EnsemblePatchTest, CheckFile) {
ByteVector data = {
+ // PatchHeader
0x5A, 0x75, 0x63, 0x00, // magic
0x05, 0x00, 0x00, 0x00, // old_size
0xDF, 0x13, 0xE4, 0x10, // old_crc
0x03, 0x00, 0x00, 0x00, // new_size
0xDC, 0xF7, 0x00, 0x40, // new_crc
- 1, 0, 0, 0, // number of element
-
- 0x01, 0, 0, 0, // old_offset
- 0x00, 0, 0, 0, // new_offset
- 0x02, 0, 0, 0, // old_length
- 0x03, 0, 0, 0, // new_length
- 1, 0, 0, 0, // EXE_TYPE_WIN32_X86
- 0, 0, 0, 0, // src_skip size
- 0, 0, 0, 0, // dst_skip size
- 0, 0, 0, 0, // copy_count size
- 0, 0, 0, 0, // extra_data size
- 0, 0, 0, 0, // raw_delta_skip size
- 0, 0, 0, 0, // raw_delta_diff size
- 0, 0, 0, 0, // reference_delta size
- 0, 0, 0, 0, // pool count
+ 1, 0, 0, 0, // number of element
+
+ // PatchElementHeader
+ 0x01, 0, 0, 0, // old_offset
+ 0x02, 0, 0, 0, // old_length
+ 0x00, 0, 0, 0, // new_offset
+ 0x03, 0, 0, 0, // new_length
+ 'P', 'x', '8', '6', // exe_type = EXE_TYPE_WIN32_X86
+ // EquivalenceSource
+ 0, 0, 0, 0, // src_skip size
+ 0, 0, 0, 0, // dst_skip size
+ 0, 0, 0, 0, // copy_count size
+ // ExtraDataSource
+ 0x03, 0, 0, 0, // extra_data size
+ 'A', 'B', 'C', // extra_data content
+ // RawDeltaSource
+ 0, 0, 0, 0, // raw_delta_skip size
+ 0, 0, 0, 0, // raw_delta_diff size
+ // ReferenceDeltaSource
+ 0, 0, 0, 0, // reference_delta size
+ // PatchElementReader
+ 0, 0, 0, 0, // pool count
};
EnsemblePatchReader ensemble_patch_reader =
@@ -568,27 +694,34 @@ TEST(EnsemblePatchTest, CheckFile) {
TEST(EnsemblePatchTest, InvalidMagic) {
ByteVector data = {
+ // PatchHeader
0x42, 0x42, 0x42, 0x00, // magic
0x10, 0x32, 0x54, 0x76, // old_size
0x00, 0x11, 0x22, 0x33, // old_crc
0x03, 0x00, 0x00, 0x00, // new_size
0x44, 0x55, 0x66, 0x77, // new_crc
- 1, 0, 0, 0, // number of element
-
- 0x01, 0, 0, 0, // old_offset
- 0x00, 0, 0, 0, // new_offset
- 0x02, 0, 0, 0, // old_length
- 0x03, 0, 0, 0, // new_length
- 1, 0, 0, 0, // EXE_TYPE_WIN32_X86
- 0, 0, 0, 0, // src_skip size
- 0, 0, 0, 0, // dst_skip size
- 0, 0, 0, 0, // copy_count size
- 0, 0, 0, 0, // extra_data size
- 0, 0, 0, 0, // raw_delta_skip size
- 0, 0, 0, 0, // raw_delta_diff size
- 0, 0, 0, 0, // reference_delta size
- 0, 0, 0, 0, // pool count
+ 1, 0, 0, 0, // number of element
+
+ // PatchElementHeader
+ 0x01, 0, 0, 0, // old_offset
+ 0x02, 0, 0, 0, // old_length
+ 0x00, 0, 0, 0, // new_offset
+ 0x03, 0, 0, 0, // new_length
+ 'P', 'x', '8', '6', // exe_type = EXE_TYPE_WIN32_X86
+ // EquivalenceSource
+ 0, 0, 0, 0, // src_skip size
+ 0, 0, 0, 0, // dst_skip size
+ 0, 0, 0, 0, // copy_count size
+ // ExtraDataSource
+ 0, 0, 0, 0, // extra_data size
+ // RawDeltaSource
+ 0, 0, 0, 0, // raw_delta_skip size
+ 0, 0, 0, 0, // raw_delta_diff size
+ // ReferenceDeltaSource
+ 0, 0, 0, 0, // reference_delta size
+ // PatchElementReader
+ 0, 0, 0, 0, // pool count
};
TestInvalidInitialize<EnsemblePatchReader>(&data);
diff --git a/chromium/components/zucchini/patch_reader.cc b/chromium/components/zucchini/patch_reader.cc
index 970b90c2831..3ec17e45487 100644
--- a/chromium/components/zucchini/patch_reader.cc
+++ b/chromium/components/zucchini/patch_reader.cc
@@ -8,6 +8,7 @@
#include <utility>
#include "base/numerics/safe_conversions.h"
+#include "components/zucchini/algorithm.h"
#include "components/zucchini/crc32.h"
namespace zucchini {
@@ -15,22 +16,30 @@ namespace zucchini {
namespace patch {
bool ParseElementMatch(BufferSource* source, ElementMatch* element_match) {
- PatchElementHeader element_header;
- if (!source->GetValue(&element_header)) {
+ PatchElementHeader unsafe_element_header;
+ if (!source->GetValue(&unsafe_element_header)) {
LOG(ERROR) << "Impossible to read ElementMatch from source.";
- LOG(ERROR) << base::debug::StackTrace().ToString();
return false;
}
ExecutableType exe_type =
- static_cast<ExecutableType>(element_header.exe_type);
- if (exe_type >= kNumExeType) {
- LOG(ERROR) << "Invalid ExecutableType encountered.";
- LOG(ERROR) << base::debug::StackTrace().ToString();
+ CastToExecutableType(unsafe_element_header.exe_type);
+ if (exe_type == kExeTypeUnknown) {
+ LOG(ERROR) << "Invalid ExecutableType found.";
return false;
}
+ if (!unsafe_element_header.old_length || !unsafe_element_header.new_length) {
+ LOG(ERROR) << "Empty patch element found.";
+ return false;
+ }
+ // |unsafe_element_header| is now considered to be safe as it has a valid
+ // |exe_type| and the length fields are of sufficient size.
+ const auto& element_header = unsafe_element_header;
+
+ // Caveat: Element offsets and lengths can still be invalid (e.g., exceeding
+ // archive bounds), but this will be checked later.
element_match->old_element.offset = element_header.old_offset;
- element_match->new_element.offset = element_header.new_offset;
element_match->old_element.size = element_header.old_length;
+ element_match->new_element.offset = element_header.new_offset;
element_match->new_element.size = element_header.new_length;
element_match->old_element.exe_type = exe_type;
element_match->new_element.exe_type = exe_type;
@@ -38,17 +47,20 @@ bool ParseElementMatch(BufferSource* source, ElementMatch* element_match) {
}
bool ParseBuffer(BufferSource* source, BufferSource* buffer) {
- uint32_t size = 0;
- if (!source->GetValue(&size)) {
+ uint32_t unsafe_size = 0; // Bytes.
+ static_assert(sizeof(size_t) >= sizeof(unsafe_size),
+ "size_t is expected to be larger than uint32_t.");
+ if (!source->GetValue(&unsafe_size)) {
LOG(ERROR) << "Impossible to read buffer size from source.";
- LOG(ERROR) << base::debug::StackTrace().ToString();
return false;
}
- if (!source->GetRegion(base::checked_cast<size_t>(size), buffer)) {
+ if (!source->GetRegion(static_cast<size_t>(unsafe_size), buffer)) {
LOG(ERROR) << "Impossible to read buffer content from source.";
- LOG(ERROR) << base::debug::StackTrace().ToString();
return false;
}
+ // Caveat: |buffer| is considered to be safe as it was possible to extract it
+ // from the patch. However, this does not mean its contents are safe and when
+ // parsed must be validated if possible.
return true;
}
@@ -103,6 +115,9 @@ base::Optional<Equivalence> EquivalenceSource::GetNext() {
if (!previous_dst_offset_.IsValid())
return base::nullopt;
+ // Caveat: |equivalence| is assumed to be safe only once the
+ // ValidateEquivalencesAndExtraData() method has returned true. Prior to this
+ // any equivalence returned is assumed to be unsafe.
return equivalence;
}
@@ -120,6 +135,7 @@ base::Optional<ConstBufferView> ExtraDataSource::GetNext(offset_t size) {
ConstBufferView buffer;
if (!extra_data_.GetRegion(size, &buffer))
return base::nullopt;
+ // |buffer| is assumed to always be safe/valid.
return buffer;
}
@@ -138,7 +154,7 @@ base::Optional<RawDeltaUnit> RawDeltaSource::GetNext() {
if (raw_delta_skip_.empty() || raw_delta_diff_.empty())
return base::nullopt;
- RawDeltaUnit delta = {};
+ RawDeltaUnit raw_delta = {};
uint32_t copy_offset_diff = 0;
if (!patch::ParseVarUInt<uint32_t>(&raw_delta_skip_, &copy_offset_diff))
return base::nullopt;
@@ -146,17 +162,22 @@ base::Optional<RawDeltaUnit> RawDeltaSource::GetNext() {
copy_offset_diff + copy_offset_compensation_;
if (!copy_offset.IsValid())
return base::nullopt;
- delta.copy_offset = copy_offset.ValueOrDie();
+ raw_delta.copy_offset = copy_offset.ValueOrDie();
- if (!raw_delta_diff_.GetValue<int8_t>(&delta.diff))
+ if (!raw_delta_diff_.GetValue<int8_t>(&raw_delta.diff))
+ return base::nullopt;
+
+ // A 0 value for a delta.diff is considered invalid since it has no meaning.
+ if (!raw_delta.diff)
return base::nullopt;
// We keep track of the compensation needed for next offset, taking into
- // accound delta encoding and bias of -1.
+ // account delta encoding and bias of -1.
copy_offset_compensation_ = copy_offset + 1;
if (!copy_offset_compensation_.IsValid())
return base::nullopt;
- return delta;
+ // |raw_delta| is assumed to always be safe/valid.
+ return raw_delta;
}
/******** ReferenceDeltaSource ********/
@@ -167,16 +188,17 @@ ReferenceDeltaSource::ReferenceDeltaSource(const ReferenceDeltaSource&) =
ReferenceDeltaSource::~ReferenceDeltaSource() = default;
bool ReferenceDeltaSource::Initialize(BufferSource* source) {
- return patch::ParseBuffer(source, &reference_delta_);
+ return patch::ParseBuffer(source, &source_);
}
base::Optional<int32_t> ReferenceDeltaSource::GetNext() {
- if (reference_delta_.empty())
+ if (source_.empty())
return base::nullopt;
- int32_t delta = 0;
- if (!patch::ParseVarInt<int32_t>(&reference_delta_, &delta))
+ int32_t ref_delta = 0;
+ if (!patch::ParseVarInt<int32_t>(&source_, &ref_delta))
return base::nullopt;
- return delta;
+ // |ref_delta| is assumed to always be safe/valid.
+ return ref_delta;
}
/******** TargetSource ********/
@@ -201,10 +223,12 @@ base::Optional<offset_t> TargetSource::GetNext() {
return base::nullopt;
// We keep track of the compensation needed for next target, taking into
- // accound delta encoding and bias of -1.
+ // account delta encoding and bias of -1.
target_compensation_ = target + 1;
if (!target_compensation_.IsValid())
return base::nullopt;
+ // Caveat: |target| will be a valid offset_t, but it's up to the caller to
+ // check whether it's a valid offset for an image.
return offset_t(target.ValueOrDie());
}
@@ -215,10 +239,11 @@ PatchElementReader::PatchElementReader(PatchElementReader&&) = default;
PatchElementReader::~PatchElementReader() = default;
bool PatchElementReader::Initialize(BufferSource* source) {
- bool ok = patch::ParseElementMatch(source, &element_match_) &&
- equivalences_.Initialize(source) &&
- extra_data_.Initialize(source) && raw_delta_.Initialize(source) &&
- reference_delta_.Initialize(source);
+ bool ok =
+ patch::ParseElementMatch(source, &element_match_) &&
+ equivalences_.Initialize(source) && extra_data_.Initialize(source) &&
+ ValidateEquivalencesAndExtraData() && raw_delta_.Initialize(source) &&
+ reference_delta_.Initialize(source);
if (!ok)
return false;
uint32_t pool_count = 0;
@@ -239,7 +264,7 @@ bool PatchElementReader::Initialize(BufferSource* source) {
}
auto insert_result = extra_targets_.insert({pool_tag, {}});
if (!insert_result.second) { // Element already present.
- LOG(ERROR) << "Multiple ExtraTargetList found for the same pool_tag";
+ LOG(ERROR) << "Multiple ExtraTargetList found for the same pool_tag.";
return false;
}
if (!insert_result.first->second.Initialize(source))
@@ -248,6 +273,43 @@ bool PatchElementReader::Initialize(BufferSource* source) {
return true;
}
+bool PatchElementReader::ValidateEquivalencesAndExtraData() {
+ EquivalenceSource equivalences_copy = equivalences_;
+
+ const size_t old_region_size = element_match_.old_element.size;
+ const size_t new_region_size = element_match_.new_element.size;
+
+ base::CheckedNumeric<uint32_t> total_length = 0;
+ // Validate that each |equivalence| falls within the bounds of the
+ // |element_match_| and are in order.
+ offset_t prev_dst_end = 0;
+ for (auto equivalence = equivalences_copy.GetNext(); equivalence.has_value();
+ equivalence = equivalences_copy.GetNext()) {
+ if (!RangeIsBounded(equivalence->src_offset, equivalence->length,
+ old_region_size) ||
+ !RangeIsBounded(equivalence->dst_offset, equivalence->length,
+ new_region_size)) {
+ LOG(ERROR) << "Out of bounds equivalence detected.";
+ return false;
+ }
+ if (prev_dst_end > equivalence->dst_end()) {
+ LOG(ERROR) << "Out of order equivalence detected.";
+ return false;
+ }
+ prev_dst_end = equivalence->dst_end();
+ total_length += equivalence->length;
+ }
+ if (!total_length.IsValid() ||
+ element_match_.new_element.region().size < total_length.ValueOrDie() ||
+ extra_data_.extra_data().size() !=
+ element_match_.new_element.region().size -
+ static_cast<size_t>(total_length.ValueOrDie())) {
+ LOG(ERROR) << "Incorrect amount of extra_data.";
+ return false;
+ }
+ return true;
+}
+
/******** EnsemblePatchReader ********/
base::Optional<EnsemblePatchReader> EnsemblePatchReader::Create(
@@ -272,6 +334,7 @@ bool EnsemblePatchReader::Initialize(BufferSource* source) {
LOG(ERROR) << "Patch contains invalid magic.";
return false;
}
+ // |header_| is assumed to be safe from this point forward.
uint32_t element_count = 0;
if (!source->GetValue(&element_count)) {
diff --git a/chromium/components/zucchini/patch_reader.h b/chromium/components/zucchini/patch_reader.h
index ad517f5956d..515da500144 100644
--- a/chromium/components/zucchini/patch_reader.h
+++ b/chromium/components/zucchini/patch_reader.h
@@ -168,13 +168,13 @@ class ReferenceDeltaSource {
// Core functions.
bool Initialize(BufferSource* source);
base::Optional<int32_t> GetNext();
- bool Done() const { return reference_delta_.empty(); }
+ bool Done() const { return source_.empty(); }
// Accessors for unittest.
- BufferSource reference_delta() const { return reference_delta_; }
+ BufferSource reference_delta() const { return source_; }
private:
- BufferSource reference_delta_;
+ BufferSource source_;
};
// Source for additional targets.
@@ -218,7 +218,11 @@ class PatchElementReader {
const Element& old_element() const { return element_match_.old_element; }
const Element& new_element() const { return element_match_.new_element; }
- // The Get*() functions below return copies of cached sources.
+ // The Get*() functions below return copies of cached sources. Callers may
+ // assume the following:
+ // - Equivalences satisfy basic boundary constraints
+ // - "Old" / "new" blocks lie entirely in "old" / "new" images.
+ // - "New" blocks are sorted.
EquivalenceSource GetEquivalenceSource() const { return equivalences_; }
ExtraDataSource GetExtraDataSource() const { return extra_data_; }
RawDeltaSource GetRawDeltaSource() const { return raw_delta_; }
@@ -231,6 +235,12 @@ class PatchElementReader {
}
private:
+ // Checks that "old" and "new" blocks of each item in |equivalences_| satisfy
+ // basic order and image bound constraints (using |element_match_| data). Also
+ // validates that the amount of extra data is correct. Returns true if
+ // successful.
+ bool ValidateEquivalencesAndExtraData();
+
ElementMatch element_match_;
// Cached sources.
diff --git a/chromium/components/zucchini/patch_utils.h b/chromium/components/zucchini/patch_utils.h
index b90438076f7..5f491950ab7 100644
--- a/chromium/components/zucchini/patch_utils.h
+++ b/chromium/components/zucchini/patch_utils.h
@@ -34,20 +34,20 @@ struct PatchHeader {
};
// Sanity check.
-static_assert(sizeof(PatchHeader) == 20, "PatchHeader is 20 bytes");
+static_assert(sizeof(PatchHeader) == 20, "PatchHeader must be 20 bytes");
// Header for a patch element, found at the beginning of every patch element.
struct PatchElementHeader {
uint32_t old_offset;
- uint32_t new_offset;
uint32_t old_length;
+ uint32_t new_offset;
uint32_t new_length;
- uint32_t exe_type;
+ uint32_t exe_type; // ExecutableType.
};
// Sanity check.
static_assert(sizeof(PatchElementHeader) == 20,
- "PatchElementHeader is 28 bytes");
+ "PatchElementHeader must be 20 bytes");
#pragma pack(pop)
diff --git a/chromium/components/zucchini/patch_writer.cc b/chromium/components/zucchini/patch_writer.cc
index 114bcd44b99..1206208e0b4 100644
--- a/chromium/components/zucchini/patch_writer.cc
+++ b/chromium/components/zucchini/patch_writer.cc
@@ -23,10 +23,10 @@ bool SerializeElementMatch(const ElementMatch& element_match,
PatchElementHeader element_header;
element_header.old_offset =
base::checked_cast<uint32_t>(element_match.old_element.offset);
- element_header.new_offset =
- base::checked_cast<uint32_t>(element_match.new_element.offset);
element_header.old_length =
base::checked_cast<uint32_t>(element_match.old_element.size);
+ element_header.new_offset =
+ base::checked_cast<uint32_t>(element_match.new_element.offset);
element_header.new_length =
base::checked_cast<uint32_t>(element_match.new_element.size);
element_header.exe_type = element_match.exe_type();
diff --git a/chromium/components/zucchini/reference_bytes_mixer.cc b/chromium/components/zucchini/reference_bytes_mixer.cc
new file mode 100644
index 00000000000..c0d5ca35ca2
--- /dev/null
+++ b/chromium/components/zucchini/reference_bytes_mixer.cc
@@ -0,0 +1,48 @@
+// 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 "components/zucchini/reference_bytes_mixer.h"
+
+#include "base/logging.h"
+#include "components/zucchini/disassembler.h"
+
+namespace zucchini {
+
+/******** ReferenceBytesMixer ********/
+
+// Default implementation is a stub, i.e., for architectures whose references
+// have operation bits and payload bits stored in separate bytes. So during
+// patch application, payload bits are copied for matched blocks, ignored by
+// bytewise corrections, and fixed by reference target corrections.
+ReferenceBytesMixer::ReferenceBytesMixer() {}
+
+ReferenceBytesMixer::~ReferenceBytesMixer() = default;
+
+// static.
+std::unique_ptr<ReferenceBytesMixer> ReferenceBytesMixer::Create(
+ const Disassembler& src_dis,
+ const Disassembler& dst_dis) {
+ ExecutableType exe_type = src_dis.GetExeType();
+ DCHECK_EQ(exe_type, dst_dis.GetExeType());
+ // TODO(huangs): Add ARM handling code when ARM is ready.
+ return std::make_unique<ReferenceBytesMixer>();
+}
+
+// Stub implementation.
+int ReferenceBytesMixer::NumBytes(uint8_t type) const {
+ return 0;
+}
+
+// Base class implementation is a stub that should not be called.
+ConstBufferView ReferenceBytesMixer::Mix(
+ uint8_t type,
+ ConstBufferView::const_iterator old_base,
+ offset_t old_offset,
+ ConstBufferView::const_iterator new_base,
+ offset_t new_offset) {
+ NOTREACHED() << "Stub.";
+ return ConstBufferView();
+}
+
+} // namespace zucchini
diff --git a/chromium/components/zucchini/reference_bytes_mixer.h b/chromium/components/zucchini/reference_bytes_mixer.h
new file mode 100644
index 00000000000..9bc8f2dbcb3
--- /dev/null
+++ b/chromium/components/zucchini/reference_bytes_mixer.h
@@ -0,0 +1,91 @@
+// 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 COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_
+#define COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/zucchini/buffer_view.h"
+#include "components/zucchini/image_utils.h"
+
+namespace zucchini {
+
+class Disassembler;
+
+// References encoding may be quite complex in some architectures (e.g., ARM),
+// requiring bit-level manipulation. In general, bits in a reference body fall
+// under 2 categories:
+// - Operation bits: Instruction op code, conditionals, or structural data.
+// - Payload bits: Actual target data of the reference. These may be absolute,
+// or be displacements relative to instruction pointer / program counter.
+// During patch application,
+// Old reference bytes = {old operation, old payload},
+// is transformed to
+// New reference bytes = {new operation, new payload}.
+// New image bytes are written by three sources:
+// (1) Direct copy from old image to new image for matched blocks.
+// (2) Bytewise diff correction.
+// (3) Dedicated reference target correction.
+//
+// For references whose operation and payload bits are stored in easily
+// separable bytes (e.g., rel32 reference in X86), (2) can exclude payload bits.
+// So during patch application, (1) naively copies everything, (2) fixes
+// operation bytes only, and (3) fixes payload bytes only.
+//
+// For architectures with references whose operation and payload bits may mix
+// within shared bytes (e.g., ARM rel32), a dilemma arises:
+// - (2) cannot ignores shared bytes, since otherwise new operation bits not
+// properly transfer.
+// - Having (2) always overwrite these bytes would reduce the benefits of
+// reference correction, since references are likely to change.
+//
+// Our solution applies a hybrid approach: For each matching old / new reference
+// pair, define:
+// Mixed reference bytes = {new operation, old payload},
+//
+// During patch generation, we compute bytewise correction from old reference
+// bytes to the mixed reference bytes. So during patch application, (2) only
+// corrects operation bit changes (and skips if they don't change), and (3)
+// overwrites old payload bits to new payload bits.
+
+// A base class for (stateful) mixed reference byte generation. This base class
+// serves as a stub. Architectures whose references store operation bits and
+// payload bits can share common bytes (e.g., ARM rel32) should override this.
+class ReferenceBytesMixer {
+ public:
+ ReferenceBytesMixer();
+ virtual ~ReferenceBytesMixer();
+
+ // Returns a new ReferenceBytesMixer instance that's owned by the caller.
+ static std::unique_ptr<ReferenceBytesMixer> Create(
+ const Disassembler& src_dis,
+ const Disassembler& dst_dis);
+
+ // Returns the number of bytes that need to be mixed for references with given
+ // |type|. Returns 0 if no mixing is required.
+ virtual int NumBytes(uint8_t type) const;
+
+ // Computes mixed reference bytes by combining (a) "payload bits" from an
+ // "old" reference of |type| at |old_base[old_offset]| with (b) "operation
+ // bits" from a "new" reference of |type| at |new_base[new_offset]|. Returns
+ // the result as ConstBufferView, which is valid only until the next call to
+ // Mix().
+ virtual ConstBufferView Mix(uint8_t type,
+ ConstBufferView::const_iterator old_base,
+ offset_t old_offset,
+ ConstBufferView::const_iterator new_base,
+ offset_t new_offset);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ReferenceBytesMixer);
+};
+
+} // namespace zucchini
+
+#endif // COMPONENTS_ZUCCHINI_REFERENCE_BYTES_MIXER_H_
diff --git a/chromium/components/zucchini/target_pool.h b/chromium/components/zucchini/target_pool.h
index b881b1e45bf..27884d628dc 100644
--- a/chromium/components/zucchini/target_pool.h
+++ b/chromium/components/zucchini/target_pool.h
@@ -54,6 +54,9 @@ class TargetPool {
// this class.
offset_t OffsetForKey(key_t key) const { return targets_[key]; }
+ // Returns whether a particular key is valid.
+ bool KeyIsValid(key_t key) const { return key < targets_.size(); }
+
// Uses |offset_mapper| to transform "old" |targets_| to "new" |targets_|,
// resulting in sorted and unique targets.
void FilterAndProject(const OffsetMapper& offset_mapper);
diff --git a/chromium/components/zucchini/type_ztf.h b/chromium/components/zucchini/type_ztf.h
new file mode 100644
index 00000000000..42798b22628
--- /dev/null
+++ b/chromium/components/zucchini/type_ztf.h
@@ -0,0 +1,52 @@
+// 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 COMPONENTS_ZUCCHINI_TYPE_ZTF_H_
+#define COMPONENTS_ZUCCHINI_TYPE_ZTF_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace zucchini {
+
+namespace ztf {
+
+typedef int16_t dim_t;
+
+// A exclusive upper bound on number of lines and/or columns. Throughout the ZTF
+// code a dimension (dim) refers to a block of 1-3 digits which contain a line
+// or column number.
+enum : size_t { kMaxDimValue = 1000 };
+
+enum SignChar : uint8_t {
+ kMinus = '-',
+ kPlus = '+',
+};
+
+// Lines and columns are 1-based to follow the convention of most modern text
+// editing software. |line| and |col| should be positive, but int16_t is used to
+// limit ranges such that it matches DeltaLineCol.
+struct LineCol {
+ dim_t line;
+ dim_t col;
+};
+
+struct DeltaLineCol {
+ dim_t line;
+ dim_t col;
+};
+
+constexpr DeltaLineCol operator-(const LineCol& lhs, const LineCol& rhs) {
+ return DeltaLineCol{lhs.line - rhs.line, lhs.col - rhs.col};
+}
+
+constexpr LineCol operator+(const LineCol& lhs, const DeltaLineCol& rhs) {
+ return LineCol{lhs.line + rhs.line, lhs.col + rhs.col};
+}
+
+} // namespace ztf
+
+} // namespace zucchini
+
+#endif // COMPONENTS_ZUCCHINI_TYPE_ZTF_H_
diff --git a/chromium/components/zucchini/zucchini.h b/chromium/components/zucchini/zucchini.h
index 9100709dd3c..e9093eb6aca 100644
--- a/chromium/components/zucchini/zucchini.h
+++ b/chromium/components/zucchini/zucchini.h
@@ -5,6 +5,8 @@
#ifndef COMPONENTS_ZUCCHINI_ZUCCHINI_H_
#define COMPONENTS_ZUCCHINI_ZUCCHINI_H_
+#include <string>
+
#include "components/zucchini/buffer_view.h"
#include "components/zucchini/patch_reader.h"
#include "components/zucchini/patch_writer.h"
@@ -31,12 +33,25 @@ enum Code {
} // namespace status
-// Generates ensemble patch from |old_image| to |new_image|, and writes it to
-// |patch_writer|.
+// Generates ensemble patch from |old_image| to |new_image| using the default
+// element detection and matching heuristics, writes the results to
+// |patch_writer|, and returns a status::Code.
status::Code GenerateEnsemble(ConstBufferView old_image,
ConstBufferView new_image,
EnsemblePatchWriter* patch_writer);
+// Same as GenerateEnsemble(), but if |imposed_matches| is non-empty, then
+// overrides default element detection and matching heuristics with custom
+// element matching encoded in |imposed_matches|, which should be formatted as:
+// "#+#=#+#,#+#=#+#,..." (e.g., "1+2=3+4", "1+2=3+4,5+6=7+8"),
+// where "#+#=#+#" encodes a match as 4 unsigned integers:
+// [offset in "old", size in "old", offset in "new", size in "new"].
+status::Code GenerateEnsembleWithImposedMatches(
+ ConstBufferView old_image,
+ ConstBufferView new_image,
+ std::string imposed_matches,
+ EnsemblePatchWriter* patch_writer);
+
// Generates raw patch from |old_image| to |new_image|, and writes it to
// |patch_writer|.
status::Code GenerateRaw(ConstBufferView old_image,
diff --git a/chromium/components/zucchini/zucchini_apply.cc b/chromium/components/zucchini/zucchini_apply.cc
index 15328742b21..8969e3bbe56 100644
--- a/chromium/components/zucchini/zucchini_apply.cc
+++ b/chromium/components/zucchini/zucchini_apply.cc
@@ -26,17 +26,18 @@ bool ApplyEquivalenceAndExtraData(ConstBufferView old_image,
for (auto equivalence = equiv_source.GetNext(); equivalence.has_value();
equivalence = equiv_source.GetNext()) {
- // TODO(etiennep): Guard against out of range errors and return false
- // instead.
MutableBufferView::iterator next_dst_it =
new_image.begin() + equivalence->dst_offset;
CHECK(next_dst_it >= dst_it);
+
offset_t gap = static_cast<offset_t>(next_dst_it - dst_it);
base::Optional<ConstBufferView> extra_data = extra_data_source.GetNext(gap);
if (!extra_data) {
LOG(ERROR) << "Error reading extra_data";
return false;
}
+ // |extra_data| length is based on what was parsed from the patch so this
+ // copy should be valid.
dst_it = std::copy(extra_data->begin(), extra_data->end(), dst_it);
CHECK_EQ(dst_it, next_dst_it);
dst_it = std::copy_n(old_image.begin() + equivalence->src_offset,
@@ -150,6 +151,11 @@ bool ApplyReferencesCorrection(ExecutableType exe_type,
LOG(ERROR) << "Error reading reference_delta";
return false;
}
+ const key_t key = expected_key + delta.value();
+ if (!targets.KeyIsValid(key)) {
+ LOG(ERROR) << "Invalid reference_delta";
+ return false;
+ }
ref->target = targets.OffsetForKey(expected_key + delta.value());
ref->location =
ref->location - equivalence->src_offset + equivalence->dst_offset;
diff --git a/chromium/components/zucchini/zucchini_commands.cc b/chromium/components/zucchini/zucchini_commands.cc
index 2d4b1564746..62dd20d215d 100644
--- a/chromium/components/zucchini/zucchini_commands.cc
+++ b/chromium/components/zucchini/zucchini_commands.cc
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <ostream>
+#include <string>
#include <utility>
#include "base/command_line.h"
@@ -29,6 +30,7 @@ namespace {
/******** Command-line Switches ********/
constexpr char kSwitchDump[] = "dump";
+constexpr char kSwitchImpose[] = "impose";
constexpr char kSwitchKeep[] = "keep";
constexpr char kSwitchRaw[] = "raw";
@@ -56,11 +58,18 @@ zucchini::status::Code MainGen(MainParams params) {
zucchini::EnsemblePatchWriter patch_writer(old_image.region(),
new_image.region());
- auto generate = params.command_line.HasSwitch(kSwitchRaw)
- ? zucchini::GenerateRaw
- : zucchini::GenerateEnsemble;
- zucchini::status::Code result =
- generate(old_image.region(), new_image.region(), &patch_writer);
+ zucchini::status::Code result = zucchini::status::kStatusSuccess;
+ if (params.command_line.HasSwitch(kSwitchRaw)) {
+ result = GenerateRaw(old_image.region(), new_image.region(), &patch_writer);
+ } else {
+ // May be empty.
+ std::string imposed_matches =
+ params.command_line.GetSwitchValueASCII(kSwitchImpose);
+ result = GenerateEnsembleWithImposedMatches(
+ old_image.region(), new_image.region(), std::move(imposed_matches),
+ &patch_writer);
+ }
+
if (result != zucchini::status::kStatusSuccess) {
params.out << "Fatal error encountered when generating patch." << std::endl;
return result;
@@ -154,9 +163,13 @@ zucchini::status::Code MainMatch(MainParams params) {
<< new_image.error();
return zucchini::status::kStatusFileReadError;
}
+
+ std::string imposed_matches =
+ params.command_line.GetSwitchValueASCII(kSwitchImpose);
zucchini::status::Code status =
zucchini::MatchAll({old_image.data(), old_image.length()},
- {new_image.data(), new_image.length()}, params.out);
+ {new_image.data(), new_image.length()},
+ std::move(imposed_matches), params.out);
if (status != zucchini::status::kStatusSuccess)
params.err << "Fatal error found when matching executables." << std::endl;
return status;
diff --git a/chromium/components/zucchini/zucchini_gen.cc b/chromium/components/zucchini/zucchini_gen.cc
index af7c7ddc4a9..29be8147841 100644
--- a/chromium/components/zucchini/zucchini_gen.cc
+++ b/chromium/components/zucchini/zucchini_gen.cc
@@ -10,6 +10,7 @@
#include <algorithm>
#include <map>
#include <memory>
+#include <string>
#include <utility>
#include "base/logging.h"
@@ -21,7 +22,9 @@
#include "components/zucchini/equivalence_map.h"
#include "components/zucchini/heuristic_ensemble_matcher.h"
#include "components/zucchini/image_index.h"
+#include "components/zucchini/imposed_ensemble_matcher.h"
#include "components/zucchini/patch_writer.h"
+#include "components/zucchini/reference_bytes_mixer.h"
#include "components/zucchini/suffix_array.h"
#include "components/zucchini/targets_affinity.h"
@@ -120,6 +123,7 @@ bool GenerateRawDelta(ConstBufferView old_image,
ConstBufferView new_image,
const EquivalenceMap& equivalence_map,
const ImageIndex& new_image_index,
+ ReferenceBytesMixer* reference_bytes_mixer,
PatchElementWriter* patch_writer) {
RawDeltaSink raw_delta_sink;
@@ -130,14 +134,37 @@ bool GenerateRawDelta(ConstBufferView old_image,
Equivalence equivalence = candidate.eq;
// For each bytewise delta from |old_image| to |new_image|, compute "copy
// offset" and pass it along with delta to the sink.
- for (offset_t i = 0; i < equivalence.length; ++i) {
- if (new_image_index.IsReference(equivalence.dst_offset + i))
- continue; // Skip references since they're handled elsewhere.
-
- int8_t diff = new_image[equivalence.dst_offset + i] -
- old_image[equivalence.src_offset + i];
- if (diff)
- raw_delta_sink.PutNext({base_copy_offset + i, diff});
+ for (offset_t i = 0; i < equivalence.length;) {
+ if (new_image_index.IsReference(equivalence.dst_offset + i)) {
+ DCHECK(new_image_index.IsToken(equivalence.dst_offset + i));
+ TypeTag type_tag =
+ new_image_index.LookupType(equivalence.dst_offset + i);
+
+ // Reference delta has its own flow. On some architectures (e.g., x86)
+ // this does not involve raw delta, so we skip. On other architectures
+ // (e.g., ARM) references are mixed with other bits that may change, so
+ // we need to "mix" data and store some changed bits into raw delta.
+ int num_bytes = reference_bytes_mixer->NumBytes(type_tag.value());
+ if (num_bytes) {
+ ConstBufferView mixed_ref_bytes = reference_bytes_mixer->Mix(
+ type_tag.value(), old_image.begin(), equivalence.src_offset + i,
+ new_image.begin(), equivalence.dst_offset + i);
+ for (int j = 0; j < num_bytes; ++j) {
+ int8_t diff =
+ mixed_ref_bytes[j] - old_image[equivalence.src_offset + i + j];
+ if (diff)
+ raw_delta_sink.PutNext({base_copy_offset + i + j, diff});
+ }
+ }
+ i += new_image_index.refs(type_tag).width();
+ DCHECK_LE(i, equivalence.length);
+ } else {
+ int8_t diff = new_image[equivalence.dst_offset + i] -
+ old_image[equivalence.src_offset + i];
+ if (diff)
+ raw_delta_sink.PutNext({base_copy_offset + i, diff});
+ ++i;
+ }
}
base_copy_offset += equivalence.length;
}
@@ -225,10 +252,12 @@ bool GenerateRawElement(const std::vector<offset_t>& old_sa,
kMinEquivalenceSimilarity);
patch_writer->SetReferenceDeltaSink({});
+
+ ReferenceBytesMixer no_op_bytes_mixer;
return GenerateEquivalencesAndExtraData(new_image, equivalences,
patch_writer) &&
GenerateRawDelta(old_image, new_image, equivalences, new_image_index,
- patch_writer);
+ &no_op_bytes_mixer, patch_writer);
}
bool GenerateExecutableElement(ExecutableType exe_type,
@@ -282,20 +311,18 @@ bool GenerateExecutableElement(ExecutableType exe_type,
}
}
patch_writer->SetReferenceDeltaSink(std::move(reference_delta_sink));
-
+ std::unique_ptr<ReferenceBytesMixer> reference_bytes_mixer =
+ ReferenceBytesMixer::Create(*old_disasm, *new_disasm);
return GenerateEquivalencesAndExtraData(new_image, equivalences,
patch_writer) &&
GenerateRawDelta(old_image, new_image, equivalences, new_image_index,
- patch_writer);
+ reference_bytes_mixer.get(), patch_writer);
}
-/******** Exported Functions ********/
-
-status::Code GenerateEnsemble(ConstBufferView old_image,
- ConstBufferView new_image,
- EnsemblePatchWriter* patch_writer) {
- std::unique_ptr<EnsembleMatcher> matcher =
- std::make_unique<HeuristicEnsembleMatcher>(nullptr);
+status::Code GenerateEnsembleCommon(ConstBufferView old_image,
+ ConstBufferView new_image,
+ std::unique_ptr<EnsembleMatcher> matcher,
+ EnsemblePatchWriter* patch_writer) {
if (!matcher->RunMatch(old_image, new_image)) {
LOG(INFO) << "RunMatch() failed, generating raw patch.";
return GenerateRaw(old_image, new_image, patch_writer);
@@ -392,6 +419,29 @@ status::Code GenerateEnsemble(ConstBufferView old_image,
return status::kStatusSuccess;
}
+/******** Exported Functions ********/
+
+status::Code GenerateEnsemble(ConstBufferView old_image,
+ ConstBufferView new_image,
+ EnsemblePatchWriter* patch_writer) {
+ return GenerateEnsembleCommon(
+ old_image, new_image, std::make_unique<HeuristicEnsembleMatcher>(nullptr),
+ patch_writer);
+}
+
+status::Code GenerateEnsembleWithImposedMatches(
+ ConstBufferView old_image,
+ ConstBufferView new_image,
+ std::string imposed_matches,
+ EnsemblePatchWriter* patch_writer) {
+ if (imposed_matches.empty())
+ return GenerateEnsemble(old_image, new_image, patch_writer);
+
+ return GenerateEnsembleCommon(
+ old_image, new_image,
+ std::make_unique<ImposedEnsembleMatcher>(imposed_matches), patch_writer);
+}
+
status::Code GenerateRaw(ConstBufferView old_image,
ConstBufferView new_image,
EnsemblePatchWriter* patch_writer) {
diff --git a/chromium/components/zucchini/zucchini_gen.h b/chromium/components/zucchini/zucchini_gen.h
index a0f36303ef9..17f1fd4b2a4 100644
--- a/chromium/components/zucchini/zucchini_gen.h
+++ b/chromium/components/zucchini/zucchini_gen.h
@@ -18,6 +18,7 @@ class EquivalenceMap;
class OffsetMapper;
class ImageIndex;
class PatchElementWriter;
+class ReferenceBytesMixer;
class ReferenceDeltaSink;
class ReferenceSet;
class TargetPool;
@@ -48,6 +49,7 @@ bool GenerateRawDelta(ConstBufferView old_image,
ConstBufferView new_image,
const EquivalenceMap& equivalence_map,
const ImageIndex& new_image_index,
+ ReferenceBytesMixer* reference_bytes_mixer,
PatchElementWriter* patch_writer);
// Writes reference delta between references from |old_refs| and from
diff --git a/chromium/components/zucchini/zucchini_tools.cc b/chromium/components/zucchini/zucchini_tools.cc
index 57ff0b2cd9b..5fcf0667f4a 100644
--- a/chromium/components/zucchini/zucchini_tools.cc
+++ b/chromium/components/zucchini/zucchini_tools.cc
@@ -10,7 +10,7 @@
#include <algorithm>
#include <memory>
#include <ostream>
-#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/logging.h"
@@ -19,6 +19,7 @@
#include "components/zucchini/element_detection.h"
#include "components/zucchini/ensemble_matcher.h"
#include "components/zucchini/heuristic_ensemble_matcher.h"
+#include "components/zucchini/imposed_ensemble_matcher.h"
#include "components/zucchini/io_utils.h"
namespace zucchini {
@@ -44,11 +45,10 @@ status::Code ReadReferences(ConstBufferView image,
targets.erase(std::unique(targets.begin(), targets.end()), targets.end());
size_t num_targets = targets.size();
- out << "Type " << int(group.type_tag().value());
- out << ": Pool=" << static_cast<uint32_t>(group.pool_tag().value());
- out << ", width=" << group.width();
- out << ", #locations=" << num_locations;
- out << ", #targets=" << num_targets;
+ out << "Type " << int(group.type_tag().value())
+ << ": Pool=" << static_cast<uint32_t>(group.pool_tag().value())
+ << ", width=" << group.width() << ", #locations=" << num_locations
+ << ", #targets=" << num_targets;
if (num_targets > 0) {
double ratio = static_cast<double>(num_locations) / num_targets;
out << " (ratio=" << base::StringPrintf("%.4f", ratio) << ")";
@@ -59,8 +59,8 @@ status::Code ReadReferences(ConstBufferView image,
refs = group.GetReader(disasm.get());
for (auto ref = refs->GetNext(); ref; ref = refs->GetNext()) {
- out << " " << AsHex<8>(ref->location);
- out << " " << AsHex<8>(ref->target) << std::endl;
+ out << " " << AsHex<8>(ref->location) << " " << AsHex<8>(ref->target)
+ << std::endl;
}
}
}
@@ -112,14 +112,27 @@ status::Code DetectAll(ConstBufferView image,
status::Code MatchAll(ConstBufferView old_image,
ConstBufferView new_image,
+ std::string imposed_matches,
std::ostream& out) {
- HeuristicEnsembleMatcher matcher(&out);
- if (!matcher.RunMatch(old_image, new_image)) {
+ std::unique_ptr<EnsembleMatcher> matcher;
+ if (imposed_matches.empty()) {
+ matcher = std::make_unique<HeuristicEnsembleMatcher>(&out);
+ } else {
+ matcher =
+ std::make_unique<ImposedEnsembleMatcher>(std::move(imposed_matches));
+ }
+ if (!matcher->RunMatch(old_image, new_image)) {
out << "RunMatch() failed.";
return status::kStatusFatal;
}
- out << "Found " << matcher.matches().size() << " nontrivial matches and "
- << matcher.num_identical() << " identical matches." << std::endl;
+ out << "Found " << matcher->matches().size() << " nontrivial matches and "
+ << matcher->num_identical() << " identical matches." << std::endl
+ << "To impose the same matches by command line, use: " << std::endl
+ << " -impose=";
+ PrefixSep sep(",");
+ for (const ElementMatch& match : matcher->matches())
+ out << sep << match.ToString();
+ out << std::endl;
return status::kStatusSuccess;
}
diff --git a/chromium/components/zucchini/zucchini_tools.h b/chromium/components/zucchini/zucchini_tools.h
index 626874552d8..bf9a95c3861 100644
--- a/chromium/components/zucchini/zucchini_tools.h
+++ b/chromium/components/zucchini/zucchini_tools.h
@@ -6,6 +6,7 @@
#define COMPONENTS_ZUCCHINI_ZUCCHINI_TOOLS_H_
#include <iosfwd>
+#include <string>
#include <vector>
#include "components/zucchini/buffer_view.h"
@@ -29,8 +30,14 @@ status::Code DetectAll(ConstBufferView image,
std::vector<ConstBufferView>* sub_image_list);
// Prints all matched regions from |old_image| to |new_image|.
+// |imposed_matches|, if non-empty, encodes custom element matching to override
+// the default element detection and matching heuristics, and is formatted as:
+// "#+#=#+#,#+#=#+#,..." (e.g., "1+2=3+4", "1+2=3+4,5+6=7+8"),
+// where "#+#=#+#" encodes a match as 4 unsigned integers:
+// [offset in "old", size in "old", offset in "new", size in "new"].
status::Code MatchAll(ConstBufferView old_image,
ConstBufferView new_image,
+ std::string imposed_matches,
std::ostream& out);
} // namespace zucchini